summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore15
-rw-r--r--aclocal/enable-drvmgr.m412
-rwxr-xr-xbootstrap16
-rw-r--r--c/src/aclocal/enable-drvmgr.m412
-rw-r--r--c/src/lib/libbsp/shared/include/irq-generic.h2
-rw-r--r--c/src/lib/libbsp/shared/include/irq.h8
-rw-r--r--c/src/lib/libbsp/sparc/Makefile.am154
-rw-r--r--c/src/lib/libbsp/sparc/erc32/Makefile.am3
-rw-r--r--c/src/lib/libbsp/sparc/erc32/include/bsp.h7
-rw-r--r--c/src/lib/libbsp/sparc/erc32/startup/setvec.c2
-rw-r--r--c/src/lib/libbsp/sparc/leon2/Makefile.am190
-rw-r--r--c/src/lib/libbsp/sparc/leon2/cchip/cchip.c358
-rw-r--r--c/src/lib/libbsp/sparc/leon2/console/console.c2
-rw-r--r--c/src/lib/libbsp/sparc/leon2/console/debugputs.c9
-rw-r--r--c/src/lib/libbsp/sparc/leon2/include/bsp.h104
-rw-r--r--c/src/lib/libbsp/sparc/leon2/include/bsp/irq.h20
-rw-r--r--c/src/lib/libbsp/sparc/leon2/include/cchip.h26
-rw-r--r--c/src/lib/libbsp/sparc/leon2/include/leon.h13
-rw-r--r--c/src/lib/libbsp/sparc/leon2/include/rasta.h111
-rw-r--r--c/src/lib/libbsp/sparc/leon2/leon_smc91111/leon_smc91111.c6
-rw-r--r--c/src/lib/libbsp/sparc/leon2/pci/at697_pci.c658
-rw-r--r--c/src/lib/libbsp/sparc/leon2/pci/pci.c674
-rw-r--r--c/src/lib/libbsp/sparc/leon2/preinstall.am248
-rw-r--r--c/src/lib/libbsp/sparc/leon2/rasta/rasta.c388
-rw-r--r--c/src/lib/libbsp/sparc/leon2/startup/bsppredriver.c80
-rw-r--r--c/src/lib/libbsp/sparc/leon2/startup/setvec.c2
-rw-r--r--c/src/lib/libbsp/sparc/leon3/Makefile.am202
-rw-r--r--c/src/lib/libbsp/sparc/leon3/amba/amba.c152
-rw-r--r--c/src/lib/libbsp/sparc/leon3/clock/ckinit.c39
-rw-r--r--c/src/lib/libbsp/sparc/leon3/console/console.c413
-rw-r--r--c/src/lib/libbsp/sparc/leon3/console/debugputs.c157
-rw-r--r--c/src/lib/libbsp/sparc/leon3/include/amba.h4
-rw-r--r--c/src/lib/libbsp/sparc/leon3/include/bsp.h131
-rw-r--r--c/src/lib/libbsp/sparc/leon3/include/bsp/irq.h36
-rw-r--r--c/src/lib/libbsp/sparc/leon3/include/leon.h129
-rw-r--r--c/src/lib/libbsp/sparc/leon3/leon_greth/leon_greth.c22
-rw-r--r--c/src/lib/libbsp/sparc/leon3/leon_open_eth/leon_open_eth.c41
-rw-r--r--c/src/lib/libbsp/sparc/leon3/leon_smc91111/leon_smc91111.c40
-rw-r--r--c/src/lib/libbsp/sparc/leon3/pci/pci.c586
-rw-r--r--c/src/lib/libbsp/sparc/leon3/preinstall.am213
-rw-r--r--c/src/lib/libbsp/sparc/leon3/shmsupp/getcfg.c14
-rw-r--r--c/src/lib/libbsp/sparc/leon3/startup/bspidle.S1
-rw-r--r--c/src/lib/libbsp/sparc/leon3/startup/bsppredriver.c27
-rw-r--r--c/src/lib/libbsp/sparc/leon3/startup/bspstart.c37
-rw-r--r--c/src/lib/libbsp/sparc/leon3/startup/eirq.c27
-rw-r--r--c/src/lib/libbsp/sparc/leon3/startup/linkcmds_ngmp210
-rw-r--r--c/src/lib/libbsp/sparc/leon3/startup/setvec.c2
-rw-r--r--c/src/lib/libbsp/sparc/leon3/startup/spurious.c2
-rw-r--r--c/src/lib/libbsp/sparc/leon3/timer/timer.c4
-rw-r--r--c/src/lib/libbsp/sparc/leon3/timer/watchdog.c91
-rw-r--r--c/src/lib/libbsp/sparc/shared/1553/b1553brm.c1961
-rw-r--r--c/src/lib/libbsp/sparc/shared/1553/b1553brm_pci.c132
-rw-r--r--c/src/lib/libbsp/sparc/shared/1553/b1553brm_rasta.c115
-rw-r--r--c/src/lib/libbsp/sparc/shared/1553/b1553rt.c851
-rw-r--r--c/src/lib/libbsp/sparc/shared/1553/gr1553b.c313
-rw-r--r--c/src/lib/libbsp/sparc/shared/1553/gr1553bc.c1682
-rw-r--r--c/src/lib/libbsp/sparc/shared/1553/gr1553bm.c526
-rw-r--r--c/src/lib/libbsp/sparc/shared/1553/gr1553rt.c1250
-rw-r--r--c/src/lib/libbsp/sparc/shared/amba/ahbstat.c196
-rw-r--r--c/src/lib/libbsp/sparc/shared/amba/ambapp.c866
-rw-r--r--c/src/lib/libbsp/sparc/shared/amba/ambapp_alloc.c28
-rw-r--r--c/src/lib/libbsp/sparc/shared/amba/ambapp_count.c27
-rw-r--r--c/src/lib/libbsp/sparc/shared/amba/ambapp_depth.c27
-rw-r--r--c/src/lib/libbsp/sparc/shared/amba/ambapp_find_by_idx.c42
-rw-r--r--c/src/lib/libbsp/sparc/shared/amba/ambapp_freq.c114
-rw-r--r--c/src/lib/libbsp/sparc/shared/amba/ambapp_names.c395
-rw-r--r--c/src/lib/libbsp/sparc/shared/amba/ambapp_old.c106
-rw-r--r--c/src/lib/libbsp/sparc/shared/amba/ambapp_parent.c26
-rw-r--r--c/src/lib/libbsp/sparc/shared/amba/ambapp_show.c76
-rw-r--r--c/src/lib/libbsp/sparc/shared/analog/gradcdac.c582
-rw-r--r--c/src/lib/libbsp/sparc/shared/ascs/grascs.c629
-rw-r--r--c/src/lib/libbsp/sparc/shared/bspgetworkarea.c11
-rw-r--r--c/src/lib/libbsp/sparc/shared/can/canmux.c202
-rw-r--r--c/src/lib/libbsp/sparc/shared/can/grcan.c1678
-rw-r--r--c/src/lib/libbsp/sparc/shared/can/grcan_rasta.c100
-rw-r--r--c/src/lib/libbsp/sparc/shared/can/occan.c1186
-rw-r--r--c/src/lib/libbsp/sparc/shared/can/occan_pci.c64
-rw-r--r--c/src/lib/libbsp/sparc/shared/can/satcan.c721
-rw-r--r--c/src/lib/libbsp/sparc/shared/drvmgr/ambapp_bus.c762
-rw-r--r--c/src/lib/libbsp/sparc/shared/drvmgr/ambapp_bus_grlib.c230
-rw-r--r--c/src/lib/libbsp/sparc/shared/drvmgr/ambapp_bus_leon2.c268
-rw-r--r--c/src/lib/libbsp/sparc/shared/drvmgr/ambapp_bus_rmap.c776
-rw-r--r--c/src/lib/libbsp/sparc/shared/drvmgr/leon2_amba_bus.c463
-rw-r--r--c/src/lib/libbsp/sparc/shared/drvmgr/spw_bus.c960
-rw-r--r--c/src/lib/libbsp/sparc/shared/gpio/gpiolib.c280
-rw-r--r--c/src/lib/libbsp/sparc/shared/gpio/grgpio.c454
-rw-r--r--c/src/lib/libbsp/sparc/shared/graes/graes.c1290
-rw-r--r--c/src/lib/libbsp/sparc/shared/grpwrx/grpwrx.c1317
-rw-r--r--c/src/lib/libbsp/sparc/shared/i2c/i2cmst.c351
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/ahbstat.h74
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/ambapp.h548
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/ambapp_ids.h245
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/apbuart.h12
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/apbuart_pci.h43
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/apbuart_rasta.h43
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/b1553brm.h26
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/b1553brm_pci.h57
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/b1553brm_rasta.h57
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/b1553rt.h76
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/canmux.h37
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/cons.h42
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/drvmgr/ambapp_bus.h135
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/drvmgr/ambapp_bus_grlib.h35
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/drvmgr/ambapp_bus_rmap.h79
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/drvmgr/leon2_amba_bus.h96
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/drvmgr/spw_bus.h131
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/drvmgr/spw_bus_ids.h22
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/genirq.h94
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/gpiolib.h95
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/gr1553b.h369
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/gr1553bc.h254
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/gr1553bc_list.h709
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/gr1553bm.h212
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/gr1553rt.h443
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/gr_701.h49
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/gr_rasta_adcdac.h50
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/gr_rasta_io.h50
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/gr_rasta_tmtc.h100
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/gr_tmtc_1553.h50
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/gradcdac.h230
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/graes.h136
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/grascs.h97
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/grcan.h20
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/grcan_rasta.h24
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/grctm.h169
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/greth.h159
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/grgpio.h26
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/grlib.h92
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/grpci2.h51
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/grpwm.h128
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/grpwrx.h139
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/grslink.h153
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/grspw.h55
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/grspw_pci.h49
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/grspw_pkt.h599
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/grspw_rasta.h49
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/grspw_router.h93
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/grtc.h157
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/grtm.h246
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/i2cmst.h20
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/network_interface_add.h48
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/occan.h12
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/occan_pci.h42
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/rmap.h292
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/rmap_drv_grspw.h31
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/satcan.h147
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/spictrl.h127
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/spwcuc.h189
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/tlib.h177
-rw-r--r--c/src/lib/libbsp/sparc/shared/irq/genirq.c230
-rw-r--r--c/src/lib/libbsp/sparc/shared/irq/irq-shared.c110
-rw-r--r--c/src/lib/libbsp/sparc/shared/mem/mctrl.c214
-rw-r--r--c/src/lib/libbsp/sparc/shared/mem/mctrl_rmap.c248
-rw-r--r--c/src/lib/libbsp/sparc/shared/net/README7
-rw-r--r--c/src/lib/libbsp/sparc/shared/net/greth.c1451
-rw-r--r--c/src/lib/libbsp/sparc/shared/net/network_interface_add.c66
-rw-r--r--c/src/lib/libbsp/sparc/shared/pci/gr_701.c596
-rw-r--r--c/src/lib/libbsp/sparc/shared/pci/gr_rasta_adcdac.c671
-rw-r--r--c/src/lib/libbsp/sparc/shared/pci/gr_rasta_io.c688
-rw-r--r--c/src/lib/libbsp/sparc/shared/pci/gr_rasta_spw_router.c681
-rw-r--r--c/src/lib/libbsp/sparc/shared/pci/gr_rasta_tmtc.c694
-rw-r--r--c/src/lib/libbsp/sparc/shared/pci/gr_tmtc_1553.c575
-rw-r--r--c/src/lib/libbsp/sparc/shared/pci/grpci.c698
-rw-r--r--c/src/lib/libbsp/sparc/shared/pci/grpci2.c906
-rw-r--r--c/src/lib/libbsp/sparc/shared/pci/pci_memreg_sparc_be.c19
-rw-r--r--c/src/lib/libbsp/sparc/shared/pci/pci_memreg_sparc_le.c19
-rw-r--r--c/src/lib/libbsp/sparc/shared/pci/pcif.c567
-rw-r--r--c/src/lib/libbsp/sparc/shared/pci/pcifinddevice.c57
-rw-r--r--c/src/lib/libbsp/sparc/shared/pwm/grpwm.c848
-rw-r--r--c/src/lib/libbsp/sparc/shared/slink/grslink.c665
-rw-r--r--c/src/lib/libbsp/sparc/shared/spi/spictrl.c1011
-rw-r--r--c/src/lib/libbsp/sparc/shared/spw/grspw.c2816
-rw-r--r--c/src/lib/libbsp/sparc/shared/spw/grspw_pci.c127
-rw-r--r--c/src/lib/libbsp/sparc/shared/spw/grspw_pkt.c2634
-rw-r--r--c/src/lib/libbsp/sparc/shared/spw/grspw_rasta.c155
-rw-r--r--c/src/lib/libbsp/sparc/shared/spw/grspw_router.c547
-rw-r--r--c/src/lib/libbsp/sparc/shared/spw/rmap.c645
-rw-r--r--c/src/lib/libbsp/sparc/shared/spw/rmap_drv_grspw.c161
-rw-r--r--c/src/lib/libbsp/sparc/shared/startup/early_malloc.c44
-rw-r--r--c/src/lib/libbsp/sparc/shared/time/grctm.c410
-rw-r--r--c/src/lib/libbsp/sparc/shared/time/spwcuc.c370
-rw-r--r--c/src/lib/libbsp/sparc/shared/timer/gptimer.c533
-rw-r--r--c/src/lib/libbsp/sparc/shared/timer/tlib.c66
-rw-r--r--c/src/lib/libbsp/sparc/shared/timer/tlib_ckinit.c280
-rw-r--r--c/src/lib/libbsp/sparc/shared/tmtc/grtc.c1960
-rw-r--r--c/src/lib/libbsp/sparc/shared/tmtc/grtc_rmap.c2233
-rw-r--r--c/src/lib/libbsp/sparc/shared/tmtc/grtm.c1599
-rw-r--r--c/src/lib/libbsp/sparc/shared/tmtc/grtm_rmap.c1699
-rw-r--r--c/src/lib/libbsp/sparc/shared/uart/apbuart.c963
-rw-r--r--c/src/lib/libbsp/sparc/shared/uart/apbuart_cons.c692
-rw-r--r--c/src/lib/libbsp/sparc/shared/uart/apbuart_pci.c42
-rw-r--r--c/src/lib/libbsp/sparc/shared/uart/apbuart_rasta.c42
-rw-r--r--c/src/lib/libbsp/sparc/shared/uart/cons.c189
-rw-r--r--c/src/lib/libcpu/sparc/Makefile.am7
-rw-r--r--c/src/lib/libcpu/sparc/access/access.S65
-rw-r--r--c/src/lib/libcpu/sparc/access/access_le.c32
-rw-r--r--c/src/lib/libcpu/sparc/include/libcpu/access.h48
-rw-r--r--c/src/lib/libcpu/sparc/include/libcpu/byteorder.h66
-rw-r--r--c/src/lib/libcpu/sparc/preinstall.am8
-rw-r--r--c/src/lib/libcpu/sparc/reg_win/window.S35
-rw-r--r--c/src/libchip/network/greth.c618
-rw-r--r--c/src/libchip/network/greth.h2
-rw-r--r--c/src/libchip/network/smc91111.c26
-rw-r--r--c/src/libchip/network/smc91111exp.h2
-rw-r--r--c/src/make/configure.ac1
-rw-r--r--configure.ac1
-rw-r--r--cpukit/Makefile.am8
-rw-r--r--cpukit/aclocal/enable-drvmgr.m412
-rw-r--r--cpukit/configure.ac8
-rw-r--r--cpukit/libdrvmgr/Makefile.am31
-rw-r--r--cpukit/libdrvmgr/README113
-rw-r--r--cpukit/libdrvmgr/drvmgr.c646
-rw-r--r--cpukit/libdrvmgr/drvmgr.h889
-rw-r--r--cpukit/libdrvmgr/drvmgr_by_id.c34
-rw-r--r--cpukit/libdrvmgr/drvmgr_by_name.c38
-rw-r--r--cpukit/libdrvmgr/drvmgr_confdefs.h346
-rw-r--r--cpukit/libdrvmgr/drvmgr_drvinf.c145
-rw-r--r--cpukit/libdrvmgr/drvmgr_for_each_dev.c105
-rw-r--r--cpukit/libdrvmgr/drvmgr_for_each_list_dev.c45
-rw-r--r--cpukit/libdrvmgr/drvmgr_func.c43
-rw-r--r--cpukit/libdrvmgr/drvmgr_func_call.c22
-rw-r--r--cpukit/libdrvmgr/drvmgr_init.c27
-rw-r--r--cpukit/libdrvmgr/drvmgr_internal.h62
-rw-r--r--cpukit/libdrvmgr/drvmgr_list.c68
-rw-r--r--cpukit/libdrvmgr/drvmgr_list.h77
-rw-r--r--cpukit/libdrvmgr/drvmgr_lock.c39
-rw-r--r--cpukit/libdrvmgr/drvmgr_print.c455
-rw-r--r--cpukit/libdrvmgr/drvmgr_res.c103
-rw-r--r--cpukit/libdrvmgr/drvmgr_rw.c53
-rw-r--r--cpukit/libdrvmgr/drvmgr_translate.c152
-rw-r--r--cpukit/libdrvmgr/drvmgr_unregister.c184
-rw-r--r--cpukit/libmisc/Makefile.am3
-rw-r--r--cpukit/libmisc/shell/main_drvmgr.c422
-rw-r--r--cpukit/libmisc/shell/main_pci.c493
-rw-r--r--cpukit/libmisc/shell/shellconfig.h25
-rw-r--r--cpukit/libpci/CHANGES46
-rw-r--r--cpukit/libpci/Makefile31
-rw-r--r--cpukit/libpci/Makefile.am47
-rw-r--r--cpukit/libpci/README4
l---------cpukit/libpci/drvmgr/drvmgr.h1
l---------cpukit/libpci/drvmgr/drvmgr_confdefs.h1
l---------cpukit/libpci/drvmgr/drvmgr_list.h1
l---------cpukit/libpci/drvmgr/pci_bus.h1
-rw-r--r--cpukit/libpci/pci.h374
-rw-r--r--cpukit/libpci/pci/access.h315
-rw-r--r--cpukit/libpci/pci/cfg.h237
-rw-r--r--cpukit/libpci/pci/cfg_auto.h51
-rw-r--r--cpukit/libpci/pci/cfg_peripheral.h12
-rw-r--r--cpukit/libpci/pci/cfg_read.h14
-rw-r--r--cpukit/libpci/pci/cfg_static.h14
-rw-r--r--cpukit/libpci/pci/ids.h (renamed from c/src/lib/libbsp/sparc/shared/include/pci.h)393
-rw-r--r--cpukit/libpci/pci/ids_extra.h19
-rw-r--r--cpukit/libpci/pci/irq.h98
-rw-r--r--cpukit/libpci/pci_access.c77
-rw-r--r--cpukit/libpci/pci_access_func.c63
-rw-r--r--cpukit/libpci/pci_access_io.c51
-rw-r--r--cpukit/libpci/pci_access_mem.c11
-rw-r--r--cpukit/libpci/pci_access_mem_be.c62
-rw-r--r--cpukit/libpci/pci_access_mem_le.c61
-rw-r--r--cpukit/libpci/pci_bus.c564
-rw-r--r--cpukit/libpci/pci_bus.h159
-rw-r--r--cpukit/libpci/pci_cfg.c58
-rw-r--r--cpukit/libpci/pci_cfg_auto.c1040
-rw-r--r--cpukit/libpci/pci_cfg_peripheral.c32
-rw-r--r--cpukit/libpci/pci_cfg_print_code.c163
-rw-r--r--cpukit/libpci/pci_cfg_read.c360
-rw-r--r--cpukit/libpci/pci_cfg_static.c158
-rw-r--r--cpukit/libpci/pci_find.c55
-rw-r--r--cpukit/libpci/pci_find_dev.c52
-rw-r--r--cpukit/libpci/pci_for_each.c68
-rw-r--r--cpukit/libpci/pci_for_each_child.c31
-rw-r--r--cpukit/libpci/pci_for_each_dev.c8
-rw-r--r--cpukit/libpci/pci_get_dev.c39
-rw-r--r--cpukit/libpci/pci_irq.c22
-rw-r--r--cpukit/libpci/pci_print.c197
-rw-r--r--cpukit/libpci/preinstall.am74
-rw-r--r--cpukit/preinstall.am17
-rw-r--r--cpukit/sapi/include/confdefs.h46
-rw-r--r--cpukit/sapi/src/exinit.c63
-rw-r--r--cpukit/sapi/src/io.c4
-rw-r--r--cpukit/sapi/src/ioregisterdriver.c14
-rw-r--r--cpukit/score/cpu/sparc/cpu_asm.S23
-rw-r--r--cpukit/score/cpu/sparc/rtems/score/sparc.h12
-rw-r--r--cpukit/wrapup/Makefile.am3
-rw-r--r--doc/ada_user/Makefile.am1
-rw-r--r--doc/ada_user/ada_user.texi2
-rw-r--r--doc/develenv/direct.t3
-rw-r--r--doc/redo.sh9
-rw-r--r--doc/user/Makefile.am11
-rw-r--r--doc/user/c_user.texi2
-rw-r--r--doc/user/conf.t50
-rw-r--r--doc/user/libpci.t409
-rw-r--r--testsuites/mptests/mp06/task1.c1
-rw-r--r--testsuites/psxtests/psxualarm/init.c2
-rw-r--r--testsuites/sptests/sp20/task1.c4
295 files changed, 65877 insertions, 9397 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000..6b89e1e6b2
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,15 @@
+*configure*
+*autom4te.cache*
+aclocal.m4
+Makefile.in
+install-sh
+missing
+config.guess
+bspopts.h.in
+config.sub
+INSTALL
+depcomp
+mdate-sh
+texinfo.tex
+config.h.in
+compile
diff --git a/aclocal/enable-drvmgr.m4 b/aclocal/enable-drvmgr.m4
new file mode 100644
index 0000000000..489f60e75f
--- /dev/null
+++ b/aclocal/enable-drvmgr.m4
@@ -0,0 +1,12 @@
+AC_DEFUN([RTEMS_ENABLE_DRVMGR],
+[
+## AC_BEFORE([$0], [RTEMS_CHECK_DRVMGR_STARTUP])dnl
+
+AC_ARG_ENABLE(drvmgr,
+[AS_HELP_STRING([--enable-drvmgr],[enable Driver Manager at Startup])],
+[case "${enableval}" in
+ yes) RTEMS_DRVMGR_STARTUP=yes ;;
+ no) RTEMS_DRVMGR_STARTUP=no ;;
+ *) AC_MSG_ERROR(bad value ${enableval} for enable-drvmgr option) ;;
+esac],[RTEMS_DRVMGR_STARTUP=yes])
+])
diff --git a/bootstrap b/bootstrap
index 2f7d4dc450..af87459e56 100755
--- a/bootstrap
+++ b/bootstrap
@@ -18,6 +18,7 @@ top_srcdir=`dirname $0`
verbose="";
quiet="false"
mode="generate"
+root=.
usage()
{
@@ -89,6 +90,15 @@ case $1 in
-r|--re|--rec|--reco|--recon|--reconf)
mode="autoreconf";
shift;;
+-s|--sp|--spa|--spar|--sparc)
+ root=./c/src/lib/libbsp/sparc
+ shift;;
+--cpukit)
+ root=./cpukit
+ shift;;
+--max)
+ maxdepth="--maxdepth 1"
+ shift;;
-*) echo "unknown option $1" ;
usage ;;
*) echo "invalid parameter $1" ;
@@ -98,7 +108,7 @@ done
case $mode in
preinstall)
- confs=`find . -name Makefile.am -exec grep -l 'include .*/preinstall\.am' {} \;`
+ confs=`find $root -name Makefile.am -exec grep -l 'include .*/preinstall\.am' {} \;`
for i in $confs; do
dir=$(dirname $i);
test "$quite" = "true" || echo "Generating $dir/preinstall.am"
@@ -138,7 +148,7 @@ generate)
;;
esac
- confs=`find . \( -name 'configure.in' -o -name 'configure.ac' \) -print`
+ confs=`find $root \( -name 'configure.in' -o -name 'configure.ac' \) -print`
for i in $confs; do
dir=`dirname $i`;
configure=`basename $i`;
@@ -170,7 +180,7 @@ autoreconf)
exit 1
fi
- confs=`find . -name 'configure.ac' -print`
+ confs=`find . -name 'configure.ac' -print $maxdepth`
for i in $confs; do
dir=`dirname $i`;
configure=`basename $i`;
diff --git a/c/src/aclocal/enable-drvmgr.m4 b/c/src/aclocal/enable-drvmgr.m4
new file mode 100644
index 0000000000..489f60e75f
--- /dev/null
+++ b/c/src/aclocal/enable-drvmgr.m4
@@ -0,0 +1,12 @@
+AC_DEFUN([RTEMS_ENABLE_DRVMGR],
+[
+## AC_BEFORE([$0], [RTEMS_CHECK_DRVMGR_STARTUP])dnl
+
+AC_ARG_ENABLE(drvmgr,
+[AS_HELP_STRING([--enable-drvmgr],[enable Driver Manager at Startup])],
+[case "${enableval}" in
+ yes) RTEMS_DRVMGR_STARTUP=yes ;;
+ no) RTEMS_DRVMGR_STARTUP=no ;;
+ *) AC_MSG_ERROR(bad value ${enableval} for enable-drvmgr option) ;;
+esac],[RTEMS_DRVMGR_STARTUP=yes])
+])
diff --git a/c/src/lib/libbsp/shared/include/irq-generic.h b/c/src/lib/libbsp/shared/include/irq-generic.h
index 181bc58e2c..b69cbc0cb7 100644
--- a/c/src/lib/libbsp/shared/include/irq-generic.h
+++ b/c/src/lib/libbsp/shared/include/irq-generic.h
@@ -130,6 +130,7 @@ static inline rtems_vector_number bsp_interrupt_handler_index(
* @{
*/
+#if !defined(BSP_INTERRUPT_CUSTOM_VALID_VECTOR)
/**
* @brief Returns true if the interrupt vector with number @a vector is valid.
*/
@@ -138,6 +139,7 @@ static inline bool bsp_interrupt_is_valid_vector(rtems_vector_number vector)
return (rtems_vector_number) BSP_INTERRUPT_VECTOR_MIN <= vector
&& vector <= (rtems_vector_number) BSP_INTERRUPT_VECTOR_MAX;
}
+#endif
/**
* @brief Default interrupt handler.
diff --git a/c/src/lib/libbsp/shared/include/irq.h b/c/src/lib/libbsp/shared/include/irq.h
index ae57bd1c54..19aed6fd40 100644
--- a/c/src/lib/libbsp/shared/include/irq.h
+++ b/c/src/lib/libbsp/shared/include/irq.h
@@ -72,6 +72,14 @@
typedef uint8_t bsp_interrupt_handler_index_type;
#endif
+/**
+ * @brief Enable custom vector checking
+ *
+ * If defined the BSP must implement the custom bsp_interrupt_is_valid_vector()
+ * vector validator check routine.
+ */
+#undef BSP_INTERRUPT_CUSTOM_VALID_VECTOR
+
/** @} */
#endif /* LIBBSP_SHARED_IRQ_CONFIG_H */
diff --git a/c/src/lib/libbsp/sparc/Makefile.am b/c/src/lib/libbsp/sparc/Makefile.am
index 8081d61609..03360913cc 100644
--- a/c/src/lib/libbsp/sparc/Makefile.am
+++ b/c/src/lib/libbsp/sparc/Makefile.am
@@ -14,54 +14,168 @@ EXTRA_DIST += shared/bspstart.c
EXTRA_DIST += shared/gnatcommon.c
EXTRA_DIST += shared/start.S
+# Interrupt
+EXTRA_DIST += shared/irq/irq-shared.c
+EXTRA_DIST += shared/irq/genirq.c
+EXTRA_DIST += shared/include/genirq.h
+
# AMBA Plug&Play bus
+EXTRA_DIST += shared/include/ahbstat.h
EXTRA_DIST += shared/include/ambapp.h
+EXTRA_DIST += shared/include/ambapp_ids.h
+EXTRA_DIST += shared/include/grlib.h
+EXTRA_DIST += shared/amba/ahbstat.c
EXTRA_DIST += shared/amba/ambapp.c
+EXTRA_DIST += shared/amba/ambapp_alloc.c
+EXTRA_DIST += shared/amba/ambapp_count.c
+EXTRA_DIST += shared/amba/ambapp_depth.c
+EXTRA_DIST += shared/amba/ambapp_find_by_idx.c
+EXTRA_DIST += shared/amba/ambapp_freq.c
+EXTRA_DIST += shared/amba/ambapp_parent.c
+EXTRA_DIST += shared/amba/ambapp_names.c
+EXTRA_DIST += shared/amba/ambapp_old.c
+EXTRA_DIST += shared/amba/ambapp_show.c
+
+# Clock Driver and Timer Library
+EXTRA_DIST += shared/include/tlib.h
+EXTRA_DIST += shared/timer/gptimer.c
+EXTRA_DIST += shared/timer/tlib.c
+EXTRA_DIST += shared/timer/tlib_ckinit.c
# PCI bus
-EXTRA_DIST += shared/include/pci.h
-EXTRA_DIST += shared/pci/pcifinddevice.c
+EXTRA_DIST += shared/include/grpci2.h
+EXTRA_DIST += shared/pci/grpci.c
+EXTRA_DIST += shared/pci/grpci2.c
+EXTRA_DIST += shared/pci/pcif.c
+EXTRA_DIST += shared/pci/pci_memreg_sparc_le.c
+EXTRA_DIST += shared/pci/pci_memreg_sparc_be.c
+
+# PCI target boards
+EXTRA_DIST += shared/include/gr_701.h
+EXTRA_DIST += shared/include/gr_rasta_adcdac.h
+EXTRA_DIST += shared/include/gr_rasta_io.h
+EXTRA_DIST += shared/include/gr_rasta_tmtc.h
+EXTRA_DIST += shared/include/gr_tmtc_1553.h
+EXTRA_DIST += shared/pci/gr_701.c
+EXTRA_DIST += shared/pci/gr_rasta_adcdac.c
+EXTRA_DIST += shared/pci/gr_rasta_io.c
+EXTRA_DIST += shared/pci/gr_rasta_spw_router.c
+EXTRA_DIST += shared/pci/gr_rasta_tmtc.c
+EXTRA_DIST += shared/pci/gr_tmtc_1553.c
# DEBUG
EXTRA_DIST += shared/include/debug_defs.h
-# SpaceWire (GRSPW)
+# SpaceWire
EXTRA_DIST += shared/spw/grspw.c
-EXTRA_DIST += shared/spw/grspw_pci.c
-EXTRA_DIST += shared/spw/grspw_rasta.c
+EXTRA_DIST += shared/spw/grspw_router.c
+EXTRA_DIST += shared/spw/rmap.c
+EXTRA_DIST += shared/spw/rmap_drv_grspw.c
EXTRA_DIST += shared/include/grspw.h
-EXTRA_DIST += shared/include/grspw_pci.h
-EXTRA_DIST += shared/include/grspw_rasta.h
+EXTRA_DIST += shared/include/grspw_router.h
+EXTRA_DIST += shared/include/rmap.h
+EXTRA_DIST += shared/include/rmap_drv_grspw.h
-# UART (APBUART)
+# UART
+EXTRA_DIST += shared/uart/cons.c
+EXTRA_DIST += shared/uart/apbuart_cons.c
+EXTRA_DIST += shared/include/cons.h
EXTRA_DIST += shared/uart/apbuart.c
-EXTRA_DIST += shared/uart/apbuart_pci.c
-EXTRA_DIST += shared/uart/apbuart_rasta.c
EXTRA_DIST += shared/include/apbuart.h
-EXTRA_DIST += shared/include/apbuart_pci.h
-EXTRA_DIST += shared/include/apbuart_rasta.h
# CAN (OC_CAN, GRCAN)
EXTRA_DIST += shared/can/occan.c
-EXTRA_DIST += shared/can/occan_pci.c
EXTRA_DIST += shared/can/grcan.c
-EXTRA_DIST += shared/can/grcan_rasta.c
EXTRA_DIST += shared/include/occan.h
-EXTRA_DIST += shared/include/occan_pci.h
EXTRA_DIST += shared/include/grcan.h
-EXTRA_DIST += shared/include/grcan_rasta.h
+
+# MEM
+EXTRA_DIST += shared/mem/mctrl.c
+EXTRA_DIST += shared/mem/mctrl_rmap.c
# MIL-STD-B1553 (Core1553BRM)
EXTRA_DIST += shared/1553/b1553brm.c
-EXTRA_DIST += shared/1553/b1553brm_pci.c
-EXTRA_DIST += shared/1553/b1553brm_rasta.c
+EXTRA_DIST += shared/1553/b1553rt.c
EXTRA_DIST += shared/include/b1553brm.h
-EXTRA_DIST += shared/include/b1553brm_pci.h
-EXTRA_DIST += shared/include/b1553brm_rasta.h
+EXTRA_DIST += shared/include/b1553rt.h
+
+# MIL-STD-B1553 (GR1553B)
+EXTRA_DIST += shared/1553/gr1553b.c
+EXTRA_DIST += shared/1553/gr1553bc.c
+EXTRA_DIST += shared/1553/gr1553bm.c
+EXTRA_DIST += shared/1553/gr1553rt.c
+EXTRA_DIST += shared/include/gr1553b.h
+EXTRA_DIST += shared/include/gr1553bc.h
+EXTRA_DIST += shared/include/gr1553bc_list.h
+EXTRA_DIST += shared/include/gr1553bm.h
+EXTRA_DIST += shared/include/gr1553rt.h
# I2C-master (I2CMST)
EXTRA_DIST += shared/i2c/i2cmst.c
EXTRA_DIST += shared/include/i2cmst.h
+# SPI
+EXTRA_DIST += shared/spi/spictrl.c
+EXTRA_DIST += shared/include/spictrl.h
+
+# TIME
+EXTRA_DIST += shared/time/spwcuc.c
+EXTRA_DIST += shared/time/grctm.c
+EXTRA_DIST += shared/include/spwcuc.h
+EXTRA_DIST += shared/include/grctm.h
+
+# GPIO
+EXTRA_DIST += shared/gpio/grgpio.c
+EXTRA_DIST += shared/gpio/gpiolib.c
+EXTRA_DIST += shared/include/grgpio.h
+EXTRA_DIST += shared/include/gpiolib.h
+
+# PWM
+EXTRA_DIST += shared/pwm/grpwm.c
+EXTRA_DIST += shared/include/grpwm.h
+
+# ADC and DAC
+EXTRA_DIST += shared/analog/gradcdac.c
+EXTRA_DIST += shared/include/gradcdac.h
+
+# GRETH
+EXTRA_DIST += shared/net/greth.c
+EXTRA_DIST += shared/include/greth.h
+
+# Network configuration
+EXTRA_DIST += shared/net/network_interface_add.c
+EXTRA_DIST += shared/include/network_interface_add.h
+
+# Driver Manager
+EXTRA_DIST += shared/drvmgr/ambapp_bus.c
+EXTRA_DIST += shared/drvmgr/ambapp_bus_grlib.c
+EXTRA_DIST += shared/drvmgr/ambapp_bus_leon2.c
+EXTRA_DIST += shared/drvmgr/ambapp_bus_rmap.c
+EXTRA_DIST += shared/drvmgr/leon2_amba_bus.c
+EXTRA_DIST += shared/drvmgr/spw_bus.c
+
+EXTRA_DIST += shared/include/drvmgr/ambapp_bus_grlib.h
+EXTRA_DIST += shared/include/drvmgr/ambapp_bus_rmap.h
+EXTRA_DIST += shared/include/drvmgr/ambapp_bus.h
+EXTRA_DIST += shared/include/drvmgr/leon2_amba_bus.h
+EXTRA_DIST += shared/include/drvmgr/spw_bus.h
+EXTRA_DIST += shared/include/drvmgr/spw_bus_ids.h
+
+# GR712
+EXTRA_DIST += shared/ascs/grascs.c
+EXTRA_DIST += shared/include/grascs.h
+EXTRA_DIST += shared/can/satcan.c
+EXTRA_DIST += shared/include/satcan.h
+EXTRA_DIST += shared/slink/grslink.c
+EXTRA_DIST += shared/include/grslink.h
+
+# TMTC
+EXTRA_DIST += shared/tmtc/grtc.c
+EXTRA_DIST += shared/tmtc/grtc_rmap.c
+EXTRA_DIST += shared/include/grtc.h
+EXTRA_DIST += shared/tmtc/grtm.c
+EXTRA_DIST += shared/tmtc/grtm_rmap.c
+EXTRA_DIST += shared/include/grtm.h
+
include $(top_srcdir)/../../../automake/subdirs.am
include $(top_srcdir)/../../../automake/local.am
diff --git a/c/src/lib/libbsp/sparc/erc32/Makefile.am b/c/src/lib/libbsp/sparc/erc32/Makefile.am
index dd8bed26e0..fe36df054e 100644
--- a/c/src/lib/libbsp/sparc/erc32/Makefile.am
+++ b/c/src/lib/libbsp/sparc/erc32/Makefile.am
@@ -39,7 +39,8 @@ libbsp_a_SOURCES += ../../shared/bspclean.c ../../shared/bsplibc.c \
../../sparc/shared/bsppretaskinghook.c ../../shared/bsppost.c \
../../shared/bspstart.c ../../shared/bootcard.c \
../../shared/sbrk.c startup/setvec.c startup/spurious.c \
- startup/erc32mec.c startup/boardinit.S startup/bspidle.c
+ startup/erc32mec.c startup/boardinit.S startup/bspidle.c \
+ ../../sparc/shared/startup/early_malloc.c
# gnatsupp
libbsp_a_SOURCES += gnatsupp/gnatsupp.c ../../sparc/shared/gnatcommon.c
# console
diff --git a/c/src/lib/libbsp/sparc/erc32/include/bsp.h b/c/src/lib/libbsp/sparc/erc32/include/bsp.h
index 8655732e05..0ec160ae52 100644
--- a/c/src/lib/libbsp/sparc/erc32/include/bsp.h
+++ b/c/src/lib/libbsp/sparc/erc32/include/bsp.h
@@ -71,6 +71,10 @@ extern int end; /* last address in the program */
/* functions */
+/* set_vec type */
+#define SET_VECTOR_RAW 0 /* Raw trap handler */
+#define SET_VECTOR_INT 1 /* Trap handler with _ISR_Handler interrupt handler */
+
rtems_isr_entry set_vector( /* returns old vector */
rtems_isr_entry handler, /* isr routine */
rtems_vector_number vector, /* vector number */
@@ -81,6 +85,9 @@ void BSP_fatal_return( void );
void bsp_spurious_initialize( void );
+/* Allocate 8-byte aligned non-freeable pre-malloc memory */
+void *bsp_early_malloc(int size);
+
#ifdef __cplusplus
}
#endif
diff --git a/c/src/lib/libbsp/sparc/erc32/startup/setvec.c b/c/src/lib/libbsp/sparc/erc32/startup/setvec.c
index 3a7601d012..7e697a07cb 100644
--- a/c/src/lib/libbsp/sparc/erc32/startup/setvec.c
+++ b/c/src/lib/libbsp/sparc/erc32/startup/setvec.c
@@ -42,7 +42,7 @@ rtems_isr_entry set_vector( /* returns old vector */
uint32_t real_trap;
uint32_t source;
- if ( type )
+ if ( type == SET_VECTOR_INT )
rtems_interrupt_catch( handler, vector, &previous_isr );
else
_CPU_ISR_install_raw_handler( vector, handler, (void *)&previous_isr );
diff --git a/c/src/lib/libbsp/sparc/leon2/Makefile.am b/c/src/lib/libbsp/sparc/leon2/Makefile.am
index c751c60854..d5e80a49bc 100644
--- a/c/src/lib/libbsp/sparc/leon2/Makefile.am
+++ b/c/src/lib/libbsp/sparc/leon2/Makefile.am
@@ -12,24 +12,7 @@ dist_project_lib_DATA = bsp_specs
include_HEADERS = include/bsp.h
include_HEADERS += include/tm27.h
-include_HEADERS += include/rasta.h
-include_HEADERS += include/cchip.h
-include_HEADERS += ../../sparc/shared/include/ambapp.h
-include_HEADERS += ../../sparc/shared/include/grspw.h
-include_HEADERS += ../../sparc/shared/include/grspw_pci.h
-include_HEADERS += ../../sparc/shared/include/grspw_rasta.h
-include_HEADERS += ../../sparc/shared/include/occan.h
-include_HEADERS += ../../sparc/shared/include/occan_pci.h
-include_HEADERS += ../../sparc/shared/include/grcan.h
-include_HEADERS += ../../sparc/shared/include/grcan_rasta.h
-include_HEADERS += ../../sparc/shared/include/apbuart.h
-include_HEADERS += ../../sparc/shared/include/apbuart_pci.h
-include_HEADERS += ../../sparc/shared/include/apbuart_rasta.h
-include_HEADERS += ../../sparc/shared/include/b1553brm.h
-include_HEADERS += ../../sparc/shared/include/b1553brm_pci.h
-include_HEADERS += ../../sparc/shared/include/b1553brm_rasta.h
include_HEADERS += ../../sparc/shared/include/debug_defs.h
-include_HEADERS += ../../sparc/shared/include/pci.h
nodist_include_HEADERS = include/bspopts.h
nodist_include_bsp_HEADERS = ../../shared/include/bootcard.h
@@ -55,47 +38,167 @@ libbsp_a_SOURCES =
# startup
libbsp_a_SOURCES += ../../shared/bspclean.c ../../shared/bsplibc.c \
- ../../shared/bsppost.c ../../shared/bsppredriverhook.c \
+ ../../shared/bsppost.c startup/bsppredriver.c \
startup/bspstart.c ../../sparc/shared/bsppretaskinghook.c \
../../sparc/shared/bspgetworkarea.c ../../shared/bootcard.c \
- ../../shared/sbrk.c startup/setvec.c startup/spurious.c startup/bspidle.c
+ ../../shared/sbrk.c startup/setvec.c startup/spurious.c startup/bspidle.c \
+ ../../sparc/shared/startup/early_malloc.c
# gnatsupp
libbsp_a_SOURCES += gnatsupp/gnatsupp.c ../../sparc/shared/gnatcommon.c
# console
libbsp_a_SOURCES += console/console.c console/debugputs.c
# clock
libbsp_a_SOURCES += clock/ckinit.c ../../../shared/clockdrv_shell.h
-# AMBA PnP Scanning
+# IRQ
+include_HEADERS += ../../sparc/shared/include/genirq.h
+libbsp_a_SOURCES += ../../sparc/shared/irq/genirq.c
+include_bsp_HEADERS = \
+ ../../shared/include/irq-generic.h \
+ ../../shared/include/irq-info.h \
+ include/bsp/irq.h
+libbsp_a_SOURCES += \
+ ../../sparc/shared/irq/irq-shared.c \
+ ../../shared/src/irq-generic.c \
+ ../../shared/src/irq-legacy.c \
+ ../../shared/src/irq-info.c \
+ ../../shared/src/irq-shell.c \
+ ../../shared/src/irq-server.c
+
+# AMBA bus
+include_HEADERS += ../../sparc/shared/include/ambapp.h
+include_HEADERS += ../../sparc/shared/include/ambapp_ids.h
+include_HEADERS += ../../sparc/shared/include/grlib.h
+include_HEADERS += ../../sparc/shared/include/ahbstat.h
libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp.c
+libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp_alloc.c
+libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp_count.c
+libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp_depth.c
+libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp_find_by_idx.c
+libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp_freq.c
+libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp_parent.c
+libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp_old.c
+libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp_names.c
+libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp_show.c
+libbsp_a_SOURCES += ../../sparc/shared/amba/ahbstat.c
+
+# Clock Driver and Timer Library
+include_HEADERS += ../../sparc/shared/include/tlib.h
+libbsp_a_SOURCES += ../../sparc/shared/timer/gptimer.c
+libbsp_a_SOURCES += ../../sparc/shared/timer/tlib.c
+
# PCI
-libbsp_a_SOURCES += pci/pci.c ../../sparc/shared/pci/pcifinddevice.c
-# RASTA Kit
-libbsp_a_SOURCES += rasta/rasta.c
-# Companion Chip Kit
-libbsp_a_SOURCES += cchip/cchip.c
+include_HEADERS += ../../sparc/shared/include/grpci2.h
+libbsp_a_SOURCES += ../../sparc/shared/pci/grpci2.c
+libbsp_a_SOURCES += ../../sparc/shared/pci/grpci.c
+libbsp_a_SOURCES += ../../sparc/shared/pci/pcif.c
+libbsp_a_SOURCES += ../../sparc/shared/pci/pci_memreg_sparc_le.c
+libbsp_a_SOURCES += ../../sparc/shared/pci/pci_memreg_sparc_be.c
+libbsp_a_SOURCES += pci/at697_pci.c
+
+# PCI target devices
+include_HEADERS += ../../sparc/shared/include/gr_701.h
+include_HEADERS += ../../sparc/shared/include/gr_rasta_adcdac.h
+include_HEADERS += ../../sparc/shared/include/gr_rasta_io.h
+include_HEADERS += ../../sparc/shared/include/gr_rasta_tmtc.h
+libbsp_a_SOURCES += ../../sparc/shared/pci/gr_701.c
+libbsp_a_SOURCES += ../../sparc/shared/pci/gr_rasta_adcdac.c
+libbsp_a_SOURCES += ../../sparc/shared/pci/gr_rasta_io.c
+libbsp_a_SOURCES += ../../sparc/shared/pci/gr_rasta_spw_router.c
+libbsp_a_SOURCES += ../../sparc/shared/pci/gr_rasta_tmtc.c
+
# B1553BRM
-libbsp_a_SOURCES += ../../sparc/shared/1553/b1553brm.c \
- ../../sparc/shared/1553/b1553brm_pci.c \
- ../../sparc/shared/1553/b1553brm_rasta.c
+include_HEADERS += ../../sparc/shared/include/b1553brm.h
+include_HEADERS += ../../sparc/shared/include/b1553rt.h
+libbsp_a_SOURCES += ../../sparc/shared/1553/b1553brm.c
+libbsp_a_SOURCES += ../../sparc/shared/1553/b1553rt.c
+
+# GR1553B
+include_HEADERS += ../../sparc/shared/include/gr1553b.h
+include_HEADERS += ../../sparc/shared/include/gr1553bc.h
+include_HEADERS += ../../sparc/shared/include/gr1553bc_list.h
+include_HEADERS += ../../sparc/shared/include/gr1553bm.h
+include_HEADERS += ../../sparc/shared/include/gr1553rt.h
+libbsp_a_SOURCES += ../../sparc/shared/1553/gr1553b.c
+libbsp_a_SOURCES += ../../sparc/shared/1553/gr1553bc.c
+libbsp_a_SOURCES += ../../sparc/shared/1553/gr1553bm.c
+libbsp_a_SOURCES += ../../sparc/shared/1553/gr1553rt.c
+
# CAN
+include_HEADERS += ../../sparc/shared/include/occan.h
+include_HEADERS += ../../sparc/shared/include/grcan.h
libbsp_a_SOURCES += ../../sparc/shared/can/occan.c \
- ../../sparc/shared/can/occan_pci.c \
- ../../sparc/shared/can/grcan.c \
- ../../sparc/shared/can/grcan_rasta.c
+ ../../sparc/shared/can/grcan.c
+
# SpaceWire
-libbsp_a_SOURCES += ../../sparc/shared/spw/grspw.c \
- ../../sparc/shared/spw/grspw_pci.c ../../sparc/shared/spw/grspw_rasta.c
+include_HEADERS += ../../sparc/shared/include/grspw.h
+include_HEADERS += ../../sparc/shared/include/grspw_router.h
+include_HEADERS += ../../sparc/shared/include/rmap.h
+include_HEADERS += ../../sparc/shared/include/rmap_drv_grspw.h
+libbsp_a_SOURCES += ../../sparc/shared/spw/grspw.c
+libbsp_a_SOURCES += ../../sparc/shared/spw/grspw_router.c
+libbsp_a_SOURCES += ../../sparc/shared/spw/rmap.c
+libbsp_a_SOURCES += ../../sparc/shared/spw/rmap_drv_grspw.c
+
# UART (RAW)
-libbsp_a_SOURCES += ../../sparc/shared/uart/apbuart.c \
- ../../sparc/shared/uart/apbuart_pci.c \
- ../../sparc/shared/uart/apbuart_rasta.c
+include_HEADERS += ../../sparc/shared/include/apbuart.h
+libbsp_a_SOURCES += ../../sparc/shared/uart/apbuart.c
+
# I2CMST
include_HEADERS += ../../sparc/shared/include/i2cmst.h
libbsp_a_SOURCES += ../../sparc/shared/i2c/i2cmst.c
+# SPI
+include_HEADERS += ../../sparc/shared/include/spictrl.h
+libbsp_a_SOURCES += ../../sparc/shared/spi/spictrl.c
+
+# TIME
+include_HEADERS += ../../sparc/shared/include/spwcuc.h
+include_HEADERS += ../../sparc/shared/include/grctm.h
+libbsp_a_SOURCES += ../../sparc/shared/time/spwcuc.c
+libbsp_a_SOURCES += ../../sparc/shared/time/grctm.c
+
+# GPIO
+include_HEADERS += ../../sparc/shared/include/grgpio.h
+include_HEADERS += ../../sparc/shared/include/gpiolib.h
+libbsp_a_SOURCES += ../../sparc/shared/gpio/grgpio.c
+libbsp_a_SOURCES += ../../sparc/shared/gpio/gpiolib.c
+
+# PWM
+include_HEADERS += ../../sparc/shared/include/grpwm.h
+libbsp_a_SOURCES += ../../sparc/shared/pwm/grpwm.c
+
+# ADC and DAC
+include_HEADERS += ../../sparc/shared/include/gradcdac.h
+libbsp_a_SOURCES += ../../sparc/shared/analog/gradcdac.c
+
+# Memory controllers
+libbsp_a_SOURCES += ../../sparc/shared/mem/mctrl.c
+libbsp_a_SOURCES += ../../sparc/shared/mem/mctrl_rmap.c
+
# timer
libbsp_a_SOURCES += timer/timer.c
+# TM/TC
+include_HEADERS += ../../sparc/shared/include/grtc.h
+include_HEADERS += ../../sparc/shared/include/grtm.h
+libbsp_a_SOURCES += ../../sparc/shared/tmtc/grtc.c
+libbsp_a_SOURCES += ../../sparc/shared/tmtc/grtc_rmap.c
+libbsp_a_SOURCES += ../../sparc/shared/tmtc/grtm.c
+libbsp_a_SOURCES += ../../sparc/shared/tmtc/grtm_rmap.c
+
+# Driver Manager
+include_drvmgrdir = $(includedir)/drvmgr
+include_drvmgr_HEADERS = ../../sparc/shared/include/drvmgr/ambapp_bus.h
+include_drvmgr_HEADERS += ../../sparc/shared/include/drvmgr/ambapp_bus_rmap.h
+include_drvmgr_HEADERS += ../../sparc/shared/include/drvmgr/leon2_amba_bus.h
+include_drvmgr_HEADERS += ../../sparc/shared/include/drvmgr/spw_bus.h
+include_drvmgr_HEADERS += ../../sparc/shared/include/drvmgr/spw_bus_ids.h
+libbsp_a_SOURCES += ../../sparc/shared/drvmgr/ambapp_bus.c
+libbsp_a_SOURCES += ../../sparc/shared/drvmgr/ambapp_bus_leon2.c
+libbsp_a_SOURCES += ../../sparc/shared/drvmgr/ambapp_bus_rmap.c
+libbsp_a_SOURCES += ../../sparc/shared/drvmgr/leon2_amba_bus.c
+libbsp_a_SOURCES += ../../sparc/shared/drvmgr/spw_bus.c
+
if HAS_NETWORKING
noinst_PROGRAMS += leon_smc91111.rel
leon_smc91111_rel_SOURCES = leon_smc91111/leon_smc91111.c
@@ -112,12 +215,27 @@ leon_open_eth_rel_CPPFLAGS += -D__INSIDE_RTEMS_BSD_TCPIP_STACK__
leon_open_eth_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
endif
+if HAS_NETWORKING
+noinst_PROGRAMS += leon_greth.rel
+leon_greth_rel_SOURCES = ../../sparc/shared/net/greth.c
+include_HEADERS += ../../sparc/shared/include/greth.h
+leon_greth_rel_CPPFLAGS = $(AM_CPPFLAGS)
+leon_greth_rel_CPPFLAGS += -D__INSIDE_RTEMS_BSD_TCPIP_STACK__
+leon_greth_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
+
+# BSP Network configuration
+include_HEADERS += ../../sparc/shared/include/network_interface_add.h
+libbsp_a_SOURCES += ../../sparc/shared/net/network_interface_add.c
+endif
+
libbsp_a_LIBADD = \
+ ../../../libcpu/@RTEMS_CPU@/access.rel \
../../../libcpu/@RTEMS_CPU@/cache.rel \
../../../libcpu/@RTEMS_CPU@/reg_win.rel \
../../../libcpu/@RTEMS_CPU@/syscall.rel
if HAS_NETWORKING
+libbsp_a_LIBADD += leon_greth.rel
libbsp_a_LIBADD += leon_open_eth.rel
libbsp_a_LIBADD += leon_smc91111.rel
endif
diff --git a/c/src/lib/libbsp/sparc/leon2/cchip/cchip.c b/c/src/lib/libbsp/sparc/leon2/cchip/cchip.c
deleted file mode 100644
index e0c6364c66..0000000000
--- a/c/src/lib/libbsp/sparc/leon2/cchip/cchip.c
+++ /dev/null
@@ -1,358 +0,0 @@
-/*
- * $Id$
- */
-
-#include <bsp.h>
-#include <rtems/bspIo.h>
-#include <rtems.h>
-#include <string.h>
-
-#include <rtems.h>
-#include <leon.h>
-#include <ambapp.h>
-#include <pci.h>
-
-#include <b1553brm_pci.h>
-#include <occan_pci.h>
-#include <grspw_pci.h>
-#include <apbuart_pci.h>
-
-#include <cchip.h>
-
-/*
-#define DEBUG
-#define DEBUG_IRQS
-*/
-#define BOARD_INFO
-/*#define PRINT_SPURIOUS*/
-
-/* AT697 Register MAP */
-static LEON_Register_Map *regs = (LEON_Register_Map *)0x80000000;
-
-/* initializes interrupt management for companionship board */
-void cchip1_irq_init(void);
-
-/* register interrupt handler (called from drivers) */
-void cchip1_set_isr(void *handler, int irqno, void *arg);
-
-#define READ_REG(address) _READ_REG((unsigned int)address)
-static __inline__ unsigned int _READ_REG(unsigned int addr) {
- unsigned int tmp;
- asm("lda [%1]1, %0 "
- : "=r"(tmp)
- : "r"(addr)
- );
- return tmp;
-}
-
-/* PCI bride reg layout on AMBA side */
-typedef struct {
- unsigned int bar0;
- unsigned int bar1;
- unsigned int bar2;
- unsigned int bar3;
- unsigned int bar4;/* 0x10 */
-
- unsigned int unused[4*3-1];
-
- unsigned int ambabars[1]; /* 0x40 */
-} amba_bridge_regs;
-
-/* PCI bride reg layout on PCI side */
-typedef struct {
- unsigned int bar0;
- unsigned int bar1;
- unsigned int bar2;
- unsigned int bar3;
- unsigned int bar4; /* 0x10 */
-
- unsigned int ilevel;
- unsigned int ipend;
- unsigned int iforce;
- unsigned int istatus;
- unsigned int iclear;
- unsigned int imask;
-} pci_bridge_regs;
-
-typedef struct {
- pci_bridge_regs *pcib;
- amba_bridge_regs *ambab;
-
- /* AT697 PCI */
- unsigned int bars[5];
- int bus, dev, fun;
-
- /* AMBA bus */
- amba_confarea_type amba_bus;
- struct amba_mmap amba_maps[2];
-
- /* FT AHB SRAM */
- int ftsram_size; /* kb */
- unsigned int ftsram_start;
- unsigned int ftsram_end;
-
-} cchip1;
-
-cchip1 cc1;
-
-int init_pcif(void){
- unsigned int com1;
- int i,bus,dev,fun;
- pci_bridge_regs *pcib;
- amba_bridge_regs *ambab;
- int amba_master_cnt;
- amba_confarea_type *abus;
-
- if ( BSP_pciFindDevice(0x1AC8, 0x0701, 0, &bus, &dev, &fun) == 0 ) {
- ;
- }else if (BSP_pciFindDevice(0x16E3, 0x0210, 0, &bus, &dev, &fun) == 0) {
- ;
- } else {
- /* didn't find any Companionship board on the PCI bus. */
- return -1;
- }
-
- /* found Companionship PCI board, Set it up: */
-
- pci_read_config_dword(bus, dev, fun, 0x10, &cc1.bars[0]);
- pci_read_config_dword(bus, dev, fun, 0x14, &cc1.bars[1]);
- pci_read_config_dword(bus, dev, fun, 0x18, &cc1.bars[2]);
- pci_read_config_dword(bus, dev, fun, 0x1c, &cc1.bars[3]);
- pci_read_config_dword(bus, dev, fun, 0x20, &cc1.bars[4]);
-
-#ifdef DEBUG
- for(i=0; i<5; i++){
- printk("PCI: BAR%d: 0x%x\n\r",i,cc1.bars[i]);
- }
-#endif
-
- /* Set up PCI ==> AMBA */
- pcib = (void *)cc1.bars[0];
- pcib->bar0 = 0xfc000000;
-/* pcib->bar1 = 0xff000000;*/
-#ifdef BOARD_INFO
- printk("Found CCHIP1 Board at 0x%lx\n\r",(unsigned int)pcib);
-#endif
-
- /* AMBA MAP cc1.bars[1] (in CPU) ==> 0xf0000000(remote amba address) */
- cc1.amba_maps[0].size = 0x04000000;
- cc1.amba_maps[0].cpu_adr = cc1.bars[1];
- cc1.amba_maps[0].remote_amba_adr = 0xfc000000;
-
- /* Mark end of table */
- cc1.amba_maps[1].size=0;
- cc1.amba_maps[1].cpu_adr = 0;
- cc1.amba_maps[1].remote_amba_adr = 0;
-
- /* Enable I/O and Mem accesses */
- pci_read_config_dword(bus, dev, fun, 0x4, &com1);
- com1 |= 0x3;
- pci_write_config_dword(bus, dev, fun, 0x4, com1);
- pci_read_config_dword(bus, dev, fun, 0x4, &com1);
-
- /* Set up AMBA Masters ==> PCI */
- ambab = (void *)(cc1.bars[1]+0x400);
-#ifdef DEBUG
- printk("AMBA: PCIBAR[%d]: 0x%x, 0x%x\n\r",0,ambab->bar0,pcib->bar0);
- printk("AMBA: PCIBAR[%d]: 0x%x, 0x%x\n\r",1,ambab->bar1,pcib->bar1);
- printk("AMBA: PCIBAR[%d]: 0x%x, 0x%x\n\r",2,ambab->bar2,pcib->bar2);
-#endif
- ambab->ambabars[0] = 0x40000000; /* 0xe0000000(AMBA) ==> 0x40000000(PCI) ==> 0x40000000(AT697 AMBA) */
-
- /* Scan bus for AMBA devices */
- abus = &cc1.amba_bus;
- memset(abus,0,sizeof(amba_confarea_type));
- amba_scan(abus,cc1.bars[1]+0x3f00000,&cc1.amba_maps[0]);
-
- /* Get number of amba masters */
- amba_master_cnt = abus->ahbmst.devnr;
-#ifdef BOARD_INFO
- printk("Found %d AMBA masters\n\r",amba_master_cnt);
-#endif
- for(i=1; i<amba_master_cnt; i++){
- ambab->ambabars[i] = 0x40000000;
- }
-
- /* Enable PCI Master */
- pci_read_config_dword(bus, dev, fun, 0x4, &com1);
- com1 |= 0x4;
- pci_write_config_dword(bus, dev, fun, 0x4, com1);
- pci_read_config_dword(bus, dev, fun, 0x4, &com1);
-
- cc1.pcib = pcib;
- cc1.ambab = ambab;
- cc1.bus = bus;
- cc1.dev = dev;
- cc1.fun = fun;
-
- return 0;
-}
-
-#ifndef GAISLER_FTAHBRAM
- #define GAISLER_FTAHBRAM 0x50
-#endif
-int init_onboard_sram(void){
- amba_ahb_device ahb;
- amba_apb_device apb;
- unsigned int conf, size;
-
- /* Find SRAM controller
- * 1. AHB slave interface
- * 2. APB slave interface
- */
- if ( amba_find_apbslv(&cc1.amba_bus,VENDOR_GAISLER,GAISLER_FTAHBRAM,&apb) != 1 ){
- printk("On Board FT SRAM not found (APB)\n");
- return -1;
- }
-
- if ( amba_find_ahbslv(&cc1.amba_bus,VENDOR_GAISLER,GAISLER_FTAHBRAM,&ahb) != 1 ){
- printk("On Board FT SRAM not found (AHB)\n");
- return -1;
- }
-
- /* We have found the controller.
- * Get it going.
- *
- * Get size of SRAM
- */
- conf = *(unsigned int *)apb.start;
- size = (conf >>10) & 0x7;
-
- /* 2^x kb */
- cc1.ftsram_size = 1<<size;
- cc1.ftsram_start = ahb.start[0];
- cc1.ftsram_end = size*1024 + cc1.ftsram_start;
-#ifdef BOARD_INFO
- printk("Found FT AHB SRAM %dkb at 0x%lx\n",cc1.ftsram_size,cc1.ftsram_start);
-#endif
- return 0;
-}
-
-int cchip1_register(void){
-
- /* Init AT697 PCI Controller */
- init_pci();
-
- /* Find & init CChip board .
- * Also scan AMBA Plug&Play info for us.
- */
- if ( init_pcif() ){
- printk("Failed to initialize CCHIP board\n\r");
- return -1;
- }
-
- /* Set interrupt common board stuff */
- cchip1_irq_init();
-
- /* Find on board SRAM */
- if ( init_onboard_sram() ){
- printk("Failed to register On Board SRAM. It is needed by b1553BRM\n");
- return -1;
- }
-
- /* Register interrupt install functions */
- b1553brm_pci_int_reg = cchip1_set_isr;
- occan_pci_int_reg = cchip1_set_isr;
- grspw_pci_int_reg = cchip1_set_isr;
- apbuart_pci_int_reg = cchip1_set_isr;
-
- /* register the BRM PCI driver, use 16k FTSRAM... */
- if ( b1553brm_pci_register(&cc1.amba_bus,0,0,3,cc1.ftsram_start,0xffa00000) ){
- printk("Failed to register BRM PCI driver\n");
- return -1;
- }
-
- /* register the BRM PCI driver, no DMA memory... */
- if ( occan_pci_register(&cc1.amba_bus) ){
- printk("Failed to register OC_CAN PCI driver\n");
- return -1;
- }
-
- /* register the GRSPW PCI driver, use malloc... */
- if ( grspw_pci_register(&cc1.amba_bus,0,0xe0000000) ){
- printk("Failed to register GRSPW PCI driver\n");
- return -1;
- }
-
- /* register the APBUART PCI driver, no DMA memory */
- if ( apbuart_pci_register(&cc1.amba_bus) ){
- printk("Failed to register APBUART PCI driver\n");
- return -1;
- }
-
- return 0;
-}
-
-static rtems_isr cchip1_interrupt_dispatcher(rtems_vector_number v);
-static unsigned int cchip1_spurious_cnt;
-
-typedef struct {
- unsigned int (*handler)(int irqno, void *arg);
- void *arg;
-} int_handler;
-
-static int_handler int_handlers[16];
-
-void cchip1_irq_init(void){
-
- /* Configure AT697 ioport bit 7 to input pci irq */
- regs->PIO_Direction &= ~(1<<7);
- regs->PIO_Interrupt = 0x87; /* level sensitive */
-
- /* Set up irq controller (mask all IRQs) */
- cc1.pcib->imask = 0x0000;
- cc1.pcib->ipend = 0;
- cc1.pcib->iclear = 0xffff;
- cc1.pcib->iforce = 0;
- cc1.pcib->ilevel = 0x0;
-
- memset(int_handlers,0,sizeof(int_handlers));
-
- /* Reset spurious counter */
- cchip1_spurious_cnt = 0;
-
- /* Register interrupt handler */
- set_vector(cchip1_interrupt_dispatcher,LEON_TRAP_TYPE(CCHIP_IRQ),1);
-}
-
-void cchip1_set_isr(void *handler, int irqno, void *arg){
- int_handlers[irqno].handler = handler;
- int_handlers[irqno].arg = arg;
-#ifdef DEBUG
- printk("Registering IRQ %d to 0x%lx(%d,0x%lx)\n\r",irqno,(unsigned int)handler,irqno,(unsigned int)arg);
-#endif
- cc1.pcib->imask |= 1<<irqno; /* Enable the registered IRQ */
-}
-
-static rtems_isr cchip1_interrupt_dispatcher(rtems_vector_number v){
- unsigned int pending = READ_REG(&cc1.pcib->ipend);
- unsigned int (*handler)(int irqno, void *arg);
- unsigned int clr = pending;
- int irq=1;
-
- if ( !pending ){
-#ifdef PRINT_SPURIOUS
- printk("Spurious IRQ %d: %d\n",v,cchip1_spurious_cnt);
-#endif
- cchip1_spurious_cnt++;
- return;
- }
-#ifdef DEBUG_IRQS
- printk("CCIRQ: 0x%x\n",(unsigned int)pending);
-#endif
- /* IRQ 0 doesn't exist */
- irq=1;
- pending = pending>>1;
-
- while ( pending ){
- if ( (pending & 1) && (handler=int_handlers[irq].handler) ){
- handler(irq,int_handlers[irq].arg);
- }
- irq++;
- pending = pending>>1;
- }
-
- cc1.pcib->iclear = clr;
-
- /*LEON_Clear_interrupt( brd->irq );*/
-}
diff --git a/c/src/lib/libbsp/sparc/leon2/console/console.c b/c/src/lib/libbsp/sparc/leon2/console/console.c
index 91a1daa739..7f4d1cfdaf 100644
--- a/c/src/lib/libbsp/sparc/leon2/console/console.c
+++ b/c/src/lib/libbsp/sparc/leon2/console/console.c
@@ -69,7 +69,7 @@ int console_inbyte_nonblocking( int port );
* Buffers between task and ISRs
*/
-#include <ringbuf.h>
+#include <rtems/ringbuf.h>
Ring_buffer_t TX_Buffer[ 2 ];
bool Is_TX_active[ 2 ];
diff --git a/c/src/lib/libbsp/sparc/leon2/console/debugputs.c b/c/src/lib/libbsp/sparc/leon2/console/debugputs.c
index ffd489b4a6..ae17248f12 100644
--- a/c/src/lib/libbsp/sparc/leon2/console/debugputs.c
+++ b/c/src/lib/libbsp/sparc/leon2/console/debugputs.c
@@ -29,14 +29,23 @@ void console_outbyte_polled(
unsigned char ch
)
{
+send:
if ( port == 0 ) {
while ( (LEON_REG.UART_Status_1 & LEON_REG_UART_STATUS_THE) == 0 );
LEON_REG.UART_Channel_1 = (unsigned int) ch;
+ if ( ch == '\n' ) {
+ ch = '\r';
+ goto send;
+ }
return;
}
while ( (LEON_REG.UART_Status_2 & LEON_REG_UART_STATUS_THE) == 0 );
LEON_REG.UART_Channel_2 = (unsigned int) ch;
+ if ( ch == '\n' ) {
+ ch = '\r';
+ goto send;
+ }
}
/*
diff --git a/c/src/lib/libbsp/sparc/leon2/include/bsp.h b/c/src/lib/libbsp/sparc/leon2/include/bsp.h
index 34e31ce206..a5aeeb3ba0 100644
--- a/c/src/lib/libbsp/sparc/leon2/include/bsp.h
+++ b/c/src/lib/libbsp/sparc/leon2/include/bsp.h
@@ -32,6 +32,7 @@ extern "C" {
#include <leon.h>
#include <rtems/clockdrv.h>
#include <rtems/console.h>
+#include <rtems/irq-extension.h>
/* SPARC CPU variant: LEON2 */
#define LEON2 1
@@ -58,6 +59,9 @@ extern int rtems_smc91111_driver_attach_leon2(
#define RTEMS_BSP_NETWORK_DRIVER_ATTACH_SMC91111 \
rtems_smc91111_driver_attach_leon2
+#define GRETH_SUPPORTED
+#define GRETH_MEM_LOAD(addr) leon_r32_no_cache(addr)
+
/*
* The synchronous trap is an arbitrarily chosen software trap.
*/
@@ -84,6 +88,10 @@ extern int end; /* last address in the program */
/* miscellaneous stuff assumed to exist */
+/* set_vec type */
+#define SET_VECTOR_RAW 0 /* Raw trap handler */
+#define SET_VECTOR_INT 1 /* Trap handler with _ISR_Handler interrupt handler */
+
rtems_isr_entry set_vector( /* returns old vector */
rtems_isr_entry handler, /* isr routine */
rtems_vector_number vector, /* vector number */
@@ -94,6 +102,102 @@ void BSP_fatal_return( void );
void bsp_spurious_initialize( void );
+/* Allocate 8-byte aligned non-freeable pre-malloc memory */
+void *bsp_early_malloc(int size);
+
+/* Interrupt Service Routine (ISR) pointer */
+typedef void (*bsp_shared_isr)(void *arg);
+
+/* Initializes the Shared System Interrupt service */
+extern int BSP_shared_interrupt_init(void);
+
+/* Registers a shared IRQ handler, and enable it at IRQ controller. Multiple
+ * interrupt handlers may use the same IRQ number, all ISRs will be called
+ * when an interrupt on that line is fired.
+ *
+ * Arguments
+ * irq System IRQ number
+ * info Optional Name of IRQ source
+ * isr Function pointer to the ISR
+ * arg Second argument to function isr
+ */
+static __inline__ int BSP_shared_interrupt_register
+ (
+ int irq,
+ const char *info,
+ bsp_shared_isr isr,
+ void *arg
+ )
+{
+ return rtems_interrupt_handler_install(irq, info,
+ RTEMS_INTERRUPT_SHARED, isr, arg);
+}
+
+/* Unregister previously registered shared IRQ handler.
+ *
+ * Arguments
+ * irq System IRQ number
+ * isr Function pointer to the ISR
+ * arg Second argument to function isr
+ */
+static __inline__ int BSP_shared_interrupt_unregister
+ (
+ int irq,
+ bsp_shared_isr isr,
+ void *arg
+ )
+{
+ return rtems_interrupt_handler_remove(irq, isr, arg);
+}
+
+/* Clear interrupt pending on IRQ controller, this is typically done on a
+ * level triggered interrupt source such as PCI to avoid taking double IRQs.
+ * In such a case the interrupt source must be cleared first on LEON, before
+ * acknowledging the IRQ with this function.
+ *
+ * Arguments
+ * irq System IRQ number
+ */
+extern void BSP_shared_interrupt_clear(int irq);
+
+/* Enable Interrupt. This function will unmask the IRQ at the interrupt
+ * controller. This is normally done by _register(). Note that this will
+ * affect all ISRs on this IRQ.
+ *
+ * Arguments
+ * irq System IRQ number
+ */
+extern void BSP_shared_interrupt_unmask(int irq);
+
+/* Disable Interrupt. This function will mask one IRQ at the interrupt
+ * controller. This is normally done by _unregister(). Note that this will
+ * affect all ISRs on this IRQ.
+ *
+ * Arguments
+ * irq System IRQ number
+ */
+extern void BSP_shared_interrupt_mask(int irq);
+
+/* BSP PCI Interrupt support */
+#define BSP_PCI_shared_interrupt_register BSP_shared_interrupt_register
+#define BSP_PCI_shared_interrupt_unregister BSP_shared_interrupt_unregister
+#define BSP_PCI_shared_interrupt_unmask BSP_shared_interrupt_unmask
+#define BSP_PCI_shared_interrupt_mask BSP_shared_interrupt_mask
+#define BSP_PCI_shared_interrupt_clear BSP_shared_interrupt_clear
+
+/* AT697 has PCI defined as big endian */
+#define BSP_PCI_BIG_ENDIAN
+
+/* Common driver build-time configurations. On small systems undefine
+ * [DRIVER]_INFO_AVAIL to avoid info routines get dragged in. It is good
+ * for debugging and printing information about the system, but makes the
+ * image bigger.
+ */
+#define AMBAPPBUS_INFO_AVAIL /* AMBAPP Bus driver */
+#define GPTIMER_INFO_AVAIL /* GPTIMER Timer driver */
+#define GRETH_INFO_AVAIL /* GRETH Ethernet driver */
+#define GRTC_RMAP_INFO_AVAIL /* GRTC over SpaceWire/RMAP driver */
+
#ifdef __cplusplus
}
#endif
diff --git a/c/src/lib/libbsp/sparc/leon2/include/bsp/irq.h b/c/src/lib/libbsp/sparc/leon2/include/bsp/irq.h
new file mode 100644
index 0000000000..709b5631aa
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/leon2/include/bsp/irq.h
@@ -0,0 +1,20 @@
+/* LEON2 generic shared IRQ setup
+ *
+ * Based on libbsp/shared/include/irq.h.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#ifndef LIBBSP_LEON2_IRQ_CONFIG_H
+#define LIBBSP_LEON2_IRQ_CONFIG_H
+
+#define BSP_INTERRUPT_VECTOR_MAX_STD 15 /* Standard IRQ controller */
+#define BSP_INTERRUPT_VECTOR_MIN 0
+#define BSP_INTERRUPT_VECTOR_MAX BSP_INTERRUPT_VECTOR_MAX_STD
+
+/* No extra check is needed */
+#undef BSP_INTERRUPT_CUSTOM_VALID_VECTOR
+
+#endif /* LIBBSP_LEON2_IRQ_CONFIG_H */
diff --git a/c/src/lib/libbsp/sparc/leon2/include/cchip.h b/c/src/lib/libbsp/sparc/leon2/include/cchip.h
deleted file mode 100644
index 5136f9452c..0000000000
--- a/c/src/lib/libbsp/sparc/leon2/include/cchip.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * $Id$
- */
-
-#ifndef __CCHIP_H__
-#define __CCHIP_H__
-
-#include <b1553brm_pci.h>
-#include <occan_pci.h>
-#include <grspw_pci.h>
-#include <apbuart_pci.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define CCHIP_IRQ 4
-
-/* Register all drivers supported by the Companion Chip board */
-int cchip_register(void);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/c/src/lib/libbsp/sparc/leon2/include/leon.h b/c/src/lib/libbsp/sparc/leon2/include/leon.h
index 168ebe5b52..4ff53060f8 100644
--- a/c/src/lib/libbsp/sparc/leon2/include/leon.h
+++ b/c/src/lib/libbsp/sparc/leon2/include/leon.h
@@ -271,6 +271,11 @@ typedef struct {
extern LEON_Register_Map LEON_REG;
+static __inline__ int leon_irq_fixup(int irq)
+{
+ return irq;
+}
+
/*
* Macros to manipulate the Interrupt Clear, Interrupt Force, Interrupt Mask,
* and the Interrupt Pending Registers.
@@ -369,6 +374,14 @@ extern LEON_Register_Map LEON_REG;
#define LEON_REG_TIMER_COUNTER_DEFINED_MASK 0x00000003
#define LEON_REG_TIMER_COUNTER_CURRENT_MODE_MASK 0x00000003
+/* Load 32-bit word by forcing a cache-miss */
+static inline unsigned int leon_r32_no_cache(unsigned int addr)
+{
+ unsigned int tmp;
+ asm volatile (" lda [%1] 1, %0\n" : "=r"(tmp) : "r"(addr) );
+ return tmp;
+}
+
#endif /* !ASM */
#ifdef __cplusplus
diff --git a/c/src/lib/libbsp/sparc/leon2/include/rasta.h b/c/src/lib/libbsp/sparc/leon2/include/rasta.h
deleted file mode 100644
index 751ec3eb8e..0000000000
--- a/c/src/lib/libbsp/sparc/leon2/include/rasta.h
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * $Id$
- */
-
-#ifndef __RASTA_H__
-#define __RASTA_H__
-
-#include <bsp.h>
-
-#include <grcan.h>
-#include <b1553brm_rasta.h>
-#include <grspw.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-extern int rasta_register(void);
-
-/* Address of PCI bus on RASTA local AMBA bus */
-#define RASTA_PCI_BASE 0xe0000000
-
-/* Address of SRAM on RASTA local AMBA bus */
-#define RASTA_LOCAL_SRAM 0x40000000
-
-#define UART0_IRQNO 2
-#define UART1_IRQNO 3
-#define GRCAN_IRQNO 7
-#define SPW0_IRQNO 10
-#define SPW1_IRQNO 11
-#define SPW2_IRQNO 12
-#define BRM_IRQNO 13
-
-#define GRCAN_IRQ (3<<GRCAN_IRQNO)
-#define SPW0_IRQ (1<<SPW0_IRQNO)
-#define SPW1_IRQ (1<<SPW1_IRQNO)
-#define SPW2_IRQ (1<<SPW2_IRQNO)
-#define SPW_IRQ (7<<SPW0_IRQNO)
-#define BRM_IRQ (1<<BRM_IRQNO)
-#define UART0_IRQ (1<<UART0_IRQNO)
-#define UART1_IRQ (1<<UART1_IRQNO)
-
-/*
- * The following defines the bits in the UART Control Registers.
- *
- */
-#define LEON_REG_UART_CONTROL_RTD 0x000000FF /* RX/TX data */
-
-/*
- * The following defines the bits in the LEON UART Status Registers.
- */
-#define LEON_REG_UART_STATUS_DR 0x00000001 /* Data Ready */
-#define LEON_REG_UART_STATUS_TSE 0x00000002 /* TX Send Register Empty */
-#define LEON_REG_UART_STATUS_THE 0x00000004 /* TX Hold Register Empty */
-#define LEON_REG_UART_STATUS_BR 0x00000008 /* Break Error */
-#define LEON_REG_UART_STATUS_OE 0x00000010 /* RX Overrun Error */
-#define LEON_REG_UART_STATUS_PE 0x00000020 /* RX Parity Error */
-#define LEON_REG_UART_STATUS_FE 0x00000040 /* RX Framing Error */
-#define LEON_REG_UART_STATUS_ERR 0x00000078 /* Error Mask */
-
-
-/*
- * The following defines the bits in the LEON UART Status Registers.
- */
-#define LEON_REG_UART_CTRL_RE 0x00000001 /* Receiver enable */
-#define LEON_REG_UART_CTRL_TE 0x00000002 /* Transmitter enable */
-#define LEON_REG_UART_CTRL_RI 0x00000004 /* Receiver interrupt enable */
-#define LEON_REG_UART_CTRL_TI 0x00000008 /* Transmitter interrupt enable */
-#define LEON_REG_UART_CTRL_PS 0x00000010 /* Parity select */
-#define LEON_REG_UART_CTRL_PE 0x00000020 /* Parity enable */
-#define LEON_REG_UART_CTRL_FL 0x00000040 /* Flow control enable */
-#define LEON_REG_UART_CTRL_LB 0x00000080 /* Loop Back enable */
-
-#define UART_SET_SCALER 0
-#define UART_SET_CTRL 1
-#define UART_GET_STAT 2
-#define UART_CLR_STAT 3
-
-struct uart_reg {
- volatile unsigned int data; /* 0x00 */
- volatile unsigned int status; /* 0x04 */
- volatile unsigned int ctrl; /* 0x08 */
- volatile unsigned int scaler; /* 0x0C */
-};
-
-
-void uart_register(unsigned int baseaddr);
-rtems_device_driver uart_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
-rtems_device_driver uart_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
-rtems_device_driver uart_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
-rtems_device_driver uart_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
-rtems_device_driver uart_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
-rtems_device_driver uart_control(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
-
-
-struct gpio_reg {
- volatile unsigned int in_data; /* 0x00 */
- volatile unsigned int out_data; /* 0x04 */
- volatile unsigned int dir; /* 0x08 */
- volatile unsigned int imask; /* 0x0C */
- volatile unsigned int ipol; /* 0x10 */
- volatile unsigned int iedge; /* 0x14 */
-};
-
-extern struct gpio_reg *gpio0, *gpio1;
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/c/src/lib/libbsp/sparc/leon2/leon_smc91111/leon_smc91111.c b/c/src/lib/libbsp/sparc/leon2/leon_smc91111/leon_smc91111.c
index 47b4d7a413..3a065f9ec1 100644
--- a/c/src/lib/libbsp/sparc/leon2/leon_smc91111/leon_smc91111.c
+++ b/c/src/lib/libbsp/sparc/leon2/leon_smc91111/leon_smc91111.c
@@ -26,12 +26,12 @@
#define SMC91111_BASE_ADDR (void*)0x20000300
-#define SMC91111_BASE_IRQ LEON_TRAP_TYPE(4)
+#define SMC91111_BASE_IRQ 4
#define SMC91111_BASE_PIO 4
scmv91111_configuration_t leon_scmv91111_configuration = {
SMC91111_BASE_ADDR, /* base address */
- SMC91111_BASE_IRQ, /* vector number */
+ SMC91111_BASE_IRQ, /* IRQ number to IRQ funcs */
SMC91111_BASE_PIO, /* PIO */
100, /* 100b */
1, /* fulldx */
@@ -55,7 +55,7 @@ int rtems_smc91111_driver_attach_leon2(struct rtems_bsdnet_ifconfig *config)
*((volatile unsigned int *)0x80000000) |= 0x10f80000;
*((volatile unsigned int *)0x800000A8) |=
(0xe0 | leon_scmv91111_configuration.pio)
- << (8 * ((leon_scmv91111_configuration.vector & 0x0f) - 4));
+ << (8 * (leon_scmv91111_configuration.irq - 4));
return _rtems_smc91111_driver_attach(config,&leon_scmv91111_configuration);
diff --git a/c/src/lib/libbsp/sparc/leon2/pci/at697_pci.c b/c/src/lib/libbsp/sparc/leon2/pci/at697_pci.c
new file mode 100644
index 0000000000..a2dc44b877
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/leon2/pci/at697_pci.c
@@ -0,0 +1,658 @@
+/* LEON2 AT697 PCI Host Driver.
+ *
+ * COPYRIGHT (c) 2008.
+ * Aeroflex Gaisler AB.
+ *
+ * Configures the AT697 PCI core and initialize,
+ * - the PCI Library (pci.c)
+ * - the general part of the PCI Bus driver (pci_bus.c)
+ *
+ * System interrupt assigned to PCI interrupt (INTA#..INTD#) is by
+ * default taken from Plug and Play, but may be overridden by the
+ * driver resources INTA#..INTD#.
+ *
+ * The license and distribution terms for this file may be
+ * found in found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2008-12-06, Daniel Hellstrom <daniel@gaisler.com>
+ * Created
+ *
+ * Configurable parameters
+ * =======================
+ * INT[A..D]# Select system IRQ (can be tranlated into I/O interrupt)
+ * INT[A..D]#_PIO Select PIO used to generate I/O interrupt
+ *
+ * Notes
+ * =====
+ * IRQ must not be enabled before all PCI boards have been enabled, the
+ * IRQ is therefore enabled first in init2. The init2() for this driver
+ * is assumed to be executed earlier that all boards and their devices
+ * driver's init2() function.
+ *
+ */
+
+#include <rtems/bspIo.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <libcpu/byteorder.h>
+#include <libcpu/access.h>
+#include <pci.h>
+#include <pci/cfg.h>
+
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/pci_bus.h>
+#include <drvmgr/leon2_amba_bus.h>
+
+#include <leon.h>
+
+/* Configuration options */
+
+#define SYSTEM_MAINMEM_START 0x40000000
+#define SYSTEM_MAINMEM_START2 0x60000000
+
+/* Interrupt assignment. Set to other value than 0xff in order to
+ * override defaults and plug&play information
+ */
+#ifndef AT697_INTA_SYSIRQ
+ #define AT697_INTA_SYSIRQ 0xff
+#endif
+#ifndef AT697_INTB_SYSIRQ
+ #define AT697_INTB_SYSIRQ 0xff
+#endif
+#ifndef AT697_INTC_SYSIRQ
+ #define AT697_INTC_SYSIRQ 0xff
+#endif
+#ifndef AT697_INTD_SYSIRQ
+ #define AT697_INTD_SYSIRQ 0xff
+#endif
+
+#ifndef AT697_INTA_PIO
+ #define AT697_INTA_PIO 0xff
+#endif
+#ifndef AT697_INTB_PIO
+ #define AT697_INTB_PIO 0xff
+#endif
+#ifndef AT697_INTC_PIO
+ #define AT697_INTC_PIO 0xff
+#endif
+#ifndef AT697_INTD_PIO
+ #define AT697_INTD_PIO 0xff
+#endif
+
+
+/* AT697 PCI */
+#define AT697_PCI_REG_ADR 0x80000100
+
+/* PCI Window used */
+#define PCI_MEM_START 0xa0000000
+#define PCI_MEM_END 0xf0000000
+#define PCI_MEM_SIZE (PCI_MEM_END - PCI_MEM_START)
+
+/* #define DEBUG 1 */
+
+#ifdef DEBUG
+#define DBG(x...) printf(x)
+#else
+#define DBG(x...)
+#endif
+
+#define PCI_INVALID_VENDORDEVICEID 0xffffffff
+#define PCI_MULTI_FUNCTION 0x80
+
+struct at697pci_regs {
+ volatile unsigned int pciid1; /* 0x80000100 - PCI Device identification register 1 */
+ volatile unsigned int pcisc; /* 0x80000104 - PCI Status & Command */
+ volatile unsigned int pciid2; /* 0x80000108 - PCI Device identification register 2 */
+ volatile unsigned int pcibhlc; /* 0x8000010c - BIST, Header type, Cache line size register */
+ volatile unsigned int mbar1; /* 0x80000110 - Memory Base Address Register 1 */
+ volatile unsigned int mbar2; /* 0x80000114 - Memory Base Address Register 2 */
+ volatile unsigned int iobar3; /* 0x80000118 - IO Base Address Register 3 */
+ volatile unsigned int dummy1[4]; /* 0x8000011c - 0x80000128 */
+ volatile unsigned int pcisid; /* 0x8000012c - Subsystem identification register */
+ volatile unsigned int dummy2; /* 0x80000130 */
+ volatile unsigned int pcicp; /* 0x80000134 - PCI capabilities pointer register */
+ volatile unsigned int dummy3; /* 0x80000138 */
+ volatile unsigned int pcili; /* 0x8000013c - PCI latency interrupt register */
+ volatile unsigned int pcirt; /* 0x80000140 - PCI retry, trdy config */
+ volatile unsigned int pcicw; /* 0x80000144 - PCI configuration write register */
+ volatile unsigned int pcisa; /* 0x80000148 - PCI Initiator Start Address */
+ volatile unsigned int pciiw; /* 0x8000014c - PCI Initiator Write Register */
+ volatile unsigned int pcidma; /* 0x80000150 - PCI DMA configuration register */
+ volatile unsigned int pciis; /* 0x80000154 - PCI Initiator Status Register */
+ volatile unsigned int pciic; /* 0x80000158 - PCI Initiator Configuration */
+ volatile unsigned int pcitpa; /* 0x8000015c - PCI Target Page Address Register */
+ volatile unsigned int pcitsc; /* 0x80000160 - PCI Target Status-Command Register */
+ volatile unsigned int pciite; /* 0x80000164 - PCI Interrupt Enable Register */
+ volatile unsigned int pciitp; /* 0x80000168 - PCI Interrupt Pending Register */
+ volatile unsigned int pciitf; /* 0x8000016c - PCI Interrupt Force Register */
+ volatile unsigned int pcid; /* 0x80000170 - PCI Data Register */
+ volatile unsigned int pcibe; /* 0x80000174 - PCI Burst End Register */
+ volatile unsigned int pcidmaa; /* 0x80000178 - PCI DMA Address Register */
+};
+
+/* PCI Interrupt assignment. Connects an PCI interrupt pin (INTA#..INTD#)
+ * to a system interrupt number.
+ */
+unsigned char at697_pci_irq_table[4] =
+{
+ /* INTA# */ AT697_INTA_SYSIRQ,
+ /* INTB# */ AT697_INTB_SYSIRQ,
+ /* INTC# */ AT697_INTC_SYSIRQ,
+ /* INTD# */ AT697_INTD_SYSIRQ
+};
+
+/* PCI Interrupt PIO assignment. Selects which GPIO pin will be used to
+ * generate the system IRQ.
+ *
+ * PCI IRQ -> GPIO -> 4 x I/O select -> System IRQ
+ * ^- pio_table ^- irq_select
+ */
+unsigned char at697_pci_irq_pio_table[4] =
+{
+ /* INTA# */ AT697_INTA_PIO,
+ /* INTB# */ AT697_INTB_PIO,
+ /* INTC# */ AT697_INTC_PIO,
+ /* INTD# */ AT697_INTD_PIO
+};
+
+/* Driver private data struture */
+struct at697pci_priv {
+ struct drvmgr_dev *dev;
+ struct at697pci_regs *regs;
+ int minor;
+
+ uint32_t devVend; /* PCI Device and Vendor ID of Host */
+ uint32_t bar1_pci_adr;
+ uint32_t bar2_pci_adr;
+
+ struct drvmgr_map_entry maps_up[3];
+ struct drvmgr_map_entry maps_down[2];
+ struct pcibus_config config;
+};
+
+struct at697pci_priv *at697pcipriv = NULL;
+static int at697pci_minor = 0;
+
+int at697pci_init1(struct drvmgr_dev *dev);
+int at697pci_init2(struct drvmgr_dev *dev);
+
+/* AT697 PCI DRIVER */
+
+struct drvmgr_drv_ops at697pci_ops =
+{
+ .init = {at697pci_init1, at697pci_init2, NULL, NULL},
+ .remove = NULL,
+ .info = NULL
+};
+
+struct leon2_amba_dev_id at697pci_ids[] =
+{
+ {LEON2_AMBA_AT697PCI_ID},
+ {0} /* Mark end of table */
+};
+
+struct leon2_amba_drv_info at697pci_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_LEON2_AMBA_AT697PCI, /* Driver ID */
+ "AT697PCI_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_LEON2_AMBA, /* Bus Type */
+ &at697pci_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ sizeof(struct at697pci_priv), /* let drvmgr alloc private */
+ },
+ &at697pci_ids[0]
+};
+
+void at697pci_register_drv(void)
+{
+ DBG("Registering AT697 PCI driver\n");
+ drvmgr_drv_register(&at697pci_info.general);
+}
+
+/* The configuration access functions uses the DMA functionality of the
+ * AT697 pci controller to be able access all slots
+ */
+
+int at697pci_cfg_r32(pci_dev_t dev, int offset, uint32_t *val)
+{
+ struct at697pci_regs *regs;
+ volatile unsigned int data = 0;
+ unsigned int address;
+ int bus = PCI_DEV_BUS(dev);
+ int slot = PCI_DEV_SLOT(dev);
+ int func = PCI_DEV_FUNC(dev);
+ int retval;
+
+ if (slot > 21 || (offset & ~0xfc)) {
+ *val = 0xffffffff;
+ return PCISTS_EINVAL;
+ }
+
+ regs = at697pcipriv->regs;
+
+ regs->pciitp = 0xff; /* clear interrupts */
+
+ if ( bus == 0 ) {
+ /* PCI Access - TYPE 0 */
+ address = (1<<(11+slot)) | (func << 8) | offset;
+ } else {
+ /* PCI access - TYPE 1 */
+ address = ((bus & 0xff) << 16) | ((slot & 0x1f) << 11) |
+ (func << 8) | offset | 1;
+ }
+ regs->pcisa = address;
+ regs->pcidma = 0xa01;
+ regs->pcidmaa = (unsigned int) &data;
+
+ while (regs->pciitp == 0)
+ ;
+
+ regs->pciitp = 0xff; /* clear interrupts */
+
+ if (regs->pcisc & 0x20000000) { /* Master Abort */
+ regs->pcisc |= 0x20000000;
+ *val = 0xffffffff;
+ retval = PCISTS_MSTABRT;
+ } else {
+ *val = data;
+ retval = PCISTS_OK;
+ }
+
+ DBG("pci_read - bus: %d, dev: %d, fn: %d, off: %d => addr: %x, val: %x\n",
+ bus, slot, func, offset, address, *val);
+
+ return retval;
+}
+
+int at697pci_cfg_r16(pci_dev_t dev, int ofs, uint16_t *val)
+{
+ uint32_t v;
+ int retval;
+
+ if (ofs & 1)
+ return PCISTS_EINVAL;
+
+ retval = at697pci_cfg_r32(dev, ofs & ~0x3, &v);
+ *val = 0xffff & (v >> (8*(ofs & 0x3)));
+
+ return retval;
+}
+
+int at697pci_cfg_r8(pci_dev_t dev, int ofs, uint8_t *val)
+{
+ uint32_t v;
+ int retval;
+
+ retval = at697pci_cfg_r32(dev, ofs & ~0x3, &v);
+
+ *val = 0xff & (v >> (8*(ofs & 3)));
+
+ return retval;
+}
+
+int at697pci_cfg_w32(pci_dev_t dev, int offset, uint32_t val)
+{
+ struct at697pci_regs *regs;
+ volatile unsigned int tmp_val = val;
+ unsigned int address;
+ int bus = PCI_DEV_BUS(dev);
+ int slot = PCI_DEV_SLOT(dev);
+ int func = PCI_DEV_FUNC(dev);
+ int retval;
+
+ if (slot > 21 || (offset & ~0xfc))
+ return PCISTS_EINVAL;
+
+ regs = at697pcipriv->regs;
+
+ regs->pciitp = 0xff; /* clear interrupts */
+
+ if ( bus == 0 ) {
+ /* PCI Access - TYPE 0 */
+ address = (1<<(11+slot)) | (func << 8) | offset;
+ } else {
+ /* PCI access - TYPE 1 */
+ address = ((bus & 0xff) << 16) | ((slot & 0x1f) << 11) |
+ (func << 8) | offset | 1;
+ }
+ regs->pcisa = address;
+ regs->pcidma = 0xb01;
+ regs->pcidmaa = (unsigned int) &tmp_val;
+
+ while (regs->pciitp == 0)
+ ;
+
+ if (regs->pcisc & 0x20000000) { /* Master Abort */
+ regs->pcisc |= 0x20000000;
+ retval = PCISTS_MSTABRT;
+ } else
+ retval = PCISTS_OK;
+
+ regs->pciitp = 0xff; /* clear interrupts */
+
+ DBG("pci_write - bus: %d, dev: %d, fn: %d, off: %d => addr: %x, val: %x\n",
+ bus, slot, func, offset, address, val);
+
+ return retval;
+}
+
+int at697pci_cfg_w16(pci_dev_t dev, int ofs, uint16_t val)
+{
+ uint32_t v;
+ int retval;
+
+ if (ofs & 1)
+ return PCISTS_EINVAL;
+
+ retval = at697pci_cfg_r32(dev, ofs & ~0x3, &v);
+ if (retval != PCISTS_OK)
+ return retval;
+
+ v = (v & ~(0xffff << (8*(ofs&3)))) | ((0xffff&val) << (8*(ofs&3)));
+
+ return at697pci_cfg_w32(dev, ofs & ~0x3, v);
+}
+
+int at697pci_cfg_w8(pci_dev_t dev, int ofs, uint8_t val)
+{
+ uint32_t v;
+
+ at697pci_cfg_r32(dev, ofs & ~0x3, &v);
+
+ v = (v & ~(0xff << (8*(ofs&3)))) | ((0xff&val) << (8*(ofs&3)));
+
+ return at697pci_cfg_w32(dev, ofs & ~0x3, v);
+}
+
+/* Return the assigned system IRQ number that corresponds to the PCI
+ * "Interrupt Pin" information from configuration space.
+ *
+ * The IRQ information is stored in the at697_pci_irq_table configurable
+ * by the user.
+ *
+ * Returns the "system IRQ" for the PCI INTA#..INTD# pin in irq_pin. Returns
+ * 0xff if not assigned.
+ */
+uint8_t at697pci_bus0_irq_map(pci_dev_t dev, int irq_pin)
+{
+ uint8_t sysIrqNr = 0; /* not assigned */
+ int irq_group;
+
+ if ( (irq_pin >= 1) && (irq_pin <= 4) ) {
+ /* Use default IRQ decoding on PCI BUS0 according slot numbering */
+ irq_group = PCI_DEV_SLOT(dev) & 0x3;
+ irq_pin = ((irq_pin - 1) + irq_group) & 0x3;
+ /* Valid PCI "Interrupt Pin" number */
+ sysIrqNr = at697_pci_irq_table[irq_pin];
+ }
+ return sysIrqNr;
+}
+
+int at697pci_translate(uint32_t *address, int type, int dir)
+{
+ /* No address translation implmented at this point */
+ return 0;
+}
+
+extern struct pci_memreg_ops pci_memreg_sparc_be_ops;
+
+/* AT697 Big-Endian PCI access routines */
+struct pci_access_drv at697pci_access_drv = {
+ .cfg =
+ {
+ at697pci_cfg_r8,
+ at697pci_cfg_r16,
+ at697pci_cfg_r32,
+ at697pci_cfg_w8,
+ at697pci_cfg_w16,
+ at697pci_cfg_w32,
+ },
+ .io =
+ { /* AT697 only supports non-standard Big-Endian PCI Bus */
+ _ld8,
+ _ld_be16,
+ _ld_be32,
+ _st8,
+ _st_be16,
+ _st_be32,
+
+ },
+ .memreg = &pci_memreg_sparc_be_ops,
+ .translate = at697pci_translate,
+};
+
+/* Initializes the AT697PCI core hardware
+ *
+ */
+int at697pci_hw_init(struct at697pci_priv *priv)
+{
+ struct at697pci_regs *regs = priv->regs;
+ unsigned short vendor = regs->pciid1 >> 16;
+ pci_dev_t host = PCI_DEV(0, 0, 0);
+
+ /* Must match ATMEL or ESA ID */
+ if ( !((vendor == 0x1202) || (vendor == 0x1E0F)) ) {
+ /* No AT697 PCI, quit */
+ return -1;
+ }
+
+ /* Reset PCI Core */
+ regs->pciic = 0xffffffff;
+
+ /* Mask PCI interrupts */
+ regs->pciite = 0;
+
+ /* Map parts of AT697 main memory into PCI (for DMA) */
+ regs->mbar1 = priv->bar1_pci_adr;
+ regs->mbar2 = priv->bar2_pci_adr;
+ regs->pcitpa = (priv->bar1_pci_adr & 0xff000000) |
+ ((priv->bar2_pci_adr>>16) & 0xff00);
+
+ /* Enable PCI master and target memory command response */
+ regs->pcisc |= 0x40 | 0x6;
+
+ /* Set latency timer to 64 */
+ regs->pcibhlc = 0x00004000;
+
+ /* Set Inititator configuration so that AHB slave accesses generate memory read/write commands */
+ regs->pciic = 0x41;
+
+ /* Get the AT697PCI Host PCI ID */
+ at697pci_cfg_r32(host, PCI_VENDOR_ID, &priv->devVend);
+
+ return 0;
+}
+
+/* Initializes the AT697PCI core and driver, must be called before calling init_pci()
+ *
+ * Return values
+ * 0 Successful initalization
+ * -1 Error during initialization.
+ */
+int at697pci_init(struct at697pci_priv *priv)
+{
+ int pin;
+ union drvmgr_key_value *value;
+ char keyname_sysirq[6];
+ char keyname_pio[10];
+
+ /* PCI core, init private structure */
+ priv->regs = (struct at697pci_regs *) AT697_PCI_REG_ADR;
+
+ /* Init PCI interrupt assignment table to all use the interrupt routed
+ * through the GPIO core.
+ *
+ * INT[A..D]# selects system IRQ (and I/O interrupt)
+ * INT[A..D]#_PIO selects PIO used to generate I/O interrupt
+ */
+ strcpy(keyname_sysirq, "INTX#");
+ strcpy(keyname_pio, "INTX#_PIO");
+ for (pin=1; pin<5; pin++) {
+ if ( at697_pci_irq_table[pin-1] == 0xff ) {
+ /* User may override hardcoded IRQ setup */
+ keyname_sysirq[3] = 'A' + (pin-1);
+ value = drvmgr_dev_key_get(priv->dev,
+ keyname_sysirq, KEY_TYPE_INT);
+ if ( value )
+ at697_pci_irq_table[pin-1] = value->i;
+ }
+ if ( at697_pci_irq_pio_table[pin-1] == 0xff ) {
+ /* User may override hardcoded IRQ setup */
+ keyname_pio[3] = 'A' + (pin-1);
+ value = drvmgr_dev_key_get(priv->dev,
+ keyname_pio, KEY_TYPE_INT);
+ if ( value )
+ at697_pci_irq_pio_table[pin-1] = value->i;
+ }
+ }
+
+ /* Use GRPCI target BAR1 and BAR2 to map CPU RAM to PCI, this is to
+ * make it possible for PCI peripherals to do DMA directly to CPU memory
+ *
+ * Defualt is to map system RAM at pci address 0x40000000 and system
+ * SDRAM to pci address 0x60000000
+ */
+ value = drvmgr_dev_key_get(priv->dev, "tgtbar1", KEY_TYPE_INT);
+ if (value)
+ priv->bar1_pci_adr = value->i;
+ else
+ priv->bar1_pci_adr = SYSTEM_MAINMEM_START; /* default */
+
+ value = drvmgr_dev_key_get(priv->dev, "tgtbar2", KEY_TYPE_INT);
+ if (value)
+ priv->bar2_pci_adr = value->i;
+ else
+ priv->bar2_pci_adr = SYSTEM_MAINMEM_START2; /* default */
+
+ /* Init the PCI Core */
+ if ( at697pci_hw_init(priv) ) {
+ return -3;
+ }
+
+ /* Down streams translation table */
+ priv->maps_down[0].name = "AMBA -> PCI MEM Window";
+ priv->maps_down[0].size = 0xF0000000 - 0xA0000000;
+ priv->maps_down[0].from_adr = (void *)0xA0000000;
+ priv->maps_down[0].to_adr = (void *)0xA0000000;
+ /* End table */
+ priv->maps_down[1].size = 0;
+
+ /* Up streams translation table, 2x16Mb mapped 1:1 */
+ priv->maps_up[0].name = "Target BAR0 -> AMBA";
+ priv->maps_up[0].size = 0x01000000; /* 16Mb BAR1 */
+ priv->maps_up[0].from_adr = (void *)priv->bar1_pci_adr;
+ priv->maps_up[0].to_adr = (void *)priv->bar1_pci_adr;
+ priv->maps_up[1].name = "Target BAR1 -> AMBA";
+ priv->maps_up[1].size = 0x01000000; /* 16Mb BAR2 */
+ priv->maps_up[1].from_adr = (void *)priv->bar2_pci_adr;
+ priv->maps_up[1].to_adr = (void *)priv->bar2_pci_adr;
+ /* End table */
+ priv->maps_up[2].size = 0;
+
+ return 0;
+}
+
+/* Called when a core is found with the AMBA device and vendor ID
+ * given in at697pci_ids[].
+ */
+int at697pci_init1(struct drvmgr_dev *dev)
+{
+ struct at697pci_priv *priv;
+ struct pci_auto_setup at697pci_auto_cfg;
+
+ DBG("AT697PCI[%d] on bus %s\n", dev->minor_drv,
+ dev->parent->dev->name);
+
+ if ( at697pci_minor != 0 ) {
+ DBG("Driver only supports one PCI core\n");
+ return DRVMGR_FAIL;
+ }
+
+ at697pcipriv = priv = dev->priv;
+ if ( !priv )
+ return DRVMGR_NOMEM;
+
+ priv->dev = dev;
+ priv->minor = at697pci_minor++;
+
+ if (at697pci_init(priv)) {
+ DBG("Failed to initialize at697pci driver\n");
+ return DRVMGR_FAIL;
+ }
+
+ /* Host is always Big-Endian */
+ pci_endian = PCI_BIG_ENDIAN;
+
+ if (pci_access_drv_register(&at697pci_access_drv)) {
+ /* Access routines registration failed */
+ return DRVMGR_FAIL;
+ }
+
+ /* Prepare memory MAP */
+ at697pci_auto_cfg.options = 0;
+ at697pci_auto_cfg.mem_start = 0;
+ at697pci_auto_cfg.mem_size = 0;
+ at697pci_auto_cfg.memio_start = PCI_MEM_START;
+ at697pci_auto_cfg.memio_size = PCI_MEM_SIZE;
+ at697pci_auto_cfg.io_start = 0;
+ at697pci_auto_cfg.io_size = 0;
+ at697pci_auto_cfg.irq_map = at697pci_bus0_irq_map;
+ at697pci_auto_cfg.irq_route = NULL; /* use standard routing */
+ pci_config_register(&at697pci_auto_cfg);
+
+ if (pci_config_init()) {
+ /* PCI configuration failed */
+ return DRVMGR_FAIL;
+ }
+
+ priv->config.maps_down = &priv->maps_down[0];
+ priv->config.maps_up = &priv->maps_up[0];
+ return pcibus_register(dev, &priv->config);
+}
+
+int at697pci_init2(struct drvmgr_dev *dev)
+{
+#if 0
+ struct at697pci_priv *priv = dev->priv;
+#endif
+ int pin, irq, pio, ioport;
+ LEON_Register_Map *regs = (LEON_Register_Map *)0x80000000;
+
+ /* Enable interrupts now that init1 has been reached for all devices
+ * on the bus.
+ */
+
+ for (pin=1; pin<5; pin++) {
+ irq = at697_pci_irq_table[pin-1];
+ pio = at697_pci_irq_pio_table[pin-1];
+ if ( (pio < 16) && (irq >= 4) && (irq <= 7) ) {
+ /* AT697 I/O IRQ, we know how to set up this
+ *
+ * IRQ 4 -> I/O 0
+ * IRQ 5 -> I/O 1
+ * IRQ 6 -> I/O 2
+ * IRQ 7 -> I/O 3
+ */
+ ioport = irq - 4;
+
+ /* First disable interrupts */
+ regs->PIO_Interrupt &= ~(0xff << (ioport * 8));
+ /* Set PIO as input pin */
+ regs->PIO_Direction &= ~(1 << pio);
+ /* Set Low Level sensitivity */
+ regs->PIO_Interrupt |= ((0x80 | pio) << (ioport * 8));
+ }
+ }
+
+ /* Unmask Interrupt */
+ /*priv->regs->pciite = 0xff;*/
+
+ return DRVMGR_OK;
+}
diff --git a/c/src/lib/libbsp/sparc/leon2/pci/pci.c b/c/src/lib/libbsp/sparc/leon2/pci/pci.c
deleted file mode 100644
index 5e48c4703f..0000000000
--- a/c/src/lib/libbsp/sparc/leon2/pci/pci.c
+++ /dev/null
@@ -1,674 +0,0 @@
-/*
- * pci.c : this file contains basic PCI Io functions.
- *
- * Copyright (C) 1999 valette@crf.canon.fr
- *
- * This code is heavily inspired by the public specification of STREAM V2
- * that can be found at :
- *
- * <http://www.chorus.com/Documentation/index.html> by following
- * the STREAM API Specification Document link.
- *
- * The license and distribution terms for this file may be
- * found in found in the file LICENSE in this distribution or at
- * http://www.rtems.com/license/LICENSE.
- *
- * $Id$
- *
- * Till Straumann, <strauman@slac.stanford.edu>, 1/2002
- * - separated bridge detection code out of this file
- *
- * Adapted to LEON2 AT697 PCI
- * Copyright (C) 2006 Gaisler Research
- *
- */
-
-#include <pci.h>
-#include <rtems/bspIo.h>
-#include <stdlib.h>
-
-/* Define PCI_INFO to get a listing of configured devices at boot time */
-#define PCI_INFO 1
-
-/* #define DEBUG 1 */
-
-#ifdef DEBUG
-#define DBG(x...) printk(x)
-#else
-#define DBG(x...)
-#endif
-
-/* allow for overriding these definitions */
-#ifndef PCI_CONFIG_ADDR
-#define PCI_CONFIG_ADDR 0xcf8
-#endif
-#ifndef PCI_CONFIG_DATA
-#define PCI_CONFIG_DATA 0xcfc
-#endif
-
-#define PCI_INVALID_VENDORDEVICEID 0xffffffff
-#define PCI_MULTI_FUNCTION 0x80
-
-/* define a shortcut */
-#define pci BSP_pci_configuration
-
-/*
- * Bit encode for PCI_CONFIG_HEADER_TYPE register
- */
-unsigned char ucMaxPCIBus;
-
-typedef struct {
- volatile unsigned int pciid1; /* 0x80000100 - PCI Device identification register 1 */
- volatile unsigned int pcisc; /* 0x80000104 - PCI Status & Command */
- volatile unsigned int pciid2; /* 0x80000108 - PCI Device identification register 2 */
- volatile unsigned int pcibhlc; /* 0x8000010c - BIST, Header type, Cache line size register */
- volatile unsigned int mbar1; /* 0x80000110 - Memory Base Address Register 1 */
- volatile unsigned int mbar2; /* 0x80000114 - Memory Base Address Register 2 */
- volatile unsigned int iobar3; /* 0x80000118 - IO Base Address Register 3 */
- volatile unsigned int dummy1[4]; /* 0x8000011c - 0x80000128 */
- volatile unsigned int pcisid; /* 0x8000012c - Subsystem identification register */
- volatile unsigned int dummy2; /* 0x80000130 */
- volatile unsigned int pcicp; /* 0x80000134 - PCI capabilities pointer register */
- volatile unsigned int dummy3; /* 0x80000138 */
- volatile unsigned int pcili; /* 0x8000013c - PCI latency interrupt register */
- volatile unsigned int pcirt; /* 0x80000140 - PCI retry, trdy config */
- volatile unsigned int pcicw; /* 0x80000144 - PCI configuration write register */
- volatile unsigned int pcisa; /* 0x80000148 - PCI Initiator Start Address */
- volatile unsigned int pciiw; /* 0x8000014c - PCI Initiator Write Register */
- volatile unsigned int pcidma; /* 0x80000150 - PCI DMA configuration register */
- volatile unsigned int pciis; /* 0x80000154 - PCI Initiator Status Register */
- volatile unsigned int pciic; /* 0x80000158 - PCI Initiator Configuration */
- volatile unsigned int pcitpa; /* 0x8000015c - PCI Target Page Address Register */
- volatile unsigned int pcitsc; /* 0x80000160 - PCI Target Status-Command Register */
- volatile unsigned int pciite; /* 0x80000164 - PCI Interrupt Enable Register */
- volatile unsigned int pciitp; /* 0x80000168 - PCI Interrupt Pending Register */
- volatile unsigned int pciitf; /* 0x8000016c - PCI Interrupt Force Register */
- volatile unsigned int pcid; /* 0x80000170 - PCI Data Register */
- volatile unsigned int pcibe; /* 0x80000174 - PCI Burst End Register */
- volatile unsigned int pcidmaa; /* 0x80000178 - PCI DMA Address Register */
-} AT697_PCI_Map;
-
-AT697_PCI_Map *pcic = (AT697_PCI_Map *) 0x80000100;
-
-#define PCI_MEM_START 0xa0000000
-#define PCI_MEM_END 0xf0000000
-#define PCI_MEM_SIZE (PCI_MEM_START - PCI_MEM_END)
-
-
-struct pci_res {
- unsigned int size;
- unsigned char bar;
- unsigned char devfn;
-};
-
-/* The configuration access functions uses the DMA functionality of the
- * AT697 pci controller to be able access all slots
- */
-
-static int
-BSP_pci_read_config_dword(unsigned char bus, unsigned char slot, unsigned char function, unsigned char offset, unsigned int *val) {
-
- volatile unsigned int data;
-
- if (offset & 3) return PCIBIOS_BAD_REGISTER_NUMBER;
-
- pcic->pciitp = 0xff; /* clear interrupts */
-
- pcic->pcisa = ( 1<<(11+slot) ) | ((function & 7)<<8) | (offset&0x3f);
- pcic->pcidma = 0xa01;
- pcic->pcidmaa = (unsigned int) &data;
-
- while (pcic->pciitp == 0)
- ;
-
- pcic->pciitp = 0xff; /* clear interrupts */
-
- if (pcic->pcisc & 0x20000000) { /* Master Abort */
- pcic->pcisc |= 0x20000000;
- *val = 0xffffffff;
- }
- else
- *val = data;
-
- DBG("pci_read - bus: %d, dev: %d, fn: %d, off: %d => addr: %x, val: %x\n", bus, slot, function, offset, (1<<(11+slot) ) | ((function & 7)<<8) | (offset&0x3f), *val);
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-
-static int
-BSP_pci_read_config_word(unsigned char bus, unsigned char slot, unsigned char function, unsigned char offset, unsigned short *val) {
- unsigned int v;
-
- if (offset & 1) return PCIBIOS_BAD_REGISTER_NUMBER;
-
- pci_read_config_dword(bus, slot, function, offset&~3, &v);
- *val = 0xffff & (v >> (8*(offset & 3)));
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-
-static int
-BSP_pci_read_config_byte(unsigned char bus, unsigned char slot, unsigned char function, unsigned char offset, unsigned char *val) {
- unsigned int v;
-
- pci_read_config_dword(bus, slot, function, offset&~3, &v);
-
- *val = 0xff & (v >> (8*(offset & 3)));
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-
-static int
-BSP_pci_write_config_dword(unsigned char bus, unsigned char slot, unsigned char function, unsigned char offset, unsigned int val) {
-
- if (offset & 3) return PCIBIOS_BAD_REGISTER_NUMBER;
-
- pcic->pciitp = 0xff; /* clear interrupts */
-
- pcic->pcisa = ( 1<<(11+slot) ) | ((function & 7)<<8) | (offset&0x3f);
- pcic->pcidma = 0xb01;
- pcic->pcidmaa = (unsigned int) &val;
-
- while (pcic->pciitp == 0)
- ;
-
- if (pcic->pcisc & 0x20000000) { /* Master Abort */
- pcic->pcisc |= 0x20000000;
- }
-
- pcic->pciitp = 0xff; /* clear interrupts */
-
-/* DBG("pci write - bus: %d, dev: %d, fn: %d, off: %d => addr: %x, val: %x\n", bus, slot, function, offset, (1<<(11+slot) ) | ((function & 7)<<8) | (offset&0x3f), val); */
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-
-static int
-BSP_pci_write_config_word(unsigned char bus, unsigned char slot, unsigned char function, unsigned char offset, unsigned short val) {
- unsigned int v;
-
- if (offset & 1) return PCIBIOS_BAD_REGISTER_NUMBER;
-
- pci_read_config_dword(bus, slot, function, offset&~3, &v);
-
- v = (v & ~(0xffff << (8*(offset&3)))) | ((0xffff&val) << (8*(offset&3)));
-
- return pci_write_config_dword(bus, slot, function, offset&~3, v);
-}
-
-
-static int
-BSP_pci_write_config_byte(unsigned char bus, unsigned char slot, unsigned char function, unsigned char offset, unsigned char val) {
- unsigned int v;
-
- pci_read_config_dword(bus, slot, function, offset&~3, &v);
-
- v = (v & ~(0xff << (8*(offset&3)))) | ((0xff&val) << (8*(offset&3)));
-
- return pci_write_config_dword(bus, slot, function, offset&~3, v);
-}
-
-
-
-const pci_config_access_functions pci_access_functions = {
- BSP_pci_read_config_byte,
- BSP_pci_read_config_word,
- BSP_pci_read_config_dword,
- BSP_pci_write_config_byte,
- BSP_pci_write_config_word,
- BSP_pci_write_config_dword
-};
-
-rtems_pci_config_t BSP_pci_configuration = {
- (volatile unsigned char*)PCI_CONFIG_ADDR,
- (volatile unsigned char*)PCI_CONFIG_DATA,
- &pci_access_functions
-};
-
-
-void init_at697_pci(void) {
-
- /* Reset */
- pcic->pciic = 0xffffffff;
-
- /* Map system RAM at pci address 0x40000000 and system SDRAM to pci address 0x60000000 */
- pcic->mbar1 = 0x40000000;
- pcic->mbar2 = 0x60000000;
- pcic->pcitpa = 0x40006000;
-
- /* Enable PCI master and target memory command response */
- pcic->pcisc |= 0x40 | 0x6;
-
- /* Set latency timer to 64 */
- pcic->pcibhlc = 0x00004000;
-
- /* Set Inititator configuration so that AHB slave accesses generate memory read/write commands */
- pcic->pciic = 0x41;
-
- pcic->pciite = 0xff;
-
-}
-
-/* May not pass a 1k boundary */
-int dma_from_pci_1k(unsigned int addr, unsigned int paddr, unsigned char len) {
-
- int retval = 0;
-
- if (addr & 3) {
- return -1;
- }
-
- pcic->pciitp = 0xff; /* clear interrupts */
-
- pcic->pcisa = paddr;
- pcic->pcidma = 0xc00 | len;
- pcic->pcidmaa = addr;
-
- while (pcic->pciitp == 0)
- ;
-
- if (pcic->pciitp & 0x7F) {
- retval = -1;
- }
-
- pcic->pciitp = 0xff; /* clear interrupts */
-
- if (pcic->pcisc & 0x20000000) { /* Master Abort */
- pcic->pcisc |= 0x20000000;
- retval = -1;
- }
-
- return retval;
-}
-
-/* May not pass a 1k boundary */
-int dma_to_pci_1k(unsigned int addr, unsigned int paddr, unsigned char len) {
-
- int retval = 0;
-
- if (addr & 3) return -1;
-
- pcic->pciitp = 0xff; /* clear interrupts */
-
- pcic->pcisa = paddr;
- pcic->pcidma = 0x700 | len;
- pcic->pcidmaa = addr;
-
- while (pcic->pciitp == 0)
- ;
-
- if (pcic->pciitp & 0x7F) retval = -1;
-
- pcic->pciitp = 0xff; /* clear interrupts */
-
- if (pcic->pcisc & 0x20000000) { /* Master Abort */
- pcic->pcisc |= 0x20000000;
- retval = -1;
- }
-
- return retval;
-}
-
-/* Transfer len number of words from addr to paddr */
-int dma_to_pci(unsigned int addr, unsigned int paddr, unsigned int len) {
-
- int tmp_len;
-
- /* Align to 1k boundary */
- tmp_len = ((addr + 1024) & 0xfffffc00) - addr;
-
- tmp_len = (tmp_len/4 < len) ? tmp_len : (len*4);
-
- if (dma_to_pci_1k(addr, paddr, tmp_len/4) < 0)
- return -1;
-
- addr += tmp_len;
- paddr += tmp_len;
- len -= tmp_len/4;
-
- /* Transfer all 1k blocks */
- while (len >= 128) {
-
- if (dma_to_pci_1k(addr, paddr, 128) < 0)
- return -1;
-
- addr += 512;
- paddr += 512;
- len -= 128;
-
- }
-
- /* Transfer last words */
- if (len) return dma_to_pci_1k(addr, paddr, len);
-
- return 0;
-}
-
-/* Transfer len number of words from paddr to addr */
-int dma_from_pci(unsigned int addr, unsigned int paddr, unsigned int len) {
-
- int tmp_len;
-
- /* Align to 1k boundary */
- tmp_len = ((addr + 1024) & 0xfffffc00) - addr;
-
- tmp_len = (tmp_len/4 < len) ? tmp_len : (len*4);
-
- if (dma_from_pci_1k(addr, paddr, tmp_len/4) < 0)
- return -1;
-
- addr += tmp_len;
- paddr += tmp_len;
- len -= tmp_len/4;
-
- /* Transfer all 1k blocks */
- while (len >= 128) {
-
- if (dma_from_pci_1k(addr, paddr, 128) < 0)
- return -1;
- addr += 512;
- paddr += 512;
- len -= 128;
-
- }
-
- /* Transfer last words */
- if (len) return dma_from_pci_1k(addr, paddr, len);
-
- return 0;
-}
-
-void pci_mem_enable(unsigned char bus, unsigned char slot, unsigned char function) {
- unsigned int data;
-
- pci_read_config_dword(0, slot, function, PCI_COMMAND, &data);
- pci_write_config_dword(0, slot, function, PCI_COMMAND, data | PCI_COMMAND_MEMORY);
-
-}
-
-void pci_master_enable(unsigned char bus, unsigned char slot, unsigned char function) {
- unsigned int data;
-
- pci_read_config_dword(0, slot, function, PCI_COMMAND, &data);
- pci_write_config_dword(0, slot, function, PCI_COMMAND, data | PCI_COMMAND_MASTER);
-
-}
-
-static inline void swap_res(struct pci_res **p1, struct pci_res **p2) {
-
- struct pci_res *tmp = *p1;
- *p1 = *p2;
- *p2 = tmp;
-
-}
-
-/* pci_allocate_resources
- *
- * This function scans the bus and assigns PCI addresses to all devices. It handles both
- * single function and multi function devices. All allocated devices are enabled and
- * latency timers are set to 40.
- *
- * NOTE that it only allocates PCI memory space devices. IO spaces are not enabled.
- * Also, it does not handle pci-pci bridges. They are left disabled.
- *
- *
-*/
-void pci_allocate_resources(void) {
-
- unsigned int slot, numfuncs, func, id, pos, size, tmp, i, swapped, addr, dev, fn;
- unsigned char header;
- struct pci_res **res;
-
- res = (struct pci_res **) malloc(sizeof(struct pci_res *)*32*8*6);
-
- for (i = 0; i < 32*8*6; i++) {
- res[i] = (struct pci_res *) malloc(sizeof(struct pci_res));
- res[i]->size = 0;
- res[i]->devfn = i;
- }
-
- for(slot = 0; slot< PCI_MAX_DEVICES; slot++) {
-
- pci_read_config_dword(0, slot, 0, PCI_VENDOR_ID, &id);
-
- if(id == PCI_INVALID_VENDORDEVICEID || id == 0) {
- /*
- * This slot is empty
- */
- continue;
- }
-
- pci_read_config_byte(0, slot, 0, PCI_HEADER_TYPE, &header);
-
- if(header & PCI_MULTI_FUNCTION) {
- numfuncs = PCI_MAX_FUNCTIONS;
- }
- else {
- numfuncs = 1;
- }
-
- for(func = 0; func < numfuncs; func++) {
-
- pci_read_config_dword(0, slot, func, PCI_VENDOR_ID, &id);
- if(id == PCI_INVALID_VENDORDEVICEID || id == 0) {
- continue;
- }
-
- pci_read_config_dword(0, slot, func, PCI_CLASS_REVISION, &tmp);
- tmp >>= 16;
- if (tmp == PCI_CLASS_BRIDGE_PCI) {
- continue;
- }
-
- for (pos = 0; pos < 6; pos++) {
- pci_write_config_dword(0, slot, func, PCI_BASE_ADDRESS_0 + (pos<<2), 0xffffffff);
- pci_read_config_dword(0, slot, func, PCI_BASE_ADDRESS_0 + (pos<<2), &size);
-
- if (size == 0 || size == 0xffffffff || (size & 0xff) != 0) {
- pci_write_config_dword(0, slot, func, PCI_BASE_ADDRESS_0 + (pos<<2), 0);
- continue;
- }
-
- else {
- res[slot*8*6+func*6+pos]->size = ~size+1;
- res[slot*8*6+func*6+pos]->devfn = slot*8 + func;
- res[slot*8*6+func*6+pos]->bar = pos;
-
- DBG("Slot: %d, function: %d, bar%d size: %x\n", slot, func, pos, ~size+1);
- }
- }
- }
- }
-
-
- /* Sort the resources in descending order */
-
- swapped = 1;
- while (swapped == 1) {
- swapped = 0;
- for (i = 0; i < 32*8*6-1; i++) {
- if (res[i]->size < res[i+1]->size) {
- swap_res(&res[i], &res[i+1]);
- swapped = 1;
- }
- }
- i++;
- }
-
- /* Assign the BARs */
-
- addr = PCI_MEM_START;
- for (i = 0; i < 32*8*6; i++) {
-
- if (res[i]->size == 0) {
- goto done;
- }
- if ( (addr + res[i]->size) > PCI_MEM_END) {
- printk("Out of PCI memory space, all devices not configured.\n");
- goto done;
- }
-
- dev = res[i]->devfn >> 3;
- fn = res[i]->devfn & 7;
-
- DBG("Assigning PCI addr %x to device %d, function %d, bar %d\n", addr, dev, fn, res[i]->bar);
- pci_write_config_dword(0, dev, fn, PCI_BASE_ADDRESS_0+res[i]->bar*4, addr);
- addr += res[i]->size;
-
- /* Set latency timer to 64 */
- pci_read_config_dword(0, dev, fn, 0xC, &tmp);
- pci_write_config_dword(0, dev, fn, 0xC, tmp|0x4000);
-
- pci_mem_enable(0, dev, fn);
-
- }
-
-
-
-done:
-
-#ifdef PCI_INFO
- printk("\nPCI devices found and configured:\n");
- for (slot = 0; slot < PCI_MAX_DEVICES; slot++) {
-
- pci_read_config_byte(0, slot, 0, PCI_HEADER_TYPE, &header);
-
- if(header & PCI_MULTI_FUNCTION) {
- numfuncs = PCI_MAX_FUNCTIONS;
- }
- else {
- numfuncs = 1;
- }
-
- for (func = 0; func < numfuncs; func++) {
-
- pci_read_config_dword(0, slot, func, PCI_COMMAND, &tmp);
-
- if (tmp & PCI_COMMAND_MEMORY) {
-
- pci_read_config_dword(0, slot, func, PCI_VENDOR_ID, &id);
-
- if (id == PCI_INVALID_VENDORDEVICEID || id == 0) continue;
-
- printk("\nSlot %d function: %d\nVendor id: 0x%x, device id: 0x%x\n", slot, func, id & 0xffff, id>>16);
-
- for (pos = 0; pos < 6; pos++) {
- pci_read_config_dword(0, slot, func, PCI_BASE_ADDRESS_0 + pos*4, &tmp);
-
- if (tmp != 0 && tmp != 0xffffffff && (tmp & 0xff) == 0) {
-
- printk("\tBAR %d: %x\n", pos, tmp);
- }
-
- }
- printk("\n");
-
- }
-
- }
- }
- printk("\n");
-#endif
-
- for (i = 0; i < 1536; i++) {
- free(res[i]);
- }
- free(res);
-}
-
-
-
-
-
-
-
-/*
- * This routine determines the maximum bus number in the system
- */
-int init_pci(void)
-{
- unsigned char ucSlotNumber, ucFnNumber, ucNumFuncs;
- unsigned char ucHeader;
- unsigned char ucMaxSubordinate;
- unsigned int ulClass, ulDeviceID;
-
- init_at697_pci();
- pci_allocate_resources();
-
-/*
- * Scan PCI bus 0 looking for PCI-PCI bridges
- */
- for(ucSlotNumber=0;ucSlotNumber<PCI_MAX_DEVICES;ucSlotNumber++) {
- (void)pci_read_config_dword(0,
- ucSlotNumber,
- 0,
- PCI_VENDOR_ID,
- &ulDeviceID);
- if(ulDeviceID==PCI_INVALID_VENDORDEVICEID) {
-/*
- * This slot is empty
- */
- continue;
- }
- (void)pci_read_config_byte(0,
- ucSlotNumber,
- 0,
- PCI_HEADER_TYPE,
- &ucHeader);
- if(ucHeader&PCI_MULTI_FUNCTION) {
- ucNumFuncs=PCI_MAX_FUNCTIONS;
- }
- else {
- ucNumFuncs=1;
- }
- for(ucFnNumber=0;ucFnNumber<ucNumFuncs;ucFnNumber++) {
- (void)pci_read_config_dword(0,
- ucSlotNumber,
- ucFnNumber,
- PCI_VENDOR_ID,
- &ulDeviceID);
- if(ulDeviceID==PCI_INVALID_VENDORDEVICEID) {
-/*
- * This slot/function is empty
- */
- continue;
- }
-
-/*
- * This slot/function has a device fitted.
- */
- (void)pci_read_config_dword(0,
- ucSlotNumber,
- ucFnNumber,
- PCI_CLASS_REVISION,
- &ulClass);
- ulClass >>= 16;
- if (ulClass == PCI_CLASS_BRIDGE_PCI) {
-/*
- * We have found a PCI-PCI bridge
- */
- (void)pci_read_config_byte(0,
- ucSlotNumber,
- ucFnNumber,
- PCI_SUBORDINATE_BUS,
- &ucMaxSubordinate);
- if(ucMaxSubordinate>ucMaxPCIBus) {
- ucMaxPCIBus=ucMaxSubordinate;
- }
- }
- }
- }
- return 0;
-}
-
-/*
- * Return the number of PCI busses in the system
- */
-unsigned char BusCountPCI(void)
-{
- return(ucMaxPCIBus+1);
-}
diff --git a/c/src/lib/libbsp/sparc/leon2/preinstall.am b/c/src/lib/libbsp/sparc/leon2/preinstall.am
index 4b7d4daf29..b53baabfe8 100644
--- a/c/src/lib/libbsp/sparc/leon2/preinstall.am
+++ b/c/src/lib/libbsp/sparc/leon2/preinstall.am
@@ -45,107 +45,221 @@ $(PROJECT_INCLUDE)/tm27.h: include/tm27.h $(PROJECT_INCLUDE)/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/tm27.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/tm27.h
-$(PROJECT_INCLUDE)/rasta.h: include/rasta.h $(PROJECT_INCLUDE)/$(dirstamp)
- $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rasta.h
-PREINSTALL_FILES += $(PROJECT_INCLUDE)/rasta.h
+$(PROJECT_INCLUDE)/debug_defs.h: ../../sparc/shared/include/debug_defs.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/debug_defs.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/debug_defs.h
+
+$(PROJECT_INCLUDE)/bspopts.h: include/bspopts.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bspopts.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bspopts.h
+
+$(PROJECT_INCLUDE)/bsp/bootcard.h: ../../shared/include/bootcard.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/bootcard.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/bootcard.h
+
+$(PROJECT_INCLUDE)/leon.h: include/leon.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/leon.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/leon.h
+
+$(PROJECT_INCLUDE)/coverhd.h: ../../shared/include/coverhd.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/coverhd.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/coverhd.h
+
+$(PROJECT_LIB)/start.$(OBJEXT): start.$(OBJEXT) $(PROJECT_LIB)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_LIB)/start.$(OBJEXT)
+TMPINSTALL_FILES += $(PROJECT_LIB)/start.$(OBJEXT)
+
+$(PROJECT_LIB)/linkcmds: startup/linkcmds $(PROJECT_LIB)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_LIB)/linkcmds
+PREINSTALL_FILES += $(PROJECT_LIB)/linkcmds
+
+$(PROJECT_LIB)/linkcmds.base: ../shared/startup/linkcmds.base $(PROJECT_LIB)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_LIB)/linkcmds.base
+PREINSTALL_FILES += $(PROJECT_LIB)/linkcmds.base
+
+$(PROJECT_INCLUDE)/genirq.h: ../../sparc/shared/include/genirq.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/genirq.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/genirq.h
+
+$(PROJECT_INCLUDE)/bsp/irq-generic.h: ../../shared/include/irq-generic.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/irq-generic.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/irq-generic.h
-$(PROJECT_INCLUDE)/cchip.h: include/cchip.h $(PROJECT_INCLUDE)/$(dirstamp)
- $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/cchip.h
-PREINSTALL_FILES += $(PROJECT_INCLUDE)/cchip.h
+$(PROJECT_INCLUDE)/bsp/irq-info.h: ../../shared/include/irq-info.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/irq-info.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/irq-info.h
+
+$(PROJECT_INCLUDE)/bsp/irq.h: include/bsp/irq.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/irq.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/irq.h
$(PROJECT_INCLUDE)/ambapp.h: ../../sparc/shared/include/ambapp.h $(PROJECT_INCLUDE)/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/ambapp.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/ambapp.h
-$(PROJECT_INCLUDE)/grspw.h: ../../sparc/shared/include/grspw.h $(PROJECT_INCLUDE)/$(dirstamp)
- $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grspw.h
-PREINSTALL_FILES += $(PROJECT_INCLUDE)/grspw.h
+$(PROJECT_INCLUDE)/ambapp_ids.h: ../../sparc/shared/include/ambapp_ids.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/ambapp_ids.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/ambapp_ids.h
+
+$(PROJECT_INCLUDE)/grlib.h: ../../sparc/shared/include/grlib.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grlib.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/grlib.h
+
+$(PROJECT_INCLUDE)/ahbstat.h: ../../sparc/shared/include/ahbstat.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/ahbstat.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/ahbstat.h
+
+$(PROJECT_INCLUDE)/tlib.h: ../../sparc/shared/include/tlib.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/tlib.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/tlib.h
+
+$(PROJECT_INCLUDE)/grpci2.h: ../../sparc/shared/include/grpci2.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grpci2.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/grpci2.h
+
+$(PROJECT_INCLUDE)/gr_701.h: ../../sparc/shared/include/gr_701.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/gr_701.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/gr_701.h
+
+$(PROJECT_INCLUDE)/gr_rasta_adcdac.h: ../../sparc/shared/include/gr_rasta_adcdac.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/gr_rasta_adcdac.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/gr_rasta_adcdac.h
+
+$(PROJECT_INCLUDE)/gr_rasta_io.h: ../../sparc/shared/include/gr_rasta_io.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/gr_rasta_io.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/gr_rasta_io.h
+
+$(PROJECT_INCLUDE)/gr_rasta_tmtc.h: ../../sparc/shared/include/gr_rasta_tmtc.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/gr_rasta_tmtc.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/gr_rasta_tmtc.h
+
+$(PROJECT_INCLUDE)/b1553brm.h: ../../sparc/shared/include/b1553brm.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/b1553brm.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/b1553brm.h
+
+$(PROJECT_INCLUDE)/b1553rt.h: ../../sparc/shared/include/b1553rt.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/b1553rt.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/b1553rt.h
+
+$(PROJECT_INCLUDE)/gr1553b.h: ../../sparc/shared/include/gr1553b.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/gr1553b.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/gr1553b.h
-$(PROJECT_INCLUDE)/grspw_pci.h: ../../sparc/shared/include/grspw_pci.h $(PROJECT_INCLUDE)/$(dirstamp)
- $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grspw_pci.h
-PREINSTALL_FILES += $(PROJECT_INCLUDE)/grspw_pci.h
+$(PROJECT_INCLUDE)/gr1553bc.h: ../../sparc/shared/include/gr1553bc.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/gr1553bc.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/gr1553bc.h
-$(PROJECT_INCLUDE)/grspw_rasta.h: ../../sparc/shared/include/grspw_rasta.h $(PROJECT_INCLUDE)/$(dirstamp)
- $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grspw_rasta.h
-PREINSTALL_FILES += $(PROJECT_INCLUDE)/grspw_rasta.h
+$(PROJECT_INCLUDE)/gr1553bc_list.h: ../../sparc/shared/include/gr1553bc_list.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/gr1553bc_list.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/gr1553bc_list.h
+
+$(PROJECT_INCLUDE)/gr1553bm.h: ../../sparc/shared/include/gr1553bm.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/gr1553bm.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/gr1553bm.h
+
+$(PROJECT_INCLUDE)/gr1553rt.h: ../../sparc/shared/include/gr1553rt.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/gr1553rt.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/gr1553rt.h
$(PROJECT_INCLUDE)/occan.h: ../../sparc/shared/include/occan.h $(PROJECT_INCLUDE)/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/occan.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/occan.h
-$(PROJECT_INCLUDE)/occan_pci.h: ../../sparc/shared/include/occan_pci.h $(PROJECT_INCLUDE)/$(dirstamp)
- $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/occan_pci.h
-PREINSTALL_FILES += $(PROJECT_INCLUDE)/occan_pci.h
-
$(PROJECT_INCLUDE)/grcan.h: ../../sparc/shared/include/grcan.h $(PROJECT_INCLUDE)/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grcan.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/grcan.h
-$(PROJECT_INCLUDE)/grcan_rasta.h: ../../sparc/shared/include/grcan_rasta.h $(PROJECT_INCLUDE)/$(dirstamp)
- $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grcan_rasta.h
-PREINSTALL_FILES += $(PROJECT_INCLUDE)/grcan_rasta.h
+$(PROJECT_INCLUDE)/grspw.h: ../../sparc/shared/include/grspw.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grspw.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/grspw.h
+
+$(PROJECT_INCLUDE)/grspw_router.h: ../../sparc/shared/include/grspw_router.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grspw_router.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/grspw_router.h
+
+$(PROJECT_INCLUDE)/rmap.h: ../../sparc/shared/include/rmap.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rmap.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/rmap.h
+
+$(PROJECT_INCLUDE)/rmap_drv_grspw.h: ../../sparc/shared/include/rmap_drv_grspw.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rmap_drv_grspw.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/rmap_drv_grspw.h
$(PROJECT_INCLUDE)/apbuart.h: ../../sparc/shared/include/apbuart.h $(PROJECT_INCLUDE)/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/apbuart.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/apbuart.h
-$(PROJECT_INCLUDE)/apbuart_pci.h: ../../sparc/shared/include/apbuart_pci.h $(PROJECT_INCLUDE)/$(dirstamp)
- $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/apbuart_pci.h
-PREINSTALL_FILES += $(PROJECT_INCLUDE)/apbuart_pci.h
+$(PROJECT_INCLUDE)/i2cmst.h: ../../sparc/shared/include/i2cmst.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/i2cmst.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/i2cmst.h
-$(PROJECT_INCLUDE)/apbuart_rasta.h: ../../sparc/shared/include/apbuart_rasta.h $(PROJECT_INCLUDE)/$(dirstamp)
- $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/apbuart_rasta.h
-PREINSTALL_FILES += $(PROJECT_INCLUDE)/apbuart_rasta.h
+$(PROJECT_INCLUDE)/spictrl.h: ../../sparc/shared/include/spictrl.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/spictrl.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/spictrl.h
-$(PROJECT_INCLUDE)/b1553brm.h: ../../sparc/shared/include/b1553brm.h $(PROJECT_INCLUDE)/$(dirstamp)
- $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/b1553brm.h
-PREINSTALL_FILES += $(PROJECT_INCLUDE)/b1553brm.h
+$(PROJECT_INCLUDE)/spwcuc.h: ../../sparc/shared/include/spwcuc.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/spwcuc.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/spwcuc.h
-$(PROJECT_INCLUDE)/b1553brm_pci.h: ../../sparc/shared/include/b1553brm_pci.h $(PROJECT_INCLUDE)/$(dirstamp)
- $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/b1553brm_pci.h
-PREINSTALL_FILES += $(PROJECT_INCLUDE)/b1553brm_pci.h
+$(PROJECT_INCLUDE)/grctm.h: ../../sparc/shared/include/grctm.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grctm.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/grctm.h
-$(PROJECT_INCLUDE)/b1553brm_rasta.h: ../../sparc/shared/include/b1553brm_rasta.h $(PROJECT_INCLUDE)/$(dirstamp)
- $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/b1553brm_rasta.h
-PREINSTALL_FILES += $(PROJECT_INCLUDE)/b1553brm_rasta.h
+$(PROJECT_INCLUDE)/grgpio.h: ../../sparc/shared/include/grgpio.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grgpio.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/grgpio.h
-$(PROJECT_INCLUDE)/debug_defs.h: ../../sparc/shared/include/debug_defs.h $(PROJECT_INCLUDE)/$(dirstamp)
- $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/debug_defs.h
-PREINSTALL_FILES += $(PROJECT_INCLUDE)/debug_defs.h
+$(PROJECT_INCLUDE)/gpiolib.h: ../../sparc/shared/include/gpiolib.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/gpiolib.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/gpiolib.h
-$(PROJECT_INCLUDE)/pci.h: ../../sparc/shared/include/pci.h $(PROJECT_INCLUDE)/$(dirstamp)
- $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/pci.h
-PREINSTALL_FILES += $(PROJECT_INCLUDE)/pci.h
+$(PROJECT_INCLUDE)/grpwm.h: ../../sparc/shared/include/grpwm.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grpwm.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/grpwm.h
-$(PROJECT_INCLUDE)/bspopts.h: include/bspopts.h $(PROJECT_INCLUDE)/$(dirstamp)
- $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bspopts.h
-PREINSTALL_FILES += $(PROJECT_INCLUDE)/bspopts.h
+$(PROJECT_INCLUDE)/gradcdac.h: ../../sparc/shared/include/gradcdac.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/gradcdac.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/gradcdac.h
-$(PROJECT_INCLUDE)/bsp/bootcard.h: ../../shared/include/bootcard.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
- $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/bootcard.h
-PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/bootcard.h
+$(PROJECT_INCLUDE)/grtc.h: ../../sparc/shared/include/grtc.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grtc.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/grtc.h
-$(PROJECT_INCLUDE)/leon.h: include/leon.h $(PROJECT_INCLUDE)/$(dirstamp)
- $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/leon.h
-PREINSTALL_FILES += $(PROJECT_INCLUDE)/leon.h
+$(PROJECT_INCLUDE)/grtm.h: ../../sparc/shared/include/grtm.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grtm.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/grtm.h
-$(PROJECT_INCLUDE)/coverhd.h: ../../shared/include/coverhd.h $(PROJECT_INCLUDE)/$(dirstamp)
- $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/coverhd.h
-PREINSTALL_FILES += $(PROJECT_INCLUDE)/coverhd.h
+$(PROJECT_INCLUDE)/drvmgr/$(dirstamp):
+ @$(MKDIR_P) $(PROJECT_INCLUDE)/drvmgr
+ @: > $(PROJECT_INCLUDE)/drvmgr/$(dirstamp)
+PREINSTALL_DIRS += $(PROJECT_INCLUDE)/drvmgr/$(dirstamp)
-$(PROJECT_LIB)/start.$(OBJEXT): start.$(OBJEXT) $(PROJECT_LIB)/$(dirstamp)
- $(INSTALL_DATA) $< $(PROJECT_LIB)/start.$(OBJEXT)
-TMPINSTALL_FILES += $(PROJECT_LIB)/start.$(OBJEXT)
+$(PROJECT_INCLUDE)/drvmgr/ambapp_bus.h: ../../sparc/shared/include/drvmgr/ambapp_bus.h $(PROJECT_INCLUDE)/drvmgr/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/drvmgr/ambapp_bus.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/drvmgr/ambapp_bus.h
-$(PROJECT_LIB)/linkcmds: startup/linkcmds $(PROJECT_LIB)/$(dirstamp)
- $(INSTALL_DATA) $< $(PROJECT_LIB)/linkcmds
-PREINSTALL_FILES += $(PROJECT_LIB)/linkcmds
+$(PROJECT_INCLUDE)/drvmgr/ambapp_bus_rmap.h: ../../sparc/shared/include/drvmgr/ambapp_bus_rmap.h $(PROJECT_INCLUDE)/drvmgr/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/drvmgr/ambapp_bus_rmap.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/drvmgr/ambapp_bus_rmap.h
-$(PROJECT_LIB)/linkcmds.base: ../shared/startup/linkcmds.base $(PROJECT_LIB)/$(dirstamp)
- $(INSTALL_DATA) $< $(PROJECT_LIB)/linkcmds.base
-PREINSTALL_FILES += $(PROJECT_LIB)/linkcmds.base
+$(PROJECT_INCLUDE)/drvmgr/leon2_amba_bus.h: ../../sparc/shared/include/drvmgr/leon2_amba_bus.h $(PROJECT_INCLUDE)/drvmgr/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/drvmgr/leon2_amba_bus.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/drvmgr/leon2_amba_bus.h
-$(PROJECT_INCLUDE)/i2cmst.h: ../../sparc/shared/include/i2cmst.h $(PROJECT_INCLUDE)/$(dirstamp)
- $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/i2cmst.h
-PREINSTALL_FILES += $(PROJECT_INCLUDE)/i2cmst.h
+$(PROJECT_INCLUDE)/drvmgr/spw_bus.h: ../../sparc/shared/include/drvmgr/spw_bus.h $(PROJECT_INCLUDE)/drvmgr/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/drvmgr/spw_bus.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/drvmgr/spw_bus.h
+$(PROJECT_INCLUDE)/drvmgr/spw_bus_ids.h: ../../sparc/shared/include/drvmgr/spw_bus_ids.h $(PROJECT_INCLUDE)/drvmgr/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/drvmgr/spw_bus_ids.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/drvmgr/spw_bus_ids.h
+
+if HAS_NETWORKING
+$(PROJECT_INCLUDE)/greth.h: ../../sparc/shared/include/greth.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/greth.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/greth.h
+
+$(PROJECT_INCLUDE)/network_interface_add.h: ../../sparc/shared/include/network_interface_add.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/network_interface_add.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/network_interface_add.h
+endif
diff --git a/c/src/lib/libbsp/sparc/leon2/rasta/rasta.c b/c/src/lib/libbsp/sparc/leon2/rasta/rasta.c
deleted file mode 100644
index 7b66b07246..0000000000
--- a/c/src/lib/libbsp/sparc/leon2/rasta/rasta.c
+++ /dev/null
@@ -1,388 +0,0 @@
-/*
- * $Id$
- */
-
-#include <rtems/bspIo.h>
-#include <pci.h>
-#include <rasta.h>
-#include <ambapp.h>
-#include <grcan_rasta.h>
-#include <grspw_rasta.h>
-#include <b1553brm_rasta.h>
-#include <apbuart_rasta.h>
-
-#include <string.h>
-
-/* If RASTA_SRAM is defined SRAM will be used, else SDRAM */
-/*#define RASTA_SRAM 1*/
-
-#define RASTA_IRQ 5
-
-/* Offset from 0x80000000 (dual bus version) */
-#define AHB1_IOAREA_BASE_ADDR 0x80100000
-#define APB2_OFFSET 0x200000
-#define IRQ_OFFSET 0x200500
-#define GRHCAN_OFFSET 0x201000
-#define BRM_OFFSET 0x100000
-#define SPW_OFFSET 0xa00
-#define UART_OFFSET 0x200200
-#define GPIO0_OFF 0x200600
-#define GPIO1_OFF 0x200700
-
-/* #define DEBUG 1 */
-
-#ifdef DEBUG
-#define DBG(x...) printk(x)
-#else
-#define DBG(x...)
-#endif
-
-/*
-typedef struct {
- volatile unsigned int ilevel;
- volatile unsigned int ipend;
- volatile unsigned int iforce;
- volatile unsigned int iclear;
- volatile unsigned int mpstat;
- volatile unsigned int notused01;
- volatile unsigned int notused02;
- volatile unsigned int notused03;
- volatile unsigned int notused10;
- volatile unsigned int notused11;
- volatile unsigned int notused12;
- volatile unsigned int notused13;
- volatile unsigned int notused20;
- volatile unsigned int notused21;
- volatile unsigned int notused22;
- volatile unsigned int notused23;
- volatile unsigned int mask[16];
- volatile unsigned int force[16];
-} LEON3_IrqCtrl_Regs_Map;
-*/
-static int bus, dev, fun;
-
-LEON3_IrqCtrl_Regs_Map *irq = NULL;
-LEON_Register_Map *regs = (LEON_Register_Map *)0x80000000;
-
-struct gpio_reg *gpio0, *gpio1;
-
-/* static rtems_isr pci_interrupt_handler (rtems_vector_number v) { */
-
-/* volatile unsigned int *pci_int = (volatile unsigned int *) 0x80000168; */
-/* volatile unsigned int *pci_mem = (volatile unsigned int *) 0xb0400000; */
-
-/* if (*pci_int & 0x20) { */
-
-/* *pci_int = 0x20; */
-
-/* *pci_mem = 0; */
-
-/* printk("pci died\n"); */
-
-/* } */
-
-/* } */
-
-void *uart0_int_arg, *uart1_int_arg;
-void *spw0_int_arg, *spw1_int_arg, *spw2_int_arg;
-void *grcan_int_arg;
-void *brm_int_arg;
-
-void (*uart0_int_handler)(int irq, void *arg) = NULL;
-void (*uart1_int_handler)(int irq, void *arg) = NULL;
-void (*spw0_int_handler)(int irq, void *arg) = NULL;
-void (*spw1_int_handler)(int irq, void *arg) = NULL;
-void (*spw2_int_handler)(int irq, void *arg) = NULL;
-void (*grcan_int_handler)(int irq, void *arg) = NULL;
-void (*brm_int_handler)(int irq, void *arg) = NULL;
-
-static rtems_isr rasta_interrupt_handler (rtems_vector_number v)
-{
- unsigned int status;
-
- status = irq->ipend;
-
- if ( (status & GRCAN_IRQ) && grcan_int_handler ) {
- grcan_int_handler(GRCAN_IRQNO,grcan_int_arg);
- }
-
- if (status & SPW_IRQ) {
- if ( (status & SPW0_IRQ) && spw0_int_handler ){
- spw0_int_handler(SPW0_IRQNO,spw0_int_arg);
- }
-
- if ( (status & SPW1_IRQ) && spw1_int_handler ){
- spw1_int_handler(SPW1_IRQNO,spw1_int_arg);
- }
-
- if ( (status & SPW2_IRQ) && spw2_int_handler ){
- spw2_int_handler(SPW2_IRQNO,spw2_int_arg);
- }
- }
- if ((status & BRM_IRQ) && brm_int_handler ){
- brm_int_handler(BRM_IRQNO,brm_int_arg);
- }
- if ( (status & UART0_IRQ) && uart0_int_handler ) {
- uart0_int_handler(UART0_IRQNO,uart0_int_arg);
- }
- if ( (status & UART1_IRQ) && uart1_int_handler) {
- uart1_int_handler(UART1_IRQNO,uart1_int_arg);
- }
-
- DBG("RASTA-IRQ: 0x%x\n",status);
- irq->iclear = status;
-
-}
-
-void rasta_interrrupt_register(void *handler, int irqno, void *arg)
-{
- DBG("RASTA: Registering irq %d\n",irqno);
- if ( irqno == UART0_IRQNO ){
- DBG("RASTA: Registering uart0 handler: 0x%x, arg: 0x%x\n",handler,arg);
- uart0_int_handler = handler;
- uart0_int_arg = arg;
-
- /* unmask interrupt source */
- irq->iclear = UART0_IRQ;
- irq->mask[0] |= UART0_IRQ;
- }
-
- if ( irqno == UART1_IRQNO ){
- DBG("RASTA: Registering uart1 handler: 0x%x, arg: 0x%x\n",handler,arg);
- uart1_int_handler = handler;
- uart1_int_arg = arg;
-
- /* unmask interrupt source */
- irq->iclear = UART1_IRQ;
- irq->mask[0] |= UART1_IRQ;
- }
-
- if ( irqno == SPW0_IRQNO ){
- DBG("RASTA: Registering spw0 handler: 0x%x, arg: 0x%x\n",handler,arg);
- spw0_int_handler = handler;
- spw0_int_arg = arg;
-
- /* unmask interrupt source */
- irq->iclear = SPW0_IRQ;
- irq->mask[0] |= SPW0_IRQ;
- }
-
- if ( irqno == SPW1_IRQNO ){
- DBG("RASTA: Registering spw1 handler: 0x%x, arg: 0x%x\n",handler,arg);
- spw1_int_handler = handler;
- spw1_int_arg = arg;
-
- /* unmask interrupt source */
- irq->iclear = SPW1_IRQ;
- irq->mask[0] |= SPW1_IRQ;
- }
-
- if ( irqno == SPW2_IRQNO ){
- DBG("RASTA: Registering spw2 handler: 0x%x, arg: 0x%x\n",handler,arg);
- spw2_int_handler = handler;
- spw2_int_arg = arg;
-
- /* unmask interrupt source */
- irq->iclear = SPW2_IRQ;
- irq->mask[0] |= SPW2_IRQ;
- }
-
- if ( irqno == GRCAN_IRQNO ){
- DBG("RASTA: Registering GRCAN handler: 0x%x, arg: 0x%x\n",handler,arg);
- grcan_int_handler = handler;
- grcan_int_arg = arg;
-
- /* unmask interrupt source */
- irq->iclear = GRCAN_IRQ;
- irq->mask[0] |= GRCAN_IRQ;
- }
-
- if ( irqno == BRM_IRQNO ){
- DBG("RASTA: Registering BRM handler: 0x%x, arg: 0x%x\n",handler,arg);
- brm_int_handler = handler;
- brm_int_arg = arg;
-
- /* unmask interrupt source */
- irq->iclear = BRM_IRQ;
- irq->mask[0] |= BRM_IRQ;
- }
-}
-
-
-int rasta_get_gpio(amba_confarea_type *abus, int index, struct gpio_reg **regs, int *irq)
-{
- amba_apb_device dev;
- int cores;
-
- if ( !abus )
- return -1;
-
- /* Scan PnP info for GPIO port number 'index' */
- cores = amba_find_next_apbslv(abus,VENDOR_GAISLER,GAISLER_PIOPORT,&dev,index);
- if ( cores < 1 )
- return -1;
-
- if ( regs )
- *regs = (struct gpio_reg *)dev.start;
-
- if ( irq )
- *irq = dev.irq;
-
- return 0;
-}
-
-/* AMBA Plug&Play information */
-static amba_confarea_type abus;
-static struct amba_mmap amba_maps[3];
-
-int rasta_register(void)
-{
- unsigned int bar0, bar1, data;
-
- unsigned int *page0 = NULL;
- unsigned int *apb_base = NULL;
- int found=0;
-
-
- DBG("Searching for RASTA board ...");
-
- /* Search PCI vendor/device id. */
- if (BSP_pciFindDevice(0x1AC8, 0x0010, 0, &bus, &dev, &fun) == 0) {
- found = 1;
- }
-
- /* Search old PCI vendor/device id. */
- if ( (!found) && (BSP_pciFindDevice(0x16E3, 0x0210, 0, &bus, &dev, &fun) == 0) ) {
- found = 1;
- }
-
- /* Did we find a RASTA board? */
- if ( !found )
- return -1;
-
- DBG(" found it (dev/fun: %d/%d).\n", dev, fun);
-
- pci_read_config_dword(bus, dev, fun, 0x10, &bar0);
- pci_read_config_dword(bus, dev, fun, 0x14, &bar1);
-
- page0 = (unsigned int *)(bar0 + 0x400000);
- *page0 = 0x80000000; /* Point PAGE0 to start of APB */
-
- apb_base = (unsigned int *)(bar0+APB2_OFFSET);
-
-/* apb_base[0] = 0x000002ff;
- apb_base[1] = 0x8a205260;
- apb_base[2] = 0x00184000; */
-
- /* Configure memory controller */
-#ifdef RASTA_SRAM
- apb_base[0] = 0x000002ff;
- apb_base[1] = 0x00001260;
- apb_base[2] = 0x000e8000;
-#else
- apb_base[0] = 0x000002ff;
- apb_base[1] = 0x82206000;
- apb_base[2] = 0x000e8000;
-#endif
- /* Set up rasta irq controller */
- irq = (LEON3_IrqCtrl_Regs_Map *) (bar0+IRQ_OFFSET);
- irq->iclear = 0xffff;
- irq->ilevel = 0;
- irq->mask[0] = 0xffff & ~(UART0_IRQ|UART1_IRQ|SPW0_IRQ|SPW1_IRQ|SPW2_IRQ|GRCAN_IRQ|BRM_IRQ);
-
- /* Configure AT697 ioport bit 7 to input pci irq */
- regs->PIO_Direction &= ~(1<<7);
- regs->PIO_Interrupt |= (0x87<<8); /* level sensitive */
-
- apb_base[0x100] |= 0x40000000; /* Set GRPCI mmap 0x4 */
- apb_base[0x104] = 0x40000000; /* 0xA0000000; Point PAGE1 to RAM */
-
-
- /* set parity error response */
- pci_read_config_dword(bus, dev, fun, 0x4, &data);
- pci_write_config_dword(bus, dev, fun, 0x4, data|0x40);
-
-
- pci_master_enable(bus, dev, fun);
-
- /* install PCI interrupt vector */
- /* set_vector(pci_interrupt_handler,14+0x10, 1); */
-
-
- /* install interrupt vector */
- set_vector(rasta_interrupt_handler, RASTA_IRQ+0x10, 1);
-
- /* Scan AMBA Plug&Play */
-
- /* AMBA MAP bar0 (in CPU) ==> 0x80000000(remote amba address) */
- amba_maps[0].size = 0x10000000;
- amba_maps[0].cpu_adr = bar0;
- amba_maps[0].remote_amba_adr = 0x80000000;
-
- /* AMBA MAP bar1 (in CPU) ==> 0x40000000(remote amba address) */
- amba_maps[1].size = 0x10000000;
- amba_maps[1].cpu_adr = bar1;
- amba_maps[1].remote_amba_adr = 0x40000000;
-
- /* Mark end of table */
- amba_maps[2].size=0;
- amba_maps[2].cpu_adr = 0;
- amba_maps[2].remote_amba_adr = 0;
-
- memset(&abus,0,sizeof(abus));
-
- /* Start AMBA PnP scan at first AHB bus */
- amba_scan(&abus,bar0+(AHB1_IOAREA_BASE_ADDR&~0xf0000000),&amba_maps[0]);
-
- printk("Registering RASTA GRCAN driver\n\r");
-
- /*grhcan_register(bar0 + GRHCAN_OFFSET, bar1);*/
- grcan_rasta_int_reg=rasta_interrrupt_register;
- if ( grcan_rasta_ram_register(&abus,bar1+0x20000) ){
- printk("Failed to register RASTA GRCAN driver\n\r");
- return -1;
- }
-
- printk("Registering RASTA BRM driver\n\r");
-
- /*brm_register(bar0 + BRM_OFFSET, bar1);*/
- /* register the BRM RASTA driver, use 128k on RASTA SRAM... */
- b1553brm_rasta_int_reg=rasta_interrrupt_register;
- if ( b1553brm_rasta_register(&abus,2,0,3,bar1,0x40000000) ){
- printk("Failed to register BRM RASTA driver\n");
- return -1;
- }
-
- /* provide the spacewire driver with AMBA Plug&Play
- * info so that it can find the GRSPW cores.
- */
- grspw_rasta_int_reg=rasta_interrrupt_register;
- if ( grspw_rasta_register(&abus,bar1) ){
- printk("Failed to register RASTA GRSPW driver\n\r");
- return -1;
- }
-
- /* provide the spacewire driver with AMBA Plug&Play
- * info so that it can find the GRSPW cores.
- */
- apbuart_rasta_int_reg=rasta_interrrupt_register;
- if ( apbuart_rasta_register(&abus) ){
- printk("Failed to register RASTA APBUART driver\n\r");
- return -1;
- }
-
- /* Find GPIO0 address */
- if ( rasta_get_gpio(&abus,0,&gpio0,NULL) ){
- printk("Failed to get address for RASTA GPIO0\n\r");
- return -1;
- }
-
- /* Find GPIO1 address */
- if ( rasta_get_gpio(&abus,1,&gpio1,NULL) ){
- printk("Failed to get address for RASTA GPIO1\n\r");
- return -1;
- }
-
- /* Successfully registered the RASTA board */
- return 0;
-}
diff --git a/c/src/lib/libbsp/sparc/leon2/startup/bsppredriver.c b/c/src/lib/libbsp/sparc/leon2/startup/bsppredriver.c
new file mode 100644
index 0000000000..eef11540da
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/leon2/startup/bsppredriver.c
@@ -0,0 +1,80 @@
+/* Installs the BSP pre-driver hook
+ *
+ * COPYRIGHT (c) 2011
+ * Aeroflex Gaisler
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+
+#include <bsp.h>
+
+/* If RTEMS_DRVMGR_STARTUP is defined extra code is added that
+ * registers the LEON2 AMBA bus driver as root driver into the
+ * driver manager.
+ *
+ * The structues here are declared weak so that the user can override
+ * the configuration and add custom cores in the RTEMS project.
+ */
+#ifdef RTEMS_DRVMGR_STARTUP
+#include <drvmgr/leon2_amba_bus.h>
+
+/* All drivers included by BSP, this is overridden by the user by including
+ * the devmgr_confdefs.h. No specifc drivers needed by BSP since IRQ/TIMER/UART
+ * is not drvmgr drivers.
+ */
+struct drvmgr_drv_reg_func drvmgr_drivers[] __attribute__((weak)) =
+{
+ {NULL} /* End array with NULL */
+};
+
+/* Defines what cores are avilable on the bus in addition to the standard
+ * LEON2 peripherals.
+ */
+struct leon2_core leon2_amba_custom_cores[] __attribute__((weak)) =
+{
+ EMPTY_LEON2_CORE
+};
+
+/* Configure LEON2 Root bus driver */
+struct leon2_bus leon2_bus_config __attribute__((weak)) =
+{
+ &leon2_std_cores[0], /* The standard cores, defined by driver */
+ &leon2_amba_custom_cores[0], /* custom cores, defined by us */
+ DRVMGR_TRANSLATE_ONE2ONE,
+ DRVMGR_TRANSLATE_ONE2ONE,
+};
+
+/* Driver resources on LEON2 AMBA bus. Used to set options for particular
+ * LEON2 cores, it is up to the driver to look at the configuration paramters
+ * once started.
+ */
+struct drvmgr_bus_res leon2_amba_res __attribute__((weak)) =
+{
+ .next = NULL,
+ .resource = {
+ RES_EMPTY
+ },
+};
+#endif
+
+/*
+ * bsp_predriver_hook
+ *
+ * BSP predriver hook. Called just before drivers are initialized.
+ * Is used to initialize shared interrupt handling.
+ */
+void bsp_predriver_hook( void )
+{
+ /* Initialize shared interrupt handling, must be done after IRQ
+ * controller has been found and initialized.
+ */
+ BSP_shared_interrupt_init();
+
+#ifdef RTEMS_DRVMGR_STARTUP
+ leon2_root_register(&leon2_bus_config, &leon2_amba_res);
+#endif
+}
diff --git a/c/src/lib/libbsp/sparc/leon2/startup/setvec.c b/c/src/lib/libbsp/sparc/leon2/startup/setvec.c
index c7b8af6616..028b17a26a 100644
--- a/c/src/lib/libbsp/sparc/leon2/startup/setvec.c
+++ b/c/src/lib/libbsp/sparc/leon2/startup/setvec.c
@@ -42,7 +42,7 @@ rtems_isr_entry set_vector( /* returns old vector */
uint32_t real_trap;
uint32_t source;
- if ( type )
+ if ( type == SET_VECTOR_INT )
rtems_interrupt_catch( handler, vector, &previous_isr );
else
_CPU_ISR_install_raw_handler( vector, handler, (void *)&previous_isr );
diff --git a/c/src/lib/libbsp/sparc/leon3/Makefile.am b/c/src/lib/libbsp/sparc/leon3/Makefile.am
index ebe8ffbf41..a9d4fea088 100644
--- a/c/src/lib/libbsp/sparc/leon3/Makefile.am
+++ b/c/src/lib/libbsp/sparc/leon3/Makefile.am
@@ -31,7 +31,10 @@ noinst_LIBRARIES = libbspstart.a
libbspstart_a_SOURCES = ../../sparc/shared/start.S
project_lib_DATA = start.$(OBJEXT)
-dist_project_lib_DATA += startup/linkcmds ../shared/startup/linkcmds.base
+dist_project_lib_DATA += \
+ startup/linkcmds \
+ startup/linkcmds_ngmp \
+ ../shared/startup/linkcmds.base
noinst_LIBRARIES += libbsp.a
libbsp_a_SOURCES =
@@ -39,55 +42,196 @@ libbsp_a_SOURCES =
# startup
libbsp_a_SOURCES += ../../shared/bspclean.c ../../shared/bsplibc.c \
../../shared/bsppost.c ../../shared/bootcard.c startup/bspstart.c \
- ../../sparc/shared/bsppretaskinghook.c ../../shared/bsppredriverhook.c \
+ ../../sparc/shared/bsppretaskinghook.c startup/bsppredriver.c \
../../sparc/shared/bspgetworkarea.c ../../shared/sbrk.c startup/setvec.c \
+ ../../sparc/shared/startup/early_malloc.c \
startup/spurious.c startup/bspidle.S
# gnatsupp
libbsp_a_SOURCES += gnatsupp/gnatsupp.c ../../sparc/shared/gnatcommon.c
-# amba
+# AMBA bus
include_HEADERS += include/amba.h
include_HEADERS += ../../sparc/shared/include/ambapp.h
-libbsp_a_SOURCES += amba/amba.c ../../sparc/shared/amba/ambapp.c
+include_HEADERS += ../../sparc/shared/include/ambapp_ids.h
+include_HEADERS += ../../sparc/shared/include/grlib.h
+include_HEADERS += ../../sparc/shared/include/ahbstat.h
+libbsp_a_SOURCES += amba/amba.c
+libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp.c
+libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp_alloc.c
+libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp_count.c
+libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp_depth.c
+libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp_find_by_idx.c
+libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp_freq.c
+libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp_parent.c
+libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp_old.c
+libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp_names.c
+libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp_show.c
+libbsp_a_SOURCES += ../../sparc/shared/amba/ahbstat.c
+
+# Clock Driver and Timer Library
+include_HEADERS += ../../sparc/shared/include/tlib.h
+libbsp_a_SOURCES += ../../sparc/shared/timer/gptimer.c
+libbsp_a_SOURCES += ../../sparc/shared/timer/tlib.c
+libbsp_a_SOURCES += ../../sparc/shared/timer/tlib_ckinit.c
+# non-Driver Manager Clock Implementation
+libbsp_a_SOURCES += clock/ckinit.c ../../../shared/clockdrv_shell.h
+
# console
libbsp_a_SOURCES += console/console.c
+libbsp_a_SOURCES += ../../sparc/shared/uart/cons.c
+libbsp_a_SOURCES += ../../sparc/shared/uart/apbuart_cons.c
+include_HEADERS += ../../sparc/shared/include/cons.h
# debugio
libbsp_a_SOURCES += console/debugputs.c
-# clock
-libbsp_a_SOURCES += clock/ckinit.c ../../../shared/clockdrv_shell.h
+
+# IRQ
+include_HEADERS += ../../sparc/shared/include/genirq.h
+include_bsp_HEADERS = \
+ ../../shared/include/irq-generic.h \
+ ../../shared/include/irq-info.h \
+ include/bsp/irq.h
+libbsp_a_SOURCES += \
+ startup/eirq.c \
+ ../../sparc/shared/irq/genirq.c \
+ ../../sparc/shared/irq/irq-shared.c \
+ ../../shared/src/irq-generic.c \
+ ../../shared/src/irq-legacy.c \
+ ../../shared/src/irq-info.c \
+ ../../shared/src/irq-shell.c \
+ ../../shared/src/irq-server.c
+
# PCI
-include_HEADERS += ../../sparc/shared/include/pci.h
-libbsp_a_SOURCES += pci/pci.c ../../sparc/shared/pci/pcifinddevice.c
+include_HEADERS += ../../sparc/shared/include/grpci2.h
+libbsp_a_SOURCES += ../../sparc/shared/pci/grpci.c
+libbsp_a_SOURCES += ../../sparc/shared/pci/grpci2.c
+libbsp_a_SOURCES += ../../sparc/shared/pci/pcif.c
+libbsp_a_SOURCES += ../../sparc/shared/pci/pci_memreg_sparc_le.c
+libbsp_a_SOURCES += ../../sparc/shared/pci/pci_memreg_sparc_be.c
+
+# PCI target devices
+include_HEADERS += ../../sparc/shared/include/gr_701.h
+include_HEADERS += ../../sparc/shared/include/gr_rasta_adcdac.h
+include_HEADERS += ../../sparc/shared/include/gr_rasta_io.h
+include_HEADERS += ../../sparc/shared/include/gr_rasta_tmtc.h
+include_HEADERS += ../../sparc/shared/include/gr_tmtc_1553.h
+libbsp_a_SOURCES += ../../sparc/shared/pci/gr_701.c
+libbsp_a_SOURCES += ../../sparc/shared/pci/gr_rasta_adcdac.c
+libbsp_a_SOURCES += ../../sparc/shared/pci/gr_rasta_io.c
+libbsp_a_SOURCES += ../../sparc/shared/pci/gr_rasta_spw_router.c
+libbsp_a_SOURCES += ../../sparc/shared/pci/gr_rasta_tmtc.c
+libbsp_a_SOURCES += ../../sparc/shared/pci/gr_tmtc_1553.c
# B1553BRM
-include_HEADERS += ../../sparc/shared/include/b1553brm.h \
- ../../sparc/shared/include/b1553brm_pci.h
-libbsp_a_SOURCES += ../../sparc/shared/1553/b1553brm.c \
- ../../sparc/shared/1553/b1553brm_pci.c
+include_HEADERS += ../../sparc/shared/include/b1553brm.h
+include_HEADERS += ../../sparc/shared/include/b1553rt.h
+libbsp_a_SOURCES += ../../sparc/shared/1553/b1553brm.c
+libbsp_a_SOURCES += ../../sparc/shared/1553/b1553rt.c
+
+# GR1553B
+include_HEADERS += ../../sparc/shared/include/gr1553b.h
+include_HEADERS += ../../sparc/shared/include/gr1553bc.h
+include_HEADERS += ../../sparc/shared/include/gr1553bc_list.h
+include_HEADERS += ../../sparc/shared/include/gr1553bm.h
+include_HEADERS += ../../sparc/shared/include/gr1553rt.h
+libbsp_a_SOURCES += ../../sparc/shared/1553/gr1553b.c
+libbsp_a_SOURCES += ../../sparc/shared/1553/gr1553bc.c
+libbsp_a_SOURCES += ../../sparc/shared/1553/gr1553bm.c
+libbsp_a_SOURCES += ../../sparc/shared/1553/gr1553rt.c
# CAN
include_HEADERS += ../../sparc/shared/include/occan.h \
- ../../sparc/shared/include/occan_pci.h ../../sparc/shared/include/grcan.h
+ ../../sparc/shared/include/grcan.h
libbsp_a_SOURCES += ../../sparc/shared/can/occan.c \
- ../../sparc/shared/can/occan_pci.c ../../sparc/shared/can/grcan.c
+ ../../sparc/shared/can/grcan.c
# SpaceWire
-include_HEADERS += ../../sparc/shared/include/grspw.h \
- ../../sparc/shared/include/grspw_pci.h
-libbsp_a_SOURCES += ../../sparc/shared/spw/grspw.c \
- ../../sparc/shared/spw/grspw_pci.c
+include_HEADERS += ../../sparc/shared/include/grspw.h
+include_HEADERS += ../../sparc/shared/include/grspw_pkt.h
+include_HEADERS += ../../sparc/shared/include/grspw_router.h
+include_HEADERS += ../../sparc/shared/include/rmap.h
+include_HEADERS += ../../sparc/shared/include/rmap_drv_grspw.h
+libbsp_a_SOURCES += ../../sparc/shared/spw/grspw.c
+libbsp_a_SOURCES += ../../sparc/shared/spw/grspw_pkt.c
+libbsp_a_SOURCES += ../../sparc/shared/spw/grspw_router.c
+libbsp_a_SOURCES += ../../sparc/shared/spw/rmap.c
+libbsp_a_SOURCES += ../../sparc/shared/spw/rmap_drv_grspw.c
# UART
-include_HEADERS += ../../sparc/shared/include/apbuart.h \
- ../../sparc/shared/include/apbuart_pci.h
-libbsp_a_SOURCES += ../../sparc/shared/uart/apbuart.c \
- ../../sparc/shared/uart/apbuart_pci.c
+include_HEADERS += ../../sparc/shared/include/apbuart.h
+libbsp_a_SOURCES += ../../sparc/shared/uart/apbuart.c
# I2CMST
include_HEADERS += ../../sparc/shared/include/i2cmst.h
libbsp_a_SOURCES += ../../sparc/shared/i2c/i2cmst.c
+# SPI
+include_HEADERS += ../../sparc/shared/include/spictrl.h
+libbsp_a_SOURCES += ../../sparc/shared/spi/spictrl.c
+
+# TIME
+include_HEADERS += ../../sparc/shared/include/spwcuc.h
+include_HEADERS += ../../sparc/shared/include/grctm.h
+libbsp_a_SOURCES += ../../sparc/shared/time/spwcuc.c
+libbsp_a_SOURCES += ../../sparc/shared/time/grctm.c
+
+# GPIO
+include_HEADERS += ../../sparc/shared/include/grgpio.h
+include_HEADERS += ../../sparc/shared/include/gpiolib.h
+libbsp_a_SOURCES += ../../sparc/shared/gpio/grgpio.c
+libbsp_a_SOURCES += ../../sparc/shared/gpio/gpiolib.c
+
+# GRAES
+include_HEADERS += ../../sparc/shared/include/graes.h
+libbsp_a_SOURCES += ../../sparc/shared/graes/graes.c
+
+# GRPWRX
+include_HEADERS += ../../sparc/shared/include/grpwrx.h
+libbsp_a_SOURCES += ../../sparc/shared/grpwrx/grpwrx.c
+
+# PWM
+include_HEADERS += ../../sparc/shared/include/grpwm.h
+libbsp_a_SOURCES += ../../sparc/shared/pwm/grpwm.c
+
+# ADC and DAC
+include_HEADERS += ../../sparc/shared/include/gradcdac.h
+libbsp_a_SOURCES += ../../sparc/shared/analog/gradcdac.c
+
+# Memory controllers
+libbsp_a_SOURCES += ../../sparc/shared/mem/mctrl.c
+libbsp_a_SOURCES += ../../sparc/shared/mem/mctrl_rmap.c
+
# timer
libbsp_a_SOURCES += timer/timer.c
+libbsp_a_SOURCES += timer/watchdog.c
+
+# GR712
+include_HEADERS += ../../sparc/shared/include/grascs.h
+include_HEADERS += ../../sparc/shared/include/satcan.h
+include_HEADERS += ../../sparc/shared/include/canmux.h
+include_HEADERS += ../../sparc/shared/include/grslink.h
+libbsp_a_SOURCES += ../../sparc/shared/ascs/grascs.c
+libbsp_a_SOURCES += ../../sparc/shared/can/satcan.c
+libbsp_a_SOURCES += ../../sparc/shared/can/canmux.c
+libbsp_a_SOURCES += ../../sparc/shared/slink/grslink.c
+
+# TM/TC
+include_HEADERS += ../../sparc/shared/include/grtc.h
+include_HEADERS += ../../sparc/shared/include/grtm.h
+libbsp_a_SOURCES += ../../sparc/shared/tmtc/grtc.c
+libbsp_a_SOURCES += ../../sparc/shared/tmtc/grtc_rmap.c
+libbsp_a_SOURCES += ../../sparc/shared/tmtc/grtm.c
+libbsp_a_SOURCES += ../../sparc/shared/tmtc/grtm_rmap.c
+
+# Driver Manager
+include_drvmgrdir = $(includedir)/drvmgr
+include_drvmgr_HEADERS = ../../sparc/shared/include/drvmgr/ambapp_bus_grlib.h
+include_drvmgr_HEADERS += ../../sparc/shared/include/drvmgr/ambapp_bus_rmap.h
+include_drvmgr_HEADERS += ../../sparc/shared/include/drvmgr/ambapp_bus.h
+include_drvmgr_HEADERS += ../../sparc/shared/include/drvmgr/spw_bus.h
+include_drvmgr_HEADERS += ../../sparc/shared/include/drvmgr/spw_bus_ids.h
+libbsp_a_SOURCES += ../../sparc/shared/drvmgr/ambapp_bus.c
+libbsp_a_SOURCES += ../../sparc/shared/drvmgr/ambapp_bus_grlib.c
+libbsp_a_SOURCES += ../../sparc/shared/drvmgr/ambapp_bus_rmap.c
+libbsp_a_SOURCES += ../../sparc/shared/drvmgr/spw_bus.c
if HAS_NETWORKING
noinst_PROGRAMS += leon_smc91111.rel
@@ -107,12 +251,20 @@ endif
if HAS_NETWORKING
noinst_PROGRAMS += leon_greth.rel
-leon_greth_rel_SOURCES = leon_greth/leon_greth.c
+libbsp_a_SOURCES += leon_greth/leon_greth.c
+leon_greth_rel_SOURCES = ../../sparc/shared/net/greth.c
+include_HEADERS += ../../sparc/shared/include/greth.h
leon_greth_rel_CPPFLAGS = $(AM_CPPFLAGS)
leon_greth_rel_CPPFLAGS += -D__INSIDE_RTEMS_BSD_TCPIP_STACK__
leon_greth_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
endif
+# BSP Network configuration
+if HAS_NETWORKING
+include_HEADERS += ../../sparc/shared/include/network_interface_add.h
+libbsp_a_SOURCES += ../../sparc/shared/net/network_interface_add.c
+endif
+
EXTRA_DIST = shmsupp/README
if HAS_MP
# shmsupp
@@ -120,7 +272,9 @@ libbsp_a_SOURCES += shmsupp/addrconv.c shmsupp/getcfg.c shmsupp/lock.c \
shmsupp/mpisr.c
endif
-libbsp_a_LIBADD = ../../../libcpu/@RTEMS_CPU@/cache.rel \
+libbsp_a_LIBADD = \
+ ../../../libcpu/@RTEMS_CPU@/access.rel \
+ ../../../libcpu/@RTEMS_CPU@/cache.rel \
../../../libcpu/@RTEMS_CPU@/reg_win.rel \
../../../libcpu/@RTEMS_CPU@/syscall.rel
diff --git a/c/src/lib/libbsp/sparc/leon3/amba/amba.c b/c/src/lib/libbsp/sparc/leon3/amba/amba.c
index 6f86e27ded..a439300d27 100644
--- a/c/src/lib/libbsp/sparc/leon3/amba/amba.c
+++ b/c/src/lib/libbsp/sparc/leon3/amba/amba.c
@@ -1,10 +1,10 @@
/*
- * AMBA Plag & Play Bus Driver
+ * AMBA Plug & Play Bus Driver
*
* This driver hook performs bus scanning.
*
- * COPYRIGHT (c) 2004.
- * Gaisler Research
+ * COPYRIGHT (c) 2011.
+ * Aeroflex Gaisler
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
@@ -14,14 +14,60 @@
*/
#include <bsp.h>
+#include <ambapp.h>
-/* Structure containing address to devices found on the Amba Plug&Play bus */
-amba_confarea_type amba_conf;
+/* AMBA Plug&Play information description.
+ *
+ * After software has scanned AMBA PnP it builds a tree to make
+ * it easier for drivers to work with the bus architecture.
+ */
+struct ambapp_bus ambapp_plb;
-/* Pointers to Interrupt Controller configuration registers */
-volatile LEON3_IrqCtrl_Regs_Map *LEON3_IrqCtrl_Regs;
+/* If RTEMS_DRVMGR_STARTUP is defined extra code is added that
+ * registers the GRLIB AMBA PnP bus driver as root driver.
+ */
+#ifdef RTEMS_DRVMGR_STARTUP
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus_grlib.h>
+
+extern void gptimer_register_drv (void);
+extern void apbuart_cons_register_drv(void);
+/* All drivers included by BSP, this is overridden by the user by including
+ * the drvmgr_confdefs.h. By default the Timer and UART driver are included.
+ */
+struct drvmgr_drv_reg_func drvmgr_drivers[] __attribute__((weak)) =
+{
+ {gptimer_register_drv},
+ {apbuart_cons_register_drv},
+ {NULL} /* End array with NULL */
+};
+
+/* Driver resources configuration for AMBA root bus. It is declared weak
+ * so that the user may override it, if the defualt settings are not
+ * enough.
+ */
+struct drvmgr_bus_res grlib_drv_resources __attribute__((weak)) =
+{
+ .next = NULL,
+ .resource =
+ {
+ RES_EMPTY,
+ }
+};
+
+/* GRLIB AMBA bus configuration (the LEON3 root bus configuration) */
+struct grlib_config grlib_bus_config =
+{
+ &ambapp_plb, /* AMBAPP bus setup */
+ &grlib_drv_resources, /* Driver configuration */
+};
+#endif
-int LEON3_Cpu_Index = 0;
+/* GRLIB extended IRQ controller register */
+extern void leon3_ext_irq_init(void);
+
+/* Pointers to Interrupt Controller configuration registers */
+volatile struct irqmp_regs *LEON3_IrqCtrl_Regs;
/*
* amba_initialize
@@ -33,45 +79,67 @@ int LEON3_Cpu_Index = 0;
* amba_ahb_masters, amba_ahb_slaves and amba.
*/
-unsigned int getasr17(void);
-
-asm(" .text \n"
- "getasr17: \n"
- "retl \n"
- "mov %asr17, %o0\n"
-);
+void amba_initialize(void)
+{
+ int icsel;
+ struct ambapp_dev *adev;
+ /* Scan AMBA Plug&Play read-only information. The routine builds a PnP
+ * tree into ambapp_plb in RAM, after this we never access the PnP
+ * information in hardware directly any more.
+ * Since on Processor Local Bus (PLB) memory mapping is 1:1
+ */
+ ambapp_scan(&ambapp_plb, LEON3_IO_AREA, NULL, NULL);
-extern rtems_configuration_table Configuration;
-extern int scan_uarts(void);
+ /* Find LEON3 Interrupt controller */
+ adev = (void *)ambapp_for_each(&ambapp_plb, (OPTIONS_ALL|OPTIONS_APB_SLVS),
+ VENDOR_GAISLER, GAISLER_IRQMP,
+ ambapp_find_by_idx, NULL);
+ if (adev == NULL) {
+ /* PANIC IRQ controller not found!
+ *
+ * What else can we do but stop ...
+ */
+ asm volatile( "mov 1, %g1; ta 0x0" );
+ }
-void amba_initialize(void)
-{
- int i;
- amba_apb_device dev;
-
- /* Scan the AMBA Plug&Play info at the default LEON3 area */
- amba_scan(&amba_conf,LEON3_IO_AREA,NULL);
-
- /* Find LEON3 Interrupt controler */
- i = amba_find_apbslv(&amba_conf,VENDOR_GAISLER,GAISLER_IRQMP,&dev);
- if ( i > 0 ){
- /* Found APB IRQ_MP Interrupt Controller */
- LEON3_IrqCtrl_Regs = (volatile LEON3_IrqCtrl_Regs_Map *) dev.start;
-#if defined(RTEMS_MULTIPROCESSING)
- if (rtems_configuration_get_user_multiprocessing_table() != NULL) {
- unsigned int tmp = getasr17();
- LEON3_Cpu_Index = (tmp >> 28) & 3;
- }
-#endif
+ LEON3_IrqCtrl_Regs = (volatile struct irqmp_regs *)DEV_TO_APB(adev)->start;
+ if ((LEON3_IrqCtrl_Regs->ampctrl >> 28) > 0) {
+ /* IRQ Controller has support for multiple IRQ Controllers, each
+ * CPU can be routed to different Controllers, we find out which
+ * controller by looking at the IRQCTRL Select Register for this CPU.
+ * Each Controller is located at a 4KByte offset.
+ */
+ icsel = LEON3_IrqCtrl_Regs->icsel[LEON3_Cpu_Index/8];
+ icsel = (icsel >> ((7 - (LEON3_Cpu_Index & 0x7)) * 4)) & 0xf;
+ LEON3_IrqCtrl_Regs += icsel;
+ LEON3_IrqCtrl_Regs->mask[LEON3_Cpu_Index] = 0;
+ LEON3_IrqCtrl_Regs->force[LEON3_Cpu_Index] = 0;
+ LEON3_IrqCtrl_Regs->iclear = 0xffffffff;
}
+ /* Init Extended IRQ controller if available */
+ leon3_ext_irq_init();
+
+ /* If we are running without Driver Manager at startup, we must still
+ * assure that Timer and Console UART is working. So we can not
+ * depend on the DrvMgr capable Timer and Console UART drivers,
+ * instead we use the small-footprint drivers.
+ */
+#ifndef RTEMS_DRVMGR_STARTUP
/* find GP Timer */
- i = amba_find_apbslv(&amba_conf,VENDOR_GAISLER,GAISLER_GPTIMER,&dev);
- if ( i > 0 ){
- LEON3_Timer_Regs = (volatile LEON3_Timer_Regs_Map *) dev.start;
- }
+ adev = (void *)ambapp_for_each(&ambapp_plb, (OPTIONS_ALL|OPTIONS_APB_SLVS),
+ VENDOR_GAISLER, GAISLER_GPTIMER,
+ ambapp_find_by_idx, NULL);
+ if (adev) {
+ LEON3_Timer_Regs = (volatile struct gptimer_regs *)DEV_TO_APB(adev)->start;
- /* find UARTS */
- scan_uarts();
+ /* Register AMBA Bus Frequency */
+ ambapp_freq_init(&ambapp_plb, adev,
+ (LEON3_Timer_Regs->scaler_reload + 1) * 1000000);
+ }
+#else
+ /* Register Root bus, Use GRLIB AMBA PnP bus as root bus for LEON3 */
+ ambapp_grlib_root_register(&grlib_bus_config);
+#endif
}
diff --git a/c/src/lib/libbsp/sparc/leon3/clock/ckinit.c b/c/src/lib/libbsp/sparc/leon3/clock/ckinit.c
index 5bd41bb7cd..dd197370ac 100644
--- a/c/src/lib/libbsp/sparc/leon3/clock/ckinit.c
+++ b/c/src/lib/libbsp/sparc/leon3/clock/ckinit.c
@@ -23,6 +23,16 @@
#include <bsp.h>
#include <bspopts.h>
+/* The LEON3 BSP Timer driver can rely on the Driver Manager if the
+ * DrvMgr is initialized during startup. Otherwise the classic driver
+ * must be used.
+ *
+ * The DrvMgr Clock driver is located in the shared/timer directory
+ */
+#ifndef RTEMS_DRVMGR_STARTUP
+
+#include <ambapp.h>
+
#if SIMSPARC_FAST_IDLE==1
#define CLOCK_DRIVER_USE_FAST_IDLE
#endif
@@ -39,7 +49,7 @@
#endif
-volatile LEON3_Timer_Regs_Map *LEON3_Timer_Regs = 0;
+volatile struct gptimer_regs *LEON3_Timer_Regs = 0;
static int clkirq;
#define CLOCK_VECTOR LEON_TRAP_TYPE( clkirq )
@@ -54,20 +64,21 @@ static int clkirq;
} \
} while(0)
#else
- #define Adjust_clkirq_for_node()
+ #define Adjust_clkirq_for_node() do { clkirq += LEON3_CLOCK_INDEX; } while(0)
#endif
#define Clock_driver_support_find_timer() \
do { \
- int cnt; \
- amba_apb_device dev; \
+ struct ambapp_dev *adev; \
\
- /* Find LEON3 GP Timer */ \
- cnt = amba_find_apbslv(&amba_conf,VENDOR_GAISLER,GAISLER_GPTIMER,&dev); \
- if ( cnt > 0 ){ \
+ /* Find first LEON3 GP Timer */ \
+ adev = (void *)ambapp_for_each(&ambapp_plb, (OPTIONS_ALL|OPTIONS_APB_SLVS),\
+ VENDOR_GAISLER, GAISLER_GPTIMER, ambapp_find_by_idx, NULL); \
+ if ( adev ) { \
/* Found APB GPTIMER Timer */ \
- LEON3_Timer_Regs = (volatile LEON3_Timer_Regs_Map *) dev.start; \
- clkirq = (LEON3_Timer_Regs->status & 0xfc) >> 3; \
+ LEON3_Timer_Regs = (volatile struct gptimer_regs *) \
+ DEV_TO_APB(adev)->start; \
+ clkirq = (LEON3_Timer_Regs->cfg & 0xf8) >> 3; \
\
Adjust_clkirq_for_node(); \
} \
@@ -83,7 +94,7 @@ static int clkirq;
LEON3_Timer_Regs->timer[LEON3_CLOCK_INDEX].reload = \
rtems_configuration_get_microseconds_per_tick() - 1; \
\
- LEON3_Timer_Regs->timer[LEON3_CLOCK_INDEX].conf = \
+ LEON3_Timer_Regs->timer[LEON3_CLOCK_INDEX].ctrl = \
LEON3_GPTIMER_EN | LEON3_GPTIMER_RL | \
LEON3_GPTIMER_LD | LEON3_GPTIMER_IRQEN; \
} while (0)
@@ -91,7 +102,7 @@ static int clkirq;
#define Clock_driver_support_shutdown_hardware() \
do { \
LEON_Mask_interrupt(LEON_TRAP_TYPE(clkirq)); \
- LEON3_Timer_Regs->timer[LEON3_CLOCK_INDEX].conf = 0; \
+ LEON3_Timer_Regs->timer[LEON3_CLOCK_INDEX].ctrl = 0; \
} while (0)
uint32_t bsp_clock_nanoseconds_since_last_tick(void)
@@ -102,10 +113,10 @@ uint32_t bsp_clock_nanoseconds_since_last_tick(void)
if ( !LEON3_Timer_Regs )
return 0;
- clicks = LEON3_Timer_Regs->timer[0].value;
+ clicks = LEON3_Timer_Regs->timer[LEON3_CLOCK_INDEX].value;
if ( LEON_Is_interrupt_pending( clkirq ) ) {
- clicks = LEON3_Timer_Regs->timer[0].value;
+ clicks = LEON3_Timer_Regs->timer[LEON3_CLOCK_INDEX].value;
usecs = (2*rtems_configuration_get_microseconds_per_tick() - clicks);
} else {
usecs = (rtems_configuration_get_microseconds_per_tick() - clicks);
@@ -118,3 +129,5 @@ uint32_t bsp_clock_nanoseconds_since_last_tick(void)
bsp_clock_nanoseconds_since_last_tick
#include "../../../shared/clockdrv_shell.h"
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/leon3/console/console.c b/c/src/lib/libbsp/sparc/leon3/console/console.c
index fee8721dee..0ac17be696 100644
--- a/c/src/lib/libbsp/sparc/leon3/console/console.c
+++ b/c/src/lib/libbsp/sparc/leon3/console/console.c
@@ -17,6 +17,17 @@
* $Id$
*/
+/* Define CONSOLE_USE_INTERRUPTS to enable APBUART interrupt handling instead
+ * of polling mode.
+ *
+ * Note that it is not possible to use the interrupt mode of the driver
+ * together with the "old" APBUART and -u to GRMON. However the new
+ * APBUART core (from GRLIB 1.0.17-b2710) has the GRMON debug bit and can
+ * handle interrupts.
+ *
+ * NOTE: This can be defined in the make/custom/leon3.cfg file.
+ */
+
#include <bsp.h>
#include <rtems/libio.h>
#include <stdlib.h>
@@ -24,59 +35,281 @@
#include <rtems/bspIo.h>
#include <amba.h>
-/*
- * Should we use a polled or interrupt drived console?
- *
- * NOTE: This is defined in the custom/leon.cfg file.
+#ifndef RTEMS_DRVMGR_STARTUP
+
+/* Let user override which on-chip APBUART will be debug UART
+ * 0 = Default APBUART. On MP system CPU0=APBUART0, CPU1=APBUART1...
+ * 1 = APBUART[0]
+ * 2 = APBUART[1]
+ * 3 = APBUART[2]
+ * ...
*/
+int syscon_uart_index __attribute__((weak)) = 0;
/*
- * console_outbyte_polled
+ * apbuart_outbyte_polled
*
* This routine transmits a character using polling.
*/
-void console_outbyte_polled(
- int port,
- char ch
-);
+extern void apbuart_outbyte_polled(
+ struct apbuart_regs *regs,
+ unsigned char ch,
+ int do_cr_on_newline,
+ int wait_sent);
+
/* body is in debugputs.c */
/*
- * console_inbyte_nonblocking
+ * apbuart_inbyte_nonblocking
*
* This routine polls for a character.
*/
-int console_inbyte_nonblocking( int port );
+extern int apbuart_inbyte_nonblocking(struct apbuart_regs *regs);
/* body is in debugputs.c */
+struct apbuart_priv {
+ struct apbuart_regs *regs;
+ unsigned int freq_hz;
+#if CONSOLE_USE_INTERRUPTS
+ int irq;
+ void *cookie;
+ volatile int sending;
+ char *buf;
+#endif
+};
+static struct apbuart_priv apbuarts[BSP_NUMBER_OF_TERMIOS_PORTS];
+static int uarts = 0;
+
+#if CONSOLE_USE_INTERRUPTS
+
+/* Handle UART interrupts */
+void console_isr(void *arg)
+{
+ struct apbuart_priv *uart = arg;
+ unsigned int status;
+ char data;
+
+ /* Get all received characters */
+ while ((status=uart->regs->status) & LEON_REG_UART_STATUS_DR) {
+ /* Data has arrived, get new data */
+ data = uart->regs->data;
+
+ /* Tell termios layer about new character */
+ rtems_termios_enqueue_raw_characters(uart->cookie, &data, 1);
+ }
+
+ if (status & LEON_REG_UART_STATUS_THE) {
+ /* Sent the one char, we disable TX interrupts */
+ uart->regs->ctrl &= ~LEON_REG_UART_CTRL_TI;
+
+ /* Tell close that we sent everything */
+ uart->sending = 0;
+
+ /* write_interrupt will get called from this function */
+ rtems_termios_dequeue_characters(uart->cookie, 1);
+ }
+}
+
+/*
+ * Console Termios Write-Buffer Support Entry Point
+ *
+ */
+
+int console_write_interrupt (int minor, const char *buf, int len)
+{
+ struct apbuart_priv *uart;
+ unsigned int oldLevel;
+
+ if (minor == 0)
+ uart = &apbuarts[syscon_uart_index];
+ else
+ uart = &apbuarts[minor - 1];
+
+ /* Remember what position in buffer */
+
+ rtems_interrupt_disable(oldLevel);
+
+ /* Enable TX interrupt */
+ uart->regs->ctrl |= LEON_REG_UART_CTRL_TI;
+
+ /* start UART TX, this will result in an interrupt when done */
+ uart->regs->data = *buf;
+
+ uart->sending = 1;
+
+ rtems_interrupt_enable(oldLevel);
+
+ return 0;
+}
+
+#else
/*
* Console Termios Support Entry Points
*
*/
-ssize_t console_write_support (int minor, const char *buf, size_t len)
+ssize_t console_write_polled (int minor, const char *buf, size_t len)
{
- int nwrite = 0;
+ int nwrite = 0, port;
+
+ if (minor == 0)
+ port = syscon_uart_index;
+ else
+ port = minor - 1;
while (nwrite < len) {
- console_outbyte_polled( minor, *buf++ );
+ apbuart_outbyte_polled(apbuarts[port].regs, *buf++, 1, 0 );
nwrite++;
}
return nwrite;
}
+int console_pollRead(int minor)
+{
+ int port;
+
+ if (minor == 0)
+ port = syscon_uart_index;
+ else
+ port = minor - 1;
+
+ return apbuart_inbyte_nonblocking(apbuarts[port].regs);
+}
+
+#endif
+
+int console_set_attributes(int minor, const struct termios *t)
+{
+ unsigned int scaler;
+ unsigned int ctrl;
+ int baud;
+ struct apbuart_priv *uart;
+
+ switch(t->c_cflag & CSIZE) {
+ default:
+ case CS5:
+ case CS6:
+ case CS7:
+ /* Hardware doesn't support other than CS8 */
+ return -1;
+ case CS8:
+ break;
+ }
+
+ if (minor == 0)
+ uart = &apbuarts[syscon_uart_index];
+ else
+ uart = &apbuarts[minor - 1];
+
+ /* Read out current value */
+ ctrl = uart->regs->ctrl;
+
+ switch(t->c_cflag & (PARENB|PARODD)){
+ case (PARENB|PARODD):
+ /* Odd parity */
+ ctrl |= LEON_REG_UART_CTRL_PE|LEON_REG_UART_CTRL_PS;
+ break;
+
+ case PARENB:
+ /* Even parity */
+ ctrl &= ~LEON_REG_UART_CTRL_PS;
+ ctrl |= LEON_REG_UART_CTRL_PE;
+ break;
+
+ default:
+ case 0:
+ case PARODD:
+ /* No Parity */
+ ctrl &= ~(LEON_REG_UART_CTRL_PS|LEON_REG_UART_CTRL_PE);
+ }
+
+ if ( !(t->c_cflag & CLOCAL) ){
+ ctrl |= LEON_REG_UART_CTRL_FL;
+ }else{
+ ctrl &= ~LEON_REG_UART_CTRL_FL;
+ }
+
+ /* Update new settings */
+ uart->regs->ctrl = ctrl;
+
+ /* Baud rate */
+ switch(t->c_cflag & CBAUD){
+ default: baud = -1; break;
+ case B50: baud = 50; break;
+ case B75: baud = 75; break;
+ case B110: baud = 110; break;
+ case B134: baud = 134; break;
+ case B150: baud = 150; break;
+ case B200: baud = 200; break;
+ case B300: baud = 300; break;
+ case B600: baud = 600; break;
+ case B1200: baud = 1200; break;
+ case B1800: baud = 1800; break;
+ case B2400: baud = 2400; break;
+ case B4800: baud = 4800; break;
+ case B9600: baud = 9600; break;
+ case B19200: baud = 19200; break;
+ case B38400: baud = 38400; break;
+ case B57600: baud = 57600; break;
+ case B115200: baud = 115200; break;
+ case B230400: baud = 230400; break;
+ case B460800: baud = 460800; break;
+ }
+
+ if ( baud > 0 ){
+ /* Calculate Baud rate generator "scaler" number */
+ scaler = (((uart->freq_hz * 10)/(baud * 8)) - 5) / 10;
+
+ /* Set new baud rate by setting scaler */
+ uart->regs->scaler = scaler;
+ }
+
+ return 0;
+}
+
+/* AMBA PP find routine. Extract AMBA PnP information into data structure. */
+int find_matching_apbuart(struct ambapp_dev *dev, int index, void *arg)
+{
+ struct ambapp_apb_info *apb = (struct ambapp_apb_info *)dev->devinfo;
+
+ /* Extract needed information of one APBUART */
+ apbuarts[uarts].regs = (struct apbuart_regs *)apb->start;
+#if CONSOLE_USE_INTERRUPTS
+ apbuarts[uarts].irq = apb->irq;
+#endif
+ /* Get APBUART core frequency, it is assumed that it is the same
+ * as Bus frequency where the UART is situated
+ */
+ apbuarts[uarts].freq_hz = ambapp_freq_get(&ambapp_plb, dev);
+ uarts++;
+
+ if (uarts >= BSP_NUMBER_OF_TERMIOS_PORTS)
+ return 1; /* Satisfied number of UARTs, stop search */
+ else
+ return 0; /* Continue searching for more UARTs */
+}
+
+/* Find all UARTs */
+int console_scan_uarts(void)
+{
+ memset(apbuarts, 0, sizeof(apbuarts));
+
+ /* Find APBUART cores */
+ ambapp_for_each(&ambapp_plb, (OPTIONS_ALL|OPTIONS_APB_SLVS), VENDOR_GAISLER,
+ GAISLER_APBUART, find_matching_apbuart, NULL);
+
+ return uarts;
+}
/*
* Console Device Driver Entry Points
*
*/
-int uarts = 0;
-volatile LEON3_UART_Regs_Map *LEON3_Console_Uart[LEON3_APBUARTS];
rtems_device_driver console_initialize(
rtems_device_major_number major,
@@ -85,45 +318,50 @@ rtems_device_driver console_initialize(
)
{
rtems_status_code status;
- int i, uart0;
+ int i;
char console_name[16];
rtems_termios_initialize();
- /* default console to zero and override if multiprocessing */
- uart0 = 0;
- #if defined(RTEMS_MULTIPROCESSING)
- if (rtems_configuration_get_user_multiprocessing_table() != NULL)
- uart0 = LEON3_Cpu_Index;
- #endif
+ /* Find UARTs */
+ console_scan_uarts();
- /* Register Device Names */
- if (uarts && (uart0 < uarts)) {
+ /* Update syscon_uart_index to index used as /dev/console
+ * Let user select System console by setting syscon_uart_index. If the
+ * BSP is to provide the default UART (syscon_uart_index==0):
+ * non-MP: APBUART[0] is system console
+ * MP: LEON CPU index select UART
+ */
+ if (syscon_uart_index == 0) {
+#if defined(RTEMS_MULTIPROCESSING)
+ syscon_uart_index = LEON3_Cpu_Index;
+#else
+ syscon_uart_index = 0;
+#endif
+ } else {
+ syscon_uart_index = syscon_uart_index - 1; /* User selected sys-console */
+ }
+
+ /* Register Device Names
+ *
+ * 0 /dev/console - APBUART[USER-SELECTED, DEFAULT=APBUART[0]]
+ * 1 /dev/console_a - APBUART[0] (by default not present because is console)
+ * 2 /dev/console_b - APBUART[1]
+ * ...
+ *
+ * On a MP system one should not open UARTs that other OS instances use.
+ */
+ if (syscon_uart_index < uarts) {
status = rtems_io_register_name( "/dev/console", major, 0 );
if (status != RTEMS_SUCCESSFUL)
rtems_fatal_error_occurred(status);
-
- strcpy(console_name,"/dev/console_a");
- for (i = uart0+1; i < uarts; i++) {
- console_name[13]++;
- status = rtems_io_register_name( console_name, major, i);
- }
}
-
- /*
- * Initialize Hardware if ONLY CPU or first CPU in MP system
- */
-
- #if defined(RTEMS_MULTIPROCESSING)
- if (rtems_configuration_get_user_multiprocessing_table()->node == 1)
- #endif
- {
- for (i = uart0; i < uarts; i++)
- {
- LEON3_Console_Uart[i]->ctrl |=
- LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE;
- LEON3_Console_Uart[i]->status = 0;
- }
+ strcpy(console_name,"/dev/console_a");
+ for (i = 0; i < uarts; i++) {
+ if (i == syscon_uart_index)
+ continue; /* skip UART that is registered as /dev/console */
+ console_name[13] = 'a' + i;
+ status = rtems_io_register_name( console_name, major, i+1);
}
return RTEMS_SUCCESSFUL;
@@ -136,25 +374,70 @@ rtems_device_driver console_open(
)
{
rtems_status_code sc;
+ struct apbuart_priv *uart;
+#if CONSOLE_USE_INTERRUPTS
+ rtems_libio_open_close_args_t *priv = arg;
- static const rtems_termios_callbacks pollCallbacks = {
+ /* Interrupt mode routines */
+ static const rtems_termios_callbacks Callbacks = {
+ NULL, /* firstOpen */
+ NULL, /* lastClose */
+ NULL, /* pollRead */
+ console_write_interrupt, /* write */
+ console_set_attributes, /* setAttributes */
+ NULL, /* stopRemoteTx */
+ NULL, /* startRemoteTx */
+ 1 /* outputUsesInterrupts */
+ };
+#else
+ /* Polling mode routines */
+ static const rtems_termios_callbacks Callbacks = {
NULL, /* firstOpen */
NULL, /* lastClose */
- console_inbyte_nonblocking, /* pollRead */
- console_write_support, /* write */
- NULL, /* setAttributes */
+ console_pollRead, /* pollRead */
+ console_write_polled, /* write */
+ console_set_attributes, /* setAttributes */
NULL, /* stopRemoteTx */
NULL, /* startRemoteTx */
0 /* outputUsesInterrupts */
};
+#endif
-
- assert( minor <= LEON3_APBUARTS );
- if ( minor > LEON3_APBUARTS )
+ assert(minor <= uarts);
+ if (minor > uarts || minor == (syscon_uart_index + 1))
return RTEMS_INVALID_NUMBER;
- sc = rtems_termios_open (major, minor, arg, &pollCallbacks);
-
+ sc = rtems_termios_open (major, minor, arg, &Callbacks);
+ if (sc != RTEMS_SUCCESSFUL)
+ return sc;
+
+ if (minor == 0)
+ uart = &apbuarts[syscon_uart_index];
+ else
+ uart = &apbuarts[minor - 1];
+
+#if CONSOLE_USE_INTERRUPTS
+ if (priv && priv->iop)
+ uart->cookie = priv->iop->data1;
+ else
+ uart->cookie = NULL;
+
+ /* Register Interrupt handler */
+ sc = rtems_interrupt_handler_install(uart->irq, "console",
+ RTEMS_INTERRUPT_SHARED, console_isr,
+ uart);
+ if (sc != RTEMS_SUCCESSFUL)
+ return sc;
+
+ uart->sending = 0;
+ /* Enable Receiver and transmitter and Turn on RX interrupts */
+ uart->regs->ctrl |= LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE |
+ LEON_REG_UART_CTRL_RI;
+#else
+ /* Initialize UART on opening */
+ uart->regs->ctrl |= LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE;
+#endif
+ uart->regs->status = 0;
return RTEMS_SUCCESSFUL;
}
@@ -165,6 +448,25 @@ rtems_device_driver console_close(
void * arg
)
{
+#if CONSOLE_USE_INTERRUPTS
+ struct apbuart_priv *uart;
+
+ if (minor == 0)
+ uart = &apbuarts[syscon_uart_index];
+ else
+ uart = &apbuarts[minor - 1];
+
+ /* Turn off RX interrupts */
+ uart->regs->ctrl &= ~(LEON_REG_UART_CTRL_RI);
+
+ /**** Flush device ****/
+ while (uart->sending) {
+ /* Wait until all data has been sent */
+ }
+
+ /* uninstall ISR */
+ rtems_interrupt_handler_remove(uart->irq, console_isr, uart);
+#endif
return rtems_termios_close (arg);
}
@@ -195,3 +497,4 @@ rtems_device_driver console_control(
return rtems_termios_ioctl (arg);
}
+#endif
diff --git a/c/src/lib/libbsp/sparc/leon3/console/debugputs.c b/c/src/lib/libbsp/sparc/leon3/console/debugputs.c
index 2cd0d136e1..b9b9022b5f 100644
--- a/c/src/lib/libbsp/sparc/leon3/console/debugputs.c
+++ b/c/src/lib/libbsp/sparc/leon3/console/debugputs.c
@@ -7,8 +7,8 @@
* On-Line Applications Research Corporation (OAR).
*
* Modified for LEON3 BSP.
- * COPYRIGHT (c) 2004.
- * Gaisler Research.
+ * COPYRIGHT (c) 2011.
+ * Aeroflex Gaisler.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
@@ -21,86 +21,131 @@
#include <rtems/libio.h>
#include <stdlib.h>
#include <assert.h>
-
-/*
- * Number of uarts on AMBA bus
+#include <stdio.h>
+
+/* Let user override which on-chip APBUART will be debug UART
+ * 0 = Default APBUART. On MP system CPU0=APBUART0, CPU1=APBUART1...
+ * 1 = APBUART[0]
+ * 2 = APBUART[1]
+ * 3 = APBUART[2]
+ * ...
*/
-extern int uarts;
+int debug_uart_index __attribute__((weak)) = 0;
+struct apbuart_regs *dbg_uart = NULL;
-static int isinit = 0;
+/* Before UART driver has registered (or when no UART is available), calls to
+ * printk that gets to bsp_out_char() will be filling data into the
+ * pre_printk_dbgbuf[] buffer, hopefully the buffer can help debugging the
+ * early BSP boot.. At least the last printk() will be caught.
+ */
+char pre_printk_dbgbuf[32] = {0};
+int pre_printk_pos = 0;
-/*
- * Scan for UARTS in configuration
+/* Initialize the BSP system debug console layer. It will scan AMBA Plu&Play
+ * for a debug APBUART and enable RX/TX for that UART.
*/
-int scan_uarts(void)
+int bsp_debug_uart_init(void)
{
int i;
- amba_apb_device apbuarts[LEON3_APBUARTS];
-
- if (isinit == 0) {
- i = 0;
- uarts = 0;
-
- uarts = amba_find_apbslvs(
- &amba_conf, VENDOR_GAISLER, GAISLER_APBUART, apbuarts, LEON3_APBUARTS);
- for(i=0; i<uarts; i++) {
- LEON3_Console_Uart[i] = (volatile LEON3_UART_Regs_Map *)apbuarts[i].start;
- }
-
- /* initialize uart 0 if present for printk */
- if ( uarts ) {
- LEON3_Console_Uart[0]->ctrl |=
- LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE;
- LEON3_Console_Uart[0]->status = 0;
- }
- isinit = 1;
+ struct ambapp_dev *adev;
+ struct ambapp_apb_info *apb;
+
+ /* Update debug_uart_index to index used as debug console.
+ * Let user select Debug console by setting debug_uart_index. If the
+ * BSP is to provide the default UART (debug_uart_index==0):
+ * non-MP: APBUART[0] is debug console
+ * MP: LEON CPU index select UART
+ */
+ if (debug_uart_index == 0) {
+#if defined(RTEMS_MULTIPROCESSING)
+ debug_uart_index = LEON3_Cpu_Index;
+#else
+ debug_uart_index = 0;
+#endif
+ } else {
+ debug_uart_index = debug_uart_index - 1; /* User selected dbg-console */
}
- return uarts;
+ /* Find APBUART core for System Debug Console */
+ i = debug_uart_index;
+ adev = (void *)ambapp_for_each(&ambapp_plb, (OPTIONS_ALL|OPTIONS_APB_SLVS),
+ VENDOR_GAISLER, GAISLER_APBUART,
+ ambapp_find_by_idx, (void *)&i);
+ if (adev) {
+ /* Found a matching debug console, initialize debug uart if present
+ * for printk
+ */
+ apb = (struct ambapp_apb_info *)adev->devinfo;
+ dbg_uart = (struct apbuart_regs *)apb->start;
+ dbg_uart->ctrl |= LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE;
+ dbg_uart->status = 0;
+ return 1;
+ } else
+ return 0;
}
/*
- * console_outbyte_polled
+ * apbuart_outbyte_polled
*
* This routine transmits a character using polling.
*/
-void console_outbyte_polled(
- int port,
- unsigned char ch
+void apbuart_outbyte_polled(
+ struct apbuart_regs *regs,
+ unsigned char ch,
+ int do_cr_on_newline,
+ int wait_sent
)
{
- if ((port >= 0) && (port < uarts)) {
- int u = LEON3_Cpu_Index+port;
- while ( (LEON3_Console_Uart[u]->status & LEON_REG_UART_STATUS_THE) == 0 );
- LEON3_Console_Uart[u]->data = (unsigned int) ch;
+send:
+ while ( (regs->status & LEON_REG_UART_STATUS_THE) == 0 ) {
+ /* Lower bus utilization while waiting for UART */
+ asm volatile ("nop"::); asm volatile ("nop"::);
+ asm volatile ("nop"::); asm volatile ("nop"::);
+ asm volatile ("nop"::); asm volatile ("nop"::);
+ asm volatile ("nop"::); asm volatile ("nop"::);
+ }
+ regs->data = (unsigned int) ch;
+
+ if ((ch == '\n') && do_cr_on_newline) {
+ ch = '\r';
+ goto send;
+ }
+
+ /* Wait until the character has been sent? */
+ if (wait_sent) {
+ while ((regs->status & LEON_REG_UART_STATUS_THE) == 0)
+ ;
}
}
/*
- * console_inbyte_nonblocking
+ * apbuart_inbyte_nonblocking
*
* This routine polls for a character.
*/
-int console_inbyte_nonblocking( int port )
+int apbuart_inbyte_nonblocking(struct apbuart_regs *regs)
{
- if ((port >= 0) && (port < uarts)) {
- int u = LEON3_Cpu_Index+port;
- if (LEON3_Console_Uart[u]->status & LEON_REG_UART_STATUS_ERR)
- LEON3_Console_Uart[u]->status = ~LEON_REG_UART_STATUS_ERR;
-
- if ((LEON3_Console_Uart[u]->status & LEON_REG_UART_STATUS_DR) == 0)
- return -1;
- return (int) LEON3_Console_Uart[u]->data;
- } else {
- assert( 0 );
- }
- return -1;
+ /* Clear errors */
+ if (regs->status & LEON_REG_UART_STATUS_ERR)
+ regs->status = ~LEON_REG_UART_STATUS_ERR;
+
+ if ((regs->status & LEON_REG_UART_STATUS_DR) == 0)
+ return EOF;
+ else
+ return (int) regs->data;
}
/* putchar/getchar for printk */
static void bsp_out_char(char c)
{
- console_outbyte_polled(0, c);
+ if (dbg_uart == NULL) {
+ /* Local debug buffer when UART driver has not registered */
+ pre_printk_dbgbuf[pre_printk_pos++] = c;
+ pre_printk_pos = pre_printk_pos & (sizeof(pre_printk_dbgbuf)-1);
+ return;
+ }
+
+ apbuart_outbyte_polled(dbg_uart, c, 1, 1);
}
/*
@@ -115,7 +160,11 @@ static int bsp_in_char(void)
{
int tmp;
- while ((tmp = console_inbyte_nonblocking(0)) < 0);
+ if (dbg_uart == NULL)
+ return EOF;
+
+ while ((tmp = apbuart_inbyte_nonblocking(dbg_uart)) < 0)
+ ;
return tmp;
}
diff --git a/c/src/lib/libbsp/sparc/leon3/include/amba.h b/c/src/lib/libbsp/sparc/leon3/include/amba.h
index 9167ff111f..a4a0ac9bce 100644
--- a/c/src/lib/libbsp/sparc/leon3/include/amba.h
+++ b/c/src/lib/libbsp/sparc/leon3/include/amba.h
@@ -25,16 +25,16 @@
#define LEON3_AHB_MASTERS 64
#define LEON3_AHB_SLAVES 64
#define LEON3_APB_SLAVES 16
-#define LEON3_APBUARTS 8
#include <ambapp.h>
+#include <grlib.h>
#ifdef __cplusplus
extern "C" {
#endif
/* The AMBA Plug&Play info of the bus that the LEON3 sits on */
-extern amba_confarea_type amba_conf;
+extern struct ambapp_bus ambapp_plb;
#ifdef __cplusplus
}
diff --git a/c/src/lib/libbsp/sparc/leon3/include/bsp.h b/c/src/lib/libbsp/sparc/leon3/include/bsp.h
index 89b36d47f5..a37574675c 100644
--- a/c/src/lib/libbsp/sparc/leon3/include/bsp.h
+++ b/c/src/lib/libbsp/sparc/leon3/include/bsp.h
@@ -32,6 +32,7 @@ extern "C" {
#include <leon.h>
#include <rtems/clockdrv.h>
#include <rtems/console.h>
+#include <rtems/irq-extension.h>
/* SPARC CPU variant: LEON3 */
#define LEON3 1
@@ -42,6 +43,9 @@ extern "C" {
void *bsp_idle_thread( uintptr_t ignored );
#define BSP_IDLE_TASK_BODY bsp_idle_thread
+/* Maximum supported APBUARTs by BSP */
+#define BSP_NUMBER_OF_TERMIOS_PORTS 8
+
/*
* Network driver configuration
*/
@@ -71,6 +75,10 @@ extern int rtems_leon_greth_driver_attach(
#define RTEMS_BSP_NETWORK_DRIVER_ATTACH RTEMS_BSP_NETWORK_DRIVER_ATTACH_GRETH
#endif
+/* Configure GRETH driver */
+#define GRETH_SUPPORTED
+#define GRETH_MEM_LOAD(addr) leon_r32_no_cache(addr)
+
extern int CPU_SPARC_HAS_SNOOPING;
@@ -94,6 +102,10 @@ extern int end; /* last address in the program */
/* miscellaneous stuff assumed to exist */
+/* set_vec type */
+#define SET_VECTOR_RAW 0 /* Raw trap handler */
+#define SET_VECTOR_INT 1 /* Trap handler with _ISR_Handler interrupt handler */
+
rtems_isr_entry set_vector( /* returns old vector */
rtems_isr_entry handler, /* isr routine */
rtems_vector_number vector, /* vector number */
@@ -104,6 +116,125 @@ void BSP_fatal_return( void );
void bsp_spurious_initialize( void );
+/* Allocate 8-byte aligned non-freeable pre-malloc memory */
+void *bsp_early_malloc(int size);
+
+/* Interrupt Service Routine (ISR) pointer */
+typedef void (*bsp_shared_isr)(void *arg);
+
+/* Initializes the Shared System Interrupt service */
+extern int BSP_shared_interrupt_init(void);
+
+/* Registers a shared IRQ handler, and enable it at IRQ controller. Multiple
+ * interrupt handlers may use the same IRQ number, all ISRs will be called
+ * when an interrupt on that line is fired.
+ *
+ * Arguments
+ * irq System IRQ number
+ * info Optional Name of IRQ source
+ * isr Function pointer to the ISR
+ * arg Second argument to function isr
+ */
+static __inline__ int BSP_shared_interrupt_register
+ (
+ int irq,
+ const char *info,
+ bsp_shared_isr isr,
+ void *arg
+ )
+{
+ return rtems_interrupt_handler_install(irq, info,
+ RTEMS_INTERRUPT_SHARED, isr, arg);
+}
+
+/* Unregister previously registered shared IRQ handler.
+ *
+ * Arguments
+ * irq System IRQ number
+ * isr Function pointer to the ISR
+ * arg Second argument to function isr
+ */
+static __inline__ int BSP_shared_interrupt_unregister
+ (
+ int irq,
+ bsp_shared_isr isr,
+ void *arg
+ )
+{
+ return rtems_interrupt_handler_remove(irq, isr, arg);
+}
+
+/* Clear interrupt pending on IRQ controller, this is typically done on a
+ * level triggered interrupt source such as PCI to avoid taking double IRQs.
+ * In such a case the interrupt source must be cleared first on LEON, before
+ * acknowledging the IRQ with this function.
+ *
+ * Arguments
+ * irq System IRQ number
+ */
+extern void BSP_shared_interrupt_clear(int irq);
+
+/* Enable Interrupt. This function will unmask the IRQ at the interrupt
+ * controller. This is normally done by _register(). Note that this will
+ * affect all ISRs on this IRQ.
+ *
+ * Arguments
+ * irq System IRQ number
+ */
+extern void BSP_shared_interrupt_unmask(int irq);
+
+/* Disable Interrupt. This function will mask one IRQ at the interrupt
+ * controller. This is normally done by _unregister(). Note that this will
+ * affect all ISRs on this IRQ.
+ *
+ * Arguments
+ * irq System IRQ number
+ */
+extern void BSP_shared_interrupt_mask(int irq);
+
+/* BSP PCI Interrupt support */
+#define BSP_PCI_shared_interrupt_register BSP_shared_interrupt_register
+#define BSP_PCI_shared_interrupt_unregister BSP_shared_interrupt_unregister
+#define BSP_PCI_shared_interrupt_unmask BSP_shared_interrupt_unmask
+#define BSP_PCI_shared_interrupt_mask BSP_shared_interrupt_mask
+#define BSP_PCI_shared_interrupt_clear BSP_shared_interrupt_clear
+
+/* Initialize BSP watchdog routines. Returns number of watchdog timers found.
+ * Currently only one is supported.
+ */
+extern int bsp_watchdog_init(void);
+
+/* Reload watchdog (last timer on the first GPTIMER core), all systems does not
+ * feature a watchdog, it is expected that if this function is called the
+ * user knows that there is a watchdog available.
+ *
+ * The prescaler is normally set to number of MHz of system, this is to
+ * make the system clock tick be stable.
+ *
+ * Arguments
+ * watchdog - Always 0 for now
+ * reload_value - Number of timer clocks (after prescaler) to count before
+ * watchdog is woken.
+ */
+extern void bsp_watchdog_reload(int watchdog, unsigned int reload_value);
+
+/* Stop watchdog timer */
+extern void bsp_watchdog_stop(int watchdog);
+
+/* Use watchdog0 timer to reset the system */
+extern void bsp_watchdog_system_reset(void);
+
+/* Common driver build-time configurations. On small systems undefine
+ * [DRIVER]_INFO_AVAIL to avoid info routines get dragged in. It is good
+ * for debugging and printing information about the system, but makes the
+ * image bigger.
+ */
+#define AMBAPPBUS_INFO_AVAIL /* AMBAPP Bus driver */
+#define APBUART_INFO_AVAIL /* APBUART Console driver */
+#define GPTIMER_INFO_AVAIL /* GPTIMER Timer driver */
+#define GRETH_INFO_AVAIL /* GRETH Ethernet driver */
+#define GRTC_RMAP_INFO_AVAIL /* GRTC over SpaceWire/RMAP driver */
+
#ifdef __cplusplus
}
#endif
diff --git a/c/src/lib/libbsp/sparc/leon3/include/bsp/irq.h b/c/src/lib/libbsp/sparc/leon3/include/bsp/irq.h
new file mode 100644
index 0000000000..71c0df3c5d
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/leon3/include/bsp/irq.h
@@ -0,0 +1,36 @@
+/* LEON3 generic shared IRQ setup
+ *
+ * Based on libbsp/shared/include/irq.h.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#ifndef LIBBSP_LEON3_IRQ_CONFIG_H
+#define LIBBSP_LEON3_IRQ_CONFIG_H
+
+#define BSP_INTERRUPT_VECTOR_MAX_STD 15 /* Standard IRQ controller */
+#define BSP_INTERRUPT_VECTOR_MAX_EXT 31 /* Extended IRQ controller */
+
+#define BSP_INTERRUPT_VECTOR_MIN 0
+#define BSP_INTERRUPT_VECTOR_MAX BSP_INTERRUPT_VECTOR_MAX_EXT
+
+/* The check is different depending on IRQ controller, runtime detected */
+#define BSP_INTERRUPT_CUSTOM_VALID_VECTOR
+
+extern int LEON3_IrqCtrl_EIrq;
+
+/**
+ * @brief Returns true if the interrupt vector with number @a vector is valid.
+ */
+static inline bool bsp_interrupt_is_valid_vector(rtems_vector_number vector)
+{
+ return (rtems_vector_number) BSP_INTERRUPT_VECTOR_MIN <= vector
+ && ((vector <= (rtems_vector_number) BSP_INTERRUPT_VECTOR_MAX_STD &&
+ LEON3_IrqCtrl_EIrq == 0) ||
+ (vector <= (rtems_vector_number) BSP_INTERRUPT_VECTOR_MAX_EXT &&
+ LEON3_IrqCtrl_EIrq != 0));
+}
+
+#endif /* LIBBSP_LEON3_IRQ_CONFIG_H */
diff --git a/c/src/lib/libbsp/sparc/leon3/include/leon.h b/c/src/lib/libbsp/sparc/leon3/include/leon.h
index ee5ae30af8..864536d73a 100644
--- a/c/src/lib/libbsp/sparc/leon3/include/leon.h
+++ b/c/src/lib/libbsp/sparc/leon3/include/leon.h
@@ -46,97 +46,6 @@ extern "C" {
( (_trap) >= 0x11 && \
(_trap) <= 0x1F )
-/*
- * Structure for LEON memory mapped registers.
- *
- * Source: Section 6.1 - On-chip registers
- *
- * NOTE: There is only one of these structures per CPU, its base address
- * is 0x80000000, and the variable LEON_REG is placed there by the
- * linkcmds file.
- */
-
-/* Leon uses dynamic register mapping using amba configuration records,
- * LEON_Register_Map is obsolete
- */
-/*
- typedef struct {
- volatile unsigned int Memory_Config_1;
- volatile unsigned int Memory_Config_2;
- volatile unsigned int Edac_Control;
- volatile unsigned int Failed_Address;
- volatile unsigned int Memory_Status;
- volatile unsigned int Cache_Control;
- volatile unsigned int Power_Down;
- volatile unsigned int Write_Protection_1;
- volatile unsigned int Write_Protection_2;
- volatile unsigned int Leon_Configuration;
- volatile unsigned int dummy2;
- volatile unsigned int dummy3;
- volatile unsigned int dummy4;
- volatile unsigned int dummy5;
- volatile unsigned int dummy6;
- volatile unsigned int dummy7;
- volatile unsigned int Timer_Counter_1;
- volatile unsigned int Timer_Reload_1;
- volatile unsigned int Timer_Control_1;
- volatile unsigned int Watchdog;
- volatile unsigned int Timer_Counter_2;
- volatile unsigned int Timer_Reload_2;
- volatile unsigned int Timer_Control_2;
- volatile unsigned int dummy8;
- volatile unsigned int Scaler_Counter;
- volatile unsigned int Scaler_Reload;
- volatile unsigned int dummy9;
- volatile unsigned int dummy10;
- volatile unsigned int UART_Channel_1;
- volatile unsigned int UART_Status_1;
- volatile unsigned int UART_Control_1;
- volatile unsigned int UART_Scaler_1;
- volatile unsigned int UART_Channel_2;
- volatile unsigned int UART_Status_2;
- volatile unsigned int UART_Control_2;
- volatile unsigned int UART_Scaler_2;
- volatile unsigned int Interrupt_Mask;
- volatile unsigned int Interrupt_Pending;
- volatile unsigned int Interrupt_Force;
- volatile unsigned int Interrupt_Clear;
- volatile unsigned int PIO_Data;
- volatile unsigned int PIO_Direction;
- volatile unsigned int PIO_Interrupt;
-} LEON_Register_Map;
-*/
-
-typedef struct {
- volatile unsigned int data;
- volatile unsigned int status;
- volatile unsigned int ctrl;
-} LEON3_UART_Regs_Map;
-
-typedef struct {
- volatile unsigned int value;
- volatile unsigned int reload;
- volatile unsigned int conf;
- volatile unsigned int notused;
-} LEON3_Timer_SubType;
-
-typedef struct {
- volatile unsigned int scaler_value; /* common timer registers */
- volatile unsigned int scaler_reload;
- volatile unsigned int status;
- volatile unsigned int notused;
- LEON3_Timer_SubType timer[8];
-} LEON3_Timer_Regs_Map;
-
-typedef struct {
- volatile unsigned int iodata;
- volatile unsigned int ioout;
- volatile unsigned int iodir;
- volatile unsigned int irqmask;
- volatile unsigned int irqpol;
- volatile unsigned int irqedge;
-} LEON3_IOPORT_Regs_Map;
-
/* /\* */
/* * This is used to manipulate the on-chip registers. */
/* * */
@@ -191,9 +100,9 @@ typedef struct {
#define LEON_REG_UART_STATUS_OE 0x00000010 /* RX Overrun Error */
#define LEON_REG_UART_STATUS_PE 0x00000020 /* RX Parity Error */
#define LEON_REG_UART_STATUS_FE 0x00000040 /* RX Framing Error */
+#define LEON_REG_UART_STATUS_TF 0x00000200 /* FIFO Full */
#define LEON_REG_UART_STATUS_ERR 0x00000078 /* Error Mask */
-
/*
* The following defines the bits in the LEON UART Status Registers.
*/
@@ -206,13 +115,34 @@ typedef struct {
#define LEON_REG_UART_CTRL_PE 0x00000020 /* Parity enable */
#define LEON_REG_UART_CTRL_FL 0x00000040 /* Flow control enable */
#define LEON_REG_UART_CTRL_LB 0x00000080 /* Loop Back enable */
+#define LEON_REG_UART_CTRL_DB 0x00000800 /* Debug FIFO enable */
+#define LEON_REG_UART_CTRL_SI 0x00004000 /* TX shift register empty IRQ enable */
+#define LEON_REG_UART_CTRL_FA 0x80000000 /* FIFO Available */
+#define LEON_REG_UART_CTRL_FA_BIT 31
-extern volatile LEON3_IrqCtrl_Regs_Map *LEON3_IrqCtrl_Regs; /* LEON3 Interrupt Controller */
-extern volatile LEON3_Timer_Regs_Map *LEON3_Timer_Regs; /* LEON3 GP Timer */
-extern volatile LEON3_UART_Regs_Map *LEON3_Console_Uart[LEON3_APBUARTS];
+extern volatile struct irqmp_regs *LEON3_IrqCtrl_Regs; /* LEON3 Interrupt Controller */
+extern volatile struct gptimer_regs *LEON3_Timer_Regs; /* LEON3 GP Timer */
+/* LEON3 CPU Index of boot CPU */
extern int LEON3_Cpu_Index;
+/* The external IRQ number, -1 if not external interrupts */
+extern int LEON3_IrqCtrl_EIrq;
+
+static __inline__ int leon_irq_fixup(int irq)
+{
+ int eirq;
+
+ if (LEON3_IrqCtrl_EIrq != 0 && irq == LEON3_IrqCtrl_EIrq) {
+ /* Get interrupt number from IRQ controller */
+ eirq = LEON3_IrqCtrl_Regs->intid[LEON3_Cpu_Index] & 0x1f;
+ if (eirq & 0x10)
+ irq = eirq;
+ }
+
+ return irq;
+}
+
/* Macros used for manipulating bits in LEON3 GP Timer Control Register */
#define LEON3_GPTIMER_EN 1
@@ -252,7 +182,6 @@ extern int LEON3_Cpu_Index;
(LEON3_IrqCtrl_Regs->mask[LEON3_Cpu_Index] & (1 << (_source))); \
} while (0)
-
#define LEON_Mask_interrupt( _source ) \
do { \
uint32_t _level; \
@@ -322,6 +251,14 @@ extern int LEON3_Cpu_Index;
#define LEON_REG_TIMER_COUNTER_DEFINED_MASK 0x00000003
#define LEON_REG_TIMER_COUNTER_CURRENT_MODE_MASK 0x00000003
+/* Load 32-bit word by forcing a cache-miss */
+static inline unsigned int leon_r32_no_cache(uintptr_t addr)
+{
+ unsigned int tmp;
+ asm volatile (" lda [%1] 1, %0\n" : "=r"(tmp) : "r"(addr));
+ return tmp;
+}
+
#endif /* !ASM */
#ifdef __cplusplus
diff --git a/c/src/lib/libbsp/sparc/leon3/leon_greth/leon_greth.c b/c/src/lib/libbsp/sparc/leon3/leon_greth/leon_greth.c
index 341bd2792e..95a0c2b689 100644
--- a/c/src/lib/libbsp/sparc/leon3/leon_greth/leon_greth.c
+++ b/c/src/lib/libbsp/sparc/leon3/leon_greth/leon_greth.c
@@ -31,29 +31,31 @@ int rtems_leon_greth_driver_attach(
int attach
)
{
- int device_found = 0;
unsigned int base_addr = 0; /* avoid warnings */
unsigned int eth_irq = 0; /* avoid warnings */
- amba_apb_device apbgreth;
+ struct ambapp_dev *adev;
+ struct ambapp_apb_info *apb;
/* Scan for MAC AHB slave interface */
- device_found = amba_find_apbslv(&amba_conf,VENDOR_GAISLER,GAISLER_ETHMAC,&apbgreth);
- if (device_found == 1)
- {
- base_addr = apbgreth.start;
- eth_irq = apbgreth.irq + 0x10;
+ adev = (void *)ambapp_for_each(&ambapp_plb, (OPTIONS_ALL|OPTIONS_APB_SLVS),
+ VENDOR_GAISLER, GAISLER_ETHMAC,
+ ambapp_find_by_idx, NULL);
+ if (adev) {
+ apb = DEV_TO_APB(adev);
+ base_addr = apb->start;
+ eth_irq = apb->irq;
/* clear control register and reset NIC */
*(volatile int *) base_addr = 0;
*(volatile int *) base_addr = GRETH_CTRL_RST;
*(volatile int *) base_addr = 0;
leon_greth_configuration.base_address = base_addr;
- leon_greth_configuration.vector = eth_irq;
+ leon_greth_configuration.irq = eth_irq;
leon_greth_configuration.txd_count = TDA_COUNT;
leon_greth_configuration.rxd_count = RDA_COUNT;
if (rtems_greth_driver_attach( config, &leon_greth_configuration )) {
- LEON_Clear_interrupt(leon_greth_configuration.vector);
- LEON_Unmask_interrupt(leon_greth_configuration.vector);
+ LEON_Clear_interrupt(eth_irq);
+ LEON_Unmask_interrupt(eth_irq);
}
}
return 0;
diff --git a/c/src/lib/libbsp/sparc/leon3/leon_open_eth/leon_open_eth.c b/c/src/lib/libbsp/sparc/leon3/leon_open_eth/leon_open_eth.c
index 3d42d9f53b..a6bb848dbb 100644
--- a/c/src/lib/libbsp/sparc/leon3/leon_open_eth/leon_open_eth.c
+++ b/c/src/lib/libbsp/sparc/leon3/leon_open_eth/leon_open_eth.c
@@ -31,44 +31,41 @@ int rtems_leon_open_eth_driver_attach(
int attach
)
{
- int device_found = 0;
- int i;
- unsigned int conf, iobar;
unsigned int base_addr = 0; /* avoid warnings */
unsigned int eth_irq = 0; /* avoid warnings */
-
+ struct ambapp_dev *adev;
+ struct ambapp_ahb_info *ahb;
/* Scan for MAC AHB slave interface */
- for (i = 0; i < amba_conf.ahbslv.devnr; i++)
- {
- conf = amba_get_confword(amba_conf.ahbslv, i, 0);
- if (((amba_vendor(conf) == VENDOR_OPENCORES) && (amba_device(conf) == OPENCORES_ETHMAC)) ||
- ((amba_vendor(conf) == VENDOR_GAISLER) && (amba_device(conf) == GAISLER_ETHAHB)))
- {
- iobar = amba_ahb_get_membar(amba_conf.ahbslv, i, 0);
- base_addr = amba_iobar_start(LEON3_IO_AREA, iobar);
- eth_irq = amba_irq(conf) + 0x10;
- device_found = 1;
- break;
- }
+ adev = (void *)ambapp_for_each(&ambapp_plb, (OPTIONS_ALL|OPTIONS_AHB_SLVS),
+ VENDOR_OPENCORES, OPENCORES_ETHMAC,
+ ambapp_find_by_idx, NULL);
+ if (!adev) {
+ adev = (void *)ambapp_for_each(&ambapp_plb, (OPTIONS_ALL|OPTIONS_AHB_SLVS),
+ VENDOR_GAISLER, GAISLER_ETHAHB,
+ ambapp_find_by_idx, NULL);
}
-
- if (device_found)
+ if (adev)
{
+ ahb = DEV_TO_AHB(adev);
+ base_addr = ahb->start[0];
+ eth_irq = ahb->irq;
+
/* clear control register and reset NIC */
*(volatile int *) base_addr = 0;
*(volatile int *) base_addr = 0x800;
*(volatile int *) base_addr = 0;
leon_open_eth_configuration.base_address = base_addr;
- leon_open_eth_configuration.vector = eth_irq;
+ leon_open_eth_configuration.vector = eth_irq + 0x10;
leon_open_eth_configuration.txd_count = TDA_COUNT;
leon_open_eth_configuration.rxd_count = RDA_COUNT;
/* enable 100 MHz operation only if cpu frequency >= 50 MHz */
- if (LEON3_Timer_Regs->scaler_reload >= 49) leon_open_eth_configuration.en100MHz = 1;
+ if (LEON3_Timer_Regs->scaler_reload >= 49)
+ leon_open_eth_configuration.en100MHz = 1;
if (rtems_open_eth_driver_attach( config, &leon_open_eth_configuration )) {
- LEON_Clear_interrupt(leon_open_eth_configuration.vector);
- LEON_Unmask_interrupt(leon_open_eth_configuration.vector);
+ LEON_Clear_interrupt(eth_irq);
+ LEON_Unmask_interrupt(eth_irq);
}
}
return 0;
diff --git a/c/src/lib/libbsp/sparc/leon3/leon_smc91111/leon_smc91111.c b/c/src/lib/libbsp/sparc/leon3/leon_smc91111/leon_smc91111.c
index 5ebdc12cfc..babd414473 100644
--- a/c/src/lib/libbsp/sparc/leon3/leon_smc91111/leon_smc91111.c
+++ b/c/src/lib/libbsp/sparc/leon3/leon_smc91111/leon_smc91111.c
@@ -5,7 +5,7 @@
#include <bsp.h>
#include <libchip/smc91111exp.h>
#include <rtems/bspIo.h>
-
+#include <ambapp.h>
#define SMC91111_BASE_ADDR (void*)0x20000300
#define SMC91111_BASE_IRQ 4
@@ -13,9 +13,9 @@
scmv91111_configuration_t leon_scmv91111_configuration = {
SMC91111_BASE_ADDR, /* base address */
- LEON_TRAP_TYPE (SMC91111_BASE_IRQ), /* vector number */
+ SMC91111_BASE_IRQ, /* IRQ number */
SMC91111_BASE_PIO, /* PIO */
- 100, /* 100b */
+ 100, /* 100b */
1, /* fulldx */
1 /* autoneg */
};
@@ -31,28 +31,31 @@ rtems_smc91111_driver_attach_leon3 (struct rtems_bsdnet_ifconfig *config,
int attach)
{
unsigned long addr_mctrl = 0;
- LEON3_IOPORT_Regs_Map *io;
-
- amba_apb_device apbpio;
- amba_ahb_device apbmctrl;
+ struct grgpio_regs *io;
+ struct ambapp_apb_info apbpio;
+ struct ambapp_apb_info apbmctrl;
- if ( amba_find_apbslv(&amba_conf,VENDOR_GAISLER,GAISLER_PIOPORT,&apbpio) != 1 ){
+ if (ambapp_find_apbslv(&ambapp_plb,VENDOR_GAISLER,GAISLER_GPIO,&apbpio) != 1) {
printk("SMC9111_leon3: didn't find PIO\n");
return 0;
}
/* Find LEON2 memory controller */
- if ( amba_find_ahbslv(&amba_conf,VENDOR_ESA,ESA_MCTRL,&apbmctrl) != 1 ){
+ if (ambapp_find_apbslv(&ambapp_plb,VENDOR_ESA,ESA_MCTRL,&apbmctrl) != 1) {
/* LEON2 memory controller not found, search for fault tolerant memory controller */
- if ( amba_find_ahbslv(&amba_conf,VENDOR_GAISLER,GAISLER_FTMCTRL,&apbmctrl) != 1 ) {
- printk("SMC9111_leon3: didn't find any memory controller\n");
- return 0;
+ if (ambapp_find_apbslv(&ambapp_plb,VENDOR_GAISLER,GAISLER_FTMCTRL,&apbmctrl) != 1) {
+ if (ambapp_find_apbslv(&ambapp_plb,VENDOR_GAISLER,GAISLER_FTSRCTRL,&apbmctrl) != 1) {
+ if (ambapp_find_apbslv(&ambapp_plb,VENDOR_GAISLER,GAISLER_FTSRCTRL8,&apbmctrl) != 1) {
+ printk("SMC9111_leon3: didn't find any memory controller\n");
+ return 0;
+ }
+ }
}
}
/* Get controller address */
addr_mctrl = (unsigned long) apbmctrl.start;
- io = (LEON3_IOPORT_Regs_Map *) apbpio.start;
+ io = (struct grgpio_regs *) apbpio.start;
printk(
"Activating Leon3 io port for smsc_lan91cxx (pio:%x mctrl:%x)\n",
@@ -60,14 +63,13 @@ rtems_smc91111_driver_attach_leon3 (struct rtems_bsdnet_ifconfig *config,
(unsigned int)addr_mctrl);
/* Setup PIO IRQ */
- io->irqmask |= (1 << leon_scmv91111_configuration.pio);
- io->irqpol |= (1 << leon_scmv91111_configuration.pio);
- io->irqedge |= (1 << leon_scmv91111_configuration.pio);
- io->iodir &= ~(1 << leon_scmv91111_configuration.pio);
+ io->imask |= (1 << leon_scmv91111_configuration.pio);
+ io->ipol |= (1 << leon_scmv91111_configuration.pio);
+ io->iedge |= (1 << leon_scmv91111_configuration.pio);
+ io->dir &= ~(1 << leon_scmv91111_configuration.pio);
/* Setup memory controller I/O waitstates */
*((volatile unsigned int *) addr_mctrl) |= 0x10f80000; /* enable I/O area access */
- return _rtems_smc91111_driver_attach (config,
- &leon_scmv91111_configuration);
+ return _rtems_smc91111_driver_attach (config, &leon_scmv91111_configuration);
};
diff --git a/c/src/lib/libbsp/sparc/leon3/pci/pci.c b/c/src/lib/libbsp/sparc/leon3/pci/pci.c
deleted file mode 100644
index 9eedec3f25..0000000000
--- a/c/src/lib/libbsp/sparc/leon3/pci/pci.c
+++ /dev/null
@@ -1,586 +0,0 @@
-/*
- * pci.c : this file contains basic PCI Io functions.
- *
- * Copyright (C) 1999 valette@crf.canon.fr
- *
- * This code is heavily inspired by the public specification of STREAM V2
- * that can be found at :
- *
- * <http://www.chorus.com/Documentation/index.html> by following
- * the STREAM API Specification Document link.
- *
- * The license and distribution terms for this file may be
- * found in found in the file LICENSE in this distribution or at
- * http://www.rtems.com/license/LICENSE.
- *
- * pci.c,v 1.2.4.4 2004/11/10 22:15:01 joel Exp
- *
- * Till Straumann, <strauman@slac.stanford.edu>, 1/2002
- * - separated bridge detection code out of this file
- *
- *
- * Adapted to GRPCI
- * Copyright (C) 2006 Gaisler Research
- *
- */
-
-#include <pci.h>
-#include <stdlib.h>
-#include <rtems/bspIo.h>
-
-#define PCI_ADDR 0x80000400
-#define DMAPCI_ADDR 0x80000500
-#define PCI_CONF 0xfff50000
-#define PCI_MEM_START 0xe0000000
-#define PCI_MEM_END 0xf0000000
-#define PCI_MEM_SIZE (PCI_MEM_START - PCI_MEM_END)
-
-/* If uncommented byte twisting is enabled */
-/*#define BT_ENABLED 1*/
-
-/* Define PCI_INFO to get a listing of configured devices at boot time */
-#define PCI_INFO 1
-
-#define DEBUG 1
-
-#ifdef DEBUG
-#define DBG(x...) printk(x)
-#else
-#define DBG(x...)
-#endif
-
-/* allow for overriding these definitions */
-#ifndef PCI_CONFIG_ADDR
-#define PCI_CONFIG_ADDR 0xcf8
-#endif
-#ifndef PCI_CONFIG_DATA
-#define PCI_CONFIG_DATA 0xcfc
-#endif
-
-#define PCI_INVALID_VENDORDEVICEID 0xffffffff
-#define PCI_MULTI_FUNCTION 0x80
-
-/* define a shortcut */
-#define pci BSP_pci_configuration
-
-/*
- * Bit encode for PCI_CONFIG_HEADER_TYPE register
- */
-unsigned char ucMaxPCIBus;
-typedef struct {
- volatile unsigned int cfg_stat;
- volatile unsigned int bar0;
- volatile unsigned int page0;
- volatile unsigned int bar1;
- volatile unsigned int page1;
- volatile unsigned int iomap;
- volatile unsigned int stat_cmd;
-} LEON3_GRPCI_Regs_Map;
-
-LEON3_GRPCI_Regs_Map *pcic = (LEON3_GRPCI_Regs_Map *) PCI_ADDR;
-unsigned int *pcidma = (unsigned int *)DMAPCI_ADDR;
-
-struct pci_res {
- unsigned int size;
- unsigned char bar;
- unsigned char devfn;
-};
-
-static inline unsigned int flip_dword (unsigned int l)
-{
- return ((l&0xff)<<24) | (((l>>8)&0xff)<<16) | (((l>>16)&0xff)<<8)| ((l>>24)&0xff);
-}
-
-
-/* The configuration access functions uses the DMA functionality of the
- * AT697 pci controller to be able access all slots
- */
-
-
-static int
-BSP_pci_read_config_dword(
- unsigned char bus,
- unsigned char slot,
- unsigned char function,
- unsigned char offset,
- unsigned int *val
-)
-{
- volatile unsigned int *pci_conf;
-
- if (offset & 3) return PCIBIOS_BAD_REGISTER_NUMBER;
-
- if (slot > 21) {
- *val = 0xffffffff;
- return PCIBIOS_SUCCESSFUL;
- }
-
- pci_conf = (volatile unsigned int *) (PCI_CONF +
- ((slot<<11) | (function<<8) | offset));
-
-#ifdef BT_ENABLED
- *val = flip_dword(*pci_conf);
-#else
- *val = *pci_conf;
-#endif
-
- if (pcic->cfg_stat & 0x100) {
- *val = 0xffffffff;
- }
-
- DBG("pci_read - bus: %d, dev: %d, fn: %d, off: %d => addr: %x, val: %x\n", bus, slot, function, offset, (1<<(11+slot) ) | ((function & 7)<<8) | (offset&0x3f), *val);
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-
-static int
-BSP_pci_read_config_word(unsigned char bus, unsigned char slot, unsigned char function, unsigned char offset, unsigned short *val) {
- unsigned int v;
-
- if (offset & 1) return PCIBIOS_BAD_REGISTER_NUMBER;
-
- pci_read_config_dword(bus, slot, function, offset&~3, &v);
- *val = 0xffff & (v >> (8*(offset & 3)));
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-
-static int
-BSP_pci_read_config_byte(unsigned char bus, unsigned char slot, unsigned char function, unsigned char offset, unsigned char *val) {
- unsigned int v;
-
- pci_read_config_dword(bus, slot, function, offset&~3, &v);
-
- *val = 0xff & (v >> (8*(offset & 3)));
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-
-static int
-BSP_pci_write_config_dword(unsigned char bus, unsigned char slot, unsigned char function, unsigned char offset, unsigned int val) {
-
- volatile unsigned int *pci_conf;
- unsigned int value;
-
- if (offset & 3 || bus != 0) return PCIBIOS_BAD_REGISTER_NUMBER;
-
-
- pci_conf = (volatile unsigned int *) (PCI_CONF +
- ((slot<<11) | (function<<8) | (offset & ~3)));
-
-#ifdef BT_ENABLED
- value = flip_dword(val);
-#else
- value = val;
-#endif
-
- *pci_conf = value;
-
- DBG("pci write - bus: %d, dev: %d, fn: %d, off: %d => addr: %x, val: %x\n", bus, slot, function, offset, (1<<(11+slot) ) | ((function & 7)<<8) | (offset&0x3f), value);
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-
-static int
-BSP_pci_write_config_word(unsigned char bus, unsigned char slot, unsigned char function, unsigned char offset, unsigned short val) {
- unsigned int v;
-
- if (offset & 1) return PCIBIOS_BAD_REGISTER_NUMBER;
-
- pci_read_config_dword(bus, slot, function, offset&~3, &v);
-
- v = (v & ~(0xffff << (8*(offset&3)))) | ((0xffff&val) << (8*(offset&3)));
-
- return pci_write_config_dword(bus, slot, function, offset&~3, v);
-}
-
-
-static int
-BSP_pci_write_config_byte(unsigned char bus, unsigned char slot, unsigned char function, unsigned char offset, unsigned char val) {
- unsigned int v;
-
- pci_read_config_dword(bus, slot, function, offset&~3, &v);
-
- v = (v & ~(0xff << (8*(offset&3)))) | ((0xff&val) << (8*(offset&3)));
-
- return pci_write_config_dword(bus, slot, function, offset&~3, v);
-}
-
-
-
-const pci_config_access_functions pci_access_functions = {
- BSP_pci_read_config_byte,
- BSP_pci_read_config_word,
- BSP_pci_read_config_dword,
- BSP_pci_write_config_byte,
- BSP_pci_write_config_word,
- BSP_pci_write_config_dword
-};
-
-rtems_pci_config_t BSP_pci_configuration = {
- (volatile unsigned char*)PCI_CONFIG_ADDR,
- (volatile unsigned char*)PCI_CONFIG_DATA,
- &pci_access_functions
-};
-
-
-int init_grpci(void) {
-
- volatile unsigned int *page0 = (unsigned volatile int *) PCI_MEM_START;
- unsigned int data, addr;
-
-#ifndef BT_ENABLED
- pci_write_config_dword(0,0,0,0x10, 0xffffffff);
- pci_read_config_dword(0,0,0,0x10, &addr);
- pci_write_config_dword(0,0,0,0x10, flip_dword(0x10000000)); /* Setup bar0 to nonzero value (grpci considers BAR==0 as invalid) */
- addr = (~flip_dword(addr)+1)>>1; /* page0 is accessed through upper half of bar0 */
- pcic->cfg_stat |= 0x10000000; /* Setup mmap reg so we can reach bar0 */
- page0[addr/4] = 0; /* Disable bytetwisting ... */
-#endif
-
- /* set 1:1 mapping between AHB -> PCI memory */
- pcic->cfg_stat = (pcic->cfg_stat & 0x0fffffff) | PCI_MEM_START;
-
- /* and map system RAM at pci address 0x40000000 */
- pci_write_config_dword(0, 0, 0, 0x14, 0x40000000);
- pcic->page1 = 0x40000000;
-
- /* set as bus master and enable pci memory responses */
- pci_read_config_dword(0, 0, 0, 0x4, &data);
- pci_write_config_dword(0, 0, 0, 0x4, data | 0x6);
-
- return 0;
-}
-
-/* DMA functions which uses GRPCIs optional DMA controller (len in words) */
-int dma_to_pci(unsigned int ahb_addr, unsigned int pci_addr, unsigned int len) {
- int ret = 0;
-
- pcidma[0] = 0x82;
- pcidma[1] = ahb_addr;
- pcidma[2] = pci_addr;
- pcidma[3] = len;
- pcidma[0] = 0x83;
-
- while ( (pcidma[0] & 0x4) == 0)
- ;
-
- if (pcidma[0] & 0x8) { /* error */
- ret = -1;
- }
-
- pcidma[0] |= 0xC;
- return ret;
-
-}
-
-int dma_from_pci(unsigned int ahb_addr, unsigned int pci_addr, unsigned int len) {
- int ret = 0;
-
- pcidma[0] = 0x80;
- pcidma[1] = ahb_addr;
- pcidma[2] = pci_addr;
- pcidma[3] = len;
- pcidma[0] = 0x81;
-
- while ( (pcidma[0] & 0x4) == 0)
- ;
-
- if (pcidma[0] & 0x8) { /* error */
- ret = -1;
- }
-
- pcidma[0] |= 0xC;
- return ret;
-
-}
-
-
-void pci_mem_enable(unsigned char bus, unsigned char slot, unsigned char function) {
- unsigned int data;
-
- pci_read_config_dword(0, slot, function, PCI_COMMAND, &data);
- pci_write_config_dword(0, slot, function, PCI_COMMAND, data | PCI_COMMAND_MEMORY);
-
-}
-
-void pci_master_enable(unsigned char bus, unsigned char slot, unsigned char function) {
- unsigned int data;
-
- pci_read_config_dword(0, slot, function, PCI_COMMAND, &data);
- pci_write_config_dword(0, slot, function, PCI_COMMAND, data | PCI_COMMAND_MASTER);
-
-}
-
-static inline void swap_res(struct pci_res **p1, struct pci_res **p2) {
-
- struct pci_res *tmp = *p1;
- *p1 = *p2;
- *p2 = tmp;
-
-}
-
-/* pci_allocate_resources
- *
- * This function scans the bus and assigns PCI addresses to all devices. It handles both
- * single function and multi function devices. All allocated devices are enabled and
- * latency timers are set to 40.
- *
- * NOTE that it only allocates PCI memory space devices (that are at least 1 KB).
- * IO spaces are not enabled. Also, it does not handle pci-pci bridges. They are left disabled.
- *
- *
-*/
-void pci_allocate_resources(void) {
-
- unsigned int slot, numfuncs, func, id, pos, size, tmp, i, swapped, addr, dev, fn;
- unsigned char header;
- struct pci_res **res;
-
- res = (struct pci_res **) malloc(sizeof(struct pci_res *)*32*8*6);
-
- for (i = 0; i < 32*8*6; i++) {
- res[i] = (struct pci_res *) malloc(sizeof(struct pci_res));
- res[i]->size = 0;
- res[i]->devfn = i;
- }
-
- for(slot = 1; slot < PCI_MAX_DEVICES; slot++) {
-
- pci_read_config_dword(0, slot, 0, PCI_VENDOR_ID, &id);
-
- if(id == PCI_INVALID_VENDORDEVICEID || id == 0) {
- /*
- * This slot is empty
- */
- continue;
- }
-
- pci_read_config_byte(0, slot, 0, PCI_HEADER_TYPE, &header);
-
- if(header & PCI_MULTI_FUNCTION) {
- numfuncs = PCI_MAX_FUNCTIONS;
- }
- else {
- numfuncs = 1;
- }
-
- for(func = 0; func < numfuncs; func++) {
-
- pci_read_config_dword(0, slot, func, PCI_VENDOR_ID, &id);
- if(id == PCI_INVALID_VENDORDEVICEID || id == 0) {
- continue;
- }
-
- pci_read_config_dword(0, slot, func, PCI_CLASS_REVISION, &tmp);
- tmp >>= 16;
- if (tmp == PCI_CLASS_BRIDGE_PCI) {
- continue;
- }
-
- for (pos = 0; pos < 6; pos++) {
- pci_write_config_dword(0, slot, func, PCI_BASE_ADDRESS_0 + (pos<<2), 0xffffffff);
- pci_read_config_dword(0, slot, func, PCI_BASE_ADDRESS_0 + (pos<<2), &size);
-
- if (size == 0 || size == 0xffffffff || (size & 0x3f1) != 0){
- pci_write_config_dword(0, slot, func, PCI_BASE_ADDRESS_0 + (pos<<2), 0);
- continue;
-
- }else {
- size &= 0xfffffff0;
- res[slot*8*6+func*6+pos]->size = ~size+1;
- res[slot*8*6+func*6+pos]->devfn = slot*8 + func;
- res[slot*8*6+func*6+pos]->bar = pos;
-
- DBG("Slot: %d, function: %d, bar%d size: %x\n", slot, func, pos, ~size+1);
- }
- }
- }
- }
-
-
- /* Sort the resources in descending order */
- swapped = 1;
- while (swapped == 1) {
- swapped = 0;
- for (i = 0; i < 32*8*6-1; i++) {
- if (res[i]->size < res[i+1]->size) {
- swap_res(&res[i], &res[i+1]);
- swapped = 1;
- }
- }
- i++;
- }
-
- /* Assign the BARs */
- addr = PCI_MEM_START;
- for (i = 0; i < 32*8*6; i++) {
-
- if (res[i]->size == 0) {
- goto done;
- }
- if ( (addr + res[i]->size) > PCI_MEM_END) {
- printk("Out of PCI memory space, all devices not configured.\n");
- goto done;
- }
-
- dev = res[i]->devfn >> 3;
- fn = res[i]->devfn & 7;
-
- DBG("Assigning PCI addr %x to device %d, function %d, bar %d\n", addr, dev, fn, res[i]->bar);
- pci_write_config_dword(0, dev, fn, PCI_BASE_ADDRESS_0+res[i]->bar*4, addr);
- addr += res[i]->size;
-
- /* Set latency timer to 64 */
- pci_read_config_dword(0, dev, fn, 0xC, &tmp);
- pci_write_config_dword(0, dev, fn, 0xC, tmp|0x4000);
-
- pci_mem_enable(0, dev, fn);
-
- }
-
-
-
-done:
-
-#ifdef PCI_INFO
- printk("\nPCI devices found and configured:\n");
- for (slot = 1; slot < PCI_MAX_DEVICES; slot++) {
-
- pci_read_config_byte(0, slot, 0, PCI_HEADER_TYPE, &header);
-
- if(header & PCI_MULTI_FUNCTION) {
- numfuncs = PCI_MAX_FUNCTIONS;
- }
- else {
- numfuncs = 1;
- }
-
- for (func = 0; func < numfuncs; func++) {
-
- pci_read_config_dword(0, slot, func, PCI_COMMAND, &tmp);
-
- if (tmp & PCI_COMMAND_MEMORY) {
-
- pci_read_config_dword(0, slot, func, PCI_VENDOR_ID, &id);
-
- if (id == PCI_INVALID_VENDORDEVICEID || id == 0) continue;
-
- printk("\nSlot %d function: %d\nVendor id: 0x%x, device id: 0x%x\n", slot, func, id & 0xffff, id>>16);
-
- for (pos = 0; pos < 6; pos++) {
- pci_read_config_dword(0, slot, func, PCI_BASE_ADDRESS_0 + pos*4, &tmp);
-
- if (tmp != 0 && tmp != 0xffffffff && (tmp & 0x3f1) == 0) {
-
- printk("\tBAR %d: %x\n", pos, tmp);
- }
-
- }
- printk("\n");
-
- }
-
- }
- }
- printk("\n");
-#endif
-
- for (i = 0; i < 1536; i++) {
- free(res[i]);
- }
- free(res);
-}
-
-
-
-int init_pci(void)
-{
- unsigned char ucSlotNumber, ucFnNumber, ucNumFuncs;
- unsigned char ucHeader;
- unsigned char ucMaxSubordinate;
- unsigned int ulClass, ulDeviceID;
-
- DBG("Initializing PCI\n");
- if ( init_grpci() ) {
- return -1;
- }
- pci_allocate_resources();
- DBG("PCI resource allocation done\n");
-/*
- * Scan PCI bus 0 looking for PCI-PCI bridges
- */
- for(ucSlotNumber=0;ucSlotNumber<PCI_MAX_DEVICES;ucSlotNumber++) {
- (void)pci_read_config_dword(0,
- ucSlotNumber,
- 0,
- PCI_VENDOR_ID,
- &ulDeviceID);
- if(ulDeviceID==PCI_INVALID_VENDORDEVICEID) {
-/*
- * This slot is empty
- */
- continue;
- }
- (void)pci_read_config_byte(0,
- ucSlotNumber,
- 0,
- PCI_HEADER_TYPE,
- &ucHeader);
- if(ucHeader&PCI_MULTI_FUNCTION) {
- ucNumFuncs=PCI_MAX_FUNCTIONS;
- }
- else {
- ucNumFuncs=1;
- }
- for(ucFnNumber=0;ucFnNumber<ucNumFuncs;ucFnNumber++) {
- (void)pci_read_config_dword(0,
- ucSlotNumber,
- ucFnNumber,
- PCI_VENDOR_ID,
- &ulDeviceID);
- if(ulDeviceID==PCI_INVALID_VENDORDEVICEID) {
-/*
- * This slot/function is empty
- */
- continue;
- }
-
-/*
- * This slot/function has a device fitted.
- */
- (void)pci_read_config_dword(0,
- ucSlotNumber,
- ucFnNumber,
- PCI_CLASS_REVISION,
- &ulClass);
- ulClass >>= 16;
- if (ulClass == PCI_CLASS_BRIDGE_PCI) {
-/*
- * We have found a PCI-PCI bridge
- */
- (void)pci_read_config_byte(0,
- ucSlotNumber,
- ucFnNumber,
- PCI_SUBORDINATE_BUS,
- &ucMaxSubordinate);
- if(ucMaxSubordinate>ucMaxPCIBus) {
- ucMaxPCIBus=ucMaxSubordinate;
- }
- }
- }
- }
- return 0;
-}
-
-/*
- * Return the number of PCI busses in the system
- */
-unsigned char BusCountPCI(void)
-{
- return(ucMaxPCIBus+1);
-}
diff --git a/c/src/lib/libbsp/sparc/leon3/preinstall.am b/c/src/lib/libbsp/sparc/leon3/preinstall.am
index b948529704..00eeb53aa1 100644
--- a/c/src/lib/libbsp/sparc/leon3/preinstall.am
+++ b/c/src/lib/libbsp/sparc/leon3/preinstall.am
@@ -73,6 +73,10 @@ $(PROJECT_LIB)/linkcmds: startup/linkcmds $(PROJECT_LIB)/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_LIB)/linkcmds
PREINSTALL_FILES += $(PROJECT_LIB)/linkcmds
+$(PROJECT_LIB)/linkcmds_ngmp: startup/linkcmds_ngmp $(PROJECT_LIB)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_LIB)/linkcmds_ngmp
+PREINSTALL_FILES += $(PROJECT_LIB)/linkcmds_ngmp
+
$(PROJECT_LIB)/linkcmds.base: ../shared/startup/linkcmds.base $(PROJECT_LIB)/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_LIB)/linkcmds.base
PREINSTALL_FILES += $(PROJECT_LIB)/linkcmds.base
@@ -85,26 +89,98 @@ $(PROJECT_INCLUDE)/ambapp.h: ../../sparc/shared/include/ambapp.h $(PROJECT_INCLU
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/ambapp.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/ambapp.h
-$(PROJECT_INCLUDE)/pci.h: ../../sparc/shared/include/pci.h $(PROJECT_INCLUDE)/$(dirstamp)
- $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/pci.h
-PREINSTALL_FILES += $(PROJECT_INCLUDE)/pci.h
+$(PROJECT_INCLUDE)/ambapp_ids.h: ../../sparc/shared/include/ambapp_ids.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/ambapp_ids.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/ambapp_ids.h
+
+$(PROJECT_INCLUDE)/grlib.h: ../../sparc/shared/include/grlib.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grlib.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/grlib.h
+
+$(PROJECT_INCLUDE)/ahbstat.h: ../../sparc/shared/include/ahbstat.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/ahbstat.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/ahbstat.h
+
+$(PROJECT_INCLUDE)/tlib.h: ../../sparc/shared/include/tlib.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/tlib.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/tlib.h
+
+$(PROJECT_INCLUDE)/cons.h: ../../sparc/shared/include/cons.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/cons.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/cons.h
+
+$(PROJECT_INCLUDE)/genirq.h: ../../sparc/shared/include/genirq.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/genirq.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/genirq.h
+
+$(PROJECT_INCLUDE)/bsp/irq-generic.h: ../../shared/include/irq-generic.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/irq-generic.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/irq-generic.h
+
+$(PROJECT_INCLUDE)/bsp/irq-info.h: ../../shared/include/irq-info.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/irq-info.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/irq-info.h
+
+$(PROJECT_INCLUDE)/bsp/irq.h: include/bsp/irq.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/irq.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/irq.h
+
+$(PROJECT_INCLUDE)/grpci2.h: ../../sparc/shared/include/grpci2.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grpci2.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/grpci2.h
+
+$(PROJECT_INCLUDE)/gr_701.h: ../../sparc/shared/include/gr_701.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/gr_701.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/gr_701.h
+
+$(PROJECT_INCLUDE)/gr_rasta_adcdac.h: ../../sparc/shared/include/gr_rasta_adcdac.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/gr_rasta_adcdac.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/gr_rasta_adcdac.h
+
+$(PROJECT_INCLUDE)/gr_rasta_io.h: ../../sparc/shared/include/gr_rasta_io.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/gr_rasta_io.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/gr_rasta_io.h
+
+$(PROJECT_INCLUDE)/gr_rasta_tmtc.h: ../../sparc/shared/include/gr_rasta_tmtc.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/gr_rasta_tmtc.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/gr_rasta_tmtc.h
+
+$(PROJECT_INCLUDE)/gr_tmtc_1553.h: ../../sparc/shared/include/gr_tmtc_1553.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/gr_tmtc_1553.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/gr_tmtc_1553.h
$(PROJECT_INCLUDE)/b1553brm.h: ../../sparc/shared/include/b1553brm.h $(PROJECT_INCLUDE)/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/b1553brm.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/b1553brm.h
-$(PROJECT_INCLUDE)/b1553brm_pci.h: ../../sparc/shared/include/b1553brm_pci.h $(PROJECT_INCLUDE)/$(dirstamp)
- $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/b1553brm_pci.h
-PREINSTALL_FILES += $(PROJECT_INCLUDE)/b1553brm_pci.h
+$(PROJECT_INCLUDE)/b1553rt.h: ../../sparc/shared/include/b1553rt.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/b1553rt.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/b1553rt.h
+
+$(PROJECT_INCLUDE)/gr1553b.h: ../../sparc/shared/include/gr1553b.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/gr1553b.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/gr1553b.h
+
+$(PROJECT_INCLUDE)/gr1553bc.h: ../../sparc/shared/include/gr1553bc.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/gr1553bc.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/gr1553bc.h
+
+$(PROJECT_INCLUDE)/gr1553bc_list.h: ../../sparc/shared/include/gr1553bc_list.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/gr1553bc_list.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/gr1553bc_list.h
+
+$(PROJECT_INCLUDE)/gr1553bm.h: ../../sparc/shared/include/gr1553bm.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/gr1553bm.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/gr1553bm.h
+
+$(PROJECT_INCLUDE)/gr1553rt.h: ../../sparc/shared/include/gr1553rt.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/gr1553rt.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/gr1553rt.h
$(PROJECT_INCLUDE)/occan.h: ../../sparc/shared/include/occan.h $(PROJECT_INCLUDE)/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/occan.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/occan.h
-$(PROJECT_INCLUDE)/occan_pci.h: ../../sparc/shared/include/occan_pci.h $(PROJECT_INCLUDE)/$(dirstamp)
- $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/occan_pci.h
-PREINSTALL_FILES += $(PROJECT_INCLUDE)/occan_pci.h
-
$(PROJECT_INCLUDE)/grcan.h: ../../sparc/shared/include/grcan.h $(PROJECT_INCLUDE)/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grcan.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/grcan.h
@@ -113,19 +189,122 @@ $(PROJECT_INCLUDE)/grspw.h: ../../sparc/shared/include/grspw.h $(PROJECT_INCLUDE
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grspw.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/grspw.h
-$(PROJECT_INCLUDE)/grspw_pci.h: ../../sparc/shared/include/grspw_pci.h $(PROJECT_INCLUDE)/$(dirstamp)
- $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grspw_pci.h
-PREINSTALL_FILES += $(PROJECT_INCLUDE)/grspw_pci.h
+$(PROJECT_INCLUDE)/grspw_pkt.h: ../../sparc/shared/include/grspw_pkt.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grspw_pkt.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/grspw_pkt.h
+
+$(PROJECT_INCLUDE)/grspw_router.h: ../../sparc/shared/include/grspw_router.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grspw_router.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/grspw_router.h
+
+$(PROJECT_INCLUDE)/rmap.h: ../../sparc/shared/include/rmap.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rmap.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/rmap.h
+
+$(PROJECT_INCLUDE)/rmap_drv_grspw.h: ../../sparc/shared/include/rmap_drv_grspw.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rmap_drv_grspw.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/rmap_drv_grspw.h
$(PROJECT_INCLUDE)/apbuart.h: ../../sparc/shared/include/apbuart.h $(PROJECT_INCLUDE)/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/apbuart.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/apbuart.h
-$(PROJECT_INCLUDE)/apbuart_pci.h: ../../sparc/shared/include/apbuart_pci.h $(PROJECT_INCLUDE)/$(dirstamp)
- $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/apbuart_pci.h
-PREINSTALL_FILES += $(PROJECT_INCLUDE)/apbuart_pci.h
-
$(PROJECT_INCLUDE)/i2cmst.h: ../../sparc/shared/include/i2cmst.h $(PROJECT_INCLUDE)/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/i2cmst.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/i2cmst.h
+$(PROJECT_INCLUDE)/spictrl.h: ../../sparc/shared/include/spictrl.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/spictrl.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/spictrl.h
+
+$(PROJECT_INCLUDE)/spwcuc.h: ../../sparc/shared/include/spwcuc.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/spwcuc.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/spwcuc.h
+
+$(PROJECT_INCLUDE)/grctm.h: ../../sparc/shared/include/grctm.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grctm.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/grctm.h
+
+$(PROJECT_INCLUDE)/grgpio.h: ../../sparc/shared/include/grgpio.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grgpio.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/grgpio.h
+
+$(PROJECT_INCLUDE)/gpiolib.h: ../../sparc/shared/include/gpiolib.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/gpiolib.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/gpiolib.h
+
+$(PROJECT_INCLUDE)/graes.h: ../../sparc/shared/include/graes.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/graes.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/graes.h
+
+$(PROJECT_INCLUDE)/grpwrx.h: ../../sparc/shared/include/grpwrx.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grpwrx.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/grpwrx.h
+
+$(PROJECT_INCLUDE)/grpwm.h: ../../sparc/shared/include/grpwm.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grpwm.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/grpwm.h
+
+$(PROJECT_INCLUDE)/gradcdac.h: ../../sparc/shared/include/gradcdac.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/gradcdac.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/gradcdac.h
+
+$(PROJECT_INCLUDE)/grascs.h: ../../sparc/shared/include/grascs.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grascs.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/grascs.h
+
+$(PROJECT_INCLUDE)/satcan.h: ../../sparc/shared/include/satcan.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/satcan.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/satcan.h
+
+$(PROJECT_INCLUDE)/canmux.h: ../../sparc/shared/include/canmux.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/canmux.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/canmux.h
+
+$(PROJECT_INCLUDE)/grslink.h: ../../sparc/shared/include/grslink.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grslink.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/grslink.h
+
+$(PROJECT_INCLUDE)/grtc.h: ../../sparc/shared/include/grtc.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grtc.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/grtc.h
+
+$(PROJECT_INCLUDE)/grtm.h: ../../sparc/shared/include/grtm.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grtm.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/grtm.h
+
+$(PROJECT_INCLUDE)/drvmgr/$(dirstamp):
+ @$(MKDIR_P) $(PROJECT_INCLUDE)/drvmgr
+ @: > $(PROJECT_INCLUDE)/drvmgr/$(dirstamp)
+PREINSTALL_DIRS += $(PROJECT_INCLUDE)/drvmgr/$(dirstamp)
+
+$(PROJECT_INCLUDE)/drvmgr/ambapp_bus_grlib.h: ../../sparc/shared/include/drvmgr/ambapp_bus_grlib.h $(PROJECT_INCLUDE)/drvmgr/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/drvmgr/ambapp_bus_grlib.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/drvmgr/ambapp_bus_grlib.h
+
+$(PROJECT_INCLUDE)/drvmgr/ambapp_bus_rmap.h: ../../sparc/shared/include/drvmgr/ambapp_bus_rmap.h $(PROJECT_INCLUDE)/drvmgr/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/drvmgr/ambapp_bus_rmap.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/drvmgr/ambapp_bus_rmap.h
+
+$(PROJECT_INCLUDE)/drvmgr/ambapp_bus.h: ../../sparc/shared/include/drvmgr/ambapp_bus.h $(PROJECT_INCLUDE)/drvmgr/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/drvmgr/ambapp_bus.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/drvmgr/ambapp_bus.h
+
+$(PROJECT_INCLUDE)/drvmgr/spw_bus.h: ../../sparc/shared/include/drvmgr/spw_bus.h $(PROJECT_INCLUDE)/drvmgr/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/drvmgr/spw_bus.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/drvmgr/spw_bus.h
+
+$(PROJECT_INCLUDE)/drvmgr/spw_bus_ids.h: ../../sparc/shared/include/drvmgr/spw_bus_ids.h $(PROJECT_INCLUDE)/drvmgr/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/drvmgr/spw_bus_ids.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/drvmgr/spw_bus_ids.h
+
+if HAS_NETWORKING
+$(PROJECT_INCLUDE)/greth.h: ../../sparc/shared/include/greth.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/greth.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/greth.h
+endif
+if HAS_NETWORKING
+$(PROJECT_INCLUDE)/network_interface_add.h: ../../sparc/shared/include/network_interface_add.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/network_interface_add.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/network_interface_add.h
+endif
diff --git a/c/src/lib/libbsp/sparc/leon3/shmsupp/getcfg.c b/c/src/lib/libbsp/sparc/leon3/shmsupp/getcfg.c
index 609c2b1d98..55b5659155 100644
--- a/c/src/lib/libbsp/sparc/leon3/shmsupp/getcfg.c
+++ b/c/src/lib/libbsp/sparc/leon3/shmsupp/getcfg.c
@@ -76,8 +76,12 @@ extern rtems_mpci_entry Shm_Send_packet(
#define INTERRUPT 0 /* XXX: */
#define POLLING 1 /* XXX: fix me -- is polling ONLY!!! */
-
-shm_config_table BSP_shm_cfgtbl;
+/* Let user override this configuration by declaring this a weak variable */
+shm_config_table BSP_shm_cfgtbl __attribute__((weak)) =
+{
+ (vol_u32 *)0x40000000,
+ 0x00001000,
+};
void Shm_Get_configuration(
uint32_t localnode,
@@ -88,8 +92,6 @@ void Shm_Get_configuration(
int i;
unsigned int tmp;
- BSP_shm_cfgtbl.base = 0x40000000;
- BSP_shm_cfgtbl.length = 0x00001000;
BSP_shm_cfgtbl.format = SHM_BIG;
/*
@@ -107,14 +109,14 @@ void Shm_Get_configuration(
BSP_shm_cfgtbl.poll_intr = INTR_MODE;
BSP_shm_cfgtbl.Intr.address =
- (vol_u32) &(LEON3_IrqCtrl_Regs->force[LEON3_Cpu_Index]);
+ (vol_u32 *) &(LEON3_IrqCtrl_Regs->force[LEON3_Cpu_Index]);
BSP_shm_cfgtbl.Intr.value = 1 << LEON3_MP_IRQ ;
BSP_shm_cfgtbl.Intr.length = 4;
if (LEON3_Cpu_Index == 0) {
tmp = 0;
for (i = 1;
- i < (Configuration.User_multiprocessing_table)->maximum_nodes+1; i++)
+ i < (Configuration.User_multiprocessing_table)->maximum_nodes; i++)
tmp |= (1 << i);
LEON3_IrqCtrl_Regs->mpstat = tmp;
}
diff --git a/c/src/lib/libbsp/sparc/leon3/startup/bspidle.S b/c/src/lib/libbsp/sparc/leon3/startup/bspidle.S
index 24be8c0cb0..cb832677bf 100644
--- a/c/src/lib/libbsp/sparc/leon3/startup/bspidle.S
+++ b/c/src/lib/libbsp/sparc/leon3/startup/bspidle.S
@@ -24,6 +24,7 @@
PUBLIC(bsp_idle_thread)
SYM(bsp_idle_thread):
pwdloop: mov %g0, %asr19
+ lda [%sp] 1, %g0 ! Needed for UT699 and GR712
ba pwdloop
nop
retl
diff --git a/c/src/lib/libbsp/sparc/leon3/startup/bsppredriver.c b/c/src/lib/libbsp/sparc/leon3/startup/bsppredriver.c
new file mode 100644
index 0000000000..ff633fee98
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/leon3/startup/bsppredriver.c
@@ -0,0 +1,27 @@
+/* Installs the BSP pre-driver hook
+ *
+ * COPYRIGHT (c) 2011
+ * Aeroflex Gaisler
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+
+#include <bsp.h>
+
+/*
+ * bsp_predriver_hook
+ *
+ * BSP predriver hook. Called just before drivers are initialized.
+ * Is used to initialize shared interrupt handling.
+ */
+void bsp_predriver_hook( void )
+{
+ /* Initialize shared interrupt handling, must be done after IRQ
+ * controller has been found and initialized.
+ */
+ BSP_shared_interrupt_init();
+}
diff --git a/c/src/lib/libbsp/sparc/leon3/startup/bspstart.c b/c/src/lib/libbsp/sparc/leon3/startup/bspstart.c
index fbe6b876ed..9e957020ba 100644
--- a/c/src/lib/libbsp/sparc/leon3/startup/bspstart.c
+++ b/c/src/lib/libbsp/sparc/leon3/startup/bspstart.c
@@ -27,25 +27,37 @@
*/
int CPU_SPARC_HAS_SNOOPING;
+/* Index of CPU, in an AMP system CPU-index may be non-zero */
+int LEON3_Cpu_Index = 0;
+
extern void amba_initialize(void);
+extern void bsp_debug_uart_init(void);
/*
* set_snooping
*
* Read the data cache configuration register to determine if
- * bus snooping is available. This is needed for some drivers so
- * that they can select the most efficient copy routines.
+ * bus snooping is available and enabled. This is needed for some
+ * drivers so that they can select the most efficient copy routines.
*
*/
static inline int set_snooping(void)
{
int tmp;
- asm(" lda [%1] 2, %0 "
+ asm(" lda [%%g0] 2, %0 "
: "=r"(tmp)
- : "r"(0xC)
+ :
);
- return (tmp >> 27) & 1;
+ return (tmp >> 23) & 1;
+}
+
+/* ASM-function used to get the CPU-Index on calling LEON3 CPUs */
+static inline unsigned int get_asr17(void)
+{
+ unsigned int reg;
+ __asm__ (" mov %%asr17, %0 " : "=r"(reg) :);
+ return reg;
}
/*
@@ -57,6 +69,19 @@ void bsp_start( void )
{
CPU_SPARC_HAS_SNOOPING = set_snooping();
- /* Find UARTs */
+ /* Get the LEON3 CPU index, normally 0, but for MP systems we do
+ * _not_ assume that this is CPU0. One may run another OS on CPU0
+ * and RTEMS on this CPU, and AMP system with mixed operating
+ * systems
+ */
+ LEON3_Cpu_Index = (get_asr17() >> 28) & 3;
+
+ /* Scan AMBA Plug&Play and parse it into a RAM description (ambapp_plb),
+ * find GPTIMER for bus frequency, find IRQ Controller and initialize
+ * interrupt support
+ */
amba_initialize();
+
+ /* find debug UART for printk() */
+ bsp_debug_uart_init();
}
diff --git a/c/src/lib/libbsp/sparc/leon3/startup/eirq.c b/c/src/lib/libbsp/sparc/leon3/startup/eirq.c
new file mode 100644
index 0000000000..68089a3d0c
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/leon3/startup/eirq.c
@@ -0,0 +1,27 @@
+/*
+ * GRLIB/LEON3 extended interrupt controller
+ *
+ * COPYRIGHT (c) 2011
+ * Aeroflex Gaisler
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ */
+
+#include <bsp.h>
+
+extern int LEON3_Cpu_Index;
+
+/* GRLIB extended IRQ controller IRQ number */
+int LEON3_IrqCtrl_EIrq = -1;
+
+/* Initialize Exteneded Interrupt controller */
+void leon3_ext_irq_init(void)
+{
+ if ( (LEON3_IrqCtrl_Regs->mpstat >> 16) & 0xf ) {
+ /* Extended IRQ controller available */
+ LEON3_IrqCtrl_EIrq = (LEON3_IrqCtrl_Regs->mpstat >> 16) & 0xf;
+ }
+}
diff --git a/c/src/lib/libbsp/sparc/leon3/startup/linkcmds_ngmp b/c/src/lib/libbsp/sparc/leon3/startup/linkcmds_ngmp
new file mode 100644
index 0000000000..b0acd650c7
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/leon3/startup/linkcmds_ngmp
@@ -0,0 +1,210 @@
+/* linkcmds
+ *
+ * $Id: linkcmds,v 1.8 2008/08/08 15:54:59 joel Exp $
+ */
+
+OUTPUT_ARCH(sparc)
+__DYNAMIC = 0;
+
+/*
+ * The memory map looks like this:
+ * +--------------------+ <- low memory
+ * | .text |
+ * | etext |
+ * | ctor list | the ctor and dtor lists are for
+ * | dtor list | C++ support
+ * | _endtext |
+ * +--------------------+
+ * | .data | initialized data goes here
+ * | _sdata |
+ * | _edata |
+ * +--------------------+
+ * | .bss |
+ * | __bss_start | start of bss, cleared by crt0
+ * | _end | start of heap, used by sbrk()
+ * +--------------------+
+ * | heap space |
+ * | _ENDHEAP |
+ * | stack space |
+ * | __stack | top of stack
+ * +--------------------+ <- high memory
+ */
+
+
+/*
+ * User modifiable values:
+ *
+ * _CLOCK_SPEED in Mhz (used to program the counter/timers)
+ *
+ * _PROM_SIZE size of PROM (permissible values are 128K, 256K,
+ * 512K, 1M, 2M, 4M, 8M and 16M)
+ * _RAM_SIZE size of RAM (permissible values are 256K, 512K,
+ * 1M, 2M, 4M, 8M, 16M, and 32M)
+ *
+ */
+
+/* Default values, can be overridden */
+
+/*_PROM_SIZE = 2M;*/
+_RAM_SIZE = 64M;
+
+_RAM_START = 0x00000000;
+_RAM_END = _RAM_START + _RAM_SIZE;
+
+/*_PROM_START = 0xC0000000;
+_PROM_END = _PROM_START + _PROM_SIZE;*/
+
+/*
+ * Alternate names without leading _.
+ */
+
+/*PROM_START = _PROM_START;
+PROM_SIZE = _PROM_SIZE;
+PROM_END = _PROM_END;*/
+
+RAM_START = _RAM_START;
+RAM_SIZE = _RAM_SIZE;
+RAM_END = _RAM_END;
+
+/* these are the maximum values */
+
+MEMORY
+{
+ rom : ORIGIN = 0xC0000000, LENGTH = 256M
+ ram : ORIGIN = 0x00000000, LENGTH = 2048M
+ sram : ORIGIN = 0xD0000000, LENGTH = 256M
+}
+
+/*
+ * SPARC monitor assumes this is present to provide proper RTEMS awareness.
+ */
+EXTERN(rtems_get_version_string);
+
+/*
+ * stick everything in ram (of course)
+ */
+SECTIONS
+{
+ .text :
+ {
+ CREATE_OBJECT_SYMBOLS
+ text_start = .;
+ _text_start = .;
+ *(.text*)
+ . = ALIGN (16);
+
+ /*
+ * Special FreeBSD sysctl sections.
+ */
+ . = ALIGN (16);
+ __start_set_sysctl_set = .;
+ *(set_sysctl_*);
+ __stop_set_sysctl_set = ABSOLUTE(.);
+ *(set_domain_*);
+ *(set_pseudo_*);
+
+ *(.eh_frame)
+ . = ALIGN (16);
+
+ *(.gnu.linkonce.t*)
+
+ /*
+ * C++ constructors
+ */
+ /* gcc uses crtbegin.o to find the start of
+ the constructors, so we make sure it is
+ first. Because this is a wildcard, it
+ doesn't matter if the user does not
+ actually link against crtbegin.o; the
+ linker won't look for a file to match a
+ wildcard. The wildcard also means that it
+ doesn't matter which directory crtbegin.o
+ is in. */
+ KEEP (*crtbegin.o(.ctors))
+ KEEP (*crtbegin?.o(.ctors))
+ /* We don't want to include the .ctor section from
+ the crtend.o file until after the sorted ctors.
+ The .ctor section from the crtend file contains the
+ end of ctors marker and it must be last */
+ KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
+ KEEP (*(SORT(.ctors.*)))
+ KEEP (*(.ctors))
+ KEEP (*crtbegin.o(.dtors))
+ KEEP (*crtbegin?.o(.dtors))
+ KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
+ KEEP (*(SORT(.dtors.*)))
+ KEEP (*(.dtors))
+
+ _rodata_start = . ;
+ *(.rodata*)
+ *(.gnu.linkonce.r*)
+ _erodata = ALIGN( 0x10 ) ;
+
+ etext = ALIGN(0x10);
+ _etext = .;
+ *(.init)
+ *(.fini)
+ *(.lit)
+ *(.shdata)
+ . = ALIGN (16);
+ _endtext = .;
+ } > ram
+ .rela.dyn :
+ {
+ *(.rela.init)
+ *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
+ *(.rela.fini)
+ *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
+ *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
+ *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
+ *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
+ *(.rela.ctors)
+ *(.rela.dtors)
+ *(.rela.got)
+ *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
+ } >ram
+ .data :
+ {
+ data_start = .;
+ _data_start = .;
+ _sdata = . ;
+ *(.data*)
+ *(.gnu.linkonce.d*)
+ *(.gcc_except_table*)
+ . = ALIGN(0x10);
+ edata = .;
+ _edata = .;
+ } > ram
+ .dynamic : { *(.dynamic) } >ram
+ .jcr : { *(.jcr) } >ram
+ .got : { *(.got) } >ram
+ .plt : { *(.plt) } >ram
+ .hash : { *(.hash) } >ram
+ .dynrel : { *(.dynrel) } >ram
+ .dynsym : { *(.dynsym) } >ram
+ .dynstr : { *(.dynstr) } >ram
+ .hash : { *(.hash) } >ram
+ .shbss :
+ {
+ *(.shbss)
+ } > ram
+ .bss :
+ {
+ __bss_start = ALIGN(0x8);
+ _bss_start = .;
+ bss_start = .;
+ *(.bss .bss* .gnu.linkonce.b*)
+ *(COMMON)
+ end = .;
+ _end = ALIGN(0x8);
+ __end = ALIGN(0x8);
+ } > ram
+ .stab . (NOLOAD) :
+ {
+ [ .stab ]
+ }
+ .stabstr . (NOLOAD) :
+ {
+ [ .stabstr ]
+ }
+}
diff --git a/c/src/lib/libbsp/sparc/leon3/startup/setvec.c b/c/src/lib/libbsp/sparc/leon3/startup/setvec.c
index c7b8af6616..028b17a26a 100644
--- a/c/src/lib/libbsp/sparc/leon3/startup/setvec.c
+++ b/c/src/lib/libbsp/sparc/leon3/startup/setvec.c
@@ -42,7 +42,7 @@ rtems_isr_entry set_vector( /* returns old vector */
uint32_t real_trap;
uint32_t source;
- if ( type )
+ if ( type == SET_VECTOR_INT )
rtems_interrupt_catch( handler, vector, &previous_isr );
else
_CPU_ISR_install_raw_handler( vector, handler, (void *)&previous_isr );
diff --git a/c/src/lib/libbsp/sparc/leon3/startup/spurious.c b/c/src/lib/libbsp/sparc/leon3/startup/spurious.c
index 62d38d3f0c..c7b63eb6a4 100644
--- a/c/src/lib/libbsp/sparc/leon3/startup/spurious.c
+++ b/c/src/lib/libbsp/sparc/leon3/startup/spurious.c
@@ -38,7 +38,7 @@ rtems_isr bsp_spurious_handler(
real_trap = SPARC_REAL_TRAP_NUMBER(trap);
- printk( "Unexpected trap (%2d) at address 0x%08x\n", real_trap, isf->tpc);
+ printk( "Unexpected trap (0x%02x) at address 0x%08x\n", real_trap, isf->tpc);
switch (real_trap) {
diff --git a/c/src/lib/libbsp/sparc/leon3/timer/timer.c b/c/src/lib/libbsp/sparc/leon3/timer/timer.c
index 47de8339dc..b16c970b2f 100644
--- a/c/src/lib/libbsp/sparc/leon3/timer/timer.c
+++ b/c/src/lib/libbsp/sparc/leon3/timer/timer.c
@@ -34,7 +34,7 @@ bool benchmark_timer_find_average_overhead;
bool benchmark_timer_is_initialized = false;
-extern volatile LEON3_Timer_Regs_Map *LEON3_Timer_Regs;
+extern volatile struct gptimer_regs *LEON3_Timer_Regs;
void benchmark_timer_initialize(void)
{
@@ -49,7 +49,7 @@ void benchmark_timer_initialize(void)
} else {
benchmark_timer_is_initialized = true;
}
- LEON3_Timer_Regs->timer[LEON3_TIMER_INDEX].conf = LEON3_GPTIMER_EN | LEON3_GPTIMER_LD;
+ LEON3_Timer_Regs->timer[LEON3_TIMER_INDEX].ctrl = LEON3_GPTIMER_EN | LEON3_GPTIMER_LD;
}
}
diff --git a/c/src/lib/libbsp/sparc/leon3/timer/watchdog.c b/c/src/lib/libbsp/sparc/leon3/timer/watchdog.c
new file mode 100644
index 0000000000..47a5a8051a
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/leon3/timer/watchdog.c
@@ -0,0 +1,91 @@
+/* GPTIMER Watchdog timer routines. On some systems the first GPTIMER
+ * core's last Timer instance underflow signal is connected to system
+ * reset.
+ *
+ * COPYRIGHT (c) 2011
+ * Aeroflex Gaisler
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+
+#include <bsp.h>
+#include <grlib.h>
+
+extern volatile struct gptimer_regs *LEON3_Timer_Regs;
+
+struct gptimer_watchdog_priv {
+ struct gptimer_regs *regs;
+ struct gptimer_timer_regs *timer;
+ int timerno;
+};
+
+struct gptimer_watchdog_priv bsp_watchdogs[1];
+int bsp_watchdog_count = 0;
+
+int bsp_watchdog_init(void)
+{
+ int timercnt;
+
+ if (!LEON3_Timer_Regs)
+ return 0;
+
+ /* Get Watchdogs in system, this is implemented for one GPTIMER core
+ * only.
+ *
+ * First watchdog is a special case, we can get the first timer core by
+ * looking at LEON3_Timer_Regs, the watchdog within a timer core is
+ * always the last timer. Unfortunately we can not know it the watchdog
+ * functionality is available or not, we assume that it is if we
+ * reached this function.
+ */
+ bsp_watchdogs[0].regs = (struct gptimer_regs *)LEON3_Timer_Regs;
+
+ /* Find Timer that has watchdog functionality */
+ timercnt = bsp_watchdogs[0].regs->cfg & 0x7;
+ if (timercnt < 2) /* First timer system clock timer */
+ return 0;
+
+ bsp_watchdogs[0].timerno = timercnt - 1;
+ bsp_watchdogs[0].timer = &bsp_watchdogs[0].regs->timer[bsp_watchdogs[0].timerno];
+
+ bsp_watchdog_count = 1;
+ return bsp_watchdog_count;
+}
+
+void bsp_watchdog_reload(int watchdog, unsigned int reload_value)
+{
+ if (bsp_watchdog_count == 0)
+ bsp_watchdog_init();
+
+ if (bsp_watchdog_count <= watchdog)
+ return;
+
+ /* Kick watchdog, and clear interrupt pending bit */
+ bsp_watchdogs[watchdog].timer->reload = reload_value;
+ bsp_watchdogs[watchdog].timer->ctrl =
+ (LEON3_GPTIMER_LD | LEON3_GPTIMER_EN) |
+ (bsp_watchdogs[watchdog].timer->ctrl & ~(1<<4));
+}
+
+void bsp_watchdog_stop(int watchdog)
+{
+ if (bsp_watchdog_count == 0)
+ bsp_watchdog_init();
+
+ if (bsp_watchdog_count <= watchdog)
+ return;
+
+ /* Stop watchdog timer */
+ bsp_watchdogs[watchdog].timer->ctrl = 0;
+}
+
+/* Use watchdog timer to reset system */
+void bsp_watchdog_system_reset(void)
+{
+ sparc_disable_interrupts();
+ bsp_watchdog_reload(0, 1);
+}
diff --git a/c/src/lib/libbsp/sparc/shared/1553/b1553brm.c b/c/src/lib/libbsp/sparc/shared/1553/b1553brm.c
index 5eac447450..ca81a929a6 100644
--- a/c/src/lib/libbsp/sparc/shared/1553/b1553brm.c
+++ b/c/src/lib/libbsp/sparc/shared/1553/b1553brm.c
@@ -1,51 +1,23 @@
/*
- * BRM driver
+ * BRM driver
*
- * COPYRIGHT (c) 2006.
- * Gaisler Research.
+ * COPYRIGHT (c) 2008.
+ * Aeroflex Gaisler.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
*
+ * 2008-12-10, Daniel Hellstrom <daniel@gaisler.com>
+ * Converted to support driver manager
*/
/********** Set defaults **********/
-/* basic bus/interface of device,
- * Default to direct accessed AMBA bus.
- */
-#ifndef B1553BRM_NO_AMBA
- #define B1553BRM_AMBA
- #undef B1553BRM_PCI
-#endif
-
-/* default name to /dev/brm */
-#if !defined(B1553BRM_DEVNAME) || !defined(B1553BRM_DEVNAME_NO)
- #undef B1553BRM_DEVNAME
- #undef B1553BRM_DEVNAME_NO
- #define B1553BRM_DEVNAME "/dev/brm0"
- #define B1553BRM_DEVNAME_NO(devstr,no) ((devstr)[8]='0'+(no))
-#endif
-
-#ifndef B1553BRM_PREFIX
- #define B1553BRM_PREFIX(name) b1553brm##name
-#endif
-
-/* default to no translation */
-#ifndef B1553BRM_ADR_TO
- #define memarea_to_hw(x) ((unsigned int)(x))
-#endif
-
-#ifndef B1553BRM_REG_INT
- #define B1553BRM_REG_INT(handler,irqno,arg) set_vector(handler,(irqno)+0x10,1)
- #undef B1553BRM_DEFINE_INTHANDLER
- #define B1553BRM_DEFINE_INTHANDLER
-#endif
-
-/* default to 128K memory layout */
-#if !defined(DMA_MEM_16K)
- #define DMA_MEM_128K
+/* default to 16K memory layout */
+#define DMA_MEM_128K
+#if !defined(DMA_MEM_128K)
+ #define DMA_MEM_16K
#endif
#include <bsp.h>
@@ -57,8 +29,10 @@
#include <ctype.h>
#include <rtems/bspIo.h>
+#include <drvmgr/drvmgr.h>
#include <b1553brm.h>
#include <ambapp.h>
+#include <drvmgr/ambapp_bus.h>
/* Uncomment for debug output */
/*#define DEBUG 1
@@ -68,28 +42,28 @@
/* EVENT_QUEUE_SIZE sets the size of the event queue
*/
-#define EVENT_QUEUE_SIZE 1024
+#define EVENT_QUEUE_SIZE 1024
#define INDEX(x) ( x&(EVENT_QUEUE_SIZE-1) )
-#ifdef DEBUG
+#if 0
#define DBG(x...) printk(x)
#else
-#define DBG(x...)
+#define DBG(x...)
#endif
#ifdef FUNCDEBUG
#define FUNCDBG(x...) printk(x)
#else
-#define FUNCDBG(x...)
+#define FUNCDBG(x...)
#endif
-#define READ_REG(address) _BRM_REG_READ16((unsigned int)address)
+#define READ_REG(address) (*(volatile unsigned int *)address)
#define READ_DMA(address) _BRM_REG_READ16((unsigned int)address)
static __inline__ unsigned short _BRM_REG_READ16(unsigned int addr) {
unsigned short tmp;
- asm(" lduha [%1]1, %0 "
+ __asm__(" lduha [%1]1, %0 "
: "=r"(tmp)
: "r"(addr)
);
@@ -105,7 +79,7 @@ static rtems_device_driver brm_control(rtems_device_major_number major, rtems_de
#define BRM_DRIVER_TABLE_ENTRY { brm_initialize, brm_open, brm_close, brm_read, brm_write, brm_control }
-static rtems_driver_address_table brm_driver = BRM_DRIVER_TABLE_ENTRY;
+static rtems_driver_address_table b1553brm_driver = BRM_DRIVER_TABLE_ENTRY;
struct msg {
unsigned short miw;
@@ -132,165 +106,450 @@ struct irq_log_list {
volatile unsigned short iaw;
};
-typedef struct {
-
- unsigned int memarea_base;
- struct brm_reg *regs;
-
- /* BRM descriptors */
- struct desc_table {
-
- volatile unsigned short ctrl;
- volatile unsigned short top;
- volatile unsigned short cur;
- volatile unsigned short bot;
-
- } *desc;
-
- volatile unsigned short *mem;
- /* bc mem struct */
+typedef struct {
+
+ struct drvmgr_dev *dev; /* Driver manager device */
+ char devName[32]; /* Device Name */
+ struct brm_reg *regs;
+
+ unsigned int memarea_base;
+ unsigned int memarea_base_remote;
+ unsigned int cfg_clksel;
+ unsigned int cfg_clkdiv;
+ unsigned int cfg_freq;
+
+ /* BRM descriptors */
+ struct desc_table {
+ volatile unsigned short ctrl;
+ volatile unsigned short top;
+ volatile unsigned short cur;
+ volatile unsigned short bot;
+ } *desc;
+
+ volatile unsigned short *mem;
+ /* bc mem struct */
+ struct {
+ /* BC Descriptors */
+ struct {
+ unsigned short ctrl; /* control */
+ unsigned short cw1; /* Command word 1*/
+ unsigned short cw2; /* Command word 1*/
+ unsigned short dptr; /* Data pointer in halfword offset from bcmem */
+ unsigned short tsw[2]; /* status word 1 & 2 */
+ unsigned short ba; /* branch address */
+ unsigned short timer; /* timer value */
+ } descs[128]; /* 2k (1024 half words) */
+
+ /* message data */
struct {
- /* BC Descriptors */
- struct {
- unsigned short ctrl; /* control */
- unsigned short cw1; /* Command word 1*/
- unsigned short cw2; /* Command word 1*/
- unsigned short dptr; /* Data pointer in halfword offset from bcmem */
- unsigned short tsw[2]; /* status word 1 & 2 */
- unsigned short ba; /* branch address */
- unsigned short timer; /* timer value */
- } descs[128]; /* 2k (1024 half words) */
-
- /* message data */
- struct {
- unsigned short data[32]; /* 1 message's data */
- } msg_data[128]; /* 8k */
+ unsigned short data[32]; /* 1 message's data */
+ } msg_data[128]; /* 8k */
#if defined(DMA_MEM_128K)
- /* offset to last 64bytes of 128k */
- unsigned short unused[(64*1024-(128*8+128*32))-16*2];
+ /* offset to last 64bytes of 128k */
+ unsigned short unused[(64*1024-(128*8+128*32))-16*2];
#elif defined(DMA_MEM_16K)
- unsigned short unused[(8*1024-(128*8+128*32))-16*2];
+ unsigned short unused[(8*1024-(128*8+128*32))-16*2];
#endif
- /* interrupt log at 64 bytes from end */
- struct irq_log_list irq_logs[16];
- } *bcmem;
+ /* interrupt log at 64 bytes from end */
+ struct irq_log_list irq_logs[16];
+ } *bcmem;
#if defined(DMA_MEM_128K)
- /* Memory structure of a RT being inited, just used
- * for RT initialization.
- *
- * *mesgs[32] fit each minimally 8 messages per sub address.
- */
- struct {
- /* RX Sub Address descriptors */
- struct desc_table rxsubs[32];
- /* TX Sub Address descriptors */
- struct desc_table txsubs[32];
- /* RX mode code descriptors */
- struct desc_table rxmodes[32];
- /* TX mode code descriptors */
- struct desc_table txmodes[32];
-
- /* RX Sub Address messages */
- struct circ_buf rxsuba_msgs[32];
- /* TX Sub Address messages */
- struct circ_buf txsuba_msgs[32];
- /* RX Mode Code messages */
- struct circ_buf rxmode_msgs[32];
- /* RX Mode Code messages */
- struct circ_buf txmode_msgs[32];
-
-
- /* offset to last 64bytes of 128k: tot-used-needed */
- unsigned short unused[(64*1024-(4*32*4+4*32*9*34))-16*2];
-
- /* interrupt log at 64 bytes from end */
- struct irq_log_list irq_logs[16];
- } *rtmem;
+ /* Memory structure of a RT being inited, just used
+ * for RT initialization.
+ *
+ * *mesgs[32] fit each minimally 8 messages per sub address.
+ */
+ struct {
+ /* RX Sub Address descriptors */
+ struct desc_table rxsubs[32];
+ /* TX Sub Address descriptors */
+ struct desc_table txsubs[32];
+ /* RX mode code descriptors */
+ struct desc_table rxmodes[32];
+ /* TX mode code descriptors */
+ struct desc_table txmodes[32];
+
+ /* RX Sub Address messages */
+ struct circ_buf rxsuba_msgs[32];
+ /* TX Sub Address messages */
+ struct circ_buf txsuba_msgs[32];
+ /* RX Mode Code messages */
+ struct circ_buf rxmode_msgs[32];
+ /* RX Mode Code messages */
+ struct circ_buf txmode_msgs[32];
+
+ /* offset to last 64bytes of 128k: tot-used-needed */
+ unsigned short unused[(64*1024-(4*32*4+4*32*9*34))-16*2];
+
+ /* interrupt log at 64 bytes from end */
+ struct irq_log_list irq_logs[16];
+ } *rtmem;
#elif defined(DMA_MEM_16K)
- /* Memory structure of a RT being inited, just used
- * for RT initialization.
- *
- * circ_buf_2 *mesgs[32] fit each minimally 2 messages per queue.
- * circ_buf_1 *mesgs[32] fit each minimally 1 messages per queue.
- */
- struct {
- /* RX Sub Address descriptors */
- struct desc_table rxsubs[32];
- /* TX Sub Address descriptors */
- struct desc_table txsubs[32];
- /* RX mode code descriptors */
- struct desc_table rxmodes[32];
- /* TX mode code descriptors */
- struct desc_table txmodes[32];
-
- /* RX Sub Address messages */
- struct circ_buf_2 rxsuba_msgs[32];
- /* TX Sub Address messages */
- struct circ_buf_2 txsuba_msgs[32];
- /* RX Mode Code messages */
- struct circ_buf_2 rxmode_msgs[32];
- /* RX Mode Code messages */
- struct circ_buf_1 txmode_msgs[32];
-
-
- /* offset to last 64bytes of 16k: tot-used-needed */
- unsigned short unused[8*1024 -(4*32*4 +3*32*2*34 +1*32*1*34) -16*2];
-
- /* interrupt log at 64 bytes from end */
- struct irq_log_list irq_logs[16];
- } *rtmem;
+ /* Memory structure of a RT being inited, just used
+ * for RT initialization.
+ *
+ * circ_buf_2 *mesgs[32] fit each minimally 2 messages per queue.
+ * circ_buf_1 *mesgs[32] fit each minimally 1 messages per queue.
+ */
+ struct {
+ /* RX Sub Address descriptors */
+ struct desc_table rxsubs[32];
+ /* TX Sub Address descriptors */
+ struct desc_table txsubs[32];
+ /* RX mode code descriptors */
+ struct desc_table rxmodes[32];
+ /* TX mode code descriptors */
+ struct desc_table txmodes[32];
+
+ /* RX Sub Address messages */
+ struct circ_buf_2 rxsuba_msgs[32];
+ /* TX Sub Address messages */
+ struct circ_buf_2 txsuba_msgs[32];
+ /* RX Mode Code messages */
+ struct circ_buf_2 rxmode_msgs[32];
+ /* RX Mode Code messages */
+ struct circ_buf_1 txmode_msgs[32];
+
+ /* offset to last 64bytes of 16k: tot-used-needed */
+ unsigned short unused[8*1024 -(4*32*4 +3*32*2*34 +1*32*1*34) -16*2];
+
+ /* interrupt log at 64 bytes from end */
+ struct irq_log_list irq_logs[16];
+ } *rtmem;
#else
#error You must define one DMA_MEM_???K
#endif
- /* Interrupt log list */
- struct irq_log_list *irq_log;
- unsigned int irq;
+ /* Interrupt log list */
+ struct irq_log_list *irq_log;
+ unsigned int irq;
- /* Received events waiting to be read */
- struct rt_msg *rt_event;
- struct bm_msg *bm_event;
+ /* Received events waiting to be read */
+ struct rt_msg *rt_event;
+ struct bm_msg *bm_event;
- unsigned int head, tail;
+ unsigned int head, tail;
- unsigned int last_read[128];
- unsigned int written[32];
+ unsigned int last_read[128];
+ unsigned int written[32];
- struct bc_msg *cur_list;
+ struct bc_msg *cur_list;
- int tx_blocking, rx_blocking;
+ int tx_blocking, rx_blocking;
- rtems_id rx_sem, tx_sem, dev_sem;
- int minor;
- int irqno;
- unsigned int mode;
-#ifdef DEBUG
- unsigned int log[EVENT_QUEUE_SIZE*4];
- unsigned int log_i;
+ rtems_id rx_sem, tx_sem, dev_sem;
+ int minor;
+ int irqno;
+ unsigned int mode;
+#ifdef DEBUG
+ unsigned int log[EVENT_QUEUE_SIZE*4];
+ unsigned int log_i;
#endif
- rtems_id event_id; /* event that may be signalled upon errors, needs to be set through ioctl command BRM_SET_EVENTID */
- unsigned int status;
- int bc_list_fail;
+ rtems_id event_id; /* event that may be signalled upon errors, needs to be set through ioctl command BRM_SET_EVENTID */
+ unsigned int status;
+ int bc_list_fail;
} brm_priv;
-static int brm_cores;
-static unsigned int allbrm_memarea;
-static brm_priv *brms;
-static amba_confarea_type *amba_bus;
-static unsigned int allbrm_cfg_clksel;
-static unsigned int allbrm_cfg_clkdiv;
-static unsigned int allbrm_cfg_freq;
-
-static void brm_interrupt(brm_priv *brm);
-#ifdef B1553BRM_DEFINE_INTHANDLER
-static void b1553brm_interrupt_handler(rtems_vector_number v);
-#endif
+static void b1553brm_interrupt(void *arg);
+static rtems_device_driver rt_init(brm_priv *brm);
#define OFS(ofs) (((unsigned int)&ofs & 0x1ffff)>>1)
+static int b1553brm_driver_io_registered = 0;
+static rtems_device_major_number b1553brm_driver_io_major = 0;
+
+/******************* Driver manager interface ***********************/
+
+/* Driver prototypes */
+int b1553brm_register_io(rtems_device_major_number *m);
+int b1553brm_device_init(brm_priv *pDev);
+
+int b1553brm_init2(struct drvmgr_dev *dev);
+int b1553brm_init3(struct drvmgr_dev *dev);
+int b1553brm_remove(struct drvmgr_dev *dev);
+
+struct drvmgr_drv_ops b1553brm_ops =
+{
+ .init = {NULL, b1553brm_init2, b1553brm_init3, NULL},
+ .remove = b1553brm_remove,
+ .info = NULL
+};
+
+struct amba_dev_id b1553brm_ids[] =
+{
+ {VENDOR_GAISLER, GAISLER_B1553BRM},
+ {0, 0} /* Mark end of table */
+};
+
+struct amba_drv_info b1553brm_drv_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_AMBAPP_GAISLER_B1553BRM_ID, /* Driver ID */
+ "B1553BRM_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */
+ &b1553brm_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ 0,
+ },
+ &b1553brm_ids[0]
+};
+
+void b1553brm_register_drv (void)
+{
+ DBG("Registering B1553BRM driver\n");
+ drvmgr_drv_register(&b1553brm_drv_info.general);
+}
+
+int b1553brm_init2(struct drvmgr_dev *dev)
+{
+ brm_priv *priv;
+
+ DBG("B1553BRM[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
+ priv = dev->priv = malloc(sizeof(brm_priv));
+ if ( !priv )
+ return DRVMGR_NOMEM;
+ memset(priv, 0, sizeof(*priv));
+ priv->dev = dev;
+
+ /* This core will not find other cores, so we wait for init2() */
+
+ return DRVMGR_OK;
+}
+
+int b1553brm_init3(struct drvmgr_dev *dev)
+{
+ brm_priv *priv;
+ char prefix[32];
+ rtems_status_code status;
+
+ priv = dev->priv;
+
+ /* Do initialization */
+
+ if ( b1553brm_driver_io_registered == 0) {
+ /* Register the I/O driver only once for all cores */
+ if ( b1553brm_register_io(&b1553brm_driver_io_major) ) {
+ /* Failed to register I/O driver */
+ dev->priv = NULL;
+ return DRVMGR_FAIL;
+ }
+
+ b1553brm_driver_io_registered = 1;
+ }
+
+ /* I/O system registered and initialized
+ * Now we take care of device initialization.
+ */
+
+ if ( b1553brm_device_init(priv) ) {
+ return DRVMGR_FAIL;
+ }
+
+ /* Get Filesystem name prefix */
+ prefix[0] = '\0';
+ if ( drvmgr_get_dev_prefix(dev, prefix) ) {
+ /* Failed to get prefix, make sure of a unique FS name
+ * by using the driver minor.
+ */
+ sprintf(priv->devName, "/dev/b1553brm%d", dev->minor_drv);
+ } else {
+ /* Got special prefix, this means we have a bus prefix
+ * And we should use our "bus minor"
+ */
+ sprintf(priv->devName, "/dev/%sb1553brm%d", prefix, dev->minor_bus);
+ }
+
+ /* Register Device */
+ status = rtems_io_register_name(priv->devName, b1553brm_driver_io_major, dev->minor_drv);
+ if (status != RTEMS_SUCCESSFUL) {
+ return DRVMGR_FAIL;
+ }
+
+ return DRVMGR_OK;
+}
+
+int b1553brm_remove(struct drvmgr_dev *dev)
+{
+ /* Stop more tasks to open driver */
+
+ /* Throw out all tasks using this driver */
+
+ /* Unregister I/O node */
+
+ /* Unregister and disable Interrupt */
+
+ /* Free device memory */
+
+ /* Return sucessfully */
+
+ return DRVMGR_OK;
+}
+
+/******************* Driver Implementation ***********************/
+
+int b1553brm_register_io(rtems_device_major_number *m)
+{
+ rtems_status_code r;
+
+ if ((r = rtems_io_register_driver(0, &b1553brm_driver, m)) == RTEMS_SUCCESSFUL) {
+ DBG("B1553BRM driver successfully registered, major: %d\n", *m);
+ } else {
+ switch(r) {
+ case RTEMS_TOO_MANY:
+ printk("B1553BRM rtems_io_register_driver failed: RTEMS_TOO_MANY\n");
+ return -1;
+ case RTEMS_INVALID_NUMBER:
+ printk("B1553BRM rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n");
+ return -1;
+ case RTEMS_RESOURCE_IN_USE:
+ printk("B1553BRM rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n");
+ return -1;
+ default:
+ printk("B1553BRM rtems_io_register_driver failed\n");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int b1553brm_device_init(brm_priv *pDev)
+{
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
+ union drvmgr_key_value *value;
+ char *mem;
+
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)pDev->dev->businfo;
+ if ( ambadev == NULL ) {
+ return -1;
+ }
+ pnpinfo = &ambadev->info;
+ pDev->irqno = pnpinfo->irq;
+ /* Two versions of the BRM core. One where the registers are accessed using the AHB bus
+ * and one where the APB bus is used
+ */
+ if ( pnpinfo->ahb_slv ) {
+ /* Registers accessed over AHB */
+ pDev->regs = (struct brm_reg *)pnpinfo->ahb_slv->start[0];
+ } else {
+ /* Registers accessed over APB */
+ pDev->regs = (struct brm_reg *)pnpinfo->apb_slv->start;
+ }
+ pDev->minor = pDev->dev->minor_drv;
+#ifdef DEBUG
+ pDev->log_i = 0;
+ memset(pDev->log,0,sizeof(pDev->log));
+#endif
+
+ /* Get memory configuration from bus resources */
+ value = drvmgr_dev_key_get(pDev->dev, "dmaBaseAdr", KEY_TYPE_POINTER);
+ if ( value ) {
+ mem = value->ptr;
+ if ( (unsigned int)mem & 1 ) {
+ /* Remote address, address as BRM looks at it. */
+
+ /* Translate the base address into an address that the the CPU can understand */
+ mem = (char *)((unsigned int)mem & ~1);
+ drvmgr_translate(pDev->dev, 1, 1, (void *)mem, (void **)&mem);
+ }
+ } else {
+ /* Use dynamically allocated memory */
+ mem = (char *)malloc(128 * 1024 * 2); /* 128k DMA memory + 128k for alignment */
+ if ( !mem ){
+ printk("BRM: Failed to allocate HW memory\n\r");
+ return -1;
+ }
+ }
+ /* align memory to 128k boundary */
+ mem = (char *)(((unsigned int)mem+0x1ffff) & ~0x1ffff);
+
+ /* clear the used memory */
+#ifdef DMA_MEM_128K
+ memset(mem, 0, (128 * 1024));
+#else
+ memset(mem, 0, (16 * 1024));
+#endif
+
+ /* Set base address of all descriptors */
+ pDev->memarea_base = (unsigned int)mem;
+ pDev->desc = (struct desc_table *) pDev->memarea_base;
+ pDev->mem = (volatile unsigned short *) pDev->memarea_base;
+ pDev->irq_log = (struct irq_log_list *)(pDev->memarea_base + (0xFFE0<<1)); /* last 64byte */
+
+ /* Translate the base address into an address that the BRM core can understand */
+ drvmgr_translate(pDev->dev, 0, 0, (void *)mem, (void **)&pDev->memarea_base_remote);
+
+ pDev->bm_event = NULL;
+ pDev->rt_event = NULL;
+
+ pDev->cfg_clksel = 0;
+ pDev->cfg_clkdiv = 0;
+ pDev->cfg_freq = BRM_FREQ_24MHZ;
+
+ value = drvmgr_dev_key_get(pDev->dev, "clkSel", KEY_TYPE_INT);
+ if ( value ) {
+ pDev->cfg_clksel = value->i & CLKSEL_MASK;
+ }
+
+ value = drvmgr_dev_key_get(pDev->dev, "clkDiv", KEY_TYPE_INT);
+ if ( value ) {
+ pDev->cfg_clkdiv = value->i & CLKDIV_MASK;
+ }
+
+ value = drvmgr_dev_key_get(pDev->dev, "coreFreq", KEY_TYPE_INT);
+ if ( value ) {
+ pDev->cfg_freq = value->i & BRM_FREQ_MASK;
+ }
+
+ /* Sel clock so that we can write to BRM's registers */
+ pDev->regs->w_ctrl = (pDev->cfg_clksel<<9) | (pDev->cfg_clkdiv<<5);
+ /* Reset BRM core */
+ pDev->regs->w_ctrl = 1<<10 | READ_REG(&pDev->regs->w_ctrl);
+
+ /* RX Semaphore created with count = 0 */
+ if ( rtems_semaphore_create(rtems_build_name('B', 'M', 'R', '0' + pDev->minor),
+ 0,
+ RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &pDev->rx_sem) != RTEMS_SUCCESSFUL ) {
+ printk("BRM: Failed to create rx semaphore\n");
+ return RTEMS_INTERNAL_ERROR;
+ }
+
+ /* TX Semaphore created with count = 1 */
+ if ( rtems_semaphore_create(rtems_build_name('B', 'M', 'T', '0' + pDev->minor),
+ 1,
+ RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &pDev->tx_sem) != RTEMS_SUCCESSFUL ){
+ printk("BRM: Failed to create tx semaphore\n");
+ return RTEMS_INTERNAL_ERROR;
+ }
+
+ /* Device Semaphore created with count = 1 */
+ if ( rtems_semaphore_create(rtems_build_name('B', 'M', 'D', '0' + pDev->minor),
+ 1,
+ RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &pDev->dev_sem) != RTEMS_SUCCESSFUL ){
+ printk("BRM: Failed to create device semaphore\n");
+ return RTEMS_INTERNAL_ERROR;
+ }
+
+ /* Default to RT-mode */
+ rt_init(pDev);
+
+ return 0;
+}
+
static int odd_parity(unsigned int data) {
unsigned int i=0;
@@ -298,12 +557,11 @@ static int odd_parity(unsigned int data) {
{
i++;
data &= (data - 1);
- }
+ }
return !(i&1);
}
-
static void start_operation(brm_priv *brm) {
unsigned int ctrl = READ_REG(&brm->regs->ctrl);
brm->regs->ctrl = ctrl | 0x8000;
@@ -318,72 +576,6 @@ static int is_executing(brm_priv *brm) {
return ((ctrl>>15) & 1);
}
-#ifdef LEON3
-#ifndef DONT_DEF_RAMON
-int brm_register_leon3_ramon_fpga(void){
- /* Clock div & Clock sel is NOT available.
- * The BRM is always clocked with 24MHz.
- * 3 in BRM enhanced register will select 24MHz
- */
- return b1553brm_register(&amba_conf,0,0,3);
-}
-
-int brm_register_leon3_ramon_asic(void){
- /* Clock div & Clock sel is available.
- * Clkdiv only matter when clksel is 1.
- * clksel=2, clkdiv=don't care, brm_frq=24MHz
- *
- * 3 in BRM enhanced register will select 24MHz
- */
- return b1553brm_register(&amba_conf,2,0,3);
-}
-#endif
-#endif
-
-int B1553BRM_PREFIX(_register)(amba_confarea_type *bus, unsigned int clksel, unsigned int clkdiv, unsigned int brm_freq)
-{
- rtems_status_code r;
- rtems_device_major_number m;
-
- FUNCDBG("brm_register:\n\r");
-
- /* save amba bus pointer */
- amba_bus = bus;
- if ( !bus ){
- printk("brm_register: bus is NULL\n\r");
- return 1;
- }
-
-#ifdef B1553BRM_LOCAL_MEM
- allbrm_memarea = B1553BRM_LOCAL_MEM_ADR;
-#else
- allbrm_memarea = 0;
-#endif
-
- /* Save clksel, clkdiv and brm_freq for later use */
- allbrm_cfg_clksel = clksel & CLKSEL_MASK;
- allbrm_cfg_clkdiv = clkdiv & CLKDIV_MASK;
- allbrm_cfg_freq = brm_freq & BRM_FREQ_MASK;
-
- if ((r = rtems_io_register_driver(0, &brm_driver, &m)) == RTEMS_SUCCESSFUL) {
- DBG("BRM: driver successfully registered, major: %d\n",m);
-
- } else {
- switch(r) {
- case RTEMS_TOO_MANY:
- printk("BRM rtems_io_register_driver failed: RTEMS_TOO_MANY\n"); break;
- case RTEMS_INVALID_NUMBER:
- printk("BRM rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n"); break;
- case RTEMS_RESOURCE_IN_USE:
- printk("BRM rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n"); break;
- default:
- printk("BRM rtems_io_register_driver failed\n");
- }
- return 1;
- }
- return 0;
-}
-
static void clr_int_logs(struct irq_log_list *logs){
int i;
for(i=0; i<16; i++){
@@ -398,18 +590,18 @@ static rtems_device_driver rt_init(brm_priv *brm) {
brm->head = brm->tail = 0;
brm->rx_blocking = brm->tx_blocking = 1;
- if ( brm->bm_event )
+ if ( brm->bm_event )
free(brm->bm_event);
brm->bm_event = NULL;
- if ( brm->rt_event )
+ if ( brm->rt_event )
free(brm->rt_event);
-
+
brm->bcmem = NULL;
brm->rtmem = (void *)brm->mem;
brm->rt_event = (struct rt_msg *) malloc(EVENT_QUEUE_SIZE*sizeof(struct rt_msg));
-
+
if (brm->rt_event == NULL) {
DBG("BRM driver failed to allocated memory.");
return RTEMS_NO_MEMORY;
@@ -422,11 +614,11 @@ static rtems_device_driver rt_init(brm_priv *brm) {
brm->regs->imask = BRM_RT_ILLCMD_IRQ|BRM_SUBAD_IRQ|BRM_TAPF_IRQ|BRM_DMAF_IRQ|BRM_WRAPF_IRQ|BRM_MERR_IRQ;
brm->regs->dpoint = 0;
brm->regs->ipoint = OFS(brm->rtmem->irq_logs[0]);
- brm->regs->enhanced = 0x0000 | allbrm_cfg_freq; /* BRM clocked with freq = 12,16,20 or 24MHz */
- brm->regs->w_ctrl = (allbrm_cfg_clksel<<9) | (allbrm_cfg_clkdiv<<5) | 1;
+ brm->regs->enhanced = 0x0000 | brm->cfg_freq; /* BRM clocked with freq = 12,16,20 or 24MHz */
+ brm->regs->w_ctrl = (brm->cfg_clksel<<9) | (brm->cfg_clkdiv<<5) | 1;
brm->regs->w_irqctrl = 6;
- brm->regs->w_ahbaddr = (unsigned int) memarea_to_hw(brm->memarea_base);
-
+ brm->regs->w_ahbaddr = brm->memarea_base_remote;
+
clr_int_logs(brm->irq_log);
/* Legalize all commands */
@@ -434,19 +626,19 @@ static rtems_device_driver rt_init(brm_priv *brm) {
brm->regs->rt_cmd_leg[i] = 0;
}
- /* Init descriptor table
- *
+ /* Init descriptor table
+ *
* Each circular buffer has room for 8 messages with up to 34 (32 data + miw + time) words (16b) in each.
* The buffers must separated by 34 words.
*/
-
+
/* RX Sub-address 0 - 31 */
for (i = 0; i < 32; i++) {
brm->rtmem->rxsubs[i].ctrl = 0x00E0; /* Interrupt: INTX, IWA, and IBRD */
brm->rtmem->rxsubs[i].top = OFS(brm->rtmem->rxsuba_msgs[i]); /* Top address */
brm->rtmem->rxsubs[i].cur = OFS(brm->rtmem->rxsuba_msgs[i]); /* Current address */
- brm->rtmem->rxsubs[i].bot = OFS(brm->rtmem->rxsuba_msgs[i+1]) - sizeof(struct msg)/2; /* Bottom address */
+ brm->rtmem->rxsubs[i].bot = OFS(brm->rtmem->rxsuba_msgs[i+1]) - sizeof(struct msg)/2; /* Bottom address */
brm->last_read[i] = OFS(brm->rtmem->rxsuba_msgs[i]);
}
/* TX Sub-address 0 - 31 */
@@ -465,7 +657,7 @@ static rtems_device_driver rt_init(brm_priv *brm) {
brm->rtmem->rxmodes[i].cur = OFS(brm->rtmem->rxmode_msgs[i]); /* Current address */
brm->rtmem->rxmodes[i].bot = OFS(brm->rtmem->rxmode_msgs[i+1]) - sizeof(struct msg)/2; /* Bottom address */
brm->last_read[i+64] = OFS(brm->rtmem->rxmode_msgs[i]);
- }
+ }
/* TX mode code 0 - 31 */
for (i = 0; i < 32; i++) {
brm->rtmem->txmodes[i].ctrl = 0x0060; /* Interrupt: IWA and IBRD */
@@ -475,6 +667,12 @@ static rtems_device_driver rt_init(brm_priv *brm) {
brm->last_read[i+96] = OFS(brm->rtmem->txmode_msgs[i]);
}
+#ifdef DEBUG
+ printk("b1553BRM DMA_AREA: 0x%x\n", (unsigned int)brm->rtmem);
+ printk("LOG: 0x%x\n", &brm->log[0]);
+ printk("LOG_I: 0x%x\n", &brm->log_i);
+#endif
+
brm->mode = BRM_MODE_RT;
return RTEMS_SUCCESSFUL;
@@ -482,36 +680,35 @@ static rtems_device_driver rt_init(brm_priv *brm) {
static rtems_device_driver bc_init(brm_priv *brm){
- if ( brm->bm_event )
+ if ( brm->bm_event )
free(brm->bm_event);
brm->bm_event = NULL;
- if ( brm->rt_event )
+ if ( brm->rt_event )
free(brm->rt_event);
brm->rt_event = NULL;
-
+
brm->bcmem = (void *)brm->mem;
brm->rtmem = NULL;
brm->irq_log = (struct irq_log_list *)&brm->bcmem->irq_logs[0];
-
+
brm->head = brm->tail = 0;
brm->rx_blocking = brm->tx_blocking = 1;
-
+
brm->regs->ctrl = 0x0006; /* ping pong enable and enable interrupt log */
brm->regs->oper = 0x0800; /* configure as BC */
brm->regs->imask = BRM_EOL_IRQ|BRM_BC_ILLCMD_IRQ|BRM_ILLOP_IRQ|BRM_DMAF_IRQ|BRM_WRAPF_IRQ|BRM_MERR_IRQ;
brm->regs->dpoint = 0;
- printk("Set BC interrupt log: 0x%lx, 0x%lx, 0x%lx\n",OFS(brm->bcmem->irq_logs[0]),&brm->bcmem->irq_logs[0],brm->bcmem);
brm->regs->ipoint = OFS(brm->bcmem->irq_logs[0]);
- brm->regs->enhanced = 0x0000 | (allbrm_cfg_freq&0x3); /* freq = 24 */
- brm->regs->w_ctrl = (allbrm_cfg_clksel<<9) | (allbrm_cfg_clkdiv<<5) | 1;
+ brm->regs->enhanced = 0x0000 | (brm->cfg_freq&BRM_FREQ_MASK); /* freq = 24 */
+ brm->regs->w_ctrl = (brm->cfg_clksel<<9) | (brm->cfg_clkdiv<<5) | 1;
brm->regs->w_irqctrl = 6;
- brm->regs->w_ahbaddr = (unsigned int) memarea_to_hw(brm->memarea_base);
-
+ brm->regs->w_ahbaddr = brm->memarea_base_remote;
+
clr_int_logs(brm->irq_log);
-
+
brm->mode = BRM_MODE_BC;
-
+
return RTEMS_SUCCESSFUL;
}
@@ -521,18 +718,18 @@ static rtems_device_driver bm_init(brm_priv *brm) {
brm->head = brm->tail = 0;
brm->rx_blocking = brm->tx_blocking = 1;
- if ( brm->rt_event )
+ if ( brm->rt_event )
free(brm->rt_event);
brm->rt_event = NULL;
- if ( brm->bm_event )
+ if ( brm->bm_event )
free(brm->bm_event);
-
+
brm->bcmem = NULL;
brm->rtmem = NULL;
-
+
brm->bm_event = (struct bm_msg *) malloc(EVENT_QUEUE_SIZE*sizeof(struct bm_msg));
-
+
if (brm->bm_event == NULL) {
DBG("BRM driver failed to allocated memory.");
return RTEMS_NO_MEMORY;
@@ -543,760 +740,634 @@ static rtems_device_driver bm_init(brm_priv *brm) {
brm->regs->ctrl = 0x0006; /* ping pong enable and enable interrupt log */
brm->regs->oper = 0x0A00; /* configure as BM */
- brm->regs->imask = BRM_MBC_IRQ|BRM_MERR_IRQ|BRM_DMAF_IRQ|BRM_MERR_IRQ;
+ brm->regs->imask = BRM_MBC_IRQ|BRM_MERR_IRQ|BRM_DMAF_IRQ;
brm->regs->dpoint = 0;
brm->regs->ipoint = OFS(brm->mem[8*1024-16*2]);
brm->regs->mcpoint = 0; /* Command pointer */
brm->regs->mdpoint = 0x100; /* Data pointer */
brm->regs->mbc = 1; /* Block count */
- brm->regs->enhanced = 0x0000 | (allbrm_cfg_freq&0x3); /* freq = 24 */
- brm->regs->w_ctrl = (allbrm_cfg_clksel<<9) | (allbrm_cfg_clkdiv<<5) | 1;
+ brm->regs->enhanced = 0x0000 | (brm->cfg_freq&BRM_FREQ_MASK); /* freq = 24 */
+ brm->regs->w_ctrl = (brm->cfg_clksel<<9) | (brm->cfg_clkdiv<<5) | 1;
brm->regs->w_irqctrl = 6;
- brm->regs->w_ahbaddr = (unsigned int) memarea_to_hw(brm->memarea_base);
-
+ brm->regs->w_ahbaddr = brm->memarea_base_remote;
+
clr_int_logs(brm->irq_log);
-
+
brm->mode = BRM_MODE_BM;
-
+
return RTEMS_SUCCESSFUL;
}
static rtems_device_driver brm_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
{
- rtems_status_code status;
- int dev_cnt;
- char fs_name[20];
- brm_priv *brm;
- amba_ahb_device ambadev;
- char *mem;
-
- FUNCDBG("brm_initialize\n");
+ return RTEMS_SUCCESSFUL;
+}
- brm_cores = 0;
- strcpy(fs_name,B1553BRM_DEVNAME);
+static rtems_device_driver brm_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) {
+ brm_priv *brm;
+ struct drvmgr_dev *dev;
- /* Find all BRM devices */
- dev_cnt = amba_get_number_ahbslv_devices(amba_bus,VENDOR_GAISLER,GAISLER_BRM);
- if ( dev_cnt < 1 ){
- /* Failed to find any CAN cores! */
- printk("BRM: Failed to find any BRM cores\n\r");
- return -1;
- }
+ FUNCDBG("brm_open\n");
- /* allocate & zero memory for the brm devices */
- brms = (brm_priv *)malloc(sizeof(*brms)*dev_cnt);
- if ( !brms ){
- printk("BRM: Failed to allocate SW memory\n\r");
- return -1;
+ if ( drvmgr_get_dev(&b1553brm_drv_info.general, minor, &dev) ) {
+ DBG("Wrong minor %d\n", minor);
+ return RTEMS_UNSATISFIED;
}
- memset(brms,0,sizeof(*brms)*dev_cnt);
-
- /* Allocate memory for all device's descriptors,
- * they must be aligned to a XXX byte boundary.
- */
- #define BRM_DESCS_PER_CTRL 128
- if ( allbrm_memarea ){
- mem = (char *)allbrm_memarea;
- }else{
- /* sizeof(struct desc_table) * BRM_DESCS_PER_CTRL * dev_cnt */
- mem = (char *)malloc( (128*1024) * (dev_cnt+1)); /* 128k per core + 128k for alignment */
- if ( !mem ){
- free(brms);
- printk("BRM: Failed to allocate HW memory\n\r");
- return -1;
- }
+ brm = (brm_priv *)dev->priv;
- /* align memory to 128k boundary */
- mem = (char *)(((unsigned int)mem+0x1ffff) & ~0x1ffff);
+ if (rtems_semaphore_obtain(brm->dev_sem, RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT) != RTEMS_SUCCESSFUL) {
+ DBG("brm_open: resource in use\n");
+ return RTEMS_RESOURCE_IN_USE; /* EBUSY */
}
- /* clear the used memory */
- memset(mem,0,(128*1024) * dev_cnt);
-
- /* initialize each brm device, one at a time */
- for(minor=0; minor<dev_cnt; minor++){
- brm = &brms[minor];
+ /* Set defaults */
+ brm->event_id = 0;
- /* Get AMBA AHB device info from Plug&Play */
- amba_find_next_ahbslv(amba_bus,VENDOR_GAISLER,GAISLER_BRM,&ambadev,minor);
+ start_operation(brm);
- /* Copy Basic HW info */
- brm->regs = (void *)ambadev.start[0];
- brm->irqno = ambadev.irq;
- brm->minor = minor;
- brm->irq = 0;
-#ifdef DEBUG
- brm->log_i = 0;
- memset(brm->log,0,sizeof(brm->log));
-#endif
-
- /* Set unique name */
- B1553BRM_DEVNAME_NO(fs_name,minor);
-
- DBG("Registering BRM core at [0x%x] irq %d, minor %d as %s\n",brm->regs,brm->irqno,minor,fs_name);
-
- /* Bind filesystem name to device number (minor) */
- status = rtems_io_register_name(fs_name, major, minor);
- if (status != RTEMS_SUCCESSFUL)
- rtems_fatal_error_occurred(status);
-
- /* RX Semaphore created with count = 0 */
- if ( rtems_semaphore_create(rtems_build_name('B', 'M', 'R', '0'+minor),
- 0,
- RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
- 0,
- &brm->rx_sem) != RTEMS_SUCCESSFUL ){
- printk("BRM: Failed to create rx semaphore\n");
- return RTEMS_INTERNAL_ERROR;
- }
-
- /* TX Semaphore created with count = 1 */
- if ( rtems_semaphore_create(rtems_build_name('B', 'M', 'T', '0'+minor),
- 1,
- RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
- 0,
- &brm->tx_sem) != RTEMS_SUCCESSFUL ){
- printk("BRM: Failed to create tx semaphore\n");
- return RTEMS_INTERNAL_ERROR;
- }
-
- /* Device Semaphore created with count = 1 */
- if ( rtems_semaphore_create(rtems_build_name('B', 'M', 'D', '0'+minor),
- 1,
- RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
- 0,
- &brm->dev_sem) != RTEMS_SUCCESSFUL ){
- printk("BRM: Failed to create device semaphore\n");
- return RTEMS_INTERNAL_ERROR;
- }
-
-
- /* Set base address of all descriptors */
- brm->memarea_base = (unsigned int)&mem[(128*1024) * minor];
- brm->desc = (struct desc_table *) brm->memarea_base;
- brm->mem = (volatile unsigned short *) brm->memarea_base;
- brm->irq_log = (struct irq_log_list *)(brm->memarea_base + (0xFFE0<<1)); /* last 64byte */
-
- brm->bm_event = NULL;
- brm->rt_event = NULL;
-
- /* Sel clock so that we can write to BRM's registers */
- brm->regs->w_ctrl = (allbrm_cfg_clksel<<9) | (allbrm_cfg_clkdiv<<5);
- /* Reset BRM core */
- brm->regs->w_ctrl = 1<<10 | READ_REG(&brm->regs->w_ctrl);
-
- /* Register interrupt handler */
- B1553BRM_REG_INT(B1553BRM_PREFIX(_interrupt_handler), brm->irqno, brm);
-
- rt_init(brm);
-
- DBG("BRM: LOG: 0x%lx, 0x%lx\n\r",brm->log,brm);
+ /* Register interrupt routine */
+ if ( drvmgr_interrupt_register(brm->dev, 0, "b1553brm", b1553brm_interrupt, brm) ) {
+ rtems_semaphore_release(brm->dev_sem);
+ return RTEMS_UNSATISFIED;
}
- /* save number of BRM cores found */
- brm_cores = dev_cnt;
-
- DBG("BRM initialisation done.\n");
-
return RTEMS_SUCCESSFUL;
}
-
-static rtems_device_driver brm_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) {
- brm_priv *brm;
-
- FUNCDBG("brm_open\n");
-
- if (minor >= brm_cores) {
- DBG("Wrong minor %d\n", minor);
- return RTEMS_UNSATISFIED; /* ENODEV */
- }
-
- brm = &brms[minor];
-
- if (rtems_semaphore_obtain(brm->dev_sem, RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT) != RTEMS_SUCCESSFUL) {
- DBG("brm_open: resource in use\n");
- return RTEMS_RESOURCE_IN_USE; /* EBUSY */
- }
-
- /* Set defaults */
- brm->event_id = 0;
-
- start_operation(brm);
-
- return RTEMS_SUCCESSFUL;
-}
-
+
static rtems_device_driver brm_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
{
- brm_priv *brm = &brms[minor];
+ brm_priv *brm;
+ struct drvmgr_dev *dev;
+
FUNCDBG("brm_close");
+
+ if ( drvmgr_get_dev(&b1553brm_drv_info.general, minor, &dev) ) {
+ return RTEMS_UNSATISFIED;
+ }
+ brm = (brm_priv *)dev->priv;
+
+ drvmgr_interrupt_unregister(brm->dev, 0, b1553brm_interrupt, brm);
stop_operation(brm);
rtems_semaphore_release(brm->dev_sem);
return RTEMS_SUCCESSFUL;
}
+
+static int get_rt_messages(brm_priv *brm, void *buf, unsigned int msg_count)
+{
+ struct rt_msg *dest = (struct rt_msg *) buf;
+ int count = 0;
-static int get_rt_messages(brm_priv *brm, void *buf, unsigned int msg_count) {
-
- struct rt_msg *dest = (struct rt_msg *) buf;
- int count = 0;
-
- if (brm->head == brm->tail) {
- return 0;
- }
-
- do {
-
- DBG("rt read - head: %d, tail: %d\n", brm->head, brm->tail);
- dest[count++] = brm->rt_event[INDEX(brm->tail++)];
+ if (brm->head == brm->tail) {
+ return 0;
+ }
- } while (brm->head != brm->tail && count < msg_count);
+ do {
- return count;
+ DBG("rt read - head: %d, tail: %d\n", brm->head, brm->tail);
+ dest[count++] = brm->rt_event[INDEX(brm->tail++)];
+ } while (brm->head != brm->tail && count < msg_count);
+ return count;
}
-static int get_bm_messages(brm_priv *brm, void *buf, unsigned int msg_count) {
-
- struct bm_msg *dest = (struct bm_msg *) buf;
- int count = 0;
-
- if (brm->head == brm->tail) {
- return 0;
- }
+static int get_bm_messages(brm_priv *brm, void *buf, unsigned int msg_count)
+{
+ struct bm_msg *dest = (struct bm_msg *) buf;
+ int count = 0;
- do {
+ if (brm->head == brm->tail) {
+ return 0;
+ }
- DBG("bm read - head: %d, tail: %d\n", brm->head, brm->tail);
- dest[count++] = brm->bm_event[INDEX(brm->tail++)];
+ do {
- } while (brm->head != brm->tail && count < msg_count);
+ DBG("bm read - head: %d, tail: %d\n", brm->head, brm->tail);
+ dest[count++] = brm->bm_event[INDEX(brm->tail++)];
- return count;
+ } while (brm->head != brm->tail && count < msg_count);
+ return count;
}
static rtems_device_driver brm_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
{
- rtems_libio_rw_args_t *rw_args;
- int count = 0;
- brm_priv *brm = &brms[minor];
- int (*get_messages)(brm_priv *brm, void *buf, unsigned int count);
-
- if ( ! (brm->mode & (BRM_MODE_RT | BRM_MODE_BM)) ){
- return RTEMS_INVALID_NAME;
- }
-
- rw_args = (rtems_libio_rw_args_t *) arg;
-
- if ( ((READ_REG(&brm->regs->oper)>>8) & 3) == 1 ) { /* RT */
- get_messages = get_rt_messages;
- }
- else { /* BM */
- get_messages = get_bm_messages;
- }
+ rtems_libio_rw_args_t *rw_args;
+ int count = 0;
+ brm_priv *brm;
+ struct drvmgr_dev *dev;
+ int (*get_messages)(brm_priv *brm, void *buf, unsigned int count);
+ if ( drvmgr_get_dev(&b1553brm_drv_info.general, minor, &dev) ) {
+ return RTEMS_UNSATISFIED;
+ }
+ brm = (brm_priv *)dev->priv;
- FUNCDBG("brm_read [%i,%i]: buf: 0x%x len: %i\n",major, minor, (unsigned int)rw_args->buffer,rw_args->count);
+ if ( ! (brm->mode & (BRM_MODE_RT | BRM_MODE_BM)) ){
+ return RTEMS_INVALID_NAME;
+ }
- while ( (count=get_messages(brm,rw_args->buffer, rw_args->count)) == 0 ) {
+ rw_args = (rtems_libio_rw_args_t *) arg;
- if (brm->rx_blocking) {
- rtems_semaphore_obtain(brm->rx_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
- }
- else {
- /* Translates to EBUSY */
- return RTEMS_RESOURCE_IN_USE;
- }
+ if ( ((READ_REG(&brm->regs->oper)>>8) & 3) == 1 ) { /* RT */
+ get_messages = get_rt_messages;
+ } else { /* BM */
+ get_messages = get_bm_messages;
+ }
- }
+ FUNCDBG("brm_read [%i,%i]: buf: 0x%x len: %i\n",major, minor, (unsigned int)rw_args->buffer,rw_args->count);
- rw_args->bytes_moved = count;
- return RTEMS_SUCCESSFUL;
+ while ( (count=get_messages(brm,rw_args->buffer, rw_args->count)) == 0 ) {
+ if (brm->rx_blocking) {
+ rtems_semaphore_obtain(brm->rx_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+ } else {
+ /* Translates to EBUSY */
+ return RTEMS_RESOURCE_IN_USE;
+ }
+ }
+ rw_args->bytes_moved = count;
+ return RTEMS_SUCCESSFUL;
}
-
static rtems_device_driver brm_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
{
- rtems_libio_rw_args_t *rw_args;
- struct rt_msg *source;
- unsigned int count=0, current, next, descriptor, wc, suba;
- brm_priv *brm = &brms[minor];
-
- if ( ! (brm->mode & BRM_MODE_RT) ){
- return RTEMS_INVALID_NAME;
- }
-
- rw_args = (rtems_libio_rw_args_t *) arg;
- source = (struct rt_msg *) rw_args->buffer;
-
- FUNCDBG("brm_write [%i,%i]: buf: 0x%x len: %i\n",major, minor, (unsigned int)rw_args->buffer,rw_args->count);
+ rtems_libio_rw_args_t *rw_args;
+ struct rt_msg *source;
+ unsigned int count=0, current, next, descriptor, wc, suba;
+ brm_priv *brm;
+ struct drvmgr_dev *dev;
+
+ if ( drvmgr_get_dev(&b1553brm_drv_info.general, minor, &dev) ) {
+ return RTEMS_UNSATISFIED;
+ }
+ brm = (brm_priv *)dev->priv;
+
+ if ( ! (brm->mode & BRM_MODE_RT) ){
+ return RTEMS_INVALID_NAME;
+ }
+
+ rw_args = (rtems_libio_rw_args_t *) arg;
+ source = (struct rt_msg *) rw_args->buffer;
- do {
+ FUNCDBG("brm_write [%i,%i]: buf: 0x%x len: %i\n",major, minor, (unsigned int)rw_args->buffer,rw_args->count);
- descriptor = source[count].desc & 0x7F;
- suba = descriptor-32;
- wc = source[count].miw >> 11;
- wc = wc ? wc : 32;
+ do {
- /* Only subaddress transmission is allowed with write */
- if (descriptor < 32 || descriptor >= 64)
- return RTEMS_INVALID_NAME;
+ descriptor = source[count].desc & 0x7F;
+ suba = descriptor-32;
+ wc = source[count].miw >> 11;
+ wc = wc ? wc : 32;
- current = brm->desc[descriptor].cur;
- next = brm->written[suba] + 2 + wc;
+ /* Only subaddress transmission is allowed with write */
+ if (descriptor < 32 || descriptor >= 64)
+ return RTEMS_INVALID_NAME;
- if (brm->written[suba] < current) {
+ current = brm->desc[descriptor].cur;
+ next = brm->written[suba] + 2 + wc;
- if (next > current) {
+ if (brm->written[suba] < current) {
- /* No room in transmission buffer */
+ if (next > current) {
- if (brm->tx_blocking && count == 0) {
- rtems_semaphore_obtain(brm->tx_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
- }
- else if ( brm->tx_blocking && (count != 0) ){
- /* return the number of messages sent so far */
- break;
- }
- else {
- /* Translates to posix EBUSY */
- return RTEMS_RESOURCE_IN_USE;
- }
- }
- }
+ /* No room in transmission buffer */
+ if (brm->tx_blocking && count == 0) {
+ rtems_semaphore_obtain(brm->tx_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+ } else if ( count > 0 ) {
+ /* return the number of messages sent so far */
+ break;
+ } else {
+ /* Translates to posix EBUSY */
+ return RTEMS_RESOURCE_IN_USE;
+ }
+ }
+ }
- memcpy((void *)&brm->mem[brm->written[suba]], &source[count], (2+wc)*2);
+ memcpy((void *)&brm->mem[brm->written[suba]], &source[count], (2+wc)*2);
- count++;
+ count++;
- if (next >= brm->desc[descriptor].bot) {
- next = brm->desc[descriptor].top;
- }
- brm->written[suba] = next;
+ if (next >= brm->desc[descriptor].bot) {
+ next = brm->desc[descriptor].top;
+ }
+ brm->written[suba] = next;
- } while (count < rw_args->count);
+ } while (count < rw_args->count);
- rw_args->bytes_moved = count;
+ rw_args->bytes_moved = count;
- if (count >= 0) {
- return RTEMS_SUCCESSFUL;
- }
- return RTEMS_UNSATISFIED;
+ if (count >= 0) {
+ return RTEMS_SUCCESSFUL;
+ }
+ return RTEMS_UNSATISFIED;
}
static rtems_device_driver brm_control(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
{
+
+ unsigned int i=0;
+ unsigned short ctrl, oper, cw1, cw2;
+ rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *) arg;
+ unsigned int *data = ioarg->buffer;
+ struct bc_msg *cmd_list = (struct bc_msg *) ioarg->buffer;
+ brm_priv *brm;
+ struct drvmgr_dev *dev;
+ rtems_device_driver ret;
+ int len, msglen;
+
+ FUNCDBG("brm_control[%d]: [%i,%i]\n", minor, major, minor);
+
+ if ( drvmgr_get_dev(&b1553brm_drv_info.general, minor, &dev) ) {
+ return RTEMS_UNSATISFIED;
+ }
+ brm = (brm_priv *)dev->priv;
- unsigned int i=0;
- unsigned short ctrl, oper, cw1, cw2;
- rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *) arg;
- unsigned int *data = ioarg->buffer;
- struct bc_msg *cmd_list = (struct bc_msg *) ioarg->buffer;
- brm_priv *brm = &brms[minor];
- rtems_device_driver ret;
- int len;
-
- FUNCDBG("brm_control[%d]: [%i,%i]\n",minor,major, minor);
-
- if (!ioarg) {
- DBG("brm_control: invalid argument\n");
- return RTEMS_INVALID_NAME;
- }
-
- ioarg->ioctl_return = 0;
- switch(ioarg->command) {
-
- case BRM_SET_MODE:
- if ( data[0] > 2 )
- return RTEMS_INVALID_NAME;
- stop_operation(brm);
- if (data[0] == 0) {
- ret = bc_init(brm);
- }
- else if (data[0] == 1) {
- ret = rt_init(brm);
- }
- else if (data[0] == 2) {
- ret = bm_init(brm);
- }else
- ret = RTEMS_INVALID_NAME;
-
- if ( ret != RTEMS_SUCCESSFUL)
- return ret;
-
- if ( brm->mode & (BRM_MODE_RT | BRM_MODE_BM ) )
- start_operation(brm);
- break;
-
- case BRM_SET_BUS:
- stop_operation(brm);
- ctrl = READ_REG(&brm->regs->ctrl);
- ctrl &= 0xE7FF; /* Clear bit 12-11 ... */
- ctrl |= (data[0]&0x3)<<11; /* ... OR in new bus status */
- brm->regs->ctrl = ctrl;
- start_operation(brm);
- break;
-
- case BRM_SET_MSGTO:
- stop_operation(brm);
- ctrl = READ_REG(&brm->regs->ctrl);
- ctrl &= 0xFDFF; /* Clear bit 9 ... */
- ctrl |= (data[0]&1)<<9; /* ... OR in new MSGTO */
- brm->regs->ctrl = ctrl;
- start_operation(brm);
- break;
-
- case BRM_SET_RT_ADDR:
- stop_operation(brm);
- oper = READ_REG(&brm->regs->oper);
- oper &= 0x03FF; /* Clear bit 15-10 ... */
- oper |= (data[0]&0x1f)<<11; /* ... OR in new address */
- oper |= odd_parity(data[0]&0x1f)<<10; /* ... OR in parity */
- brm->regs->oper = oper;
- start_operation(brm);
- break;
-
- case BRM_SET_STD:
- stop_operation(brm);
- ctrl = READ_REG(&brm->regs->ctrl);
- ctrl &= 0xFF7F; /* Clear bit 7 ... */
- ctrl |= (data[0]&1)<<7; /* ... OR in new ABSTD (1=A) */
- brm->regs->ctrl = ctrl;
- start_operation(brm);
- break;
-
- case BRM_SET_BCE:
- stop_operation(brm);
- ctrl = READ_REG(&brm->regs->ctrl);
- ctrl &= 0xFFEF; /* Clear bit 4 ... */
- ctrl |= (data[0]&1)<<4; /* ... OR in new BCE */
- brm->regs->ctrl = ctrl;
- start_operation(brm);
- break;
-
- case BRM_TX_BLOCK:
- brm->tx_blocking = data[0];
- break;
-
- case BRM_RX_BLOCK:
- brm->rx_blocking = data[0];
- break;
-
- case BRM_DO_LIST:
-
- if ( brm->mode != BRM_MODE_BC ){
- return RTEMS_INVALID_NAME;
- }
-
- /* Check if we are bus controller */
- if ( ((READ_REG(&brm->regs->oper)>>8) & 3) != 0 ) {
- return RTEMS_INVALID_NAME;
- }
-
- /* Already processing list? */
- if (is_executing(brm)) {
- return RTEMS_RESOURCE_IN_USE;
- }
-
- /* clear any earlier releases */
- rtems_semaphore_obtain(brm->tx_sem, RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT);
-
- brm->bc_list_fail = 0;
- brm->cur_list = cmd_list;
- brm->regs->dpoint = 0;
-
- i = 0;
- while ( (cmd_list[i].ctrl & BC_EOL) == 0) {
+ if (!ioarg) {
+ DBG("brm_control: invalid argument\n");
+ return RTEMS_INVALID_NAME;
+ }
- ctrl = (4<<12) | (((cmd_list[i].ctrl&BC_BUSA)==BC_BUSA)<<9) | (((cmd_list[i].ctrl&BC_RTRT)==BC_RTRT)<<8);
+ ioarg->ioctl_return = 0;
+ switch (ioarg->command) {
- if (cmd_list[i].ctrl&BC_RTRT) {
- cw1 = (cmd_list[i].rtaddr[0]<<11) | (0<<10) | (cmd_list[i].subaddr[0]<<5) | (cmd_list[i].wc & 0x1f); /* receive cw */
- cw2 = (cmd_list[i].rtaddr[1]<<11) | (1<<10) | (cmd_list[i].subaddr[1]<<5) | (cmd_list[i].wc & 0x1f); /* transmit cw */
- }
- else {
- cw1 = (cmd_list[i].rtaddr[0]<<11) | (((cmd_list[i].ctrl&BC_TR)==BC_TR)<<10) | (cmd_list[i].subaddr[0]<<5) | (cmd_list[i].wc&0x1f);
- cw2 = 0;
- }
+ case BRM_SET_MODE:
+ if ( data[0] > 2 )
+ return RTEMS_INVALID_NAME;
+ stop_operation(brm);
+ if (data[0] == 0) {
+ ret = bc_init(brm);
+ } else if (data[0] == 1) {
+ ret = rt_init(brm);
+ } else if (data[0] == 2) {
+ ret = bm_init(brm);
+ } else {
+ ret = RTEMS_INVALID_NAME;
+ }
+ if ( ret != RTEMS_SUCCESSFUL)
+ return ret;
+
+ if ( brm->mode & (BRM_MODE_RT | BRM_MODE_BM ) )
+ start_operation(brm);
+ break;
+
+ case BRM_SET_BUS:
+ stop_operation(brm);
+ ctrl = READ_REG(&brm->regs->ctrl);
+ ctrl &= 0xE7FF; /* Clear bit 12-11 ... */
+ ctrl |= (data[0]&0x3)<<11; /* ... OR in new bus status */
+ brm->regs->ctrl = ctrl;
+ start_operation(brm);
+ break;
+
+ case BRM_SET_MSGTO:
+ stop_operation(brm);
+ ctrl = READ_REG(&brm->regs->ctrl);
+ ctrl &= 0xFDFF; /* Clear bit 9 ... */
+ ctrl |= (data[0]&1)<<9; /* ... OR in new MSGTO */
+ brm->regs->ctrl = ctrl;
+ start_operation(brm);
+ break;
+
+ case BRM_SET_RT_ADDR:
+ stop_operation(brm);
+ oper = READ_REG(&brm->regs->oper);
+ oper &= 0x03FF; /* Clear bit 15-10 ... */
+ oper |= (data[0]&0x1f)<<11; /* ... OR in new address */
+ oper |= odd_parity(data[0]&0x1f)<<10; /* ... OR in parity */
+ brm->regs->oper = oper;
+ start_operation(brm);
+ break;
+
+ case BRM_SET_STD:
+ stop_operation(brm);
+ ctrl = READ_REG(&brm->regs->ctrl);
+ ctrl &= 0xFF7F; /* Clear bit 7 ... */
+ ctrl |= (data[0]&1)<<7; /* ... OR in new ABSTD (1=A) */
+ brm->regs->ctrl = ctrl;
+ start_operation(brm);
+ break;
+
+ case BRM_SET_BCE:
+ stop_operation(brm);
+ ctrl = READ_REG(&brm->regs->ctrl);
+ ctrl &= 0xFFEF; /* Clear bit 4 ... */
+ ctrl |= (data[0]&1)<<4; /* ... OR in new BCE */
+ brm->regs->ctrl = ctrl;
+ start_operation(brm);
+ break;
+
+ case BRM_TX_BLOCK:
+ brm->tx_blocking = data[0];
+ break;
+
+ case BRM_RX_BLOCK:
+ brm->rx_blocking = data[0];
+ break;
+
+ case BRM_DO_LIST:
+ if ( brm->mode != BRM_MODE_BC ){
+ return RTEMS_INVALID_NAME;
+ }
+ /* Check if we are bus controller */
+ if ( ((READ_REG(&brm->regs->oper)>>8) & 3) != 0 ) {
+ return RTEMS_INVALID_NAME;
+ }
- /* Set up command block */
- brm->bcmem->descs[i].ctrl = ctrl;
- brm->bcmem->descs[i].cw1 = cw1;
- brm->bcmem->descs[i].cw2 = cw2;
- /* data pointer:
- * (&brm->bcmem->msg_data[i].data[0] & 0x1ffff) / 2
- */
- brm->bcmem->descs[i].dptr = 1024+i*32; /* data pointer */
- brm->bcmem->descs[i].tsw[0] = 0;
- brm->bcmem->descs[i].tsw[1] = 0;
- brm->bcmem->descs[i].ba = 0;
- brm->bcmem->descs[i].timer = 0;
+ /* Already processing list? */
+ if (is_executing(brm)) {
+ return RTEMS_RESOURCE_IN_USE;
+ }
- memcpy((void *)&brm->bcmem->msg_data[i].data[0], &cmd_list[i].data[0], cmd_list[i].wc*2);
+ /* clear any earlier releases */
+ rtems_semaphore_obtain(brm->tx_sem, RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT);
+
+ brm->bc_list_fail = 0;
+ brm->cur_list = cmd_list;
+ brm->regs->dpoint = 0;
+
+ i = 0;
+ while ( (cmd_list[i].ctrl & BC_EOL) == 0) {
+
+ ctrl = (4<<12) | (((cmd_list[i].ctrl&BC_BUSA)==BC_BUSA)<<9) | (((cmd_list[i].ctrl&BC_RTRT)==BC_RTRT)<<8);
+
+ if (cmd_list[i].ctrl&BC_RTRT) {
+ cw1 = (cmd_list[i].rtaddr[0]<<11) | (0<<10) | (cmd_list[i].subaddr[0]<<5) | (cmd_list[i].wc & 0x1f); /* receive cw */
+ cw2 = (cmd_list[i].rtaddr[1]<<11) | (1<<10) | (cmd_list[i].subaddr[1]<<5) | (cmd_list[i].wc & 0x1f); /* transmit cw */
+ } else {
+ cw1 = (cmd_list[i].rtaddr[0]<<11) | (((cmd_list[i].ctrl&BC_TR)==BC_TR)<<10) | (cmd_list[i].subaddr[0]<<5) | (cmd_list[i].wc&0x1f);
+ cw2 = 0;
+ }
+
+ /* Set up command block */
+ brm->bcmem->descs[i].ctrl = ctrl;
+ brm->bcmem->descs[i].cw1 = cw1;
+ brm->bcmem->descs[i].cw2 = cw2;
+ /* data pointer:
+ * (&brm->bcmem->msg_data[i].data[0] & 0x1ffff) / 2
+ */
+ brm->bcmem->descs[i].dptr = 1024+i*32; /* data pointer */
+ brm->bcmem->descs[i].tsw[0] = 0;
+ brm->bcmem->descs[i].tsw[1] = 0;
+ brm->bcmem->descs[i].ba = 0;
+ brm->bcmem->descs[i].timer = 0;
+
+ msglen = cmd_list[i].wc;
+ if ( msglen == 0 )
+ msglen = 32;
+ memcpy((void *)&brm->bcmem->msg_data[i].data[0], &cmd_list[i].data[0], msglen*2);
+
+ i++;
+ }
- i++;
- }
+ brm->bcmem->descs[i].ctrl = 0; /* end of list */
- brm->bcmem->descs[i].ctrl = 0; /* end of list */
+ start_operation(brm);
+ break;
- start_operation(brm);
+ case BRM_LIST_DONE:
- break;
+ if ( brm->mode != BRM_MODE_BC ){
+ return RTEMS_INVALID_NAME;
+ }
+
+ /* Check if we are bus controller */
+ if ( ((READ_REG(&brm->regs->oper)>>8) & 3) != 0 ) {
+ return RTEMS_INVALID_NAME;
+ }
- case BRM_LIST_DONE:
+ if (is_executing(brm)) {
- if ( brm->mode != BRM_MODE_BC ){
- return RTEMS_INVALID_NAME;
+ data[0] = 0;
+ if (brm->tx_blocking) {
+ rtems_semaphore_obtain(brm->tx_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+ data[0] = 1;
+ if ( brm->bc_list_fail ){
+ return RTEMS_INVALID_NAME;
}
+ } else {
+ return RTEMS_RESOURCE_IN_USE;
+ }
+ } else {
+ data[0] = 1; /* done */
+ }
- /* Check if we are bus controller */
- if ( ((READ_REG(&brm->regs->oper)>>8) & 3) != 0 ) {
- return RTEMS_INVALID_NAME;
- }
-
- if (is_executing(brm)) {
-
- data[0] = 0;
- if (brm->tx_blocking) {
- rtems_semaphore_obtain(brm->tx_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
- data[0] = 1;
- if ( brm->bc_list_fail ){
- return RTEMS_INVALID_NAME;
- }
- }else{
- return RTEMS_RESOURCE_IN_USE;
- }
-
-
- }
- else {
- data[0] = 1; /* done */
- }
-
- /* copy finished list results back into bc_msg array */
- i = 0;
- while ( (brm->cur_list[i].ctrl & BC_EOL) == 0) {
-
- if (READ_DMA(&brm->bcmem->descs[i].ctrl) & 1) {
- brm->cur_list[i].ctrl |= 0x8000; /* Set BAME */
- }
- if (brm->cur_list[i].ctrl & BC_TR) {
- /* RT Transmit command, copy received data */
- len = brm->cur_list[i].wc;
- while( len-- > 0){
- brm->cur_list[i].data[len] = READ_DMA(&brm->bcmem->msg_data[i].data[len]);
- }
- }
- brm->cur_list[i].tsw[0] = READ_DMA(&brm->bcmem->descs[i].tsw[0]);
- brm->cur_list[i].tsw[1] = READ_DMA(&brm->bcmem->descs[i].tsw[1]);
-
- i++;
- }
- break;
-
-
- case BRM_CLR_STATUS:
- brm->status = 0;
- break;
+ /* copy finished list results back into bc_msg array */
+ i = 0;
+ while ( (brm->cur_list[i].ctrl & BC_EOL) == 0) {
+ if (READ_DMA(&brm->bcmem->descs[i].ctrl) & 1) {
+ brm->cur_list[i].ctrl |= 0x8000; /* Set BAME */
+ }
+ if (brm->cur_list[i].ctrl & BC_TR) {
+ /* RT Transmit command, copy received data */
+ len = brm->cur_list[i].wc;
+ if ( len == 0 )
+ len = 32;
+ while ( len-- > 0) {
+ brm->cur_list[i].data[len] = READ_DMA(&brm->bcmem->msg_data[i].data[len]);
+ }
+ }
+ brm->cur_list[i].tsw[0] = READ_DMA(&brm->bcmem->descs[i].tsw[0]);
+ brm->cur_list[i].tsw[1] = READ_DMA(&brm->bcmem->descs[i].tsw[1]);
- case BRM_GET_STATUS: /* copy status */
+ i++;
+ }
+ break;
- if ( !ioarg->buffer )
- return RTEMS_INVALID_NAME;
+ case BRM_CLR_STATUS:
+ brm->status = 0;
+ break;
- *(unsigned int *)ioarg->buffer = brm->status;
- break;
+ case BRM_GET_STATUS: /* copy status */
+ if ( !ioarg->buffer )
+ return RTEMS_INVALID_NAME;
+ *(unsigned int *)ioarg->buffer = brm->status;
+ break;
+
case BRM_SET_EVENTID:
- brm->event_id = (rtems_id)ioarg->buffer;
- break;
-
- default:
- return RTEMS_NOT_DEFINED;
- }
- return RTEMS_SUCCESSFUL;
-}
+ brm->event_id = (rtems_id)ioarg->buffer;
+ break;
-#ifdef B1553BRM_DEFINE_INTHANDLER
-static void b1553brm_interrupt_handler(rtems_vector_number v){
- int i;
- /* find minor */
- for(i=0; i<brm_cores; i++){
- if ( (brms[i].irqno+0x10) == v ){
- brm_interrupt(&brms[i]);
- return;
- }
+ default:
+ return RTEMS_NOT_DEFINED;
}
+ return RTEMS_SUCCESSFUL;
}
-#endif
-static void brm_interrupt(brm_priv *brm) {
- unsigned short descriptor, current, pending, miw, wc, tmp;
+static void b1553brm_interrupt(void *arg)
+{
+ brm_priv *brm = arg;
+ unsigned short descriptor, current, pending, miw, wc, tmp, ctrl;
unsigned short msgadr, iaw, iiw;
int len;
- int signal_event=0;
+ int signal_event=0, wake_rx_task=0, wake_tx_task=0;
unsigned int event_status=0;
+ int accessed;
#define SET_ERROR_DESCRIPTOR(descriptor) (event_status = (event_status & 0x0000ffff) | descriptor<<16)
-
- while( (iiw=READ_REG(&brm->irq_log[brm->irq].iiw)) != 0xffff ){
- iaw=READ_REG(&brm->irq_log[brm->irq].iaw);
-
+
+ while( (iiw=READ_DMA(&brm->irq_log[brm->irq].iiw)) != 0xffff ){
+ iaw=READ_DMA(&brm->irq_log[brm->irq].iaw);
+
/* indicate that the interrupt log entry has been processed */
brm->irq_log[brm->irq].iiw = 0xffff;
/* Interpret interrupt log entry */
- descriptor = iaw >> 2;
- pending = iiw;
- brm->irq = (brm->irq + 1) % 16;
-
+ descriptor = iaw >> 2;
+ pending = iiw;
+ brm->irq = (brm->irq + 1) % 16;
+
/* Clear the log so that we */
- /* Subaddress accessed irq (RT only)
- *
- * Can be either a receive or transmit command
- * as well as a mode code.
- */
- if (pending & BRM_SUBAD_IRQ) {
-
- /* Pointer to next free message in circular buffer */
- current = READ_DMA(&brm->desc[descriptor].cur);
-
- while ( (msgadr=brm->last_read[descriptor]) != current) {
-
- /* Get word count */
- miw = READ_DMA(&brm->mem[msgadr]);
- wc = miw >> 11;
-
- /* Data received */
- if (descriptor < 32) {
- wc = wc ? wc : 32;
- }
- /* Data transmitted */
- else if (descriptor < 64) {
- wc = wc ? wc : 32;
- rtems_semaphore_release(brm->tx_sem);
- }
- /* RX Mode code */
- else if (descriptor < 96) {
- wc = (wc>>4);
- }
- /* TX Mode code */
- else if (descriptor < 128) {
- wc = (wc>>4);
- }
-
+ /* Subaddress accessed irq (RT only)
+ *
+ * Can be either a receive or transmit command
+ * as well as a mode code.
+ */
+ if (pending & BRM_SUBAD_IRQ) {
+
+ /* Pointer to next free message in circular buffer */
+ current = READ_DMA(&brm->desc[descriptor].cur);
+ ctrl = READ_DMA(&brm->desc[descriptor].ctrl);
#ifdef DEBUG
- brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = (descriptor << 16) | wc;
- brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = current;
- brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = msgadr;
+ brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = (0xff<<16);
+ brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = current;
+ brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = ctrl;
+ brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = 0;
#endif
+ accessed = ctrl & 0x10;
+ /* Note that current may be equal to bot and top when
+ * circular buffer one can handle one message.
+ */
+ if ( accessed )
+ do {
+ msgadr = brm->last_read[descriptor];
+
+ /* Get word count */
+ miw = READ_DMA(&brm->mem[msgadr]);
+ wc = miw >> 11;
+
+ /* Data received */
+ if (descriptor < 32) {
+ wc = wc ? wc : 32;
+ }
+ /* Data transmitted */
+ else if (descriptor < 64) {
+ wc = wc ? wc : 32;
+ wake_tx_task=1;
+ }
+ /* RX Mode code */
+ else if (descriptor < 96) {
+ wc = (wc>>4);
+ }
+ /* TX Mode code */
+ else if (descriptor < 128) {
+ wc = (wc>>4);
+ }
- /* If there is room in the event queue, copy the event there */
- if (brm->head - brm->tail != EVENT_QUEUE_SIZE) {
-
- /* Copy to event queue */
- brm->rt_event[INDEX(brm->head)].miw = READ_DMA(&brm->mem[msgadr]);
- brm->rt_event[INDEX(brm->head)].time = READ_DMA(&brm->mem[msgadr+1]);
- len = wc;
- while( len-- > 0){
- brm->rt_event[INDEX(brm->head)].data[len] = READ_DMA(&brm->mem[msgadr+2+len]);
- }
- brm->rt_event[INDEX(brm->head)].desc = descriptor;
- brm->head++;
+#ifdef DEBUG
+ brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = (descriptor << 16) | wc;
+ brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = current;
+ brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = msgadr;
+#endif
- }
- else {
- /* Indicate overrun */
- brm->rt_event[INDEX(brm->head)].desc |= 0x8000;
- }
+ /* If there is room in the event queue, copy the event there */
+ if (brm->head - brm->tail != EVENT_QUEUE_SIZE) {
+
+ /* Copy to event queue */
+ brm->rt_event[INDEX(brm->head)].miw = READ_DMA(&brm->mem[msgadr]);
+ brm->rt_event[INDEX(brm->head)].time = READ_DMA(&brm->mem[msgadr+1]);
+ len = wc;
+ while( len-- > 0){
+ brm->rt_event[INDEX(brm->head)].data[len] = READ_DMA(&brm->mem[msgadr+2+len]);
+ }
+ brm->rt_event[INDEX(brm->head)].desc = descriptor;
+ brm->head++;
+ }
+ else {
+ /* Indicate overrun */
+ brm->rt_event[INDEX(brm->head)].desc |= 0x8000;
+ }
- msgadr += (2+wc);
+ msgadr += (2+wc);
- if (msgadr >= brm->desc[descriptor].bot) {
- msgadr = brm->desc[descriptor].top;
- }
- brm->last_read[descriptor] = msgadr;
+ if (msgadr >= READ_DMA(&brm->desc[descriptor].bot)) {
+ msgadr = READ_DMA(&brm->desc[descriptor].top);
+ }
+ brm->last_read[descriptor] = msgadr;
#ifdef DEBUG
- brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = msgadr;
+ brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = msgadr;
#endif
+ wake_rx_task = 1;
+ } while ( (msgadr=brm->last_read[descriptor]) != current );
+ }
- /* Wake any blocked rx thread */
- rtems_semaphore_release(brm->rx_sem);
-
- }
-
- }
-
- if (pending & BRM_EOL_IRQ) {
- rtems_semaphore_release(brm->tx_sem);
- }
-
- if (pending & BRM_BC_ILLCMD_IRQ) {
- brm->bc_list_fail = 1;
- rtems_semaphore_release(brm->tx_sem);
- SET_ERROR_DESCRIPTOR(descriptor);
- FUNCDBG("BRM: ILLCMD IRQ\n\r");
- }
-
- /* Monitor irq */
- if (pending & BRM_MBC_IRQ) {
-
- stop_operation(brm);
- brm->regs->mbc = 1;
- start_operation(brm);
-
- /* If there is room in the event queue, copy the event there */
- if (brm->head - brm->tail != EVENT_QUEUE_SIZE) {
-
- /* Copy to event queue */
+ if (pending & BRM_EOL_IRQ) {
+ wake_tx_task = 1;
+ }
- brm->bm_event[INDEX(brm->head)].miw = READ_DMA(&brm->mem[0]);
- brm->bm_event[INDEX(brm->head)].cw1 = READ_DMA(&brm->mem[1]);
- brm->bm_event[INDEX(brm->head)].cw2 = READ_DMA(&brm->mem[2]);
- brm->bm_event[INDEX(brm->head)].sw1 = READ_DMA(&brm->mem[4]);
- brm->bm_event[INDEX(brm->head)].sw2 = READ_DMA(&brm->mem[5]);
- brm->bm_event[INDEX(brm->head)].time = READ_DMA(&brm->mem[6]);
+ if (pending & BRM_BC_ILLCMD_IRQ) {
+ brm->bc_list_fail = 1;
+ wake_tx_task = 1;
+ SET_ERROR_DESCRIPTOR(descriptor);
+ FUNCDBG("BRM: ILLCMD IRQ\n\r");
+ }
- len = 32;
- while ( len-- ){
- brm->bm_event[INDEX(brm->head)].data[len] = READ_DMA(&brm->mem[0x100+len]);
- len--;
- brm->bm_event[INDEX(brm->head)].data[len] = READ_DMA(&brm->mem[0x100+len]);
- len--;
- brm->bm_event[INDEX(brm->head)].data[len] = READ_DMA(&brm->mem[0x100+len]);
- len--;
- brm->bm_event[INDEX(brm->head)].data[len] = READ_DMA(&brm->mem[0x100+len]);
- }
-/* memcpy((void *)brm->bm_event[INDEX(brm->head)].data, &brm->mem[0x100], 32);*/
+ /* Monitor irq */
+ if (pending & BRM_MBC_IRQ) {
+
+ stop_operation(brm);
+ brm->regs->mbc = 1;
+ start_operation(brm);
+
+ /* If there is room in the event queue, copy the event there */
+ if (brm->head - brm->tail != EVENT_QUEUE_SIZE) {
+
+ /* Copy to event queue */
+
+ brm->bm_event[INDEX(brm->head)].miw = READ_DMA(&brm->mem[0]);
+ brm->bm_event[INDEX(brm->head)].cw1 = READ_DMA(&brm->mem[1]);
+ brm->bm_event[INDEX(brm->head)].cw2 = READ_DMA(&brm->mem[2]);
+ brm->bm_event[INDEX(brm->head)].sw1 = READ_DMA(&brm->mem[4]);
+ brm->bm_event[INDEX(brm->head)].sw2 = READ_DMA(&brm->mem[5]);
+ brm->bm_event[INDEX(brm->head)].time = READ_DMA(&brm->mem[6]);
+
+ len = 32;
+ while ( len-- ){
+ brm->bm_event[INDEX(brm->head)].data[len] = READ_DMA(&brm->mem[0x100+len]);
+ len--;
+ brm->bm_event[INDEX(brm->head)].data[len] = READ_DMA(&brm->mem[0x100+len]);
+ len--;
+ brm->bm_event[INDEX(brm->head)].data[len] = READ_DMA(&brm->mem[0x100+len]);
+ len--;
+ brm->bm_event[INDEX(brm->head)].data[len] = READ_DMA(&brm->mem[0x100+len]);
+ }
+/* memcpy((void *)brm->bm_event[INDEX(brm->head)].data, &brm->mem[0x100], 32);*/
#ifdef DEBUG
- brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = READ_REG(&brm->regs->mbc);
- brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = READ_DMA(&brm->mem[0]);
- brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = READ_DMA(&brm->mem[1]);
- brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = READ_DMA(&brm->mem[4]);
+ brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = READ_REG(&brm->regs->mbc) & 0xffff;
+ brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = READ_DMA(&brm->mem[0]);
+ brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = READ_DMA(&brm->mem[1]);
+ brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = READ_DMA(&brm->mem[4]);
#endif
- brm->head++;
+ brm->head++;
- }
- else {
- /* Indicate overrun */
- brm->rt_event[INDEX(brm->head)].miw |= 0x8000;
- }
+ }
+ else {
+ /* Indicate overrun */
+ brm->bm_event[INDEX(brm->head)].miw |= 0x8000;
+ }
- /* Wake any blocking thread */
- rtems_semaphore_release(brm->rx_sem);
-
- }
+ /* Wake any blocking thread */
+ wake_rx_task = 1;
+ }
- /* The reset of the interrupts
+ /* The reset of the interrupts
* cause a event to be signalled
* so that user can handle error.
*/
@@ -1311,9 +1382,9 @@ static void brm_interrupt(brm_priv *brm) {
if ( pending & BRM_ILLOP_IRQ){
FUNCDBG("BRM: BRM_ILLOP_IRQ\n\r");
brm->bc_list_fail = 1;
- rtems_semaphore_release(brm->tx_sem);
+ wake_tx_task = 1;
event_status |= BRM_ILLOP_IRQ;
- SET_ERROR_DESCRIPTOR(descriptor);
+ SET_ERROR_DESCRIPTOR(descriptor);
signal_event=1;
}
@@ -1323,10 +1394,15 @@ static void brm_interrupt(brm_priv *brm) {
SET_ERROR_DESCRIPTOR(descriptor);
signal_event=1;
}
- /* Clear Block Accessed Bit */
- tmp = READ_REG(&brm->desc[descriptor].ctrl);
- brm->desc[descriptor].ctrl = tmp & ~0x10;
-
+ /* Clear Block Accessed Bit */
+ tmp = READ_DMA(&brm->desc[descriptor].ctrl);
+ brm->desc[descriptor].ctrl = tmp & ~0x10;
+#ifdef DEBUG
+ brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = (0xfe<<16);
+ brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = 0;
+ brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = tmp & ~0x10;
+ brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = tmp;
+#endif
} /* While */
/* clear interrupt flags & handle Hardware errors */
@@ -1357,9 +1433,88 @@ static void brm_interrupt(brm_priv *brm) {
brm->status |= event_status;
}
+ /* Wake any blocked rx thread only on receive interrupts */
+ if ( wake_rx_task ) {
+ rtems_semaphore_release(brm->rx_sem);
+ }
+
+ /* Wake any blocked tx thread only on transmit interrupts */
+ if ( wake_tx_task ) {
+ rtems_semaphore_release(brm->tx_sem);
+ }
+
/* signal event once */
if ( signal_event && (brm->event_id!=0) ){
rtems_event_send(brm->event_id, event_status);
}
}
+
+void b1553brm_print_dev(struct drvmgr_dev *dev, int options)
+{
+ brm_priv *pDev = dev->priv;
+ struct amba_dev_info *devinfo;
+ struct brm_reg *regs = pDev->regs;
+
+ devinfo = (struct amba_dev_info *)pDev->dev->businfo;
+
+ /* Print */
+ printf("--- B1553BRM[%d] %s ---\n", pDev->minor, pDev->devName);
+ printf(" REGS: 0x%x\n", (unsigned int)pDev->regs);
+ printf(" IRQ: %d\n", pDev->irqno);
+ switch (pDev->mode) {
+ case BRM_MODE_BC:
+ printf(" MODE: BC\n");
+ printf(" DESCS: 0x%x\n", (unsigned int)&pDev->bcmem->descs[0]);
+ printf(" DATA: 0x%x\n", (unsigned int)&pDev->bcmem->msg_data[0].data[0]);
+ printf(" IRQLOG: 0x%x\n", (unsigned int)&pDev->bcmem->irq_logs[0]);
+ break;
+ case BRM_MODE_BM:
+ printf(" MODE: BM\n");
+ break;
+ case BRM_MODE_RT:
+ printf(" MODE: RT\n");
+ printf(" RXSUBS: 0x%x\n", (unsigned int)&pDev->rtmem->rxsubs[0]);
+ printf(" TXSUBS: 0x%x\n", (unsigned int)&pDev->rtmem->txsubs[0]);
+ printf(" RXMODES: 0x%x\n", (unsigned int)&pDev->rtmem->rxmodes[0]);
+ printf(" TXOMODES: 0x%x\n", (unsigned int)&pDev->rtmem->txmodes[0]);
+ printf(" RXSUBS MSGS: 0x%x\n", (unsigned int)&pDev->rtmem->rxsuba_msgs[0]);
+ printf(" TXSUBS MSGS: 0x%x\n", (unsigned int)&pDev->rtmem->txsuba_msgs[0]);
+ printf(" RXMODES MSGS: 0x%x\n", (unsigned int)&pDev->rtmem->rxmode_msgs[0]);
+ printf(" TXMODES MSGS: 0x%x\n", (unsigned int)&pDev->rtmem->txmode_msgs[0]);
+ printf(" IRQLOG: 0x%x\n", (unsigned int)&pDev->rtmem->irq_logs[0]);
+ break;
+ }
+ printf(" CTRL: 0x%x\n", regs->ctrl);
+ printf(" OPER: 0x%x\n", regs->oper);
+ printf(" CUR_CMD: 0x%x\n", regs->cur_cmd);
+ printf(" IMASK: 0x%x\n", regs->imask);
+ printf(" IPEND: 0x%x\n", regs->ipend);
+ printf(" IPOINT: 0x%x\n", regs->ipoint);
+ printf(" BIT_REG: 0x%x\n", regs->bit_reg);
+ printf(" TTAG: 0x%x\n", regs->ttag);
+ printf(" DPOINT: 0x%x\n", regs->dpoint);
+ printf(" SW: 0x%x\n", regs->sw);
+ printf(" INITCOUNT: 0x%x\n", regs->initcount);
+ printf(" MCPOINT: 0x%x\n", regs->mcpoint);
+ printf(" MDPOINT: 0x%x\n", regs->mdpoint);
+ printf(" MBC: 0x%x\n", regs->mbc);
+ printf(" MFILTA: 0x%x\n", regs->mfilta);
+ printf(" MFILTB: 0x%x\n", regs->mfiltb);
+ printf(" ENHANCED: 0x%x\n", regs->enhanced);
+ printf(" W_CTRL: 0x%x\n", regs->w_ctrl);
+ printf(" W_IRQCTRL: 0x%x\n", regs->w_irqctrl);
+ printf(" W_AHBADDR: 0x%x\n", regs->w_ahbaddr);
+}
+
+void b1553brm_print(int options)
+{
+ struct amba_drv_info *drv = &b1553brm_drv_info;
+ struct drvmgr_dev *dev;
+
+ dev = drv->general.dev;
+ while(dev) {
+ b1553brm_print_dev(dev, options);
+ dev = dev->next_in_drv;
+ }
+}
diff --git a/c/src/lib/libbsp/sparc/shared/1553/b1553brm_pci.c b/c/src/lib/libbsp/sparc/shared/1553/b1553brm_pci.c
deleted file mode 100644
index 76c9f2e56a..0000000000
--- a/c/src/lib/libbsp/sparc/shared/1553/b1553brm_pci.c
+++ /dev/null
@@ -1,132 +0,0 @@
-/* Select PCI driver */
-#define B1553BRM_NO_AMBA
-#define B1553BRM_PCI
-
-#undef B1553BRM_MAXDEVS
-
-/* Use only 16K memory */
-#define DMA_MEM_16K
-
-/* Malloced memory or
- * Card local memory
- */
-#define B1553BRM_LOCAL_MEM
-
-#define DONT_DEF_RAMON
-
-/* memory must be aligned to a 128k boundary */
-unsigned int brmpci_memarea_address;
-#define B1553BRM_LOCAL_MEM_ADR brmpci_memarea_address
-
-/* We have custom address tranlation for HW addresses */
-#define B1553BRM_ADR_TO
-
-/* No custom MEMAREA=>CPU used since BRM Core work with offsets
- * in it's descriptors.
- */
-#undef B1553BRM_ADR_FROM
-
-/* Set registered device name */
-#define B1553BRM_DEVNAME "/dev/brmpci0"
-#define B1553BRM_DEVNAME_NO(devstr,no) ((devstr)[11]='0'+(no))
-
-/* Any non-static function will begin with */
-#define B1553BRM_PREFIX(name) b1553brmpci##name
-
-/* do nothing, assume that the interrupt handler is called
- * setup externally calling b1553_interrupt_handler.
- */
-#define B1553BRM_REG_INT(handler,irq,arg) \
- if ( b1553brm_pci_int_reg ) \
- b1553brm_pci_int_reg(handler,irq,arg);
-
-
-#ifdef B1553BRM_ADR_TO
-/* Translate a address within the Memory Region (memarea) into an Hardware
- * device address. This address is put into hardware registers or descriptors
- * so that the hardware can access the Memory Region.
- * Example:
- * An local AMBA access at 0xe0000000 will translate into PCI address 0x40000000,
- * the PCI address 0x40000000 will translate into CPU-AMBA address 0x40000000.
- */
-unsigned int brmpci_hw_address;
-static inline unsigned int memarea_to_hw(unsigned int addr) {
- /* don't translate? */
- if ( brmpci_hw_address == 0xffffffff )
- return addr;
- return ((addr & 0x000fffff) | brmpci_hw_address);
-}
-#endif
-
-/* not used since BRM Core work with offsets */
-#ifdef B1553BRM_ADR_FROM
-unsigned int brmpci_cpu_access_address;
-static inline unsigned int hw_to_cpu(unsigned int addr) {
- /* don't translate? */
- if ( brmpci_cpu_address == 0xffffffff )
- return addr;
- return ((addr & 0x0fffffff) | brmpci_cpu_address);
-}
-#endif
-
-void (*b1553brm_pci_int_reg)(void *handler, int irq, void *arg) = 0;
-
-static void b1553brmpci_interrupt_handler(int irq, void *arg);
-
-#include "b1553brm.c"
-
-/*
- *
- * memarea = preallocated memory somewhere, pointer to start of memory.
- * hw_address = how to translate a memarea address into an HW device AMBA address.
- */
-
-int b1553brm_pci_register(
- amba_confarea_type *bus,
- unsigned int clksel,
- unsigned int clkdiv,
- unsigned int brm_freq,
- unsigned int memarea,
- unsigned int hw_address
- )
-{
- /* Setup configuration */
-
- /* if zero malloc will be used */
- brmpci_memarea_address = memarea;
-
- brmpci_hw_address = hw_address;
-
-#ifdef B1553BRM_ADR_FROM
- brmpci_cpu_address = memarea & 0xf0000000;
-#endif
-
- /* Register the driver */
- return B1553BRM_PREFIX(_register)(bus,clksel,clkdiv,brm_freq);
-}
-
-/* Call this from PCI interrupt handler
- * irq = the irq number of the HW device local to that IRQMP controller
- *
- */
-static void b1553brmpci_interrupt_handler(int irq, void *arg){
- brm_interrupt(arg);
-}
-
-#if 0
-int b1553brm_pci_interrupt_handler(int irqmask){
- int i;
- unsigned int mask=0;
- /* find minor */
- for(i=0; i<brm_cores; i++){
- if ( (1<<brms[i].irqno) & irqmask ){
- mask |= 1<<brms[i].irqno;
- brm_interrupt(&brms[i]);
- /* more interrupts to scan for? */
- if ( irqmask & ~mask )
- return mask; /* handled */
- }
- }
- return mask;
-}
-#endif
diff --git a/c/src/lib/libbsp/sparc/shared/1553/b1553brm_rasta.c b/c/src/lib/libbsp/sparc/shared/1553/b1553brm_rasta.c
deleted file mode 100644
index 10adb0aec5..0000000000
--- a/c/src/lib/libbsp/sparc/shared/1553/b1553brm_rasta.c
+++ /dev/null
@@ -1,115 +0,0 @@
-/* Select PCI driver */
-#define B1553BRM_NO_AMBA
-#define B1553BRM_PCI
-
-#undef B1553BRM_MAXDEVS
-
-/* Use only 16K memory */
-#define DMA_MEM_128K
-
-/* Malloced memory or
- * Card local memory
- */
-#define B1553BRM_LOCAL_MEM
-
-#define DONT_DEF_RAMON
-
-/* memory must be aligned to a 128k boundary */
-unsigned int brmrasta_memarea_address;
-#define B1553BRM_LOCAL_MEM_ADR brmrasta_memarea_address
-
-/* We have custom address tranlation for HW addresses */
-#define B1553BRM_ADR_TO
-
-/* No custom MEMAREA=>CPU used since BRM Core work with offsets
- * in it's descriptors.
- */
-#undef B1553BRM_ADR_FROM
-
-/* Set registered device name */
-#define B1553BRM_DEVNAME "/dev/brmrasta0"
-#define B1553BRM_DEVNAME_NO(devstr,no) ((devstr)[13]='0'+(no))
-
-/* Any non-static function will begin with */
-#define B1553BRM_PREFIX(name) b1553brmrasta##name
-
-/* do nothing, assume that the interrupt handler is called
- * setup externally calling b1553_interrupt_handler.
- */
-#define B1553BRM_REG_INT(handler,irq,arg) \
- if ( b1553brm_rasta_int_reg ) \
- b1553brm_rasta_int_reg(handler,irq,arg);
-
-
-#ifdef B1553BRM_ADR_TO
-/* Translate a address within the Memory Region (memarea) into an Hardware
- * device address. This address is put into hardware registers or descriptors
- * so that the hardware can access the Memory Region.
- * Example:
- * An local AMBA access at 0xe0000000 will translate into PCI address 0x40000000,
- * the PCI address 0x40000000 will translate into CPU-AMBA address 0x40000000.
- */
-unsigned int brmrasta_hw_address;
-static inline unsigned int memarea_to_hw(unsigned int addr) {
- /* don't translate? */
- if ( brmrasta_hw_address == 0xffffffff )
- return addr;
- return ((addr & 0x0fffffff) | brmrasta_hw_address);
-}
-#endif
-
-/* not used since BRM Core work with offsets */
-#ifdef B1553BRM_ADR_FROM
-unsigned int brmrasta_cpu_access_address;
-static inline unsigned int hw_to_cpu(unsigned int addr) {
- /* don't translate? */
- if ( brmrasta_cpu_address == 0xffffffff )
- return addr;
- return ((addr & 0x0fffffff) | brmrasta_cpu_address);
-}
-#endif
-
-void (*b1553brm_rasta_int_reg)(void *handler, int irq, void *arg) = 0;
-
-static void b1553brmrasta_interrupt_handler(int irq, void *arg);
-
-#include "b1553brm.c"
-
-/*
- *
- * memarea = preallocated memory somewhere, pointer to start of memory.
- * hw_address = how to translate a memarea address into an HW device AMBA address.
- */
-
-int b1553brm_rasta_register(
- amba_confarea_type *bus,
- unsigned int clksel,
- unsigned int clkdiv,
- unsigned int brm_freq,
- unsigned int memarea,
- unsigned int hw_address
- )
-{
- /* Setup configuration */
-
- /* if zero the malloc will be used */
- brmrasta_memarea_address = memarea;
-
- brmrasta_hw_address = hw_address;
-
-#ifdef B1553BRM_ADR_FROM
- brmrasta_cpu_address = memarea & 0xf0000000;
-#endif
-
- /* Register the driver */
- return B1553BRM_PREFIX(_register)(bus,clksel,clkdiv,brm_freq);
-}
-
-/* Call this from RASTA interrupt handler
- * irq = the irq number of the HW device local to that IRQMP controller
- *
- */
-static void b1553brmrasta_interrupt_handler(int irq, void *arg){
- brm_interrupt(arg);
-}
-
diff --git a/c/src/lib/libbsp/sparc/shared/1553/b1553rt.c b/c/src/lib/libbsp/sparc/shared/1553/b1553rt.c
new file mode 100644
index 0000000000..acb9379650
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/1553/b1553rt.c
@@ -0,0 +1,851 @@
+/*
+ * B1553RT driver implmenetation
+ *
+ * COPYRIGHT (c) 2009.
+ * Aeroflex Gaisler.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ *
+ */
+
+
+#include <bsp.h>
+#include <rtems/libio.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+#include <rtems/bspIo.h>
+
+#include <drvmgr/drvmgr.h>
+#include <b1553rt.h>
+#include <ambapp.h>
+#include <drvmgr/ambapp_bus.h>
+
+/* Uncomment for debug output */
+/*#define DEBUG 1*/
+
+/*
+ #define FUNCDEBUG 1*/
+/*#undef DEBUG*/
+#undef FUNCDEBUG
+
+/* EVENT_QUEUE_SIZE sets the size of the event queue
+ */
+#define EVENT_QUEUE_SIZE 1024
+
+
+#define INDEX(x) ( x&(EVENT_QUEUE_SIZE-1) )
+
+#if 0
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+#ifdef FUNCDEBUG
+#define FUNCDBG(x...) printk(x)
+#else
+#define FUNCDBG(x...)
+#endif
+
+#define READ_DMA(address) _READ16((unsigned int)address)
+
+static __inline__ unsigned short _READ16(unsigned int addr) {
+ unsigned short tmp;
+ asm(" lduha [%1]1, %0 "
+ : "=r"(tmp)
+ : "r"(addr)
+ );
+ return tmp;
+}
+
+static rtems_device_driver rt_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver rt_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver rt_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver rt_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver rt_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver rt_control(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+
+#define RT_DRIVER_TABLE_ENTRY { rt_initialize, rt_open, rt_close, rt_read, rt_write, rt_control }
+
+static rtems_driver_address_table b1553rt_driver = RT_DRIVER_TABLE_ENTRY;
+
+typedef struct {
+
+ struct drvmgr_dev *dev; /* Driver manager device */
+ char devName[32]; /* Device Name */
+
+ struct rt_reg *regs;
+ unsigned int ctrl_copy; /* Local copy of config register */
+
+ unsigned int cfg_freq;
+
+ unsigned int memarea_base;
+ unsigned int memarea_base_remote;
+
+ volatile unsigned short *mem;
+
+ /* Received events waiting to be read */
+ struct rt_msg *rt_event;
+ unsigned int head, tail;
+
+ int rx_blocking;
+
+ rtems_id rx_sem, tx_sem, dev_sem;
+ int minor;
+ int irqno;
+
+#ifdef DEBUG
+ unsigned int log[EVENT_QUEUE_SIZE*4];
+ unsigned int log_i;
+#endif
+
+ unsigned int status;
+ rtems_id event_id; /* event that may be signalled upon errors, needs to be set through ioctl command RT_SET_EVENTID */
+
+} rt_priv;
+
+static void b1553rt_interrupt(void *arg);
+static rtems_device_driver rt_init(rt_priv *rt);
+
+#define OFS(ofs) (((unsigned int)&ofs & 0x1ffff)>>1)
+
+static int b1553rt_driver_io_registered = 0;
+static rtems_device_major_number b1553rt_driver_io_major = 0;
+
+/******************* Driver manager interface ***********************/
+
+/* Driver prototypes */
+int b1553rt_register_io(rtems_device_major_number *m);
+int b1553rt_device_init(rt_priv *pDev);
+
+int b1553rt_init2(struct drvmgr_dev *dev);
+int b1553rt_init3(struct drvmgr_dev *dev);
+int b1553rt_remove(struct drvmgr_dev *dev);
+
+struct drvmgr_drv_ops b1553rt_ops =
+{
+ .init = {NULL, b1553rt_init2, b1553rt_init3, NULL},
+ .remove = b1553rt_remove,
+ .info = NULL
+};
+
+struct amba_dev_id b1553rt_ids[] =
+{
+ {VENDOR_GAISLER, GAISLER_B1553RT},
+ {0, 0} /* Mark end of table */
+};
+
+struct amba_drv_info b1553rt_drv_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_AMBAPP_GAISLER_B1553RT_ID, /* Driver ID */
+ "B1553RT_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */
+ &b1553rt_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ 0,
+
+ },
+ &b1553rt_ids[0]
+};
+
+void b1553rt_register_drv (void)
+{
+ DBG("Registering B1553RT driver\n");
+ drvmgr_drv_register(&b1553rt_drv_info.general);
+}
+
+int b1553rt_init2(struct drvmgr_dev *dev)
+{
+ rt_priv *priv;
+
+ DBG("B1553RT[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
+ priv = dev->priv = malloc(sizeof(rt_priv));
+ if ( !priv )
+ return DRVMGR_NOMEM;
+ memset(priv, 0, sizeof(*priv));
+ priv->dev = dev;
+
+ /* This core will not find other cores, so we wait for init2() */
+
+ return DRVMGR_OK;
+}
+
+int b1553rt_init3(struct drvmgr_dev *dev)
+{
+ rt_priv *priv;
+ char prefix[32];
+ rtems_status_code status;
+
+ priv = dev->priv;
+
+ /* Do initialization */
+
+ if ( b1553rt_driver_io_registered == 0) {
+ /* Register the I/O driver only once for all cores */
+ if ( b1553rt_register_io(&b1553rt_driver_io_major) ) {
+ /* Failed to register I/O driver */
+ dev->priv = NULL;
+ return DRVMGR_FAIL;
+ }
+
+ b1553rt_driver_io_registered = 1;
+ }
+
+ /* I/O system registered and initialized
+ * Now we take care of device initialization.
+ */
+
+ if ( b1553rt_device_init(priv) ) {
+ return DRVMGR_FAIL;
+ }
+
+ /* Get Filesystem name prefix */
+ prefix[0] = '\0';
+ if ( drvmgr_get_dev_prefix(dev, prefix) ) {
+ /* Failed to get prefix, make sure of a unique FS name
+ * by using the driver minor.
+ */
+ sprintf(priv->devName, "/dev/b1553rt%d", dev->minor_drv);
+ } else {
+ /* Got special prefix, this means we have a bus prefix
+ * And we should use our "bus minor"
+ */
+ sprintf(priv->devName, "/dev/%sb1553rt%d", prefix, dev->minor_bus);
+ }
+
+ /* Register Device */
+ status = rtems_io_register_name(priv->devName, b1553rt_driver_io_major, dev->minor_drv);
+ if (status != RTEMS_SUCCESSFUL) {
+ return DRVMGR_FAIL;
+ }
+
+ return DRVMGR_OK;
+}
+
+int b1553rt_remove(struct drvmgr_dev *dev)
+{
+ /* Stop more tasks to open driver */
+
+ /* Throw out all tasks using this driver */
+
+ /* Unregister I/O node */
+
+ /* Unregister and disable Interrupt */
+
+ /* Free device memory */
+
+ /* Return sucessfully */
+
+ return DRVMGR_FAIL;
+}
+
+/******************* Driver Implementation ***********************/
+
+int b1553rt_register_io(rtems_device_major_number *m)
+{
+ rtems_status_code r;
+
+ if ((r = rtems_io_register_driver(0, &b1553rt_driver, m)) == RTEMS_SUCCESSFUL) {
+ DBG("B1553RT driver successfully registered, major: %d\n", *m);
+ } else {
+ switch(r) {
+ case RTEMS_TOO_MANY:
+ printk("B1553RT rtems_io_register_driver failed: RTEMS_TOO_MANY\n");
+ return -1;
+ case RTEMS_INVALID_NUMBER:
+ printk("B1553RT rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n");
+ return -1;
+ case RTEMS_RESOURCE_IN_USE:
+ printk("B1553RT rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n");
+ return -1;
+ default:
+ printk("B1553RT rtems_io_register_driver failed\n");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int b1553rt_device_init(rt_priv *pDev)
+{
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
+ union drvmgr_key_value *value;
+ char *mem;
+ unsigned int sys_freq_hz;
+
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)pDev->dev->businfo;
+ if ( ambadev == NULL ) {
+ return -1;
+ }
+ pnpinfo = &ambadev->info;
+ pDev->irqno = pnpinfo->irq;
+ pDev->regs = (struct rt_reg *)pnpinfo->apb_slv->start;
+ pDev->minor = pDev->dev->minor_drv;
+
+#ifdef DEBUG
+ pDev->log_i = 0;
+ memset(pDev->log,0,sizeof(pDev->log));
+ printf("LOG: 0x%x\n", &pDev->log[0]);
+ printf("LOG_I: 0x%x\n", &pDev->log_i);
+#endif
+
+ /* Get memory configuration from bus resources */
+ value = drvmgr_dev_key_get(pDev->dev, "dmaBaseAdr", KEY_TYPE_POINTER);
+ if ( value ) {
+ mem = value->ptr;
+ if ( (unsigned int)mem & 1 ) {
+ /* Remote address, address as RT looks at it. */
+
+ /* Translate the base address into an address that the the CPU can understand */
+ mem = (char *)((unsigned int)mem & ~1);
+ drvmgr_translate(pDev->dev, 1, 1, (void *)mem, (void **)&mem);
+ }
+ } else {
+ /* Use dynamically allocated memory */
+ mem = (char *)malloc(4 * 1024 * 2); /* 4k DMA memory + 4k for alignment */
+ if ( !mem ){
+ printk("RT: Failed to allocate HW memory\n\r");
+ return -1;
+ }
+ }
+
+ /* align memory to 4k boundary */
+ mem = (char *)(((unsigned int)mem+0xfff) & ~0xfff);
+
+ /* clear the used memory */
+ memset(mem, 0, (4 * 1024));
+
+ /* Set base address of all descriptors */
+ pDev->memarea_base = (unsigned int)mem;
+ pDev->mem = (volatile unsigned short *) pDev->memarea_base;
+
+ /* Translate the base address into an address that the RT core can understand */
+ drvmgr_translate(pDev->dev, 0, 0, (void *)mem, (void **)&pDev->memarea_base_remote);
+
+ pDev->rt_event = NULL;
+
+ /* The RT is always clocked at the same frequency as the bus
+ * If the frequency doesnt match it is defaulted to 24MHz,
+ * user can always override it.
+ */
+ pDev->cfg_freq = RT_FREQ_24MHZ;
+
+ /* Get frequency in Hz */
+ if ( drvmgr_freq_get(pDev->dev, DEV_APB_SLV, &sys_freq_hz) == 0 ) {
+ if ( sys_freq_hz == 20000000 ) {
+ pDev->cfg_freq = RT_FREQ_20MHZ;
+ } else if ( sys_freq_hz == 16000000 ) {
+ pDev->cfg_freq = RT_FREQ_16MHZ;
+ } else if ( sys_freq_hz == 12000000 ) {
+ pDev->cfg_freq = RT_FREQ_12MHZ;
+ }
+ }
+
+ value = drvmgr_dev_key_get(pDev->dev, "coreFreq", KEY_TYPE_INT);
+ if ( value ) {
+ pDev->cfg_freq = value->i & RT_FREQ_MASK;
+ }
+
+ /* RX Semaphore created with count = 0 */
+ if ( rtems_semaphore_create(rtems_build_name('R', 'T', '0', '0' + pDev->minor),
+ 0,
+ RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &pDev->rx_sem) != RTEMS_SUCCESSFUL ) {
+ printk("RT: Failed to create rx semaphore\n");
+ return RTEMS_INTERNAL_ERROR;
+ }
+
+ /* Device Semaphore created with count = 1 */
+ if ( rtems_semaphore_create(rtems_build_name('R', 'T', '0', '0' + pDev->minor),
+ 1,
+ RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &pDev->dev_sem) != RTEMS_SUCCESSFUL ){
+ printk("RT: Failed to create device semaphore\n");
+ return RTEMS_INTERNAL_ERROR;
+ }
+
+ /* Default to RT-mode */
+ rt_init(pDev);
+
+ return 0;
+}
+
+static int odd_parity(unsigned int data)
+{
+ unsigned int i=0;
+
+ while(data)
+ {
+ i++;
+ data &= (data - 1);
+ }
+
+ return !(i&1);
+}
+
+static void start_operation(rt_priv *rt)
+{
+
+}
+
+static void stop_operation(rt_priv *rt)
+{
+
+}
+
+static void set_extmdata_en(rt_priv *rt, int extmdata)
+{
+ if ( extmdata )
+ extmdata = 1;
+ rt->ctrl_copy = (rt->ctrl_copy & ~(1<<16)) | (extmdata<<16);
+ rt->regs->ctrl = rt->ctrl_copy;
+}
+
+static void set_vector_word(rt_priv *rt, unsigned short vword)
+{
+ rt->regs->vword = vword;
+}
+
+/* Set clock speed */
+static void set_clkspd(rt_priv *rt, int spd)
+{
+ rt->ctrl_copy = (rt->ctrl_copy & ~0xC0) | (spd<<6);
+ rt->regs->ctrl = rt->ctrl_copy;
+ asm volatile("nop"::);
+ rt->regs->ctrl = rt->ctrl_copy | (1<<20);
+}
+
+static void set_rtaddr(rt_priv *rt, int addr)
+{
+ rt->ctrl_copy = (rt->ctrl_copy & ~0x3F00) | (addr << 8) | (odd_parity(addr)<<13);
+ rt->regs->ctrl = rt->ctrl_copy;
+}
+
+static void set_broadcast_en(rt_priv *rt, int data)
+{
+ rt->ctrl_copy = (rt->ctrl_copy & ~0x40000) | (data<<18);
+ rt->regs->ctrl = rt->ctrl_copy;
+}
+
+static rtems_device_driver rt_init(rt_priv *rt)
+{
+ rt->rx_blocking = 1;
+
+ if ( rt->rt_event )
+ free(rt->rt_event);
+ rt->rt_event = NULL;
+
+ rt->rt_event = (struct rt_msg *) malloc(EVENT_QUEUE_SIZE*sizeof(struct rt_msg));
+
+ if (rt->rt_event == NULL) {
+ DBG("RT driver failed to allocated memory.");
+ return RTEMS_NO_MEMORY;
+ }
+
+ rt->ctrl_copy = rt->regs->ctrl & 0x3F00; /* Keep rtaddr and rtaddrp */
+ rt->ctrl_copy |= 0x3C0D0; /* broadcast disabled, extmdata=1, writetsw = writecmd = 1 */
+ rt->regs->ctrl = rt->ctrl_copy;
+
+ /* Set Clock speed */
+ set_clkspd(rt, rt->cfg_freq);
+
+ rt->regs->addr = rt->memarea_base_remote;
+ rt->regs->ipm = 0x70000; /* Enable RT RX, MEM Failure and AHB Error interrupts */
+
+ DBG("B1553RT DMA_AREA: 0x%x\n", (unsigned int)rt->mem);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+
+static rtems_device_driver rt_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver rt_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) {
+ rt_priv *rt;
+ struct drvmgr_dev *dev;
+
+ FUNCDBG("rt_open\n");
+
+ if ( drvmgr_get_dev(&b1553rt_drv_info.general, minor, &dev) ) {
+ DBG("Wrong minor %d\n", minor);
+ return RTEMS_UNSATISFIED;
+ }
+ rt = (rt_priv *)dev->priv;
+
+ if (rtems_semaphore_obtain(rt->dev_sem, RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT) != RTEMS_SUCCESSFUL) {
+ DBG("rt_open: resource in use\n");
+ return RTEMS_RESOURCE_IN_USE; /* EBUSY */
+ }
+
+ /* Set defaults */
+ rt->event_id = 0;
+
+ start_operation(rt);
+
+ /* Register interrupt routine */
+ if (drvmgr_interrupt_register(rt->dev, 0, "b1553rt", b1553rt_interrupt, rt)) {
+ rtems_semaphore_release(rt->dev_sem);
+ return -1;
+ }
+
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver rt_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ rt_priv *rt;
+ struct drvmgr_dev *dev;
+
+ FUNCDBG("rt_close");
+
+ if ( drvmgr_get_dev(&b1553rt_drv_info.general, minor, &dev) ) {
+ return RTEMS_UNSATISFIED;
+ }
+ rt = (rt_priv *)dev->priv;
+
+ drvmgr_interrupt_unregister(rt->dev, 0, b1553rt_interrupt, rt);
+
+ stop_operation(rt);
+ rtems_semaphore_release(rt->dev_sem);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static int get_messages(rt_priv *rt, void *buf, unsigned int msg_count)
+{
+
+ struct rt_msg *dest = (struct rt_msg *) buf;
+ int count = 0;
+
+ if (rt->head == rt->tail) {
+ return 0;
+ }
+
+ do {
+
+ DBG("rt read - head: %d, tail: %d\n", rt->head, rt->tail);
+ dest[count++] = rt->rt_event[INDEX(rt->tail++)];
+
+ } while (rt->head != rt->tail && count < msg_count);
+
+ return count;
+
+}
+static rtems_device_driver rt_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ rtems_libio_rw_args_t *rw_args;
+ int count = 0;
+ rt_priv *rt;
+ struct drvmgr_dev *dev;
+
+ if ( drvmgr_get_dev(&b1553rt_drv_info.general, minor, &dev) ) {
+ return RTEMS_UNSATISFIED;
+ }
+ rt = (rt_priv *)dev->priv;
+
+ rw_args = (rtems_libio_rw_args_t *) arg;
+
+ FUNCDBG("rt_read [%i,%i]: buf: 0x%x, len: %i\n",major, minor, (unsigned int)rw_args->buffer, rw_args->count);
+
+ while ( (count = get_messages(rt,rw_args->buffer, rw_args->count)) == 0 ) {
+
+ if (rt->rx_blocking) {
+ rtems_semaphore_obtain(rt->rx_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+ } else {
+ /* Translates to EBUSY */
+ return RTEMS_RESOURCE_IN_USE;
+ }
+ }
+
+ rw_args->bytes_moved = count;
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver rt_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ rtems_libio_rw_args_t *rw_args;
+ struct rt_msg *source;
+ rt_priv *rt;
+ struct drvmgr_dev *dev;
+ unsigned int descriptor, suba, wc;
+
+ if ( drvmgr_get_dev(&b1553rt_drv_info.general, minor, &dev) ) {
+ return RTEMS_UNSATISFIED;
+ }
+ rt = (rt_priv *)dev->priv;
+
+ rw_args = (rtems_libio_rw_args_t *) arg;
+
+ if ( rw_args->count != 1 ) {
+ return RTEMS_INVALID_NAME;
+ }
+
+ source = (struct rt_msg *) rw_args->buffer;
+
+ descriptor = source[0].desc & 0x7F;
+ suba = descriptor-32;
+ wc = source[0].miw >> 11;
+ wc = wc ? wc : 32;
+
+ FUNCDBG("rt_write [%i,%i]: buf: 0x%x\n",major, minor, (unsigned int)rw_args->buffer);
+
+ memcpy((void *)&rt->mem[0x400 + suba*32], &source[0].data[0], wc*2);
+
+ rw_args->bytes_moved = 1;
+
+ return RTEMS_SUCCESSFUL;
+
+}
+
+static rtems_device_driver rt_control(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *) arg;
+ unsigned int *data = ioarg->buffer;
+
+ rt_priv *rt;
+ struct drvmgr_dev *dev;
+
+ FUNCDBG("rt_control[%d]: [%i,%i]\n", minor, major, minor);
+
+ if ( drvmgr_get_dev(&b1553rt_drv_info.general, minor, &dev) ) {
+ return RTEMS_UNSATISFIED;
+ }
+ rt = (rt_priv *)dev->priv;
+
+ if (!ioarg) {
+ DBG("rt_control: invalid argument\n");
+ return RTEMS_INVALID_NAME;
+ }
+
+ ioarg->ioctl_return = 0;
+ switch (ioarg->command) {
+
+ case RT_SET_ADDR:
+ set_rtaddr(rt, data[0]);
+ break;
+
+ case RT_SET_BCE:
+ set_broadcast_en(rt, data[0]);
+ break;
+
+ case RT_SET_VECTORW:
+ set_vector_word(rt, data[0]);
+ break;
+
+ case RT_SET_EXTMDATA:
+ set_extmdata_en(rt, data[0]);
+ break;
+
+ case RT_RX_BLOCK:
+ rt->rx_blocking = data[0];
+ break;
+
+ case RT_CLR_STATUS:
+ rt->status = 0;
+ break;
+
+ case RT_GET_STATUS: /* copy status */
+ if ( !ioarg->buffer )
+ return RTEMS_INVALID_NAME;
+
+ *(unsigned int *)ioarg->buffer = rt->status;
+ break;
+
+ case RT_SET_EVENTID:
+ rt->event_id = (rtems_id)ioarg->buffer;
+ break;
+
+ default:
+ return RTEMS_NOT_IMPLEMENTED;
+ }
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static void b1553rt_interrupt(void *arg)
+{
+ rt_priv *rt = arg;
+ unsigned short descriptor;
+ int signal_event=0, wake_rx_task=0;
+ unsigned int event_status=0;
+ unsigned int wc, irqv, cmd, tsw, suba, tx, miw, i;
+ unsigned int ipend;
+
+ #define SET_ERROR_DESCRIPTOR(descriptor) (event_status = (event_status & 0x0000ffff) | descriptor<<16)
+ ipend = rt->regs->ipm;
+
+ if (ipend == 0) {
+ /* IRQ mask has been cleared, we must have been reset */
+ /* Restore ctrl registers */
+ rt->regs->ctrl = rt->ctrl_copy;
+ rt->regs->addr = rt->memarea_base_remote;
+ rt->regs->ipm = 0x70000;
+ /* Send reset mode code event */
+ if (rt->head - rt->tail != EVENT_QUEUE_SIZE) {
+ miw = (8<<11);
+ descriptor = 64 + 32 + 8;
+ rt->rt_event[INDEX(rt->head)].miw = miw;
+ rt->rt_event[INDEX(rt->head)].time = 0;
+ rt->rt_event[INDEX(rt->head)].desc = descriptor;
+ rt->head++;
+ }
+ }
+
+ if ( ipend & 0x1 ) {
+ /* RT IRQ */
+ if (rt->head - rt->tail != EVENT_QUEUE_SIZE) {
+
+ irqv = rt->regs->irq;
+ cmd = irqv >> 7;
+ wc = cmd & 0x1F; /* word count / mode code */
+ suba = irqv & 0x1F; /* sub address (0-31) */
+ tx = (irqv >> 5) & 1;
+
+ /* read status word */
+ tsw = READ_DMA(&rt->mem[tx*0x3E0+suba]);
+
+ /* Build Message Information Word (B1553BRM-style) */
+ miw = (wc<<11) | (tsw&RT_TSW_BUS)>>4 | !(tsw&RT_TSW_OK)>>7 | (tsw&RT_TSW_ILL)>>5 |
+ (tsw&RT_TSW_PAR)>>5 | (tsw&RT_TSW_MAN)>>7;
+
+ descriptor = (tx << 5) | suba;
+
+ /* Mode codes */
+ if (suba == 0 || suba == 31) {
+ descriptor = 64 + (tx*32) + wc;
+ }
+
+ /* Data received or transmitted */
+ if (descriptor < 64) {
+ wc = wc ? wc : 32; /* wc = 0 means 32 words transmitted */
+ }
+ /* RX Mode code */
+ else if (descriptor < 96) {
+ wc = (wc>>4);
+ }
+ /* TX Mode code */
+ else if (descriptor < 128) {
+ wc = (wc>>4);
+ }
+
+ /* Copy to event queue */
+ rt->rt_event[INDEX(rt->head)].miw = miw;
+ rt->rt_event[INDEX(rt->head)].time = 0;
+
+ for (i = 0; i < wc; i++) {
+ rt->rt_event[INDEX(rt->head)].data[i] = READ_DMA(&rt->mem[tx*0x400 + suba*32 + i]);
+ }
+ rt->rt_event[INDEX(rt->head)].desc = descriptor;
+ rt->head++;
+
+
+ /* Handle errors */
+ if ( tsw & RT_TSW_ILL){
+ FUNCDBG("RT: RT_ILLCMD\n\r");
+ rt->status |= RT_ILLCMD_IRQ;
+ event_status |= RT_ILLCMD_IRQ;
+ SET_ERROR_DESCRIPTOR(descriptor);
+ signal_event=1;
+ }
+
+ if ( !(tsw & RT_TSW_OK) ) {
+ FUNCDBG("RT: RT_MERR_IRQ\n\r");
+ rt->status |= RT_MERR_IRQ;
+ event_status |= RT_MERR_IRQ;
+ SET_ERROR_DESCRIPTOR(descriptor);
+ signal_event=1;
+ }
+
+ }
+ else {
+ /* Indicate overrun */
+ rt->rt_event[INDEX(rt->head)].desc |= 0x8000;
+ }
+ }
+
+ if ( ipend & 0x2 ) {
+ /* Memory failure IRQ */
+ FUNCDBG("B1553RT: Memory failure\n");
+ event_status |= RT_DMAF_IRQ;
+ signal_event=1;
+ }
+
+ if ( ipend & 0x4 ) {
+ /* AHB Error */
+ FUNCDBG("B1553RT: AHB ERROR\n");
+ event_status |= RT_DMAF_IRQ;
+ signal_event=1;
+ }
+
+#ifdef DEBUG
+ rt->log[rt->log_i++ % EVENT_QUEUE_SIZE] = descriptor;
+ rt->log[rt->log_i++ % EVENT_QUEUE_SIZE] = cmd;
+ rt->log[rt->log_i++ % EVENT_QUEUE_SIZE] = miw;
+ rt->log[rt->log_i++ % EVENT_QUEUE_SIZE] = tsw;
+#endif
+
+ wake_rx_task = 1;
+
+ /* Wake any blocked rx thread only on receive interrupts */
+ if ( wake_rx_task ) {
+ rtems_semaphore_release(rt->rx_sem);
+ }
+
+ /* Copy current mask to status mask */
+ if ( event_status ) {
+ if ( event_status & 0xffff0000 )
+ rt->status &= 0x0000ffff;
+ rt->status |= event_status;
+ }
+
+ /* signal event once */
+ if ( signal_event && (rt->event_id != 0) ) {
+ rtems_event_send(rt->event_id, event_status);
+ }
+
+}
+
+void b1553rt_print_dev(struct drvmgr_dev *dev, int options)
+{
+ rt_priv *pDev = dev->priv;
+ struct amba_dev_info *devinfo;
+
+ devinfo = (struct amba_dev_info *)pDev->dev->businfo;
+
+ /* Print */
+ printf("--- B1553RT[%d] %s ---\n", pDev->minor, pDev->devName);
+ printf(" REGS: 0x%x\n", (unsigned int)pDev->regs);
+ printf(" IRQ: %d\n", pDev->irqno);
+
+}
+
+void b1553rt_print(int options)
+{
+ struct amba_drv_info *drv = &b1553rt_drv_info;
+ struct drvmgr_dev *dev;
+
+ dev = drv->general.dev;
+ while(dev) {
+ b1553rt_print_dev(dev, options);
+ dev = dev->next_in_drv;
+ }
+}
diff --git a/c/src/lib/libbsp/sparc/shared/1553/gr1553b.c b/c/src/lib/libbsp/sparc/shared/1553/gr1553b.c
new file mode 100644
index 0000000000..3c86349202
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/1553/gr1553b.c
@@ -0,0 +1,313 @@
+/* GR1553B driver, used by BC, RT and/or BM driver
+ *
+ * COPYRIGHT (c) 2010.
+ * Aeroflex Gaisler.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2010-03-15, Daniel Hellstrom <daniel@gaisler.com>
+ * Created
+ *
+ *
+ * OVERVIEW
+ * ========
+ * See header file
+ */
+
+#include <stdlib.h>
+#include <drvmgr/ambapp_bus.h>
+
+#include <gr1553b.h>
+
+/* Driver Manager interface for BC, RT, BM, BRM, BC-BM and RT-BM */
+
+#define GR1553B_WRITE_REG(adr, val) *(volatile uint32_t *)(adr) = (val)
+#define GR1553B_READ_REG(adr) (*(volatile uint32_t *)(adr))
+
+#define FEAT_BC 0x1
+#define FEAT_RT 0x2
+#define FEAT_BM 0x4
+
+#define ALLOC_BC 0x1
+#define ALLOC_RT 0x2
+#define ALLOC_BM 0x4
+
+struct gr1553_device {
+ struct drvmgr_dev *dev;
+ int features;
+ int alloc;
+};
+
+struct gr1553_device_feature {
+ struct gr1553_device_feature *next;
+ struct gr1553_device *dev;
+ int minor;
+};
+
+/* Device lists */
+struct gr1553_device_feature *gr1553_bm_root = NULL;
+struct gr1553_device_feature *gr1553_rt_root = NULL;
+struct gr1553_device_feature *gr1553_bc_root = NULL;
+
+/* Driver registered */
+int gr1553_driver_registerd = 0;
+
+/* Add 'feat' to linked list pointed to by 'root'. A minor is also assigned. */
+void gr1553_list_add
+ (
+ struct gr1553_device_feature **root,
+ struct gr1553_device_feature *feat
+ )
+{
+ int minor;
+ struct gr1553_device_feature *curr;
+
+ if ( *root == NULL ) {
+ *root = feat;
+ feat->next = NULL;
+ feat->minor = 0;
+ return;
+ }
+
+ minor = 0;
+retry_new_minor:
+ curr = *root;
+ while ( curr->next ) {
+ if ( curr->minor == minor ) {
+ minor++;
+ goto retry_new_minor;
+ }
+ curr = curr->next;
+ }
+
+ feat->next = NULL;
+ feat->minor = minor;
+ curr->next = feat;
+}
+
+struct gr1553_device_feature *gr1553_list_find
+ (
+ struct gr1553_device_feature *root,
+ int minor
+ )
+{
+ struct gr1553_device_feature *curr = root;
+ while ( curr ) {
+ if ( curr->minor == minor ) {
+ return curr;
+ }
+ curr = curr->next;
+ }
+ return NULL;
+}
+
+struct drvmgr_dev **gr1553_bc_open(int minor)
+{
+ struct gr1553_device_feature *feat;
+
+ feat = gr1553_list_find(gr1553_bc_root, minor);
+ if ( feat == NULL )
+ return NULL;
+
+ /* Only possible to allocate is RT and BC is free,
+ * this is beacuse it is not possible to use the
+ * RT and the BC at the same time.
+ */
+ if ( feat->dev->alloc & (ALLOC_BC|ALLOC_RT) )
+ return NULL;
+
+ /* Alloc BC device */
+ feat->dev->alloc |= ALLOC_BC;
+
+ return &feat->dev->dev;
+}
+
+void gr1553_bc_close(struct drvmgr_dev **dev)
+{
+ struct gr1553_device *d = (struct gr1553_device *)dev;
+
+ d->alloc &= ~ALLOC_BC;
+}
+
+struct drvmgr_dev **gr1553_rt_open(int minor)
+{
+ struct gr1553_device_feature *feat;
+
+ feat = gr1553_list_find(gr1553_rt_root, minor);
+ if ( feat == NULL )
+ return NULL;
+
+ /* Only possible to allocate is RT and BC is free,
+ * this is beacuse it is not possible to use the
+ * RT and the BC at the same time.
+ */
+ if ( feat->dev->alloc & (ALLOC_BC|ALLOC_RT) )
+ return NULL;
+
+ /* Alloc RT device */
+ feat->dev->alloc |= ALLOC_RT;
+
+ return &feat->dev->dev;
+}
+
+void gr1553_rt_close(struct drvmgr_dev **dev)
+{
+ struct gr1553_device *d = (struct gr1553_device *)dev;
+
+ d->alloc &= ~ALLOC_RT;
+}
+
+struct drvmgr_dev **gr1553_bm_open(int minor)
+{
+ struct gr1553_device_feature *feat;
+
+ feat = gr1553_list_find(gr1553_bm_root, minor);
+ if ( feat == NULL )
+ return NULL;
+
+ /* Only possible to allocate is RT and BC is free,
+ * this is beacuse it is not possible to use the
+ * RT and the BC at the same time.
+ */
+ if ( feat->dev->alloc & ALLOC_BM )
+ return NULL;
+
+ /* Alloc BM device */
+ feat->dev->alloc |= ALLOC_BM;
+
+ return &feat->dev->dev;
+}
+
+void gr1553_bm_close(struct drvmgr_dev **dev)
+{
+ struct gr1553_device *d = (struct gr1553_device *)dev;
+
+ d->alloc &= ~ALLOC_BM;
+}
+
+int gr1553_init2(struct drvmgr_dev *dev)
+{
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
+ struct gr1553b_regs *regs;
+
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)dev->businfo;
+ if ( ambadev == NULL ) {
+ return DRVMGR_FAIL;
+ }
+ pnpinfo = &ambadev->info;
+ regs = (struct gr1553b_regs *)pnpinfo->apb_slv->start;
+
+ /* Stop IRQ */
+ GR1553B_WRITE_REG(&regs->imask, 0);
+ GR1553B_WRITE_REG(&regs->irq, 0xffffffff);
+ /* Stop BC if not already stopped (just in case) */
+ GR1553B_WRITE_REG(&regs->bc_ctrl, 0x15520204);
+ /* Stop RT rx (just in case) */
+ GR1553B_WRITE_REG(&regs->rt_cfg, 0x15530000);
+ /* Stop BM logging (just in case) */
+ GR1553B_WRITE_REG(&regs->bm_ctrl, 0);
+
+ return DRVMGR_OK;
+}
+
+/* Register the different functionalities that the
+ * core supports.
+ */
+int gr1553_init3(struct drvmgr_dev *dev)
+{
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
+ struct gr1553_device *priv;
+ struct gr1553_device_feature *feat;
+ struct gr1553b_regs *regs;
+
+ priv = malloc(sizeof(struct gr1553_device));
+ if ( priv == NULL )
+ return DRVMGR_NOMEM;
+ priv->dev = dev;
+ priv->alloc = 0;
+ priv->features = 0;
+ dev->priv = NULL; /* Let higher level driver handle this */
+
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)dev->businfo;
+ if ( ambadev == NULL ) {
+ return DRVMGR_FAIL;
+ }
+ pnpinfo = &ambadev->info;
+ regs = (struct gr1553b_regs *)pnpinfo->apb_slv->start;
+
+ if ( GR1553B_READ_REG(&regs->bm_stat) & GR1553B_BM_STAT_BMSUP ) {
+ priv->features |= FEAT_BM;
+ feat = malloc(sizeof(struct gr1553_device_feature));
+ feat->dev = priv;
+ /* Init Minor and Next */
+ gr1553_list_add(&gr1553_bm_root, feat);
+ }
+
+ if ( GR1553B_READ_REG(&regs->bc_stat) & GR1553B_BC_STAT_BCSUP ) {
+ priv->features |= FEAT_BC;
+ feat = malloc(sizeof(struct gr1553_device_feature));
+ feat->dev = priv;
+ /* Init Minor and Next */
+ gr1553_list_add(&gr1553_bc_root, feat);
+ }
+
+ if ( GR1553B_READ_REG(&regs->rt_stat) & GR1553B_RT_STAT_RTSUP ) {
+ priv->features |= FEAT_RT;
+ feat = malloc(sizeof(struct gr1553_device_feature));
+ feat->dev = priv;
+ /* Init Minor and Next */
+ gr1553_list_add(&gr1553_rt_root, feat);
+ }
+
+ return DRVMGR_OK;
+}
+
+struct drvmgr_drv_ops gr1553_ops =
+{
+ {NULL, gr1553_init2, gr1553_init3, NULL},
+ NULL,
+ NULL
+};
+
+struct amba_dev_id gr1553_ids[] =
+{
+ {VENDOR_GAISLER, GAISLER_GR1553B},
+ {0, 0} /* Mark end of table */
+};
+
+struct amba_drv_info gr1553_drv_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_AMBAPP_GAISLER_GR1553B_ID,/* Driver ID */
+ "GR1553_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */
+ &gr1553_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ 0,
+ },
+ &gr1553_ids[0]
+};
+
+/* Multiple drivers may call this function. The drivers that depends on
+ * this driver:
+ * - BM driver
+ * - BC driver
+ * - RT driver
+ */
+void gr1553_register(void)
+{
+ if ( gr1553_driver_registerd == 0 ) {
+ gr1553_driver_registerd = 1;
+ drvmgr_drv_register(&gr1553_drv_info.general);
+ }
+}
diff --git a/c/src/lib/libbsp/sparc/shared/1553/gr1553bc.c b/c/src/lib/libbsp/sparc/shared/1553/gr1553bc.c
new file mode 100644
index 0000000000..d409761994
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/1553/gr1553bc.c
@@ -0,0 +1,1682 @@
+/* GR1553B BC driver
+ *
+ * COPYRIGHT (c) 2010.
+ * Aeroflex Gaisler.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2010-03-15, Daniel Hellstrom <daniel@gaisler.com>
+ * Created
+ *
+ *
+ * OVERVIEW
+ * ========
+ * See header file and list header file.
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+
+#include <gr1553b.h>
+#include <gr1553bc.h>
+
+#define GR1553BC_WRITE_MEM(adr, val) *(volatile uint32_t *)(adr) = (uint32_t)(val)
+#define GR1553BC_READ_MEM(adr) (*(volatile uint32_t *)(adr))
+
+#define GR1553BC_WRITE_REG(adr, val) *(volatile uint32_t *)(adr) = (uint32_t)(val)
+#define GR1553BC_READ_REG(adr) (*(volatile uint32_t *)(adr))
+
+#ifndef IRQ_GLOBAL_PREPARE
+ #define IRQ_GLOBAL_PREPARE(level) rtems_interrupt_level level
+#endif
+
+#ifndef IRQ_GLOBAL_DISABLE
+ #define IRQ_GLOBAL_DISABLE(level) rtems_interrupt_disable(level)
+#endif
+
+#ifndef IRQ_GLOBAL_ENABLE
+ #define IRQ_GLOBAL_ENABLE(level) rtems_interrupt_enable(level)
+#endif
+
+/* Needed by list for data pinter and BD translation */
+struct gr1553bc_priv {
+ struct drvmgr_dev **pdev;
+ struct gr1553b_regs *regs;
+ struct gr1553bc_list *list;
+ struct gr1553bc_list *alist;
+ int started;
+
+ /* IRQ log management */
+ void *irq_log_p;
+ uint32_t *irq_log_base;
+ uint32_t *irq_log_curr;
+ uint32_t *irq_log_end;
+ uint32_t *irq_log_base_hw;
+
+ /* Standard IRQ handler function */
+ bcirq_func_t irq_func;
+ void *irq_data;
+};
+
+
+/*************** LIST HANDLING ROUTINES ***************/
+
+/* This marks that the jump is a jump to next Minor.
+ * It is important that it sets one of the two LSB
+ * so that we can separate it from a JUMP-IRQ function,
+ * function pointers must be aligned to 4bytes.
+ *
+ * This marker is used to optimize the INDICATION process,
+ * from a descriptor pointer we can step to next Jump that
+ * has this MARKER set, then we know that the MID is stored
+ * there.
+ *
+ * The marker is limited to 1 byte.
+ */
+#define NEXT_MINOR_MARKER 0x01
+
+/* To separate ASYNC list from SYNC list we mark them differently, but with
+ * LSB always set. This can be used to get the list the descriptor is a part
+ * of.
+ */
+#define NEXT_MINOR_MARKER_ASYNC 0x80
+
+struct gr1553bc_list_cfg gr1553bc_def_cfg =
+{
+ .rt_timeout =
+ {
+ 20, 20, 20, 20,
+ 20, 20, 20, 20,
+ 20, 20, 20, 20,
+ 20, 20, 20, 20,
+ 20, 20, 20, 20,
+ 20, 20, 20, 20,
+ 20, 20, 20, 20,
+ 20, 20, 20
+ },
+ .bc_timeout = 30,
+ .tropt_irq_on_err = 0,
+ .tropt_pause_on_err = 0,
+ .async_list = 0,
+};
+
+int gr1553bc_list_alloc(struct gr1553bc_list **list, int max_major)
+{
+ int size;
+ struct gr1553bc_list *l;
+
+ size = sizeof(struct gr1553bc_list) + max_major * sizeof(void *);
+ l = malloc(size);
+ if ( l == NULL )
+ return -1;
+ memset(l, 0, size);
+
+ l->major_cnt = max_major;
+ *list = l;
+
+ /* Set default options:
+ * - RT timeout tolerance 20us
+ * - Global transfer options used when generating transfer descriptors
+ * - No BC device, note that this only works when no translation is
+ * required
+ */
+ if ( gr1553bc_list_config(l, &gr1553bc_def_cfg, NULL) ) {
+ free(l);
+ return -1;
+ }
+
+ return 0;
+}
+
+void gr1553bc_list_free(struct gr1553bc_list *list)
+{
+ gr1553bc_list_table_free(list);
+ free(list);
+}
+
+int gr1553bc_list_config
+ (
+ struct gr1553bc_list *list,
+ struct gr1553bc_list_cfg *cfg,
+ void *bc
+ )
+{
+ int timeout, i, tropts;
+
+ /* RT Time Tolerances */
+ for (i=0; i<31; i++) {
+ /* 0=14us, 1=18us ... 0xf=74us
+ * round upwards: 15us will be 18us
+ */
+ timeout = ((cfg->rt_timeout[i] + 1) - 14) / 4;
+ if ( (timeout > 0xf) || (timeout < 0) )
+ return -1;
+ list->rt_timeout[i] = timeout;
+ }
+ timeout = ((cfg->bc_timeout + 1) - 14) / 4;
+ if ( timeout > 0xf )
+ return -1;
+ list->rt_timeout[i] = timeout;
+
+ /* Transfer descriptor generation options */
+ tropts = 0;
+ if ( cfg->tropt_irq_on_err )
+ tropts |= 1<<28;
+ if ( cfg->tropt_pause_on_err )
+ tropts |= 1<<26;
+ list->tropts = tropts;
+
+ list->async_list = cfg->async_list;
+ list->bc = bc;
+
+ return 0;
+}
+
+void gr1553bc_list_link_major(
+ struct gr1553bc_major *major,
+ struct gr1553bc_major *next
+ )
+{
+ if ( major ) {
+ major->next = next;
+ if ( next ) {
+ major->minors[major->cfg->minor_cnt-1]->next =
+ next->minors[0];
+ } else {
+ major->minors[major->cfg->minor_cnt-1]->next = NULL;
+ }
+ }
+}
+
+int gr1553bc_list_set_major(
+ struct gr1553bc_list *list,
+ struct gr1553bc_major *major,
+ int no)
+{
+ struct gr1553bc_major *prev, *next;
+
+ if ( no >= list->major_cnt )
+ return -1;
+
+ list->majors[no] = major;
+
+ /* Link previous Major frame with this one */
+ if ( no > 0 ) {
+ prev = list->majors[no-1];
+ } else {
+ /* First Major is linked with last major */
+ prev = list->majors[list->major_cnt-1];
+ }
+
+ /* Link to next Major if not the last one and if there is
+ * a next major
+ */
+ if ( no == list->major_cnt-1 ) {
+ /* The last major, assume that it is connected with the first */
+ next = list->majors[0];
+ } else {
+ next = list->majors[no+1];
+ }
+
+ /* Link previous frame to jump into this */
+ gr1553bc_list_link_major(prev, major);
+
+ /* Link This frame to jump into the next */
+ gr1553bc_list_link_major(major, next);
+
+ return 0;
+}
+
+/* Translate Descriptor address from CPU-address to Hardware Address */
+static inline union gr1553bc_bd *gr1553bc_bd_cpu2hw
+ (
+ struct gr1553bc_list *list,
+ union gr1553bc_bd *bd
+ )
+{
+ return (union gr1553bc_bd *)(((unsigned int)bd - list->table_cpu) +
+ list->table_hw);
+}
+
+/* Translate Descriptor address from HW-address to CPU Address */
+static inline union gr1553bc_bd *gr1553bc_bd_hw2cpu
+ (
+ struct gr1553bc_list *list,
+ union gr1553bc_bd *bd
+ )
+{
+ return (union gr1553bc_bd *)(((unsigned int)bd - list->table_hw) +
+ list->table_cpu);
+}
+
+int gr1553bc_minor_table_size(struct gr1553bc_minor *minor)
+{
+ struct gr1553bc_minor_cfg *mincfg = minor->cfg;
+ int slot_cnt;
+
+ /* SLOTS + JUMP */
+ slot_cnt = mincfg->slot_cnt + 1;
+ if ( mincfg->timeslot ) {
+ /* time management requires 1 extra slot */
+ slot_cnt++;
+ }
+
+ return slot_cnt * GR1553BC_BD_SIZE;
+}
+
+int gr1553bc_list_table_size(struct gr1553bc_list *list)
+{
+ struct gr1553bc_major *major;
+ int i, j, minor_cnt, size;
+
+ size = 0;
+ for (i=0; i<list->major_cnt; i++) {
+ major = list->majors[i];
+ minor_cnt = major->cfg->minor_cnt;
+ for (j=0; j<minor_cnt; j++) {
+ /* 128-bit Alignment required by HW */
+ size += (GR1553BC_BD_ALIGN -
+ (size & (GR1553BC_BD_ALIGN-1))) &
+ ~(GR1553BC_BD_ALIGN-1);
+
+ /* Size required by descriptors */
+ size += gr1553bc_minor_table_size(major->minors[j]);
+ }
+ }
+
+ return size;
+}
+
+int gr1553bc_list_table_alloc
+ (
+ struct gr1553bc_list *list,
+ void *bdtab_custom
+ )
+{
+ struct gr1553bc_major *major;
+ int i, j, minor_cnt, size;
+ unsigned int table;
+ struct gr1553bc_priv *bcpriv = list->bc;
+
+ /* Free previous allocated descriptor table */
+ gr1553bc_list_table_free(list);
+
+ /* Remember user's settings for uninitialization */
+ list->_table_custom = bdtab_custom;
+
+ if ( bdtab_custom == NULL ) {
+ /* Get Size required for descriptors */
+ size = gr1553bc_list_table_size(list);
+
+ /* Allocate descriptors */
+ list->_table = malloc(size + (GR1553BC_BD_ALIGN-1));
+ if ( list->_table == NULL )
+ return -1;
+ } else if ( (unsigned int)bdtab_custom & 0x1 ) {
+ /* Address given in Hardware accessible address, we
+ * convert it into CPU-accessible address.
+ */
+ drvmgr_translate(
+ *bcpriv->pdev,
+ 1,
+ 1,
+ (void *)((unsigned int)bdtab_custom & ~0x1),
+ (void **)&list->_table
+ );
+ } else {
+ /* Custom address, given in CPU-accessible address */
+ list->_table = bdtab_custom;
+ }
+
+ /* 128-bit Alignment required by HW */
+ table = (unsigned int)list->_table;
+ table = (table + (GR1553BC_BD_ALIGN-1)) & ~(GR1553BC_BD_ALIGN-1);
+ list->table_cpu = table;
+ list->table_hw = table;
+
+ /* We got CPU accessible descriptor table address, now we translate
+ * that into an address which the Hardware can understand
+ */
+ if ( bcpriv ) {
+ drvmgr_translate(
+ *bcpriv->pdev,
+ 0,
+ 0,
+ (void *)list->table_cpu,
+ (void **)&list->table_hw
+ );
+ }
+
+ /* Write End-Of-List all over the descriptor table here,
+ * For debugging/safety?
+ */
+
+ /* Assign descriptors to all minor frames. The addresses is
+ * CPU-accessible addresses.
+ */
+ for (i=0; i<list->major_cnt; i++) {
+ major = list->majors[i];
+ minor_cnt = major->cfg->minor_cnt;
+ for (j=0; j<minor_cnt; j++) {
+ /* 128-bit Alignment required by HW */
+ table = (table + (GR1553BC_BD_ALIGN-1)) &
+ ~(GR1553BC_BD_ALIGN-1);
+ major->minors[j]->bds = (union gr1553bc_bd *)table;
+
+ /* Calc size required by descriptors */
+ table += gr1553bc_minor_table_size(major->minors[j]);
+ }
+ }
+
+ return 0;
+}
+
+void gr1553bc_list_table_free(struct gr1553bc_list *list)
+{
+ if ( (list->_table_custom == NULL) && list->_table ) {
+ free(list->_table);
+ }
+ list->_table = NULL;
+ list->_table_custom = NULL;
+ list->table_cpu = 0;
+ list->table_hw = 0;
+}
+
+/* Init descriptor table provided by each minor frame,
+ * we link them together using unconditional JUMP.
+ */
+int gr1553bc_list_table_build(struct gr1553bc_list *list)
+{
+ struct gr1553bc_major *major;
+ struct gr1553bc_minor *minor;
+ struct gr1553bc_minor_cfg *mincfg;
+ int i, j, k, minor_cnt, marker;
+ union gr1553bc_bd *bds, *hwbd;
+
+ marker = NEXT_MINOR_MARKER;
+ if ( list->async_list )
+ marker |= NEXT_MINOR_MARKER_ASYNC;
+
+ /* Create Major linking */
+ for (i=0; i<list->major_cnt; i++) {
+ major = list->majors[i];
+ minor_cnt = major->cfg->minor_cnt;
+ for (j=0; j<minor_cnt; j++) {
+ minor = major->minors[j];
+ mincfg = minor->cfg;
+ bds = minor->bds;
+
+ /* BD[0..SLOTCNT-1] = message slots
+ * BD[SLOTCNT+0] = END
+ * BD[SLOTCNT+1] = JUMP
+ *
+ * or if no optional time slot handling:
+ *
+ * BD[0..SLOTCNT-1] = message slots
+ * BD[SLOTCNT] = JUMP
+ */
+
+ /* BD[0..SLOTCNT-1] */
+ for (k=0; k<mincfg->slot_cnt; k++) {
+ gr1553bc_bd_tr_init(
+ &bds[k].tr,
+ GR1553BC_TR_DUMMY_0,
+ GR1553BC_TR_DUMMY_1,
+ 0,
+ 0);
+ }
+
+ /* BD[SLOTCNT] (OPTIONAL)
+ * If a minor frame is configured to be executed in
+ * certain time (given a time slot), this descriptor
+ * sums up all unused time. The time slot is
+ * decremented when messages are inserted into the
+ * minor frame and increased when messages are removed.
+ */
+ if ( mincfg->timeslot > 0 ) {
+ gr1553bc_bd_tr_init(
+ &bds[k].tr,
+ GR1553BC_TR_DUMMY_0 | (mincfg->timeslot >> 2),
+ GR1553BC_TR_DUMMY_1,
+ 0,
+ 0);
+ k++;
+ }
+
+ /* Last descriptor is a jump to next minor frame, to a
+ * synchronization point. If chain ends here, the list
+ * is marked with a "end-of-list" marker.
+ *
+ */
+ if ( minor->next ) {
+ /* Translate CPU address of BD into HW address */
+ hwbd = gr1553bc_bd_cpu2hw(
+ list,
+ &minor->next->bds[0]
+ );
+ gr1553bc_bd_init(
+ &bds[k],
+ 0xf,
+ GR1553BC_UNCOND_JMP,
+ (uint32_t)hwbd,
+ ((GR1553BC_ID(i,j,k) << 8) | marker),
+ 0
+ );
+ } else {
+ gr1553bc_bd_init(
+ &bds[k],
+ 0xf,
+ GR1553BC_TR_EOL,
+ 0,
+ ((GR1553BC_ID(i,j,k) << 8) | marker),
+ 0);
+ }
+ }
+ }
+
+ return 0;
+}
+
+void gr1553bc_bd_init(
+ union gr1553bc_bd *bd,
+ unsigned int flags,
+ uint32_t word0,
+ uint32_t word1,
+ uint32_t word2,
+ uint32_t word3
+ )
+{
+ struct gr1553bc_bd_raw *raw = &bd->raw;
+
+ if ( flags & 0x1 ) {
+ if ( (flags & KEEP_TIMESLOT) &&
+ ((word0 & GR1553BC_BD_TYPE) == 0) ) {
+ /* Don't touch timeslot previously allocated */
+ word0 &= ~GR1553BC_TR_TIME;
+ word0 |= GR1553BC_READ_MEM(&raw->words[0]) &
+ GR1553BC_TR_TIME;
+ }
+ GR1553BC_WRITE_MEM(&raw->words[0], word0);
+ }
+ if ( flags & 0x2 )
+ GR1553BC_WRITE_MEM(&raw->words[1], word1);
+ if ( flags & 0x4 )
+ GR1553BC_WRITE_MEM(&raw->words[2], word2);
+ if ( flags & 0x8 )
+ GR1553BC_WRITE_MEM(&raw->words[3], word3);
+}
+
+/* Alloc a Major frame according to the configuration structure */
+int gr1553bc_major_alloc_skel
+ (
+ struct gr1553bc_major **major,
+ struct gr1553bc_major_cfg *cfg
+ )
+{
+ struct gr1553bc_major *maj;
+ struct gr1553bc_minor *minor;
+ int size, i;
+
+ if ( (cfg == NULL) || (major == NULL) || (cfg->minor_cnt <= 0) )
+ return -1;
+
+ /* Allocate Major Frame description, but no descriptors */
+ size = sizeof(struct gr1553bc_major) + cfg->minor_cnt *
+ (sizeof(struct gr1553bc_minor) + sizeof(void *));
+ maj = (struct gr1553bc_major *)malloc(size);
+ if ( maj == NULL )
+ return -1;
+
+ maj->cfg = cfg;
+ maj->next = NULL;
+
+ /* Create links between minor frames, and from minor frames
+ * to configuration structure.
+ */
+ minor = (struct gr1553bc_minor *)&maj->minors[cfg->minor_cnt];
+ for (i=0; i<cfg->minor_cnt; i++, minor++) {
+ maj->minors[i] = minor;
+ minor->next = minor + 1;
+ minor->cfg = &cfg->minor_cfgs[i];
+ minor->alloc = 0;
+ minor->bds = NULL;
+ }
+ /* last Minor should point to next Major frame's first minor,
+ * we do that somewhere else.
+ */
+ (minor - 1)->next = NULL;
+
+ *major = maj;
+
+ return 0;
+}
+
+struct gr1553bc_major *gr1553bc_major_from_id
+ (
+ struct gr1553bc_list *list,
+ int mid
+ )
+{
+ int major_no;
+
+ /* Find Minor Frame from MID */
+ major_no = GR1553BC_MAJID_FROM_ID(mid);
+
+ if ( major_no >= list->major_cnt )
+ return NULL;
+ return list->majors[major_no];
+}
+
+struct gr1553bc_minor *gr1553bc_minor_from_id
+ (
+ struct gr1553bc_list *list,
+ int mid
+ )
+{
+ int minor_no;
+ struct gr1553bc_major *major;
+
+ /* Get Major from ID */
+ major = gr1553bc_major_from_id(list, mid);
+ if ( major == NULL )
+ return NULL;
+
+ /* Find Minor Frame from MID */
+ minor_no = GR1553BC_MINID_FROM_ID(mid);
+
+ if ( minor_no >= major->cfg->minor_cnt )
+ return NULL;
+ return major->minors[minor_no];
+}
+
+union gr1553bc_bd *gr1553bc_slot_bd
+ (
+ struct gr1553bc_list *list,
+ int mid
+ )
+{
+ struct gr1553bc_minor *minor;
+ int slot_no;
+
+ /*** look up BD ***/
+
+ /* Get minor */
+ minor = gr1553bc_minor_from_id(list, mid);
+ if ( minor == NULL )
+ return NULL;
+
+ /* Get Slot */
+ slot_no = GR1553BC_SLOTID_FROM_ID(mid);
+ if ( slot_no >= 0xff )
+ slot_no = 0;
+
+ /* Get BD address */
+ return &minor->bds[slot_no];
+}
+
+int gr1553bc_minor_first_avail(struct gr1553bc_minor *minor)
+{
+ int slot_num;
+ uint32_t alloc;
+
+ alloc = minor->alloc;
+ if ( alloc == 0xffffffff ) {
+ /* No free */
+ return -1;
+ }
+ slot_num = 0;
+ while ( alloc & 1 ) {
+ alloc = alloc >> 1;
+ slot_num++;
+ }
+ if ( slot_num >= minor->cfg->slot_cnt ) {
+ /* no free */
+ return -1;
+ }
+ return slot_num;
+}
+
+int gr1553bc_slot_alloc(
+ struct gr1553bc_list *list,
+ int *mid,
+ int timeslot,
+ union gr1553bc_bd **bd
+ )
+{
+ struct gr1553bc_minor *minor = gr1553bc_minor_from_id(list, *mid);
+
+ return gr1553bc_slot_alloc2(minor, mid, timeslot, bd);
+}
+
+/* Same as gr1553bc_slot_alloc but identifies a minor instead of list.
+ * The major/minor part of MID is ignored.
+ */
+int gr1553bc_slot_alloc2(
+ struct gr1553bc_minor *minor,
+ int *mid,
+ int timeslot,
+ union gr1553bc_bd **bd
+ )
+{
+ int slot_no;
+ uint32_t set0;
+ int timefree;
+ struct gr1553bc_bd_tr *trbd;
+ struct gr1553bc_minor_cfg *mincfg;
+
+ if ( minor == NULL )
+ return -1;
+
+ mincfg = minor->cfg;
+
+ /* Find first free slot if not a certain slot is requested */
+ slot_no = GR1553BC_SLOTID_FROM_ID(*mid);
+ if ( slot_no == 0xff ) {
+ slot_no = gr1553bc_minor_first_avail(minor);
+ if ( slot_no < 0 )
+ return -1;
+ } else {
+ /* Allocate a certain slot, check that it is free */
+ if ( slot_no >= mincfg->slot_cnt )
+ return -1;
+ if ( (1<<slot_no) & minor->alloc )
+ return -1;
+ }
+
+ /* Ok, we got our slot. Lets allocate time for slot if requested by user
+ * and time management is enabled for this Minor Frame.
+ */
+ if ( timeslot > 0 ) {
+ /* Make timeslot on a 4us boundary (time resolution of core) */
+ timeslot = (timeslot + 0x3) >> 2;
+
+ if ( mincfg->timeslot ) {
+ /* Subtract requested time from free time */
+ trbd = &minor->bds[mincfg->slot_cnt].tr;
+ set0 = GR1553BC_READ_MEM(&trbd->settings[0]);
+ timefree = set0 & GR1553BC_TR_TIME;
+ if ( timefree < timeslot ) {
+ /* Not enough time left to schedule slot in minor */
+ return -1;
+ }
+ /* Store back the time left */
+ timefree -= timeslot;
+ set0 = (set0 & ~GR1553BC_TR_TIME) | timefree;
+ GR1553BC_WRITE_MEM(&trbd->settings[0], set0);
+ /* Note: at the moment the minor frame can be executed faster
+ * than expected, we hurry up writing requested
+ * descriptor.
+ */
+ }
+ }
+
+ /* Make the allocated descriptor be an empty slot with the
+ * timeslot requested.
+ */
+ trbd = &minor->bds[slot_no].tr;
+ gr1553bc_bd_tr_init(
+ trbd,
+ GR1553BC_TR_DUMMY_0 | timeslot,
+ GR1553BC_TR_DUMMY_1,
+ 0,
+ 0);
+
+ /* Allocate slot */
+ minor->alloc |= 1<<slot_no;
+
+ if ( bd )
+ *bd = (union gr1553bc_bd *)trbd;
+ *mid = GR1553BC_ID_SET_SLOT(*mid, slot_no);
+
+ return 0;
+}
+
+/* Return time slot freed (if time is managed by driver), negative on error */
+int gr1553bc_slot_free(struct gr1553bc_list *list, int mid)
+{
+ struct gr1553bc_minor *minor = gr1553bc_minor_from_id(list, mid);
+
+ return gr1553bc_slot_free2(minor, mid);
+}
+
+/* Return time slot freed (if time is managed by driver), negative on error */
+int gr1553bc_slot_free2(struct gr1553bc_minor *minor, int mid)
+{
+ union gr1553bc_bd *bd;
+ struct gr1553bc_bd_tr *endbd;
+ struct gr1553bc_minor_cfg *mincfg;
+ int slot_no, timeslot, timefree;
+ uint32_t word0, set0;
+
+ if ( minor == NULL )
+ return -1;
+
+ slot_no = GR1553BC_SLOTID_FROM_ID(mid);
+
+ if ( (minor->alloc & (1<<slot_no)) == 0 )
+ return -1;
+
+ bd = &minor->bds[slot_no];
+
+ /* If the driver handles time for this minor frame, return
+ * time if previuosly requested.
+ */
+ timeslot = 0;
+ mincfg = minor->cfg;
+ if ( mincfg->timeslot > 0 ) {
+ /* Find out if message slot had time allocated */
+ word0 = GR1553BC_READ_MEM(&bd->raw.words[0]);
+ if ( word0 & GR1553BC_BD_TYPE ) {
+ /* Condition ==> no time slot allocated */
+ } else {
+ /* Transfer descriptor, may have time slot */
+ timeslot = word0 & GR1553BC_TR_TIME;
+ if ( timeslot > 0 ) {
+ /* Return previously allocated time to END
+ * TIME descriptor.
+ */
+ endbd = &minor->bds[mincfg->slot_cnt].tr;
+ set0 = GR1553BC_READ_MEM(&endbd->settings[0]);
+ timefree = set0 & GR1553BC_TR_TIME;
+ timefree += timeslot;
+ set0 = (set0 & ~GR1553BC_TR_TIME) | timefree;
+ GR1553BC_WRITE_MEM(&endbd->settings[0], set0);
+ /* Note: at the moment the minor frame can be
+ * executed slower than expected, the
+ * timeslot is at two locations.
+ */
+ }
+ }
+ }
+
+ /* Make slot an empty message */
+ gr1553bc_bd_tr_init(
+ &bd->tr,
+ GR1553BC_TR_DUMMY_0,
+ GR1553BC_TR_DUMMY_1,
+ 0,
+ 0);
+
+ /* unallocate descriptor */
+ minor->alloc &= ~(1<<slot_no);
+
+ /* Return time freed in microseconds */
+ return timeslot << 2;
+}
+
+int gr1553bc_list_freetime(struct gr1553bc_list *list, int mid)
+{
+ struct gr1553bc_minor *minor = gr1553bc_minor_from_id(list, mid);
+
+ return gr1553bc_minor_freetime(minor);
+}
+
+int gr1553bc_minor_freetime(struct gr1553bc_minor *minor)
+{
+ struct gr1553bc_bd_tr *endbd;
+ struct gr1553bc_minor_cfg *mincfg;
+ int timefree;
+ uint32_t set0;
+
+ if ( minor == NULL )
+ return -1;
+
+ /* If the driver handles time for this minor frame, return
+ * time if previuosly requested.
+ */
+ timefree = 0;
+ mincfg = minor->cfg;
+ if ( mincfg->timeslot > 0 ) {
+ /* Return previously allocated time to END
+ * TIME descriptor.
+ */
+ endbd = &minor->bds[mincfg->slot_cnt].tr;
+ set0 = GR1553BC_READ_MEM(&endbd->settings[0]);
+ timefree = (set0 & GR1553BC_TR_TIME) << 2;
+ }
+
+ /* Return time freed */
+ return timefree;
+}
+
+int gr1553bc_slot_raw
+ (
+ struct gr1553bc_list *list,
+ int mid,
+ unsigned int flags,
+ uint32_t word0,
+ uint32_t word1,
+ uint32_t word2,
+ uint32_t word3
+ )
+{
+ struct gr1553bc_minor *minor;
+ union gr1553bc_bd *bd;
+ int slot_no;
+
+ minor = gr1553bc_minor_from_id(list, mid);
+ if ( minor == NULL )
+ return -1;
+
+ /* Get Slot */
+ slot_no = GR1553BC_SLOTID_FROM_ID(mid);
+ if ( slot_no >= minor->cfg->slot_cnt ) {
+ return -1;
+ }
+
+ /* Get descriptor */
+ bd = &minor->bds[slot_no];
+
+ /* Build empty descriptor. */
+ gr1553bc_bd_init(
+ bd,
+ flags,
+ word0,
+ word1,
+ word2,
+ word3);
+
+ return 0;
+}
+
+/* Create unconditional IRQ customly defined location
+ * The IRQ is disabled, enable it with gr1553bc_slot_irq_enable().
+ */
+int gr1553bc_slot_irq_prepare
+ (
+ struct gr1553bc_list *list,
+ int mid,
+ bcirq_func_t func,
+ void *data
+ )
+{
+ union gr1553bc_bd *bd;
+ int slot_no, to_mid;
+
+ /* Build unconditional IRQ descriptor. The padding is used
+ * for identifying the MINOR frame and function and custom data.
+ *
+ * The IRQ is disabled at first, a unconditional jump to next
+ * descriptor in table.
+ */
+
+ /* Get BD address of jump destination */
+ slot_no = GR1553BC_SLOTID_FROM_ID(mid);
+ to_mid = GR1553BC_ID_SET_SLOT(mid, slot_no + 1);
+ bd = gr1553bc_slot_bd(list, to_mid);
+ if ( bd == NULL )
+ return -1;
+ bd = gr1553bc_bd_cpu2hw(list, bd);
+
+ return gr1553bc_slot_raw(
+ list,
+ mid,
+ 0xF,
+ GR1553BC_UNCOND_JMP,
+ (uint32_t)bd,
+ (uint32_t)func,
+ (uint32_t)data
+ );
+}
+
+/* Enable previously prepared unconditional IRQ */
+int gr1553bc_slot_irq_enable(struct gr1553bc_list *list, int mid)
+{
+ /* Leave word1..3 untouched:
+ * 1. Unconditional Jump address
+ * 2. Function
+ * 3. Custom Data
+ *
+ * Since only one bit is changed in word0 (Condition word),
+ * no hardware/software races will exist ==> it is safe
+ * to enable/disable IRQ at any time independent of where
+ * hardware is in table.
+ */
+ return gr1553bc_slot_raw(
+ list,
+ mid,
+ 0x1, /* change only WORD0 */
+ GR1553BC_UNCOND_IRQ,
+ 0,
+ 0,
+ 0);
+}
+
+/* Disable unconditional IRQ point, changed to unconditional JUMP
+ * to descriptor following.
+ * After disabling it it can be enabled again, or freed.
+ */
+int gr1553bc_slot_irq_disable(struct gr1553bc_list *list, int mid)
+{
+ return gr1553bc_slot_raw(
+ list,
+ mid,
+ 0x1, /* change only WORD0, JUMP address already set */
+ GR1553BC_UNCOND_JMP,
+ 0,
+ 0,
+ 0);
+}
+
+int gr1553bc_slot_empty(struct gr1553bc_list *list, int mid)
+{
+ return gr1553bc_slot_raw(
+ list,
+ mid,
+ 0xF | KEEP_TIMESLOT,
+ GR1553BC_TR_DUMMY_0,
+ GR1553BC_TR_DUMMY_1,
+ 0,
+ 0);
+}
+
+int gr1553bc_slot_exttrig(struct gr1553bc_list *list, int mid)
+{
+ return gr1553bc_slot_raw(
+ list,
+ mid,
+ 0xF | KEEP_TIMESLOT,
+ GR1553BC_TR_DUMMY_0 | GR1553BC_TR_EXTTRIG,
+ GR1553BC_TR_DUMMY_1,
+ 0,
+ 0);
+}
+
+int gr1553bc_slot_jump
+ (
+ struct gr1553bc_list *list,
+ int mid,
+ uint32_t condition,
+ int to_mid
+ )
+{
+ union gr1553bc_bd *bd;
+
+ /* Get BD address */
+ bd = gr1553bc_slot_bd(list, to_mid);
+ if ( bd == NULL )
+ return -1;
+ /* Convert into an address that the HW understand */
+ bd = gr1553bc_bd_cpu2hw(list, bd);
+
+ return gr1553bc_slot_raw(
+ list,
+ mid,
+ 0xF,
+ condition,
+ (uint32_t)bd,
+ 0,
+ 0);
+}
+
+int gr1553bc_slot_transfer(
+ struct gr1553bc_list *list,
+ int mid,
+ int options,
+ int tt,
+ uint16_t *dptr)
+{
+ uint32_t set0, set1;
+ union gr1553bc_bd *bd;
+ int rx_rtadr, tx_rtadr, timeout;
+
+ /* Get BD address */
+ bd = gr1553bc_slot_bd(list, mid);
+ if ( bd == NULL )
+ return -1;
+
+ /* Translate Data pointer from CPU-local to 1553-core accessible
+ * address if user wants that. This may be useful for AMBA-over-PCI
+ * cores.
+ */
+ if ( (unsigned int)dptr & 0x1 ) {
+ struct gr1553bc_priv *bcpriv = list->bc;
+
+ drvmgr_translate(
+ *bcpriv->pdev,
+ 0,
+ 0,
+ (void *)((unsigned int)dptr & ~0x1),
+ (void **)&dptr
+ );
+ }
+
+ /* It is assumed that the descriptor has already been initialized
+ * as a empty slot (Dummy bit set), so to avoid races the dummy
+ * bit is cleared last.
+ *
+ * If we knew that the write would do a burst (for example over SpW)
+ * it would be safe to write in order.
+ */
+
+ /* Preserve timeslot */
+ set0 = GR1553BC_READ_MEM(&bd->tr.settings[0]);
+ set0 &= GR1553BC_TR_TIME;
+ set0 |= options & 0x61f00000;
+ set0 |= list->tropts; /* Global options */
+
+ /* Set transfer type, bus and let RT tolerance table descide
+ * responce tolerance.
+ *
+ * If a destination address is specified the longest timeout
+ * tolerance is taken.
+ */
+ rx_rtadr = (tt >> 22) & 0x1f;
+ tx_rtadr = (tt >> 12) & 0x1f;
+ if ( (tx_rtadr != 0x1f) &&
+ (list->rt_timeout[rx_rtadr] < list->rt_timeout[tx_rtadr]) ) {
+ timeout = list->rt_timeout[tx_rtadr];
+ } else {
+ timeout = list->rt_timeout[rx_rtadr];
+ }
+ set1 = ((timeout & 0xf) << 27) | (tt & 0x27ffffff) | ((options & 0x3)<<30);
+
+ GR1553BC_WRITE_MEM(&bd->tr.settings[0], set0);
+ GR1553BC_WRITE_MEM(&bd->tr.dptr, (uint32_t)dptr);
+ /* Write UNUSED BIT, when cleared it Indicates that BC has written it */
+ GR1553BC_WRITE_MEM(&bd->tr.status, 0x80000000);
+ GR1553BC_WRITE_MEM(&bd->tr.settings[1], set1);
+
+ return 0;
+}
+
+int gr1553bc_slot_update
+ (
+ struct gr1553bc_list *list,
+ int mid,
+ uint16_t *dptr,
+ unsigned int *stat
+ )
+{
+ union gr1553bc_bd *bd;
+ unsigned int status;
+ unsigned int dataptr = (unsigned int)dptr;
+
+ /* Get BD address */
+ bd = gr1553bc_slot_bd(list, mid);
+ if ( bd == NULL )
+ return -1;
+
+ /* Write new Data Pointer if needed */
+ if ( dataptr ) {
+ struct gr1553bc_priv *bcpriv = list->bc;
+
+ /* Translate Data pointer from CPU-local to 1553-core accessible
+ * address if user wants that. This may be useful for AMBA-over-PCI
+ * cores.
+ */
+ if ( dataptr & 0x1 ) {
+ drvmgr_translate(
+ *bcpriv->pdev,
+ 0,
+ 0,
+ (void *)(dataptr & ~0x1),
+ (void **)&dptr
+ );
+ }
+
+ /* Update Data Pointer */
+ GR1553BC_WRITE_MEM(&bd->tr.dptr, dataptr);
+ }
+
+ /* Get status of transfer descriptor */
+ if ( stat ) {
+ status = *stat;
+ *stat = GR1553BC_READ_MEM(&bd->tr.status);
+ if ( status ) {
+ /* Clear status fields user selects, then
+ * or bit31 if user wants that. The bit31
+ * may be used to indicate if the BC has
+ * performed the access.
+ */
+ status = (*stat & (status & 0xffffff)) |
+ (status & (1<<31));
+ GR1553BC_WRITE_MEM(&bd->tr.status, status);
+ }
+ }
+
+ return 0;
+}
+
+int gr1553bc_slot_dummy(
+ struct gr1553bc_list *list,
+ int mid,
+ unsigned int *dummy)
+{
+ union gr1553bc_bd *bd;
+ unsigned int set1, new_set1;
+
+ /* Get BD address */
+ bd = gr1553bc_slot_bd(list, mid);
+ if ( bd == NULL )
+ return -1;
+ /* Update the Dummy Bit */
+ set1 = GR1553BC_READ_MEM(&bd->tr.settings[1]);
+ new_set1 = (set1 & ~GR1553BC_TR_DUMMY_1) | (*dummy & GR1553BC_TR_DUMMY_1);
+ GR1553BC_WRITE_MEM(&bd->tr.settings[1], new_set1);
+
+ *dummy = set1;
+
+ return 0;
+}
+
+/* Find MID from Descriptor pointer */
+int gr1553bc_mid_from_bd(
+ union gr1553bc_bd *bd,
+ int *mid,
+ int *async
+ )
+{
+ int i, bdmid, slot_no;
+ uint32_t word0, word2;
+
+ /* Find Jump to next Minor Frame or End-Of-List,
+ * at those locations we have stored a MID
+ *
+ * GR1553BC_SLOT_MAX+2 = Worst case, BD is max distance from jump
+ * descriptor. 2=END and Jump descriptors.
+ */
+ for (i=0; i<GR1553BC_SLOT_MAX+2; i++) {
+ word0 = GR1553BC_READ_MEM(&bd->raw.words[0]);
+ if ( word0 & GR1553BC_BD_TYPE ) {
+ if ( word0 == GR1553BC_UNCOND_JMP ) {
+ /* May be a unconditional IRQ set by user. In
+ * that case the function is stored in WORD3,
+ * functions must be aligned to 4 byte boudary.
+ */
+ word2 = GR1553BC_READ_MEM(&bd->raw.words[2]);
+ if ( word2 & NEXT_MINOR_MARKER ) {
+ goto found_mid;
+ }
+ } else if ( word0 == GR1553BC_TR_EOL ) {
+ /* End-Of-List, does contain a MID */
+ word2 = GR1553BC_READ_MEM(&bd->raw.words[2]);
+ goto found_mid;
+ }
+ }
+ bd++;
+ }
+
+ return -1;
+
+found_mid:
+ /* Get MID of JUMP descriptor */
+ bdmid = word2 >> 8;
+ /* Subtract distance from JUMP descriptor to find MID
+ * of requested BD.
+ */
+ slot_no = GR1553BC_SLOTID_FROM_ID(bdmid);
+ slot_no -= i;
+ bdmid = GR1553BC_ID_SET_SLOT(bdmid, slot_no);
+
+ if ( mid )
+ *mid = bdmid;
+
+ /* Determine which list BD belongs to: async or sync */
+ if ( async )
+ *async = word2 & NEXT_MINOR_MARKER_ASYNC;
+
+ return 0;
+}
+
+/*************** END OF LIST HANDLING ROUTINES ***************/
+
+/*************** DEVICE HANDLING ROUTINES ***************/
+
+void gr1553bc_device_init(struct gr1553bc_priv *priv);
+void gr1553bc_device_uninit(struct gr1553bc_priv *priv);
+void gr1553bc_isr(void *data);
+
+/*** GR1553BC driver ***/
+
+void gr1553bc_register(void)
+{
+ /* The BC driver rely on the GR1553B Driver */
+ gr1553_register();
+}
+
+void gr1553bc_isr_std(union gr1553bc_bd *bd, void *data)
+{
+ /* Do nothing */
+}
+
+/* Take a GR1553BC hardware device identified by minor.
+ * A pointer is returned that is used internally by the GR1553BC
+ * driver, it is used as an input paramter 'bc' to all other
+ * functions that manipulate the hardware.
+ */
+void *gr1553bc_open(int minor)
+{
+ struct drvmgr_dev **pdev = NULL;
+ struct gr1553bc_priv *priv = NULL;
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
+ void *irq_log_p = NULL;
+
+ /* Allocate requested device */
+ pdev = gr1553_bc_open(minor);
+ if ( pdev == NULL )
+ goto fail;
+
+ irq_log_p = malloc(GR1553BC_IRQLOG_SIZE*2);
+ if ( irq_log_p == NULL )
+ goto fail;
+
+ priv = malloc(sizeof(struct gr1553bc_priv));
+ if ( priv == NULL )
+ goto fail;
+ memset(priv, 0, sizeof(struct gr1553bc_priv));
+
+ /* Init BC device */
+ priv->pdev = pdev;
+ (*pdev)->priv = priv;
+ priv->irq_log_p = irq_log_p;
+ priv->started = 0;
+
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)(*pdev)->businfo;
+ pnpinfo = &ambadev->info;
+ priv->regs = (struct gr1553b_regs *)pnpinfo->apb_slv->start;
+
+ gr1553bc_device_init(priv);
+
+ /* Register ISR handler (unmask at IRQ controller) */
+ if ( drvmgr_interrupt_register(*priv->pdev, 0, "gr1553bc",
+ gr1553bc_isr, priv) ) {
+ goto fail;
+ }
+
+ return priv;
+
+fail:
+ if ( pdev )
+ gr1553_bc_close(pdev);
+ if ( irq_log_p )
+ free(irq_log_p);
+ if ( priv )
+ free(priv);
+ return NULL;
+}
+
+void gr1553bc_close(void *bc)
+{
+ struct gr1553bc_priv *priv = bc;
+
+ /* Stop Hardware */
+ gr1553bc_stop(bc, 0x3);
+
+ gr1553bc_device_uninit(priv);
+
+ /* Remove interrupt handler (mask IRQ at IRQ controller) */
+ drvmgr_interrupt_unregister(*priv->pdev, 0, gr1553bc_isr, priv);
+
+ /* Free device */
+ gr1553_bc_close(priv->pdev);
+ free(priv->irq_log_p);
+ free(priv);
+}
+
+/* Return Current Minor frame number */
+int gr1553bc_indication(void *bc, int async, int *mid)
+{
+ struct gr1553bc_priv *priv = bc;
+ union gr1553bc_bd *bd;
+
+ /* Get current descriptor pointer */
+ if ( async ) {
+ bd = (union gr1553bc_bd *)
+ GR1553BC_READ_REG(&priv->regs->bc_aslot);
+ bd = gr1553bc_bd_hw2cpu(priv->alist, bd);
+ } else {
+ bd = (union gr1553bc_bd *)
+ GR1553BC_READ_REG(&priv->regs->bc_slot);
+ bd = gr1553bc_bd_hw2cpu(priv->list, bd);
+ }
+
+ return gr1553bc_mid_from_bd(bd, mid, NULL);
+}
+
+/* Start major frame processing, wait for TimerManager tick or start directly */
+int gr1553bc_start(void *bc, struct gr1553bc_list *list, struct gr1553bc_list *list_async)
+{
+ struct gr1553bc_priv *priv = bc;
+ union gr1553bc_bd *bd = NULL, *bd_async = NULL;
+ uint32_t ctrl, irqmask;
+ IRQ_GLOBAL_PREPARE(oldLevel);
+
+ if ( (list == NULL) && (list_async == NULL) )
+ return 0;
+
+ /* Find first descriptor in list, the descriptor
+ * first to be executed.
+ */
+ ctrl = GR1553BC_KEY;
+ if ( list ) {
+ bd = gr1553bc_slot_bd(list, GR1553BC_ID(0,0,0));
+ if ( bd == NULL )
+ return -1;
+ bd = gr1553bc_bd_cpu2hw(list, bd);
+ ctrl |= GR1553B_BC_ACT_SCSRT;
+ }
+ if ( list_async ) {
+ bd_async = gr1553bc_slot_bd(list_async, GR1553BC_ID(0,0,0));
+ if ( bd_async == NULL )
+ return -1;
+ bd_async = gr1553bc_bd_cpu2hw(list_async, bd_async);
+ ctrl |= GR1553B_BC_ACT_ASSRT;
+ }
+
+ /* Do "hot-swapping" of lists */
+ IRQ_GLOBAL_DISABLE(oldLevel);
+ if ( list ) {
+ priv->list = list;
+ GR1553BC_WRITE_REG(&priv->regs->bc_bd, (uint32_t)bd);
+ }
+ if ( list_async ) {
+ priv->alist = list_async;
+ GR1553BC_WRITE_REG(&priv->regs->bc_abd, (uint32_t)bd_async);
+ }
+
+ /* If not enabled before, we enable it now. */
+ GR1553BC_WRITE_REG(&priv->regs->bc_ctrl, ctrl);
+
+ /* Enable IRQ */
+ if ( priv->started == 0 ) {
+ priv->started = 1;
+ irqmask = GR1553BC_READ_REG(&priv->regs->imask);
+ irqmask |= GR1553B_IRQEN_BCEVE|GR1553B_IRQEN_BCDE|GR1553B_IRQEN_BCWKE;
+ GR1553BC_WRITE_REG(&priv->regs->imask, irqmask);
+ }
+
+ IRQ_GLOBAL_ENABLE(oldLevel);
+
+ return 0;
+}
+
+/* Pause GR1553 BC transfers */
+int gr1553bc_pause(void *bc)
+{
+ struct gr1553bc_priv *priv = bc;
+ uint32_t ctrl;
+ IRQ_GLOBAL_PREPARE(oldLevel);
+
+ /* Do "hot-swapping" of lists */
+ IRQ_GLOBAL_DISABLE(oldLevel);
+ ctrl = GR1553BC_KEY | GR1553B_BC_ACT_SCSUS;
+ GR1553BC_WRITE_REG(&priv->regs->bc_ctrl, ctrl);
+ IRQ_GLOBAL_ENABLE(oldLevel);
+
+ return 0;
+}
+
+/* Restart GR1553 BC transfers, after being paused */
+int gr1553bc_restart(void *bc)
+{
+ struct gr1553bc_priv *priv = bc;
+ uint32_t ctrl;
+ IRQ_GLOBAL_PREPARE(oldLevel);
+
+ IRQ_GLOBAL_DISABLE(oldLevel);
+ ctrl = GR1553BC_KEY | GR1553B_BC_ACT_SCSRT;
+ GR1553BC_WRITE_REG(&priv->regs->bc_ctrl, ctrl);
+ IRQ_GLOBAL_ENABLE(oldLevel);
+
+ return 0;
+}
+
+/* Stop BC transmission */
+int gr1553bc_stop(void *bc, int options)
+{
+ struct gr1553bc_priv *priv = bc;
+ uint32_t ctrl;
+ IRQ_GLOBAL_PREPARE(oldLevel);
+
+ ctrl = GR1553BC_KEY;
+ if ( options & 0x1 )
+ ctrl |= GR1553B_BC_ACT_SCSTP;
+ if ( options & 0x2 )
+ ctrl |= GR1553B_BC_ACT_ASSTP;
+
+ IRQ_GLOBAL_DISABLE(oldLevel);
+ GR1553BC_WRITE_REG(&priv->regs->bc_ctrl, ctrl);
+ priv->started = 0;
+ IRQ_GLOBAL_ENABLE(oldLevel);
+
+ return 0;
+}
+
+/* Reset software and BC hardware into a known "unused/init" state */
+void gr1553bc_device_init(struct gr1553bc_priv *priv)
+{
+/* RESET HARDWARE REGISTERS */
+ /* Stop BC if not already stopped */
+ GR1553BC_WRITE_REG(&priv->regs->bc_ctrl, GR1553BC_KEY | 0x0204);
+
+ /* Since RT can not be used at the same time as BC, we stop
+ * RT rx, it should already be stopped...
+ */
+ GR1553BC_WRITE_REG(&priv->regs->rt_cfg, GR1553RT_KEY);
+
+ /* Clear some registers */
+ GR1553BC_WRITE_REG(&priv->regs->bc_bd, 0);
+ GR1553BC_WRITE_REG(&priv->regs->bc_abd, 0);
+ GR1553BC_WRITE_REG(&priv->regs->bc_timer, 0);
+ GR1553BC_WRITE_REG(&priv->regs->bc_wake, 0);
+ GR1553BC_WRITE_REG(&priv->regs->bc_irqptr, 0);
+ GR1553BC_WRITE_REG(&priv->regs->bc_busmsk, 0);
+
+/* PUT SOFTWARE INTO INITIAL STATE */
+ priv->list = NULL;
+ priv->alist = NULL;
+
+ priv->irq_log_base = (uint32_t *)
+ (((uint32_t)priv->irq_log_p + (GR1553BC_IRQLOG_SIZE-1)) &
+ ~(GR1553BC_IRQLOG_SIZE-1));
+ /* Translate into a hardware accessible address */
+ drvmgr_translate(
+ *priv->pdev,
+ 0,
+ 0,
+ (void *)priv->irq_log_base,
+ (void **)&priv->irq_log_base_hw
+ );
+ priv->irq_log_curr = priv->irq_log_base;
+ priv->irq_log_end = &priv->irq_log_base[GR1553BC_IRQLOG_CNT-1];
+ priv->irq_func = gr1553bc_isr_std;
+ priv->irq_data = NULL;
+
+ GR1553BC_WRITE_REG(&priv->regs->bc_irqptr,(uint32_t)priv->irq_log_base_hw);
+}
+
+void gr1553bc_device_uninit(struct gr1553bc_priv *priv)
+{
+ uint32_t irqmask;
+
+ /* Stop BC if not already stopped */
+ GR1553BC_WRITE_REG(&priv->regs->bc_ctrl, GR1553BC_KEY | 0x0204);
+
+ /* Since RT can not be used at the same time as BC, we stop
+ * RT rx, it should already be stopped...
+ */
+ GR1553BC_WRITE_REG(&priv->regs->rt_cfg, GR1553RT_KEY);
+
+ /* Turn off IRQ generation */
+ irqmask=GR1553BC_READ_REG(&priv->regs->imask);
+ irqmask&=~(GR1553B_IRQEN_BCEVE|GR1553B_IRQEN_BCDE|GR1553B_IRQEN_BCWKE);
+ GR1553BC_WRITE_REG(&priv->regs->irq, irqmask);
+}
+
+/* Interrupt handler */
+void gr1553bc_isr(void *arg)
+{
+ struct gr1553bc_priv *priv = arg;
+ uint32_t *curr, *pos, word0, word2;
+ union gr1553bc_bd *bd;
+ bcirq_func_t func;
+ void *data;
+ int handled, irq;
+
+ /* Did core make IRQ */
+ irq = GR1553BC_READ_REG(&priv->regs->irq);
+ irq &= (GR1553B_IRQEN_BCEVE|GR1553B_IRQEN_BCDE|GR1553B_IRQEN_BCWKE);
+ if ( irq == 0 )
+ return; /* Shared IRQ: some one else may have caused the IRQ */
+
+ /* Clear handled IRQs */
+ GR1553BC_WRITE_REG(&priv->regs->irq, irq);
+
+ /* DMA error. This IRQ does not affect the IRQ log.
+ * We let standard IRQ handle handle it.
+ */
+ if ( irq & GR1553B_IRQEN_BCDE ) {
+ priv->irq_func(NULL, priv->irq_data);
+ }
+
+ /* Get current posistion in hardware */
+ pos = (uint32_t *)GR1553BC_READ_REG(&priv->regs->bc_irqptr);
+ /* Convertin into CPU address */
+ pos = priv->irq_log_base +
+ ((unsigned int)pos - (unsigned int)priv->irq_log_base_hw)/4;
+
+ /* Step in IRQ log until we reach the end. */
+ handled = 0;
+ curr = priv->irq_log_curr;
+ while ( curr != pos ) {
+ bd = (union gr1553bc_bd *)(GR1553BC_READ_MEM(curr) & ~1);
+ GR1553BC_WRITE_MEM(curr, 0x2); /* Mark Handled */
+
+ /* Convert Descriptor in IRQ log into CPU address. In order
+ * to convert we must know which list the descriptor belongs
+ * to, we compare the address of the bd to the ASYNC list
+ * descriptor table area.
+ */
+ if ( priv->alist && ((unsigned int)bd>=priv->alist->table_hw) &&
+ ((unsigned int)bd <
+ (priv->alist->table_hw + priv->alist->table_size))) {
+ /* BD in async list */
+ bd = gr1553bc_bd_hw2cpu(priv->alist, bd);
+ } else {
+ /* BD in sync list */
+ bd = gr1553bc_bd_hw2cpu(priv->list, bd);
+ }
+
+ /* Handle Descriptor that cased IRQ
+ *
+ * If someone have inserted an IRQ descriptor and tied
+ * that to a custom function we call that function, otherwise
+ * we let the standard IRQ handle handle it.
+ */
+ word0 = GR1553BC_READ_MEM(&bd->raw.words[0]);
+ if ( word0 == GR1553BC_UNCOND_IRQ ) {
+ word2 = GR1553BC_READ_MEM(&bd->raw.words[2]);
+ if ( (word2 & 0x3) == 0 ) {
+ func = (bcirq_func_t)(word2 & ~0x3);
+ data = (void *)
+ GR1553BC_READ_MEM(&bd->raw.words[3]);
+ func(bd, data);
+ handled = 1;
+ }
+ }
+
+ if ( handled == 0 ) {
+ /* Let standard IRQ handle handle it */
+ priv->irq_func(bd, priv->irq_data);
+ } else {
+ handled = 0;
+ }
+
+ /* Increment to next entry in IRQ LOG */
+ if ( curr == priv->irq_log_end )
+ curr = priv->irq_log_base;
+ else
+ curr++;
+ }
+ priv->irq_log_curr = curr;
+}
+
+int gr1553bc_irq_setup
+ (
+ void *bc,
+ bcirq_func_t func,
+ void *data
+ )
+{
+ struct gr1553bc_priv *priv = bc;
+
+ if ( func == NULL )
+ priv->irq_func = gr1553bc_isr_std;
+ else
+ priv->irq_func = func;
+ priv->irq_data = data;
+
+ return 0;
+}
+
+void gr1553bc_ext_trig(void *bc, int trig)
+{
+ struct gr1553bc_priv *priv = bc;
+ unsigned int trigger;
+
+ if ( trig )
+ trigger = GR1553B_BC_ACT_SETT;
+ else
+ trigger = GR1553B_BC_ACT_CLRT;
+
+ GR1553BC_WRITE_REG(&priv->regs->bc_ctrl, GR1553BC_KEY | trigger);
+}
+
+void gr1553bc_status(void *bc, struct gr1553bc_status *status)
+{
+ struct gr1553bc_priv *priv = bc;
+
+ status->status = GR1553BC_READ_REG(&priv->regs->bc_stat);
+ status->time = GR1553BC_READ_REG(&priv->regs->bc_timer);
+}
+
+/*** DEBUGGING HELP FUNCTIONS ***/
+
+#include <stdio.h>
+
+void gr1553bc_show_list(struct gr1553bc_list *list, int options)
+{
+ struct gr1553bc_major *major;
+ struct gr1553bc_minor *minor;
+ int i, j, minor_cnt, timefree;
+
+ printf("LIST\n");
+ printf(" major cnt: %d\n", list->major_cnt);
+ for (i=0; i<32; i++) {
+ printf(" RT[%d] timeout: %d\n", i, 14+(list->rt_timeout[i]*4));
+ }
+
+ for (i=0; i<list->major_cnt; i++) {
+ major = list->majors[i];
+ minor_cnt = major->cfg->minor_cnt;
+ printf(" MAJOR[%d]\n", i);
+ printf(" minor count: %d\n", minor_cnt);
+
+ for (j=0; j<minor_cnt; j++) {
+ minor = major->minors[j];
+
+ printf(" MINOR[%d]\n", j);
+ printf(" bd: 0x%08x (HW:0x%08x)\n",
+ (unsigned int)&minor->bds[0],
+ (unsigned int)gr1553bc_bd_cpu2hw(list,
+ &minor->bds[0]));
+ printf(" slot cnt: %d\n", minor->cfg->slot_cnt);
+ if ( minor->cfg->timeslot ) {
+ timefree = gr1553bc_minor_freetime(minor);
+ printf(" timefree: %d\n", timefree);
+ printf(" timetotal: %d\n",
+ minor->cfg->timeslot);
+ } else {
+ printf(" no time mgr\n");
+ }
+ }
+ }
+}
diff --git a/c/src/lib/libbsp/sparc/shared/1553/gr1553bm.c b/c/src/lib/libbsp/sparc/shared/1553/gr1553bm.c
new file mode 100644
index 0000000000..2ceb2a9046
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/1553/gr1553bm.c
@@ -0,0 +1,526 @@
+/* GR1553B BM driver
+ *
+ * COPYRIGHT (c) 2010.
+ * Aeroflex Gaisler.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2010-03-15, Daniel Hellstrom <daniel@gaisler.com>
+ * Created
+ *
+ * OVERVIEW
+ * ========
+ * See header file
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+
+#include <gr1553b.h>
+#include <gr1553bm.h>
+
+
+#define GR1553BM_WRITE_MEM(adr, val) *(volatile uint32_t *)(adr) = (val)
+#define GR1553BM_READ_MEM(adr) (*(volatile uint32_t *)(adr))
+
+#define GR1553BM_WRITE_REG(adr, val) *(volatile uint32_t *)(adr) = (val)
+#define GR1553BM_READ_REG(adr) (*(volatile uint32_t *)(adr))
+
+#ifndef IRQ_GLOBAL_PREPARE
+ #define IRQ_GLOBAL_PREPARE(level) rtems_interrupt_level level
+#endif
+
+#ifndef IRQ_GLOBAL_DISABLE
+ #define IRQ_GLOBAL_DISABLE(level) rtems_interrupt_disable(level)
+#endif
+
+#ifndef IRQ_GLOBAL_ENABLE
+ #define IRQ_GLOBAL_ENABLE(level) rtems_interrupt_enable(level)
+#endif
+
+struct gr1553bm_priv {
+ struct drvmgr_dev **pdev;
+ struct gr1553b_regs *regs;
+
+ void *buffer;
+ unsigned int buffer_base_hw;
+ unsigned int buffer_base;
+ unsigned int buffer_end;
+ unsigned int buffer_size;
+ unsigned int read_pos;
+ int started;
+ struct gr1553bm_config cfg;
+
+ /* Time updated by IRQ when 24-bit Time counter overflows */
+ volatile uint64_t time;
+};
+
+void gr1553bm_isr(void *data);
+
+/* Default Driver configuration */
+struct gr1553bm_config gr1553bm_default_config =
+{
+ /* Highest resolution, use Time overflow IRQ to track */
+ .time_resolution = 0,
+ .time_ovf_irq = 1,
+
+ /* No filtering, log all */
+ .filt_error_options = GR1553BM_ERROPTS_ALL,
+ .filt_rtadr = 0xffffffff,
+ .filt_subadr = 0xffffffff,
+ .filt_mc = 0x0007ffff,
+
+ /* 128Kbyte dynamically allocated buffer. */
+ .buffer_size = 128*1024,
+ .buffer_custom = NULL,
+};
+
+void gr1553bm_register(void)
+{
+ /* The BM driver rely on the GR1553B Driver */
+ gr1553_register();
+}
+
+static void gr1553bm_hw_start(struct gr1553bm_priv *priv)
+{
+ IRQ_GLOBAL_PREPARE(oldLevel);
+
+ /* Enable IRQ source and mark running state */
+ IRQ_GLOBAL_DISABLE(oldLevel);
+
+ priv->started = 1;
+
+ /* Clear old IRQ flags */
+ priv->regs->irq = GR1553B_IRQ_BMD | GR1553B_IRQ_BMTOF;
+
+ /* Unmask IRQ sources */
+ if ( priv->cfg.time_ovf_irq ) {
+ priv->regs->imask |= GR1553B_IRQEN_BMDE | GR1553B_IRQEN_BMTOE;
+ } else {
+ priv->regs->imask |= GR1553B_IRQEN_BMDE;
+ }
+
+ /* Start logging */
+ priv->regs->bm_ctrl =
+ (priv->cfg.filt_error_options &
+ (GR1553B_BM_CTRL_MANL|GR1553B_BM_CTRL_UDWL|GR1553B_BM_CTRL_IMCL))
+ | GR1553B_BM_CTRL_BMEN;
+
+ IRQ_GLOBAL_ENABLE(oldLevel);
+}
+
+static void gr1553bm_hw_stop(struct gr1553bm_priv *priv)
+{
+ IRQ_GLOBAL_PREPARE(oldLevel);
+
+ IRQ_GLOBAL_DISABLE(oldLevel);
+
+ /* Stop Logging */
+ priv->regs->bm_ctrl = 0;
+
+ /* Stop IRQ source */
+ priv->regs->imask &= ~(GR1553B_IRQEN_BMDE|GR1553B_IRQEN_BMTOE);
+
+ /* Clear IRQ flags */
+ priv->regs->irq = GR1553B_IRQ_BMD | GR1553B_IRQ_BMTOF;
+
+ priv->started = 0;
+
+ IRQ_GLOBAL_ENABLE(oldLevel);
+}
+
+/* Open device by number */
+void *gr1553bm_open(int minor)
+{
+ struct drvmgr_dev **pdev = NULL;
+ struct gr1553bm_priv *priv = NULL;
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
+
+ /* Allocate requested device */
+ pdev = gr1553_bm_open(minor);
+ if ( pdev == NULL )
+ goto fail;
+
+ priv = malloc(sizeof(struct gr1553bm_priv));
+ if ( priv == NULL )
+ goto fail;
+ memset(priv, 0, sizeof(struct gr1553bm_priv));
+
+ /* Init BC device */
+ priv->pdev = pdev;
+ (*pdev)->priv = priv;
+
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)(*pdev)->businfo;
+ pnpinfo = &ambadev->info;
+ priv->regs = (struct gr1553b_regs *)pnpinfo->apb_slv->start;
+
+ /* Start with default configuration */
+ priv->cfg = gr1553bm_default_config;
+
+ /* Unmask IRQs */
+ gr1553bm_hw_stop(priv);
+
+ return priv;
+
+fail:
+ if ( pdev )
+ gr1553_bm_close(pdev);
+ if ( priv )
+ free(priv);
+ return NULL;
+}
+
+/* Close previously */
+void gr1553bm_close(void *bm)
+{
+ struct gr1553bm_priv *priv = bm;
+
+ if ( priv->started ) {
+ gr1553bm_stop(bm);
+ }
+
+ if ( (priv->cfg.buffer_custom == NULL) && priv->buffer )
+ free(priv->buffer);
+
+ gr1553_bm_close(priv->pdev);
+ free(priv);
+}
+
+/* Configure the BM driver */
+int gr1553bm_config(void *bm, struct gr1553bm_config *cfg)
+{
+ struct gr1553bm_priv *priv = bm;
+
+ if ( priv->started )
+ return -1;
+
+ /* Check Config validity? */
+/*#warning IMPLEMENT.*/
+
+ /* Free old buffer if dynamically allocated */
+ if ( (priv->cfg.buffer_custom == NULL) && priv->buffer ) {
+ free(priv->buffer);
+ priv->buffer = NULL;
+ }
+ priv->buffer_size = cfg->buffer_size & ~0x7; /* on 8 byte bounadry */
+ if ( cfg->buffer_custom == NULL ) {
+ /* Allocate new buffer dynamically */
+ priv->buffer = malloc(priv->buffer_size + 8);
+ if ( priv->buffer == NULL )
+ return -1;
+ } else {
+ if ( (unsigned int)cfg->buffer_custom & 1 ) {
+ /* Custom Address Given in Remote address. We need
+ * to convert it intoTranslate into Hardware a
+ * hardware accessible address
+ */
+ drvmgr_translate(
+ *priv->pdev,
+ 1,
+ 1,
+ (void *)((unsigned int)cfg->buffer_custom & ~1),
+ (void **)&priv->buffer
+ );
+ } else {
+ /* Address given in CPU accessible address, no
+ * translation required.
+ */
+ priv->buffer = cfg->buffer_custom;
+ }
+ }
+
+ /* Align to 16 bytes */
+ priv->buffer_base = ((unsigned int)priv->buffer + (8-1)) & ~(8-1);
+
+ /* Translate address of buffer base into address that Hardware must
+ * use to access the buffer.
+ */
+ drvmgr_translate(
+ *priv->pdev,
+ 0,
+ 0,
+ (void *)priv->buffer_base,
+ (void **)&priv->buffer_base_hw
+ );
+
+ /* Copy valid config */
+ priv->cfg = *cfg;
+
+ return 0;
+}
+
+/* Start logging */
+int gr1553bm_start(void *bm)
+{
+ struct gr1553bm_priv *priv = bm;
+
+ if ( priv->started )
+ return -1;
+ if ( priv->buffer == NULL )
+ return -2;
+
+ /* Start at Time = 0 */
+ priv->regs->bm_ttag =
+ priv->cfg.time_resolution << GR1553B_BM_TTAG_RES_BIT;
+
+ /* Configure Filters */
+ priv->regs->bm_adr = priv->cfg.filt_rtadr;
+ priv->regs->bm_subadr = priv->cfg.filt_subadr;
+ priv->regs->bm_mc = priv->cfg.filt_mc;
+
+ /* Set up buffer */
+ priv->regs->bm_start = priv->buffer_base_hw;
+ priv->regs->bm_end = priv->buffer_base_hw + priv->cfg.buffer_size - 4;
+ priv->regs->bm_pos = priv->buffer_base_hw;
+ priv->read_pos = priv->buffer_base;
+ priv->buffer_end = priv->buffer_base + priv->cfg.buffer_size;
+
+ /* Register ISR handler and unmask IRQ source at IRQ controller */
+ if (drvmgr_interrupt_register(*priv->pdev, 0, "gr1553bm", gr1553bm_isr, priv))
+ return -3;
+
+ /* Start hardware and set priv->started */
+ gr1553bm_hw_start(priv);
+
+ return 0;
+}
+
+/* Stop logging */
+void gr1553bm_stop(void *bm)
+{
+ struct gr1553bm_priv *priv = bm;
+
+ /* Stop Hardware */
+ gr1553bm_hw_stop(priv);
+
+ /* At this point the hardware must be stopped and IRQ
+ * sources unmasked.
+ */
+
+ /* Unregister ISR handler and unmask 1553 IRQ source at IRQ ctrl */
+ drvmgr_interrupt_unregister(*priv->pdev, 0, gr1553bm_isr, priv);
+}
+
+int gr1553bm_started(void *bm)
+{
+ return ((struct gr1553bm_priv *)bm)->started;
+}
+
+/* Get 64-bit 1553 Time.
+ *
+ * Update software time counters and return the current time.
+ */
+void gr1553bm_time(void *bm, uint64_t *time)
+{
+ struct gr1553bm_priv *priv = bm;
+ unsigned int hwtime, hwtime2;
+
+resample:
+ if ( priv->started && (priv->cfg.time_ovf_irq == 0) ) {
+ /* Update Time overflow counter. The carry bit from Time counter
+ * is located in IRQ Flag.
+ *
+ * When IRQ is not used this function must be called often
+ * enough to avoid that the Time overflows and the carry
+ * bit is already set. The frequency depends on the Time
+ * resolution.
+ */
+ if ( priv->regs->irq & GR1553B_IRQ_BMTOF ) {
+ /* Clear carry bit */
+ priv->regs->irq = GR1553B_IRQ_BMTOF;
+ priv->time += (GR1553B_BM_TTAG_VAL + 1);
+ }
+ }
+
+ /* Report current Time, even if stopped */
+ hwtime = priv->regs->bm_ttag & GR1553B_BM_TTAG_VAL;
+ if ( time )
+ *time = priv->time | hwtime;
+
+ if ( priv->cfg.time_ovf_irq ) {
+ /* Detect wrap around */
+ hwtime2 = priv->regs->bm_ttag & GR1553B_BM_TTAG_VAL;
+ if ( hwtime > hwtime2 ) {
+ /* priv->time and hwtime may be out of sync if
+ * IRQ updated priv->time just after bm_ttag was read
+ * here, we resample if we detect inconsistancy.
+ */
+ goto resample;
+ }
+ }
+}
+
+/* Number of entries available in DMA buffer */
+int gr1553bm_available(void *bm, int *nentries)
+{
+ struct gr1553bm_priv *priv = bm;
+ unsigned int top, bot, pos;
+
+ if ( !priv->started )
+ return -1;
+
+ /* Get BM posistion in log */
+ pos = priv->regs->bm_pos;
+
+ /* Convert into CPU accessible address */
+ pos = priv->buffer_base + (pos - priv->buffer_base_hw);
+
+ if ( pos >= priv->read_pos ) {
+ top = (pos - priv->read_pos)/sizeof(struct gr1553bm_entry);
+ bot = 0;
+ } else {
+ top = (priv->buffer_end - priv->read_pos)/sizeof(struct gr1553bm_entry);
+ bot = (pos - priv->buffer_base)/sizeof(struct gr1553bm_entry);
+ }
+
+ if ( nentries )
+ *nentries = top+bot;
+
+ return 0;
+}
+
+/* Read a maximum number of entries from LOG buffer. */
+int gr1553bm_read(void *bm, struct gr1553bm_entry *dst, int *max)
+{
+ struct gr1553bm_priv *priv = bm;
+ unsigned int dest, pos, left, newPos, len;
+ unsigned int topAdr, botAdr, topLen, botLen;
+
+ if ( !priv || !priv->started )
+ return -1;
+
+ left = *max;
+ pos = priv->regs->bm_pos & ~0x7;
+
+ /* Convert into CPU accessible address */
+ pos = priv->buffer_base + (pos - priv->buffer_base_hw);
+
+ if ( (pos == priv->read_pos) || (left < 1) ) {
+ /* No data available */
+ *max = 0;
+ return 0;
+ }
+ newPos = 0;
+
+ /* Addresses and lengths of BM log buffer */
+ if ( pos >= priv->read_pos ) {
+ /* Read Top only */
+ topAdr = priv->read_pos;
+ botAdr = 0;
+ topLen = (pos - priv->read_pos)/sizeof(struct gr1553bm_entry);
+ botLen = 0;
+ } else {
+ /* Read Top and Bottom */
+ topAdr = priv->read_pos;
+ botAdr = priv->buffer_base;
+ topLen = (priv->buffer_end - priv->read_pos)/sizeof(struct gr1553bm_entry);
+ botLen = (pos - priv->buffer_base)/sizeof(struct gr1553bm_entry);
+ }
+
+ dest = (unsigned int)dst;
+ if ( topLen > 0 ) {
+ /* Copy from top area first */
+ if ( topLen > left ) {
+ len = left;
+ left = 0;
+ } else {
+ len = topLen;
+ left -= topLen;
+ }
+ newPos = topAdr + (len * sizeof(struct gr1553bm_entry));
+ if ( newPos >= priv->buffer_end )
+ newPos -= priv->buffer_size;
+ if ( priv->cfg.copy_func ) {
+ dest += priv->cfg.copy_func(
+ dest, /*Optional Destination*/
+ (void *)topAdr, /* DMA start address */
+ len, /* Number of entries */
+ priv->cfg.copy_func_arg /* Custom ARG */
+ );
+ } else {
+ memcpy( (void *)dest,
+ (void *)topAdr,
+ len * sizeof(struct gr1553bm_entry));
+ dest += len * sizeof(struct gr1553bm_entry);
+ }
+ }
+
+ if ( (botLen > 0) && (left > 0) ) {
+ /* Copy bottom area last */
+ if ( botLen > left ) {
+ len = left;
+ left = 0;
+ } else {
+ len = botLen;
+ left -= botLen;
+ }
+ newPos = botAdr + (len * sizeof(struct gr1553bm_entry));
+
+ if ( priv->cfg.copy_func ) {
+ priv->cfg.copy_func(
+ dest, /*Optional Destination*/
+ (void *)botAdr, /* DMA start address */
+ len, /* Number of entries */
+ priv->cfg.copy_func_arg /* Custom ARG */
+ );
+ } else {
+ memcpy( (void *)dest,
+ (void *)botAdr,
+ len * sizeof(struct gr1553bm_entry));
+ }
+ }
+
+ /* Remember last read posistion in buffer */
+ /*printf("New pos: 0x%08x (0x%08x), %d\n", newPos, priv->read_pos, *max - left);*/
+ priv->read_pos = newPos;
+
+ /* Return number of entries read */
+ *max = *max - left;
+
+ return 0;
+}
+
+/* Note: This is a shared interrupt handler, with BC/RT driver
+ * we must determine the cause of IRQ before handling it.
+ */
+void gr1553bm_isr(void *data)
+{
+ struct gr1553bm_priv *priv = data;
+ uint32_t irqflag;
+
+ /* Get Causes */
+ irqflag = priv->regs->irq & (GR1553B_IRQ_BMD | GR1553B_IRQ_BMTOF);
+
+ /* Check spurious IRQs */
+ if ( (irqflag == 0) || (priv->started == 0) )
+ return;
+
+ if ( (irqflag & GR1553B_IRQ_BMTOF) && priv->cfg.time_ovf_irq ) {
+ /* 1553 Time Over flow. Time is 24-bits */
+ priv->time += (GR1553B_BM_TTAG_VAL + 1);
+
+ /* Clear cause handled */
+ priv->regs->irq = GR1553B_IRQ_BMTOF;
+ }
+
+ if ( irqflag & GR1553B_IRQ_BMD ) {
+ /* BM DMA ERROR. Fatal error, we stop BM hardware and let
+ * user take care of it. From now on all calls will result
+ * in an error because the BM is stopped (priv->started=0).
+ */
+
+ /* Clear cause handled */
+ priv->regs->irq = GR1553B_IRQ_BMD;
+
+ if ( priv->cfg.dma_error_isr )
+ priv->cfg.dma_error_isr(data, priv->cfg.dma_error_arg);
+
+ gr1553bm_hw_stop(priv);
+ }
+}
diff --git a/c/src/lib/libbsp/sparc/shared/1553/gr1553rt.c b/c/src/lib/libbsp/sparc/shared/1553/gr1553rt.c
new file mode 100644
index 0000000000..7ada4d1ac7
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/1553/gr1553rt.c
@@ -0,0 +1,1250 @@
+/* GR1553B RT driver
+ *
+ * COPYRIGHT (c) 2010.
+ * Aeroflex Gaisler.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2010-03-15, Daniel Hellstrom <daniel@gaisler.com>
+ * Created
+ *
+ *
+ * OVERVIEW
+ * ========
+ * See header file.
+ */
+
+
+#include <rtems.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <gr1553b.h>
+#include <gr1553rt.h>
+
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+
+#define GR1553RT_WRITE_MEM(adr, val) *(volatile uint32_t *)(adr) = (val)
+#define GR1553RT_READ_MEM(adr) (*(volatile uint32_t *)(adr))
+
+#define GR1553RT_WRITE_REG(adr, val) *(volatile uint32_t *)(adr) = (val)
+#define GR1553RT_READ_REG(adr) (*(volatile uint32_t *)(adr))
+
+#ifndef IRQ_GLOBAL_PREPARE
+ #define IRQ_GLOBAL_PREPARE(level) rtems_interrupt_level level
+#endif
+
+#ifndef IRQ_GLOBAL_DISABLE
+ #define IRQ_GLOBAL_DISABLE(level) rtems_interrupt_disable(level)
+#endif
+
+#ifndef IRQ_GLOBAL_ENABLE
+ #define IRQ_GLOBAL_ENABLE(level) rtems_interrupt_enable(level)
+#endif
+
+/* Software representation of one hardware descriptor */
+struct gr1553rt_sw_bd {
+ unsigned short this_next;/* Next entry or this entry. 0xffff: no next */
+ unsigned char listid; /* ListID of List the descriptor is attached */
+ char unused;
+} __attribute__((packed));
+
+/* Software description of a subaddress */
+struct gr1553rt_subadr {
+ /* RX LIST */
+ unsigned char rxlistid;
+ /* TX LIST */
+ unsigned char txlistid;
+};
+
+struct gr1553rt_irqerr {
+ gr1553rt_irqerr_t func;
+ void *data;
+};
+
+struct gr1553rt_irqmc {
+ gr1553rt_irqmc_t func;
+ void *data;
+};
+
+struct gr1553rt_irq {
+ gr1553rt_irq_t func;
+ void *data;
+};
+
+struct gr1553rt_priv {
+ /* Pointer to Hardware registers */
+ struct gr1553b_regs *regs;
+
+ /* Software State */
+ int started;
+ struct gr1553rt_cfg cfg;
+
+ /* Handle to GR1553B RT device layer */
+ struct drvmgr_dev **pdev;
+
+ /* Each Index represents one RT Subaddress. 31 = Broadcast */
+ struct gr1553rt_subadr subadrs[32];
+
+ /* Pointer to array of Software's description of a hardware
+ * descriptor.
+ */
+#if (RTBD_MAX == 0)
+ struct gr1553rt_sw_bd *swbds;
+#else
+ struct gr1553rt_sw_bd swbds[RTBD_MAX];
+#endif
+
+ /* List of Free descriptors */
+ unsigned short swbd_free;
+ int swbd_free_cnt;
+
+ /* Hardware SubAddress descriptors given for CPU and Hardware */
+ void *satab_buffer;
+ struct gr1553rt_sa *sas_cpu; /* Translated for CPU */
+ struct gr1553rt_sa *sas_hw; /* Translated for Hardware */
+
+ /* Hardware descriptors address given for CPU and hardware */
+ void *bd_buffer;
+ int bds_cnt; /* Number of descriptors */
+ struct gr1553rt_bd *bds_cpu; /* Translated for CPU */
+ struct gr1553rt_bd *bds_hw; /* Translated for Hardware */
+
+
+ /* Event Log buffer in */
+ void *evlog_buffer;
+ unsigned int *evlog_cpu_next; /* Next LOG entry to be handled */
+ unsigned int *evlog_cpu_base; /* First Entry in LOG */
+ unsigned int *evlog_cpu_end; /* Last+1 Entry in LOG */
+ unsigned int *evlog_hw_base; /* Translated for Hardware */
+
+ /* Each Index represents a LIST ID */
+ struct gr1553rt_list *lists[RTLISTID_MAX];
+
+ /* IRQ handlers, one per SUBADDRESS */
+ struct gr1553rt_irq irq_rx[32];
+ struct gr1553rt_irq irq_tx[32];
+
+ /* ISR called when an ERROR IRQ is received */
+ struct gr1553rt_irqerr irq_err;
+
+ /* ISR called when an Mode Code is received */
+ struct gr1553rt_irqmc irq_mc;
+};
+
+void gr1553rt_sw_init(struct gr1553rt_priv *priv);
+void gr1553rt_sw_free(struct gr1553rt_priv *priv);
+int gr1553rt_sw_alloc(struct gr1553rt_priv *priv);
+
+/* Assign and ID to the list. An LIST ID is needed before scheduling list
+ * on an RT subaddress.
+ *
+ * Only 64 lists can be registered at a time on the same device.
+ */
+int gr1553rt_list_reg(struct gr1553rt_list *list)
+{
+ struct gr1553rt_priv *priv = list->rt;
+ int i;
+
+ /* Find first free list ID */
+ for ( i=0; i<RTLISTID_MAX; i++) {
+ if ( priv->lists[i] == NULL ) {
+ priv->lists[i] = list;
+ list->listid = i;
+ return i;
+ }
+ }
+
+ /* No available LIST IDs */
+ list->listid = -1;
+
+ return -1;
+}
+
+/* Unregister List from device */
+void gr1553rt_list_unreg(struct gr1553rt_list *list)
+{
+ struct gr1553rt_priv *priv = list->rt;
+
+ priv->lists[list->listid] = NULL;
+ list->listid = -1;
+}
+
+static int gr1553rt_bdid(void *rt, struct gr1553rt_sw_bd *bd)
+{
+ struct gr1553rt_priv *priv = rt;
+
+ unsigned short index;
+
+ /* Get Index of Software BD */
+ index = ((unsigned int)bd - (unsigned int)&priv->swbds[0]) /
+ sizeof(struct gr1553rt_sw_bd);
+
+ return index;
+}
+
+void gr1553rt_bd_alloc_init(void *rt, int count)
+{
+ struct gr1553rt_priv *priv = rt;
+ int i;
+
+ for (i=0; i<count-1; i++) {
+ priv->swbds[i].this_next = i+1;
+ }
+ priv->swbds[count-1].this_next = 0xffff;
+ priv->swbd_free = 0;
+ priv->swbd_free_cnt = count;
+}
+
+/* Allocate a Chain of descriptors */
+int gr1553rt_bd_alloc(void *rt, struct gr1553rt_sw_bd **bd, int cnt)
+{
+ struct gr1553rt_priv *priv = rt;
+ struct gr1553rt_sw_bd *curr;
+ int i;
+
+ if ( priv->swbd_free_cnt < cnt ) {
+ *bd = NULL;
+ return -1;
+ }
+
+ *bd = &priv->swbds[priv->swbd_free];
+ for (i=0; i<cnt; i++) {
+ if ( i == 0) {
+ curr = &priv->swbds[priv->swbd_free];
+ } else {
+ curr = &priv->swbds[curr->this_next];
+ }
+ if ( curr->this_next == 0xffff ) {
+ *bd = NULL;
+ return -1;
+ }
+ }
+ priv->swbd_free = curr->this_next;
+ priv->swbd_free_cnt -= cnt;
+ curr->this_next = 0xffff; /* Mark end of chain on last entry */
+
+ return 0;
+}
+
+void gr1553rt_bd_free(void *rt, struct gr1553rt_sw_bd *bd)
+{
+ struct gr1553rt_priv *priv = rt;
+ unsigned short index;
+
+ /* Get Index of Software BD */
+ index = gr1553rt_bdid(priv, bd);
+
+ /* Insert first in list */
+ bd->this_next = priv->swbd_free;
+ priv->swbd_free = index;
+ priv->swbd_free_cnt++;
+}
+
+int gr1553rt_list_init
+ (
+ void *rt,
+ struct gr1553rt_list **plist,
+ struct gr1553rt_list_cfg *cfg
+ )
+{
+ struct gr1553rt_priv *priv = rt;
+ int i, size;
+ struct gr1553rt_sw_bd *swbd;
+ unsigned short index;
+ struct gr1553rt_list *list;
+
+ /* The user may provide a pre allocated LIST, or
+ * let the driver handle allocation by using malloc()
+ *
+ * If the IN/OUT plist argument points to NULL a list
+ * dynamically allocated here.
+ */
+ list = *plist;
+ if ( list == NULL ) {
+ /* Dynamically allocate LIST */
+ size = offsetof(struct gr1553rt_list, bds) +
+ (cfg->bd_cnt * sizeof(unsigned short));
+ list = (struct gr1553rt_list *)malloc(size);
+ if ( list == NULL )
+ return -1;
+ *plist = list;
+ }
+
+ list->rt = rt;
+ list->subadr = -1;
+ list->listid = gr1553rt_list_reg(list);
+ if ( list->listid == -1 )
+ return -2; /* Too many lists */
+ list->cfg = cfg;
+ list->bd_cnt = cfg->bd_cnt;
+
+ /* Allocate all BDs needed by list */
+ if ( gr1553rt_bd_alloc(rt, &swbd, list->bd_cnt) ) {
+ return -3; /* Too few descriptors */
+ }
+
+ /* Get ID/INDEX of Software BDs */
+ index = gr1553rt_bdid(rt, swbd);
+ list->bds[0] = index;
+ for (i=1; i<list->bd_cnt; i++) {
+ list->bds[i] = priv->swbds[list->bds[i-1]].this_next;
+ }
+
+ /* Now that the next pointer has fullfilled it's job and not
+ * needed anymore, we use it as list entry pointer instead.
+ * The this_next pointer is a list entry number.
+ */
+ for (i=0; i<list->bd_cnt; i++) {
+ priv->swbds[list->bds[i]].this_next = i;
+ }
+
+ return 0;
+}
+
+int gr1553rt_bd_init(
+ struct gr1553rt_list *list,
+ unsigned short entry_no,
+ unsigned int flags,
+ uint16_t *dptr,
+ unsigned short next
+ )
+{
+ struct gr1553rt_priv *priv;
+ unsigned short bdid;
+ struct gr1553rt_bd *bd;
+ unsigned int nextbd, dataptr;
+ IRQ_GLOBAL_PREPARE(oldLevel);
+
+ if ( entry_no >= list->bd_cnt )
+ return -1;
+
+ /* Find Descriptor */
+ bdid = list->bds[entry_no];
+ priv = list->rt;
+ bd = &priv->bds_cpu[bdid];
+
+ if ( next == 0xfffe ) {
+ next = entry_no + 1;
+ if ( next >= list->bd_cnt )
+ next = 0;
+ }
+
+ /* Find next descriptor in address space that the
+ * Hardware understand.
+ */
+ if ( next >= 0xffff ) {
+ nextbd = 0x3; /* End of list */
+ } else if ( next >= list->bd_cnt ) {
+ return -1;
+ } else {
+ bdid = list->bds[next];
+ nextbd = (unsigned int)&priv->bds_hw[bdid];
+ }
+
+ dataptr = (unsigned int)dptr;
+ if ( dataptr & 1 ) {
+ /* Translate address from CPU-local into remote */
+ dataptr &= ~1;
+ drvmgr_translate(
+ *priv->pdev,
+ 0,
+ 0,
+ (void *)dataptr,
+ (void **)&dataptr
+ );
+ }
+
+ /* Get current status, and clear */
+ IRQ_GLOBAL_DISABLE(oldLevel);
+ bd->ctrl = flags & GR1553RT_BD_FLAGS_IRQEN;
+ bd->dptr = (unsigned int)dptr;
+ bd->next = nextbd;
+ IRQ_GLOBAL_ENABLE(oldLevel);
+
+ return 0;
+}
+
+int gr1553rt_bd_update(
+ struct gr1553rt_list *list,
+ int entry_no,
+ unsigned int *status,
+ uint16_t **dptr
+ )
+{
+ struct gr1553rt_priv *priv;
+ unsigned short bdid;
+ struct gr1553rt_bd *bd;
+ unsigned int tmp, dataptr;
+ IRQ_GLOBAL_PREPARE(oldLevel);
+
+ if ( entry_no >= list->bd_cnt )
+ return -1;
+
+ /* Find Descriptor */
+ bdid = list->bds[entry_no];
+ priv = list->rt;
+ bd = &priv->bds_cpu[bdid];
+
+ /* Prepare translation if needed */
+ if ( dptr && (dataptr=(unsigned int)*dptr) ) {
+ if ( dataptr & 1 ) {
+ /* Translate address from CPU-local into remote. May
+ * be used when RT core is accessed over the PCI bus.
+ */
+ dataptr &= ~1;
+ drvmgr_translate(
+ *priv->pdev,
+ 0,
+ 0,
+ (void *)dataptr,
+ (void **)&dataptr
+ );
+ }
+ }
+
+ /* Get current status, and clear */
+ IRQ_GLOBAL_DISABLE(oldLevel);
+ /* READ/WRITE Status/Control word */
+ if ( status ) {
+ tmp = bd->ctrl;
+ if ( *status ) {
+ bd->ctrl = *status;
+ }
+ *status = tmp;
+ }
+ /* READ/WRITE Data-Pointer word */
+ if ( dptr ) {
+ tmp = bd->dptr;
+ if ( dataptr ) {
+ bd->dptr = dataptr;
+ }
+ *dptr = (uint16_t *)tmp;
+ }
+ IRQ_GLOBAL_ENABLE(oldLevel);
+
+ return 0;
+}
+
+int gr1553rt_irq_err
+ (
+ void *rt,
+ gr1553rt_irqerr_t func,
+ void *data
+ )
+{
+ struct gr1553rt_priv *priv = rt;
+ IRQ_GLOBAL_PREPARE(oldLevel);
+
+ IRQ_GLOBAL_DISABLE(oldLevel);
+ priv->irq_err.func = func;
+ priv->irq_err.data = data;
+ IRQ_GLOBAL_ENABLE(oldLevel);
+
+ return 0;
+}
+
+int gr1553rt_irq_mc
+ (
+ void *rt,
+ gr1553rt_irqmc_t func,
+ void *data
+ )
+{
+ struct gr1553rt_priv *priv = rt;
+ IRQ_GLOBAL_PREPARE(oldLevel);
+
+ IRQ_GLOBAL_DISABLE(oldLevel);
+ priv->irq_mc.func = func;
+ priv->irq_mc.data = data;
+ IRQ_GLOBAL_ENABLE(oldLevel);
+
+ return 0;
+}
+
+int gr1553rt_irq_sa
+ (
+ void *rt,
+ int subadr,
+ int tx,
+ gr1553rt_irq_t func,
+ void *data
+ )
+{
+ struct gr1553rt_priv *priv = rt;
+ IRQ_GLOBAL_PREPARE(oldLevel);
+
+ IRQ_GLOBAL_DISABLE(oldLevel);
+ if ( tx ) {
+ priv->irq_tx[subadr].func = func;
+ priv->irq_tx[subadr].data = data;
+ } else {
+ priv->irq_rx[subadr].func = func;
+ priv->irq_rx[subadr].data = data;
+ }
+ IRQ_GLOBAL_ENABLE(oldLevel);
+
+ return 0;
+}
+
+/* GR1553-RT Interrupt Service Routine */
+void gr1553rt_isr(void *data)
+{
+ struct gr1553rt_priv *priv = data;
+ unsigned int firstirq, lastpos;
+ int index;
+ unsigned int *last, *curr, entry, hwbd;
+ int type, samc, mcode, subadr;
+ int listid;
+ struct gr1553rt_irq *isr;
+ struct gr1553rt_irqerr *isrerr;
+ struct gr1553rt_irqmc *isrmc;
+ unsigned int irq;
+
+ /* Ack IRQ before reading current write pointer, but after
+ * reading current IRQ pointer. This is because RT_EVIRQ
+ * may be updated after we ACK the IRQ source.
+ */
+ irq = priv->regs->irq &
+ (GR1553B_IRQ_RTTE|GR1553B_IRQ_RTD|GR1553B_IRQ_RTEV);
+ if ( irq == 0 )
+ return;
+
+ firstirq = priv->regs->rt_evirq;
+ priv->regs->irq = irq;
+ lastpos = priv->regs->rt_evlog;
+
+ /* Quit if nothing has been added to the log */
+ if ( lastpos == firstirq )
+ return;
+
+ if ( irq & (GR1553B_IRQ_RTTE|GR1553B_IRQ_RTD) ) {
+ isrerr = &priv->irq_err;
+ if ( isrerr->func ) {
+ isrerr->func(irq, isrerr->data);
+ }
+
+ /* Stop Hardware and enter non-started mode. This will
+ * make all future calls to driver result in an error.
+ */
+ gr1553rt_stop(priv);
+ }
+
+ /* Step between first log entry causing an IRQ to last
+ * entry. Each entry that has caused an IRQ will be handled
+ * by calling user-defined function.
+ *
+ * We convert hardware addresses into CPU accessable addresses
+ * first.
+ */
+ index = (firstirq - (unsigned int)priv->evlog_hw_base) /
+ sizeof(unsigned int);
+ curr = priv->evlog_cpu_base + index;
+ index = (lastpos - (unsigned int)priv->evlog_hw_base) /
+ sizeof(unsigned int);
+ last = priv->evlog_cpu_base + index;
+
+ do {
+ /* Process one entry */
+ entry = *curr;
+
+ if ( entry & 0x80000000 ) {
+ /* Entry caused IRQ */
+ type = (entry >> 29) & 0x3;
+ samc = (entry >> 24) & 0x1f;
+ if ( (type & 0x2) == 0 ) {
+ /* Transmit/Receive Data */
+ subadr = samc;
+ if ( type ) {
+ /* Receive */
+ listid = priv->subadrs[subadr].rxlistid;
+ hwbd = priv->sas_cpu[subadr].rxptr;
+ isr = &priv->irq_rx[subadr];
+ } else {
+ /* Transmit */
+ listid = priv->subadrs[subadr].txlistid;
+ hwbd = priv->sas_cpu[subadr].txptr;
+ isr = &priv->irq_tx[subadr];
+ }
+
+ index = ((unsigned int)hwbd - (unsigned int)
+ priv->bds_hw)/sizeof(struct gr1553rt_bd);
+
+ /* Call user ISR of RX/TX transfer */
+ if ( isr->func ) {
+ isr->func(
+ priv->lists[listid],
+ entry,
+ priv->swbds[index].this_next,
+ isr->data
+ );
+ }
+ } else if ( type == 0x2) {
+ /* Modecode */
+ mcode = samc;
+ isrmc = &priv->irq_mc;
+
+ /* Call user ISR of ModeCodes RX/TX */
+ if ( isrmc->func ) {
+ isrmc->func(
+ mcode,
+ entry,
+ isrmc->data
+ );
+ }
+ } else {
+ /* ERROR OF SOME KIND, EVLOG OVERWRITTEN? */
+ exit(-1);
+ }
+ }
+
+ /* Calc next entry posistion */
+ curr++;
+ if ( curr == priv->evlog_cpu_end )
+ curr = priv->evlog_cpu_base;
+
+ } while ( curr != last );
+}
+
+int gr1553rt_indication(void *rt, int subadr, int *txeno, int *rxeno)
+{
+ struct gr1553rt_priv *priv = rt;
+ struct gr1553rt_sa *sa;
+ unsigned int bd, index;
+
+ /* Sub address valid */
+ if ( (subadr < 0) || (subadr > 31) )
+ return -1;
+
+ /* Get SubAddress Descriptor address as accessed from CPU */
+ sa = &priv->sas_cpu[subadr];
+
+ /* Indication of TX descriptor? */
+ if ( txeno ) {
+ bd = sa->txptr;
+ /* Get Index of Hardware BD */
+ index = ((unsigned int)bd - (unsigned int)&priv->bds_hw[0]) /
+ sizeof(struct gr1553rt_bd);
+ *txeno = priv->swbds[index].this_next;
+ }
+
+ /* Indication of RX descriptor? */
+ if ( rxeno ) {
+ bd = sa->rxptr;
+ /* Get Index of Hardware BD */
+ index = ((unsigned int)bd - (unsigned int)&priv->bds_hw[0]) /
+ sizeof(struct gr1553rt_bd);
+ *rxeno = priv->swbds[index].this_next;
+ }
+
+ return 0;
+}
+
+#if 0
+int gr1553rt_bd_irq(
+ struct gr1553rt_list *list,
+ unsigned short entry_no,
+ void (*func)(struct gr1553rt_list *list, int entry, void *data),
+ void *data
+ )
+{
+ struct gr1553rt_priv *priv = list->rt;
+ int irqid;
+ int ret;
+ IRQ_GLOBAL_PREPARE(oldLevel);
+
+ if ( entry_no == 0xffff ) {
+ /* Default interrupt for all list entries without
+ * assigned IRQ function.
+ */
+ list->irqs[0].func = func;
+ list->irqs[0].data = data;
+ return 0;
+ }
+
+ if ( entry_no >= list->bd_cnt ) {
+ return -1;
+ }
+
+ bdid = list->bds[entry_no];
+ irqid = priv->swbds[bdid].irqid;
+
+ ret = 0;
+ IRQ_GLOBAL_DISABLE(oldLevel);
+ if ( (irqid != 0) && (func == 0) ) {
+ /* Unassign IRQ function */
+ list->irqs[irqid].func = NULL;
+ list->irqs[irqid].data = NULL;
+ irqid = 0; /* Disable IRQ (default handler) */
+ } else if ( priv->swbds[bdid].irqid != 0 ) {
+ /* reassign IRQ function */
+ list->irqs[irqid].func = func;
+ list->irqs[irqid].data = data;
+ } else {
+ /* Find free IRQ spot. If no free irqid=0 (general IRQ) */
+ ret = -1;
+ for (i=0; i<list->cfg->maxirq; i++) {
+ if ( list->irqs[i].func == NULL ) {
+ irqid = i;
+ list->irqs[i].func = func;
+ list->irqs[i].data = data;
+ ret = 0;
+ break;
+ }
+ }
+ }
+ priv->swbds[bdid].irqid = irqid;
+ IRQ_GLOBAL_ENABLE(oldLevel);
+
+ return ret;
+}
+#endif
+
+void gr1553rt_hw_stop(struct gr1553rt_priv *priv);
+
+void gr1553rt_register(void)
+{
+ /* The RT driver rely on the GR1553B Driver */
+ gr1553_register();
+}
+
+void *gr1553rt_open(int minor)
+{
+ struct drvmgr_dev **pdev = NULL;
+ struct gr1553rt_priv *priv = NULL;
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
+
+ /* Allocate requested device */
+ pdev = gr1553_rt_open(minor);
+ if ( pdev == NULL )
+ goto fail;
+
+ priv = malloc(sizeof(struct gr1553rt_priv));
+ if ( priv == NULL )
+ goto fail;
+ memset(priv, 0, sizeof(struct gr1553rt_priv));
+
+ /* Assign a device private to RT device */
+ priv->pdev = pdev;
+ (*pdev)->priv = priv;
+
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)(*pdev)->businfo;
+ pnpinfo = &ambadev->info;
+ priv->regs = (struct gr1553b_regs *)pnpinfo->apb_slv->start;
+
+ /* Start with default configuration */
+ /*priv->cfg = gr1553rt_default_config;*/
+
+ /* Unmask IRQs and so */
+ gr1553rt_hw_stop(priv);
+
+ /* Register ISR handler. hardware mask IRQ, so it is safe to unmask
+ * at IRQ controller.
+ */
+ if (drvmgr_interrupt_register(*priv->pdev, 0, "gr1553rt", gr1553rt_isr, priv))
+ goto fail;
+
+ return priv;
+
+fail:
+ if ( pdev )
+ gr1553_rt_close(pdev);
+ if ( priv )
+ free(priv);
+ return NULL;
+}
+
+void gr1553rt_close(void *rt)
+{
+ struct gr1553rt_priv *priv = rt;
+
+ if ( priv->started ) {
+ gr1553rt_stop(priv);
+ }
+
+ /* Remove ISR handler */
+ drvmgr_interrupt_unregister(*priv->pdev, 0, gr1553rt_isr, priv);
+
+ /* Free dynamically allocated buffers if any */
+ gr1553rt_sw_free(priv);
+
+ /* Return RT/BC device */
+ gr1553_rt_close(priv->pdev);
+}
+
+/* Stop Hardware and disable IRQ */
+void gr1553rt_hw_stop(struct gr1553rt_priv *priv)
+{
+ uint32_t irqmask;
+
+ /* Disable RT */
+ GR1553RT_WRITE_REG(&priv->regs->rt_cfg, GR1553RT_KEY);
+
+ /* Stop BC if not already stopped: BC can not be used simultaneously
+ * as the RT anyway
+ */
+ GR1553RT_WRITE_REG(&priv->regs->bc_ctrl, GR1553BC_KEY | 0x0204);
+
+ /* Turn off RT IRQ generation */
+ irqmask=GR1553RT_READ_REG(&priv->regs->imask);
+ irqmask&=~(GR1553B_IRQEN_RTEVE|GR1553B_IRQEN_RTDE);
+ GR1553RT_WRITE_REG(&priv->regs->irq, irqmask);
+}
+
+/* Free dynamically allocated buffers, if any */
+void gr1553rt_sw_free(struct gr1553rt_priv *priv)
+{
+ /* Event log */
+ if ( (priv->cfg.evlog_buffer == NULL) && priv->evlog_buffer ) {
+ free(priv->evlog_buffer);
+ priv->evlog_buffer = NULL;
+ }
+
+ /* RX/TX Descriptors */
+ if ( (priv->cfg.bd_buffer == NULL) && priv->bd_buffer ) {
+ free(priv->bd_buffer);
+ priv->bd_buffer = NULL;
+ }
+
+#if (RTBD_MAX == 0)
+ if ( priv->swbds ) {
+ free(priv->swbds);
+ priv->swbds = NULL;
+ }
+#endif
+
+ /* Sub address table */
+ if ( (priv->cfg.satab_buffer == NULL) && priv->satab_buffer ) {
+ free(priv->satab_buffer);
+ priv->satab_buffer = NULL;
+ }
+}
+
+/* Free dynamically allocated buffers, if any */
+int gr1553rt_sw_alloc(struct gr1553rt_priv *priv)
+{
+ int size;
+
+ /* Allocate Event log */
+ if ( priv->cfg.evlog_buffer == NULL ) {
+ priv->evlog_buffer = malloc(priv->cfg.evlog_size * 2);
+ } else if ( (unsigned int)priv->cfg.evlog_buffer & 1 ) {
+ /* Translate Address from HARDWARE (REMOTE) to CPU-LOCAL */
+ drvmgr_translate(
+ *priv->pdev,
+ 1,
+ 1,
+ (void *)((unsigned int)priv->cfg.evlog_buffer & ~0x1),
+ (void **)&priv->evlog_buffer
+ );
+ } else {
+ /* Addess already CPU-LOCAL */
+ priv->evlog_buffer = priv->cfg.evlog_buffer;
+ }
+
+ /* Allocate Transfer Descriptors */
+ if ( priv->cfg.bd_buffer == NULL ) {
+ size = priv->cfg.bd_count * sizeof(struct gr1553rt_bd) + 0xf;
+ priv->bd_buffer = malloc(size);
+ } else if ( (unsigned int)priv->cfg.bd_buffer & 1 ) {
+ /* Translate Address from HARDWARE (REMOTE) to CPU-LOCAL */
+ drvmgr_translate(
+ *priv->pdev,
+ 1,
+ 1,
+ (void *)((unsigned int)priv->cfg.bd_buffer & ~0x1),
+ (void **)&priv->bd_buffer
+ );
+ } else {
+ /* Addess already CPU-LOCAL */
+ priv->bd_buffer = priv->cfg.bd_buffer;
+ }
+
+#if (RTBD_MAX == 0)
+ /* Allocate software description of */
+ priv->swbds = malloc(priv->cfg.bd_count * sizeof(struct gr1553rt_sw_bd));
+ if ( priv->swbds == NULL ) {
+ return -1;
+ }
+#endif
+
+ /* Allocate Sub address table */
+ if ( priv->cfg.satab_buffer == NULL ) {
+ priv->satab_buffer = malloc((16 * 32) * 2);
+ } else if ( (unsigned int)priv->cfg.satab_buffer & 1 ) {
+ /* Translate Address from HARDWARE (REMOTE) to CPU-LOCAL */
+ drvmgr_translate(
+ *priv->pdev,
+ 1,
+ 1,
+ (void *)((unsigned int)priv->cfg.satab_buffer & ~0x1),
+ (void **)&priv->satab_buffer
+ );
+ } else {
+ /* Addess already CPU-LOCAL */
+ priv->satab_buffer = priv->cfg.satab_buffer;
+ }
+
+ if ( !priv->evlog_buffer || !priv->bd_buffer || !priv->satab_buffer )
+ return -1;
+
+ return 0;
+}
+
+void gr1553rt_sw_init(struct gr1553rt_priv *priv)
+{
+ unsigned int buf;
+ int i;
+
+ /* Align to 512 bytes boundary */
+ buf = (unsigned int)priv->satab_buffer;
+ buf = (buf + 0x1ff) & ~0x1ff;
+ priv->sas_cpu = (struct gr1553rt_sa *)buf;
+ /* Translate Address from CPU-LOCAL to HARDWARE (REMOTE) */
+ drvmgr_translate(
+ *priv->pdev,
+ 0,
+ 0,
+ (void *)buf,
+ (void **)&priv->sas_hw
+ );
+ memset(priv->sas_cpu, 0, 512);
+
+ /* Align to 16 bytes boundary */
+ buf = (unsigned int)priv->bd_buffer;
+ buf = (buf + 0xf) & ~0xf;
+ priv->bds_cpu = (struct gr1553rt_bd *)buf;
+ /* Translate from CPU address to hardware address */
+ drvmgr_translate(
+ *priv->pdev,
+ 0,
+ 0,
+ (void *)buf,
+ (void **)&priv->bds_hw
+ );
+ priv->bds_cnt = priv->cfg.bd_count;
+ memset(priv->bds_cpu, 0, priv->bds_cnt * 16);
+
+ /* Align to SIZE bytes boundary */
+ buf = (unsigned int)priv->evlog_buffer;
+ buf = (buf + (priv->cfg.evlog_size-1)) & ~(priv->cfg.evlog_size-1);
+ priv->evlog_cpu_base = (unsigned int *)buf;
+ /* Translate from CPU address to hardware address */
+ drvmgr_translate(
+ *priv->pdev,
+ 0,
+ 0,
+ (void *)buf,
+ (void **)&priv->evlog_hw_base
+ );
+ priv->evlog_cpu_end = priv->evlog_cpu_base +
+ priv->cfg.evlog_size/sizeof(unsigned int *);
+ memset(priv->evlog_cpu_base, 0, priv->cfg.evlog_size);
+
+ /* Init descriptor allocation algorithm */
+ gr1553rt_bd_alloc_init(priv, priv->bds_cnt);
+
+ /* Init table used to convert from sub address to list.
+ * Currently non assigned.
+ */
+ for (i=0; i<32; i++) {
+ priv->subadrs[i].rxlistid = 0xff;
+ priv->subadrs[i].txlistid = 0xff;
+ }
+
+ /* Clear all previous IRQ handlers */
+ for (i=0; i<32; i++) {
+ priv->irq_rx[i].func = NULL;
+ priv->irq_tx[i].data = NULL;
+ }
+ priv->irq_err.func = NULL;
+ priv->irq_err.data = NULL;
+ priv->irq_mc.func = NULL;
+ priv->irq_mc.data = NULL;
+
+ /* Clear LIST to LISTID table */
+ for (i=0; i<RTLISTID_MAX; i++) {
+ priv->lists[i] = NULL;
+ }
+}
+
+int gr1553rt_config(void *rt, struct gr1553rt_cfg *cfg)
+{
+ struct gr1553rt_priv *priv = rt;
+
+ if ( priv->started )
+ return -1;
+
+ /*** Free dynamically allocated buffers ***/
+
+ gr1553rt_sw_free(priv);
+
+ /*** Check new config ***/
+ if ( cfg->rtaddress > 30 )
+ return -1;
+ if ( (cfg->evlog_size & (cfg->evlog_size-1)) != 0)
+ return -1; /* SIZE: Not aligned to a power of 2 */
+ if ( ((unsigned int)priv->cfg.evlog_buffer & (cfg->evlog_size-1)) != 0 )
+ return -1; /* Buffer: Not aligned to size */
+#if (RTBD_MAX > 0)
+ if ( cfg->bd_count > RTBD_MAX )
+ return -1;
+#endif
+
+ /*** Make new config current ***/
+ priv->cfg = *cfg;
+
+ /*** Adapt to new config ***/
+
+ if ( gr1553rt_sw_alloc(priv) != 0 )
+ return -1;
+
+ gr1553rt_sw_init(priv);
+
+ return 0;
+}
+
+int gr1553rt_start(void *rt)
+{
+ struct gr1553rt_priv *priv = rt;
+ IRQ_GLOBAL_PREPARE(oldLevel);
+
+ if ( priv->started )
+ return -1;
+
+ /*** Initialize software Pointers and stuff ***/
+
+ if ( !priv->satab_buffer || !priv->bd_buffer || !priv->evlog_buffer )
+ return -2;
+
+ priv->evlog_cpu_next = priv->evlog_cpu_base;
+
+ /*** Initialize Registers ***/
+
+ /* Subaddress table base */
+ priv->regs->rt_tab = (unsigned int)priv->sas_hw;
+
+ /* Mode code configuration */
+ priv->regs->rt_mcctrl = priv->cfg.modecode;
+
+ /* RT Time Tag resolution */
+ priv->regs->rt_ttag = priv->cfg.time_res << 16;
+
+ /* Event LOG base and size */
+ priv->regs->rt_evsz = ~(priv->cfg.evlog_size - 1);
+ priv->regs->rt_evlog = (unsigned int)priv->evlog_hw_base;
+ priv->regs->rt_evirq = 0;
+
+ /* Clear and old IRQ flag and Enable IRQ */
+ IRQ_GLOBAL_DISABLE(oldLevel);
+ priv->regs->irq = GR1553B_IRQ_RTEV|GR1553B_IRQ_RTD|GR1553B_IRQ_RTTE;
+ priv->regs->imask |= GR1553B_IRQEN_RTEVE | GR1553B_IRQEN_RTDE |
+ GR1553B_IRQEN_RTTEE;
+
+ /* Enable and Set RT address */
+ priv->regs->rt_cfg = GR1553RT_KEY |
+ (priv->cfg.rtaddress << GR1553B_RT_CFG_RTADDR_BIT) |
+ GR1553B_RT_CFG_RTEN;
+
+ /* Tell software RT is started */
+ priv->started = 1;
+ IRQ_GLOBAL_ENABLE(oldLevel);
+
+ return 0;
+}
+
+void gr1553rt_stop(void *rt)
+{
+ struct gr1553rt_priv *priv = rt;
+ IRQ_GLOBAL_PREPARE(oldLevel);
+
+ IRQ_GLOBAL_DISABLE(oldLevel);
+
+ /* Stop Hardware */
+ gr1553rt_hw_stop(priv);
+
+ /* Software state */
+ priv->started = 0;
+
+ IRQ_GLOBAL_ENABLE(oldLevel);
+}
+
+void gr1553rt_sa_schedule(
+ void *rt,
+ int subadr,
+ int tx,
+ struct gr1553rt_list *list
+ )
+{
+ struct gr1553rt_priv *priv = rt;
+ unsigned short bdid;
+ struct gr1553rt_bd *bd;
+
+ if ( !list || (list->listid == -1) )
+ return;
+
+ /* Get Hardware address of first descriptor in list */
+ bdid = list->bds[0];
+ if ( bdid == 0xffff )
+ return;
+ bd = &priv->bds_hw[bdid];
+
+ list->subadr = subadr;
+
+ /* Update Sub address table */
+ if ( tx ) {
+ list->subadr |= 0x100;
+ priv->subadrs[subadr].txlistid = list->listid;
+ priv->sas_cpu[subadr].txptr = (unsigned int)bd;
+ } else {
+ priv->subadrs[subadr].rxlistid = list->listid;
+ priv->sas_cpu[subadr].rxptr = (unsigned int)bd;
+ }
+}
+
+void gr1553rt_sa_setopts(
+ void *rt,
+ int subadr,
+ unsigned int mask,
+ unsigned int options
+ )
+{
+ struct gr1553rt_priv *priv = rt;
+ unsigned int ctrl;
+
+ if ( (subadr > 31) || (priv->sas_cpu == NULL) )
+ return;
+
+ ctrl = priv->sas_cpu[subadr].ctrl;
+ priv->sas_cpu[subadr].ctrl = (ctrl & ~mask) | options;
+}
+
+void gr1553rt_set_vecword(void *rt, unsigned int mask, unsigned int words)
+{
+ struct gr1553rt_priv *priv = rt;
+ unsigned int vword;
+
+ if ( mask == 0 )
+ return;
+
+ vword = priv->regs->rt_statw;
+
+ priv->regs->rt_statw = (vword & ~mask) | (words & mask);
+}
+
+void gr1553rt_set_bussts(void *rt, unsigned int mask, unsigned int sts)
+{
+ struct gr1553rt_priv *priv = rt;
+ unsigned int stat;
+
+ stat = priv->regs->rt_stat2;
+ priv->regs->rt_stat2 = (stat & ~mask) | (mask & sts);
+}
+
+void gr1553rt_status(void *rt, struct gr1553rt_status *status)
+{
+ struct gr1553rt_priv *priv = rt;
+ struct gr1553b_regs *regs = priv->regs;
+ unsigned int tmp;
+ IRQ_GLOBAL_PREPARE(oldLevel);
+
+ IRQ_GLOBAL_DISABLE(oldLevel);
+ status->status = regs->rt_stat;
+ status->bus_status = regs->rt_stat2;
+
+ tmp = regs->rt_sync;
+ status->synctime = tmp >> 16;
+ status->syncword = tmp & 0xffff;
+
+ tmp = regs->rt_ttag;
+ status->time_res = tmp >> 16;
+ status->time = tmp & 0xffff;
+
+ IRQ_GLOBAL_ENABLE(oldLevel);
+}
+
+void gr1553rt_list_sa(struct gr1553rt_list *list, int *subadr, int *tx)
+{
+ int sa, trt;
+
+ if ( list->subadr == -1 ) {
+ sa = -1;
+ trt = -1;
+ } else {
+ sa = list->subadr & 0xff;
+ trt = (list->subadr & 0x100) >> 8;
+ }
+
+ if ( subadr )
+ *subadr = sa;
+ if ( tx )
+ *tx = trt;
+}
+
+int gr1553rt_evlog_read(void *rt, unsigned int *dst, int max)
+{
+ struct gr1553rt_priv *priv = rt;
+ int cnt, top, bot, left;
+ unsigned int *hwpos;
+
+ /* Get address of hardware's current working entry */
+ hwpos = (unsigned int *)priv->regs->rt_evlog;
+
+ /* Convert into CPU address */
+ hwpos = (unsigned int *)
+ ((unsigned int)hwpos - (unsigned int)priv->evlog_hw_base +
+ (unsigned int)priv->evlog_cpu_base);
+
+ if ( priv->evlog_cpu_next == hwpos )
+ return 0;
+
+ if ( priv->evlog_cpu_next > hwpos ) {
+ top = (unsigned int)priv->evlog_cpu_end -
+ (unsigned int)priv->evlog_cpu_next;
+ bot = (unsigned int)hwpos - (unsigned int)priv->evlog_cpu_base;
+ } else {
+ top = (unsigned int)hwpos - (unsigned int)priv->evlog_cpu_next;
+ bot = 0;
+ }
+ top = top / 4;
+ bot = bot / 4;
+
+ left = max;
+ if ( top > 0 ) {
+ if ( top > left ) {
+ cnt = left;
+ } else {
+ cnt = top;
+ }
+ memcpy(dst, priv->evlog_cpu_next, cnt*4);
+ dst += cnt;
+ left -= cnt;
+ }
+
+ if ( (bot > 0) && (left > 0) ) {
+ if ( bot > left ) {
+ cnt = left;
+ } else {
+ cnt = bot;
+ }
+ memcpy(dst, priv->evlog_cpu_base, cnt*4);
+ left -= cnt;
+ }
+
+ cnt = max - left;
+ priv->evlog_cpu_next += cnt;
+ if ( priv->evlog_cpu_next >= priv->evlog_cpu_end ) {
+ priv->evlog_cpu_next = (unsigned int *)
+ ((unsigned int)priv->evlog_cpu_base +
+ ((unsigned int)priv->evlog_cpu_next -
+ (unsigned int)priv->evlog_cpu_end ));
+ }
+
+ return max - left;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/amba/ahbstat.c b/c/src/lib/libbsp/sparc/shared/amba/ahbstat.c
new file mode 100644
index 0000000000..6f659fa71e
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/amba/ahbstat.c
@@ -0,0 +1,196 @@
+#include <stdint.h>
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+
+#include <ahbstat.h>
+
+void ahbstat_isr(void *arg);
+
+/* AHB fail interrupt callback to user. This function is declared weak so that
+ * the user can define a function pointer variable containing the address
+ * responsible for handling errors
+ *
+ * minor Index of AHBSTAT hardware
+ * regs Register address of AHBSTAT
+ * status AHBSTAT status register at IRQ
+ * failing_address AHBSTAT Failing address register at IRQ
+ *
+ * * User return
+ * 0: print error onto terminal with printk and reenable AHBSTAT
+ * 1: just re-enable AHBSTAT
+ * 2: just print error
+ * 3: do nothing, let user do custom handling
+ */
+int (*ahbstat_error)(
+ int minor,
+ struct ahbstat_regs *regs,
+ uint32_t status,
+ uint32_t failing_address
+ ) __attribute__((weak)) = NULL;
+
+#define AHBSTAT_STS_CE_BIT 9
+#define AHBSTAT_STS_NE_BIT 8
+#define AHBSTAT_STS_HW_BIT 7
+#define AHBSTAT_STS_HM_BIT 3
+#define AHBSTAT_STS_HS_BIT 0
+
+#define AHBSTAT_STS_CE (1 << AHBSTAT_STS_CE_BIT)
+#define AHBSTAT_STS_NE (1 << AHBSTAT_STS_NE_BIT)
+#define AHBSTAT_STS_HW (1 << AHBSTAT_STS_HW_BIT)
+#define AHBSTAT_STS_HM (0xf << AHBSTAT_STS_HM_BIT)
+#define AHBSTAT_STS_HS (0x7 << AHBSTAT_STS_HS_BIT)
+
+struct ahbstat_priv {
+ struct drvmgr_dev *dev;
+ struct ahbstat_regs *regs;
+ int minor;
+ uint32_t last_status;
+ uint32_t last_address;
+};
+
+int ahbstat_init2(struct drvmgr_dev *dev);
+
+struct drvmgr_drv_ops ahbstat_ops =
+{
+ .init = {NULL, ahbstat_init2, NULL, NULL},
+ .remove = NULL,
+ .info = NULL
+};
+
+struct amba_dev_id ahbstat_ids[] =
+{
+ {VENDOR_GAISLER, GAISLER_AHBSTAT},
+ {0, 0} /* Mark end of table */
+};
+
+struct amba_drv_info ahbstat_drv_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_AMBAPP_GAISLER_AHBSTAT_ID,/* Driver ID */
+ "AHBSTAT_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */
+ &ahbstat_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ sizeof(struct ahbstat_priv),
+ },
+ &ahbstat_ids[0]
+};
+
+void ahbstat_register_drv (void)
+{
+ drvmgr_drv_register(&ahbstat_drv_info.general);
+}
+
+int ahbstat_init2(struct drvmgr_dev *dev)
+{
+ struct ahbstat_priv *priv;
+ struct amba_dev_info *ambadev;
+
+ priv = dev->priv;
+ if (!priv)
+ return DRVMGR_NOMEM;
+ priv->dev = dev;
+
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)dev->businfo;
+ if (ambadev == NULL)
+ return DRVMGR_FAIL;
+ priv->regs = (struct ahbstat_regs *)ambadev->info.apb_slv->start;
+ priv->minor = dev->minor_drv;
+
+ /* Initialize hardware */
+ priv->regs->status = 0;
+
+ /* Install IRQ handler */
+ drvmgr_interrupt_register(dev, 0, "ahbstat", ahbstat_isr, priv);
+
+ return DRVMGR_OK;
+}
+
+void ahbstat_isr(void *arg)
+{
+ struct ahbstat_priv *priv = arg;
+ uint32_t fadr, status;
+ int rc;
+
+ /* Get hardware status */
+ status = priv->regs->status;
+ if ((status & AHBSTAT_STS_NE) == 0)
+ return;
+
+ /* IRQ generated by AHBSTAT core... handle it here */
+
+ /* Get Failing address */
+ fadr = priv->regs->failing;
+
+ priv->last_status = status;
+ priv->last_address = fadr;
+
+ /* Let user handle error, default to print the error and reenable HW
+ *
+ * User return
+ * 0: print error and reenable AHBSTAT
+ * 1: just reenable AHBSTAT
+ * 2: just print error reenable
+ * 3: do nothing
+ */
+ rc = 0;
+ if (ahbstat_error != NULL)
+ rc = ahbstat_error(priv->minor, priv->regs, status, fadr);
+
+ if ((rc & 0x1) == 0) {
+ printk("\n### AHBSTAT: %s %s error of size %lu by master %d"
+ " at 0x%08lx\n",
+ status & AHBSTAT_STS_CE ? "single" : "non-correctable",
+ status & AHBSTAT_STS_HW ? "write" : "read",
+ (status & AHBSTAT_STS_HS) >> AHBSTAT_STS_HS_BIT,
+ (status & AHBSTAT_STS_HM) >> AHBSTAT_STS_HM_BIT,
+ fadr);
+ }
+
+ if ((rc & 0x2) == 0) {
+ /* Trigger new interrupts */
+ priv->regs->status = 0;
+ }
+}
+
+/* Get Last received AHB Error
+ *
+ * Return
+ * 0: No error received
+ * 1: Error Received, last status and address stored into argument pointers
+ * -1: No such AHBSTAT device
+ */
+int ahbstat_last_error(int minor, uint32_t *status, uint32_t *address)
+{
+ struct drvmgr_dev *dev;
+ struct ahbstat_priv *priv;
+
+ if (drvmgr_get_dev(&ahbstat_drv_info.general, minor, &dev)) {
+ return -1;
+ }
+ priv = (struct ahbstat_priv *)dev->priv;
+
+ *status = priv->last_status;
+ *address = priv->last_address;
+
+ return (priv->last_status & AHBSTAT_STS_NE) >> AHBSTAT_STS_NE_BIT;
+}
+
+/* Get AHBSTAT registers address from minor. NULL returned if no such device */
+struct ahbstat_regs *ahbstat_get_regs(int minor)
+{
+ struct drvmgr_dev *dev;
+ struct ahbstat_priv *priv;
+
+ if (drvmgr_get_dev(&ahbstat_drv_info.general, minor, &dev)) {
+ return NULL;
+ }
+ priv = (struct ahbstat_priv *)dev->priv;
+
+ return priv->regs;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/amba/ambapp.c b/c/src/lib/libbsp/sparc/shared/amba/ambapp.c
index 814ee8c28e..62c96a0f7f 100644
--- a/c/src/lib/libbsp/sparc/shared/amba/ambapp.c
+++ b/c/src/lib/libbsp/sparc/shared/amba/ambapp.c
@@ -1,499 +1,475 @@
/*
- * AMBA Plag & Play Bus Driver
+ * AMBA Plug & Play routines
*
- * This driver hook performs bus scanning.
- *
- * COPYRIGHT (c) 2004.
- * Gaisler Research
+ * COPYRIGHT (c) 2011.
+ * Aeroflex Gaisler.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
*
- * $Id$
+ * $Id: ambapp.c,v 1.2 2009/11/29 15:33:27 ralf Exp $
+ *
+ *
+ * 2008-12-01, Daniel Hellstrom <daniel@gaisler.com>
+ * Created
*/
-#include <bsp.h>
-#include <rtems/bspIo.h>
+#include <string.h>
+#include <stdlib.h>
+#include <string.h>
+
#include <ambapp.h>
+#include <bsp.h>
+
+#define AMBA_CONF_AREA 0xff000
+#define AMBA_AHB_SLAVE_CONF_AREA (1 << 11)
+#define AMBA_APB_SLAVES 16
-#define amba_insert_device(tab, address) \
-{ \
- if (*(address)) \
- { \
- (tab)->addr[(tab)->devnr] = (address); \
- (tab)->devnr ++; \
- } \
-} while(0)
-
-#define amba_insert_apb_device(tab, address, apbmst) \
-{ \
- if (*(address)) \
- { \
- (tab)->addr[(tab)->devnr] = (address); \
- (tab)->apbmst[(tab)->devnr] = (apbmst); \
- (tab)->devnr ++; \
- } \
-} while(0)
-
-static unsigned int
-addr_from (struct amba_mmap *mmaps, unsigned int address)
+/* Allocate one AMBA device */
+struct ambapp_dev *ambapp_alloc_dev_struct(int dev_type)
{
- /* no translation? */
- if (!mmaps)
- return address;
-
- while (mmaps->size) {
- if ((address >= mmaps->remote_amba_adr)
- && (address <= (mmaps->remote_amba_adr + (mmaps->size - 1)))) {
- return (address - mmaps->remote_amba_adr) + mmaps->cpu_adr;
- }
- mmaps++;
- }
- return 1;
+ int size = sizeof(struct ambapp_dev);
+ struct ambapp_dev *dev;
+
+ if (dev_type == DEV_APB_SLV)
+ size += sizeof(struct ambapp_apb_info);
+ else
+ size += sizeof(struct ambapp_ahb_info); /* AHB */
+ dev = (struct ambapp_dev *)bsp_early_malloc(size);
+ if (dev == NULL)
+ return NULL;
+ memset(dev, 0 , size);
+ dev->dev_type = dev_type;
+ return dev;
}
-
-void
-amba_scan (amba_confarea_type * amba_conf, unsigned int ioarea,
- struct amba_mmap *mmaps)
+unsigned int
+ambapp_addr_from (struct ambapp_mmap *mmaps, unsigned int address)
{
- unsigned int *cfg_area; /* address to configuration area */
- unsigned int mbar, conf, custom;
- int i, j;
- unsigned int apbmst;
- int maxloops = amba_conf->notroot ? 16 : 64; /* scan first bus for 64 devices, rest for 16 devices */
-
- amba_conf->ahbmst.devnr = 0;
- amba_conf->ahbslv.devnr = 0;
- amba_conf->apbslv.devnr = 0;
- cfg_area = (unsigned int *) (ioarea | AMBA_CONF_AREA);
- amba_conf->ioarea = ioarea;
- amba_conf->mmaps = mmaps;
-
- for (i = 0; i < maxloops; i++) {
- amba_insert_device (&amba_conf->ahbmst, cfg_area);
- cfg_area += AMBA_AHB_CONF_WORDS;
- }
-
- cfg_area =
- (unsigned int *) (ioarea | AMBA_CONF_AREA | AMBA_AHB_SLAVE_CONF_AREA);
- for (i = 0; i < maxloops; i++) {
- amba_insert_device (&amba_conf->ahbslv, cfg_area);
- cfg_area += AMBA_AHB_CONF_WORDS;
- }
-
- for (i = 0; i < amba_conf->ahbslv.devnr; i++){
- conf = amba_get_confword(amba_conf->ahbslv, i, 0);
- mbar = amba_ahb_get_membar(amba_conf->ahbslv, i, 0);
- if ( (amba_vendor(conf) == VENDOR_GAISLER) && (amba_device(conf) == GAISLER_AHB2AHB) ){
- /* Found AHB->AHB bus bridge, scan it if more free amba_confarea_type:s available
- * Custom config 1 contain ioarea.
- */
- custom = amba_ahb_get_custom(amba_conf->ahbslv,i,1);
-
- if ( amba_ver(conf) && amba_conf->next ){
- amba_conf->next->notroot = 1;
- amba_scan(amba_conf->next,custom,mmaps);
- }
- }else if ((amba_vendor(conf) == VENDOR_GAISLER) && (amba_device(conf) == GAISLER_APBMST))
- {
- apbmst = amba_membar_start(mbar);
- if ( (apbmst=addr_from(mmaps,apbmst)) == 1 )
- continue; /* no available memory translation available, will not be able to access
- * Plug&Play information for this AHB/APB bridge. Skip it.
- */
- cfg_area = (unsigned int *)( apbmst | AMBA_CONF_AREA);
- for (j=0; (amba_conf->apbslv.devnr<AMBA_APB_SLAVES) && (j<AMBA_APB_SLAVES); j++){
- amba_insert_apb_device(&amba_conf->apbslv, cfg_area, apbmst);
- cfg_area += AMBA_APB_CONF_WORDS;
- }
- }
- }
+ /* no translation? */
+ if (!mmaps)
+ return address;
+
+ while (mmaps->size) {
+ if ((address >= mmaps->remote_adr) &&
+ (address <= (mmaps->remote_adr + (mmaps->size - 1)))) {
+ return (address - mmaps->remote_adr) + mmaps->local_adr;
+ }
+ mmaps++;
+ }
+ return 1;
}
-void
-amba_print_dev(int devno, unsigned int conf){
- int irq = amba_irq(conf);
- if ( irq > 0 ){
- printk("%x.%x.%x: irq %d\n",devno,amba_vendor(conf),amba_device(conf),irq);
- }else{
- printk("%x.%x.%x: no irq\n",devno,amba_vendor(conf),amba_device(conf));
+void ambapp_ahb_dev_init(
+ unsigned int ioarea,
+ struct ambapp_mmap *mmaps,
+ struct ambapp_pnp_ahb *ahb,
+ struct ambapp_dev *dev,
+ int ahbidx
+ )
+{
+ int bar;
+ struct ambapp_ahb_info *ahb_info;
+ unsigned int addr, mask, mbar;
+
+ /* Setup device struct */
+ dev->vendor = ambapp_pnp_vendor(ahb->id);
+ dev->device = ambapp_pnp_device(ahb->id);
+ ahb_info = DEV_TO_AHB(dev);
+ ahb_info->ver = ambapp_pnp_ver(ahb->id);
+ ahb_info->irq = ambapp_pnp_irq(ahb->id);
+ ahb_info->ahbidx = ahbidx;
+ ahb_info->custom[0] = (unsigned int)ahb->custom[0];
+ ahb_info->custom[1] = (unsigned int)ahb->custom[1];
+ ahb_info->custom[2] = (unsigned int)ahb->custom[2];
+
+ /* Memory BARs */
+ for (bar=0; bar<4; bar++) {
+ mbar = ahb->mbar[bar];
+ if (mbar == 0) {
+ addr = 0;
+ mask = 0;
+ } else {
+ addr = ambapp_pnp_start(mbar);
+ if (ambapp_pnp_mbar_type(mbar) == AMBA_TYPE_AHBIO) {
+ /* AHB I/O area is releative IO_AREA */
+ addr = AMBA_TYPE_AHBIO_ADDR(addr, ioarea);
+ mask = (((unsigned int)
+ (ambapp_pnp_mbar_mask((~mbar))<<8) |
+ 0xff)) + 1;
+ } else {
+ /* AHB memory area, absolute address */
+ addr = ambapp_addr_from(mmaps, addr);
+ mask = (~((unsigned int)
+ (ambapp_pnp_mbar_mask(mbar)<<20))) + 1;
+ }
+ }
+ ahb_info->start[bar] = addr;
+ ahb_info->mask[bar] = mask;
+ ahb_info->type[bar] = ambapp_pnp_mbar_type(mbar);
}
}
-void
-amba_apb_print_dev(int devno, unsigned int conf, unsigned int address){
- int irq = amba_irq(conf);
- if ( irq > 0 ){
- printk("%x.%x.%x: irq %d, apb: 0x%lx\n",devno,amba_vendor(conf),amba_device(conf),irq,address);
- }else{
- printk("%x.%x.%x: no irq, apb: 0x%lx\n",devno,amba_vendor(conf),amba_device(conf),address);
- }
+void ambapp_apb_dev_init(
+ unsigned int base,
+ struct ambapp_mmap *mmaps,
+ struct ambapp_pnp_apb *apb,
+ struct ambapp_dev *dev,
+ int ahbidx
+ )
+{
+ struct ambapp_apb_info *apb_info;
+
+ /* Setup device struct */
+ dev->vendor = ambapp_pnp_vendor(apb->id);
+ dev->device = ambapp_pnp_device(apb->id);
+ apb_info = DEV_TO_APB(dev);
+ apb_info->ver = ambapp_pnp_ver(apb->id);
+ apb_info->irq = ambapp_pnp_irq(apb->id);
+ apb_info->ahbidx = ahbidx;
+ apb_info->start = ambapp_pnp_apb_start(apb->iobar, base);
+ apb_info->mask = ambapp_pnp_apb_mask(apb->iobar);
}
-/* Print AMBA Plug&Play info on terminal */
-void
-amba_print_conf (amba_confarea_type * amba_conf)
+int ambapp_add_ahbbus(
+ struct ambapp_bus *abus,
+ unsigned int ioarea
+ )
{
- int i,base=0;
- unsigned int conf, iobar, address;
- unsigned int apbmst;
-
- /* print all ahb masters */
- printk("--- AMBA AHB Masters ---\n");
- for(i=0; i<amba_conf->ahbmst.devnr; i++){
- conf = amba_get_confword(amba_conf->ahbmst, i, 0);
- amba_print_dev(i,conf);
+ int i;
+ for (i=0; i<AHB_BUS_MAX; i++) {
+ if (abus->ahbs[i].ioarea == 0) {
+ abus->ahbs[i].ioarea = ioarea;
+ return i;
+ } else if (abus->ahbs[i].ioarea == ioarea) {
+ /* Bus already added */
+ return -1;
+ }
}
+ return -1;
+}
- /* print all ahb slaves */
- printk("--- AMBA AHB Slaves ---\n");
- for(i=0; i<amba_conf->ahbslv.devnr; i++){
- conf = amba_get_confword(amba_conf->ahbslv, i, 0);
- amba_print_dev(i,conf);
+/* Internal AMBA Scanning Function */
+static int ambapp_scan2(
+ struct ambapp_bus *abus,
+ unsigned int ioarea,
+ ambapp_memcpy_t memfunc,
+ struct ambapp_dev *parent,
+ struct ambapp_dev **root
+ )
+{
+ struct ambapp_pnp_ahb *ahb, ahb_buf;
+ struct ambapp_pnp_apb *apb, apb_buf;
+ struct ambapp_dev *dev, *prev, *prevapb, *apbdev;
+ struct ambapp_ahb_info *ahb_info;
+ int maxloops = 64;
+ unsigned int apbbase, bridge_adr;
+ int i, j, ahbidx;
+
+ *root = NULL;
+
+ if (parent) {
+ /* scan first bus for 64 devices, rest for 16 devices */
+ maxloops = 16;
}
- /* print all apb slaves */
- apbmst = 0;
- for(i=0; i<amba_conf->apbslv.devnr; i++){
- if ( apbmst != amba_conf->apbslv.apbmst[i] ){
- apbmst = amba_conf->apbslv.apbmst[i];
- printk("--- AMBA APB Slaves on 0x%x ---\n",apbmst);
- base=i;
- }
- conf = amba_get_confword(amba_conf->apbslv, i, 0);
- iobar = amba_apb_get_membar(amba_conf->apbslv, i);
- address = amba_iobar_start(amba_conf->apbslv.apbmst[i], iobar);
- amba_apb_print_dev(i-base,conf,address);
+ ahbidx = ambapp_add_ahbbus(abus, ioarea);
+ if (ahbidx < 0) {
+ /* Bus already scanned, stop */
+ return 0;
}
-}
-/**** APB Slaves ****/
+ prev = parent;
-/* Return number of APB Slave devices which has given vendor and device */
-int
-amba_get_number_apbslv_devices (amba_confarea_type * amba_conf, int vendor,
- int device)
-{
- unsigned int conf;
- int cnt, i;
-
- for (cnt = i = 0; i < amba_conf->apbslv.devnr; i++) {
- conf = amba_get_confword (amba_conf->apbslv, i, 0);
- if ((amba_vendor (conf) == vendor) && (amba_device (conf) == device))
- cnt++;
- }
- return cnt;
-}
+ /* AHB MASTERS */
+ ahb = (struct ambapp_pnp_ahb *) (ioarea | AMBA_CONF_AREA);
+ for (i = 0; i < maxloops; i++, ahb++) {
+ memfunc(&ahb_buf, ahb, sizeof(struct ambapp_pnp_ahb), abus);
+ if (ahb_buf.id == 0)
+ continue;
-/* Get First APB Slave device of this vendor&device id */
-int
-amba_find_apbslv (amba_confarea_type * amba_conf, int vendor, int device,
- amba_apb_device * dev)
-{
- unsigned int conf, iobar;
- int i;
-
- for (i = 0; i < amba_conf->apbslv.devnr; i++) {
- conf = amba_get_confword (amba_conf->apbslv, i, 0);
- if ((amba_vendor (conf) == vendor) && (amba_device (conf) == device)) {
- iobar = amba_apb_get_membar (amba_conf->apbslv, i);
- dev->start = amba_iobar_start (amba_conf->apbslv.apbmst[i], iobar);
- dev->irq = amba_irq (conf);
- return 1;
- }
- }
- return 0;
-}
+ /* An AHB device present here */
+ dev = ambapp_alloc_dev_struct(DEV_AHB_MST);
+ if (!dev)
+ return -1;
-/* Get APB Slave device of this vendor&device id. (setting nr to 0 is eqivalent to calling amba_find_apbslv() ) */
-int
-amba_find_next_apbslv (amba_confarea_type * amba_conf, int vendor, int device,
- amba_apb_device * dev, int index)
-{
- unsigned int conf, iobar;
- int cnt, i;
-
- for (cnt = i = 0; i < amba_conf->apbslv.devnr; i++) {
- conf = amba_get_confword (amba_conf->apbslv, i, 0);
- if ((amba_vendor (conf) == vendor) && (amba_device (conf) == device)) {
- if (cnt == index) {
- /* found device */
- iobar = amba_apb_get_membar (amba_conf->apbslv, i);
- dev->start = amba_iobar_start (amba_conf->apbslv.apbmst[i], iobar);
- dev->irq = amba_irq (conf);
- return 1;
- }
- cnt++;
- }
- }
- return 0;
-}
+ ambapp_ahb_dev_init(ioarea, abus->mmaps, &ahb_buf, dev, ahbidx);
-/* Get first nr APB Slave devices, put them into dev (which is an array of nr length) */
-int
-amba_find_apbslvs (amba_confarea_type * amba_conf, int vendor, int device,
- amba_apb_device * devs, int maxno)
-{
- unsigned int conf, iobar;
- int cnt, i;
-
- for (cnt = i = 0; (i < amba_conf->apbslv.devnr) && (cnt < maxno); i++) {
- conf = amba_get_confword (amba_conf->apbslv, i, 0);
- if ((amba_vendor (conf) == vendor) && (amba_device (conf) == device)) {
- /* found device */
- iobar = amba_apb_get_membar (amba_conf->apbslv, i);
- devs[cnt].start = amba_iobar_start (amba_conf->apbslv.apbmst[i], iobar);
- devs[cnt].irq = amba_irq (conf);
- cnt++;
- }
- }
- return cnt;
-}
+ if (*root == NULL)
+ *root = dev;
-/***** AHB SLAVES *****/
+ if (prev != parent)
+ prev->next = dev;
+ dev->prev = prev;
+ prev = dev;
+ }
-/* Return number of AHB Slave devices which has given vendor and device */
-int
-amba_get_number_ahbslv_devices (amba_confarea_type * amba_conf, int vendor,
- int device)
-{
- unsigned int conf;
- int cnt, i;
-
- for (cnt = i = 0; i < amba_conf->ahbslv.devnr; i++) {
- conf = amba_get_confword (amba_conf->ahbslv, i, 0);
- if ((amba_vendor (conf) == vendor) && (amba_device (conf) == device))
- cnt++;
- }
- return cnt;
-}
+ /* AHB SLAVES */
+ ahb = (struct ambapp_pnp_ahb *)
+ (ioarea | AMBA_CONF_AREA | AMBA_AHB_SLAVE_CONF_AREA);
+ for (i = 0; i < maxloops; i++, ahb++) {
+ memfunc(&ahb_buf, ahb, sizeof(struct ambapp_pnp_ahb), abus);
+ if (ahb_buf.id == 0)
+ continue;
+
+ /* An AHB device present here */
+ dev = ambapp_alloc_dev_struct(DEV_AHB_SLV);
+ if (!dev)
+ return -1;
+
+ ambapp_ahb_dev_init(ioarea, abus->mmaps, &ahb_buf, dev, ahbidx);
+
+ if (*root == NULL)
+ *root = dev;
+
+ if (prev != parent)
+ prev->next = dev;
+ dev->prev = prev;
+ prev = dev;
+
+ ahb_info = DEV_TO_AHB(dev);
+
+ /* Is it a AHB/AHB Bridge ? */
+ if (((dev->device == GAISLER_AHB2AHB) &&
+ (dev->vendor == VENDOR_GAISLER) && (ahb_info->ver>0)) ||
+ ((dev->device == GAISLER_L2CACHE) &&
+ (dev->vendor == VENDOR_GAISLER)) ||
+ ((dev->device == GAISLER_GRIOMMU) &&
+ (dev->vendor == VENDOR_GAISLER))) {
+ /* AHB/AHB Bridge Found, recurse down the
+ * Bridge
+ */
+ if (ahb_info->custom[1] != 0) {
+ bridge_adr = ambapp_addr_from(abus->mmaps,
+ ahb_info->custom[1]);
+ /* Scan next bus if not already scanned */
+ if (ambapp_scan2(abus, bridge_adr, memfunc, dev,
+ &dev->children))
+ return -1;
+ }
+ } else if ((dev->device == GAISLER_APBMST) &&
+ (dev->vendor == VENDOR_GAISLER)) {
+ /* AHB/APB Bridge Found, add the APB devices to this
+ * AHB Slave's children
+ */
+ prevapb = dev;
+ apbbase = ahb_info->start[0];
+
+ /* APB SLAVES */
+ apb = (struct ambapp_pnp_apb *)
+ (apbbase | AMBA_CONF_AREA);
+ for (j=0; j<AMBA_APB_SLAVES; j++, apb++) {
+ memfunc(&apb_buf, apb, sizeof(*apb), abus);
+ if (apb_buf.id == 0)
+ continue;
+
+ apbdev = ambapp_alloc_dev_struct(DEV_APB_SLV);
+ if (!dev)
+ return -1;
+
+ ambapp_apb_dev_init(apbbase, abus->mmaps,
+ &apb_buf, apbdev, ahbidx);
+
+ if (prevapb != dev)
+ prevapb->next = apbdev;
+ else
+ dev->children = apbdev;
+ apbdev->prev = prevapb;
+ prevapb = apbdev;
+ }
+ }
+ }
-/* Get First AHB Slave device of this vendor&device id */
-int
-amba_find_ahbslv (amba_confarea_type * amba_conf, int vendor, int device,
- amba_ahb_device * dev)
-{
- unsigned int conf, mbar, addr;
- int j, i;
-
- for (i = 0; i < amba_conf->ahbslv.devnr; i++) {
- conf = amba_get_confword (amba_conf->ahbslv, i, 0);
- if ((amba_vendor (conf) == vendor) && (amba_device (conf) == device)) {
- for (j = 0; j < 4; j++) {
- mbar = amba_ahb_get_membar (amba_conf->ahbslv, i, j);
- addr = amba_membar_start (mbar);
- if (amba_membar_type (mbar) == AMBA_TYPE_AHBIO) {
- addr = AMBA_TYPE_AHBIO_ADDR (addr, amba_conf->ioarea);
- } else { /* convert address if needed */
- if ((addr = addr_from (amba_conf->mmaps, addr)) == 1) {
- addr = 0; /* no available memory translation available, will not be able to access
- * Plug&Play information for this AHB address. Skip it.
- */
- }
- }
- dev->start[j] = addr;
- }
- dev->irq = amba_irq (conf);
- dev->ver = amba_ver (conf);
- return 1;
- }
- }
- return 0;
-}
+ /* Remember first AHB MST/SLV device on bus and Parent Bridge */
+ abus->ahbs[ahbidx].dev = *root;
+ abus->ahbs[ahbidx].bridge = parent;
-/* Get AHB Slave device of this vendor&device id. (setting nr to 0 is eqivalent to calling amba_find_ahbslv() ) */
-int
-amba_find_next_ahbslv (amba_confarea_type * amba_conf, int vendor, int device,
- amba_ahb_device * dev, int index)
-{
- unsigned int conf, mbar, addr;
- int i, j, cnt;
-
- for (cnt = i = 0; i < amba_conf->ahbslv.devnr; i++) {
- conf = amba_get_confword (amba_conf->ahbslv, i, 0);
- if ((amba_vendor (conf) == vendor) && (amba_device (conf) == device)) {
- if (cnt == index) {
- for (j = 0; j < 4; j++) {
- mbar = amba_ahb_get_membar (amba_conf->ahbslv, i, j);
- addr = amba_membar_start (mbar);
- if (amba_membar_type (mbar) == AMBA_TYPE_AHBIO) {
- addr = AMBA_TYPE_AHBIO_ADDR (addr, amba_conf->ioarea);
- } else {
- /* convert address if needed */
- if ((addr = addr_from (amba_conf->mmaps, addr)) == 1) {
- addr = 0; /* no available memory translation available, will not be able to access
- * Plug&Play information for this AHB address. Skip it.
- */
- }
- }
- dev->start[j] = addr;
- }
- dev->irq = amba_irq (conf);
- dev->ver = amba_ver (conf);
- return 1;
- }
- cnt++;
- }
- }
- return 0;
+ return 0;
}
-/* Get first nr AHB Slave devices, put them into dev (which is an array of nr length) */
-int
-amba_find_ahbslvs (amba_confarea_type * amba_conf, int vendor, int device,
- amba_ahb_device * devs, int maxno)
+/* Build AMBA Plug & Play device graph */
+int ambapp_scan(
+ struct ambapp_bus *abus,
+ unsigned int ioarea,
+ ambapp_memcpy_t memfunc,
+ struct ambapp_mmap *mmaps
+ )
{
- unsigned int conf, mbar, addr;
- int i, j, cnt;
-
- for (cnt = i = 0; (i < amba_conf->ahbslv.devnr) && (maxno < cnt); i++) {
- conf = amba_get_confword (amba_conf->ahbslv, i, 0);
- if ((amba_vendor (conf) == vendor) && (amba_device (conf) == device)) {
- for (j = 0; j < 4; j++) {
- mbar = amba_ahb_get_membar (amba_conf->ahbslv, i, j);
- addr = amba_membar_start (mbar);
- if (amba_membar_type (mbar) == AMBA_TYPE_AHBIO) {
- addr = AMBA_TYPE_AHBIO_ADDR (addr, amba_conf->ioarea);
- } else {
- /* convert address if needed */
- if ((addr = addr_from (amba_conf->mmaps, addr)) == 1) {
- addr = 0; /* no available memory translation available, will not be able to access
- * Plug&Play information for this AHB address. Skip it.
- */
- }
- }
- devs[cnt].start[j] = addr;
- }
- devs[cnt].irq = amba_irq (conf);
- devs[cnt].ver = amba_ver (conf);
- cnt++;
- }
- }
- return cnt;
-}
+ memset(abus, 0, sizeof(*abus));
+ abus->mmaps = mmaps;
+ /* Default to memcpy() */
+ if (!memfunc)
+ memfunc = (ambapp_memcpy_t)memcpy;
-/***** AHB Masters *****/
+ return ambapp_scan2(abus, ioarea, memfunc, NULL, &abus->root);
+}
-/* Return number of AHB Slave devices which has given vendor and device */
-int
-amba_get_number_ahbmst_devices (amba_confarea_type * amba_conf, int vendor,
- int device)
+/* Match search options againt device */
+int ambapp_dev_match_options(struct ambapp_dev *dev, unsigned int options, int vendor, int device)
{
- unsigned int conf;
- int cnt, i;
-
- for (cnt = i = 0; i < amba_conf->ahbmst.devnr; i++) {
- conf = amba_get_confword (amba_conf->ahbmst, i, 0);
- if ((amba_vendor (conf) == vendor) && (amba_device (conf) == device))
- cnt++;
- }
- return cnt;
+ if ((((options & (OPTIONS_ALL_DEVS)) == OPTIONS_ALL_DEVS) || /* TYPE */
+ ((options & OPTIONS_AHB_MSTS) && (dev->dev_type == DEV_AHB_MST)) ||
+ ((options & OPTIONS_AHB_SLVS) && (dev->dev_type == DEV_AHB_SLV)) ||
+ ((options & OPTIONS_APB_SLVS) && (dev->dev_type == DEV_APB_SLV))) &&
+ ((vendor == -1) || (vendor == dev->vendor)) && /* VENDOR/DEV ID */
+ ((device == -1) || (device == dev->device)) &&
+ (((options & OPTIONS_ALL) == OPTIONS_ALL) || /* Allocated State */
+ ((options & OPTIONS_FREE) && DEV_IS_FREE(dev)) ||
+ ((options & OPTIONS_ALLOCATED) && DEV_IS_ALLOCATED(dev)))) {
+ return 1;
+ }
+ return 0;
}
-/* Get First AHB Slave device of this vendor&device id */
-int
-amba_find_ahbmst (amba_confarea_type * amba_conf, int vendor, int device,
- amba_ahb_device * dev)
+/* If device is an APB bridge all devices on the APB bridge is processed */
+static int ambapp_for_each_apb(
+ struct ambapp_dev *dev,
+ unsigned int options,
+ int vendor,
+ int device,
+ ambapp_func_t func,
+ void *arg)
{
- unsigned int conf, mbar, addr;
- int j, i;
-
- for (i = 0; i < amba_conf->ahbmst.devnr; i++) {
- conf = amba_get_confword (amba_conf->ahbslv, i, 0);
- if ((amba_vendor (conf) == vendor) && (amba_device (conf) == device)) {
- for (j = 0; j < 4; j++) {
- mbar = amba_ahb_get_membar (amba_conf->ahbmst, i, j);
- addr = amba_membar_start (mbar);
- if (amba_membar_type (mbar) == AMBA_TYPE_AHBIO) {
- addr = AMBA_TYPE_AHBIO_ADDR (addr, amba_conf->ioarea);
- } else {
- /* convert address if needed */
- if ((addr = addr_from (amba_conf->mmaps, addr)) == 1) {
- addr = 0; /* no available memory translation available, will not be able to access
- * Plug&Play information for this AHB address. Skip it.
- */
- }
- }
- dev->start[j] = addr;
- }
- dev->irq = amba_irq (conf);
- dev->ver = amba_ver (conf);
- return 1;
- }
- }
- return 0;
+ int index, ret;
+ struct ambapp_dev *apbslv;
+
+ ret = 0;
+ if (dev->children && (dev->children->dev_type == DEV_APB_SLV)) {
+ /* Found a APB Bridge */
+ index = 0;
+ apbslv = dev->children;
+ while (apbslv) {
+ if (ambapp_dev_match_options(apbslv, options,
+ vendor, device) == 1) {
+ ret = func(apbslv, index, arg);
+ if (ret != 0)
+ break; /* Signalled stopped */
+ }
+ index++;
+ apbslv = apbslv->next;
+ }
+ }
+
+ return ret;
}
-/* Get AHB Slave device of this vendor&device id. (setting nr to 0 is eqivalent to calling amba_find_ahbslv() ) */
-int
-amba_find_next_ahbmst (amba_confarea_type * amba_conf, int vendor, int device,
- amba_ahb_device * dev, int index)
+/* Traverse the prescanned device information */
+static int ambapp_for_each_dev(
+ struct ambapp_dev *root,
+ unsigned int options,
+ int vendor,
+ int device,
+ ambapp_func_t func,
+ void *arg)
{
- unsigned int conf, mbar, addr;
- int i, j, cnt;
-
- for (cnt = i = 0; i < amba_conf->ahbmst.devnr; i++) {
- conf = amba_get_confword (amba_conf->ahbmst, i, 0);
- if ((amba_vendor (conf) == vendor) && (amba_device (conf) == device)) {
- if (cnt == index) {
- for (j = 0; j < 4; j++) {
- mbar = amba_ahb_get_membar (amba_conf->ahbmst, i, j);
- addr = amba_membar_start (mbar);
- if (amba_membar_type (mbar) == AMBA_TYPE_AHBIO) {
- addr = AMBA_TYPE_AHBIO_ADDR (addr, amba_conf->ioarea);
- } else {
- /* convert address if needed */
- if ((addr = addr_from (amba_conf->mmaps, addr)) == 1) {
- addr = 0; /* no available memory translation available, will not be able to access
- * Plug&Play information for this AHB address. Skip it.
- */
- }
- }
- dev->start[j] = addr;
- }
- dev->irq = amba_irq (conf);
- dev->ver = amba_ver (conf);
- return 1;
- }
- cnt++;
- }
- }
- return 0;
+ struct ambapp_dev *dev;
+ int ahb_slave = 0;
+ int index, ret;
+
+ /* Start at device 'root' and process downwards.
+ *
+ * Breadth first search, search order
+ * 1. AHB MSTS
+ * 2. AHB SLVS
+ * 3. APB SLVS on primary bus
+ * 4. AHB/AHB secondary... -> step to 1.
+ */
+
+ /* AHB MST / AHB SLV */
+ if (options & (OPTIONS_AHB_MSTS|OPTIONS_AHB_SLVS|OPTIONS_DEPTH_FIRST)) {
+ index = 0;
+ dev = root;
+ while (dev) {
+ if ((dev->dev_type == DEV_AHB_SLV) && !ahb_slave) {
+ /* First AHB Slave */
+ ahb_slave = 1;
+ index = 0;
+ }
+
+ /* Conditions must be fullfilled for function to be
+ * called
+ */
+ if (ambapp_dev_match_options(dev, options, vendor,
+ device) == 1) {
+ /* Correct device and vendor ID */
+ ret = func(dev, index, arg);
+ if (ret != 0)
+ return ret; /* Signalled stopped */
+ }
+
+ if ((options & OPTIONS_DEPTH_FIRST) &&
+ (options & OPTIONS_APB_SLVS)) {
+ /* Check is APB bridge, and process all APB
+ * Slaves in that case
+ */
+ ret = ambapp_for_each_apb(dev, options, vendor,
+ device, func, arg);
+ if (ret != 0)
+ return ret; /* Signalled stopped */
+ }
+
+ if (options & OPTIONS_DEPTH_FIRST) {
+ if (dev->children &&
+ (dev->children->dev_type != DEV_APB_SLV)) {
+ /* Found AHB Bridge, recurse */
+ ret = ambapp_for_each_dev(dev->children,
+ options, vendor,
+ device, func, arg);
+ if (ret != 0)
+ return ret;
+ }
+ }
+
+ index++;
+ dev = dev->next;
+ }
+ }
+
+ /* Find APB Bridges */
+ if ((options & OPTIONS_APB_SLVS) && !(options & OPTIONS_DEPTH_FIRST)) {
+ dev = root;
+ while (dev) {
+ /* Check is APB bridge, and process all APB Slaves in
+ * that case
+ */
+ ret = ambapp_for_each_apb(dev, options, vendor, device,
+ func, arg);
+ if (ret != 0)
+ return ret; /* Signalled stopped */
+ dev = dev->next;
+ }
+ }
+
+ /* Find AHB Bridges */
+ if (!(options & OPTIONS_DEPTH_FIRST)) {
+ dev = root;
+ while (dev) {
+ if (dev->children &&
+ (dev->children->dev_type != DEV_APB_SLV)) {
+ /* Found AHB Bridge, recurse */
+ ret = ambapp_for_each_dev(dev->children,
+ options, vendor,
+ device, func, arg);
+ if (ret != 0)
+ return ret;
+ }
+ dev = dev->next;
+ }
+ }
+
+ return 0;
}
-/* Get first nr AHB Slave devices, put them into dev (which is an array of nr length) */
-int
-amba_find_ahbmsts (amba_confarea_type * amba_conf, int vendor, int device,
- amba_ahb_device * devs, int maxno)
+int ambapp_for_each(
+ struct ambapp_bus *abus,
+ unsigned int options,
+ int vendor,
+ int device,
+ ambapp_func_t func,
+ void *arg)
{
- unsigned int conf, mbar, addr;
- int i, j, cnt;
-
- for (cnt = i = 0; (i < amba_conf->ahbmst.devnr) && (maxno < cnt); i++) {
- conf = amba_get_confword (amba_conf->ahbslv, i, 0);
- if ((amba_vendor (conf) == vendor) && (amba_device (conf) == device)) {
- for (j = 0; j < 4; j++) {
- mbar = amba_ahb_get_membar (amba_conf->ahbmst, i, j);
- addr = amba_membar_start (mbar);
- if (amba_membar_type (mbar) == AMBA_TYPE_AHBIO) {
- addr = AMBA_TYPE_AHBIO_ADDR (addr, amba_conf->ioarea);
- } else {
- /* convert address if needed */
- if ((addr = addr_from (amba_conf->mmaps, addr)) == 1) {
- addr = 0; /* no available memory translation available, will not be able to access
- * Plug&Play information for this AHB address. Skip it.
- */
- }
- }
- devs[cnt].start[j] = addr;
- }
- devs[cnt].irq = amba_irq (conf);
- devs[cnt].ver = amba_ver (conf);
- cnt++;
- }
- }
- return cnt;
+ return ambapp_for_each_dev(abus->root, options, vendor, device, func,
+ arg);
}
diff --git a/c/src/lib/libbsp/sparc/shared/amba/ambapp_alloc.c b/c/src/lib/libbsp/sparc/shared/amba/ambapp_alloc.c
new file mode 100644
index 0000000000..0188267fe9
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/amba/ambapp_alloc.c
@@ -0,0 +1,28 @@
+/*
+ * AMBA Plug & Play routines
+ *
+ * COPYRIGHT (c) 2011
+ * Aeroflex Gaisler
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id: ambapp_alloc.c,v
+ *
+ */
+
+#include <ambapp.h>
+
+int ambapp_alloc_dev(struct ambapp_dev *dev, void *owner)
+{
+ if (dev->owner)
+ return -1;
+ dev->owner = owner;
+ return 0;
+}
+
+void ambapp_free_dev(struct ambapp_dev *dev)
+{
+ dev->owner = 0;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/amba/ambapp_count.c b/c/src/lib/libbsp/sparc/shared/amba/ambapp_count.c
new file mode 100644
index 0000000000..5be46079ec
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/amba/ambapp_count.c
@@ -0,0 +1,27 @@
+/*
+ * AMBA Plug & Play routines
+ *
+ * COPYRIGHT (c) 2011
+ * Aeroflex Gaisler
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id: ambapp_count.c,v
+ *
+ */
+
+#include <ambapp.h>
+
+/* Get number of devices matching search options */
+int ambapp_dev_count(struct ambapp_bus *abus, unsigned int options,
+ int vendor, int device)
+{
+ int count = 10000;
+
+ ambapp_for_each(abus, options, vendor, device, ambapp_find_by_idx,
+ &count);
+
+ return 10000 - count;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/amba/ambapp_depth.c b/c/src/lib/libbsp/sparc/shared/amba/ambapp_depth.c
new file mode 100644
index 0000000000..cd1a7b48e6
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/amba/ambapp_depth.c
@@ -0,0 +1,27 @@
+/*
+ * AMBA Plug & Play routines
+ *
+ * COPYRIGHT (c) 2011
+ * Aeroflex Gaisler
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id: ambapp_depth.c,v
+ *
+ */
+
+#include <ambapp.h>
+
+int ambapp_depth(struct ambapp_dev *dev)
+{
+ int depth = 0;
+
+ do {
+ dev = ambapp_find_parent(dev);
+ depth++;
+ } while (dev);
+
+ return depth - 1;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/amba/ambapp_find_by_idx.c b/c/src/lib/libbsp/sparc/shared/amba/ambapp_find_by_idx.c
new file mode 100644
index 0000000000..9d078c0e11
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/amba/ambapp_find_by_idx.c
@@ -0,0 +1,42 @@
+/*
+ * AMBA Plug & Play routines
+ *
+ * COPYRIGHT (c) 2011
+ * Aeroflex Gaisler
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id: ambapp_find_by_idx.c,v
+ *
+ */
+
+#include <ambapp.h>
+
+/* AMBAPP helper routine to find a device by index. The function is given to
+ * ambapp_for_each, the argument may be NULL (find first device) or a pointer
+ * to a index which is downcounted until 0 is reached. If the int-pointer
+ * points to a value of:
+ * 0 - first device is returned
+ * 1 - second device is returned
+ * ...
+ *
+ * The matching device is returned, which will stop the ambapp_for_each search.
+ * If zero is returned from ambapp_for_each no device matching the index was
+ * found
+ */
+int ambapp_find_by_idx(struct ambapp_dev *dev, int index, void *pcount)
+{
+ int *pi = pcount;
+
+ if (pi) {
+ if (*pi-- == 0)
+ return (int)dev;
+ else
+ return 0;
+ } else {
+ /* Satisfied with first matching device, stop search */
+ return (int)dev;
+ }
+}
diff --git a/c/src/lib/libbsp/sparc/shared/amba/ambapp_freq.c b/c/src/lib/libbsp/sparc/shared/amba/ambapp_freq.c
new file mode 100644
index 0000000000..d3f0e7878d
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/amba/ambapp_freq.c
@@ -0,0 +1,114 @@
+/*
+ * AMBA Plug & Play routines
+ *
+ * COPYRIGHT (c) 2011
+ * Aeroflex Gaisler
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id: ambapp_freq.c,v
+ *
+ */
+
+#include <ambapp.h>
+
+/* Calculate AHB Bus frequency of
+ * - Bus[0] (inverse=1), relative to the frequency of Bus[ahbidx]
+ * NOTE: set freq_hz to frequency of Bus[ahbidx].
+ * or
+ * - Bus[ahbidx] (inverse=0), relative to the frequency of Bus[0]
+ * NOTE: set freq_hz to frequency of Bus[0].
+ *
+ * If a unsupported bridge is found the invalid frequncy of 0Hz is
+ * returned.
+ */
+unsigned int ambapp_freq_calc(
+ struct ambapp_bus *abus,
+ int ahbidx,
+ unsigned int freq_hz,
+ int inverse)
+{
+ struct ambapp_ahb_info *ahb;
+ struct ambapp_dev *bridge;
+ unsigned char ffact;
+ int dir;
+
+ /* Found Bus0? */
+ bridge = abus->ahbs[ahbidx].bridge;
+ if (!bridge)
+ return freq_hz;
+
+ /* Find this bus frequency relative to freq_hz */
+ if ((bridge->vendor == VENDOR_GAISLER) &&
+ ((bridge->device == GAISLER_AHB2AHB) ||
+ (bridge->device == GAISLER_L2CACHE))) {
+ ahb = DEV_TO_AHB(bridge);
+ ffact = (ahb->custom[0] & AMBAPP_FLAG_FFACT) >> 4;
+ if (ffact != 0) {
+ dir = ahb->custom[0] & AMBAPP_FLAG_FFACT_DIR;
+
+ /* Calculate frequency by dividing or
+ * multiplying system frequency
+ */
+ if ((dir && !inverse) || (!dir && inverse))
+ freq_hz = freq_hz * ffact;
+ else
+ freq_hz = freq_hz / ffact;
+ }
+ return ambapp_freq_calc(abus, ahb->ahbidx, freq_hz, inverse);
+ } else {
+ /* Unknown bridge, impossible to calc frequency */
+ return 0;
+ }
+}
+
+/* Find the frequency of all AHB Buses from knowing the frequency of one
+ * particular APB/AHB Device.
+ */
+void ambapp_freq_init(
+ struct ambapp_bus *abus,
+ struct ambapp_dev *dev,
+ unsigned int freq_hz)
+{
+ struct ambapp_common_info *info;
+ int i;
+
+ for (i=0; i<AHB_BUS_MAX; i++)
+ abus->ahbs[i].freq_hz = 0;
+
+ /* Register Frequency at the AHB bus that the device the user gave us
+ * is located at.
+ */
+ if (dev) {
+ info = DEV_TO_COMMON(dev);
+ abus->ahbs[info->ahbidx].freq_hz = freq_hz;
+
+ /* Find Frequency of Bus 0 */
+ abus->ahbs[0].freq_hz =
+ ambapp_freq_calc(abus, info->ahbidx, freq_hz, 1);
+ } else {
+ abus->ahbs[0].freq_hz = freq_hz;
+ }
+
+ /* Find Frequency of all except for Bus0 and the bus which frequency
+ * was reported at
+ */
+ for (i=1; i<AHB_BUS_MAX; i++) {
+ if (abus->ahbs[i].ioarea == 0)
+ break;
+ if (abus->ahbs[i].freq_hz != 0)
+ continue;
+ abus->ahbs[i].freq_hz =
+ ambapp_freq_calc(abus, i, abus->ahbs[0].freq_hz, 0);
+ }
+}
+
+/* Assign a AMBA Bus a frequency but reporting the frequency of a
+ * particular AHB/APB device */
+unsigned int ambapp_freq_get(struct ambapp_bus *abus, struct ambapp_dev *dev)
+{
+ struct ambapp_common_info *info = DEV_TO_COMMON(dev);
+ return abus->ahbs[info->ahbidx].freq_hz;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/amba/ambapp_names.c b/c/src/lib/libbsp/sparc/shared/amba/ambapp_names.c
new file mode 100644
index 0000000000..1fe65537aa
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/amba/ambapp_names.c
@@ -0,0 +1,395 @@
+/*
+ * AMBA Plug & Play Device and Vendor name database
+ *
+ * COPYRIGHT (c) 2009.
+ * Aeroflex Gaisler.
+ *
+ * The device and vendor definitions are extracted with a script from
+ * GRLIB.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2009-01-27, Daniel Hellstrom <daniel@gaisler.com>
+ * Created from GRLIB 3386.
+ */
+
+#include <ambapp_ids.h>
+#include <string.h>
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+typedef struct {
+ int device_id;
+ char *name;
+} ambapp_device_name;
+
+typedef struct {
+ unsigned int vendor_id;
+ char *name;
+ ambapp_device_name *devices;
+} ambapp_vendor_devnames;
+
+/**************** AUTO GENERATED FROM devices.vhd ****************/
+static ambapp_device_name GAISLER_devices[] =
+{
+ {GAISLER_LEON2DSU, "LEON2DSU"},
+ {GAISLER_LEON3, "LEON3"},
+ {GAISLER_LEON3DSU, "LEON3DSU"},
+ {GAISLER_ETHAHB, "ETHAHB"},
+ {GAISLER_APBMST, "APBMST"},
+ {GAISLER_AHBUART, "AHBUART"},
+ {GAISLER_SRCTRL, "SRCTRL"},
+ {GAISLER_SDCTRL, "SDCTRL"},
+ {GAISLER_SSRCTRL, "SSRCTRL"},
+ {GAISLER_APBUART, "APBUART"},
+ {GAISLER_IRQMP, "IRQMP"},
+ {GAISLER_AHBRAM, "AHBRAM"},
+ {GAISLER_AHBDPRAM, "AHBDPRAM"},
+ {GAISLER_GPTIMER, "GPTIMER"},
+ {GAISLER_PCITRG, "PCITRG"},
+ {GAISLER_PCISBRG, "PCISBRG"},
+ {GAISLER_PCIFBRG, "PCIFBRG"},
+ {GAISLER_PCITRACE, "PCITRACE"},
+ {GAISLER_DMACTRL, "DMACTRL"},
+ {GAISLER_AHBTRACE, "AHBTRACE"},
+ {GAISLER_DSUCTRL, "DSUCTRL"},
+ {GAISLER_CANAHB, "CANAHB"},
+ {GAISLER_GPIO, "GPIO"},
+ {GAISLER_AHBROM, "AHBROM"},
+ {GAISLER_AHBJTAG, "AHBJTAG"},
+ {GAISLER_ETHMAC, "ETHMAC"},
+ {GAISLER_SWNODE, "SWNODE"},
+ {GAISLER_SPW, "SPW"},
+ {GAISLER_AHB2AHB, "AHB2AHB"},
+ {GAISLER_USBDC, "USBDC"},
+ {GAISLER_USB_DCL, "USB_DCL"},
+ {GAISLER_DDRMP, "DDRMP"},
+ {GAISLER_ATACTRL, "ATACTRL"},
+ {GAISLER_DDRSP, "DDRSP"},
+ {GAISLER_EHCI, "EHCI"},
+ {GAISLER_UHCI, "UHCI"},
+ {GAISLER_I2CMST, "I2CMST"},
+ {GAISLER_SPW2, "SPW2"},
+ {GAISLER_AHBDMA, "AHBDMA"},
+ {GAISLER_NUHOSP3, "NUHOSP3"},
+ {GAISLER_CLKGATE, "CLKGATE"},
+ {GAISLER_SPICTRL, "SPICTRL"},
+ {GAISLER_DDR2SP, "DDR2SP"},
+ {GAISLER_SLINK, "SLINK"},
+ {GAISLER_GRTM, "GRTM"},
+ {GAISLER_GRTC, "GRTC"},
+ {GAISLER_GRPW, "GRPW"},
+ {GAISLER_GRCTM, "GRCTM"},
+ {GAISLER_GRHCAN, "GRHCAN"},
+ {GAISLER_GRFIFO, "GRFIFO"},
+ {GAISLER_GRADCDAC, "GRADCDAC"},
+ {GAISLER_GRPULSE, "GRPULSE"},
+ {GAISLER_GRTIMER, "GRTIMER"},
+ {GAISLER_AHB2PP, "AHB2PP"},
+ {GAISLER_GRVERSION, "GRVERSION"},
+ {GAISLER_APB2PW, "APB2PW"},
+ {GAISLER_PW2APB, "PW2APB"},
+ {GAISLER_GRCAN, "GRCAN"},
+ {GAISLER_I2CSLV, "I2CSLV"},
+ {GAISLER_U16550, "U16550"},
+ {GAISLER_AHBMST_EM, "AHBMST_EM"},
+ {GAISLER_AHBSLV_EM, "AHBSLV_EM"},
+ {GAISLER_GRTESTMOD, "GRTESTMOD"},
+ {GAISLER_ASCS, "ASCS"},
+ {GAISLER_IPMVBCTRL, "IPMVBCTRL"},
+ {GAISLER_SPIMCTRL, "SPIMCTRL"},
+ {GAISLER_LEON4, "LEON4"},
+ {GAISLER_LEON4DSU, "LEON4DSU"},
+ {GAISLER_GRPWM, "GRPWM"},
+ {GAISLER_FTAHBRAM, "FTAHBRAM"},
+ {GAISLER_FTSRCTRL, "FTSRCTRL"},
+ {GAISLER_AHBSTAT, "AHBSTAT"},
+ {GAISLER_LEON3FT, "LEON3FT"},
+ {GAISLER_FTMCTRL, "FTMCTRL"},
+ {GAISLER_FTSDCTRL, "FTSDCTRL"},
+ {GAISLER_FTSRCTRL8, "FTSRCTRL8"},
+ {GAISLER_MEMSCRUB, "MEMSCRUB"},
+ {GAISLER_APBPS2, "APBPS2"},
+ {GAISLER_VGACTRL, "VGACTRL"},
+ {GAISLER_LOGAN, "LOGAN"},
+ {GAISLER_SVGACTRL, "SVGACTRL"},
+ {GAISLER_T1AHB, "T1AHB"},
+ {GAISLER_MP7WRAP, "MP7WRAP"},
+ {GAISLER_GRSYSMON, "GRSYSMON"},
+ {GAISLER_GRACECTRL, "GRACECTRL"},
+ {GAISLER_B1553BC, "B1553BC"},
+ {GAISLER_B1553RT, "B1553RT"},
+ {GAISLER_B1553BRM, "B1553BRM"},
+ {GAISLER_SATCAN, "SATCAN"},
+ {GAISLER_CANMUX, "CANMUX"},
+ {GAISLER_GRTMRX, "GRTMRX"},
+ {GAISLER_GRTCTX, "GRTCTX"},
+ {GAISLER_GRTMDESC, "GRTMDESC"},
+ {GAISLER_GRTMVC, "GRTMVC"},
+ {GAISLER_GEFFE, "GEFFE"},
+ {GAISLER_AES, "AES"},
+ {GAISLER_GRAESDMA, "GRAESDMA"},
+ {GAISLER_ECC, "ECC"},
+ {GAISLER_PCIF, "PCIF"},
+ {GAISLER_CLKMOD, "CLKMOD"},
+ {GAISLER_HAPSTRAK, "HAPSTRAK"},
+ {GAISLER_TEST_1X2, "TEST_1X2"},
+ {GAISLER_WILD2AHB, "WILD2AHB"},
+ {GAISLER_BIO1, "BIO1"},
+ {GAISLER_GR1553B, "GR1553B"},
+ {GAISLER_L2CACHE, "L2CACHE"},
+ {GAISLER_L4STAT, "L4STAT"},
+ {GAISLER_GRPCI2, "GRPCI2"},
+ {GAISLER_GRPCI2_DMA, "GRPCI2_DMA"},
+ {GAISLER_GRIOMMU, "GRIOMMU"},
+ {GAISLER_SPW2_DMA, "SPW2_DMA"},
+ {GAISLER_SPW_ROUTER, "SPW_ROUTER"},
+ {0, NULL}
+};
+
+static ambapp_device_name PENDER_devices[] =
+{
+ {0, NULL}
+};
+
+static ambapp_device_name ESA_devices[] =
+{
+ {ESA_LEON2, "LEON2"},
+ {ESA_LEON2APB, "LEON2APB"},
+ {ESA_IRQ, "IRQ"},
+ {ESA_TIMER, "TIMER"},
+ {ESA_UART, "UART"},
+ {ESA_CFG, "CFG"},
+ {ESA_IO, "IO"},
+ {ESA_MCTRL, "MCTRL"},
+ {ESA_PCIARB, "PCIARB"},
+ {ESA_HURRICANE, "HURRICANE"},
+ {ESA_SPW_RMAP, "SPW_RMAP"},
+ {ESA_AHBUART, "AHBUART"},
+ {ESA_SPWA, "SPWA"},
+ {ESA_BOSCHCAN, "BOSCHCAN"},
+ {ESA_IRQ2, "IRQ2"},
+ {ESA_AHBSTAT, "AHBSTAT"},
+ {ESA_WPROT, "WPROT"},
+ {ESA_WPROT2, "WPROT2"},
+ {ESA_PDEC3AMBA, "PDEC3AMBA"},
+ {ESA_PTME3AMBA, "PTME3AMBA"},
+ {0, NULL}
+};
+
+static ambapp_device_name ASTRIUM_devices[] =
+{
+ {0, NULL}
+};
+
+static ambapp_device_name OPENCHIP_devices[] =
+{
+ {OPENCHIP_APBGPIO, "APBGPIO"},
+ {OPENCHIP_APBI2C, "APBI2C"},
+ {OPENCHIP_APBSPI, "APBSPI"},
+ {OPENCHIP_APBCHARLCD, "APBCHARLCD"},
+ {OPENCHIP_APBPWM, "APBPWM"},
+ {OPENCHIP_APBPS2, "APBPS2"},
+ {OPENCHIP_APBMMCSD, "APBMMCSD"},
+ {OPENCHIP_APBNAND, "APBNAND"},
+ {OPENCHIP_APBLPC, "APBLPC"},
+ {OPENCHIP_APBCF, "APBCF"},
+ {OPENCHIP_APBSYSACE, "APBSYSACE"},
+ {OPENCHIP_APB1WIRE, "APB1WIRE"},
+ {OPENCHIP_APBJTAG, "APBJTAG"},
+ {OPENCHIP_APBSUI, "APBSUI"},
+ {0, NULL}
+};
+
+static ambapp_device_name OPENCORES_devices[] =
+{
+ {0, NULL}
+};
+
+static ambapp_device_name CONTRIB_devices[] =
+{
+ {CONTRIB_CORE1, "CORE1"},
+ {CONTRIB_CORE2, "CORE2"},
+ {0, NULL}
+};
+
+static ambapp_device_name EONIC_devices[] =
+{
+ {0, NULL}
+};
+
+static ambapp_device_name RADIONOR_devices[] =
+{
+ {0, NULL}
+};
+
+static ambapp_device_name GLEICHMANN_devices[] =
+{
+ {GLEICHMANN_CUSTOM, "CUSTOM"},
+ {GLEICHMANN_GEOLCD01, "GEOLCD01"},
+ {GLEICHMANN_DAC, "DAC"},
+ {GLEICHMANN_HPI, "HPI"},
+ {GLEICHMANN_SPI, "SPI"},
+ {GLEICHMANN_HIFC, "HIFC"},
+ {GLEICHMANN_ADCDAC, "ADCDAC"},
+ {GLEICHMANN_SPIOC, "SPIOC"},
+ {GLEICHMANN_AC97, "AC97"},
+ {0, NULL}
+};
+
+static ambapp_device_name MENTA_devices[] =
+{
+ {0, NULL}
+};
+
+static ambapp_device_name SUN_devices[] =
+{
+ {SUN_T1, "SUN_T1"},
+ {SUN_S1, "SUN_S1"},
+ {0, NULL}
+};
+
+static ambapp_device_name MOVIDIA_devices[] =
+{
+ {0, NULL}
+};
+
+static ambapp_device_name ORBITA_devices[] =
+{
+ {ORBITA_1553B, "1553B"},
+ {ORBITA_429, "429"},
+ {ORBITA_SPI, "SPI"},
+ {ORBITA_I2C, "I2C"},
+ {ORBITA_SMARTCARD, "SMARTCARD"},
+ {ORBITA_SDCARD, "SDCARD"},
+ {ORBITA_UART16550, "UART16550"},
+ {ORBITA_CRYPTO, "CRYPTO"},
+ {ORBITA_SYSIF, "SYSIF"},
+ {ORBITA_PIO, "PIO"},
+ {ORBITA_RTC, "RTC"},
+ {ORBITA_COLORLCD, "COLORLCD"},
+ {ORBITA_PCI, "PCI"},
+ {ORBITA_DSP, "DSP"},
+ {ORBITA_USBHOST, "USBHOST"},
+ {ORBITA_USBDEV, "USBDEV"},
+ {0, NULL}
+};
+
+static ambapp_device_name SYNOPSYS_devices[] =
+{
+ {0, NULL}
+};
+
+static ambapp_device_name NASA_devices[] =
+{
+ {NASA_EP32, "EP32"},
+ {0, NULL}
+};
+
+static ambapp_device_name CAL_devices[] =
+{
+ {CAL_DDRCTRL, "DDRCTRL"},
+ {0, NULL}
+};
+
+static ambapp_device_name EMBEDDIT_devices[] =
+{
+ {0, NULL}
+};
+
+static ambapp_device_name CETON_devices[] =
+{
+ {0, NULL}
+};
+
+static ambapp_device_name ACTEL_devices[] =
+{
+ {ACTEL_COREMP7, "COREMP7"},
+ {0, NULL}
+};
+
+static ambapp_vendor_devnames vendors[] =
+{
+ {VENDOR_GAISLER, "GAISLER", GAISLER_devices},
+ {VENDOR_PENDER, "PENDER", PENDER_devices},
+ {VENDOR_ESA, "ESA", ESA_devices},
+ {VENDOR_ASTRIUM, "ASTRIUM", ASTRIUM_devices},
+ {VENDOR_OPENCHIP, "OPENCHIP", OPENCHIP_devices},
+ {VENDOR_OPENCORES, "OPENCORES", OPENCORES_devices},
+ {VENDOR_CONTRIB, "CONTRIB", CONTRIB_devices},
+ {VENDOR_EONIC, "EONIC", EONIC_devices},
+ {VENDOR_RADIONOR, "RADIONOR", RADIONOR_devices},
+ {VENDOR_GLEICHMANN, "GLEICHMANN", GLEICHMANN_devices},
+ {VENDOR_MENTA, "MENTA", MENTA_devices},
+ {VENDOR_SUN, "SUN", SUN_devices},
+ {VENDOR_MOVIDIA, "MOVIDIA", MOVIDIA_devices},
+ {VENDOR_ORBITA, "ORBITA", ORBITA_devices},
+ {VENDOR_SYNOPSYS, "SYNOPSYS", SYNOPSYS_devices},
+ {VENDOR_NASA, "NASA", NASA_devices},
+ {VENDOR_CAL, "CAL", CAL_devices},
+ {VENDOR_EMBEDDIT, "EMBEDDIT", EMBEDDIT_devices},
+ {VENDOR_CETON, "CETON", CETON_devices},
+ {VENDOR_ACTEL, "ACTEL", ACTEL_devices},
+ {0, NULL, NULL}
+};
+
+/*****************************************************************/
+
+static char *ambapp_get_devname(ambapp_device_name *devs, int id)
+{
+ while (devs->device_id > 0) {
+ if (devs->device_id == id)
+ return devs->name;
+ devs++;
+ }
+ return NULL;
+}
+
+char *ambapp_device_id2str(int vendor, int id)
+{
+ ambapp_vendor_devnames *ven = &vendors[0];
+
+ while (ven->vendor_id > 0) {
+ if (ven->vendor_id == vendor)
+ return ambapp_get_devname(ven->devices,id);
+ ven++;
+ }
+ return NULL;
+}
+
+char *ambapp_vendor_id2str(int vendor)
+{
+ ambapp_vendor_devnames *ven = &vendors[0];
+
+ while (ven->vendor_id > 0) {
+ if (ven->vendor_id == vendor)
+ return ven->name;
+ ven++;
+ }
+ return NULL;
+}
+
+int ambapp_vendev_id2str(int vendor, int id, char *buf)
+{
+ char *dstr, *vstr;
+
+ *buf = '\0';
+
+ vstr = ambapp_vendor_id2str(vendor);
+ if (vstr == NULL)
+ return 0;
+
+ dstr = ambapp_device_id2str(vendor, id);
+ if (dstr == NULL)
+ return 0;
+
+ strcpy(buf, vstr);
+ strcat(buf, "_");
+ strcat(buf, dstr);
+
+ return strlen(buf);
+}
diff --git a/c/src/lib/libbsp/sparc/shared/amba/ambapp_old.c b/c/src/lib/libbsp/sparc/shared/amba/ambapp_old.c
new file mode 100644
index 0000000000..1b543abde9
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/amba/ambapp_old.c
@@ -0,0 +1,106 @@
+/* Old AMBA scanning Interface provided for backwards compability */
+#include <ambapp.h>
+
+struct ambapp_dev_find_match_arg {
+ int index;
+ int count;
+ int type;
+ void *dev;
+};
+
+/* AMBA PP find routines */
+int ambapp_dev_find_match(struct ambapp_dev *dev, int index, void *arg)
+{
+ struct ambapp_dev_find_match_arg *p = arg;
+
+ if (p->index == 0) {
+ /* Found controller, stop */
+ if (p->type == DEV_APB_SLV) {
+ *(struct ambapp_apb_info *)p->dev = *DEV_TO_APB(dev);
+ p->dev = ((struct ambapp_apb_info *)p->dev)+1;
+ } else {
+ *(struct ambapp_ahb_info *)p->dev = *DEV_TO_AHB(dev);
+ p->dev = ((struct ambapp_ahb_info *)p->dev)+1;
+ }
+ p->count--;
+ if (p->count < 1)
+ return 1;
+ } else {
+ p->index--;
+ }
+ return 0;
+}
+
+int ambapp_find_apbslvs_next(struct ambapp_bus *abus, int vendor, int device, struct ambapp_apb_info *dev, int index, int maxno)
+{
+ struct ambapp_dev_find_match_arg arg;
+
+ arg.index = index;
+ arg.count = maxno;
+ arg.type = DEV_APB_SLV; /* APB */
+ arg.dev = dev;
+
+ ambapp_for_each(abus, (OPTIONS_ALL|OPTIONS_APB_SLVS), vendor, device,
+ ambapp_dev_find_match, &arg);
+
+ return maxno - arg.count;
+}
+
+int ambapp_find_apbslv(struct ambapp_bus *abus, int vendor, int device, struct ambapp_apb_info *dev)
+{
+ return ambapp_find_apbslvs_next(abus, vendor, device, dev, 0, 1);
+}
+
+int ambapp_find_apbslv_next(struct ambapp_bus *abus, int vendor, int device, struct ambapp_apb_info *dev, int index)
+{
+ return ambapp_find_apbslvs_next(abus, vendor, device, dev, index, 1);
+}
+
+int ambapp_find_apbslvs(struct ambapp_bus *abus, int vendor, int device, struct ambapp_apb_info *dev, int maxno)
+{
+ return ambapp_find_apbslvs_next(abus, vendor, device, dev, 0, maxno);
+}
+
+int ambapp_get_number_apbslv_devices(struct ambapp_bus *abus, int vendor, int device)
+{
+ return ambapp_dev_count(abus,
+ (OPTIONS_ALL|OPTIONS_APB_SLVS),
+ vendor, device);
+}
+
+int ambapp_find_ahbslvs_next(struct ambapp_bus *abus, int vendor, int device, struct ambapp_ahb_info *dev, int index, int maxno)
+{
+ struct ambapp_dev_find_match_arg arg;
+
+ arg.index = index;
+ arg.count = maxno;
+ arg.type = DEV_AHB_SLV; /* AHB SLV */
+ arg.dev = dev;
+
+ ambapp_for_each(abus, (OPTIONS_ALL|OPTIONS_AHB_SLVS), vendor, device,
+ ambapp_dev_find_match, &arg);
+
+ return maxno - arg.count;
+}
+
+int ambapp_find_ahbslv_next(struct ambapp_bus *abus, int vendor, int device, struct ambapp_ahb_info *dev, int index)
+{
+ return ambapp_find_ahbslvs_next(abus, vendor, device, dev, index, 1);
+}
+
+int ambapp_find_ahbslv(struct ambapp_bus *abus, int vendor, int device, struct ambapp_ahb_info *dev)
+{
+ return ambapp_find_ahbslvs_next(abus, vendor, device, dev, 0, 1);
+}
+
+int ambapp_find_ahbslvs(struct ambapp_bus *abus, int vendor, int device, struct ambapp_ahb_info *dev, int maxno)
+{
+ return ambapp_find_ahbslvs_next(abus, vendor, device, dev, 0, maxno);
+}
+
+int ambapp_get_number_ahbslv_devices(struct ambapp_bus *abus, int vendor, int device)
+{
+ return ambapp_dev_count(abus,
+ (OPTIONS_ALL|OPTIONS_AHB_SLVS),
+ vendor, device);
+}
diff --git a/c/src/lib/libbsp/sparc/shared/amba/ambapp_parent.c b/c/src/lib/libbsp/sparc/shared/amba/ambapp_parent.c
new file mode 100644
index 0000000000..44d3b26ea7
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/amba/ambapp_parent.c
@@ -0,0 +1,26 @@
+/*
+ * AMBA Plug & Play routines
+ *
+ * COPYRIGHT (c) 2011
+ * Aeroflex Gaisler
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id: ambapp_parent.c,v
+ *
+ */
+
+#include <stdlib.h>
+#include <ambapp.h>
+
+struct ambapp_dev *ambapp_find_parent(struct ambapp_dev *dev)
+{
+ while (dev->prev) {
+ if (dev == dev->prev->children)
+ return dev->prev;
+ dev = dev->prev;
+ }
+ return NULL;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/amba/ambapp_show.c b/c/src/lib/libbsp/sparc/shared/amba/ambapp_show.c
new file mode 100644
index 0000000000..eecca406e9
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/amba/ambapp_show.c
@@ -0,0 +1,76 @@
+/* AMBA Plug & Play device information printing.
+ *
+ * COPYRIGHT (c) 2009.
+ * Aeroflex Gaisler.
+ *
+ * Prints a short description of APB and AHB devices.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2008-12-01, Daniel Hellstrom <daniel@gaisler.com>
+ * Created
+ */
+
+#include <stdio.h>
+#include <ambapp.h>
+
+extern char *ambapp_device_id2str(int vendor, int id);
+extern char *ambapp_vendor_id2str(int vendor);
+
+struct ambapp_dev_print_arg {
+ int show_depth;
+};
+
+static char *unknown = "unknown";
+
+int ambapp_dev_print(struct ambapp_dev *dev, int index, void *arg)
+{
+ char *dev_str, *ven_str, *type_str;
+ struct ambapp_dev_print_arg *p = arg;
+ char dp[32];
+ int i=0;
+ unsigned int basereg;
+
+ if (p->show_depth) {
+ for (i=0; i<ambapp_depth(dev)*2; i+=2) {
+ dp[i] = ' ';
+ dp[i+1] = ' ';
+ }
+ }
+ dp[i] = '\0';
+
+ ven_str = ambapp_vendor_id2str(dev->vendor);
+ if (!ven_str) {
+ ven_str = unknown;
+ dev_str = unknown;
+ } else {
+ dev_str = ambapp_device_id2str(dev->vendor,dev->device);
+ if (!dev_str)
+ dev_str = unknown;
+ }
+ if (dev->dev_type == DEV_APB_SLV) {
+ /* APB */
+ basereg = DEV_TO_APB(dev)->start;
+ type_str = "apb";
+ } else {
+ /* AHB */
+ basereg = DEV_TO_AHB(dev)->start[0];
+ type_str = "ahb";
+ }
+ printf("%s |-> 0x%x:0x%x:0x%x: %s_%s, %s: 0x%x, 0x%x (OWNER: 0x%x)\n",
+ dp, index, dev->vendor, dev->device, ven_str, dev_str, type_str,
+ basereg, (unsigned int)dev, (unsigned int)dev->owner);
+
+ return 0;
+}
+
+void ambapp_print(struct ambapp_bus *abus, int show_depth)
+{
+ struct ambapp_dev_print_arg arg;
+ arg.show_depth = show_depth;
+ ambapp_for_each(abus,
+ (OPTIONS_ALL_DEVS|OPTIONS_ALL|OPTIONS_DEPTH_FIRST), -1,
+ -1, ambapp_dev_print, &arg);
+}
diff --git a/c/src/lib/libbsp/sparc/shared/analog/gradcdac.c b/c/src/lib/libbsp/sparc/shared/analog/gradcdac.c
new file mode 100644
index 0000000000..6c7b233b1f
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/analog/gradcdac.c
@@ -0,0 +1,582 @@
+/* ADC / DAC (GRADCDAC) interface implementation
+ *
+ * COPYRIGHT (c) 2009.
+ * Aeroflex Gaisler AB
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2009-06-01, Daniel Hellstrom <daniel@gaisler.com>
+ * Created
+ *
+ */
+
+#include <rtems.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+#include <gradcdac.h>
+
+/****************** DEBUG Definitions ********************/
+#define DBG_IOCTRL 1
+#define DBG_TX 2
+#define DBG_RX 4
+
+#define DEBUG_FLAGS (DBG_IOCTRL | DBG_RX | DBG_TX )
+/* Uncomment for debug output */
+/*
+#define DEBUG
+#define DEBUGFUNCS
+*/
+#include <debug_defs.h>
+
+struct gradcdac_priv {
+ struct gradcdac_regs *regs; /* Must be first */
+ struct drvmgr_dev *dev;
+ char devName[48];
+
+ unsigned int freq;
+ int irqno;
+ int minor;
+
+ void (*isr_adc)(void *cookie, void *arg);
+ void (*isr_dac)(void *cookie, void *arg);
+ void *isr_adc_arg;
+ void *isr_dac_arg;
+
+ int open;
+};
+
+/* Global variables */
+
+/* Print Info routines */
+void gradcdac_print(void *cookie);
+
+int gradcdac_init2(struct drvmgr_dev *dev);
+int gradcdac_init3(struct drvmgr_dev *dev);
+int gradcadc_device_init(struct gradcdac_priv *pDev);
+void gradcdac_adc_interrupt(void *arg);
+void gradcdac_dac_interrupt(void *arg);
+
+struct drvmgr_drv_ops gradcdac_ops =
+{
+ .init = {NULL, gradcdac_init2, gradcdac_init3, NULL},
+ .remove = NULL,
+ .info = NULL
+};
+
+struct amba_dev_id gradcdac_ids[] =
+{
+ {VENDOR_GAISLER, GAISLER_GRADCDAC},
+ {0, 0} /* Mark end of table */
+};
+
+struct amba_drv_info gradcdac_drv_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_AMBAPP_GAISLER_GRADCDAC_ID, /* Driver ID */
+ "GRADCDAC_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */
+ &gradcdac_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ 0,
+ },
+ &gradcdac_ids[0]
+};
+
+void gradcdac_register_drv (void)
+{
+ DBG("Registering GRADCDAC driver\n");
+ drvmgr_drv_register(&gradcdac_drv_info.general);
+}
+
+int gradcdac_init2(struct drvmgr_dev *dev)
+{
+ struct gradcdac_priv *priv;
+
+ DBG("GRADCDAC[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
+
+ priv = dev->priv = malloc(sizeof(struct gradcdac_priv));
+ if ( !priv )
+ return DRVMGR_NOMEM;
+ memset(priv, 0, sizeof(*priv));
+ priv->dev = dev;
+
+ /* This core will not find other cores, so we wait for init2() */
+
+ return DRVMGR_OK;
+}
+
+
+int gradcdac_init3(struct drvmgr_dev *dev)
+{
+ struct gradcdac_priv *priv = dev->priv;
+ char prefix[32];
+
+ if ( !priv )
+ return DRVMGR_FAIL;
+
+ if ( gradcadc_device_init(priv) ) {
+ free(dev->priv);
+ dev->priv = NULL;
+ return DRVMGR_FAIL;
+ }
+
+ /* Get Filesystem name prefix */
+ prefix[0] = '\0';
+ if ( drvmgr_get_dev_prefix(dev, prefix) ) {
+ /* Failed to get prefix, make sure of a unique FS name
+ * by using the driver minor.
+ */
+ sprintf(priv->devName, "/dev/gradcdac%d", dev->minor_drv);
+ } else {
+ /* Got special prefix, this means we have a bus prefix
+ * And we should use our "bus minor"
+ */
+ sprintf(priv->devName, "/dev/%sgradcdac%d", prefix, dev->minor_bus);
+ }
+
+ return DRVMGR_OK;
+}
+
+void gradcdac_print_dev(struct gradcdac_priv *pDev)
+{
+ printf("======= GRADCDAC %p =======\n", pDev->regs);
+ printf(" Minor: %d\n", pDev->minor);
+ printf(" Dev Name: %s\n", pDev->devName);
+ printf(" RegBase: %p\n", pDev->regs);
+ printf(" IRQ: %d and %d\n", pDev->irqno, pDev->irqno+1);
+ printf(" Core Freq: %d kHz\n", pDev->freq / 1000);
+ printf(" Opened: %s\n", pDev->open ? "YES" : "NO");
+
+ printf(" CONFIG: 0x%x\n", pDev->regs->config);
+ printf(" STATUS: 0x%x\n", pDev->regs->status);
+}
+
+void gradcdac_print(void *cookie)
+{
+ struct drvmgr_dev *dev;
+ struct gradcdac_priv *pDev;
+
+ if ( cookie ) {
+ gradcdac_print_dev(cookie);
+ return;
+ }
+
+ /* Show all */
+ dev = gradcdac_drv_info.general.dev;
+ while (dev) {
+ pDev = (struct gradcdac_priv *)dev->priv;
+ gradcdac_print_dev(pDev);
+ dev = dev->next_in_drv;
+ }
+}
+
+void gradcdac_hw_reset(struct gradcdac_regs *regs)
+{
+ /* Reset core */
+ regs->config = 0;
+ regs->adrdir = 0;
+ regs->adrout = 0;
+ regs->data_dir = 0;
+ regs->data_out = 0;
+}
+
+/* Device initialization called once on startup */
+int gradcadc_device_init(struct gradcdac_priv *pDev)
+{
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
+
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)pDev->dev->businfo;
+ if ( ambadev == NULL ) {
+ return -1;
+ }
+ pnpinfo = &ambadev->info;
+ pDev->irqno = pnpinfo->irq;
+ pDev->regs = (struct gradcdac_regs *)pnpinfo->apb_slv->start;
+ pDev->minor = pDev->dev->minor_drv;
+
+ /* Reset Hardware before attaching IRQ handler */
+ gradcdac_hw_reset(pDev->regs);
+
+ pDev->open = 0;
+
+ /* Get frequency in Hz */
+ if ( drvmgr_freq_get(pDev->dev, DEV_APB_SLV, &pDev->freq) ) {
+ return -1;
+ }
+
+ DBG("GRADCDAC frequency: %d Hz\n", pDev->freq);
+
+ return 0;
+}
+
+void gradcdac_dac_interrupt(void *arg)
+{
+ struct gradcdac_priv *pDev = arg;
+ if ( pDev->isr_dac )
+ pDev->isr_dac(pDev, pDev->isr_dac_arg);
+}
+
+void gradcdac_adc_interrupt(void *arg)
+{
+ struct gradcdac_priv *pDev = arg;
+ if ( pDev->isr_adc )
+ pDev->isr_adc(pDev, pDev->isr_adc_arg);
+}
+
+void *gradcdac_open(char *devname)
+{
+ struct gradcdac_priv *pDev;
+ struct drvmgr_dev *dev;
+
+ /* Find device by name */
+ dev = gradcdac_drv_info.general.dev;
+ while ( dev ) {
+ pDev = (struct gradcdac_priv *)dev->priv;
+ if ( pDev ) {
+ if ( strncmp(pDev->devName, devname, sizeof(pDev->devName)) == 0 ) {
+ /* Found matching device name */
+ break;
+ }
+ }
+ dev = dev->next_in_drv;
+ }
+
+ if ( !dev )
+ return NULL;
+
+ /* is device busy/taken? */
+ if ( pDev->open )
+ return NULL;
+
+ /* Mark device taken */
+ pDev->open = 1;
+
+ return pDev;
+}
+
+void gradcdac_set_config(void *cookie, struct gradcdac_config *cfg)
+{
+ struct gradcdac_priv *pDev = cookie;
+ unsigned int config=0;
+
+ config = (cfg->dac_ws<<GRADCDAC_CFG_DACWS_BIT)&GRADCDAC_CFG_DACWS;
+
+ if ( cfg->wr_pol )
+ config |= GRADCDAC_CFG_WRPOL;
+
+ config |= (cfg->dac_dw<<GRADCDAC_CFG_DACDW_BIT)&GRADCDAC_CFG_DACDW;
+
+ config |= (cfg->adc_ws<<GRADCDAC_CFG_ADCWS_BIT)&GRADCDAC_CFG_ADCWS;
+
+ if ( cfg->rc_pol )
+ config |= GRADCDAC_CFG_RCPOL;
+
+ config |= (cfg->cs_mode<<GRADCDAC_CFG_CSMODE_BIT)&GRADCDAC_CFG_CSMODE;
+
+ if ( cfg->cs_pol )
+ config |= GRADCDAC_CFG_CSPOL;
+
+ if ( cfg->ready_mode )
+ config |= GRADCDAC_CFG_RDYMODE;
+
+ if ( cfg->ready_pol )
+ config |= GRADCDAC_CFG_RDYPOL;
+
+ if ( cfg->trigg_pol )
+ config |= GRADCDAC_CFG_TRIGPOL;
+
+ config |= (cfg->trigg_mode<<GRADCDAC_CFG_TRIGMODE_BIT)&GRADCDAC_CFG_TRIGMODE;
+
+ config |= (cfg->adc_dw<<GRADCDAC_CFG_ADCDW_BIT)&GRADCDAC_CFG_ADCDW;
+
+ /* Write config */
+ pDev->regs->config = config;
+}
+
+void gradcdac_get_config(void *cookie, struct gradcdac_config *cfg)
+{
+ struct gradcdac_priv *pDev = cookie;
+ unsigned int config;
+
+ if ( !cfg )
+ return;
+
+ /* Get config */
+ config = pDev->regs->config;
+
+ cfg->dac_ws = (config&GRADCDAC_CFG_DACWS)>>GRADCDAC_CFG_DACWS_BIT;
+
+ cfg->wr_pol = (config&GRADCDAC_CFG_WRPOL)>>GRADCDAC_CFG_WRPOL_BIT;
+
+ cfg->dac_dw = (config&GRADCDAC_CFG_DACDW)>>GRADCDAC_CFG_DACDW_BIT;
+
+ cfg->adc_ws = (config&GRADCDAC_CFG_ADCWS)>>GRADCDAC_CFG_ADCWS_BIT;
+
+ cfg->rc_pol = (config&GRADCDAC_CFG_RCPOL)>>GRADCDAC_CFG_RCPOL_BIT;
+
+ cfg->cs_mode = (config&GRADCDAC_CFG_CSMODE)>>GRADCDAC_CFG_CSMODE_BIT;
+
+ cfg->cs_pol = (config&GRADCDAC_CFG_CSPOL)>>GRADCDAC_CFG_CSPOL_BIT;
+
+ cfg->ready_mode = (config&GRADCDAC_CFG_RDYMODE)>>GRADCDAC_CFG_RDYMODE_BIT;
+
+ cfg->ready_pol = (config&GRADCDAC_CFG_RDYPOL)>>GRADCDAC_CFG_RDYPOL_BIT;
+
+ cfg->trigg_pol = (config&GRADCDAC_CFG_TRIGPOL)>>GRADCDAC_CFG_TRIGPOL_BIT;
+
+ cfg->trigg_mode = (config&GRADCDAC_CFG_TRIGMODE)>>GRADCDAC_CFG_TRIGMODE_BIT;
+
+ cfg->adc_dw = (config&GRADCDAC_CFG_ADCDW)>>GRADCDAC_CFG_ADCDW_BIT;
+}
+
+void gradcdac_set_cfg(void *cookie, unsigned int config)
+{
+ struct gradcdac_priv *pDev = cookie;
+ pDev->regs->config = config;
+}
+
+unsigned int gradcdac_get_cfg(void *cookie)
+{
+ struct gradcdac_priv *pDev = cookie;
+ return pDev->regs->config;
+}
+
+unsigned int gradcdac_get_status(void *cookie)
+{
+ struct gradcdac_priv *pDev = cookie;
+ return pDev->regs->status;
+}
+
+/* Install IRQ handler for ADC and/or DAC interrupt.
+ * The installed IRQ handler(ISR) must read the status
+ * register to clear the pending interrupt avoiding multiple
+ * entries to the ISR caused by the same IRQ.
+ *
+ * \param adc 1=ADC interrupt, 2=ADC interrupt, 3=ADC and DAC interrupt
+ * \param isr Interrupt service routine called when IRQ is fired
+ * \param arg custom argument passed to ISR when called.
+ */
+int gradcdac_install_irq_handler(void *cookie, int adc, void (*isr)(void *cookie, void *arg), void *arg)
+{
+ struct gradcdac_priv *pDev = cookie;
+
+ if ( (adc > 3) || !adc )
+ return -1;
+
+ if ( adc & GRADCDAC_ISR_ADC ){
+ pDev->isr_adc_arg = arg;
+ pDev->isr_adc = isr;
+ drvmgr_interrupt_register(pDev->dev, GRADCDAC_IRQ_ADC, "gradcdac_adc", gradcdac_adc_interrupt, pDev);
+ }
+
+ if ( adc & GRADCDAC_ISR_DAC ){
+ pDev->isr_dac_arg = arg;
+ pDev->isr_dac = isr;
+ drvmgr_interrupt_register(pDev->dev, GRADCDAC_IRQ_DAC, "gradcdac_dac", gradcdac_dac_interrupt, pDev);
+ }
+
+ return 0;
+}
+
+void gradcdac_uninstall_irq_handler(void *cookie, int adc)
+{
+ struct gradcdac_priv *pDev = cookie;
+
+ if ( (adc > 3) || !adc )
+ return;
+
+ if ( adc & GRADCDAC_ISR_ADC ){
+ drvmgr_interrupt_unregister(pDev->dev, GRADCDAC_IRQ_ADC, gradcdac_adc_interrupt, pDev);
+ pDev->isr_adc = NULL;
+ pDev->isr_adc_arg = NULL;
+ }
+
+ if ( adc & GRADCDAC_ISR_DAC ){
+ drvmgr_interrupt_unregister(pDev->dev, GRADCDAC_IRQ_DAC, gradcdac_dac_interrupt, pDev);
+ pDev->isr_dac = NULL;
+ pDev->isr_dac_arg = NULL;
+ }
+}
+
+/* Make the ADC circuitry initialize a analogue to digital
+ * conversion. The result can be read out by gradcdac_adc_convert_try
+ * or gradcdac_adc_convert.
+ */
+void gradcdac_adc_convert_start(void *cookie)
+{
+ struct gradcdac_priv *pDev = cookie;
+
+ /* Write to ADC Data Input register to start a conversion */
+ pDev->regs->adc_din = 0;
+}
+
+/* Tries to read the conversion result. If the circuitry is busy
+ * converting the function return a non-zero value, if the conversion
+ * has successfully finished the function return zero.
+ *
+ * \param digital_value the resulting converted value is placed here
+ * \return zero = ADC conversion complete, digital_value contain current conversion result
+ * positive = ADC busy, digital_value contain previous conversion result
+ * negative = Conversion request failed.
+ */
+int gradcdac_adc_convert_try(void *cookie, unsigned short *digital_value)
+{
+ struct gradcdac_priv *pDev = cookie;
+ unsigned int status;
+
+ status = pDev->regs->status;
+
+ if ( digital_value ){
+ *digital_value = pDev->regs->adc_din;
+ }
+
+ if ( gradcdac_ADC_isOngoing(status) )
+ return 1;
+
+ if ( gradcdac_ADC_isCompleted(status) )
+ return 0;
+
+ /* Failure */
+ return -1;
+}
+
+/* Waits until the ADC circuity has finished a digital to analogue
+ * conversion. The Waiting is implemented as a busy loop utilizing
+ * 100% CPU load.
+ */
+int gradcdac_adc_convert(void *cookie, unsigned short *digital_value)
+{
+ struct gradcdac_priv *pDev = cookie;
+ unsigned int status;
+
+ do {
+ status=gradcdac_get_status(pDev);
+ }while ( gradcdac_ADC_isOngoing(status) );
+
+ if ( digital_value )
+ *digital_value = pDev->regs->adc_din;
+
+ if ( gradcdac_ADC_isCompleted(status) )
+ return 0;
+
+ return -1;
+}
+
+/* Try to make the DAC circuitry initialize a digital to analogue
+ * conversion. If the circuitry is busy by a previous conversion
+ * the function return a non-zero value, if the conversion is
+ * successfully initialized the function return zero.
+ */
+int gradcdac_dac_convert_try(void *cookie, unsigned short digital_value)
+{
+ struct gradcdac_priv *pDev = cookie;
+ unsigned int status = pDev->regs->status;
+
+ if ( gradcdac_DAC_isOngoing(status) )
+ return -1;
+
+ /* Force a new conversion */
+ pDev->regs->dac_dout = digital_value;
+
+ /* Return success */
+ return 0;
+}
+
+/* Initializes a digital to analogue conversion by waiting until
+ * previous conversions is finished before proceeding with the
+ * conversion. The Waiting is implemented as a busy loop utilizing
+ * 100% CPU load.
+ */
+void gradcdac_dac_convert(void *cookie, unsigned short digital_value)
+{
+ struct gradcdac_priv *pDev = cookie;
+ unsigned int status;
+
+ do {
+ status = gradcdac_get_status(pDev);
+ }while( gradcdac_DAC_isOngoing(status) );
+
+ pDev->regs->dac_dout = digital_value;
+}
+
+unsigned int gradcdac_get_adrinput(void *cookie)
+{
+ struct gradcdac_priv *pDev = cookie;
+ return pDev->regs->adrin;
+}
+
+void gradcdac_set_adrinput(void *cookie, unsigned int input)
+{
+ struct gradcdac_priv *pDev = cookie;
+ pDev->regs->adrin = input;
+}
+
+unsigned int gradcdac_get_adroutput(void *cookie)
+{
+ struct gradcdac_priv *pDev = cookie;
+ return pDev->regs->adrout;
+}
+
+void gradcdac_set_adroutput(void *cookie, unsigned int output)
+{
+ struct gradcdac_priv *pDev = cookie;
+ pDev->regs->adrout = output;
+}
+
+unsigned int gradcdac_get_adrdir(void *cookie)
+{
+ struct gradcdac_priv *pDev = cookie;
+ return pDev->regs->adrdir;
+}
+
+void gradcdac_set_adrdir(void *cookie, unsigned int dir)
+{
+ struct gradcdac_priv *pDev = cookie;
+ pDev->regs->adrdir = dir;
+}
+
+unsigned int gradcdac_get_datainput(void *cookie)
+{
+ struct gradcdac_priv *pDev = cookie;
+ return pDev->regs->data_in;
+}
+
+void gradcdac_set_datainput(void *cookie, unsigned int input)
+{
+ struct gradcdac_priv *pDev = cookie;
+ pDev->regs->data_in = input;
+}
+
+unsigned int gradcdac_get_dataoutput(void *cookie)
+{
+ struct gradcdac_priv *pDev = cookie;
+ return pDev->regs->data_out;
+}
+
+void gradcdac_set_dataoutput(void *cookie, unsigned int output)
+{
+ struct gradcdac_priv *pDev = cookie;
+ pDev->regs->data_out = output;
+}
+
+unsigned int gradcdac_get_datadir(void *cookie)
+{
+ struct gradcdac_priv *pDev = cookie;
+ return pDev->regs->data_dir;
+}
+
+void gradcdac_set_datadir(void *cookie, unsigned int dir)
+{
+ struct gradcdac_priv *pDev = cookie;
+ pDev->regs->data_dir = dir;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/ascs/grascs.c b/c/src/lib/libbsp/sparc/shared/ascs/grascs.c
new file mode 100644
index 0000000000..2323260335
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/ascs/grascs.c
@@ -0,0 +1,629 @@
+/* This file contains the GRASCS RTEMS driver
+ *
+ * --------------------------------------------------------------------------
+ * -- This file is a part of GAISLER RESEARCH source code.
+ * -- Copyright (C) 2008, Gaisler Research AB - all rights reserved.
+ * --
+ * -- ANY USE OR REDISTRIBUTION IN PART OR IN WHOLE MUST BE HANDLED IN
+ * -- ACCORDANCE WITH THE GAISLER LICENSE AGREEMENT AND MUST BE APPROVED
+ * -- IN ADVANCE IN WRITING.
+ * --
+ * -- BY DEFAULT, DISTRIBUTION OR DISCLOSURE IS NOT PERMITTED.
+ * --------------------------------------------------------------------------
+ *
+ * Created:
+ * 2008-02-06: Jonas Ekergarn, ekergarn@gaisler.com
+ * Modified:
+ * 2009-01-07: Jonas Ekergarn, ekergarn@gaisler.com
+ * Replaced volatile variables tcactive and tmactive with
+ * semaphores tcsem2 and tmsem2. Also fixed a return value, a
+ * typo, renamed tcsem and tmsem to tcsem1 and tmsem1
+ * respectively, and corrected a function description.
+ *
+ */
+
+#include <stdlib.h>
+#include <bsp.h>
+#include <ambapp.h>
+#include <grascs.h>
+
+#ifndef GAISLER_ASCS
+#define GAISLER_ASCS 0x043
+#endif
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+typedef struct {
+ volatile unsigned int cmd;
+ volatile unsigned int clk;
+ volatile unsigned int sts;
+ volatile unsigned int tcd;
+ volatile unsigned int tmd;
+} GRASCS_regs;
+
+typedef struct {
+ unsigned char tmconf;
+ unsigned char usconf;
+ unsigned char nslaves;
+ unsigned char dbits;
+ int clkfreq;
+} GRASCS_caps;
+
+typedef struct {
+ GRASCS_regs *regs; /* Pointer to core registers */
+ GRASCS_caps *caps; /* Pointer to capability struct */
+ rtems_id tcsem1, tcsem2;
+ rtems_id tmsem1, tmsem2;
+ volatile char running;
+ int tcptr;
+ int tmptr;
+ int tcwords;
+ int tmwords;
+} GRASCS_cfg;
+
+static GRASCS_cfg *cfg = NULL;
+
+/*------------------------------------*/
+/* Start of internal helper functions */
+/*------------------------------------*/
+
+/* Function: ASCS_getaddr
+ Arguments: base: Core's register base address
+ irq: Core's irq
+ Return values: 0 if successful, -1 if core is not found
+ Description: Assigns core's register base address and
+ irq to arguments. Uses AMBA plug and play to find the
+ core.
+*/
+static int ASCS_get_addr(int *base, int *irq) {
+
+ struct ambapp_apb_info core;
+
+ if(ambapp_find_apbslv(&ambapp_plb, VENDOR_GAISLER, GAISLER_ASCS, &core) == 1) {
+ *base = core.start;
+ *irq = core.irq;
+ DBG("ASCS_get_addr: Registerd ASCS core at 0x%x with irq %i\n",core.start, core.irq);
+ return 0;
+ }
+ DBG("ASCS_get_addr: Failed to detect core\n");
+ return -1;
+}
+
+/* Function: ASCS_calc_clkreg
+ Arguments: sysfreq: System clock frequency in kHz
+ etrfreq: ETR frequency in Hz
+ Return values: Value of core's CLK-register
+ Description: Calculates value of core's CLK-register. See
+ GRASCS IP core documentation for details.
+*/
+static int ASCS_calc_clkreg(int sysfreq, int etrfreq) {
+
+ if(cfg->caps->usconf)
+ return 1000000/etrfreq;
+ else
+ return sysfreq*1000/etrfreq;
+}
+
+/* Function: ASCS_get_sysfreq
+ Arguments: -
+ Return values: System clock frequency in kHz, -1 if failed
+ Description: Uses AMBA plug and play to lookup system frequency
+*/
+static int ASCS_get_sysfreq(void) {
+
+ struct ambapp_apb_info gpt;
+ struct gptimer_regs *tregs;
+ int tmp;
+
+ if(ambapp_find_apbslv(&ambapp_plb, VENDOR_GAISLER, GAISLER_GPTIMER, &gpt) == 1) {
+ tregs = (struct gptimer_regs *) gpt.start;
+ tmp = (tregs->scaler_reload + 1)*1000;
+ DBG("ASCS_get_sysfreq: Detected system frequency %i kHz\n",tmp);
+ if((tmp < GRASCS_MIN_SFREQ) || (tmp > GRASCS_MAX_SFREQ)) {
+ DBG("ASCS_get_sysfreq: System frequency is invalid for ASCS core\n");
+ return -1;
+ }
+ else
+ return (tregs->scaler_reload + 1)*1000;
+ }
+ DBG("ASCS_get_sysfreq: Failed to detect system frequency\n");
+ return -1;
+}
+
+/* Function: ASCS_irqhandler
+ Arguments: v: not used
+ Return values: -
+ Description: Determines the source of the interrupt, clears the
+ appropriate bits in the core's STS register and releases
+ the associated semaphore
+*/
+static rtems_isr ASCS_irqhandler(rtems_vector_number v) {
+
+ if(cfg->regs->sts & GRASCS_STS_TCDONE) {
+ /* Clear TC done bit */
+ cfg->regs->sts |= GRASCS_STS_TCDONE;
+
+ if(--cfg->tcwords == 0)
+ /* No more TCs to perform right now */
+ rtems_semaphore_release(cfg->tcsem2);
+ else {
+ /* Block not sent yet, start next TC */
+ if(cfg->caps->dbits == 8) {
+ cfg->tcptr++;
+ cfg->regs->tcd = *((unsigned char*)cfg->tcptr);
+ }
+ else if(cfg->caps->dbits == 16) {
+ cfg->tcptr += 2;
+ cfg->regs->tcd = *((unsigned short int*)cfg->tcptr);
+ }
+ else {
+ cfg->tcptr += 4;
+ cfg->regs->tcd = *((unsigned int*)cfg->tcptr);
+ }
+ }
+ }
+
+ if(cfg->regs->sts & GRASCS_STS_TMDONE) {
+ /* Clear TM done bit */
+ cfg->regs->sts |= GRASCS_STS_TMDONE;
+
+ /* Store received data */
+ if(cfg->caps->dbits == 8) {
+ *((unsigned char*)cfg->tmptr) = (unsigned char)(cfg->regs->tmd & 0xFF);
+ cfg->tmptr++;
+ }
+ else if(cfg->caps->dbits == 16) {
+ *((unsigned short int*)cfg->tmptr) = (unsigned short int)(cfg->regs->tmd & 0xFFFF);
+ cfg->tmptr += 2;
+ }
+ else {
+ *((unsigned int*)cfg->tmptr) = cfg->regs->tmd;
+ cfg->tmptr += 4;
+ }
+
+ if(--cfg->tmwords == 0)
+ /* No more TMs to perform right now */
+ rtems_semaphore_release(cfg->tmsem2);
+ else
+ /* Block not received yet, start next TM */
+ cfg->regs->cmd |= GRASCS_CMD_SENDTM;
+ }
+}
+
+/*---------------------------*/
+/* Start of driver interface */
+/*---------------------------*/
+
+/* Function: ASCS_init
+ Arguments: -
+ Return values: 0 if successful, -1 if unsuccessful
+ Description: Initializes the ASCS core
+*/
+int ASCS_init(void) {
+
+ int base, irq, tmp;
+
+ DBG("ASCS_init: Starting initialization of ASCS core\n");
+
+ /* Allocate memory for config, status and capability struct */
+ if((cfg = (GRASCS_cfg*)malloc(sizeof(GRASCS_cfg))) == NULL) {
+ DBG("ASCS_init: Could not allocate memory for cfg struc\n");
+ return -1;
+ }
+
+ if((cfg->caps = (GRASCS_caps*)calloc(1,sizeof(GRASCS_caps))) == NULL) {
+ DBG("ASCS_init: Could not allocate memory for caps struc\n");
+ goto init_error1;
+ }
+
+ /* Create semaphores for blocking ASCS_TC/TM functions */
+ if(rtems_semaphore_create(rtems_build_name('A','S','C','0'),1,
+ (RTEMS_FIFO|RTEMS_BINARY_SEMAPHORE|
+ RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|
+ RTEMS_NO_PRIORITY_CEILING), 0,
+ &cfg->tcsem1) != RTEMS_SUCCESSFUL) {
+ DBG("ASCS_init: Failed to create semaphore ASC0\n");
+ goto init_error2;
+ }
+ if(rtems_semaphore_create(rtems_build_name('A','S','C','1'),1,
+ (RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|
+ RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|
+ RTEMS_NO_PRIORITY_CEILING), 0,
+ &cfg->tmsem1) != RTEMS_SUCCESSFUL) {
+ DBG("ASCS_init: Failed to create semaphore ASC1\n");
+ goto init_error2;
+ }
+ if(rtems_semaphore_create(rtems_build_name('A','S','C','2'),0,
+ (RTEMS_FIFO|RTEMS_BINARY_SEMAPHORE|
+ RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|
+ RTEMS_NO_PRIORITY_CEILING), 0,
+ &cfg->tcsem2) != RTEMS_SUCCESSFUL) {
+ DBG("ASCS_init: Failed to create semaphore ASC2\n");
+ goto init_error2;
+ }
+ if(rtems_semaphore_create(rtems_build_name('A','S','C','3'),0,
+ (RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|
+ RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|
+ RTEMS_NO_PRIORITY_CEILING), 0,
+ &cfg->tmsem2) != RTEMS_SUCCESSFUL) {
+ DBG("ASCS_init: Failed to create semaphore ASC3\n");
+ goto init_error2;
+ }
+
+ /* Set pointer to core registers */
+ if(ASCS_get_addr(&base, &irq) == -1)
+ goto init_error2;
+
+ cfg->regs = (GRASCS_regs*)base;
+
+ /* Read core capabilities */
+ tmp = cfg->regs->sts;
+ cfg->caps->dbits = ((tmp >> GRASCS_STS_DBITS_BITS) & 0x1F) + 1;
+ cfg->caps->nslaves = ((tmp >> GRASCS_STS_NSLAVES_BITS) & 0xF) + 1;
+ cfg->caps->tmconf = (tmp >> GRASCS_STS_TMCONF_BITS) & 0x1;
+ cfg->caps->usconf = (tmp >> GRASCS_STS_USCONF_BITS) & 0x1;
+
+ /* Reset and configure core */
+ cfg->running = 0;
+ cfg->regs->cmd |= GRASCS_CMD_RESET;
+ if((tmp = ASCS_get_sysfreq()) == -1)
+ goto init_error2;
+ cfg->caps->clkfreq = tmp;
+ while(ASCS_iface_status())
+ ;
+ cfg->regs->clk = ASCS_calc_clkreg(tmp, GRASCS_DEFAULT_ETRFREQ);
+ cfg->regs->cmd = GRASCS_CMD_US1C;
+ cfg->regs->cmd |= (tmp/1000 << GRASCS_CMD_US1_BITS) | GRASCS_CMD_US1C |
+ GRASCS_CMD_TCDONE | GRASCS_CMD_TMDONE;
+
+ /* Register interrupt routine */
+ set_vector(ASCS_irqhandler,irq+0x10,2);
+
+ return 0;
+
+ init_error2:
+ free(cfg->caps);
+ init_error1:
+ free(cfg);
+ return -1;
+}
+
+/* Function: ASCS_input_select
+ Arguments: slave: The number of the slave that is active,
+ numbered from 0-15
+ Return values: 0 if successful, -GRASCS_ERROR_CAPFAULT if slave value
+ is negative or too big, -GRASCS_ERROR_TRANSACTIVE if
+ a TM is active.
+ Description: Sets the slave_sel bits in the core's CMD register.
+ they are used to choose which slave the core listens
+ to when performing a TM. The bits can't be set
+ during a TM, and the function will in such a case fail.
+*/
+int ASCS_input_select(int slave) {
+
+ if((slave < 0) || (slave > cfg->caps->nslaves)) {
+ /* Slave number is negative or too big */
+ DBG("ASCS_input_select: Wrong slave number\n");
+ return -GRASCS_ERROR_CAPFAULT;
+ }
+
+ if(rtems_semaphore_obtain(cfg->tmsem1,RTEMS_NO_WAIT,RTEMS_NO_TIMEOUT) !=
+ RTEMS_SUCCESSFUL) {
+ /* Can't change active slave during a TM */
+ DBG("ASCS_input_select: Transaction active\n");
+ return -GRASCS_ERROR_TRANSACTIVE;
+ }
+
+ cfg->regs->cmd = ((cfg->regs->cmd &= ~GRASCS_CMD_SLAVESEL) |
+ (slave << GRASCS_CMD_SLAVESEL_BITS));
+
+ rtems_semaphore_release(cfg->tmsem1);
+ return 0;
+}
+
+/* Function: ASCS_etr_select
+ Arguments: src: The source of the ETR signal, valid values are
+ 0-GRASCS_MAX_TMS (0 = internal source, 1-GRASCS_MAX_TMS =
+ external time markers 1-GRASCS_MAX_TMS).
+ freq: ETR frequency in Hz. Valid values are
+ GRASCS_MIN_ETRFREQ-GRASCS_MAX_ETRFREQ
+ Return values: 0 if successful, -GRASCS_ERROR_CAPFAULT if src or freq values
+ are invalid, -GRASCS_ERROR_STARTSTOP if synchronization interface
+ isn't stopped.
+ Description: Changes the source for the ETR signal. The frequency of source signal
+ is assumed to be the same as the frequency of the freq input
+*/
+int ASCS_etr_select(int etr, int freq) {
+
+ if((etr < 0) || (etr > GRASCS_MAX_TMS) || ((cfg->caps->tmconf == 0) && (etr > 0)) ||
+ (freq < GRASCS_MIN_ETRFREQ) || (freq > GRASCS_MAX_ETRFREQ)) {
+ /* ETR source value or frequency is invalid */
+ DBG("ASCS_etr_select: Wrong etr src number or wrong frequency\n");
+ return -GRASCS_ERROR_CAPFAULT;
+ }
+
+ if(cfg->regs->sts & GRASCS_STS_ERUNNING) {
+ /* Synchronization interface is running */
+ DBG("ASCS_etr_select: Synch interface is running\n");
+ return -GRASCS_ERROR_STARTSTOP;
+ }
+
+ cfg->regs->clk = ASCS_calc_clkreg(cfg->caps->clkfreq,freq);
+ cfg->regs->cmd = ((cfg->regs->cmd &= ~GRASCS_CMD_ETRCTRL) |
+ (etr << GRASCS_CMD_ETRCTRL_BITS));
+
+ return 0;
+}
+
+/* Function: ASCS_start
+ Arguments: -
+ Return values: -
+ Description: Enables the serial interface.
+*/
+void ASCS_start(void) {
+
+ /* Set register and internal status to running */
+ cfg->regs->cmd |= GRASCS_CMD_STARTSTOP;
+ cfg->running = 1;
+}
+
+/* Function: ASCS_stop
+ Arguments: -
+ Return values: -
+ Description: Disables the serial interface. This function will
+ block until possible calls to TC_send(_block) and
+ TM_recv(_block) has returned in order to be sure
+ that started transactions will be performed.
+*/
+void ASCS_stop(void) {
+
+ /* Set internal status to stopped */
+ cfg->running = 0;
+
+ /* Obtain semaphores to avoid possible situation where a
+ TC_send(_block) or TM_recv(_block) is aborted and driver is
+ waiting forever for an interrupt */
+ rtems_semaphore_obtain(cfg->tcsem1,RTEMS_WAIT,RTEMS_NO_TIMEOUT);
+ rtems_semaphore_obtain(cfg->tmsem1,RTEMS_WAIT,RTEMS_NO_TIMEOUT);
+
+ /* Change actual register value */
+ cfg->regs->cmd &= ~GRASCS_CMD_STARTSTOP;
+
+ /* Release the semaphores */
+ rtems_semaphore_release(cfg->tcsem1);
+ rtems_semaphore_release(cfg->tmsem1);
+}
+
+/* Function: ASCS_iface_status
+ Arguments: -
+ Return values: 0 if both serial interface and synch interface is stopped,
+ 1 if serial interface is running buth synch interface is
+ stopped, 2 if serial interface is stopped but synch interface
+ is running, 3 if both serial and synch interface is running
+ Description: Reads the core's STS register and reports the status of the
+ serial and synch interfaces
+*/
+int ASCS_iface_status(void) {
+
+ return ((cfg->regs->sts & 0x3) & (0x2 | cfg->running));
+}
+
+/* Function: ASCS_TC_send
+ Arguments: word: Pointer to a word that should be sent
+ Return values: 0 on success
+ -GRASCS_ERROR_STARTSTOP if serial interface is stopped,
+ -GRASCS_ERROR_TRANSACTIVE if another TC is in progress.
+ Description: Start a TC and sends the data that word points to.
+*/
+int ASCS_TC_send(int *word) {
+
+ int retval;
+
+ if(rtems_semaphore_obtain(cfg->tcsem1,RTEMS_NO_WAIT,RTEMS_NO_TIMEOUT) !=
+ RTEMS_SUCCESSFUL) {
+ /* Can't start a TC_send if another TC_send of TC_send_block is
+ in progress */
+ DBG("ASCS_TC_send: Could not obtain semaphore, transcation probably in progress\n");
+ return -GRASCS_ERROR_TRANSACTIVE;
+ }
+
+ if(!cfg->running) {
+ /* Can't start a TC if serial interface isn't started */
+ DBG("ASCS_TC_send: Serial interface is not started\n");
+ retval = -GRASCS_ERROR_STARTSTOP;
+ }
+ else {
+ /* Start the transfer */
+ cfg->tcwords = 1;
+ if(cfg->caps->dbits == 8)
+ cfg->regs->tcd = *((unsigned char*)word);
+ else if(cfg->caps->dbits == 16)
+ cfg->regs->tcd = *((unsigned short int*)((int)word & ~1));
+ else
+ cfg->regs->tcd = *((unsigned int*)((int)word & ~3));
+
+ /* Wait until transfer is complete */
+ rtems_semaphore_obtain(cfg->tcsem2,RTEMS_WAIT,RTEMS_NO_TIMEOUT);
+ retval = 0;
+ }
+
+ rtems_semaphore_release(cfg->tcsem1);
+
+ return retval;
+}
+
+/* Function: ASCS_TC_send_block
+ Arguments: block: Pointer to the start of a datablock that
+ should be sent.
+ ntrans: Number of transfers needed to transfer
+ the block.
+ Return values: 0 if successfull, -GRASCS_ERROR_STARTSTOP if TC
+ couldn't be started because serial interface is
+ stopped, -GRASCS_ERROR_TRANSACTIVE if TC couldn't
+ be started because another TC isn't done yet.
+ Description: Starts ntrans TCs and sends the data that starts at the
+ address that block points to. The size of each
+ transaction will vary depending on whether the core is
+ configured for 8, 16, or 32 bits data transfers.
+*/
+int ASCS_TC_send_block(int *block, int ntrans) {
+
+ int retval;
+
+ if(rtems_semaphore_obtain(cfg->tcsem1,RTEMS_NO_WAIT,RTEMS_NO_TIMEOUT) !=
+ RTEMS_SUCCESSFUL) {
+ /* Can't start a TC_send_block if another TC_send of TC_send_block is
+ in progress */
+ DBG("ASCS_TC_send_block: Could not obtain semaphore, transcation probably in progress\n");
+ return -GRASCS_ERROR_TRANSACTIVE;
+ }
+
+ if(!cfg->running) {
+ /* Can't start a TC if serial interface isn't started */
+ DBG("ASCS_TC_send_block: Serial interface is not started\n");
+ retval = -GRASCS_ERROR_STARTSTOP;
+ }
+ else {
+ /* Start the first transfer */
+ cfg->tcwords = ntrans;
+ if(cfg->caps->dbits == 8) {
+ cfg->tcptr = (int)block;
+ cfg->regs->tcd = *((unsigned char*)cfg->tcptr);
+ }
+ else if(cfg->caps->dbits == 16) {
+ cfg->tcptr = (int)block & ~1;
+ cfg->regs->tcd = *((unsigned short int*)cfg->tcptr);
+ }
+ else {
+ cfg->tcptr = (int)block & ~3;
+ cfg->regs->tcd = *((unsigned int*)cfg->tcptr);
+ }
+
+ /* Wait until all transfers are complete */
+ rtems_semaphore_obtain(cfg->tcsem2,RTEMS_WAIT,RTEMS_NO_TIMEOUT);
+ retval = 0;
+ }
+
+ rtems_semaphore_release(cfg->tcsem1);
+
+ return retval;
+}
+
+/* Function: ASCS_TC_sync_start
+ Arguments: -
+ Return values: -
+ Description: Starts synchronization interface. Might
+ be delayed if a TM is in progress. SW can poll
+ ASCS_iface_status() to find out when synch interface is
+ started. First ETR pulse can be delay up to one ETR
+ period depending on the source of the ETR and
+ activity on the TM line.
+*/
+void ASCS_TC_sync_start(void) {
+
+ cfg->regs->cmd |= GRASCS_CMD_ESTARTSTOP;
+}
+
+/* Function: ASCS_TC_sync_stop
+ Arguments: -
+ Return values: -
+ Description: Stops the synchronization interface. Might
+ be delayed for 1 us if a ETR pulse is being generated. SW
+ can determine when synch interface has stopped by polling
+ ASCS_iface_status().
+*/
+void ASCS_TC_sync_stop(void) {
+
+ cfg->regs->cmd &= ~GRASCS_CMD_ESTARTSTOP;
+}
+
+/* Function: ASCS_TM_recv
+ Arguments: word: Pointer to where the received word should be
+ placed
+ Return values: 0 if successful, -GRASCS_ERROR_STARTSTOP if serial
+ interface isn't started, -GRASCS_ERROR_TRANSACTIVE
+ if another TM is in progress
+ Description: Starts a TM and stores the incoming data in word.
+*/
+int ASCS_TM_recv(int *word) {
+
+ int retval;
+
+ if(rtems_semaphore_obtain(cfg->tmsem1,RTEMS_NO_WAIT,RTEMS_NO_TIMEOUT) !=
+ RTEMS_SUCCESSFUL) {
+ /* Can't start a TM_recv if another TM_recv of TM_recv_block is
+ in progress */
+ DBG("ASCS_TM_recv: Could not obtain semaphore, transaction probably in progress\n");
+ return -GRASCS_ERROR_TRANSACTIVE;
+ }
+
+ if(!cfg->running) {
+ /* Can't start a TM if serial interface isn't started */
+ DBG("ASCS_TM_recv: Serial interface is not started\n");
+ retval = -GRASCS_ERROR_STARTSTOP;
+ }
+ else {
+ /* Start transfer */
+ cfg->tmwords = 1;
+ cfg->tmptr = (int)word;
+ cfg->regs->cmd |= GRASCS_CMD_SENDTM;
+
+ /* Wait until transfer finishes */
+ rtems_semaphore_obtain(cfg->tmsem2,RTEMS_WAIT,RTEMS_NO_TIMEOUT);
+ retval = 0;
+ }
+
+ rtems_semaphore_release(cfg->tmsem1);
+
+ return retval;
+}
+
+/* Function: ASCS_TM_recv_block
+ Arguments: block: Pointer to where the received datablock
+ should be stored.
+ ntrans: Number of transfers needed to transfer
+ the block.
+ Return values: 0 if successful, -GRASCS_ERROR_STARTSTOP if serial
+ interface isn't started, -GRASCS_ERROR_TRANSACTIVE if
+ a performed TM hasn't been processed yet
+ Description: Starts ntrans TMs and stores the data at the address
+ that block points to. The size of each transaction
+ will vary depending on whether the core is
+ configured for 8, 16, or 32 bits data transfers.
+*/
+int ASCS_TM_recv_block(int *block, int ntrans) {
+
+ int retval;
+
+ if(rtems_semaphore_obtain(cfg->tmsem1,RTEMS_NO_WAIT,RTEMS_NO_TIMEOUT) !=
+ RTEMS_SUCCESSFUL) {
+ /* Can't start a TM_recv_block if another TM_recv of TM_recv_block is
+ in progress */
+ DBG("ASCS_TM_recv_block: Could not obtain semaphore, transaction probably in progress\n");
+ return -GRASCS_ERROR_TRANSACTIVE;
+ }
+
+ if(!cfg->running) {
+ /* Can't start a TM if serial interface isn't started */
+ DBG("ASCS_TM_recv_block: Serial interface is not started\n");
+ retval = -GRASCS_ERROR_STARTSTOP;
+ }
+ else {
+ /* Start transfer */
+ cfg->tmwords = ntrans;
+ cfg->tmptr = (int)block;
+ cfg->regs->cmd |= GRASCS_CMD_SENDTM;
+
+ /* Wait until transfer finishes */
+ rtems_semaphore_obtain(cfg->tmsem2,RTEMS_WAIT,RTEMS_NO_TIMEOUT);
+ retval = 0;
+ }
+
+ rtems_semaphore_release(cfg->tmsem1);
+
+ return retval;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/bspgetworkarea.c b/c/src/lib/libbsp/sparc/shared/bspgetworkarea.c
index a9fe1603a1..5be52549f2 100644
--- a/c/src/lib/libbsp/sparc/shared/bspgetworkarea.c
+++ b/c/src/lib/libbsp/sparc/shared/bspgetworkarea.c
@@ -21,6 +21,10 @@
/* Tells us where to put the workspace in case remote debugger is present. */
extern uint32_t rdb_start;
+extern int _end;
+
+/* Must be aligned to 8, _end is aligned to 8 */
+unsigned int early_mem = (unsigned int)&_end;
/*
* This method returns the base address and size of the area which
@@ -37,8 +41,11 @@ void bsp_get_work_area(
/* must be identical to STACK_SIZE in start.S */
#define STACK_SIZE (16 * 1024)
- *work_area_start = &end;
- *work_area_size = (void *)rdb_start - (void *)&end - STACK_SIZE;
+ /* Early dynamic memory allocator is placed just above _end */
+ *work_area_start = (void *)early_mem;
+ *work_area_size = (void *)rdb_start - (void *)early_mem - STACK_SIZE;
+ early_mem = ~0; /* Signal bsp_early_malloc not to be used anymore */
+
*heap_start = BSP_BOOTCARD_HEAP_USES_WORK_AREA;
*heap_size = BSP_BOOTCARD_HEAP_SIZE_DEFAULT;
diff --git a/c/src/lib/libbsp/sparc/shared/can/canmux.c b/c/src/lib/libbsp/sparc/shared/can/canmux.c
new file mode 100644
index 0000000000..2f990fe71e
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/can/canmux.c
@@ -0,0 +1,202 @@
+/*
+ * CAN_MUX driver
+ *
+ * --------------------------------------------------------------------------
+ * -- This file is a part of GAISLER RESEARCH source code.
+ * -- Copyright (C) 2008, Gaisler Research AB - all rights reserved.
+ * --
+ * -- ANY USE OR REDISTRIBUTION IN PART OR IN WHOLE MUST BE HANDLED IN
+ * -- ACCORDANCE WITH THE GAISLER LICENSE AGREEMENT AND MUST BE APPROVED
+ * -- IN ADVANCE IN WRITING.
+ * --
+ * -- BY DEFAULT, DISTRIBUTION OR DISCLOSURE IS NOT PERMITTED.
+ * --------------------------------------------------------------------------
+ *
+ */
+
+#include <rtems/libio.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <bsp.h>
+#include <rtems/bspIo.h> /* printk */
+
+#include <canmux.h>
+#include <ambapp.h>
+
+#ifndef GAISLER_CANMUX
+#define GAISLER_CANMUX 0x081
+#endif
+
+#if !defined(CANMUX_DEVNAME)
+ #undef CANMUX_DEVNAME
+ #define CANMUX_DEVNAME "/dev/canmux"
+#endif
+
+/* Enable debug output? */
+/* #define DEBUG */
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+#define BUSA_SELECT (1 << 0)
+#define BUSB_SELECT (1 << 1)
+
+struct canmux_priv {
+ volatile unsigned int *muxreg;
+ rtems_id devsem;
+ int open;
+};
+
+static struct canmux_priv *priv;
+
+static rtems_device_driver canmux_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver canmux_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver canmux_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver canmux_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver canmux_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver canmux_initialize(rtems_device_major_number major, rtems_device_minor_number unused, void *arg);
+
+
+static rtems_device_driver canmux_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t*)arg;
+
+ DBG("CAN_MUX: IOCTL %d\n\r", ioarg->command);
+
+ ioarg->ioctl_return = 0;
+ switch(ioarg->command) {
+ case CANMUX_IOC_BUSA_SATCAN: *priv->muxreg &= ~BUSA_SELECT; break;
+ case CANMUX_IOC_BUSA_OCCAN1: *priv->muxreg |= BUSA_SELECT; break;
+ case CANMUX_IOC_BUSB_SATCAN: *priv->muxreg &= ~BUSB_SELECT; break;
+ case CANMUX_IOC_BUSB_OCCAN2: *priv->muxreg |= BUSB_SELECT; break;
+ default: return RTEMS_NOT_DEFINED;
+ }
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver canmux_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ rtems_libio_rw_args_t *rw_args=(rtems_libio_rw_args_t*)arg;
+
+ rw_args->bytes_moved = 0;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver canmux_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t*)arg;
+
+ rw_args->bytes_moved = 0;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+
+static rtems_device_driver canmux_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ DBG("CAN_MUX: Closing %d\n\r",minor);
+
+ priv->open = 0;
+ return RTEMS_SUCCESSFUL;
+}
+
+
+static rtems_device_driver canmux_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ DBG("CAN_MUX: Opening %d\n\r",minor);
+
+ rtems_semaphore_obtain(priv->devsem,RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+ if (priv->open) {
+ rtems_semaphore_release(priv->devsem);
+ return RTEMS_RESOURCE_IN_USE; /* EBUSY */
+ }
+ priv->open = 1;
+ rtems_semaphore_release(priv->devsem);
+
+ DBG("CAN_MUX: Opening %d success\n\r",minor);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver canmux_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ struct ambapp_apb_info d;
+ char fs_name[20];
+ rtems_status_code status;
+
+ DBG("CAN_MUX: Initialize..\n\r");
+
+ strcpy(fs_name, CANMUX_DEVNAME);
+
+ /* Find core and initialize register pointer */
+ if (!ambapp_find_apbslv(&ambapp_plb, VENDOR_GAISLER, GAISLER_CANMUX, &d)) {
+ printk("CAN_MUX: Failed to find CAN_MUX core\n\r");
+ return -1;
+ }
+
+ status = rtems_io_register_name(fs_name, major, minor);
+ if (RTEMS_SUCCESSFUL != status)
+ rtems_fatal_error_occurred(status);
+
+ /* Create private structure */
+ if ((priv = malloc(sizeof(struct canmux_priv))) == NULL) {
+ printk("CAN_MUX driver could not allocate memory for priv structure\n\r");
+ return -1;
+ }
+
+ priv->muxreg = (unsigned int*)d.start;
+
+ status = rtems_semaphore_create(
+ rtems_build_name('M', 'd', 'v', '0'),
+ 1,
+ RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | \
+ RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &priv->devsem);
+ if (status != RTEMS_SUCCESSFUL) {
+ printk("CAN_MUX: Failed to create dev semaphore (%d)\n\r", status);
+ free(priv);
+ return RTEMS_UNSATISFIED;
+ }
+
+ priv->open = 0;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+
+#define CANMUX_DRIVER_TABLE_ENTRY { canmux_initialize, canmux_open, canmux_close, canmux_read, canmux_write, canmux_ioctl }
+
+static rtems_driver_address_table canmux_driver = CANMUX_DRIVER_TABLE_ENTRY;
+
+int canmux_register(void)
+{
+ rtems_status_code r;
+ rtems_device_major_number m;
+
+ DBG("CAN_MUX: canmux_register called\n\r");
+
+ if ((r = rtems_io_register_driver(0, &canmux_driver, &m)) == RTEMS_SUCCESSFUL) {
+ DBG("CAN_MUX driver successfully registered, major: %d\n\r", m);
+ } else {
+ switch(r) {
+ case RTEMS_TOO_MANY:
+ printk("CAN_MUX rtems_io_register_driver failed: RTEMS_TOO_MANY\n\r"); break;
+ case RTEMS_INVALID_NUMBER:
+ printk("CAN_MUX rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n\r"); break;
+ case RTEMS_RESOURCE_IN_USE:
+ printk("CAN_MUX rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n\r"); break;
+ default:
+ printk("CAN_MUX rtems_io_register_driver failed\n\r");
+ }
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/can/grcan.c b/c/src/lib/libbsp/sparc/shared/can/grcan.c
index c176490c68..251519ac86 100644
--- a/c/src/lib/libbsp/sparc/shared/can/grcan.c
+++ b/c/src/lib/libbsp/sparc/shared/can/grcan.c
@@ -1,13 +1,15 @@
/*
* GRCAN driver
*
- * COPYRIGHT (c) 2007.
- * Gaisler Research.
+ * COPYRIGHT (c) 2008.
+ * Aeroflex Gaisler.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
*
+ * 2008-12-10, Daniel Hellstrom <daniel@gaisler.com>
+ * Converted driver to support driver manager
*
* 2007-06-13, Daniel Hellstrom <daniel@gaisler.com>
* New driver in sparc shared directory. Parts taken
@@ -25,6 +27,8 @@
#include <rtems/bspIo.h>
#include <grcan.h>
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
#include <ambapp.h>
#define WRAP_AROUND_TX_MSGS 1
@@ -32,14 +36,17 @@
#define GRCAN_MSG_SIZE sizeof(struct grcan_msg)
#define BLOCK_SIZE (16*4)
+/* grcan needs to have it buffers aligned to 1k boundaries */
+#define BUFFER_ALIGNMENT_NEEDS 1024
+
/* Default Maximium buffer size for statically allocated buffers */
#ifndef TX_BUF_SIZE
-#define TX_BUF_SIZE (BLOCK_SIZE*16)
+ #define TX_BUF_SIZE (BLOCK_SIZE*16)
#endif
/* Make receiver buffers bigger than transmitt */
#ifndef RX_BUF_SIZE
-#define RX_BUF_SIZE ((3*BLOCK_SIZE)*16)
+ #define RX_BUF_SIZE ((3*BLOCK_SIZE)*16)
#endif
#ifndef IRQ_GLOBAL_PREPARE
@@ -66,35 +73,13 @@
#define IRQ_MASK(irqno)
#endif
-#ifndef GRCAN_PREFIX
- #define GRCAN_PREFIX(name) grcan##name
-#endif
-
-#ifndef MEMAREA_TO_HW
- #define MEMAREA_TO_HW(x) (x)
-#endif
-
-/* default name to /dev/grcan0 */
-#if !defined(GRCAN_DEVNAME) || !defined(GRCAN_DEVNAME_NO)
- #undef GRCAN_DEVNAME
- #undef GRCAN_DEVNAME_NO
- #define GRCAN_DEVNAME "/dev/grcan0"
- #define GRCAN_DEVNAME_NO(devstr,no) ((devstr)[10]='0'+(no))
-#endif
-
-#ifndef GRCAN_REG_INT
- #define GRCAN_REG_INT(handler,irqno,arg) set_vector(handler,irqno+0x10,1)
- #undef GRCAN_DEFINE_INTHANDLER
- #define GRCAN_DEFINE_INTHANDLER
-#endif
-
#ifndef GRCAN_DEFAULT_BAUD
- /* default to 500kbits/s */
- #define GRCAN_DEFAULT_BAUD 500000
+ /* default to 500kbits/s */
+ #define GRCAN_DEFAULT_BAUD 500000
#endif
#ifndef GRCAN_SAMPLING_POINT
-#define GRCAN_SAMPLING_POINT 80
+ #define GRCAN_SAMPLING_POINT 80
#endif
/* Uncomment for debug output */
@@ -112,63 +97,9 @@
/*********************************************************/
-/* grcan needs to have it buffers aligned to 1k boundaries */
-#define BUFFER_ALIGNMENT_NEEDS 1024
-
-#ifdef STATICALLY_ALLOCATED_TX_BUFFER
-static unsigned int tx_circbuf[GRCAN_MAX_CORES][TX_BUF_SIZE]
- __attribute__ ((aligned(BUFFER_ALIGNMENT_NEEDS)));
-#define STATIC_TX_BUF_SIZE TX_BUF_SIZE
-#define STATIC_TX_BUF_ADDR(core) (&tx_circbuf[(core)][0])
-#endif
-
-#ifdef STATICALLY_ALLOCATED_RX_BUFFER
-static unsigned int rx_circbuf[GRCAN_MAX_CORES][RX_BUF_SIZE]
- __attribute__ ((aligned(BUFFER_ALIGNMENT_NEEDS)));
-#define STATIC_RX_BUF_SIZE RX_BUF_SIZE
-#define STATIC_RX_BUF_ADDR(core) (&rx_circbuf[(core)][0])
-#endif
-
-/*
- * If USE_AT697_RAM is defined the RAM on the AT697 board will be used for DMA buffers (but rx message queue is always in AT697 ram).
- * USE_AT697_DMA specifies whether the messages will be fetched using DMA or PIO.
- *
- * RASTA_PCI_BASE is the base address of the GRPCI AHB slave
- *
- * GRCAN_BUF_SIZE must be set to the size (in bytes) of the GRCAN DMA buffers.
- *
- * RX_QUEUE_SIZE defines the number of messages that fits in the RX message queue. On RX interrupts the messages in the DMA buffer
- * are copied into the message queue (using dma if the rx buf is not in the AT697 ram).
- */
-
-/*#define USE_AT697_RAM 1 */
-#define USE_AT697_DMA 1
-#define RASTA_PCI_BASE 0xe0000000
-#define GRCAN_BUF_SIZE 4096
-#define RX_QUEUE_SIZE 1024
-
-#define INDEX(x) ( x&(RX_QUEUE_SIZE-1) )
-
-/* pa(x)
- *
- * x: address in AT697 address space
- *
- * returns the address in the RASTA address space that can be used to access x with dma.
- *
-*/
-#ifdef USE_AT697_RAM
-static inline unsigned int pa(unsigned int addr) {
- return ((addr & 0x0fffffff) | RASTA_PCI_BASE);
-}
-#else
-static inline unsigned int pa(unsigned int addr) {
- return ((addr & 0x0fffffff) | 0x40000000);
-}
-#endif
-
struct grcan_msg {
- unsigned int head[2];
- unsigned char data[8];
+ unsigned int head[2];
+ unsigned char data[8];
};
struct grcan_config {
@@ -179,43 +110,41 @@ struct grcan_config {
};
struct grcan_priv {
- unsigned int baseaddr, ram_base;
- struct grcan_regs *regs;
- int irq;
- int minor;
- int open;
- int started;
- unsigned int channel;
- int flushing;
- unsigned int corefreq_hz;
-
- /* Circular DMA buffers */
- void *_rx;
- void *_tx;
- struct grcan_msg *rx;
- struct grcan_msg *tx;
- unsigned int rxbuf_size; /* requested RX buf size in bytes */
- unsigned int txbuf_size; /* requested TX buf size in bytes */
-
- int txblock, rxblock;
- int txcomplete, rxcomplete;
- int txerror, rxerror;
-
- struct grcan_filter sfilter;
- struct grcan_filter afilter;
- int config_changed; /* 0=no changes, 1=changes ==> a Core reset is needed */
- struct grcan_config config;
- struct grcan_stats stats;
-
- rtems_id rx_sem, tx_sem, txempty_sem, dev_sem;
+ struct drvmgr_dev *dev; /* Driver manager device */
+ char devName[32]; /* Device Name */
+ unsigned int baseaddr, ram_base;
+ struct grcan_regs *regs;
+ int irq;
+ int minor;
+ int open;
+ int started;
+ unsigned int channel;
+ int flushing;
+ unsigned int corefreq_hz;
+
+ /* Circular DMA buffers */
+ void *_rx;
+ void *_tx;
+ void *txbuf_adr;
+ void *rxbuf_adr;
+ struct grcan_msg *rx;
+ struct grcan_msg *tx;
+ unsigned int rxbuf_size; /* requested RX buf size in bytes */
+ unsigned int txbuf_size; /* requested TX buf size in bytes */
+
+ int txblock, rxblock;
+ int txcomplete, rxcomplete;
+ int txerror, rxerror;
+
+ struct grcan_filter sfilter;
+ struct grcan_filter afilter;
+ int config_changed; /* 0=no changes, 1=changes ==> a Core reset is needed */
+ struct grcan_config config;
+ struct grcan_stats stats;
+
+ rtems_id rx_sem, tx_sem, txempty_sem, dev_sem;
};
-static int grcan_core_cnt;
-struct grcan_priv *grcans;
-static amba_confarea_type *amba_bus;
-struct grcan_device_info *grcan_cores;
-static int grcan_core_cnt;
-
static rtems_device_driver grcan_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
static rtems_device_driver grcan_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
static rtems_device_driver grcan_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
@@ -225,6 +154,8 @@ static rtems_device_driver grcan_ioctl(rtems_device_major_number major, rtems_de
#define GRCAN_DRIVER_TABLE_ENTRY { grcan_initialize, grcan_open, grcan_close, grcan_read, grcan_write, grcan_ioctl }
+static void __inline__ grcan_hw_reset(struct grcan_regs *regs);
+
static unsigned int grcan_hw_read_try(
struct grcan_priv *pDev,
struct grcan_regs *regs,
@@ -249,11 +180,7 @@ static void grcan_hw_sync(
struct grcan_regs *regs,
struct grcan_filter *sfilter);
-#ifndef GRCAN_DONT_DECLARE_IRQ_HANDLER
-static rtems_isr grcan_interrupt_handler(rtems_vector_number v);
-#endif
-
-static void grcan_interrupt(struct grcan_priv *pDev);
+static void grcan_interrupt(void *arg);
#ifdef GRCAN_REG_BYPASS_CACHE
#define READ_REG(address) _grcan_read_nocache((unsigned int)(address))
@@ -266,12 +193,12 @@ static void grcan_interrupt(struct grcan_priv *pDev);
#define READ_DMA_BYTE(address) _grcan_read_nocache_byte((unsigned int)(address))
static unsigned char __inline__ _grcan_read_nocache_byte(unsigned int address)
{
- unsigned char tmp;
- asm(" lduba [%1]1, %0 "
- : "=r"(tmp)
- : "r"(address)
- );
- return tmp;
+ unsigned char tmp;
+ __asm__(" lduba [%1]1, %0 "
+ : "=r"(tmp)
+ : "r"(address)
+ );
+ return tmp;
}
#else
#define READ_DMA_WORD(address) (*(volatile unsigned int *)(address))
@@ -281,17 +208,228 @@ static unsigned char __inline__ _grcan_read_nocache_byte(unsigned int address)
#if defined(GRCAN_REG_BYPASS_CACHE) || defined(GRCAN_DMA_BYPASS_CACHE)
static unsigned int __inline__ _grcan_read_nocache(unsigned int address)
{
- unsigned int tmp;
- asm(" lda [%1]1, %0 "
- : "=r"(tmp)
- : "r"(address)
- );
- return tmp;
+ unsigned int tmp;
+ __asm__(" lda [%1]1, %0 "
+ : "=r"(tmp)
+ : "r"(address)
+ );
+ return tmp;
}
#endif
static rtems_driver_address_table grcan_driver = GRCAN_DRIVER_TABLE_ENTRY;
+static int grcan_driver_io_registered = 0;
+static rtems_device_major_number grcan_driver_io_major = 0;
+
+/******************* Driver manager interface ***********************/
+
+/* Driver prototypes */
+int grcan_register_io(rtems_device_major_number *m);
+int grcan_device_init(struct grcan_priv *pDev);
+
+int grcan_init2(struct drvmgr_dev *dev);
+int grcan_init3(struct drvmgr_dev *dev);
+
+struct drvmgr_drv_ops grcan_ops =
+{
+ .init = {NULL, grcan_init2, grcan_init3, NULL},
+ .remove = NULL,
+ .info = NULL
+};
+
+struct amba_dev_id grcan_ids[] =
+{
+ {VENDOR_GAISLER, GAISLER_GRCAN},
+ {VENDOR_GAISLER, GAISLER_GRHCAN},
+ {0, 0} /* Mark end of table */
+};
+
+struct amba_drv_info grcan_drv_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_AMBAPP_GAISLER_GRCAN_ID, /* Driver ID */
+ "GRCAN_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */
+ &grcan_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ 0,
+ },
+ &grcan_ids[0]
+};
+
+void grcan_register_drv (void)
+{
+ DBG("Registering GRCAN driver\n");
+ drvmgr_drv_register(&grcan_drv_info.general);
+}
+
+int grcan_init2(struct drvmgr_dev *dev)
+{
+ struct grcan_priv *priv;
+
+ DBG("GRCAN[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
+ priv = dev->priv = malloc(sizeof(struct grcan_priv));
+ if ( !priv )
+ return DRVMGR_NOMEM;
+ memset(priv, 0, sizeof(*priv));
+ priv->dev = dev;
+
+ /* This core will not find other cores, so we wait for init2() */
+
+ return DRVMGR_OK;
+}
+
+int grcan_init3(struct drvmgr_dev *dev)
+{
+ struct grcan_priv *priv;
+ char prefix[32];
+ rtems_status_code status;
+
+ priv = dev->priv;
+
+ /* Do initialization */
+
+ if ( grcan_driver_io_registered == 0) {
+ /* Register the I/O driver only once for all cores */
+ if ( grcan_register_io(&grcan_driver_io_major) ) {
+ /* Failed to register I/O driver */
+ dev->priv = NULL;
+ return DRVMGR_FAIL;
+ }
+
+ grcan_driver_io_registered = 1;
+ }
+
+ /* I/O system registered and initialized
+ * Now we take care of device initialization.
+ */
+
+ if ( grcan_device_init(priv) ) {
+ return DRVMGR_FAIL;
+ }
+
+ /* Get Filesystem name prefix */
+ prefix[0] = '\0';
+ if ( drvmgr_get_dev_prefix(dev, prefix) ) {
+ /* Failed to get prefix, make sure of a unique FS name
+ * by using the driver minor.
+ */
+ sprintf(priv->devName, "/dev/grcan%d", dev->minor_drv);
+ } else {
+ /* Got special prefix, this means we have a bus prefix
+ * And we should use our "bus minor"
+ */
+ sprintf(priv->devName, "/dev/%sgrcan%d", prefix, dev->minor_bus);
+ }
+
+ /* Register Device */
+ status = rtems_io_register_name(priv->devName, grcan_driver_io_major, dev->minor_drv);
+ if (status != RTEMS_SUCCESSFUL) {
+ return DRVMGR_FAIL;
+ }
+
+ return DRVMGR_OK;
+}
+
+/******************* Driver Implementation ***********************/
+
+int grcan_register_io(rtems_device_major_number *m)
+{
+ rtems_status_code r;
+
+ if ((r = rtems_io_register_driver(0, &grcan_driver, m)) == RTEMS_SUCCESSFUL) {
+ DBG("GRCAN driver successfully registered, major: %d\n", *m);
+ } else {
+ switch(r) {
+ case RTEMS_TOO_MANY:
+ printk("GRCAN rtems_io_register_driver failed: RTEMS_TOO_MANY\n");
+ return -1;
+ case RTEMS_INVALID_NUMBER:
+ printk("GRCAN rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n");
+ return -1;
+ case RTEMS_RESOURCE_IN_USE:
+ printk("GRCAN rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n");
+ return -1;
+ default:
+ printk("GRCAN rtems_io_register_driver failed\n");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int grcan_device_init(struct grcan_priv *pDev)
+{
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
+
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)pDev->dev->businfo;
+ if ( ambadev == NULL ) {
+ return -1;
+ }
+ pnpinfo = &ambadev->info;
+ pDev->irq = pnpinfo->irq;
+ pDev->regs = (struct grcan_regs *)pnpinfo->apb_slv->start;
+ pDev->minor = pDev->dev->minor_drv;
+
+ /* Get frequency in Hz */
+ if ( drvmgr_freq_get(pDev->dev, DEV_APB_SLV, &pDev->corefreq_hz) ) {
+ return -1;
+ }
+
+ DBG("GRCAN frequency: %d Hz\n", pDev->corefreq_hz);
+
+ /* Reset Hardware before attaching IRQ handler */
+ grcan_hw_reset(pDev->regs);
+
+ /* RX Semaphore created with count = 0 */
+ if ( rtems_semaphore_create(rtems_build_name('G', 'C', 'R', '0' + pDev->minor),
+ 0,
+ RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|\
+ RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &pDev->rx_sem) != RTEMS_SUCCESSFUL ) {
+ return RTEMS_INTERNAL_ERROR;
+ }
+
+ /* TX Semaphore created with count = 0 */
+ if ( rtems_semaphore_create(rtems_build_name('G', 'C', 'T', '0' + pDev->minor),
+ 0,
+ RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|\
+ RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &pDev->tx_sem) != RTEMS_SUCCESSFUL ) {
+ return RTEMS_INTERNAL_ERROR;
+ }
+
+ /* TX Empty Semaphore created with count = 0 */
+ if ( rtems_semaphore_create(rtems_build_name('G', 'C', 'E', '0' + pDev->minor),
+ 0,
+ RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|\
+ RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &pDev->txempty_sem) != RTEMS_SUCCESSFUL ) {
+ return RTEMS_INTERNAL_ERROR;
+ }
+
+ /* Device Semaphore created with count = 1 */
+ if ( rtems_semaphore_create(rtems_build_name('G', 'C', 'A', '0' + pDev->minor),
+ 1,
+ RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|\
+ RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &pDev->dev_sem) != RTEMS_SUCCESSFUL ) {
+ return RTEMS_INTERNAL_ERROR;
+ }
+
+ return 0;
+}
static void __inline__ grcan_hw_reset(struct grcan_regs *regs)
{
@@ -318,11 +456,13 @@ static rtems_device_driver grcan_start(struct grcan_priv *pDev)
}
/* Setup receiver */
- pDev->regs->rx0addr = MEMAREA_TO_HW((unsigned int)pDev->rx);
+ drvmgr_translate(pDev->dev, 0, 0, (void *)pDev->rx, (void **)&pDev->regs->rx0addr);
+ /*pDev->regs->rx0addr = MEMAREA_TO_HW((unsigned int)pDev->rx);*/
pDev->regs->rx0size = pDev->rxbuf_size;
/* Setup Transmitter */
- pDev->regs->tx0addr = MEMAREA_TO_HW((unsigned int)pDev->tx);
+ drvmgr_translate(pDev->dev, 0, 0, (void *)pDev->tx, (void **)&pDev->regs->tx0addr);
+ /*pDev->regs->tx0addr = MEMAREA_TO_HW((unsigned int)pDev->tx);*/
pDev->regs->tx0size = pDev->txbuf_size;
/* Setup acceptance filters */
@@ -869,7 +1009,7 @@ static int grcan_wait_txspace(
IRQ_GLOBAL_DISABLE(oldLevel);
- /*pDev->regs->tx0ctrl = GRCAN_TXCTRL_ENABLE;*/
+ pDev->regs->tx0ctrl = GRCAN_TXCTRL_ENABLE;
size = READ_REG(&pDev->regs->tx0size);
wp = READ_REG(&pDev->regs->tx0wr);
@@ -966,847 +1106,663 @@ static int grcan_tx_flush(struct grcan_priv *pDev)
static int grcan_alloc_buffers(struct grcan_priv *pDev, int rx, int tx)
{
- FUNCDBG();
-
- if ( tx ) {
-#ifdef STATIC_TX_BUF_ADDR
- pDev->_tx = STATIC_TX_BUF_ADDR(pDev->minor);
- if ( pDev->txbuf_size > STATIC_TX_BUF_SIZE ){
- pDev->txbuf_size = STATIC_TX_BUF_SIZE;
- return -1;
- }
- /* Assume aligned buffer */
- pDev->tx = (struct grcan_msg *)pDev->_tx;
-#else
- pDev->_tx = malloc(pDev->txbuf_size + BUFFER_ALIGNMENT_NEEDS);
- if ( !pDev->_tx )
- return -1;
+ FUNCDBG();
+
+ if ( tx ) {
+ if ( pDev->txbuf_adr ) {
+ /* User defined address */
+ pDev->_tx = pDev->txbuf_adr;
+ } else {
+ pDev->_tx = malloc(pDev->txbuf_size + BUFFER_ALIGNMENT_NEEDS);
+ if ( !pDev->_tx )
+ return -1;
+ }
- /* Align TX buffer */
- pDev->tx = (struct grcan_msg *)
- (((unsigned int)pDev->_tx + (BUFFER_ALIGNMENT_NEEDS-1)) &
- ~(BUFFER_ALIGNMENT_NEEDS-1));
-#endif
- }
+ /* Align TX buffer */
+ pDev->tx = (struct grcan_msg *)
+ (((unsigned int)pDev->_tx + (BUFFER_ALIGNMENT_NEEDS-1)) &
+ ~(BUFFER_ALIGNMENT_NEEDS-1));
+ }
- if ( rx ) {
-#ifdef STATIC_RX_BUF_ADDR
- pDev->_rx = STATIC_RX_BUF_ADDR(pDev->minor);
- if ( pDev->rxbuf_size > STATIC_RX_BUF_SIZE ){
- pDev->rxbuf_size = STATIC_RX_BUF_SIZE;
- return -1;
- }
- /* Assume aligned buffer */
- pDev->rx = (struct grcan_msg *)pDev->_rx;
-#else
- pDev->_rx = malloc(pDev->rxbuf_size + BUFFER_ALIGNMENT_NEEDS);
- if ( !pDev->_rx )
- return -1;
+ if ( rx ) {
+ if ( pDev->rxbuf_adr ) {
+ /* User defined address */
+ pDev->_rx = pDev->rxbuf_adr;
+ } else {
+ pDev->_rx = malloc(pDev->rxbuf_size + BUFFER_ALIGNMENT_NEEDS);
+ if ( !pDev->_rx )
+ return -1;
+ }
- /* Align TX buffer */
- pDev->rx = (struct grcan_msg *)
- (((unsigned int)pDev->_rx + (BUFFER_ALIGNMENT_NEEDS-1)) &
- ~(BUFFER_ALIGNMENT_NEEDS-1));
-#endif
- }
- return 0;
+ /* Align RX buffer */
+ pDev->rx = (struct grcan_msg *)
+ (((unsigned int)pDev->_rx + (BUFFER_ALIGNMENT_NEEDS-1)) &
+ ~(BUFFER_ALIGNMENT_NEEDS-1));
+ }
+ return 0;
}
static void grcan_free_buffers(struct grcan_priv *pDev, int rx, int tx)
{
FUNCDBG();
-#ifndef STATIC_TX_BUF_ADDR
if ( tx && pDev->_tx ){
free(pDev->_tx);
pDev->_tx = NULL;
pDev->tx = NULL;
}
-#endif
-#ifndef STATIC_RX_BUF_ADDR
+
if ( rx && pDev->_rx ){
free(pDev->_rx);
pDev->_rx = NULL;
pDev->rx = NULL;
}
-#endif
}
-#if 0
-static char *almalloc(int sz)
-{
- char *tmp;
- tmp = calloc(1,2*sz);
- tmp = (char *) (((int)tmp+sz) & ~(sz -1));
- return(tmp);
-}
-#endif
-
static rtems_device_driver grcan_initialize(
rtems_device_major_number major,
rtems_device_minor_number unused,
void *arg
)
{
- int minor;
- struct grcan_priv *pDev;
- amba_apb_device dev;
- rtems_status_code status;
- char fs_name[20];
- unsigned int sys_freq_hz;
- unsigned int deviceid = GAISLER_GRHCAN;
-
- printk("grcan_initialize()\n\r");
-
- FUNCDBG();
-
- /* find GRCAN cores */
- if ( !grcan_cores ) {
- grcan_core_cnt = amba_get_number_apbslv_devices(amba_bus,VENDOR_GAISLER,deviceid);
- if ( grcan_core_cnt < 1 ){
- deviceid = GAISLER_GRCAN;
- grcan_core_cnt = amba_get_number_apbslv_devices(amba_bus,VENDOR_GAISLER,deviceid);
- if ( grcan_core_cnt < 1 ) {
- DBG("GRCAN: Using AMBA Plug&Play, found %d cores\n",grcan_core_cnt);
- return RTEMS_UNSATISFIED;
- }
- }
- DBG("GRCAN: Using AMBA Plug&Play, found %d cores\n",grcan_core_cnt);
- }
-
-#ifdef GRCAN_MAX_CORENR
- /* limit number of cores */
- if ( grcan_core_cnt > GRCAN_MAX_CORENR )
- grcan_core_cnt = GRCAN_MAX_CORENR;
-#endif
-
- /* Allocate memory for cores */
- grcans = malloc(grcan_core_cnt * sizeof(struct grcan_priv));
- if ( !grcans )
- return RTEMS_NO_MEMORY;
- memset(grcans,0,grcan_core_cnt * sizeof(struct grcan_priv));
-
- /* make a local copy of device name */
- strcpy(fs_name,GRCAN_DEVNAME);
-
- /* Detect System Frequency from initialized timer */
-#ifndef SYS_FREQ_HZ
-#if defined(LEON3)
- /* LEON3: find timer address via AMBA Plug&Play info */
- {
- amba_apb_device gptimer;
- LEON3_Timer_Regs_Map *tregs;
-
- if (amba_find_apbslv (&amba_conf, VENDOR_GAISLER, GAISLER_GPTIMER, &gptimer)
- == 1) {
- tregs = (LEON3_Timer_Regs_Map *) gptimer.start;
- sys_freq_hz = (tregs->scaler_reload + 1) * 1000 * 1000;
- DBG("GRCAN: detected %dHZ system frequency\n\r", sys_freq_hz);
- } else {
- sys_freq_hz = 40000000; /* Default to 40MHz */
- printk("GRCAN: Failed to detect system frequency\n\r");
- }
- }
-#elif defined(LEON2)
- /* LEON2: use hardcoded address to get to timer */
- {
- LEON_Register_Map *regs = (LEON_Register_Map *) 0x80000000;
-
- sys_freq_hz = (regs->Scaler_Reload + 1) * 1000 * 1000;
- }
-#else
-#error CPU not supported by driver
-#endif
-#else
- /* Use hardcoded frequency */
- sys_freq_hz = SYS_FREQ_HZ;
-#endif
-
- for(minor=0; minor<grcan_core_cnt; minor++){
-
- pDev = &grcans[minor];
- pDev->minor = minor;
- pDev->open = 0;
- pDev->corefreq_hz = sys_freq_hz;
- GRCAN_DEVNAME_NO(fs_name,minor);
-
- /* Find core address & IRQ */
- if ( !grcan_cores ) {
- amba_find_next_apbslv(amba_bus,VENDOR_GAISLER,deviceid,&dev,minor);
- pDev->irq = dev.irq;
- pDev->regs = (struct grcan_regs *)dev.start;
- }else{
- pDev->irq = grcan_cores[minor].irq;
- pDev->regs = (struct grcan_regs *)grcan_cores[minor].base_address;
- }
-
- printk("Registering GRCAN core at [0x%x] irq %d, minor %d as %s\n\r",pDev->regs,pDev->irq,minor,fs_name);
-
- status = rtems_io_register_name(fs_name, major, 0);
- if (status != RTEMS_SUCCESSFUL)
- rtems_fatal_error_occurred(status);
-
- /* Reset Hardware before attaching IRQ handler */
- grcan_hw_reset(pDev->regs);
-
- /* Register interrupt handler */
- GRCAN_REG_INT(GRCAN_PREFIX(_interrupt_handler), pDev->irq+GRCAN_IRQ_IRQ, pDev);
- /*
- GRCAN_REG_INT(grcan_interrupt_handler, pDev->irq+GRCAN_IRQ_TXSYNC, pDev);
- GRCAN_REG_INT(grcan_interrupt_handler, pDev->irq+GRCAN_IRQ_RXSYNC, pDev);
- */
-
- /* RX Semaphore created with count = 0 */
- if ( rtems_semaphore_create(rtems_build_name('G', 'C', 'R', '0'+minor),
- 0,
- RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|\
- RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
- 0,
- &pDev->rx_sem) != RTEMS_SUCCESSFUL )
- return RTEMS_INTERNAL_ERROR;
-
- /* TX Semaphore created with count = 0 */
- if ( rtems_semaphore_create(rtems_build_name('G', 'C', 'T', '0'+minor),
- 0,
- RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|\
- RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
- 0,
- &pDev->tx_sem) != RTEMS_SUCCESSFUL )
- return RTEMS_INTERNAL_ERROR;
-
- /* TX Empty Semaphore created with count = 0 */
- if ( rtems_semaphore_create(rtems_build_name('G', 'C', 'E', '0'+minor),
- 0,
- RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|\
- RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
- 0,
- &pDev->txempty_sem) != RTEMS_SUCCESSFUL )
- return RTEMS_INTERNAL_ERROR;
-
- /* Device Semaphore created with count = 1 */
- if ( rtems_semaphore_create(rtems_build_name('G', 'C', 'A', '0'+minor),
- 1,
- RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|\
- RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
- 0,
- &pDev->dev_sem) != RTEMS_SUCCESSFUL )
- return RTEMS_INTERNAL_ERROR;
- }
-
- return RTEMS_SUCCESSFUL;
+ return RTEMS_SUCCESSFUL;
}
-static rtems_device_driver grcan_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) {
- struct grcan_priv *pDev;
- rtems_device_driver ret;
-
- FUNCDBG();
+static rtems_device_driver grcan_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ struct grcan_priv *pDev;
+ rtems_device_driver ret;
+ struct drvmgr_dev *dev;
+ union drvmgr_key_value *value;
- if ( (minor < 0) || (minor>=grcan_core_cnt) ) {
- DBG("Wrong minor %d\n", minor);
- return RTEMS_INVALID_NUMBER;
- }
+ FUNCDBG();
- pDev = &grcans[minor];
+ if ( drvmgr_get_dev(&grcan_drv_info.general, minor, &dev) ) {
+ DBG("Wrong minor %d\n", minor);
+ return RTEMS_INVALID_NAME;
+ }
+ pDev = (struct grcan_priv *)dev->priv;
- /* Wait until we get semaphore */
- if ( rtems_semaphore_obtain(pDev->dev_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT) !=
- RTEMS_SUCCESSFUL ){
- return RTEMS_INTERNAL_ERROR;
- }
+ /* Wait until we get semaphore */
+ if (rtems_semaphore_obtain(pDev->dev_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT)
+ != RTEMS_SUCCESSFUL) {
+ return RTEMS_INTERNAL_ERROR;
+ }
- /* is device busy/taken? */
- if ( pDev->open ) {
- ret=RTEMS_RESOURCE_IN_USE;
- goto out;
- }
+ /* is device busy/taken? */
+ if ( pDev->open ) {
+ ret=RTEMS_RESOURCE_IN_USE;
+ goto out;
+ }
- /* Mark device taken */
- pDev->open = 1;
-
- pDev->txblock = pDev->rxblock = 1;
- pDev->txcomplete = pDev->rxcomplete = 0;
- pDev->started = 0;
- pDev->config_changed = 1;
- pDev->config.silent = 0;
- pDev->config.abort = 0;
- pDev->config.selection.selection = 0;
- pDev->config.selection.enable0 = 0;
- pDev->config.selection.enable1 = 1;
- pDev->flushing = 0;
- pDev->rx = pDev->_rx = NULL;
- pDev->tx = pDev->_tx = NULL;
- pDev->txbuf_size = TX_BUF_SIZE;
- pDev->rxbuf_size = RX_BUF_SIZE;
- printk("Defaulting to rxbufsize: %d, txbufsize: %d\n",RX_BUF_SIZE,TX_BUF_SIZE);
-
- /* Default to accept all messages */
- pDev->afilter.mask = 0x00000000;
- pDev->afilter.code = 0x00000000;
-
- /* Default to disable sync messages (only trigger when id is set to all ones) */
- pDev->sfilter.mask = 0xffffffff;
- pDev->sfilter.code = 0x00000000;
-
- /* Calculate default timing register values */
- grcan_calc_timing(GRCAN_DEFAULT_BAUD,pDev->corefreq_hz,GRCAN_SAMPLING_POINT,&pDev->config.timing);
-
- if ( grcan_alloc_buffers(pDev,1,1) ) {
- ret=RTEMS_NO_MEMORY;
- goto out;
- }
+ /* Mark device taken */
+ pDev->open = 1;
+
+ pDev->txblock = pDev->rxblock = 1;
+ pDev->txcomplete = pDev->rxcomplete = 0;
+ pDev->started = 0;
+ pDev->config_changed = 1;
+ pDev->config.silent = 0;
+ pDev->config.abort = 0;
+ pDev->config.selection.selection = 0;
+ pDev->config.selection.enable0 = 0;
+ pDev->config.selection.enable1 = 1;
+ pDev->flushing = 0;
+ pDev->rx = pDev->_rx = NULL;
+ pDev->tx = pDev->_tx = NULL;
+ pDev->txbuf_adr = 0;
+ pDev->rxbuf_adr = 0;
+ pDev->txbuf_size = TX_BUF_SIZE;
+ pDev->rxbuf_size = RX_BUF_SIZE;
+
+ /* Override default buffer sizes if available from bus resource */
+ value = drvmgr_dev_key_get(pDev->dev, "txBufSize", KEY_TYPE_INT);
+ if ( value )
+ pDev->txbuf_size = value->i;
+
+ value = drvmgr_dev_key_get(pDev->dev, "rxBufSize", KEY_TYPE_INT);
+ if ( value )
+ pDev->rxbuf_size = value->i;
+
+ value = drvmgr_dev_key_get(pDev->dev, "txBufAdr", KEY_TYPE_POINTER);
+ if ( value )
+ pDev->txbuf_adr = value->ptr;
+
+ value = drvmgr_dev_key_get(pDev->dev, "rxBufAdr", KEY_TYPE_POINTER);
+ if ( value )
+ pDev->rxbuf_adr = value->ptr;
+
+ DBG("Defaulting to rxbufsize: %d, txbufsize: %d\n",RX_BUF_SIZE,TX_BUF_SIZE);
+
+ /* Default to accept all messages */
+ pDev->afilter.mask = 0x00000000;
+ pDev->afilter.code = 0x00000000;
+
+ /* Default to disable sync messages (only trigger when id is set to all ones) */
+ pDev->sfilter.mask = 0xffffffff;
+ pDev->sfilter.code = 0x00000000;
+
+ /* Calculate default timing register values */
+ grcan_calc_timing(GRCAN_DEFAULT_BAUD,pDev->corefreq_hz,GRCAN_SAMPLING_POINT,&pDev->config.timing);
+
+ if ( grcan_alloc_buffers(pDev,1,1) ) {
+ ret=RTEMS_NO_MEMORY;
+ goto out;
+ }
- /* Clear statistics */
- memset(&pDev->stats,0,sizeof(struct grcan_stats));
+ /* Clear statistics */
+ memset(&pDev->stats,0,sizeof(struct grcan_stats));
- ret = RTEMS_SUCCESSFUL;
+ ret = RTEMS_SUCCESSFUL;
out:
- rtems_semaphore_release(pDev->dev_sem);
- return ret;
+ rtems_semaphore_release(pDev->dev_sem);
+ return ret;
}
static rtems_device_driver grcan_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
{
- struct grcan_priv *pDev = &grcans[minor];
+ struct grcan_priv *pDev;
+ struct drvmgr_dev *dev;
- FUNCDBG();
+ FUNCDBG();
- if ( pDev->started )
- grcan_stop(pDev);
+ if ( drvmgr_get_dev(&grcan_drv_info.general, minor, &dev) ) {
+ return RTEMS_INVALID_NAME;
+ }
+ pDev = (struct grcan_priv *)dev->priv;
- grcan_hw_reset(pDev->regs);
+ if ( pDev->started )
+ grcan_stop(pDev);
- grcan_free_buffers(pDev,1,1);
+ grcan_hw_reset(pDev->regs);
- /* Mark Device as closed */
- pDev->open = 0;
+ grcan_free_buffers(pDev,1,1);
- return RTEMS_SUCCESSFUL;
+ /* Mark Device as closed */
+ pDev->open = 0;
+
+ return RTEMS_SUCCESSFUL;
}
static rtems_device_driver grcan_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
{
- struct grcan_priv *pDev = &grcans[minor];
- rtems_libio_rw_args_t *rw_args;
- CANMsg *dest;
- unsigned int count, left;
- int req_cnt;
+ struct grcan_priv *pDev;
+ struct drvmgr_dev *dev;
+ rtems_libio_rw_args_t *rw_args;
+ CANMsg *dest;
+ unsigned int count, left;
+ int req_cnt;
- rw_args = (rtems_libio_rw_args_t *) arg;
- dest = (CANMsg *) rw_args->buffer;
- req_cnt = rw_args->count / sizeof(CANMsg);
+ FUNCDBG();
- FUNCDBG();
+ if ( drvmgr_get_dev(&grcan_drv_info.general, minor, &dev) ) {
+ return RTEMS_INVALID_NAME;
+ }
+ pDev = (struct grcan_priv *)dev->priv;
- if ( (!dest) || (req_cnt<1) )
- return RTEMS_INVALID_NAME;
+ rw_args = (rtems_libio_rw_args_t *) arg;
+ dest = (CANMsg *) rw_args->buffer;
+ req_cnt = rw_args->count / sizeof(CANMsg);
- if ( !pDev->started )
- return RTEMS_RESOURCE_IN_USE;
+ if ( (!dest) || (req_cnt<1) )
+ return RTEMS_INVALID_NAME;
-/* FUNCDBG("grcan_read [%i,%i]: buf: 0x%x len: %i\n",major, minor, (unsigned int)rw_args->buffer,rw_args->count);*/
+ if ( !pDev->started )
+ return RTEMS_RESOURCE_IN_USE;
- count = grcan_hw_read_try(pDev,pDev->regs,dest,req_cnt);
- if ( !( pDev->rxblock && pDev->rxcomplete && (count!=req_cnt) ) ){
- if ( count > 0 ) {
- /* Successfully received messages (at least one) */
- rw_args->bytes_moved = count * sizeof(CANMsg);
- return RTEMS_SUCCESSFUL;
- }
+ /*FUNCDBG("grcan_read [%i,%i]: buf: 0x%x len: %i\n",major, minor, (unsigned int)rw_args->buffer,rw_args->count);*/
- /* nothing read, shall we block? */
- if ( !pDev->rxblock ) {
- /* non-blocking mode */
- rw_args->bytes_moved = 0;
- return RTEMS_TIMEOUT;
- }
- }
+ count = grcan_hw_read_try(pDev,pDev->regs,dest,req_cnt);
+ if ( !( pDev->rxblock && pDev->rxcomplete && (count!=req_cnt) ) ){
+ if ( count > 0 ) {
+ /* Successfully received messages (at least one) */
+ rw_args->bytes_moved = count * sizeof(CANMsg);
+ return RTEMS_SUCCESSFUL;
+ }
- while(count == 0 || (pDev->rxcomplete && (count!=req_cnt)) ){
+ /* nothing read, shall we block? */
+ if ( !pDev->rxblock ) {
+ /* non-blocking mode */
+ rw_args->bytes_moved = 0;
+ return RTEMS_TIMEOUT;
+ }
+ }
- if ( !pDev->rxcomplete ){
- left = 1; /* return as soon as there is one message available */
- }else{
- left = req_cnt - count; /* return as soon as all data are available */
-
- /* never wait for more than the half the maximum size of the receive buffer
- * Why? We need some time to copy buffer before to catch up with hw, otherwise
- * we would have to copy everything when the data has been received.
- */
- if ( left > ((pDev->rxbuf_size/GRCAN_MSG_SIZE)/2) ){
- left = (pDev->rxbuf_size/GRCAN_MSG_SIZE)/2;
- }
- }
+ while(count == 0 || (pDev->rxcomplete && (count!=req_cnt)) ){
- if ( grcan_wait_rxdata(pDev,left) ) {
- /* The wait has been aborted, probably due to
- * the device driver has been closed by another
- * thread.
- */
- rw_args->bytes_moved = count * sizeof(CANMsg);
- return RTEMS_UNSATISFIED;
- }
+ if ( !pDev->rxcomplete ){
+ left = 1; /* return as soon as there is one message available */
+ }else{
+ left = req_cnt - count; /* return as soon as all data are available */
- /* Try read bytes from circular buffer */
- count += grcan_hw_read_try(
- pDev,
- pDev->regs,
- dest+count,
- req_cnt-count);
- }
- /* no need to unmask IRQ as IRQ Handler do that for us. */
- rw_args->bytes_moved = count * sizeof(CANMsg);
- return RTEMS_SUCCESSFUL;
+ /* never wait for more than the half the maximum size of the receive buffer
+ * Why? We need some time to copy buffer before to catch up with hw,
+ * otherwise we would have to copy everything when the data has been
+ * received.
+ */
+ if ( left > ((pDev->rxbuf_size/GRCAN_MSG_SIZE)/2) ){
+ left = (pDev->rxbuf_size/GRCAN_MSG_SIZE)/2;
+ }
+ }
+
+ if ( grcan_wait_rxdata(pDev,left) ) {
+ /* The wait has been aborted, probably due to
+ * the device driver has been closed by another
+ * thread.
+ */
+ rw_args->bytes_moved = count * sizeof(CANMsg);
+ return RTEMS_UNSATISFIED;
+ }
+
+ /* Try read bytes from circular buffer */
+ count += grcan_hw_read_try(
+ pDev,
+ pDev->regs,
+ dest+count,
+ req_cnt-count);
+ }
+ /* no need to unmask IRQ as IRQ Handler do that for us. */
+ rw_args->bytes_moved = count * sizeof(CANMsg);
+ return RTEMS_SUCCESSFUL;
}
static rtems_device_driver grcan_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
{
- struct grcan_priv *pDev = &grcans[minor];
- rtems_libio_rw_args_t *rw_args;
- CANMsg *source;
- unsigned int count, left;
- int req_cnt;
+ struct grcan_priv *pDev;
+ struct drvmgr_dev *dev;
+ rtems_libio_rw_args_t *rw_args;
+ CANMsg *source;
+ unsigned int count, left;
+ int req_cnt;
- DBGC(DBG_TX,"\n");
- /*FUNCDBG();*/
+ DBGC(DBG_TX,"\n");
- if ( !pDev->started || pDev->config.silent || pDev->flushing )
- return RTEMS_RESOURCE_IN_USE;
+ if ( drvmgr_get_dev(&grcan_drv_info.general, minor, &dev) ) {
+ return RTEMS_INVALID_NAME;
+ }
+ pDev = (struct grcan_priv *)dev->priv;
- rw_args = (rtems_libio_rw_args_t *) arg;
- req_cnt = rw_args->count / sizeof(CANMsg);
- source = (CANMsg *) rw_args->buffer;
+ if ( !pDev->started || pDev->config.silent || pDev->flushing )
+ return RTEMS_RESOURCE_IN_USE;
- /* check proper length and buffer pointer */
- if (( req_cnt < 1) || (source == NULL) ){
- return RTEMS_INVALID_NAME;
- }
+ rw_args = (rtems_libio_rw_args_t *) arg;
+ req_cnt = rw_args->count / sizeof(CANMsg);
+ source = (CANMsg *) rw_args->buffer;
- count = grcan_hw_write_try(pDev,pDev->regs,source,req_cnt);
- if ( !(pDev->txblock && pDev->txcomplete && (count!=req_cnt)) ) {
- if ( count > 0 ) {
- /* Successfully transmitted chars (at least one char) */
- rw_args->bytes_moved = count * sizeof(CANMsg);
- return RTEMS_SUCCESSFUL;
- }
+ /* check proper length and buffer pointer */
+ if (( req_cnt < 1) || (source == NULL) ){
+ return RTEMS_INVALID_NAME;
+ }
- /* nothing written, shall we block? */
- if ( !pDev->txblock ) {
- /* non-blocking mode */
- rw_args->bytes_moved = 0;
- return RTEMS_TIMEOUT;
- }
- }
+ count = grcan_hw_write_try(pDev,pDev->regs,source,req_cnt);
+ if ( !(pDev->txblock && pDev->txcomplete && (count!=req_cnt)) ) {
+ if ( count > 0 ) {
+ /* Successfully transmitted chars (at least one char) */
+ rw_args->bytes_moved = count * sizeof(CANMsg);
+ return RTEMS_SUCCESSFUL;
+ }
- /* if in txcomplete mode we need to transmit all chars */
- while((count == 0) || (pDev->txcomplete && (count!=req_cnt)) ){
- /*** block until room to fit all or as much of transmit buffer as possible IRQ comes
- * Set up a valid IRQ point so that an IRQ is received
- * when we can put a chunk of data into transmit fifo
- */
- if ( !pDev->txcomplete ){
- left = 1; /* wait for anything to fit buffer */
- }else{
- left = req_cnt - count; /* wait for all data to fit in buffer */
+ /* nothing written, shall we block? */
+ if ( !pDev->txblock ) {
+ /* non-blocking mode */
+ rw_args->bytes_moved = 0;
+ return RTEMS_TIMEOUT;
+ }
+ }
- /* never wait for more than the half the maximum size of the transmitt buffer
- * Why? We need some time to fill buffer before hw catches up.
- */
- if ( left > ((pDev->txbuf_size/GRCAN_MSG_SIZE)/2) ){
- left = (pDev->txbuf_size/GRCAN_MSG_SIZE)/2;
- }
- }
+ /* if in txcomplete mode we need to transmit all chars */
+ while((count == 0) || (pDev->txcomplete && (count!=req_cnt)) ){
+ /*** block until room to fit all or as much of transmit buffer as possible
+ * IRQ comes. Set up a valid IRQ point so that an IRQ is received
+ * when we can put a chunk of data into transmit fifo
+ */
+ if ( !pDev->txcomplete ){
+ left = 1; /* wait for anything to fit buffer */
+ }else{
+ left = req_cnt - count; /* wait for all data to fit in buffer */
+
+ /* never wait for more than the half the maximum size of the transmit
+ * buffer
+ * Why? We need some time to fill buffer before hw catches up.
+ */
+ if ( left > ((pDev->txbuf_size/GRCAN_MSG_SIZE)/2) ){
+ left = (pDev->txbuf_size/GRCAN_MSG_SIZE)/2;
+ }
+ }
- /* Wait until more room in transmit buffer */
- if ( grcan_wait_txspace(pDev,left) ){
- /* The wait has been aborted, probably due to
- * the device driver has been closed by another
- * thread. To avoid deadlock we return directly
- * with error status.
- */
- rw_args->bytes_moved = count * sizeof(CANMsg);
- return RTEMS_UNSATISFIED;
- }
+ /* Wait until more room in transmit buffer */
+ if ( grcan_wait_txspace(pDev,left) ){
+ /* The wait has been aborted, probably due to
+ * the device driver has been closed by another
+ * thread. To avoid deadlock we return directly
+ * with error status.
+ */
+ rw_args->bytes_moved = count * sizeof(CANMsg);
+ return RTEMS_UNSATISFIED;
+ }
- if ( pDev->txerror ){
- /* Return number of bytes sent, compare write pointers */
- pDev->txerror = 0;
-#if 0
+ if ( pDev->txerror ){
+ /* Return number of bytes sent, compare write pointers */
+ pDev->txerror = 0;
+#if 0
#error HANDLE AMBA error
#endif
- }
+ }
- /* Try read bytes from circular buffer */
- count += grcan_hw_write_try(
- pDev,
- pDev->regs,
- source+count,
- req_cnt-count);
- }
- /* no need to unmask IRQ as IRQ Handler do that for us. */
+ /* Try read bytes from circular buffer */
+ count += grcan_hw_write_try(
+ pDev,
+ pDev->regs,
+ source+count,
+ req_cnt-count);
+ }
+ /* no need to unmask IRQ as IRQ Handler do that for us. */
- rw_args->bytes_moved = count * sizeof(CANMsg);
- return RTEMS_SUCCESSFUL;
+ rw_args->bytes_moved = count * sizeof(CANMsg);
+ return RTEMS_SUCCESSFUL;
}
static rtems_device_driver grcan_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
{
- struct grcan_priv *pDev = &grcans[minor];
- rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *)arg;
- unsigned int *data = ioarg->buffer;
- struct grcan_timing timing;
- unsigned int speed;
- struct grcan_selection *selection;
- int tmp,ret;
- rtems_device_driver status;
- struct grcan_stats *stats;
- struct grcan_filter *filter;
- IRQ_GLOBAL_PREPARE(oldLevel);
+ struct grcan_priv *pDev;
+ struct drvmgr_dev *dev;
+ rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *)arg;
+ unsigned int *data = ioarg->buffer;
+ struct grcan_timing timing;
+ unsigned int speed;
+ struct grcan_selection *selection;
+ int tmp,ret;
+ rtems_device_driver status;
+ struct grcan_stats *stats;
+ struct grcan_filter *filter;
+ IRQ_GLOBAL_PREPARE(oldLevel);
+
+ FUNCDBG();
+
+ if ( drvmgr_get_dev(&grcan_drv_info.general, minor, &dev) ) {
+ return RTEMS_INVALID_NAME;
+ }
+ pDev = (struct grcan_priv *)dev->priv;
- FUNCDBG();
+ if (!ioarg)
+ return RTEMS_INVALID_NAME;
- if (!ioarg)
- return RTEMS_INVALID_NAME;
+ ioarg->ioctl_return = 0;
+ switch(ioarg->command) {
+ case GRCAN_IOC_START:
+ if ( pDev->started )
+ return RTEMS_RESOURCE_IN_USE; /* EBUSY */
- ioarg->ioctl_return = 0;
- switch(ioarg->command) {
- case GRCAN_IOC_START:
- if ( pDev->started )
- return RTEMS_RESOURCE_IN_USE; /* EBUSY */
+ if ( (status=grcan_start(pDev)) != RTEMS_SUCCESSFUL ){
+ return status;
+ }
+ /* Read and write are now open... */
+ pDev->started = 1;
- if ( (status=grcan_start(pDev)) != RTEMS_SUCCESSFUL ){
- return status;
- }
- /* Read and write are now open... */
- pDev->started = 1;
- break;
+ /* Register interrupt routine and enable IRQ at IRQ ctrl */
+ drvmgr_interrupt_register(dev, 0, "grcan", grcan_interrupt, pDev);
- case GRCAN_IOC_STOP:
- if ( !pDev->started )
- return RTEMS_RESOURCE_IN_USE;
+ break;
- grcan_stop(pDev);
- pDev->started = 0;
- break;
+ case GRCAN_IOC_STOP:
+ if ( !pDev->started )
+ return RTEMS_RESOURCE_IN_USE;
- case GRCAN_IOC_ISSTARTED:
- if ( !pDev->started )
- return RTEMS_RESOURCE_IN_USE;
- break;
+ /* Disable interrupts */
+ drvmgr_interrupt_unregister(dev, 0, grcan_interrupt, pDev);
- case GRCAN_IOC_FLUSH:
- if ( !pDev->started || pDev->flushing || pDev->config.silent )
- return RTEMS_RESOURCE_IN_USE;
-
- pDev->flushing = 1;
- tmp = grcan_tx_flush(pDev);
- pDev->flushing = 0;
- if ( tmp ) {
- /* The wait has been aborted, probably due to
- * the device driver has been closed by another
- * thread.
- */
- return RTEMS_UNSATISFIED;
- }
- break;
+ grcan_stop(pDev);
+ pDev->started = 0;
+ break;
+
+ case GRCAN_IOC_ISSTARTED:
+ if ( !pDev->started )
+ return RTEMS_RESOURCE_IN_USE;
+ break;
+
+ case GRCAN_IOC_FLUSH:
+ if ( !pDev->started || pDev->flushing || pDev->config.silent )
+ return RTEMS_RESOURCE_IN_USE;
+
+ pDev->flushing = 1;
+ tmp = grcan_tx_flush(pDev);
+ pDev->flushing = 0;
+ if ( tmp ) {
+ /* The wait has been aborted, probably due to
+ * the device driver has been closed by another
+ * thread.
+ */
+ return RTEMS_UNSATISFIED;
+ }
+ break;
#if 0
- /* Set physical link */
+ /* Set physical link */
case GRCAN_IOC_SET_LINK:
#ifdef REDUNDANT_CHANNELS
- if ( pDev->started )
- return RTEMS_RESOURCE_IN_USE; /* EBUSY */
+ if ( pDev->started )
+ return RTEMS_RESOURCE_IN_USE; /* EBUSY */
- /* switch HW channel */
- pDev->channel = (unsigned int)ioargs->buffer;
+ /* switch HW channel */
+ pDev->channel = (unsigned int)ioargs->buffer;
#else
- return RTEMS_NOT_IMPLEMENTED;
+ return RTEMS_NOT_IMPLEMENTED;
#endif
- break;
+ break;
#endif
- case GRCAN_IOC_SET_SILENT:
- if ( pDev->started )
- return RTEMS_RESOURCE_IN_USE;
- pDev->config.silent = (int)ioarg->buffer;
- pDev->config_changed = 1;
- break;
-
- case GRCAN_IOC_SET_ABORT:
- if ( pDev->started )
- return RTEMS_RESOURCE_IN_USE;
- pDev->config.abort = (int)ioarg->buffer;
- /* This Configuration parameter doesn't need HurriCANe reset
- * ==> no pDev->config_changed = 1;
- */
- break;
-
- case GRCAN_IOC_SET_SELECTION:
- if ( pDev->started )
- return RTEMS_RESOURCE_IN_USE;
-
- selection = (struct grcan_selection *)ioarg->buffer;
- if ( !selection )
- return RTEMS_INVALID_NAME;
-
- pDev->config.selection = *selection;
- pDev->config_changed = 1;
- break;
-
- case GRCAN_IOC_SET_RXBLOCK:
- pDev->rxblock = (int)ioarg->buffer;
- break;
-
- case GRCAN_IOC_SET_TXBLOCK:
- pDev->txblock = (int)ioarg->buffer;
- break;
-
- case GRCAN_IOC_SET_TXCOMPLETE:
- pDev->txcomplete = (int)ioarg->buffer;
- break;
-
- case GRCAN_IOC_SET_RXCOMPLETE:
- pDev->rxcomplete = (int)ioarg->buffer;
- break;
-
- case GRCAN_IOC_GET_STATS:
- stats = (struct grcan_stats *)ioarg->buffer;
- if ( !stats )
- return RTEMS_INVALID_NAME;
- *stats = pDev->stats;
- break;
-
- case GRCAN_IOC_CLR_STATS:
- IRQ_GLOBAL_DISABLE(oldLevel);
- memset(&pDev->stats,0,sizeof(struct grcan_stats));
- IRQ_GLOBAL_ENABLE(oldLevel);
- break;
+ case GRCAN_IOC_SET_SILENT:
+ if ( pDev->started )
+ return RTEMS_RESOURCE_IN_USE;
+ pDev->config.silent = (int)ioarg->buffer;
+ pDev->config_changed = 1;
+ break;
+
+ case GRCAN_IOC_SET_ABORT:
+ if ( pDev->started )
+ return RTEMS_RESOURCE_IN_USE;
+ pDev->config.abort = (int)ioarg->buffer;
+ /* This Configuration parameter doesn't need HurriCANe reset
+ * ==> no pDev->config_changed = 1;
+ */
+ break;
+
+ case GRCAN_IOC_SET_SELECTION:
+ if ( pDev->started )
+ return RTEMS_RESOURCE_IN_USE;
+
+ selection = (struct grcan_selection *)ioarg->buffer;
+ if ( !selection )
+ return RTEMS_INVALID_NAME;
+
+ pDev->config.selection = *selection;
+ pDev->config_changed = 1;
+ break;
+
+ case GRCAN_IOC_SET_RXBLOCK:
+ pDev->rxblock = (int)ioarg->buffer;
+ break;
+
+ case GRCAN_IOC_SET_TXBLOCK:
+ pDev->txblock = (int)ioarg->buffer;
+ break;
+
+ case GRCAN_IOC_SET_TXCOMPLETE:
+ pDev->txcomplete = (int)ioarg->buffer;
+ break;
+
+ case GRCAN_IOC_SET_RXCOMPLETE:
+ pDev->rxcomplete = (int)ioarg->buffer;
+ break;
+
+ case GRCAN_IOC_GET_STATS:
+ stats = (struct grcan_stats *)ioarg->buffer;
+ if ( !stats )
+ return RTEMS_INVALID_NAME;
+ *stats = pDev->stats;
+ break;
+
+ case GRCAN_IOC_CLR_STATS:
+ IRQ_GLOBAL_DISABLE(oldLevel);
+ memset(&pDev->stats,0,sizeof(struct grcan_stats));
+ IRQ_GLOBAL_ENABLE(oldLevel);
+ break;
case GRCAN_IOC_SET_SPEED:
-
- /* cannot change speed during run mode */
- if ( pDev->started )
- return RTEMS_RESOURCE_IN_USE; /* EBUSY */
-
- /* get speed rate from argument */
- speed = (unsigned int)ioarg->buffer;
- ret = grcan_calc_timing(speed,pDev->corefreq_hz,GRCAN_SAMPLING_POINT,&timing);
- if ( ret )
- return RTEMS_INVALID_NAME; /* EINVAL */
-
- /* save timing/speed */
- pDev->config.timing = timing;
- pDev->config_changed = 1;
- break;
-
- case GRCAN_IOC_SET_BTRS:
- /* Set BTR registers manually
- * Read GRCAN/HurriCANe Manual.
- */
- if ( pDev->started )
- return RTEMS_RESOURCE_IN_USE; /* EBUSY */
-
- if ( !ioarg->buffer )
- return RTEMS_INVALID_NAME;
-
- pDev->config.timing = *(struct grcan_timing *)ioarg->buffer;
- pDev->config_changed = 1;
- break;
-
- case GRCAN_IOC_SET_AFILTER:
- filter = (struct grcan_filter *)ioarg->buffer;
- if ( !filter ){
- /* Disable filtering - let all messages pass */
- pDev->afilter.mask = 0x0;
- pDev->afilter.code = 0x0;
- }else{
- /* Save filter */
- pDev->afilter = *filter;
- }
- /* Set hardware acceptance filter */
- grcan_hw_accept(pDev->regs,&pDev->afilter);
- break;
-
- case GRCAN_IOC_SET_SFILTER:
- filter = (struct grcan_filter *)ioarg->buffer;
- if ( !filter ){
- /* disable TX/RX SYNC filtering */
- pDev->sfilter.mask = 0xffffffff;
- pDev->sfilter.mask = 0;
-
- /* disable Sync interrupt */
- pDev->regs->imr = READ_REG(&pDev->regs->imr) & ~(GRCAN_RXSYNC_IRQ|GRCAN_TXSYNC_IRQ);
- }else{
- /* Save filter */
- pDev->sfilter = *filter;
-
- /* Enable Sync interrupt */
- pDev->regs->imr = READ_REG(&pDev->regs->imr) | (GRCAN_RXSYNC_IRQ|GRCAN_TXSYNC_IRQ);
- }
- /* Set Sync RX/TX filter */
- grcan_hw_sync(pDev->regs,&pDev->sfilter);
- break;
-
- case GRCAN_IOC_GET_STATUS:
- if ( !data )
- return RTEMS_INVALID_NAME;
- /* Read out the statsu register from the GRCAN core */
- data[0] = READ_REG(&pDev->regs->stat);
- break;
-
- default:
- return RTEMS_NOT_DEFINED;
- }
- return RTEMS_SUCCESSFUL;
+ /* cannot change speed during run mode */
+ if ( pDev->started )
+ return RTEMS_RESOURCE_IN_USE; /* EBUSY */
+
+ /* get speed rate from argument */
+ speed = (unsigned int)ioarg->buffer;
+ ret = grcan_calc_timing(speed, pDev->corefreq_hz, GRCAN_SAMPLING_POINT, &timing);
+ if ( ret )
+ return RTEMS_INVALID_NAME; /* EINVAL */
+
+ /* save timing/speed */
+ pDev->config.timing = timing;
+ pDev->config_changed = 1;
+ break;
+
+ case GRCAN_IOC_SET_BTRS:
+ /* Set BTR registers manually
+ * Read GRCAN/HurriCANe Manual.
+ */
+ if ( pDev->started )
+ return RTEMS_RESOURCE_IN_USE; /* EBUSY */
+ if ( !ioarg->buffer )
+ return RTEMS_INVALID_NAME;
+
+ pDev->config.timing = *(struct grcan_timing *)ioarg->buffer;
+ pDev->config_changed = 1;
+ break;
+
+ case GRCAN_IOC_SET_AFILTER:
+ filter = (struct grcan_filter *)ioarg->buffer;
+ if ( !filter ){
+ /* Disable filtering - let all messages pass */
+ pDev->afilter.mask = 0x0;
+ pDev->afilter.code = 0x0;
+ }else{
+ /* Save filter */
+ pDev->afilter = *filter;
+ }
+ /* Set hardware acceptance filter */
+ grcan_hw_accept(pDev->regs,&pDev->afilter);
+ break;
+
+ case GRCAN_IOC_SET_SFILTER:
+ filter = (struct grcan_filter *)ioarg->buffer;
+ if ( !filter ){
+ /* disable TX/RX SYNC filtering */
+ pDev->sfilter.mask = 0xffffffff;
+ pDev->sfilter.mask = 0;
+
+ /* disable Sync interrupt */
+ pDev->regs->imr = READ_REG(&pDev->regs->imr) & ~(GRCAN_RXSYNC_IRQ|GRCAN_TXSYNC_IRQ);
+ }else{
+ /* Save filter */
+ pDev->sfilter = *filter;
+
+ /* Enable Sync interrupt */
+ pDev->regs->imr = READ_REG(&pDev->regs->imr) | (GRCAN_RXSYNC_IRQ|GRCAN_TXSYNC_IRQ);
+ }
+ /* Set Sync RX/TX filter */
+ grcan_hw_sync(pDev->regs,&pDev->sfilter);
+ break;
+
+ case GRCAN_IOC_GET_STATUS:
+ if ( !data )
+ return RTEMS_INVALID_NAME;
+ /* Read out the statsu register from the GRCAN core */
+ data[0] = READ_REG(&pDev->regs->stat);
+ break;
+
+ default:
+ return RTEMS_NOT_DEFINED;
+ }
+ return RTEMS_SUCCESSFUL;
}
-#ifndef GRCAN_DONT_DECLARE_IRQ_HANDLER
-/* Find what device caused the IRQ */
-static rtems_isr grcan_interrupt_handler(rtems_vector_number v)
-{
- int minor=0;
- while ( minor < grcan_core_cnt ){
- if ( (grcans[minor].irq+0x10) == v ){
- grcan_interrupt(&grcans[minor]);
- break;
- }
- }
-}
-#endif
-
/* Handle the IRQ */
-static void grcan_interrupt(struct grcan_priv *pDev)
+static void grcan_interrupt(void *arg)
{
- unsigned int status = READ_REG(&pDev->regs->pimsr);
- unsigned int canstat = READ_REG(&pDev->regs->stat);
+ struct grcan_priv *pDev = arg;
+ unsigned int status = READ_REG(&pDev->regs->pimsr);
+ unsigned int canstat = READ_REG(&pDev->regs->stat);
- /* Spurious IRQ call? */
- if ( !status && !canstat )
- return;
+ /* Spurious IRQ call? */
+ if ( !status && !canstat )
+ return;
- FUNCDBG();
+ FUNCDBG();
- /* Increment number of interrupts counter */
- pDev->stats.ints++;
+ /* Increment number of interrupts counter */
+ pDev->stats.ints++;
- if ( (status & GRCAN_ERR_IRQ) || (canstat & GRCAN_STAT_PASS) ){
- /* Error-Passive interrupt */
- pDev->stats.passive_cnt++;
- }
+ if ( (status & GRCAN_ERR_IRQ) || (canstat & GRCAN_STAT_PASS) ){
+ /* Error-Passive interrupt */
+ pDev->stats.passive_cnt++;
+ }
- if ( (status & GRCAN_OFF_IRQ) || (canstat & GRCAN_STAT_OFF) ){
- /* Bus-off condition interrupt
- * The link is brought down by hardware, we wake all threads
- * that is blocked in read/write calls and stop futher calls
- * to read/write until user has called ioctl(fd,START,0).
- */
- pDev->started = 0;
- grcan_stop(pDev); /* this mask all IRQ sources */
- status=0x1ffff; /* clear all interrupts */
- goto out;
- }
+ if ( (status & GRCAN_OFF_IRQ) || (canstat & GRCAN_STAT_OFF) ){
+ /* Bus-off condition interrupt
+ * The link is brought down by hardware, we wake all threads
+ * that is blocked in read/write calls and stop futher calls
+ * to read/write until user has called ioctl(fd,START,0).
+ */
+ pDev->started = 0;
+ grcan_stop(pDev); /* this mask all IRQ sources */
+ status=0x1ffff; /* clear all interrupts */
+ goto out;
+ }
- if ( (status & GRCAN_OR_IRQ) || (canstat & GRCAN_STAT_OR) ){
- /* Over-run during reception interrupt */
- pDev->stats.overrun_cnt++;
- }
+ if ( (status & GRCAN_OR_IRQ) || (canstat & GRCAN_STAT_OR) ){
+ /* Over-run during reception interrupt */
+ pDev->stats.overrun_cnt++;
+ }
- if ( (status & GRCAN_RXAHBERR_IRQ) ||
- (status & GRCAN_TXAHBERR_IRQ) ||
- (canstat & GRCAN_STAT_AHBERR) ){
- /* RX or Tx AHB Error interrupt */
- printk("AHBERROR: status: 0x%x, canstat: 0x%x\n",status,canstat);
- pDev->stats.ahberr_cnt++;
- }
+ if ( (status & GRCAN_RXAHBERR_IRQ) ||
+ (status & GRCAN_TXAHBERR_IRQ) ||
+ (canstat & GRCAN_STAT_AHBERR) ){
+ /* RX or Tx AHB Error interrupt */
+ printk("AHBERROR: status: 0x%x, canstat: 0x%x\n",status,canstat);
+ pDev->stats.ahberr_cnt++;
+ }
- if ( status & GRCAN_TXLOSS_IRQ ) {
- pDev->stats.txloss_cnt++;
- }
+ if ( status & GRCAN_TXLOSS_IRQ ) {
+ pDev->stats.txloss_cnt++;
+ }
- if ( status & GRCAN_RXIRQ_IRQ ){
- /* RX IRQ pointer interrupt */
- /*printk("RxIrq 0x%x\n",status);*/
- pDev->regs->imr = READ_REG(&pDev->regs->imr) & ~GRCAN_RXIRQ_IRQ;
- rtems_semaphore_release(pDev->rx_sem);
- }
+ if ( status & GRCAN_RXIRQ_IRQ ){
+ /* RX IRQ pointer interrupt */
+ /*printk("RxIrq 0x%x\n",status);*/
+ pDev->regs->imr = READ_REG(&pDev->regs->imr) & ~GRCAN_RXIRQ_IRQ;
+ rtems_semaphore_release(pDev->rx_sem);
+ }
- if ( status & GRCAN_TXIRQ_IRQ ){
- /* TX IRQ pointer interrupt */
- pDev->regs->imr = READ_REG(&pDev->regs->imr) & ~GRCAN_TXIRQ_IRQ;
- rtems_semaphore_release(pDev->tx_sem);
- }
+ if ( status & GRCAN_TXIRQ_IRQ ){
+ /* TX IRQ pointer interrupt */
+ pDev->regs->imr = READ_REG(&pDev->regs->imr) & ~GRCAN_TXIRQ_IRQ;
+ rtems_semaphore_release(pDev->tx_sem);
+ }
- if ( status & GRCAN_TXSYNC_IRQ ){
- /* TxSync message transmitted interrupt */
- pDev->stats.txsync_cnt++;
- }
+ if ( status & GRCAN_TXSYNC_IRQ ){
+ /* TxSync message transmitted interrupt */
+ pDev->stats.txsync_cnt++;
+ }
- if ( status & GRCAN_RXSYNC_IRQ ){
- /* RxSync message received interrupt */
- pDev->stats.rxsync_cnt++;
- }
+ if ( status & GRCAN_RXSYNC_IRQ ){
+ /* RxSync message received interrupt */
+ pDev->stats.rxsync_cnt++;
+ }
- if ( status & GRCAN_TXEMPTY_IRQ ){
- pDev->regs->imr = READ_REG(&pDev->regs->imr) & ~GRCAN_TXEMPTY_IRQ;
- rtems_semaphore_release(pDev->txempty_sem);
- }
+ if ( status & GRCAN_TXEMPTY_IRQ ){
+ pDev->regs->imr = READ_REG(&pDev->regs->imr) & ~GRCAN_TXEMPTY_IRQ;
+ rtems_semaphore_release(pDev->txempty_sem);
+ }
out:
- /* Clear IRQs */
- pDev->regs->picr = status;
-}
-
-static int grcan_register_internal(void)
-{
- rtems_status_code r;
- rtems_device_major_number m;
-
- if ((r = rtems_io_register_driver(0, &grcan_driver, &m)) !=
- RTEMS_SUCCESSFUL) {
- switch(r) {
- case RTEMS_TOO_MANY:
- DBG2("failed RTEMS_TOO_MANY\n");
- break;
- case RTEMS_INVALID_NUMBER:
- DBG2("failed RTEMS_INVALID_NUMBER\n");
- break;
- case RTEMS_RESOURCE_IN_USE:
- DBG2("failed RTEMS_RESOURCE_IN_USE\n");
- break;
- default:
- DBG("failed %i\n",r);
- break;
- }
- return 1;
- }
- DBG("Registered GRCAN on major %d\n",m);
- return 0;
-}
-
-
-/* Use custom addresses and IRQs to find hardware */
-int GRCAN_PREFIX(_register_abs)(struct grcan_device_info *devices, int dev_cnt)
-{
- FUNCDBG();
-
- if ( !devices || (dev_cnt<0) )
- return 1;
- grcan_cores = devices;
- grcan_core_cnt = dev_cnt;
-
- amba_bus = NULL;
- return grcan_register_internal();
-}
-
-/* Use prescanned AMBA Plug&Play information to find all GRCAN cores */
-int GRCAN_PREFIX(_register)(amba_confarea_type *abus)
-{
- FUNCDBG();
-
- if ( !abus )
- return 1;
- amba_bus = abus;
- grcan_cores = NULL;
- grcan_core_cnt = 0;
- return grcan_register_internal();
+ /* Clear IRQs */
+ pDev->regs->picr = status;
}
diff --git a/c/src/lib/libbsp/sparc/shared/can/grcan_rasta.c b/c/src/lib/libbsp/sparc/shared/can/grcan_rasta.c
deleted file mode 100644
index f9b126f552..0000000000
--- a/c/src/lib/libbsp/sparc/shared/can/grcan_rasta.c
+++ /dev/null
@@ -1,100 +0,0 @@
-
-#include <rasta.h>
-
-/* PCI frequency */
-#define SYS_FREQ_HZ 30000000
-
-/*#define USE_AT697_RAM 1 */
-
-/* memarea_to_hw(x)
- *
- * x: address in AT697 address space
- *
- * returns the address in the RASTA address space that can be used to access x with dma.
- *
-*/
-#ifdef USE_AT697_RAM
-static inline unsigned int memarea_to_hw(unsigned int addr) {
- return ((addr & 0x0fffffff) | RASTA_PCI_BASE);
-}
-#else
-static inline unsigned int memarea_to_hw(unsigned int addr) {
- return ((addr & 0x0fffffff) | RASTA_LOCAL_SRAM);
-}
-#endif
-
-#define MEMAREA_TO_HW(x) memarea_to_hw(x)
-
-#define IRQ_CLEAR_PENDING(irqno)
-#define IRQ_UNMASK(irqno)
-#define IRQ_MASK(irqno)
-
-#define IRQ_GLOBAL_PREPARE(level) rtems_interrupt_level level
-#define IRQ_GLOBAL_DISABLE(level) rtems_interrupt_disable(level)
-#define IRQ_GLOBAL_ENABLE(level) rtems_interrupt_enable(level)
-
-#define GRCAN_REG_INT(handler,irqno,arg) \
- if ( grcan_rasta_int_reg ) \
- grcan_rasta_int_reg(handler,irqno,arg);
-
-void (*grcan_rasta_int_reg)(void *handler, int irq, void *arg) = 0;
-
-#define GRCAN_PREFIX(name) grcan_rasta##name
-
-/* We provide our own handler */
-#define GRCAN_DONT_DECLARE_IRQ_HANDLER
-
-#define GRCAN_REG_BYPASS_CACHE
-#define GRCAN_DMA_BYPASS_CACHE
-
-#define GRCAN_MAX_CORES 1
-
-/* Custom Statically allocated memory */
-#undef STATICALLY_ALLOCATED_TX_BUFFER
-#undef STATICALLY_ALLOCATED_RX_BUFFER
-
-#define STATIC_TX_BUF_SIZE 4096
-#define STATIC_RX_BUF_SIZE 4096
-#define TX_BUF_SIZE 4096
-#define RX_BUF_SIZE 4096
-
-#define STATIC_TX_BUF_ADDR(core) \
- ((unsigned int *)\
- (grcan_rasta_rambase+(core)*(STATIC_TX_BUF_SIZE+STATIC_RX_BUF_SIZE)))
-
-#define STATIC_RX_BUF_ADDR(core) \
- ((unsigned int *) \
- (grcan_rasta_rambase+(core)*(STATIC_TX_BUF_SIZE+STATIC_RX_BUF_SIZE)+STATIC_RX_BUF_SIZE))
-
-
-#define GRCAN_DEVNAME "/dev/grcan0"
-#define GRCAN_DEVNAME_NO(devstr,no) ((devstr)[10]='0'+(no))
-
-void grcan_rasta_interrupt_handler(int irq, void *pDev);
-
-unsigned int grcan_rasta_rambase;
-
-#include "grcan.c"
-
-
-int grcan_rasta_ram_register(amba_confarea_type *abus, int rambase)
-{
- grcan_rasta_rambase = rambase;
-
- return GRCAN_PREFIX(_register)(abus);
-}
-#if 0
-static void grcan_rasta_interrupt_handler(int v)
-{
- /* We know there is always only one GRCAN core in a RASTA chip... */
- grcan_interrupt(&grcans[0]);
- /*
- struct grcan_priv *pDev = arg;
- grcan_interrupt(pDev);
- */
-}
-#endif
-void GRCAN_PREFIX(_interrupt_handler)(int irq, void *pDev)
-{
- grcan_interrupt(pDev);
-}
diff --git a/c/src/lib/libbsp/sparc/shared/can/occan.c b/c/src/lib/libbsp/sparc/shared/can/occan.c
index 8b6dbfd32a..9ff89ea7df 100644
--- a/c/src/lib/libbsp/sparc/shared/can/occan.c
+++ b/c/src/lib/libbsp/sparc/shared/can/occan.c
@@ -1,13 +1,15 @@
/* OC_CAN driver
*
- * COPYRIGHT (c) 2007.
- * Gaisler Research.
+ * COPYRIGHT (c) 2008.
+ * Aeroflex Gaisler.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
*
- * Author: Daniel Hellström, Gaisler Research AB, www.gaisler.com
+ * 2008-12-17, Daniel Hellstrom <daniel@gaisler.com>
+ * Converted driver to support driver manager
+ *
*/
#include <rtems/libio.h>
@@ -17,8 +19,8 @@
#include <bsp.h>
#include <rtems/bspIo.h> /* printk */
-#include <leon.h>
-#include <ambapp.h>
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
#include <occan.h>
/* RTEMS -> ERRNO decoding table
@@ -52,27 +54,8 @@ rtems_assoc_t errno_assoc[] = {
#undef OCCAN_BYTE_REGS
#endif
-#ifndef OCCAN_PREFIX
- #define OCCAN_PREFIX(name) occan##name
-#endif
-
-#if !defined(OCCAN_DEVNAME) || !defined(OCCAN_DEVNAME_NO)
- #undef OCCAN_DEVNAME
- #undef OCCAN_DEVNAME_NO
- #define OCCAN_DEVNAME "/dev/occan0"
- #define OCCAN_DEVNAME_NO(devstr,no) ((devstr)[10]='0'+(no))
-#endif
-
-#ifndef OCCAN_REG_INT
- #define OCCAN_REG_INT(handler,irq,arg) set_vector(handler,irq+0x10,1)
- #undef OCCAN_DEFINE_INTHANDLER
- #define OCCAN_DEFINE_INTHANDLER
-#endif
-
-/* Default to 40MHz system clock */
-/*#ifndef SYS_FREQ_HZ
- #define SYS_FREQ_HZ 40000000
-#endif*/
+/* Enable Fixup code older OCCAN with a TX IRQ-FLAG bug */
+#define OCCAN_TX_IRQ_FLAG_FIXUP 1
#define OCCAN_WORD_REG_OFS 0x80
#define OCCAN_NCORE_OFS 0x100
@@ -102,7 +85,7 @@ typedef struct {
} occan_fifo;
/* PELICAN */
-#ifdef OCCAN_BYTE_REGS
+
typedef struct {
unsigned char
mode,
@@ -148,8 +131,8 @@ typedef struct {
unsigned char rx_msg_cnt;
unsigned char unused1;
unsigned char clkdiv;
-} pelican_regs;
-#else
+} pelican8_regs;
+
typedef struct {
unsigned char
mode, unused0[3],
@@ -195,9 +178,15 @@ typedef struct {
unsigned char rx_msg_cnt,unused16[3];
unsigned char unused17[4];
unsigned char clkdiv,unused18[3];
-} pelican_regs;
+} pelican32_regs;
+
+#ifdef OCCAN_BYTE_REGS
+#define pelican_regs pelican8_regs
+#else
+#define pelican_regs pelican32_regs
#endif
+
#define MAX_TSEG2 7
#define MAX_TSEG1 15
@@ -216,12 +205,17 @@ typedef struct {
} occan_speed_regs;
typedef struct {
+ struct drvmgr_dev *dev;
+ char devName[32];
+
/* hardware shortcuts */
pelican_regs *regs;
+ int byte_regs;
int irq;
occan_speed_regs timing;
int channel; /* 0=default, 1=second bus */
int single_mode;
+ unsigned int sys_freq_hz;
/* driver state */
rtems_id devsem;
@@ -231,6 +225,7 @@ typedef struct {
int started;
int rxblk;
int txblk;
+ int sending;
unsigned int status;
occan_stats stats;
@@ -265,7 +260,7 @@ static int pelican_start(occan_priv *priv);
static void pelican_stop(occan_priv *priv);
static int pelican_send(occan_priv *can, CANMsg *msg);
static void pelican_set_accept(occan_priv *priv, unsigned char *acode, unsigned char *amask);
-static void occan_interrupt(occan_priv *can);
+void occan_interrupt(void *arg);
#ifdef DEBUG_PRINT_REGMAP
static void pelican_regadr_print(pelican_regs *regs);
#endif
@@ -277,33 +272,55 @@ static rtems_device_driver occan_read(rtems_device_major_number major, rtems_dev
static rtems_device_driver occan_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
static rtems_device_driver occan_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
static rtems_device_driver occan_initialize(rtems_device_major_number major, rtems_device_minor_number unused, void *arg);
-#ifdef OCCAN_DEFINE_INTHANDLER
-static void occan_interrupt_handler(rtems_vector_number v);
-#endif
-static int can_cores;
-static occan_priv *cans;
-static amba_confarea_type *amba_bus;
-static unsigned int sys_freq_hz;
+
+#define OCCAN_DRIVER_TABLE_ENTRY { occan_initialize, occan_open, occan_close, occan_read, occan_write, occan_ioctl }
+static rtems_driver_address_table occan_driver = OCCAN_DRIVER_TABLE_ENTRY;
/* Read byte bypassing */
-#ifdef OCCAN_DONT_BYPASS_CACHE
- #define READ_REG(address) (*(volatile unsigned char *)(address))
-#else
+
/* Bypass cache */
- #define READ_REG(address) _OCCAN_REG_READ((unsigned int)(address))
- static __inline__ unsigned char _OCCAN_REG_READ(unsigned int addr) {
- unsigned char tmp;
- asm(" lduba [%1]1, %0 "
- : "=r"(tmp)
- : "r"(addr)
- );
- return tmp;
+#if 0
+#define READ_REG(address) _OCCAN_REG_READ((unsigned int)(address))
+static __inline__ unsigned char _OCCAN_REG_READ(unsigned int addr) {
+ unsigned char tmp;
+ __asm__(" lduba [%1]1, %0 "
+ : "=r"(tmp)
+ : "r"(addr)
+ );
+ return tmp;
}
#endif
-#define WRITE_REG(address,data) (*(volatile unsigned char *)(address) = (data))
+/*#define WRITE_REG(address,data) (*(volatile unsigned char *)(address) = (data))*/
+
+#define READ_REG(priv, address) occan_reg_read(priv, (unsigned int)address)
+#define WRITE_REG(priv, address, data) occan_reg_write(priv, (unsigned int)address, data)
+
+unsigned int occan_reg_read(occan_priv *priv, unsigned int address)
+{
+ unsigned int adr;
+ if ( priv->byte_regs ) {
+ adr = address;
+ } else {
+ /* Word accessed registers */
+ adr = (address & (~0x7f)) | ((address & 0x7f)<<2);
+ }
+ return *(volatile unsigned char *)adr;
+}
+
+void occan_reg_write(occan_priv *priv, unsigned int address, unsigned char value)
+{
+ unsigned int adr;
+ if ( priv->byte_regs ) {
+ adr = address;
+ } else {
+ /* Word accessed registers */
+ adr = (address & (~0x7f)) | ((address & 0x7f)<<2);
+ }
+ *(volatile unsigned char *)adr = value;;
+}
/* Mode register bit definitions */
#define PELICAN_MOD_RESET 0x1
@@ -390,9 +407,370 @@ static unsigned int sys_freq_hz;
#define PELICAN_S_ 0x80
*/
+static int occan_driver_io_registered = 0;
+static rtems_device_major_number occan_driver_io_major = 0;
+
+/******************* Driver manager interface ***********************/
+
+/* Driver prototypes */
+int occan_register_io(rtems_device_major_number *m);
+int occan_device_init(occan_priv *pDev);
+
+int occan_init2(struct drvmgr_dev *dev);
+int occan_init3(struct drvmgr_dev *dev);
+
+struct drvmgr_drv_ops occan_ops =
+{
+ .init = {NULL, occan_init2, occan_init3, NULL},
+ .remove = NULL,
+ .info = NULL
+};
+
+struct amba_dev_id occan_ids[] =
+{
+ {VENDOR_GAISLER, GAISLER_CANAHB},
+ {0, 0} /* Mark end of table */
+};
+
+struct amba_drv_info occan_drv_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_AMBAPP_GAISLER_OCCAN_ID, /* Driver ID */
+ "OCCAN_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */
+ &occan_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ 0,
+ },
+ &occan_ids[0]
+};
+
+void occan_register_drv (void)
+{
+ DBG("Registering OCCAN driver\n");
+ drvmgr_drv_register(&occan_drv_info.general);
+}
+
+int occan_init2(struct drvmgr_dev *dev)
+{
+ occan_priv *priv;
+
+ DBG("OCCAN[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
+ priv = dev->priv = malloc(sizeof(occan_priv));
+ if ( !priv )
+ return DRVMGR_NOMEM;
+ memset(priv, 0, sizeof(*priv));
+ priv->dev = dev;
+
+ return DRVMGR_OK;
+}
+
+int occan_init3(struct drvmgr_dev *dev)
+{
+ occan_priv *priv;
+ char prefix[32];
+ rtems_status_code status;
+
+ priv = dev->priv;
+
+ /* Do initialization */
+
+ if ( occan_driver_io_registered == 0) {
+ /* Register the I/O driver only once for all cores */
+ if ( occan_register_io(&occan_driver_io_major) ) {
+ /* Failed to register I/O driver */
+ dev->priv = NULL;
+ return DRVMGR_FAIL;
+ }
+
+ occan_driver_io_registered = 1;
+ }
+
+ /* I/O system registered and initialized
+ * Now we take care of device initialization.
+ */
+
+ if ( occan_device_init(priv) ) {
+ return DRVMGR_FAIL;
+ }
+
+ /* Get Filesystem name prefix */
+ prefix[0] = '\0';
+ if ( drvmgr_get_dev_prefix(dev, prefix) ) {
+ /* Failed to get prefix, make sure of a unique FS name
+ * by using the driver minor.
+ */
+ sprintf(priv->devName, "/dev/occan%d", dev->minor_drv);
+ } else {
+ /* Got special prefix, this means we have a bus prefix
+ * And we should use our "bus minor"
+ */
+ sprintf(priv->devName, "/dev/%soccan%d", prefix, dev->minor_bus);
+ }
+
+ /* Register Device */
+ DBG("OCCAN[%d]: Registering %s\n", dev->minor_drv, priv->devName);
+ status = rtems_io_register_name(priv->devName, occan_driver_io_major, dev->minor_drv);
+ if (status != RTEMS_SUCCESSFUL) {
+ return DRVMGR_FAIL;
+ }
+
+ return DRVMGR_OK;
+}
+
+/******************* Driver Implementation ***********************/
+
+int occan_register_io(rtems_device_major_number *m)
+{
+ rtems_status_code r;
+
+ if ((r = rtems_io_register_driver(0, &occan_driver, m)) == RTEMS_SUCCESSFUL) {
+ DBG("OCCAN driver successfully registered, major: %d\n", *m);
+ } else {
+ switch(r) {
+ case RTEMS_TOO_MANY:
+ printk("OCCAN rtems_io_register_driver failed: RTEMS_TOO_MANY\n");
+ return -1;
+ case RTEMS_INVALID_NUMBER:
+ printk("OCCAN rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n");
+ return -1;
+ case RTEMS_RESOURCE_IN_USE:
+ printk("OCCAN rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n");
+ return -1;
+ default:
+ printk("OCCAN rtems_io_register_driver failed\n");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int occan_device_init(occan_priv *pDev)
+{
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
+ rtems_status_code status;
+ int minor;
+
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)pDev->dev->businfo;
+ if ( ambadev == NULL ) {
+ return -1;
+ }
+ pnpinfo = &ambadev->info;
+ pDev->irq = pnpinfo->irq;
+ pDev->regs = (pelican_regs *)(pnpinfo->ahb_slv->start[0] + OCCAN_NCORE_OFS*pnpinfo->index);
+ pDev->byte_regs = 1;
+ minor = pDev->dev->minor_drv;
+
+ /* Get frequency in Hz */
+ if ( drvmgr_freq_get(pDev->dev, DEV_AHB_SLV, &pDev->sys_freq_hz) ) {
+ return -1;
+ }
+
+ DBG("OCCAN frequency: %d Hz\n", pDev->sys_freq_hz);
+
+ /* initialize software */
+ pDev->open = 0;
+ pDev->started = 0; /* Needed for spurious interrupts */
+ pDev->rxfifo = NULL;
+ pDev->txfifo = NULL;
+ status = rtems_semaphore_create(
+ rtems_build_name('C', 'd', 'v', '0'+minor),
+ 1,
+ RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | \
+ RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &pDev->devsem);
+ if ( status != RTEMS_SUCCESSFUL ){
+ printk("OCCAN[%d]: Failed to create dev semaphore, (%d)\n\r",minor, status);
+ return RTEMS_UNSATISFIED;
+ }
+ status = rtems_semaphore_create(
+ rtems_build_name('C', 't', 'x', '0'+minor),
+ 0,
+ RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | \
+ RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &pDev->txsem);
+ if ( status != RTEMS_SUCCESSFUL ){
+ printk("OCCAN[%d]: Failed to create tx semaphore, (%d)\n\r",minor, status);
+ return RTEMS_UNSATISFIED;
+ }
+ status = rtems_semaphore_create(
+ rtems_build_name('C', 'r', 'x', '0'+minor),
+ 0,
+ RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | \
+ RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &pDev->rxsem);
+ if ( status != RTEMS_SUCCESSFUL ){
+ printk("OCCAN[%d]: Failed to create rx semaphore, (%d)\n\r",minor, status);
+ return RTEMS_UNSATISFIED;
+ }
+
+ /* hardware init/reset */
+ pelican_init(pDev);
+
+#ifdef DEBUG_PRINT_REGMAP
+ pelican_regadr_print(pDev->regs);
+#endif
+
+ return 0;
+}
+
+
+#ifdef DEBUG
+static void pelican_regs_print(occan_priv *pDev){
+ pelican_regs *regs = pDev->regs;
+ printk("--- PELICAN 0x%lx ---\n\r",(unsigned int)regs);
+ printk(" MODE: 0x%02x\n\r",READ_REG(pDev, &regs->mode));
+ printk(" CMD: 0x%02x\n\r",READ_REG(pDev, &regs->cmd));
+ printk(" STATUS: 0x%02x\n\r",READ_REG(pDev, &regs->status));
+ /*printk(" INTFLG: 0x%02x\n\r",READ_REG(pDev, &regs->intflags));*/
+ printk(" INTEN: 0x%02x\n\r",READ_REG(pDev, &regs->inten));
+ printk(" BTR0: 0x%02x\n\r",READ_REG(pDev, &regs->bustim0));
+ printk(" BTR1: 0x%02x\n\r",READ_REG(pDev, &regs->bustim1));
+ printk(" ARBCODE: 0x%02x\n\r",READ_REG(pDev, &regs->arbcode));
+ printk(" ERRCODE: 0x%02x\n\r",READ_REG(pDev, &regs->errcode));
+ printk(" ERRWARN: 0x%02x\n\r",READ_REG(pDev, &regs->errwarn));
+ printk(" RX_ERR_CNT: 0x%02x\n\r",READ_REG(pDev, &regs->rx_err_cnt));
+ printk(" TX_ERR_CNT: 0x%02x\n\r",READ_REG(pDev, &regs->tx_err_cnt));
+ if ( READ_REG(pDev, &regs->mode) & PELICAN_MOD_RESET ){
+ /* in reset mode it is possible to read acceptance filters */
+ printk(" ACR0: 0x%02x (0x%lx)\n\r",READ_REG(pDev, &regs->rx_fi_xff),&regs->rx_fi_xff);
+ printk(" ACR1: 0x%02x (0x%lx)\n\r",READ_REG(pDev, &regs->msg.rst_accept.code[0]),(unsigned int)&regs->msg.rst_accept.code[0]);
+ printk(" ACR1: 0x%02x (0x%lx)\n\r",READ_REG(pDev, &regs->msg.rst_accept.code[1]),(unsigned int)&regs->msg.rst_accept.code[1]);
+ printk(" ACR1: 0x%02x (0x%lx)\n\r",READ_REG(pDev, &regs->msg.rst_accept.code[2]),(unsigned int)&regs->msg.rst_accept.code[2]);
+ printk(" AMR0: 0x%02x (0x%lx)\n\r",READ_REG(pDev, &regs->msg.rst_accept.mask[0]),(unsigned int)&regs->msg.rst_accept.mask[0]);
+ printk(" AMR1: 0x%02x (0x%lx)\n\r",READ_REG(pDev, &regs->msg.rst_accept.mask[1]),(unsigned int)&regs->msg.rst_accept.mask[1]);
+ printk(" AMR2: 0x%02x (0x%lx)\n\r",READ_REG(pDev, &regs->msg.rst_accept.mask[2]),(unsigned int)&regs->msg.rst_accept.mask[2]);
+ printk(" AMR3: 0x%02x (0x%lx)\n\r",READ_REG(pDev, &regs->msg.rst_accept.mask[3]),(unsigned int)&regs->msg.rst_accept.mask[3]);
+
+ }else{
+ printk(" RXFI_XFF: 0x%02x\n\r",READ_REG(pDev, &regs->rx_fi_xff));
+ }
+ printk(" RX_MSG_CNT: 0x%02x\n\r",READ_REG(pDev, &regs->rx_msg_cnt));
+ printk(" CLKDIV: 0x%02x\n\r",READ_REG(pDev, &regs->clkdiv));
+ printk("-------------------\n\r");
+}
+#endif
+
+#ifdef DEBUG_PRINT_REGMAP
+static void pelican_regadr_print(pelican_regs *regs){
+ printk("--- PELICAN 0x%lx ---\n\r",(unsigned int)regs);
+ printk(" MODE: 0x%lx\n\r",(unsigned int)&regs->mode);
+ printk(" CMD: 0x%lx\n\r",(unsigned int)&regs->cmd);
+ printk(" STATUS: 0x%lx\n\r",(unsigned int)&regs->status);
+ /*printk(" INTFLG: 0x%lx\n\r",&regs->intflags);*/
+ printk(" INTEN: 0x%lx\n\r",(unsigned int)&regs->inten);
+ printk(" BTR0: 0x%lx\n\r",(unsigned int)&regs->bustim0);
+ printk(" BTR1: 0x%lx\n\r",(unsigned int)&regs->bustim1);
+ printk(" ARBCODE: 0x%lx\n\r",(unsigned int)&regs->arbcode);
+ printk(" ERRCODE: 0x%lx\n\r",(unsigned int)&regs->errcode);
+ printk(" ERRWARN: 0x%lx\n\r",(unsigned int)&regs->errwarn);
+ printk(" RX_ERR_CNT: 0x%lx\n\r",(unsigned int)&regs->rx_err_cnt);
+ printk(" TX_ERR_CNT: 0x%lx\n\r",(unsigned int)&regs->tx_err_cnt);
+
+ /* in reset mode it is possible to read acceptance filters */
+ printk(" RXFI_XFF: 0x%lx\n\r",(unsigned int)&regs->rx_fi_xff);
+
+ /* reset registers */
+ printk(" ACR0: 0x%lx\n\r",(unsigned int)&regs->rx_fi_xff);
+ printk(" ACR1: 0x%lx\n\r",(unsigned int)&regs->msg.rst_accept.code[0]);
+ printk(" ACR2: 0x%lx\n\r",(unsigned int)&regs->msg.rst_accept.code[1]);
+ printk(" ACR3: 0x%lx\n\r",(unsigned int)&regs->msg.rst_accept.code[2]);
+ printk(" AMR0: 0x%lx\n\r",(unsigned int)&regs->msg.rst_accept.mask[0]);
+ printk(" AMR1: 0x%lx\n\r",(unsigned int)&regs->msg.rst_accept.mask[1]);
+ printk(" AMR2: 0x%lx\n\r",(unsigned int)&regs->msg.rst_accept.mask[2]);
+ printk(" AMR3: 0x%lx\n\r",(unsigned int)&regs->msg.rst_accept.mask[3]);
+
+ /* TX Extended */
+ printk(" EFFTX_ID[0]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_eff.id[0]);
+ printk(" EFFTX_ID[1]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_eff.id[1]);
+ printk(" EFFTX_ID[2]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_eff.id[2]);
+ printk(" EFFTX_ID[3]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_eff.id[3]);
+
+ printk(" EFFTX_DATA[0]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_eff.data[0]);
+ printk(" EFFTX_DATA[1]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_eff.data[1]);
+ printk(" EFFTX_DATA[2]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_eff.data[2]);
+ printk(" EFFTX_DATA[3]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_eff.data[3]);
+ printk(" EFFTX_DATA[4]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_eff.data[4]);
+ printk(" EFFTX_DATA[5]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_eff.data[5]);
+ printk(" EFFTX_DATA[6]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_eff.data[6]);
+ printk(" EFFTX_DATA[7]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_eff.data[7]);
+
+ /* RX Extended */
+ printk(" EFFRX_ID[0]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_eff.id[0]);
+ printk(" EFFRX_ID[1]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_eff.id[1]);
+ printk(" EFFRX_ID[2]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_eff.id[2]);
+ printk(" EFFRX_ID[3]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_eff.id[3]);
+
+ printk(" EFFRX_DATA[0]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_eff.data[0]);
+ printk(" EFFRX_DATA[1]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_eff.data[1]);
+ printk(" EFFRX_DATA[2]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_eff.data[2]);
+ printk(" EFFRX_DATA[3]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_eff.data[3]);
+ printk(" EFFRX_DATA[4]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_eff.data[4]);
+ printk(" EFFRX_DATA[5]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_eff.data[5]);
+ printk(" EFFRX_DATA[6]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_eff.data[6]);
+ printk(" EFFRX_DATA[7]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_eff.data[7]);
+
+
+ /* RX Extended */
+ printk(" SFFRX_ID[0]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_sff.id[0]);
+ printk(" SFFRX_ID[1]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_sff.id[1]);
+
+ printk(" SFFRX_DATA[0]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_sff.data[0]);
+ printk(" SFFRX_DATA[1]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_sff.data[1]);
+ printk(" SFFRX_DATA[2]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_sff.data[2]);
+ printk(" SFFRX_DATA[3]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_sff.data[3]);
+ printk(" SFFRX_DATA[4]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_sff.data[4]);
+ printk(" SFFRX_DATA[5]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_sff.data[5]);
+ printk(" SFFRX_DATA[6]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_sff.data[6]);
+ printk(" SFFRX_DATA[7]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_sff.data[7]);
+
+ /* TX Extended */
+ printk(" SFFTX_ID[0]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_sff.id[0]);
+ printk(" SFFTX_ID[1]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_sff.id[1]);
+
+ printk(" SFFTX_DATA[0]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_sff.data[0]);
+ printk(" SFFTX_DATA[1]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_sff.data[1]);
+ printk(" SFFTX_DATA[2]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_sff.data[2]);
+ printk(" SFFTX_DATA[3]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_sff.data[3]);
+ printk(" SFFTX_DATA[4]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_sff.data[4]);
+ printk(" SFFTX_DATA[5]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_sff.data[5]);
+ printk(" SFFTX_DATA[6]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_sff.data[6]);
+ printk(" SFFTX_DATA[7]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_sff.data[7]);
+
+ printk(" RX_MSG_CNT: 0x%lx\n\r",(unsigned int)&regs->rx_msg_cnt);
+ printk(" CLKDIV: 0x%lx\n\r",(unsigned int)&regs->clkdiv);
+ printk("-------------------\n\r");
+}
+#endif
+
+#ifdef DEBUG
+static void occan_stat_print(occan_stats *stats){
+ printk("----Stats----\n\r");
+ printk("rx_msgs: %d\n\r",stats->rx_msgs);
+ printk("tx_msgs: %d\n\r",stats->tx_msgs);
+ printk("err_warn: %d\n\r",stats->err_warn);
+ printk("err_dovr: %d\n\r",stats->err_dovr);
+ printk("err_errp: %d\n\r",stats->err_errp);
+ printk("err_arb: %d\n\r",stats->err_arb);
+ printk("err_bus: %d\n\r",stats->err_bus);
+ printk("Int cnt: %d\n\r",stats->ints);
+ printk("tx_buf_err: %d\n\r",stats->tx_buf_error);
+ printk("-------------\n\r");
+}
+#endif
+
static void pelican_init(occan_priv *priv){
/* Reset core */
- priv->regs->mode = PELICAN_MOD_RESET;
+ WRITE_REG(priv, &priv->regs->mode, PELICAN_MOD_RESET);
/* wait for core to reset complete */
/*usleep(1);*/
@@ -417,20 +795,21 @@ static void pelican_open(occan_priv *priv){
/* Set clock divider to extended mode, clkdiv not connected
*/
- priv->regs->clkdiv = (1<<PELICAN_CDR_MODE_BITS) | (DEFAULT_CLKDIV & PELICAN_CDR_DIV);
+ WRITE_REG(priv, &priv->regs->clkdiv, (1<<PELICAN_CDR_MODE_BITS) | (DEFAULT_CLKDIV & PELICAN_CDR_DIV));
- ret = occan_calc_speedregs(sys_freq_hz,priv->speed,&priv->timing);
+ ret = occan_calc_speedregs(priv->sys_freq_hz,priv->speed,&priv->timing);
if ( ret ){
/* failed to set speed for this system freq, try with 50K instead */
priv->speed = OCCAN_SPEED_50K;
- occan_calc_speedregs(sys_freq_hz,priv->speed,&priv->timing);
+ occan_calc_speedregs(priv->sys_freq_hz, priv->speed,
+ &priv->timing);
}
/* disable all interrupts */
- priv->regs->inten = 0;
+ WRITE_REG(priv, &priv->regs->inten, 0);
/* clear pending interrupts by reading */
- tmp = READ_REG(&priv->regs->intflags);
+ tmp = READ_REG(priv, &priv->regs->intflags);
}
static int pelican_start(occan_priv *priv){
@@ -440,21 +819,22 @@ static int pelican_start(occan_priv *priv){
if ( !priv->rxfifo || !priv->txfifo )
return -1;
- /* In case we were started before and stopped we
- * should empty the TX fifo or try to resend those
- * messages. We make it simple...
- */
- occan_fifo_clr(priv->txfifo);
+ /* In case we were started before and stopped we
+ * should empty the TX fifo or try to resend those
+ * messages. We make it simple...
+ */
+ occan_fifo_clr(priv->txfifo);
/* Clear status bits */
priv->status = 0;
+ priv->sending = 0;
/* clear pending interrupts */
- tmp = READ_REG(&priv->regs->intflags);
+ tmp = READ_REG(priv, &priv->regs->intflags);
/* clear error counters */
- priv->regs->rx_err_cnt = 0;
- priv->regs->tx_err_cnt = 0;
+ WRITE_REG(priv, &priv->regs->rx_err_cnt, 0);
+ WRITE_REG(priv, &priv->regs->tx_err_cnt, 0);
#ifdef REDUNDANT_CHANNELS
if ( (priv->channel == 0) || (priv->channel >= REDUNDANT_CHANNELS) ){
@@ -468,15 +848,21 @@ static int pelican_start(occan_priv *priv){
/* set the speed regs of the CAN core */
occan_set_speedregs(priv,&priv->timing);
- DBG("OCCAN: start: set timing regs btr0: 0x%x, btr1: 0x%x\n\r",READ_REG(&priv->regs->bustim0),READ_REG(&priv->regs->bustim1));
+ DBG("OCCAN: start: set timing regs btr0: 0x%x, btr1: 0x%x\n\r",
+ READ_REG(priv, &priv->regs->bustim0),
+ READ_REG(priv, &priv->regs->bustim1));
/* Set default acceptance filter */
pelican_set_accept(priv,priv->acode,priv->amask);
- /* turn on interrupts */
- priv->regs->inten = PELICAN_IE_RX | PELICAN_IE_TX | PELICAN_IE_ERRW |
- PELICAN_IE_ERRP | PELICAN_IE_BUS;
+ /* Nothing can fail from here, this must be set before interrupts are
+ * enabled */
+ priv->started = 1;
+ /* turn on interrupts */
+ WRITE_REG(priv, &priv->regs->inten,
+ PELICAN_IE_RX | PELICAN_IE_TX | PELICAN_IE_ERRW |
+ PELICAN_IE_ERRP | PELICAN_IE_BUS);
#ifdef DEBUG
/* print setup before starting */
pelican_regs_print(priv->regs);
@@ -484,17 +870,23 @@ static int pelican_start(occan_priv *priv){
#endif
/* core already in reset mode,
- * ¤ Exit reset mode
+ * ¤ Exit reset mode
* ¤ Enter Single/Dual mode filtering.
*/
- priv->regs->mode = (priv->single_mode << 3);
+ WRITE_REG(priv, &priv->regs->mode, (priv->single_mode << 3));
+
+ /* Register interrupt routine and unmask IRQ at IRQ controller */
+ drvmgr_interrupt_register(priv->dev, 0, "occan", occan_interrupt, priv);
return 0;
}
-static void pelican_stop(occan_priv *priv){
+static void pelican_stop(occan_priv *priv)
+{
/* stop HW */
+ drvmgr_interrupt_unregister(priv->dev, 0, occan_interrupt, priv);
+
#ifdef DEBUG
/* print setup before stopping */
pelican_regs_print(priv->regs);
@@ -502,14 +894,28 @@ static void pelican_stop(occan_priv *priv){
#endif
/* put core in reset mode */
- priv->regs->mode = PELICAN_MOD_RESET;
+ WRITE_REG(priv, &priv->regs->mode, PELICAN_MOD_RESET);
/* turn off interrupts */
- priv->regs->inten = 0;
+ WRITE_REG(priv, &priv->regs->inten, 0);
priv->status |= OCCAN_STATUS_RESET;
}
+static inline int pelican_tx_ready(occan_priv *can)
+{
+ unsigned char status;
+ pelican_regs *regs = can->regs;
+
+ /* is there room in send buffer? */
+ status = READ_REG(can, &regs->status);
+ if ( !(status & PELICAN_STAT_TXBUF) ) {
+ /* tx fifo taken, we have to wait */
+ return 0;
+ }
+
+ return 1;
+}
/* Try to send message "msg", if hardware txfifo is
* full, then -1 is returned.
@@ -518,12 +924,11 @@ static void pelican_stop(occan_priv *priv){
* entering this function.
*/
static int pelican_send(occan_priv *can, CANMsg *msg){
- unsigned char tmp,status;
+ unsigned char tmp;
pelican_regs *regs = can->regs;
/* is there room in send buffer? */
- status = READ_REG(&regs->status);
- if ( !(status & PELICAN_STAT_TXBUF) ){
+ if ( !pelican_tx_ready(can) ) {
/* tx fifo taken, we have to wait */
return -1;
}
@@ -534,39 +939,40 @@ static int pelican_send(occan_priv *can, CANMsg *msg){
if ( msg->extended ){
/* Extended Frame */
- regs->rx_fi_xff = 0x80 | tmp;
- WRITE_REG(&regs->msg.tx_eff.id[0],(msg->id >> (5+8+8)) & 0xff);
- WRITE_REG(&regs->msg.tx_eff.id[1],(msg->id >> (5+8)) & 0xff);
- WRITE_REG(&regs->msg.tx_eff.id[2],(msg->id >> (5)) & 0xff);
- WRITE_REG(&regs->msg.tx_eff.id[3],(msg->id << 3) & 0xf8);
+ WRITE_REG(can, &regs->rx_fi_xff, 0x80 | tmp);
+ WRITE_REG(can, &regs->msg.tx_eff.id[0],(msg->id >> (5+8+8)) & 0xff);
+ WRITE_REG(can, &regs->msg.tx_eff.id[1],(msg->id >> (5+8)) & 0xff);
+ WRITE_REG(can, &regs->msg.tx_eff.id[2],(msg->id >> (5)) & 0xff);
+ WRITE_REG(can, &regs->msg.tx_eff.id[3],(msg->id << 3) & 0xf8);
tmp = msg->len;
while(tmp--){
- WRITE_REG(&regs->msg.tx_eff.data[tmp],msg->data[tmp]);
+ WRITE_REG(can, &regs->msg.tx_eff.data[tmp], msg->data[tmp]);
}
}else{
/* Standard Frame */
- regs->rx_fi_xff = tmp;
- WRITE_REG(&regs->msg.tx_sff.id[0],(msg->id >> 3) & 0xff);
- WRITE_REG(&regs->msg.tx_sff.id[1],(msg->id << 5) & 0xe0);
+ WRITE_REG(can, &regs->rx_fi_xff, tmp);
+ WRITE_REG(can, &regs->msg.tx_sff.id[0],(msg->id >> 3) & 0xff);
+ WRITE_REG(can, &regs->msg.tx_sff.id[1],(msg->id << 5) & 0xe0);
tmp = msg->len;
while(tmp--){
- WRITE_REG(&regs->msg.tx_sff.data[tmp],msg->data[tmp]);
+ WRITE_REG(can, &regs->msg.tx_sff.data[tmp],msg->data[tmp]);
}
}
/* let HW know of new message */
if ( msg->sshot ){
- regs->cmd = PELICAN_CMD_TXREQ | PELICAN_CMD_ABORT;
+ WRITE_REG(can, &regs->cmd, PELICAN_CMD_TXREQ | PELICAN_CMD_ABORT);
}else{
/* normal case -- try resend until sent */
- regs->cmd = PELICAN_CMD_TXREQ;
+ WRITE_REG(can, &regs->cmd, PELICAN_CMD_TXREQ);
}
return 0;
}
-static void pelican_set_accept(occan_priv *priv, unsigned char *acode, unsigned char *amask){
+static void pelican_set_accept(occan_priv *priv, unsigned char *acode, unsigned char *amask)
+{
unsigned char *acode0, *acode1, *acode2, *acode3;
unsigned char *amask0, *amask1, *amask2, *amask3;
@@ -581,159 +987,17 @@ static void pelican_set_accept(occan_priv *priv, unsigned char *acode, unsigned
amask3 = (unsigned char *)&priv->regs->msg.rst_accept.mask[3];
/* Set new mask & code */
- *acode0 = acode[0];
- *acode1 = acode[1];
- *acode2 = acode[2];
- *acode3 = acode[3];
-
- *amask0 = amask[0];
- *amask1 = amask[1];
- *amask2 = amask[2];
- *amask3 = amask[3];
-}
-
-#ifdef DEBUG
-static void pelican_regs_print(pelican_regs *regs){
- printk("--- PELICAN 0x%lx ---\n\r",(unsigned int)regs);
- printk(" MODE: 0x%02x\n\r",READ_REG(&regs->mode));
- printk(" CMD: 0x%02x\n\r",READ_REG(&regs->cmd));
- printk(" STATUS: 0x%02x\n\r",READ_REG(&regs->status));
- /*printk(" INTFLG: 0x%02x\n\r",READ_REG(&regs->intflags));*/
- printk(" INTEN: 0x%02x\n\r",READ_REG(&regs->inten));
- printk(" BTR0: 0x%02x\n\r",READ_REG(&regs->bustim0));
- printk(" BTR1: 0x%02x\n\r",READ_REG(&regs->bustim1));
- printk(" ARBCODE: 0x%02x\n\r",READ_REG(&regs->arbcode));
- printk(" ERRCODE: 0x%02x\n\r",READ_REG(&regs->errcode));
- printk(" ERRWARN: 0x%02x\n\r",READ_REG(&regs->errwarn));
- printk(" RX_ERR_CNT: 0x%02x\n\r",READ_REG(&regs->rx_err_cnt));
- printk(" TX_ERR_CNT: 0x%02x\n\r",READ_REG(&regs->tx_err_cnt));
- if ( READ_REG(&regs->mode) & PELICAN_MOD_RESET ){
- /* in reset mode it is possible to read acceptance filters */
- printk(" ACR0: 0x%02x (0x%lx)\n\r",READ_REG(&regs->rx_fi_xff),&regs->rx_fi_xff);
- printk(" ACR1: 0x%02x (0x%lx)\n\r",READ_REG(&regs->msg.rst_accept.code[0]),(unsigned int)&regs->msg.rst_accept.code[0]);
- printk(" ACR1: 0x%02x (0x%lx)\n\r",READ_REG(&regs->msg.rst_accept.code[1]),(unsigned int)&regs->msg.rst_accept.code[1]);
- printk(" ACR1: 0x%02x (0x%lx)\n\r",READ_REG(&regs->msg.rst_accept.code[2]),(unsigned int)&regs->msg.rst_accept.code[2]);
- printk(" AMR0: 0x%02x (0x%lx)\n\r",READ_REG(&regs->msg.rst_accept.mask[0]),(unsigned int)&regs->msg.rst_accept.mask[0]);
- printk(" AMR1: 0x%02x (0x%lx)\n\r",READ_REG(&regs->msg.rst_accept.mask[1]),(unsigned int)&regs->msg.rst_accept.mask[1]);
- printk(" AMR2: 0x%02x (0x%lx)\n\r",READ_REG(&regs->msg.rst_accept.mask[2]),(unsigned int)&regs->msg.rst_accept.mask[2]);
- printk(" AMR3: 0x%02x (0x%lx)\n\r",READ_REG(&regs->msg.rst_accept.mask[3]),(unsigned int)&regs->msg.rst_accept.mask[3]);
-
- }else{
- printk(" RXFI_XFF: 0x%02x\n\r",READ_REG(&regs->rx_fi_xff));
- }
- printk(" RX_MSG_CNT: 0x%02x\n\r",READ_REG(&regs->rx_msg_cnt));
- printk(" CLKDIV: 0x%02x\n\r",READ_REG(&regs->clkdiv));
- printk("-------------------\n\r");
+ WRITE_REG(priv, acode0, acode[0]);
+ WRITE_REG(priv, acode1, acode[1]);
+ WRITE_REG(priv, acode2, acode[2]);
+ WRITE_REG(priv, acode3, acode[3]);
+
+ WRITE_REG(priv, amask0, amask[0]);
+ WRITE_REG(priv, amask1, amask[1]);
+ WRITE_REG(priv, amask2, amask[2]);
+ WRITE_REG(priv, amask3, amask[3]);
}
-#endif
-#ifdef DEBUG_PRINT_REGMAP
-static void pelican_regadr_print(pelican_regs *regs){
- printk("--- PELICAN 0x%lx ---\n\r",(unsigned int)regs);
- printk(" MODE: 0x%lx\n\r",(unsigned int)&regs->mode);
- printk(" CMD: 0x%lx\n\r",(unsigned int)&regs->cmd);
- printk(" STATUS: 0x%lx\n\r",(unsigned int)&regs->status);
- /*printk(" INTFLG: 0x%lx\n\r",&regs->intflags);*/
- printk(" INTEN: 0x%lx\n\r",(unsigned int)&regs->inten);
- printk(" BTR0: 0x%lx\n\r",(unsigned int)&regs->bustim0);
- printk(" BTR1: 0x%lx\n\r",(unsigned int)&regs->bustim1);
- printk(" ARBCODE: 0x%lx\n\r",(unsigned int)&regs->arbcode);
- printk(" ERRCODE: 0x%lx\n\r",(unsigned int)&regs->errcode);
- printk(" ERRWARN: 0x%lx\n\r",(unsigned int)&regs->errwarn);
- printk(" RX_ERR_CNT: 0x%lx\n\r",(unsigned int)&regs->rx_err_cnt);
- printk(" TX_ERR_CNT: 0x%lx\n\r",(unsigned int)&regs->tx_err_cnt);
-
- /* in reset mode it is possible to read acceptance filters */
- printk(" RXFI_XFF: 0x%lx\n\r",(unsigned int)&regs->rx_fi_xff);
-
- /* reset registers */
- printk(" ACR0: 0x%lx\n\r",(unsigned int)&regs->rx_fi_xff);
- printk(" ACR1: 0x%lx\n\r",(unsigned int)&regs->msg.rst_accept.code[0]);
- printk(" ACR2: 0x%lx\n\r",(unsigned int)&regs->msg.rst_accept.code[1]);
- printk(" ACR3: 0x%lx\n\r",(unsigned int)&regs->msg.rst_accept.code[2]);
- printk(" AMR0: 0x%lx\n\r",(unsigned int)&regs->msg.rst_accept.mask[0]);
- printk(" AMR1: 0x%lx\n\r",(unsigned int)&regs->msg.rst_accept.mask[1]);
- printk(" AMR2: 0x%lx\n\r",(unsigned int)&regs->msg.rst_accept.mask[2]);
- printk(" AMR3: 0x%lx\n\r",(unsigned int)&regs->msg.rst_accept.mask[3]);
-
- /* TX Extended */
- printk(" EFFTX_ID[0]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_eff.id[0]);
- printk(" EFFTX_ID[1]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_eff.id[1]);
- printk(" EFFTX_ID[2]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_eff.id[2]);
- printk(" EFFTX_ID[3]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_eff.id[3]);
-
- printk(" EFFTX_DATA[0]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_eff.data[0]);
- printk(" EFFTX_DATA[1]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_eff.data[1]);
- printk(" EFFTX_DATA[2]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_eff.data[2]);
- printk(" EFFTX_DATA[3]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_eff.data[3]);
- printk(" EFFTX_DATA[4]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_eff.data[4]);
- printk(" EFFTX_DATA[5]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_eff.data[5]);
- printk(" EFFTX_DATA[6]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_eff.data[6]);
- printk(" EFFTX_DATA[7]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_eff.data[7]);
-
- /* RX Extended */
- printk(" EFFRX_ID[0]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_eff.id[0]);
- printk(" EFFRX_ID[1]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_eff.id[1]);
- printk(" EFFRX_ID[2]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_eff.id[2]);
- printk(" EFFRX_ID[3]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_eff.id[3]);
-
- printk(" EFFRX_DATA[0]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_eff.data[0]);
- printk(" EFFRX_DATA[1]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_eff.data[1]);
- printk(" EFFRX_DATA[2]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_eff.data[2]);
- printk(" EFFRX_DATA[3]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_eff.data[3]);
- printk(" EFFRX_DATA[4]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_eff.data[4]);
- printk(" EFFRX_DATA[5]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_eff.data[5]);
- printk(" EFFRX_DATA[6]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_eff.data[6]);
- printk(" EFFRX_DATA[7]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_eff.data[7]);
-
-
- /* RX Extended */
- printk(" SFFRX_ID[0]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_sff.id[0]);
- printk(" SFFRX_ID[1]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_sff.id[1]);
-
- printk(" SFFRX_DATA[0]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_sff.data[0]);
- printk(" SFFRX_DATA[1]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_sff.data[1]);
- printk(" SFFRX_DATA[2]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_sff.data[2]);
- printk(" SFFRX_DATA[3]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_sff.data[3]);
- printk(" SFFRX_DATA[4]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_sff.data[4]);
- printk(" SFFRX_DATA[5]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_sff.data[5]);
- printk(" SFFRX_DATA[6]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_sff.data[6]);
- printk(" SFFRX_DATA[7]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_sff.data[7]);
-
- /* TX Extended */
- printk(" SFFTX_ID[0]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_sff.id[0]);
- printk(" SFFTX_ID[1]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_sff.id[1]);
-
- printk(" SFFTX_DATA[0]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_sff.data[0]);
- printk(" SFFTX_DATA[1]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_sff.data[1]);
- printk(" SFFTX_DATA[2]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_sff.data[2]);
- printk(" SFFTX_DATA[3]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_sff.data[3]);
- printk(" SFFTX_DATA[4]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_sff.data[4]);
- printk(" SFFTX_DATA[5]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_sff.data[5]);
- printk(" SFFTX_DATA[6]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_sff.data[6]);
- printk(" SFFTX_DATA[7]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_sff.data[7]);
-
- printk(" RX_MSG_CNT: 0x%lx\n\r",(unsigned int)&regs->rx_msg_cnt);
- printk(" CLKDIV: 0x%lx\n\r",(unsigned int)&regs->clkdiv);
- printk("-------------------\n\r");
-}
-#endif
-
-#ifdef DEBUG
-static void occan_stat_print(occan_stats *stats){
- printk("----Stats----\n\r");
- printk("rx_msgs: %d\n\r",stats->rx_msgs);
- printk("tx_msgs: %d\n\r",stats->tx_msgs);
- printk("err_warn: %d\n\r",stats->err_warn);
- printk("err_dovr: %d\n\r",stats->err_dovr);
- printk("err_errp: %d\n\r",stats->err_errp);
- printk("err_arb: %d\n\r",stats->err_arb);
- printk("err_bus: %d\n\r",stats->err_bus);
- printk("Int cnt: %d\n\r",stats->ints);
- printk("tx_buf_err: %d\n\r",stats->tx_buf_error);
- printk("-------------\n\r");
-}
-#endif
/* This function calculates BTR0 and BTR1 values for a given bitrate.
*
@@ -743,7 +1007,8 @@ static void occan_stat_print(occan_stats *stats){
* \param result Pointer to where resulting BTRs will be stored.
* \return zero if successful to calculate a baud rate.
*/
-static int occan_calc_speedregs(unsigned int clock_hz, unsigned int rate, occan_speed_regs *result){
+static int occan_calc_speedregs(unsigned int clock_hz, unsigned int rate, occan_speed_regs *result)
+{
int best_error = 1000000000;
int error;
int best_tseg=0, best_brp=0, best_rate=0, brp=0;
@@ -827,12 +1092,14 @@ static int occan_calc_speedregs(unsigned int clock_hz, unsigned int rate, occan_
return 0;
}
-static int occan_set_speedregs(occan_priv *priv, occan_speed_regs *timing){
+static int occan_set_speedregs(occan_priv *priv, occan_speed_regs *timing)
+{
if ( !timing || !priv || !priv->regs)
return -1;
- priv->regs->bustim0 = timing->btr0;
- priv->regs->bustim1 = timing->btr1;
+ WRITE_REG(priv, &priv->regs->bustim0, timing->btr0);
+ WRITE_REG(priv, &priv->regs->bustim1, timing->btr1);
+
return 0;
}
@@ -861,7 +1128,7 @@ static int pelican_speed_auto(occan_priv *priv){
while ( (speed=pelican_speed_auto_steplist[i]) > 0){
/* Reset core */
- priv->regs->mode = PELICAN_MOD_RESET;
+ WRITE_REG(priv, &priv->regs->mode, PELICAN_MOD_RESET);
/* tell int handler about the auto speed detection test */
@@ -873,7 +1140,7 @@ static int pelican_speed_auto(occan_priv *priv){
pelican_set_accept(priv);
/* calc timing params for this */
- if ( occan_calc_speedregs(sys_freq_hz,speed,&timing) ){
+ if ( occan_calc_speedregs(priv->sys_freq_hz,speed,&timing) ){
/* failed to get good timings for this frequency
* test with next
*/
@@ -887,13 +1154,13 @@ static int pelican_speed_auto(occan_priv *priv){
/* Empty previous messages in hardware RX fifo */
/*
- while( READ_REG(&priv->regs->) ){
+ while( READ_REG(priv, &priv->regs->) ){
}
*/
/* Clear pending interrupts */
- tmp = READ_REG(&priv->regs->intflags);
+ tmp = READ_REG(priv, &priv->regs->intflags);
/* enable RX & ERR interrupt */
priv->regs->inten =
@@ -911,172 +1178,23 @@ static int pelican_speed_auto(occan_priv *priv){
#endif
}
-
-static rtems_device_driver occan_initialize(rtems_device_major_number major, rtems_device_minor_number unused, void *arg){
- int dev_cnt,minor,subcore_cnt,devi,subi,subcores;
- amba_ahb_device ambadev;
- occan_priv *can;
- char fs_name[20];
- rtems_status_code status;
-
- strcpy(fs_name,OCCAN_DEVNAME);
-
- /* find device on amba bus */
- dev_cnt = amba_get_number_ahbslv_devices(amba_bus,VENDOR_GAISLER,GAISLER_OCCAN);
- if ( dev_cnt < 1 ){
- /* Failed to find any CAN cores! */
- printk("OCCAN: Failed to find any CAN cores\n\r");
- return -1;
- }
-
- /* Detect System Frequency from initialized timer */
-#ifndef SYS_FREQ_HZ
-#if defined(LEON3)
- /* LEON3: find timer address via AMBA Plug&Play info */
- {
- amba_apb_device gptimer;
- LEON3_Timer_Regs_Map *tregs;
-
- if ( amba_find_apbslv(&amba_conf,VENDOR_GAISLER,GAISLER_GPTIMER,&gptimer) == 1 ){
- tregs = (LEON3_Timer_Regs_Map *)gptimer.start;
- sys_freq_hz = (tregs->scaler_reload+1)*1000*1000;
- DBG("OCCAN: detected %dHZ system frequency\n\r",sys_freq_hz);
- }else{
- sys_freq_hz = 40000000; /* Default to 40MHz */
- printk("OCCAN: Failed to detect system frequency\n\r");
- }
-
- }
-#elif defined(LEON2)
- /* LEON2: use hardcoded address to get to timer */
- {
- LEON_Register_Map *regs = (LEON_Register_Map *)0x80000000;
- sys_freq_hz = (regs->Scaler_Reload+1)*1000*1000;
- }
-#else
- #error CPU not supported for OC_CAN driver
-#endif
-#else
- /* Use hardcoded frequency */
- sys_freq_hz = SYS_FREQ_HZ;
-#endif
-
- DBG("OCCAN: Detected %dHz system frequency\n\r",sys_freq_hz);
-
- /* OCCAN speciality:
- * Mulitple cores are supported through the same amba AHB interface.
- * The number of "sub cores" can be detected by decoding the AMBA
- * Plug&Play version information. verion = ncores. A maximum of 8
- * sub cores are supported, each separeated with 0x100 inbetween.
- *
- * Now, lets detect sub cores.
- */
-
- for(subcore_cnt=devi=0; devi<dev_cnt; devi++){
- amba_find_next_ahbslv(amba_bus,VENDOR_GAISLER,GAISLER_OCCAN,&ambadev,devi);
- subcore_cnt += (ambadev.ver & 0x7)+1;
- }
-
- printk("OCCAN: Found %d devs, totally %d sub cores\n\r",dev_cnt,subcore_cnt);
-
- /* allocate memory for cores */
- can_cores = subcore_cnt;
- cans = calloc(subcore_cnt*sizeof(occan_priv),1);
-
- minor=0;
- for(devi=0; devi<dev_cnt; devi++){
-
- /* Get AHB device info */
- amba_find_next_ahbslv(amba_bus,VENDOR_GAISLER,GAISLER_OCCAN,&ambadev,devi);
- subcores = (ambadev.ver & 0x7)+1;
- DBG("OCCAN: on dev %d found %d sub cores\n\r",devi,subcores);
-
- /* loop all subcores, at least 1 */
- for(subi=0; subi<subcores; subi++){
- can = &cans[minor];
-
-#ifdef OCCAN_BYTE_REGS
- /* regs is byte regs */
- can->regs = (void *)(ambadev.start[0] + OCCAN_NCORE_OFS*subi);
-#else
- /* regs is word regs, accessed 0x100 from base address */
- can->regs = (void *)(ambadev.start[0] + OCCAN_NCORE_OFS*subi+ OCCAN_WORD_REG_OFS);
-#endif
-
- /* remember IRQ number */
- can->irq = ambadev.irq+subi;
-
- /* bind filesystem name to device */
- OCCAN_DEVNAME_NO(fs_name,minor);
- printk("OCCAN: Registering %s to [%d %d] @ 0x%lx irq %d\n\r",fs_name,major,minor,(unsigned int)can->regs,can->irq);
- status = rtems_io_register_name(fs_name, major, minor);
- if (RTEMS_SUCCESSFUL != status )
- rtems_fatal_error_occurred(status);
-
- /* initialize software */
- can->open = 0;
- can->rxfifo = NULL;
- can->txfifo = NULL;
- status = rtems_semaphore_create(
- rtems_build_name('C', 'd', 'v', '0'+minor),
- 1,
- RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | \
- RTEMS_NO_PRIORITY_CEILING,
- 0,
- &can->devsem);
- if ( status != RTEMS_SUCCESSFUL ){
- printk("OCCAN: Failed to create dev semaphore for minor %d, (%d)\n\r",minor,status);
- return RTEMS_UNSATISFIED;
- }
- status = rtems_semaphore_create(
- rtems_build_name('C', 't', 'x', '0'+minor),
- 0,
- RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | \
- RTEMS_NO_PRIORITY_CEILING,
- 0,
- &can->txsem);
- if ( status != RTEMS_SUCCESSFUL ){
- printk("OCCAN: Failed to create tx semaphore for minor %d, (%d)\n\r",minor,status);
- return RTEMS_UNSATISFIED;
- }
- status = rtems_semaphore_create(
- rtems_build_name('C', 'r', 'x', '0'+minor),
- 0,
- RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | \
- RTEMS_NO_PRIORITY_CEILING,
- 0,
- &can->rxsem);
- if ( status != RTEMS_SUCCESSFUL ){
- printk("OCCAN: Failed to create rx semaphore for minor %d, (%d)\n\r",minor,status);
- return RTEMS_UNSATISFIED;
- }
-
- /* hardware init/reset */
- pelican_init(can);
-
- /* Setup interrupt handler for each channel */
- OCCAN_REG_INT(OCCAN_PREFIX(_interrupt_handler), can->irq, can);
-
- minor++;
-#ifdef DEBUG_PRINT_REGMAP
- pelican_regadr_print(can->regs);
-#endif
- }
- }
-
+static rtems_device_driver occan_initialize(rtems_device_major_number major, rtems_device_minor_number unused, void *arg)
+{
return RTEMS_SUCCESSFUL;
}
static rtems_device_driver occan_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg){
occan_priv *can;
+ struct drvmgr_dev *dev;
DBG("OCCAN: Opening %d\n\r",minor);
- if ( minor >= can_cores )
+ /* get can device */
+ if ( drvmgr_get_dev(&occan_drv_info.general, minor, &dev) ) {
+ DBG("Wrong minor %d\n", minor);
return RTEMS_UNSATISFIED; /* NODEV */
-
- /* get can device */
- can = &cans[minor];
+ }
+ can = (occan_priv *)dev->priv;
/* already opened? */
rtems_semaphore_obtain(can->devsem,RTEMS_WAIT, RTEMS_NO_TIMEOUT);
@@ -1122,17 +1240,24 @@ static rtems_device_driver occan_open(rtems_device_major_number major, rtems_dev
return RTEMS_SUCCESSFUL;
}
-static rtems_device_driver occan_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg){
- occan_priv *can = &cans[minor];
+static rtems_device_driver occan_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ occan_priv *can;
+ struct drvmgr_dev *dev;
DBG("OCCAN: Closing %d\n\r",minor);
+ if ( drvmgr_get_dev(&occan_drv_info.general, minor, &dev) ) {
+ return RTEMS_INVALID_NAME;
+ }
+ can = (occan_priv *)dev->priv;
+
/* stop if running */
if ( can->started )
pelican_stop(can);
/* Enter Reset Mode */
- can->regs->mode = PELICAN_MOD_RESET;
+ WRITE_REG(can, &can->regs->mode, PELICAN_MOD_RESET);
/* free fifo memory */
occan_fifo_free(can->rxfifo);
@@ -1141,16 +1266,24 @@ static rtems_device_driver occan_close(rtems_device_major_number major, rtems_de
can->rxfifo = NULL;
can->txfifo = NULL;
+ can->open = 0;
+
return RTEMS_SUCCESSFUL;
}
static rtems_device_driver occan_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg){
- occan_priv *can = &cans[minor];
+ occan_priv *can;
+ struct drvmgr_dev *dev;
rtems_libio_rw_args_t *rw_args=(rtems_libio_rw_args_t *) arg;
CANMsg *dstmsg, *srcmsg;
rtems_interrupt_level oldLevel;
int left;
+ if ( drvmgr_get_dev(&occan_drv_info.general, minor, &dev) ) {
+ return RTEMS_INVALID_NAME;
+ }
+ can = (occan_priv *)dev->priv;
+
if ( !can->started ){
DBG("OCCAN: cannot read from minor %d when not started\n\r",minor);
return RTEMS_RESOURCE_IN_USE; /* -EBUSY*/
@@ -1201,8 +1334,9 @@ static rtems_device_driver occan_read(rtems_device_major_number major, rtems_dev
DBG("OCCAN: Waiting for RX int\n\r");
- /* wait for incomming messages */
- rtems_semaphore_obtain(can->rxsem,RTEMS_WAIT,RTEMS_NO_TIMEOUT);
+ /* wait for incoming messages */
+ rtems_semaphore_obtain(can->rxsem, RTEMS_WAIT,
+ RTEMS_NO_TIMEOUT);
/* did we get woken up by a BUS OFF error? */
if ( can->status & (OCCAN_STATUS_ERR_BUSOFF|OCCAN_STATUS_RESET) ){
@@ -1240,7 +1374,8 @@ static rtems_device_driver occan_read(rtems_device_major_number major, rtems_dev
}
static rtems_device_driver occan_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg){
- occan_priv *can = &cans[minor];
+ occan_priv *can;
+ struct drvmgr_dev *dev;
rtems_libio_rw_args_t *rw_args=(rtems_libio_rw_args_t *) arg;
CANMsg *msg,*fifo_msg;
rtems_interrupt_level oldLevel;
@@ -1248,6 +1383,11 @@ static rtems_device_driver occan_write(rtems_device_major_number major, rtems_de
DBG("OCCAN: Writing %d bytes from 0x%lx (%d)\n\r",rw_args->count,rw_args->buffer,sizeof(CANMsg));
+ if ( drvmgr_get_dev(&occan_drv_info.general, minor, &dev) ) {
+ return RTEMS_INVALID_NAME;
+ }
+ can = (occan_priv *)dev->priv;
+
if ( !can->started )
return RTEMS_RESOURCE_IN_USE; /* EBUSY */
@@ -1289,6 +1429,11 @@ static rtems_device_driver occan_write(rtems_device_major_number major, rtems_de
left -= sizeof(CANMsg);
msg++;
+#ifdef OCCAN_TX_IRQ_FLAG_FIXUP
+ /* Mark that we have put at least one msg in TX FIFO */
+ can->sending = 1;
+#endif
+
/* bump stat counters */
can->stats.tx_msgs++;
@@ -1337,11 +1482,16 @@ static rtems_device_driver occan_write(rtems_device_major_number major, rtems_de
if ( occan_fifo_empty(can->txfifo) ){
if ( !pelican_send(can,msg) ) {
/* First message put directly into HW TX fifo
- * This will turn TX interrupt on.
- */
+ * This will turn TX interrupt on.
+ */
left -= sizeof(CANMsg);
msg++;
+#ifdef OCCAN_TX_IRQ_FLAG_FIXUP
+ /* Mark that we have put at least one msg in TX FIFO */
+ can->sending = 1;
+#endif
+
/* bump stat counters */
can->stats.tx_msgs++;
@@ -1377,15 +1527,21 @@ static rtems_device_driver occan_write(rtems_device_major_number major, rtems_de
static rtems_device_driver occan_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg){
int ret;
occan_speed_regs timing;
- occan_priv *can = &cans[minor];
+ occan_priv *can;
+ struct drvmgr_dev *dev;
unsigned int speed;
- rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *) arg;
+ rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *) arg;
struct occan_afilter *afilter;
occan_stats *dststats;
unsigned int rxcnt,txcnt;
DBG("OCCAN: IOCTL %d\n\r",ioarg->command);
+ if ( drvmgr_get_dev(&occan_drv_info.general, minor, &dev) ) {
+ return RTEMS_INVALID_NAME;
+ }
+ can = (occan_priv *)dev->priv;
+
ioarg->ioctl_return = 0;
switch(ioarg->command){
case OCCAN_IOC_SET_SPEED:
@@ -1396,7 +1552,7 @@ static rtems_device_driver occan_ioctl(rtems_device_major_number major, rtems_de
/* get speed rate from argument */
speed = (unsigned int)ioarg->buffer;
- ret = occan_calc_speedregs(sys_freq_hz,speed,&timing);
+ ret = occan_calc_speedregs(can->sys_freq_hz,speed,&timing);
if ( ret )
return RTEMS_INVALID_NAME; /* EINVAL */
@@ -1475,8 +1631,8 @@ static rtems_device_driver occan_ioctl(rtems_device_major_number major, rtems_de
return RTEMS_INVALID_NAME; /* EINVAL */
/* copy data stats into userspace buffer */
- if ( can->rxfifo )
- can->stats.rx_sw_dovr = can->rxfifo->ovcnt;
+ if ( can->rxfifo )
+ can->stats.rx_sw_dovr = can->rxfifo->ovcnt;
*dststats = can->stats;
break;
@@ -1539,7 +1695,9 @@ static rtems_device_driver occan_ioctl(rtems_device_major_number major, rtems_de
return RTEMS_RESOURCE_IN_USE; /* EBUSY */
if ( pelican_start(can) )
return RTEMS_NO_MEMORY; /* failed because of no memory, can happen if SET_BUFLEN failed */
- can->started = 1;
+ /* can->started = 1; -- Is set in pelican_start due to interrupt may occur before we
+ * get here.
+ */
break;
case OCCAN_IOC_STOP:
@@ -1555,7 +1713,9 @@ static rtems_device_driver occan_ioctl(rtems_device_major_number major, rtems_de
return RTEMS_SUCCESSFUL;
}
-static void occan_interrupt(occan_priv *can){
+void occan_interrupt(void *arg)
+{
+ occan_priv *can = arg;
unsigned char iflags;
pelican_regs *regs = can->regs;
CANMsg *msg;
@@ -1563,11 +1723,33 @@ static void occan_interrupt(occan_priv *can){
unsigned char tmp, errcode, arbcode;
int tx_error_cnt,rx_error_cnt;
- can->stats.ints++;
+ if ( !can->started )
+ return; /* Spurious Interrupt, do nothing */
+
+ while (1) {
+
+ iflags = READ_REG(can, &can->regs->intflags);
+
+#ifdef OCCAN_TX_IRQ_FLAG_FIXUP
+ /* TX IRQ may be cleared when reading regs->intflags due
+ * to a bug in some chips. Instead of looking at the TX_IRQ_FLAG
+ * the TX-fifo emoty register is looked at when something has
+ * been scheduled for transmission.
+ */
+ if ((iflags & PELICAN_IF_TX) == 0) {
+ if (can->sending && pelican_tx_ready(can)) {
+ can->sending = 0;
+ iflags |= PELICAN_IF_TX;
+ }
+ }
+#endif
- while ( (iflags = READ_REG(&can->regs->intflags)) != 0 ){
+ if (iflags == 0)
+ break;
/* still interrupts to handle */
+ can->stats.ints++;
+
if ( iflags & PELICAN_IF_RX ){
/* the rx fifo is not empty
* put 1 message into rxfifo for later use
@@ -1575,52 +1757,53 @@ static void occan_interrupt(occan_priv *can){
/* get empty (or make room) message */
msg = occan_fifo_put_claim(can->rxfifo,1);
- tmp = READ_REG(&regs->rx_fi_xff);
+ tmp = READ_REG(can, &regs->rx_fi_xff);
msg->extended = tmp >> 7;
msg->rtr = (tmp >> 6) & 1;
msg->len = tmp = tmp & 0x0f;
if ( msg->extended ){
/* extended message */
- msg->id = READ_REG(&regs->msg.rx_eff.id[0])<<(5+8+8) |
- READ_REG(&regs->msg.rx_eff.id[1])<<(5+8) |
- READ_REG(&regs->msg.rx_eff.id[2])<<5 |
- READ_REG(&regs->msg.rx_eff.id[3])>>3;
+ msg->id = READ_REG(can, &regs->msg.rx_eff.id[0])<<(5+8+8) |
+ READ_REG(can, &regs->msg.rx_eff.id[1])<<(5+8) |
+ READ_REG(can, &regs->msg.rx_eff.id[2])<<5 |
+ READ_REG(can, &regs->msg.rx_eff.id[3])>>3;
+
while(tmp--){
- msg->data[tmp] = READ_REG(&regs->msg.rx_eff.data[tmp]);
+ msg->data[tmp] = READ_REG(can, &regs->msg.rx_eff.data[tmp]);
}
/*
- msg->data[0] = READ_REG(&regs->msg.rx_eff.data[0]);
- msg->data[1] = READ_REG(&regs->msg.rx_eff.data[1]);
- msg->data[2] = READ_REG(&regs->msg.rx_eff.data[2]);
- msg->data[3] = READ_REG(&regs->msg.rx_eff.data[3]);
- msg->data[4] = READ_REG(&regs->msg.rx_eff.data[4]);
- msg->data[5] = READ_REG(&regs->msg.rx_eff.data[5]);
- msg->data[6] = READ_REG(&regs->msg.rx_eff.data[6]);
- msg->data[7] = READ_REG(&regs->msg.rx_eff.data[7]);
+ msg->data[0] = READ_REG(can, &regs->msg.rx_eff.data[0]);
+ msg->data[1] = READ_REG(can, &regs->msg.rx_eff.data[1]);
+ msg->data[2] = READ_REG(can, &regs->msg.rx_eff.data[2]);
+ msg->data[3] = READ_REG(can, &regs->msg.rx_eff.data[3]);
+ msg->data[4] = READ_REG(can, &regs->msg.rx_eff.data[4]);
+ msg->data[5] = READ_REG(can, &regs->msg.rx_eff.data[5]);
+ msg->data[6] = READ_REG(can, &regs->msg.rx_eff.data[6]);
+ msg->data[7] = READ_REG(can, &regs->msg.rx_eff.data[7]);
*/
}else{
/* standard message */
- msg->id = READ_REG(&regs->msg.rx_sff.id[0])<<3 |
- READ_REG(&regs->msg.rx_sff.id[1])>>5;
+ msg->id = READ_REG(can, &regs->msg.rx_sff.id[0])<<3 |
+ READ_REG(can, &regs->msg.rx_sff.id[1])>>5;
while(tmp--){
- msg->data[tmp] = READ_REG(&regs->msg.rx_sff.data[tmp]);
+ msg->data[tmp] = READ_REG(can, &regs->msg.rx_sff.data[tmp]);
}
/*
- msg->data[0] = READ_REG(&regs->msg.rx_sff.data[0]);
- msg->data[1] = READ_REG(&regs->msg.rx_sff.data[1]);
- msg->data[2] = READ_REG(&regs->msg.rx_sff.data[2]);
- msg->data[3] = READ_REG(&regs->msg.rx_sff.data[3]);
- msg->data[4] = READ_REG(&regs->msg.rx_sff.data[4]);
- msg->data[5] = READ_REG(&regs->msg.rx_sff.data[5]);
- msg->data[6] = READ_REG(&regs->msg.rx_sff.data[6]);
- msg->data[7] = READ_REG(&regs->msg.rx_sff.data[7]);
+ msg->data[0] = READ_REG(can, &regs->msg.rx_sff.data[0]);
+ msg->data[1] = READ_REG(can, &regs->msg.rx_sff.data[1]);
+ msg->data[2] = READ_REG(can, &regs->msg.rx_sff.data[2]);
+ msg->data[3] = READ_REG(can, &regs->msg.rx_sff.data[3]);
+ msg->data[4] = READ_REG(can, &regs->msg.rx_sff.data[4]);
+ msg->data[5] = READ_REG(can, &regs->msg.rx_sff.data[5]);
+ msg->data[6] = READ_REG(can, &regs->msg.rx_sff.data[6]);
+ msg->data[7] = READ_REG(can, &regs->msg.rx_sff.data[7]);
*/
}
/* Re-Enable RX buffer for a new message */
- regs->cmd = PELICAN_CMD_RELRXBUF;
+ WRITE_REG(can, &regs->cmd, PELICAN_CMD_RELRXBUF);
/* make message available to the user */
occan_fifo_put(can->rxfifo);
@@ -1632,7 +1815,8 @@ static void occan_interrupt(occan_priv *can){
signal_rx = 1;
}
- if ( iflags & PELICAN_IF_TX ){
+ if ( iflags & PELICAN_IF_TX ) {
+
/* there is room in tx fifo of HW */
if ( !occan_fifo_empty(can->txfifo) ){
@@ -1651,6 +1835,9 @@ static void occan_interrupt(occan_priv *can){
can->status |= OCCAN_STATUS_QUEUE_ERROR;
can->stats.tx_buf_error++;
}
+#ifdef OCCAN_TX_IRQ_FLAG_FIXUP
+ can->sending = 1;
+#endif
/* free software-fifo space taken by sent message */
occan_fifo_get(can->txfifo);
@@ -1664,8 +1851,8 @@ static void occan_interrupt(occan_priv *can){
}
if ( iflags & PELICAN_IF_ERRW ){
- tx_error_cnt = READ_REG(&regs->tx_err_cnt);
- rx_error_cnt = READ_REG(&regs->rx_err_cnt);
+ tx_error_cnt = READ_REG(can, &regs->tx_err_cnt);
+ rx_error_cnt = READ_REG(can, &regs->rx_err_cnt);
/* 1. if bus off tx error counter = 127 */
if ( (tx_error_cnt > 96) || (rx_error_cnt > 96) ){
@@ -1673,7 +1860,7 @@ static void occan_interrupt(occan_priv *can){
can->status |= OCCAN_STATUS_WARN;
/* check reset bit for reset mode */
- if ( READ_REG(&regs->mode) & PELICAN_MOD_RESET ){
+ if ( READ_REG(can, &regs->mode) & PELICAN_MOD_RESET ){
/* in reset mode ==> bus off */
can->status |= OCCAN_STATUS_ERR_BUSOFF | OCCAN_STATUS_RESET;
@@ -1681,7 +1868,7 @@ static void occan_interrupt(occan_priv *can){
* turn off interrupts
* enter reset mode (HW already done that for us)
*/
- regs->inten = 0;
+ WRITE_REG(can, &regs->inten,0);
/* Indicate that we are not started any more.
* This will make write/read return with EBUSY
@@ -1718,8 +1905,8 @@ static void occan_interrupt(occan_priv *can){
/* Let the error counters decide what kind of
* interrupt it was. In/Out of EPassive area.
*/
- tx_error_cnt = READ_REG(&regs->tx_err_cnt);
- rx_error_cnt = READ_REG(&regs->rx_err_cnt);
+ tx_error_cnt = READ_REG(can, &regs->tx_err_cnt);
+ rx_error_cnt = READ_REG(can, &regs->rx_err_cnt);
if ( (tx_error_cnt > 127) || (rx_error_cnt > 127) ){
can->status |= OCCAN_STATUS_ERR_PASSIVE;
@@ -1732,7 +1919,7 @@ static void occan_interrupt(occan_priv *can){
}
if ( iflags & PELICAN_IF_ARB){
- arbcode = READ_REG(&regs->arbcode);
+ arbcode = READ_REG(can, &regs->arbcode);
can->stats.err_arb_bitnum[arbcode & PELICAN_ARB_BITS]++;
can->stats.err_arb++;
DBG("OCCAN_INT: ARB (0x%x)\n\r",arbcode & PELICAN_ARB_BITS);
@@ -1743,7 +1930,7 @@ static void occan_interrupt(occan_priv *can){
* statistics. Error Register is decoded
* and put into can->stats.
*/
- errcode = READ_REG(&regs->errcode);
+ errcode = READ_REG(can, &regs->errcode);
switch( errcode & PELICAN_ECC_CODE ){
case PELICAN_ECC_CODE_BIT:
can->stats.err_bus_bit++;
@@ -1784,56 +1971,12 @@ static void occan_interrupt(occan_priv *can){
}
}
-#ifdef OCCAN_DEFINE_INTHANDLER
-static void occan_interrupt_handler(rtems_vector_number v){
- int minor;
-
- /* convert to */
- for(minor = 0; minor < can_cores; minor++) {
- if ( v == (cans[minor].irq+0x10) ) {
- occan_interrupt(&cans[minor]);
- return;
- }
- }
-}
-#endif
-
-#define OCCAN_DRIVER_TABLE_ENTRY { occan_initialize, occan_open, occan_close, occan_read, occan_write, occan_ioctl }
-
-static rtems_driver_address_table occan_driver = OCCAN_DRIVER_TABLE_ENTRY;
-
-int OCCAN_PREFIX(_register)(amba_confarea_type *bus){
- rtems_status_code r;
- rtems_device_major_number m;
-
- amba_bus = bus;
- if ( !bus )
- return 1;
-
- if ((r = rtems_io_register_driver(0, &occan_driver, &m)) == RTEMS_SUCCESSFUL) {
- DBG("OCCAN driver successfully registered, major: %d\n\r", m);
- }else{
- switch(r) {
- case RTEMS_TOO_MANY:
- printk("OCCAN rtems_io_register_driver failed: RTEMS_TOO_MANY\n\r"); break;
- case RTEMS_INVALID_NUMBER:
- printk("OCCAN rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n\r"); break;
- case RTEMS_RESOURCE_IN_USE:
- printk("OCCAN rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n\r"); break;
- default:
- printk("OCCAN rtems_io_register_driver failed\n\r");
- }
- return 1;
- }
- return 0;
-}
-
-
/*******************************************************************************
* FIFO IMPLEMENTATION
*/
-static occan_fifo *occan_fifo_create(int cnt){
+static occan_fifo *occan_fifo_create(int cnt)
+{
occan_fifo *fifo;
fifo = malloc(sizeof(occan_fifo)+cnt*sizeof(CANMsg));
if ( fifo ){
@@ -1848,21 +1991,25 @@ static occan_fifo *occan_fifo_create(int cnt){
return fifo;
}
-static void occan_fifo_free(occan_fifo *fifo){
+static void occan_fifo_free(occan_fifo *fifo)
+{
if ( fifo )
free(fifo);
}
-static int occan_fifo_full(occan_fifo *fifo){
+static int occan_fifo_full(occan_fifo *fifo)
+{
return fifo->full;
}
-static int occan_fifo_empty(occan_fifo *fifo){
+static int occan_fifo_empty(occan_fifo *fifo)
+{
return (!fifo->full) && (fifo->head == fifo->tail);
}
/* Stage 1 - get buffer to fill (never fails if force!=0) */
-static CANMsg *occan_fifo_put_claim(occan_fifo *fifo, int force){
+static CANMsg *occan_fifo_put_claim(occan_fifo *fifo, int force)
+{
if ( !fifo )
return NULL;
@@ -1880,7 +2027,8 @@ static CANMsg *occan_fifo_put_claim(occan_fifo *fifo, int force){
}
/* Stage 2 - increment indexes */
-static void occan_fifo_put(occan_fifo *fifo){
+static void occan_fifo_put(occan_fifo *fifo)
+{
if ( occan_fifo_full(fifo) )
return;
@@ -1891,7 +2039,8 @@ static void occan_fifo_put(occan_fifo *fifo){
fifo->full = 1;
}
-static CANMsg *occan_fifo_claim_get(occan_fifo *fifo){
+static CANMsg *occan_fifo_claim_get(occan_fifo *fifo)
+{
if ( occan_fifo_empty(fifo) )
return NULL;
@@ -1900,7 +2049,8 @@ static CANMsg *occan_fifo_claim_get(occan_fifo *fifo){
}
-static void occan_fifo_get(occan_fifo *fifo){
+static void occan_fifo_get(occan_fifo *fifo)
+{
if ( !fifo )
return;
@@ -1908,14 +2058,16 @@ static void occan_fifo_get(occan_fifo *fifo){
return;
/* increment indexes */
- fifo->tail = (fifo->tail >= &fifo->base[fifo->cnt-1])? fifo->base : fifo->tail+1;
+ fifo->tail = (fifo->tail >= &fifo->base[fifo->cnt-1]) ?
+ fifo->base : fifo->tail+1;
fifo->full = 0;
}
-static void occan_fifo_clr(occan_fifo *fifo){
- fifo->full = 0;
- fifo->ovcnt = 0;
- fifo->head = fifo->tail = fifo->base;
+static void occan_fifo_clr(occan_fifo *fifo)
+{
+ fifo->full = 0;
+ fifo->ovcnt = 0;
+ fifo->head = fifo->tail = fifo->base;
}
-/*******************************************************************************/
+/******************************************************************************/
diff --git a/c/src/lib/libbsp/sparc/shared/can/occan_pci.c b/c/src/lib/libbsp/sparc/shared/can/occan_pci.c
deleted file mode 100644
index 2dd2e5be21..0000000000
--- a/c/src/lib/libbsp/sparc/shared/can/occan_pci.c
+++ /dev/null
@@ -1,64 +0,0 @@
-
-/* PCI cannot do byte accesses to addresses aligned byte wise
- * Use alternative reg map.
- */
-#define OCCAN_WORD_REGS
-
-/* Set registered device name */
-#define OCCAN_DEVNAME "/dev/occanpci0"
-#define OCCAN_DEVNAME_NO(devstr,no) ((devstr)[13]='0'+(no))
-
-/* Any non-static function will begin with */
-#define OCCAN_PREFIX(name) occanpci##name
-
-/* do nothing, assume that the interrupt handler is called
- * setup externally calling b1553_interrupt_handler.
- */
-#define OCCAN_REG_INT(handler,irq,arg) \
- if ( occan_pci_int_reg ) \
- occan_pci_int_reg(handler,irq,arg);
-
-void (*occan_pci_int_reg)(void *handler, int irq, void *arg) = 0;
-
-void occanpci_interrupt_handler(int irq, void *arg);
-
-/* AMBA Bus is clocked using the PCI clock (33.3MHz) */
-#define SYS_FREQ_HZ 33333333
-
-/* Enable two redundant channels */
-#define REDUNDANT_CHANNELS 2
-
-#define OCCAN_SET_CHANNEL(priv,channel) occanpci_set_channel(priv,channel)
-
-#include "occan.c"
-
-/* Define method that sets redundant channel
- * The channel select register:
- * 0x00 = byte regs
- * 0x40 = channel select
- * 0x80 = word regs
- */
-static void inline occanpci_set_channel(occan_priv *priv, int channel){
- unsigned int *chan_sel = (unsigned int *)(((unsigned int)priv->regs & ~0xff)+0x40);
- if ( channel == 0 )
- *chan_sel = 0;
- else
- *chan_sel = 0xffffffff;
-}
-
-int occan_pci_register(amba_confarea_type *bus)
-{
- /* Setup configuration */
-
- /* Register the driver */
- return OCCAN_PREFIX(_register)(bus);
-}
-
-
-/* Call this from PCI interrupt handler
- * irq = the irq number of the HW device local to that IRQMP controller
- *
- */
-void occanpci_interrupt_handler(int irq, void *arg){
- occan_interrupt(arg);
-}
diff --git a/c/src/lib/libbsp/sparc/shared/can/satcan.c b/c/src/lib/libbsp/sparc/shared/can/satcan.c
new file mode 100644
index 0000000000..1921c6bd12
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/can/satcan.c
@@ -0,0 +1,721 @@
+/*
+ * RTEMS SatCAN FPGA driver
+ *
+ * --------------------------------------------------------------------------
+ * -- This file is a part of GAISLER RESEARCH source code.
+ * -- Copyright (C) 2008, Gaisler Research AB - all rights reserved.
+ * --
+ * -- ANY USE OR REDISTRIBUTION IN PART OR IN WHOLE MUST BE HANDLED IN
+ * -- ACCORDANCE WITH THE GAISLER LICENSE AGREEMENT AND MUST BE APPROVED
+ * -- IN ADVANCE IN WRITING.
+ * --
+ * -- BY DEFAULT, DISTRIBUTION OR DISCLOSURE IS NOT PERMITTED.
+ * --------------------------------------------------------------------------
+ *
+ * Based on the OC_CAN driver.
+ *
+ */
+
+#include <rtems/libio.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <bsp.h>
+#include <rtems/bspIo.h> /* printk */
+
+#include <satcan.h>
+#include <ambapp.h>
+
+#ifndef GAISLER_SATCAN
+#define GAISLER_SATCAN 0x080
+#endif
+
+#if !defined(SATCAN_DEVNAME)
+ #undef SATCAN_DEVNAME
+ #define SATCAN_DEVNAME "/dev/satcan"
+#endif
+
+/* Enable debug output? */
+/* #define DEBUG */
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+
+/* Defines related to DMA */
+#define ALIGN_2KMEM 32*1024
+#define ALIGN_8KMEM 128*1024
+
+#define OFFSET_2K_LOW_POS 15
+#define OFFSET_8K_LOW_POS 17
+
+#define DMA_2K_DATA_SELECT (1 << 14)
+#define DMA_8K_DATA_SELECT (1 << 16)
+
+#define DMA_2K_DATA_OFFSET 16*1024
+#define DMA_8K_DATA_OFFSET 64*1024
+
+/* Core register structures and defines */
+
+/* Indexes to SatCAN registers in satcan array are declared in satcan.h*/
+/* Fields for some of the SatCAN FPGA registers */
+
+/* CmdReg0 */
+#define CAN_TODn_Int_sel (1 << 5)
+
+/* CmdReg1 */
+#define Sel_2k_8kN (1 << 0)
+
+/* Read FIFO */
+#define FIFO_Full (1 << 8)
+#define FIFO_Empty (1 << 9)
+
+/* DMA Ch_Enable */
+#define DMA_AutoInitDmaTx (1 << 3)
+#define DMA_EnTx2 (1 << 2)
+#define DMA_EnTx1 (1 << 1)
+#define DMA_EnRx (1 << 0)
+
+/* SatCAN wrapper register fields */
+#define CTRL_BT_P 9
+#define CTRL_NODENO_P 5
+#define CTRL_DIS (1 << 2)
+#define CTRL_DPS_P 1
+#define CTRL_RST (1 << 0)
+
+#define IRQ_AHB (1 << 8)
+#define IRQ_PPS (1 << 7)
+#define IRQ_M5 (1 << 6)
+#define IRQ_M4 (1 << 5)
+#define IRQ_M3 (1 << 4)
+#define IRQ_M2 (1 << 3)
+#define IRQ_M1 (1 << 2)
+#define IRQ_SYNC (1 << 1)
+#define IRQ_CAN (1 << 0)
+
+#define MSK_AHB (1 << 8)
+#define MSK_PPS (1 << 7)
+#define MSK_M5 (1 << 6)
+#define MSK_M4 (1 << 5)
+#define MSK_M3 (1 << 4)
+#define MSK_M2 (1 << 3)
+#define MSK_M1 (1 << 2)
+#define MSK_SYNC (1 << 1)
+#define MSK_CAN (1 << 0)
+
+
+
+struct satcan_regs {
+ volatile unsigned int satcan[32];
+ volatile unsigned int ctrl;
+ volatile unsigned int irqpend;
+ volatile unsigned int irqmask;
+ volatile unsigned int membase;
+};
+
+
+struct satcan_priv {
+ /* config */
+ void *dmaptr;
+ unsigned char *alptr;
+ satcan_config *cfg;
+
+ /* driver state */
+ rtems_id devsem;
+ rtems_id txsem;
+ int open;
+ int txactive;
+ int dmaen;
+ int doff;
+ rtems_interval timeout;
+ int dmamode;
+};
+
+static struct satcan_regs *regs;
+static struct satcan_priv *priv;
+
+static rtems_device_driver satcan_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver satcan_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver satcan_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver satcan_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver satcan_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver satcan_initialize(rtems_device_major_number major, rtems_device_minor_number unused, void *arg);
+
+
+/*
+ * almalloc: allocate memory area of size sz aligned on sz boundary
+ * alptr: Utilized to return aligned pointer
+ * ptr: Unaligned pointer
+ * sz: Size of memory area
+ */
+static void almalloc(unsigned char **alptr, void **ptr, int sz)
+{
+ *ptr = calloc(1,2*sz);
+ *alptr = (unsigned char *) (((int)*ptr+sz) & ~(sz-1));
+}
+
+static rtems_isr satcan_interrupt_handler(rtems_vector_number v)
+{
+ unsigned int irq;
+ unsigned int fifo;
+
+ irq = regs->irqpend;
+
+ if (irq & IRQ_AHB && priv->cfg->ahb_irq_callback) {
+ priv->cfg->ahb_irq_callback();
+ }
+ if (irq & IRQ_PPS && priv->cfg->pps_irq_callback) {
+ priv->cfg->pps_irq_callback();
+ }
+ if (irq & IRQ_M5 && priv->cfg->m5_irq_callback) {
+ priv->cfg->m5_irq_callback();
+ }
+ if (irq & IRQ_M4 && priv->cfg->m4_irq_callback) {
+ priv->cfg->m4_irq_callback();
+ }
+ if (irq & IRQ_M3 && priv->cfg->m3_irq_callback) {
+ priv->cfg->m3_irq_callback();
+ }
+ if (irq & IRQ_M2 && priv->cfg->m2_irq_callback) {
+ priv->cfg->m2_irq_callback();
+ }
+ if (irq & IRQ_M1 && priv->cfg->m1_irq_callback) {
+ priv->cfg->m1_irq_callback();
+ }
+ if (irq & IRQ_SYNC && priv->cfg->sync_irq_callback) {
+ priv->cfg->sync_irq_callback();
+ }
+ if (irq & IRQ_CAN) {
+ fifo = regs->satcan[SATCAN_FIFO];
+ if (!(fifo & FIFO_Empty) && priv->txactive &&
+ (((fifo & 0xff) == SATCAN_IRQ_EOD1) || ((fifo & 0xff) == SATCAN_IRQ_EOD2))) {
+ rtems_semaphore_release(priv->txsem);
+ }
+ if (priv->cfg->can_irq_callback)
+ priv->cfg->can_irq_callback(fifo);
+ }
+}
+
+
+
+static rtems_device_driver satcan_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t*)arg;
+ int *value;
+ rtems_interval *timeout;
+ satcan_regmod *regmod;
+
+ DBG("SatCAN: IOCTL %d\n\r", ioarg->command);
+
+ ioarg->ioctl_return = 0;
+ switch(ioarg->command) {
+ case SATCAN_IOC_DMA_2K:
+ DBG("SatCAN: ioctl: setting 2K DMA mode\n\r");
+ free(priv->dmaptr);
+ almalloc(&priv->alptr, &priv->dmaptr, ALIGN_2KMEM);
+ if (priv->dmaptr == NULL) {
+ printk("SatCAN: Failed to allocate DMA memory\n\r");
+ return RTEMS_NO_MEMORY;
+ }
+
+ regs->membase = (unsigned int)priv->alptr;
+ regs->satcan[SATCAN_RAM_BASE] = (unsigned int)priv->alptr >> OFFSET_2K_LOW_POS;
+ regs->satcan[SATCAN_CMD1] = regs->satcan[SATCAN_CMD1] | Sel_2k_8kN;
+ break;
+
+ case SATCAN_IOC_DMA_8K:
+ DBG("SatCAN: ioctl: setting 8K DMA mode\n\r");
+ free(priv->dmaptr);
+ almalloc(&priv->alptr, &priv->dmaptr, ALIGN_8KMEM);
+ if (priv->dmaptr == NULL) {
+ printk("SatCAN: Failed to allocate DMA memory\n\r");
+ return RTEMS_NO_MEMORY;
+ }
+
+ regs->membase = (unsigned int)priv->alptr;
+ regs->satcan[SATCAN_RAM_BASE] = (unsigned int)priv->alptr >> OFFSET_8K_LOW_POS;
+ regs->satcan[SATCAN_CMD1] = regs->satcan[SATCAN_CMD1] & ~Sel_2k_8kN;
+ break;
+
+ case SATCAN_IOC_GET_REG:
+ /* Get regmod structure from argument */
+ regmod = (satcan_regmod*)ioarg->buffer;
+ DBG("SatCAN: ioctl: getting register %d\n\r", regmod->reg);
+ if (regmod->reg < 0)
+ return RTEMS_INVALID_NAME;
+ else if (regmod->reg <= SATCAN_FILTER_STOP)
+ regmod->val = regs->satcan[regmod->reg];
+ else if (regmod->reg == SATCAN_WCTRL)
+ regmod->val = regs->ctrl;
+ else if (regmod->reg == SATCAN_WIPEND)
+ regmod->val = regs->irqpend;
+ else if (regmod->reg == SATCAN_WIMASK)
+ regmod->val = regs->irqmask;
+ else if (regmod->reg == SATCAN_WAHBADDR)
+ regmod->val = regs->membase;
+ else
+ return RTEMS_INVALID_NAME;
+ break;
+
+ case SATCAN_IOC_SET_REG:
+ /* Get regmod structure from argument */
+ regmod = (satcan_regmod*)ioarg->buffer;
+ DBG("SatCAN: ioctl: setting register %d, value %x\n\r",
+ regmod->reg, regmod->val);
+ if (regmod->reg < 0)
+ return RTEMS_INVALID_NAME;
+ else if (regmod->reg <= SATCAN_FILTER_STOP)
+ regs->satcan[regmod->reg] = regmod->val;
+ else if (regmod->reg == SATCAN_WCTRL)
+ regs->ctrl = regmod->val;
+ else if (regmod->reg == SATCAN_WIPEND)
+ regs->irqpend = regmod->val;
+ else if (regmod->reg == SATCAN_WIMASK)
+ regs->irqmask = regmod->val;
+ else if (regmod->reg == SATCAN_WAHBADDR)
+ regs->membase = regmod->val;
+ else
+ return RTEMS_INVALID_NAME;
+ break;
+
+ case SATCAN_IOC_OR_REG:
+ /* Get regmod structure from argument */
+ regmod = (satcan_regmod*)ioarg->buffer;
+ DBG("SatCAN: ioctl: or:ing register %d, with value %x\n\r",
+ regmod->reg, regmod->val);
+ if (regmod->reg < 0)
+ return RTEMS_INVALID_NAME;
+ else if (regmod->reg <= SATCAN_FILTER_STOP)
+ regs->satcan[regmod->reg] |= regmod->val;
+ else if (regmod->reg == SATCAN_WCTRL)
+ regs->ctrl |= regmod->val;
+ else if (regmod->reg == SATCAN_WIPEND)
+ regs->irqpend |= regmod->val;
+ else if (regmod->reg == SATCAN_WIMASK)
+ regs->irqmask |= regmod->val;
+ else if (regmod->reg == SATCAN_WAHBADDR)
+ regs->membase |= regmod->val;
+ else
+ return RTEMS_INVALID_NAME;
+ break;
+
+ case SATCAN_IOC_AND_REG:
+ /* Get regmod structure from argument */
+ regmod = (satcan_regmod*)ioarg->buffer;
+ DBG("SatCAN: ioctl: masking register %d, with value %x\n\r",
+ regmod->reg, regmod->val);
+ if (regmod->reg < 0)
+ return RTEMS_INVALID_NAME;
+ else if (regmod->reg <= SATCAN_FILTER_STOP)
+ regs->satcan[regmod->reg] &= regmod->val;
+ else if (regmod->reg == SATCAN_WCTRL)
+ regs->ctrl &= regmod->val;
+ else if (regmod->reg == SATCAN_WIPEND)
+ regs->irqpend &= regmod->val;
+ else if (regmod->reg == SATCAN_WIMASK)
+ regs->irqmask &= regmod->val;
+ else if (regmod->reg == SATCAN_WAHBADDR)
+ regs->membase &= regmod->val;
+ else
+ return RTEMS_INVALID_NAME;
+ break;
+
+ case SATCAN_IOC_EN_TX1_DIS_TX2:
+ priv->dmaen = SATCAN_DMA_ENABLE_TX1;
+ break;
+
+ case SATCAN_IOC_EN_TX2_DIS_TX1:
+ priv->dmaen = SATCAN_DMA_ENABLE_TX2;
+ break;
+
+ case SATCAN_IOC_GET_DMA_MODE:
+ value = (int*)ioarg->buffer;
+ *value = priv->dmamode;
+ break;
+
+ case SATCAN_IOC_SET_DMA_MODE:
+ value = (int*)ioarg->buffer;
+ if (*value != SATCAN_DMA_MODE_USER && *value != SATCAN_DMA_MODE_SYSTEM) {
+ DBG("SatCAN: ioctl: invalid DMA mode\n\r");
+ return RTEMS_INVALID_NAME;
+ }
+ priv->dmamode = *value;
+ break;
+
+ case SATCAN_IOC_ACTIVATE_DMA:
+ if (priv->dmamode != SATCAN_DMA_MODE_USER) {
+ DBG("SatCAN: ioctl: ACTIVATE_DMA: not in user mode\n\r");
+ return RTEMS_INVALID_NAME;
+ }
+ value = (int*)ioarg->buffer;
+ if (*value != SATCAN_DMA_ENABLE_TX1 && *value != SATCAN_DMA_ENABLE_TX2) {
+ DBG("SatCAN: ioctl: ACTIVATE_DMA: Illegal channel\n\r");
+ return RTEMS_INVALID_NAME;
+ }
+ regs->satcan[SATCAN_DMA] |= *value << 1;
+ break;
+
+ case SATCAN_IOC_DEACTIVATE_DMA:
+ if (priv->dmamode != SATCAN_DMA_MODE_USER) {
+ DBG("SatCAN: ioctl: DEACTIVATE_DMA: not in user mode\n\r");
+ return RTEMS_INVALID_NAME;
+ }
+ value = (int*)ioarg->buffer;
+ if (*value != SATCAN_DMA_ENABLE_TX1 && *value != SATCAN_DMA_ENABLE_TX2) {
+ DBG("SatCAN: ioctl: DEACTIVATE_DMA: Illegal channel\n\r");
+ return RTEMS_INVALID_NAME;
+ }
+ regs->satcan[SATCAN_DMA] &= ~(*value << 1);
+ break;
+
+ case SATCAN_IOC_GET_DOFFSET:
+ value = (int*)ioarg->buffer;
+ *value = priv->doff;
+ break;
+
+ case SATCAN_IOC_SET_DOFFSET:
+ value = (int*)ioarg->buffer;
+ priv->doff = *value;
+ break;
+
+ case SATCAN_IOC_GET_TIMEOUT:
+ timeout = (rtems_interval*)ioarg->buffer;
+ *timeout = priv->timeout;
+ break;
+
+ case SATCAN_IOC_SET_TIMEOUT:
+ timeout = (rtems_interval*)ioarg->buffer;
+ priv->timeout = *timeout;
+ break;
+
+ default:
+ return RTEMS_NOT_DEFINED;
+ }
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver satcan_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ int i;
+ int doff;
+ int msgindex;
+ int messages;
+ rtems_libio_rw_args_t *rw_args=(rtems_libio_rw_args_t *) arg;
+ satcan_msg *msgs;
+ rtems_status_code status;
+
+ DBG("SatCAN: Writing %d bytes from %p\n\r",rw_args->count,rw_args->buffer);
+
+ if ((rw_args->count < sizeof(satcan_msg)) || (!rw_args->buffer)) {
+ DBG("SatCAN: write: returning EINVAL\n\r");
+ return RTEMS_INVALID_NAME; /* EINVAL */
+ }
+
+ messages = rw_args->count / sizeof(satcan_msg);
+ msgs = (satcan_msg*)rw_args->buffer;
+
+ /* Check that size matches any number of satcan_msg */
+ if (rw_args->count % sizeof(satcan_msg)) {
+ DBG("SatCAN: write: count can not be evenly divided with satcan_msg size\n\r");
+ return RTEMS_INVALID_NAME; /* EINVAL */
+ }
+
+
+ /* DMA channel must be set if we are in system DMA mode */
+ DBG("SatCAN: write: dma channel select is %x\n\r", priv->dmaen);
+ if (!priv->dmaen && priv->dmamode == SATCAN_DMA_MODE_SYSTEM)
+ return RTEMS_INVALID_NAME; /* EINVAL */
+
+ /* DMA must not be active */
+ if (regs->satcan[SATCAN_DMA] & (DMA_EnTx1 | DMA_EnTx2 | DMA_AutoInitDmaTx)) {
+ DBG("SatCAN: write: DMA was active\n\r");
+ rw_args->bytes_moved = 0;
+ return RTEMS_IO_ERROR; /* EIO */
+ }
+
+ doff = regs->satcan[SATCAN_CMD1] & Sel_2k_8kN ? DMA_2K_DATA_OFFSET : DMA_8K_DATA_OFFSET;
+
+ for (msgindex = 0; msgindex < messages; msgindex++) {
+ /* Place header in DMA area */
+ for (i = 0; i < SATCAN_HEADER_SIZE; i++) {
+ priv->alptr[priv->doff+8*msgindex+i] = msgs[msgindex].header[i];
+ }
+
+ /* Place data in DMA area */
+ for (i = 0; i < SATCAN_PAYLOAD_SIZE; i++)
+ priv->alptr[priv->doff+doff+8*msgindex+i] = msgs[msgindex].payload[i];
+ }
+
+ if ((priv->dmaen & SATCAN_DMA_ENABLE_TX1) || priv->dmamode == SATCAN_DMA_MODE_USER) {
+ regs->satcan[SATCAN_DMA_TX_1_CUR] = 0;
+ regs->satcan[SATCAN_DMA_TX_1_END] = messages<<3;
+ }
+
+ if ((priv->dmaen & SATCAN_DMA_ENABLE_TX2) || priv->dmamode == SATCAN_DMA_MODE_USER) {
+ regs->satcan[SATCAN_DMA_TX_2_CUR] = 0;
+ regs->satcan[SATCAN_DMA_TX_2_END] = messages<<3;
+ }
+
+ /* If we are in DMA user mode we are done here, otherwise we block */
+ if (priv->dmamode == SATCAN_DMA_MODE_SYSTEM) {
+ priv->txactive = 1;
+
+ /* Enable DMA */
+ regs->satcan[SATCAN_DMA] |= priv->dmaen << 1;
+
+ /* Wait for TX interrupt */
+ status = rtems_semaphore_obtain(priv->txsem, RTEMS_WAIT, priv->timeout);
+
+ priv->txactive = 0;
+
+ /* Disable activated Tx DMA */
+ regs->satcan[SATCAN_DMA] &= ~(priv->dmaen << 1);
+
+ if (status != RTEMS_SUCCESSFUL) {
+ rw_args->bytes_moved = 0;
+ return status;
+ }
+ }
+
+ rw_args->bytes_moved = rw_args->count;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver satcan_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ char *buf;
+ int i;
+ int canid;
+ int messages;
+ rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t*)arg;
+ satcan_msg *ret;
+
+ /* Check that there is room for the return */
+ if (rw_args->count < sizeof(satcan_msg)) {
+ DBG("SatCAN: read: length of buffer must be at least %d, current is %d\n\r",
+ sizeof(satcan_msg) + sizeof(int), rw_args->count);
+ return RTEMS_INVALID_NAME; /* -EINVAL */
+ }
+
+ /* Check that size matches any number of satcan_msg */
+ if (rw_args->count % sizeof(satcan_msg)) {
+ DBG("SatCAN: read: count can not be evenly divided with satcan_msg size\n\r");
+ return RTEMS_INVALID_NAME; /* EINVAL */
+ }
+
+ messages = rw_args->count / sizeof(satcan_msg);
+ ret = (satcan_msg*)rw_args->buffer;
+
+ DBG("SatCAN: read: reading %d messages to %p\n\r", messages, ret);
+
+ for (i = 0; i < messages; i++) {
+ canid = (ret[i].header[1] << 8) | ret[i].header[0];
+
+ /* Copy message header from DMA header area to buffer */
+ buf = (char*)((int)priv->alptr | (canid << 3));
+ memcpy(ret[i].header, buf, SATCAN_HEADER_SIZE);
+
+ DBG("SatCAN: read: copied header from %p to %p\n\r", buf, ret[i].header);
+
+ /* Clear New Message Marker */
+ buf[SATCAN_HEADER_NMM_POS] = 0;
+
+ /* Copy message payload from DMA data area to buffer */
+ buf = (char*)((int)buf |
+ (regs->satcan[SATCAN_CMD1] & Sel_2k_8kN ? DMA_2K_DATA_SELECT : DMA_8K_DATA_SELECT));
+ memcpy(ret[i].payload, buf, SATCAN_PAYLOAD_SIZE);
+
+ DBG("SatCAN: read: copied payload from %p to %p\n\r", buf, ret[i].payload);
+ }
+ rw_args->bytes_moved = rw_args->count;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+
+static rtems_device_driver satcan_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ DBG("SatCAN: Closing %d\n\r",minor);
+
+ if (priv->open) {
+ regs->irqmask = 0;
+ regs->satcan[SATCAN_INT_EN] = 0;
+ regs->satcan[SATCAN_RX] = 0;
+ regs->satcan[SATCAN_DMA] = 0;
+ priv->open = 0;
+ priv->dmaen = 0;
+ priv->doff = 0;
+ priv->timeout = RTEMS_NO_TIMEOUT;
+ priv->dmamode = SATCAN_DMA_MODE_SYSTEM;
+ }
+
+ return RTEMS_SUCCESSFUL;
+}
+
+
+static rtems_device_driver satcan_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ DBG("SatCAN: Opening %d\n\r",minor);
+
+ rtems_semaphore_obtain(priv->devsem,RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+ if (priv->open) {
+ rtems_semaphore_release(priv->devsem);
+ return RTEMS_RESOURCE_IN_USE; /* EBUSY */
+ }
+ priv->open = 1;
+ rtems_semaphore_release(priv->devsem);
+
+ /* Enable AHB and CAN IRQs in wrapper and EOD1, EOD2 and CAN critical IRQs in SatCAN core */
+ regs->irqmask = MSK_AHB | MSK_CAN;
+ regs->satcan[SATCAN_INT_EN] = ((1 << SATCAN_IRQ_EOD1) | (1 << SATCAN_IRQ_EOD2) |
+ (1 << SATCAN_IRQ_CRITICAL));
+
+ /* Select can_int as IRQ source */
+ regs->satcan[SATCAN_CMD0] = CAN_TODn_Int_sel;
+ /* CAN RX DMA Enable */
+ regs->satcan[SATCAN_DMA] = 1;
+ /* CAN RX Enable */
+ regs->satcan[SATCAN_RX] = 1;
+
+ DBG("SatCAN: Opening %d success\n\r",minor);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver satcan_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ struct ambapp_ahb_info d;
+ char fs_name[20];
+ rtems_status_code status;
+
+ DBG("SatCAN: Initialize..\n\r");
+
+ strcpy(fs_name, SATCAN_DEVNAME);
+
+ /* Find core and initialize register pointer */
+ if (!ambapp_find_ahbslv(&ambapp_plb, VENDOR_GAISLER, GAISLER_SATCAN, &d)) {
+ printk("SatCAN: Failed to find SatCAN core\n\r");
+ return -1;
+ }
+
+ status = rtems_io_register_name(fs_name, major, minor);
+ if (RTEMS_SUCCESSFUL != status)
+ rtems_fatal_error_occurred(status);
+
+ regs = (struct satcan_regs*)d.start[0];
+
+ /* Set node number and DPS */
+ regs->ctrl |= ((priv->cfg->nodeno & 0xf) << 5) | (priv->cfg->dps << 1);
+
+ /* Reset core */
+ regs->ctrl |= CTRL_RST;
+
+ /* Allocate DMA area */
+ almalloc(&priv->alptr, &priv->dmaptr, ALIGN_2KMEM);
+ if (priv->dmaptr == NULL) {
+ printk("SatCAN: Failed to allocate DMA memory\n\r");
+ free(priv->cfg);
+ free(priv);
+ return -1;
+ }
+
+ /* Wait until core reset has completed */
+ while (regs->ctrl & CTRL_RST)
+ ;
+
+ /* Initialize core registers, default is 2K messages */
+ regs->membase = (unsigned int)priv->alptr;
+ regs->satcan[SATCAN_RAM_BASE] = (unsigned int)priv->alptr >> 15;
+
+ DBG("regs->membase = %x\n\r", (unsigned int)priv->alptr);
+ DBG("regs->satcan[SATCAN_RAM_BASE] = %x\n\r", (unsigned int)priv->alptr >> 15);
+
+ status = rtems_semaphore_create(
+ rtems_build_name('S', 'd', 'v', '0'),
+ 1,
+ RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | \
+ RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &priv->devsem);
+ if (status != RTEMS_SUCCESSFUL) {
+ printk("SatCAN: Failed to create dev semaphore (%d)\n\r", status);
+ free(priv->cfg);
+ free(priv);
+ return RTEMS_UNSATISFIED;
+ }
+ status = rtems_semaphore_create(
+ rtems_build_name('S', 't', 'x', '0'),
+ 0,
+ RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | \
+ RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &priv->txsem);
+ if (status != RTEMS_SUCCESSFUL) {
+ printk("SatCAN: Failed to create tx semaphore (%d)\n\r", status);
+ free(priv->cfg);
+ free(priv);
+ return RTEMS_UNSATISFIED;
+ }
+
+ priv->txactive = 0;
+ priv->open = 0;
+ priv->dmaen = 0;
+ priv->doff = 0;
+ priv->timeout = RTEMS_NO_TIMEOUT;
+ priv->dmamode = SATCAN_DMA_MODE_SYSTEM;
+
+ /* Register interrupt handler */
+ set_vector(satcan_interrupt_handler, d.irq+0x10, 2);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+
+
+#define SATCAN_DRIVER_TABLE_ENTRY { satcan_initialize, satcan_open, satcan_close, satcan_read, satcan_write, satcan_ioctl }
+
+static rtems_driver_address_table satcan_driver = SATCAN_DRIVER_TABLE_ENTRY;
+
+int satcan_register(satcan_config *conf)
+{
+ rtems_status_code r;
+ rtems_device_major_number m;
+
+ DBG("SatCAN: satcan_register called\n\r");
+
+ /* Create private structure */
+ if ((priv = malloc(sizeof(struct satcan_priv))) == NULL) {
+ printk("SatCAN driver could not allocate memory for priv structure\n\r");
+ return -1;
+ }
+
+ DBG("SatCAN: Creating local copy of config structure\n\r");
+ if ((priv->cfg = malloc(sizeof(satcan_config))) == NULL) {
+ printk("SatCAN driver could not allocate memory for cfg structure\n\r");
+ return 1;
+ }
+ memcpy(priv->cfg, conf, sizeof(satcan_config));
+
+ if ((r = rtems_io_register_driver(0, &satcan_driver, &m)) == RTEMS_SUCCESSFUL) {
+ DBG("SatCAN driver successfully registered, major: %d\n\r", m);
+ } else {
+ switch(r) {
+ case RTEMS_TOO_MANY:
+ printk("SatCAN rtems_io_register_driver failed: RTEMS_TOO_MANY\n\r"); break;
+ case RTEMS_INVALID_NUMBER:
+ printk("SatCAN rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n\r"); break;
+ case RTEMS_RESOURCE_IN_USE:
+ printk("SatCAN rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n\r"); break;
+ default:
+ printk("SatCAN rtems_io_register_driver failed\n\r");
+ }
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/drvmgr/ambapp_bus.c b/c/src/lib/libbsp/sparc/shared/drvmgr/ambapp_bus.c
new file mode 100644
index 0000000000..007cefb9e2
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/drvmgr/ambapp_bus.c
@@ -0,0 +1,762 @@
+/* General part of a AMBA Plug & Play bus driver.
+ *
+ * COPYRIGHT (c) 2008.
+ * Aeroflex Gaisler.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * This is the general part of the different AMBA Plug & Play
+ * drivers. The drivers are wrappers around this driver, making
+ * the code size smaller for systems with multiple AMBA Plug &
+ * Play buses.
+ *
+ * The BSP define APBUART_INFO_AVAIL in order to add the info routine
+ * used for debugging.
+ *
+ *
+ * 2009-11-20, Daniel Hellstrom <daniel@gaisler.com>
+ * Added support for AMBA-RMAP
+ *
+ * 2008-12-03, Daniel Hellstrom <daniel@gaisler.com>
+ * Created
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+
+#include <bsp.h>
+#include <ambapp.h>
+
+/*#define DEBUG 1*/
+#define DBG(args...)
+/*#define DBG(args...) printk(args)*/
+
+struct grlib_gptimer_regs {
+ volatile unsigned int scaler_value; /* common timer registers */
+ volatile unsigned int scaler_reload;
+ volatile unsigned int status;
+ volatile unsigned int notused;
+};
+
+/* AMBA IMPLEMENTATION */
+
+int ambapp_bus_init1(struct drvmgr_bus *bus);
+int ambapp_bus_remove(struct drvmgr_bus *bus);
+int ambapp_unite(struct drvmgr_drv *drv, struct drvmgr_dev *dev);
+int ambapp_int_register(struct drvmgr_dev *dev, int index, const char *info, drvmgr_isr isr, void *arg);
+int ambapp_int_unregister(struct drvmgr_dev *dev, int index, drvmgr_isr isr, void *arg);
+int ambapp_int_clear(struct drvmgr_dev *dev, int index);
+int ambapp_int_mask(struct drvmgr_dev *dev, int index);
+int ambapp_int_unmask(struct drvmgr_dev *dev, int index);
+int ambapp_get_params(struct drvmgr_dev *dev, struct drvmgr_bus_params *params);
+int ambapp_bus_freq_get(
+ struct drvmgr_dev *dev,
+ int options,
+ unsigned int *freq_hz);
+void ambapp_dev_info(struct drvmgr_dev *, void (*print)(void *p, char *str), void *p);
+
+struct drvmgr_bus_ops ambapp_bus_ops =
+{
+ .init =
+ {
+ /* init1 */ ambapp_bus_init1,
+ /* init2 */ NULL,
+ /* init3 */ NULL,
+ /* init4 */ NULL
+ },
+ .remove = ambapp_bus_remove,
+ .unite = ambapp_unite,
+ .int_register = ambapp_int_register,
+ .int_unregister = ambapp_int_unregister,
+ .int_clear = ambapp_int_clear,
+ .int_mask = ambapp_int_mask,
+ .int_unmask = ambapp_int_unmask,
+ .get_params = ambapp_get_params,
+ .freq_get = ambapp_bus_freq_get,
+#ifdef AMBAPPBUS_INFO_AVAIL
+ .info_dev = ambapp_dev_info,
+#endif
+};
+
+struct ambapp_priv {
+ struct ambapp_config *config;
+};
+
+int ambapp_unite(struct drvmgr_drv *drv, struct drvmgr_dev *dev)
+{
+ struct amba_drv_info *adrv;
+ struct amba_dev_id *id;
+ struct amba_dev_info *amba;
+
+ if ( !drv || !dev || !dev->parent )
+ return 0;
+
+ if ( ! (((drv->bus_type == DRVMGR_BUS_TYPE_AMBAPP) && (dev->parent->bus_type == DRVMGR_BUS_TYPE_AMBAPP)) ||
+ ((drv->bus_type == DRVMGR_BUS_TYPE_AMBAPP_RMAP) && (dev->parent->bus_type == DRVMGR_BUS_TYPE_AMBAPP_RMAP)) ||
+ ((drv->bus_type == DRVMGR_BUS_TYPE_AMBAPP_DIST) && (dev->parent->bus_type == DRVMGR_BUS_TYPE_AMBAPP_DIST)))
+ ) {
+ return 0;
+ }
+
+ amba = (struct amba_dev_info *)dev->businfo;
+ if ( !amba )
+ return 0;
+
+ adrv = (struct amba_drv_info *)drv;
+ id = adrv->ids;
+ if ( !id )
+ return 0;
+ while( id->vendor != 0 ) {
+ if ( (id->vendor == amba->id.vendor) &&
+ (id->device == amba->id.device) ) {
+ /* Unite device and driver */
+ DBG("DRV 0x%x and DEV 0x%x united\n", (unsigned int)drv, (unsigned int)dev);
+ return 1;
+ }
+ id++;
+ }
+
+ return 0;
+}
+
+static int ambapp_int_get(struct drvmgr_dev *dev, int index)
+{
+ int irq;
+
+ /* Relative (positive) or absolute (negative) IRQ number */
+ if ( index >= 0 ) {
+ /* IRQ Index relative to Cores base IRQ */
+
+ /* Get Base IRQ */
+ irq = ((struct amba_dev_info *)dev->businfo)->info.irq;
+ if ( irq < 0 )
+ return -1;
+ irq += index;
+ } else {
+ /* Absolute IRQ number */
+ irq = -index;
+ }
+ return irq;
+}
+
+int ambapp_int_register(
+ struct drvmgr_dev *dev,
+ int index,
+ const char *info,
+ drvmgr_isr isr,
+ void *arg)
+{
+ struct drvmgr_dev *busdev;
+ struct ambapp_priv *priv;
+ int irq;
+
+ busdev = dev->parent->dev;
+ priv = dev->parent->priv;
+
+ /* Get IRQ number from index and device information */
+ irq = ambapp_int_get(dev, index);
+ if ( irq < 0 )
+ return DRVMGR_EINVAL;
+
+ DBG("Register interrupt on 0x%x for dev 0x%x (IRQ: %d)\n", (unsigned int)busdev, (unsigned int)dev, irq);
+
+ if ( priv->config->ops->int_register ) {
+ /* Let device override driver default */
+ return priv->config->ops->int_register(dev, irq, info, isr, arg);
+ } else {
+ return DRVMGR_ENOSYS;
+ }
+}
+
+int ambapp_int_unregister(
+ struct drvmgr_dev *dev,
+ int index,
+ drvmgr_isr isr,
+ void *arg)
+{
+ struct drvmgr_dev *busdev;
+ struct ambapp_priv *priv;
+ int irq;
+
+ busdev = dev->parent->dev;
+ priv = dev->parent->priv;
+
+ /* Get IRQ number from index and device information */
+ irq = ambapp_int_get(dev, index);
+ if ( irq < 0 )
+ return DRVMGR_EINVAL;
+
+ DBG("Unregister interrupt on 0x%x for dev 0x%x (IRQ: %d)\n", (unsigned int)busdev, (unsigned int)dev, irq);
+
+ if ( priv->config->ops->int_unregister ) {
+ /* Let device override driver default */
+ return priv->config->ops->int_unregister(dev, irq, isr, arg);
+ } else {
+ return DRVMGR_ENOSYS;
+ }
+}
+
+int ambapp_int_clear(
+ struct drvmgr_dev *dev,
+ int index)
+{
+ struct drvmgr_dev *busdev;
+ struct ambapp_priv *priv;
+ int irq;
+
+ busdev = dev->parent->dev;
+ priv = dev->parent->priv;
+
+ /* Get IRQ number from index and device information */
+ irq = ambapp_int_get(dev, index);
+ if ( irq < 0 )
+ return -1;
+
+ DBG("Clear interrupt on 0x%x for dev 0x%x (IRQ: %d)\n", (unsigned int)busdev, (unsigned int)dev, irq);
+
+ if ( priv->config->ops->int_clear ) {
+ /* Let device override driver default */
+ return priv->config->ops->int_clear(dev, irq);
+ } else {
+ return DRVMGR_ENOSYS;
+ }
+}
+
+int ambapp_int_mask(
+ struct drvmgr_dev *dev,
+ int index)
+{
+ struct drvmgr_dev *busdev;
+ struct ambapp_priv *priv;
+ int irq;
+
+ busdev = dev->parent->dev;
+ priv = dev->parent->priv;
+
+ /* Get IRQ number from index and device information */
+ irq = ambapp_int_get(dev, index);
+ if ( irq < 0 )
+ return -1;
+
+ DBG("MASK interrupt on 0x%x for dev 0x%x (IRQ: %d)\n", (unsigned int)busdev, (unsigned int)dev, irq);
+
+ if ( priv->config->ops->int_mask ) {
+ /* Let device override driver default */
+ return priv->config->ops->int_mask(dev, irq);
+ } else {
+ return DRVMGR_ENOSYS;
+ }
+}
+
+int ambapp_int_unmask(
+ struct drvmgr_dev *dev,
+ int index)
+{
+ struct drvmgr_dev *busdev;
+ struct ambapp_priv *priv;
+ int irq;
+
+ busdev = dev->parent->dev;
+ priv = dev->parent->priv;
+
+ /* Get IRQ number from index and device information */
+ irq = ambapp_int_get(dev, index);
+ if ( irq < 0 )
+ return DRVMGR_EINVAL;
+
+ DBG("UNMASK interrupt on 0x%x for dev 0x%x (IRQ: %d)\n", (unsigned int)busdev, (unsigned int)dev, irq);
+
+ if ( priv->config->ops->int_unmask ) {
+ /* Let device override driver default */
+ return priv->config->ops->int_unmask(dev, irq);
+ } else {
+ return DRVMGR_ENOSYS;
+ }
+}
+
+/* Assign frequency to an AMBA Bus */
+void ambapp_bus_freq_register(
+ struct drvmgr_dev *dev,
+ int amba_interface,
+ unsigned int freq_hz
+ )
+{
+ struct ambapp_priv *priv = (struct ambapp_priv *)dev->parent->priv;
+ struct ambapp_dev *adev;
+ struct amba_dev_info *pnp = dev->businfo;
+
+ if ( freq_hz == 0 )
+ return;
+
+ if ( amba_interface == DEV_AHB_MST ) {
+ adev = (struct ambapp_dev *)
+ ((unsigned int)pnp->info.ahb_mst -
+ sizeof(struct ambapp_dev));
+ } else if ( amba_interface == DEV_AHB_SLV ) {
+ adev = (struct ambapp_dev *)
+ ((unsigned int)pnp->info.ahb_slv -
+ sizeof(struct ambapp_dev));
+ } else if ( amba_interface == DEV_APB_SLV ) {
+ adev = (struct ambapp_dev *)
+ ((unsigned int)pnp->info.apb_slv -
+ sizeof(struct ambapp_dev));
+ } else {
+ return;
+ }
+
+ /* Calculate Top bus frequency from lower part. The frequency comes
+ * from some kind of hardware able to report local bus frequency.
+ */
+ ambapp_freq_init(priv->config->abus, adev, freq_hz);
+}
+
+int ambapp_bus_freq_get(
+ struct drvmgr_dev *dev,
+ int options,
+ unsigned int *freq_hz)
+{
+ struct ambapp_priv *priv = (struct ambapp_priv *)dev->parent->priv;
+ struct ambapp_dev *adev;
+ struct amba_dev_info *pnp = dev->businfo;
+
+ if ( options == DEV_AHB_MST ) {
+ adev = (struct ambapp_dev *)
+ ((unsigned int)pnp->info.ahb_mst -
+ sizeof(struct ambapp_dev));
+ } else if ( options == DEV_AHB_SLV ) {
+ adev = (struct ambapp_dev *)
+ ((unsigned int)pnp->info.ahb_slv -
+ sizeof(struct ambapp_dev));
+ } else if ( options == DEV_APB_SLV ) {
+ adev = (struct ambapp_dev *)
+ ((unsigned int)pnp->info.apb_slv -
+ sizeof(struct ambapp_dev));
+ } else {
+ *freq_hz = 0;
+ return -1;
+ }
+
+ /* Calculate core/bus frequency from top most bus frequency. */
+ *freq_hz = ambapp_freq_get(priv->config->abus, adev);
+ if ( *freq_hz == 0 )
+ return -1;
+ return 0;
+}
+
+int ambapp_get_params(struct drvmgr_dev *dev, struct drvmgr_bus_params *params)
+{
+ struct ambapp_priv *priv = dev->parent->priv;
+
+ if ( priv->config->ops->get_params ) {
+ /* Let device override driver default */
+ return priv->config->ops->get_params(dev, params);
+ } else {
+ return -1;
+ }
+}
+
+#ifdef AMBAPPBUS_INFO_AVAIL
+void ambapp_dev_info(
+ struct drvmgr_dev *dev,
+ void (*print_line)(void *p, char *str),
+ void *p)
+{
+ struct amba_dev_info *devinfo;
+ struct ambapp_core *core;
+ char buf[64];
+ int ver, i;
+ char *str1, *str2, *str3;
+ unsigned int ahbmst_freq, ahbslv_freq, apbslv_freq;
+
+ if (!dev)
+ return;
+
+ devinfo = (struct amba_dev_info *)dev->businfo;
+ if (!devinfo)
+ return;
+ core = &devinfo->info;
+
+ print_line(p, "AMBA PnP DEVICE");
+
+ str1 = ambapp_vendor_id2str(devinfo->id.vendor);
+ if (str1 == NULL)
+ str1 = "unknown";
+ sprintf(buf, "VENDOR ID: 0x%04x (%s)", devinfo->id.vendor, str1);
+ print_line(p, buf);
+
+ str1 = ambapp_device_id2str(devinfo->id.vendor, devinfo->id.device);
+ if (str1 == NULL)
+ str1 = "unknown";
+ sprintf(buf, "DEVICE ID: 0x%04x (%s)", devinfo->id.device, str1);
+ print_line(p, buf);
+
+ ahbmst_freq = ahbslv_freq = apbslv_freq = 0;
+ ver = 0;
+ str1 = str2 = str3 = "";
+ if (core->ahb_mst) {
+ str1 = "AHBMST ";
+ ver = core->ahb_mst->ver;
+ ambapp_bus_freq_get(dev, DEV_AHB_MST, &ahbmst_freq);
+ }
+ if (core->ahb_slv) {
+ str2 = "AHBSLV ";
+ ver = core->ahb_slv->ver;
+ ambapp_bus_freq_get(dev, DEV_AHB_SLV, &ahbslv_freq);
+ }
+ if (core->apb_slv) {
+ str3 = "APBSLV";
+ ver = core->apb_slv->ver;
+ ambapp_bus_freq_get(dev, DEV_APB_SLV, &apbslv_freq);
+ }
+
+ sprintf(buf, "IRQ: %d", ambapp_int_get(dev, 0));
+ print_line(p, buf);
+
+ sprintf(buf, "VERSION: 0x%x", ver);
+ print_line(p, buf);
+
+ sprintf(buf, "ambapp_core: %p", core);
+ print_line(p, buf);
+
+ sprintf(buf, "interfaces: %s%s%s", str1, str2, str3);
+ print_line(p, buf);
+
+ if (ahbmst_freq != 0) {
+ sprintf(buf, "AHBMST FREQ: %dkHz", ahbmst_freq/1000);
+ print_line(p, buf);
+ }
+
+ if (ahbslv_freq != 0) {
+ sprintf(buf, "AHBSLV FREQ: %dkHz", ahbslv_freq/1000);
+ print_line(p, buf);
+ }
+
+ if (apbslv_freq != 0) {
+ sprintf(buf, "APBSLV FREQ: %dkHz", apbslv_freq/1000);
+ print_line(p, buf);
+ }
+
+ if (core->ahb_slv) {
+ for(i=0; i<4; i++) {
+ if (core->ahb_slv->type[i] == AMBA_TYPE_AHBIO)
+ str1 = " ahbio";
+ else if (core->ahb_slv->type[i] == AMBA_TYPE_MEM)
+ str1 = "ahbmem";
+ else
+ continue;
+ sprintf(buf, " %s[%d]: 0x%08x-0x%08x", str1, i,
+ core->ahb_slv->start[i],
+ core->ahb_slv->start[i]+core->ahb_slv->mask[i]-1);
+ print_line(p, buf);
+ }
+ }
+ if (core->apb_slv) {
+ sprintf(buf, " apb: 0x%08x-0x%08x",
+ core->apb_slv->start,
+ core->apb_slv->start + core->apb_slv->mask - 1);
+ print_line(p, buf);
+ }
+}
+#endif
+
+/* Fix device in last stage */
+int ambapp_dev_fixup(struct drvmgr_dev *dev, struct amba_dev_info *pnp)
+{
+ /* OCCAN speciality:
+ * Mulitple cores are supported through the same amba AHB interface.
+ * The number of "sub cores" can be detected by decoding the AMBA
+ * Plug&Play version information. verion = ncores. A maximum of 8
+ * sub cores are supported, each separeated with 0x100 inbetween.
+ *
+ * Now, lets detect sub cores.
+ */
+ if ( (pnp->info.device == GAISLER_CANAHB) && (pnp->info.vendor == VENDOR_GAISLER) ) {
+ struct drvmgr_dev *newdev;
+ struct amba_dev_info *pnpinfo;
+ int subcores;
+ int core;
+
+ subcores = (pnp->info.ahb_slv->ver & 0x7) + 1;
+ for(core = 1; core < subcores; core++) {
+ drvmgr_alloc_dev(&newdev, sizeof(*pnpinfo));
+ memcpy(newdev, dev, sizeof(*newdev));
+ pnpinfo = (struct amba_dev_info *)(newdev+1);
+ memcpy(pnpinfo, pnp, sizeof(*pnp));
+ pnpinfo->info.index = core;
+ pnpinfo->info.irq += core;
+ newdev->businfo = (void *)pnpinfo;
+
+ /* Register device */
+ drvmgr_dev_register(newdev);
+ }
+ } else if ( (pnp->info.device == GAISLER_GPIO) && (pnp->info.vendor == VENDOR_GAISLER) ) {
+ /* PIO[N] is connected to IRQ[N]. */
+ pnp->info.irq = 0;
+ }
+ return 0;
+}
+
+struct ambapp_dev_reg_struct {
+ struct ambapp_bus *abus;
+ struct drvmgr_bus *bus;
+ struct ambapp_dev *ahb_mst;
+ struct ambapp_dev *ahb_slv;
+ struct ambapp_dev *apb_slv;
+};
+
+void ambapp_core_register(
+ struct ambapp_dev *ahb_mst,
+ struct ambapp_dev *ahb_slv,
+ struct ambapp_dev *apb_slv,
+ struct ambapp_dev_reg_struct *arg
+ )
+{
+ struct drvmgr_dev *newdev;
+ struct amba_dev_info *pnpinfo;
+ unsigned short device;
+ unsigned char vendor;
+ int namelen;
+ char buf[64];
+
+ if ( ahb_mst ) {
+ device = ahb_mst->device;
+ vendor = ahb_mst->vendor;
+ }else if ( ahb_slv ) {
+ device = ahb_slv->device;
+ vendor = ahb_slv->vendor;
+ }else if( apb_slv ) {
+ device = apb_slv->device;
+ vendor = apb_slv->vendor;
+ } else {
+ DBG("NO DEV!\n");
+ return;
+ }
+
+ DBG("CORE REGISTER DEV [%x:%x] MST: 0x%x, SLV: 0x%x, APB: 0x%x\n", vendor, device, (unsigned int)ahb_mst, (unsigned int)ahb_slv, (unsigned int)apb_slv);
+
+ /* Get unique device name from AMBA data base by combining VENDOR and
+ * DEVICE short names
+ */
+ namelen = ambapp_vendev_id2str(vendor, device, buf);
+
+ /* Allocate a device */
+ drvmgr_alloc_dev(&newdev, sizeof(struct amba_dev_info) + namelen);
+ pnpinfo = (struct amba_dev_info *)(newdev + 1);
+ newdev->parent = arg->bus; /* Ourselfs */
+ newdev->minor_drv = 0;
+ newdev->minor_bus = 0;
+ newdev->priv = NULL;
+ newdev->drv = NULL;
+ if (namelen > 0) {
+ newdev->name = (char *)(pnpinfo + 1);
+ strcpy(newdev->name, buf);
+ } else {
+ newdev->name = NULL;
+ }
+ newdev->next_in_drv = NULL;
+ newdev->bus = NULL;
+
+ /* Init PnP information, Assign Core interfaces with this device */
+ pnpinfo->id.vendor = vendor;
+ pnpinfo->id.device = device;
+ pnpinfo->info.vendor = vendor;
+ pnpinfo->info.device = device;
+ pnpinfo->info.index = 0;
+ if ( ahb_mst ) {
+ pnpinfo->info.ahb_mst = (struct ambapp_ahb_info *)
+ ahb_mst->devinfo;
+ ambapp_alloc_dev(ahb_mst, (void *)newdev);
+ if ( pnpinfo->info.ahb_mst->irq )
+ pnpinfo->info.irq = pnpinfo->info.ahb_mst->irq;
+ }
+ if ( ahb_slv ) {
+ pnpinfo->info.ahb_slv = (struct ambapp_ahb_info *)
+ ahb_slv->devinfo;
+ ambapp_alloc_dev(ahb_slv, (void *)newdev);
+ if ( pnpinfo->info.ahb_slv->irq )
+ pnpinfo->info.irq = pnpinfo->info.ahb_slv->irq;
+ }
+ if ( apb_slv ) {
+ pnpinfo->info.apb_slv = (struct ambapp_apb_info *)
+ apb_slv->devinfo;
+ ambapp_alloc_dev(apb_slv, (void *)newdev);
+ if ( pnpinfo->info.apb_slv->irq )
+ pnpinfo->info.irq = pnpinfo->info.apb_slv->irq;
+ }
+ if ( pnpinfo->info.irq == 0 )
+ pnpinfo->info.irq = -1; /* indicate no IRQ */
+
+ /* Connect device with PnP information */
+ newdev->businfo = (void *)pnpinfo;
+
+ ambapp_dev_fixup(newdev, pnpinfo);
+
+ /* Register New Device */
+ drvmgr_dev_register(newdev);
+}
+
+/* Register one AMBA device */
+int ambapp_dev_register(struct ambapp_dev *dev, int index, void *arg)
+{
+ struct ambapp_dev_reg_struct *p = arg;
+
+#ifdef DEBUG
+ char *type;
+
+ if ( dev->dev_type == DEV_AHB_MST )
+ type = "AHB MST";
+ else if ( dev->dev_type == DEV_AHB_SLV )
+ type = "AHB SLV";
+ else if ( dev->dev_type == DEV_APB_SLV )
+ type = "APB SLV";
+
+ DBG("Found [%d:%x:%x], %s\n", index, dev->vendor, dev->device, type);
+#endif
+
+ if ( dev->dev_type == DEV_AHB_MST ) {
+ if ( p->ahb_mst ) {
+ /* This should not happen */
+ printk("ambapp_dev_register: ahb_mst not NULL!\n");
+ exit(1);
+ }
+
+ /* Remember AHB Master */
+ p->ahb_mst = dev;
+
+ /* Find AHB Slave and APB slave for this Core */
+ ambapp_for_each(p->abus, (OPTIONS_AHB_SLVS|OPTIONS_APB_SLVS|OPTIONS_FREE), dev->vendor, dev->device, ambapp_dev_register, p);
+
+ ambapp_core_register(p->ahb_mst, p->ahb_slv, p->apb_slv, p);
+ p->ahb_mst = p->ahb_slv = p->apb_slv = NULL;
+ return 0;
+
+ } else if ( dev->dev_type == DEV_AHB_SLV ) {
+ if ( p->ahb_slv ) {
+ /* Already got our AHB Slave interface */
+ return 0;
+ }
+
+ /* Remember AHB Slave */
+ p->ahb_slv = dev;
+
+ if ( p->ahb_mst ) {
+ /* Continue searching for APB Slave */
+ return 0;
+ } else {
+ /* Find APB Slave interface for this Core */
+ ambapp_for_each(p->abus, (OPTIONS_APB_SLVS|OPTIONS_FREE), dev->vendor, dev->device, ambapp_dev_register, p);
+
+ ambapp_core_register(p->ahb_mst, p->ahb_slv, p->apb_slv, p);
+ p->ahb_mst = p->ahb_slv = p->apb_slv = NULL;
+ return 0;
+ }
+ } else if ( dev->dev_type == DEV_APB_SLV ) {
+ if ( p->apb_slv ) {
+ /* This should not happen */
+ printk("ambapp_dev_register: apb_slv not NULL!\n");
+ exit(1);
+ }
+ /* Remember APB Slave */
+ p->apb_slv = dev;
+
+ if ( p->ahb_mst || p->ahb_slv ) {
+ /* Stop scanning */
+ return 1;
+ } else {
+ ambapp_core_register(p->ahb_mst, p->ahb_slv, p->apb_slv, p);
+ p->ahb_mst = p->ahb_slv = p->apb_slv = NULL;
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+/* Register all AMBA devices available on the AMBAPP bus */
+int ambapp_ids_register(struct drvmgr_bus *bus)
+{
+ struct ambapp_priv *priv = bus->priv;
+ struct ambapp_bus *abus;
+ struct ambapp_dev_reg_struct arg;
+
+ DBG("ambapp_ids_register:\n");
+
+ memset(&arg, 0, sizeof(arg));
+
+ abus = priv->config->abus;
+ arg.abus = abus;
+ arg.bus = bus;
+
+ /* Combine the AHB MST, AHB SLV and APB SLV interfaces of a core. A core has often more than
+ * one interface. A core can not have more than one interface of the same type.
+ */
+ ambapp_for_each(abus, (OPTIONS_ALL_DEVS|OPTIONS_FREE), -1, -1, ambapp_dev_register, &arg);
+
+#ifdef DEBUG
+ ambapp_print(abus->root, 1);
+#endif
+
+ return DRVMGR_OK;
+}
+
+/*** DEVICE FUNCTIONS ***/
+
+int ambapp_bus_register(struct drvmgr_dev *dev, struct ambapp_config *config)
+{
+ struct ambapp_priv *priv;
+
+ if ( !config || !config->ops )
+ return DRVMGR_OK;
+
+ DBG("AMBAPP BUS: initializing\n");
+
+ /* Register BUS */
+ drvmgr_alloc_bus(&dev->bus, sizeof(struct ambapp_priv));
+ priv = (struct ambapp_priv *)(dev->bus + 1);
+ priv->config = config;
+ if ( priv->config->bus_type == DRVMGR_BUS_TYPE_AMBAPP_DIST )
+ dev->bus->bus_type = DRVMGR_BUS_TYPE_AMBAPP_DIST;
+ else if ( priv->config->bus_type == DRVMGR_BUS_TYPE_AMBAPP_RMAP )
+ dev->bus->bus_type = DRVMGR_BUS_TYPE_AMBAPP_RMAP;
+ else
+ dev->bus->bus_type = DRVMGR_BUS_TYPE_AMBAPP;
+ dev->bus->next = NULL;
+ dev->bus->dev = dev;
+ dev->bus->priv = priv;
+ dev->bus->children = NULL;
+ dev->bus->ops = &ambapp_bus_ops;
+ dev->bus->funcs = config->funcs;
+ dev->bus->dev_cnt = 0;
+ dev->bus->reslist = NULL;
+ dev->bus->maps_up = config->maps_up;
+ dev->bus->maps_down = config->maps_down;
+
+ /* Add resource configuration */
+ if ( priv->config->resources )
+ drvmgr_bus_res_add(dev->bus, priv->config->resources);
+
+ drvmgr_bus_register(dev->bus);
+
+ return DRVMGR_OK;
+}
+
+/*** BUS INITIALIZE FUNCTIONS ***/
+
+/* Initialize the bus, register devices on this bus */
+int ambapp_bus_init1(struct drvmgr_bus *bus)
+{
+ /* Initialize the bus, register devices on this bus */
+ return ambapp_ids_register(bus);
+}
+
+int ambapp_bus_remove(struct drvmgr_bus *bus)
+{
+ return DRVMGR_OK;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/drvmgr/ambapp_bus_grlib.c b/c/src/lib/libbsp/sparc/shared/drvmgr/ambapp_bus_grlib.c
new file mode 100644
index 0000000000..eb4e5deb77
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/drvmgr/ambapp_bus_grlib.c
@@ -0,0 +1,230 @@
+/* LEON3 GRLIB AMBA Plug & Play bus driver.
+ *
+ * COPYRIGHT (c) 2008.
+ * Aeroflex Gaisler.
+ *
+ * This is driver is a wrapper for the general AMBA Plug & Play bus
+ * driver. This is the root bus driver for GRLIB systems.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2008-12-03, Daniel Hellstrom <daniel@gaisler.com>
+ * Created
+ *
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <libcpu/access.h>
+
+#include <drvmgr/ambapp_bus.h>
+#include <drvmgr/ambapp_bus_grlib.h>
+#include <genirq.h>
+
+#include <bsp.h>
+
+#define DBG(args...)
+/*#define DBG(args...) printk(args)*/
+
+int ambapp_grlib_int_register(
+ struct drvmgr_dev *dev,
+ int irq,
+ const char *info,
+ drvmgr_isr isr,
+ void *arg);
+int ambapp_grlib_int_unregister(
+ struct drvmgr_dev *dev,
+ int irq,
+ drvmgr_isr isr,
+ void *arg);
+int ambapp_grlib_int_clear(
+ struct drvmgr_dev *dev,
+ int irq);
+int ambapp_grlib_int_mask(
+ struct drvmgr_dev *dev,
+ int irq);
+int ambapp_grlib_int_unmask(
+ struct drvmgr_dev *dev,
+ int irq);
+int ambapp_grlib_get_params(
+ struct drvmgr_dev *dev,
+ struct drvmgr_bus_params *params);
+
+int ambapp_grlib_init1(struct drvmgr_dev *dev);
+int ambapp_grlib_init2(struct drvmgr_dev *dev);
+int ambapp_grlib_remove(struct drvmgr_dev *dev);
+
+/* READ/WRITE access to SpaceWire target over RMAP */
+void *ambapp_grlib_rw_arg(struct drvmgr_dev *dev);
+
+struct ambapp_ops ambapp_grlib_ops = {
+ .int_register = ambapp_grlib_int_register,
+ .int_unregister = ambapp_grlib_int_unregister,
+ .int_clear = ambapp_grlib_int_clear,
+ .int_mask = ambapp_grlib_int_mask,
+ .int_unmask = ambapp_grlib_int_unmask,
+ .get_params = ambapp_grlib_get_params
+};
+
+void *ambapp_grlib_rw_arg(struct drvmgr_dev *dev)
+{
+ return dev; /* No argument really needed, but for debug? */
+}
+
+struct drvmgr_func ambapp_grlib_funcs[] =
+{
+ DRVMGR_FUNC(AMBAPP_RW_ARG, ambapp_grlib_rw_arg),
+
+ DRVMGR_FUNC(AMBAPP_R8, _ld8),
+ DRVMGR_FUNC(AMBAPP_R16, _ld16),
+ DRVMGR_FUNC(AMBAPP_R32, _ld32),
+ DRVMGR_FUNC(AMBAPP_R64, _ld64),
+
+ DRVMGR_FUNC(AMBAPP_W8, _st8),
+ DRVMGR_FUNC(AMBAPP_W16, _st16),
+ DRVMGR_FUNC(AMBAPP_W32, _st32),
+ DRVMGR_FUNC(AMBAPP_W64, _st64),
+
+ DRVMGR_FUNC(AMBAPP_RMEM, memcpy),
+ DRVMGR_FUNC(AMBAPP_WMEM, memcpy),
+
+ DRVMGR_FUNC_END,
+};
+
+struct drvmgr_drv_ops ambapp_grlib_drv_ops =
+{
+ .init = {ambapp_grlib_init1, ambapp_grlib_init2, NULL, NULL},
+ .remove = ambapp_grlib_remove,
+ .info = NULL,
+};
+
+struct drvmgr_drv ambapp_bus_drv_grlib =
+{
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_GRLIB_AMBAPP_ID, /* Driver ID */
+ "AMBAPP_GRLIB_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_ROOT, /* Bus Type */
+ &ambapp_grlib_drv_ops,
+ NULL, /* Funcs */
+ 0,
+ 0,
+};
+
+static struct grlib_config *drv_mgr_grlib_config = NULL;
+
+void ambapp_grlib_register(void)
+{
+ drvmgr_drv_register(&ambapp_bus_drv_grlib);
+}
+
+int ambapp_grlib_root_register(struct grlib_config *config)
+{
+
+ /* Save the configuration for later */
+ drv_mgr_grlib_config = config;
+
+ /* Register root device driver */
+ drvmgr_root_drv_register(&ambapp_bus_drv_grlib);
+
+ return 0;
+}
+
+/* Function called from Driver Manager Initialization Stage 1 */
+int ambapp_grlib_init1(struct drvmgr_dev *dev)
+{
+ struct ambapp_config *config;
+
+ dev->priv = NULL;
+ dev->name = "GRLIB AMBA PnP";
+
+ DBG("AMBAPP GRLIB: intializing\n");
+
+ config = malloc(sizeof(struct ambapp_config));
+ if ( !config )
+ return RTEMS_NO_MEMORY;
+
+ config->ops = &ambapp_grlib_ops;
+ config->maps_up = DRVMGR_TRANSLATE_ONE2ONE;
+ config->maps_down = DRVMGR_TRANSLATE_ONE2ONE;
+ config->abus = drv_mgr_grlib_config->abus;
+ config->resources = drv_mgr_grlib_config->resources;
+ config->funcs = ambapp_grlib_funcs;
+ config->bus_type = DRVMGR_BUS_TYPE_AMBAPP;
+
+ /* Initialize the generic part of the AMBA Bus */
+ return ambapp_bus_register(dev, config);
+}
+
+int ambapp_grlib_init2(struct drvmgr_dev *dev)
+{
+ return 0;
+}
+
+int ambapp_grlib_remove(struct drvmgr_dev *dev)
+{
+ return 0;
+}
+
+int ambapp_grlib_int_register
+ (
+ struct drvmgr_dev *dev,
+ int irq,
+ const char *info,
+ drvmgr_isr isr,
+ void *arg
+ )
+{
+ return BSP_shared_interrupt_register(irq, info, isr, arg);
+}
+
+int ambapp_grlib_int_unregister
+ (
+ struct drvmgr_dev *dev,
+ int irq,
+ drvmgr_isr isr,
+ void *arg
+ )
+{
+ return BSP_shared_interrupt_unregister(irq, isr, arg);
+}
+
+int ambapp_grlib_int_clear
+ (
+ struct drvmgr_dev *dev,
+ int irq)
+{
+ BSP_shared_interrupt_clear(irq);
+ return DRVMGR_OK;
+}
+
+int ambapp_grlib_int_mask
+ (
+ struct drvmgr_dev *dev,
+ int irq
+ )
+{
+ BSP_shared_interrupt_mask(irq);
+ return DRVMGR_OK;
+}
+
+int ambapp_grlib_int_unmask
+ (
+ struct drvmgr_dev *dev,
+ int irq
+ )
+{
+ BSP_shared_interrupt_unmask(irq);
+ return DRVMGR_OK;
+}
+
+int ambapp_grlib_get_params(struct drvmgr_dev *dev, struct drvmgr_bus_params *params)
+{
+ /* Leave params->freq_hz untouched for default */
+ params->dev_prefix = "";
+ return 0;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/drvmgr/ambapp_bus_leon2.c b/c/src/lib/libbsp/sparc/shared/drvmgr/ambapp_bus_leon2.c
new file mode 100644
index 0000000000..d68a362470
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/drvmgr/ambapp_bus_leon2.c
@@ -0,0 +1,268 @@
+/* LEON2 GRLIB AMBA Plug & Play bus driver.
+ *
+ * COPYRIGHT (c) 2008.
+ * Aeroflex Gaisler.
+ *
+ * This is driver is a wrapper for the general AMBA Plug & Play bus
+ * driver. This is a bus driver for LEON2-GRLIB systems providing a
+ * AMBA Plug & Play bus, the parent bus must be a LEON2 hardcoded
+ * Bus. All IRQs must be routed to this bus driver in order for IRQs
+ * to work. The PnP information is used to extract IRQs and base
+ * register addresses.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2008-12-03, Daniel Hellstrom <daniel@gaisler.com>
+ * Created
+ *
+ */
+
+#include <bsp.h>
+
+#ifdef LEON2
+#include <stdlib.h>
+#include <stdio.h>
+#include <libcpu/access.h>
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+#include <drvmgr/leon2_amba_bus.h>
+
+#define DBG(args...)
+
+int ambapp_leon2_int_register(
+ struct drvmgr_dev *dev,
+ int index,
+ const char *info,
+ drvmgr_isr isr,
+ void *arg);
+int ambapp_leon2_int_unregister(
+ struct drvmgr_dev *dev,
+ int index,
+ drvmgr_isr isr,
+ void *arg);
+int ambapp_leon2_int_clear(
+ struct drvmgr_dev *dev,
+ int index);
+int ambapp_leon2_int_mask(
+ struct drvmgr_dev *dev,
+ int irq);
+int ambapp_leon2_int_unmask(
+ struct drvmgr_dev *dev,
+ int irq);
+int ambapp_leon2_get_params(
+ struct drvmgr_dev *dev,
+ struct drvmgr_bus_params *params);
+
+int ambapp_leon2_init1(struct drvmgr_dev *dev);
+int ambapp_leon2_init2(struct drvmgr_dev *dev);
+int ambapp_leon2_remove(struct drvmgr_dev *dev);
+
+/* READ/WRITE access to SpaceWire target over RMAP */
+void *ambapp_leon2_rw_arg(struct drvmgr_dev *dev);
+
+struct ambappl2_priv {
+ struct ambapp_bus abus;
+ struct ambapp_config config;
+};
+
+struct ambapp_ops ambapp_leon2_ops = {
+ .int_register = ambapp_leon2_int_register,
+ .int_unregister = ambapp_leon2_int_unregister,
+ .int_clear = ambapp_leon2_int_clear,
+ .int_mask = ambapp_leon2_int_mask,
+ .int_unmask = ambapp_leon2_int_unmask,
+ .get_params = ambapp_leon2_get_params
+};
+
+struct drvmgr_func ambapp_leon2_funcs[] = {
+ DRVMGR_FUNC(AMBAPP_RW_ARG, ambapp_leon2_rw_arg),
+
+ DRVMGR_FUNC(AMBAPP_R8, _ld8),
+ DRVMGR_FUNC(AMBAPP_R16, _ld16),
+ DRVMGR_FUNC(AMBAPP_R32, _ld32),
+ DRVMGR_FUNC(AMBAPP_R64, _ld64),
+
+ DRVMGR_FUNC(AMBAPP_W8, _st8),
+ DRVMGR_FUNC(AMBAPP_W16, _st16),
+ DRVMGR_FUNC(AMBAPP_W32, _st32),
+ DRVMGR_FUNC(AMBAPP_W64, _st64),
+
+ DRVMGR_FUNC(AMBAPP_RMEM, memcpy),
+ DRVMGR_FUNC(AMBAPP_WMEM, memcpy),
+
+ DRVMGR_FUNC_END
+};
+
+struct drvmgr_drv_ops ambapp_ops = {
+ .init = {ambapp_leon2_init1, ambapp_leon2_init2, NULL, NULL},
+ .remove = ambapp_leon2_remove,
+ .info = NULL,
+};
+
+struct leon2_amba_dev_id ambapp_leon2_ids[] = {
+ {LEON2_AMBA_AMBAPP_ID},
+ {0}
+};
+
+struct leon2_amba_drv_info ambapp_bus_drv_leon2 = {
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_LEON2_AMBA_AMBAPP, /* Driver ID */
+ "AMBAPP_LEON2_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_LEON2_AMBA, /* Bus Type */
+ &ambapp_ops,
+ NULL, /* Funcs */
+ 0,
+ sizeof(struct ambappl2_priv), /* Let DrvMgr allocate priv */
+ },
+ &ambapp_leon2_ids[0]
+};
+
+void ambapp_leon2_register(void)
+{
+ drvmgr_drv_register(&ambapp_bus_drv_leon2.general);
+}
+
+/* Function called from a hard configuration */
+int ambapp_leon2_init1(struct drvmgr_dev *dev)
+{
+ union drvmgr_key_value *value;
+ struct ambappl2_priv *priv = dev->priv;
+ struct leon2_amba_dev_info *devinfo;
+ struct ambapp_config *config;
+ unsigned int ioarea;
+ unsigned int freq_hz;
+ LEON_Register_Map *regs;
+
+ dev->name = "LEON2 AMBA PnP";
+
+ if (!priv)
+ return DRVMGR_NOMEM;
+
+ config = &priv->config;
+ config->abus = &priv->abus;
+ config->ops = &ambapp_leon2_ops;
+ config->maps_up = DRVMGR_TRANSLATE_ONE2ONE;
+ config->maps_down = DRVMGR_TRANSLATE_ONE2ONE;
+ config->funcs = ambapp_leon2_funcs;
+ config->bus_type = DRVMGR_BUS_TYPE_LEON2_AMBA;
+
+ /* Get AMBA PnP Area from REG0 */
+ devinfo = (struct leon2_amba_dev_info *)dev->businfo;
+ ioarea = devinfo->reg_base;
+
+ /* Scan AMBA PnP Bus. ABUS has already been cleared with memset() */
+ ambapp_scan(&priv->abus, ioarea, NULL, NULL);
+
+ /* Try to get Configuration from resource configuration */
+
+ value = drvmgr_dev_key_get(dev, "busFreq", KEY_TYPE_INT);
+ if (value) {
+ /* Set frequency of AMBA bus if specified by user. The frequency
+ * must be for AHB bus which IOAREA matches (AHB bus 0).
+ */
+ freq_hz = value->i;
+ } else {
+ /* Get Bus/LEON2 Frequency from timer prescaler,
+ * the hardcoded address is used to get to timer
+ */
+ regs = (LEON_Register_Map *) 0x80000000;
+ freq_hz = (regs->Scaler_Reload + 1) * 1000 * 1000;
+ }
+ /* Note that this can be overrided by a driver on the AMBA PnP bus.*/
+ ambapp_freq_init(&priv->abus, NULL, freq_hz);
+
+ value = drvmgr_dev_key_get(dev, "drvRes", KEY_TYPE_POINTER);
+ if (!value) {
+ DBG("ambapp_leon2_init1: Failed getting resource drvRes\n");
+ config->resources = NULL;
+ } else {
+ DBG("ambapp_leon2_init1: drvRes: 0x%08x\n", (unsigned int)value->ptr);
+ config->resources = (struct drvmgr_bus_res *)value->ptr;
+ }
+
+ /* Initialize the AMBA Bus */
+ return ambapp_bus_register(dev, config);
+}
+
+int ambapp_leon2_init2(struct drvmgr_dev *dev)
+{
+ return 0;
+}
+
+int ambapp_leon2_remove(struct drvmgr_dev *dev)
+{
+ return 0;
+}
+
+void *ambapp_leon2_rw_arg(struct drvmgr_dev *dev)
+{
+ return dev; /* No argument really needed, by for debug */
+}
+
+int ambapp_leon2_int_register
+ (
+ struct drvmgr_dev *dev,
+ int index,
+ const char *info,
+ drvmgr_isr isr,
+ void *arg
+ )
+{
+ /* Let LEON2 bus handle interrupt requests */
+ return drvmgr_interrupt_register(dev->parent->dev, index, info, isr, arg);
+}
+
+int ambapp_leon2_int_unregister
+ (
+ struct drvmgr_dev *dev,
+ int index,
+ drvmgr_isr isr,
+ void *arg
+ )
+{
+ /* Let LEON2 bus handle interrupt requests */
+ return drvmgr_interrupt_unregister(dev->parent->dev, index, isr, arg);
+}
+
+int ambapp_leon2_int_clear
+ (
+ struct drvmgr_dev *dev,
+ int index
+ )
+{
+ /* Let LEON2 bus handle interrupt requests */
+ return drvmgr_interrupt_clear(dev->parent->dev, index);
+}
+
+int ambapp_leon2_int_mask
+ (
+ struct drvmgr_dev *dev,
+ int index
+ )
+{
+ /* Let LEON2 bus handle interrupt requests */
+ return drvmgr_interrupt_mask(dev->parent->dev, index);
+}
+
+int ambapp_leon2_int_unmask
+ (
+ struct drvmgr_dev *dev,
+ int index
+ )
+{
+ /* Let LEON2 bus handle interrupt requests */
+ return drvmgr_interrupt_unmask(dev->parent->dev, index);
+}
+
+int ambapp_leon2_get_params(struct drvmgr_dev *dev, struct drvmgr_bus_params *params)
+{
+ params->dev_prefix = "";
+ return 0;
+}
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/drvmgr/ambapp_bus_rmap.c b/c/src/lib/libbsp/sparc/shared/drvmgr/ambapp_bus_rmap.c
new file mode 100644
index 0000000000..a5c6afb834
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/drvmgr/ambapp_bus_rmap.c
@@ -0,0 +1,776 @@
+/* RMAP AMBA Plug & Play bus driver. The AMBA bus is accessed over a SpaceWire network.
+ *
+ * COPYRIGHT (c) 2008.
+ * Aeroflex Gaisler.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2009-11-20, Daniel Hellstrom <daniel@gaisler.com>
+ * Created
+ * 2010-02-03, Daniel Hellstrom <daniel@gaisler.com>
+ * Added support for prefix in device name.
+ *
+ * MEMORY PARTITIONS
+ * -----------------
+ * A partition represents a memory area, for example the SRAM of a system, the drivers
+ * may allocate from different partitions to make sure that the descriptors of buffers
+ * are located at the correct place.
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <drvmgr/spw_bus.h>
+#include <drvmgr/ambapp_bus.h>
+#include <drvmgr/ambapp_bus_rmap.h>
+#include <genirq.h>
+#include <grlib.h>
+
+#include <bsp.h>
+
+/* Remote RMAP Access macros */
+#define WRITE_REG(pDev, adr, value) priv->rw_w32((uint32_t *)adr, (uint32_t)value, &pDev->rw_arg)
+#define READ_REG(pDev, adr) priv->rw_r32((uint32_t *)adr, &pDev->rw_arg)
+
+#define PARTITION_MAX 4
+#define INHERIT_LENGTH 11
+
+#define DBG(args...)
+/*#define DBG(args...) printk(args)*/
+
+int ambapp_bus_rmap_debug = 0;
+
+struct mem_block;
+
+struct mem_block {
+ struct mem_block *next;
+ struct mem_block *prev;
+ unsigned int start;
+ unsigned int length;
+};
+
+struct mem_partition {
+ /* Free memory */
+ struct mem_block *head;
+ struct mem_block *tail;
+};
+
+struct ambapp_rmap_priv {
+ struct drvmgr_dev *dev;
+ char prefix[32];
+ int minor;
+ struct ambapp_config config;
+ struct ambapp_bus abus;
+
+ /* MEMORY ALLOCATION */
+ unsigned int partition_valid;
+ struct mem_partition partitions[PARTITION_MAX];
+
+ /* IRQ HANDLING */
+ int irq_support;
+ genirq_t genirq;
+ struct irqmp_regs *irq;
+ unsigned int mask;
+
+ /* Access routines */
+ struct drvmgr_func funcs[INHERIT_LENGTH+3];
+ struct drvmgr_rw_arg rw_arg;
+ spwbus_w32 rw_w32;
+ spwbus_r32 rw_r32;
+ spwbus_rmem rw_rmem;
+};
+
+int ambapp_rmap_int_register(
+ struct drvmgr_dev *dev,
+ int irq,
+ const char *info,
+ drvmgr_isr isr,
+ void *arg);
+int ambapp_rmap_int_unregister(
+ struct drvmgr_dev *dev,
+ int irq,
+ drvmgr_isr isr,
+ void *arg);
+int ambapp_rmap_int_unmask(struct drvmgr_dev *dev, int irq);
+int ambapp_rmap_int_mask(struct drvmgr_dev *dev, int irq);
+int ambapp_rmap_int_clear(struct drvmgr_dev *dev, int irq);
+int ambapp_rmap_get_params(
+ struct drvmgr_dev *dev,
+ struct drvmgr_bus_params *params);
+void ambapp_rmap_isr(void *arg);
+
+int ambapp_rmap_init1(struct drvmgr_dev *dev);
+int ambapp_rmap_init2(struct drvmgr_dev *dev);
+
+void *ambapp_rmap_rw_arg(struct drvmgr_dev *dev);
+void ambapp_rmap_rw_err(struct drvmgr_rw_arg *a, struct drvmgr_bus *bus,
+ int funcid, void *adr);
+
+struct ambapp_ops ambapp_rmap_ops = {
+ .int_register = ambapp_rmap_int_register,
+ .int_unregister = ambapp_rmap_int_unregister,
+ .int_clear = ambapp_rmap_int_clear,
+ .int_unmask = ambapp_rmap_int_unmask,
+ .int_mask = ambapp_rmap_int_mask,
+ .get_params = ambapp_rmap_get_params
+};
+
+struct spw_id spw_rmap_ids[] =
+{
+ {SPW_NODE_ID_GRLIB},
+ {SPW_NODE_ID_NONE}
+};
+
+struct drvmgr_drv_ops ambapp_rmap_drv_ops =
+{
+ .init = {ambapp_rmap_init1, ambapp_rmap_init2, NULL, NULL},
+ .remove = NULL,
+ .info = NULL,
+};
+
+struct spw_bus_drv_info ambapp_bus_drv_rmap =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_SPW_RMAP_AMBAPP_ID, /* Driver ID */
+ "AMBAPP_RMAP_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_SPW_RMAP, /* Bus Type */
+ &ambapp_rmap_drv_ops,
+ NULL, /* Funcs */
+ 0,
+ sizeof(struct ambapp_rmap_priv),
+ },
+ &spw_rmap_ids[0],
+
+};
+
+int ambapp_rmap_inherit_list[INHERIT_LENGTH] =
+{
+ SPWBUS_R8,
+ SPWBUS_R16,
+ SPWBUS_R32,
+ SPWBUS_R64,
+ SPWBUS_W8,
+ SPWBUS_W16,
+ SPWBUS_W32,
+ SPWBUS_W64,
+ SPWBUS_RMEM,
+ SPWBUS_WMEM,
+ SPWBUS_MEMSET,
+};
+
+struct drvmgr_bus_res **ambapp_rmap_resources = NULL;
+int ambapp_rmap_resources_cnt = 0;
+
+void ambapp_rmap_register(void)
+{
+ drvmgr_drv_register(&ambapp_bus_drv_rmap.general);
+}
+
+void ambapp_rmap_set_resources(struct drvmgr_bus_res **resources, int cnt)
+{
+ ambapp_rmap_resources = resources;
+ ambapp_rmap_resources_cnt = cnt;
+}
+
+void *ambapp_rmap_memcpy(
+ void *dest,
+ const void *src,
+ int n,
+ struct ambapp_bus *abus)
+{
+ struct ambapp_rmap_priv *priv = (struct ambapp_rmap_priv *)
+ ((unsigned int)abus -
+ offsetof(struct ambapp_rmap_priv, abus));
+
+ priv->rw_rmem(dest, src, n, &priv->rw_arg);
+
+ return dest;
+}
+
+/* Function called from Driver Manager Initialization Stage 1 */
+int ambapp_rmap_init1(struct drvmgr_dev *dev)
+{
+ struct ambapp_config *config;
+ union drvmgr_key_value *value;
+ int status, i, funcid;
+ unsigned int ioarea, freq;
+ struct ambapp_rmap_priv *priv;
+ struct spw_bus_dev_info *businfo;
+ struct ambapp_dev *tmp;
+ char prefix[32];
+
+ dev->name = "RMAP AMBA PnP";
+ businfo = (struct spw_bus_dev_info *)dev->businfo;
+
+ DBG("AMBAPP RMAP: intializing\n");
+
+ priv = dev->priv;
+ if ( !priv )
+ return DRVMGR_NOMEM;
+
+ /* Get Configuration */
+ ioarea = 0xfff00000; /* Defualt IO Area */
+ value = drvmgr_dev_key_get(dev, "IOArea", KEY_TYPE_INT);
+ if ( value ) {
+ ioarea = value->i;
+ }
+ freq = 0;
+ value = drvmgr_dev_key_get(dev, "BusFreq", KEY_TYPE_INT);
+ if ( value )
+ freq = value->i;
+ value = drvmgr_dev_key_get(dev, "noIRQ", KEY_TYPE_INT);
+ if ( value )
+ priv->irq_support = 0;
+ else
+ priv->irq_support = 1;
+
+ priv->dev = dev;
+ if ( priv->irq_support )
+ priv->genirq = genirq_init(16);
+
+ /* Get Read/Write operations for bus */
+ priv->rw_arg.dev = dev;
+ priv->rw_arg.arg = (void *)drvmgr_func_call(dev->parent, SPWBUS_RW_ARG, dev, NULL, NULL, NULL);
+ drvmgr_func_get(dev->parent, SPWBUS_R32, (void **)&priv->rw_r32);
+ drvmgr_func_get(dev->parent, SPWBUS_W32, (void **)&priv->rw_w32);
+ drvmgr_func_get(dev->parent, SPWBUS_RMEM, (void **)&priv->rw_rmem);
+
+ /* Scan Amba Bus */
+ status = ambapp_scan(&priv->abus, ioarea, ambapp_rmap_memcpy, NULL);
+ if ( status ) {
+ return DRVMGR_FAIL;
+ }
+
+ if ( ambapp_bus_rmap_debug )
+ ambapp_print(&priv->abus, 10);
+
+ /* Find IRQ controller */
+ tmp = (void *)ambapp_for_each(&priv->abus, (OPTIONS_ALL|OPTIONS_APB_SLVS),
+ VENDOR_GAISLER, GAISLER_IRQMP,
+ ambapp_find_by_idx, NULL);
+ if ( !tmp ) {
+ /* Silent error if not IRQ controller is found and IRQ support
+ * is disabled
+ */
+ if ( priv->irq_support )
+ return -4;
+ } else {
+ priv->irq = (struct irqmp_regs *)DEV_TO_APB(tmp)->start;
+ /* Set up IRQ controller */
+ WRITE_REG(priv, &priv->irq->iclear, 0xffff);
+ WRITE_REG(priv, &priv->irq->ilevel, 0);
+ WRITE_REG(priv, &priv->irq->mask[0], 0);
+
+ /* Clear any old interrupt requests (IRQ IS LEVEL) */
+ drvmgr_interrupt_clear(priv->dev, 0);
+ }
+
+ /* Get Filesystem name prefix */
+ prefix[0] = '\0';
+ if ( drvmgr_get_dev_prefix(dev, prefix) ) {
+ /* Failed to get prefix, make sure of a unique FS name
+ * by using the driver minor.
+ */
+ sprintf(priv->prefix, "/dev/rmap_%02x",
+ (unsigned char)businfo->dstadr);
+ } else {
+ /* Got special prefix, this means we have a bus prefix
+ * And we should use our "bus minor"
+ */
+ sprintf(priv->prefix, "/dev/%srmap_%02x",
+ prefix, (unsigned char)businfo->dstadr);
+ }
+
+ mkdir(priv->prefix, S_IRWXU | S_IRWXG | S_IRWXO);
+ strcat(priv->prefix, "/");
+
+ printf("\n\n--- RMAP AMBAPnP[%d] ---\n", dev->minor_drv);
+ printf(" SpW ADDRESS: %d\n", businfo->dstadr);
+ printf(" DEV BASE: %s\n", priv->prefix);
+ printf(" FREQ: %u [Hz]\n", freq);
+ printf(" I/O AREA: 0x%08x\n", ioarea);
+ printf(" IRQ REGS: 0x%08x\n", (unsigned int)priv->irq);
+
+ /* Initialize the Frequency of the AMBA bus */
+ ambapp_freq_init(&priv->abus, NULL, freq);
+
+ /* Inherit R/W functions from parent */
+ for (i = 0; i < INHERIT_LENGTH; i++) {
+ funcid = ambapp_rmap_inherit_list[i];
+ if (drvmgr_func_get(dev->parent, funcid, &priv->funcs[i].func) != DRVMGR_OK)
+ return -5;
+ priv->funcs[i].funcid = funcid;
+ }
+ priv->funcs[i].funcid = AMBAPP_RMAP_RW_ARG;
+ priv->funcs[i].func = ambapp_rmap_rw_arg;
+ priv->funcs[i+1].funcid = AMBAPP_RMAP_RW_ERR;
+ priv->funcs[i+1].func = ambapp_rmap_rw_err;
+ priv->funcs[i+2].funcid = DRVMGR_FUNCID_NONE;
+
+ config = &priv->config;
+ config->ops = &ambapp_rmap_ops;
+ config->maps_up = DRVMGR_TRANSLATE_NO_BRIDGE;
+ config->maps_down = DRVMGR_TRANSLATE_NO_BRIDGE;
+ config->abus = &priv->abus;
+ config->bus_type = DRVMGR_BUS_TYPE_AMBAPP_RMAP;
+ config->funcs = priv->funcs;
+ /* Set this AMBA Bus driver resources */
+ if ( ambapp_rmap_resources && (priv->dev->minor_drv < ambapp_rmap_resources_cnt) ) {
+ config->resources = ambapp_rmap_resources[priv->dev->minor_drv];
+ } else {
+ value = drvmgr_dev_key_get(dev, "BusRes", KEY_TYPE_POINTER);
+ if ( value )
+ config->resources = value->ptr;
+ else
+ config->resources = NULL;
+ }
+
+ /* Target is assumed to be equipped with 256Mb RAM */
+ /*ambapp_rmap_partition_create(dev, 0, 0x40000000, 0x10000000);*/
+ /*ambapp_rmap_partition_create_internal(priv, 0, 0x40000000, 0x10000000);*/
+
+ /* Initialize the AMBA Bus */
+ return ambapp_bus_register(dev, config);
+}
+
+int ambapp_rmap_init2(struct drvmgr_dev *dev)
+{
+ struct ambapp_rmap_priv *priv = dev->priv;
+
+ /* Enable System IRQ so that the SpW Node Core's interrupt goes through.
+ *
+ * It is important to enable it in stage init2. If interrupts were
+ * enabled in init1 this might hang the system when more than one SpW
+ * Node is connected to the same IRQ line, this is because interrupts
+ * might be shared and Node 2 have not initialized and might therefore
+ * drive interrupt already when entering init1().
+ */
+ if ( priv->irq_support )
+ drvmgr_interrupt_register(priv->dev, 0, "ambapp_rmap",
+ ambapp_rmap_isr, (void *)priv);
+
+ return 0;
+}
+
+/* The ISR is executed on the SpW-BUS ISR Task, ie. not in interrupt context */
+void ambapp_rmap_isr (void *arg)
+{
+ struct ambapp_rmap_priv *priv = arg;
+ unsigned int status, tmp;
+ int irq;
+ tmp = status = READ_REG(priv, &priv->irq->ipend) & priv->mask;
+ /* DBG("AMBAPP-RMAP-ISR: IRQ 0x%x\n",status); */
+
+ /* Clear handled IRQs at remote IRQ controller, These IRQs are not
+ * level sensitive which makes it ok to clear the before they are
+ * handled.
+ */
+ if ( status )
+ WRITE_REG(priv, &priv->irq->iclear, status);
+
+ for (irq=0; irq<16; irq++) {
+ if ( status & (1<<irq) ) {
+ genirq_doirq(priv->genirq, irq);
+ status &= ~(1<<irq);
+ if ( status == 0 )
+ break;
+ }
+ }
+
+ /* ACK interrupt, this is because Interrupt is Level, so the IRQ
+ * Controller still drives the IRQ.
+ */
+ if ( tmp )
+ drvmgr_interrupt_clear(priv->dev, 0);
+
+ DBG("AMBAPP-RMAP-ISR: 0x%x\n", tmp);
+}
+
+void *ambapp_rmap_rw_arg(struct drvmgr_dev *dev)
+{
+ struct ambapp_rmap_priv *priv;
+
+ if (!dev || !dev->parent || !dev->parent->dev)
+ return (void *)DRVMGR_FAIL;
+
+ priv = dev->parent->dev->priv;
+
+ /* Use same argument as for ourselves */
+ return priv->rw_arg.arg;
+}
+
+/* Called by SpaceWire Lay if a device directly on this bus has been witness
+ * to an error.
+ */
+void ambapp_rmap_rw_err(struct drvmgr_rw_arg *a, struct drvmgr_bus *bus,
+ int funcid, void *adr)
+{
+ printk("AMBAPP_RMAP: erraccess %p with 0x%08x (amba: %p, dev: %p)\n",
+ adr, funcid, a->dev->parent, a->dev);
+ /* Take some error action here? Remove bus or just faulting device? */
+}
+
+int ambapp_rmap_int_register(
+ struct drvmgr_dev *dev,
+ int irq,
+ const char *info,
+ drvmgr_isr isr,
+ void *arg)
+{
+ struct ambapp_rmap_priv *priv = dev->parent->dev->priv;
+ int status;
+ unsigned int tmp;
+
+ DBG("AMBAPP-RMAP-INT_REG: %d\n", irq);
+
+ if (priv->irq_support == 0)
+ return -1;
+
+ status = genirq_register(priv->genirq, irq, isr, arg);
+ if ( status == 0 ) {
+ /* Disable and clear IRQ for first registered handler */
+ WRITE_REG(priv, &priv->irq->iclear, (1<<irq));
+ tmp = READ_REG(priv, &priv->irq->mask[0]);
+ WRITE_REG(priv, &priv->irq->mask[0], (tmp & ~(1<<irq))); /* mask interrupt source */
+ } else if ( status == 1 )
+ status = 0;
+
+ if (status != 0)
+ return DRVMGR_FAIL;
+
+ status = genirq_enable(priv->genirq, irq, isr, arg);
+ if ( status == 0 ) {
+ /* Enable IRQ for first enabled handler only */
+
+ /* unmask interrupt source */
+ priv->mask = READ_REG(priv, &priv->irq->mask[0]);
+ priv->mask |= (1<<irq);
+ WRITE_REG(priv, &priv->irq->mask[0], priv->mask);
+ } else if ( status == 1 )
+ status = DRVMGR_OK;
+
+ return status;
+}
+
+int ambapp_rmap_int_unregister(
+ struct drvmgr_dev *dev,
+ int irq,
+ drvmgr_isr isr,
+ void *arg)
+{
+ struct ambapp_rmap_priv *priv = dev->parent->dev->priv;
+ int status;
+ unsigned int tmp;
+
+ DBG("AMBAPP-RMAP-INT_UNREG: %d\n", irq);
+
+ if (priv->irq_support == 0)
+ return -1;
+
+ status = genirq_disable(priv->genirq, irq, isr, arg);
+ if ( status == 0 ) {
+ /* Disable IRQ only when no enabled handler exists */
+
+ /* mask interrupt source */
+ priv->mask = READ_REG(priv, &priv->irq->mask[0]);
+ priv->mask &= ~(1<<irq);
+ WRITE_REG(priv, &priv->irq->mask[0], priv->mask);
+ }
+
+ status = genirq_unregister(priv->genirq, irq, isr, arg);
+ if ( status != 0 )
+ status = DRVMGR_FAIL;
+
+ return status;
+}
+
+int ambapp_rmap_int_unmask(struct drvmgr_dev *dev, int irq)
+{
+ struct ambapp_rmap_priv *priv = dev->parent->dev->priv;
+
+ DBG("AMBAPP-RMAP-INT_UNMASK: %d\n", irq);
+
+ if (priv->irq_support == 0)
+ return -1;
+
+ if ( genirq_check(priv->genirq, irq) )
+ return DRVMGR_FAIL;
+
+ /* unmask interrupt source */
+ priv->mask = READ_REG(priv, &priv->irq->mask[0]);
+ priv->mask |= (1<<irq);
+ WRITE_REG(priv, &priv->irq->mask[0], priv->mask);
+
+ return DRVMGR_OK;
+}
+
+int ambapp_rmap_int_mask(struct drvmgr_dev *dev, int irq)
+{
+ struct ambapp_rmap_priv *priv = dev->parent->dev->priv;
+
+ DBG("AMBAPP-RMAP-INT_MASK: %d\n", irq);
+
+ if (priv->irq_support == 0)
+ return -1;
+
+ if ( genirq_check(priv->genirq, irq) )
+ return DRVMGR_FAIL;
+
+ /* mask interrupt source */
+ priv->mask = READ_REG(priv, &priv->irq->mask[0]);
+ priv->mask &= (1<<irq);
+ WRITE_REG(priv, &priv->irq->mask[0], priv->mask);
+
+ return DRVMGR_OK;
+}
+
+int ambapp_rmap_int_clear(struct drvmgr_dev *dev, int irq)
+{
+ struct ambapp_rmap_priv *priv = dev->parent->dev->priv;
+
+ if (priv->irq_support == 0)
+ return -1;
+
+ if ( genirq_check(priv->genirq, irq) )
+ return DRVMGR_FAIL;
+
+ WRITE_REG(priv, &priv->irq->iclear, (1<<irq));
+
+ return 0;
+}
+
+int ambapp_rmap_get_params(struct drvmgr_dev *dev, struct drvmgr_bus_params *params)
+{
+ struct ambapp_rmap_priv *priv = dev->parent->dev->priv;
+
+ params->dev_prefix = &priv->prefix[5];
+ return 0;
+}
+
+/************* MEMORY SERVICES FOR REMOTE TARGETS *************
+ *
+ * This was written with resource usage in mind, and alignment needs
+ * that has to be fullfilled. It is typically used by drivers to allocate
+ * large data areas that need a certain alignment.
+ */
+
+/* Caller know that there is enough memory within block, this function allocates it */
+void *alloc_block(struct mem_partition *part, struct mem_block *block, unsigned int start, size_t size)
+{
+ struct mem_block *newblock;
+ unsigned int block_end;
+
+ DBG("ALLOC_BLOCK: 0x%x - 0x%x\n", start, start + size);
+
+ /* At start of block? */
+ if ( block->start == start ) {
+ block->start += size;
+ block->length -= size;
+ return (void *)start;
+ }
+
+ /* At End of block? */
+ block_end = block->start + block->length;
+ if ( block_end == (start + size) ) {
+ block->length -= size;
+ return (void *)start;
+ }
+
+ /* Not at start or end means that we must insert a new block describing
+ * the area in between the two blocks.
+ */
+ newblock = (struct mem_block *)malloc(sizeof(struct mem_block));
+ if ( !newblock ) {
+ return NULL;
+ }
+
+ /* 1. assign unused area after the allocated area to newblock
+ * 2. shink the first block that the area is taken from
+ * 3. insert newblock into free memory list.
+ *
+ * 1.
+ */
+ newblock->start = start + size;
+ newblock->length = block_end - (start + size);
+
+ /* 2. */
+ block->length = start - block->start;
+
+ /* 3. */
+ newblock->prev = block;
+ newblock->next = block->next;
+ if ( block->next ) {
+ block->next->prev = newblock;
+ } else {
+ part->tail = newblock;
+ }
+ block->next = newblock;
+
+ return (void *)start;
+}
+
+/* Try to allocate from a block */
+void *alloc_try(struct mem_partition *part, struct mem_block *block, unsigned int start, size_t size)
+{
+ unsigned int end = start + size;
+ unsigned int block_end = block->start + block->length;
+
+ /* Is the section available in this block? */
+ if ( (start >= block->start) && (start <= block_end) && /* Check start and end */
+ (end <= block_end) && (end > block->start) ) {
+ /* Found a block that is available, allocate it */
+ return alloc_block(part, block, start, size);
+ }
+
+ return NULL;
+}
+
+/* Iterate over all free memory blocks from the tail to head*/
+void *alloc_back(struct mem_partition *part, size_t boundary, size_t size)
+{
+ struct mem_block *block;
+ unsigned int start, block_end;
+ void *mem;
+
+ /* Find a section of memory matching the alignment and size */
+ block = part->tail;
+ while ( block ) {
+ if ( block->length >= size ) {
+ /* Calculate the last address that is needed within this block */
+ block_end = block->start + block->length;
+ start = (block_end - size) & ~(boundary - 1);
+
+ if ( (mem=alloc_try(part, block, start, size)) != NULL ) {
+ return mem;
+ }
+ }
+
+ /* memory not available within this block */
+ block = block->prev;
+ }
+
+ DBG("AMBAPP_RMAP_MEMALIGN_BACK: FAILED TO ALLOCATE %dBytes at a 0x%x boundary\n", size, boundary);
+
+ return NULL;
+}
+
+void *alloc_front(struct mem_partition *part, size_t boundary, size_t size)
+{
+ struct mem_block *block;
+ unsigned int start;
+ void *mem;
+
+ /* Find a section of memory matching the alignment and size */
+ block = part->head;
+ while ( block ) {
+
+ if ( block->length >= size ) {
+ /* Calculate the first address that is needed
+ * within this block
+ */
+ start = (block->start + (boundary - 1)) &
+ ~(boundary - 1);
+
+ if ((mem=alloc_try(part, block, start, size)) != NULL) {
+ return mem;
+ }
+ }
+ /* memory not available within this block */
+ block = block->next;
+ }
+
+ DBG("AMBAPP_RMAP_MEMALIGN_FRONT: FAILED TO ALLOCATE %dBytes at a 0x%x boundary\n", size, boundary);
+
+ return NULL;
+}
+
+void *ambapp_rmap_partition_memalign(
+ struct drvmgr_dev *dev,
+ int partition,
+ size_t boundary,
+ size_t size)
+{
+ struct ambapp_rmap_priv *priv;
+ struct mem_partition *part = NULL;
+
+ if ( size < 1 ) {
+ DBG("AMBAPP_RMAP_MEMALIGN: size < 1\n");
+ return NULL;
+ }
+
+ /* Never deal with smaller units than 16 bytes */
+ if ( boundary < 0x10 ) {
+ boundary = 0x10;
+ }
+
+ DBG("RMAP MEMALIGN: partition %d, boundary 0x%x, size 0x%x\n", partition, boundary, size);
+
+ /* Get Partition */
+ priv = dev->parent->dev->priv;
+ if ( (partition >= PARTITION_MAX) || (priv->partition_valid & (1<<partition)) == 0 ) {
+ DBG("RMAP MEMALIGN: partition invalid\n");
+ return NULL;
+ }
+ part = &priv->partitions[partition];
+
+ if ( (boundary >= 0x10000) || (size >= 0x10000) ) {
+ return alloc_front(part, boundary, size);
+ } else {
+ return alloc_back(part, boundary, size);
+ }
+}
+
+int ambapp_rmap_partition_create_internal(
+ struct ambapp_rmap_priv *priv,
+ int partition,
+ unsigned int start,
+ size_t size)
+{
+ struct mem_partition *part;
+ struct mem_block *block;
+
+ /* Get Partition */
+ if ( (partition >= PARTITION_MAX) || (priv->partition_valid & (1<<partition)) ) {
+ DBG("RMAP PART CREATE: invalid part num %d\n", partition);
+ return -1;
+ }
+ part = &priv->partitions[partition];
+ if ( part->head || part->tail ) {
+ DBG("RMAP PART CREATE: part %d already initied\n", partition);
+ return -1;
+ }
+
+ /* Init on free memory block */
+ block = (struct mem_block *)malloc(sizeof(struct mem_block));
+ part->head = part->tail = block;
+ block->next = block->prev = NULL;
+ block->start = start;
+ block->length = size;
+ priv->partition_valid |= 1 << partition;
+
+ DBG("RMAP PART CREATE: DONE initiing part %d\n", partition);
+
+ return 0;
+}
+
+int ambapp_rmap_partition_create(
+ struct drvmgr_dev *dev,
+ int partition,
+ unsigned int start,
+ size_t size)
+{
+ struct ambapp_rmap_priv *priv;
+
+ priv = dev->parent->dev->priv;
+
+ return ambapp_rmap_partition_create_internal(priv, partition, start, size);
+}
diff --git a/c/src/lib/libbsp/sparc/shared/drvmgr/leon2_amba_bus.c b/c/src/lib/libbsp/sparc/shared/drvmgr/leon2_amba_bus.c
new file mode 100644
index 0000000000..9d194ec0a6
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/drvmgr/leon2_amba_bus.c
@@ -0,0 +1,463 @@
+/* LEON2 Hardcoded bus driver.
+ *
+ * COPYRIGHT (c) 2008.
+ * Aeroflex Gaisler.
+ *
+ * Bus driver for a hardcoded setup. LEON2 systems have some
+ * cores always present, here called "Standard Cores". In
+ * addtion to the standard cores there are often extra cores
+ * that can be defined using the "Custom Cores" mechanism.
+ *
+ * A Core is described by assigning a base register and
+ * IRQ0..IRQ15 using the leon2_core structure.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2008-12-03, Daniel Hellstrom <daniel@gaisler.com>
+ * Created
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/leon2_amba_bus.h>
+
+#include <bsp.h>
+
+#define DBG(args...)
+/*#define DBG(args...) printk(args)*/
+
+struct drvmgr_drv leon2_bus_drv;
+
+int leon2_amba_bus_init1(struct drvmgr_bus *bus);
+int leon2_amba_unite(struct drvmgr_drv *drv, struct drvmgr_dev *dev);
+int leon2_amba_int_register(
+ struct drvmgr_dev *dev,
+ int index,
+ const char *info,
+ drvmgr_isr isr,
+ void *arg);
+int leon2_amba_int_unregister(
+ struct drvmgr_dev *dev,
+ int index,
+ drvmgr_isr isr,
+ void *arg);
+int leon2_amba_int_clear(
+ struct drvmgr_dev *dev,
+ int index);
+int leon2_amba_int_mask(
+ struct drvmgr_dev *dev,
+ int index);
+int leon2_amba_int_unmask(
+ struct drvmgr_dev *dev,
+ int index);
+
+/* LEON2 bus operations */
+struct drvmgr_bus_ops leon2_amba_bus_ops =
+{
+ .init = {
+ leon2_amba_bus_init1,
+ NULL,
+ NULL,
+ NULL
+ },
+ .remove = NULL,
+ .unite = leon2_amba_unite,
+ .int_register = leon2_amba_int_register,
+ .int_unregister = leon2_amba_int_unregister,
+ .int_clear = leon2_amba_int_clear,
+ .int_mask = leon2_amba_int_mask,
+ .int_unmask = leon2_amba_int_unmask,
+ .get_params = NULL,
+};
+
+struct leon2_isr_handler {
+ void (*handler)(int irq, void *arg);
+ void *arg;
+};
+
+/* Interrupt handlers */
+struct leon2_isr_handler leon2_isrs[16];
+
+/* Standard LEON2 configuration */
+
+struct drvmgr_key leon2_timers[] =
+{
+ {"REG0", KEY_TYPE_INT, {0x80000040}},
+ {"IRQ0", KEY_TYPE_INT, {8}},
+ {"IRQ1", KEY_TYPE_INT, {9}},
+ KEY_EMPTY
+};
+
+struct drvmgr_key leon2_uart1[] =
+{
+ {"REG0", KEY_TYPE_INT, {0x80000070}},
+ {"IRQ0", KEY_TYPE_INT, {3}},
+ KEY_EMPTY
+};
+
+struct drvmgr_key leon2_uart2[] =
+{
+ {"REG0", KEY_TYPE_INT, {0x80000080}},
+ {"IRQ0", KEY_TYPE_INT, {2}},
+ KEY_EMPTY
+};
+
+struct drvmgr_key leon2_irqctrl[] =
+{
+ {"REG0", KEY_TYPE_INT, {0x80000090}},
+ KEY_EMPTY
+};
+
+struct drvmgr_key leon2_gpio0[] =
+{
+ {"REG0", KEY_TYPE_INT, {0x800000A0}},
+ {"IRQ0", KEY_TYPE_INT, {4}},
+ {"IRQ1", KEY_TYPE_INT, {5}},
+ {"IRQ2", KEY_TYPE_INT, {6}},
+ {"IRQ3", KEY_TYPE_INT, {7}},
+ KEY_EMPTY
+};
+
+struct leon2_core leon2_std_cores[] =
+{
+ {{LEON2_AMBA_TIMER_ID}, "Timers", &leon2_timers[0]},
+ {{LEON2_AMBA_UART_ID}, "Uart1", &leon2_uart1[0]},
+ {{LEON2_AMBA_UART_ID}, "Uart2", &leon2_uart2[0]},
+ {{LEON2_AMBA_IRQCTRL_ID}, "IRQCtrl", &leon2_irqctrl[0]},
+ {{LEON2_AMBA_GPIO_ID}, "GPIO", &leon2_gpio0[0]},
+ EMPTY_LEON2_CORE
+};
+
+static struct leon2_bus *leon2_bus_config = NULL;
+static struct drvmgr_bus_res *leon2_bus_res = NULL;
+
+int leon2_root_register(struct leon2_bus *bus_config, struct drvmgr_bus_res *resources)
+{
+ /* Save the configuration for later */
+ leon2_bus_config = bus_config;
+ leon2_bus_res = resources;
+
+ /* Register root device driver */
+ drvmgr_root_drv_register(&leon2_bus_drv);
+
+ return 0;
+}
+
+int leon2_amba_dev_register(struct drvmgr_bus *bus, struct leon2_core *core, int index)
+{
+ struct drvmgr_dev *newdev;
+ struct leon2_amba_dev_info *info;
+ union drvmgr_key_value *value;
+ char irq_name[8];
+ int i;
+
+ /* Allocate new device and businfo */
+ drvmgr_alloc_dev(&newdev, sizeof(struct leon2_amba_dev_info));
+ info = (struct leon2_amba_dev_info *)(newdev + 1);
+
+ /* Set Core ID */
+ info->core_id = core->id.core_id;
+
+ /* Get information from bus configuration */
+ value = drvmgr_key_val_get(core->keys, "REG0", KEY_TYPE_INT);
+ if ( !value ) {
+ printk("leon2_amba_dev_register: Failed getting resource REG0\n");
+ info->reg_base = 0x00000000;
+ } else {
+ DBG("leon2_amba_dev_register: REG0: 0x%08x\n", value->i);
+ info->reg_base = value->i;
+ }
+
+ strcpy(irq_name, "IRQ");
+ for(i=0; i<16; i++){
+ if ( i < 10 ){
+ irq_name[3] = '0' + i;
+ irq_name[4] = '\0';
+ } else {
+ irq_name[3] = '1';
+ irq_name[4] = '0' + (i-10);
+ irq_name[5] = '\0';
+ }
+
+ value = drvmgr_key_val_get(core->keys, irq_name, KEY_TYPE_INT);
+ if ( !value ) {
+ DBG("leon2_amba_dev_register: Failed getting resource IRQ%d for REG 0x%x\n", i, info->reg_base);
+ info->irqs[i] = 0;
+ } else {
+ DBG("leon2_amba_dev_register: IRQ%d: %d\n", i, value->i);
+ info->irqs[i] = value->i;
+ }
+ }
+
+ /* Init new device */
+ newdev->next = NULL;
+ newdev->parent = bus; /* Ourselfs */
+ newdev->minor_drv = 0;
+ newdev->minor_bus = 0;
+ newdev->businfo = (void *)info;
+ newdev->priv = NULL;
+ newdev->drv = NULL;
+ newdev->name = core->name;
+ newdev->next_in_drv = NULL;
+ newdev->bus = NULL;
+
+ /* Register new device */
+ drvmgr_dev_register(newdev);
+
+ return 0;
+}
+
+int leon2_amba_init1(struct drvmgr_dev *dev)
+{
+ /* Init our own device */
+ dev->priv = NULL;
+ dev->name = "LEON2 AMBA";
+
+ memset(leon2_isrs, 0, sizeof(leon2_isrs));
+
+ /* Init the bus */
+ drvmgr_alloc_bus(&dev->bus, 0);
+ dev->bus->bus_type = DRVMGR_BUS_TYPE_LEON2_AMBA;
+ dev->bus->next = NULL;
+ dev->bus->dev = dev;
+ dev->bus->priv = NULL;
+ dev->bus->children = NULL;
+ dev->bus->ops = &leon2_amba_bus_ops;
+ dev->bus->dev_cnt = 0;
+ dev->bus->reslist = NULL;
+ dev->bus->maps_up = leon2_bus_config->maps_up;
+ dev->bus->maps_down = leon2_bus_config->maps_down;
+ drvmgr_bus_register(dev->bus);
+
+ return DRVMGR_OK;
+}
+
+int leon2_amba_init2(struct drvmgr_dev *dev)
+{
+ return DRVMGR_OK;
+}
+
+int leon2_amba_remove(struct drvmgr_dev *dev)
+{
+ return DRVMGR_OK;
+}
+
+int leon2_amba_bus_init1(struct drvmgr_bus *bus)
+{
+ struct leon2_core *core;
+ int i;
+
+ if ( leon2_bus_res )
+ drvmgr_bus_res_add(bus, leon2_bus_res);
+
+ /**** REGISTER NEW DEVICES ****/
+ i=0;
+ core = leon2_bus_config->std_cores;
+ if ( core ) {
+ while ( core->id.core_id ) {
+ if ( leon2_amba_dev_register(bus, core, i) ) {
+ return RTEMS_UNSATISFIED;
+ }
+ i++;
+ core++;
+ }
+ }
+ core = leon2_bus_config->custom_cores;
+ if ( core ) {
+ while ( core->id.core_id ) {
+ if ( leon2_amba_dev_register(bus, core, i) ) {
+ return RTEMS_UNSATISFIED;
+ }
+ i++;
+ core++;
+ }
+ }
+
+ return 0;
+}
+
+int leon2_amba_unite(struct drvmgr_drv *drv, struct drvmgr_dev *dev)
+{
+ struct leon2_amba_dev_info *info;
+ struct leon2_amba_drv_info *adrv;
+ struct leon2_amba_dev_id *id;
+
+ if ( !drv || !dev || !dev->parent )
+ return 0;
+
+ if ( (drv->bus_type!=DRVMGR_BUS_TYPE_LEON2_AMBA) || (dev->parent->bus_type != DRVMGR_BUS_TYPE_LEON2_AMBA) ) {
+ return 0;
+ }
+
+ info = (struct leon2_amba_dev_info *)dev->businfo;
+ if ( !info )
+ return 0;
+
+ /* Get LEON2 AMBA driver info */
+ adrv = (struct leon2_amba_drv_info *)drv;
+ id = adrv->ids;
+ if ( !id )
+ return 0;
+
+ while ( id->core_id ) {
+ if ( id->core_id == info->core_id ) {
+ /* Driver is suitable for device, Unite them */
+ return 1;
+ }
+ id++;
+ }
+
+ return 0;
+}
+
+rtems_isr leon2_amba_isr(rtems_vector_number v)
+{
+ int irq = v - 0x10; /* Convert Vector number to Interrupt number */
+ struct leon2_isr_handler *isr;
+
+ isr = &leon2_isrs[irq];
+ if ( isr->handler ) {
+ isr->handler(irq, isr->arg);
+ }
+}
+
+int leon2_amba_get_irq(struct drvmgr_dev *dev, int index)
+{
+ int irq;
+ struct leon2_amba_dev_info *info;
+
+ if ( !dev || (index > 15) )
+ return -1;
+
+ /* Relative (positive) or absolute (negative) IRQ number */
+ if ( index >= 0 ) {
+ /* IRQ Index relative to Cores base IRQ */
+
+ /* Get IRQ array configured by user */
+ info = (struct leon2_amba_dev_info *)dev->businfo;
+ irq = info->irqs[index];
+ if ( irq == 0 )
+ return -1;
+ } else {
+ /* Absolute IRQ number */
+ irq = -index;
+ }
+ return irq;
+}
+
+int leon2_amba_int_register
+ (
+ struct drvmgr_dev *dev,
+ int index,
+ const char *info,
+ drvmgr_isr isr,
+ void *arg
+ )
+{
+ int irq;
+
+ irq = leon2_amba_get_irq(dev, index);
+ if ( irq < 0 )
+ return -1;
+
+ DBG("Registering IRQ %d to func 0x%x arg 0x%x\n", irq, (unsigned int)isr, (unsigned int)arg);
+
+ return BSP_shared_interrupt_register(irq, info, isr, arg);
+}
+
+int leon2_amba_int_unregister
+ (
+ struct drvmgr_dev *dev,
+ int index,
+ drvmgr_isr isr,
+ void *arg
+ )
+{
+ int irq;
+
+ irq = leon2_amba_get_irq(dev, index);
+ if ( irq < 0 )
+ return -1;
+
+ DBG("Unregistering IRQ %d to func 0x%x arg 0x%x\n", irq, (unsigned int)handler, (unsigned int)arg);
+
+ return BSP_shared_interrupt_unregister(irq, isr, arg);
+}
+
+int leon2_amba_int_clear
+ (
+ struct drvmgr_dev *dev,
+ int index
+ )
+{
+ int irq;
+
+ irq = leon2_amba_get_irq(dev, index);
+ if ( irq < 0 )
+ return -1;
+
+ BSP_shared_interrupt_clear(irq);
+
+ return DRVMGR_OK;
+}
+
+int leon2_amba_int_mask
+ (
+ struct drvmgr_dev *dev,
+ int index
+ )
+{
+ int irq;
+
+ irq = leon2_amba_get_irq(dev, index);
+ if ( irq < 0 )
+ return -1;
+
+ BSP_shared_interrupt_mask(irq);
+
+ return DRVMGR_OK;
+}
+
+int leon2_amba_int_unmask
+ (
+ struct drvmgr_dev *dev,
+ int index
+ )
+{
+ int irq;
+
+ irq = leon2_amba_get_irq(dev, index);
+ if ( irq < 0 )
+ return -1;
+
+ BSP_shared_interrupt_unmask(irq);
+
+ return DRVMGR_OK;
+}
+
+struct drvmgr_drv_ops leon2_amba_ops =
+{
+ .init = {leon2_amba_init1, leon2_amba_init2, NULL, NULL},
+ .remove = leon2_amba_remove,
+ .info = NULL
+};
+
+struct drvmgr_drv leon2_bus_drv =
+{
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_LEON2_AMBA_ID, /* Driver ID */
+ "LEON2_AMBA_DRV", /* Must be placed at top bus */
+ DRVMGR_BUS_TYPE_ROOT, /* Bus Type */
+ &leon2_amba_ops, /* Bus Operations */
+ NULL, /* Funcs */
+ 0, /* Device Count */
+ 0, /* Private structure size */
+};
diff --git a/c/src/lib/libbsp/sparc/shared/drvmgr/spw_bus.c b/c/src/lib/libbsp/sparc/shared/drvmgr/spw_bus.c
new file mode 100644
index 0000000000..4556e62b9a
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/drvmgr/spw_bus.c
@@ -0,0 +1,960 @@
+/* SpaceWire bus driver interface.
+ *
+ * COPYRIGHT (c) 2008.
+ * Aeroflex Gaisler.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2009-11-20, Daniel Hellstrom <daniel@gaisler.com>
+ * Created
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/spw_bus.h>
+#include <genirq.h>
+#include <gpiolib.h>
+#include <rmap.h>
+
+#include <bsp.h>
+#include <stdint.h>
+
+#undef DEBUG
+
+#ifdef DEBUG
+ #define DBG(args...) printk(args)
+#else
+ #define DBG(args...)
+#endif
+
+struct virq_entry {
+ char *gpio_fsname;
+ int fd;
+};
+
+struct spw_bus_priv {
+ /* SpW-Bus driver handle */
+ struct drvmgr_bus *bus;
+
+ /* User configuration */
+ struct spw_bus_config *config; /* User configuration */
+
+ /* Device prefix */
+ int spwbus_id;
+ char prefix[16]; /* Device name prefix */
+
+ /* IRQ Handling */
+ volatile unsigned int irq_mask; /* Bit mask of which IRQs has been received, and to handle */
+ genirq_t genirq; /* Shared IRQ, ISR handling */
+ rtems_id irqlock; /* Protect IRQ handling (register,enable,disable etc.) */
+ rtems_id isr_task; /* TASK used to execute registered ISRs on SpaceWire Bus */
+ rtems_id isr_execute_sem; /* Used to signal to ISR TASK that one or more IRQs has been received */
+ volatile int task_terminate; /* Used to signal to ISR TASK to stop it's execution, and delete itself */
+ char virqs[4]; /* Virtual IRQ table, used to separate IRQ from different GPIO pins */
+};
+
+struct drvmgr_drv spw_bus_drv;
+static int spw_bus_cnt = 0;
+
+int spw_bus_init1(struct drvmgr_bus *bus);
+int spw_bus_unite(struct drvmgr_drv *drv, struct drvmgr_dev *dev);
+int spw_bus_int_register(struct drvmgr_dev *dev, int index, const char *info, drvmgr_isr handler, void *arg);
+int spw_bus_int_unregister(struct drvmgr_dev *dev, int index, drvmgr_isr isr, void *arg);
+int spw_bus_int_mask(struct drvmgr_dev *dev, int index);
+int spw_bus_int_unmask(struct drvmgr_dev *dev, int index);
+int spw_bus_int_clear(struct drvmgr_dev *dev, int index);
+
+int spw_bus_freq_get(
+ struct drvmgr_dev *dev,
+ int options,
+ unsigned int *freq_hz);
+/* READ/WRITE access to SpaceWire target over RMAP */
+int spw_bus_memcpy(void *dest, const void *src, int n, struct drvmgr_rw_arg *a);
+int spw_bus_write_mem(void *dest, const void *src, int n, struct drvmgr_rw_arg *a);
+int spw_bus_memset(void *dest, int c, int n, struct drvmgr_rw_arg *a);
+uint8_t spw_bus_r8(uint8_t *srcadr, struct drvmgr_rw_arg *a);
+uint16_t spw_bus_r16(uint16_t *srcadr, struct drvmgr_rw_arg *a);
+uint32_t spw_bus_r32(uint32_t *srcadr, struct drvmgr_rw_arg *a);
+uint64_t spw_bus_r64(uint64_t *srcadr, struct drvmgr_rw_arg *a);
+void spw_bus_w8(uint8_t *dstadr, uint8_t data, struct drvmgr_rw_arg *a);
+void spw_bus_w16(uint16_t *dstadr, uint16_t data, struct drvmgr_rw_arg *a);
+void spw_bus_w32(uint32_t *dstadr, uint32_t data, struct drvmgr_rw_arg *a);
+void spw_bus_w64(uint64_t *dstadr, uint64_t data, struct drvmgr_rw_arg *a);
+int spw_bus_get_params(struct drvmgr_dev *dev, struct drvmgr_bus_params *params);
+void *spw_bus_rw_arg(struct drvmgr_dev *dev);
+
+/* SPW RMAP bus operations */
+struct drvmgr_bus_ops spw_bus_ops =
+{
+ .init =
+ {
+ spw_bus_init1,
+ NULL,
+ NULL,
+ NULL
+ },
+ .remove = NULL,
+ .unite = spw_bus_unite,
+ .int_register = spw_bus_int_register,
+ .int_unregister = spw_bus_int_unregister,
+ .int_mask = spw_bus_int_mask,
+ .int_unmask = spw_bus_int_unmask,
+ .int_clear = spw_bus_int_clear,
+ .get_params = spw_bus_get_params,
+ .freq_get = spw_bus_freq_get,
+};
+
+struct drvmgr_func spw_bus_funcs[] =
+{
+ DRVMGR_FUNC(SPWBUS_RW_ARG, spw_bus_rw_arg),
+
+ DRVMGR_FUNC(SPWBUS_R8, spw_bus_r8),
+ DRVMGR_FUNC(SPWBUS_R16, spw_bus_r16),
+ DRVMGR_FUNC(SPWBUS_R32, spw_bus_r32),
+ DRVMGR_FUNC(SPWBUS_R64, spw_bus_r64),
+
+ DRVMGR_FUNC(SPWBUS_W8, spw_bus_w8),
+ DRVMGR_FUNC(SPWBUS_W16, spw_bus_w16),
+ DRVMGR_FUNC(SPWBUS_W32, spw_bus_w32),
+ DRVMGR_FUNC(SPWBUS_W64, spw_bus_w64),
+
+ DRVMGR_FUNC(SPWBUS_RMEM, spw_bus_memcpy),
+ DRVMGR_FUNC(SPWBUS_WMEM, spw_bus_write_mem),
+ DRVMGR_FUNC(SPWBUS_MEMSET, spw_bus_memset),
+
+ DRVMGR_FUNC_END,
+};
+
+int spw_bus_dev_register(struct drvmgr_bus *bus, struct spw_node *node, int index)
+{
+ struct drvmgr_dev *newdev;
+ struct spw_bus_dev_info *info;
+ union drvmgr_key_value *value;
+
+ int virq;
+ char virq_name[6];
+
+ /* Allocate new device and bus information */
+ drvmgr_alloc_dev(&newdev, sizeof(struct spw_bus_dev_info));
+ info = (struct spw_bus_dev_info *)(newdev + 1);
+
+ /* Set Node ID */
+ info->spwid = node->id.spwid;
+
+ /* Get information from bus configuration */
+ value = drvmgr_key_val_get(node->keys, "DST_ADR", KEY_TYPE_INT);
+ if ( !value ) {
+ printk("spw_bus_dev_register: Failed getting resource DST_ADR\n");
+ info->dstadr = 0xfe;
+ } else {
+ DBG("spw_bus_dev_register: DST_ADR: 0x%02x\n", value->i);
+ info->dstadr = value->i;
+ }
+ value = drvmgr_key_val_get(node->keys, "DST_KEY", KEY_TYPE_INT);
+ if ( !value ) {
+ printk("spw_bus_dev_register: Failed getting resource DST_KEY\n");
+ info->dstkey = 0;
+ } else {
+ DBG("spw_bus_dev_register: DST_KEY: 0x%02x\n", value->i);
+ info->dstkey = value->i;
+ }
+ /* Get the Virtual IRQ numbers, that will be looked up in VIRQ->GPIO table */
+ strcpy(virq_name, "VIRQX");
+ for (virq=1; virq<5; virq++) {
+ virq_name[4] = '0' + virq;
+ value = drvmgr_key_val_get(node->keys, virq_name, KEY_TYPE_INT);
+ if ( !value ) {
+ /* IRQ is optional, this device does not support VIRQ[X] */
+ info->virqs[virq-1] = -1;
+ } else {
+ DBG("spw_bus_dev_register: %s: %d\n", virq_name, value->i);
+ info->virqs[virq-1] = value->i;
+ }
+ }
+
+ /* Init new device */
+ newdev->next = NULL;
+ newdev->parent = bus; /* Ourselfs */
+ newdev->minor_drv = 0;
+ newdev->minor_bus = 0;
+ newdev->businfo = (void *)info;
+ newdev->priv = NULL;
+ newdev->drv = NULL;
+ newdev->name = node->name;
+ newdev->next_in_drv = NULL;
+ newdev->bus = NULL;
+
+ /* Register new device */
+ drvmgr_dev_register(newdev);
+
+ return 0;
+}
+
+/* Interrupt Service Routine, executes in interrupt context. This ISR:
+ * 1. Disable/Mask IRQ on IRQ controller, this disables further interrupts on
+ this IRQ number
+ * 2. Mark in the private struct that the IRQ has happened
+ * 3. Wake ISR TASK that will handle each marked IRQ
+ *
+ * The TASK will for every IRQ that is marked:
+ * 1. Call the ISRs that the SpW Node drivers have registered for this specific IRQ
+ * 2. unmask IRQ again.
+ *
+ * wakes */
+void spw_bus_isr(void *arg)
+{
+ struct spw_bus_priv *priv;
+ unsigned int old_irq_mask;
+ char *pvirq = (char *)arg;
+ int virq = *pvirq;
+
+ priv = (struct spw_bus_priv *)(pvirq - offsetof(struct spw_bus_priv, virqs) - (virq-1));
+
+ gpiolib_irq_mask(priv->config->virq_table[virq-1].handle);
+
+ /* Mark IRQ was received */
+ old_irq_mask = priv->irq_mask;
+ priv->irq_mask = old_irq_mask | (1 << virq);
+
+ /* Wake ISR execution TASK only if not woken before */
+ if ( old_irq_mask == 0 ) {
+ rtems_semaphore_release(priv->isr_execute_sem);
+ }
+}
+
+void spwbus_task(rtems_task_argument argument)
+{
+ int virq;
+ rtems_interrupt_level level;
+ unsigned int mask;
+ struct spw_bus_priv *priv = (struct spw_bus_priv *)argument;
+
+ DBG("SpW-Bus: ISR Task is started\n");
+
+ while ( priv->task_terminate == 0 ) {
+ while ( (mask = priv->irq_mask) != 0 ) {
+
+ /* Mark the IRQs handled */
+ rtems_interrupt_disable(level);
+ priv->irq_mask &= ~mask;
+ rtems_interrupt_enable(level);
+
+ mask = mask >> 1;
+ virq = 1;
+ while ( mask ) {
+ if ( mask & 1 ) {
+ /* execute all ISRs on this IRQ */
+ DBG("SpW-Bus: ISR Task is executing VIRQ %d\n", virq);
+ genirq_doirq(priv->genirq, virq);
+ }
+
+ /* Reenable the handled IRQ */
+ gpiolib_irq_unmask(priv->config->virq_table[virq-1].handle);
+
+ virq++;
+ mask = mask >> 1;
+ }
+ }
+
+ DBG("SpW-Bus: ISR Task going to sleep\n");
+
+ rtems_task_wake_after(1);
+
+ /* Wait for new IRQs to handle */
+ rtems_semaphore_obtain(priv->isr_execute_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+
+ DBG("SpW-Bus: ISR Task woke up\n");
+ }
+
+ DBG("SpW-Bus: ISR Task is deleted\n");
+
+ rtems_task_delete(RTEMS_SELF);
+}
+
+int spw_bus_init1(struct drvmgr_bus *bus)
+{
+ struct spw_node *node;
+ int i;
+ struct spw_bus_priv *priv = (struct spw_bus_priv *)bus->priv;
+ int status;
+ struct spwbus_virq_config *vcfg;
+ int virq;
+ struct gpiolib_config gpiocfg;
+
+ DBG("SpW-BUS: init\n");
+
+ priv->spwbus_id = spw_bus_cnt++;
+ priv->irq_mask = 0;
+ priv->task_terminate = 0;
+
+ priv->genirq = genirq_init(32);
+ if ( priv->genirq == NULL ) {
+ return RTEMS_UNSATISFIED;
+ }
+
+ if ( priv->config->resources )
+ drvmgr_bus_res_add(bus, priv->config->resources);
+
+ /* Create Semaphore used when doing IRQ/ISR registering/enabling etc. */
+ status = rtems_semaphore_create(
+ rtems_build_name('S', 'P', 'C', '0' + bus->dev->minor_drv),
+ 1,
+ RTEMS_FIFO | RTEMS_COUNTING_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | \
+ RTEMS_LOCAL | RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &priv->irqlock);
+ if ( status != RTEMS_SUCCESSFUL ) {
+ DBG("SpW-BUS: Failed to create irqlock semaphore: %d\n", status);
+ return -1;
+ }
+
+ /* Create Semaphore used to Signal to ISR TASK that a Interrupt has happened */
+ status = rtems_semaphore_create(
+ rtems_build_name('S', 'P', 'D', '0' + bus->dev->minor_drv),
+ 0,
+ RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | \
+ RTEMS_LOCAL | RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &priv->isr_execute_sem);
+ if ( status != RTEMS_SUCCESSFUL ) {
+ DBG("SpW-BUS: Failed to create irqlock semaphore: %d\n", status);
+ return -1;
+ }
+
+ /* Create ISR task */
+ status = rtems_task_create(
+ rtems_build_name( 'I', 'S', 'T', '0' + bus->dev->minor_drv),
+ 1,
+ RTEMS_MINIMUM_STACK_SIZE,
+ RTEMS_NO_PREEMPT,
+ RTEMS_LOCAL | RTEMS_NO_FLOATING_POINT,
+ &priv->isr_task);
+ if (status != RTEMS_SUCCESSFUL) {
+ DBG ("SpW-BUS: Can't create task: %d\n", status);
+ return -1;
+ }
+
+ /* Initialize VIRQs and open the GPIO drivers if not already done */
+ vcfg = &priv->config->virq_table[0];
+ for (virq=1; virq<5; virq++) {
+ priv->virqs[virq-1] = -1;
+ if ( vcfg->handle == NULL ) {
+ /* Open GPIO PIN and diable IRQ for now */
+ if ( vcfg->gpio_fsname ) {
+ vcfg->handle = gpiolib_open_by_name(vcfg->gpio_fsname);
+ if ( vcfg->handle != NULL ) {
+ priv->virqs[virq-1] = virq;
+ gpiocfg.mask = 0;
+ gpiocfg.irq_level = GPIOLIB_IRQ_LEVEL;
+ gpiocfg.irq_polarity = GPIOLIB_IRQ_POL_HIGH;
+ gpiolib_set_config(vcfg->handle, &gpiocfg);
+ if ( gpiolib_set(vcfg->handle, 0, 0) ) {
+ DBG("SpW-BUS: Failed to configure GPIO as input for VIRQ%d\n", virq);
+ }
+ if ( gpiolib_irq_register(vcfg->handle, spw_bus_isr, &priv->virqs[virq-1]) ) {
+ DBG("SpW-BUS: Failed to register GPIO ISR for VIRQ%d\n", virq);
+ }
+ } else {
+ DBG("SpW-BUS: Failed to open GPIO (%s) for VIRQ%d\n",vcfg->gpio_fsname, virq);
+ }
+ }
+ } else {
+ /* Already opened for us */
+ priv->virqs[virq-1] = virq;
+ }
+ vcfg++;
+ }
+
+ /* Start ISR Task, there is no work to do, so the task will wait for isr_execute_sem semaphore released by real ISR */
+ status = rtems_task_start(priv->isr_task, spwbus_task, (int)priv);
+ if ( status != RTEMS_SUCCESSFUL ) {
+ DBG("SpW-BUS: Failed to start ISR task: %d\n", status);
+ return -1;
+ }
+
+ /* Create Device name */
+ strcpy(priv->prefix, "/dev/spwbus0");
+ priv->prefix[11] = '0' + priv->spwbus_id;
+ mkdir(priv->prefix, S_IRWXU | S_IRWXG | S_IRWXO);
+ priv->prefix[12] = '/';
+ priv->prefix[13] = '\0';
+
+ /**** REGISTER NEW DEVICES ****/
+ i=0;
+ node = priv->config->nodes;
+ if ( node ) {
+ while ( node->id.spwid ) {
+ DBG("SpW-BUS: register node %d (%p)\n", i, node);
+ if ( spw_bus_dev_register(bus, node, i) ) {
+ return RTEMS_UNSATISFIED;
+ }
+ i++;
+ node++;
+ }
+ }
+
+ return DRVMGR_OK;
+}
+
+int spw_bus_unite(struct drvmgr_drv *drv, struct drvmgr_dev *dev)
+{
+ struct spw_bus_dev_info *info;
+ struct spw_bus_drv_info *spwdrv;
+ struct spw_id *id;
+
+ if ( !drv || !dev || !dev->parent )
+ return 0;
+
+ if ( (drv->bus_type!=DRVMGR_BUS_TYPE_SPW_RMAP) || (dev->parent->bus_type != DRVMGR_BUS_TYPE_SPW_RMAP) ) {
+ return 0;
+ }
+
+ info = (struct spw_bus_dev_info *)dev->businfo;
+ if ( !info )
+ return 0;
+
+ /* Get SPW RMAP driver info */
+ spwdrv = (struct spw_bus_drv_info *)drv;
+ id = spwdrv->ids;
+ if ( !id )
+ return 0;
+
+ while ( id->spwid ) {
+ if ( id->spwid == info->spwid ) {
+ /* Driver is suitable for device, Unite them */
+ return 1;
+ }
+ id++;
+ }
+
+ return 0;
+}
+
+int spw_bus_int_get(struct drvmgr_dev *dev, int index)
+{
+ int virq;
+
+ /* Relative (positive) or absolute (negative) IRQ number */
+ if ( index >= 0 ) {
+ /* IRQ Index relative to Cores base IRQ */
+
+ /* Get Base IRQ */
+ virq = ((struct spw_bus_dev_info *)dev->businfo)->virqs[index];
+ if ( virq <= 0 )
+ return -1;
+ } else {
+ /* Absolute IRQ number */
+ virq = -index;
+ }
+ return virq;
+}
+
+int spw_bus_int_register(
+ struct drvmgr_dev *dev,
+ int index,
+ const char *info,
+ drvmgr_isr handler,
+ void *arg)
+{
+ struct drvmgr_bus *bus;
+ struct spw_bus_priv *priv;
+ int status, virq;
+ void *handle;
+
+ /* Get IRQ number from index and device information */
+ virq = spw_bus_int_get(dev, index);
+ if ( virq <= 0 )
+ return DRVMGR_FAIL;
+
+ bus = dev->parent;
+ priv = bus->priv;
+
+ DBG("SpW-BUS: Register ISR for VIRQ%d\n", virq);
+
+ handle = priv->config->virq_table[virq-1].handle;
+ if ( handle == NULL )
+ return DRVMGR_FAIL;
+
+ rtems_semaphore_obtain(priv->irqlock, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+
+ status = genirq_register(priv->genirq, virq, handler, arg);
+ if ( status >= 0 ) {
+ status = genirq_enable(priv->genirq, virq, handler, arg);
+ if ( status == 0 ) {
+ /* Enable IRQ for first enabled handler only */
+
+ /* Unmask the GPIO IRQ at the source (at the GPIO core),
+ * and at the IRQ controller
+ */
+ struct gpiolib_config gpiocfg;
+ gpiocfg.mask = 1;
+ gpiocfg.irq_level = GPIOLIB_IRQ_LEVEL;
+ gpiocfg.irq_polarity = GPIOLIB_IRQ_POL_HIGH;
+ gpiolib_set_config(handle, &gpiocfg);
+
+ gpiolib_irq_enable(handle);
+ }
+ }
+
+ rtems_semaphore_release(priv->irqlock);
+
+ if (status < 0)
+ return DRVMGR_FAIL;
+ else
+ return DRVMGR_OK;
+}
+
+int spw_bus_int_unregister(struct drvmgr_dev *dev, int index, drvmgr_isr isr, void *arg)
+{
+ struct drvmgr_bus *bus;
+ struct spw_bus_priv *priv;
+ int virq, status;
+ void *handle;
+
+ /* Get IRQ number from index and device information */
+ virq = spw_bus_int_get(dev, index);
+ if ( virq <= 0 )
+ return DRVMGR_FAIL;
+
+ DBG("SpW-BUS: unregister ISR for VIRQ%d\n", virq);
+
+ bus = dev->parent;
+ priv = bus->priv;
+
+ handle = priv->config->virq_table[virq-1].handle;
+ if ( handle == NULL )
+ return DRVMGR_FAIL;
+
+ rtems_semaphore_obtain(priv->irqlock, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+
+ status = genirq_disable(priv->genirq, virq, isr, arg);
+ if ( status >= 0 ) {
+ if ( status == 0 ) {
+ /* Disable IRQ only when no other handler is enabled */
+
+ /* Mask the GPIO IRQ at the source (at the GPIO core),
+ * disable the IRQ at the interrupt controller.
+ */
+ struct gpiolib_config gpiocfg;
+ gpiocfg.mask = 0;
+ gpiocfg.irq_level = GPIOLIB_IRQ_LEVEL;
+ gpiocfg.irq_polarity = GPIOLIB_IRQ_POL_HIGH;
+ gpiolib_set_config(handle, &gpiocfg);
+
+ gpiolib_irq_disable(handle);
+ }
+ status = genirq_unregister(priv->genirq, virq, isr, arg);
+ }
+
+ rtems_semaphore_release(priv->irqlock);
+
+ if (status < 0)
+ return DRVMGR_FAIL;
+ else
+ return DRVMGR_OK;
+}
+
+/* Unmask interrupt */
+int spw_bus_int_unmask(struct drvmgr_dev *dev, int index)
+{
+ struct drvmgr_bus *bus;
+ struct spw_bus_priv *priv;
+ int virq;
+ void *handle;
+
+ /* Get IRQ number from index and device information */
+ virq = spw_bus_int_get(dev, index);
+ if ( virq <= 0 )
+ return DRVMGR_FAIL;
+
+ bus = dev->parent;
+ priv = bus->priv;
+
+ DBG("SpW-BUS: unmask IRQ for VIRQ%d\n", virq);
+
+ handle = priv->config->virq_table[virq-1].handle;
+ if ( handle == NULL )
+ return DRVMGR_FAIL;
+
+ if ( genirq_check(priv->genirq, virq) )
+ return DRVMGR_FAIL;
+
+ rtems_semaphore_obtain(priv->irqlock, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+
+ gpiolib_irq_unmask(handle);
+
+ rtems_semaphore_release(priv->irqlock);
+
+ return DRVMGR_OK;
+}
+
+/* mask interrupt */
+int spw_bus_int_mask(struct drvmgr_dev *dev, int index)
+{
+ struct drvmgr_bus *bus;
+ struct spw_bus_priv *priv;
+ int virq;
+ void *handle;
+
+ /* Get IRQ number from index and device information */
+ virq = spw_bus_int_get(dev, index);
+ if ( virq <= 0 )
+ return DRVMGR_FAIL;
+
+ bus = dev->parent;
+ priv = bus->priv;
+
+ handle = priv->config->virq_table[virq-1].handle;
+ if ( handle == NULL )
+ return DRVMGR_FAIL;
+
+ if ( genirq_check(priv->genirq, virq) )
+ return DRVMGR_FAIL;
+
+ rtems_semaphore_obtain(priv->irqlock, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+
+ /* Register a ISR for the first registered handler */
+ gpiolib_irq_mask(handle);
+
+ rtems_semaphore_release(priv->irqlock);
+
+ return DRVMGR_OK;
+}
+
+int spw_bus_int_clear(struct drvmgr_dev *dev, int index)
+{
+ struct drvmgr_bus *bus;
+ struct spw_bus_priv *priv;
+ int virq;
+ void *handle;
+
+ /* Get IRQ number from index and device information */
+ virq = spw_bus_int_get(dev, index);
+ if ( virq < 0 )
+ return DRVMGR_FAIL;
+
+ bus = dev->parent;
+ priv = bus->priv;
+
+ handle = priv->config->virq_table[virq-1].handle;
+ if ( handle == NULL )
+ return DRVMGR_FAIL;
+
+ /* Register a ISR for the first registered handler */
+ /*drvmgr_interrupt_clear(bus->dev, -irq, spw_bus_isr, priv);*/
+ if ( gpiolib_irq_clear(handle)) {
+ DBG("SpW-BUS: Failed to Clear IRQ for VIRQ%d\n", virq);
+ }
+
+ return DRVMGR_OK;
+}
+
+void *spw_bus_rw_arg(struct drvmgr_dev *dev)
+{
+ if (dev == NULL)
+ return (void *)DRVMGR_FAIL;
+ return dev;
+}
+
+/* Copy */
+int spw_bus_memcpy(void *dest, const void *src, int n, struct drvmgr_rw_arg *a)
+{
+ struct rmap_command_read readcmd;
+ int status;
+ struct drvmgr_dev *dev = (struct drvmgr_dev *)a->arg;
+ struct spw_bus_dev_info *info = (struct spw_bus_dev_info *)dev->businfo;
+ struct spw_bus_priv *priv = (struct spw_bus_priv *)dev->parent->priv;
+ int max_pkt_size = 128; /* We assume that RMAP can do at least 128 bytes data per packet */
+
+ unsigned int source, destination, left;
+
+ if ( n > max_pkt_size ) {
+ struct rmap_config stack_cfg;
+ rmap_ioctl(priv->config->rmap, RMAP_IOCTL_GET_CONFIG, &stack_cfg);
+ max_pkt_size = stack_cfg.max_rx_len;
+ }
+
+ source = (unsigned int)src;
+ destination = (unsigned int )dest;
+ left = n;
+ while ( left > 0 ) {
+ readcmd.type = RMAP_CMD_RI;
+ readcmd.dstadr = info->dstadr;
+ readcmd.dstkey = info->dstkey;
+ readcmd.address = source;
+ readcmd.length = (left > max_pkt_size) ? max_pkt_size : left;
+ readcmd.datalength = 0;
+ readcmd.data = (void *)destination;
+
+ DBG("RMAP READ1: 0x%08x - 0x%08x\n", source, (source + (readcmd.length - 1)));
+
+ /* Send Command */
+ status = rmap_send(priv->config->rmap, (struct rmap_command *)&readcmd);
+
+ if ( status ) {
+ printf("RMAP_MEMCPY READ: Failed to send/receive command %d\n", status);
+ memset(dest, 0, n);
+ /* Should we remove device? */
+ return -1;
+ }
+
+ /* Read Data */
+ if ( readcmd.status != 0 ) {
+ printf("RMAP_MEMCPY READ: Status non-zero 0x%x, dlen: 0x%x\n", readcmd.status, readcmd.datalength);
+ memset(dest, 0, n);
+ /* Should we remove device? */
+ return -1;
+ }
+
+ source += readcmd.length;
+ destination += readcmd.length;
+ left -= readcmd.length;
+ }
+
+#ifdef DEBUG
+ if ( n == 4 ) {
+ printf("RMAP READ2: 0x%08x(4): 0x%08x\n", src, *(unsigned int *)dest);
+ } else {
+ printf("RMAP READ2: 0x%08x - 0x%08x\n", src, ((unsigned int)src)+(n-1));
+ }
+#endif
+
+ /* Return sucessful */
+ return 0;
+}
+
+/* Note that ((unsigned char *)src)[n] will be overwitten with the RMAP DATA CRC */
+int spw_bus_write_mem(void *dest, const void *src, int n, struct drvmgr_rw_arg *a)
+{
+ struct rmap_command_write writecmd;
+ int status;
+ struct drvmgr_dev *dev = (struct drvmgr_dev *)a->arg;
+ struct spw_bus_dev_info *info = (struct spw_bus_dev_info *)dev->businfo;
+ struct spw_bus_priv *priv = (struct spw_bus_priv *)dev->parent->priv;
+
+ /* Use Verify Write when accessing registers (length 1,2,4). */
+ if ( n <= 4 && n != 3) {
+ writecmd.type = RMAP_CMD_WIV;
+ } else {
+ writecmd.type = RMAP_CMD_WI;
+ }
+ writecmd.dstadr = info->dstadr;
+ writecmd.dstkey = info->dstkey;
+ writecmd.address = (unsigned int)dest;
+ writecmd.length = n;
+ writecmd.data = (unsigned char *)src;
+#ifdef DEBUG
+ if ( n == 4 ) {
+ printf("RMAP WRITE: 0x%08x(4): 0x%08x\n",
+ dest, *(unsigned int *)src);
+ } else {
+ printf("RMAP WRITE: 0x%08x - 0x%08x\n",
+ dest, ((unsigned int)dest)+(n-1));
+ }
+#endif
+ /* Send Command */
+ status = rmap_send(priv->config->rmap,
+ (struct rmap_command *)&writecmd);
+
+ if ( status ) {
+ printf("RMAP_MEMCPY WRITE: Failed to send/receive command %d\n",
+ status);
+ return -1;
+ }
+
+ /* Read Data */
+ if ( writecmd.status != 0 ) {
+ printf("RMAP_MEMCPY WRITE: Status non-zero 0x%x, adr: 0x%x\n",
+ (unsigned char)writecmd.status,
+ (unsigned char)writecmd.address);
+ return -1;
+ }
+
+ /* Return sucessful */
+ return 0;
+}
+
+/* Use standard Driver manager skeleton for this implementation */
+int spw_bus_memset(void *dest, int c, int n, struct drvmgr_rw_arg *a)
+{
+ drvmgr_rw_memset(dest, c, n, a, (drvmgr_wmem_arg)spw_bus_write_mem);
+ return 0;
+}
+
+int spw_bus_freq_get(
+ struct drvmgr_dev *dev,
+ int options,
+ unsigned int *freq_hz)
+{
+ /* Link Frequency does not translate so good here, since it is
+ * a SpaceWire network, different parts may have different
+ * transfer rates.
+ */
+ *freq_hz = 0;
+
+ return -1;
+}
+
+uint8_t spw_bus_r8(uint8_t *srcadr, struct drvmgr_rw_arg *a)
+{
+ uint8_t result;
+ if ( spw_bus_memcpy((void *)&result, (const void *)srcadr, 1, a) ) {
+ return 0xff;
+ }
+ return result;
+}
+
+uint16_t spw_bus_r16(uint16_t *srcadr, struct drvmgr_rw_arg *a)
+{
+ uint16_t result;
+ if ( spw_bus_memcpy((void *)&result, (const void *)srcadr, 2, a) ) {
+ return 0xff;
+ }
+ return result;
+}
+
+uint32_t spw_bus_r32(uint32_t *srcadr, struct drvmgr_rw_arg *a)
+{
+ uint32_t result;
+ if ( spw_bus_memcpy((void *)&result, (const void *)srcadr, 4, a) ) {
+ return 0xff;
+ }
+ return result;
+}
+
+uint64_t spw_bus_r64(uint64_t *srcadr, struct drvmgr_rw_arg *a)
+{
+ uint64_t result;
+ if ( spw_bus_memcpy((void *)&result, (const void *)srcadr, 8, a) ) {
+ return 0xff;
+ }
+ return result;
+}
+
+void spw_bus_w8(uint8_t *dstadr, uint8_t data, struct drvmgr_rw_arg *a)
+{
+ uint8_t buf[2]; /* One byte extra room for RMAP DATA CRC */
+
+ buf[0] = data;
+ if ( spw_bus_write_mem((void *)dstadr, (const void *)&buf[0], 1, a) ) {
+ /* Handle Error */
+ }
+}
+
+void spw_bus_w16(uint16_t *dstadr, uint16_t data, struct drvmgr_rw_arg *a)
+{
+ uint16_t buf[2]; /* One byte extra room for RMAP DATA CRC */
+
+ buf[0] = data;
+ if ( spw_bus_write_mem((void *)dstadr, (const void *)&buf[0], 2, a) ) {
+ /* Handle Error */
+ }
+}
+
+void spw_bus_w32(uint32_t *dstadr, uint32_t data, struct drvmgr_rw_arg *a)
+{
+ uint32_t buf[2]; /* One byte extra room for RMAP DATA CRC */
+
+ buf[0] = data;
+ if ( spw_bus_write_mem((void *)dstadr, (const void *)&buf[0], 4, a) ) {
+ /* Handle Error */
+ }
+}
+
+void spw_bus_w64(uint64_t *dstadr, uint64_t data, struct drvmgr_rw_arg *a)
+{
+ uint64_t buf[2]; /* One byte extra room for RMAP DATA CRC */
+
+ buf[0] = data;
+ if ( spw_bus_write_mem((void *)dstadr, (const void *)&buf[0], 8, a) ) {
+ /* Handle Error */
+ }
+}
+
+int spw_bus_get_params(struct drvmgr_dev *dev, struct drvmgr_bus_params *params)
+{
+ struct spw_bus_priv *priv = dev->parent->priv;
+
+ params->dev_prefix = &priv->prefix[5];
+
+ return 0;
+}
+
+/************* USER INTERFACE *************/
+
+/*** START: THIS SHOULD BE MOVED TO GRSPW DRIVER ***/
+struct grspw_priv {
+ /* configuration parameters */
+ struct drvmgr_dev *dev; /* Driver manager device */
+ char devName[32]; /* Device Name */
+ void *regs;
+};
+extern struct drvmgr_drv grspw_drv_info;
+
+/* Find GRSPW device from device name */
+static struct drvmgr_dev *grspw_find_dev(char *devName)
+{
+ struct drvmgr_drv *drv = &grspw_drv_info;
+ struct drvmgr_dev *dev;
+ struct grspw_priv *grspw_priv;
+
+ dev = drv->dev;
+ while(dev) {
+ grspw_priv = dev->priv;
+ if ( strcmp(devName, grspw_priv->devName) == 0 )
+ return dev;
+ dev = dev->next_in_drv;
+ }
+ return NULL;
+}
+/*** STOP: THIS SHOULD BE MOVED TO GRSPW DRIVER ***/
+
+
+/* Called from USER to attach bus */
+int spw_bus_register(struct spw_bus_config *config)
+{
+ struct drvmgr_dev *grspw_dev;
+ struct drvmgr_bus *bus;
+ struct spw_bus_priv *priv;
+
+ DBG("SpW-BUS: finding GRSPW device\n");
+
+ /* Find GRSPW Driver to attach bus to */
+ grspw_dev = grspw_find_dev(config->devName);
+ if ( !grspw_dev ) {
+ DBG("SpW-BUS: Failed to find GRSPW device\n");
+ return -1;
+ }
+ if ( grspw_dev->bus ) {
+ DBG("SpW-BUS: GRSPW already has a bus attached to it, aborting\n");
+ return -1;
+ }
+
+ /* Allocate Bus and private structures */
+ drvmgr_alloc_bus(&bus, sizeof(*priv));
+ priv = (struct spw_bus_priv *)(bus + 1);
+
+ /* Save the configuration for later */
+ priv->config = config;
+
+ /* Init the bus */
+ grspw_dev->bus = bus;
+ bus->bus_type = DRVMGR_BUS_TYPE_SPW_RMAP;
+ bus->dev = grspw_dev;
+ bus->priv = priv;
+ bus->ops = (struct drvmgr_bus_ops *)&spw_bus_ops;
+ bus->funcs = spw_bus_funcs;
+ priv->bus = bus;
+
+ DBG("SpW-BUS: registering bus\n");
+ drvmgr_bus_register(bus); /* this will call spw_bus_init to register the devices */
+
+ return 0;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/gpio/gpiolib.c b/c/src/lib/libbsp/sparc/shared/gpio/gpiolib.c
new file mode 100644
index 0000000000..98ebd75002
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/gpio/gpiolib.c
@@ -0,0 +1,280 @@
+/* GPIOLIB interface implementation
+ *
+ * COPYRIGHT (c) 2009.
+ * Aeroflex Gaisler AB
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2009-05-20, Daniel Hellstrom <daniel@gaisler.com>
+ * Created
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <gpiolib.h>
+
+struct gpiolib_port;
+
+struct gpiolib_port {
+ struct gpiolib_port *next;
+ int minor;
+ struct gpiolib_drv *drv;
+ void *handle;
+
+ int open;
+};
+
+/* Root of GPIO Ports */
+struct gpiolib_port *gpiolib_ports;
+
+/* Number of GPIO ports registered */
+static int port_nr;
+
+/* 1 if libraray initialized */
+static int gpiolib_initied = 0;
+
+/* Insert a port first in ports list */
+void gpiolib_list_add(struct gpiolib_port *port)
+{
+ port->next = gpiolib_ports;
+ gpiolib_ports = port;
+}
+
+struct gpiolib_port *gpiolib_find(int minor)
+{
+ struct gpiolib_port *p;
+
+ p = gpiolib_ports;
+ while ( p && (p->minor != minor) ) {
+ p = p->next;
+ }
+ return p;
+}
+
+struct gpiolib_port *gpiolib_find_by_name(char *name)
+{
+ struct gpiolib_port *p;
+ struct gpiolib_info info;
+ int (*get_info)(void *, struct gpiolib_info *);
+
+ p = gpiolib_ports;
+ while ( p ) {
+ get_info = p->drv->ops->get_info;
+ if ( get_info && (get_info(p->handle, &info) == 0) ) {
+ if ( strncmp(name, (char *)&info.devName[0], 64) == 0 ) {
+ break;
+ }
+ }
+ p = p->next;
+ }
+ return p;
+}
+
+void gpiolib_list_remove(struct gpiolib_port *port)
+{
+
+}
+
+int gpiolib_drv_register(struct gpiolib_drv *drv, void *handle)
+{
+ struct gpiolib_port *port;
+
+ if ( !drv || !drv->ops )
+ return -1;
+
+ port = malloc(sizeof(*port));
+ if ( port == NULL )
+ return -1;
+
+ memset(port, 0, sizeof(*port));
+ port->handle = handle;
+ port->minor = port_nr++;
+ port->drv = drv;
+
+ gpiolib_list_add(port);
+
+ return 0;
+}
+
+void gpiolib_show(int port, void *handle)
+{
+ struct gpiolib_port *p;
+
+ if ( port == -1 ) {
+ p = gpiolib_ports;
+ while (p != NULL) {
+ if ( p->drv->ops->show )
+ p->drv->ops->show(p->handle);
+ p = p->next;
+ }
+ } else {
+ if ( handle ) {
+ p = handle;
+ } else {
+ p = gpiolib_find(port);
+ }
+ if ( p == NULL ) {
+ printf("PORT %d NOT FOUND\n", port);
+ return;
+ }
+ if ( p->drv->ops->show )
+ p->drv->ops->show(p->handle);
+ }
+}
+
+void *gpiolib_open_internal(int port, char *devName)
+{
+ struct gpiolib_port *p;
+
+ if ( gpiolib_initied == 0 )
+ return NULL;
+
+ /* Find */
+ if ( port >= 0 ) {
+ p = gpiolib_find(port);
+ } else {
+ p = gpiolib_find_by_name(devName);
+ }
+ if ( p == NULL )
+ return NULL;
+
+ if ( p->open )
+ return NULL;
+
+ p->open = 1;
+ return p;
+}
+
+void *gpiolib_open(int port)
+{
+ return gpiolib_open_internal(port, NULL);
+}
+
+void *gpiolib_open_by_name(char *devName)
+{
+ return gpiolib_open_internal(-1, devName);
+}
+
+void gpiolib_close(void *handle)
+{
+ struct gpiolib_port *p = handle;
+
+ if ( p && p->open ) {
+ p->open = 0;
+ }
+}
+
+int gpiolib_set_config(void *handle, struct gpiolib_config *cfg)
+{
+ struct gpiolib_port *port = handle;
+
+ if ( !port || !cfg )
+ return -1;
+
+ if ( !port->drv->ops->config )
+ return -1;
+
+ return port->drv->ops->config(port->handle, cfg);
+}
+
+int gpiolib_set(void *handle, int dir, int outval)
+{
+ struct gpiolib_port *port = handle;
+
+ if ( !port )
+ return -1;
+
+ if ( !port->drv->ops->set )
+ return -1;
+
+ return port->drv->ops->set(port->handle, dir, outval);
+}
+
+int gpiolib_get(void *handle, int *inval)
+{
+ struct gpiolib_port *port = handle;
+
+ if ( !port || !inval)
+ return -1;
+
+ if ( !port->drv->ops->get )
+ return -1;
+
+ return port->drv->ops->get(port->handle, inval);
+}
+
+/*** IRQ Functions ***/
+int gpiolib_irq_register(void *handle, void *func, void *arg)
+{
+ struct gpiolib_port *port = handle;
+
+ if ( !port )
+ return -1;
+
+ if ( !port->drv->ops->irq_register )
+ return -1;
+
+ return port->drv->ops->irq_register(port->handle, func, arg);
+}
+
+int gpiolib_irq_opts(void *handle, unsigned int options)
+{
+ struct gpiolib_port *port = handle;
+
+ if ( !port )
+ return -1;
+
+ if ( !port->drv->ops->irq_opts )
+ return -1;
+
+ return port->drv->ops->irq_opts(port->handle, options);
+}
+
+int gpiolib_irq_clear(void *handle)
+{
+ return gpiolib_irq_opts(handle, GPIOLIB_IRQ_CLEAR);
+}
+
+int gpiolib_irq_force(void *handle)
+{
+ return gpiolib_irq_opts(handle, GPIOLIB_IRQ_FORCE);
+}
+
+int gpiolib_irq_enable(void *handle)
+{
+ return gpiolib_irq_opts(handle, GPIOLIB_IRQ_ENABLE);
+}
+
+int gpiolib_irq_disable(void *handle)
+{
+ return gpiolib_irq_opts(handle, GPIOLIB_IRQ_DISABLE);
+}
+
+int gpiolib_irq_mask(void *handle)
+{
+ return gpiolib_irq_opts(handle, GPIOLIB_IRQ_MASK);
+}
+
+int gpiolib_irq_unmask(void *handle)
+{
+ return gpiolib_irq_opts(handle, GPIOLIB_IRQ_UNMASK);
+}
+
+
+/*** Initialization ***/
+int gpiolib_initialize(void)
+{
+ if ( gpiolib_initied != 0 )
+ return 0;
+
+ /* Initialize Libarary */
+ port_nr = 0;
+ gpiolib_ports = 0;
+ gpiolib_initied = 1;
+ return 0;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/gpio/grgpio.c b/c/src/lib/libbsp/sparc/shared/gpio/grgpio.c
new file mode 100644
index 0000000000..ab08e1bfbb
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/gpio/grgpio.c
@@ -0,0 +1,454 @@
+/*
+ * GRGPIO GPIO Driver interface.
+ *
+ * COPYRIGHT (c) 2009.
+ * Gaisler Research
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2009-05-20, Daniel Hellstrom <daniel@gaisler.com>
+ * Created
+ */
+
+
+#include <bsp.h>
+#include <rtems/libio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <rtems/bspIo.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+#include <grgpio.h>
+#include <gpiolib.h>
+#include <ambapp.h>
+#include <grlib.h>
+
+/*#define DEBUG 1*/
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#define STATIC
+#else
+#define DBG(x...)
+#define STATIC static
+#endif
+
+struct grgpio_isr {
+ drvmgr_isr isr;
+ void *arg;
+};
+
+struct grgpio_priv {
+ struct drvmgr_dev *dev;
+ struct grgpio_regs *regs;
+ int irq;
+ int minor;
+
+ /* Driver implementation */
+ int port_cnt;
+ unsigned char port_handles[32];
+ struct grgpio_isr isrs[32];
+ struct gpiolib_drv gpiolib_desc;
+ unsigned int bypass;
+ unsigned int imask;
+};
+
+/******************* Driver Manager Part ***********************/
+
+int grgpio_device_init(struct grgpio_priv *priv);
+
+int grgpio_init1(struct drvmgr_dev *dev);
+int grgpio_init2(struct drvmgr_dev *dev);
+
+struct drvmgr_drv_ops grgpio_ops =
+{
+ .init = {grgpio_init1, NULL, NULL, NULL},
+ .remove = NULL,
+ .info = NULL
+};
+
+struct amba_dev_id grgpio_ids[] =
+{
+ {VENDOR_GAISLER, GAISLER_GPIO},
+ {0, 0} /* Mark end of table */
+};
+
+struct amba_drv_info grgpio_drv_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_AMBAPP_GAISLER_GRGPIO_ID, /* Driver ID */
+ "GRGPIO_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */
+ &grgpio_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ 0,
+ },
+ &grgpio_ids[0]
+};
+
+void grgpio_register_drv (void)
+{
+ DBG("Registering GRGPIO driver\n");
+ drvmgr_drv_register(&grgpio_drv_info.general);
+}
+
+/* Register GRGPIO pins as quick as possible to the GPIO library,
+ * other drivers may depend upon them in INIT LEVEL 2.
+ * Note that since IRQ may not be available in init1, it is assumed
+ * that the GPIOLibrary does not request IRQ routines until LEVEL 2.
+ */
+int grgpio_init1(struct drvmgr_dev *dev)
+{
+ struct grgpio_priv *priv;
+ int status, port;
+
+ DBG("GRGPIO[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
+
+ /* This core will not find other cores, but other driver may depend upon
+ * the GPIO library to function. So, we set up GPIO right away.
+ */
+
+ /* Initialize library if not already done */
+ status = gpiolib_initialize();
+ if ( status < 0 )
+ return DRVMGR_FAIL;
+
+ priv = dev->priv = malloc(sizeof(struct grgpio_priv));
+ if ( !priv )
+ return DRVMGR_NOMEM;
+ memset(priv, 0, sizeof(*priv));
+ priv->dev = dev;
+
+ if ( grgpio_device_init(priv) ) {
+ free(dev->priv);
+ dev->priv = NULL;
+ return DRVMGR_FAIL;
+ }
+
+ /* Register all ports available on this core as GPIO port to
+ * upper layer
+ */
+ for(port=0; port<priv->port_cnt; port++) {
+ priv->port_handles[port] = port;
+ gpiolib_drv_register(&priv->gpiolib_desc,
+ &priv->port_handles[port]);
+ }
+
+ return DRVMGR_OK;
+}
+
+/******************* Driver Implementation ***********************/
+
+/* Find port from handle, returns -1 if not found */
+int grgpio_find_port(void *handle, struct grgpio_priv **priv)
+{
+ unsigned char portnr;
+
+ portnr = *(unsigned char *)handle;
+ if ( portnr > 31 )
+ return -1;
+ *priv = (struct grgpio_priv *)
+ (((unsigned int)handle - portnr*sizeof(unsigned char)) -
+ offsetof(struct grgpio_priv, port_handles));
+ return portnr;
+}
+
+int grgpio_gpiolib_open(void *handle)
+{
+ struct grgpio_priv *priv;
+ int portnr;
+
+ portnr = grgpio_find_port(handle, &priv);
+ if ( portnr < 0 ) {
+ DBG("GRGPIO: FAILED OPENING HANDLE 0x%08x\n", handle);
+ return -1;
+ }
+ DBG("GRGPIO[0x%08x][%d]: OPENING\n", priv->regs, portnr);
+
+ /* Open the device, nothing to be done... */
+
+ return 0;
+}
+
+int grgpio_grpiolib_config(void *handle, struct gpiolib_config *cfg)
+{
+ struct grgpio_priv *priv;
+ int portnr;
+ unsigned int mask;
+
+ portnr = grgpio_find_port(handle, &priv);
+ if ( portnr < 0 ) {
+ return -1;
+ }
+ DBG("GRGPIO[0x%08x][%d]: CONFIG\n", priv->regs, portnr);
+
+ /* Configure the device. And check that operation is supported,
+ * not all I/O Pins have IRQ support.
+ */
+ mask = (1<<portnr);
+
+ /* Return error when IRQ not supported by this I/O Line and it
+ * is beeing enabled by user.
+ */
+ if ( ((mask & priv->imask) == 0) && cfg->mask )
+ return -1;
+
+ priv->regs->imask &= ~mask; /* Disable interrupt temporarily */
+
+ /* Configure settings before enabling interrupt */
+ priv->regs->ipol = (priv->regs->ipol & ~mask) | (cfg->irq_polarity ? mask : 0);
+ priv->regs->iedge = (priv->regs->iedge & ~mask) | (cfg->irq_level ? 0 : mask);
+ priv->regs->imask |= cfg->mask ? mask : 0;
+
+ return 0;
+}
+
+int grgpio_grpiolib_get(void *handle, int *inval)
+{
+ struct grgpio_priv *priv;
+ int portnr;
+
+ portnr = grgpio_find_port(handle, &priv);
+ if ( portnr < 0 ) {
+ return -1;
+ }
+ DBG("GRGPIO[0x%08x][%d]: GET\n", priv->regs, portnr);
+
+ /* Get current status of the port */
+ if ( inval )
+ *inval = (priv->regs->data >> portnr) & 0x1;
+
+ return 0;
+}
+
+int grgpio_grpiolib_irq_opts(void *handle, unsigned int options)
+{
+ struct grgpio_priv *priv;
+ int portnr;
+ drvmgr_isr isr;
+ void *arg;
+
+ portnr = grgpio_find_port(handle, &priv);
+ if ( portnr < 0 ) {
+ return -1;
+ }
+ DBG("GRGPIO[0x%08x][%d]: IRQ OPTS 0x%x\n", priv->regs, portnr, options);
+
+ if ( options & GPIOLIB_IRQ_FORCE )
+ return -1;
+
+ isr = priv->isrs[portnr].isr;
+ arg = priv->isrs[portnr].arg;
+
+ if ( options & GPIOLIB_IRQ_DISABLE ) {
+ /* Disable interrupt at interrupt controller */
+ if ( drvmgr_interrupt_unregister(priv->dev, portnr, isr, arg) ) {
+ return -1;
+ }
+ }
+ if ( options & GPIOLIB_IRQ_CLEAR ) {
+ /* Clear interrupt at interrupt controller */
+ if ( drvmgr_interrupt_clear(priv->dev, portnr) ) {
+ return -1;
+ }
+ }
+ if ( options & GPIOLIB_IRQ_ENABLE ) {
+ /* Enable interrupt at interrupt controller */
+ if ( drvmgr_interrupt_register(priv->dev, portnr, "grgpio", isr, arg) ) {
+ return -1;
+ }
+ }
+ if ( options & GPIOLIB_IRQ_MASK ) {
+ /* Mask (disable) interrupt at interrupt controller */
+ if ( drvmgr_interrupt_mask(priv->dev, portnr) ) {
+ return -1;
+ }
+ }
+ if ( options & GPIOLIB_IRQ_UNMASK ) {
+ /* Unmask (enable) interrupt at interrupt controller */
+ if ( drvmgr_interrupt_unmask(priv->dev, portnr) ) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int grgpio_grpiolib_irq_register(void *handle, void *func, void *arg)
+{
+ struct grgpio_priv *priv;
+ int portnr;
+
+ portnr = grgpio_find_port(handle, &priv);
+ if ( portnr < 0 ) {
+ DBG("GRGPIO: FAILED OPENING HANDLE 0x%08x\n", handle);
+ return -1;
+ }
+ DBG("GRGPIO: OPENING %d at [0x%08x]\n", portnr, priv->regs);
+
+ /* Since the user doesn't provide the ISR and argument, we must... */
+ priv->isrs[portnr].isr = func;
+ priv->isrs[portnr].arg = arg;
+
+ return 0;
+}
+
+int grgpio_grpiolib_set(void *handle, int dir, int outval)
+{
+ struct grgpio_priv *priv;
+ int portnr;
+ unsigned int mask;
+
+ portnr = grgpio_find_port(handle, &priv);
+ if ( portnr < 0 ) {
+ DBG("GRGPIO: FAILED OPENING HANDLE 0x%08x\n", handle);
+ return -1;
+ }
+ DBG("GRGPIO: OPENING %d at [0x%08x]\n", portnr, priv->regs);
+
+ /* Set Direction and Output */
+ mask = 1<<portnr;
+ priv->regs->dir = (priv->regs->dir & ~mask) | (dir ? mask : 0);
+ priv->regs->output = (priv->regs->output & ~mask) | (outval ? mask : 0);
+
+ return 0;
+}
+
+int grgpio_gpiolib_show(void *handle)
+{
+ struct grgpio_priv *priv;
+ int portnr, i, regs[7];
+ volatile unsigned int *reg;
+
+ portnr = grgpio_find_port(handle, &priv);
+ if ( portnr < 0 ) {
+ DBG("GRGPIO: FAILED SHOWING HANDLE 0x%08x\n", handle);
+ return -1;
+ }
+ for (i=0, reg=&priv->regs->data; i<7; i++, reg++) {
+ regs[i] = ( *reg >> portnr) & 1;
+ }
+ printf("GRGPIO[%p] PORT[%d]: IN/OUT/DIR: [%d,%d,%d], MASK/POL/EDGE: [%d,%d,%d], BYPASS: %d\n",
+ priv->regs, portnr, regs[0], regs[1], regs[2], regs[3], regs[4], regs[5], regs[6]);
+ return 0;
+}
+
+int grgpio_gpiolib_get_info(void *handle, struct gpiolib_info *pinfo)
+{
+ struct grgpio_priv *priv;
+ int portnr;
+ char prefix[48];
+ struct drvmgr_dev *dev;
+
+ if ( !pinfo )
+ return -1;
+
+ portnr = grgpio_find_port(handle, &priv);
+ if ( portnr < 0 ) {
+ DBG("GRGPIO: FAILED GET_INFO HANDLE 0x%08x\n", handle);
+ return -1;
+ }
+
+ /* Get Filesystem name prefix */
+ dev = priv->dev;
+ prefix[0] = '\0';
+ if ( drvmgr_get_dev_prefix(dev, prefix) ) {
+ /* Failed to get prefix, make sure of a unique FS name
+ * by using the driver minor.
+ */
+ snprintf(pinfo->devName, 64, "/dev/grgpio%d/%d", dev->minor_drv, portnr);
+ } else {
+ /* Got special prefix, this means we have a bus prefix
+ * And we should use our "bus minor"
+ */
+ snprintf(pinfo->devName, 64, "/dev/%sgrgpio%d/%d", prefix, dev->minor_bus, portnr);
+ }
+
+ return 0;
+}
+
+static struct gpiolib_drv_ops grgpio_gpiolib_ops =
+{
+ .config = grgpio_grpiolib_config,
+ .get = grgpio_grpiolib_get,
+ .irq_opts = grgpio_grpiolib_irq_opts,
+ .irq_register = grgpio_grpiolib_irq_register,
+ .open = grgpio_gpiolib_open,
+ .set = grgpio_grpiolib_set,
+ .show = grgpio_gpiolib_show,
+ .get_info = grgpio_gpiolib_get_info,
+};
+
+int grgpio_device_init(struct grgpio_priv *priv)
+{
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
+ union drvmgr_key_value *value;
+ unsigned int mask;
+ int port_cnt;
+
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)priv->dev->businfo;
+ if ( ambadev == NULL ) {
+ return -1;
+ }
+ pnpinfo = &ambadev->info;
+ priv->irq = pnpinfo->irq;
+ priv->regs = (struct grgpio_regs *)pnpinfo->apb_slv->start;
+
+ DBG("GRGPIO: 0x%08x irq %d\n", (unsigned int)priv->regs, priv->irq);
+
+ /* Mask all Interrupts */
+ priv->regs->imask = 0;
+
+ /* Make IRQ Rising edge triggered default */
+ priv->regs->ipol = 0xfffffffe;
+ priv->regs->iedge = 0xfffffffe;
+
+ /* Read what I/O lines have IRQ support */
+ priv->imask = priv->regs->ipol;
+
+ /* Let the user configure the port count, this might be needed
+ * when the GPIO lines must not be changed (assigned during bootup)
+ */
+ value = drvmgr_dev_key_get(priv->dev, "nBits", KEY_TYPE_INT);
+ if ( value ) {
+ priv->port_cnt = value->i;
+ } else {
+ /* Auto detect number of GPIO ports */
+ priv->regs->dir = 0;
+ priv->regs->output = 0xffffffff;
+ mask = priv->regs->output;
+ priv->regs->output = 0;
+
+ for(port_cnt=0; port_cnt<32; port_cnt++)
+ if ( (mask & (1<<port_cnt)) == 0 )
+ break;
+ priv->port_cnt = port_cnt;
+ }
+
+ /* Let the user configure the BYPASS register, this might be needed
+ * to select which cores can do I/O on a pin.
+ */
+ value = drvmgr_dev_key_get(priv->dev, "bypass", KEY_TYPE_INT);
+ if ( value ) {
+ priv->bypass = value->i;
+ } else {
+ priv->bypass = 0;
+ }
+ priv->regs->bypass = priv->bypass;
+
+ /* Prepare GPIOLIB layer */
+ priv->gpiolib_desc.ops = &grgpio_gpiolib_ops;
+
+ return 0;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/graes/graes.c b/c/src/lib/libbsp/sparc/shared/graes/graes.c
new file mode 100644
index 0000000000..1e729837b7
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/graes/graes.c
@@ -0,0 +1,1290 @@
+/* GRAES AES dma driver
+ *
+ * --------------------------------------------------------------------------
+ * -- This file is a part of GAISLER RESEARCH source code.
+ * -- Copyright (C) 2009, Aeroflex Gaisler AB - all rights reserved.
+ * --
+ * -- ANY USE OR REDISTRIBUTION IN PART OR IN WHOLE MUST BE HANDLED IN
+ * -- ACCORDANCE WITH THE GAISLER LICENSE AGREEMENT AND MUST BE APPROVED
+ * -- IN ADVANCE IN WRITING.
+ * --
+ * -- BY DEFAULT, DISTRIBUTION OR DISCLOSURE IS NOT PERMITTED.
+ * --------------------------------------------------------------------------
+ *
+ * 2010-06-29, Konrad Eisele <konrad@gaisler.com>
+ * GRAES DMA driver based on GRTM driver
+ *
+ * 2008-12-11, Daniel Hellstrom <daniel@gaisler.com>
+ * Converted to support driver manager
+ *
+ * 2007-04-17, Daniel Hellstrom <daniel@gaisler.com>
+ * New driver in sparc shared directory.
+ *
+ */
+
+
+#include <bsp.h>
+#include <rtems/libio.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+#include <malloc.h>
+#include <rtems/bspIo.h>
+
+#include <drvmgr/drvmgr.h>
+#include <ambapp.h>
+#include <drvmgr/ambapp_bus.h>
+#include <graes.h>
+
+#define REMOTE_DESCRIPTORS
+
+#ifndef IRQ_GLOBAL_PREPARE
+ #define IRQ_GLOBAL_PREPARE(level) rtems_interrupt_level level
+#endif
+
+#ifndef IRQ_GLOBAL_DISABLE
+ #define IRQ_GLOBAL_DISABLE(level) rtems_interrupt_disable(level)
+#endif
+
+#ifndef IRQ_GLOBAL_ENABLE
+ #define IRQ_GLOBAL_ENABLE(level) rtems_interrupt_enable(level)
+#endif
+
+/*
+#define DEBUG
+#define DEBUGFUNCS
+*/
+
+#include <debug_defs.h>
+
+/* GRAES register map */
+struct graes_regs {
+ volatile unsigned int dma_ctrl; /* DMA Control Register (0x00) */
+ volatile unsigned int dma_status; /* DMA Status Register (0x04) */
+ volatile unsigned int dma_bd; /* DMA Descriptor Pointer Register (0x08) */
+ volatile unsigned int d0; /* */
+
+ volatile unsigned int d1; /* */
+ volatile unsigned int d2; /* */
+
+ int unused0[(0x80-0x18)/4];
+
+};
+
+#define GRAES_BDAR_ENTRIES 32
+#define GRAES_BDAR_SIZE (GRAES_BDAR_ENTRIES * sizeof(struct graes_bd))
+
+/* DMA Control Register (0x00) */
+#define GRAES_DMA_CTRL_EN_BIT 0
+#define GRAES_DMA_CTRL_IE_BIT 1
+
+#define GRAES_DMA_CTRL_EN (1<<GRAES_DMA_CTRL_EN_BIT)
+#define GRAES_DMA_CTRL_IE (1<<GRAES_DMA_CTRL_IE_BIT)
+
+/* GRAES transmit descriptor (GRAES_BDAR_SIZE Alignment need) */
+struct graes_bd {
+ volatile unsigned int ctrl;
+ union {
+ unsigned int d[5];
+ struct {
+ unsigned int in;
+ unsigned int out;
+ unsigned int iv;
+ unsigned int key;
+ unsigned int next;
+ };
+ } u;
+};
+
+#define GRAES_BD_EN_BIT 0
+#define GRAES_BD_IE_BIT 1
+#define GRAES_BD_WR_BIT 2
+#define GRAES_BD_KEY_BIT 7
+#define GRAES_BD_IV_BIT 6
+#define GRAES_BD_OUT_BIT 5
+
+#define GRAES_BD_EN (1<<GRAES_BD_EN_BIT)
+#define GRAES_BD_WR (1<<GRAES_BD_WR_BIT)
+#define GRAES_BD_IE (1<<GRAES_BD_IE_BIT)
+#define GRAES_BD_KEY (1<<GRAES_BD_KEY_BIT)
+#define GRAES_BD_IV (1<<GRAES_BD_IV_BIT)
+#define GRAES_BD_OUT (1<<GRAES_BD_OUT_BIT)
+
+/* Load register */
+
+#define READ_REG(address) (*(volatile unsigned int *)address)
+
+/* Driver functions */
+static rtems_device_driver graes_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver graes_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver graes_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver graes_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver graes_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver graes_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+
+#define GRAES_DRIVER_TABLE_ENTRY { graes_initialize, graes_open, graes_close, graes_read, graes_write, graes_ioctl }
+
+static rtems_driver_address_table graes_driver = GRAES_DRIVER_TABLE_ENTRY;
+
+/* Structure that connects BD with SoftWare Frame */
+struct graes_ring {
+ struct graes_ring *next;
+ struct graes_bd *bd;
+ struct graes_block *frm;
+};
+
+struct graes_priv {
+ struct drvmgr_dev *dev; /* Driver manager device */
+ char devName[32]; /* Device Name */
+ struct graes_regs *regs;
+ int irq;
+ int minor;
+
+ int open;
+ int running;
+
+ struct graes_bd *bds;
+ void *_bds;
+
+ /* Interrupt generation */
+ int enable_cnt_curr;/* Down counter, when 0 the interrupt bit is set for next descriptor */
+ volatile int handling_transmission; /* Tells ISR if user are active changing descriptors/queues */
+
+ struct graes_ring *_ring; /* Root of ring */
+ struct graes_ring *ring; /* Next ring to use for new frames to be transmitted */
+ struct graes_ring *ring_end; /* Oldest activated ring used */
+
+ /* Collections of frames Ready to sent/ Scheduled for transmission/Sent
+ * frames waiting for the user to reclaim
+ */
+ struct graes_list ready; /* Frames Waiting for free BDs */
+ struct graes_list scheduled; /* Frames in BDs beeing transmitted */
+ struct graes_list sent; /* Sent Frames waiting for user to reclaim and reuse */
+
+ /* Number of frames in the lists */
+ int ready_cnt; /* Number of ready frames */
+ int scheduled_cnt; /* Number of scheduled frames */
+ int sent_cnt; /* Number of sent frames */
+
+ struct graes_ioc_hw hw_avail; /* Hardware support available */
+ struct graes_ioc_config config;
+ struct graes_ioc_stats stats;
+
+ rtems_id sem_rx;
+};
+
+/* Prototypes */
+static void *graes_memalign(unsigned int boundary, unsigned int length, void *realbuf);
+static void graes_hw_reset(struct graes_priv *pDev);
+static void graes_interrupt(int irq, void *arg);
+
+/* Common Global Variables */
+static rtems_id graes_dev_sem;
+static int graes_driver_io_registered = 0;
+static rtems_device_major_number graes_driver_io_major = 0;
+
+/******************* Driver manager interface ***********************/
+
+/* Driver prototypes */
+static int graes_register_io(rtems_device_major_number *m);
+static int graes_device_init(struct graes_priv *pDev);
+
+static int graes_init2(struct drvmgr_dev *dev);
+static int graes_init3(struct drvmgr_dev *dev);
+
+static struct drvmgr_drv_ops graes_ops =
+{
+ {NULL, graes_init2, graes_init3, NULL},
+ NULL,
+ NULL,
+};
+
+static struct amba_dev_id graes_ids[] =
+{
+ {VENDOR_GAISLER, GAISLER_GRAESDMA},
+ {0, 0} /* Mark end of table */
+};
+
+static struct amba_drv_info graes_drv_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_AMBAPP_GAISLER_GRAES_ID, /* Driver ID */
+ "GRAES_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */
+ &graes_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ 0,
+ },
+ &graes_ids[0]
+};
+
+void graes_register_drv (void)
+{
+ DBG("Registering GRAES driver\n");
+ drvmgr_drv_register(&graes_drv_info.general);
+}
+
+static int graes_init2(struct drvmgr_dev *dev)
+{
+ struct graes_priv *priv;
+
+ DBG("GRAES[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
+ priv = dev->priv = malloc(sizeof(struct graes_priv));
+ if ( !priv )
+ return DRVMGR_NOMEM;
+ memset(priv, 0, sizeof(*priv));
+ priv->dev = dev;
+
+ /* This core will not find other cores, so we wait for init2() */
+
+ return DRVMGR_OK;
+}
+
+static int graes_init3(struct drvmgr_dev *dev)
+{
+ struct graes_priv *priv;
+ char prefix[32];
+ rtems_status_code status;
+
+ priv = dev->priv;
+
+ /* Do initialization */
+
+ if ( graes_driver_io_registered == 0) {
+ /* Register the I/O driver only once for all cores */
+ if ( graes_register_io(&graes_driver_io_major) ) {
+ /* Failed to register I/O driver */
+ DBG("GRAES[%d] Failed to register I/O driver\n", dev->minor_drv);
+ dev->priv = NULL;
+ return DRVMGR_FAIL;
+ }
+
+ graes_driver_io_registered = 1;
+ }
+
+ /* I/O system registered and initialized
+ * Now we take care of device initialization.
+ */
+ if ( graes_device_init(priv) ) {
+ DBG("GRAES[%d] Failed to call graes_device_init\n", dev->minor_drv);
+ return DRVMGR_FAIL;
+ }
+
+ /* Get Filesystem name prefix */
+ prefix[0] = '\0';
+ if ( drvmgr_get_dev_prefix(dev, prefix) ) {
+ /* Failed to get prefix, make sure of a unique FS name
+ * by using the driver minor.
+ */
+ sprintf(priv->devName, "/dev/graes%d", dev->minor_drv);
+ } else {
+ /* Got special prefix, this means we have a bus prefix
+ * And we should use our "bus minor"
+ */
+ sprintf(priv->devName, "/dev/%sgraes%d", prefix, dev->minor_bus);
+ }
+
+ DBG("GRAES: add dev %s\n",priv->devName);
+
+ /* Register Device */
+ status = rtems_io_register_name(priv->devName, graes_driver_io_major, dev->minor_drv);
+ if (status != RTEMS_SUCCESSFUL) {
+ return status;
+ }
+
+ return DRVMGR_OK;
+}
+
+/******************* Driver Implementation ***********************/
+
+static int graes_register_io(rtems_device_major_number *m)
+{
+ rtems_status_code r;
+
+ if ((r = rtems_io_register_driver(0, &graes_driver, m)) == RTEMS_SUCCESSFUL) {
+ DBG("GRAES driver successfully registered, major: %d\n", *m);
+ } else {
+ switch(r) {
+ case RTEMS_TOO_MANY:
+ printk("GRAES rtems_io_register_driver failed: RTEMS_TOO_MANY\n");
+ return -1;
+ case RTEMS_INVALID_NUMBER:
+ printk("GRAES rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n");
+ return -1;
+ case RTEMS_RESOURCE_IN_USE:
+ printk("GRAES rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n");
+ return -1;
+ default:
+ printk("GRAES rtems_io_register_driver failed\n");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int graes_device_init(struct graes_priv *pDev)
+{
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
+
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)pDev->dev->businfo;
+ if ( ambadev == NULL ) {
+ return -1;
+ }
+ pnpinfo = &ambadev->info;
+ pDev->irq = pnpinfo->irq;
+ pDev->regs = (struct graes_regs *)pnpinfo->apb_slv->start;
+ pDev->minor = pDev->dev->minor_drv;
+ pDev->open = 0;
+ pDev->running = 0;
+
+ /* Create Binary RX Semaphore with count = 0 */
+ if ( rtems_semaphore_create(rtems_build_name('G', 'P', 'R', '0' + pDev->minor),
+ 0,
+ RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|\
+ RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &pDev->sem_rx) != RTEMS_SUCCESSFUL ) {
+ return -1;
+ }
+
+ /* Allocate Memory for Descriptors */
+#ifdef REMOTE_DESCRIPTORS
+ pDev->bds = 0xc0800000;
+ pDev->_bds = 0xc0800000;
+#else
+ pDev->bds = (struct graes_bd *)graes_memalign(GRAES_BDAR_SIZE, GRAES_BDAR_SIZE, &pDev->_bds);
+#endif
+ if ( !pDev->bds ) {
+ DBG("GRAES: Failed to allocate descriptor table\n");
+ return -1;
+ }
+ memset(pDev->bds, 0, GRAES_BDAR_SIZE);
+
+ pDev->_ring = malloc(sizeof(struct graes_ring) * GRAES_BDAR_ENTRIES);
+ if ( !pDev->_ring ) {
+ DBG("GRAES: Failed to allocate ring\n");
+ return -1;
+ }
+
+ /* Reset Hardware before attaching IRQ handler */
+ graes_hw_reset(pDev);
+
+ return 0;
+}
+
+
+static inline void graes_list_clr(struct graes_list *list)
+{
+ list->head = NULL;
+ list->tail = NULL;
+}
+
+static void graes_hw_reset(struct graes_priv *pDev)
+{
+ /* Reset Core */
+}
+
+static void graes_hw_get_implementation(struct graes_priv *pDev, struct graes_ioc_hw *hwcfg)
+{
+ hwcfg->key_size= 256;
+}
+
+#warning Extra: Implement proper default calculation from hardware configuration
+static void graes_hw_get_default_modes(struct graes_ioc_config *cfg, struct graes_ioc_hw *hwcfg)
+{
+ cfg->key_size = 256;
+
+ /* Interrupt options */
+ cfg->blocking = 0; /* non-blocking mode is default */
+ cfg->enable_cnt = 1; /* generate interrupt every 16 descriptor */
+ cfg->isr_desc_proc = 1; /* Let interrupt handler do descriptor processing */
+ cfg->timeout = RTEMS_NO_TIMEOUT;
+
+}
+
+static void *graes_memalign(unsigned int boundary, unsigned int length, void *realbuf)
+{
+ *(int *)realbuf = (int)malloc(length+boundary);
+ DBG("GRAES: Alloced %d (0x%x) bytes, requested: %d\n",length+boundary,length+boundary,length);
+ return (void *)(((*(unsigned int *)realbuf)+boundary) & ~(boundary-1));
+}
+
+static int graes_hw_set_config(struct graes_priv *pDev, struct graes_ioc_config *cfg, struct graes_ioc_hw *hwcfg)
+{
+ struct graes_regs *regs = pDev->regs;
+ unsigned int tmp;
+
+ return 0;
+}
+
+static int graes_start(struct graes_priv *pDev)
+{
+ struct graes_regs *regs = pDev->regs;
+ int i;
+ struct graes_ioc_config *cfg = &pDev->config;
+ volatile unsigned int *txrdy_reg;
+ unsigned int txrdy_mask, transaddr;
+
+ /* Clear Descriptors */
+ memset(pDev->bds,0,GRAES_BDAR_SIZE);
+
+ /* Clear stats */
+ memset(&pDev->stats,0,sizeof(struct graes_ioc_stats));
+
+ /* Init Descriptor Ring */
+ memset(pDev->_ring,0,sizeof(struct graes_ring)*GRAES_BDAR_ENTRIES);
+ for(i=0;i<(GRAES_BDAR_ENTRIES-1);i++){
+ pDev->_ring[i].next = &pDev->_ring[i+1];
+ pDev->_ring[i].bd = &pDev->bds[i];
+ pDev->_ring[i].frm = NULL;
+ }
+ pDev->_ring[(GRAES_BDAR_ENTRIES-1)].next = &pDev->_ring[0];
+ pDev->_ring[(GRAES_BDAR_ENTRIES-1)].bd = &pDev->bds[(GRAES_BDAR_ENTRIES-1)];
+ pDev->_ring[(GRAES_BDAR_ENTRIES-1)].frm = NULL;
+
+ pDev->ring = &pDev->_ring[0];
+ pDev->ring_end = &pDev->_ring[0];
+
+ /* Clear Scheduled, Ready and Sent list */
+ graes_list_clr(&pDev->ready);
+ graes_list_clr(&pDev->scheduled);
+ graes_list_clr(&pDev->sent);
+
+ /* Software init */
+ pDev->handling_transmission = 0;
+
+ /* Reset the transmitter */
+ regs->dma_ctrl = 0; /* Leave Reset */
+
+
+ /* Set Descriptor Pointer Base register to point to first descriptor */
+ drvmgr_translate(pDev->dev, 0, 0, (void *)pDev->bds, (void **)&transaddr);
+ regs->dma_bd = transaddr;
+
+ DBG("GRAES: set bd to 0x%08x\n",transaddr);
+
+ /*regs->dma_bd = (unsigned int)pDev->bds;*/
+
+ /* Set hardware options as defined by config */
+ if ( graes_hw_set_config(pDev, cfg, &pDev->hw_avail) ) {
+ return RTEMS_IO_ERROR;
+ }
+
+
+ DBG("GRAES: reset time %d\n",i);
+
+
+ /* Mark running before enabling the DMA transmitter */
+ pDev->running = 1;
+
+ /* Enable interrupts (Error and DMA TX) */
+ regs->dma_ctrl = GRAES_DMA_CTRL_IE;
+
+ DBG("GRAES: STARTED\n");
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static void graes_stop(struct graes_priv *pDev)
+{
+ struct graes_regs *regs = pDev->regs;
+
+ /* Disable the transmitter & Interrupts */
+ regs->dma_ctrl = 0;
+
+
+ DBG("GRAES: STOPPED\n");
+
+ /* Flush semaphore in case a thread is stuck waiting for TX Interrupts */
+ rtems_semaphore_flush(pDev->sem_rx);
+}
+
+static rtems_device_driver graes_open(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg)
+{
+ struct graes_priv *pDev;
+ struct drvmgr_dev *dev;
+
+ FUNCDBG();
+
+ if ( drvmgr_get_dev(&graes_drv_info.general, minor, &dev) ) {
+ DBG("Wrong minor %d\n", minor);
+ return RTEMS_INVALID_NUMBER;
+ }
+ pDev = (struct graes_priv *)dev->priv;
+
+ /* Wait until we get semaphore */
+ if ( rtems_semaphore_obtain(graes_dev_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT) != RTEMS_SUCCESSFUL ){
+ return RTEMS_INTERNAL_ERROR;
+ }
+
+ /* Is device in use? */
+ if ( pDev->open ){
+ rtems_semaphore_release(graes_dev_sem);
+ return RTEMS_RESOURCE_IN_USE;
+ }
+
+ /* Mark device taken */
+ pDev->open = 1;
+
+ rtems_semaphore_release(graes_dev_sem);
+
+ DBG("graes_open: OPENED minor %d (pDev: 0x%x)\n",pDev->minor,(unsigned int)pDev);
+ /* Set defaults */
+ pDev->config.timeout = RTEMS_NO_TIMEOUT; /* no timeout (wait forever) */
+ pDev->config.blocking = 0; /* polling mode */
+
+ pDev->running = 0; /* not in running mode yet */
+
+ memset(&pDev->config,0,sizeof(pDev->config));
+
+ /* The core has been reset when we execute here, so it is possible
+ * to read out what HW is implemented from core.
+ */
+ graes_hw_get_implementation(pDev, &pDev->hw_avail);
+
+ /* Get default modes */
+ graes_hw_get_default_modes(&pDev->config,&pDev->hw_avail);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver graes_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ struct graes_priv *pDev;
+ struct drvmgr_dev *dev;
+
+ FUNCDBG();
+
+ if ( drvmgr_get_dev(&graes_drv_info.general, minor, &dev) ) {
+ return RTEMS_INVALID_NUMBER;
+ }
+ pDev = (struct graes_priv *)dev->priv;
+
+ if ( pDev->running ){
+ graes_stop(pDev);
+ pDev->running = 0;
+ }
+
+ /* Reset core */
+ graes_hw_reset(pDev);
+
+ /* Clear descriptor area just for sure */
+ memset(pDev->bds, 0, GRAES_BDAR_SIZE);
+
+ /* Mark not open */
+ pDev->open = 0;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver graes_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ FUNCDBG();
+ return RTEMS_NOT_IMPLEMENTED;
+}
+
+static rtems_device_driver graes_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ FUNCDBG();
+ return RTEMS_NOT_IMPLEMENTED;
+}
+
+/* Scans the desciptor table for scheduled frames that has been sent,
+ * and moves these frames from the head of the scheduled queue to the
+ * tail of the sent queue.
+ *
+ * Also, for all frames the status is updated.
+ *
+ * Return Value
+ * Number of frames freed.
+ */
+static int graes_free_encrypted(struct graes_priv *pDev)
+{
+ struct graes_ring *curr;
+ struct graes_block *last_frm, *first_frm;
+ int freed_frame_cnt=0;
+ unsigned int ctrl;
+
+ curr = pDev->ring_end;
+
+ /* Step into TX ring to find sent frames */
+ if ( !curr->frm ){
+ /* No scheduled frames, abort */
+ return 0;
+ }
+
+ /* There has been messages scheduled ==> scheduled messages may have been
+ * transmitted and needs to be collected.
+ */
+
+ first_frm = curr->frm;
+
+ /* Loop until first enabled unsent frame is found.
+ * A unused descriptor is indicated by an unassigned frm field
+ */
+ while ( curr->frm && !((ctrl=READ_REG(&curr->bd->ctrl)) & GRAES_BD_EN) ){
+ /* Handle one sent Frame */
+#ifdef DEBUG
+ printk(" fini bd: 0x%08x @ 0x%08x\n",ctrl,curr->bd);
+#endif
+
+ /* Remember last handled frame so that insertion/removal from
+ * frames lists go fast.
+ */
+ last_frm = curr->frm;
+
+ /* 1. Set flags to indicate error(s) and other information */
+ last_frm->flags |= GRAES_FLAGS_PROCESSED; /* Mark sent */
+
+ /* Update Stats */
+ pDev->stats.blocks_processed++;
+
+ curr->frm = NULL; /* Mark unused */
+
+ /* Increment */
+ curr = curr->next;
+ freed_frame_cnt++;
+ }
+
+ /* 1. Remove all handled frames from scheduled queue
+ * 2. Put all handled frames into sent queue
+ */
+ if ( freed_frame_cnt > 0 ){
+
+ /* Save TX ring posistion */
+ pDev->ring_end = curr;
+
+ /* Remove all sent frames from scheduled list */
+ if ( pDev->scheduled.tail == last_frm ){
+ /* All scheduled frames sent... */
+ pDev->scheduled.head = NULL;
+ pDev->scheduled.tail = NULL;
+ }else{
+ pDev->scheduled.head = last_frm->next;
+ }
+ last_frm->next = NULL;
+
+ /* Put all sent frames into "Sent queue" for user to
+ * collect, later on.
+ */
+ if ( !pDev->sent.head ){
+ /* Sent queue empty */
+ pDev->sent.head = first_frm;
+ pDev->sent.tail = last_frm;
+ }else{
+ pDev->sent.tail->next = first_frm;
+ pDev->sent.tail = last_frm;
+ }
+ }
+ return freed_frame_cnt;
+}
+
+static unsigned int graes_trans(struct graes_priv *pDev, struct graes_block *curr_frm, unsigned int addr_in ) {
+ unsigned int addr = addr_in;
+ /* Prepare descriptor address. Three cases:
+ * - GRAES core on same bus as CPU ==> no translation (Address used by CPU = address used by GRAES)
+ * - GRAES core on remote bus, and payload address given as used by CPU ==> Translation needed
+ * - GRAES core on remote bus, and payload address given as used by GRAES ==> no translation [ USER does custom translation]
+ */
+ if ( curr_frm->flags & (GRAES_FLAGS_TRANSLATE|GRAES_FLAGS_TRANSLATE_AND_REMEMBER) ) {
+ /* Do translation */
+ drvmgr_translate(pDev->dev, 0, 0, (void *)addr_in, (void **)&addr);
+ if ( curr_frm->flags & GRAES_FLAGS_TRANSLATE_AND_REMEMBER ) {
+ if ( addr_in != addr ) {
+ /* Translation needed */
+ curr_frm->flags &= ~GRAES_FLAGS_TRANSLATE_AND_REMEMBER;
+ curr_frm->flags |= GRAES_FLAGS_TRANSLATE;
+ } else {
+ /* No Trnaslation needed */
+ curr_frm->flags &= ~(GRAES_FLAGS_TRANSLATE|GRAES_FLAGS_TRANSLATE_AND_REMEMBER);
+ }
+ }
+ } else {
+ /* Custom translation or no translation needed */
+ addr = (unsigned int)addr_in;
+ }
+ return addr;
+}
+
+/* Moves as many frames in the ready queue (as there are free descriptors for)
+ * to the scheduled queue. The free descriptors are then assigned one frame
+ * each and enabled for transmission.
+ *
+ * Return Value
+ * Returns number of frames moved from ready to scheduled queue
+ */
+static int graes_schedule_ready(struct graes_priv *pDev, int ints_off)
+{
+ int cnt;
+ unsigned int ctrl, dmactrl, oldLevel, addr;
+ struct graes_ring *curr_bd;
+ struct graes_block *curr_frm, *last_frm;
+
+ if ( !pDev->ready.head ){
+ return 0;
+ }
+
+ cnt=0;
+ curr_frm = pDev->ready.head;
+ curr_bd = pDev->ring;
+ while( !curr_bd->frm ){
+ int i = 0, j; unsigned int kaddr = -1, iaddr = -1, oaddr = -1, daddr, naddr;
+ /* Assign frame to descriptor */
+ curr_bd->frm = curr_frm;
+
+ /* Prepare descriptor address. Three cases:
+ * - GRAES core on same bus as CPU ==> no translation (Address used by CPU = address used by GRAES)
+ * - GRAES core on remote bus, and payload address given as used by CPU ==> Translation needed
+ * - GRAES core on remote bus, and payload address given as used by GRAES ==> no translation [ USER does custom translation]
+ */
+
+ ctrl = GRAES_BD_EN;
+
+ daddr = addr = graes_trans(pDev, curr_frm, curr_frm->payload);
+ curr_bd->bd->u.d[i++] = addr;
+
+ if (curr_frm->out) {
+ ctrl |= GRAES_BD_OUT;
+ oaddr = addr = graes_trans(pDev, curr_frm, curr_frm->out);
+ curr_bd->bd->u.d[i++] = addr;
+ }
+ if (curr_frm->iv) {
+ ctrl |= GRAES_BD_IV;
+ iaddr = addr = graes_trans(pDev, curr_frm, curr_frm->iv);
+ curr_bd->bd->u.d[i++] = addr;
+ }
+ if (curr_frm->key) {
+ ctrl |= GRAES_BD_KEY;
+ kaddr = addr = graes_trans(pDev, curr_frm, curr_frm->key);
+ curr_bd->bd->u.d[i++] = addr;
+ }
+
+ drvmgr_translate(pDev->dev, 0, 0, (void *)curr_bd->next->bd, (void **)&naddr);
+ curr_bd->bd->u.d[i++] = naddr;
+
+ if ( curr_bd->next == pDev->_ring ){
+
+ /* Wrap around */
+ }
+
+ ctrl |= ((curr_frm->length & 0x7ff) << 21);
+
+ /* Apply user options/flags */
+ ctrl |= (curr_frm->flags & GRAES_FLAGS_MASK);
+
+ /* Is this Frame going to be an interrupt Frame? */
+ if ( (--pDev->enable_cnt_curr) <= 0 ){
+ if ( pDev->config.enable_cnt == 0 ){
+ pDev->enable_cnt_curr = 0x3fffffff;
+ }else{
+ pDev->enable_cnt_curr = pDev->config.enable_cnt;
+ ctrl |= GRAES_BD_IE;
+ }
+ }
+
+ /* Enable descriptor */
+ curr_bd->bd->ctrl = ctrl;
+
+#ifdef DEBUG
+ printk(" add bd: 0x%08x @ 0x%08x [0x%08x",ctrl,curr_bd->bd, daddr);
+ if(oaddr != -1)
+ printk(",o:0x%08x",oaddr);
+ if(iaddr != -1)
+ printk(",i:0x%08x",iaddr);
+ if(kaddr != -1)
+ printk(",k:0x%08x",kaddr);
+ printk("] [");
+ for (j = 0; j < 6; j++) {
+ printk(" 0x%08x",((unsigned int *)curr_bd->bd)[j]);
+ }
+ printk("]\n");
+
+#endif
+
+ last_frm = curr_frm;
+ curr_bd = curr_bd->next;
+ cnt++;
+
+ /* Get Next Frame from Ready Queue */
+ if ( curr_frm == pDev->ready.tail ){
+ /* Handled all in ready queue. */
+ curr_frm = NULL;
+ break;
+ }
+ curr_frm = curr_frm->next;
+ }
+
+ /* Has frames have been scheduled? */
+ if ( cnt > 0 ){
+ /* Make last frame mark end of chain, probably pointless... */
+ last_frm->next = NULL;
+
+ /* Insert scheduled packets into scheduled queue */
+ if ( !pDev->scheduled.head ){
+ /* empty scheduled queue */
+ pDev->scheduled.head = pDev->ready.head;
+ pDev->scheduled.tail = last_frm;
+ }else{
+ pDev->scheduled.tail->next = pDev->ready.head;
+ pDev->scheduled.tail = last_frm;
+ }
+
+ /* Remove scheduled packets from ready queue */
+ pDev->ready.head = curr_frm;
+ if ( !curr_frm ){
+ pDev->ready.tail = NULL;
+ }
+
+ /* Update TX ring posistion */
+ pDev->ring = curr_bd;
+ if ( !ints_off ) {
+ IRQ_GLOBAL_DISABLE(oldLevel);
+ }
+
+ /* Make hardware aware of the newly enabled descriptors */
+ dmactrl = READ_REG(&pDev->regs->dma_ctrl);
+ dmactrl |= GRAES_DMA_CTRL_EN;
+ pDev->regs->dma_ctrl = dmactrl;
+
+ if ( !ints_off ) {
+ IRQ_GLOBAL_ENABLE(oldLevel);
+ }
+ }
+ return cnt;
+}
+
+static void graes_printchain(struct graes_priv *pDev, struct graes_print_status *ps, struct graes_list *chain)
+{
+ struct graes_block *curr;
+ curr = chain->head;
+ while(curr){
+ printk(" 0x%08x: [@0x%08x]\n",curr,curr->payload);
+ if (curr == chain->tail)
+ break;
+ curr = curr->next;
+ }
+}
+
+static void graes_printstatus(struct graes_priv *pDev, struct graes_print_status *ps)
+{
+ int oldLevel;
+
+ IRQ_GLOBAL_DISABLE(oldLevel);
+
+ printk("processed : %d\n",(int)pDev->stats.blocks_processed);
+
+ printk("ready_cnt : %d\n",pDev->ready_cnt);
+ printk("scheduled_cnt: %d\n",pDev->scheduled_cnt);
+ printk("sent_cnt : %d\n",pDev->sent_cnt);
+
+ printk(" ready:\n");
+ graes_printchain(pDev, ps, &pDev->ready);
+ printk(" scheduled:\n");
+ graes_printchain(pDev, ps, &pDev->scheduled);
+ printk(" sent:\n");
+ graes_printchain(pDev, ps, &pDev->sent);
+ IRQ_GLOBAL_ENABLE(oldLevel);
+}
+
+
+static rtems_device_driver graes_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ struct graes_priv *pDev;
+ struct drvmgr_dev *dev;
+ rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *)arg;
+ unsigned int *data = ioarg->buffer;
+ int status;
+ struct graes_ioc_config *cfg;
+ struct graes_ioc_hw_status *hwregs;
+ IRQ_GLOBAL_PREPARE(oldLevel);
+ struct graes_list *chain;
+ struct graes_block *curr;
+ struct graes_ioc_hw *hwimpl;
+ struct graes_ioc_stats *stats;
+ struct graes_print_status *ps;
+ int num,ret;
+
+ FUNCDBG();
+
+ if ( drvmgr_get_dev(&graes_drv_info.general, minor, &dev) ) {
+ return RTEMS_INVALID_NUMBER;
+ }
+ pDev = (struct graes_priv *)dev->priv;
+
+ if (!ioarg)
+ return RTEMS_INVALID_NAME;
+
+ ioarg->ioctl_return = 0;
+ switch(ioarg->command) {
+ case GRAES_IOC_START:
+ if ( pDev->running ) {
+ return RTEMS_RESOURCE_IN_USE; /* EBUSY */
+ }
+ if ( (status=graes_start(pDev)) != RTEMS_SUCCESSFUL ){
+ return status;
+ }
+ /* Register interrupt handler and unmask IRQ at IRQ ctrl */
+ drvmgr_interrupt_register(dev, 0, "graes", graes_interrupt, pDev);
+
+ /* Read and write are now open... */
+ break;
+
+ case GRAES_IOC_STOP:
+ if ( !pDev->running ) {
+ return RTEMS_RESOURCE_IN_USE;
+ }
+
+ /* Disable interrupts */
+ drvmgr_interrupt_unregister(dev, 0, graes_interrupt, pDev);
+ graes_stop(pDev);
+ pDev->running = 0;
+ break;
+
+ case GRAES_IOC_ISSTARTED:
+ if ( !pDev->running ) {
+ return RTEMS_RESOURCE_IN_USE;
+ }
+ break;
+
+ case GRAES_IOC_SET_BLOCKING_MODE:
+ if ( (unsigned int)data > GRAES_BLKMODE_BLK ) {
+ return RTEMS_INVALID_NAME;
+ }
+ DBG("GRAES: Set blocking mode: %d\n",(unsigned int)data);
+ pDev->config.blocking = (unsigned int)data;
+ break;
+
+ case GRAES_IOC_SET_TIMEOUT:
+ DBG("GRAES: Timeout: %d\n",(unsigned int)data);
+ pDev->config.timeout = (rtems_interval)data;
+ break;
+
+ case GRAES_IOC_SET_CONFIG:
+ cfg = (struct graes_ioc_config *)data;
+ if ( !cfg ) {
+ return RTEMS_INVALID_NAME;
+ }
+
+ if ( pDev->running ) {
+ return RTEMS_RESOURCE_IN_USE;
+ }
+
+ pDev->config = *cfg;
+ break;
+
+ case GRAES_IOC_GET_STATS:
+ stats = (struct graes_ioc_stats *)data;
+ if ( !stats ) {
+ return RTEMS_INVALID_NAME;
+ }
+ memcpy(stats,&pDev->stats,sizeof(struct graes_ioc_stats));
+ break;
+
+ case GRAES_IOC_CLR_STATS:
+ memset(&pDev->stats,0,sizeof(struct graes_ioc_stats));
+ break;
+
+ case GRAES_IOC_GET_CONFIG:
+ cfg = (struct graes_ioc_config *)data;
+ if ( !cfg ) {
+ return RTEMS_INVALID_NAME;
+ }
+
+ *cfg = pDev->config;
+ break;
+
+ case GRAES_IOC_GET_HW_IMPL:
+ hwimpl = (struct graes_ioc_hw *)data;
+ if ( !hwimpl ) {
+ return RTEMS_INVALID_NAME;
+ }
+ *hwimpl = pDev->hw_avail;
+ break;
+
+ case GRAES_IOC_GET_HW_STATUS:
+ hwregs = (struct graes_ioc_hw_status *)data;
+ if ( !hwregs ) {
+ return RTEMS_INVALID_NAME;
+ }
+ /* We disable interrupt in order to get a snapshot of the registers */
+ IRQ_GLOBAL_DISABLE(oldLevel);
+ IRQ_GLOBAL_ENABLE(oldLevel);
+ break;
+
+ case GRAES_IOC_PRINT_STATUS:
+ ps = (struct graes_print_status *)data;
+ graes_printstatus(pDev, ps);
+ break;
+
+ /* Put a chain of frames at the back of the "Ready frames" queue. This
+ * triggers the driver to put frames from the Ready queue into unused
+ * available descriptors. (Ready -> Scheduled)
+ */
+
+ case GRAES_IOC_ENCRYPT:
+ if ( !pDev->running ){
+ return RTEMS_RESOURCE_IN_USE;
+ }
+ num=0;
+
+ /* Get pointer to frame chain wished be sent */
+ chain = (struct graes_list *)ioarg->buffer;
+ if ( !chain ){
+ /* No new frames to send ==> just trigger hardware
+ * to send previously made ready frames to be sent.
+ */
+ pDev->handling_transmission = 1;
+ goto trigger_transmission;
+ }
+ if ( !chain->tail || !chain->head ){
+ return RTEMS_INVALID_NAME;
+ }
+
+
+ /* Mark ready frames unsent by clearing GRAES_FLAGS_PROCESSED of all frames */
+
+ curr = chain->head;
+ while(curr != chain->tail){
+ curr->flags = curr->flags & ~(GRAES_FLAGS_PROCESSED|GRRM_FLAGS_ERR);
+ curr = curr->next;
+ num++;
+ }
+ curr->flags = curr->flags & ~(GRAES_FLAGS_PROCESSED|GRRM_FLAGS_ERR);
+ num++;
+
+ DBG("GRAES_ENCRYPT: head: 0x%x, tail: 0x%x num: %d\n",chain->head,chain->tail, num);
+
+ pDev->handling_transmission = 1;
+ /* 1. Put frames into ready queue
+ * (New Frames->READY)
+ */
+ if ( pDev->ready.head ){
+ /* Frames already on ready queue (no free descriptors previously) ==>
+ * Put frames at end of ready queue
+ */
+ pDev->ready.tail->next = chain->head;
+ pDev->ready.tail = chain->tail;
+ chain->tail->next = NULL;
+ }else{
+ /* All frames is put into the ready queue for later processing */
+ pDev->ready.head = chain->head;
+ pDev->ready.tail = chain->tail;
+ chain->tail->next = NULL;
+ }
+ pDev->ready_cnt += num; /* Added 'num' frames to ready queue */
+trigger_transmission:
+ /* 2. Free used descriptors and put the sent frame into the "Sent queue"
+ * (SCHEDULED->SENT)
+ */
+ num = graes_free_encrypted(pDev);
+ pDev->scheduled_cnt -= num;
+ pDev->sent_cnt += num;
+
+ /* 3. Use all available free descriptors there are frames for
+ * in the ready queue.
+ * (READY->SCHEDULED)
+ */
+ num = graes_schedule_ready(pDev,0);
+ pDev->ready_cnt -= num;
+ pDev->scheduled_cnt += num;
+
+ pDev->handling_transmission = 0;
+ break;
+
+ /* Take all available sent frames from the "Sent frames" queue.
+ * If no frames has been sent, the thread may get blocked if in blocking
+ * mode. The blocking mode is not available if driver is not in running mode.
+ *
+ * Note this ioctl may return success even if the driver is not in STARTED mode.
+ * This is because in case of a error (link error of similar) and the driver switch
+ * from START to STOP mode we must still be able to get our frames back.
+ *
+ * Note in case the driver fails to send a frame for some reason (link error),
+ * the sent flag is set to 0 indicating a failure.
+ *
+ */
+ case GRAES_IOC_RECLAIM:
+ /* Get pointer to were to place reaped chain */
+ chain = (struct graes_list *)ioarg->buffer;
+ if ( !chain ){
+ return RTEMS_INVALID_NAME;
+ }
+
+ /* Lock out interrupt handler */
+ pDev->handling_transmission = 1;
+
+ do {
+ /* Move sent frames from descriptors to Sent queue. This makes more
+ * descriptors (BDs) available.
+ */
+ num = graes_free_encrypted(pDev);
+ pDev->scheduled_cnt -= num;
+ pDev->sent_cnt += num;
+
+
+ if ( pDev->running ){
+ /* Fill descriptors with as many frames from the ready list
+ * as possible.
+ */
+ num = graes_schedule_ready(pDev,0);
+ pDev->ready_cnt -= num;
+ pDev->scheduled_cnt += num;
+ }
+
+ /* Are there any frames on the sent queue waiting to be
+ * reclaimed?
+ */
+
+ if ( !pDev->sent.head ){
+ /* No frames to reclaim - no frame in sent queue.
+ * Instead we block thread until frames have been sent
+ * if in blocking mode.
+ */
+ if ( pDev->running && pDev->config.blocking ){
+ ret = rtems_semaphore_obtain(pDev->sem_rx,RTEMS_WAIT,pDev->config.timeout);
+ if ( ret == RTEMS_TIMEOUT ) {
+ pDev->handling_transmission = 0;
+ return RTEMS_TIMEOUT;
+ } else if ( ret == RTEMS_SUCCESSFUL ) {
+ /* There might be frames available, go check */
+ continue;
+ } else {
+ /* any error (driver closed, internal error etc.) */
+ pDev->handling_transmission = 0;
+ return RTEMS_UNSATISFIED;
+ }
+
+ }else{
+ /* non-blocking mode, we quit */
+ chain->head = NULL;
+ chain->tail = NULL;
+ /* do not lock out interrupt handler any more */
+ pDev->handling_transmission = 0;
+ return RTEMS_TIMEOUT;
+ }
+ }else{
+ /* Take all sent framess from sent queue to userspace queue */
+ chain->head = pDev->sent.head;
+ chain->tail = pDev->sent.tail;
+ chain->tail->next = NULL; /* Just for sure */
+
+ /* Mark no Sent */
+ graes_list_clr(&pDev->sent);
+
+ DBG("TX_RECLAIM: head: 0x%x, tail: 0x%x\n",chain->head,chain->tail);
+ break;
+ }
+
+ }while(1);
+
+ /* do not lock out interrupt handler any more */
+ pDev->handling_transmission = 0;
+ break;
+
+ default:
+ return RTEMS_NOT_DEFINED;
+ }
+ return RTEMS_SUCCESSFUL;
+}
+
+static void graes_interrupt(int irq, void *arg)
+{
+ struct graes_priv *pDev = arg;
+ struct graes_regs *regs = pDev->regs;
+ unsigned int status;
+ int num;
+
+ /* Clear interrupt by reading it */
+ status = READ_REG(&regs->dma_status);
+
+
+ DBG("GRAES: irq 0x%x\n",(unsigned int)status);
+
+ /* Spurious Interrupt? */
+ if ( !pDev->running )
+ return;
+
+ if ( status )
+ regs->dma_status = status;
+
+
+ if ( 1 ){
+
+ if ( pDev->config.isr_desc_proc && !pDev->handling_transmission ) {
+ /* Free used descriptors and put the sent frame into the "Sent queue"
+ * (SCHEDULED->SENT)
+ */
+ num = graes_free_encrypted(pDev);
+ pDev->scheduled_cnt -= num;
+ pDev->sent_cnt += num;
+
+ /* Use all available free descriptors there are frames for
+ * in the ready queue.
+ * (READY->SCHEDULED)
+ */
+ num = graes_schedule_ready(pDev,1);
+ pDev->ready_cnt -= num;
+ pDev->scheduled_cnt += num;
+
+#if 0
+ if ( (pDev->config.blocking==GRAES_BLKMODE_COMPLETE) && pDev->timeout ){
+ /* Signal to thread only if enough data is available */
+ if ( pDev->wait_for_frames > graes_data_avail(pDev) ){
+ /* Not enough data available */
+ goto procceed_processing_interrupts;
+ }
+
+ /* Enough number of frames has been transmitted which means that
+ * the waiting thread should be woken up.
+ */
+ rtems_semaphore_release(pDev->sem_rx);
+ }
+#endif
+ }
+
+ if ( pDev->config.blocking == GRAES_BLKMODE_BLK ) {
+ /* Blocking mode */
+
+#if 0
+ /* Disable further Interrupts until handled by waiting task. */
+ regs->dma_ctrl = READ_REG(&regs->dma_ctrl) & ~GRAES_DMA_CTRL_IE;
+#endif
+
+ /* Signal Semaphore to wake waiting thread in ioctl(ENCRYPT|RECLAIM) */
+ rtems_semaphore_release(pDev->sem_rx);
+ }
+
+ }
+
+procceed_processing_interrupts:
+ ;
+}
+
+static rtems_device_driver graes_initialize(
+ rtems_device_major_number major,
+ rtems_device_minor_number unused,
+ void *arg
+ )
+{
+ /* Device Semaphore created with count = 1 */
+ if ( rtems_semaphore_create(rtems_build_name('G', 'R', 'P', 'R'),
+ 1,
+ RTEMS_FIFO|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &graes_dev_sem) != RTEMS_SUCCESSFUL ) {
+ return RTEMS_INTERNAL_ERROR;
+ }
+
+ return RTEMS_SUCCESSFUL;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/grpwrx/grpwrx.c b/c/src/lib/libbsp/sparc/shared/grpwrx/grpwrx.c
new file mode 100644
index 0000000000..2f29c148a4
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/grpwrx/grpwrx.c
@@ -0,0 +1,1317 @@
+/* GRPWRX Packetwire driver
+ *
+ * --------------------------------------------------------------------------
+ * -- This file is a part of GAISLER RESEARCH source code.
+ * -- Copyright (C) 2009, Aeroflex Gaisler AB - all rights reserved.
+ * --
+ * -- ANY USE OR REDISTRIBUTION IN PART OR IN WHOLE MUST BE HANDLED IN
+ * -- ACCORDANCE WITH THE GAISLER LICENSE AGREEMENT AND MUST BE APPROVED
+ * -- IN ADVANCE IN WRITING.
+ * --
+ * -- BY DEFAULT, DISTRIBUTION OR DISCLOSURE IS NOT PERMITTED.
+ * --------------------------------------------------------------------------
+ *
+ * 2010-06-29, Konrad Eisele <konrad@gaisler.com>
+ * Packetwire rx driver based on GRTM driver
+ *
+ * 2008-12-11, Daniel Hellstrom <daniel@gaisler.com>
+ * Converted to support driver manager
+ *
+ * 2007-04-17, Daniel Hellstrom <daniel@gaisler.com>
+ * New driver in sparc shared directory.
+ *
+ */
+
+
+#include <bsp.h>
+#include <rtems/libio.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+#include <malloc.h>
+#include <rtems/bspIo.h>
+
+#include <drvmgr/drvmgr.h>
+#include <ambapp.h>
+#include <drvmgr/ambapp_bus.h>
+#include <grpwrx.h>
+
+#ifndef IRQ_GLOBAL_PREPARE
+ #define IRQ_GLOBAL_PREPARE(level) rtems_interrupt_level level
+#endif
+
+#ifndef IRQ_GLOBAL_DISABLE
+ #define IRQ_GLOBAL_DISABLE(level) rtems_interrupt_disable(level)
+#endif
+
+#ifndef IRQ_GLOBAL_ENABLE
+ #define IRQ_GLOBAL_ENABLE(level) rtems_interrupt_enable(level)
+#endif
+
+/*
+#define DEBUG
+#define DEBUGFUNCS
+*/
+
+#include <debug_defs.h>
+
+/* GRPWRX register map */
+struct grpwrx_regs {
+ volatile unsigned int dma_ctrl; /* DMA Control Register (0x00) */
+ volatile unsigned int dma_status; /* DMA Status Register (0x04) */
+ volatile unsigned int dma_bd; /* DMA Descriptor Pointer Register (0x08) */
+ volatile unsigned int d0; /* DMA Length Register (0x08) */
+
+ volatile unsigned int d1; /* DMA Configuration Register (0x10) */
+ volatile unsigned int d2; /* GRPWRX Revision Register (0x14) */
+
+ int unused0[(0x80-0x18)/4];
+
+ volatile unsigned int ctrl; /* GRPWRX Control Register (0x80) */
+ volatile unsigned int status; /* GRPWRX Status Register (0x84) */
+ volatile unsigned int cfg; /* GRPWRX Configuration Register (0x88) */
+ volatile unsigned int phy; /* GRPWRX Physical Layer Register (0x8c) */
+};
+
+#define GRPWRX_BDAR_SIZE 0x4000
+#define GRPWRX_BDAR_ENTRIES (GRPWRX_BDAR_SIZE / sizeof(struct grpwrx_bd))
+
+/* DMA Control Register (0x00) */
+#define GRPWRX_DMA_CTRL_EN_BIT 0
+#define GRPWRX_DMA_CTRL_IE_BIT 1
+#define GRPWRX_DMA_CTRL_TXRST_BIT 2
+#define GRPWRX_DMA_CTRL_RST_BIT 3
+#define GRPWRX_DMA_CTRL_TFIE_BIT 4
+
+#define GRPWRX_DMA_CTRL_EN (1<<GRPWRX_DMA_CTRL_EN_BIT)
+#define GRPWRX_DMA_CTRL_IE (1<<GRPWRX_DMA_CTRL_IE_BIT)
+#define GRPWRX_DMA_CTRL_TXRST (1<<GRPWRX_DMA_CTRL_TXRST_BIT)
+#define GRPWRX_DMA_CTRL_RST (1<<GRPWRX_DMA_CTRL_RST_BIT)
+#define GRPWRX_DMA_CTRL_TFIE (1<<GRPWRX_DMA_CTRL_TFIE_BIT)
+
+/* DMA Status Register (0x04) */
+#define GRPWRX_DMA_STS_RE_BIT 0
+#define GRPWRX_DMA_STS_RI_BIT 1
+#define GRPWRX_DMA_STS_RA_BIT 2
+
+#define GRPWRX_DMA_STS_RE (1<<GRPWRX_DMA_STS_RE_BIT)
+#define GRPWRX_DMA_STS_RI (1<<GRPWRX_DMA_STS_RI_BIT)
+#define GRPWRX_DMA_STS_RA (1<<GRPWRX_DMA_STS_RA_BIT)
+#define GRPWRX_DMA_STS_ALL 0x7
+
+/* DMA Descriptor Pointer Register (0x0c) */
+#define GRPWRX_DMA_BD_INDEX_BIT 0
+#define GRPWRX_DMA_BD_BASE_BIT 10
+
+#define GRPWRX_DMA_BD_INDEX (0x3ff<<GRPWRX_DMA_BD_INDEX_BIT)
+#define GRPWRX_DMA_BD_BASE (0xfffffc<<GRPWRX_DMA_BD_BASE_BIT)
+
+/* GRPWRX Control Register (0x80) */
+#define GRPWRX_CTRL_EN_BIT 0
+#define GRPWRX_CTRL_RST_BIT 2
+
+#define GRPWRX_CTRL_EN (1<<GRPWRX_CTRL_EN_BIT)
+#define GRPWRX_CTRL_RST (1<<GRPWRX_CTRL_RST_BIT)
+
+
+/* TM Physical Layer Register (0x90) */
+#define GRPWRX_PHY_CLKRISE_BIT 4
+#define GRPWRX_PHY_VALIDPOS_BIT 5
+#define GRPWRX_PHY_READYPOS_BIT 6
+#define GRPWRX_PHY_BUSYPOS_BIT 7
+
+#define GRPWRX_PHY_CLKRISE (1 << GRPWRX_PHY_CLKRISE_BIT)
+#define GRPWRX_PHY_VALIDPOS (1 << GRPWRX_PHY_VALIDPOS_BIT)
+#define GRPWRX_PHY_READYPOS (1 << GRPWRX_PHY_READYPOS_BIT)
+#define GRPWRX_PHY_BUSYPOS (1 << GRPWRX_PHY_BUSYPOS_BIT)
+
+
+/* TM FSH/Insert Zone Registers (0xc0..0xcc) */
+#define GRPWRX_FSH_DATA_BIT 0
+
+#define GRPWRX_FSH_DATA 0xffffffff
+
+/* GRPWRX transmit descriptor (GRPWRX_BDAR_SIZE Alignment need) */
+struct grpwrx_bd {
+ volatile unsigned int ctrl;
+ unsigned int address;
+ unsigned int dummy1;
+ unsigned int dummy2;
+};
+
+#define GRPWRX_BD_EN_BIT 0
+#define GRPWRX_BD_IE_BIT 1
+#define GRPWRX_BD_WR_BIT 2
+
+#define GRPWRX_BD_EN (1<<GRPWRX_BD_EN_BIT)
+#define GRPWRX_BD_WR (1<<GRPWRX_BD_WR_BIT)
+#define GRPWRX_BD_IE (1<<GRPWRX_BD_IE_BIT)
+
+
+/* Load register */
+
+#define READ_REG(address) (*(volatile unsigned int *)address)
+
+/* Driver functions */
+static rtems_device_driver grpwrx_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver grpwrx_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver grpwrx_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver grpwrx_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver grpwrx_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver grpwrx_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+
+#define GRPWRX_DRIVER_TABLE_ENTRY { grpwrx_initialize, grpwrx_open, grpwrx_close, grpwrx_read, grpwrx_write, grpwrx_ioctl }
+
+static rtems_driver_address_table grpwrx_driver = GRPWRX_DRIVER_TABLE_ENTRY;
+
+/* Structure that connects BD with SoftWare Frame */
+struct grpwrx_ring {
+ struct grpwrx_ring *next;
+ struct grpwrx_bd *bd;
+ struct grpwrx_packet *frm;
+};
+
+struct grpwrx_priv {
+ struct drvmgr_dev *dev; /* Driver manager device */
+ char devName[32]; /* Device Name */
+ struct grpwrx_regs *regs;
+ int irq;
+ int minor;
+
+ int open;
+ int running;
+
+ struct grpwrx_bd *bds;
+ void *_bds;
+
+ /* Interrupt generation */
+ int enable_cnt_curr;/* Down counter, when 0 the interrupt bit is set for next descriptor */
+ volatile int handling_transmission; /* Tells ISR if user are active changing descriptors/queues */
+
+ struct grpwrx_ring *_ring; /* Root of ring */
+ struct grpwrx_ring *ring; /* Next ring to use for new frames to be transmitted */
+ struct grpwrx_ring *ring_end; /* Oldest activated ring used */
+
+ /* Collections of frames Ready to sent/ Scheduled for transmission/Sent
+ * frames waiting for the user to reclaim
+ */
+ struct grpwrx_list ready; /* Frames Waiting for free BDs */
+ struct grpwrx_list scheduled; /* Frames in BDs beeing transmitted */
+ struct grpwrx_list sent; /* Sent Frames waiting for user to reclaim and reuse */
+
+ /* Number of frames in the lists */
+ int ready_cnt; /* Number of ready frames */
+ int scheduled_cnt; /* Number of scheduled frames */
+ int sent_cnt; /* Number of sent frames */
+
+ struct grpwrx_ioc_hw hw_avail; /* Hardware support available */
+ struct grpwrx_ioc_config config;
+ struct grpwrx_ioc_stats stats;
+
+ rtems_id sem_rx;
+};
+
+/* Prototypes */
+static void *grpwrx_memalign(unsigned int boundary, unsigned int length, void *realbuf);
+static void grpwrx_hw_reset(struct grpwrx_priv *pDev);
+static void grpwrx_interrupt(int irq, void *arg);
+
+/* Common Global Variables */
+static rtems_id grpwrx_dev_sem;
+static int grpwrx_driver_io_registered = 0;
+static rtems_device_major_number grpwrx_driver_io_major = 0;
+
+/******************* Driver manager interface ***********************/
+
+/* Driver prototypes */
+static int grpwrx_register_io(rtems_device_major_number *m);
+static int grpwrx_device_init(struct grpwrx_priv *pDev);
+
+static int grpwrx_init2(struct drvmgr_dev *dev);
+static int grpwrx_init3(struct drvmgr_dev *dev);
+
+static struct drvmgr_drv_ops grpwrx_ops =
+{
+ {NULL, grpwrx_init2, grpwrx_init3, NULL},
+ NULL,
+ NULL
+};
+
+static struct amba_dev_id grpwrx_ids[] =
+{
+ {VENDOR_GAISLER, GAISLER_PW2APB},
+ {0, 0} /* Mark end of table */
+};
+
+static struct amba_drv_info grpwrx_drv_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_AMBAPP_GAISLER_GRPWRX_ID,/* Driver ID */
+ "GRPWRX_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */
+ &grpwrx_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ 0,
+ },
+ &grpwrx_ids[0]
+};
+
+void grpwrx_register_drv (void)
+{
+ DBG("Registering GRPWRX driver\n");
+ drvmgr_drv_register(&grpwrx_drv_info.general);
+}
+
+static int grpwrx_init2(struct drvmgr_dev *dev)
+{
+ struct grpwrx_priv *priv;
+
+ DBG("GRPWRX[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
+ priv = dev->priv = malloc(sizeof(struct grpwrx_priv));
+ if ( !priv )
+ return DRVMGR_NOMEM;
+ memset(priv, 0, sizeof(*priv));
+ priv->dev = dev;
+
+ /* This core will not find other cores, so we wait for init2() */
+
+ return DRVMGR_OK;
+}
+
+static int grpwrx_init3(struct drvmgr_dev *dev)
+{
+ struct grpwrx_priv *priv;
+ char prefix[32];
+ rtems_status_code status;
+
+ priv = dev->priv;
+
+ /* Do initialization */
+
+ if ( grpwrx_driver_io_registered == 0) {
+ /* Register the I/O driver only once for all cores */
+ if ( grpwrx_register_io(&grpwrx_driver_io_major) ) {
+ /* Failed to register I/O driver */
+ dev->priv = NULL;
+ return DRVMGR_FAIL;
+ }
+
+ grpwrx_driver_io_registered = 1;
+ }
+
+ /* I/O system registered and initialized
+ * Now we take care of device initialization.
+ */
+ if ( grpwrx_device_init(priv) ) {
+ return DRVMGR_FAIL;
+ }
+
+ /* Get Filesystem name prefix */
+ prefix[0] = '\0';
+ if ( drvmgr_get_dev_prefix(dev, prefix) ) {
+ /* Failed to get prefix, make sure of a unique FS name
+ * by using the driver minor.
+ */
+ sprintf(priv->devName, "/dev/grpwrx%d", dev->minor_drv);
+ } else {
+ /* Got special prefix, this means we have a bus prefix
+ * And we should use our "bus minor"
+ */
+ sprintf(priv->devName, "/dev/%sgrpwrx%d", prefix, dev->minor_bus);
+ }
+
+ DBG("GRPWRX: add dev %s\n",priv->devName);
+
+ /* Register Device */
+ status = rtems_io_register_name(priv->devName, grpwrx_driver_io_major, dev->minor_drv);
+ if (status != RTEMS_SUCCESSFUL) {
+ return status;
+ }
+
+ return DRVMGR_OK;
+}
+
+/******************* Driver Implementation ***********************/
+
+static int grpwrx_register_io(rtems_device_major_number *m)
+{
+ rtems_status_code r;
+
+ if ((r = rtems_io_register_driver(0, &grpwrx_driver, m)) == RTEMS_SUCCESSFUL) {
+ DBG("GRPWRX driver successfully registered, major: %d\n", *m);
+ } else {
+ switch(r) {
+ case RTEMS_TOO_MANY:
+ printk("GRPWRX rtems_io_register_driver failed: RTEMS_TOO_MANY\n");
+ return -1;
+ case RTEMS_INVALID_NUMBER:
+ printk("GRPWRX rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n");
+ return -1;
+ case RTEMS_RESOURCE_IN_USE:
+ printk("GRPWRX rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n");
+ return -1;
+ default:
+ printk("GRPWRX rtems_io_register_driver failed\n");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int grpwrx_device_init(struct grpwrx_priv *pDev)
+{
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
+ union drvmgr_key_value *value;
+
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)pDev->dev->businfo;
+ if ( ambadev == NULL ) {
+ return -1;
+ }
+ pnpinfo = &ambadev->info;
+ pDev->irq = pnpinfo->irq;
+ pDev->regs = (struct grpwrx_regs *)pnpinfo->apb_slv->start;
+ pDev->minor = pDev->dev->minor_drv;
+ pDev->open = 0;
+ pDev->running = 0;
+
+ /* Create Binary RX Semaphore with count = 0 */
+ if ( rtems_semaphore_create(rtems_build_name('G', 'P', 'R', '0' + pDev->minor),
+ 0,
+ RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|\
+ RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &pDev->sem_rx) != RTEMS_SUCCESSFUL ) {
+ return -1;
+ }
+
+ /* Allocate Memory for Buffer Descriptor Table, or let user provide a
+ * custom address.
+ */
+ value = drvmgr_dev_key_get(pDev->dev, "bdTabAdr", KEY_TYPE_POINTER);
+ if ( value ) {
+ pDev->bds = (struct grpwrx_bd *)value->ptr;
+ pDev->_bds = (void *)value->ptr;
+ } else {
+ pDev->bds = (struct grpwrx_bd *)grpwrx_memalign(GRPWRX_BDAR_SIZE, GRPWRX_BDAR_SIZE, &pDev->_bds);
+ }
+ if ( !pDev->bds ) {
+ DBG("GRPWRX: Failed to allocate descriptor table\n");
+ return -1;
+ }
+ memset(pDev->bds, 0, GRPWRX_BDAR_SIZE);
+
+ pDev->_ring = malloc(sizeof(struct grpwrx_ring) * GRPWRX_BDAR_ENTRIES);
+ if ( !pDev->_ring ) {
+ return -1;
+ }
+
+ /* Reset Hardware before attaching IRQ handler */
+ grpwrx_hw_reset(pDev);
+
+ return 0;
+}
+
+
+static inline void grpwrx_list_clr(struct grpwrx_list *list)
+{
+ list->head = NULL;
+ list->tail = NULL;
+}
+
+static void grpwrx_hw_reset(struct grpwrx_priv *pDev)
+{
+ /* Reset Core */
+ pDev->regs->ctrl = GRPWRX_CTRL_RST;
+ pDev->regs->dma_status = GRPWRX_DMA_STS_ALL;
+}
+
+static void grpwrx_hw_get_implementation(struct grpwrx_priv *pDev, struct grpwrx_ioc_hw *hwcfg)
+{
+ unsigned int cfg = READ_REG(&pDev->regs->cfg), phy = READ_REG(&pDev->regs->phy);
+
+ hwcfg->fifo_size= (cfg >> 8) & 0xffff;
+ hwcfg->mode= (cfg >> 0) & 0x1;
+
+ hwcfg->clkdivide= (phy >> 20) & 0xfff;
+}
+
+#warning Extra: Implement proper default calculation from hardware configuration
+static void grpwrx_hw_get_default_modes(struct grpwrx_ioc_config *cfg, struct grpwrx_ioc_hw *hwcfg)
+{
+ cfg->framing = 1;
+
+ /* Physical */
+ cfg->phy_clkrise = 1; /* sample at falling for rx */
+ cfg->phy_validpos = 1;
+ cfg->phy_readypos = 1;
+ cfg->phy_busypos = 0;
+
+ /* Interrupt options */
+ cfg->blocking = 0; /* non-blocking mode is default */
+ cfg->enable_cnt = 1; /* generate interrupt every 16 descriptor */
+ cfg->isr_desc_proc = 1; /* Let interrupt handler do descriptor processing */
+ cfg->timeout = RTEMS_NO_TIMEOUT;
+
+}
+
+static void *grpwrx_memalign(unsigned int boundary, unsigned int length, void *realbuf)
+{
+ *(int *)realbuf = (int)malloc(length+boundary);
+ DBG("GRPWRX: Alloced %d (0x%x) bytes, requested: %d\n",length+boundary,length+boundary,length);
+ return (void *)(((*(unsigned int *)realbuf)+boundary) & ~(boundary-1));
+}
+
+static int grpwrx_hw_set_config(struct grpwrx_priv *pDev, struct grpwrx_ioc_config *cfg, struct grpwrx_ioc_hw *hwcfg)
+{
+ struct grpwrx_regs *regs = pDev->regs;
+ unsigned int tmp;
+
+ /* Physical layer options */
+ tmp = ((cfg->phy_clkrise << GRPWRX_PHY_CLKRISE_BIT) & GRPWRX_PHY_CLKRISE) |
+ ((cfg->phy_validpos << GRPWRX_PHY_VALIDPOS_BIT) & GRPWRX_PHY_VALIDPOS) |
+ ((cfg->phy_readypos << GRPWRX_PHY_READYPOS_BIT) & GRPWRX_PHY_READYPOS) |
+ ((cfg->phy_busypos << GRPWRX_PHY_BUSYPOS_BIT) & GRPWRX_PHY_BUSYPOS);
+ regs->phy = tmp;
+
+ regs->cfg = cfg->framing ? 1 : 0;
+
+ return 0;
+}
+
+static int grpwrx_start(struct grpwrx_priv *pDev)
+{
+ struct grpwrx_regs *regs = pDev->regs;
+ int i;
+ struct grpwrx_ioc_config *cfg = &pDev->config;
+ volatile unsigned int *txrdy_reg;
+ unsigned int txrdy_mask, transaddr;
+
+ /* Clear Descriptors */
+ memset(pDev->bds,0,GRPWRX_BDAR_SIZE);
+
+ /* Clear stats */
+ memset(&pDev->stats,0,sizeof(struct grpwrx_ioc_stats));
+
+ /* Init Descriptor Ring */
+ memset(pDev->_ring,0,sizeof(struct grpwrx_ring)*GRPWRX_BDAR_ENTRIES);
+ for(i=0;i<(GRPWRX_BDAR_ENTRIES-1);i++){
+ pDev->_ring[i].next = &pDev->_ring[i+1];
+ pDev->_ring[i].bd = &pDev->bds[i];
+ pDev->_ring[i].frm = NULL;
+ }
+ pDev->_ring[(GRPWRX_BDAR_ENTRIES-1)].next = &pDev->_ring[0];
+ pDev->_ring[(GRPWRX_BDAR_ENTRIES-1)].bd = &pDev->bds[(GRPWRX_BDAR_ENTRIES-1)];
+ pDev->_ring[(GRPWRX_BDAR_ENTRIES-1)].frm = NULL;
+
+ pDev->ring = &pDev->_ring[0];
+ pDev->ring_end = &pDev->_ring[0];
+
+ /* Clear Scheduled, Ready and Sent list */
+ grpwrx_list_clr(&pDev->ready);
+ grpwrx_list_clr(&pDev->scheduled);
+ grpwrx_list_clr(&pDev->sent);
+
+ /* Software init */
+ pDev->handling_transmission = 0;
+
+ /* Reset the transmitter */
+ regs->dma_ctrl = GRPWRX_DMA_CTRL_TXRST;
+ regs->dma_ctrl = 0; /* Leave Reset */
+
+ /* Clear old interrupts */
+ regs->dma_status = GRPWRX_DMA_STS_ALL;
+
+ /* Set Descriptor Pointer Base register to point to first descriptor */
+ drvmgr_translate(pDev->dev, 0, 0, (void *)pDev->bds, (void **)&transaddr);
+ regs->dma_bd = transaddr;
+
+ DBG("GRPWRX: set bd to 0x%08x\n",transaddr);
+
+ /*regs->dma_bd = (unsigned int)pDev->bds;*/
+
+ /* Set hardware options as defined by config */
+ if ( grpwrx_hw_set_config(pDev, cfg, &pDev->hw_avail) ) {
+ return RTEMS_IO_ERROR;
+ }
+
+ /* Enable GRPWRX Transmitter */
+ regs->ctrl = GRPWRX_CTRL_EN;
+
+ DBG("GRPWRX: reset time %d\n",i);
+
+ /* Mark running before enabling the DMA transmitter */
+ pDev->running = 1;
+
+ /* Enable interrupts (Error and DMA TX) */
+ regs->dma_ctrl = GRPWRX_DMA_CTRL_IE;
+
+ DBG("GRPWRX: STARTED\n");
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static void grpwrx_stop(struct grpwrx_priv *pDev)
+{
+ struct grpwrx_regs *regs = pDev->regs;
+
+ /* Disable the transmitter & Interrupts */
+ regs->dma_ctrl = 0;
+
+ /* Clear any pending interrupt */
+ regs->dma_status = GRPWRX_DMA_STS_ALL;
+
+ DBG("GRPWRX: STOPPED\n");
+
+ /* Flush semaphore in case a thread is stuck waiting for TX Interrupts */
+ rtems_semaphore_flush(pDev->sem_rx);
+}
+
+static rtems_device_driver grpwrx_open(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg)
+{
+ struct grpwrx_priv *pDev;
+ struct drvmgr_dev *dev;
+
+ FUNCDBG();
+
+ if ( drvmgr_get_dev(&grpwrx_drv_info.general, minor, &dev) ) {
+ DBG("Wrong minor %d\n", minor);
+ return RTEMS_INVALID_NUMBER;
+ }
+ pDev = (struct grpwrx_priv *)dev->priv;
+
+ /* Wait until we get semaphore */
+ if ( rtems_semaphore_obtain(grpwrx_dev_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT) != RTEMS_SUCCESSFUL ){
+ return RTEMS_INTERNAL_ERROR;
+ }
+
+ /* Is device in use? */
+ if ( pDev->open ){
+ rtems_semaphore_release(grpwrx_dev_sem);
+ return RTEMS_RESOURCE_IN_USE;
+ }
+
+ /* Mark device taken */
+ pDev->open = 1;
+
+ rtems_semaphore_release(grpwrx_dev_sem);
+
+ DBG("grpwrx_open: OPENED minor %d (pDev: 0x%x)\n",pDev->minor,(unsigned int)pDev);
+ /* Set defaults */
+ pDev->config.timeout = RTEMS_NO_TIMEOUT; /* no timeout (wait forever) */
+ pDev->config.blocking = 0; /* polling mode */
+
+ pDev->running = 0; /* not in running mode yet */
+
+ memset(&pDev->config,0,sizeof(pDev->config));
+
+ /* The core has been reset when we execute here, so it is possible
+ * to read out what HW is implemented from core.
+ */
+ grpwrx_hw_get_implementation(pDev, &pDev->hw_avail);
+
+ /* Get default modes */
+ grpwrx_hw_get_default_modes(&pDev->config,&pDev->hw_avail);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver grpwrx_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ struct grpwrx_priv *pDev;
+ struct drvmgr_dev *dev;
+
+ FUNCDBG();
+
+ if ( drvmgr_get_dev(&grpwrx_drv_info.general, minor, &dev) ) {
+ return RTEMS_INVALID_NUMBER;
+ }
+ pDev = (struct grpwrx_priv *)dev->priv;
+
+ if ( pDev->running ){
+ grpwrx_stop(pDev);
+ pDev->running = 0;
+ }
+
+ /* Reset core */
+ grpwrx_hw_reset(pDev);
+
+ /* Clear descriptor area just for sure */
+ memset(pDev->bds, 0, GRPWRX_BDAR_SIZE);
+
+ /* Mark not open */
+ pDev->open = 0;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver grpwrx_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ FUNCDBG();
+ return RTEMS_NOT_IMPLEMENTED;
+}
+
+static rtems_device_driver grpwrx_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ FUNCDBG();
+ return RTEMS_NOT_IMPLEMENTED;
+}
+
+/* Scans the desciptor table for scheduled frames that has been sent,
+ * and moves these frames from the head of the scheduled queue to the
+ * tail of the sent queue.
+ *
+ * Also, for all frames the status is updated.
+ *
+ * Return Value
+ * Number of frames freed.
+ */
+static int grpwrx_free_received(struct grpwrx_priv *pDev)
+{
+ struct grpwrx_ring *curr;
+ struct grpwrx_packet *last_frm, *first_frm;
+ int freed_frame_cnt=0;
+ unsigned int ctrl;
+
+ curr = pDev->ring_end;
+
+ /* Step into TX ring to find sent frames */
+ if ( !curr->frm ){
+ /* No scheduled frames, abort */
+ return 0;
+ }
+
+ /* There has been messages scheduled ==> scheduled messages may have been
+ * transmitted and needs to be collected.
+ */
+
+ first_frm = curr->frm;
+
+ /* Loop until first enabled unsent frame is found.
+ * A unused descriptor is indicated by an unassigned frm field
+ */
+ while ( curr->frm && !((ctrl=READ_REG(&curr->bd->ctrl)) & GRPWRX_BD_EN) ){
+ /* Handle one sent Frame */
+
+ DBG("fini bd: 0x%x @ 0x%x\n",(int)ctrl, curr->bd);
+
+ /* Remember last handled frame so that insertion/removal from
+ * frames lists go fast.
+ */
+ last_frm = curr->frm;
+
+ /* 1. Set flags to indicate error(s) and other information */
+ last_frm->flags |= GRPWRX_FLAGS_RECEIVED; /* Mark sent */
+
+ /* Update Stats */
+ pDev->stats.packets_received++;
+
+ curr->frm = NULL; /* Mark unused */
+
+ /* Increment */
+ curr = curr->next;
+ freed_frame_cnt++;
+ }
+
+ /* 1. Remove all handled frames from scheduled queue
+ * 2. Put all handled frames into sent queue
+ */
+ if ( freed_frame_cnt > 0 ){
+
+ /* Save TX ring posistion */
+ pDev->ring_end = curr;
+
+ /* Remove all sent frames from scheduled list */
+ if ( pDev->scheduled.tail == last_frm ){
+ /* All scheduled frames sent... */
+ pDev->scheduled.head = NULL;
+ pDev->scheduled.tail = NULL;
+ }else{
+ pDev->scheduled.head = last_frm->next;
+ }
+ last_frm->next = NULL;
+
+ /* Put all sent frames into "Sent queue" for user to
+ * collect, later on.
+ */
+ if ( !pDev->sent.head ){
+ /* Sent queue empty */
+ pDev->sent.head = first_frm;
+ pDev->sent.tail = last_frm;
+ }else{
+ pDev->sent.tail->next = first_frm;
+ pDev->sent.tail = last_frm;
+ }
+ }
+ return freed_frame_cnt;
+}
+
+
+/* Moves as many frames in the ready queue (as there are free descriptors for)
+ * to the scheduled queue. The free descriptors are then assigned one frame
+ * each and enabled for transmission.
+ *
+ * Return Value
+ * Returns number of frames moved from ready to scheduled queue
+ */
+static int grpwrx_schedule_ready(struct grpwrx_priv *pDev, int ints_off)
+{
+ int cnt;
+ unsigned int ctrl, dmactrl, oldLevel, transaddr;
+ struct grpwrx_ring *curr_bd;
+ struct grpwrx_packet *curr_frm, *last_frm;
+
+ if ( !pDev->ready.head ){
+ return 0;
+ }
+
+ cnt=0;
+ curr_frm = pDev->ready.head;
+ curr_bd = pDev->ring;
+ while( !curr_bd->frm ){
+ /* Assign frame to descriptor */
+ curr_bd->frm = curr_frm;
+
+ /* Prepare descriptor address. Three cases:
+ * - GRPWRX core on same bus as CPU ==> no translation (Address used by CPU = address used by GRPWRX)
+ * - GRPWRX core on remote bus, and payload address given as used by CPU ==> Translation needed
+ * - GRPWRX core on remote bus, and payload address given as used by GRPWRX ==> no translation [ USER does custom translation]
+ */
+ if ( curr_frm->flags & (GRPWRX_FLAGS_TRANSLATE|GRPWRX_FLAGS_TRANSLATE_AND_REMEMBER) ) {
+ /* Do translation */
+ drvmgr_translate(pDev->dev, 0, 0, (void *)curr_frm->payload, (void **)&transaddr);
+ curr_bd->bd->address = transaddr;
+ if ( curr_frm->flags & GRPWRX_FLAGS_TRANSLATE_AND_REMEMBER ) {
+ if ( curr_frm->payload != curr_bd->bd->address ) {
+ /* Translation needed */
+ curr_frm->flags &= ~GRPWRX_FLAGS_TRANSLATE_AND_REMEMBER;
+ curr_frm->flags |= GRPWRX_FLAGS_TRANSLATE;
+ } else {
+ /* No Trnaslation needed */
+ curr_frm->flags &= ~(GRPWRX_FLAGS_TRANSLATE|GRPWRX_FLAGS_TRANSLATE_AND_REMEMBER);
+ }
+ }
+ } else {
+ /* Custom translation or no translation needed */
+ transaddr = curr_bd->bd->address = (unsigned int)curr_frm->payload;
+ }
+
+ ctrl = GRPWRX_BD_EN;
+ if ( curr_bd->next == pDev->_ring ){
+ ctrl |= GRPWRX_BD_WR; /* Wrap around */
+ }
+ /* Apply user options/flags */
+ ctrl |= (curr_frm->flags & GRPWRX_FLAGS_MASK);
+ ctrl |= (curr_frm->length & 0xffff) << 16;
+
+ /* Is this Frame going to be an interrupt Frame? */
+ if ( (--pDev->enable_cnt_curr) <= 0 ){
+ if ( pDev->config.enable_cnt == 0 ){
+ pDev->enable_cnt_curr = 0x3fffffff;
+ }else{
+ pDev->enable_cnt_curr = pDev->config.enable_cnt;
+ ctrl |= GRPWRX_BD_IE;
+ }
+ }
+
+ /* Enable descriptor */
+ curr_bd->bd->ctrl = ctrl;
+
+ DBG("add bd: [0x%08x,0x%08x] @ 0x%08x\n",(int)ctrl, transaddr,curr_bd->bd);
+
+ last_frm = curr_frm;
+ curr_bd = curr_bd->next;
+ cnt++;
+
+ /* Get Next Frame from Ready Queue */
+ if ( curr_frm == pDev->ready.tail ){
+ /* Handled all in ready queue. */
+ curr_frm = NULL;
+ break;
+ }
+ curr_frm = curr_frm->next;
+ }
+
+ /* Has frames have been scheduled? */
+ if ( cnt > 0 ){
+ /* Make last frame mark end of chain, probably pointless... */
+ last_frm->next = NULL;
+
+ /* Insert scheduled packets into scheduled queue */
+ if ( !pDev->scheduled.head ){
+ /* empty scheduled queue */
+ pDev->scheduled.head = pDev->ready.head;
+ pDev->scheduled.tail = last_frm;
+ }else{
+ pDev->scheduled.tail->next = pDev->ready.head;
+ pDev->scheduled.tail = last_frm;
+ }
+
+ /* Remove scheduled packets from ready queue */
+ pDev->ready.head = curr_frm;
+ if ( !curr_frm ){
+ pDev->ready.tail = NULL;
+ }
+
+ /* Update TX ring posistion */
+ pDev->ring = curr_bd;
+ if ( !ints_off ) {
+ IRQ_GLOBAL_DISABLE(oldLevel);
+ }
+
+ /* Make hardware aware of the newly enabled descriptors */
+ dmactrl = READ_REG(&pDev->regs->dma_ctrl);
+ dmactrl &= ~(GRPWRX_DMA_CTRL_TXRST | GRPWRX_DMA_CTRL_RST);
+ dmactrl |= GRPWRX_DMA_CTRL_EN;
+ pDev->regs->dma_ctrl = dmactrl;
+ pDev->regs->ctrl = GRPWRX_CTRL_EN;
+
+ if ( !ints_off ) {
+ IRQ_GLOBAL_ENABLE(oldLevel);
+ }
+ }
+ return cnt;
+}
+
+static void grpwrx_printchain(struct grpwrx_priv *pDev, struct grpwrx_print_status *ps, struct grpwrx_list *chain)
+{
+ struct grpwrx_packet *curr;
+ curr = chain->head;
+ while(curr){
+ printk(" 0x%08x: [0x%08x@0x%08x:0x%08x]\n",curr,curr->length,curr->payload,curr->flags);
+ if (curr == chain->tail)
+ break;
+ curr = curr->next;
+ }
+
+}
+
+static void grpwrx_printstatus(struct grpwrx_priv *pDev, struct grpwrx_print_status *ps)
+{
+ int oldLevel;
+
+ IRQ_GLOBAL_DISABLE(oldLevel);
+ printk("pack_rec: %d\n",(int)pDev->stats.packets_received);
+
+ printk("ready_cnt : %d\n",pDev->ready_cnt);
+ printk("scheduled_cnt: %d\n",pDev->scheduled_cnt);
+ printk("sent_cnt : %d\n",pDev->sent_cnt);
+
+ printk(" ready:\n");
+ grpwrx_printchain(pDev, ps, &pDev->ready);
+ printk(" scheduled:\n");
+ grpwrx_printchain(pDev, ps, &pDev->scheduled);
+ printk(" sent:\n");
+ grpwrx_printchain(pDev, ps, &pDev->sent);
+ IRQ_GLOBAL_ENABLE(oldLevel);
+}
+
+
+static rtems_device_driver grpwrx_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ struct grpwrx_priv *pDev;
+ struct drvmgr_dev *dev;
+ rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *)arg;
+ unsigned int *data = ioarg->buffer;
+ int status;
+ struct grpwrx_ioc_config *cfg;
+ struct grpwrx_ioc_hw_status *hwregs;
+ IRQ_GLOBAL_PREPARE(oldLevel);
+ struct grpwrx_list *chain;
+ struct grpwrx_packet *curr;
+ struct grpwrx_ioc_hw *hwimpl;
+ struct grpwrx_ioc_stats *stats;
+ struct grpwrx_print_status *ps;
+ int num,ret;
+
+ FUNCDBG();
+
+ if ( drvmgr_get_dev(&grpwrx_drv_info.general, minor, &dev) ) {
+ return RTEMS_INVALID_NUMBER;
+ }
+ pDev = (struct grpwrx_priv *)dev->priv;
+
+ if (!ioarg)
+ return RTEMS_INVALID_NAME;
+
+ ioarg->ioctl_return = 0;
+ switch(ioarg->command) {
+ case GRPWRX_IOC_START:
+ if ( pDev->running ) {
+ return RTEMS_RESOURCE_IN_USE; /* EBUSY */
+ }
+ if ( (status=grpwrx_start(pDev)) != RTEMS_SUCCESSFUL ){
+ return status;
+ }
+ /* Register interrupt handler & Enable interrupt */
+ drvmgr_interrupt_register(dev, 0, "grpwrx", grpwrx_interrupt, pDev);
+
+ /* Read and write are now open... */
+ break;
+
+ case GRPWRX_IOC_STOP:
+ if ( !pDev->running ) {
+ return RTEMS_RESOURCE_IN_USE;
+ }
+
+ /* Disable interrupts */
+ drvmgr_interrupt_unregister(dev, 0, grpwrx_interrupt, pDev);
+ grpwrx_stop(pDev);
+ pDev->running = 0;
+ break;
+
+ case GRPWRX_IOC_ISSTARTED:
+ if ( !pDev->running ) {
+ return RTEMS_RESOURCE_IN_USE;
+ }
+ break;
+
+ case GRPWRX_IOC_SET_BLOCKING_MODE:
+ if ( (unsigned int)data > GRPWRX_BLKMODE_BLK ) {
+ return RTEMS_INVALID_NAME;
+ }
+ DBG("GRPWRX: Set blocking mode: %d\n",(unsigned int)data);
+ pDev->config.blocking = (unsigned int)data;
+ break;
+
+ case GRPWRX_IOC_SET_TIMEOUT:
+ DBG("GRPWRX: Timeout: %d\n",(unsigned int)data);
+ pDev->config.timeout = (rtems_interval)data;
+ break;
+
+ case GRPWRX_IOC_SET_CONFIG:
+ cfg = (struct grpwrx_ioc_config *)data;
+ if ( !cfg ) {
+ return RTEMS_INVALID_NAME;
+ }
+
+ if ( pDev->running ) {
+ return RTEMS_RESOURCE_IN_USE;
+ }
+
+ pDev->config = *cfg;
+ break;
+
+ case GRPWRX_IOC_GET_STATS:
+ stats = (struct grpwrx_ioc_stats *)data;
+ if ( !stats ) {
+ return RTEMS_INVALID_NAME;
+ }
+ memcpy(stats,&pDev->stats,sizeof(struct grpwrx_ioc_stats));
+ break;
+
+ case GRPWRX_IOC_CLR_STATS:
+ memset(&pDev->stats,0,sizeof(struct grpwrx_ioc_stats));
+ break;
+
+ case GRPWRX_IOC_GET_CONFIG:
+ cfg = (struct grpwrx_ioc_config *)data;
+ if ( !cfg ) {
+ return RTEMS_INVALID_NAME;
+ }
+
+ *cfg = pDev->config;
+ break;
+
+ case GRPWRX_IOC_GET_HW_IMPL:
+ hwimpl = (struct grpwrx_ioc_hw *)data;
+ if ( !hwimpl ) {
+ return RTEMS_INVALID_NAME;
+ }
+ *hwimpl = pDev->hw_avail;
+ break;
+
+ case GRPWRX_IOC_GET_HW_STATUS:
+ hwregs = (struct grpwrx_ioc_hw_status *)data;
+ if ( !hwregs ) {
+ return RTEMS_INVALID_NAME;
+ }
+ /* We disable interrupt in order to get a snapshot of the registers */
+ IRQ_GLOBAL_DISABLE(oldLevel);
+ IRQ_GLOBAL_ENABLE(oldLevel);
+ break;
+
+ case GRPWRX_IOC_PRINT_STATUS:
+ ps = (struct grpwrx_print_status *)data;
+ grpwrx_printstatus(pDev, ps);
+ break;
+
+ /* Put a chain of frames at the back of the "Ready frames" queue. This
+ * triggers the driver to put frames from the Ready queue into unused
+ * available descriptors. (Ready -> Scheduled)
+ */
+
+ case GRPWRX_IOC_RECV:
+ if ( !pDev->running ){
+ return RTEMS_RESOURCE_IN_USE;
+ }
+ num=0;
+
+ /* Get pointer to frame chain wished be sent */
+ chain = (struct grpwrx_list *)ioarg->buffer;
+ if ( !chain ){
+ /* No new frames to send ==> just trigger hardware
+ * to send previously made ready frames to be sent.
+ */
+ pDev->handling_transmission = 1;
+ goto trigger_transmission;
+ }
+ if ( !chain->tail || !chain->head ){
+ return RTEMS_INVALID_NAME;
+ }
+
+
+ /* Mark ready frames unsent by clearing GRPWRX_FLAGS_RECEIVED of all frames */
+
+ curr = chain->head;
+ while(curr != chain->tail){
+ curr->flags = curr->flags & ~(GRPWRX_FLAGS_RECEIVED|GRRM_FLAGS_ERR);
+ curr = curr->next;
+ num++;
+ }
+ curr->flags = curr->flags & ~(GRPWRX_FLAGS_RECEIVED|GRRM_FLAGS_ERR);
+ num++;
+
+ DBG("GRPWRX_RECV: head: 0x%x, tail: 0x%x num: %d\n",chain->head,chain->tail, num);
+
+ pDev->handling_transmission = 1;
+ /* 1. Put frames into ready queue
+ * (New Frames->READY)
+ */
+ if ( pDev->ready.head ){
+ /* Frames already on ready queue (no free descriptors previously) ==>
+ * Put frames at end of ready queue
+ */
+ pDev->ready.tail->next = chain->head;
+ pDev->ready.tail = chain->tail;
+ chain->tail->next = NULL;
+ }else{
+ /* All frames is put into the ready queue for later processing */
+ pDev->ready.head = chain->head;
+ pDev->ready.tail = chain->tail;
+ chain->tail->next = NULL;
+ }
+ pDev->ready_cnt += num; /* Added 'num' frames to ready queue */
+trigger_transmission:
+ /* 2. Free used descriptors and put the sent frame into the "Sent queue"
+ * (SCHEDULED->SENT)
+ */
+ num = grpwrx_free_received(pDev);
+ pDev->scheduled_cnt -= num;
+ pDev->sent_cnt += num;
+
+ /* 3. Use all available free descriptors there are frames for
+ * in the ready queue.
+ * (READY->SCHEDULED)
+ */
+ num = grpwrx_schedule_ready(pDev,0);
+ pDev->ready_cnt -= num;
+ pDev->scheduled_cnt += num;
+
+ pDev->handling_transmission = 0;
+ break;
+
+ /* Take all available sent frames from the "Sent frames" queue.
+ * If no frames has been sent, the thread may get blocked if in blocking
+ * mode. The blocking mode is not available if driver is not in running mode.
+ *
+ * Note this ioctl may return success even if the driver is not in STARTED mode.
+ * This is because in case of a error (link error of similar) and the driver switch
+ * from START to STOP mode we must still be able to get our frames back.
+ *
+ * Note in case the driver fails to send a frame for some reason (link error),
+ * the sent flag is set to 0 indicating a failure.
+ *
+ */
+ case GRPWRX_IOC_RECLAIM:
+ /* Get pointer to were to place reaped chain */
+ chain = (struct grpwrx_list *)ioarg->buffer;
+ if ( !chain ){
+ return RTEMS_INVALID_NAME;
+ }
+
+ /* Lock out interrupt handler */
+ pDev->handling_transmission = 1;
+
+ do {
+ /* Move sent frames from descriptors to Sent queue. This makes more
+ * descriptors (BDs) available.
+ */
+ num = grpwrx_free_received(pDev);
+ pDev->scheduled_cnt -= num;
+ pDev->sent_cnt += num;
+
+
+ if ( pDev->running ){
+ /* Fill descriptors with as many frames from the ready list
+ * as possible.
+ */
+ num = grpwrx_schedule_ready(pDev,0);
+ pDev->ready_cnt -= num;
+ pDev->scheduled_cnt += num;
+ }
+
+ /* Are there any frames on the sent queue waiting to be
+ * reclaimed?
+ */
+
+ if ( !pDev->sent.head ){
+ /* No frames to reclaim - no frame in sent queue.
+ * Instead we block thread until frames have been sent
+ * if in blocking mode.
+ */
+ if ( pDev->running && pDev->config.blocking ){
+ ret = rtems_semaphore_obtain(pDev->sem_rx,RTEMS_WAIT,pDev->config.timeout);
+ if ( ret == RTEMS_TIMEOUT ) {
+ pDev->handling_transmission = 0;
+ return RTEMS_TIMEOUT;
+ } else if ( ret == RTEMS_SUCCESSFUL ) {
+ /* There might be frames available, go check */
+ continue;
+ } else {
+ /* any error (driver closed, internal error etc.) */
+ pDev->handling_transmission = 0;
+ return RTEMS_UNSATISFIED;
+ }
+
+ }else{
+ /* non-blocking mode, we quit */
+ chain->head = NULL;
+ chain->tail = NULL;
+ /* do not lock out interrupt handler any more */
+ pDev->handling_transmission = 0;
+ return RTEMS_TIMEOUT;
+ }
+ }else{
+ /* Take all sent framess from sent queue to userspace queue */
+ chain->head = pDev->sent.head;
+ chain->tail = pDev->sent.tail;
+ chain->tail->next = NULL; /* Just for sure */
+
+ /* Mark no Sent */
+ grpwrx_list_clr(&pDev->sent);
+
+ DBG("TX_RECLAIM: head: 0x%x, tail: 0x%x\n",chain->head,chain->tail);
+ break;
+ }
+
+ }while(1);
+
+ /* do not lock out interrupt handler any more */
+ pDev->handling_transmission = 0;
+ break;
+
+ default:
+ return RTEMS_NOT_DEFINED;
+ }
+ return RTEMS_SUCCESSFUL;
+}
+
+static void grpwrx_interrupt(int irq, void *arg)
+{
+ struct grpwrx_priv *pDev = arg;
+ struct grpwrx_regs *regs = pDev->regs;
+ unsigned int status;
+ int num;
+
+ /* Clear interrupt by reading it */
+ status = READ_REG(&regs->dma_status);
+
+ DBG("irq 0x%x\n",status);
+
+ /* Spurious Interrupt? */
+ if ( !pDev->running )
+ return;
+
+ if ( status )
+ regs->dma_status = status;
+
+
+ if ( status & GRPWRX_DMA_STS_RA ){
+ pDev->stats.err_ahb++;
+ }
+
+ if ( status & GRPWRX_DMA_STS_RE ){
+ pDev->stats.err_tx++;
+ }
+
+ if ( status & GRPWRX_DMA_STS_RI ){
+
+
+ if ( pDev->config.isr_desc_proc && !pDev->handling_transmission ) {
+ /* Free used descriptors and put the sent frame into the "Sent queue"
+ * (SCHEDULED->SENT)
+ */
+ num = grpwrx_free_received(pDev);
+ pDev->scheduled_cnt -= num;
+ pDev->sent_cnt += num;
+
+ /* Use all available free descriptors there are frames for
+ * in the ready queue.
+ * (READY->SCHEDULED)
+ */
+ num = grpwrx_schedule_ready(pDev,1);
+ pDev->ready_cnt -= num;
+ pDev->scheduled_cnt += num;
+
+#if 0
+ if ( (pDev->config.blocking==GRPWRX_BLKMODE_COMPLETE) && pDev->timeout ){
+ /* Signal to thread only if enough data is available */
+ if ( pDev->wait_for_frames > grpwrx_data_avail(pDev) ){
+ /* Not enough data available */
+ goto procceed_processing_interrupts;
+ }
+
+ /* Enough number of frames has been transmitted which means that
+ * the waiting thread should be woken up.
+ */
+ rtems_semaphore_release(pDev->sem_rx);
+ }
+#endif
+ }
+
+ if ( pDev->config.blocking == GRPWRX_BLKMODE_BLK ) {
+ /* Blocking mode */
+
+#if 0
+ /* Disable further Interrupts until handled by waiting task. */
+ regs->dma_ctrl = READ_REG(&regs->dma_ctrl) & ~GRPWRX_DMA_CTRL_IE;
+#endif
+
+ /* Signal Semaphore to wake waiting thread in ioctl(SEND|RECLAIM) */
+ rtems_semaphore_release(pDev->sem_rx);
+ }
+
+ }
+
+procceed_processing_interrupts:
+ ;
+}
+
+static rtems_device_driver grpwrx_initialize(
+ rtems_device_major_number major,
+ rtems_device_minor_number unused,
+ void *arg
+ )
+{
+ /* Device Semaphore created with count = 1 */
+ if ( rtems_semaphore_create(rtems_build_name('G', 'R', 'P', 'R'),
+ 1,
+ RTEMS_FIFO|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &grpwrx_dev_sem) != RTEMS_SUCCESSFUL ) {
+ return RTEMS_INTERNAL_ERROR;
+ }
+
+ return RTEMS_SUCCESSFUL;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/i2c/i2cmst.c b/c/src/lib/libbsp/sparc/shared/i2c/i2cmst.c
index fb6a573763..b600225737 100644
--- a/c/src/lib/libbsp/sparc/shared/i2c/i2cmst.c
+++ b/c/src/lib/libbsp/sparc/shared/i2c/i2cmst.c
@@ -10,25 +10,45 @@
*
* This file contains the driver and initialization code
*
+ * 2009-03-24: Added support for multiple I2C Cores, converted
+ * to driver manager. (daniel@gaisler.com)
* 2007-09-27: First version of driver (jan@gaisler.com)
*/
#include <bsp.h>
-#include <i2cmst.h>
+#include <stdlib.h>
+#include <stdio.h>
#include <ambapp.h>
#include <rtems/libi2c.h>
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+
+#include <i2cmst.h>
/* Enable debug printks? */
-/* #define DEBUG */
+/*#define DEBUG*/
-/* Default to 40 MHz system clock? */
-/*
- #ifndef SYS_FREQ_kHZ
- #define SYS_FREQ_kHZ 40000
- #endif
-*/
+#ifdef DEBUG
+ #define DBG(args...) printk(args)
+#else
+ #define DBG(args...)
+#endif
+/* The OC I2C core will perform a write after a start unless the RD bit
+ in the command register has been set. Since the rtems framework has
+ a send_start function we buffer that command and use it when the first
+ data is written. The START is buffered in the sendstart member below */
+typedef struct gr_i2cmst_prv {
+ rtems_libi2c_bus_t i2clib_desc;
+ struct drvmgr_dev *dev;
+ gr_i2cmst_regs_t *reg_ptr;
+ unsigned int sysfreq; /* System clock frequency in kHz */
+ int minor;
+ unsigned char sendstart; /* START events are buffered here */
+ /* rtems_irq_number irq_number; */
+ /* rtems_id irq_sema_id; */
+} gr_i2cmst_prv_t;
/* Calculates the scaler value for 100 kHz operation */
static int gr_i2cmst_calc_scaler(int sysfreq)
@@ -41,12 +61,12 @@ static int gr_i2cmst_wait(gr_i2cmst_prv_t *prv_ptr, uint8_t expected_sts)
{
uint32_t tout = 0;
int current_sts;
-#if defined(DEBUG)
- printk("(gr_i2cmst_wait called...");
-#endif
+
+ DBG("(gr_i2cmst_wait called...");
do {
if (tout++ > 1000000) {
+ DBG("gr_i2cmst_wait: TIMEOUT\n");
return RTEMS_TIMEOUT;
}
} while (prv_ptr->reg_ptr->cmdsts & GRI2C_STS_TIP);
@@ -56,32 +76,31 @@ static int gr_i2cmst_wait(gr_i2cmst_prv_t *prv_ptr, uint8_t expected_sts)
if (current_sts != expected_sts) {
#if defined(DEBUG)
if (prv_ptr->reg_ptr->cmdsts & GRI2C_STS_RXACK) {
- printk("Transfer NAKed..");
+ DBG("Transfer NAKed..");
}
if (prv_ptr->reg_ptr->cmdsts & GRI2C_STS_AL) {
- printk("arbitration lost..");
+ DBG("arbitration lost..");
}
if (prv_ptr->reg_ptr->cmdsts & GRI2C_STS_TIP) {
- printk("transfer still in progress, huh?..");
+ DBG("transfer still in progress, huh?..");
}
- printk("exited with IO error..)");
+ DBG("exited with IO error..)");
#endif
+ DBG("gr_i2cmst_wait: IO-ERROR\n");
return RTEMS_IO_ERROR;
}
-#if defined(DEBUG)
- printk("exited...)");
-#endif
+ DBG("exited...)");
+
return RTEMS_SUCCESSFUL;
}
/* Initialize hardware core */
static rtems_status_code gr_i2cmst_init(rtems_libi2c_bus_t *bushdl)
{
- gr_i2cmst_prv_t *prv_ptr = &(((gr_i2cmst_desc_t *)(bushdl))->prv);
-#if defined(DEBUG)
- printk("gr_i2cmst_init called...");
-#endif
+ gr_i2cmst_prv_t *prv_ptr = (gr_i2cmst_prv_t *)bushdl;
+
+ DBG("gr_i2cmst_init called...");
/* Disable core before changing prescale register */
prv_ptr->reg_ptr->ctrl = 0;
@@ -95,54 +114,48 @@ static rtems_status_code gr_i2cmst_init(rtems_libi2c_bus_t *bushdl)
/* Clear possible START condition */
prv_ptr->sendstart = 0;
-#if defined(DEBUG)
- printk("exited\n");
-#endif
+ DBG("exited\n");
+
return RTEMS_SUCCESSFUL;
}
static rtems_status_code gr_i2cmst_send_start(rtems_libi2c_bus_t *bushdl)
{
- gr_i2cmst_prv_t *prv_ptr = &(((gr_i2cmst_desc_t *)(bushdl))->prv);
-#if defined(DEBUG)
- printk("gr_i2cmst_send_start called...");
-#endif
+ gr_i2cmst_prv_t *prv_ptr = (gr_i2cmst_prv_t *)bushdl;
+
+ DBG("gr_i2cmst_send_start called...");
/* The OC I2C core does not work with stand alone START events,
instead the event is buffered */
prv_ptr->sendstart = GRI2C_CMD_STA;
-#if defined(DEBUG)
- printk("exited\n");
-#endif
+ DBG("exited\n");
+
return RTEMS_SUCCESSFUL;
}
static rtems_status_code gr_i2cmst_send_stop(rtems_libi2c_bus_t *bushdl)
{
- gr_i2cmst_prv_t *prv_ptr = &(((gr_i2cmst_desc_t *)(bushdl))->prv);
-#if defined(DEBUG)
- printk("gr_i2cmst_send_stop called...");
-#endif
+ gr_i2cmst_prv_t *prv_ptr = (gr_i2cmst_prv_t *)bushdl;
+
+ DBG("gr_i2cmst_send_stop called...");
prv_ptr->reg_ptr->cmdsts = GRI2C_CMD_STO;
-#if defined(DEBUG)
- printk("exited\n");
-#endif
+ DBG("exited\n");
+
return RTEMS_SUCCESSFUL;
}
static rtems_status_code gr_i2cmst_send_addr(rtems_libi2c_bus_t *bushdl,
uint32_t addr, int rw)
{
- gr_i2cmst_prv_t *prv_ptr = &(((gr_i2cmst_desc_t *)(bushdl))->prv);
+ gr_i2cmst_prv_t *prv_ptr = (gr_i2cmst_prv_t *)bushdl;
uint8_t addr_byte;
rtems_status_code rc;
-#if defined(DEBUG)
- printk("gr_i2cmst_send_addr called, addr = 0x%x, rw = %d...",
+
+ DBG("gr_i2cmst_send_addr called, addr = 0x%x, rw = %d...",
addr, rw);
-#endif
/* Check if long address is needed */
if (addr > 0x7f) {
@@ -155,9 +168,9 @@ static rtems_status_code gr_i2cmst_send_addr(rtems_libi2c_bus_t *bushdl,
/* Wait for transfer to complete */
rc = gr_i2cmst_wait(prv_ptr, GRI2C_STATUS_IDLE);
if (rc != RTEMS_SUCCESSFUL) {
-#if defined(DEBUG)
- printk("exited with error\n");
-#endif
+
+ DBG("exited with error\n");
+
return -rc;
}
}
@@ -175,16 +188,12 @@ static rtems_status_code gr_i2cmst_send_addr(rtems_libi2c_bus_t *bushdl,
/* Wait for transfer to complete */
rc = gr_i2cmst_wait(prv_ptr, GRI2C_STATUS_IDLE);
if (rc != RTEMS_SUCCESSFUL) {
-#if defined(DEBUG)
- printk("exited with error\n");
-#endif
+ DBG("exited with error\n");
return -rc;
}
- }
+ }
-#if defined(DEBUG)
- printk("exited\n");
-#endif
+ DBG("exited\n");
return rc;
}
@@ -192,13 +201,12 @@ static rtems_status_code gr_i2cmst_send_addr(rtems_libi2c_bus_t *bushdl,
static int gr_i2cmst_read_bytes(rtems_libi2c_bus_t *bushdl,
unsigned char *bytes, int nbytes)
{
- gr_i2cmst_prv_t *prv_ptr = &(((gr_i2cmst_desc_t *)(bushdl))->prv);
+ gr_i2cmst_prv_t *prv_ptr = (gr_i2cmst_prv_t *)bushdl;
unsigned char *buf = bytes;
rtems_status_code rc;
unsigned char expected_sts = GRI2C_STATUS_IDLE;
-#if defined(DEBUG)
- printk("gr_i2cmst_read_bytes called, nbytes = %d...", nbytes);
-#endif
+
+ DBG("gr_i2cmst_read_bytes called, nbytes = %d...", nbytes);
while (nbytes-- > 0) {
if (nbytes == 0) {
@@ -213,34 +221,30 @@ static int gr_i2cmst_read_bytes(rtems_libi2c_bus_t *bushdl,
/* Wait until end of transfer */
rc = gr_i2cmst_wait(prv_ptr, expected_sts);
if (rc != RTEMS_SUCCESSFUL) {
+ DBG("exited with error\n");
return -rc;
-#if defined(DEBUG)
- printk("exited with error\n");
-#endif
}
*buf++ = prv_ptr->reg_ptr->tdrd;
}
-#if defined(DEBUG)
- printk("exited\n");
-#endif
+ DBG("exited\n");
+
return buf - bytes;
}
static int gr_i2cmst_write_bytes(rtems_libi2c_bus_t *bushdl,
unsigned char *bytes, int nbytes)
{
- gr_i2cmst_prv_t *prv_ptr = &(((gr_i2cmst_desc_t *)(bushdl))->prv);
+ gr_i2cmst_prv_t *prv_ptr = (gr_i2cmst_prv_t *)bushdl;
unsigned char *buf = bytes;
rtems_status_code rc;
-#if defined(DEBUG)
- printk("gr_i2cmst_write_bytes called, nbytes = %d...", nbytes);
-#endif
+
+ DBG("gr_i2cmst_write_bytes called, nbytes = %d...", nbytes);
while (nbytes-- > 0) {
-#if defined(DEBUG)
- printk("writing byte 0x%02X...", *buf);
-#endif
+
+ DBG("writing byte 0x%02X...", *buf);
+
prv_ptr->reg_ptr->tdrd = *buf++;
prv_ptr->reg_ptr->cmdsts = GRI2C_CMD_WR | prv_ptr->sendstart;
prv_ptr->sendstart = 0;
@@ -249,16 +253,13 @@ static int gr_i2cmst_write_bytes(rtems_libi2c_bus_t *bushdl,
rc = gr_i2cmst_wait(prv_ptr, GRI2C_STATUS_IDLE);
if (rc != RTEMS_SUCCESSFUL) {
-#if defined(DEBUG)
- printk("exited with error\n");
-#endif
+ DBG("exited with error\n");
return -rc;
}
}
-#if defined(DEBUG)
- printk("exited\n");
-#endif
+ DBG("exited\n");
+
return buf - bytes;
}
@@ -271,88 +272,148 @@ static rtems_libi2c_bus_ops_t gr_i2cmst_ops = {
write_bytes: gr_i2cmst_write_bytes,
};
+/* Get Hardware and disable it */
+int i2cmst_device_init(gr_i2cmst_prv_t *priv)
+{
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
-static gr_i2cmst_desc_t gr_i2cmst_desc = {
- { /* rtems_libi2c_bus_t */
- ops : &gr_i2cmst_ops,
- size : sizeof(gr_i2cmst_ops),
- },
- { /* gr_i2cmst_prv_t, private data */
- reg_ptr : NULL,
- sysfreq : 40000,
- }
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)priv->dev->businfo;
+ if ( ambadev == NULL ) {
+ return -1;
+ }
+ pnpinfo = &ambadev->info;
+ priv->reg_ptr = (gr_i2cmst_regs_t *)pnpinfo->apb_slv->start;
+
+ /* Disable core */
+ priv->reg_ptr->ctrl = 0;
+
+ priv->i2clib_desc.ops = &gr_i2cmst_ops;
+ priv->i2clib_desc.size = sizeof(gr_i2cmst_ops);
+ return 0;
+}
+
+/******************* Driver Manager Part ***********************/
+
+int i2cmst_init2(struct drvmgr_dev *dev);
+int i2cmst_init3(struct drvmgr_dev *dev);
+
+struct drvmgr_drv_ops i2cmst_ops =
+{
+ .init = {NULL, i2cmst_init2, i2cmst_init3, NULL},
+ .remove = NULL,
+ .info = NULL
};
-/* Scans for I2CMST core and initalizes i2c library */
-rtems_status_code leon_register_i2c(amba_confarea_type *abus)
+struct amba_dev_id i2cmst_ids[] =
{
-#if defined(DEBUG)
- printk("leon_register_i2c called...");
-#endif
+ {VENDOR_GAISLER, GAISLER_I2CMST},
+ {0, 0} /* Mark end of table */
+};
+
+struct amba_drv_info i2cmst_drv_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_AMBAPP_GAISLER_I2CMST_ID, /* Driver ID */
+ "I2CMST_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */
+ &i2cmst_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ 0,
+ },
+ &i2cmst_ids[0]
+};
+
+void i2cmst_register_drv (void)
+{
+ DBG("Registering I2CMST driver\n");
+ drvmgr_drv_register(&i2cmst_drv_info.general);
+}
- int rc;
- int device_found = 0;
- amba_apb_device apbi2cmst;
+/* The I2CMST Driver is informed about a new hardware device */
+int i2cmst_init2(struct drvmgr_dev *dev)
+{
+ gr_i2cmst_prv_t *priv;
- /* Scan AMBA bus for I2CMST core */
- device_found = amba_find_apbslv(abus, VENDOR_GAISLER, GAISLER_I2CMST,
- &apbi2cmst);
+ DBG("I2CMST[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
- if (device_found == 1) {
+ priv = dev->priv = malloc(sizeof(gr_i2cmst_prv_t));
+ if ( !priv )
+ return DRVMGR_NOMEM;
+ memset(priv, 0, sizeof(*priv));
+ priv->dev = dev;
- /* Initialize i2c library */
- rc = rtems_libi2c_initialize();
- if (rc < 0) {
-#if defined(DEBUG)
- printk("rtems_libi2x_initialize failed, exiting...\n");
-#endif
- return rc;
- }
+ /* This core will not find other cores, so we wait for init2() */
- gr_i2cmst_desc.prv.reg_ptr = (gr_i2cmst_regs_t *)apbi2cmst.start;
+ return DRVMGR_OK;
+}
- /* Detect system frequency, same as in apbuart_initialize */
-#ifndef SYS_FREQ_kHZ
-#if defined(LEON3)
- /* LEON3: find timer address via AMBA Plug&Play info */
- {
- amba_apb_device gptimer;
- LEON3_Timer_Regs_Map *tregs;
-
- if (amba_find_apbslv(abus,VENDOR_GAISLER,
- GAISLER_GPTIMER,&gptimer) == 1 ) {
- tregs = (LEON3_Timer_Regs_Map *)gptimer.start;
- gr_i2cmst_desc.prv.sysfreq = (tregs->scaler_reload+1)*1000;
- } else {
- gr_i2cmst_desc.prv.sysfreq = 40000; /* Default to 40MHz */
- }
+/* Init stage 2 */
+int i2cmst_init3(struct drvmgr_dev *dev)
+{
+ gr_i2cmst_prv_t *priv;
+ char prefix[32];
+ char devName[32];
+ int rc;
+
+ priv = (gr_i2cmst_prv_t *)dev->priv;
+
+ /* Do initialization */
+
+ /* Initialize i2c library */
+ rc = rtems_libi2c_initialize();
+ if (rc != 0) {
+ DBG("I2CMST: rtems_libi2c_initialize failed, exiting...\n");
+ free(dev->priv);
+ dev->priv = NULL;
+ return DRVMGR_FAIL;
}
-#elif defined(LEON2)
- /* LEON2: use hardcoded address to get to timer */
- {
- LEON_Register_Map *regs = (LEON_Register_Map *)0x80000000;
- gr_i2cmst_desc.prv.sysfreq = (regs->Scaler_Reload+1)*1000;
+
+ /* I/O system registered and initialized
+ * Now we take care of device initialization.
+ */
+
+ /* Get frequency */
+ if ( drvmgr_freq_get(dev, DEV_APB_SLV, &priv->sysfreq) ) {
+ return DRVMGR_FAIL;
}
-#else
-#error CPU not supported for I2CMST driver */
-#endif
-#else
- /* Use hardcoded frequency */
- gr_i2cmst_desc.prv.sysfreq = SYS_FREQ_kHZ;
-#endif
+ priv->sysfreq = priv->sysfreq / 1000; /* Convert to kHz */
- rc = rtems_libi2c_register_bus("/dev/i2c1", &gr_i2cmst_desc.bus_desc);
- if (rc < 0) {
-#if defined(DEBUG)
- printk("rtems_libi2c_register_bus failed, exiting..\n");
-#endif
- return -rc;
- }
- }
+ if ( i2cmst_device_init(priv) ) {
+ free(dev->priv);
+ dev->priv = NULL;
+ return DRVMGR_FAIL;
+ }
-#if defined(DEBUG)
- printk("exited\n");
-#endif
- return 0;
+ /* Get Filesystem name prefix */
+ prefix[0] = '\0';
+ if ( drvmgr_get_dev_prefix(dev, prefix) ) {
+ /* Failed to get prefix, make sure of a unique FS name
+ * by using the driver minor.
+ */
+ sprintf(devName, "/dev/i2c%d", dev->minor_drv+1);
+ } else {
+ /* Got special prefix, this means we have a bus prefix
+ * And we should use our "bus minor"
+ */
+ sprintf(devName, "/dev/%si2c%d", prefix, dev->minor_bus+1);
+ }
+
+ /* Register Bus for this Device */
+ rc = rtems_libi2c_register_bus(devName, &priv->i2clib_desc);
+ if (rc < 0) {
+ DBG("I2CMST: rtems_libi2c_register_bus(%s) failed, exiting..\n", devName);
+ free(dev->priv);
+ dev->priv = NULL;
+ return DRVMGR_FAIL;
+ }
+ priv->minor = rc;
+
+ return DRVMGR_OK;
}
diff --git a/c/src/lib/libbsp/sparc/shared/include/ahbstat.h b/c/src/lib/libbsp/sparc/shared/include/ahbstat.h
new file mode 100644
index 0000000000..28244a6588
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/ahbstat.h
@@ -0,0 +1,74 @@
+/*
+ * AHBSTAT driver interface
+ *
+ * COPYRIGHT (c) 2011
+ * Gaisler Research
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#ifndef __AHBSTAT_H__
+#define __AHBSTAT_H__
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* AHBSTAT Registers layout */
+struct ahbstat_regs {
+ volatile uint32_t status;
+ volatile uint32_t failing;
+};
+
+/* AHB fail interrupt callback to user. This function is declared weak so that
+ * the user can define a function pointer variable containing the address
+ * responsible for handling errors
+ *
+ * minor Index of AHBSTAT hardware
+ * regs Register address of AHBSTAT
+ * status AHBSTAT status register at IRQ
+ * failing_address AHBSTAT Failing address register at IRQ
+ *
+ * * User return
+ * 0: print error onto terminal with printk and reenable AHBSTAT
+ * 1: just re-enable AHBSTAT
+ * 2: just print error
+ * 3: do nothing, let user do custom handling
+ */
+extern int (*ahbstat_error)(
+ int minor,
+ struct ahbstat_regs *regs,
+ uint32_t status,
+ uint32_t failing_address);
+
+/* Get Last received AHB Error
+ *
+ * \param minor Index used to indentify a specific AHBSTAT core
+ * \param status Status register at time of error IRQ was recevied
+ * \param address Failing address register at time of error IRQ
+ *
+ * Return
+ * 0: No error received
+ * 1: Error Received, last status and address stored into argument pointers
+ * -1: No such AHBSTAT device
+ */
+extern int ahbstat_last_error(int minor, uint32_t *status, uint32_t *address);
+
+/* Get AHBSTAT registers address from minor. Can also be used to check if
+ * AHBSTAT hardware is present.
+ *
+ * Return
+ * NULL returned if no such device
+ * non-zero Address to AHBSTAT register
+ */
+extern struct ahbstat_regs *ahbstat_get_regs(int minor);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/include/ambapp.h b/c/src/lib/libbsp/sparc/shared/include/ambapp.h
index e2b557d85e..6d9611a489 100644
--- a/c/src/lib/libbsp/sparc/shared/include/ambapp.h
+++ b/c/src/lib/libbsp/sparc/shared/include/ambapp.h
@@ -1,10 +1,8 @@
/*
- * AMBA Plag & Play Bus Driver Macros for LEON2
+ * AMBA Plug & Play routines
*
- * Macros used for AMBA Plug & Play bus scanning
- *
- * COPYRIGHT (c) 2007.
- * Gaisler Research
+ * COPYRIGHT (c) 2009.
+ * Aeroflex Gaisler.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
@@ -16,265 +14,355 @@
#ifndef __AMBAPP_H__
#define __AMBAPP_H__
+/* Include VENDOR and DEVICE definitions */
+#include <ambapp_ids.h>
+
#ifdef __cplusplus
extern "C" {
#endif
-#define AMBA_CONF_AREA 0xff000
-#define AMBA_AHB_SLAVE_CONF_AREA (1 << 11)
-
-#define AMBA_AHB_CONF_WORDS 8
-#define AMBA_APB_CONF_WORDS 2
-#define AMBA_AHB_MASTERS 16
-#define AMBA_AHB_SLAVES 16
-#define AMBA_APB_SLAVES 16
-#define AMBA_APBUARTS 8
-
-/* Vendor codes */
-#define VENDOR_GAISLER 1
-#define VENDOR_PENDER 2
-#define VENDOR_ESA 4
-#define VENDOR_OPENCORES 8
-
-/* Gaisler Research device id's */
-#define GAISLER_LEON3 0x03
-#define GAISLER_LEON3DSU 0x04
-#define GAISLER_ETHAHB 0x05
-#define GAISLER_APBMST 0x06
-#define GAISLER_AHBUART 0x07
-#define GAISLER_SRCTRL 0x08
-#define GAISLER_SDCTRL 0x09
-#define GAISLER_APBUART 0x0C
-#define GAISLER_IRQMP 0x0D
-#define GAISLER_AHBRAM 0x0E
-#define GAISLER_GPTIMER 0x11
-#define GAISLER_PCITRG 0x12
-#define GAISLER_PCISBRG 0x13
-#define GAISLER_PCIFBRG 0x14
-#define GAISLER_PCITRACE 0x15
-#define GAISLER_DMACTRL 0x16
-#define GAISLER_OCCAN 0x19
-#define GAISLER_PIOPORT 0x1A
-#define GAISLER_ETHMAC 0x1D
-#define GAISLER_SPACEWIRE 0x1f
-#define GAISLER_AHB2AHB 0x20
-#define GAISLER_I2CMST 0x28
-#define GAISLER_GRSPW2 0x29
-#define GAISLER_GRCAN 0x34
-#define GAISLER_GRHCAN 0x3d
-#define GAISLER_GRFIFO 0x35
-#define GAISLER_GRADCDAC 0x36
-#define GAISLER_GRPULSE 0x37
-#define GAISLER_GRTIMER 0x38
-#define GAISLER_FTAHBRAM 0x50
-#define GAISLER_FTMCTRL 0x54
-#define GAISLER_BRM 0x72
-
-
-/* European Space Agency device id's */
-#define ESA_LEON2 0x2
-#define ESA_MCTRL 0xF
-#define ESA_SPW2 0x12
-
-/* Opencores device id's */
-#define OPENCORES_PCIBR 0x4
-#define OPENCORES_ETHMAC 0x5
+/* Max supported AHB buses */
+#define AHB_BUS_MAX 6
+
+struct ambapp_dev;
+struct ambapp_core;
+struct ambapp_apb_info;
+struct ambapp_ahb_info;
+
+struct ambapp_dev {
+ struct ambapp_dev *next; /* Next */
+ struct ambapp_dev *prev; /* Previous Device. If (this ==
+ * rev->child) prev is bus bridge */
+ struct ambapp_dev *children; /* Points to first device on sub-bus */
+ void *owner; /* Owner of this AMBA device */
+ unsigned char dev_type; /* AHB MST, AHB SLV or APB SLV*/
+ unsigned char vendor; /* Vendor ID */
+ unsigned short device; /* Device ID */
+ int devinfo[0]; /* Device info (APB/AHB dep. on type) */
+};
-/*
- *
- * Macros for manipulating Configuration registers
- *
- */
-#define amba_get_confword(tab, index, word) (*((tab).addr[(index)]+(word)))
+#define AMBAPP_FLAG_FFACT_DIR 0x100 /* Frequency factor direction, 0=down, 1=up */
+#define AMBAPP_FLAG_FFACT 0x0f0 /* Frequency factor against top bus */
+#define AMBAPP_FLAG_MBUS 0x00c
+#define AMBAPP_FLAG_SBUS 0x003
+
+/* Get APB or AHB information from a AMBA device */
+#define DEV_TO_APB(adev) ((struct ambapp_apb_info *)((adev)->devinfo))
+#define DEV_TO_AHB(adev) ((struct ambapp_ahb_info *)((adev)->devinfo))
+#define DEV_TO_COMMON(adev) ((struct ambapp_common_info *)((adev)->devinfo))
+/* Convert address of ambapp_apb_info/ambapp_ahb_info into ambapp_dev */
+#define APB_TO_DEV(apb_info) ((struct ambapp_dev *)(unsigned int(apb_info) - \
+ offsetof(struct ambapp_dev, devinfo)))
+#define AHB_TO_DEV(ahb_info) ((struct ambapp_dev *)(unsigned int(ahb_info) - \
+ offsetof(struct ambapp_dev, devinfo)))
+
+struct ambapp_common_info {
+ unsigned char irq;
+ unsigned char ver;
+ unsigned char ahbidx; /* AHB Bus Index */
+};
-#define amba_vendor(x) (((x) >> 24) & 0xff)
+struct ambapp_apb_info {
+ /* COMMON */
+ unsigned char irq;
+ unsigned char ver;
+ unsigned char ahbidx; /* AHB Bus Index */
-#define amba_device(x) (((x) >> 12) & 0xfff)
+ /* APB SPECIFIC */
+ unsigned int start;
+ unsigned int mask;
+};
-#define amba_ahb_get_membar(tab, index, nr) (*((tab).addr[(index)]+4+(nr)))
+struct ambapp_ahb_info {
+ /* COMMON */
+ unsigned char irq;
+ unsigned char ver;
+ unsigned char ahbidx; /* AHB Bus Index */
+
+ /* AHB SPECIFIC */
+ unsigned int start[4];
+ unsigned int mask[4];
+ char type[4]; /* type[N] Determine type of start[N]-mask[N],
+ * 2=AHB Memory Space, 3=AHB I/O Space */
+ unsigned int custom[3];
+};
-#define amba_ahb_get_custom(tab, index, nr) (*((tab).addr[(index)]+1+(nr)))
+/* Describes a complete AMBA Core. Each device may consist of 3 interfaces */
+struct ambapp_core {
+ char irq; /* irq=-1 indicate no IRQ */
+ unsigned char vendor;
+ unsigned short device;
+ int index; /* Core index */
+ struct ambapp_ahb_info *ahb_mst;
+ struct ambapp_ahb_info *ahb_slv;
+ struct ambapp_apb_info *apb_slv;
+};
-#define amba_apb_get_membar(tab, index) (*((tab).addr[(index)]+1))
+struct ambapp_ahb_bus {
+ unsigned int ioarea; /* AHB Bus IOAREA */
+ unsigned int freq_hz; /* Frequency of AHB Bus */
+ struct ambapp_dev *bridge;/* Bridge Device on Parent AHB Bus */
+ struct ambapp_dev *dev; /* First Device on AHB Bus */
+};
-#define amba_membar_start(mbar) (((mbar) & 0xfff00000) & (((mbar) & 0xfff0) << 16))
+struct ambapp_mmap {
+ unsigned int size;
+ unsigned int local_adr;
+ unsigned int remote_adr;
+};
-#define amba_iobar_start(base, iobar) ((base) | ((((iobar) & 0xfff00000)>>12) & (((iobar) & 0xfff0)<<4)) )
+/* Complete AMBA PnP information */
+struct ambapp_bus {
+ struct ambapp_dev *root; /* AHB/APB Device Tree*/
+ struct ambapp_mmap *mmaps; /* Memory MAP Array */
+ struct ambapp_ahb_bus ahbs[AHB_BUS_MAX]; /* AHB Buses */
+};
-#define amba_irq(conf) ((conf) & 0x1f)
+/*
+ * Return values
+ * 0 - continue
+ * 1 - stop scanning
+ */
+typedef int (*ambapp_func_t)(struct ambapp_dev *dev, int index, void *arg);
+
+#define DEV_IS_FREE(dev) (dev->owner == NULL)
+#define DEV_IS_ALLOCATED(dev) (dev->owner != NULL)
+
+/* Options to ambapp_for_each */
+#define OPTIONS_AHB_MSTS 0x00000001
+#define OPTIONS_AHB_SLVS 0x00000002
+#define OPTIONS_APB_SLVS 0x00000004
+#define OPTIONS_ALL_DEVS (OPTIONS_AHB_MSTS|OPTIONS_AHB_SLVS|OPTIONS_APB_SLVS)
+
+#define OPTIONS_FREE 0x00000010
+#define OPTIONS_ALLOCATED 0x00000020
+#define OPTIONS_ALL (OPTIONS_FREE|OPTIONS_ALLOCATED)
+
+/* Depth first search, Defualt is breath first search. */
+#define OPTIONS_DEPTH_FIRST 0x00000100
+
+#define DEV_AHB_NONE 0
+#define DEV_AHB_MST 1
+#define DEV_AHB_SLV 2
+#define DEV_APB_SLV 3
+
+/* Structures used to access Plug&Play information directly */
+struct ambapp_pnp_ahb {
+ const unsigned int id; /* VENDOR, DEVICE, VER, IRQ, */
+ const unsigned int custom[3];
+ const unsigned int mbar[4]; /* MASK, ADDRESS, TYPE, CACHABLE/PREFETCHABLE */
+};
-#define amba_ver(conf) (((conf)>>5) & 0x1f)
+struct ambapp_pnp_apb {
+ const unsigned int id; /* VENDOR, DEVICE, VER, IRQ, */
+ const unsigned int iobar; /* MASK, ADDRESS, TYPE, CACHABLE/PREFETCHABLE */
+};
+
+#define ambapp_pnp_vendor(id) (((id) >> 24) & 0xff)
+#define ambapp_pnp_device(id) (((id) >> 12) & 0xfff)
+#define ambapp_pnp_ver(id) (((id)>>5) & 0x1f)
+#define ambapp_pnp_irq(id) ((id) & 0x1f)
+
+#define ambapp_pnp_start(mbar) (((mbar) & 0xfff00000) & (((mbar) & 0xfff0) << 16))
+#define ambapp_pnp_mbar_mask(mbar) (((mbar)>>4) & 0xfff)
+#define ambapp_pnp_mbar_type(mbar) ((mbar) & 0xf)
+
+#define ambapp_pnp_apb_start(iobar, base) ((base) | ((((iobar) & 0xfff00000)>>12) & (((iobar) & 0xfff0)<<4)) )
+#define ambapp_pnp_apb_mask(iobar) ((~(ambapp_pnp_mbar_mask(iobar)<<8) & 0x000fffff) + 1)
-#define amba_membar_type(mbar) ((mbar) & 0xf)
+#define AMBA_TYPE_AHBIO_ADDR(addr,base_ioarea) ((unsigned int)(base_ioarea) | ((addr) >> 12))
#define AMBA_TYPE_APBIO 0x1
#define AMBA_TYPE_MEM 0x2
#define AMBA_TYPE_AHBIO 0x3
-#define AMBA_TYPE_AHBIO_ADDR(addr,base_ioarea) ((unsigned int)(base_ioarea) | ((addr) >> 12))
-
-/*
- * Types and structure used for AMBA Plug & Play bus scanning
+/* Copy Data from AMBA PnP I/O Area */
+typedef void *(*ambapp_memcpy_t)(
+ void *dest, /* Destination RAM copy */
+ const void *src, /* Source AMBA PnP Address to copy from */
+ int n, /* Number of bytes to be copied */
+ struct ambapp_bus *abus /* Optional AMBA Bus pointer */
+ );
+
+/* Scan a AMBA Plug & Play bus and create all device structures describing the
+ * the devices. The devices will form a tree, where every node describes one
+ * interface. The resulting tree is placed in the location pointed to by root.
+ *
+ * Since it the tree is located in RAM it is easier to work with AMBA buses
+ * that is located over PCI and SpaceWire etc.
+ *
+ * \param ioarea The IO-AREA where Plug & Play information can be found.
+ * \param parent Used internally when recursing down a bridge. Set to NULL.
+ * \param mmaps Is used to perform address translation if needed.
+ * \param root Resulting device node tree root is stored here.
*
*/
-typedef struct amba_device_table {
- int devnr; /* numbrer of devices on AHB or APB bus */
- unsigned int *addr[16]; /* addresses to the devices configuration tables */
-} amba_device_table;
-
-typedef struct {
- int devnr;
- unsigned int *addr[AMBA_APB_SLAVES]; /* addresses to the devices configuration tables */
- unsigned int apbmst[AMBA_APB_SLAVES]; /* pointer to AHB slave (which is a APB master) */
-} amba_apb_dev;
-
-struct amba_mmap {
- unsigned int cpu_adr;
- unsigned int size;
- unsigned int remote_amba_adr;
-};
-
-typedef struct _amba_confarea_type amba_confarea_type;
-
-struct _amba_confarea_type {
- amba_confarea_type *next; /* next bus in chain */
- int notroot; /* is root of a bus (mother AHB has 64 masters/slaves rest 16) */
- unsigned int ioarea;
- struct amba_mmap *mmaps;
- amba_device_table ahbmst;
- amba_device_table ahbslv;
- amba_apb_dev apbslv;
-};
-
-typedef struct {
- unsigned int start, irq, bus_id;
-} amba_apb_device;
-
-typedef struct {
- unsigned int start[4], irq, ver;
-} amba_ahb_device;
-
-/* Scans AMBA Plug&Play Information and convers that information
- * to a more readable format in RAM.
+extern int ambapp_scan(
+ struct ambapp_bus *abus,
+ unsigned int ioarea,
+ ambapp_memcpy_t memfunc,
+ struct ambapp_mmap *mmaps
+ );
+
+/* Initialize the frequency [Hz] of all AHB Buses from knowing the frequency
+ * of one particular APB/AHB Device.
+ */
+extern void ambapp_freq_init(
+ struct ambapp_bus *abus,
+ struct ambapp_dev *dev,
+ unsigned int freq);
+
+/* Returns the frequency [Hz] of a AHB/APB device */
+extern unsigned int ambapp_freq_get(
+ struct ambapp_bus *abus,
+ struct ambapp_dev *dev);
+
+/* Iterates through all AMBA devices previously found, it calls func
+ * once for every device that match the search arguments.
+ *
+ * SEARCH OPTIONS
+ * All search options must be fulfilled, type of devices searched (options)
+ * and AMBA Plug&Play ID [VENDOR,DEVICE], before func() is called. The options
+ * can be use to search only for AMBA APB or AHB Slaves or AHB Masters for
+ * example. Note that when VENDOR=-1 or DEVICE=-1 it will match any vendor or
+ * device ID, this means setting both VENDOR and DEVICE to -1 will result in
+ * calling all devices matches the options argument.
*
- * Will scan for - AHB Masters
- * - AHB Slaves
- * - APB Slaves (if a AHB/APB bridge is found)
+ * \param abus AMBAPP Bus to search
+ * \param options Search options, see OPTIONS_* above
+ * \param vendor AMBAPP VENDOR ID to search for
+ * \param device AMBAPP DEVICE ID to search for
+ * \param func Function called for every device matching search options
+ * \param arg Optional argument passed on to func
*
- * \param amba_conf AMBA P&P device info is placed here.
- * \param ioarea address of AMBA Plug&Play information,
- * on LEON3 systems default is 0xfff00000
- * \param mmaps Memory mmap specific to this amba bus,
- * if NULL no translation will be made (default).
- * A array of maps, ending with a entry with size=0.
+ * func return value affects the search, returning a non-zero value will
+ * stop the search and ambapp_for_each will return immediately returning the
+ * same non-zero value.
+ *
+ * Return Values
+ * 0 - all devices was scanned
+ * non-zero - stopped by user function returning the non-zero value
*/
-void amba_scan (amba_confarea_type * amba_conf, unsigned int ioarea,
- struct amba_mmap *mmaps);
-
-/* Print AMBA Plug&Play info on terminal */
-void amba_print_conf (amba_confarea_type * amba_conf);
-
-
-
-
-/***** APB SLAVES *****/
-
-/* Return number of APB Slave devices which has given vendor and device */
-int amba_get_number_apbslv_devices (amba_confarea_type * amba_conf, int vendor,
- int device);
-
-/* Get First APB Slave device of this vendor&device id */
-int amba_find_apbslv (amba_confarea_type * amba_conf, int vendor, int device,
- amba_apb_device * dev);
-
-/* Get APB Slave device of this vendor&device id. (setting nr to 0 is eqivalent to calling amba_find_apbslv() ) */
-int amba_find_next_apbslv (amba_confarea_type * amba_conf, int vendor,
- int device, amba_apb_device * dev, int index);
-
-/* Get first nr APB Slave devices, put them into dev (which is an array of nr length) */
-int amba_find_apbslvs (amba_confarea_type * amba_conf, int vendor, int device,
- amba_apb_device * devs, int maxno);
-
-
-
-/***** AHB SLAVES *****/
-
-/* Return number of AHB Slave devices which has given vendor and device */
-int amba_get_number_ahbslv_devices (amba_confarea_type * amba_conf, int vendor,
- int device);
-
-/* Get First AHB Slave device of this vendor&device id */
-int amba_find_ahbslv (amba_confarea_type * amba_conf, int vendor, int device,
- amba_ahb_device * dev);
-
-/* Get AHB Slave device of this vendor&device id. (setting nr to 0 is eqivalent to calling amba_find_ahbslv() ) */
-int amba_find_next_ahbslv (amba_confarea_type * amba_conf, int vendor,
- int device, amba_ahb_device * dev, int index);
-
-/* Get first nr AHB Slave devices, put them into dev (which is an array of nr length) */
-int amba_find_ahbslvs (amba_confarea_type * amba_conf, int vendor, int device,
- amba_ahb_device * devs, int maxno);
-
-
-
-/***** AHB MASTERS *****/
-
-/* Return number of AHB Master devices which has given vendor and device */
-int amba_get_number_ahbmst_devices (amba_confarea_type * amba_conf, int vendor,
- int device);
+extern int ambapp_for_each(
+ struct ambapp_bus *abus,
+ unsigned int options,
+ int vendor,
+ int device,
+ ambapp_func_t func,
+ void *arg);
+
+/* Helper function for ambapp_for_each(), find a device by index. If pcount
+ * is NULL the first device is returned, else pcount is interpreted as index
+ * by decrementing the value until zero is reaced: *count=0 first device,
+ * *count=1 second device etc.
+ *
+ * The matching device is returned, which will stop the ambapp_for_each search.
+ * If zero is returned from ambapp_for_each no device matching the index was
+ * found
+ */
+extern int ambapp_find_by_idx(struct ambapp_dev *dev, int index, void *pcount);
-/* Get First AHB Master device of this vendor&device id */
-int amba_find_ahbmst (amba_confarea_type * amba_conf, int vendor, int device,
- amba_ahb_device * dev);
+/* Get number of devices matching the options/vendor/device arguments, the
+ * arguments are passed onto ambapp_for_each().
+ */
+extern int ambapp_dev_count(struct ambapp_bus *abus, unsigned int options,
+ int vendor, int device);
-/* Get AHB Master device of this vendor&device id. (setting nr to 0 is eqivalent to calling amba_find_ahbmst() ) */
-int amba_find_next_ahbmst (amba_confarea_type * amba_conf, int vendor,
- int device, amba_ahb_device * dev, int index);
+/* Print short information about devices on the AMBA bus onto the console */
+extern void ambapp_print(struct ambapp_bus *abus, int show_depth);
-/* Get first nr AHB Master devices, put them into dev (which is an array of nr length) */
-int amba_find_ahbmsts (amba_confarea_type * amba_conf, int vendor, int device,
- amba_ahb_device * devs, int maxno);
+/* Mark a device taken (allocate), Owner field is set with owner Data. Returns
+ * -1 if device has already been allocated.
+ */
+extern int ambapp_alloc_dev(struct ambapp_dev *dev, void *owner);
+/* Owner field is cleared, which indicates that device is not allocated */
+extern void ambapp_free_dev(struct ambapp_dev *dev);
-/******** AMBA DEVICES *******/
+/* Find AHB/APB Bridge or AHB/AHB Bridge Parent */
+extern struct ambapp_dev *ambapp_find_parent(struct ambapp_dev *dev);
-/* ESA MEMORY CONTROLLER */
-typedef struct {
- unsigned int mcfg1;
- unsigned int mcfg2;
- unsigned int mcfg3;
-} ambapp_regmap_mctrl;
+/* Returns bus depth (number of sub AHB buses) of device from root bus */
+extern int ambapp_depth(struct ambapp_dev *dev);
-/* APB UART */
-typedef struct {
- volatile unsigned int data;
- volatile unsigned int status;
- volatile unsigned int ctrl;
- volatile unsigned int scaler;
-} ambapp_apb_uart;
+/* Get Device Name from AMBA PnP name database */
+extern char *ambapp_device_id2str(int vendor, int id);
-typedef struct {
- volatile unsigned int ilevel;
- volatile unsigned int ipend;
- volatile unsigned int iforce;
- volatile unsigned int iclear;
- volatile unsigned int mpstat;
- volatile unsigned int notused01;
- volatile unsigned int notused02;
- volatile unsigned int notused03;
- volatile unsigned int notused10;
- volatile unsigned int notused11;
- volatile unsigned int notused12;
- volatile unsigned int notused13;
- volatile unsigned int notused20;
- volatile unsigned int notused21;
- volatile unsigned int notused22;
- volatile unsigned int notused23;
- volatile unsigned int mask[16];
- volatile unsigned int force[16];
-} LEON3_IrqCtrl_Regs_Map;
+/* Get Vendor Name from AMBA PnP name database */
+extern char *ambapp_vendor_id2str(int vendor);
-/*****************************/
+/* Set together VENDOR_DEVICE Name from AMBA PnP name database. Return length
+ * of C-string stored in buf not including string termination '\0'.
+ */
+extern int ambapp_vendev_id2str(int vendor, int id, char *buf);
+
+/* Help functions for backwards compability */
+
+extern int ambapp_find_apbslv(
+ struct ambapp_bus *abus,
+ int vendor,
+ int device,
+ struct ambapp_apb_info *dev);
+
+extern int ambapp_find_apbslv_next(
+ struct ambapp_bus *abus,
+ int vendor,
+ int device,
+ struct ambapp_apb_info *dev,
+ int index);
+
+extern int ambapp_find_apbslvs_next(
+ struct ambapp_bus *abus,
+ int vendor,
+ int device,
+ struct ambapp_apb_info *dev,
+ int index,
+ int maxno);
+
+extern int ambapp_find_apbslvs(
+ struct ambapp_bus *abus,
+ int vendor,
+ int device,
+ struct ambapp_apb_info *dev,
+ int maxno);
+
+extern int ambapp_get_number_apbslv_devices(
+ struct ambapp_bus *abus,
+ int vendor,
+ int device);
+
+extern int ambapp_find_ahbslv(
+ struct ambapp_bus *abus,
+ int vendor,
+ int device,
+ struct ambapp_ahb_info *dev);
+
+extern int ambapp_find_ahbslv_next(
+ struct ambapp_bus *abus,
+ int vendor,
+ int device,
+ struct ambapp_ahb_info *dev,
+ int index);
+
+extern int ambapp_find_ahbslvs_next(
+ struct ambapp_bus *abus,
+ int vendor,
+ int device,
+ struct ambapp_ahb_info *dev,
+ int index,
+ int maxno);
+
+extern int ambapp_find_ahbslvs(
+ struct ambapp_bus *abus,
+ int vendor,
+ int device,
+ struct ambapp_ahb_info *dev,
+ int maxno);
+
+extern int ambapp_get_number_ahbslv_devices(
+ struct ambapp_bus *abus,
+ int vendor,
+ int device);
#ifdef __cplusplus
}
diff --git a/c/src/lib/libbsp/sparc/shared/include/ambapp_ids.h b/c/src/lib/libbsp/sparc/shared/include/ambapp_ids.h
new file mode 100644
index 0000000000..e6f3601ee2
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/ambapp_ids.h
@@ -0,0 +1,245 @@
+/* AMBA Plug & Play Bus Vendor and Device IDs.
+ *
+ * COPYRIGHT (c) 2008.
+ * Gaisler Research
+ *
+ * This header file provide all known VENDOR and DEVICE IDs available
+ * in the AMBA Plug & Play information. Taken from GRLIB 3386.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ */
+
+
+#ifndef __AMBAPP_DEVS_H__
+#define __AMBAPP_DEVS_H__
+
+/* Vendor codes */
+#define VENDOR_GAISLER 1
+#define VENDOR_PENDER 2
+#define VENDOR_ESA 4
+#define VENDOR_ASTRIUM 6
+#define VENDOR_OPENCHIP 7
+#define VENDOR_OPENCORES 8
+#define VENDOR_CONTRIB 9
+#define VENDOR_EONIC 11
+#define VENDOR_RADIONOR 15
+#define VENDOR_GLEICHMANN 16
+#define VENDOR_MENTA 17
+#define VENDOR_SUN 19
+#define VENDOR_MOVIDIA 20
+#define VENDOR_ORBITA 23
+#define VENDOR_SYNOPSYS 33
+#define VENDOR_NASA 34
+#define VENDOR_ACTEL 172
+#define VENDOR_CAL 202
+#define VENDOR_EMBEDDIT 234
+#define VENDOR_CETON 203
+
+/* Gaisler Research device id's */
+#define GAISLER_LEON2DSU 0x002
+#define GAISLER_LEON3 0x003
+#define GAISLER_LEON3DSU 0x004
+#define GAISLER_ETHAHB 0x005
+#define GAISLER_APBMST 0x006
+#define GAISLER_AHBUART 0x007
+#define GAISLER_SRCTRL 0x008
+#define GAISLER_SDCTRL 0x009
+#define GAISLER_SSRCTRL 0x00a
+#define GAISLER_APBUART 0x00c
+#define GAISLER_IRQMP 0x00d
+#define GAISLER_AHBRAM 0x00e
+#define GAISLER_AHBDPRAM 0x00f
+#define GAISLER_GPTIMER 0x011
+#define GAISLER_PCITRG 0x012
+#define GAISLER_PCISBRG 0x013
+#define GAISLER_PCIFBRG 0x014
+#define GAISLER_PCITRACE 0x015
+#define GAISLER_DMACTRL 0x016
+#define GAISLER_AHBTRACE 0x017
+#define GAISLER_DSUCTRL 0x018
+#define GAISLER_CANAHB 0x019
+#define GAISLER_GPIO 0x01a
+#define GAISLER_AHBROM 0x01b
+#define GAISLER_AHBJTAG 0x01c
+#define GAISLER_ETHMAC 0x01d
+#define GAISLER_SWNODE 0x01e
+#define GAISLER_SPW 0x01f
+#define GAISLER_AHB2AHB 0x020
+#define GAISLER_USBDC 0x021
+#define GAISLER_USB_DCL 0x022
+#define GAISLER_DDRMP 0x023
+#define GAISLER_ATACTRL 0x024
+#define GAISLER_DDRSP 0x025
+#define GAISLER_EHCI 0x026
+#define GAISLER_UHCI 0x027
+#define GAISLER_I2CMST 0x028
+#define GAISLER_SPW2 0x029
+#define GAISLER_AHBDMA 0x02a
+#define GAISLER_NUHOSP3 0x02b
+#define GAISLER_CLKGATE 0x02c
+#define GAISLER_SPICTRL 0x02d
+#define GAISLER_DDR2SP 0x02e
+#define GAISLER_SLINK 0x02f
+#define GAISLER_GRTM 0x030
+#define GAISLER_GRTC 0x031
+#define GAISLER_GRPW 0x032
+#define GAISLER_GRCTM 0x033
+#define GAISLER_GRHCAN 0x034
+#define GAISLER_GRFIFO 0x035
+#define GAISLER_GRADCDAC 0x036
+#define GAISLER_GRPULSE 0x037
+#define GAISLER_GRTIMER 0x038
+#define GAISLER_AHB2PP 0x039
+#define GAISLER_GRVERSION 0x03a
+#define GAISLER_APB2PW 0x03b
+#define GAISLER_PW2APB 0x03c
+#define GAISLER_GRCAN 0x03d
+#define GAISLER_I2CSLV 0x03e
+#define GAISLER_U16550 0x03f
+#define GAISLER_AHBMST_EM 0x040
+#define GAISLER_AHBSLV_EM 0x041
+#define GAISLER_GRTESTMOD 0x042
+#define GAISLER_ASCS 0x043
+#define GAISLER_IPMVBCTRL 0x044
+#define GAISLER_SPIMCTRL 0x045
+#define GAISLER_L4STAT 0x047
+#define GAISLER_LEON4 0x048
+#define GAISLER_LEON4DSU 0x049
+#define GAISLER_GRPWM 0x04a
+#define GAISLER_L2CACHE 0x04b
+#define GAISLER_GR1553B 0x04d
+#define GAISLER_GRIOMMU 0x04f
+#define GAISLER_FTAHBRAM 0x050
+#define GAISLER_FTSRCTRL 0x051
+#define GAISLER_AHBSTAT 0x052
+#define GAISLER_LEON3FT 0x053
+#define GAISLER_FTMCTRL 0x054
+#define GAISLER_FTSDCTRL 0x055
+#define GAISLER_FTSRCTRL8 0x056
+#define GAISLER_MEMSCRUB 0x057
+#define GAISLER_APBPS2 0x060
+#define GAISLER_VGACTRL 0x061
+#define GAISLER_LOGAN 0x062
+#define GAISLER_SVGACTRL 0x063
+#define GAISLER_T1AHB 0x064
+#define GAISLER_MP7WRAP 0x065
+#define GAISLER_GRSYSMON 0x066
+#define GAISLER_GRACECTRL 0x067
+#define GAISLER_B1553BC 0x070
+#define GAISLER_B1553RT 0x071
+#define GAISLER_B1553BRM 0x072
+#define GAISLER_GRAES 0x073
+#define GAISLER_SATCAN 0x080
+#define GAISLER_CANMUX 0x081
+#define GAISLER_GRTMRX 0x082
+#define GAISLER_GRTCTX 0x083
+#define GAISLER_GRTMDESC 0x084
+#define GAISLER_GRTMVC 0x085
+#define GAISLER_GEFFE 0x086
+#define GAISLER_AES 0x073
+#define GAISLER_ECC 0x074
+#define GAISLER_PCIF 0x075
+#define GAISLER_CLKMOD 0x076
+#define GAISLER_HAPSTRAK 0x077
+#define GAISLER_TEST_1X2 0x078
+#define GAISLER_WILD2AHB 0x079
+#define GAISLER_BIO1 0x07a
+#define GAISLER_GRAESDMA 0x07b
+#define GAISLER_GRPCI2 0x07c
+#define GAISLER_GRPCI2_DMA 0x07d
+#define GAISLER_SPWCUC 0x089
+#define GAISLER_SPW2_DMA 0x08a
+#define GAISLER_SPW_ROUTER 0x08b
+
+
+#define GAISLER_PIPEWRAPPER 0xffa
+#define GAISLER_L2TIME 0xffd /* internal device: leon2 timer */
+#define GAISLER_L2C 0xffe /* internal device: leon2compat */
+#define GAISLER_PLUGPLAY 0xfff /* internal device: plug & play configarea */
+
+/* European Space Agency device id's */
+#define ESA_LEON2 0x002
+#define ESA_LEON2APB 0x003
+#define ESA_IRQ 0x005
+#define ESA_TIMER 0x006
+#define ESA_UART 0x007
+#define ESA_CFG 0x008
+#define ESA_IO 0x009
+#define ESA_MCTRL 0x00f
+#define ESA_PCIARB 0x010
+#define ESA_HURRICANE 0x011
+#define ESA_SPW_RMAP 0x012
+#define ESA_SPW2 0x012
+#define ESA_AHBUART 0x013
+#define ESA_SPWA 0x014
+#define ESA_BOSCHCAN 0x015
+#define ESA_IRQ2 0x016
+#define ESA_AHBSTAT 0x017
+#define ESA_WPROT 0x018
+#define ESA_WPROT2 0x019
+#define ESA_PDEC3AMBA 0x020
+#define ESA_PTME3AMBA 0x021
+
+#define OPENCHIP_APBGPIO 0x001
+#define OPENCHIP_APBI2C 0x002
+#define OPENCHIP_APBSPI 0x003
+#define OPENCHIP_APBCHARLCD 0x004
+#define OPENCHIP_APBPWM 0x005
+#define OPENCHIP_APBPS2 0x006
+#define OPENCHIP_APBMMCSD 0x007
+#define OPENCHIP_APBNAND 0x008
+#define OPENCHIP_APBLPC 0x009
+#define OPENCHIP_APBCF 0x00a
+#define OPENCHIP_APBSYSACE 0x00b
+#define OPENCHIP_APB1WIRE 0x00c
+#define OPENCHIP_APBJTAG 0x00d
+#define OPENCHIP_APBSUI 0x00e
+
+
+#define CONTRIB_CORE1 0x001
+#define CONTRIB_CORE2 0x002
+
+#define GLEICHMANN_CUSTOM 0x001
+#define GLEICHMANN_GEOLCD01 0x002
+#define GLEICHMANN_DAC 0x003
+#define GLEICHMANN_HPI 0x004
+#define GLEICHMANN_SPI 0x005
+#define GLEICHMANN_HIFC 0x006
+#define GLEICHMANN_ADCDAC 0x007
+#define GLEICHMANN_SPIOC 0x008
+#define GLEICHMANN_AC97 0x009
+
+#define SUN_T1 0x001
+#define SUN_S1 0x011
+
+#define ORBITA_1553B 0x001
+#define ORBITA_429 0x002
+#define ORBITA_SPI 0x003
+#define ORBITA_I2C 0x004
+#define ORBITA_SMARTCARD 0x064
+#define ORBITA_SDCARD 0x065
+#define ORBITA_UART16550 0x066
+#define ORBITA_CRYPTO 0x067
+#define ORBITA_SYSIF 0x068
+#define ORBITA_PIO 0x069
+#define ORBITA_RTC 0x0c8
+#define ORBITA_COLORLCD 0x12c
+#define ORBITA_PCI 0x190
+#define ORBITA_DSP 0x1f4
+#define ORBITA_USBHOST 0x258
+#define ORBITA_USBDEV 0x2bc
+
+#define NASA_EP32 0x001
+
+#define CAL_DDRCTRL 0x188
+
+#define ACTEL_COREMP7 0x001
+
+/* Opencores device id's */
+#define OPENCORES_PCIBR 0x4
+#define OPENCORES_ETHMAC 0x5
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/include/apbuart.h b/c/src/lib/libbsp/sparc/shared/include/apbuart.h
index c8a6e35fec..079f349ef2 100644
--- a/c/src/lib/libbsp/sparc/shared/include/apbuart.h
+++ b/c/src/lib/libbsp/sparc/shared/include/apbuart.h
@@ -1,7 +1,7 @@
/*
* Driver interface for APBUART
*
- * COPYRIGHT (c) 2007.
+ * COPYRIGHT (c) 2008.
* Gaisler Research
*
* The license and distribution terms for this file may be
@@ -13,7 +13,7 @@
#ifndef __APBUART_H__
#define __APBUART_H__
-#include <ambapp.h>
+#include <drvmgr/drvmgr.h>
#ifdef __cplusplus
extern "C" {
@@ -57,6 +57,7 @@ typedef struct {
#define APBUART_CTRL_EC 0x100
#define APBUART_CTRL_TF 0x200
#define APBUART_CTRL_RF 0x400
+#define APBUART_CTRL_DB 0x800
#define APBUART_STATUS_DR 0x1
#define APBUART_STATUS_TS 0x2
@@ -70,11 +71,8 @@ typedef struct {
#define APBUART_STATUS_TF 0x200
#define APBUART_STATUS_RF 0x400
-/* Register APBUART driver
- * bus = pointer to AMBA bus description used to search for APBUART(s).
- * (&amba_conf for LEON3), (LEON2: see amba_scan)
- */
-int apbuart_register (amba_confarea_type * bus);
+/* Register APBUART driver to the driver manager system */
+void apbuart_register_drv (void);
#ifdef __cplusplus
}
diff --git a/c/src/lib/libbsp/sparc/shared/include/apbuart_pci.h b/c/src/lib/libbsp/sparc/shared/include/apbuart_pci.h
deleted file mode 100644
index e8064297c8..0000000000
--- a/c/src/lib/libbsp/sparc/shared/include/apbuart_pci.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * APBUART via PCI - driver interface
- *
- * COPYRIGHT (c) 2007.
- * Gaisler Research
- *
- * The license and distribution terms for this file may be
- * found in the file LICENSE in this distribution or at
- * http://www.rtems.com/license/LICENSE.
- *
- */
-
-#ifndef __APBUART_PCI_H__
-#define __APBUART_PCI_H__
-
-#include <apbuart.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Register APBUART driver, if APBUART devices are found.
- * bus = pointer to AMBA bus description used to search for APBUART(s).
- *
- */
-
-int apbuart_pci_register (amba_confarea_type * bus);
-
-/* This function must be called on APBUART interrupt. Called from the
- * PCI interrupt handler.
- * irq = AMBA IRQ assigned to the APBUART device, is found by reading
- * pending register on IRQMP connected to the APBUART device.
- *
- */
-void apbuartpci_interrupt_handler (int irq, void *arg);
-
-extern void (*apbuart_pci_int_reg) (void *handler, int irq, void *arg);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __APBUART_PCI_H__ */
diff --git a/c/src/lib/libbsp/sparc/shared/include/apbuart_rasta.h b/c/src/lib/libbsp/sparc/shared/include/apbuart_rasta.h
deleted file mode 100644
index 1edf6f98d3..0000000000
--- a/c/src/lib/libbsp/sparc/shared/include/apbuart_rasta.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * APBUART RASTA via PCI - driver interface
- *
- * COPYRIGHT (c) 2007.
- * Gaisler Research
- *
- * The license and distribution terms for this file may be
- * found in the file LICENSE in this distribution or at
- * http://www.rtems.com/license/LICENSE.
- *
- */
-
-#ifndef __APBUART_RASTA_H__
-#define __APBUART_RASTA_H__
-
-#include <apbuart.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Register APBUART driver, if APBUART devices are found.
- * bus = pointer to AMBA bus description used to search for APBUART(s).
- *
- */
-
-int apbuart_rasta_register(amba_confarea_type *bus);
-
-/* This function must be called on APBUART interrupt. Called from the
- * RASTA interrupt handler.
- * irq = AMBA IRQ assigned to the APBUART device, is found by reading
- * pending register on IRQMP connected to the APBUART device.
- *
- */
-void apbuartrasta_interrupt_handler(int irq, void *arg);
-
-extern void (*apbuart_rasta_int_reg)(void *handler, int irq, void *arg);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __APBUART_RASTA_H__ */
diff --git a/c/src/lib/libbsp/sparc/shared/include/b1553brm.h b/c/src/lib/libbsp/sparc/shared/include/b1553brm.h
index f5fd343078..c1ceb1578b 100644
--- a/c/src/lib/libbsp/sparc/shared/include/b1553brm.h
+++ b/c/src/lib/libbsp/sparc/shared/include/b1553brm.h
@@ -1,7 +1,7 @@
- /*
- * Macros used for brm controller
+/*
+ * B1553BRM driver interface.
*
- * COPYRIGHT (c) 2006.
+ * COPYRIGHT (c) 2008.
* Gaisler Research
*
* The license and distribution terms for this file may be
@@ -13,8 +13,6 @@
#ifndef __B1553BRM_H__
#define __B1553BRM_H__
-#include <ambapp.h>
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -96,6 +94,7 @@ struct bc_msg {
#define BC_RTRT 0x0002
#define BC_BUSA 0x0004
#define BC_EOL 0x0020
+#define BC_SKIP 0x0040
#define BC_BAME 0x8000
#define BRM_MBC_IRQ 1 /* Monitor Block Counter irq */
@@ -108,7 +107,7 @@ struct bc_msg {
#define BRM_IXEQ0_IRQ 256 /* Index Equal Zero irq */
#define BRM_BDRCV_IRQ 512 /* Broadcast Command Received irq */
#define BRM_SUBAD_IRQ 1024 /* Subaddress Accessed irq */
-#define BRM_MERR_IRQ 4096 /* Message Error irq */
+#define BRM_MERR_IRQ 2048 /* Message Error irq */
#define BRM_TAPF_IRQ 8192 /* Terminal Address Parity Fail irq */
#define BRM_WRAPF_IRQ 16384 /* Wrap Fail irq */
#define BRM_DMAF_IRQ 32768 /* DMA Fail irq */
@@ -138,13 +137,6 @@ struct bc_msg {
#define BRM_MODE_BM 0x2
#define BRM_MODE_BM_RT 0x3 /* both RT and BM */
-
-/* Register RAMON FPGA BRM driver, calls brm_register */
-int brm_register_leon3_ramon_fpga(void);
-
-/* Register RAMON ASIC BRM driver, calls brm_register */
-int brm_register_leon3_ramon_asic(void);
-
#define BRM_FREQ_12MHZ 0
#define BRM_FREQ_16MHZ 1
#define BRM_FREQ_20MHZ 2
@@ -155,15 +147,11 @@ int brm_register_leon3_ramon_asic(void);
#define CLKSEL_MASK 0x7
-/* Register BRM driver
- * See (struct brm_reg).w_ctrl for clksel and clkdiv.
- * See Enhanced register (the least signinficant 2 bits) in BRM Core for brm_freq
- * bus = &amba_conf for LEON3. (LEON2 not yet supported for this driver)
- */
-int b1553brm_register(amba_confarea_type *bus, unsigned int clksel, unsigned int clkdiv, unsigned int brm_freq);
+void b1553brm_register_drv(void);
#ifdef __cplusplus
}
#endif
#endif /* __BRM_H__ */
+
diff --git a/c/src/lib/libbsp/sparc/shared/include/b1553brm_pci.h b/c/src/lib/libbsp/sparc/shared/include/b1553brm_pci.h
deleted file mode 100644
index 74f9d321de..0000000000
--- a/c/src/lib/libbsp/sparc/shared/include/b1553brm_pci.h
+++ /dev/null
@@ -1,57 +0,0 @@
- /*
- * Macros used for brm controller
- *
- * COPYRIGHT (c) 2006.
- * Gaisler Research
- *
- * The license and distribution terms for this file may be
- * found in the file LICENSE in this distribution or at
- * http://www.rtems.com/license/LICENSE.
- *
- */
-
-#ifndef __B1553BRM_PCI_H__
-#define __B1553BRM_PCI_H__
-
-#include <b1553brm.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Register BRM driver
- * See (struct brm_reg).w_ctrl for clksel and clkdiv.
- * See Enhanced register (the least signinficant 2 bits) in BRM Core for brm_freq
- * bus = &amba_conf for LEON3. (LEON2 not yet supported for this driver)
- *
- * Memory setup:
- * memarea = 128k aligned pointer to memory (if zero malloc will be used) (as the CPU sees it)
- * hw_address = address that HW must use to access memarea. (used in the translation process)
- */
-
-int b1553brm_pci_register(
- amba_confarea_type *bus,
- unsigned int clksel,
- unsigned int clkdiv,
- unsigned int brm_freq,
- unsigned int memarea,
- unsigned int hw_address
- );
-
-
-/* This function must be called on BRM interrupt. Called from the
- * PCI interrupt handler. irq = AMBA IRQ MASK assigned to the BRM device,
- * is found by reading pending register on IRQMP connected to BRM
- * device.
- *
- * Return 0=not handled. nono-zero=handled
- */
-int b1553brm_pci_interrupt_handler(int irq, void *arg);
-
-extern void (*b1553brm_pci_int_reg)(void *handler, int irq, void *arg);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __B1553BRM_PCI_H__ */
diff --git a/c/src/lib/libbsp/sparc/shared/include/b1553brm_rasta.h b/c/src/lib/libbsp/sparc/shared/include/b1553brm_rasta.h
deleted file mode 100644
index cd5165801c..0000000000
--- a/c/src/lib/libbsp/sparc/shared/include/b1553brm_rasta.h
+++ /dev/null
@@ -1,57 +0,0 @@
- /*
- * Macros used for brm controller
- *
- * COPYRIGHT (c) 2006.
- * Gaisler Research
- *
- * The license and distribution terms for this file may be
- * found in the file LICENSE in this distribution or at
- * http://www.rtems.com/license/LICENSE.
- *
- */
-
-#ifndef __B1553BRM_RASTA_H__
-#define __B1553BRM_RASTA_H__
-
-#include <b1553brm.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Register BRM driver
- * See (struct brm_reg).w_ctrl for clksel and clkdiv.
- * See Enhanced register (the least signinficant 2 bits) in BRM Core for brm_freq
- * bus = &amba_conf for LEON3. (LEON2 not yet supported for this driver)
- *
- * Memory setup:
- * memarea = 128k aligned pointer to memory (if zero malloc will be used) (as the CPU sees it)
- * hw_address = address that HW must use to access memarea. (used in the translation process)
- */
-
-int b1553brm_rasta_register(
- amba_confarea_type *bus,
- unsigned int clksel,
- unsigned int clkdiv,
- unsigned int brm_freq,
- unsigned int memarea,
- unsigned int hw_address
- );
-
-
-/* This function must be called on BRM interrupt. Called from the
- * PCI interrupt handler. irq = AMBA IRQ MASK assigned to the BRM device,
- * is found by reading pending register on IRQMP connected to BRM
- * device.
- *
- * Return 0=not handled. nono-zero=handled
- */
-int b1553brm_rasta_interrupt_handler(int irq, void *arg);
-
-extern void (*b1553brm_rasta_int_reg)(void *handler, int irq, void *arg);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __B1553BRM_RASTA_H__ */
diff --git a/c/src/lib/libbsp/sparc/shared/include/b1553rt.h b/c/src/lib/libbsp/sparc/shared/include/b1553rt.h
new file mode 100644
index 0000000000..a92324700b
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/b1553rt.h
@@ -0,0 +1,76 @@
+/*
+ * B1553RT driver interface
+ *
+ * COPYRIGHT (c) 2009.
+ * Aeroflex Gaisler AB
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ */
+
+#ifndef __B1553RT_H__
+#define __B1553RT_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct rt_reg {
+ volatile unsigned int stat; /* 0x00 */
+ volatile unsigned int ctrl; /* 0x04 */
+ volatile unsigned int vword; /* 0x08 */
+ volatile unsigned int irq; /* 0x0C */
+ volatile unsigned int addr; /* 0x10 */
+ volatile unsigned int ipm; /* 0x14 */
+};
+
+
+struct rt_msg {
+ unsigned short miw;
+ unsigned short time;
+ unsigned short data[32];
+ unsigned short desc;
+};
+
+#define RT_FREQ_12MHZ 0
+#define RT_FREQ_16MHZ 1
+#define RT_FREQ_20MHZ 2
+#define RT_FREQ_24MHZ 3
+#define RT_FREQ_MASK 0x3
+
+/* IOCTLs */
+#define RT_SET_ADDR 3
+#define RT_SET_BCE 5
+#define RT_RX_BLOCK 8
+#define RT_CLR_STATUS 12
+#define RT_GET_STATUS 13
+#define RT_SET_EVENTID 14
+
+#define RT_SET_VECTORW 32
+#define RT_SET_EXTMDATA 33
+
+#define RT_ILLCMD_IRQ 128
+#define RT_MERR_IRQ 2048
+#define RT_DMAF_IRQ 32768 /* DMA Fail irq */
+
+#define RT_TSW_OK (1<<14)
+#define RT_TSW_BUS (1<<13)
+#define RT_TSW_BC (1<<12)
+#define RT_TSW_LPBKERRB (1<<11)
+#define RT_TSW_LPBKERRA (1<<10)
+#define RT_TSW_ILL (1<<9)
+#define RT_TSW_MEM (1<<8)
+#define RT_TSW_MAN (1<<7)
+#define RT_TSW_PAR (1<<6)
+#define RT_TSW_WC (1<<5)
+
+void b1553rt_register_drv(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __RT_H__ */
+
diff --git a/c/src/lib/libbsp/sparc/shared/include/canmux.h b/c/src/lib/libbsp/sparc/shared/include/canmux.h
new file mode 100644
index 0000000000..6ee4c19395
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/canmux.h
@@ -0,0 +1,37 @@
+/*
+ * Header file for RTEMS CAN_MUX driver
+ *
+ * --------------------------------------------------------------------------
+ * -- This file is a part of GAISLER RESEARCH source code.
+ * -- Copyright (C) 2008, Gaisler Research AB - all rights reserved.
+ * --
+ * -- ANY USE OR REDISTRIBUTION IN PART OR IN WHOLE MUST BE HANDLED IN
+ * -- ACCORDANCE WITH THE GAISLER LICENSE AGREEMENT AND MUST BE APPROVED
+ * -- IN ADVANCE IN WRITING.
+ * --
+ * -- BY DEFAULT, DISTRIBUTION OR DISCLOSURE IS NOT PERMITTED.
+ * --------------------------------------------------------------------------
+ *
+ */
+
+#ifndef __CANMUX_H__
+#define __CANMUX_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Driver interface */
+int canmux_register(void);
+
+/* ioctl calls */
+#define CANMUX_IOC_BUSA_SATCAN 1
+#define CANMUX_IOC_BUSA_OCCAN1 2
+#define CANMUX_IOC_BUSB_SATCAN 3
+#define CANMUX_IOC_BUSB_OCCAN2 4
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CANMUX_H__ */
diff --git a/c/src/lib/libbsp/sparc/shared/include/cons.h b/c/src/lib/libbsp/sparc/shared/include/cons.h
new file mode 100644
index 0000000000..816e20f899
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/cons.h
@@ -0,0 +1,42 @@
+/* Console driver interface to UART drivers
+ *
+ * - First console device that has System Console flag set will be
+ * system console.
+ * - If none of the registered console devices has system console set,
+ * the first is registered device is used, unless it has
+ *
+ * COPYRIGHT (c) 2010.
+ * Aeroflex Gaisler.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#ifndef __CONS_H__
+#define __CONS_H__
+
+struct console_dev;
+
+#define CONSOLE_FLAG_SYSCON 0x01
+
+struct console_cons_ops {
+ void (*get_uart_attrs)(struct console_dev *, struct termios *t);
+};
+
+struct console_dev {
+ /* Set to non-zero if this UART should be system console and/or
+ * debug console.
+ */
+ int flags;
+ char *fsname; /* File system prefix */
+ const struct rtems_termios_callbacks *callbacks; /* TERMIOS Callbacks */
+ struct console_cons_ops ops;
+};
+
+extern void console_dev_register(struct console_dev *dev);
+#if 0
+extern void console_dev_unregister(struct console_dev *dev);
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/include/drvmgr/ambapp_bus.h b/c/src/lib/libbsp/sparc/shared/include/drvmgr/ambapp_bus.h
new file mode 100644
index 0000000000..3fad75d57a
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/drvmgr/ambapp_bus.h
@@ -0,0 +1,135 @@
+/* General part of a AMBA Plug & Play bus driver.
+ *
+ * COPYRIGHT (c) 2008.
+ * Aeroflex Gaisler.
+ *
+ * This is the general part of the different AMBA Plug & Play
+ * drivers. The drivers are wrappers around this driver, making
+ * the code size smaller for systems with multiple AMBA Plug &
+ * Play buses.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ */
+
+#ifndef __AMBAPP_BUS_H__
+#define __AMBAPP_BUS_H__
+
+#include <drvmgr/drvmgr.h>
+#include <ambapp.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* GRLIB AMBA Plug&Play Driver ID generation */
+#define DRIVER_AMBAPP_ID(vendor, device) \
+ DRIVER_ID(DRVMGR_BUS_TYPE_AMBAPP, ((((vendor) & 0xff) << 16) | ((device) & 0xfff)))
+
+/*** Gaisler Hardware Device Driver IDs ***/
+#define DRIVER_AMBAPP_GAISLER_AHBSTAT_ID DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_AHBSTAT)
+#define DRIVER_AMBAPP_GAISLER_APBUART_ID DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_APBUART)
+#define DRIVER_AMBAPP_GAISLER_B1553BRM_ID DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_B1553BRM)
+#define DRIVER_AMBAPP_GAISLER_B1553RT_ID DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_B1553RT)
+#define DRIVER_AMBAPP_GAISLER_GPTIMER_ID DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_GPTIMER)
+#define DRIVER_AMBAPP_GAISLER_GR1553B_ID DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_GR1553B)
+#define DRIVER_AMBAPP_GAISLER_GRADCDAC_ID DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_GRADCDAC)
+#define DRIVER_AMBAPP_GAISLER_GRAES_ID DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_GRAESDMA)
+#define DRIVER_AMBAPP_GAISLER_GRCAN_ID DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_GRCAN)
+#define DRIVER_AMBAPP_GAISLER_GRCTM_ID DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_GRCTM)
+#define DRIVER_AMBAPP_GAISLER_GRETH_ID DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_ETHMAC)
+#define DRIVER_AMBAPP_GAISLER_GRGPIO_ID DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_GPIO)
+#define DRIVER_AMBAPP_GAISLER_GRPCI2_ID DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_GRPCI2)
+#define DRIVER_AMBAPP_GAISLER_GRPCI_ID DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_PCIFBRG)
+#define DRIVER_AMBAPP_GAISLER_GRPWM_ID DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_GRPWM)
+#define DRIVER_AMBAPP_GAISLER_GRPWRX_ID DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_PW2APB)
+#define DRIVER_AMBAPP_GAISLER_GRSPW_ID DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_SPW)
+#define DRIVER_AMBAPP_GAISLER_GRSPW2_ID DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_SPW2)
+#define DRIVER_AMBAPP_GAISLER_GRTC_ID DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_GRTC)
+#define DRIVER_AMBAPP_GAISLER_GRTM_ID DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_GRTM)
+#define DRIVER_AMBAPP_GAISLER_I2CMST_ID DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_I2CMST)
+#define DRIVER_AMBAPP_GAISLER_OCCAN_ID DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_CANAHB)
+#define DRIVER_AMBAPP_GAISLER_PCIF_ID DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_PCIF)
+#define DRIVER_AMBAPP_GAISLER_PCITRACE_ID DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_PCITRACE)
+#define DRIVER_AMBAPP_GAISLER_SPICTRL_ID DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_SPICTRL)
+#define DRIVER_AMBAPP_GAISLER_SPWCUC_ID DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_SPWCUC)
+#define DRIVER_AMBAPP_GAISLER_SPW_ROUTER_ID DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_SPW_ROUTER)
+
+/*** ESA Hardware Device Driver IDs ***/
+#define DRIVER_AMBAPP_ESA_MCTRL_ID DRIVER_AMBAPP_ID(VENDOR_ESA, ESA_MCTRL)
+#define DRIVER_AMBAPP_MCTRL_ID DRIVER_AMBAPP_ESA_MCTRL_ID
+
+struct amba_dev_id {
+ unsigned short vendor;
+ unsigned short device;
+ /* Version ? */
+};
+
+struct amba_drv_info {
+ struct drvmgr_drv general; /* General bus info */
+ /* AMBA specific bus information */
+ struct amba_dev_id *ids; /* Supported hardware */
+};
+
+struct amba_dev_info {
+ struct amba_dev_id id;
+ struct ambapp_core info;
+};
+
+struct ambapp_ops {
+ int (*int_register)
+ (struct drvmgr_dev *dev, int index, const char *info, drvmgr_isr isr, void *arg);
+ int (*int_unregister)
+ (struct drvmgr_dev *dev, int index, drvmgr_isr isr, void *arg);
+ int (*int_clear)(struct drvmgr_dev *dev, int index);
+ int (*int_mask)(struct drvmgr_dev *dev, int index);
+ int (*int_unmask)(struct drvmgr_dev *dev, int index);
+ int (*get_params)
+ (struct drvmgr_dev *, struct drvmgr_bus_params *);
+};
+
+struct ambapp_config {
+ struct ambapp_bus *abus; /* Prescanned AMBA PnP bus */
+ struct ambapp_ops *ops; /* AMBA bus operations */
+ struct drvmgr_map_entry *maps_up; /* Bus memory map up-stream towards CPU */
+ struct drvmgr_map_entry *maps_down; /* Bus memory map down-stream towards HW */
+ struct drvmgr_bus_res *resources; /* Driver Resources */
+ int bus_type; /* Set DRVMGR_BUS_TYPE_AMBAPP_DIST if distributed AMBA Bus */
+ struct drvmgr_func *funcs; /* Custom functions */
+};
+
+/*** Bus operations with READ/WRITE access operations ***
+ *
+ * The functions are implemented using the standard drvmgr RW interface
+ */
+#define AMBAPP_R8 DRVMGR_RWFUNC(RW_SIZE_1|RW_READ|RW_REG)
+#define AMBAPP_R16 DRVMGR_RWFUNC(RW_SIZE_2|RW_READ|RW_REG)
+#define AMBAPP_R32 DRVMGR_RWFUNC(RW_SIZE_4|RW_READ|RW_REG)
+#define AMBAPP_R64 DRVMGR_RWFUNC(RW_SIZE_8|RW_READ|RW_REG)
+#define AMBAPP_W8 DRVMGR_RWFUNC(RW_SIZE_1|RW_WRITE|RW_REG)
+#define AMBAPP_W16 DRVMGR_RWFUNC(RW_SIZE_2|RW_WRITE|RW_REG)
+#define AMBAPP_W32 DRVMGR_RWFUNC(RW_SIZE_4|RW_WRITE|RW_REG)
+#define AMBAPP_W64 DRVMGR_RWFUNC(RW_SIZE_8|RW_WRITE|RW_REG)
+#define AMBAPP_RMEM DRVMGR_RWFUNC(RW_SIZE_ANY|RW_READ|RW_MEM)
+#define AMBAPP_WMEM DRVMGR_RWFUNC(RW_SIZE_ANY|RW_WRITE|RW_MEM)
+#define AMBAPP_MEMSET DRVMGR_RWFUNC(RW_SIZE_ANY|RW_SET|RW_MEM)
+#define AMBAPP_RW_ARG DRVMGR_RWFUNC(RW_ARG)
+
+/* Register an ambapp bus on-top of a device */
+extern int ambapp_bus_register(
+ struct drvmgr_dev *dev,
+ struct ambapp_config *config
+ );
+
+extern void ambapp_bus_freq_register(
+ struct drvmgr_dev *dev,
+ int amba_interface,
+ unsigned int freq_hz);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/include/drvmgr/ambapp_bus_grlib.h b/c/src/lib/libbsp/sparc/shared/include/drvmgr/ambapp_bus_grlib.h
new file mode 100644
index 0000000000..f14c546abd
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/drvmgr/ambapp_bus_grlib.h
@@ -0,0 +1,35 @@
+/* LEON3 GRLIB AMBA Plug & Play bus driver interface.
+ *
+ * COPYRIGHT (c) 2008.
+ * Aeroflex Gaisler.
+ *
+ * This is driver is a wrapper for the general AMBA Plug & Play bus
+ * driver. This is the root bus driver for GRLIB systems.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ *
+ */
+
+#ifndef __AMBAPP_BUS_GRLIB_H__
+#define __AMBAPP_BUS_GRLIB_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct grlib_config {
+ struct ambapp_bus *abus;
+ struct drvmgr_bus_res *resources;
+};
+
+/* Register GRLIB AMBA PnP Bus as root bus at driver manager */
+extern int ambapp_grlib_root_register(struct grlib_config *config);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/include/drvmgr/ambapp_bus_rmap.h b/c/src/lib/libbsp/sparc/shared/include/drvmgr/ambapp_bus_rmap.h
new file mode 100644
index 0000000000..c7ec880ba2
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/drvmgr/ambapp_bus_rmap.h
@@ -0,0 +1,79 @@
+/* SpaceWire RMAP AMBA Plug & Play bus driver interface.
+ *
+ * COPYRIGHT (c) 2009.
+ * Aeroflex Gaisler.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ */
+
+#ifndef __AMBAPP_BUS_RMAP_H__
+#define __AMBAPP_BUS_RMAP_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void ambapp_rmap_register(void);
+
+/*** Bus operations with READ/WRITE access operations ***
+ *
+ * The functions are implemented using the standard drvmgr RW interface
+ */
+#define AMBAPP_RMAP_R8 DRVMGR_RWFUNC(RW_SIZE_1|RW_READ|RW_REG)
+#define AMBAPP_RMAP_R16 DRVMGR_RWFUNC(RW_SIZE_2|RW_READ|RW_REG)
+#define AMBAPP_RMAP_R32 DRVMGR_RWFUNC(RW_SIZE_4|RW_READ|RW_REG)
+#define AMBAPP_RMAP_R64 DRVMGR_RWFUNC(RW_SIZE_8|RW_READ|RW_REG)
+#define AMBAPP_RMAP_W8 DRVMGR_RWFUNC(RW_SIZE_1|RW_WRITE|RW_REG)
+#define AMBAPP_RMAP_W16 DRVMGR_RWFUNC(RW_SIZE_2|RW_WRITE|RW_REG)
+#define AMBAPP_RMAP_W32 DRVMGR_RWFUNC(RW_SIZE_4|RW_WRITE|RW_REG)
+#define AMBAPP_RMAP_W64 DRVMGR_RWFUNC(RW_SIZE_8|RW_WRITE|RW_REG)
+#define AMBAPP_RMAP_RMEM DRVMGR_RWFUNC(RW_SIZE_ANY|RW_READ|RW_MEM)
+#define AMBAPP_RMAP_WMEM DRVMGR_RWFUNC(RW_SIZE_ANY|RW_WRITE|RW_MEM)
+#define AMBAPP_RMAP_MEMSET DRVMGR_RWFUNC(RW_SIZE_ANY|RW_SET|RW_MEM)
+#define AMBAPP_RMAP_RW_ARG DRVMGR_RWFUNC(RW_ARG)
+#define AMBAPP_RMAP_RW_ERR DRVMGR_RWFUNC(RW_ERR)
+
+/* Read/Write function types with additional argument */
+typedef uint8_t (*ambapp_rmap_r8)(uint8_t *srcadr, struct drvmgr_rw_arg *a);
+typedef uint16_t (*ambapp_rmap_r16)(uint16_t *srcadr, struct drvmgr_rw_arg *a);
+typedef uint32_t (*ambapp_rmap_r32)(uint32_t *srcadr, struct drvmgr_rw_arg *a);
+typedef uint64_t (*ambapp_rmap_r64)(uint64_t *srcadr, struct drvmgr_rw_arg *a);
+typedef void (*ambapp_rmap_w8)(uint8_t *dstadr, uint8_t data, struct drvmgr_rw_arg *a);
+typedef void (*ambapp_rmap_w16)(uint16_t *dstadr, uint16_t data, struct drvmgr_rw_arg *a);
+typedef void (*ambapp_rmap_w32)(uint32_t *dstadr, uint32_t data, struct drvmgr_rw_arg *a);
+typedef void (*ambapp_rmap_w64)(uint64_t *dstadr, uint64_t data, struct drvmgr_rw_arg *a);
+/* READ/COPY a memory area located on bus into CPU memory.
+ * From 'src' (remote) to the destination 'dest' (local), n=number of bytes
+ */
+typedef int (*ambapp_rmap_rmem)(void *dest, const void *src, int n, struct drvmgr_rw_arg *a);
+/* WRITE/COPY a user buffer located in CPU memory to a location on the bus.
+ * From 'src' (local) to the destination 'dest' (remote), n=number of bytes
+ */
+typedef int (*ambapp_rmap_wmem)(void *dest, const void *src, int n, struct drvmgr_rw_arg *a);
+/* Set a memory area to the byte value given in c, see LIBC memset(). Memset is
+ * implemented by calling wmem() multiple times with a "large" buffer.
+ */
+typedef int (*ambapp_rmap_memset)(void *dstadr, int c, size_t n, struct drvmgr_rw_arg *a);
+
+/* Allocate memory from the SpaceWire target's memory */
+extern void *ambapp_rmap_partition_memalign(
+ struct drvmgr_dev *dev,
+ int partition,
+ size_t boundary,
+ size_t size);
+
+/* Register a partition of memory in the SpaceWire target */
+extern int ambapp_rmap_partition_create(
+ struct drvmgr_dev *dev,
+ int partition,
+ unsigned int start,
+ size_t size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/include/drvmgr/leon2_amba_bus.h b/c/src/lib/libbsp/sparc/shared/include/drvmgr/leon2_amba_bus.h
new file mode 100644
index 0000000000..539e0b4693
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/drvmgr/leon2_amba_bus.h
@@ -0,0 +1,96 @@
+/* LEON2 Hardcoded bus driver interface.
+ *
+ * COPYRIGHT (c) 2008.
+ * Aeroflex Gaisler.
+ *
+ * Bus driver for a hardcoded setup. LEON2 systems have some
+ * cores always present, here called "Standard Cores". In
+ * addtion to the standard cores there are often extra cores
+ * that can be defined using the "Custom Cores" mechanism.
+ *
+ * A Core is described by assigning a base register and
+ * IRQ0..IRQ15 using the leon2_core structure.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ */
+
+#ifndef __LEON2_AMBA_BUS_H__
+#define __LEON2_AMBA_BUS_H__
+
+/*** Cores location and IRQs hardcoded ***/
+
+#include <drvmgr/drvmgr.h>
+#include <ambapp.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* LEON2 AMBA Driver ID generation */
+#define DRIVER_LEON2_AMBA(id) DRIVER_ID(DRVMGR_BUS_TYPE_LEON2_AMBA, id)
+
+/* LEON2 Cores (any unique 48-bit number will do) */
+#define LEON2_AMBA_NONE_ID 0
+#define LEON2_AMBA_TIMER_ID 1
+#define LEON2_AMBA_UART_ID 2
+#define LEON2_AMBA_GPIO_ID 3
+#define LEON2_AMBA_IRQCTRL_ID 4
+
+#define LEON2_AMBA_AT697PCI_ID 100
+#define LEON2_AMBA_AMBAPP_ID 0xfff0
+
+/* LEON2 driver IDs */
+#define DRIVER_LEON2_AMBA_TIMER DRIVER_LEON2_AMBA(LEON2_AMBA_TIMER_ID)
+#define DRIVER_LEON2_AMBA_UART DRIVER_LEON2_AMBA(LEON2_AMBA_UART_ID)
+#define DRIVER_LEON2_AMBA_AT697PCI DRIVER_LEON2_AMBA(LEON2_AMBA_AT697PCI_ID)
+#define DRIVER_LEON2_AMBA_AMBAPP DRIVER_LEON2_AMBA(LEON2_AMBA_AMBAPP_ID)
+
+struct leon2_amba_dev_id {
+ unsigned short core_id;
+};
+
+#define EMPTY_LEON2_CORE {{LEON2_AMBA_NONE_ID}, NULL, NULL}
+struct leon2_core {
+ struct leon2_amba_dev_id id; /* Core ID */
+ char *name; /* Name of Core */
+ struct drvmgr_key *keys; /* Core setup (location, IRQs) */
+};
+
+struct leon2_bus {
+ struct leon2_core *std_cores; /* The LEON2 standard cores */
+ struct leon2_core *custom_cores; /* Custom cores on the same bus */
+ struct drvmgr_map_entry *maps_up; /* Memory map ip-stream */
+ struct drvmgr_map_entry *maps_down; /* Memory map down-stream */
+};
+
+extern struct leon2_core leon2_std_cores[];
+
+/* Data structure drivers can access */
+struct leon2_amba_dev_info {
+ unsigned short core_id; /* Core ID */
+ unsigned int reg_base; /* Register base */
+ char irqs[16]; /* 16 irqs */
+};
+
+struct leon2_amba_drv_info {
+ struct drvmgr_drv general; /* General bus info */
+ /* AMBA specific bus information */
+ struct leon2_amba_dev_id *ids; /* Supported hardware */
+};
+
+/* Initialize LEON2 bus with a configuration
+ * bus_config - What cores, their location and irqs
+ * resources - Driver configuration for the cores specified bus_config
+ */
+int leon2_root_register(
+ struct leon2_bus *bus_config,
+ struct drvmgr_bus_res *resources);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/include/drvmgr/spw_bus.h b/c/src/lib/libbsp/sparc/shared/include/drvmgr/spw_bus.h
new file mode 100644
index 0000000000..870b7eb4a8
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/drvmgr/spw_bus.h
@@ -0,0 +1,131 @@
+/* SpaceWire Network bus driver interface.
+ *
+ * COPYRIGHT (c) 2009.
+ * Aeroflex Gaisler.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ */
+
+#ifndef __SPW_BUS_H__
+#define __SPW_BUS_H__
+
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/spw_bus_ids.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* SpW Bus Driver ID generation */
+#define DRIVER_SPWBUS_ID(vendor, device) \
+ DRIVER_ID(DRVMGR_BUS_TYPE_SPW_RMAP, ((((vendor) & 0xffff) << 16) | ((device) & 0xffff)))
+
+/* SpaceWire Driver IDs */
+#define DRIVER_SPW_RMAP_AMBAPP_ID 1
+
+/**** SpaceWire Driver IDs *****/
+#define SPW_NODE_ID_GRLIB DRIVER_SPWBUS_ID(SPWBUS_VENDOR_GAISLER,SPWBUS_DEVICE_GAISLER_GRLIB)
+
+
+/* SpaceWire Target ID */
+struct spw_id {
+ unsigned int spwid; /* SpaceWire Target ID */
+};
+#define SPW_NODE_ID_NONE 0
+
+/* SpaceWire Target Setup */
+struct spw_node {
+ struct spw_id id; /* Node ID */
+ char *name; /* Name of Target */
+ struct drvmgr_key *keys; /* Target setup (Destination address, Destination Key) */
+};
+
+/* spw_node.keys that must be defined for SpaceWire targets
+ * INTEGER DST_ADR SpaceWire Destination Address
+ * INTEGER DST_KEY RMAP Destination Key
+ */
+
+#define EMPTY_SPW_NODE {{SPW_NODE_ID_NONE}, NULL, NULL}
+
+/* Virtual IRQ to GPIO Pin translation */
+struct spwbus_virq_config {
+ char *gpio_fsname; /* GPIO Filesystem Name */
+ void *handle; /* If already opened, set "File descriptor" handle here */
+};
+
+/* SpaceWire Bus driver configuration */
+struct spw_bus_config {
+ void *rmap; /* RMAP Stack handle, note that it should be thread-safe */
+ int maxlen; /* Maximum length */
+ struct spw_node *nodes; /* Bus configuration (SpaceWire nodes available) */
+ char devName[32]; /* GRSPW Dev name bus is attached to */
+ struct drvmgr_bus_res *resources; /* Driver resouces present on the bus */
+ struct spwbus_virq_config virq_table[4]; /* Virtual IRQ number to GPIO translation table */
+};
+
+/* Register SpW Bus */
+int drv_mgr_spw_init(struct spw_bus_config *config);
+
+struct spw_bus_dev_info {
+ unsigned int spwid;
+
+ unsigned char dstadr;
+ unsigned char dstkey;
+ char virqs[4]; /* 4 virtual IRQs(VIRQ[1..4]) */
+};
+
+#define SPWBUS_VIRQ1 1
+#define SPWBUS_VIRQ2 2
+#define SPWBUS_VIRQ3 3
+#define SPWBUS_VIRQ4 4
+
+struct spw_bus_drv_info {
+ struct drvmgr_drv general; /* General bus info */
+ /* SpW RMAP specific bus information */
+ struct spw_id *ids; /* Supported target hardware */
+};
+
+/*** Bus operations with READ/WRITE access operations ***/
+#define SPWBUS_RW_ARG DRVMGR_RWFUNC(RW_ARG)
+#define SPWBUS_RW_ERR DRVMGR_RWFUNC(RW_ERR)
+#define SPWBUS_R8 DRVMGR_RWFUNC(RW_SIZE_1|RW_READ|RW_REG)
+#define SPWBUS_R16 DRVMGR_RWFUNC(RW_SIZE_2|RW_READ|RW_REG)
+#define SPWBUS_R32 DRVMGR_RWFUNC(RW_SIZE_4|RW_READ|RW_REG)
+#define SPWBUS_R64 DRVMGR_RWFUNC(RW_SIZE_8|RW_READ|RW_REG)
+#define SPWBUS_W8 DRVMGR_RWFUNC(RW_SIZE_1|RW_WRITE|RW_REG)
+#define SPWBUS_W16 DRVMGR_RWFUNC(RW_SIZE_2|RW_WRITE|RW_REG)
+#define SPWBUS_W32 DRVMGR_RWFUNC(RW_SIZE_4|RW_WRITE|RW_REG)
+#define SPWBUS_W64 DRVMGR_RWFUNC(RW_SIZE_8|RW_WRITE|RW_REG)
+#define SPWBUS_RMEM DRVMGR_RWFUNC(RW_SIZE_ANY|RW_READ|RW_MEM)
+#define SPWBUS_WMEM DRVMGR_RWFUNC(RW_SIZE_ANY|RW_WRITE|RW_MEM)
+#define SPWBUS_MEMSET DRVMGR_RWFUNC(RW_SIZE_ANY|RW_SET|RW_MEM)
+
+/* Read/Write function types with additional argument */
+typedef uint8_t (*spwbus_r8)(uint8_t *srcadr, struct drvmgr_rw_arg *a);
+typedef uint16_t (*spwbus_r16)(uint16_t *srcadr, struct drvmgr_rw_arg *a);
+typedef uint32_t (*spwbus_r32)(uint32_t *srcadr, struct drvmgr_rw_arg *a);
+typedef uint64_t (*spwbus_r64)(uint64_t *srcadr, struct drvmgr_rw_arg *a);
+typedef void (*spwbus_w8)(uint8_t *dstadr, uint8_t data, struct drvmgr_rw_arg *a);
+typedef void (*spwbus_w16)(uint16_t *dstadr, uint16_t data, struct drvmgr_rw_arg *a);
+typedef void (*spwbus_w32)(uint32_t *dstadr, uint32_t data, struct drvmgr_rw_arg *a);
+typedef void (*spwbus_w64)(uint64_t *dstadr, uint64_t data, struct drvmgr_rw_arg *a);
+
+/* READ/COPY a memory area located in 'src' to the destination 'dest', n=number of bytes */
+typedef int (*spwbus_rmem)(void *dest, const void *src, int n, struct drvmgr_rw_arg *a);
+
+/* WRITE/COPY a user buffer located in 'src' to the destination 'dest', n=number of bytes */
+typedef int (*spwbus_wmem)(void *dest, const void *src, int n, struct drvmgr_rw_arg *a);
+
+/* Set a memory area to the byte value given in c, see LIBC memset(). Memset is implemented by
+ * calling busops->write_mem multiple times with a zero buffer.
+ */
+typedef int (*spwbus_memset)(void *dstadr, int c, size_t n, struct drvmgr_rw_arg *a);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/include/drvmgr/spw_bus_ids.h b/c/src/lib/libbsp/sparc/shared/include/drvmgr/spw_bus_ids.h
new file mode 100644
index 0000000000..7ec5bdb46e
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/drvmgr/spw_bus_ids.h
@@ -0,0 +1,22 @@
+/* SpaceWire bus device IDs, these are all made up, because there is no such thing as
+ * Plug & Play on the SpW bus. This is just an attempt to structure the SpW bus driver.
+ *
+ * COPYRIGHT (c) 2009.
+ * Aeroflex Gaisler.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ */
+
+#ifndef __SPW_BUS_IDS_H__
+#define __SPW_BUS_IDS_H__
+
+/* SpW bus VENDOR IDs */
+#define SPWBUS_VENDOR_GAISLER 1 /* Aeroflex Gaisler AB */
+
+/* SpW bus DEVICE IDs for vendor GAISLER */
+#define SPWBUS_DEVICE_GAISLER_GRLIB 1 /* General GRLIB system */
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/include/genirq.h b/c/src/lib/libbsp/sparc/shared/include/genirq.h
new file mode 100644
index 0000000000..50b3e0a5e4
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/genirq.h
@@ -0,0 +1,94 @@
+#ifndef __GENIRQ_H__
+#define __GENIRQ_H__
+
+/* General Shared Interrupt handling function interface
+ *
+ * The functions does not manipulate the IRQ controller or the
+ * interrupt level of the CPU. It simply helps the caller with
+ * managing shared interrupts where multiple interrupt routines
+ * share on interrupt vector/number.
+ *
+ *
+ */
+
+typedef void (*genirq_handler)(void *arg);
+typedef void* genirq_t;
+
+struct genirq_stats {
+ unsigned int irq_cnt;
+};
+
+/* Initialize the genirq interface. Must be the first function
+ * called.
+ *
+ * Returns zero on success, otherwise failure.
+ */
+extern genirq_t genirq_init(int number_of_irqs);
+
+/* Free the dynamically allocated memory that the genirq interface has
+ * allocated.
+ *
+ * Returns zero on success, otherwise failure.
+ */
+extern void genirq_destroy(genirq_t d);
+
+/* Check IRQ number validity
+ *
+ * Returns zero for valid IRQ numbers, -1 of invalid IRQ numbers.
+ */
+extern int genirq_check(genirq_t d, int irq);
+
+/* Register shared interrupt handler.
+ *
+ * \param irq The interrupt number to register ISR on
+ * \param isr The interrupt service routine called upon IRQ
+ * \param arg The argument given to isr() when called.
+ *
+ * Return Values
+ * -1 = Failed
+ * 0 = Handler registered Successfully, first handler on this IRQ
+ * 1 = Handler registered Successfully, _not_ first handler on this IRQ
+ */
+extern int genirq_register(genirq_t d, int irq, genirq_handler isr, void *arg);
+
+/* Unregister an previous registered interrupt handler
+ *
+ * Return Values
+ * -1 = ISR not registered before
+ * 0 = ISR unregistered
+ * 1 = Unable to unregister enabled ISR
+ */
+extern int genirq_unregister(genirq_t d, int irq, genirq_handler isr, void *arg);
+
+/* Enables IRQ only for this isr[arg] combination. Records if this
+ * is the first interrupt enable, only then must interrupts be enabled
+ * on the interrupt controller.
+ *
+ * IRQs must be disabled before entering this function.
+ *
+ * Return values
+ * -1 = Failure, for example isr[arg] not registered on this irq
+ * 0 = IRQ must be enabled, it is the first IRQ handler to be enabled
+ * 1 = IRQ has already been enabled, either by isr[arg] or by another handler
+ */
+extern int genirq_enable(genirq_t d, int irq, genirq_handler isr, void *arg);
+
+/* Disables IRQ only for this isr[arg] combination. Records if this
+ * is the only interrupt handler that is enabled on this IRQ, only then
+ * must interrupts be disabled on the interrupt controller.
+ *
+ * IRQs must be disabled before entering this function.
+ *
+ * Return values
+ * -1 = Failure, for example isr[arg] not registered on this irq
+ * 0 = IRQ must be disabled, no ISR are enabled for this IRQ
+ * 1 = ISR has already been disabled, or other ISRs are still enabled
+ */
+extern int genirq_disable(genirq_t d, int irq, genirq_handler isr, void *arg);
+
+/* Must be called by user when an IRQ has fired, the argument 'irq'
+ * is the IRQ number of the IRQ which was fired.
+ */
+extern void genirq_doirq(genirq_t d, int irq);
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/include/gpiolib.h b/c/src/lib/libbsp/sparc/shared/include/gpiolib.h
new file mode 100644
index 0000000000..4b4ab1bc8f
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/gpiolib.h
@@ -0,0 +1,95 @@
+/* GPIO Library interface
+ *
+ * COPYRIGHT (c) 2009.
+ * Aeroflex Gaisler AB
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ */
+
+#ifndef __GPIOLIB_H__
+#define __GPIOLIB_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* GPIO Config of one GPIO port */
+struct gpiolib_config {
+ char mask; /* 0=Masked/1=Unmasked IRQ */
+ char irq_level; /* Edge or Level triggered IRQ */
+ char irq_polarity; /* Polarity of IRQ */
+};
+
+#define GPIOLIB_IRQ_EDGE 0
+#define GPIOLIB_IRQ_LEVEL 1
+
+#define GPIOLIB_IRQ_POL_LOW 0
+#define GPIOLIB_IRQ_POL_HIGH 1
+
+/* Libarary initialize function must be called befor any other */
+extern int gpiolib_initialize(void);
+
+/*** User Interface ***/
+
+extern void *gpiolib_open(int port);
+extern void *gpiolib_open_by_name(char *devName);
+extern void gpiolib_close(void *handle);
+
+/* Show the current status one or all GPIO ports in the system.
+ * Int port is port nunber, if port = -1 selects all ports.
+ *
+ * If port != -1, handle is used to get port.
+ * If port != -1, handle == NULL, then port is used as port number
+ */
+extern void gpiolib_show(int port, void *handle);
+
+extern int gpiolib_set_config(void *handle, struct gpiolib_config *cfg);
+extern int gpiolib_set(void *handle, int dir, int val);
+extern int gpiolib_get(void *handle, int *inval);
+extern int gpiolib_irq_clear(void *handle);
+extern int gpiolib_irq_enable(void *handle);
+extern int gpiolib_irq_disable(void *handle);
+extern int gpiolib_irq_mask(void *handle);
+extern int gpiolib_irq_unmask(void *handle);
+extern int gpiolib_irq_force(void *handle);
+extern int gpiolib_irq_register(void *handle, void *func, void *arg);
+
+/*** Driver Interface ***/
+
+struct gpiolib_info {
+ char devName[64];
+};
+
+struct gpiolib_drv_ops {
+ int (*config)(void *handle, struct gpiolib_config *cfg);
+ int (*get)(void *handle, int *val);
+ int (*irq_opts)(void *handle, unsigned int options);
+ int (*irq_register)(void *handle, void *func, void *arg);
+ int (*open)(void *handle);
+ int (*set)(void *handle, int dir, int outval);
+ int (*show)(void *handle);
+ int (*get_info)(void *handle, struct gpiolib_info *pinfo);
+};
+
+#define GPIOLIB_IRQ_ENABLE 0x01
+#define GPIOLIB_IRQ_DISABLE 0x02
+#define GPIOLIB_IRQ_CLEAR 0x04
+#define GPIOLIB_IRQ_FORCE 0x08
+#define GPIOLIB_IRQ_MASK 0x10
+#define GPIOLIB_IRQ_UNMASK 0x20
+
+struct gpiolib_drv {
+ struct gpiolib_drv_ops *ops;
+};
+
+/* Register a GPIO port */
+extern int gpiolib_drv_register(struct gpiolib_drv *drv, void *handle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/include/gr1553b.h b/c/src/lib/libbsp/sparc/shared/include/gr1553b.h
new file mode 100644
index 0000000000..4b566a013a
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/gr1553b.h
@@ -0,0 +1,369 @@
+#ifndef __GR1553B_H__
+#define __GR1553B_H__
+
+/* GR1553B driver, used by BC, RT and/or BM driver
+ *
+ * COPYRIGHT (c) 2010.
+ * Aeroflex Gaisler.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2010-03-15, Daniel Hellstrom <daniel@gaisler.com>
+ * Created
+ *
+ *
+ * OVERVIEW
+ * ========
+ * This driver controls the GR1553B device regardless of interfaces supported
+ * (BC, RT and/or BM). The device can be located at an on-chip AMBA or an
+ * AMBA-over-PCI bus. This driver provides an interface for the BC, RT and BM
+ * drivers to use. Since the different interfaces are accessed over the same
+ * register interface on the same core, the other drivers must share a GR1553B
+ * device. Any combination of interface functionality is supported, but the RT
+ * and BC functionality can nnot be used simultaneously due to hardware
+ * limitation.
+ *
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* The GR1553B registers */
+struct gr1553b_regs {
+ /* Common Registers */
+ volatile unsigned int irq; /* 0x00 IRQ register */
+ volatile unsigned int imask; /* 0x04 IRQ enable mask */
+ int unused0[(0x10-0x08)/4];
+ volatile unsigned int hwcfg; /* 0x10 HW config register */
+
+ int unused1[(0x40-0x14)/4]; /* Padding */
+
+ /* BC Registers */
+ volatile unsigned int bc_stat; /* 0x40 BC status */
+ volatile unsigned int bc_ctrl; /* 0x44 BC Action register */
+ volatile unsigned int bc_bd; /* 0x48 BC transfer list pointer */
+ volatile unsigned int bc_abd; /* 0x4c BC async list pointer */
+ volatile unsigned int bc_timer; /* 0x50 BC timer register */
+ volatile unsigned int bc_wake; /* 0x54 BC wakeup control register */
+ volatile unsigned int bc_irqptr;/* 0x58 BC transfer IRQ pointer */
+ volatile unsigned int bc_busmsk;/* 0x5C BC per-RT bus mask register */
+
+ int unused2[(0x68-0x60)/4]; /* Padding */
+
+ volatile unsigned int bc_slot; /* 0x48 BC Current BD pointer */
+ volatile unsigned int bc_aslot; /* 0x4c BC Current async BD pointer */
+
+ int unused3[(0x80-0x70)/4]; /* Padding */
+
+ /* RT Registers */
+ volatile unsigned int rt_stat; /* 0x80 RT status */
+ volatile unsigned int rt_cfg; /* 0x84 RT config register */
+ volatile unsigned int rt_stat2; /* 0x88 RT bus status bits */
+ volatile unsigned int rt_statw; /* 0x8c RT status words */
+ volatile unsigned int rt_sync; /* 0x90 RT bus synchronize */
+ volatile unsigned int rt_tab; /* 0x94 RT subaddress table base */
+ volatile unsigned int rt_mcctrl;/* 0x98 RT valid mode code mask */
+ int unused4[(0xa4-0x9c)/4];
+ volatile unsigned int rt_ttag; /* 0xa4 RT time tag register */
+ int unused5; /* 0xa8 RESERVED */
+ volatile unsigned int rt_evsz; /* 0xac RT event log end pointer */
+ volatile unsigned int rt_evlog; /* 0xb0 RT event log position */
+ volatile unsigned int rt_evirq; /* 0xb4 RT event log IRQ position */
+
+ int unused6[(0xc0-0xb8)/4]; /* Padding */
+
+ /* BM Registers */
+ volatile unsigned int bm_stat; /* 0xc0 BM status */
+ volatile unsigned int bm_ctrl; /* 0xc4 BM control register */
+ volatile unsigned int bm_adr; /* 0xc8 BM address filter */
+ volatile unsigned int bm_subadr;/* 0xcc BM subaddress filter */
+ volatile unsigned int bm_mc; /* 0xd0 BM mode code filter */
+ volatile unsigned int bm_start; /* 0xd4 BM log start address */
+ volatile unsigned int bm_end; /* 0xd8 BM log size/alignment mask */
+ volatile unsigned int bm_pos; /* 0xdc BM log position */
+ volatile unsigned int bm_ttag; /* 0xe0 BM time tag register */
+};
+
+#define GR1553BC_KEY 0x15520000
+#define GR1553RT_KEY 0x15530000
+
+/* IRQ Definitions */
+#define GR1553BC_IRQLOG_SIZE 64
+#define GR1553BC_IRQLOG_CNT (GR1553BC_IRQLOG_SIZE/sizeof(uint32_t))
+
+/*** IRQ Flag Register ***/
+#define GR1553B_IRQ_BCEV_BIT 0
+#define GR1553B_IRQ_BCD_BIT 1
+#define GR1553B_IRQ_BCWK_BIT 2
+#define GR1553B_IRQ_RTEV_BIT 8
+#define GR1553B_IRQ_RTD_BIT 9
+#define GR1553B_IRQ_RTTE_BIT 10
+#define GR1553B_IRQ_BMD_BIT 16
+#define GR1553B_IRQ_BMTOF_BIT 17
+
+#define GR1553B_IRQ_BCEV (1<<GR1553B_IRQ_BCEV_BIT)
+#define GR1553B_IRQ_BCD (1<<GR1553B_IRQ_BCD_BIT)
+#define GR1553B_IRQ_BCWK (1<<GR1553B_IRQ_BCWK_BIT)
+#define GR1553B_IRQ_RTEV (1<<GR1553B_IRQ_RTEV_BIT)
+#define GR1553B_IRQ_RTD (1<<GR1553B_IRQ_RTD_BIT)
+#define GR1553B_IRQ_RTTE (1<<GR1553B_IRQ_RTTE_BIT)
+#define GR1553B_IRQ_BMD (1<<GR1553B_IRQ_BMD_BIT)
+#define GR1553B_IRQ_BMTOF (1<<GR1553B_IRQ_BMTOF_BIT)
+
+/*** IRQ Enable Register ***/
+#define GR1553B_IRQEN_BCEVE_BIT 0
+#define GR1553B_IRQEN_BCDE_BIT 1
+#define GR1553B_IRQEN_BCWKE_BIT 2
+#define GR1553B_IRQEN_RTEVE_BIT 8
+#define GR1553B_IRQEN_RTDE_BIT 9
+#define GR1553B_IRQEN_RTTEE_BIT 10
+#define GR1553B_IRQEN_BMDE_BIT 16
+#define GR1553B_IRQEN_BMTOE_BIT 17
+
+#define GR1553B_IRQEN_BCEVE (1<<GR1553B_IRQEN_BCEVE_BIT)
+#define GR1553B_IRQEN_BCDE (1<<GR1553B_IRQEN_BCDE_BIT)
+#define GR1553B_IRQEN_BCWKE (1<<GR1553B_IRQEN_BCWKE_BIT)
+#define GR1553B_IRQEN_RTEVE (1<<GR1553B_IRQEN_RTEVE_BIT)
+#define GR1553B_IRQEN_RTDE (1<<GR1553B_IRQEN_RTDE_BIT)
+#define GR1553B_IRQEN_RTTEE (1<<GR1553B_IRQEN_RTTEE_BIT)
+#define GR1553B_IRQEN_BMDE (1<<GR1553B_IRQEN_BMDE_BIT)
+#define GR1553B_IRQEN_BMTOE (1<<GR1553B_IRQEN_BMTOE_BIT)
+
+/*** BC Status Register ***/
+#define GR1553B_BC_STAT_SCST_BIT 0
+#define GR1553B_BC_STAT_SCADL_BIT 3
+#define GR1553B_BC_STAT_ASST_BIT 8
+#define GR1553B_BC_STAT_ASADL_BIT 11
+#define GR1553B_BC_STAT_BCSUP_BIT 31
+
+#define GR1553B_BC_STAT_SCST (0x3<<GR1553B_BC_STAT_SCST_BIT)
+#define GR1553B_BC_STAT_SCADL (0x1f<<GR1553B_BC_STAT_SCADL_BIT)
+#define GR1553B_BC_STAT_ASST (0x3<<GR1553B_BC_STAT_ASST_BIT)
+#define GR1553B_BC_STAT_ASADL (0x1f<<GR1553B_BC_STAT_ASADL_BIT)
+#define GR1553B_BC_STAT_BCSUP (1<<GR1553B_BC_STAT_BCSUP_BIT)
+
+/*** BC Action Register ***/
+#define GR1553B_BC_ACT_SCSRT_BIT 0
+#define GR1553B_BC_ACT_SCSUS_BIT 1
+#define GR1553B_BC_ACT_SCSTP_BIT 2
+#define GR1553B_BC_ACT_SETT_BIT 3
+#define GR1553B_BC_ACT_CLRT_BIT 4
+#define GR1553B_BC_ACT_ASSRT_BIT 8
+#define GR1553B_BC_ACT_ASSTP_BIT 9
+#define GR1553B_BC_ACT_BCKEY_BIT 16
+
+#define GR1553B_BC_ACT_SCSRT (1<<GR1553B_BC_ACT_SCSRT_BIT)
+#define GR1553B_BC_ACT_SCSUS (1<<GR1553B_BC_ACT_SCSUS_BIT)
+#define GR1553B_BC_ACT_SCSTP (1<<GR1553B_BC_ACT_SCSTP_BIT)
+#define GR1553B_BC_ACT_SETT (1<<GR1553B_BC_ACT_SETT_BIT)
+#define GR1553B_BC_ACT_CLRT (1<<GR1553B_BC_ACT_CLRT_BIT)
+#define GR1553B_BC_ACT_ASSRT (1<<GR1553B_BC_ACT_ASSRT_BIT)
+#define GR1553B_BC_ACT_ASSTP (1<<GR1553B_BC_ACT_ASSTP_BIT)
+#define GR1553B_BC_ACT_BCKEY (0xffff<<GR1553B_BC_ACT_BCKEY_BIT)
+
+/*** BC Timer Register ***/
+#define GR1553B_BC_TIMER_SCTM_BIT 0
+
+#define GR1553B_BC_TIMER_SCTM (0xffffff<<GR1553B_BC_TIMER_SCTM_BIT)
+
+/*** BC Wake-up control Register ***/
+#define GR1553B_BC_WAKE_TIME_BIT 0
+#define GR1553B_BC_WAKE_WKEN_BIT 31
+
+#define GR1553B_BC_WAKE_TIME (0xffffff<<GR1553B_BC_WAKE_TIME_BIT)
+#define GR1553B_BC_WAKE_WKEN (1<GR1553B_BC_WAKE_WKEN_BIT)
+
+/*** RT status Register ***/
+#define GR1553B_RT_STAT_RUN_BIT 0
+#define GR1553B_RT_STAT_SHDB_BIT 1
+#define GR1553B_RT_STAT_SHDA_BIT 2
+#define GR1553B_RT_STAT_ACT_BIT 3
+#define GR1553B_RT_STAT_RTSUP_BIT 31
+
+#define GR1553B_RT_STAT_RUN (1<<GR1553B_RT_STAT_RUN_BIT)
+#define GR1553B_RT_STAT_SHDB (1<<GR1553B_RT_STAT_SHDB_BIT)
+#define GR1553B_RT_STAT_SHDA (1<<GR1553B_RT_STAT_SHDA_BIT)
+#define GR1553B_RT_STAT_ACT (1<<GR1553B_RT_STAT_ACT_BIT)
+#define GR1553B_RT_STAT_RTSUP (1<<GR1553B_RT_STAT_RTSUP_BIT)
+
+
+/*** RT Config Register ***/
+#define GR1553B_RT_CFG_RTEN_BIT 0
+#define GR1553B_RT_CFG_RTADDR_BIT 1
+#define GR1553B_RT_CFG_RTKEY_BIT 16
+
+#define GR1553B_RT_CFG_RTEN (1<<GR1553B_RT_CFG_RTEN_BIT)
+#define GR1553B_RT_CFG_RTADDR (1<<GR1553B_RT_CFG_RTADDR_BIT)
+#define GR1553B_RT_CFG_RTKEY (0xffff<<GR1553B_RT_CFG_RTKEY_BIT)
+
+/*** RT Bus Status Register ***/
+#define GR1553B_RT_STAT2_RTEN_BIT 0
+#define GR1553B_RT_STAT2_DBCA_BIT 1
+#define GR1553B_RT_STAT2_SSF_BIT 2
+#define GR1553B_RT_STAT2_BUSY_BIT 3
+#define GR1553B_RT_STAT2_SREQ_BIT 4
+
+#define GR1553B_RT_STAT2_RTEN (1<<GR1553B_RT_STAT2_RTEN_BIT)
+#define GR1553B_RT_STAT2_DBCA (1<<GR1553B_RT_STAT2_DBCA_BIT)
+#define GR1553B_RT_STAT2_SSF (1<<GR1553B_RT_STAT2_SSF_BIT)
+#define GR1553B_RT_STAT2_BUSY (1<<GR1553B_RT_STAT2_BUSY_BIT)
+#define GR1553B_RT_STAT2_SREQ (1<<GR1553B_RT_STAT2_RTEN_BIT)
+
+/*** RT Status Words Register ***/
+#define GR1553B_RT_STATW_VECW_BIT 0
+#define GR1553B_RT_STATW_BITW_BIT 16
+
+#define GR1553B_RT_STATW_VECW (0xffff<<GR1553B_RT_STATW_VECW_BIT)
+#define GR1553B_RT_STATW_BITW (0xffff<<GR1553B_RT_STATW_BITW_BIT)
+
+/*** RT Sync Register ***/
+#define GR1553B_RT_SYNC_SYD_BIT 0
+#define GR1553B_RT_SYNC_SYTM_BIT 16
+
+#define GR1553B_RT_SYNC_SYD (0xffff<<GR1553B_RT_SYNC_SYD_BIT)
+#define GR1553B_RT_SYNC_SYTM (0xffff<<GR1553B_RT_SYNC_SYTM_BIT)
+
+/*** RT Sub adress table Register ***/
+#define GR1553B_RT_TAB_SATB_BIT 0
+
+#define GR1553B_RT_TAB_SATB (0xffff<<GR1553B_RT_TAB_SATB_BIT)
+
+/*** RT Mode code control Register ***/
+#define GR1553B_RT_MCCTRL_S_BIT 0
+#define GR1553B_RT_MCCTRL_SB_BIT 2
+#define GR1553B_RT_MCCTRL_SD_BIT 4
+#define GR1553B_RT_MCCTRL_SDB_BIT 6
+#define GR1553B_RT_MCCTRL_TS_BIT 8
+#define GR1553B_RT_MCCTRL_TSB_BIT 10
+#define GR1553B_RT_MCCTRL_TVW_BIT 12
+#define GR1553B_RT_MCCTRL_TBW_BIT 14
+#define GR1553B_RT_MCCTRL_DBC_BIT 16
+#define GR1553B_RT_MCCTRL_IST_BIT 18
+#define GR1553B_RT_MCCTRL_ISTB_BIT 20
+#define GR1553B_RT_MCCTRL_ITF_BIT 22
+#define GR1553B_RT_MCCTRL_ITFB_BIT 24
+#define GR1553B_RT_MCCTRL_RRT_BIT 26
+#define GR1553B_RT_MCCTRL_RRTB_BIT 28
+
+#define GR1553B_RT_MCCTRL_S (1<<GR1553B_RT_MCCTRL_S_BIT)
+#define GR1553B_RT_MCCTRL_SB (1<<GR1553B_RT_MCCTRL_SB_BIT)
+#define GR1553B_RT_MCCTRL_SD (1<<GR1553B_RT_MCCTRL_SD_BIT)
+#define GR1553B_RT_MCCTRL_SDB (1<<GR1553B_RT_MCCTRL_SDB_BIT)
+#define GR1553B_RT_MCCTRL_TS (1<<GR1553B_RT_MCCTRL_TS_BIT)
+#define GR1553B_RT_MCCTRL_TSB (1<<GR1553B_RT_MCCTRL_TSB_BIT)
+#define GR1553B_RT_MCCTRL_TVW (1<<GR1553B_RT_MCCTRL_TVW_BIT)
+#define GR1553B_RT_MCCTRL_TBW (1<<GR1553B_RT_MCCTRL_TBW_BIT)
+#define GR1553B_RT_MCCTRL_DBC (1<<GR1553B_RT_MCCTRL_DBC_BIT)
+#define GR1553B_RT_MCCTRL_IST (1<<GR1553B_RT_MCCTRL_IST_BIT)
+#define GR1553B_RT_MCCTRL_ISTB (1<<GR1553B_RT_MCCTRL_ISTB_BIT)
+#define GR1553B_RT_MCCTRL_ITF (1<<GR1553B_RT_MCCTRL_ITF_BIT)
+#define GR1553B_RT_MCCTRL_ITFB (1<<GR1553B_RT_MCCTRL_ITFB_BIT)
+#define GR1553B_RT_MCCTRL_RRT (1<<GR1553B_RT_MCCTRL_RRT_BIT)
+#define GR1553B_RT_MCCTRL_RRTB (1<<GR1553B_RT_MCCTRL_RRTB_BIT)
+
+/*** RT Time Tag control Register ***/
+#define GR1553B_RT_TTAG_TVAL_BIT 0
+#define GR1553B_RT_TTAG_TRES_BIT 16
+
+#define GR1553B_RT_TTAG_TVAL (0xffff<<GR1553B_RT_TTAG_TVAL_BIT)
+#define GR1553B_RT_TTAG_TRES (0xffff<<GR1553B_RT_TTAG_TRES_BIT)
+
+/*** BM Control Register ***/
+#define GR1553B_BM_STAT_BMSUP_BIT 31
+
+#define GR1553B_BM_STAT_BMSUP (1<<GR1553B_BM_STAT_BMSUP_BIT)
+
+/*** BM Control Register ***/
+#define GR1553B_BM_CTRL_BMEN_BIT 0
+#define GR1553B_BM_CTRL_MANL_BIT 1
+#define GR1553B_BM_CTRL_UDWL_BIT 2
+#define GR1553B_BM_CTRL_IMCL_BIT 3
+
+#define GR1553B_BM_CTRL_BMEN (1<<GR1553B_BM_CTRL_BMEN_BIT)
+#define GR1553B_BM_CTRL_MANL (1<<GR1553B_BM_CTRL_MANL_BIT)
+#define GR1553B_BM_CTRL_UDWL (1<<GR1553B_BM_CTRL_UDWL_BIT)
+#define GR1553B_BM_CTRL_IMCL (1<<GR1553B_BM_CTRL_IMCL_BIT)
+
+/*** BM RT Mode code filter Register ***/
+#define GR1553B_BM_MC_S_BIT 0
+#define GR1553B_BM_MC_SB_BIT 1
+#define GR1553B_BM_MC_SD_BIT 2
+#define GR1553B_BM_MC_SDB_BIT 3
+#define GR1553B_BM_MC_TS_BIT 4
+#define GR1553B_BM_MC_TSB_BIT 5
+#define GR1553B_BM_MC_TVW_BIT 6
+#define GR1553B_BM_MC_TBW_BIT 7
+#define GR1553B_BM_MC_DBC_BIT 8
+#define GR1553B_BM_MC_IST_BIT 9
+#define GR1553B_BM_MC_ISTB_BIT 10
+#define GR1553B_BM_MC_ITF_BIT 11
+#define GR1553B_BM_MC_ITFB_BIT 12
+#define GR1553B_BM_MC_RRT_BIT 13
+#define GR1553B_BM_MC_RRTB_BIT 14
+#define GR1553B_BM_MC_TSW_BIT 15
+#define GR1553B_BM_MC_TLC_BIT 16
+#define GR1553B_BM_MC_STS_BIT 17
+#define GR1553B_BM_MC_STSB_BIT 18
+
+#define GR1553B_BM_MC_S (1<<GR1553B_BM_MC_S_BIT)
+#define GR1553B_BM_MC_SB (1<<GR1553B_BM_MC_SB_BIT)
+#define GR1553B_BM_MC_SD (1<<GR1553B_BM_MC_SD_BIT)
+#define GR1553B_BM_MC_SDB (1<<GR1553B_BM_MC_SDB_BIT)
+#define GR1553B_BM_MC_TS (1<<GR1553B_BM_MC_TS_BIT)
+#define GR1553B_BM_MC_TSB (1<<GR1553B_BM_MC_TSB_BIT)
+#define GR1553B_BM_MC_TVW (1<<GR1553B_BM_MC_TVW_BIT)
+#define GR1553B_BM_MC_TBW (1<<GR1553B_BM_MC_TBW_BIT)
+#define GR1553B_BM_MC_DBC (1<<GR1553B_BM_MC_DBC_BIT)
+#define GR1553B_BM_MC_IST (1<<GR1553B_BM_MC_IST_BIT)
+#define GR1553B_BM_MC_ISTB (1<<GR1553B_BM_MC_ISTB_BIT)
+#define GR1553B_BM_MC_ITF (1<<GR1553B_BM_MC_ITF_BIT)
+#define GR1553B_BM_MC_ITFB (1<<GR1553B_BM_MC_ITFB_BIT)
+#define GR1553B_BM_MC_RRT (1<<GR1553B_BM_MC_RRT_BIT)
+#define GR1553B_BM_MC_RRTB (1<<GR1553B_BM_MC_RRTB_BIT)
+#define GR1553B_BM_MC_TSW (1<<GR1553B_BM_MC_TSW_BIT)
+#define GR1553B_BM_MC_TLC (1<<GR1553B_BM_MC_TLC_BIT)
+#define GR1553B_BM_MC_STS (1<<GR1553B_BM_MC_STS_BIT)
+#define GR1553B_BM_MC_STSB (1<<GR1553B_BM_MC_STSB_BIT)
+
+/*** BM RT Mode code filter Register ***/
+#define GR1553B_BM_TTAG_VAL_BIT 0
+#define GR1553B_BM_TTAG_RES_BIT 24
+
+#define GR1553B_BM_TTAG_VAL (0xffffff<<GR1553B_BM_TTAG_VAL_BIT)
+#define GR1553B_BM_TTAG_RES (0xff<<GR1553B_BM_TTAG_RES_BIT)
+
+/* Register GR1553B driver */
+extern void gr1553_register(void);
+
+/*** BC Device allocation ***/
+/* Allocate a BC device. Minor is assigned to a device in the order
+ * they are registered to the driver.
+ */
+extern struct drvmgr_dev **gr1553_bc_open(int minor);
+/* Free a BC device previously allocated */
+extern void gr1553_bc_close(struct drvmgr_dev **dev);
+
+/*** RT Device allocation ***/
+/* Allocate a BC device. Minor is assigned to a device in the order
+ * they are registered to the driver.
+ */
+extern struct drvmgr_dev **gr1553_rt_open(int minor);
+/* Free a BC device previously allocated */
+extern void gr1553_rt_close(struct drvmgr_dev **dev);
+
+/*** BM Device allocation ***/
+/* Allocate a BC device. Minor is assigned to a device in the order
+ * they are registered to the driver.
+ */
+extern struct drvmgr_dev **gr1553_bm_open(int minor);
+/* Free a BC device previously allocated */
+extern void gr1553_bm_close(struct drvmgr_dev **dev);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GR1553B_H__ */
diff --git a/c/src/lib/libbsp/sparc/shared/include/gr1553bc.h b/c/src/lib/libbsp/sparc/shared/include/gr1553bc.h
new file mode 100644
index 0000000000..4157dc6cba
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/gr1553bc.h
@@ -0,0 +1,254 @@
+#ifndef __GR1553BC_H__
+#define __GR1553BC_H__
+
+/* GR1553B BC driver
+ *
+ * COPYRIGHT (c) 2010.
+ * Aeroflex Gaisler.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2010-03-15, Daniel Hellstrom <daniel@gaisler.com>
+ * Created
+ *
+ *
+ * OVERVIEW
+ * ========
+ * This driver controls the BC device, located at an on-chip AMBA or an
+ * AMBA-over-PCI bus. The driver operates the BC device and provides you
+ * with interrupt services and core control. The driver start execution of
+ * a synchronuos and/or an asynchronous BC descriptor List. The list contains
+ * a descriptor table and a software description to make some operations
+ * possible, for example translate descriptor-address into descriptor-number.
+ *
+ * BC descriptors are generated by the list API, available in gr1553bc_list.h.
+ *
+ * See gr1553bc_list.h for more information.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Forward declaration */
+struct gr1553bc_list;
+struct gr1553bc_major;
+struct gr1553bc_minor;
+struct gr1553bc_minor_cfg;
+struct gr1553bc_major_cfg;
+
+#ifdef __cplusplus
+}
+#endif
+
+#include <stdint.h>
+#include <gr1553bc_list.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Register GR1553B driver needed by BC driver */
+extern void gr1553bc_register(void);
+
+/* A BC descriptor accessed as is */
+struct gr1553bc_bd_raw {
+ volatile uint32_t words[4];
+};
+
+/* A BC descriptor accessed as a transfer descriptor */
+struct gr1553bc_bd_tr {
+ volatile uint32_t settings[2];
+ volatile uint32_t dptr;
+ volatile uint32_t status;
+};
+
+/* A BC descriptor accessed as a conditional descriptor */
+struct gr1553bc_bd_cond {
+ volatile uint32_t cond;
+ volatile uint32_t bdptr;
+ volatile uint32_t padding[2];
+};
+
+/* A BC descriptor accessed any way */
+union gr1553bc_bd {
+ struct gr1553bc_bd_raw raw;
+ struct gr1553bc_bd_tr tr;
+ struct gr1553bc_bd_cond cond;
+};
+
+/* Current state of the BC hardware */
+struct gr1553bc_status {
+ unsigned int status;
+ unsigned int time;
+};
+
+#define KEEP_TIMESLOT 0x10
+/* Initialize a BC descriptor. The words written is controllable by
+ * the flags argument.
+ *
+ * flags:
+ * bit[N=0..3]: 1 = set BD wordN according to argument wordN,
+ * 0 = do not modify BD wordN
+ *
+ * If bit KEEP_TIMESLOT is set the time slot of word0 is preserved,
+ * this bit only have an affect when the descriptor is a transfer
+ * descriptor.
+ */
+extern void gr1553bc_bd_init(
+ union gr1553bc_bd *bd,
+ unsigned int flags,
+ uint32_t word0,
+ uint32_t word1,
+ uint32_t word2,
+ uint32_t word3
+ );
+
+/* Initialize a Transfer descriptor
+ *
+ * Arguments:
+ * struct gr1553bc_bd_tr *bd
+ * uint32_t setting0
+ * uint32_t setting1
+ * uint32_t data
+ * uint32_t status
+ */
+#define gr1553bc_bd_tr_init(bd, set0, set1, data, status) \
+ gr1553bc_bd_init((union gr1553bc_bd *)bd,\
+ 0xf, set0, set1, data, status)
+/* Initializa a Condition descriptor
+ *
+ * Arguments:
+ * struct gr1553bc_bd_cond *bd
+ * uint32_t cond
+ * uint32_t jump_adr
+ */
+#define gr1553bc_bd_cond_init(bd, cond, jump_adr) \
+ gr1553bc_bd_init((union gr1553bc_bd *)bd, \
+ 0xf, cond, jump_adr, 0, 0)
+
+/* Size of a descriptor */
+#define GR1553BC_BD_SIZE sizeof(struct gr1553bc_bd_raw)
+
+/* Alignment of a descriptor */
+#define GR1553BC_BD_ALIGN 16
+
+/* End of list marker */
+#define GR1553BC_TR_EOL 0x80ffffff
+
+#define GR1553BC_BD_TYPE 0x80000000
+
+/* Condition descriptor bits */
+#define GR1553BC_UNCOND_JMP 0x820000ff
+#define GR1553BC_UNCOND_IRQ 0x860000ff
+#define GR1553BC_UNCOND_NOJMP 0x82000000
+
+/* Transfer descriptor bits */
+#define GR1553BC_TR_DUMMY_0 0x00000000
+#define GR1553BC_TR_DUMMY_1 0x80000000
+
+#define GR1553BC_TR_TIME 0x0000ffff
+
+#define GR1553BC_TR_EXTTRIG 0x40000000
+
+/* Take a GR1553BC hardware device identified by instance index (minor).
+ * A pointer is returned that is used internally by the GR1553BC
+ * driver, it is used as an input paramter 'bc' to all other
+ * functions that manipulate the hardware.
+ */
+extern void *gr1553bc_open(int minor);
+
+extern void gr1553bc_close(void *bc);
+
+/* Stores Current Major/Minor frame number and the Slot number executing
+ * into the location indicated by 'mid'. There may be two lists executing
+ * in "parallel", the 'async' argument select for which list the MID is
+ * looked up, the Syncronous (async=0) list or the Asynchronous (async=1)
+ * list.
+ *
+ */
+extern int gr1553bc_indication(void *bc, int async, int *mid);
+
+/* Trigger external time sync by writing to the BC action register.
+ * This may be good for debugging or if the time management is
+ * implemented in software.
+ *
+ * if trig=0 the external trigger memory is cleared.
+ * if trig!=0 the external trigger memory is set.
+ */
+extern void gr1553bc_ext_trig(void *bc, int trig);
+
+/* Configure the GR1553BC driver */
+/*extern int gr1553bc_config(struct gr1553bc_config *cfg);*/
+
+/* Start major frame processing. At least one list pointer must be
+ * non-zero to affect BC operation. The BC communication is enabled
+ * depending on list and Interrupts are enabled. This function can
+ * be called multiple times.
+ *
+ * If a list is already executing it will be replaced with the new
+ * list.
+ *
+ * list - Schedule Transfer List
+ * list_async - Asynchronous list
+ */
+extern int gr1553bc_start
+ (
+ void *bc,
+ struct gr1553bc_list *list,
+ struct gr1553bc_list *list_async
+ );
+
+/* Pause GR1553B BC scheduled transfers.
+ *
+ * Does not affect asynchronous operation.
+ */
+extern int gr1553bc_pause(void *bc);
+
+/* Restart GR1553B BC scheduled transfers, after being paused
+ *
+ * Does not affect asynchronous operation.
+ */
+extern int gr1553bc_restart(void *bc);
+
+/* Stop BC transmission.
+ *
+ * OPTIONS
+ * bit0 - 1=STOP schedule list
+ * bit1 - 1=STOP asynchronous list
+ */
+extern int gr1553bc_stop(void *bc, int options);
+
+/* Standard IRQ function setup. IRQ can be generated by condition descriptors
+ * or by transfer descriptors or by errors.
+ *
+ * Condition descriptors are inserted into the list by user, each condition
+ * may have a custom function and data assigned to it, see
+ * gr1553bc_slot_irq_prepare(). IRQs generated by condition descriptors are
+ * not handled by this function.
+ *
+ * Transfer descriptors can generate IRQ if enabled by user.
+ *
+ * IRQs generated by transfer descriptors or by BC errors (DMA error etc.)
+ * is handled by this standard ISR handler.
+ */
+extern int gr1553bc_irq_setup
+ (
+ void *bc,
+ bcirq_func_t func,
+ void *data
+ );
+
+/* Get Current BC hardware state/status. The Status is stored into the
+ * area pointed to by status. See "struct gr1553bc_status" for more
+ * info.
+ */
+extern void gr1553bc_status(void *bc, struct gr1553bc_status *status);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GR1553BC_H__ */
diff --git a/c/src/lib/libbsp/sparc/shared/include/gr1553bc_list.h b/c/src/lib/libbsp/sparc/shared/include/gr1553bc_list.h
new file mode 100644
index 0000000000..be043f0b33
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/gr1553bc_list.h
@@ -0,0 +1,709 @@
+#ifndef __GR1553BC_LIST_H__
+#define __GR1553BC_LIST_H__
+/*
+ * GR1553B BC driver, Descriptor LIST handling
+ *
+ * COPYRIGHT (c) 2010.
+ * Aeroflex Gaisler.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2010-03-15, Daniel Hellstrom <daniel@gaisler.com>
+ * Created
+ */
+
+/*!\file doc/gr1553bc_list.h
+ * \brief GR1553B BC driver
+ *
+ * \section OVERVIEW
+ *
+ * The BC device driver can schedule synchronous and asynchronous lists
+ * of descriptors. The list contains a descriptor table and a software
+ * description to make some operations possible, for example translate
+ * descriptor-address into descriptor-number.
+ *
+ * This is the LIST API. It provides functionality to create and manage
+ * a BC descriptor list.
+ *
+ * A list is built up by the following build blocks:
+ * - Major Frame (Consists of N Minor Frames)
+ * - Minor Frame (Consists of up to 32 1553 Message Slots)
+ * - Message Slot (Transfer/Condition BC descriptor)
+ *
+ * The user can configure lists with different configuration of number of
+ * Major Frames, Minor Frame and messages slots within a Minor Frame. The
+ * List manages a strait descriptor table (may be changed) and a Frame/Slot
+ * tree in order to easily find it's way through all descriptor created.
+ *
+ * Each Minor frame consist of up to 32 message slot and 2 message slots
+ * for time management and descriptor find operations. The list can manage
+ * time slots per minor frame, for example a minor frame may be programmed
+ * to take 8ms and when the user allocate a message slot within that Minor
+ * frame the time spcified will be subtracted from the 8ms, and when the
+ * message slot is freed the time will be returned to the Minor frame again.
+ *
+ * A Major, Minor and Message Slots are identified using a MID (Message-ID).
+ * The MID is a way for the user to avoid using pointers are talk with the
+ * list API in an easier way. For example a condition Slot that should jump
+ * to a transfer slot can be created by knowing "MID and Jump-To-MID". When
+ * allocating a Slot (with or without time) the user may specify a certain
+ * Slot or a Minor frame, when a Minor frame is given then the API will find
+ * a free Slot as early in the Minor Frame as possible and return it to the
+ * user.
+ *
+ * A MID can be created using the macros:
+ * GR1553BC_ID(major,minor,slot) - ID of a SLOT
+ * GR1553BC_MINOR_ID(major,minor) - ID of a MINOR (Slot=0xff)
+ * GR1553BC_MAJOR_ID(major) - ID of a Major (Minor=0xff,Slot=0xff)
+ *
+ * The typical approach create lists is in the following order:
+ * -# gr1553bc_list_alloc(&list, MAJOR_CNT)
+ * -# gr1553bc_list_config(list, &listcfg)
+ * -# Create all Major Frames and Minor frame, for each major frame:
+ * a) gr1553bc_major_alloc_skel(&major, &major_minor_cfg)
+ * b) gr1553bc_list_set_major(list, &major, MAJOR_NUM)
+ * -# link end Major Frames together:
+ * a) gr1553bc_list_set_major(&major7, &major0) // Connect Major frames
+ * -# gr1553bc_list_table_alloc() (Allocate Descriptor Table)
+ * -# gr1553bc_list_table_build() (Build Descriptor Table from Majors/Minors)
+ * -# Allocate and initialize Descriptors pre defined before starting:
+ * -## gr1553bc_slot_alloc(list, &MID, TIME_REQUIRED, ..)
+ * -## gr1553bc_slot_transfer(MID, ...)
+ * -# START BC HARDWARE BY SHCDULING ABOVE LIST
+ * -# Operate on List
+ *
+ *
+ * \section bc_list_update Changing a scheduled BC list (during BC-runtime)
+ *
+ * One can use the INDICATION service to avoid modifying
+ * a descriptor currently in use by the BC core. One can also in most cases
+ * do descriptor initialization in three steps: Init Descriptor as Dummy
+ * with and allocated time (often done before starting/scheduling list),
+ * then modify transfer options and data-pointers, then clear the Dummy
+ * bit in one atomic data store. This approach will avoid potential races
+ * between software has hardware.
+ *
+ *
+ * \section bc_memory_setup Custom Memory Setup
+ *
+ * For designs where dynamically memory is not an option, or the driver
+ * is used on a AMBA-over-PCI bus (where malloc() does not work), the
+ * API allows the user to provide custom addresses for descriptor table
+ * and object descriptions (lists, major frames, minor frames). Custom
+ * descriptor table is probably the most interesting thing for most, it
+ * is setup with gr1553bc_list_table_alloc(list, CUSTOM_ADDRESS).
+ *
+ * Object descriptions are normally allocated during initialization
+ * procedure by providing the API with a object configuration, for
+ * example a Major Frame configuration enables the API to allocate
+ * the software description of a Major Frame with all it's Minor frames.
+ *
+ *
+ * \section major Major Frame
+ *
+ * Consists of multiple Minor frames. A Major frame may be connected/linked
+ * with another Major frame, this will result in a Jump Slot from last
+ * Minor frame in the first Major to the first Minor in the second Major.
+ *
+ *
+ * \section minor Minor Frame
+ *
+ * Consists of up to 32 Message Slots. The services are Time-Management and
+ * Slot allocation.
+ *
+ * Time-Management is optional.
+ *
+ * Time-Slot-Management can be enabled per Minor frame. A Minor frame can be
+ * assigned a time in microseconds. The BC will not continue to the next
+ * Minor frame until the time has passed. It is managed by adding an extra
+ * Dummy Message Slot with the total minor frame time. Each time a message
+ * Slot is allocated (with a certain time: Slot-Time) the Slot-Time will
+ * be decremented from the total time of the Minor frame. This way the
+ * sum of the Message Slot will always sum up to the total time of the
+ * Minor configuration. When a message slot is freed, the Dymmy Message
+ * Slot's Slot-Time is incremented with the freed Slot-Time.
+ *
+ * A Message Slot can be allocated by identifying a specific free Slot
+ * by the MID (Message-ID) or by letting the API allocate the first free
+ * Slot in the Minor Frame (Set MID Slot-ID to 0xff to identify Minor
+ * Frame).
+ *
+ *
+ * \section slot Message Slot
+ *
+ * The GR1553B BC core supports two Slot (Descriptor) Types:
+ * - Transfer descriptor
+ * - Condition descriptor (Jump, unconditional-IRQ)
+ *
+ * See the hardware manual for a detail description of a descriptor (Slot).
+ *
+ * The BC Core is unaware of lists, it steps through executing each
+ * descriptor as the encountered, Conditionals resulting in jumps may
+ * let us to create more complex arrangements of buffer descriptos (BDs)
+ * which we call list.
+ *
+ * Transfer BDs (TBDs) may have a time slot assigned, the BC core will wait
+ * until the time has expired before executing the next descriptor. Time
+ * slots are handled by a Minor frame in the list.
+ *
+ * A Message Slot is allocated using the gr1553bc_slot_alloc() function,
+ * and configured by calling one of the below functions:
+ * - gr1553bc_slot_irq_prepare [unconditional IRQ slot]
+ * - gr1553bc_slot_jump [unconditional jump]
+ * - gr1553bc_slot_exttrig [Dummy transfer, wait for EXTERNAL-TRIGGER]
+ * - gr1553bc_slot_transfer [Transfer descriptor]
+ * - gr1553bc_slot_empty [Create Dummy Transfer descriptor]
+ * - gr1553bc_slot_raw [Custom Descriptor handling]
+ *
+ * - gr1553bc_slot_dummy [Set existing Transfer descriptor to Dummy]
+ * - gr1553bc_slot_update [Update DataPointer|Status of a TBD]
+ *
+ *
+ * \section bc_IRQ Interrupt Handling
+ *
+ * There are different types of interrupts, Error IRQs or transfer IRQs. The
+ * Error IRQs are handled by the driver can a callback function is called.
+ *
+ * Transfer Descriptors can be programmed to generate interrupt, and
+ * condition descriptors can be programmed to generate interrupt
+ * unconditionaly (there exists more conditional types). When a Transfer
+ * descriptor causes IRQ the general ISR callback of the BC driver is
+ * called to let the user handle the interrupt. When a condition descriptor
+ * causes an IRQ a custom IRQ handler is called (if assigned).
+ *
+ * Transfers descriptor IRQ is enabled by configuring the descriptor.
+ *
+ * The API provides functions for placing unconditional IRQ points anywhere
+ * in the list. The order:
+ * -# gr1553bc_slot_alloc(&MID, TIME=0, ..)
+ * -# gr1553bc_slot_irq_prepare(MID, funcISR, data)
+ * -# gr1553bc_slot_irq_enable(MID)
+ *
+ * \verbatim
+ * void funcISR(*bd, *data)
+ * {
+ * // HANDLE ONE OR MULTIPLE DESCRIPTORS (MULTIPLE IN THIS EXAMPLE):
+ * int MID;
+ * gr1553bc_mid_from_bd(bd,&MID,NULL);
+ * printf("IRQ ON %06x\n", MID);
+ * }
+ * \endverbatim
+ *
+ * \ingroup GR1553BC
+ */
+
+#include <stdint.h>
+#include <gr1553bc.h>
+
+/**** CONFIGURATION OPTIONS ****/
+
+/* Define GR1553BC_TIMESLOT to make driver take care of time
+ * management of minor frames.
+ */
+#define GR1553BC_TIMESLOT
+
+#define GR1553BC_MINOR_MAX 256
+#define GR1553BC_SLOT_MAX 32
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct gr1553bc_list;
+struct gr1553bc_major;
+struct gr1553bc_minor;
+struct gr1553bc_minor_cfg;
+struct gr1553bc_major_cfg;
+
+struct gr1553bc_minor_cfg {
+ int slot_cnt;
+ int timeslot; /* Total time of minor frame in us */
+};
+
+struct gr1553bc_major_cfg {
+ int minor_cnt; /* Number of Minor Frames */
+ struct gr1553bc_minor_cfg minor_cfgs[1];
+};
+
+struct gr1553bc_list_cfg {
+ unsigned char rt_timeout[31]; /* Number of us timeout tolerance per RT */
+ unsigned char bc_timeout; /* Number of us timeout tolerance of
+ * broadcast transfers */
+ int tropt_irq_on_err; /* Generate IRQ on transfer error */
+ int tropt_pause_on_err; /* Pause list on transfer error */
+ int async_list; /* Set to non-zero if asyncronous list*/
+};
+
+/* Default Configuration */
+extern struct gr1553bc_list_cfg gr1553bc_def_cfg;
+
+/* Complete list of all major frames */
+struct gr1553bc_list {
+ void *_table_custom; /* Config option given by user */
+ void *_table; /* address of allocated bd-table */
+ unsigned int table_hw; /* Descriptor table base HW-ADR */
+ unsigned int table_cpu; /* Descriptor table base CPU-ADR */
+ int table_size; /* Descriptor Table Size */
+ void *bc; /* BC HW, needed for adr translation */
+ unsigned char rt_timeout[32]; /* Tolerance per RT, default 20us
+ * Note: 31 is for Broadcast */
+ uint32_t tropts; /* Transfer descriptor options:
+ * On transfer error the following bits
+ * do affect:
+ * - bit28 1=Generate IRQ
+ * - bit26 1=Pause transfer list
+ *
+ */
+ int async_list; /* async list or not */
+ int major_cnt; /* Number of Major frames */
+ struct gr1553bc_major *majors[1]; /* Var-Array of Major Pointers*/
+};
+
+/* Alloc a List with a maximum number of Major frames supported */
+extern int gr1553bc_list_alloc(struct gr1553bc_list **list, int max_major);
+
+/* Free List if allocated with gr1553bc_list_alloc() */
+extern void gr1553bc_list_free(struct gr1553bc_list *list);
+
+/* Configure Global List parameters
+ *
+ * \param list List to be configured and initialized.
+ * \param cfg List Configuration
+ * \param bc The BC hardware device description
+ * (only needed for address translation)
+ */
+extern int gr1553bc_list_config
+ (
+ struct gr1553bc_list *list,
+ struct gr1553bc_list_cfg *cfg,
+ void *bc
+ );
+
+/* Link a 'major' Major frame with next major frame
+ * The links affected:
+ * - major->next
+ * - major->minor[LAST]->next
+ */
+extern void gr1553bc_list_link_major(
+ struct gr1553bc_major *major,
+ struct gr1553bc_major *next
+ );
+
+/* Link in a Major frame into a BC list.
+ * Calls gr1553bc_list_link_major() to link major frame with major-1 and
+ * major+1. If ending or starting major frame the frame is wrapped around.
+ */
+extern int gr1553bc_list_set_major(
+ struct gr1553bc_list *list,
+ struct gr1553bc_major *major,
+ int no);
+
+/* Calculate the size required in the descriptor table by one minor frame. */
+extern int gr1553bc_minor_table_size(struct gr1553bc_minor *minor);
+
+/* Calculate the size required for the descriptor table.
+ */
+extern int gr1553bc_list_table_size(struct gr1553bc_list *list);
+
+/* Allocate an empty descriptor table from list description suitable for
+ * the BC given by 'bc'.
+ *
+ * \param bdtab_custom Custom Descriptor Allocation options:
+ * ZERO: Dynamically allocated by Driver (CPU near RAM)
+ * Non-Zero: Use provided address as BASE of BD-TABLE
+ * Non-Zero with LSB set: Same as Non-Zero but address
+ * is given as HW address (used with AMBA-over-PCI to
+ * to specify RAM location on PCI board).
+ */
+extern int gr1553bc_list_table_alloc
+ (
+ struct gr1553bc_list *list,
+ void *bdtab_custom
+ );
+
+/* Free descriptor table allocated with gr1553bc_list_table_alloc() */
+extern void gr1553bc_list_table_free(struct gr1553bc_list *list);
+
+/* Build an empty descriptor table from list description,
+ * the minor frames will be linked together.
+ */
+extern int gr1553bc_list_table_build(struct gr1553bc_list *list);
+
+/* Major Frame */
+struct gr1553bc_major {
+ struct gr1553bc_major *next; /* Next Major Frame */
+ struct gr1553bc_major_cfg *cfg; /* User Config of Major frame */
+ struct gr1553bc_minor *minors[1]; /* Minor frames */
+};
+
+/* Minor Frame */
+struct gr1553bc_minor {
+ struct gr1553bc_minor *next; /* Next Minor Frame */
+ struct gr1553bc_minor_cfg *cfg; /* User Config of Minor frame */
+ uint32_t alloc; /* Descripts allocated */
+
+ /* Note: THIS POINTER MUST BE ALIGNED ON A 128-bit BOUNDARY */
+ union gr1553bc_bd *bds; /* Descriptors for this minor frame (CPU ADRS)*/
+};
+
+/* Alloc a Major/Minor frame skeleton according to the configuration structure.
+ * The descriptor table is not allocated.
+ */
+extern int gr1553bc_major_alloc_skel
+ (
+ struct gr1553bc_major **major,
+ struct gr1553bc_major_cfg *cfg
+ );
+
+/* Unique Message/Descriptor ID. Can be used to identify a Major or Minor
+ * Frame, or a Slot.
+ *
+ * - If minor_num is 0xff, the ID identifies a Major Frame
+ * - If slot_num is 0xff, the ID identifies a Minor Frame
+ * - If non of the above is true, the ID identifies a specific Slot
+ */
+#define GR1553BC_ID(major_num, minor_num, slot_num) \
+ ((((major_num)<<16)&0xff0000) | (((minor_num)<<8)&0xff00) | \
+ ((slot_num) & 0xff))
+#define GR1553BC_MINOR_ID(major_num, minor_num) \
+ GR1553BC_ID(major_num, minor_num, 0xff)
+#define GR1553BC_MAJOR_ID(major_num) \
+ GR1553BC_ID(major_num, 0xff, 0xff)
+
+#define GR1553BC_MAJID_FROM_ID(mid) (((mid) >> 16) & 0xff)
+#define GR1553BC_MINID_FROM_ID(mid) (((mid) >> 8) & 0xff)
+#define GR1553BC_SLOTID_FROM_ID(mid) ((mid) & 0xff)
+#define GR1553BC_ID_SET_SLOT(mid, slot_num) (((mid) & ~0xff) | ((slot_num) & 0xff))
+
+extern struct gr1553bc_major *gr1553bc_major_from_id
+ (
+ struct gr1553bc_list *list,
+ int mid
+ );
+
+extern struct gr1553bc_minor *gr1553bc_minor_from_id
+ (
+ struct gr1553bc_list *list,
+ int mid
+ );
+
+/* Get free time left of minor frame identified by MID 'mid' */
+extern int gr1553bc_list_freetime(struct gr1553bc_list *list, int mid);
+
+/* Get free time left of minor frame */
+extern int gr1553bc_minor_freetime(struct gr1553bc_minor *minor);
+
+/* Allocate a time slot on a minor frame, major/minor frame is identified
+ * by MID. The 'mid' is a input/ouput parameter, the resulting slot taken
+ * will be placed in 'mid', a pointer to the allocated descriptor is stored
+ * into bd.
+ *
+ * Major/Minor must be specified by MID, if slot is specified that slot will
+ * be allocated, if slot is 0xff, then the first free slot is allocated.
+ *
+ * The function fails (return negative) if timeslot is longer than remaining
+ * time in minor frame, if no more slots are available in minor frame, if
+ * MID points to a bad major/minor or major/minor/slot.
+ */
+extern int gr1553bc_slot_alloc(
+ struct gr1553bc_list *list,
+ int *mid,
+ int timeslot,
+ union gr1553bc_bd **bd
+ );
+/* Same as gr1553bc_slot_alloc but identifies a minor instead of list.
+ * The major/minor part of MID is ignored.
+ */
+extern int gr1553bc_slot_alloc2(
+ struct gr1553bc_minor *minor,
+ int *mid,
+ int timeslot,
+ union gr1553bc_bd **bd
+ );
+
+/* Free message slot and the time associated with it. The time taken by the
+ * message slot is added to the END TIME descriptor, if managed by the driver
+ * for this minor frame. The descriptor will be
+ */
+extern int gr1553bc_slot_free(struct gr1553bc_list *list, int mid);
+extern int gr1553bc_slot_free2(struct gr1553bc_minor *minor, int mid);
+
+/* Find MID from Descriptor pointer
+ *
+ * In the end of each minor frame is a unconditional jump
+ * to next minor frame descriptor. The hardware does not
+ * use the last 8 bytes of conditional descriptors, in the
+ * padding area a MID is stored so that we can lookup the
+ * MID of a descriptor. This function finds the jump
+ * descriptor and subtracs the offset from it.
+ *
+ * A faster way of looking up can be implemented if the
+ * list is symertical, however in the current setup we
+ * allow different numbers of slots in minor frames, and
+ * different number of minor frames in a major frame.
+ *
+ * \param bd IN: Descriptor to lookup MID of (CPU address of BD)
+ * \param mid OUT: Pointer to where Message-ID (Slot-ID) will be stored
+ * \param async OUT: Function will store non-zero value if BD belogs to
+ * async list.
+ */
+extern int gr1553bc_mid_from_bd(
+ union gr1553bc_bd *bd,
+ int *mid,
+ int *async
+ );
+
+/********** TRANSFER DESCRIPTOR MANIPULATION **********/
+
+/* Get pointer to descriptor entry from MID. */
+extern union gr1553bc_bd *gr1553bc_slot_bd
+ (
+ struct gr1553bc_list *list,
+ int mid
+ );
+
+/* IRQ function */
+typedef void (*bcirq_func_t)(union gr1553bc_bd *bd, void *data);
+
+/* Create unconditional IRQ customly defined location.
+ * The IRQ is disabled, enable it with gr1553bc_slot_irq_enable().
+ */
+extern int gr1553bc_slot_irq_prepare
+ (
+ struct gr1553bc_list *list,
+ int mid,
+ bcirq_func_t func,
+ void *data
+ );
+
+/* Enable previously prepared unconditional IRQ */
+extern int gr1553bc_slot_irq_enable(struct gr1553bc_list *list, int mid);
+
+/* Disable unconditional IRQ point, changed to unconditional JUMP
+ * to descriptor following.
+ * After disabling it it can be enabled again, or freed.
+ */
+extern int gr1553bc_slot_irq_disable(struct gr1553bc_list *list, int mid);
+
+/* Create custom jump to descriptor, conditional or unconditional, see
+ * hardware manual for conditions.
+ *
+ * set conditional to GR1553BC_UNCOND_JMP for unconditional jump.
+ */
+extern int gr1553bc_slot_jump
+ (
+ struct gr1553bc_list *list,
+ int mid,
+ uint32_t condition,
+ int to_mid
+ );
+
+/* Create a dummy transfer, paused until external trigger is set. The
+ * Slot is will have the dummy bit set, no transfer will take place.
+ */
+extern int gr1553bc_slot_exttrig(struct gr1553bc_list *list, int mid);
+
+/* Create a transfer on a previous allocated descriptor. It is assumed
+ * that the descriptor has been initialized empty before calling this
+ * function, this is to avoid races.
+ *
+ * The settings that are controlled on a global level (and not
+ * by this function):
+ * - IRQ after transfer error
+ * - IRQ after transfer (not supported, insert separate IRQ slot after this)
+ * - Pause schedule after transfer error
+ * - Pause schedule after transfer (not supported)
+ * - slot time optional (set when MID allocated), otherwise 0
+ * - (OPTIONAL) Dummy Bit, set using slot_empty() or ..._TT_DUMMY
+ * - RT timeout tolerance (managed per RT)
+ *
+ * Input Parameters:
+ * - Retry Mode (options)
+ * - Number of retires (options)
+ * - Bus selection (A or B) (options)
+ * - dummy bit (options)
+ * - transfer type (tt)
+ * - rt src/dst address (tt)
+ * - RT subaddress (tt)
+ * - word count (tt)
+ * - mode code (tt)
+ * - data pointer (dptr)
+ *
+ *
+ * See macros defined in this header file for creating transfer types (tt)
+ * and word count etc.
+ *
+ * See macros defined in this header file for creating the mask of options.
+ *
+ * Note that if bit0 (LSB) of dptr is set, then the address is translated into
+ * hardware address, otherwise the dptr is assumed to be accessible from the
+ * 1553 core. This is an option only for AMBA-over-PCI.
+ */
+extern int gr1553bc_slot_transfer(
+ struct gr1553bc_list *list,
+ int mid,
+ int options,
+ int tt,
+ uint16_t *dptr);
+
+/* Remove or set dummy bit of a transfer descriptor
+ * Bit31 of *dummy is written to the dummy bit, the
+ * old descriptor value is stored into *dummy.
+ */
+extern int gr1553bc_slot_dummy(
+ struct gr1553bc_list *list,
+ int mid,
+ unsigned int *dummy);
+
+/* Make a slot empty (BC will not generate bus transfers), time slot
+ * allocated is untouched (if assigned).
+ */
+extern int gr1553bc_slot_empty(struct gr1553bc_list *list, int mid);
+
+/* Transfer descriptor status and/or update Transfer descriptor data pointer.
+ *
+ * Read and/or write Status of a slot. Writing the status word may be
+ * used by software to indicate that result has been handled, or bit 31
+ * may be written 1 telling software that when it reaches 0, then BC
+ * has executed the request.
+ *
+ * Operation:
+ * bd->status = *stat & (bd->status 0xffffff) | (*stat & 0x80000000);
+ * *stat = Value of bd->status before rewrite.
+ *
+ * Note that the status word is not written when *stat is zero.
+ *
+ * Note that if bit0 (LSB) of dptr is set, then the address is translated into
+ * hardware address, otherwise the dptr is assumed to be accessible from the
+ * 1553 core. This is an option only for AMBA-over-PCI.
+ */
+extern int gr1553bc_slot_update(
+ struct gr1553bc_list *list,
+ int mid,
+ uint16_t *dptr,
+ unsigned int *stat);
+
+/* Modify a transfer descriptor in any way,
+ *
+ * flags:
+ * bit[N=0..3]: 1 = set BD wordN according to argument wordN,
+ * 0 = do not modify BD wordN
+ */
+extern int gr1553bc_slot_raw
+ (
+ struct gr1553bc_list *list,
+ int mid,
+ unsigned int flags,
+ uint32_t word0,
+ uint32_t word1,
+ uint32_t word2,
+ uint32_t word3
+ );
+
+
+/***** Macros to create BC Transfer Types (tt) for gr1553bc_slot_transfer() *****/
+
+/* WRITE TO RT (BC-to-RT) */
+#define GR1553BC_BC2RT(rtadr, subadr, word_count) \
+ ((rtadr<<11) | (subadr<<5) | (0x1f<<21) | (0<<10) | \
+ ((word_count>=32) ? 0 : word_count))
+
+/* READ FROM RT (RT-to-BC) */
+#define GR1553BC_RT2BC(rtadr, subadr, word_count) \
+ ((rtadr<<11) | (subadr<<5) | (0x1f<<21) | (1<<10) | \
+ ((word_count>=32) ? 0 : word_count))
+
+/* RT(TX) WRITE TO RT(RX) (RT-to-RT) */
+#define GR1553BC_RT2RT(tx_rtadr, tx_subadr, rx_rtadr, rx_subadr, word_count) \
+ ((rx_rtadr<<11) | (rx_subadr<<5) | \
+ (tx_rtadr<<21) | (tx_subadr<<16) | \
+ (0<<10) | \
+ ((word_count>=32) ? 0 : word_count))
+
+/* Mode command without data. (BC-to-RT)
+ * Mode code: 0,1,2,3,4,5,6,7 or 8.
+ */
+#define GR1553BC_MC_NODATA(rtadr, modecode) \
+ ((rtadr<<11) | (0x1f<<5) | (0x1f<<21) | \
+ (modecode<<0) | (1<<10))
+
+/* Mode command with 4 byte data (RT-to-BC)
+ * Mode code: 16, 18 or 19.
+ */
+#define GR1553BC_MC_RT2BC(rtadr, modecode) \
+ ((rtadr<<11) | (0x1f<<5) | (0x1f<<21) | \
+ (modecode<<0) | (1<<10))
+
+/* Mode command with 4 byte data (BC-to-RT)
+ * Mode code: 17, 20 or 21.
+ */
+#define GR1553BC_MC_BC2RT(rtadr, modecode) \
+ ((rtadr<<11) | (0x1f<<5) | (0x1f<<21) | \
+ (modecode<<0) | (0<<10))
+
+/* Broadcast to all RTs, to a specific subaddress (BC-to-RTs) */
+#define GR1553BC_BC_BC2RT(subadr, word_count) \
+ ((0x1f<<11) | (subadr<<5) | (0x1f<<21) | \
+ (0<<10) | \
+ ((word_count>=32) ? 0 : word_count))
+
+/* Request RT to broadcast to all RTs, to a specific subaddress (RT-to-RTs) */
+#define GR1553BC_BC_RT2RT(tx_rtadr, tx_subadr, rx_subadr, word_count) \
+ ((0x1f<<11) | (rx_subadr<<5) | \
+ (tx_rtadr<<21) | (tx_subadr<<16) | \
+ (0<<10) | \
+ ((word_count>=32) ? 0 : word_count))
+
+/* Broadcast mode command without data (BC-to-RTs)
+ * Mode code: 1,3,4,5,6,7 or 8
+ */
+#define GR1553BC_BC_MC_NODATA(modecode) \
+ ((0x1f<<11) | (0x1f<<5) | (0x1f<<21) | \
+ ((modecode)<<0) | (1<<10))
+
+/* Broadcast mode command with 4 byte data (BC-to-RTs)
+ * Mode code: 17, 20 or 21
+ */
+#define GR1553BC_BC_MC_BC2RT(modecode) \
+ ((0x1f<<11) | (0x1f<<5) | (0x1f<<21) | \
+ ((modecode)<<0) | (0<<10))
+
+
+/***** Macros to create BC options (options) for gr1553bc_slot_transfer() *****/
+
+/* Dummy (BC does no bus trasactions) */
+#define GR1553BC_OPT_DUMMY (1<<1)
+
+/* Retry modes */
+#define GR1553BC_RETRY_SAME 0x0 /* Retry on the same bus only */
+#define GR1553BC_RETRY_ALTER 0x1 /* Retry alternating on both busses */
+#define GR1553BC_RETRY_ATTEMPT 0x2 /* Many attepts first on original
+ * bus then on other bus */
+/* Number of retires supported */
+#define GR1553BC_RETRY_CNT_MAX 6
+
+/* Dummy bit: No transfer
+ * Bus bit: 0=A, 1=B
+ * Exttrig bit: Wait for external trigger (used for timesync)
+ * Exclusive bit: 1=Don't allow other messages in this time slot.
+ */
+#define GR1553BC_OPTIONS(dummy, exttrig, exclusive, retrymode, nretry, bus) \
+ ((((exttrig) & 0x1) << 30) | (((exclusive) & 0x1) << 29) | \
+ ((retrymode) << 23) | ((nretry) << 20) | \
+ ((bus) & 1) | (((dummy) & 0x1) << 1))
+
+#define GR1553BC_OPTIONS_BUSA GR1553BC_OPTIONS(0,0,0,GR1553BC_RETRY_SAME,0,0)
+#define GR1553BC_OPTIONS_BUSB GR1553BC_OPTIONS(0,0,0,GR1553BC_RETRY_SAME,0,1)
+#define GR1553BC_OPTIONS_BUSA_DUM GR1553BC_OPTIONS(1,0,0,GR1553BC_RETRY_SAME,0,0)
+#define GR1553BC_OPTIONS_BUSB_DUM GR1553BC_OPTIONS(1,0,0,GR1553BC_RETRY_SAME,0,1)
+
+/* Show parts of a list - this is for debugging only */
+extern void gr1553bc_show_list(struct gr1553bc_list *list, int options);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GR1553BC_LIST_H__ */
diff --git a/c/src/lib/libbsp/sparc/shared/include/gr1553bm.h b/c/src/lib/libbsp/sparc/shared/include/gr1553bm.h
new file mode 100644
index 0000000000..4d241c5f0d
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/gr1553bm.h
@@ -0,0 +1,212 @@
+#ifndef __GR1553BM_H__
+#define __GR1553BM_H__
+
+/* GR1553B BM driver
+ *
+ * COPYRIGHT (c) 2010.
+ * Aeroflex Gaisler.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2010-03-15, Daniel Hellstrom <daniel@gaisler.com>
+ * Created
+ *
+ *
+ * OVERVIEW
+ * ========
+ *
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Register GR1553B driver needed by BM driver */
+extern void gr1553bm_register(void);
+
+struct gr1553bm_entry {
+ uint32_t time; /* bit31=1, bit 30=0 */
+ uint32_t data; /* bit31=0, bit 30=0 */
+};
+
+#define GR1553BM_ERROPTS_MANL 0x02
+#define GR1553BM_ERROPTS_UDWL 0x04
+#define GR1553BM_ERROPTS_IMCL 0x08
+#define GR1553BM_ERROPTS_ALL 0x0e
+
+/* Function used to implement a custom copy routine.
+ * Returns number of bytes the desctionation address
+ * should be incremented with.
+ *
+ * \param dst Optional Destination address
+ * \param src Source DMA address
+ * \param nentires Number of entries to be processed.
+ * \param data Custom Data (set by config)
+ */
+typedef int (*bmcopy_func_t)(
+ unsigned int dst,
+ struct gr1553bm_entry *src,
+ int nentries,
+ void *data
+ );
+
+/* IRQ function callback, called on BM DMA error */
+typedef void (*bmisr_func_t)(void *bm, void *data);
+
+/* BM driver configuration */
+struct gr1553bm_config {
+
+ /*** Time options ***/
+
+ /* 8-bit time resolution, the BM will update the time according
+ * to this setting. 0 will make the time tag be of highest
+ * resolution (no division), 1 will make the BM increment the
+ * time tag once for two time ticks (div with 2), etc.
+ */
+ uint8_t time_resolution;
+
+ /* Enable Time Overflow IRQ handling. Setting this to 1
+ * makes the driver to update the 64-bit time by it self,
+ * it will use time overflow IRQ to detect when the 64-bit
+ * time counter must be incremented.
+ *
+ * If set to zero, the driver expect the user to call
+ * gr1553bm_time() regularly, it must be called more often
+ * than the time overflows to avoid an incorrect time.
+ */
+ int time_ovf_irq;
+
+
+
+ /*** Filtering options ***/
+
+ /* Bus error log options
+ *
+ * bit0,4-31 = reserved, set to zero
+ * Bit1 = Enables logging of Invalid mode code errors
+ * Bit2 = Enables logging of Unexpected Data errors
+ * Bit3 = Enables logging of Manchester/parity errors
+ */
+ unsigned int filt_error_options;
+
+ /* RT Address filtering bit mask. Each bit enables (if set)
+ * logging of a certain RT sub address. Bit 31 enables logging
+ * of broadcast messages.
+ */
+ unsigned int filt_rtadr;
+
+ /* RT Subaddress filtering bit mask, bit definition:
+ * 31: Enables logging of mode commands on subadr 31
+ * 1..30: BitN enables/disables logging of RT subadr N
+ * 0: Enables logging of mode commands on subadr 0
+ */
+ unsigned int filt_subadr;
+
+ /* Mode code Filter, is written into "BM RT Mode code filter"
+ * register, please see hardware manual for bit declarations.
+ */
+ unsigned int filt_mc;
+
+
+
+ /*** Buffer options ***/
+
+ /* Size of buffer in bytes, must be aligned to 8-byte
+ * The size is limited to max 4Mb.
+ */
+ unsigned int buffer_size;
+
+ /* Custom buffer, must be aligned to 8-byte and be of buffer_size
+ * length. If NULL dynamic memory allocation is used.
+ */
+ void *buffer_custom;
+
+ /* Custom Copy function, may be used to implement a more
+ * effective way of copying the DMA buffer. For example
+ * the DMA log may need to be compressed before copied
+ * onto a storage, this function can be used to avoid an
+ * extra copy.
+ */
+ bmcopy_func_t copy_func;
+
+ /* Optional Custom Data passed on to copy_func() */
+ void *copy_func_arg;
+
+
+
+ /*** Interrupt options ***/
+
+ /* Custom DMA error function, note that this function is called
+ * from Interrupt Context. Set to NULL to disable this callback.
+ */
+ bmisr_func_t dma_error_isr;
+
+ /* Optional Custom Data passed on to dma_error_isr() */
+ void *dma_error_arg;
+};
+
+/* Open BM device by instance number (minor)
+ *
+ * The return value is used as input parameter in all other function calls
+ * in the A
+ */
+extern void *gr1553bm_open(int minor);
+
+/* Close previously opened Bm device */
+extern void gr1553bm_close(void *bm);
+
+/* Configure the BM driver before starting */
+extern int gr1553bm_config(void *bm, struct gr1553bm_config *cfg);
+
+/* Start logging */
+extern int gr1553bm_start(void *bm);
+
+/* Get 64-bit 1553 Time. Low 24-bit time is acquired from BM hardware,
+ * the MSB is taken from a software counter internal to the driver. The
+ * counter is incremented every time the Time overflows by:
+ * - using "Time overflow" IRQ if enabled in user configuration
+ * - by checking IRQ flag (IRQ disabled), it is required that user
+ * calls this function before the next time overflow.
+ *
+ * The BM timer is limited to 24-bits, in order to handle overflows
+ * correctly and maintain a valid time an Interrupt handler is used
+ * or this function must be called when IRQ is not used.
+ *
+ * Update software time counters and return the current time.
+ */
+extern void gr1553bm_time(void *bm, uint64_t *time);
+
+/* Return zero when logging has not been started, non-zero when logging
+ * has been started
+ */
+extern int gr1553bm_started(void *bm);
+
+/* Check how many entries are currently stored in the BM Log DMA-area */
+extern int gr1553bm_available(void *bm, int *nentries);
+
+/* Stop logging */
+extern void gr1553bm_stop(void *bm);
+
+/* Read a maximum number of entries from LOG buffer. This function
+ * must be
+ *
+ * Arguments
+ * bm - Private pointer returned by gr1553bm_open()
+ * dst - Address where log data is written
+ * max - (IN/OUT) Maximum number of entires, when successfull
+ * the number of entries actually written is stored
+ * into the address of max.
+ *
+ * Result
+ * 0 = success
+ * -1 = fail. (may be due to BM logging not started)
+ */
+extern int gr1553bm_read(void *bm, struct gr1553bm_entry *dst, int *max);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GR1553BM_H__ */
diff --git a/c/src/lib/libbsp/sparc/shared/include/gr1553rt.h b/c/src/lib/libbsp/sparc/shared/include/gr1553rt.h
new file mode 100644
index 0000000000..afa4ae2f4c
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/gr1553rt.h
@@ -0,0 +1,443 @@
+#ifndef __GR1553RT_H__
+#define __GR1553RT_H__
+
+/* GR1553B RT driver
+ *
+ * COPYRIGHT (c) 2010.
+ * Aeroflex Gaisler.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2010-03-15, Daniel Hellstrom <daniel@gaisler.com>
+ * Created
+ *
+ *
+ * OVERVIEW
+ * ========
+ *
+ *
+ */
+
+/* CONFIG OPTION: Maximum number of LIST IDs supported.
+ * There are two lists per RT subaddress, one for RX one
+ * for TX.
+ */
+#define RTLISTID_MAX 64
+
+/* CONFIG OPTION: Maximum number of Interrupt handlers per device supported
+ * max is 256 supported, and minimum is 1.
+ */
+#define RTISR_MAX 64
+
+/* CONFIG OPTION: Maximum number of transfer (RX/TX) descriptors supported.
+ *
+ * Set this option to zero to allow flexible number of descriptors,
+ * requires dynamically allocation of driver structures.
+ */
+/*#define RTBD_MAX 4096*/
+#define RTBD_MAX 0
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Register GR1553B driver needed by RT driver */
+extern void gr1553rt_register(void);
+
+struct gr1553rt_list;
+
+/* Descriptor read/written by hardware.
+ *
+ * Must be aligned to 16 byte boundary
+ */
+struct gr1553rt_bd {
+ volatile unsigned int ctrl; /* 0x00 Control/Status word */
+ volatile unsigned int dptr; /* 0x04 Data Pointer */
+ volatile unsigned int next; /* 0x08 Next Descriptor in list */
+ volatile unsigned int unused; /* 0x0C UNUSED BY HARDWARE */
+};
+
+/* Sub address table entry, the hardware access */
+struct gr1553rt_sa {
+ volatile unsigned int ctrl; /* 0x00 SUBADDRESS CONTROL WORD */
+ volatile unsigned int txptr; /* 0x04 TRANSMIT BD POINTER */
+ volatile unsigned int rxptr; /* 0x08 RECEIVE BD POINTER */
+ volatile unsigned int unused; /* 0x0C UNUSED BY HARDWARE */
+};
+
+/* Configuration of a RT-SubAddress-List */
+struct gr1553rt_list_cfg {
+ unsigned int bd_cnt; /* Number of hw-descriptors in list */
+};
+
+/* A TX or RX subaddress descriptor list */
+struct gr1553rt_list {
+ short listid; /* ID/NUMBER of List. -1 unassigned */
+ short subadr; /* SubAddress. -1 when not scheduled */
+ void *rt; /* Scheduled on Device */
+ struct gr1553rt_list_cfg *cfg; /* List configuration */
+ int bd_cnt; /* Number of Descriptors */
+
+ /* !!Must be last in data structure!!
+ * !!Array must at least be of length bd_cnt!!
+ */
+ unsigned short bds[1]; /* Array of BDIDs, -1 unused/end */
+};
+
+/* GR1553B-RT Driver configuration options used when calling gr1553rt_config().
+ *
+ * Note that if not custom addresses are given the driver will dynamically
+ * allocate memory for buffers.
+ * Note that if custom addresses with the LSB set, the address will be
+ * interpreted as a address accessible by hardware, and translated
+ * into an address used by CPU.
+ */
+struct gr1553rt_cfg {
+ unsigned char rtaddress; /* RT Address 0..30 */
+
+ /*** MODE CODE CONFIG ***/
+ unsigned int modecode; /* Mode codes enable/disable/IRQ/EV-Log.
+ * Each modecode has a 2-bit cfg field.
+ * See Mode Code Control Register in
+ * hardware manual.
+ */
+
+ /*** TIME CONFIG ***/
+ unsigned short time_res; /* Time tag resolution in us */
+
+ /*** SUBADDRESS TABLE CONFIG ***/
+ void *satab_buffer; /* Optional Custom buffer. Must be
+ * At least 16*32 bytes, and be aligned
+ * to 10-bit (1KB) boundary. Set to NULL
+ * to make driver allocate buffer.
+ */
+
+ /*** EVENT LOG CONFIG ***/
+ void *evlog_buffer; /* Optional Custom buffer */
+ int evlog_size; /* Length, must be a multiple of 2.
+ * If set to ZERO event log is disabled
+ */
+
+ /*** TRANSFER DESCRIPTOR CONFIG ***/
+ int bd_count; /* Number of transfer descriptors shared
+ * by all RX/TX sub-addresses */
+ void *bd_buffer; /* Optional Custom descriptor area.
+ * Must hold bd_count*32 bytes.
+ * If NULL, descriptors will be
+ * allocated dynamically. */
+};
+
+/* GR1553B-RT status indication, copied from the RT registers and stored
+ * here. Used when calling the gr1553rt_status() function.
+ */
+struct gr1553rt_status {
+ unsigned int status; /* RT Status word */
+ unsigned int bus_status; /* BUS Status */
+ unsigned short synctime; /* Time Tag of last sync with data */
+ unsigned short syncword; /* Data of last mode code synchronize
+ * with data. */
+ unsigned short time_res; /* Time resolution (set by config) */
+ unsigned short time; /* Current Time Tag */
+};
+
+/* ISR callback definition for ERRORs detected in the GR1553B-RT interrupt
+ * handler.
+ *
+ * \param err Inidicate Error type. The IRQ flag register bit mask:
+ * Bit 9 - RT DMA ERROR
+ * Bit 10 - RT Table access error
+ * \param data Custom data assigned by user
+ */
+typedef void (*gr1553rt_irqerr_t)(int err, void *data);
+
+/* ISR callback definition for modecodes that are configured to generate
+ * an IRQ. The callback is called from within the GR1553B-RT interrupt
+ * handler.
+ *
+ * \param mcode Mode code that caused this IRQ
+ * \param entry The raw Eventlog Entry
+ * \param data Custom data assigned by user
+ */
+typedef void (*gr1553rt_irqmc_t)(int mcode, unsigned int entry, void *data);
+
+/* Transfer ISR callback definition. Called from GR1553B-RT interrupt handler
+ * when an interrupt has been generated and a event logged due to a 1553
+ * transfer to this RT.
+ *
+ * \param list List (Subaddress/TransferType) that caused IRQ
+ * \param entry The raw Eventlog Entry
+ * \param bd_next Next Descriptor-entry index in the list (Subaddress/tr-type)
+ * This can be used to process all descriptors upto entry_next.
+ * \param data Custom data assigned by user
+ */
+typedef void (*gr1553rt_irq_t)(
+ struct gr1553rt_list *list,
+ unsigned int entry,
+ int bd_next,
+ void *data
+ );
+
+/* Configure a list according to configuration. Assign the list
+ * to a device, however not to a RT sub address yet. The rt
+ * is stored within list.
+ *
+ * \param rt RT Device driver identification, stored within list.
+ * \param list The list to configure
+ * \param cfg Configuration for list. Pointer to configuration is
+ * stored within list for later use.
+ */
+extern int gr1553rt_list_init
+ (
+ void *rt,
+ struct gr1553rt_list **plist,
+ struct gr1553rt_list_cfg *cfg
+ );
+
+/* Assign an Error Interrupt handler. Before the handler is called the
+ * RT hardware is stopped/disabled. The handler is optional, if not assigned
+ * the ISR will still stop the RT upon error.
+ *
+ * Errors detected by the interrupt handler:
+ * - DMA error
+ * - Subaddress table access error
+ *
+ * \param func ISR called when an error causes an interrupt.
+ * \param data Custom data given as an argument when calling ISR
+ */
+extern int gr1553rt_irq_err
+ (
+ void *rt,
+ gr1553rt_irqerr_t func,
+ void *data
+ );
+
+/* Assign a ModeCode Interrupt handler callback. Called when a 1553 modecode
+ * transfer is logged and cause an IRQ. The modecode IRQ generation is
+ * configured from "struct gr1553rt_cfg" when calling gr1553rt_config().
+ *
+ * \param func ISR called when a modecode causes an interrupt.
+ * \param data Custom data given as an argument when calling ISR
+ */
+extern int gr1553rt_irq_mc
+ (
+ void *rt,
+ gr1553rt_irqmc_t func,
+ void *data
+ );
+
+/* Assign transfer interrupt handler callback. Called when a RX or TX
+ * transfer is logged and cause an interrupt, the function is called
+ * from the GR1553B-RT driver's ISR, in interrupt context.
+ *
+ * The callback can be installed per subaddress and transfer type.
+ * Subaddress 0 and 31 are not valid (gr1553rt_irq_mc() for modecodes).
+ *
+ * \param subadr Select subaddress (1-30)
+ * \param tx 1=TX subaddress, 0=RX subaddress
+ * \param func ISR called when subaddress of spcified transfer type
+ * causes an interrupt.
+ * \param data Custom data given as an argument when calling ISR
+ */
+extern int gr1553rt_irq_sa
+ (
+ void *rt,
+ int subadr,
+ int tx,
+ gr1553rt_irq_t func,
+ void *data
+ );
+
+#define GR1553RT_BD_FLAGS_IRQEN (1<<30)
+/* Initialize a descriptor entry in a list. This is typically done
+ * prior to scheduling the list.
+ *
+ * \param entry_no Entry number in list (descriptor index in list)
+ * \param flags Enable IRQ when descriptor is accessed by setting
+ * argument GR1553RT_BD_FLAGS_IRQEN. Enabling IRQ on a
+ * descriptor basis will override SA-table IRQ config.
+ * \param dptr Data Pointer to RX or TX operation. The LSB indicate
+ * if the address must be translated into Hardware address
+ * - this is useful when a buffer close to CPU is used
+ * as a data pointer and the RT core is located over PCI.
+ * \param next Next Entry in list. Set to 0xffff for end of list. Set
+ * 0xfffe for next entry in list, wrap around to entry
+ * zero if entry_no is last descriptor in list (circular).
+ */
+extern int gr1553rt_bd_init(
+ struct gr1553rt_list *list,
+ unsigned short entry_no,
+ unsigned int flags,
+ uint16_t *dptr,
+ unsigned short next
+ );
+
+/* Manipulate/Read Control/Status and Data Pointer words of a buffer descriptor.
+ * If status is zero, the control/status word is accessed. If dptr is non-zero
+ * the data pointer word is accessed.
+ *
+ * \param list The list that the descriptor is located at
+ *
+ * \param entry_no The descriptor number accessed
+ *
+ * \param status IN/OUT. If zero no effect. If pointer is non-zero the
+ * value pointed to:
+ * IN: Written to Control/Status
+ * OUT: the value of the Control/Status word before writing.
+ *
+ * \param dptr IN/OUT. If zero no effect. If pointer is non-zero, the
+ * value pointed to:
+ * IN: non-zero: Descriptor data pointer will be updated with
+ * this value. Note that the LSB indicate if the address
+ * must be translated into hardware-aware address.
+ * OUT: The old data pointer is stored here.
+ */
+extern int gr1553rt_bd_update(
+ struct gr1553rt_list *list,
+ int entry_no,
+ unsigned int *status,
+ uint16_t **dptr
+ );
+
+/* Get the next/current descriptor processed of a RT sub-address.
+ *
+ * \param subadr RT Subaddress
+ * \param txeno Pointer to where TX descriptor number is stored.
+ * \param rxeno Pointer to where RX descriptor number is stored.
+ */
+extern int gr1553rt_indication(void *rt, int subadr, int *txeno, int *rxeno);
+
+/* Take a GR1553RT hardware device identified by minor.
+ * A pointer is returned that is used internally by the GR1553RT
+ * driver, it is used as an input parameter 'rt' to all other
+ * functions that manipulate the hardware.
+ *
+ * This function initializes the RT hardware to a stopped/disable level.
+ */
+extern void *gr1553rt_open(int minor);
+
+/* Close and stop/disable the RT hardware. */
+extern void gr1553rt_close(void *rt);
+
+/* Configure the RT. The RT device must be configured once before
+ * started. A started RT device can not be configured.
+ *
+ * \param rt The RT to configure
+ * \param cfg Configuration parameters
+ */
+extern int gr1553rt_config(void *rt, struct gr1553rt_cfg *cfg);
+
+/* Schedule a RX or TX list on a sub address. If a list has already been
+ * schduled on the subaddress and on the same transfer type (RX/TX), the
+ * old list is replaced with the list given here.
+ *
+ * \param subadr Subaddress to schedule list on
+ * \param tx Subaddress transfer type: 1=TX, 0=RX
+ * \param list Preconfigued RT list scheduled
+ */
+extern void gr1553rt_sa_schedule(
+ void *rt,
+ int subadr,
+ int tx,
+ struct gr1553rt_list *list
+ );
+
+/* Set SubAdress options. One may for example Enable or Disable a sub
+ * address RX and/or TX. See hardware manual for SA-Table configuration
+ * options.
+ *
+ * \param subadr SubAddress to configure
+ * \param mask Bit mask of option-bits written to subaddress config
+ * \param options The new options written to subaddress config.
+ *
+ */
+extern void gr1553rt_sa_setopts(
+ void *rt,
+ int subadr,
+ unsigned int mask,
+ unsigned int options
+ );
+
+/* Get The Subaddress and transfer type of a scheduled list. Normally the
+ * application knows which subaddress the list is for.
+ *
+ * \param list List to lookup information for
+ * \param subadr Pointer to where the subaddress is stored
+ * \param tx Transfer type is stored here. 1=TX, 0=RX.
+ */
+extern void gr1553rt_list_sa(
+ struct gr1553rt_list *list,
+ int *subadr,
+ int *tx
+ );
+
+/* Start RT Communication
+ *
+ * Interrupts will be enabled. The RT enabled and the "RT-run-time"
+ * part of the API will be opened for the user and parts that need the
+ * RT to be stopped are no longer available. After the RT has been
+ * started the configuration function can not be called.
+ */
+extern int gr1553rt_start(void *rt);
+
+/* Get Status of the RT core. See data structure gr1553rt_status for more
+ * information about the result. It can be used to read out:
+ * - time information
+ * - sync information
+ * - bus & RT status
+ *
+ * \param status Pointer to where the status words will be stored. They
+ * are stored according to the gr1553rt_status data structure.
+ */
+extern void gr1553rt_status(void *rt, struct gr1553rt_status *status);
+
+/* Stop RT communication. Only possible to stop an already started RT device.
+ * Interrupts are disabled and the RT Enable bit cleared.
+ */
+extern void gr1553rt_stop(void *rt);
+
+/* Set RT vector and/or bit word.
+ *
+ * - Vector Word is used in response to "Transmit vector word" BC commands
+ * - Bit Word is used in response to "Transmit bit word" BC commands
+ *
+ *
+ * \param mask Bit-Mask, bits that are 1 will result in that bit in the
+ * words register being overwritten with the value of words
+ * \param words Bits 31..16: Bit Word. Bits 15..0: Vector Word.
+ *
+ * Operation:
+ * hw_words = (hw_words & ~mask) | (words & mask)
+ */
+extern void gr1553rt_set_vecword(
+ void *rt,
+ unsigned int mask,
+ unsigned int words
+ );
+
+/* Set selectable bits of the "Bus Status Register". The bits written
+ * is determined by the "mask" bit-mask. Operation:
+ *
+ * bus_status = (bus_status & ~mask) | (sts & mask)
+ *
+ */
+extern void gr1553rt_set_bussts(void *rt, unsigned int mask, unsigned int sts);
+
+/* Read up to MAX number of entries in eventlog log.
+ *
+ * \param dst Destination address for event log entries
+ * \param max Maximal number of event log entries that an be stored into dst
+ *
+ * Return
+ * negative Failure
+ * zero No entries available at the moment
+ * positive Number of entries copied into dst
+ */
+extern int gr1553rt_evlog_read(void *rt, unsigned int *dst, int max);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/include/gr_701.h b/c/src/lib/libbsp/sparc/shared/include/gr_701.h
new file mode 100644
index 0000000000..1bf16a7f5d
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/gr_701.h
@@ -0,0 +1,49 @@
+/* GR-701 PCI Target driver.
+ *
+ * COPYRIGHT (c) 2008.
+ * Aeroflex Gaisler AB.
+ *
+ * Configures the GR-701 interface PCI board.
+ * This driver provides a AMBA PnP bus by using the general part
+ * of the AMBA PnP bus driver (ambapp_bus.c).
+ *
+ * Driver resources for the AMBA PnP bus provided can be set using
+ * gr701_set_resources().
+ *
+ * The license and distribution terms for this file may be
+ * found in found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ */
+
+#ifndef __GR_701_H__
+#define __GR_701_H__
+
+#include <drvmgr/drvmgr.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* An array of pointers to GR-701 resources. The resources will be
+ * used by the drivers controlling the cores on the GR-701 target AMBA bus.
+ *
+ * The gr_rasta_io_resources is declared weak so that the user can override the
+ * default configuration.
+ */
+extern struct drvmgr_bus_res *gr701_resources[];
+
+#define GR701_OPTIONS_AMBA 0x01
+#define GR701_OPTIONS_IRQ 0x02
+
+/* Print information about GR-RASTA-IO PCI board */
+void gr701_print(int options);
+
+/* Register GR-701 driver */
+void gr701_register_drv(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/include/gr_rasta_adcdac.h b/c/src/lib/libbsp/sparc/shared/include/gr_rasta_adcdac.h
new file mode 100644
index 0000000000..6c58674aad
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/gr_rasta_adcdac.h
@@ -0,0 +1,50 @@
+/* GR-RASTA-ADCDAC PCI Target driver.
+ *
+ * COPYRIGHT (c) 2008.
+ * Aeroflex Gaisler AB.
+ *
+ * Configures the GR-RASTA-ADCDAC interface PCI board.
+ * This driver provides a AMBA PnP bus by using the general part
+ * of the AMBA PnP bus driver (ambapp_bus.c).
+ *
+ * Driver resources for the AMBA PnP bus provided can be set using
+ * gr_rasta_adcdac_set_resources().
+ *
+ * The license and distribution terms for this file may be
+ * found in found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ */
+
+#ifndef __GR_RASTA_ADCDAC_H__
+#define __GR_RASTA_ADCDAC_H__
+
+#include <drvmgr/drvmgr.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* An array of pointers to GR-RASTA-ADCDAC resources. The resources will be
+ * used by the drivers controlling the cores on the GR-RASTA-ADCDAC target AMBA bus.
+ *
+ * The gr_rasta_io_resources is declared weak so that the user can override the
+ * default configuration.
+ */
+extern struct drvmgr_bus_res *gr_rasta_adcdac_resources[];
+
+/* Options to gr_rasta_io_print function */
+#define RASTA_ADCDAC_OPTIONS_AMBA 0x01 /* Print AMBA bus devices */
+#define RASTA_ADCDAC_OPTIONS_IRQ 0x02 /* Print current IRQ setup */
+
+/* Print information about GR-RASTA-IO PCI board */
+void gr_rasta_adcdac_print(int options);
+
+/* Register GR-RASTA-IO driver */
+void gr_rasta_adcdac_register_drv(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/include/gr_rasta_io.h b/c/src/lib/libbsp/sparc/shared/include/gr_rasta_io.h
new file mode 100644
index 0000000000..b3e2a4166d
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/gr_rasta_io.h
@@ -0,0 +1,50 @@
+/* GR-RASTA-IO PCI Target driver.
+ *
+ * COPYRIGHT (c) 2008.
+ * Aeroflex Gaisler AB.
+ *
+ * Configures the GR-RASTA-IO interface PCI board.
+ * This driver provides a AMBA PnP bus by using the general part
+ * of the AMBA PnP bus driver (ambapp_bus.c).
+ *
+ * Driver resources for the AMBA PnP bus provided can be set using
+ * gr_rasta_io_set_resources().
+ *
+ * The license and distribution terms for this file may be
+ * found in found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ */
+
+#ifndef __GR_RASTA_IO_H__
+#define __GR_RASTA_IO_H__
+
+#include <drvmgr/drvmgr.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* An array of pointers to GR-RASTA-IO resources. The resources will be
+ * used by the drivers controlling the cores on the GR-RASTA-IO target AMBA bus.
+ *
+ * The gr_rasta_io_resources is declared weak so that the user can override the
+ * default configuration.
+ */
+extern struct drvmgr_bus_res *gr_rasta_io_resources[];
+
+/* Options to gr_rasta_io_print function */
+#define RASTA_IO_OPTIONS_AMBA 0x01 /* Print AMBA bus devices */
+#define RASTA_IO_OPTIONS_IRQ 0x02 /* Print current IRQ setup */
+
+/* Print information about GR-RASTA-IO PCI board */
+void gr_rasta_io_print(int options);
+
+/* Register GR-RASTA-IO driver */
+void gr_rasta_io_register_drv(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/include/gr_rasta_tmtc.h b/c/src/lib/libbsp/sparc/shared/include/gr_rasta_tmtc.h
new file mode 100644
index 0000000000..67ca7fca46
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/gr_rasta_tmtc.h
@@ -0,0 +1,100 @@
+/* GR-RASTA-TMTC PCI Target driver.
+ *
+ * COPYRIGHT (c) 2008.
+ * Aeroflex Gaisler AB.
+ *
+ * Configures the GR-RASTA-TMTC interface PCI board.
+ * This driver provides a AMBA PnP bus by using the general part
+ * of the AMBA PnP bus driver (ambapp_bus.c).
+ *
+ * Driver resources for the AMBA PnP bus provided can be set using
+ * gr_rasta_tmtc_set_resources().
+ *
+ * The license and distribution terms for this file may be
+ * found in found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ */
+
+#ifndef __GR_RASTA_TMTC_H__
+#define __GR_RASTA_TMTC_H__
+
+#include <drvmgr/drvmgr.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* GPIO TM/TC configuration pin definitions
+ * --31 PWRX (1=PW2APB, 0=TM VC3/4)
+ * --30 PWTC (1=APB2PW, 0=TC MAP1/2)
+ * --29 Redundant TM (1=enable, 0=disable)
+ * --28 Redundant TC (1=enable, 0=disable)
+ * --27 Select TM output (1=GRTM, 0=PTME)
+ * --26 Loop back PW (1=enable, 0=disable)
+ * --25 Transponder clock (1=PLL, 0=PLL bypass)
+ * --24 PWTX-SELECT (0=TX0-0, 1=TX0-1)
+ * --23 PDEC Map Switch (1=on, 0=off)
+ * --22 PDEC Ext CPDU (1=on, 0=off)
+ * --21 PDEC Super User (1=on, 0=off)
+ * --20 PDEC RM On (1=on, 0=off)
+ * --19 PDEC AU Enable (1=on, 0=off)
+ * --18 PDEC Dynamic Mode (1=on, 0=off)
+ * --17 PDEC Priority (1=on, 0=off)
+ * --16 TC PSS Support (1=on, 0=off)
+ * --15 TC Mark (1=on, 0=off)
+ * --14 TC Pseudo (1=on, 0=off)
+ * --13 TC Rising Clock (1=rise, 0=fall)
+ * --12 TC Active High (1=high, 0=low)
+ * --11 Bit Lock Positive (1=high, 0=low)
+ * --10 RF Avail Positive (1=high, 0=low)
+ * -- 9 : 0 SpaceCraft ID
+ */
+
+#define GR_TMTC_GPIO_PWRX (1<<31)
+#define GR_TMTC_GPIO_PWTC (1<<30)
+#define GR_TMTC_GPIO_RED_TM (1<<29)
+#define GR_TMTC_GPIO_RED_TC (1<<28)
+#define GR_TMTC_GPIO_GRTM_SEL (1<<27)
+#define GR_TMTC_GPIO_LB_PW (1<<26)
+#define GR_TMTC_GPIO_TRANSP_CLK (1<<25)
+#define GR_TMTC_GPIO_PWTX_SEL (1<<24)
+#define GR_TMTC_GPIO_PDEC_MAP (1<<23)
+#define GR_TMTC_GPIO_PDEC_CPDU (1<<22)
+#define GR_TMTC_GPIO_PDEC_SU (1<<21)
+#define GR_TMTC_GPIO_PDEC_RM (1<<20)
+#define GR_TMTC_GPIO_PDEC_AU (1<<19)
+#define GR_TMTC_GPIO_PDEC_DYN_MODE (1<<18)
+#define GR_TMTC_GPIO_PDEC_PRIO (1<<17)
+#define GR_TMTC_GPIO_TC_PSS (1<<16)
+#define GR_TMTC_GPIO_TC_MARK (1<<15)
+#define GR_TMTC_GPIO_TC_PSEUDO (1<<14)
+#define GR_TMTC_GPIO_TC_RISING_CLK (1<<13)
+#define GR_TMTC_GPIO_TC_ACTIVE_HIGH (1<<12)
+#define GR_TMTC_GPIO_TC_BIT_LOCK (1<<11)
+#define GR_TMTC_GPIO_TC_RF_AVAIL (1<<10)
+#define GR_TMTC_GPIO_SCID (0x000003ff)
+
+/* An array of pointers to GR-RASTA-TMTC bus resources. The resources will be
+ * used by the device drivers controlling the cores on the GR-RASTA-IO target
+ * AMBA bus.
+ *
+ * The array is defined weak, and defualts to no resources.
+ */
+extern struct drvmgr_bus_res *gr_rasta_tmtc_resources[];
+
+/* Options to gr_rasta_io_print function */
+#define RASTA_TMTC_OPTIONS_AMBA 0x01 /* Print AMBA bus devices */
+#define RASTA_TMTC_OPTIONS_IRQ 0x02 /* Print current IRQ setup */
+
+/* Print information about GR-RASTA-TMTC PCI board */
+void gr_rasta_tmtc_print(int options);
+
+/* Register GR-RASTA-TMTC driver */
+void gr_rasta_tmtc_register_drv(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/include/gr_tmtc_1553.h b/c/src/lib/libbsp/sparc/shared/include/gr_tmtc_1553.h
new file mode 100644
index 0000000000..32615907f1
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/gr_tmtc_1553.h
@@ -0,0 +1,50 @@
+/* GR-TMTC-1553 PCI Target driver.
+ *
+ * COPYRIGHT (c) 2010.
+ * Aeroflex Gaisler AB.
+ *
+ * Configures the GR-TMTC-1553 interface PCI board.
+ * This driver provides a AMBA PnP bus by using the general part
+ * of the AMBA PnP bus driver (ambapp_bus.c).
+ *
+ * Driver resources for the AMBA PnP bus provided can be set using
+ * gr_tmtc_1553_set_resources().
+ *
+ * The license and distribution terms for this file may be
+ * found in found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ */
+
+#ifndef __GR_TMTC_1553_H__
+#define __GR_TMTC_1553_H__
+
+#include <drvmgr/drvmgr.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* An array of pointers to GR-TMTC-1553 resources. The resources will be
+ * used by the drivers controlling the cores on the GR-TMTC-1553 target AMBA bus.
+ *
+ * The gr_rasta_io_resources is declared weak so that the user can override the
+ * default configuration.
+ */
+extern struct drvmgr_bus_res *gr_tmtc_1553_resources[];
+
+/* Options to gr_rasta_io_print function */
+#define TMTC_1553_OPTIONS_AMBA 0x01 /* Print AMBA bus devices */
+#define TMTC_1553_OPTIONS_IRQ 0x02 /* Print current IRQ setup */
+
+/* Print information about GR-RASTA-IO PCI board */
+void gr_tmtc_1553_print(int options);
+
+/* Register GR-RASTA-IO driver */
+void gr_tmtc_1553_register_drv(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/include/gradcdac.h b/c/src/lib/libbsp/sparc/shared/include/gradcdac.h
new file mode 100644
index 0000000000..04b55edcf0
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/gradcdac.h
@@ -0,0 +1,230 @@
+/* ADC / DAC (GRADCDAC) interface
+/*
+ * Driver interface for APBUART
+ *
+ * COPYRIGHT (c) 2009.
+ * Aeroflex Gaisler AB
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ */
+
+#ifndef __GRADCDAC_H__
+#define __GRADCDAC_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct gradcdac_regs {
+ volatile unsigned int config; /* 0x00 Configuration Register */
+ volatile unsigned int status; /* 0x04 Status Register */
+ int unused0[2];
+ volatile unsigned int adc_din; /* 0x10 ADC Data Input Register */
+ volatile unsigned int dac_dout; /* 0x14 DAC Data Output Register */
+ int unused1[2];
+ volatile unsigned int adrin; /* 0x20 Address Input Register */
+ volatile unsigned int adrout; /* 0x24 Address Output Register */
+ volatile unsigned int adrdir; /* 0x28 Address Direction Register */
+ int unused2[1];
+ volatile unsigned int data_in; /* 0x30 Data Input Register */
+ volatile unsigned int data_out; /* 0x34 Data Output Register */
+ volatile unsigned int data_dir; /* 0x38 Data Direction Register */
+};
+
+#define GRADCDAC_CFG_DACWS 0x00f80000
+#define GRADCDAC_CFG_WRPOL 0x00040000
+#define GRADCDAC_CFG_DACDW 0x00030000
+#define GRADCDAC_CFG_ADCWS 0x0000f800
+#define GRADCDAC_CFG_RCPOL 0x00000400
+#define GRADCDAC_CFG_CSMODE 0x00000300
+#define GRADCDAC_CFG_CSPOL 0x00000080
+#define GRADCDAC_CFG_RDYMODE 0x00000040
+#define GRADCDAC_CFG_RDYPOL 0x00000020
+#define GRADCDAC_CFG_TRIGPOL 0x00000010
+#define GRADCDAC_CFG_TRIGMODE 0x0000000c
+#define GRADCDAC_CFG_ADCDW 0x00000003
+
+#define GRADCDAC_CFG_DACWS_BIT 19
+#define GRADCDAC_CFG_WRPOL_BIT 18
+#define GRADCDAC_CFG_DACDW_BIT 16
+#define GRADCDAC_CFG_ADCWS_BIT 11
+#define GRADCDAC_CFG_RCPOL_BIT 10
+#define GRADCDAC_CFG_CSMODE_BIT 8
+#define GRADCDAC_CFG_CSPOL_BIT 7
+#define GRADCDAC_CFG_RDYMODE_BIT 6
+#define GRADCDAC_CFG_RDYPOL_BIT 5
+#define GRADCDAC_CFG_TRIGPOL_BIT 4
+#define GRADCDAC_CFG_TRIGMODE_BIT 2
+#define GRADCDAC_CFG_ADCDW_BIT 0
+
+#define GRADCDAC_STATUS_DACNO 0x40
+#define GRADCDAC_STATUS_DACRDY 0x20
+#define GRADCDAC_STATUS_DACON 0x10
+#define GRADCDAC_STATUS_ADCTO 0x08
+#define GRADCDAC_STATUS_ADCNO 0x04
+#define GRADCDAC_STATUS_ADCRDY 0x02
+#define GRADCDAC_STATUS_ADCON 0x01
+
+#define GRADCDAC_STATUS_DACNO_BIT 6
+#define GRADCDAC_STATUS_DACRDY_BIT 5
+#define GRADCDAC_STATUS_DACON_BIT 4
+#define GRADCDAC_STATUS_ADCTO_BIT 3
+#define GRADCDAC_STATUS_ADCNO_BIT 2
+#define GRADCDAC_STATUS_ADCRDY_BIT 1
+#define GRADCDAC_STATUS_ADCON_BIT 0
+
+#define GRADCDAC_IRQ_DAC 1
+#define GRADCDAC_IRQ_ADC 0
+
+struct gradcdac_config {
+ unsigned char dac_ws;
+ char wr_pol;
+ unsigned char dac_dw;
+ unsigned char adc_ws;
+ char rc_pol;
+ unsigned char cs_mode;
+ char cs_pol;
+ char ready_mode;
+ char ready_pol;
+ char trigg_pol;
+ unsigned char trigg_mode;
+ unsigned char adc_dw;
+};
+
+extern void *gradcdac_open(char *devname);
+
+extern void gradcdac_set_config(void *cookie, struct gradcdac_config *cfg);
+
+extern void gradcdac_get_config(void *cookie, struct gradcdac_config *cfg);
+
+extern void gradcdac_set_cfg(void *cookie, unsigned int config);
+
+extern unsigned int gradcdac_get_cfg(void *cookie);
+
+extern unsigned int gradcdac_get_status(void *cookie);
+
+static int __inline__ gradcdac_DAC_ReqRej(unsigned int status)
+{
+ return (status & GRADCDAC_STATUS_DACNO);
+}
+
+static int __inline__ gradcdac_DAC_isCompleted(unsigned int status)
+{
+ return (status & GRADCDAC_STATUS_DACRDY);
+}
+
+static int __inline__ gradcdac_DAC_isOngoing(unsigned int status)
+{
+ return (status & GRADCDAC_STATUS_DACON);
+}
+
+static int __inline__ gradcdac_ADC_isTimeouted(unsigned int status)
+{
+ return (status & GRADCDAC_STATUS_ADCTO);
+}
+
+static int __inline__ gradcdac_ADC_ReqRej(unsigned int status)
+{
+ return (status & GRADCDAC_STATUS_ADCNO);
+}
+
+static int __inline__ gradcdac_ADC_isCompleted(unsigned int status)
+{
+ return (status & GRADCDAC_STATUS_ADCRDY);
+}
+
+static int __inline__ gradcdac_ADC_isOngoing(unsigned int status)
+{
+ return (status & GRADCDAC_STATUS_ADCON);
+}
+
+#define GRADCDAC_ISR_BOTH 3
+#define GRADCDAC_ISR_DAC 2
+#define GRADCDAC_ISR_ADC 1
+
+/* Install IRQ handler for ADC and/or DAC interrupt.
+ * The installed IRQ handler(ISR) must read the status
+ * register to clear the pending interrupt avoiding multiple
+ * entries to the ISR caused by the same IRQ.
+ *
+ * \param adc 1=ADC interrupt, 2=ADC interrupt, 3=ADC and DAC interrupt
+ * \param isr Interrupt service routine called when IRQ is fired
+ * \param arg custom argument passed to ISR when called.
+ */
+extern int gradcdac_install_irq_handler
+ (void *cookie, int adc, void (*isr)(void *cookie, void *arg), void *arg);
+
+extern void gradcdac_uninstall_irq_handler(void *cookie, int adc);
+
+/* Make the ADC circuitry initialize a analogue to digital
+ * conversion. The result can be read out by gradcdac_adc_convert_try
+ * or gradcdac_adc_convert.
+ */
+extern void gradcdac_adc_convert_start(void *cookie);
+
+/* Tries to read the conversion result. If the circuitry is busy
+ * converting the function return a non-zero value, if the conversion
+ * has successfully finished the function return zero.
+ *
+ * \param digital_value the resulting converted value is placed here
+ * \return zero = ADC conversion complete, digital_value contain current conversion result
+ * positive = ADC busy, digital_value contain previous conversion result
+ * negative = Conversion request failed.
+ */
+extern int gradcdac_adc_convert_try(void *cookie, unsigned short *digital_value);
+
+/* Waits until the ADC circuity has finished a digital to analogue
+ * conversion. The Waiting is implemented as a busy loop utilizing
+ * 100% CPU load.
+ *
+ * \return zero = Conversion ok
+ * negative = Conversion request failed.
+ */
+extern int gradcdac_adc_convert(void *cookie, unsigned short *digital_value);
+
+/* Try to make the DAC circuitry initialize a digital to analogue
+ * conversion. If the circuitry is busy by a previous conversion
+ * the function return a non-zero value, if the conversion is
+ * successfully initialized the function return zero.
+ */
+extern int gradcdac_dac_convert_try(void *cookie, unsigned short digital_value);
+
+/* Initializes a digital to analogue conversion by waiting until
+ * previous conversions is finished before procceding with the
+ * conversion. The Waiting is implemented as a busy loop utilizing
+ * 100% CPU load.
+ */
+extern void gradcdac_dac_convert(void *cookie, unsigned short digital_value);
+
+extern unsigned int gradcdac_get_adrinput(void *cookie);
+extern void gradcdac_set_adrinput(void *cookie, unsigned int input);
+
+extern unsigned int gradcdac_get_adroutput(void *cookie);
+extern void gradcdac_set_adroutput(void *cookie, unsigned int output);
+
+extern unsigned int gradcdac_get_adrdir(void *cookie);
+extern void gradcdac_set_adrdir(void *cookie, unsigned int dir);
+
+extern unsigned int gradcdac_get_datainput(void *cookie);
+extern void gradcdac_set_datainput(void *cookie, unsigned int input);
+
+extern unsigned int gradcdac_get_dataoutput(void *cookie);
+extern void gradcdac_set_dataoutput(void *cookie, unsigned int output);
+
+extern unsigned int gradcdac_get_datadir(void *cookie);
+extern void gradcdac_set_datadir(void *cookie, unsigned int dir);
+
+/* Show one or all GRADCDAC cores. If cookie is NULL all GRADCDAC's are shown */
+extern void grAdcDacShow(void *cookie);
+
+/* Register Driver routine */
+extern void gradcdac_register_drv (void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/include/graes.h b/c/src/lib/libbsp/sparc/shared/include/graes.h
new file mode 100644
index 0000000000..e79df9d1c6
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/graes.h
@@ -0,0 +1,136 @@
+/* GRAES Packetwire
+ *
+ * --------------------------------------------------------------------------
+ * -- This file is a part of GAISLER RESEARCH source code.
+ * -- Copyright (C) 2009, Gaisler Research AB - all rights reserved.
+ * --
+ * -- ANY USE OR REDISTRIBUTION IN PART OR IN WHOLE MUST BE HANDLED IN
+ * -- ACCORDANCE WITH THE GAISLER LICENSE AGREEMENT AND MUST BE APPROVED
+ * -- IN ADVANCE IN WRITING.
+ * --
+ * -- BY DEFAULT, DISTRIBUTION OR DISCLOSURE IS NOT PERMITTED.
+ * --------------------------------------------------------------------------
+ *
+ */
+
+#ifndef __GRAES_H__
+#define __GRAES_H__
+
+#include <rtems.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GRAES_IOC_UNUSED 0
+
+/* Driver operation controlling commands */
+#define GRAES_IOC_START 1
+#define GRAES_IOC_STOP 2
+#define GRAES_IOC_ISSTARTED 3
+#define GRAES_IOC_SET_BLOCKING_MODE 4
+#define GRAES_IOC_SET_TIMEOUT 5
+
+/* Available only in RUNNING mode */
+#define GRAES_IOC_ENCRYPT 17
+
+/* Available only in STOPPED mode */
+#define GRAES_IOC_SET_CONFIG 32
+
+/* Available in both running and stopped mode */
+#define GRAES_IOC_RECLAIM 64
+#define GRAES_IOC_GET_CONFIG 65
+#define GRAES_IOC_GET_HW_IMPL 66
+#define GRAES_IOC_GET_HW_STATUS 67 /* Not implemented */
+#define GRAES_IOC_GET_STATS 69
+#define GRAES_IOC_CLR_STATS 70
+
+#define GRAES_IOC_PRINT_STATUS 71
+
+
+
+/* Args to GRTC_IOC_SET_BLOCKING_MODE */
+enum {
+ GRAES_BLKMODE_POLL = 0, /* Never block (polling mode) */
+ GRAES_BLKMODE_BLK = 1, /* Block until at least 1 byte can be read */
+};
+
+struct graes_ioc_hw {
+ unsigned short key_size; /* KEY Size */
+};
+
+struct graes_print_status {
+ unsigned short printbd;
+};
+
+
+/* Argument of GRAES_IOC_SET_CONFIG and GRAES_IOC_GET_CONFIG.
+ * Driver and Hardware configuration.
+ *
+ * Pointer to:
+ */
+struct graes_ioc_config {
+
+ unsigned short key_size;
+
+ /* Interrupt options */
+ unsigned int enable_cnt; /* Number of frames in between Interrupt is generated, Zero disables interrupt */
+ int isr_desc_proc; /* Enable ISR to process descriptors */
+ int blocking; /* Blocking mode select (POLL,BLK..) */
+ rtems_interval timeout; /* Blocking mode timeout */
+};
+
+struct graes_block;
+
+struct graes_list {
+ struct graes_block *head; /* First Frame in list */
+ struct graes_block *tail; /* Last Frame in list */
+};
+
+#define GRAES_FLAGS_PROCESSED 0x01
+#define GRRM_FLAGS_ERR 0x02
+
+#define GRAES_FLAGS_TRANSLATE (1<<31) /* Translate block payload address from CPU address to remote bus (the bus GRAES is resident on) */
+#define GRAES_FLAGS_TRANSLATE_AND_REMEMBER (1<<30) /* As GRAES_FLAGS_TRANSLATE, however if the translated payload address equals the payload address
+ * the GRAES_FLAGS_TRANSLATE_AND_REMEMBER bit is cleared and the GRAES_FLAGS_TRANSLATE bit is set */
+#define GRAES_FLAGS_COPY_DATA (1<<29) /* Where available: Transfer Frame payload to target, may be used for SpaceWire, where the GRAES driver transfer
+ * the payload to a buffer on the SpaceWire target.
+ */
+
+#define GRAES_FLAGS_MASK (GRAES_BD_ED)
+
+#define GRAES_BD_ED_BIT 4
+
+#define GRAES_BD_ED (1<<GRAES_BD_ED_BIT)
+
+
+/* The GRAES software representation of a Frame */
+struct graes_block {
+ /* Options and status */
+ unsigned int flags; /* bypass options, and sent/error status */
+ struct graes_block *next; /* Next packet in chain */
+ int length;
+ unsigned char *key;
+ unsigned char *iv;
+ unsigned char *payload; /* in */
+ unsigned char *out; /* out */
+};
+
+#define FRAME_SIZE(payloadlen) (sizeof(struct graes_block)+payloadlen)
+
+struct graes_ioc_stats {
+ unsigned long long blocks_processed;
+ unsigned int err_underrun;
+ unsigned int err_tx;
+ unsigned int err_ahb;
+ unsigned int err_transfer_frame;
+};
+
+/* Register GRAES driver at driver manager */
+void graes_register_drv(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GRAES_H__ */
diff --git a/c/src/lib/libbsp/sparc/shared/include/grascs.h b/c/src/lib/libbsp/sparc/shared/include/grascs.h
new file mode 100644
index 0000000000..84afc942a8
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/grascs.h
@@ -0,0 +1,97 @@
+/*
+ * Header file for GRASCS RTEMS driver
+ *
+ * --------------------------------------------------------------------------
+ * -- This file is a part of GAISLER RESEARCH source code.
+ * -- Copyright (C) 2008, Gaisler Research AB - all rights reserved.
+ * --
+ * -- ANY USE OR REDISTRIBUTION IN PART OR IN WHOLE MUST BE HANDLED IN
+ * -- ACCORDANCE WITH THE GAISLER LICENSE AGREEMENT AND MUST BE APPROVED
+ * -- IN ADVANCE IN WRITING.
+ * --
+ * -- BY DEFAULT, DISTRIBUTION OR DISCLOSURE IS NOT PERMITTED.
+ * --------------------------------------------------------------------------
+ *
+ */
+
+#ifndef __GRASCS_H__
+#define __GRASCS_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Minimum and maximum system frequency */
+#define GRASCS_MIN_SFREQ 10000
+#define GRASCS_MAX_SFREQ 255000
+
+/* Default, minimum and maximum ETR pulse frequency */
+#define GRASCS_DEFAULT_ETRFREQ 10
+#define GRASCS_MIN_ETRFREQ 1
+#define GRASCS_MAX_ETRFREQ 100
+
+/* Maximum number of external time markers */
+#define GRASCS_MAX_TMS 6
+
+/* Error codes */
+#define GRASCS_ERROR_STARTSTOP 1 /* Serial/synch interface is running/stopped */
+#define GRASCS_ERROR_TRANSACTIVE 2 /* Busy with transaction */
+#define GRASCS_ERROR_CAPFAULT 3 /* Core capabilities prohibit request */
+
+/* Command register */
+#define GRASCS_CMD_RESET (1 << 0)
+#define GRASCS_CMD_STARTSTOP (1 << 1)
+#define GRASCS_CMD_ESTARTSTOP (1 << 2)
+#define GRASCS_CMD_SENDTM (1 << 3)
+#define GRASCS_CMD_ETRCTRL (7 << 4)
+#define GRASCS_CMD_ETRCTRL_BITS 4
+#define GRASCS_CMD_SLAVESEL (15 << 8)
+#define GRASCS_CMD_SLAVESEL_BITS 8
+#define GRASCS_CMD_TCDONE (1 << 12)
+#define GRASCS_CMD_TMDONE (1 << 13)
+#define GRASCS_CMD_US1 (255 << 16)
+#define GRASCS_CMD_US1_BITS 16
+#define GRASCS_CMD_US1C (1 << 24)
+
+/* Clock scale register */
+#define GRASCS_CLK_ETRFREQ_BITS 12
+
+/* Status register */
+#define GRASCS_STS_RUNNING (1 << 0)
+#define GRASCS_STS_ERUNNING (1 << 1)
+#define GRASCS_STS_TCDONE (1 << 4)
+#define GRASCS_STS_TMDONE (1 << 5)
+#define GRASCS_STS_DBITS_BITS 8
+#define GRASCS_STS_NSLAVES_BITS 13
+#define GRASCS_STS_USCONF_BITS 18
+#define GRASCS_STS_TMCONF_BITS 19
+
+extern int ASCS_init();
+
+extern int ASCS_input_select(int slave);
+
+extern int ASCS_etr_select(int etr, int freq);
+
+extern void ASCS_start(void);
+
+extern void ASCS_stop(void);
+
+extern int ASCS_iface_status(void);
+
+extern int ASCS_TC_send(int *word);
+
+extern int ASCS_TC_send_block(int *block, int ntrans);
+
+extern void ASCS_TC_sync_start(void);
+
+extern void ASCS_TC_sync_stop(void);
+
+extern int ASCS_TM_recv(int *word);
+
+extern int ASCS_TM_recv_block(int *block, int ntrans);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/include/grcan.h b/c/src/lib/libbsp/sparc/shared/include/grcan.h
index 8b3ed15e55..3f5dcbee72 100644
--- a/c/src/lib/libbsp/sparc/shared/include/grcan.h
+++ b/c/src/lib/libbsp/sparc/shared/include/grcan.h
@@ -1,8 +1,8 @@
/*
* Macros used for grcan controller
*
- * COPYRIGHT (c) 2007.
- * Gaisler Research
+ * COPYRIGHT (c) 2008.
+ * Aeroflex Gaisler.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
@@ -13,8 +13,6 @@
#ifndef __GRCAN_H__
#define __GRCAN_H__
-#include <ambapp.h>
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -181,20 +179,8 @@ typedef struct {
#define GRCAN_IOC_SET_SFILTER 40 /* Set Sync Messages RX/TX filters, NULL disables the IRQ completely */
#define GRCAN_IOC_GET_STATUS 41 /* Get status register of GRCAN core */
-struct grcan_device_info {
- unsigned int base_address;
- int irq;
-};
-
-/* Use hard coded addresses and IRQs to find hardware */
-int grcan_register_abs(struct grcan_device_info *devices, int dev_cnt);
-/* Use prescanned AMBA Plug&Play information to find all GRFIFO cores */
-int grcan_register(amba_confarea_type *abus);
-#if 0
-void grcan_register(unsigned int baseaddr, unsigned int ram_base);
-void grcan_interrupt_handler(rtems_vector_number v);
-#endif
+void grcan_register_drv(void);
#ifdef __cplusplus
}
diff --git a/c/src/lib/libbsp/sparc/shared/include/grcan_rasta.h b/c/src/lib/libbsp/sparc/shared/include/grcan_rasta.h
deleted file mode 100644
index 1f96da6bef..0000000000
--- a/c/src/lib/libbsp/sparc/shared/include/grcan_rasta.h
+++ /dev/null
@@ -1,24 +0,0 @@
-
-#ifndef __GRCAN_RASTA_H__
-#define __GRCAN_RASTA_H__
-
-#include <grcan.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Registers the GRCAN for RASTA
- *
- * rambase is address of the first GRCAN core has it's TX buffer, followed by
- * it's RX buffer
- */
-int grcan_rasta_ram_register(amba_confarea_type *abus, int rambase);
-
-extern void (*grcan_rasta_int_reg)(void *handler, int irq, void *arg);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/c/src/lib/libbsp/sparc/shared/include/grctm.h b/c/src/lib/libbsp/sparc/shared/include/grctm.h
new file mode 100644
index 0000000000..5f8c104681
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/grctm.h
@@ -0,0 +1,169 @@
+/* GRCTM - CCSDS Time Manager - register driver interface.
+ *
+ * COPYRIGHT (c) 2009.
+ * Aeroflex Gaisler AB
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ */
+
+#ifndef __GRCTM_H__
+#define __GRCTM_H__
+
+#define DAT0_IRQ 0x1
+#define DAT1_IRQ 0x2
+#define DAT2_IRQ 0x4
+#define PULSE0_IRQ 0x10
+#define PULSE1_IRQ 0x20
+#define PULSE2_IRQ 0x40
+#define PULSE3_IRQ 0x80
+#define PULSE4_IRQ 0x100
+#define PULSE5_IRQ 0x200
+#define PULSE6_IRQ 0x400
+#define PULSE7_IRQ 0x800
+
+struct grctm_regs {
+ volatile unsigned int grr;
+ volatile unsigned int gcr;
+ volatile unsigned int gsr;
+ volatile unsigned int unused[2];
+ volatile unsigned int pfr;
+ volatile unsigned int etcr;
+ volatile unsigned int etfr;
+ volatile unsigned int dcr0;
+ volatile unsigned int dfr0;
+ volatile unsigned int dcr1;
+ volatile unsigned int dfr1;
+ volatile unsigned int dcr2;
+ volatile unsigned int dfr2;
+ volatile unsigned int stcr;
+ volatile unsigned int stfr;
+ volatile unsigned int pdr[8];
+ volatile unsigned int pimsr;
+ volatile unsigned int pimr;
+ volatile unsigned int pisr;
+ volatile unsigned int pir;
+ volatile unsigned int imr;
+ volatile unsigned int picr;
+ volatile unsigned int unused1[2];
+ volatile unsigned int etir;
+ volatile unsigned int fsir;
+ volatile unsigned int serconf;
+ volatile unsigned int unused2;
+ volatile unsigned int twsc;
+ volatile unsigned int twadj;
+ volatile unsigned int twtx;
+ volatile unsigned int twrx;
+};
+
+struct grctm_stats {
+
+ /* IRQ Stats */
+ unsigned int nirqs;
+ unsigned int pulse;
+};
+
+/* Function ISR callback prototype */
+typedef void (*grctm_isr_t)(unsigned int pimr, void *data);
+
+/* Open a GRCTM device by minor number. */
+extern void *grctm_open(int minor);
+
+/* Close a previously opened GRCTM device */
+extern void grctm_close(void *spwcuc);
+
+/* Hardware Reset of GRCTM */
+extern int grctm_reset(void *grctm);
+
+/* Enable Interrupts at Interrupt controller */
+extern void grctm_int_enable(void *grctm);
+
+/* Disable Interrupts at Interrupt controller */
+extern void grctm_int_disable(void *grctm);
+
+/* Clear Statistics gathered by the driver */
+extern void grctm_clr_stats(void *grctm);
+
+/* Get Statistics gathered by the driver */
+extern void grctm_get_stats(void *grctm, struct grctm_stats *stats);
+
+/* Register an Interrupt handler and custom data, the function call is
+ * removed by setting func to NULL.
+ */
+extern void grctm_int_register(void *grctm, grctm_isr_t func, void *data);
+
+/* Enable external synchronisation (from spwcuc) */
+extern void grctm_enable_ext_sync(void *grctm);
+
+/* Disable external synchronisation (from spwcuc) */
+extern void grctm_disable_ext_sync(void *grctm);
+
+/* Enable TimeWire synchronisation */
+extern void grctm_enable_tw_sync(void *grctm);
+
+/* Disable TimeWire synchronisation */
+extern void grctm_disable_tw_sync(void *grctm);
+
+/* Disable frequency synthesizer from driving ET */
+extern void grctm_disable_fs(void *grctm);
+
+/* Enable frequency synthesizer to drive ET */
+extern void grctm_enable_fs(void *grctm);
+
+/* Return elapsed coarse time */
+extern unsigned int grctm_get_et_coarse(void *grctm);
+
+/* Return elapsed fine time */
+extern unsigned int grctm_get_et_fine(void *grctm);
+
+/* Return elapsed time (coarse and fine) */
+extern unsigned long long grctm_get_et(void *grctm);
+
+/* Return 1 if specified datation has been latched */
+extern int grctm_is_dat_latched(void *grctm, int dat);
+
+/* Set triggering edge of datation input */
+extern void grctm_set_dat_edge(void *grctm, int dat, int edge);
+
+/* Return latched datation coarse time */
+extern unsigned int grctm_get_dat_coarse(void *grctm, int dat);
+
+/* Return latched datation fine time */
+extern unsigned int grctm_get_dat_fine(void *grctm, int dat);
+
+/* Return latched datation ET */
+extern unsigned long long grctm_get_dat_et(void *grctm, int dat);
+
+/* Return current pulse configuration */
+extern unsigned int grctm_get_pulse_reg(void *grctm, int pulse);
+
+/* Set pulse register */
+extern void grctm_set_pulse_reg(void *grctm, int pulse, unsigned int val);
+
+/* Configure pulse: pp = period, pw = width, pl = level, en = enable */
+extern void grctm_cfg_pulse(void *grctm, int pulse, int pp, int pw, int pl, int en);
+
+/* Enable pulse output */
+extern void grctm_enable_pulse(void *grctm, int pulse);
+
+/* Disable pulse output */
+extern void grctm_disable_pulse(void *grctm, int pulse);
+
+/* Clear interrupts */
+extern void grctm_clear_irqs(void *grctm, int irqs);
+
+/* Enable interrupts */
+extern void grctm_enable_irqs(void *grctm, int irqs);
+
+/* Set Frequency synthesizer increment */
+void grctm_set_fs_incr(void *grctm, int incr);
+
+/* Set ET increment */
+void grctm_set_et_incr(void *grctm, int incr);
+
+/* Register the GRCTM driver to Driver Manager */
+extern void grctm_register(void);
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/include/greth.h b/c/src/lib/libbsp/sparc/shared/include/greth.h
new file mode 100644
index 0000000000..021d2fc6bb
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/greth.h
@@ -0,0 +1,159 @@
+/*
+ * Gaisler Research ethernet MAC driver
+ * adapted from Opencores driver by Marko Isomaki
+ *
+ * The license and distribution terms for this file may be
+ * found in found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id: greth.h,v 1.4 2007/09/07 15:01:15 joel Exp $
+ */
+
+
+#ifndef __GRETH_H__
+#define __GRETH_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Configuration Information */
+
+typedef struct {
+ uint32_t base_address;
+ uint32_t vector;
+ uint32_t txd_count;
+ uint32_t rxd_count;
+} greth_configuration_t;
+
+/* Ethernet configuration registers */
+
+typedef struct _greth_regs {
+ volatile uint32_t ctrl; /* Ctrl Register */
+ volatile uint32_t status; /* Status Register */
+ volatile uint32_t mac_addr_msb; /* Bit 47-32 of MAC address */
+ volatile uint32_t mac_addr_lsb; /* Bit 31-0 of MAC address */
+ volatile uint32_t mdio_ctrl; /* MDIO control and status */
+ volatile uint32_t txdesc; /* Transmit descriptor pointer */
+ volatile uint32_t rxdesc; /* Receive descriptor pointer */
+} greth_regs;
+
+#define GRETH_TOTAL_BD 128
+#define GRETH_MAXBUF_LEN 1520
+
+/* Tx BD */
+#define GRETH_TXD_ENABLE 0x0800 /* Tx BD Enable */
+#define GRETH_TXD_WRAP 0x1000 /* Tx BD Wrap (last BD) */
+#define GRETH_TXD_IRQ 0x2000 /* Tx BD IRQ Enable */
+#define GRETH_TXD_MORE 0x20000 /* Tx BD More (more descs for packet) */
+#define GRETH_TXD_IPCS 0x40000 /* Tx BD insert ip chksum */
+#define GRETH_TXD_TCPCS 0x80000 /* Tx BD insert tcp chksum */
+#define GRETH_TXD_UDPCS 0x100000 /* Tx BD insert udp chksum */
+
+#define GRETH_TXD_UNDERRUN 0x4000 /* Tx BD Underrun Status */
+#define GRETH_TXD_RETLIM 0x8000 /* Tx BD Retransmission Limit Status */
+#define GRETH_TXD_LATECOL 0x10000 /* Tx BD Late Collision */
+
+#define GRETH_TXD_STATS (GRETH_TXD_UNDERRUN | \
+ GRETH_TXD_RETLIM | \
+ GRETH_TXD_LATECOL)
+
+#define GRETH_TXD_CS (GRETH_TXD_IPCS | \
+ GRETH_TXD_TCPCS | \
+ GRETH_TXD_UDPCS)
+
+/* Rx BD */
+#define GRETH_RXD_ENABLE 0x0800 /* Rx BD Enable */
+#define GRETH_RXD_WRAP 0x1000 /* Rx BD Wrap (last BD) */
+#define GRETH_RXD_IRQ 0x2000 /* Rx BD IRQ Enable */
+
+#define GRETH_RXD_DRIBBLE 0x4000 /* Rx BD Dribble Nibble Status */
+#define GRETH_RXD_TOOLONG 0x8000 /* Rx BD Too Long Status */
+#define GRETH_RXD_CRCERR 0x10000 /* Rx BD CRC Error Status */
+#define GRETH_RXD_OVERRUN 0x20000 /* Rx BD Overrun Status */
+#define GRETH_RXD_LENERR 0x40000 /* Rx BD Length Error */
+#define GRETH_RXD_ID 0x40000 /* Rx BD IP Detected */
+#define GRETH_RXD_IR 0x40000 /* Rx BD IP Chksum Error */
+#define GRETH_RXD_UD 0x40000 /* Rx BD UDP Detected*/
+#define GRETH_RXD_UR 0x40000 /* Rx BD UDP Chksum Error */
+#define GRETH_RXD_TD 0x40000 /* Rx BD TCP Detected */
+#define GRETH_RXD_TR 0x40000 /* Rx BD TCP Chksum Error */
+
+
+#define GRETH_RXD_STATS (GRETH_RXD_OVERRUN | \
+ GRETH_RXD_DRIBBLE | \
+ GRETH_RXD_TOOLONG | \
+ GRETH_RXD_CRCERR)
+
+/* CTRL Register */
+#define GRETH_CTRL_TXEN 0x00000001 /* Transmit Enable */
+#define GRETH_CTRL_RXEN 0x00000002 /* Receive Enable */
+#define GRETH_CTRL_TXIRQ 0x00000004 /* Transmit Enable */
+#define GRETH_CTRL_RXIRQ 0x00000008 /* Receive Enable */
+#define GRETH_CTRL_FULLD 0x00000010 /* Full Duplex */
+#define GRETH_CTRL_PRO 0x00000020 /* Promiscuous (receive all) */
+#define GRETH_CTRL_RST 0x00000040 /* Reset MAC */
+#define GRETH_CTRL_DD 0x00001000 /* Disable EDCL Duplex Detection */
+
+/* Status Register */
+#define GRETH_STATUS_RXERR 0x00000001 /* Receive Error */
+#define GRETH_STATUS_TXERR 0x00000002 /* Transmit Error IRQ */
+#define GRETH_STATUS_RXIRQ 0x00000004 /* Receive Frame IRQ */
+#define GRETH_STATUS_TXIRQ 0x00000008 /* Transmit Error IRQ */
+#define GRETH_STATUS_RXAHBERR 0x00000010 /* Receiver AHB Error */
+#define GRETH_STATUS_TXAHBERR 0x00000020 /* Transmitter AHB Error */
+
+/* MDIO Control */
+#define GRETH_MDIO_WRITE 0x00000001 /* MDIO Write */
+#define GRETH_MDIO_READ 0x00000002 /* MDIO Read */
+#define GRETH_MDIO_LINKFAIL 0x00000004 /* MDIO Link failed */
+#define GRETH_MDIO_BUSY 0x00000008 /* MDIO Link Busy */
+#define GRETH_MDIO_REGADR 0x000007C0 /* Register Address */
+#define GRETH_MDIO_PHYADR 0x0000F800 /* PHY address */
+#define GRETH_MDIO_DATA 0xFFFF0000 /* MDIO DATA */
+
+
+/* MII registers */
+#define GRETH_MII_EXTADV_1000FD 0x00000200
+#define GRETH_MII_EXTADV_1000HD 0x00000100
+#define GRETH_MII_EXTPRT_1000FD 0x00000800
+#define GRETH_MII_EXTPRT_1000HD 0x00000400
+
+#define GRETH_MII_100T4 0x00000200
+#define GRETH_MII_100TXFD 0x00000100
+#define GRETH_MII_100TXHD 0x00000080
+#define GRETH_MII_10FD 0x00000040
+#define GRETH_MII_10HD 0x00000020
+
+
+
+/* Attach routine */
+
+void greth_register_drv(void);
+
+/* PHY data */
+struct phy_device_info
+{
+ int vendor;
+ int device;
+ int rev;
+
+ int adv;
+ int part;
+
+ int extadv;
+ int extpart;
+};
+
+/*
+#ifdef CPU_U32_FIX
+void ipalign(struct mbuf *m);
+#endif
+
+*/
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/c/src/lib/libbsp/sparc/shared/include/grgpio.h b/c/src/lib/libbsp/sparc/shared/include/grgpio.h
new file mode 100644
index 0000000000..b9900c83f5
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/grgpio.h
@@ -0,0 +1,26 @@
+/*
+ * GRGPIO GPIO Driver interface.
+ *
+ * COPYRIGHT (c) 2009.
+ * Gaisler Research
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ */
+
+#ifndef __GRGPIO_H__
+#define __GRGPIO_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void grgpio_register_drv (void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/include/grlib.h b/c/src/lib/libbsp/sparc/shared/include/grlib.h
new file mode 100644
index 0000000000..00373452f3
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/grlib.h
@@ -0,0 +1,92 @@
+/*
+ * Common GRLIB AMBA Core Register definitions
+ *
+ * COPYRIGHT (c) 2008.
+ * Aeroflex Gaisler.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ */
+
+#ifndef __GRLIB_H__
+#define __GRLIB_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ESA MEMORY CONTROLLER */
+struct mctrl_regs {
+ unsigned int mcfg1;
+ unsigned int mcfg2;
+ unsigned int mcfg3;
+};
+
+/* APB UART */
+struct apbuart_regs {
+ volatile unsigned int data;
+ volatile unsigned int status;
+ volatile unsigned int ctrl;
+ volatile unsigned int scaler;
+};
+
+/* IRQMP and IRQAMP interrupt controllers */
+struct irqmp_regs {
+ volatile unsigned int ilevel; /* 0x00 */
+ volatile unsigned int ipend; /* 0x04 */
+ volatile unsigned int iforce; /* 0x08 */
+ volatile unsigned int iclear; /* 0x0c */
+ volatile unsigned int mpstat; /* 0x10 */
+ volatile unsigned int bcast; /* 0x14 */
+ volatile unsigned int notused02; /* 0x18 */
+ volatile unsigned int notused03; /* 0x1c */
+ volatile unsigned int ampctrl; /* 0x20 */
+ volatile unsigned int icsel[2]; /* 0x24,0x28 */
+ volatile unsigned int notused13; /* 0x2c */
+ volatile unsigned int notused20; /* 0x30 */
+ volatile unsigned int notused21; /* 0x34 */
+ volatile unsigned int notused22; /* 0x38 */
+ volatile unsigned int notused23; /* 0x3c */
+ volatile unsigned int mask[16]; /* 0x40 */
+ volatile unsigned int force[16]; /* 0x80 */
+ /* Extended IRQ registers */
+ volatile unsigned int intid[16]; /* 0xc0 */
+ /* 0x100, align to 4Kb boundary */
+ volatile unsigned int resv1[(0x1000-0x100)/4];
+};
+
+/* GPTIMER Timer instance */
+struct gptimer_timer_regs {
+ volatile unsigned int value;
+ volatile unsigned int reload;
+ volatile unsigned int ctrl;
+ volatile unsigned int notused;
+};
+
+/* GPTIMER common registers */
+struct gptimer_regs {
+ volatile unsigned int scaler_value; /* common timer registers */
+ volatile unsigned int scaler_reload;
+ volatile unsigned int cfg;
+ volatile unsigned int notused;
+ struct gptimer_timer_regs timer[7];
+};
+
+/* GRGPIO GPIO */
+struct grgpio_regs {
+ volatile unsigned int data; /* 0x00 I/O port data register */
+ volatile unsigned int output; /* 0x04 I/O port output register */
+ volatile unsigned int dir; /* 0x08 I/O port direction register */
+ volatile unsigned int imask; /* 0x0C Interrupt mask register */
+ volatile unsigned int ipol; /* 0x10 Interrupt polarity register */
+ volatile unsigned int iedge; /* 0x14 Interrupt edge register */
+ volatile unsigned int bypass; /* 0x18 Bypass register */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/include/grpci2.h b/c/src/lib/libbsp/sparc/shared/include/grpci2.h
new file mode 100644
index 0000000000..c2c178f41b
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/grpci2.h
@@ -0,0 +1,51 @@
+#ifndef __GRPCI2_H__
+#define __GRPCI2_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void grpci2_register_drv(void);
+
+/* Driver Resources:
+ *
+ * PCI Interrupts
+ * ==============
+ * The interrupt settings are normally autodetected from Plyg&Play, however
+ * if IRQs are routed using custom GPIO pins in order to reduce the PIN count
+ * reserved for PCI, the options below can be used to tell GRPCI2 driver which
+ * System IRQ a PCI interrupt is connected to.
+ * Name="INTA#", Type=INT, System Interrupt number that PCI INTA is connected to
+ * Name="INTB#", Type=INT, System Interrupt number that PCI INTB is connected to
+ * Name="INTC#", Type=INT, System Interrupt number that PCI INTC is connected to
+ * Name="INTD#", Type=INT, System Interrupt number that PCI INTD is connected to
+ *
+ * Name="IRQmask", Type=INT,
+ *
+ * PCI Bytetwisting (endianess)
+ * ============================
+ * Name="byteTwisting", Type=INT, Enable/Disable Bytetwisting by hardware
+ *
+ * PCI Host's Target BARs setup
+ * ============================
+ * The Host's BARs are not configured by the configuration routines, by default
+ * the BARs are configured disabled (BAR=0) except for BAR0 which is mapped to
+ * the Main Memory for the Host.
+ * Name="tgtBarCfg", Type=PTR (*grpci2_pcibar_cfg), Target PCI BARs of Host
+ */
+
+/* When the Host acts as a target on the PCI bus, the PCI BARs of the host's
+ * configuration space determine at which PCI address the Host will be accessed
+ * at and when accessing a BAR which AMBA address it will be translated to.
+ */
+struct grpci2_pcibar_cfg {
+ unsigned int pciadr; /* PCI address of BAR (BAR content) */
+ unsigned int ahbadr; /* 'pciadr' translated to this AHB Address */
+ unsigned int barsize; /* PCI BAR Size, must be a power of 2 */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/include/grpwm.h b/c/src/lib/libbsp/sparc/shared/include/grpwm.h
new file mode 100644
index 0000000000..6d84462394
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/grpwm.h
@@ -0,0 +1,128 @@
+/*
+ * GRPWM PWM Driver interface.
+ *
+ * COPYRIGHT (c) 2009.
+ * Gaisler Research
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ */
+
+#ifndef __GRPWM_H__
+#define __GRPWM_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void grpwm_register_drv (void);
+
+#define GRPWM_IOCTL_GET_CAP 1 /* Get Capabilities */
+#define GRPWM_IOCTL_SET_CONFIG 2 /* Configure one PWM Channel */
+#define GRPWM_IOCTL_SET_SCALER 3 /* Set one scaler */
+#define GRPWM_IOCTL_UPDATE 4 /* Set current period and compare value */
+#define GRPWM_IOCTL_IRQ 5 /* Set up IRQ handling */
+
+/*** Argument for GRPWM_IOCTL_GET_CAP ***/
+
+/* The Capability of the PWM core */
+struct grpwm_ioctl_cap {
+ int channel_cnt; /* Number of channels */
+ unsigned int pwm; /* Capability1 register */
+ unsigned int wave; /* Capability2 register, Wave form capabilities of last PWM channel, otherwise 0 */
+};
+
+/*** Argument for GRPWM_IOCTL_GET_CONFIG and GRPWM_IOCTL_SET_CONFIG ***/
+
+/* Config One PWM */
+struct grpwm_ioctl_config {
+ unsigned int channel; /* Select channel to configure */
+
+ /* Specific for one PWM channel */
+ unsigned int options; /* PWM options */
+ unsigned char dbscaler; /* value greater than 15 disable Dead band */
+ unsigned char scaler_index; /* Select scaler used by PWM channel */
+
+ /* IRQ Setup */
+ unsigned char irqscaler; /* IRQ scaler */
+ void *isr_arg; /* Argument of IRQ handler */
+ void (*isr)(int channel, void *arg); /* Interrupt service routine for this PWM Channel */
+
+ /* Waveform set up */
+ int wave_activate; /* Enables Waveform functionality */
+ unsigned int wave_synccfg; /* Bits [29,30,31] is written into Wave-Config register */
+ unsigned int wave_sync; /* Sets sync compare register */
+ unsigned int *wave_data; /* If not NULL, the Wave RAM is filled with data */
+ unsigned int wave_data_length; /* Length of Wave RAM Data, Also used for wstopaddr */
+};
+
+#define GRPWM_CONFIG_OPTION_FLIP 0x04000000 /* Set this to Flip PWM output pair */
+#define GRPWM_CONFIG_OPTION_DEAD_BAND 0x00200000 /* Dead Band enable */
+#define GRPWM_CONFIG_OPTION_SYMMETRIC 0x00000040 /* If not defined, asymmetric */
+#define GRPWM_CONFIG_OPTION_ASYMMERTIC 0
+#define GRPWM_CONFIG_OPTION_DUAL 0x00000020 /* Dual Compare Enable */
+#define GRPWM_CONFIG_OPTION_PAIR 0x00000004 /* PWM Pair Enable */
+#define GRPWM_CONFIG_OPTION_SINGLE 0x00000000 /* PWM Pair Disable */
+#define GRPWM_CONFIG_OPTION_POLARITY_HIGH 0x00000002 /* PWM Polarity HIGH */
+#define GRPWM_CONFIG_OPTION_POLARITY_LOW 0x00000000 /* PWM Polarity LOW */
+
+#define GRPWM_CONFIG_OPTION_MASK ( \
+ GRPWM_CONFIG_OPTION_DEAD_BAND | GRPWM_CONFIG_OPTION_SYMMETRIC | \
+ GRPWM_CONFIG_OPTION_DUAL | GRPWM_CONFIG_OPTION_PAIR | \
+ GRPWM_CONFIG_OPTION_POLARITY_HIGH \
+ )
+
+/*** Argument for GPPWM_IOCTL_SET_SCALER ***/
+
+struct grpwm_ioctl_scaler {
+ unsigned int index_mask;/* Scaler update index mask, bit 0 = Scaler 0, bit 1 = Scaler 1 */
+ unsigned int values[8]; /* Scaler update values, values[N] is stored into scaler N, if mask & 1<<N is set */
+};
+
+/*** Argument for GRPWM_IOCTL_UPDATE ***/
+
+#define GRPWM_UPDATE_OPTION_ENABLE 0x01 /* Enable the PWM core */
+#define GRPWM_UPDATE_OPTION_DISABLE 0x02 /* Disable the PWM core */
+#define GRPWM_UPDATE_OPTION_PERIOD 0x04 /* Update period register */
+#define GRPWM_UPDATE_OPTION_COMP 0x08 /* Update Compare register */
+#define GRPWM_UPDATE_OPTION_DBCOMP 0x10 /* Update Dead band register */
+#define GRPWM_UPDATE_OPTION_FIX 0x20 /* Update fix output pins (bypass PWM) */
+
+/* FIX PIN bit-mask */
+#define GRPWM_UPDATE_FIX_ENABLE 1 /* Enable force ouput */
+#define GRPWM_UPDATE_FIX_DISABLE 0 /* Disable force ouput */
+#define GRPWM_UPDATE_FIX_0_LOW 0 /* PIN 0 OUPUT: LOW */
+#define GRPWM_UPDATE_FIX_0_HIGH 2 /* PIN 0 OUPUT: HIGH */
+#define GRPWM_UPDATE_FIX_1_LOW 0 /* PIN 1 OUPUT: LOW */
+#define GRPWM_UPDATE_FIX_1_HIGH 4 /* PIN 1 OUPUT: HIGH */
+
+struct grpwm_ioctl_update_chan {
+ unsigned int options; /* Select what is updated */
+ unsigned int period; /* Period register content */
+ unsigned int compare; /* Compare register content */
+ unsigned int dbcomp; /* Dead band register content */
+ unsigned char fix; /* Bit-mask that select output on one or two PWM
+ * output pins. Depends on PAIR config value.
+ */
+};
+struct grpwm_ioctl_update {
+ unsigned char chanmask; /* Bit Mask select channels */
+ struct grpwm_ioctl_update_chan channels[8]; /* */
+};
+
+/*** Argument for GPPWM_IOCTL_IRQ ***/
+
+#define GRPWM_IRQ_DISABLE 0 /* Disable IRQ */
+#define GRPWM_IRQ_PERIOD 1 /* Enable IRQ on period match */
+#define GRPWM_IRQ_COMPARE 3 /* Enable IRQ on Compare Match */
+#define GRPWM_IRQ_CLEAR 0x10 /* Clear any pending IRQ on GRPWM and IRQ controller */
+
+#define GRPWM_IRQ_CHAN 0x100 /* Channel N is selected, by adding 0x100*N */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/include/grpwrx.h b/c/src/lib/libbsp/sparc/shared/include/grpwrx.h
new file mode 100644
index 0000000000..2f287181e6
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/grpwrx.h
@@ -0,0 +1,139 @@
+/* GRPWRX Packetwire
+ *
+ * --------------------------------------------------------------------------
+ * -- This file is a part of GAISLER RESEARCH source code.
+ * -- Copyright (C) 2009, Gaisler Research AB - all rights reserved.
+ * --
+ * -- ANY USE OR REDISTRIBUTION IN PART OR IN WHOLE MUST BE HANDLED IN
+ * -- ACCORDANCE WITH THE GAISLER LICENSE AGREEMENT AND MUST BE APPROVED
+ * -- IN ADVANCE IN WRITING.
+ * --
+ * -- BY DEFAULT, DISTRIBUTION OR DISCLOSURE IS NOT PERMITTED.
+ * --------------------------------------------------------------------------
+ *
+ */
+
+#ifndef __GRPWRX_H__
+#define __GRPWRX_H__
+
+#include <rtems.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GRPWRX_IOC_UNUSED 0
+
+/* Driver operation controlling commands */
+#define GRPWRX_IOC_START 1
+#define GRPWRX_IOC_STOP 2
+#define GRPWRX_IOC_ISSTARTED 3
+#define GRPWRX_IOC_SET_BLOCKING_MODE 4
+#define GRPWRX_IOC_SET_TIMEOUT 5
+
+/* Available only in RUNNING mode */
+#define GRPWRX_IOC_RECV 17
+
+/* Available only in STOPPED mode */
+#define GRPWRX_IOC_SET_CONFIG 32
+
+/* Available in both running and stopped mode */
+#define GRPWRX_IOC_RECLAIM 64
+#define GRPWRX_IOC_GET_CONFIG 65
+#define GRPWRX_IOC_GET_HW_IMPL 66
+#define GRPWRX_IOC_GET_HW_STATUS 67 /* Not implemented */
+#define GRPWRX_IOC_GET_STATS 69
+#define GRPWRX_IOC_CLR_STATS 70
+
+#define GRPWRX_IOC_PRINT_STATUS 71
+
+
+/* Args to GRTC_IOC_SET_BLOCKING_MODE */
+enum {
+ GRPWRX_BLKMODE_POLL = 0, /* Never block (polling mode) */
+ GRPWRX_BLKMODE_BLK = 1, /* Block until at least 1 byte can be read */
+};
+
+struct grpwrx_ioc_hw {
+
+ unsigned short fifo_size; /* FIFO Size */
+ unsigned short mode; /* frame mode = 1, packet mode = 0 */
+ unsigned short clkdivide; /* Clock divide */
+
+};
+
+struct grpwrx_print_status {
+ unsigned short printbd;
+
+};
+
+/* Argument of GRPWRX_IOC_SET_CONFIG and GRPWRX_IOC_GET_CONFIG.
+ * Driver and Hardware configuration.
+ *
+ * Pointer to:
+ */
+struct grpwrx_ioc_config {
+
+ int framing;
+
+ /* Physical layer options */
+ unsigned short phy_clkrise;
+ unsigned short phy_validpos;
+ unsigned short phy_readypos;
+ unsigned short phy_busypos;
+
+ /* Interrupt options */
+ unsigned int enable_cnt; /* Number of frames in between Interrupt is generated, Zero disables interrupt */
+ int isr_desc_proc; /* Enable ISR to process descriptors */
+ int blocking; /* Blocking mode select (POLL,BLK..) */
+ rtems_interval timeout; /* Blocking mode timeout */
+};
+
+struct grpwrx_packet;
+
+struct grpwrx_list {
+ struct grpwrx_packet *head; /* First Frame in list */
+ struct grpwrx_packet *tail; /* Last Frame in list */
+};
+
+#define GRPWRX_FLAGS_RECEIVED 0x01
+#define GRRM_FLAGS_ERR 0x02
+
+#define GRPWRX_FLAGS_TRANSLATE (1<<31) /* Translate frame payload address from CPU address to remote bus (the bus GRPWRX is resident on) */
+#define GRPWRX_FLAGS_TRANSLATE_AND_REMEMBER (1<<30) /* As GRPWRX_FLAGS_TRANSLATE, however if the translated payload address equals the payload address
+ * the GRPWRX_FLAGS_TRANSLATE_AND_REMEMBER bit is cleared and the GRPWRX_FLAGS_TRANSLATE bit is set */
+#define GRPWRX_FLAGS_COPY_DATA (1<<29) /* Where available: Transfer Frame payload to target, may be used for SpaceWire, where the GRPWRX driver transfer
+ * the payload to a buffer on the SpaceWire target.
+ */
+
+#define GRPWRX_FLAGS_FHP (1<<3)
+
+#define GRPWRX_FLAGS_MASK (GRPWRX_FLAGS_FHP)
+
+/* The GRPWRX software representation of a Frame */
+struct grpwrx_packet {
+ /* Options and status */
+ unsigned int flags; /* bypass options, and sent/error status */
+ struct grpwrx_packet *next; /* Next packet in chain */
+ int length;
+ unsigned char *payload; /* The Headers and Payload, Frame data and header must be word aligned */
+};
+
+#define FRAME_SIZE(payloadlen) (sizeof(struct grpwrx_packet)+payloadlen)
+
+struct grpwrx_ioc_stats {
+ unsigned long long packets_received;
+ unsigned int err_underrun;
+ unsigned int err_tx;
+ unsigned int err_ahb;
+ unsigned int err_transfer_frame;
+};
+
+/* Register GRPWRX driver at driver manager */
+void grpwrx_register_drv(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GRPWRX_H__ */
diff --git a/c/src/lib/libbsp/sparc/shared/include/grslink.h b/c/src/lib/libbsp/sparc/shared/include/grslink.h
new file mode 100644
index 0000000000..41b44772c1
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/grslink.h
@@ -0,0 +1,153 @@
+/*
+ * Header file for RTEMS GRSLINK SLINK master driver
+ *
+ * --------------------------------------------------------------------------
+ * -- This file is a part of GAISLER RESEARCH source code.
+ * -- Copyright (C) 2008, Gaisler Research AB - all rights reserved.
+ * --
+ * -- ANY USE OR REDISTRIBUTION IN PART OR IN WHOLE MUST BE HANDLED IN
+ * -- ACCORDANCE WITH THE GAISLER LICENSE AGREEMENT AND MUST BE APPROVED
+ * -- IN ADVANCE IN WRITING.
+ * --
+ * -- BY DEFAULT, DISTRIBUTION OR DISCLOSURE IS NOT PERMITTED.
+ * --------------------------------------------------------------------------
+ *
+ */
+
+#ifndef __GRSLINK_H__
+#define __GRSLINK_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**** Configuration ****/
+/* Collect statistics ? */
+#define SLINK_COLLECT_STATISTICS
+
+/* Frequency of SLINK SCLK */
+#define SLINK_FREQ_HZ 6000000
+/* Number of queues used in driver */
+#define SLINK_NUMQUEUES 4
+
+/* The four values below are only used in the demo software */
+#define SLINK_CORE_REGBASE 0x80000600
+#define SLINK_CORE_IRQ 6
+#define IRQ_CNTRL_REG 0x80000200
+#define IRQ_CNTRL_MASK_OFFSET 0x40
+
+/*
+ * Structure returned by SLINK_statistics if SLINK_COLLECT_STATISTCS has
+ * been defined
+ */
+typedef struct {
+ unsigned int parerr; /* Number of parity errors */
+ unsigned int recov; /* Number of receive overflows */
+ unsigned int reads; /* Number of completed READs */
+ unsigned int writes; /* Number of performed WRITES */
+ unsigned int sequences; /* Number of started SEQUENCEs */
+ unsigned int seqcomp; /* Number of completed SEQUENCEs */
+ unsigned int interrupts; /* Number of INTERRUPT transfers */
+ unsigned int lostwords; /* Number of lost words due to full queue */
+} SLINK_stats;
+
+/**** SLINK status codes ****/
+#define SLINK_ABORTED 0
+#define SLINK_QFULL 1
+#define SLINK_ACTIVE 2
+#define SLINK_AMBAERR 3
+#define SLINK_COMPLETED 4
+#define SLINK_PARERR 5
+#define SLINK_ROV 6 /* Only used internally in driver */
+
+/**** SLINK master register fields *****/
+/* Control register */
+#define SLINK_C_SLEN_POS 16
+#define SLINK_C_SRO (1 << 8)
+#define SLINK_C_SCN_POS 4
+#define SLINK_C_PAR (1 << 3)
+#define SLINK_C_AS (1 << 2)
+#define SLINK_C_SE (1 << 1)
+#define SLINK_C_SLE (1 << 0)
+
+/* Status register fields */
+#define SLINK_S_SI_POS 16
+#define SLINK_S_PERR (1 << 7)
+#define SLINK_S_AERR (1 << 6)
+#define SLINK_S_ROV (1 << 5)
+#define SLINK_S_RNE (1 << 4)
+#define SLINK_S_TNF (1 << 3)
+#define SLINK_S_SC (1 << 2)
+#define SLINK_S_SA (1 << 1)
+#define SLINK_S_SRX (1 << 0)
+
+/* Mask register fields */
+#define SLINK_M_PERRE (1 << 7)
+#define SLINK_M_AERRE (1 << 6)
+#define SLINK_M_ROVE (1 << 5)
+#define SLINK_M_RNEE (1 << 4)
+#define SLINK_M_TNFE (1 << 3)
+#define SLINK_M_SCE (1 << 2)
+#define SLINK_M_SAE (1 << 1)
+#define SLINK_M_SRXE (1 << 0)
+
+/**** Macros ****/
+/* Get channel field from received SLINK word */
+#define SLINK_WRD_CHAN(x) ((x >> 16) & 0xF)
+/* Get IO card # from received SLINK word */
+#define SLINK_WRD_CARDNUM(x) ((x >> 21) & 0x3)
+/* Get data part from SLINK word */
+#define SLINK_WRD_PAYLOAD(x) (x & 0xFFFF)
+
+/* Checks status value to see if transmit queue has free slot */
+#define SLINK_STS_TRANSFREE(x) (x & SLINK_S_TNF)
+/* Get Sequence Index value */
+#define SLINK_STS_SI(x) ((x >> 16) & 0xFF)
+
+/**** Function declarations, driver interface ****/
+/* Initializes the SLINK core */
+int SLINK_init(unsigned int nullwrd, int parity, int qsize,
+ void (*interrupt_trans_handler)(int),
+ void (*sequence_callback)(int));
+
+/* Enables the core */
+void SLINK_start(void);
+
+/* Disables the core */
+void SLINK_stop(void);
+
+/* Reads one word */
+int SLINK_read(int data, int channel, int *reply);
+
+/* Writes one word */
+int SLINK_write(int data, int channel);
+
+/* Peforms a SEQUENCE */
+int SLINK_seqstart(int *a, int *b, int n, int channel, int reconly);
+
+/* Aborts a SEQUENCE */
+void SLINK_seqabort(void);
+
+/* Status of current or last SEQUENCE */
+int SLINK_seqstatus(void);
+
+/* Number of words transferred in last SEQUENCE */
+int SLINK_seqwrds(void);
+
+/* Returns value of core's status register */
+int SLINK_hwstatus(void);
+
+/* Returns number of elements in queue associated with IO card */
+int SLINK_queuestatus(int iocard);
+
+/* Take first element from queue for IO card # 'iocard' */
+int SLINK_dequeue(int iocard, int *elem);
+
+/* Returns structure containing core driver statistics */
+SLINK_stats *SLINK_statistics(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GRSLINK_H__ */
diff --git a/c/src/lib/libbsp/sparc/shared/include/grspw.h b/c/src/lib/libbsp/sparc/shared/include/grspw.h
index 4c6c869d61..6e5ffe5cfb 100644
--- a/c/src/lib/libbsp/sparc/shared/include/grspw.h
+++ b/c/src/lib/libbsp/sparc/shared/include/grspw.h
@@ -1,7 +1,7 @@
/*
* Macros used for Spacewire bus
*
- * COPYRIGHT (c) 2007.
+ * COPYRIGHT (c) 2008.
* Gaisler Research
*
* The license and distribution terms for this file may be
@@ -26,12 +26,18 @@ typedef struct {
unsigned int txhsize;
} spw_ioctl_packetsize;
+#define GRSPW_PKTSEND_OPTION_HDR_CRC 0x1
+#define GRSPW_PKTSEND_OPTION_DATA_CRC 0x2
+#define GRSPW_PKTSEND_OPTION_NOCRCLEN(len) ((len & 0xf) << 8)
+#define GRSPW_PKTSEND_OPTION_NOCRCLEN_MASK 0xf00
+
typedef struct {
unsigned int hlen;
char *hdr;
unsigned int dlen;
char *data;
unsigned int sent;
+ unsigned int options;
} spw_ioctl_pkt_send;
typedef struct {
@@ -78,6 +84,11 @@ typedef struct {
unsigned int is_rmapcrc;
unsigned int nodemask;
+ unsigned int keep_source; /* copy source address to user-buffer in read() operations
+ * Note that rm_prot_id has no effect when keep_source is
+ * set.
+ */
+ unsigned int rtimeout; /* Read timeout if != 0 */
} spw_config;
#define SPACEWIRE_IOCTRL_SET_NODEADDR 1
@@ -107,30 +118,42 @@ typedef struct {
#define SPACEWIRE_IOCTRL_SET_COREFREQ 32
#define SPACEWIRE_IOCTRL_SET_CLKDIVSTART 33
#define SPACEWIRE_IOCTRL_SET_NODEMASK 34
+#define SPACEWIRE_IOCTRL_SET_KEEP_SOURCE 35
+#define SPACEWIRE_IOCTRL_SET_TCODE_CTRL 36
+#define SPACEWIRE_IOCTRL_SET_TCODE 37
+#define SPACEWIRE_IOCTRL_GET_TCODE 38
+#define SPACEWIRE_IOCTRL_SET_READ_TIMEOUT 39
#define SPACEWIRE_IOCTRL_START 64
#define SPACEWIRE_IOCTRL_STOP 65
-int grspw_register(amba_confarea_type *bus);
+/* Defines what register bits that will be touched
+ * for SPACEWIRE_IOCTRL_SET_TCODE_CTRL
+ */
+#define SPACEWIRE_TCODE_CTRL_IE_MSK 0x001
+#define SPACEWIRE_TCODE_CTRL_TT_MSK 0x004
+#define SPACEWIRE_TCODE_CTRL_TR_MSK 0x008
+/* Defines what register bits that should be set
+ * for SPACEWIRE_IOCTRL_SET_TCODE_CTRL
+ */
+#define SPACEWIRE_TCODE_CTRL_IE 0x100
+#define SPACEWIRE_TCODE_CTRL_TT 0x400
+#define SPACEWIRE_TCODE_CTRL_TR 0x800
-#if 0
-struct grspw_buf;
+/* SPACEWIRE_IOCTRL_SET_TCODE argument mask */
+#define SPACEWIRE_TCODE_TCODE 0x0ff
+#define SPACEWIRE_TCODE_SET 0x100 /* Set Timecode register */
+#define SPACEWIRE_TCODE_TX 0x400
-struct grspw_buf {
- grspw_buf *next; /* next packet in chain */
+void grspw_register_drv (void);
- /* Always used */
- unsigned int dlen; /* data length of '*data' */
- unsigned int max_dlen; /* allocated length of '*data' */
- void *data; /* pointer to beginning of cargo data */
+void grspw_print(int options);
+
+/* Global GRSPW Function pointer called upon timecode receive interrupt */
+extern void (*grspw_timecode_callback)
+ (void *pDev, void *regs, int minor, unsigned int tc);
- /* Only used when transmitting */
- unsigned int hlen; /* length of header '*header' */
- unsigned int max_hlen; /* allocated length of '*header' */
- void *header; /* pointer to beginning of header data */
-};
-#endif
#ifdef __cplusplus
}
diff --git a/c/src/lib/libbsp/sparc/shared/include/grspw_pci.h b/c/src/lib/libbsp/sparc/shared/include/grspw_pci.h
deleted file mode 100644
index aea50f3791..0000000000
--- a/c/src/lib/libbsp/sparc/shared/include/grspw_pci.h
+++ /dev/null
@@ -1,49 +0,0 @@
- /*
- * Macros used for GRSPW controller
- *
- * COPYRIGHT (c) 2006.
- * Gaisler Research
- *
- * The license and distribution terms for this file may be
- * found in the file LICENSE in this distribution or at
- * http://www.rtems.com/license/LICENSE.
- *
- */
-
-#ifndef __GRSPW_PCI_H__
-#define __GRSPW_PCI_H__
-
-#include <grspw.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Register GRSPW Driver
- * bus = &amba_conf for LEON3
- *
- * Memory setup:
- * memarea = 128k aligned pointer to memory (if zero malloc will be used) (as the CPU sees it)
- * hw_address = address that HW must use to access memarea. (used in the translation process)
- */
-
-int grspw_pci_register (amba_confarea_type * bus,
- unsigned int memarea, unsigned int hw_address);
-
-
-/* This function must be called on BRM interrupt. Called from the
- * PCI interrupt handler. irq = AMBA IRQ MASK assigned to the BRM device,
- * is found by reading pending register on IRQMP connected to BRM
- * device.
- *
- * Return 0=not handled. nono-zero=handled
- */
-unsigned int grspw_pci_interrupt_handler (int irq, void *arg);
-
-extern void (*grspw_pci_int_reg) (void *handler, int irq, void *arg);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __GRSPW_PCI_H__ */
diff --git a/c/src/lib/libbsp/sparc/shared/include/grspw_pkt.h b/c/src/lib/libbsp/sparc/shared/include/grspw_pkt.h
new file mode 100644
index 0000000000..c52e2a1666
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/grspw_pkt.h
@@ -0,0 +1,599 @@
+/*
+ * GRSPW/GRSPW2 SpaceWire Kernel Library Interface
+ *
+ * COPYRIGHT (c) 2011
+ * Aeroflex Gaisler AB
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ */
+
+#ifndef __GRSPW_PKT_H__
+#define __GRSPW_PKT_H__
+
+struct grspw_pkt;
+
+/* Maximum number of GRSPW devices supported by driver */
+#define GRSPW_MAX 32
+
+/* Weak overridable variable the user can use to define the worker-task
+ * priority (0..255) or to disable (-1) the creation of the worker-task
+ * and the message queue to save space */
+extern int grspw_work_task_priority;
+
+#ifndef GRSPW_PKT_FLAGS
+#define GRSPW_PKT_FLAGS
+/*** TX Packet flags ***/
+
+/* Enable IRQ generation */
+#define TXPKT_FLAG_IE 0x0040
+
+/* Enable Header CRC generation (if CRC is available in HW)
+ * Header CRC will be appended (one byte at end of header)
+ */
+#define TXPKT_FLAG_HCRC 0x0100
+
+/* Enable Data CRC generation (if CRC is available in HW)
+ * Data CRC will be appended (one byte at end of packet)
+ */
+#define TXPKT_FLAG_DCRC 0x0200
+
+/* Control how many bytes the beginning of the Header
+ * the CRC should not be calculated for */
+#define TXPKT_FLAG_NOCRC_MASK 0x0000000f
+#define TXPKT_FLAG_NOCRC_LEN0 0x00000000
+#define TXPKT_FLAG_NOCRC_LEN1 0x00000001
+#define TXPKT_FLAG_NOCRC_LEN2 0x00000002
+#define TXPKT_FLAG_NOCRC_LEN3 0x00000003
+#define TXPKT_FLAG_NOCRC_LEN4 0x00000004
+#define TXPKT_FLAG_NOCRC_LEN5 0x00000005
+#define TXPKT_FLAG_NOCRC_LEN6 0x00000006
+#define TXPKT_FLAG_NOCRC_LEN7 0x00000007
+#define TXPKT_FLAG_NOCRC_LEN8 0x00000008
+#define TXPKT_FLAG_NOCRC_LEN9 0x00000009
+#define TXPKT_FLAG_NOCRC_LENa 0x0000000a
+#define TXPKT_FLAG_NOCRC_LENb 0x0000000b
+#define TXPKT_FLAG_NOCRC_LENc 0x0000000c
+#define TXPKT_FLAG_NOCRC_LENd 0x0000000d
+#define TXPKT_FLAG_NOCRC_LENe 0x0000000e
+#define TXPKT_FLAG_NOCRC_LENf 0x0000000f
+
+/* Marks if packet was transmitted or not */
+#define TXPKT_FLAG_TX 0x8000
+
+#define TXPKT_FLAG_INPUT_MASK (TXPKT_FLAG_NOCRC_MASK | TXPKT_FLAG_IE | \
+ TXPKT_FLAG_HCRC | TXPKT_FLAG_DCRC)
+
+/* Link Error */
+#define TXPKT_FLAG_LINKERR 0x4000
+
+#define TXPKT_FLAG_OUTPUT_MASK (TXPKT_FLAG_LINKERR)
+
+/*** RX Packet Flags ***/
+
+/* Enable IRQ generation */
+#define RXPKT_FLAG_IE 0x0010
+
+#define RXPKT_FLAG_INPUT_MASK (RXPKT_FLAG_IE)
+
+/* Packet was truncated */
+#define RXPKT_FLAG_TRUNK 0x0800
+/* Data CRC error (only valid if RMAP CRC is enabled) */
+#define RXPKT_FLAG_DCRC 0x0400
+/* Header CRC error (only valid if RMAP CRC is enabled) */
+#define RXPKT_FLAG_HCRC 0x0200
+/* Error in End-of-Packet */
+#define RXPKT_FLAG_EEOP 0x0100
+/* Marks if packet was recevied or not */
+#define RXPKT_FLAG_RX 0x8000
+
+#define RXPKT_FLAG_OUTPUT_MASK (RXPKT_FLAG_TRUNK | RXPKT_FLAG_DCRC | \
+ RXPKT_FLAG_HCRC | RXPKT_FLAG_EEOP)
+
+/*** General packet flag options ***/
+
+/* Translate Hdr and/or Payload address */
+#define PKT_FLAG_TR_DATA 0x1000
+#define PKT_FLAG_TR_HDR 0x2000
+/* All General options */
+#define PKT_FLAG_MASK 0x3000
+
+#endif
+/* GRSPW RX/TX Packet structure.
+ *
+ * - For RX the 'hdr' and 'hlen' fields are not used, they are not written
+ * by driver.
+ *
+ * - The 'pkt_id' field is untouched by driver, it is intended for packet
+ * numbering or user-custom data.
+ *
+ * - The last packet in a list must have 'next' set to NULL.
+ *
+ * - data and hdr pointers are written without modification to hardware,
+ * this means that caller must do address translation to hardware
+ * address itself.
+ *
+ * - the 'flags' field are interpreted differently depending on transfer
+ * type (RX/TX). See XXPKT_FLAG_* options above.
+ */
+struct grspw_pkt {
+ struct grspw_pkt *next;
+ unsigned int pkt_id; /* User assigned ID */
+ unsigned short flags; /* RX/TX Options */
+ unsigned char reserved; /* Reserved, must be zero */
+ unsigned char hlen; /* Length of Header Buffer */
+ unsigned int dlen; /* Length of Data Buffer */
+ void *data; /* 4-byte or byte aligned depends on HW */
+ void *hdr; /* 4-byte or byte aligned depends on HW */
+};
+
+/* GRSPW SpaceWire Packet List */
+struct grspw_list {
+ struct grspw_pkt *head;
+ struct grspw_pkt *tail;
+};
+
+/* SpaceWire Link State */
+typedef enum {
+ SPW_LS_ERRRST = 0,
+ SPW_LS_ERRWAIT = 1,
+ SPW_LS_READY = 2,
+ SPW_LS_CONNECTING = 3,
+ SPW_LS_STARTED = 4,
+ SPW_LS_RUN = 5
+} spw_link_state_t;
+
+/* Address Configuration */
+struct grspw_addr_config {
+ /* Ignore address field and put all received packets to first
+ * DMA channel.
+ */
+ int promiscuous;
+
+ /* Default Node Address and Mask */
+ unsigned char def_addr;
+ unsigned char def_mask;
+ /* DMA Channel custom Node Address and Mask */
+ struct {
+ char node_en; /* Enable Separate Addr */
+ unsigned char node_addr; /* Node address */
+ unsigned char node_mask; /* Node address mask */
+ } dma_nacfg[4];
+};
+
+/* Hardware Support in GRSPW Core */
+struct grspw_hw_sup {
+ char rmap; /* If RMAP in HW is available */
+ char rmap_crc; /* If RMAP CRC is available */
+ char rx_unalign; /* RX unaligned (byte boundary) access allowed*/
+ char nports; /* Number of Ports (1 or 2) */
+ char ndma_chans; /* Number of DMA Channels (1..4) */
+ char strip_adr; /* Hardware can strip ADR from packet data */
+ char strip_pid; /* Hardware can strip PID from packet data */
+ int hw_version; /* GRSPW Hardware Version */
+ char reserved[2];
+};
+
+struct grspw_core_stats {
+ int irq_cnt;
+ int err_credit;
+ int err_eeop;
+ int err_addr;
+ int err_parity;
+ int err_escape;
+ int err_wsync; /* only in GRSPW1 */
+};
+
+/* grspw_link_ctrl() options */
+#define LINKOPTS_ENABLE 0x0000
+#define LINKOPTS_DISABLE 0x0001
+#define LINKOPTS_START 0x0002
+#define LINKOPTS_AUTOSTART 0x0004
+#define LINKOPTS_DIS_ONERR 0x0008
+/*#define LINKOPTS_TICK_OUT_IRQ 0x0100*//* Enable Tick-out IRQ */
+#define LINKOPTS_IRQ 0x0200 /* Enable Error Link IRQ */
+#define LINKOPTS_MASK 0x020f /* All above options */
+
+/* grspw_tc_ctrl() options */
+#define TCOPTS_EN_RXIRQ 0x0001 /* Tick-Out IRQ */
+#define TCOPTS_EN_TX 0x0004
+#define TCOPTS_EN_RX 0x0008
+
+/* grspw_rmap_ctrl() options */
+#define RMAPOPTS_EN_RMAP 0x0001
+#define RMAPOPTS_EN_BUF 0x0002
+
+
+/* grspw_dma_config.flags options */
+#define DMAFLAG_NO_SPILL 0x0001 /* See HW doc DMA-CTRL NS bit */
+#define DMAFLAG_RESV1 0x0002 /* HAS NO EFFECT */
+#define DMAFLAG_STRIP_ADR 0x0004 /* See HW doc DMA-CTRL SA bit */
+#define DMAFLAG_STRIP_PID 0x0008 /* See HW doc DMA-CTRL SP bit */
+#define DMAFLAG_RESV2 0x0010 /* HAS NO EFFECT */
+#define DMAFLAG_MASK (DMAFLAG_NO_SPILL|DMAFLAG_STRIP_ADR|DMAFLAG_STRIP_PID)
+
+struct grspw_dma_config {
+ int flags;
+
+ int rxmaxlen; /* RX Max Packet Length */
+ int rx_irq_en_cnt; /* Enable RX IRQ every cnt descriptors */
+ int tx_irq_en_cnt; /* Enable TX IRQ every cnt descriptors */
+};
+
+/* Statistics per DMA channel */
+struct grspw_dma_stats {
+ /* IRQ Statistics */
+ int irq_cnt; /* Number of DMA IRQs generated by channel */
+
+ /* Descriptor Statistics */
+ int tx_pkts; /* Number of Transmitted packets */
+ int tx_err_link; /* Number of Transmitted packets with Link Error*/
+ int rx_pkts; /* Number of Received packets */
+ int rx_err_trunk; /* Number of Received Truncated packets */
+ int rx_err_endpkt; /* Number of Received packets with bad ending */
+
+ /* Diagnostics to help developers sizing their number buffers to avoid
+ * out-of-buffers or other phenomenons.
+ */
+ int send_cnt_min; /* Minimum number of packets in TX SEND Q */
+ int send_cnt_max; /* Maximum number of packets in TX SEND Q */
+ int tx_sched_cnt_min; /* Minimum number of packets in TX SCHED Q */
+ int tx_sched_cnt_max; /* Maximum number of packets in TX SCHED Q */
+ int sent_cnt_max; /* Maximum number of packets in TX SENT Q */
+ int tx_work_cnt; /* Times the work thread processed TX BDs */
+ int tx_work_enabled; /* No. RX BDs enabled by work thread */
+
+ int ready_cnt_min; /* Minimum number of packets in RX READY Q */
+ int ready_cnt_max; /* Maximum number of packets in RX READY Q */
+ int rx_sched_cnt_min; /* Minimum number of packets in RX SCHED Q */
+ int rx_sched_cnt_max; /* Maximum number of packets in RX SCHED Q */
+ int recv_cnt_max; /* Maximum number of packets in RX RECV Q */
+ int rx_work_cnt; /* Times the work thread processed RX BDs */
+ int rx_work_enabled; /* No. RX BDs enabled by work thread */
+};
+
+extern void grspw_initialize_user(
+ /* Callback every time a GRSPW device is found. Args: DeviceIndex */
+ void *(*devfound)(int),
+ /* Callback every time a GRSPW device is removed. Args:
+ * int = DeviceIndex
+ * void* = Return Value from devfound()
+ */
+ void (*devremove)(int,void*)
+ );
+extern int grspw_dev_count(void);
+extern void *grspw_open(int dev_no);
+extern void grspw_close(void *d);
+extern void grspw_hw_support(void *d, struct grspw_hw_sup *hw);
+extern void grspw_stats_read(void *d, struct grspw_core_stats *sts);
+extern void grspw_stats_clr(void *d);
+
+/* Set and Read current node address configuration. The dma_nacfg[N] field
+ * represents the configuration for DMA Channel N.
+ *
+ * Set cfg->promiscous to -1 in order to only read current configuration.
+ */
+extern void grspw_addr_ctrl(void *d, struct grspw_addr_config *cfg);
+
+/*** Link Control interface ***/
+/* Read Link State */
+extern spw_link_state_t grspw_link_state(void *d);
+/* options [in/out]: set to -1 to only read current config
+ *
+ * CLKDIV register contain:
+ * bits 7..0 : Clock Div RUN (only run-state)
+ * bits 15..8 : Clock Div During Startup (all link states except run-state)
+ */
+extern void grspw_link_ctrl(void *d, int *options, int *clkdiv);
+/* Read the current value of the status register */
+extern unsigned int grspw_status(void *d);
+
+/*** Time Code Interface ***/
+/* Generate Tick-In (increment Time Counter, Send Time Code) */
+extern void grspw_tc_tx(void *d);
+/* Control Timcode settings of core */
+extern void grspw_tc_ctrl(void *d, int *options);
+/* Assign ISR Function to TimeCode RX IRQ */
+extern void grspw_tc_isr(void *d, void (*tcisr)(void *data, int tc), void *data);
+/* Read/Write TCTRL and TIMECNT. Write if not -1, always read current value
+ * TCTRL = bits 7 and 6
+ * TIMECNT = bits 5 to 0
+ */
+extern void grspw_tc_time(void *d, int *time);
+
+/*** RMAP Control Interface ***/
+/* Set (not -1) and/or read RMAP options. */
+extern int grspw_rmap_ctrl(void *d, int *options, int *dstkey);
+extern void grspw_rmap_support(void *d, char *rmap, char *rmap_crc);
+
+/*** SpW Port Control Interface ***/
+
+/* Select port, if
+ * -1=The current selected port is returned
+ * 0=Port 0
+ * 1=Port 1
+ * Other positive values=Both Port0 and Port1
+ */
+extern int grspw_port_ctrl(void *d, int *port);
+/* Returns Number ports available in hardware */
+extern int grspw_port_count(void *d);
+/* Returns the current active port */
+extern int grspw_port_active(void *d);
+
+/*** DMA Interface ***/
+extern void *grspw_dma_open(void *d, int chan_no);
+extern void grspw_dma_close(void *c);
+
+extern int grspw_dma_start(void *c);
+extern void grspw_dma_stop(void *c);
+
+/* Schedule List of packets for transmission at some point in
+ * future.
+ *
+ * 1. Move transmitted packets to SENT List (SCHED->SENT)
+ * 2. Add the requested packets to the SEND List (USER->SEND)
+ * 3. Schedule as many packets as possible for transmission (SEND->SCHED)
+ *
+ * Call this function with pkts=NULL to just do step 1 and 3. This may be
+ * required in Polling-mode.
+ *
+ * The above steps 1 and 3 may be skipped by setting 'opts':
+ * bit0 = 1: Skip Step 1.
+ * bit1 = 1: Skip Step 3.
+ * Skipping both step 1 and 3 may be usefull when IRQ is enabled, then
+ * the work queue will be totaly responsible for handling descriptors.
+ *
+ * The fastest solution in retreiving sent TX packets and sending new frames
+ * is to call:
+ * A. grspw_dma_tx_reclaim(opts=0)
+ * B. grspw_dma_tx_send(opts=1)
+ *
+ * NOTE: the TXPKT_FLAG_TX flag must not be set.
+ *
+ * Return Code
+ * -1 Error
+ * 0 Successfully added pkts to send/sched list
+ * 1 DMA stopped. No operation.
+ */
+extern int grspw_dma_tx_send(void *c, int opts, struct grspw_list *pkts, int count);
+
+/* Reclaim TX packet buffers that has previously been scheduled for transmission
+ * with grspw_dma_tx_send().
+ *
+ * 1. Move transmitted packets to SENT List (SCHED->SENT)
+ * 2. Move all SENT List to pkts list (SENT->USER)
+ * 3. Schedule as many packets as possible for transmission (SEND->SCHED)
+ *
+ * The above steps 1 may be skipped by setting 'opts':
+ * bit0 = 1: Skip Step 1.
+ * bit1 = 1: Skip Step 3.
+ *
+ * The fastest solution in retreiving sent TX packets and sending new frames
+ * is to call:
+ * A. grspw_dma_tx_reclaim(opts=2) (Skip step 3)
+ * B. grspw_dma_tx_send(opts=1) (Skip step 1)
+ *
+ * Return Code
+ * -1 Error
+ * 0 Successful. pkts list filled with all packets from sent list
+ * 1 Same as 0, but indicates that DMA stopped
+ */
+extern int grspw_dma_tx_reclaim(void *c, int opts, struct grspw_list *pkts, int *count);
+
+/* Get current number of Packets in respective TX Queue. */
+extern void grspw_dma_tx_count(void *c, int *send, int *sched, int *sent);
+
+#define GRSPW_OP_AND 0
+#define GRSPW_OP_OR 1
+/* Block until ready_cnt or fewer packets are Queued in "Send and Scheduled" Q,
+ * op (AND or OR), sent_cnt or more packet "have been sent" (Sent Q) condition
+ * is met.
+ * If a link error occurs and the Stop on Link error is defined, this function
+ * will also return to caller.
+ * The timeout argument is used to return after timeout ticks, regardless of
+ * the other conditions. If timeout is zero, the function will wait forever
+ * until the condition is satisfied.
+ *
+ * NOTE: if IRQ of TX descriptors are not enabled conditions are never
+ * checked, this may hang infinitely unless a timeout has been specified
+ *
+ * Return Code
+ * -1 Error
+ * 0 Returing to caller because specified conditions are now fullfilled
+ * 1 DMA stopped
+ * 2 Timeout, conditions are not met
+ */
+extern int grspw_dma_tx_wait(void *c, int send_cnt, int op, int sent_cnt, int timeout);
+
+/* Get received RX packet buffers that has previously been scheduled for
+ * reception with grspw_dma_rx_prepare().
+ *
+ * 1. Move Scheduled packets to RECV List (SCHED->RECV)
+ * 2. Move all RECV packet to the callers list (RECV->USER)
+ * 3. Schedule as many free packet buffers as possible (READY->SCHED)
+ *
+ * The above steps 1 may be skipped by setting 'opts':
+ * bit0 = 1: Skip Step 1.
+ * bit1 = 1: Skip Step 3.
+ *
+ * The fastest solution in retreiving received RX packets and preparing new
+ * packet buffers for future receive, is to call:
+ * A. grspw_dma_rx_recv(opts=2, &recvlist) (Skip step 3)
+ * B. grspw_dma_rx_prepare(opts=1, &freelist) (Skip step 1)
+ *
+ * Return Code
+ * -1 Error
+ * 0 Successfully filled pkts list with packets from recv list.
+ * 1 DMA stopped
+ */
+extern int grspw_dma_rx_recv(void *c, int opts, struct grspw_list *pkts, int *count);
+
+/* Add more RX packet buffers for future for reception. The received packets
+ * can later be read out with grspw_dma_rx_recv().
+ *
+ * 1. Move Received packets to RECV List (SCHED->RECV)
+ * 2. Add the "free/ready" packet buffers to the READY List (USER->READY)
+ * 3. Schedule as many packets as possible (READY->SCHED)
+ *
+ * The above steps 1 may be skipped by setting 'opts':
+ * bit0 = 1: Skip Step 1.
+ * bit1 = 1: Skip Step 3.
+ *
+ * The fastest solution in retreiving received RX packets and preparing new
+ * packet buffers for future receive, is to call:
+ * A. grspw_dma_rx_recv(opts=2, &recvlist) (Skip step 3)
+ * B. grspw_dma_rx_prepare(opts=1, &freelist) (Skip step 1)
+ *
+ * Return Code
+ * -1 Error
+ * 0 Successfully added packet buffers from pkt list into the ready queue
+ * 1 DMA stopped
+ */
+extern int grspw_dma_rx_prepare(void *c, int opts, struct grspw_list *pkts, int count);
+
+/* Get current number of Packets in respective RX Queue. */
+extern void grspw_dma_rx_count(void *c, int *ready, int *sched, int *recv);
+
+/* Block until recv_cnt or more packets are Queued in RECV Q, op (AND or OR),
+ * ready_cnt or fewer packet buffers are available in the "READY and Scheduled" Q,
+ * condition is met.
+ * If a link error occurs and the Stop on Link error is defined, this function
+ * will also return to caller, however with an error.
+ * The timeout argument is used to return after timeout ticks, regardless of
+ * the other conditions. If timeout is zero, the function will wait forever
+ * until the condition is satisfied.
+ *
+ * NOTE: if IRQ of TX descriptors are not enabled conditions are never
+ * checked, this may hang infinitely unless a timeout has been specified
+ *
+ * Return Code
+ * -1 Error
+ * 0 Returing to caller because specified conditions are now fullfilled
+ * 1 DMA stopped
+ * 2 Timeout, conditions are not met
+ */
+extern int grspw_dma_rx_wait(void *c, int recv_cnt, int op, int ready_cnt, int timeout);
+
+extern int grspw_dma_config(void *c, struct grspw_dma_config *cfg);
+extern void grspw_dma_config_read(void *c, struct grspw_dma_config *cfg);
+
+extern void grspw_dma_stats_read(void *c, struct grspw_dma_stats *sts);
+extern void grspw_dma_stats_clr(void *c);
+
+/*** GRSPW SpaceWire Packet List Handling Routines ***/
+
+static inline void grspw_list_clr(struct grspw_list *list)
+{
+ list->head = NULL;
+ list->tail = NULL;
+}
+
+static inline int grspw_list_is_empty(struct grspw_list *list)
+{
+ return (list->head == NULL);
+}
+
+/* Return Number of entries in list */
+static inline int grspw_list_cnt(struct grspw_list *list)
+{
+ struct grspw_pkt *lastpkt = NULL, *pkt = list->head;
+ int cnt = 0;
+ while ( pkt ) {
+ cnt++;
+ lastpkt = pkt;
+ pkt = pkt->next;
+ }
+ if ( lastpkt && (list->tail != lastpkt) )
+ return -1;
+ return cnt;
+}
+
+static inline void
+grspw_list_append(struct grspw_list *list, struct grspw_pkt *pkt)
+{
+ pkt->next = NULL;
+ if ( list->tail == NULL ) {
+ list->head = pkt;
+ } else {
+ list->tail->next = pkt;
+ }
+ list->tail = pkt;
+}
+
+static inline void
+grspw_list_prepend(struct grspw_list *list, struct grspw_pkt *pkt)
+{
+ pkt->next = list->head;
+ if ( list->head == NULL ) {
+ list->tail = pkt;
+ }
+ list->head = pkt;
+}
+
+static inline void
+grspw_list_append_list(struct grspw_list *list, struct grspw_list *alist)
+{
+ alist->tail->next = NULL;
+ if ( list->tail == NULL ) {
+ list->head = alist->head;
+ } else {
+ list->tail->next = alist->head;
+ }
+ list->tail = alist->tail;
+}
+
+static inline void
+grspw_list_prepend_list(struct grspw_list *list, struct grspw_list *alist)
+{
+ if ( list->head == NULL ) {
+ list->tail = alist->tail;
+ alist->tail->next = NULL;
+ } else {
+ alist->tail->next = list->head;
+ }
+ list->head = alist->head;
+}
+
+/* Remove dlist (delete-list) from head of list */
+static inline void
+grspw_list_remove_head_list(struct grspw_list *list, struct grspw_list *dlist)
+{
+ list->head = dlist->tail->next;
+ if ( list->head == NULL ) {
+ list->tail = NULL;
+ }
+ dlist->tail->next = NULL;
+}
+
+/* Take A number of entries from head of list 'list' and put the entires
+ * to rlist (result list).
+ */
+static inline int
+grspw_list_take_head_list(struct grspw_list *list, struct grspw_list *rlist, int max)
+{
+ int cnt;
+ struct grspw_pkt *pkt, *last;
+
+ pkt = list->head;
+
+ if ( (max < 1) || (pkt == NULL) ) {
+ grspw_list_clr(rlist);
+ return 0;
+ }
+
+ cnt = 0;
+ rlist->head = pkt;
+ last = pkt;
+ while ((cnt < max) && pkt) {
+ last = pkt;
+ pkt = pkt->next;
+ cnt++;
+ }
+ rlist->tail = last;
+ grspw_list_remove_head_list(list, rlist);
+ return cnt;
+}
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/include/grspw_rasta.h b/c/src/lib/libbsp/sparc/shared/include/grspw_rasta.h
deleted file mode 100644
index 0e4e5bee4d..0000000000
--- a/c/src/lib/libbsp/sparc/shared/include/grspw_rasta.h
+++ /dev/null
@@ -1,49 +0,0 @@
- /*
- * Macros used for RASTA PCI GRSPW controller
- *
- * COPYRIGHT (c) 2006.
- * Gaisler Research
- *
- * The license and distribution terms for this file may be
- * found in the file LICENSE in this distribution or at
- * http://www.rtems.com/license/LICENSE.
- *
- */
-
-#ifndef __GRSPW_RASTA_H__
-#define __GRSPW_RASTA_H__
-
-#include <grspw.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Register GRSPW Driver
- * bus = &amba_conf for LEON3
- *
- * Memory setup:
- * ram_base = 128k aligned pointer to memory (as the CPU sees it)
- */
-
-int grspw_rasta_register(
- amba_confarea_type *bus,
- unsigned int ram_base
- );
-
-/* This function must be called on GRSPW interrupt. Called from the
- * PCI interrupt handler. irq = AMBA IRQ MASK assigned to the GRSPW device,
- * is found by reading pending register on IRQMP connected to GRSPW
- * device.
- *
- */
-void grspw_rasta_interrupt_handler(unsigned int status);
-
-/* callback to register interrupt handler */
-extern void (*grspw_rasta_int_reg)(void *handler, int irq, void *arg);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __GRSPW_RASTA_PCI_H__ */
diff --git a/c/src/lib/libbsp/sparc/shared/include/grspw_router.h b/c/src/lib/libbsp/sparc/shared/include/grspw_router.h
new file mode 100644
index 0000000000..f126f2f267
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/grspw_router.h
@@ -0,0 +1,93 @@
+#ifndef __GRSPW_ROUTER_H__
+#define __GRSPW_ROUTER_H__
+
+/* Hardware Information */
+struct router_hw_info {
+ unsigned char nports_spw;
+ unsigned char nports_amba;
+ unsigned char nports_fifo;
+ char timers_avail;
+ char pnp_avail;
+ unsigned char ver_major;
+ unsigned char ver_minor;
+ unsigned char ver_patch;
+ unsigned char iid;
+};
+
+#define ROUTER_FLG_CFG 0x01
+#define ROUTER_FLG_IID 0x02
+#define ROUTER_FLG_IDIV 0x04
+#define ROUTER_FLG_TPRES 0x08
+#define ROUTER_FLG_TRLD 0x10
+#define ROUTER_FLG_ALL 0x1f /* All Above Flags */
+
+struct router_config {
+ unsigned int flags; /* Determine what configuration should be updated */
+
+ /* Router Configuration Register */
+ unsigned int config;
+
+ /* Set Instance ID */
+ unsigned char iid;
+
+ /* SpaceWire Link Initialization Clock Divisor */
+ unsigned char idiv;
+
+ /* Timer Prescaler and Reload */
+ unsigned int timer_prescaler;
+ unsigned int timer_reload[32];
+};
+
+/* Logical routing table */
+struct router_routes {
+ unsigned int route[224];
+};
+
+/* Port Setup, see register definitions for "Port setup register" */
+struct router_ps {
+ unsigned int ps[31]; /* Port Setup for ports 1-31 */
+ unsigned int ps_logical[224]; /* Port setup for locgical addresses 32-255 */
+};
+
+/* Set/Get Port Control/Status */
+#define ROUTER_PORTFLG_SET_CTRL 0x01
+#define ROUTER_PORTFLG_GET_CTRL 0x02
+#define ROUTER_PORTFLG_SET_STS 0x04
+#define ROUTER_PORTFLG_GET_STS 0x08
+struct router_port {
+ unsigned int flag;
+ int port;
+ unsigned int ctrl;
+ unsigned int sts;
+};
+
+/* Get Hardware support/information available */
+#define GRSPWR_IOCTL_HWINFO 0x01 /* OUT: struct router_hw_info */
+
+/* Router Configuration */
+#define GRSPWR_IOCTL_CFG_SET 0x02 /* IN: struct router_config */
+#define GRSPWR_IOCTL_CFG_GET 0x03 /* OUT: struct router_config */
+
+/* Routes */
+#define GRSPWR_IOCTL_ROUTES_SET 0x04 /* IN: struct router_routes */
+#define GRSPWR_IOCTL_ROUTES_GET 0x05 /* OUT: struct router_routes */
+
+/* Port Setup */
+#define GRSPWR_IOCTL_PS_SET 0x06 /* IN: struct router_ps */
+#define GRSPWR_IOCTL_PS_GET 0x07 /* OUT: struct router_ps */
+
+/* Set configuration write enable */
+#define GRSPWR_IOCTL_WE_SET 0x08 /* INT: int */
+
+/* Set/Get Port Control/Status */
+#define GRSPWR_IOCTL_PORT 0x09 /* IN/OUT: struct router_port */
+
+/* Set Router Configuration/Status Register */
+#define GRSPWR_IOCTL_CFGSTS_SET 0x0a /* IN: unsigned int */
+/* Get Router Configuration/Status Register */
+#define GRSPWR_IOCTL_CFGSTS_GET 0x0b /* OUT: unsigned int */
+
+/* Get Current Time-Code Register */
+#define GRSPWR_IOCTL_TC_GET 0x0c /* OUT: unsigned int */
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/include/grtc.h b/c/src/lib/libbsp/sparc/shared/include/grtc.h
new file mode 100644
index 0000000000..cfd23dd525
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/grtc.h
@@ -0,0 +1,157 @@
+/* GRTC Telecommand (TC) decoder driver interface
+ *
+ * --------------------------------------------------------------------------
+ * -- This file is a part of GAISLER RESEARCH source code.
+ * -- Copyright (C) 2009, Gaisler Research AB - all rights reserved.
+ * --
+ * -- ANY USE OR REDISTRIBUTION IN PART OR IN WHOLE MUST BE HANDLED IN
+ * -- ACCORDANCE WITH THE GAISLER LICENSE AGREEMENT AND MUST BE APPROVED
+ * -- IN ADVANCE IN WRITING.
+ * --
+ * -- BY DEFAULT, DISTRIBUTION OR DISCLOSURE IS NOT PERMITTED.
+ * --------------------------------------------------------------------------
+ *
+ */
+
+#ifndef __GRTC_H__
+#define __GRTC_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GRTC_IOC_UNUSED 0
+
+/* Driver operation controlling commands */
+#define GRTC_IOC_START 1
+#define GRTC_IOC_STOP 2
+#define GRTC_IOC_ISSTARTED 3
+#define GRTC_IOC_SET_BLOCKING_MODE 4 /* Raw mode only */
+#define GRTC_IOC_SET_TIMEOUT 5 /* Raw mode only */
+
+#define GRTC_IOC_ADD_BUFF 16 /* Frame mode only */
+#define GRTC_IOC_RECV 17 /* Frame mode only */
+
+/* Available only in STOPPED mode */
+#define GRTC_IOC_SET_MODE 32 /* Set frame mode (ioctl) or raw mode (read) */
+#define GRTC_IOC_SET_BUF_PARAM 33
+#define GRTC_IOC_SET_CONFIG 34
+#define GRTC_IOC_POOLS_SETUP 35 /* Frame mode only */
+
+/* Available in both running and stopped mode */
+#define GRTC_IOC_GET_CONFIG 64
+#define GRTC_IOC_GET_BUF_PARAM 65
+#define GRTC_IOC_GET_HW_STATUS 66
+#define GRTC_IOC_ASSIGN_FRM_POOL 67
+#define GRTC_IOC_GET_CLCW_ADR 68 /* Get address of CLCWRx1 */
+#define GRTC_IOC_GET_STATS 69 /* Get statistics, note that most of the stats are only avilable in FRAME mode */
+#define GRTC_IOC_CLR_STATS 70 /* Clear statistics */
+
+/* Available only in RUNNING mode */
+
+/* Args to GRTC_IOC_GET_BUF_PARAMS */
+#define GRTC_BUF_MAXLEN (0x100*1024)
+#define GRTC_BUF_MASK 0xfffffc00
+struct grtc_ioc_buf_params {
+ unsigned int length; /* Length of new buffer in multiples of 1kbyte blocks */
+ void *custom_buffer; /* If set zero driver will allocate with malloc, set LSB to 1 to indicate remote address */
+};
+
+/* Args to GRTC_IOC_SET_BLOCKING_MODE */
+enum {
+ GRTC_BLKMODE_POLL = 0, /* Never block (polling mode) */
+ GRTC_BLKMODE_BLK = 1, /* Block until at least 1 byte can be read */
+ GRTC_BLKMODE_COMPLETE = 2 /* Block until all data requested has be read */
+};
+
+/* Argument of GRTC_IOC_SET_CONFIG and GRTC_IOC_GET_CONFIG
+ * Pointer to:
+ */
+struct grtc_ioc_config {
+ int psr_enable;
+ int nrzm_enable;
+ int pss_enable;
+ int crc_calc; /* Enable Software CRC calculation (only Frame mode) */
+};
+
+/* Argument of GRTC_IOC_GET_HW_STATUS:
+ * Pointer to a grtc_ioc_hw_status structure that will be filled
+ * in by driver.
+ */
+struct grtc_ioc_hw_status {
+ unsigned int sir;
+ unsigned int far;
+ unsigned int clcw1;
+ unsigned int clcw2;
+ unsigned int phir;
+ unsigned int str;
+};
+
+struct grtc_hdr {
+ unsigned short flags_scid;
+ unsigned short vc_len;
+ unsigned char seqnum;
+} __attribute__((packed));
+
+/* Frame pool, all frames in pool have the same buffer length (frame mode only) */
+struct grtc_frame {
+ struct grtc_frame *next; /* Next frame in list */
+ unsigned short len; /* Length of frame extracted */
+ unsigned short reserved; /* Reserved */
+ struct grtc_frame_pool *pool; /* The frame pool this frame belongs to */
+
+ /* The Frame content */
+ struct grtc_hdr hdr; /* Primary Header */
+ unsigned char data[3]; /* Frame payload */
+} __attribute__((packed));
+
+/* GRTC_IOC_RECV argument, single linked list of received frames */
+struct grtc_list {
+ struct grtc_frame *head; /* First frame in list */
+ struct grtc_frame *tail; /* Last frame in list */
+ int cnt; /* Number of frames in list */
+};
+
+struct grtc_ioc_pools_setup {
+ unsigned int pool_cnt; /* Number of pools */
+ unsigned int pool_frame_len[1]; /* Array of 'pool_cnt' length: Frame length of frames in a pool
+ * Lengths must be sorted, starting with the smallest frame pool.
+ */
+};
+
+struct grtc_ioc_assign_frm_pool {
+ unsigned int frame_len; /* The length of the pool to insert the frame into */
+ struct grtc_frame *frames; /* Frames to assign to a pool */
+};
+
+enum {
+ GRTC_MODE_RAW = 0,
+ GRTC_MODE_FRAME = 1
+};
+
+/* TC driver stats collected during receiving. The statistics is only available
+ * in FRAME mode. In RAW mode the user interprets the incoming frames and is
+ * therefore responsible for generating the staticstics.
+ */
+struct grtc_ioc_stats {
+ unsigned long long frames_recv; /* Total number of non-erroneous frames received */
+ /* Errors related to incoming data */
+ unsigned int err; /* total number of errors */
+ unsigned int err_hdr; /* number of errors in Header */
+ unsigned int err_payload; /* Number of errors in payload */
+ unsigned int err_ending; /* Number of errors in end (Filler, end marker) */
+ unsigned int err_abandoned; /* Number of abandoned frames, NOT IMPLEMENTED */
+ /* Errors related to the handling of incoming frames */
+ unsigned int dropped; /* Number of dropped frames TC driver */
+ unsigned int dropped_no_buf; /* Number of dropped frame caused by no buffers were available */
+ unsigned int dropped_too_long; /* Number of dropped frames that was larger than any buffer available for driver */
+};
+
+/* Register GRTC driver at driver manager */
+void grtc_register_drv(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GRTC_H__ */
diff --git a/c/src/lib/libbsp/sparc/shared/include/grtm.h b/c/src/lib/libbsp/sparc/shared/include/grtm.h
new file mode 100644
index 0000000000..8eca52819d
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/grtm.h
@@ -0,0 +1,246 @@
+/* GRTM Telemetry (TM) driver interface
+ *
+ * --------------------------------------------------------------------------
+ * -- This file is a part of GAISLER RESEARCH source code.
+ * -- Copyright (C) 2009, Gaisler Research AB - all rights reserved.
+ * --
+ * -- ANY USE OR REDISTRIBUTION IN PART OR IN WHOLE MUST BE HANDLED IN
+ * -- ACCORDANCE WITH THE GAISLER LICENSE AGREEMENT AND MUST BE APPROVED
+ * -- IN ADVANCE IN WRITING.
+ * --
+ * -- BY DEFAULT, DISTRIBUTION OR DISCLOSURE IS NOT PERMITTED.
+ * --------------------------------------------------------------------------
+ *
+ */
+
+#ifndef __GRTM_H__
+#define __GRTM_H__
+
+#include <rtems.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GRTM_IOC_UNUSED 0
+
+/* Driver operation controlling commands */
+#define GRTM_IOC_START 1
+#define GRTM_IOC_STOP 2
+#define GRTM_IOC_ISSTARTED 3
+#define GRTM_IOC_SET_BLOCKING_MODE 4
+#define GRTM_IOC_SET_TIMEOUT 5
+
+/* Available only in STOPPED mode */
+#define GRTM_IOC_SET_CONFIG 32
+
+/* Available in both running and stopped mode */
+#define GRTM_IOC_RECLAIM 64
+#define GRTM_IOC_GET_CONFIG 65
+#define GRTM_IOC_GET_HW_IMPL 66
+#define GRTM_IOC_GET_HW_STATUS 67 /* Not implemented */
+#define GRTM_IOC_GET_OCFREG 68
+#define GRTM_IOC_GET_STATS 69
+#define GRTM_IOC_CLR_STATS 70
+
+/* Available only in RUNNING mode */
+#define GRTM_IOC_SEND 96
+
+/* Args to GRTC_IOC_SET_BLOCKING_MODE */
+enum {
+ GRTM_BLKMODE_POLL = 0, /* Never block (polling mode) */
+ GRTM_BLKMODE_BLK = 1, /* Block until at least 1 byte can be read */
+};
+
+/* Reed Solomon Encoder implemented */
+enum {
+ GRTM_RS_IMPL_NONE = 0,
+ GRTM_RS_IMPL_E16 = 1, /* E16 */
+ GRTM_RS_IMPL_E8 = 2, /* E8 */
+ GRTM_RS_IMPL_BOTH = 3 /* Both E8 and E16 */
+
+};
+
+struct grtm_ioc_hw {
+ char cs; /* Sub Carrier */
+ char sp; /* Split-Phase Level */
+ char ce;
+ char nrz;
+ char psr;
+ char te;
+ unsigned char rsdep;
+ unsigned char rs;
+ char aasm;
+ char fecf;
+ char ocf;
+ char evc;
+ char idle;
+ char fsh;
+ char mcg;
+ char iz;
+ char fhec;
+ char aos;
+ char cif;
+ char ocfb;
+
+ unsigned short blk_size; /* Block Size */
+ unsigned short fifo_size; /* FIFO Size */
+
+};
+
+/* Driver Mode */
+enum {
+ GRTM_MODE_TM = 0, /* TM */
+ GRTM_MODE_AOS = 1 /* AOS */
+};
+
+/* Physical layer Options */
+#define GRTM_IOC_PHY_SCF (1<<15) /* Sub Carrier Fall */
+#define GRTM_IOC_PHY_SF (1<<31) /* Symbol Fall */
+
+/* Coding Sub-layer Options */
+#define GRTM_IOC_CODE_SC (1<<0) /* Enable Sub Carrier modulation */
+#define GRTM_IOC_CODE_SP (1<<1) /* Enable Split-Phase (SP) level modulation */
+#define GRTM_IOC_CODE_CE (1<<5) /* Enable Convolutional Encoding */
+#define GRTM_IOC_CODE_NRZ (1<<6) /* Enable Non-Return-to-Zero mark encoding */
+#define GRTM_IOC_CODE_PSR (1<<7) /* Enable Pseudo-Randomizer */
+#define GRTM_IOC_CODE_RS8 (1<<11) /* Reed-solomon Encoder to use: 0=E16, 1=E8 */
+#define GRTM_IOC_CODE_RS (1<<15) /* Enable Reed-Solomon Encoder */
+#define GRTM_IOC_CODE_AASM (1<<16) /* Enable Alternative attached synchronization marker */
+#define GRTM_IOC_CODE_ALL (GRTM_IOC_CODE_SC|GRTM_IOC_CODE_SP|GRTM_IOC_CODE_CE| \
+ GRTM_IOC_CODE_NRZ|GRTM_IOC_CODE_PSR|GRTM_IOC_CODE_RS8|\
+ GRTM_IOC_CODE_RS|GRTM_IOC_CODE_AASM)
+
+enum {
+ GRTM_CERATE_00 = 0, /* Rate 1/2, no puncturing */
+ GRTM_CERATE_02 = 2, /* Rate 1/2, punctured */
+ GRTM_CERATE_04 = 4, /* Rate 2/3, punctured */
+ GRTM_CERATE_05 = 5, /* Rate 3/4, punctured */
+ GRTM_CERATE_06 = 6, /* Rate 5/6, punctured */
+ GRTM_CERATE_07 = 7, /* Rate 7/8, punctured */
+};
+
+/* Options for Generating all frames */
+#define GRTM_IOC_ALL_FHEC 0x01 /* Enable Frame Header Error Control (Only AOS) */
+#define GRTM_IOC_ALL_FECF 0x02 /* Enable Transfer Frame CRC */
+#define GRTM_IOC_ALL_IZ 0x04 /* Enable Insert Zone */
+#define GRTM_IOC_ALL_ALL (GRTM_IOC_ALL_FHEC|GRTM_IOC_ALL_FECF|GRTM_IOC_ALL_IZ)
+
+/* Master Frame Generation Options */
+#define GRTM_IOC_MF_OW 0x01 /* Over Write OCF bits 16 and 17 */
+#define GRTM_IOC_MF_OCF 0x02 /* Enable Operation Control Field (OCF) for master channel */
+#define GRTM_IOC_MF_FSH 0x04 /* Enable MC_FSH for master channel */
+#define GRTM_IOC_MF_MC 0x08 /* Enable Master channel counter generation */
+#define GRTM_IOC_MF_ALL (GRTM_IOC_MF_OW|GRTM_IOC_MF_OCF|GRTM_IOC_MF_FSH|GRTM_IOC_MF_MC)
+
+/* Idle Frames Generation Options */
+#define GRTM_IOC_IDLE_MC 0x01 /* Enable Master Channel (MC) counter generation (TM Only) */
+#define GRTM_IOC_IDLE_VCC 0x02 /* Enable Virtual Channel counter cycle generation (AOS Only)*/
+#define GRTM_IOC_IDLE_FSH 0x04 /* Enable Frame Secondary Header (FSH) for idle frames (TM Only) */
+#define GRTM_IOC_IDLE_EVC 0x08 /* Enable Extended Virtual Channel Counter Generation */
+#define GRTM_IOC_IDLE_OCF 0x10 /* Enable OCF/CLCW in idle frame */
+#define GRTM_IOC_IDLE_EN 0x20 /* Enable Idle frame generation */
+#define GRTM_IOC_IDLE_ALL (GRTM_IOC_IDLE_MC|GRTM_IOC_IDLE_VCC|GRTM_IOC_IDLE_FSH| \
+ GRTM_IOC_IDLE_EVC|GRTM_IOC_IDLE_OCF|GRTM_IOC_IDLE_EN)
+
+/* Argument of GRTM_IOC_SET_CONFIG and GRTM_IOC_GET_CONFIG.
+ * Driver and Hardware configuration.
+ *
+ * Pointer to:
+ */
+struct grtm_ioc_config {
+
+ /* Mode AOS or TM */
+ unsigned char mode; /* 0=TM, 1=AOS */
+
+ unsigned short frame_length; /* Length of every frame transmitted */
+ unsigned short limit; /* Number of data bytes fetched by DMA before transmission starts */
+ unsigned int as_marker; /* Attached Synchronization Marker */
+
+ /* Physical layer options */
+ unsigned short phy_subrate; /* Sub Carrier rate - sub carrier devision factor - 1 */
+ unsigned short phy_symbolrate; /* Symbol Rate division factor - 1 */
+ unsigned char phy_opts; /* Mask of GRTM_IOC_PHY_XXXX */
+
+ /* Coding sub-layer Options */
+ unsigned char code_rsdep; /* Coding sub-layer Reed-Solomon interleave depth (3-bit) */
+ unsigned char code_ce_rate; /* Convolutional encoding rate, select one of GRTM_CERATE_00 ... GRTM_CERATE_07 */
+ unsigned char code_csel; /* */
+ unsigned int code_opts; /* Mask of GRTM_IOC_CODE_XXXX */
+
+ /* All Frames Generation */
+ unsigned char all_izlen; /* FSH/IZ Length (5-bit) */
+ unsigned char all_opts; /* Mask of GRTM_IOC_ALL_XXXX */
+
+ /* Master Frame Generation */
+ unsigned char mf_opts; /* Mask of GRTM_IOC_MF_XXXX */
+
+ /* Idle frame Generation */
+ unsigned short idle_scid;
+ unsigned char idle_vcid;
+ unsigned char idle_opts; /* Mask of GRTM_IOC_IDLE_XXXX */
+
+ /* Interrupt options */
+ unsigned int enable_cnt; /* Number of frames in between Interrupt is generated, Zero disables interrupt */
+ int isr_desc_proc; /* Enable ISR to process descriptors */
+ int blocking; /* Blocking mode select (POLL,BLK..) */
+ rtems_interval timeout; /* Blocking mode timeout */
+};
+
+struct grtm_frame;
+
+struct grtm_list {
+ struct grtm_frame *head; /* First Frame in list */
+ struct grtm_frame *tail; /* Last Frame in list */
+};
+
+#define GRTM_FLAGS_SENT 0x01
+#define GRRM_FLAGS_ERR 0x02
+
+#define GRTM_FLAGS_TRANSLATE (1<<31) /* Translate frame payload address from CPU address to remote bus (the bus GRTM is resident on) */
+#define GRTM_FLAGS_TRANSLATE_AND_REMEMBER (1<<30) /* As GRTM_FLAGS_TRANSLATE, however if the translated payload address equals the payload address
+ * the GRTM_FLAGS_TRANSLATE_AND_REMEMBER bit is cleared and the GRTM_FLAGS_TRANSLATE bit is set */
+#define GRTM_FLAGS_COPY_DATA (1<<29) /* Where available: Transfer Frame payload to target, may be used for SpaceWire, where the GRTM driver transfer
+ * the payload to a buffer on the SpaceWire target.
+ */
+
+#define GRTM_FLAGS_TS (1<<9)
+#define GRTM_FLAGS_MCB (1<<8)
+#define GRTM_FLAGS_FSHB (1<<7)
+#define GRTM_FLAGS_OCFB (1<<6)
+#define GRTM_FLAGS_FHECB (1<<5)
+#define GRTM_FLAGS_IZB (1<<4)
+#define GRTM_FLAGS_FECFB (1<<3)
+
+#define GRTM_FLAGS_MASK (GRTM_FLAGS_TS|GRTM_FLAGS_MCB|GRTM_FLAGS_FSHB|\
+ GRTM_FLAGS_OCFB|GRTM_FLAGS_FHECB|GRTM_FLAGS_IZB|\
+ GRTM_FLAGS_FECFB)
+
+/* The GRTM software representation of a Frame */
+struct grtm_frame {
+ /* Options and status */
+ unsigned int flags; /* bypass options, and sent/error status */
+
+ struct grtm_frame *next; /* Next packet in chain */
+
+ unsigned int *payload; /* The Headers and Payload, Frame data and header must be word aligned */
+};
+
+#define FRAME_SIZE(payloadlen) (sizeof(struct grtm_frame)+payloadlen)
+
+struct grtm_ioc_stats {
+ unsigned long long frames_sent;
+ unsigned int err_underrun;
+ unsigned int err_tx;
+ unsigned int err_ahb;
+ unsigned int err_transfer_frame;
+};
+
+/* Register GRTM driver at driver manager */
+void grtm_register_drv(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GRTM_H__ */
diff --git a/c/src/lib/libbsp/sparc/shared/include/i2cmst.h b/c/src/lib/libbsp/sparc/shared/include/i2cmst.h
index 21780ee143..36febc4b4a 100644
--- a/c/src/lib/libbsp/sparc/shared/include/i2cmst.h
+++ b/c/src/lib/libbsp/sparc/shared/include/i2cmst.h
@@ -50,26 +50,6 @@ typedef struct gr_i2cmst_regs {
#define GRI2C_STATUS_IDLE 0x00000000
-/* The OC I2C core will perform a write after a start unless the RD bit
- in the command register has been set. Since the rtems framework has
- a send_start function we buffer that command and use it when the first
- data is written. The START is buffered in the sendstart member below */
-typedef struct gr_i2cmst_prv {
- gr_i2cmst_regs_t *reg_ptr;
- unsigned int sysfreq; /* System clock frequency in kHz */
- unsigned char sendstart; /* START events are buffered here */
- /* rtems_irq_number irq_number; */
- /* rtems_id irq_sema_id; */
-} gr_i2cmst_prv_t;
-
-typedef struct gr_i2cmst_desc {
- rtems_libi2c_bus_t bus_desc;
- gr_i2cmst_prv_t prv;
-} gr_i2cmst_desc_t;
-
-/* Scans for I2CMST core and initalizes i2c library */
-rtems_status_code leon_register_i2c(amba_confarea_type *abus);
-
#ifdef __cplusplus
}
#endif
diff --git a/c/src/lib/libbsp/sparc/shared/include/network_interface_add.h b/c/src/lib/libbsp/sparc/shared/include/network_interface_add.h
new file mode 100644
index 0000000000..50deb696d8
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/network_interface_add.h
@@ -0,0 +1,48 @@
+/* Network interface register help function
+ *
+ * COPYRIGHT (c) 2008.
+ * Aeroflex Gaisler AB.
+ *
+ * This function adds a network interface to the
+ * rtems_bsdnet_config.ifconfig linked list of interfaces.
+ * The interface configuration is taken from the user defined
+ * array interface_configs. This function is useful for PnP
+ * systems when an unknown number of interfaces are available.
+ *
+ * The license and distribution terms for this file may be
+ * found in found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ */
+
+#ifndef __NETWORK_INTERFACE_ADD_H__
+#define __NETWORK_INTERFACE_ADD_H__
+
+#include <rtems/rtems_bsdnet.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Interface configuration description */
+struct ethernet_config {
+ char *ip_addr; /* IP address */
+ char *ip_netmask; /* IP Netmask */
+ char eth_adr[6]; /* Ethernet hardware MAC address */
+};
+
+/* Array with configurations for all interfaces in the system
+ * Must be defined by the user.
+ */
+extern struct ethernet_config interface_configs[];
+
+/* Routine adding interface to rtems_bsdnet_config.ifconfig linked
+ * list of interfaces.
+ */
+int network_interface_add(struct rtems_bsdnet_ifconfig *interface);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTEMS_NETWORKCONFIG_H_ */
diff --git a/c/src/lib/libbsp/sparc/shared/include/occan.h b/c/src/lib/libbsp/sparc/shared/include/occan.h
index 12ec42a01c..13d707d761 100644
--- a/c/src/lib/libbsp/sparc/shared/include/occan.h
+++ b/c/src/lib/libbsp/sparc/shared/include/occan.h
@@ -1,7 +1,7 @@
/* Gaisler wrapper to OpenCores CAN, driver interface
*
- * COPYRIGHT (c) 2007.
- * Gaisler Research.
+ * COPYRIGHT (c) 2008.
+ * Aeroflex Gaisler.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
@@ -11,10 +11,8 @@
*/
-#ifndef __OCCAN_H__
-#define __OCCAN_H__
-
-#include <ambapp.h>
+#ifndef __OCCAN_DRIVER_H__
+#define __OCCAN_DRIVER_H__
#ifdef __cplusplus
extern "C" {
@@ -147,7 +145,7 @@ struct occan_afilter {
#define OCCAN_BLK_MODE_RX 0x1
#define OCCAN_BLK_MODE_TX 0x2
-int occan_register(amba_confarea_type *bus);
+void occan_register_drv (void);
#define OCCAN_SPEED_500K 500000
diff --git a/c/src/lib/libbsp/sparc/shared/include/occan_pci.h b/c/src/lib/libbsp/sparc/shared/include/occan_pci.h
deleted file mode 100644
index 2f46293af2..0000000000
--- a/c/src/lib/libbsp/sparc/shared/include/occan_pci.h
+++ /dev/null
@@ -1,42 +0,0 @@
- /*
- * OC_CAN controller via PCI - driver interface
- *
- * COPYRIGHT (c) 2007.
- * Gaisler Research
- *
- * The license and distribution terms for this file may be
- * found in the file LICENSE in this distribution or at
- * http://www.rtems.com/license/LICENSE.
- *
- */
-
-#ifndef __OCCAN_PCI_H__
-#define __OCCAN_PCI_H__
-
-#include <occan.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Register OC_CAN driver
- * bus = pointer to AMBA bus description used to search for OC_CAN contrller(s).
- */
-
-int occan_pci_register(amba_confarea_type *bus);
-
-/* This function must be called on OC_CAN interrupt. Called from the
- * PCI interrupt handler. irq = AMBA IRQ assigned to the OC_CAN device,
- * is found by reading pending register on IRQMP connected to the OC_CAN
- * device.
- *
- */
-void occanpci_interrupt_handler(int irq, void *arg);
-
-extern void (*occan_pci_int_reg)(void *handler, int irq, void *arg);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __OCCAN_PCI_H__ */
diff --git a/c/src/lib/libbsp/sparc/shared/include/rmap.h b/c/src/lib/libbsp/sparc/shared/include/rmap.h
new file mode 100644
index 0000000000..c18dafed5e
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/rmap.h
@@ -0,0 +1,292 @@
+/* RMAP stack and RMAP driver interface
+ *
+ * COPYRIGHT (c) 2009
+ * Aeroflex Gaisler.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ */
+
+#ifndef __RMAP_H__
+#define __RMAP_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*** RMAP Driver interface ***/
+
+#define PKT_OPTION_HDR_CRC 0x1 /* Enable Header CRC by Hardware */
+#define PKT_OPTION_DATA_CRC 0x2 /* Enable Data CRC by Hardware */
+/* skip len of header when calculating CRC by hardware */
+#define PKT_OPTION_HDR_CRC_SKIPLEN(len) (((len) & 0xf) << 8)
+#define PKT_OPTION_HDR_CRC_SKIPLEN_MASK 0xf00
+
+/* RMAP SpW packet */
+struct rmap_spw_pkt {
+ int options; /* Data CRC | Header CRC */
+ int hlen;
+ unsigned char *hdr;
+ int dlen;
+ unsigned char *data;
+ int reserved[2]; /* May be used internally by driver layer */
+};
+
+struct rmap_drv_ops {
+ int (*init)(void *cookie); /* Initialize driver */
+ int (*ioctl)(void *cookie, int command, void *arg); /* Configure driver */
+ int (*send)(void *cookie, struct rmap_spw_pkt *pkt); /* Schedule one packet for transmission */
+ int (*recv)(void *cookie, struct rmap_spw_pkt *pkt); /* Receive one packet */
+};
+
+/* RMAP driver description */
+struct rmap_drv {
+ struct rmap_drv_ops ops;
+ void *cookie;
+};
+
+#define RMAP_TIMEOUT_SET_RTIME 0x01
+#define RMAP_TIMEOUT_SET_WTIME 0x02
+struct rmap_drv_timeout {
+ unsigned int options;
+ unsigned int rtimeout;
+ unsigned int wtimeout;
+};
+
+/* RMAP driver ioctl commands */
+#define RMAP_DRV_IOCTL_START 1 /* Start operation, packets will be sent/received after this command */
+#define RMAP_DRV_IOCTL_STOP 2 /* Stop operation, no more packets will be sent before next START */
+#define RMAP_DRV_IOCTL_BLOCK 3 /* Set RX/TX blocking */
+#define RMAP_DRV_IOCTL_TIMEOUT 4 /* Set timeout in blocing mode */
+#define RMAP_DRV_IOCTL_GET_CAP 5 /* Get capabilities of the driver/hardware */
+#define RMAP_IOCTL_GET_CONFIG 6 /* Get Stack Configuration */
+
+/* Capabilities */
+#define DRV_CAP_HDR_CRC 0x1 /* Hardware supports HEADER CRC generation */
+#define DRV_CAP_DATA_CRC 0x2 /* Hardware supports DATA CRC generation */
+
+
+/*** RMAP Stack interface ***/
+
+/* Function that will generate path addressing.
+ *
+ * \param cookie Identifies RMAP stack,
+ * \param dir Direction (0=to dst, 1=from dst)
+ * \param srcadr Source address (the SpW address of the interface used)
+ * \param dstadr Destination address to translate. Note that it is actually
+ * a "unsigned short" given here, so this is rather a Node-ID.
+ * \param buf Where path address is put
+ * \param len On calling it indicates max length. On return it must be set
+ * reflect the number of bytes was written to buf.
+ */
+typedef int (*rmap_route_t)(void *cookie, int dir, int srcadr, int dstadr, void *buf, int *len);
+
+struct rmap_config {
+ rmap_route_t route_func; /* Function that will generate path addressing */
+ int tid_msb; /* 8 most significant bits in TID.
+ * Set to -1 for normal operation using
+ * all bits in TID for sequence counting.
+ */
+ int spw_adr; /* The SpW Address of the SpW interface used */
+ struct rmap_drv *drv; /* Driver used for transmission */
+ int max_rx_len; /* Maximum data length of received packets */
+ int max_tx_len; /* Maximum data length of transmitted packets */
+ int thread_safe; /* Set this to non-zero to enable the RMAP stack to create a
+ * semaphore used to protect from multiple tasks entering the
+ * transfer function(s) of the stack at the same time */
+};
+
+struct rmap_command {
+ char type; /* READ/WRITE/MODIFY ... */
+ unsigned char dstkey; /* Destination key */
+ unsigned char status; /* Error/Status response. 0 if no response is expected */
+ unsigned short dstadr; /* Destination address */
+ unsigned short tid; /* TID assigned to packet */
+ unsigned long long address; /* READ/WRITE address, 32-bit + 8-bit extended */
+ union {
+ struct {
+ unsigned int length; /* 24-bit data length */
+ unsigned char *data; /* Data bytes, NOTE that 1 byte must be available
+ * for the stack to write the DATA CRC in the end
+ * of the data buffer. Stack write data[length] = CRC
+ */
+ } write;
+ struct {
+ unsigned int length; /* 24-bit length */
+ unsigned int datalength;/* Response 24-bit length, may be different from requested length */
+ unsigned int *data; /* Response data is stored in this buffer */
+ } read;
+ struct {
+ unsigned int length; /* length 1,2 or 4 valid */
+ unsigned int data; /* 1,2 or 4 bytes data */
+ unsigned int mask; /* 1,2 or 4 bytes data mask */
+ unsigned int oldlength; /* Response, old data length */
+ unsigned int olddata; /* Response, old data before write */
+ } read_m_write;
+ } data;
+};
+
+struct rmap_command_write {
+ char type; /* WRITE (Increment, Single, ACK, Verify) */
+ unsigned char dstkey; /* Destination key */
+ unsigned char status; /* Status response, set if ACK, non-zero indicates error */
+ unsigned short dstadr; /* Destination address */
+ unsigned short tid; /* TID assigned to packet */
+ unsigned long long address; /* READ/WRITE address */
+ unsigned int length; /* 24-bit data length */
+ unsigned char *data; /* Data bytes, NOTE that 1 byte must be available
+ * for the stack to write the DATA CRC in the end
+ * of the data buffer. Stack write data[length] = CRC
+ */
+};
+
+struct rmap_command_read {
+ char type; /* READ (Single, Increment) */
+ unsigned char dstkey; /* Destination key */
+ unsigned char status; /* Status response, always set, non-zero indicates error */
+ unsigned short dstadr; /* Destination address */
+ unsigned short tid; /* TID assigned to packet */
+ unsigned long long address; /* READ/WRITE address */
+ unsigned int length; /* 24-bit data length */
+ unsigned int datalength; /* Response 24-bit length, may be different from requested length */
+ unsigned int *data; /* Response data is stored in this buffer */
+};
+
+struct rmap_command_rmw {
+ char type; /* RMAP_CMD_RMWI */
+ unsigned char dstkey; /* Destination key */
+ unsigned char status; /* Status response, always set, non-zero indicates error */
+ unsigned short dstadr; /* Destination address */
+ unsigned short tid; /* TID assigned to packet */
+ unsigned long long address; /* READ/WRITE address */
+ unsigned int length; /* length 1,2 or 4 valid */
+ unsigned int data; /* 1,2 or 4 bytes data */
+ unsigned int mask; /* 1,2 or 4 bytes data mask */
+ unsigned int oldlength; /* Response, old data length */
+ unsigned int olddata; /* Response, old data before write */
+};
+
+/* Command definition.
+ *
+ * R = READ
+ * W = WRITE
+ * M = MODIFY
+ * S = SINGLE
+ * I = INCREMENTING ADDRESSES
+ * V = VERIFY
+ * A = ACKNOWLEDGE
+ */
+enum {
+ RMAP_CMD_UNUSED1 = 0x0, /* Not used */
+ RMAP_CMD_UNUSED2 = 0x1, /* Not used */
+ RMAP_CMD_RS = 0x2, /* Read single address */
+ RMAP_CMD_RI = 0x3, /* Read incrementing addresses */
+ RMAP_CMD_UNUSED3 = 0x4, /* Not used */
+ RMAP_CMD_UNUSED4 = 0x5, /* Not used */
+ RMAP_CMD_UNUSED5 = 0x6, /* Not used */
+ RMAP_CMD_RMWI = 0x7, /* Read-Modify-Write incrementing addresses */
+ RMAP_CMD_WS = 0x8, /* Write, single address, don't verify before writing, no acknowledge */
+ RMAP_CMD_WI = 0x9, /* Write, incrementing addresses, don't verify before writing, no acknowledge */
+ RMAP_CMD_WSA = 0xa, /* Write, single address, don't verify before writing, send acknowledge */
+ RMAP_CMD_WIA = 0xb, /* Write, incrementing addresses, don't verify before writing, send acknowledge */
+ RMAP_CMD_WSV = 0xc, /* Write, single address, verify before writing, no acknowledge */
+ RMAP_CMD_WIV = 0xd, /* Write, incrementing addresses, verify before writing, no acknowledge */
+ RMAP_CMD_WSVA = 0xe, /* Write, single address, verify before writing, send acknowledge */
+ RMAP_CMD_WIVA = 0xf, /* Write, incrementing addresses, verify before writing, send acknowledge */
+};
+
+#define RMAP_CMD_INCREMENT 0x1
+#define RMAP_CMD_ACKNOWLEDGE 0x2
+#define RMAP_CMD_VERIFY 0x4
+#define RMAP_CMD_WRITE 0x8
+
+/* Initialize the stack
+ *
+ * \param route_func Function that will generate path addressing
+ * \param drv Set driver used for transmission
+ */
+void *rmap_init(struct rmap_config *config);
+
+/* Enables the RMAP stack to send/receive commands */
+
+/* Disables the RMAP stack to send/receive commands */
+
+/* Configure stack (blocking etc)*/
+extern int rmap_ioctl(void *cookie, int command, void *arg);
+
+/* Send a command and optionally block waiting for response.
+ *
+ * The transaction ID is incremented
+ *
+ * \param cmd RMAP command to transmit
+ * \param resp Response (stack blocking mode only)
+ * \param tid Pointer to where the Transaction ID is stored (stack non-blocking mode only)
+ */
+extern int rmap_send(void *cookie, struct rmap_command *cmd);
+
+#if NOT_IMPLEMENTED
+/** OPTIONAL PART 1 **/
+
+/* Wait for response on a previously sent RMAP command, the command was sent
+ * using rmap_send and was assigned a transaction ID (tid). The TID is used'
+ * to separate different RMAP commands from each other.
+ *
+ * This is a blocking call.
+ *
+ * Only available when,
+ * - stack in non-blocking mode
+ * - driver in blocking mode.
+ *
+ * \param timeout Timeout in ticks. Currently NOT used.
+ * \param resp Response on the Transaction ID
+ * \param tid Transaction ID
+ */
+extern int rmap_resp_wait(void *cookie, int timeout, struct rmap_command *resp, unsigned int tid);
+
+/** OPTIONAL PART 2 **/
+
+/* Check for response on a previously sent RMAP command, the command was sent
+ * using rmap_send and was assigned a transaction ID (tid). The TID is used'
+ * to separate different RMAP commands from each other.
+ *
+ * This function will never block.
+ *
+ * Only available when,
+ * - stack in non-blocking mode
+ * - driver in non-blocking mode.
+ *
+ * \param resp Response on the Transaction ID
+ * \param tid Transaction ID
+ */
+extern int rmap_resp_poll(void *cookie, struct rmap_command *resp, unsigned int tid);
+#endif
+
+/* rmap_ioctl commands */
+#define RMAP_IOCTL_START 0 /* Start RMAP stack, enables stack to send/receive packets */
+#define RMAP_IOCTL_STOP 1 /* Stop RMAP stack, no packets will be sent/received */
+#define RMAP_IOCTL_BLOCK 2 /* Set blocking mode */
+#define RMAP_IOCTL_TIMEOUT 3 /* Set timeout for command responses in number of ticks */
+
+#define RMAP_IOCTRL_BLOCK_ALL 0
+
+
+/*** RMAP Stack help interface ***/
+
+/* Parse a Write command */
+
+/* Return the CRC of a RMAP data buffer of length len */
+extern unsigned char rmap_crc_calc(unsigned char *data, unsigned int len);
+
+/* A handy write function using the RMAP stack */
+extern int rmap_write(void *cookie, void *dst, void *buf, int length, int dstadr, int dstkey);
+
+/* A handy read function using the RMAP stack */
+extern int rmap_read(void *cookie, void *src, void *buf, int length, int dstadr, int dstkey);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/include/rmap_drv_grspw.h b/c/src/lib/libbsp/sparc/shared/include/rmap_drv_grspw.h
new file mode 100644
index 0000000000..1ba71db2b0
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/rmap_drv_grspw.h
@@ -0,0 +1,31 @@
+/* GRSPW RMAP driver, used by RMAP stack to talk to the GRSPW driver.
+ *
+ * COPYRIGHT (c) 2009
+ * Aeroflex Gaisler.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ */
+
+#ifndef __RMAP_DRV_GRSPW_H__
+#define __RMAP_DRV_GRSPW_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern struct rmap_drv_ops rmap_grspw_ops;
+
+struct rmap_drv_grspw_config {
+ int fd;
+};
+
+void *rmap_drv_grspw_init(struct rmap_drv_grspw_config *config);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/include/satcan.h b/c/src/lib/libbsp/sparc/shared/include/satcan.h
new file mode 100644
index 0000000000..048890d4b9
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/satcan.h
@@ -0,0 +1,147 @@
+/*
+ * Header file for RTEMS SATCAN FPGA driver
+ *
+ * --------------------------------------------------------------------------
+ * -- This file is a part of GAISLER RESEARCH source code.
+ * -- Copyright (C) 2008, Gaisler Research AB - all rights reserved.
+ * --
+ * -- ANY USE OR REDISTRIBUTION IN PART OR IN WHOLE MUST BE HANDLED IN
+ * -- ACCORDANCE WITH THE GAISLER LICENSE AGREEMENT AND MUST BE APPROVED
+ * -- IN ADVANCE IN WRITING.
+ * --
+ * -- BY DEFAULT, DISTRIBUTION OR DISCLOSURE IS NOT PERMITTED.
+ * --------------------------------------------------------------------------
+ *
+ */
+
+#ifndef __SATCAN_H__
+#define __SATCAN_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Config structure passed to SatCAN_init(..) */
+typedef struct {
+ /* Configuration */
+ int nodeno;
+ int dps;
+ /* Callback functions */
+ void (*ahb_irq_callback)(void);
+ void (*pps_irq_callback)(void);
+ void (*m5_irq_callback)(void);
+ void (*m4_irq_callback)(void);
+ void (*m3_irq_callback)(void);
+ void (*m2_irq_callback)(void);
+ void (*m1_irq_callback)(void);
+ void (*sync_irq_callback)(void);
+ void (*can_irq_callback)(unsigned int fifo);
+} satcan_config;
+
+#define SATCAN_HEADER_SIZE 4
+#define SATCAN_HEADER_NMM_POS 3
+#define SATCAN_PAYLOAD_SIZE 8
+
+/* SatCAN message */
+typedef struct {
+ unsigned char header[SATCAN_HEADER_SIZE]; /* Header of SatCAN message */
+ unsigned char payload[SATCAN_PAYLOAD_SIZE]; /* Payload of SatCAN message */
+} satcan_msg;
+
+/* SatCAN modify register structure */
+typedef struct {
+ unsigned int reg;
+ unsigned int val;
+} satcan_regmod;
+
+/* Driver interface */
+int satcan_register(satcan_config *conf);
+
+/* SatCAN interrupt IDs */
+#define SATCAN_IRQ_NONACT_TO_ACT 0
+#define SATCAN_IRQ_ACTIVE_TO_NONACT 1
+#define SATCAN_IRQ_STR1_TO_DPS 2
+#define SATCAN_IRQ_DPS_TO_STR1 3
+#define SATCAN_IRQ_STR2_TO_DPS 4
+#define SATCAN_IRQ_DPS_TO_STR2 5
+#define SATCAN_IRQ_STR3_TO_DPS 6
+#define SATCAN_IRQ_DPS_TO_STR3 7
+#define SATCAN_IRQ_PLD1_TO_DPS 8
+#define SATCAN_IRQ_DPS_TO_PLD1 9
+#define SATCAN_IRQ_PLD2_TO_DPS 10
+#define SATCAN_IRQ_DPS_TO_PLD2 11
+#define SATCAN_IRQ_SYNC 16
+#define SATCAN_IRQ_TIME_MARKER1 17
+#define SATCAN_IRQ_TIME_MARKER2 18
+#define SATCAN_IRQ_TIME_MARKER3 19
+#define SATCAN_IRQ_TIME_MARKER4 20
+#define SATCAN_IRQ_TIME_MARKER5 21
+#define SATCAN_IRQ_EOD1 22
+#define SATCAN_IRQ_EOD2 23
+#define SATCAN_IRQ_TOD 24
+#define SATCAN_IRQ_CRITICAL 25
+
+/* IOC */
+#define SATCAN_IOC_DMA_2K 1 /* Use DMA area for 2K messages */
+#define SATCAN_IOC_DMA_8K 2 /* Use DMA area for 8K messages */
+#define SATCAN_IOC_GET_REG 3 /* Provides direct read access to all core registers */
+#define SATCAN_IOC_SET_REG 4 /* Provides direct write access to all core registers */
+#define SATCAN_IOC_OR_REG 5 /* Provides direct read access to all core registers */
+#define SATCAN_IOC_AND_REG 6 /* Provides direct write access to all core registers */
+#define SATCAN_IOC_EN_TX1_DIS_TX2 7 /* Enable DMA TX channel 1, Disable DMA TX channel 2 */
+#define SATCAN_IOC_EN_TX2_DIS_TX1 8 /* Enable DMA TX channel 2, Disable DMA TX channel 1 */
+#define SATCAN_IOC_GET_DMA_MODE 9 /* Returns the current DMA mode */
+#define SATCAN_IOC_SET_DMA_MODE 10 /* Sets the DMA mode */
+#define SATCAN_IOC_ACTIVATE_DMA 11 /* Directly activate DMA channel */
+#define SATCAN_IOC_DEACTIVATE_DMA 12 /* Directly deactivate DMA channel */
+#define SATCAN_IOC_DMA_STATUS 13 /* Returns status of directly activated DMA */
+#define SATCAN_IOC_GET_DOFFSET 14 /* Get TX DMA offset */
+#define SATCAN_IOC_SET_DOFFSET 15 /* Set TX DMA offset */
+#define SATCAN_IOC_GET_TIMEOUT 16 /* Set TX DMA timeout */
+#define SATCAN_IOC_SET_TIMEOUT 17 /* Get TX DMA timeout */
+
+
+/* Values used to select core register with IOC_SET_REG/IOC_GET_REG */
+#define SATCAN_SWRES 0 /* Software reset */
+#define SATCAN_INT_EN 1 /* Interrupt enable */
+#define SATCAN_FIFO 3 /* FIFO read */
+#define SATCAN_FIFO_RES 4 /* FIFO reset */
+#define SATCAN_TSTAMP 5 /* Current time stamp */
+#define SATCAN_CMD0 6 /* Command register 0 */
+#define SATCAN_CMD1 7 /* Command register 1 */
+#define SATCAN_START_CTC 8 /* Start cycle time counter */
+#define SATCAN_RAM_BASE 9 /* RAM offset address */
+#define SATCAN_STOP_CTC 10 /* Stop cycle time counter / DPS active status */
+#define SATCAN_DPS_ACT 10 /* Stop cycle time counter / DPS active status */
+#define SATCAN_PLL_RST 11 /* DPLL reset */
+#define SATCAN_PLL_CMD 12 /* DPLL command */
+#define SATCAN_PLL_STAT 13 /* DPLL status */
+#define SATCAN_PLL_OFF 14 /* DPLL offset */
+#define SATCAN_DMA 15 /* DMA channel enable */
+#define SATCAN_DMA_TX_1_CUR 16 /* DMA channel 1 TX current address */
+#define SATCAN_DMA_TX_1_END 17 /* DMA channel 1 TX end address */
+#define SATCAN_DMA_TX_2_CUR 18 /* DMA channel 2 TX current address */
+#define SATCAN_DMA_TX_2_END 19 /* DMA channel 2 TX end address */
+#define SATCAN_RX 20 /* CAN RX enable / Filter start ID */
+#define SATCAN_FILTER_START 20 /* CAN RX enable / Filter start ID */
+#define SATCAN_FILTER_SETUP 21 /* Filter setup / Filter stop ID */
+#define SATCAN_FILTER_STOP 21 /* Filter setup / Filter stop ID */
+#define SATCAN_WCTRL 32 /* Wrapper status/control register */
+#define SATCAN_WIPEND 33 /* Wrapper interrupt pending register */
+#define SATCAN_WIMASK 34 /* Wrapper interrupt mask register */
+#define SATCAN_WAHBADDR 35 /* Wrapper AHB address register */
+
+
+/* Values used to communicate DMA mode */
+#define SATCAN_DMA_MODE_USER 0
+#define SATCAN_DMA_MODE_SYSTEM 1
+
+/* Values used to directly activate DMA channel */
+#define SATCAN_DMA_ENABLE_TX1 1
+#define SATCAN_DMA_ENABLE_TX2 2
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __SATCAN_H__ */
diff --git a/c/src/lib/libbsp/sparc/shared/include/spictrl.h b/c/src/lib/libbsp/sparc/shared/include/spictrl.h
new file mode 100644
index 0000000000..d298f5be68
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/spictrl.h
@@ -0,0 +1,127 @@
+/*
+ * SPICTRL SPI Driver interface.
+ *
+ * COPYRIGHT (c) 2009.
+ * Gaisler Research
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ */
+
+#ifndef __SPICTRL_H__
+#define __SPICTRL_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void spictrl_register_drv (void);
+
+/*** REGISTER LAYOUT ***/
+struct spictrl_regs {
+ volatile unsigned int capability; /* 0x00 */
+ volatile unsigned int resv[7]; /* 0x04 */
+ volatile unsigned int mode; /* 0x20 */
+ volatile unsigned int event; /* 0x24 */
+ volatile unsigned int mask; /* 0x28 */
+ volatile unsigned int command; /* 0x2c */
+ volatile unsigned int tx; /* 0x30 */
+ volatile unsigned int rx; /* 0x34 */
+ volatile unsigned int slvsel; /* 0x38 */
+ volatile unsigned int am_slvsel; /* 0x3c */
+ volatile unsigned int am_cfg; /* 0x40 */
+ volatile unsigned int am_period; /* 0x44 */
+ int reserved0[2];
+ volatile unsigned int am_mask[4]; /* 0x50-0x5C */
+ int reserved1[(0x200-0x60)/4];
+ volatile unsigned int am_tx[128]; /* 0x200-0x3FC */
+ volatile unsigned int am_rx[128]; /* 0x400-0x5FC */
+};
+
+/* -- About automated periodic transfer mode --
+ *
+ * Core must support this feature.
+ *
+ * The SPI core must be configured in periodic mode before
+ * writing the data into the transfer FIFO which will be used
+ * mutiple times in different transfers, it will also make
+ * the receive FIFO to be updated.
+ *
+ * In periodic mode the following sequence is performed,
+ * 1. start()
+ * 2. ioctl(CONFIG, &config) - Enable periodic mode
+ * 3. set_address()
+ * 4. write() - Fills TX FIFO, this has some constraints
+ * 5. ioctl(START) - Starts the periodic transmission of the TX FIFO
+ * 6. read() - Read one response of the tranistted data. It will
+ * hang until data is available. If hanging is not an
+ * options use ioctl(STATUS)
+ * 7. go back to 6.
+ *
+ * 8. ioctl(STOP) - Stop to set up a new periodic or normal transfer
+ * 9. stop()
+ *
+ * Note that the the read length must equal the total write length.
+ */
+
+/* Custom SPICTRL driver ioctl commands */
+#define SPICTRL_IOCTL_PERIOD_START 5000 /* Start automated periodic transfer mode */
+#define SPICTRL_IOCTL_PERIOD_STOP 5001 /* Stop to SPI core from doing periodic transfers */
+#define SPICTRL_IOCTL_CONFIG 5002 /* Configure Periodic transfer mode (before calling write() and START) */
+#define SPICTRL_IOCTL_STATUS 5003 /* Get status */
+
+#define SPICTRL_IOCTL_PERIOD_READ 5005 /* Write transmit registers and mask register
+ * (only in automatic periodic mode)
+ * Note that it is probably prefferred to read
+ * the received words using the read() using
+ * operations instead.
+ */
+#define SPICTRL_IOCTL_PERIOD_WRITE 5006 /* Read receive registers and mask register
+ * (only in automatic periodic mode) */
+#define SPICTRL_IOCTL_REGS 5007 /* Get SPICTRL Register */
+
+/* SPICTRL_IOCTL_CONFIG argument */
+struct spictrl_ioctl_config {
+ int clock_gap; /* Clock GAP between */
+ unsigned int flags; /* Normal mode flags */
+ int periodic_mode; /* 1=Enables Automated periodic transfers if supported by hardware */
+ unsigned int period; /* Number of clocks between automated transfers are started */
+ unsigned int period_flags; /* Options */
+ unsigned int period_slvsel; /* Slave Select when transfer is not active, default is 0xffffffff */
+};
+#define SPICTRL_FLAGS_TAC 0x10
+
+#define SPICTRL_PERIOD_FLAGS_ERPT 0x80 /* Trigger start-period from external signal */
+#define SPICTRL_PERIOD_FLAGS_SEQ 0x40
+#define SPICTRL_PERIOD_FLAGS_STRICT 0x20
+#define SPICTRL_PERIOD_FLAGS_OVTB 0x10
+#define SPICTRL_PERIOD_FLAGS_OVDB 0x08
+#define SPICTRL_PERIOD_FLAGS_ASEL 0x04
+#define SPICTRL_PERIOD_FLAGS_EACT 0x01
+
+/* SPICTRL_IOCTL_PERIOD_READ and SPICTRL_IOCTL_PERIOD_WRITE Argument data structure
+ *
+ * Note that the order of reading the mask registers are different for read/write
+ * operation. See options notes.
+ */
+struct spictrl_period_io {
+ int options; /* READ: bit0=Read Mask Registers into masks[].
+ * bit1=Read Receive registers according to masks[]
+ * (after reading masks).
+ *
+ * WRITE: bit0=Update Mask accoring to masks[].
+ * bit1=Update Transmit registers according to masks[].
+ * (before reading masks)
+ */
+ unsigned int masks[4];
+
+ void *data; /* Data read sequentially according to masks[] bit. */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/include/spwcuc.h b/c/src/lib/libbsp/sparc/shared/include/spwcuc.h
new file mode 100644
index 0000000000..5b50b43125
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/spwcuc.h
@@ -0,0 +1,189 @@
+/* SPWCUC - SpaceWire - CCSDS unsegmented Code Transfer Protocol GRLIB core
+ * register driver interface.
+ *
+ * COPYRIGHT (c) 2009.
+ * Aeroflex Gaisler AB
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ */
+
+#ifndef __SPWCUC_H__
+#define __SPWCUC_H__
+
+#define PKT_INIT_IRQ 0x1
+#define PKT_ERR_IRQ 0x2
+#define PKT_RX_IRQ 0x4
+#define WRAP_ERR_IRQ 0x8
+#define WRAP_IRQ 0x10
+#define SYNC_ERR_IRQ 0x20
+#define SYNC_IRQ 0x40
+#define TOL_ERR_IRQ 0x80
+#define TICK_RX_ERR_IRQ 0x100
+#define TICK_RX_WRAP_IRQ 0x200
+#define TICK_RX_IRQ 0x400
+#define TICK_TX_WRAP_IRQ 0x800
+#define TICK_TX_IRQ 0x1000
+
+/* SPWCUC Register layout */
+struct spwcuc_regs {
+ volatile unsigned int config; /* 00 */
+ volatile unsigned int status; /* 04 */
+ volatile unsigned int control; /* 08 */
+ volatile unsigned int unused0; /* 0c */
+ volatile unsigned int dla; /* 10 */
+ volatile unsigned int pid; /* 14 */
+ volatile unsigned int offset; /* 18 */
+ volatile unsigned int unused1; /* 1c */
+ volatile unsigned int pkt_ct; /* 20 */
+ volatile unsigned int pkt_ft; /* 24 */
+ volatile unsigned int pkt_pf_crc; /* 28 */
+ volatile unsigned int unused2; /* 2c */
+ volatile unsigned int etct; /* 30 */
+ volatile unsigned int etft; /* 34 */
+ volatile unsigned int etct_next; /* 38 */
+ volatile unsigned int etft_next; /* 3c */
+ volatile unsigned int unused3[8]; /* 40-5c */
+ volatile unsigned int pimsr; /* 60 */
+ volatile unsigned int pimr; /* 64 */
+ volatile unsigned int pisr; /* 68 */
+ volatile unsigned int pir; /* 6c */
+ volatile unsigned int imr; /* 70 */
+ volatile unsigned int picr; /* 74 */
+};
+
+struct spwcuc_cfg {
+ unsigned char sel_out; /* Bits 3-0 enable time code transmission on respective output */
+ unsigned char sel_in; /* Select SpW to receive time codes on, 0-3 */
+ unsigned char mapping; /* Define mapping of time code time info into T-field, 0-31 */
+ unsigned char tolerance; /* Define SpaceWire time code reception tolerance, 0-31 */
+ unsigned char tid; /* Define CUC P-Field time code identification, 1 = Level 1, 2 = Level 2 */
+ unsigned char ctf; /* If 1 check time code flags to be all zero */
+ unsigned char cp; /* If 1 check P-Field time code id against tid */
+
+ unsigned char txen; /* Enable SpaceWire time code transmission */
+ unsigned char rxen; /* Enable SpaceWire time code reception */
+ unsigned char pktsyncen; /* Enable SpaceWire time CUC packet sync */
+ unsigned char pktiniten; /* Enable SpaceWire time CUC packet init */
+ unsigned char pktrxen; /* Enable SpaceWire time CUC packet reception */
+
+ unsigned char dla; /* SpaceWire destination logical address */
+ unsigned char dla_mask; /* SpaceWire destination logical address mask */
+ unsigned char pid; /* SpaceWire protocol ID */
+
+ unsigned int offset; /* Packet reception offset */
+};
+
+/* SPWCUC Statistics gathered by driver */
+struct spwcuc_stats {
+
+ /* IRQ Stats */
+ unsigned int nirqs;
+ unsigned int tick_tx;
+ unsigned int tick_tx_wrap;
+ unsigned int tick_rx;
+ unsigned int tick_rx_wrap;
+ unsigned int tick_rx_error;
+ unsigned int tolerr;
+ unsigned int sync;
+ unsigned int syncerr;
+ unsigned int wrap;
+ unsigned int wraperr;
+ unsigned int pkt_rx;
+ unsigned int pkt_err;
+ unsigned int pkt_init;
+};
+
+/* Function ISR callback prototype
+ *
+ * pimr - PIMR/PIR register of the SPWCUC core read by ISR
+ * data - Custom data provided by user
+ */
+typedef void (*spwcuc_isr_t)(unsigned int pimr, void *data);
+
+/* Open a SPWCUC device by minor number. A SPWCUC device can only by opened
+ * once. The handle returned must be used as the input parameter 'spwcuc' in
+ * the rest of the calls in the function interface.
+ */
+extern void *spwcuc_open(int minor);
+
+/* Close a previously opened SPWCUC device */
+extern void spwcuc_close(void *spwcuc);
+
+/* Reset SPWCUC Core */
+extern int spwcuc_reset(void *spwcuc);
+
+/* Enable Interrupts at Interrupt controller */
+extern void spwcuc_int_enable(void *spwcuc);
+
+/* Disable Interrupts at Interrupt controller */
+extern void spwcuc_int_disable(void *spwcuc);
+
+/* Clear Statistics gathered by the driver */
+extern void spwcuc_clr_stats(void *spwcuc);
+
+/* Get Statistics gathered by the driver. The statistics are stored into
+ * the location pointed to by 'stats'.
+ */
+extern void spwcuc_get_stats(void *spwcuc, struct spwcuc_stats *stats);
+
+/* Register an Interrupt handler and custom data, the function call is
+ * removed by setting func to NULL.
+ *
+ * The driver's interrupt handler is installed on open(), however the user
+ * callback called from the driver's ISR is installed using this function.
+ */
+extern void spwcuc_int_register(void *spwcuc, spwcuc_isr_t func, void *data);
+
+/* Configure the spwcuc core. The configuration is taken from the data
+ * structure pointed to by 'cfg'. See data structure spwcuc_cfg fields.
+ */
+extern void spwcuc_config(void *spwcuc, struct spwcuc_cfg *cfg);
+
+/* Return elapsed coarse time */
+extern unsigned int spwcuc_get_et_coarse(void *spwcuc);
+
+/* Return elapsed fine time */
+extern unsigned int spwcuc_get_et_fine(void *spwcuc);
+
+/* Return elapsed time (coarse and fine) 64-bit value */
+extern unsigned long long spwcuc_get_et(void *spwcuc);
+
+/* Return next elapsed coarse time (for use when sending SpW time packet) */
+extern unsigned int spwcuc_get_next_et_coarse(void *spwcuc);
+
+/* Return next elapsed fine time (for use when sending SpW time packet) */
+extern unsigned int spwcuc_get_next_et_fine(void *spwcuc);
+
+/* Return next elapsed time (for use when sending SpW time packet) */
+extern unsigned long long spwcuc_get_next_et(void *spwcuc);
+
+/* Force/Set the elapsed time (coarse 32-bit and fine 24-bit) by writing the
+ * T-Field Time Packet Registers then the FORCE bit.
+ */
+extern void spwcuc_force_et(void *spwcuc, unsigned long long time);
+
+/* Return received (from time packet) elapsed coarse time */
+extern unsigned int spwcuc_get_tp_et_coarse(void *spwcuc);
+
+/* Return received (from time packet) elapsed fine time */
+extern unsigned int spwcuc_get_tp_et_fine(void *spwcuc);
+
+/* Return received (from time packet) elapsed time (coarse and fine) */
+extern unsigned long long spwcuc_get_tp_et(void *spwcuc);
+
+/* Clear interrupts */
+extern void spwcuc_clear_irqs(void *spwcuc, int irqs);
+
+/* Enable interrupts */
+extern void spwcuc_enable_irqs(void *spwcuc, int irqs);
+
+/* Get Register */
+extern struct spwcuc_regs *spwcuc_get_regs(void *spwcuc);
+
+/* Register the SPWCUC Driver to the Driver Manager */
+extern void spwcuc_register(void);
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/include/tlib.h b/c/src/lib/libbsp/sparc/shared/include/tlib.h
new file mode 100644
index 0000000000..7b253b7813
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/tlib.h
@@ -0,0 +1,177 @@
+/*
+ * Timer Library (TLIB)
+ *
+ * The Library rely on timer drivers, the timer presented by the
+ * timer driver must look like a down-counter timer, which generates
+ * interrupt (if configured) when underflown.
+ *
+ * If Timer hardware is an up-counter the Timer driver must recalculate
+ * into values that would match as if it was a down-counter.
+ *
+ * COPYRIGHT (c) 2011.
+ * Aeroflex Gaisler.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+struct tlib_dev;
+
+typedef void (*tlib_isr_t)(void *data);
+
+struct tlib_drv {
+ /*** Functions ***/
+ void (*reset)(struct tlib_dev *hand);
+ void (*get_freq)(
+ struct tlib_dev *hand,
+ unsigned int *basefreq,
+ unsigned int *tickrate);
+ int (*set_freq)(struct tlib_dev *hand, unsigned int tickrate);
+ void (*irq_reg)(struct tlib_dev *hand, tlib_isr_t func, void *data);
+ void (*irq_unreg)(struct tlib_dev *hand, tlib_isr_t func,void *data);
+ void (*start)(struct tlib_dev *hand, int once);
+ void (*stop)(struct tlib_dev *hand);
+ void (*restart)(struct tlib_dev *hand);
+ void (*get_counter)(struct tlib_dev *hand, unsigned int *counter);
+ int (*custom)(struct tlib_dev *hand, int cmd, void *arg);
+ int (*int_pend)(struct tlib_dev *hand, int ack);
+};
+
+struct tlib_dev {
+ struct tlib_dev *next;
+ char status; /* 0=closed, 1=open, 2=timer started */
+ char index; /* Timer Index */
+ tlib_isr_t isr_func;
+ void *isr_data;
+ struct tlib_drv *drv;
+};
+
+#ifdef RTEMS_DRVMGR_STARTUP
+/* Clock Driver Timer register function. Only used when the TLIB-Clock
+ * driver is used. A specific Timer is registered as the System Clock
+ * timer.
+ */
+extern void Clock_timer_register(int timer_number);
+#endif
+
+/* Register Timer. Called by Timer Drivers in order to register
+ * a Timer to the Timer Library. The registration order determines
+ * the Timer Number used in tlib_open() to identify a specific
+ * Timer.
+ */
+extern int tlib_dev_reg(struct tlib_dev *newdev);
+
+/* Allocate a Timer.
+ *
+ * A Timer handle is returned identifying the timer in later calls.
+ */
+extern void *tlib_open(int timer_no);
+
+/* Close Timer */
+extern void tlib_close(void *hand);
+
+/* Returns Number of Timers currently registered to Timer Library */
+extern int tlib_ntimer(void);
+
+static inline void tlib_reset(void *hand)
+{
+ struct tlib_dev *dev = hand;
+
+ dev->drv->reset(dev);
+}
+/* Get Frequencies:
+ * - Base Frequency (unchangable base freq rate of timer, prescaler, clkinput)
+ * - Current Tick Rate [in multiples of Base Frequency]
+ */
+static inline void tlib_get_freq(
+ void *hand,
+ unsigned int *basefreq,
+ unsigned int *tickrate)
+{
+ struct tlib_dev *dev = hand;
+
+ dev->drv->get_freq(dev, basefreq, tickrate);
+}
+
+/* Set current Tick Rate in number of "Base-Frequency ticks" */
+static inline int tlib_set_freq(void *hand, unsigned int tickrate)
+{
+ struct tlib_dev *dev = hand;
+
+ return dev->drv->set_freq(dev, tickrate);
+}
+
+/* Register ISR at Timer ISR */
+static inline void tlib_irq_unregister(void *hand)
+{
+ struct tlib_dev *dev = hand;
+
+ if ( dev->isr_func ) {
+ dev->drv->irq_unreg(dev, dev->isr_func, dev->isr_data);
+ dev->isr_func = NULL;
+ }
+}
+
+/* Register ISR at Timer ISR */
+static inline void tlib_irq_register(void *hand, tlib_isr_t func, void *data)
+{
+ struct tlib_dev *dev = hand;
+
+ /* Unregister previous ISR if installed */
+ tlib_irq_unregister(hand);
+ dev->isr_func = func;
+ dev->isr_data = data;
+ dev->drv->irq_reg(dev, func, data);
+}
+
+/* Start Timer, ISRs will be generated if enabled.
+ *
+ * once determines if timer should restart (=0) on underflow automatically,
+ * or stop when underflow is reached (=1).
+ */
+static inline void tlib_start(void *hand, int once)
+{
+ struct tlib_dev *dev = hand;
+
+ dev->drv->start(dev, once);
+}
+
+/* Stop Timer, no more ISRs will be generated */
+static inline void tlib_stop(void *hand)
+{
+ struct tlib_dev *dev = hand;
+
+ dev->drv->stop(dev);
+}
+
+/* Restart/Reload Timer, may be usefull if a Watchdog Timer */
+static inline void tlib_restart(void *hand)
+{
+ struct tlib_dev *dev = hand;
+
+ dev->drv->restart(dev);
+}
+
+/* Get current counter value (since last tick) */
+static inline void tlib_get_counter(void *hand, unsigned int *counter)
+{
+ struct tlib_dev *dev = hand;
+
+ dev->drv->get_counter(dev, counter);
+}
+
+/* Do a custom operation */
+static inline void tlib_custom(void *hand, int cmd, void *arg)
+{
+ struct tlib_dev *dev = hand;
+
+ dev->drv->custom(dev, cmd, arg);
+}
+
+static inline int tlib_interrupt_pending(void *hand, int ack)
+{
+ struct tlib_dev *dev = hand;
+
+ return dev->drv->int_pend(dev, ack);
+}
diff --git a/c/src/lib/libbsp/sparc/shared/irq/genirq.c b/c/src/lib/libbsp/sparc/shared/irq/genirq.c
new file mode 100644
index 0000000000..f4e72909da
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/irq/genirq.c
@@ -0,0 +1,230 @@
+#include <rtems.h>
+#include <stdlib.h>
+#include <string.h>
+#include <genirq.h>
+
+struct genirq_handler_entry {
+ struct genirq_handler_entry *next; /* Next ISR entry for this IRQ number */
+ genirq_handler isr; /* ISR function called upon IRQ */
+ void *arg; /* custom argument to ISR */
+ int enabled; /* Inidicates if IRQ is enabled */
+};
+
+struct genirq_irq_entry {
+ struct genirq_handler_entry *head;
+ struct genirq_stats stats;
+};
+
+struct genirq_priv {
+ /* Maximum number of interrupt */
+ int genirq_max;
+ /* IRQ Table index N reflect IRQ number N */
+ struct genirq_irq_entry genirq_table[1]; /* Length depends on */
+};
+
+genirq_t genirq_init(int number_of_irqs)
+{
+ int size;
+ struct genirq_priv *priv;
+
+ size = sizeof(int) +
+ number_of_irqs * sizeof(struct genirq_irq_entry);
+
+ priv = (struct genirq_priv *)malloc(size);
+ if ( !priv )
+ return NULL;
+ memset(priv, 0, size);
+ priv->genirq_max = number_of_irqs - 1;
+ return priv;
+}
+
+void genirq_destroy(genirq_t d)
+{
+ struct genirq_priv *priv = d;
+ struct genirq_irq_entry *irqentry;
+ struct genirq_handler_entry *isrentry, *tmp;
+ int i;
+
+ /* Free all registered interrupts */
+ for ( i=0; i<priv->genirq_max; i++) {
+ irqentry = &priv->genirq_table[i];
+ isrentry = irqentry->head;
+ while ( isrentry ) {
+ tmp = isrentry;
+ isrentry = isrentry->next;
+ free(tmp);
+ }
+ }
+
+ free(priv);
+}
+
+int genirq_check(genirq_t d, int irq)
+{
+ struct genirq_priv *priv = d;
+
+ if ( (irq <= 0) || (irq > priv->genirq_max) )
+ return -1;
+ else
+ return 0;
+}
+
+int genirq_register(genirq_t d, int irq, genirq_handler isr, void *arg)
+{
+ struct genirq_priv *priv = d;
+ struct genirq_irq_entry *irqentry;
+ struct genirq_handler_entry *isrentry, *newentry;
+ rtems_interrupt_level level;
+
+ if ( genirq_check(d, irq) )
+ return -1;
+
+ newentry = malloc(sizeof(*newentry));
+ if ( !newentry )
+ return -1;
+
+ /* Initialize ISR entry */
+ newentry->isr = isr;
+ newentry->arg = arg;
+ newentry->enabled = 0;
+
+ rtems_interrupt_disable(level);
+
+ /* Insert new ISR entry first into table */
+ irqentry = &priv->genirq_table[irq];
+ isrentry = irqentry->head;
+ irqentry->head = newentry;
+ newentry->next = isrentry;
+
+ rtems_interrupt_enable(level);
+
+ if ( isrentry )
+ return 1; /* This is the first handler on this IRQ */
+ return 0;
+}
+
+int genirq_unregister(genirq_t d, int irq, genirq_handler isr, void *arg)
+{
+ struct genirq_priv *priv = d;
+ struct genirq_irq_entry *irqentry;
+ struct genirq_handler_entry *isrentry, **prev;
+ rtems_interrupt_level level;
+ int ret;
+
+ if ( genirq_check(d, irq) )
+ return -1;
+
+ /* Remove isr[arg] from ISR list */
+ irqentry = &priv->genirq_table[irq];
+ ret = -1;
+
+ rtems_interrupt_disable(level);
+
+ prev = &irqentry->head;
+ isrentry = irqentry->head;
+ while ( isrentry ) {
+ if ( (isrentry->arg == arg) && (isrentry->isr == isr) ) {
+ /* Found ISR, remove it from list */
+ if ( isrentry->enabled ) {
+ /* Can not remove enabled ISRs, disable first */
+ ret = 1;
+ break;
+ }
+ *prev = isrentry->next;
+ ret = 0;
+ break;
+ }
+ prev = &isrentry->next;
+ isrentry = isrentry->next;
+ }
+
+ rtems_interrupt_enable(level);
+
+ return ret;
+}
+
+/* Enables or Disables ISR handler. Internal function to reduce footprint
+ * of enable/disable functions.
+ *
+ * \param action 1=enable, 0=disable ISR
+ */
+int genirq_set_active(struct genirq_priv *priv, int irq, genirq_handler isr, void *arg, int action)
+{
+ struct genirq_irq_entry *irqentry;
+ struct genirq_handler_entry *isrentry, *e = NULL;
+ int enabled;
+
+ if ( genirq_check(priv, irq) )
+ return -1;
+
+ /* Find isr[arg] in ISR list */
+ irqentry = &priv->genirq_table[irq];
+ enabled = 0;
+
+ isrentry = irqentry->head;
+ while ( isrentry ) {
+ if ( (isrentry->arg == arg) && (isrentry->isr == isr) ) {
+ /* Found ISR */
+ if ( isrentry->enabled == action ) {
+ /* The ISR is already enabled or disabled
+ * depending on request, neccessary actions
+ * were taken last time the same action was
+ * requested.
+ */
+ return 1;
+ }
+ e = isrentry;
+ } else {
+ enabled += isrentry->enabled;
+ }
+ isrentry = isrentry->next;
+ }
+
+ if ( !e )
+ return -1;
+
+ e->enabled = action;
+
+ return enabled;
+}
+
+int genirq_enable(genirq_t d, int irq, genirq_handler isr, void *arg)
+{
+ struct genirq_priv *priv = d;
+ return genirq_set_active(priv, irq, isr, arg, 1);
+}
+
+int genirq_disable(genirq_t d, int irq, genirq_handler isr, void *arg)
+{
+ struct genirq_priv *priv = d;
+ return genirq_set_active(priv, irq, isr, arg, 0);
+}
+
+void genirq_doirq(genirq_t d, int irq)
+{
+ struct genirq_priv *priv = d;
+ struct genirq_irq_entry *irqentry;
+ struct genirq_handler_entry *isrentry;
+ int enabled;
+
+ irqentry = &priv->genirq_table[irq];
+ irqentry->stats.irq_cnt++;
+
+ enabled = 0;
+
+ isrentry = irqentry->head;
+ while ( isrentry ) {
+ if ( isrentry->enabled ) {
+ enabled = 1;
+ /* Call the ISR */
+ isrentry->isr(isrentry->arg);
+ }
+ isrentry = isrentry->next;
+ }
+
+ /* Was the IRQ an IRQ without source? */
+ if ( enabled == 0 ) {
+ /* This should not happen */
+ printk("Spurious IRQ happened on IRQ %d\n", irq);
+ }
+}
diff --git a/c/src/lib/libbsp/sparc/shared/irq/irq-shared.c b/c/src/lib/libbsp/sparc/shared/irq/irq-shared.c
new file mode 100644
index 0000000000..99480e451e
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/irq/irq-shared.c
@@ -0,0 +1,110 @@
+#include <rtems.h>
+#include <bsp.h>
+#include <bsp/irq-generic.h>
+#include <leon.h>
+
+static inline void leon_dispatch_irq(int irq)
+{
+ bsp_interrupt_handler_entry *e =
+ &bsp_interrupt_handler_table[bsp_interrupt_handler_index(irq)];
+
+ while (e != NULL) {
+ (*e->handler)(e->arg);
+ e = e->next;
+ }
+}
+
+/* Called directly from IRQ trap handler TRAP[0x10..0x1F] = IRQ[0..15] */
+void LEON_ISR_handler(rtems_vector_number vector)
+{
+ int irq = LEON_TRAP_SOURCE(vector);
+
+ /* Let BSP fixup and/or handle incomming IRQ */
+ irq = leon_irq_fixup(irq);
+
+ leon_dispatch_irq(irq);
+}
+
+/* Initialize interrupts */
+int BSP_shared_interrupt_init(void)
+{
+ rtems_vector_number vector;
+ rtems_isr_entry previous_isr;
+ int sc, i;
+
+ for (i=0; i <= BSP_INTERRUPT_VECTOR_MAX_STD; i++) {
+ vector = LEON_TRAP_TYPE(i);
+ rtems_interrupt_catch(LEON_ISR_handler, vector, &previous_isr);
+ }
+
+ /* Initalize interrupt support */
+ sc = bsp_interrupt_initialize();
+ if (sc != RTEMS_SUCCESSFUL)
+ return -1;
+
+ return 0;
+}
+
+/* Callback from bsp_interrupt_initialize() */
+rtems_status_code bsp_interrupt_facility_initialize(void)
+{
+ return RTEMS_SUCCESSFUL;
+}
+
+/* Spurious IRQ handler */
+void bsp_interrupt_handler_default(rtems_vector_number vector)
+{
+ printk("Spurious IRQ %d\n", (int)vector);
+}
+
+rtems_status_code bsp_interrupt_vector_enable(rtems_vector_number vector)
+{
+ rtems_interrupt_level level;
+
+ rtems_interrupt_disable(level);
+ LEON_Unmask_interrupt((int)vector);
+ rtems_interrupt_enable(level);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+rtems_status_code bsp_interrupt_vector_disable(rtems_vector_number vector)
+{
+ rtems_interrupt_level level;
+
+ rtems_interrupt_disable(level);
+ LEON_Mask_interrupt((int)vector);
+ rtems_interrupt_enable(level);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+void BSP_shared_interrupt_mask(int irq)
+{
+ rtems_interrupt_level level;
+
+ rtems_interrupt_disable(level);
+
+ LEON_Mask_interrupt(irq);
+
+ rtems_interrupt_enable(level);
+}
+
+void BSP_shared_interrupt_unmask(int irq)
+{
+ rtems_interrupt_level level;
+
+ rtems_interrupt_disable(level);
+
+ LEON_Unmask_interrupt(irq);
+
+ rtems_interrupt_enable(level);
+}
+
+void BSP_shared_interrupt_clear(int irq)
+{
+ /* We don't have to interrupt lock here, because the register is only
+ * written and self clearing
+ */
+ LEON_Clear_interrupt(irq);
+}
diff --git a/c/src/lib/libbsp/sparc/shared/mem/mctrl.c b/c/src/lib/libbsp/sparc/shared/mem/mctrl.c
new file mode 100644
index 0000000000..587dc57de1
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/mem/mctrl.c
@@ -0,0 +1,214 @@
+/* Memory Controller driver (FTMTRL, MCTRL)
+ *
+ * COPYRIGHT (c) 2008.
+ * Aeroflex Gaisler AB.
+ *
+ * This file contains the driver for the MCTRL memory controller.
+ * The driver sets the memory configuration registers (MCFG1, MCFG2, MCFG3)
+ * during driver initialization
+ *
+ * The license and distribution terms for this file may be
+ * found in found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2008-12-08, Daniel Hellstrom <daniel@gaisler.com>
+ * Created
+ *
+ */
+
+/******************* Driver manager interface ***********************/
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+
+#define MEMSET(priv, start, c, length) memset((void *)start, c, length)
+
+#define DBG(args...)
+/*#define DBG(args...) printk(args)*/
+
+struct mctrl_regs {
+ unsigned int mcfg[8];
+};
+
+struct mctrl_priv;
+
+struct mctrl_ops {
+ void (*mcfg_set)(struct mctrl_priv *priv, int index, void *regs, unsigned int regval);
+};
+
+struct mctrl_priv {
+ struct drvmgr_dev *dev;
+ void *regs;
+ unsigned int mcfg[8]; /* The wanted memory configuration */
+ unsigned int configured; /* Determines what mcfgs was configured by user */
+ struct mctrl_ops *ops; /* Operation may depend on hardware */
+};
+
+static int mctrl_init1(struct drvmgr_dev *dev);
+static int mctrl_remove(struct drvmgr_dev *dev);
+
+/* Standard MCFG registers */
+static void mctrl_set_std(struct mctrl_priv *priv, int index, void *regs, unsigned int regval);
+
+struct mctrl_ops std_mctrl_ops =
+{
+ mctrl_set_std
+};
+
+struct drvmgr_drv_ops mctrl_ops =
+{
+ .init = {mctrl_init1, NULL, NULL, NULL},
+ .remove = mctrl_remove,
+ .info = NULL
+};
+
+struct amba_dev_id mctrl_ids[] =
+{
+ {VENDOR_ESA, ESA_MCTRL},
+ {VENDOR_GAISLER, GAISLER_FTMCTRL},
+ {VENDOR_GAISLER, GAISLER_FTSRCTRL},
+ {0, 0} /* Mark end of table */
+};
+
+struct amba_drv_info mctrl_drv_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_AMBAPP_MCTRL_ID, /* Driver ID */
+ "MCTRL_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */
+ &mctrl_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ 0,
+ },
+ &mctrl_ids[0]
+};
+
+void mctrl_register_drv (void)
+{
+ DBG("Registering MCTRL driver\n");
+ drvmgr_drv_register(&mctrl_drv_info.general);
+}
+
+static int mctrl_init1(struct drvmgr_dev *dev)
+{
+ struct mctrl_priv *priv;
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
+ int i;
+ char res_name[16];
+ union drvmgr_key_value *value;
+ unsigned int start, length;
+
+ DBG("MCTRL[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
+ priv = dev->priv = malloc(sizeof(struct mctrl_priv));
+ if ( !priv )
+ return DRVMGR_NOMEM;
+ memset(priv, 0, sizeof(*priv));
+ priv->dev = dev;
+
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)priv->dev->businfo;
+ if ( ambadev == NULL ) {
+ return DRVMGR_FAIL;
+ }
+ pnpinfo = &ambadev->info;
+ if ( pnpinfo->apb_slv == NULL ) {
+ /* LEON2 PnP systems are missing the APB interface */
+ priv->regs = (void *)0x80000000;
+ } else {
+ priv->regs = (void *)pnpinfo->apb_slv->start;
+ }
+
+ /* Depending on Hardware selection write/read routines */
+ switch ( pnpinfo->vendor ) {
+ case VENDOR_ESA:
+ switch ( pnpinfo->device ) {
+ case ESA_MCTRL:
+ default:
+ priv->ops = &std_mctrl_ops;
+ }
+ break;
+
+ case VENDOR_GAISLER:
+ switch ( pnpinfo->device ) {
+ case GAISLER_FTMCTRL:
+ case GAISLER_FTSRCTRL:
+ default:
+ priv->ops = &std_mctrl_ops;
+ }
+ break;
+
+ default:
+ priv->ops = &std_mctrl_ops;
+ break;
+ }
+
+ /* Find user configuration from bus resources */
+ priv->configured = 0;
+ strcpy(res_name, "mcfgX");
+ for(i=0; i<8; i++) {
+ res_name[4] = '1' + i;
+ value = drvmgr_dev_key_get(priv->dev, res_name, KEY_TYPE_INT);
+ if ( value ) {
+ priv->mcfg[i] = value->i;
+ priv->configured |= (1<<i);
+ }
+ }
+
+ /* Init hardware registers right away, other devices may depend on it in init2(), also
+ * the washing depend on it.
+ */
+ for ( i=0; i<8; i++) {
+ if ( priv->configured & (1<<i) ) {
+ DBG("Setting MCFG%d to 0x%08x\n", i+1, priv->mcfg[i]);
+ priv->ops->mcfg_set(priv, i, priv->regs, priv->mcfg[i]);
+ }
+ }
+
+ /* Wash memory partitions if user wants */
+ for (i=0; i<9; i++) {
+ strcpy(res_name, "washXStart");
+ res_name[4] = '0' + i;
+ value = drvmgr_dev_key_get(priv->dev, res_name, KEY_TYPE_INT);
+ if ( value ) {
+ start = value->i;
+ strcpy(res_name, "washXLength");
+ res_name[4] = '0' + i;
+ value = drvmgr_dev_key_get(priv->dev, res_name, KEY_TYPE_INT);
+ if ( value ) {
+ length = value->i;
+
+ if ( length > 0 ) {
+ DBG("MCTRL: Washing 0x%08x-0x%08x\n", start, start+length-1);
+
+ MEMSET(priv, (void *)start, 0, length);
+ }
+ }
+ }
+ }
+
+ return DRVMGR_OK;
+}
+
+static int mctrl_remove(struct drvmgr_dev *dev)
+{
+ /* Nothing to be done */
+ DBG("Removing %s\n", dev->name);
+ return DRVMGR_OK;
+}
+
+/* Standard Operations */
+static void mctrl_set_std(struct mctrl_priv *priv, int index, void *regs, unsigned int regval)
+{
+ struct mctrl_regs *pregs = regs;
+
+ /* Store new value */
+ pregs->mcfg[index] = regval;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/mem/mctrl_rmap.c b/c/src/lib/libbsp/sparc/shared/mem/mctrl_rmap.c
new file mode 100644
index 0000000000..19e85dabff
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/mem/mctrl_rmap.c
@@ -0,0 +1,248 @@
+/* Memory Controller driver (FTMTRL, FTSRCTRL, MCTRL)
+ *
+ * COPYRIGHT (c) 2008.
+ * Aeroflex Gaisler AB.
+ *
+ * This file contains the driver for the MCTRL memory controller.
+ * The driver sets the memory configuration registers (MCFG1, MCFG2, MCFG3)
+ * during driver initialization
+ *
+ * The license and distribution terms for this file may be
+ * found in found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2009-11-19, Daniel Hellstrom <daniel@gaisler.com>
+ * Created from on-chip memory controller driver
+ *
+ */
+
+/******************* Driver manager interface ***********************/
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+#include <drvmgr/ambapp_bus_rmap.h>
+
+/* This call will take 128 bytes of buffer at stack */
+#define MEMSET(pDev, adr, c, length) pDev->rw_memset(adr, c, length, &pDev->rw_arg)
+
+#define DBG(args...)
+/*#define DBG(args...) printk(args)*/
+
+struct mctrl_regs {
+ unsigned int mcfg[8];
+};
+
+struct mctrl_priv;
+
+struct mctrl_ops {
+ void (*mcfg_set)(struct mctrl_priv *priv, int index, void *regs, unsigned int regval);
+};
+
+struct mctrl_priv {
+ struct drvmgr_dev *dev;
+ void *regs;
+ unsigned int mcfg[8]; /* The wanted memory configuration */
+ unsigned int configured; /* Determines what mcfgs was configured by user */
+ struct mctrl_ops *ops; /* Operation may depend on hardware */
+
+ /* Read/Write access operations */
+ struct drvmgr_rw_arg rw_arg;
+ ambapp_rmap_w32 rw_w32;
+ ambapp_rmap_memset rw_memset;
+};
+
+static int mctrl_init1(struct drvmgr_dev *dev);
+static int mctrl_remove(struct drvmgr_dev *dev);
+
+/* Standard MCFG registers */
+static void mctrl_set_std(struct mctrl_priv *priv, int index, void *regs, unsigned int regval);
+
+static struct mctrl_ops std_mctrl_ops =
+{
+ mctrl_set_std
+};
+
+static struct drvmgr_drv_ops mctrl_ops =
+{
+ .init = {mctrl_init1,NULL, NULL, NULL},
+ .remove = mctrl_remove,
+ .info = NULL
+};
+
+static struct amba_dev_id mctrl_ids[] =
+{
+ {VENDOR_ESA, ESA_MCTRL},
+ {VENDOR_GAISLER, GAISLER_FTMCTRL},
+ {VENDOR_GAISLER, GAISLER_FTSRCTRL},
+ {0, 0} /* Mark end of table */
+};
+
+static struct amba_drv_info mctrl_drv_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_AMBAPP_MCTRL_ID, /* Driver ID */
+ "MCTRL_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_AMBAPP_RMAP, /* Bus Type */
+ &mctrl_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ 0,
+ },
+ &mctrl_ids[0]
+};
+
+void mctrl_rmap_register_drv (void)
+{
+ DBG("Registering MCTRL driver\n");
+ drvmgr_drv_register(&mctrl_drv_info.general);
+}
+
+static int mctrl_init1(struct drvmgr_dev *dev)
+{
+ struct mctrl_priv *priv;
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
+ int i;
+ char res_name[16];
+ union drvmgr_key_value *value;
+ unsigned int start, length;
+
+ DBG("MCTRL[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
+ priv = dev->priv = malloc(sizeof(struct mctrl_priv));
+ if ( !priv )
+ return DRVMGR_NOMEM;
+ memset(priv, 0, sizeof(*priv));
+ priv->dev = dev;
+
+ /* Get Read/Write operations for bus */
+ priv->rw_arg.dev = dev;
+ priv->rw_arg.arg = drvmgr_func_call(dev->parent, AMBAPP_RMAP_RW_ARG, dev, NULL, NULL, NULL);
+ drvmgr_func_get(dev->parent, AMBAPP_RMAP_W32, (void **)&priv->rw_w32);
+ drvmgr_func_get(dev->parent, AMBAPP_RMAP_MEMSET, (void **)&priv->rw_memset);
+
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)priv->dev->businfo;
+ if ( ambadev == NULL ) {
+ return DRVMGR_FAIL;
+ }
+ pnpinfo = &ambadev->info;
+ if ( pnpinfo->apb_slv == NULL ) {
+ /* LEON2 PnP systems are missing the APB interface */
+ priv->regs = (void *)0x80000000;
+ } else {
+ priv->regs = (void *)pnpinfo->apb_slv->start;
+ }
+
+ /* Depending on Hardware selection write/read routines */
+ switch ( pnpinfo->vendor ) {
+ case VENDOR_ESA:
+ switch ( pnpinfo->device ) {
+ case ESA_MCTRL:
+ default:
+ priv->ops = &std_mctrl_ops;
+ }
+ break;
+
+ case VENDOR_GAISLER:
+ switch ( pnpinfo->device ) {
+ case GAISLER_FTMCTRL:
+ case GAISLER_FTSRCTRL:
+ default:
+ priv->ops = &std_mctrl_ops;
+ }
+ break;
+
+ default:
+ priv->ops = &std_mctrl_ops;
+ break;
+ }
+
+ /* Find user configuration from bus resources */
+ priv->configured = 0;
+ strcpy(res_name, "mcfgX");
+ for(i=0; i<8; i++) {
+ res_name[4] = '1' + i;
+ value = drvmgr_dev_key_get(priv->dev, res_name, KEY_TYPE_INT);
+ if ( value ) {
+ priv->mcfg[i] = value->i;
+ priv->configured |= (1<<i);
+ }
+ }
+
+ /* Init hardware registers right away, other devices may depend on it in init2(), also
+ * the washing depend on it.
+ */
+ for ( i=0; i<8; i++) {
+ if ( priv->configured & (1<<i) ) {
+ DBG("Setting MCFG%d to 0x%08x\n", i+1, priv->mcfg[i]);
+ priv->ops->mcfg_set(priv, i, priv->regs, priv->mcfg[i]);
+ }
+ }
+
+ /* Wash memory partitions if user wants */
+ for (i=0; i<9; i++) {
+ strcpy(res_name, "washXStart");
+ res_name[4] = '0' + i;
+ value = drvmgr_dev_key_get(priv->dev, res_name, KEY_TYPE_INT);
+ if ( value ) {
+ start = value->i;
+ strcpy(res_name, "washXLength");
+ res_name[4] = '0' + i;
+ value = drvmgr_dev_key_get(priv->dev, res_name, KEY_TYPE_INT);
+ if ( value ) {
+ length = value->i;
+
+ if ( length > 0 ) {
+ DBG("MCTRL-RMAP: Washing 0x%08x-0x%08x\n", start, start+length-1);
+
+ MEMSET(priv, (void *)start, 0, length);
+ }
+ }
+ }
+ }
+
+ /* Register memory partitions if user wants */
+ for (i=0; i<9; i++) {
+ strcpy(res_name, "partXStart");
+ res_name[4] = '0' + i;
+ value = drvmgr_dev_key_get(priv->dev, res_name, KEY_TYPE_INT);
+ if ( value ) {
+ start = value->i;
+ strcpy(res_name, "partXLength");
+ res_name[4] = '0' + i;
+ value = drvmgr_dev_key_get(priv->dev, res_name, KEY_TYPE_INT);
+ if ( value ) {
+ length = value->i;
+
+ DBG("MCTRL-RMAP: registering partition %d: 0x%08x-0x%08x\n", i, start, length);
+
+ /* Register partition */
+ ambapp_rmap_partition_create(dev, i, start, length);
+ }
+ }
+ }
+
+ return DRVMGR_OK;
+}
+
+static int mctrl_remove(struct drvmgr_dev *dev)
+{
+ /* Nothing to be done */
+ DBG("Removing %s\n", dev->name);
+ return DRVMGR_OK;
+}
+
+/* Standard Operations */
+static void mctrl_set_std(struct mctrl_priv *priv, int index, void *regs, unsigned int regval)
+{
+ struct mctrl_regs *pregs = regs;
+
+ /* Store new value */
+ priv->rw_w32((uint32_t *)&pregs->mcfg[index], (uint32_t)regval, &priv->rw_arg);
+}
diff --git a/c/src/lib/libbsp/sparc/shared/net/README b/c/src/lib/libbsp/sparc/shared/net/README
new file mode 100644
index 0000000000..3ef086f223
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/net/README
@@ -0,0 +1,7 @@
+A non Driver Manager GRETH driver is located in libchip/network/greth.c. This
+version requires the driver manager.
+
+network_interface_add is used to assign IP/NETMASK and MAC address to
+GRETH interfaces dynamically according to in which order devices are
+registered. The function takes the settings from the user defined
+interface_configs[] array, defined in the project configuration.
diff --git a/c/src/lib/libbsp/sparc/shared/net/greth.c b/c/src/lib/libbsp/sparc/shared/net/greth.c
new file mode 100644
index 0000000000..fea8890c72
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/net/greth.c
@@ -0,0 +1,1451 @@
+/*
+ * Gaisler Research ethernet MAC driver
+ * adapted from Opencores driver by Marko Isomaki
+ *
+ * The license and distribution terms for this file may be
+ * found in found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ *
+ * 2008-12-10, Converted to driver manager and added support for
+ * multiple GRETH cores. <daniel@gaisler.com>
+ * 2007-09-07, Ported GBIT support from 4.6.5
+ */
+#include <rtems.h>
+#define _KERNEL
+#define CPU_U32_FIX
+#include <bsp.h>
+
+#ifdef GRETH_SUPPORTED
+
+#include <inttypes.h>
+#include <errno.h>
+#include <rtems/bspIo.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <rtems/error.h>
+#include <rtems/rtems_bsdnet.h>
+
+#include <greth.h>
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+#include <ambapp.h>
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#ifdef malloc
+#undef malloc
+#endif
+#ifdef free
+#undef free
+#endif
+
+#if defined(__m68k__)
+extern m68k_isr_entry set_vector( rtems_isr_entry, rtems_vector_number, int );
+#else
+extern rtems_isr_entry set_vector( rtems_isr_entry, rtems_vector_number, int );
+#endif
+
+
+/* #define GRETH_DEBUG */
+
+#ifdef GRETH_DEBUG
+#define DBG(args...) printk(args)
+#else
+#define DBG(args...)
+#endif
+
+/* #define GRETH_DEBUG_MII */
+
+#ifdef GRETH_DEBUG_MII
+#define MIIDBG(args...) printk(args)
+#else
+#define MIIDBG(args...)
+#endif
+
+#ifdef CPU_U32_FIX
+extern void ipalign(struct mbuf *m);
+#endif
+
+/* Used when reading from memory written by GRETH DMA unit */
+#ifndef GRETH_MEM_LOAD
+#define GRETH_MEM_LOAD(addr) (*(volatile unsigned int *)(addr))
+#endif
+
+/*
+ * Number of OCs supported by this driver
+ */
+#define NOCDRIVER 1
+
+/*
+ * Receive buffer size -- Allow for a full ethernet packet including CRC
+ */
+#define RBUF_SIZE 1518
+
+#define ET_MINLEN 64 /* minimum message length */
+
+/*
+ * RTEMS event used by interrupt handler to signal driver tasks.
+ * This must not be any of the events used by the network task synchronization.
+ */
+#define INTERRUPT_EVENT RTEMS_EVENT_1
+
+/*
+ * RTEMS event used to start transmit daemon.
+ * This must not be the same as INTERRUPT_EVENT.
+ */
+#define START_TRANSMIT_EVENT RTEMS_EVENT_2
+
+ /* event to send when tx buffers become available */
+#define GRETH_TX_WAIT_EVENT RTEMS_EVENT_3
+
+#if (MCLBYTES < RBUF_SIZE)
+# error "Driver must have MCLBYTES > RBUF_SIZE"
+#endif
+
+/* 4s Autonegotiation Timeout */
+#ifndef GRETH_AUTONEGO_TIMEOUT_MS
+#define GRETH_AUTONEGO_TIMEOUT_MS 4000
+#endif
+const struct timespec greth_tan = {
+ GRETH_AUTONEGO_TIMEOUT_MS/1000,
+ GRETH_AUTONEGO_TIMEOUT_MS*1000000
+};
+
+/* For optimizing the autonegotiation time */
+#define GRETH_AUTONEGO_PRINT_TIME
+
+/* Ethernet buffer descriptor */
+
+typedef struct _greth_rxtxdesc {
+ volatile uint32_t ctrl; /* Length and status */
+ uint32_t *addr; /* Buffer pointer */
+} greth_rxtxdesc;
+
+
+/*
+ * Per-device data
+ */
+struct greth_softc
+{
+
+ struct arpcom arpcom;
+ struct drvmgr_dev *dev; /* Driver manager device */
+ char devName[32];
+
+ greth_regs *regs;
+ int minor;
+ int phyaddr; /* PHY Address configured by user (or -1 to autodetect) */
+
+ int acceptBroadcast;
+ rtems_id daemonTid;
+
+ unsigned int tx_ptr;
+ unsigned int tx_dptr;
+ unsigned int tx_cnt;
+ unsigned int rx_ptr;
+ unsigned int txbufs;
+ unsigned int rxbufs;
+ greth_rxtxdesc *txdesc;
+ greth_rxtxdesc *rxdesc;
+ unsigned int txdesc_remote;
+ unsigned int rxdesc_remote;
+ struct mbuf **rxmbuf;
+ struct mbuf **txmbuf;
+ rtems_vector_number vector;
+
+ /* TX descriptor interrupt generation */
+ int tx_int_gen;
+ int tx_int_gen_cur;
+ struct mbuf *next_tx_mbuf;
+ int max_fragsize;
+
+ /*Status*/
+ struct phy_device_info phydev;
+ int phy_read_access;
+ int phy_write_access;
+ int fd;
+ int sp;
+ int gb;
+ int gbit_mac;
+ int auto_neg;
+ struct timespec auto_neg_time;
+
+ /*
+ * Statistics
+ */
+ unsigned long rxInterrupts;
+
+ unsigned long rxPackets;
+ unsigned long rxLengthError;
+ unsigned long rxNonOctet;
+ unsigned long rxBadCRC;
+ unsigned long rxOverrun;
+
+ unsigned long txInterrupts;
+
+ unsigned long txDeferred;
+ unsigned long txHeartbeat;
+ unsigned long txLateCollision;
+ unsigned long txRetryLimit;
+ unsigned long txUnderrun;
+
+};
+
+int greth_process_tx_gbit(struct greth_softc *sc);
+int greth_process_tx(struct greth_softc *sc);
+
+static char *almalloc(int sz)
+{
+ char *tmp;
+ tmp = calloc(1,2*sz);
+ tmp = (char *) (((int)tmp+sz) & ~(sz -1));
+ return(tmp);
+}
+
+/* GRETH interrupt handler */
+
+void greth_interrupt (void *arg)
+{
+ uint32_t status;
+ uint32_t ctrl;
+ rtems_event_set events = 0;
+ struct greth_softc *greth = arg;
+
+ /* read and clear interrupt cause */
+ status = greth->regs->status;
+ greth->regs->status = status;
+ ctrl = greth->regs->ctrl;
+
+ /* Frame received? */
+ if ((ctrl & GRETH_CTRL_RXIRQ) && (status & (GRETH_STATUS_RXERR | GRETH_STATUS_RXIRQ)))
+ {
+ greth->rxInterrupts++;
+ /* Stop RX-Error and RX-Packet interrupts */
+ ctrl &= ~GRETH_CTRL_RXIRQ;
+ events |= INTERRUPT_EVENT;
+ }
+
+ if ( (ctrl & GRETH_CTRL_TXIRQ) && (status & (GRETH_STATUS_TXERR | GRETH_STATUS_TXIRQ)) )
+ {
+ greth->txInterrupts++;
+ ctrl &= ~GRETH_CTRL_TXIRQ;
+ events |= GRETH_TX_WAIT_EVENT;
+ }
+
+ /* Clear interrupt sources */
+ greth->regs->ctrl = ctrl;
+
+ /* Send the event(s) */
+ if ( events )
+ rtems_event_send (greth->daemonTid, events);
+}
+
+static uint32_t read_mii(struct greth_softc *sc, uint32_t phy_addr, uint32_t reg_addr)
+{
+ sc->phy_read_access++;
+ while (sc->regs->mdio_ctrl & GRETH_MDIO_BUSY) {}
+ sc->regs->mdio_ctrl = (phy_addr << 11) | (reg_addr << 6) | GRETH_MDIO_READ;
+ while (sc->regs->mdio_ctrl & GRETH_MDIO_BUSY) {}
+ if (!(sc->regs->mdio_ctrl & GRETH_MDIO_LINKFAIL)) {
+ MIIDBG("greth%d: mii read[%d] OK to %x.%x (0x%08x,0x%08x)\n",
+ sc->minor, sc->phy_read_access, phy_addr, reg_addr,
+ sc->regs->ctrl, sc->regs->mdio_ctrl);
+
+ return((sc->regs->mdio_ctrl >> 16) & 0xFFFF);
+ } else {
+ printf("greth%d: mii read[%d] failed to %x.%x (0x%08x,0x%08x)\n",
+ sc->minor, sc->phy_read_access, phy_addr, reg_addr,
+ sc->regs->ctrl, sc->regs->mdio_ctrl);
+ return (0xffff);
+ }
+}
+
+static void write_mii(struct greth_softc *sc, uint32_t phy_addr, uint32_t reg_addr, uint32_t data)
+{
+ sc->phy_write_access++;
+ while (sc->regs->mdio_ctrl & GRETH_MDIO_BUSY) {}
+ sc->regs->mdio_ctrl =
+ ((data & 0xFFFF) << 16) | (phy_addr << 11) | (reg_addr << 6) | GRETH_MDIO_WRITE;
+ while (sc->regs->mdio_ctrl & GRETH_MDIO_BUSY) {}
+ if (!(sc->regs->mdio_ctrl & GRETH_MDIO_LINKFAIL)) {
+ MIIDBG("greth%d: mii write[%d] OK to %x.%x (0x%08x,0x%08x)\n",
+ sc->minor, sc->phy_write_access, phy_addr, reg_addr,
+ sc->regs->ctrl, sc->regs->mdio_ctrl);
+ } else {
+ printf("greth%d: mii write[%d] failed to %x.%x (0x%08x,0x%08x)\n",
+ sc->minor, sc->phy_write_access, phy_addr, reg_addr,
+ sc->regs->ctrl, sc->regs->mdio_ctrl);
+ }
+}
+
+static void print_init_info(struct greth_softc *sc)
+{
+ printf("greth: driver attached\n");
+ if ( sc->auto_neg == -1 ){
+ printf("Auto negotiation timed out. Selecting default config\n");
+ }
+ printf("**** PHY ****\n");
+ printf("Vendor: %x Device: %x Revision: %d\n",sc->phydev.vendor, sc->phydev.device, sc->phydev.rev);
+ printf("Current Operating Mode: ");
+ if (sc->gb) {
+ printf("1000 Mbit ");
+ } else if (sc->sp) {
+ printf("100 Mbit ");
+ } else {
+ printf("10 Mbit ");
+ }
+ if (sc->fd) {
+ printf("Full Duplex\n");
+ } else {
+ printf("Half Duplex\n");
+ }
+#ifdef GRETH_AUTONEGO_PRINT_TIME
+ if ( sc->auto_neg ) {
+ printf("Autonegotiation Time: %dms\n", sc->auto_neg_time.tv_sec * 1000 +
+ sc->auto_neg_time.tv_nsec / 1000000);
+ }
+#endif
+}
+
+
+/*
+ * Initialize the ethernet hardware
+ */
+static void
+greth_initialize_hardware (struct greth_softc *sc)
+{
+ struct mbuf *m;
+ int i;
+ int phyaddr;
+ int phyctrl;
+ int phystatus;
+ int tmp1;
+ int tmp2;
+ struct timespec tstart, tnow;
+
+ greth_regs *regs;
+
+ regs = sc->regs;
+
+ /* Reset the controller. */
+ sc->rxInterrupts = 0;
+ sc->rxPackets = 0;
+
+ regs->ctrl = GRETH_CTRL_RST; /* Reset ON */
+ for (i = 0; i<100 && (regs->ctrl & GRETH_CTRL_RST); i++)
+ ;
+ regs->ctrl = GRETH_CTRL_DD; /* Reset OFF. SW do PHY Init */
+
+ /* Check if mac is gbit capable*/
+ sc->gbit_mac = (regs->ctrl >> 27) & 1;
+
+ /* Get the phy address which assumed to have been set
+ correctly with the reset value in hardware*/
+ if ( sc->phyaddr == -1 ) {
+ phyaddr = (regs->mdio_ctrl >> 11) & 0x1F;
+ } else {
+ phyaddr = sc->phyaddr;
+ }
+ sc->phy_read_access = 0;
+ sc->phy_write_access = 0;
+
+ /* As I understand the PHY comes back to a good default state after
+ * Power-down or Reset, so we do both just in case. Power-down bit should
+ * be cleared.
+ * Wait for old reset (if asserted by boot loader) to complete, otherwise
+ * power-down instruction might not have any effect.
+ */
+ while (read_mii(sc, phyaddr, 0) & 0x8000) {}
+ write_mii(sc, phyaddr, 0, 0x0800); /* Power-down */
+ write_mii(sc, phyaddr, 0, 0x0000); /* Power-Up */
+ write_mii(sc, phyaddr, 0, 0x8000); /* Reset */
+
+ /* We wait about 30ms */
+ rtems_task_wake_after(rtems_clock_get_ticks_per_second()/32);
+
+ /* Wait for reset to complete and get default values */
+ while ((phyctrl = read_mii(sc, phyaddr, 0)) & 0x8000) {}
+
+ /* Enable/Disable GBit auto-neg advetisement so that the link partner
+ * know that we have/haven't GBit capability. The MAC may not support
+ * Gbit even though PHY does...
+ */
+ phystatus = read_mii(sc, phyaddr, 1);
+ if (phystatus & 0x0100) {
+ tmp1 = read_mii(sc, phyaddr, 9);
+ if (sc->gbit_mac)
+ write_mii(sc, phyaddr, 9, tmp1 | 0x300);
+ else
+ write_mii(sc, phyaddr, 9, tmp1 & ~(0x300));
+ }
+
+ /* If autonegotiation implemented we start it */
+ if (phystatus & 0x0008) {
+ write_mii(sc, phyaddr, 0, phyctrl | 0x1200);
+ phyctrl = read_mii(sc, phyaddr, 0);
+ }
+
+ /* Check if PHY is autoneg capable and then determine operating mode,
+ otherwise force it to 10 Mbit halfduplex */
+ sc->gb = 0;
+ sc->fd = 0;
+ sc->sp = 0;
+ sc->auto_neg = 0;
+ _Timespec_Set_to_zero(&sc->auto_neg_time);
+ if ((phyctrl >> 12) & 1) {
+ /*wait for auto negotiation to complete*/
+ sc->auto_neg = 1;
+ if (rtems_clock_get_uptime(&tstart) != RTEMS_SUCCESSFUL)
+ printk("rtems_clock_get_uptime failed\n");
+ while (!(((phystatus = read_mii(sc, phyaddr, 1)) >> 5) & 1)) {
+ if (rtems_clock_get_uptime(&tnow) != RTEMS_SUCCESSFUL)
+ printk("rtems_clock_get_uptime failed\n");
+ _Timespec_Subtract(&tstart, &tnow, &sc->auto_neg_time);
+ if (_Timespec_Greater_than(&sc->auto_neg_time, &greth_tan)) {
+ sc->auto_neg = -1; /* Failed */
+ tmp1 = read_mii(sc, phyaddr, 0);
+ sc->gb = ((phyctrl >> 6) & 1) && !((phyctrl >> 13) & 1);
+ sc->sp = !((phyctrl >> 6) & 1) && ((phyctrl >> 13) & 1);
+ sc->fd = (phyctrl >> 8) & 1;
+ goto auto_neg_done;
+ }
+ /* Wait about 30ms, time is PHY dependent */
+ rtems_task_wake_after(rtems_clock_get_ticks_per_second()/32);
+ }
+ sc->phydev.adv = read_mii(sc, phyaddr, 4);
+ sc->phydev.part = read_mii(sc, phyaddr, 5);
+ if ((phystatus >> 8) & 1) {
+ sc->phydev.extadv = read_mii(sc, phyaddr, 9);
+ sc->phydev.extpart = read_mii(sc, phyaddr, 10);
+ if ( (sc->phydev.extadv & GRETH_MII_EXTADV_1000FD) &&
+ (sc->phydev.extpart & GRETH_MII_EXTPRT_1000FD)) {
+ sc->gb = 1;
+ sc->fd = 1;
+ }
+ if ( (sc->phydev.extadv & GRETH_MII_EXTADV_1000HD) &&
+ (sc->phydev.extpart & GRETH_MII_EXTPRT_1000HD)) {
+ sc->gb = 1;
+ sc->fd = 0;
+ }
+ }
+ if ((sc->gb == 0) || ((sc->gb == 1) && (sc->gbit_mac == 0))) {
+ if ( (sc->phydev.adv & GRETH_MII_100TXFD) &&
+ (sc->phydev.part & GRETH_MII_100TXFD)) {
+ sc->sp = 1;
+ sc->fd = 1;
+ }
+ if ( (sc->phydev.adv & GRETH_MII_100TXHD) &&
+ (sc->phydev.part & GRETH_MII_100TXHD)) {
+ sc->sp = 1;
+ sc->fd = 0;
+ }
+ if ( (sc->phydev.adv & GRETH_MII_10FD) &&
+ (sc->phydev.part & GRETH_MII_10FD)) {
+ sc->fd = 1;
+ }
+ }
+ }
+auto_neg_done:
+ sc->phydev.vendor = 0;
+ sc->phydev.device = 0;
+ sc->phydev.rev = 0;
+ phystatus = read_mii(sc, phyaddr, 1);
+
+ /* Read out PHY info if extended registers are available */
+ if (phystatus & 1) {
+ tmp1 = read_mii(sc, phyaddr, 2);
+ tmp2 = read_mii(sc, phyaddr, 3);
+
+ sc->phydev.vendor = (tmp1 << 6) | ((tmp2 >> 10) & 0x3F);
+ sc->phydev.rev = tmp2 & 0xF;
+ sc->phydev.device = (tmp2 >> 4) & 0x3F;
+ }
+
+ /* Force to 10 mbit half duplex if the 10/100 MAC is used with a 1000 PHY */
+ if (((sc->gb) && !(sc->gbit_mac)) || !((phyctrl >> 12) & 1)) {
+ write_mii(sc, phyaddr, 0, sc->sp << 13);
+
+ /* check if marvell 88EE1111 PHY. Needs special reset handling */
+ if ((phystatus & 1) && (sc->phydev.vendor == 0x005043) &&
+ (sc->phydev.device == 0x0C))
+ write_mii(sc, phyaddr, 0, 0x8000);
+
+ sc->gb = 0;
+ sc->sp = 0;
+ sc->fd = 0;
+ }
+ while ((read_mii(sc, phyaddr, 0)) & 0x8000) {}
+
+ regs->ctrl = GRETH_CTRL_RST; /* Reset ON */
+ for (i = 0; i < 100 && (regs->ctrl & GRETH_CTRL_RST); i++)
+ ;
+ regs->ctrl = GRETH_CTRL_DD;
+
+ /* Initialize rx/tx descriptor pointers */
+ sc->txdesc = (greth_rxtxdesc *) almalloc(1024);
+ sc->rxdesc = (greth_rxtxdesc *) almalloc(1024);
+ sc->tx_ptr = 0;
+ sc->tx_dptr = 0;
+ sc->tx_cnt = 0;
+ sc->rx_ptr = 0;
+
+ /* Translate the base address into an address that the GRETH core can understand */
+ drvmgr_translate(sc->dev, 0, 0, (void *)sc->txdesc, (void **)&sc->txdesc_remote);
+ drvmgr_translate(sc->dev, 0, 0, (void *)sc->rxdesc, (void **)&sc->rxdesc_remote);
+ regs->txdesc = (int) sc->txdesc_remote;
+ regs->rxdesc = (int) sc->rxdesc_remote;
+
+ sc->rxmbuf = calloc(sc->rxbufs, sizeof(*sc->rxmbuf));
+ sc->txmbuf = calloc(sc->txbufs, sizeof(*sc->txmbuf));
+
+ for (i = 0; i < sc->txbufs; i++)
+ {
+ sc->txdesc[i].ctrl = 0;
+ if (!(sc->gbit_mac)) {
+ drvmgr_translate(sc->dev, 0, 0, (void *)malloc(GRETH_MAXBUF_LEN), (void **)&sc->txdesc[i].addr);
+ }
+#ifdef GRETH_DEBUG
+ /* printf("TXBUF: %08x\n", (int) sc->txdesc[i].addr); */
+#endif
+ }
+ for (i = 0; i < sc->rxbufs; i++)
+ {
+ MGETHDR (m, M_WAIT, MT_DATA);
+ MCLGET (m, M_WAIT);
+ if (sc->gbit_mac)
+ m->m_data += 2;
+ m->m_pkthdr.rcvif = &sc->arpcom.ac_if;
+ sc->rxmbuf[i] = m;
+ drvmgr_translate(sc->dev, 0, 0, (void *)mtod(m, uint32_t *), (void **)&sc->rxdesc[i].addr);
+ sc->rxdesc[i].ctrl = GRETH_RXD_ENABLE | GRETH_RXD_IRQ;
+#ifdef GRETH_DEBUG
+/* printf("RXBUF: %08x\n", (int) sc->rxdesc[i].addr); */
+#endif
+ }
+ sc->rxdesc[sc->rxbufs - 1].ctrl |= GRETH_RXD_WRAP;
+
+ /* set ethernet address. */
+ regs->mac_addr_msb =
+ sc->arpcom.ac_enaddr[0] << 8 | sc->arpcom.ac_enaddr[1];
+ regs->mac_addr_lsb =
+ sc->arpcom.ac_enaddr[2] << 24 | sc->arpcom.ac_enaddr[3] << 16 |
+ sc->arpcom.ac_enaddr[4] << 8 | sc->arpcom.ac_enaddr[5];
+
+ if ( sc->rxbufs < 10 ) {
+ sc->tx_int_gen = sc->tx_int_gen_cur = 1;
+ }else{
+ sc->tx_int_gen = sc->tx_int_gen_cur = sc->txbufs/2;
+ }
+ sc->next_tx_mbuf = NULL;
+
+ if ( !sc->gbit_mac )
+ sc->max_fragsize = 1;
+
+ /* clear all pending interrupts */
+ regs->status = 0xffffffff;
+
+ /* install interrupt handler */
+ drvmgr_interrupt_register(sc->dev, 0, "greth", greth_interrupt, sc);
+
+ regs->ctrl |= GRETH_CTRL_RXEN | (sc->fd << 4) | GRETH_CTRL_RXIRQ | (sc->sp << 7) | (sc->gb << 8);
+
+ print_init_info(sc);
+}
+
+#ifdef CPU_U32_FIX
+
+/*
+ * Routine to align the received packet so that the ip header
+ * is on a 32-bit boundary. Necessary for cpu's that do not
+ * allow unaligned loads and stores and when the 32-bit DMA
+ * mode is used.
+ *
+ * Transfers are done on word basis to avoid possibly slow byte
+ * and half-word writes.
+ */
+
+void ipalign(struct mbuf *m)
+{
+ unsigned int *first, *last, data;
+ unsigned int tmp = 0;
+
+ if ((((int) m->m_data) & 2) && (m->m_len)) {
+ last = (unsigned int *) ((((int) m->m_data) + m->m_len + 8) & ~3);
+ first = (unsigned int *) (((int) m->m_data) & ~3);
+ /* tmp = *first << 16; */
+ asm volatile (" lda [%1] 1, %0\n" : "=r"(tmp) : "r"(first) );
+ tmp = tmp << 16;
+ first++;
+ do {
+ /* When snooping is not available the LDA instruction must be used
+ * to avoid the cache to return an illegal value.
+ ** Load with forced cache miss
+ * data = *first;
+ */
+ asm volatile (" lda [%1] 1, %0\n" : "=r"(data) : "r"(first) );
+ *first = tmp | (data >> 16);
+ tmp = data << 16;
+ first++;
+ } while (first <= last);
+
+ m->m_data = (caddr_t)(((int) m->m_data) + 2);
+ }
+}
+#endif
+
+void
+greth_Daemon (void *arg)
+{
+ struct ether_header *eh;
+ struct greth_softc *dp = (struct greth_softc *) arg;
+ struct ifnet *ifp = &dp->arpcom.ac_if;
+ struct mbuf *m;
+ unsigned int len, len_status, bad;
+ rtems_event_set events;
+ rtems_interrupt_level level;
+ int first;
+ int tmp;
+ unsigned int addr;
+
+ for (;;)
+ {
+ rtems_bsdnet_event_receive (INTERRUPT_EVENT | GRETH_TX_WAIT_EVENT,
+ RTEMS_WAIT | RTEMS_EVENT_ANY,
+ RTEMS_NO_TIMEOUT, &events);
+
+ if ( events & GRETH_TX_WAIT_EVENT ){
+ /* TX interrupt.
+ * We only end up here when all TX descriptors has been used,
+ * and
+ */
+ if ( dp->gbit_mac )
+ greth_process_tx_gbit(dp);
+ else
+ greth_process_tx(dp);
+
+ /* If we didn't get a RX interrupt we don't process it */
+ if ( (events & INTERRUPT_EVENT) == 0 )
+ continue;
+ }
+
+
+#ifdef GRETH_ETH_DEBUG
+ printf ("r\n");
+#endif
+ first=1;
+ /* Scan for Received packets */
+again:
+ while (!((len_status =
+ GRETH_MEM_LOAD(&dp->rxdesc[dp->rx_ptr].ctrl)) & GRETH_RXD_ENABLE))
+ {
+ bad = 0;
+ if (len_status & GRETH_RXD_TOOLONG)
+ {
+ dp->rxLengthError++;
+ bad = 1;
+ }
+ if (len_status & GRETH_RXD_DRIBBLE)
+ {
+ dp->rxNonOctet++;
+ bad = 1;
+ }
+ if (len_status & GRETH_RXD_CRCERR)
+ {
+ dp->rxBadCRC++;
+ bad = 1;
+ }
+ if (len_status & GRETH_RXD_OVERRUN)
+ {
+ dp->rxOverrun++;
+ bad = 1;
+ }
+ if (len_status & GRETH_RXD_LENERR)
+ {
+ dp->rxLengthError++;
+ bad = 1;
+ }
+ if (!bad)
+ {
+ /* pass on the packet in the receive buffer */
+ len = len_status & 0x7FF;
+ m = dp->rxmbuf[dp->rx_ptr];
+#ifdef GRETH_DEBUG
+ int i;
+ printf("RX: 0x%08x, Len: %d : ", (int) m->m_data, len);
+ for (i=0; i<len; i++)
+ printf("%x%x", (m->m_data[i] >> 4) & 0x0ff, m->m_data[i] & 0x0ff);
+ printf("\n");
+#endif
+ m->m_len = m->m_pkthdr.len =
+ len - sizeof (struct ether_header);
+
+ eh = mtod (m, struct ether_header *);
+
+ m->m_data += sizeof (struct ether_header);
+#ifdef CPU_U32_FIX
+ if(!dp->gbit_mac) {
+ /* OVERRIDE CACHED ETHERNET HEADER FOR NON-SNOOPING SYSTEMS */
+ addr = (unsigned int)eh;
+ asm volatile (" lda [%1] 1, %0\n" : "=r"(tmp) : "r"(addr) );
+ addr+=4;
+ asm volatile (" lda [%1] 1, %0\n" : "=r"(tmp) : "r"(addr) );
+ addr+=4;
+ asm volatile (" lda [%1] 1, %0\n" : "=r"(tmp) : "r"(addr) );
+ addr+=4;
+ asm volatile (" lda [%1] 1, %0\n" : "=r"(tmp) : "r"(addr) );
+
+ ipalign(m); /* Align packet on 32-bit boundary */
+ }
+#endif
+/*
+ if(!(dp->gbit_mac) && !CPU_SPARC_HAS_SNOOPING) {
+ rtems_cache_invalidate_entire_data();
+ }
+*/
+ ether_input (ifp, eh, m);
+ MGETHDR (m, M_WAIT, MT_DATA);
+ MCLGET (m, M_WAIT);
+ if (dp->gbit_mac)
+ m->m_data += 2;
+ dp->rxmbuf[dp->rx_ptr] = m;
+ m->m_pkthdr.rcvif = ifp;
+ drvmgr_translate(dp->dev, 0, 0, (void *)mtod (m, uint32_t *), (void **)&dp->rxdesc[dp->rx_ptr].addr);
+ dp->rxPackets++;
+ }
+ if (dp->rx_ptr == dp->rxbufs - 1) {
+ dp->rxdesc[dp->rx_ptr].ctrl = GRETH_RXD_ENABLE | GRETH_RXD_IRQ | GRETH_RXD_WRAP;
+ } else {
+ dp->rxdesc[dp->rx_ptr].ctrl = GRETH_RXD_ENABLE | GRETH_RXD_IRQ;
+ }
+ rtems_interrupt_disable(level);
+ dp->regs->ctrl |= GRETH_CTRL_RXEN;
+ rtems_interrupt_enable(level);
+ dp->rx_ptr = (dp->rx_ptr + 1) % dp->rxbufs;
+ }
+
+ /* Always scan twice to avoid deadlock */
+ if ( first ){
+ first=0;
+ rtems_interrupt_disable(level);
+ dp->regs->ctrl |= GRETH_CTRL_RXIRQ;
+ rtems_interrupt_enable(level);
+ goto again;
+ }
+
+ }
+
+}
+
+static int inside = 0;
+static int
+sendpacket (struct ifnet *ifp, struct mbuf *m)
+{
+ struct greth_softc *dp = ifp->if_softc;
+ unsigned char *temp;
+ struct mbuf *n;
+ unsigned int len;
+ rtems_interrupt_level level;
+
+ /*printf("Send packet entered\n");*/
+ if (inside) printf ("error: sendpacket re-entered!!\n");
+ inside = 1;
+
+ /*
+ * Is there a free descriptor available?
+ */
+ if (GRETH_MEM_LOAD(&dp->txdesc[dp->tx_ptr].ctrl) & GRETH_TXD_ENABLE){
+ /* No. */
+ inside = 0;
+ return 1;
+ }
+
+ /* Remember head of chain */
+ n = m;
+
+ len = 0;
+ temp = (unsigned char *) GRETH_MEM_LOAD(&dp->txdesc[dp->tx_ptr].addr);
+ drvmgr_translate(dp->dev, 1, 1, (void *)temp, (void **)&temp);
+#ifdef GRETH_DEBUG
+ printf("TXD: 0x%08x : BUF: 0x%08x\n", (int) m->m_data, (int) temp);
+#endif
+ for (;;)
+ {
+#ifdef GRETH_DEBUG
+ int i;
+ printf("MBUF: 0x%08x : ", (int) m->m_data);
+ for (i=0;i<m->m_len;i++)
+ printf("%x%x", (m->m_data[i] >> 4) & 0x0ff, m->m_data[i] & 0x0ff);
+ printf("\n");
+#endif
+ len += m->m_len;
+ if (len <= RBUF_SIZE)
+ memcpy ((void *) temp, (char *) m->m_data, m->m_len);
+ temp += m->m_len;
+ if ((m = m->m_next) == NULL)
+ break;
+ }
+
+ m_freem (n);
+
+ /* don't send long packets */
+
+ if (len <= GRETH_MAXBUF_LEN) {
+ if (dp->tx_ptr < dp->txbufs-1) {
+ dp->txdesc[dp->tx_ptr].ctrl = GRETH_TXD_ENABLE | len;
+ } else {
+ dp->txdesc[dp->tx_ptr].ctrl =
+ GRETH_TXD_WRAP | GRETH_TXD_ENABLE | len;
+ }
+ dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
+ rtems_interrupt_disable(level);
+ dp->regs->ctrl = dp->regs->ctrl | GRETH_CTRL_TXEN;
+ rtems_interrupt_enable(level);
+
+ }
+ inside = 0;
+
+ return 0;
+}
+
+
+int
+sendpacket_gbit (struct ifnet *ifp, struct mbuf *m)
+{
+ struct greth_softc *dp = ifp->if_softc;
+ unsigned int len;
+
+ unsigned int ctrl;
+ int frags;
+ struct mbuf *mtmp;
+ int int_en;
+ rtems_interrupt_level level;
+
+ if (inside) printf ("error: sendpacket re-entered!!\n");
+ inside = 1;
+
+ len = 0;
+#ifdef GRETH_DEBUG
+ printf("TXD: 0x%08x\n", (int) m->m_data);
+#endif
+ /* Get number of fragments too see if we have enough
+ * resources.
+ */
+ frags=1;
+ mtmp=m;
+ while(mtmp->m_next){
+ frags++;
+ mtmp = mtmp->m_next;
+ }
+
+ if ( frags > dp->max_fragsize )
+ dp->max_fragsize = frags;
+
+ if ( frags > dp->txbufs ){
+ inside = 0;
+ printf("GRETH: MBUF-chain cannot be sent. Increase descriptor count.\n");
+ return -1;
+ }
+
+ if ( frags > (dp->txbufs-dp->tx_cnt) ){
+ inside = 0;
+ /* Return number of fragments */
+ return frags;
+ }
+
+
+ /* Enable interrupt from descriptor every tx_int_gen
+ * descriptor. Typically every 16 descriptor. This
+ * is only to reduce the number of interrupts during
+ * heavy load.
+ */
+ dp->tx_int_gen_cur-=frags;
+ if ( dp->tx_int_gen_cur <= 0 ){
+ dp->tx_int_gen_cur = dp->tx_int_gen;
+ int_en = GRETH_TXD_IRQ;
+ }else{
+ int_en = 0;
+ }
+
+ /* At this stage we know that enough descriptors are available */
+ for (;;)
+ {
+
+#ifdef GRETH_DEBUG
+ int i;
+ printf("MBUF: 0x%08x, Len: %d : ", (int) m->m_data, m->m_len);
+ for (i=0; i<m->m_len; i++)
+ printf("%x%x", (m->m_data[i] >> 4) & 0x0ff, m->m_data[i] & 0x0ff);
+ printf("\n");
+#endif
+ len += m->m_len;
+ drvmgr_translate(dp->dev, 0, 0, (void *)(uint32_t *)m->m_data, (void **)&dp->txdesc[dp->tx_ptr].addr);
+
+ /* Wrap around? */
+ if (dp->tx_ptr < dp->txbufs-1) {
+ ctrl = GRETH_TXD_ENABLE | GRETH_TXD_CS;
+ }else{
+ ctrl = GRETH_TXD_ENABLE | GRETH_TXD_CS | GRETH_TXD_WRAP;
+ }
+
+ /* Enable Descriptor */
+ if ((m->m_next) == NULL) {
+ dp->txdesc[dp->tx_ptr].ctrl = ctrl | int_en | m->m_len;
+ break;
+ }else{
+ dp->txdesc[dp->tx_ptr].ctrl = GRETH_TXD_MORE | ctrl | int_en | m->m_len;
+ }
+
+ /* Next */
+ dp->txmbuf[dp->tx_ptr] = m;
+ dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
+ dp->tx_cnt++;
+ m = m->m_next;
+ }
+ dp->txmbuf[dp->tx_ptr] = m;
+ dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
+ dp->tx_cnt++;
+
+ /* Tell Hardware about newly enabled descriptor */
+ rtems_interrupt_disable(level);
+ dp->regs->ctrl = dp->regs->ctrl | GRETH_CTRL_TXEN;
+ rtems_interrupt_enable(level);
+
+ inside = 0;
+
+ return 0;
+}
+
+int greth_process_tx_gbit(struct greth_softc *sc)
+{
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ struct mbuf *m;
+ rtems_interrupt_level level;
+ int first=1;
+
+ /*
+ * Send packets till queue is empty
+ */
+ for (;;){
+ /* Reap Sent packets */
+ while((sc->tx_cnt > 0) && !(GRETH_MEM_LOAD(&sc->txdesc[sc->tx_dptr].ctrl) & GRETH_TXD_ENABLE)) {
+ m_free(sc->txmbuf[sc->tx_dptr]);
+ sc->tx_dptr = (sc->tx_dptr + 1) % sc->txbufs;
+ sc->tx_cnt--;
+ }
+
+ if ( sc->next_tx_mbuf ){
+ /* Get packet we tried but faild to transmit last time */
+ m = sc->next_tx_mbuf;
+ sc->next_tx_mbuf = NULL; /* Mark packet taken */
+ }else{
+ /*
+ * Get the next mbuf chain to transmit from Stack.
+ */
+ IF_DEQUEUE (&ifp->if_snd, m);
+ if (!m){
+ /* Hardware has sent all schedule packets, this
+ * makes the stack enter at greth_start next time
+ * a packet is to be sent.
+ */
+ ifp->if_flags &= ~IFF_OACTIVE;
+ break;
+ }
+ }
+
+ /* Are there free descriptors available? */
+ /* Try to send packet, if it a negative number is returned. */
+ if ( (sc->tx_cnt >= sc->txbufs) || sendpacket_gbit(ifp, m) ){
+ /* Not enough resources */
+
+ /* Since we have taken the mbuf out of the "send chain"
+ * we must remember to use that next time we come back.
+ * or else we have dropped a packet.
+ */
+ sc->next_tx_mbuf = m;
+
+ /* Not enough resources, enable interrupt for transmissions
+ * this way we will be informed when more TX-descriptors are
+ * available.
+ */
+ if ( first ){
+ first = 0;
+ rtems_interrupt_disable(level);
+ ifp->if_flags |= IFF_OACTIVE;
+ sc->regs->ctrl |= GRETH_CTRL_TXIRQ;
+ rtems_interrupt_enable(level);
+
+ /* We must check again to be sure that we didn't
+ * miss an interrupt (if a packet was sent just before
+ * enabling interrupts)
+ */
+ continue;
+ }
+
+ return -1;
+ }else{
+ /* Sent Ok, proceed to process more packets if available */
+ }
+ }
+ return 0;
+}
+
+int greth_process_tx(struct greth_softc *sc)
+{
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ struct mbuf *m;
+ rtems_interrupt_level level;
+ int first=1;
+
+ /*
+ * Send packets till queue is empty
+ */
+ for (;;){
+ if ( sc->next_tx_mbuf ){
+ /* Get packet we tried but failed to transmit last time */
+ m = sc->next_tx_mbuf;
+ sc->next_tx_mbuf = NULL; /* Mark packet taken */
+ }else{
+ /*
+ * Get the next mbuf chain to transmit from Stack.
+ */
+ IF_DEQUEUE (&ifp->if_snd, m);
+ if (!m){
+ /* Hardware has sent all schedule packets, this
+ * makes the stack enter at greth_start next time
+ * a packet is to be sent.
+ */
+ ifp->if_flags &= ~IFF_OACTIVE;
+ break;
+ }
+ }
+
+ /* Try to send packet, failed if it a non-zero number is returned. */
+ if ( sendpacket(ifp, m) ){
+ /* Not enough resources */
+
+ /* Since we have taken the mbuf out of the "send chain"
+ * we must remember to use that next time we come back.
+ * or else we have dropped a packet.
+ */
+ sc->next_tx_mbuf = m;
+
+ /* Not enough resources, enable interrupt for transmissions
+ * this way we will be informed when more TX-descriptors are
+ * available.
+ */
+ if ( first ){
+ first = 0;
+ rtems_interrupt_disable(level);
+ ifp->if_flags |= IFF_OACTIVE;
+ sc->regs->ctrl |= GRETH_CTRL_TXIRQ;
+ rtems_interrupt_enable(level);
+
+ /* We must check again to be sure that we didn't
+ * miss an interrupt (if a packet was sent just before
+ * enabling interrupts)
+ */
+ continue;
+ }
+
+ return -1;
+ }else{
+ /* Sent Ok, proceed to process more packets if available */
+ }
+ }
+ return 0;
+}
+
+static void
+greth_start (struct ifnet *ifp)
+{
+ struct greth_softc *sc = ifp->if_softc;
+
+ if ( ifp->if_flags & IFF_OACTIVE )
+ return;
+
+ if ( sc->gbit_mac ){
+ /* No use trying to handle this if we are waiting on GRETH
+ * to send the previously scheduled packets.
+ */
+
+ greth_process_tx_gbit(sc);
+ }else{
+ greth_process_tx(sc);
+ }
+
+}
+
+/*
+ * Initialize and start the device
+ */
+static void
+greth_init (void *arg)
+{
+ struct greth_softc *sc = arg;
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ char name[4] = {'E', 'T', 'H', '0'};
+
+ if (sc->daemonTid == 0)
+ {
+
+ /*
+ * Start driver tasks
+ */
+ name[3] += sc->minor;
+ sc->daemonTid = rtems_bsdnet_newproc (name, 4096,
+ greth_Daemon, sc);
+
+ /*
+ * Set up GRETH hardware
+ */
+ greth_initialize_hardware (sc);
+
+ }
+
+ /*
+ * Tell the world that we're running.
+ */
+ ifp->if_flags |= IFF_RUNNING;
+
+}
+
+/*
+ * Stop the device
+ */
+static void
+greth_stop (struct greth_softc *sc)
+{
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+
+ ifp->if_flags &= ~IFF_RUNNING;
+
+ sc->regs->ctrl = 0; /* RX/TX OFF */
+ sc->regs->ctrl = GRETH_CTRL_RST; /* Reset ON */
+ sc->regs->ctrl = 0; /* Reset OFF */
+
+ sc->next_tx_mbuf = NULL;
+}
+
+
+/*
+ * Show interface statistics
+ */
+static void
+greth_stats (struct greth_softc *sc)
+{
+ printf (" Rx Interrupts:%-8lu", sc->rxInterrupts);
+ printf (" Rx Packets:%-8lu", sc->rxPackets);
+ printf (" Length:%-8lu", sc->rxLengthError);
+ printf (" Non-octet:%-8lu\n", sc->rxNonOctet);
+ printf (" Bad CRC:%-8lu", sc->rxBadCRC);
+ printf (" Overrun:%-8lu", sc->rxOverrun);
+ printf (" Tx Interrupts:%-8lu", sc->txInterrupts);
+ printf (" Maximal Frags:%-8d", sc->max_fragsize);
+ printf (" GBIT MAC:%-8d", sc->gbit_mac);
+}
+
+/*
+ * Driver ioctl handler
+ */
+static int
+greth_ioctl (struct ifnet *ifp, ioctl_command_t command, caddr_t data)
+{
+ struct greth_softc *sc = ifp->if_softc;
+ int error = 0;
+
+ switch (command)
+ {
+ case SIOCGIFADDR:
+ case SIOCSIFADDR:
+ ether_ioctl (ifp, command, data);
+ break;
+
+ case SIOCSIFFLAGS:
+ switch (ifp->if_flags & (IFF_UP | IFF_RUNNING))
+ {
+ case IFF_RUNNING:
+ greth_stop (sc);
+ break;
+
+ case IFF_UP:
+ greth_init (sc);
+ break;
+
+ case IFF_UP | IFF_RUNNING:
+ greth_stop (sc);
+ greth_init (sc);
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case SIO_RTEMS_SHOW_STATS:
+ greth_stats (sc);
+ break;
+
+ /*
+ * FIXME: All sorts of multicast commands need to be added here!
+ */
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ return error;
+}
+
+/*
+ * Attach an GRETH driver to the system
+ */
+int
+greth_interface_driver_attach (
+ struct rtems_bsdnet_ifconfig *config,
+ int attach
+ )
+{
+ struct greth_softc *sc;
+ struct ifnet *ifp;
+ int mtu;
+ int unitNumber;
+ char *unitName;
+
+ /* parse driver name */
+ if ((unitNumber = rtems_bsdnet_parse_driver_name (config, &unitName)) < 0)
+ return 0;
+
+ sc = config->drv_ctrl;
+ ifp = &sc->arpcom.ac_if;
+#ifdef GRETH_DEBUG
+ printf("GRETH[%d]: %s, sc %p, dev %p on %s\n", unitNumber, config->ip_address, sc, sc->dev, sc->dev->parent->dev->name);
+#endif
+ if (config->hardware_address)
+ {
+ memcpy (sc->arpcom.ac_enaddr, config->hardware_address,
+ ETHER_ADDR_LEN);
+ }
+ else
+ {
+ memset (sc->arpcom.ac_enaddr, 0x08, ETHER_ADDR_LEN);
+ }
+
+ if (config->mtu)
+ mtu = config->mtu;
+ else
+ mtu = ETHERMTU;
+
+ sc->acceptBroadcast = !config->ignore_broadcast;
+
+ /*
+ * Set up network interface values
+ */
+ ifp->if_softc = sc;
+ ifp->if_unit = unitNumber;
+ ifp->if_name = unitName;
+ ifp->if_mtu = mtu;
+ ifp->if_init = greth_init;
+ ifp->if_ioctl = greth_ioctl;
+ ifp->if_start = greth_start;
+ ifp->if_output = ether_output;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
+ if (ifp->if_snd.ifq_maxlen == 0)
+ ifp->if_snd.ifq_maxlen = ifqmaxlen;
+
+ /*
+ * Attach the interface
+ */
+ if_attach (ifp);
+ ether_ifattach (ifp);
+
+#ifdef GRETH_DEBUG
+ printf ("GRETH : driver has been attached\n");
+#endif
+ return 1;
+}
+
+/******************* Driver manager interface ***********************/
+
+/* Driver prototypes */
+int greth_register_io(rtems_device_major_number *m);
+int greth_device_init(struct greth_softc *sc);
+int network_interface_add(struct rtems_bsdnet_ifconfig *interface);
+
+#ifdef GRETH_INFO_AVAIL
+static int greth_info(
+ struct drvmgr_dev *dev,
+ void (*print_line)(void *p, char *str),
+ void *p, int argc, char *argv[]);
+#define GRETH_INFO_FUNC greth_info
+#else
+#define GRETH_INFO_FUNC NULL
+#endif
+
+int greth_init2(struct drvmgr_dev *dev);
+int greth_init3(struct drvmgr_dev *dev);
+
+struct drvmgr_drv_ops greth_ops =
+{
+ .init =
+ {
+ NULL,
+ greth_init2,
+ greth_init3,
+ NULL
+ },
+ .remove = NULL,
+ .info = GRETH_INFO_FUNC,
+};
+
+struct amba_dev_id greth_ids[] =
+{
+ {VENDOR_GAISLER, GAISLER_ETHMAC},
+ {0, 0} /* Mark end of table */
+};
+
+struct amba_drv_info greth_drv_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_AMBAPP_GAISLER_GRETH_ID, /* Driver ID */
+ "GRETH_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */
+ &greth_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ 0,
+ },
+ &greth_ids[0]
+};
+
+void greth_register_drv (void)
+{
+ DBG("Registering GRETH driver\n");
+ drvmgr_drv_register(&greth_drv_info.general);
+}
+
+int greth_init2(struct drvmgr_dev *dev)
+{
+ struct greth_softc *priv;
+
+ DBG("GRETH[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
+ priv = dev->priv = malloc(sizeof(struct greth_softc));
+ if ( !priv )
+ return DRVMGR_NOMEM;
+ memset(priv, 0, sizeof(*priv));
+ priv->dev = dev;
+
+ /* This core will not find other cores, so we wait for init3() */
+
+ return DRVMGR_OK;
+}
+
+int greth_init3(struct drvmgr_dev *dev)
+{
+ struct greth_softc *sc;
+ struct rtems_bsdnet_ifconfig *ifp;
+ rtems_status_code status;
+
+ sc = dev->priv;
+ sprintf(sc->devName, "gr_eth%d", (dev->minor_drv+1));
+
+ /* Init GRETH device */
+ if ( greth_device_init(sc) ) {
+ printk("GRETH: Failed to init device\n");
+ return DRVMGR_FAIL;
+ }
+
+ /* Register GRETH device as an Network interface */
+ ifp = malloc(sizeof(struct rtems_bsdnet_ifconfig));
+ memset(ifp, 0, sizeof(*ifp));
+
+ ifp->name = sc->devName;
+ ifp->drv_ctrl = sc;
+ ifp->attach = greth_interface_driver_attach;
+
+ status = network_interface_add(ifp);
+ if (status != 0) {
+ return DRVMGR_FAIL;
+ }
+
+ return DRVMGR_OK;
+}
+
+int greth_device_init(struct greth_softc *sc)
+{
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
+ union drvmgr_key_value *value;
+
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)sc->dev->businfo;
+ if ( ambadev == NULL ) {
+ return -1;
+ }
+ pnpinfo = &ambadev->info;
+ sc->regs = (greth_regs *)pnpinfo->apb_slv->start;
+ sc->minor = sc->dev->minor_drv;
+
+ /* clear control register and reset NIC
+ * This should be done as quick as possible during startup, this is to
+ * stop DMA transfers after a reboot.
+ */
+ sc->regs->ctrl = 0;
+ sc->regs->ctrl = GRETH_CTRL_RST;
+ sc->regs->ctrl = 0;
+
+ /* Configure driver by overriding default config with the bus resources
+ * configured by the user
+ */
+ sc->txbufs = 32;
+ sc->rxbufs = 32;
+ sc->phyaddr = -1;
+
+ value = drvmgr_dev_key_get(sc->dev, "txDescs", KEY_TYPE_INT);
+ if ( value && (value->i <= 128) )
+ sc->txbufs = value->i;
+
+ value = drvmgr_dev_key_get(sc->dev, "rxDescs", KEY_TYPE_INT);
+ if ( value && (value->i <= 128) )
+ sc->rxbufs = value->i;
+
+ value = drvmgr_dev_key_get(sc->dev, "phyAdr", KEY_TYPE_INT);
+ if ( value && (value->i < 32) )
+ sc->phyaddr = value->i;
+
+ return 0;
+}
+
+#ifdef GRETH_INFO_AVAIL
+static int greth_info(
+ struct drvmgr_dev *dev,
+ void (*print_line)(void *p, char *str),
+ void *p, int argc, char *argv[])
+{
+ struct greth_softc *sc;
+ char buf[64];
+
+ if (dev->priv == NULL)
+ return -DRVMGR_EINVAL;
+ sc = dev->priv;
+
+ sprintf(buf, "IFACE NAME: %s", sc->devName);
+ print_line(p, buf);
+ sprintf(buf, "GBIT MAC: %s", sc->gbit_mac ? "YES" : "NO");
+ print_line(p, buf);
+
+ return DRVMGR_OK;
+}
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/net/network_interface_add.c b/c/src/lib/libbsp/sparc/shared/net/network_interface_add.c
new file mode 100644
index 0000000000..7c7ce31b4a
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/net/network_interface_add.c
@@ -0,0 +1,66 @@
+/* Network interface register help function
+ *
+ * COPYRIGHT (c) 2008.
+ * Aeroflex Gaisler AB.
+ *
+ * This function adds a network interface to the
+ * rtems_bsdnet_config.ifconfig linked list of interfaces.
+ * The interface configuration is taken from the user defined
+ * array interface_configs. This function is useful for PnP
+ * systems when an unknown number of interfaces are available.
+ *
+ * The license and distribution terms for this file may be
+ * found in found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2008-12-08, Daniel Hellstrom <daniel@gaisler.com>
+ * Created
+ *
+ */
+
+#include <rtems/rtems_bsdnet.h>
+#include <stdio.h>
+
+#include <network_interface_add.h>
+
+extern struct rtems_bsdnet_config rtems_bsdnet_config;
+
+/* Number of interfaces taken */
+int network_interface_cnt = 0;
+
+int network_interface_add(struct rtems_bsdnet_ifconfig *interface)
+{
+ struct ethernet_config *cfg = NULL;
+ int i, last_entry = 1;
+
+ /* Init interface description */
+ interface->next = NULL;
+
+ cfg = &interface_configs[network_interface_cnt];
+ for(i=0; i<6; i++) {
+ if ( cfg->eth_adr[i] != 0 ) {
+ last_entry = 0;
+ break;
+ }
+ }
+ /* Do we have a valid configuration? */
+ if ( last_entry == 0 ) {
+ cfg = &interface_configs[network_interface_cnt];
+
+ interface->ip_address = cfg->ip_addr;
+ interface->ip_netmask = cfg->ip_netmask;
+ interface->hardware_address = cfg->eth_adr;
+
+ network_interface_cnt++;
+ } else {
+ interface->ip_address = NULL;
+ interface->ip_netmask = NULL;
+ interface->hardware_address = NULL;
+ }
+
+ /* Insert interface first into list */
+ interface->next = rtems_bsdnet_config.ifconfig;
+ rtems_bsdnet_config.ifconfig = interface;
+
+ return 0;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/pci/gr_701.c b/c/src/lib/libbsp/sparc/shared/pci/gr_701.c
new file mode 100644
index 0000000000..01c6b88f1c
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/pci/gr_701.c
@@ -0,0 +1,596 @@
+/* GR-701 PCI Target driver.
+ *
+ * COPYRIGHT (c) 2008.
+ * Aeroflex Gaisler AB.
+ *
+ * Configures the GR-701 interface PCI board.
+ * This driver provides a AMBA PnP bus by using the general part
+ * of the AMBA PnP bus driver (ambapp_bus.c).
+ *
+ * Driver resources for the AMBA PnP bus provided can be set using
+ * gr701_set_resources().
+ *
+ * The license and distribution terms for this file may be
+ * found in found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2008-12-05, Daniel Hellstrom <daniel@gaisler.com>
+ * Created
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <bsp.h>
+#include <rtems/bspIo.h>
+#include <pci.h>
+#include <pci/access.h>
+
+#include <ambapp.h>
+
+#include <ambapp.h>
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+#include <drvmgr/pci_bus.h>
+#include <genirq.h>
+
+#include <gr_701.h>
+
+/* Offset from 0x80000000 (dual bus version) */
+#define AHB1_BASE_ADDR 0x80000000
+#define AHB1_IOAREA_BASE_ADDR 0x80100000
+
+/* #define DEBUG 1 */
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+int gr701_init1(struct drvmgr_dev *dev);
+int gr701_init2(struct drvmgr_dev *dev);
+
+#define READ_REG(address) (*(volatile unsigned int *)address)
+
+/* PCI bride reg layout on AMBA side */
+struct amba_bridge_regs {
+ volatile unsigned int bar0;
+ volatile unsigned int bar1;
+ volatile unsigned int bar2;
+ volatile unsigned int bar3;
+ volatile unsigned int bar4;/* 0x10 */
+
+ volatile unsigned int unused[4*3-1];
+
+ volatile unsigned int ambabars[1]; /* 0x40 */
+};
+
+/* PCI bride reg layout on PCI side */
+struct pci_bridge_regs {
+ volatile unsigned int bar0;
+ volatile unsigned int bar1;
+ volatile unsigned int bar2;
+ volatile unsigned int bar3;
+ volatile unsigned int bar4; /* 0x10 */
+
+ volatile unsigned int ilevel;
+ volatile unsigned int ipend;
+ volatile unsigned int iforce;
+ volatile unsigned int istatus;
+ volatile unsigned int iclear;
+ volatile unsigned int imask;
+};
+
+/* Private data structure for driver */
+struct gr701_priv {
+ /* Driver management */
+ struct drvmgr_dev *dev;
+ char prefix[16];
+
+ struct pci_bridge_regs *pcib;
+ struct amba_bridge_regs *ambab;
+
+ /* PCI */
+ pci_dev_t pcidev;
+ struct pci_dev_info *devinfo;
+
+ /* IRQ */
+ genirq_t genirq;
+ int interrupt_cnt;
+
+ /* GR-701 Address translation */
+ struct drvmgr_map_entry bus_maps_up[2];
+ struct drvmgr_map_entry bus_maps_down[2];
+
+ /* AMBA Plug&Play information on GR-701 */
+ struct ambapp_bus abus;
+ struct ambapp_mmap amba_maps[3];
+ struct ambapp_config config;
+};
+
+int ambapp_gr701_int_register(
+ struct drvmgr_dev *dev,
+ int irq,
+ const char *info,
+ drvmgr_isr handler,
+ void *arg);
+int ambapp_gr701_int_unregister(
+ struct drvmgr_dev *dev,
+ int irq,
+ drvmgr_isr isr,
+ void *arg);
+int ambapp_gr701_int_unmask(
+ struct drvmgr_dev *dev,
+ int irq);
+int ambapp_gr701_int_mask(
+ struct drvmgr_dev *dev,
+ int irq);
+int ambapp_gr701_int_clear(
+ struct drvmgr_dev *dev,
+ int irq);
+int ambapp_gr701_get_params(
+ struct drvmgr_dev *dev,
+ struct drvmgr_bus_params *params);
+
+struct ambapp_ops ambapp_gr701_ops = {
+ .int_register = ambapp_gr701_int_register,
+ .int_unregister = ambapp_gr701_int_unregister,
+ .int_unmask = ambapp_gr701_int_unmask,
+ .int_mask = ambapp_gr701_int_mask,
+ .int_clear = ambapp_gr701_int_clear,
+ .get_params = ambapp_gr701_get_params
+};
+
+struct drvmgr_drv_ops gr701_ops =
+{
+ .init = {gr701_init1, gr701_init2, NULL, NULL},
+ .remove = NULL,
+ .info = NULL
+};
+
+struct pci_dev_id_match gr701_ids[] =
+{
+ PCIID_DEVVEND(PCIID_VENDOR_GAISLER, PCIID_DEVICE_GR_701),
+ PCIID_END_TABLE /* Mark end of table */
+};
+
+struct pci_drv_info gr701_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_PCI_GAISLER_GR701_ID, /* Driver ID */
+ "GR-701_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_PCI, /* Bus Type */
+ &gr701_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ 0,
+ },
+ &gr701_ids[0]
+};
+
+/* Driver resources configuration for the AMBA bus on the GR-701 board.
+ * It is declared weak so that the user may override it from the project file,
+ * if the default settings are not enough.
+ *
+ * The configuration consists of an array of configuration pointers, each
+ * pointer determine the configuration of one GR-701 board. Pointer
+ * zero is for board0, pointer 1 for board1 and so on.
+ *
+ * The array must end with a NULL pointer.
+ */
+struct drvmgr_bus_res *gr701_resources[] __attribute__((weak)) =
+{
+ NULL
+};
+int gr701_resources_cnt = 0;
+
+void gr701_register_drv(void)
+{
+ DBG("Registering GR-701 PCI driver\n");
+ drvmgr_drv_register(&gr701_info.general);
+}
+
+void gr701_interrupt(void *arg)
+{
+ struct gr701_priv *priv = arg;
+ unsigned int status;
+ int irq = 0;
+
+ while ( (status=priv->pcib->istatus) != 0 ) {
+ priv->interrupt_cnt++; /* An interrupt was generated */
+ irq = status;
+ genirq_doirq(priv->genirq, irq);
+ /* ACK interrupt */
+ priv->pcib->istatus = 0;
+ }
+
+ /* ACK interrupt, this is because PCI is Level, so the IRQ Controller still drives the IRQ. */
+ if ( irq )
+ drvmgr_interrupt_clear(priv->dev, 0);
+}
+
+int gr701_hw_init(struct gr701_priv *priv)
+{
+ uint32_t com1;
+ struct pci_bridge_regs *pcib;
+ struct amba_bridge_regs *ambab;
+ int mst;
+ unsigned int pci_freq_hz;
+ pci_dev_t pcidev = priv->pcidev;
+ struct pci_dev_info *devinfo = priv->devinfo;
+
+ /* Set up PCI ==> AMBA */
+ priv->pcib = pcib = (void *)devinfo->resources[0].address;
+ pcib->bar0 = 0xfc000000;
+
+ /* Set up GR701 AMBA Masters connection to PCI */
+ priv->ambab = ambab = (struct amba_bridge_regs *)(
+ devinfo->resources[1].address + 0x400);
+
+ /* Init all msters, max 16 */
+ for (mst=0; mst<16; mst++) {
+ ambab->ambabars[mst] = 0x40000000;
+ if (READ_REG(&ambab->ambabars[mst]) != 0x40000000)
+ break;
+ }
+
+ /* Setup Address translation for AMBA bus, assume that PCI BAR
+ * are mapped 1:1 to CPU.
+ */
+
+ priv->amba_maps[0].size = 0x04000000;
+ priv->amba_maps[0].local_adr = devinfo->resources[1].address;
+ priv->amba_maps[0].remote_adr = 0xfc000000;
+
+ /* Mark end of table */
+ priv->amba_maps[1].size=0;
+ priv->amba_maps[1].local_adr = 0;
+ priv->amba_maps[1].remote_adr = 0;
+
+ /* Setup DOWN-streams address translation */
+ priv->bus_maps_down[0].name = "PCI BAR1 -> AMBA";
+ priv->bus_maps_down[0].size = priv->amba_maps[0].size;
+ priv->bus_maps_down[0].from_adr = (void *)devinfo->resources[1].address;
+ priv->bus_maps_down[0].to_adr = (void *)0xfc000000;
+
+ /* Setup UP-streams address translation */
+ priv->bus_maps_up[0].name = "AMBA PCIF Window";
+ priv->bus_maps_up[0].size = 0x10000000;
+ priv->bus_maps_up[0].from_adr = (void *)0xe0000000;
+ priv->bus_maps_up[0].to_adr = (void *)0x40000000;
+
+ /* Mark end of translation tables */
+ priv->bus_maps_down[1].size = 0;
+ priv->bus_maps_up[1].size = 0;
+
+ /* Enable I/O and Mem accesses */
+ pci_cfg_r32(pcidev, PCI_COMMAND, &com1);
+ com1 |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
+ pci_cfg_w32(pcidev, PCI_COMMAND, com1);
+
+ /* Start AMBA PnP scan at first AHB bus */
+ ambapp_scan(&priv->abus, devinfo->resources[1].address + 0x3f00000,
+ NULL, &priv->amba_maps[0]);
+
+ /* Frequency is the same as the PCI bus frequency */
+ drvmgr_freq_get(priv->dev, NULL, &pci_freq_hz);
+
+ /* Initialize Frequency of AMBA bus */
+ ambapp_freq_init(&priv->abus, NULL, pci_freq_hz);
+
+ /* Init IRQ controller (avoid IRQ generation) */
+ pcib->imask = 0x0000;
+ pcib->ipend = 0;
+ pcib->iclear = 0xffff;
+ pcib->iforce = 0;
+ pcib->ilevel = 0x0;
+
+ /* Successfully registered the GR-701 board */
+ return 0;
+}
+
+void gr701_hw_init2(struct gr701_priv *priv)
+{
+ /* Enable PCI Master (for DMA) */
+ pci_master_enable(priv->pcidev);
+}
+
+/* Called when a PCI target is found with the PCI device and vendor ID
+ * given in gr701_ids[].
+ */
+int gr701_init1(struct drvmgr_dev *dev)
+{
+ struct gr701_priv *priv;
+ struct pci_dev_info *devinfo;
+ uint32_t bar0, bar1, bar0_size, bar1_size;
+
+ priv = malloc(sizeof(struct gr701_priv));
+ if ( !priv )
+ return DRVMGR_NOMEM;
+
+ memset(priv, 0, sizeof(*priv));
+ dev->priv = priv;
+ priv->dev = dev;
+
+ /* Determine number of configurations */
+ if ( gr701_resources_cnt == 0 ) {
+ while ( gr701_resources[gr701_resources_cnt] )
+ gr701_resources_cnt++;
+ }
+
+ /* Generate Device prefix */
+
+ strcpy(priv->prefix, "/dev/gr701_0");
+ priv->prefix[11] += dev->minor_drv;
+ mkdir(priv->prefix, S_IRWXU | S_IRWXG | S_IRWXO);
+ priv->prefix[12] = '/';
+ priv->prefix[13] = '\0';
+
+ priv->devinfo = devinfo = (struct pci_dev_info *)dev->businfo;
+ priv->pcidev = devinfo->pcidev;
+ bar0 = devinfo->resources[0].address;
+ bar0_size = devinfo->resources[0].size;
+ bar1 = devinfo->resources[1].address;
+ bar1_size = devinfo->resources[1].size;
+ printf("\n\n--- GR-701[%d] ---\n", dev->minor_drv);
+ printf(" PCI BUS: 0x%x, SLOT: 0x%x, FUNCTION: 0x%x\n",
+ PCI_DEV_EXPAND(priv->pcidev));
+ printf(" PCI VENDOR: 0x%04x, DEVICE: 0x%04x\n\n\n",
+ devinfo->id.vendor, devinfo->id.device);
+ printf(" PCI BAR[0]: 0x%lx - 0x%lx\n", bar0, bar0 + bar0_size - 1);
+ printf(" PCI BAR[1]: 0x%lx - 0x%lx\n", bar1, bar1 + bar1_size - 1);
+ printf(" IRQ: %d\n\n\n", devinfo->irq);
+
+ /* all neccessary space assigned to GR-701 target? */
+ if ((bar0_size == 0) || (bar1_size == 0))
+ return DRVMGR_ENORES;
+
+ priv->genirq = genirq_init(16);
+ if ( priv->genirq == NULL ) {
+ free(priv);
+ dev->priv = NULL;
+ return DRVMGR_FAIL;
+ }
+
+ if ( gr701_hw_init(priv) ) {
+ genirq_destroy(priv->genirq);
+ free(priv);
+ dev->priv = NULL;
+ printf(" Failed to initialize GR-701 HW\n");
+ return DRVMGR_FAIL;
+ }
+
+ /* Init amba bus */
+ priv->config.abus = &priv->abus;
+ priv->config.ops = &ambapp_gr701_ops;
+ priv->config.maps_up = &priv->bus_maps_up[0];
+ priv->config.maps_down = &priv->bus_maps_down[0];
+ if ( priv->dev->minor_drv < gr701_resources_cnt ) {
+ priv->config.resources = gr701_resources[priv->dev->minor_drv];
+ } else {
+ priv->config.resources = NULL;
+ }
+
+ /* Create and register AMBA PnP bus. */
+ return ambapp_bus_register(dev, &priv->config);
+}
+
+/* Called when a PCI target is found with the PCI device and vendor ID
+ * given in gr701_ids[].
+ */
+int gr701_init2(struct drvmgr_dev *dev)
+{
+ struct gr701_priv *priv = dev->priv;
+
+ /* Clear any old interrupt requests */
+ drvmgr_interrupt_clear(dev, 0);
+
+ /* Enable System IRQ so that GR-701 PCI target interrupt goes through.
+ *
+ * It is important to enable it in stage init2. If interrupts were
+ * enabled in init1 this might hang the system when more than one PCI
+ * board is connected, this is because PCI interrupts might be shared
+ * and PCI target 2 have not initialized and might therefore drive
+ * interrupt already when entering init1().
+ */
+ drvmgr_interrupt_register(dev, 0, "gr701", gr701_interrupt, priv);
+
+ gr701_hw_init2(priv);
+
+ return DRVMGR_OK;
+}
+
+int ambapp_gr701_int_register(
+ struct drvmgr_dev *dev,
+ int irq,
+ const char *info,
+ drvmgr_isr handler,
+ void *arg)
+{
+ struct gr701_priv *priv = dev->parent->dev->priv;
+ rtems_interrupt_level level;
+ int status;
+
+ rtems_interrupt_disable(level);
+
+ status = genirq_register(priv->genirq, irq, handler, arg);
+ if ( status == 0 ) {
+ /* Clear IRQ for first registered handler */
+ priv->pcib->iclear = (1<<irq);
+ } else if ( status == 1 )
+ status = 0;
+
+ if (status != 0) {
+ rtems_interrupt_enable(level);
+ return DRVMGR_FAIL;
+ }
+
+ status = genirq_enable(priv->genirq, irq, handler, arg);
+ if ( status == 0 ) {
+ /* Enable IRQ for first enabled handler only */
+ priv->pcib->imask |= (1<<irq); /* unmask interrupt source */
+ } else if ( status == 1 )
+ status = DRVMGR_OK;
+
+ rtems_interrupt_enable(level);
+
+ return status;
+}
+
+int ambapp_gr701_int_unregister(
+ struct drvmgr_dev *dev,
+ int irq,
+ drvmgr_isr isr,
+ void *arg)
+{
+ struct gr701_priv *priv = dev->parent->dev->priv;
+ rtems_interrupt_level level;
+ int status;
+
+ rtems_interrupt_disable(level);
+
+ status = genirq_disable(priv->genirq, irq, isr, arg);
+ if ( status == 0 ) {
+ /* Disable IRQ only when no enabled handler exists */
+ priv->pcib->imask &= ~(1<<irq); /* mask interrupt source */
+ }
+
+ status = genirq_unregister(priv->genirq, irq, isr, arg);
+ if ( status != 0 )
+ status = DRVMGR_FAIL;
+
+ rtems_interrupt_enable(level);
+
+ return status;
+}
+
+int ambapp_gr701_int_unmask(
+ struct drvmgr_dev *dev,
+ int irq)
+{
+ struct gr701_priv *priv = dev->parent->dev->priv;
+ rtems_interrupt_level level;
+
+ DBG("GR-701 IRQ %d: enable\n", irq);
+
+ if ( genirq_check(priv->genirq, irq) )
+ return DRVMGR_FAIL;
+
+ rtems_interrupt_disable(level);
+
+ /* Enable IRQ */
+ priv->pcib->imask |= (1<<irq); /* unmask interrupt source */
+
+ rtems_interrupt_enable(level);
+
+ return DRVMGR_OK;
+}
+
+int ambapp_gr701_int_mask(
+ struct drvmgr_dev *dev,
+ int irq)
+{
+ struct gr701_priv *priv = dev->parent->dev->priv;
+ rtems_interrupt_level level;
+
+ DBG("GR-701 IRQ %d: disable\n", irq);
+
+ if ( genirq_check(priv->genirq, irq) )
+ return DRVMGR_FAIL;
+
+ rtems_interrupt_disable(level);
+
+ /* Disable IRQ */
+ priv->pcib->imask &= ~(1<<irq); /* mask interrupt source */
+
+ rtems_interrupt_enable(level);
+
+ return DRVMGR_OK;
+}
+
+int ambapp_gr701_int_clear(
+ struct drvmgr_dev *dev,
+ int irq)
+{
+ struct gr701_priv *priv = dev->parent->dev->priv;
+
+ if ( genirq_check(priv->genirq, irq) )
+ return DRVMGR_FAIL;
+
+ priv->pcib->iclear = (1<<irq);
+
+ return DRVMGR_OK;
+}
+
+int ambapp_gr701_get_params(struct drvmgr_dev *dev, struct drvmgr_bus_params *params)
+{
+ struct gr701_priv *priv = dev->parent->dev->priv;
+
+ /* Device name prefix pointer, skip /dev */
+ params->dev_prefix = &priv->prefix[5];
+
+ return 0;
+}
+
+void gr701_print_dev(struct drvmgr_dev *dev, int options)
+{
+ struct gr701_priv *priv = dev->priv;
+ struct pci_dev_info *devinfo = priv->devinfo;
+ unsigned int freq_hz;
+ uint32_t bar0, bar1, bar0_size, bar1_size;
+
+ /* Print */
+ printf("--- GR-701 [bus 0x%x, dev 0x%x, fun 0x%x] ---\n",
+ PCI_DEV_EXPAND(priv->pcidev));
+ bar0 = devinfo->resources[0].address;
+ bar0_size = devinfo->resources[0].size;
+ bar1 = devinfo->resources[1].address;
+ bar1_size = devinfo->resources[1].size;
+
+ printf(" PCI BAR[0]: 0x%lx - 0x%lx\n", bar0, bar0 + bar0_size - 1);
+ printf(" PCI BAR[1]: 0x%lx - 0x%lx\n", bar1, bar1 + bar1_size - 1);
+ printf(" IRQ: %d\n", devinfo->irq);
+
+ /* Frequency is the same as the PCI bus frequency */
+ drvmgr_freq_get(dev, 0, &freq_hz);
+
+ printf(" FREQ: %u Hz\n", freq_hz);
+ printf(" IMASK: 0x%08x\n", priv->pcib->imask);
+ printf(" IPEND: 0x%08x\n", priv->pcib->ipend);
+
+ /* Print amba config */
+ if ( options & GR701_OPTIONS_AMBA ) {
+ ambapp_print(&priv->abus, 10);
+ }
+
+#if 0
+ /* Print IRQ handlers and their arguments */
+ if ( options & GR701_OPTIONS_IRQ ) {
+ int i;
+ for(i=0; i<16; i++) {
+ printf(" IRQ[%02d]: 0x%x, arg: 0x%x\n",
+ i, (unsigned int)priv->isrs[i].handler, (unsigned int)priv->isrs[i].arg);
+ }
+ }
+#endif
+}
+
+void gr701_print(int options)
+{
+ struct pci_drv_info *drv = &gr701_info;
+ struct drvmgr_dev *dev;
+
+ dev = drv->general.dev;
+ while(dev) {
+ gr701_print_dev(dev, options);
+ dev = dev->next_in_drv;
+ }
+}
diff --git a/c/src/lib/libbsp/sparc/shared/pci/gr_rasta_adcdac.c b/c/src/lib/libbsp/sparc/shared/pci/gr_rasta_adcdac.c
new file mode 100644
index 0000000000..163ccfb98c
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/pci/gr_rasta_adcdac.c
@@ -0,0 +1,671 @@
+/* GR-RASTA-ADCDAC PCI Target driver.
+ *
+ * COPYRIGHT (c) 2008.
+ * Aeroflex Gaisler AB.
+ *
+ * Configures the GR-RASTA-ADCDAC interface PCI board.
+ * This driver provides a AMBA PnP bus by using the general part
+ * of the AMBA PnP bus driver (ambapp_bus.c).
+ *
+ * Driver resources for the AMBA PnP bus provided can be set using
+ * gr_rasta_adcdac_set_resources().
+ *
+ * The license and distribution terms for this file may be
+ * found in found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2008-12-05, Daniel Hellstrom <daniel@gaisler.com>
+ * Created
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <bsp.h>
+#include <rtems/bspIo.h>
+#include <pci.h>
+
+#include <ambapp.h>
+#include <grlib.h>
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+#include <drvmgr/pci_bus.h>
+#include <genirq.h>
+
+#include <gr_rasta_adcdac.h>
+
+/*#define DEBUG 1*/
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+/* Determines which PCI address the AHB masters will access, it should be
+ * set so that the masters can access the CPU RAM. Default is base of CPU RAM,
+ * CPU RAM is mapped 1:1 to PCI space.
+ */
+extern unsigned int _RAM_START;
+#define AHBMST2PCIADR (((unsigned int)&_RAM_START) & 0xf0000000)
+
+/* PCI ID */
+#define PCIID_VENDOR_GAISLER 0x1AC8
+#define PCIID_DEVICE_GR_RASTA_ADCDAC 0x0014
+
+int gr_rasta_adcdac_init1(struct drvmgr_dev *dev);
+int gr_rasta_adcdac_init2(struct drvmgr_dev *dev);
+
+struct grpci_regs {
+ volatile unsigned int cfg_stat;
+ volatile unsigned int bar0;
+ volatile unsigned int page0;
+ volatile unsigned int bar1;
+ volatile unsigned int page1;
+ volatile unsigned int iomap;
+ volatile unsigned int stat_cmd;
+};
+
+struct gr_rasta_adcdac_ver {
+ const unsigned int amba_freq_hz; /* The frequency */
+ const unsigned int amba_ioarea; /* The address where the PnP IOAREA starts at */
+};
+
+/* Private data structure for driver */
+struct gr_rasta_adcdac_priv {
+ /* Driver management */
+ struct drvmgr_dev *dev;
+ char prefix[20];
+
+ /* PCI */
+ pci_dev_t pcidev;
+ struct pci_dev_info *devinfo;
+ uint32_t ahbmst2pci_map;
+
+ /* IRQ */
+ genirq_t genirq;
+
+ /* GR-RASTA-ADCDAC */
+ struct gr_rasta_adcdac_ver *version;
+ struct irqmp_regs *irq;
+ struct grpci_regs *grpci;
+ struct drvmgr_map_entry bus_maps_down[3];
+ struct drvmgr_map_entry bus_maps_up[2];
+
+ /* AMBA Plug&Play information on GR-RASTA-ADCDAC */
+ struct ambapp_bus abus;
+ struct ambapp_mmap amba_maps[4];
+ struct ambapp_config config;
+};
+
+struct gr_rasta_adcdac_ver gr_rasta_adcdac_ver0 = {
+ .amba_freq_hz = 50000000,
+ .amba_ioarea = 0x80100000,
+};
+
+int ambapp_rasta_adcdac_int_register(
+ struct drvmgr_dev *dev,
+ int irq,
+ const char *info,
+ drvmgr_isr handler,
+ void *arg);
+int ambapp_rasta_adcdac_int_unregister(
+ struct drvmgr_dev *dev,
+ int irq,
+ drvmgr_isr isr,
+ void *arg);
+int ambapp_rasta_adcdac_int_unmask(
+ struct drvmgr_dev *dev,
+ int irq);
+int ambapp_rasta_adcdac_int_mask(
+ struct drvmgr_dev *dev,
+ int irq);
+int ambapp_rasta_adcdac_int_clear(
+ struct drvmgr_dev *dev,
+ int irq);
+int ambapp_rasta_adcdac_get_params(
+ struct drvmgr_dev *dev,
+ struct drvmgr_bus_params *params);
+
+struct ambapp_ops ambapp_rasta_adcdac_ops = {
+ .int_register = ambapp_rasta_adcdac_int_register,
+ .int_unregister = ambapp_rasta_adcdac_int_unregister,
+ .int_unmask = ambapp_rasta_adcdac_int_unmask,
+ .int_mask = ambapp_rasta_adcdac_int_mask,
+ .int_clear = ambapp_rasta_adcdac_int_clear,
+ .get_params = ambapp_rasta_adcdac_get_params
+};
+
+struct drvmgr_drv_ops gr_rasta_adcdac_ops =
+{ .init = {gr_rasta_adcdac_init1, gr_rasta_adcdac_init2, NULL, NULL},
+ .remove = NULL,
+ .info = NULL
+};
+
+struct pci_dev_id_match gr_rasta_adcdac_ids[] =
+{
+ PCIID_DEVVEND(PCIID_VENDOR_GAISLER, PCIID_DEVICE_GR_RASTA_ADCDAC),
+ PCIID_END_TABLE /* Mark end of table */
+};
+
+struct pci_drv_info gr_rasta_adcdac_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_PCI_GAISLER_RASTAADCDAC_ID,/* Driver ID */
+ "GR-RASTA-ADCDAC_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_PCI, /* Bus Type */
+ &gr_rasta_adcdac_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ 0,
+ },
+ &gr_rasta_adcdac_ids[0]
+};
+
+/* Driver resources configuration for the AMBA bus on the GR-RASTA-ADCDAC board.
+ * It is declared weak so that the user may override it from the project file,
+ * if the default settings are not enough.
+ *
+ * The configuration consists of an array of configuration pointers, each
+ * pointer determine the configuration of one GR-RASTA-ADCDAC board. Pointer
+ * zero is for board0, pointer 1 for board1 and so on.
+ *
+ * The array must end with a NULL pointer.
+ */
+struct drvmgr_bus_res *gr_rasta_adcdac_resources[] __attribute__((weak)) =
+{
+ NULL
+};
+int gr_rasta_adcdac_resources_cnt = 0;
+
+void gr_rasta_adcdac_register_drv(void)
+{
+ DBG("Registering GR-RASTA-ADCDAC PCI driver\n");
+ drvmgr_drv_register(&gr_rasta_adcdac_info.general);
+}
+
+void gr_rasta_adcdac_isr (void *arg)
+{
+ struct gr_rasta_adcdac_priv *priv = arg;
+ unsigned int status, tmp;
+ int irq;
+ tmp = status = priv->irq->ipend;
+
+ /* DBG("GR-RASTA-ADCDAC: IRQ 0x%x\n",status); */
+
+ for(irq=0; irq<16; irq++) {
+ if ( status & (1<<irq) ) {
+ genirq_doirq(priv->genirq, irq);
+ priv->irq->iclear = (1<<irq);
+ status &= ~(1<<irq);
+ if ( status == 0 )
+ break;
+ }
+ }
+
+ /* ACK interrupt, this is because PCI is Level, so the IRQ Controller still drives the IRQ. */
+ if ( tmp )
+ drvmgr_interrupt_clear(priv->dev, 0);
+
+ DBG("RASTA-ADCDAC-IRQ: 0x%x\n", tmp);
+}
+
+int gr_rasta_adcdac_hw_init1(struct gr_rasta_adcdac_priv *priv)
+{
+ uint32_t data;
+ unsigned int *page0 = NULL;
+ struct ambapp_dev *tmp;
+ int status;
+ struct ambapp_ahb_info *ahb;
+ struct pci_dev_info *devinfo = priv->devinfo;
+ uint32_t bar0, bar0_size;
+
+ /* Select version of GR-RASTA-ADCDAC board */
+ switch (devinfo->rev) {
+ case 0:
+ priv->version = &gr_rasta_adcdac_ver0;
+ break;
+ default:
+ return -2;
+ }
+
+ bar0 = devinfo->resources[0].address;
+ bar0_size = devinfo->resources[0].size;
+ page0 = (unsigned int *)(bar0 + bar0_size/2);
+
+ /* Point PAGE0 to start of Plug and Play information */
+ *page0 = priv->version->amba_ioarea & 0xf0000000;
+
+ /* set parity error response */
+ pci_cfg_r32(priv->pcidev, PCI_COMMAND, &data);
+ pci_cfg_w32(priv->pcidev, PCI_COMMAND, (data|PCI_COMMAND_PARITY));
+
+ /* Setup cache line size. Default cache line size will result in
+ * poor performance (256 word fetches), 0xff will set it according
+ * to the max size of the PCI FIFO.
+ */
+ pci_cfg_w8(priv->pcidev, PCI_CACHE_LINE_SIZE, 0xff);
+
+ /* Scan AMBA Plug&Play */
+
+ /* AMBA MAP bar0 (in CPU) ==> 0x80000000(remote amba address) */
+ priv->amba_maps[0].size = bar0_size/2;
+ priv->amba_maps[0].local_adr = bar0;
+ priv->amba_maps[0].remote_adr = 0x80000000;
+
+ /* AMBA MAP bar1 (in CPU) ==> 0x40000000(remote amba address) */
+ priv->amba_maps[1].size = devinfo->resources[1].size;
+ priv->amba_maps[1].local_adr = devinfo->resources[1].address;
+ priv->amba_maps[1].remote_adr = 0x40000000;
+
+ /* Addresses not matching with map be untouched */
+ priv->amba_maps[2].size = 0xfffffff0;
+ priv->amba_maps[2].local_adr = 0;
+ priv->amba_maps[2].remote_adr = 0;
+
+ /* Mark end of table */
+ priv->amba_maps[3].size=0;
+ priv->amba_maps[3].local_adr = 0;
+ priv->amba_maps[3].remote_adr = 0;
+
+ /* Start AMBA PnP scan at first AHB bus */
+ /*ambapp_scan(priv->bar0 + (priv->version->amba_ioarea & ~0xf0000000),
+ NULL, &priv->amba_maps[0], NULL, &priv->abus.root, NULL);*/
+ ambapp_scan(&priv->abus,
+ bar0 + (priv->version->amba_ioarea & ~0xf0000000),
+ NULL, &priv->amba_maps[0]);
+
+ /* Initialize Frequency of AMBA bus */
+ ambapp_freq_init(&priv->abus, NULL, priv->version->amba_freq_hz);
+
+ /* Point PAGE0 to start of APB area */
+ *page0 = 0x80000000;
+
+ /* Find GRPCI controller */
+ tmp = (void *)ambapp_for_each(&priv->abus,
+ (OPTIONS_ALL|OPTIONS_APB_SLVS),
+ VENDOR_GAISLER, GAISLER_PCIFBRG,
+ ambapp_find_by_idx, NULL);
+ if ( !tmp ) {
+ return -3;
+ }
+ priv->grpci = (struct grpci_regs *)((struct ambapp_apb_info *)tmp->devinfo)->start;
+
+ /* Set GRPCI mmap so that AMBA masters can access CPU-RAM over
+ * the PCI window.
+ */
+ priv->grpci->cfg_stat = (priv->grpci->cfg_stat & 0x0fffffff) |
+ (priv->ahbmst2pci_map & 0xf0000000);
+ priv->grpci->page1 = 0x40000000;
+
+ /* Find IRQ controller */
+ tmp = (void *)ambapp_for_each(&priv->abus,
+ (OPTIONS_ALL|OPTIONS_APB_SLVS),
+ VENDOR_GAISLER, GAISLER_IRQMP,
+ ambapp_find_by_idx, NULL);
+ if ( !tmp ) {
+ return -4;
+ }
+ priv->irq = (struct irqmp_regs *)DEV_TO_APB(tmp)->start;
+ /* Set up GR-RASTA-ADCDAC irq controller */
+ priv->irq->iclear = 0xffff;
+ priv->irq->ilevel = 0;
+ priv->irq->mask[0] = 0;
+
+ /* DOWN streams translation table */
+ priv->bus_maps_down[0].name = "PCI BAR0 -> AMBA";
+ priv->bus_maps_down[0].size = priv->amba_maps[0].size;
+ priv->bus_maps_down[0].from_adr = (void *)priv->amba_maps[0].local_adr;
+ priv->bus_maps_down[0].to_adr = (void *)priv->amba_maps[0].remote_adr;
+
+ priv->bus_maps_down[1].name = "PCI BAR1 -> AMBA";
+ priv->bus_maps_down[1].size = priv->amba_maps[1].size;
+ priv->bus_maps_down[1].from_adr = (void *)priv->amba_maps[1].local_adr;
+ priv->bus_maps_down[1].to_adr = (void *)priv->amba_maps[1].remote_adr;
+
+ /* Mark end of translation table */
+ priv->bus_maps_down[2].size = 0;
+
+ /* Find GRPCI controller AHB Slave interface */
+ tmp = (void *)ambapp_for_each(&priv->abus,
+ (OPTIONS_ALL|OPTIONS_AHB_SLVS),
+ VENDOR_GAISLER, GAISLER_PCIFBRG,
+ ambapp_find_by_idx, NULL);
+ if ( !tmp ) {
+ return -5;
+ }
+ ahb = (struct ambapp_ahb_info *)tmp->devinfo;
+
+ /* UP streams translation table */
+ priv->bus_maps_up[0].name = "AMBA GRPCI Window";
+ priv->bus_maps_up[0].size = ahb->mask[0]; /* AMBA->PCI Window on GR-RASTA-ADCDAC board */
+ priv->bus_maps_up[0].from_adr = (void *)ahb->start[0];
+ priv->bus_maps_up[0].to_adr = (void *)
+ (priv->ahbmst2pci_map & 0xf0000000);
+
+ /* Mark end of translation table */
+ priv->bus_maps_up[1].size = 0;
+
+ /* Successfully registered the RASTA board */
+ return 0;
+}
+
+int gr_rasta_adcdac_hw_init2(struct gr_rasta_adcdac_priv *priv)
+{
+ /* Enable DMA by enabling PCI target as master */
+ pci_master_enable(priv->pcidev);
+
+ return DRVMGR_OK;
+}
+
+/* Called when a PCI target is found with the PCI device and vendor ID
+ * given in gr_rasta_adcdac_ids[].
+ */
+int gr_rasta_adcdac_init1(struct drvmgr_dev *dev)
+{
+ struct gr_rasta_adcdac_priv *priv;
+ struct pci_dev_info *devinfo;
+ int status;
+ uint32_t bar0, bar1, bar0_size, bar1_size;
+ union drvmgr_key_value *value;
+
+ priv = malloc(sizeof(struct gr_rasta_adcdac_priv));
+ if ( !priv )
+ return DRVMGR_NOMEM;
+
+ memset(priv, 0, sizeof(*priv));
+ dev->priv = priv;
+ priv->dev = dev;
+
+ /* Determine number of configurations */
+ if ( gr_rasta_adcdac_resources_cnt == 0 ) {
+ while ( gr_rasta_adcdac_resources[gr_rasta_adcdac_resources_cnt] )
+ gr_rasta_adcdac_resources_cnt++;
+ }
+
+ /* Generate Device prefix */
+
+ strcpy(priv->prefix, "/dev/rastaadcdac0");
+ priv->prefix[16] += dev->minor_drv;
+ mkdir(priv->prefix, S_IRWXU | S_IRWXG | S_IRWXO);
+ priv->prefix[17] = '/';
+ priv->prefix[18] = '\0';
+
+ priv->devinfo = devinfo = (struct pci_dev_info *)dev->businfo;
+ priv->pcidev = devinfo->pcidev;
+ bar0 = devinfo->resources[0].address;
+ bar0_size = devinfo->resources[0].size;
+ bar1 = devinfo->resources[1].address;
+ bar1_size = devinfo->resources[1].size;
+ printf("\n\n--- GR-RASTA-ADCDAC[%d] ---\n", dev->minor_drv);
+ printf(" PCI BUS: 0x%x, SLOT: 0x%x, FUNCTION: 0x%x\n",
+ PCI_DEV_EXPAND(priv->pcidev));
+ printf(" PCI VENDOR: 0x%04x, DEVICE: 0x%04x\n",
+ devinfo->id.vendor, devinfo->id.device);
+ printf(" PCI BAR[0]: 0x%lx - 0x%lx\n", bar0, bar0 + bar0_size - 1);
+ printf(" PCI BAR[1]: 0x%lx - 0x%lx\n", bar1, bar1 + bar1_size - 1);
+ printf(" IRQ: %d\n\n\n", devinfo->irq);
+
+ /* all neccessary space assigned to GR-RASTA-ADCDAC target? */
+ if ((bar0_size == 0) || (bar1_size == 0))
+ return DRVMGR_ENORES;
+
+ /* Let user override which PCI address the AHB masters of the
+ * RASTA-ADCDAC board access when doing DMA to CPU RAM. The AHB masters
+ * access the PCI Window of the AMBA bus, the MSB 4-bits of that address
+ * is translated according this config option before the address
+ * goes out on the PCI bus.
+ * Only the 4 MSB bits have an effect;
+ */
+ value = drvmgr_dev_key_get(priv->dev, "ahbmst2pci", KEY_TYPE_INT);
+ if (value)
+ priv->ahbmst2pci_map = value->i;
+ else
+ priv->ahbmst2pci_map = AHBMST2PCIADR; /* default */
+
+ priv->genirq = genirq_init(16);
+ if ( priv->genirq == NULL ) {
+ free(priv);
+ dev->priv = NULL;
+ return DRVMGR_FAIL;
+ }
+
+ if ( (status = gr_rasta_adcdac_hw_init1(priv)) != 0 ) {
+ genirq_destroy(priv->genirq);
+ free(priv);
+ dev->priv = NULL;
+ printf(" Failed to initialize GR-RASTA-ADCDAC HW: %d\n", status);
+ return DRVMGR_FAIL;
+ }
+
+ /* Init amba bus */
+ priv->config.abus = &priv->abus;
+ priv->config.ops = &ambapp_rasta_adcdac_ops;
+ priv->config.maps_up = &priv->bus_maps_up[0];
+ priv->config.maps_down = &priv->bus_maps_down[0];
+ if ( priv->dev->minor_drv < gr_rasta_adcdac_resources_cnt ) {
+ priv->config.resources = gr_rasta_adcdac_resources[priv->dev->minor_drv];
+ } else {
+ priv->config.resources = NULL;
+ }
+
+ /* Create and register AMBA PnP bus. */
+ return ambapp_bus_register(dev, &priv->config);
+}
+
+int gr_rasta_adcdac_init2(struct drvmgr_dev *dev)
+{
+ struct gr_rasta_adcdac_priv *priv = dev->priv;
+
+ /* Clear any old interrupt requests */
+ drvmgr_interrupt_clear(dev, 0);
+
+ /* Enable System IRQ so that GR-RASTA-ADCDAC PCI target interrupt
+ * goes through.
+ *
+ * It is important to enable it in stage init2. If interrupts were
+ * enabled in init1 this might hang the system when more than one
+ * PCI board is connected, this is because PCI interrupts might
+ * be shared and PCI board 2 have not initialized and might
+ * therefore drive interrupt already when entering init1().
+ */
+ drvmgr_interrupt_register(
+ dev,
+ 0,
+ "gr_rasta_adcdac",
+ gr_rasta_adcdac_isr,
+ (void *)priv);
+
+ return gr_rasta_adcdac_hw_init2(priv);
+}
+
+int ambapp_rasta_adcdac_int_register(
+ struct drvmgr_dev *dev,
+ int irq,
+ const char *info,
+ drvmgr_isr handler,
+ void *arg)
+{
+ struct gr_rasta_adcdac_priv *priv = dev->parent->dev->priv;
+ rtems_interrupt_level level;
+ int status;
+
+ rtems_interrupt_disable(level);
+
+ status = genirq_register(priv->genirq, irq, handler, arg);
+ if ( status == 0 ) {
+ /* Clear IRQ for first registered handler */
+ priv->irq->iclear = (1<<irq);
+ } else if ( status == 1 )
+ status = 0;
+
+ if (status != 0) {
+ rtems_interrupt_enable(level);
+ return DRVMGR_FAIL;
+ }
+
+ status = genirq_enable(priv->genirq, irq, handler, arg);
+ if ( status == 0 ) {
+ /* Enable IRQ for first enabled handler only */
+ priv->irq->mask[0] |= (1<<irq); /* unmask interrupt source */
+ } else if ( status == 1 )
+ status = 0;
+
+ rtems_interrupt_enable(level);
+
+ return status;
+}
+
+int ambapp_rasta_adcdac_int_unregister(
+ struct drvmgr_dev *dev,
+ int irq,
+ drvmgr_isr isr,
+ void *arg)
+{
+ struct gr_rasta_adcdac_priv *priv = dev->parent->dev->priv;
+ rtems_interrupt_level level;
+ int status;
+
+ rtems_interrupt_disable(level);
+
+ status = genirq_disable(priv->genirq, irq, isr, arg);
+ if ( status == 0 ) {
+ /* Disable IRQ only when no enabled handler exists */
+ priv->irq->mask[0] &= ~(1<<irq); /* mask interrupt source */
+ }
+
+ status = genirq_unregister(priv->genirq, irq, isr, arg);
+ if ( status != 0 )
+ status = DRVMGR_FAIL;
+
+ rtems_interrupt_enable(level);
+
+ return status;
+}
+
+int ambapp_rasta_adcdac_int_unmask(
+ struct drvmgr_dev *dev,
+ int irq)
+{
+ struct gr_rasta_adcdac_priv *priv = dev->parent->dev->priv;
+ rtems_interrupt_level level;
+
+ DBG("RASTA-ADCDAC IRQ %d: unmask\n", irq);
+
+ if ( genirq_check(priv->genirq, irq) )
+ return DRVMGR_EINVAL;
+
+ rtems_interrupt_disable(level);
+
+ /* Enable IRQ for first enabled handler only */
+ priv->irq->mask[0] |= (1<<irq); /* unmask interrupt source */
+
+ rtems_interrupt_enable(level);
+
+ return DRVMGR_OK;
+}
+
+int ambapp_rasta_adcdac_int_mask(
+ struct drvmgr_dev *dev,
+ int irq)
+{
+ struct gr_rasta_adcdac_priv *priv = dev->parent->dev->priv;
+ rtems_interrupt_level level;
+
+ DBG("RASTA-ADCDAC IRQ %d: mask\n", irq);
+
+ if ( genirq_check(priv->genirq, irq) )
+ return DRVMGR_EINVAL;
+
+ rtems_interrupt_disable(level);
+
+ /* Disable/mask IRQ */
+ priv->irq->mask[0] &= ~(1<<irq); /* mask interrupt source */
+
+ rtems_interrupt_enable(level);
+
+ return DRVMGR_OK;
+}
+
+int ambapp_rasta_adcdac_int_clear(
+ struct drvmgr_dev *dev,
+ int irq)
+{
+ struct gr_rasta_adcdac_priv *priv = dev->parent->dev->priv;
+
+ if ( genirq_check(priv->genirq, irq) )
+ return DRVMGR_FAIL;
+
+ priv->irq->iclear = (1<<irq);
+
+ return DRVMGR_OK;
+}
+
+int ambapp_rasta_adcdac_get_params(struct drvmgr_dev *dev, struct drvmgr_bus_params *params)
+{
+ struct gr_rasta_adcdac_priv *priv = dev->parent->dev->priv;
+
+ /* Device name prefix pointer, skip /dev */
+ params->dev_prefix = &priv->prefix[5];
+
+ return 0;
+}
+
+void gr_rasta_adcdac_print_dev(struct drvmgr_dev *dev, int options)
+{
+ struct gr_rasta_adcdac_priv *priv = dev->priv;
+ struct pci_dev_info *devinfo = priv->devinfo;
+ uint32_t bar0, bar1, bar0_size, bar1_size;
+
+ /* Print */
+ printf("--- GR-RASTA-ADCDAC [bus 0x%x, dev 0x%x, fun 0x%x] ---\n",
+ PCI_DEV_EXPAND(priv->pcidev));
+
+ bar0 = devinfo->resources[0].address;
+ bar0_size = devinfo->resources[0].size;
+ bar1 = devinfo->resources[1].address;
+ bar1_size = devinfo->resources[1].size;
+
+ printf(" PCI BAR[0]: 0x%lx - 0x%lx\n", bar0, bar0 + bar0_size - 1);
+ printf(" PCI BAR[1]: 0x%lx - 0x%lx\n", bar1, bar1 + bar1_size - 1);
+ printf(" IRQ REGS: 0x%x\n", (unsigned int)priv->irq);
+ printf(" IRQ: %d\n", devinfo->irq);
+ printf(" PCI REVISION: %d\n", devinfo->rev);
+ printf(" FREQ: %d Hz\n", priv->version->amba_freq_hz);
+ printf(" IMASK: 0x%08x\n", priv->irq->mask[0]);
+ printf(" IPEND: 0x%08x\n", priv->irq->ipend);
+
+ /* Print amba config */
+ if ( options & RASTA_ADCDAC_OPTIONS_AMBA ) {
+ ambapp_print(&priv->abus, 10);
+ }
+#if 0
+ /* Print IRQ handlers and their arguments */
+ if ( options & RASTA_ADCDAC_OPTIONS_IRQ ) {
+ int i;
+ for(i=0; i<16; i++) {
+ printf(" IRQ[%02d]: 0x%x, arg: 0x%x\n",
+ i, (unsigned int)priv->isrs[i].handler, (unsigned int)priv->isrs[i].arg);
+ }
+ }
+#endif
+}
+
+void gr_rasta_adcdac_print(int options)
+{
+ struct pci_drv_info *drv = &gr_rasta_adcdac_info;
+ struct drvmgr_dev *dev;
+
+ dev = drv->general.dev;
+ while(dev) {
+ gr_rasta_adcdac_print_dev(dev, options);
+ dev = dev->next_in_drv;
+ }
+}
diff --git a/c/src/lib/libbsp/sparc/shared/pci/gr_rasta_io.c b/c/src/lib/libbsp/sparc/shared/pci/gr_rasta_io.c
new file mode 100644
index 0000000000..071636ba45
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/pci/gr_rasta_io.c
@@ -0,0 +1,688 @@
+/* GR-RASTA-IO PCI Target driver.
+ *
+ * COPYRIGHT (c) 2008.
+ * Aeroflex Gaisler AB.
+ *
+ * Configures the GR-RASTA-IO interface PCI board.
+ * This driver provides a AMBA PnP bus by using the general part
+ * of the AMBA PnP bus driver (ambapp_bus.c).
+ *
+ * Driver resources for the AMBA PnP bus provided can be set using
+ * gr_rasta_io_set_resources().
+ *
+ * The license and distribution terms for this file may be
+ * found in found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2008-12-05, Daniel Hellstrom <daniel@gaisler.com>
+ * Created
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <bsp.h>
+#include <rtems/bspIo.h>
+#include <pci.h>
+
+#include <ambapp.h>
+#include <grlib.h>
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+#include <drvmgr/pci_bus.h>
+#include <genirq.h>
+
+#include <gr_rasta_io.h>
+
+/* Determines which PCI address the AHB masters will access, it should be
+ * set so that the masters can access the CPU RAM. Default is base of CPU RAM,
+ * CPU RAM is mapped 1:1 to PCI space.
+ */
+extern unsigned int _RAM_START;
+#define AHBMST2PCIADR (((unsigned int)&_RAM_START) & 0xf0000000)
+
+/* Offset from 0x80000000 (dual bus version) */
+#define AHB1_BASE_ADDR 0x80000000
+#define AHB1_IOAREA_BASE_ADDR 0x80100000
+
+/* #define DEBUG 1 */
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+/* PCI ID */
+#define PCIID_VENDOR_GAISLER 0x1AC8
+
+int gr_rasta_io_init1(struct drvmgr_dev *dev);
+int gr_rasta_io_init2(struct drvmgr_dev *dev);
+
+struct grpci_regs {
+ volatile unsigned int cfg_stat;
+ volatile unsigned int bar0;
+ volatile unsigned int page0;
+ volatile unsigned int bar1;
+ volatile unsigned int page1;
+ volatile unsigned int iomap;
+ volatile unsigned int stat_cmd;
+};
+
+struct gr_rasta_io_ver {
+ const unsigned int amba_freq_hz; /* The frequency */
+ const unsigned int amba_ioarea; /* The address where the PnP IOAREA starts at */
+};
+
+/* Private data structure for driver */
+struct gr_rasta_io_priv {
+ /* Driver management */
+ struct drvmgr_dev *dev;
+ char prefix[16];
+
+ /* PCI */
+ pci_dev_t pcidev;
+ struct pci_dev_info *devinfo;
+ uint32_t ahbmst2pci_map;
+
+ /* IRQ */
+ genirq_t genirq;
+
+ /* GR-RASTA-IO */
+ struct gr_rasta_io_ver *version;
+ struct irqmp_regs *irq;
+ struct grpci_regs *grpci;
+ struct drvmgr_map_entry bus_maps_down[3];
+ struct drvmgr_map_entry bus_maps_up[2];
+
+ /* AMBA Plug&Play information on GR-RASTA-IO */
+ struct ambapp_bus abus;
+ struct ambapp_mmap amba_maps[4];
+ struct ambapp_config config;
+};
+
+struct gr_rasta_io_ver gr_rasta_io_ver0 = {
+ .amba_freq_hz = 30000000,
+ .amba_ioarea = 0x80100000,
+};
+
+struct gr_rasta_io_ver gr_rasta_io_ver1 = {
+ .amba_freq_hz = 50000000,
+ .amba_ioarea = 0x80100000,
+};
+
+int ambapp_rasta_io_int_register(
+ struct drvmgr_dev *dev,
+ int irq,
+ const char *info,
+ drvmgr_isr handler,
+ void *arg);
+int ambapp_rasta_io_int_unregister(
+ struct drvmgr_dev *dev,
+ int irq,
+ drvmgr_isr handler,
+ void *arg);
+int ambapp_rasta_io_int_unmask(
+ struct drvmgr_dev *dev,
+ int irq);
+int ambapp_rasta_io_int_mask(
+ struct drvmgr_dev *dev,
+ int irq);
+int ambapp_rasta_io_int_clear(
+ struct drvmgr_dev *dev,
+ int irq);
+int ambapp_rasta_io_get_params(
+ struct drvmgr_dev *dev,
+ struct drvmgr_bus_params *params);
+
+struct ambapp_ops ambapp_rasta_io_ops = {
+ .int_register = ambapp_rasta_io_int_register,
+ .int_unregister = ambapp_rasta_io_int_unregister,
+ .int_unmask = ambapp_rasta_io_int_unmask,
+ .int_mask = ambapp_rasta_io_int_mask,
+ .int_clear = ambapp_rasta_io_int_clear,
+ .get_params = ambapp_rasta_io_get_params
+};
+
+struct drvmgr_drv_ops gr_rasta_io_ops =
+{
+ .init = {gr_rasta_io_init1, gr_rasta_io_init2, NULL, NULL},
+ .remove = NULL,
+ .info = NULL
+};
+
+struct pci_dev_id_match gr_rasta_io_ids[] =
+{
+ PCIID_DEVVEND(PCIID_VENDOR_GAISLER, PCIID_DEVICE_GR_RASTA_IO),
+ PCIID_DEVVEND(PCIID_VENDOR_GAISLER_OLD, PCIID_DEVICE_GR_RASTA_IO_OLD),
+ PCIID_END_TABLE /* Mark end of table */
+};
+
+struct pci_drv_info gr_rasta_io_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_PCI_GAISLER_RASTAIO_ID, /* Driver ID */
+ "GR-RASTA-IO_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_PCI, /* Bus Type */
+ &gr_rasta_io_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ 0,
+ },
+ &gr_rasta_io_ids[0]
+};
+
+/* Driver resources configuration for the AMBA bus on the GR-RASTA-IO board.
+ * It is declared weak so that the user may override it from the project file,
+ * if the default settings are not enough.
+ *
+ * The configuration consists of an array of configuration pointers, each
+ * pointer determine the configuration of one GR-RASTA-IO board. Pointer
+ * zero is for board0, pointer 1 for board1 and so on.
+ *
+ * The array must end with a NULL pointer.
+ */
+struct drvmgr_bus_res *gr_rasta_io_resources[] __attribute__((weak)) =
+{
+ NULL
+};
+int gr_rasta_io_resources_cnt = 0;
+
+void gr_rasta_io_register_drv(void)
+{
+ DBG("Registering GR-RASTA-IO PCI driver\n");
+ drvmgr_drv_register(&gr_rasta_io_info.general);
+}
+
+void gr_rasta_io_isr (void *arg)
+{
+ struct gr_rasta_io_priv *priv = arg;
+ unsigned int status, tmp;
+ int irq;
+ tmp = status = priv->irq->ipend;
+
+ /* DBG("GR-RASTA-IO: IRQ 0x%x\n",status); */
+
+ for(irq=0; irq<16; irq++) {
+ if ( status & (1<<irq) ) {
+ genirq_doirq(priv->genirq, irq);
+ priv->irq->iclear = (1<<irq);
+ status &= ~(1<<irq);
+ if ( status == 0 )
+ break;
+ }
+ }
+
+ /* ACK interrupt, this is because PCI is Level, so the IRQ Controller still drives the IRQ. */
+ if ( tmp )
+ drvmgr_interrupt_clear(priv->dev, 0);
+
+ DBG("RASTA-IO-IRQ: 0x%x\n", tmp);
+}
+
+int gr_rasta_io_hw_init(struct gr_rasta_io_priv *priv)
+{
+ unsigned int *page0 = NULL;
+ struct ambapp_dev *tmp;
+ int status;
+ struct ambapp_ahb_info *ahb;
+ struct pci_dev_info *devinfo = priv->devinfo;
+ uint32_t bar0, bar0_size;
+
+ /* Select version of GR-RASTA-IO board */
+ switch (devinfo->rev) {
+ case 0:
+ priv->version = &gr_rasta_io_ver0;
+ break;
+ case 1:
+ priv->version = &gr_rasta_io_ver1;
+ break;
+ default:
+ return -2;
+ }
+
+ bar0 = devinfo->resources[0].address;
+ bar0_size = devinfo->resources[0].size;
+ page0 = (unsigned int *)(bar0 + bar0_size/2);
+
+ /* Point PAGE0 to start of Plug and Play information */
+ *page0 = priv->version->amba_ioarea & 0xf0000000;
+
+#if 0
+ {
+ uint32_t data;
+ /* set parity error response */
+ pci_cfg_r32(priv->pcidev, PCI_COMMAND, &data);
+ pci_cfg_w32(priv->pcidev, PCI_COMMAND, (data|PCI_COMMAND_PARITY));
+ }
+#endif
+
+ /* Setup cache line size. Default cache line size will result in
+ * poor performance (256 word fetches), 0xff will set it according
+ * to the max size of the PCI FIFO.
+ */
+ pci_cfg_w8(priv->pcidev, PCI_CACHE_LINE_SIZE, 0xff);
+
+ /* Scan AMBA Plug&Play */
+
+ /* AMBA MAP bar0 (in CPU) ==> 0x80000000(remote amba address) */
+ priv->amba_maps[0].size = bar0_size/2;
+ priv->amba_maps[0].local_adr = bar0;
+ priv->amba_maps[0].remote_adr = 0x80000000;
+
+ /* AMBA MAP bar1 (in CPU) ==> 0x40000000(remote amba address) */
+ priv->amba_maps[1].size = devinfo->resources[1].size;
+ priv->amba_maps[1].local_adr = devinfo->resources[1].address;
+ priv->amba_maps[1].remote_adr = 0x40000000;
+
+ /* Addresses not matching with map be untouched */
+ priv->amba_maps[2].size = 0xfffffff0;
+ priv->amba_maps[2].local_adr = 0;
+ priv->amba_maps[2].remote_adr = 0;
+
+ /* Mark end of table */
+ priv->amba_maps[3].size=0;
+ priv->amba_maps[3].local_adr = 0;
+ priv->amba_maps[3].remote_adr = 0;
+
+ /* Start AMBA PnP scan at first AHB bus */
+ ambapp_scan(&priv->abus,
+ bar0 + (priv->version->amba_ioarea & ~0xf0000000),
+ NULL, &priv->amba_maps[0]);
+
+ /* Initialize Frequency of AMBA bus */
+ ambapp_freq_init(&priv->abus, NULL, priv->version->amba_freq_hz);
+
+ /* Point PAGE0 to start of APB area */
+ *page0 = 0x80000000;
+
+ /* Find GRPCI controller */
+ tmp = (void *)ambapp_for_each(&priv->abus,
+ (OPTIONS_ALL|OPTIONS_APB_SLVS),
+ VENDOR_GAISLER, GAISLER_PCIFBRG,
+ ambapp_find_by_idx, NULL);
+ if ( !tmp ) {
+ return -3;
+ }
+ priv->grpci = (struct grpci_regs *)((struct ambapp_apb_info *)tmp->devinfo)->start;
+
+ /* Set GRPCI mmap so that AMBA masters can access CPU-RAM over
+ * the PCI window.
+ */
+ priv->grpci->cfg_stat = (priv->grpci->cfg_stat & 0x0fffffff) |
+ (priv->ahbmst2pci_map & 0xf0000000);
+ priv->grpci->page1 = 0x40000000;
+
+ /* Find IRQ controller, Clear all current IRQs */
+ tmp = (void *)ambapp_for_each(&priv->abus,
+ (OPTIONS_ALL|OPTIONS_APB_SLVS),
+ VENDOR_GAISLER, GAISLER_IRQMP,
+ ambapp_find_by_idx, NULL);
+ if ( !tmp ) {
+ return -4;
+ }
+ priv->irq = (struct irqmp_regs *)DEV_TO_APB(tmp)->start;
+ /* Set up GR-RASTA-IO irq controller */
+ priv->irq->mask[0] = 0;
+ priv->irq->iclear = 0xffff;
+ priv->irq->ilevel = 0;
+
+ /* DOWN streams translation table */
+ priv->bus_maps_down[0].name = "PCI BAR0 -> AMBA";
+ priv->bus_maps_down[0].size = priv->amba_maps[0].size;
+ priv->bus_maps_down[0].from_adr = (void *)priv->amba_maps[0].local_adr;
+ priv->bus_maps_down[0].to_adr = (void *)priv->amba_maps[0].remote_adr;
+
+ priv->bus_maps_down[1].name = "PCI BAR1 -> AMBA";
+ priv->bus_maps_down[1].size = priv->amba_maps[1].size;
+ priv->bus_maps_down[1].from_adr = (void *)priv->amba_maps[1].local_adr;
+ priv->bus_maps_down[1].to_adr = (void *)priv->amba_maps[1].remote_adr;
+
+ /* Mark end of translation table */
+ priv->bus_maps_down[2].size = 0;
+
+ /* Find GRPCI controller AHB Slave interface */
+ tmp = (void *)ambapp_for_each(&priv->abus,
+ (OPTIONS_ALL|OPTIONS_AHB_SLVS),
+ VENDOR_GAISLER, GAISLER_PCIFBRG,
+ ambapp_find_by_idx, NULL);
+ if ( !tmp ) {
+ return -5;
+ }
+ ahb = (struct ambapp_ahb_info *)tmp->devinfo;
+
+ /* UP streams translation table */
+ priv->bus_maps_up[0].name = "AMBA GRPCI Window";
+ priv->bus_maps_up[0].size = ahb->mask[0]; /* AMBA->PCI Window on GR-RASTA-IO board */
+ priv->bus_maps_up[0].from_adr = (void *)ahb->start[0];
+ priv->bus_maps_up[0].to_adr = (void *)
+ (priv->ahbmst2pci_map & 0xf0000000);
+
+ /* Mark end of translation table */
+ priv->bus_maps_up[1].size = 0;
+
+ /* Successfully registered the RASTA board */
+ return 0;
+}
+
+int gr_rasta_io_hw_init2(struct gr_rasta_io_priv *priv)
+{
+ /* Enable DMA by enabling PCI target as master */
+ pci_master_enable(priv->pcidev);
+
+ return DRVMGR_OK;
+}
+
+/* Called when a PCI target is found with the PCI device and vendor ID
+ * given in gr_rasta_io_ids[].
+ */
+int gr_rasta_io_init1(struct drvmgr_dev *dev)
+{
+ struct gr_rasta_io_priv *priv;
+ struct pci_dev_info *devinfo;
+ int status;
+ uint32_t bar0, bar1, bar0_size, bar1_size;
+ union drvmgr_key_value *value;
+
+ priv = malloc(sizeof(struct gr_rasta_io_priv));
+ if ( !priv )
+ return DRVMGR_NOMEM;
+
+ memset(priv, 0, sizeof(*priv));
+ dev->priv = priv;
+ priv->dev = dev;
+
+ /* Determine number of configurations */
+ if ( gr_rasta_io_resources_cnt == 0 ) {
+ while ( gr_rasta_io_resources[gr_rasta_io_resources_cnt] )
+ gr_rasta_io_resources_cnt++;
+ }
+
+ /* Generate Device prefix */
+
+ strcpy(priv->prefix, "/dev/rastaio0");
+ priv->prefix[12] += dev->minor_drv;
+ mkdir(priv->prefix, S_IRWXU | S_IRWXG | S_IRWXO);
+ priv->prefix[13] = '/';
+ priv->prefix[14] = '\0';
+
+ priv->devinfo = devinfo = (struct pci_dev_info *)dev->businfo;
+ priv->pcidev = devinfo->pcidev;
+ bar0 = devinfo->resources[0].address;
+ bar0_size = devinfo->resources[0].size;
+ bar1 = devinfo->resources[1].address;
+ bar1_size = devinfo->resources[1].size;
+ printf("\n\n--- GR-RASTA-IO[%d] ---\n", dev->minor_drv);
+ printf(" PCI BUS: 0x%x, SLOT: 0x%x, FUNCTION: 0x%x\n",
+ PCI_DEV_EXPAND(priv->pcidev));
+ printf(" PCI VENDOR: 0x%04x, DEVICE: 0x%04x\n",
+ devinfo->id.vendor, devinfo->id.device);
+ printf(" PCI BAR[0]: 0x%lx - 0x%lx\n", bar0, bar0 + bar0_size - 1);
+ printf(" PCI BAR[1]: 0x%lx - 0x%lx\n", bar1, bar1 + bar1_size - 1);
+ printf(" IRQ: %d\n\n\n", devinfo->irq);
+
+ /* all neccessary space assigned to GR-RASTA-IO target? */
+ if ((bar0_size == 0) || (bar1_size == 0))
+ return DRVMGR_ENORES;
+
+ /* Let user override which PCI address the AHB masters of the
+ * GR-RASTA-IO board access when doing DMA to CPU RAM. The AHB masters
+ * access the PCI Window of the AMBA bus, the MSB 4-bits of that address
+ * is translated according this config option before the address
+ * goes out on the PCI bus.
+ * Only the 4 MSB bits have an effect;
+ */
+ value = drvmgr_dev_key_get(priv->dev, "ahbmst2pci", KEY_TYPE_INT);
+ if (value)
+ priv->ahbmst2pci_map = value->i;
+ else
+ priv->ahbmst2pci_map = AHBMST2PCIADR; /* default */
+
+ priv->genirq = genirq_init(16);
+ if ( priv->genirq == NULL ) {
+ free(priv);
+ dev->priv = NULL;
+ return DRVMGR_FAIL;
+ }
+
+ status = gr_rasta_io_hw_init(priv);
+ if ( status != 0 ) {
+ genirq_destroy(priv->genirq);
+ free(priv);
+ dev->priv = NULL;
+ printf(" Failed to initialize GR-RASTA-IO HW: %d\n", status);
+ return DRVMGR_FAIL;
+ }
+
+ /* Init amba bus */
+ priv->config.abus = &priv->abus;
+ priv->config.ops = &ambapp_rasta_io_ops;
+ priv->config.maps_up = &priv->bus_maps_up[0];
+ priv->config.maps_down = &priv->bus_maps_down[0];
+ if ( priv->dev->minor_drv < gr_rasta_io_resources_cnt ) {
+ priv->config.resources = gr_rasta_io_resources[priv->dev->minor_drv];
+ } else {
+ priv->config.resources = NULL;
+ }
+
+ /* Create and register AMBA PnP bus. */
+ return ambapp_bus_register(dev, &priv->config);
+}
+
+int gr_rasta_io_init2(struct drvmgr_dev *dev)
+{
+ struct gr_rasta_io_priv *priv = dev->priv;
+
+ /* Clear any old interrupt requests */
+ drvmgr_interrupt_clear(dev, 0);
+
+ /* Enable System IRQ so that GR-RASTA-IO PCI target interrupt goes
+ * through.
+ *
+ * It is important to enable it in stage init2. If interrupts were
+ * enabled in init1 this might hang the system when more than one
+ * PCI board is connected, this is because PCI interrupts might
+ * be shared and PCI board 2 have not initialized and
+ * might therefore drive interrupt already when entering init1().
+ */
+ drvmgr_interrupt_register(
+ dev,
+ 0,
+ "gr_rasta_io",
+ gr_rasta_io_isr,
+ (void *)priv);
+
+ return gr_rasta_io_hw_init2(priv);
+}
+
+int ambapp_rasta_io_int_register(
+ struct drvmgr_dev *dev,
+ int irq,
+ const char *info,
+ drvmgr_isr handler,
+ void *arg)
+{
+ struct gr_rasta_io_priv *priv = dev->parent->dev->priv;
+ rtems_interrupt_level level;
+ int status;
+
+ rtems_interrupt_disable(level);
+
+ status = genirq_register(priv->genirq, irq, handler, arg);
+ if ( status == 0 ) {
+ /* Clear IRQ for first registered handler */
+ priv->irq->iclear = (1<<irq);
+ } else if ( status == 1 )
+ status = 0;
+
+ if (status != 0) {
+ rtems_interrupt_enable(level);
+ return DRVMGR_FAIL;
+ }
+
+ status = genirq_enable(priv->genirq, irq, handler, arg);
+ if ( status == 0 ) {
+ /* Enable IRQ for first enabled handler only */
+ priv->irq->mask[0] |= (1<<irq); /* unmask interrupt source */
+ } else if ( status == 1 )
+ status = 0;
+
+ rtems_interrupt_enable(level);
+
+ return status;
+}
+
+int ambapp_rasta_io_int_unregister(
+ struct drvmgr_dev *dev,
+ int irq,
+ drvmgr_isr isr,
+ void *arg)
+{
+ struct gr_rasta_io_priv *priv = dev->parent->dev->priv;
+ rtems_interrupt_level level;
+ int status;
+
+ rtems_interrupt_disable(level);
+
+ status = genirq_disable(priv->genirq, irq, isr, arg);
+ if ( status == 0 ) {
+ /* Disable IRQ only when no enabled handler exists */
+ priv->irq->mask[0] &= ~(1<<irq); /* mask interrupt source */
+ }
+
+ status = genirq_unregister(priv->genirq, irq, isr, arg);
+ if ( status != 0 )
+ status = DRVMGR_FAIL;
+
+ rtems_interrupt_enable(level);
+
+ return status;
+}
+
+int ambapp_rasta_io_int_unmask(
+ struct drvmgr_dev *dev,
+ int irq)
+{
+ struct gr_rasta_io_priv *priv = dev->parent->dev->priv;
+ rtems_interrupt_level level;
+
+ DBG("RASTA-IO IRQ %d: unmask\n", irq);
+
+ if ( genirq_check(priv->genirq, irq) )
+ return DRVMGR_EINVAL;
+
+ rtems_interrupt_disable(level);
+
+ /* Enable IRQ for first enabled handler only */
+ priv->irq->mask[0] |= (1<<irq); /* unmask interrupt source */
+
+ rtems_interrupt_enable(level);
+
+ return DRVMGR_OK;
+}
+
+int ambapp_rasta_io_int_mask(
+ struct drvmgr_dev *dev,
+ int irq)
+{
+ struct gr_rasta_io_priv *priv = dev->parent->dev->priv;
+ rtems_interrupt_level level;
+
+ DBG("RASTA-IO IRQ %d: mask\n", irq);
+
+ if ( genirq_check(priv->genirq, irq) )
+ return DRVMGR_EINVAL;
+
+ rtems_interrupt_disable(level);
+
+ /* Disable/mask IRQ */
+ priv->irq->mask[0] &= ~(1<<irq); /* mask interrupt source */
+
+ rtems_interrupt_enable(level);
+
+ return DRVMGR_OK;
+}
+
+int ambapp_rasta_io_int_clear(
+ struct drvmgr_dev *dev,
+ int irq)
+{
+ struct gr_rasta_io_priv *priv = dev->parent->dev->priv;
+
+ if ( genirq_check(priv->genirq, irq) )
+ return DRVMGR_EINVAL;
+
+ priv->irq->iclear = (1<<irq);
+
+ return DRVMGR_OK;
+}
+
+int ambapp_rasta_io_get_params(struct drvmgr_dev *dev, struct drvmgr_bus_params *params)
+{
+ struct gr_rasta_io_priv *priv = dev->parent->dev->priv;
+
+ /* Device name prefix pointer, skip /dev */
+ params->dev_prefix = &priv->prefix[5];
+
+ return 0;
+}
+
+void gr_rasta_io_print_dev(struct drvmgr_dev *dev, int options)
+{
+ struct gr_rasta_io_priv *priv = dev->priv;
+ struct pci_dev_info *devinfo = priv->devinfo;
+ uint32_t bar0, bar1, bar0_size, bar1_size;
+
+ /* Print */
+ printf("--- GR-RASTA-IO [bus 0x%x, dev 0x%x, fun 0x%x] ---\n",
+ PCI_DEV_EXPAND(priv->pcidev));
+
+ bar0 = devinfo->resources[0].address;
+ bar0_size = devinfo->resources[0].size;
+ bar1 = devinfo->resources[1].address;
+ bar1_size = devinfo->resources[1].size;
+
+ printf(" PCI BAR[0]: 0x%lx - 0x%lx\n", bar0, bar0 + bar0_size - 1);
+ printf(" PCI BAR[1]: 0x%lx - 0x%lx\n", bar1, bar1 + bar1_size - 1);
+ printf(" IRQ REGS: 0x%x\n", (unsigned int)priv->irq);
+ printf(" IRQ: %d\n", devinfo->irq);
+ printf(" PCI REVISION: %d\n", devinfo->rev);
+ printf(" FREQ: %d Hz\n", priv->version->amba_freq_hz);
+ printf(" IMASK: 0x%08x\n", priv->irq->mask[0]);
+ printf(" IPEND: 0x%08x\n", priv->irq->ipend);
+
+ /* Print amba config */
+ if ( options & RASTA_IO_OPTIONS_AMBA ) {
+ ambapp_print(&priv->abus, 10);
+ }
+
+#if 0
+ /* Print IRQ handlers and their arguments */
+ if ( options & RASTA_IO_OPTIONS_IRQ ) {
+ int i;
+ for(i=0; i<16; i++) {
+ printf(" IRQ[%02d]: 0x%x, arg: 0x%x\n",
+ i, (unsigned int)priv->isrs[i].handler, (unsigned int)priv->isrs[i].arg);
+ }
+ }
+#endif
+}
+
+void gr_rasta_io_print(int options)
+{
+ struct pci_drv_info *drv = &gr_rasta_io_info;
+ struct drvmgr_dev *dev;
+
+ dev = drv->general.dev;
+ while(dev) {
+ gr_rasta_io_print_dev(dev, options);
+ dev = dev->next_in_drv;
+ }
+}
diff --git a/c/src/lib/libbsp/sparc/shared/pci/gr_rasta_spw_router.c b/c/src/lib/libbsp/sparc/shared/pci/gr_rasta_spw_router.c
new file mode 100644
index 0000000000..c6a17f0ecf
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/pci/gr_rasta_spw_router.c
@@ -0,0 +1,681 @@
+/* GR-RASTA-SPW-ROUTER PCI Target driver.
+ *
+ * COPYRIGHT (c) 2011.
+ * Aeroflex Gaisler AB.
+ *
+ * The license and distribution terms for this file may be
+ * found in found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * Configures the GR-RASTA-SPW-ROUTER interface PCI board.
+ * This driver provides a AMBA PnP bus by using the general part
+ * of the AMBA PnP bus driver (ambapp_bus.c). Based on the
+ * GR-RASTA-IO driver.
+ *
+ * 2011-06-07, Marko Isomaki <marko@gaisler.com>
+ * Created
+ * 2011-07-14, Daniel Hellstrom <daniel@gaisler.com>
+ * Converted to new driver-manger/libpci layers
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <bsp.h>
+#include <rtems/bspIo.h>
+#include <pci.h>
+
+#include <ambapp.h>
+#include <grlib.h>
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+#include <drvmgr/pci_bus.h>
+#include <genirq.h>
+
+/*#include <gr_rasta_spw_router.h> */
+
+/* Determines which PCI address the AHB masters will access, it should be
+ * set so that the masters can access the CPU RAM. Default is base of CPU RAM,
+ * CPU RAM is mapped 1:1 to PCI space.
+ */
+extern unsigned int _RAM_START;
+#define AHBMST2PCIADR (((unsigned int)&_RAM_START) & 0xf0000000)
+
+/* Offset from 0x80000000 (dual bus version) */
+#define AHB1_BASE_ADDR 0x80000000
+#define AHB1_IOAREA_BASE_ADDR 0x80100000
+
+#define GRPCI2_BAR0_TO_AHB_MAP 0x04 /* Fixme */
+#define GRPCI2_PCI_CONFIG 0x20 /* Fixme */
+#define RASTA_SPW_ROUTER_OPTIONS_AMBA 0x01 /* Print AMBA bus devices */ /* Fixme */
+#define RASTA_SPW_ROUTER_OPTIONS_IRQ 0x02 /* Print current IRQ setup */ /* Fixme */
+
+
+/* #define DEBUG 1 */
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+/* PCI ID */
+#define PCIID_VENDOR_GAISLER 0x1AC8
+
+int gr_rasta_spw_router_init1(struct drvmgr_dev *dev);
+int gr_rasta_spw_router_init2(struct drvmgr_dev *dev);
+
+struct grpci2_regs {
+ volatile unsigned int ctrl;
+ volatile unsigned int statcap;
+ volatile unsigned int pcimstprefetch;
+ volatile unsigned int ahbtopciiomap;
+ volatile unsigned int dmactrl;
+ volatile unsigned int dmadesc;
+ volatile unsigned int dmachanact;
+ volatile unsigned int reserved;
+ volatile unsigned int pcibartoahb[6];
+ volatile unsigned int reserved2[2];
+ volatile unsigned int ahbtopcimemmap[16];
+ volatile unsigned int trcctrl;
+ volatile unsigned int trccntmode;
+ volatile unsigned int trcadpat;
+ volatile unsigned int trcadmask;
+ volatile unsigned int trcctrlsigpat;
+ volatile unsigned int trcctrlsigmask;
+ volatile unsigned int trcadstate;
+ volatile unsigned int trcctrlsigstate;
+};
+
+struct gr_rasta_spw_router_ver {
+ const unsigned int amba_freq_hz; /* The frequency */
+ const unsigned int amba_ioarea; /* The address where the PnP IOAREA starts at */
+};
+
+/* Private data structure for driver */
+struct gr_rasta_spw_router_priv {
+ /* Driver management */
+ struct drvmgr_dev *dev;
+ char prefix[20];
+
+ /* PCI */
+ pci_dev_t pcidev;
+ struct pci_dev_info *devinfo;
+ uint32_t ahbmst2pci_map;
+
+ /* IRQ */
+ genirq_t genirq;
+
+ /* GR-RASTA-SPW-ROUTER */
+ struct gr_rasta_spw_router_ver *version;
+ struct irqmp_regs *irq;
+ struct grpci2_regs *grpci2;
+ struct drvmgr_map_entry bus_maps_up[2];
+ struct drvmgr_map_entry bus_maps_down[2];
+
+ /* AMBA Plug&Play information on GR-RASTA-SPW-ROUTER */
+ struct ambapp_bus abus;
+ struct ambapp_mmap amba_maps[3];
+ struct ambapp_config config;
+};
+
+struct gr_rasta_spw_router_ver gr_rasta_spw_router_ver0 = {
+ .amba_freq_hz = 50000000,
+ .amba_ioarea = 0xfff00000,
+};
+
+int ambapp_rasta_spw_router_int_register(
+ struct drvmgr_dev *dev,
+ int irq,
+ const char *info,
+ drvmgr_isr handler,
+ void *arg);
+int ambapp_rasta_spw_router_int_unregister(
+ struct drvmgr_dev *dev,
+ int irq,
+ drvmgr_isr handler,
+ void *arg);
+int ambapp_rasta_spw_router_int_unmask(
+ struct drvmgr_dev *dev,
+ int irq);
+int ambapp_rasta_spw_router_int_mask(
+ struct drvmgr_dev *dev,
+ int irq);
+int ambapp_rasta_spw_router_int_clear(
+ struct drvmgr_dev *dev,
+ int irq);
+int ambapp_rasta_spw_router_get_params(
+ struct drvmgr_dev *dev,
+ struct drvmgr_bus_params *params);
+
+struct ambapp_ops ambapp_rasta_spw_router_ops = {
+ .int_register = ambapp_rasta_spw_router_int_register,
+ .int_unregister = ambapp_rasta_spw_router_int_unregister,
+ .int_unmask = ambapp_rasta_spw_router_int_unmask,
+ .int_mask = ambapp_rasta_spw_router_int_mask,
+ .int_clear = ambapp_rasta_spw_router_int_clear,
+ .get_params = ambapp_rasta_spw_router_get_params
+};
+
+struct drvmgr_drv_ops gr_rasta_spw_router_ops =
+{
+ .init = {gr_rasta_spw_router_init1, gr_rasta_spw_router_init2, NULL, NULL},
+ .remove = NULL,
+ .info = NULL
+};
+
+struct pci_dev_id_match gr_rasta_spw_router_ids[] =
+{
+ PCIID_DEVVEND(PCIID_VENDOR_GAISLER, PCIID_DEVICE_GR_RASTA_SPW_RTR),
+ PCIID_END_TABLE /* Mark end of table */
+};
+
+struct pci_drv_info gr_rasta_spw_router_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_PCI_GAISLER_RASTA_SPW_ROUTER_ID, /* Driver ID */
+ "GR-RASTA-SPW_ROUTER_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_PCI, /* Bus Type */
+ &gr_rasta_spw_router_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ sizeof(struct gr_rasta_spw_router_priv),
+ },
+ &gr_rasta_spw_router_ids[0]
+};
+
+/* Driver resources configuration for the AMBA bus on the GR-RASTA-SPW-ROUTER board.
+ * It is declared weak so that the user may override it from the project file,
+ * if the default settings are not enough.
+ *
+ * The configuration consists of an array of configuration pointers, each
+ * pointer determine the configuration of one GR-RASTA-SPW-ROUTER board. Pointer
+ * zero is for board0, pointer 1 for board1 and so on.
+ *
+ * The array must end with a NULL pointer.
+ */
+struct drvmgr_bus_res *gr_rasta_spw_router_resources[] __attribute__((weak)) =
+{
+ NULL
+};
+int gr_rasta_spw_router_resources_cnt = 0;
+
+void gr_rasta_spw_router_register_drv(void)
+{
+ DBG("Registering GR-RASTA-SPW-ROUTER PCI driver\n");
+ drvmgr_drv_register(&gr_rasta_spw_router_info.general);
+}
+
+void gr_rasta_spw_router_isr(void *arg)
+{
+ struct gr_rasta_spw_router_priv *priv = arg;
+ unsigned int status, tmp;
+ int irq;
+ tmp = status = priv->irq->ipend;
+
+ /* DBG("GR-RASTA-SPW-ROUTER: IRQ 0x%x\n",status); */
+
+ for(irq=0; irq<16; irq++) {
+ if ( status & (1<<irq) ) {
+ genirq_doirq(priv->genirq, irq);
+ priv->irq->iclear = (1<<irq);
+ status &= ~(1<<irq);
+ if ( status == 0 )
+ break;
+ }
+ }
+
+ /* ACK interrupt, this is because PCI is Level, so the IRQ Controller
+ * still drives the IRQ
+ */
+ if ( tmp )
+ drvmgr_interrupt_clear(priv->dev, 0);
+
+ DBG("RASTA-SPW_ROUTER-IRQ: 0x%x\n", tmp);
+}
+
+int gr_rasta_spw_router_hw_init(struct gr_rasta_spw_router_priv *priv)
+{
+ int i;
+ uint32_t data;
+ unsigned int ctrl;
+ uint8_t tmp2;
+ struct ambapp_dev *tmp;
+ int status;
+ struct ambapp_ahb_info *ahb;
+ uint8_t cap_ptr;
+ pci_dev_t pcidev = priv->pcidev;
+ struct pci_dev_info *devinfo = priv->devinfo;
+
+ /* Select version of GR-RASTA-SPW-ROUTER board. Currently only one
+ * version
+ */
+ switch (devinfo->rev) {
+ case 0:
+ priv->version = &gr_rasta_spw_router_ver0;
+ break;
+ default:
+ return -2;
+ }
+
+ /* Check capabilities list bit */
+ pci_cfg_r8(pcidev, PCI_STATUS, &tmp2);
+
+ if (!((tmp2 >> 4) & 1)) {
+ /* Capabilities list not available which it should be in the GRPCI2 */
+ return -3;
+ }
+
+ /* Read capabilities pointer */
+ pci_cfg_r8(pcidev, PCI_CAP_PTR, &cap_ptr);
+
+ /* Set AHB address mappings for target PCI bars */
+ pci_cfg_w32(pcidev, cap_ptr+GRPCI2_BAR0_TO_AHB_MAP, 0xffe00000); /* APB bus, AHB I/O bus 2 MB */
+
+ /* Set PCI bus to be big endian */
+ pci_cfg_r32(pcidev, cap_ptr+GRPCI2_PCI_CONFIG, &data);
+ data = data & 0xFFFFFFFE;
+ pci_cfg_w32(pcidev, cap_ptr+GRPCI2_PCI_CONFIG, data);
+
+#if 0
+ /* set parity error response */
+ pci_cfg_r32(pcidev, PCI_COMMAND, &data);
+ pci_cfg_w32(pcidev, PCI_COMMAND, (data|PCI_COMMAND_PARITY));
+#endif
+
+ /* Scan AMBA Plug&Play */
+
+ /* AMBA MAP bar0 (in router) ==> 0xffe00000(remote amba address) */
+ priv->amba_maps[0].size = devinfo->resources[0].size;
+ priv->amba_maps[0].local_adr = devinfo->resources[0].address;
+ priv->amba_maps[0].remote_adr = 0xffe00000;
+
+ /* Addresses not matching with map be untouched */
+ priv->amba_maps[1].size = 0xfffffff0;
+ priv->amba_maps[1].local_adr = 0;
+ priv->amba_maps[1].remote_adr = 0;
+
+ /* Mark end of table */
+ priv->amba_maps[2].size=0;
+
+ /* Start AMBA PnP scan at first AHB bus */
+ ambapp_scan(
+ &priv->abus,
+ devinfo->resources[0].address + 0x100000,
+ NULL,
+ &priv->amba_maps[0]);
+
+ /* Initialize Frequency of AMBA bus */
+ ambapp_freq_init(&priv->abus, NULL, priv->version->amba_freq_hz);
+
+ /* Find IRQ controller, Clear all current IRQs */
+ tmp = ambapp_for_each(&priv->abus,
+ (OPTIONS_ALL|OPTIONS_APB_SLVS),
+ VENDOR_GAISLER, GAISLER_IRQMP,
+ ambapp_find_by_idx, NULL);
+ if ( !tmp ) {
+ return -4;
+ }
+ priv->irq = (struct irqmp_regs *)DEV_TO_APB(tmp)->start;
+ /* Set up GR-RASTA-SPW-ROUTER irq controller */
+ priv->irq->mask[0] = 0;
+ priv->irq->iclear = 0xffff;
+ priv->irq->ilevel = 0;
+
+ priv->bus_maps_down[0].name = "PCI BAR0 -> AMBA";
+ priv->bus_maps_down[0].size = priv->amba_maps[0].size;
+ priv->bus_maps_down[0].from_adr = (void *)priv->amba_maps[0].local_adr;
+ priv->bus_maps_down[0].to_adr = (void *)priv->amba_maps[0].remote_adr;
+ priv->bus_maps_down[1].size = 0;
+
+ /* Find GRPCI2 controller AHB Slave interface */
+ tmp = (void *)ambapp_for_each(&priv->abus,
+ (OPTIONS_ALL|OPTIONS_AHB_SLVS),
+ VENDOR_GAISLER, GAISLER_GRPCI2,
+ ambapp_find_by_idx, NULL);
+ if ( !tmp ) {
+ return -5;
+ }
+ ahb = (struct ambapp_ahb_info *)tmp->devinfo;
+ priv->bus_maps_up[0].name = "AMBA GRPCI2 Window";
+ priv->bus_maps_up[0].size = ahb->mask[0]; /* AMBA->PCI Window on GR-RASTA-SPW-ROUTER board */
+ priv->bus_maps_up[0].from_adr = (void *)ahb->start[0];
+ priv->bus_maps_up[0].to_adr = (void *)
+ (priv->ahbmst2pci_map & ~(ahb->mask[0]-1));
+ priv->bus_maps_up[1].size = 0;
+
+ /* Find GRPCI2 controller APB Slave interface */
+ tmp = (void *)ambapp_for_each(&priv->abus,
+ (OPTIONS_ALL|OPTIONS_APB_SLVS),
+ VENDOR_GAISLER, GAISLER_GRPCI2,
+ ambapp_find_by_idx, NULL);
+ if ( !tmp ) {
+ return -6;
+ }
+ priv->grpci2 = (struct grpci2_regs *)
+ ((struct ambapp_apb_info *)tmp->devinfo)->start;
+
+ /* Set AHB to PCI mapping for all AMBA AHB masters */
+ for(i = 0; i < 16; i++) {
+ priv->grpci2->ahbtopcimemmap[i] = priv->ahbmst2pci_map &
+ ~(ahb->mask[0]-1);
+ }
+
+ /* Make sure dirq(0) sampling is enabled */
+ ctrl = priv->grpci2->ctrl;
+ ctrl = (ctrl & 0xFFFFFF0F) | (1 << 4);
+ printf("data: 0x%x\n", ctrl);
+ priv->grpci2->ctrl = ctrl;
+
+ /* Successfully registered the RASTA-SPW-ROUTER board */
+ return 0;
+}
+
+int gr_rasta_spw_router_hw_init2(struct gr_rasta_spw_router_priv *priv)
+{
+ /* Enable DMA by enabling PCI target as master */
+ pci_master_enable(priv->pcidev);
+
+ return DRVMGR_OK;
+}
+
+/* Called when a PCI target is found with the PCI device and vendor ID
+ * given in gr_rasta_spw_router_ids[].
+ */
+int gr_rasta_spw_router_init1(struct drvmgr_dev *dev)
+{
+ struct gr_rasta_spw_router_priv *priv;
+ struct pci_dev_info *devinfo;
+ int status;
+ uint32_t bar0, bar0_size;
+ union drvmgr_key_value *value;
+
+ priv = dev->priv;
+ if (!priv)
+ return DRVMGR_NOMEM;
+
+ memset(priv, 0, sizeof(*priv));
+ dev->priv = priv;
+ priv->dev = dev;
+
+ /* Determine number of configurations */
+ if ( gr_rasta_spw_router_resources_cnt == 0 ) {
+ while ( gr_rasta_spw_router_resources[gr_rasta_spw_router_resources_cnt] )
+ gr_rasta_spw_router_resources_cnt++;
+ }
+
+ /* Generate Device prefix */
+
+ strcpy(priv->prefix, "/dev/spwrouter0");
+ priv->prefix[14] += dev->minor_drv;
+ mkdir(priv->prefix, S_IRWXU | S_IRWXG | S_IRWXO);
+ priv->prefix[15] = '/';
+ priv->prefix[16] = '\0';
+
+ priv->devinfo = devinfo = (struct pci_dev_info *)dev->businfo;
+ priv->pcidev = devinfo->pcidev;
+ bar0 = devinfo->resources[0].address;
+ bar0_size = devinfo->resources[0].size;
+ printf("\n\n--- GR-RASTA-SPW-ROUTER[%d] ---\n", dev->minor_drv);
+ printf(" PCI BUS: 0x%x, SLOT: 0x%x, FUNCTION: 0x%x\n",
+ PCI_DEV_EXPAND(priv->pcidev));
+ printf(" PCI VENDOR: 0x%04x, DEVICE: 0x%04x\n",
+ devinfo->id.vendor, devinfo->id.device);
+ printf(" PCI BAR[0]: 0x%08lx - 0x%08lx\n", bar0, bar0 + bar0_size - 1);
+ printf(" IRQ: %d\n\n\n", devinfo->irq);
+
+ /* all neccessary space assigned to GR-RASTA-SPW-ROUTER target? */
+ if (bar0_size == 0)
+ return DRVMGR_ENORES;
+
+ /* Let user override which PCI address the AHB masters of the
+ * GR-RASTA-SPW board access when doing DMA to CPU RAM. The AHB masters
+ * access the PCI Window of the AMBA bus, the MSB 4-bits of that address
+ * is translated according this config option before the address
+ * goes out on the PCI bus.
+ * Only the 4 MSB bits have an effect;
+ */
+ value = drvmgr_dev_key_get(priv->dev, "ahbmst2pci", KEY_TYPE_INT);
+ if (value)
+ priv->ahbmst2pci_map = value->i;
+ else
+ priv->ahbmst2pci_map = AHBMST2PCIADR; /* default */
+
+ priv->genirq = genirq_init(16);
+ if ( priv->genirq == NULL )
+ return DRVMGR_FAIL;
+
+ if ((status = gr_rasta_spw_router_hw_init(priv)) != 0) {
+ genirq_destroy(priv->genirq);
+ printf(" Failed to initialize GR-RASTA-SPW-ROUTER HW: %d\n", status);
+ return DRVMGR_FAIL;
+ }
+
+ /* Init amba bus */
+ priv->config.abus = &priv->abus;
+ priv->config.ops = &ambapp_rasta_spw_router_ops;
+ priv->config.maps_up = &priv->bus_maps_up[0];
+ priv->config.maps_down = &priv->bus_maps_down[0];
+ if ( priv->dev->minor_drv < gr_rasta_spw_router_resources_cnt ) {
+ priv->config.resources = gr_rasta_spw_router_resources[priv->dev->minor_drv];
+ } else {
+ priv->config.resources = NULL;
+ }
+
+ /* Create and register AMBA PnP bus. */
+ return ambapp_bus_register(dev, &priv->config);
+}
+
+int gr_rasta_spw_router_init2(struct drvmgr_dev *dev)
+{
+ struct gr_rasta_spw_router_priv *priv = dev->priv;
+
+ /* Clear any old interrupt requests */
+ drvmgr_interrupt_clear(dev, 0);
+
+ /* Enable System IRQ so that GR-RASTA-SPW-ROUTER PCI target interrupt
+ * goes through.
+ *
+ * It is important to enable it in stage init2. If interrupts were
+ * enabled in init1 this might hang the system when more than one
+ * PCI board is connected, this is because PCI interrupts might
+ * be shared and PCI board 2 have not initialized and
+ * might therefore drive interrupt already when entering init1().
+ */
+ drvmgr_interrupt_register(
+ dev,
+ 0,
+ "gr_rasta_spw_router",
+ gr_rasta_spw_router_isr,
+ (void *)priv);
+
+ return gr_rasta_spw_router_hw_init2(priv);
+}
+
+int ambapp_rasta_spw_router_int_register(
+ struct drvmgr_dev *dev,
+ int irq,
+ const char *info,
+ drvmgr_isr handler,
+ void *arg)
+{
+ struct gr_rasta_spw_router_priv *priv = dev->parent->dev->priv;
+ rtems_interrupt_level level;
+ int status;
+
+ rtems_interrupt_disable(level);
+
+ status = genirq_register(priv->genirq, irq, handler, arg);
+ if (status == 0) {
+ /* Clear IRQ for first registered handler */
+ priv->irq->iclear = (1<<irq);
+ } else if (status == 1)
+ status = 0;
+
+ if (status != 0) {
+ rtems_interrupt_enable(level);
+ return DRVMGR_FAIL;
+ }
+
+ status = genirq_enable(priv->genirq, irq, handler, arg);
+ if ( status == 0 ) {
+ /* Enable IRQ for first enabled handler only */
+ priv->irq->mask[0] |= (1<<irq); /* unmask interrupt source */
+ } else if ( status == 1 )
+ status = 0;
+
+ rtems_interrupt_enable(level);
+
+ return status;
+}
+
+int ambapp_rasta_spw_router_int_unregister(
+ struct drvmgr_dev *dev,
+ int irq,
+ drvmgr_isr isr,
+ void *arg)
+{
+ struct gr_rasta_spw_router_priv *priv = dev->parent->dev->priv;
+ rtems_interrupt_level level;
+ int status;
+
+ rtems_interrupt_disable(level);
+
+ status = genirq_disable(priv->genirq, irq, isr, arg);
+ if ( status == 0 ) {
+ /* Disable IRQ only when no enabled handler exists */
+ priv->irq->mask[0] &= ~(1<<irq); /* mask interrupt source */
+ }
+
+ status = genirq_unregister(priv->genirq, irq, isr, arg);
+ if ( status != 0 )
+ status = DRVMGR_FAIL;
+
+ rtems_interrupt_enable(level);
+
+ return status;
+}
+
+int ambapp_rasta_spw_router_int_unmask(
+ struct drvmgr_dev *dev,
+ int irq)
+{
+ struct gr_rasta_spw_router_priv *priv = dev->parent->dev->priv;
+ rtems_interrupt_level level;
+
+ DBG("RASTA-SPW-ROUTER IRQ %d: unmask\n", irq);
+
+ if ( genirq_check(priv->genirq, irq) )
+ return DRVMGR_EINVAL;
+
+ rtems_interrupt_disable(level);
+
+ /* Enable IRQ for first enabled handler only */
+ priv->irq->mask[0] |= (1<<irq); /* unmask interrupt source */
+
+ rtems_interrupt_enable(level);
+
+ return DRVMGR_OK;
+}
+
+int ambapp_rasta_spw_router_int_mask(
+ struct drvmgr_dev *dev,
+ int irq)
+{
+ struct gr_rasta_spw_router_priv *priv = dev->parent->dev->priv;
+ rtems_interrupt_level level;
+
+ DBG("RASTA-SPW-ROUTER IRQ %d: mask\n", irq);
+
+ if ( genirq_check(priv->genirq, irq) )
+ return DRVMGR_EINVAL;
+
+ rtems_interrupt_disable(level);
+
+ /* Disable/mask IRQ */
+ priv->irq->mask[0] &= ~(1<<irq); /* mask interrupt source */
+
+ rtems_interrupt_enable(level);
+
+ return DRVMGR_OK;
+}
+
+int ambapp_rasta_spw_router_int_clear(
+ struct drvmgr_dev *dev,
+ int irq)
+{
+ struct gr_rasta_spw_router_priv *priv = dev->parent->dev->priv;
+
+ if ( genirq_check(priv->genirq, irq) )
+ return DRVMGR_EINVAL;
+
+ priv->irq->iclear = (1<<irq);
+
+ return DRVMGR_OK;
+}
+
+int ambapp_rasta_spw_router_get_params(struct drvmgr_dev *dev, struct drvmgr_bus_params *params)
+{
+ struct gr_rasta_spw_router_priv *priv = dev->parent->dev->priv;
+
+ /* Device name prefix pointer, skip /dev */
+ params->dev_prefix = &priv->prefix[5];
+
+ return 0;
+}
+
+void gr_rasta_spw_router_print_dev(struct drvmgr_dev *dev, int options)
+{
+ struct gr_rasta_spw_router_priv *priv = dev->priv;
+ struct pci_dev_info *devinfo = priv->devinfo;
+ uint32_t bar0, bar0_size;
+
+ /* Print */
+ printf("--- GR-RASTA-SPW-ROUTER [bus 0x%x, dev 0x%x, fun 0x%x] ---\n",
+ PCI_DEV_EXPAND(priv->pcidev));
+
+ bar0 = devinfo->resources[0].address;
+ bar0_size = devinfo->resources[0].size;
+ printf(" PCI BAR[0]: 0x%lx - 0x%lx\n", bar0, bar0 + bar0_size - 1);
+ printf(" IRQ REGS: 0x%x\n", (unsigned int)priv->irq);
+ printf(" IRQ: %d\n", devinfo->irq);
+ printf(" PCI REVISION: %d\n", devinfo->rev);
+ printf(" FREQ: %d Hz\n", priv->version->amba_freq_hz);
+ printf(" IMASK: 0x%08x\n", priv->irq->mask[0]);
+ printf(" IPEND: 0x%08x\n", priv->irq->ipend);
+
+ /* Print amba config */
+ if (options & RASTA_SPW_ROUTER_OPTIONS_AMBA)
+ ambapp_print(&priv->abus, 10);
+
+#if 0
+ /* Print IRQ handlers and their arguments */
+ if (options & RASTA_SPW_ROUTER_OPTIONS_IRQ) {
+ int i;
+ for(i = 0; i < 16; i++) {
+ printf(" IRQ[%02d]: 0x%x, arg: 0x%x\n",
+ i, (unsigned int)priv->isrs[i].handler,
+ (unsigned int)priv->isrs[i].arg);
+ }
+ }
+#endif
+}
+
+void gr_rasta_spw_router_print(int options)
+{
+ struct pci_drv_info *drv = &gr_rasta_spw_router_info;
+ struct drvmgr_dev *dev;
+
+ dev = drv->general.dev;
+ while(dev) {
+ gr_rasta_spw_router_print_dev(dev, options);
+ dev = dev->next_in_drv;
+ }
+}
diff --git a/c/src/lib/libbsp/sparc/shared/pci/gr_rasta_tmtc.c b/c/src/lib/libbsp/sparc/shared/pci/gr_rasta_tmtc.c
new file mode 100644
index 0000000000..8e31b65f0e
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/pci/gr_rasta_tmtc.c
@@ -0,0 +1,694 @@
+/* GR-RASTA-TMTC PCI Target driver.
+ *
+ * COPYRIGHT (c) 2008.
+ * Aeroflex Gaisler AB.
+ *
+ * Configures the GR-RASTA-TMTC interface PCI board.
+ * This driver provides a AMBA PnP bus by using the general part
+ * of the AMBA PnP bus driver (ambapp_bus.c).
+ *
+ * Driver resources for the AMBA PnP bus provided can be set by overriding
+ * the defaults by declaring gr_rasta_tmtc_resources[].
+ *
+ * The license and distribution terms for this file may be
+ * found in found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2008-12-05, Daniel Hellstrom <daniel@gaisler.com>
+ * Created
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <bsp.h>
+#include <rtems/bspIo.h>
+#include <pci.h>
+
+#include <ambapp.h>
+#include <grlib.h>
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+#include <drvmgr/pci_bus.h>
+#include <genirq.h>
+
+#include <gr_rasta_tmtc.h>
+
+/* Determines which PCI address the AHB masters will access, it should be
+ * set so that the masters can access the CPU RAM. Default is base of CPU RAM,
+ * CPU RAM is mapped 1:1 to PCI space.
+ */
+extern unsigned int _RAM_START;
+#define AHBMST2PCIADR (((unsigned int)&_RAM_START) & 0xf0000000)
+
+#define GAISLER_GPIO 0x01a
+#define AHB1_BASE_ADDR 0x80000000
+#define AHB1_IOAREA_BASE_ADDR 0x80200000
+
+/* #define DEBUG 1 */
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+int gr_rasta_tmtc_init1(struct drvmgr_dev *dev);
+int gr_rasta_tmtc_init2(struct drvmgr_dev *dev);
+
+struct grpci_regs {
+ volatile unsigned int cfg_stat;
+ volatile unsigned int bar0;
+ volatile unsigned int page0;
+ volatile unsigned int bar1;
+ volatile unsigned int page1;
+ volatile unsigned int iomap;
+ volatile unsigned int stat_cmd;
+};
+
+struct gr_rasta_tmtc_ver {
+ const unsigned int amba_freq_hz; /* The frequency */
+ const unsigned int amba_ioarea; /* The address where the PnP IOAREA starts at */
+};
+
+/* Private data structure for driver */
+struct gr_rasta_tmtc_priv {
+ /* Driver management */
+ struct drvmgr_dev *dev;
+ char prefix[20];
+
+ /* PCI */
+ pci_dev_t pcidev;
+ struct pci_dev_info *devinfo;
+ uint32_t ahbmst2pci_map;
+
+ /* IRQ */
+ genirq_t genirq;
+
+ /* GR-RASTA-TMTC */
+ struct gr_rasta_tmtc_ver *version;
+ struct irqmp_regs *irq;
+ struct grpci_regs *grpci;
+ struct grgpio_regs *gpio;
+ struct drvmgr_map_entry bus_maps_down[3];
+ struct drvmgr_map_entry bus_maps_up[2];
+
+ /* AMBA Plug&Play information on GR-RASTA-TMTC */
+ struct ambapp_bus abus;
+ struct ambapp_mmap amba_maps[4];
+ struct ambapp_config config;
+};
+
+struct gr_rasta_tmtc_ver gr_rasta_tmtc_ver0 = {
+ .amba_freq_hz = 30000000,
+ .amba_ioarea = AHB1_IOAREA_BASE_ADDR,
+};
+
+int ambapp_rasta_tmtc_int_register(
+ struct drvmgr_dev *dev,
+ int irq,
+ const char *info,
+ drvmgr_isr handler,
+ void *arg);
+int ambapp_rasta_tmtc_int_unregister(
+ struct drvmgr_dev *dev,
+ int irq,
+ drvmgr_isr handler,
+ void *arg);
+int ambapp_rasta_tmtc_int_unmask(
+ struct drvmgr_dev *dev,
+ int irq);
+int ambapp_rasta_tmtc_int_mask(
+ struct drvmgr_dev *dev,
+ int irq);
+int ambapp_rasta_tmtc_int_clear(
+ struct drvmgr_dev *dev,
+ int irq);
+int ambapp_rasta_tmtc_get_params(
+ struct drvmgr_dev *dev,
+ struct drvmgr_bus_params *params);
+
+struct ambapp_ops ambapp_rasta_tmtc_ops = {
+ .int_register = ambapp_rasta_tmtc_int_register,
+ .int_unregister = ambapp_rasta_tmtc_int_unregister,
+ .int_unmask = ambapp_rasta_tmtc_int_unmask,
+ .int_mask = ambapp_rasta_tmtc_int_mask,
+ .int_clear = ambapp_rasta_tmtc_int_clear,
+ .get_params = ambapp_rasta_tmtc_get_params
+};
+
+struct drvmgr_drv_ops gr_rasta_tmtc_ops =
+{
+ .init = {gr_rasta_tmtc_init1, gr_rasta_tmtc_init2, NULL, NULL},
+ .remove = NULL,
+ .info = NULL,
+};
+
+struct pci_dev_id_match gr_rasta_tmtc_ids[] =
+{
+ PCIID_DEVVEND(PCIID_VENDOR_GAISLER, PCIID_DEVICE_GR_RASTA_TMTC),
+ PCIID_END_TABLE /* Mark end of table */
+};
+
+struct pci_drv_info gr_rasta_tmtc_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_PCI_GAISLER_RASTATMTC_ID,/* Driver ID */
+ "GR-RASTA-TMTC_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_PCI, /* Bus Type */
+ &gr_rasta_tmtc_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ sizeof(struct gr_rasta_tmtc_priv) /* Let drvmgr alloc private */
+ },
+ &gr_rasta_tmtc_ids[0]
+};
+
+/* Driver resources configuration for the AMBA bus on the GR-RASTA-TMTC board.
+ * It is declared weak so that the user may override it from the project file,
+ * if the default settings are not enough.
+ *
+ * The configuration consists of an array of configuration pointers, each
+ * pointer determine the configuration of one GR-RASTA-TMTC board. Pointer
+ * zero is for board0, pointer 1 for board1 and so on.
+ *
+ * The array must end with a NULL pointer.
+ */
+struct drvmgr_bus_res *gr_rasta_tmtc_resources[] __attribute__((weak)) =
+{
+ NULL,
+};
+int gr_rasta_tmtc_resources_cnt = 0;
+
+void gr_rasta_tmtc_register_drv(void)
+{
+ DBG("Registering GR-RASTA-TMTC PCI driver\n");
+ drvmgr_drv_register(&gr_rasta_tmtc_info.general);
+}
+
+void gr_rasta_tmtc_isr (void *arg)
+{
+ struct gr_rasta_tmtc_priv *priv = arg;
+ unsigned int status, tmp;
+ int irq;
+ tmp = status = priv->irq->ipend;
+
+ /* printk("GR-RASTA-TMTC: IRQ 0x%x\n",status); */
+
+ for(irq=0; irq<32; irq++) {
+ if ( status & (1<<irq) ) {
+ genirq_doirq(priv->genirq, irq);
+ priv->irq->iclear = (1<<irq);
+ status &= ~(1<<irq);
+ if ( status == 0 )
+ break;
+ }
+ }
+
+ /* ACK interrupt, this is because PCI is Level, so the IRQ Controller still drives the IRQ. */
+ if ( tmp )
+ drvmgr_interrupt_clear(priv->dev, 0);
+
+ DBG("RASTA-TMTC-IRQ: 0x%x\n", tmp);
+}
+
+int gr_rasta_tmtc_hw_init(struct gr_rasta_tmtc_priv *priv)
+{
+ unsigned int *page0 = NULL;
+ struct ambapp_dev *tmp;
+ struct ambapp_ahb_info *ahb;
+ unsigned int pci_freq_hz;
+ pci_dev_t pcidev = priv->pcidev;
+ struct pci_dev_info *devinfo = priv->devinfo;
+ uint32_t bar0, bar0_size;
+
+ /* Select version of GR-RASTA-TMTC board */
+ switch (devinfo->rev) {
+ case 0:
+ priv->version = &gr_rasta_tmtc_ver0;
+ break;
+ default:
+ return -2;
+ }
+
+ bar0 = devinfo->resources[0].address;
+ bar0_size = devinfo->resources[0].size;
+ page0 = (unsigned int *)(bar0 + bar0_size/2);
+
+ /* Point PAGE0 to start of Plug and Play information */
+ *page0 = priv->version->amba_ioarea & 0xf0000000;
+
+#if 0
+ {
+ uint32_t data;
+ /* set parity error response */
+ pci_cfg_r32(pcidev, PCI_COMMAND, &data);
+ pci_cfg_w32(pcidev, PCI_COMMAND, (data|PCI_COMMAND_PARITY));
+ }
+#endif
+
+ /* Setup cache line size. Default cache line size will result in
+ * poor performance (256 word fetches), 0xff will set it according
+ * to the max size of the PCI FIFO.
+ */
+ pci_cfg_w8(pcidev, PCI_CACHE_LINE_SIZE, 0xff);
+
+ /* Scan AMBA Plug&Play */
+
+ /* AMBA MAP bar0 (in CPU) ==> 0x80000000(remote amba address) */
+ priv->amba_maps[0].size = 0x10000000;
+ priv->amba_maps[0].local_adr = bar0;
+ priv->amba_maps[0].remote_adr = AHB1_BASE_ADDR;
+
+ /* AMBA MAP bar1 (in CPU) ==> 0x40000000(remote amba address) */
+ priv->amba_maps[1].size = devinfo->resources[1].size;
+ priv->amba_maps[1].local_adr = devinfo->resources[1].address;
+ priv->amba_maps[1].remote_adr = 0x40000000;
+
+ /* Addresses not matching with map be untouched */
+ priv->amba_maps[2].size = 0xfffffff0;
+ priv->amba_maps[2].local_adr = 0;
+ priv->amba_maps[2].remote_adr = 0;
+
+ /* Mark end of table */
+ priv->amba_maps[3].size=0;
+ priv->amba_maps[3].local_adr = 0;
+ priv->amba_maps[3].remote_adr = 0;
+
+ /* Start AMBA PnP scan at first AHB bus */
+ ambapp_scan(&priv->abus,
+ bar0 + (priv->version->amba_ioarea & ~0xf0000000),
+ NULL, &priv->amba_maps[0]);
+
+ /* Frequency is the same as the PCI bus frequency */
+ drvmgr_freq_get(priv->dev, 0, &pci_freq_hz);
+
+ /* Initialize Frequency of AMBA bus */
+ ambapp_freq_init(&priv->abus, NULL, pci_freq_hz);
+
+ /* Point PAGE0 to start of APB area */
+ *page0 = AHB1_BASE_ADDR;
+
+ /* Find GRPCI controller */
+ tmp = (void *)ambapp_for_each(&priv->abus,
+ (OPTIONS_ALL|OPTIONS_APB_SLVS),
+ VENDOR_GAISLER, GAISLER_PCIFBRG,
+ ambapp_find_by_idx, NULL);
+ if ( !tmp ) {
+ return -3;
+ }
+ priv->grpci = (struct grpci_regs *)((struct ambapp_apb_info *)tmp->devinfo)->start;
+
+ /* Set GRPCI mmap so that AMBA masters can access CPU-RAM over
+ * the PCI window.
+ */
+ priv->grpci->cfg_stat = (priv->grpci->cfg_stat & 0x0fffffff) |
+ (priv->ahbmst2pci_map & 0xf0000000);
+ priv->grpci->page1 = 0x40000000;
+
+ /* Find IRQ controller, Clear all current IRQs */
+ tmp = (void *)ambapp_for_each(&priv->abus,
+ (OPTIONS_ALL|OPTIONS_APB_SLVS),
+ VENDOR_GAISLER, GAISLER_IRQMP,
+ ambapp_find_by_idx, NULL);
+ if ( !tmp ) {
+ return -4;
+ }
+ priv->irq = (struct irqmp_regs *)DEV_TO_APB(tmp)->start;
+ /* Set up GR-RASTA-TMTC irq controller */
+ priv->irq->mask[0] = 0;
+ priv->irq->iclear = 0xffffffff;
+ priv->irq->ilevel = 0;
+
+ /* Find First GPIO controller */
+ tmp = (void *)ambapp_for_each(&priv->abus,
+ (OPTIONS_ALL|OPTIONS_APB_SLVS),
+ VENDOR_GAISLER, GAISLER_GPIO,
+ ambapp_find_by_idx, NULL);
+ if ( !tmp ) {
+ return -5;
+ }
+ priv->gpio = (struct grgpio_regs *) (((struct ambapp_apb_info *)tmp->devinfo)->start);
+ /* Clear GR-RASTA-TMTC GPIO controller */
+ priv->gpio->imask = 0;
+ priv->gpio->ipol = 0;
+ priv->gpio->iedge = 0;
+ priv->gpio->bypass = 0;
+ /* Set up GR-RASTA-TMTC GPIO controller to select GRTM and GRTC */
+ priv->gpio->output = (GR_TMTC_GPIO_GRTM_SEL|GR_TMTC_GPIO_TRANSP_CLK) | (GR_TMTC_GPIO_TC_BIT_LOCK|GR_TMTC_GPIO_TC_RF_AVAIL|GR_TMTC_GPIO_TC_ACTIVE_HIGH|GR_TMTC_GPIO_TC_RISING_CLK);
+ priv->gpio->dir = 0xffffffff;
+ DBG("GR-TMTC GPIO: 0x%x\n", (unsigned int)priv->gpio);
+
+ /* Enable DMA by enabling PCI target as master */
+ pci_master_enable(pcidev);
+
+ /* DOWN streams translation table */
+ priv->bus_maps_down[0].name = "PCI BAR0 -> AMBA";
+ priv->bus_maps_down[0].size = priv->amba_maps[0].size;
+ priv->bus_maps_down[0].from_adr = (void *)priv->amba_maps[0].local_adr;
+ priv->bus_maps_down[0].to_adr = (void *)priv->amba_maps[0].remote_adr;
+
+ priv->bus_maps_down[1].name = "PCI BAR1 -> AMBA";
+ priv->bus_maps_down[1].size = priv->amba_maps[1].size;
+ priv->bus_maps_down[1].from_adr = (void *)priv->amba_maps[1].local_adr;
+ priv->bus_maps_down[1].to_adr = (void *)priv->amba_maps[1].remote_adr;
+
+ /* Mark end of translation table */
+ priv->bus_maps_down[2].size = 0;
+
+ /* Find GRPCI controller AHB Slave interface */
+ tmp = (struct ambapp_dev *)ambapp_for_each(&priv->abus,
+ (OPTIONS_ALL|OPTIONS_AHB_SLVS),
+ VENDOR_GAISLER, GAISLER_PCIFBRG,
+ ambapp_find_by_idx, NULL);
+ if ( !tmp ) {
+ return -6;
+ }
+ ahb = (struct ambapp_ahb_info *)tmp->devinfo;
+
+ /* UP streams translation table */
+ priv->bus_maps_up[0].name = "AMBA GRPCI Window";
+ priv->bus_maps_up[0].size = ahb->mask[0]; /* AMBA->PCI Window on GR-RASTA-TMTC board */
+ priv->bus_maps_up[0].from_adr = (void *)ahb->start[0];
+ priv->bus_maps_up[0].to_adr = (void *)
+ (priv->ahbmst2pci_map & 0xf0000000);
+
+ /* Mark end of translation table */
+ priv->bus_maps_up[1].size = 0;
+
+ /* Successfully registered the RASTA board */
+ return 0;
+}
+
+void gr_rasta_tmtc_hw_init2(struct gr_rasta_tmtc_priv *priv)
+{
+ /* Enable DMA by enabling PCI target as master */
+ pci_master_enable(priv->pcidev);
+}
+
+/* Called when a PCI target is found with the PCI device and vendor ID
+ * given in gr_rasta_tmtc_ids[].
+ */
+int gr_rasta_tmtc_init1(struct drvmgr_dev *dev)
+{
+ struct gr_rasta_tmtc_priv *priv;
+ struct pci_dev_info *devinfo;
+ int status;
+ uint32_t bar0, bar1, bar0_size, bar1_size;
+ union drvmgr_key_value *value;
+
+ priv = dev->priv;
+ if (!priv)
+ return DRVMGR_NOMEM;
+ priv->dev = dev;
+
+ /* Determine number of configurations */
+ if ( gr_rasta_tmtc_resources_cnt == 0 ) {
+ while ( gr_rasta_tmtc_resources[gr_rasta_tmtc_resources_cnt] )
+ gr_rasta_tmtc_resources_cnt++;
+ }
+
+ /* Generate Device prefix */
+
+ strcpy(priv->prefix, "/dev/rastatmtc0");
+ priv->prefix[14] += dev->minor_drv;
+ mkdir(priv->prefix, S_IRWXU | S_IRWXG | S_IRWXO);
+ priv->prefix[15] = '/';
+ priv->prefix[16] = '\0';
+
+ priv->devinfo = devinfo = (struct pci_dev_info *)dev->businfo;
+ priv->pcidev = devinfo->pcidev;
+ bar0 = devinfo->resources[0].address;
+ bar0_size = devinfo->resources[0].size;
+ bar1 = devinfo->resources[1].address;
+ bar1_size = devinfo->resources[1].size;
+ printf("\n\n--- GR-RASTA-TMTC[%d] ---\n", dev->minor_drv);
+ printf(" PCI BUS: 0x%x, SLOT: 0x%x, FUNCTION: 0x%x\n",
+ PCI_DEV_EXPAND(priv->pcidev));
+ printf(" PCI VENDOR: 0x%04x, DEVICE: 0x%04x\n",
+ devinfo->id.vendor, devinfo->id.device);
+ printf(" PCI BAR[0]: 0x%lx - 0x%lx\n", bar0, bar0 + bar0_size - 1);
+ printf(" PCI BAR[1]: 0x%lx - 0x%lx\n", bar1, bar1 + bar1_size - 1);
+ printf(" IRQ: %d\n\n\n", devinfo->irq);
+
+ /* all neccessary space assigned to GR-RASTA-IO target? */
+ if ((bar0_size == 0) || (bar1_size == 0))
+ return DRVMGR_ENORES;
+
+ /* Let user override which PCI address the AHB masters of the
+ * GR-RASTA-TMTC board access when doing DMA to CPU RAM. The AHB masters
+ * access the PCI Window of the AMBA bus, the MSB 4-bits of that address
+ * is translated according this config option before the address
+ * goes out on the PCI bus.
+ * Only the 4 MSB bits have an effect;
+ */
+ value = drvmgr_dev_key_get(priv->dev, "ahbmst2pci", KEY_TYPE_INT);
+ if (value)
+ priv->ahbmst2pci_map = value->i;
+ else
+ priv->ahbmst2pci_map = AHBMST2PCIADR; /* default */
+
+ priv->genirq = genirq_init(32);
+ if ( priv->genirq == NULL )
+ return DRVMGR_FAIL;
+
+ status = gr_rasta_tmtc_hw_init(priv);
+ if ( status != 0 ) {
+ genirq_destroy(priv->genirq);
+ printf(" Failed to initialize GR-RASTA-TMTC HW: %d\n", status);
+ return DRVMGR_FAIL;
+ }
+
+ /* Init amba bus */
+ priv->config.abus = &priv->abus;
+ priv->config.ops = &ambapp_rasta_tmtc_ops;
+ priv->config.maps_up = &priv->bus_maps_up[0];
+ priv->config.maps_down = &priv->bus_maps_down[0];
+ if ( priv->dev->minor_drv < gr_rasta_tmtc_resources_cnt ) {
+ priv->config.resources = gr_rasta_tmtc_resources[priv->dev->minor_drv];
+ } else {
+ priv->config.resources = NULL;
+ }
+
+ return ambapp_bus_register(dev, &priv->config);
+}
+
+int gr_rasta_tmtc_init2(struct drvmgr_dev *dev)
+{
+ struct gr_rasta_tmtc_priv *priv = dev->priv;
+
+ /* Clear any old interrupt requests */
+ drvmgr_interrupt_clear(priv->dev, 0);
+
+ /* Enable System IRQ so that GR-RASTA-TMTC PCI target interrupt goes
+ * through.
+ *
+ * It is important to enable it in stage init2. If interrupts were
+ * enabled in init1 this might hang the system when more than one
+ * PCI target is connected, this is because PCI interrupts might
+ * be shared and PCI board 2 have not initialized and
+ * might therefore drive interrupt already when entering init1().
+ */
+ drvmgr_interrupt_register(
+ priv->dev,
+ 0,
+ "gr_rasta_tmtc",
+ gr_rasta_tmtc_isr,
+ (void *)priv);
+
+ gr_rasta_tmtc_hw_init2(priv);
+
+ return DRVMGR_OK;
+}
+
+int ambapp_rasta_tmtc_int_register(
+ struct drvmgr_dev *dev,
+ int irq,
+ const char *info,
+ drvmgr_isr handler,
+ void *arg)
+{
+ struct gr_rasta_tmtc_priv *priv = dev->parent->dev->priv;
+ rtems_interrupt_level level;
+ int status;
+
+ rtems_interrupt_disable(level);
+
+ status = genirq_register(priv->genirq, irq, handler, arg);
+ if ( status == 0 ) {
+ /* Disable and clear IRQ for first registered handler */
+ priv->irq->iclear = (1<<irq);
+ } else if ( status == 1 )
+ status = 0;
+
+ if (status != 0) {
+ rtems_interrupt_enable(level);
+ return DRVMGR_FAIL;
+ }
+
+ status = genirq_enable(priv->genirq, irq, handler, arg);
+ if ( status == 0 ) {
+ /* Enable IRQ for first enabled handler only */
+ priv->irq->mask[0] |= (1<<irq); /* unmask interrupt source */
+ } else if ( status == 1 )
+ status = 0;
+
+ rtems_interrupt_enable(level);
+
+ return status;
+}
+
+int ambapp_rasta_tmtc_int_unregister(
+ struct drvmgr_dev *dev,
+ int irq,
+ drvmgr_isr isr,
+ void *arg)
+{
+ struct gr_rasta_tmtc_priv *priv = dev->parent->dev->priv;
+ rtems_interrupt_level level;
+ int status;
+
+ rtems_interrupt_disable(level);
+
+ status = genirq_disable(priv->genirq, irq, isr, arg);
+ if ( status == 0 ) {
+ /* Disable IRQ only when no enabled handler exists */
+ priv->irq->mask[0] &= ~(1<<irq); /* mask interrupt source */
+ } else if ( status == 1 )
+ status = 0;
+
+ status = genirq_unregister(priv->genirq, irq, isr, arg);
+ if ( status != 0 )
+ status = DRVMGR_FAIL;
+
+ rtems_interrupt_enable(level);
+
+ return status;
+}
+
+int ambapp_rasta_tmtc_int_unmask(
+ struct drvmgr_dev *dev,
+ int irq)
+{
+ struct gr_rasta_tmtc_priv *priv = dev->parent->dev->priv;
+ rtems_interrupt_level level;
+
+ DBG("RASTA-TMTC IRQ %d: unmask\n", irq);
+
+ if ( genirq_check(priv->genirq, irq) )
+ return DRVMGR_EINVAL;
+
+ rtems_interrupt_disable(level);
+
+ /* Enable IRQ */
+ priv->irq->mask[0] |= (1<<irq); /* unmask interrupt source */
+
+ rtems_interrupt_enable(level);
+
+ return DRVMGR_OK;
+}
+
+int ambapp_rasta_tmtc_int_mask(
+ struct drvmgr_dev *dev,
+ int irq)
+{
+ struct gr_rasta_tmtc_priv *priv = dev->parent->dev->priv;
+ rtems_interrupt_level level;
+
+ DBG("RASTA-TMTC IRQ %d: mask\n", irq);
+
+ if ( genirq_check(priv->genirq, irq) )
+ return DRVMGR_EINVAL;
+
+ rtems_interrupt_disable(level);
+
+ /* Disable IRQ */
+ priv->irq->mask[0] &= ~(1<<irq); /* mask interrupt source */
+
+ rtems_interrupt_enable(level);
+
+ return DRVMGR_OK;
+}
+
+int ambapp_rasta_tmtc_int_clear(
+ struct drvmgr_dev *dev,
+ int irq)
+{
+ struct gr_rasta_tmtc_priv *priv = dev->parent->dev->priv;
+
+ if ( genirq_check(priv->genirq, irq) )
+ return DRVMGR_FAIL;
+
+ priv->irq->iclear = (1<<irq);
+
+ return DRVMGR_OK;
+}
+
+int ambapp_rasta_tmtc_get_params(struct drvmgr_dev *dev, struct drvmgr_bus_params *params)
+{
+ struct gr_rasta_tmtc_priv *priv = dev->parent->dev->priv;
+
+ /* Device name prefix pointer, skip /dev */
+ params->dev_prefix = &priv->prefix[5];
+
+ return 0;
+}
+
+void gr_rasta_tmtc_print_dev(struct drvmgr_dev *dev, int options)
+{
+ struct gr_rasta_tmtc_priv *priv = dev->priv;
+ struct pci_dev_info *devinfo = priv->devinfo;
+ uint32_t bar0, bar1, bar0_size, bar1_size;
+
+ /* Print */
+ printf("--- GR-RASTA-TMTC [bus 0x%x, dev 0x%x, fun 0x%x] ---\n",
+ PCI_DEV_EXPAND(priv->pcidev));
+
+ bar0 = devinfo->resources[0].address;
+ bar0_size = devinfo->resources[0].size;
+ bar1 = devinfo->resources[1].address;
+ bar1_size = devinfo->resources[1].size;
+
+ printf(" PCI BAR[0]: 0x%lx - 0x%lx\n", bar0, bar0 + bar0_size - 1);
+ printf(" PCI BAR[1]: 0x%lx - 0x%lx\n", bar1, bar1 + bar1_size - 1);
+ printf(" IRQ: %d\n", devinfo->irq);
+ printf(" PCI REVISION: %d\n", devinfo->rev);
+ printf(" FREQ: %d Hz\n", priv->version->amba_freq_hz);
+ printf(" IMASK: 0x%08x\n", priv->irq->mask[0]);
+ printf(" IPEND: 0x%08x\n", priv->irq->ipend);
+
+ /* Print amba config */
+ if ( options & RASTA_TMTC_OPTIONS_AMBA ) {
+ ambapp_print(&priv->abus, 10);
+ }
+
+#if 0
+ /* Print IRQ handlers and their arguments */
+ if ( options & RASTA_TMTC_OPTIONS_IRQ ) {
+ int i;
+ for(i=0; i<16; i++) {
+ printf(" IRQ[%02d]: 0x%x, arg: 0x%x\n",
+ i, (unsigned int)priv->isrs[i].handler, (unsigned int)priv->isrs[i].arg);
+ }
+ }
+#endif
+}
+
+void gr_rasta_tmtc_print(int options)
+{
+ struct pci_drv_info *drv = &gr_rasta_tmtc_info;
+ struct drvmgr_dev *dev;
+
+ dev = drv->general.dev;
+ while(dev) {
+ gr_rasta_tmtc_print_dev(dev, options);
+ dev = dev->next_in_drv;
+ }
+}
diff --git a/c/src/lib/libbsp/sparc/shared/pci/gr_tmtc_1553.c b/c/src/lib/libbsp/sparc/shared/pci/gr_tmtc_1553.c
new file mode 100644
index 0000000000..53f8ce998b
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/pci/gr_tmtc_1553.c
@@ -0,0 +1,575 @@
+/* GR-TMTC-1553 PCI Target driver.
+ *
+ * COPYRIGHT (c) 2008.
+ * Aeroflex Gaisler AB.
+ *
+ * Configures the GR-TMTC-1553 interface PCI board.
+ * This driver provides a AMBA PnP bus by using the general part
+ * of the AMBA PnP bus driver (ambapp_bus.c).
+ *
+ * Driver resources for the AMBA PnP bus provided can be set using
+ * gr_tmtc_1553_set_resources().
+ *
+ * The license and distribution terms for this file may be
+ * found in found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2010-06-21, Kristoffer Glembo
+ * Created
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <bsp.h>
+#include <rtems/bspIo.h>
+#include <pci.h>
+#include <pci/access.h>
+
+#include <ambapp.h>
+#include <grlib.h>
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+#include <drvmgr/pci_bus.h>
+#include <genirq.h>
+
+#include <gr_tmtc_1553.h>
+
+
+/*#define DEBUG 1 */
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+/* PCI ID */
+#define PCIID_VENDOR_GAISLER 0x1AC8
+
+int gr_tmtc_1553_init1(struct drvmgr_dev *dev);
+int gr_tmtc_1553_init2(struct drvmgr_dev *dev);
+
+struct gr_tmtc_1553_ver {
+ const unsigned int amba_freq_hz; /* The frequency */
+ const unsigned int amba_ioarea; /* The address where the PnP IOAREA starts at */
+};
+
+/* Private data structure for driver */
+struct gr_tmtc_1553_priv {
+ /* Driver management */
+ struct drvmgr_dev *dev;
+ char prefix[32];
+
+ /* PCI */
+ pci_dev_t pcidev;
+ struct pci_dev_info *devinfo;
+
+ /* IRQ */
+ genirq_t genirq;
+
+ struct gr_tmtc_1553_ver *version;
+ struct irqmp_regs *irq;
+ struct drvmgr_map_entry bus_maps_down[2];
+
+ struct ambapp_bus abus;
+ struct ambapp_mmap amba_maps[4];
+ struct ambapp_config config;
+};
+
+struct gr_tmtc_1553_ver gr_tmtc_1553_ver0 = {
+ .amba_freq_hz = 33333333,
+ .amba_ioarea = 0xfff00000,
+};
+
+
+int ambapp_tmtc_1553_int_register(
+ struct drvmgr_dev *dev,
+ int irq,
+ const char *info,
+ drvmgr_isr handler,
+ void *arg);
+int ambapp_tmtc_1553_int_unregister(
+ struct drvmgr_dev *dev,
+ int irq,
+ drvmgr_isr handler,
+ void *arg);
+int ambapp_tmtc_1553_int_unmask(
+ struct drvmgr_dev *dev,
+ int irq);
+int ambapp_tmtc_1553_int_mask(
+ struct drvmgr_dev *dev,
+ int irq);
+int ambapp_tmtc_1553_int_clear(
+ struct drvmgr_dev *dev,
+ int irq);
+int ambapp_tmtc_1553_get_params(
+ struct drvmgr_dev *dev,
+ struct drvmgr_bus_params *params);
+
+struct ambapp_ops ambapp_tmtc_1553_ops = {
+ .int_register = ambapp_tmtc_1553_int_register,
+ .int_unregister = ambapp_tmtc_1553_int_unregister,
+ .int_unmask = ambapp_tmtc_1553_int_unmask,
+ .int_mask = ambapp_tmtc_1553_int_mask,
+ .int_clear = ambapp_tmtc_1553_int_clear,
+ .get_params = ambapp_tmtc_1553_get_params
+};
+
+struct drvmgr_drv_ops gr_tmtc_1553_ops =
+{
+ {gr_tmtc_1553_init1, gr_tmtc_1553_init2, NULL, NULL},
+ NULL,
+ NULL
+};
+
+struct pci_dev_id_match gr_tmtc_1553_ids[] =
+{
+ PCIID_DEVVEND(PCIID_VENDOR_GAISLER, PCIID_DEVICE_GR_TMTC_1553),
+ PCIID_END_TABLE /* Mark end of table */
+};
+
+struct pci_drv_info gr_tmtc_1553_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_PCI_GAISLER_TMTC_1553_ID, /* Driver ID */
+ "GR-TMTC-1553_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_PCI, /* Bus Type */
+ &gr_tmtc_1553_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ 0,
+ },
+ &gr_tmtc_1553_ids[0]
+};
+
+/* Driver resources configuration for the AMBA bus on the GR-RASTA-IO board.
+ * It is declared weak so that the user may override it from the project file,
+ * if the default settings are not enough.
+ *
+ * The configuration consists of an array of configuration pointers, each
+ * pointer determine the configuration of one GR-RASTA-IO board. Pointer
+ * zero is for board0, pointer 1 for board1 and so on.
+ *
+ * The array must end with a NULL pointer.
+ */
+struct drvmgr_bus_res *gr_tmtc_1553_resources[] __attribute__((weak)) =
+{
+ NULL
+};
+int gr_tmtc_1553_resources_cnt = 0;
+
+void gr_tmtc_1553_register_drv(void)
+{
+ DBG("Registering GR-TMTC-1553 PCI driver\n");
+ drvmgr_drv_register(&gr_tmtc_1553_info.general);
+}
+
+void gr_tmtc_1553_isr (void *arg)
+{
+ struct gr_tmtc_1553_priv *priv = arg;
+ unsigned int status, tmp;
+ int irq;
+ tmp = status = priv->irq->ipend;
+
+ /* DBG("GR-RASTA-IO: IRQ 0x%x\n",status); */
+
+ for(irq=0; irq<16; irq++) {
+ if ( status & (1<<irq) ) {
+ genirq_doirq(priv->genirq, irq);
+ priv->irq->iclear = (1<<irq);
+ status &= ~(1<<irq);
+ if ( status == 0 )
+ break;
+ }
+ }
+
+ /* ACK interrupt, this is because PCI is Level, so the IRQ Controller still drives the IRQ. */
+ if ( tmp )
+ drvmgr_interrupt_clear(priv->dev, 0);
+
+ DBG("GR-TMTC-1553-IRQ: 0x%x\n", tmp);
+}
+
+int gr_tmtc_1553_hw_init(struct gr_tmtc_1553_priv *priv)
+{
+ unsigned int *page0 = NULL;
+ struct ambapp_dev *tmp;
+ int status;
+ unsigned int pci_freq_hz;
+ struct pci_dev_info *devinfo = priv->devinfo;
+ uint32_t bar0, bar0_size;
+
+ /* Select version of GR-TMTC-1553 board */
+ switch (devinfo->rev) {
+ case 0:
+ priv->version = &gr_tmtc_1553_ver0;
+ break;
+ default:
+ return -2;
+ }
+
+ bar0 = devinfo->resources[0].address;
+ bar0_size = devinfo->resources[0].size;
+ page0 = (unsigned int *)(bar0 + bar0_size/2);
+
+ /* Point PAGE0 to start of board address map. RAM at 0xff000000, APB at 0xffc00000, IOAREA at 0xfff000000 */
+ /* XXX We assume little endian host with byte twisting enabled here */
+ *page0 = 0x010000ff; /* Set little endian mode on peripheral. */
+
+ /* Scan AMBA Plug&Play */
+
+ /* AMBA MAP bar0 (in CPU) ==> 0x80000000(remote amba address) */
+ priv->amba_maps[0].size = 0x1000000;
+ priv->amba_maps[0].local_adr = bar0;
+ priv->amba_maps[0].remote_adr = 0xff000000;
+
+ /* Addresses not matching with map be untouched */
+ priv->amba_maps[2].size = 0xfffffff0;
+ priv->amba_maps[2].local_adr = 0;
+ priv->amba_maps[2].remote_adr = 0;
+
+ /* Mark end of table */
+ priv->amba_maps[3].size=0;
+ priv->amba_maps[3].local_adr = 0;
+ priv->amba_maps[3].remote_adr = 0;
+
+ /* Start AMBA PnP scan at first AHB bus */
+ ambapp_scan(&priv->abus,
+ bar0 + (priv->version->amba_ioarea & ~0xff000000),
+ NULL, &priv->amba_maps[0]);
+
+ /* Frequency is the hsame as the PCI bus frequency */
+ drvmgr_freq_get(priv->dev, NULL, &pci_freq_hz);
+
+ ambapp_freq_init(&priv->abus, NULL, pci_freq_hz);
+
+ /* Find IRQ controller */
+ tmp = (void *)ambapp_for_each(&priv->abus,
+ (OPTIONS_ALL|OPTIONS_APB_SLVS),
+ VENDOR_GAISLER, GAISLER_IRQMP,
+ ambapp_find_by_idx, NULL);
+ if ( !tmp ) {
+ return -4;
+ }
+ priv->irq = (struct irqmp_regs *)DEV_TO_APB(tmp)->start;
+ /* Set up irq controller */
+ priv->irq->mask[0] = 0;
+ priv->irq->iclear = 0xffff;
+ priv->irq->ilevel = 0;
+
+ /* DOWN streams translation table */
+ priv->bus_maps_down[0].name = "PCI BAR0 -> AMBA";
+ priv->bus_maps_down[0].size = priv->amba_maps[0].size;
+ priv->bus_maps_down[0].from_adr = (void *)priv->amba_maps[0].local_adr;
+ priv->bus_maps_down[0].to_adr = (void *)priv->amba_maps[0].remote_adr;
+ /* Mark end of translation table */
+ priv->bus_maps_down[1].size = 0;
+
+ /* Successfully registered the board */
+ return 0;
+}
+
+
+/* Called when a PCI target is found with the PCI device and vendor ID
+ * given in gr_tmtc_1553_ids[].
+ */
+int gr_tmtc_1553_init1(struct drvmgr_dev *dev)
+{
+ struct gr_tmtc_1553_priv *priv;
+ struct pci_dev_info *devinfo;
+ int status;
+ uint32_t bar0, bar0_size;
+
+ /* PCI device does not have the IRQ line register, when PCI autoconf configures it the configuration
+ * is forgotten. We take the IRQ number from the PCI Host device (AMBA device), this works as long
+ * as PCI-IRQs are ored together on the bus.
+ *
+ * Note that this only works on LEON.
+ */
+ ((struct pci_dev_info *)dev->businfo)->irq = ((struct amba_dev_info *)dev->parent->dev->businfo)->info.irq;
+
+ priv = malloc(sizeof(struct gr_tmtc_1553_priv));
+ if ( !priv )
+ return DRVMGR_NOMEM;
+
+ memset(priv, 0, sizeof(*priv));
+ dev->priv = priv;
+ priv->dev = dev;
+
+ /* Determine number of configurations */
+ if ( gr_tmtc_1553_resources_cnt == 0 ) {
+ while ( gr_tmtc_1553_resources[gr_tmtc_1553_resources_cnt] )
+ gr_tmtc_1553_resources_cnt++;
+ }
+
+ /* Generate Device prefix */
+
+ strcpy(priv->prefix, "/dev/tmtc1553_0/");
+ priv->prefix[19] += dev->minor_drv;
+ mkdir(priv->prefix, S_IRWXU | S_IRWXG | S_IRWXO);
+ priv->prefix[20] = '/';
+ priv->prefix[21] = '\0';
+
+ priv->devinfo = devinfo = (struct pci_dev_info *)dev->businfo;
+ priv->pcidev = devinfo->pcidev;
+ bar0 = devinfo->resources[0].address;
+ bar0_size = devinfo->resources[0].size;
+ printf("\n\n--- GR-TMTC-1553[%d] ---\n", dev->minor_drv);
+ printf(" PCI BUS: 0x%x, SLOT: 0x%x, FUNCTION: 0x%x\n",
+ PCI_DEV_EXPAND(priv->pcidev));
+ printf(" PCI VENDOR: 0x%04x, DEVICE: 0x%04x\n",
+ devinfo->id.vendor, devinfo->id.device);
+ printf(" PCI BAR[0]: 0x%lx - 0x%lx\n", bar0, bar0 + bar0_size - 1);
+ printf(" IRQ: %d\n\n\n", devinfo->irq);
+
+ /* all neccessary space assigned to GR-TMTC-1553 target? */
+ if (bar0_size == 0)
+ return DRVMGR_ENORES;
+
+ priv->genirq = genirq_init(16);
+ if ( priv->genirq == NULL ) {
+ free(priv);
+ dev->priv = NULL;
+ return DRVMGR_FAIL;
+ }
+
+ status = gr_tmtc_1553_hw_init(priv);
+ if ( status != 0 ) {
+ genirq_destroy(priv->genirq);
+ free(priv);
+ dev->priv = NULL;
+ printf(" Failed to initialize GR-TMTC-1553 HW: %d\n", status);
+ return DRVMGR_FAIL;
+ }
+
+ /* Init amba bus */
+ priv->config.abus = &priv->abus;
+ priv->config.ops = &ambapp_tmtc_1553_ops;
+ priv->config.maps_down = &priv->bus_maps_down[0];
+ /* This PCI device has only target interface so DMA is not supported,
+ * which means that translation from AMBA->PCI should fail if attempted.
+ */
+ priv->config.maps_up = DRVMGR_TRANSLATE_NO_BRIDGE;
+ if ( priv->dev->minor_drv < gr_tmtc_1553_resources_cnt ) {
+ priv->config.resources = gr_tmtc_1553_resources[priv->dev->minor_drv];
+ } else {
+ priv->config.resources = NULL;
+ }
+
+ /* Create And Register AMBA PnP Bus */
+ return ambapp_bus_register(dev, &priv->config);
+}
+
+int gr_tmtc_1553_init2(struct drvmgr_dev *dev)
+{
+ struct gr_tmtc_1553_priv *priv = dev->priv;
+
+ /* Clear any old interrupt requests */
+ drvmgr_interrupt_clear(dev, 0);
+
+ /* Enable System IRQ so that GR-TMTC-1553 PCI target interrupt goes through.
+ *
+ * It is important to enable it in stage init2. If interrupts were enabled in init1
+ * this might hang the system when more than one PCI target is connected, this is
+ * because PCI interrupts might be shared and PCI target 2 have not initialized and
+ * might therefore drive interrupt already when entering init1().
+ */
+ drvmgr_interrupt_register(
+ dev,
+ 0,
+ "gr_tmtc_1553",
+ gr_tmtc_1553_isr,
+ (void *)priv);
+
+ return DRVMGR_OK;
+}
+
+int ambapp_tmtc_1553_int_register(
+ struct drvmgr_dev *dev,
+ int irq,
+ const char *info,
+ drvmgr_isr handler,
+ void *arg)
+{
+ struct gr_tmtc_1553_priv *priv = dev->parent->dev->priv;
+ rtems_interrupt_level level;
+ int status;
+
+ rtems_interrupt_disable(level);
+
+ status = genirq_register(priv->genirq, irq, handler, arg);
+ if ( status == 0 ) {
+ /* Disable and clear IRQ for first registered handler */
+ priv->irq->iclear = (1<<irq);
+ priv->irq->mask[0] &= ~(1<<irq); /* mask interrupt source */
+ } else if ( status == 1 )
+ status = 0;
+
+ if (status != 0) {
+ rtems_interrupt_enable(level);
+ return DRVMGR_FAIL;
+ }
+
+ status = genirq_enable(priv->genirq, irq, handler, arg);
+ if ( status == 0 ) {
+ /* Enable IRQ for first enabled handler only */
+ priv->irq->mask[0] |= (1<<irq); /* unmask interrupt source */
+ } else if ( status == 1 )
+ status = 0;
+
+ rtems_interrupt_enable(level);
+
+ return status;
+}
+
+int ambapp_tmtc_1553_int_unregister(
+ struct drvmgr_dev *dev,
+ int irq,
+ drvmgr_isr isr,
+ void *arg)
+{
+ struct gr_tmtc_1553_priv *priv = dev->parent->dev->priv;
+ rtems_interrupt_level level;
+ int status;
+
+ rtems_interrupt_disable(level);
+
+ status = genirq_disable(priv->genirq, irq, isr, arg);
+ if ( status == 0 ) {
+ /* Disable IRQ only when no enabled handler exists */
+ priv->irq->mask[0] &= ~(1<<irq); /* mask interrupt source */
+ } else if ( status == 1 )
+ status = 0;
+
+ status = genirq_unregister(priv->genirq, irq, isr, arg);
+ if ( status != 0 )
+ status = DRVMGR_FAIL;
+
+ rtems_interrupt_enable(level);
+
+ return status;
+}
+
+int ambapp_tmtc_1553_int_unmask(
+ struct drvmgr_dev *dev,
+ int irq)
+{
+ struct gr_tmtc_1553_priv *priv = dev->parent->dev->priv;
+ rtems_interrupt_level level;
+
+ DBG("TMTC-1553 IRQ %d: enable\n", irq);
+
+ if ( genirq_check(priv->genirq, irq) )
+ return DRVMGR_FAIL;
+
+ rtems_interrupt_disable(level);
+
+ /* Enable IRQ */
+ priv->irq->mask[0] |= (1<<irq); /* unmask interrupt source */
+
+ rtems_interrupt_enable(level);
+
+ return DRVMGR_OK;
+}
+
+int ambapp_tmtc_1553_int_mask(
+ struct drvmgr_dev *dev,
+ int irq)
+{
+ struct gr_tmtc_1553_priv *priv = dev->parent->dev->priv;
+ rtems_interrupt_level level;
+
+ DBG("TMTC-1553 IRQ %d: disable\n", irq);
+
+ if ( genirq_check(priv->genirq, irq) )
+ return DRVMGR_FAIL;
+
+ rtems_interrupt_disable(level);
+
+ /* Disable IRQ */
+ priv->irq->mask[0] &= ~(1<<irq); /* mask interrupt source */
+
+ rtems_interrupt_enable(level);
+
+ return DRVMGR_OK;
+}
+
+int ambapp_tmtc_1553_int_clear(
+ struct drvmgr_dev *dev,
+ int irq)
+{
+ struct gr_tmtc_1553_priv *priv = dev->parent->dev->priv;
+
+ if ( genirq_check(priv->genirq, irq) )
+ return DRVMGR_FAIL;
+
+ priv->irq->iclear = (1<<irq);
+
+ return DRVMGR_OK;
+}
+
+int ambapp_tmtc_1553_get_params(struct drvmgr_dev *dev, struct drvmgr_bus_params *params)
+{
+ struct gr_tmtc_1553_priv *priv = dev->parent->dev->priv;
+
+ /* Device name prefix pointer, skip /dev */
+ params->dev_prefix = &priv->prefix[5];
+
+ return 0;
+}
+
+void gr_tmtc_1553_print_dev(struct drvmgr_dev *dev, int options)
+{
+ struct gr_tmtc_1553_priv *priv = dev->priv;
+ struct pci_dev_info *devinfo = priv->devinfo;
+ uint32_t bar0, bar0_size;
+
+ /* Print */
+ printf("--- GR-TMTC-1553 [bus 0x%x, dev 0x%x, fun 0x%x] ---\n",
+ PCI_DEV_EXPAND(priv->pcidev));
+
+ bar0 = devinfo->resources[0].address;
+ bar0_size = devinfo->resources[0].size;
+
+ printf(" PCI BAR[0]: 0x%lx - 0x%lx\n", bar0, bar0 + bar0_size - 1);
+ printf(" IRQ REGS: 0x%x\n", (unsigned int)priv->irq);
+ printf(" IRQ: %d\n", devinfo->irq);
+ printf(" FREQ: %d Hz\n", priv->version->amba_freq_hz);
+ printf(" IMASK: 0x%08x\n", priv->irq->mask[0]);
+ printf(" IPEND: 0x%08x\n", priv->irq->ipend);
+
+ /* Print amba config */
+ if ( options & TMTC_1553_OPTIONS_AMBA ) {
+ ambapp_print(&priv->abus, 10);
+ }
+#if 0
+ /* Print IRQ handlers and their arguments */
+ if ( options & TMTC_1553_OPTIONS_IRQ ) {
+ int i;
+ for(i=0; i<16; i++) {
+ printf(" IRQ[%02d]: 0x%x, arg: 0x%x\n",
+ i, (unsigned int)priv->isrs[i].handler, (unsigned int)priv->isrs[i].arg);
+ }
+ }
+#endif
+}
+
+void gr_tmtc_1553_print(int options)
+{
+ struct pci_drv_info *drv = &gr_tmtc_1553_info;
+ struct drvmgr_dev *dev;
+
+ dev = drv->general.dev;
+ while(dev) {
+ gr_tmtc_1553_print_dev(dev, options);
+ dev = dev->next_in_drv;
+ }
+}
diff --git a/c/src/lib/libbsp/sparc/shared/pci/grpci.c b/c/src/lib/libbsp/sparc/shared/pci/grpci.c
new file mode 100644
index 0000000000..b649b61aee
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/pci/grpci.c
@@ -0,0 +1,698 @@
+/* GRLIB GRPCI PCI HOST driver.
+ *
+ * COPYRIGHT (c) 2008.
+ * Aeroflex Gaisler AB.
+ *
+ * Configures the GRPCI core and initialize,
+ * - the PCI Library (pci.c)
+ * - the general part of the PCI Bus driver (pci_bus.c)
+ *
+ * System interrupt assigned to PCI interrupt (INTA#..INTD#) is by
+ * default taken from Plug and Play, but may be overridden by the
+ * driver resources INTA#..INTD#.
+ *
+ * The license and distribution terms for this file may be
+ * found in found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2008-12-06, Daniel Hellstrom <daniel@gaisler.com>
+ * Created
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <rtems/bspIo.h>
+#include <libcpu/byteorder.h>
+#include <libcpu/access.h>
+#include <pci.h>
+#include <pci/cfg.h>
+
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+#include <ambapp.h>
+#include <drvmgr/pci_bus.h>
+
+#define DMAPCI_ADDR 0x80000500
+
+/* Configuration options */
+#define SYSTEM_MAINMEM_START 0x40000000
+
+/* If defined to 1 - byte twisting is enabled by default */
+#define DEFAULT_BT_ENABLED 0
+
+/* Interrupt assignment. Set to other value than 0xff in order to
+ * override defaults and plug&play information
+ */
+#ifndef GRPCI_INTA_SYSIRQ
+ #define GRPCI_INTA_SYSIRQ 0xff
+#endif
+#ifndef GRPCI_INTB_SYSIRQ
+ #define GRPCI_INTB_SYSIRQ 0xff
+#endif
+#ifndef GRPCI_INTC_SYSIRQ
+ #define GRPCI_INTC_SYSIRQ 0xff
+#endif
+#ifndef GRPCI_INTD_SYSIRQ
+ #define GRPCI_INTD_SYSIRQ 0xff
+#endif
+
+#define PAGE0_BTEN_BIT 0
+#define PAGE0_BTEN (1<<PAGE0_BTEN_BIT)
+
+#define CFGSTAT_HOST_BIT 13
+#define CFGSTAT_HOST (1<<CFGSTAT_HOST_BIT)
+
+/*#define DEBUG 1*/
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+#define PCI_INVALID_VENDORDEVICEID 0xffffffff
+#define PCI_MULTI_FUNCTION 0x80
+
+/*
+ * Bit encode for PCI_CONFIG_HEADER_TYPE register
+ */
+struct grpci_regs {
+ volatile unsigned int cfg_stat;
+ volatile unsigned int bar0;
+ volatile unsigned int page0;
+ volatile unsigned int bar1;
+ volatile unsigned int page1;
+ volatile unsigned int iomap;
+ volatile unsigned int stat_cmd;
+ volatile unsigned int irq;
+};
+
+struct grpci_priv *grpcipriv = NULL;
+static int grpci_minor = 0;
+static unsigned int *pcidma = (unsigned int *)DMAPCI_ADDR;
+
+/* PCI Interrupt assignment. Connects an PCI interrupt pin (INTA#..INTD#)
+ * to a system interrupt number.
+ */
+unsigned char grpci_pci_irq_table[4] =
+{
+ /* INTA# */ GRPCI_INTA_SYSIRQ,
+ /* INTB# */ GRPCI_INTB_SYSIRQ,
+ /* INTC# */ GRPCI_INTC_SYSIRQ,
+ /* INTD# */ GRPCI_INTD_SYSIRQ
+};
+
+/* Driver private data struture */
+struct grpci_priv {
+ struct drvmgr_dev *dev;
+ struct grpci_regs *regs;
+ int irq;
+ int minor;
+
+ uint32_t bar1_pci_adr;
+ uint32_t bar1_size;
+
+ int bt_enabled;
+ unsigned int pci_area;
+ unsigned int pci_area_end;
+ unsigned int pci_io;
+ unsigned int pci_conf;
+ unsigned int pci_conf_end;
+
+ uint32_t devVend; /* Host PCI Vendor/Device ID */
+
+ struct drvmgr_map_entry maps_up[2];
+ struct drvmgr_map_entry maps_down[2];
+ struct pcibus_config config;
+};
+
+int grpci_init1(struct drvmgr_dev *dev);
+
+/* GRPCI DRIVER */
+
+struct drvmgr_drv_ops grpci_ops =
+{
+ .init = {grpci_init1, NULL, NULL, NULL},
+ .remove = NULL,
+ .info = NULL
+};
+
+struct amba_dev_id grpci_ids[] =
+{
+ {VENDOR_GAISLER, GAISLER_PCIFBRG},
+ {0, 0} /* Mark end of table */
+};
+
+struct amba_drv_info grpci_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_AMBAPP_GAISLER_GRPCI_ID, /* Driver ID */
+ "GRPCI_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */
+ &grpci_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ sizeof(struct grpci_priv), /* Make drvmgr alloc private */
+ },
+ &grpci_ids[0]
+};
+
+void grpci_register_drv(void)
+{
+ DBG("Registering GRPCI driver\n");
+ drvmgr_drv_register(&grpci_info.general);
+}
+
+int grpci_cfg_r32(pci_dev_t dev, int ofs, uint32_t *val)
+{
+ struct grpci_priv *priv = grpcipriv;
+ volatile uint32_t *pci_conf;
+ unsigned int devfn = PCI_DEV_DEVFUNC(dev);
+ int retval;
+ int bus = PCI_DEV_BUS(dev);
+
+ if (ofs & 3)
+ return PCISTS_EINVAL;
+
+ if (PCI_DEV_SLOT(dev) > 21) {
+ *val = 0xffffffff;
+ return PCISTS_OK;
+ }
+
+ /* Select bus */
+ priv->regs->cfg_stat = (priv->regs->cfg_stat & ~(0xf<<23)) | (bus<<23);
+
+ pci_conf = (volatile uint32_t *)(priv->pci_conf | (devfn << 8) | ofs);
+
+ if (priv->bt_enabled) {
+ *val = CPU_swap_u32(*pci_conf);
+ } else {
+ *val = *pci_conf;
+ }
+
+ if (priv->regs->cfg_stat & 0x100) {
+ *val = 0xffffffff;
+ retval = PCISTS_MSTABRT;
+ } else
+ retval = PCISTS_OK;
+
+ DBG("pci_read: [%x:%x:%x] reg: 0x%x => addr: 0x%x, val: 0x%x\n",
+ PCI_DEV_EXPAND(dev), ofs, pci_conf, *val);
+
+ return retval;
+}
+
+
+int grpci_cfg_r16(pci_dev_t dev, int ofs, uint16_t *val)
+{
+ uint32_t v;
+ int retval;
+
+ if (ofs & 1)
+ return PCISTS_EINVAL;
+
+ retval = grpci_cfg_r32(dev, ofs & ~0x3, &v);
+ *val = 0xffff & (v >> (8*(ofs & 0x3)));
+
+ return retval;
+}
+
+int grpci_cfg_r8(pci_dev_t dev, int ofs, uint8_t *val)
+{
+ uint32_t v;
+ int retval;
+
+ retval = grpci_cfg_r32(dev, ofs & ~0x3, &v);
+
+ *val = 0xff & (v >> (8*(ofs & 3)));
+
+ return retval;
+}
+
+int grpci_cfg_w32(pci_dev_t dev, int ofs, uint32_t val)
+{
+ struct grpci_priv *priv = grpcipriv;
+ volatile uint32_t *pci_conf;
+ uint32_t value, devfn = PCI_DEV_DEVFUNC(dev);
+ int bus = PCI_DEV_BUS(dev);
+
+ if (ofs & 0x3)
+ return PCISTS_EINVAL;
+
+ if (PCI_DEV_SLOT(dev) > 21)
+ return PCISTS_MSTABRT;
+
+ /* Select bus */
+ priv->regs->cfg_stat = (priv->regs->cfg_stat & ~(0xf<<23)) | (bus<<23);
+
+ pci_conf = (volatile uint32_t *)(priv->pci_conf | (devfn << 8) | ofs);
+
+ if ( priv->bt_enabled ) {
+ value = CPU_swap_u32(val);
+ } else {
+ value = val;
+ }
+
+ *pci_conf = value;
+
+ DBG("pci_write - [%x:%x:%x] reg: 0x%x => addr: 0x%x, val: 0x%x\n",
+ PCI_DEV_EXPAND(dev), ofs, pci_conf, value);
+
+ return PCISTS_OK;
+}
+
+int grpci_cfg_w16(pci_dev_t dev, int ofs, uint16_t val)
+{
+ uint32_t v;
+ int retval;
+
+ if (ofs & 1)
+ return PCISTS_EINVAL;
+
+ retval = grpci_cfg_r32(dev, ofs & ~0x3, &v);
+ if (retval != PCISTS_OK)
+ return retval;
+
+ v = (v & ~(0xffff << (8*(ofs&3)))) | ((0xffff&val) << (8*(ofs&3)));
+
+ return grpci_cfg_w32(dev, ofs & ~0x3, v);
+}
+
+int grpci_cfg_w8(pci_dev_t dev, int ofs, uint8_t val)
+{
+ uint32_t v;
+ int retval;
+
+ retval = grpci_cfg_r32(dev, ofs & ~0x3, &v);
+ if (retval != PCISTS_OK)
+ return retval;
+
+ v = (v & ~(0xff << (8*(ofs&3)))) | ((0xff&val) << (8*(ofs&3)));
+
+ return grpci_cfg_w32(dev, ofs & ~0x3, v);
+}
+
+/* Return the assigned system IRQ number that corresponds to the PCI
+ * "Interrupt Pin" information from configuration space.
+ *
+ * The IRQ information is stored in the grpci_pci_irq_table configurable
+ * by the user.
+ *
+ * Returns the "system IRQ" for the PCI INTA#..INTD# pin in irq_pin. Returns
+ * 0xff if not assigned.
+ */
+uint8_t grpci_bus0_irq_map(pci_dev_t dev, int irq_pin)
+{
+ uint8_t sysIrqNr = 0; /* not assigned */
+ int irq_group;
+
+ if ( (irq_pin >= 1) && (irq_pin <= 4) ) {
+ /* Use default IRQ decoding on PCI BUS0 according slot numbering */
+ irq_group = PCI_DEV_SLOT(dev) & 0x3;
+ irq_pin = ((irq_pin - 1) + irq_group) & 0x3;
+ /* Valid PCI "Interrupt Pin" number */
+ sysIrqNr = grpci_pci_irq_table[irq_pin];
+ }
+ return sysIrqNr;
+}
+
+int grpci_translate(uint32_t *address, int type, int dir)
+{
+ uint32_t adr;
+ struct grpci_priv *priv = grpcipriv;
+
+ if (type == 1) {
+ /* I/O */
+ if (dir != 0) {
+ /* The PCI bus can not access the CPU bus from I/O
+ * because GRPCI core does not support I/O BARs
+ */
+ return -1;
+ }
+
+ /* We have got a PCI BAR address that the CPU want to access...
+ * Check that it is within the PCI I/O window, I/O adresses
+ * are mapped 1:1 with GRPCI driver... no translation needed.
+ */
+ adr = *(uint32_t *)address;
+ if (adr < priv->pci_io || adr >= priv->pci_conf)
+ return -1;
+ } else {
+ /* MEMIO and MEM.
+ * Memory space is mapped 1:1 so no translation is needed.
+ * Check that address is within accessible windows.
+ */
+ adr = *(uint32_t *)address;
+ if (dir == 0) {
+ /* PCI BAR to AMBA-CPU address.. check that it is
+ * located within GRPCI PCI Memory Window
+ * adr = PCI address.
+ */
+ if (adr < priv->pci_area || adr >= priv->pci_area_end)
+ return -1;
+ } else {
+ /* We have a CPU address and want to get access to it
+ * from PCI space, typically when doing DMA into CPU
+ * RAM. The GRPCI core has two target BARs that PCI
+ * masters can access, we check here that the address
+ * is accessible from PCI.
+ * adr = AMBA address.
+ */
+ if (adr < priv->bar1_pci_adr ||
+ adr >= (priv->bar1_pci_adr + priv->bar1_size))
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+extern struct pci_memreg_ops pci_memreg_sparc_le_ops;
+extern struct pci_memreg_ops pci_memreg_sparc_be_ops;
+
+/* GRPCI PCI access routines, default to Little-endian PCI Bus */
+struct pci_access_drv grpci_access_drv = {
+ .cfg =
+ {
+ grpci_cfg_r8,
+ grpci_cfg_r16,
+ grpci_cfg_r32,
+ grpci_cfg_w8,
+ grpci_cfg_w16,
+ grpci_cfg_w32,
+ },
+ .io =
+ {
+ _ld8,
+ _ld_le16,
+ _ld_le32,
+ _st8,
+ _st_le16,
+ _st_le32,
+ },
+ .memreg = &pci_memreg_sparc_le_ops,
+ .translate = grpci_translate,
+};
+
+struct pci_io_ops grpci_io_ops_be =
+{
+ _ld8,
+ _ld_be16,
+ _ld_be32,
+ _st8,
+ _st_be16,
+ _st_be32,
+};
+
+int grpci_hw_init(struct grpci_priv *priv)
+{
+ volatile unsigned int *mbar0, *page0;
+ uint32_t data, addr, mbar0size;
+ pci_dev_t host = PCI_DEV(0, 0, 0);
+
+ mbar0 = (volatile unsigned int *)priv->pci_area;
+
+ if ( !priv->bt_enabled && ((priv->regs->page0 & PAGE0_BTEN) == PAGE0_BTEN) ) {
+ /* Byte twisting is on, turn it off */
+ grpci_cfg_w32(host, PCI_BASE_ADDRESS_0, 0xffffffff);
+ grpci_cfg_r32(host, PCI_BASE_ADDRESS_0, &addr);
+ /* Setup bar0 to nonzero value */
+ grpci_cfg_w32(host, PCI_BASE_ADDRESS_0,
+ CPU_swap_u32(0x80000000));
+ /* page0 is accessed through upper half of bar0 */
+ addr = (~CPU_swap_u32(addr)+1)>>1;
+ mbar0size = addr*2;
+ DBG("GRPCI: Size of MBAR0: 0x%x, MBAR0: 0x%x(lower) 0x%x(upper)\n",mbar0size,((unsigned int)mbar0),((unsigned int)mbar0)+mbar0size/2);
+ page0 = &mbar0[mbar0size/8];
+ DBG("GRPCI: PAGE0 reg address: 0x%x (0x%x)\n",((unsigned int)mbar0)+mbar0size/2,page0);
+ priv->regs->cfg_stat = (priv->regs->cfg_stat & (~0xf0000000)) | 0x80000000; /* Setup mmap reg so we can reach bar0 */
+ *page0 = 0<<PAGE0_BTEN_BIT; /* Disable bytetwisting ... */
+ }
+
+ /* Get the GRPCI Host PCI ID */
+ grpci_cfg_r32(host, PCI_VENDOR_ID, &priv->devVend);
+
+ /* set 1:1 mapping between AHB -> PCI memory */
+ priv->regs->cfg_stat = (priv->regs->cfg_stat & 0x0fffffff) | priv->pci_area;
+
+ /* determine size of target BAR1 */
+ grpci_cfg_w32(host, PCI_BASE_ADDRESS_1, 0xffffffff);
+ grpci_cfg_r32(host, PCI_BASE_ADDRESS_1, &addr);
+ priv->bar1_size = (~(addr & ~0xf)) + 1;
+
+ /* and map system RAM at pci address 0x40000000 */
+ priv->bar1_pci_adr &= ~(priv->bar1_size - 1); /* Fix alignment of BAR1 */
+ grpci_cfg_w32(host, PCI_BASE_ADDRESS_1, priv->bar1_pci_adr);
+ priv->regs->page1 = priv->bar1_pci_adr;
+
+ /* Translate I/O accesses 1:1 */
+ priv->regs->iomap = priv->pci_io & 0xffff0000;
+
+ /* Setup Latency Timer and cache line size. Default cache line
+ * size will result in poor performance (256 word fetches), 0xff
+ * will set it according to the max size of the PCI FIFO.
+ */
+ grpci_cfg_w8(host, PCI_CACHE_LINE_SIZE, 0xff);
+ grpci_cfg_w8(host, PCI_LATENCY_TIMER, 0x40);
+
+ /* set as bus master and enable pci memory responses */
+ grpci_cfg_r32(host, PCI_COMMAND, &data);
+ data |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+ grpci_cfg_w32(host, PCI_COMMAND, data);
+
+ /* unmask all PCI interrupts at PCI Core, not all GRPCI cores support
+ * this
+ */
+ priv->regs->irq = 0xf0000;
+
+ /* Successful */
+ return 0;
+}
+
+/* Initializes the GRPCI core and driver, must be called before calling init_pci()
+ *
+ * Return values
+ * 0 Successful initalization
+ * -1 Error during initialization, for example "PCI core not found".
+ * -2 Error PCI controller not HOST (targets not supported)
+ * -3 Error due to GRPCI hardware initialization
+ * -4 Error registering driver to PCI layer
+ */
+int grpci_init(struct grpci_priv *priv)
+{
+ struct ambapp_apb_info *apb;
+ struct ambapp_ahb_info *ahb;
+ int pin;
+ union drvmgr_key_value *value;
+ char keyname[6];
+ struct amba_dev_info *ainfo = priv->dev->businfo;
+
+ /* Find PCI core from Plug&Play information */
+ apb = ainfo->info.apb_slv;
+ ahb = ainfo->info.ahb_slv;
+
+ /* Found PCI core, init private structure */
+ priv->irq = apb->irq;
+ priv->regs = (struct grpci_regs *)apb->start;
+ priv->bt_enabled = DEFAULT_BT_ENABLED;
+
+ /* Calculate the PCI windows
+ * AMBA->PCI Window: AHB SLAVE AREA0
+ * AMBA->PCI I/O cycles Window: AHB SLAVE AREA1 Lower half
+ * AMBA->PCI Configuration cycles Window: AHB SLAVE AREA1 Upper half
+ */
+ priv->pci_area = ahb->start[0];
+ priv->pci_area_end = ahb->start[0] + ahb->mask[0];
+ priv->pci_io = ahb->start[1];
+ priv->pci_conf = ahb->start[1] + (ahb->mask[1] >> 1);
+ priv->pci_conf_end = ahb->start[1] + ahb->mask[1];
+
+ /* On systems where PCI I/O area and configuration area is apart of the "PCI Window"
+ * the PCI Window stops at the start of the PCI I/O area
+ */
+ if ( (priv->pci_io > priv->pci_area) && (priv->pci_io < (priv->pci_area_end-1)) ) {
+ priv->pci_area_end = priv->pci_io;
+ }
+
+ /* Init PCI interrupt assignment table to all use the interrupt routed through
+ * the GRPCI core.
+ */
+ strcpy(keyname, "INTX#");
+ for (pin=1; pin<5; pin++) {
+ if ( grpci_pci_irq_table[pin-1] == 0xff ) {
+ grpci_pci_irq_table[pin-1] = priv->irq;
+
+ /* User may override Both hardcoded IRQ setup and Plug & Play IRQ */
+ keyname[3] = 'A' + (pin-1);
+ value = drvmgr_dev_key_get(priv->dev, keyname, KEY_TYPE_INT);
+ if ( value )
+ grpci_pci_irq_table[pin-1] = value->i;
+ }
+ }
+
+ /* User may override DEFAULT_BT_ENABLED to enable/disable byte twisting */
+ value = drvmgr_dev_key_get(priv->dev, "byteTwisting", KEY_TYPE_INT);
+ if ( value )
+ priv->bt_enabled = value->i;
+
+ /* Use GRPCI target BAR1 to map CPU RAM to PCI, this is to make it
+ * possible for PCI peripherals to do DMA directly to CPU memory.
+ */
+ value = drvmgr_dev_key_get(priv->dev, "tgtbar1", KEY_TYPE_INT);
+ if (value)
+ priv->bar1_pci_adr = value->i;
+ else
+ priv->bar1_pci_adr = SYSTEM_MAINMEM_START; /* default */
+
+ /* This driver only support HOST systems, we check for HOST */
+ if ( !(priv->regs->cfg_stat & CFGSTAT_HOST) ) {
+ /* Target not supported */
+ return -2;
+ }
+
+ /* Init the PCI Core */
+ if ( grpci_hw_init(priv) ) {
+ return -3;
+ }
+
+ /* Down streams translation table */
+ priv->maps_down[0].name = "AMBA -> PCI MEM Window";
+ priv->maps_down[0].size = priv->pci_area_end - priv->pci_area;
+ priv->maps_down[0].from_adr = (void *)priv->pci_area;
+ priv->maps_down[0].to_adr = (void *)priv->pci_area;
+ /* End table */
+ priv->maps_down[1].size = 0;
+
+ /* Up streams translation table */
+ priv->maps_up[0].name = "Target BAR1 -> AMBA";
+ priv->maps_up[0].size = priv->bar1_size;
+ priv->maps_up[0].from_adr = (void *)priv->bar1_pci_adr;
+ priv->maps_up[0].to_adr = (void *)priv->bar1_pci_adr;
+ /* End table */
+ priv->maps_up[1].size = 0;
+
+ return 0;
+}
+
+/* Called when a core is found with the AMBA device and vendor ID
+ * given in grpci_ids[]. IRQ, Console does not work here
+ */
+int grpci_init1(struct drvmgr_dev *dev)
+{
+ int status;
+ struct grpci_priv *priv;
+ struct pci_auto_setup grpci_auto_cfg;
+
+ DBG("GRPCI[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
+
+ if ( grpci_minor != 0 ) {
+ DBG("Driver only supports one PCI core\n");
+ return DRVMGR_FAIL;
+ }
+
+ if ( (strcmp(dev->parent->dev->drv->name, "AMBAPP_GRLIB_DRV") != 0) &&
+ (strcmp(dev->parent->dev->drv->name, "AMBAPP_LEON2_DRV") != 0) ) {
+ /* We only support GRPCI driver on local bus */
+ return DRVMGR_FAIL;
+ }
+
+ priv = dev->priv;
+ if ( !priv )
+ return DRVMGR_NOMEM;
+
+ priv->dev = dev;
+ priv->minor = grpci_minor++;
+
+ grpcipriv = priv;
+ status = grpci_init(priv);
+ if (status) {
+ printf("Failed to initialize grpci driver %d\n", status);
+ return DRVMGR_FAIL;
+ }
+
+
+ /* Register the PCI core at the PCI layers */
+
+ if (priv->bt_enabled == 0) {
+ /* Host is Big-Endian */
+ pci_endian = PCI_BIG_ENDIAN;
+
+ memcpy(&grpci_access_drv.io, &grpci_io_ops_be,
+ sizeof(grpci_io_ops_be));
+ grpci_access_drv.memreg = &pci_memreg_sparc_be_ops;
+ }
+
+ if (pci_access_drv_register(&grpci_access_drv)) {
+ /* Access routines registration failed */
+ return DRVMGR_FAIL;
+ }
+
+ /* Prepare memory MAP */
+ grpci_auto_cfg.options = 0;
+ grpci_auto_cfg.mem_start = 0;
+ grpci_auto_cfg.mem_size = 0;
+ grpci_auto_cfg.memio_start = priv->pci_area;
+ grpci_auto_cfg.memio_size = priv->pci_area_end - priv->pci_area;
+ grpci_auto_cfg.io_start = priv->pci_io;
+ grpci_auto_cfg.io_size = priv->pci_conf - priv->pci_io;
+ grpci_auto_cfg.irq_map = grpci_bus0_irq_map;
+ grpci_auto_cfg.irq_route = NULL; /* use standard routing */
+ pci_config_register(&grpci_auto_cfg);
+
+ if (pci_config_init()) {
+ /* PCI configuration failed */
+ return DRVMGR_FAIL;
+ }
+
+ priv->config.maps_down = &priv->maps_down[0];
+ priv->config.maps_up = &priv->maps_up[0];
+ return pcibus_register(dev, &priv->config);
+}
+
+/* DMA functions which uses GRPCIs optional DMA controller (len in words) */
+int grpci_dma_to_pci(unsigned int ahb_addr, unsigned int pci_addr, unsigned int len) {
+ int ret = 0;
+
+ pcidma[0] = 0x82;
+ pcidma[1] = ahb_addr;
+ pcidma[2] = pci_addr;
+ pcidma[3] = len;
+ pcidma[0] = 0x83;
+
+ while ( (pcidma[0] & 0x4) == 0)
+ ;
+
+ if (pcidma[0] & 0x8) { /* error */
+ ret = -1;
+ }
+
+ pcidma[0] |= 0xC;
+ return ret;
+
+}
+
+int grpci_dma_from_pci(unsigned int ahb_addr, unsigned int pci_addr, unsigned int len) {
+ int ret = 0;
+
+ pcidma[0] = 0x80;
+ pcidma[1] = ahb_addr;
+ pcidma[2] = pci_addr;
+ pcidma[3] = len;
+ pcidma[0] = 0x81;
+
+ while ( (pcidma[0] & 0x4) == 0)
+ ;
+
+ if (pcidma[0] & 0x8) { /* error */
+ ret = -1;
+ }
+
+ pcidma[0] |= 0xC;
+ return ret;
+
+}
diff --git a/c/src/lib/libbsp/sparc/shared/pci/grpci2.c b/c/src/lib/libbsp/sparc/shared/pci/grpci2.c
new file mode 100644
index 0000000000..0745b3a741
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/pci/grpci2.c
@@ -0,0 +1,906 @@
+/* GRLIB GRPCI2 PCI HOST driver.
+ *
+ * COPYRIGHT (c) 2011
+ * Aeroflex Gaisler AB.
+ *
+ * Configures the GRPCI2 core and initialize,
+ * - the PCI Library (pci.c)
+ * - the general part of the PCI Bus driver (pci_bus.c)
+ *
+ * System interrupt assigned to PCI interrupt (INTA#..INTD#) is by
+ * default taken from Plug and Play, but may be overridden by the
+ * driver resources INTA#..INTD#. GRPCI2 handles differently depending
+ * on the design (4 different ways).
+ *
+ * The license and distribution terms for this file may be
+ * found in found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2011-02-04, Daniel Hellstrom <daniel@gaisler.com>
+ * Created
+ *
+ *
+ * GRPCI2 IRQ implementation notes
+ * -------------------------------
+ * Since the Driver Manager pci_bus layer implements IRQ by calling
+ * pci_interrupt_* which translates into BSP_shared_interrupt_*, and the
+ * root-bus also relies on BSP_shared_interrupt_*, it is safe for the GRPCI2
+ * driver to use the drvmgr_interrupt_* routines since they will be
+ * accessing the same routines in the end. Otherwise the GRPCI2 driver must
+ * have used the pci_interrupt_* routines.
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <rtems/bspIo.h>
+#include <libcpu/byteorder.h>
+#include <libcpu/access.h>
+#include <pci.h>
+#include <pci/cfg.h>
+
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+#include <ambapp.h>
+#include <drvmgr/pci_bus.h>
+#include <grpci2.h>
+
+#ifndef IRQ_GLOBAL_PREPARE
+ #define IRQ_GLOBAL_PREPARE(level) rtems_interrupt_level level
+#endif
+
+#ifndef IRQ_GLOBAL_DISABLE
+ #define IRQ_GLOBAL_DISABLE(level) rtems_interrupt_disable(level)
+#endif
+
+#ifndef IRQ_GLOBAL_ENABLE
+ #define IRQ_GLOBAL_ENABLE(level) rtems_interrupt_enable(level)
+#endif
+
+/* If defined to 1 - byte twisting is enabled by default */
+#define DEFAULT_BT_ENABLED 0
+
+/* Interrupt assignment. Set to other value than 0xff in order to
+ * override defaults and plug&play information
+ */
+#ifndef GRPCI2_INTA_SYSIRQ
+ #define GRPCI2_INTA_SYSIRQ 0xff
+#endif
+#ifndef GRPCI2_INTB_SYSIRQ
+ #define GRPCI2_INTB_SYSIRQ 0xff
+#endif
+#ifndef GRPCI2_INTC_SYSIRQ
+ #define GRPCI2_INTC_SYSIRQ 0xff
+#endif
+#ifndef GRPCI2_INTD_SYSIRQ
+ #define GRPCI2_INTD_SYSIRQ 0xff
+#endif
+
+/*#define DEBUG 1*/
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+#define PCI_INVALID_VENDORDEVICEID 0xffffffff
+#define PCI_MULTI_FUNCTION 0x80
+
+/*
+ * GRPCI2 APB Register MAP
+ */
+struct grpci2_regs {
+ volatile unsigned int ctrl; /* 0x00 */
+ volatile unsigned int sts_cap; /* 0x04 */
+ int res1; /* 0x08 */
+ volatile unsigned int io_map; /* 0x0C */
+ volatile unsigned int dma_ctrl; /* 0x10 */
+ volatile unsigned int dma_bdbase; /* 0x14 */
+ int res2[2]; /* 0x18 */
+ volatile unsigned int bars[6]; /* 0x20 */
+ int res3[2]; /* 0x38 */
+ volatile unsigned int ahbmst_map[16]; /* 0x40 */
+};
+
+#define CTRL_BUS_BIT 16
+
+#define CTRL_SI (1<<27)
+#define CTRL_PE (1<<26)
+#define CTRL_EI (1<<25)
+#define CTRL_ER (1<<24)
+#define CTRL_BUS (0xff<<CTRL_BUS_BIT)
+#define CTRL_HOSTINT 0xf
+
+#define STS_HOST_BIT 31
+#define STS_MST_BIT 30
+#define STS_TAR_BIT 29
+#define STS_DMA_BIT 28
+#define STS_DI_BIT 27
+#define STS_HI_BIT 26
+#define STS_IRQMODE_BIT 24
+#define STS_TRACE_BIT 23
+#define STS_CFGERRVALID_BIT 20
+#define STS_CFGERR_BIT 19
+#define STS_INTTYPE_BIT 12
+#define STS_INTSTS_BIT 8
+#define STS_FDEPTH_BIT 2
+#define STS_FNUM_BIT 0
+
+#define STS_HOST (1<<STS_HOST_BIT)
+#define STS_MST (1<<STS_MST_BIT)
+#define STS_TAR (1<<STS_TAR_BIT)
+#define STS_DMA (1<<STS_DMA_BIT)
+#define STS_DI (1<<STS_DI_BIT)
+#define STS_HI (1<<STS_HI_BIT)
+#define STS_IRQMODE (0x3<<STS_IRQMODE_BIT)
+#define STS_TRACE (1<<STS_TRACE_BIT)
+#define STS_CFGERRVALID (1<<STS_CFGERRVALID_BIT)
+#define STS_CFGERR (1<<STS_CFGERR_BIT)
+#define STS_INTTYPE (0x3f<<STS_INTTYPE_BIT)
+#define STS_INTSTS (0xf<<STS_INTSTS_BIT)
+#define STS_FDEPTH (0x7<<STS_FDEPTH_BIT)
+#define STS_FNUM (0x3<<STS_FNUM_BIT)
+
+#define STS_ISYSERR (1<<17)
+#define STS_IDMA (1<<16)
+#define STS_IDMAERR (1<<15)
+#define STS_IMSTABRT (1<<14)
+#define STS_ITGTABRT (1<<13)
+#define STS_IPARERR (1<<12)
+
+struct grpci2_bd_chan {
+ volatile unsigned int ctrl; /* 0x00 DMA Control */
+ volatile unsigned int nchan; /* 0x04 Next DMA Channel Address */
+ volatile unsigned int nbd; /* 0x08 Next Data Descriptor in channel */
+ volatile unsigned int res; /* 0x0C Reserved */
+};
+
+#define BD_CHAN_EN 0x80000000
+#define BD_CHAN_TYPE 0x00300000
+#define BD_CHAN_BDCNT 0x0000ffff
+#define BD_CHAN_EN_BIT 31
+#define BD_CHAN_TYPE_BIT 20
+#define BD_CHAN_BDCNT_BIT 0
+
+struct grpci2_bd_data {
+ volatile unsigned int ctrl; /* 0x00 DMA Data Control */
+ volatile unsigned int pci_adr; /* 0x04 PCI Start Address */
+ volatile unsigned int ahb_adr; /* 0x08 AHB Start address */
+ volatile unsigned int next; /* 0x0C Next Data Descriptor in channel */
+};
+
+#define BD_DATA_EN 0x80000000
+#define BD_DATA_IE 0x40000000
+#define BD_DATA_DR 0x20000000
+#define BD_DATA_TYPE 0x00300000
+#define BD_DATA_ER 0x00080000
+#define BD_DATA_LEN 0x0000ffff
+#define BD_DATA_EN_BIT 31
+#define BD_DATA_IE_BIT 30
+#define BD_DATA_DR_BIT 29
+#define BD_DATA_TYPE_BIT 20
+#define BD_DATA_ER_BIT 19
+#define BD_DATA_LEN_BIT 0
+
+/* GRPCI2 Capability */
+struct grpci2_cap_first {
+ unsigned int ctrl;
+ unsigned int pci2ahb_map[6];
+ unsigned int ext2ahb_map;
+ unsigned int io_map;
+ unsigned int pcibar_size[6];
+};
+#define CAP9_CTRL_OFS 0
+#define CAP9_BAR_OFS 0x4
+#define CAP9_IOMAP_OFS 0x20
+#define CAP9_BARSIZE_OFS 0x24
+
+struct grpci2_priv *grpci2priv = NULL;
+
+/* PCI Interrupt assignment. Connects an PCI interrupt pin (INTA#..INTD#)
+ * to a system interrupt number.
+ */
+unsigned char grpci2_pci_irq_table[4] =
+{
+ /* INTA# */ GRPCI2_INTA_SYSIRQ,
+ /* INTB# */ GRPCI2_INTB_SYSIRQ,
+ /* INTC# */ GRPCI2_INTC_SYSIRQ,
+ /* INTD# */ GRPCI2_INTD_SYSIRQ
+};
+
+/* Start of workspace/dynamical area */
+extern unsigned int _end;
+#define DMA_START ((unsigned int) &_end)
+
+/* Default BAR mapping, set BAR0 256MB 1:1 mapped base of CPU RAM */
+struct grpci2_pcibar_cfg grpci2_default_bar_mapping[6] = {
+ /* BAR0 */ {DMA_START, DMA_START, 0x10000000},
+ /* BAR1 */ {0, 0, 0},
+ /* BAR2 */ {0, 0, 0},
+ /* BAR3 */ {0, 0, 0},
+ /* BAR4 */ {0, 0, 0},
+ /* BAR5 */ {0, 0, 0},
+};
+
+/* Driver private data struture */
+struct grpci2_priv {
+ struct drvmgr_dev *dev;
+ struct grpci2_regs *regs;
+ char irq;
+ char irq_mode; /* IRQ Mode from CAPSTS REG */
+ char bt_enabled;
+ unsigned int irq_mask;
+
+ struct grpci2_pcibar_cfg *barcfg;
+
+ unsigned int pci_area;
+ unsigned int pci_area_end;
+ unsigned int pci_io;
+ unsigned int pci_conf;
+ unsigned int pci_conf_end;
+
+ uint32_t devVend; /* Host PCI Device/Vendor ID */
+
+ struct drvmgr_map_entry maps_up[7];
+ struct drvmgr_map_entry maps_down[2];
+ struct pcibus_config config;
+};
+
+int grpci2_init1(struct drvmgr_dev *dev);
+int grpci2_init3(struct drvmgr_dev *dev);
+
+/* GRPCI2 DRIVER */
+
+struct drvmgr_drv_ops grpci2_ops =
+{
+ .init = {grpci2_init1, NULL, grpci2_init3, NULL},
+ .remove = NULL,
+ .info = NULL
+};
+
+struct amba_dev_id grpci2_ids[] =
+{
+ {VENDOR_GAISLER, GAISLER_GRPCI2},
+ {0, 0} /* Mark end of table */
+};
+
+struct amba_drv_info grpci2_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_AMBAPP_GAISLER_GRPCI2_ID,/* Driver ID */
+ "GRPCI2_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */
+ &grpci2_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ sizeof(struct grpci2_priv), /* Make drvmgr alloc private */
+ },
+ &grpci2_ids[0]
+};
+
+void grpci2_register_drv(void)
+{
+ DBG("Registering GRPCI2 driver\n");
+ drvmgr_drv_register(&grpci2_info.general);
+}
+
+int grpci2_cfg_r32(pci_dev_t dev, int ofs, uint32_t *val)
+{
+ struct grpci2_priv *priv = grpci2priv;
+ volatile uint32_t *pci_conf;
+ unsigned int tmp, devfn;
+ IRQ_GLOBAL_PREPARE(oldLevel);
+ int retval, bus = PCI_DEV_BUS(dev);
+
+ if ((unsigned int)ofs & 0xffffff03) {
+ retval = PCISTS_EINVAL;
+ goto out2;
+ }
+
+ if (PCI_DEV_SLOT(dev) > 15) {
+ retval = PCISTS_MSTABRT;
+ goto out;
+ }
+
+ /* GRPCI2 can access "non-standard" devices on bus0 (on AD11.AD16),
+ * we skip them.
+ */
+ if (bus == 0 && PCI_DEV_SLOT(dev) != 0)
+ devfn = PCI_DEV_DEVFUNC(dev) + PCI_DEV(0, 6, 0);
+ else
+ devfn = PCI_DEV_DEVFUNC(dev);
+
+ pci_conf = (volatile uint32_t *) (priv->pci_conf | (devfn << 8) | ofs);
+
+ IRQ_GLOBAL_DISABLE(oldLevel); /* protect regs */
+
+ /* Select bus */
+ priv->regs->ctrl = (priv->regs->ctrl & ~(0xff<<16)) | (bus<<16);
+ /* clear old status */
+ priv->regs->sts_cap = (STS_CFGERR | STS_CFGERRVALID);
+
+ tmp = *pci_conf;
+
+ /* Wait until GRPCI2 signals that CFG access is done, it should be
+ * done instantaneously unless a DMA operation is ongoing...
+ */
+ while ((priv->regs->sts_cap & STS_CFGERRVALID) == 0)
+ ;
+
+ if (priv->regs->sts_cap & STS_CFGERR) {
+ retval = PCISTS_MSTABRT;
+ } else {
+ /* Bus always little endian (unaffected by byte-swapping) */
+ *val = CPU_swap_u32(tmp);
+ retval = PCISTS_OK;
+ }
+
+ IRQ_GLOBAL_ENABLE(oldLevel);
+
+out:
+ if (retval != PCISTS_OK)
+ *val = 0xffffffff;
+
+ DBG("pci_read: [%x:%x:%x] reg: 0x%x => addr: 0x%x, val: 0x%x (%d)\n",
+ PCI_DEV_EXPAND(dev), ofs, pci_conf, *val, retval);
+
+out2:
+ return retval;
+}
+
+int grpci2_cfg_r16(pci_dev_t dev, int ofs, uint16_t *val)
+{
+ uint32_t v;
+ int retval;
+
+ if (ofs & 1)
+ return PCISTS_EINVAL;
+
+ retval = grpci2_cfg_r32(dev, ofs & ~0x3, &v);
+ *val = 0xffff & (v >> (8*(ofs & 0x3)));
+
+ return retval;
+}
+
+int grpci2_cfg_r8(pci_dev_t dev, int ofs, uint8_t *val)
+{
+ uint32_t v;
+ int retval;
+
+ retval = grpci2_cfg_r32(dev, ofs & ~0x3, &v);
+
+ *val = 0xff & (v >> (8*(ofs & 3)));
+
+ return retval;
+}
+
+int grpci2_cfg_w32(pci_dev_t dev, int ofs, uint32_t val)
+{
+ struct grpci2_priv *priv = grpci2priv;
+ volatile uint32_t *pci_conf;
+ uint32_t value, devfn;
+ int retval, bus = PCI_DEV_BUS(dev);
+ IRQ_GLOBAL_PREPARE(oldLevel);
+
+ if ((unsigned int)ofs & 0xffffff03)
+ return PCISTS_EINVAL;
+
+ if (PCI_DEV_SLOT(dev) > 15)
+ return PCISTS_MSTABRT;
+
+ value = CPU_swap_u32(val);
+
+ /* GRPCI2 can access "non-standard" devices on bus0 (on AD11.AD16),
+ * we skip them.
+ */
+ if (bus == 0 && PCI_DEV_SLOT(dev) != 0)
+ devfn = PCI_DEV_DEVFUNC(dev) + PCI_DEV(0, 6, 0);
+ else
+ devfn = PCI_DEV_DEVFUNC(dev);
+
+ pci_conf = (volatile uint32_t *) (priv->pci_conf | (devfn << 8) | ofs);
+
+ IRQ_GLOBAL_DISABLE(oldLevel); /* protect regs */
+
+ /* Select bus */
+ priv->regs->ctrl = (priv->regs->ctrl & ~(0xff<<16)) | (bus<<16);
+ /* clear old status */
+ priv->regs->sts_cap = (STS_CFGERR | STS_CFGERRVALID);
+
+ *pci_conf = value;
+
+ /* Wait until GRPCI2 signals that CFG access is done, it should be
+ * done instantaneously unless a DMA operation is ongoing...
+ */
+ while ((priv->regs->sts_cap & STS_CFGERRVALID) == 0)
+ ;
+
+ if (priv->regs->sts_cap & STS_CFGERR)
+ retval = PCISTS_MSTABRT;
+ else
+ retval = PCISTS_OK;
+
+ IRQ_GLOBAL_ENABLE(oldLevel);
+
+ DBG("pci_write - [%x:%x:%x] reg: 0x%x => addr: 0x%x, val: 0x%x (%d)\n",
+ PCI_DEV_EXPAND(dev), ofs, pci_conf, value, retval);
+
+ return retval;
+}
+
+int grpci2_cfg_w16(pci_dev_t dev, int ofs, uint16_t val)
+{
+ uint32_t v;
+ int retval;
+
+ if (ofs & 1)
+ return PCISTS_EINVAL;
+
+ retval = grpci2_cfg_r32(dev, ofs & ~0x3, &v);
+ if (retval != PCISTS_OK)
+ return retval;
+
+ v = (v & ~(0xffff << (8*(ofs&3)))) | ((0xffff&val) << (8*(ofs&3)));
+
+ return grpci2_cfg_w32(dev, ofs & ~0x3, v);
+}
+
+int grpci2_cfg_w8(pci_dev_t dev, int ofs, uint8_t val)
+{
+ uint32_t v;
+ int retval;
+
+ retval = grpci2_cfg_r32(dev, ofs & ~0x3, &v);
+ if (retval != PCISTS_OK)
+ return retval;
+
+ v = (v & ~(0xff << (8*(ofs&3)))) | ((0xff&val) << (8*(ofs&3)));
+
+ return grpci2_cfg_w32(dev, ofs & ~0x3, v);
+}
+
+/* Return the assigned system IRQ number that corresponds to the PCI
+ * "Interrupt Pin" information from configuration space.
+ *
+ * The IRQ information is stored in the grpci2_pci_irq_table configurable
+ * by the user.
+ *
+ * Returns the "system IRQ" for the PCI INTA#..INTD# pin in irq_pin. Returns
+ * 0xff if not assigned.
+ */
+uint8_t grpci2_bus0_irq_map(pci_dev_t dev, int irq_pin)
+{
+ uint8_t sysIrqNr = 0; /* not assigned */
+ int irq_group;
+
+ if ( (irq_pin >= 1) && (irq_pin <= 4) ) {
+ /* Use default IRQ decoding on PCI BUS0 according slot numbering */
+ irq_group = PCI_DEV_SLOT(dev) & 0x3;
+ irq_pin = ((irq_pin - 1) + irq_group) & 0x3;
+ /* Valid PCI "Interrupt Pin" number */
+ sysIrqNr = grpci2_pci_irq_table[irq_pin];
+ }
+ return sysIrqNr;
+}
+
+int grpci2_translate(uint32_t *address, int type, int dir)
+{
+ uint32_t adr, start, end;
+ struct grpci2_priv *priv = grpci2priv;
+ int i;
+
+ if (type == 1) {
+ /* I/O */
+ if (dir != 0) {
+ /* The PCI bus can not access the CPU bus from I/O
+ * because GRPCI2 core does not support I/O BARs
+ */
+ return -1;
+ }
+
+ /* We have got a PCI IO BAR address that the CPU want to access.
+ * Check that it is within the PCI I/O window, I/O adresses
+ * are NOT mapped 1:1 with GRPCI2 driver... translation needed.
+ */
+ adr = *(uint32_t *)address;
+ if (adr < 0x100 || adr > 0x10000)
+ return -1;
+ *address = adr + priv->pci_io;
+ } else {
+ /* MEMIO and MEM.
+ * Memory space is mapped 1:1 so no translation is needed.
+ * Check that address is within accessible windows.
+ */
+ adr = *(uint32_t *)address;
+ if (dir == 0) {
+ /* PCI BAR to AMBA-CPU address.. check that it is
+ * located within GRPCI2 PCI Memory Window
+ * adr = PCI address.
+ */
+ if (adr < priv->pci_area || adr >= priv->pci_area_end)
+ return -1;
+ } else {
+ /* We have a CPU address and want to get access to it
+ * from PCI space, typically when doing DMA into CPU
+ * RAM. The GRPCI2 core may have multiple target BARs
+ * that PCI masters can access, the BARs are user
+ * configurable in the following ways:
+ * BAR_SIZE, PCI_BAR Address and MAPPING (AMBA ADR)
+ *
+ * The below code tries to find a BAR for which the
+ * AMBA bar may have been mapped onto, and translate
+ * the AMBA-CPU address into a PCI address using the
+ * given mapping.
+ *
+ * adr = AMBA address.
+ */
+ for(i=0; i<6; i++) {
+ start = priv->barcfg[i].ahbadr;
+ end = priv->barcfg[i].ahbadr +
+ priv->barcfg[i].barsize;
+ if (adr >= start && adr < end) {
+ /* BAR match: Translate address */
+ *address = (adr - start) +
+ priv->barcfg[i].pciadr;
+ return 0;
+ }
+ }
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+extern struct pci_memreg_ops pci_memreg_sparc_le_ops;
+extern struct pci_memreg_ops pci_memreg_sparc_be_ops;
+
+/* GRPCI2 PCI access routines, default to Little-endian PCI Bus */
+struct pci_access_drv grpci2_access_drv = {
+ .cfg =
+ {
+ grpci2_cfg_r8,
+ grpci2_cfg_r16,
+ grpci2_cfg_r32,
+ grpci2_cfg_w8,
+ grpci2_cfg_w16,
+ grpci2_cfg_w32,
+ },
+ .io =
+ {
+ _ld8,
+ _ld_le16,
+ _ld_le32,
+ _st8,
+ _st_le16,
+ _st_le32,
+ },
+ .memreg = &pci_memreg_sparc_le_ops,
+ .translate = grpci2_translate,
+};
+
+struct pci_io_ops grpci2_io_ops_be =
+{
+ _ld8,
+ _ld_be16,
+ _ld_be32,
+ _st8,
+ _st_be16,
+ _st_be32,
+};
+
+/* PCI Error Interrupt handler, called when there may be a PCI Target/Master
+ * Abort.
+ */
+void grpci2_err_isr(void *arg)
+{
+ struct grpci2_priv *priv = arg;
+ unsigned int sts = priv->regs->sts_cap;
+
+ if (sts & (STS_IMSTABRT | STS_ITGTABRT | STS_IPARERR | STS_ISYSERR)) {
+ /* A PCI error IRQ ... Error handler unimplemented
+ * add your code here...
+ */
+ if (sts & STS_IMSTABRT) {
+ printk("GRPCI2: unhandled Master Abort IRQ\n");
+ }
+ if (sts & STS_ITGTABRT) {
+ printk("GRPCI2: unhandled Target Abort IRQ\n");
+ }
+ if (sts & STS_IPARERR) {
+ printk("GRPCI2: unhandled Parity Error IRQ\n");
+ }
+ if (sts & STS_ISYSERR) {
+ printk("GRPCI2: unhandled System Error IRQ\n");
+ }
+ }
+}
+
+int grpci2_hw_init(struct grpci2_priv *priv)
+{
+ struct grpci2_regs *regs = priv->regs;
+ int i;
+ uint8_t capptr;
+ uint32_t data, io_map, ahbadr, pciadr, size;
+ pci_dev_t host = PCI_DEV(0, 0, 0);
+ struct grpci2_pcibar_cfg *barcfg = priv->barcfg;
+
+ /* Reset any earlier setup */
+ regs->ctrl = 0;
+ regs->sts_cap = ~0; /* Clear Status */
+ regs->dma_ctrl = 0;
+ regs->dma_bdbase = 0;
+
+ /* Translate I/O accesses 1:1, (will not work for PCI 2.3) */
+ regs->io_map = priv->pci_io & 0xffff0000;
+
+ /* set 1:1 mapping between AHB -> PCI memory space, for all Masters
+ * Each AHB master has it's own mapping registers. Max 16 AHB masters.
+ */
+ for (i=0; i<16; i++)
+ regs->ahbmst_map[i] = priv->pci_area;
+
+ /* Get the GRPCI2 Host PCI ID */
+ grpci2_cfg_r32(host, PCI_VENDOR_ID, &priv->devVend);
+
+ /* Get address to first (always defined) capability structure */
+ grpci2_cfg_r8(host, PCI_CAP_PTR, &capptr);
+ if (capptr == 0)
+ return -1;
+
+ /* Enable/Disable Byte twisting */
+ grpci2_cfg_r32(host, capptr+CAP9_IOMAP_OFS, &io_map);
+ io_map = (io_map & ~0x1) | (priv->bt_enabled ? 1 : 0);
+ grpci2_cfg_w32(host, capptr+CAP9_IOMAP_OFS, io_map);
+
+ /* Setup the Host's PCI Target BARs for others to access (DMA) */
+ for (i=0; i<6; i++) {
+ /* Make sure address is properly aligned */
+ size = ~(barcfg[i].barsize-1);
+ barcfg[i].pciadr &= size;
+ barcfg[i].ahbadr &= size;
+
+ pciadr = barcfg[i].pciadr;
+ ahbadr = barcfg[i].ahbadr;
+ size |= PCI_BASE_ADDRESS_MEM_PREFETCH;
+
+ grpci2_cfg_w32(host, capptr+CAP9_BARSIZE_OFS+i*4, size);
+ grpci2_cfg_w32(host, capptr+CAP9_BAR_OFS+i*4, ahbadr);
+ grpci2_cfg_w32(host, PCI_BASE_ADDRESS_0+i*4, pciadr);
+ }
+
+ /* set as bus master and enable pci memory responses */
+ grpci2_cfg_r32(host, PCI_COMMAND, &data);
+ data |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+ grpci2_cfg_w32(host, PCI_COMMAND, data);
+
+ /* Enable Error respone (CPU-TRAP) on illegal memory access */
+ regs->ctrl = CTRL_ER | CTRL_PE;
+
+ /* Successful */
+ return 0;
+}
+
+/* Initializes the GRPCI2 core and driver, must be called before calling
+ * init_pci()
+ *
+ * Return values
+ * 0 Successful initalization
+ * -1 Error during initialization, for example "PCI core not found".
+ * -2 Error PCI controller not HOST (targets not supported)
+ * -3 Error due to GRPCI2 hardware initialization
+ */
+int grpci2_init(struct grpci2_priv *priv)
+{
+ struct ambapp_apb_info *apb;
+ struct ambapp_ahb_info *ahb;
+ int pin, i, j;
+ union drvmgr_key_value *value;
+ char keyname[6];
+ struct amba_dev_info *ainfo = priv->dev->businfo;
+ struct grpci2_pcibar_cfg *barcfg;
+ unsigned int size;
+
+ /* Find PCI core from Plug&Play information */
+ apb = ainfo->info.apb_slv;
+ ahb = ainfo->info.ahb_slv;
+
+ /* Found PCI core, init private structure */
+ priv->irq = apb->irq;
+ priv->regs = (struct grpci2_regs *)apb->start;
+ priv->bt_enabled = DEFAULT_BT_ENABLED;
+ priv->irq_mode = (priv->regs->sts_cap & STS_IRQMODE) >> STS_IRQMODE_BIT;
+
+ /* Calculate the PCI windows
+ * AMBA->PCI Window: AHB SLAVE AREA0
+ * AMBA->PCI I/O cycles Window: AHB SLAVE AREA1 Lower half
+ * AMBA->PCI Configuration cycles Window: AHB SLAVE AREA1 Upper half
+ */
+ priv->pci_area = ahb->start[0];
+ priv->pci_area_end = ahb->start[0] + ahb->mask[0];
+ priv->pci_io = ahb->start[1];
+ priv->pci_conf = ahb->start[1] + 0x10000;
+ priv->pci_conf_end = priv->pci_conf + 0x10000;
+
+ /* On systems where PCI I/O area and configuration area is apart of the
+ * "PCI Window" the PCI Window stops at the start of the PCI I/O area
+ */
+ if ((priv->pci_io > priv->pci_area) &&
+ (priv->pci_io < (priv->pci_area_end-1))) {
+ priv->pci_area_end = priv->pci_io;
+ }
+
+ /* Init PCI interrupt assignment table to all use the interrupt routed
+ * through the GRPCI2 core.
+ */
+ strcpy(keyname, "INTX#");
+ for (pin=1; pin<5; pin++) {
+ if (grpci2_pci_irq_table[pin-1] == 0xff) {
+ if (priv->irq_mode < 2) {
+ /* PCI Interrupts are shared */
+ grpci2_pci_irq_table[pin-1] = priv->irq;
+ } else {
+ /* Unique IRQ per PCI INT Pin */
+ grpci2_pci_irq_table[pin-1] = priv->irq + pin-1;
+ }
+
+ /* User may override Both hardcoded IRQ setup and Plug & Play IRQ */
+ keyname[3] = 'A' + (pin-1);
+ value = drvmgr_dev_key_get(priv->dev, keyname, KEY_TYPE_INT);
+ if (value)
+ grpci2_pci_irq_table[pin-1] = value->i;
+ }
+
+ /* Remember which IRQs are enabled */
+ if (grpci2_pci_irq_table[pin-1] != 0)
+ priv->irq_mask |= 1 << (pin-1);
+ }
+
+ /* User may override DEFAULT_BT_ENABLED to enable/disable byte twisting */
+ value = drvmgr_dev_key_get(priv->dev, "byteTwisting", KEY_TYPE_INT);
+ if (value)
+ priv->bt_enabled = value->i;
+
+ /* Let user Configure the 6 target BARs */
+ value = drvmgr_dev_key_get(priv->dev, "tgtBarCfg", KEY_TYPE_POINTER);
+ if (value)
+ priv->barcfg = value->ptr;
+ else
+ priv->barcfg = grpci2_default_bar_mapping;
+
+ /* This driver only support HOST systems, we check that it can act as a
+ * PCI Master and that it is in the Host slot. */
+ if ((priv->regs->sts_cap&STS_HOST) || !(priv->regs->sts_cap&STS_MST))
+ return -2; /* Target not supported */
+
+ /* Init the PCI Core */
+ if (grpci2_hw_init(priv))
+ return -3;
+
+ /* Down streams translation table */
+ priv->maps_down[0].name = "AMBA -> PCI MEM Window";
+ priv->maps_down[0].size = priv->pci_area_end - priv->pci_area;
+ priv->maps_down[0].from_adr = (void *)priv->pci_area;
+ priv->maps_down[0].to_adr = (void *)priv->pci_area;
+ /* End table */
+ priv->maps_down[1].size = 0;
+
+ /* Up streams translation table */
+ /* Setup the Host's PCI Target BARs for others to access (DMA) */
+ barcfg = priv->barcfg;
+ for (i=0,j=0; i<6; i++) {
+ size = barcfg[i].barsize;
+ if (size == 0)
+ continue;
+
+ /* Make sure address is properly aligned */
+ priv->maps_up[j].name = "Target BAR[I] -> AMBA";
+ priv->maps_up[j].size = size;
+ priv->maps_up[j].from_adr = (void *)
+ (barcfg[i].pciadr & ~(size - 1));
+ priv->maps_up[j].to_adr = (void *)
+ (barcfg[i].ahbadr & ~(size - 1));
+ j++;
+ }
+
+ /* End table */
+ priv->maps_up[j].size = 0;
+
+ return 0;
+}
+
+/* Called when a core is found with the AMBA device and vendor ID
+ * given in grpci2_ids[]. IRQ, Console does not work here
+ */
+int grpci2_init1(struct drvmgr_dev *dev)
+{
+ int status;
+ struct grpci2_priv *priv;
+ struct pci_auto_setup grpci2_auto_cfg;
+
+ DBG("GRPCI2[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
+
+ if (grpci2priv) {
+ DBG("Driver only supports one PCI core\n");
+ return DRVMGR_FAIL;
+ }
+
+ if ((strcmp(dev->parent->dev->drv->name, "AMBAPP_GRLIB_DRV") != 0) &&
+ (strcmp(dev->parent->dev->drv->name, "AMBAPP_LEON2_DRV") != 0)) {
+ /* We only support GRPCI2 driver on local bus */
+ return DRVMGR_FAIL;
+ }
+
+ priv = dev->priv;
+ if (!priv)
+ return DRVMGR_NOMEM;
+
+ priv->dev = dev;
+ grpci2priv = priv;
+
+ /* Initialize GRPCI2 Hardware */
+ status = grpci2_init(priv);
+ if (status) {
+ printf("Failed to initialize grpci2 driver %d\n", status);
+ return -1;
+ }
+
+ /* Register the PCI core at the PCI layers */
+
+ if (priv->bt_enabled == 0) {
+ /* Host is Big-Endian */
+ pci_endian = PCI_BIG_ENDIAN;
+
+ memcpy(&grpci2_access_drv.io, &grpci2_io_ops_be,
+ sizeof(grpci2_io_ops_be));
+ grpci2_access_drv.memreg = &pci_memreg_sparc_be_ops;
+ }
+
+ if (pci_access_drv_register(&grpci2_access_drv)) {
+ /* Access routines registration failed */
+ return DRVMGR_FAIL;
+ }
+
+ /* Prepare memory MAP */
+ grpci2_auto_cfg.options = 0;
+ grpci2_auto_cfg.mem_start = 0;
+ grpci2_auto_cfg.mem_size = 0;
+ grpci2_auto_cfg.memio_start = priv->pci_area;
+ grpci2_auto_cfg.memio_size = priv->pci_area_end - priv->pci_area;
+ grpci2_auto_cfg.io_start = 0x100; /* avoid PCI address 0 */
+ grpci2_auto_cfg.io_size = 0x10000 - 0x100; /* lower 64kB I/O 16 */
+ grpci2_auto_cfg.irq_map = grpci2_bus0_irq_map;
+ grpci2_auto_cfg.irq_route = NULL; /* use standard routing */
+ pci_config_register(&grpci2_auto_cfg);
+
+ if (pci_config_init()) {
+ /* PCI configuration failed */
+ return DRVMGR_FAIL;
+ }
+
+ /* Initialize/Register Driver Manager PCI Bus */
+ priv->config.maps_down = &priv->maps_down[0];
+ priv->config.maps_up = &priv->maps_up[0];
+ return pcibus_register(dev, &priv->config);
+}
+
+int grpci2_init3(struct drvmgr_dev *dev)
+{
+ struct grpci2_priv *priv = dev->priv;
+
+ /* Install and Enable PCI Error interrupt handler */
+ drvmgr_interrupt_register(dev, 0, "grpci2", grpci2_err_isr, priv);
+
+ /* Unmask Error IRQ and all PCI interrupts at PCI Core. For this to be
+ * safe every PCI board have to be resetted (no IRQ generation) before
+ * Global IRQs are enabled (Init is reached or similar)
+ */
+ priv->regs->ctrl |= (CTRL_EI | priv->irq_mask);
+
+ return DRVMGR_OK;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/pci/pci_memreg_sparc_be.c b/c/src/lib/libbsp/sparc/shared/pci/pci_memreg_sparc_be.c
new file mode 100644
index 0000000000..714c978dcb
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/pci/pci_memreg_sparc_be.c
@@ -0,0 +1,19 @@
+/* Registers-over-Memory Space - SPARC Big endian PCI bus definitions */
+
+#include <pci.h>
+#include <libcpu/access.h>
+
+struct pci_memreg_ops pci_memreg_sparc_be_ops = {
+ .ld8 = _ld8,
+ .st8 = _st8,
+
+ .ld_le16 = _ld_be16,
+ .st_le16 = _st_be16,
+ .ld_be16 = _ld_le16,
+ .st_be16 = _st_le16,
+
+ .ld_le32 = _ld_be32,
+ .st_le32 = _st_be32,
+ .ld_be32 = _ld_le32,
+ .st_be32 = _st_le16,
+};
diff --git a/c/src/lib/libbsp/sparc/shared/pci/pci_memreg_sparc_le.c b/c/src/lib/libbsp/sparc/shared/pci/pci_memreg_sparc_le.c
new file mode 100644
index 0000000000..357643ed39
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/pci/pci_memreg_sparc_le.c
@@ -0,0 +1,19 @@
+/* Registers-over-Memory Space - SPARC Little endian PCI bus definitions */
+
+#include <pci.h>
+#include <libcpu/access.h>
+
+struct pci_memreg_ops pci_memreg_sparc_le_ops = {
+ .ld8 = _ld8,
+ .st8 = _st8,
+
+ .ld_le16 = _ld_le16,
+ .st_le16 = _st_le16,
+ .ld_be16 = _ld_be16,
+ .st_be16 = _st_be16,
+
+ .ld_le32 = _ld_le32,
+ .st_le32 = _st_le32,
+ .ld_be32 = _ld_be32,
+ .st_be32 = _st_be16,
+};
diff --git a/c/src/lib/libbsp/sparc/shared/pci/pcif.c b/c/src/lib/libbsp/sparc/shared/pci/pcif.c
new file mode 100644
index 0000000000..3f37107293
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/pci/pcif.c
@@ -0,0 +1,567 @@
+/* GRLIB PCIF PCI HOST driver.
+ *
+ * COPYRIGHT (c) 2008.
+ * Aeroflex Gaisler AB.
+ *
+ * Configures the PCIF core and initialize,
+ * - the PCI Library (pci.c)
+ * - the general part of the PCI Bus driver (pci_bus.c)
+ *
+ * System interrupt assigned to PCI interrupt (INTA#..INTD#) is by
+ * default taken from Plug and Play, but may be overridden by the
+ * driver resources INTA#..INTD#.
+ *
+ * The license and distribution terms for this file may be
+ * found in found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2008-12-06, Daniel Hellstrom <daniel@gaisler.com>
+ * Created
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libcpu/byteorder.h>
+#include <libcpu/access.h>
+#include <pci.h>
+#include <pci/cfg.h>
+
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+#include <ambapp.h>
+#include <drvmgr/pci_bus.h>
+
+#include <pci.h>
+#include <rtems/bspIo.h>
+#include <string.h>
+
+/* Configuration options */
+#define SYSTEM_MAINMEM_START 0x40000000
+
+/* Interrupt assignment. Set to other value than 0xff in order to
+ * override defaults and plug&play information
+ */
+#ifndef PCIF_INTA_SYSIRQ
+ #define PCIF_INTA_SYSIRQ 0xff
+#endif
+#ifndef PCIF_INTB_SYSIRQ
+ #define PCIF_INTB_SYSIRQ 0xff
+#endif
+#ifndef PCIF_INTC_SYSIRQ
+ #define PCIF_INTC_SYSIRQ 0xff
+#endif
+#ifndef PCIF_INTD_SYSIRQ
+ #define PCIF_INTD_SYSIRQ 0xff
+#endif
+
+/*#define DEBUG 1 */
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+/*
+ * Bit encode for PCI_CONFIG_HEADER_TYPE register
+ */
+struct pcif_regs {
+ volatile unsigned int bars[4]; /* 0x00-0x10 */
+ volatile unsigned int bus; /* 0x10 */
+ volatile unsigned int map_io; /* 0x14 */
+ volatile unsigned int status; /* 0x18 */
+ volatile unsigned int intr; /* 0x1c */
+ int unused[(0x40-0x20)/4]; /* 0x20-0x40 */
+ volatile unsigned int maps[(0x80-0x40)/4]; /* 0x40-0x80*/
+};
+
+struct pcif_priv *pcifpriv = NULL;
+static int pcif_minor = 0;
+
+/* PCI Interrupt assignment. Connects an PCI interrupt pin (INTA#..INTD#)
+ * to a system interrupt number.
+ */
+unsigned char pcif_pci_irq_table[4] =
+{
+ /* INTA# */ PCIF_INTA_SYSIRQ,
+ /* INTB# */ PCIF_INTB_SYSIRQ,
+ /* INTC# */ PCIF_INTC_SYSIRQ,
+ /* INTD# */ PCIF_INTD_SYSIRQ
+};
+
+/* Driver private data struture */
+struct pcif_priv {
+ struct drvmgr_dev *dev;
+ struct pcif_regs *regs;
+ int irq;
+ int minor;
+ int irq_mask;
+
+ unsigned int pci_area;
+ unsigned int pci_area_end;
+ unsigned int pci_io;
+ unsigned int pci_conf;
+ unsigned int pci_conf_end;
+
+ uint32_t devVend; /* Host PCI Vendor/Device ID */
+ uint32_t bar1_size;
+
+ struct drvmgr_map_entry maps_up[2];
+ struct drvmgr_map_entry maps_down[2];
+ struct pcibus_config config;
+};
+
+int pcif_init1(struct drvmgr_dev *dev);
+int pcif_init3(struct drvmgr_dev *dev);
+
+/* PCIF DRIVER */
+
+struct drvmgr_drv_ops pcif_ops =
+{
+ .init = {pcif_init1, NULL, pcif_init3, NULL},
+ .remove = NULL,
+ .info = NULL
+};
+
+struct amba_dev_id pcif_ids[] =
+{
+ {VENDOR_GAISLER, GAISLER_PCIF},
+ {0, 0} /* Mark end of table */
+};
+
+struct amba_drv_info pcif_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_AMBAPP_GAISLER_PCIF_ID, /* Driver ID */
+ "PCIF_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */
+ &pcif_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ sizeof(struct pcif_priv), /* Let drvmgr alloc private */
+ },
+ &pcif_ids[0]
+};
+
+void pcif_register_drv(void)
+{
+ DBG("Registering PCIF driver\n");
+ drvmgr_drv_register(&pcif_info.general);
+}
+
+int pcif_cfg_r32(pci_dev_t dev, int ofs, uint32_t *val)
+{
+ struct pcif_priv *priv = pcifpriv;
+ volatile uint32_t *pci_conf;
+ unsigned int devfn = PCI_DEV_DEVFUNC(dev);
+ int retval;
+ int bus = PCI_DEV_BUS(dev);
+
+ if (ofs & 3)
+ return PCISTS_EINVAL;
+
+ if (PCI_DEV_SLOT(dev) > 21) {
+ *val = 0xffffffff;
+ return PCISTS_OK;
+ }
+
+ /* Select bus */
+ priv->regs->bus = bus << 16;
+
+ pci_conf = (volatile uint32_t *)(priv->pci_conf | (devfn << 8) | ofs);
+
+ *val = *pci_conf;
+
+ if (priv->regs->status & 0x30000000) {
+ *val = 0xffffffff;
+ retval = PCISTS_MSTABRT;
+ } else
+ retval = PCISTS_OK;
+
+ DBG("pci_read: [%x:%x:%x] reg: 0x%x => addr: 0x%x, val: 0x%x\n",
+ PCI_DEV_EXPAND(dev), ofs, pci_conf, *val);
+
+ return retval;
+}
+int pcif_cfg_r16(pci_dev_t dev, int ofs, uint16_t *val)
+{
+ uint32_t v;
+ int retval;
+
+ if (ofs & 1)
+ return PCISTS_EINVAL;
+
+ retval = pcif_cfg_r32(dev, ofs & ~0x3, &v);
+ *val = 0xffff & (v >> (8*(ofs & 0x3)));
+
+ return retval;
+}
+
+int pcif_cfg_r8(pci_dev_t dev, int ofs, uint8_t *val)
+{
+ uint32_t v;
+ int retval;
+
+ retval = pcif_cfg_r32(dev, ofs & ~0x3, &v);
+
+ *val = 0xff & (v >> (8*(ofs & 3)));
+
+ return retval;
+}
+
+int pcif_cfg_w32(pci_dev_t dev, int ofs, uint32_t val)
+{
+ struct pcif_priv *priv = pcifpriv;
+ volatile uint32_t *pci_conf;
+ uint32_t devfn = PCI_DEV_DEVFUNC(dev);
+ int bus = PCI_DEV_BUS(dev);
+
+ if (ofs & ~0xfc)
+ return PCISTS_EINVAL;
+
+ if (PCI_DEV_SLOT(dev) > 21)
+ return PCISTS_MSTABRT;
+
+ /* Select bus */
+ priv->regs->bus = bus << 16;
+
+ pci_conf = (volatile uint32_t *)(priv->pci_conf | (devfn << 8) | ofs);
+
+ *pci_conf = val;
+
+ DBG("pci_write - [%x:%x:%x] reg: 0x%x => addr: 0x%x, val: 0x%x\n",
+ PCI_DEV_EXPAND(dev), ofs, pci_conf, value);
+
+ return PCISTS_OK;
+}
+
+int pcif_cfg_w16(pci_dev_t dev, int ofs, uint16_t val)
+{
+ uint32_t v;
+ int retval;
+
+ if (ofs & 1)
+ return PCISTS_EINVAL;
+
+ retval = pcif_cfg_r32(dev, ofs & ~0x3, &v);
+ if (retval != PCISTS_OK)
+ return retval;
+
+ v = (v & ~(0xffff << (8*(ofs&3)))) | ((0xffff&val) << (8*(ofs&3)));
+
+ return pcif_cfg_w32(dev, ofs & ~0x3, v);
+}
+
+int pcif_cfg_w8(pci_dev_t dev, int ofs, uint8_t val)
+{
+ uint32_t v;
+ int retval;
+
+ retval = pcif_cfg_r32(dev, ofs & ~0x3, &v);
+ if (retval != PCISTS_OK)
+ return retval;
+
+ v = (v & ~(0xff << (8*(ofs&3)))) | ((0xff&val) << (8*(ofs&3)));
+
+ return pcif_cfg_w32(dev, ofs & ~0x3, v);
+}
+
+
+/* Return the assigned system IRQ number that corresponds to the PCI
+ * "Interrupt Pin" information from configuration space.
+ *
+ * The IRQ information is stored in the pcif_pci_irq_table configurable
+ * by the user.
+ *
+ * Returns the "system IRQ" for the PCI INTA#..INTD# pin in irq_pin. Returns
+ * 0xff if not assigned.
+ */
+uint8_t pcif_bus0_irq_map(pci_dev_t dev, int irq_pin)
+{
+ uint8_t sysIrqNr = 0; /* not assigned */
+ int irq_group;
+
+ if ( (irq_pin >= 1) && (irq_pin <= 4) ) {
+ /* Use default IRQ decoding on PCI BUS0 according slot numbering */
+ irq_group = PCI_DEV_SLOT(dev) & 0x3;
+ irq_pin = ((irq_pin - 1) + irq_group) & 0x3;
+ /* Valid PCI "Interrupt Pin" number */
+ sysIrqNr = pcif_pci_irq_table[irq_pin];
+ }
+ return sysIrqNr;
+}
+
+int pcif_translate(uint32_t *address, int type, int dir)
+{
+ /* No address translation implmented at this point */
+ return 0;
+}
+
+extern struct pci_memreg_ops pci_memreg_sparc_be_ops;
+
+/* PCIF Big-Endian PCI access routines */
+struct pci_access_drv pcif_access_drv = {
+ .cfg =
+ {
+ pcif_cfg_r8,
+ pcif_cfg_r16,
+ pcif_cfg_r32,
+ pcif_cfg_w8,
+ pcif_cfg_w16,
+ pcif_cfg_w32,
+ },
+ .io = /* PCIF only supports Big-endian */
+ {
+ _ld8,
+ _ld_be16,
+ _ld_be32,
+ _st8,
+ _st_be16,
+ _st_be32,
+ },
+ .memreg = &pci_memreg_sparc_be_ops,
+ .translate = pcif_translate,
+};
+
+/* Initializes the PCIF core hardware
+ *
+ */
+int pcif_hw_init(struct pcif_priv *priv)
+{
+ struct pcif_regs *regs;
+ uint32_t data, size;
+ int mst;
+ pci_dev_t host = PCI_DEV(0, 0, 0);
+
+ regs = priv->regs;
+
+ /* Mask PCI interrupts */
+ regs->intr = 0;
+
+ /* Get the PCIF Host PCI ID */
+ pcif_cfg_r32(host, PCI_VENDOR_ID, &priv->devVend);
+
+ /* set 1:1 mapping between AHB -> PCI memory space, for all Master cores */
+ for ( mst=0; mst<16; mst++) {
+ regs->maps[mst] = priv->pci_area;
+
+ /* Check if this register is implemented */
+ if ( regs->maps[mst] != priv->pci_area )
+ break;
+ }
+
+ /* and map system RAM at pci address SYSTEM_MAINMEM_START. This way
+ * PCI targets can do DMA directly into CPU main memory.
+ */
+ regs->bars[0] = SYSTEM_MAINMEM_START;
+ regs->bars[1] = 0;
+ regs->bars[2] = 0;
+ regs->bars[3] = 0;
+
+ /* determine size of target BAR1 */
+ pcif_cfg_w32(host, PCI_BASE_ADDRESS_1, 0xffffffff);
+ pcif_cfg_r32(host, PCI_BASE_ADDRESS_1, &size);
+ priv->bar1_size = (~(size & ~0xf)) + 1;
+
+ pcif_cfg_w32(host, PCI_BASE_ADDRESS_0, 0);
+ pcif_cfg_w32(host, PCI_BASE_ADDRESS_1, SYSTEM_MAINMEM_START);
+ pcif_cfg_w32(host, PCI_BASE_ADDRESS_2, 0);
+ pcif_cfg_w32(host, PCI_BASE_ADDRESS_3, 0);
+ pcif_cfg_w32(host, PCI_BASE_ADDRESS_4, 0);
+ pcif_cfg_w32(host, PCI_BASE_ADDRESS_5, 0);
+
+ /* set as bus master and enable pci memory responses */
+ pcif_cfg_r32(host, PCI_COMMAND, &data);
+ data |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+ pcif_cfg_w32(host, PCI_COMMAND, data);
+
+ /* Successful */
+ return 0;
+}
+
+/* Initializes the PCIF core and driver, must be called before calling init_pci()
+ *
+ * Return values
+ * 0 Successful initalization
+ * -1 Error during initialization, for example "PCI core not found".
+ * -2 Error PCI controller not HOST (targets not supported)
+ * -3 Error due to PCIF hardware initialization
+ * -4 Error registering driver to PCI layer
+ */
+int pcif_init(struct pcif_priv *priv)
+{
+ struct ambapp_apb_info *apb;
+ struct ambapp_ahb_info *ahb;
+ int pin;
+ union drvmgr_key_value *value;
+ char keyname[6];
+ struct amba_dev_info *ainfo = priv->dev->businfo;
+
+ /* Find PCI core from Plug&Play information */
+ apb = ainfo->info.apb_slv;
+ ahb = ainfo->info.ahb_slv;
+
+ /* Found PCI core, init private structure */
+ priv->irq = apb->irq;
+ priv->regs = (struct pcif_regs *)apb->start;
+
+ /* Calculate the PCI windows
+ * AMBA->PCI Window: AHB SLAVE AREA0
+ * AMBA->PCI I/O cycles Window: AHB SLAVE AREA1 Lower half
+ * AMBA->PCI Configuration cycles Window: AHB SLAVE AREA1 Upper half
+ */
+ priv->pci_area = ahb->start[0];
+ priv->pci_area_end = ahb->start[0] + ahb->mask[0];
+ priv->pci_io = ahb->start[1];
+ priv->pci_conf = ahb->start[1] + (ahb->mask[1] >> 1);
+ priv->pci_conf_end = ahb->start[1] + ahb->mask[1];
+
+ /* On systems where PCI I/O area and configuration area is apart of the "PCI Window"
+ * the PCI Window stops at the start of the PCI I/O area
+ */
+ if ( (priv->pci_io > priv->pci_area) && (priv->pci_io < (priv->pci_area_end-1)) ) {
+ priv->pci_area_end = priv->pci_io;
+ }
+
+ /* Init PCI interrupt assignment table to all use the interrupt routed through
+ * the PCIF core.
+ */
+ strcpy(keyname, "INTX#");
+ for (pin=1; pin<5; pin++) {
+ if ( pcif_pci_irq_table[pin-1] == 0xff ) {
+ pcif_pci_irq_table[pin-1] = priv->irq;
+
+ /* User may override Plug & Play IRQ */
+ keyname[3] = 'A' + (pin-1);
+ value = drvmgr_dev_key_get(priv->dev, keyname, KEY_TYPE_INT);
+ if ( value )
+ pcif_pci_irq_table[pin-1] = value->i;
+ }
+ }
+
+ priv->irq_mask = 0xf;
+ value = drvmgr_dev_key_get(priv->dev, "", KEY_TYPE_INT);
+ if ( value )
+ priv->irq_mask = value->i & 0xf;
+
+ /* This driver only support HOST systems, we check for HOST */
+ if ( priv->regs->status & 0x00000001 ) {
+ /* Target not supported */
+ return -2;
+ }
+
+ /* Init the PCI Core */
+ if ( pcif_hw_init(priv) ) {
+ return -3;
+ }
+
+ /* Down streams translation table */
+ priv->maps_down[0].name = "AMBA -> PCI MEM Window";
+ priv->maps_down[0].size = priv->pci_area_end - priv->pci_area;
+ priv->maps_down[0].from_adr = (void *)priv->pci_area;
+ priv->maps_down[0].to_adr = (void *)priv->pci_area;
+ /* End table */
+ priv->maps_down[1].size = 0;
+
+ /* Up streams translation table */
+ priv->maps_up[0].name = "Target BAR1 -> AMBA";
+ priv->maps_up[0].size = priv->bar1_size;
+ priv->maps_up[0].from_adr = (void *)SYSTEM_MAINMEM_START;
+ priv->maps_up[0].to_adr = (void *)SYSTEM_MAINMEM_START;
+ /* End table */
+ priv->maps_up[1].size = 0;
+
+ return 0;
+}
+
+/* Called when a core is found with the AMBA device and vendor ID
+ * given in pcif_ids[].
+ */
+int pcif_init1(struct drvmgr_dev *dev)
+{
+ struct pcif_priv *priv;
+ struct pci_auto_setup pcif_auto_cfg;
+
+ DBG("PCIF[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
+
+ if ( pcif_minor != 0 ) {
+ printf("Driver only supports one PCI core\n");
+ return DRVMGR_FAIL;
+ }
+
+ priv = dev->priv;
+ if ( !priv )
+ return DRVMGR_NOMEM;
+
+ dev->priv = priv;
+ priv->dev = dev;
+ priv->minor = pcif_minor++;
+
+ pcifpriv = priv;
+ if ( pcif_init(priv) ) {
+ printf("Failed to initialize PCIF driver\n");
+ free(priv);
+ dev->priv = NULL;
+ return DRVMGR_FAIL;
+ }
+
+ /* Host is always Big-Endian */
+ pci_endian = PCI_BIG_ENDIAN;
+
+ /* Register the PCI core at the PCI layer */
+
+ if (pci_access_drv_register(&pcif_access_drv)) {
+ /* Access routines registration failed */
+ return DRVMGR_FAIL;
+ }
+
+ /* Prepare memory MAP */
+ pcif_auto_cfg.options = 0;
+ pcif_auto_cfg.mem_start = 0;
+ pcif_auto_cfg.mem_size = 0;
+ pcif_auto_cfg.memio_start = priv->pci_area;
+ pcif_auto_cfg.memio_size = priv->pci_area_end - priv->pci_area;
+ pcif_auto_cfg.io_start = priv->pci_io;
+ pcif_auto_cfg.io_size = priv->pci_conf - priv->pci_io;
+ pcif_auto_cfg.irq_map = pcif_bus0_irq_map;
+ pcif_auto_cfg.irq_route = NULL; /* use standard routing */
+ pci_config_register(&pcif_auto_cfg);
+
+ if (pci_config_init()) {
+ /* PCI configuration failed */
+ return DRVMGR_FAIL;
+ }
+
+ priv->config.maps_down = &priv->maps_down[0];
+ priv->config.maps_up = &priv->maps_up[0];
+ return pcibus_register(dev, &priv->config);
+}
+
+int pcif_init3(struct drvmgr_dev *dev)
+{
+ struct pcif_priv *priv = dev->priv;
+
+ /* Unmask all interrupts, on some sytems this
+ * might be problematic because all PCI IRQs are
+ * not connected on the PCB or used for something
+ * else. The irqMask driver resource can be used to
+ * control which PCI IRQs are used to generate the
+ * PCI system IRQ, example:
+ *
+ * 0xf - enable all (DEFAULT)
+ * 0x8 - enable one PCI irq
+ *
+ * Before unmasking PCI IRQ, all PCI boards must
+ * have been initialized and IRQ turned off to avoid
+ * system hang.
+ */
+
+ priv->regs->intr = priv->irq_mask;
+
+ return DRVMGR_OK;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/pci/pcifinddevice.c b/c/src/lib/libbsp/sparc/shared/pci/pcifinddevice.c
deleted file mode 100644
index 0047d07784..0000000000
--- a/c/src/lib/libbsp/sparc/shared/pci/pcifinddevice.c
+++ /dev/null
@@ -1,57 +0,0 @@
-
-/* Author: Till Straumann <strauman@slac.stanford.edu>, 2001 */
-
-/* find a particular PCI device
- * (we assume, the firmware configured the PCI bus[es] for us)
- *
- * pcifinddevice.c,v 1.1.4.2 2003/07/18 15:48:54 joel Exp
- */
-
-#define PCI_INVALID_VENDORDEVICEID 0xffffffff
-#define PCI_MULTI_FUNCTION 0x80
-
-#include <pci.h>
-#include <rtems/bspIo.h>
-
-int
-BSP_pciFindDevice( unsigned short vendorid, unsigned short deviceid,
- int instance, int *pbus, int *pdev, int *pfun )
-{
- unsigned int d;
- unsigned short s;
- unsigned char bus,dev,fun,hd;
-
- for (bus=0; bus<BusCountPCI(); bus++) {
- for (dev=0; dev<PCI_MAX_DEVICES; dev++) {
-
- pci_read_config_byte(bus,dev,0, PCI_HEADER_TYPE, &hd);
- hd = (hd & PCI_MULTI_FUNCTION ? PCI_MAX_FUNCTIONS : 1);
-
- for (fun=0; fun<hd; fun++) {
- /*
- * The last devfn id/slot is special; must skip it
- */
- if (PCI_MAX_DEVICES-1==dev && PCI_MAX_FUNCTIONS-1 == fun)
- break;
- (void)pci_read_config_dword(bus,dev,fun,PCI_VENDOR_ID,&d);
- if (PCI_INVALID_VENDORDEVICEID == d)
- continue;
-#ifdef PCI_DEBUG
- printk("BSP_pciFindDevice: found 0x%08x at %d/%d/%d\n",d,bus,dev,fun);
-#endif
- (void) pci_read_config_word(bus,dev,fun,PCI_VENDOR_ID,&s);
- if (vendorid != s)
- continue;
- (void) pci_read_config_word(bus,dev,fun,PCI_DEVICE_ID,&s);
- if (deviceid == s) {
- if (instance--) continue;
- *pbus=bus; *pdev=dev; *pfun=fun;
- return 0;
- }
- }
- }
- }
- return -1;
-}
-
-/* eof */
diff --git a/c/src/lib/libbsp/sparc/shared/pwm/grpwm.c b/c/src/lib/libbsp/sparc/shared/pwm/grpwm.c
new file mode 100644
index 0000000000..0727cdff4f
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/pwm/grpwm.c
@@ -0,0 +1,848 @@
+/*
+ * GRPWM PWM Driver interface.
+ *
+ * COPYRIGHT (c) 2009.
+ * Gaisler Research
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ */
+
+#include <bsp.h>
+#include <rtems/libio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <rtems/bspIo.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+#include <grpwm.h>
+#include <ambapp.h>
+
+/* #define DEBUG 1 */
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#define STATIC
+#else
+#define DBG(x...)
+#define STATIC static
+#endif
+
+/*** REGISTER LAYOUT ***/
+
+/* PWM Channel specific registers */
+struct grpwm_pwm_regs {
+ volatile unsigned int period; /* 0x00 */
+ volatile unsigned int comp; /* 0x04 */
+ volatile unsigned int dbcomp; /* 0x08 */
+ volatile unsigned int ctrl; /* 0x0C */
+};
+
+/* Core common registers */
+struct grpwm_regs {
+ volatile unsigned int ctrl; /* 0x00 */
+ volatile unsigned int scaler; /* 0x04 */
+ volatile unsigned int ipend; /* 0x08 */
+ volatile unsigned int cap1; /* 0x0C */
+ volatile unsigned int cap2; /* 0x10 */
+ volatile unsigned int wctrl; /* 0x14 */
+ int reserved0[2];
+ struct grpwm_pwm_regs pwms[8]; /* 0x20 */
+ int reserved1[(0x8000-0xA0)/4]; /* 0xA0-0x7FFC */
+ volatile unsigned int wram[0x8000/4]; /* 0x8000-0xFFFC */
+};
+
+/*** REGISTER BIT LAYOUT ***/
+
+/* CTRL REGISTER - 0x0 */
+#define GRPWM_CTRL_EN_BIT 0
+#define GRPWM_CTRL_SCSEL_BIT 8
+#define GRPWM_CTRL_NOUP_BIT 12
+#define GRPWM_CTRL_EN (1<<GRPWM_CTRL_EN_BIT)
+#define GRPWM_CTRL_SCSEL (0x7<<GRPWM_CTRL_SCSEL_BIT)
+#define GRPWM_CTRL_NOUP (0xff<<GRPWM_CTRL_NOUP_BIT)
+
+
+/* CAPABILITY1 REGISTER - 0x0C */
+#define GRPWM_CAP_NPWM_BIT 0
+#define GRPWM_CAP_PBITS_BIT 3
+#define GRPWM_CAP_SBITS_BIT 8
+#define GRPWM_CAP_NSC_BIT 13
+#define GRPWM_CAP_DBB_BIT 16
+#define GRPWM_CAP_DBSC_BIT 21
+#define GRPWM_CAP_ASY_BIT 22
+#define GRPWM_CAP_SYM_BIT 23
+#define GRPWM_CAP_SEP_BIT 25
+#define GRPWM_CAP_DCM_BIT 27
+
+#define GRPWM_CAP_NPWM (0x7<<GRPWM_CAP_NPWM_BIT)
+#define GRPWM_CAP_PBITS (0x1f<<GRPWM_CAP_PBITS_BIT)
+#define GRPWM_CAP_SBITS (0x1f<<GRPWM_CAP_SBITS_BIT)
+#define GRPWM_CAP_NSC (0x7<<GRPWM_CAP_NSC_BIT)
+#define GRPWM_CAP_DBB (0x1f<<GRPWM_CAP_DBB_BIT)
+#define GRPWM_CAP_DBSC (1<<GRPWM_CAP_DBSC_BIT)
+#define GRPWM_CAP_ASY (1<<GRPWM_CAP_ASY_BIT)
+#define GRPWM_CAP_SYM (1<<GRPWM_CAP_SYM_BIT)
+#define GRPWM_CAP_SEP (0x3<<GRPWM_CAP_SEP_BIT)
+#define GRPWM_CAP_DCM (1<<GRPWM_CAP_DCM_BIT)
+
+/* CAPABILITY2 REGISTER - 0x10 */
+#define GRPWM_CAP2_WPWM_BIT 0
+#define GRPWM_CAP2_WDBITS_BIT 1
+#define GRPWM_CAP2_WABITS_BIT 6
+#define GRPWM_CAP2_WSYNC_BIT 10
+
+#define GRPWM_CAP2_WPWM (0x1<<GRPWM_CAP2_WPWM_BIT)
+#define GRPWM_CAP2_WDBITS (0x1f<<GRPWM_CAP2_WDBITS_BIT)
+#define GRPWM_CAP2_WABITS (0xf<<GRPWM_CAP2_WABITS_BIT)
+#define GRPWM_CAP2_WSYNC (1<<GRPWM_CAP2_WSYNC_BIT)
+
+/* WAVE FORM CONFIG REGISTER - 0x14 */
+#define GRPWM_WCTRL_STOP_BIT 0
+#define GRPWM_WCTRL_WSYNC_BIT 16
+#define GRPWM_WCTRL_WSEN_BIT 29
+#define GRPWM_WCTRL_WSYNCCFG_BIT 30
+
+#define GRPWM_WCTRL_STOP (0x1fff<<GRPWM_WCTRL_STOP_BIT)
+#define GRPWM_WCTRL_WSYNC (0x1fff<<GRPWM_WCTRL_WSYNC_BIT)
+#define GRPWM_WCTRL_WSEN (0x1<<GRPWM_WCTRL_WSEN_BIT)
+#define GRPWM_WCTRL_WSYNCCFG (0x3<<GRPWM_WCTRL_WSYNCCFG_BIT)
+
+
+/* PWM CONTROL REGISTER - 0x2C, 0x3C... */
+#define GRPWM_PCTRL_EN_BIT 0
+#define GRPWM_PCTRL_POL_BIT 1
+#define GRPWM_PCTRL_PAIR_BIT 2
+#define GRPWM_PCTRL_FIX_BIT 3
+#define GRPWM_PCTRL_METH_BIT 6
+#define GRPWM_PCTRL_DCEN_BIT 8
+#define GRPWM_PCTRL_WEN_BIT 9
+#define GRPWM_PCTRL_SCSEL_BIT 10
+#define GRPWM_PCTRL_IEN_BIT 13
+#define GRPWM_PCTRL_IT_BIT 14
+#define GRPWM_PCTRL_ISC_BIT 15
+#define GRPWM_PCTRL_DBEN_BIT 21
+#define GRPWM_PCTRL_DBSC_BIT 22
+#define GRPWM_PCTRL_FLIP_BIT 26
+
+#define GRPWM_PCTRL_EN (0x1<<GRPWM_PCTRL_EN_BIT)
+#define GRPWM_PCTRL_POL (0x1<<GRPWM_PCTRL_POL_BIT)
+#define GRPWM_PCTRL_PAIR (0x1<<GRPWM_PCTRL_PAIR_BIT)
+#define GRPWM_PCTRL_FIX (0x7<<GRPWM_PCTRL_FIX_BIT)
+#define GRPWM_PCTRL_METH (0x1<<GRPWM_PCTRL_METH_BIT)
+#define GRPWM_PCTRL_DCEN (0x1<<GRPWM_PCTRL_DCEN_BIT)
+#define GRPWM_PCTRL_WEN (0x1<<GRPWM_PCTRL_WEN_BIT)
+#define GRPWM_PCTRL_SCSEL (0x7<<GRPWM_PCTRL_SCSEL_BIT)
+#define GRPWM_PCTRL_IEN (0x1<<GRPWM_PCTRL_IEN_BIT)
+#define GRPWM_PCTRL_IT (0x1<<GRPWM_PCTRL_IT_BIT)
+#define GRPWM_PCTRL_ISC (0x3f<<GRPWM_PCTRL_ISC_BIT)
+#define GRPWM_PCTRL_DBEN (0x1<<GRPWM_PCTRL_DBEN_BIT)
+#define GRPWM_PCTRL_DBSC (0xf<<GRPWM_PCTRL_DBSC_BIT)
+#define GRPWM_PCTRL_FLIP (0xf<<GRPWM_PCTRL_FLIP_BIT)
+
+/*** DRIVER PRIVATE STRUCTURE ***/
+struct grpwm_priv {
+ struct drvmgr_dev *dev;
+ struct grpwm_regs *regs;
+ char devName[32];
+ int irq;
+ int open;
+
+ /* Driver implementation */
+ char nscalers; /* Number of scalers */
+ char wave; /* If Wave form is available */
+ int wlength; /* Wave Form RAM Length */
+ int channel_cnt;
+ struct grpwm_chan_priv *channels[8];
+ rtems_id dev_sem;
+};
+
+struct grpwm_chan_priv {
+ struct grpwm_priv *common;
+ struct grpwm_pwm_regs *pwmregs;
+ /* IRQ */
+ int irqindex;
+ void (*isr)(int channel, void *arg);
+ void *isr_arg;
+};
+
+/******************* Driver Manager Part ***********************/
+
+int grpwm_device_init(struct grpwm_priv *priv);
+int grpwm_register_io(rtems_device_major_number *m);
+static int grpwm_driver_io_registered = 0;
+static rtems_device_major_number grpwm_driver_io_major = 0;
+
+int grpwm_init2(struct drvmgr_dev *dev);
+int grpwm_init3(struct drvmgr_dev *dev);
+
+struct drvmgr_drv_ops grpwm_ops =
+{
+ .init = {NULL, grpwm_init2, grpwm_init3, NULL},
+ .remove = NULL,
+ .info = NULL
+};
+
+struct amba_dev_id grpwm_ids[] =
+{
+ {VENDOR_GAISLER, GAISLER_GRPWM},
+ {0, 0} /* Mark end of table */
+};
+
+struct amba_drv_info grpwm_drv_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_AMBAPP_GAISLER_GRPWM_ID, /* Driver ID */
+ "GRPWM_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */
+ &grpwm_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ 0,
+ },
+ &grpwm_ids[0]
+};
+
+void grpwm_register_drv (void)
+{
+ DBG("Registering GRPWM driver\n");
+ drvmgr_drv_register(&grpwm_drv_info.general);
+}
+
+int grpwm_init2(struct drvmgr_dev *dev)
+{
+ struct grpwm_priv *priv;
+
+ DBG("GRPWM[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
+
+ priv = dev->priv = malloc(sizeof(struct grpwm_priv));
+ if ( !priv )
+ return DRVMGR_NOMEM;
+ memset(priv, 0, sizeof(*priv));
+ priv->dev = dev;
+
+ /* This core will not find other cores, so we wait for init2() */
+
+ return DRVMGR_OK;
+}
+
+int grpwm_init3(struct drvmgr_dev *dev)
+{
+ struct grpwm_priv *priv = dev->priv;
+ char prefix[32];
+ rtems_status_code status;
+
+ if ( !priv )
+ return DRVMGR_FAIL;
+
+ if ( grpwm_driver_io_registered == 0) {
+ /* Register the I/O driver only once for all cores */
+ if ( grpwm_register_io(&grpwm_driver_io_major) ) {
+ /* Failed to register I/O driver */
+ dev->priv = NULL;
+ return DRVMGR_FAIL;
+ }
+
+ grpwm_driver_io_registered = 1;
+ }
+
+ /* I/O system registered and initialized
+ * Now we take care of device initialization.
+ */
+ if ( grpwm_device_init(priv) ) {
+ free(dev->priv);
+ dev->priv = NULL;
+ return DRVMGR_FAIL;
+ }
+
+ /* Get Filesystem name prefix */
+ prefix[0] = '\0';
+ if ( drvmgr_get_dev_prefix(dev, prefix) ) {
+ /* Failed to get prefix, make sure of a unique FS name
+ * by using the driver minor.
+ */
+ sprintf(priv->devName, "/dev/grpwm%d", dev->minor_drv);
+ } else {
+ /* Got special prefix, this means we have a bus prefix
+ * And we should use our "bus minor"
+ */
+ sprintf(priv->devName, "/dev/%sgrpwm%d", prefix, dev->minor_bus);
+ }
+
+ /* Register Device */
+ status = rtems_io_register_name(priv->devName, grpwm_driver_io_major,
+ dev->minor_drv);
+ if (status != RTEMS_SUCCESSFUL) {
+ return DRVMGR_FAIL;
+ }
+
+ return DRVMGR_OK;
+}
+
+/******************* Driver Implementation ***********************/
+
+static rtems_device_driver grpwm_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver grpwm_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver grpwm_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver grpwm_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver grpwm_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver grpwm_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+
+#define GRPWM_DRIVER_TABLE_ENTRY { grpwm_initialize, grpwm_open, grpwm_close, grpwm_read, grpwm_write, grpwm_ioctl }
+
+static rtems_driver_address_table grpwm_driver = GRPWM_DRIVER_TABLE_ENTRY;
+
+int grpwm_register_io(rtems_device_major_number *m)
+{
+ rtems_status_code r;
+
+ if ((r = rtems_io_register_driver(0, &grpwm_driver, m)) == RTEMS_SUCCESSFUL) {
+ DBG("GRPWM driver successfully registered, major: %d\n", *m);
+ } else {
+ switch(r) {
+ case RTEMS_TOO_MANY:
+ DBG("GRPWM rtems_io_register_driver failed: RTEMS_TOO_MANY\n");
+ return -1;
+ case RTEMS_INVALID_NUMBER:
+ DBG("GRPWM rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n");
+ return -1;
+ case RTEMS_RESOURCE_IN_USE:
+ DBG("GRPWM rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n");
+ return -1;
+ default:
+ DBG("GRPWM rtems_io_register_driver failed\n");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+void grpwm_scaler_set(struct grpwm_regs *regs, int scaler, unsigned int value)
+{
+ /* Select scaler */
+ regs->ctrl = (regs->ctrl & ~GRPWM_CTRL_SCSEL) | (scaler << GRPWM_CTRL_SCSEL_BIT);
+ /* Write scaler */
+ regs->scaler = value;
+}
+
+/* Write Wave form RAM */
+void grpwm_write_wram(struct grpwm_regs *regs, unsigned int *data, int length)
+{
+ unsigned int *end;
+ volatile unsigned int *pos;
+
+ pos = &regs->wram[0];
+
+ /* Write RAM */
+ if ( data ) {
+ end = data + length;
+ while ( data < end ) {
+ *pos++ = *data++;
+ }
+ } else {
+ while( length > 0 ) {
+ *pos++ = 0;
+ length -= 4;
+ }
+ }
+}
+
+void grpwm_hw_reset(struct grpwm_priv *priv)
+{
+ int i;
+ struct grpwm_chan_priv *pwm;
+ struct grpwm_regs *regs = priv->regs;
+
+ /* Disable Core */
+ regs->ctrl = 0;
+
+ /* Clear all registers */
+ regs->ipend = 0xffffffff;
+ regs->wctrl = 0;
+
+ /* Init all PWM channels */
+ for (i=0; i<priv->channel_cnt; i++) {
+ pwm = priv->channels[i];
+ pwm->pwmregs->ctrl = 0;
+ pwm->pwmregs->period = 0;
+ pwm->pwmregs->comp = 0;
+ pwm->pwmregs->dbcomp = 0;
+ pwm->pwmregs->ctrl = 0; /* Twice because METH and POL requires EN=0 */
+ }
+
+ /* Clear RAM */
+ if ( priv->wave ) {
+ grpwm_write_wram(regs, NULL, priv->wlength);
+ }
+
+ /* Set max scaler */
+ for (i=0; i<priv->nscalers; i++) {
+ grpwm_scaler_set(regs, i, 0xffffffff);
+ }
+}
+
+/* Update one Channel but leaves the "Hold update" bit set
+ *
+ * A bit mask of updated bits are returned.
+ */
+unsigned int grpwm_update_prepare_channel(
+ struct grpwm_priv *priv,
+ int channel,
+ struct grpwm_ioctl_update_chan *up
+ )
+{
+ struct grpwm_chan_priv *pwm;
+ struct grpwm_pwm_regs *pwmregs;
+ unsigned int ctrl;
+ unsigned int ret;
+
+ pwm = priv->channels[channel];
+ pwmregs = pwm->pwmregs;
+
+ /* Read channel control register */
+ ctrl = pwmregs->ctrl;
+ ret = 0;
+
+ if ( up->options & GRPWM_UPDATE_OPTION_DISABLE ) {
+ ctrl &= ~GRPWM_PCTRL_EN;
+ pwmregs->ctrl = ctrl;
+ ret |= GRPWM_PCTRL_EN;
+ }
+
+ /* Hold the updates */
+ if ( up->options & (GRPWM_UPDATE_OPTION_PERIOD|
+ GRPWM_UPDATE_OPTION_COMP|GRPWM_UPDATE_OPTION_DBCOMP) ) {
+
+ if ( up->options & (GRPWM_UPDATE_OPTION_PERIOD) ) {
+ DBG("GRPWM: UPDATING 0x%x: 0x%x\n", &pwmregs->period, up->period);
+ pwmregs->period = up->period;
+ }
+ if ( up->options & (GRPWM_UPDATE_OPTION_COMP) ) {
+ DBG("GRPWM: UPDATING 0x%x: 0x%x\n", &pwmregs->comp, up->compare);
+ pwmregs->comp = up->compare;
+ }
+ if ( up->options & (GRPWM_UPDATE_OPTION_DBCOMP) ) {
+ DBG("GRPWM: UPDATING 0x%x: 0x%x\n", &pwmregs->dbcomp, up->dbcomp);
+ pwmregs->dbcomp = up->dbcomp;
+ }
+ }
+
+ if ( up->options & GRPWM_UPDATE_OPTION_ENABLE ) {
+ ret |= GRPWM_PCTRL_EN;
+ pwmregs->ctrl = ctrl | GRPWM_PCTRL_EN;
+ }
+ return ret;
+}
+
+void grpwm_update_active(struct grpwm_priv *priv, int enable)
+{
+ unsigned int ctrl;
+ int i;
+
+ ctrl = priv->regs->ctrl;
+
+ /* Make all "Update Hold" bits be cleared */
+ ctrl &= ~GRPWM_CTRL_NOUP;
+
+ /* A change in any of the Channel enable/disable bits? */
+ if ( enable ) {
+ ctrl &= ~GRPWM_CTRL_EN;
+ for(i=0; i<priv->channel_cnt; i++) {
+ ctrl |= priv->regs->pwms[i].ctrl & GRPWM_CTRL_EN;
+ }
+ }
+ priv->regs->ctrl = ctrl;
+}
+
+/* Configure the hardware of a channel according to this */
+rtems_status_code grpwm_config_channel(
+ struct grpwm_priv *priv,
+ int channel,
+ struct grpwm_ioctl_config *cfg
+ )
+{
+ struct grpwm_chan_priv *pwm;
+ unsigned int pctrl, wctrl=0;
+
+ pwm = priv->channels[channel];
+ if ( pwm->pwmregs->ctrl & GRPWM_PCTRL_EN_BIT ) {
+ return RTEMS_RESOURCE_IN_USE;
+ }
+ if ( cfg->options & ~GRPWM_CONFIG_OPTION_MASK ) {
+ return RTEMS_INVALID_NAME;
+ }
+ if ( (cfg->options & GRPWM_CONFIG_OPTION_DUAL) &&
+ ((priv->regs->cap1 & GRPWM_CAP_DCM) == 0) ) {
+ return RTEMS_INVALID_NAME;
+ }
+ /* IRQ set up */
+ pwm->isr_arg = cfg->isr_arg;
+ pwm->isr = cfg->isr;
+
+ pctrl = cfg->options |
+ (cfg->dbscaler << GRPWM_PCTRL_DBSC_BIT) |
+ (cfg->irqscaler << GRPWM_PCTRL_ISC_BIT) |
+ (cfg->scaler_index << GRPWM_PCTRL_SCSEL_BIT);
+
+ /* Set Wave form gerneration if available */
+ if ( !priv->wave || (priv->channel_cnt != (channel+1)) ) {
+ /* Wave Form not available for this channel (or core) */
+ if ( cfg->wave_activate || cfg->wave_data || cfg->wave_data_length ) {
+ return RTEMS_INVALID_NAME;
+ }
+ } else if ( cfg->wave_activate ) {
+ /* Enable Wave form generation */
+ DBG("GRPWM: ENABLING WAVE FORM GENERATION 0x%x\n", cfg->wave_data_length);
+
+ if ( cfg->wave_data ) {
+ grpwm_write_wram(priv->regs, cfg->wave_data, cfg->wave_data_length);
+ }
+
+ /* Write length register, and let user control Wave-Sync functionality */
+ wctrl = (((cfg->wave_data_length-1) << GRPWM_WCTRL_STOP_BIT) & GRPWM_WCTRL_STOP);
+ wctrl |= cfg->wave_synccfg & (GRPWM_WCTRL_WSYNCCFG|GRPWM_WCTRL_WSEN);
+ wctrl |= (cfg->wave_sync << 16) & 0x1fff0000;
+ priv->regs->wctrl = wctrl;
+
+ /* Enable Wave form */
+ pctrl |= GRPWM_PCTRL_WEN;
+ }
+
+ DBG("GRPWM: CONFIG: 0x%x, WAVE CONFIG: 0x%x\n", pctrl, wctrl);
+
+ pwm->pwmregs->ctrl = pctrl;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static void grpwm_isr(void *arg)
+{
+ unsigned int ipend;
+ struct grpwm_chan_priv *pwm = arg;
+ struct grpwm_priv *priv = pwm->common;
+ int i;
+
+ /* Get current pending interrupts */
+ ipend = priv->regs->ipend;
+
+ for (i=0; i<priv->channel_cnt; i++) {
+ if ( ipend & (1<<i) ) {
+ pwm = priv->channels[i];
+ if ( pwm->isr ) {
+ pwm->isr(i, pwm->isr_arg);
+ }
+ }
+ }
+ priv->regs->ipend = ipend;
+}
+
+static rtems_device_driver grpwm_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver grpwm_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ struct grpwm_priv *priv;
+ rtems_device_driver ret;
+ struct drvmgr_dev *dev;
+
+ if ( drvmgr_get_dev(&grpwm_drv_info.general, minor, &dev) ) {
+ DBG("Wrong minor %d\n", minor);
+ return RTEMS_INVALID_NAME;
+ }
+ priv = (struct grpwm_priv *)dev->priv;
+
+ /* Wait until we get semaphore */
+ if ( rtems_semaphore_obtain(priv->dev_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT) !=
+ RTEMS_SUCCESSFUL ){
+ return RTEMS_INTERNAL_ERROR;
+ }
+
+ /* is device busy/taken? */
+ if ( priv->open ) {
+ ret=RTEMS_RESOURCE_IN_USE;
+ goto out;
+ }
+
+ /* Mark device taken */
+ priv->open = 1;
+
+ ret = RTEMS_SUCCESSFUL;
+out:
+ rtems_semaphore_release(priv->dev_sem);
+ return ret;
+}
+
+static rtems_device_driver grpwm_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ struct grpwm_priv *priv;
+ struct drvmgr_dev *dev;
+
+ if ( drvmgr_get_dev(&grpwm_drv_info.general, minor, &dev) ) {
+ return RTEMS_INVALID_NAME;
+ }
+ priv = (struct grpwm_priv *)dev->priv;
+
+ /* Reset Hardware */
+ grpwm_hw_reset(priv);
+
+ /* Mark Device closed */
+ priv->open = 0;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver grpwm_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ return RTEMS_UNSATISFIED;
+}
+
+static rtems_device_driver grpwm_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ return RTEMS_UNSATISFIED;
+}
+
+static rtems_device_driver grpwm_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+
+ struct grpwm_priv *priv;
+ struct drvmgr_dev *dev;
+ rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *)arg;
+
+ if ( drvmgr_get_dev(&grpwm_drv_info.general, minor, &dev) ) {
+ return RTEMS_INVALID_NAME;
+ }
+ priv = (struct grpwm_priv *)dev->priv;
+
+ if (!ioarg)
+ return RTEMS_INVALID_NAME;
+
+ ioarg->ioctl_return = 0;
+ switch(ioarg->command) {
+ default: /* Not a valid command */
+ return RTEMS_NOT_DEFINED;
+
+ case GRPWM_IOCTL_GET_CAP:
+ {
+ struct grpwm_ioctl_cap *cap = (void *)ioarg->buffer;
+ if ( cap == NULL )
+ return RTEMS_INVALID_NAME;
+
+ /* Copy Capability registers to user */
+ cap->channel_cnt = priv->channel_cnt;
+ cap->pwm = priv->regs->cap1;
+ cap->wave = priv->regs->cap2;
+ break;
+ }
+ case GRPWM_IOCTL_SET_CONFIG:
+ {
+ struct grpwm_ioctl_config *cfg = (void *)ioarg->buffer;
+ if ( cfg == NULL )
+ return RTEMS_INVALID_NAME;
+ if ( cfg->channel >= priv->channel_cnt )
+ return RTEMS_INVALID_NAME;
+
+ return grpwm_config_channel(priv, cfg->channel, cfg);
+ }
+ case GRPWM_IOCTL_SET_SCALER:
+ {
+ unsigned int invalid_mask;
+ int i;
+ struct grpwm_ioctl_scaler *sc = ioarg->buffer;
+
+ if ( sc == NULL )
+ return RTEMS_INVALID_NAME;
+
+ /* Test if caller reqest to set a scaler not existing */
+ invalid_mask = ~((1 << priv->nscalers) - 1);
+ if ( invalid_mask & sc->index_mask ) {
+ return RTEMS_INVALID_NAME;
+ }
+
+ /* Set scalers requested */
+ for (i=0; i<priv->nscalers; i++) {
+ if ( sc->index_mask & (1<<i) ) {
+ /* Update Scaler 'i' */
+ grpwm_scaler_set(priv->regs, i, sc->values[i]);
+ }
+ }
+ break;
+ }
+ case GRPWM_IOCTL_UPDATE:
+ {
+ struct grpwm_ioctl_update *up = ioarg->buffer;
+ unsigned int invalid_mask, pctrl = 0;
+ int i;
+
+ if ( up == NULL )
+ return RTEMS_INVALID_NAME;
+
+ /* Test if caller reqest to set a scaler not existing */
+ invalid_mask = ~((1 << priv->channel_cnt) - 1);
+ if ( invalid_mask & up->chanmask ) {
+ return RTEMS_INVALID_NAME;
+ }
+
+ /* In order for the changes to take effect at the same time, the "Hold update"
+ * bits is set for all PWM channels that will be updated. The hold update bits
+ * will be cleared at the same time for all channels.
+ */
+ priv->regs->ctrl = (priv->regs->ctrl & ~GRPWM_CTRL_NOUP) |
+ (up->chanmask << GRPWM_CTRL_NOUP_BIT);
+
+ for (i=0; i<priv->channel_cnt; i++) {
+ if ( up->chanmask & (1<<i) ) {
+ /* Prepare update channel 'i' */
+ pctrl |= grpwm_update_prepare_channel(priv, i, &up->channels[i]);
+ }
+ }
+
+ /* 1. Update all channels requested,
+ * 2. Enable the core if at least one channel is enabled
+ * 3. Disable the core if all channels are disabled
+ */
+ grpwm_update_active(priv, (pctrl & GRPWM_PCTRL_EN));
+
+ break;
+ }
+ case GRPWM_IOCTL_IRQ:
+ {
+ unsigned int data = (unsigned int)ioarg->buffer;
+ int channel = (data >> 8) & 0x7;
+ struct grpwm_chan_priv *pwm;
+ unsigned int pctrl;
+
+ pwm = priv->channels[channel];
+
+ if ( data & GRPWM_IRQ_CLEAR ) {
+ priv->regs->ipend |= (1<<channel);
+ drvmgr_interrupt_clear(priv->dev, pwm->irqindex);
+ }
+ if ( (data & 0x3) && !pwm->isr ) {
+ /* Enable IRQ but no ISR */
+ return RTEMS_INVALID_NAME;
+ }
+ pctrl = pwm->pwmregs->ctrl & ~(GRPWM_PCTRL_IEN|GRPWM_PCTRL_IT);
+ pctrl |= ((data & 0x3) << GRPWM_PCTRL_IEN_BIT);
+ pwm->pwmregs->ctrl = pctrl;
+ break;
+ }
+ }
+
+ return RTEMS_SUCCESSFUL;
+}
+
+#define MAX_CHANNEL 8
+char grpwm_irqindex_lookup[8][MAX_CHANNEL] =
+{
+/* Channel 1 2 3 4 5 6 7 8 */
+/* npwm 1 */ {0, 0, 0, 0, 0, 0, 0, 0},
+/* npwm 2 */ {0, 1, 0, 0, 0, 0, 0, 0},
+/* npwm 3 */ {0, 0, 0, 0, 0, 0, 0, 0},
+/* npwm 4 */ {0, 0, 0, 1, 0, 0, 0, 0},
+/* npwm 5 */ {0, 0, 0, 1, 2, 0, 0, 0},
+/* npwm 6 */ {0, 0, 0, 1, 1, 1, 0, 0},
+/* npwm 7 */ {0, 0, 0, 1, 1, 1, 2, 0},
+/* npwm 8 */ {0, 0, 0, 1, 1, 1, 2, 3}
+};
+
+int grpwm_device_init(struct grpwm_priv *priv)
+{
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
+ int mask, i, sepirq;
+ unsigned int wabits;
+ struct grpwm_chan_priv *pwm;
+ struct grpwm_regs *regs;
+
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)priv->dev->businfo;
+ if ( ambadev == NULL ) {
+ return -1;
+ }
+ pnpinfo = &ambadev->info;
+ priv->irq = pnpinfo->irq;
+ regs = priv->regs = (struct grpwm_regs *)pnpinfo->apb_slv->start;
+
+ DBG("GRPWM: 0x%08x irq %d\n", (unsigned int)regs, priv->irq);
+
+ /* Disable Core */
+ regs->ctrl = 0;
+
+ /* Clear all registers */
+ regs->ipend = 0xffffffff;
+ regs->wctrl = 0;
+
+ /* Find the number of PWM channels */
+ priv->channel_cnt = 1 + ((regs->cap1 & GRPWM_CAP_NPWM) >> GRPWM_CAP_NPWM_BIT);
+ pwm = malloc(sizeof(*pwm)*priv->channel_cnt);
+ if ( !pwm )
+ return -1;
+ memset(pwm, 0, sizeof(*pwm)*priv->channel_cnt);
+
+ /* Init all PWM channels */
+ sepirq = ((regs->cap1 & GRPWM_CAP_SEP) >> GRPWM_CAP_SEP_BIT);
+ for (i=0; i<priv->channel_cnt; i++, pwm++) {
+ priv->channels[i] = pwm;
+ pwm->common = priv;
+ pwm->pwmregs = &regs->pwms[i];
+ if ( sepirq == 0 ) {
+ pwm->irqindex = 0;
+ } else if ( sepirq == 1 ) {
+ pwm->irqindex = i;
+ } else {
+ pwm->irqindex = grpwm_irqindex_lookup[priv->channel_cnt][i];
+ }
+ }
+
+ /* Detect if Wave Form capability is availble for last PWM channel */
+ if ( regs->cap2 & GRPWM_CAP2_WPWM ) {
+ priv->wave = 1;
+
+ /* Clear RAM */
+ wabits = (regs->cap2 & GRPWM_CAP2_WABITS) >> GRPWM_CAP2_WABITS_BIT;
+ priv->wlength = 1 << wabits;
+ }
+ priv->nscalers = 1 + ((regs->cap1 & GRPWM_CAP_NSC) >> GRPWM_CAP_NSC_BIT);
+
+ grpwm_hw_reset(priv);
+
+ /* Device Semaphore created with count = 1 */
+ if ( rtems_semaphore_create(rtems_build_name('G', 'P', 'W', 'M'),
+ 1,
+ RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|\
+ RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &priv->dev_sem) != RTEMS_SUCCESSFUL ) {
+ return -1;
+ }
+
+ /* Register interrupt handler for all PWM channels */
+ mask = 0;
+ for (i=0; i<priv->channel_cnt; i++) {
+ pwm = priv->channels[i];
+ if ( (mask & (1 << pwm->irqindex)) == 0 ) {
+ /* Not registered interrupt handler for this IRQ index before,
+ * we do it now.
+ */
+ mask |= (1 << pwm->irqindex);
+ drvmgr_interrupt_register(
+ priv->dev,
+ pwm->irqindex,
+ "grpwm",
+ grpwm_isr,
+ pwm);
+ }
+ }
+
+ return 0;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/slink/grslink.c b/c/src/lib/libbsp/sparc/shared/slink/grslink.c
new file mode 100644
index 0000000000..99e59b89c7
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/slink/grslink.c
@@ -0,0 +1,665 @@
+/*
+ * This file contains the RTEMS GRSLINK SLINK master driver
+ *
+ * --------------------------------------------------------------------------
+ * -- This file is a part of GAISLER RESEARCH source code.
+ * -- Copyright (C) 2008, Gaisler Research AB - all rights reserved.
+ * --
+ * -- ANY USE OR REDISTRIBUTION IN PART OR IN WHOLE MUST BE HANDLED IN
+ * -- ACCORDANCE WITH THE GAISLER LICENSE AGREEMENT AND MUST BE APPROVED
+ * -- IN ADVANCE IN WRITING.
+ * --
+ * -- BY DEFAULT, DISTRIBUTION OR DISCLOSURE IS NOT PERMITTED.
+ * --------------------------------------------------------------------------
+ *
+ * Comments concerning current driver implementation:
+ *
+ * The SLINK specification says that there are three IO cards that are capable
+ * of transmitting data. But these IO cards can have the address range 0 to 3,
+ * and an 'For information only' comment explains that the current
+ * implementation has receive buffers for ".. x 4 (IO cards)".
+ * Because of this the driver has four queues, one for each IO card 0 - 3.
+ * When the addressing convention used for the IO cards is known, the number of
+ * queues may be lowered to three.
+ *
+ */
+
+#include <stdlib.h>
+
+#include <bsp.h>
+#include <grslink.h>
+#include <ambapp.h>
+
+#ifndef GAISLER_SLINK
+#define GAISLER_SLINK 0x02F
+#endif
+
+/* Enable debug output? */
+/* #define DEBUG */
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+/* Bits and fields in SLINK transmit word */
+#define SLINK_RW (1 << 23)
+#define SLINK_CHAN_POS 16
+
+/* Local types */
+typedef struct {
+ volatile unsigned int clockscale;
+ volatile unsigned int ctrl;
+ volatile unsigned int nullwrd;
+ volatile unsigned int sts;
+ volatile unsigned int msk;
+ volatile unsigned int abase;
+ volatile unsigned int bbase;
+ volatile unsigned int td;
+ volatile unsigned int rd;
+} SLINK_regs;
+
+typedef struct {
+ char readstat; /* Status of READ operation */
+ char seqstat; /* Status of SEQUENCE operation */
+ unsigned char scnt; /* Number of SEQUENCE words transferred */
+} SLINK_status;
+
+typedef struct {
+ int size;
+ unsigned int *buf;
+ unsigned int *first;
+ unsigned int *last;
+ unsigned int *max;
+ int full;
+} SLINK_queue;
+
+typedef struct {
+ SLINK_regs *reg; /* Pointer to core registers */
+ SLINK_status *status; /* Driver status information */
+ void (*slink_irq_handler)(int); /* Handler for INTERRUPT */
+ void (*slink_seq_change)(int); /* Callback on SEQUENCE change */
+ int rword; /* Placeholder for READ response */
+ rtems_id read_sem; /* Semaphore for blocking SLINK_read */
+ SLINK_queue *queues; /* Receive queues */
+#ifdef SLINK_COLLECT_STATISTICS
+ SLINK_stats *stats; /* Core statistics, optional */
+#endif
+} SLINK_cfg;
+
+
+static SLINK_cfg *cfg = NULL;
+
+/**** SLINK driver queues for unsolicited and INTERRUPT requests ****/
+
+/* Function: SLINK_createqueues
+ * Arguments: size: Number of elements in each queue
+ * Returns: 0 on success, -1 on failure
+ * Description: Creates SLINK_NUMQUEUES queues, one for each IO card
+ * that can send data. The pointers to the queues is saved in the driver
+ * config structure.
+ */
+static int SLINK_createqueues(int size)
+{
+ SLINK_queue *q;
+ int i, j;
+
+ if ((q = malloc(SLINK_NUMQUEUES*sizeof(SLINK_queue))) == NULL)
+ goto slink_qiniterr1;
+
+ for (i = 0; i < SLINK_NUMQUEUES; i++) {
+ q[i].size = size;
+ if ((q[i].buf = malloc(size*sizeof(int))) == NULL)
+ goto slink_qiniterr2;
+ q[i].first = q[i].last = q[i].buf;
+ q[i].max = q[i].buf + (size-1);
+ q[i].full = 0;
+ }
+
+ cfg->queues = q;
+
+ return 0;
+
+ slink_qiniterr2:
+ for (j = 0; j < i; j++)
+ free(q[i].buf);
+ free(q);
+ slink_qiniterr1:
+ return -1;
+}
+
+/*
+ * Function: SLINK_destroyqueues
+ * Arguments: None
+ * Returns: Nothing
+ * Description: Frees the memory occupied by the queues in cfg->queues
+ */
+/*
+ static void SLINK_destroyqueues(void)
+ {
+ int i;
+
+ for(i = 0; i < SLINK_NUMQUEUES; i++)
+ free(cfg->queues[i].buf);
+
+ free(cfg->queues);
+}
+*/
+
+/*
+ * Function: SLINK_enqueue
+ * Arguments: Received SLINK word
+ * Returns: Nothing
+ * Description:
+ */
+static void SLINK_enqueue(unsigned int slink_wrd)
+{
+ SLINK_queue *ioq = cfg->queues + SLINK_WRD_CARDNUM(slink_wrd);
+
+ if (!ioq->full && SLINK_WRD_CARDNUM(slink_wrd) < SLINK_NUMQUEUES) {
+ *ioq->last = slink_wrd;
+ ioq->last = (ioq->last >= ioq->max) ? ioq->buf : ioq->last+1;
+ ioq->full = ioq->last == ioq->first;
+ return;
+ }
+#ifdef SLINK_COLLECT_STATISTICS
+ cfg->stats->lostwords++;
+#endif
+}
+
+/**** SLINK driver helper functions ****/
+
+/*
+ * Function: SLINK_getaddr
+ * Arguments: amba_conf
+ * base: assigned to base of core registers
+ * irq: assigned to core irq lines
+ * Returns: Base address and IRQ via arguments, 0 if core is found, else -1
+ * Description: See above.
+ */
+static int SLINK_getaddr(int *base, int *irq)
+{
+ struct ambapp_apb_info c;
+
+ if (ambapp_find_apbslv(&ambapp_plb,VENDOR_GAISLER,GAISLER_SLINK,&c) == 1) {
+ *base = c.start;
+ *irq = c.irq;
+ return 0;
+ }
+ return -1;
+}
+
+/* Function: SLINK_calcscaler
+ * Arguments: sysfreq: System frequency in Hz
+ * Returns: Clock scaler register value
+ * Description: Calculates value for SLINK clock scaler register to attain
+ * a SLINK bus frequency as close to 6 MHz as possible. Please see the IP core
+ * documentation for a description of how clock scaling is implemented.
+ */
+static int SLINK_calcscaler(int sysfreq)
+{
+ int fact = sysfreq / SLINK_FREQ_HZ;
+ return ((fact/2-1) << 16) | (fact % 2 ? fact/2 : fact/2-1);
+}
+
+
+/*
+ * Function: SLINK_getsysfreq
+ * Arguments: None
+ * Returns: System frequency in Hz, or 0 if system timer is not found.
+ * Description: Looks at the timer to determine system frequency. Makes use
+ * of AMBA Plug'n'Play.
+ */
+static int SLINK_getsysfreq(void)
+{
+ struct ambapp_apb_info t;
+ struct gptimer_regs *tregs;
+
+ if (ambapp_find_apbslv(&ambapp_plb,VENDOR_GAISLER,GAISLER_GPTIMER,&t)==1) {
+ tregs = (struct gptimer_regs *)t.start;
+ DBG("SLINK_getsysfreq returning %d\n",
+ (tregs->scaler_reload+1)*1000*1000);
+ return (tregs->scaler_reload+1)*1000*1000;
+ }
+ return 0;
+}
+
+/*
+ * Function: SLINK_interrupt_handler
+ * Arguments: v: not used
+ * Returns: Nothing
+ * Description: Interrupt handles checks RNE, SEQUENCE and error status
+ * bits. Reads word from receive queue and distinguishes between INTERRUPT,
+ * READ responses and SLAVE-WORD-SEND. When an INTERRUPT transfer is detected
+ * the handler calls the user specified slink_irq_handler with the received
+ * word. READ responses are saved and given to SLINK_read via a private
+ * variable. SLAVE-WORD-SEND transfers are placed in the IO card's receive
+ * queue.
+ */
+static rtems_isr SLINK_interrupt_handler(rtems_vector_number v)
+{
+ unsigned int sts;
+ unsigned int wrd;
+
+ /* Read all words from Receive queue */
+ while ((sts = cfg->reg->sts) & SLINK_S_RNE) {
+
+ /* Read first word in receive queue */
+ wrd = cfg->reg->rd;
+
+ /* Check channel value to determine action */
+ switch (SLINK_WRD_CHAN(wrd)) {
+ case 0: /* Interrupt */
+ cfg->slink_irq_handler(wrd);
+#ifdef SLINK_COLLECT_STATISTICS
+ cfg->stats->interrupts++;
+#endif
+ break;
+ case 3: /* Read response, if no active READ, fall-through */
+ if (cfg->status->readstat == SLINK_ACTIVE) {
+ rtems_semaphore_release(cfg->read_sem);
+ cfg->status->readstat = SLINK_COMPLETED;
+ cfg->rword = wrd;
+ break;
+ }
+ default: /* Unsolicited request */
+ SLINK_enqueue(wrd);
+ break;
+ }
+ }
+
+ /* Check sequence operation */
+ if (sts & SLINK_S_SC) {
+ /* SEQUENCE completed */
+ cfg->status->seqstat = SLINK_COMPLETED;
+ if (cfg->slink_seq_change)
+ cfg->slink_seq_change(SLINK_COMPLETED);
+#ifdef SLINK_COLLECT_STATISTICS
+ cfg->stats->seqcomp++;
+#endif
+ } else if (sts & SLINK_S_SA) {
+ /* SEQUENCE aborted */
+ cfg->status->seqstat = SLINK_ABORTED;
+ cfg->status->scnt = (sts >> SLINK_S_SI_POS);
+ if (cfg->slink_seq_change)
+ cfg->slink_seq_change(SLINK_ABORTED);
+ }
+
+ /* Check error conditions */
+ if (sts & SLINK_S_PERR) {
+ /*
+ Parity error detected, set seqstat if there is an ongoing
+ sequence so that the calling application can decide if the
+ sequence should be aborted
+ */
+ if (cfg->status->seqstat == SLINK_ACTIVE) {
+ cfg->status->seqstat = SLINK_PARERR;
+ if (cfg->slink_seq_change)
+ cfg->slink_seq_change(SLINK_PARERR);
+ }
+ /* Abort READ operation */
+ if (cfg->status->readstat == SLINK_ACTIVE) {
+ cfg->status->readstat = SLINK_PARERR;
+ rtems_semaphore_release(cfg->read_sem);
+ }
+#ifdef SLINK_COLLECT_STATISTICS
+ cfg->stats->parerr++;
+#endif
+ }
+ if (sts & SLINK_S_AERR) {
+ /* AMBA error response, sequence aborted */
+ cfg->status->seqstat = SLINK_AMBAERR;
+ cfg->status->scnt = sts >> SLINK_S_SI_POS;
+ if (cfg->slink_seq_change)
+ cfg->slink_seq_change(SLINK_AMBAERR);
+ }
+ if (sts & SLINK_S_ROV) {
+ /* Receive overflow, abort any ongoing READ */
+ if (cfg->status->readstat == SLINK_ACTIVE) {
+ cfg->status->readstat = SLINK_ROV;
+ rtems_semaphore_release(cfg->read_sem);
+ }
+#ifdef SLINK_COLLECT_STATISICS
+ cfg->status->recov++;
+#endif
+ }
+
+ /* Clear processed bits */
+ cfg->reg->sts = sts;
+}
+
+/**** SLINK driver interface starts here ****/
+
+/* Function: SLINK_init
+ * Arguments: nullwrd: NULL word
+ * parity: Even (0) or Odd (1) parity
+ * interrupt_trans_handler: Function that handles interrupt requests
+ * sequence_callback: Callback on SEQUENCE status changes
+ * qsize: Size of each receive queue
+ * Returns: 0 on success, -1 on failure
+ * Description: Initializes the SLINK core
+ */
+int SLINK_init(unsigned int nullwrd, int parity, int qsize,
+ void (*interrupt_trans_handler)(int),
+ void (*sequence_callback)(int))
+{
+ int base;
+ int irq;
+ rtems_status_code st;
+
+ /* Allocate private config structure */
+ if (cfg == NULL && (cfg = malloc(sizeof(SLINK_cfg))) == NULL) {
+ DBG("SLINK_init: Could not allocate cfg structure\n");
+ goto slink_initerr1;
+ }
+
+ /* Create simple binary semaphore for blocking SLINK_read */
+ st = rtems_semaphore_create(rtems_build_name('S', 'L', 'R', '0'), 0,
+ (RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|
+ RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|
+ RTEMS_NO_PRIORITY_CEILING), 0,
+ &cfg->read_sem);
+ if (st != RTEMS_SUCCESSFUL) {
+ DBG("SLINK_init: Could not create semaphore\n");
+ goto slink_initerr1;
+ }
+
+ /* Initialize pointer to SLINK core registers and get IRQ line */
+ if (SLINK_getaddr(&base, &irq) == -1) {
+ DBG("SLINK_init: Could not find core\n");
+ goto slink_initerr2;
+ }
+ cfg->reg = (SLINK_regs*)base;
+
+ /* Allocate status structure and initialize members */
+ if ((cfg->status = calloc(1, sizeof(SLINK_status))) == NULL) {
+ DBG("SLINK_init: Could not allocate status structure\n");
+ goto slink_initerr2;
+ }
+ cfg->status->seqstat = SLINK_COMPLETED;
+ cfg->status->readstat = SLINK_COMPLETED;
+
+#ifdef SLINK_COLLECT_STATISTICS
+ /* Allocate statistics structure and initialize members */
+ if ((cfg->stats = calloc(1, sizeof(SLINK_stats))) == NULL) {
+ DBG("SLINK_init: Could not allocate statistics structure\n");
+ goto slink_initerr3;
+ }
+#endif
+
+ /* Allocate and initialize queues */
+ if (SLINK_createqueues(qsize) == -1) {
+ DBG("SLINK_init: Could not create queues\n");
+ goto slink_initerr3;
+ }
+
+ /* Configure core registers */
+ cfg->reg->clockscale = SLINK_calcscaler(SLINK_getsysfreq());
+ cfg->reg->ctrl = parity ? SLINK_C_PAR : 0;
+ cfg->reg->nullwrd = nullwrd;
+ cfg->reg->msk = (SLINK_M_PERRE | SLINK_M_AERRE | SLINK_M_ROVE |
+ SLINK_M_RNEE | SLINK_M_SAE | SLINK_M_SCE);
+
+ /* Set-up INTERRUPT transfer handling */
+ cfg->slink_irq_handler = interrupt_trans_handler;
+
+ /* Save SEQUENCE callback */
+ cfg->slink_seq_change = sequence_callback;
+
+ /* Set-up IRQ handling */
+ set_vector(SLINK_interrupt_handler,irq+0x10,2);
+
+ return 0;
+
+ slink_initerr3:
+ free(cfg->status);
+ slink_initerr2:
+ free(cfg);
+ slink_initerr1:
+ return -1;
+}
+
+/* Function: SLINK_start
+ * Description: Enables the core
+ */
+void SLINK_start(void)
+{
+ if (cfg != NULL)
+ cfg->reg->ctrl |= SLINK_C_SLE;
+}
+
+/* Function: SLINK_stop
+ * Description: Disables the core
+ */
+void SLINK_stop(void)
+{
+ if (cfg != NULL)
+ cfg->reg->ctrl &= ~SLINK_C_SLE;
+}
+
+/*
+ * Function: SLINK_read
+ * Arguments: data: Payload of data word
+ * channel: -
+ * reply: Reply from IO card
+ * Returns: 0 on success
+ * -(SLINK_PARERR, SLINK_ROV) on error or -SLINK_QFULL if transmit queue
+ * is full and software should try again.
+ * Description: Reads one word and returns the response in *reply unless there
+ * is an error. This function blocks until the READ operation is
+ * completed or aborted.
+ */
+int SLINK_read(int data, int channel, int *reply)
+{
+ DBG("SLINK_read: called..");
+
+ if (cfg->reg->sts & SLINK_S_TNF) {
+ cfg->status->readstat = SLINK_ACTIVE;
+ cfg->reg->td = SLINK_RW | channel << SLINK_CHAN_POS | data;
+ } else {
+ DBG("queue FULL\n");
+ return -SLINK_QFULL; /* Transmit queue full */
+ }
+
+ /* Block until the operation has completed or has been aborted */
+ rtems_semaphore_obtain(cfg->read_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+
+ if (cfg->status->readstat == SLINK_COMPLETED) {
+ *reply = cfg->rword;
+#ifdef SLINK_COLLECT_STATISTICS
+ cfg->stats->reads++;
+#endif
+ DBG("returning 0\n");
+ return 0;
+ } else {
+ DBG("returning error code\n");
+ return -cfg->status->readstat;
+ }
+}
+
+/*
+ * Function: SLINK_write
+ * Arguments: data: Payload of SLINK data word
+ * channel: Channel value (bits 22 downto 16) of receive
+ * register word
+ * Returns: 0 if command was placed in transmit queue
+ * -SLINK_QFULL if transmit queue was full (software should retry)
+ * Description: See above.
+ */
+int SLINK_write(int data, int channel)
+{
+ if (cfg->reg->sts & SLINK_S_TNF) {
+ cfg->reg->td = channel << SLINK_CHAN_POS | data;
+#ifdef SLINK_COLLECT_STATISTICS
+ cfg->stats->writes++;
+#endif
+ return 0;
+ }
+
+ return -SLINK_QFULL;
+}
+
+/*
+ * Function: SLINK_sequence
+ * Arguments: a: Array containing sequence commands
+ * b: Array where SEQUENCE responses will be stored
+ * n: Number of commands in a array
+ * channel: Sequence Channel Number
+ * reconly: Set to 1 if the SEQUENCE operation is receive only
+ * Returns: 0 if SEQUENCE could be started (SUCCESS)
+ * -1 if SEQUNCE was not started due to ongoing SEQUENCE
+ */
+int SLINK_seqstart(int *a, int *b, int n, int channel, int reconly)
+{
+ /* Only start a new SEQUENCE of the former SEQUENCE has completed */
+ if (cfg->status->seqstat == SLINK_ACTIVE ||
+ cfg->status->seqstat == SLINK_PARERR)
+ return -1;
+
+ /* Tell core about arrays */
+ cfg->reg->abase = (int)a;
+ cfg->reg->bbase = (int)b;
+
+ /* As far as software is concerned the sequence is now active */
+ cfg->status->seqstat = SLINK_ACTIVE;
+
+ /* Enable SEQUENCE operation with SCN = channel and SLEN = n-1 */
+ if (reconly == 1) {
+ cfg->reg->ctrl = (((n-1) << SLINK_C_SLEN_POS) | SLINK_C_SRO |
+ (channel << SLINK_C_SCN_POS) |
+ SLINK_C_SE | (cfg->reg->ctrl & 0xC000000F));
+ } else {
+ cfg->reg->ctrl = (((n-1) << SLINK_C_SLEN_POS) |
+ (channel << SLINK_C_SCN_POS) |
+ SLINK_C_SE | (cfg->reg->ctrl & 0xC000000F));
+ }
+
+#ifdef SLINK_COLLECT_STATISTICS
+ cfg->stats->sequences++;
+#endif
+
+ return 0;
+}
+
+
+/* Function: SLINK_seqabort
+ * Description: This function aborts an ongoing SEQUENCE. Software can tell
+ * when the SEQUENCE is aborted by polling SLINK_seqstat().
+ */
+void SLINK_seqabort(void)
+{
+ cfg->reg->ctrl = cfg->reg->ctrl | SLINK_C_AS;
+}
+
+
+/*
+ * Function: SLINK_seqstatus
+ * Returns: The current or status of the SEQUENCE operation:
+ * SLINK_COMPLETED, SLINK_ACTIVE, SLINK_PARERR, SLINK_AMBAERR,
+ * SLINK_ABORTED (these are defined in grslink.h)
+ * Description: Meaning of returned values:
+ * SLINK_ABORTED: Aborted before all operations completed.
+ * SLINK_ACTIVE: The core is busy processing the SEQUENCE
+ * SLINK_AMBAERR: The last SEQUENCE was aborted by an AMBA ERROR
+ * SLINK_COMPLETED: All words were transferred in the last SEQUENCE
+ * SLINK_PARERR: Parity error detected. Software may want to abort
+ *
+ * If the SEQUENCE was aborted SLINK_seqwrds() can be used to
+ * determine the number of completed operations.
+ */
+int SLINK_seqstatus(void)
+{
+ return cfg->status->seqstat;
+}
+
+/*
+ * Function: SLINK_seqwrds
+ * Returns: -1 for ongoing sequence
+ * 0 if all words were transferred in the last sequence
+ * number of words if the last SEQUENCE did not complete
+ * (SLINK_AMBAERR or SLINK_ABORTED is reported ny SLINK_seqstatus())
+ */
+int SLINK_seqwrds(void)
+{
+ switch (cfg->status->seqstat) {
+ case SLINK_COMPLETED: return 0;
+ case SLINK_ACTIVE | SLINK_PARERR: return -1;
+ default: return cfg->status->scnt;
+ }
+}
+
+/*
+ * Function: SLINK_hwstatus
+ * Returns: The SLINK core's status register. The register values can be
+ * interpreted with the help of macros defined in grslink.h.
+ */
+int SLINK_hwstatus(void)
+{
+ return cfg->reg->sts;
+}
+
+/*
+ * Function: SLINK_queuestatus
+ * Arguments: iocard: Queue which to check status for
+ * Returns: Number of elements in queue or -1 on non-existent queue
+ * Description: SLINK_queuestatus(queue) returns the number of elements in
+ * queue 'iocard'
+ */
+int SLINK_queuestatus(int iocard)
+{
+ unsigned int first, last;
+ SLINK_queue *ioq;
+
+ if (iocard >= SLINK_NUMQUEUES)
+ return -1;
+
+ ioq = cfg->queues + iocard;
+
+ if (ioq->full)
+ return ioq->size;
+ if (ioq->first == ioq->last)
+ return 0;
+
+ first = ((unsigned int)ioq->first)/sizeof(unsigned int);
+ last = ((unsigned int)ioq->last)/sizeof(unsigned int);
+
+ return first < last ? last - first : ioq->size - first + last;
+}
+
+/*
+ * Function: SLINK_dequeue
+ * Arguments: iocard: IO card number
+ * elem: First element in IO card queue
+ * Returns: 0 on success or -1 on empty or non-existent queue
+ * Description:
+ */
+int SLINK_dequeue(int iocard, int *elem)
+{
+ if (iocard >= SLINK_NUMQUEUES)
+ return -1;
+
+ SLINK_queue *ioq = cfg->queues + iocard;
+
+ if (ioq->last != ioq->first || ioq->full) {
+ *elem = *ioq->first;
+ ioq->first = (ioq->first >= ioq->max) ? ioq->buf : ioq->first+1;
+ ioq->full = 0;
+ return 0;
+ }
+ return -1;
+}
+
+/*
+ * Function: SLINK_statistics
+ * Returns: If the core has statistics colletion enabled this function returns
+ * a pointer to a struct containing statistics information, otherwise NULL.
+ */
+SLINK_stats *SLINK_statistics(void)
+{
+#ifdef SLINK_COLLECT_STATISTICS
+ return cfg->stats;
+#else
+ return NULL;
+#endif
+}
diff --git a/c/src/lib/libbsp/sparc/shared/spi/spictrl.c b/c/src/lib/libbsp/sparc/shared/spi/spictrl.c
new file mode 100644
index 0000000000..8dddf0c88f
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/spi/spictrl.c
@@ -0,0 +1,1011 @@
+/*
+ * SPICTRL SPI driver implmenetation
+ *
+ * COPYRIGHT (c) 2009.
+ * Aeroflex Gaisler.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ *
+ */
+
+
+#include <bsp.h>
+#include <rtems/libio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <rtems/bspIo.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+#include <spictrl.h>
+#include <ambapp.h>
+
+#include <rtems/libi2c.h>
+
+/*#define DEBUG 1*/
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#define STATIC
+#else
+#define DBG(x...)
+#define STATIC static
+#endif
+
+/*** CAPABILITY REGISTER 0x00 ***/
+#define SPICTRL_CAP_SSSZ_BIT 24
+#define SPICTRL_CAP_AMODE_BIT 18
+#define SPICTRL_CAP_ASELA_BIT 17
+#define SPICTRL_CAP_SSEN_BIT 16
+#define SPICTRL_CAP_FDEPTH_BIT 8
+#define SPICTRL_CAP_REV_BIT 0
+
+#define SPICTRL_CAP_SSSZ (0xff << SPICTRL_CAP_SSSZ_BIT)
+#define SPICTRL_CAP_AMODE (1<<SPICTRL_CAP_AMODE_BIT)
+#define SPICTRL_CAP_ASELA (1<<SPICTRL_CAP_ASELA_BIT)
+#define SPICTRL_CAP_SSEN (1 << SPICTRL_CAP_SSEN_BIT)
+#define SPICTRL_CAP_FDEPTH (0xff << SPICTRL_CAP_FDEPTH_BIT)
+#define SPICTRL_CAP_REV (0xff << SPICTRL_CAP_REV_BIT)
+
+/*** MODE REGISTER 0x20 ***/
+#define SPICTRL_MODE_AMEN_BIT 31
+#define SPICTRL_MODE_LOOP_BIT 30
+#define SPICTRL_MODE_CPOL_BIT 29
+#define SPICTRL_MODE_CPHA_BIT 28
+#define SPICTRL_MODE_DIV16_BIT 27
+#define SPICTRL_MODE_REV_BIT 26
+#define SPICTRL_MODE_MS_BIT 25
+#define SPICTRL_MODE_EN_BIT 24
+#define SPICTRL_MODE_LEN_BIT 20
+#define SPICTRL_MODE_PM_BIT 16
+#define SPICTRL_MODE_ASEL_BIT 14
+#define SPICTRL_MODE_FACT_BIT 13
+#define SPICTRL_MODE_CG_BIT 7
+#define SPICTRL_MODE_TAC_BIT 4
+
+#define SPICTRL_MODE_AMEN (1 << SPICTRL_MODE_AMEN_BIT)
+#define SPICTRL_MODE_LOOP (1 << SPICTRL_MODE_LOOP_BIT)
+#define SPICTRL_MODE_CPOL (1 << SPICTRL_MODE_CPOL_BIT)
+#define SPICTRL_MODE_CPHA (1 << SPICTRL_MODE_CPHA_BIT)
+#define SPICTRL_MODE_DIV16 (1 << SPICTRL_MODE_DIV16_BIT)
+#define SPICTRL_MODE_REV (1 << SPICTRL_MODE_REV_BIT)
+#define SPICTRL_MODE_MS (1 << SPICTRL_MODE_MS_BIT)
+#define SPICTRL_MODE_EN (1 << SPICTRL_MODE_EN_BIT)
+#define SPICTRL_MODE_LEN (0xf << SPICTRL_MODE_LEN_BIT)
+#define SPICTRL_MODE_PM (0xf << SPICTRL_MODE_PM_BIT)
+#define SPICTRL_MODE_ASEL (1 << SPICTRL_MODE_ASEL_BIT)
+#define SPICTRL_MODE_FACT (1 << SPICTRL_MODE_FACT_BIT)
+#define SPICTRL_MODE_CG (0x1f << SPICTRL_MODE_CG_BIT)
+#define SPICTRL_MODE_TAC (0x1 << SPICTRL_MODE_TAC_BIT)
+
+/*** EVENT REGISTER 0x24 ***/
+#define SPICTRL_EVENT_AT_BIT 15
+#define SPICTRL_EVENT_LT_BIT 14
+#define SPICTRL_EVENT_OV_BIT 12
+#define SPICTRL_EVENT_UN_BIT 11
+#define SPICTRL_EVENT_MME_BIT 10
+#define SPICTRL_EVENT_NE_BIT 9
+#define SPICTRL_EVENT_NF_BIT 8
+
+#define SPICTRL_EVENT_AT (1 << SPICTRL_EVENT_AT_BIT)
+#define SPICTRL_EVENT_LT (1 << SPICTRL_EVENT_LT_BIT)
+#define SPICTRL_EVENT_OV (1 << SPICTRL_EVENT_OV_BIT)
+#define SPICTRL_EVENT_UN (1 << SPICTRL_EVENT_UN_BIT)
+#define SPICTRL_EVENT_MME (1 << SPICTRL_EVENT_MME_BIT)
+#define SPICTRL_EVENT_NE (1 << SPICTRL_EVENT_NE_BIT)
+#define SPICTRL_EVENT_NF (1 << SPICTRL_EVENT_NF_BIT)
+
+/*** MASK REGISTER 0x28 ***/
+#define SPICTRL_MASK_ATE_BIT 15
+#define SPICTRL_MASK_LTE_BIT 14
+#define SPICTRL_MASK_OVE_BIT 12
+#define SPICTRL_MASK_UNE_BIT 11
+#define SPICTRL_MASK_MMEE_BIT 10
+#define SPICTRL_MASK_NEE_BIT 9
+#define SPICTRL_MASK_NFE_BIT 8
+
+#define SPICTRL_MASK_ATE (1 << SPICTRL_MASK_ATE_BIT)
+#define SPICTRL_MASK_LTE (1 << SPICTRL_MASK_LTE_BIT)
+#define SPICTRL_MASK_OVE (1 << SPICTRL_MASK_OVE_BIT)
+#define SPICTRL_MASK_UNE (1 << SPICTRL_MASK_UNE_BIT)
+#define SPICTRL_MASK_MMEE (1 << SPICTRL_MASK_MMEE_BIT)
+#define SPICTRL_MASK_NEE (1 << SPICTRL_MASK_NEE_BIT)
+#define SPICTRL_MASK_NFE (1 << SPICTRL_MASK_NFE_BIT)
+
+/*** COMMAND REGISTER 0x2c ***/
+#define SPICTRL_CMD_LST_BIT 22
+#define SPICTRL_CMD_LST (1 << SPICTRL_CMD_LST_BIT)
+
+/*** TRANSMIT REGISTER 0x30 ***/
+#define SPICTRL_TX_TDATA_BIT 0
+#define SPICTRL_TX_TDATA 0xffffffff
+
+/*** RECEIVE REGISTER 0x34 ***/
+#define SPICTRL_RX_RDATA_BIT 0
+#define SPICTRL_RX_RDATA 0xffffffff
+
+/*** SLAVE SELECT REGISTER 0x38 - VARIABLE ***/
+
+/*** AM CONFIGURATION REGISTER 0x40 ***/
+#define SPICTRL_AMCFG_ERPT_BIT 6
+#define SPICTRL_AMCFG_SEQ_BIT 5
+#define SPICTRL_AMCFG_STRICT_BIT 4
+#define SPICTRL_AMCFG_OVTB_BIT 3
+#define SPICTRL_AMCFG_OVDB_BIT 2
+#define SPICTRL_AMCFG_ACT_BIT 1
+#define SPICTRL_AMCFG_EACT_BIT 0
+
+#define SPICTRL_AMCFG_ERPT (1<<SPICTRL_AMCFG_ERPT_BIT)
+#define SPICTRL_AMCFG_SEQ (1<<SPICTRL_AMCFG_SEQ_BIT)
+#define SPICTRL_AMCFG_STRICT (1<<SPICTRL_AMCFG_STRICT_BIT)
+#define SPICTRL_AMCFG_OVTB (1<<SPICTRL_AMCFG_OVTB_BIT)
+#define SPICTRL_AMCFG_OVDB (1<<SPICTRL_AMCFG_OVDB_BIT)
+#define SPICTRL_AMCFG_ACT (1<<SPICTRL_AMCFG_ACT_BIT)
+#define SPICTRL_AMCFG_EACT (1<<SPICTRL_AMCFG_EACT_BIT)
+
+struct spictrl_priv {
+ rtems_libi2c_bus_t i2clib_desc;
+ struct drvmgr_dev *dev;
+ struct spictrl_regs *regs;
+ int irq;
+ int minor;
+ unsigned int core_freq_hz;
+
+ /* Driver */
+ int fdepth;
+ int bits_per_char;
+ int lsb_first;
+ int txshift;
+ int rxshift;
+ unsigned int idle_char;
+ int (*slvSelFunc)(void *regs, uint32_t addr, int select);
+
+ /* Automated Periodic transfers */
+ int periodic_started;
+ struct spictrl_ioctl_config periodic_cfg;
+};
+
+/******************* Driver Manager Part ***********************/
+
+int spictrl_device_init(struct spictrl_priv *priv);
+
+int spictrl_init2(struct drvmgr_dev *dev);
+int spictrl_init3(struct drvmgr_dev *dev);
+
+struct drvmgr_drv_ops spictrl_ops =
+{
+ .init = {NULL, spictrl_init2, spictrl_init3, NULL},
+ .remove = NULL,
+ .info = NULL
+};
+
+struct amba_dev_id spictrl_ids[] =
+{
+ {VENDOR_GAISLER, GAISLER_SPICTRL},
+ {0, 0} /* Mark end of table */
+};
+
+struct amba_drv_info spictrl_drv_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_AMBAPP_GAISLER_SPICTRL_ID, /* Driver ID */
+ "SPICTRL_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */
+ &spictrl_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ 0,
+ },
+ &spictrl_ids[0]
+};
+
+void spictrl_register_drv (void)
+{
+ DBG("Registering SPICTRL driver\n");
+ drvmgr_drv_register(&spictrl_drv_info.general);
+}
+
+int spictrl_init2(struct drvmgr_dev *dev)
+{
+ struct spictrl_priv *priv;
+
+ DBG("SPICTRL[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
+
+ priv = dev->priv = malloc(sizeof(struct spictrl_priv));
+ if ( !priv )
+ return DRVMGR_NOMEM;
+ memset(priv, 0, sizeof(*priv));
+ priv->dev = dev;
+
+ /* This core will not find other cores, so we wait for init2() */
+
+ return DRVMGR_OK;
+}
+
+int spictrl_init3(struct drvmgr_dev *dev)
+{
+ struct spictrl_priv *priv;
+ char prefix[32];
+ char devName[32];
+ int rc;
+
+ priv = (struct spictrl_priv *)dev->priv;
+
+ /* Do initialization */
+
+ /* Initialize i2c library */
+ rc = rtems_libi2c_initialize();
+ if (rc != 0) {
+ DBG("SPICTRL: rtems_libi2c_initialize failed, exiting...\n");
+ free(dev->priv);
+ dev->priv = NULL;
+ return DRVMGR_FAIL;
+ }
+
+ /* I/O system registered and initialized
+ * Now we take care of device initialization.
+ */
+
+ /* Get frequency */
+ if ( drvmgr_freq_get(dev, DEV_APB_SLV, &priv->core_freq_hz) ) {
+ return DRVMGR_FAIL;
+ }
+
+ if ( spictrl_device_init(priv) ) {
+ free(dev->priv);
+ dev->priv = NULL;
+ return DRVMGR_FAIL;
+ }
+
+ /* Get Filesystem name prefix */
+ prefix[0] = '\0';
+ if ( drvmgr_get_dev_prefix(dev, prefix) ) {
+ /* Failed to get prefix, make sure of a unique FS name
+ * by using the driver minor.
+ */
+ sprintf(devName, "/dev/spi%d", dev->minor_drv+1);
+ } else {
+ /* Got special prefix, this means we have a bus prefix
+ * And we should use our "bus minor"
+ */
+ sprintf(devName, "/dev/%sspi%d", prefix, dev->minor_bus+1);
+ }
+
+ /* Register Bus for this Device */
+ rc = rtems_libi2c_register_bus(devName, &priv->i2clib_desc);
+ if (rc < 0) {
+ DBG("SPICTRL: rtems_libi2c_register_bus(%s) failed\n", devName);
+ free(dev->priv);
+ dev->priv = NULL;
+ return DRVMGR_FAIL;
+ }
+ priv->minor = rc;
+
+ return DRVMGR_OK;
+}
+
+/******************* Driver Implementation ***********************/
+
+STATIC rtems_status_code spictrl_libi2c_send_addr(rtems_libi2c_bus_t *bushdl,
+ uint32_t addr, int rw);
+
+/* Set as high frequency of SCK as possible but not higher than
+ * requested frequency (freq).
+ */
+int spictrl_set_freq(struct spictrl_priv *priv, unsigned int freq)
+{
+ unsigned int core_freq_hz = priv->core_freq_hz;
+ unsigned int lowest_freq_possible, result;
+ unsigned int div, div16, pm, fact;
+
+ /* Lowest possible when DIV16 is set and PM is 0xf */
+ lowest_freq_possible = core_freq_hz / (16 * 4 * (0xf + 1));
+
+ if ( freq < lowest_freq_possible ) {
+ DBG("SPICTRL: TOO LOW FREQ %u, CORE FREQ %u, LOWEST FREQ %u\n",
+ freq, core_freq_hz, lowest_freq_possible);
+ return -1;
+ }
+
+ div = ((core_freq_hz / 2) + (freq-1)) / freq;
+ DBG("SPICTRL: DIV=%d, FREQ=%d\n", div, freq);
+
+ /* Is DIV16 neccessary? */
+ if ( div > 16 ) {
+ div = (div + (16 - 1)) / 16;
+ div16 = 1;
+ } else {
+ div16 = 0;
+ }
+
+ if ( div > 0xf ) {
+ fact = 0; /* FACT adds an factor /2 */
+ div = (div + (2 - 1)) / 2;
+ } else {
+ fact = 1;
+ }
+
+ pm = div-1;
+
+ /* Update hardware */
+ priv->regs->mode =
+ (priv->regs->mode & ~(SPICTRL_MODE_PM|SPICTRL_MODE_DIV16|SPICTRL_MODE_FACT)) |
+ (pm << SPICTRL_MODE_PM_BIT) | (div16 << SPICTRL_MODE_DIV16_BIT) |
+ (fact << SPICTRL_MODE_FACT_BIT);
+
+ result = core_freq_hz / (2 * (fact ? 1 : 2) * (div) * (div16 ? 16 : 1) );
+ DBG("SPICTRL: Effective bit rate %u (requested %u), PM: %x, FACT: %d, div16: %x, core_freq: %u\n", result, freq, pm, fact, div16, core_freq_hz);
+
+ return 0;
+}
+
+/* Start Automated Periodic transfers, after this call read can be done */
+int spictrl_start_periodic(struct spictrl_priv *priv)
+{
+ struct spictrl_ioctl_config *cfg = &priv->periodic_cfg;
+ unsigned int am_cfg;
+
+ /* Clear the events */
+ priv->regs->event = 0xffffffff;
+
+ /* Enable core */
+ priv->regs->mode |= SPICTRL_MODE_EN | SPICTRL_MODE_MS;
+
+ /* Update hardware config from flags and period */
+ priv->regs->am_period = cfg->period;
+
+ /* Remove SPICTRL_PERIOD_FLAGS_ASEL and ACT bit and shift into posistion */
+ am_cfg = (cfg->period_flags & 0x1f8) >> 1;
+ priv->regs->am_cfg = am_cfg;
+
+ /* Start automated periodic transfers */
+ if ( cfg->period_flags & SPICTRL_PERIOD_FLAGS_EACT ) {
+ /* Enable external triggering */
+ priv->regs->am_cfg = am_cfg | SPICTRL_AMCFG_EACT;
+ } else {
+ /* Activate periodic transfers */
+ priv->regs->am_cfg = am_cfg | SPICTRL_AMCFG_ACT;
+ }
+
+ return 0;
+}
+
+/* Stop Automated Periodic transfers */
+void spictrl_stop_periodic(struct spictrl_priv *priv)
+{
+ priv->regs->am_cfg = 0;
+}
+
+/* Return the status of the SPI controller (the event register),
+ * it may be needed in periodic mode to look at the Not Full bit (NF)
+ * in order not to hang in an infinte loop when read is called.
+ */
+unsigned int spictrl_status(struct spictrl_priv *priv)
+{
+ return priv->regs->event;
+}
+
+int spictrl_read_periodic(struct spictrl_priv *priv, struct spictrl_period_io *rarg)
+{
+ int i, rxi, rxshift, bits_per_char, reg;
+ unsigned int rx_word, mask;
+ void *rxbuf;
+
+ if ( rarg->options & 0x1 ) {
+ /* Read mask registers */
+ for (i=0; i<4; i++) {
+ rarg->masks[i] = priv->regs->am_mask[i];
+ }
+ }
+
+ if ( rarg->options & 0x2 ) {
+ /* Read receive registers (after updating masks so that the caller can
+ * read current buffer without knowning of actual register mask).
+ */
+
+ /* If not started we could be hanging here forever. */
+ if ( !priv->periodic_started )
+ return -1;
+
+ rxshift = priv->rxshift;
+ bits_per_char = priv->bits_per_char;
+ rx_word = 0;
+
+ rxbuf = rarg->data;
+ if ( !rxbuf ) {
+ /* If no data pointer specified we cannot copy data... */
+ return -1;
+ }
+
+ /* Wait until all data is available (if started) */
+ while ( (priv->regs->event & SPICTRL_EVENT_NE) == 0 ) {
+ ;
+ }
+
+ rxi = 0;
+ for (i=0; i<4; i++) {
+ mask = rarg->masks[i];
+ reg = 0;
+ while ( mask ) {
+ if ( mask & 1 ) {
+ /* Update Register */
+ rx_word = priv->regs->am_rx[i*32 + reg] >> rxshift;
+
+ if ( bits_per_char <= 8 ) {
+ *((unsigned char *)rxbuf + rxi) = rx_word;
+ } else if ( bits_per_char <= 16 ) {
+ *((unsigned short *)rxbuf + rxi) = rx_word;
+ } else {
+ *((unsigned int *)rxbuf + rxi) = rx_word;
+ }
+ rxi++;
+ }
+
+ mask = mask>>1;
+ reg++;
+ }
+ }
+ }
+
+ return 0;
+}
+
+int spictrl_write_periodic(struct spictrl_priv *priv, struct spictrl_period_io *warg)
+{
+ int i, txi, txshift, bits_per_char, reg;
+ unsigned int tx_word, mask;
+ void *txbuf;
+
+ if ( warg->options & 0x2 ) {
+
+ /* Make sure core is enabled, otherwise TX registers writes are lost */
+ priv->regs->mode |= SPICTRL_MODE_EN;
+
+ /* Update Transmit registers (before updating masks so that we do not
+ * transmit invalid data)
+ */
+
+ txshift = priv->txshift;
+ bits_per_char = priv->bits_per_char;
+ tx_word = 0;
+
+ txbuf = warg->data;
+ if ( !txbuf ) {
+ /* If no data pointer specified we fill up with
+ * idle chars.
+ */
+ tx_word = priv->idle_char << txshift;
+ }
+
+ txi = 0;
+ for (i=0; i<4; i++) {
+ mask = warg->masks[i];
+ reg = 0;
+ while ( mask ) {
+ if ( mask & 1 ) {
+ if ( txbuf ) {
+ if ( bits_per_char <= 8 ) {
+ tx_word = *((unsigned char *)txbuf + txi);
+ } else if ( bits_per_char <= 16 ) {
+ tx_word = *((unsigned short *)txbuf + txi);
+ } else {
+ tx_word = *((unsigned int *)txbuf + txi);
+ }
+ tx_word = tx_word << txshift;
+ txi++;
+ }
+
+ /* Update Register */
+ DBG("WRITE 0x%08x to 0x%08x\n", tx_word, &priv->regs->am_tx[i*32 + reg]);
+ priv->regs->am_tx[i*32 + reg] = tx_word;
+ }
+
+ mask = mask>>1;
+ reg++;
+ }
+ }
+ }
+
+ if ( warg->options & 0x1 ) {
+ /* Update mask registers */
+ for (i=0; i<4; i++) {
+ DBG("WRITE 0x%08x to 0x%08x (MSK%d)\n", warg->masks[i], &priv->regs->am_mask[i], i);
+ priv->regs->am_mask[i] = warg->masks[i];
+ }
+ }
+
+ return 0;
+}
+
+int spictrl_read_write(struct spictrl_priv *priv, void *rxbuf, void *txbuf, int len)
+{
+ unsigned int tx_word, rx_word, tmp;
+ int txshift = priv->txshift;
+ int rxshift = priv->rxshift;
+ int txi, rxi, bits_per_char;
+ int length;
+
+ /* Use IOCTL for periodic reads. The FIFO is not supported in automated
+ * periodic mode
+ */
+ if ( priv->periodic_cfg.periodic_mode ) {
+ return -1;
+ }
+
+ bits_per_char = priv->bits_per_char;
+ tx_word = 0;
+ if ( !txbuf ) {
+ tx_word = priv->idle_char << txshift;
+ }
+
+ /* Clear the events */
+ priv->regs->event = 0xffffffff;
+
+ /* Enable core */
+ priv->regs->mode |= SPICTRL_MODE_EN | SPICTRL_MODE_MS;
+
+ length = len;
+ if ( bits_per_char > 8 ) {
+ length = length / 2;
+ if ( bits_per_char > 16 )
+ length = length / 2;
+ }
+ DBG("SPICTRL: LENGTH = %d, Bits/Char: %d, Shift: %d, %d\n", length, bits_per_char, txshift, rxshift);
+
+ txi=0;
+ rxi=0;
+ while ( (rxi < length) || (txi < length) ) {
+ /* Get transmit word */
+ if ( length > txi ) {
+ if ( txbuf ) {
+ if ( bits_per_char <= 8 ) {
+ tx_word = *((unsigned char *)txbuf + txi);
+ } else if ( bits_per_char <= 16 ) {
+ tx_word = *((unsigned short *)txbuf + txi);
+ } else {
+ tx_word = *((unsigned int *)txbuf + txi);
+ }
+ tx_word = tx_word << txshift;
+ }
+
+ /* Wait for SPICTRL to get ready for another TX char */
+ while ( (priv->regs->event & SPICTRL_EVENT_NF) == 0 ) {
+ /* Wait for all chars to transmit */
+/* Could implement waiting for SPICTRL IRQ here */
+ }
+
+ DBG("SPICTRL: Writing 0x%x\n", tx_word);
+
+ /* Transmit word */
+ priv->regs->tx = tx_word;
+ txi++;
+ }
+
+ /* Read */
+ while ( priv->regs->event & SPICTRL_EVENT_NE ) {
+ /* Read to avoid overrun */
+ tmp = priv->regs->rx;
+ DBG("SPICTRL: Read 0x%x\n", tmp);
+
+ if ( rxbuf && (length > rxi) ) {
+ /* Copy word to user buffer */
+ rx_word = (tmp >> rxshift);
+
+ DBG("SPICTRL: Receiving 0x%x (0x%x, %d)\n", rx_word, tmp, rxshift);
+
+ if ( bits_per_char <= 8 ) {
+ *((unsigned char *)rxbuf + rxi) = rx_word;
+ } else if ( bits_per_char <= 16 ) {
+ *((unsigned short *)rxbuf + rxi) = rx_word;
+ } else {
+ *((unsigned int *)rxbuf + rxi) = rx_word;
+ }
+
+ }
+ rxi++;
+ }
+ }
+
+ return len;
+}
+
+
+STATIC rtems_status_code spictrl_libi2c_init(rtems_libi2c_bus_t *bushdl)
+{
+ struct spictrl_priv *priv = (struct spictrl_priv *)bushdl;
+
+ DBG("SPICTRL: spictrl_libi2c_init\n");
+
+ /* Disable SPICTTRL, Select Master mode */
+ priv->regs->mode = SPICTRL_MODE_MS;
+
+ /* Mask all Interrupts */
+ priv->regs->mask = 0;
+
+ /* Select no slave */
+ priv->regs->slvsel = 0xffffffff;
+
+ /* Clear all events */
+ priv->regs->event = 0xffffffff;
+
+ return 0;
+}
+
+/* Nothing to be done in start */
+STATIC rtems_status_code spictrl_libi2c_send_start(rtems_libi2c_bus_t *bushdl)
+{
+ DBG("SPICTRL: spictrl_libi2c_send_start\n");
+
+ return 0;
+}
+
+/* Inactivate all chip selects, indicates "End of command" */
+STATIC rtems_status_code spictrl_libi2c_send_stop(rtems_libi2c_bus_t *bushdl)
+{
+ struct spictrl_priv *priv = (struct spictrl_priv *)bushdl;
+
+ priv->regs->slvsel = 0xffffffff;
+
+ if ( priv->slvSelFunc ) {
+ /* unslect all */
+ return priv->slvSelFunc(priv->regs, -1, 0);
+ }
+
+ DBG("SPICTRL: spictrl_libi2c_send_stop\n");
+ return 0;
+}
+
+/* Select Slave address by selecting apropriate chip select */
+STATIC rtems_status_code spictrl_libi2c_send_addr(rtems_libi2c_bus_t *bushdl,
+ uint32_t addr, int rw)
+{
+ struct spictrl_priv *priv = (struct spictrl_priv *)bushdl;
+
+ DBG("SPICTRL: spictrl_libi2c_send_addr, %d\n", addr);
+
+ if ( priv->slvSelFunc ) {
+ /* Let user set spi select using for example GPIO */
+ return priv->slvSelFunc(priv->regs, addr, 1);
+ } else if ( priv->regs->capability & SPICTRL_CAP_SSEN ) {
+ int slaves;
+
+ /* Maximum number of slaves the core support */
+ slaves = (priv->regs->capability & SPICTRL_CAP_SSSZ) >> SPICTRL_CAP_SSSZ_BIT;
+
+ if ( addr > slaves )
+ return -1;
+
+ if ( (priv->regs->capability & SPICTRL_CAP_ASELA) &&
+ (priv->periodic_cfg.period_flags & SPICTRL_PERIOD_FLAGS_ASEL) ) {
+ /* When automatic slave select is supported by hardware and
+ * enabled by configuration the SPI address is determined by
+ * the automatic slave select register and the "idle" slave
+ * select register is set by configuration.
+ */
+ priv->regs->am_slvsel = ~(1<<(addr-1));
+ priv->regs->slvsel = priv->periodic_cfg.period_slvsel;
+ /* Enable automatic slave select */
+ priv->regs->mode |= SPICTRL_MODE_ASEL;
+ } else {
+ /* Normal mode */
+ priv->regs->slvsel = ~(1<<(addr-1));
+ }
+ }
+
+ return 0;
+}
+
+/* Read a number of bytes */
+STATIC int spictrl_libi2c_read_bytes(rtems_libi2c_bus_t *bushdl,
+ unsigned char *bytes, int nbytes)
+{
+ struct spictrl_priv *priv = (struct spictrl_priv *)bushdl;
+ int ret;
+
+ DBG("SPICTRL: spictrl_libi2c_read_bytes %d\n", nbytes);
+ ret = spictrl_read_write(priv, bytes, NULL, nbytes);
+ if ( ret < 0 ) {
+ printf("SPICTRL: Error Reading\n");
+ }
+#ifdef DEBUG
+ else {
+ int i;
+ for(i=0; i<nbytes; i+=16) {
+ DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x ",
+ bytes[0+i], bytes[1+i], bytes[2+i], bytes[3+i], bytes[4+i], bytes[5+i], bytes[6+i], bytes[7+i]);
+ DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
+ bytes[8+i], bytes[9+i], bytes[10+i], bytes[11+i], bytes[12+i], bytes[13+i], bytes[14+i], bytes[15+i]);
+ }
+ }
+#endif
+ return ret;
+}
+
+/* Write a number of bytes */
+STATIC int spictrl_libi2c_write_bytes(rtems_libi2c_bus_t *bushdl,
+ unsigned char *bytes, int nbytes)
+{
+ struct spictrl_priv *priv = (struct spictrl_priv *)bushdl;
+
+#ifdef DEBUG
+ int i;
+ DBG("SPICTRL: spictrl_libi2c_write_bytes: %d\n", nbytes);
+
+ for(i=0; i<nbytes; i+=16) {
+ DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x ",
+ bytes[0+i], bytes[1+i], bytes[2+i], bytes[3+i], bytes[4+i], bytes[5+i], bytes[6+i], bytes[7+i]);
+ DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
+ bytes[8+i], bytes[9+i], bytes[10+i], bytes[11+i], bytes[12+i], bytes[13+i], bytes[14+i], bytes[15+i]);
+ }
+#endif
+
+ return spictrl_read_write(priv, NULL, bytes, nbytes);
+}
+
+/* Configure the interface and do simultaneous READ/WRITE operations */
+STATIC int spictrl_libi2c_ioctl(
+ rtems_libi2c_bus_t * bushdl,
+ int cmd,
+ void *buffer)
+{
+ struct spictrl_priv *priv = (struct spictrl_priv *)bushdl;
+ int ret;
+
+ DBG("SPICTRL: spictrl_libi2c_ioctl(%d, 0x%x)\n", cmd, (unsigned int)buffer);
+
+ switch (cmd) {
+ case RTEMS_LIBI2C_IOCTL_SET_TFRMODE:
+ {
+ rtems_libi2c_tfr_mode_t *trf_mode = buffer;
+ unsigned int mode;
+
+ /* Must disable core to write new values */
+ priv->regs->mode &= ~SPICTRL_MODE_EN;
+
+ /* Change bit frequency */
+ if ( spictrl_set_freq(priv, trf_mode->baudrate) ) {
+ /* Unable to set such a low frequency. */
+ return -1;
+ }
+
+ /* Set Clock Polarity, Clock Phase, Reverse mode and Word Length */
+ mode = (priv->regs->mode &
+ ~(SPICTRL_MODE_CPOL|SPICTRL_MODE_CPHA|SPICTRL_MODE_REV|SPICTRL_MODE_LEN));
+ if ( trf_mode->clock_inv )
+ mode |= SPICTRL_MODE_CPOL;
+ if ( trf_mode->clock_phs )
+ mode |= SPICTRL_MODE_CPHA;
+ if ( trf_mode->lsb_first == 0 )
+ mode |= SPICTRL_MODE_REV; /* Set Reverse mode (MSB first) */
+
+ if ( (trf_mode->bits_per_char < 4) ||
+ ((trf_mode->bits_per_char > 16) && (trf_mode->bits_per_char != 32)) )
+ return -1;
+ if ( trf_mode->bits_per_char == 32 ) {
+ priv->txshift = 0;
+ priv->rxshift = 0;
+ } else {
+ mode |= (trf_mode->bits_per_char-1) << SPICTRL_MODE_LEN_BIT;
+ if ( trf_mode->lsb_first == 0 ) {
+ /* REV bit 1 */
+ priv->txshift = 32 - trf_mode->bits_per_char;
+ priv->rxshift = 16;
+ } else {
+ /* REV bit 0 */
+ priv->txshift = 0;
+ priv->rxshift = 16 - trf_mode->bits_per_char;
+ }
+ }
+
+ priv->bits_per_char = trf_mode->bits_per_char;
+ priv->lsb_first = trf_mode->lsb_first;
+ priv->idle_char = trf_mode->idle_char;
+
+ /* Update hardware */
+ priv->regs->mode = mode;
+
+ return 0;
+ }
+
+ case RTEMS_LIBI2C_IOCTL_READ_WRITE:
+ {
+ rtems_libi2c_read_write_t *arg = buffer;
+
+ DBG("SPICTRL: IOCTL READ/WRITE, RX: 0x%x, TX: 0x%x, len: %d\n", arg->rd_buf, arg->wr_buf, arg->byte_cnt);
+#ifdef DEBUG
+ /* Printf out what is going to be transmitted */
+ if ( arg->wr_buf ) {
+ unsigned char *bytes = (unsigned char *)arg->wr_buf;
+ int i;
+ for(i=0; i<arg->byte_cnt; i+=16) {
+ DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x ",
+ bytes[0+i], bytes[1+i], bytes[2+i], bytes[3+i], bytes[4+i], bytes[5+i], bytes[6+i], bytes[7+i]);
+ DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
+ bytes[8+i], bytes[9+i], bytes[10+i], bytes[11+i], bytes[12+i], bytes[13+i], bytes[14+i], bytes[15+i]);
+ }
+ }
+#endif
+
+ ret = spictrl_read_write(priv, arg->rd_buf, (unsigned char *)arg->wr_buf,
+ arg->byte_cnt);
+#ifdef DEBUG
+ /* Printf out what was read */
+ if ( arg->rd_buf ) {
+ unsigned char *bytes = (unsigned char *)arg->rd_buf;
+ int i;
+ for(i=0; i<arg->byte_cnt; i+=16) {
+ DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x ",
+ bytes[0+i], bytes[1+i], bytes[2+i], bytes[3+i], bytes[4+i], bytes[5+i], bytes[6+i], bytes[7+i]);
+ DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
+ bytes[8+i], bytes[9+i], bytes[10+i], bytes[11+i], bytes[12+i], bytes[13+i], bytes[14+i], bytes[15+i]);
+ }
+ }
+#endif
+ return ret;
+ }
+
+ /* Enable Periodic mode */
+ case SPICTRL_IOCTL_CONFIG:
+ {
+ struct spictrl_ioctl_config *cfg;
+
+ DBG("SPICTRL: Configuring Periodic mode\n");
+
+ if ( priv->periodic_started ) {
+ DBG("SPICTRL: Periodic mode already started, too late to configure\n");
+ return -1;
+ }
+
+ cfg = buffer;
+ if ( cfg == NULL ) {
+ memset(&priv->periodic_cfg, 0, sizeof(priv->periodic_cfg));
+ } else {
+ priv->periodic_cfg = *cfg;
+ }
+ cfg = &priv->periodic_cfg;
+ if ( cfg->periodic_mode ) {
+ /* Enable Automated Periodic mode */
+ priv->regs->mode |= SPICTRL_MODE_AMEN;
+
+ /* Check that hardware has support for periodic mode */
+ if ( (priv->regs->mode & SPICTRL_MODE_AMEN) == 0 ) {
+ priv->periodic_cfg.periodic_mode = 0;
+ DBG("SPICTRL: Periodic mode not supported by hardware\n");
+ return -1;
+ }
+ } else {
+ /* Disable Periodic mode */
+ priv->regs->mode &= ~SPICTRL_MODE_AMEN;
+ }
+ priv->periodic_started = 0;
+
+ /* Set clockgap and TAC */
+ priv->regs->mode = (priv->regs->mode & ~(SPICTRL_MODE_CG|SPICTRL_MODE_TAC)) |
+ (cfg->clock_gap << SPICTRL_MODE_CG_BIT) |
+ (cfg->flags & SPICTRL_MODE_TAC);
+ return 0;
+ }
+ case SPICTRL_IOCTL_PERIOD_START:
+ {
+ if ( !priv->periodic_cfg.periodic_mode || priv->periodic_started ) {
+ return -1;
+ }
+ if ( spictrl_start_periodic(priv) == 0 ) {
+ priv->periodic_started = 1;
+ return 0;
+ } else
+ return -1;
+ }
+ case SPICTRL_IOCTL_PERIOD_STOP:
+ {
+ if ( !priv->periodic_cfg.periodic_mode || !priv->periodic_started ) {
+ return -1;
+ }
+ spictrl_stop_periodic(priv);
+ priv->periodic_started = 0;
+ return 0;
+ }
+ case SPICTRL_IOCTL_STATUS:
+ {
+ if ( !buffer )
+ return 0;
+ *(unsigned int *)buffer = spictrl_status(priv);
+ return 0;
+ }
+
+ case SPICTRL_IOCTL_PERIOD_WRITE:
+ {
+ if ( !priv->periodic_cfg.periodic_mode || !buffer ) {
+ return -1;
+ }
+ if ( spictrl_write_periodic(priv, (struct spictrl_period_io *)
+ buffer) == 0 ) {
+ return 0;
+ } else
+ return -1;
+ }
+
+ case SPICTRL_IOCTL_PERIOD_READ:
+ {
+ if ( !priv->periodic_cfg.periodic_mode || !buffer ) {
+ return -1;
+ }
+ if ( spictrl_read_periodic(priv, (struct spictrl_period_io *)
+ buffer) == 0 ) {
+ return 0;
+ } else
+ return -1;
+ }
+
+ case SPICTRL_IOCTL_REGS:
+ {
+ /* Copy Register Base Address to user space */
+ if ( !buffer ) {
+ return -1;
+ }
+ *(struct spictrl_regs **)buffer = priv->regs;
+ return 0;
+ }
+
+ default:
+ /* Unknown IOCTL */
+ return -1;
+ }
+
+ return 0;
+}
+
+STATIC rtems_libi2c_bus_ops_t spictrl_libi2c_ops =
+{
+ .init = spictrl_libi2c_init,
+ .send_start = spictrl_libi2c_send_start,
+ .send_stop = spictrl_libi2c_send_stop,
+ .send_addr = spictrl_libi2c_send_addr,
+ .read_bytes = spictrl_libi2c_read_bytes,
+ .write_bytes = spictrl_libi2c_write_bytes,
+ .ioctl = spictrl_libi2c_ioctl
+};
+
+int spictrl_device_init(struct spictrl_priv *priv)
+{
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
+ union drvmgr_key_value *value;
+
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)priv->dev->businfo;
+ if ( ambadev == NULL ) {
+ return -1;
+ }
+ pnpinfo = &ambadev->info;
+ priv->irq = pnpinfo->irq;
+ priv->regs = (struct spictrl_regs *)pnpinfo->apb_slv->start;
+ priv->fdepth = (priv->regs->capability & SPICTRL_CAP_FDEPTH) >> SPICTRL_CAP_FDEPTH_BIT;
+
+ DBG("SPCTRL: 0x%x irq %d, FIFO: %d\n", (unsigned int)priv->regs, priv->irq, priv->fdepth);
+
+ /* Mask all Interrupts */
+ priv->regs->mask = 0;
+
+ /* Disable SPICTTRL */
+ priv->regs->mode = 0;
+
+ /* Get custom */
+ value = drvmgr_dev_key_get(priv->dev, "slvSelFunc", KEY_TYPE_POINTER);
+ if ( value ) {
+ priv->slvSelFunc = value->ptr;
+ }
+
+ /* Prepare I2C layer */
+ priv->i2clib_desc.ops = &spictrl_libi2c_ops;
+ priv->i2clib_desc.size = sizeof(spictrl_libi2c_ops);
+ return 0;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/spw/grspw.c b/c/src/lib/libbsp/sparc/shared/spw/grspw.c
index cd6c801cb6..42dbeae887 100644
--- a/c/src/lib/libbsp/sparc/shared/spw/grspw.c
+++ b/c/src/lib/libbsp/sparc/shared/spw/grspw.c
@@ -1,14 +1,17 @@
/*
* This file contains the GRSPW SpaceWire Driver for LEON2 and LEON3.
*
- * COPYRIGHT (c) 2007
- * Gaisler Research.
+ * COPYRIGHT (c) 2008
+ * Aeroflex Gaisler.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
*
* Changes:
+ *
+ * 2008-12-09, Daniel Hellstrom <daniel@gaisler.com>
+ * Converted driver to support driver manager
*
* 2007-09-27, Daniel Hellstrom <daniel@gaisler.com>
* Added basic support for GRSPW2 core.
@@ -23,23 +26,23 @@
* Typical LEON3 register: grspw_register(&amba_conf);
*
* 2007-05-28, Daniel Hellstrom <daniel@gaisler.com>
- * Changed errno return values, compatible with RASTA
+ * Changed errno return values, compatible with RASTA
* Spacewire driver
*
* 2007-05-25, Daniel Hellstrom <daniel@gaisler.com>
- * Changed name from /dev/spacewire,/dev/spacewire_b...
+ * Changed name from /dev/spacewire,/dev/spacewire_b...
* to /dev/grspw0,/dev/grspw1...
*
* 2007-05-24, Daniel Hellstrom <daniel@gaisler.com>
* Merged LEON3, LEON2 and RASTA driver to one - this.
- * The driver is included and configured from grspw_pci.c
+ * The driver is included and configured from grspw_pci.c
* and grspw_rasta.c.
*
* 2007-05-23, Daniel Hellstrom <daniel@gaisler.com>
* Changed open call, now one need to first call open
* and then ioctl(fd,START,timeout) in order to setup
* hardware for communication.
- *
+ *
* 2007-05-23, Daniel Hellstrom <daniel@gaisler.com>
* Added ioctl(fd,SET_COREFREQ,freq_arg), the command
* can autodetect the register values disconnect and
@@ -48,32 +51,6 @@
*
*/
-/* default name to /dev/grspw0 */
-#if !defined(GRSPW_DEVNAME) || !defined(GRSPW_DEVNAME_NO)
- #undef GRSPW_DEVNAME
- #undef GRSPW_DEVNAME_NO
- #define GRSPW_DEVNAME "/dev/grspw0"
- #define GRSPW_DEVNAME_NO(devstr,no) ((devstr)[10]='0'+(no))
-#endif
-
-#ifndef GRSPW_PREFIX
- #define GRSPW_PREFIX(name) grspw##name
-#endif
-
-/* default to no translation */
-#ifndef GRSPW_ADR_TO
- #define memarea_to_hw(x) ((unsigned int)(x))
-#endif
-#ifndef GRSPW_ADR_FROM
- #define hw_to_memarea(x) ((unsigned int)(x))
-#endif
-
-#ifndef GRSPW_REG_INT
- #define GRSPW_REG_INT(handler,irqno,arg) set_vector(handler,irqno+0x10,1)
- #undef GRSPW_DEFINE_INTHANDLER
- #define GRSPW_DEFINE_INTHANDLER
-#endif
-
#include <bsp.h>
#include <rtems/libio.h>
#include <stdlib.h>
@@ -83,6 +60,9 @@
#include <ctype.h>
#include <rtems/bspIo.h>
#include <ambapp.h>
+
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
#include <grspw.h>
#define DBGSPW_IOCALLS 1
@@ -93,7 +73,7 @@
#define DEBUG_SPACEWIRE_FLAGS (DBGSPW_IOCALLS | DBGSPW_TX | DBGSPW_RX )
/* #define DEBUG_SPACEWIRE_ONOFF */
-
+
#ifdef DEBUG_SPACEWIRE_ONOFF
#define SPACEWIRE_DBG(fmt, args...) do { { printk(" : %03d @ %18s()]:" fmt , __LINE__,__FUNCTION__,## args); }} while(0)
#define SPACEWIRE_DBG2(fmt) do { { printk(" : %03d @ %18s()]:" fmt , __LINE__,__FUNCTION__); }} while(0)
@@ -113,15 +93,15 @@ typedef struct {
volatile unsigned int time;
volatile unsigned int timer;
volatile unsigned int pad;
-
- volatile unsigned int dma0ctrl;
+
+ volatile unsigned int dma0ctrl;
volatile unsigned int dma0rxmax;
volatile unsigned int dma0txdesc;
volatile unsigned int dma0rxdesc;
-
+
/* For GRSPW core 2 and onwards */
volatile unsigned int dma0addr;
-
+
} LEON3_SPACEWIRE_Regs_Map;
typedef struct {
@@ -149,7 +129,10 @@ typedef struct {
#define SPW_ALIGN(p,c) ((((unsigned int)(p))+((c)-1))&~((c)-1))
typedef struct {
- /* configuration parameters */
+ /* configuration parameters */
+ struct drvmgr_dev *dev; /* Driver manager device */
+ char devName[32]; /* Device Name */
+ LEON3_SPACEWIRE_Regs_Map *regs;
spw_config config;
unsigned int tx_all_in_use;
@@ -163,12 +146,24 @@ typedef struct {
unsigned int txbufcnt;
unsigned int rxbufcnt;
+ /* DMA Area set by user */
+ unsigned int rx_dma_area;
+ unsigned int tx_data_dma_area;
+ unsigned int tx_hdr_dma_area;
+ unsigned int bd_dma_area;
+
/* statistics */
spw_stats stat;
+ unsigned int _ptr_rxbuf0;
char *ptr_rxbuf0;
char *ptr_txdbuf0;
char *ptr_txhbuf0;
+ char *ptr_bd0;
+
+ char *ptr_rxbuf0_remote;
+ char *ptr_txdbuf0_remote;
+ char *ptr_txhbuf0_remote;
unsigned int irq;
int minor;
@@ -176,7 +171,7 @@ typedef struct {
int open;
int running;
unsigned int core_freq_khz;
-
+ unsigned int rtimeout;
/* semaphores*/
rtems_id txsp;
@@ -185,48 +180,53 @@ typedef struct {
SPACEWIRE_RXBD *rx;
SPACEWIRE_TXBD *tx;
-#ifdef GRSPW_STATIC_MEM
- unsigned int membase, memend, mem_bdtable;
-#else
- char _rxtable[SPACEWIRE_BDTABLE_SIZE*2];
- char _txtable[SPACEWIRE_BDTABLE_SIZE*2];
-#endif
-
- LEON3_SPACEWIRE_Regs_Map *regs;
+ unsigned int rx_remote;
+ unsigned int tx_remote;
} GRSPW_DEV;
-static int spw_cores;
-static int spw_cores2;
-static unsigned int sys_freq_khz;
-static GRSPW_DEV *grspw_devs;
+/* Function pointer called upon timecode receive */
+void (*grspw_timecode_callback)
+ (void *pDev, void *regs, int minor, unsigned int tc) = NULL;
#ifdef GRSPW_DONT_BYPASS_CACHE
#define _SPW_READ(address) (*(volatile unsigned int *)(address))
-#define _MEM_READ(address) (*(volatile unsigned char *)(address))
+#define _MEM_READ8(address) (*(volatile unsigned char *)(address))
+#define _MEM_READ32(address) (*(volatile unsigned int *)(address))
#else
-static unsigned int _SPW_READ(void *addr) {
+static inline unsigned int _SPW_READ(volatile void *addr) {
unsigned int tmp;
- asm(" lda [%1]1, %0 "
+ asm volatile (" lda [%1]1, %0 "
: "=r"(tmp)
: "r"(addr)
);
return tmp;
}
-static unsigned int _MEM_READ(void *addr) {
+static inline unsigned int _MEM_READ8(volatile void *addr) {
unsigned int tmp;
- asm(" lduba [%1]1, %0 "
+ asm volatile (" lduba [%1]1, %0 "
: "=r"(tmp)
: "r"(addr)
);
- return tmp;
+ return tmp;
+
+}
+
+static inline unsigned int _MEM_READ32(volatile void *addr) {
+ unsigned int tmp;
+ asm volatile (" lda [%1]1, %0 "
+ : "=r"(tmp)
+ : "r"(addr)
+ );
+ return tmp;
}
#endif
-#define MEM_READ(addr) _MEM_READ((void *)(addr))
-#define SPW_READ(addr) _SPW_READ((void *)(addr))
-#define SPW_WRITE(addr,v) *addr=v
+#define MEM_READ8(addr) _MEM_READ8((volatile void *)(addr))
+#define MEM_READ32(addr) _MEM_READ32((volatile void *)(addr))
+#define SPW_READ(addr) _SPW_READ((volatile void *)(addr))
+#define SPW_WRITE(addr,v) (*(volatile unsigned int *)addr)=v
#define SPW_REG(c,r) (c->regs->r)
#define SPW_REG_CTRL(c) SPW_REG(c,ctrl)
@@ -264,6 +264,8 @@ static unsigned int _MEM_READ(void *addr) {
#define SPW_TXBD_WR (1 << 13)
#define SPW_TXBD_IE (1 << 14)
#define SPW_TXBD_LE (1 << 15)
+#define SPW_TXBD_HC (1 << 16)
+#define SPW_TXBD_DC (1 << 17)
#define SPW_TXBD_ERROR (SPW_TXBD_LE)
@@ -312,7 +314,7 @@ static unsigned int _MEM_READ(void *addr) {
#define SPW_PREPAREMASK_RX (SPW_DMACTRL_TXEN | SPW_DMACTRL_TXIE | SPW_DMACTRL_AI | SPW_DMACTRL_PR | SPW_DMACTRL_RA)
static int grspw_hw_init(GRSPW_DEV *pDev);
-static int grspw_hw_send(GRSPW_DEV *pDev, unsigned int hlen, char *hdr, unsigned int dlen, char *data);
+static int grspw_hw_send(GRSPW_DEV *pDev, unsigned int hlen, char *hdr, unsigned int dlen, char *data, unsigned int options);
static int grspw_hw_receive(GRSPW_DEV *pDev,char *b,int c);
static int grspw_hw_startup (GRSPW_DEV *pDev, int timeout);
static int grspw_hw_stop (GRSPW_DEV *pDev, int rx, int tx);
@@ -323,7 +325,8 @@ static void grspw_hw_read_config(GRSPW_DEV *pDev);
static void check_rx_errors(GRSPW_DEV *pDev, int ctrl);
static void grspw_rxnext(GRSPW_DEV *pDev);
-static void grspw_interrupt(GRSPW_DEV *pDev);
+static void grspw_interrupt(void *arg);
+static int grspw_buffer_alloc(GRSPW_DEV *pDev);
static rtems_device_driver grspw_initialize(
rtems_device_major_number major,
@@ -370,74 +373,272 @@ static rtems_device_driver grspw_control(
grspw_control }
static rtems_driver_address_table grspw_driver = GRSPW_DRIVER_TABLE_ENTRY;
-static amba_confarea_type *amba_bus;
+static int grspw_driver_io_registered = 0;
+static rtems_device_major_number grspw_driver_io_major = 0;
-int GRSPW_PREFIX(_register)(amba_confarea_type *bus)
-{
- rtems_status_code r;
- rtems_device_major_number m;
+/******************* Driver manager interface ***********************/
- /* Get System clock frequency */
- sys_freq_khz = 0;
+/* Driver prototypes */
+int grspw_register_io(rtems_device_major_number *m);
+int grspw_device_init(GRSPW_DEV *pDev);
- amba_bus = bus;
+int grspw_init2(struct drvmgr_dev *dev);
+int grspw_init3(struct drvmgr_dev *dev);
- /* Auto Detect the GRSPW core frequency by assuming that the system frequency is
- * is the same as the GRSPW core frequency.
- */
-#ifndef SYS_FREQ_KHZ
-#ifdef LEON3
- /* LEON3: find timer address via AMBA Plug&Play info */
+struct drvmgr_drv_ops grspw_ops =
+{
+ .init = {NULL, grspw_init2, grspw_init3, NULL},
+ .remove = NULL,
+ .info = NULL
+};
+
+struct amba_dev_id grspw_ids[] =
+{
+ {VENDOR_GAISLER, GAISLER_SPW},
+ {VENDOR_GAISLER, GAISLER_SPW2},
+ {VENDOR_GAISLER, GAISLER_SPW2_DMA},
+ {0, 0} /* Mark end of table */
+};
+
+struct amba_drv_info grspw_drv_info =
+{
{
- amba_apb_device gptimer;
- LEON3_Timer_Regs_Map *tregs;
-
- if ( amba_find_apbslv(&amba_conf,VENDOR_GAISLER,GAISLER_GPTIMER,&gptimer) == 1 ){
- tregs = (LEON3_Timer_Regs_Map *)gptimer.start;
- sys_freq_khz = (tregs->scaler_reload+1)*1000;
- SPACEWIRE_DBG("GRSPW: detected %dkHZ system frequency\n\r",sys_freq_khz);
- }else{
- sys_freq_khz = 40000; /* Default to 40MHz */
- printk("GRSPW: Failed to detect system frequency\n\r");
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_AMBAPP_GAISLER_GRSPW_ID, /* Driver ID */
+ "GRSPW_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */
+ &grspw_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ 0,
+ },
+ &grspw_ids[0]
+};
+
+void grspw_register_drv (void)
+{
+ SPACEWIRE_DBG("Registering GRSPW driver\n");
+ drvmgr_drv_register(&grspw_drv_info.general);
+}
+
+int grspw_init2(struct drvmgr_dev *dev)
+{
+ GRSPW_DEV *priv;
+
+ SPACEWIRE_DBG("GRSPW[%d] on bus %s\n", dev->minor_drv,
+ dev->parent->dev->name);
+ priv = dev->priv = malloc(sizeof(GRSPW_DEV));
+ if ( !priv )
+ return DRVMGR_NOMEM;
+ memset(priv, 0, sizeof(*priv));
+ priv->dev = dev;
+
+ /* This core will not find other cores, so we wait for init2() */
+
+ return DRVMGR_OK;
+}
+
+int grspw_init3(struct drvmgr_dev *dev)
+{
+ GRSPW_DEV *priv;
+ char prefix[32];
+ rtems_status_code status;
+
+ priv = dev->priv;
+
+ /* Do initialization */
+
+ if ( grspw_driver_io_registered == 0) {
+ /* Register the I/O driver only once for all cores */
+ if ( grspw_register_io(&grspw_driver_io_major) ) {
+ /* Failed to register I/O driver */
+ free(dev->priv);
+ dev->priv = NULL;
+ return DRVMGR_FAIL;
}
+ grspw_driver_io_registered = 1;
}
-#elif defined(LEON2)
- /* LEON2: use hardcoded address to get to timer */
- {
- LEON_Register_Map *regs = (LEON_Register_Map *)0x80000000;
- sys_freq_khz = (regs->Scaler_Reload+1)*1000;
- }
-#else
- #error CPU not supported by GRSPW driver
-#endif
-#else
- /* Use hardcoded frequency */
- sys_freq_khz = SYS_FREQ_KHZ;
-#endif
- SPACEWIRE_DBG2("register driver\n");
- if ((r = rtems_io_register_driver(0, &grspw_driver, &m)) == RTEMS_SUCCESSFUL) {
- SPACEWIRE_DBG2("success\n");
- return 0;
- } else {
- switch(r) {
- case RTEMS_TOO_MANY:
- SPACEWIRE_DBG2("failed RTEMS_TOO_MANY\n");
- break;
- case RTEMS_INVALID_NUMBER:
- SPACEWIRE_DBG2("failed RTEMS_INVALID_NUMBER\n");
- break;
- case RTEMS_RESOURCE_IN_USE:
- SPACEWIRE_DBG2("failed RTEMS_RESOURCE_IN_USE\n");
- break;
- default:
- SPACEWIRE_DBG("failed %i\n",r);
- break;
- }
- return 1;
- }
+ /* I/O system registered and initialized
+ * Now we take care of device initialization.
+ */
+
+ /* Get frequency in Hz */
+ if ( drvmgr_freq_get(dev, DEV_APB_SLV, &priv->core_freq_khz) ) {
+ return DRVMGR_FAIL;
+ }
+ /* Convert from Hz -> kHz */
+ priv->core_freq_khz = priv->core_freq_khz / 1000;
+
+ if ( grspw_device_init(priv) ) {
+ return DRVMGR_FAIL;
+ }
+
+ /* Get Filesystem name prefix */
+ prefix[0] = '\0';
+ if ( drvmgr_get_dev_prefix(dev, prefix) ) {
+ /* Failed to get prefix, make sure of a unique FS name
+ * by using the driver minor.
+ */
+ sprintf(priv->devName, "/dev/grspw%d", dev->minor_drv);
+ } else {
+ /* Got special prefix, this means we have a bus prefix
+ * And we should use our "bus minor"
+ */
+ sprintf(priv->devName, "/dev/%sgrspw%d", prefix, dev->minor_bus);
+ }
+
+ /* Register Device */
+ status = rtems_io_register_name(priv->devName, grspw_driver_io_major, dev->minor_drv);
+ if (status != RTEMS_SUCCESSFUL) {
+ return DRVMGR_FAIL;
+ }
+ return DRVMGR_OK;
+}
+
+/******************* Driver Implementation ***********************/
+
+int grspw_register_io(rtems_device_major_number *m)
+{
+ rtems_status_code r;
+
+ if ((r = rtems_io_register_driver(0, &grspw_driver, m)) == RTEMS_SUCCESSFUL) {
+ SPACEWIRE_DBG("GRSPW driver successfully registered, major: %d\n", *m);
+ } else {
+ switch(r) {
+ case RTEMS_TOO_MANY:
+ printk("GRSPW rtems_io_register_driver failed: RTEMS_TOO_MANY\n");
+ return -1;
+ case RTEMS_INVALID_NUMBER:
+ printk("GRSPW rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n");
+ return -1;
+ case RTEMS_RESOURCE_IN_USE:
+ printk("GRSPW rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n");
+ return -1;
+ default:
+ printk("GRSPW rtems_io_register_driver failed\n");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int grspw_device_init(GRSPW_DEV *pDev)
+{
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
+ union drvmgr_key_value *value;
+
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)pDev->dev->businfo;
+ if ( ambadev == NULL ) {
+ return -1;
+ }
+ pnpinfo = &ambadev->info;
+ pDev->irq = pnpinfo->irq;
+ pDev->regs = (LEON3_SPACEWIRE_Regs_Map *)pnpinfo->apb_slv->start;
+ pDev->minor = pDev->dev->minor_drv;
+
+ /* Get SpaceWire core version */
+ switch( pnpinfo->device ) {
+ case GAISLER_SPW:
+ pDev->core_ver = 1;
+ break;
+ case GAISLER_SPW2:
+ pDev->core_ver = 2;
+ break;
+ case GAISLER_SPW2_DMA:
+ pDev->core_ver = 3;
+ break;
+ default:
+ return -1;
+ }
+
+ /* initialize the code with some resonable values,
+ * actual initialization is done later using ioctl(fd)
+ * on the opened device */
+ pDev->config.rxmaxlen = SPACEWIRE_RXPCK_SIZE;
+ pDev->txdbufsize = SPACEWIRE_TXD_SIZE;
+ pDev->txhbufsize = SPACEWIRE_TXH_SIZE;
+ pDev->rxbufsize = SPACEWIRE_RXPCK_SIZE;
+ pDev->txbufcnt = SPACEWIRE_TXBUFS_NR;
+ pDev->rxbufcnt = SPACEWIRE_RXBUFS_NR;
+
+ pDev->_ptr_rxbuf0 = 0;
+ pDev->ptr_rxbuf0 = 0;
+ pDev->ptr_txdbuf0 = 0;
+ pDev->ptr_txhbuf0 = 0;
+ pDev->ptr_bd0 = 0;
+ pDev->rx_dma_area = 0;
+ pDev->tx_data_dma_area = 0;
+ pDev->tx_hdr_dma_area = 0;
+ pDev->bd_dma_area = 0;
+
+ /* Get Configuration from Bus resources (Let user override defaults) */
+
+ value = drvmgr_dev_key_get(pDev->dev, "txBdCnt", KEY_TYPE_INT);
+ if ( value )
+ pDev->txbufcnt = value->i;
+
+ value = drvmgr_dev_key_get(pDev->dev, "rxBdCnt", KEY_TYPE_INT);
+ if ( value )
+ pDev->rxbufcnt = value->i;
+
+ value = drvmgr_dev_key_get(pDev->dev, "txDataSize", KEY_TYPE_INT);
+ if ( value )
+ pDev->txdbufsize = value->i;
+
+ value = drvmgr_dev_key_get(pDev->dev, "txHdrSize", KEY_TYPE_INT);
+ if ( value )
+ pDev->txhbufsize = value->i;
+
+ value = drvmgr_dev_key_get(pDev->dev, "rxPktSize", KEY_TYPE_INT);
+ if ( value )
+ pDev->rxbufsize = value->i;
+
+ value = drvmgr_dev_key_get(pDev->dev, "rxDmaArea", KEY_TYPE_INT);
+ if ( value )
+ pDev->rx_dma_area = value->i;
+
+ value = drvmgr_dev_key_get(pDev->dev, "txDataDmaArea", KEY_TYPE_INT);
+ if ( value )
+ pDev->tx_data_dma_area = value->i;
+
+ value = drvmgr_dev_key_get(pDev->dev, "txHdrDmaArea", KEY_TYPE_INT);
+ if ( value )
+ pDev->tx_hdr_dma_area = value->i;
+
+ value = drvmgr_dev_key_get(pDev->dev, "bdDmaArea", KEY_TYPE_INT);
+ if ( value )
+ pDev->bd_dma_area = value->i;
+
+ if (grspw_buffer_alloc(pDev))
+ return RTEMS_NO_MEMORY;
+
+ /* Create semaphores */
+ rtems_semaphore_create(
+ rtems_build_name('T', 'x', 'S', '0' + pDev->minor),
+ 0,
+ RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | \
+ RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &(pDev->txsp));
+
+ rtems_semaphore_create(
+ rtems_build_name('R', 'x', 'S', '0' + pDev->minor),
+ 0,
+ RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | \
+ RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &(pDev->rxsp));
+
+ grspw_hw_init(pDev);
+
+ return 0;
}
/* Get a value at least 6.4us in number of clock cycles */
@@ -452,1184 +653,1212 @@ static unsigned int grspw_calc_disconnect(int freq_khz){
return disconnect & 0x3ff;
}
-#if 0
-static int grspw_buffer_alloc(GRSPW_DEV *pDev) {
- if (pDev->ptr_rxbuf0) {
- free(pDev->ptr_rxbuf0);
- }
- if (pDev->ptr_txdbuf0) {
- free(pDev->ptr_txdbuf0);
- }
- if (pDev->ptr_txhbuf0) {
- free(pDev->ptr_txhbuf0);
- }
- pDev->ptr_rxbuf0 = (char *) malloc(pDev->rxbufsize * pDev->rxbufcnt);
- pDev->ptr_txdbuf0 = (char *) malloc(pDev->txdbufsize * pDev->txbufcnt);
- pDev->ptr_txhbuf0 = (char *) malloc(pDev->txhbufsize * pDev->txbufcnt);
- if ((pDev->ptr_rxbuf0 == NULL) ||
- (pDev->ptr_txdbuf0 == NULL) || (pDev->ptr_txhbuf0 == NULL)) {
- return 1;
- } else {
- return 0;
- }
-}
-#endif
-
static int grspw_buffer_alloc(GRSPW_DEV *pDev)
{
-#ifndef GRSPW_STATIC_MEM
- if (pDev->ptr_rxbuf0) {
- free(pDev->ptr_rxbuf0);
- }
- if (pDev->ptr_txdbuf0) {
- free(pDev->ptr_txdbuf0);
- }
- if (pDev->ptr_txhbuf0) {
- free(pDev->ptr_txhbuf0);
- }
-
- pDev->ptr_rxbuf0 = (char *) malloc(pDev->rxbufsize * pDev->rxbufcnt);
- pDev->ptr_txdbuf0 = (char *) malloc(pDev->txdbufsize * pDev->txbufcnt);
- pDev->ptr_txhbuf0 = (char *) malloc(pDev->txhbufsize * pDev->txbufcnt);
- if ((pDev->ptr_rxbuf0 == NULL) ||
- (pDev->ptr_txdbuf0 == NULL) || (pDev->ptr_txhbuf0 == NULL)) {
- return 1;
- } else {
- return 0;
- }
-#else
- if ( (pDev->membase + pDev->rxbufsize*pDev->rxbufcnt + pDev->txdbufsize*pDev->txbufcnt) >= pDev->memend ) {
- return -1;
- }
- pDev->ptr_rxbuf0 = (char *) pDev->membase;
- pDev->ptr_txdbuf0 = pDev->ptr_rxbuf0 + pDev->rxbufsize * pDev->rxbufcnt;
- pDev->ptr_txhbuf0 = pDev->ptr_txdbuf0 + pDev->txdbufsize * pDev->txbufcnt;
- return 0;
-#endif
+ if ( pDev->rx_dma_area ) {
+#warning Check size?
+ if ( pDev->rx_dma_area & 1 ) {
+ /* Address given in remote address */
+ drvmgr_translate(pDev->dev, 1, 1, (void *)(pDev->rx_dma_area & ~1), (void **)&pDev->ptr_rxbuf0);
+ } else {
+ pDev->ptr_rxbuf0 = pDev->rx_dma_area;
+ }
+ } else {
+ if (pDev->_ptr_rxbuf0) {
+ free(pDev->_ptr_rxbuf0);
+ }
+ pDev->_ptr_rxbuf0 = (unsigned int) malloc(pDev->rxbufsize * pDev->rxbufcnt+4);
+ pDev->ptr_rxbuf0 = (char *)((pDev->_ptr_rxbuf0+7)&~7);
+ if ( !pDev->ptr_rxbuf0 )
+ return 1;
+ }
+ if ( pDev->tx_data_dma_area ) {
+ if ( pDev->tx_data_dma_area & 1 ) {
+ /* Address given in remote address */
+ drvmgr_translate(pDev->dev, 1, 1, (void *)(pDev->tx_data_dma_area & ~1), (void **)&pDev->ptr_txdbuf0);
+ } else {
+ pDev->ptr_txdbuf0 = pDev->tx_data_dma_area;
+ }
+ } else {
+ if (pDev->ptr_txdbuf0) {
+ free(pDev->ptr_txdbuf0);
+ }
+ pDev->ptr_txdbuf0 = (char *) malloc(pDev->txdbufsize * pDev->txbufcnt);
+ if ( !pDev->ptr_txdbuf0 )
+ return 1;
+ }
+ if ( pDev->tx_hdr_dma_area ) {
+ if ( pDev->tx_hdr_dma_area & 1 ) {
+ /* Address given in remote address */
+ drvmgr_translate(pDev->dev, 1, 1, (void *)(pDev->tx_hdr_dma_area & ~1), (void **)&pDev->ptr_txhbuf0);
+ } else {
+ pDev->ptr_txhbuf0 = pDev->tx_hdr_dma_area;
+ }
+ } else {
+ if (pDev->ptr_txhbuf0) {
+ free(pDev->ptr_txhbuf0);
+ }
+ pDev->ptr_txhbuf0 = (char *) malloc(pDev->txhbufsize * pDev->txbufcnt);
+ if ( !pDev->ptr_txhbuf0 )
+ return 1;
+ }
+ if ( pDev->bd_dma_area ) {
+ if ( pDev->bd_dma_area & 1 ) {
+ /* Address given in remote address */
+ drvmgr_translate(pDev->dev, 1, 1, (void *)(pDev->bd_dma_area & ~1), (void **)&pDev->ptr_bd0);
+ } else {
+ pDev->ptr_bd0 = pDev->bd_dma_area;
+ }
+ } else {
+ if (pDev->ptr_bd0) {
+ free(pDev->ptr_bd0);
+ }
+ pDev->ptr_bd0 = (char *) malloc(3*SPACEWIRE_BDTABLE_SIZE);
+ if ( !pDev->ptr_bd0 )
+ return 1;
+ }
+ /* Translate into remote address */
+ drvmgr_translate(pDev->dev, 0, 0, (void *)pDev->ptr_rxbuf0, (void **)&pDev->ptr_rxbuf0_remote);
+ drvmgr_translate(pDev->dev, 0, 0, (void *)pDev->ptr_txdbuf0,(void **)&pDev->ptr_txdbuf0_remote);
+ drvmgr_translate(pDev->dev, 0, 0, (void *)pDev->ptr_txhbuf0, (void **)&pDev->ptr_txhbuf0_remote);
+ return 0;
}
-#ifdef GRSPW_DEFINE_INTHANDLER
-/*
- * Standard Interrupt handler
- */
-static rtems_isr grspw_interrupt_handler(rtems_vector_number v)
+static void grspw_interrupt(void *arg)
{
- int minor;
-
- for(minor = 0; minor < spw_cores+spw_cores2; minor++) {
- if (v == (grspw_devs[minor].irq+0x10) ) {
- grspw_interrupt(&grspw_devs[minor]);
- break;
- }
- }
-}
-#endif
-
-static void grspw_interrupt(GRSPW_DEV *pDev){
- int dmactrl;
- int status;
- int ctrl;
-
- status = SPW_STATUS_READ(pDev);
- SPW_STATUS_WRITE(pDev, SPW_STATUS_CE | SPW_STATUS_ER | SPW_STATUS_DE | SPW_STATUS_PE | SPW_STATUS_WE | SPW_STATUS_IA | SPW_STATUS_EE);
- dmactrl = SPW_READ(&pDev->regs->dma0ctrl);
- SPW_WRITE(&pDev->regs->dma0ctrl, dmactrl | SPW_DMACTRL_PR);
- /* If linkinterrupts are enabled check if it was a linkerror irq and then send an event to the
- process set in the config */
- if (pDev->config.link_err_irq) {
- if (status & (SPW_STATUS_CE | SPW_STATUS_ER | SPW_STATUS_DE | SPW_STATUS_PE | SPW_STATUS_WE)) {
- rtems_event_send(pDev->config.event_id, SPW_LINKERR_EVENT);
- if (pDev->config.disable_err) {
- /* disable link*/
- SPW_CTRL_WRITE(pDev, (SPW_CTRL_READ(pDev) & 0xFFFFFFFC) | SPW_CTRL_LINKDISABLED);
- pDev->config.linkdisabled = 1;
- pDev->config.linkstart = 0;
- pDev->running = 0;
- }
- }
- }
- if (status & SPW_STATUS_CE) {
- pDev->stat.credit_err++;
- }
- if (status & SPW_STATUS_ER) {
- pDev->stat.escape_err++;
- }
- if (status & SPW_STATUS_DE) {
- pDev->stat.disconnect_err++;
- }
- if (status & SPW_STATUS_PE) {
- pDev->stat.parity_err++;
- }
- if (status & SPW_STATUS_WE) {
- pDev->stat.write_sync_err++;
- }
- if (status & SPW_STATUS_IA) {
- pDev->stat.invalid_address++;
- }
- if (status & SPW_STATUS_EE) {
- pDev->stat.early_ep++;
- }
-
- /* Check for tx interrupts */
- while( (pDev->tx_sent != pDev->tx_cur) || pDev->tx_all_in_use) {
- /* Has this descriptor been sent? */
- ctrl = SPW_READ((volatile void *)&pDev->tx[pDev->tx_sent].ctrl);
- if ( ctrl & SPW_TXBD_EN ) {
- break;
- }
- /* Yes, increment status counters & tx_sent so we can use this descriptor to send more packets with */
- pDev->stat.packets_sent++;
-
- rtems_semaphore_release(pDev->txsp);
-
- if ( ctrl & SPW_TXBD_LE ) {
- pDev->stat.tx_link_err++;
- }
-
- /* step to next descriptor */
- pDev->tx_sent = (pDev->tx_sent + 1) % pDev->txbufcnt;
- pDev->tx_all_in_use = 0; /* not all of the descriptors can be in use since we just freed one. */
- }
-
- /* Check for rx interrupts */
- if (dmactrl & SPW_DMACTRL_PR) {
- rtems_semaphore_release(pDev->rxsp);
- }
-}
+ GRSPW_DEV *pDev = (GRSPW_DEV *)arg;
+ int dmactrl;
+ int status;
+ int ctrl;
+ unsigned int timecode;
+
+ status = SPW_STATUS_READ(pDev);
+ /*SPW_STATUS_WRITE(pDev, SPW_STATUS_CE | SPW_STATUS_ER | SPW_STATUS_DE | SPW_STATUS_PE | SPW_STATUS_WE | SPW_STATUS_IA | SPW_STATUS_EE | SPW_STATUS_TO);*/
+ SPW_STATUS_WRITE(pDev, status & (SPW_STATUS_CE | SPW_STATUS_ER | SPW_STATUS_DE | SPW_STATUS_PE | SPW_STATUS_WE | SPW_STATUS_IA | SPW_STATUS_EE));
+
+ /* Make sure to put the timecode handling first in order to get the smallest
+ * possible interrupt latency
+ */
+ if ( (status & SPW_STATUS_TO) && (grspw_timecode_callback != NULL) ) {
+ /* Timecode received. Let custom function handle this */
+ SPW_STATUS_WRITE(pDev, SPW_STATUS_TO);
+ timecode = SPW_READ(&pDev->regs->time);
+ (grspw_timecode_callback)(pDev,pDev->regs,pDev->minor,timecode);
+ }
-static rtems_device_driver grspw_initialize(
- rtems_device_major_number major,
- rtems_device_minor_number minor,
- void *arg
-)
-{
- rtems_status_code status;
- int i=0;
- char c;
- GRSPW_DEV *pDev;
- char console_name[20];
- amba_apb_device dev;
+ /* Clear SPW_DMACTRL_PR if set */
+ dmactrl = SPW_READ(&pDev->regs->dma0ctrl);
+ /*SPW_WRITE(&pDev->regs->dma0ctrl, dmactrl | SPW_DMACTRL_PR);*/
+ SPW_WRITE(&pDev->regs->dma0ctrl, dmactrl);
+
+ /* If linkinterrupts are enabled check if it was a linkerror irq and then send an event to the
+ process set in the config */
+ if (pDev->config.link_err_irq) {
+ if (status & (SPW_STATUS_CE | SPW_STATUS_ER | SPW_STATUS_DE | SPW_STATUS_PE | SPW_STATUS_WE)) {
+ rtems_event_send(pDev->config.event_id, SPW_LINKERR_EVENT);
+ if (pDev->config.disable_err) {
+ /* disable link*/
+ SPW_CTRL_WRITE(pDev, (SPW_CTRL_READ(pDev) & 0xFFFFFFFC) | SPW_CTRL_LINKDISABLED);
+ pDev->config.linkdisabled = 1;
+ pDev->config.linkstart = 0;
+ pDev->running = 0;
+ }
+ }
+ }
+ if (status & SPW_STATUS_CE) {
+ pDev->stat.credit_err++;
+ }
+ if (status & SPW_STATUS_ER) {
+ pDev->stat.escape_err++;
+ }
+ if (status & SPW_STATUS_DE) {
+ pDev->stat.disconnect_err++;
+ }
+ if (status & SPW_STATUS_PE) {
+ pDev->stat.parity_err++;
+ }
+ if (status & SPW_STATUS_WE) {
+ pDev->stat.write_sync_err++;
+ }
+ if (status & SPW_STATUS_IA) {
+ pDev->stat.invalid_address++;
+ }
+ if (status & SPW_STATUS_EE) {
+ pDev->stat.early_ep++;
+ }
- SPACEWIRE_DBG2("spacewire driver initialization\n");
+ /* Check for tx interrupts */
+ while( (pDev->tx_sent != pDev->tx_cur) || pDev->tx_all_in_use) {
+ /* Has this descriptor been sent? */
+ ctrl = SPW_READ((volatile void *)&pDev->tx[pDev->tx_sent].ctrl);
+ if ( ctrl & SPW_TXBD_EN ) {
+ break;
+ }
+ /* Yes, increment status counters & tx_sent so we can use this descriptor to send more packets with */
+ pDev->stat.packets_sent++;
- /* Copy device name */
- strcpy(console_name,GRSPW_DEVNAME);
+ rtems_semaphore_release(pDev->txsp);
- /* Get the number of GRSPW cores */
- i=0; spw_cores = 0; spw_cores2 = 0;
+ if ( ctrl & SPW_TXBD_LE ) {
+ pDev->stat.tx_link_err++;
+ }
- /* get number of GRSPW cores */
- spw_cores = amba_get_number_apbslv_devices(amba_bus,VENDOR_GAISLER,GAISLER_SPACEWIRE);
- spw_cores2 = amba_get_number_apbslv_devices(amba_bus,VENDOR_GAISLER,GAISLER_GRSPW2);
-#if 0
- if ( spw_cores > SPACEWIRE_MAX_CORENR )
- spw_cores = SPACEWIRE_MAX_CORENR;
-
- while (i < amba_conf.apbslv.devnr) {
- conf = amba_get_confword(amba_conf.apbslv, i, 0);
- if ((amba_vendor(conf) == VENDOR_GAISLER) && (amba_device(conf) == GAISLER_SPACEWIRE))
- spw_cores++;
- i++;
- }
-#endif
+ /* step to next descriptor */
+ pDev->tx_sent = (pDev->tx_sent + 1) % pDev->txbufcnt;
+ pDev->tx_all_in_use = 0; /* not all of the descriptors can be in use since we just freed one. */
+ }
- if ( (spw_cores+spw_cores2) < 1 ){
- /* No GRSPW cores around... */
- return RTEMS_SUCCESSFUL;
- }
-
- /* Allocate memory for all spacewire cores */
- grspw_devs = (GRSPW_DEV *)malloc((spw_cores+spw_cores2) * sizeof(GRSPW_DEV));
-
- /* Zero out all memory */
- memset(grspw_devs,0,(spw_cores+spw_cores2) * sizeof(GRSPW_DEV));
-
- /* loop all found spacewire cores */
- i = 0;
- for(minor=0; minor<(spw_cores+spw_cores2); minor++){
-
- pDev = &grspw_devs[minor];
-
- /* Get device */
- if ( spw_cores > minor ) {
- amba_find_next_apbslv(amba_bus,VENDOR_GAISLER,GAISLER_SPACEWIRE,&dev,minor);
- pDev->core_ver = 1;
- } else {
- amba_find_next_apbslv(amba_bus,VENDOR_GAISLER,GAISLER_GRSPW2,&dev,minor-spw_cores);
- pDev->core_ver = 2;
- }
-
- pDev->regs = (LEON3_SPACEWIRE_Regs_Map *)dev.start;
- pDev->irq = dev.irq;
- pDev->minor = minor;
- pDev->open = 0;
-
- /* register interrupt routine */
- GRSPW_REG_INT(GRSPW_PREFIX(_interrupt_handler), pDev->irq, pDev);
-
- SPACEWIRE_DBG("spacewire core at [0x%x]\n", (unsigned int) pDev->regs);
-
- /* initialize the code with some resonable values,
- actual initialization is done later using ioctl(fd)
- on the opened device */
- pDev->config.rxmaxlen = SPACEWIRE_RXPCK_SIZE;
- pDev->txdbufsize = SPACEWIRE_TXD_SIZE;
- pDev->txhbufsize = SPACEWIRE_TXH_SIZE;
- pDev->rxbufsize = SPACEWIRE_RXPCK_SIZE;
- pDev->txbufcnt = SPACEWIRE_TXBUFS_NR;
- pDev->rxbufcnt = SPACEWIRE_RXBUFS_NR;
- pDev->config.check_rmap_err = 0;
- pDev->config.tx_blocking = 0;
- pDev->config.tx_block_on_full = 0;
- pDev->config.rx_blocking = 0;
- pDev->config.disable_err = 0;
- pDev->config.link_err_irq = 0;
- pDev->config.event_id = 0;
-
- pDev->ptr_rxbuf0 = 0;
- pDev->ptr_txdbuf0 = 0;
- pDev->ptr_txhbuf0 = 0;
-
-#ifdef GRSPW_STATIC_MEM
- GRSPW_CALC_MEMOFS(spw_cores,minor,&pDev->membase,&pDev->memend,&pDev->mem_bdtable);
-#endif
+ /* Check for rx interrupts */
+ if (dmactrl & SPW_DMACTRL_PR) {
+ rtems_semaphore_release(pDev->rxsp);
+ }
+}
- if (grspw_buffer_alloc(pDev))
- return RTEMS_NO_MEMORY;
-
- }
-
- /* Register Device Names, /dev/grspw0, /dev/grspw1 ... */
- for (i = 0; i < spw_cores+spw_cores2; i++) {
- GRSPW_DEVNAME_NO(console_name,i);
- SPACEWIRE_DBG("registering minor %i as %s\n", i, console_name);
- status = rtems_io_register_name( console_name, major, i);
- if (status != RTEMS_SUCCESSFUL){
- rtems_fatal_error_occurred(status);
- }
- }
-
- /* Initialize Hardware and semaphores*/
- c = 'a';
- for (i = 0; i < spw_cores+spw_cores2; i++) {
- pDev = &grspw_devs[i];
- rtems_semaphore_create(
- rtems_build_name('T', 'x', 'S', c),
- 0,
- RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | \
- RTEMS_NO_PRIORITY_CEILING,
- 0,
- &(pDev->txsp));
- rtems_semaphore_create(
- rtems_build_name('R', 'x', 'S', c),
- 0,
- RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | \
- RTEMS_NO_PRIORITY_CEILING,
- 0,
- &(pDev->rxsp));
- c++;
- grspw_hw_init(pDev);
- }
-
- return RTEMS_SUCCESSFUL;
+static rtems_device_driver grspw_initialize(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg
+)
+{
+ /* Initialize device-common data structures here */
+ return RTEMS_SUCCESSFUL;
}
static rtems_device_driver grspw_open(
rtems_device_major_number major,
rtems_device_minor_number minor,
- void * arg
- )
+ void * arg
+ )
{
- GRSPW_DEV *pDev;
- SPACEWIRE_DBGC(DBGSPW_IOCALLS, "open [%i,%i]\n", major, minor);
- if ( minor >= (spw_cores+spw_cores2) ) {
- SPACEWIRE_DBG("minor %i too big\n", minor);
- return RTEMS_INVALID_NAME;
- }
- pDev = &grspw_devs[minor];
-
- if ( pDev->open )
- return RTEMS_RESOURCE_IN_USE;
-
- /* Mark device open */
- pDev->open = 1;
-
- pDev->stat.tx_link_err = 0;
- pDev->stat.rx_rmap_header_crc_err = 0;
- pDev->stat.rx_rmap_data_crc_err = 0;
- pDev->stat.rx_eep_err = 0;
- pDev->stat.rx_truncated = 0;
- pDev->stat.parity_err = 0;
- pDev->stat.escape_err = 0;
- pDev->stat.credit_err = 0;
- pDev->stat.write_sync_err = 0;
- pDev->stat.disconnect_err = 0;
- pDev->stat.early_ep = 0;
- pDev->stat.invalid_address = 0;
- pDev->stat.packets_sent = 0;
- pDev->stat.packets_received = 0;
-
- pDev->running = 0;
- pDev->core_freq_khz = 0;
-
- /* Reset Core */
- grspw_hw_reset(pDev);
-
- /* Read default configuration */
- grspw_hw_read_config(pDev);
-
- return RTEMS_SUCCESSFUL;
+ GRSPW_DEV *pDev;
+ struct drvmgr_dev *dev;
+ SPACEWIRE_DBGC(DBGSPW_IOCALLS, "open [%i,%i]\n", major, minor);
+
+ if ( drvmgr_get_dev(&grspw_drv_info.general, minor, &dev) ) {
+ SPACEWIRE_DBG("Wrong minor %d\n", minor);
+ return RTEMS_INVALID_NAME;
+ }
+ pDev = (GRSPW_DEV *)dev->priv;
+
+ if ( pDev->open )
+ return RTEMS_RESOURCE_IN_USE;
+
+ /* Mark device open */
+ pDev->open = 1;
+
+ pDev->stat.tx_link_err = 0;
+ pDev->stat.rx_rmap_header_crc_err = 0;
+ pDev->stat.rx_rmap_data_crc_err = 0;
+ pDev->stat.rx_eep_err = 0;
+ pDev->stat.rx_truncated = 0;
+ pDev->stat.parity_err = 0;
+ pDev->stat.escape_err = 0;
+ pDev->stat.credit_err = 0;
+ pDev->stat.write_sync_err = 0;
+ pDev->stat.disconnect_err = 0;
+ pDev->stat.early_ep = 0;
+ pDev->stat.invalid_address = 0;
+ pDev->stat.packets_sent = 0;
+ pDev->stat.packets_received = 0;
+
+ pDev->config.rm_prot_id = 0;
+ pDev->config.keep_source = 0;
+ pDev->config.check_rmap_err = 0;
+ pDev->config.tx_blocking = 0;
+ pDev->config.tx_block_on_full = 0;
+ pDev->config.rx_blocking = 0;
+ pDev->config.disable_err = 0;
+ pDev->config.link_err_irq = 0;
+ pDev->config.event_id = 0;
+ pDev->config.rtimeout = 0;
+
+ pDev->running = 0;
+ pDev->core_freq_khz = 0;
+
+ /* Reset Core */
+ grspw_hw_reset(pDev);
+
+ /* Read default configuration */
+ grspw_hw_read_config(pDev);
+
+ return RTEMS_SUCCESSFUL;
}
static rtems_device_driver grspw_close(
- rtems_device_major_number major,
- rtems_device_minor_number minor,
- void * arg
- )
-{
- GRSPW_DEV *pDev = &grspw_devs[minor];
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+ )
+{
+ GRSPW_DEV *pDev;
+ struct drvmgr_dev *dev;
+
+ if ( drvmgr_get_dev(&grspw_drv_info.general, minor, &dev) ) {
+ return RTEMS_INVALID_NAME;
+ }
+ pDev = (GRSPW_DEV *)dev->priv;
- SPACEWIRE_DBGC(DBGSPW_IOCALLS, "close [%i,%i]\n", major, minor);
- rtems_semaphore_delete(pDev->txsp);
- rtems_semaphore_delete(pDev->rxsp);
+ SPACEWIRE_DBGC(DBGSPW_IOCALLS, "close [%i,%i]\n", major, minor);
+ rtems_semaphore_delete(pDev->txsp);
+ rtems_semaphore_delete(pDev->rxsp);
- grspw_hw_stop(pDev,1,1);
+ grspw_hw_stop(pDev,1,1);
- grspw_hw_reset(pDev);
+ grspw_hw_reset(pDev);
- /* Mark device closed - not open */
- pDev->open = 0;
+ /* Mark device closed - not open */
+ pDev->open = 0;
- return RTEMS_SUCCESSFUL;
+ return RTEMS_SUCCESSFUL;
}
static rtems_device_driver grspw_read(
- rtems_device_major_number major,
- rtems_device_minor_number minor,
- void * arg
- )
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+ )
{
- GRSPW_DEV *pDev = &grspw_devs[minor];
- rtems_libio_rw_args_t *rw_args;
- unsigned int count = 0;
- rw_args = (rtems_libio_rw_args_t *) arg;
+ rtems_libio_rw_args_t *rw_args;
+ unsigned int count = 0;
+ GRSPW_DEV *pDev;
+ struct drvmgr_dev *dev;
+ int status;
+
+ if ( drvmgr_get_dev(&grspw_drv_info.general, minor, &dev) ) {
+ return RTEMS_INVALID_NAME;
+ }
+ pDev = (GRSPW_DEV *)dev->priv;
+
+ rw_args = (rtems_libio_rw_args_t *) arg;
- /* is link up? */
- if ( !pDev->running ) {
- return RTEMS_INVALID_NAME;
- }
+ /* is link up? */
+ if ( !pDev->running ) {
+ return RTEMS_INVALID_NAME;
+ }
- if ((rw_args->count < 1) || (rw_args->buffer == NULL)) {
- return RTEMS_INVALID_NAME;
- }
+ if ((rw_args->count < 1) || (rw_args->buffer == NULL)) {
+ return RTEMS_INVALID_NAME;
+ }
- SPACEWIRE_DBGC(DBGSPW_IOCALLS, "read [%i,%i]: buf:0x%x len:%i \n", major, minor, (unsigned int)rw_args->buffer, rw_args->count);
+ SPACEWIRE_DBGC(DBGSPW_IOCALLS, "read [%i,%i]: buf:0x%x len:%i \n", major, minor, (unsigned int)rw_args->buffer, rw_args->count);
- while ( (count = grspw_hw_receive(pDev, rw_args->buffer, rw_args->count)) == 0) {
- /* wait a moment for any descriptors to get available
- *
+ while ( (count = grspw_hw_receive(pDev, rw_args->buffer, rw_args->count)) == 0) {
+ /* wait a moment for any descriptors to get available
+ *
* Semaphore is signaled by interrupt handler
*/
if (pDev->config.rx_blocking) {
SPACEWIRE_DBG2("Rx blocking\n");
- rtems_semaphore_obtain(pDev->rxsp, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+ if ( pDev->config.rtimeout ) {
+ status = rtems_semaphore_obtain(pDev->rxsp, RTEMS_WAIT, pDev->config.rtimeout);
+ if ( status == RTEMS_TIMEOUT )
+ return RTEMS_TIMEOUT;
+ } else {
+ rtems_semaphore_obtain(pDev->rxsp, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+ }
} else {
- SPACEWIRE_DBG2("Rx non blocking\n");
+ SPACEWIRE_DBG2("Rx non blocking\n");
return RTEMS_RESOURCE_IN_USE;
}
}
-#ifdef DEBUG_SPACEWIRE_ONOFF
- if (DEBUG_SPACEWIRE_FLAGS & DBGSPW_DUMP) {
- int k;
- for (k = 0; k < count; k++){
- if (k % 16 == 0) {
- printf ("\n");
- }
- printf ("%.2x(%c) ", rw_args->buffer[k] & 0xff, isprint(rw_args->buffer[k] & 0xff) ? rw_args->buffer[k] & 0xff : ' ');
- }
- printf ("\n");
- }
+#ifdef DEBUG_SPACEWIRE_ONOFF
+ if (DEBUG_SPACEWIRE_FLAGS & DBGSPW_DUMP) {
+ int k;
+ for (k = 0; k < count; k++){
+ if (k % 16 == 0) {
+ printf ("\n");
+ }
+ printf ("%.2x(%c) ", rw_args->buffer[k] & 0xff, isprint(rw_args->buffer[k] & 0xff) ? rw_args->buffer[k] & 0xff : ' ');
+ }
+ printf ("\n");
+ }
#endif
- rw_args->bytes_moved = count;
- return RTEMS_SUCCESSFUL;
-
+ rw_args->bytes_moved = count;
+ return RTEMS_SUCCESSFUL;
}
static rtems_device_driver grspw_write(
- rtems_device_major_number major,
- rtems_device_minor_number minor,
- void * arg
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
)
{
- GRSPW_DEV *pDev = &grspw_devs[minor];
- rtems_libio_rw_args_t *rw_args;
- rw_args = (rtems_libio_rw_args_t *) arg;
- SPACEWIRE_DBGC(DBGSPW_IOCALLS, "write [%i,%i]: buf:0x%x len:%i\n", major, minor, (unsigned int)rw_args->buffer, rw_args->count);
-
- /* is link up? */
- if ( !pDev->running ) {
- return RTEMS_INVALID_NAME;
- }
-
- if ((rw_args->count > pDev->txdbufsize) || (rw_args->count < 1) || (rw_args->buffer == NULL)) {
- return RTEMS_INVALID_NAME;
- }
-
- while ((rw_args->bytes_moved = grspw_hw_send(pDev, 0, NULL, rw_args->count, rw_args->buffer)) == 0) {
- if (pDev->config.tx_block_on_full == 1) {
- SPACEWIRE_DBG2("Tx Block on full \n");
- rtems_semaphore_obtain(pDev->txsp, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
- } else {
- SPACEWIRE_DBG2("Tx non blocking return when full \n");
- return RTEMS_RESOURCE_IN_USE;
- }
- }
- return RTEMS_SUCCESSFUL;
+ rtems_libio_rw_args_t *rw_args;
+ GRSPW_DEV *pDev;
+ struct drvmgr_dev *dev;
+
+ if ( drvmgr_get_dev(&grspw_drv_info.general, minor, &dev) ) {
+ return RTEMS_INVALID_NAME;
+ }
+ pDev = (GRSPW_DEV *)dev->priv;
+
+ rw_args = (rtems_libio_rw_args_t *) arg;
+ SPACEWIRE_DBGC(DBGSPW_IOCALLS, "write [%i,%i]: buf:0x%x len:%i\n", major, minor, (unsigned int)rw_args->buffer, rw_args->count);
+
+ /* is link up? */
+ if ( !pDev->running ) {
+ return RTEMS_INVALID_NAME;
+ }
+
+ if ((rw_args->count > pDev->txdbufsize) || (rw_args->count < 1) || (rw_args->buffer == NULL)) {
+ return RTEMS_INVALID_NAME;
+ }
+
+ while ((rw_args->bytes_moved = grspw_hw_send(pDev, 0, NULL, rw_args->count, rw_args->buffer, 0)) == 0) {
+ if (pDev->config.tx_block_on_full == 1) {
+ SPACEWIRE_DBG2("Tx Block on full \n");
+ rtems_semaphore_obtain(pDev->txsp, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+ } else {
+ SPACEWIRE_DBG2("Tx non blocking return when full \n");
+ return RTEMS_RESOURCE_IN_USE;
+ }
+ }
+ return RTEMS_SUCCESSFUL;
}
static rtems_device_driver grspw_control(
- rtems_device_major_number major,
- rtems_device_minor_number minor,
- void * arg
- )
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+ )
{
- GRSPW_DEV *pDev = &grspw_devs[minor];
- spw_ioctl_pkt_send *args;
- spw_ioctl_packetsize *ps;
- int status;
- unsigned int tmp,nodeaddr,nodemask;
- int timeout;
- rtems_device_driver ret;
- rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *) arg;
- SPACEWIRE_DBGC(DBGSPW_IOCALLS, "ctrl [%i,%i]\n", major, minor);
-
- if (!ioarg)
- return RTEMS_INVALID_NAME;
-
-
- ioarg->ioctl_return = 0;
- switch(ioarg->command) {
- case SPACEWIRE_IOCTRL_SET_NODEADDR:
- /*set node address*/
- SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_NODEADDR %i\n",(unsigned int)ioarg->buffer);
- if ((unsigned int)ioarg->buffer > 255) {
- return RTEMS_INVALID_NAME;
- }
- nodeaddr = ((unsigned int)ioarg->buffer) & 0xff;
- tmp = SPW_READ(&pDev->regs->nodeaddr);
- tmp &= 0xffffff00; /* Remove old address */
- tmp |= nodeaddr;
- SPW_WRITE(&pDev->regs->nodeaddr, tmp);
- if ((SPW_READ(&pDev->regs->nodeaddr)&0xff) != nodeaddr) {
- return RTEMS_IO_ERROR;
- }
- pDev->config.nodeaddr = nodeaddr;
- break;
- case SPACEWIRE_IOCTRL_SET_NODEMASK:
- /*set node address*/
- SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_NODEMASK %i\n",(unsigned int)ioarg->buffer);
- if ( pDev->core_ver > 1 ){
- if ((unsigned int)ioarg->buffer > 255) {
- return RTEMS_INVALID_NAME;
- }
- nodemask = ((unsigned int)ioarg->buffer) & 0xff;
- tmp = SPW_READ(&pDev->regs->nodeaddr);
- tmp &= 0xffff00ff; /* Remove old mask */
- tmp |= nodemask<<8;
- SPW_WRITE(&pDev->regs->nodeaddr, tmp);
- if (((SPW_READ(&pDev->regs->nodeaddr)>>8)&0xff) != nodemask) {
- return RTEMS_IO_ERROR;
- }
- pDev->config.nodemask = nodemask;
- }else{
- SPACEWIRE_DBG("SPACEWIRE_IOCTRL_SET_NODEMASK: not implemented in GRSPW1 HW\n");
- }
- break;
- case SPACEWIRE_IOCTRL_SET_RXBLOCK:
- SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_RXBLOCK %i \n", (unsigned int)ioarg->buffer);
- if ((unsigned int)ioarg->buffer > 1) {
- return RTEMS_INVALID_NAME;
- }
- pDev->config.rx_blocking = (unsigned int)ioarg->buffer;
- break;
- case SPACEWIRE_IOCTRL_SET_DESTKEY:
- SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_DESTKEY %i\n", (unsigned int)ioarg->buffer);
- if (!pDev->config.is_rmap) {
- return RTEMS_NOT_IMPLEMENTED;
- }
- if ((unsigned int)ioarg->buffer > 255) {
- return RTEMS_INVALID_NAME;
- }
- SPW_WRITE(&pDev->regs->destkey, (unsigned int)ioarg->buffer);
- if (SPW_READ(&pDev->regs->destkey) != (unsigned int)ioarg->buffer) {
- return RTEMS_IO_ERROR;
- }
- pDev->config.destkey = (unsigned int)ioarg->buffer;
- break;
- case SPACEWIRE_IOCTRL_SET_CLKDIV:
- SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_CLKDIV %i\n", (unsigned int)ioarg->buffer);
- if ((unsigned int)ioarg->buffer > 255) {
- return RTEMS_INVALID_NAME;
- }
- tmp = SPW_READ(&pDev->regs->clkdiv);
- tmp &= ~0xff; /* Remove old Clockdiv Setting */
- tmp |= ((unsigned int)ioarg->buffer) & 0xff; /* add new clockdiv setting */
- SPW_WRITE(&pDev->regs->clkdiv, tmp);
- if (SPW_READ(&pDev->regs->clkdiv) != tmp) {
- return RTEMS_IO_ERROR;
- }
- pDev->config.clkdiv = tmp;
- break;
- case SPACEWIRE_IOCTRL_SET_CLKDIVSTART:
- SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_CLKDIVSTART %i\n", (unsigned int)ioarg->buffer);
- if ((unsigned int)ioarg->buffer > 255) {
- return RTEMS_INVALID_NAME;
- }
- tmp = SPW_READ(&pDev->regs->clkdiv);
- tmp &= ~0xff00; /* Remove old Clockdiv Start Setting */
- tmp |= (((unsigned int)ioarg->buffer) & 0xff)<<8; /* add new clockdiv start setting */
- SPW_WRITE(&pDev->regs->clkdiv, tmp);
- if (SPW_READ(&pDev->regs->clkdiv) != tmp) {
- return RTEMS_IO_ERROR;
- }
- pDev->config.clkdiv = tmp;
- break;
- case SPACEWIRE_IOCTRL_SET_TIMER:
- SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_TIMER %i\n", (unsigned int)ioarg->buffer);
- if ( pDev->core_ver <= 1 ) {
- if ((unsigned int)ioarg->buffer > 4095) {
- return RTEMS_INVALID_NAME;
- }
- SPW_WRITE(&pDev->regs->timer, (SPW_READ(&pDev->regs->timer) & 0xFFFFF000) | ((unsigned int)ioarg->buffer & 0xFFF));
- if ((SPW_READ(&pDev->regs->timer) & 0xFFF) != (unsigned int)ioarg->buffer) {
- return RTEMS_IO_ERROR;
- }
- pDev->config.timer = (unsigned int)ioarg->buffer;
- }else{
- SPACEWIRE_DBG("SPACEWIRE_IOCTRL_SET_TIMER: removed in GRSPW2 HW\n");
- }
- break;
- case SPACEWIRE_IOCTRL_SET_DISCONNECT:
- SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_DISCONNECT %i\n", (unsigned int)ioarg->buffer);
- if ( pDev->core_ver <= 1 ) {
- if ((unsigned int)ioarg->buffer > 1023) {
- return RTEMS_INVALID_NAME;
- }
- SPW_WRITE(&pDev->regs->timer, (SPW_READ(&pDev->regs->timer) & 0xFFC00FFF) | (((unsigned int)ioarg->buffer & 0x3FF) << 12));
- if (((SPW_READ(&pDev->regs->timer) >> 12) & 0x3FF) != (unsigned int)ioarg->buffer) {
- return RTEMS_IO_ERROR;
- }
- pDev->config.disconnect = (unsigned int)ioarg->buffer;
- }else{
- SPACEWIRE_DBG("SPACEWIRE_IOCTRL_SET_DISCONNECT: not implemented for GRSPW2\n");
- }
- break;
- case SPACEWIRE_IOCTRL_SET_PROMISCUOUS:
- SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_PROMISCUOUS %i \n", (unsigned int)ioarg->buffer);
- if ((unsigned int)ioarg->buffer > 1) {
- return RTEMS_INVALID_NAME;
- }
- SPW_CTRL_WRITE(pDev, SPW_CTRL_READ(pDev) | ((unsigned int)ioarg->buffer << 5));
- if (((SPW_CTRL_READ(pDev) >> 5) & 1) != (unsigned int)ioarg->buffer) {
- return RTEMS_IO_ERROR;
- }
- pDev->config.promiscuous = (unsigned int)ioarg->buffer;
- break;
- case SPACEWIRE_IOCTRL_SET_RMAPEN:
- SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_RMAPEN %i \n", (unsigned int)ioarg->buffer);
- if ((unsigned int)ioarg->buffer > 1) {
- return RTEMS_INVALID_NAME;
- }
- SPW_CTRL_WRITE(pDev, (SPW_STATUS_READ(pDev) & 0xFFFEFFFF) | ((unsigned int)ioarg->buffer << 16));
- if (((SPW_CTRL_READ(pDev) >> 16) & 1) != (unsigned int)ioarg->buffer) {
- return RTEMS_IO_ERROR;
- }
- pDev->config.rmapen = (unsigned int)ioarg->buffer;
- break;
- case SPACEWIRE_IOCTRL_SET_RMAPBUFDIS:
- SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_RMAPBUFDIS %i \n", (unsigned int)ioarg->buffer);
- if ((unsigned int)ioarg->buffer > 1) {
- return RTEMS_INVALID_NAME;
- }
- SPW_CTRL_WRITE(pDev, (SPW_STATUS_READ(pDev) & 0xFFFDFFFF) | ((unsigned int)ioarg->buffer << 17));
- if (((SPW_CTRL_READ(pDev) >> 17) & 1) != (unsigned int)ioarg->buffer) {
- return RTEMS_IO_ERROR;
- }
- pDev->config.rmapbufdis = (unsigned int)ioarg->buffer;
- break;
- case SPACEWIRE_IOCTRL_SET_CHECK_RMAP:
- SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_CHECK_RMAP %i \n", (unsigned int)ioarg->buffer);
- if ((unsigned int)ioarg->buffer > 1) {
- return RTEMS_INVALID_NAME;
- }
- pDev->config.check_rmap_err = (unsigned int)ioarg->buffer;
- break;
- case SPACEWIRE_IOCTRL_SET_RM_PROT_ID:
- SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_RM_PROT_ID %i \n", (unsigned int)ioarg->buffer);
- if ((unsigned int)ioarg->buffer > 1) {
- return RTEMS_INVALID_NAME;
- }
- pDev->config.rm_prot_id = (unsigned int)ioarg->buffer;
- break;
- case SPACEWIRE_IOCTRL_SET_TXBLOCK:
- SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_TXBLOCK %i \n", (unsigned int)ioarg->buffer);
- if ((unsigned int)ioarg->buffer > 1) {
- return RTEMS_INVALID_NAME;
- }
- pDev->config.tx_blocking = (unsigned int)ioarg->buffer;
- break;
- case SPACEWIRE_IOCTRL_SET_TXBLOCK_ON_FULL:
- SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_TXBLOCK_ON_FULL %i \n", (unsigned int)ioarg->buffer);
- if ((unsigned int)ioarg->buffer > 1) {
- return RTEMS_INVALID_NAME;
- }
- pDev->config.tx_block_on_full = (unsigned int)ioarg->buffer;
- break;
- case SPACEWIRE_IOCTRL_SET_DISABLE_ERR:
- SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_DISABLE_ERR %i \n", (unsigned int)ioarg->buffer);
- if ((unsigned int)ioarg->buffer > 1) {
- return RTEMS_INVALID_NAME;
- }
- pDev->config.disable_err = (unsigned int)ioarg->buffer;
- break;
- case SPACEWIRE_IOCTRL_SET_LINK_ERR_IRQ:
- SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_LINK_ERR_IRQ %i \n", (unsigned int)ioarg->buffer);
- SPACEWIRE_DBGC(DBGSPW_IOCTRL, "CTRL REG: %x\n", SPW_CTRL_READ(pDev));
- if ((unsigned int)ioarg->buffer > 1) {
- return RTEMS_INVALID_NAME;
- }
- SPW_CTRL_WRITE(pDev, (SPW_CTRL_READ(pDev) & 0xFFFFFDF7) | ((unsigned int)ioarg->buffer << 9) | (pDev->config.link_err_irq << 3));
- SPACEWIRE_DBGC(DBGSPW_IOCTRL, "CTRL REG: %x\n", SPW_CTRL_READ(pDev));
- if (((SPW_CTRL_READ(pDev) >> 9) & 1) != (unsigned int)ioarg->buffer) {
- return RTEMS_IO_ERROR;
- }
- pDev->config.link_err_irq = (unsigned int)ioarg->buffer;
- break;
- case SPACEWIRE_IOCTRL_SET_EVENT_ID:
- SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_EVENT_ID %i \n", (unsigned int)ioarg->buffer);
- pDev->config.event_id = (rtems_id)ioarg->buffer;
- SPACEWIRE_DBGC(DBGSPW_IOCTRL, "Event id: %i\n", pDev->config.event_id);
- break;
-
- /* Change MAX Packet size by:
- * - stop RX/TX (if on)
- * - wait for hw to complete RX DMA (if on)
- * - reallocate buffers with new size
- * - tell hw about new size & start RX/TX again (if previously on)
- */
- case SPACEWIRE_IOCTRL_SET_PACKETSIZE:
- if (ioarg->buffer == NULL)
- return RTEMS_INVALID_NAME;
- ps = (spw_ioctl_packetsize*) ioarg->buffer;
- SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_RXPACKETSIZE %i \n", (unsigned int)ioarg->buffer);
-
- tmp = pDev->running;
-
- if ( pDev->running ){
- /* Stop RX */
- grspw_hw_stop(pDev,1,1);
-
- /* If packetsize fails it is good to know if in running mode */
- pDev->running = 0;
-
- /* Wait for Receiver to finnish pending DMA transfers if any */
- grspw_hw_wait_rx_inactive(pDev);
- }
-
- /* Save new buffer sizes */
- pDev->rxbufsize = ps->rxsize;
- pDev->txdbufsize = ps->txdsize;
- pDev->txhbufsize = ps->txhsize;
- pDev->config.rxmaxlen = pDev->rxbufsize;
-
- /* Free previous buffers & allocate buffers with new size */
- if (grspw_buffer_alloc(pDev))
- return RTEMS_NO_MEMORY;
-
- /* if RX was actived before, we reactive it again */
- if ( tmp ) {
- if ( (status = grspw_hw_startup(pDev,-1)) != RTEMS_SUCCESSFUL ) {
- return status;
- }
- pDev->running = 1;
- }
+ spw_ioctl_pkt_send *args;
+ spw_ioctl_packetsize *ps;
+ int status;
+ unsigned int tmp,mask,nodeaddr,nodemask;
+ int timeout;
+ rtems_device_driver ret;
+ rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *) arg;
+ GRSPW_DEV *pDev;
+ struct drvmgr_dev *dev;
+
+ SPACEWIRE_DBGC(DBGSPW_IOCALLS, "ctrl [%i,%i]\n", major, minor);
+
+ if ( drvmgr_get_dev(&grspw_drv_info.general, minor, &dev) ) {
+ return RTEMS_INVALID_NAME;
+ }
+ pDev = (GRSPW_DEV *)dev->priv;
+
+ if (!ioarg)
+ return RTEMS_INVALID_NAME;
+
+ ioarg->ioctl_return = 0;
+ switch(ioarg->command) {
+ case SPACEWIRE_IOCTRL_SET_NODEADDR:
+ /*set node address*/
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_NODEADDR %i\n",(unsigned int)ioarg->buffer);
+ if ((unsigned int)ioarg->buffer > 255) {
+ return RTEMS_INVALID_NAME;
+ }
+ nodeaddr = ((unsigned int)ioarg->buffer) & 0xff;
+ tmp = SPW_READ(&pDev->regs->nodeaddr);
+ tmp &= 0xffffff00; /* Remove old address */
+ tmp |= nodeaddr;
+ SPW_WRITE(&pDev->regs->nodeaddr, tmp);
+ if ((SPW_READ(&pDev->regs->nodeaddr)&0xff) != nodeaddr) {
+ return RTEMS_IO_ERROR;
+ }
+ pDev->config.nodeaddr = nodeaddr;
+ break;
+ case SPACEWIRE_IOCTRL_SET_NODEMASK:
+ /*set node address*/
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_NODEMASK %i\n",(unsigned int)ioarg->buffer);
+ if ( pDev->core_ver > 1 ){
+ if ((unsigned int)ioarg->buffer > 255) {
+ return RTEMS_INVALID_NAME;
+ }
+ nodemask = ((unsigned int)ioarg->buffer) & 0xff;
+ tmp = SPW_READ(&pDev->regs->nodeaddr);
+ tmp &= 0xffff00ff; /* Remove old mask */
+ tmp |= nodemask<<8;
+ SPW_WRITE(&pDev->regs->nodeaddr, tmp);
+ if (((SPW_READ(&pDev->regs->nodeaddr)>>8)&0xff) != nodemask) {
+ return RTEMS_IO_ERROR;
+ }
+ pDev->config.nodemask = nodemask;
+ }else{
+ SPACEWIRE_DBG("SPACEWIRE_IOCTRL_SET_NODEMASK: not implemented in GRSPW1 HW\n");
+ }
+ break;
+ case SPACEWIRE_IOCTRL_SET_RXBLOCK:
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_RXBLOCK %i \n", (unsigned int)ioarg->buffer);
+ if ((unsigned int)ioarg->buffer > 1) {
+ return RTEMS_INVALID_NAME;
+ }
+ pDev->config.rx_blocking = (unsigned int)ioarg->buffer;
+ break;
+ case SPACEWIRE_IOCTRL_SET_DESTKEY:
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_DESTKEY %i\n", (unsigned int)ioarg->buffer);
+ if (!pDev->config.is_rmap) {
+ return RTEMS_NOT_IMPLEMENTED;
+ }
+ if ((unsigned int)ioarg->buffer > 255) {
+ return RTEMS_INVALID_NAME;
+ }
+ SPW_WRITE(&pDev->regs->destkey, (unsigned int)ioarg->buffer);
+ if (SPW_READ(&pDev->regs->destkey) != (unsigned int)ioarg->buffer) {
+ return RTEMS_IO_ERROR;
+ }
+ pDev->config.destkey = (unsigned int)ioarg->buffer;
+ break;
+ case SPACEWIRE_IOCTRL_SET_CLKDIV:
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_CLKDIV %i\n", (unsigned int)ioarg->buffer);
+ if ((unsigned int)ioarg->buffer > 255) {
+ return RTEMS_INVALID_NAME;
+ }
+ if ( pDev->core_ver == 3 )
+ break;
+ tmp = SPW_READ(&pDev->regs->clkdiv);
+ tmp &= ~0xff; /* Remove old Clockdiv Setting */
+ tmp |= ((unsigned int)ioarg->buffer) & 0xff; /* add new clockdiv setting */
+ SPW_WRITE(&pDev->regs->clkdiv, tmp);
+ if (SPW_READ(&pDev->regs->clkdiv) != tmp) {
+ return RTEMS_IO_ERROR;
+ }
+ pDev->config.clkdiv = tmp;
+ break;
+ case SPACEWIRE_IOCTRL_SET_CLKDIVSTART:
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_CLKDIVSTART %i\n", (unsigned int)ioarg->buffer);
+ if ((unsigned int)ioarg->buffer > 255) {
+ return RTEMS_INVALID_NAME;
+ }
+ if ( pDev->core_ver == 3 )
+ break;
+ tmp = SPW_READ(&pDev->regs->clkdiv);
+ tmp &= ~0xff00; /* Remove old Clockdiv Start Setting */
+ tmp |= (((unsigned int)ioarg->buffer) & 0xff)<<8; /* add new clockdiv start setting */
+ SPW_WRITE(&pDev->regs->clkdiv, tmp);
+ if (SPW_READ(&pDev->regs->clkdiv) != tmp) {
+ return RTEMS_IO_ERROR;
+ }
+ pDev->config.clkdiv = tmp;
+ break;
+ case SPACEWIRE_IOCTRL_SET_TIMER:
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_TIMER %i\n", (unsigned int)ioarg->buffer);
+ if ( pDev->core_ver <= 1 ) {
+ if ((unsigned int)ioarg->buffer > 4095) {
+ return RTEMS_INVALID_NAME;
+ }
+ SPW_WRITE(&pDev->regs->timer, (SPW_READ(&pDev->regs->timer) & 0xFFFFF000) | ((unsigned int)ioarg->buffer & 0xFFF));
+ if ((SPW_READ(&pDev->regs->timer) & 0xFFF) != (unsigned int)ioarg->buffer) {
+ return RTEMS_IO_ERROR;
+ }
+ pDev->config.timer = (unsigned int)ioarg->buffer;
+ }else{
+ SPACEWIRE_DBG("SPACEWIRE_IOCTRL_SET_TIMER: removed in GRSPW2 HW\n");
+ }
+ break;
+ case SPACEWIRE_IOCTRL_SET_DISCONNECT:
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_DISCONNECT %i\n", (unsigned int)ioarg->buffer);
+ if ( pDev->core_ver <= 1 ) {
+ if ((unsigned int)ioarg->buffer > 1023) {
+ return RTEMS_INVALID_NAME;
+ }
+ SPW_WRITE(&pDev->regs->timer, (SPW_READ(&pDev->regs->timer) & 0xFFC00FFF) | (((unsigned int)ioarg->buffer & 0x3FF) << 12));
+ if (((SPW_READ(&pDev->regs->timer) >> 12) & 0x3FF) != (unsigned int)ioarg->buffer) {
+ return RTEMS_IO_ERROR;
+ }
+ pDev->config.disconnect = (unsigned int)ioarg->buffer;
+ }else{
+ SPACEWIRE_DBG("SPACEWIRE_IOCTRL_SET_DISCONNECT: not implemented for GRSPW2\n");
+ }
+ break;
+ case SPACEWIRE_IOCTRL_SET_PROMISCUOUS:
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_PROMISCUOUS %i \n", (unsigned int)ioarg->buffer);
+ if ((unsigned int)ioarg->buffer > 1) {
+ return RTEMS_INVALID_NAME;
+ }
+ SPW_CTRL_WRITE(pDev, SPW_CTRL_READ(pDev) | ((unsigned int)ioarg->buffer << 5));
+ if (((SPW_CTRL_READ(pDev) >> 5) & 1) != (unsigned int)ioarg->buffer) {
+ return RTEMS_IO_ERROR;
+ }
+ pDev->config.promiscuous = (unsigned int)ioarg->buffer;
+ break;
+ case SPACEWIRE_IOCTRL_SET_RMAPEN:
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_RMAPEN %i \n", (unsigned int)ioarg->buffer);
+ if ((unsigned int)ioarg->buffer > 1) {
+ return RTEMS_INVALID_NAME;
+ }
+ SPW_CTRL_WRITE(pDev, (SPW_CTRL_READ(pDev) & 0xFFFEFFFF) | ((unsigned int)ioarg->buffer << 16));
+ if (((SPW_CTRL_READ(pDev) >> 16) & 1) != (unsigned int)ioarg->buffer) {
+ return RTEMS_IO_ERROR;
+ }
+ pDev->config.rmapen = (unsigned int)ioarg->buffer;
+ break;
+ case SPACEWIRE_IOCTRL_SET_RMAPBUFDIS:
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_RMAPBUFDIS %i \n", (unsigned int)ioarg->buffer);
+ if ((unsigned int)ioarg->buffer > 1) {
+ return RTEMS_INVALID_NAME;
+ }
+ SPW_CTRL_WRITE(pDev, (SPW_CTRL_READ(pDev) & 0xFFFDFFFF) | ((unsigned int)ioarg->buffer << 17));
+ if (((SPW_CTRL_READ(pDev) >> 17) & 1) != (unsigned int)ioarg->buffer) {
+ return RTEMS_IO_ERROR;
+ }
+ pDev->config.rmapbufdis = (unsigned int)ioarg->buffer;
+ break;
+ case SPACEWIRE_IOCTRL_SET_CHECK_RMAP:
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_CHECK_RMAP %i \n", (unsigned int)ioarg->buffer);
+ if ((unsigned int)ioarg->buffer > 1) {
+ return RTEMS_INVALID_NAME;
+ }
+ pDev->config.check_rmap_err = (unsigned int)ioarg->buffer;
+ break;
+ case SPACEWIRE_IOCTRL_SET_RM_PROT_ID:
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_RM_PROT_ID %i \n", (unsigned int)ioarg->buffer);
+ if ((unsigned int)ioarg->buffer > 1) {
+ return RTEMS_INVALID_NAME;
+ }
+ pDev->config.rm_prot_id = (unsigned int)ioarg->buffer;
+ break;
+ case SPACEWIRE_IOCTRL_SET_KEEP_SOURCE:
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_KEEP_SOURCE %i \n", (unsigned int)ioarg->buffer);
+ if ((unsigned int)ioarg->buffer > 1) {
+ return RTEMS_INVALID_NAME;
+ }
+ pDev->config.keep_source = (unsigned int)ioarg->buffer;
+ break;
+ case SPACEWIRE_IOCTRL_SET_TXBLOCK:
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_TXBLOCK %i \n", (unsigned int)ioarg->buffer);
+ if ((unsigned int)ioarg->buffer > 1) {
+ return RTEMS_INVALID_NAME;
+ }
+ pDev->config.tx_blocking = (unsigned int)ioarg->buffer;
+ break;
+ case SPACEWIRE_IOCTRL_SET_TXBLOCK_ON_FULL:
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_TXBLOCK_ON_FULL %i \n", (unsigned int)ioarg->buffer);
+ if ((unsigned int)ioarg->buffer > 1) {
+ return RTEMS_INVALID_NAME;
+ }
+ pDev->config.tx_block_on_full = (unsigned int)ioarg->buffer;
+ break;
+ case SPACEWIRE_IOCTRL_SET_DISABLE_ERR:
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_DISABLE_ERR %i \n", (unsigned int)ioarg->buffer);
+ if ((unsigned int)ioarg->buffer > 1) {
+ return RTEMS_INVALID_NAME;
+ }
+ pDev->config.disable_err = (unsigned int)ioarg->buffer;
+ break;
+ case SPACEWIRE_IOCTRL_SET_LINK_ERR_IRQ:
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_LINK_ERR_IRQ %i \n", (unsigned int)ioarg->buffer);
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL, "CTRL REG: %x\n", SPW_CTRL_READ(pDev));
+ if ((unsigned int)ioarg->buffer > 1) {
+ return RTEMS_INVALID_NAME;
+ }
+ tmp = (SPW_CTRL_READ(pDev) & 0xFFFFFDF7) | ((unsigned int)ioarg->buffer << 9);
+ if (tmp & (SPW_CTRL_LI|SPW_CTRL_TQ))
+ tmp |= SPW_CTRL_IE;
+ SPW_CTRL_WRITE(pDev, tmp);
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL, "CTRL REG: %x\n", SPW_CTRL_READ(pDev));
+ if (((SPW_CTRL_READ(pDev) >> 9) & 1) != (unsigned int)ioarg->buffer) {
+ return RTEMS_IO_ERROR;
+ }
+ pDev->config.link_err_irq = (unsigned int)ioarg->buffer;
+ break;
+ case SPACEWIRE_IOCTRL_SET_EVENT_ID:
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_EVENT_ID %i \n", (unsigned int)ioarg->buffer);
+ pDev->config.event_id = (rtems_id)ioarg->buffer;
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL, "Event id: %i\n", pDev->config.event_id);
+ break;
+
+ /* Change MAX Packet size by:
+ * - stop RX/TX (if on)
+ * - wait for hw to complete RX DMA (if on)
+ * - reallocate buffers with new size
+ * - tell hw about new size & start RX/TX again (if previously on)
+ */
+ case SPACEWIRE_IOCTRL_SET_PACKETSIZE:
+ if (ioarg->buffer == NULL)
+ return RTEMS_INVALID_NAME;
+ ps = (spw_ioctl_packetsize*) ioarg->buffer;
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_RXPACKETSIZE %i \n", (unsigned int)ioarg->buffer);
+
+ tmp = pDev->running;
+
+ if ( pDev->running ){
+ /* Stop RX */
+ grspw_hw_stop(pDev,1,1);
+
+ /* If packetsize fails it is good to know if in running mode */
+ pDev->running = 0;
+
+ /* Wait for Receiver to finnish pending DMA transfers if any */
+ grspw_hw_wait_rx_inactive(pDev);
+ }
+
+ /* Save new buffer sizes */
+ pDev->rxbufsize = ((ps->rxsize+7)&~7);
+ pDev->txdbufsize = ps->txdsize;
+ pDev->txhbufsize = ps->txhsize;
+ pDev->config.rxmaxlen = pDev->rxbufsize;
+
+ /* Free previous buffers & allocate buffers with new size */
+ if (grspw_buffer_alloc(pDev))
+ return RTEMS_NO_MEMORY;
+
+ /* if RX was actived before, we reactive it again */
+ if ( tmp ) {
+ if ( (status = grspw_hw_startup(pDev,-1)) != RTEMS_SUCCESSFUL ) {
+ return status;
+ }
+ pDev->running = 1;
+ }
#if 0
- /* Rewrite previous config which was wasted due to reset in hw_startup */
- SPW_WRITE(&pDev->regs->nodeaddr, pDev->config.nodeaddr);
- SPW_WRITE(&pDev->regs->destkey, pDev->config.destkey);
- SPW_WRITE(&pDev->regs->clkdiv, pDev->config.clkdiv);
- SPW_WRITE(&pDev->regs->timer, pDev->config.timer | ( (pDev->config.disconnect & 0x3FF) << 12) );
- SPW_CTRL_WRITE(pDev, (SPW_CTRL_READ(pDev) & !(SPW_CTRL_LINKSTART | SPW_CTRL_PM | SPW_CTRL_RE | SPW_CTRL_RD | SPW_CTRL_TT | SPW_CTRL_TR)) | \
- (pDev->config.promiscuous << 5) | (pDev->config.rmapen << 16) | (pDev->config.rmapbufdis << 17) | \
- (pDev->config.linkdisabled) | (pDev->config.linkstart << 1));
+ /* Rewrite previous config which was wasted due to reset in hw_startup */
+ SPW_WRITE(&pDev->regs->nodeaddr, pDev->config.nodeaddr);
+ SPW_WRITE(&pDev->regs->destkey, pDev->config.destkey);
+ SPW_WRITE(&pDev->regs->clkdiv, pDev->config.clkdiv);
+ SPW_WRITE(&pDev->regs->timer, pDev->config.timer | ( (pDev->config.disconnect & 0x3FF) << 12) );
+ SPW_CTRL_WRITE(pDev, (SPW_CTRL_READ(pDev) & !(SPW_CTRL_LINKSTART | SPW_CTRL_PM | SPW_CTRL_RE | SPW_CTRL_RD | SPW_CTRL_TT | SPW_CTRL_TR)) | \
+ (pDev->config.promiscuous << 5) | (pDev->config.rmapen << 16) | (pDev->config.rmapbufdis << 17) | \
+ (pDev->config.linkdisabled) | (pDev->config.linkstart << 1));
#endif
- break;
- case SPACEWIRE_IOCTRL_GET_CONFIG:
- if (ioarg->buffer == NULL)
- return RTEMS_INVALID_NAME;
- SPACEWIRE_DBG2("SPACEWIRE_IOCTRL_GET_CONFIG \n");
- (*(spw_config *)ioarg->buffer).nodeaddr = pDev->config.nodeaddr;
- (*(spw_config *)ioarg->buffer).nodemask = pDev->config.nodemask;
- (*(spw_config *)ioarg->buffer).destkey = pDev->config.destkey;
- (*(spw_config *)ioarg->buffer).clkdiv = pDev->config.clkdiv;
- (*(spw_config *)ioarg->buffer).rxmaxlen = pDev->config.rxmaxlen;
- (*(spw_config *)ioarg->buffer).timer = pDev->config.timer;
- (*(spw_config *)ioarg->buffer).disconnect = pDev->config.disconnect;
- (*(spw_config *)ioarg->buffer).promiscuous = pDev->config.promiscuous;
- (*(spw_config *)ioarg->buffer).rmapen = pDev->config.rmapen;
- (*(spw_config *)ioarg->buffer).rmapbufdis = pDev->config.rmapbufdis;
- (*(spw_config *)ioarg->buffer).check_rmap_err = pDev->config.check_rmap_err;
- (*(spw_config *)ioarg->buffer).rm_prot_id = pDev->config.rm_prot_id;
- (*(spw_config *)ioarg->buffer).tx_blocking = pDev->config.tx_blocking;
- (*(spw_config *)ioarg->buffer).disable_err = pDev->config.disable_err;
- (*(spw_config *)ioarg->buffer).link_err_irq = pDev->config.link_err_irq;
- (*(spw_config *)ioarg->buffer).event_id = pDev->config.event_id;
- (*(spw_config *)ioarg->buffer).is_rmap = pDev->config.is_rmap;
- (*(spw_config *)ioarg->buffer).is_rmapcrc = pDev->config.is_rmapcrc;
- (*(spw_config *)ioarg->buffer).is_rxunaligned = pDev->config.is_rxunaligned;
- (*(spw_config *)ioarg->buffer).linkdisabled = pDev->config.linkdisabled;
- (*(spw_config *)ioarg->buffer).linkstart = pDev->config.linkstart;
- (*(spw_config *)ioarg->buffer).rx_blocking = pDev->config.rx_blocking;
- (*(spw_config *)ioarg->buffer).tx_block_on_full = pDev->config.tx_block_on_full;
- break;
- case SPACEWIRE_IOCTRL_GET_LINK_STATUS:
- SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_GET_STATUS=%i \n", (unsigned int)((SPW_STATUS_READ(pDev) >> 21) & 0x7));
- *(unsigned int *)ioarg->buffer = (unsigned int )((SPW_STATUS_READ(pDev) >> 21) & 0x7);
- break;
- case SPACEWIRE_IOCTRL_GET_STATISTICS:
- if (ioarg->buffer == NULL)
- return RTEMS_INVALID_NAME;
- SPACEWIRE_DBG2("SPACEWIRE_IOCTRL_GET_STATISTICS \n");
- (*(spw_stats *)ioarg->buffer).tx_link_err = pDev->stat.tx_link_err;
- (*(spw_stats *)ioarg->buffer).rx_rmap_header_crc_err = pDev->stat.rx_rmap_header_crc_err;
- (*(spw_stats *)ioarg->buffer).rx_rmap_data_crc_err = pDev->stat.rx_rmap_data_crc_err;
- (*(spw_stats *)ioarg->buffer).rx_eep_err = pDev->stat.rx_eep_err;
- (*(spw_stats *)ioarg->buffer).rx_truncated = pDev->stat.rx_truncated;
- (*(spw_stats *)ioarg->buffer).parity_err = pDev->stat.parity_err;
- (*(spw_stats *)ioarg->buffer).escape_err = pDev->stat.escape_err;
- (*(spw_stats *)ioarg->buffer).credit_err = pDev->stat.credit_err;
- (*(spw_stats *)ioarg->buffer).write_sync_err = pDev->stat.write_sync_err;
- (*(spw_stats *)ioarg->buffer).disconnect_err = pDev->stat.disconnect_err;
- (*(spw_stats *)ioarg->buffer).early_ep = pDev->stat.early_ep;
- (*(spw_stats *)ioarg->buffer).invalid_address = pDev->stat.invalid_address;
- (*(spw_stats *)ioarg->buffer).packets_sent = pDev->stat.packets_sent;
- (*(spw_stats *)ioarg->buffer).packets_received = pDev->stat.packets_received;
- break;
- case SPACEWIRE_IOCTRL_CLR_STATISTICS:
- SPACEWIRE_DBG2("SPACEWIRE_IOCTRL_CLR_STATISTICS \n");
- pDev->stat.tx_link_err = 0;
- pDev->stat.rx_rmap_header_crc_err = 0;
- pDev->stat.rx_rmap_data_crc_err = 0;
- pDev->stat.rx_eep_err = 0;
- pDev->stat.rx_truncated = 0;
- pDev->stat.parity_err = 0;
- pDev->stat.escape_err = 0;
- pDev->stat.credit_err = 0;
- pDev->stat.write_sync_err = 0;
- pDev->stat.disconnect_err = 0;
- pDev->stat.early_ep = 0;
- pDev->stat.invalid_address = 0;
- pDev->stat.packets_sent = 0;
- pDev->stat.packets_received = 0;
- break;
- case SPACEWIRE_IOCTRL_SEND:
- if (ioarg->buffer == NULL)
- return RTEMS_INVALID_NAME;
- args = (spw_ioctl_pkt_send *)ioarg->buffer;
- args->sent = 0;
-
- /* is link up? */
- if ( !pDev->running ) {
- return RTEMS_INVALID_NAME;
- }
-
- SPACEWIRE_DBGC(DBGSPW_IOCALLS, "write [%i,%i]: hlen: %i hbuf:0x%x dlen:%i dbuf:0x%x\n", major, minor,
- (unsigned int)args->hlen, (int)args->hdr,(unsigned int)args->dlen, (int)args->data);
-
- if ((args->hlen > pDev->txhbufsize) || (args->dlen > pDev->txdbufsize) ||
- ((args->hlen+args->dlen) < 1) ||
- ((args->hdr == NULL) && (args->hlen != 0)) || ((args->data == NULL) && (args->dlen != 0))) {
- return RTEMS_INVALID_NAME;
- }
- while ((args->sent = grspw_hw_send(pDev, args->hlen, args->hdr, args->dlen, args->data)) == 0) {
- if (pDev->config.tx_block_on_full == 1) {
- SPACEWIRE_DBG2("Tx Block on full \n");
- rtems_semaphore_obtain(pDev->txsp, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
- } else {
- SPACEWIRE_DBG2("Tx non blocking return when full \n");
- return RTEMS_RESOURCE_IN_USE;
- }
- }
- SPACEWIRE_DBGC(DBGSPW_IOCALLS, "Tx ioctl return: %i \n", args->sent);
- break;
-
- case SPACEWIRE_IOCTRL_LINKDISABLE:
- pDev->config.linkdisabled = 1;
- pDev->config.linkstart = 0;
- SPW_CTRL_WRITE(pDev, (SPW_CTRL_READ(pDev) & 0xFFFFFFFC) | 1);
- if ((SPW_CTRL_READ(pDev) & 3) != 1) {
- return RTEMS_IO_ERROR;
- }
- break;
-
- case SPACEWIRE_IOCTRL_LINKSTART:
- pDev->config.linkdisabled = 0;
- pDev->config.linkstart = 1;
- SPW_CTRL_WRITE(pDev, (SPW_CTRL_READ(pDev) & 0xFFFFFFFC) | 2);
- if ((SPW_CTRL_READ(pDev) & 3) != 2) {
- return RTEMS_IO_ERROR;
- }
- break;
-
- /* Calculate timer register from GRSPW Core frequency
- * Also possible to set disconnect and timer64 from
- * - SPACEWIRE_IOCTRL_SET_DISCONNECT
- * - SPACEWIRE_IOCTRL_SET_TIMER
- */
- case SPACEWIRE_IOCTRL_SET_COREFREQ:
- pDev->core_freq_khz = (unsigned int)ioarg->buffer;
- if ( pDev->core_freq_khz == 0 ){
- /* Get GRSPW clock frequency from system clock.
- * System clock has been read from timer inited
- * by RTEMS loader (mkprom)
- */
- pDev->core_freq_khz = sys_freq_khz;
- }
-
- /* Only GRSPW1 needs the Timer64 and Disconnect values
- * GRSPW2 and onwards doesn't have this register.
- */
- if ( pDev->core_ver <= 1 ){
- /* Calculate Timer64 & Disconnect */
- pDev->config.timer = grspw_calc_timer64(pDev->core_freq_khz);
- pDev->config.disconnect = grspw_calc_disconnect(pDev->core_freq_khz);
-
- /* Set Timer64 & Disconnect Register */
- SPW_WRITE(&pDev->regs->timer,
- (SPW_READ(&pDev->regs->timer) & 0xFFC00000) |
- ((pDev->config.disconnect & 0x3FF)<<12) |
- (pDev->config.timer & 0xFFF));
-
- /* Check that the registers were written successfully */
- tmp = SPW_READ(&pDev->regs->timer) & 0x003fffff;
- if ( ((tmp & 0xFFF) != pDev->config.timer) ||
- (((tmp >> 12) & 0x3FF) != pDev->config.disconnect) ) {
- return RTEMS_IO_ERROR;
- }
- }
- break;
-
- case SPACEWIRE_IOCTRL_START:
- if ( pDev->running ){
- return RTEMS_INVALID_NAME;
- }
-
- /* Get timeout from userspace
- * timeout:
- * ¤ -1 = Default timeout
- * ¤ less than -1 = forever
- * ¤ 0 = no wait, proceed if link is up
- * ¤ positive = specifies number of system clock ticks that
- * startup will wait for link to enter ready mode.
- */
- timeout = (int)ioarg->buffer;
-
- if ( (ret=grspw_hw_startup(pDev,timeout)) != RTEMS_SUCCESSFUL ) {
- return ret;
- }
- pDev->running = 1;
- break;
-
- case SPACEWIRE_IOCTRL_STOP:
- if ( !pDev->running ){
- return RTEMS_INVALID_NAME;
- }
- pDev->running = 0;
-
- /* Stop Receiver and transmitter */
- grspw_hw_stop(pDev,1,1);
- break;
-
- default:
- return RTEMS_NOT_IMPLEMENTED;
- }
-
- SPACEWIRE_DBGC(DBGSPW_IOCALLS, "SPW_IOCTRL Return\n");
- return RTEMS_SUCCESSFUL;
+ break;
+ case SPACEWIRE_IOCTRL_GET_CONFIG:
+ if (ioarg->buffer == NULL)
+ return RTEMS_INVALID_NAME;
+ SPACEWIRE_DBG2("SPACEWIRE_IOCTRL_GET_CONFIG \n");
+ (*(spw_config *)ioarg->buffer).nodeaddr = pDev->config.nodeaddr;
+ (*(spw_config *)ioarg->buffer).nodemask = pDev->config.nodemask;
+ (*(spw_config *)ioarg->buffer).destkey = pDev->config.destkey;
+ (*(spw_config *)ioarg->buffer).clkdiv = pDev->config.clkdiv;
+ (*(spw_config *)ioarg->buffer).rxmaxlen = pDev->config.rxmaxlen;
+ (*(spw_config *)ioarg->buffer).timer = pDev->config.timer;
+ (*(spw_config *)ioarg->buffer).disconnect = pDev->config.disconnect;
+ (*(spw_config *)ioarg->buffer).promiscuous = pDev->config.promiscuous;
+ (*(spw_config *)ioarg->buffer).rmapen = pDev->config.rmapen;
+ (*(spw_config *)ioarg->buffer).rmapbufdis = pDev->config.rmapbufdis;
+ (*(spw_config *)ioarg->buffer).check_rmap_err = pDev->config.check_rmap_err;
+ (*(spw_config *)ioarg->buffer).rm_prot_id = pDev->config.rm_prot_id;
+ (*(spw_config *)ioarg->buffer).tx_blocking = pDev->config.tx_blocking;
+ (*(spw_config *)ioarg->buffer).disable_err = pDev->config.disable_err;
+ (*(spw_config *)ioarg->buffer).link_err_irq = pDev->config.link_err_irq;
+ (*(spw_config *)ioarg->buffer).event_id = pDev->config.event_id;
+ (*(spw_config *)ioarg->buffer).is_rmap = pDev->config.is_rmap;
+ (*(spw_config *)ioarg->buffer).is_rmapcrc = pDev->config.is_rmapcrc;
+ (*(spw_config *)ioarg->buffer).is_rxunaligned = pDev->config.is_rxunaligned;
+ (*(spw_config *)ioarg->buffer).linkdisabled = pDev->config.linkdisabled;
+ (*(spw_config *)ioarg->buffer).linkstart = pDev->config.linkstart;
+ (*(spw_config *)ioarg->buffer).rx_blocking = pDev->config.rx_blocking;
+ (*(spw_config *)ioarg->buffer).tx_block_on_full = pDev->config.tx_block_on_full;
+ (*(spw_config *)ioarg->buffer).keep_source = pDev->config.keep_source;
+ (*(spw_config *)ioarg->buffer).rtimeout = pDev->config.rtimeout;
+ break;
+ case SPACEWIRE_IOCTRL_GET_LINK_STATUS:
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_GET_STATUS=%i \n", (unsigned int)((SPW_STATUS_READ(pDev) >> 21) & 0x7));
+ *(unsigned int *)ioarg->buffer = (unsigned int )((SPW_STATUS_READ(pDev) >> 21) & 0x7);
+ break;
+ case SPACEWIRE_IOCTRL_GET_STATISTICS:
+ if (ioarg->buffer == NULL)
+ return RTEMS_INVALID_NAME;
+ SPACEWIRE_DBG2("SPACEWIRE_IOCTRL_GET_STATISTICS \n");
+ (*(spw_stats *)ioarg->buffer).tx_link_err = pDev->stat.tx_link_err;
+ (*(spw_stats *)ioarg->buffer).rx_rmap_header_crc_err = pDev->stat.rx_rmap_header_crc_err;
+ (*(spw_stats *)ioarg->buffer).rx_rmap_data_crc_err = pDev->stat.rx_rmap_data_crc_err;
+ (*(spw_stats *)ioarg->buffer).rx_eep_err = pDev->stat.rx_eep_err;
+ (*(spw_stats *)ioarg->buffer).rx_truncated = pDev->stat.rx_truncated;
+ (*(spw_stats *)ioarg->buffer).parity_err = pDev->stat.parity_err;
+ (*(spw_stats *)ioarg->buffer).escape_err = pDev->stat.escape_err;
+ (*(spw_stats *)ioarg->buffer).credit_err = pDev->stat.credit_err;
+ (*(spw_stats *)ioarg->buffer).write_sync_err = pDev->stat.write_sync_err;
+ (*(spw_stats *)ioarg->buffer).disconnect_err = pDev->stat.disconnect_err;
+ (*(spw_stats *)ioarg->buffer).early_ep = pDev->stat.early_ep;
+ (*(spw_stats *)ioarg->buffer).invalid_address = pDev->stat.invalid_address;
+ (*(spw_stats *)ioarg->buffer).packets_sent = pDev->stat.packets_sent;
+ (*(spw_stats *)ioarg->buffer).packets_received = pDev->stat.packets_received;
+ break;
+ case SPACEWIRE_IOCTRL_CLR_STATISTICS:
+ SPACEWIRE_DBG2("SPACEWIRE_IOCTRL_CLR_STATISTICS \n");
+ pDev->stat.tx_link_err = 0;
+ pDev->stat.rx_rmap_header_crc_err = 0;
+ pDev->stat.rx_rmap_data_crc_err = 0;
+ pDev->stat.rx_eep_err = 0;
+ pDev->stat.rx_truncated = 0;
+ pDev->stat.parity_err = 0;
+ pDev->stat.escape_err = 0;
+ pDev->stat.credit_err = 0;
+ pDev->stat.write_sync_err = 0;
+ pDev->stat.disconnect_err = 0;
+ pDev->stat.early_ep = 0;
+ pDev->stat.invalid_address = 0;
+ pDev->stat.packets_sent = 0;
+ pDev->stat.packets_received = 0;
+ break;
+ case SPACEWIRE_IOCTRL_SEND:
+ if (ioarg->buffer == NULL)
+ return RTEMS_INVALID_NAME;
+ args = (spw_ioctl_pkt_send *)ioarg->buffer;
+ args->sent = 0;
+
+ /* is link up? */
+ if ( !pDev->running ) {
+ return RTEMS_INVALID_NAME;
+ }
+
+ SPACEWIRE_DBGC(DBGSPW_IOCALLS, "write [%i,%i]: hlen: %i hbuf:0x%x dlen:%i dbuf:0x%x\n", major, minor,
+ (unsigned int)args->hlen, (int)args->hdr,(unsigned int)args->dlen, (int)args->data);
+
+ if ((args->hlen > pDev->txhbufsize) || (args->dlen > pDev->txdbufsize) ||
+ ((args->hlen+args->dlen) < 1) ||
+ ((args->hdr == NULL) && (args->hlen != 0)) || ((args->data == NULL) && (args->dlen != 0))) {
+ return RTEMS_INVALID_NAME;
+ }
+ while ((args->sent = grspw_hw_send(pDev, args->hlen, args->hdr, args->dlen, args->data, args->options)) == 0) {
+ if (pDev->config.tx_block_on_full == 1) {
+ SPACEWIRE_DBG2("Tx Block on full \n");
+ rtems_semaphore_obtain(pDev->txsp, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+ } else {
+ SPACEWIRE_DBG2("Tx non blocking return when full \n");
+ return RTEMS_RESOURCE_IN_USE;
+ }
+ }
+ SPACEWIRE_DBGC(DBGSPW_IOCALLS, "Tx ioctl return: %i \n", args->sent);
+ break;
+
+ case SPACEWIRE_IOCTRL_LINKDISABLE:
+ pDev->config.linkdisabled = 1;
+ pDev->config.linkstart = 0;
+ if ( pDev->core_ver != 3 ) {
+ SPW_CTRL_WRITE(pDev, (SPW_CTRL_READ(pDev) & 0xFFFFFFFC) | 1);
+ if ((SPW_CTRL_READ(pDev) & 3) != 1) {
+ return RTEMS_IO_ERROR;
+ }
+ }
+ break;
+
+ case SPACEWIRE_IOCTRL_LINKSTART:
+ pDev->config.linkdisabled = 0;
+ pDev->config.linkstart = 1;
+ if ( pDev->core_ver != 3 ) {
+ SPW_CTRL_WRITE(pDev, (SPW_CTRL_READ(pDev) & 0xFFFFFFFC) | 2);
+ if ((SPW_CTRL_READ(pDev) & 3) != 2) {
+ return RTEMS_IO_ERROR;
+ }
+ }
+ break;
+
+ /* Calculate timer register from GRSPW Core frequency
+ * Also possible to set disconnect and timer64 from
+ * - SPACEWIRE_IOCTRL_SET_DISCONNECT
+ * - SPACEWIRE_IOCTRL_SET_TIMER
+ */
+ case SPACEWIRE_IOCTRL_SET_COREFREQ:
+ pDev->core_freq_khz = (unsigned int)ioarg->buffer;
+ if ( pDev->core_freq_khz == 0 ){
+ /* Get GRSPW clock frequency from system clock.
+ * System clock has been read from timer inited
+ * by RTEMS loader (mkprom)
+ */
+ drvmgr_freq_get(pDev->dev, DEV_APB_SLV,
+ &pDev->core_freq_khz);
+ /* Convert from Hz -> kHz */
+ pDev->core_freq_khz = pDev->core_freq_khz / 1000;
+ }
+
+ /* Only GRSPW1 needs the Timer64 and Disconnect values
+ * GRSPW2 and onwards doesn't have this register.
+ */
+ if ( pDev->core_ver <= 1 ){
+ /* Calculate Timer64 & Disconnect */
+ pDev->config.timer = grspw_calc_timer64(pDev->core_freq_khz);
+ pDev->config.disconnect = grspw_calc_disconnect(pDev->core_freq_khz);
+
+ /* Set Timer64 & Disconnect Register */
+ SPW_WRITE(&pDev->regs->timer,
+ (SPW_READ(&pDev->regs->timer) & 0xFFC00000) |
+ ((pDev->config.disconnect & 0x3FF)<<12) |
+ (pDev->config.timer & 0xFFF));
+
+ /* Check that the registers were written successfully */
+ tmp = SPW_READ(&pDev->regs->timer) & 0x003fffff;
+ if ( ((tmp & 0xFFF) != pDev->config.timer) ||
+ (((tmp >> 12) & 0x3FF) != pDev->config.disconnect) ) {
+ return RTEMS_IO_ERROR;
+ }
+ }
+ break;
+
+ case SPACEWIRE_IOCTRL_START:
+ if ( pDev->running ){
+ return RTEMS_INVALID_NAME;
+ }
+
+ /* Get timeout from userspace
+ * timeout:
+ * ¤ -1 = Default timeout
+ * ¤ less than -1 = forever
+ * ¤ 0 = no wait, proceed if link is up
+ * ¤ positive = specifies number of system clock ticks that
+ * startup will wait for link to enter ready mode.
+ */
+ timeout = (int)ioarg->buffer;
+
+ if ( (ret=grspw_hw_startup(pDev,timeout)) != RTEMS_SUCCESSFUL ) {
+ return ret;
+ }
+ pDev->running = 1;
+ /* Register interrupt routine and unmask IRQ */
+ drvmgr_interrupt_register(pDev->dev, 0, "grspw", grspw_interrupt, pDev);
+
+ break;
+
+ case SPACEWIRE_IOCTRL_STOP:
+ if ( !pDev->running ){
+ return RTEMS_INVALID_NAME;
+ }
+ /* Disable interrupts */
+ drvmgr_interrupt_unregister(dev, 0, grspw_interrupt, pDev);
+
+ pDev->running = 0;
+
+ /* Stop Receiver and transmitter */
+ grspw_hw_stop(pDev,1,1);
+ break;
+
+ /* Set time-code control register bits, and Enables/Disables
+ * Time code interrupt, make sure to connect the callback
+ * grspw_timecode_callback if using interrupts.
+ */
+ case SPACEWIRE_IOCTRL_SET_TCODE_CTRL:
+ tmp = (unsigned int)ioarg->buffer;
+ mask = tmp & (SPACEWIRE_TCODE_CTRL_IE_MSK|SPACEWIRE_TCODE_CTRL_TT_MSK|SPACEWIRE_TCODE_CTRL_TR_MSK);
+ mask <<= 8;
+ tmp &= mask;
+ tmp = (SPW_CTRL_READ(pDev) & ~(mask | SPW_CTRL_IE)) | tmp;
+ if (tmp & (SPW_CTRL_LI|SPW_CTRL_TQ))
+ tmp |= SPW_CTRL_IE;
+ SPW_CTRL_WRITE(pDev, tmp);
+ break;
+
+ /* Set time register and optionaly send a time code */
+ case SPACEWIRE_IOCTRL_SET_TCODE:
+ tmp = (unsigned int)ioarg->buffer;
+ /* Set timecode register */
+ if (tmp & SPACEWIRE_TCODE_SET) {
+ SPW_WRITE(&pDev->regs->time,
+ ((SPW_READ(&pDev->regs->time) & ~(0xff)) |
+ (tmp & SPACEWIRE_TCODE_TCODE)));
+ }
+ /* Send timecode directly (tick-in) ? */
+ if (tmp & SPACEWIRE_TCODE_TX) {
+ SPW_CTRL_WRITE(pDev,
+ ((SPW_CTRL_READ(pDev) & ~(SPW_CTRL_TI)) | SPW_CTRL_TI));
+ }
+ break;
+
+ /* Read time code register and tick-out status bit */
+ case SPACEWIRE_IOCTRL_GET_TCODE:
+ tmp = (unsigned int)ioarg->buffer;
+ if ( !tmp ){
+ return RTEMS_INVALID_NAME;
+ }
+
+ /* Copy timecode register */
+ if (SPW_READ(&pDev->regs->status) & SPW_STATUS_TO) {
+ *(unsigned int *)tmp = (1 << 8) | SPW_READ(&pDev->regs->time);
+ } else {
+ *(unsigned int *)tmp = SPW_READ(&pDev->regs->time);
+ }
+ break;
+
+ case SPACEWIRE_IOCTRL_SET_READ_TIMEOUT:
+ pDev->config.rtimeout = (unsigned int)ioarg->buffer;
+ break;
+
+ default:
+ return RTEMS_NOT_IMPLEMENTED;
+ }
+
+ SPACEWIRE_DBGC(DBGSPW_IOCALLS, "SPW_IOCTRL Return\n");
+ return RTEMS_SUCCESSFUL;
}
/* ============================================================================== */
static int grspw_set_rxmaxlen(GRSPW_DEV *pDev) {
- unsigned int rxmax;
- SPW_WRITE(&pDev->regs->dma0rxmax,pDev->config.rxmaxlen); /*set rx maxlength*/
- rxmax = SPW_READ(&pDev->regs->dma0rxmax);
- if (rxmax != pDev->config.rxmaxlen) {
- return 0;
- }
- return 1;
+ unsigned int rxmax;
+ SPW_WRITE(&pDev->regs->dma0rxmax,pDev->config.rxmaxlen); /*set rx maxlength*/
+ rxmax = SPW_READ(&pDev->regs->dma0rxmax);
+ if (rxmax != pDev->config.rxmaxlen) {
+ return 0;
+ }
+ return 1;
}
static int grspw_hw_init(GRSPW_DEV *pDev) {
- unsigned int ctrl;
+ unsigned int ctrl;
- ctrl = SPW_CTRL_READ(pDev);
+ ctrl = SPW_CTRL_READ(pDev);
-#ifdef GRSPW_STATIC_MEM
- pDev->rx = (SPACEWIRE_RXBD *) pDev->mem_bdtable;
- pDev->tx = (SPACEWIRE_RXBD *) pDev->mem_bdtable + SPACEWIRE_BDTABLE_SIZE;
-#else
- pDev->rx = (SPACEWIRE_RXBD *) SPW_ALIGN(&pDev->_rxtable, SPACEWIRE_BDTABLE_SIZE);
- pDev->tx = (SPACEWIRE_TXBD *) SPW_ALIGN(&pDev->_txtable, SPACEWIRE_BDTABLE_SIZE);
-#endif
- SPACEWIRE_DBG("hw_init [minor %i]\n", pDev->minor);
+ pDev->rx = (SPACEWIRE_RXBD *) SPW_ALIGN(pDev->ptr_bd0, SPACEWIRE_BDTABLE_SIZE);
+ pDev->tx = (SPACEWIRE_TXBD *) &pDev->rx[SPACEWIRE_RXBUFS_NR];
+
+ /* Translate into remote address */
+ drvmgr_translate(pDev->dev, 0, 0, (void *)pDev->rx, (void **)&pDev->rx_remote);
+ drvmgr_translate(pDev->dev, 0, 0, (void *)pDev->tx, (void **)&pDev->tx_remote);
- pDev->config.is_rmap = ctrl & SPW_CTRL_RA;
- pDev->config.is_rxunaligned = ctrl & SPW_CTRL_RX;
- pDev->config.is_rmapcrc = ctrl & SPW_CTRL_RC;
- return 0;
+ SPACEWIRE_DBG("hw_init [minor %i]\n", pDev->minor);
+
+ pDev->config.is_rmap = ctrl & SPW_CTRL_RA;
+ pDev->config.is_rxunaligned = ctrl & SPW_CTRL_RX;
+ pDev->config.is_rmapcrc = ctrl & SPW_CTRL_RC;
+ return 0;
}
-static int grspw_hw_waitlink (GRSPW_DEV *pDev, int timeout)
+static int grspw_hw_waitlink (GRSPW_DEV *pDev, int timeout)
{
- int j;
-
- if ( timeout == -1 ){
- /* Wait default timeout */
- timeout = SPACEWIRE_INIT_TIMEOUT;
- }
-
- j=0;
- while (SPW_LINKSTATE(SPW_STATUS_READ(pDev)) != 5) {
- if ( timeout < -1 ) {
- /* wait forever */
- }else if ( j >= timeout ){
- /* timeout reached, return fail */
- return 1;
- }
-
- /* Sleep for 10 ticks */
- rtems_task_wake_after(10);
- j+=10;
- }
- return 0;
+ int j;
+
+ /* No actual link interface on a DMA-only GRSPW2 connected to the
+ * SPW router
+ */
+ if (pDev->core_ver == 3)
+ return 0;
+
+ if ( timeout == -1 ){
+ /* Wait default timeout */
+ timeout = SPACEWIRE_INIT_TIMEOUT;
+ }
+
+ j=0;
+ while (SPW_LINKSTATE(SPW_STATUS_READ(pDev)) != 5) {
+ if ( timeout < -1 ) {
+ /* wait forever */
+ }else if ( j >= timeout ){
+ /* timeout reached, return fail */
+ return 1;
+ }
+
+ /* Sleep for 10 ticks */
+ rtems_task_wake_after(10);
+ j+=10;
+ }
+ return 0;
}
static void grspw_hw_reset(GRSPW_DEV *pDev)
{
- SPW_CTRL_WRITE(pDev, SPW_CTRL_RESET); /*reset core*/
- SPW_STATUS_WRITE(pDev, SPW_STATUS_TO | SPW_STATUS_CE | SPW_STATUS_ER | SPW_STATUS_DE | SPW_STATUS_PE |
- SPW_STATUS_WE | SPW_STATUS_IA | SPW_STATUS_EE); /*clear status*/
- SPW_CTRL_WRITE(pDev, SPW_CTRL_LINKSTART); /*start link core*/
+ SPW_CTRL_WRITE(pDev, SPW_CTRL_RESET); /*reset core*/
+ SPW_STATUS_WRITE(pDev, SPW_STATUS_TO | SPW_STATUS_CE | SPW_STATUS_ER | SPW_STATUS_DE | SPW_STATUS_PE |
+ SPW_STATUS_WE | SPW_STATUS_IA | SPW_STATUS_EE); /*clear status*/
+ SPW_CTRL_WRITE(pDev, SPW_CTRL_LINKSTART); /*start link core*/
}
static void grspw_hw_read_config(GRSPW_DEV *pDev)
{
- unsigned int tmp;
+ unsigned int tmp;
+
+ tmp = SPW_READ(&pDev->regs->nodeaddr);
+ pDev->config.nodeaddr = 0xFF & tmp;
+ pDev->config.nodemask = 0xFF & (tmp>>8);
+ pDev->config.destkey = 0xFF & SPW_READ(&pDev->regs->destkey);
+ pDev->config.clkdiv = 0xFFFF & SPW_READ(&pDev->regs->clkdiv);
+
+ tmp = SPW_CTRL_READ(pDev);
+ pDev->config.promiscuous = 1 & (tmp >> 5);
+ pDev->config.rmapen = 1 & (tmp >> 16);
+ pDev->config.rmapbufdis = 1 & (tmp >> 17);
+ pDev->config.is_rmap = 1 & (tmp >> 31);
+ pDev->config.is_rxunaligned = 1 & (tmp >> 30);
+ pDev->config.is_rmapcrc = 1 & (tmp >> 29);
+ pDev->config.linkdisabled = 1 & tmp;
+ pDev->config.linkstart = 1 & (tmp >> 1);
+
+ if ( pDev->core_ver <= 1 ){
+ tmp = SPW_READ(&pDev->regs->timer);
+ pDev->config.timer = 0xFFF & tmp;
+ pDev->config.disconnect = 0x3FF & (tmp >> 12);
+ }else{
+ pDev->config.timer = 0;
+ pDev->config.disconnect = 0;
+ }
- tmp = SPW_READ(&pDev->regs->nodeaddr);
- pDev->config.nodeaddr = 0xFF & tmp;
- pDev->config.nodemask = 0xFF & (tmp>>8);
- pDev->config.destkey = 0xFF & SPW_READ(&pDev->regs->destkey);
- pDev->config.clkdiv = 0xFFFF & SPW_READ(&pDev->regs->clkdiv);
-
- tmp = SPW_CTRL_READ(pDev);
- pDev->config.promiscuous = 1 & (tmp >> 5);
- pDev->config.rmapen = 1 & (tmp >> 16);
- pDev->config.rmapbufdis = 1 & (tmp >> 17);
- pDev->config.is_rmap = 1 & (tmp >> 31);
- pDev->config.is_rxunaligned = 1 & (tmp >> 30);
- pDev->config.is_rmapcrc = 1 & (tmp >> 29);
- pDev->config.linkdisabled = 1 & tmp;
- pDev->config.linkstart = 1 & (tmp >> 1);
-
- if ( pDev->core_ver <= 1 ){
- tmp = SPW_READ(&pDev->regs->timer);
- pDev->config.timer = 0xFFF & tmp;
- pDev->config.disconnect = 0x3FF & (tmp >> 12);
- }else{
- pDev->config.timer = 0;
- pDev->config.disconnect = 0;
- }
-
- return;
+ return;
}
/* timeout is given in ticks */
static int grspw_hw_startup (GRSPW_DEV *pDev, int timeout)
{
- int i;
- unsigned int dmactrl;
-
- SPW_WRITE(&pDev->regs->status, (SPW_STATUS_TO|SPW_STATUS_CE|SPW_STATUS_ER|SPW_STATUS_DE|SPW_STATUS_PE|SPW_STATUS_WE|SPW_STATUS_IA|SPW_STATUS_EE)); /*clear status*/
-
- if (grspw_hw_waitlink(pDev,timeout)) {
- SPACEWIRE_DBG2("Device open. Link is not up\n");
- return RTEMS_TIMEOUT;
- }
-
- SPW_WRITE(&pDev->regs->dma0ctrl, SPW_DMACTRL_PS | SPW_DMACTRL_PR | SPW_DMACTRL_TA | SPW_DMACTRL_RA); /*clear status, set ctrl*/
-
-
- if ((dmactrl = SPW_READ(&pDev->regs->dma0ctrl)) != 0) {
- SPACEWIRE_DBG2("DMACtrl is not cleared\n");
- return RTEMS_IO_ERROR;
- }
-
- /* prepare transmit buffers */
- for (i = 0; i < pDev->txbufcnt; i++) {
- pDev->tx[i].ctrl = 0;
- pDev->tx[i].addr_header = memarea_to_hw(((unsigned int)&pDev->ptr_txhbuf0[0]) + (i * pDev->txhbufsize));
- pDev->tx[i].addr_data = memarea_to_hw(((unsigned int)&pDev->ptr_txdbuf0[0]) + (i * pDev->txdbufsize));
- }
- pDev->tx_cur = 0;
- pDev->tx_sent = 0;
- pDev->tx_all_in_use = 0;
-
- /* prepare receive buffers */
- for (i = 0; i < pDev->rxbufcnt; i++) {
- if (i+1 == pDev->rxbufcnt) {
- pDev->rx[i].ctrl = SPW_RXBD_IE | SPW_RXBD_EN | SPW_RXBD_WR;
- } else {
- pDev->rx[i].ctrl = SPW_RXBD_IE | SPW_RXBD_EN;
- }
- pDev->rx[i].addr = memarea_to_hw(((unsigned int)&pDev->ptr_rxbuf0[0]) + (i * pDev->rxbufsize));
- }
- pDev->rxcur = 0;
- pDev->rxbufcur = -1;
- grspw_set_rxmaxlen(pDev);
-
- SPW_WRITE(&pDev->regs->dma0txdesc, memarea_to_hw((unsigned int) pDev->tx));
- SPW_WRITE(&pDev->regs->dma0rxdesc, memarea_to_hw((unsigned int) pDev->rx));
-
- /* start RX */
- dmactrl = SPW_READ(&pDev->regs->dma0ctrl);
- SPW_WRITE(&pDev->regs->dma0ctrl, (dmactrl & SPW_PREPAREMASK_RX) | SPW_DMACTRL_RD | SPW_DMACTRL_RXEN | SPW_DMACTRL_NS | SPW_DMACTRL_TXIE | SPW_DMACTRL_RXIE);
-
- SPACEWIRE_DBGC(DBGSPW_TX,"0x%x: setup complete\n", (unsigned int)pDev->regs);
- return RTEMS_SUCCESSFUL;
+ int i;
+ unsigned int dmactrl;
+
+ SPW_WRITE(&pDev->regs->status, (SPW_STATUS_TO|SPW_STATUS_CE|SPW_STATUS_ER|SPW_STATUS_DE|SPW_STATUS_PE|SPW_STATUS_WE|SPW_STATUS_IA|SPW_STATUS_EE)); /*clear status*/
+
+ if (grspw_hw_waitlink(pDev,timeout)) {
+ SPACEWIRE_DBG2("Device open. Link is not up\n");
+ return RTEMS_TIMEOUT;
+ }
+
+ SPW_WRITE(&pDev->regs->dma0ctrl, SPW_DMACTRL_PS | SPW_DMACTRL_PR | SPW_DMACTRL_TA | SPW_DMACTRL_RA); /*clear status, set ctrl*/
+
+ if ((dmactrl = SPW_READ(&pDev->regs->dma0ctrl)) != 0) {
+ SPACEWIRE_DBG2("DMACtrl is not cleared\n");
+ return RTEMS_IO_ERROR;
+ }
+
+ /* prepare transmit buffers */
+ for (i = 0; i < pDev->txbufcnt; i++) {
+ pDev->tx[i].ctrl = 0;
+ pDev->tx[i].addr_header = ((unsigned int)&pDev->ptr_txhbuf0_remote[0]) + (i * pDev->txhbufsize);
+ pDev->tx[i].addr_data = ((unsigned int)&pDev->ptr_txdbuf0_remote[0]) + (i * pDev->txdbufsize);
+ }
+ pDev->tx_cur = 0;
+ pDev->tx_sent = 0;
+ pDev->tx_all_in_use = 0;
+
+ /* prepare receive buffers */
+ for (i = 0; i < pDev->rxbufcnt; i++) {
+ if (i+1 == pDev->rxbufcnt) {
+ pDev->rx[i].ctrl = SPW_RXBD_IE | SPW_RXBD_EN | SPW_RXBD_WR;
+ } else {
+ pDev->rx[i].ctrl = SPW_RXBD_IE | SPW_RXBD_EN;
+ }
+ pDev->rx[i].addr = ((unsigned int)&pDev->ptr_rxbuf0_remote[0]) + (i * pDev->rxbufsize);
+ }
+ pDev->rxcur = 0;
+ pDev->rxbufcur = -1;
+ grspw_set_rxmaxlen(pDev);
+
+ SPW_WRITE(&pDev->regs->dma0txdesc, pDev->tx_remote);
+ SPW_WRITE(&pDev->regs->dma0rxdesc, pDev->rx_remote);
+
+ /* start RX */
+ dmactrl = SPW_READ(&pDev->regs->dma0ctrl);
+ SPW_WRITE(&pDev->regs->dma0ctrl, (dmactrl & SPW_PREPAREMASK_RX) | SPW_DMACTRL_RD | SPW_DMACTRL_RXEN | SPW_DMACTRL_NS | SPW_DMACTRL_TXIE | SPW_DMACTRL_RXIE);
+
+ SPACEWIRE_DBGC(DBGSPW_TX,"0x%x: setup complete\n", (unsigned int)pDev->regs);
+ return RTEMS_SUCCESSFUL;
}
/* Wait until the receiver is inactive */
static void grspw_hw_wait_rx_inactive(GRSPW_DEV *pDev)
{
- while( SPW_READ(&pDev->regs->dma0ctrl) & SPW_DMACTRL_RX ){
- /* switching may be needed:
- * - low frequency GRSPW
- * - mega packet incoming
- */
- rtems_task_wake_after(1);
- }
+ while( SPW_READ(&pDev->regs->dma0ctrl) & SPW_DMACTRL_RX ){
+ /* switching may be needed:
+ * - low frequency GRSPW
+ * - mega packet incoming
+ */
+ rtems_task_wake_after(1);
+ }
}
/* Stop the rx or/and tx by disabling the receiver/transmitter */
-static int grspw_hw_stop (GRSPW_DEV *pDev, int rx, int tx)
-{
- unsigned int dmactrl;
-
- /* stop rx and/or tx */
- dmactrl = SPW_READ(&pDev->regs->dma0ctrl);
- if ( rx ) {
- dmactrl &= ~(SPW_DMACTRL_RXEN|SPW_DMACTRL_RXIE|SPW_DMACTRL_RD);
- }
- if ( tx ) {
- dmactrl &= ~(SPW_DMACTRL_TXEN|SPW_DMACTRL_TXIE);
- }
- /*SPW_WRITE(&pDev->regs->dma0ctrl, (dmactrl & SPW_PREPAREMASK_RX) & ~(SPW_DMACTRL_RD | SPW_DMACTRL_RXEN) & ~(SPW_DMACTRL_TXEN));*/
-
- /* don't clear status flags */
- dmactrl &= ~(SPW_DMACTRL_RA|SPW_DMACTRL_PR|SPW_DMACTRL_AI);
- SPW_WRITE(&pDev->regs->dma0ctrl, dmactrl);
- return RTEMS_SUCCESSFUL;
-}
-
-int grspw_hw_send(GRSPW_DEV *pDev, unsigned int hlen, char *hdr, unsigned int dlen, char *data)
+static int grspw_hw_stop (GRSPW_DEV *pDev, int rx, int tx)
{
+ unsigned int dmactrl;
- unsigned int dmactrl, ctrl;
-#ifdef DEBUG_SPACEWIRE_ONOFF
- unsigned int k;
-#endif
- rtems_interrupt_level level;
- unsigned int cur = pDev->tx_cur;
- char *txh = pDev->ptr_txhbuf0 + (cur * pDev->txhbufsize);
- char *txd = pDev->ptr_txdbuf0 + (cur * pDev->txdbufsize);
+ /* stop rx and/or tx */
+ dmactrl = SPW_READ(&pDev->regs->dma0ctrl);
+ if ( rx ) {
+ dmactrl &= ~(SPW_DMACTRL_RXEN|SPW_DMACTRL_RXIE|SPW_DMACTRL_RD);
+ }
+ if ( tx ) {
+ dmactrl &= ~(SPW_DMACTRL_TXEN|SPW_DMACTRL_TXIE);
+ }
+ /*SPW_WRITE(&pDev->regs->dma0ctrl, (dmactrl & SPW_PREPAREMASK_RX) & ~(SPW_DMACTRL_RD | SPW_DMACTRL_RXEN) & ~(SPW_DMACTRL_TXEN));*/
- ctrl = SPW_READ((volatile void *)&pDev->tx[cur].ctrl);
+ /* don't clear status flags */
+ dmactrl &= ~(SPW_DMACTRL_RA|SPW_DMACTRL_PR|SPW_DMACTRL_AI);
+ SPW_WRITE(&pDev->regs->dma0ctrl, dmactrl);
+ return RTEMS_SUCCESSFUL;
+}
- if (ctrl & SPW_TXBD_EN) {
- return 0;
- }
- memcpy(&txd[0], data, dlen);
- memcpy(&txh[0], hdr, hlen);
+int grspw_hw_send(GRSPW_DEV *pDev, unsigned int hlen, char *hdr, unsigned int dlen, char *data, unsigned int options)
+{
+ unsigned int dmactrl, ctrl;
#ifdef DEBUG_SPACEWIRE_ONOFF
- if (DEBUG_SPACEWIRE_FLAGS & DBGSPW_DUMP) {
- for (k = 0; k < hlen; k++){
- if (k % 16 == 0) {
- printf ("\n");
- }
- printf ("%.2x(%c) ",txh[k] & 0xff,isprint(txh[k] & 0xff) ? txh[k] & 0xff : ' ');
- }
- printf ("\n");
- }
- if (DEBUG_SPACEWIRE_FLAGS & DBGSPW_DUMP) {
- for (k = 0; k < dlen; k++){
- if (k % 16 == 0) {
- printf ("\n");
- }
- printf ("%.2x(%c) ",txd[k] & 0xff,isprint(txd[k] & 0xff) ? txd[k] & 0xff : ' ');
- }
- printf ("\n");
- }
+ unsigned int k;
#endif
+ rtems_interrupt_level level;
+ unsigned int cur = pDev->tx_cur, bdctrl;
+ char *txh = pDev->ptr_txhbuf0 + (cur * pDev->txhbufsize);
+ char *txd = pDev->ptr_txdbuf0 + (cur * pDev->txdbufsize);
+ char *txh_remote = pDev->ptr_txhbuf0_remote + (cur * pDev->txhbufsize);
+ char *txd_remote = pDev->ptr_txdbuf0_remote + (cur * pDev->txdbufsize);
+ unsigned int tmp, tmp2;
+
+ ctrl = SPW_READ((volatile void *)&pDev->tx[cur].ctrl);
+
+ if (ctrl & SPW_TXBD_EN) {
+ return 0;
+ }
- pDev->tx[cur].addr_header = memarea_to_hw((unsigned int)txh);
- pDev->tx[cur].len = dlen;
- pDev->tx[cur].addr_data = memarea_to_hw((unsigned int)txd);
- if (pDev->tx_cur == (pDev->txbufcnt - 1) ) {
- pDev->tx[cur].ctrl = SPW_TXBD_IE | SPW_TXBD_WR | SPW_TXBD_EN | hlen;
- } else {
- pDev->tx[cur].ctrl = SPW_TXBD_IE | SPW_TXBD_EN | hlen;
- }
+ memcpy(&txd[0], data, dlen);
+ memcpy(&txh[0], hdr, hlen);
- dmactrl = SPW_READ(&pDev->regs->dma0ctrl);
- SPW_WRITE(&pDev->regs->dma0ctrl, (dmactrl & SPW_PREPAREMASK_TX) | SPW_DMACTRL_TXEN | SPW_DMACTRL_TXIE);
+#ifdef DEBUG_SPACEWIRE_ONOFF
+ if (DEBUG_SPACEWIRE_FLAGS & DBGSPW_DUMP) {
+ for (k = 0; k < hlen; k++){
+ if (k % 16 == 0) {
+ printf ("\n");
+ }
+ printf ("%.2x(%c) ",txh[k] & 0xff,isprint(txh[k] & 0xff) ? txh[k] & 0xff : ' ');
+ }
+ printf ("\n");
+ }
+ if (DEBUG_SPACEWIRE_FLAGS & DBGSPW_DUMP) {
+ for (k = 0; k < dlen; k++){
+ if (k % 16 == 0) {
+ printf ("\n");
+ }
+ printf ("%.2x(%c) ",txd[k] & 0xff,isprint(txd[k] & 0xff) ? txd[k] & 0xff : ' ');
+ }
+ printf ("\n");
+ }
+#endif
+
+ pDev->tx[cur].addr_header = (unsigned int)txh_remote;
+ pDev->tx[cur].len = dlen;
+ pDev->tx[cur].addr_data = (unsigned int)txd_remote;
+
+ bdctrl = SPW_TXBD_IE | SPW_TXBD_EN | hlen;
+ if ( options & GRSPW_PKTSEND_OPTION_HDR_CRC )
+ bdctrl |= SPW_TXBD_HC;
+ if ( options & GRSPW_PKTSEND_OPTION_DATA_CRC )
+ bdctrl |= SPW_TXBD_DC;
+ bdctrl |= options & GRSPW_PKTSEND_OPTION_NOCRCLEN_MASK;
+
+ /* Update counters */
+ rtems_interrupt_disable(level);
+ if (pDev->tx_cur == (pDev->txbufcnt - 1) ) {
+ bdctrl |= SPW_TXBD_WR;
+ }
+ pDev->tx[cur].ctrl = bdctrl;
- /* Update counters */
- rtems_interrupt_disable(level);
+ dmactrl = SPW_READ(&pDev->regs->dma0ctrl);
+ SPW_WRITE(&pDev->regs->dma0ctrl, (dmactrl & SPW_PREPAREMASK_TX) | SPW_DMACTRL_TXEN | SPW_DMACTRL_TXIE);
- pDev->tx_cur = (pDev->tx_cur + 1) % pDev->txbufcnt;
- if (pDev->tx_cur == pDev->tx_sent) {
- pDev->tx_all_in_use = 1;
- }
- rtems_interrupt_enable(level);
+ pDev->tx_cur = (pDev->tx_cur + 1) % pDev->txbufcnt;
+ if (pDev->tx_cur == pDev->tx_sent) {
+ pDev->tx_all_in_use = 1;
+ }
+ rtems_interrupt_enable(level);
- /* In blocking mode wait until message is sent */
+ /* In blocking mode wait until message is sent */
if (pDev->config.tx_blocking) {
while ( SPW_READ(&pDev->regs->dma0ctrl) & SPW_DMACTRL_TXEN) {
/* if changed to blocking mode */
- SPACEWIRE_DBGC(DBGSPW_TX, "Tx blocking\n");
- rtems_semaphore_obtain(pDev->txsp, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+ SPACEWIRE_DBGC(DBGSPW_TX, "Tx blocking\n");
+ rtems_semaphore_obtain(pDev->txsp, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
}
}
- SPACEWIRE_DBGC(DBGSPW_TX, "0x%x: transmitted <%i> bytes\n", (unsigned int) pDev->regs, dlen+hlen);
- return hlen + dlen;
+ SPACEWIRE_DBGC(DBGSPW_TX, "0x%x: transmitted <%i> bytes\n", (unsigned int) pDev->regs, dlen+hlen);
+ return hlen + dlen;
}
static int grspw_hw_receive(GRSPW_DEV *pDev, char *b, int c) {
- unsigned int len, rxlen, ctrl;
- unsigned int cur;
- unsigned int tmp;
- unsigned int dump_start_len;
- int i;
- char *rxb;
-
- if ( pDev->config.promiscuous ) {
+ unsigned int len, rxlen, ctrl;
+ unsigned int cur;
+ unsigned int tmp;
+ unsigned int dump_start_len;
+ int i;
+ char *rxb;
+
+ if ( pDev->config.promiscuous || pDev->config.keep_source ) {
dump_start_len = 0; /* make sure address and prot can be read in promiscuous mode */
} else if (pDev->config.rm_prot_id) {
dump_start_len = 2; /* skip source address and protocol id */
@@ -1637,92 +1866,153 @@ static int grspw_hw_receive(GRSPW_DEV *pDev, char *b, int c) {
dump_start_len = 1; /* default: skip only source address */
}
- rxlen = 0;
- cur = pDev->rxcur;
- rxb = pDev->ptr_rxbuf0 + (cur * pDev->rxbufsize);
-
- SPACEWIRE_DBGC(DBGSPW_RX, "0x%x: waitin packet at pos %i\n", (unsigned int) pDev->regs, cur);
-
- ctrl = SPW_READ((volatile void *)&pDev->rx[cur].ctrl);
- if (ctrl & SPW_RXBD_EN) {
- return rxlen;
- }
- SPACEWIRE_DBGC(DBGSPW_RX, "checking packet\n");
-
- len = SPW_RXBD_LENGTH & ctrl;
- if (!((ctrl & SPW_RXBD_ERROR) || (pDev->config.check_rmap_err && (ctrl & SPW_RXBD_RMAPERROR)))) {
- if (pDev->rxbufcur == -1) {
- SPACEWIRE_DBGC(DBGSPW_RX, "incoming packet len %i\n", len);
- pDev->stat.packets_received++;
- pDev->rxbufcur = dump_start_len;
- }
- rxlen = tmp = len - pDev->rxbufcur;
- SPACEWIRE_DBGC(DBGSPW_RX, "C %i\n", c);
- SPACEWIRE_DBGC(DBGSPW_RX, "Dump %i\n", dump_start_len);
- SPACEWIRE_DBGC(DBGSPW_RX, "Bufcur %i\n", pDev->rxbufcur);
- SPACEWIRE_DBGC(DBGSPW_RX, "Rxlen %i\n", rxlen );
- if (rxlen > c) {
- rxlen = c;
- }
- if (CPU_SPARC_HAS_SNOOPING) {
- memcpy(b, rxb+pDev->rxbufcur, rxlen);
- } else {
- for(i = 0; i < rxlen; i++) {
- b[i] = MEM_READ(rxb+pDev->rxbufcur);
- }
- }
-
- pDev->rxbufcur += rxlen;
- if (c >= tmp) {
- SPACEWIRE_DBGC(DBGSPW_RX, "Next descriptor\n");
- grspw_rxnext(pDev);
- }
- } else {
- check_rx_errors(pDev, ctrl);
- }
- return rxlen;
+ rxlen = 0;
+ cur = pDev->rxcur;
+ rxb = pDev->ptr_rxbuf0 + (cur * pDev->rxbufsize);
+
+ SPACEWIRE_DBGC(DBGSPW_RX, "0x%x: waitin packet at pos %i\n", (unsigned int) pDev->regs, cur);
+
+ ctrl = SPW_READ((volatile void *)&pDev->rx[cur].ctrl);
+ if (ctrl & SPW_RXBD_EN) {
+ return rxlen;
+ }
+ SPACEWIRE_DBGC(DBGSPW_RX, "checking packet\n");
+
+ len = SPW_RXBD_LENGTH & ctrl;
+ if (!((ctrl & SPW_RXBD_ERROR) || (pDev->config.check_rmap_err && (ctrl & SPW_RXBD_RMAPERROR)))) {
+ if (pDev->rxbufcur == -1) {
+ SPACEWIRE_DBGC(DBGSPW_RX, "incoming packet len %i\n", len);
+ pDev->stat.packets_received++;
+ pDev->rxbufcur = dump_start_len;
+ }
+ rxlen = tmp = len - pDev->rxbufcur;
+ SPACEWIRE_DBGC(DBGSPW_RX, "C %i\n", c);
+ SPACEWIRE_DBGC(DBGSPW_RX, "Dump %i\n", dump_start_len);
+ SPACEWIRE_DBGC(DBGSPW_RX, "Bufcur %i\n", pDev->rxbufcur);
+ SPACEWIRE_DBGC(DBGSPW_RX, "Rxlen %i\n", rxlen );
+ if (rxlen > c) {
+ rxlen = c;
+ }
+ if (CPU_SPARC_HAS_SNOOPING) {
+/* if ( 1 ) {*/
+ /*printf("RX_MEMCPY(0x%x, 0x%x, 0x%x)\n", (unsigned int)b, (unsigned int)(rxb+pDev->rxbufcur), (unsigned int)rxlen);*/
+ memcpy(b, rxb+pDev->rxbufcur, rxlen);
+ } else {
+ int left = rxlen;
+ /* Copy word wise if Aligned */
+ if ( (((int)b & 3) == 0) && (((int)(rxb+pDev->rxbufcur) & 3) == 0) ){
+ while(left>=32){
+ *(int *)(b+0) = MEM_READ32(rxb+pDev->rxbufcur+0);
+ *(int *)(b+4) = MEM_READ32(rxb+pDev->rxbufcur+4);
+ *(int *)(b+8) = MEM_READ32(rxb+pDev->rxbufcur+8);
+ *(int *)(b+12) = MEM_READ32(rxb+pDev->rxbufcur+12);
+ *(int *)(b+16) = MEM_READ32(rxb+pDev->rxbufcur+16);
+ *(int *)(b+20) = MEM_READ32(rxb+pDev->rxbufcur+20);
+ *(int *)(b+24) = MEM_READ32(rxb+pDev->rxbufcur+24);
+ *(int *)(b+28) = MEM_READ32(rxb+pDev->rxbufcur+28);
+ rxb+=32;
+ b+=32;
+ left-=32;
+ }
+ while(left>=4){
+ *(int *)b = MEM_READ32(rxb+pDev->rxbufcur);
+ rxb+=4;
+ b+=4;
+ left-=4;
+ }
+ }
+ for(i = 0; i < left; i++) {
+ b[i] = MEM_READ8(rxb+pDev->rxbufcur+i);
+ }
+ }
+
+ pDev->rxbufcur += rxlen;
+ if (c >= tmp) {
+ SPACEWIRE_DBGC(DBGSPW_RX, "Next descriptor\n");
+ grspw_rxnext(pDev);
+ }
+ } else {
+ check_rx_errors(pDev, ctrl);
+ grspw_rxnext(pDev);
+ }
+ return rxlen;
}
-static void grspw_rxnext(GRSPW_DEV *pDev)
+static void grspw_rxnext(GRSPW_DEV *pDev)
{
- unsigned int dmactrl;
- unsigned int cur = pDev->rxcur;
- unsigned int ctrl = 0;
- if (cur == (pDev->rxbufcnt - 1)) {
- pDev->rx[cur].ctrl = ctrl | SPW_RXBD_EN | SPW_RXBD_IE | SPW_RXBD_WR;
- cur = 0;
- } else {
- pDev->rx[cur].ctrl = ctrl | SPW_RXBD_EN | SPW_RXBD_IE;
- cur++;
- }
-
- pDev->rxcur = cur;
- pDev->rxbufcur = -1;
-
- /* start RX */
- dmactrl = SPW_READ(&pDev->regs->dma0ctrl);
- SPW_WRITE(&pDev->regs->dma0ctrl, (dmactrl & SPW_PREPAREMASK_RX) | SPW_DMACTRL_RD | SPW_DMACTRL_RXEN | SPW_DMACTRL_RXIE | SPW_DMACTRL_NS);
+ unsigned int dmactrl;
+ unsigned int cur = pDev->rxcur;
+ unsigned int ctrl = 0;
+ rtems_interrupt_level level;
+
+ rtems_interrupt_disable(level);
+
+ if (cur == (pDev->rxbufcnt - 1)) {
+ pDev->rx[cur].ctrl = ctrl | SPW_RXBD_EN | SPW_RXBD_IE | SPW_RXBD_WR;
+ cur = 0;
+ } else {
+ pDev->rx[cur].ctrl = ctrl | SPW_RXBD_EN | SPW_RXBD_IE;
+ cur++;
+ }
+
+ pDev->rxcur = cur;
+ pDev->rxbufcur = -1;
+
+ /* start RX */
+ dmactrl = SPW_READ(&pDev->regs->dma0ctrl);
+ SPW_WRITE(&pDev->regs->dma0ctrl, (dmactrl & SPW_PREPAREMASK_RX) | SPW_DMACTRL_RD | SPW_DMACTRL_RXEN | SPW_DMACTRL_RXIE | SPW_DMACTRL_NS);
+ rtems_interrupt_enable(level);
+}
+
+static void check_rx_errors(GRSPW_DEV *pDev, int ctrl)
+{
+ if (ctrl & SPW_RXBD_EEP) {
+ pDev->stat.rx_eep_err++;
+ }
+ if (ctrl & SPW_RXBD_EHC) {
+ if (pDev->config.check_rmap_err) {
+ pDev->stat.rx_rmap_header_crc_err++;
+ }
+ }
+ if (ctrl & SPW_RXBD_EDC) {
+ if (pDev->config.check_rmap_err) {
+ pDev->stat.rx_rmap_data_crc_err++;
+ }
+ }
+ if (ctrl & SPW_RXBD_ETR) {
+ pDev->stat.rx_truncated++;
+ }
}
-static void check_rx_errors(GRSPW_DEV *pDev, int ctrl)
+
+void grspw_print_dev(struct drvmgr_dev *dev, int options)
{
- if (ctrl & SPW_RXBD_EEP) {
- pDev->stat.rx_eep_err++;
- }
- if (ctrl & SPW_RXBD_EHC) {
- if (pDev->config.check_rmap_err) {
- pDev->stat.rx_rmap_header_crc_err++;
- }
- }
- if (ctrl & SPW_RXBD_EDC) {
- if (pDev->config.check_rmap_err) {
- pDev->stat.rx_rmap_data_crc_err++;
- }
- }
- if (ctrl & SPW_RXBD_ETR) {
- pDev->stat.rx_truncated++;
- }
+ GRSPW_DEV *pDev = dev->priv;
+ struct amba_dev_info *devinfo;
+
+ devinfo = (struct amba_dev_info *)pDev->dev->businfo;
+
+ /* Print */
+ printf("--- GRSPW %s ---\n", pDev->devName);
+ printf(" REGS: 0x%x\n", (unsigned int)pDev->regs);
+ printf(" IRQ: %d\n", pDev->irq);
+ printf(" CORE VERSION: %d\n", pDev->core_ver);
+ printf(" CTRL: 0x%x\n", pDev->regs->ctrl);
+ printf(" STATUS: 0x%x\n", pDev->regs->status);
+ printf(" DMA0CTRL: 0x%x\n", pDev->regs->dma0ctrl);
+ printf(" TXBD: 0x%x\n", (unsigned int)pDev->tx);
+ printf(" RXBD: 0x%x\n", (unsigned int)pDev->rx);
}
+void grspw_print(int options)
+{
+ struct amba_drv_info *drv = &grspw_drv_info;
+ struct drvmgr_dev *dev;
+ dev = drv->general.dev;
+ while(dev) {
+ grspw_print_dev(dev, options);
+ dev = dev->next_in_drv;
+ }
+}
diff --git a/c/src/lib/libbsp/sparc/shared/spw/grspw_pci.c b/c/src/lib/libbsp/sparc/shared/spw/grspw_pci.c
deleted file mode 100644
index a8003be8f9..0000000000
--- a/c/src/lib/libbsp/sparc/shared/spw/grspw_pci.c
+++ /dev/null
@@ -1,127 +0,0 @@
-/* Select PCI driver */
-#define GRSPW_PCI
-
-#undef GRSPW_MAXDEVS
-#undef DEBUG_SPACEWIRE_ONOFF
-
-/* Only Malloced memory supported
- */
-#undef GRSPW_LOCAL_MEM
-
-/* memory must be aligned to a 128k boundary */
-unsigned int grspwpci_memarea_address;
-#define GRSPW_LOCAL_MEM_ADR grspwpci_memarea_address
-
-/* We have custom address tranlation for HW addresses */
-#define GRSPW_ADR_TO
-
-/* MEMAREA=>CPU used when reading descriptor buffer pointers,
- * they need to be translated from adresses used by GRSPW HW
- * into CPU readable addresses.
- *
- * NOT NEEDED AS GRSPW DRIVER USES INDEXES TO GET DESCRIPTOR
- * DATA POINTER ADDRESSES.
- */
-#undef GRSPW_ADR_FROM
-
-/* Set registered device name */
-#define GRSPW_DEVNAME "/dev/grspwpci0"
-#define GRSPW_DEVNAME_NO(devstr,no) ((devstr)[13]='0'+(no))
-
-/* Any non-static function will begin with */
-#define GRSPW_PREFIX(name) grspwpci##name
-
-/* do nothing, assume that the interrupt handler is called
- * setup externally calling b1553_interrupt_handler.
- */
-#define GRSPW_REG_INT(handler,irq,arg) \
- if ( grspw_pci_int_reg ) \
- grspw_pci_int_reg(handler,irq,arg);
-
-void (*grspw_pci_int_reg)(void *handler, int irq, void *arg) = 0;
-
-
-#ifdef GRSPW_ADR_TO
-/* Translate an address within the Memory Region (memarea) into an Hardware
- * device address. This address is put into hardware registers or descriptors
- * so that the hardware can access the Memory Region.
- * Example:
- * A local AMBA access at 0xe0000000 will translate into PCI address 0x40000000,
- * the PCI address 0x40000000 will translate into LEON-AMBA address 0x40000000.
- */
-unsigned int grspwpci_hw_address;
-static inline unsigned int memarea_to_hw(unsigned int addr) {
- /* don't translate? */
- if ( grspwpci_hw_address == 0xffffffff )
- return addr;
- return ((addr & 0x0fffffff) | grspwpci_hw_address);
-}
-#endif
-
-/* not used since BRM Core work with offsets */
-#ifdef GRSPW_ADR_FROM
-unsigned int grspwpci_cpu_access_address;
-static inline unsigned int hw_to_cpu(unsigned int addr) {
- /* don't translate? */
- if ( grspwpci_cpu_address == 0xffffffff )
- return addr;
- return ((addr & 0x0fffffff) | grspwpci_cpu_address);
-}
-#endif
-
-int grspwpci_interrupt_handler(int irq, void *arg);
-#include "grspw.c"
-
-/*
- *
- * memarea = preallocated memory somewhere, pointer to start of memory.
- * hw_address = how to translate a memarea address into an HW device AMBA address.
- */
-
-int grspw_pci_register(
- amba_confarea_type *bus,
- unsigned int memarea,
- unsigned int hw_address
- )
-{
- /* Setup configuration */
-
- /* if zero the malloc will be used */
- grspwpci_memarea_address = memarea;
-
- grspwpci_hw_address = hw_address;
-
-#ifdef GRSPW_ADR_FROM
- grspwpci_cpu_address = memarea & 0xf0000000;
-#endif
-
- /* Register the driver */
- return GRSPW_PREFIX(_register)(bus);
-}
-
-/* Call this from PCI interrupt handler
- * irq = the irq number of the HW device local to that IRQMP controller
- *
- */
-int grspwpci_interrupt_handler(int irq, void *arg){
- grspw_interrupt( (GRSPW_DEV *)arg );
- return 0;
-}
-
-#if 0
-int grspw_pci_interrupt_handler(int irqmask){
- int i;
- unsigned int mask=0;
- /* find minor */
- for(i=0; i<spw_cores; i++){
- if ( (1<<SPW_PARAM(i).irq) & irqmask ){
- mask |= 1<<SPW_PARAM(i).irq;
- grspw_interrupt(i);
- /* more interrupts to scan for? */
- if ( irqmask & ~mask )
- return mask; /* handled */
- }
- }
- return mask;
-}
-#endif
diff --git a/c/src/lib/libbsp/sparc/shared/spw/grspw_pkt.c b/c/src/lib/libbsp/sparc/shared/spw/grspw_pkt.c
new file mode 100644
index 0000000000..10a869748d
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/spw/grspw_pkt.c
@@ -0,0 +1,2634 @@
+/*
+ * Aeroflex Gaisler GRSPW2 SpaceWire Kernel Library Interface for RTEMS.
+ *
+ * This driver can be used to implement a standard I/O system "char"-driver
+ * or used directly. NOTE SMP support has not been tested.
+ *
+ * COPYRIGHT (c) 2011
+ * Aeroflex Gaisler AB
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#include <rtems.h>
+#include <bsp.h>
+#include <rtems/libio.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+#include <malloc.h>
+#include <rtems/bspIo.h>
+
+#include <drvmgr/drvmgr.h>
+#include <ambapp.h>
+#include <drvmgr/ambapp_bus.h>
+#include <grspw_pkt.h>
+
+/* This driver has been prepared for SMP operation however never tested
+ * on a SMP system - use on your own risk.
+ */
+#ifdef RTEMS_HAS_SMP
+
+#include <rtems/score/smplock.h> /* spin-lock */
+
+/* SPIN_LOCK() and SPIN_UNLOCK() NOT_IMPLEMENTED_BY_RTEMS. Use _IRQ version
+ * to implement.
+ */
+#define SPIN_DECLARE(name) SMP_lock_spinlock_simple_Control name
+#define SPIN_INIT(lock) _SMP_lock_spinlock_simple_Initialize(lock)
+#define SPIN_LOCK(lock, level) SPIN_LOCK_IRQ(lock, level)
+#define SPIN_LOCK_IRQ(lock, level) (level) = _SMP_lock_spinlock_simple_Obtain(lock)
+#define SPIN_UNLOCK(lock, level) SPIN_UNLOCK_IRQ(lock, level)
+#define SPIN_UNLOCK_IRQ(lock, level) _SMP_lock_spinlock_simple_Release(lock, level)
+#define IRQFLAGS_TYPE ISR_Level
+
+#else
+
+#define SPIN_DECLARE(name)
+#define SPIN_INIT(lock)
+#define SPIN_LOCK(lock, level)
+#define SPIN_LOCK_IRQ(lock, level) rtems_interrupt_disable(level)
+#define SPIN_UNLOCK(lock, level)
+#define SPIN_UNLOCK_IRQ(lock, level) rtems_interrupt_enable(level)
+#define IRQFLAGS_TYPE rtems_interrupt_level
+
+#endif
+
+/*#define STATIC*/
+#define STATIC static
+
+/*#define GRSPW_DBG(args...) printk(args)*/
+#define GRSPW_DBG(args...)
+
+struct grspw_dma_regs {
+ volatile unsigned int ctrl; /* DMA Channel Control */
+ volatile unsigned int rxmax; /* RX Max Packet Length */
+ volatile unsigned int txdesc; /* TX Descriptor Base/Current */
+ volatile unsigned int rxdesc; /* RX Descriptor Base/Current */
+ volatile unsigned int addr; /* Address Register */
+ volatile unsigned int resv[3];
+};
+
+struct grspw_regs {
+ volatile unsigned int ctrl;
+ volatile unsigned int status;
+ volatile unsigned int nodeaddr;
+ volatile unsigned int clkdiv;
+ volatile unsigned int destkey;
+ volatile unsigned int time;
+ volatile unsigned int timer; /* Used only in GRSPW1 */
+ volatile unsigned int resv1;
+
+ /* DMA Registers, ctrl.NCH determines number of ports,
+ * up to 4 channels are supported
+ */
+ struct grspw_dma_regs dma[4];
+};
+
+/* GRSPW - Control Register - 0x00 */
+#define GRSPW_CTRL_RA_BIT 31
+#define GRSPW_CTRL_RX_BIT 30
+#define GRSPW_CTRL_RC_BIT 29
+#define GRSPW_CTRL_NCH_BIT 27
+#define GRSPW_CTRL_PO_BIT 26
+#define GRSPW_CTRL_PS_BIT 21
+#define GRSPW_CTRL_NP_BIT 20
+#define GRSPW_CTRL_RD_BIT 17
+#define GRSPW_CTRL_RE_BIT 16
+#define GRSPW_CTRL_TR_BIT 11
+#define GRSPW_CTRL_TT_BIT 10
+#define GRSPW_CTRL_LI_BIT 9
+#define GRSPW_CTRL_TQ_BIT 8
+#define GRSPW_CTRL_RS_BIT 6
+#define GRSPW_CTRL_PM_BIT 5
+#define GRSPW_CTRL_TI_BIT 4
+#define GRSPW_CTRL_IE_BIT 3
+#define GRSPW_CTRL_AS_BIT 2
+#define GRSPW_CTRL_LS_BIT 1
+#define GRSPW_CTRL_LD_BIT 0
+
+#define GRSPW_CTRL_RA (1<<GRSPW_CTRL_RA_BIT)
+#define GRSPW_CTRL_RX (1<<GRSPW_CTRL_RX_BIT)
+#define GRSPW_CTRL_RC (1<<GRSPW_CTRL_RC_BIT)
+#define GRSPW_CTRL_NCH (0x3<<GRSPW_CTRL_NCH_BIT)
+#define GRSPW_CTRL_PO (1<<GRSPW_CTRL_PO_BIT)
+#define GRSPW_CTRL_PS (1<<GRSPW_CTRL_PS_BIT)
+#define GRSPW_CTRL_NP (1<<GRSPW_CTRL_NP_BIT)
+#define GRSPW_CTRL_RD (1<<GRSPW_CTRL_RD_BIT)
+#define GRSPW_CTRL_RE (1<<GRSPW_CTRL_RE_BIT)
+#define GRSPW_CTRL_TR (1<<GRSPW_CTRL_TR_BIT)
+#define GRSPW_CTRL_TT (1<<GRSPW_CTRL_TT_BIT)
+#define GRSPW_CTRL_LI (1<<GRSPW_CTRL_LI_BIT)
+#define GRSPW_CTRL_TQ (1<<GRSPW_CTRL_TQ_BIT)
+#define GRSPW_CTRL_RS (1<<GRSPW_CTRL_RS_BIT)
+#define GRSPW_CTRL_PM (1<<GRSPW_CTRL_PM_BIT)
+#define GRSPW_CTRL_TI (1<<GRSPW_CTRL_TI_BIT)
+#define GRSPW_CTRL_IE (1<<GRSPW_CTRL_IE_BIT)
+#define GRSPW_CTRL_AS (1<<GRSPW_CTRL_AS_BIT)
+#define GRSPW_CTRL_LS (1<<GRSPW_CTRL_LS_BIT)
+#define GRSPW_CTRL_LD (1<<GRSPW_CTRL_LD_BIT)
+
+/* GRSPW - Status Register - 0x04 */
+#define GRSPW_STS_LS_BIT 21
+#define GRSPW_STS_AP_BIT 9
+#define GRSPW_STS_EE_BIT 8
+#define GRSPW_STS_IA_BIT 7
+#define GRSPW_STS_WE_BIT 6
+#define GRSPW_STS_PE_BIT 4
+#define GRSPW_STS_DE_BIT 3
+#define GRSPW_STS_ER_BIT 2
+#define GRSPW_STS_CE_BIT 1
+#define GRSPW_STS_TO_BIT 0
+
+#define GRSPW_STS_LS (0x7<<GRSPW_STS_LS_BIT)
+#define GRSPW_STS_AP (1<<GRSPW_STS_AP_BIT)
+#define GRSPW_STS_EE (1<<GRSPW_STS_EE_BIT)
+#define GRSPW_STS_IA (1<<GRSPW_STS_IA_BIT)
+#define GRSPW_STS_WE (1<<GRSPW_STS_WE_BIT)
+#define GRSPW_STS_PE (1<<GRSPW_STS_PE_BIT)
+#define GRSPW_STS_DE (1<<GRSPW_STS_DE_BIT)
+#define GRSPW_STS_ER (1<<GRSPW_STS_ER_BIT)
+#define GRSPW_STS_CE (1<<GRSPW_STS_CE_BIT)
+#define GRSPW_STS_TO (1<<GRSPW_STS_TO_BIT)
+
+/* GRSPW - Default Address Register - 0x08 */
+#define GRSPW_DEF_ADDR_BIT 0
+#define GRSPW_DEF_MASK_BIT 8
+#define GRSPW_DEF_ADDR (0xff<<GRSPW_DEF_ADDR_BIT)
+#define GRSPW_DEF_MASK (0xff<<GRSPW_DEF_MASK_BIT)
+
+/* GRSPW - Clock Divisor Register - 0x0C */
+#define GRSPW_CLKDIV_START_BIT 8
+#define GRSPW_CLKDIV_RUN_BIT 0
+#define GRSPW_CLKDIV_START (0xff<<GRSPW_CLKDIV_START_BIT)
+#define GRSPW_CLKDIV_RUN (0xff<<GRSPW_CLKDIV_RUN_BIT)
+#define GRSPW_CLKDIV_MASK (GRSPW_CLKDIV_START|GRSPW_CLKDIV_RUN)
+
+/* GRSPW - Destination key Register - 0x10 */
+#define GRSPW_DK_DESTKEY_BIT 0
+#define GRSPW_DK_DESTKEY (0xff<<GRSPW_DK_DESTKEY_BIT)
+
+/* GRSPW - Time Register - 0x14 */
+#define GRSPW_TIME_CTRL_BIT 0
+#define GRSPW_TIME_CNT_BIT 6
+#define GRSPW_TIME_CTRL (0x3f<<GRSPW_TIME_CTRL_BIT)
+#define GRSPW_TIME_TCNT (0x3<<GRSPW_TIME_CNT_BIT)
+
+/* GRSPW - DMA Control Register - 0x20*N */
+#define GRSPW_DMACTRL_LE_BIT 16
+#define GRSPW_DMACTRL_SP_BIT 15
+#define GRSPW_DMACTRL_SA_BIT 14
+#define GRSPW_DMACTRL_EN_BIT 13
+#define GRSPW_DMACTRL_NS_BIT 12
+#define GRSPW_DMACTRL_RD_BIT 11
+#define GRSPW_DMACTRL_RX_BIT 10
+#define GRSPW_DMACTRL_AT_BIT 9
+#define GRSPW_DMACTRL_RA_BIT 8
+#define GRSPW_DMACTRL_TA_BIT 7
+#define GRSPW_DMACTRL_PR_BIT 6
+#define GRSPW_DMACTRL_PS_BIT 5
+#define GRSPW_DMACTRL_AI_BIT 4
+#define GRSPW_DMACTRL_RI_BIT 3
+#define GRSPW_DMACTRL_TI_BIT 2
+#define GRSPW_DMACTRL_RE_BIT 1
+#define GRSPW_DMACTRL_TE_BIT 0
+
+#define GRSPW_DMACTRL_LE (1<<GRSPW_DMACTRL_LE_BIT)
+#define GRSPW_DMACTRL_SP (1<<GRSPW_DMACTRL_SP_BIT)
+#define GRSPW_DMACTRL_SA (1<<GRSPW_DMACTRL_SA_BIT)
+#define GRSPW_DMACTRL_EN (1<<GRSPW_DMACTRL_EN_BIT)
+#define GRSPW_DMACTRL_NS (1<<GRSPW_DMACTRL_NS_BIT)
+#define GRSPW_DMACTRL_RD (1<<GRSPW_DMACTRL_RD_BIT)
+#define GRSPW_DMACTRL_RX (1<<GRSPW_DMACTRL_RX_BIT)
+#define GRSPW_DMACTRL_AT (1<<GRSPW_DMACTRL_AT_BIT)
+#define GRSPW_DMACTRL_RA (1<<GRSPW_DMACTRL_RA_BIT)
+#define GRSPW_DMACTRL_TA (1<<GRSPW_DMACTRL_TA_BIT)
+#define GRSPW_DMACTRL_PR (1<<GRSPW_DMACTRL_PR_BIT)
+#define GRSPW_DMACTRL_PS (1<<GRSPW_DMACTRL_PS_BIT)
+#define GRSPW_DMACTRL_AI (1<<GRSPW_DMACTRL_AI_BIT)
+#define GRSPW_DMACTRL_RI (1<<GRSPW_DMACTRL_RI_BIT)
+#define GRSPW_DMACTRL_TI (1<<GRSPW_DMACTRL_TI_BIT)
+#define GRSPW_DMACTRL_RE (1<<GRSPW_DMACTRL_RE_BIT)
+#define GRSPW_DMACTRL_TE (1<<GRSPW_DMACTRL_TE_BIT)
+
+/* GRSPW - DMA Channel Max Packet Length Register - (0x20*N + 0x04) */
+#define GRSPW_DMARXLEN_MAX_BIT 0
+#define GRSPW_DMARXLEN_MAX (0xffffff<<GRSPW_DMARXLEN_MAX_BIT)
+
+/* GRSPW - DMA Channel Address Register - (0x20*N + 0x10) */
+#define GRSPW_DMAADR_ADDR_BIT 0
+#define GRSPW_DMAADR_MASK_BIT 8
+#define GRSPW_DMAADR_ADDR (0xff<<GRSPW_DMAADR_ADDR_BIT)
+#define GRSPW_DMAADR_MASK (0xff<<GRSPW_DMAADR_MASK_BIT)
+
+/* RX Buffer Descriptor */
+struct grspw_rxbd {
+ volatile unsigned int ctrl;
+ volatile unsigned int addr;
+};
+
+/* TX Buffer Descriptor */
+struct grspw_txbd {
+ volatile unsigned int ctrl;
+ volatile unsigned int haddr;
+ volatile unsigned int dlen;
+ volatile unsigned int daddr;
+};
+
+/* GRSPW - DMA RXBD Ctrl */
+#define GRSPW_RXBD_LEN_BIT 0
+#define GRSPW_RXBD_LEN (0x1ffffff<<GRSPW_RXBD_LEN_BIT)
+#define GRSPW_RXBD_EN (1<<25)
+#define GRSPW_RXBD_WR (1<<26)
+#define GRSPW_RXBD_IE (1<<27)
+#define GRSPW_RXBD_EP (1<<28)
+#define GRSPW_RXBD_HC (1<<29)
+#define GRSPW_RXBD_DC (1<<30)
+#define GRSPW_RXBD_TR (1<<31)
+
+#define GRSPW_TXBD_HLEN (0xff<<0)
+#define GRSPW_TXBD_NCL (0xf<<8)
+#define GRSPW_TXBD_EN (1<<12)
+#define GRSPW_TXBD_WR (1<<13)
+#define GRSPW_TXBD_IE (1<<14)
+#define GRSPW_TXBD_LE (1<<15)
+#define GRSPW_TXBD_HC (1<<16)
+#define GRSPW_TXBD_DC (1<<17)
+
+#define GRSPW_DMAADR_MASK_BIT 8
+#define GRSPW_DMAADR_ADDR (0xff<<GRSPW_DMAADR_ADDR_BIT)
+#define GRSPW_DMAADR_MASK (0xff<<GRSPW_DMAADR_MASK_BIT)
+
+
+/* GRSPW Error Condition */
+#define GRSPW_STAT_ERROR (GRSPW_STS_EE | GRSPW_STS_IA | GRSPW_STS_WE | GRSPW_STS_PE | GRSPW_STS_DE | GRSPW_STS_ER | GRSPW_STS_CE)
+#define GRSPW_DMA_STATUS_ERROR (GRSPW_DMACTRL_RA | GRSPW_DMACTRL_TA)
+/* GRSPW Link configuration options */
+#define GRSPW_LINK_CFG (GRSPW_CTRL_LI | GRSPW_CTRL_LD | GRSPW_CTRL_LS | GRSPW_CTRL_AS)
+#define GRSPW_LINKSTATE(status) ((status & GRSPW_CTRL_LS) >> GRSPW_CTRL_LS_BIT)
+
+/* Software Defaults */
+#define DEFAULT_RXMAX 1024 /* 1 KBytes Max RX Packet Size */
+
+/* GRSPW Constants */
+#define GRSPW_TXBD_NR 64 /* Maximum number of TX Descriptors */
+#define GRSPW_RXBD_NR 128 /* Maximum number of RX Descriptors */
+#define BDTAB_SIZE 0x400 /* BD Table Size (RX or TX) */
+#define BDTAB_ALIGN 0x400 /* BD Table Alignment Requirement */
+
+/* Memory and HW Registers Access routines. All 32-bit access routines */
+#define BD_WRITE(addr, val) (*(volatile unsigned int *)(addr) = (unsigned int)(val))
+/*#define BD_READ(addr) (*(volatile unsigned int *)(addr))*/
+#define BD_READ(addr) leon_r32_no_cache((unsigned long)(addr))
+#define REG_WRITE(addr, val) (*(volatile unsigned int *)(addr) = (unsigned int)(val))
+#define REG_READ(addr) (*(volatile unsigned int *)(addr))
+
+struct grspw_ring {
+ struct grspw_ring *next; /* Next Descriptor */
+ union {
+ struct grspw_txbd *tx; /* Descriptor Address */
+ struct grspw_rxbd *rx; /* Descriptor Address */
+ } bd;
+ struct grspw_pkt *pkt; /* Packet description associated.NULL if none*/
+};
+
+/* An entry in the TX descriptor Ring */
+struct grspw_txring {
+ struct grspw_txring *next; /* Next Descriptor */
+ struct grspw_txbd *bd; /* Descriptor Address */
+ struct grspw_pkt *pkt; /* Packet description associated.NULL if none*/
+};
+
+/* An entry in the RX descriptor Ring */
+struct grspw_rxring {
+ struct grspw_rxring *next; /* Next Descriptor */
+ struct grspw_rxbd *bd; /* Descriptor Address */
+ struct grspw_pkt *pkt; /* Packet description associated.NULL if none*/
+};
+
+
+struct grspw_dma_priv {
+ struct grspw_priv *core; /* GRSPW Core */
+ struct grspw_dma_regs *regs; /* DMA Channel Registers */
+ int index; /* DMA Channel Index @ GRSPW core */
+ int open; /* DMA Channel opened by user */
+ int started; /* DMA Channel activity (start|stop) */
+ rtems_id sem_dma; /* DMA Channel Semaphore */
+ struct grspw_dma_stats stats; /* DMA Channel Statistics */
+ struct grspw_dma_config cfg; /* DMA Channel Configuration */
+
+ /*** RX ***/
+
+ /* RX Descriptor Ring */
+ struct grspw_rxbd *rx_bds; /* Descriptor Address */
+ struct grspw_rxbd *rx_bds_hwa; /* Descriptor HW Address */
+ struct grspw_rxring *rx_ring_base;
+ struct grspw_rxring *rx_ring_head; /* Next descriptor to enable */
+ struct grspw_rxring *rx_ring_tail; /* Oldest enabled Descriptor */
+ int rx_irq_en_cnt_curr;
+ struct {
+ int waiting;
+ int ready_cnt;
+ int op;
+ int recv_cnt;
+ rtems_id sem_wait; /* RX Semaphore used to implement RX blocking */
+ } rx_wait;
+
+ /* Queue of Packets READY to be scheduled */
+ struct grspw_list ready;
+ int ready_cnt;
+
+ /* Scheduled RX Packets Queue */
+ struct grspw_list rx_sched;
+ int rx_sched_cnt;
+
+ /* Queue of Packets that has been RECIEVED */
+ struct grspw_list recv;
+ int recv_cnt;
+
+
+ /*** TX ***/
+
+ /* TX Descriptor Ring */
+ struct grspw_txbd *tx_bds; /* Descriptor Address */
+ struct grspw_txbd *tx_bds_hwa; /* Descriptor HW Address */
+ struct grspw_txring *tx_ring_base;
+ struct grspw_txring *tx_ring_head;
+ struct grspw_txring *tx_ring_tail;
+ int tx_irq_en_cnt_curr;
+ struct {
+ int waiting;
+ int send_cnt;
+ int op;
+ int sent_cnt;
+ rtems_id sem_wait; /* TX Semaphore used to implement TX blocking */
+ } tx_wait;
+
+ /* Queue of Packets ready to be scheduled for transmission */
+ struct grspw_list send;
+ int send_cnt;
+
+ /* Scheduled TX Packets Queue */
+ struct grspw_list tx_sched;
+ int tx_sched_cnt;
+
+ /* Queue of Packets that has been SENT */
+ struct grspw_list sent;
+ int sent_cnt;
+};
+
+struct grspw_priv {
+ char devname[8]; /* Device name "grspw%d" */
+ struct drvmgr_dev *dev; /* Device */
+ struct grspw_regs *regs; /* Virtual Address of APB Registers */
+ int irq; /* AMBA IRQ number of core */
+ int index; /* Index in order it was probed */
+ int core_index; /* Core Bus Index */
+ int open; /* If Device is alrady opened (=1) or not (=0) */
+ void *data; /* User private Data for this device instance, set by grspw_initialize_user */
+
+ /* Features supported by Hardware */
+ struct grspw_hw_sup hwsup;
+
+ /* Pointer to an array of Maximally 4 DMA Channels */
+ struct grspw_dma_priv *dma;
+
+ /* Spin-lock ISR protection */
+ SPIN_DECLARE(devlock);
+
+ /* Descriptor Memory Area for TX & RX and all DMA channels */
+ unsigned int bd_mem;
+ unsigned int bd_mem_alloced;
+
+ /*** Time Code Handling ***/
+ void (*tcisr)(void *data, int timecode);
+ void *tcisr_arg;
+
+ /* Disable Link on SpW Link error */
+ int dis_link_on_err;
+
+ /* "Core Global" Statistics gathered, not dependent on DMA channel */
+ struct grspw_core_stats stats;
+};
+
+int grspw_initialized = 0;
+int grspw_count = 0;
+struct workqueue_struct *grspw_workq = NULL;
+rtems_id grspw_sem;
+static struct grspw_priv *priv_tab[GRSPW_MAX];
+
+/* callback to upper layer when devices are discovered/removed */
+void *(*grspw_dev_add)(int) = NULL;
+void (*grspw_dev_del)(int,void*) = NULL;
+
+/* USER OVERRIDABLE - The work task priority. Set to -1 to disable creating
+ * the work-task and work-queue to save space.
+ */
+int grspw_work_task_priority __attribute__((weak)) = 100;
+int grspw_task_stop = 0;
+rtems_id grspw_work_task;
+rtems_id grspw_work_queue = 0;
+#define WORK_NONE 0
+#define WORK_SHUTDOWN 0x100
+#define WORK_DMA(channel) (0x1 << (channel))
+#define WORK_DMA_MASK 0xf /* max 4 channels */
+#define WORK_CORE_BIT 16
+#define WORK_CORE_MASK 0xffff
+#define WORK_CORE(device) ((device) << WORK_CORE_BIT)
+
+STATIC void grspw_hw_stop(struct grspw_priv *priv);
+STATIC void grspw_hw_dma_stop(struct grspw_dma_priv *dma);
+STATIC void grspw_dma_reset(struct grspw_dma_priv *dma);
+STATIC void grspw_dma_stop_locked(struct grspw_dma_priv *dma);
+STATIC void grspw_isr(void *data);
+
+void *grspw_open(int dev_no)
+{
+ struct grspw_priv *priv;
+ unsigned int bdtabsize, hwa;
+ int i;
+ union drvmgr_key_value *value;
+
+ if (grspw_initialized != 1 || (dev_no >= grspw_count))
+ return NULL;
+
+ priv = priv_tab[dev_no];
+
+ /* Take GRSPW lock - Wait until we get semaphore */
+ if (rtems_semaphore_obtain(grspw_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT)
+ != RTEMS_SUCCESSFUL)
+ return NULL;
+
+ if (priv->open) {
+ priv = NULL;
+ goto out;
+ }
+
+ /* Initialize Spin-lock for GRSPW Device. This is to protect
+ * CTRL and DMACTRL registers from ISR.
+ */
+ SPIN_INIT(&priv->devlock);
+
+ priv->tcisr = NULL;
+ priv->tcisr_arg = NULL;
+
+ grspw_stats_clr(priv);
+
+ /* Allocate TX & RX Descriptor memory area for all DMA
+ * channels. Max-size descriptor area is allocated (or user assigned):
+ * - 128 RX descriptors per DMA Channel
+ * - 64 TX descriptors per DMA Channel
+ */
+ value = drvmgr_dev_key_get(priv->dev, "bdDmaArea", KEY_TYPE_INT);
+ if (value) {
+ priv->bd_mem = value->i;
+ priv->bd_mem_alloced = 0;
+ if (priv->bd_mem & (BDTAB_ALIGN-1)) {
+ GRSPW_DBG("GRSPW[%d]: user-def DMA-area not aligned",
+ priv->index);
+ priv = NULL;
+ goto out;
+ }
+ } else {
+ bdtabsize = 2 * BDTAB_SIZE * priv->hwsup.ndma_chans;
+ priv->bd_mem_alloced = (unsigned int)malloc(bdtabsize + BDTAB_ALIGN - 1);
+ if (priv->bd_mem_alloced == 0) {
+ priv = NULL;
+ goto out;
+ }
+ /* Align memory */
+ priv->bd_mem = (priv->bd_mem_alloced + (BDTAB_ALIGN - 1)) &
+ ~(BDTAB_ALIGN-1);
+ }
+
+ /* Translate into DMA address that HW can use to access DMA
+ * descriptors
+ */
+ drvmgr_translate(priv->dev, 0, 0, (void *)priv->bd_mem, (void **)&hwa);
+
+ GRSPW_DBG("GRSPW%d DMA descriptor table setup: (alloced:%p, bd_mem:%p, size: %d)\n",
+ priv->index, priv->bd_mem_alloced, priv->bd_mem, bdtabsize + BDTAB_ALIGN - 1);
+ for (i=0; i<priv->hwsup.ndma_chans; i++) {
+ /* Do DMA Channel Init, other variables etc. are inited
+ * when respective DMA channel is opened.
+ *
+ * index & core are initialized by probe function.
+ */
+ priv->dma[i].open = 0;
+ priv->dma[i].rx_bds = (struct grspw_rxbd *)
+ (priv->bd_mem + i*BDTAB_SIZE*2);
+ priv->dma[i].rx_bds_hwa = (struct grspw_rxbd *)
+ (hwa + BDTAB_SIZE*(2*i));
+ priv->dma[i].tx_bds = (struct grspw_txbd *)
+ (priv->bd_mem + BDTAB_SIZE*(2*i+1));
+ priv->dma[i].tx_bds_hwa = (struct grspw_txbd *)
+ (hwa + BDTAB_SIZE*(2*i+1));
+ GRSPW_DBG(" DMA[%i]: RX %p - %p (%p - %p) TX %p - %p (%p - %p)\n",
+ i,
+ priv->dma[i].rx_bds, (void *)priv->dma[i].rx_bds + BDTAB_SIZE - 1,
+ priv->dma[i].rx_bds_hwa, (void *)priv->dma[i].rx_bds_hwa + BDTAB_SIZE - 1,
+ priv->dma[i].tx_bds, (void *)priv->dma[i].tx_bds + BDTAB_SIZE - 1,
+ priv->dma[i].tx_bds_hwa, (void *)priv->dma[i].tx_bds_hwa + BDTAB_SIZE - 1);
+ }
+
+ /* Basic initialization of hardware, clear some registers but
+ * keep Link/RMAP/Node-Address registers intact.
+ */
+ grspw_hw_stop(priv);
+
+ /* Register Interrupt handler and enable IRQ at IRQ ctrl */
+ drvmgr_interrupt_register(priv->dev, 0, priv->devname, grspw_isr, priv);
+
+ /* Take the device */
+ priv->open = 1;
+out:
+ rtems_semaphore_release(grspw_sem);
+ return priv;
+}
+
+void grspw_close(void *d)
+{
+ struct grspw_priv *priv = d;
+ int i;
+
+ /* Take GRSPW lock - Wait until we get semaphore */
+ if (rtems_semaphore_obtain(grspw_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT)
+ != RTEMS_SUCCESSFUL)
+ return;
+
+ /* Stop Hardware from doing DMA, put HW into "startup-state",
+ * Stop hardware from generating IRQ.
+ */
+ for (i=0; i<priv->hwsup.ndma_chans; i++)
+ grspw_dma_close(&priv->dma[i]);
+ grspw_hw_stop(priv);
+
+ /* Mark not open */
+ priv->open = 0;
+
+ rtems_semaphore_release(grspw_sem);
+
+ /* Check that all threads are out? */
+}
+
+void grspw_hw_support(void *d, struct grspw_hw_sup *hw)
+{
+ struct grspw_priv *priv = d;
+
+ *hw = priv->hwsup;
+}
+
+void grspw_addr_ctrl(void *d, struct grspw_addr_config *cfg)
+{
+ struct grspw_priv *priv = d;
+ struct grspw_regs *regs = priv->regs;
+ unsigned int ctrl, nodeaddr;
+ IRQFLAGS_TYPE irqflags;
+ int i;
+
+ if (!priv || !cfg)
+ return;
+
+ SPIN_LOCK_IRQ(&priv->devlock, irqflags);
+
+ if (cfg->promiscuous != -1) {
+ /* Set Configuration */
+ ctrl = REG_READ(&regs->ctrl);
+ if (cfg->promiscuous)
+ ctrl |= GRSPW_CTRL_PM;
+ else
+ ctrl &= ~GRSPW_CTRL_PM;
+ REG_WRITE(&regs->ctrl, ctrl);
+ REG_WRITE(&regs->nodeaddr, (cfg->def_mask<<8) | cfg->def_addr);
+
+ for (i=0; i<priv->hwsup.ndma_chans; i++) {
+ ctrl = REG_READ(&regs->dma[i].ctrl);
+ ctrl &= ~(GRSPW_DMACTRL_PS|GRSPW_DMACTRL_PR|GRSPW_DMA_STATUS_ERROR);
+ if (cfg->dma_nacfg[i].node_en) {
+ ctrl |= GRSPW_DMACTRL_EN;
+ REG_WRITE(&regs->dma[i].addr,
+ (cfg->dma_nacfg[i].node_addr & 0xff) |
+ ((cfg->dma_nacfg[i].node_mask & 0xff)<<8));
+ } else {
+ ctrl &= ~GRSPW_DMACTRL_EN;
+ }
+ REG_WRITE(&regs->dma[i].ctrl, ctrl);
+ }
+ }
+
+ /* Read Current Configuration */
+ cfg->promiscuous = REG_READ(&regs->ctrl) & GRSPW_CTRL_PM;
+ nodeaddr = REG_READ(&regs->nodeaddr);
+ cfg->def_addr = (nodeaddr & GRSPW_DEF_ADDR) >> GRSPW_DEF_ADDR_BIT;
+ cfg->def_mask = (nodeaddr & GRSPW_DEF_MASK) >> GRSPW_DEF_MASK_BIT;
+ for (i=0; i<priv->hwsup.ndma_chans; i++) {
+ cfg->dma_nacfg[i].node_en = REG_READ(&regs->dma[i].ctrl) &
+ GRSPW_DMACTRL_EN;
+ ctrl = REG_READ(&regs->dma[i].addr);
+ cfg->dma_nacfg[i].node_addr = (ctrl & GRSPW_DMAADR_ADDR) >>
+ GRSPW_DMAADR_ADDR_BIT;
+ cfg->dma_nacfg[i].node_mask = (ctrl & GRSPW_DMAADR_MASK) >>
+ GRSPW_DMAADR_MASK_BIT;
+ }
+ SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
+ for (; i<4; i++) {
+ cfg->dma_nacfg[i].node_en = 0;
+ cfg->dma_nacfg[i].node_addr = 0;
+ cfg->dma_nacfg[i].node_mask = 0;
+ }
+}
+
+/* Return Current Status Register */
+unsigned int grspw_link_status(void *d)
+{
+ struct grspw_priv *priv = d;
+
+ return REG_READ(&priv->regs->status);
+}
+
+/* Return Current Link State */
+spw_link_state_t grspw_link_state(void *d)
+{
+ struct grspw_priv *priv = d;
+ unsigned int status = REG_READ(&priv->regs->status);
+
+ return (status & GRSPW_STS_LS) >> GRSPW_STS_LS_BIT;
+}
+
+/* options and clkdiv [in/out]: set to -1 to only read current config */
+void grspw_link_ctrl(void *d, int *options, int *clkdiv)
+{
+ struct grspw_priv *priv = d;
+ struct grspw_regs *regs = priv->regs;
+ unsigned int ctrl;
+ IRQFLAGS_TYPE irqflags;
+
+ /* Write? */
+ if (clkdiv) {
+ if (*clkdiv != -1)
+ REG_WRITE(&regs->clkdiv, *clkdiv & GRSPW_CLKDIV_MASK);
+ *clkdiv = REG_READ(&regs->clkdiv) & GRSPW_CLKDIV_MASK;
+ }
+ if (options) {
+ SPIN_LOCK_IRQ(&priv->devlock, irqflags);
+ ctrl = REG_READ(&regs->ctrl);
+ if (*options != -1) {
+ ctrl = (ctrl & ~GRSPW_LINK_CFG) |
+ (*options & GRSPW_LINK_CFG);
+
+ /* Enable Global IRQ only of LI or TQ is set */
+ if (ctrl & (GRSPW_CTRL_LI|GRSPW_CTRL_TQ))
+ ctrl |= GRSPW_CTRL_IE;
+ else
+ ctrl &= ~GRSPW_CTRL_IE;
+
+ REG_WRITE(&regs->ctrl, ctrl);
+ priv->dis_link_on_err = (*options & LINKOPTS_DIS_ONERR) >> 3;
+ }
+ SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
+ *options = (ctrl & GRSPW_LINK_CFG)|(priv->dis_link_on_err << 3);
+ }
+}
+
+/* Generate Tick-In (increment Time Counter, Send Time Code) */
+void grspw_tc_tx(void *d)
+{
+ struct grspw_priv *priv = d;
+ struct grspw_regs *regs = priv->regs;
+ IRQFLAGS_TYPE irqflags;
+
+ SPIN_LOCK_IRQ(&priv->devlock, irqflags);
+ REG_WRITE(&regs->ctrl, REG_READ(&regs->ctrl) | GRSPW_CTRL_TI);
+ SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
+}
+
+void grspw_tc_ctrl(void *d, int *options)
+{
+ struct grspw_priv *priv = d;
+ struct grspw_regs *regs = priv->regs;
+ unsigned int ctrl;
+ IRQFLAGS_TYPE irqflags;
+
+ if (options == NULL)
+ return;
+
+ /* Write? */
+ if (*options != -1) {
+ SPIN_LOCK_IRQ(&priv->devlock, irqflags);
+ ctrl = REG_READ(&regs->ctrl);
+ ctrl &= ~(GRSPW_CTRL_TR|GRSPW_CTRL_TT|GRSPW_CTRL_TQ);
+ ctrl |= (*options & 0xd) << GRSPW_CTRL_TQ_BIT;
+
+ /* Enable Global IRQ only of LI or TQ is set */
+ if (ctrl & (GRSPW_CTRL_LI|GRSPW_CTRL_TQ))
+ ctrl |= GRSPW_CTRL_IE;
+ else
+ ctrl &= ~GRSPW_CTRL_IE;
+
+ REG_WRITE(&regs->ctrl, ctrl);
+ SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
+ } else
+ ctrl = REG_READ(&regs->ctrl);
+ *options = (ctrl >> GRSPW_CTRL_TQ_BIT) & 0xd;
+}
+
+/* Assign ISR Function to TimeCode RX IRQ */
+void grspw_tc_isr(void *d, void (*tcisr)(void *data, int tc), void *data)
+{
+ struct grspw_priv *priv = d;
+
+ priv->tcisr_arg = data;
+ priv->tcisr = tcisr;
+}
+
+/* Read/Write TCTRL and TIMECNT. Write if not -1, always read current value
+ * TCTRL = bits 7 and 6
+ * TIMECNT = bits 5 to 0
+ */
+void grspw_tc_time(void *d, int *time)
+{
+ struct grspw_priv *priv = d;
+ struct grspw_regs *regs = priv->regs;
+
+ if (time == NULL)
+ return;
+ if (*time != -1)
+ REG_WRITE(&regs->time, *time & (GRSPW_TIME_TCNT | GRSPW_TIME_CTRL));
+ *time = REG_READ(&regs->time) & (GRSPW_TIME_TCNT | GRSPW_TIME_CTRL);
+}
+
+/* Set (not -1) and/or read RMAP options. */
+int grspw_rmap_ctrl(void *d, int *options, int *dstkey)
+{
+ struct grspw_priv *priv = d;
+ struct grspw_regs *regs = priv->regs;
+ unsigned int ctrl;
+ IRQFLAGS_TYPE irqflags;
+
+ if (dstkey) {
+ if (*dstkey != -1)
+ REG_WRITE(&regs->destkey, *dstkey & GRSPW_DK_DESTKEY);
+ *dstkey = REG_READ(&regs->destkey) & GRSPW_DK_DESTKEY;
+ }
+ if (options) {
+ if (*options != -1) {
+ if ((*options & RMAPOPTS_EN_RMAP) && !priv->hwsup.rmap)
+ return -1;
+
+
+ SPIN_LOCK_IRQ(&priv->devlock, irqflags);
+ ctrl = REG_READ(&regs->ctrl);
+ ctrl &= ~(GRSPW_CTRL_RE|GRSPW_CTRL_RD);
+ ctrl |= (*options & 0x3) << GRSPW_CTRL_RE_BIT;
+ REG_WRITE(&regs->ctrl, ctrl);
+ SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
+ }
+ *options = (REG_READ(&regs->ctrl) >> GRSPW_CTRL_RE_BIT) & 0x3;
+ }
+
+ return 0;
+}
+
+void grspw_rmap_support(void *d, char *rmap, char *rmap_crc)
+{
+ struct grspw_priv *priv = d;
+
+ if (rmap)
+ *rmap = priv->hwsup.rmap;
+ if (rmap_crc)
+ *rmap_crc = priv->hwsup.rmap_crc;
+}
+
+/* Select port, if
+ * -1=The current selected port is returned
+ * 0=Port 0
+ * 1=Port 1
+ * Others=Both Port0 and Port1
+ */
+int grspw_port_ctrl(void *d, int *port)
+{
+ struct grspw_priv *priv = d;
+ struct grspw_regs *regs = priv->regs;
+ unsigned int ctrl;
+ IRQFLAGS_TYPE irqflags;
+
+ if (port == NULL)
+ return -1;
+
+ if ((*port == 1) || (*port == 0)) {
+ /* Select port user selected */
+ if ((*port == 1) && (priv->hwsup.nports < 2))
+ return -1; /* Changing to Port 1, but only one port available */
+ SPIN_LOCK_IRQ(&priv->devlock, irqflags);
+ ctrl = REG_READ(&regs->ctrl);
+ ctrl &= ~(GRSPW_CTRL_NP | GRSPW_CTRL_PS);
+ ctrl |= (*port & 1) << GRSPW_CTRL_PS_BIT;
+ REG_WRITE(&regs->ctrl, ctrl);
+ SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
+ } else if (*port > 1) {
+ /* Select both ports */
+ SPIN_LOCK_IRQ(&priv->devlock, irqflags);
+ REG_WRITE(&regs->ctrl, REG_READ(&regs->ctrl) | GRSPW_CTRL_NP);
+ SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
+ }
+
+ /* Get current settings */
+ ctrl = REG_READ(&regs->ctrl);
+ if (ctrl & GRSPW_CTRL_NP) {
+ /* Any port, selected by hardware */
+ if (priv->hwsup.nports > 1)
+ *port = 3;
+ else
+ *port = 0; /* Port0 the only port available */
+ } else {
+ *port = (ctrl & GRSPW_CTRL_PS) >> GRSPW_CTRL_PS_BIT;
+ }
+
+ return 0;
+}
+
+/* Returns Number ports available in hardware */
+int grspw_port_count(void *d)
+{
+ struct grspw_priv *priv = d;
+
+ return priv->hwsup.nports;
+}
+
+/* Current active port: 0 or 1 */
+int grspw_port_active(void *d)
+{
+ struct grspw_priv *priv = d;
+ unsigned int status;
+
+ status = REG_READ(&priv->regs->status);
+
+ return (status & GRSPW_STS_AP) >> GRSPW_STS_AP_BIT;
+}
+
+void grspw_stats_read(void *d, struct grspw_core_stats *sts)
+{
+ struct grspw_priv *priv = d;
+
+ if (sts == NULL)
+ return;
+ memcpy(sts, &priv->stats, sizeof(priv->stats));
+}
+
+void grspw_stats_clr(void *d)
+{
+ struct grspw_priv *priv = d;
+
+ /* Clear most of the statistics */
+ memset(&priv->stats, 0, sizeof(priv->stats));
+}
+
+/*** DMA Interface ***/
+
+/* Initialize the RX and TX Descriptor Ring, empty of packets */
+STATIC void grspw_bdrings_init(struct grspw_dma_priv *dma)
+{
+ struct grspw_ring *r;
+ int i;
+
+ /* Empty BD rings */
+ dma->rx_ring_head = dma->rx_ring_base;
+ dma->rx_ring_tail = dma->rx_ring_base;
+ dma->tx_ring_head = dma->tx_ring_base;
+ dma->tx_ring_tail = dma->tx_ring_base;
+
+ /* Init RX Descriptors */
+ r = (struct grspw_ring *)dma->rx_ring_base;
+ for (i=0; i<GRSPW_RXBD_NR; i++) {
+
+ /* Init Ring Entry */
+ r[i].next = &r[i+1];
+ r[i].bd.rx = &dma->rx_bds[i];
+ r[i].pkt = NULL;
+
+ /* Init HW Descriptor */
+ BD_WRITE(&r[i].bd.rx->ctrl, 0);
+ BD_WRITE(&r[i].bd.rx->addr, 0);
+ }
+ r[GRSPW_RXBD_NR-1].next = &r[0];
+
+ /* Init TX Descriptors */
+ r = (struct grspw_ring *)dma->tx_ring_base;
+ for (i=0; i<GRSPW_TXBD_NR; i++) {
+
+ /* Init Ring Entry */
+ r[i].next = &r[i+1];
+ r[i].bd.tx = &dma->tx_bds[i];
+ r[i].pkt = NULL;
+
+ /* Init HW Descriptor */
+ BD_WRITE(&r[i].bd.tx->ctrl, 0);
+ BD_WRITE(&r[i].bd.tx->haddr, 0);
+ BD_WRITE(&r[i].bd.tx->dlen, 0);
+ BD_WRITE(&r[i].bd.tx->daddr, 0);
+ }
+ r[GRSPW_TXBD_NR-1].next = &r[0];
+}
+
+/* Try to populate descriptor ring with as many as possible READY unused packet
+ * buffers. The packets assigned with to a descriptor are put in the end of
+ * the scheduled list.
+ *
+ * The number of Packets scheduled is returned.
+ *
+ * - READY List -> RX-SCHED List
+ * - Descriptors are initialized and enabled for reception
+ */
+STATIC int grspw_rx_schedule_ready(struct grspw_dma_priv *dma)
+{
+ int cnt;
+ unsigned int ctrl, dmactrl;
+ void *hwaddr;
+ struct grspw_rxring *curr_bd;
+ struct grspw_pkt *curr_pkt, *last_pkt;
+ struct grspw_list lst;
+ IRQFLAGS_TYPE irqflags;
+
+ /* Is Ready Q empty? */
+ if (grspw_list_is_empty(&dma->ready))
+ return 0;
+
+ cnt = 0;
+ lst.head = curr_pkt = dma->ready.head;
+ curr_bd = dma->rx_ring_head;
+ while (!curr_bd->pkt) {
+
+ /* Assign Packet to descriptor */
+ curr_bd->pkt = curr_pkt;
+
+ /* Prepare descriptor address. */
+ hwaddr = curr_pkt->data;
+ if (curr_pkt->flags & PKT_FLAG_TR_DATA) {
+ drvmgr_translate(dma->core->dev, 0, 0, hwaddr, &hwaddr);
+ if (curr_pkt->data == hwaddr) /* translation needed? */
+ curr_pkt->flags &= ~PKT_FLAG_TR_DATA;
+ }
+ BD_WRITE(&curr_bd->bd->addr, hwaddr);
+
+ ctrl = GRSPW_RXBD_EN;
+ if (curr_bd->next == dma->rx_ring_base) {
+ /* Wrap around (only needed when smaller descriptor
+ * table)
+ */
+ ctrl |= GRSPW_RXBD_WR;
+ }
+
+ /* Is this Packet going to be an interrupt Packet? */
+ if ((--dma->rx_irq_en_cnt_curr) <= 0) {
+ if (dma->cfg.rx_irq_en_cnt == 0) {
+ /* IRQ is disabled. A big number to avoid
+ * equal to zero too often
+ */
+ dma->rx_irq_en_cnt_curr = 0x3fffffff;
+ } else {
+ dma->rx_irq_en_cnt_curr = dma->cfg.rx_irq_en_cnt;
+ ctrl |= GRSPW_RXBD_IE;
+ }
+ }
+
+ if (curr_pkt->flags & RXPKT_FLAG_IE)
+ ctrl |= GRSPW_RXBD_IE;
+
+ /* Enable descriptor */
+ BD_WRITE(&curr_bd->bd->ctrl, ctrl);
+
+ last_pkt = curr_pkt;
+ curr_bd = curr_bd->next;
+ cnt++;
+
+ /* Get Next Packet from Ready Queue */
+ if (curr_pkt == dma->ready.tail) {
+ /* Handled all in ready queue. */
+ curr_pkt = NULL;
+ break;
+ }
+ curr_pkt = curr_pkt->next;
+ }
+
+ /* Has Packets been scheduled? */
+ if (cnt > 0) {
+ /* Prepare list for insertion/deleation */
+ lst.tail = last_pkt;
+
+ /* Remove scheduled packets from ready queue */
+ grspw_list_remove_head_list(&dma->ready, &lst);
+ dma->ready_cnt -= cnt;
+ if (dma->stats.ready_cnt_min > dma->ready_cnt)
+ dma->stats.ready_cnt_min = dma->ready_cnt;
+
+ /* Insert scheduled packets into scheduled queue */
+ grspw_list_append_list(&dma->rx_sched, &lst);
+ dma->rx_sched_cnt += cnt;
+ if (dma->stats.rx_sched_cnt_max < dma->rx_sched_cnt)
+ dma->stats.rx_sched_cnt_max = dma->rx_sched_cnt;
+
+ /* Update TX ring posistion */
+ dma->rx_ring_head = curr_bd;
+
+ /* Make hardware aware of the newly enabled descriptors
+ * We must protect from ISR which writes RI|TI
+ */
+ SPIN_LOCK_IRQ(&dma->core->devlock, irqflags);
+ dmactrl = REG_READ(&dma->regs->ctrl);
+ dmactrl &= ~(GRSPW_DMACTRL_PS|GRSPW_DMACTRL_PR|GRSPW_DMA_STATUS_ERROR);
+ dmactrl |= GRSPW_DMACTRL_RE | GRSPW_DMACTRL_RD;
+ REG_WRITE(&dma->regs->ctrl, dmactrl);
+ SPIN_UNLOCK_IRQ(&dma->core->devlock, irqflags);
+ }
+
+ return cnt;
+}
+
+/* Scans the RX desciptor table for scheduled Packet that has been received,
+ * and moves these Packet from the head of the scheduled queue to the
+ * tail of the recv queue.
+ *
+ * Also, for all packets the status is updated.
+ *
+ * - SCHED List -> SENT List
+ *
+ * Return Value
+ * Number of packets moved
+ */
+STATIC int grspw_rx_process_scheduled(struct grspw_dma_priv *dma)
+{
+ struct grspw_rxring *curr;
+ struct grspw_pkt *last_pkt;
+ int recv_pkt_cnt = 0;
+ unsigned int ctrl;
+ struct grspw_list lst;
+
+ curr = dma->rx_ring_tail;
+
+ /* Step into RX ring to find if packets have been scheduled for
+ * reception.
+ */
+ if (!curr->pkt)
+ return 0; /* No scheduled packets, thus no received, abort */
+
+ /* There has been Packets scheduled ==> scheduled Packets may have been
+ * received and needs to be collected into RECV List.
+ *
+ * A temporary list "lst" with all received packets is created.
+ */
+ lst.head = curr->pkt;
+
+ /* Loop until first enabled "unrecveived" SpW Packet is found.
+ * An unused descriptor is indicated by an unassigned pkt field.
+ */
+ while (curr->pkt && !((ctrl=BD_READ(&curr->bd->ctrl)) & GRSPW_RXBD_EN)) {
+ /* Handle one received Packet */
+
+ /* Remember last handled Packet so that insertion/removal from
+ * Packet lists go fast.
+ */
+ last_pkt = curr->pkt;
+
+ /* Get Length of Packet in bytes, and reception options */
+ last_pkt->dlen = (ctrl & GRSPW_RXBD_LEN) >> GRSPW_RXBD_LEN_BIT;
+
+ /* Set flags to indicate error(s) and CRC information,
+ * and Mark Received.
+ */
+ last_pkt->flags = (last_pkt->flags & ~RXPKT_FLAG_OUTPUT_MASK) |
+ ((ctrl >> 20) & RXPKT_FLAG_OUTPUT_MASK) |
+ RXPKT_FLAG_RX;
+
+ /* Packet was Truncated? */
+ if (ctrl & GRSPW_RXBD_TR)
+ dma->stats.rx_err_trunk++;
+
+ /* Error End-Of-Packet? */
+ if (ctrl & GRSPW_RXBD_EP)
+ dma->stats.rx_err_endpkt++;
+ curr->pkt = NULL; /* Mark descriptor unused */
+
+ /* Increment */
+ curr = curr->next;
+ recv_pkt_cnt++;
+ }
+
+ /* 1. Remove all handled packets from scheduled queue
+ * 2. Put all handled packets into recv queue
+ */
+ if (recv_pkt_cnt > 0) {
+
+ /* Update Stats, Number of Received Packets */
+ dma->stats.rx_pkts += recv_pkt_cnt;
+
+ /* Save RX ring posistion */
+ dma->rx_ring_tail = curr;
+
+ /* Prepare list for insertion/deleation */
+ lst.tail = last_pkt;
+
+ /* Remove received Packets from RX-SCHED queue */
+ grspw_list_remove_head_list(&dma->rx_sched, &lst);
+ dma->rx_sched_cnt -= recv_pkt_cnt;
+ if (dma->stats.rx_sched_cnt_min > dma->rx_sched_cnt)
+ dma->stats.rx_sched_cnt_min = dma->rx_sched_cnt;
+
+ /* Insert received Packets into RECV queue */
+ grspw_list_append_list(&dma->recv, &lst);
+ dma->recv_cnt += recv_pkt_cnt;
+ if (dma->stats.recv_cnt_max < dma->recv_cnt)
+ dma->stats.recv_cnt_max = dma->recv_cnt;
+ }
+
+ return recv_pkt_cnt;
+}
+
+/* Try to populate descriptor ring with as many SEND packets as possible. The
+ * packets assigned with to a descriptor are put in the end of
+ * the scheduled list.
+ *
+ * The number of Packets scheduled is returned.
+ *
+ * - SEND List -> TX-SCHED List
+ * - Descriptors are initialized and enabled for transmission
+ */
+STATIC int grspw_tx_schedule_send(struct grspw_dma_priv *dma)
+{
+ int cnt;
+ unsigned int ctrl, dmactrl;
+ void *hwaddr;
+ struct grspw_txring *curr_bd;
+ struct grspw_pkt *curr_pkt, *last_pkt;
+ struct grspw_list lst;
+ IRQFLAGS_TYPE irqflags;
+
+ /* Is Ready Q empty? */
+ if (grspw_list_is_empty(&dma->send))
+ return 0;
+
+ cnt = 0;
+ lst.head = curr_pkt = dma->send.head;
+ curr_bd = dma->tx_ring_head;
+ while (!curr_bd->pkt) {
+
+ /* Assign Packet to descriptor */
+ curr_bd->pkt = curr_pkt;
+
+ /* Set up header transmission */
+ if (curr_pkt->hdr && curr_pkt->hlen) {
+ hwaddr = curr_pkt->hdr;
+ if (curr_pkt->flags & PKT_FLAG_TR_HDR) {
+ drvmgr_translate(dma->core->dev, 0, 0, hwaddr, &hwaddr);
+ /* translation needed? */
+ if (curr_pkt->hdr == hwaddr)
+ curr_pkt->flags &= ~PKT_FLAG_TR_HDR;
+ }
+ BD_WRITE(&curr_bd->bd->haddr, hwaddr);
+ ctrl = GRSPW_TXBD_EN | curr_pkt->hlen;
+ } else {
+ ctrl = GRSPW_TXBD_EN;
+ }
+ /* Enable IRQ generation and CRC options as specified
+ * by user.
+ */
+ ctrl |= (curr_pkt->flags & TXPKT_FLAG_INPUT_MASK) << 8;
+
+ if (curr_bd->next == dma->tx_ring_base) {
+ /* Wrap around (only needed when smaller descriptor table) */
+ ctrl |= GRSPW_TXBD_WR;
+ }
+
+ /* Is this Packet going to be an interrupt Packet? */
+ if ((--dma->tx_irq_en_cnt_curr) <= 0) {
+ if (dma->cfg.tx_irq_en_cnt == 0) {
+ /* IRQ is disabled.
+ * A big number to avoid equal to zero too often
+ */
+ dma->tx_irq_en_cnt_curr = 0x3fffffff;
+ } else {
+ dma->tx_irq_en_cnt_curr = dma->cfg.tx_irq_en_cnt;
+ ctrl |= GRSPW_TXBD_IE;
+ }
+ }
+
+ /* Prepare descriptor address. Parts of CTRL is written to
+ * DLEN for debug-only (CTRL is cleared by HW).
+ */
+ if (curr_pkt->data && curr_pkt->dlen) {
+ hwaddr = curr_pkt->data;
+ if (curr_pkt->flags & PKT_FLAG_TR_DATA) {
+ drvmgr_translate(dma->core->dev, 0, 0, hwaddr, &hwaddr);
+ /* translation needed? */
+ if (curr_pkt->data == hwaddr)
+ curr_pkt->flags &= ~PKT_FLAG_TR_DATA;
+ }
+ BD_WRITE(&curr_bd->bd->daddr, hwaddr);
+ BD_WRITE(&curr_bd->bd->dlen, curr_pkt->dlen |
+ ((ctrl & 0x3f000) << 12));
+ } else {
+ BD_WRITE(&curr_bd->bd->daddr, 0);
+ BD_WRITE(&curr_bd->bd->dlen, ((ctrl & 0x3f000) << 12));
+ }
+
+ /* Enable descriptor */
+ BD_WRITE(&curr_bd->bd->ctrl, ctrl);
+
+ last_pkt = curr_pkt;
+ curr_bd = curr_bd->next;
+ cnt++;
+
+ /* Get Next Packet from Ready Queue */
+ if (curr_pkt == dma->send.tail) {
+ /* Handled all in ready queue. */
+ curr_pkt = NULL;
+ break;
+ }
+ curr_pkt = curr_pkt->next;
+ }
+
+ /* Have Packets been scheduled? */
+ if (cnt > 0) {
+ /* Prepare list for insertion/deleation */
+ lst.tail = last_pkt;
+
+ /* Remove scheduled packets from ready queue */
+ grspw_list_remove_head_list(&dma->send, &lst);
+ dma->send_cnt -= cnt;
+ if (dma->stats.send_cnt_min > dma->send_cnt)
+ dma->stats.send_cnt_min = dma->send_cnt;
+
+ /* Insert scheduled packets into scheduled queue */
+ grspw_list_append_list(&dma->tx_sched, &lst);
+ dma->tx_sched_cnt += cnt;
+ if (dma->stats.tx_sched_cnt_max < dma->tx_sched_cnt)
+ dma->stats.tx_sched_cnt_max = dma->tx_sched_cnt;
+
+ /* Update TX ring posistion */
+ dma->tx_ring_head = curr_bd;
+
+ /* Make hardware aware of the newly enabled descriptors */
+ SPIN_LOCK_IRQ(&dma->core->devlock, irqflags);
+ dmactrl = REG_READ(&dma->regs->ctrl);
+ dmactrl &= ~(GRSPW_DMACTRL_PS|GRSPW_DMACTRL_PR|GRSPW_DMA_STATUS_ERROR);
+ dmactrl |= GRSPW_DMACTRL_TE;
+ REG_WRITE(&dma->regs->ctrl, dmactrl);
+ SPIN_UNLOCK_IRQ(&dma->core->devlock, irqflags);
+ }
+ return cnt;
+}
+
+/* Scans the TX desciptor table for transmitted packets, and moves these
+ * packets from the head of the scheduled queue to the tail of the sent queue.
+ *
+ * Also, for all packets the status is updated.
+ *
+ * - SCHED List -> SENT List
+ *
+ * Return Value
+ * Number of packet moved
+ */
+STATIC int grspw_tx_process_scheduled(struct grspw_dma_priv *dma)
+{
+ struct grspw_txring *curr;
+ struct grspw_pkt *last_pkt;
+ int sent_pkt_cnt = 0;
+ unsigned int ctrl;
+ struct grspw_list lst;
+
+ curr = dma->tx_ring_tail;
+
+ /* Step into TX ring to find if packets have been scheduled for
+ * transmission.
+ */
+ if (!curr->pkt)
+ return 0; /* No scheduled packets, thus no sent, abort */
+
+ /* There has been Packets scheduled ==> scheduled Packets may have been
+ * transmitted and needs to be collected into SENT List.
+ *
+ * A temporary list "lst" with all sent packets is created.
+ */
+ lst.head = curr->pkt;
+
+ /* Loop until first enabled "un-transmitted" SpW Packet is found.
+ * An unused descriptor is indicated by an unassigned pkt field.
+ */
+ while (curr->pkt && !((ctrl=BD_READ(&curr->bd->ctrl)) & GRSPW_TXBD_EN)) {
+ /* Handle one sent Packet */
+
+ /* Remember last handled Packet so that insertion/removal from
+ * packet lists go fast.
+ */
+ last_pkt = curr->pkt;
+
+ /* Set flags to indicate error(s) and Mark Sent.
+ */
+ last_pkt->flags = (last_pkt->flags & ~TXPKT_FLAG_OUTPUT_MASK) |
+ (ctrl & TXPKT_FLAG_LINKERR) |
+ TXPKT_FLAG_TX;
+
+ /* Sent packet experienced link error? */
+ if (ctrl & GRSPW_TXBD_LE)
+ dma->stats.tx_err_link++;
+
+ curr->pkt = NULL; /* Mark descriptor unused */
+
+ /* Increment */
+ curr = curr->next;
+ sent_pkt_cnt++;
+ }
+
+ /* 1. Remove all handled packets from TX-SCHED queue
+ * 2. Put all handled packets into SENT queue
+ */
+ if (sent_pkt_cnt > 0) {
+ /* Update Stats, Number of Transmitted Packets */
+ dma->stats.tx_pkts += sent_pkt_cnt;
+
+ /* Save TX ring posistion */
+ dma->tx_ring_tail = curr;
+
+ /* Prepare list for insertion/deleation */
+ lst.tail = last_pkt;
+
+ /* Remove sent packets from TX-SCHED queue */
+ grspw_list_remove_head_list(&dma->tx_sched, &lst);
+ dma->tx_sched_cnt -= sent_pkt_cnt;
+ if (dma->stats.tx_sched_cnt_min > dma->tx_sched_cnt)
+ dma->stats.tx_sched_cnt_min = dma->tx_sched_cnt;
+
+ /* Insert received packets into SENT queue */
+ grspw_list_append_list(&dma->sent, &lst);
+ dma->sent_cnt += sent_pkt_cnt;
+ if (dma->stats.sent_cnt_max < dma->sent_cnt)
+ dma->stats.sent_cnt_max = dma->sent_cnt;
+ }
+
+ return sent_pkt_cnt;
+}
+
+void *grspw_dma_open(void *d, int chan_no)
+{
+ struct grspw_priv *priv = d;
+ struct grspw_dma_priv *dma;
+ int size;
+
+ if ((chan_no < 0) && (priv->hwsup.ndma_chans <= chan_no))
+ return NULL;
+
+ dma = &priv->dma[chan_no];
+
+ /* Take GRSPW lock */
+ if (rtems_semaphore_obtain(grspw_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT)
+ != RTEMS_SUCCESSFUL)
+ return NULL;
+
+ if (dma->open) {
+ dma = NULL;
+ goto out;
+ }
+
+ dma->started = 0;
+
+ /* Set Default Configuration:
+ *
+ * - MAX RX Packet Length =
+ * - Disable IRQ generation
+ * -
+ */
+ dma->cfg.rxmaxlen = DEFAULT_RXMAX;
+ dma->cfg.rx_irq_en_cnt = 0;
+ dma->cfg.tx_irq_en_cnt = 0;
+ dma->cfg.flags = DMAFLAG_NO_SPILL;
+
+ /* DMA Channel Semaphore created with count = 1 */
+ if (rtems_semaphore_create(
+ rtems_build_name('S', 'D', '0' + priv->index, '0' + chan_no), 1,
+ RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | \
+ RTEMS_NO_INHERIT_PRIORITY | RTEMS_LOCAL | \
+ RTEMS_NO_PRIORITY_CEILING, 0, &dma->sem_dma) != RTEMS_SUCCESSFUL) {
+ dma = NULL;
+ goto out;
+ }
+
+ /* Allocate memory for the two descriptor rings */
+ size = sizeof(struct grspw_ring) * (GRSPW_RXBD_NR + GRSPW_TXBD_NR);
+ dma->rx_ring_base = (struct grspw_rxring *)malloc(size);
+ dma->tx_ring_base = (struct grspw_txring *)&dma->rx_ring_base[GRSPW_RXBD_NR];
+ if (dma->rx_ring_base == NULL) {
+ dma = NULL;
+ goto out;
+ }
+
+ /* Create DMA RX and TX Channel sempahore with count = 0 */
+ if (rtems_semaphore_create(
+ rtems_build_name('S', 'R', '0' + priv->index, '0' + chan_no), 0,
+ RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | \
+ RTEMS_NO_INHERIT_PRIORITY | RTEMS_LOCAL | \
+ RTEMS_NO_PRIORITY_CEILING, 0, &dma->rx_wait.sem_wait) != RTEMS_SUCCESSFUL) {
+ dma = NULL;
+ goto out;
+ }
+ if (rtems_semaphore_create(
+ rtems_build_name('S', 'T', '0' + priv->index, '0' + chan_no), 0,
+ RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | \
+ RTEMS_NO_INHERIT_PRIORITY | RTEMS_LOCAL | \
+ RTEMS_NO_PRIORITY_CEILING, 0, &dma->tx_wait.sem_wait) != RTEMS_SUCCESSFUL) {
+ dma = NULL;
+ goto out;
+ }
+
+ /* Reset software structures */
+ grspw_dma_reset(dma);
+
+ /* Take the device */
+ dma->open = 1;
+out:
+ /* Return GRSPW Lock */
+ rtems_semaphore_release(grspw_sem);
+
+ return dma;
+}
+
+/* Initialize Software Structures:
+ * - Clear all Queues
+ * - init BD ring
+ * - init IRQ counter
+ * - clear statistics counters
+ * - init wait structures and semaphores
+ */
+STATIC void grspw_dma_reset(struct grspw_dma_priv *dma)
+{
+ /* Empty RX and TX queues */
+ grspw_list_clr(&dma->ready);
+ grspw_list_clr(&dma->rx_sched);
+ grspw_list_clr(&dma->recv);
+ grspw_list_clr(&dma->send);
+ grspw_list_clr(&dma->tx_sched);
+ grspw_list_clr(&dma->sent);
+ dma->ready_cnt = 0;
+ dma->rx_sched_cnt = 0;
+ dma->recv_cnt = 0;
+ dma->send_cnt = 0;
+ dma->tx_sched_cnt = 0;
+ dma->sent_cnt = 0;
+
+ dma->rx_irq_en_cnt_curr = 0;
+ dma->tx_irq_en_cnt_curr = 0;
+
+ grspw_bdrings_init(dma);
+
+ dma->rx_wait.waiting = 0;
+ dma->tx_wait.waiting = 0;
+
+ grspw_dma_stats_clr(dma);
+}
+
+void grspw_dma_close(void *c)
+{
+ struct grspw_dma_priv *dma = c;
+
+ if (!dma->open)
+ return;
+
+ /* Take device lock - Wait until we get semaphore */
+ if (rtems_semaphore_obtain(dma->sem_dma, RTEMS_WAIT, RTEMS_NO_TIMEOUT)
+ != RTEMS_SUCCESSFUL)
+ return;
+
+ grspw_dma_stop_locked(dma);
+
+ /* Free resources */
+ rtems_semaphore_delete(dma->rx_wait.sem_wait);
+ rtems_semaphore_delete(dma->tx_wait.sem_wait);
+ rtems_semaphore_delete(dma->sem_dma); /* Release and delete lock */
+
+ /* Free memory */
+ if (dma->rx_ring_base)
+ free(dma->rx_ring_base);
+ dma->rx_ring_base = NULL;
+ dma->tx_ring_base = NULL;
+
+ dma->open = 0;
+}
+
+/* Schedule List of packets for transmission at some point in
+ * future.
+ *
+ * 1. Move transmitted packets to SENT List (SCHED->SENT)
+ * 2. Add the requested packets to the SEND List (USER->SEND)
+ * 3. Schedule as many packets as possible (SEND->SCHED)
+ */
+int grspw_dma_tx_send(void *c, int opts, struct grspw_list *pkts, int count)
+{
+ struct grspw_dma_priv *dma = c;
+ int ret;
+
+ /* Take DMA channel lock */
+ if (rtems_semaphore_obtain(dma->sem_dma, RTEMS_WAIT, RTEMS_NO_TIMEOUT)
+ != RTEMS_SUCCESSFUL)
+ return -1;
+
+ if (dma->started == 0) {
+ ret = 1; /* signal DMA has been stopped */
+ goto out;
+ }
+ ret = 0;
+
+ /* 1. Move transmitted packets to SENT List (SCHED->SENT) */
+ if ((opts & 1) == 0)
+ grspw_tx_process_scheduled(dma);
+
+ /* 2. Add the requested packets to the SEND List (USER->SEND) */
+ if (pkts) {
+ grspw_list_append_list(&dma->send, pkts);
+ dma->send_cnt += count;
+ if (dma->stats.send_cnt_max < dma->send_cnt)
+ dma->stats.send_cnt_max = dma->send_cnt;
+ }
+
+ /* 3. Schedule as many packets as possible (SEND->SCHED) */
+ if ((opts & 2) == 0)
+ grspw_tx_schedule_send(dma);
+
+out:
+ /* Unlock DMA channel */
+ rtems_semaphore_release(dma->sem_dma);
+
+ return ret;
+}
+
+int grspw_dma_tx_reclaim(void *c, int opts, struct grspw_list *pkts, int *count)
+{
+ struct grspw_dma_priv *dma = c;
+ struct grspw_pkt *pkt, *lastpkt;
+ int cnt, started;
+
+ /* Take DMA channel lock */
+ if (rtems_semaphore_obtain(dma->sem_dma, RTEMS_WAIT, RTEMS_NO_TIMEOUT)
+ != RTEMS_SUCCESSFUL)
+ return -1;
+
+ /* 1. Move transmitted packets to SENT List (SCHED->SENT) */
+ started = dma->started;
+ if ((started > 0) && ((opts & 1) == 0))
+ grspw_tx_process_scheduled(dma);
+
+ /* Move all/count SENT packet to the callers list (SENT->USER) */
+ if (pkts) {
+ if ((count == NULL) || (*count == -1) ||
+ (*count >= dma->sent_cnt)) {
+ /* Move all SENT Packets */
+ *pkts = dma->sent;
+ grspw_list_clr(&dma->sent);
+ if (count)
+ *count = dma->sent_cnt;
+ dma->sent_cnt = 0;
+ } else {
+ /* Move a number of SENT Packets */
+ pkts->head = pkt = lastpkt = dma->sent.head;
+ cnt = 0;
+ while (cnt < *count) {
+ lastpkt = pkt;
+ pkt = pkt->next;
+ cnt++;
+ }
+ if (cnt > 0) {
+ pkts->tail = lastpkt;
+ grspw_list_remove_head_list(&dma->sent, pkts);
+ dma->sent_cnt -= cnt;
+ } else {
+ grspw_list_clr(pkts);
+ }
+ }
+ } else if (count) {
+ *count = 0;
+ }
+
+ /* 3. Schedule as many packets as possible (SEND->SCHED) */
+ if ((started > 0 ) && ((opts & 2) == 0))
+ grspw_tx_schedule_send(dma);
+
+ /* Unlock DMA channel */
+ rtems_semaphore_release(dma->sem_dma);
+
+ return (~started) & 1; /* signal DMA has been stopped */
+}
+
+void grspw_dma_tx_count(void *c, int *send, int *sched, int *sent)
+{
+ struct grspw_dma_priv *dma = c;
+
+ if (send)
+ *send = dma->send_cnt;
+ if (sched)
+ *sched = dma->tx_sched_cnt;
+ if (sent)
+ *sent = dma->sent_cnt;
+}
+
+static inline int grspw_tx_wait_eval(struct grspw_dma_priv *dma)
+{
+ int send_val, sent_val;
+
+ if (dma->tx_wait.send_cnt >= (dma->send_cnt + dma->tx_sched_cnt))
+ send_val = 1;
+ else
+ send_val = 0;
+
+ if (dma->tx_wait.sent_cnt <= dma->sent_cnt)
+ sent_val = 1;
+ else
+ sent_val = 0;
+
+ /* AND or OR ? */
+ if (dma->tx_wait.op == 0)
+ return send_val & sent_val; /* AND */
+ else
+ return send_val | sent_val; /* OR */
+}
+
+/* Block until send_cnt or fewer packets are Queued in "Send and Scheduled" Q,
+ * op (AND or OR), sent_cnt or more packet "have been sent" (Sent Q) condition
+ * is met.
+ * If a link error occurs and the Stop on Link error is defined, this function
+ * will also return to caller.
+ */
+int grspw_dma_tx_wait(void *c, int send_cnt, int op, int sent_cnt, int timeout)
+{
+ struct grspw_dma_priv *dma = c;
+ int ret, rc;
+
+ if (timeout == 0)
+ timeout = RTEMS_NO_TIMEOUT;
+
+check_condition:
+
+ /* Take DMA channel lock */
+ if (rtems_semaphore_obtain(dma->sem_dma, RTEMS_WAIT, RTEMS_NO_TIMEOUT)
+ != RTEMS_SUCCESSFUL)
+ return -1;
+
+ /* Check so that no other thread is waiting, this driver only supports
+ * one waiter at a time.
+ */
+ if (dma->tx_wait.waiting) {
+ ret = -1;
+ goto out;
+ }
+
+ /* Stop if link error or similar, abort */
+ if (dma->started == 0) {
+ ret = 1;
+ goto out;
+ }
+
+ /* Set up Condition */
+ dma->tx_wait.send_cnt = send_cnt;
+ dma->tx_wait.op = op;
+ dma->tx_wait.sent_cnt = sent_cnt;
+
+ if (grspw_tx_wait_eval(dma) == 0) {
+ /* Prepare Wait */
+ dma->tx_wait.waiting = 1;
+
+ /* Release DMA channel lock */
+ rtems_semaphore_release(dma->sem_dma);
+
+ /* Try to take Wait lock, if this fail link may have gone down
+ * or user stopped this DMA channel
+ */
+ rc = rtems_semaphore_obtain(dma->tx_wait.sem_wait, RTEMS_WAIT,
+ timeout);
+ if (rc == RTEMS_TIMEOUT) {
+ dma->tx_wait.waiting = 0;
+ return 2;
+ } else if (rc == RTEMS_UNSATISFIED ||
+ rc == RTEMS_OBJECT_WAS_DELETED) {
+ dma->tx_wait.waiting = 0;
+ return 1; /* sem was flushed/deleted, means DMA stop */
+ } else if (rc != RTEMS_SUCCESSFUL)
+ return -1;
+
+ /* Check condition once more */
+ goto check_condition;
+ } else {
+ /* No Wait needed */
+ dma->tx_wait.waiting = 0;
+ }
+
+ ret = 0;
+out:
+ /* Unlock DMA channel */
+ rtems_semaphore_release(dma->sem_dma);
+
+ return ret;
+}
+
+int grspw_dma_rx_recv(void *c, int opts, struct grspw_list *pkts, int *count)
+{
+ struct grspw_dma_priv *dma = c;
+ struct grspw_pkt *pkt, *lastpkt;
+ int cnt, started;
+
+ /* Take DMA channel lock */
+ if (rtems_semaphore_obtain(dma->sem_dma, RTEMS_WAIT, RTEMS_NO_TIMEOUT)
+ != RTEMS_SUCCESSFUL)
+ return -1;
+
+ /* 1. Move Scheduled packets to RECV List (SCHED->RECV) */
+ started = dma->started;
+ if (((opts & 1) == 0) && (started > 0))
+ grspw_rx_process_scheduled(dma);
+
+ /* Move all RECV packet to the callers list */
+ if (pkts) {
+ if ((count == NULL) || (*count == -1) ||
+ (*count >= dma->recv_cnt)) {
+ /* Move all Received packets */
+ *pkts = dma->recv;
+ grspw_list_clr(&dma->recv);
+ if ( count )
+ *count = dma->recv_cnt;
+ dma->recv_cnt = 0;
+ } else {
+ /* Move a number of RECV Packets */
+ pkts->head = pkt = lastpkt = dma->recv.head;
+ cnt = 0;
+ while (cnt < *count) {
+ lastpkt = pkt;
+ pkt = pkt->next;
+ cnt++;
+ }
+ if (cnt > 0) {
+ pkts->tail = lastpkt;
+ grspw_list_remove_head_list(&dma->recv, pkts);
+ dma->recv_cnt -= cnt;
+ } else {
+ grspw_list_clr(pkts);
+ }
+ }
+ } else if (count) {
+ *count = 0;
+ }
+
+ /* 3. Schedule as many free packet buffers as possible (READY->SCHED) */
+ if (((opts & 2) == 0) && (started > 0))
+ grspw_rx_schedule_ready(dma);
+
+ /* Unlock DMA channel */
+ rtems_semaphore_release(dma->sem_dma);
+
+ return (~started) & 1;
+}
+
+int grspw_dma_rx_prepare(void *c, int opts, struct grspw_list *pkts, int count)
+{
+ struct grspw_dma_priv *dma = c;
+ int ret;
+
+ /* Take DMA channel lock */
+ if (rtems_semaphore_obtain(dma->sem_dma, RTEMS_WAIT, RTEMS_NO_TIMEOUT)
+ != RTEMS_SUCCESSFUL)
+ return -1;
+
+ if (dma->started == 0) {
+ ret = 1;
+ goto out;
+ }
+
+ /* 1. Move Received packets to RECV List (SCHED->RECV) */
+ if ((opts & 1) == 0)
+ grspw_rx_process_scheduled(dma);
+
+ /* 2. Add the "free/ready" packet buffers to the READY List (USER->READY) */
+ if (pkts && (count > 0)) {
+ grspw_list_append_list(&dma->ready, pkts);
+ dma->ready_cnt += count;
+ if (dma->stats.ready_cnt_max < dma->ready_cnt)
+ dma->stats.ready_cnt_max = dma->ready_cnt;
+ }
+
+ /* 3. Schedule as many packets as possible (READY->SCHED) */
+ if ((opts & 2) == 0)
+ grspw_rx_schedule_ready(dma);
+
+ ret = 0;
+out:
+ /* Unlock DMA channel */
+ rtems_semaphore_release(dma->sem_dma);
+
+ return ret;
+}
+
+void grspw_dma_rx_count(void *c, int *ready, int *sched, int *recv)
+{
+ struct grspw_dma_priv *dma = c;
+
+ if (ready)
+ *ready = dma->ready_cnt;
+ if (sched)
+ *sched = dma->rx_sched_cnt;
+ if (recv)
+ *recv = dma->recv_cnt;
+}
+
+static inline int grspw_rx_wait_eval(struct grspw_dma_priv *dma)
+{
+ int ready_val, recv_val;
+
+ if (dma->rx_wait.ready_cnt >= (dma->ready_cnt + dma->rx_sched_cnt))
+ ready_val = 1;
+ else
+ ready_val = 0;
+
+ if (dma->rx_wait.recv_cnt <= dma->recv_cnt)
+ recv_val = 1;
+ else
+ recv_val = 0;
+
+ /* AND or OR ? */
+ if (dma->rx_wait.op == 0)
+ return ready_val & recv_val; /* AND */
+ else
+ return ready_val | recv_val; /* OR */
+}
+
+/* Block until recv_cnt or more packets are Queued in RECV Q, op (AND or OR),
+ * ready_cnt or fewer packet buffers are available in the "READY and Scheduled" Q,
+ * condition is met.
+ * If a link error occurs and the Stop on Link error is defined, this function
+ * will also return to caller, however with an error.
+ */
+int grspw_dma_rx_wait(void *c, int recv_cnt, int op, int ready_cnt, int timeout)
+{
+ struct grspw_dma_priv *dma = c;
+ int ret, rc;
+
+ if (timeout == 0)
+ timeout = RTEMS_NO_TIMEOUT;
+
+check_condition:
+
+ /* Take DMA channel lock */
+ if (rtems_semaphore_obtain(dma->sem_dma, RTEMS_WAIT, RTEMS_NO_TIMEOUT)
+ != RTEMS_SUCCESSFUL)
+ return -1;
+
+ /* Check so that no other thread is waiting, this driver only supports
+ * one waiter at a time.
+ */
+ if (dma->rx_wait.waiting) {
+ ret = -1;
+ goto out;
+ }
+
+ /* Stop if link error or similar (MDA stopped) */
+ if (dma->started == 0) {
+ ret = 1;
+ goto out;
+ }
+
+ /* Set up Condition */
+ dma->rx_wait.recv_cnt = recv_cnt;
+ dma->rx_wait.op = op;
+ dma->rx_wait.ready_cnt = ready_cnt;
+
+ if (grspw_rx_wait_eval(dma) == 0) {
+ /* Prepare Wait */
+ dma->rx_wait.waiting = 1;
+
+ /* Release channel lock */
+ rtems_semaphore_release(dma->sem_dma);
+
+ /* Try to take Wait lock, if this fail link may have gone down
+ * or user stopped this DMA channel
+ */
+ rc = rtems_semaphore_obtain(dma->rx_wait.sem_wait, RTEMS_WAIT,
+ timeout);
+ if (rc == RTEMS_TIMEOUT) {
+ dma->rx_wait.waiting = 0;
+ return 2;
+ } else if (rc == RTEMS_UNSATISFIED ||
+ rc == RTEMS_OBJECT_WAS_DELETED) {
+ dma->rx_wait.waiting = 0;
+ return 1; /* sem was flushed/deleted, means DMA stop */
+ } else if (rc != RTEMS_SUCCESSFUL)
+ return -1;
+
+ /* Check condition once more */
+ goto check_condition;
+ } else {
+ /* No Wait needed */
+ dma->rx_wait.waiting = 0;
+ }
+ ret = 0;
+
+out:
+ /* Unlock DMA channel */
+ rtems_semaphore_release(dma->sem_dma);
+
+ return ret;
+}
+
+int grspw_dma_config(void *c, struct grspw_dma_config *cfg)
+{
+ struct grspw_dma_priv *dma = c;
+
+ if (dma->started || !cfg)
+ return -1;
+
+ if (cfg->flags & ~DMAFLAG_MASK)
+ return -1;
+
+ /* Update Configuration */
+ memcpy(&dma->cfg, cfg, sizeof(*cfg));
+
+ return 0;
+}
+
+void grspw_dma_config_read(void *c, struct grspw_dma_config *cfg)
+{
+ struct grspw_dma_priv *dma = c;
+
+ /* Copy Current Configuration */
+ memcpy(cfg, &dma->cfg, sizeof(*cfg));
+}
+
+void grspw_dma_stats_read(void *c, struct grspw_dma_stats *sts)
+{
+ struct grspw_dma_priv *dma = c;
+
+ memcpy(sts, &dma->stats, sizeof(dma->stats));
+}
+
+void grspw_dma_stats_clr(void *c)
+{
+ struct grspw_dma_priv *dma = c;
+
+ /* Clear most of the statistics */
+ memset(&dma->stats, 0, sizeof(dma->stats));
+
+ /* Init proper default values so that comparisons will work the
+ * first time.
+ */
+ dma->stats.send_cnt_min = 0x3fffffff;
+ dma->stats.tx_sched_cnt_min = 0x3fffffff;
+ dma->stats.ready_cnt_min = 0x3fffffff;
+ dma->stats.rx_sched_cnt_min = 0x3fffffff;
+}
+
+int grspw_dma_start(void *c)
+{
+ struct grspw_dma_priv *dma = c;
+ struct grspw_dma_regs *dregs = dma->regs;
+ unsigned int ctrl;
+
+ if (dma->started)
+ return 0;
+
+ /* Initialize Software Structures:
+ * - Clear all Queues
+ * - init BD ring
+ * - init IRQ counter
+ * - clear statistics counters
+ * - init wait structures and semaphores
+ */
+ grspw_dma_reset(dma);
+
+ /* RX&RD and TX is not enabled until user fills SEND and READY Queue
+ * with SpaceWire Packet buffers. So we do not have to worry about
+ * IRQs for this channel just yet. However other DMA channels
+ * may be active.
+ *
+ * Some functionality that is not changed during started mode is set up
+ * once and for all here:
+ *
+ * - RX MAX Packet length
+ * - TX Descriptor base address to first BD in TX ring (not enabled)
+ * - RX Descriptor base address to first BD in RX ring (not enabled)
+ * - IRQs (TX DMA, RX DMA, DMA ERROR)
+ * - Strip PID
+ * - Strip Address
+ * - No Spill
+ * - Receiver Enable
+ * - disable on link error (LE)
+ *
+ * Note that the address register and the address enable bit in DMACTRL
+ * register must be left untouched, they are configured on a GRSPW
+ * core level.
+ *
+ * Note that the receiver is enabled here, but since descriptors are
+ * not enabled the GRSPW core may stop/pause RX (if NS bit set) until
+ * descriptors are enabled or it may ignore RX packets (NS=0) until
+ * descriptors are enabled (writing RD bit).
+ */
+ REG_WRITE(&dregs->txdesc, dma->tx_bds_hwa);
+ REG_WRITE(&dregs->rxdesc, dma->rx_bds_hwa);
+
+ /* MAX Packet length */
+ REG_WRITE(&dma->regs->rxmax, dma->cfg.rxmaxlen);
+
+ ctrl = GRSPW_DMACTRL_AI | GRSPW_DMACTRL_PS | GRSPW_DMACTRL_PR |
+ GRSPW_DMACTRL_TA | GRSPW_DMACTRL_RA | GRSPW_DMACTRL_RE |
+ (dma->cfg.flags & DMAFLAG_MASK) << GRSPW_DMACTRL_NS_BIT;
+ if (dma->core->dis_link_on_err)
+ ctrl |= GRSPW_DMACTRL_LE;
+ if (dma->cfg.rx_irq_en_cnt != 0)
+ ctrl |= GRSPW_DMACTRL_RI;
+ if (dma->cfg.tx_irq_en_cnt != 0)
+ ctrl |= GRSPW_DMACTRL_TI;
+ REG_WRITE(&dregs->ctrl, ctrl);
+
+ dma->started = 1; /* open up other DMA interfaces */
+
+ return 0;
+}
+
+STATIC void grspw_dma_stop_locked(struct grspw_dma_priv *dma)
+{
+ IRQFLAGS_TYPE irqflags;
+
+ if (dma->started == 0)
+ return;
+ dma->started = 0;
+
+ SPIN_LOCK_IRQ(&priv->devlock, irqflags);
+ grspw_hw_dma_stop(dma);
+ SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
+
+ /* From here no more packets will be sent, however
+ * there may still exist scheduled packets that has been
+ * sent, and packets in the SEND Queue waiting for free
+ * descriptors. All packets are moved to the SENT Queue
+ * so that the user may get its buffers back, the user
+ * must look at the TXPKT_FLAG_TX in order to determine
+ * if the packet was sent or not.
+ */
+
+ /* Retreive scheduled all sent packets */
+ grspw_tx_process_scheduled(dma);
+
+ /* Move un-sent packets in SEND and SCHED queue to the
+ * SENT Queue. (never marked sent)
+ */
+ if (!grspw_list_is_empty(&dma->tx_sched)) {
+ grspw_list_append_list(&dma->sent, &dma->tx_sched);
+ grspw_list_clr(&dma->tx_sched);
+ dma->sent_cnt += dma->tx_sched_cnt;
+ dma->tx_sched_cnt = 0;
+ }
+ if (!grspw_list_is_empty(&dma->send)) {
+ grspw_list_append_list(&dma->sent, &dma->send);
+ grspw_list_clr(&dma->send);
+ dma->sent_cnt += dma->send_cnt;
+ dma->send_cnt = 0;
+ }
+
+ /* Similar for RX */
+ grspw_rx_process_scheduled(dma);
+ if (!grspw_list_is_empty(&dma->rx_sched)) {
+ grspw_list_append_list(&dma->recv, &dma->rx_sched);
+ grspw_list_clr(&dma->rx_sched);
+ dma->recv_cnt += dma->rx_sched_cnt;
+ dma->rx_sched_cnt = 0;
+ }
+ if (!grspw_list_is_empty(&dma->ready)) {
+ grspw_list_append_list(&dma->recv, &dma->ready);
+ grspw_list_clr(&dma->ready);
+ dma->recv_cnt += dma->ready_cnt;
+ dma->ready_cnt = 0;
+ }
+
+ /* Throw out blocked threads */
+ rtems_semaphore_flush(dma->rx_wait.sem_wait);
+ rtems_semaphore_flush(dma->tx_wait.sem_wait);
+}
+
+void grspw_dma_stop(void *c)
+{
+ struct grspw_dma_priv *dma = c;
+
+ /* Take DMA Channel lock */
+ if (rtems_semaphore_obtain(dma->sem_dma, RTEMS_WAIT, RTEMS_NO_TIMEOUT)
+ != RTEMS_SUCCESSFUL)
+ return;
+
+ grspw_dma_stop_locked(dma);
+
+ rtems_semaphore_release(dma->sem_dma);
+}
+
+/* Do general work, invoked indirectly from ISR */
+static void grspw_work_shutdown_func(struct grspw_priv *priv)
+{
+ int i;
+
+ /* Link is down for some reason, and the user has configured
+ * that we stop all DMA channels and throw out all blocked
+ * threads.
+ */
+ for (i=0; i<priv->hwsup.ndma_chans; i++)
+ grspw_dma_stop(&priv->dma[i]);
+ grspw_hw_stop(priv);
+}
+
+/* Do DMA work on one channel, invoked indirectly from ISR */
+static void grspw_work_dma_func(struct grspw_dma_priv *dma)
+{
+ int tx_cond_true, rx_cond_true;
+ unsigned int ctrl;
+ IRQFLAGS_TYPE irqflags;
+
+ rx_cond_true = 0;
+ tx_cond_true = 0;
+ dma->stats.irq_cnt++;
+
+ /* Take DMA channel lock */
+ if (rtems_semaphore_obtain(dma->sem_dma, RTEMS_WAIT, RTEMS_NO_TIMEOUT)
+ != RTEMS_SUCCESSFUL)
+ return;
+
+ /* Look at cause we were woken up and clear source */
+ SPIN_LOCK_IRQ(&priv->devlock, irqflags);
+ ctrl = REG_READ(&dma->regs->ctrl);
+
+ /* Read/Write DMA error ? */
+ if (ctrl & GRSPW_DMA_STATUS_ERROR) {
+ /* DMA error -> Stop DMA channel (both RX and TX) */
+ SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
+ grspw_dma_stop_locked(dma);
+ } else if (ctrl & (GRSPW_DMACTRL_PR | GRSPW_DMACTRL_PS)) {
+ /* DMA has finished a TX/RX packet */
+ ctrl &= ~GRSPW_DMACTRL_AT;
+ if (dma->cfg.rx_irq_en_cnt != 0)
+ ctrl |= GRSPW_DMACTRL_RI;
+ if (dma->cfg.tx_irq_en_cnt != 0)
+ ctrl |= GRSPW_DMACTRL_TI;
+ REG_WRITE(&dma->regs->ctrl, ctrl);
+ SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
+ if (ctrl & GRSPW_DMACTRL_PR) {
+ /* Do RX Work */
+ dma->stats.rx_work_cnt++;
+ grspw_rx_process_scheduled(dma);
+ dma->stats.rx_work_enabled += grspw_rx_schedule_ready(dma);
+ /* Check to see if condition for waking blocked USER
+ * task is fullfilled.
+ */
+ if (dma->rx_wait.waiting) {
+ rx_cond_true = grspw_rx_wait_eval(dma);
+ if (rx_cond_true)
+ dma->rx_wait.waiting = 0;
+ }
+ }
+ if (ctrl & GRSPW_DMACTRL_PS) {
+ /* Do TX Work */
+ dma->stats.tx_work_cnt++;
+ grspw_tx_process_scheduled(dma);
+ dma->stats.tx_work_enabled += grspw_tx_schedule_send(dma);
+ if (dma->tx_wait.waiting) {
+ tx_cond_true = grspw_tx_wait_eval(dma);
+ if (tx_cond_true)
+ dma->tx_wait.waiting = 0;
+ }
+ }
+ } else
+ SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
+
+ /* Release lock */
+ rtems_semaphore_release(dma->sem_dma);
+
+ if (rx_cond_true)
+ rtems_semaphore_release(dma->rx_wait.sem_wait);
+
+ if (tx_cond_true)
+ rtems_semaphore_release(dma->tx_wait.sem_wait);
+}
+
+/* Work task is receiving work for the work message queue posted from
+ * the ISR.
+ */
+void grspw_work_func(rtems_task_argument unused)
+{
+ rtems_status_code status;
+ unsigned int message;
+ size_t size;
+ struct grspw_priv *priv;
+ int i;
+
+ while (grspw_task_stop == 0) {
+ /* Wait for ISR to schedule work */
+ status = rtems_message_queue_receive(
+ grspw_work_queue, &message,
+ &size, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+ if (status != RTEMS_SUCCESSFUL)
+ break;
+
+ /* Handle work */
+ priv = priv_tab[message >> WORK_CORE_BIT];
+ if (message & WORK_SHUTDOWN)
+ grspw_work_shutdown_func(priv);
+ else if (message & WORK_DMA_MASK) {
+ for (i = 0; i < 4; i++) {
+ if (message & WORK_DMA(i))
+ grspw_work_dma_func(&priv->dma[i]);
+ }
+ }
+ }
+ rtems_task_delete(RTEMS_SELF);
+}
+
+STATIC void grspw_isr(void *data)
+{
+ struct grspw_priv *priv = data;
+ unsigned int dma_stat, stat, stat_clrmsk, ctrl, timecode;
+ int i, handled = 0, message = WORK_NONE;
+#ifdef RTEMS_HAS_SMP
+ IRQFLAGS_TYPE irqflags;
+#endif
+
+ /* Get Status from Hardware */
+ stat = REG_READ(&priv->regs->status);
+ stat_clrmsk = stat & (GRSPW_STS_TO | GRSPW_STAT_ERROR);
+
+ /* Make sure to put the timecode handling first in order to get the
+ * smallest possible interrupt latency
+ */
+ if ((stat & GRSPW_STS_TO) && (priv->tcisr != NULL)) {
+ /* Timecode received. Let custom function handle this */
+ timecode = priv->regs->time;
+ (priv->tcisr)(priv->tcisr_arg, timecode);
+ }
+
+ /* An Error occured? */
+ if (stat & GRSPW_STAT_ERROR) {
+ /* Wake Global WorkQ */
+ handled = 1;
+
+ if (stat & GRSPW_STS_EE)
+ priv->stats.err_eeop++;
+
+ if (stat & GRSPW_STS_IA)
+ priv->stats.err_addr++;
+
+ if (stat & GRSPW_STS_PE)
+ priv->stats.err_parity++;
+
+ if (stat & GRSPW_STS_ER)
+ priv->stats.err_escape++;
+
+ if (stat & GRSPW_STS_CE)
+ priv->stats.err_credit++;
+
+ if (stat & GRSPW_STS_WE)
+ priv->stats.err_wsync++;
+
+ if (priv->dis_link_on_err) {
+ /* Disable the link, no more transfers are expected
+ * on any DMA channel.
+ */
+ SPIN_LOCK(&priv->devlock, irqflags);
+ ctrl = REG_READ(&priv->regs->ctrl);
+ REG_WRITE(&priv->regs->ctrl, GRSPW_CTRL_LD |
+ (ctrl & ~(GRSPW_CTRL_IE|GRSPW_CTRL_LS)));
+ SPIN_UNLOCK(&priv->devlock, irqflags);
+ /* Signal to work-thread to stop DMA and clean up */
+ message = WORK_SHUTDOWN;
+ }
+ }
+
+ /* Clear Status Flags */
+ if (stat_clrmsk) {
+ handled = 1;
+ REG_WRITE(&priv->regs->status, stat_clrmsk);
+ }
+
+ /* A DMA transfer or Error occured? In that case disable more IRQs
+ * from the DMA channel, then invoke the workQ.
+ *
+ * Also the GI interrupt flag may not be available for older
+ * designs where (was added together with mutiple DMA channels).
+ */
+ SPIN_LOCK(&priv->devlock, irqflags);
+ for (i=0; i<priv->hwsup.ndma_chans; i++) {
+ dma_stat = REG_READ(&priv->regs->dma[i].ctrl);
+ /* Check for Errors and if Packets been sent or received if
+ * respective IRQ are enabled
+ */
+#ifdef HW_WITH_GI
+ if ( dma_stat & (GRSPW_DMA_STATUS_ERROR | GRSPW_DMACTRL_GI) ) {
+#else
+ if ( (((dma_stat << 3) & (GRSPW_DMACTRL_PR | GRSPW_DMACTRL_PS))
+ | GRSPW_DMA_STATUS_ERROR) & dma_stat ) {
+#endif
+ /* Disable Further IRQs (until enabled again)
+ * from this DMA channel. Let the status
+ * bit remain so that they can be handled by
+ * work function.
+ */
+ REG_WRITE(&priv->regs->dma[i].ctrl, dma_stat &
+ ~(GRSPW_DMACTRL_RI|GRSPW_DMACTRL_TI|
+ GRSPW_DMACTRL_PR|GRSPW_DMACTRL_PS|
+ GRSPW_DMACTRL_RA|GRSPW_DMACTRL_TA|
+ GRSPW_DMACTRL_AT));
+ message |= WORK_DMA(i);
+ handled = 1;
+ }
+ }
+ SPIN_UNLOCK(&priv->devlock, irqflags);
+
+ if (handled != 0)
+ priv->stats.irq_cnt++;
+
+ /* Schedule work by sending message to work thread */
+ if ((message != WORK_NONE) && grspw_work_queue) {
+ message |= WORK_CORE(priv->index);
+ stat = rtems_message_queue_send(grspw_work_queue, &message, 4);
+ if (stat != RTEMS_SUCCESSFUL)
+ printk("grspw_isr(%d): message fail %d (0x%x)\n",
+ priv->index, stat, message);
+ }
+}
+
+STATIC void grspw_hw_dma_stop(struct grspw_dma_priv *dma)
+{
+ unsigned int ctrl;
+ struct grspw_dma_regs *dregs = dma->regs;
+
+ ctrl = REG_READ(&dregs->ctrl) & (GRSPW_DMACTRL_LE | GRSPW_DMACTRL_EN |
+ GRSPW_DMACTRL_SP | GRSPW_DMACTRL_SA | GRSPW_DMACTRL_NS);
+ ctrl |= GRSPW_DMACTRL_AT;
+ REG_WRITE(&dregs->ctrl, ctrl);
+}
+
+STATIC void grspw_hw_dma_softreset(struct grspw_dma_priv *dma)
+{
+ unsigned int ctrl;
+ struct grspw_dma_regs *dregs = dma->regs;
+
+ ctrl = REG_READ(&dregs->ctrl) & (GRSPW_DMACTRL_LE | GRSPW_DMACTRL_EN);
+ REG_WRITE(&dregs->ctrl, ctrl);
+
+ REG_WRITE(&dregs->rxmax, DEFAULT_RXMAX);
+ REG_WRITE(&dregs->txdesc, 0);
+ REG_WRITE(&dregs->rxdesc, 0);
+}
+
+/* Hardware Action:
+ * - stop DMA
+ * - do not bring down the link (RMAP may be active)
+ * - RMAP settings untouched (RMAP may be active)
+ * - port select untouched (RMAP may be active)
+ * - timecodes are disabled
+ * - IRQ generation disabled
+ * - status not cleared (let user analyze it if requested later on)
+ * - Node address / First DMA channels Node address
+ * is untouched (RMAP may be active)
+ */
+STATIC void grspw_hw_stop(struct grspw_priv *priv)
+{
+ int i;
+ unsigned int ctrl;
+ IRQFLAGS_TYPE irqflags;
+
+ SPIN_LOCK_IRQ(&priv->devlock, irqflags);
+
+ for (i=0; i<priv->hwsup.ndma_chans; i++)
+ grspw_hw_dma_stop(&priv->dma[i]);
+
+ ctrl = REG_READ(&priv->regs->ctrl);
+ REG_WRITE(&priv->regs->ctrl, ctrl & (
+ GRSPW_CTRL_LD | GRSPW_CTRL_LS | GRSPW_CTRL_AS |
+ GRSPW_CTRL_RE | GRSPW_CTRL_RD |
+ GRSPW_CTRL_NP | GRSPW_CTRL_PS));
+
+ SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
+}
+
+/* Soft reset of GRSPW core registers */
+STATIC void grspw_hw_softreset(struct grspw_priv *priv)
+{
+ int i;
+
+ for (i=0; i<priv->hwsup.ndma_chans; i++)
+ grspw_hw_dma_softreset(&priv->dma[i]);
+
+ REG_WRITE(&priv->regs->status, 0xffffffff);
+ REG_WRITE(&priv->regs->time, 0);
+}
+
+int grspw_dev_count(void)
+{
+ return grspw_count;
+}
+
+void grspw_initialize_user(void *(*devfound)(int), void (*devremove)(int,void*))
+{
+ int i;
+ struct grspw_priv *priv;
+
+ /* Set new Device Found Handler */
+ grspw_dev_add = devfound;
+ grspw_dev_del = devremove;
+
+ if (grspw_initialized == 1 && grspw_dev_add) {
+ /* Call callback for every previously found device */
+ for (i=0; i<grspw_count; i++) {
+ priv = priv_tab[i];
+ if (priv)
+ priv->data = grspw_dev_add(i);
+ }
+ }
+}
+
+/******************* Driver manager interface ***********************/
+
+/* Driver prototypes */
+static int grspw_common_init(void);
+static int grspw2_init3(struct drvmgr_dev *dev);
+
+static struct drvmgr_drv_ops grspw2_ops =
+{
+ .init = {NULL, NULL, grspw2_init3, NULL},
+ .remove = NULL,
+ .info = NULL
+};
+
+static struct amba_dev_id grspw2_ids[] =
+{
+ {VENDOR_GAISLER, GAISLER_SPW}, /* not yet supported */
+ {VENDOR_GAISLER, GAISLER_SPW2},
+ {VENDOR_GAISLER, GAISLER_SPW2_DMA},
+ {0, 0} /* Mark end of table */
+};
+
+static struct amba_drv_info grspw2_drv_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_AMBAPP_GAISLER_GRSPW2_ID,/* Driver ID */
+ "GRSPW_PKT_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */
+ &grspw2_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ sizeof(struct grspw_priv), /* Let DrvMgr alloc priv */
+ },
+ &grspw2_ids[0]
+};
+
+void grspw2_register_drv (void)
+{
+ GRSPW_DBG("Registering GRSPW2 packet driver\n");
+ drvmgr_drv_register(&grspw2_drv_info.general);
+}
+
+static int grspw2_init3(struct drvmgr_dev *dev)
+{
+ struct grspw_priv *priv;
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
+ int i, size;
+ unsigned int ctrl;
+ union drvmgr_key_value *value;
+
+ GRSPW_DBG("GRSPW[%d] on bus %s\n", dev->minor_drv,
+ dev->parent->dev->name);
+
+ if (grspw_count > GRSPW_MAX)
+ return DRVMGR_ENORES;
+
+ priv = dev->priv;
+ if (priv == NULL)
+ return DRVMGR_NOMEM;
+ priv->dev = dev;
+
+ /* If first device init common part of driver */
+ if (grspw_common_init())
+ return DRVMGR_FAIL;
+
+ /*** Now we take care of device initialization ***/
+
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)dev->businfo;
+ if (ambadev == NULL)
+ return -1;
+ pnpinfo = &ambadev->info;
+ priv->irq = pnpinfo->irq;
+ priv->regs = (struct grspw_regs *)pnpinfo->apb_slv->start;
+
+ /* Read Hardware Support from Control Register */
+ ctrl = REG_READ(&priv->regs->ctrl);
+ priv->hwsup.rmap = (ctrl & GRSPW_CTRL_RA) >> GRSPW_CTRL_RA_BIT;
+ priv->hwsup.rmap_crc = (ctrl & GRSPW_CTRL_RC) >> GRSPW_CTRL_RC_BIT;
+ priv->hwsup.rx_unalign = (ctrl & GRSPW_CTRL_RX) >> GRSPW_CTRL_RX_BIT;
+ priv->hwsup.nports = 1 + ((ctrl & GRSPW_CTRL_PO) >> GRSPW_CTRL_PO_BIT);
+ priv->hwsup.ndma_chans = 1 + ((ctrl & GRSPW_CTRL_NCH) >> GRSPW_CTRL_NCH_BIT);
+
+ /* Construct hardware version identification */
+ priv->hwsup.hw_version = pnpinfo->device << 16 | pnpinfo->apb_slv->ver;
+
+ if ((pnpinfo->device == GAISLER_SPW2) ||
+ (pnpinfo->device == GAISLER_SPW2_DMA)) {
+ priv->hwsup.strip_adr = 1; /* All GRSPW2 can strip Address */
+ priv->hwsup.strip_pid = 1; /* All GRSPW2 can strip PID */
+ } else {
+ /* Autodetect GRSPW1 features? */
+ priv->hwsup.strip_adr = 0;
+ priv->hwsup.strip_pid = 0;
+ }
+
+ /* Let user limit the number of DMA channels on this core to save
+ * space. Only the first nDMA channels will be available.
+ */
+ value = drvmgr_dev_key_get(priv->dev, "nDMA", KEY_TYPE_INT);
+ if (value && (value->i < priv->hwsup.ndma_chans))
+ priv->hwsup.ndma_chans = value->i;
+
+ /* Allocate and init Memory for all DMA channels */
+ size = sizeof(struct grspw_dma_priv) * priv->hwsup.ndma_chans;
+ priv->dma = (struct grspw_dma_priv *) malloc(size);
+ if (priv->dma == NULL)
+ return DRVMGR_NOMEM;
+ memset(priv->dma, 0, size);
+ for (i=0; i<priv->hwsup.ndma_chans; i++) {
+ priv->dma[i].core = priv;
+ priv->dma[i].index = i;
+ priv->dma[i].regs = &priv->regs->dma[i];
+ }
+
+ /* Startup Action:
+ * - stop DMA
+ * - do not bring down the link (RMAP may be active)
+ * - RMAP settings untouched (RMAP may be active)
+ * - port select untouched (RMAP may be active)
+ * - timecodes are diabled
+ * - IRQ generation disabled
+ * - status cleared
+ * - Node address / First DMA channels Node address
+ * is untouched (RMAP may be active)
+ */
+ grspw_hw_stop(priv);
+ grspw_hw_softreset(priv);
+
+ /* Register character device in registered region */
+ priv->index = grspw_count;
+ priv_tab[priv->index] = priv;
+ grspw_count++;
+
+ /* Device name */
+ sprintf(priv->devname, "grspw%d", priv->index);
+
+ /* Tell above layer about new device */
+ if (grspw_dev_add)
+ priv->data = grspw_dev_add(priv->index);
+
+ return DRVMGR_OK;
+}
+
+/******************* Driver Implementation ***********************/
+
+static int grspw_common_init(void)
+{
+ if (grspw_initialized == 1)
+ return 0;
+ if (grspw_initialized == -1)
+ return -1;
+ grspw_initialized = -1;
+
+ /* Device Semaphore created with count = 1 */
+ if (rtems_semaphore_create(rtems_build_name('S', 'G', 'L', 'S'), 1,
+ RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | \
+ RTEMS_NO_INHERIT_PRIORITY | RTEMS_LOCAL | \
+ RTEMS_NO_PRIORITY_CEILING, 0, &grspw_sem) != RTEMS_SUCCESSFUL)
+ return -1;
+
+ /* Work queue, Work thread. Not created if user disables it.
+ * user can disable it when interrupt is not used to save resources
+ */
+ if (grspw_work_task_priority != -1) {
+ if (rtems_message_queue_create(
+ rtems_build_name('S', 'G', 'L', 'Q'), 32, 4, RTEMS_FIFO,
+ &grspw_work_queue) != RTEMS_SUCCESSFUL)
+ return -1;
+
+ if (rtems_task_create(rtems_build_name('S', 'G', 'L', 'T'),
+ grspw_work_task_priority, RTEMS_MINIMUM_STACK_SIZE,
+ RTEMS_PREEMPT | RTEMS_NO_ASR, RTEMS_NO_FLOATING_POINT,
+ &grspw_work_task) != RTEMS_SUCCESSFUL)
+ return -1;
+
+ if (rtems_task_start(grspw_work_task, grspw_work_func, 0) !=
+ RTEMS_SUCCESSFUL)
+ return -1;
+ }
+
+ grspw_initialized = 1;
+ return 0;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/spw/grspw_rasta.c b/c/src/lib/libbsp/sparc/shared/spw/grspw_rasta.c
deleted file mode 100644
index 6cd5698f44..0000000000
--- a/c/src/lib/libbsp/sparc/shared/spw/grspw_rasta.c
+++ /dev/null
@@ -1,155 +0,0 @@
-/* Select PCI driver */
-#define GRSPW_PCI
-
-#undef GRSPW_MAXDEVS
-#undef DEBUG_SPACEWIRE_ONOFF
-/*#define DEBUG_SPACEWIRE_ONOFF*/
-/*
- * If USE_AT697_RAM is defined the RAM on the AT697 board will be used for DMA buffers (but rx message queue is always in AT697 ram).
- * USE_AT697_DMA specifies whether the messages will be fetched using DMA or PIO.
- *
- * RASTA_PCI_BASE is the base address of the GRPCI AHB slave
- *
- */
-
-#define USE_AT697_RAM 1
-#define USE_AT697_DMA 0
-#define RASTA_PCI_BASE 0xe0000000
-#define GRSPW_RASTA_MEM_OFF 0x21000
-
-/* Make GRSPW driver use malloced or static memory
- */
-#ifdef USE_AT697_RAM
-#undef GRSPW_STATIC_MEM
-#else
-#define GRSPW_STATIC_MEM
-#define GRSPW_CALC_MEMOFS(maxcores,corenum,ptr_mem_base,ptr_mem_end,ptr_bdtable_base) \
- grspw_rasta_calc_memoffs((maxcores),(corenum),(ptr_mem_base),(ptr_mem_end),(ptr_bdtable_base))
-#endif
-
-/* We have custom address tranlation for HW addresses */
-#define GRSPW_ADR_TO
-
-/* MEMAREA=>CPU used when reading descriptor buffer pointers,
- * they need to be translated from adresses used by GRSPW HW
- * into CPU readable addresses.
- *
- * NOT NEEDED AS GRSPW DRIVER USES INDEXES TO GET DESCRIPTOR
- * DATA POINTER ADDRESSES.
- */
-#undef GRSPW_ADR_FROM
-
-/* Set registered device name */
-#define GRSPW_DEVNAME "/dev/grspwrasta0"
-#define GRSPW_DEVNAME_NO(devstr,no) ((devstr)[15]='0'+(no))
-
-/* Any non-static function will begin with */
-#define GRSPW_PREFIX(name) grspwrasta##name
-
-/* do nothing, assume that the interrupt handler is called
- * setup externally calling grspw_interrupt_handler.
- */
-#define GRSPW_REG_INT(handler,irq,arg) \
- if ( grspw_rasta_int_reg ) \
- grspw_rasta_int_reg(handler,irq,arg);
-
-#define GRSPW_DONT_BYPASS_CACHE
-
-#ifdef GRSPW_ADR_TO
-/* Translate a address within the Memory Region (memarea) into an Hardware
- * device address. This address is put into hardware registers or descriptors
- * so that the hardware can access the Memory Region.
- * Example:
- * An local AMBA access at 0xe0000000 will translate into PCI address 0x40000000,
- * the PCI address 0x40000000 will translate into CPU-AMBA address 0x40000000.
- */
-static inline unsigned int memarea_to_hw(unsigned int addr) {
- return ((addr & 0x0fffffff) | RASTA_PCI_BASE);
-}
-#endif
-
-void (*grspw_rasta_int_reg)(void *handler, int irq, void *arg) = 0;
-
-#ifdef GRSPW_STATIC_MEM
-static int grspw_rasta_calc_memoffs(int maxcores, int corenum, unsigned int *mem_base, unsigned int *mem_end, unsigned int *bdtable_base);
-#endif
-
-int grspw_rasta_interrupt_handler(unsigned int status);
-
-void grspwrasta_interrupt_handler(int irq, void *pDev);
-
-#include "grspw.c"
-
-unsigned int grspw_rasta_memarea_address;
-
-/* Register RASTA GRSPW driver.
- *
- * memarea = preallocated memory somewhere, pointer to start of memory.
- */
-
-int grspw_rasta_register(
- amba_confarea_type *bus,
- unsigned int ram_base
- )
-{
- /* Setup configuration */
-
- /* if zero the malloc will be used */
- grspw_rasta_memarea_address = ram_base + GRSPW_RASTA_MEM_OFF;
-
- /* Register the driver */
- return GRSPW_PREFIX(_register)(bus);
-}
-
-#if 0
-/* Call this from PCI interrupt handler, simply figures out
- * which GRSPW core was responsible for the IRQ (may be multiple).
- * v = status of the PCI/AMBA MCPU IRQ CTRL
- */
-int grspw_rasta_interrupt_handler(unsigned int status)
-{
- int minor;
-
- for(minor = 0; minor < spw_cores; minor++) {
- if (status & (1<<grspw_devs[minor].irq) ) {
- grspw_interrupt(&grspw_devs[minor]);
- }
- }
-}
-#endif
-
-void GRSPW_PREFIX(_interrupt_handler)(int irq, void *pDev)
-{
- grspw_interrupt(pDev);
-}
-
-
-#ifdef GRSPW_STATIC_MEM
-/*
- * --------------------------------------- <-
- * | Core1: BD TABLE 1 and 2 |
- * | Core2: BD TABLE 1 and 2 |
- * | Core3: BD TABLE 1 and 2 |
- * |-------------------------------------|
- * | Core1: rx data buf + rx header buf |
- * | Core2: rx data buf + rx header buf |
- * | Core3: rx data buf + rx header buf |
- * ---------------------------------------
- */
-static int grspw_rasta_calc_memoffs(int maxcores, int corenum, unsigned int *mem_base, unsigned int *mem_end, unsigned int *bdtable_base)
-{
- if ( maxcores > 3 )
- return -1;
-
- if ( bdtable_base )
- *bdtable_base = grspw_rasta_memarea_address + corenum*2*SPACEWIRE_BDTABLE_SIZE;
-
- if ( mem_base )
- *mem_base = grspw_rasta_memarea_address + coremax*2*SPACEWIRE_BDTABLE_SIZE + corenum*BUFMEM_PER_LINK;
-
- if ( mem_end )
- *mem_end = grspw_rasta_memarea_address + coremax*2*SPACEWIRE_BDTABLE_SIZE + (corenum+1)*BUFMEM_PER_LINK;
-
- return 0;
-}
-#endif
diff --git a/c/src/lib/libbsp/sparc/shared/spw/grspw_router.c b/c/src/lib/libbsp/sparc/shared/spw/grspw_router.c
new file mode 100644
index 0000000000..e649596058
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/spw/grspw_router.c
@@ -0,0 +1,547 @@
+/* GRSPW ROUTER APB-Register Driver.
+ *
+ * COPYRIGHT (c) 2010.
+ * Aeroflex Gaisler AB
+ *
+ * Author: Daniel Hellstrom
+ */
+
+#include <rtems.h>
+#include <rtems/libio.h>
+#include <stdio.h>
+
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+#include <grspw_router.h>
+
+#define ROUTER_DBG(args...)
+
+#define REG_READ(adr) (*(volatile unsigned int *)(adr))
+#define REG_WRITE(adr, value) (*(volatile unsigned int *)(adr) = (value))
+
+struct router_regs {
+ unsigned int resv1; /* 0x000 */
+ unsigned int psetup[255]; /* 0x004 */
+ unsigned int resv2[32]; /* 0x400 */
+ unsigned int routes[224]; /* 0x480 */
+ unsigned int pctrl[32]; /* 0x800 */
+ unsigned int psts[32]; /* 0x880 */
+ unsigned int treload[32]; /* 0x900 */
+ unsigned int resv3[32]; /* 0x980 */
+ unsigned int cfgsts; /* 0xA00 */
+ unsigned int timecode; /* 0xA04 */
+ unsigned int ver; /* 0xA08 */
+ unsigned int idiv; /* 0xA0C */
+ unsigned int cfgwe; /* 0xA10 */
+ unsigned int tprescaler; /* 0xA14 */
+ unsigned int resv4[123]; /* 0xA18 */
+ unsigned int charo[31]; /* 0xC04 */
+ unsigned int resv5; /* 0xC80 */
+ unsigned int chari[31]; /* 0xC84 */
+ unsigned int resv6; /* 0xD00 */
+ unsigned int pkto[31]; /* 0xD04 */
+ unsigned int resv7; /* 0xD80 */
+ unsigned int pkti[31]; /* 0xD84 */
+};
+
+struct router_priv {
+ char devName[32];
+ struct drvmgr_dev *dev;
+ struct router_regs *regs;
+ int minor;
+ int open;
+ struct router_hw_info hwinfo;
+ int nports;
+};
+
+static rtems_device_driver router_initialize(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+ );
+
+static rtems_device_driver router_open(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+ );
+
+static rtems_device_driver router_close(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+ );
+
+static rtems_device_driver router_control(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+ );
+
+#define ROUTER_DRIVER_TABLE_ENTRY \
+ { router_initialize, \
+ router_open, \
+ router_close, \
+ NULL, \
+ NULL, \
+ router_control }
+
+void router_hwinfo(struct router_priv *priv, struct router_hw_info *hwinfo);
+
+static rtems_driver_address_table router_driver = ROUTER_DRIVER_TABLE_ENTRY;
+static int router_driver_io_registered = 0;
+static rtems_device_major_number router_driver_io_major = 0;
+
+/******************* Driver manager interface ***********************/
+
+/* Driver prototypes */
+int router_register_io(rtems_device_major_number *m);
+
+int router_init2(struct drvmgr_dev *dev);
+
+struct drvmgr_drv_ops router_ops =
+{
+ .init = {NULL, router_init2, NULL, NULL},
+ .remove = NULL,
+ .info = NULL
+};
+
+struct amba_dev_id router_ids[] =
+{
+ {VENDOR_GAISLER, GAISLER_SPW_ROUTER},
+ {0, 0} /* Mark end of table */
+};
+
+struct amba_drv_info router_drv_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_AMBAPP_GAISLER_SPW_ROUTER_ID,/* Driver ID */
+ "ROUTER_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */
+ &router_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ sizeof(struct router_priv), /* Let DRVMGR allocate for us */
+ },
+ &router_ids[0],
+};
+
+void router_register_drv (void)
+{
+ drvmgr_drv_register(&router_drv_info.general);
+}
+
+int router_init2(struct drvmgr_dev *dev)
+{
+ struct router_priv *priv = dev->priv;
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
+ char prefix[32];
+ rtems_status_code status;
+
+ if ( priv == NULL )
+ return DRVMGR_NOMEM;
+ priv->dev = dev;
+
+ /* Do initialization */
+ if ( router_driver_io_registered == 0) {
+ /* Register the I/O driver only once for all cores */
+ if ( router_register_io(&router_driver_io_major) ) {
+ /* Failed to register I/O driver */
+ return DRVMGR_FAIL;
+ }
+
+ router_driver_io_registered = 1;
+ }
+
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)priv->dev->businfo;
+ if ( ambadev == NULL ) {
+ return DRVMGR_FAIL;
+ }
+ pnpinfo = &ambadev->info;
+ priv->regs = (struct router_regs *)pnpinfo->ahb_slv->start[0];
+ priv->minor = dev->minor_drv;
+
+ /* Register character device in registered region */
+ router_hwinfo(priv, &priv->hwinfo);
+ priv->open = 0;
+ priv->nports = priv->hwinfo.nports_spw + priv->hwinfo.nports_amba +
+ priv->hwinfo.nports_fifo;
+ if ( (priv->nports < 2) || (priv->nports > 32) )
+ return DRVMGR_FAIL;
+
+ /* Get Filesystem name prefix */
+ prefix[0] = '\0';
+ if ( drvmgr_get_dev_prefix(dev, prefix) ) {
+ /* Failed to get prefix, make sure of a unique FS name
+ * by using the driver minor.
+ */
+ sprintf(priv->devName, "/dev/router%d", dev->minor_drv);
+ } else {
+ /* Got special prefix, this means we have a bus prefix
+ * And we should use our "bus minor"
+ */
+ sprintf(priv->devName, "/dev/%srouter%d", prefix, dev->minor_bus);
+ }
+
+ /* Register Device */
+ status = rtems_io_register_name(priv->devName, router_driver_io_major, dev->minor_drv);
+ if (status != RTEMS_SUCCESSFUL) {
+ return DRVMGR_FAIL;
+ }
+
+ return DRVMGR_OK;
+}
+
+int router_register_io(rtems_device_major_number *m)
+{
+ rtems_status_code r;
+
+ if ((r = rtems_io_register_driver(0, &router_driver, m)) == RTEMS_SUCCESSFUL) {
+ ROUTER_DBG("ROUTER driver successfully registered, major: %d\n", *m);
+ } else {
+ switch(r) {
+ case RTEMS_TOO_MANY:
+ printk("ROUTER rtems_io_register_driver failed: RTEMS_TOO_MANY\n");
+ return -1;
+ case RTEMS_INVALID_NUMBER:
+ printk("ROUTER rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n");
+ return -1;
+ case RTEMS_RESOURCE_IN_USE:
+ printk("ROUTER rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n");
+ return -1;
+ default:
+ printk("ROUTER rtems_io_register_driver failed\n");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static rtems_device_driver router_initialize(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg
+ )
+{
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver router_open(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+ )
+{
+ struct router_priv *priv;
+ struct drvmgr_dev *dev;
+
+ if ( drvmgr_get_dev(&router_drv_info.general, minor, &dev) ) {
+ ROUTER_DBG("Wrong minor %d\n", minor);
+ return RTEMS_INVALID_NAME;
+ }
+ priv = (struct router_priv *)dev->priv;
+
+ if ( !priv || priv->open ) {
+ return RTEMS_RESOURCE_IN_USE;
+ }
+
+ priv->open = 1;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver router_close(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+ )
+{
+ struct router_priv *priv;
+ struct drvmgr_dev *dev;
+
+ if ( drvmgr_get_dev(&router_drv_info.general, minor, &dev) ) {
+ ROUTER_DBG("Wrong minor %d\n", minor);
+ return RTEMS_INVALID_NAME;
+ }
+ priv = (struct router_priv *)dev->priv;
+
+ priv->open = 0;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+void router_hwinfo(struct router_priv *priv, struct router_hw_info *hwinfo)
+{
+ unsigned int tmp;
+
+ tmp = REG_READ(&priv->regs->cfgsts);
+ hwinfo->nports_spw = (tmp >> 27) & 0x1f;
+ hwinfo->nports_amba = (tmp >> 22) & 0x1f;
+ hwinfo->nports_fifo = (tmp >> 17) & 0x1f;
+ hwinfo->timers_avail = (tmp >> 1) & 0x1;
+ hwinfo->pnp_avail = (tmp >> 0) & 0x1;
+
+ tmp = REG_READ(&priv->regs->ver);
+ hwinfo->ver_major = (tmp >> 24) & 0xff;
+ hwinfo->ver_minor = (tmp >> 16) & 0xff;
+ hwinfo->ver_patch = (tmp >> 8) & 0xff;
+ hwinfo->iid = (tmp >> 0) & 0xff;
+}
+
+int router_config_set(struct router_priv *priv, struct router_config *cfg)
+{
+ int i;
+
+ if ( (cfg->flags & (ROUTER_FLG_TPRES|ROUTER_FLG_TRLD)) &&
+ !priv->hwinfo.timers_avail ) {
+ return RTEMS_NOT_IMPLEMENTED;
+ }
+
+ /* Write only configuration bits in Config register */
+ if ( cfg->flags & ROUTER_FLG_CFG ) {
+ REG_WRITE(&priv->regs->cfgsts, cfg->config & ~0x4);
+ }
+
+ /* Write Instance ID to Version Register */
+ if ( cfg->flags & ROUTER_FLG_IID ) {
+ REG_WRITE(&priv->regs->ver, cfg->iid);
+ }
+
+ /* Write startup-clock-divisor Register */
+ if ( cfg->flags & ROUTER_FLG_IDIV ) {
+ REG_WRITE(&priv->regs->idiv, cfg->idiv);
+ }
+
+ /* Write Timer Prescaler Register */
+ if ( cfg->flags & ROUTER_FLG_TPRES ) {
+ REG_WRITE(&priv->regs->tprescaler, cfg->timer_prescaler);
+ }
+
+ /* Write Timer Reload Register */
+ if ( cfg->flags & ROUTER_FLG_TRLD ) {
+ for (i=0; i<=priv->nports; i++)
+ REG_WRITE(&priv->regs->treload[i], cfg->timer_reload[i]);
+ }
+
+ return 0;
+}
+
+int router_config_read(struct router_priv *priv, struct router_config *cfg)
+{
+ int i;
+
+ cfg->config = REG_READ(&priv->regs->cfgsts) & ~0xffff0007;
+ cfg->iid = REG_READ(&priv->regs->ver) & 0xff;
+ cfg->idiv = REG_READ(&priv->regs->idiv) & 0xff;
+ cfg->timer_prescaler = REG_READ(&priv->regs->tprescaler);
+ for (i=0; i<=priv->nports; i++)
+ cfg->timer_reload[i] = REG_READ(&priv->regs->treload[i]);
+
+ return 0;
+}
+
+int router_routes_set(struct router_priv *priv, struct router_routes *routes)
+{
+ int i;
+ for (i=0; i<224; i++)
+ REG_WRITE(&priv->regs->routes[i], routes->route[i]);
+ return 0;
+}
+
+int router_routes_read(struct router_priv *priv, struct router_routes *routes)
+{
+ int i;
+ for (i=0; i<224; i++)
+ routes->route[i] = REG_READ(&priv->regs->routes[i]);
+ return 0;
+}
+
+int router_ps_set(struct router_priv *priv, struct router_ps *ps)
+{
+ int i;
+ unsigned int *p = &ps->ps[0];
+ for (i=0; i<255; i++,p++)
+ REG_WRITE(&priv->regs->psetup[i], *p);
+ return 0;
+}
+
+int router_ps_read(struct router_priv *priv, struct router_ps *ps)
+{
+ int i;
+ unsigned int *p = &ps->ps[0];
+ for (i=0; i<255; i++,p++)
+ REG_WRITE(&priv->regs->psetup[i], *p);
+ return 0;
+}
+
+int router_we_set(struct router_priv *priv, int we)
+{
+ REG_WRITE(&priv->regs->cfgwe, we & 0x1);
+ return 0;
+}
+
+int router_port_ctrl(struct router_priv *priv, struct router_port *port)
+{
+ unsigned int ctrl, sts;
+
+ if ( port->port > priv->nports )
+ return RTEMS_INVALID_NAME;
+
+ ctrl = port->ctrl;
+ if ( port->flag & ROUTER_PORTFLG_GET_CTRL ) {
+ ctrl = REG_READ(&priv->regs->pctrl[port->port]);
+ }
+ sts = port->sts;
+ if ( port->flag & ROUTER_PORTFLG_GET_STS ) {
+ sts = REG_READ(&priv->regs->psts[port->port]);
+ }
+
+ if ( port->flag & ROUTER_PORTFLG_SET_CTRL ) {
+ REG_WRITE(&priv->regs->pctrl[port->port], port->ctrl);
+ }
+ if ( port->flag & ROUTER_PORTFLG_SET_STS ) {
+ REG_WRITE(&priv->regs->psts[port->port], port->sts);
+ }
+
+ port->ctrl = ctrl;
+ port->sts = sts;
+ return 0;
+}
+
+int router_cfgsts_set(struct router_priv *priv, unsigned int cfgsts)
+{
+ REG_WRITE(&priv->regs->cfgsts, cfgsts);
+ return 0;
+}
+
+int router_cfgsts_read(struct router_priv *priv, unsigned int *cfgsts)
+{
+ *cfgsts = REG_READ(&priv->regs->cfgsts);
+ return 0;
+}
+
+int router_tc_read(struct router_priv *priv, unsigned int *tc)
+{
+ *tc = REG_READ(&priv->regs->timecode);
+ return 0;
+}
+
+static rtems_device_driver router_control(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+ )
+{
+ struct router_priv *priv;
+ struct drvmgr_dev *dev;
+ rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *) arg;
+ void *argp = (void *)ioarg->buffer;
+
+ if ( drvmgr_get_dev(&router_drv_info.general, minor, &dev) ) {
+ ROUTER_DBG("Wrong minor %d\n", minor);
+ return RTEMS_INVALID_NAME;
+ }
+ priv = (struct router_priv *)dev->priv;
+
+ ioarg->ioctl_return = 0;
+ switch (ioarg->command) {
+
+ /* Get Hardware support/information available */
+ case GRSPWR_IOCTL_HWINFO:
+ {
+ struct router_hw_info *hwinfo = argp;
+ router_hwinfo(priv, hwinfo);
+ break;
+ }
+
+ /* Set Router Configuration */
+ case GRSPWR_IOCTL_CFG_SET:
+ {
+ struct router_config *cfg = argp;
+ return router_config_set(priv, cfg);
+ }
+
+ /* Read Router Configuration */
+ case GRSPWR_IOCTL_CFG_GET:
+ {
+ struct router_config *cfg = argp;
+ router_config_read(priv, cfg);
+ break;
+ }
+
+ /* Routes */
+ case GRSPWR_IOCTL_ROUTES_SET:
+ {
+ struct router_routes *routes = argp;
+ return router_routes_set(priv, routes);
+ }
+
+ case GRSPWR_IOCTL_ROUTES_GET:
+ {
+ struct router_routes *routes = argp;
+ router_routes_read(priv, routes);
+ break;
+ }
+
+ /* Port Setup */
+ case GRSPWR_IOCTL_PS_SET:
+ {
+ struct router_ps *ps = argp;
+ return router_ps_set(priv, ps);
+ }
+
+ case GRSPWR_IOCTL_PS_GET:
+ {
+ struct router_ps *ps = argp;
+ router_ps_read(priv, ps);
+ break;
+ }
+
+ /* Set configuration write enable */
+ case GRSPWR_IOCTL_WE_SET:
+ {
+ return router_we_set(priv, (int)argp);
+ }
+
+ /* Set/Get Port Control/Status */
+ case GRSPWR_IOCTL_PORT:
+ {
+ struct router_port *port = argp;
+ int result;
+ if ( (result=router_port_ctrl(priv, port)) )
+ return result;
+ break;
+ }
+
+ /* Set Router Configuration/Status Register */
+ case GRSPWR_IOCTL_CFGSTS_SET:
+ {
+ return router_cfgsts_set(priv, (int)argp);
+ }
+
+ /* Get Router Configuration/Status Register */
+ case GRSPWR_IOCTL_CFGSTS_GET:
+ {
+ unsigned int *cfgsts = argp;
+ router_cfgsts_read(priv, cfgsts);
+ break;
+ }
+
+ /* Get Current Time-Code Register */
+ case GRSPWR_IOCTL_TC_GET:
+ {
+ unsigned int *tc = argp;
+ router_tc_read(priv, tc);
+ break;
+ }
+
+ default: return RTEMS_NOT_IMPLEMENTED;
+ }
+
+ return 0;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/spw/rmap.c b/c/src/lib/libbsp/sparc/shared/spw/rmap.c
new file mode 100644
index 0000000000..a3fe60f8bc
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/spw/rmap.c
@@ -0,0 +1,645 @@
+/* RMAP stack and RMAP driver interface implementation
+ *
+ * COPYRIGHT (c) 2009
+ * Aeroflex Gaisler.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2009-11-17, Daniel Hellstrom <daniel@gaisler.com>
+ * Created
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netinet/in.h>
+#include "rmap.h"
+
+#ifdef DEBUG
+ #define DBG(args...) printf(args);
+#else
+ #define DBG(args...)
+#endif
+
+static int rmap_stack_count = 0;
+
+static unsigned char RMAP_CRCTable[256] = {
+ 0x00, 0x91, 0xe3, 0x72, 0x07, 0x96, 0xe4, 0x75,
+ 0x0e, 0x9f, 0xed, 0x7c, 0x09, 0x98, 0xea, 0x7b,
+ 0x1c, 0x8d, 0xff, 0x6e, 0x1b, 0x8a, 0xf8, 0x69,
+ 0x12, 0x83, 0xf1, 0x60, 0x15, 0x84, 0xf6, 0x67,
+ 0x38, 0xa9, 0xdb, 0x4a, 0x3f, 0xae, 0xdc, 0x4d,
+ 0x36, 0xa7, 0xd5, 0x44, 0x31, 0xa0, 0xd2, 0x43,
+ 0x24, 0xb5, 0xc7, 0x56, 0x23, 0xb2, 0xc0, 0x51,
+ 0x2a, 0xbb, 0xc9, 0x58, 0x2d, 0xbc, 0xce, 0x5f,
+ 0x70, 0xe1, 0x93, 0x02, 0x77, 0xe6, 0x94, 0x05,
+ 0x7e, 0xef, 0x9d, 0x0c, 0x79, 0xe8, 0x9a, 0x0b,
+ 0x6c, 0xfd, 0x8f, 0x1e, 0x6b, 0xfa, 0x88, 0x19,
+ 0x62, 0xf3, 0x81, 0x10, 0x65, 0xf4, 0x86, 0x17,
+ 0x48, 0xd9, 0xab, 0x3a, 0x4f, 0xde, 0xac, 0x3d,
+ 0x46, 0xd7, 0xa5, 0x34, 0x41, 0xd0, 0xa2, 0x33,
+ 0x54, 0xc5, 0xb7, 0x26, 0x53, 0xc2, 0xb0, 0x21,
+ 0x5a, 0xcb, 0xb9, 0x28, 0x5d, 0xcc, 0xbe, 0x2f,
+ 0xe0, 0x71, 0x03, 0x92, 0xe7, 0x76, 0x04, 0x95,
+ 0xee, 0x7f, 0x0d, 0x9c, 0xe9, 0x78, 0x0a, 0x9b,
+ 0xfc, 0x6d, 0x1f, 0x8e, 0xfb, 0x6a, 0x18, 0x89,
+ 0xf2, 0x63, 0x11, 0x80, 0xf5, 0x64, 0x16, 0x87,
+ 0xd8, 0x49, 0x3b, 0xaa, 0xdf, 0x4e, 0x3c, 0xad,
+ 0xd6, 0x47, 0x35, 0xa4, 0xd1, 0x40, 0x32, 0xa3,
+ 0xc4, 0x55, 0x27, 0xb6, 0xc3, 0x52, 0x20, 0xb1,
+ 0xca, 0x5b, 0x29, 0xb8, 0xcd, 0x5c, 0x2e, 0xbf,
+ 0x90, 0x01, 0x73, 0xe2, 0x97, 0x06, 0x74, 0xe5,
+ 0x9e, 0x0f, 0x7d, 0xec, 0x99, 0x08, 0x7a, 0xeb,
+ 0x8c, 0x1d, 0x6f, 0xfe, 0x8b, 0x1a, 0x68, 0xf9,
+ 0x82, 0x13, 0x61, 0xf0, 0x85, 0x14, 0x66, 0xf7,
+ 0xa8, 0x39, 0x4b, 0xda, 0xaf, 0x3e, 0x4c, 0xdd,
+ 0xa6, 0x37, 0x45, 0xd4, 0xa1, 0x30, 0x42, 0xd3,
+ 0xb4, 0x25, 0x57, 0xc6, 0xb3, 0x22, 0x50, 0xc1,
+ 0xba, 0x2b, 0x59, 0xc8, 0xbd, 0x2c, 0x5e, 0xcf,
+};
+
+unsigned char rmap_crc_calc(unsigned char *data, unsigned int len)
+{
+ unsigned char crc = 0;
+ unsigned int i;
+ for (i = 0; i < len; i++) {
+ crc = RMAP_CRCTable[(crc ^ data[i]) & 0xff];
+ }
+ return crc;
+}
+
+struct rmap_priv {
+ struct rmap_config *config; /* Configuration */
+ void *drv_cookie; /* Driver private structure */
+ struct rmap_drv_timeout timeout; /* Driver timeout */
+ unsigned short tid; /* Current TID */
+ char drv_cap; /* Driver capabiliteis */
+ char running; /* 1 is started, 0 if stopped */
+ unsigned char blocking; /* Blocking mode */
+ unsigned char tx_pkt_hdr[256+9]; /* Packet header used for transmission, last 9 bytes is for RMW commands */
+ unsigned int _rx_pkt_buf; /* RX packet Buffer */
+ unsigned int *rx_pkt_buf; /* RX packet Buffer aligned to 64b*/
+ unsigned int rx_pkt_buf_len; /* RX packet Buffer length */
+ struct rmap_spw_pkt rxpkt; /* RX packet */
+ struct rmap_spw_pkt txpkt; /* TX packet */
+ rtems_id lock; /* Optional Semaphore protection against multiple threads (thread-safe) */
+};
+
+void *rmap_init(struct rmap_config *config)
+{
+ struct rmap_priv *priv;
+ int status;
+
+ priv = (struct rmap_priv *)malloc(sizeof(struct rmap_priv));
+ if ( !priv )
+ return NULL;
+
+ memset(priv, 0, sizeof(struct rmap_priv));
+ priv->config = config;
+ if ( config->tid_msb >= 0 ) {
+ priv->tid = config->tid_msb << 8;
+ }
+ priv->drv_cookie = priv->config->drv->cookie;
+
+ /* Create Semaphore used to make RMAP layer Thread-safe */
+ if ( config->thread_safe ) {
+ status = rtems_semaphore_create(
+ rtems_build_name('R', 'M', 'A', 'P' + rmap_stack_count++),
+ 1,
+ RTEMS_FIFO | RTEMS_COUNTING_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | \
+ RTEMS_LOCAL | RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &priv->lock);
+ if ( status != RTEMS_SUCCESSFUL ) {
+ printf("RMAP_INIT: Failed to create semaphore: %d\n", status);
+ free(priv);
+ return NULL;
+ }
+ DBG("RMAP_INIT: semaphore ID: 0x%x (%p)\n", priv->lock, &priv->lock);
+ }
+
+ return priv;
+}
+
+void rmap_init_rxpkt(struct rmap_priv *priv, struct rmap_spw_pkt *pkt)
+{
+ pkt->data = (unsigned char *)priv->rx_pkt_buf;
+ pkt->dlen = priv->rx_pkt_buf_len;
+ pkt->hlen = 0;
+ pkt->hdr = 0;
+ pkt->options = 0;
+}
+
+
+int rmap_start(struct rmap_priv *priv)
+{
+ if ( priv->running == 0 ) {
+ if ( !priv->_rx_pkt_buf ) {
+ /* Header length + Data CRC + 4 extra */
+ priv->rx_pkt_buf_len = priv->config->max_rx_len + 16 + 1 + 4;
+ priv->_rx_pkt_buf = (unsigned int)malloc(priv->rx_pkt_buf_len+4);
+ priv->rx_pkt_buf = (unsigned int*)((priv->_rx_pkt_buf+7)&~7);
+ if ( priv->rx_pkt_buf == NULL )
+ return -1;
+
+ }
+
+ /* Set blocking mode */
+ if ( priv->config->drv->ops.ioctl(priv->drv_cookie, RMAP_DRV_IOCTL_BLOCK, (void *)(int)priv->blocking) ){
+ /* Failed to set blocking mode */
+ return -1;
+ }
+
+ /* Set timeout, defualt is zero = Wait forever */
+ if ( priv->config->drv->ops.ioctl(priv->drv_cookie, RMAP_DRV_IOCTL_TIMEOUT, (void *)&priv->timeout) ){
+ /* Failed to set timeout */
+ return -1;
+ }
+
+ if ( priv->drv_cap == 0 ) {
+ unsigned int capabilities;
+ if ( priv->config->drv->ops.ioctl(priv->drv_cookie, RMAP_DRV_IOCTL_GET_CAP, &capabilities) ){
+ /* Failed to get capabilities, assume none */
+ priv->drv_cap = 0;
+ } else {
+ priv->drv_cap = capabilities & 0xff;
+ }
+ }
+
+ if ( priv->config->drv->ops.ioctl(priv->drv_cookie, RMAP_DRV_IOCTL_START, 0) ){
+ /* Failed to start */
+ return -1;
+ }
+
+ }
+ priv->running = 1;
+
+ return 0;
+}
+
+
+/* Disables the RMAP stack to send/receive commands */
+int rmap_stop(struct rmap_priv *priv)
+{
+ if ( priv->running == 0 )
+ return 0;
+
+ priv->running = 0;
+ if ( priv->config->drv->ops.ioctl(priv->drv_cookie, RMAP_DRV_IOCTL_STOP, 0) ){
+ /* Failed to start */
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Set operating mode */
+int rmap_set_blocking(struct rmap_priv *priv, unsigned int mode)
+{
+ if ( priv->running )
+ return -1;
+
+ if ( mode != RMAP_IOCTRL_BLOCK_ALL ) {
+ return -1;
+ }
+
+ priv->blocking = mode;
+
+ return 0;
+}
+
+/* Set Timeout */
+int rmap_set_timeout(struct rmap_priv *priv, struct rmap_drv_timeout *timeout)
+{
+ priv->timeout = *timeout;
+ if ( priv->config->drv->ops.ioctl(priv->drv_cookie, RMAP_DRV_IOCTL_TIMEOUT, timeout) ){
+ /* Failed to set timeout */
+ return -1;
+ }
+ return 0;
+}
+
+int rmap_get_config(struct rmap_priv *priv, struct rmap_config *result)
+{
+ if ( !result || !priv )
+ return -1;
+ *result = *priv->config;
+ return 0;
+}
+
+/* Configure stack (blocking etc)*/
+int rmap_ioctl(void *cookie, int command, void *arg)
+{
+ switch (command) {
+ case RMAP_IOCTL_START:
+ return rmap_start((struct rmap_priv *)cookie);
+ case RMAP_IOCTL_STOP:
+ return rmap_stop((struct rmap_priv *)cookie);
+ case RMAP_IOCTL_BLOCK:
+ return rmap_set_blocking((struct rmap_priv *)cookie, (unsigned int)arg);
+ case RMAP_IOCTL_TIMEOUT:
+ return rmap_set_timeout((struct rmap_priv *)cookie, (struct rmap_drv_timeout *)arg);
+ case RMAP_IOCTL_GET_CONFIG:
+ return rmap_get_config((struct rmap_priv *)cookie, (struct rmap_config *)arg);
+ default:
+ return -1;
+ }
+}
+
+int rmap_build(struct rmap_priv *priv, struct rmap_command *cmd, struct rmap_spw_pkt *txpkt)
+{
+ int len1, len2;
+ unsigned char *pos, *pkt = (unsigned char *)txpkt->hdr;
+ unsigned int length, src_path_len;
+ int options;
+
+ /* Begin with address translation */
+ if ( priv->config->route_func ) {
+ /* Custom translation */
+
+ /* Generate path addressing to destination */
+ len1 = 120;
+ priv->config->route_func(priv, 0, priv->config->spw_adr, cmd->dstadr, pkt, &len1);
+
+ /* Generate path addressing from destination */
+ len2 = 13;
+ priv->config->route_func(priv, 1, priv->config->spw_adr, cmd->dstadr, &pkt[len1+3], &len2);
+
+ } else {
+ pkt[0] = cmd->dstadr & 0xff;
+ pkt[4] = priv->config->spw_adr;
+ len1 = 1;
+ len2 = 1;
+ }
+ /* Protocol Identifier */
+ if ( len2 == 1 ) {
+ src_path_len = 0;
+ } else {
+ src_path_len = ((len2-1)+3) / 4;
+ }
+ pos = &pkt[len1];
+ *pos++ = 0x01;
+ *pos++ = 0x40 | (cmd->type << 2) | src_path_len;
+ *pos++ = cmd->dstkey;
+ pos += len2; /* Jump over address, len1 + 3 + len2 */
+ *pos++ = (priv->tid >> 8);
+ *pos++ = priv->tid & 0xff;
+ cmd->tid = priv->tid; /* Remember TID */
+ /* Increment TID */
+ if ( priv->config->tid_msb < 0 ) {
+ priv->tid++;
+ } else {
+ if ( (priv->tid & 0xff) == 0xff) {
+ priv->tid = priv->tid & 0xff00;
+ } else {
+ priv->tid++;
+ }
+ }
+
+ /* Address */
+ *pos++ = (cmd->address >> 32) & 0xff; /* Extended Address */
+ *pos++ = (cmd->address >> 24) & 0xff;
+ *pos++ = (cmd->address >> 16) & 0xff;
+ *pos++ = (cmd->address >> 8) & 0xff;
+ *pos++ = cmd->address & 0xff;
+ /* pos = pkt[len1+3+len2+7] */
+ if ( cmd->type & RMAP_CMD_WRITE ) { /* WRITE */
+ length = cmd->data.write.length;
+ } else if ( cmd->type == RMAP_CMD_RMWI ) { /* READ-MODIFY_WRITE */
+ length = cmd->data.read_m_write.length * 2;
+ } else { /* READ */
+ length = cmd->data.read.length;
+ }
+ *pos++ = (length >> 16) & 0xff;
+ *pos++ = (length >> 8) & 0xff;
+ *pos++ = length & 0xff;
+ txpkt->hlen = pos - pkt; /* HDR CRC is fixed later */
+
+ if ( cmd->type & RMAP_CMD_WRITE ) { /* WRITE */
+ txpkt->dlen = length;
+ if ( cmd->data.write.data > 0 ) {
+ txpkt->data = cmd->data.write.data; /* CRC will be added later */
+ } else {
+ txpkt->data = ((char *)&txpkt->dlen + 1); /* Temporary storage of CRC when no data */
+ }
+ } else if ( cmd->type == RMAP_CMD_RMWI ) { /* READ-MODIFY_WRITE */
+ txpkt->dlen = length; /* CRC will be added later */
+ txpkt->data = &txpkt->hdr[256];
+ if ( cmd->data.read_m_write.length == 4 ) {
+ /* 4byte */
+ txpkt->hdr[256] = (cmd->data.read_m_write.data >> 24) & 0xff;
+ txpkt->hdr[257] = (cmd->data.read_m_write.data >> 16) & 0xff;
+ txpkt->hdr[258] = (cmd->data.read_m_write.data >> 8) & 0xff;
+ txpkt->hdr[259] = cmd->data.read_m_write.data & 0xff;
+
+ txpkt->hdr[260] = (cmd->data.read_m_write.mask >> 24) & 0xff;
+ txpkt->hdr[261] = (cmd->data.read_m_write.mask >> 16) & 0xff;
+ txpkt->hdr[262] = (cmd->data.read_m_write.mask >> 8) & 0xff;
+ txpkt->hdr[263] = cmd->data.read_m_write.mask & 0xff;
+ } else if ( cmd->data.read_m_write.length == 1 ) {
+ /* 1byte */
+ txpkt->hdr[256] = cmd->data.read_m_write.data & 0xff;
+ txpkt->hdr[257] = cmd->data.read_m_write.mask & 0xff;
+ } else if ( cmd->data.read_m_write.length == 2 ) {
+ /* 2byte */
+ txpkt->hdr[256] = (cmd->data.read_m_write.data >> 8) & 0xff;
+ txpkt->hdr[257] = cmd->data.read_m_write.data & 0xff;
+
+ txpkt->hdr[258] = (cmd->data.read_m_write.mask >> 8) & 0xff;
+ txpkt->hdr[259] = cmd->data.read_m_write.mask & 0xff;
+ } else {
+ /* Wrong input */
+ return -1;
+ }
+ } else { /* READ */
+ txpkt->dlen = 0;
+ txpkt->data = NULL;
+ }
+
+ /*** CRC ***/
+ if ( len1 > 1 ) /* PATH target address not part of Header CRC */
+ options = PKT_OPTION_HDR_CRC_SKIPLEN(len1-1);
+ else
+ options = 0;
+
+ /* HEADER CRC */
+ if ( priv->drv_cap & DRV_CAP_HDR_CRC ) {
+ options |= PKT_OPTION_HDR_CRC;
+ } else {
+ /* Generate CRC and put it at the end of data buffer, Don't calculate
+ * CRC on Destination Path address.
+ */
+ unsigned char crc;
+ crc = rmap_crc_calc(&txpkt->hdr[len1-1], txpkt->hlen - (len1-1));
+ ((unsigned char *)txpkt->hdr)[txpkt->hlen] = crc;
+ txpkt->hlen++;
+ }
+ /* DATA CRC */
+ if ( txpkt->data ) {
+ if ( txpkt->dlen == 0 ) {
+ /* Need to put CRC even when no data available,
+ * CRC will always be 0x00
+ */
+ ((unsigned char *)txpkt->data)[0] = 0x00;
+ txpkt->dlen = 1;
+ } else if ( priv->drv_cap & DRV_CAP_DATA_CRC ) {
+ options |= PKT_OPTION_DATA_CRC;
+ } else {
+ /* Generate CRC and put it at the end of data buffer */
+ unsigned char crc;
+ crc = rmap_crc_calc(txpkt->data, txpkt->dlen);
+ ((unsigned char *)txpkt->data)[txpkt->dlen] = crc;
+ txpkt->dlen++;
+ }
+ }
+
+ txpkt->options = options;
+
+ return 0;
+}
+
+int rmap_parse(struct rmap_priv *priv, struct rmap_command *cmd, struct rmap_spw_pkt *rxpkt)
+{
+ unsigned char *pkt;
+ unsigned int length;
+
+ pkt = rxpkt->data;
+
+ /* Check that the protocol ID, Replay and TID matches before proceeding */
+ if ( (pkt[1] != 0x01) || ((pkt[2] & 0x40) != 0) ||
+ (pkt[5] != (cmd->tid>>8)) || (pkt[6] != (cmd->tid & 0xff))) {
+ return -1;
+ }
+
+ cmd->status = pkt[3];
+ if ( cmd->type & RMAP_CMD_WRITE ){
+ return 0;
+ }
+
+ if ( cmd->type == RMAP_CMD_RMWI ) {
+ /* Copy data content */
+ cmd->data.read_m_write.oldlength = length = pkt[10];
+ if ( length == 4 ) {
+ cmd->data.read_m_write.olddata = ntohl(*(unsigned int *)&pkt[12]);
+ } else if ( length == 1 ){
+ cmd->data.read_m_write.olddata = pkt[12];
+ } else if ( length == 2 ) {
+ cmd->data.read_m_write.olddata = ntohs(*(unsigned short *)&pkt[12]);
+ } else {
+ cmd->data.read_m_write.olddata = 0;
+ }
+ return 0;
+ }
+
+ /* READ COMMAND RESPONSE - copy data */
+ if ( cmd->status != 0 ) {
+ /* Error status, skip other bytes */
+ return 0;
+ }
+
+ /* Length may be equal or less than request nembuer of bytes */
+ cmd->data.read.datalength = length = (pkt[8]<<16) | (pkt[9]<<8) | pkt[10];
+ if ( length > cmd->data.read.length ) {
+ printf("Response DATA Length != Command Data Length [%p, %p]\n",
+ cmd, pkt);
+ return -1;
+ }
+ if ( length > 0 ) {
+ memcpy(cmd->data.read.data, &pkt[12], length);
+ }
+
+ return 0;
+}
+
+int rmap_send(void *cookie, struct rmap_command *cmd)
+{
+ struct rmap_priv *priv = cookie;
+ struct rmap_drv *drv;
+ int wait_response;
+ int ret=0, status;
+ struct rmap_spw_pkt *txpkt, *rxpkt;
+
+ if ( !priv || !cmd || !priv->running )
+ return -1;
+
+ /*** Check invalid command type ***/
+ if ( (cmd->type > RMAP_CMD_WIVA) ||
+ ((cmd->type < RMAP_CMD_RMWI) && (cmd->type != RMAP_CMD_RS) && (cmd->type != RMAP_CMD_RI))
+ )
+ return -1;
+ if ( (cmd->type == RMAP_CMD_RMWI) && (cmd->data.read_m_write.length != 1) &&
+ (cmd->data.read_m_write.length != 2) && (cmd->data.read_m_write.length != 4)
+ )
+ return -1;
+
+ /*** Determine if stack must wait for response to arrive after transmission ***/
+ wait_response = 0;
+ if ( ((cmd->type & RMAP_CMD_WRITE) == 0) || /* READ ALWAYS RETURNS DATA */
+ (cmd->type & RMAP_CMD_ACKNOWLEDGE) /* WAIT FOR ACK */
+ )
+ wait_response = 1;
+
+ /*** Check that READ/WRITE length is within boundaries ***/
+ if ( (cmd->type & RMAP_CMD_WRITE) && (cmd->data.write.length > (priv->config->max_tx_len-4)) ) {
+ return -1;
+ }
+ if ( ((cmd->type & RMAP_CMD_WRITE) == 0) && (cmd->data.read.length > (priv->config->max_rx_len)) ) {
+ return -1;
+ }
+
+ if ( priv->lock ) {
+ status = rtems_semaphore_obtain(priv->lock, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+ if ( status != RTEMS_SUCCESSFUL ) {
+ printf("RMAP-STACK: FAILED TO OBTAIN LOCK: %d (%p)\n",
+ status, priv->lock);
+ return -1;
+ }
+ }
+
+ /*** Alloc RX/TX packet ***/
+ txpkt = &priv->txpkt;
+ rxpkt = &priv->rxpkt;
+
+ /*** Build command ***/
+ txpkt->hdr = &priv->tx_pkt_hdr[0];
+ txpkt->hlen = 0;
+ txpkt->data = NULL;
+ txpkt->dlen = 0;
+ txpkt->options = 0;
+ if ( rmap_build(priv, cmd, txpkt) ){
+ ret = -1;
+ goto out_sem;
+ }
+
+ /*** Send command ***/
+ drv = priv->config->drv;
+ if ( !drv->ops.send ){
+ ret = -1;
+ goto out_sem;
+ }
+
+ /* Schedule packet for transmission */
+ status = drv->ops.send(priv->drv_cookie, txpkt);
+ if ( status ) {
+ /* Failed to schedule packet */
+ ret = -1;
+ goto out_sem;
+ }
+ cmd->status = 0;
+
+ /*** Wait for response ***/
+ if ( wait_response ) {
+retry:
+ rmap_init_rxpkt(priv, rxpkt);
+ status = drv->ops.recv(priv->drv_cookie, rxpkt);
+ if ( status < 1 ) {
+ /* Failed to receive packet, for example timeout driver error
+ * or driver not in blocking mode.
+ */
+ ret = -2;
+ goto out_sem;
+ }
+ /*** ONE RECEIVED PACKET ***/
+
+ /* Parse input packet */
+ if ( rmap_parse(priv, cmd, rxpkt) == -1 ) {
+ /* Got wrong packet, for example wrong TID */
+ DBG("RMAP: wrong packet\n");
+ goto retry;
+ }
+ }
+
+out_sem:
+ if ( priv->lock ) {
+ rtems_semaphore_release(priv->lock);
+ }
+ return ret;
+}
+
+int rmap_write(void *cookie, void *dst, void *buf, int length, int dstadr, int dstkey)
+{
+ struct rmap_command_write writecmd;
+ int status;
+
+ /* Build RMAP Write Command. Do not use Verify Write */
+ writecmd.type = RMAP_CMD_WI;
+ /*writecmd.type = RMAP_CMD_WIV;*/
+ writecmd.dstadr = dstadr;
+ writecmd.dstkey = dstkey;
+ writecmd.address = (unsigned int)dst;
+ writecmd.length = length;
+ writecmd.data = (unsigned char *)buf;
+
+#ifdef DEBUG
+ if ( length == 4 ) {
+ printf("RMAP_WRITE(4): 0x%08x <== 0x%08x\n", dst, *(unsigned int *)buf);
+ } else {
+ printf("RMAP_WRITE: 0x%08x - 0x%08x\n", dst, ((unsigned int)dst)+(length-1));
+ }
+#endif
+
+ /* Send Command */
+ status = rmap_send(cookie, (struct rmap_command *)&writecmd);
+ if ( status ) {
+ printf("GRTMPAHB WRITE: Failed to send/receive command %d\n", status);
+ return -1;
+ }
+
+ /* Read Data */
+ if ( writecmd.status != 0 ) {
+ printf("GRTMPAHB WRITE: Status non-zero 0x%x, address: 0x%llx\n",
+ writecmd.status, writecmd.address);
+ return -1;
+ }
+
+ /* Return sucessful */
+ return 0;
+}
+
+int rmap_read(void *cookie, void *src, void *buf, int length, int dstadr, int dstkey)
+{
+ /* Send it, and wait for result */
+ struct rmap_command_read readcmd;
+ int status;
+
+ /* Build RMAP READ Command */
+ readcmd.type = RMAP_CMD_RI;
+ readcmd.dstadr = dstadr;
+ readcmd.dstkey = dstkey;
+ readcmd.address = (unsigned int)src;
+ readcmd.length = length;
+ readcmd.datalength = 0;
+ readcmd.data = buf;
+
+ DBG("RMAP READ1: 0x%08x - 0x%08x\n", (unsigned int)src, ((unsigned int)src + (readcmd.length - 1)));
+
+ /* Send Command */
+ status = rmap_send(cookie, (struct rmap_command *)&readcmd);
+ if ( status ) {
+ printf("RMAP READ: Failed to send/receive command %d\n", status);
+ memset(buf, 0, length);
+ /* Should we remove device? */
+ return -1;
+ }
+
+ /* Read Data */
+ if ( readcmd.status != 0 ) {
+ printf("RMAP READ: Status non-zero 0x%x, dlen: 0x%x\n", readcmd.status, readcmd.datalength);
+ memset(buf, 0, length);
+ /* Should we remove device? */
+ return -1;
+ }
+
+#ifdef DEBUG
+ if ( length == 4 ) {
+ printf("RMAP READ2: 0x%08x(4): 0x%08x\n", (unsigned int)src, *(unsigned int *)buf);
+ } else {
+ printf("RMAP READ2: 0x%08x - 0x%08x\n", (unsigned int)src, ((unsigned int)src)+(length-1));
+ }
+#endif
+
+ /* Return sucessful */
+ return 0;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/spw/rmap_drv_grspw.c b/c/src/lib/libbsp/sparc/shared/spw/rmap_drv_grspw.c
new file mode 100644
index 0000000000..83a0b04266
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/spw/rmap_drv_grspw.c
@@ -0,0 +1,161 @@
+/* GRSPW RMAP Driver it use the standard GRSPW RTEMS DRIVER
+ *
+ * COPYRIGHT (c) 2009
+ * Aeroflex Gaisler.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2009-11-17, Daniel Hellstrom <daniel@gaisler.com>
+ * Created
+ */
+
+#include <rtems.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <grspw.h>
+#include "rmap.h"
+#include "rmap_drv_grspw.h"
+
+struct rmap_drv_grspw_priv {
+ struct rmap_drv_grspw_config *config;
+};
+
+void *rmap_drv_grspw_init(struct rmap_drv_grspw_config *config)
+{
+ struct rmap_drv_grspw_priv *priv;
+
+ priv = (struct rmap_drv_grspw_priv *)malloc(sizeof(struct rmap_drv_grspw_priv));
+ if ( !priv )
+ return NULL;
+ memset(priv, 0, sizeof(struct rmap_drv_grspw_priv));
+
+ priv->config = config;
+
+ return priv;
+}
+
+int rmap_drv_grspw_ops_init(void *cookie)
+{
+ /*struct rmap_drv_grspw_priv *priv = cookie;*/
+ return 0;
+}
+
+int rmap_drv_grspw_get_cap(struct rmap_drv_grspw_priv *priv, unsigned int *result)
+{
+ spw_config grspw_config;
+ int status;
+ unsigned int options;
+
+ status = ioctl(priv->config->fd, SPACEWIRE_IOCTRL_GET_CONFIG, &grspw_config);
+ if ( status != 0 ) {
+ *result = 0;
+ return -1;
+ }
+
+ /* Get capabilities from GRSPW driver */
+ options = 0;
+ if ( grspw_config.is_rmap || grspw_config.is_rmapcrc )
+ options |= (PKT_OPTION_HDR_CRC | PKT_OPTION_DATA_CRC);
+
+ *result = options;
+
+ return 0;
+}
+
+int rmap_drv_grspw_set_rtimeout(struct rmap_drv_grspw_priv *priv, unsigned int timeout)
+{
+ int status;
+
+ status = ioctl(priv->config->fd, SPACEWIRE_IOCTRL_SET_READ_TIMEOUT, timeout);
+ if ( status != 0 ) {
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int rmap_drv_grspw_ops_ioctl(void *cookie, int command, void *arg)
+{
+ struct rmap_drv_grspw_priv *priv = cookie;
+ struct rmap_drv_timeout *timeout;
+
+ switch ( command ) {
+ case RMAP_DRV_IOCTL_START:
+ case RMAP_DRV_IOCTL_STOP:
+ case RMAP_DRV_IOCTL_BLOCK: /* Only blocking mode supported */
+ break;
+ case RMAP_DRV_IOCTL_TIMEOUT: /* Only Read timeout support */
+ timeout = arg;
+ if ( timeout->options & RMAP_TIMEOUT_SET_RTIME ) {
+ /* Set read timeout */
+ rmap_drv_grspw_set_rtimeout(priv, timeout->rtimeout);
+ }
+ break;
+ case RMAP_DRV_IOCTL_GET_CAP: /* No DATA/HEADER CRC capabilities */
+ return rmap_drv_grspw_get_cap(cookie, (unsigned int *)arg);
+ default:
+ return -1;
+ }
+ return 0;
+}
+
+int rmap_drv_grspw_ops_send(void *cookie, struct rmap_spw_pkt *pkt)
+{
+ struct rmap_drv_grspw_priv *priv = cookie;
+ spw_ioctl_pkt_send *grspw_pkt;
+ int status;
+
+ grspw_pkt = (spw_ioctl_pkt_send *)&pkt->hlen;
+ grspw_pkt->options = pkt->options & (PKT_OPTION_HDR_CRC_SKIPLEN_MASK|
+ PKT_OPTION_DATA_CRC|PKT_OPTION_HDR_CRC);
+ grspw_pkt->sent = 0;
+
+ /* Send packet by using the IOCTL SEND method, it takes separate header and data arguments */
+ status = ioctl(priv->config->fd, SPACEWIRE_IOCTRL_SEND, grspw_pkt);
+ if ( status < 0 ) {
+ return -1;
+ }
+ return 0;
+}
+
+int rmap_drv_grspw_ops_recv(void *cookie, struct rmap_spw_pkt *pkt)
+{
+ struct rmap_drv_grspw_priv *priv = cookie;
+ int len;
+
+ if ( !pkt->data ) {
+ return -1;
+ }
+
+ len = read(priv->config->fd, pkt->data, pkt->dlen);
+ if ( len < 0 ) {
+ printf("RMAP_DRV_GRSPW: Error reading: %s (%d, %d)", strerror(errno), errno, len);
+ return -1;
+ } else if ( len == 0 ) {
+ if ( errno == ETIMEDOUT ) {
+ /* Read Timeout */
+ return -2;
+ }
+ return -1;
+ }
+
+ /* Update packet size */
+ pkt->dlen = len;
+
+ return 1; /* Received one packet */
+}
+
+struct rmap_drv_ops rmap_grspw_ops =
+{
+ .init = rmap_drv_grspw_ops_init,
+ .ioctl = rmap_drv_grspw_ops_ioctl,
+ .send = rmap_drv_grspw_ops_send,
+ .recv = rmap_drv_grspw_ops_recv
+};
diff --git a/c/src/lib/libbsp/sparc/shared/startup/early_malloc.c b/c/src/lib/libbsp/sparc/shared/startup/early_malloc.c
new file mode 100644
index 0000000000..c6abaca2b1
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/startup/early_malloc.c
@@ -0,0 +1,44 @@
+/*
+ * Early dynamic memory allocation (not freeable) for BSP
+ * boot routines. Minimum alignment 8 bytes. Memory is
+ * allocated after _end, it will shrink the workspace.
+ *
+ * COPYRIGHT (c) 2011.
+ * Aeroflex Gaisler AB
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id: early_malloc.c
+ */
+
+#include <bsp.h>
+#include <stdlib.h>
+
+/* Tells us where to put the workspace in case remote debugger is present. */
+extern uint32_t rdb_start;
+
+/* Must be aligned to 8 */
+extern unsigned int early_mem;
+
+/* must be identical to STACK_SIZE in start.S */
+#define STACK_SIZE (16 * 1024)
+
+void *bsp_early_malloc(int size)
+{
+ void *start;
+
+ /* Not early anymore? */
+ if (early_mem == ~0)
+ return malloc(size);
+
+ size = (size + 7) & ~0x7;
+ if (rdb_start - STACK_SIZE - early_mem < size)
+ return NULL;
+
+ start = (void *)early_mem;
+ early_mem += size;
+
+ return start;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/time/grctm.c b/c/src/lib/libbsp/sparc/shared/time/grctm.c
new file mode 100644
index 0000000000..96b1ec4e63
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/time/grctm.c
@@ -0,0 +1,410 @@
+/* GRCTM - CCSDS Time Manager - register driver interface.
+ *
+ * COPYRIGHT (c) 2009.
+ * Aeroflex Gaisler AB
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ */
+
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+#include <stdlib.h>
+
+#include <grctm.h>
+
+/* Private structure of GRCTM driver */
+struct grctm_priv {
+ struct drvmgr_dev *dev;
+ struct grctm_regs *regs;
+ int open;
+
+ grctm_isr_t user_isr;
+ void *user_isr_arg;
+
+ struct grctm_stats stats;
+};
+
+void grctm_isr(void *data);
+
+struct amba_drv_info grctm_drv_info;
+
+void *grctm_open(int minor)
+{
+ struct grctm_priv *priv;
+ struct drvmgr_dev *dev;
+
+ /* Get Device from Minor */
+ if ( drvmgr_get_dev(&grctm_drv_info.general, minor, &dev) ) {
+ return NULL;
+ }
+
+ priv = dev->priv;
+ if ( (priv == NULL) || priv->open )
+ return NULL;
+
+ /* Set initial state of software */
+ priv->open = 1;
+
+ /* Clear Statistics */
+ grctm_clr_stats(priv);
+ priv->user_isr = NULL;
+ priv->user_isr_arg = NULL;
+
+ return priv;
+}
+
+void grctm_close(void *grctm)
+{
+ struct grctm_priv *priv = (struct grctm_priv *)grctm;
+
+ if ( priv->open == 0 )
+ return;
+
+ /* Reset Hardware */
+ grctm_reset(priv);
+
+ priv->open = 0;
+}
+
+/* Hardware Reset of GRCTM */
+int grctm_reset(void *grctm)
+{
+ struct grctm_priv *priv = grctm;
+ struct grctm_regs *r = priv->regs;
+
+ r->grr = 0x55000001;
+
+ int i = 1000;
+ while ((r->grr & 1) && i > 0) {
+ i--;
+ }
+
+ return i ? 0 : -1;
+}
+
+void grctm_int_enable(void *grctm)
+{
+ struct grctm_priv *priv = (struct grctm_priv *)grctm;
+
+ /* Register and Enable Interrupt at Interrupt controller */
+ drvmgr_interrupt_register(priv->dev, 0, "grctm", grctm_isr, priv);
+}
+
+void grctm_int_disable(void *grctm)
+{
+ struct grctm_priv *priv = (struct grctm_priv *)grctm;
+
+ /* Enable Interrupt at Interrupt controller */
+ drvmgr_interrupt_unregister(priv->dev, 0, grctm_isr, priv);
+}
+
+void grctm_clr_stats(void *grctm)
+{
+ struct grctm_priv *priv = (struct grctm_priv *)grctm;
+
+ memset(&priv->stats, 0, sizeof(priv->stats));
+}
+
+void grctm_get_stats(void *grctm, struct grctm_stats *stats)
+{
+ struct grctm_priv *priv = (struct grctm_priv *)grctm;
+
+ memcpy(stats, &priv->stats, sizeof(priv->stats));
+}
+
+/* Enable external synchronisation (from grctm) */
+void grctm_enable_ext_sync(void *grctm)
+{
+ struct grctm_priv *priv = grctm;
+
+ priv->regs->gcr |= 0x55<<24 | 1<<9;
+}
+
+/* Disable external synchronisation (from grctm) */
+void grctm_disable_ext_sync(void *grctm)
+{
+ struct grctm_priv *priv = grctm;
+
+ priv->regs->gcr &= ~((0xAA<<24) | 1<<9);
+}
+
+/* Enable TimeWire synchronisation */
+void grctm_enable_tw_sync(void *grctm)
+{
+ struct grctm_priv *priv = grctm;
+
+ priv->regs->gcr |= 0x55<<24 | 1<<8;
+}
+
+/* Disable TimeWire synchronisation */
+void grctm_disable_tw_sync(void *grctm)
+{
+ struct grctm_priv *priv = grctm;
+
+ priv->regs->gcr &= ~((0xAA<<24) | 1<<8);
+}
+
+/* Disable frequency synthesizer from driving ET */
+void grctm_disable_fs(void *grctm)
+{
+ struct grctm_priv *priv = grctm;
+
+ priv->regs->gcr |= 0x55<<24 | 1<<7;
+}
+
+/* Enable frequency synthesizer to drive ET */
+void grctm_enable_fs(void *grctm)
+{
+ struct grctm_priv *priv = grctm;
+
+ priv->regs->gcr &= ~((0xAA<<24) | 1<<7);
+}
+
+/* Return elapsed coarse time */
+unsigned int grctm_get_et_coarse(void *grctm)
+{
+ struct grctm_priv *priv = grctm;
+
+ return priv->regs->etcr;
+}
+
+/* Return elapsed fine time */
+unsigned int grctm_get_et_fine(void *grctm)
+{
+ struct grctm_priv *priv = grctm;
+
+ return (priv->regs->etfr & 0xffffff00) >> 8;
+}
+
+/* Return elapsed time (coarse and fine) */
+unsigned long long grctm_get_et(void *grctm)
+{
+ return (((unsigned long)grctm_get_et_coarse(grctm)) << 24) | grctm_get_et_fine(grctm);
+}
+
+
+/* Return 1 if specified datation has been latched */
+int grctm_is_dat_latched(void *grctm, int dat)
+{
+ struct grctm_priv *priv = grctm;
+
+ return (priv->regs->gsr >> dat) & 1;
+}
+
+/* Set triggering edge of datation input */
+void grctm_set_dat_edge(void *grctm, int dat, int edge)
+{
+ struct grctm_priv *priv = grctm;
+
+ priv->regs->gcr &= ~((0xAA<<24) | 1 << (10+dat));
+ priv->regs->gcr |= 0x55<<24 | (edge&1) << (10+dat);
+}
+
+/* Return latched datation coarse time */
+unsigned int grctm_get_dat_coarse(void *grctm, int dat)
+{
+ struct grctm_priv *priv = grctm;
+
+ switch (dat) {
+ case 0 : return priv->regs->dcr0;
+ case 1 : return priv->regs->dcr1;
+ case 2 : return priv->regs->dcr2;
+ default: return -1;
+ }
+}
+
+/* Return latched datation fine time */
+unsigned int grctm_get_dat_fine(void *grctm, int dat)
+{
+ struct grctm_priv *priv = grctm;
+
+ switch (dat) {
+ case 0 : return (priv->regs->dfr0 & 0xffffff00) >> 8;
+ case 1 : return (priv->regs->dfr1 & 0xffffff00) >> 8;
+ case 2 : return (priv->regs->dfr2 & 0xffffff00) >> 8;
+ default: return -1;
+ }
+}
+
+
+/* Return latched datation ET */
+unsigned long long grctm_get_dat_et(void *grctm, int dat)
+{
+ return (((unsigned long)grctm_get_dat_coarse(grctm, dat)) << 24) |
+ grctm_get_dat_fine(grctm, dat);
+}
+
+
+/* Return current pulse configuration */
+unsigned int grctm_get_pulse_reg(void *grctm, int pulse)
+{
+ struct grctm_priv *priv = grctm;
+
+ return priv->regs->pdr[pulse];
+}
+
+/* Set pulse register */
+void grctm_set_pulse_reg(void *grctm, int pulse, unsigned int val)
+{
+ struct grctm_priv *priv = grctm;
+
+ priv->regs->pdr[pulse] = val;
+}
+
+/* Configure pulse: pp = period, pw = width, pl = level, en = enable */
+void grctm_cfg_pulse(void *grctm, int pulse, int pp, int pw, int pl, int en)
+{
+ grctm_set_pulse_reg(grctm, pulse, (pp&0xf)<<20 | (pw&0xf)<<16 | (pl&1)<<10 | (en&1)<<1);
+}
+
+/* Enable pulse output */
+void grctm_enable_pulse(void *grctm, int pulse)
+{
+ struct grctm_priv *priv = grctm;
+
+ priv->regs->pdr[pulse] |= 0x2;
+}
+
+/* Disable pulse output */
+void grctm_disable_pulse(void *grctm, int pulse)
+{
+ struct grctm_priv *priv = grctm;
+
+ priv->regs->pdr[pulse] &= ~0x2;
+}
+
+/* Clear interrupts */
+void grctm_clear_irqs(void *grctm, int irqs)
+{
+ struct grctm_priv *priv = grctm;
+
+ priv->regs->picr = irqs;
+}
+
+/* Enable interrupts */
+void grctm_enable_irqs(void *grctm, int irqs)
+{
+ struct grctm_priv *priv = grctm;
+
+ priv->regs->imr = irqs;
+}
+
+/* Set Frequency synthesizer increment */
+void grctm_set_fs_incr(void *grctm, int incr)
+{
+ struct grctm_priv *priv = grctm;
+
+ priv->regs->fsir = incr;
+}
+
+/* Set ET increment */
+void grctm_set_et_incr(void *grctm, int incr)
+{
+ struct grctm_priv *priv = grctm;
+
+ priv->regs->etir = incr;
+}
+
+
+void grctm_isr(void *data)
+{
+ struct grctm_priv *priv = data;
+ struct grctm_stats *stats = &priv->stats;
+ unsigned int pimr = priv->regs->pimr;
+
+ if ( pimr == 0 )
+ return;
+
+ stats->nirqs++;
+ if (pimr & PULSE0_IRQ )
+ stats->pulse++;
+
+ /* Let user Handle Interrupt */
+ if ( priv->user_isr )
+ priv->user_isr(pimr, priv->user_isr_arg);
+}
+
+struct grctm_regs *grctm_get_regs(void *grctm)
+{
+ struct grctm_priv *priv = (struct grctm_priv *)grctm;
+
+ return priv->regs;
+}
+
+void grctm_int_register(void *grctm, grctm_isr_t func, void *data)
+{
+ struct grctm_priv *priv = (struct grctm_priv *)grctm;
+
+ priv->user_isr = func;
+ priv->user_isr_arg = data;
+}
+
+/*** INTERFACE TO DRIVER MANAGER ***/
+
+int grctm_init2(struct drvmgr_dev *dev)
+{
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
+ struct grctm_priv *priv;
+ struct grctm_regs *regs;
+
+ priv = (struct grctm_priv *)malloc(sizeof(*priv));
+ if ( priv == NULL )
+ return -1;
+ memset(priv, 0, sizeof(*priv));
+ priv->dev = dev;
+ dev->priv = priv;
+
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)dev->businfo;
+ if ( ambadev == NULL ) {
+ return -1;
+ }
+ pnpinfo = &ambadev->info;
+ regs = (struct grctm_regs *)pnpinfo->ahb_slv->start[0];
+
+ priv->regs = regs;
+
+ grctm_reset(priv);
+
+ return 0;
+}
+
+struct drvmgr_drv_ops grctm_ops =
+{
+ {NULL, grctm_init2, NULL, NULL},
+ NULL,
+ NULL
+};
+
+struct amba_dev_id grctm_ids[] =
+{
+ {VENDOR_GAISLER, GAISLER_GRCTM},
+ {0, 0} /* Mark end of table */
+};
+
+struct amba_drv_info grctm_drv_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_AMBAPP_GAISLER_GRCTM_ID, /* Driver ID */
+ "GRCTM_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */
+ &grctm_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ 0,
+ },
+ &grctm_ids[0]
+};
+
+/* Register the grctm Driver */
+void grctm_register(void)
+{
+ drvmgr_drv_register(&grctm_drv_info.general);
+}
diff --git a/c/src/lib/libbsp/sparc/shared/time/spwcuc.c b/c/src/lib/libbsp/sparc/shared/time/spwcuc.c
new file mode 100644
index 0000000000..ae8c875179
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/time/spwcuc.c
@@ -0,0 +1,370 @@
+/* SPWCUC - SpaceWire - CCSDS unsegmented Code Transfer Protocol GRLIB core
+ * register driver interface.
+ *
+ * COPYRIGHT (c) 2009.
+ * Aeroflex Gaisler AB
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ */
+
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+#include <stdlib.h>
+
+#include <spwcuc.h>
+
+/* Private structure of SPWCUC driver. */
+struct spwcuc_priv {
+ struct drvmgr_dev *dev;
+ struct spwcuc_regs *regs;
+ int open;
+
+ spwcuc_isr_t user_isr;
+ void *user_isr_arg;
+
+ struct spwcuc_stats stats;
+};
+
+void spwcuc_isr(void *data);
+
+struct amba_drv_info spwcuc_drv_info;
+
+/* Hardware Reset of SPWCUC */
+int spwcuc_hw_reset(struct spwcuc_priv *priv)
+{
+ struct spwcuc_regs *r = priv->regs;
+ int i = 1000;
+
+ r->control = 1;
+
+ while ((r->control & 1) && i > 0) {
+ i--;
+ }
+
+ spwcuc_clear_irqs(priv, -1);
+
+ return i ? 0 : -1;
+}
+
+int spwcuc_reset(void *spwcuc)
+{
+ struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
+
+ return spwcuc_hw_reset(priv);
+}
+
+void *spwcuc_open(int minor)
+{
+ struct spwcuc_priv *priv;
+ struct drvmgr_dev *dev;
+
+ /* Get Device from Minor */
+ if ( drvmgr_get_dev(&spwcuc_drv_info.general, minor, &dev) ) {
+ return NULL;
+ }
+
+ priv = dev->priv;
+ if ( (priv == NULL) || priv->open )
+ return NULL;
+
+ /* Set initial state of software */
+ priv->open = 1;
+
+ /* Clear Statistics */
+ spwcuc_clr_stats(priv);
+ priv->user_isr = NULL;
+ priv->user_isr_arg = NULL;
+
+ return priv;
+}
+
+void spwcuc_close(void *spwcuc)
+{
+ struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
+
+ if ( priv->open == 0 )
+ return;
+
+ /* Reset Hardware */
+ spwcuc_hw_reset(priv);
+
+ priv->open = 0;
+}
+
+void spwcuc_int_enable(void *spwcuc)
+{
+ struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
+
+ /* Register and Enable Interrupt at Interrupt controller */
+ drvmgr_interrupt_register(priv->dev, 0, "spwcuc", spwcuc_isr, priv);
+}
+
+void spwcuc_int_disable(void *spwcuc)
+{
+ struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
+
+ /* Enable Interrupt at Interrupt controller */
+ drvmgr_interrupt_unregister(priv->dev, 0, spwcuc_isr, priv);
+}
+
+void spwcuc_clr_stats(void *spwcuc)
+{
+ struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
+
+ memset(&priv->stats, 0, sizeof(priv->stats));
+}
+
+void spwcuc_get_stats(void *spwcuc, struct spwcuc_stats *stats)
+{
+ struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
+
+ memcpy(stats, &priv->stats, sizeof(priv->stats));
+}
+
+/* Configure the spwcuc core */
+void spwcuc_config(void *spwcuc, struct spwcuc_cfg *cfg)
+{
+ struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
+ struct spwcuc_regs *r = priv->regs;
+
+ r->config = (cfg->sel_out & 0x1f) << 28 |
+ (cfg->sel_in & 0x1f) << 24 |
+ (cfg->mapping & 0x1f) << 16 |
+ (cfg->tolerance & 0x1f) << 8 |
+ (cfg->tid & 0x7) << 4 |
+ (cfg->ctf & 1) << 1 |
+ (cfg->cp & 1);
+
+ r->control = (cfg->txen & 1) << 1 |
+ (cfg->rxen & 1) << 2 |
+ (cfg->pktsyncen & 1) << 3 |
+ (cfg->pktiniten & 1) << 4 |
+ (cfg->pktrxen & 1) << 5;
+
+ r->dla = (cfg->dla_mask & 0xff)<<8 | (cfg->dla & 0xff);
+
+ r->pid = cfg->pid;
+
+ r->offset = cfg->offset;
+}
+
+/* Return elapsed coarse time */
+unsigned int spwcuc_get_et_coarse(void *spwcuc)
+{
+ struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
+
+ return priv->regs->etct;
+}
+
+/* Return elapsed fine time */
+unsigned int spwcuc_get_et_fine(void *spwcuc)
+{
+ struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
+
+ return (priv->regs->etft & 0xffffff) >> 8;
+}
+
+/* Return elapsed time (coarse and fine) */
+unsigned long long spwcuc_get_et(void *spwcuc)
+{
+ return (((unsigned long long)spwcuc_get_et_coarse(spwcuc)) << 24) | spwcuc_get_et_fine(spwcuc);
+}
+
+/* Return next elapsed coarse time (for use when sending SpW time packet) */
+unsigned int spwcuc_get_next_et_coarse(void *spwcuc)
+{
+ struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
+
+ return priv->regs->etct_next;
+}
+
+/* Return next elapsed fine time (for use when sending SpW time packet) */
+unsigned int spwcuc_get_next_et_fine(void *spwcuc)
+{
+ struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
+
+ return (priv->regs->etft_next & 0xffffff) >> 8;
+}
+
+/* Return next elapsed time (for use when sending SpW time packet) */
+unsigned long long spwcuc_get_next_et(void *spwcuc)
+{
+ return (((unsigned long long)spwcuc_get_next_et_coarse(spwcuc)) << 24) | spwcuc_get_next_et_fine(spwcuc);
+}
+
+/* Force/Set the elapsed time (coarse 32-bit and fine 24-bit) by writing the
+ * T-Field Time Packet Registers then the FORCE, NEW and INIT bits.
+ * The latter three are needed for the ET to be set with the new value.
+ */
+void spwcuc_force_et(void *spwcuc, unsigned long long time)
+{
+ struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
+ struct spwcuc_regs *regs = priv->regs;
+
+ regs->etft_next = (time & 0xffffff) << 8;
+ regs->etct_next = (time >> 24) & 0xffffffff;
+ regs->pkt_pf_crc = (1 << 29) | (1 << 30) | (1 << 31);
+}
+
+/* Return received (from time packet) elapsed coarse time */
+unsigned int spwcuc_get_tp_et_coarse(void *spwcuc)
+{
+ struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
+
+ return priv->regs->pkt_ct;
+}
+
+/* Return received (from time packet) elapsed fine time */
+unsigned int spwcuc_get_tp_et_fine(void *spwcuc)
+{
+ struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
+
+ return (priv->regs->pkt_ft & 0xffffff) >> 8;
+}
+
+/* Return received (from time packet) elapsed time (coarse and fine) */
+unsigned long long spwcuc_get_tp_et(void *spwcuc)
+{
+ return (((unsigned long long)spwcuc_get_tp_et_coarse(spwcuc)) << 24) | spwcuc_get_tp_et_fine(spwcuc);
+}
+
+/* Clear interrupts */
+void spwcuc_clear_irqs(void *spwcuc, int irqs)
+{
+ struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
+
+ priv->regs->picr = irqs;
+}
+
+/* Enable interrupts */
+void spwcuc_enable_irqs(void *spwcuc, int irqs)
+{
+ struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
+
+ priv->regs->imr = irqs;
+}
+
+struct spwcuc_regs *spwcuc_get_regs(void *spwcuc)
+{
+ struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
+
+ return priv->regs;
+}
+
+void spwcuc_int_register(void *spwcuc, spwcuc_isr_t func, void *data)
+{
+ struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
+
+ priv->user_isr = func;
+ priv->user_isr_arg = data;
+}
+
+void spwcuc_isr(void *data)
+{
+ struct spwcuc_priv *priv = data;
+ struct spwcuc_stats *stats = &priv->stats;
+ unsigned int pimr = priv->regs->pimr;
+
+ stats->nirqs++;
+
+ if (pimr & PKT_INIT_IRQ)
+ stats->pkt_init++;
+ if (pimr & PKT_ERR_IRQ)
+ stats->pkt_err++;
+ if (pimr & PKT_RX_IRQ)
+ stats->pkt_rx++;
+ if (pimr & WRAP_ERR_IRQ)
+ stats->wraperr++;
+ if (pimr & WRAP_IRQ)
+ stats->wrap++;
+ if (pimr & SYNC_ERR_IRQ)
+ stats->syncerr++;
+ if (pimr & SYNC_IRQ)
+ stats->sync++;
+ if (pimr & TOL_ERR_IRQ)
+ stats->tolerr++;
+ if (pimr & TICK_RX_ERR_IRQ)
+ stats->tick_rx_error++;
+ if (pimr & TICK_RX_WRAP_IRQ)
+ stats->tick_rx_wrap++;
+ if (pimr & TICK_RX_IRQ)
+ stats->tick_rx++;
+ if (pimr & TICK_TX_WRAP_IRQ)
+ stats->tick_tx_wrap++;
+ if (pimr & TICK_TX_IRQ)
+ stats->tick_tx++;
+
+ /* Let user Handle Interrupt */
+ if ( priv->user_isr )
+ priv->user_isr(pimr, priv->user_isr_arg);
+}
+
+/*** INTERFACE TO DRIVER MANAGER ***/
+
+int spwcuc_init2(struct drvmgr_dev *dev)
+{
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
+ struct spwcuc_priv *priv;
+ struct spwcuc_regs *regs;
+
+ priv = (struct spwcuc_priv *)malloc(sizeof(*priv));
+ if ( priv == NULL )
+ return -1;
+ memset(priv, 0, sizeof(*priv));
+ priv->dev = dev;
+ dev->priv = priv;
+
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)dev->businfo;
+ if ( ambadev == NULL ) {
+ return -1;
+ }
+ pnpinfo = &ambadev->info;
+ regs = (struct spwcuc_regs *)pnpinfo->apb_slv->start;
+
+ priv->regs = regs;
+
+ spwcuc_hw_reset(priv);
+
+ return 0;
+}
+
+struct drvmgr_drv_ops spwcuc_ops =
+{
+ {NULL, spwcuc_init2, NULL, NULL},
+ NULL,
+ NULL
+};
+
+struct amba_dev_id spwcuc_ids[] =
+{
+ {VENDOR_GAISLER, GAISLER_SPWCUC},
+ {0, 0} /* Mark end of table */
+};
+
+struct amba_drv_info spwcuc_drv_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_AMBAPP_GAISLER_SPWCUC_ID,/* Driver ID */
+ "SPWCUC_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */
+ &spwcuc_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ 0,
+ },
+ &spwcuc_ids[0]
+};
+
+/* Register the SPWCUC Driver */
+void spwcuc_register(void)
+{
+ drvmgr_drv_register(&spwcuc_drv_info.general);
+}
diff --git a/c/src/lib/libbsp/sparc/shared/timer/gptimer.c b/c/src/lib/libbsp/sparc/shared/timer/gptimer.c
new file mode 100644
index 0000000000..3f3877f66d
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/timer/gptimer.c
@@ -0,0 +1,533 @@
+/* This file contains the driver for the GRLIB GPTIMER timers port. The driver
+ * is implemented by using the tlib.c simple timer layer and the Driver
+ * Manager.
+ *
+ * The Driver can be configured using driver resources:
+ *
+ * - timerStart Timer Index if first Timer, this parameters is typically used
+ * in AMP systems for resource allocation. The Timers before
+ * timerStart will not be accessed.
+ * - timerCnt Number of timers that the driver will use, this parameters is
+ * typically used in AMP systems for resource allocation between
+ * OS instances.
+ * - prescaler Base prescaler, normally set by bootloader but can be
+ * overridden. The default scaler reload value set by bootloader
+ * is so that Timers operate in 1MHz. Setting the prescaler to a
+ * lower value increase the accuracy of the timers but shortens
+ * the time until underflow happens.
+ * - clockTimer Used to select a particular timer to be the system clock
+ * timer. This is useful when multiple GPTIMERs cores are
+ * available, or in AMP systems. By default the TLIB selects the
+ * first timer registered as system clock timer.
+ *
+ * The BSP define APBUART_INFO_AVAIL in order to add the info routine
+ * used for debugging.
+ *
+ * COPYRIGHT (c) 2010.
+ * Aeroflex Gaisler.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2010-09-27, Daniel Hellstrom <daniel@gaisler.com>
+ * created
+ */
+
+#include <rtems.h>
+#include <bsp.h>
+#include <stdlib.h>
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+#include <grlib.h>
+#include "tlib.h"
+
+#if defined(LEON3) && defined(RTEMS_DRVMGR_STARTUP)
+#include <leon.h>
+volatile struct gptimer_regs *LEON3_Timer_Regs = 0;
+#endif
+
+#ifdef GPTIMER_INFO_AVAIL
+#include <stdio.h>
+#endif
+
+/* GPTIMER Core Configuration Register (READ-ONLY) */
+#define GPTIMER_CFG_TIMERS_BIT 0
+#define GPTIMER_CFG_IRQ_BIT 3
+#define GPTIMER_CFG_SI_BIT 8
+#define GPTIMER_CFG_DF_BIT 9
+
+#define GPTIMER_CFG_TIMERS (0x7<<GPTIMER_CFG_TIMERS_BIT)
+#define GPTIMER_CFG_IRQ (0x1f<<GPTIMER_CFG_IRQ_BIT)
+#define GPTIMER_CFG_SI (1<<GPTIMER_CFG_SI_BIT)
+#define GPTIMER_CFG_DF (1<<GPTIMER_CFG_DF_BIT)
+
+/* GPTIMER Timer Control Register */
+#define GPTIMER_CTRL_EN_BIT 0
+#define GPTIMER_CTRL_RS_BIT 1
+#define GPTIMER_CTRL_LD_BIT 2
+#define GPTIMER_CTRL_IE_BIT 3
+#define GPTIMER_CTRL_IP_BIT 4
+#define GPTIMER_CTRL_CH_BIT 5
+#define GPTIMER_CTRL_DH_BIT 6
+
+#define GPTIMER_CTRL_EN (1<<GPTIMER_CTRL_EN_BIT)
+#define GPTIMER_CTRL_RS (1<<GPTIMER_CTRL_RS_BIT)
+#define GPTIMER_CTRL_LD (1<<GPTIMER_CTRL_LD_BIT)
+#define GPTIMER_CTRL_IE (1<<GPTIMER_CTRL_IE_BIT)
+#define GPTIMER_CTRL_IP (1<<GPTIMER_CTRL_IP_BIT)
+#define GPTIMER_CTRL_CH (1<<GPTIMER_CTRL_CH_BIT)
+#define GPTIMER_CTRL_DH (1<<GPTIMER_CTRL_DH_BIT)
+
+#define DBG(x...)
+
+/* GPTIMER timer private */
+struct gptimer_timer {
+ struct tlib_dev tdev; /* Must be first in struct */
+ struct gptimer_timer_regs *tregs;
+ char index; /* Timer Index in this driver */
+ char tindex; /* Timer Index In Hardware */
+ unsigned char irq_ack_mask;
+};
+
+/* GPTIMER Core private */
+struct gptimer_priv {
+ struct drvmgr_dev *dev;
+ struct gptimer_regs *regs;
+ unsigned int base_clk;
+ unsigned int base_freq;
+ int separate_interrupt;
+
+ /* Structure per Timer unit, the core supports up to 8 timers */
+ int timer_cnt;
+ struct gptimer_timer timers[0];
+};
+
+void gptimer_isr(void *data);
+
+#if 0
+void gptimer_tlib_irq_register(struct tlib_drv *tdrv, tlib_isr_t func, void *data)
+{
+ struct gptimer_priv *priv = (struct gptimer_priv *)tdrv;
+
+ if ( SHARED ...)
+
+
+ drvmgr_interrupt_register();
+}
+#endif
+
+/******************* Driver manager interface ***********************/
+
+/* Driver prototypes */
+struct tlib_drv gptimer_tlib_drv;
+int gptimer_device_init(struct gptimer_priv *priv);
+
+int gptimer_init1(struct drvmgr_dev *dev);
+#ifdef GPTIMER_INFO_AVAIL
+static int gptimer_info(
+ struct drvmgr_dev *dev,
+ void (*print_line)(void *p, char *str),
+ void *p, int, char *argv[]);
+#define GTIMER_INFO_FUNC gptimer_info
+#else
+#define GTIMER_INFO_FUNC NULL
+#endif
+
+struct drvmgr_drv_ops gptimer_ops =
+{
+ .init = {gptimer_init1, NULL, NULL, NULL},
+ .remove = NULL,
+ .info = GTIMER_INFO_FUNC,
+};
+
+struct amba_dev_id gptimer_ids[] =
+{
+ {VENDOR_GAISLER, GAISLER_GPTIMER},
+ {0, 0} /* Mark end of table */
+};
+
+struct amba_drv_info gptimer_drv_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_AMBAPP_GAISLER_GPTIMER_ID,/* Driver ID */
+ "GPTIMER_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */
+ &gptimer_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ 0,
+ },
+ &gptimer_ids[0]
+};
+
+void gptimer_register_drv (void)
+{
+ DBG("Registering GPTIMER driver\n");
+ drvmgr_drv_register(&gptimer_drv_info.general);
+}
+
+int gptimer_init1(struct drvmgr_dev *dev)
+{
+ struct gptimer_priv *priv;
+ struct gptimer_regs *regs;
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
+ int timer_hw_cnt, timer_cnt, timer_start;
+ int i, size;
+ struct gptimer_timer *timer;
+ union drvmgr_key_value *value;
+ unsigned char irq_ack_mask;
+#if defined(LEON3) && defined(RTEMS_DRVMGR_STARTUP)
+ char timer_index[7];
+#endif
+
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)dev->businfo;
+ if ( ambadev == NULL ) {
+ return -1;
+ }
+ pnpinfo = &ambadev->info;
+ regs = (struct gptimer_regs *)pnpinfo->apb_slv->start;
+
+ DBG("GPTIMER[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
+
+ /* Get number of Timers */
+ timer_hw_cnt = regs->cfg & GPTIMER_CFG_TIMERS;
+
+ /* Let user spelect a range of timers to be used. In AMP systems
+ * it is sometimes neccessary to leave timers for other CPU instances.
+ *
+ * The default operation in AMP is to shared the timers within the
+ * first GPTIMER core as below. This can of course be overrided by
+ * driver resources.
+ */
+ timer_cnt = timer_hw_cnt;
+ timer_start = 0;
+#if defined(RTEMS_MULTIPROCESSING) && defined(LEON3)
+ if ((dev->minor_drv == 0) && drvmgr_on_rootbus(dev)) {
+ timer_cnt = 1;
+ timer_start = LEON3_Cpu_Index;
+ }
+#endif
+ value = drvmgr_dev_key_get(dev, "timerStart", KEY_TYPE_INT);
+ if ( value) {
+ timer_start = value->i;
+ timer_cnt = timer_hw_cnt - timer_start;
+ }
+ value = drvmgr_dev_key_get(dev, "timerCnt", KEY_TYPE_INT);
+ if ( value && (value->i < timer_cnt) ) {
+ timer_cnt = value->i;
+ }
+
+ /* Allocate Common Timer Description, size depends on how many timers
+ * are present.
+ */
+ size = sizeof(struct gptimer_priv) +
+ timer_cnt*sizeof(struct gptimer_timer);
+ priv = dev->priv = (struct gptimer_priv *)malloc(size);
+ if ( !priv )
+ return DRVMGR_NOMEM;
+ memset(priv, 0, size);
+ priv->dev = dev;
+ priv->regs = regs;
+
+#if defined(LEON3) && defined(RTEMS_DRVMGR_STARTUP)
+ if ( drvmgr_on_rootbus(priv->dev) && !LEON3_Timer_Regs) {
+ /* Bootloader has initialized the Timer prescaler to 1MHz,
+ * this means that the AMBA Frequency is 1MHz * PRESCALER.
+ */
+ priv->base_clk = (regs->scaler_reload + 1) * 1000000;
+ ambapp_bus_freq_register(priv->dev,DEV_APB_SLV,priv->base_clk);
+ LEON3_Timer_Regs = (void *)regs;
+ } else
+#endif
+ {
+ /* The Base Frequency of the GPTIMER core is the same as the
+ * frequency of the AMBA bus it is situated on.
+ */
+ drvmgr_freq_get(dev, DEV_APB_SLV, &priv->base_clk);
+ }
+
+ /* This core will may provide important Timer functionality
+ * to other drivers and the RTEMS kernel, the Clock driver
+ * may for example use this device. So the Timer driver must be
+ * initialized in the first iiitialization stage.
+ */
+
+ /*** Initialize Hardware ***/
+
+ /* If user request to set prescaler, we will do that. However, note
+ * that doing so for the Root-Bus GPTIMER may affect the RTEMS Clock
+ * so that Clock frequency is wrong.
+ */
+ value = drvmgr_dev_key_get(priv->dev, "prescaler", KEY_TYPE_INT);
+ if ( value )
+ regs->scaler_reload = value->i;
+
+ /* Get Frequency that the timers are operating in (after prescaler) */
+ priv->base_freq = priv->base_clk / (priv->regs->scaler_reload + 1);
+
+ /* Stop Timer and probe Pending bit. In newer hardware the
+ * timer has pending bit is cleared by writing a one to it,
+ * whereas older versions it is cleared with a zero.
+ */
+ priv->regs->timer[0].ctrl = GPTIMER_CTRL_IP;
+ if ((priv->regs->timer[0].ctrl & GPTIMER_CTRL_IP) != 0)
+ irq_ack_mask = ~GPTIMER_CTRL_IP;
+ else
+ irq_ack_mask = ~0;
+
+ priv->timer_cnt = timer_cnt;
+ for (i=0; i<timer_cnt; i++) {
+ timer = &priv->timers[i];
+ timer->index = i;
+ timer->tindex = i + timer_start;
+ timer->tregs = &regs->timer[(int)timer->tindex];
+ timer->tdev.drv = &gptimer_tlib_drv;
+ timer->irq_ack_mask = irq_ack_mask;
+
+ /* Register Timer at Timer Library */
+#if defined(LEON3) && defined(RTEMS_DRVMGR_STARTUP)
+ timer_index[i] =
+#endif
+ tlib_dev_reg(&timer->tdev);
+ }
+
+ /* Check Interrupt support implementation, two cases:
+ * A. All Timers share one IRQ
+ * B. Each Timer have an individual IRQ. The number is:
+ * BASE_IRQ + timer_index
+ */
+ priv->separate_interrupt = regs->cfg & GPTIMER_CFG_SI;
+
+ if ( priv->separate_interrupt == 0 ) {
+ /* Shared IRQ handler */
+ drvmgr_interrupt_register(
+ priv->dev,
+ 0,
+ "gptimer_shared",
+ gptimer_isr,
+ priv);
+ }
+
+ /* Older HW */
+
+
+
+ /* If the user request a certain Timer to be the RTEMS Clock Timer,
+ * the timer must be registered at the Clock Driver.
+ */
+#if defined(LEON3) && defined(RTEMS_DRVMGR_STARTUP)
+ value = drvmgr_dev_key_get(priv->dev, "clockTimer", KEY_TYPE_INT);
+ if ( value && (value->i < timer_cnt) ) {
+ LEON3_Timer_Regs = (void *)regs;
+ Clock_timer_register(timer_index[value->i]);
+ }
+#endif
+
+ return DRVMGR_OK;
+}
+
+#ifdef GPTIMER_INFO_AVAIL
+static int gptimer_info(
+ struct drvmgr_dev *dev,
+ void (*print_line)(void *p, char *str),
+ void *p, int argc, char *argv[])
+{
+ struct gptimer_priv *priv = dev->priv;
+ struct gptimer_timer *timer;
+ char buf[64];
+ int i;
+
+ if (priv == NULL || argc != 0)
+ return -DRVMGR_EINVAL;
+
+ sprintf(buf, "Timer Count: %d", priv->timer_cnt);
+ print_line(p, buf);
+ sprintf(buf, "REGS: 0x%08x", (unsigned int)priv->regs);
+ print_line(p, buf);
+ sprintf(buf, "BASE SCALER: %d", priv->regs->scaler_reload);
+ print_line(p, buf);
+ sprintf(buf, "BASE FREQ: %dkHz", priv->base_freq / 1000);
+ print_line(p, buf);
+ sprintf(buf, "SeparateIRQ: %s", priv->separate_interrupt ? "YES":"NO");
+ print_line(p, buf);
+
+ for (i=0; i<priv->timer_cnt; i++) {
+ timer = &priv->timers[i];
+ sprintf(buf, " - TIMER HW Index %d -", timer->tindex);
+ print_line(p, buf);
+ sprintf(buf, " TLIB Index: %d", timer->index);
+ print_line(p, buf);
+ sprintf(buf, " RELOAD REG: %d", timer->tregs->reload);
+ print_line(p, buf);
+ sprintf(buf, " CTRL REG: %d", timer->tregs->ctrl);
+ print_line(p, buf);
+ }
+
+ return DRVMGR_OK;
+}
+#endif
+
+static inline struct gptimer_priv *priv_from_timer(struct gptimer_timer *t)
+{
+ return (struct gptimer_priv *)
+ ((unsigned int)t -
+ sizeof(struct gptimer_priv) -
+ t->index * sizeof(struct gptimer_timer));
+}
+
+int gptimer_tlib_int_pend(struct tlib_dev *hand, int ack)
+{
+ struct gptimer_timer *timer = (struct gptimer_timer *)hand;
+ unsigned int ctrl = timer->tregs->ctrl;
+
+ if ((ctrl & (GPTIMER_CTRL_IP | GPTIMER_CTRL_IE)) ==
+ (GPTIMER_CTRL_IP | GPTIMER_CTRL_IE)) {
+ /* clear Pending IRQ ? */
+ if (ack)
+ timer->tregs->ctrl = ctrl & timer->irq_ack_mask;
+ return 1; /* timer generated IRQ */
+ } else
+ return 0; /* was not timer causing IRQ */
+}
+
+void gptimer_isr(void *data)
+{
+ struct gptimer_priv *priv = data;
+ int i;
+
+ /* Check all timers for IRQ */
+ for (i=0;i<priv->timer_cnt; i++) {
+ if (gptimer_tlib_int_pend((void *)&priv->timers[i], 0)) {
+ /* IRQ Was generated by Timer and Pending flag has *not*
+ * yet been cleared, this is to allow ISR to look at
+ * pending bit. Call ISR registered. Clear pending bit.
+ */
+ if (priv->timers[i].tdev.isr_func) {
+ priv->timers[i].tdev.isr_func(
+ priv->timers[i].tdev.isr_data);
+ }
+ gptimer_tlib_int_pend((void *)&priv->timers[i], 1);
+ }
+ }
+}
+
+void gptimer_tlib_reset(struct tlib_dev *hand)
+{
+ struct gptimer_timer *timer = (struct gptimer_timer *)hand;
+
+ timer->tregs->ctrl = 0;
+ timer->tregs->reload = 0xffffffff;
+ timer->tregs->ctrl = GPTIMER_CTRL_LD;
+}
+
+void gptimer_tlib_get_freq(
+ struct tlib_dev *hand,
+ unsigned int *basefreq,
+ unsigned int *tickrate)
+{
+ struct gptimer_timer *timer = (struct gptimer_timer *)hand;
+ struct gptimer_priv *priv = priv_from_timer(timer);
+
+ /* Calculate base frequency from Timer Clock and Prescaler */
+ if ( basefreq )
+ *basefreq = priv->base_freq;
+ if ( tickrate )
+ *tickrate = timer->tregs->reload + 1;
+}
+
+int gptimer_tlib_set_freq(struct tlib_dev *hand, unsigned int tickrate)
+{
+ struct gptimer_timer *timer = (struct gptimer_timer *)hand;
+
+ timer->tregs->reload = tickrate - 1;
+
+ /*Check that value was allowed (Timer may not be as wide as expected)*/
+ if ( timer->tregs->reload != (tickrate - 1) )
+ return -1;
+ else
+ return 0;
+}
+
+void gptimer_tlib_irq_reg(struct tlib_dev *hand, tlib_isr_t func, void *data)
+{
+ struct gptimer_timer *timer = (struct gptimer_timer *)hand;
+ struct gptimer_priv *priv = priv_from_timer(timer);
+
+ if ( priv->separate_interrupt ) {
+ drvmgr_interrupt_register(priv->dev, timer->tindex,
+ "gptimer", func, data);
+ }
+
+ timer->tregs->ctrl |= GPTIMER_CTRL_IE;
+}
+
+void gptimer_tlib_irq_unreg(struct tlib_dev *hand, tlib_isr_t func, void *data)
+{
+ struct gptimer_timer *timer = (struct gptimer_timer *)hand;
+ struct gptimer_priv *priv = priv_from_timer(timer);
+
+ /* Turn off IRQ at source, unregister IRQ handler */
+ timer->tregs->ctrl &= ~GPTIMER_CTRL_IE;
+
+ if ( priv->separate_interrupt ) {
+ drvmgr_interrupt_unregister(priv->dev, timer->tindex,
+ func, data);
+ } else {
+ timer->tdev.isr_func = NULL;
+ }
+}
+
+void gptimer_tlib_start(struct tlib_dev *hand, int once)
+{
+ struct gptimer_timer *timer = (struct gptimer_timer *)hand;
+ unsigned int ctrl;
+
+ /* Load the selected frequency before starting Frequency */
+ ctrl = GPTIMER_CTRL_LD | GPTIMER_CTRL_EN;
+ if ( once == 0 )
+ ctrl |= GPTIMER_CTRL_RS; /* Restart Timer */
+ timer->tregs->ctrl |= ctrl;
+}
+
+void gptimer_tlib_stop(struct tlib_dev *hand)
+{
+ struct gptimer_timer *timer = (struct gptimer_timer *)hand;
+
+ /* Load the selected Frequency */
+ timer->tregs->ctrl &= ~(GPTIMER_CTRL_EN|GPTIMER_CTRL_IP);
+}
+
+void gptimer_tlib_restart(struct tlib_dev *hand)
+{
+ struct gptimer_timer *timer = (struct gptimer_timer *)hand;
+
+ timer->tregs->ctrl |= GPTIMER_CTRL_LD | GPTIMER_CTRL_EN;
+}
+
+void gptimer_tlib_get_counter(struct tlib_dev *hand, unsigned int *counter)
+{
+ struct gptimer_timer *timer = (struct gptimer_timer *)hand;
+
+ *counter = timer->tregs->value;
+}
+
+struct tlib_drv gptimer_tlib_drv =
+{
+ .reset = gptimer_tlib_reset,
+ .get_freq = gptimer_tlib_get_freq,
+ .set_freq = gptimer_tlib_set_freq,
+ .irq_reg = gptimer_tlib_irq_reg,
+ .irq_unreg = gptimer_tlib_irq_unreg,
+ .start = gptimer_tlib_start,
+ .stop = gptimer_tlib_stop,
+ .restart = gptimer_tlib_restart,
+ .get_counter = gptimer_tlib_get_counter,
+ .custom = NULL,
+ .int_pend = gptimer_tlib_int_pend,
+};
diff --git a/c/src/lib/libbsp/sparc/shared/timer/tlib.c b/c/src/lib/libbsp/sparc/shared/timer/tlib.c
new file mode 100644
index 0000000000..3cfb7e4f6c
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/timer/tlib.c
@@ -0,0 +1,66 @@
+#include <rtems.h>
+#include <tlib.h>
+
+struct tlib_dev *tlib_dev_head = NULL;
+struct tlib_dev *tlib_dev_tail = NULL;
+static int tlib_dev_cnt = 0;
+
+/* Register Timer device to Timer Library */
+int tlib_dev_reg(struct tlib_dev *newdev)
+{
+ /* Reset device */
+ newdev->status = 0;
+ newdev->isr_func = NULL;
+ newdev->index = tlib_dev_cnt;
+
+ /* Insert last in queue */
+ newdev->next = NULL;
+ if ( tlib_dev_tail == NULL ) {
+ tlib_dev_head = newdev;
+ } else {
+ tlib_dev_tail->next = newdev;
+ }
+ tlib_dev_tail = newdev;
+
+ /* Return Index of Registered Timer */
+ return tlib_dev_cnt++;
+}
+
+void *tlib_open(int timer_no)
+{
+ struct tlib_dev *dev;
+
+ if ( timer_no < 0 )
+ return NULL;
+
+ dev = tlib_dev_head;
+ while ( (timer_no > 0) && dev ) {
+ timer_no--;
+ dev = dev->next;
+ }
+ if ( dev ) {
+ if ( dev->status )
+ return NULL;
+ dev->status = 1;
+ /* Reset Timer to initial state */
+ tlib_reset(dev);
+ }
+ return dev;
+}
+
+void tlib_close(void *hand)
+{
+ struct tlib_dev *dev = hand;
+
+ /* Stop any ongoing timer operation and unregister IRQ if registered */
+ tlib_stop(dev);
+ tlib_irq_unregister(dev);
+
+ /* Mark not open */
+ dev->status = 0;
+}
+
+int tlib_ntimer(void)
+{
+ return tlib_dev_cnt;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/timer/tlib_ckinit.c b/c/src/lib/libbsp/sparc/shared/timer/tlib_ckinit.c
new file mode 100644
index 0000000000..a67d31c5ba
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/timer/tlib_ckinit.c
@@ -0,0 +1,280 @@
+/*
+ * Clock Tick Device Driver using Timer Library implemented
+ * by the GRLIB GPTIMER / LEON2 Timer drivers.
+ *
+ * COPYRIGHT (c) 2010.
+ * Aeroflex Gaisler AB.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ */
+
+#include <stdlib.h>
+#include <bsp.h>
+#include <tlib.h>
+
+/* Undefine (default) this to save space in standard LEON configurations,
+ * it will assume that Prescaler is running at 1MHz.
+ */
+/*#undef CLOCK_DRIVER_DONT_ASSUME_PRESCALER_1MHZ*/
+
+/* Set the below defines from bsp.h if function needed.
+#undef CLOCK_DRIVER_ISRS_PER_TICK
+#undef CLOCK_DRIVER_USE_FAST_IDLE
+*/
+#define Clock_driver_support_at_tick()
+
+/*
+ * Number of Clock ticks since initialization
+ */
+volatile uint32_t Clock_driver_ticks;
+
+/*
+ * Timer Number in Timer Library. Defaults to the first Timer in
+ * the System.
+ */
+int Clock_timer = 0;
+
+/*
+ * Timer Handle in Timer Library
+ */
+void *Clock_handle = NULL;
+
+#ifdef CLOCK_DRIVER_DONT_ASSUME_PRESCALER_1MHZ
+unsigned int Clock_basefreq;
+#endif
+
+void Clock_exit(void);
+
+/*
+ * Major and minor number.
+ */
+
+rtems_device_major_number rtems_clock_major = UINT32_MAX;
+rtems_device_minor_number rtems_clock_minor;
+
+/*
+ * Clock_isr
+ *
+ * This is the clock tick interrupt handler.
+ *
+ * Input parameters:
+ * vector - vector number
+ *
+ * Output parameters: NONE
+ *
+ * Return values: NONE
+ *
+ */
+
+void Clock_isr(void *arg_unused)
+{
+ /*
+ * Support for shared interrupts. Ack IRQ at source, only handle
+ * interrupts generated from the tick-timer. Clearing pending bit
+ * is also needed for Clock_nanoseconds_since_last_tick() to work.
+ */
+ if ( tlib_interrupt_pending(Clock_handle, 1) == 0 )
+ return;
+
+ /*
+ * Accurate count of ISRs
+ */
+
+ Clock_driver_ticks += 1;
+
+#ifdef CLOCK_DRIVER_USE_FAST_IDLE
+ do {
+ rtems_clock_tick();
+ } while ( _Thread_Executing == _Thread_Idle &&
+ _Thread_Heir == _Thread_Executing);
+
+ Clock_driver_support_at_tick();
+ return;
+
+#else
+
+ /*
+ * Add custom handling at every tick from bsp.h
+ */
+ Clock_driver_support_at_tick();
+
+#ifdef CLOCK_DRIVER_ISRS_PER_TICK
+ /*
+ * The driver is multiple ISRs per clock tick.
+ */
+
+ if ( !Clock_driver_isrs ) {
+
+ rtems_clock_tick();
+
+ Clock_driver_isrs = CLOCK_DRIVER_ISRS_PER_TICK;
+ }
+ Clock_driver_isrs--;
+#else
+
+ /*
+ * The driver is one ISR per clock tick.
+ */
+ rtems_clock_tick();
+#endif
+#endif
+}
+
+/*
+ * Clock_exit
+ *
+ * This routine allows the clock driver to exit by masking the interrupt and
+ * disabling the clock's counter.
+ *
+ * Input parameters: NONE
+ *
+ * Output parameters: NONE
+ *
+ * Return values: NONE
+ *
+ */
+
+void Clock_exit( void )
+{
+ /* Stop all activity of the Timer, no more ISRs.
+ * We could be using tlib_close(), however tlib_stop() is quicker
+ * and independent of IRQ unregister code.
+ */
+ if ( Clock_handle ) {
+ tlib_stop(Clock_handle);
+ Clock_handle = NULL;
+ }
+}
+
+uint32_t Clock_nanoseconds_since_last_tick(void)
+{
+ uint32_t clicks;
+ int ip;
+
+ if ( !Clock_handle )
+ return 0;
+
+ tlib_get_counter(Clock_handle, (unsigned int *)&clicks);
+ /* protect against timer counter underflow/overflow */
+ ip = tlib_interrupt_pending(Clock_handle, 0);
+ if (ip)
+ tlib_get_counter(Clock_handle, (unsigned int *)&clicks);
+
+#ifdef CLOCK_DRIVER_DONT_ASSUME_PRESCALER_1MHZ
+ {
+ /* Down counter. Calc from BaseFreq. */
+ uint64_t tmp;
+ if (ip)
+ clicks += Clock_basefreq;
+ tmp = ((uint64_t)clicks * 1000000000) / ((uint64_t)Clock_basefreq);
+ return (uint32_t)tmp;
+ }
+#else
+ /* Down counter. Timer base frequency is initialized to 1 MHz */
+ return (uint32_t)
+ ((rtems_configuration_get_microseconds_per_tick() << ip) - clicks) * 1000;
+#endif
+}
+
+/*
+ * Clock_initialize
+ *
+ * This routine initializes the clock driver and starts the Clock.
+ *
+ * Input parameters:
+ * major - clock device major number
+ * minor - clock device minor number
+ * parg - pointer to optional device driver arguments
+ *
+ * Output parameters: NONE
+ *
+ * Return values:
+ * rtems_device_driver status code
+ */
+
+rtems_device_driver Clock_initialize(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *pargp
+)
+{
+ unsigned int tick_hz;
+
+ /*
+ * Take Timer that should be used as system timer.
+ *
+ */
+ Clock_handle = tlib_open(Clock_timer);
+ if ( Clock_handle == NULL ) {
+ /* System Clock Timer not found */
+ return RTEMS_NOT_DEFINED;
+ }
+
+ /*
+ * Install Clock ISR before starting timer
+ */
+ tlib_irq_register(Clock_handle, Clock_isr, NULL);
+
+ /* Set Timer Frequency to tick at Configured value. The Timer
+ * Frequency is set in multiples of the timer base frequency.
+ *
+ * In standard LEON3 designs the base frequency is is 1MHz, to
+ * save instructions define CLOCK_DRIVER_ASSUME_PRESCALER_1MHZ
+ * to avoid 64-bit calculation.
+ */
+#ifdef CLOCK_DRIVER_DONT_ASSUME_PRESCALER_1MHZ
+ {
+ uint64_t tmp;
+
+ tlib_get_freq(Clock_handle, &Clock_basefreq, NULL);
+
+ tmp = (uint64_t)Clock_basefreq;
+ tmp = tmp * (unint64_t)rtems_configuration_get_microseconds_per_tick();
+ tick_hz = tmp / 1000000;
+ }
+#else
+ tick_hz = rtems_configuration_get_microseconds_per_tick();
+#endif
+
+ tlib_set_freq(Clock_handle, tick_hz);
+
+ rtems_clock_set_nanoseconds_extension(Clock_nanoseconds_since_last_tick);
+
+ /*
+ * IRQ and Frequency is setup, now we start the Timer. IRQ is still
+ * disabled globally during startup, so IRQ will hold for a while.
+ */
+ tlib_start(Clock_handle, 0);
+
+ /*
+ * Register function called at system shutdown
+ */
+ atexit( Clock_exit );
+
+ /*
+ * make major/minor avail to others such as shared memory driver
+ */
+
+ rtems_clock_major = major;
+ rtems_clock_minor = minor;
+
+ /*
+ * If we are counting ISRs per tick, then initialize the counter.
+ */
+
+#ifdef CLOCK_DRIVER_ISRS_PER_TICK
+ Clock_driver_isrs = CLOCK_DRIVER_ISRS_PER_TICK;
+#endif
+
+ return RTEMS_SUCCESSFUL;
+}
+
+/*** Timer Driver Interface ***/
+
+void Clock_timer_register(int timer_number)
+{
+ Clock_timer = timer_number;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/tmtc/grtc.c b/c/src/lib/libbsp/sparc/shared/tmtc/grtc.c
new file mode 100644
index 0000000000..470c5c7eb4
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/tmtc/grtc.c
@@ -0,0 +1,1960 @@
+/* GRTC Telecommand decoder driver
+ *
+ * --------------------------------------------------------------------------
+ * -- This file is a part of GAISLER RESEARCH source code.
+ * -- Copyright (C) 2009, Aeroflex Gaisler AB - all rights reserved.
+ * --
+ * -- ANY USE OR REDISTRIBUTION IN PART OR IN WHOLE MUST BE HANDLED IN
+ * -- ACCORDANCE WITH THE GAISLER LICENSE AGREEMENT AND MUST BE APPROVED
+ * -- IN ADVANCE IN WRITING.
+ * --
+ * -- BY DEFAULT, DISTRIBUTION OR DISCLOSURE IS NOT PERMITTED.
+ * --------------------------------------------------------------------------
+ *
+ * 2008-12-11, Daniel Hellstrom <daniel@gaisler.com>
+ * Converted to support driver manager
+ *
+ * 2007-04-01, Daniel Hellstrom <daniel@gaisler.com>
+ * New driver in sparc shared directory.
+ *
+ */
+
+#include <bsp.h>
+#include <rtems/libio.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+#include <malloc.h>
+#include <rtems/bspIo.h>
+
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+#include <ambapp.h>
+#include <grtc.h>
+
+#ifndef IRQ_GLOBAL_PREPARE
+ #define IRQ_GLOBAL_PREPARE(level) rtems_interrupt_level level
+#endif
+
+#ifndef IRQ_GLOBAL_DISABLE
+ #define IRQ_GLOBAL_DISABLE(level) rtems_interrupt_disable(level)
+#endif
+
+#ifndef IRQ_GLOBAL_ENABLE
+ #define IRQ_GLOBAL_ENABLE(level) rtems_interrupt_enable(level)
+#endif
+
+/*
+#define DEBUG
+#define DEBUGFUNCS
+*/
+
+#include <debug_defs.h>
+
+#ifdef DEBUG_ERROR
+#define DEBUG_ERR_LOG(device,error) grtc_log_error(device,error)
+#else
+#define DEBUG_ERR_LOG(device,error)
+#endif
+
+/* GRTC register map */
+struct grtc_regs {
+ volatile unsigned int grst; /* Global Reset Register (GRR 0x00) */
+ volatile unsigned int gctrl; /* Global Control Register (GCR 0x04) */
+ int unused0;
+ volatile unsigned int sir; /* Spacecraft Identifier Register (SIR 0x0c) */
+ volatile unsigned int far; /* Frame Acceptance Report Register (FAR 0x10) */
+
+ volatile unsigned int clcw1; /* CLCW Register 1 (CLCWR1 0x14) */
+ volatile unsigned int clcw2; /* CLCW Register 2 (CLCWR2 0x18) */
+ volatile unsigned int phir; /* Physical Interface Register (PHIR 0x1c) */
+ volatile unsigned int cor; /* Control Register (COR 0x20) */
+
+ volatile unsigned int str; /* Status Register (STR 0x24) */
+ volatile unsigned int asr; /* Address Space Register (ASR 0x28) */
+ volatile unsigned int rp; /* Receive Read Pointer Register (RRP 0x2c) */
+ volatile unsigned int wp; /* Receive Write Pointer Register (RWP 0x30) */
+
+ int unused1[(0x60-0x34)/4];
+
+ volatile unsigned int pimsr; /* Pending Interrupt Masked Status Register (PIMSR 0x60) */
+ volatile unsigned int pimr; /* Pending Interrupt Masked Register (PIMR 0x64) */
+ volatile unsigned int pisr; /* Pending Interrupt Status Register (PISR 0x68) */
+ volatile unsigned int pir; /* Pending Interrupt Register (PIR 0x6c) */
+ volatile unsigned int imr; /* Interrupt Mask Register (IMR 0x70) */
+ volatile unsigned int picr; /* Pending Interrupt Clear Register (PICR 0x74) */
+};
+
+/* Security Byte */
+#define GRTC_SEB 0x55000000
+
+/* Global Reset Register (GRR 0x00) */
+#define GRTC_GRR_SRST 0x1
+#define GRTC_GRR_SRST_BIT 0
+
+/* Global Control Register (GCR 0x04) */
+#define GRTC_GCR_PSR_BIT 10
+#define GRTC_GCR_NRZM_BIT 11
+#define GRTC_GCR_PSS_BIT 12
+
+#define GRTC_GCR_PSR (1<<GRTC_GCR_PSR_BIT)
+#define GRTC_GCR_NRZM (1<<GRTC_GCR_NRZM_BIT)
+#define GRTC_GCR_PSS (1<<GRTC_GCR_PSS_BIT)
+
+/* Spacecraft Identifier Register (SIR 0x0c) */
+
+
+/* Frame Acceptance Report Register (FAR 0x10) */
+#define GRTC_FAR_SCI_BIT 10
+#define GRTC_FAR_CSEC_BIT 11
+#define GRTC_FAR_CAC_BIT 12
+#define GRTC_FAR_SSD_BIT 13
+
+#define GRTC_FAR_SCI (0x7<<GRTC_FAR_SCI_BIT)
+#define GRTC_FAR_CSEC (0x7<<GRTC_FAR_CSEC_BIT)
+#define GRTC_FAR_CAC (0x3f<<GRTC_FAR_CAC_BIT)
+#define GRTC_FAR_SSD (1<<GRTC_FAR_SSD_BIT)
+
+/* CLCW Register 1 (CLCWR1 0x14) */
+/* CLCW Register 2 (CLCWR2 0x18) */
+#define GRTC_CLCW_RVAL_BIT 0
+#define GRTC_CLCW_RTYPE_BIT 8
+#define GRTC_CLCW_FBCO_BIT 9
+#define GRTC_CLCW_RTMI_BIT 11
+#define GRTC_CLCW_WAIT_BIT 12
+#define GRTC_CLCW_LOUT_BIT 13
+#define GRTC_CLCW_NBLO_BIT 14
+#define GRTC_CLCW_NRFA_BIT 15
+#define GRTC_CLCW_VCI_BIT 18
+#define GRTC_CLCW_CIE_BIT 24
+#define GRTC_CLCW_STAF_BIT 26
+#define GRTC_CLCW_VNUM_BIT 29
+#define GRTC_CLCW_CWTY_BIT 31
+
+#define GRTC_CLCW_RVAL (0xff<<GRTC_CLCW_RVAL_BIT)
+#define GRTC_CLCW_RTYPE (1<<GRTC_CLCW_RTYPE_BIT)
+#define GRTC_CLCW_FBCO (0x3<<GRTC_CLCW_FBCO_BIT)
+#define GRTC_CLCW_RTMI (0x3<<GRTC_CLCW_RTMI_BIT)
+#define GRTC_CLCW_WAIT (1<<GRTC_CLCW_WAIT_BIT)
+#define GRTC_CLCW_LOUT (1<<GRTC_CLCW_LOUT_BIT)
+#define GRTC_CLCW_NBLO (1<<GRTC_CLCW_NBLO_BIT)
+#define GRTC_CLCW_NRFA (1<<GRTC_CLCW_NRFA_BIT)
+#define GRTC_CLCW_VCI (0x3f<<GRTC_CLCW_VCI_BIT)
+#define GRTC_CLCW_CIE (0x3<<GRTC_CLCW_CIE_BIT)
+#define GRTC_CLCW_STAF (0x3<<GRTC_CLCW_STAF_BIT)
+#define GRTC_CLCW_VNUM (0x3<<GRTC_CLCW_VNUM_BIT)
+#define GRTC_CLCW_CWTY (1<<GRTC_CLCW_CWTY_BIT)
+
+/* Physical Interface Register (PIR 0x1c) */
+#define GRTC_PIR_BLO_BIT 0
+#define GRTC_PIR_RFA_BIT 8
+
+#define GRTC_PIR_BLO (0xff<<GRTC_PIR_BLO_BIT)
+#define GRTC_PIR_RFA (0xff<<GRTC_PIR_RFA_BIT)
+
+/* Control Register (COR 0x20) */
+#define GRTC_COR_RE_BIT 0
+#define GRTC_COR_CRST_BIT 9
+
+#define GRTC_COR_RE (1<<GRTC_COR_RE_BIT)
+#define GRTC_COR_CRST (1<<GRTC_COR_CRST_BIT)
+
+/* Status Register (STR 0x24) */
+#define GRTC_STR_CR_BIT 0
+#define GRTC_STR_OV_BIT 4
+#define GRTC_STR_RFF_BIT 7
+#define GRTC_STR_RBF_BIT 10
+
+#define GRTC_STR_CR (1<<GRTC_STR_CR_BIT)
+#define GRTC_STR_OV (1<<GRTC_STR_OV_BIT)
+#define GRTC_STR_RFF (1<<GRTC_STR_RFF_BIT)
+#define GRTC_STR_RBF (1<<GRTC_STR_RBF_BIT)
+
+/* Address Space Register (ASR 0x28) */
+#define GRTC_ASR_RXLEN_BIT 0
+#define GRTC_ASR_BUFST_BIT 10
+
+#define GRTC_ASR_RXLEN (0xff<<GRTC_ASR_RXLEN_BIT)
+#define GRTC_ASR_BUFST (0x3fffff<<GRTC_ASR_BUFST_BIT)
+
+/* Receive Read Pointer Register (RRP 0x2c) */
+#define GRTC_RRP_PTR_BIT 0
+
+#define GRTC_RRP_PTR (0xffffff<<GRTC_RRP_PTR_BIT)
+
+/* Receive Write Pointer Register (RWP 0x30) */
+#define GRTC_RWP_PTR_BIT 0
+
+#define GRTC_RWP_PTR (0xffffff<<GRTC_RWP_PTR_BIT)
+
+/* Pending Interrupt Masked Status Register (PIMSR 0x60) */
+/* Pending Interrupt Masked Register (PIMR 0x64) */
+/* Pending Interrupt Status Register (PISR 0x68) */
+/* Pending Interrupt Register (PIR 0x6c) */
+/* Interrupt Mask Register (IMR 0x70) */
+/* Pending Interrupt Clear Register (PICR 0x74) */
+#define GRTC_INT_RFA_BIT 0
+#define GRTC_INT_BLO_BIT 1
+#define GRTC_INT_FAR_BIT 2
+#define GRTC_INT_CR_BIT 3
+#define GRTC_INT_RBF_BIT 4
+#define GRTC_INT_OV_BIT 5
+#define GRTC_INT_CS_BIT 6
+
+#define GRTC_INT_RFA (1<<GRTC_INT_RFA_BIT)
+#define GRTC_INT_BLO (1<<GRTC_INT_BLO_BIT)
+#define GRTC_INT_FAR (1<<GRTC_INT_FAR_BIT)
+#define GRTC_INT_CR (1<<GRTC_INT_CR_BIT)
+#define GRTC_INT_OV (1<<GRTC_INT_OV_BIT)
+#define GRTC_INT_CS (1<<GRTC_INT_CS_BIT)
+
+#define GRTC_INT_ALL (GRTC_INT_RFA|GRTC_INT_BLO|GRTC_INT_FAR|GRTC_INT_CR|GRTC_INT_OV|GRTC_INT_CS)
+
+#define READ_REG(address) (*(volatile unsigned int *)address)
+
+/* Driver functions */
+static rtems_device_driver grtc_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver grtc_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver grtc_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver grtc_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver grtc_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver grtc_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+
+#define GRTC_DRIVER_TABLE_ENTRY { grtc_initialize, grtc_open, grtc_close, grtc_read, grtc_write, grtc_ioctl }
+
+static rtems_driver_address_table grtc_driver = GRTC_DRIVER_TABLE_ENTRY;
+
+enum {
+ FRM_STATE_NONE = 0, /* not started */
+ FRM_STATE_HDR = 1, /* Reading Header (Frame length isn't known) */
+ FRM_STATE_ALLOC = 2, /* Allocate Frame to hold data */
+ FRM_STATE_PAYLOAD = 3, /* Reading Payload (Frame length is known) */
+ FRM_STATE_FILLER = 4, /* Check filler */
+ FRM_STATE_DROP = 5 /* error, drop data until end marker */
+};
+
+/* Frame pool, all frames in pool have the same buffer length (frame mode only) */
+struct grtc_frame_pool {
+ unsigned int frame_len; /* Maximal length of frame (payload+hdr+crc..) */
+ unsigned int frame_cnt; /* Current number of frames in pool (in frms) */
+ struct grtc_frame *frms; /* Chain of frames in pool (this is the pool) */
+};
+
+struct grtc_priv {
+ struct drvmgr_dev *dev; /* Driver manager device */
+ char devName[32]; /* Device Name */
+ struct grtc_regs *regs; /* TC Hardware Register MAP */
+ int irq; /* IRQ number of TC core */
+
+ int major; /* Driver major */
+ int minor; /* Device Minor */
+
+ int open; /* Device has been opened by user */
+ int running; /* TC receiver running */
+ int mode; /* RAW or FRAME mode */
+ int overrun_condition; /* Overrun condition */
+ int blocking; /* Blocking/polling mode */
+ rtems_interval timeout; /* Timeout in blocking mode */
+ int wait_for_nbytes;/* Number of bytes to wait for in blocking mode */
+
+ struct grtc_ioc_config config;
+
+/* RAW MODE ONLY */
+ /* Buffer allocation (user provided or driver allocated using malloc) */
+ void *buf;
+ void *buf_remote;
+ void *_buf;
+ int buf_custom; /* 0=no custom buffer, 1=custom buffer (don't free it...) */
+ unsigned int len;
+
+/* FRAME MODE ONLY */
+ /* Frame management when user provides buffers. */
+ int pool_cnt; /* Number of Pools */
+ struct grtc_frame_pool *pools; /* Array of pools */
+
+ struct grtc_list ready; /* Ready queue (received frames) */
+
+ /* Frame read data (Frame mode only) */
+ int frame_state;
+ int filler;
+ unsigned char hdr[5] __attribute__((aligned(2)));
+ struct grtc_frame *frm; /* Frame currently beeing copied */
+ int frmlen;
+
+ struct grtc_ioc_stats stats; /* Statistics */
+
+ rtems_id sem_rx;
+
+#ifdef DEBUG_ERROR
+ /* Buffer read/write state */
+ unsigned int rp;
+ unsigned int wp;
+
+ /* Debugging */
+ int last_error[128];
+ int last_error_cnt;
+#endif
+};
+
+/* Prototypes */
+static void grtc_hw_reset(struct grtc_priv *priv);
+static void grtc_interrupt(void *arg);
+
+/* Common Global Variables */
+static rtems_id grtc_dev_sem;
+static int grtc_driver_io_registered = 0;
+static rtems_device_major_number grtc_driver_io_major = 0;
+
+/******************* Driver manager interface ***********************/
+
+/* Driver prototypes */
+static int grtc_register_io(rtems_device_major_number *m);
+static int grtc_device_init(struct grtc_priv *pDev);
+
+static int grtc_init2(struct drvmgr_dev *dev);
+static int grtc_init3(struct drvmgr_dev *dev);
+
+static struct drvmgr_drv_ops grtc_ops =
+{
+ {NULL, grtc_init2, grtc_init3, NULL},
+ NULL,
+ NULL,
+};
+
+static struct amba_dev_id grtc_ids[] =
+{
+ {VENDOR_GAISLER, GAISLER_GRTC},
+ {0, 0} /* Mark end of table */
+};
+
+static struct amba_drv_info grtc_drv_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_AMBAPP_GAISLER_GRTC_ID, /* Driver ID */
+ "GRTC_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */
+ &grtc_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ sizeof(struct grtc_priv),
+ },
+ &grtc_ids[0]
+};
+
+void grtc_register_drv (void)
+{
+ DBG("Registering GRTC driver\n");
+ drvmgr_drv_register(&grtc_drv_info.general);
+}
+
+static int grtc_init2(struct drvmgr_dev *dev)
+{
+ struct grtc_priv *priv;
+
+ DBG("GRTC[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
+ priv = dev->priv;
+ if ( !priv )
+ return DRVMGR_NOMEM;
+ priv->dev = dev;
+
+ /* This core will not find other cores, so we wait for init2() */
+
+ return DRVMGR_OK;
+}
+
+static int grtc_init3(struct drvmgr_dev *dev)
+{
+ struct grtc_priv *priv;
+ char prefix[32];
+ rtems_status_code status;
+
+ priv = dev->priv;
+
+ /* Do initialization */
+
+ if ( grtc_driver_io_registered == 0) {
+ /* Register the I/O driver only once for all cores */
+ if ( grtc_register_io(&grtc_driver_io_major) ) {
+ /* Failed to register I/O driver */
+ dev->priv = NULL;
+ return DRVMGR_FAIL;
+ }
+
+ grtc_driver_io_registered = 1;
+ }
+
+ /* I/O system registered and initialized
+ * Now we take care of device initialization.
+ */
+ if ( grtc_device_init(priv) ) {
+ return DRVMGR_FAIL;
+ }
+
+ /* Get Filesystem name prefix */
+ prefix[0] = '\0';
+ if ( drvmgr_get_dev_prefix(dev, prefix) ) {
+ /* Failed to get prefix, make sure of a unique FS name
+ * by using the driver minor.
+ */
+ sprintf(priv->devName, "/dev/grtc%d", dev->minor_drv);
+ } else {
+ /* Got special prefix, this means we have a bus prefix
+ * And we should use our "bus minor"
+ */
+ sprintf(priv->devName, "/dev/%sgrtc%d", prefix, dev->minor_bus);
+ }
+
+ /* Register Device */
+ status = rtems_io_register_name(priv->devName, grtc_driver_io_major, dev->minor_drv);
+ if (status != RTEMS_SUCCESSFUL) {
+ return DRVMGR_FAIL;
+ }
+
+ return DRVMGR_OK;
+}
+
+/******************* Driver Implementation ***********************/
+
+static int grtc_register_io(rtems_device_major_number *m)
+{
+ rtems_status_code r;
+
+ if ((r = rtems_io_register_driver(0, &grtc_driver, m)) == RTEMS_SUCCESSFUL) {
+ DBG("GRTC driver successfully registered, major: %d\n", *m);
+ } else {
+ switch(r) {
+ case RTEMS_TOO_MANY:
+ printk("GRTC rtems_io_register_driver failed: RTEMS_TOO_MANY\n");
+ return -1;
+ case RTEMS_INVALID_NUMBER:
+ printk("GRTC rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n");
+ return -1;
+ case RTEMS_RESOURCE_IN_USE:
+ printk("GRTC rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n");
+ return -1;
+ default:
+ printk("GRTC rtems_io_register_driver failed\n");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int grtc_device_init(struct grtc_priv *pDev)
+{
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
+
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)pDev->dev->businfo;
+ if ( ambadev == NULL ) {
+ return -1;
+ }
+ pnpinfo = &ambadev->info;
+ pDev->irq = pnpinfo->irq;
+ pDev->regs = (struct grtc_regs *)pnpinfo->ahb_slv->start[0];
+ pDev->minor = pDev->dev->minor_drv;
+ pDev->open = 0;
+ pDev->running = 0;
+
+ /* Create Binary RX Semaphore with count = 0 */
+ if ( rtems_semaphore_create(rtems_build_name('G', 'R', 'C', '0' + pDev->minor),
+ 0,
+ RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|\
+ RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &pDev->sem_rx) != RTEMS_SUCCESSFUL ) {
+ return -1;
+ }
+
+ /* Reset Hardware before attaching IRQ handler */
+ grtc_hw_reset(pDev);
+
+ return 0;
+}
+
+static void grtc_hw_reset(struct grtc_priv *priv)
+{
+ /* Reset Core */
+ priv->regs->grst = GRTC_SEB | GRTC_GRR_SRST;
+}
+
+static void grtc_hw_get_defaults(struct grtc_priv *pDev, struct grtc_ioc_config *config)
+{
+ unsigned int gcr = READ_REG(&pDev->regs->gctrl);
+
+ config->psr_enable = (gcr & GRTC_GCR_PSR) ? 1:0;
+ config->nrzm_enable = (gcr & GRTC_GCR_NRZM) ? 1:0;
+ config->pss_enable = (gcr & GRTC_GCR_PSS) ? 1:0;
+
+ config->crc_calc = 0;
+}
+
+/* bufsize is given in bytes */
+static int __inline__ grtc_hw_data_avail_upper(unsigned int rrp, unsigned rwp, unsigned int bufsize)
+{
+ if ( rrp == rwp )
+ return 0;
+
+ if ( rwp > rrp ) {
+ return rwp-rrp;
+ }
+
+ return (bufsize-rrp);
+}
+
+/* bufsize is given in bytes */
+static int __inline__ grtc_hw_data_avail_lower(unsigned int rrp, unsigned rwp, unsigned int bufsize)
+{
+ if ( rrp == rwp )
+ return 0;
+
+ if ( rwp > rrp ) {
+ return 0;
+ }
+
+ return rwp;
+}
+
+/* bufsize is given in bytes */
+static int __inline__ grtc_hw_data_avail(unsigned int rrp, unsigned rwp, unsigned int bufsize)
+{
+ if ( rrp == rwp )
+ return 0;
+
+ if ( rwp > rrp ) {
+ return rwp-rrp;
+ }
+
+ return rwp+(bufsize-rrp);
+}
+
+/* Reads as much as possiböe but not more than 'max' bytes from the TC receive buffer.
+ * Number of bytes put into 'buf' is returned.
+ */
+static int grtc_hw_read_try(struct grtc_priv *pDev, char *buf, int max)
+{
+ struct grtc_regs *regs = pDev->regs;
+ unsigned int rp, wp, asr, bufmax, rrp, rwp;
+ unsigned int upper, lower;
+ unsigned int count, cnt, left;
+
+ FUNCDBG();
+
+ if ( max < 1 )
+ return 0;
+
+ rp = READ_REG(&regs->rp);
+ asr = READ_REG(&regs->asr);
+ bufmax = (asr & GRTC_ASR_RXLEN) >> GRTC_ASR_RXLEN_BIT;
+ bufmax = (bufmax+1) << 10; /* Convert from 1kbyte blocks into bytes */
+ wp = READ_REG(&regs->wp);
+
+ /* Relative rp and wp */
+ rrp = rp - (asr & GRTC_ASR_BUFST);
+ rwp = wp - (asr & GRTC_ASR_BUFST);
+
+ lower = grtc_hw_data_avail_lower(rrp,rwp,bufmax);
+ upper = grtc_hw_data_avail_upper(rrp,rwp,bufmax);
+
+ DBG("grtc_hw_read_try: AVAIL: Lower: %d, Upper: %d\n",lower,upper);
+ DBG("grtc_hw_read_try: rp: 0x%x, rrp: 0x%x, wp: 0x%x, rwp: 0x%x, bufmax: %d\n, start: 0x%x\n",
+ rp,rrp,wp,rwp,bufmax,pDev->buffer);
+
+ if ( (upper+lower) == 0 )
+ return 0;
+
+ /* Count bytes will be read */
+ count = (upper+lower) > max ? max : (upper+lower);
+ left = count;
+
+ /* Read from upper part of data buffer */
+ if ( upper > 0 ){
+ if ( left < upper ){
+ cnt = left;
+ }else{
+ cnt = upper; /* Read all upper data available */
+ }
+ DBG("grtc_hw_read_try: COPYING %d from upper\n",cnt);
+ /* Convert from Remote address (RP) into CPU Local address */
+ memcpy(buf, (void *)((rp - (unsigned int)pDev->buf_remote) + (unsigned int)pDev->buf), cnt);
+ buf += cnt;
+ left -= cnt;
+ }
+
+ /* Read from lower part of data buffer */
+ if ( left > 0 ){
+ if ( left < lower ){
+ cnt = left;
+ }else{
+ cnt = lower; /* Read all lower data available */
+ }
+ DBG("grtc_hw_read_try: COPYING %d from lower\n",cnt);
+ memcpy(buf, (void *)pDev->buf, cnt);
+ buf += cnt;
+ left -= cnt;
+ }
+
+ /* Update hardware RP pointer to tell hardware about new space available */
+ if ( (rp+count) >= ((asr&GRTC_ASR_BUFST)+bufmax) ){
+ regs->rp = (rp+count-bufmax);
+ } else {
+ regs->rp = rp+count;
+ }
+
+ return count;
+}
+
+/* Reads as much as possiböe but not more than 'max' bytes from the TC receive buffer.
+ * Number of bytes put into 'buf' is returned.
+ */
+static int grtc_data_avail(struct grtc_priv *pDev)
+{
+ unsigned int rp, wp, asr, bufmax, rrp, rwp;
+ struct grtc_regs *regs = pDev->regs;
+
+ FUNCDBG();
+
+ rp = READ_REG(&regs->rp);
+ asr = READ_REG(&regs->asr);
+ bufmax = (asr & GRTC_ASR_RXLEN) >> GRTC_ASR_RXLEN_BIT;
+ bufmax = (bufmax+1) << 10; /* Convert from 1kbyte blocks into bytes */
+ wp = READ_REG(&regs->wp);
+
+ /* Relative rp and wp */
+ rrp = rp - (asr & GRTC_ASR_BUFST);
+ rwp = wp - (asr & GRTC_ASR_BUFST);
+
+ return grtc_hw_data_avail(rrp,rwp,bufmax);
+}
+
+static void *grtc_memalign(unsigned int boundary, unsigned int length, void *realbuf)
+{
+ *(int *)realbuf = (int)malloc(length+(~GRTC_ASR_BUFST)+1);
+ DBG("GRTC: Alloced %d (0x%x) bytes, requested: %d\n",length+(~GRTC_ASR_BUFST)+1,length+(~GRTC_ASR_BUFST)+1,length);
+ return (void *)(((*(unsigned int *)realbuf)+(~GRTC_ASR_BUFST)+1) & ~(boundary-1));
+}
+
+static int grtc_start(struct grtc_priv *pDev)
+{
+ struct grtc_regs *regs = pDev->regs;
+ unsigned int tmp;
+
+ if ( !pDev->buf || (((unsigned int)pDev->buf & ~GRTC_ASR_BUFST) != 0) ||
+ (pDev->len>(1024*0x100)) || (pDev->len<1024) || ((pDev->len & (1024-1)) != 0)
+ ) {
+ DBG("GRTC: start: buffer not properly allocated(0x%x,0x%x,0x%x,0x%x)\n",pDev->buf,pDev->len,((unsigned int)pDev->buf & ~GRTC_ASR_BUFST),(pDev->len & ~(1024-1)));
+ return RTEMS_NO_MEMORY;
+ }
+
+ memset(pDev->buf,0,pDev->len);
+
+ /* Software init */
+ pDev->overrun_condition = 0;
+#ifdef DEBUG_ERROR
+ pDev->last_error_cnt = 0;
+ memset(&pDev->last_error[0],0,128*sizeof(int));
+#endif
+ memset(&pDev->stats,0,sizeof(struct grtc_ioc_stats));
+
+ /* Reset the receiver */
+ regs->cor = GRTC_SEB | GRTC_COR_CRST;
+ if ( READ_REG(&regs->cor) & GRTC_COR_CRST ){
+ /* Reset Failed */
+ DBG("GRTC: start: Reseting receiver failed\n");
+ return RTEMS_IO_ERROR;
+ }
+
+ /* Set operating modes */
+ tmp = 0;
+ if ( pDev->config.psr_enable )
+ tmp |= GRTC_GCR_PSR;
+ if ( pDev->config.nrzm_enable )
+ tmp |= GRTC_GCR_NRZM;
+ if ( pDev->config.pss_enable )
+ tmp |= GRTC_GCR_PSS;
+ regs->gctrl = GRTC_SEB | tmp;
+
+ /* Clear any pending interrupt */
+ tmp = READ_REG(&regs->pir);
+ regs->picr = GRTC_INT_ALL;
+
+ /* Unmask only the Overrun interrupt */
+ regs->imr = GRTC_INT_OV;
+
+ /* Set up DMA registers
+ * 1. Let hardware know about our DMA area (size and location)
+ * 2. Set DMA read/write posistions to zero.
+ */
+ regs->asr = (unsigned int)pDev->buf_remote | ((pDev->len>>10)-1);
+ regs->rp = (unsigned int)pDev->buf_remote;
+
+ /* Mark running before enabling the receiver, we could receive
+ * an interrupt directly after enabling the receiver and it would
+ * then interpret the interrupt as spurious (see interrupt handler)
+ */
+ pDev->running = 1;
+
+ /* Enable receiver */
+ regs->cor = GRTC_SEB | GRTC_COR_RE;
+
+ DBG("GRTC: STARTED\n");
+
+ return 0;
+}
+
+static void grtc_stop(struct grtc_priv *pDev)
+{
+ struct grtc_regs *regs = pDev->regs;
+ unsigned int tmp;
+
+ /* Disable the receiver */
+ regs->cor = GRTC_SEB;
+
+ /* disable all interrupts and clear them */
+ regs->imr = 0;
+ tmp = READ_REG(&regs->pir);
+ regs->picr = GRTC_INT_ALL;
+
+ DBG("GRTC: STOPPED\n");
+
+ /* Flush semaphores in case a thread is stuck waiting for CLTUs (RX data) */
+ rtems_semaphore_flush(pDev->sem_rx);
+}
+
+/* Wait until 'count' bytes are available in receive buffer, or until
+ * the timeout expires.
+ */
+static int grtc_wait_data(struct grtc_priv *pDev, int count, rtems_interval timeout)
+{
+ int avail;
+ int ret;
+ IRQ_GLOBAL_PREPARE(oldLevel);
+
+ FUNCDBG();
+
+ if ( count < 1 )
+ return 0;
+
+ IRQ_GLOBAL_DISABLE(oldLevel);
+
+ /* Enable interrupts when receiving CLTUs, Also clear old pending CLTUs store
+ * interrupts.
+ */
+ pDev->regs->picr = GRTC_INT_CS;
+ pDev->regs->imr = READ_REG(&pDev->regs->imr) | GRTC_INT_CS;
+
+ avail = grtc_data_avail(pDev);
+ if ( avail < count ) {
+ /* Wait for interrupt. */
+
+ IRQ_GLOBAL_ENABLE(oldLevel);
+
+ if ( timeout == 0 ){
+ timeout = RTEMS_NO_TIMEOUT;
+ }
+ ret = rtems_semaphore_obtain(pDev->sem_rx,RTEMS_WAIT,timeout);
+ /* RTEMS_SUCCESSFUL = interrupt signaled data is available
+ * RTEMS_TIMEOUT = timeout expired, probably not enough data available
+ * RTEMS_UNSATISFIED = driver has been closed or an error (overrun) occured
+ * which should cancel this operation.
+ * RTEMS_OBJECT_WAS_DELETED, RTEMS_INVALID_ID = driver error.
+ */
+ IRQ_GLOBAL_DISABLE(oldLevel);
+ }else{
+ ret = RTEMS_SUCCESSFUL;
+ }
+
+ /* Disable interrupts when receiving CLTUs */
+ pDev->regs->imr = READ_REG(&pDev->regs->imr) & ~GRTC_INT_CS;
+
+ IRQ_GLOBAL_ENABLE(oldLevel);
+
+ return ret;
+}
+
+static rtems_device_driver grtc_open(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg)
+{
+ struct grtc_priv *pDev;
+ struct drvmgr_dev *dev;
+
+ FUNCDBG();
+
+ if ( drvmgr_get_dev(&grtc_drv_info.general, minor, &dev) ) {
+ DBG("Wrong minor %d\n", minor);
+ return RTEMS_INVALID_NUMBER;
+ }
+ pDev = (struct grtc_priv *)dev->priv;
+
+ /* Wait until we get semaphore */
+ if ( rtems_semaphore_obtain(grtc_dev_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT) != RTEMS_SUCCESSFUL ){
+ return RTEMS_INTERNAL_ERROR;
+ }
+
+ /* Is device in use? */
+ if ( pDev->open ){
+ rtems_semaphore_release(grtc_dev_sem);
+ return RTEMS_RESOURCE_IN_USE;
+ }
+
+ /* Mark device taken */
+ pDev->open = 1;
+
+ rtems_semaphore_release(grtc_dev_sem);
+
+ DBG("grtc_open: OPENED minor %d (pDev: 0x%x)\n",pDev->minor,(unsigned int)pDev);
+
+ /* Set defaults */
+ pDev->buf = NULL;
+ pDev->_buf = NULL;
+ pDev->buf_custom = 0;
+ pDev->buf_remote = 0;
+ pDev->len = 0;
+ pDev->timeout = 0; /* no timeout */
+ pDev->blocking = 0; /* polling mode */
+ pDev->mode = GRTC_MODE_RAW; /* Always default to Raw mode */
+ pDev->ready.head = NULL;
+ pDev->ready.tail = NULL;
+ pDev->ready.cnt = 0;
+
+ pDev->running = 0;
+
+ memset(&pDev->config,0,sizeof(pDev->config));
+
+ /* The core has been reset when we execute here, so it is possible
+ * to read out defualts from core.
+ */
+ grtc_hw_get_defaults(pDev,&pDev->config);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver grtc_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ struct grtc_priv *pDev;
+ struct drvmgr_dev *dev;
+
+ FUNCDBG();
+
+ if ( drvmgr_get_dev(&grtc_drv_info.general, minor, &dev) ) {
+ return RTEMS_INVALID_NUMBER;
+ }
+ pDev = (struct grtc_priv *)dev->priv;
+
+ if ( pDev->running ){
+ grtc_stop(pDev);
+ pDev->running = 0;
+ }
+
+ /* Reset core */
+ grtc_hw_reset(pDev);
+
+ /* Mark not open */
+ pDev->open = 0;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver grtc_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ struct grtc_priv *pDev;
+ struct drvmgr_dev *dev;
+ int count;
+ int left;
+ int timedout;
+ int err;
+ rtems_interval timeout;
+ rtems_libio_rw_args_t *rw_args;
+
+ FUNCDBG();
+
+ if ( drvmgr_get_dev(&grtc_drv_info.general, minor, &dev) ) {
+ return RTEMS_INVALID_NUMBER;
+ }
+ pDev = (struct grtc_priv *)dev->priv;
+
+ if ( !pDev->running && !pDev->overrun_condition ) {
+ return RTEMS_RESOURCE_IN_USE;
+ }
+
+ if ( pDev->mode != GRTC_MODE_RAW ) {
+ return RTEMS_NOT_DEFINED;
+ }
+
+ rw_args = (rtems_libio_rw_args_t *) arg;
+ left = rw_args->count;
+ timedout = 0;
+ timeout = pDev->timeout;
+
+read_from_buffer:
+ /* Read maximally rw_args->count bytes from receive buffer */
+ count = grtc_hw_read_try(pDev,rw_args->buffer,left);
+
+ left -= count;
+
+ DBG("READ %d bytes from DMA, left: %d\n",count,left);
+
+ if ( !timedout && !pDev->overrun_condition && ((count < 1) || ((count < rw_args->count) && (pDev->blocking == GRTC_BLKMODE_COMPLETE))) ){
+ /* didn't read anything (no data available) or we want to wait for all bytes requested.
+ *
+ * Wait for data to arrive only in blocking mode
+ */
+ if ( pDev->blocking ) {
+ if ( (err=grtc_wait_data(pDev,left,timeout)) != RTEMS_SUCCESSFUL ){
+ /* Some kind of error, closed, overrun etc. */
+ if ( err == RTEMS_TIMEOUT ){
+ /* Got a timeout, we try to read as much as possible */
+ timedout = 1;
+ goto read_from_buffer;
+ }
+ return err;
+ }
+ goto read_from_buffer;
+ }
+ /* Non-blocking mode and no data read. */
+ return RTEMS_TIMEOUT;
+ }
+
+ /* Tell caller how much was read. */
+
+ DBG("READ returning %d bytes, left: %d\n",rw_args->count-left,left);
+
+ rw_args->bytes_moved = rw_args->count - left;
+ if ( rw_args->bytes_moved == 0 ){
+ return RTEMS_TIMEOUT;
+ }
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver grtc_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ FUNCDBG();
+ return RTEMS_NOT_IMPLEMENTED;
+}
+
+static int grtc_pool_add_frms(struct grtc_frame *frms)
+{
+ struct grtc_frame *frm, *next;
+
+ /* Add frames to pools */
+ frm = frms;
+ while(frm){
+
+ if ( !frm->pool ) {
+ /* */
+ DBG("GRTC: Frame not assigned to a pool\n");
+ return -1;
+ }
+ next = frm->next; /* Remember next frame to process */
+
+ DBG("GRTC: adding frame 0x%x to pool %d (%d)\n",frm,frm->pool->frame_len,frm->pool->frame_cnt);
+
+ /* Insert Frame into pool */
+ frm->next = frm->pool->frms;
+ frm->pool->frms = frm;
+ frm->pool->frame_cnt++;
+
+ frm = next;
+ }
+
+ return 0;
+}
+
+static struct grtc_frame *grtc_pool_get_frm(struct grtc_priv *pDev, int frame_len, int *error)
+{
+ struct grtc_frame *frm;
+ struct grtc_frame_pool *pool;
+ int i;
+
+ /* Loop through all pools until a pool is found
+ * with a matching (or larger) frame length
+ */
+ pool = pDev->pools;
+ for (i=0; i<pDev->pool_cnt; i++,pool++) {
+ if ( pool->frame_len >= frame_len ) {
+ /* Found a good pool ==> get frame */
+ frm = pool->frms;
+ if ( !frm ) {
+ /* not enough frames available for this
+ * frame length, we try next
+ *
+ * If this is a severe error add your handling
+ * code here.
+ */
+#if 0
+ if ( error )
+ *error = 0;
+ return 0;
+#endif
+ continue;
+ }
+
+ /* Got a frame, the frame is taken out of the
+ * pool for usage.
+ */
+ pool->frms = frm->next;
+ pool->frame_cnt--;
+ return frm;
+ }
+ }
+
+ if ( error )
+ *error = 1;
+
+ /* Didn't find any frames */
+ return NULL;
+}
+
+/* Return number of bytes processed, Stops at the first occurance
+ * of the pattern given in 'pattern'
+ */
+static int grtc_scan(unsigned short *src, int max, unsigned char pattern, int *found)
+{
+ unsigned short tmp = 0;
+ unsigned int left = max;
+
+ while ( (left>1) && (((tmp=*src) & 0x00ff) != pattern) ) {
+ src++;
+ left-=2;
+ }
+ if ( (tmp & 0xff) == pattern ) {
+ *found = 1;
+ } else {
+ *found = 0;
+ }
+ return max-left;
+}
+
+static int grtc_copy(unsigned short *src, unsigned char *buf, int cnt)
+{
+ unsigned short tmp;
+ int left = cnt;
+
+ while ( (left>0) && ((((tmp=*src) & 0x00ff) == 0x00) || ((tmp & 0x00ff) == 0x01)) ) {
+ *buf++ = tmp>>8;
+ src++;
+ left--;
+ }
+
+ return cnt-left;
+}
+
+
+static int grtc_hw_find_frm(struct grtc_priv *pDev)
+{
+ struct grtc_regs *regs = pDev->regs;
+ unsigned int rp, wp, asr, bufmax, rrp, rwp;
+ unsigned int upper, lower;
+ unsigned int count, cnt;
+ int found;
+
+ FUNCDBG();
+
+ rp = READ_REG(&regs->rp);
+ asr = READ_REG(&regs->asr);
+ wp = READ_REG(&regs->wp);
+
+ /* Quick Check for most common case where Start of frame is at next
+ * data byte.
+ */
+ if ( rp != wp ) {
+ /* At least 1 byte in buffer */
+ if ( ((*(unsigned short *)((rp - (unsigned int)pDev->buf_remote) + (unsigned int)pDev->buf)) & 0x00ff) == 0x01 ) {
+ return 0;
+ }
+ }
+
+ bufmax = (asr & GRTC_ASR_RXLEN) >> GRTC_ASR_RXLEN_BIT;
+ bufmax = (bufmax+1) << 10; /* Convert from 1kbyte blocks into bytes */
+
+ /* Relative rp and wp */
+ rrp = rp - (asr & GRTC_ASR_BUFST);
+ rwp = wp - (asr & GRTC_ASR_BUFST);
+
+ lower = grtc_hw_data_avail_lower(rrp,rwp,bufmax);
+ upper = grtc_hw_data_avail_upper(rrp,rwp,bufmax);
+
+ DBG("grtc_hw_find_frm: AVAIL: Lower: %d, Upper: %d\n",lower,upper);
+ DBG("grtc_hw_find_frm: rp: 0x%x, rrp: 0x%x, wp: 0x%x, rwp: 0x%x, bufmax: %d\n, start: 0x%x\n",
+ rp,rrp,wp,rwp,bufmax,pDev->buf_remote);
+
+ if ( (upper+lower) == 0 )
+ return 1;
+
+ /* Count bytes will be read */
+ count = 0;
+ found = 0;
+
+ /* Read from upper part of data buffer */
+ if ( upper > 0 ){
+ cnt = grtc_scan((unsigned short *)((rp - (unsigned int)pDev->buf_remote) + (unsigned int)pDev->buf), upper, 0x01, &found);
+ count = cnt;
+ if ( found ) {
+ DBG("grtc_hw_find_frm: SCANNED upper %d bytes until found\n",cnt);
+ goto out;
+ }
+
+ DBG("grtc_hw_find_frm: SCANNED all upper %d bytes, not found\n",cnt);
+ }
+
+ /* Read from lower part of data buffer */
+ if ( lower > 0 ){
+ cnt = grtc_scan((unsigned short *)pDev->buf, lower, 0x01, &found);
+ count += cnt;
+
+ if ( found ) {
+ DBG("grtc_hw_find_frm: SCANNED lower %d bytes until found\n",cnt);
+ goto out;
+ }
+
+ DBG("grtc_hw_find_frm: SCANNED all lower %d bytes, not found\n",cnt);
+ }
+
+out:
+ /* Update hardware RP pointer to tell hardware about new space available */
+ if ( count > 0 ) {
+ if ( (rp+count) >= ((asr&GRTC_ASR_BUFST)+bufmax) ){
+ regs->rp = (rp+count-bufmax);
+ } else {
+ regs->rp = rp+count;
+ }
+ }
+ if ( found )
+ return 0;
+ return 1;
+
+}
+
+static int grtc_check_ending(unsigned short *src, int max, int end)
+{
+ while ( max > 0 ) {
+ /* Check Filler */
+ if ( *src != 0x5500 ) {
+ /* Filler is wrong */
+ return -1;
+ }
+ src++;
+ max-=2;
+ }
+
+ /* Check ending (at least */
+ if ( end ) {
+ if ( (*src & 0x00ff) != 0x02 ) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int grtc_hw_check_ending(struct grtc_priv *pDev, int max)
+{
+ struct grtc_regs *regs = pDev->regs;
+ unsigned int rp, wp, asr, bufmax, rrp, rwp;
+ unsigned int upper, lower;
+ unsigned int count, cnt, left;
+ int tot;
+
+ FUNCDBG();
+
+ if ( max < 1 )
+ return 0;
+ max = max*2;
+ max += 2; /* Check ending also (2 byte extra) */
+
+ rp = READ_REG(&regs->rp);
+ asr = READ_REG(&regs->asr);
+ bufmax = (asr & GRTC_ASR_RXLEN) >> GRTC_ASR_RXLEN_BIT;
+ bufmax = (bufmax+1) << 10; /* Convert from 1kbyte blocks into bytes */
+ wp = READ_REG(&regs->wp);
+
+ /* Relative rp and wp */
+ rrp = rp - (asr & GRTC_ASR_BUFST);
+ rwp = wp - (asr & GRTC_ASR_BUFST);
+
+ lower = grtc_hw_data_avail_lower(rrp,rwp,bufmax);
+ upper = grtc_hw_data_avail_upper(rrp,rwp,bufmax);
+
+ DBG("grtc_hw_check_ending: AVAIL: Lower: %d, Upper: %d\n",lower,upper);
+ DBG("grtc_hw_check_ending: rp: 0x%x, rrp: 0x%x, wp: 0x%x, rwp: 0x%x, bufmax: %d\n, start: 0x%x\n",
+ rp,rrp,wp,rwp,bufmax,pDev->buf_remote);
+
+ if ( (upper+lower) < max )
+ return 0;
+
+ /* Count bytes will be read */
+ count = max;
+ left = count;
+ tot = 0;
+
+ /* Read from upper part of data buffer */
+ if ( upper > 0 ){
+ if ( left <= upper ){
+ cnt = left;
+ if ( grtc_check_ending((unsigned short *)((rp-(unsigned int)pDev->buf_remote)+(unsigned int)pDev->buf), cnt-2, 1) ) {
+ return -1;
+ }
+ }else{
+ cnt = upper; /* Read all upper data available */
+ if ( grtc_check_ending((unsigned short *)((rp-(unsigned int)pDev->buf_remote)+(unsigned int)pDev->buf), cnt, 0) ) {
+ return -1;
+ }
+ }
+ left -= cnt;
+ }
+
+ /* Read from lower part of data buffer */
+ if ( left > 0 ){
+ cnt = left;
+ if ( grtc_check_ending((unsigned short *)pDev->buf, cnt-2, 1) ) {
+ return -1;
+ }
+ left -= cnt;
+ }
+
+ /* Update hardware RP pointer to tell hardware about new space available */
+ if ( (rp+count) >= ((asr&GRTC_ASR_BUFST)+bufmax) ){
+ regs->rp = (rp+count-bufmax);
+ } else {
+ regs->rp = rp+count;
+ }
+
+ return 0;
+}
+
+/* Copies Data from DMA area to buf, the control bytes are stripped. For
+ * every data byte, in the DMA area, one control byte is stripped.
+ */
+static int grtc_hw_copy(struct grtc_priv *pDev, unsigned char *buf, int max, int partial)
+{
+ struct grtc_regs *regs = pDev->regs;
+ unsigned int rp, wp, asr, bufmax, rrp, rwp;
+ unsigned int upper, lower;
+ unsigned int count, cnt, left;
+ int ret, tot, tmp;
+
+ FUNCDBG();
+
+ if ( max < 1 )
+ return 0;
+
+ rp = READ_REG(&regs->rp);
+ asr = READ_REG(&regs->asr);
+ bufmax = (asr & GRTC_ASR_RXLEN) >> GRTC_ASR_RXLEN_BIT;
+ bufmax = (bufmax+1) << 10; /* Convert from 1kbyte blocks into bytes */
+ wp = READ_REG(&regs->wp);
+
+ /* Relative rp and wp */
+ rrp = rp - (asr & GRTC_ASR_BUFST);
+ rwp = wp - (asr & GRTC_ASR_BUFST);
+
+ lower = grtc_hw_data_avail_lower(rrp,rwp,bufmax) >> 1;
+ upper = grtc_hw_data_avail_upper(rrp,rwp,bufmax) >> 1;
+
+ DBG("grtc_hw_copy: AVAIL: Lower: %d, Upper: %d\n",lower,upper);
+ DBG("grtc_hw_copy: rp: 0x%x, rrp: 0x%x, wp: 0x%x, rwp: 0x%x, bufmax: %d\n, start: 0x%x\n",
+ rp,rrp,wp,rwp,bufmax,pDev->buf_remote);
+
+ if ( (upper+lower) == 0 || (!partial && ((upper+lower)<max) ) )
+ return 0;
+
+ /* Count bytes will be read */
+ count = (upper+lower) > max ? max : (upper+lower);
+ left = count;
+ tot = 0;
+
+ /* Read from upper part of data buffer */
+ if ( upper > 0 ){
+ if ( left < upper ){
+ cnt = left;
+ }else{
+ cnt = upper; /* Read all upper data available */
+ }
+ DBG("grtc_hw_copy: COPYING %d from upper\n",cnt);
+ if ( (tot=grtc_copy((unsigned short *)((rp-(unsigned int)pDev->buf_remote)+(unsigned int)pDev->buf), buf, cnt)) != cnt ) {
+ /* Failed to copy due to an receive error */
+ DBG("grtc_hw_copy(upper): not all in DMA buffer (%d)\n",tot);
+ count = tot;
+ ret = -1;
+ goto out;
+ }
+ buf += cnt;
+ left -= cnt;
+ }
+
+ /* Read from lower part of data buffer */
+ if ( left > 0 ){
+ if ( left < lower ){
+ cnt = left;
+ }else{
+ cnt = lower; /* Read all lower data available */
+ }
+ DBG("grtc_hw_copy: COPYING %d from lower\n",cnt);
+ if ( (tmp=grtc_copy((unsigned short *)pDev->buf, buf, cnt)) != cnt ) {
+ /* Failed to copy due to an receive error */
+ DBG("grtc_hw_copy(lower): not all in DMA buffer (%d)\n",tot);
+ count = tot+tmp;
+ ret = -1;
+ goto out;
+ }
+ buf += cnt;
+ left -= cnt;
+ }
+ ret = count;
+
+out:
+ count = count*2;
+ /* Update hardware RP pointer to tell hardware about new space available */
+ if ( (rp+count) >= ((asr&GRTC_ASR_BUFST)+bufmax) ){
+ regs->rp = (rp+count-bufmax);
+ } else {
+ regs->rp = rp+count;
+ }
+
+ return ret;
+}
+
+#ifdef DEBUG_ERROR
+void grtc_log_error(struct grtc_priv *pDev, int err)
+{
+ /* Stop Receiver */
+ *(volatile unsigned int *)&pDev->regs->cor = 0x55000000;
+ *(volatile unsigned int *)&pDev->regs->cor = 0x55000000;
+ pDev->last_error[pDev->last_error_cnt] = err;
+ if ( ++pDev->last_error_cnt > 128 )
+ pDev->last_error_cnt = 0;
+}
+#endif
+
+/* Read one frame from DMA buffer
+ *
+ * Return Values
+ * Zero - nothing more to process
+ * 1 - more to process, no free frames
+ * 2 - more to process, frame received
+ * negative - more to process, frame dropped
+ */
+static int process_dma(struct grtc_priv *pDev)
+{
+ int ret, err;
+ int left, total_len;
+ unsigned char *dst;
+ struct grtc_frame *frm;
+
+ switch( pDev->frame_state ) {
+ case FRM_STATE_NONE:
+ DBG2("FRAME_STATE_NONE\n");
+
+ /* Find Start of next frame by searching for 0x01 */
+ ret = grtc_hw_find_frm(pDev);
+ if ( ret != 0 ) {
+ /* Frame start not found */
+ return 0;
+ }
+
+ /* Start of frame found, Try to copy header */
+ pDev->frm = NULL;
+ pDev->frame_state = FRM_STATE_HDR;
+
+ case FRM_STATE_HDR:
+ DBG2("FRAME_STATE_HDR\n");
+
+ /* Wait for all of header to be in place by setting partial to 0 */
+ ret = grtc_hw_copy(pDev,pDev->hdr,5,0);
+ if ( ret < 0 ) {
+ /* Error copying header, restart scanning for new frame */
+ DEBUG_ERR_LOG(pDev,1);
+ pDev->stats.err++;
+ pDev->stats.err_hdr++;
+ DBG("FRAME_STATE_HDR: copying failed %d\n",ret);
+ pDev->frame_state = FRM_STATE_NONE;
+ return -1;
+ } else if ( ret != 5 ) {
+ DBG("FRAME_STATE_HDR: no header (%d)\n",ret);
+ /* Not all bytes available, come back later */
+ return 0;
+ }
+
+ /* The complete header has been copied, parse it */
+ pDev->frmlen = ((*(unsigned short *)&pDev->hdr[2]) & 0x3ff)+1;
+ if ( pDev->frmlen < 5 ) {
+ /* Error: frame length is not correct */
+ pDev->stats.err++;
+ pDev->stats.err_hdr++;
+ DBG("FRAME_STATE_HDR: frame length error: %d\n", pDev->frmlen);
+ pDev->frame_state = FRM_STATE_NONE;
+ return -1;
+ }
+ pDev->frame_state = FRM_STATE_ALLOC;
+
+ case FRM_STATE_ALLOC:
+ DBG2("FRAME_STATE_ALLOC\n");
+ /* Header has been read, allocate a frame to put payload and header into */
+
+ /* Allocate Frame matching Frame length */
+ err = 0;
+ frm = grtc_pool_get_frm(pDev,pDev->frmlen,&err);
+ if ( !frm ) {
+ /* Couldn't find frame */
+ DEBUG_ERR_LOG(pDev,2);
+ pDev->stats.dropped++;
+ DBG2("No free frames\n");
+ if ( err == 0 ){
+ /* Frame length exist in pool configuration, but no
+ * frames are available for that frame length.
+ */
+ DEBUG_ERR_LOG(pDev,3);
+ pDev->stats.dropped_no_buf++;
+ return 1;
+ } else {
+ /* Frame length of incoming frame is larger than the
+ * frame length in any of the configured frame pools.
+ *
+ * This may be because of an corrupt header. We simply
+ * scan for the end of frame marker in the DMA buffer
+ * so we can drop the frame.
+ */
+ DEBUG_ERR_LOG(pDev,4);
+ pDev->stats.dropped_too_long++;
+ pDev->frame_state = FRM_STATE_NONE;
+ return -2;
+ }
+ }
+ frm->len = 5; /* Only header currenlty in frame */
+
+ /* Copy Frame Header into frame structure */
+ *((unsigned char *)&frm->hdr + 0) = pDev->hdr[0];
+ *((unsigned char *)&frm->hdr + 1) = pDev->hdr[1];
+ *((unsigned char *)&frm->hdr + 2) = pDev->hdr[2];
+ *((unsigned char *)&frm->hdr + 3) = pDev->hdr[3];
+ *((unsigned char *)&frm->hdr + 4) = pDev->hdr[4];
+
+ /* Calc Total and Filler byte count in frame */
+ total_len = pDev->frmlen / 7;
+ total_len = total_len * 7;
+ if ( pDev->frmlen != total_len )
+ total_len += 7;
+
+ pDev->filler = total_len - pDev->frmlen;
+
+ pDev->frame_state = FRM_STATE_PAYLOAD;
+ pDev->frm = frm;
+
+ case FRM_STATE_PAYLOAD:
+ DBG2("FRAME_STATE_PAYLOAD\n");
+ /* Parts of payload and the complete header has been read */
+ frm = pDev->frm;
+
+ dst = (unsigned char *)&frm->data[frm->len-5];
+ left = pDev->frmlen-frm->len;
+
+ ret = grtc_hw_copy(pDev,dst,left,1);
+ if ( ret < 0 ) {
+ DEBUG_ERR_LOG(pDev,5);
+ /* Error copying header, restart scanning for new frame */
+ pDev->frame_state = FRM_STATE_NONE;
+ frm->next = NULL;
+ grtc_pool_add_frms(frm);
+ pDev->frm = NULL;
+ pDev->stats.err++;
+ pDev->stats.err_payload++;
+ return -1;
+ } else if ( ret != left ) {
+ /* Not all bytes available, come back later */
+ frm->len += ret;
+ return 0;
+ }
+ frm->len += ret;
+ pDev->frame_state = FRM_STATE_FILLER;
+
+ case FRM_STATE_FILLER:
+ DBG2("FRAME_STATE_FILLER\n");
+ /* check filler data */
+ frm = pDev->frm;
+
+ ret = grtc_hw_check_ending(pDev,pDev->filler);
+ if ( ret != 0 ) {
+ /* Error in frame, drop frame */
+ DEBUG_ERR_LOG(pDev,6);
+ pDev->frame_state = FRM_STATE_NONE;
+ frm->next = NULL;
+ grtc_pool_add_frms(frm);
+ pDev->frm = NULL;
+ pDev->stats.err++;
+ pDev->stats.err_ending++;
+ return -1;
+ }
+
+ /* A complete frame received, put it into received frame queue */
+ if ( pDev->ready.head ) {
+ /* Queue not empty */
+ pDev->ready.tail->next = frm;
+ } else {
+ /* Queue empty */
+ pDev->ready.head = frm;
+ }
+ pDev->ready.tail = frm;
+ frm->next = NULL;
+ pDev->ready.cnt++;
+ pDev->stats.frames_recv++;
+
+ pDev->frame_state = FRM_STATE_NONE;
+ frm->next = NULL;
+ return 2;
+
+#if 0
+ case FRM_STATE_DROP:
+ DBG2("FRAME_STATE_DROP\n");
+ break;
+#endif
+
+ default:
+ printk("GRTC: internal error\n");
+ pDev->frame_state = FRM_STATE_NONE;
+ break;
+ }
+
+ return 0;
+}
+
+static rtems_device_driver grtc_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ struct grtc_priv *pDev;
+ struct drvmgr_dev *dev;
+ rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *)arg;
+ unsigned int *data = ioarg->buffer;
+ int status,frm_len,i,ret;
+ struct grtc_ioc_buf_params *buf_arg;
+ struct grtc_ioc_config *cfg;
+ struct grtc_ioc_hw_status *hwregs;
+ struct grtc_ioc_pools_setup *pocfg;
+ struct grtc_ioc_assign_frm_pool *poassign;
+ struct grtc_frame *frm, *frms;
+ struct grtc_frame_pool *pool;
+ struct grtc_list *frmlist;
+ struct grtc_ioc_stats *stats;
+ unsigned int mem;
+
+ IRQ_GLOBAL_PREPARE(oldLevel);
+
+ FUNCDBG();
+
+ if ( drvmgr_get_dev(&grtc_drv_info.general, minor, &dev) ) {
+ return RTEMS_INVALID_NUMBER;
+ }
+ pDev = (struct grtc_priv *)dev->priv;
+
+ if (!ioarg)
+ return RTEMS_INVALID_NAME;
+
+ ioarg->ioctl_return = 0;
+ switch(ioarg->command) {
+ case GRTC_IOC_START:
+ if ( pDev->running ) {
+ return RTEMS_RESOURCE_IN_USE; /* EBUSY */
+ }
+ if ( (status=grtc_start(pDev)) != RTEMS_SUCCESSFUL ){
+ return status;
+ }
+ /* Register ISR and Unmask interrupt */
+ drvmgr_interrupt_register(pDev->dev, 0, "grtc", grtc_interrupt, pDev);
+
+ /* Read and write are now open... */
+ break;
+
+ case GRTC_IOC_STOP:
+ if ( !pDev->running ) {
+ return RTEMS_RESOURCE_IN_USE;
+ }
+ drvmgr_interrupt_unregister(pDev->dev, 0, grtc_interrupt, pDev);
+ grtc_stop(pDev);
+ pDev->running = 0;
+ break;
+
+ case GRTC_IOC_ISSTARTED:
+ if ( !pDev->running ) {
+ return RTEMS_RESOURCE_IN_USE;
+ }
+ break;
+
+ case GRTC_IOC_SET_BLOCKING_MODE:
+ if ( (unsigned int)data > GRTC_BLKMODE_COMPLETE ) {
+ return RTEMS_INVALID_NAME;
+ }
+ DBG("GRTC: Set blocking mode: %d\n",(unsigned int)data);
+ pDev->blocking = (unsigned int)data;
+ break;
+
+ case GRTC_IOC_SET_TIMEOUT:
+ DBG("GRTC: Timeout: %d\n",(unsigned int)data);
+ pDev->timeout = (rtems_interval)data;
+ break;
+
+ case GRTC_IOC_SET_BUF_PARAM:
+ if ( pDev->running ) {
+ return RTEMS_RESOURCE_IN_USE; /* EBUSY */
+ }
+
+ buf_arg = (struct grtc_ioc_buf_params *)data;
+ if ( !buf_arg ) {
+ return RTEMS_INVALID_NAME;
+ }
+
+ DBG("GRTC: IOC_SET_BUF_PARAM: Len: 0x%x, Custom Buffer: 0x%x\n",buf_arg->length,buf_arg->custom_buffer);
+
+ /* Check alignment need, skip bit 0 since that bit only indicates remote address or not */
+ if ( (unsigned int)buf_arg->custom_buffer & (~GRTC_BUF_MASK) & (~0x1) ) {
+ return RTEMS_INVALID_NAME;
+ }
+
+ if ( buf_arg->length > 0x100 ){
+ DBG("GRTC: Too big buffer requested\n");
+ return RTEMS_INVALID_NAME;
+ }
+
+ /* If current buffer allocated by driver we must free it */
+ if ( !pDev->buf_custom && pDev->buf ){
+ free(pDev->_buf);
+ pDev->_buf = NULL;
+ }
+ pDev->buf = NULL;
+ pDev->len = buf_arg->length*1024;
+
+ if ( pDev->len > 0 ){
+ if ( buf_arg->custom_buffer ){
+ if ( (unsigned int)buf_arg->custom_buffer & 1 ) {
+ /* Remote address given, the address is as the GRTC core looks at it */
+
+ /* Translate the base address into an address that the the CPU can understand */
+ mem = ((unsigned int)buf_arg->custom_buffer & ~1);
+ drvmgr_translate(pDev->dev, 1, 1, (void *)mem, (void **)&pDev->buf);
+ } else {
+ pDev->buf = buf_arg->custom_buffer;
+ }
+ pDev->buf_custom = 1;
+ }else{
+ pDev->buf = grtc_memalign((~GRTC_ASR_BUFST)+1,pDev->len,&pDev->_buf);
+ DBG("grtc_ioctl: SETBUF: new buf: 0x%x(0x%x), Len: %d\n",pDev->buf,pDev->_buf,pDev->len);
+ if ( !pDev->buf ){
+ pDev->len = 0;
+ pDev->buf_custom = 0;
+ pDev->_buf = NULL;
+ pDev->buf_remote = 0;
+ DBG("GRTC: Failed to allocate memory\n");
+ return RTEMS_NO_MEMORY;
+ }
+ }
+ }
+ /* Translate into a remote address so that GRTC core on a remote AMBA bus (for example over the PCI bus) gets a valid address */
+ drvmgr_translate(pDev->dev, 0, 0, (void *)pDev->buf, (void **)&pDev->buf_remote);
+ break;
+
+ case GRTC_IOC_GET_BUF_PARAM:
+ if ( pDev->running ) {
+ return RTEMS_RESOURCE_IN_USE; /* EBUSY */
+ }
+
+ buf_arg = (struct grtc_ioc_buf_params *)data;
+ if ( !buf_arg ) {
+ return RTEMS_INVALID_NAME;
+ }
+
+ buf_arg->length = pDev->len >> 10; /* Length in 1kByte blocks */
+ if ( pDev->buf_custom )
+ buf_arg->custom_buffer =(void *)pDev->buf;
+ else
+ buf_arg->custom_buffer = 0; /* Don't reveal internal driver buffer */
+ break;
+
+ case GRTC_IOC_SET_CONFIG:
+ cfg = (struct grtc_ioc_config *)data;
+ if ( !cfg ) {
+ return RTEMS_INVALID_NAME;
+ }
+
+ if ( pDev->running ) {
+ return RTEMS_RESOURCE_IN_USE;
+ }
+
+ pDev->config = *cfg;
+ break;
+
+ case GRTC_IOC_GET_CONFIG:
+ cfg = (struct grtc_ioc_config *)data;
+ if ( !cfg ) {
+ return RTEMS_INVALID_NAME;
+ }
+
+ *cfg = pDev->config;
+ break;
+
+ case GRTC_IOC_GET_HW_STATUS:
+ hwregs = (struct grtc_ioc_hw_status *)data;
+ if ( !hwregs ) {
+ return RTEMS_INVALID_NAME;
+ }
+ /* We disable interrupt in order to get a snapshot of the registers */
+ IRQ_GLOBAL_DISABLE(oldLevel);
+ hwregs->sir = READ_REG(&pDev->regs->sir);
+ hwregs->far = READ_REG(&pDev->regs->far);
+ hwregs->clcw1 = READ_REG(&pDev->regs->clcw1);
+ hwregs->clcw2 = READ_REG(&pDev->regs->clcw2);
+ hwregs->phir = READ_REG(&pDev->regs->phir);
+ hwregs->str = READ_REG(&pDev->regs->str);
+ IRQ_GLOBAL_ENABLE(oldLevel);
+ break;
+
+ case GRTC_IOC_GET_STATS:
+ stats = (struct grtc_ioc_stats *)data;
+ if ( !stats ) {
+ return RTEMS_INVALID_NAME;
+ }
+ memcpy(stats,&pDev->stats,sizeof(struct grtc_ioc_stats));
+ break;
+
+ case GRTC_IOC_CLR_STATS:
+ memset(&pDev->stats,0,sizeof(struct grtc_ioc_stats));
+ break;
+
+ case GRTC_IOC_SET_MODE:
+ if ( pDev->running ) {
+ return RTEMS_RESOURCE_IN_USE;
+ }
+ if ( (int)data == GRTC_MODE_FRAME ) {
+ pDev->mode = GRTC_MODE_FRAME;
+ } else if ( (int)data == GRTC_MODE_RAW ) {
+ pDev->mode = GRTC_MODE_RAW;
+ } else {
+ return RTEMS_INVALID_NAME;
+ }
+ break;
+
+ case GRTC_IOC_POOLS_SETUP:
+ if ( pDev->running ) {
+ return RTEMS_RESOURCE_IN_USE;
+ }
+ pocfg = (struct grtc_ioc_pools_setup *)data;
+ if ( (pDev->mode != GRTC_MODE_FRAME) || !pocfg ) {
+ return RTEMS_INVALID_NAME;
+ }
+
+ /* Check that list is sorted */
+ frm_len = 0;
+ for(i=0;i<pocfg->pool_cnt;i++){
+ if ( pocfg->pool_frame_len[i] <= frm_len ) {
+ return RTEMS_INVALID_NAME;
+ }
+ frm_len = pocfg->pool_frame_len[i];
+ }
+
+ /* Ok, we trust user. The pool descriptions are allocated
+ * but not frames, that the user must do self.
+ */
+ if ( pDev->pools ) {
+ free(pDev->pools);
+ }
+ pDev->pools = malloc(pocfg->pool_cnt * sizeof(struct grtc_frame_pool));
+ if ( !pDev->pools ) {
+ pDev->pool_cnt = 0;
+ return RTEMS_NO_MEMORY;
+ }
+ pDev->pool_cnt = pocfg->pool_cnt;
+ for (i=0;i<pocfg->pool_cnt;i++) {
+ pDev->pools[i].frame_len = pocfg->pool_frame_len[i];
+ pDev->pools[i].frame_cnt = 0;
+ pDev->pools[i].frms = NULL;
+ }
+ break;
+
+ case GRTC_IOC_ASSIGN_FRM_POOL:
+ if ( pDev->running ) {
+ return RTEMS_RESOURCE_IN_USE;
+ }
+
+ if ( (pDev->mode != GRTC_MODE_FRAME) ) {
+ return RTEMS_INVALID_NAME;
+ }
+
+ poassign = (struct grtc_ioc_assign_frm_pool *)data;
+ if ( !poassign ) {
+ return RTEMS_INVALID_NAME;
+ }
+
+ /* Find pool to assign the frames to */
+ pool = NULL;
+ for(i=0; i<pDev->pool_cnt; i++) {
+ if ( pDev->pools[i].frame_len == poassign->frame_len ) {
+ pool = &pDev->pools[i];
+ break;
+ }
+ }
+ if ( !pool ) {
+ /* No Pool matching frame length */
+ return RTEMS_INVALID_NAME;
+ }
+
+ /* Assign frames to pool */
+ frm = poassign->frames;
+ while(frm){
+ frm->pool = pool; /* Assign Frame to pool */
+ frm = frm->next;
+ }
+ break;
+
+ case GRTC_IOC_ADD_BUFF:
+ frms = (struct grtc_frame *)data;
+
+ if ( (pDev->mode != GRTC_MODE_FRAME) ) {
+ return RTEMS_NOT_DEFINED;
+ }
+ if ( !frms ) {
+ return RTEMS_INVALID_NAME;
+ }
+
+ /* Add frames to respicative pools */
+ if ( grtc_pool_add_frms(frms) ) {
+ return RTEMS_INVALID_NAME;
+ }
+ break;
+
+ /* Try to read as much data as possible from DMA area and
+ * put it into free frames.
+ *
+ * If receiver is in stopped mode, let user only read previously
+ * received frames.
+ */
+ case GRTC_IOC_RECV:
+
+ if ( (pDev->mode != GRTC_MODE_FRAME) ) {
+ return RTEMS_NOT_DEFINED;
+ }
+
+ while ( pDev->running && ((ret=process_dma(pDev) == 2) || (ret == -1)) ) {
+ /* Frame received or dropped, process next frame */
+ }
+
+ /* Take frames out from ready queue and put them to user */
+ frmlist = (struct grtc_list *)data;
+ if ( !frmlist ) {
+ return RTEMS_INVALID_NAME;
+ }
+
+ frmlist->head = pDev->ready.head;
+ frmlist->tail = pDev->ready.tail;
+ frmlist->cnt = pDev->ready.cnt;
+
+ /* Empty list */
+ pDev->ready.head = NULL;
+ pDev->ready.tail = NULL;
+ pDev->ready.cnt = 0;
+ break;
+
+ case GRTC_IOC_GET_CLCW_ADR:
+ if ( !data ) {
+ return RTEMS_INVALID_NAME;
+ }
+ *data = (unsigned int)&pDev->regs->clcw1;
+ break;
+
+ default:
+ return RTEMS_NOT_DEFINED;
+ }
+ return RTEMS_SUCCESSFUL;
+}
+
+static void grtc_interrupt(void *arg)
+{
+ struct grtc_priv *pDev = arg;
+ struct grtc_regs *regs = pDev->regs;
+ unsigned int status;
+
+ /* Clear interrupt by reading it */
+ status = READ_REG(&regs->pisr);
+
+ /* Spurious Interrupt? */
+ if ( !pDev->running )
+ return;
+
+ if ( status & GRTC_INT_OV ){
+
+ /* Stop core (Disable receiver, interrupts), set overrun condition,
+ * Flush semaphore if thread waiting for data in grtc_wait_data().
+ */
+ pDev->overrun_condition = 1;
+
+ grtc_stop(pDev);
+
+ /* No need to handle the reset of interrupts, we are still */
+ goto out;
+ }
+
+ if ( status & GRTC_INT_CS ){
+ if ( (pDev->blocking==GRTC_BLKMODE_COMPLETE) && pDev->timeout ){
+ /* Signal to thread only if enough data is available */
+ if ( pDev->wait_for_nbytes > grtc_data_avail(pDev) ){
+ /* Not enough data available */
+ goto procceed_processing_interrupts;
+ }
+
+ /* Enough data is available which means that we should wake
+ * up thread sleeping.
+ */
+ }
+
+ /* Disable further CLTUs Stored interrupts, no point until thread waiting for them
+ * say it want to wait for more.
+ */
+ regs->imr = READ_REG(&regs->imr) & ~GRTC_INT_CS;
+
+ /* Signal Semaphore to wake waiting thread in read() */
+ rtems_semaphore_release(pDev->sem_rx);
+ }
+
+procceed_processing_interrupts:
+
+ if ( status & GRTC_INT_CR ){
+
+ }
+
+ if ( status & GRTC_INT_FAR ){
+
+ }
+
+ if ( status & GRTC_INT_BLO ){
+
+ }
+
+ if ( status & GRTC_INT_RFA ){
+
+ }
+out:
+ if ( status )
+ regs->picr = status;
+}
+
+static rtems_device_driver grtc_initialize(
+ rtems_device_major_number major,
+ rtems_device_minor_number unused,
+ void *arg
+ )
+{
+ /* Device Semaphore created with count = 1 */
+ if ( rtems_semaphore_create(rtems_build_name('G', 'R', 'T', 'C'),
+ 1,
+ RTEMS_FIFO|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &grtc_dev_sem) != RTEMS_SUCCESSFUL ) {
+ return RTEMS_INTERNAL_ERROR;
+ }
+
+ return RTEMS_SUCCESSFUL;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/tmtc/grtc_rmap.c b/c/src/lib/libbsp/sparc/shared/tmtc/grtc_rmap.c
new file mode 100644
index 0000000000..ac4586797f
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/tmtc/grtc_rmap.c
@@ -0,0 +1,2233 @@
+/* GRTC Telecommand decoder driver
+ *
+ * --------------------------------------------------------------------------
+ * -- This file is a part of GAISLER RESEARCH source code.
+ * -- Copyright (C) 2009, Aeroflex Gaisler AB - all rights reserved.
+ * --
+ * -- ANY USE OR REDISTRIBUTION IN PART OR IN WHOLE MUST BE HANDLED IN
+ * -- ACCORDANCE WITH THE GAISLER LICENSE AGREEMENT AND MUST BE APPROVED
+ * -- IN ADVANCE IN WRITING.
+ * --
+ * -- BY DEFAULT, DISTRIBUTION OR DISCLOSURE IS NOT PERMITTED.
+ * --------------------------------------------------------------------------
+ *
+ * The BSP define GRTC_RMAP_INFO_AVAIL in order to add the info routine
+ * used for debugging.
+ *
+ * 2009-11-21, Daniel Hellstrom <daniel@gaisler.com>
+ * Created from on-chip GRTC driver
+ *
+ */
+
+#include <bsp.h>
+#include <rtems/libio.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+#include <malloc.h>
+#include <rtems/bspIo.h>
+
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+#include <drvmgr/ambapp_bus_rmap.h>
+#include <ambapp.h>
+#include <grtc.h>
+
+#ifndef IRQ_GLOBAL_PREPARE
+ #define IRQ_GLOBAL_PREPARE(level) rtems_interrupt_level level
+#endif
+
+#ifndef IRQ_GLOBAL_DISABLE
+ #define IRQ_GLOBAL_DISABLE(level) rtems_interrupt_disable(level)
+#endif
+
+#ifndef IRQ_GLOBAL_ENABLE
+ #define IRQ_GLOBAL_ENABLE(level) rtems_interrupt_enable(level)
+#endif
+
+/**** START: RMAP STUFF ****/
+#define DESCRIPTOR_MAX 128
+#define WRITE_REG(pDev, adr, value) pDev->rw_w32((uint32_t *)adr, (uint32_t)value, &pDev->rw_arg)
+#define READ_REG(pDev, adr) pDev->rw_r32((uint32_t *)adr, &pDev->rw_arg)
+#define MEMGET(pDev, dst, src, len) pDev->rw_rmem(dst, (const void *)src, len, &pDev->rw_arg)
+
+/**** END: RMAP STUFF ****/
+
+/*
+#define DEBUG
+#define DEBUGFUNCS
+*/
+
+#include <debug_defs.h>
+
+#ifdef DEBUG_ERROR
+#define DEBUG_ERR_LOG(device,error) grtc_log_error(device,error)
+#else
+#define DEBUG_ERR_LOG(device,error)
+#endif
+
+/* GRTC register map */
+struct grtc_regs {
+ volatile unsigned int grst; /* Global Reset Register (GRR 0x00) */
+ volatile unsigned int gctrl; /* Global Control Register (GCR 0x04) */
+ int unused0;
+ volatile unsigned int sir; /* Spacecraft Identifier Register (SIR 0x0c) */
+ volatile unsigned int far; /* Frame Acceptance Report Register (FAR 0x10) */
+
+ volatile unsigned int clcw1; /* CLCW Register 1 (CLCWR1 0x14) */
+ volatile unsigned int clcw2; /* CLCW Register 2 (CLCWR2 0x18) */
+ volatile unsigned int phir; /* Physical Interface Register (PHIR 0x1c) */
+ volatile unsigned int cor; /* Control Register (COR 0x20) */
+
+ volatile unsigned int str; /* Status Register (STR 0x24) */
+ volatile unsigned int asr; /* Address Space Register (ASR 0x28) */
+ volatile unsigned int rp; /* Receive Read Pointer Register (RRP 0x2c) */
+ volatile unsigned int wp; /* Receive Write Pointer Register (RWP 0x30) */
+
+ int unused1[(0x60-0x34)/4];
+
+ volatile unsigned int pimsr; /* Pending Interrupt Masked Status Register (PIMSR 0x60) */
+ volatile unsigned int pimr; /* Pending Interrupt Masked Register (PIMR 0x64) */
+ volatile unsigned int pisr; /* Pending Interrupt Status Register (PISR 0x68) */
+ volatile unsigned int pir; /* Pending Interrupt Register (PIR 0x6c) */
+ volatile unsigned int imr; /* Interrupt Mask Register (IMR 0x70) */
+ volatile unsigned int picr; /* Pending Interrupt Clear Register (PICR 0x74) */
+};
+
+/* Security Byte */
+#define GRTC_SEB 0x55000000
+
+/* Global Reset Register (GRR 0x00) */
+#define GRTC_GRR_SRST 0x1
+#define GRTC_GRR_SRST_BIT 0
+
+/* Global Control Register (GCR 0x04) */
+#define GRTC_GCR_PSR_BIT 10
+#define GRTC_GCR_NRZM_BIT 11
+#define GRTC_GCR_PSS_BIT 12
+
+#define GRTC_GCR_PSR (1<<GRTC_GCR_PSR_BIT)
+#define GRTC_GCR_NRZM (1<<GRTC_GCR_NRZM_BIT)
+#define GRTC_GCR_PSS (1<<GRTC_GCR_PSS_BIT)
+
+/* Spacecraft Identifier Register (SIR 0x0c) */
+
+
+/* Frame Acceptance Report Register (FAR 0x10) */
+#define GRTC_FAR_SCI_BIT 10
+#define GRTC_FAR_CSEC_BIT 11
+#define GRTC_FAR_CAC_BIT 12
+#define GRTC_FAR_SSD_BIT 13
+
+#define GRTC_FAR_SCI (0x7<<GRTC_FAR_SCI_BIT)
+#define GRTC_FAR_CSEC (0x7<<GRTC_FAR_CSEC_BIT)
+#define GRTC_FAR_CAC (0x3f<<GRTC_FAR_CAC_BIT)
+#define GRTC_FAR_SSD (1<<GRTC_FAR_SSD_BIT)
+
+/* CLCW Register 1 (CLCWR1 0x14) */
+/* CLCW Register 2 (CLCWR2 0x18) */
+#define GRTC_CLCW_RVAL_BIT 0
+#define GRTC_CLCW_RTYPE_BIT 8
+#define GRTC_CLCW_FBCO_BIT 9
+#define GRTC_CLCW_RTMI_BIT 11
+#define GRTC_CLCW_WAIT_BIT 12
+#define GRTC_CLCW_LOUT_BIT 13
+#define GRTC_CLCW_NBLO_BIT 14
+#define GRTC_CLCW_NRFA_BIT 15
+#define GRTC_CLCW_VCI_BIT 18
+#define GRTC_CLCW_CIE_BIT 24
+#define GRTC_CLCW_STAF_BIT 26
+#define GRTC_CLCW_VNUM_BIT 29
+#define GRTC_CLCW_CWTY_BIT 31
+
+#define GRTC_CLCW_RVAL (0xff<<GRTC_CLCW_RVAL_BIT)
+#define GRTC_CLCW_RTYPE (1<<GRTC_CLCW_RTYPE_BIT)
+#define GRTC_CLCW_FBCO (0x3<<GRTC_CLCW_FBCO_BIT)
+#define GRTC_CLCW_RTMI (0x3<<GRTC_CLCW_RTMI_BIT)
+#define GRTC_CLCW_WAIT (1<<GRTC_CLCW_WAIT_BIT)
+#define GRTC_CLCW_LOUT (1<<GRTC_CLCW_LOUT_BIT)
+#define GRTC_CLCW_NBLO (1<<GRTC_CLCW_NBLO_BIT)
+#define GRTC_CLCW_NRFA (1<<GRTC_CLCW_NRFA_BIT)
+#define GRTC_CLCW_VCI (0x3f<<GRTC_CLCW_VCI_BIT)
+#define GRTC_CLCW_CIE (0x3<<GRTC_CLCW_CIE_BIT)
+#define GRTC_CLCW_STAF (0x3<<GRTC_CLCW_STAF_BIT)
+#define GRTC_CLCW_VNUM (0x3<<GRTC_CLCW_VNUM_BIT)
+#define GRTC_CLCW_CWTY (1<<GRTC_CLCW_CWTY_BIT)
+
+/* Physical Interface Register (PIR 0x1c) */
+#define GRTC_PIR_BLO_BIT 0
+#define GRTC_PIR_RFA_BIT 8
+
+#define GRTC_PIR_BLO (0xff<<GRTC_PIR_BLO_BIT)
+#define GRTC_PIR_RFA (0xff<<GRTC_PIR_RFA_BIT)
+
+/* Control Register (COR 0x20) */
+#define GRTC_COR_RE_BIT 0
+#define GRTC_COR_CRST_BIT 9
+
+#define GRTC_COR_RE (1<<GRTC_COR_RE_BIT)
+#define GRTC_COR_CRST (1<<GRTC_COR_CRST_BIT)
+
+/* Status Register (STR 0x24) */
+#define GRTC_STR_CR_BIT 0
+#define GRTC_STR_OV_BIT 4
+#define GRTC_STR_RFF_BIT 7
+#define GRTC_STR_RBF_BIT 10
+
+#define GRTC_STR_CR (1<<GRTC_STR_CR_BIT)
+#define GRTC_STR_OV (1<<GRTC_STR_OV_BIT)
+#define GRTC_STR_RFF (1<<GRTC_STR_RFF_BIT)
+#define GRTC_STR_RBF (1<<GRTC_STR_RBF_BIT)
+
+/* Address Space Register (ASR 0x28) */
+#define GRTC_ASR_RXLEN_BIT 0
+#define GRTC_ASR_BUFST_BIT 10
+
+#define GRTC_ASR_RXLEN (0xff<<GRTC_ASR_RXLEN_BIT)
+#define GRTC_ASR_BUFST (0x3fffff<<GRTC_ASR_BUFST_BIT)
+
+/* Receive Read Pointer Register (RRP 0x2c) */
+#define GRTC_RRP_PTR_BIT 0
+
+#define GRTC_RRP_PTR (0xffffff<<GRTC_RRP_PTR_BIT)
+
+/* Receive Write Pointer Register (RWP 0x30) */
+#define GRTC_RWP_PTR_BIT 0
+
+#define GRTC_RWP_PTR (0xffffff<<GRTC_RWP_PTR_BIT)
+
+/* Pending Interrupt Masked Status Register (PIMSR 0x60) */
+/* Pending Interrupt Masked Register (PIMR 0x64) */
+/* Pending Interrupt Status Register (PISR 0x68) */
+/* Pending Interrupt Register (PIR 0x6c) */
+/* Interrupt Mask Register (IMR 0x70) */
+/* Pending Interrupt Clear Register (PICR 0x74) */
+#define GRTC_INT_RFA_BIT 0
+#define GRTC_INT_BLO_BIT 1
+#define GRTC_INT_FAR_BIT 2
+#define GRTC_INT_CR_BIT 3
+#define GRTC_INT_RBF_BIT 4
+#define GRTC_INT_OV_BIT 5
+#define GRTC_INT_CS_BIT 6
+
+#define GRTC_INT_RFA (1<<GRTC_INT_RFA_BIT)
+#define GRTC_INT_BLO (1<<GRTC_INT_BLO_BIT)
+#define GRTC_INT_FAR (1<<GRTC_INT_FAR_BIT)
+#define GRTC_INT_CR (1<<GRTC_INT_CR_BIT)
+#define GRTC_INT_OV (1<<GRTC_INT_OV_BIT)
+#define GRTC_INT_CS (1<<GRTC_INT_CS_BIT)
+
+#define GRTC_INT_ALL (GRTC_INT_RFA|GRTC_INT_BLO|GRTC_INT_FAR|GRTC_INT_CR|GRTC_INT_OV|GRTC_INT_CS)
+
+/*#define READ_REG(address) (*(volatile unsigned int *)address)*/
+
+/* Driver functions */
+static rtems_device_driver grtc_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver grtc_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver grtc_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver grtc_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver grtc_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver grtc_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+
+#define GRTC_DRIVER_TABLE_ENTRY { grtc_initialize, grtc_open, grtc_close, grtc_read, grtc_write, grtc_ioctl }
+
+static rtems_driver_address_table grtc_driver = GRTC_DRIVER_TABLE_ENTRY;
+
+enum {
+ FRM_STATE_NONE = 0, /* not started */
+ FRM_STATE_HDR = 1, /* Reading Header (Frame length isn't known) */
+ FRM_STATE_ALLOC = 2, /* Allocate Frame to hold data */
+ FRM_STATE_PAYLOAD = 3, /* Reading Payload (Frame length is known) */
+ FRM_STATE_FILLER = 4, /* Check filler */
+ FRM_STATE_DROP = 5 /* error, drop data until end marker */
+};
+
+/* Frame pool, all frames in pool have the same buffer length (frame mode only) */
+struct grtc_frame_pool {
+ unsigned int frame_len; /* Maximal length of frame (payload+hdr+crc..) */
+ unsigned int frame_cnt; /* Current number of frames in pool (in frms) */
+ struct grtc_frame *frms; /* Chain of frames in pool (this is the pool) */
+};
+
+/* Holds the cached data and the cached READ/WRITE pointers.
+ *
+ * IMPORTANT: The READ/WRITE pointers must always reflect the cached data available, the real
+ * hardware increment it's WRITE pointer all the time. We update the hw READ pointer
+ * each time we copy from the DMA area into our "cached" data area.
+ * The software update the cached READ pointer, however this is ignored by the "sync"
+ * routine, since the hw READ pointer has already been updated when coping the data
+ * to the cached area.
+ *
+ * buf: Set to CPU local SRAM copy (cached copy)
+ * buf_remote: Set to remote buffer start (original)
+ */
+struct cached_regs {
+ unsigned int asr;
+ unsigned int rp;
+ unsigned int wp;
+};
+
+#define CACHED_READ_REG(priv, name) ((priv)->cache.name)
+#define CACHED_WRITE_REG(priv, name, val) ((priv)->cache.name = (val))
+
+struct grtc_priv {
+ struct drvmgr_dev *dev; /* Driver manager device */
+ char devName[64]; /* Device Name */
+ struct grtc_regs *regs; /* TC Hardware Register MAP */
+ int irq; /* IRQ number of TC core */
+
+ int major; /* Driver major */
+ int minor; /* Device Minor */
+
+ int open; /* Device has been opened by user */
+ int running; /* TC receiver running */
+ int mode; /* RAW or FRAME mode */
+ int overrun_condition; /* Overrun condition */
+ int blocking; /* Blocking/polling mode */
+ rtems_interval timeout; /* Timeout in blocking mode */
+ int wait_for_nbytes;/* Number of bytes to wait for in blocking mode */
+
+ struct grtc_ioc_config config;
+
+/* RAW MODE ONLY */
+ /* Buffer allocation (user provided or driver allocated using malloc) */
+ void *buf;
+ void *buf_remote;
+ void *_buf;
+ int buf_custom; /* 0=no custom buffer, 1=custom buffer (don't free it...) */
+ unsigned int len;
+ int alloc_part_dma;
+
+/* FRAME MODE ONLY */
+ /* Frame management when user provides buffers. */
+ int pool_cnt; /* Number of Pools */
+ struct grtc_frame_pool *pools; /* Array of pools */
+
+ struct grtc_list ready; /* Ready queue (received frames) */
+
+ /* Frame read data (Frame mode only) */
+ int frame_state;
+ int filler;
+ unsigned char hdr[5] __attribute__((aligned(2)));
+ struct grtc_frame *frm; /* Frame currently beeing copied */
+ int frmlen;
+
+ struct grtc_ioc_stats stats; /* Statistics */
+
+ rtems_id sem_rx;
+
+ struct cached_regs cache;
+ struct drvmgr_rw_arg rw_arg;
+ ambapp_rmap_w32 rw_w32;
+ ambapp_rmap_r32 rw_r32;
+ ambapp_rmap_rmem rw_rmem;
+ int irq_support;
+
+#ifdef DEBUG_ERROR
+ /* Buffer read/write state */
+ unsigned int rp;
+ unsigned int wp;
+
+ /* Debugging */
+ int last_error[128];
+ int last_error_cnt;
+#endif
+};
+
+/* Prototypes */
+static void grtc_hw_reset(struct grtc_priv *priv);
+static void grtc_interrupt(void *arg);
+
+/* Common Global Variables */
+static rtems_id grtc_dev_sem;
+static int grtc_driver_io_registered = 0;
+static rtems_device_major_number grtc_driver_io_major = 0;
+
+/******************* Driver manager interface ***********************/
+
+/* Driver prototypes */
+static int grtc_register_io(rtems_device_major_number *m);
+static int grtc_device_init(struct grtc_priv *pDev);
+
+static int grtc_init2(struct drvmgr_dev *dev);
+static int grtc_init3(struct drvmgr_dev *dev);
+
+#ifdef GRTC_RMAP_INFO_AVAIL
+static int grtc_info(
+ struct drvmgr_dev *dev,
+ void (*print_line)(void *p, char *str),
+ void *p, int, char *argv[]);
+#define GRTC_INFO_FUNC grtc_info
+#else
+#define GRTC_INFO_FUNC NULL
+#endif
+
+static struct drvmgr_drv_ops grtc_ops =
+{
+ .init = {NULL, grtc_init2, grtc_init3, NULL},
+ .remove = NULL,
+ .info = GRTC_INFO_FUNC,
+};
+
+static struct amba_dev_id grtc_ids[] =
+{
+ {VENDOR_GAISLER, GAISLER_GRTC},
+ {0, 0} /* Mark end of table */
+};
+
+static struct amba_drv_info grtc_drv_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_AMBAPP_GAISLER_GRTC_ID, /* Driver ID */
+ "GRTC_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_AMBAPP_RMAP, /* Bus Type */
+ &grtc_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ sizeof(struct grtc_priv),
+ },
+ &grtc_ids[0]
+};
+
+void grtc_rmap_register_drv (void)
+{
+ DBG("Registering GRTC driver\n");
+ drvmgr_drv_register(&grtc_drv_info.general);
+}
+
+static int grtc_init2(struct drvmgr_dev *dev)
+{
+ struct grtc_priv *priv;
+
+ DBG("GRTC[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
+ priv = dev->priv;
+ if ( !priv )
+ return DRVMGR_NOMEM;
+ priv->dev = dev;
+
+ /* Get Read/Write operations for bus */
+ priv->rw_arg.dev = dev;
+ priv->rw_arg.arg = (void *)drvmgr_func_call(dev->parent, AMBAPP_RMAP_RW_ARG, dev, NULL, NULL, NULL);
+ drvmgr_func_get(dev->parent, AMBAPP_RMAP_R32, (void *)&priv->rw_r32);
+ drvmgr_func_get(dev->parent, AMBAPP_RMAP_W32, (void *)&priv->rw_w32);
+ drvmgr_func_get(dev->parent, AMBAPP_RMAP_RMEM, (void *)&priv->rw_rmem);
+
+ /* This core will not find other cores, so we wait for init2() */
+
+ return DRVMGR_OK;
+}
+
+static int grtc_init3(struct drvmgr_dev *dev)
+{
+ struct grtc_priv *priv;
+ char prefix[32];
+ rtems_status_code status;
+
+ priv = dev->priv;
+
+ /* Do initialization */
+
+ if ( grtc_driver_io_registered == 0) {
+ /* Register the I/O driver only once for all cores */
+ if ( grtc_register_io(&grtc_driver_io_major) ) {
+ /* Failed to register I/O driver */
+ dev->priv = NULL;
+ return DRVMGR_FAIL;
+ }
+
+ grtc_driver_io_registered = 1;
+ }
+
+ /* I/O system registered and initialized
+ * Now we take care of device initialization.
+ */
+ if ( grtc_device_init(priv) ) {
+ return DRVMGR_FAIL;
+ }
+
+ /* Get Filesystem name prefix */
+ prefix[0] = '\0';
+ if ( drvmgr_get_dev_prefix(dev, prefix) ) {
+ /* Failed to get prefix, make sure of a unique FS name
+ * by using the driver minor.
+ */
+ sprintf(priv->devName, "/dev/grtc%d", dev->minor_drv);
+ } else {
+ /* Got special prefix, this means we have a bus prefix
+ * And we should use our "bus minor"
+ */
+ sprintf(priv->devName, "/dev/%sgrtc%d", prefix, dev->minor_bus);
+ }
+
+ /* Register Device */
+ status = rtems_io_register_name(priv->devName, grtc_driver_io_major, dev->minor_drv);
+ if (status != RTEMS_SUCCESSFUL) {
+ return DRVMGR_FAIL;
+ }
+
+ return DRVMGR_OK;
+}
+
+/******************* Driver Implementation ***********************/
+
+static int grtc_register_io(rtems_device_major_number *m)
+{
+ rtems_status_code r;
+
+ if ((r = rtems_io_register_driver(0, &grtc_driver, m)) == RTEMS_SUCCESSFUL) {
+ DBG("GRTC driver successfully registered, major: %d\n", *m);
+ } else {
+ switch(r) {
+ case RTEMS_TOO_MANY:
+ printk("GRTC rtems_io_register_driver failed: RTEMS_TOO_MANY\n");
+ return -1;
+ case RTEMS_INVALID_NUMBER:
+ printk("GRTC rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n");
+ return -1;
+ case RTEMS_RESOURCE_IN_USE:
+ printk("GRTC rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n");
+ return -1;
+ default:
+ printk("GRTC rtems_io_register_driver failed\n");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int grtc_device_init(struct grtc_priv *pDev)
+{
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
+ union drvmgr_key_value *value;
+
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)pDev->dev->businfo;
+ if ( ambadev == NULL ) {
+ return -1;
+ }
+ pnpinfo = &ambadev->info;
+ pDev->irq = pnpinfo->irq;
+ pDev->regs = (struct grtc_regs *)pnpinfo->ahb_slv->start[0];
+ pDev->minor = pDev->dev->minor_drv;
+ pDev->open = 0;
+ pDev->running = 0;
+
+ pDev->alloc_part_dma = 0;
+ value = drvmgr_dev_key_get(pDev->dev, "dmaAllocPartition", KEY_TYPE_INT);
+ if ( value )
+ pDev->alloc_part_dma = value->i;
+
+ /* Create Binary RX Semaphore with count = 0 */
+ if ( rtems_semaphore_create(rtems_build_name('G', 'R', 'C', '0' + pDev->minor),
+ 0,
+ RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|\
+ RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &pDev->sem_rx) != RTEMS_SUCCESSFUL ) {
+ return -1;
+ }
+
+ /* Reset Hardware before attaching IRQ handler */
+ grtc_hw_reset(pDev);
+
+ return 0;
+}
+
+static void grtc_hw_reset(struct grtc_priv *priv)
+{
+ /* Reset Core */
+ WRITE_REG(priv, &priv->regs->grst, (GRTC_SEB | GRTC_GRR_SRST));
+}
+
+static void grtc_hw_get_defaults(struct grtc_priv *pDev, struct grtc_ioc_config *config)
+{
+ unsigned int gcr = READ_REG(pDev, &pDev->regs->gctrl);
+
+ config->psr_enable = (gcr & GRTC_GCR_PSR) ? 1:0;
+ config->nrzm_enable = (gcr & GRTC_GCR_NRZM) ? 1:0;
+ config->pss_enable = (gcr & GRTC_GCR_PSS) ? 1:0;
+
+ config->crc_calc = 0;
+}
+
+/* bufsize is given in bytes */
+static int __inline__ grtc_hw_data_avail_upper(unsigned int rrp, unsigned rwp, unsigned int bufsize)
+{
+ if ( rrp == rwp )
+ return 0;
+
+ if ( rwp > rrp ) {
+ return rwp-rrp;
+ }
+
+ return (bufsize-rrp);
+}
+
+/* bufsize is given in bytes */
+static int __inline__ grtc_hw_data_avail_lower(unsigned int rrp, unsigned rwp, unsigned int bufsize)
+{
+ if ( rrp == rwp )
+ return 0;
+
+ if ( rwp > rrp ) {
+ return 0;
+ }
+
+ return rwp;
+}
+
+/* bufsize is given in bytes */
+static int __inline__ grtc_hw_data_avail(unsigned int rrp, unsigned rwp, unsigned int bufsize)
+{
+ if ( rrp == rwp )
+ return 0;
+
+ if ( rwp > rrp ) {
+ return rwp-rrp;
+ }
+
+ return rwp+(bufsize-rrp);
+}
+
+#if NOT_IMPLEMENTED
+/* Reads as much as possible but not more than 'max' bytes from the TC receive buffer.
+ * Number of bytes put into 'buf' is returned.
+ */
+static int grtc_hw_read_try(struct grtc_priv *pDev, char *buf, int max)
+{
+ struct grtc_regs *regs = pDev->regs;
+ unsigned int rp, wp, asr, bufmax, rrp, rwp;
+ unsigned int upper, lower;
+ unsigned int count, cnt, left;
+
+ FUNCDBG();
+
+ if ( max < 1 )
+ return 0;
+
+ rp = READ_REG(&regs->rp);
+ asr = READ_REG(&regs->asr);
+ bufmax = (asr & GRTC_ASR_RXLEN) >> GRTC_ASR_RXLEN_BIT;
+ bufmax = (bufmax+1) << 10; /* Convert from 1kbyte blocks into bytes */
+ wp = READ_REG(&regs->wp);
+
+ /* Relative rp and wp */
+ rrp = rp - (asr & GRTC_ASR_BUFST);
+ rwp = wp - (asr & GRTC_ASR_BUFST);
+
+ lower = grtc_hw_data_avail_lower(rrp,rwp,bufmax);
+ upper = grtc_hw_data_avail_upper(rrp,rwp,bufmax);
+
+ DBG("grtc_hw_read_try: AVAIL: Lower: %d, Upper: %d\n",lower,upper);
+ DBG("grtc_hw_read_try: rp: 0x%x, rrp: 0x%x, wp: 0x%x, rwp: 0x%x, bufmax: %d\n, start: 0x%x\n",
+ rp,rrp,wp,rwp,bufmax,pDev->buffer);
+
+ if ( (upper+lower) == 0 )
+ return 0;
+
+ /* Count bytes will be read */
+ count = (upper+lower) > max ? max : (upper+lower);
+ left = count;
+
+ /* Read from upper part of data buffer */
+ if ( upper > 0 ){
+ if ( left < upper ){
+ cnt = left;
+ }else{
+ cnt = upper; /* Read all upper data available */
+ }
+ DBG("grtc_hw_read_try: COPYING %d from upper\n",cnt);
+ /* Convert from Remote address (RP) into CPU Local address */
+ memcpy(buf, (void *)((rp - (unsigned int)pDev->buf_remote) + (unsigned int)pDev->buf), cnt);
+ buf += cnt;
+ left -= cnt;
+ }
+
+ /* Read from lower part of data buffer */
+ if ( left > 0 ){
+ if ( left < lower ){
+ cnt = left;
+ }else{
+ cnt = lower; /* Read all lower data available */
+ }
+ DBG("grtc_hw_read_try: COPYING %d from lower\n",cnt);
+ memcpy(buf, (void *)pDev->buf, cnt);
+ buf += cnt;
+ left -= cnt;
+ }
+
+ /* Update hardware RP pointer to tell hardware about new space available */
+ if ( (rp+count) >= ((asr&GRTC_ASR_BUFST)+bufmax) ){
+ regs->rp = (rp+count-bufmax);
+ } else {
+ regs->rp = rp+count;
+ }
+
+ return count;
+}
+
+/* Calculates how many bytes are available in the TC DMA buffer area, both in upper
+ * and lower parts of the TC DMA area.
+ */
+static int grtc_data_avail(struct grtc_priv *pDev)
+{
+ unsigned int rp, wp, asr, bufmax, rrp, rwp;
+ struct grtc_regs *regs = pDev->regs;
+#warning NOT CONVERTED
+
+ FUNCDBG();
+
+ rp = READ_REG(&regs->rp);
+ asr = READ_REG(&regs->asr);
+ bufmax = (asr & GRTC_ASR_RXLEN) >> GRTC_ASR_RXLEN_BIT;
+ bufmax = (bufmax+1) << 10; /* Convert from 1kbyte blocks into bytes */
+ wp = READ_REG(&regs->wp);
+
+ /* Relative rp and wp */
+ rrp = rp - (asr & GRTC_ASR_BUFST);
+ rwp = wp - (asr & GRTC_ASR_BUFST);
+
+ return grtc_hw_data_avail(rrp,rwp,bufmax);
+}
+
+static void *grtc_memalign(unsigned int boundary, unsigned int length, void *realbuf)
+{
+ *(int *)realbuf = (int)malloc(length+(~GRTC_ASR_BUFST)+1);
+ DBG("GRTC: Alloced %d (0x%x) bytes, requested: %d\n",length+(~GRTC_ASR_BUFST)+1,length+(~GRTC_ASR_BUFST)+1,length);
+ return (void *)(((*(unsigned int *)realbuf)+(~GRTC_ASR_BUFST)+1) & ~(boundary-1));
+}
+#endif
+
+static int grtc_start(struct grtc_priv *pDev)
+{
+ struct grtc_regs *regs = pDev->regs;
+ unsigned int tmp;
+
+ if ( !pDev->buf ||
+ (pDev->len>(1024*0x100)) || (pDev->len<1024) || ((pDev->len & (1024-1)) != 0)
+ ) {
+ DBG("GRTC: start: buffer not properly allocated(0x%x,0x%x,0x%x,0x%x)\n",pDev->buf,pDev->len,((unsigned int)pDev->buf & ~GRTC_ASR_BUFST),(pDev->len & ~(1024-1)));
+ return RTEMS_NO_MEMORY;
+ }
+
+ memset(pDev->buf,0,pDev->len);
+
+ /* Software init */
+ pDev->overrun_condition = 0;
+#ifdef DEBUG_ERROR
+ pDev->last_error_cnt = 0;
+ memset(&pDev->last_error[0],0,128*sizeof(int));
+#endif
+ memset(&pDev->stats,0,sizeof(struct grtc_ioc_stats));
+
+ /* Reset the receiver */
+ WRITE_REG(pDev, &regs->cor, (GRTC_SEB | GRTC_COR_CRST));
+ if ( READ_REG(pDev, &regs->cor) & GRTC_COR_CRST ){
+ /* Reset Failed */
+ DBG("GRTC: start: Reseting receiver failed\n");
+ return RTEMS_IO_ERROR;
+ }
+
+ /* Set operating modes */
+ tmp = 0;
+ if ( pDev->config.psr_enable )
+ tmp |= GRTC_GCR_PSR;
+ if ( pDev->config.nrzm_enable )
+ tmp |= GRTC_GCR_NRZM;
+ if ( pDev->config.pss_enable )
+ tmp |= GRTC_GCR_PSS;
+ WRITE_REG(pDev, &regs->gctrl, (GRTC_SEB | tmp));
+
+ /* Clear any pending interrupt */
+ tmp = READ_REG(pDev, &regs->pir);
+ WRITE_REG(pDev, &regs->picr, GRTC_INT_ALL);
+
+ /* Unmask only the Overrun interrupt */
+ WRITE_REG(pDev, &regs->imr, GRTC_INT_OV);
+
+ /* Set up DMA registers
+ * 1. Let hardware know about our DMA area (size and location)
+ * 2. Set DMA read/write posistions to zero.
+ */
+ WRITE_REG(pDev, &regs->asr, ((unsigned int)pDev->buf_remote | ((pDev->len>>10)-1)));
+ WRITE_REG(pDev, &regs->rp, (unsigned int)pDev->buf_remote);
+
+ /* Update Cache (ASR and READ/WRITE POINTERS) */
+ MEMGET(pDev, &pDev->cache, &pDev->regs->asr, sizeof(struct cached_regs));
+
+ /* Mark running before enabling the receiver, we could receive
+ * an interrupt directly after enabling the receiver and it would
+ * then interpret the interrupt as spurious (see interrupt handler)
+ */
+ pDev->running = 1;
+
+ /* Enable receiver */
+ WRITE_REG(pDev, &regs->cor, (GRTC_SEB | GRTC_COR_RE));
+
+ DBG("GRTC: STARTED\n");
+
+ return 0;
+}
+
+static void grtc_stop(struct grtc_priv *pDev)
+{
+ struct grtc_regs *regs = pDev->regs;
+ unsigned int tmp;
+
+ /* Disable the receiver */
+ WRITE_REG(pDev, &regs->cor, GRTC_SEB);
+
+ /* disable all interrupts and clear them */
+ WRITE_REG(pDev, &regs->imr, 0);
+ tmp = READ_REG(pDev, &regs->pir);
+ WRITE_REG(pDev, &regs->picr, GRTC_INT_ALL);
+
+ DBG("GRTC: STOPPED\n");
+
+ /* Flush semaphores in case a thread is stuck waiting for CLTUs (RX data) */
+ rtems_semaphore_flush(pDev->sem_rx);
+}
+
+#if NOT_IMPLEMENTED
+/* Wait until 'count' bytes are available in receive buffer, or until
+ * the timeout expires.
+ */
+static int grtc_wait_data(struct grtc_priv *pDev, int count, rtems_interval timeout)
+{
+ int avail;
+ int ret;
+ IRQ_GLOBAL_PREPARE(oldLevel);
+
+ FUNCDBG();
+
+ if ( count < 1 )
+ return 0;
+
+ IRQ_GLOBAL_DISABLE(oldLevel);
+
+ /* Enable interrupts when receiving CLTUs, Also clear old pending CLTUs store
+ * interrupts.
+ */
+ pDev->regs->picr = GRTC_INT_CS;
+ pDev->regs->imr = READ_REG(&pDev->regs->imr) | GRTC_INT_CS;
+
+ avail = grtc_data_avail(pDev);
+ if ( avail < count ) {
+ /* Wait for interrupt. */
+
+ IRQ_GLOBAL_ENABLE(oldLevel);
+
+ if ( timeout == 0 ){
+ timeout = RTEMS_NO_TIMEOUT;
+ }
+ ret = rtems_semaphore_obtain(pDev->sem_rx,RTEMS_WAIT,timeout);
+ /* RTEMS_SUCCESSFUL = interrupt signaled data is available
+ * RTEMS_TIMEOUT = timeout expired, probably not enough data available
+ * RTEMS_UNSATISFIED = driver has been closed or an error (overrun) occured
+ * which should cancel this operation.
+ * RTEMS_OBJECT_WAS_DELETED, RTEMS_INVALID_ID = driver error.
+ */
+ IRQ_GLOBAL_DISABLE(oldLevel);
+ }else{
+ ret = RTEMS_SUCCESSFUL;
+ }
+
+ /* Disable interrupts when receiving CLTUs */
+ pDev->regs->imr = READ_REG(&pDev->regs->imr) & ~GRTC_INT_CS;
+
+ IRQ_GLOBAL_ENABLE(oldLevel);
+
+ return ret;
+}
+#endif
+
+/* Update cached area */
+static int grtc_sync_dma_area(struct grtc_priv *pDev, struct cached_regs *cache)
+{
+ struct cached_regs hw;
+ unsigned int cache_space, cache_data_avail;
+ unsigned int count;
+ unsigned int new_wp;
+ unsigned int cache_bufmax, cache_rrp, cache_rwp, cache_upper, cache_lower;
+
+ unsigned int hw_data_avail;
+ unsigned int hw_bufmax, hw_rrp, hw_rwp, hw_upper, hw_lower;
+
+ int left, cnt;
+
+ /* 1. Calculate how much data that can be copied into our cache */
+ cache_bufmax = (cache->asr & GRTC_ASR_RXLEN) >> GRTC_ASR_RXLEN_BIT;
+ cache_bufmax = (cache_bufmax+1) << 10; /* Convert from 1kbyte blocks into bytes */
+ /* Relative rp and wp */
+ cache_rrp = cache->rp - (cache->asr & GRTC_ASR_BUFST);
+ cache_rwp = cache->wp - (cache->asr & GRTC_ASR_BUFST);
+ cache_upper = grtc_hw_data_avail_upper(cache_rrp, cache_rwp, cache_bufmax);
+ cache_lower = grtc_hw_data_avail_lower(cache_rrp, cache_rwp, cache_bufmax);
+ cache_data_avail = cache_upper + cache_lower;
+ cache_space = pDev->len - cache_data_avail;
+ if ( cache_space < (128+8) ) {
+ /* Never copy less than 128Bytes when so cache is so full */
+ return 0;
+ }
+ cache_space -= 8; /* Never fill cache, to avoid special cases. */
+
+ /* 2. Read ASR and READ/WRITE POINTERS over SpW */
+ MEMGET(pDev, &hw, &pDev->regs->asr, sizeof(struct cached_regs));
+
+ /* 3. Calculate how much data is available in the non-cached DMA data area
+ * on the remote target.
+ */
+ hw_bufmax = (hw.asr & GRTC_ASR_RXLEN) >> GRTC_ASR_RXLEN_BIT;
+ hw_bufmax = (hw_bufmax+1) << 10; /* Convert from 1kbyte blocks into bytes */
+ /* Relative rp and wp */
+ hw_rrp = hw.rp - (hw.asr & GRTC_ASR_BUFST);
+ hw_rwp = hw.wp - (hw.asr & GRTC_ASR_BUFST);
+ hw_upper = grtc_hw_data_avail_upper(hw_rrp, hw_rwp, hw_bufmax);
+ hw_lower = grtc_hw_data_avail_lower(hw_rrp, hw_rwp, hw_bufmax);
+ hw_data_avail = hw_upper + hw_lower;
+
+ /* 4. Decide how much to copy */
+ if ( hw_data_avail > cache_space ) {
+ count = cache_space;
+ } else {
+ count = hw_data_avail;
+ }
+ /* A frame header is always at least 5 bytes + 5 control bytes = 10bytes */
+ if ( count < 10 ) {
+ return 0;
+ }
+ /* Avoid copying less than 128 unless we have nothing to process. Say nothing less than
+ * 128 bytes is ever copied, we may miss a couple of small frames if no further TC frames
+ * are received.
+ */
+ if ( (count < 128) && (cache_data_avail > 10 ) ) {
+ /* Never copy less than 128Bytes, unless we have nothing to process */
+ return 0;
+ }
+ left = count;
+
+ /* 5. Copy from Upper */
+ if ( hw_upper > 0) {
+ if ( left < hw_upper ) {
+ cnt = left;
+ } else {
+ cnt = hw_upper;
+ }
+ MEMGET(pDev, ((char *)pDev->buf + hw_rrp), (void *)((char *)pDev->buf_remote + hw_rrp), cnt);
+ left -= cnt;
+
+ new_wp = cache->wp + cnt;
+ }
+
+ /* 6. Copy from Lower */
+ if ( left > 0 ) {
+ if ( left < hw_lower ){
+ cnt = left;
+ } else {
+ cnt = hw_lower; /* Read all lower data available */
+ }
+ MEMGET(pDev, (void *)pDev->buf, (void *)pDev->buf_remote, cnt);
+ left -= cnt;
+
+ new_wp = (unsigned int)((char *)pDev->buf_remote + cnt);
+ }
+
+ /* 7. Update Hardware registers, READ pointer to tell hardware about new space available */
+ if ( (hw.rp+count) >= ((hw.asr&GRTC_ASR_BUFST)+hw_bufmax) ){
+ WRITE_REG(pDev, &pDev->regs->rp, (hw.rp+count-hw_bufmax));
+ } else {
+ WRITE_REG(pDev, &pDev->regs->rp, (hw.rp+count));
+ }
+
+ /* 8. Update Cached registers, WRITE pointer */
+ cache->wp = new_wp;
+
+ return 0;
+}
+
+static rtems_device_driver grtc_open(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg)
+{
+ struct grtc_priv *pDev;
+ struct drvmgr_dev *dev;
+
+ FUNCDBG();
+
+ if ( drvmgr_get_dev(&grtc_drv_info.general, minor, &dev) ) {
+ DBG("Wrong minor %d\n", minor);
+ return RTEMS_INVALID_NUMBER;
+ }
+ pDev = (struct grtc_priv *)dev->priv;
+
+ /* Wait until we get semaphore */
+ if ( rtems_semaphore_obtain(grtc_dev_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT) != RTEMS_SUCCESSFUL ){
+ return RTEMS_INTERNAL_ERROR;
+ }
+
+ /* Is device in use? */
+ if ( pDev->open ){
+ rtems_semaphore_release(grtc_dev_sem);
+ return RTEMS_RESOURCE_IN_USE;
+ }
+
+ /* Mark device taken */
+ pDev->open = 1;
+
+ rtems_semaphore_release(grtc_dev_sem);
+
+ DBG("grtc_open: OPENED minor %d (pDev: 0x%x)\n",pDev->minor,(unsigned int)pDev);
+
+ /* Set defaults */
+ pDev->buf = NULL;
+ pDev->_buf = NULL;
+ pDev->buf_custom = 0;
+ pDev->buf_remote = 0;
+ pDev->len = 0;
+ pDev->timeout = 0; /* no timeout */
+ pDev->blocking = 0; /* polling mode */
+ pDev->mode = GRTC_MODE_RAW; /* Always default to Raw mode */
+ pDev->ready.head = NULL;
+ pDev->ready.tail = NULL;
+ pDev->ready.cnt = 0;
+
+ pDev->running = 0;
+
+ memset(&pDev->config,0,sizeof(pDev->config));
+
+ memset(&pDev->cache,0,sizeof(pDev->cache));
+
+ /* The core has been reset when we execute here, so it is possible
+ * to read out defualts from core.
+ */
+ grtc_hw_get_defaults(pDev,&pDev->config);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver grtc_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ struct grtc_priv *pDev;
+ struct drvmgr_dev *dev;
+
+ FUNCDBG();
+
+ if ( drvmgr_get_dev(&grtc_drv_info.general, minor, &dev) ) {
+ return RTEMS_INVALID_NUMBER;
+ }
+ pDev = (struct grtc_priv *)dev->priv;
+
+ if ( pDev->running ){
+ grtc_stop(pDev);
+ pDev->running = 0;
+ }
+
+ /* Reset core */
+ grtc_hw_reset(pDev);
+
+ /* Mark not open */
+ pDev->open = 0;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver grtc_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+#if NOT_IMPLEMENTED
+ struct grtc_priv *pDev;
+ struct drvmgr_dev *dev;
+ int count;
+ int left;
+ int timedout;
+ int err;
+ rtems_interval timeout;
+ rtems_libio_rw_args_t *rw_args;
+
+ FUNCDBG();
+
+ if ( drvmgr_get_dev(&grtc_drv_info.general, minor, &dev) ) {
+ return RTEMS_INVALID_NUMBER;
+ }
+ pDev = (struct grtc_priv *)dev->priv;
+
+ if ( !pDev->running && !pDev->overrun_condition ) {
+ return RTEMS_RESOURCE_IN_USE;
+ }
+
+ if ( pDev->mode != GRTC_MODE_RAW ) {
+ return RTEMS_NOT_DEFINED;
+ }
+
+ rw_args = (rtems_libio_rw_args_t *) arg;
+ left = rw_args->count;
+ timedout = 0;
+ timeout = pDev->timeout;
+
+read_from_buffer:
+ /* Read maximally rw_args->count bytes from receive buffer */
+ count = grtc_hw_read_try(pDev,rw_args->buffer,left);
+
+ left -= count;
+
+ DBG("READ %d bytes from DMA, left: %d\n",count,left);
+
+ if ( !timedout && !pDev->overrun_condition && ((count < 1) || ((count < rw_args->count) && (pDev->blocking == GRTC_BLKMODE_COMPLETE))) ){
+ /* didn't read anything (no data available) or we want to wait for all bytes requested.
+ *
+ * Wait for data to arrive only in blocking mode
+ */
+ if ( pDev->blocking ) {
+ if ( (err=grtc_wait_data(pDev,left,timeout)) != RTEMS_SUCCESSFUL ){
+ /* Some kind of error, closed, overrun etc. */
+ if ( err == RTEMS_TIMEOUT ){
+ /* Got a timeout, we try to read as much as possible */
+ timedout = 1;
+ goto read_from_buffer;
+ }
+ return err;
+ }
+ goto read_from_buffer;
+ }
+ /* Non-blocking mode and no data read. */
+ return RTEMS_TIMEOUT;
+ }
+
+ /* Tell caller how much was read. */
+
+ DBG("READ returning %d bytes, left: %d\n",rw_args->count-left,left);
+
+ rw_args->bytes_moved = rw_args->count - left;
+ if ( rw_args->bytes_moved == 0 ){
+ return RTEMS_TIMEOUT;
+ }
+#endif
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver grtc_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ FUNCDBG();
+ return RTEMS_NOT_IMPLEMENTED;
+}
+
+static int grtc_pool_add_frms(struct grtc_frame *frms)
+{
+ struct grtc_frame *frm, *next;
+
+ /* Add frames to pools */
+ frm = frms;
+ while(frm){
+
+ if ( !frm->pool ) {
+ /* */
+ DBG("GRTC: Frame not assigned to a pool\n");
+ return -1;
+ }
+ next = frm->next; /* Remember next frame to process */
+
+ DBG("GRTC: adding frame 0x%x to pool %d (%d)\n",frm,frm->pool->frame_len,frm->pool->frame_cnt);
+
+ /* Insert Frame into pool */
+ frm->next = frm->pool->frms;
+ frm->pool->frms = frm;
+ frm->pool->frame_cnt++;
+
+ frm = next;
+ }
+
+ return 0;
+}
+
+static struct grtc_frame *grtc_pool_get_frm(struct grtc_priv *pDev, int frame_len, int *error)
+{
+ struct grtc_frame *frm;
+ struct grtc_frame_pool *pool;
+ int i;
+
+ /* Loop through all pools until a pool is found
+ * with a matching (or larger) frame length
+ */
+ pool = pDev->pools;
+ for (i=0; i<pDev->pool_cnt; i++,pool++) {
+ if ( pool->frame_len >= frame_len ) {
+ /* Found a good pool ==> get frame */
+ frm = pool->frms;
+ if ( !frm ) {
+ /* not enough frames available for this
+ * frame length, we try next
+ *
+ * If this is a severe error add your handling
+ * code here.
+ */
+#if 0
+ if ( error )
+ *error = 0;
+ return 0;
+#endif
+ continue;
+ }
+
+ /* Got a frame, the frame is taken out of the
+ * pool for usage.
+ */
+ pool->frms = frm->next;
+ pool->frame_cnt--;
+ return frm;
+ }
+ }
+
+ if ( error )
+ *error = 1;
+
+ /* Didn't find any frames */
+ return NULL;
+}
+
+/* Return number of bytes processed, Stops at the first occurance
+ * of the pattern given in 'pattern'
+ */
+static int grtc_scan(unsigned short *src, int max, unsigned char pattern, int *found)
+{
+ unsigned short tmp = 0;
+ unsigned int left = max;
+
+ while ( (left>1) && (((tmp=*src) & 0x00ff) != pattern) ) {
+ src++;
+ left-=2;
+ }
+ if ( (tmp & 0xff) == pattern ) {
+ *found = 1;
+ } else {
+ *found = 0;
+ }
+ return max-left;
+}
+
+static int grtc_copy(unsigned short *src, unsigned char *buf, int cnt)
+{
+ unsigned short tmp;
+ int left = cnt;
+
+ while ( (left>0) && ((((tmp=*src) & 0x00ff) == 0x00) || ((tmp & 0x00ff) == 0x01)) ) {
+ *buf++ = tmp>>8;
+ src++;
+ left--;
+ }
+
+ return cnt-left;
+}
+
+
+static int grtc_hw_find_frm(struct grtc_priv *pDev)
+{
+ unsigned int rp, wp, asr, bufmax, rrp, rwp;
+ unsigned int upper, lower;
+ unsigned int count, cnt;
+ int found;
+
+ FUNCDBG();
+
+ rp = CACHED_READ_REG(pDev, rp);
+ asr = CACHED_READ_REG(pDev, asr);
+ wp = CACHED_READ_REG(pDev, wp);
+
+ /* Quick Check for most common case where Start of frame is at next
+ * data byte.
+ */
+ if ( rp != wp ) {
+ /* At least 1 byte in buffer */
+ if ( ((*(unsigned short *)((rp - (unsigned int)pDev->buf_remote) + (unsigned int)pDev->buf)) & 0x00ff) == 0x01 ) {
+ return 0;
+ }
+ }
+
+ bufmax = (asr & GRTC_ASR_RXLEN) >> GRTC_ASR_RXLEN_BIT;
+ bufmax = (bufmax+1) << 10; /* Convert from 1kbyte blocks into bytes */
+
+ /* Relative rp and wp */
+ rrp = rp - (asr & GRTC_ASR_BUFST);
+ rwp = wp - (asr & GRTC_ASR_BUFST);
+
+ lower = grtc_hw_data_avail_lower(rrp,rwp,bufmax);
+ upper = grtc_hw_data_avail_upper(rrp,rwp,bufmax);
+
+ DBG("grtc_hw_find_frm: AVAIL: Lower: %d, Upper: %d\n",lower,upper);
+ DBG("grtc_hw_find_frm: rp: 0x%x, rrp: 0x%x, wp: 0x%x, rwp: 0x%x, bufmax: %d\n, start: 0x%x\n",
+ rp,rrp,wp,rwp,bufmax,pDev->buf_remote);
+
+ if ( (upper+lower) == 0 )
+ return 1;
+
+ /* Count bytes will be read */
+ count = 0;
+ found = 0;
+
+ /* Read from upper part of data buffer */
+ if ( upper > 0 ){
+ cnt = grtc_scan((unsigned short *)((rp - (unsigned int)pDev->buf_remote) + (unsigned int)pDev->buf), upper, 0x01, &found);
+ count = cnt;
+ if ( found ) {
+ DBG("grtc_hw_find_frm: SCANNED upper %d bytes until found\n",cnt);
+ goto out;
+ }
+
+ DBG("grtc_hw_find_frm: SCANNED all upper %d bytes, not found\n",cnt);
+ }
+
+ /* Read from lower part of data buffer */
+ if ( lower > 0 ){
+ cnt = grtc_scan((unsigned short *)pDev->buf, lower, 0x01, &found);
+ count += cnt;
+
+ if ( found ) {
+ DBG("grtc_hw_find_frm: SCANNED lower %d bytes until found\n",cnt);
+ goto out;
+ }
+
+ DBG("grtc_hw_find_frm: SCANNED all lower %d bytes, not found\n",cnt);
+ }
+
+out:
+ /* Update hardware RP pointer to tell hardware about new space available */
+ if ( count > 0 ) {
+ if ( (rp+count) >= ((asr&GRTC_ASR_BUFST)+bufmax) ){
+ CACHED_WRITE_REG(pDev, rp, (rp+count-bufmax));
+ } else {
+ CACHED_WRITE_REG(pDev, rp, (rp+count));
+ }
+ }
+ if ( found )
+ return 0;
+ return 1;
+
+}
+
+static int grtc_check_ending(unsigned short *src, int max, int end)
+{
+ while ( max > 0 ) {
+ /* Check Filler */
+ if ( *src != 0x5500 ) {
+ /* Filler is wrong */
+ return -1;
+ }
+ src++;
+ max-=2;
+ }
+
+ /* Check ending (at least */
+ if ( end ) {
+ if ( (*src & 0x00ff) != 0x02 ) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int grtc_hw_check_ending(struct grtc_priv *pDev, int max)
+{
+ unsigned int rp, wp, asr, bufmax, rrp, rwp;
+ unsigned int upper, lower;
+ unsigned int count, cnt, left;
+ int tot;
+
+ FUNCDBG();
+
+ if ( max < 1 )
+ return 0;
+ max = max*2;
+ max += 2; /* Check ending also (2 byte extra) */
+
+ rp = CACHED_READ_REG(pDev, rp);
+ asr = CACHED_READ_REG(pDev, asr);
+ bufmax = (asr & GRTC_ASR_RXLEN) >> GRTC_ASR_RXLEN_BIT;
+ bufmax = (bufmax+1) << 10; /* Convert from 1kbyte blocks into bytes */
+ wp = CACHED_READ_REG(pDev, wp);
+
+ /* Relative rp and wp */
+ rrp = rp - (asr & GRTC_ASR_BUFST);
+ rwp = wp - (asr & GRTC_ASR_BUFST);
+
+ lower = grtc_hw_data_avail_lower(rrp,rwp,bufmax);
+ upper = grtc_hw_data_avail_upper(rrp,rwp,bufmax);
+
+ DBG("grtc_hw_check_ending: AVAIL: Lower: %d, Upper: %d\n",lower,upper);
+ DBG("grtc_hw_check_ending: rp: 0x%x, rrp: 0x%x, wp: 0x%x, rwp: 0x%x, bufmax: %d\n, start: 0x%x\n",
+ rp,rrp,wp,rwp,bufmax,pDev->buf_remote);
+
+ if ( (upper+lower) < max )
+ return 0;
+
+ /* Count bytes will be read */
+ count = max;
+ left = count;
+ tot = 0;
+
+ /* Read from upper part of data buffer */
+ if ( upper > 0 ){
+ if ( left <= upper ){
+ cnt = left;
+ if ( grtc_check_ending((unsigned short *)((rp-(unsigned int)pDev->buf_remote)+(unsigned int)pDev->buf), cnt-2, 1) ) {
+ return -1;
+ }
+ }else{
+ cnt = upper; /* Read all upper data available */
+ if ( grtc_check_ending((unsigned short *)((rp-(unsigned int)pDev->buf_remote)+(unsigned int)pDev->buf), cnt, 0) ) {
+ return -1;
+ }
+ }
+ left -= cnt;
+ }
+
+ /* Read from lower part of data buffer */
+ if ( left > 0 ){
+ cnt = left;
+ if ( grtc_check_ending((unsigned short *)pDev->buf, cnt-2, 1) ) {
+ return -1;
+ }
+ left -= cnt;
+ }
+
+ /* Update hardware RP pointer to tell hardware about new space available */
+ if ( (rp+count) >= ((asr&GRTC_ASR_BUFST)+bufmax) ){
+ CACHED_WRITE_REG(pDev, rp, (rp+count-bufmax));
+ } else {
+ CACHED_WRITE_REG(pDev, rp, (rp+count));
+ }
+
+ return 0;
+}
+
+/* Copies Data from DMA area to buf, the control bytes are stripped. For
+ * every data byte, in the DMA area, one control byte is stripped.
+ */
+static int grtc_hw_copy(struct grtc_priv *pDev, unsigned char *buf, int max, int partial)
+{
+ unsigned int rp, wp, asr, bufmax, rrp, rwp;
+ unsigned int upper, lower;
+ unsigned int count, cnt, left;
+ int ret, tot, tmp;
+
+ FUNCDBG();
+
+ if ( max < 1 )
+ return 0;
+
+ rp = CACHED_READ_REG(pDev, rp);
+ asr = CACHED_READ_REG(pDev, asr);
+ bufmax = (asr & GRTC_ASR_RXLEN) >> GRTC_ASR_RXLEN_BIT;
+ bufmax = (bufmax+1) << 10; /* Convert from 1kbyte blocks into bytes */
+ wp = CACHED_READ_REG(pDev, wp);
+
+ /* Relative rp and wp */
+ rrp = rp - (asr & GRTC_ASR_BUFST);
+ rwp = wp - (asr & GRTC_ASR_BUFST);
+
+ lower = grtc_hw_data_avail_lower(rrp,rwp,bufmax) >> 1;
+ upper = grtc_hw_data_avail_upper(rrp,rwp,bufmax) >> 1;
+
+ DBG("grtc_hw_copy: AVAIL: Lower: %d, Upper: %d\n",lower,upper);
+ DBG("grtc_hw_copy: rp: 0x%x, rrp: 0x%x, wp: 0x%x, rwp: 0x%x, bufmax: %d\n, start: 0x%x\n",
+ rp,rrp,wp,rwp,bufmax,pDev->buf_remote);
+
+ if ( (upper+lower) == 0 || (!partial && ((upper+lower)<max) ) )
+ return 0;
+
+ /* Count bytes will be read */
+ count = (upper+lower) > max ? max : (upper+lower);
+ left = count;
+ tot = 0;
+
+ /* Read from upper part of data buffer */
+ if ( upper > 0 ){
+ if ( left < upper ){
+ cnt = left;
+ }else{
+ cnt = upper; /* Read all upper data available */
+ }
+ DBG("grtc_hw_copy: COPYING %d from upper\n",cnt);
+ if ( (tot=grtc_copy((unsigned short *)((rp-(unsigned int)pDev->buf_remote)+(unsigned int)pDev->buf), buf, cnt)) != cnt ) {
+ /* Failed to copy due to an receive error */
+ DBG("grtc_hw_copy(upper): not all in DMA buffer (%d)\n",tot);
+ count = tot;
+ ret = -1;
+ goto out;
+ }
+ buf += cnt;
+ left -= cnt;
+ }
+
+ /* Read from lower part of data buffer */
+ if ( left > 0 ){
+ if ( left < lower ){
+ cnt = left;
+ }else{
+ cnt = lower; /* Read all lower data available */
+ }
+ DBG("grtc_hw_copy: COPYING %d from lower\n",cnt);
+ if ( (tmp=grtc_copy((unsigned short *)pDev->buf, buf, cnt)) != cnt ) {
+ /* Failed to copy due to an receive error */
+ DBG("grtc_hw_copy(lower): not all in DMA buffer (%d)\n",tot);
+ count = tot+tmp;
+ ret = -1;
+ goto out;
+ }
+ buf += cnt;
+ left -= cnt;
+ }
+ ret = count;
+
+out:
+ count = count*2;
+ /* Update hardware RP pointer to tell hardware about new space available */
+ if ( (rp+count) >= ((asr&GRTC_ASR_BUFST)+bufmax) ){
+ CACHED_WRITE_REG(pDev, rp, (rp+count-bufmax));
+ } else {
+ CACHED_WRITE_REG(pDev, rp, (rp+count));
+ }
+
+ return ret;
+}
+
+#ifdef DEBUG_ERROR
+void grtc_log_error(struct grtc_priv *pDev, int err)
+{
+ /* Stop Receiver */
+ *(volatile unsigned int *)&pDev->regs->cor = 0x55000000;
+ *(volatile unsigned int *)&pDev->regs->cor = 0x55000000;
+ pDev->last_error[pDev->last_error_cnt] = err;
+ if ( ++pDev->last_error_cnt > 128 )
+ pDev->last_error_cnt = 0;
+}
+#endif
+
+/* Read one frame from DMA buffer
+ *
+ * Return Values
+ * Zero - nothing more to process
+ * 1 - more to process, no free frames
+ * 2 - more to process, frame received
+ * negative - more to process, frame dropped
+ */
+static int process_dma(struct grtc_priv *pDev)
+{
+ int ret, err;
+ int left, total_len;
+ unsigned char *dst;
+ struct grtc_frame *frm;
+
+ switch( pDev->frame_state ) {
+ case FRM_STATE_NONE:
+ DBG2("FRAME_STATE_NONE\n");
+
+ /* Find Start of next frame by searching for 0x01 */
+ ret = grtc_hw_find_frm(pDev);
+ if ( ret != 0 ) {
+ /* Frame start not found */
+ return 0;
+ }
+
+ /* Start of frame found, Try to copy header */
+ pDev->frm = NULL;
+ pDev->frame_state = FRM_STATE_HDR;
+
+ case FRM_STATE_HDR:
+ DBG2("FRAME_STATE_HDR\n");
+
+ /* Wait for all of header to be in place by setting partial to 0 */
+ ret = grtc_hw_copy(pDev,pDev->hdr,5,0);
+ if ( ret < 0 ) {
+ /* Error copying header, restart scanning for new frame */
+ DEBUG_ERR_LOG(pDev,1);
+ pDev->stats.err++;
+ pDev->stats.err_hdr++;
+ DBG("FRAME_STATE_HDR: copying failed %d\n",ret);
+ pDev->frame_state = FRM_STATE_NONE;
+ return -1;
+ } else if ( ret != 5 ) {
+ DBG("FRAME_STATE_HDR: no header (%d)\n",ret);
+ /* Not all bytes available, come back later */
+ return 0;
+ }
+
+ /* The complete header has been copied, parse it */
+ pDev->frmlen = ((*(unsigned short *)&pDev->hdr[2]) & 0x3ff)+1;
+ if ( pDev->frmlen < 5 ) {
+ /* Error: frame length is not correct */
+ pDev->stats.err++;
+ pDev->stats.err_hdr++;
+ DBG("FRAME_STATE_HDR: frame length error: %d\n", pDev->frmlen);
+ pDev->frame_state = FRM_STATE_NONE;
+ return -1;
+ }
+ pDev->frame_state = FRM_STATE_ALLOC;
+
+ case FRM_STATE_ALLOC:
+ DBG2("FRAME_STATE_ALLOC\n");
+ /* Header has been read, allocate a frame to put payload and header into */
+
+ /* Allocate Frame matching Frame length */
+ err = 0;
+ frm = grtc_pool_get_frm(pDev,pDev->frmlen,&err);
+ if ( !frm ) {
+ /* Couldn't find frame */
+ DEBUG_ERR_LOG(pDev,2);
+ pDev->stats.dropped++;
+ DBG2("No free frames\n");
+ if ( err == 0 ){
+ /* Frame length exist in pool configuration, but no
+ * frames are available for that frame length.
+ */
+ DEBUG_ERR_LOG(pDev,3);
+ pDev->stats.dropped_no_buf++;
+ return 1;
+ } else {
+ /* Frame length of incoming frame is larger than the
+ * frame length in any of the configured frame pools.
+ *
+ * This may be because of an corrupt header. We simply
+ * scan for the end of frame marker in the DMA buffer
+ * so we can drop the frame.
+ */
+ DEBUG_ERR_LOG(pDev,4);
+ pDev->stats.dropped_too_long++;
+ pDev->frame_state = FRM_STATE_NONE;
+ return -2;
+ }
+ }
+ frm->len = 5; /* Only header currenlty in frame */
+
+ /* Copy Frame Header into frame structure */
+ *((unsigned char *)&frm->hdr + 0) = pDev->hdr[0];
+ *((unsigned char *)&frm->hdr + 1) = pDev->hdr[1];
+ *((unsigned char *)&frm->hdr + 2) = pDev->hdr[2];
+ *((unsigned char *)&frm->hdr + 3) = pDev->hdr[3];
+ *((unsigned char *)&frm->hdr + 4) = pDev->hdr[4];
+
+ /* Calc Total and Filler byte count in frame */
+ total_len = pDev->frmlen / 7;
+ total_len = total_len * 7;
+ if ( pDev->frmlen != total_len )
+ total_len += 7;
+
+ pDev->filler = total_len - pDev->frmlen;
+
+ pDev->frame_state = FRM_STATE_PAYLOAD;
+ pDev->frm = frm;
+
+ case FRM_STATE_PAYLOAD:
+ DBG2("FRAME_STATE_PAYLOAD\n");
+ /* Parts of payload and the complete header has been read */
+ frm = pDev->frm;
+
+ dst = (unsigned char *)&frm->data[frm->len-5];
+ left = pDev->frmlen-frm->len;
+
+ ret = grtc_hw_copy(pDev,dst,left,1);
+ if ( ret < 0 ) {
+ DEBUG_ERR_LOG(pDev,5);
+ /* Error copying header, restart scanning for new frame */
+ pDev->frame_state = FRM_STATE_NONE;
+ frm->next = NULL;
+ grtc_pool_add_frms(frm);
+ pDev->frm = NULL;
+ pDev->stats.err++;
+ pDev->stats.err_payload++;
+ return -1;
+ } else if ( ret != left ) {
+ /* Not all bytes available, come back later */
+ frm->len += ret;
+ return 0;
+ }
+ frm->len += ret;
+ pDev->frame_state = FRM_STATE_FILLER;
+
+ case FRM_STATE_FILLER:
+ DBG2("FRAME_STATE_FILLER\n");
+ /* check filler data */
+ frm = pDev->frm;
+
+ ret = grtc_hw_check_ending(pDev,pDev->filler);
+ if ( ret != 0 ) {
+ /* Error in frame, drop frame */
+ DEBUG_ERR_LOG(pDev,6);
+ pDev->frame_state = FRM_STATE_NONE;
+ frm->next = NULL;
+ grtc_pool_add_frms(frm);
+ pDev->frm = NULL;
+ pDev->stats.err++;
+ pDev->stats.err_ending++;
+ return -1;
+ }
+
+ /* A complete frame received, put it into received frame queue */
+ if ( pDev->ready.head ) {
+ /* Queue not empty */
+ pDev->ready.tail->next = frm;
+ } else {
+ /* Queue empty */
+ pDev->ready.head = frm;
+ }
+ pDev->ready.tail = frm;
+ frm->next = NULL;
+ pDev->ready.cnt++;
+ pDev->stats.frames_recv++;
+
+ pDev->frame_state = FRM_STATE_NONE;
+ frm->next = NULL;
+ return 2;
+
+#if 0
+ case FRM_STATE_DROP:
+ DBG2("FRAME_STATE_DROP\n");
+ break;
+#endif
+
+ default:
+ printk("GRTC: internal error\n");
+ pDev->frame_state = FRM_STATE_NONE;
+ break;
+ }
+
+ return 0;
+}
+
+static rtems_device_driver grtc_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ struct grtc_priv *pDev;
+ struct drvmgr_dev *dev;
+ rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *)arg;
+ unsigned int *data = ioarg->buffer;
+ int status,frm_len,i,ret;
+ struct grtc_ioc_buf_params *buf_arg;
+ struct grtc_ioc_config *cfg;
+ struct grtc_ioc_hw_status *hwregs;
+ struct grtc_ioc_pools_setup *pocfg;
+ struct grtc_ioc_assign_frm_pool *poassign;
+ struct grtc_frame *frm, *frms;
+ struct grtc_frame_pool *pool;
+ struct grtc_list *frmlist;
+ struct grtc_ioc_stats *stats;
+ unsigned int tmpdata[8];
+
+#if NOT_IMPLEMENTED
+ IRQ_GLOBAL_PREPARE(oldLevel);
+#endif
+
+ FUNCDBG();
+
+ if ( drvmgr_get_dev(&grtc_drv_info.general, minor, &dev) ) {
+ return RTEMS_INVALID_NUMBER;
+ }
+ pDev = (struct grtc_priv *)dev->priv;
+
+ if (!ioarg)
+ return RTEMS_INVALID_NAME;
+
+ ioarg->ioctl_return = 0;
+ switch(ioarg->command) {
+ case GRTC_IOC_START:
+ if ( pDev->running ) {
+ return RTEMS_RESOURCE_IN_USE; /* EBUSY */
+ }
+ if ( (status=grtc_start(pDev)) != RTEMS_SUCCESSFUL ){
+ return status;
+ }
+ /* Register ISR & Unmask interrupt */
+ if (drvmgr_interrupt_register(pDev->dev, 0, "grtc_rmap", grtc_interrupt, pDev) != DRVMGR_OK)
+ pDev->irq_support = 0;
+ else
+ pDev->irq_support = 1;
+
+ /* Read and write are now open... */
+ break;
+
+ case GRTC_IOC_STOP:
+ if ( !pDev->running ) {
+ return RTEMS_RESOURCE_IN_USE;
+ }
+ if ( pDev->irq_support )
+ drvmgr_interrupt_unregister(pDev->dev, 0, grtc_interrupt, pDev);
+ grtc_stop(pDev);
+ pDev->running = 0;
+ break;
+
+ case GRTC_IOC_ISSTARTED:
+ if ( !pDev->running ) {
+ return RTEMS_RESOURCE_IN_USE;
+ }
+ break;
+
+ case GRTC_IOC_SET_BLOCKING_MODE:
+ if ( (unsigned int)data > GRTC_BLKMODE_COMPLETE ) {
+ return RTEMS_INVALID_NAME;
+ }
+ DBG("GRTC: Set blocking mode: %d\n",(unsigned int)data);
+ pDev->blocking = (unsigned int)data;
+ break;
+
+ case GRTC_IOC_SET_TIMEOUT:
+ DBG("GRTC: Timeout: %d\n",(unsigned int)data);
+ pDev->timeout = (rtems_interval)data;
+ break;
+
+ case GRTC_IOC_SET_BUF_PARAM:
+ if ( pDev->running ) {
+ return RTEMS_RESOURCE_IN_USE; /* EBUSY */
+ }
+
+ buf_arg = (struct grtc_ioc_buf_params *)data;
+ if ( !buf_arg ) {
+ return RTEMS_INVALID_NAME;
+ }
+
+ DBG("GRTC: IOC_SET_BUF_PARAM: Len: 0x%x, Custom Buffer: 0x%x\n",buf_arg->length,buf_arg->custom_buffer);
+
+ /* Check alignment need, skip bit 0 since that bit only indicates remote address or not */
+ if ( (unsigned int)buf_arg->custom_buffer & (~GRTC_BUF_MASK) & (~0x1) ) {
+ return RTEMS_INVALID_NAME;
+ }
+
+ if ( buf_arg->length > 0x100 ){
+ DBG("GRTC: Too big buffer requested\n");
+ return RTEMS_INVALID_NAME;
+ }
+
+ /* If current buffer allocated by driver we must free it */
+ if ( pDev->buf ) {
+ free(pDev->buf);
+ if ( !pDev->buf_custom )
+ ; /* Return buf_remote to AMBAPP RMAP bus */
+ pDev->_buf = NULL;
+ }
+ pDev->buf = NULL;
+ pDev->buf_custom = 0;
+ pDev->len = buf_arg->length*1024;
+
+ if ( pDev->len > 0 ) {
+ pDev->buf = malloc(pDev->len);
+
+ if ( buf_arg->custom_buffer ) {
+ /* No translation from CPU to RMAP target
+ * possible since not mapped in memory space.
+ */
+ if (((unsigned int)buf_arg->custom_buffer & 0x1) == 0)
+ return RTEMS_INVALID_NAME;
+ pDev->buf_remote = (unsigned int)buf_arg->custom_buffer & ~0x1;
+ pDev->buf_custom = 1;
+ } else if ( pDev->buf ) {
+ pDev->buf_remote = (void *)ambapp_rmap_partition_memalign(pDev->dev, pDev->alloc_part_dma, (~GRTC_ASR_BUFST + 1), pDev->len);
+ }
+
+ if ( !pDev->buf || !pDev->buf_remote ) {
+ if ( pDev->buf )
+ free(pDev->buf);
+ pDev->len = 0;
+ pDev->_buf = NULL;
+ pDev->buf_remote = 0;
+ DBG("GRTC: Failed to allocate memory\n");
+ return RTEMS_NO_MEMORY;
+ }
+ }
+ break;
+
+ case GRTC_IOC_GET_BUF_PARAM:
+ if ( pDev->running ) {
+ return RTEMS_RESOURCE_IN_USE; /* EBUSY */
+ }
+
+ buf_arg = (struct grtc_ioc_buf_params *)data;
+ if ( !buf_arg ) {
+ return RTEMS_INVALID_NAME;
+ }
+
+ buf_arg->length = pDev->len >> 10; /* Length in 1kByte blocks */
+ if ( pDev->buf_custom )
+ buf_arg->custom_buffer =(void *)pDev->buf;
+ else
+ buf_arg->custom_buffer = 0; /* Don't reveal internal driver buffer */
+ break;
+
+ case GRTC_IOC_SET_CONFIG:
+ cfg = (struct grtc_ioc_config *)data;
+ if ( !cfg ) {
+ return RTEMS_INVALID_NAME;
+ }
+
+ if ( pDev->running ) {
+ return RTEMS_RESOURCE_IN_USE;
+ }
+
+ pDev->config = *cfg;
+ break;
+
+ case GRTC_IOC_GET_CONFIG:
+ cfg = (struct grtc_ioc_config *)data;
+ if ( !cfg ) {
+ return RTEMS_INVALID_NAME;
+ }
+
+ *cfg = pDev->config;
+ break;
+
+ case GRTC_IOC_GET_HW_STATUS:
+ hwregs = (struct grtc_ioc_hw_status *)data;
+ if ( !hwregs ) {
+ return RTEMS_INVALID_NAME;
+ }
+#if NOT_IMPLEMENTED
+ /* We disable interrupt in order to get a snapshot of the registers */
+ IRQ_GLOBAL_DISABLE(oldLevel);
+ hwregs->sir = READ_REG(&pDev->regs->sir);
+ hwregs->far = READ_REG(&pDev->regs->far);
+ hwregs->clcw1 = READ_REG(&pDev->regs->clcw1);
+ hwregs->clcw2 = READ_REG(&pDev->regs->clcw2);
+ hwregs->phir = READ_REG(&pDev->regs->phir);
+ hwregs->str = READ_REG(&pDev->regs->str);
+ IRQ_GLOBAL_ENABLE(oldLevel);
+#endif
+ /* Read over SpaceWire */
+ MEMGET(pDev, &tmpdata[0], &pDev->regs->sir, 7*sizeof(unsigned int));
+ hwregs->sir = tmpdata[0];
+ hwregs->far = tmpdata[1];
+ hwregs->clcw1 = tmpdata[2];
+ hwregs->clcw2 = tmpdata[3];
+ hwregs->phir = tmpdata[4];
+ hwregs->str = tmpdata[6]; /* 5=cor */
+ break;
+
+ case GRTC_IOC_GET_STATS:
+ stats = (struct grtc_ioc_stats *)data;
+ if ( !stats ) {
+ return RTEMS_INVALID_NAME;
+ }
+ memcpy(stats,&pDev->stats,sizeof(struct grtc_ioc_stats));
+ break;
+
+ case GRTC_IOC_CLR_STATS:
+ memset(&pDev->stats,0,sizeof(struct grtc_ioc_stats));
+ break;
+
+ case GRTC_IOC_SET_MODE:
+ if ( pDev->running ) {
+ return RTEMS_RESOURCE_IN_USE;
+ }
+ if ( (int)data == GRTC_MODE_FRAME ) {
+ pDev->mode = GRTC_MODE_FRAME;
+ } else if ( (int)data == GRTC_MODE_RAW ) {
+ pDev->mode = GRTC_MODE_RAW;
+ } else {
+ return RTEMS_INVALID_NAME;
+ }
+ break;
+
+ case GRTC_IOC_POOLS_SETUP:
+ if ( pDev->running ) {
+ return RTEMS_RESOURCE_IN_USE;
+ }
+ pocfg = (struct grtc_ioc_pools_setup *)data;
+ if ( (pDev->mode != GRTC_MODE_FRAME) || !pocfg ) {
+ return RTEMS_INVALID_NAME;
+ }
+
+ /* Check that list is sorted */
+ frm_len = 0;
+ for(i=0;i<pocfg->pool_cnt;i++){
+ if ( pocfg->pool_frame_len[i] <= frm_len ) {
+ return RTEMS_INVALID_NAME;
+ }
+ frm_len = pocfg->pool_frame_len[i];
+ }
+
+ /* Ok, we trust user. The pool descriptions are allocated
+ * but not frames, that the user must do self.
+ */
+ if ( pDev->pools ) {
+ free(pDev->pools);
+ }
+ pDev->pools = malloc(pocfg->pool_cnt * sizeof(struct grtc_frame_pool));
+ if ( !pDev->pools ) {
+ pDev->pool_cnt = 0;
+ return RTEMS_NO_MEMORY;
+ }
+ pDev->pool_cnt = pocfg->pool_cnt;
+ for (i=0;i<pocfg->pool_cnt;i++) {
+ pDev->pools[i].frame_len = pocfg->pool_frame_len[i];
+ pDev->pools[i].frame_cnt = 0;
+ pDev->pools[i].frms = NULL;
+ }
+ break;
+
+ case GRTC_IOC_ASSIGN_FRM_POOL:
+ if ( pDev->running ) {
+ return RTEMS_RESOURCE_IN_USE;
+ }
+
+ if ( (pDev->mode != GRTC_MODE_FRAME) ) {
+ return RTEMS_INVALID_NAME;
+ }
+
+ poassign = (struct grtc_ioc_assign_frm_pool *)data;
+ if ( !poassign ) {
+ return RTEMS_INVALID_NAME;
+ }
+
+ /* Find pool to assign the frames to */
+ pool = NULL;
+ for(i=0; i<pDev->pool_cnt; i++) {
+ if ( pDev->pools[i].frame_len == poassign->frame_len ) {
+ pool = &pDev->pools[i];
+ break;
+ }
+ }
+ if ( !pool ) {
+ /* No Pool matching frame length */
+ return RTEMS_INVALID_NAME;
+ }
+
+ /* Assign frames to pool */
+ frm = poassign->frames;
+ while(frm){
+ frm->pool = pool; /* Assign Frame to pool */
+ frm = frm->next;
+ }
+ break;
+
+ case GRTC_IOC_ADD_BUFF:
+ frms = (struct grtc_frame *)data;
+
+ if ( (pDev->mode != GRTC_MODE_FRAME) ) {
+ return RTEMS_NOT_DEFINED;
+ }
+ if ( !frms ) {
+ return RTEMS_INVALID_NAME;
+ }
+
+ /* Add frames to respicative pools */
+ if ( grtc_pool_add_frms(frms) ) {
+ return RTEMS_INVALID_NAME;
+ }
+ break;
+
+ /* Try to read as much data as possible from DMA area and
+ * put it into free frames.
+ *
+ * If receiver is in stopped mode, let user only read previously
+ * received frames.
+ */
+ case GRTC_IOC_RECV:
+
+ if ( (pDev->mode != GRTC_MODE_FRAME) ) {
+ return RTEMS_NOT_DEFINED;
+ }
+
+ /* Update cache by copying from remote DMA area over SpW */
+ grtc_sync_dma_area(pDev, &pDev->cache);
+
+ while ( pDev->running && ((ret=process_dma(pDev) == 2) || (ret == -1)) ) {
+ /* Frame received or dropped, process next frame */
+ }
+
+ /* Take frames out from ready queue and put them to user */
+ frmlist = (struct grtc_list *)data;
+ if ( !frmlist ) {
+ return RTEMS_INVALID_NAME;
+ }
+
+ frmlist->head = pDev->ready.head;
+ frmlist->tail = pDev->ready.tail;
+ frmlist->cnt = pDev->ready.cnt;
+
+ /* Empty list */
+ pDev->ready.head = NULL;
+ pDev->ready.tail = NULL;
+ pDev->ready.cnt = 0;
+ break;
+
+ case GRTC_IOC_GET_CLCW_ADR:
+ if ( !data ) {
+ return RTEMS_INVALID_NAME;
+ }
+ *data = 0;
+ return RTEMS_NOT_IMPLEMENTED;
+/* This not implemented because Register is no directly mapped
+ *data = (unsigned int)&pDev->regs->clcw1;
+ break;
+*/
+
+ default:
+ return RTEMS_NOT_DEFINED;
+ }
+ return RTEMS_SUCCESSFUL;
+}
+
+static void grtc_interrupt(void *arg)
+{
+ struct grtc_priv *pDev = arg;
+ struct grtc_regs *regs = pDev->regs;
+ unsigned int status;
+
+ /* Clear interrupt by reading it */
+ status = READ_REG(pDev, &regs->pisr);
+
+ /* Spurious Interrupt? */
+ if ( !pDev->running )
+ return;
+
+ if ( status & GRTC_INT_OV ){
+
+ /* Stop core (Disable receiver, interrupts), set overrun condition,
+ * Flush semaphore if thread waiting for data in grtc_wait_data().
+ */
+ pDev->overrun_condition = 1;
+
+ grtc_stop(pDev);
+
+ /* No need to handle the reset of interrupts, we are still */
+ goto out;
+ }
+
+ if ( status & GRTC_INT_CS ){
+#warning NOT IMPLMEENTED
+#if NOT_IMPLEMENTED
+ if ( (pDev->blocking==GRTC_BLKMODE_COMPLETE) && pDev->timeout ){
+ /* Signal to thread only if enough data is available */
+ if ( pDev->wait_for_nbytes > grtc_data_avail(pDev) ){
+ /* Not enough data available */
+ goto procceed_processing_interrupts;
+ }
+
+ /* Enough data is available which means that we should wake
+ * up thread sleeping.
+ */
+ }
+
+ /* Disable further CLTUs Stored interrupts, no point until thread waiting for them
+ * say it want to wait for more.
+ */
+ regs->imr = READ_REG(&regs->imr) & ~GRTC_INT_CS;
+#endif
+ /* Signal Semaphore to wake waiting thread in read() */
+ rtems_semaphore_release(pDev->sem_rx);
+ }
+
+procceed_processing_interrupts:
+
+ if ( status & GRTC_INT_CR ){
+
+ }
+
+ if ( status & GRTC_INT_FAR ){
+
+ }
+
+ if ( status & GRTC_INT_BLO ){
+
+ }
+
+ if ( status & GRTC_INT_RFA ){
+
+ }
+out:
+ if ( status )
+ WRITE_REG(pDev, &regs->picr, status);
+}
+
+static rtems_device_driver grtc_initialize(
+ rtems_device_major_number major,
+ rtems_device_minor_number unused,
+ void *arg
+ )
+{
+ /* Device Semaphore created with count = 1 */
+ if ( rtems_semaphore_create(rtems_build_name('G', 'R', 'T', 'C'),
+ 1,
+ RTEMS_FIFO|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &grtc_dev_sem) != RTEMS_SUCCESSFUL ) {
+ return RTEMS_INTERNAL_ERROR;
+ }
+
+ return RTEMS_SUCCESSFUL;
+}
+
+#ifdef GRTC_RMAP_INFO_AVAIL
+static int grtc_info(
+ struct drvmgr_dev *dev,
+ void (*print_line)(void *p, char *str),
+ void *p, int argc, char *argv[])
+{
+ struct grtc_priv *priv = dev->priv;
+ char buf[64];
+ struct grtc_ioc_hw_status hwsts, *hwregs;
+ unsigned int tmpdata[8];
+
+ if (priv == NULL || argc != 0)
+ return -DRVMGR_EINVAL;
+
+ sprintf(buf, "REGS: 0x%08x", (unsigned int)priv->regs);
+ print_line(p, buf);
+ sprintf(buf, "Device Name: %s", priv->devName);
+ print_line(p, buf);
+ sprintf(buf, "IRQ: %ssupported", priv->irq_support ? "" : "not ");
+ print_line(p, buf);
+ sprintf(buf, "STARTED: %s", priv->running ? "YES" : "NO");
+ print_line(p, buf);
+ sprintf(buf, "MODE: %s", priv->mode ? "FRAME" : "RAW");
+ print_line(p, buf);
+ sprintf(buf, "BLOCKING: %s", priv->blocking ? "BLOCKING" : "POLL");
+ print_line(p, buf);
+ sprintf(buf, "DMA SIZE: %dBytes", priv->len);
+ print_line(p, buf);
+ sprintf(buf, "DMA AREA: %p - %p",
+ priv->buf_remote, priv->buf_remote+(priv->len-1));
+ print_line(p, buf);
+ sprintf(buf, "NO. Pools: %d", priv->pool_cnt);
+ print_line(p, buf);
+
+ /* Statistics */
+ sprintf(buf, "Received OK: %llu frames", priv->stats.frames_recv);
+ print_line(p, buf);
+ sprintf(buf, "Errors: %u frames", priv->stats.err);
+ print_line(p, buf);
+ sprintf(buf, "Header err: %u frames", priv->stats.err_hdr);
+ print_line(p, buf);
+ sprintf(buf, "Dropped: %u frames", priv->stats.dropped);
+ print_line(p, buf);
+ sprintf(buf, "Ready: %u frames", priv->ready.cnt);
+ print_line(p, buf);
+
+ /* Read over SpaceWire */
+ MEMGET(priv, &tmpdata[0], &priv->regs->sir, 7*sizeof(unsigned int));
+ hwregs = &hwsts;
+ hwregs->sir = tmpdata[0];
+ hwregs->far = tmpdata[1];
+ hwregs->clcw1 = tmpdata[2];
+ hwregs->clcw2 = tmpdata[3];
+ hwregs->phir = tmpdata[4];
+ hwregs->str = tmpdata[6]; /* 5=cor */
+
+ print_line(p, "HW REGS:");
+ sprintf(buf, " SIR: 0x%08x", hwregs->sir);
+ print_line(p, buf);
+ sprintf(buf, " FAR: 0x%08x", hwregs->far);
+ print_line(p, buf);
+ sprintf(buf, " CLCW1: 0x%08x", hwregs->clcw1);
+ print_line(p, buf);
+ sprintf(buf, " CLCW2: 0x%08x", hwregs->clcw2);
+ print_line(p, buf);
+ sprintf(buf, " PHIR: 0x%08x", hwregs->phir);
+ print_line(p, buf);
+ sprintf(buf, " STR: 0x%08x", hwregs->str);
+ print_line(p, buf);
+
+ return DRVMGR_OK;
+}
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/tmtc/grtm.c b/c/src/lib/libbsp/sparc/shared/tmtc/grtm.c
new file mode 100644
index 0000000000..8c5bc95b93
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/tmtc/grtm.c
@@ -0,0 +1,1599 @@
+/* GRTM CCSDS Telemetry Encoder driver
+ *
+ * --------------------------------------------------------------------------
+ * -- This file is a part of GAISLER RESEARCH source code.
+ * -- Copyright (C) 2009, Aeroflex Gaisler AB - all rights reserved.
+ * --
+ * -- ANY USE OR REDISTRIBUTION IN PART OR IN WHOLE MUST BE HANDLED IN
+ * -- ACCORDANCE WITH THE GAISLER LICENSE AGREEMENT AND MUST BE APPROVED
+ * -- IN ADVANCE IN WRITING.
+ * --
+ * -- BY DEFAULT, DISTRIBUTION OR DISCLOSURE IS NOT PERMITTED.
+ * --------------------------------------------------------------------------
+ *
+ * 2008-12-11, Daniel Hellstrom <daniel@gaisler.com>
+ * Converted to support driver manager
+ *
+ * 2007-04-17, Daniel Hellstrom <daniel@gaisler.com>
+ * New driver in sparc shared directory.
+ *
+ */
+
+#include <bsp.h>
+#include <rtems/libio.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+#include <malloc.h>
+#include <rtems/bspIo.h>
+
+#include <drvmgr/drvmgr.h>
+#include <ambapp.h>
+#include <drvmgr/ambapp_bus.h>
+#include <grtm.h>
+
+#ifndef IRQ_GLOBAL_PREPARE
+ #define IRQ_GLOBAL_PREPARE(level) rtems_interrupt_level level
+#endif
+
+#ifndef IRQ_GLOBAL_DISABLE
+ #define IRQ_GLOBAL_DISABLE(level) rtems_interrupt_disable(level)
+#endif
+
+#ifndef IRQ_GLOBAL_ENABLE
+ #define IRQ_GLOBAL_ENABLE(level) rtems_interrupt_enable(level)
+#endif
+
+/*
+#define DEBUG
+#define DEBUGFUNCS
+*/
+
+#include <debug_defs.h>
+
+/* GRTM register map */
+struct grtm_regs {
+ volatile unsigned int dma_ctrl; /* DMA Control Register (0x00) */
+ volatile unsigned int dma_status; /* DMA Status Register (0x04) */
+ volatile unsigned int dma_len; /* DMA Length Register (0x08) */
+ volatile unsigned int dma_bd; /* DMA Descriptor Pointer Register (0x0c) */
+
+ volatile unsigned int dma_cfg; /* DMA Configuration Register (0x10) */
+ volatile unsigned int revision; /* GRTM Revision Register (0x14) */
+
+ int unused0[(0x80-0x18)/4];
+
+ volatile unsigned int ctrl; /* TM Control Register (0x80) */
+ volatile unsigned int status; /* TM Status Register (0x84) */
+ volatile unsigned int cfg; /* TM Configuration Register (0x88) */
+ volatile unsigned int size; /* TM Size Register (0x8c) */
+
+ volatile unsigned int phy; /* TM Physical Layer Register (0x90) */
+ volatile unsigned int code; /* TM Coding Sub-Layer Register (0x94) */
+ volatile unsigned int asmr; /* TM Attached Synchronization Marker Register (0x98) */
+
+ int unused1;
+
+ volatile unsigned int all_frm; /* TM All Frames Generation Register (0xa0) */
+ volatile unsigned int mst_frm; /* TM Master Channel Frame Generation Register (0xa4) */
+ volatile unsigned int idle_frm; /* TM Idle Frame Generation Register (0xa8) */
+
+ int unused2[(0xc0-0xac)/4];
+
+ volatile unsigned int fsh[4]; /* TM FSH/Insert Zone Registers (0xc0..0xcc) */
+
+ volatile unsigned int ocf; /* TM Operational Control Field Register (0xd0) */
+};
+
+/* DMA Control Register (0x00) */
+#define GRTM_DMA_CTRL_EN_BIT 0
+#define GRTM_DMA_CTRL_IE_BIT 1
+#define GRTM_DMA_CTRL_TXRST_BIT 2
+#define GRTM_DMA_CTRL_RST_BIT 3
+#define GRTM_DMA_CTRL_TFIE_BIT 4
+
+#define GRTM_DMA_CTRL_EN (1<<GRTM_DMA_CTRL_EN_BIT)
+#define GRTM_DMA_CTRL_IE (1<<GRTM_DMA_CTRL_IE_BIT)
+#define GRTM_DMA_CTRL_TXRST (1<<GRTM_DMA_CTRL_TXRST_BIT)
+#define GRTM_DMA_CTRL_RST (1<<GRTM_DMA_CTRL_RST_BIT)
+#define GRTM_DMA_CTRL_TFIE (1<<GRTM_DMA_CTRL_TFIE_BIT)
+
+/* DMA Status Register (0x04) */
+#define GRTM_DMA_STS_TE_BIT 0
+#define GRTM_DMA_STS_TI_BIT 1
+#define GRTM_DMA_STS_TA_BIT 2
+#define GRTM_DMA_STS_TFF_BIT 3
+#define GRTM_DMA_STS_TFS_BIT 4
+
+#define GRTM_DMA_STS_TE (1<<GRTM_DMA_STS_TE_BIT)
+#define GRTM_DMA_STS_TI (1<<GRTM_DMA_STS_TI_BIT)
+#define GRTM_DMA_STS_TA (1<<GRTM_DMA_STS_TA_BIT)
+#define GRTM_DMA_STS_TFF (1<<GRTM_DMA_STS_TFF_BIT)
+#define GRTM_DMA_STS_TFS (1<<GRTM_DMA_STS_TFS_BIT)
+#define GRTM_DMA_STS_ALL 0x1f
+
+/* DMA Length Register (0x08) */
+#define GRTM_DMA_LEN_LEN_BIT 0
+#define GRTM_DMA_LEN_LIM_BIT 16
+
+#define GRTM_DMA_LEN_LEN (0x7ff<<GRTM_DMA_LEN_LEN_BIT)
+#define GRTM_DMA_LEN_LIM (0x3ff<<GRTM_DMA_LEN_LIM_BIT)
+
+/* DMA Descriptor Pointer Register (0x0c) */
+#define GRTM_DMA_BD_INDEX_BIT 0
+#define GRTM_DMA_BD_BASE_BIT 10
+
+#define GRTM_DMA_BD_INDEX (0x3ff<<GRTM_DMA_BD_INDEX_BIT)
+#define GRTM_DMA_BD_BASE (0xfffffc<<GRTM_DMA_BD_BASE_BIT)
+
+/* DMA Configuration Register (0x10) */
+#define GRTM_DMA_CFG_BLKSZ_BIT 0
+#define GRTM_DMA_CFG_FIFOSZ_BIT 16
+
+#define GRTM_DMA_CFG_BLKSZ (0xffff<<GRTM_DMA_CFG_BLKSZ_BIT)
+#define GRTM_DMA_CFG_FIFOSZ (0xffff<<GRTM_DMA_CFG_FIFOSZ_BIT)
+
+/* TM Control Register (0x80) */
+#define GRTM_CTRL_EN_BIT 0
+
+#define GRTM_CTRL_EN (1<<GRTM_CTRL_EN_BIT)
+
+/* TM Status Register (0x84) - Unused */
+
+/* TM Configuration Register (0x88) */
+#define GRTM_CFG_SC_BIT 0
+#define GRTM_CFG_SP_BIT 1
+#define GRTM_CFG_CE_BIT 2
+#define GRTM_CFG_NRZ_BIT 3
+#define GRTM_CFG_PSR_BIT 4
+#define GRTM_CFG_TE_BIT 5
+#define GRTM_CFG_RSDEP_BIT 6
+#define GRTM_CFG_RS_BIT 9
+#define GRTM_CFG_AASM_BIT 11
+#define GRTM_CFG_FECF_BIT 12
+#define GRTM_CFG_OCF_BIT 13
+#define GRTM_CFG_EVC_BIT 14
+#define GRTM_CFG_IDLE_BIT 15
+#define GRTM_CFG_FSH_BIT 16
+#define GRTM_CFG_MCG_BIT 17
+#define GRTM_CFG_IZ_BIT 18
+#define GRTM_CFG_FHEC_BIT 19
+#define GRTM_CFG_AOS_BIT 20
+#define GRTM_CFG_CIF_BIT 21
+#define GRTM_CFG_OCFB_BIT 22
+
+#define GRTM_CFG_SC (1<<GRTM_CFG_SC_BIT)
+#define GRTM_CFG_SP (1<<GRTM_CFG_SP_BIT)
+#define GRTM_CFG_CE (1<<GRTM_CFG_CE_BIT)
+#define GRTM_CFG_NRZ (1<<GRTM_CFG_NRZ_BIT)
+#define GRTM_CFG_PSR (1<<GRTM_CFG_PSR_BIT)
+#define GRTM_CFG_TE (1<<GRTM_CFG_TE_BIT)
+#define GRTM_CFG_RSDEP (0x7<<GRTM_CFG_RSDEP_BIT)
+#define GRTM_CFG_RS (0x3<<GRTM_CFG_RS_BIT)
+#define GRTM_CFG_AASM (1<<GRTM_CFG_AASM_BIT)
+#define GRTM_CFG_FECF (1<<GRTM_CFG_FECF_BIT)
+#define GRTM_CFG_OCF (1<<GRTM_CFG_OCF_BIT)
+#define GRTM_CFG_EVC (1<<GRTM_CFG_EVC_BIT)
+#define GRTM_CFG_IDLE (1<<GRTM_CFG_IDLE_BIT)
+#define GRTM_CFG_FSH (1<<GRTM_CFG_FSH_BIT)
+#define GRTM_CFG_MCG (1<<GRTM_CFG_MCG_BIT)
+#define GRTM_CFG_IZ (1<<GRTM_CFG_IZ_BIT)
+#define GRTM_CFG_FHEC (1<<GRTM_CFG_FHEC_BIT)
+#define GRTM_CFG_AOS (1<<GRTM_CFG_AOS_BIT)
+#define GRTM_CFG_CIF (1<<GRTM_CFG_CIF_BIT)
+#define GRTM_CFG_OCFB (1<<GRTM_CFG_OCFB_BIT)
+
+/* TM Size Register (0x8c) */
+#define GRTM_SIZE_BLKSZ_BIT 0
+#define GRTM_SIZE_FIFOSZ_BIT 8
+#define GRTM_SIZE_LEN_BIT 20
+
+#define GRTM_SIZE_BLKSZ (0xff<<GRTM_SIZE_BLKSZ_BIT)
+#define GRTM_SIZE_FIFOSZ (0xfff<<GRTM_SIZE_FIFOSZ_BIT)
+#define GRTM_SIZE_LEN (0xfff<<GRTM_SIZE_LEN_BIT)
+
+/* TM Physical Layer Register (0x90) */
+#define GRTM_PHY_SUB_BIT 0
+#define GRTM_PHY_SCF_BIT 15
+#define GRTM_PHY_SYM_BIT 16
+#define GRTM_PHY_SF_BIT 31
+
+#define GRTM_PHY_SUB (0x7fff<<GRTM_PHY_SUB_BIT)
+#define GRTM_PHY_SCF (1<<GRTM_PHY_SCF_BIT)
+#define GRTM_PHY_SYM (0x7fff<<GRTM_PHY_SYM_BIT)
+#define GRTM_PHY_SF (1<<GRTM_PHY_SF_BIT)
+
+/* TM Coding Sub-Layer Register (0x94) */
+#define GRTM_CODE_SC_BIT 0
+#define GRTM_CODE_SP_BIT 1
+#define GRTM_CODE_CERATE_BIT 2
+#define GRTM_CODE_CE_BIT 5
+#define GRTM_CODE_NRZ_BIT 6
+#define GRTM_CODE_PSR_BIT 7
+#define GRTM_CODE_RS8_BIT 11
+#define GRTM_CODE_RSDEP_BIT 12
+#define GRTM_CODE_RS_BIT 15
+#define GRTM_CODE_AASM_BIT 16
+#define GRTM_CODE_CSEL_BIT 17
+
+#define GRTM_CODE_SC (1<<GRTM_CODE_SC_BIT)
+#define GRTM_CODE_SP (1<<GRTM_CODE_SP_BIT)
+#define GRTM_CODE_CERATE (0x7<<GRTM_CODE_CERATE_BIT)
+#define GRTM_CODE_CE (1<<GRTM_CODE_CE_BIT)
+#define GRTM_CODE_NRZ (1<<GRTM_CODE_NRZ_BIT)
+#define GRTM_CODE_PSR (1<<GRTM_CODE_PSR_BIT)
+#define GRTM_CODE_RS8 (1<<GRTM_CODE_RS8_BIT)
+#define GRTM_CODE_RSDEP (0x7<<GRTM_CODE_RSDEP_BIT)
+#define GRTM_CODE_RS (1<<GRTM_CODE_RS_BIT)
+#define GRTM_CODE_AASM (1<<GRTM_CODE_AASM_BIT)
+#define GRTM_CODE_CSEL (0x3<<GRTM_CODE_CSEL_BIT)
+
+/* TM Attached Synchronization Marker Register (0x98) */
+#define GRTM_ASM_BIT 0
+
+#define GRTM_ASM 0xffffffff
+
+/* TM All Frames Generation Register (0xa0) */
+#define GRTM_ALL_LEN_BIT 0
+#define GRTM_ALL_VER_BIT 12
+#define GRTM_ALL_FHEC_BIT 14
+#define GRTM_ALL_FECF_BIT 15
+#define GRTM_ALL_IZ_BIT 16
+#define GRTM_ALL_IZLEN_BIT 17
+
+#define GRTM_ALL_LEN (0x7ff<<GRTM_ALL_LEN_BIT)
+#define GRTM_ALL_VER (0x3<<GRTM_ALL_VER_BIT)
+#define GRTM_ALL_FHEC (1<<GRTM_ALL_FHEC_BIT)
+#define GRTM_ALL_FECF (1<<GRTM_ALL_FECF_BIT)
+#define GRTM_ALL_IZ (1<<GRTM_ALL_IZ_BIT)
+#define GRTM_ALL_IZLEN (0x1f<<GRTM_ALL_IZLEN_BIT)
+
+/* TM Master Channel Frame Generation Register (0xa4) */
+#define GRTM_MST_OW_BIT 0
+#define GRTM_MST_OCF_BIT 1
+#define GRTM_MST_FSH_BIT 2
+#define GRTM_MST_MC_BIT 3
+#define GRTM_MST_MCCNTR_BIT 24
+
+#define GRTM_MST_OW (1<<GRTM_MST_OW_BIT)
+#define GRTM_MST_OCF (1<<GRTM_MST_OCF_BIT)
+#define GRTM_MST_FSH (1<<GRTM_MST_FSH_BIT)
+#define GRTM_MST_MC (0xff<<GRTM_MST_MC_BIT)
+
+/* TM Idle Frame Generation Register (0xa8) */
+#define GRTM_IDLE_SCID_BIT 0
+#define GRTM_IDLE_VCID_BIT 10
+#define GRTM_IDLE_MC_BIT 16
+#define GRTM_IDLE_VCC_BIT 17
+#define GRTM_IDLE_FSH_BIT 18
+#define GRTM_IDLE_EVC_BIT 19
+#define GRTM_IDLE_OCF_BIT 20
+#define GRTM_IDLE_IDLE_BIT 21
+#define GRTM_IDLE_MCCNTR_BIT 24
+
+#define GRTM_IDLE_SCID (0x3ff<<GRTM_IDLE_SCID_BIT)
+#define GRTM_IDLE_VCID (0x3f<<GRTM_IDLE_VCID_BIT)
+#define GRTM_IDLE_MC (1<<GRTM_IDLE_MC_BIT)
+#define GRTM_IDLE_VCC (1<<GRTM_IDLE_VCC_BIT)
+#define GRTM_IDLE_FSH (1<<GRTM_IDLE_FSH_BIT)
+#define GRTM_IDLE_EVC (1<<GRTM_IDLE_EVC_BIT)
+#define GRTM_IDLE_OCF (1<<GRTM_IDLE_OCF_BIT)
+#define GRTM_IDLE_IDLE (1<<GRTM_IDLE_IDLE_BIT)
+#define GRTM_IDLE_MCCNTR (0xff<<GRTM_IDLE_MCCNTR_BIT)
+
+/* TM FSH/Insert Zone Registers (0xc0..0xcc) */
+#define GRTM_FSH_DATA_BIT 0
+
+#define GRTM_FSH_DATA 0xffffffff
+
+
+/* TM Operational Control Field Register (0xd0) */
+#define GRTM_OCF_CLCW_BIT 0
+
+#define GRTM_OCF_CLCW 0xffffffff
+
+
+/* GRTM Revision 0 */
+#define GRTM_REV0_DMA_CTRL_TXRDY_BIT 5
+#define GRTM_REV0_DMA_CTRL_TXRDY (1<<GRTM_REV0_DMA_CTRL_TXRDY_BIT)
+
+/* GRTM Revision 1 */
+#define GRTM_REV1_DMA_STS_TXRDY_BIT 6
+#define GRTM_REV1_DMA_STS_TXSTAT_BIT 7
+#define GRTM_REV1_DMA_STS_TXRDY (1<<GRTM_REV1_DMA_STS_TXRDY_BIT)
+#define GRTM_REV1_DMA_STS_TXSTAT (1<<GRTM_REV1_DMA_STS_TXSTAT_BIT)
+
+#define GRTM_REV1_REV_SREV_BIT 0
+#define GRTM_REV1_REV_MREV_BIT 8
+#define GRTM_REV1_REV_TIRQ_BIT 16
+#define GRTM_REV1_REV_SREV (0xff<<GRTM_REV1_REV_SREV_BIT)
+#define GRTM_REV1_REV_MREV (0xff<<GRTM_REV1_REV_MREV_BIT)
+#define GRTM_REV1_REV_TIRQ (1<<GRTM_REV1_REV_TIRQ_BIT)
+
+
+/* GRTM transmit descriptor (0x400 Alignment need) */
+struct grtm_bd {
+ volatile unsigned int ctrl;
+ unsigned int address;
+};
+
+#define GRTM_BD_EN_BIT 0
+#define GRTM_BD_WR_BIT 1
+#define GRTM_BD_IE_BIT 2
+#define GRTM_BD_FECFB_BIT 3
+#define GRTM_BD_IZB_BIT 4
+#define GRTM_BD_FHECB_BIT 5
+#define GRTM_BD_OCFB_BIT 6
+#define GRTM_BD_FSHB_BIT 7
+#define GRTM_BD_MCB_BIT 8
+#define GRTM_BD_VCE_BIT 9
+#define GRTM_BD_TS_BIT 14
+#define GRTM_BD_UE_BIT 15
+
+#define GRTM_BD_EN (1<<GRTM_BD_EN_BIT)
+#define GRTM_BD_WR (1<<GRTM_BD_WR_BIT)
+#define GRTM_BD_IE (1<<GRTM_BD_IE_BIT)
+#define GRTM_BD_FECFB (1<<GRTM_BD_FECFB_BIT)
+#define GRTM_BD_IZB (1<<GRTM_BD_IZB_BIT)
+#define GRTM_BD_FHECB (1<<GRTM_BD_FHECB_BIT)
+#define GRTM_BD_OCFB (1<<GRTM_BD_OCFB_BIT)
+#define GRTM_BD_FSHB (1<<GRTM_BD_FSHB_BIT)
+#define GRTM_BD_MCB (1<<GRTM_BD_MCB_BIT)
+#define GRTM_BD_VCE (1<<GRTM_BD_VCE_BIT)
+#define GRTM_BD_TS (1<<GRTM_BD_TS_BIT)
+#define GRTM_BD_UE (1<<GRTM_BD_UE_BIT)
+
+/* Load register */
+
+#define READ_REG(address) (*(volatile unsigned int *)address)
+
+/* Driver functions */
+static rtems_device_driver grtm_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver grtm_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver grtm_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver grtm_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver grtm_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver grtm_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+
+#define GRTM_DRIVER_TABLE_ENTRY { grtm_initialize, grtm_open, grtm_close, grtm_read, grtm_write, grtm_ioctl }
+
+static rtems_driver_address_table grtm_driver = GRTM_DRIVER_TABLE_ENTRY;
+
+/* Structure that connects BD with SoftWare Frame */
+struct grtm_ring {
+ struct grtm_ring *next;
+ struct grtm_bd *bd;
+ struct grtm_frame *frm;
+};
+
+struct grtm_priv {
+ struct drvmgr_dev *dev; /* Driver manager device */
+ char devName[32]; /* Device Name */
+ struct grtm_regs *regs;
+ int irq;
+ int minor;
+ int subrev; /* GRTM Revision */
+
+ int open;
+ int running;
+
+ struct grtm_bd *bds;
+ void *_bds;
+
+ /* Interrupt generation */
+ int enable_cnt_curr;/* Down counter, when 0 the interrupt bit is set for next descriptor */
+ volatile int handling_transmission; /* Tells ISR if user are active changing descriptors/queues */
+
+ struct grtm_ring *_ring; /* Root of ring */
+ struct grtm_ring *ring; /* Next ring to use for new frames to be transmitted */
+ struct grtm_ring *ring_end; /* Oldest activated ring used */
+
+ /* Collections of frames Ready to sent/ Scheduled for transmission/Sent
+ * frames waiting for the user to reclaim
+ */
+ struct grtm_list ready; /* Frames Waiting for free BDs */
+ struct grtm_list scheduled; /* Frames in BDs beeing transmitted */
+ struct grtm_list sent; /* Sent Frames waiting for user to reclaim and reuse */
+
+ /* Number of frames in the lists */
+ int ready_cnt; /* Number of ready frames */
+ int scheduled_cnt; /* Number of scheduled frames */
+ int sent_cnt; /* Number of sent frames */
+
+ struct grtm_ioc_hw hw_avail; /* Hardware support available */
+ struct grtm_ioc_config config;
+ struct grtm_ioc_stats stats;
+
+ rtems_id sem_tx;
+};
+
+/* Prototypes */
+static void *grtm_memalign(unsigned int boundary, unsigned int length, void *realbuf);
+static void grtm_hw_reset(struct grtm_priv *pDev);
+static void grtm_interrupt(void *arg);
+
+/* Common Global Variables */
+static rtems_id grtm_dev_sem;
+static int grtm_driver_io_registered = 0;
+static rtems_device_major_number grtm_driver_io_major = 0;
+
+/******************* Driver manager interface ***********************/
+
+/* Driver prototypes */
+static int grtm_register_io(rtems_device_major_number *m);
+static int grtm_device_init(struct grtm_priv *pDev);
+
+static int grtm_init2(struct drvmgr_dev *dev);
+static int grtm_init3(struct drvmgr_dev *dev);
+
+static struct drvmgr_drv_ops grtm_ops =
+{
+ {NULL, grtm_init2, grtm_init3, NULL},
+ NULL,
+ NULL
+};
+
+static struct amba_dev_id grtm_ids[] =
+{
+ {VENDOR_GAISLER, GAISLER_GRTM},
+ {0, 0} /* Mark end of table */
+};
+
+static struct amba_drv_info grtm_drv_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_AMBAPP_GAISLER_GRTM_ID, /* Driver ID */
+ "GRTM_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */
+ &grtm_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ 0,
+ },
+ &grtm_ids[0]
+};
+
+void grtm_register_drv (void)
+{
+ DBG("Registering GRTM driver\n");
+ drvmgr_drv_register(&grtm_drv_info.general);
+}
+
+static int grtm_init2(struct drvmgr_dev *dev)
+{
+ struct grtm_priv *priv;
+
+ DBG("GRTM[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
+ priv = dev->priv = malloc(sizeof(struct grtm_priv));
+ if ( !priv )
+ return DRVMGR_NOMEM;
+ memset(priv, 0, sizeof(*priv));
+ priv->dev = dev;
+
+ /* This core will not find other cores, so we wait for init2() */
+
+ return DRVMGR_OK;
+}
+
+static int grtm_init3(struct drvmgr_dev *dev)
+{
+ struct grtm_priv *priv;
+ char prefix[32];
+ rtems_status_code status;
+
+ priv = dev->priv;
+
+ /* Do initialization */
+
+ if ( grtm_driver_io_registered == 0) {
+ /* Register the I/O driver only once for all cores */
+ if ( grtm_register_io(&grtm_driver_io_major) ) {
+ /* Failed to register I/O driver */
+ dev->priv = NULL;
+ return DRVMGR_FAIL;
+ }
+
+ grtm_driver_io_registered = 1;
+ }
+
+ /* I/O system registered and initialized
+ * Now we take care of device initialization.
+ */
+ if ( grtm_device_init(priv) ) {
+ return DRVMGR_FAIL;
+ }
+
+ /* Get Filesystem name prefix */
+ prefix[0] = '\0';
+ if ( drvmgr_get_dev_prefix(dev, prefix) ) {
+ /* Failed to get prefix, make sure of a unique FS name
+ * by using the driver minor.
+ */
+ sprintf(priv->devName, "/dev/grtm%d", dev->minor_drv);
+ } else {
+ /* Got special prefix, this means we have a bus prefix
+ * And we should use our "bus minor"
+ */
+ sprintf(priv->devName, "/dev/%sgrtm%d", prefix, dev->minor_bus);
+ }
+
+ /* Register Device */
+ status = rtems_io_register_name(priv->devName, grtm_driver_io_major, dev->minor_drv);
+ if (status != RTEMS_SUCCESSFUL) {
+ return DRVMGR_FAIL;
+ }
+
+ return DRVMGR_OK;
+}
+
+/******************* Driver Implementation ***********************/
+
+static int grtm_register_io(rtems_device_major_number *m)
+{
+ rtems_status_code r;
+
+ if ((r = rtems_io_register_driver(0, &grtm_driver, m)) == RTEMS_SUCCESSFUL) {
+ DBG("GRTM driver successfully registered, major: %d\n", *m);
+ } else {
+ switch(r) {
+ case RTEMS_TOO_MANY:
+ printk("GRTM rtems_io_register_driver failed: RTEMS_TOO_MANY\n");
+ return -1;
+ case RTEMS_INVALID_NUMBER:
+ printk("GRTM rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n");
+ return -1;
+ case RTEMS_RESOURCE_IN_USE:
+ printk("GRTM rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n");
+ return -1;
+ default:
+ printk("GRTM rtems_io_register_driver failed\n");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int grtm_device_init(struct grtm_priv *pDev)
+{
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
+ union drvmgr_key_value *value;
+
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)pDev->dev->businfo;
+ if ( ambadev == NULL ) {
+ return -1;
+ }
+ pnpinfo = &ambadev->info;
+ pDev->irq = pnpinfo->irq;
+ pDev->regs = (struct grtm_regs *)pnpinfo->apb_slv->start;
+ pDev->minor = pDev->dev->minor_drv;
+ pDev->open = 0;
+ pDev->running = 0;
+
+ /* Create Binary RX Semaphore with count = 0 */
+ if ( rtems_semaphore_create(rtems_build_name('G', 'R', 'M', '0' + pDev->minor),
+ 0,
+ RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|\
+ RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &pDev->sem_tx) != RTEMS_SUCCESSFUL ) {
+ return -1;
+ }
+
+ /* Allocate Memory for Buffer Descriptor Table, or let user provide a custom
+ * address.
+ */
+ value = drvmgr_dev_key_get(pDev->dev, "bdTabAdr", KEY_TYPE_POINTER);
+ if ( value ) {
+ pDev->bds = (struct grtm_bd *)value->ptr;
+ pDev->_bds = (void *)value->ptr;
+ } else {
+ pDev->bds = (struct grtm_bd *)grtm_memalign(0x400, 0x400, &pDev->_bds);
+ }
+ if ( !pDev->bds ) {
+ DBG("GRTM: Failed to allocate descriptor table\n");
+ return -1;
+ }
+ memset(pDev->bds, 0, 0x400);
+
+ pDev->_ring = malloc(sizeof(struct grtm_ring) * 128);
+ if ( !pDev->_ring ) {
+ return -1;
+ }
+
+ /* Reset Hardware before attaching IRQ handler */
+ grtm_hw_reset(pDev);
+
+ /* Read SUB revision number, ignore */
+ pDev->subrev = (READ_REG(&pDev->regs->revision) & GRTM_REV1_REV_SREV)
+ >> GRTM_REV1_REV_SREV_BIT;
+
+ return 0;
+}
+
+
+static inline void grtm_list_clr(struct grtm_list *list)
+{
+ list->head = NULL;
+ list->tail = NULL;
+}
+
+static void grtm_hw_reset(struct grtm_priv *pDev)
+{
+ /* Reset Core */
+ pDev->regs->dma_ctrl = GRTM_DMA_CTRL_RST;
+}
+
+static void grtm_hw_get_implementation(struct grtm_priv *pDev, struct grtm_ioc_hw *hwcfg)
+{
+ unsigned int cfg = READ_REG(&pDev->regs->cfg);
+
+ hwcfg->cs = (cfg & GRTM_CFG_SC) ? 1:0;
+ hwcfg->sp = (cfg & GRTM_CFG_SP) ? 1:0;
+ hwcfg->ce = (cfg & GRTM_CFG_CE) ? 1:0;
+ hwcfg->nrz = (cfg & GRTM_CFG_NRZ) ? 1:0;
+ hwcfg->psr = (cfg & GRTM_CFG_PSR) ? 1:0;
+ hwcfg->te = (cfg & GRTM_CFG_TE) ? 1:0;
+ hwcfg->rsdep = (cfg & GRTM_CFG_RSDEP)>>GRTM_CFG_RSDEP_BIT;
+ hwcfg->rs = (cfg & GRTM_CFG_RS)>>GRTM_CFG_RS_BIT;
+ hwcfg->aasm = (cfg & GRTM_CFG_AASM) ? 1:0;
+ hwcfg->fecf = (cfg & GRTM_CFG_FECF) ? 1:0;
+ hwcfg->ocf = (cfg & GRTM_CFG_OCF) ? 1:0;
+ hwcfg->evc = (cfg & GRTM_CFG_EVC) ? 1:0;
+ hwcfg->idle = (cfg & GRTM_CFG_IDLE) ? 1:0;
+ hwcfg->fsh = (cfg & GRTM_CFG_FSH) ? 1:0;
+ hwcfg->mcg = (cfg & GRTM_CFG_MCG) ? 1:0;
+ hwcfg->iz = (cfg & GRTM_CFG_IZ) ? 1:0;
+ hwcfg->fhec = (cfg & GRTM_CFG_FHEC) ? 1:0;
+ hwcfg->aos = (cfg & GRTM_CFG_AOS) ? 1:0;
+ hwcfg->cif = (cfg & GRTM_CFG_CIF) ? 1:0;
+ hwcfg->ocfb = (cfg & GRTM_CFG_OCFB) ? 1:0;
+
+ cfg = READ_REG(&pDev->regs->dma_cfg);
+ hwcfg->blk_size = (cfg & GRTM_DMA_CFG_BLKSZ) >> GRTM_DMA_CFG_BLKSZ_BIT;
+ hwcfg->fifo_size= (cfg & GRTM_DMA_CFG_FIFOSZ) >> GRTM_DMA_CFG_FIFOSZ_BIT;
+}
+
+#warning Extra: Implement proper default calculation from hardware configuration
+static void grtm_hw_get_default_modes(struct grtm_ioc_config *cfg, struct grtm_ioc_hw *hwcfg)
+{
+ cfg->mode = GRTM_MODE_TM;
+ cfg->frame_length = 223;
+ cfg->limit = 0; /* Make driver auto configure it on START, user may override with non-zero value */
+ cfg->as_marker = 0x1ACFFC1D;
+
+ /* Physical */
+ cfg->phy_subrate = 1;
+ cfg->phy_symbolrate = 1;
+ cfg->phy_opts = 0;
+
+ /* Coding Layer */
+ cfg->code_rsdep = 1;
+ cfg->code_ce_rate = 0;
+ cfg->code_csel = 0;
+ cfg->code_opts = 0;
+
+ /* All Frame Generation */
+ cfg->all_izlen = 0;
+ cfg->all_opts = GRTM_IOC_ALL_FECF;
+
+ /* Master Channel Frame Generation */
+ if ( hwcfg->mcg ) {
+ cfg->mf_opts = GRTM_IOC_MF_MC;
+ } else {
+ cfg->mf_opts = 0;
+ }
+
+ /* Idle Frame Generation */
+ cfg->idle_scid = 0;
+ cfg->idle_vcid = 0;
+ if ( hwcfg->idle ) {
+ cfg->idle_opts = GRTM_IOC_IDLE_EN;
+ } else {
+ cfg->idle_opts = 0;
+ }
+
+ /* Interrupt options */
+ cfg->blocking = 0; /* non-blocking mode is default */
+ cfg->enable_cnt = 16; /* generate interrupt every 16 descriptor */
+ cfg->isr_desc_proc = 1; /* Let interrupt handler do descriptor processing */
+ cfg->timeout = RTEMS_NO_TIMEOUT;
+
+}
+
+static void *grtm_memalign(unsigned int boundary, unsigned int length, void *realbuf)
+{
+ *(int *)realbuf = (int)malloc(length+boundary);
+ DBG("GRTM: Alloced %d (0x%x) bytes, requested: %d\n",length+boundary,length+boundary,length);
+ return (void *)(((*(unsigned int *)realbuf)+boundary) & ~(boundary-1));
+}
+
+static int grtm_hw_set_config(struct grtm_priv *pDev, struct grtm_ioc_config *cfg, struct grtm_ioc_hw *hwcfg)
+{
+ struct grtm_regs *regs = pDev->regs;
+ unsigned int tmp;
+ unsigned int limit;
+
+ if ( cfg->limit == 0 ) {
+ /* Calculate Limit */
+ if ( cfg->frame_length > hwcfg->blk_size ) {
+ limit = hwcfg->blk_size*2;
+ } else {
+ limit = cfg->frame_length;
+ }
+ } else {
+ /* Use user configured limit */
+ limit = cfg->limit;
+ }
+
+ /* Frame Length and Limit */
+ regs->dma_len = (((limit-1) << GRTM_DMA_LEN_LIM_BIT) & GRTM_DMA_LEN_LIM)|
+ (((cfg->frame_length-1) << GRTM_DMA_LEN_LEN_BIT) & GRTM_DMA_LEN_LEN);
+
+ /* Physical layer options */
+ tmp = (cfg->phy_opts & (GRTM_IOC_PHY_SCF|GRTM_IOC_PHY_SF)) |
+ (((cfg->phy_symbolrate-1)<<GRTM_PHY_SYM_BIT) & GRTM_PHY_SYM) | (((cfg->phy_subrate-1)<<GRTM_PHY_SUB_BIT) & GRTM_PHY_SUB);
+ regs->phy = tmp;
+
+ /* Coding Sub-layer Options */
+ tmp = (cfg->code_opts & GRTM_IOC_CODE_ALL) | ((cfg->code_csel<<GRTM_CODE_CSEL_BIT) & GRTM_CODE_CSEL) |
+ (((cfg->code_rsdep-1)<<GRTM_CODE_RSDEP_BIT) & GRTM_CODE_RSDEP) | ((cfg->code_ce_rate<<GRTM_CODE_CERATE_BIT) & GRTM_CODE_CERATE);
+ regs->code = tmp;
+
+ /* Attached synchronization marker register */
+ regs->asmr = cfg->as_marker;
+
+ /* All Frames Generation */
+ tmp = ((cfg->all_opts & GRTM_IOC_ALL_ALL)<<14) |
+ ((cfg->all_izlen<<GRTM_ALL_IZLEN_BIT) & GRTM_ALL_IZLEN) |
+ ((cfg->mode<<GRTM_ALL_VER_BIT) & GRTM_ALL_VER);
+ regs->all_frm = tmp;
+
+ /* Master Frame Generation */
+ regs->mst_frm = cfg->mf_opts & GRTM_IOC_MF_ALL;
+
+ /* Idle frame Generation */
+ tmp = ((cfg->idle_opts & GRTM_IOC_IDLE_ALL) << 16) |
+ ((cfg->idle_vcid << GRTM_IDLE_VCID_BIT) & GRTM_IDLE_VCID) |
+ ((cfg->idle_scid << GRTM_IDLE_SCID_BIT) & GRTM_IDLE_SCID);
+ regs->idle_frm = tmp;
+
+ return 0;
+}
+
+static int grtm_start(struct grtm_priv *pDev)
+{
+ struct grtm_regs *regs = pDev->regs;
+ int i;
+ struct grtm_ioc_config *cfg = &pDev->config;
+ unsigned int txrdy;
+
+ /* Clear Descriptors */
+ memset(pDev->bds,0,0x400);
+
+ /* Clear stats */
+ memset(&pDev->stats,0,sizeof(struct grtm_ioc_stats));
+
+ /* Init Descriptor Ring */
+ memset(pDev->_ring,0,sizeof(struct grtm_ring)*128);
+ for(i=0;i<127;i++){
+ pDev->_ring[i].next = &pDev->_ring[i+1];
+ pDev->_ring[i].bd = &pDev->bds[i];
+ pDev->_ring[i].frm = NULL;
+ }
+ pDev->_ring[127].next = &pDev->_ring[0];
+ pDev->_ring[127].bd = &pDev->bds[127];
+ pDev->_ring[127].frm = NULL;
+
+ pDev->ring = &pDev->_ring[0];
+ pDev->ring_end = &pDev->_ring[0];
+
+ /* Clear Scheduled, Ready and Sent list */
+ grtm_list_clr(&pDev->ready);
+ grtm_list_clr(&pDev->scheduled);
+ grtm_list_clr(&pDev->sent);
+
+ /* Software init */
+ pDev->handling_transmission = 0;
+
+ /* Reset the transmitter */
+ regs->dma_ctrl = GRTM_DMA_CTRL_TXRST;
+ regs->dma_ctrl = 0; /* Leave Reset */
+
+ /* Clear old interrupts */
+ regs->dma_status = GRTM_DMA_STS_ALL;
+
+ /* Set Descriptor Pointer Base register to point to first descriptor */
+ drvmgr_translate(pDev->dev, 0, 0, (void *)pDev->bds, (void **)&regs->dma_bd);
+ /*regs->dma_bd = (unsigned int)pDev->bds;*/
+
+ /* Set hardware options as defined by config */
+ if ( grtm_hw_set_config(pDev, cfg, &pDev->hw_avail) ) {
+ return RTEMS_IO_ERROR;
+ }
+
+ /* Enable TM Transmitter */
+ regs->ctrl = GRTM_CTRL_EN;
+
+ /* Wait for TXRDY to be cleared */
+ i=1000;
+ while( i > 0 ) {
+ asm volatile ("nop"::);
+ i--;
+ }
+
+ /* Check transmitter startup OK */
+ i = 1000000;
+ do {
+ /* Location of TXRDY Bit is different for different revisions */
+ if ( pDev->subrev == 0 ) {
+ txrdy = READ_REG(&regs->dma_ctrl) &
+ GRTM_REV0_DMA_CTRL_TXRDY;
+ } else {
+ txrdy = READ_REG(&regs->dma_status) &
+ GRTM_REV1_DMA_STS_TXRDY;
+ }
+ if (txrdy != 0)
+ break;
+
+ asm volatile ("nop"::);
+ } while ( --i > 0 );
+ if ( i == 0 ) {
+ /* Reset Failed */
+ DBG("GRTM: start: Reseting transmitter failed (%d)\n",i);
+ return RTEMS_IO_ERROR;
+ }
+ DBG("GRTM: reset time %d\n",i);
+
+ /* Everything is configured, the TM transmitter is started
+ * and idle frames has been sent.
+ */
+
+ /* Mark running before enabling the DMA transmitter */
+ pDev->running = 1;
+
+ /* Enable interrupts (Error and DMA TX) */
+ regs->dma_ctrl = GRTM_DMA_CTRL_IE;
+
+ DBG("GRTM: STARTED\n");
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static void grtm_stop(struct grtm_priv *pDev)
+{
+ struct grtm_regs *regs = pDev->regs;
+
+ /* Disable the transmitter & Interrupts */
+ regs->dma_ctrl = 0;
+
+ /* Clear any pending interrupt */
+ regs->dma_status = GRTM_DMA_STS_ALL;
+
+ DBG("GRTM: STOPPED\n");
+
+ /* Flush semaphore in case a thread is stuck waiting for TX Interrupts */
+ rtems_semaphore_flush(pDev->sem_tx);
+}
+
+static rtems_device_driver grtm_open(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg)
+{
+ struct grtm_priv *pDev;
+ struct drvmgr_dev *dev;
+
+ FUNCDBG();
+
+ if ( drvmgr_get_dev(&grtm_drv_info.general, minor, &dev) ) {
+ DBG("Wrong minor %d\n", minor);
+ return RTEMS_INVALID_NUMBER;
+ }
+ pDev = (struct grtm_priv *)dev->priv;
+
+ /* Wait until we get semaphore */
+ if ( rtems_semaphore_obtain(grtm_dev_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT) != RTEMS_SUCCESSFUL ){
+ return RTEMS_INTERNAL_ERROR;
+ }
+
+ /* Is device in use? */
+ if ( pDev->open ){
+ rtems_semaphore_release(grtm_dev_sem);
+ return RTEMS_RESOURCE_IN_USE;
+ }
+
+ /* Mark device taken */
+ pDev->open = 1;
+
+ rtems_semaphore_release(grtm_dev_sem);
+
+ DBG("grtm_open: OPENED minor %d (pDev: 0x%x)\n",pDev->minor,(unsigned int)pDev);
+
+ /* Set defaults */
+ pDev->config.timeout = RTEMS_NO_TIMEOUT; /* no timeout (wait forever) */
+ pDev->config.blocking = 0; /* polling mode */
+
+ pDev->running = 0; /* not in running mode yet */
+
+ memset(&pDev->config,0,sizeof(pDev->config));
+
+ /* The core has been reset when we execute here, so it is possible
+ * to read out what HW is implemented from core.
+ */
+ grtm_hw_get_implementation(pDev, &pDev->hw_avail);
+
+ /* Get default modes */
+ grtm_hw_get_default_modes(&pDev->config,&pDev->hw_avail);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver grtm_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ struct grtm_priv *pDev;
+ struct drvmgr_dev *dev;
+
+ FUNCDBG();
+
+ if ( drvmgr_get_dev(&grtm_drv_info.general, minor, &dev) ) {
+ return RTEMS_INVALID_NUMBER;
+ }
+ pDev = (struct grtm_priv *)dev->priv;
+
+ if ( pDev->running ){
+ grtm_stop(pDev);
+ pDev->running = 0;
+ }
+
+ /* Reset core */
+ grtm_hw_reset(pDev);
+
+ /* Clear descriptor area just for sure */
+ memset(pDev->bds, 0, 0x400);
+
+ /* Mark not open */
+ pDev->open = 0;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver grtm_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ FUNCDBG();
+ return RTEMS_NOT_IMPLEMENTED;
+}
+
+static rtems_device_driver grtm_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ FUNCDBG();
+ return RTEMS_NOT_IMPLEMENTED;
+}
+
+/* Scans the desciptor table for scheduled frames that has been sent,
+ * and moves these frames from the head of the scheduled queue to the
+ * tail of the sent queue.
+ *
+ * Also, for all frames the status is updated.
+ *
+ * Return Value
+ * Number of frames freed.
+ */
+static int grtm_free_sent(struct grtm_priv *pDev)
+{
+ struct grtm_ring *curr;
+ struct grtm_frame *last_frm, *first_frm;
+ int freed_frame_cnt=0;
+ unsigned int ctrl;
+
+ curr = pDev->ring_end;
+
+ /* Step into TX ring to find sent frames */
+ if ( !curr->frm ){
+ /* No scheduled frames, abort */
+ return 0;
+ }
+
+ /* There has been messages scheduled ==> scheduled messages may have been
+ * transmitted and needs to be collected.
+ */
+
+ first_frm = curr->frm;
+
+ /* Loop until first enabled unsent frame is found.
+ * A unused descriptor is indicated by an unassigned frm field
+ */
+ while ( curr->frm && !((ctrl=READ_REG(&curr->bd->ctrl)) & GRTM_BD_EN) ){
+ /* Handle one sent Frame */
+
+ /* Remember last handled frame so that insertion/removal from
+ * frames lists go fast.
+ */
+ last_frm = curr->frm;
+
+ /* 1. Set flags to indicate error(s) and other information */
+ last_frm->flags |= GRTM_FLAGS_SENT; /* Mark sent */
+
+ /* Update Stats */
+ pDev->stats.frames_sent++;
+
+ /* Did packet encounter link error? */
+ if ( ctrl & GRTM_BD_UE ) {
+ pDev->stats.err_underrun++;
+ last_frm->flags |= GRRM_FLAGS_ERR;
+ }
+
+ curr->frm = NULL; /* Mark unused */
+
+ /* Increment */
+ curr = curr->next;
+ freed_frame_cnt++;
+ }
+
+ /* 1. Remove all handled frames from scheduled queue
+ * 2. Put all handled frames into sent queue
+ */
+ if ( freed_frame_cnt > 0 ){
+
+ /* Save TX ring posistion */
+ pDev->ring_end = curr;
+
+ /* Remove all sent frames from scheduled list */
+ if ( pDev->scheduled.tail == last_frm ){
+ /* All scheduled frames sent... */
+ pDev->scheduled.head = NULL;
+ pDev->scheduled.tail = NULL;
+ }else{
+ pDev->scheduled.head = last_frm->next;
+ }
+ last_frm->next = NULL;
+
+ /* Put all sent frames into "Sent queue" for user to
+ * collect, later on.
+ */
+ if ( !pDev->sent.head ){
+ /* Sent queue empty */
+ pDev->sent.head = first_frm;
+ pDev->sent.tail = last_frm;
+ }else{
+ pDev->sent.tail->next = first_frm;
+ pDev->sent.tail = last_frm;
+ }
+ }
+ return freed_frame_cnt;
+}
+
+
+/* Moves as many frames in the ready queue (as there are free descriptors for)
+ * to the scheduled queue. The free descriptors are then assigned one frame
+ * each and enabled for transmission.
+ *
+ * Return Value
+ * Returns number of frames moved from ready to scheduled queue
+ */
+static int grtm_schedule_ready(struct grtm_priv *pDev, int ints_off)
+{
+ int cnt;
+ unsigned int ctrl, dmactrl;
+ struct grtm_ring *curr_bd;
+ struct grtm_frame *curr_frm, *last_frm;
+ IRQ_GLOBAL_PREPARE(oldLevel);
+
+ if ( !pDev->ready.head ){
+ return 0;
+ }
+
+ cnt=0;
+ curr_frm = pDev->ready.head;
+ curr_bd = pDev->ring;
+ while( !curr_bd->frm ){
+ /* Assign frame to descriptor */
+ curr_bd->frm = curr_frm;
+
+ /* Prepare descriptor address. Three cases:
+ * - GRTM core on same bus as CPU ==> no translation (Address used by CPU = address used by GRTM)
+ * - GRTM core on remote bus, and payload address given as used by CPU ==> Translation needed
+ * - GRTM core on remote bus, and payload address given as used by GRTM ==> no translation [ USER does custom translation]
+ */
+ if ( curr_frm->flags & (GRTM_FLAGS_TRANSLATE|GRTM_FLAGS_TRANSLATE_AND_REMEMBER) ) {
+ /* Do translation */
+ drvmgr_translate(pDev->dev, 0, 0, (void *)curr_frm->payload, (void **)&curr_bd->bd->address);
+ if ( curr_frm->flags & GRTM_FLAGS_TRANSLATE_AND_REMEMBER ) {
+ if ( curr_frm->payload != curr_bd->bd->address ) {
+ /* Translation needed */
+ curr_frm->flags &= ~GRTM_FLAGS_TRANSLATE_AND_REMEMBER;
+ curr_frm->flags |= GRTM_FLAGS_TRANSLATE;
+ } else {
+ /* No Trnaslation needed */
+ curr_frm->flags &= ~(GRTM_FLAGS_TRANSLATE|GRTM_FLAGS_TRANSLATE_AND_REMEMBER);
+ }
+ }
+ } else {
+ /* Custom translation or no translation needed */
+ curr_bd->bd->address = (unsigned int)curr_frm->payload;
+ }
+
+ ctrl = GRTM_BD_EN;
+ if ( curr_bd->next == pDev->_ring ){
+ ctrl |= GRTM_BD_WR; /* Wrap around */
+ }
+ /* Apply user options/flags */
+ ctrl |= (curr_frm->flags & GRTM_FLAGS_MASK);
+
+ /* Is this Frame going to be an interrupt Frame? */
+ if ( (--pDev->enable_cnt_curr) <= 0 ){
+ if ( pDev->config.enable_cnt == 0 ){
+ pDev->enable_cnt_curr = 0x3fffffff;
+ }else{
+ pDev->enable_cnt_curr = pDev->config.enable_cnt;
+ ctrl |= GRTM_BD_IE;
+ }
+ }
+
+ /* Enable descriptor */
+ curr_bd->bd->ctrl = ctrl;
+
+ last_frm = curr_frm;
+ curr_bd = curr_bd->next;
+ cnt++;
+
+ /* Get Next Frame from Ready Queue */
+ if ( curr_frm == pDev->ready.tail ){
+ /* Handled all in ready queue. */
+ curr_frm = NULL;
+ break;
+ }
+ curr_frm = curr_frm->next;
+ }
+
+ /* Has frames have been scheduled? */
+ if ( cnt > 0 ){
+ /* Make last frame mark end of chain, probably pointless... */
+ last_frm->next = NULL;
+
+ /* Insert scheduled packets into scheduled queue */
+ if ( !pDev->scheduled.head ){
+ /* empty scheduled queue */
+ pDev->scheduled.head = pDev->ready.head;
+ pDev->scheduled.tail = last_frm;
+ }else{
+ pDev->scheduled.tail->next = pDev->ready.head;
+ pDev->scheduled.tail = last_frm;
+ }
+
+ /* Remove scheduled packets from ready queue */
+ pDev->ready.head = curr_frm;
+ if ( !curr_frm ){
+ pDev->ready.tail = NULL;
+ }
+
+ /* Update TX ring posistion */
+ pDev->ring = curr_bd;
+ if ( !ints_off ) {
+ IRQ_GLOBAL_DISABLE(oldLevel);
+ }
+
+ /* Make hardware aware of the newly enabled descriptors */
+ dmactrl = READ_REG(&pDev->regs->dma_ctrl);
+ dmactrl &= ~(GRTM_DMA_CTRL_TXRST | GRTM_DMA_CTRL_RST);
+ dmactrl |= GRTM_DMA_CTRL_EN;
+ pDev->regs->dma_ctrl = dmactrl;
+
+ if ( !ints_off ) {
+ IRQ_GLOBAL_ENABLE(oldLevel);
+ }
+ }
+ return cnt;
+}
+
+
+static rtems_device_driver grtm_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ struct grtm_priv *pDev;
+ struct drvmgr_dev *dev;
+ rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *)arg;
+ unsigned int *data = ioarg->buffer;
+ int status;
+ struct grtm_ioc_config *cfg;
+ struct grtm_ioc_hw_status *hwregs;
+ IRQ_GLOBAL_PREPARE(oldLevel);
+ struct grtm_list *chain;
+ struct grtm_frame *curr;
+ struct grtm_ioc_hw *hwimpl;
+ struct grtm_ioc_stats *stats;
+ int num,ret;
+
+ FUNCDBG();
+
+ if ( drvmgr_get_dev(&grtm_drv_info.general, minor, &dev) ) {
+ return RTEMS_INVALID_NUMBER;
+ }
+ pDev = (struct grtm_priv *)dev->priv;
+
+ if (!ioarg)
+ return RTEMS_INVALID_NAME;
+
+ ioarg->ioctl_return = 0;
+ switch(ioarg->command) {
+ case GRTM_IOC_START:
+ if ( pDev->running ) {
+ return RTEMS_RESOURCE_IN_USE; /* EBUSY */
+ }
+ if ( (status=grtm_start(pDev)) != RTEMS_SUCCESSFUL ){
+ return status;
+ }
+ /* Register ISR & Enable interrupt */
+ drvmgr_interrupt_register(dev, 0, "grtm", grtm_interrupt, pDev);
+
+ /* Read and write are now open... */
+ break;
+
+ case GRTM_IOC_STOP:
+ if ( !pDev->running ) {
+ return RTEMS_RESOURCE_IN_USE;
+ }
+
+ /* Disable interrupts */
+ drvmgr_interrupt_unregister(dev, 0, grtm_interrupt, pDev);
+ grtm_stop(pDev);
+ pDev->running = 0;
+ break;
+
+ case GRTM_IOC_ISSTARTED:
+ if ( !pDev->running ) {
+ return RTEMS_RESOURCE_IN_USE;
+ }
+ break;
+
+ case GRTM_IOC_SET_BLOCKING_MODE:
+ if ( (unsigned int)data > GRTM_BLKMODE_BLK ) {
+ return RTEMS_INVALID_NAME;
+ }
+ DBG("GRTM: Set blocking mode: %d\n",(unsigned int)data);
+ pDev->config.blocking = (unsigned int)data;
+ break;
+
+ case GRTM_IOC_SET_TIMEOUT:
+ DBG("GRTM: Timeout: %d\n",(unsigned int)data);
+ pDev->config.timeout = (rtems_interval)data;
+ break;
+
+ case GRTM_IOC_SET_CONFIG:
+ cfg = (struct grtm_ioc_config *)data;
+ if ( !cfg ) {
+ return RTEMS_INVALID_NAME;
+ }
+
+ if ( pDev->running ) {
+ return RTEMS_RESOURCE_IN_USE;
+ }
+
+ pDev->config = *cfg;
+ break;
+
+ case GRTM_IOC_GET_STATS:
+ stats = (struct grtm_ioc_stats *)data;
+ if ( !stats ) {
+ return RTEMS_INVALID_NAME;
+ }
+ memcpy(stats,&pDev->stats,sizeof(struct grtm_ioc_stats));
+ break;
+
+ case GRTM_IOC_CLR_STATS:
+ memset(&pDev->stats,0,sizeof(struct grtm_ioc_stats));
+ break;
+
+ case GRTM_IOC_GET_CONFIG:
+ cfg = (struct grtm_ioc_config *)data;
+ if ( !cfg ) {
+ return RTEMS_INVALID_NAME;
+ }
+
+ *cfg = pDev->config;
+ break;
+
+ case GRTM_IOC_GET_OCFREG:
+ if ( !pDev->hw_avail.ocf ) {
+ /* Hardware does not implement the OCF register */
+ return RTEMS_NOT_DEFINED;
+ }
+ if ( !data ) {
+ return RTEMS_INVALID_NAME;
+ }
+ *(unsigned int **)data = (unsigned int *)&pDev->regs->ocf;
+ break;
+
+ case GRTM_IOC_GET_HW_IMPL:
+ hwimpl = (struct grtm_ioc_hw *)data;
+ if ( !hwimpl ) {
+ return RTEMS_INVALID_NAME;
+ }
+ *hwimpl = pDev->hw_avail;
+ break;
+
+ case GRTM_IOC_GET_HW_STATUS:
+ hwregs = (struct grtm_ioc_hw_status *)data;
+ if ( !hwregs ) {
+ return RTEMS_INVALID_NAME;
+ }
+ /* We disable interrupt in order to get a snapshot of the registers */
+ IRQ_GLOBAL_DISABLE(oldLevel);
+#warning IMPLEMENT HWREGS
+ IRQ_GLOBAL_ENABLE(oldLevel);
+ break;
+
+ /* Put a chain of frames at the back of the "Ready frames" queue. This
+ * triggers the driver to put frames from the Ready queue into unused
+ * available descriptors. (Ready -> Scheduled)
+ */
+
+ case GRTM_IOC_SEND:
+ if ( !pDev->running ){
+ return RTEMS_RESOURCE_IN_USE;
+ }
+ num=0;
+
+ /* Get pointer to frame chain wished be sent */
+ chain = (struct grtm_list *)ioarg->buffer;
+ if ( !chain ){
+ /* No new frames to send ==> just trigger hardware
+ * to send previously made ready frames to be sent.
+ */
+ pDev->handling_transmission = 1;
+ goto trigger_transmission;
+ }
+ if ( !chain->tail || !chain->head ){
+ return RTEMS_INVALID_NAME;
+ }
+
+ DBG("GRTM_SEND: head: 0x%x, tail: 0x%x\n",chain->head,chain->tail);
+
+ /* Mark ready frames unsent by clearing GRTM_FLAGS_SENT of all frames */
+
+ curr = chain->head;
+ while(curr != chain->tail){
+ curr->flags = curr->flags & ~(GRTM_FLAGS_SENT|GRRM_FLAGS_ERR);
+ curr = curr->next;
+ num++;
+ }
+ curr->flags = curr->flags & ~(GRTM_FLAGS_SENT|GRRM_FLAGS_ERR);
+ num++;
+
+ pDev->handling_transmission = 1;
+ /* 1. Put frames into ready queue
+ * (New Frames->READY)
+ */
+ if ( pDev->ready.head ){
+ /* Frames already on ready queue (no free descriptors previously) ==>
+ * Put frames at end of ready queue
+ */
+ pDev->ready.tail->next = chain->head;
+ pDev->ready.tail = chain->tail;
+ chain->tail->next = NULL;
+ }else{
+ /* All frames is put into the ready queue for later processing */
+ pDev->ready.head = chain->head;
+ pDev->ready.tail = chain->tail;
+ chain->tail->next = NULL;
+ }
+ pDev->ready_cnt += num; /* Added 'num' frames to ready queue */
+trigger_transmission:
+ /* 2. Free used descriptors and put the sent frame into the "Sent queue"
+ * (SCHEDULED->SENT)
+ */
+ num = grtm_free_sent(pDev);
+ pDev->scheduled_cnt -= num;
+ pDev->sent_cnt += num;
+
+ /* 3. Use all available free descriptors there are frames for
+ * in the ready queue.
+ * (READY->SCHEDULED)
+ */
+ num = grtm_schedule_ready(pDev,0);
+ pDev->ready_cnt -= num;
+ pDev->scheduled_cnt += num;
+
+ pDev->handling_transmission = 0;
+ break;
+
+ /* Take all available sent frames from the "Sent frames" queue.
+ * If no frames has been sent, the thread may get blocked if in blocking
+ * mode. The blocking mode is not available if driver is not in running mode.
+ *
+ * Note this ioctl may return success even if the driver is not in STARTED mode.
+ * This is because in case of a error (link error of similar) and the driver switch
+ * from START to STOP mode we must still be able to get our frames back.
+ *
+ * Note in case the driver fails to send a frame for some reason (link error),
+ * the sent flag is set to 0 indicating a failure.
+ *
+ */
+ case GRTM_IOC_RECLAIM:
+ /* Get pointer to were to place reaped chain */
+ chain = (struct grtm_list *)ioarg->buffer;
+ if ( !chain ){
+ return RTEMS_INVALID_NAME;
+ }
+
+ /* Lock out interrupt handler */
+ pDev->handling_transmission = 1;
+
+ do {
+ /* Move sent frames from descriptors to Sent queue. This makes more
+ * descriptors (BDs) available.
+ */
+ num = grtm_free_sent(pDev);
+ pDev->scheduled_cnt -= num;
+ pDev->sent_cnt += num;
+
+
+ if ( pDev->running ){
+ /* Fill descriptors with as many frames from the ready list
+ * as possible.
+ */
+ num = grtm_schedule_ready(pDev,0);
+ pDev->ready_cnt -= num;
+ pDev->scheduled_cnt += num;
+ }
+
+ /* Are there any frames on the sent queue waiting to be
+ * reclaimed?
+ */
+
+ if ( !pDev->sent.head ){
+ /* No frames to reclaim - no frame in sent queue.
+ * Instead we block thread until frames have been sent
+ * if in blocking mode.
+ */
+ if ( pDev->running && pDev->config.blocking ){
+ ret = rtems_semaphore_obtain(pDev->sem_tx,RTEMS_WAIT,pDev->config.timeout);
+ if ( ret == RTEMS_TIMEOUT ) {
+ pDev->handling_transmission = 0;
+ return RTEMS_TIMEOUT;
+ } else if ( ret == RTEMS_SUCCESSFUL ) {
+ /* There might be frames available, go check */
+ continue;
+ } else {
+ /* any error (driver closed, internal error etc.) */
+ pDev->handling_transmission = 0;
+ return RTEMS_UNSATISFIED;
+ }
+
+ }else{
+ /* non-blocking mode, we quit */
+ chain->head = NULL;
+ chain->tail = NULL;
+ /* do not lock out interrupt handler any more */
+ pDev->handling_transmission = 0;
+ return RTEMS_TIMEOUT;
+ }
+ }else{
+ /* Take all sent framess from sent queue to userspace queue */
+ chain->head = pDev->sent.head;
+ chain->tail = pDev->sent.tail;
+ chain->tail->next = NULL; /* Just for sure */
+
+ /* Mark no Sent */
+ grtm_list_clr(&pDev->sent);
+ pDev->sent_cnt = 0;
+
+ DBG("TX_RECLAIM: head: 0x%x, tail: 0x%x\n",chain->head,chain->tail);
+ break;
+ }
+
+ }while(1);
+
+ /* do not lock out interrupt handler any more */
+ pDev->handling_transmission = 0;
+ break;
+
+ default:
+ return RTEMS_NOT_DEFINED;
+ }
+ return RTEMS_SUCCESSFUL;
+}
+
+static void grtm_interrupt(void *arg)
+{
+ struct grtm_priv *pDev = arg;
+ struct grtm_regs *regs = pDev->regs;
+ unsigned int status;
+ int num;
+
+ /* Clear interrupt by reading it */
+ status = READ_REG(&regs->dma_status);
+
+ /* Spurious Interrupt? */
+ if ( !pDev->running )
+ return;
+
+ if ( status )
+ regs->dma_status = status;
+
+ if ( status & GRTM_DMA_STS_TFF ){
+ pDev->stats.err_transfer_frame++;
+ }
+
+ if ( status & GRTM_DMA_STS_TA ){
+ pDev->stats.err_ahb++;
+ }
+
+ if ( status & GRTM_DMA_STS_TE ){
+ pDev->stats.err_tx++;
+ }
+
+ if ( status & GRTM_DMA_STS_TI ){
+
+ if ( pDev->config.isr_desc_proc && !pDev->handling_transmission ) {
+ /* Free used descriptors and put the sent frame into the "Sent queue"
+ * (SCHEDULED->SENT)
+ */
+ num = grtm_free_sent(pDev);
+ pDev->scheduled_cnt -= num;
+ pDev->sent_cnt += num;
+
+ /* Use all available free descriptors there are frames for
+ * in the ready queue.
+ * (READY->SCHEDULED)
+ */
+ num = grtm_schedule_ready(pDev,1);
+ pDev->ready_cnt -= num;
+ pDev->scheduled_cnt += num;
+
+#if 0
+ if ( (pDev->config.blocking==GRTM_BLKMODE_COMPLETE) && pDev->timeout ){
+ /* Signal to thread only if enough data is available */
+ if ( pDev->wait_for_frames > grtm_data_avail(pDev) ){
+ /* Not enough data available */
+ goto procceed_processing_interrupts;
+ }
+
+ /* Enough number of frames has been transmitted which means that
+ * the waiting thread should be woken up.
+ */
+ rtems_semaphore_release(pDev->sem_tx);
+ }
+#endif
+ }
+
+ if ( pDev->config.blocking == GRTM_BLKMODE_BLK ) {
+ /* Blocking mode */
+
+#if 0
+ /* Disable further Interrupts until handled by waiting task. */
+ regs->dma_ctrl = READ_REG(&regs->dma_ctrl) & ~GRTM_DMA_CTRL_IE;
+#endif
+
+ /* Signal Semaphore to wake waiting thread in ioctl(SEND|RECLAIM) */
+ rtems_semaphore_release(pDev->sem_tx);
+ }
+
+ }
+
+procceed_processing_interrupts:
+ ;
+}
+
+static rtems_device_driver grtm_initialize(
+ rtems_device_major_number major,
+ rtems_device_minor_number unused,
+ void *arg
+ )
+{
+ /* Device Semaphore created with count = 1 */
+ if ( rtems_semaphore_create(rtems_build_name('G', 'R', 'T', 'M'),
+ 1,
+ RTEMS_FIFO|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &grtm_dev_sem) != RTEMS_SUCCESSFUL ) {
+ return RTEMS_INTERNAL_ERROR;
+ }
+
+ return RTEMS_SUCCESSFUL;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/tmtc/grtm_rmap.c b/c/src/lib/libbsp/sparc/shared/tmtc/grtm_rmap.c
new file mode 100644
index 0000000000..ecce1cdbde
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/tmtc/grtm_rmap.c
@@ -0,0 +1,1699 @@
+/* GRTM CCSDS Telemetry Encoder driver
+ *
+ * --------------------------------------------------------------------------
+ * -- This file is a part of GAISLER RESEARCH source code.
+ * -- Copyright (C) 2009, Aeroflex Gaisler AB - all rights reserved.
+ * --
+ * -- ANY USE OR REDISTRIBUTION IN PART OR IN WHOLE MUST BE HANDLED IN
+ * -- ACCORDANCE WITH THE GAISLER LICENSE AGREEMENT AND MUST BE APPROVED
+ * -- IN ADVANCE IN WRITING.
+ * --
+ * -- BY DEFAULT, DISTRIBUTION OR DISCLOSURE IS NOT PERMITTED.
+ * --------------------------------------------------------------------------
+ *
+ * 2009-11-23, Daniel Hellstrom <daniel@gaisler.com>
+ * Created from on-chip GRTM driver
+ *
+ */
+
+#include <bsp.h>
+#include <rtems/libio.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+#include <malloc.h>
+#include <rtems/bspIo.h>
+
+#include <drvmgr/drvmgr.h>
+#include <ambapp.h>
+#include <drvmgr/ambapp_bus.h>
+#include <drvmgr/ambapp_bus_rmap.h>
+#include <grtm.h>
+
+
+#ifndef IRQ_GLOBAL_PREPARE
+ #define IRQ_GLOBAL_PREPARE(level) rtems_interrupt_level level
+#endif
+
+#ifndef IRQ_GLOBAL_DISABLE
+ #define IRQ_GLOBAL_DISABLE(level) rtems_interrupt_disable(level)
+#endif
+
+#ifndef IRQ_GLOBAL_ENABLE
+ #define IRQ_GLOBAL_ENABLE(level) rtems_interrupt_enable(level)
+#endif
+
+/**** START: RMAP STUFF ****/
+#define DESCRIPTOR_MAX 128
+#define WRITE_REG(pDev, adr, value) pDev->rw_w32((uint32_t *)adr, (uint32_t)value, &pDev->rw_arg)
+#define READ_REG(pDev, adr) pDev->rw_r32((uint32_t *)adr, &pDev->rw_arg)
+#define TRANSFER_FRM(pDev, dstadr, srcadr, length) pDev->rw_wmem(dstadr, srcadr, length, &pDev->rw_arg)
+
+/* This call will take 128 bytes of buffer at stack */
+#define MEMSET(pDev, adr, c, length) pDev->rw_memset(adr, c, length, &pDev->rw_arg)
+
+/**** END: RMAP STUFF ****/
+
+/*
+#define DEBUG
+#define DEBUGFUNCS
+*/
+
+#include <debug_defs.h>
+
+/* GRTM register map */
+struct grtm_regs {
+ volatile unsigned int dma_ctrl; /* DMA Control Register (0x00) */
+ volatile unsigned int dma_status; /* DMA Status Register (0x04) */
+ volatile unsigned int dma_len; /* DMA Length Register (0x08) */
+ volatile unsigned int dma_bd; /* DMA Descriptor Pointer Register (0x0c) */
+
+ volatile unsigned int dma_cfg; /* DMA Configuration Register (0x10) */
+ volatile unsigned int revision; /* GRTM Revision Register (0x14) */
+
+ int unused00[2];
+
+ volatile unsigned int ext_ctrl; /* External Control Register (0x20) */
+
+ int unused01[2];
+
+ volatile unsigned int ext_bd; /* External Descriptor Register (0x20) */
+
+ int unused0[(0x80-0x30)/4];
+
+ volatile unsigned int ctrl; /* TM Control Register (0x80) */
+ volatile unsigned int status; /* TM Status Register (0x84) */
+ volatile unsigned int cfg; /* TM Configuration Register (0x88) */
+ volatile unsigned int size; /* TM Size Register (0x8c) */
+
+ volatile unsigned int phy; /* TM Physical Layer Register (0x90) */
+ volatile unsigned int code; /* TM Coding Sub-Layer Register (0x94) */
+ volatile unsigned int asmr; /* TM Attached Synchronization Marker Register (0x98) */
+
+ int unused1;
+
+ volatile unsigned int all_frm; /* TM All Frames Generation Register (0xa0) */
+ volatile unsigned int mst_frm; /* TM Master Channel Frame Generation Register (0xa4) */
+ volatile unsigned int idle_frm; /* TM Idle Frame Generation Register (0xa8) */
+
+ int unused2[(0xc0-0xac)/4];
+
+ volatile unsigned int fsh[4]; /* TM FSH/Insert Zone Registers (0xc0..0xcc) */
+
+ volatile unsigned int ocf; /* TM Operational Control Field Register (0xd0) */
+};
+
+/* DMA Control Register (0x00) */
+#define GRTM_DMA_CTRL_EN_BIT 0
+#define GRTM_DMA_CTRL_IE_BIT 1
+#define GRTM_DMA_CTRL_TXRST_BIT 2
+#define GRTM_DMA_CTRL_RST_BIT 3
+#define GRTM_DMA_CTRL_TFIE_BIT 4
+
+#define GRTM_DMA_CTRL_EN (1<<GRTM_DMA_CTRL_EN_BIT)
+#define GRTM_DMA_CTRL_IE (1<<GRTM_DMA_CTRL_IE_BIT)
+#define GRTM_DMA_CTRL_TXRST (1<<GRTM_DMA_CTRL_TXRST_BIT)
+#define GRTM_DMA_CTRL_RST (1<<GRTM_DMA_CTRL_RST_BIT)
+#define GRTM_DMA_CTRL_TFIE (1<<GRTM_DMA_CTRL_TFIE_BIT)
+
+/* DMA Status Register (0x04) */
+#define GRTM_DMA_STS_TE_BIT 0
+#define GRTM_DMA_STS_TI_BIT 1
+#define GRTM_DMA_STS_TA_BIT 2
+#define GRTM_DMA_STS_TFF_BIT 3
+#define GRTM_DMA_STS_TFS_BIT 4
+
+#define GRTM_DMA_STS_TE (1<<GRTM_DMA_STS_TE_BIT)
+#define GRTM_DMA_STS_TI (1<<GRTM_DMA_STS_TI_BIT)
+#define GRTM_DMA_STS_TA (1<<GRTM_DMA_STS_TA_BIT)
+#define GRTM_DMA_STS_TFF (1<<GRTM_DMA_STS_TFF_BIT)
+#define GRTM_DMA_STS_TFS (1<<GRTM_DMA_STS_TFS_BIT)
+#define GRTM_DMA_STS_ALL 0x1f
+
+/* DMA Length Register (0x08) */
+#define GRTM_DMA_LEN_LEN_BIT 0
+#define GRTM_DMA_LEN_LIM_BIT 16
+
+#define GRTM_DMA_LEN_LEN (0x7ff<<GRTM_DMA_LEN_LEN_BIT)
+#define GRTM_DMA_LEN_LIM (0x3ff<<GRTM_DMA_LEN_LIM_BIT)
+
+/* DMA Descriptor Pointer Register (0x0c) */
+#define GRTM_DMA_BD_INDEX_BIT 0
+#define GRTM_DMA_BD_BASE_BIT 10
+
+#define GRTM_DMA_BD_INDEX (0x3ff<<GRTM_DMA_BD_INDEX_BIT)
+#define GRTM_DMA_BD_BASE (0xfffffc<<GRTM_DMA_BD_BASE_BIT)
+
+/* DMA Configuration Register (0x10) */
+#define GRTM_DMA_CFG_BLKSZ_BIT 0
+#define GRTM_DMA_CFG_FIFOSZ_BIT 16
+
+#define GRTM_DMA_CFG_BLKSZ (0xffff<<GRTM_DMA_CFG_BLKSZ_BIT)
+#define GRTM_DMA_CFG_FIFOSZ (0xffff<<GRTM_DMA_CFG_FIFOSZ_BIT)
+
+/* TM Control Register (0x80) */
+#define GRTM_CTRL_EN_BIT 0
+
+#define GRTM_CTRL_EN (1<<GRTM_CTRL_EN_BIT)
+
+/* TM Status Register (0x84) - Unused */
+
+/* TM Configuration Register (0x88) */
+#define GRTM_CFG_SC_BIT 0
+#define GRTM_CFG_SP_BIT 1
+#define GRTM_CFG_CE_BIT 2
+#define GRTM_CFG_NRZ_BIT 3
+#define GRTM_CFG_PSR_BIT 4
+#define GRTM_CFG_TE_BIT 5
+#define GRTM_CFG_RSDEP_BIT 6
+#define GRTM_CFG_RS_BIT 9
+#define GRTM_CFG_AASM_BIT 11
+#define GRTM_CFG_FECF_BIT 12
+#define GRTM_CFG_OCF_BIT 13
+#define GRTM_CFG_EVC_BIT 14
+#define GRTM_CFG_IDLE_BIT 15
+#define GRTM_CFG_FSH_BIT 16
+#define GRTM_CFG_MCG_BIT 17
+#define GRTM_CFG_IZ_BIT 18
+#define GRTM_CFG_FHEC_BIT 19
+#define GRTM_CFG_AOS_BIT 20
+#define GRTM_CFG_CIF_BIT 21
+#define GRTM_CFG_OCFB_BIT 22
+
+#define GRTM_CFG_SC (1<<GRTM_CFG_SC_BIT)
+#define GRTM_CFG_SP (1<<GRTM_CFG_SP_BIT)
+#define GRTM_CFG_CE (1<<GRTM_CFG_CE_BIT)
+#define GRTM_CFG_NRZ (1<<GRTM_CFG_NRZ_BIT)
+#define GRTM_CFG_PSR (1<<GRTM_CFG_PSR_BIT)
+#define GRTM_CFG_TE (1<<GRTM_CFG_TE_BIT)
+#define GRTM_CFG_RSDEP (0x7<<GRTM_CFG_RSDEP_BIT)
+#define GRTM_CFG_RS (0x3<<GRTM_CFG_RS_BIT)
+#define GRTM_CFG_AASM (1<<GRTM_CFG_AASM_BIT)
+#define GRTM_CFG_FECF (1<<GRTM_CFG_FECF_BIT)
+#define GRTM_CFG_OCF (1<<GRTM_CFG_OCF_BIT)
+#define GRTM_CFG_EVC (1<<GRTM_CFG_EVC_BIT)
+#define GRTM_CFG_IDLE (1<<GRTM_CFG_IDLE_BIT)
+#define GRTM_CFG_FSH (1<<GRTM_CFG_FSH_BIT)
+#define GRTM_CFG_MCG (1<<GRTM_CFG_MCG_BIT)
+#define GRTM_CFG_IZ (1<<GRTM_CFG_IZ_BIT)
+#define GRTM_CFG_FHEC (1<<GRTM_CFG_FHEC_BIT)
+#define GRTM_CFG_AOS (1<<GRTM_CFG_AOS_BIT)
+#define GRTM_CFG_CIF (1<<GRTM_CFG_CIF_BIT)
+#define GRTM_CFG_OCFB (1<<GRTM_CFG_OCFB_BIT)
+
+/* TM Size Register (0x8c) */
+#define GRTM_SIZE_BLKSZ_BIT 0
+#define GRTM_SIZE_FIFOSZ_BIT 8
+#define GRTM_SIZE_LEN_BIT 20
+
+#define GRTM_SIZE_BLKSZ (0xff<<GRTM_SIZE_BLKSZ_BIT)
+#define GRTM_SIZE_FIFOSZ (0xfff<<GRTM_SIZE_FIFOSZ_BIT)
+#define GRTM_SIZE_LEN (0xfff<<GRTM_SIZE_LEN_BIT)
+
+/* TM Physical Layer Register (0x90) */
+#define GRTM_PHY_SUB_BIT 0
+#define GRTM_PHY_SCF_BIT 15
+#define GRTM_PHY_SYM_BIT 16
+#define GRTM_PHY_SF_BIT 31
+
+#define GRTM_PHY_SUB (0x7fff<<GRTM_PHY_SUB_BIT)
+#define GRTM_PHY_SCF (1<<GRTM_PHY_SCF_BIT)
+#define GRTM_PHY_SYM (0x7fff<<GRTM_PHY_SYM_BIT)
+#define GRTM_PHY_SF (1<<GRTM_PHY_SF_BIT)
+
+/* TM Coding Sub-Layer Register (0x94) */
+#define GRTM_CODE_SC_BIT 0
+#define GRTM_CODE_SP_BIT 1
+#define GRTM_CODE_CERATE_BIT 2
+#define GRTM_CODE_CE_BIT 5
+#define GRTM_CODE_NRZ_BIT 6
+#define GRTM_CODE_PSR_BIT 7
+#define GRTM_CODE_RS8_BIT 11
+#define GRTM_CODE_RSDEP_BIT 12
+#define GRTM_CODE_RS_BIT 15
+#define GRTM_CODE_AASM_BIT 16
+#define GRTM_CODE_CSEL_BIT 17
+
+#define GRTM_CODE_SC (1<<GRTM_CODE_SC_BIT)
+#define GRTM_CODE_SP (1<<GRTM_CODE_SP_BIT)
+#define GRTM_CODE_CERATE (0x7<<GRTM_CODE_CERATE_BIT)
+#define GRTM_CODE_CE (1<<GRTM_CODE_CE_BIT)
+#define GRTM_CODE_NRZ (1<<GRTM_CODE_NRZ_BIT)
+#define GRTM_CODE_PSR (1<<GRTM_CODE_PSR_BIT)
+#define GRTM_CODE_RS8 (1<<GRTM_CODE_RS8_BIT)
+#define GRTM_CODE_RSDEP (0x7<<GRTM_CODE_RSDEP_BIT)
+#define GRTM_CODE_RS (1<<GRTM_CODE_RS_BIT)
+#define GRTM_CODE_AASM (1<<GRTM_CODE_AASM_BIT)
+#define GRTM_CODE_CSEL (0x3<<GRTM_CODE_CSEL_BIT)
+
+/* TM Attached Synchronization Marker Register (0x98) */
+#define GRTM_ASM_BIT 0
+
+#define GRTM_ASM 0xffffffff
+
+/* TM All Frames Generation Register (0xa0) */
+#define GRTM_ALL_LEN_BIT 0
+#define GRTM_ALL_VER_BIT 12
+#define GRTM_ALL_FHEC_BIT 14
+#define GRTM_ALL_FECF_BIT 15
+#define GRTM_ALL_IZ_BIT 16
+#define GRTM_ALL_IZLEN_BIT 17
+
+#define GRTM_ALL_LEN (0x7ff<<GRTM_ALL_LEN_BIT)
+#define GRTM_ALL_VER (0x3<<GRTM_ALL_VER_BIT)
+#define GRTM_ALL_FHEC (1<<GRTM_ALL_FHEC_BIT)
+#define GRTM_ALL_FECF (1<<GRTM_ALL_FECF_BIT)
+#define GRTM_ALL_IZ (1<<GRTM_ALL_IZ_BIT)
+#define GRTM_ALL_IZLEN (0x1f<<GRTM_ALL_IZLEN_BIT)
+
+/* TM Master Channel Frame Generation Register (0xa4) */
+#define GRTM_MST_OW_BIT 0
+#define GRTM_MST_OCF_BIT 1
+#define GRTM_MST_FSH_BIT 2
+#define GRTM_MST_MC_BIT 3
+#define GRTM_MST_MCCNTR_BIT 24
+
+#define GRTM_MST_OW (1<<GRTM_MST_OW_BIT)
+#define GRTM_MST_OCF (1<<GRTM_MST_OCF_BIT)
+#define GRTM_MST_FSH (1<<GRTM_MST_FSH_BIT)
+#define GRTM_MST_MC (0xff<<GRTM_MST_MC_BIT)
+
+/* TM Idle Frame Generation Register (0xa8) */
+#define GRTM_IDLE_SCID_BIT 0
+#define GRTM_IDLE_VCID_BIT 10
+#define GRTM_IDLE_MC_BIT 16
+#define GRTM_IDLE_VCC_BIT 17
+#define GRTM_IDLE_FSH_BIT 18
+#define GRTM_IDLE_EVC_BIT 19
+#define GRTM_IDLE_OCF_BIT 20
+#define GRTM_IDLE_IDLE_BIT 21
+#define GRTM_IDLE_MCCNTR_BIT 24
+
+#define GRTM_IDLE_SCID (0x3ff<<GRTM_IDLE_SCID_BIT)
+#define GRTM_IDLE_VCID (0x3f<<GRTM_IDLE_VCID_BIT)
+#define GRTM_IDLE_MC (1<<GRTM_IDLE_MC_BIT)
+#define GRTM_IDLE_VCC (1<<GRTM_IDLE_VCC_BIT)
+#define GRTM_IDLE_FSH (1<<GRTM_IDLE_FSH_BIT)
+#define GRTM_IDLE_EVC (1<<GRTM_IDLE_EVC_BIT)
+#define GRTM_IDLE_OCF (1<<GRTM_IDLE_OCF_BIT)
+#define GRTM_IDLE_IDLE (1<<GRTM_IDLE_IDLE_BIT)
+#define GRTM_IDLE_MCCNTR (0xff<<GRTM_IDLE_MCCNTR_BIT)
+
+/* TM FSH/Insert Zone Registers (0xc0..0xcc) */
+#define GRTM_FSH_DATA_BIT 0
+
+#define GRTM_FSH_DATA 0xffffffff
+
+
+/* TM Operational Control Field Register (0xd0) */
+#define GRTM_OCF_CLCW_BIT 0
+
+#define GRTM_OCF_CLCW 0xffffffff
+
+
+/* GRTM Revision 0 */
+#define GRTM_REV0_DMA_CTRL_TXRDY_BIT 5
+#define GRTM_REV0_DMA_CTRL_TXRDY (1<<GRTM_REV0_DMA_CTRL_TXRDY_BIT)
+
+/* GRTM Revision 1 */
+#define GRTM_REV1_DMA_STS_TXRDY_BIT 6
+#define GRTM_REV1_DMA_STS_TXSTAT_BIT 7
+#define GRTM_REV1_DMA_STS_TXRDY (1<<GRTM_REV1_DMA_STS_TXRDY_BIT)
+#define GRTM_REV1_DMA_STS_TXSTAT (1<<GRTM_REV1_DMA_STS_TXSTAT_BIT)
+
+#define GRTM_REV1_REV_SREV_BIT 0
+#define GRTM_REV1_REV_MREV_BIT 8
+#define GRTM_REV1_REV_TIRQ_BIT 16
+#define GRTM_REV1_REV_SREV (0xff<<GRTM_REV1_REV_SREV_BIT)
+#define GRTM_REV1_REV_MREV (0xff<<GRTM_REV1_REV_MREV_BIT)
+#define GRTM_REV1_REV_TIRQ (1<<GRTM_REV1_REV_TIRQ_BIT)
+
+
+/* GRTM transmit descriptor (0x400 Alignment need) */
+struct grtm_bd {
+ volatile unsigned int ctrl;
+ unsigned int address;
+};
+
+#define GRTM_BD_EN_BIT 0
+#define GRTM_BD_WR_BIT 1
+#define GRTM_BD_IE_BIT 2
+#define GRTM_BD_FECFB_BIT 3
+#define GRTM_BD_IZB_BIT 4
+#define GRTM_BD_FHECB_BIT 5
+#define GRTM_BD_OCFB_BIT 6
+#define GRTM_BD_FSHB_BIT 7
+#define GRTM_BD_MCB_BIT 8
+#define GRTM_BD_VCE_BIT 9
+#define GRTM_BD_TS_BIT 14
+#define GRTM_BD_UE_BIT 15
+
+#define GRTM_BD_EN (1<<GRTM_BD_EN_BIT)
+#define GRTM_BD_WR (1<<GRTM_BD_WR_BIT)
+#define GRTM_BD_IE (1<<GRTM_BD_IE_BIT)
+#define GRTM_BD_FECFB (1<<GRTM_BD_FECFB_BIT)
+#define GRTM_BD_IZB (1<<GRTM_BD_IZB_BIT)
+#define GRTM_BD_FHECB (1<<GRTM_BD_FHECB_BIT)
+#define GRTM_BD_OCFB (1<<GRTM_BD_OCFB_BIT)
+#define GRTM_BD_FSHB (1<<GRTM_BD_FSHB_BIT)
+#define GRTM_BD_MCB (1<<GRTM_BD_MCB_BIT)
+#define GRTM_BD_VCE (1<<GRTM_BD_VCE_BIT)
+#define GRTM_BD_TS (1<<GRTM_BD_TS_BIT)
+#define GRTM_BD_UE (1<<GRTM_BD_UE_BIT)
+
+/* Load register */
+
+/*#define READ_REG(address) (*(volatile unsigned int *)address)*/
+
+/* Driver functions */
+static rtems_device_driver grtm_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver grtm_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver grtm_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver grtm_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver grtm_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver grtm_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+
+#define GRTM_DRIVER_TABLE_ENTRY { grtm_initialize, grtm_open, grtm_close, grtm_read, grtm_write, grtm_ioctl }
+
+static rtems_driver_address_table grtm_driver = GRTM_DRIVER_TABLE_ENTRY;
+
+/* Structure that connects BD with SoftWare Frame */
+struct grtm_ring {
+ struct grtm_ring *next;
+ struct grtm_bd *bd;
+ struct grtm_frame *frm;
+ void *buf; /* Frame buffer in remote address */
+};
+
+struct grtm_priv {
+ struct drvmgr_dev *dev; /* Driver manager device */
+ char devName[32]; /* Device Name */
+ struct grtm_regs *regs;
+ int irq;
+ int minor;
+ int subrev; /* GRTM Revision */
+
+ int open;
+ int running;
+
+ int alloc_part_bd; /* Partition to allocate descriptors from */
+ int alloc_part_frm; /* Partition to allocate Frame buffers from */
+
+ struct grtm_bd *bds;
+ void *_bds;
+ unsigned char *_frame_buffers;
+ int frame_length_max;
+
+ /* Interrupt generation */
+ int enable_cnt_curr;/* Down counter, when 0 the interrupt bit is set for next descriptor */
+ rtems_id handling_transmission; /* SEMAPHORE: Tells ISR if user are active changing descriptors/queues */
+
+ struct grtm_ring *_ring; /* Root of ring */
+ struct grtm_ring *ring; /* Next ring to use for new frames to be transmitted */
+ struct grtm_ring *ring_end; /* Oldest activated ring used */
+
+ /* Collections of frames Ready to sent/ Scheduled for transmission/Sent
+ * frames waiting for the user to reclaim
+ */
+ struct grtm_list ready; /* Frames Waiting for free BDs */
+ struct grtm_list scheduled; /* Frames in BDs beeing transmitted */
+ struct grtm_list sent; /* Sent Frames waiting for user to reclaim and reuse */
+
+ /* Number of frames in the lists */
+ int ready_cnt; /* Number of ready frames */
+ int scheduled_cnt; /* Number of scheduled frames */
+ int sent_cnt; /* Number of sent frames */
+
+ struct grtm_ioc_hw hw_avail; /* Hardware support available */
+ struct grtm_ioc_config config;
+ struct grtm_ioc_stats stats;
+
+ /* Read/Write access operations */
+ struct drvmgr_rw_arg rw_arg;
+ ambapp_rmap_w32 rw_w32;
+ ambapp_rmap_r32 rw_r32;
+ ambapp_rmap_wmem rw_wmem;
+ ambapp_rmap_memset rw_memset;
+
+ rtems_id sem_tx;
+};
+
+/* Prototypes */
+static void grtm_hw_reset(struct grtm_priv *pDev);
+static void grtm_interrupt(void *arg);
+
+/* Common Global Variables */
+static rtems_id grtm_dev_sem;
+static int grtm_driver_io_registered = 0;
+static rtems_device_major_number grtm_driver_io_major = 0;
+
+/******************* Driver manager interface ***********************/
+
+/* Driver prototypes */
+static int grtm_register_io(rtems_device_major_number *m);
+static int grtm_device_init(struct grtm_priv *pDev);
+
+static int grtm_init2(struct drvmgr_dev *dev);
+static int grtm_init3(struct drvmgr_dev *dev);
+
+static struct drvmgr_drv_ops grtm_ops =
+{
+ {NULL, grtm_init2, grtm_init3, NULL},
+ NULL,
+ NULL
+};
+
+static struct amba_dev_id grtm_ids[] =
+{
+ {VENDOR_GAISLER, GAISLER_GRTM},
+ {0, 0} /* Mark end of table */
+};
+
+static struct amba_drv_info grtm_rmap_drv_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_AMBAPP_GAISLER_GRTM_ID, /* Driver ID */
+ "GRTM_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_AMBAPP_RMAP, /* Bus Type */
+ &grtm_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ 0,
+ },
+ &grtm_ids[0]
+};
+
+void grtm_rmap_register_drv (void)
+{
+ DBG("Registering RMAP-GRTM driver\n");
+ drvmgr_drv_register(&grtm_rmap_drv_info.general);
+}
+
+static int grtm_init2(struct drvmgr_dev *dev)
+{
+ struct grtm_priv *priv;
+
+ DBG("GRTM[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
+ priv = dev->priv = malloc(sizeof(struct grtm_priv));
+ if ( !priv )
+ return DRVMGR_NOMEM;
+ memset(priv, 0, sizeof(*priv));
+ priv->dev = dev;
+
+ /* Get Read/Write operations for bus */
+ priv->rw_arg.dev = dev;
+ priv->rw_arg.arg = drvmgr_func_call(dev->parent, AMBAPP_RMAP_RW_ARG, dev, NULL, NULL, NULL);
+ drvmgr_func_get(dev->parent, AMBAPP_RMAP_R32, (void **)&priv->rw_r32);
+ drvmgr_func_get(dev->parent, AMBAPP_RMAP_W32, (void **)&priv->rw_w32);
+ drvmgr_func_get(dev->parent, AMBAPP_RMAP_WMEM, (void **)&priv->rw_wmem);
+ drvmgr_func_get(dev->parent, AMBAPP_RMAP_MEMSET,
+ (void **)&priv->rw_memset);
+
+ /* This core will not find other cores, so we wait for init2() */
+
+ return DRVMGR_OK;
+}
+
+static int grtm_init3(struct drvmgr_dev *dev)
+{
+ struct grtm_priv *priv;
+ char prefix[32];
+ rtems_status_code status;
+
+ priv = dev->priv;
+
+ /* Do initialization */
+
+ if ( grtm_driver_io_registered == 0) {
+ /* Register the I/O driver only once for all cores */
+ if ( grtm_register_io(&grtm_driver_io_major) ) {
+ /* Failed to register I/O driver */
+ dev->priv = NULL;
+ return DRVMGR_FAIL;
+ }
+
+ grtm_driver_io_registered = 1;
+ }
+
+ /* I/O system registered and initialized
+ * Now we take care of device initialization.
+ */
+ if ( grtm_device_init(priv) ) {
+ return DRVMGR_FAIL;
+ }
+
+ /* Get Filesystem name prefix */
+ prefix[0] = '\0';
+ if ( drvmgr_get_dev_prefix(dev, prefix) ) {
+ /* Failed to get prefix, make sure of a unique FS name
+ * by using the driver minor.
+ */
+ sprintf(priv->devName, "/dev/grtm%d", dev->minor_drv);
+ } else {
+ /* Got special prefix, this means we have a bus prefix
+ * And we should use our "bus minor"
+ */
+ sprintf(priv->devName, "/dev/%sgrtm%d", prefix, dev->minor_bus);
+ }
+
+ /* Register Device */
+ status = rtems_io_register_name(priv->devName, grtm_driver_io_major, dev->minor_drv);
+ if (status != RTEMS_SUCCESSFUL) {
+ return DRVMGR_FAIL;
+ }
+
+ return DRVMGR_OK;
+}
+
+/******************* Driver Implementation ***********************/
+
+static int grtm_register_io(rtems_device_major_number *m)
+{
+ rtems_status_code r;
+
+ if ((r = rtems_io_register_driver(0, &grtm_driver, m)) == RTEMS_SUCCESSFUL) {
+ DBG("GRTM driver successfully registered, major: %d\n", *m);
+ } else {
+ switch(r) {
+ case RTEMS_TOO_MANY:
+ printk("GRTM rtems_io_register_driver failed: RTEMS_TOO_MANY\n");
+ return -1;
+ case RTEMS_INVALID_NUMBER:
+ printk("GRTM rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n");
+ return -1;
+ case RTEMS_RESOURCE_IN_USE:
+ printk("GRTM rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n");
+ return -1;
+ default:
+ printk("GRTM rtems_io_register_driver failed\n");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int grtm_device_init(struct grtm_priv *pDev)
+{
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
+ union drvmgr_key_value *value;
+
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)pDev->dev->businfo;
+ if ( ambadev == NULL ) {
+ return -1;
+ }
+ pnpinfo = &ambadev->info;
+ pDev->irq = pnpinfo->irq;
+ pDev->regs = (struct grtm_regs *)pnpinfo->apb_slv->start;
+ pDev->minor = pDev->dev->minor_drv;
+ pDev->open = 0;
+ pDev->running = 0;
+
+ /* Create Binary RX Semaphore with count = 0 */
+ if ( rtems_semaphore_create(rtems_build_name('G', 'R', 'M', '0' + pDev->minor),
+ 0,
+ RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|\
+ RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &pDev->sem_tx) != RTEMS_SUCCESSFUL ) {
+ return -1;
+ }
+
+ /* Create ISR protection Counting Semaphore with count = 1 */
+ if ( rtems_semaphore_create(rtems_build_name('G', 'T', 'M', '0' + pDev->minor),
+ 1,
+ RTEMS_FIFO | RTEMS_COUNTING_SEMAPHORE | RTEMS_PRIORITY | \
+ RTEMS_LOCAL | RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &pDev->handling_transmission) != RTEMS_SUCCESSFUL ) {
+ return -1;
+ }
+
+ /* Override default 2k MAX FRAME length if available from bus resource */
+ pDev->frame_length_max = 2*1024;
+ value = drvmgr_dev_key_get(pDev->dev, "maxFrameLength", KEY_TYPE_INT);
+ if ( value )
+ pDev->frame_length_max = value->i;
+
+ /* Default to allocate from partition 0 */
+ pDev->alloc_part_bd = 0;
+ pDev->alloc_part_frm = 0;
+ value = drvmgr_dev_key_get(pDev->dev, "bdAllocPartition", KEY_TYPE_INT);
+ if ( value )
+ pDev->alloc_part_bd = value->i;
+ value = drvmgr_dev_key_get(pDev->dev, "frameAllocPartition", KEY_TYPE_INT);
+ if ( value )
+ pDev->alloc_part_frm = value->i;
+
+ /* Allocate Memory for Descriptors */
+#ifdef REMOTE_DESCRIPTORS
+ pDev->bds = 0xA0000000;
+ pDev->_bds = 0xA0000000;
+#else
+ pDev->_bds = pDev->bds = (struct grtm_bd *)
+ ambapp_rmap_partition_memalign(pDev->dev, pDev->alloc_part_bd, 0x400, 0x400);
+#endif
+ if ( !pDev->bds ) {
+ DBG("GRTM: Failed to allocate descriptor table\n");
+ return -1;
+ }
+ MEMSET(pDev, pDev->bds, 0, 0x400);
+
+ pDev->_ring = malloc(sizeof(struct grtm_ring) * 128);
+ if ( !pDev->_ring ) {
+ return -1;
+ }
+ pDev->_frame_buffers = (unsigned char *) ambapp_rmap_partition_memalign(
+ pDev->dev, pDev->alloc_part_frm, 0x4, DESCRIPTOR_MAX * pDev->frame_length_max);
+ if ( !pDev->_frame_buffers ) {
+ return -1;
+ }
+
+ /* Reset Hardware before attaching IRQ handler */
+ grtm_hw_reset(pDev);
+
+ /* Read SUB revision number, ignore */
+ pDev->subrev = (READ_REG(pDev, &pDev->regs->revision) & GRTM_REV1_REV_SREV)
+ >> GRTM_REV1_REV_SREV_BIT;
+
+ return 0;
+}
+
+
+static inline void grtm_list_clr(struct grtm_list *list)
+{
+ list->head = NULL;
+ list->tail = NULL;
+}
+
+static void grtm_hw_reset(struct grtm_priv *pDev)
+{
+ /* Reset Core */
+ WRITE_REG(pDev, &pDev->regs->dma_ctrl, GRTM_DMA_CTRL_RST);
+}
+
+static void grtm_hw_get_implementation(struct grtm_priv *pDev, struct grtm_ioc_hw *hwcfg)
+{
+ struct grtm_regs *regs = pDev->regs;
+ unsigned int cfg = READ_REG(pDev, &regs->cfg);
+
+ hwcfg->cs = (cfg & GRTM_CFG_SC) ? 1:0;
+ hwcfg->sp = (cfg & GRTM_CFG_SP) ? 1:0;
+ hwcfg->ce = (cfg & GRTM_CFG_CE) ? 1:0;
+ hwcfg->nrz = (cfg & GRTM_CFG_NRZ) ? 1:0;
+ hwcfg->psr = (cfg & GRTM_CFG_PSR) ? 1:0;
+ hwcfg->te = (cfg & GRTM_CFG_TE) ? 1:0;
+ hwcfg->rsdep = (cfg & GRTM_CFG_RSDEP)>>GRTM_CFG_RSDEP_BIT;
+ hwcfg->rs = (cfg & GRTM_CFG_RS)>>GRTM_CFG_RS_BIT;
+ hwcfg->aasm = (cfg & GRTM_CFG_AASM) ? 1:0;
+ hwcfg->fecf = (cfg & GRTM_CFG_FECF) ? 1:0;
+ hwcfg->ocf = (cfg & GRTM_CFG_OCF) ? 1:0;
+ hwcfg->evc = (cfg & GRTM_CFG_EVC) ? 1:0;
+ hwcfg->idle = (cfg & GRTM_CFG_IDLE) ? 1:0;
+ hwcfg->fsh = (cfg & GRTM_CFG_FSH) ? 1:0;
+ hwcfg->mcg = (cfg & GRTM_CFG_MCG) ? 1:0;
+ hwcfg->iz = (cfg & GRTM_CFG_IZ) ? 1:0;
+ hwcfg->fhec = (cfg & GRTM_CFG_FHEC) ? 1:0;
+ hwcfg->aos = (cfg & GRTM_CFG_AOS) ? 1:0;
+ hwcfg->cif = (cfg & GRTM_CFG_CIF) ? 1:0;
+ hwcfg->ocfb = (cfg & GRTM_CFG_OCFB) ? 1:0;
+
+
+ cfg = READ_REG(pDev, &regs->dma_cfg);
+ hwcfg->blk_size = (cfg & GRTM_DMA_CFG_BLKSZ) >> GRTM_DMA_CFG_BLKSZ_BIT;
+ hwcfg->fifo_size= (cfg & GRTM_DMA_CFG_FIFOSZ) >> GRTM_DMA_CFG_FIFOSZ_BIT;
+}
+
+#warning Extra: Implement proper default calculation from hardware configuration
+static void grtm_hw_get_default_modes(struct grtm_ioc_config *cfg, struct grtm_ioc_hw *hwcfg)
+{
+ cfg->mode = GRTM_MODE_TM;
+ cfg->frame_length = 223;
+ cfg->limit = 0; /* Make driver auto configure it on START, user may override with non-zero value */
+ cfg->as_marker = 0x1ACFFC1D;
+
+ /* Physical */
+ cfg->phy_subrate = 1;
+ cfg->phy_symbolrate = 1;
+ cfg->phy_opts = 0;
+
+ /* Coding Layer */
+ cfg->code_rsdep = 1;
+ cfg->code_ce_rate = 0;
+ cfg->code_csel = 0;
+ cfg->code_opts = 0;
+
+ /* All Frame Generation */
+ cfg->all_izlen = 0;
+ cfg->all_opts = GRTM_IOC_ALL_FECF;
+
+ /* Master Channel Frame Generation */
+ if ( hwcfg->mcg ) {
+ cfg->mf_opts = GRTM_IOC_MF_MC;
+ } else {
+ cfg->mf_opts = 0;
+ }
+
+ /* Idle Frame Generation */
+ cfg->idle_scid = 0;
+ cfg->idle_vcid = 0;
+ if ( hwcfg->idle ) {
+ cfg->idle_opts = GRTM_IOC_IDLE_EN;
+ } else {
+ cfg->idle_opts = 0;
+ }
+
+ /* Interrupt options */
+ cfg->blocking = 0; /* non-blocking mode is default */
+ cfg->enable_cnt = 16; /* generate interrupt every 16 descriptor */
+ cfg->isr_desc_proc = 1; /* Enable interrupt handler from doing descriptor processing, this
+ * is not efficient since a semaphore must be used to lock the free_sent()
+ * and grtm_schedule_ready() functions, because they are locking when
+ * depending on the RMAP stack */
+ cfg->timeout = RTEMS_NO_TIMEOUT;
+
+}
+
+static int grtm_hw_set_config(struct grtm_priv *pDev, struct grtm_ioc_config *cfg, struct grtm_ioc_hw *hwcfg)
+{
+ struct grtm_regs *regs = pDev->regs;
+ unsigned int tmp;
+ unsigned int limit;
+
+ /* Check that the buffers that we have allocated allows the new frame length */
+ if ( cfg->frame_length > pDev->frame_length_max )
+ return -1;
+
+ if ( cfg->limit == 0 ) {
+ /* Calculate Limit */
+ if ( cfg->frame_length > hwcfg->blk_size ) {
+ limit = hwcfg->blk_size*2;
+ } else {
+ limit = cfg->frame_length;
+ }
+ } else {
+ /* Use user configured limit */
+ limit = cfg->limit;
+ }
+
+ /* Frame Length and Limit */
+ tmp = (((limit-1) << GRTM_DMA_LEN_LIM_BIT) & GRTM_DMA_LEN_LIM)|
+ (((cfg->frame_length-1) << GRTM_DMA_LEN_LEN_BIT) & GRTM_DMA_LEN_LEN);
+ WRITE_REG(pDev, &regs->dma_len, tmp);
+
+ /* Physical layer options */
+ tmp = (cfg->phy_opts & (GRTM_IOC_PHY_SCF|GRTM_IOC_PHY_SF)) |
+ (((cfg->phy_symbolrate-1)<<GRTM_PHY_SYM_BIT) & GRTM_PHY_SYM) | (((cfg->phy_subrate-1)<<GRTM_PHY_SUB_BIT) & GRTM_PHY_SUB);
+ WRITE_REG(pDev, &regs->phy, tmp);
+
+ /* Coding Sub-layer Options */
+ tmp = (cfg->code_opts & GRTM_IOC_CODE_ALL) | ((cfg->code_csel<<GRTM_CODE_CSEL_BIT) & GRTM_CODE_CSEL) |
+ (((cfg->code_rsdep-1)<<GRTM_CODE_RSDEP_BIT) & GRTM_CODE_RSDEP) | ((cfg->code_ce_rate<<GRTM_CODE_CERATE_BIT) & GRTM_CODE_CERATE);
+ WRITE_REG(pDev, &regs->code, tmp);
+
+ /* Attached synchronization marker register */
+ WRITE_REG(pDev, &regs->asmr, cfg->as_marker);
+
+ /* All Frames Generation */
+ tmp = ((cfg->all_opts & GRTM_IOC_ALL_ALL)<<14) |
+ ((cfg->all_izlen<<GRTM_ALL_IZLEN_BIT) & GRTM_ALL_IZLEN) |
+ ((cfg->mode<<GRTM_ALL_VER_BIT) & GRTM_ALL_VER);
+ WRITE_REG(pDev, &regs->all_frm, tmp);
+
+ /* Master Frame Generation */
+ WRITE_REG(pDev, &regs->mst_frm, cfg->mf_opts & GRTM_IOC_MF_ALL);
+
+ /* Idle frame Generation */
+ tmp = ((cfg->idle_opts & GRTM_IOC_IDLE_ALL) << 16) |
+ ((cfg->idle_vcid << GRTM_IDLE_VCID_BIT) & GRTM_IDLE_VCID) |
+ ((cfg->idle_scid << GRTM_IDLE_SCID_BIT) & GRTM_IDLE_SCID);
+ WRITE_REG(pDev, &regs->idle_frm, tmp);
+
+ return 0;
+}
+
+static int grtm_start(struct grtm_priv *pDev)
+{
+ struct grtm_regs *regs = pDev->regs;
+ int i;
+ struct grtm_ioc_config *cfg = &pDev->config;
+ volatile unsigned int *txrdy_reg;
+ unsigned int txrdy_mask;
+ unsigned int frame_buffer_ofs;
+
+ /* Clear Descriptors */
+ MEMSET(pDev, pDev->bds, 0, 0x400);
+
+ /* Clear stats */
+ memset(&pDev->stats,0,sizeof(struct grtm_ioc_stats));
+
+ /* Init Descriptor Ring */
+ memset(pDev->_ring, 0, sizeof(struct grtm_ring)*DESCRIPTOR_MAX);
+ frame_buffer_ofs = 0;
+ for(i=0; i<DESCRIPTOR_MAX-1; i++){
+ pDev->_ring[i].next = &pDev->_ring[i+1];
+ pDev->_ring[i].bd = &pDev->bds[i];
+ pDev->_ring[i].frm = NULL;
+ pDev->_ring[i].buf = &pDev->_frame_buffers[frame_buffer_ofs];
+ WRITE_REG(pDev, &pDev->_ring[i].bd->address, pDev->_ring[i].buf); /* INIT BD ADDRESS */
+ frame_buffer_ofs += pDev->frame_length_max;
+ }
+ pDev->_ring[DESCRIPTOR_MAX-1].next = &pDev->_ring[0];
+ pDev->_ring[DESCRIPTOR_MAX-1].bd = &pDev->bds[DESCRIPTOR_MAX-1];
+ pDev->_ring[DESCRIPTOR_MAX-1].frm = NULL;
+ pDev->_ring[DESCRIPTOR_MAX-1].buf = &pDev->_frame_buffers[frame_buffer_ofs];
+ WRITE_REG(pDev, &pDev->_ring[DESCRIPTOR_MAX-1].bd->address, pDev->_ring[DESCRIPTOR_MAX-1].buf); /* INIT BD ADDRESS */
+
+ pDev->ring = &pDev->_ring[0];
+ pDev->ring_end = &pDev->_ring[0];
+
+ /* Clear Scheduled, Ready and Sent list */
+ grtm_list_clr(&pDev->ready);
+ grtm_list_clr(&pDev->scheduled);
+ grtm_list_clr(&pDev->sent);
+
+ /* Software init */
+ /*pDev->handling_transmission = 0;*/
+
+ /* Reset the transmitter */
+ WRITE_REG(pDev, &regs->dma_ctrl, GRTM_DMA_CTRL_TXRST);
+ WRITE_REG(pDev, &regs->dma_ctrl, 0); /* Leave Reset */
+
+ /* Clear old interrupts */
+ WRITE_REG(pDev, &regs->dma_status, GRTM_DMA_STS_ALL);
+
+ /* Set Descriptor Pointer Base register to point to first descriptor */
+ WRITE_REG(pDev, &regs->dma_bd, pDev->bds);
+ /*drvmgr_mmap_translate(pDev->dev, 0, (void *)pDev->bds, (void **)&regs->dma_bd);*/
+ /*regs->dma_bd = (unsigned int)pDev->bds;*/
+
+ /* Set hardware options as defined by config */
+ if ( grtm_hw_set_config(pDev, cfg, &pDev->hw_avail) ) {
+ return RTEMS_IO_ERROR;
+ }
+
+ /* Enable TM Transmitter */
+ WRITE_REG(pDev, &regs->ctrl, GRTM_CTRL_EN);
+
+ /* Wait for TXRDY to be cleared */
+ i=1000;
+ while( i > 0 ) {
+ asm volatile ("nop"::);
+ i--;
+ }
+
+ /* Location of TXRDY Bit is different for different revisions */
+ if ( pDev->subrev == 0 ) {
+ txrdy_reg = &regs->dma_ctrl;
+ txrdy_mask = GRTM_REV0_DMA_CTRL_TXRDY;
+ } else {
+ txrdy_reg = &regs->dma_status;
+ txrdy_mask = GRTM_REV1_DMA_STS_TXRDY;
+ }
+
+ /* Check transmitter startup OK */
+ i=0;
+ while( !(READ_REG(pDev, txrdy_reg) & txrdy_mask) && (i<1000) ){
+ i++;
+ }
+ if ( !(READ_REG(pDev, txrdy_reg) & txrdy_mask) ){
+ /* Reset Failed */
+ DBG("GRTM: start: Reseting transmitter failed (%d)\n",i);
+ return RTEMS_IO_ERROR;
+ }
+ DBG("GRTM: reset time %d\n",i);
+
+ /* Everything is configured, the TM transmitter is started
+ * and idle frames has been sent.
+ */
+
+ /* Mark running before enabling the DMA transmitter */
+ pDev->running = 1;
+
+ /* Enable interrupts (Error and DMA TX) */
+ WRITE_REG(pDev, &regs->dma_ctrl, GRTM_DMA_CTRL_IE);
+
+ DBG("GRTM: STARTED\n");
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static void grtm_stop(struct grtm_priv *pDev)
+{
+ struct grtm_regs *regs = pDev->regs;
+
+ /* Disable the transmitter & Interrupts */
+ WRITE_REG(pDev, &regs->dma_ctrl, 0);
+
+ /* Clear any pending interrupt */
+ WRITE_REG(pDev, &regs->dma_status, GRTM_DMA_STS_ALL);
+
+ DBG("GRTM: STOPPED\n");
+
+ /* Flush semaphore in case a thread is stuck waiting for TX Interrupts */
+ rtems_semaphore_flush(pDev->sem_tx);
+}
+
+static rtems_device_driver grtm_open(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg)
+{
+ struct grtm_priv *pDev;
+ struct drvmgr_dev *dev;
+
+ FUNCDBG();
+
+ if ( drvmgr_get_dev(&grtm_rmap_drv_info.general, minor, &dev) ) {
+ DBG("Wrong minor %d\n", minor);
+ return RTEMS_INVALID_NUMBER;
+ }
+ pDev = (struct grtm_priv *)dev->priv;
+
+ /* Wait until we get semaphore */
+ if ( rtems_semaphore_obtain(grtm_dev_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT) != RTEMS_SUCCESSFUL ){
+ return RTEMS_INTERNAL_ERROR;
+ }
+
+ /* Is device in use? */
+ if ( pDev->open ){
+ rtems_semaphore_release(grtm_dev_sem);
+ return RTEMS_RESOURCE_IN_USE;
+ }
+
+ /* Mark device taken */
+ pDev->open = 1;
+
+ rtems_semaphore_release(grtm_dev_sem);
+
+ DBG("grtm_open: OPENED minor %d (pDev: 0x%x)\n",pDev->minor,(unsigned int)pDev);
+
+ /* Set defaults */
+ pDev->config.timeout = RTEMS_NO_TIMEOUT; /* no timeout (wait forever) */
+ pDev->config.blocking = 0; /* polling mode */
+
+ pDev->running = 0; /* not in running mode yet */
+
+ memset(&pDev->config,0,sizeof(pDev->config));
+
+ /* The core has been reset when we execute here, so it is possible
+ * to read out what HW is implemented from core.
+ */
+ grtm_hw_get_implementation(pDev, &pDev->hw_avail);
+
+ /* Get default modes */
+ grtm_hw_get_default_modes(&pDev->config,&pDev->hw_avail);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver grtm_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ struct grtm_priv *pDev;
+ struct drvmgr_dev *dev;
+
+ FUNCDBG();
+
+ if ( drvmgr_get_dev(&grtm_rmap_drv_info.general, minor, &dev) ) {
+ return RTEMS_INVALID_NUMBER;
+ }
+ pDev = (struct grtm_priv *)dev->priv;
+
+ if ( pDev->running ){
+ grtm_stop(pDev);
+ pDev->running = 0;
+ }
+
+ /* Reset core */
+ grtm_hw_reset(pDev);
+
+ /* Clear descriptor area just for sure */
+ MEMSET(pDev, pDev->bds, 0, 0x400);
+
+ /* Mark not open */
+ pDev->open = 0;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver grtm_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ FUNCDBG();
+ return RTEMS_NOT_IMPLEMENTED;
+}
+
+static rtems_device_driver grtm_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ FUNCDBG();
+ return RTEMS_NOT_IMPLEMENTED;
+}
+
+/* Scans the desciptor table for scheduled frames that has been sent,
+ * and moves these frames from the head of the scheduled queue to the
+ * tail of the sent queue.
+ *
+ * Also, for all frames the status is updated.
+ *
+ * Return Value
+ * Number of frames freed.
+ */
+static int grtm_free_sent(struct grtm_priv *pDev)
+{
+ struct grtm_ring *curr;
+ struct grtm_frame *last_frm, *first_frm;
+ int freed_frame_cnt=0;
+ unsigned int ctrl;
+
+ curr = pDev->ring_end;
+
+ /* Step into TX ring to find sent frames */
+ if ( !curr->frm ){
+ /* No scheduled frames, abort */
+ return 0;
+ }
+
+ /* There has been messages scheduled ==> scheduled messages may have been
+ * transmitted and needs to be collected.
+ */
+
+ first_frm = curr->frm;
+
+ /* Loop until first enabled unsent frame is found.
+ * A unused descriptor is indicated by an unassigned frm field
+ */
+ while ( curr->frm && !((ctrl=READ_REG(pDev, &curr->bd->ctrl)) & GRTM_BD_EN) ){
+ /* Handle one sent Frame */
+
+ /* Remember last handled frame so that insertion/removal from
+ * frames lists go fast.
+ */
+ last_frm = curr->frm;
+
+ /* 1. Set flags to indicate error(s) and other information */
+ last_frm->flags |= GRTM_FLAGS_SENT; /* Mark sent */
+
+ /* Update Stats */
+ pDev->stats.frames_sent++;
+
+ /* Did packet encounter link error? */
+ if ( ctrl & GRTM_BD_UE ) {
+ pDev->stats.err_underrun++;
+ last_frm->flags |= GRRM_FLAGS_ERR;
+ }
+
+ curr->frm = NULL; /* Mark unused */
+
+ /* Increment */
+ curr = curr->next;
+ freed_frame_cnt++;
+ }
+
+ /* 1. Remove all handled frames from scheduled queue
+ * 2. Put all handled frames into sent queue
+ */
+ if ( freed_frame_cnt > 0 ){
+
+ /* Save TX ring posistion */
+ pDev->ring_end = curr;
+
+ /* Remove all sent frames from scheduled list */
+ if ( pDev->scheduled.tail == last_frm ){
+ /* All scheduled frames sent... */
+ pDev->scheduled.head = NULL;
+ pDev->scheduled.tail = NULL;
+ }else{
+ pDev->scheduled.head = last_frm->next;
+ }
+ last_frm->next = NULL;
+
+ /* Put all sent frames into "Sent queue" for user to
+ * collect, later on.
+ */
+ if ( !pDev->sent.head ){
+ /* Sent queue empty */
+ pDev->sent.head = first_frm;
+ pDev->sent.tail = last_frm;
+ }else{
+ pDev->sent.tail->next = first_frm;
+ pDev->sent.tail = last_frm;
+ }
+ }
+ return freed_frame_cnt;
+}
+
+
+/* Moves as many frames in the ready queue (as there are free descriptors for)
+ * to the scheduled queue. The free descriptors are then assigned one frame
+ * each and enabled for transmission.
+ *
+ * Return Value
+ * Returns number of frames moved from ready to scheduled queue
+ */
+static int grtm_schedule_ready(struct grtm_priv *pDev, int ints_off)
+{
+ int cnt;
+ unsigned int ctrl, dmactrl, oldLevel;
+ struct grtm_ring *curr_bd;
+ struct grtm_frame *curr_frm, *last_frm;
+
+ if ( !pDev->ready.head ){
+ return 0;
+ }
+
+ cnt=0;
+ curr_frm = pDev->ready.head;
+ curr_bd = pDev->ring;
+ while( !curr_bd->frm ){
+ /* Assign frame to descriptor */
+ curr_bd->frm = curr_frm;
+
+#warning REMOVE TRANSLATE FLAG?
+ /* Is frame located at SpaceWire target or at the local RAM? */
+ if ( curr_frm->flags & GRTM_FLAGS_COPY_DATA ) {
+ /* Transfer frame to the target via SpW, we make sure that is aligned to a 4byte
+ * boundary, this is good practice and does not cost anything.
+ */
+ TRANSFER_FRM(pDev, curr_bd->buf, curr_frm->payload, (pDev->config.frame_length + 3) & ~0x3);
+
+ /* That the BD->address is not constant */
+ WRITE_REG(pDev, &curr_bd->bd->address, curr_bd->buf);
+ } else {
+ /* The Frame has already been copied to the SpaceWire target, we simply
+ * write the address of the frame.
+ */
+ WRITE_REG(pDev, &curr_bd->bd->address, curr_frm->payload);
+ }
+#if 0
+ /* Prepare descriptor address. Three cases:
+ * - GRTM core on same bus as CPU ==> no translation (Address used by CPU = address used by GRTM)
+ * - GRTM core on remote bus, and payload address given as used by CPU ==> Translation needed
+ * - GRTM core on remote bus, and payload address given as used by GRTM ==> no translation [ USER does custom translation]
+ */
+ if ( curr_frm->flags & (GRTM_FLAGS_TRANSLATE|GRTM_FLAGS_TRANSLATE_AND_REMEMBER) ) {
+ /* Do translation */
+ drvmgr_mmap_translate(pDev->dev, 0, (void *)curr_frm->payload, (void **)&curr_bd->bd->address);
+ if ( curr_frm->flags & GRTM_FLAGS_TRANSLATE_AND_REMEMBER ) {
+ if ( curr_frm->payload != curr_bd->bd->address ) {
+ /* Translation needed */
+ curr_frm->flags &= ~GRTM_FLAGS_TRANSLATE_AND_REMEMBER;
+ curr_frm->flags |= GRTM_FLAGS_TRANSLATE;
+ } else {
+ /* No Trnaslation needed */
+ curr_frm->flags &= ~(GRTM_FLAGS_TRANSLATE|GRTM_FLAGS_TRANSLATE_AND_REMEMBER);
+ }
+ }
+ } else {
+ /* Custom translation or no translation needed */
+ curr_bd->bd->address = (unsigned int)curr_frm->payload;
+ }
+#endif
+
+ ctrl = GRTM_BD_EN;
+ if ( curr_bd->next == pDev->_ring ){
+ ctrl |= GRTM_BD_WR; /* Wrap around */
+ }
+ /* Apply user options/flags */
+ ctrl |= (curr_frm->flags & GRTM_FLAGS_MASK);
+
+ /* Is this Frame going to be an interrupt Frame? */
+ if ( (--pDev->enable_cnt_curr) <= 0 ){
+ if ( pDev->config.enable_cnt == 0 ){
+ pDev->enable_cnt_curr = 0x3fffffff;
+ }else{
+ pDev->enable_cnt_curr = pDev->config.enable_cnt;
+ ctrl |= GRTM_BD_IE;
+ }
+ }
+
+ /* Enable descriptor */
+ WRITE_REG(pDev, &curr_bd->bd->ctrl, ctrl);
+
+ last_frm = curr_frm;
+ curr_bd = curr_bd->next;
+ cnt++;
+
+ /* Get Next Frame from Ready Queue */
+ if ( curr_frm == pDev->ready.tail ){
+ /* Handled all in ready queue. */
+ curr_frm = NULL;
+ break;
+ }
+ curr_frm = curr_frm->next;
+ }
+
+ /* Has frames have been scheduled? */
+ if ( cnt > 0 ){
+ /* Make last frame mark end of chain, probably pointless... */
+ last_frm->next = NULL;
+
+ /* Insert scheduled packets into scheduled queue */
+ if ( !pDev->scheduled.head ){
+ /* empty scheduled queue */
+ pDev->scheduled.head = pDev->ready.head;
+ pDev->scheduled.tail = last_frm;
+ }else{
+ pDev->scheduled.tail->next = pDev->ready.head;
+ pDev->scheduled.tail = last_frm;
+ }
+
+ /* Remove scheduled packets from ready queue */
+ pDev->ready.head = curr_frm;
+ if ( !curr_frm ){
+ pDev->ready.tail = NULL;
+ }
+
+ /* Update TX ring posistion */
+ pDev->ring = curr_bd;
+ if ( !ints_off ) {
+ IRQ_GLOBAL_DISABLE(oldLevel);
+ }
+
+ /* Make hardware aware of the newly enabled descriptors */
+ dmactrl = READ_REG(pDev, &pDev->regs->dma_ctrl);
+ dmactrl &= ~(GRTM_DMA_CTRL_TXRST | GRTM_DMA_CTRL_RST);
+ dmactrl |= GRTM_DMA_CTRL_EN;
+ WRITE_REG(pDev, &pDev->regs->dma_ctrl, dmactrl);
+
+ if ( !ints_off ) {
+ IRQ_GLOBAL_ENABLE(oldLevel);
+ }
+ }
+ return cnt;
+}
+
+
+static rtems_device_driver grtm_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ struct grtm_priv *pDev;
+ struct drvmgr_dev *dev;
+ rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *)arg;
+ unsigned int *data = ioarg->buffer;
+ int status;
+ struct grtm_ioc_config *cfg;
+ struct grtm_ioc_hw_status *hwregs;
+ IRQ_GLOBAL_PREPARE(oldLevel);
+ struct grtm_list *chain;
+ struct grtm_frame *curr;
+ struct grtm_ioc_hw *hwimpl;
+ struct grtm_ioc_stats *stats;
+ int num,ret;
+
+ FUNCDBG();
+
+ if ( drvmgr_get_dev(&grtm_rmap_drv_info.general, minor, &dev) ) {
+ return RTEMS_INVALID_NUMBER;
+ }
+ pDev = (struct grtm_priv *)dev->priv;
+
+ if (!ioarg)
+ return RTEMS_INVALID_NAME;
+
+ ioarg->ioctl_return = 0;
+ switch(ioarg->command) {
+ case GRTM_IOC_START:
+ if ( pDev->running ) {
+ return RTEMS_RESOURCE_IN_USE; /* EBUSY */
+ }
+ if ( (status=grtm_start(pDev)) != RTEMS_SUCCESSFUL ){
+ return status;
+ }
+ /* Register ISR & Enable interrupt */
+ drvmgr_interrupt_register(dev, 0, "grtm_rmap", grtm_interrupt, pDev);
+
+ /* Read and write are now open... */
+ break;
+
+ case GRTM_IOC_STOP:
+ if ( !pDev->running ) {
+ return RTEMS_RESOURCE_IN_USE;
+ }
+
+ /* Disable interrupts */
+ drvmgr_interrupt_unregister(dev, 0, grtm_interrupt, pDev);
+ grtm_stop(pDev);
+ pDev->running = 0;
+ break;
+
+ case GRTM_IOC_ISSTARTED:
+ if ( !pDev->running ) {
+ return RTEMS_RESOURCE_IN_USE;
+ }
+ break;
+
+ case GRTM_IOC_SET_BLOCKING_MODE:
+ if ( (unsigned int)data > GRTM_BLKMODE_BLK ) {
+ return RTEMS_INVALID_NAME;
+ }
+ DBG("GRTM: Set blocking mode: %d\n",(unsigned int)data);
+ pDev->config.blocking = (unsigned int)data;
+ break;
+
+ case GRTM_IOC_SET_TIMEOUT:
+ DBG("GRTM: Timeout: %d\n",(unsigned int)data);
+ pDev->config.timeout = (rtems_interval)data;
+ break;
+
+ case GRTM_IOC_SET_CONFIG:
+ cfg = (struct grtm_ioc_config *)data;
+ if ( !cfg ) {
+ return RTEMS_INVALID_NAME;
+ }
+
+ if ( pDev->running ) {
+ return RTEMS_RESOURCE_IN_USE;
+ }
+
+ pDev->config = *cfg;
+ break;
+
+ case GRTM_IOC_GET_STATS:
+ stats = (struct grtm_ioc_stats *)data;
+ if ( !stats ) {
+ return RTEMS_INVALID_NAME;
+ }
+ memcpy(stats,&pDev->stats,sizeof(struct grtm_ioc_stats));
+ break;
+
+ case GRTM_IOC_CLR_STATS:
+ memset(&pDev->stats,0,sizeof(struct grtm_ioc_stats));
+ break;
+
+ case GRTM_IOC_GET_CONFIG:
+ cfg = (struct grtm_ioc_config *)data;
+ if ( !cfg ) {
+ return RTEMS_INVALID_NAME;
+ }
+
+ *cfg = pDev->config;
+ break;
+
+ case GRTM_IOC_GET_OCFREG:
+ if ( !pDev->hw_avail.ocf ) {
+ /* Hardware does not implement the OCF register */
+ return RTEMS_NOT_DEFINED;
+ }
+ if ( !data ) {
+ return RTEMS_INVALID_NAME;
+ }
+#warning THIS IOCTL COPY THE REMOTE ADDRESS
+ *(unsigned int **)data = (unsigned int *)&pDev->regs->ocf;
+ break;
+
+ case GRTM_IOC_GET_HW_IMPL:
+ hwimpl = (struct grtm_ioc_hw *)data;
+ if ( !hwimpl ) {
+ return RTEMS_INVALID_NAME;
+ }
+ *hwimpl = pDev->hw_avail;
+ break;
+
+ case GRTM_IOC_GET_HW_STATUS:
+ hwregs = (struct grtm_ioc_hw_status *)data;
+ if ( !hwregs ) {
+ return RTEMS_INVALID_NAME;
+ }
+ /* We disable interrupt in order to get a snapshot of the registers */
+ IRQ_GLOBAL_DISABLE(oldLevel);
+#warning IMPLEMENT HWREGS HERE
+ IRQ_GLOBAL_ENABLE(oldLevel);
+ break;
+
+ /* Put a chain of frames at the back of the "Ready frames" queue. This
+ * triggers the driver to put frames from the Ready queue into unused
+ * available descriptors. (Ready -> Scheduled)
+ */
+
+ case GRTM_IOC_SEND:
+ if ( !pDev->running ){
+ return RTEMS_RESOURCE_IN_USE;
+ }
+ num=0;
+
+ /* Get pointer to frame chain wished be sent */
+ chain = (struct grtm_list *)ioarg->buffer;
+ if ( !chain ){
+ /* No new frames to send ==> just trigger hardware
+ * to send previously made ready frames to be sent.
+ */
+ rtems_semaphore_obtain(pDev->handling_transmission, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+ goto trigger_transmission;
+ }
+ if ( !chain->tail || !chain->head ){
+ return RTEMS_INVALID_NAME;
+ }
+
+ DBG("GRTM_SEND: head: 0x%x, tail: 0x%x\n",chain->head,chain->tail);
+
+ /* Mark ready frames unsent by clearing GRTM_FLAGS_SENT of all frames */
+
+ curr = chain->head;
+ while(curr != chain->tail){
+ curr->flags = curr->flags & ~(GRTM_FLAGS_SENT|GRRM_FLAGS_ERR);
+ curr = curr->next;
+ num++;
+ }
+ curr->flags = curr->flags & ~(GRTM_FLAGS_SENT|GRRM_FLAGS_ERR);
+ num++;
+
+ rtems_semaphore_obtain(pDev->handling_transmission, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+ /* 1. Put frames into ready queue
+ * (New Frames->READY)
+ */
+ if ( pDev->ready.head ){
+ /* Frames already on ready queue (no free descriptors previously) ==>
+ * Put frames at end of ready queue
+ */
+ pDev->ready.tail->next = chain->head;
+ pDev->ready.tail = chain->tail;
+ chain->tail->next = NULL;
+ }else{
+ /* All frames is put into the ready queue for later processing */
+ pDev->ready.head = chain->head;
+ pDev->ready.tail = chain->tail;
+ chain->tail->next = NULL;
+ }
+ pDev->ready_cnt += num; /* Added 'num' frames to ready queue */
+trigger_transmission:
+ /* 2. Free used descriptors and put the sent frame into the "Sent queue"
+ * (SCHEDULED->SENT)
+ */
+ num = grtm_free_sent(pDev);
+ pDev->scheduled_cnt -= num;
+ pDev->sent_cnt += num;
+
+ /* 3. Use all available free descriptors there are frames for
+ * in the ready queue.
+ * (READY->SCHEDULED)
+ */
+ num = grtm_schedule_ready(pDev,0);
+ pDev->ready_cnt -= num;
+ pDev->scheduled_cnt += num;
+
+ rtems_semaphore_release(pDev->handling_transmission);
+ break;
+
+ /* Take all available sent frames from the "Sent frames" queue.
+ * If no frames has been sent, the thread may get blocked if in blocking
+ * mode. The blocking mode is not available if driver is not in running mode.
+ *
+ * Note this ioctl may return success even if the driver is not in STARTED mode.
+ * This is because in case of a error (link error of similar) and the driver switch
+ * from START to STOP mode we must still be able to get our frames back.
+ *
+ * Note in case the driver fails to send a frame for some reason (link error),
+ * the sent flag is set to 0 indicating a failure.
+ *
+ */
+ case GRTM_IOC_RECLAIM:
+ /* Get pointer to were to place reaped chain */
+ chain = (struct grtm_list *)ioarg->buffer;
+ if ( !chain ){
+ return RTEMS_INVALID_NAME;
+ }
+
+ /* Lock out interrupt handler */
+ rtems_semaphore_obtain(pDev->handling_transmission, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+
+ do {
+ /* Move sent frames from descriptors to Sent queue. This makes more
+ * descriptors (BDs) available.
+ */
+ num = grtm_free_sent(pDev);
+ pDev->scheduled_cnt -= num;
+ pDev->sent_cnt += num;
+
+
+ if ( pDev->running ){
+ /* Fill descriptors with as many frames from the ready list
+ * as possible.
+ */
+ num = grtm_schedule_ready(pDev,0);
+ pDev->ready_cnt -= num;
+ pDev->scheduled_cnt += num;
+ }
+
+ /* Are there any frames on the sent queue waiting to be
+ * reclaimed?
+ */
+
+ if ( !pDev->sent.head ){
+ /* No frames to reclaim - no frame in sent queue.
+ * Instead we block thread until frames have been sent
+ * if in blocking mode.
+ */
+ if ( pDev->running && pDev->config.blocking ){
+ ret = rtems_semaphore_obtain(pDev->sem_tx,RTEMS_WAIT,pDev->config.timeout);
+ if ( ret == RTEMS_TIMEOUT ) {
+ /* do not lock out interrupt handler any more */
+ rtems_semaphore_release(pDev->handling_transmission);
+ return RTEMS_TIMEOUT;
+ } else if ( ret == RTEMS_SUCCESSFUL ) {
+ /* There might be frames available, go check */
+ continue;
+ } else {
+ /* any error (driver closed, internal error etc.) */
+ rtems_semaphore_release(pDev->handling_transmission);
+ return RTEMS_UNSATISFIED;
+ }
+
+ }else{
+ /* non-blocking mode, we quit */
+ chain->head = NULL;
+ chain->tail = NULL;
+ /* do not lock out interrupt handler any more */
+ rtems_semaphore_release(pDev->handling_transmission);
+ return RTEMS_TIMEOUT;
+ }
+ }else{
+ /* Take all sent framess from sent queue to userspace queue */
+ chain->head = pDev->sent.head;
+ chain->tail = pDev->sent.tail;
+ chain->tail->next = NULL; /* Just for sure */
+
+ /* Mark no Sent */
+ grtm_list_clr(&pDev->sent);
+
+ DBG("TX_RECLAIM: head: 0x%x, tail: 0x%x\n",chain->head,chain->tail);
+ break;
+ }
+
+ }while(1);
+
+ /* do not lock out interrupt handler any more */
+ rtems_semaphore_release(pDev->handling_transmission);
+ break;
+
+ default:
+ return RTEMS_NOT_DEFINED;
+ }
+ return RTEMS_SUCCESSFUL;
+}
+
+static void grtm_interrupt(void *arg)
+{
+ struct grtm_priv *pDev = arg;
+ struct grtm_regs *regs = pDev->regs;
+ unsigned int status;
+ int num;
+
+ /* Clear interrupt by reading it */
+ status = READ_REG(pDev, &regs->dma_status);
+
+ /* Spurious Interrupt? */
+ if ( !pDev->running )
+ return;
+
+ if ( status )
+ WRITE_REG(pDev, &regs->dma_status, status);
+
+ if ( status & GRTM_DMA_STS_TFF ){
+ pDev->stats.err_transfer_frame++;
+ }
+
+ if ( status & GRTM_DMA_STS_TA ){
+ pDev->stats.err_ahb++;
+ }
+
+ if ( status & GRTM_DMA_STS_TE ){
+ pDev->stats.err_tx++;
+ }
+
+ if ( status & GRTM_DMA_STS_TI ){
+
+ if ( pDev->config.isr_desc_proc &&
+ (rtems_semaphore_obtain(pDev->handling_transmission, RTEMS_NO_WAIT, 0) == RTEMS_SUCCESSFUL) ) {
+ /* Free used descriptors and put the sent frame into the "Sent queue"
+ * (SCHEDULED->SENT)
+ */
+ num = grtm_free_sent(pDev);
+ pDev->scheduled_cnt -= num;
+ pDev->sent_cnt += num;
+
+ /* Use all available free descriptors there are frames for
+ * in the ready queue.
+ * (READY->SCHEDULED)
+ */
+ num = grtm_schedule_ready(pDev,1);
+ pDev->ready_cnt -= num;
+ pDev->scheduled_cnt += num;
+
+ rtems_semaphore_release(pDev->handling_transmission);
+
+#if 0
+ if ( (pDev->config.blocking==GRTM_BLKMODE_COMPLETE) && pDev->timeout ){
+ /* Signal to thread only if enough data is available */
+ if ( pDev->wait_for_frames > grtm_data_avail(pDev) ){
+ /* Not enough data available */
+ goto procceed_processing_interrupts;
+ }
+
+ /* Enough number of frames has been transmitted which means that
+ * the waiting thread should be woken up.
+ */
+ rtems_semaphore_release(pDev->sem_tx);
+ }
+#endif
+ }
+
+ if ( pDev->config.blocking == GRTM_BLKMODE_BLK ) {
+ /* Blocking mode */
+
+#if 0
+ /* Disable further Interrupts until handled by waiting task. */
+ regs->dma_ctrl = READ_REG(pDev, &regs->dma_ctrl) & ~GRTM_DMA_CTRL_IE;
+#endif
+
+ /* Signal Semaphore to wake waiting thread in ioctl(SEND|RECLAIM) */
+ rtems_semaphore_release(pDev->sem_tx);
+ }
+
+ }
+#if 0
+procceed_processing_interrupts:
+ ;
+#endif
+}
+
+static rtems_device_driver grtm_initialize(
+ rtems_device_major_number major,
+ rtems_device_minor_number unused,
+ void *arg
+ )
+{
+ /* Device Semaphore created with count = 1 */
+ if ( rtems_semaphore_create(rtems_build_name('G', 'R', 'T', 'M'),
+ 1,
+ RTEMS_FIFO|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &grtm_dev_sem) != RTEMS_SUCCESSFUL ) {
+ return RTEMS_INTERNAL_ERROR;
+ }
+
+ return RTEMS_SUCCESSFUL;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/uart/apbuart.c b/c/src/lib/libbsp/sparc/shared/uart/apbuart.c
index 58d0eab4dc..403c81a6bd 100644
--- a/c/src/lib/libbsp/sparc/shared/uart/apbuart.c
+++ b/c/src/lib/libbsp/sparc/shared/uart/apbuart.c
@@ -1,485 +1,413 @@
-/*
- * This file contains the driver for the APBUART serial port.
+/* Unused driver at the moment since we can not have two drivers for
+ * the same hardware...
+ */
+#if 0
+
+/* This file contains the driver for the GRLIB APBUART serial port.
* No console driver, only char driver.
*
- * COPYRIGHT (c) 2007.
- * Gaisler Research.
+ * COPYRIGHT (c) 2008.
+ * Aeroflex Gaisler.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
*
- *
+ * 2008-12-03, Daniel Hellstrom <daniel@gaisler.com>
+ * Converted to support driver manager.
+ *
* 2007-07-11, Daniel Hellstrom <daniel@gaisler.com>
* Added ioctl command APBUART_CLR_STATS
*/
+/******************* Driver manager interface ***********************/
#include <bsp.h>
#include <rtems/libio.h>
#include <stdlib.h>
#include <assert.h>
#include <rtems/bspIo.h>
#include <string.h>
+#include <stdio.h>
-#include <ambapp.h>
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
#include <apbuart.h>
+#include <ambapp.h>
+#include <grlib.h>
-#ifndef DEFAULT_TXBUF_SIZE
- #define DEFAULT_TXBUF_SIZE 32
-#endif
-#ifndef DEFAULT_RXBUF_SIZE
- #define DEFAULT_RXBUF_SIZE 32
-#endif
-
-#ifndef APBUART_PREFIX
- #define APBUART_PREFIX(name) apbuart##name
-#endif
-
-#if !defined(APBUART_DEVNAME) || !defined(APBUART_DEVNAME_NO)
- #undef APBUART_DEVNAME
- #undef APBUART_DEVNAME_NO
- #define APBUART_DEVNAME "/dev/apbuart0"
- #define APBUART_DEVNAME_NO(devstr,no) ((devstr)[12]='0'+(no))
-#endif
+/*#define DEBUG 1 */
-#ifndef APBUART_REG_INT
- #define APBUART_REG_INT(handler,irq,arg) set_vector(handler,irq+0x10,1)
- #undef APBUART_DEFINE_INTHANDLER
- #define APBUART_DEFINE_INTHANDLER
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
#endif
-/* Default to 40MHz system clock */
-/*#ifndef SYS_FREQ_HZ
- #define SYS_FREQ_HZ 40000000
-#endif*/
-
typedef struct {
- int size;
- unsigned char *buf,
- *tail,
- *head,
- *max;
- int full; /* no more place in fifo */
+ int size;
+ unsigned char *buf,
+ *tail,
+ *head,
+ *max;
+ int full; /* no more place in fifo */
} apbuart_fifo;
-static apbuart_fifo *apbuart_fifo_create(int size);
-static void apbuart_fifo_free(apbuart_fifo *fifo);
-static inline int apbuart_fifo_isFull(apbuart_fifo *fifo);
-static inline int apbuart_fifo_isEmpty(apbuart_fifo *fifo);
-static int apbuart_fifo_put(apbuart_fifo *fifo, unsigned char c);
-static int apbuart_fifo_get(apbuart_fifo *fifo, unsigned char *c);
-static int inline apbuart_fifo_peek(apbuart_fifo *fifo, unsigned char **c);
-static void inline apbuart_fifo_skip(apbuart_fifo *fifo);
-
-static rtems_device_driver apbuart_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
-static rtems_device_driver apbuart_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
-static rtems_device_driver apbuart_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
-static rtems_device_driver apbuart_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
-static rtems_device_driver apbuart_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
-static rtems_device_driver apbuart_control(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
-
-typedef struct {
- ambapp_apb_uart *regs;
- int irq;
- int minor;
- int scaler;
- unsigned int baud;
-
- int txblk; /* Make write block until at least 1 char has
- * been put into software send fifo
- */
- int tx_flush; /* Set this to block until all data has
- * placed into the hardware send fifo
- */
- int rxblk; /* Make read block until at least 1 char has
- * been received (or taken from software fifo).
- */
- int started; /* Set to 1 when in running mode */
-
- int ascii_mode; /* Set to 1 to make \n be printed as \r\n */
+struct apbuart_priv {
+ struct drvmgr_dev *dev;
+ struct apbuart_regs *regs;
+ int irq;
+ int minor;
+ int scaler;
+ unsigned int baud;
+ unsigned int freq_hz; /* UART Core Frequency */
+
+ int txblk; /* Make write block until at least 1 char has
+ * been put into software send fifo
+ */
+ int tx_flush; /* Set this to block until all data has
+ * placed into the hardware send fifo
+ */
+ int rxblk; /* Make read block until at least 1 char has
+ * been received (or taken from software fifo).
+ */
+ int started; /* Set to 1 when in running mode */
+
+ int ascii_mode; /* Set to 1 to make \n be printed as \r\n */
/* TX/RX software FIFO Buffers */
- apbuart_fifo *txfifo;
- apbuart_fifo *rxfifo;
+ apbuart_fifo *txfifo;
+ apbuart_fifo *rxfifo;
- apbuart_stats stats;
+ apbuart_stats stats;
- rtems_id dev_sem;
- rtems_id rx_sem;
- rtems_id tx_sem;
-} apbuart_priv;
+ rtems_id dev_sem;
+ rtems_id rx_sem;
+ rtems_id tx_sem;
+};
-static int dev_cnt;
-static apbuart_priv *apbuarts;
-static unsigned int sys_freq_hz;
+/* Driver prototypes */
+int apbuart_register_io(rtems_device_major_number *m);
+int apbuart_device_init(struct apbuart_priv *priv);
-#define APBUART_DRIVER_TABLE_ENTRY { apbuart_initialize, apbuart_open, apbuart_close, apbuart_read, apbuart_write, apbuart_control }
-
-static rtems_driver_address_table apbuart_driver = APBUART_DRIVER_TABLE_ENTRY;
-static amba_confarea_type *amba_bus;
-
-static void apbuart_interrupt(apbuart_priv *uart);
-#ifdef APBUART_DEFINE_INTHANDLER
-static void apbuart_interrupt_handler(rtems_vector_number v);
-#endif
-static void apbuart_hw_close(apbuart_priv *uart);
-static void apbuart_hw_open(apbuart_priv *uart);
-
-/* Uncomment for debug output */
-/* #define DEBUG 1
- #define FUNCDEBUG 1 */
-
-#ifdef DEBUG
-#define DBG(x...) printk(x)
-#else
-#define DBG(x...)
-#endif
-#ifdef FUNCDEBUG
-#define FUNCDBG(x...) printk(x)
-#else
-#define FUNCDBG(x...)
-#endif
+int apbuart_init2(struct drvmgr_dev *dev);
+int apbuart_init3(struct drvmgr_dev *dev);
-#ifndef READ_REG
- #define READ_REG(address) _APBUART_READ_REG((unsigned int)(address))
- static __inline__ unsigned int _APBUART_READ_REG(unsigned int addr) {
- unsigned int tmp;
- asm(" lda [%1]1, %0 "
- : "=r"(tmp)
- : "r"(addr)
- );
- return tmp;
- }
-#endif
+struct drvmgr_drv_ops apbuart_ops =
+{
+ .init = {NULL, apbuart_init2, apbuart_init3, NULL},
+ .remove = NULL,
+ .info = NULL
+};
-#if 0
-static int apbuart_outbyte_try(ambapp_apb_uart *regs, unsigned char ch)
+struct amba_dev_id apbuart_ids[] =
{
- if ( (READ_REG(&regs->status) & LEON_REG_UART_STATUS_THE) == 0 )
- return -1; /* Failed */
+ {VENDOR_GAISLER, GAISLER_APBUART},
+ {0, 0} /* Mark end of table */
+};
- /* There is room in fifo, put ch in it */
- regs->data = (unsigned int) ch;
- return 0;
+struct amba_drv_info apbuart_drv_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_AMBAPP_GAISLER_APBUART_ID, /* Driver ID */
+ "APBUART_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */
+ &apbuart_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ 0,
+ },
+ &apbuart_ids[0]
+};
+
+static int apbuart_driver_io_registered = 0;
+static rtems_device_major_number apbuart_driver_io_major = 0;
+
+void apbuart_register_drv (void)
+{
+ DBG("Registering APBUART driver\n");
+ drvmgr_drv_register(&apbuart_drv_info.general);
}
-
-static int apbuart_inbyte_try(ambapp_apb_uart *regs)
+int apbuart_init2(struct drvmgr_dev *dev)
{
- unsigned int status;
- /* Clear errors if any */
- if ( (status=READ_REG(&regs->status)) & LEON_REG_UART_STATUS_ERR) {
- regs->status = status & ~LEON_REG_UART_STATUS_ERR;
+ struct apbuart_priv *priv;
+
+ DBG("APBUART[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
+ if ( strcmp(dev->parent->dev->drv->name, "AMBAPP_GRLIB_DRV") == 0 ) {
+ /* Let standard console driver take care of APBUART
+ * for CPU-local APBUART cores.
+ */
+ dev->priv = NULL;
+ DBG("-- SKIPPING APBUART 1 --\n");
+ return DRVMGR_FAIL;
}
+ priv = dev->priv = malloc(sizeof(struct apbuart_priv));
+ if ( !priv )
+ return DRVMGR_NOMEM;
+ memset(priv, 0, sizeof(*priv));
+ priv->dev = dev;
- /* Is Data available? */
- if ( (READ_REG(&regs->status) & LEON_REG_UART_STATUS_DR) == 0 )
- return -1; /* No data avail */
+ /* This core will not find other cores, so we wait for init2() */
- /* Return Data */
- return (int)READ_REG(&regs->data);
+ return DRVMGR_OK;
}
-static int apbuart_write_support(apbuart_priv *uart, const char *buf, int len)
+int apbuart_init3(struct drvmgr_dev *dev)
{
- int nwrite = 0;
+ struct apbuart_priv *priv;
+ char prefix[32];
+ char devName[32];
+ rtems_status_code status;
- while (nwrite < len) {
- if ( apbuart_outbyte_try(minor, *buf++) ){
- /* TX Fifo full */
+ priv = dev->priv;
- }
- nwrite++;
- }
- return nwrite;
-}
-#endif
+ /* Do initialization */
-static void apbuart_hw_open(apbuart_priv *uart){
- unsigned int scaler;
+ if ( apbuart_driver_io_registered == 0) {
+ /* Register the I/O driver only once for all cores */
+ if ( apbuart_register_io(&apbuart_driver_io_major) ) {
+ /* Failed to register I/O driver */
+ dev->priv = NULL;
+ return DRVMGR_FAIL;
+ }
- /* Calculate Baudrate */
- if ( uart->scaler > 0 ) {
- scaler = uart->scaler;
- }else{
- scaler = (((sys_freq_hz*10)/(uart->baud*8))-5)/10;
+ apbuart_driver_io_registered = 1;
}
- /* Set new baud rate */
- uart->regs->scaler = scaler;
+ /* I/O system registered and initialized
+ * Now we take care of device initialization.
+ */
- /* Enable receiver & Transmitter */
- uart->regs->ctrl = APBUART_CTRL_RE | APBUART_CTRL_RF | APBUART_CTRL_RI | APBUART_CTRL_TI;
-}
+ /* Get frequency */
+ if ( drvmgr_freq_get(dev, DEV_APB_SLV, &priv->freq_hz) ) {
+ return DRVMGR_FAIL;
+ }
-static void apbuart_hw_close(apbuart_priv *uart){
- /* disable receiver & transmitter & all IRQs */
- uart->regs->ctrl = 0;
-}
+ if ( apbuart_device_init(priv) ) {
+ return DRVMGR_FAIL;
+ }
-#ifdef APBUART_DEFINE_INTHANDLER
-/* interrupt handler */
-static void apbuart_interrupt_handler(rtems_vector_number v){
- int minor;
+ /* Get Filesystem name prefix */
+ prefix[0] = '\0';
+ if ( drvmgr_get_dev_prefix(dev, prefix) ) {
+ /* Failed to get prefix, make sure of a unique FS name
+ * by using the driver minor.
+ */
+ sprintf(devName, "/dev/apbuart%d", dev->minor_drv);
+ } else {
+ /* Got special prefix, this means we have a bus prefix
+ * And we should use our "bus minor"
+ */
+ sprintf(devName, "/dev/%sapbuart%d", prefix, dev->minor_bus);
+ }
- /* convert to */
- for(minor = 0; minor < dev_cnt; minor++) {
- if ( v == (apbuarts[minor].irq+0x10) ) {
- apbuart_interrupt(&apbuarts[minor]);
- return;
- }
+ /* Register Device */
+ status = rtems_io_register_name(devName, apbuart_driver_io_major, dev->minor_drv);
+ if (status != RTEMS_SUCCESSFUL) {
+ return DRVMGR_FAIL;
}
+
+ return DRVMGR_OK;
}
-#endif
-/* The interrupt handler, taking care of the
- * APBUART hardware
- */
-static void apbuart_interrupt(apbuart_priv *uart){
- unsigned int status;
- int empty;
- unsigned char c, *next_char = NULL;
- int signal;
+/******************* Driver Implementation ***********************/
- /* Clear & record any error */
- status = READ_REG(&uart->regs->status);
- if ( status & (APBUART_STATUS_OV|APBUART_STATUS_PE|APBUART_STATUS_FE) ){
- /* Data overrun */
- if ( status & APBUART_STATUS_OV ){
- uart->stats.hw_dovr++;
- }
- /* Parity error */
- if ( status & APBUART_STATUS_PE ){
- uart->stats.hw_parity++;
- }
- /* Framing error */
- if ( status & APBUART_STATUS_FE ){
- uart->stats.hw_frame++;
- }
- uart->regs->status = status & ~(APBUART_STATUS_OV|APBUART_STATUS_PE|APBUART_STATUS_FE);
- }
+#ifndef DEFAULT_TXBUF_SIZE
+ #define DEFAULT_TXBUF_SIZE 32
+#endif
+#ifndef DEFAULT_RXBUF_SIZE
+ #define DEFAULT_RXBUF_SIZE 32
+#endif
- /* Empty RX fifo into software fifo */
- signal = 0;
- while ( (status=READ_REG(&uart->regs->status)) & APBUART_STATUS_DR ){
- c = READ_REG(&uart->regs->data);
- if ( apbuart_fifo_isFull(uart->rxfifo) ){
- uart->stats.sw_dovr++;
- DBG("]");
- break;
- }
- /* put into fifo */
- apbuart_fifo_put(uart->rxfifo,c);
+/* Uncomment for debug output */
+/* #define DEBUG 1
+ #define FUNCDEBUG 1 */
- /* bump RX counter */
- uart->stats.rx_cnt++;
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+#ifdef FUNCDEBUG
+#define FUNCDBG(x...) printk(x)
+#else
+#define FUNCDBG(x...)
+#endif
- signal = 1;
+#ifndef READ_REG
+ #define READ_REG(address) _APBUART_READ_REG((unsigned int)(address))
+ static __inline__ unsigned int _APBUART_READ_REG(unsigned int addr) {
+ unsigned int tmp;
+ asm(" lda [%1]1, %0 "
+ : "=r"(tmp)
+ : "r"(addr)
+ );
+ return tmp;
}
+#endif
- /* Wake RX thread if any */
- if ( signal )
- rtems_semaphore_release(uart->rx_sem);
-
- /* If room in HW fifo and we got more chars to be sent */
- if ( !(status & APBUART_STATUS_TF) ){
-
- if ( apbuart_fifo_isEmpty(uart->txfifo) ){
- /* Turn off TX interrupt when no data is to be sent */
- if ( status & APBUART_STATUS_TE ){
- uart->regs->ctrl = READ_REG(&uart->regs->ctrl) & ~APBUART_CTRL_TF;
- DBG("?");
- }
- return;
- }
+static apbuart_fifo *apbuart_fifo_create(int size);
+static void apbuart_fifo_free(apbuart_fifo *fifo);
+static inline int apbuart_fifo_isFull(apbuart_fifo *fifo);
+static inline int apbuart_fifo_isEmpty(apbuart_fifo *fifo);
+static int apbuart_fifo_put(apbuart_fifo *fifo, unsigned char c);
+static int apbuart_fifo_get(apbuart_fifo *fifo, unsigned char *c);
+static int inline apbuart_fifo_peek(apbuart_fifo *fifo, unsigned char **c);
+static void inline apbuart_fifo_skip(apbuart_fifo *fifo);
- /* signal when there will be more room in SW fifo */
- if ( apbuart_fifo_isFull(uart->txfifo) )
- signal = 1;
+static rtems_device_driver apbuart_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver apbuart_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver apbuart_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver apbuart_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver apbuart_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver apbuart_control(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
- do{
- /* Put data into HW TX fifo */
- apbuart_fifo_peek(uart->txfifo,&next_char);
- c = *next_char;
- if ( uart->ascii_mode && ( c == '\n') ){
- uart->regs->data = '\n';
- *next_char = '\r'; /* avoid sending mutiple '\n' or '\r' */
- }else{
- uart->regs->data = c;
- apbuart_fifo_skip(uart->txfifo); /* remove sent char from fifo */
- }
- uart->regs->ctrl = READ_REG(&uart->regs->ctrl) | APBUART_CTRL_TE | APBUART_CTRL_TF;
- DBG("!");
- }while(!(empty=apbuart_fifo_isEmpty(uart->txfifo)) &&
- !((status=READ_REG(&uart->regs->status))&APBUART_STATUS_TF) );
+static void apbuart_interrupt(void *arg);
- /* Wake userspace thread, on empty or full fifo
- * This makes tx_flush and block work.
- */
- if ( signal || empty ){
- rtems_semaphore_release(uart->tx_sem);
- }
- }
-}
+#define APBUART_DRIVER_TABLE_ENTRY { apbuart_initialize, apbuart_open, apbuart_close, apbuart_read, apbuart_write, apbuart_control }
+static rtems_driver_address_table apbuart_driver = APBUART_DRIVER_TABLE_ENTRY;
-int APBUART_PREFIX(_register)(amba_confarea_type *bus) {
+int apbuart_register_io(rtems_device_major_number *m)
+{
rtems_status_code r;
- rtems_device_major_number m;
- amba_bus = bus;
-
- FUNCDBG("apbuart_register:\n");
-
- if ((r = rtems_io_register_driver(0, &apbuart_driver, &m)) == RTEMS_SUCCESSFUL) {
- DBG("APBUART driver successfully registered, major: %d\n", m);
+ if ((r = rtems_io_register_driver(0, &apbuart_driver, m)) == RTEMS_SUCCESSFUL) {
+ DBG("APBUART driver successfully registered, major: %d\n", *m);
} else {
switch(r) {
case RTEMS_TOO_MANY:
- printk("APBUART rtems_io_register_driver failed: RTEMS_TOO_MANY\n"); return -1;
- case RTEMS_INVALID_NUMBER:
- printk("APBUART rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n"); return -1;
+ printk("APBUART rtems_io_register_driver failed: RTEMS_TOO_MANY\n");
+ return -1;
+ case RTEMS_INVALID_NUMBER:
+ printk("APBUART rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n");
+ return -1;
case RTEMS_RESOURCE_IN_USE:
- printk("APBUART rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n"); return -1;
+ printk("APBUART rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n");
+ return -1;
default:
- printk("APBUART rtems_io_register_driver failed\n");
- return -1;
+ printk("APBUART rtems_io_register_driver failed\n");
+ return -1;
}
}
return 0;
}
-static rtems_device_driver apbuart_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+int apbuart_device_init(struct apbuart_priv *priv)
{
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
+ int minor = priv->dev->minor_drv;
+ int rxFifoLen, txFifoLen;
+ union drvmgr_key_value *value;
+
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)priv->dev->businfo;
+ if ( ambadev == NULL ) {
+ return -1;
+ }
+ pnpinfo = &ambadev->info;
+ priv->irq = pnpinfo->irq;
+ priv->regs = (struct apbuart_regs *)pnpinfo->apb_slv->start;
- rtems_status_code status;
- int i;
- amba_apb_device dev;
- char fs_name[20];
+ /* Clear HW regs */
+ priv->regs->status = 0;
+ priv->regs->ctrl = 0;
- FUNCDBG("apbuart_initialize\n");
+ /* Get Configuration from Bus resources (Let user override defaults) */
+ rxFifoLen = DEFAULT_RXBUF_SIZE;
+ txFifoLen = DEFAULT_TXBUF_SIZE;
- /* Find all APB UART devices */
- dev_cnt = amba_get_number_apbslv_devices(amba_bus,VENDOR_GAISLER,GAISLER_APBUART);
- if ( dev_cnt < 1 ){
- /* Failed to find any CAN cores! */
- printk("APBUART: Failed to find any APBUART cores\n\r");
- return -1;
- }
+ value = drvmgr_dev_key_get(priv->dev, "rxFifoLen", KEY_TYPE_INT);
+ if ( value )
+ rxFifoLen = value->i;
- strcpy(fs_name,APBUART_DEVNAME);
+ value = drvmgr_dev_key_get(priv->dev, "txFifoLen", KEY_TYPE_INT);
+ if ( value )
+ txFifoLen = value->i;
- DBG("Found %d APBUART(s)\n\r",dev_cnt);
+ /* Allocate default software buffers */
+ priv->txfifo = apbuart_fifo_create(txFifoLen);
+ priv->rxfifo = apbuart_fifo_create(rxFifoLen);
+ if ( !priv->txfifo || !priv->rxfifo )
+ return -1;
- /* Allocate memory for device structures */
- apbuarts = malloc(sizeof(apbuart_priv) * dev_cnt);
- if ( !apbuarts ){
- printk("APBUART: Failed to allocate SW memory\n\r");
+ /* Device A Semaphore created with count = 1 */
+ if ( rtems_semaphore_create(rtems_build_name('A', 'U', 'D', '0'+minor),
+ 1,
+ RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &priv->dev_sem) != RTEMS_SUCCESSFUL ){
return -1;
}
- memset(apbuarts,0,sizeof(sizeof(apbuart_priv) * dev_cnt));
+ if ( rtems_semaphore_create(rtems_build_name('A', 'U', 'T', '0'+minor),
+ 1,
+ RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &priv->tx_sem) != RTEMS_SUCCESSFUL ) {
+ return -1;
+ }
- /* Detect System Frequency from initialized timer */
-#ifndef SYS_FREQ_HZ
-#if defined(LEON3)
- /* LEON3: find timer address via AMBA Plug&Play info */
- {
- amba_apb_device gptimer;
- LEON3_Timer_Regs_Map *tregs;
+ if ( rtems_semaphore_create(rtems_build_name('A', 'U', 'R', '0'+minor),
+ 1,
+ RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &priv->rx_sem) != RTEMS_SUCCESSFUL ) {
+ return -1;
+ }
- if ( amba_find_apbslv(&amba_conf,VENDOR_GAISLER,GAISLER_GPTIMER,&gptimer) == 1 ){
- tregs = (LEON3_Timer_Regs_Map *)gptimer.start;
- sys_freq_hz = (tregs->scaler_reload+1)*1000*1000;
- DBG("APBUART: detected %dHZ system frequency\n\r",sys_freq_hz);
- }else{
- sys_freq_hz = 40000000; /* Default to 40MHz */
- printk("APBUART: Failed to detect system frequency\n\r");
- }
+ return 0;
+}
+/******************* I/O driver implementation ***********************/
+
+static void apbuart_hw_open(struct apbuart_priv *uart)
+{
+ unsigned int scaler;
+
+ /* Calculate Baudrate */
+ if ( uart->scaler > 0 ) {
+ scaler = uart->scaler;
+ } else {
+ scaler = (((uart->freq_hz*10)/(uart->baud*8))-5)/10;
+ uart->scaler = scaler;
}
-#elif defined(LEON2)
- /* LEON2: use hardcoded address to get to timer */
- {
- LEON_Register_Map *regs = (LEON_Register_Map *)0x80000000;
- sys_freq_hz = (regs->Scaler_Reload+1)*1000*1000;
- }
-#else
- #error CPU not supported for OC_CAN driver
-#endif
-#else
- /* Use hardcoded frequency */
- sys_freq_hz = SYS_FREQ_HZ;
-#endif
+
+ /* Set new baud rate */
+ uart->regs->scaler = scaler;
+
+ /* Enable receiver & Transmitter */
+ uart->regs->ctrl = APBUART_CTRL_RE | APBUART_CTRL_RF | APBUART_CTRL_RI | APBUART_CTRL_TI;
+}
+
+static void apbuart_hw_close(struct apbuart_priv *uart)
+{
+ /* disable receiver & transmitter & all IRQs */
+ uart->regs->ctrl = 0;
+}
- for(i=0; i<dev_cnt; i++){
- /* Get AMBA AHB device info from Plug&Play */
- amba_find_next_apbslv(amba_bus,VENDOR_GAISLER,GAISLER_APBUART,&dev,i);
-
- printk("APBUART[%d]: at 0x%x irq %d (0x%x)\n\r",i,dev.start,dev.irq,(unsigned int)&apbuarts[i]);
-
- apbuarts[i].regs = (ambapp_apb_uart *)dev.start;
- apbuarts[i].irq = dev.irq;
- apbuarts[i].minor = i;
-
- /* Clear HW regs */
- apbuarts[i].regs->status = 0;
- apbuarts[i].regs->ctrl = 0;
-
- /* Allocate default software buffers */
- apbuarts[i].txfifo = apbuart_fifo_create(DEFAULT_TXBUF_SIZE);
- apbuarts[i].rxfifo = apbuart_fifo_create(DEFAULT_RXBUF_SIZE);
- if ( !apbuarts[i].txfifo || !apbuarts[i].rxfifo )
- rtems_fatal_error_occurred(RTEMS_NO_MEMORY);
-
- APBUART_DEVNAME_NO(fs_name,i);
-
- /* Bind name to device */
- DBG("APBUART[%d]: binding to name %s\n\r",i,fs_name);
- status = rtems_io_register_name(fs_name, major, i);
- if (status != RTEMS_SUCCESSFUL)
- rtems_fatal_error_occurred(status);
-
- /* Setup interrupt handler for each channel */
- APBUART_REG_INT(APBUART_PREFIX(_interrupt_handler), apbuarts[i].irq, &apbuarts[i]);
-
- /* Device A Semaphore created with count = 1 */
- if ( rtems_semaphore_create(rtems_build_name('A', 'U', 'D', '0'+i),
- 1,
- RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
- 0,
- &apbuarts[i].dev_sem) != RTEMS_SUCCESSFUL )
- return RTEMS_INTERNAL_ERROR;
-
- if ( rtems_semaphore_create(rtems_build_name('A', 'U', 'T', '0'+i),
- 1,
- RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
- 0,
- &apbuarts[i].tx_sem) != RTEMS_SUCCESSFUL )
- return RTEMS_INTERNAL_ERROR;
-
- if ( rtems_semaphore_create(rtems_build_name('A', 'U', 'R', '0'+i),
- 1,
- RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
- 0,
- &apbuarts[i].rx_sem) != RTEMS_SUCCESSFUL )
- return RTEMS_INTERNAL_ERROR;
+static rtems_device_driver apbuart_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ /* Initialize common data structures, for example common semaphores... */
- }
return RTEMS_SUCCESSFUL;
}
static rtems_device_driver apbuart_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
-{
- apbuart_priv *uart;
+{
+ struct apbuart_priv *uart;
+ struct drvmgr_dev *dev;
- FUNCDBG("apbuart_open: major %d, minor %d\n", major, minor);
-
- if ( (minor < 0) || (minor >= dev_cnt) ) {
+ if ( drvmgr_get_dev(&apbuart_drv_info.general, minor, &dev) ) {
DBG("Wrong minor %d\n", minor);
return RTEMS_INVALID_NAME;
}
+ uart = (struct apbuart_priv *)dev->priv;
- uart = &apbuarts[minor];
+ FUNCDBG("apbuart_open: major %d, minor %d\n", major, minor);
if (rtems_semaphore_obtain(uart->dev_sem, RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT) != RTEMS_SUCCESSFUL) {
DBG("apbuart_open: resource in use\n");
@@ -506,8 +434,8 @@ static rtems_device_driver apbuart_open(rtems_device_major_number major, rtems_d
/* non-ascii mode */
uart->ascii_mode = 0;
- /* not started */
- uart->started = 0;
+ /* not started */
+ uart->started = 0;
if ( !uart->txfifo || (uart->txfifo->size!=DEFAULT_TXBUF_SIZE) ){
apbuart_fifo_free(uart->txfifo);
@@ -525,39 +453,53 @@ static rtems_device_driver apbuart_open(rtems_device_major_number major, rtems_d
}
/* Now user must call ioctl(START,0) to begin */
-
+
return RTEMS_SUCCESSFUL;
}
static rtems_device_driver apbuart_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
{
- apbuart_priv *uart = &apbuarts[minor];
+ struct apbuart_priv *uart;
+ struct drvmgr_dev *dev;
- FUNCDBG("apbuart_close[%d]:\n",minor);
+ if ( drvmgr_get_dev(&apbuart_drv_info.general, minor, &dev) ) {
+ DBG("Wrong minor %d\n", minor);
+ return RTEMS_INVALID_NAME;
+ }
+ uart = (struct apbuart_priv *)dev->priv;
+ FUNCDBG("apbuart_close[%d]:\n",minor);
+
apbuart_hw_close(uart);
/* Software state will be set when open is called again */
rtems_semaphore_release(uart->rx_sem);
rtems_semaphore_release(uart->tx_sem);
uart->started = 0;
-
+
rtems_semaphore_release(uart->dev_sem);
-
+
return RTEMS_SUCCESSFUL;
}
-
+
static rtems_device_driver apbuart_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
{
rtems_libio_rw_args_t *rw_args;
unsigned int count = 0, oldLevel;
unsigned char *buf;
- apbuart_priv *uart = &apbuarts[minor];
+ struct apbuart_priv *uart;
+ struct drvmgr_dev *dev;
+ if ( drvmgr_get_dev(&apbuart_drv_info.general, minor, &dev) ) {
+ DBG("Wrong minor %d\n", minor);
+ return RTEMS_INVALID_NAME;
+ }
+ uart = (struct apbuart_priv *)dev->priv;
+
rw_args = (rtems_libio_rw_args_t *) arg;
FUNCDBG("apbuart_read\n");
-
+
buf = (unsigned char *)rw_args->buffer;
if ( (rw_args->count < 1) || !buf )
return RTEMS_INVALID_NAME; /* EINVAL */
@@ -565,65 +507,71 @@ static rtems_device_driver apbuart_read(rtems_device_major_number major, rtems_d
rtems_interrupt_disable(oldLevel);
do {
if ( (unsigned int)uart < 0x40000000 ) {
- printk("UART %x is screwed\n",uart);
- }
+ printk("UART %x is screwed\n",uart);
+ }
/* Read from SW fifo */
- if ( apbuart_fifo_get(uart->rxfifo,&buf[count]) != 0 ){
+ if ( apbuart_fifo_get(uart->rxfifo,&buf[count]) != 0 ){
/* non blocking or read at least 1 byte */
if ( (count > 0) || (!uart->rxblk) )
break; /* Return */
-
+
rtems_interrupt_enable(oldLevel);
/* Block thread until a char is received */
rtems_semaphore_obtain(uart->rx_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
-
+
rtems_interrupt_disable(oldLevel);
continue;
}
-
+
/* Got char from SW FIFO */
count++;
-
+
} while (count < rw_args->count );
-
+
rtems_interrupt_enable(oldLevel);
rw_args->bytes_moved = count;
-
+
if (count == 0)
return RTEMS_TIMEOUT; /* ETIMEDOUT should be EAGAIN/EWOULDBLOCK */
return RTEMS_SUCCESSFUL;
}
-
+
static rtems_device_driver apbuart_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
{
rtems_libio_rw_args_t *rw_args;
unsigned int count, oldLevel, ctrl;
char *buf;
- apbuart_priv *uart = &apbuarts[minor];
int direct=0;
+ struct apbuart_priv *uart;
+ struct drvmgr_dev *dev;
-
+ if ( drvmgr_get_dev(&apbuart_drv_info.general, minor, &dev) ) {
+ DBG("Wrong minor %d\n", minor);
+ return RTEMS_INVALID_NAME;
+ }
+ uart = (struct apbuart_priv *)dev->priv;
+
rw_args = (rtems_libio_rw_args_t *) arg;
-
+
FUNCDBG("apbuart_write\n");
-
+
buf = rw_args->buffer;
-
+
if ( rw_args->count < 1 || !buf )
- return RTEMS_INVALID_NAME; /* EINVAL */
-
+ return RTEMS_INVALID_NAME; /* EINVAL */
+
count = 0;
rtems_interrupt_disable(oldLevel);
/* Do we need to start to send first char direct via HW
* to get IRQ going.
*/
-
+
ctrl = READ_REG(&uart->regs->ctrl);
if ( (ctrl & APBUART_CTRL_TF) == 0 ){
- /* TX interrupt is disabled ==>
+ /* TX interrupt is disabled ==>
* SW FIFO is empty and,
* HW FIFO empty
*/
@@ -637,7 +585,7 @@ static rtems_device_driver apbuart_write(rtems_device_major_number major, rtems_
uart->regs->ctrl = ctrl | APBUART_CTRL_TE | APBUART_CTRL_TF;
direct = 1;
}
-
+
while( count < rw_args->count ) {
/* write to HW FIFO direct skipping SW FIFO */
if ( direct && ((READ_REG(&uart->regs->status) & APBUART_STATUS_TF) == 0) ){
@@ -647,23 +595,23 @@ static rtems_device_driver apbuart_write(rtems_device_major_number major, rtems_
else if ( apbuart_fifo_put(uart->txfifo,buf[count]) ){
direct = 0;
DBG("APBUART[%d]: write: SW FIFO Full\n\r",minor);
-
+
/* is full, block? */
if ( ((count < 1) && uart->txblk) || uart->tx_flush ){
-
+
rtems_interrupt_enable(oldLevel);
-
+
rtems_semaphore_obtain(uart->tx_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
-
+
rtems_interrupt_disable(oldLevel);
-
+
/* Do we need to start to send first char direct via HW
* to get IRQ going.
*/
-
+
ctrl = READ_REG(&uart->regs->ctrl);
if ( (ctrl & APBUART_CTRL_TF) == 0 ){
- /* TX interrupt is disabled ==>
+ /* TX interrupt is disabled ==>
* SW FIFO is empty and,
* HW FIFO empty
*/
@@ -677,7 +625,7 @@ static rtems_device_driver apbuart_write(rtems_device_major_number major, rtems_
uart->regs->ctrl = ctrl | APBUART_CTRL_TF | APBUART_CTRL_TE;
direct = 1;
}
-
+
continue;
}
/* don't block, return current status */
@@ -685,18 +633,18 @@ static rtems_device_driver apbuart_write(rtems_device_major_number major, rtems_
}else{
direct = 0;
}
-
+
count++;
-
+
}
rtems_interrupt_enable(oldLevel);
-
+
rw_args->bytes_moved = count;
-
+
if (count == 0)
return RTEMS_TIMEOUT; /* ETIMEDOUT should be EAGAIN/EWOULDBLOCK */
-
+
return RTEMS_SUCCESSFUL;
}
@@ -704,17 +652,24 @@ static rtems_device_driver apbuart_control(rtems_device_major_number major, rtem
{
rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *)arg;
unsigned int *data = ioarg->buffer;
- apbuart_priv *uart = &apbuarts[minor];
int size;
unsigned int baudrate, blocking;
apbuart_stats *stats;
+ struct apbuart_priv *uart;
+ struct drvmgr_dev *dev;
- FUNCDBG("apbuart_control [%i,%i]\n",major, minor);
+ if ( drvmgr_get_dev(&apbuart_drv_info.general, minor, &dev) ) {
+ DBG("Wrong minor %d\n", minor);
+ return RTEMS_INVALID_NAME;
+ }
+ uart = (struct apbuart_priv *)dev->priv;
+ FUNCDBG("apbuart_control [%i,%i]\n",major, minor);
+
if (!ioarg)
return RTEMS_INVALID_NAME;
- ioarg->ioctl_return = 0;
+ ioarg->ioctl_return = 0;
switch(ioarg->command) {
/* Enable Receiver & transmitter */
@@ -723,58 +678,62 @@ static rtems_device_driver apbuart_control(rtems_device_major_number major, rtem
return RTEMS_INVALID_NAME;
apbuart_hw_open(uart);
uart->started = 1;
+ /* Setup interrupt handler & Enable IRQ */
+ drvmgr_interrupt_register(dev, 0, "apbuart",
+ apbuart_interrupt, uart);
break;
/* Close Receiver & transmitter */
case APBUART_STOP:
if ( !uart->started )
return RTEMS_INVALID_NAME;
+ drvmgr_interrupt_unregister(dev, 0, apbuart_interrupt, uart);
apbuart_hw_close(uart);
uart->started = 0;
break;
- /* Set RX FIFO Software buffer length
+ /* Set RX FIFO Software buffer length
* It is only possible to change buffer size in
* non-running mode.
*/
case APBUART_SET_RXFIFO_LEN:
if ( uart->started )
return RTEMS_RESOURCE_IN_USE; /* EBUSY */
-
+
size = (int)ioarg->buffer;
- if ( size < 1 )
+ if ( size < 1 )
return RTEMS_INVALID_NAME; /* EINVAL */
-
+
/* Free old buffer */
apbuart_fifo_free(uart->rxfifo);
-
+
/* Allocate new buffer & init it */
uart->rxfifo = apbuart_fifo_create(size);
if ( !uart->rxfifo )
return RTEMS_NO_MEMORY;
break;
- /* Set TX FIFO Software buffer length
- * It is only possible to change buffer size
+ /* Set TX FIFO Software buffer length
+ * It is only possible to change buffer size
* while in non-running mode.
*/
case APBUART_SET_TXFIFO_LEN:
if ( uart->started )
return RTEMS_RESOURCE_IN_USE; /* EBUSY */
-
+
size = (int)ioarg->buffer;
- if ( size < 1 )
+ if ( size < 1 )
return RTEMS_INVALID_NAME; /* EINVAL */
-
+
/* Free old buffer */
apbuart_fifo_free(uart->txfifo);
-
+
/* Allocate new buffer & init it */
uart->txfifo = apbuart_fifo_create(size);
if ( !uart->txfifo )
return RTEMS_NO_MEMORY;
break;
-
+
case APBUART_SET_BAUDRATE:
/* Set baud rate of */
baudrate = (int)ioarg->buffer;
@@ -784,47 +743,139 @@ static rtems_device_driver apbuart_control(rtems_device_major_number major, rtem
uart->scaler = 0; /* use uart->baud */
uart->baud = baudrate;
break;
-
+
case APBUART_SET_SCALER:
/* use uart->scaler not uart->baud */
uart->scaler = data[0];
break;
-
+
case APBUART_SET_BLOCKING:
blocking = (unsigned int)ioarg->buffer;
uart->rxblk = ( blocking & APBUART_BLK_RX );
uart->txblk = ( blocking & APBUART_BLK_TX );
uart->tx_flush = ( blocking & APBUART_BLK_FLUSH );
break;
-
+
case APBUART_GET_STATS:
stats = (void *)ioarg->buffer;
if ( !stats )
return RTEMS_INVALID_NAME;
-
+
/* Copy Stats */
*stats = uart->stats;
break;
-
- case APBUART_CLR_STATS:
+
+ case APBUART_CLR_STATS:
/* Clear/reset Stats */
- memset(&uart->stats,0,sizeof(uart->stats));
+ memset(&uart->stats,0,sizeof(uart->stats));
break;
-
+
case APBUART_SET_ASCII_MODE:
uart->ascii_mode = (int)ioarg->buffer;
break;
-
+
default:
return RTEMS_NOT_DEFINED;
}
return RTEMS_SUCCESSFUL;
}
+/* The interrupt handler, taking care of the
+ * APBUART hardware
+ */
+static void apbuart_interrupt(void *arg)
+{
+ struct apbuart_priv *uart = (struct apbuart_priv *)arg;
+ unsigned int status;
+ int empty;
+ unsigned char c, *next_char = NULL;
+ int signal;
+
+ /* Clear & record any error */
+ status = READ_REG(&uart->regs->status);
+ if ( status & (APBUART_STATUS_OV|APBUART_STATUS_PE|APBUART_STATUS_FE) ){
+ /* Data overrun */
+ if ( status & APBUART_STATUS_OV ){
+ uart->stats.hw_dovr++;
+ }
+ /* Parity error */
+ if ( status & APBUART_STATUS_PE ){
+ uart->stats.hw_parity++;
+ }
+ /* Framing error */
+ if ( status & APBUART_STATUS_FE ){
+ uart->stats.hw_frame++;
+ }
+ uart->regs->status = status & ~(APBUART_STATUS_OV|APBUART_STATUS_PE|APBUART_STATUS_FE);
+ }
+
+ /* Empty RX fifo into software fifo */
+ signal = 0;
+ while ( (status=READ_REG(&uart->regs->status)) & APBUART_STATUS_DR ){
+ c = READ_REG(&uart->regs->data);
+ if ( apbuart_fifo_isFull(uart->rxfifo) ){
+ uart->stats.sw_dovr++;
+ DBG("]");
+ break;
+ }
+ /* put into fifo */
+ apbuart_fifo_put(uart->rxfifo,c);
+
+ /* bump RX counter */
+ uart->stats.rx_cnt++;
+
+ signal = 1;
+ }
+
+ /* Wake RX thread if any */
+ if ( signal )
+ rtems_semaphore_release(uart->rx_sem);
+
+ /* If room in HW fifo and we got more chars to be sent */
+ if ( !(status & APBUART_STATUS_TF) ){
+
+ if ( apbuart_fifo_isEmpty(uart->txfifo) ){
+ /* Turn off TX interrupt when no data is to be sent */
+ if ( status & APBUART_STATUS_TE ){
+ uart->regs->ctrl = READ_REG(&uart->regs->ctrl) & ~APBUART_CTRL_TF;
+ DBG("?");
+ }
+ return;
+ }
+
+ /* signal when there will be more room in SW fifo */
+ if ( apbuart_fifo_isFull(uart->txfifo) )
+ signal = 1;
+
+ do{
+ /* Put data into HW TX fifo */
+ apbuart_fifo_peek(uart->txfifo,&next_char);
+ c = *next_char;
+ if ( uart->ascii_mode && ( c == '\n') ){
+ uart->regs->data = '\n';
+ *next_char = '\r'; /* avoid sending mutiple '\n' or '\r' */
+ }else{
+ uart->regs->data = c;
+ apbuart_fifo_skip(uart->txfifo); /* remove sent char from fifo */
+ }
+ uart->regs->ctrl = READ_REG(&uart->regs->ctrl) | APBUART_CTRL_TE | APBUART_CTRL_TF;
+ DBG("!");
+ }while(!(empty=apbuart_fifo_isEmpty(uart->txfifo)) &&
+ !((status=READ_REG(&uart->regs->status))&APBUART_STATUS_TF) );
+
+ /* Wake userspace thread, on empty or full fifo
+ * This makes tx_flush and block work.
+ */
+ if ( signal || empty ){
+ rtems_semaphore_release(uart->tx_sem);
+ }
+ }
+}
/******************* APBUART FIFO implementation ***********************/
-static apbuart_fifo *apbuart_fifo_create(int size){
+static apbuart_fifo *apbuart_fifo_create(int size)
+{
apbuart_fifo *fifo;
fifo = (apbuart_fifo *) malloc(size + sizeof(apbuart_fifo));
if ( fifo ) {
@@ -839,22 +890,26 @@ static apbuart_fifo *apbuart_fifo_create(int size){
return fifo;
}
-static void apbuart_fifo_free(apbuart_fifo *fifo){
+static void apbuart_fifo_free(apbuart_fifo *fifo)
+{
if ( fifo )
free(fifo);
}
-static inline int apbuart_fifo_isFull(apbuart_fifo *fifo){
+static inline int apbuart_fifo_isFull(apbuart_fifo *fifo)
+{
return fifo->full;
}
-static inline int apbuart_fifo_isEmpty(apbuart_fifo *fifo){
+static inline int apbuart_fifo_isEmpty(apbuart_fifo *fifo)
+{
if ( (fifo->head == fifo->tail) && !fifo->full )
return -1;
return 0;
}
-static int apbuart_fifo_put(apbuart_fifo *fifo, unsigned char c){
+static int apbuart_fifo_put(apbuart_fifo *fifo, unsigned char c)
+{
if ( !fifo->full ){
*fifo->head = c;
fifo->head = (fifo->head >= fifo->max ) ? fifo->buf : fifo->head+1;
@@ -865,7 +920,8 @@ static int apbuart_fifo_put(apbuart_fifo *fifo, unsigned char c){
return -1;
}
-static int apbuart_fifo_get(apbuart_fifo *fifo, unsigned char *c){
+static int apbuart_fifo_get(apbuart_fifo *fifo, unsigned char *c)
+{
if ( apbuart_fifo_isEmpty(fifo) )
return -1;
if ( c )
@@ -875,7 +931,8 @@ static int apbuart_fifo_get(apbuart_fifo *fifo, unsigned char *c){
return 0;
}
-static int inline apbuart_fifo_peek(apbuart_fifo *fifo, unsigned char **c){
+static int inline apbuart_fifo_peek(apbuart_fifo *fifo, unsigned char **c)
+{
if ( apbuart_fifo_isEmpty(fifo) )
return -1;
if ( c )
@@ -883,9 +940,11 @@ static int inline apbuart_fifo_peek(apbuart_fifo *fifo, unsigned char **c){
return 0;
}
-static void inline apbuart_fifo_skip(apbuart_fifo *fifo){
+static void inline apbuart_fifo_skip(apbuart_fifo *fifo)
+{
if ( !apbuart_fifo_isEmpty(fifo) ){
fifo->tail = (fifo->tail >= fifo->max ) ? fifo->buf : fifo->tail+1;
fifo->full = 0;
}
}
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/uart/apbuart_cons.c b/c/src/lib/libbsp/sparc/shared/uart/apbuart_cons.c
new file mode 100644
index 0000000000..4e1304b227
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/uart/apbuart_cons.c
@@ -0,0 +1,692 @@
+/* This file contains the driver for the GRLIB APBUART serial port. The driver
+ * is implemented by using the cons.c console layer. Interrupt/Polling/Task
+ * driven mode can be configured using driver resources:
+ *
+ * - mode (0=Polling, 1=Interrupt, 2=Task-Driven-Interrupt Mode)
+ * - syscon (0=Force not Ssystem Console, 1=Suggest System Console)
+ *
+ * The BSP define APBUART_INFO_AVAIL in order to add the info routine
+ * used for debugging.
+ *
+ * COPYRIGHT (c) 2010.
+ * Aeroflex Gaisler.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2010-09-27, Daniel Hellstrom <daniel@gaisler.com>
+ * created
+ */
+
+/******************* Driver manager interface ***********************/
+#include <bsp.h>
+#include <rtems/libio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <rtems/bspIo.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+#include <apbuart.h>
+#include <ambapp.h>
+#include <grlib.h>
+#include <cons.h>
+#include <rtems/termiostypes.h>
+
+/*#define DEBUG 1 */
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+/* LEON3 Low level transmit/receive functions provided by debug-uart code */
+extern void apbuart_outbyte_polled(
+ struct apbuart_regs *regs,
+ unsigned char ch,
+ int do_cr_on_newline,
+ int wait_sent);
+extern int apbuart_inbyte_nonblocking(struct apbuart_regs *regs);
+extern struct apbuart_regs *dbg_uart; /* The debug UART */
+
+struct apbuart_priv {
+ struct console_dev condev;
+ struct drvmgr_dev *dev;
+ struct apbuart_regs *regs;
+ char devName[32];
+ void *cookie;
+ int sending;
+ int mode;
+};
+
+/* TERMIOS Layer Callback functions */
+void apbuart_get_attributes(struct console_dev *condev, struct termios *t);
+int apbuart_set_attributes(int minor, const struct termios *t);
+ssize_t apbuart_write_polled(int minor, const char *buf, size_t len);
+int apbuart_pollRead(int minor);
+ssize_t apbuart_write_intr(int minor, const char *buf, size_t len);
+int apbuart_pollRead_task(int minor);
+int apbuart_firstOpen(int major, int minor, void *arg);
+int apbuart_lastClose(int major, int minor, void *arg);
+
+void apbuart_isr(void *arg);
+int apbuart_get_baud(struct apbuart_priv *uart);
+
+int apbuart_init1(struct drvmgr_dev *dev);
+#ifdef APBUART_INFO_AVAIL
+static int apbuart_info(
+ struct drvmgr_dev *dev,
+ void (*print_line)(void *p, char *str),
+ void *p, int, char *argv[]);
+#define APBUART_INFO_FUNC apbuart_info
+#else
+#define APBUART_INFO_FUNC NULL
+#endif
+
+struct drvmgr_drv_ops apbuart_ops =
+{
+ .init = {apbuart_init1, NULL, NULL, NULL},
+ .remove = NULL,
+ .info = APBUART_INFO_FUNC
+};
+
+static struct amba_dev_id apbuart_ids[] =
+{
+ {VENDOR_GAISLER, GAISLER_APBUART},
+ {0, 0} /* Mark end of table */
+};
+
+static struct amba_drv_info apbuart_drv_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_AMBAPP_GAISLER_APBUART_ID, /* Driver ID */
+ "APBUART_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */
+ &apbuart_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ sizeof(struct apbuart_priv), /*DrvMgr alloc private*/
+ },
+ &apbuart_ids[0]
+};
+
+void apbuart_cons_register_drv (void)
+{
+ DBG("Registering APBUART Console driver\n");
+ drvmgr_drv_register(&apbuart_drv_info.general);
+}
+
+/* Interrupt mode routines */
+static const rtems_termios_callbacks Callbacks_intr = {
+ apbuart_firstOpen, /* firstOpen */
+ apbuart_lastClose, /* lastClose */
+ NULL, /* pollRead */
+ apbuart_write_intr, /* write */
+ apbuart_set_attributes, /* setAttributes */
+ NULL, /* stopRemoteTx */
+ NULL, /* startRemoteTx */
+ TERMIOS_IRQ_DRIVEN /* outputUsesInterrupts */
+};
+
+/* Polling mode routines */
+static const rtems_termios_callbacks Callbacks_task = {
+ apbuart_firstOpen, /* firstOpen */
+ apbuart_lastClose, /* lastClose */
+ apbuart_pollRead_task, /* pollRead */
+ apbuart_write_intr, /* write */
+ apbuart_set_attributes, /* setAttributes */
+ NULL, /* stopRemoteTx */
+ NULL, /* startRemoteTx */
+ TERMIOS_TASK_DRIVEN /* outputUsesInterrupts */
+};
+
+/* Polling mode routines */
+static const rtems_termios_callbacks Callbacks_poll = {
+ apbuart_firstOpen, /* firstOpen */
+ apbuart_lastClose, /* lastClose */
+ apbuart_pollRead, /* pollRead */
+ apbuart_write_polled, /* write */
+ apbuart_set_attributes, /* setAttributes */
+ NULL, /* stopRemoteTx */
+ NULL, /* startRemoteTx */
+ TERMIOS_POLLED /* outputUsesInterrupts */
+};
+
+int apbuart_init1(struct drvmgr_dev *dev)
+{
+ struct apbuart_priv *priv;
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
+ union drvmgr_key_value *value;
+ char prefix[32];
+ unsigned int db;
+ static int first_uart = 1;
+
+ /* The default operation in AMP is to use APBUART[0] for CPU[0],
+ * APBUART[1] for CPU[1] and so on. The remaining UARTs is not used
+ * since we don't know how many CPU-cores there are. Note this only
+ * affects the on-chip amba bus (the root bus). The user can override
+ * the default resource sharing by defining driver resources for the
+ * APBUART devices on each AMP OS instance.
+ */
+#if defined(RTEMS_MULTIPROCESSING) && defined(LEON3)
+ if (drvmgr_on_rootbus(dev) && dev->minor_drv != LEON3_Cpu_Index &&
+ drvmgr_keys_get(dev, NULL) != 0) {
+ /* User hasn't configured on-chip APBUART, leave it untouched */
+ return DRVMGR_EBUSY;
+ }
+#endif
+
+ DBG("APBUART[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
+ /* Private data was allocated and zeroed by driver manager */
+ priv = dev->priv;
+ if (!priv)
+ return DRVMGR_NOMEM;
+ priv->dev = dev;
+
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)priv->dev->businfo;
+ if (ambadev == NULL)
+ return -1;
+ pnpinfo = &ambadev->info;
+ priv->regs = (struct apbuart_regs *)pnpinfo->apb_slv->start;
+
+ /* Clear HW regs, leave baudrate register as it is */
+ priv->regs->status = 0;
+ /* leave debug bit, and Transmitter/receiver if this is the debug UART.
+ * With old APBUARTs debug is enabled by setting LB and FL, since LB is
+ * not reset we can not trust is, however since FL is reset we guess
+ * that we are debugging old UART if both FL and LB is already set.
+ */
+#ifdef LEON3
+ if (priv->regs == dbg_uart) {
+ db = priv->regs->ctrl & (LEON_REG_UART_CTRL_DB |
+ LEON_REG_UART_CTRL_RE |
+ LEON_REG_UART_CTRL_TE |
+ LEON_REG_UART_CTRL_FL |
+ LEON_REG_UART_CTRL_LB |
+ LEON_REG_UART_CTRL_PE |
+ LEON_REG_UART_CTRL_PS);
+ } else
+#endif
+ {
+ if (priv->regs->ctrl & (LEON_REG_UART_CTRL_FL |
+ LEON_REG_UART_CTRL_LB))
+ db = priv->regs->ctrl & (LEON_REG_UART_CTRL_FL |
+ LEON_REG_UART_CTRL_LB);
+ else
+ db = priv->regs->ctrl & LEON_REG_UART_CTRL_DB;
+ }
+
+ priv->regs->ctrl = db;
+
+ /* The system console and Debug console may depend on this device, so
+ * initialize it straight away.
+ *
+ * We default to have System Console on first APBUART, user may override
+ * this behaviour by setting the syscon option to 0.
+ */
+ if (drvmgr_on_rootbus(dev) && first_uart) {
+ priv->condev.flags = CONSOLE_FLAG_SYSCON;
+ first_uart = 0;
+ } else {
+ priv->condev.flags = 0;
+ }
+
+ value = drvmgr_dev_key_get(priv->dev, "syscon", KEY_TYPE_INT);
+ if (value) {
+ if (value->i)
+ priv->condev.flags |= CONSOLE_FLAG_SYSCON;
+ else
+ priv->condev.flags &= ~CONSOLE_FLAG_SYSCON;
+ }
+
+ priv->condev.fsname = NULL;
+ priv->condev.ops.get_uart_attrs = apbuart_get_attributes;
+
+ /* Select 0=Polled, 1=IRQ, 2=Task-Driven UART Mode */
+ value = drvmgr_dev_key_get(priv->dev, "mode", KEY_TYPE_INT);
+ if (value)
+ priv->mode = value->i;
+ else
+ priv->mode = TERMIOS_POLLED;
+ if (priv->mode == TERMIOS_IRQ_DRIVEN) {
+ priv->condev.callbacks = &Callbacks_intr;
+ } else if (priv->mode == TERMIOS_TASK_DRIVEN) {
+ priv->condev.callbacks = &Callbacks_task;
+ } else {
+ priv->condev.callbacks = &Callbacks_poll;
+ }
+
+ /* Get Filesystem name prefix */
+ prefix[0] = '\0';
+ if (drvmgr_get_dev_prefix(dev, prefix)) {
+ /* Got special prefix, this means we have a bus prefix
+ * And we should use our "bus minor"
+ */
+ sprintf(priv->devName, "/dev/%sapbuart%d", prefix, dev->minor_bus);
+ priv->condev.fsname = priv->devName;
+ }
+
+ /* Register it as a console device, the console driver will register
+ * a termios device as well
+ */
+ console_dev_register(&priv->condev);
+
+ return DRVMGR_OK;
+}
+
+#ifdef APBUART_INFO_AVAIL
+static int apbuart_info(
+ struct drvmgr_dev *dev,
+ void (*print_line)(void *p, char *str),
+ void *p, int argc, char *argv[])
+{
+ struct apbuart_priv *priv = dev->priv;
+ char *str1;
+ char buf[64];
+
+ if (dev->priv == NULL)
+ return -DRVMGR_EINVAL;
+
+ if (priv->mode == TERMIOS_POLLED)
+ str1 = "TERMIOS_POLLED";
+ else if (priv->mode == TERMIOS_TASK_DRIVEN)
+ str1 = "TERMIOS_TASK_DRIVEN";
+ else if (priv->mode == TERMIOS_TASK_DRIVEN)
+ str1 = "TERMIOS_TASK_DRIVEN";
+ else
+ str1 = "BAD MODE";
+
+ sprintf(buf, "UART Mode: %s", str1);
+ print_line(p, buf);
+ if (priv->condev.fsname) {
+ sprintf(buf, "FS Name: %s", priv->condev.fsname);
+ print_line(p, buf);
+ }
+ sprintf(buf, "STATUS REG: 0x%x", priv->regs->status);
+ print_line(p, buf);
+ sprintf(buf, "CTRL REG: 0x%x", priv->regs->ctrl);
+ print_line(p, buf);
+ sprintf(buf, "SCALER REG: 0x%x baud rate %d",
+ priv->regs->scaler, apbuart_get_baud(priv));
+ print_line(p, buf);
+
+ return DRVMGR_OK;
+}
+#endif
+
+#ifndef LEON3
+/* This routine transmits a character, it will busy-wait until on character
+ * fits in the APBUART Transmit FIFO
+ */
+void apbuart_outbyte_polled(
+ struct apbuart_regs *regs,
+ unsigned char ch,
+ int do_cr_on_newline,
+ int wait_sent)
+{
+send:
+ while ((regs->status & LEON_REG_UART_STATUS_THE) == 0) {
+ /* Lower bus utilization while waiting for UART */
+ asm volatile ("nop"::); asm volatile ("nop"::);
+ asm volatile ("nop"::); asm volatile ("nop"::);
+ asm volatile ("nop"::); asm volatile ("nop"::);
+ asm volatile ("nop"::); asm volatile ("nop"::);
+ }
+ regs->data = (unsigned int) ch;
+
+ if ((ch == '\n') && do_cr_on_newline) {
+ ch = '\r';
+ goto send;
+ }
+
+ /* Wait until the character has been sent? */
+ if (wait_sent) {
+ while ((regs->status & LEON_REG_UART_STATUS_THE) == 0)
+ ;
+ }
+}
+
+/* This routine polls for one character, return EOF if no character is available */
+int apbuart_inbyte_nonblocking(struct apbuart_regs *regs)
+{
+ if (regs->status & LEON_REG_UART_STATUS_ERR) {
+ regs->status = ~LEON_REG_UART_STATUS_ERR;
+ }
+
+ if ((regs->status & LEON_REG_UART_STATUS_DR) == 0)
+ return EOF;
+
+ return (int)regs->data;
+}
+#endif
+
+int apbuart_firstOpen(int major, int minor, void *arg)
+{
+ struct apbuart_priv *uart = (struct apbuart_priv *)minor;
+ rtems_libio_open_close_args_t *ioarg = arg;
+
+ if ( ioarg && ioarg->iop )
+ uart->cookie = ioarg->iop->data1;
+ else
+ uart->cookie = NULL;
+
+ /* Enable TX/RX */
+ uart->regs->ctrl |= LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE;
+
+ if (uart->mode != TERMIOS_POLLED) {
+ /* Register interrupt and enable it */
+ drvmgr_interrupt_register(uart->dev, 0, "apbuart",
+ apbuart_isr, uart);
+
+ uart->sending = 0;
+ /* Turn on RX interrupts */
+ uart->regs->ctrl |= LEON_REG_UART_CTRL_RI;
+ }
+
+ return 0;
+}
+
+int apbuart_lastClose(int major, int minor, void *arg)
+{
+ struct apbuart_priv *uart = (struct apbuart_priv *)minor;
+
+ if (uart->mode != TERMIOS_POLLED) {
+ /* Turn off RX interrupts */
+ uart->regs->ctrl &= ~(LEON_REG_UART_CTRL_RI);
+
+ /**** Flush device ****/
+ while (uart->sending) {
+ /* Wait until all data has been sent */
+ }
+
+ /* Disable and unregister interrupt handler */
+ drvmgr_interrupt_unregister(uart->dev, 0, apbuart_isr, uart);
+ }
+
+#ifdef LEON3
+ /* Disable TX/RX if not used for DEBUG */
+ if (uart->regs != dbg_uart)
+ uart->regs->ctrl &= ~(LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE);
+#endif
+
+ return 0;
+}
+
+int apbuart_pollRead(int minor)
+{
+ struct apbuart_priv *uart = (struct apbuart_priv *)minor;
+
+ return apbuart_inbyte_nonblocking(uart->regs);
+}
+
+int apbuart_pollRead_task(int minor)
+{
+ struct apbuart_priv *uart = (struct apbuart_priv *)minor;
+ int c, tot;
+ char buf[32];
+
+ tot = 0;
+ while ((c=apbuart_inbyte_nonblocking(uart->regs)) != EOF) {
+ buf[tot] = c;
+ tot++;
+ if (tot > 31) {
+ rtems_termios_enqueue_raw_characters(uart->cookie, buf, tot);
+ tot = 0;
+ }
+ }
+ if (tot > 0)
+ rtems_termios_enqueue_raw_characters(uart->cookie, buf, tot);
+
+ return EOF;
+}
+
+struct apbuart_baud {
+ unsigned int num;
+ unsigned int baud;
+};
+struct apbuart_baud apbuart_baud_table[] = {
+ {B50, 50},
+ {B75, 75},
+ {B110, 110},
+ {B134, 134},
+ {B150, 150},
+ {B200, 200},
+ {B300, 300},
+ {B600, 600},
+ {B1200, 1200},
+ {B1800, 1800},
+ {B2400, 2400},
+ {B4800, 4800},
+ {B9600, 9600},
+ {B19200, 19200},
+ {B38400, 38400},
+ {B57600, 57600},
+ {B115200, 115200},
+ {B230400, 230400},
+ {B460800, 460800},
+};
+#define BAUD_NUM (sizeof(apbuart_baud_table)/sizeof(struct apbuart_baud))
+
+int apbuart_baud_num2baud(unsigned int num)
+{
+ int i;
+
+ for(i=0; i<BAUD_NUM; i++)
+ if (apbuart_baud_table[i].num == num)
+ return apbuart_baud_table[i].baud;
+ return -1;
+}
+
+struct apbuart_baud *apbuart_baud_find_closest(unsigned int baud)
+{
+ int i, diff;
+
+ for(i=0; i<BAUD_NUM-1; i++) {
+ diff = apbuart_baud_table[i+1].baud -
+ apbuart_baud_table[i].baud;
+ if (baud < (apbuart_baud_table[i].baud + diff/2))
+ return &apbuart_baud_table[i];
+ }
+ return &apbuart_baud_table[BAUD_NUM-1];
+}
+
+int apbuart_get_baud(struct apbuart_priv *uart)
+{
+ unsigned int core_clk_hz;
+ unsigned int scaler;
+
+ /* Get current scaler setting */
+ scaler = uart->regs->scaler;
+
+ /* Get APBUART core frequency */
+ drvmgr_freq_get(uart->dev, DEV_APB_SLV, &core_clk_hz);
+
+ /* Calculate baud rate from generator "scaler" number */
+ return core_clk_hz / ((scaler + 1) * 8);
+}
+
+struct apbuart_baud *apbuart_get_baud_closest(struct apbuart_priv *uart)
+{
+ return apbuart_baud_find_closest(apbuart_get_baud(uart));
+}
+
+int apbuart_set_attributes(int minor, const struct termios *t)
+{
+ unsigned int core_clk_hz;
+ unsigned int scaler;
+ unsigned int ctrl;
+ int baud;
+ struct apbuart_priv *uart = (struct apbuart_priv *)minor;
+
+ switch(t->c_cflag & CSIZE) {
+ default:
+ case CS5:
+ case CS6:
+ case CS7:
+ /* Hardware doesn't support other than CS8 */
+ return -1;
+ case CS8:
+ break;
+ }
+
+ /* Read out current value */
+ ctrl = uart->regs->ctrl;
+
+ switch(t->c_cflag & (PARENB|PARODD)){
+ case (PARENB|PARODD):
+ /* Odd parity */
+ ctrl |= LEON_REG_UART_CTRL_PE|LEON_REG_UART_CTRL_PS;
+ break;
+
+ case PARENB:
+ /* Even parity */
+ ctrl &= ~LEON_REG_UART_CTRL_PS;
+ ctrl |= LEON_REG_UART_CTRL_PE;
+ break;
+
+ default:
+ case 0:
+ case PARODD:
+ /* No Parity */
+ ctrl &= ~(LEON_REG_UART_CTRL_PS|LEON_REG_UART_CTRL_PE);
+ }
+
+ if (!(t->c_cflag & CLOCAL))
+ ctrl |= LEON_REG_UART_CTRL_FL;
+ else
+ ctrl &= ~LEON_REG_UART_CTRL_FL;
+
+ /* Update new settings */
+ uart->regs->ctrl = ctrl;
+
+ /* Baud rate */
+ baud = apbuart_baud_num2baud(t->c_cflag & CBAUD);
+ if (baud > 0){
+ /* Get APBUART core frequency */
+ drvmgr_freq_get(uart->dev, DEV_APB_SLV, &core_clk_hz);
+
+ /* Calculate Baud rate generator "scaler" number */
+ scaler = (((core_clk_hz*10)/(baud*8))-5)/10;
+
+ /* Set new baud rate by setting scaler */
+ uart->regs->scaler = scaler;
+ }
+
+ return 0;
+}
+
+void apbuart_get_attributes(struct console_dev *condev, struct termios *t)
+{
+ struct apbuart_priv *uart = (struct apbuart_priv *)condev;
+ unsigned int ctrl;
+ struct apbuart_baud *baud;
+
+ t->c_cflag = t->c_cflag & ~(CSIZE|PARENB|PARODD|CLOCAL|CBAUD);
+
+ /* Hardware support only CS8 */
+ t->c_cflag |= CS8;
+
+ /* Read out current parity */
+ ctrl = uart->regs->ctrl;
+ if (ctrl & LEON_REG_UART_CTRL_PE) {
+ if (ctrl & LEON_REG_UART_CTRL_PS)
+ t->c_cflag |= PARENB|PARODD; /* Odd parity */
+ else
+ t->c_cflag |= PARENB; /* Even parity */
+ }
+
+ if ((ctrl & LEON_REG_UART_CTRL_FL) == 0)
+ t->c_cflag |= CLOCAL;
+
+ baud = apbuart_get_baud_closest(uart);
+ t->c_cflag |= baud->num;
+}
+
+ssize_t apbuart_write_polled(int minor, const char *buf, size_t len)
+{
+ int nwrite = 0;
+ struct apbuart_priv *uart = (struct apbuart_priv *)minor;
+
+ while (nwrite < len) {
+ apbuart_outbyte_polled(uart->regs, *buf++, 0, 0);
+ nwrite++;
+ }
+ return nwrite;
+}
+
+ssize_t apbuart_write_intr(int minor, const char *buf, size_t len)
+{
+ struct apbuart_priv *uart = (struct apbuart_priv *)minor;
+ unsigned int oldLevel;
+ unsigned int ctrl;
+
+ rtems_interrupt_disable(oldLevel);
+
+ /* Enable TX interrupt */
+ ctrl = uart->regs->ctrl;
+ uart->regs->ctrl = ctrl | LEON_REG_UART_CTRL_TI;
+
+ if (ctrl & LEON_REG_UART_CTRL_FA) {
+ /* APBUART with FIFO.. Fill as many as FIFO allows */
+ uart->sending = 0;
+ while (((uart->regs->status & LEON_REG_UART_STATUS_TF) == 0) &&
+ (uart->sending < len)) {
+ uart->regs->data = *buf;
+ buf++;
+ uart->sending++;
+ }
+ } else {
+ /* start UART TX, this will result in an interrupt when done */
+ uart->regs->data = *buf;
+
+ uart->sending = 1;
+ }
+
+ rtems_interrupt_enable(oldLevel);
+
+ return 0;
+}
+
+/* Handle UART interrupts */
+void apbuart_isr(void *arg)
+{
+ struct apbuart_priv *uart = arg;
+ unsigned int status;
+ char data;
+ int cnt;
+
+ /* Get all received characters */
+ if (uart->mode == TERMIOS_TASK_DRIVEN) {
+ if ((status=uart->regs->status) & LEON_REG_UART_STATUS_DR)
+ rtems_termios_rxirq_occured(uart->cookie);
+ } else {
+ while ((status=uart->regs->status) & LEON_REG_UART_STATUS_DR) {
+ /* Data has arrived, get new data */
+ data = uart->regs->data;
+
+ /* Tell termios layer about new character */
+ rtems_termios_enqueue_raw_characters(uart->cookie, &data, 1);
+ }
+ }
+
+ if (uart->sending && (status & LEON_REG_UART_STATUS_THE)) {
+ /* Sent the one char, we disable TX interrupts */
+ uart->regs->ctrl &= ~LEON_REG_UART_CTRL_TI;
+
+ /* Tell close that we sent everything */
+ cnt = uart->sending;
+ uart->sending = 0;
+
+ /* apbuart_write_intr() will get called from this function */
+ rtems_termios_dequeue_characters(uart->cookie, cnt);
+ }
+}
diff --git a/c/src/lib/libbsp/sparc/shared/uart/apbuart_pci.c b/c/src/lib/libbsp/sparc/shared/uart/apbuart_pci.c
deleted file mode 100644
index 54d14ce459..0000000000
--- a/c/src/lib/libbsp/sparc/shared/uart/apbuart_pci.c
+++ /dev/null
@@ -1,42 +0,0 @@
-
-#undef DEBUG
-
-/* Set registered device name */
-#define APBUART_DEVNAME "/dev/apbupci0"
-#define APBUART_DEVNAME_NO(devstr,no) ((devstr)[12]='0'+(no))
-
-/* Any non-static function will begin with */
-#define APBUART_PREFIX(name) apbuartpci##name
-
-/* do nothing, assume that the interrupt handler is called
- * setup externally calling apbuartpci_interrupt_handler.
- */
-#define APBUART_REG_INT(handler,irq,arg) \
- if ( apbuart_pci_int_reg ) \
- apbuart_pci_int_reg(handler,irq,arg);
-
-void (*apbuart_pci_int_reg)(void *handler, int irq, void *arg) = 0;
-
-void apbuartpci_interrupt_handler(int irq, void *arg);
-
-/* AMBA Bus is clocked using the PCI clock (33.3MHz) */
-#define SYS_FREQ_HZ 33333333
-
-#include "apbuart.c"
-
-int apbuart_pci_register(amba_confarea_type *bus)
-{
- /* Setup configuration */
-
- /* Register the driver */
- return APBUART_PREFIX(_register)(bus);
-}
-
-
-/* Call this from PCI interrupt handler
- * irq = the irq number of the HW device local to that IRQMP controller
- *
- */
-void apbuartpci_interrupt_handler(int irq, void *arg){
- apbuart_interrupt(arg);
-}
diff --git a/c/src/lib/libbsp/sparc/shared/uart/apbuart_rasta.c b/c/src/lib/libbsp/sparc/shared/uart/apbuart_rasta.c
deleted file mode 100644
index 4b8734fdb6..0000000000
--- a/c/src/lib/libbsp/sparc/shared/uart/apbuart_rasta.c
+++ /dev/null
@@ -1,42 +0,0 @@
-
-#undef DEBUG
-
-/* Set registered device name */
-#define APBUART_DEVNAME "/dev/apburasta0"
-#define APBUART_DEVNAME_NO(devstr,no) ((devstr)[14]='0'+(no))
-
-/* Any non-static function will begin with */
-#define APBUART_PREFIX(name) apbuartrasta##name
-
-/* do nothing, assume that the interrupt handler is called
- * setup externally calling apbuartrasta_interrupt_handler.
- */
-#define APBUART_REG_INT(handler,irq,arg) \
- if ( apbuart_rasta_int_reg ) \
- apbuart_rasta_int_reg(handler,irq,arg);
-
-void (*apbuart_rasta_int_reg)(void *handler, int irq, void *arg) = 0;
-
-void apbuartrasta_interrupt_handler(int irq, void *arg);
-
-/* AMBA Bus is clocked using the RASTA internal clock (30MHz) */
-#define SYS_FREQ_HZ 30000000
-
-#include "apbuart.c"
-
-int apbuart_rasta_register(amba_confarea_type *bus)
-{
- /* Setup configuration */
-
- /* Register the driver */
- return APBUART_PREFIX(_register)(bus);
-}
-
-
-/* Call this from RASTA interrupt handler
- * irq = the irq number of the HW device local to that IRQMP controller
- *
- */
-void apbuartrasta_interrupt_handler(int irq, void *arg){
- apbuart_interrupt(arg);
-}
diff --git a/c/src/lib/libbsp/sparc/shared/uart/cons.c b/c/src/lib/libbsp/sparc/shared/uart/cons.c
new file mode 100644
index 0000000000..981fb956d6
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/uart/cons.c
@@ -0,0 +1,189 @@
+/* This file contains the TTY driver for the serial ports. The driver
+ * is layered so that different UART hardware can be used. It is implemented
+ * using the Driver Manager.
+ *
+ * This driver uses the termios pseudo driver.
+ *
+ * COPYRIGHT (c) 2010.
+ * Aeroflex Gaisler
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#include <bsp.h>
+#include <stdlib.h>
+#include <rtems/libio.h>
+#include <rtems/bspIo.h>
+#include <cons.h>
+
+#ifdef RTEMS_DRVMGR_STARTUP
+
+/* Note that it is not possible to use the interrupt mode of the driver
+ * together with the "old" APBUART and -u to GRMON. However the new
+ * APBUART core (from 1.0.17-b2710) has the GRMON debug bit and can
+ * handle interrupts.
+ */
+
+int console_initialized = 0;
+rtems_device_major_number console_major = 0;
+
+#define FLAG_SYSCON 0x01
+struct console_priv {
+ unsigned char flags; /* 0x1=SystemConsole */
+ unsigned char minor;
+ struct console_dev *dev;
+};
+
+#define CONSOLE_MAX BSP_NUMBER_OF_TERMIOS_PORTS
+struct console_priv cons[CONSOLE_MAX] = {{0,0},};
+
+/* Register Console to TERMIOS layer and initialize it */
+void console_dev_init(struct console_priv *con, int minor)
+{
+ char name[16], *fsname;
+ rtems_status_code status;
+
+ if (!con->dev->fsname) {
+ strcpy(name, "/dev/console_a");
+ /* Special console name and MINOR for SYSTEM CONSOLE */
+ if (minor == 0)
+ name[12] = '\0'; /* /dev/console */
+ name[13] += minor; /* when minor=0, this has no effect... */
+ fsname = name;
+ } else {
+ fsname = con->dev->fsname;
+ }
+ status = rtems_io_register_name(fsname, console_major, minor);
+ if ((minor == 0) && (status != RTEMS_SUCCESSFUL))
+ rtems_fatal_error_occurred(status);
+}
+
+void console_dev_register(struct console_dev *dev)
+{
+ int i, minor = 0;
+ struct console_priv *con = NULL;
+
+ if ((dev->flags & CONSOLE_FLAG_SYSCON) && !cons[0].dev) {
+ con = &cons[0];
+ con->flags = FLAG_SYSCON;
+ } else {
+ for (i=1; i<CONSOLE_MAX; i++) {
+ if (!cons[i].dev) {
+ con = &cons[i];
+ con->flags = 0;
+ minor = i;
+ break;
+ }
+ }
+ }
+ if (con == NULL) {
+ /* Not enough console structures */
+ return;
+ }
+
+ /* Assign Console */
+ con->dev = dev;
+ con->minor = minor;
+
+ /* Console layer is already initialized, that means that we can
+ * register termios interface directly.
+ */
+ if (console_initialized)
+ console_dev_init(con, minor);
+}
+
+#if 0
+void console_dev_unregister(struct console_dev *dev)
+{
+
+}
+#endif
+
+rtems_device_driver console_initialize(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg)
+{
+ int i;
+
+ console_major = major;
+
+ rtems_termios_initialize();
+
+ /* Register all Console a file system device node */
+ for (i=0; i<CONSOLE_MAX; i++) {
+ if (cons[i].dev)
+ console_dev_init(&cons[i], i);
+ }
+
+ console_initialized = 1;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+rtems_device_driver console_open(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg)
+{
+ rtems_status_code status;
+ struct termios term;
+
+ if ((minor >= CONSOLE_MAX) || !cons[minor].dev)
+ return RTEMS_INVALID_NUMBER;
+
+ status = rtems_termios_open(
+ major,
+ (int)cons[minor].dev,
+ arg,
+ cons[minor].dev->callbacks);
+
+ /* Inherit UART hardware parameters from bootloader on system console */
+ if ((status == RTEMS_SUCCESSFUL) && (cons[minor].flags & FLAG_SYSCON) &&
+ (cons[minor].dev->ops.get_uart_attrs != NULL)) {
+ if (tcgetattr(STDIN_FILENO, &term) >= 0) {
+ cons[minor].dev->ops.get_uart_attrs(cons[minor].dev,
+ &term);
+ term.c_oflag |= ONLCR;
+ tcsetattr(STDIN_FILENO, TCSANOW, &term);
+ }
+ }
+
+ return status;
+}
+
+rtems_device_driver console_close(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg)
+{
+ return rtems_termios_close(arg);
+}
+
+rtems_device_driver console_read(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg)
+{
+ return rtems_termios_read(arg);
+}
+
+rtems_device_driver console_write(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg)
+{
+ return rtems_termios_write(arg);
+}
+
+rtems_device_driver console_control(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg)
+{
+ return rtems_termios_ioctl(arg);
+}
+
+#endif
diff --git a/c/src/lib/libcpu/sparc/Makefile.am b/c/src/lib/libcpu/sparc/Makefile.am
index 7bebd9417e..711d6b1fa8 100644
--- a/c/src/lib/libcpu/sparc/Makefile.am
+++ b/c/src/lib/libcpu/sparc/Makefile.am
@@ -10,6 +10,8 @@ noinst_PROGRAMS =
include_libcpudir = $(includedir)/libcpu
include_libcpu_HEADERS = ../shared/include/cache.h
+include_libcpu_HEADERS += include/libcpu/byteorder.h
+include_libcpu_HEADERS += include/libcpu/access.h
noinst_PROGRAMS += cache.rel
cache_rel_SOURCES = cache/cache.c cache/cache_.h \
@@ -31,5 +33,10 @@ reg_win_rel_SOURCES = reg_win/window.S
reg_win_rel_CPPFLAGS = $(AM_CPPFLAGS)
reg_win_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
+noinst_PROGRAMS += access.rel
+access_rel_SOURCES = access/access.S access/access_le.c
+access_rel_CPPFLAGS = $(AM_CPPFLAGS)
+access_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
+
include $(srcdir)/preinstall.am
include $(top_srcdir)/../../../automake/local.am
diff --git a/c/src/lib/libcpu/sparc/access/access.S b/c/src/lib/libcpu/sparc/access/access.S
new file mode 100644
index 0000000000..7e69f64c9d
--- /dev/null
+++ b/c/src/lib/libcpu/sparc/access/access.S
@@ -0,0 +1,65 @@
+/*
+ * Access routines for SPARC
+ *
+ * COPYRIGHT (c) 2011
+ * Aeroflex Gaisler.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#include <rtems/asm.h>
+
+ .align 4
+ .seg "text"
+ PUBLIC(_ld8)
+ PUBLIC(_ld16)
+ PUBLIC(_ld32)
+ PUBLIC(_ld64)
+ PUBLIC(_st8)
+ PUBLIC(_st16)
+ PUBLIC(_st32)
+ PUBLIC(_st64)
+ PUBLIC(_ld_be16)
+ PUBLIC(_ld_be32)
+ PUBLIC(_st_be16)
+ PUBLIC(_st_be32)
+
+SYM(_ld8):
+ retl
+ ldub [%o0], %o0
+
+SYM(_ld_be16):
+SYM(_ld16):
+ retl
+ lduh [%o0], %o0
+
+SYM(_ld_be32):
+SYM(_ld32):
+ retl
+ ld [%o0], %o0
+
+SYM(_ld_be64):
+SYM(_ld64):
+ retl
+ ldd [%o0], %o0
+
+SYM(_st8):
+ retl
+ stub %o1, [%o0]
+
+SYM(_st_be16):
+SYM(_st16):
+ retl
+ stuh %o1, [%o0]
+
+SYM(_st_be32):
+SYM(_st32):
+ retl
+ st %o1, [%o0]
+
+SYM(_st_be64):
+SYM(_st64):
+ retl
+ std %o1, [%o0]
diff --git a/c/src/lib/libcpu/sparc/access/access_le.c b/c/src/lib/libcpu/sparc/access/access_le.c
new file mode 100644
index 0000000000..15031ccf50
--- /dev/null
+++ b/c/src/lib/libcpu/sparc/access/access_le.c
@@ -0,0 +1,32 @@
+/*
+ * Little-endian access routines for SPARC
+ *
+ * COPYRIGHT (c) 2011
+ * Aeroflex Gaisler.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#include <libcpu/byteorder.h>
+
+uint16_t _ld_le16(uint16_t *addr)
+{
+ return ld_le16(addr);
+}
+
+void _st_le16(uint16_t *addr, uint16_t val)
+{
+ st_le16(addr, val);
+}
+
+uint32_t _ld_le32(uint32_t *addr)
+{
+ return ld_le32(addr);
+}
+
+void _st_le32(uint32_t *addr, uint32_t val)
+{
+ st_le32(addr, val);
+}
diff --git a/c/src/lib/libcpu/sparc/include/libcpu/access.h b/c/src/lib/libcpu/sparc/include/libcpu/access.h
new file mode 100644
index 0000000000..2d87c2ad48
--- /dev/null
+++ b/c/src/lib/libcpu/sparc/include/libcpu/access.h
@@ -0,0 +1,48 @@
+/*
+ * access.h - access routines for SPARC. SPARC is big endian only.
+ *
+ * COPYRIGHT (c) 2011
+ * Aeroflex Gaisler.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#ifndef _LIBCPU_ACCESS_H
+#define _LIBCPU_ACCESS_H
+
+#include <rtems/system.h>
+#include <rtems/score/cpu.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* "Raw" access */
+extern uint8_t _ld8(uint8_t *addr);
+extern void _st8(uint8_t *addr, uint8_t val);
+extern uint16_t _ld16(uint16_t *addr);
+extern void _st16(uint16_t *addr, uint16_t val);
+extern uint32_t _ld32(uint32_t *addr);
+extern void _st32(uint32_t *addr, uint32_t val);
+extern uint64_t _ld64(uint64_t *addr);
+extern void _st64(uint64_t *addr, uint64_t val);
+
+/* Aliases for Big Endian */
+extern uint16_t _ld_be16(uint16_t *addr);
+extern void _st_be16(uint16_t *addr, uint16_t val);
+extern uint32_t _ld_be32(uint32_t *addr);
+extern void _st_be32(uint32_t *addr, uint32_t val);
+
+/* Little endian */
+extern uint16_t _ld_le16(uint16_t *addr);
+extern void _st_le16(uint16_t *addr, uint16_t val);
+extern uint32_t _ld_le32(uint32_t *addr);
+extern void _st_le32(uint32_t *addr, uint32_t val);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/c/src/lib/libcpu/sparc/include/libcpu/byteorder.h b/c/src/lib/libcpu/sparc/include/libcpu/byteorder.h
new file mode 100644
index 0000000000..d626f28068
--- /dev/null
+++ b/c/src/lib/libcpu/sparc/include/libcpu/byteorder.h
@@ -0,0 +1,66 @@
+/*
+ * byteorder.h - Endian conversion for SPARC. SPARC is big endian only.
+ *
+ * COPYRIGHT (c) 2011
+ * Aeroflex Gaisler.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#ifndef _LIBCPU_BYTEORDER_H
+#define _LIBCPU_BYTEORDER_H
+
+#include <rtems/system.h>
+#include <rtems/score/cpu.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+RTEMS_INLINE_ROUTINE uint16_t ld_le16(volatile uint16_t *addr)
+{
+ return CPU_swap_u16(*addr);
+}
+
+RTEMS_INLINE_ROUTINE void st_le16(volatile uint16_t *addr, uint16_t val)
+{
+ *addr = CPU_swap_u16(val);
+}
+
+RTEMS_INLINE_ROUTINE uint32_t ld_le32(volatile uint32_t *addr)
+{
+ return CPU_swap_u32(*addr);
+}
+
+RTEMS_INLINE_ROUTINE void st_le32(volatile uint32_t *addr, uint32_t val)
+{
+ *addr = CPU_swap_u32(val);
+}
+
+RTEMS_INLINE_ROUTINE uint16_t ld_be16(volatile uint16_t *addr)
+{
+ return *addr;
+}
+
+RTEMS_INLINE_ROUTINE void st_be16(volatile uint16_t *addr, uint16_t val)
+{
+ *addr = val;
+}
+
+RTEMS_INLINE_ROUTINE uint32_t ld_be32(volatile uint32_t *addr)
+{
+ return *addr;
+}
+
+RTEMS_INLINE_ROUTINE void st_be32(volatile uint32_t *addr, uint32_t val)
+{
+ *addr = val;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/c/src/lib/libcpu/sparc/preinstall.am b/c/src/lib/libcpu/sparc/preinstall.am
index 412b683681..2efe38bb30 100644
--- a/c/src/lib/libcpu/sparc/preinstall.am
+++ b/c/src/lib/libcpu/sparc/preinstall.am
@@ -22,3 +22,11 @@ $(PROJECT_INCLUDE)/libcpu/cache.h: ../shared/include/cache.h $(PROJECT_INCLUDE)/
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/libcpu/cache.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/libcpu/cache.h
+$(PROJECT_INCLUDE)/libcpu/byteorder.h: include/libcpu/byteorder.h $(PROJECT_INCLUDE)/libcpu/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/libcpu/byteorder.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/libcpu/byteorder.h
+
+$(PROJECT_INCLUDE)/libcpu/access.h: include/libcpu/access.h $(PROJECT_INCLUDE)/libcpu/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/libcpu/access.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/libcpu/access.h
+
diff --git a/c/src/lib/libcpu/sparc/reg_win/window.S b/c/src/lib/libcpu/sparc/reg_win/window.S
index e28774d74e..3ec3f50a10 100644
--- a/c/src/lib/libcpu/sparc/reg_win/window.S
+++ b/c/src/lib/libcpu/sparc/reg_win/window.S
@@ -130,8 +130,7 @@ SYM(window_underflow_trap_handler):
/*
* Flush All Windows trap handler.
*
- * Flush all windows with valid contents except the current one
- * and the one we will be returning to.
+ * Flush all windows with valid contents except the current one.
*
* In examining the set register windows, one may logically divide
* the windows into sets (some of which may be empty) based on their
@@ -154,8 +153,8 @@ SYM(window_underflow_trap_handler):
* + 5 - current
* + 6-7 - used
*
- * In this case, we only would save the used windows which we
- * will not be returning to -- 6.
+ * In this case, we only would save the used windows 6 and 7, but
+ * not 5.
*
* Register Usage while saving the windows:
* g1 = current PSR
@@ -194,22 +193,9 @@ SYM(window_flush_trap_handler):
mov 1, %g4
sll %g4, %g5, %g4 ! g4 = WIM mask for CWP+1 invalid
- restore ! go back one register window
-
save_frame_loop:
- sll %g4, 1, %g5 ! rotate the "wim" left 1
- srl %g4, SPARC_NUMBER_OF_REGISTER_WINDOWS - 1, %g4
- or %g4, %g5, %g4 ! g4 = wim if we do one restore
- /*
- * If a restore would not underflow, then continue.
- */
-
- andcc %g4, %g2, %g0 ! Any windows to flush?
- bnz done_flushing ! No, then continue
- nop
-
- restore ! back one window
+ restore ! go back one register window
/*
* Now save the window just as if we overflowed to it.
@@ -225,8 +211,17 @@ save_frame_loop:
std %i4, [%sp + CPU_STACK_FRAME_I4_OFFSET]
std %i6, [%sp + CPU_STACK_FRAME_I6_FP_OFFSET]
- ba save_frame_loop
- nop
+ sll %g4, 1, %g5 ! rotate the "wim" left 1
+ srl %g4, SPARC_NUMBER_OF_REGISTER_WINDOWS - 1, %g4
+ or %g4, %g5, %g4 ! g4 = wim if we do one restore
+
+ /*
+ * If a restore would not underflow, then continue.
+ */
+
+ andcc %g4, %g2, %g0 ! Any windows to flush?
+ be save_frame_loop ! Yes, then continue saving
+ nop
done_flushing:
diff --git a/c/src/libchip/network/greth.c b/c/src/libchip/network/greth.c
index 257a16c928..6cd5bd198f 100644
--- a/c/src/libchip/network/greth.c
+++ b/c/src/libchip/network/greth.c
@@ -12,10 +12,10 @@
*/
#include <rtems.h>
-
-#define GRETH_SUPPORTED
#include <bsp.h>
+#ifdef GRETH_SUPPORTED
+
#include <inttypes.h>
#include <errno.h>
#include <rtems/bspIo.h>
@@ -42,19 +42,17 @@
#undef free
#endif
-#if defined(__m68k__)
-extern m68k_isr_entry set_vector( rtems_isr_entry, rtems_vector_number, int );
-#else
-extern rtems_isr_entry set_vector( rtems_isr_entry, rtems_vector_number, int );
-#endif
-
-
/* #define GRETH_DEBUG */
#ifdef CPU_U32_FIX
extern void ipalign(struct mbuf *m);
#endif
+/* Used when reading from memory written by GRETH DMA unit */
+#ifndef GRETH_MEM_LOAD
+#define GRETH_MEM_LOAD(addr) (*(volatile unsigned int *)(addr))
+#endif
+
/*
* Number of OCs supported by this driver
*/
@@ -82,11 +80,6 @@ extern void ipalign(struct mbuf *m);
/* event to send when tx buffers become available */
#define GRETH_TX_WAIT_EVENT RTEMS_EVENT_3
- /* suspend when all TX descriptors exhausted */
- /*
-#define GRETH_SUSPEND_NOTXBUF
- */
-
#if (MCLBYTES < RBUF_SIZE)
# error "Driver must have MCLBYTES > RBUF_SIZE"
#endif
@@ -95,6 +88,10 @@ extern void ipalign(struct mbuf *m);
#ifndef GRETH_AUTONEGO_TIMEOUT_MS
#define GRETH_AUTONEGO_TIMEOUT_MS 4000
#endif
+const struct timespec greth_tan = {
+ GRETH_AUTONEGO_TIMEOUT_MS/1000,
+ GRETH_AUTONEGO_TIMEOUT_MS*1000000
+};
/* For optimizing the autonegotiation time */
#define GRETH_AUTONEGO_PRINT_TIME
@@ -118,8 +115,7 @@ struct greth_softc
greth_regs *regs;
int acceptBroadcast;
- rtems_id rxDaemonTid;
- rtems_id txDaemonTid;
+ rtems_id daemonTid;
unsigned int tx_ptr;
unsigned int tx_dptr;
@@ -131,7 +127,13 @@ struct greth_softc
greth_rxtxdesc *rxdesc;
struct mbuf **rxmbuf;
struct mbuf **txmbuf;
- rtems_vector_number vector;
+ int irq;
+
+ /* TX descriptor interrupt generation */
+ int tx_int_gen;
+ int tx_int_gen_cur;
+ struct mbuf *next_tx_mbuf;
+ int max_fragsize;
/*Status*/
struct phy_device_info phydev;
@@ -140,7 +142,7 @@ struct greth_softc
int gb;
int gbit_mac;
int auto_neg;
- unsigned int auto_neg_time;
+ struct timespec auto_neg_time;
/*
* Statistics
@@ -165,6 +167,9 @@ struct greth_softc
static struct greth_softc greth;
+int greth_process_tx_gbit(struct greth_softc *sc);
+int greth_process_tx(struct greth_softc *sc);
+
static char *almalloc(int sz)
{
char *tmp;
@@ -175,33 +180,39 @@ static char *almalloc(int sz)
/* GRETH interrupt handler */
-static rtems_isr
-greth_interrupt_handler (rtems_vector_number v)
+void greth_interrupt_handler (void *arg)
{
uint32_t status;
- /* read and clear interrupt cause */
+ uint32_t ctrl;
+ rtems_event_set events = 0;
+ /* read and clear interrupt cause */
status = greth.regs->status;
greth.regs->status = status;
+ ctrl = greth.regs->ctrl;
/* Frame received? */
- if (status & (GRETH_STATUS_RXERR | GRETH_STATUS_RXIRQ))
+ if ((ctrl & GRETH_CTRL_RXIRQ) && (status & (GRETH_STATUS_RXERR | GRETH_STATUS_RXIRQ)))
{
greth.rxInterrupts++;
- rtems_event_send (greth.rxDaemonTid, INTERRUPT_EVENT);
+ /* Stop RX-Error and RX-Packet interrupts */
+ ctrl &= ~GRETH_CTRL_RXIRQ;
+ events |= INTERRUPT_EVENT;
}
-#ifdef GRETH_SUSPEND_NOTXBUF
- if (status & (GRETH_STATUS_TXERR | GRETH_STATUS_TXIRQ))
+
+ if ( (ctrl & GRETH_CTRL_TXIRQ) && (status & (GRETH_STATUS_TXERR | GRETH_STATUS_TXIRQ)) )
{
greth.txInterrupts++;
- rtems_event_send (greth.txDaemonTid, GRETH_TX_WAIT_EVENT);
+ ctrl &= ~GRETH_CTRL_TXIRQ;
+ events |= GRETH_TX_WAIT_EVENT;
}
-#endif
- /*
- #ifdef __leon__
- LEON_Clear_interrupt(v-0x10);
- #endif
- */
+
+ /* Clear interrupt sources */
+ greth.regs->ctrl = ctrl;
+
+ /* Send the event(s) */
+ if ( events )
+ rtems_event_send (greth.daemonTid, events);
}
static uint32_t read_mii(uint32_t phy_addr, uint32_t reg_addr)
@@ -228,6 +239,9 @@ static void write_mii(uint32_t phy_addr, uint32_t reg_addr, uint32_t data)
static void print_init_info(struct greth_softc *sc)
{
printf("greth: driver attached\n");
+ if ( sc->auto_neg == -1 ){
+ printf("Auto negotiation timed out. Selecting default config\n");
+ }
printf("**** PHY ****\n");
printf("Vendor: %x Device: %x Revision: %d\n",sc->phydev.vendor, sc->phydev.device, sc->phydev.rev);
printf("Current Operating Mode: ");
@@ -244,8 +258,9 @@ static void print_init_info(struct greth_softc *sc)
printf("Half Duplex\n");
}
#ifdef GRETH_AUTONEGO_PRINT_TIME
- if ( sc->auto_neg ){
- printf("Autonegotiation Time: %dms\n",sc->auto_neg_time);
+ if ( sc->auto_neg ) {
+ printf("Autonegotiation Time: %dms\n", sc->auto_neg_time.tv_sec * 1000 +
+ sc->auto_neg_time.tv_nsec / 1000000);
}
#endif
}
@@ -264,8 +279,7 @@ greth_initialize_hardware (struct greth_softc *sc)
int phystatus;
int tmp1;
int tmp2;
- unsigned int msecs;
- struct timeval tstart, tnow;
+ struct timespec tstart, tnow;
greth_regs *regs;
@@ -300,42 +314,27 @@ greth_initialize_hardware (struct greth_softc *sc)
sc->fd = 0;
sc->sp = 0;
sc->auto_neg = 0;
- sc->auto_neg_time = 0;
+ _Timespec_Set_to_zero(&sc->auto_neg_time);
if ((phyctrl >> 12) & 1) {
/*wait for auto negotiation to complete*/
- msecs = 0;
sc->auto_neg = 1;
- if ( rtems_clock_get_tod_timeval(&tstart) == RTEMS_NOT_DEFINED){
- /* Not inited, set to epoch */
- rtems_time_of_day time;
- time.year = 1988;
- time.month = 1;
- time.day = 1;
- time.hour = 0;
- time.minute = 0;
- time.second = 0;
- time.ticks = 0;
- rtems_clock_set(&time);
-
- tstart.tv_sec = 0;
- tstart.tv_usec = 0;
- rtems_clock_get_tod_timeval(&tstart);
- }
+ if (rtems_clock_get_uptime(&tstart) != RTEMS_SUCCESSFUL)
+ printk("rtems_clock_get_uptime failed\n");
while (!(((phystatus = read_mii(phyaddr, 1)) >> 5) & 1)) {
- if ( rtems_clock_get_tod_timeval(&tnow) != RTEMS_SUCCESSFUL )
- printk("rtems_clock_get_tod_timeval failed\n\r");
- msecs = (tnow.tv_sec-tstart.tv_sec)*1000+(tnow.tv_usec-tstart.tv_usec)/1000;
- if ( msecs > GRETH_AUTONEGO_TIMEOUT_MS ){
- sc->auto_neg_time = msecs;
- printk("Auto negotiation timed out. Selecting default config\n\r");
+ if (rtems_clock_get_uptime(&tnow) != RTEMS_SUCCESSFUL)
+ printk("rtems_clock_get_uptime failed\n");
+ _Timespec_Subtract(&tstart, &tnow, &sc->auto_neg_time);
+ if (_Timespec_Greater_than(&sc->auto_neg_time, &greth_tan)) {
+ sc->auto_neg = -1; /* Failed */
tmp1 = read_mii(phyaddr, 0);
sc->gb = ((phyctrl >> 6) & 1) && !((phyctrl >> 13) & 1);
sc->sp = !((phyctrl >> 6) & 1) && ((phyctrl >> 13) & 1);
sc->fd = (phyctrl >> 8) & 1;
goto auto_neg_done;
}
+ /* Wait about 30ms, time is PHY dependent */
+ rtems_task_wake_after(rtems_clock_get_ticks_per_second()/32);
}
- sc->auto_neg_time = msecs;
sc->phydev.adv = read_mii(phyaddr, 4);
sc->phydev.part = read_mii(phyaddr, 5);
if ((phystatus >> 8) & 1) {
@@ -376,7 +375,7 @@ auto_neg_done:
phystatus = read_mii(phyaddr, 1);
/*Read out PHY info if extended registers are available */
- if (phystatus & 1) {
+ if (phystatus & 1) {
tmp1 = read_mii(phyaddr, 2);
tmp2 = read_mii(phyaddr, 3);
@@ -463,24 +462,71 @@ auto_neg_done:
mac_addr_lsb |= sc->arpcom.ac_enaddr[5];
regs->mac_addr_lsb = mac_addr_lsb;
- /* install interrupt vector */
- set_vector(greth_interrupt_handler, sc->vector, 1);
+ if ( sc->rxbufs < 10 ) {
+ sc->tx_int_gen = sc->tx_int_gen_cur = 1;
+ }else{
+ sc->tx_int_gen = sc->tx_int_gen_cur = sc->txbufs/2;
+ }
+ sc->next_tx_mbuf = NULL;
+
+ if ( !sc->gbit_mac )
+ sc->max_fragsize = 1;
/* clear all pending interrupts */
-
regs->status = 0xffffffff;
-
-#ifdef GRETH_SUSPEND_NOTXBUF
- regs->ctrl |= GRETH_CTRL_TXIRQ;
-#endif
+
+ /* install interrupt handler */
+ rtems_interrupt_handler_install(sc->irq, "greth", RTEMS_INTERRUPT_SHARED,
+ greth_interrupt_handler, sc);
regs->ctrl |= GRETH_CTRL_RXEN | (sc->fd << 4) | GRETH_CTRL_RXIRQ | (sc->sp << 7) | (sc->gb << 8);
print_init_info(sc);
}
-static void
-greth_rxDaemon (void *arg)
+#ifdef CPU_U32_FIX
+
+/*
+ * Routine to align the received packet so that the ip header
+ * is on a 32-bit boundary. Necessary for cpu's that do not
+ * allow unaligned loads and stores and when the 32-bit DMA
+ * mode is used.
+ *
+ * Transfers are done on word basis to avoid possibly slow byte
+ * and half-word writes.
+ */
+
+void ipalign(struct mbuf *m)
+{
+ unsigned int *first, *last, data;
+ unsigned int tmp = 0;
+
+ if ((((int) m->m_data) & 2) && (m->m_len)) {
+ last = (unsigned int *) ((((int) m->m_data) + m->m_len + 8) & ~3);
+ first = (unsigned int *) (((int) m->m_data) & ~3);
+ /* tmp = *first << 16; */
+ asm volatile (" lda [%1] 1, %0\n" : "=r"(tmp) : "r"(first) );
+ tmp = tmp << 16;
+ first++;
+ do {
+ /* When snooping is not available the LDA instruction must be used
+ * to avoid the cache to return an illegal value.
+ ** Load with forced cache miss
+ * data = *first;
+ */
+ asm volatile (" lda [%1] 1, %0\n" : "=r"(data) : "r"(first) );
+ *first = tmp | (data >> 16);
+ tmp = data << 16;
+ first++;
+ } while (first <= last);
+
+ m->m_data = (caddr_t)(((int) m->m_data) + 2);
+ }
+}
+#endif
+
+void
+greth_Daemon (void *arg)
{
struct ether_header *eh;
struct greth_softc *dp = (struct greth_softc *) &greth;
@@ -488,18 +534,40 @@ greth_rxDaemon (void *arg)
struct mbuf *m;
unsigned int len, len_status, bad;
rtems_event_set events;
+ rtems_interrupt_level level;
+ int first;
+ int tmp;
+ unsigned int addr;
for (;;)
{
- rtems_bsdnet_event_receive (INTERRUPT_EVENT,
+ rtems_bsdnet_event_receive (INTERRUPT_EVENT | GRETH_TX_WAIT_EVENT,
RTEMS_WAIT | RTEMS_EVENT_ANY,
RTEMS_NO_TIMEOUT, &events);
+ if ( events & GRETH_TX_WAIT_EVENT ){
+ /* TX interrupt.
+ * We only end up here when all TX descriptors has been used,
+ * and
+ */
+ if ( dp->gbit_mac )
+ greth_process_tx_gbit(dp);
+ else
+ greth_process_tx(dp);
+
+ /* If we didn't get a RX interrupt we don't process it */
+ if ( (events & INTERRUPT_EVENT) == 0 )
+ continue;
+ }
+
#ifdef GRETH_ETH_DEBUG
printf ("r\n");
#endif
+ first=1;
+ /* Scan for Received packets */
+again:
while (!((len_status =
- dp->rxdesc[dp->rx_ptr].ctrl) & GRETH_RXD_ENABLE))
+ GRETH_MEM_LOAD(&dp->rxdesc[dp->rx_ptr].ctrl)) & GRETH_RXD_ENABLE))
{
bad = 0;
if (len_status & GRETH_RXD_TOOLONG)
@@ -543,12 +611,27 @@ greth_rxDaemon (void *arg)
len - sizeof (struct ether_header);
eh = mtod (m, struct ether_header *);
+
+ /* OVERRIDE CACHED ETHERNET HEADER FOR NON-SNOOPING SYSTEMS */
+ addr = (unsigned int)eh;
+ asm volatile (" lda [%1] 1, %0\n" : "=r"(tmp) : "r"(addr) );
+ addr+=4;
+ asm volatile (" lda [%1] 1, %0\n" : "=r"(tmp) : "r"(addr) );
+ addr+=4;
+ asm volatile (" lda [%1] 1, %0\n" : "=r"(tmp) : "r"(addr) );
+ addr+=4;
+ asm volatile (" lda [%1] 1, %0\n" : "=r"(tmp) : "r"(addr) );
+
m->m_data += sizeof (struct ether_header);
#ifdef CPU_U32_FIX
if(!(dp->gbit_mac))
ipalign(m); /* Align packet on 32-bit boundary */
#endif
-
+/*
+ if(!(dp->gbit_mac) && !CPU_SPARC_HAS_SNOOPING) {
+ rtems_cache_invalidate_entire_data();
+ }
+*/
ether_input (ifp, eh, m);
MGETHDR (m, M_WAIT, MT_DATA);
MCLGET (m, M_WAIT);
@@ -565,43 +648,53 @@ greth_rxDaemon (void *arg)
} else {
dp->rxdesc[dp->rx_ptr].ctrl = GRETH_RXD_ENABLE | GRETH_RXD_IRQ;
}
+ rtems_interrupt_disable(level);
dp->regs->ctrl |= GRETH_CTRL_RXEN;
+ rtems_interrupt_enable(level);
dp->rx_ptr = (dp->rx_ptr + 1) % dp->rxbufs;
}
+
+ /* Always scan twice to avoid deadlock */
+ if ( first ){
+ first=0;
+ rtems_interrupt_disable(level);
+ dp->regs->ctrl |= GRETH_CTRL_RXIRQ;
+ rtems_interrupt_enable(level);
+ goto again;
+ }
+
}
}
static int inside = 0;
-static void
+static int
sendpacket (struct ifnet *ifp, struct mbuf *m)
{
struct greth_softc *dp = ifp->if_softc;
unsigned char *temp;
struct mbuf *n;
unsigned int len;
+ rtems_interrupt_level level;
/*printf("Send packet entered\n");*/
if (inside) printf ("error: sendpacket re-entered!!\n");
inside = 1;
+
/*
- * Waiting for Transmitter ready
+ * Is there a free descriptor available?
*/
- n = m;
+ if (GRETH_MEM_LOAD(&dp->txdesc[dp->tx_ptr].ctrl) & GRETH_TXD_ENABLE){
+ /* No. */
+ inside = 0;
+ return 1;
+ }
- while (dp->txdesc[dp->tx_ptr].ctrl & GRETH_TXD_ENABLE)
- {
-#ifdef GRETH_SUSPEND_NOTXBUF
- dp->txdesc[dp->tx_ptr].ctrl |= GRETH_TXD_IRQ;
- rtems_event_set events;
- rtems_bsdnet_event_receive (GRETH_TX_WAIT_EVENT,
- RTEMS_WAIT | RTEMS_EVENT_ANY,
- TOD_MILLISECONDS_TO_TICKS(500), &events);
-#endif
- }
+ /* Remember head of chain */
+ n = m;
len = 0;
- temp = (unsigned char *) dp->txdesc[dp->tx_ptr].addr;
+ temp = (unsigned char *) GRETH_MEM_LOAD(&dp->txdesc[dp->tx_ptr].addr);
#ifdef GRETH_DEBUG
printf("TXD: 0x%08x : BUF: 0x%08x\n", (int) m->m_data, (int) temp);
#endif
@@ -633,179 +726,282 @@ sendpacket (struct ifnet *ifp, struct mbuf *m)
dp->txdesc[dp->tx_ptr].ctrl =
GRETH_TXD_WRAP | GRETH_TXD_ENABLE | len;
}
- dp->regs->ctrl = dp->regs->ctrl | GRETH_CTRL_TXEN;
dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
+ rtems_interrupt_disable(level);
+ dp->regs->ctrl = dp->regs->ctrl | GRETH_CTRL_TXEN;
+ rtems_interrupt_enable(level);
+
}
inside = 0;
+
+ return 0;
}
-static void
+int
sendpacket_gbit (struct ifnet *ifp, struct mbuf *m)
{
struct greth_softc *dp = ifp->if_softc;
unsigned int len;
+
+ unsigned int ctrl;
+ int frags;
+ struct mbuf *mtmp;
+ int int_en;
+ rtems_interrupt_level level;
- /*printf("Send packet entered\n");*/
if (inside) printf ("error: sendpacket re-entered!!\n");
inside = 1;
- /*
- * Waiting for Transmitter ready
- */
len = 0;
#ifdef GRETH_DEBUG
printf("TXD: 0x%08x\n", (int) m->m_data);
#endif
+ /* Get number of fragments too see if we have enough
+ * resources.
+ */
+ frags=1;
+ mtmp=m;
+ while(mtmp->m_next){
+ frags++;
+ mtmp = mtmp->m_next;
+ }
+
+ if ( frags > dp->max_fragsize )
+ dp->max_fragsize = frags;
+
+ if ( frags > dp->txbufs ){
+ inside = 0;
+ printf("GRETH: MBUF-chain cannot be sent. Increase descriptor count.\n");
+ return -1;
+ }
+
+ if ( frags > (dp->txbufs-dp->tx_cnt) ){
+ inside = 0;
+ /* Return number of fragments */
+ return frags;
+ }
+
+
+ /* Enable interrupt from descriptor every tx_int_gen
+ * descriptor. Typically every 16 descriptor. This
+ * is only to reduce the number of interrupts during
+ * heavy load.
+ */
+ dp->tx_int_gen_cur-=frags;
+ if ( dp->tx_int_gen_cur <= 0 ){
+ dp->tx_int_gen_cur = dp->tx_int_gen;
+ int_en = GRETH_TXD_IRQ;
+ }else{
+ int_en = 0;
+ }
+
+ /* At this stage we know that enough descriptors are available */
for (;;)
{
- while (dp->txdesc[dp->tx_ptr].ctrl & GRETH_TXD_ENABLE)
- {
-#ifdef GRETH_SUSPEND_NOTXBUF
- dp->txdesc[dp->tx_ptr].ctrl |= GRETH_TXD_IRQ;
- rtems_event_set events;
- rtems_bsdnet_event_receive (GRETH_TX_WAIT_EVENT,
- RTEMS_WAIT | RTEMS_EVENT_ANY,
- TOD_MILLISECONDS_TO_TICKS(500), &events);
-#endif
- }
+
#ifdef GRETH_DEBUG
- int i;
- printf("MBUF: 0x%08x, Len: %d : ", (int) m->m_data, m->m_len);
- for (i=0; i<m->m_len; i++)
- printf("%x%x", (m->m_data[i] >> 4) & 0x0ff, m->m_data[i] & 0x0ff);
- printf("\n");
+ int i;
+ printf("MBUF: 0x%08x, Len: %d : ", (int) m->m_data, m->m_len);
+ for (i=0; i<m->m_len; i++)
+ printf("%x%x", (m->m_data[i] >> 4) & 0x0ff, m->m_data[i] & 0x0ff);
+ printf("\n");
#endif
len += m->m_len;
dp->txdesc[dp->tx_ptr].addr = (uint32_t *)m->m_data;
+
+ /* Wrap around? */
if (dp->tx_ptr < dp->txbufs-1) {
- if ((m->m_next) == NULL) {
- dp->txdesc[dp->tx_ptr].ctrl = GRETH_TXD_ENABLE | GRETH_TXD_CS | m->m_len;
- break;
- } else {
- dp->txdesc[dp->tx_ptr].ctrl = GRETH_TXD_ENABLE | GRETH_TXD_MORE | GRETH_TXD_CS | m->m_len;
- }
- } else {
- if ((m->m_next) == NULL) {
- dp->txdesc[dp->tx_ptr].ctrl =
- GRETH_TXD_WRAP | GRETH_TXD_ENABLE | GRETH_TXD_CS | m->m_len;
- break;
- } else {
- dp->txdesc[dp->tx_ptr].ctrl =
- GRETH_TXD_WRAP | GRETH_TXD_ENABLE | GRETH_TXD_MORE | GRETH_TXD_CS | m->m_len;
- }
+ ctrl = GRETH_TXD_ENABLE | GRETH_TXD_CS;
+ }else{
+ ctrl = GRETH_TXD_ENABLE | GRETH_TXD_CS | GRETH_TXD_WRAP;
+ }
+
+ /* Enable Descriptor */
+ if ((m->m_next) == NULL) {
+ dp->txdesc[dp->tx_ptr].ctrl = ctrl | int_en | m->m_len;
+ break;
+ }else{
+ dp->txdesc[dp->tx_ptr].ctrl = GRETH_TXD_MORE | ctrl | int_en | m->m_len;
}
+
+ /* Next */
dp->txmbuf[dp->tx_ptr] = m;
dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
dp->tx_cnt++;
m = m->m_next;
-
- }
+ }
dp->txmbuf[dp->tx_ptr] = m;
+ dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
dp->tx_cnt++;
+
+ /* Tell Hardware about newly enabled descriptor */
+ rtems_interrupt_disable(level);
dp->regs->ctrl = dp->regs->ctrl | GRETH_CTRL_TXEN;
- dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
+ rtems_interrupt_enable(level);
+
inside = 0;
+
+ return 0;
}
-/*
- * Driver transmit daemon
- */
-void
-greth_txDaemon (void *arg)
+int greth_process_tx_gbit(struct greth_softc *sc)
{
- struct greth_softc *sc = (struct greth_softc *) arg;
struct ifnet *ifp = &sc->arpcom.ac_if;
struct mbuf *m;
- rtems_event_set events;
+ rtems_interrupt_level level;
+ int first=1;
- for (;;)
- {
+ /*
+ * Send packets till queue is empty
+ */
+ for (;;){
+ /* Reap Sent packets */
+ while((sc->tx_cnt > 0) && !(GRETH_MEM_LOAD(&sc->txdesc[sc->tx_dptr].ctrl) & GRETH_TXD_ENABLE)) {
+ m_free(sc->txmbuf[sc->tx_dptr]);
+ sc->tx_dptr = (sc->tx_dptr + 1) % sc->txbufs;
+ sc->tx_cnt--;
+ }
+
+ if ( sc->next_tx_mbuf ){
+ /* Get packet we tried but faild to transmit last time */
+ m = sc->next_tx_mbuf;
+ sc->next_tx_mbuf = NULL; /* Mark packet taken */
+ }else{
/*
- * Wait for packet
+ * Get the next mbuf chain to transmit from Stack.
*/
+ IF_DEQUEUE (&ifp->if_snd, m);
+ if (!m){
+ /* Hardware has sent all schedule packets, this
+ * makes the stack enter at greth_start next time
+ * a packet is to be sent.
+ */
+ ifp->if_flags &= ~IFF_OACTIVE;
+ break;
+ }
+ }
- rtems_bsdnet_event_receive (START_TRANSMIT_EVENT,
- RTEMS_EVENT_ANY | RTEMS_WAIT,
- RTEMS_NO_TIMEOUT, &events);
-#ifdef GRETH_DEBUG
- printf ("t\n");
-#endif
+ /* Are there free descriptors available? */
+ /* Try to send packet, if it a negative number is returned. */
+ if ( (sc->tx_cnt >= sc->txbufs) || sendpacket_gbit(ifp, m) ){
+ /* Not enough resources */
- /*
- * Send packets till queue is empty
+ /* Since we have taken the mbuf out of the "send chain"
+ * we must remember to use that next time we come back.
+ * or else we have dropped a packet.
*/
+ sc->next_tx_mbuf = m;
-
- for (;;)
- {
- /*
- * Get the next mbuf chain to transmit.
- */
- IF_DEQUEUE (&ifp->if_snd, m);
- if (!m)
- break;
- sendpacket(ifp, m);
+ /* Not enough resources, enable interrupt for transmissions
+ * this way we will be informed when more TX-descriptors are
+ * available.
+ */
+ if ( first ){
+ first = 0;
+ rtems_interrupt_disable(level);
+ ifp->if_flags |= IFF_OACTIVE;
+ sc->regs->ctrl |= GRETH_CTRL_TXIRQ;
+ rtems_interrupt_enable(level);
+
+ /* We must check again to be sure that we didn't
+ * miss an interrupt (if a packet was sent just before
+ * enabling interrupts)
+ */
+ continue;
}
- ifp->if_flags &= ~IFF_OACTIVE;
+
+ return -1;
+ }else{
+ /* Sent Ok, proceed to process more packets if available */
+ }
}
+ return 0;
}
-/*
- * Driver transmit daemon
- */
-void
-greth_txDaemon_gbit (void *arg)
+int greth_process_tx(struct greth_softc *sc)
{
- struct greth_softc *sc = (struct greth_softc *) arg;
struct ifnet *ifp = &sc->arpcom.ac_if;
struct mbuf *m;
- rtems_event_set events;
+ rtems_interrupt_level level;
+ int first=1;
- for (;;)
- {
+ /*
+ * Send packets till queue is empty
+ */
+ for (;;){
+ if ( sc->next_tx_mbuf ){
+ /* Get packet we tried but failed to transmit last time */
+ m = sc->next_tx_mbuf;
+ sc->next_tx_mbuf = NULL; /* Mark packet taken */
+ }else{
/*
- * Wait for packet
+ * Get the next mbuf chain to transmit from Stack.
*/
+ IF_DEQUEUE (&ifp->if_snd, m);
+ if (!m){
+ /* Hardware has sent all schedule packets, this
+ * makes the stack enter at greth_start next time
+ * a packet is to be sent.
+ */
+ ifp->if_flags &= ~IFF_OACTIVE;
+ break;
+ }
+ }
- rtems_bsdnet_event_receive (START_TRANSMIT_EVENT,
- RTEMS_EVENT_ANY | RTEMS_WAIT,
- RTEMS_NO_TIMEOUT, &events);
-#ifdef GRETH_DEBUG
- printf ("t\n");
-#endif
+ /* Try to send packet, failed if it a non-zero number is returned. */
+ if ( sendpacket(ifp, m) ){
+ /* Not enough resources */
- /*
- * Send packets till queue is empty
+ /* Since we have taken the mbuf out of the "send chain"
+ * we must remember to use that next time we come back.
+ * or else we have dropped a packet.
*/
- for (;;)
- {
- while((sc->tx_cnt > 0) && !(sc->txdesc[sc->tx_dptr].ctrl & GRETH_TXD_ENABLE)) {
- m_free(sc->txmbuf[sc->tx_dptr]);
- sc->tx_dptr = (sc->tx_dptr + 1) % sc->txbufs;
- sc->tx_cnt--;
- }
- /*
- * Get the next mbuf chain to transmit.
- */
- IF_DEQUEUE (&ifp->if_snd, m);
- if (!m)
- break;
- sendpacket_gbit(ifp, m);
+ sc->next_tx_mbuf = m;
+
+ /* Not enough resources, enable interrupt for transmissions
+ * this way we will be informed when more TX-descriptors are
+ * available.
+ */
+ if ( first ){
+ first = 0;
+ rtems_interrupt_disable(level);
+ ifp->if_flags |= IFF_OACTIVE;
+ sc->regs->ctrl |= GRETH_CTRL_TXIRQ;
+ rtems_interrupt_enable(level);
+
+ /* We must check again to be sure that we didn't
+ * miss an interrupt (if a packet was sent just before
+ * enabling interrupts)
+ */
+ continue;
}
- ifp->if_flags &= ~IFF_OACTIVE;
+
+ return -1;
+ }else{
+ /* Sent Ok, proceed to process more packets if available */
+ }
}
+ return 0;
}
-
static void
greth_start (struct ifnet *ifp)
{
struct greth_softc *sc = ifp->if_softc;
- ifp->if_flags |= IFF_OACTIVE;
- rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT);
+ if ( ifp->if_flags & IFF_OACTIVE )
+ return;
+ if ( sc->gbit_mac ){
+ /* No use trying to handle this if we are waiting on GRETH
+ * to send the previously scheduled packets.
+ */
+
+ greth_process_tx_gbit(sc);
+ }else{
+ greth_process_tx(sc);
+ }
}
/*
@@ -817,34 +1013,25 @@ greth_init (void *arg)
struct greth_softc *sc = arg;
struct ifnet *ifp = &sc->arpcom.ac_if;
- if (sc->txDaemonTid == 0)
- {
+ if (sc->daemonTid == 0) {
- /*
- * Set up GRETH hardware
- */
- greth_initialize_hardware (sc);
+ /*
+ * Start driver tasks
+ */
+ sc->daemonTid = rtems_bsdnet_newproc ("DCrxtx", 4096,
+ greth_Daemon, sc);
- /*
- * Start driver tasks
- */
- sc->rxDaemonTid = rtems_bsdnet_newproc ("DCrx", 4096,
- greth_rxDaemon, sc);
- if (sc->gbit_mac) {
- sc->txDaemonTid = rtems_bsdnet_newproc ("DCtx", 4096,
- greth_txDaemon_gbit, sc);
- } else {
- sc->txDaemonTid = rtems_bsdnet_newproc ("DCtx", 4096,
- greth_txDaemon, sc);
- }
+ /*
+ * Set up GRETH hardware
+ */
+ greth_initialize_hardware (sc);
- }
+ }
/*
* Tell the world that we're running.
*/
ifp->if_flags |= IFF_RUNNING;
-
}
/*
@@ -860,6 +1047,8 @@ greth_stop (struct greth_softc *sc)
sc->regs->ctrl = 0; /* RX/TX OFF */
sc->regs->ctrl = GRETH_CTRL_RST; /* Reset ON */
sc->regs->ctrl = 0; /* Reset OFF */
+
+ sc->next_tx_mbuf = NULL;
}
@@ -876,6 +1065,8 @@ greth_stats (struct greth_softc *sc)
printf (" Bad CRC:%-8lu", sc->rxBadCRC);
printf (" Overrun:%-8lu", sc->rxOverrun);
printf (" Tx Interrupts:%-8lu", sc->txInterrupts);
+ printf (" Maximal Frags:%-8d", sc->max_fragsize);
+ printf (" GBIT MAC:%-8d", sc->gbit_mac);
}
/*
@@ -967,7 +1158,7 @@ rtems_greth_driver_attach (struct rtems_bsdnet_ifconfig *config,
sc->acceptBroadcast = !config->ignore_broadcast;
sc->regs = (void *) chip->base_address;
- sc->vector = chip->vector;
+ sc->irq = chip->irq;
sc->txbufs = chip->txd_count;
sc->rxbufs = chip->rxd_count;
@@ -998,3 +1189,4 @@ rtems_greth_driver_attach (struct rtems_bsdnet_ifconfig *config,
return 1;
};
+#endif
diff --git a/c/src/libchip/network/greth.h b/c/src/libchip/network/greth.h
index 222a9efbc2..dbc1f22c55 100644
--- a/c/src/libchip/network/greth.h
+++ b/c/src/libchip/network/greth.h
@@ -18,7 +18,7 @@
typedef struct {
uint32_t base_address;
- uint32_t vector;
+ uint32_t irq;
uint32_t txd_count;
uint32_t rxd_count;
} greth_configuration_t;
diff --git a/c/src/libchip/network/smc91111.c b/c/src/libchip/network/smc91111.c
index d959386463..f08c3e31b4 100644
--- a/c/src/libchip/network/smc91111.c
+++ b/c/src/libchip/network/smc91111.c
@@ -15,13 +15,14 @@
*/
#if defined(__sparc__)
- #define SMC91111_SUPPORTED
+ #include <bsp.h>
+ #if defined(LEON2) || defined(LEON3)
+ #define SMC91111_SUPPORTED
+ #endif
#endif
#if defined(SMC91111_SUPPORTED)
-#include <bsp.h>
-
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
@@ -58,12 +59,6 @@
#include "smc91111config.h"
#include <libchip/smc91111.h>
-#if defined(__m68k__)
-extern m68k_isr_entry set_vector( rtems_isr_entry, rtems_vector_number, int );
-#else
-extern rtems_isr_entry set_vector( rtems_isr_entry, rtems_vector_number, int );
-#endif
-
struct lan91cxx_priv_data smc91111;
int lan91cxx_hardware_init(struct lan91cxx_priv_data *cpd);
@@ -87,9 +82,9 @@ static void lan91cxx_phy_configure(struct lan91cxx_priv_data *cpd);
#define max(l,r) ((l) > (r) ? (l) : (r))
/* \ ------------- Interrupt ------------- \ */
-rtems_isr lan91cxx_interrupt_handler(rtems_vector_number v)
+void lan91cxx_interrupt_handler(void *arg)
{
- struct lan91cxx_priv_data *cpd = &smc91111;
+ struct lan91cxx_priv_data *cpd = arg;
unsigned short irq, event;
unsigned short oldbase;
unsigned short oldpointer;
@@ -1048,15 +1043,18 @@ static void smc91111_stop(struct lan91cxx_priv_data *cpd)
int lan91cxx_hardware_init(struct lan91cxx_priv_data *cpd)
{
unsigned short val;
- int i;
+ int i, rc;
DEBUG_FUNCTION();
cpd->txbusy = cpd->within_send = 0;
/* install interrupt vector */
- db_printf("Install lan91cxx irqvector at %d\n", cpd->config.vector);
- set_vector(lan91cxx_interrupt_handler, cpd->config.vector, 1);
+ db_printf("Install lan91cxx isr at irq %d\n", cpd->config.irq);
+ rc = rtems_interrupt_handler_install(cpd->config.irq, "smc91cxx",
+ RTEMS_INTERRUPT_SHARED, lan91cxx_interrupt_handler, cpd);
+ if (rc != RTEMS_SUCCESSFUL)
+ return 0;
/* Reset chip */
put_reg(cpd, LAN91CXX_RCR, LAN91CXX_RCR_SOFT_RST);
diff --git a/c/src/libchip/network/smc91111exp.h b/c/src/libchip/network/smc91111exp.h
index 72e41fa0d9..c9698c9291 100644
--- a/c/src/libchip/network/smc91111exp.h
+++ b/c/src/libchip/network/smc91111exp.h
@@ -7,7 +7,7 @@
typedef struct scmv91111_configuration {
void *baseaddr;
- unsigned int vector;
+ int irq;
unsigned int pio;
unsigned int ctl_rspeed;
unsigned int ctl_rfduplx;
diff --git a/c/src/make/configure.ac b/c/src/make/configure.ac
index ebb379636b..7ed21f29b1 100644
--- a/c/src/make/configure.ac
+++ b/c/src/make/configure.ac
@@ -22,6 +22,7 @@ RTEMS_ENABLE_POSIX
RTEMS_ENABLE_ITRON
RTEMS_ENABLE_NETWORKING
RTEMS_ENABLE_CXX
+RTEMS_ENABLE_DRVMGR
RTEMS_ENV_RTEMSBSP
diff --git a/configure.ac b/configure.ac
index 597115e6f1..a37017edb1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -30,6 +30,7 @@ RTEMS_ENABLE_TESTS
RTEMS_ENABLE_RTEMS_DEBUG
RTEMS_ENABLE_RTEMSBSP
RTEMS_ENABLE_MULTILIB
+RTEMS_ENABLE_DRVMGR
AC_ARG_ENABLE([docs],
[AS_HELP_STRING([--enable-docs],[enable building documentation
diff --git a/cpukit/Makefile.am b/cpukit/Makefile.am
index 943d1fd0dd..d84d2d3c95 100644
--- a/cpukit/Makefile.am
+++ b/cpukit/Makefile.am
@@ -10,7 +10,9 @@ include $(top_srcdir)/automake/multilib.am
# librtemscpu
SUBDIRS = . score rtems sapi posix itron
SUBDIRS += libcsupport libblock libfs
+SUBDIRS += libdrvmgr
SUBDIRS += libnetworking librpc
+SUBDIRS += libpci
SUBDIRS += libi2c
SUBDIRS += libmisc
SUBDIRS += libmd
@@ -181,6 +183,12 @@ include_rtems_HEADERS += libmisc/untar/untar.h
## fsmount
include_rtems_HEADERS += libmisc/fsmount/fsmount.h
+## Driver manager
+include_drvmgrdir = $(includedir)/drvmgr
+include_drvmgr_HEADERS = libdrvmgr/drvmgr.h
+include_drvmgr_HEADERS += libdrvmgr/drvmgr_confdefs.h
+include_drvmgr_HEADERS += libdrvmgr/drvmgr_list.h
+
include $(srcdir)/preinstall.am
include $(top_srcdir)/automake/subdirs.am
include $(top_srcdir)/automake/local.am
diff --git a/cpukit/aclocal/enable-drvmgr.m4 b/cpukit/aclocal/enable-drvmgr.m4
new file mode 100644
index 0000000000..a9da288b11
--- /dev/null
+++ b/cpukit/aclocal/enable-drvmgr.m4
@@ -0,0 +1,12 @@
+dnl $Id: enable-drvmgr.m4,v 1.0
+
+AC_DEFUN([RTEMS_ENABLE_DRVMGR],
+[
+AC_ARG_ENABLE(drvmgr,
+AS_HELP_STRING(--enable-drvmgr,enable drvmgr at startup),
+[case "${enableval}" in
+ yes) RTEMS_DRVMGR_STARTUP=yes ;;
+ no) RTEMS_DRVMGR_STARTUP=no ;;
+ *) AC_MSG_ERROR(bad value ${enableval} for enable-drvmgr option) ;;
+esac],[RTEMS_DRVMGR_STARTUP=yes])
+])
diff --git a/cpukit/configure.ac b/cpukit/configure.ac
index b369b63e41..17ab9eae8d 100644
--- a/cpukit/configure.ac
+++ b/cpukit/configure.ac
@@ -20,6 +20,7 @@ RTEMS_ENABLE_RTEMS_DEBUG
RTEMS_ENABLE_NETWORKING
RTEMS_ENABLE_HTTPD
RTEMS_ENABLE_SHTTPD
+RTEMS_ENABLE_DRVMGR
RTEMS_ENV_RTEMSCPU
RTEMS_CHECK_RTEMS_DEBUG
@@ -154,6 +155,11 @@ RTEMS_CPUOPT([RTEMS_NETWORKING],
[1],
[if networking is enabled])
+RTEMS_CPUOPT([RTEMS_DRVMGR_STARTUP],
+ [test x"$enable_drvmgr" = xyes],
+ [1],
+ [if driver manager api is supported])
+
RTEMS_CPUOPT([RTEMS_VERSION],
[true],
["]_RTEMS_VERSION["],
@@ -322,11 +328,13 @@ score/cpu/no_cpu/Makefile
posix/Makefile
itron/Makefile
libblock/Makefile
+libdrvmgr/Makefile
libfs/Makefile
libfs/src/nfsclient/Makefile
libgnat/Makefile
libcsupport/Makefile
libnetworking/Makefile
+libpci/Makefile
librpc/Makefile
libmisc/Makefile
libi2c/Makefile
diff --git a/cpukit/libdrvmgr/Makefile.am b/cpukit/libdrvmgr/Makefile.am
new file mode 100644
index 0000000000..471ae79421
--- /dev/null
+++ b/cpukit/libdrvmgr/Makefile.am
@@ -0,0 +1,31 @@
+##
+## $Id: Makefile.am
+##
+
+include $(top_srcdir)/automake/compile.am
+
+EXTRA_DIST=
+
+noinst_LIBRARIES = libdrvmgr.a
+
+libdrvmgr_a_SOURCES = drvmgr.c
+libdrvmgr_a_SOURCES += drvmgr.h
+libdrvmgr_a_SOURCES += drvmgr_by_name.c
+libdrvmgr_a_SOURCES += drvmgr_by_id.c
+libdrvmgr_a_SOURCES += drvmgr_drvinf.c
+libdrvmgr_a_SOURCES += drvmgr_init.c
+libdrvmgr_a_SOURCES += drvmgr_confdefs.h
+libdrvmgr_a_SOURCES += drvmgr_for_each_dev.c
+libdrvmgr_a_SOURCES += drvmgr_for_each_list_dev.c
+libdrvmgr_a_SOURCES += drvmgr_func.c
+libdrvmgr_a_SOURCES += drvmgr_func_call.c
+libdrvmgr_a_SOURCES += drvmgr_list.c
+libdrvmgr_a_SOURCES += drvmgr_list.h
+libdrvmgr_a_SOURCES += drvmgr_lock.c
+libdrvmgr_a_SOURCES += drvmgr_print.c
+libdrvmgr_a_SOURCES += drvmgr_res.c
+libdrvmgr_a_SOURCES += drvmgr_rw.c
+libdrvmgr_a_SOURCES += drvmgr_translate.c
+libdrvmgr_a_SOURCES += drvmgr_unregister.c
+
+include $(top_srcdir)/automake/local.am
diff --git a/cpukit/libdrvmgr/README b/cpukit/libdrvmgr/README
new file mode 100644
index 0000000000..51c668efb3
--- /dev/null
+++ b/cpukit/libdrvmgr/README
@@ -0,0 +1,113 @@
+DRIVER MANAGER
+==============
+
+See documentation in Aeroflex Gaisler Driver manual.
+
+
+INITIALIZATION
+==============
+The Driver Manager can be intialized in two different ways:
+ 1. during RTEMS startup
+ 2. started by user, typically in the Init task
+
+The driver manager is initalized during RTEMS startup in the
+rtems_initialize_device_drivers() function when RTEMS is
+configured with driver manager support.
+
+When RTEMS is not configured with the driver manager, the manager
+may still be initialized by the user after system startup, typically
+from the Init() task.
+
+The main difference between the two ways is when interrupt
+is enabled. Interrupt is enabled for the first time by RTEMS when
+the Init task is started. This means, for the first case, that
+drivers can not use interrupt services until after the
+initialization phase is over and the user request services from
+the drivers. For the second case of initialization, this means
+that driver writers must take extra care during initalization
+when interrupt is enalbed so that spurious interrupts are not
+generated and that the system does not hang in an infinite
+IRQ loop.
+
+Most of the problems above are solved for the two methods by
+specifying in which initialization levels IRQ handling is done.
+See Level 1 and Level 2 below.
+
+Other differences is that IRQ, System Clock Timer, debug Console
+and Console can be initalized by the help of the driver manager
+when initialized during start up. Between Level0 and Level1 the
+RTEMS I/O Manager drivers are initialized. The LEON3 BSP has
+therefore two different versions of the basic drivers.
+
+
+LEVEL0
+------
+The level of uninitialized devices that have been united with a
+driver.
+
+
+LEVEL1 - FIND/RESET/IRQ Clear
+-----------------------------
+The driver is for the first time informed of the presence of a
+device. Only basic initialization.
+
+- Find all hardware needed for IRQ, Console, Timer and hardware
+ that need to be reset.
+- Reset hardware, so that interrupts are not generated by mistake
+ when enabled later on.
+- Init low level non-interrupt (polling-mode) services needed by
+ drivers init LEVEL2 and onwards, such as
+ * debug UART console for printk()
+ * Timer API (non-IRQ)
+ * GPIO (non-IRQ)
+ * special non-main memory configuration, washing
+- Register IRQ controller at BSP IRQ library
+- Register Timer for system clock
+- Register Console UART
+
+During this intialization level interrupts may not be registered,
+enabled or disabled at the IRQ controller. But, all IRQ sources
+should be cleared to avoid spurious interrupts later on.
+
+
+AFTER LEVEL1 - if initializaed during startup
+---------------------------------------------
+The statically configured drivers are initialized as normally by RTEMS. The
+hardware was found in LEVEL1.
+
+CONFIGURE_BSP_PREREQUISITE_DRIVERS may initialize IRQ driver, or
+IRQ lib initialized when IRQ controller was registered during LEVEL1.
+
+
+LEVEL2
+------
+Initialize other device drivers than IRQ, Timer, console:
+- ISR can be registered, enabled, disabled at IRQ controller
+ (IRQ is still masked by CPU interrupt level if initialized during
+ RTEMS startup)
+- Timer API that does not require IRQ can be used
+- printf() can be used
+
+For standard peripherals this is the first initialization.
+
+
+LEVEL3
+------
+Initialize drivers that require features/APIs provided by drivers
+in LEVEL2.
+
+Such features may involve services that require IRQ.
+
+
+LEVEL4
+------
+Unused extra level.
+
+
+
+LEVEL INACTIVE - NOT ENABLED DEVICES
+------------------------------------
+List of devices that experienced:
+ - no driver found for device (not united)
+ - ignored (not united with a driver, forced by user)
+ - an error was reported by device driver during initialization
diff --git a/cpukit/libdrvmgr/drvmgr.c b/cpukit/libdrvmgr/drvmgr.c
new file mode 100644
index 0000000000..161f3ad7b9
--- /dev/null
+++ b/cpukit/libdrvmgr/drvmgr.c
@@ -0,0 +1,646 @@
+/* Driver Manager Interface Implementation.
+ *
+ * COPYRIGHT (c) 2009-2011.
+ * Aeroflex Gaisler AB
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/drvmgr_confdefs.h>
+
+#include "drvmgr_internal.h"
+
+/* Enable debugging */
+/*#define DEBUG 1*/
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+struct rtems_driver_manager drv_mgr = {
+ .level = 0,
+ .initializing_objs = 0,
+ .lock = 0,
+ .root_dev = {0},
+ .root_drv = NULL,
+
+ .drivers = LIST_INITIALIZER(struct drvmgr_drv, next),
+
+ .buses = {
+ LIST_INITIALIZER(struct drvmgr_bus, next),
+ LIST_INITIALIZER(struct drvmgr_bus, next),
+ LIST_INITIALIZER(struct drvmgr_bus, next),
+ LIST_INITIALIZER(struct drvmgr_bus, next),
+ LIST_INITIALIZER(struct drvmgr_bus, next),
+ },
+ .buses_inactive = LIST_INITIALIZER(struct drvmgr_bus, next),
+
+ .devices = {
+ LIST_INITIALIZER(struct drvmgr_dev, next),
+ LIST_INITIALIZER(struct drvmgr_dev, next),
+ LIST_INITIALIZER(struct drvmgr_dev, next),
+ LIST_INITIALIZER(struct drvmgr_dev, next),
+ LIST_INITIALIZER(struct drvmgr_dev, next),
+ },
+ .devices_inactive = LIST_INITIALIZER(struct drvmgr_dev, next),
+};
+
+static int do_bus_init(
+ struct rtems_driver_manager *mgr,
+ struct drvmgr_bus *bus,
+ int level);
+static int do_dev_init(
+ struct rtems_driver_manager *mgr,
+ struct drvmgr_dev *dev,
+ int level);
+
+/* DRIVER MANAGER */
+
+void _DRV_Manager_init_level(int level)
+{
+ struct rtems_driver_manager *mgr = &drv_mgr;
+
+ if (mgr->level >= level)
+ return;
+
+ /* Set new Level */
+ mgr->level = level;
+
+ /* Initialize buses and devices into this new level */
+ drvmgr_init_update();
+}
+
+/* Initialize Data structures of the driver manager and call driver
+ * register functions configured by the user.
+ */
+void _DRV_Manager_initialization(void)
+{
+ struct drvmgr_drv_reg_func *drvreg;
+
+ /* drv_mgr is already initialized statically by compiler except
+ * the lock
+ */
+ DRVMGR_LOCK_INIT();
+
+ /* Call driver register functions. */
+ drvreg = &drvmgr_drivers[0];
+ while (drvreg->drv_reg) {
+ /* Make driver register */
+ drvreg->drv_reg();
+ drvreg++;
+ }
+}
+
+/* Take ready devices and buses into the correct init level step by step.
+ * Once a bus or a device has been registered there is no turning
+ * back - they are taken to the level of the driver manager.
+ */
+void drvmgr_init_update(void)
+{
+ struct rtems_driver_manager *mgr = &drv_mgr;
+ struct drvmgr_bus *bus;
+ struct drvmgr_dev *dev;
+ int bus_might_been_registered;
+ int level;
+
+ /* "Lock" to make sure we don't use up the stack and that the lists
+ * remain consistent.
+ */
+ DRVMGR_LOCK_WRITE();
+ if (mgr->initializing_objs || (mgr->level == 0))
+ goto out;
+ mgr->initializing_objs = 1;
+
+init_registered_buses:
+ /* Take all buses and devices ready into the same stage
+ * as the driver manager global level.
+ */
+ for (level = 0; level < mgr->level; level++) {
+
+ bus_might_been_registered = 0;
+
+ /* Take buses into next level */
+
+ while ((bus = BUS_LIST_HEAD(&mgr->buses[level])) != NULL) {
+
+ /* Remove first in the list (will be inserted in
+ * appropriate list by do_bus_init())
+ */
+ drvmgr_list_remove_head(&mgr->buses[level]);
+
+ DRVMGR_UNLOCK();
+
+ /* Initialize Bus, this will register devices on
+ * the bus. Take bus into next level.
+ */
+ do_bus_init(mgr, bus, level+1);
+
+ DRVMGR_LOCK_WRITE();
+ }
+
+ /* Take devices into next level */
+ while ((dev = DEV_LIST_HEAD(&mgr->devices[level])) != NULL) {
+
+ /* Always process first in list */
+ dev = DEV_LIST_HEAD(&mgr->devices[level]);
+
+ /* Remove first in the list (will be inserted in
+ * appropriate list by do_dev_init())
+ */
+ drvmgr_list_remove_head(&mgr->devices[level]);
+
+ DRVMGR_UNLOCK();
+
+ /* Initialize Device, this may register a new bus */
+ do_dev_init(mgr, dev, level+1);
+
+ DRVMGR_LOCK_WRITE();
+
+ bus_might_been_registered = 1;
+ }
+
+ /* Make sure all buses registered and ready are taken at
+ * the same time into init level N.
+ */
+ if (bus_might_been_registered)
+ goto init_registered_buses;
+ }
+
+ /* Release bus/device initialization "Lock" */
+ mgr->initializing_objs = 0;
+
+out:
+ DRVMGR_UNLOCK();
+}
+
+/* Take bus into next level */
+static int do_bus_init(
+ struct rtems_driver_manager *mgr,
+ struct drvmgr_bus *bus,
+ int level)
+{
+ int (*init)(struct drvmgr_bus *);
+
+ /* If bridge device has failed during initialization, the bus is not
+ * initialized further.
+ */
+ if (bus->dev->state & DEV_STATE_INIT_FAILED) {
+ bus->state |= BUS_STATE_DEPEND_FAILED;
+ goto inactivate_out;
+ }
+
+ if (bus->ops && (init = bus->ops->init[level-1])) {
+ /* Note: This init1 function may register new devices */
+ bus->error = init(bus);
+ if (bus->error != DRVMGR_OK) {
+ /* An error of some kind during bus initialization.
+ *
+ * Child devices and their buses are not inactived
+ * directly here, instead they will all be catched by
+ * do_dev_init() and do_bus_init() by checking if
+ * parent or bridge-device failed. We know that
+ * initialization will happen later for those devices.
+ */
+ goto inactivate_out;
+ }
+ }
+
+ DRVMGR_LOCK_WRITE();
+
+ /* Bus taken into the new level */
+ bus->level = level;
+
+ /* Put bus into list of buses reached level 'level'.
+ * Put at end of bus list so that init[N+1]() calls comes
+ * in the same order as init[N]()
+ */
+ drvmgr_list_add_tail(&mgr->buses[level], bus);
+
+ DRVMGR_UNLOCK();
+
+ return 0;
+
+inactivate_out:
+ DRVMGR_LOCK_WRITE();
+ bus->state |= BUS_STATE_INIT_FAILED;
+ bus->state |= BUS_STATE_LIST_INACTIVE;
+ drvmgr_list_add_head(&mgr->buses_inactive, bus);
+ DRVMGR_UNLOCK();
+
+ DBG("do_bus_init(%d): (DEV: %s) failed\n", level, bus->dev->name);
+
+ return 1;
+}
+
+/* Take device to initialization level 1 */
+static int do_dev_init(
+ struct rtems_driver_manager *mgr,
+ struct drvmgr_dev *dev,
+ int level)
+{
+ int (*init)(struct drvmgr_dev *);
+
+ /* Try to allocate Private Device Structure for driver if driver
+ * requests for this feature.
+ */
+ if (dev->drv && dev->drv->dev_priv_size && !dev->priv) {
+ dev->priv = malloc(dev->drv->dev_priv_size);
+ memset(dev->priv, 0, dev->drv->dev_priv_size);
+ }
+
+ /* If parent bus has failed during initialization,
+ * the device is not initialized further.
+ */
+ if (dev->parent && (dev->parent->state & BUS_STATE_INIT_FAILED)) {
+ dev->state |= DEV_STATE_DEPEND_FAILED;
+ goto inactivate_out;
+ }
+
+ /* Call Driver's Init Routine */
+ if (dev->drv && (init = dev->drv->ops->init[level-1])) {
+ /* Note: This init function may register new devices */
+ dev->error = init(dev);
+ if (dev->error != DRVMGR_OK) {
+ /* An error of some kind has occured in the
+ * driver/device, the failed device is put into the
+ * inactive list, this way Init2,3 and/or 4 will not
+ * be called for this device.
+ *
+ * The device is not removed from the bus (not
+ * unregistered). The driver can be used to find
+ * device information and debugging for example even
+ * if device initialization failed.
+ *
+ * Child buses and their devices are not inactived
+ * directly here, instead they will all be catched by
+ * do_dev_init() and do_bus_init() by checking if
+ * parent or bridge-device failed. We know that
+ * initialization will happen later for those devices.
+ */
+ goto inactivate_out;
+ }
+ }
+
+ DRVMGR_LOCK_WRITE();
+ /* Dev taken into new level */
+ dev->level = level;
+
+ /* Put at end of device list so that init[N+1]() calls comes
+ * in the same order as init[N]()
+ */
+ drvmgr_list_add_tail(&mgr->devices[level], dev);
+ DRVMGR_UNLOCK();
+
+ return 0;
+
+inactivate_out:
+ DRVMGR_LOCK_WRITE();
+ dev->state |= DEV_STATE_INIT_FAILED;
+ dev->state |= DEV_STATE_LIST_INACTIVE;
+ drvmgr_list_add_head(&mgr->devices_inactive, dev);
+ DRVMGR_UNLOCK();
+
+ DBG("do_dev_init(%d): DRV: %s (DEV: %s) failed\n",
+ level, dev->drv->name, dev->name);
+
+ return 1; /* Failed to take device into requested level */
+}
+
+/* Register Root device driver */
+int drvmgr_root_drv_register(struct drvmgr_drv *drv)
+{
+ struct rtems_driver_manager *mgr = &drv_mgr;
+ struct drvmgr_dev *root = &mgr->root_dev;
+
+ if (mgr->root_drv) {
+ /* Only possible to register root device once */
+ return DRVMGR_FAIL;
+ }
+
+ /* Set root device driver */
+ drv->next = NULL;
+ mgr->root_drv = drv;
+
+ /* Init root device non-NULL fields */
+ root->minor_drv = -1;
+ root->minor_bus = 0;
+ root->businfo = mgr;
+ root->name = "root bus";
+ /* Custom Driver association */
+ root->drv = mgr->root_drv;
+
+ /* This registers the root device and a bus */
+ drvmgr_dev_register(root);
+
+ return DRVMGR_OK;
+}
+
+/* Register a driver */
+int drvmgr_drv_register(struct drvmgr_drv *drv)
+{
+ struct rtems_driver_manager *mgr = &drv_mgr;
+
+ /* All drivers must have been registered before start of init,
+ * because the manager does not scan all existing devices to find
+ * suitable hardware for this driver, and it is not protected with
+ * a lock therefore.
+ */
+ if (mgr->level > 0)
+ return -1;
+
+ drv->obj_type = DRVMGR_OBJ_DRV;
+
+ /* Put driver into list of registered drivers */
+ drvmgr_list_add_head(&mgr->drivers, drv);
+
+ /* TODO: we could scan for devices that this new driver has support
+ * for. However, at this stage we assume that all drivers are
+ * registered before devices are registered.
+ *
+ * LOCK: From the same assumsion locking the driver list is not needed
+ * either.
+ */
+
+ return 0;
+}
+
+/* Insert a device into a driver's device list and assign a driver minor number
+ * to the device.
+ *
+ * The devices are ordered by their minor number (sorted linked list of devices)
+ * the minor number is found by looking for a gap or at the end.
+ */
+static void drvmgr_insert_dev_into_drv(
+ struct drvmgr_drv *drv,
+ struct drvmgr_dev *dev)
+{
+ struct drvmgr_dev *curr, **pprevnext;
+ int minor;
+
+ minor = 0;
+ pprevnext = &drv->dev;
+ curr = drv->dev;
+
+ while (curr) {
+ if (minor < curr->minor_drv) {
+ /* Found a gap. Insert new device between prev
+ * and curr. */
+ break;
+ }
+ minor++;
+ pprevnext = &curr->next_in_drv;
+ curr = curr->next_in_drv;
+ }
+ dev->next_in_drv = curr;
+ *pprevnext = dev;
+
+ /* Set minor */
+ dev->minor_drv = minor;
+ drv->dev_cnt++;
+}
+
+/* Insert a device into a bus device list and assign a bus minor number to the
+ * device.
+ *
+ * The devices are ordered by their minor number (sorted linked list of devices)
+ * and by their registeration order if not using the same driver.
+ *
+ * The minor number is found by looking for a gap or at the end.
+ */
+static void drvmgr_insert_dev_into_bus(
+ struct drvmgr_bus *bus,
+ struct drvmgr_dev *dev)
+{
+ struct drvmgr_dev *curr, **pprevnext;
+ int minor;
+
+ minor = 0;
+ pprevnext = &bus->children;
+ curr = bus->children;
+
+ while (curr) {
+ if (dev->drv && (dev->drv == curr->drv)) {
+ if (minor < curr->minor_bus) {
+ /* Found a gap. Insert new device between prev
+ * and curr. */
+ break;
+ }
+ minor++;
+ }
+ pprevnext = &curr->next_in_bus;
+ curr = curr->next_in_bus;
+ }
+ dev->next_in_bus = curr;
+ *pprevnext = dev;
+
+ /* Set minor. Devices without driver are given -1 */
+ if (dev->drv == NULL)
+ minor = -1;
+ dev->minor_bus = minor;
+ bus->dev_cnt++;
+}
+
+/* Try to find a driver for a device (unite a device with driver).
+ * a device with a driver
+ */
+static struct drvmgr_drv *drvmgr_dev_find_drv(
+ struct drvmgr_dev *dev)
+{
+ struct rtems_driver_manager *mgr = &drv_mgr;
+ struct drvmgr_drv *drv;
+
+ /* NOTE: No locking is needed here since Driver list is supposed to be
+ * initialized once during startup, we treat it as a static
+ * read-only list
+ */
+
+ /* Try to find a driver that can handle this device */
+ for (drv = DRV_LIST_HEAD(&mgr->drivers); drv; drv = drv->next)
+ if (dev->parent->ops->unite(drv, dev) == 1)
+ break;
+
+ return drv;
+}
+
+/* Register a device */
+int drvmgr_dev_register(struct drvmgr_dev *dev)
+{
+ struct rtems_driver_manager *mgr = &drv_mgr;
+ struct drvmgr_drv *drv;
+ struct drvmgr_bus *bus = dev->parent;
+ struct drvmgr_key *keys;
+ struct drvmgr_list *init_list = &mgr->devices_inactive;
+
+ DBG("DEV_REG: %s at bus \"%s\"\n", dev->name,
+ bus && bus->dev && bus->dev->name ? bus->dev->name : "UNKNOWN");
+
+ /* Custom driver assocation? */
+ if (dev->drv) {
+ drv = dev->drv;
+ DBG("CUSTOM ASSOCIATION (%s to %s)\n", dev->name, drv->name);
+ } else {
+ /* Try to find a driver that can handle this device */
+ dev->drv = drv = drvmgr_dev_find_drv(dev);
+ }
+
+ DRVMGR_LOCK_WRITE();
+
+ /* Assign Bus Minor number and put into bus device list
+ * unless root device.
+ */
+ if (bus)
+ drvmgr_insert_dev_into_bus(bus, dev);
+
+ if (!drv) {
+ /* No driver found that can handle this device, put into
+ * inactive list
+ */
+ dev->minor_drv = -1;
+ dev->state |= DEV_STATE_LIST_INACTIVE;
+ } else {
+ /* United device with driver.
+ * Put the device on the registered device list
+ */
+ dev->state |= DEV_STATE_UNITED;
+
+ /* Check if user want to skip this core. This is not a
+ * normal request, however in a multi-processor system
+ * the two(or more) RTEMS instances must not use the same
+ * devices in a system, not reporting a device to
+ * it's driver will effectively accomplish this. In a
+ * non Plug & Play system one can easily avoid this
+ * problem by not report the core, but in a Plug & Play
+ * system the bus driver will report all found cores.
+ *
+ * To stop the two RTEMS instances from using the same
+ * device the user can simply define a resource entry
+ * for a certain device but set the keys field to NULL.
+ */
+ if (drvmgr_keys_get(dev, &keys) == 0 && keys == NULL) {
+ /* Found Driver resource entry point
+ * for this device, it was NULL, this
+ * indicates to skip the core.
+ *
+ * We put it into the inactive list
+ * marking it as ignored.
+ */
+ dev->state |= DEV_STATE_IGNORED;
+ } else {
+ /* Assign Driver Minor number and put into driver's
+ * device list
+ */
+ drvmgr_insert_dev_into_drv(drv, dev);
+
+ /* Just register device, it will be initialized
+ * later together with bus.
+ *
+ * At the end of the list (breadth first search)
+ */
+ init_list = &mgr->devices[0];
+
+ DBG("Registered %s (DRV: %s) on %s\n",
+ dev->name, drv->name,
+ bus ? bus->dev->name : "NO PARENT");
+ }
+ }
+
+ drvmgr_list_add_tail(init_list, dev);
+
+ DRVMGR_UNLOCK();
+
+ /* Trigger Device initialization if not root device and
+ * has a driver
+ */
+ if (bus && dev->drv)
+ drvmgr_init_update();
+
+ return 0;
+}
+
+/* Register a bus */
+int drvmgr_bus_register(struct drvmgr_bus *bus)
+{
+ struct rtems_driver_manager *mgr = &drv_mgr;
+ struct drvmgr_bus *bus_up;
+
+ /* Get bus architecture depth - the distance from root bus */
+ bus->depth = 0;
+ bus_up = bus->dev->parent;
+ while (bus_up) {
+ bus->depth++;
+ bus_up = bus_up->dev->parent;
+ }
+
+ DRVMGR_LOCK_WRITE();
+
+ /* Put driver into list of found buses */
+ drvmgr_list_add_tail(&mgr->buses[0], bus);
+
+ DRVMGR_UNLOCK();
+
+ /* Take bus into level1 and so on */
+ drvmgr_init_update();
+
+ return 0;
+}
+
+/* Allocate memory for a Device structure */
+int drvmgr_alloc_dev(struct drvmgr_dev **pdev, int extra)
+{
+ struct drvmgr_dev *dev;
+ int size;
+
+ size = ((sizeof(struct drvmgr_dev) + 3) & ~0x3) + extra;
+ dev = (struct drvmgr_dev *)malloc(size);
+ if (!dev) {
+ /* Failed to allocate device structure - critical error */
+ rtems_fatal_error_occurred(RTEMS_NO_MEMORY);
+ }
+ *pdev = dev;
+ memset(dev, 0, size);
+ dev->obj_type = DRVMGR_OBJ_DEV;
+
+ return 0;
+}
+
+/* Allocate memory for a Bus structure */
+int drvmgr_alloc_bus(struct drvmgr_bus **pbus, int extra)
+{
+ struct drvmgr_bus *bus;
+ int size;
+
+ size = ((sizeof(struct drvmgr_bus) + 3) & ~0x3) + extra;
+ bus = (struct drvmgr_bus *)malloc(size);
+ if (!bus) {
+ /* Failed to allocate device structure - critical error */
+ rtems_fatal_error_occurred(RTEMS_NO_MEMORY);
+ }
+ *pbus = bus;
+ memset(bus, 0, size);
+ bus->obj_type = DRVMGR_OBJ_BUS;
+
+ return 0;
+}
+
+/* Add driver resources to a bus instance */
+void drvmgr_bus_res_add(struct drvmgr_bus *bus,
+ struct drvmgr_bus_res *bres)
+{
+ /* insert first in bus resource list. Locking isn't needed since
+ * resources can only be added before resource requests are made.
+ * When bus has been registered resources are considered a read-only
+ * tree.
+ */
+ bres->next = bus->reslist;
+ bus->reslist = bres;
+}
diff --git a/cpukit/libdrvmgr/drvmgr.h b/cpukit/libdrvmgr/drvmgr.h
new file mode 100644
index 0000000000..fe8cd1ee3f
--- /dev/null
+++ b/cpukit/libdrvmgr/drvmgr.h
@@ -0,0 +1,889 @@
+/* Driver Manager Interface.
+ *
+ * COPYRIGHT (c) 2009-2011
+ * Aeroflex Gaisler AB
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ */
+
+#ifndef _DRIVER_MANAGER_H_
+#define _DRIVER_MANAGER_H_
+
+#include <rtems.h>
+#include <drvmgr/drvmgr_list.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*** Configure Driver manager ***/
+
+/* Define the number of initialization levels of device drivers */
+#define DRVMGR_LEVEL_MAX 4
+
+struct drvmgr_dev; /* Device */
+struct drvmgr_bus; /* Bus */
+struct drvmgr_drv; /* Driver */
+
+/*** List Interface shortcuts ***/
+#define BUS_LIST_HEAD(list) LIST_HEAD(list, struct drvmgr_bus)
+#define BUS_LIST_TAIL(list) LIST_TAIL(list, struct drvmgr_bus)
+#define DEV_LIST_HEAD(list) LIST_HEAD(list, struct drvmgr_dev)
+#define DEV_LIST_TAIL(list) LIST_TAIL(list, struct drvmgr_dev)
+#define DRV_LIST_HEAD(list) LIST_HEAD(list, struct drvmgr_drv)
+#define DRV_LIST_TAIL(list) LIST_TAIL(list, struct drvmgr_drv)
+
+/*** Bus indentification ***/
+#define DRVMGR_BUS_TYPE_NONE 0 /* Not a valid bus */
+#define DRVMGR_BUS_TYPE_ROOT 1 /* Hard coded bus */
+#define DRVMGR_BUS_TYPE_PCI 2 /* PCI bus */
+#define DRVMGR_BUS_TYPE_AMBAPP 3 /* AMBA Plug & Play bus */
+#define DRVMGR_BUS_TYPE_LEON2_AMBA 4 /* LEON2 hardcoded bus */
+#define DRVMGR_BUS_TYPE_AMBAPP_DIST 5 /* Distibuted AMBA Plug & Play bus accessed using a communication interface */
+#define DRVMGR_BUS_TYPE_SPW_RMAP 6 /* SpaceWire Network bus */
+#define DRVMGR_BUS_TYPE_AMBAPP_RMAP 7 /* SpaceWire RMAP accessed AMBA Plug & Play bus */
+
+enum {
+ DRVMGR_OBJ_NONE = 0,
+ DRVMGR_OBJ_DRV = 1,
+ DRVMGR_OBJ_BUS = 2,
+ DRVMGR_OBJ_DEV = 3,
+};
+
+/*** Driver indentification ***
+ *
+ * 64-bit identification integer definition
+ * * Bus ID 8-bit [7..0]
+ * * Reserved 8-bit field [63..56]
+ * * Device ID specific for bus type 48-bit [55..8] (Different buses have
+ * different unique identifications for hardware/driver.)
+ *
+ * ID Rules
+ * * A root bus driver must always have device ID set to 0. There can only by
+ * one root bus driver for a certain bus type.
+ * * A Driver ID must identify a unique hardware core
+ *
+ */
+
+/* Bus ID Mask */
+#define DRIVER_ID_BUS_MASK 0x00000000000000FFULL
+
+/* Reserved Mask for future use */
+#define DRIVER_ID_RSV_MASK 0xFF00000000000000ULL
+
+/* Reserved Mask for future use */
+#define DRIVER_ID_DEV_MASK 0x00FFFFFFFFFFFF00ULL
+
+/* Set Bus ID Mask. */
+#define DRIVER_ID(busid, devid) ((unsigned long long) \
+ ((((unsigned long long)(devid) << 8) & DRIVER_ID_DEV_MASK) | \
+ ((unsigned long long)(busid) & DRIVER_ID_BUS_MASK)))
+
+/* Get IDs */
+#define DRIVER_BUSID_GET(id) ((unsigned long long)(id) & DRIVER_ID_BUS_MASK)
+#define DRIVER_DEVID_GET(id) (((unsigned long long)(id) & DRIVER_ID_DEV_MASK) >> 8)
+
+#define DRIVER_ROOTBUS_ID(bus_type) DRIVER_ID(bus_type, 0)
+
+/*** Root Bus drivers ***/
+
+/* Generic Hard coded Root bus: Driver ID */
+#define DRIVER_ROOT_ID DRIVER_ROOTBUS_ID(DRVMGR_BUS_TYPE_ROOT)
+
+/* PCI Plug & Play bus: Driver ID */
+#define DRIVER_PCIBUS_ID DRIVER_ROOTBUS_ID(DRVMGR_BUS_TYPE_PCI)
+
+/* AMBA Plug & Play bus: Driver ID */
+#define DRIVER_GRLIB_AMBAPP_ID DRIVER_ROOTBUS_ID(DRVMGR_BUS_TYPE_AMBAPP)
+
+/* AMBA Hard coded bus: Driver ID */
+#define DRIVER_LEON2_AMBA_ID DRIVER_ROOTBUS_ID(DRVMGR_BUS_TYPE_LEON2_AMBA)
+
+/* Distributed AMBA Plug & Play bus: Driver ID */
+#define DRIVER_AMBAPP_DIST_ID DRIVER_ROOTBUS_ID(DRVMGR_BUS_TYPE_AMBAPP_DIST)
+
+/*! Bus parameters used by driver interface functions to aquire information
+ * about bus. All Bus drivers should implement the operation 'get_params' so
+ * that the driver interface routines can access bus dependent information in
+ * an non-dependent way.
+ */
+struct drvmgr_bus_params {
+ char *dev_prefix; /*!< Optional name prefix */
+};
+
+/* Interrupt Service Routine (ISR) */
+typedef void (*drvmgr_isr)(void *arg);
+
+/*! Bus operations */
+struct drvmgr_bus_ops {
+ /* Functions used internally within driver manager */
+ int (*init[DRVMGR_LEVEL_MAX])(struct drvmgr_bus *);
+ int (*remove)(struct drvmgr_bus *);
+ int (*unite)(struct drvmgr_drv *, struct drvmgr_dev *); /*!< Unite Hardware Device with Driver */
+
+ /* Functions called indirectly from drivers */
+ int (*int_register)(struct drvmgr_dev *, int index, const char *info, drvmgr_isr isr, void *arg);
+ int (*int_unregister)(struct drvmgr_dev *, int index, drvmgr_isr isr, void *arg);
+ int (*int_clear)(struct drvmgr_dev *, int index);
+ int (*int_mask)(struct drvmgr_dev *, int index);
+ int (*int_unmask)(struct drvmgr_dev *, int index);
+
+ /* Get Parameters */
+ int (*get_params)(struct drvmgr_dev *, struct drvmgr_bus_params *);
+ /* Get Frequency of Bus */
+ int (*freq_get)(struct drvmgr_dev*, int, unsigned int*);
+ /*! Function called to request information about a device. The bus
+ * driver interpret the bus-specific information about the device.
+ */
+ void (*info_dev)(struct drvmgr_dev *, void (*print)(void *p, char *str), void *p);
+};
+#define BUS_OPS_NUM (sizeof(struct drvmgr_bus_ops)/sizeof(void (*)(void)))
+
+struct drvmgr_func {
+ int funcid;
+ void *func;
+};
+#define DRVMGR_FUNC(_ID_, _FUNC_) {(int)(_ID_), (void *)(_FUNC_)}
+#define DRVMGR_FUNC_END {0, NULL}
+
+/*** Resource definitions ***
+ *
+ * Overview of structures:
+ * All bus resources entries (_bus_res) are linked together per bus
+ * (bus_info->reslist). One bus resource entry has a pointer to an array of
+ * driver resources (_drv_res). One driver resouces is made out of an array
+ * of keys (drvmgr_key). All keys belongs to the same driver and harwdare
+ * device. Each key has a Name, Type ID and Data interpreted differently
+ * depending on the Type ID (union drvmgr_key_value).
+ *
+ */
+
+/* Key Data Types */
+#define KEY_TYPE_NONE 0
+#define KEY_TYPE_INT 1
+#define KEY_TYPE_STRING 2
+#define KEY_TYPE_POINTER 3
+
+#define KEY_EMPTY {NULL, KEY_TYPE_NONE, {0}}
+#define RES_EMPTY {0, 0, NULL}
+#define MMAP_EMPTY {0, 0, 0}
+
+/*! Union of different values */
+union drvmgr_key_value {
+ unsigned int i; /*!< Key data type UNSIGNED INTEGER */
+ char *str; /*!< Key data type STRING */
+ void *ptr; /*!< Key data type ADDRESS/POINTER */
+};
+
+/* One key. One Value. Holding information relevant to the driver. */
+struct drvmgr_key {
+ char *key_name; /* Name of key */
+ int key_type; /* How to interpret key_value */
+ union drvmgr_key_value key_value; /* The value or pointer to value */
+};
+
+/*! Driver resource entry, Driver resources for a certain device instance,
+ * containing a number of keys where each key hold the data of interest.
+ */
+struct drvmgr_drv_res {
+ uint64_t drv_id; /*!< Identifies the driver this resource is aiming */
+ int minor_bus; /*!< Indentifies a specfic device */
+ struct drvmgr_key *keys; /*!< First key in key array, ended with KEY_EMPTY */
+};
+
+/*! Bus resource list node */
+struct drvmgr_bus_res {
+ struct drvmgr_bus_res *next; /*!< Next resource node in list */
+ struct drvmgr_drv_res resource[]; /*!< Array of resources, one per device instance */
+};
+
+/*! MAP entry. Describes an linear address space translation. Untranslated
+ * Start, Translated Start and length.
+ *
+ * Used by bus drivers to describe the address translation needed for
+ * the translation driver interface.
+ */
+struct drvmgr_map_entry {
+ char *name; /*!< Map Name */
+ unsigned int size; /*!< Size of map window */
+ char *from_adr; /*!< Start address of access window used
+ * to reach into remote bus */
+ char *to_adr; /*!< Start address of remote system
+ * address range */
+};
+#define DRVMGR_TRANSLATE_ONE2ONE NULL
+#define DRVMGR_TRANSLATE_NO_BRIDGE ((void *)1) /* No bridge, error */
+
+/*! Bus information. Describes a bus. */
+struct drvmgr_bus {
+ int obj_type; /*!< DRVMGR_OBJ_BUS */
+ unsigned char bus_type; /*!< Type of bus */
+ unsigned char depth; /*!< Bus level distance from root bus */
+ struct drvmgr_bus *next; /*!< Next Bus */
+ struct drvmgr_dev *dev; /*!< Bus device, the hardware... */
+ void *priv; /*!< Private data structure used by BUS driver */
+ struct drvmgr_dev *children; /*!< Hardware devices on this bus */
+ struct drvmgr_bus_ops *ops; /*!< Bus operations supported by this bus driver */
+ struct drvmgr_func *funcs; /*!< Extra operations */
+ int dev_cnt; /*!< Number of devices this bus has */
+ struct drvmgr_bus_res *reslist; /*!< Bus resources, head of a linked list of resources. */
+ struct drvmgr_map_entry *maps_up; /*!< Map Translation, array of address spaces upstreams to CPU */
+ struct drvmgr_map_entry *maps_down; /*!< Map Translation, array of address spaces downstreams to Hardware */
+
+ /* Bus status */
+ int level; /*!< Initialization Level of Bus */
+ int state; /*!< Init State of Bus, BUS_STATE_* */
+ int error; /*!< Return code from bus->ops->initN() */
+};
+
+/* States of a bus */
+#define BUS_STATE_INIT_FAILED 0x00000001 /* Initialization Failed */
+#define BUS_STATE_LIST_INACTIVE 0x00001000 /* In inactive bus list */
+#define BUS_STATE_DEPEND_FAILED 0x00000004 /* Device init failed */
+
+/* States of a device */
+#define DEV_STATE_INIT_FAILED 0x00000001 /* Initialization Failed */
+#define DEV_STATE_INIT_DONE 0x00000002 /* All init levels completed */
+#define DEV_STATE_DEPEND_FAILED 0x00000004 /* Parent Bus init failed */
+#define DEV_STATE_UNITED 0x00000100 /* Device United with Device Driver */
+#define DEV_STATE_REMOVED 0x00000200 /* Device has been removed (unregistered) */
+#define DEV_STATE_IGNORED 0x00000400 /* Device was ignored according to user's request, the device
+ * was never reported to it's driver (as expected).
+ */
+#define DEV_STATE_LIST_INACTIVE 0x00001000 /* In inactive device list */
+
+/*! Device information */
+struct drvmgr_dev {
+ int obj_type; /*!< DRVMGR_OBJ_DEV */
+ struct drvmgr_dev *next; /*!< Next device */
+ struct drvmgr_dev *next_in_bus; /*!< Next device on the same bus */
+ struct drvmgr_dev *next_in_drv; /*!< Next device using the same driver */
+
+ struct drvmgr_drv *drv; /*!< The driver owning this device */
+ struct drvmgr_bus *parent; /*!< Bus that this device resides on */
+ short minor_drv; /*!< Device number within driver */
+ short minor_bus; /*!< Device number on bus (for device separation) */
+ char *name; /*!< Name of Device Hardware */
+ void *priv; /*!< Pointer to driver private device structure */
+ void *businfo; /*!< Host bus specific information */
+ struct drvmgr_bus *bus; /*!< Pointer to bus, set only if this is a bridge */
+
+ /* Device Status */
+ unsigned int state; /*!< State of device, see DEV_STATE_* */
+ int level; /*!< Init Level */
+ int error; /*!< Error state returned by driver */
+};
+
+/*! Driver operations, function pointers. */
+struct drvmgr_drv_ops {
+ int (*init[DRVMGR_LEVEL_MAX])(struct drvmgr_dev *); /*! Function doing Init Stage 1 of a hardware device */
+ int (*remove)(struct drvmgr_dev *); /*! Function called when device instance is to be removed */
+ int (*info)(struct drvmgr_dev *, void (*print)(void *p, char *str), void *p, int, char *argv[]);/*! Function called to request information about a device or driver */
+};
+#define DRV_OPS_NUM (sizeof(struct drvmgr_drv_ops)/sizeof(void (*)(void)))
+
+/*! Device driver description */
+struct drvmgr_drv {
+ int obj_type; /*!< DRVMGR_OBJ_DRV */
+ struct drvmgr_drv *next; /*!< Next Driver */
+ struct drvmgr_dev *dev; /*!< Devices using this driver */
+
+ uint64_t drv_id; /*!< Unique Driver ID */
+ char *name; /*!< Name of Driver */
+ int bus_type; /*!< Type of Bus this driver supports */
+ struct drvmgr_drv_ops *ops; /*!< Driver operations */
+ struct drvmgr_func *funcs; /*!< Extra Operations */
+ unsigned int dev_cnt; /*!< Number of devices in dev */
+ unsigned int dev_priv_size; /*!< If non-zero DRVMGR will allocate memory for dev->priv */
+};
+
+/*! Structure defines a function pointer called when driver manager is ready
+ * for drivers to register themselfs. Used to select drivers available to the
+ * driver manager.
+ */
+struct drvmgr_drv_reg_func {
+ void (*drv_reg)(void);
+};
+
+/*** DRIVER | DEVICE | BUS FUNCTIONS ***/
+
+/* Return Codes */
+enum {
+ DRVMGR_OK = 0,
+ DRVMGR_NOMEM = 1,
+ DRVMGR_EIO = 2,
+ DRVMGR_EINVAL = 3,
+ DRVMGR_ENOSYS = 4,
+ DRVMGR_TIMEDOUT = 5,
+ DRVMGR_EBUSY = 6,
+ DRVMGR_ENORES = 7, /* Not enough resources */
+ DRVMGR_FAIL = -1
+};
+
+/*! Initialize data structures of the driver management system.
+ * Calls predefined register driver functions so that drivers can
+ * register themselves.
+ */
+extern void _DRV_Manager_initialization(void);
+
+/*! Take all devices into init level 'level', all devices registered later
+ * will directly be taken into this level as well, ensuring that all
+ * registerd devices has been taken into the level.
+ *
+ */
+extern void _DRV_Manager_init_level(int level);
+
+/*! Init driver manager all in one go, will call _DRV_Manager_initialization(),
+ * then _DRV_Manager_init_level([1..DRVMGR_LEVEL_MAX]).
+ * Typically called from Init task when user wants to initilize driver
+ * manager after startup, otherwise not used.
+ */
+extern int drvmgr_init(void);
+
+/* Take registered buses and devices into the correct init level,
+ * this function is called from _init_level() so normally
+ * we don't need to call it directly.
+ */
+extern void drvmgr_init_update(void);
+
+/*! Register Root Bus device driver */
+extern int drvmgr_root_drv_register(struct drvmgr_drv *drv);
+
+/*! Register a driver */
+extern int drvmgr_drv_register(struct drvmgr_drv *drv);
+
+/*! Register a device */
+extern int drvmgr_dev_register(struct drvmgr_dev *dev);
+
+/*! Remove a device, and all its children devices if device is a bus device. The
+ * device driver will be requested to remove the device and once gone from bus,
+ * device and driver list the device is put into a inactive list for debugging
+ * (this is optional by using remove argument).
+ *
+ * Removing the Root Bus Device is not supported.
+ *
+ * \param remove If non-zero the device will be deallocated, and not put into
+ * the inacitve list.
+ */
+extern int drvmgr_dev_unregister(struct drvmgr_dev *dev);
+
+/*! Register a bus */
+extern int drvmgr_bus_register(struct drvmgr_bus *bus);
+
+/*! Unregister a bus */
+extern int drvmgr_bus_unregister(struct drvmgr_bus *bus);
+
+/*! Unregister all child devices of a bus.
+ *
+ * This function is called from the bus driver, from a "safe" state where
+ * devices will not be added or removed on this particular bus at this time
+ */
+extern int drvmgr_children_unregister(struct drvmgr_bus *bus);
+
+/* Separate a device from the driver it has been united with */
+extern int drvmgr_dev_drv_separate(struct drvmgr_dev *dev);
+
+/*! Allocate a device structure, if no memory available
+ * rtems_error_fatal_occurred is called.
+ * The 'extra' argment tells how many bytes extra space is to be allocated after
+ * the device structure, this is typically used for "businfo" structures. The extra
+ * space is always aligned to a 4-byte boundary.
+ */
+extern int drvmgr_alloc_dev(struct drvmgr_dev **pdev, int extra);
+
+/*! Allocate a bus structure, if no memory available rtems_error_fatal_occurred
+ * is called.
+ * The 'extra' argment tells how many bytes extra space is to be allocated after
+ * the device structure, this is typically used for "businfo" structures. The
+ * extra space is always aligned to a 4-byte boundary.
+ */
+extern int drvmgr_alloc_bus(struct drvmgr_bus **pbus, int extra);
+
+/*** DRIVER RESOURCE FUNCTIONS ***/
+
+/*! Add resources to a bus, typically used by a bus driver.
+ *
+ * \param bus The Bus to add the resources to.
+ * \param res An array with Driver resources, all together are called bus
+ * resources.
+ */
+extern void drvmgr_bus_res_add(struct drvmgr_bus *bus,
+ struct drvmgr_bus_res *bres);
+
+/*! Find all the resource keys for a device among all driver resources on a
+ * bus. Typically used by a device driver to get configuration options.
+ *
+ * \param dev Device to find resources for
+ * \param key Location where the pointer to the driver resource array (drvmgr_drv_res->keys) is stored.
+ */
+extern int drvmgr_keys_get(struct drvmgr_dev *dev, struct drvmgr_key **keys);
+
+/*! Return the one key that matches key name from a driver keys array. The keys
+ * can be obtained using drvmgr_keys_get().
+ *
+ * \param keys An array of keys ended with KEY_EMPTY to search among.
+ * \param key_name Name of key to search for among the keys.
+ */
+extern struct drvmgr_key *drvmgr_key_get(struct drvmgr_key *keys, char *key_name);
+
+/*! Extract key value from the key in the keys array matching name and type.
+ *
+ * This function calls drvmgr_keys_get to get the key requested (from key
+ * name), then determines if the type is correct. A pointer to the key value
+ * is returned.
+ *
+ * \param keys An array of keys ended with KEY_EMPTY to search among.
+ * \param key_name Name of key to search for among the keys.
+ * \param key_type Data Type of value. INTEGER, ADDRESS, STRING.
+ * \return Returns NULL if no value found matching Key Name and Key
+ * Type.
+ */
+extern union drvmgr_key_value *drvmgr_key_val_get(
+ struct drvmgr_key *keys,
+ char *key_name,
+ int key_type);
+
+/*! Get key value from the bus resources matching [device, key name, key type]
+ * if no matching key is found NULL is returned.
+ *
+ * This is typically used by device drivers to find a particular device
+ * resource.
+ *
+ * \param dev The device to search resource for.
+ * \param key_name The key name to search for
+ * \param key_type The key type expected.
+ * \return Returns NULL if no value found matching Key Name and
+ * Key Type was found for device.
+ */
+extern union drvmgr_key_value *drvmgr_dev_key_get(
+ struct drvmgr_dev *dev,
+ char *key_name,
+ int key_type);
+
+/*** DRIVER INTERACE USED TO REQUEST INFORMATION/SERVICES FROM BUS DRIVER ***/
+
+/*! Get parent bus */
+static inline struct drvmgr_bus *drvmgr_get_parent(struct drvmgr_dev *dev)
+{
+ if (dev)
+ return dev->parent;
+ else
+ return NULL;
+}
+
+/*! Get Driver of device */
+static inline struct drvmgr_drv *drvmgr_get_drv(struct drvmgr_dev *dev)
+{
+ if (dev)
+ return dev->drv;
+ else
+ return NULL;
+}
+
+/*! Calls func() for every device found in the device tree, regardless of
+ * device state or if a driver is assigned. With the options argument the user
+ * can decide to do either a depth-first or a breadth-first search.
+ *
+ * If the function func() returns a non-zero value then for_each_dev will
+ * return imediatly with the same return value as func() returned.
+ *
+ * \param func Function called on each device
+ * \param arg Custom function argument
+ * \param options Search Options, see DRVMGR_FED_*
+ *
+ */
+#define DRVMGR_FED_BF 1 /* Breadth-first search */
+#define DRVMGR_FED_DF 0 /* Depth first search */
+extern int drvmgr_for_each_dev(
+ int (*func)(struct drvmgr_dev *dev, void *arg),
+ void *arg,
+ int options);
+
+/*! Get Device pointer from Driver and Driver minor number
+ *
+ * \param drv Driver the device is united with.
+ * \param minor Driver minor number assigned to device.
+ * \param pdev Location where the Device point will be stored.
+ * \return Zero on success. -1 on failure, when device was not
+ * found in driver device list.
+ */
+extern int drvmgr_get_dev(
+ struct drvmgr_drv *drv,
+ int minor,
+ struct drvmgr_dev **pdev);
+
+/*! Get Bus frequency in Hertz. Frequency is stored into address of freq_hz.
+ *
+ * \param dev The Device to get Bus frequency for.
+ * \param options Bus-type specific options
+ * \param freq_hz Location where Bus Frequency will be stored.
+ */
+extern int drvmgr_freq_get(
+ struct drvmgr_dev *dev,
+ int options,
+ unsigned int *freq_hz);
+
+/*! Return 0 if dev is not located on the root bus, 1 if on root bus */
+extern int drvmgr_on_rootbus(struct drvmgr_dev *dev);
+
+/*! Get device name prefix, this name can be used to register a unique name in
+ * the bus->error filesystem or to get an idea where the device is located.
+ *
+ * \param dev The Device to get the device Prefix for.
+ * \param dev_prefix Location where the prefix will be stored.
+ */
+extern int drvmgr_get_dev_prefix(struct drvmgr_dev *dev, char *dev_prefix);
+
+/*! Register a shared interrupt handler. Since this service is shared among
+ * interrupt drivers/handlers the handler[arg] must be installed before the
+ * interrupt can be cleared or disabled. The handler is by default disabled
+ * after registration.
+ *
+ * \param index Index is used to identify the IRQ number if hardware has
+ * multiple IRQ sources. Normally Index is set to 0 to
+ * indicated the first and only IRQ source.
+ * A negative index is interpreted as a absolute bus IRQ
+ * number.
+ * \param isr Interrupt Service Routine.
+ * \param arg Optional ISR argument.
+ */
+extern int drvmgr_interrupt_register(
+ struct drvmgr_dev *dev,
+ int index,
+ const char *info,
+ drvmgr_isr isr,
+ void *arg);
+
+/*! Unregister an interrupt handler. This also disables the interrupt before
+ * unregistering the interrupt handler.
+ * \param index Index is used to identify the IRQ number if hardware has
+ * multiple IRQ sources. Normally Index is set to 0 to
+ * indicated the first and only IRQ source.
+ * A negative index is interpreted as a absolute bus IRQ
+ * number.
+ * \param isr Interrupt Service Routine, previously registered.
+ * \param arg Optional ISR argument, previously registered.
+ */
+extern int drvmgr_interrupt_unregister(
+ struct drvmgr_dev *dev,
+ int index,
+ drvmgr_isr isr,
+ void *arg);
+
+/*! Clear (ACK) pending interrupt
+ *
+ * \param dev Device to clear interrupt for.
+ * \param index Index is used to identify the IRQ number if hardware has multiple IRQ sources.
+ * Normally Index is set to 0 to indicated the first and only IRQ source.
+ * A negative index is interpreted as a absolute bus IRQ number.
+ * \param isr Interrupt Service Routine, previously registered.
+ * \param arg Optional ISR argument, previously registered.
+ */
+extern int drvmgr_interrupt_clear(
+ struct drvmgr_dev *dev,
+ int index);
+
+/*! Force unmasking/enableing an interrupt on the interrupt controller, this is not normally used,
+ * if used the caller has masked/disabled the interrupt just before.
+ *
+ * \param dev Device to clear interrupt for.
+ * \param index Index is used to identify the IRQ number if hardware has multiple IRQ sources.
+ * Normally Index is set to 0 to indicated the first and only IRQ source.
+ * A negative index is interpreted as a absolute bus IRQ number.
+ * \param isr Interrupt Service Routine, previously registered.
+ * \param arg Optional ISR argument, previously registered.
+ */
+extern int drvmgr_interrupt_unmask(
+ struct drvmgr_dev *dev,
+ int index);
+
+/*! Force masking/disable an interrupt on the interrupt controller, this is not normally performed
+ * since this will stop all other (shared) ISRs to be disabled until _unmask() is called.
+ *
+ * \param dev Device to mask interrupt for.
+ * \param index Index is used to identify the IRQ number if hardware has multiple IRQ sources.
+ * Normally Index is set to 0 to indicated the first and only IRQ source.
+ * A negative index is interpreted as a absolute bus IRQ number.
+ */
+extern int drvmgr_interrupt_mask(
+ struct drvmgr_dev *dev,
+ int index);
+
+/*! Translate an address on one bus to an address on another bus.
+ *
+ * The device determines source or destination bus, the root bus is always
+ * the other bus. It is assumed that the CPU is located on the root bus or
+ * that it can access it without address translation (mapped 1:1).
+ *
+ * cpu_addresses determines if the address is targeted for the CPU (1) or
+ * hardware (0) doing DMA.
+ *
+ * The address conversion can be done up-streams (towards the CPU) or down-
+ * streams (towards DMA hardware) the bus architecture. The CPU is assumed
+ * to be located on level 0 top most in the bus hierarchy.
+ *
+ * Source address is translated and the result is put into *dst_address, if
+ * the address is not accessible on the other bus -1 is returned.
+ *
+ * Two common operations is to translate a CPU accessible RAM address to an
+ * address that DMA units can access (dev=DMA-unit, cpu_address=0, upstream=0,
+ * src_address=CPU-RAM-ADR) and to translate an address of a PCI resource for
+ * example RAM mapped into a PCI BAR to an CPU accessible address
+ * (dev=PCI-device, cpu_address=1, upstream=1, src_address=PCI-BAR-ADR).
+ *
+ * \param dev Device to translate addresses for
+ * \param cpu_addresses Addresses are inteded for CPU(1) or DMA-Hardware(0)
+ * \param upsteam Select translation direction (0=towards hardware,
+ * 1=towards CPU) and thereby which bus src_address is
+ * valid for
+ * \param src_address Address to translate
+ * \param dst_address Location where translated address is stored
+ *
+ * Returns -1 if unable to translate. If no map is present src_address is
+ * translated 1:1 (just copied). If dev is on root-bus no translation is
+ * performed 0 is returned and src_address is stored in *dst_address.
+ */
+extern int drvmgr_translate(
+ struct drvmgr_dev *dev,
+ int cpu_addresses,
+ int upstream,
+ void *src_address,
+ void **dst_address);
+
+/* Translate addresses between buses, used internally to implement
+ * drvmgr_translate. Function is not limited to translate from/to root bus
+ * where CPU is resident, however buses must be on a straight path relative
+ * to each other (parent of parent of parent and so on).
+ *
+ * \param from src_address is given for this bus
+ * \param to src_address is translated to this bus
+ * \param reverse Selects translation method, if map entries are used in
+ * the reverse order (map_up->to is used as map_up->from)
+ * \param src_address Address to be translated
+ * \param dst_address Translated address is stored here on success (return=0)
+ *
+ * Returns -1 if failed to translate address between buses. 0 successfully
+ * translated, reuslt is in *dst_address
+ */
+extern int drvmgr_translate_bus(
+ struct drvmgr_bus *from,
+ struct drvmgr_bus *to,
+ int reverse,
+ void *src_address,
+ void **dst_address);
+
+/*! Get function pointer from Device Driver or Bus Driver.
+ *
+ * Returns 0 if function is available
+ */
+extern int drvmgr_func_get(void *obj, int funcid, void **func);
+
+/*! Lookup function and call it directly with the four optional arguments */
+extern int drvmgr_func_call(void *obj, int funcid, void *a, void *b, void *c, void *d);
+
+/* Builds a Function ID.
+ *
+ * Used to request optional functions by a bus or device driver
+ */
+#define DRVMGR_FUNCID(major, minor) ((((major) & 0xfff) << 20) | ((minor) & 0xfffff))
+#define DRVMGR_FUNCID_NONE 0
+#define DRVMGR_FUNCID_END DRVMGR_FUNCID(DRVMGR_FUNCID_NONE, 0)
+
+/* Major Function ID. Most significant 12-bits. */
+enum {
+ FUNCID_NONE = 0x000,
+ FUNCID_RW = 0x001, /* Read/Write functions */
+};
+
+/* Select Sub-Function Read/Write function by ID */
+#define RW_SIZE_1 0x00001 /* Access Size */
+#define RW_SIZE_2 0x00002
+#define RW_SIZE_4 0x00004
+#define RW_SIZE_8 0x00008
+#define RW_SIZE_ANY 0x00000
+#define RW_SIZE(id) ((unsigned int)(id) & 0xf)
+
+#define RW_DIR_ANY 0x00000 /* Access Direction */
+#define RW_READ 0x00000 /* Read */
+#define RW_WRITE 0x00010 /* Write */
+#define RW_SET 0x00020 /* Write with same value (memset) */
+#define RW_DIR(id) (((unsigned int)(id) >> 4) & 0x3)
+
+#define RW_RAW 0x00000 /* Raw access - no swapping (machine default) */
+#define RW_LITTLE 0x00040 /* Little Endian */
+#define RW_BIG 0x00080 /* Big Endian */
+#define RW_ENDIAN(id) (((unsigned int)(id) >> 6) & 0x3)
+
+#define RW_TYPE_ANY 0x00000 /* Access type */
+#define RW_REG 0x00100
+#define RW_MEM 0x00200
+#define RW_MEMREG 0x00300
+#define RW_CFG 0x00400
+#define RW_TYPE(id) (((unsigned int)(id) >> 8) & 0xf)
+
+#define RW_ARG 0x01000 /* Optional Argument */
+#define RW_ERR 0x02000 /* Optional Error Handler */
+
+/* Build a Read/Write function ID */
+#define DRVMGR_RWFUNC(minor) DRVMGR_FUNCID(FUNCID_RW, minor)
+
+/* Argument to Read/Write functions, the "void *arg" pointer is returned by
+ * RW_ARG. If NULL is returned no argument is needed.
+ */
+struct drvmgr_rw_arg {
+ void *arg;
+ struct drvmgr_dev *dev;
+};
+
+/* Standard Read/Write function types */
+typedef uint8_t (*drvmgr_r8)(uint8_t *srcadr);
+typedef uint16_t (*drvmgr_r16)(uint16_t *srcadr);
+typedef uint32_t (*drvmgr_r32)(uint32_t *srcadr);
+typedef uint64_t (*drvmgr_r64)(uint64_t *srcadr);
+typedef void (*drvmgr_w8)(uint8_t *dstadr, uint8_t data);
+typedef void (*drvmgr_w16)(uint16_t *dstadr, uint16_t data);
+typedef void (*drvmgr_w32)(uint32_t *dstadr, uint32_t data);
+typedef void (*drvmgr_w64)(uint64_t *dstadr, uint64_t data);
+/* READ/COPY a memory area located on bus into CPU memory.
+ * From 'src' (remote) to the destination 'dest' (local), n=number of bytes
+ */
+typedef int (*drvmgr_rmem)(void *dest, const void *src, int n);
+/* WRITE/COPY a user buffer located in CPU memory to a location on the bus.
+ * From 'src' (local) to the destination 'dest' (remote), n=number of bytes
+ */
+typedef int (*drvmgr_wmem)(void *dest, const void *src, int n);
+/* Set a memory area to the byte value given in c, see LIBC memset(). Memset is
+ * implemented by calling wmem() multiple times with a "large" buffer.
+ */
+typedef int (*drvmgr_memset)(void *dstadr, int c, size_t n);
+
+/* Read/Write function types with additional argument */
+typedef uint8_t (*drvmgr_r8_arg)(uint8_t *srcadr, void *a);
+typedef uint16_t (*drvmgr_r16_arg)(uint16_t *srcadr, void *a);
+typedef uint32_t (*drvmgr_r32_arg)(uint32_t *srcadr, void *a);
+typedef uint64_t (*drvmgr_r64_arg)(uint64_t *srcadr, void *a);
+typedef void (*drvmgr_w8_arg)(uint8_t *dstadr, uint8_t data, void *a);
+typedef void (*drvmgr_w16_arg)(uint16_t *dstadr, uint16_t data, void *a);
+typedef void (*drvmgr_w32_arg)(uint32_t *dstadr, uint32_t data, void *a);
+typedef void (*drvmgr_w64_arg)(uint64_t *dstadr, uint64_t data, void *a);
+typedef int (*drvmgr_rmem_arg)(void *dest, const void *src, int n, void *a);
+typedef int (*drvmgr_wmem_arg)(void *dest, const void *src, int n, void *a);
+typedef int (*drvmgr_memset_arg)(void *dstadr, int c, size_t n, void *a);
+
+/* Report an error to the parent bus of the device */
+typedef void (*drvmgr_rw_err)(struct drvmgr_rw_arg *a, struct drvmgr_bus *bus,
+ int funcid, void *adr);
+
+/* Helper function for buses that implement the memset() over wmem() */
+extern void drvmgr_rw_memset(
+ void *dstadr,
+ int c,
+ size_t n,
+ void *a,
+ drvmgr_wmem_arg wmem
+ );
+
+/*** PRINT INFORMATION ABOUT DRIVER MANAGER ***/
+
+/*! Calls func() for every device found matching the search requirements of
+ * set_mask and clr_mask. Each bit set in set_mask must be set in the
+ * device state bit mask (dev->state), and Each bit in the clr_mask must
+ * be cleared in the device state bit mask (dev->state). There are three
+ * special cases:
+ *
+ * 1. If state_set_mask and state_clr_mask are zero the state bits are
+ * ignored and all cores are treated as a match.
+ *
+ * 2. If state_set_mask is zero the function func will not be called due to
+ * a bit being set in the state mask.
+ *
+ * 3. If state_clr_mask is zero the function func will not be called due to
+ * a bit being cleared in the state mask.
+ *
+ * If the function func() returns a non-zero value then for_each_dev will
+ * return imediatly with the same return value as func() returned.
+ *
+ * \param devlist The list to iterate though searching for devices.
+ * \param state_set_mask Defines the bits that must be set in dev->state
+ * \param state_clr_mask Defines the bits that must be cleared in dev->state
+ * \param func Function called on each
+ *
+ */
+extern int drvmgr_for_each_listdev(
+ struct drvmgr_list *devlist,
+ unsigned int state_set_mask,
+ unsigned int state_clr_mask,
+ int (*func)(struct drvmgr_dev *dev, void *arg),
+ void *arg);
+
+/* Print all devices */
+#define PRINT_DEVS_FAILED 0x01 /* Failed during initialization */
+#define PRINT_DEVS_ASSIGNED 0x02 /* Driver assigned */
+#define PRINT_DEVS_UNASSIGNED 0x04 /* Driver not assigned */
+#define PRINT_DEVS_IGNORED 0x08 /* Device ignored on user's request */
+#define PRINT_DEVS_ALL (PRINT_DEVS_FAILED | \
+ PRINT_DEVS_ASSIGNED | \
+ PRINT_DEVS_UNASSIGNED |\
+ PRINT_DEVS_IGNORED)
+
+/*! Print number of devices, buses and drivers */
+extern void drvmgr_summary(void);
+
+/*! Print devices with certain condictions met according to 'options' */
+extern void drvmgr_print_devs(unsigned int options);
+
+/*! Print device/bus topology */
+extern void drvmgr_print_topo(void);
+
+/*! Print the memory usage
+ * Only accounts for data structures. Not for the text size.
+ */
+extern void drvmgr_print_mem(void);
+
+#define OPTION_DEV_GENINFO 0x00000001
+#define OPTION_DEV_BUSINFO 0x00000002
+#define OPTION_DEV_DRVINFO 0x00000004
+#define OPTION_DRV_DEVS 0x00000100
+#define OPTION_BUS_DEVS 0x00010000
+#define OPTION_RECURSIVE 0x01000000
+#define OPTION_INFO_ALL 0xffffffff
+
+/*! Print information about a driver manager object (device, driver, bus) */
+extern void drvmgr_info(void *id, unsigned int options);
+
+/*! Get information about a device */
+extern void drvmgr_info_dev(struct drvmgr_dev *dev, unsigned int options);
+
+/*! Get information about a bus */
+extern void drvmgr_info_bus(struct drvmgr_bus *bus, unsigned int options);
+
+/*! Get information about a driver */
+extern void drvmgr_info_drv(struct drvmgr_drv *drv, unsigned int options);
+
+/*! Get information about all devices on a bus */
+extern void drvmgr_info_devs_on_bus(struct drvmgr_bus *bus, unsigned int options);
+
+/*! Get information about all devices in the system (on all buses) */
+extern void drvmgr_info_devs(unsigned int options);
+
+/*! Get information about all drivers in the system */
+extern void drvmgr_info_drvs(unsigned int options);
+
+/*! Get information about all buses in the system */
+extern void drvmgr_info_buses(unsigned int options);
+
+/*! Get Driver by Driver ID */
+extern struct drvmgr_drv *drvmgr_drv_by_id(uint64_t id);
+
+/*! Get Driver by Driver Name */
+extern struct drvmgr_drv *drvmgr_drv_by_name(const char *name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/cpukit/libdrvmgr/drvmgr_by_id.c b/cpukit/libdrvmgr/drvmgr_by_id.c
new file mode 100644
index 0000000000..b7782c3839
--- /dev/null
+++ b/cpukit/libdrvmgr/drvmgr_by_id.c
@@ -0,0 +1,34 @@
+/* Find driver by driver-ID
+ *
+ * COPYRIGHT (c) 2011
+ * Aeroflex Gaisler AB
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ */
+
+#include <drvmgr/drvmgr.h>
+#include "drvmgr_internal.h"
+
+/* Get driver from driver name */
+struct drvmgr_drv *drvmgr_drv_by_id(uint64_t id)
+{
+ struct rtems_driver_manager *mgr = &drv_mgr;
+ struct drvmgr_drv *drv = NULL;
+
+ /* NOTE: No locking is needed here since Driver list is supposed to be
+ * initialized once during startup, we treat it as a static
+ * read-only list
+ */
+
+ drv = DRV_LIST_HEAD(&mgr->drivers);
+ while (drv) {
+ if (drv->drv_id == id)
+ break;
+ drv = drv->next;
+ }
+
+ return drv;
+}
diff --git a/cpukit/libdrvmgr/drvmgr_by_name.c b/cpukit/libdrvmgr/drvmgr_by_name.c
new file mode 100644
index 0000000000..619333f76b
--- /dev/null
+++ b/cpukit/libdrvmgr/drvmgr_by_name.c
@@ -0,0 +1,38 @@
+/* Find driver by driver-name
+ *
+ * COPYRIGHT (c) 2011
+ * Aeroflex Gaisler AB
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ */
+
+#include <string.h>
+#include <drvmgr/drvmgr.h>
+#include "drvmgr_internal.h"
+
+/* Get driver from driver name */
+struct drvmgr_drv *drvmgr_drv_by_name(const char *name)
+{
+ struct rtems_driver_manager *mgr = &drv_mgr;
+ struct drvmgr_drv *drv = NULL;
+
+ if (!name)
+ return NULL;
+
+ /* NOTE: No locking is needed here since Driver list is supposed to be
+ * initialized once during startup, we treat it as a static
+ * read-only list
+ */
+
+ drv = DRV_LIST_HEAD(&mgr->drivers);
+ while (drv) {
+ if (drv->name && (strcmp(drv->name, name) == 0))
+ break;
+ drv = drv->next;
+ }
+
+ return drv;
+}
diff --git a/cpukit/libdrvmgr/drvmgr_confdefs.h b/cpukit/libdrvmgr/drvmgr_confdefs.h
new file mode 100644
index 0000000000..3a08c73968
--- /dev/null
+++ b/cpukit/libdrvmgr/drvmgr_confdefs.h
@@ -0,0 +1,346 @@
+/* Driver Manager Configuration file.
+ *
+ * COPYRIGHT (c) 2009-2011
+ * Aeroflex Gaisler AB
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * The configuration consist of an array with function pointers that
+ * register one or more drivers that will be used by the Driver Manger.
+ *
+ * The Functions are called in the order they are declared.
+ *
+ */
+
+#ifndef _DRIVER_MANAGER_CONFDEFS_H_
+#define _DRIVER_MANAGER_CONFDEFS_H_
+
+/*#include <drvmgr/drvmgr.h>*/
+#include "drvmgr.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern struct drvmgr_drv_reg_func drvmgr_drivers[];
+
+#ifdef CONFIGURE_INIT
+
+/*** AMBA Plug & Play Drivers ***/
+#define DRIVER_AMBAPP_GAISLER_GPTIMER_REG {gptimer_register_drv}
+extern void gptimer_register_drv(void);
+
+#define DRIVER_AMBAPP_GAISLER_APBUART_REG {apbuart_cons_register_drv}
+extern void apbuart_cons_register_drv(void);
+
+#define DRIVER_AMBAPP_GAISLER_GRETH_REG {greth_register_drv}
+extern void greth_register_drv(void);
+
+#define DRIVER_AMBAPP_GAISLER_GRSPW_REG {grspw_register_drv}
+extern void grspw_register_drv(void);
+
+#define DRIVER_AMBAPP_GAISLER_GRSPW2_REG {grspw2_register_drv}
+extern void grspw2_register_drv(void);
+
+#define DRIVER_AMBAPP_GAISLER_GRCAN_REG {grcan_register_drv}
+extern void grcan_register_drv(void);
+
+#define DRIVER_AMBAPP_GAISLER_OCCAN_REG {occan_register_drv}
+extern void occan_register_drv(void);
+
+#define DRIVER_AMBAPP_GAISLER_GR1553B_REG {gr1553_register}
+extern void gr1553_register(void);
+
+#define DRIVER_AMBAPP_GAISLER_GR1553BC_REG {gr1553bc_register}
+extern void gr1553bc_register(void);
+
+#define DRIVER_AMBAPP_GAISLER_GR1553BM_REG {gr1553bm_register}
+extern void gr1553bm_register(void);
+
+#define DRIVER_AMBAPP_GAISLER_GR1553RT_REG {gr1553rt_register}
+extern void gr1553rt_register(void);
+
+#define DRIVER_AMBAPP_GAISLER_B1553BRM_REG {b1553brm_register_drv}
+extern void b1553brm_register_drv(void);
+
+#define DRIVER_AMBAPP_GAISLER_B1553RT_REG {b1553rt_register_drv}
+extern void b1553rt_register_drv(void);
+
+#define DRIVER_AMBAPP_GAISLER_GRTM_REG {grtm_register_drv}
+extern void grtm_register_drv(void);
+
+#define DRIVER_AMBAPP_GAISLER_GRTC_REG {grtc_register_drv}
+extern void grtc_register_drv(void);
+
+#define DRIVER_AMBAPP_MCTRL_REG {mctrl_register_drv}
+extern void mctrl_register_drv(void);
+
+#define DRIVER_AMBAPP_GAISLER_PCIF_REG {pcif_register_drv}
+extern void pcif_register_drv(void);
+
+#define DRIVER_AMBAPP_GAISLER_GRPCI_REG {grpci_register_drv}
+extern void grpci_register_drv(void);
+
+#define DRIVER_AMBAPP_GAISLER_GRPCI2_REG {grpci2_register_drv}
+extern void grpci2_register_drv(void);
+
+#define DRIVER_AMBAPP_GAISLER_SPICTRL_REG {spictrl_register_drv}
+extern void spictrl_register_drv(void);
+
+#define DRIVER_AMBAPP_GAISLER_I2CMST_REG {i2cmst_register_drv}
+extern void i2cmst_register_drv(void);
+
+#define DRIVER_AMBAPP_GAISLER_GRGPIO_REG {grgpio_register_drv}
+extern void grgpio_register_drv(void);
+
+#define DRIVER_AMBAPP_GAISLER_GRPWM_REG {grpwm_register_drv}
+extern void grpwm_register_drv(void);
+
+#define DRIVER_AMBAPP_GAISLER_GRADCDAC_REG {gradcdac_register_drv}
+extern void gradcdac_register_drv(void);
+
+#define DRIVER_AMBAPP_GAISLER_SPWCUC_REG {spwcuc_register}
+extern void spwcuc_register(void);
+
+#define DRIVER_AMBAPP_GAISLER_GRCTM_REG {grctm_register}
+extern void grctm_register(void);
+
+#define DRIVER_AMBAPP_GAISLER_SPW_ROUTER_REG {router_register_drv}
+extern void router_register_drv(void);
+
+#define DRIVER_AMBAPP_GAISLER_AHBSTAT_REG {ahbstat_register_drv}
+extern void ahbstat_register_drv(void);
+
+#define DRIVER_AMBAPP_GAISLER_GRAES_REG {graes_register_drv}
+extern void graes_register_drv(void);
+
+#define DRIVER_AMBAPP_GAISLER_GRPWRX_REG {grpwrx_register_drv}
+extern void grpwrx_register_drv(void);
+
+
+/*** LEON2 AMBA Hard coded bus Drivers ***/
+#define DRIVER_LEON2_AT697PCI_REG {at697pci_register_drv}
+extern void at697pci_register_drv(void);
+
+#define DRIVER_LEON2_AMBAPP_REG {ambapp_leon2_register}
+extern void ambapp_leon2_register(void);
+
+
+/*** PCI Bus Drivers (PCI Target drivers) ***/
+#define DRIVER_PCI_GR_RASTA_ADCDAC {gr_rasta_adcdac_register_drv}
+extern void gr_rasta_adcdac_register_drv(void);
+
+#define DRIVER_PCI_GR_RASTA_IO {gr_rasta_io_register_drv}
+extern void gr_rasta_io_register_drv(void);
+
+#define DRIVER_PCI_GR_RASTA_TMTC {gr_rasta_tmtc_register_drv}
+extern void gr_rasta_tmtc_register_drv(void);
+
+#define DRIVER_PCI_GR_701 {gr701_register_drv}
+extern void gr701_register_drv(void);
+
+#define DRIVER_PCI_GR_TMTC_1553 {gr_tmtc_1553_register_drv}
+extern void gr_tmtc_1553_register_drv(void);
+
+#define DRIVER_PCI_GR_RASTA_SPW_ROUTER {gr_rasta_spw_router_register_drv}
+extern void gr_rasta_spw_router_register_drv(void);
+
+/*** SpaceWire Node Drivers ***/
+#define DRIVER_SPW_RMAP_AMBAPP {ambapp_rmap_register}
+extern void ambapp_rmap_register(void);
+
+
+/*** AMBA Plug&Play over SpaceWire (RMAP) drivers ***/
+#define DRIVER_RMAP_AMBAPP_MCTRL {mctrl_rmap_register_drv}
+extern void mctrl_rmap_register_drv(void);
+
+#define DRIVER_RMAP_AMBAPP_GRTC {grtc_rmap_register_drv}
+extern void grtc_rmap_register_drv(void);
+
+#define DRIVER_RMAP_AMBAPP_GRTM {grtm_rmap_register_drv}
+extern void grtm_rmap_register_drv(void);
+
+/* CONFIGURE DRIVER MANAGER */
+struct drvmgr_drv_reg_func drvmgr_drivers[] = {
+ /*** AMBA Plug & Play Drivers ***/
+#ifdef CONFIGURE_DRIVER_AMBAPP_GAISLER_GPTIMER
+ DRIVER_AMBAPP_GAISLER_GPTIMER_REG,
+#endif
+#ifdef CONFIGURE_DRIVER_AMBAPP_GAISLER_APBUART
+ DRIVER_AMBAPP_GAISLER_APBUART_REG,
+#endif
+#ifdef CONFIGURE_DRIVER_AMBAPP_GAISLER_GRETH
+ DRIVER_AMBAPP_GAISLER_GRETH_REG,
+#endif
+#ifdef CONFIGURE_DRIVER_AMBAPP_GAISLER_GRSPW
+ DRIVER_AMBAPP_GAISLER_GRSPW_REG,
+#endif
+#ifdef CONFIGURE_DRIVER_AMBAPP_GAISLER_GRSPW2
+ DRIVER_AMBAPP_GAISLER_GRSPW2_REG,
+#endif
+#ifdef CONFIGURE_DRIVER_AMBAPP_GAISLER_GRCAN
+ DRIVER_AMBAPP_GAISLER_GRCAN_REG,
+#endif
+#ifdef CONFIGURE_DRIVER_AMBAPP_GAISLER_OCCAN
+ DRIVER_AMBAPP_GAISLER_OCCAN_REG,
+#endif
+#ifdef CONFIGURE_DRIVER_AMBAPP_GAISLER_GR1553B
+ DRIVER_AMBAPP_GAISLER_GR1553B_REG,
+#endif
+#ifdef CONFIGURE_DRIVER_AMBAPP_GAISLER_GR1553BC
+ DRIVER_AMBAPP_GAISLER_GR1553BC_REG,
+#endif
+#ifdef CONFIGURE_DRIVER_AMBAPP_GAISLER_GR1553BM
+ DRIVER_AMBAPP_GAISLER_GR1553BM_REG,
+#endif
+#ifdef CONFIGURE_DRIVER_AMBAPP_GAISLER_GR1553RT
+ DRIVER_AMBAPP_GAISLER_GR1553RT_REG,
+#endif
+#ifdef CONFIGURE_DRIVER_AMBAPP_GAISLER_B1553BRM
+ DRIVER_AMBAPP_GAISLER_B1553BRM_REG,
+#endif
+#ifdef CONFIGURE_DRIVER_AMBAPP_GAISLER_B1553RT
+ DRIVER_AMBAPP_GAISLER_B1553RT_REG,
+#endif
+#ifdef CONFIGURE_DRIVER_AMBAPP_GAISLER_GRTM
+ DRIVER_AMBAPP_GAISLER_GRTM_REG,
+#endif
+#ifdef CONFIGURE_DRIVER_AMBAPP_GAISLER_GRTC
+ DRIVER_AMBAPP_GAISLER_GRTC_REG,
+#endif
+#ifdef CONFIGURE_DRIVER_AMBAPP_GAISLER_PCIF
+ DRIVER_AMBAPP_GAISLER_PCIF_REG,
+#endif
+#ifdef CONFIGURE_DRIVER_AMBAPP_GAISLER_GRPCI
+ DRIVER_AMBAPP_GAISLER_GRPCI_REG,
+#endif
+#ifdef CONFIGURE_DRIVER_AMBAPP_GAISLER_GRPCI2
+ DRIVER_AMBAPP_GAISLER_GRPCI2_REG,
+#endif
+#ifdef CONFIGURE_DRIVER_AMBAPP_MCTRL
+ DRIVER_AMBAPP_MCTRL_REG,
+#endif
+#ifdef CONFIGURE_DRIVER_AMBAPP_GAISLER_SPICTRL
+ DRIVER_AMBAPP_GAISLER_SPICTRL_REG,
+#endif
+#ifdef CONFIGURE_DRIVER_AMBAPP_GAISLER_I2CMST
+ DRIVER_AMBAPP_GAISLER_I2CMST_REG,
+#endif
+#ifdef CONFIGURE_DRIVER_AMBAPP_GAISLER_GRGPIO
+ DRIVER_AMBAPP_GAISLER_GRGPIO_REG,
+#endif
+#ifdef CONFIGURE_DRIVER_AMBAPP_GAISLER_GRPWM
+ DRIVER_AMBAPP_GAISLER_GRPWM_REG,
+#endif
+#ifdef CONFIGURE_DRIVER_AMBAPP_GAISLER_GRADCDAC
+ DRIVER_AMBAPP_GAISLER_GRADCDAC_REG,
+#endif
+#ifdef CONFIGURE_DRIVER_AMBAPP_GAISLER_SPWCUC
+ DRIVER_AMBAPP_GAISLER_SPWCUC_REG,
+#endif
+#ifdef CONFIGURE_DRIVER_AMBAPP_GAISLER_GRCTM
+ DRIVER_AMBAPP_GAISLER_GRCTM_REG,
+#endif
+#ifdef CONFIGURE_DRIVER_AMBAPP_GAISLER_SPW_ROUTER
+ DRIVER_AMBAPP_GAISLER_SPW_ROUTER_REG,
+#endif
+#ifdef CONFIGURE_DRIVER_AMBAPP_GAISLER_AHBSTAT
+ DRIVER_AMBAPP_GAISLER_AHBSTAT_REG,
+#endif
+#ifdef CONFIGURE_DRIVER_AMBAPP_GAISLER_GRAES
+ DRIVER_AMBAPP_GAISLER_GRAES_REG,
+#endif
+#ifdef CONFIGURE_DRIVER_AMBAPP_GAISLER_GRPWRX
+ DRIVER_AMBAPP_GAISLER_GRPWRX_REG,
+#endif
+
+
+ /*** LEON2 AMBA Drivers ***/
+#ifdef CONFIGURE_DRIVER_LEON2_AT697PCI
+ DRIVER_LEON2_AT697PCI_REG,
+#endif
+#ifdef CONFIGURE_DRIVER_LEON2_AMBAPP
+ DRIVER_LEON2_AMBAPP_REG,
+#endif
+
+ /*** PCI Target Drivers ***/
+#ifdef CONFIGURE_DRIVER_PCI_GR_RASTA_ADCDAC
+ DRIVER_PCI_GR_RASTA_ADCDAC,
+#endif
+#ifdef CONFIGURE_DRIVER_PCI_GR_RASTA_IO
+ DRIVER_PCI_GR_RASTA_IO,
+#endif
+#ifdef CONFIGURE_DRIVER_PCI_GR_RASTA_TMTC
+ DRIVER_PCI_GR_RASTA_TMTC,
+#endif
+#ifdef CONFIGURE_DRIVER_PCI_GR_701
+ DRIVER_PCI_GR_701,
+#endif
+#ifdef CONFIGURE_DRIVER_PCI_GR_TMTC_1553
+ DRIVER_PCI_GR_TMTC_1553,
+#endif
+#ifdef CONFIGURE_DRIVER_PCI_GR_RASTA_SPW_ROUTER
+ DRIVER_PCI_GR_RASTA_SPW_ROUTER,
+#endif
+
+ /*** SpaceWire Node Drivers ***/
+#ifdef CONFIGURE_DRIVER_SPW_RMAP_AMBAPP
+ DRIVER_SPW_RMAP_AMBAPP,
+#endif
+
+ /*** AMBA Plug&Play over SpaceWire (RMAP) drivers ***/
+#ifdef CONFIGURE_DRIVER_RMAP_AMBAPP_MCTRL
+ DRIVER_RMAP_AMBAPP_MCTRL,
+#endif
+#ifdef CONFIGURE_DRIVER_RMAP_AMBAPP_GRTC
+ DRIVER_RMAP_AMBAPP_GRTC,
+#endif
+#ifdef CONFIGURE_DRIVER_RMAP_AMBAPP_GRTM
+ DRIVER_RMAP_AMBAPP_GRTM,
+#endif
+
+
+/* Macros for adding custom drivers without needing to recompile
+ * kernel.
+ */
+#ifdef CONFIGURE_DRIVER_CUSTOM1
+ DRIVER_CUSTOM1_REG,
+#endif
+#ifdef CONFIGURE_DRIVER_CUSTOM2
+ DRIVER_CUSTOM2_REG,
+#endif
+#ifdef CONFIGURE_DRIVER_CUSTOM3
+ DRIVER_CUSTOM3_REG,
+#endif
+#ifdef CONFIGURE_DRIVER_CUSTOM4
+ DRIVER_CUSTOM4_REG,
+#endif
+#ifdef CONFIGURE_DRIVER_CUSTOM5
+ DRIVER_CUSTOM5_REG,
+#endif
+#ifdef CONFIGURE_DRIVER_CUSTOM6
+ DRIVER_CUSTOM6_REG,
+#endif
+#ifdef CONFIGURE_DRIVER_CUSTOM7
+ DRIVER_CUSTOM7_REG,
+#endif
+#ifdef CONFIGURE_DRIVER_CUSTOM8
+ DRIVER_CUSTOM8_REG,
+#endif
+#ifdef CONFIGURE_DRIVER_CUSTOM9
+ DRIVER_CUSTOM9_REG,
+#endif
+
+ /* End array with NULL */
+ {NULL}
+};
+
+#endif /* CONFIGURE_INIT */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DRIVER_MANAGER_CONFDEFS_H_ */
diff --git a/cpukit/libdrvmgr/drvmgr_drvinf.c b/cpukit/libdrvmgr/drvmgr_drvinf.c
new file mode 100644
index 0000000000..621ec1641b
--- /dev/null
+++ b/cpukit/libdrvmgr/drvmgr_drvinf.c
@@ -0,0 +1,145 @@
+/* Driver Manager Driver Interface Implementation.
+ *
+ * COPYRIGHT (c) 2009.
+ * Aeroflex Gaisler AB
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * This is the part the device driver API, the functions rely on that the
+ * parent bus driver has implemented the neccessary operations correctly.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <drvmgr/drvmgr.h>
+#include "drvmgr_internal.h"
+
+/* Get device pointer from knowing the Driver and the Driver minor
+ * that was assigned to it
+ */
+int drvmgr_get_dev(
+ struct drvmgr_drv *drv,
+ int minor,
+ struct drvmgr_dev **pdev)
+{
+ struct drvmgr_dev *dev;
+ if (!drv)
+ return -1;
+
+ DRVMGR_LOCK_READ();
+ dev = drv->dev;
+ while (dev) {
+ if (dev->minor_drv == minor)
+ break;
+ dev = dev->next_in_drv;
+ }
+ DRVMGR_UNLOCK();
+ if (!dev)
+ return -1;
+ if (pdev)
+ *pdev = dev;
+ return 0;
+}
+
+/* Get Bus frequency in HZ from bus driver */
+int drvmgr_freq_get(
+ struct drvmgr_dev *dev,
+ int options,
+ unsigned int *freq_hz)
+{
+ if (!dev || !dev->parent || !dev->parent->ops->freq_get)
+ return -1;
+
+ return dev->parent->ops->freq_get(dev, options, freq_hz);
+}
+
+/* Get driver prefix */
+int drvmgr_get_dev_prefix(struct drvmgr_dev *dev, char *dev_prefix)
+{
+ struct drvmgr_bus_params params;
+ if (!dev || !dev->parent || !dev->parent->ops->get_params)
+ return -1;
+
+ dev->parent->ops->get_params(dev, &params);
+ if (!params.dev_prefix)
+ return -1;
+ if (dev_prefix)
+ strcpy(dev_prefix, params.dev_prefix);
+ return 0;
+}
+
+/* Register an interrupt */
+int drvmgr_interrupt_register(
+ struct drvmgr_dev *dev,
+ int index,
+ const char *info,
+ drvmgr_isr isr,
+ void *arg)
+{
+ if (!dev || !dev->parent || !dev->parent->ops->int_register)
+ return -1;
+
+ if (!isr)
+ return -1;
+
+ return dev->parent->ops->int_register(dev, index, info, isr, arg);
+}
+
+/* Unregister an interrupt */
+int drvmgr_interrupt_unregister(
+ struct drvmgr_dev *dev,
+ int index,
+ drvmgr_isr isr,
+ void *arg)
+{
+ if (!dev || !dev->parent || !dev->parent->ops->int_unregister)
+ return -1;
+
+ if (!isr)
+ return -1;
+
+ return dev->parent->ops->int_unregister(dev, index, isr, arg);
+}
+
+int drvmgr_interrupt_clear(
+ struct drvmgr_dev *dev,
+ int index)
+{
+ if (!dev || !dev->parent || !dev->parent->ops->int_clear)
+ return -1;
+
+ return dev->parent->ops->int_clear(dev, index);
+}
+
+int drvmgr_interrupt_unmask(
+ struct drvmgr_dev *dev,
+ int index)
+{
+ if (!dev || !dev->parent || !dev->parent->ops->int_unmask)
+ return -1;
+
+ return dev->parent->ops->int_unmask(dev, index);
+}
+
+int drvmgr_interrupt_mask(
+ struct drvmgr_dev *dev,
+ int index)
+{
+ if (!dev || !dev->parent || !dev->parent->ops->int_mask)
+ return -1;
+
+ return dev->parent->ops->int_mask(dev, index);
+}
+
+int drvmgr_on_rootbus(struct drvmgr_dev *dev)
+{
+ if (dev->parent && dev->parent->dev && dev->parent->dev->parent)
+ return 0;
+ else
+ return 1;
+}
diff --git a/cpukit/libdrvmgr/drvmgr_for_each_dev.c b/cpukit/libdrvmgr/drvmgr_for_each_dev.c
new file mode 100644
index 0000000000..8fdbe83a58
--- /dev/null
+++ b/cpukit/libdrvmgr/drvmgr_for_each_dev.c
@@ -0,0 +1,105 @@
+/* Iterate over device tree topology, breadth or depth-first
+ *
+ * COPYRIGHT (c) 2009-2011
+ * Aeroflex Gaisler AB
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ */
+
+#include <string.h>
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/drvmgr_list.h>
+#include "drvmgr_internal.h"
+
+/* Traverse device tree breadth-first. Supports up to 31 buses */
+static int drvmgr_for_each_dev_breadth(
+ int (*func)(struct drvmgr_dev *dev, void *arg),
+ void *arg
+ )
+{
+ int ret = 0, i, pos;
+ struct drvmgr_bus *bus, *buses[32];
+ struct drvmgr_dev *dev;
+
+ pos = 0;
+ memset(&buses[0], 0, sizeof(buses));
+ buses[pos++] = drv_mgr.root_dev.bus; /* Get root bus */
+
+ for (i = 0, bus = buses[0]; buses[i]; i++, bus = buses[i]) {
+ dev = bus->children;
+ while (dev) {
+ ret = func(dev, arg);
+ if (ret != 0)
+ break;
+ if (dev->bus && pos < 31)
+ buses[pos++] = dev->bus;
+
+ dev = dev->next_in_bus;
+ }
+ }
+
+ return ret;
+}
+
+/* Traverse device tree depth-first. */
+static int drvmgr_for_each_dev_depth(
+ int (*func)(struct drvmgr_dev *dev, void *arg),
+ void *arg
+ )
+{
+ int ret = 0;
+ struct drvmgr_dev *dev;
+
+ /* Get first device */
+ dev = drv_mgr.root_dev.bus->children;
+
+ while (dev) {
+ ret = func(dev, arg);
+ if (ret != 0)
+ break;
+ if (dev->bus && dev->bus->children) {
+ dev = dev->bus->children;
+ } else {
+next_dev:
+ if (dev->next_in_bus == NULL) {
+ /* Step up one level... back to parent bus */
+ dev = dev->parent->dev;
+ if (dev == &drv_mgr.root_dev)
+ break;
+ goto next_dev;
+ } else {
+ dev = dev->next_in_bus;
+ }
+ }
+ }
+
+ return ret;
+}
+
+/* Traverse device tree depth-first or breadth-first */
+int drvmgr_for_each_dev(
+ int (*func)(struct drvmgr_dev *dev, void *arg),
+ void *arg,
+ int options
+ )
+{
+ int ret;
+
+ DRVMGR_LOCK_READ();
+
+ /* Get Root Device */
+ if (drv_mgr.root_dev.bus->children != NULL) {
+ if (options & DRVMGR_FED_BF)
+ ret = drvmgr_for_each_dev_breadth(func, arg);
+ else
+ ret = drvmgr_for_each_dev_depth(func, arg);
+ } else
+ ret = 0;
+
+ DRVMGR_UNLOCK();
+
+ return ret;
+}
diff --git a/cpukit/libdrvmgr/drvmgr_for_each_list_dev.c b/cpukit/libdrvmgr/drvmgr_for_each_list_dev.c
new file mode 100644
index 0000000000..f15004472e
--- /dev/null
+++ b/cpukit/libdrvmgr/drvmgr_for_each_list_dev.c
@@ -0,0 +1,45 @@
+/* Iterate over one list of devices used internally by driver manager
+ *
+ * COPYRIGHT (c) 2009-2011
+ * Aeroflex Gaisler AB
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ */
+
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/drvmgr_list.h>
+#include "drvmgr_internal.h"
+
+int drvmgr_for_each_listdev(
+ struct drvmgr_list *devlist,
+ unsigned int state_set_mask,
+ unsigned int state_clr_mask,
+ int (*func)(struct drvmgr_dev *dev, void *arg),
+ void *arg
+ )
+{
+ struct drvmgr_dev *dev;
+ int ret = 0;
+
+ DRVMGR_LOCK_READ();
+
+ /* Get First Device */
+ dev = DEV_LIST_HEAD(devlist);
+ while (dev) {
+ if (((state_set_mask != 0) && ((dev->state & state_set_mask) == state_set_mask)) ||
+ ((state_clr_mask != 0) && ((dev->state & state_clr_mask) == 0)) ||
+ ((state_set_mask == 0) && (state_clr_mask == 0))) {
+ ret = func(dev, arg);
+ if (ret != 0)
+ break;
+ }
+ dev = dev->next;
+ }
+
+ DRVMGR_UNLOCK();
+
+ return ret;
+}
diff --git a/cpukit/libdrvmgr/drvmgr_func.c b/cpukit/libdrvmgr/drvmgr_func.c
new file mode 100644
index 0000000000..def53aaa9d
--- /dev/null
+++ b/cpukit/libdrvmgr/drvmgr_func.c
@@ -0,0 +1,43 @@
+/* Driver Manager optional dynamic function interface
+ *
+ * COPYRIGHT (c) 2011
+ * Aeroflex Gaisler AB
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ */
+
+#include <drvmgr/drvmgr.h>
+
+/* Get Function from Function ID */
+int drvmgr_func_get(void *obj, int funcid, void **func)
+{
+ int objtype;
+ struct drvmgr_func *f;
+
+ if (!obj)
+ return DRVMGR_FAIL;
+ objtype = *(int *)obj;
+
+ if (objtype == DRVMGR_OBJ_BUS)
+ f = ((struct drvmgr_bus *)obj)->funcs;
+ else if (objtype == DRVMGR_OBJ_DRV)
+ f = ((struct drvmgr_drv *)obj)->funcs;
+ else
+ return DRVMGR_FAIL;
+
+ if (f == NULL)
+ return DRVMGR_FAIL;
+
+ while (f->funcid != DRVMGR_FUNCID_NONE) {
+ if (f->funcid == funcid) {
+ *func = f->func;
+ return DRVMGR_OK;
+ }
+ f++;
+ }
+
+ return DRVMGR_FAIL;
+}
diff --git a/cpukit/libdrvmgr/drvmgr_func_call.c b/cpukit/libdrvmgr/drvmgr_func_call.c
new file mode 100644
index 0000000000..9b74ef2a71
--- /dev/null
+++ b/cpukit/libdrvmgr/drvmgr_func_call.c
@@ -0,0 +1,22 @@
+/* Driver Manager optional dynamic function interface
+ *
+ * COPYRIGHT (c) 2011
+ * Aeroflex Gaisler AB
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ */
+
+#include <drvmgr/drvmgr.h>
+
+/* Lookup function from function ID and call it using given arguments */
+int drvmgr_func_call(void *obj, int funcid, void *a, void *b, void *c, void *d)
+{
+ int (*func)(void *arg1, void *arg2, void *arg3, void *arg4) = NULL;
+
+ if (drvmgr_func_get(obj, funcid, (void *)&func) != DRVMGR_OK)
+ return DRVMGR_FAIL;
+ return func(a, b, c, d);
+}
diff --git a/cpukit/libdrvmgr/drvmgr_init.c b/cpukit/libdrvmgr/drvmgr_init.c
new file mode 100644
index 0000000000..a13fb5bc03
--- /dev/null
+++ b/cpukit/libdrvmgr/drvmgr_init.c
@@ -0,0 +1,27 @@
+/* Driver Manager Initialization
+ *
+ * COPYRIGHT (c) 2009-2011
+ * Aeroflex Gaisler AB
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ */
+
+#include <drvmgr/drvmgr.h>
+
+/* Init driver manager - all in one go. Typically called from Init task when
+ * user wants to initilize driver manager after startup, otherwise not used.
+ */
+int drvmgr_init(void)
+{
+ int level;
+
+ _DRV_Manager_initialization();
+
+ for (level = 1; level <= DRVMGR_LEVEL_MAX; level++)
+ _DRV_Manager_init_level(level);
+
+ return 0;
+}
diff --git a/cpukit/libdrvmgr/drvmgr_internal.h b/cpukit/libdrvmgr/drvmgr_internal.h
new file mode 100644
index 0000000000..631480564d
--- /dev/null
+++ b/cpukit/libdrvmgr/drvmgr_internal.h
@@ -0,0 +1,62 @@
+/* Private driver manager declarations
+ *
+ * COPYRIGHT (c) 2009-2011
+ * Aeroflex Gaisler AB
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * Structure hold all information the driver manager needs to know of. Used
+ * internally by Driver Manager routines.
+ */
+
+struct rtems_driver_manager {
+ int level;
+ int initializing_objs;
+
+ /* Device tree Lock */
+ rtems_id lock;
+
+ /* The first device - The root device and it's driver */
+ struct drvmgr_drv *root_drv;
+ struct drvmgr_dev root_dev;
+
+ /*!< Linked list of all registered drivers */
+ struct drvmgr_list drivers;
+
+ /* Buses that reached a certain initialization level.
+ * Lists by Level:
+ * N=0 - Not intialized, just registered
+ * N=1..MAX-1 - Reached init level N
+ * N=MAX - Successfully initialized bus
+ */
+ struct drvmgr_list buses[DRVMGR_LEVEL_MAX+1];
+ /* Buses failed to initialize or has been removed by not freed */
+ struct drvmgr_list buses_inactive;
+
+ /* Devices that reached a certain initialization level.
+ * Lists by Level:
+ * N=0 - Not intialized, just registered
+ * N=1..MAX-1 - Reached init level N
+ * N=MAX - Successfully initialized device
+ */
+ struct drvmgr_list devices[DRVMGR_LEVEL_MAX+1];
+ /*!< Devices failed to initialize, removed, ignored, no driver */
+ struct drvmgr_list devices_inactive;
+};
+
+extern struct rtems_driver_manager drv_mgr;
+
+extern void _DRV_Manager_Lock(void);
+extern void _DRV_Manager_Unlock(void);
+extern int _DRV_Manager_Init_Lock(void);
+
+/* The best solution is to implement the locking with a RW lock, however there
+ * is no such API available. Care must be taken so that dead-lock isn't created
+ * for example in recursive functions.
+ */
+#define DRVMGR_LOCK_INIT() _DRV_Manager_Init_Lock()
+#define DRVMGR_LOCK_WRITE() _DRV_Manager_Lock()
+#define DRVMGR_LOCK_READ() _DRV_Manager_Lock()
+#define DRVMGR_UNLOCK() _DRV_Manager_Unlock()
diff --git a/cpukit/libdrvmgr/drvmgr_list.c b/cpukit/libdrvmgr/drvmgr_list.c
new file mode 100644
index 0000000000..e25f496827
--- /dev/null
+++ b/cpukit/libdrvmgr/drvmgr_list.c
@@ -0,0 +1,68 @@
+/* Driver Manager List Interface Implementation.
+ *
+ * COPYRIGHT (c) 2009.
+ * Aeroflex Gaisler AB
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ */
+
+#include <stdlib.h>
+#include <drvmgr/drvmgr_list.h>
+
+/* LIST interface */
+
+void drvmgr_list_init(struct drvmgr_list *list, int offset)
+{
+ list->head = list->tail = NULL;
+ list->ofs = offset;
+}
+
+void drvmgr_list_empty(struct drvmgr_list *list)
+{
+ list->head = list->tail = NULL;
+}
+
+void drvmgr_list_add_head(struct drvmgr_list *list, void *entry)
+{
+ LIST_FIELD(list, entry) = list->head;
+ if (list->head == NULL)
+ list->tail = entry;
+ list->head = entry;
+}
+
+void drvmgr_list_add_tail(struct drvmgr_list *list, void *entry)
+{
+ if (list->tail == NULL)
+ list->head = entry;
+ else
+ LIST_FIELD(list, list->tail) = entry;
+ LIST_FIELD(list, entry) = NULL;
+ list->tail = entry;
+}
+
+void drvmgr_list_remove_head(struct drvmgr_list *list)
+{
+ list->head = LIST_FIELD(list, list->head);
+ if (list->head == NULL)
+ list->tail = NULL;
+}
+
+void drvmgr_list_remove(struct drvmgr_list *list, void *entry)
+{
+ void **prevptr = &list->head;
+ void *curr, *prev;
+
+ prev = NULL;
+ curr = list->head;
+ while (curr != entry) {
+ prev = curr;
+ prevptr = &LIST_FIELD(list, curr);
+ curr = LIST_FIELD(list, curr);
+ }
+ *prevptr = LIST_FIELD(list, entry);
+ if (list->tail == entry)
+ list->tail = prev;
+}
diff --git a/cpukit/libdrvmgr/drvmgr_list.h b/cpukit/libdrvmgr/drvmgr_list.h
new file mode 100644
index 0000000000..9497d6d55c
--- /dev/null
+++ b/cpukit/libdrvmgr/drvmgr_list.h
@@ -0,0 +1,77 @@
+/* Linked list help functions used by driver manager.
+ *
+ * COPYRIGHT (c) 2009.
+ * Aeroflex Gaisler AB
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * Help functions for the Driver Manager. Implements a singly linked list
+ * with head and tail pointers for fast insertions/deleations to head and
+ * tail in list.
+ */
+
+#ifndef _DRVIVER_MANAGER_LIST_H_
+#define _DRVIVER_MANAGER_LIST_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*! List description, Singly link list with head and tail pointers. */
+struct drvmgr_list {
+ void *head; /*!< First entry in queue */
+ void *tail; /*!< Last entry in queue */
+ int ofs; /*!< Offset into head and tail to find next field */
+};
+
+/* Static initialization of list */
+#define LIST_INITIALIZER(type, field) {NULL, NULL, offsetof(type, field)}
+
+/* Return the first element in list */
+#define LIST_HEAD(list, type) ((type *)(list)->head)
+
+/* Return the last element in list */
+#define LIST_TAIL(list, type) ((type *)(list)->tail)
+
+/* Get the next pointer of an entry */
+#define LIST_FIELD(list, entry) (*(void **)((char *)(entry) + (list)->ofs))
+
+/* Return the next emlement in list */
+#define LIST_NEXT(list, entry, type) ((type *)(LIST_FIELD(list, entry)))
+
+/* Iterate through all entries in list */
+#define LIST_FOR_EACH(list, entry, type) \
+ for (entry = LIST_HEAD(list, type); \
+ entry; \
+ entry = LIST_NEXT(list, entry, type))
+
+/*! Initialize a list during runtime
+ *
+ * \param list The list to initialize
+ * \param offset The number of bytes into the entry structure the next pointer
+ * is found
+ */
+extern void drvmgr_list_init(struct drvmgr_list *list, int offset);
+
+/*! Clear list */
+extern void drvmgr_list_empty(struct drvmgr_list *list);
+
+/*! Add entry to front of list */
+extern void drvmgr_list_add_head(struct drvmgr_list *list, void *entry);
+
+/*! Add entry to end of list */
+extern void drvmgr_list_add_tail(struct drvmgr_list *list, void *entry);
+
+/*! Remove entry from front of list */
+extern void drvmgr_list_remove_head(struct drvmgr_list *list);
+
+/*! Remove entry from anywhere in list */
+extern void drvmgr_list_remove(struct drvmgr_list *list, void *entry);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/cpukit/libdrvmgr/drvmgr_lock.c b/cpukit/libdrvmgr/drvmgr_lock.c
new file mode 100644
index 0000000000..91b597d653
--- /dev/null
+++ b/cpukit/libdrvmgr/drvmgr_lock.c
@@ -0,0 +1,39 @@
+/* Driver Manager Internal locking implementation
+ *
+ * COPYRIGHT (c) 2009.
+ * Aeroflex Gaisler AB
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ */
+
+#include <rtems.h>
+#include <drvmgr/drvmgr.h>
+#include "drvmgr_internal.h"
+
+void _DRV_Manager_Lock(void)
+{
+ rtems_semaphore_obtain(drv_mgr.lock, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+}
+
+void _DRV_Manager_Unlock(void)
+{
+ rtems_semaphore_release(drv_mgr.lock);
+}
+
+int _DRV_Manager_Init_Lock(void)
+{
+ int rc;
+
+ rc = rtems_semaphore_create(
+ rtems_build_name('D', 'R', 'V', 'M'),
+ 1,
+ RTEMS_DEFAULT_ATTRIBUTES,
+ 0,
+ &drv_mgr.lock);
+ if (rc != RTEMS_SUCCESSFUL)
+ return -1;
+ return 0;
+}
diff --git a/cpukit/libdrvmgr/drvmgr_print.c b/cpukit/libdrvmgr/drvmgr_print.c
new file mode 100644
index 0000000000..d8e4a465dd
--- /dev/null
+++ b/cpukit/libdrvmgr/drvmgr_print.c
@@ -0,0 +1,455 @@
+/* Driver Manager Information printing Interface Implementation
+ *
+ * COPYRIGHT (c) 2009.
+ * Aeroflex Gaisler AB
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * These functions print stuff about the driver manager, what devices were
+ * found and were united with a driver, the Bus topology, memory taken, etc.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <drvmgr/drvmgr.h>
+#include "drvmgr_internal.h"
+
+typedef void (*fun_ptr)(void);
+
+static int print_dev_found(struct drvmgr_dev *dev, void *arg)
+{
+ char **pparg = arg;
+
+ if (pparg && *pparg) {
+ printf(*pparg);
+ *pparg = NULL;
+ }
+
+ printf(" DEV %p %s on bus %p\n", dev,
+ dev->name ? dev->name : "NO_NAME", dev->parent);
+
+ return 0; /* Continue to next device */
+}
+
+void drvmgr_print_devs(unsigned int options)
+{
+ struct rtems_driver_manager *mgr = &drv_mgr;
+ char *parg;
+
+ /* Print Drivers */
+ if (options & PRINT_DEVS_ASSIGNED) {
+ parg = " --- DEVICES ASSIGNED TO DRIVER ---\n";
+ drvmgr_for_each_listdev(&mgr->devices[DRVMGR_LEVEL_MAX],
+ DEV_STATE_UNITED, 0, print_dev_found, &parg);
+ if (parg != NULL)
+ printf("\n NO DEVICES WERE ASSIGNED A DRIVER\n");
+ }
+
+ if (options & PRINT_DEVS_UNASSIGNED) {
+ parg = "\n --- DEVICES WITHOUT DRIVER ---\n";
+ drvmgr_for_each_listdev(&mgr->devices_inactive, 0,
+ DEV_STATE_UNITED, print_dev_found, &parg);
+ if (parg != NULL)
+ printf("\n NO DEVICES WERE WITHOUT DRIVER\n");
+ }
+
+ if (options & PRINT_DEVS_FAILED) {
+ parg = "\n --- DEVICES FAILED TO INITIALIZE ---\n";
+ drvmgr_for_each_listdev(&mgr->devices_inactive,
+ DEV_STATE_INIT_FAILED, 0, print_dev_found, &parg);
+ if (parg != NULL)
+ printf("\n NO DEVICES FAILED TO INITIALIZE\n");
+ }
+
+ if (options & PRINT_DEVS_IGNORED) {
+ parg = "\n --- DEVICES IGNORED ---\n";
+ drvmgr_for_each_listdev(&mgr->devices_inactive,
+ DEV_STATE_IGNORED, 0, print_dev_found, &parg);
+ if (parg != NULL)
+ printf("\n NO DEVICES WERE IGNORED\n");
+ }
+
+ printf("\n\n");
+}
+
+int drvmgr_topo_func(struct drvmgr_dev *dev, void *arg)
+{
+ char prefix[32];
+ int depth = dev->parent->depth;
+
+ if (depth > 30)
+ return 0; /* depth more than 30 not supported */
+ memset(prefix, ' ', depth + 1);
+ prefix[depth + 1] = '\0';
+
+ printf(" %s|-> DEV %p %s\n", prefix, dev,
+ dev->name ? dev->name : "NO_NAME");
+ return 0;
+}
+
+void drvmgr_print_topo(void)
+{
+ /* Print Bus topology */
+ printf(" --- BUS TOPOLOGY ---\n");
+ drvmgr_for_each_dev(drvmgr_topo_func, NULL, DRVMGR_FED_DF);
+ printf("\n\n");
+}
+
+/* Print the memory usage */
+void drvmgr_print_mem(void)
+{
+ struct rtems_driver_manager *mgr = &drv_mgr;
+ struct drvmgr_bus *bus;
+ struct drvmgr_dev *dev;
+ struct drvmgr_drv *drv;
+
+ struct drvmgr_bus_res *node;
+ struct drvmgr_drv_res *res;
+ struct drvmgr_key *key;
+
+ unsigned int busmem = 0;
+ unsigned int devmem = 0;
+ unsigned int drvmem = 0;
+ unsigned int resmem = 0;
+ unsigned int devprivmem = 0;
+
+ DRVMGR_LOCK_READ();
+
+ bus = BUS_LIST_HEAD(&mgr->buses[DRVMGR_LEVEL_MAX]);
+ while (bus) {
+ busmem += sizeof(struct drvmgr_bus);
+
+ /* Get size of resources on this bus */
+ node = bus->reslist;
+ while (node) {
+ resmem += sizeof(struct drvmgr_bus_res);
+
+ res = node->resource;
+ while (res->keys) {
+ resmem += sizeof(struct drvmgr_drv_res);
+
+ key = res->keys;
+ while (key->key_type != KEY_TYPE_NONE) {
+ resmem += sizeof
+ (struct drvmgr_key);
+ key++;
+ }
+ resmem += sizeof(struct drvmgr_key);
+ res++;
+ }
+
+ node = node->next;
+ }
+
+ bus = bus->next;
+ }
+
+ drv = DRV_LIST_HEAD(&mgr->drivers);
+ while (drv) {
+ drvmem += sizeof(struct drvmgr_drv);
+ drv = drv->next;
+ }
+
+ dev = DEV_LIST_HEAD(&mgr->devices[DRVMGR_LEVEL_MAX]);
+ while (dev) {
+ devmem += sizeof(struct drvmgr_dev);
+ if (dev->drv && dev->drv->dev_priv_size > 0)
+ devprivmem += dev->drv->dev_priv_size;
+ dev = dev->next;
+ }
+
+ DRVMGR_UNLOCK();
+
+ printf(" --- MEMORY USAGE ---\n");
+ printf(" BUS: %d bytes\n", busmem);
+ printf(" DRV: %d bytes\n", drvmem);
+ printf(" DEV: %d bytes\n", devmem);
+ printf(" DEV private: %d bytes\n", devprivmem);
+ printf(" RES: %d bytes\n", resmem);
+ printf(" TOTAL: %d bytes\n",
+ busmem + drvmem + devmem + devprivmem + resmem);
+ printf("\n\n");
+}
+
+/* Print the memory usage */
+void drvmgr_summary(void)
+{
+ struct rtems_driver_manager *mgr = &drv_mgr;
+ struct drvmgr_bus *bus;
+ struct drvmgr_dev *dev;
+ struct drvmgr_drv *drv;
+ int i, buscnt = 0, devcnt = 0, drvcnt = 0;
+
+ printf(" --- SUMMARY ---\n");
+
+ drv = DRV_LIST_HEAD(&mgr->drivers);
+ while (drv) {
+ drvcnt++;
+ drv = drv->next;
+ }
+ printf(" NUMBER OF DRIVERS: %d\n", drvcnt);
+
+ DRVMGR_LOCK_READ();
+
+ for (i = 0; i <= DRVMGR_LEVEL_MAX; i++) {
+ buscnt = 0;
+ bus = BUS_LIST_HEAD(&mgr->buses[i]);
+ while (bus) {
+ buscnt++;
+ bus = bus->next;
+ }
+ if (buscnt > 0) {
+ printf(" NUMBER OF BUSES IN LEVEL[%d]: %d\n",
+ i, buscnt);
+ }
+ }
+
+ for (i = 0; i <= DRVMGR_LEVEL_MAX; i++) {
+ devcnt = 0;
+ dev = DEV_LIST_HEAD(&mgr->devices[i]);
+ while (dev) {
+ devcnt++;
+ dev = dev->next;
+ }
+ if (devcnt > 0) {
+ printf(" NUMBER OF DEVS IN LEVEL[%d]: %d\n",
+ i, devcnt);
+ }
+ }
+
+ DRVMGR_UNLOCK();
+
+ printf("\n\n");
+}
+
+static void print_info(void *p, char *str)
+{
+ printf(" ");
+ puts(str);
+}
+
+void drvmgr_info_dev(struct drvmgr_dev *dev, unsigned int options)
+{
+ if (!dev)
+ return;
+
+ printf(" -- DEVICE %p --\n", dev);
+ if (options & OPTION_DEV_GENINFO) {
+ printf(" PARENT BUS: %p\n", dev->parent);
+ printf(" NAME: %s\n", dev->name ? dev->name : "NO_NAME");
+ printf(" STATE: 0x%08x\n", dev->state);
+ if (dev->bus)
+ printf(" BRIDGE TO: %p\n", dev->bus);
+ printf(" INIT LEVEL: %d\n", dev->level);
+ printf(" ERROR: %d\n", dev->error);
+ printf(" MINOR BUS: %d\n", dev->minor_bus);
+ if (dev->drv) {
+ printf(" MINOR DRV: %d\n", dev->minor_drv);
+ printf(" DRIVER: %p (%s)\n", dev->drv,
+ dev->drv->name ? dev->drv->name : "NO_NAME");
+ printf(" PRIVATE: %p\n", dev->priv);
+ }
+ }
+
+ if (options & OPTION_DEV_BUSINFO) {
+ printf(" --- DEVICE INFO FROM BUS DRIVER ---\n");
+ if (!dev->parent)
+ printf(" !! device has no parent bus !!\n");
+ else if (dev->parent->ops->info_dev)
+ dev->parent->ops->info_dev(dev, print_info, NULL);
+ else
+ printf(" Bus doesn't implement info_dev func\n");
+ }
+
+ if (options & OPTION_DEV_DRVINFO) {
+ if (dev->drv) {
+ printf(" --- DEVICE INFO FROM DEVICE DRIVER ---\n");
+ if (dev->drv->ops->info)
+ dev->drv->ops->info(dev, print_info, NULL, 0, 0);
+ else
+ printf(" Driver doesn't implement info func\n");
+ }
+ }
+}
+
+void drvmgr_info_bus_map(struct drvmgr_map_entry *map)
+{
+ if (map == NULL)
+ printf(" Addresses mapped 1:1\n");
+ else if (map == DRVMGR_TRANSLATE_NO_BRIDGE)
+ printf(" No bridge in this direction\n");
+ else {
+ while (map->size != 0) {
+ printf(" 0x%08lx-0x%08lx => 0x%08lx-0x%08lx %s\n",
+ (unsigned long)map->from_adr,
+ (unsigned long)(map->from_adr + map->size - 1),
+ (unsigned long)map->to_adr,
+ (unsigned long)(map->to_adr + map->size - 1),
+ map->name ? map->name : "no label");
+ map++;
+ }
+ }
+}
+
+void drvmgr_info_bus(struct drvmgr_bus *bus, unsigned int options)
+{
+ struct drvmgr_dev *dev;
+
+ /* Print Driver */
+ printf("-- BUS %p --\n", bus);
+ printf(" BUS TYPE: %d\n", bus->bus_type);
+ printf(" DEVICE: %p (%s)\n", bus->dev,
+ bus->dev->name ? bus->dev->name : "NO_NAME");
+ printf(" OPS: %p\n", bus->ops);
+ printf(" CHILDREN: %d devices\n", bus->dev_cnt);
+ printf(" LEVEL: %d\n", bus->level);
+ printf(" STATE: 0x%08x\n", bus->state);
+ printf(" ERROR: %d\n", bus->error);
+
+ /* Print address mappings up- (to parent) and down- (from parent to
+ * this bus) stream the bridge of this bus
+ */
+ printf(" DOWN STREAMS BRIDGE MAPPINGS (from parent to this bus)\n");
+ drvmgr_info_bus_map(bus->maps_down);
+ printf(" UP STREAMS BRIDGE MAPPINGS (from this bus to parent)\n");
+ drvmgr_info_bus_map(bus->maps_up);
+
+ /* Print Devices on this bus? */
+ if (options & OPTION_BUS_DEVS) {
+ printf(" CHILDREN:\n");
+ DRVMGR_LOCK_READ();
+ dev = bus->children;
+ while (dev) {
+ printf(" |- DEV[%02d]: %p %s\n", dev->minor_bus,
+ dev, dev->name ? dev->name : "NO_NAME");
+ dev = dev->next_in_bus;
+ }
+ DRVMGR_UNLOCK();
+ }
+}
+
+char *drv_ops_names[DRV_OPS_NUM] = {
+ "init[1]:",
+ "init[2]:",
+ "init[3]:",
+ "init[4]:",
+ "remove: ",
+ "info: "
+};
+
+void drvmgr_info_drv(struct drvmgr_drv *drv, unsigned int options)
+{
+ struct drvmgr_dev *dev;
+ fun_ptr *ppfunc;
+ int i;
+
+ /* Print Driver */
+ printf(" -- DRIVER %p --\n", drv);
+ printf(" DRIVER ID: 0x%llx\n", drv->drv_id);
+ printf(" NAME: %s\n", drv->name ? drv->name : "NO_NAME");
+ printf(" BUS TYPE: %d\n", drv->bus_type);
+ printf(" OPERATIONS:\n");
+ for (i = 0, ppfunc = (fun_ptr *)&drv->ops->init[0]; i<DRV_OPS_NUM; i++)
+ printf(" %s %p\n", drv_ops_names[i], ppfunc[i]);
+ printf(" NO. DEVICES: %d\n", drv->dev_cnt);
+
+ /* Print devices united with this driver? */
+ if (options & OPTION_DRV_DEVS) {
+ DRVMGR_LOCK_READ();
+ dev = drv->dev;
+ while (dev) {
+ printf(" DEV[%02d]: %p %s\n", dev->minor_drv,
+ dev, dev->name ? dev->name : "NO_NAME");
+ dev = dev->next_in_drv;
+ }
+ DRVMGR_UNLOCK();
+ }
+}
+
+void (*info_obj[3])(void *obj, unsigned int) = {
+ /* DRVMGR_OBJ_DRV */ (void (*)(void *, unsigned int))drvmgr_info_drv,
+ /* DRVMGR_OBJ_BUS */ (void (*)(void *, unsigned int))drvmgr_info_bus,
+ /* DRVMGR_OBJ_DEV */ (void (*)(void *, unsigned int))drvmgr_info_dev,
+};
+
+/* Get information about a device/bus/driver */
+void drvmgr_info(void *id, unsigned int options)
+{
+ int obj_type;
+ void (*func)(void *, unsigned int);
+
+ if (!id)
+ return;
+ obj_type = *(int *)id;
+ if ((obj_type < DRVMGR_OBJ_DRV) || (obj_type > DRVMGR_OBJ_DEV))
+ return;
+ func = info_obj[obj_type - 1];
+ func(id, options);
+}
+
+void drvmgr_info_devs_on_bus(struct drvmgr_bus *bus, unsigned int options)
+{
+ struct drvmgr_dev *dev;
+
+ /* Print All Devices on Bus */
+ printf("\n\n -= All Devices on BUS %p =-\n\n", bus);
+ dev = bus->children;
+ while (dev) {
+ drvmgr_info_dev(dev, options);
+ puts("");
+ dev = dev->next_in_bus;
+ }
+
+ if ((options & OPTION_RECURSIVE) == 0)
+ return;
+
+ /* This device provides a bus, print the bus */
+ dev = bus->children;
+ while (dev) {
+ if (dev->bus)
+ drvmgr_info_devs_on_bus(dev->bus, options);
+ dev = dev->next_in_bus;
+ }
+}
+
+void drvmgr_info_devs(unsigned int options)
+{
+ struct rtems_driver_manager *mgr = &drv_mgr;
+ struct drvmgr_dev *dev;
+
+ /* Print device information of all devices and their child devices */
+ dev = &mgr->root_dev;
+ drvmgr_info_devs_on_bus(dev->bus, options);
+ printf("\n\n");
+}
+
+void drvmgr_info_drvs(unsigned int options)
+{
+ struct rtems_driver_manager *mgr = &drv_mgr;
+ struct drvmgr_drv *drv;
+
+ drv = DRV_LIST_HEAD(&mgr->drivers);
+ while (drv) {
+ drvmgr_info_drv(drv, options);
+ puts("\n");
+ drv = drv->next;
+ }
+}
+
+void drvmgr_info_buses(unsigned int options)
+{
+ struct rtems_driver_manager *mgr = &drv_mgr;
+ struct drvmgr_bus *bus;
+
+ bus = BUS_LIST_HEAD(&mgr->buses[DRVMGR_LEVEL_MAX]);
+ while (bus) {
+ drvmgr_info_bus(bus, options);
+ puts("\n");
+ bus = bus->next;
+ }
+}
diff --git a/cpukit/libdrvmgr/drvmgr_res.c b/cpukit/libdrvmgr/drvmgr_res.c
new file mode 100644
index 0000000000..e8545d78ee
--- /dev/null
+++ b/cpukit/libdrvmgr/drvmgr_res.c
@@ -0,0 +1,103 @@
+/* Driver Manager Driver Resource Interface Implementation.
+ *
+ * COPYRIGHT (c) 2009.
+ * Aeroflex Gaisler AB
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ */
+
+#include <string.h>
+#include <drvmgr/drvmgr.h>
+
+/* Find all the resource keys for a device among all bus resources */
+int drvmgr_keys_get(struct drvmgr_dev *dev, struct drvmgr_key **keys)
+{
+ struct drvmgr_bus *bus;
+ struct drvmgr_bus_res *node;
+ struct drvmgr_drv_res *res;
+ uint64_t drv_id;
+
+ bus = dev->parent;
+ if (!bus || !dev->drv)
+ return -1;
+
+ drv_id = dev->drv->drv_id;
+
+ /* Loop all resource arrays */
+ node = bus->reslist;
+ while (node) {
+ /* Find driver ID in resource array */
+ res = &node->resource[0];
+ while (res->drv_id) {
+ if (res->drv_id == drv_id) {
+ /* Found resource matching driver, now check
+ * that this resource is for this device.
+ */
+ if (dev->minor_bus == res->minor_bus) {
+ /* Matching driver and core number */
+ if (keys)
+ *keys = res->keys;
+ return 0;
+ }
+ }
+ res++;
+ }
+ node = node->next;
+ }
+ if (keys)
+ *keys = NULL;
+ return 1;
+}
+
+/* Return key that matches key name */
+struct drvmgr_key *drvmgr_key_get(
+ struct drvmgr_key *keys,
+ char *key_name)
+{
+ struct drvmgr_key *key;
+
+ if (!keys)
+ return NULL;
+
+ key = keys;
+ while (key->key_type != KEY_TYPE_NONE) {
+ if (strcmp(key_name, key->key_name) == 0)
+ return key;
+ key++;
+ }
+ return NULL;
+}
+
+union drvmgr_key_value *drvmgr_key_val_get(
+ struct drvmgr_key *keys,
+ char *key_name,
+ int key_type)
+{
+ struct drvmgr_key *key_match;
+
+ key_match = drvmgr_key_get(keys, key_name);
+ if (key_match) {
+ /* Found key, put pointer to value into */
+ if ((key_type == -1) || (key_match->key_type == key_type))
+ return &key_match->key_value;
+ }
+ return NULL;
+}
+
+union drvmgr_key_value *drvmgr_dev_key_get(
+ struct drvmgr_dev *dev,
+ char *key_name,
+ int key_type)
+{
+ struct drvmgr_key *keys = NULL;
+
+ /* Find first entry in key array for the device */
+ if (drvmgr_keys_get(dev, &keys))
+ return NULL;
+
+ /* Find a specific key among the device keys */
+ return drvmgr_key_val_get(keys, key_name, key_type);
+}
diff --git a/cpukit/libdrvmgr/drvmgr_rw.c b/cpukit/libdrvmgr/drvmgr_rw.c
new file mode 100644
index 0000000000..4a65e953ff
--- /dev/null
+++ b/cpukit/libdrvmgr/drvmgr_rw.c
@@ -0,0 +1,53 @@
+/* Driver Manager Read/Write Interface Implementation.
+ *
+ * COPYRIGHT (c) 2009.
+ * Aeroflex Gaisler AB
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ */
+
+#include <string.h>
+#include <drvmgr/drvmgr.h>
+
+/* Set a range of memory in 128 byte chunks.
+ * This call will take 128 bytes for buffer on stack
+ */
+void drvmgr_rw_memset(
+ void *dstadr,
+ int c,
+ size_t n,
+ void *a,
+ drvmgr_wmem_arg wmem
+ )
+{
+ unsigned long long buf[16+1]; /* Extra bytes after data are reserved
+ * for optimizations by write_mem */
+ int txlen, status;
+ char *adr;
+
+ if (n <= 0)
+ return;
+
+ if (n > sizeof(unsigned long long)*16)
+ txlen = sizeof(unsigned long long)*16;
+ else
+ txlen = n;
+
+ memset(buf, c, txlen);
+
+ adr = dstadr;
+ do {
+ wmem(adr, (const void *)&buf[0], txlen, a);
+ adr += txlen;
+ n -= txlen;
+
+ /* next length to transmitt */
+ if (n > 16*sizeof(unsigned long long))
+ txlen = 16*sizeof(unsigned long long);
+ else
+ txlen = n;
+ } while (n > 0);
+}
diff --git a/cpukit/libdrvmgr/drvmgr_translate.c b/cpukit/libdrvmgr/drvmgr_translate.c
new file mode 100644
index 0000000000..630ba6f007
--- /dev/null
+++ b/cpukit/libdrvmgr/drvmgr_translate.c
@@ -0,0 +1,152 @@
+/* Driver Manager Driver Translate Interface Implementation
+ *
+ * COPYRIGHT (c) 2010.
+ * Aeroflex Gaisler AB
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * Used by device drivers. The functions rely on that the parent bus driver
+ * has implemented the neccessary operations correctly.
+ *
+ * The translate functions are used to translate addresses between buses
+ * for DMA cores located on a "remote" bus, or for memory-mapped obtaining
+ * an address that can be used to access an remote bus.
+ *
+ * For example, PCI I/O might be memory-mapped at the PCI Host bridge,
+ * say address 0xfff10000-0xfff1ffff is mapped to the PCI I/O address
+ * of 0x00000000-0x0000ffff. The PCI Host bridge driver may then set up
+ * a map so that a driver that get PCI address 0x100 can translate that
+ * into 0xfff10100.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <drvmgr/drvmgr.h>
+#include "drvmgr_internal.h"
+
+int drvmgr_translate_bus(
+ struct drvmgr_bus *from,
+ struct drvmgr_bus *to,
+ int reverse,
+ void *src_address,
+ void **dst_address)
+{
+ struct drvmgr_bus *path[16];
+ int upstream, ret, depth, i;
+ void *dst, *from_adr, *to_adr;
+ struct drvmgr_map_entry *map;
+ struct drvmgr_bus *bus;
+
+ dst = src_address;
+ ret = 0;
+
+ if (from == to) /* no need traslating addresses when on same bus */
+ goto out;
+
+ if (from->depth > to->depth) {
+ /* up-streams */
+ upstream = 1;
+ depth = from->depth - to->depth;
+ if (depth >= 16)
+ return -1; /* Does not support such a big depth */
+
+ /* Intensionally we skip the last bus since its bridge is
+ * not used in this translation
+ */
+ path[0] = from;
+ for (i=1; i < depth; i++)
+ path[i] = path[i-1]->dev->parent;
+ } else {
+ /* down-streams */
+ upstream = 0;
+ depth = to->depth - from->depth;
+ if (depth >= 16)
+ return -1; /* Does not support such a big depth */
+
+ /* Intensionally we skip the last bus since its bridge is
+ * not used in this translation
+ */
+ path[depth-1] = to;
+ for (i=depth-1; i > 0; i--)
+ path[i-1] = path[i]->dev->parent;
+ }
+
+ /* Translate address */
+ for (i=0; i < depth && ret == 0; i++) {
+ bus = path[i];
+
+ if ((upstream && reverse) || (!upstream && !reverse))
+ map = bus->maps_down;
+ else
+ map = bus->maps_up;
+
+ if (map == NULL)
+ continue; /* No translation needed - 1:1 mapping */
+
+ ret = -1;
+
+ if (map == DRVMGR_TRANSLATE_NO_BRIDGE)
+ break; /* No bridge interface in this direction */
+
+ while (map->size != 0) {
+ if (reverse) {
+ /* Opposite direction */
+ from_adr = map->to_adr;
+ to_adr = map->from_adr;
+ } else {
+ from_adr = map->from_adr;
+ to_adr = map->to_adr;
+ }
+
+ if ((dst >= from_adr) &&
+ (dst <= (from_adr + (map->size - 1)))) {
+ dst = (dst - from_adr) + to_adr;
+ ret = 0;
+ break;
+ }
+ map++;
+ }
+ }
+
+out:
+ if (dst_address)
+ *dst_address = dst;
+
+ return ret;
+}
+
+/* Translate Address, used by drivers when an address need to be
+ * converted in order to access a remote address or for a remote
+ * hardware to access (DMA) to access CPU local RAM.
+ * - from remote address to CPU local
+ * - from CPU local to remote
+ */
+int drvmgr_translate(
+ struct drvmgr_dev *dev,
+ int cpu_addresses,
+ int upstream,
+ void *src_address,
+ void **dst_address)
+{
+ struct drvmgr_bus *to, *from;
+ int rev;
+
+ if (upstream) {
+ from = dev->parent;
+ to = drv_mgr.root_dev.bus;
+ } else {
+ from = drv_mgr.root_dev.bus;
+ to = dev->parent;
+ }
+
+ if (cpu_addresses)
+ rev = upstream;
+ else
+ rev = !upstream;
+
+ return drvmgr_translate_bus(from, to, rev, src_address, dst_address);
+}
diff --git a/cpukit/libdrvmgr/drvmgr_unregister.c b/cpukit/libdrvmgr/drvmgr_unregister.c
new file mode 100644
index 0000000000..e6154ff165
--- /dev/null
+++ b/cpukit/libdrvmgr/drvmgr_unregister.c
@@ -0,0 +1,184 @@
+/* Driver Manager Device Unregister (removal) implementation
+ *
+ * COPYRIGHT (c) 2011.
+ * Aeroflex Gaisler AB
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ */
+
+#include <stdlib.h>
+
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/drvmgr_list.h>
+#include "drvmgr_internal.h"
+
+/* Unregister all children on a bus.
+ *
+ * This function is called from the bus driver, from a "safe" state where
+ * devices will not be added or removed on this particular bus at this time
+ */
+int drvmgr_children_unregister(struct drvmgr_bus *bus)
+{
+ while (bus->children != NULL) {
+ bus->children->error = drvmgr_dev_unregister(bus->children);
+ if (bus->children->error != DRVMGR_OK) {
+ /* An error occured */
+ return bus->children->error;
+ }
+ }
+
+ return DRVMGR_OK;
+}
+
+/* Unregister a BUS and all it's devices.
+ *
+ * It is up to the bus driver to remove all it's devices, either manually
+ * one by one calling drvmgr_dev_unregister(), or by letting the driver
+ * manager unregister all children by calling drvmgr_children_unregister().
+ */
+int drvmgr_bus_unregister(struct drvmgr_bus *bus)
+{
+ struct rtems_driver_manager *mgr = &drv_mgr;
+ struct drvmgr_list *list;
+
+ if (bus->ops->remove == NULL)
+ return DRVMGR_ENOSYS;
+
+ /* Call Bus driver to clean things up, it must remove all children */
+ bus->error = bus->ops->remove(bus);
+ if (bus->error != DRVMGR_OK)
+ return bus->error;
+ /* Check that bus driver has done its job and removed all children */
+ if (bus->children != NULL)
+ return DRVMGR_FAIL;
+ /* Remove References to bus */
+ bus->dev->bus = NULL;
+
+ DRVMGR_LOCK_WRITE();
+
+ /* Remove bus from bus-list */
+ if (bus->state & BUS_STATE_LIST_INACTIVE)
+ list = &mgr->buses_inactive;
+ else
+ list = &mgr->buses[bus->level];
+ drvmgr_list_remove(list, bus);
+
+ DRVMGR_UNLOCK();
+
+ /* All references to this bus has been removed at this point */
+ free(bus);
+
+ return DRVMGR_OK;
+}
+
+/* Separate Driver and Device from each other */
+int drvmgr_dev_drv_separate(struct drvmgr_dev *dev)
+{
+ struct rtems_driver_manager *mgr = &drv_mgr;
+ struct drvmgr_dev *subdev, **pprev;
+ int rc;
+
+ /* Remove children if this device exports a bus of devices. All
+ * children must be removed first as they depend upon the bus
+ * services this bridge provide.
+ */
+ if (dev->bus) {
+ rc = drvmgr_bus_unregister(dev->bus);
+ if (rc != DRVMGR_OK)
+ return rc;
+ }
+
+ if (dev->drv == NULL)
+ return DRVMGR_OK;
+
+ /* Remove device by letting assigned driver take care of hardware
+ * issues
+ */
+ if (!dev->drv->ops->remove) {
+ /* No remove function is considered severe when someone
+ * is trying to remove the device
+ */
+ return DRVMGR_ENOSYS;
+ }
+ dev->error = dev->drv->ops->remove(dev);
+ if (dev->error != DRVMGR_OK)
+ return DRVMGR_FAIL;
+
+ DRVMGR_LOCK_WRITE();
+
+ /* Delete device from driver's device list */
+ pprev = &dev->drv->dev;
+ subdev = dev->drv->dev;
+ while (subdev != dev) {
+ pprev = &subdev->next_in_drv;
+ subdev = subdev->next_in_drv;
+ }
+ *pprev = subdev->next_in_drv;
+ dev->drv->dev_cnt--;
+
+ /* Move device to inactive list */
+ drvmgr_list_remove(&mgr->devices[dev->level], dev);
+ dev->level = 0;
+ dev->state &= ~(DEV_STATE_UNITED|DEV_STATE_INIT_DONE);
+ dev->state |= DEV_STATE_LIST_INACTIVE;
+ drvmgr_list_add_tail(&mgr->devices_inactive, dev);
+
+ DRVMGR_UNLOCK();
+
+ /* Free Device Driver Private memory if allocated previously by
+ * Driver manager.
+ */
+ if (dev->drv->dev_priv_size && dev->priv) {
+ free(dev->priv);
+ dev->priv = NULL;
+ }
+ dev->drv = NULL;
+
+ return DRVMGR_OK;
+}
+
+/* Unregister device,
+ * - let assigned driver handle deletion
+ * - remove from device list
+ * - remove from driver list
+ * - remove from bus list
+ */
+int drvmgr_dev_unregister(struct drvmgr_dev *dev)
+{
+ struct rtems_driver_manager *mgr = &drv_mgr;
+ struct drvmgr_dev *subdev, **pprev;
+ int err;
+
+ /* Separate device from driver, if the device is united with a driver.
+ *
+ * If this device is a bridge all child buses/devices are also removed.
+ */
+ err = drvmgr_dev_drv_separate(dev);
+ if (err != DRVMGR_OK)
+ return err;
+
+ DRVMGR_LOCK_WRITE();
+
+ /* Remove it from inactive list */
+ drvmgr_list_remove(&mgr->devices_inactive, dev);
+
+ /* Remove device from parent bus list (no check if dev not in list) */
+ pprev = &dev->parent->children;
+ subdev = dev->parent->children;
+ while (subdev != dev) {
+ pprev = &subdev->next_in_bus;
+ subdev = subdev->next_in_bus;
+ }
+ *pprev = subdev->next_in_bus;
+ dev->parent->dev_cnt--;
+
+ DRVMGR_UNLOCK();
+
+ /* All references to this device has been removed at this point */
+ free(dev);
+
+ return DRVMGR_OK;
+}
diff --git a/cpukit/libmisc/Makefile.am b/cpukit/libmisc/Makefile.am
index 2a7ba78d41..fbb6d096c8 100644
--- a/cpukit/libmisc/Makefile.am
+++ b/cpukit/libmisc/Makefile.am
@@ -97,7 +97,8 @@ libshell_a_SOURCES = shell/cat_file.c shell/cmds.c shell/internal.h \
shell/hexdump-odsyntax.c shell/hexdump-parse.c shell/hexsyntax.c \
shell/main_time.c shell/main_mknod.c \
shell/main_setenv.c shell/main_getenv.c shell/main_unsetenv.c \
- shell/main_mkrfs.c shell/main_debugrfs.c
+ shell/main_mkrfs.c shell/main_debugrfs.c \
+ shell/main_drvmgr.c shell/main_pci.c
if LIBNETWORKING
libshell_a_SOURCES += \
diff --git a/cpukit/libmisc/shell/main_drvmgr.c b/cpukit/libmisc/shell/main_drvmgr.c
new file mode 100644
index 0000000000..1a2563af7f
--- /dev/null
+++ b/cpukit/libmisc/shell/main_drvmgr.c
@@ -0,0 +1,422 @@
+/*
+ * DRVMGR Command Implmentation
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <drvmgr/drvmgr.h>
+
+#include <rtems.h>
+#include <rtems/shell.h>
+#include "internal.h"
+
+static void usage(void);
+
+static void *get_obj_adr(char *arg)
+{
+ unsigned long obj_adr;
+
+ obj_adr = strtoul(arg, NULL, 16);
+ if (obj_adr == ULONG_MAX || obj_adr == 0) {
+ puts(" Not a valid ID");
+ return NULL;
+ }
+
+ return (void *)obj_adr;
+}
+
+/* General info, root bus, number of devices etc. */
+void show_drvmgr_info(void)
+{
+ drvmgr_summary();
+ drvmgr_print_devs(PRINT_DEVS_ALL);
+}
+
+int shell_drvmgr_topo(int argc, char *argv[])
+{
+ drvmgr_print_topo();
+ return 0;
+}
+
+int shell_drvmgr_short(int argc, char *argv[])
+{
+ void *obj;
+
+ if (argc < 2)
+ return -1;
+ if (argc < 3) {
+ /* All Devices */
+ drvmgr_info_drvs(0);
+ drvmgr_info_buses(0);
+ drvmgr_info_devs(OPTION_DEV_GENINFO);
+ return 0;
+ }
+
+ /* Get ID from string */
+ obj = get_obj_adr(argv[2]);
+ if (!obj)
+ return -3;
+
+ drvmgr_info(obj, OPTION_DEV_GENINFO);
+
+ return 0;
+}
+
+int shell_drvmgr_info(int argc, char *argv[])
+{
+ void *obj;
+
+ if (argc < 2)
+ return -1;
+ if (argc < 3) {
+ /* All Drivers, Buses and Devices */
+ drvmgr_info_drvs(OPTION_INFO_ALL);
+ drvmgr_info_buses(OPTION_INFO_ALL);
+ drvmgr_info_devs(OPTION_INFO_ALL);
+ return 0;
+ }
+
+ /* Get ID from string */
+ obj = get_obj_adr(argv[2]);
+ if (!obj)
+ return -3;
+
+ drvmgr_info(obj, OPTION_INFO_ALL);
+
+ return 0;
+}
+
+int shell_drvmgr_remove(int argc, char *argv[])
+{
+ puts(" Not implemented");
+ return 0;
+}
+
+int shell_drvmgr_parent(int argc, char *argv[])
+{
+ void *obj;
+ int obj_type;
+ struct drvmgr_dev *dev;
+ struct drvmgr_bus *bus;
+
+ /* Get ID from string */
+ if (argc < 3)
+ return -2;
+ obj = get_obj_adr(argv[2]);
+ if (!obj)
+ return -3;
+
+ obj_type = *(int *)obj;
+ if (obj_type == DRVMGR_OBJ_BUS) {
+ bus = obj;
+ if (!bus->dev) {
+ puts(" bus has no bridge device");
+ } else if(!bus->dev->parent) {
+ puts(" bridge device has no parent");
+ } else {
+ dev = bus->dev;
+ printf(" BUSID=%p\n", dev->parent);
+ }
+ } else if (obj_type == DRVMGR_OBJ_DEV) {
+ dev = obj;
+ if (!dev->parent) {
+ puts(" device has no parent bus");
+ } else {
+ printf(" BUSID=%p\n", dev->parent);
+ }
+ } else {
+ puts(" ID is not a device or bus");
+ return 1;
+ }
+
+ return 0;
+}
+
+void shell_drvmgr_print_key_array(struct drvmgr_key *keys)
+{
+ struct drvmgr_key *key;
+ static char *type_strs[4] = {"UNKNOWN","INTEGER","STRING ","POINTER"};
+ int type;
+ union drvmgr_key_value *val;
+
+ if (keys == NULL) {
+ printf(" DEV HAS NO KEYS\n");
+ return;
+ }
+
+ key = &keys[0];
+ while (key->key_type != KEY_TYPE_NONE) {
+ if (key->key_type > KEY_TYPE_POINTER)
+ type = 0;
+ else
+ type = key->key_type;
+ printf(" NAME=%-14s TYPE=%s VALUE=", key->key_name, type_strs[type]);
+ val = &key->key_value;
+ switch (type) {
+ default:
+ case 0:
+ case KEY_TYPE_INT:
+ printf("0x%x (%d)\n", val->i, val->i);
+ break;
+ case KEY_TYPE_STRING:
+ printf("%s\n", val->str);
+ break;
+ case KEY_TYPE_POINTER:
+ printf("%p\n", val->ptr);
+ break;
+ }
+ key++;
+ }
+}
+
+void shell_drvmgr_print_res_array(struct drvmgr_drv_res *resources)
+{
+ struct drvmgr_drv_res *res = &resources[0];
+ struct drvmgr_drv *drv;
+ char *drv_name;
+
+ while (res->drv_id) {
+ /* Find Driver in order to print name of driver */
+ drv = drvmgr_drv_by_id(res->drv_id);
+ if (drv && drv->name)
+ drv_name = drv->name;
+ else
+ drv_name = "UNKNOWN";
+ printf(" RESOURCES FOR DEVICE[%02d] DRIVER[0x%llx (%s)]\n",
+ res->minor_bus, res->drv_id, drv_name);
+ shell_drvmgr_print_key_array(res->keys);
+ res++;
+ }
+}
+
+int shell_drvmgr_res(int argc, char *argv[])
+{
+ void *obj;
+ int obj_type;
+ struct drvmgr_dev *dev;
+ struct drvmgr_bus *bus;
+ struct drvmgr_key *keys;
+ struct drvmgr_bus_res *lst;
+ int i;
+
+ /* Get ID from string */
+ if (argc < 3)
+ return -2;
+ obj = get_obj_adr(argv[2]);
+ if (!obj)
+ return -3;
+
+ obj_type = *(int *)obj;
+ if (obj_type == DRVMGR_OBJ_BUS) {
+ bus = obj;
+ lst = bus->reslist;
+ if (lst == NULL) {
+ puts(" BUS does not have resources\n");
+ return 0;
+ }
+ i = 0;
+ while (lst) {
+ printf(" -- RESOURCES ARRAY %d --\n", i);
+ shell_drvmgr_print_res_array(lst->resource);
+ puts("");
+ i++;
+ lst = lst->next;
+ }
+ } else if (obj_type == DRVMGR_OBJ_DEV) {
+ dev = obj;
+ if (dev->drv == NULL) {
+ puts(" DEVICE has no driver ==> resources not available\n");
+ return 0;
+ }
+ drvmgr_keys_get(dev, &keys);
+ if (keys == NULL) {
+ puts(" DEVICE does not have resources\n");
+ return 0;
+ }
+ shell_drvmgr_print_key_array(keys);
+ } else {
+ puts(" ID is not a device or bus");
+ return 1;
+ }
+
+ return 0;
+}
+
+int shell_drvmgr_buses(int argc, char *argv[])
+{
+ drvmgr_info_buses(OPTION_INFO_ALL);
+ return 0;
+}
+
+int shell_drvmgr_devs(int argc, char *argv[])
+{
+ drvmgr_info_devs(OPTION_INFO_ALL);
+ return 0;
+}
+
+int shell_drvmgr_drvs(int argc, char *argv[])
+{
+ drvmgr_info_drvs(OPTION_INFO_ALL);
+ return 0;
+}
+
+int shell_drvmgr_mem(int argc, char *argv[])
+{
+ drvmgr_print_mem();
+ return 0;
+}
+
+int shell_drvmgr_translate(int argc, char *argv[])
+{
+ int rc, cpu, up, obj_type;
+ void *obj, *dst;
+ unsigned long src, tmp;
+
+ if (argc != 5)
+ return -1;
+
+ obj = get_obj_adr(argv[2]);
+ if (!obj)
+ return -3;
+
+ obj_type = *(int *)obj;
+ if (obj_type != DRVMGR_OBJ_DEV) {
+ puts(" ID is not a device\n");
+ return 0;
+ }
+
+ tmp = strtoul(argv[3], NULL, 0);
+ if (tmp > 3) {
+ puts(" Not a valid option OPT, only [0..3] is valid");
+ return 0;
+ }
+ cpu = tmp & 1;
+ up = (tmp >> 1) & 1;
+
+ src = strtoul(argv[4], NULL, 0);
+ if (src == ULONG_MAX && errno == ERANGE) {
+ puts(" Not a valid source address");
+ return 0;
+ }
+
+ rc = drvmgr_translate((struct drvmgr_dev *)obj, cpu, up, (void *)src, &dst);
+ if (rc != 0)
+ printf(" Address %p could not be translated\n", (void *)src);
+ else
+ printf(" %p => %p\n", (void *)src, dst);
+
+ return 0;
+}
+
+const char drvmgr_usage_str[] =
+ " usage:\n"
+ " drvmgr buses List bus specfic information on all buses\n"
+ " drvmgr devs List general and driver specfic information\n"
+ " about all devices\n"
+ " drvmgr drvs List driver specfic information on all drivers\n"
+ " drvmgr info [ID] List general and driver specfic information\n"
+ " about all devices or one device, bus or driver\n"
+ " drvmgr mem Dynamically memory usage\n"
+ " drvmgr parent ID Short info about parent bus of a device\n"
+ " drvmgr remove ID Remove a device or a bus\n"
+ " drvmgr res ID List Resources of a device or bus\n"
+ " drvmgr short [ID] Short info about all devices/buses or one\n"
+ " device/bus\n"
+ " drvmgr topo Show bus topology with all devices\n"
+ " drvmgr tr ID OPT ADR Translate hw(0)/cpu(1) (OPT bit0) address ADR\n"
+ " down(0)/up(1) streams (OPT bit1) for device\n"
+ " drvmgr --help\n";
+
+static void usage(void)
+{
+ puts(drvmgr_usage_str);
+}
+
+int shell_drvmgr_usage(int argc, char *argv[])
+{
+ usage();
+ return 0;
+}
+
+struct shell_drvmgr_modifier {
+ char *name;
+ int (*func)(int argc, char *argv[]);
+};
+
+#define MODIFIER_NUM 12
+static struct shell_drvmgr_modifier shell_drvmgr_modifiers[MODIFIER_NUM] =
+{
+ {"buses", shell_drvmgr_buses},
+ {"devs", shell_drvmgr_devs},
+ {"drvs", shell_drvmgr_drvs},
+ {"info", shell_drvmgr_info},
+ {"mem", shell_drvmgr_mem},
+ {"parent", shell_drvmgr_parent},
+ {"remove", shell_drvmgr_remove},
+ {"res", shell_drvmgr_res},
+ {"short", shell_drvmgr_short},
+ {"topo", shell_drvmgr_topo},
+ {"tr", shell_drvmgr_translate},
+ {"--help", shell_drvmgr_usage},
+};
+
+struct shell_drvmgr_modifier *shell_drvmgr_find_modifier(char *name)
+{
+ struct shell_drvmgr_modifier *mod;
+ int i;
+
+ if (name == NULL)
+ return NULL;
+
+ for (i=0, mod=&shell_drvmgr_modifiers[0]; i<MODIFIER_NUM; i++, mod++) {
+ if (strcmp(name, mod->name) == 0)
+ return mod;
+ }
+
+ return NULL;
+}
+
+int rtems_shell_main_drvmgr(
+ int argc,
+ char *argv[]
+)
+{
+ struct shell_drvmgr_modifier *mod;
+ int rc;
+
+ if (argc < 2) {
+ show_drvmgr_info();
+ rc = 0;
+ } else if ((mod=shell_drvmgr_find_modifier(argv[1])) != NULL) {
+ rc = mod->func(argc, argv);
+ } else {
+ rc = -1;
+ }
+
+ if (rc < 0) {
+ printf(" invalid argument\n");
+ usage();
+ }
+
+ return rc;
+}
+
+rtems_shell_cmd_t rtems_shell_DRVMGR_Command = {
+ "drvmgr", /* name */
+ drvmgr_usage_str, /* usage */
+ "system", /* topic */
+ rtems_shell_main_drvmgr, /* command */
+ NULL, /* alias */
+ NULL /* next */
+};
diff --git a/cpukit/libmisc/shell/main_pci.c b/cpukit/libmisc/shell/main_pci.c
new file mode 100644
index 0000000000..56190c05eb
--- /dev/null
+++ b/cpukit/libmisc/shell/main_pci.c
@@ -0,0 +1,493 @@
+/*
+ * LIBPCI Command Implmentation
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <pci.h>
+#include <pci/cfg.h>
+#include <pci/access.h>
+#include <rtems/endian.h>
+#include <bsp.h> /* For PCI endianness config */
+
+#include <rtems.h>
+#include <rtems/shell.h>
+#include "internal.h"
+
+static void usage(void);
+
+struct shell_pci_modifier {
+ char *name;
+ int (*func)(int argc, char *argv[], struct shell_pci_modifier *mod);
+ int data;
+};
+
+static unsigned long get_pciid_from_string(char *arg)
+{
+ unsigned long pciid;
+ char *bus_str, *dev_str, *fun_str;
+ unsigned long busno, devno, funno;
+
+ dev_str = strstr(arg, ":");
+ if (dev_str == NULL) {
+ /* PCIID */
+ pciid = strtoul(arg, NULL, 16);
+ if (pciid == ULONG_MAX)
+ return ~0;
+ } else {
+ /* bus:dev:fun */
+ bus_str = arg;
+ *dev_str = '\0';
+ dev_str++;
+ fun_str = strstr(dev_str, ":");
+ if (fun_str == NULL)
+ return ~0;
+ *fun_str = '\0';
+ fun_str++;
+
+ busno = strtoul(bus_str, NULL, 16);
+ if (busno == ULONG_MAX)
+ return ~0;
+ devno = strtoul(dev_str, NULL, 16);
+ if (devno == ULONG_MAX)
+ return ~0;
+ funno = strtoul(fun_str, NULL, 16);
+ if (funno == ULONG_MAX)
+ return ~0;
+ pciid = PCI_DEV(busno, devno, funno);
+ }
+
+ return pciid;
+}
+
+/* Print current PCI configuration that can be used in a static/peripheral PCI
+ * configuration setup.
+ */
+int shell_pci_pcfg(int argc, char *argv[], struct shell_pci_modifier *mod)
+{
+ if (argc != 2)
+ return -1;
+
+ pci_cfg_print();
+
+ return 0;
+}
+
+int shell_pci_ls(int argc, char *argv[], struct shell_pci_modifier *mod)
+{
+ unsigned long pciid;
+
+ if (argc == 2) {
+ /* List all devices */
+ pci_print();
+ } else if (argc > 3) {
+ return -1;
+ } else {
+ pciid = get_pciid_from_string(argv[2]);
+ if ((pciid & 0xffff0000) != 0)
+ return -1;
+
+ pci_print_dev((pci_dev_t)pciid);
+ }
+ return 0;
+}
+
+int shell_pci_rX(unsigned long pciid, int offset, int size)
+{
+ uint8_t data8;
+ uint16_t data16;
+ uint32_t data32;
+ int result;
+
+ switch(size) {
+ case 1:
+ result = pci_cfg_r8(pciid, offset, &data8);
+ if (result == PCISTS_OK)
+ printf(" r08[0x%02x]: 0x%02x DEC=%d\n", offset, data8, data8);
+ break;
+
+ case 2:
+ result = pci_cfg_r16(pciid, offset, &data16);
+ if (result == PCISTS_OK)
+ printf(" r16[0x%02x]: 0x%04x DEC=%d\n", offset, data16, data16);
+ break;
+
+ case 4:
+ result = pci_cfg_r32(pciid, offset, &data32);
+ if (result == PCISTS_OK)
+ printf(" r32[0x%02x]: 0x%08lx DEC=%lu\n", offset, data32, data32);
+ break;
+
+ default:
+ return PCISTS_EINVAL;
+ }
+ return result;
+}
+
+int shell_pci_wX(unsigned long pciid, int offset, uint32_t data, int size)
+{
+ uint8_t data8;
+ uint16_t data16;
+ int result;
+
+ switch(size) {
+ case 1:
+ if (data > 0xff)
+ return PCISTS_EINVAL;
+ data8 = data & 0xff;
+ result = pci_cfg_w8(pciid, offset, data8);
+ if (result == PCISTS_OK)
+ printf(" w08[0x%02x]: 0x%02x DEC=%d\n", offset, data8, data8);
+ break;
+
+ case 2:
+ if (data > 0xffff)
+ return PCISTS_EINVAL;
+ data16 = data & 0xffff;
+ result = pci_cfg_w16(pciid, offset, data16);
+ if (result == PCISTS_OK)
+ printf(" w16[0x%02x]: 0x%04x DEC=%d\n", offset, data16, data16);
+ break;
+
+ case 4:
+ result = pci_cfg_w32(pciid, offset, data);
+ if (result == PCISTS_OK)
+ printf(" w32[0x%02x]: 0x%08lx DEC=%lu\n", offset, data, data);
+ break;
+
+ default:
+ return PCISTS_EINVAL;
+ }
+ return result;
+}
+
+int shell_pci_read(int argc, char *argv[], struct shell_pci_modifier *mod)
+{
+ unsigned long pciid, offset;
+ int result, size;
+
+ if (argc != 4)
+ return -1;
+
+ pciid = get_pciid_from_string(argv[2]);
+ if ((pciid & 0xffff0000) != 0)
+ return -1;
+
+ offset = strtoul(argv[3], NULL, 0);
+ if (offset > 256)
+ return -1;
+
+ size = mod->data;
+ result = shell_pci_rX(pciid, offset, size);
+ switch (result) {
+ default:
+ case PCISTS_OK:
+ break;
+
+ case PCISTS_ERR:
+ case PCISTS_EINVAL:
+ puts(" Bad input argument\n");
+ return PCISTS_EINVAL;
+
+ case PCISTS_MSTABRT:
+ puts(" Master abort while reading configuration space");
+ return PCISTS_MSTABRT;
+ }
+
+ return 0;
+}
+
+int shell_pci_write(int argc, char *argv[], struct shell_pci_modifier *mod)
+{
+ unsigned long pciid, offset;
+ int result, size;
+ uint32_t data;
+
+ if (argc != 5)
+ return -1;
+
+ pciid = get_pciid_from_string(argv[2]);
+ if ((pciid & 0xffff0000) != 0)
+ return -1;
+
+ offset = strtoul(argv[3], NULL, 0);
+ if (offset > 256)
+ return -1;
+
+ data = strtoul(argv[4], NULL, 0);
+ if (data == ULONG_MAX && errno == ERANGE)
+ return -1;
+
+ size = mod->data;
+ result = shell_pci_wX(pciid, offset, data, size);
+ switch (result) {
+ default:
+ case PCISTS_OK:
+ break;
+
+ case PCISTS_ERR:
+ case PCISTS_EINVAL:
+ puts(" Bad input argument\n");
+ return PCISTS_EINVAL;
+
+ case PCISTS_MSTABRT:
+ puts(" Master abort while reading configuration space");
+ return PCISTS_MSTABRT;
+ }
+ return 0;
+}
+
+int shell_pci_pciid(int argc, char *argv[], struct shell_pci_modifier *mod)
+{
+ unsigned long pciid;
+
+ if (argc != 3)
+ return -1;
+
+ pciid = get_pciid_from_string(argv[2]);
+ if ((pciid & 0xffff0000) != 0)
+ return -1;
+
+ printf(" PCIID: 0x%lx [%lx:%lx:%lx]\n", pciid, PCI_DEV_EXPAND(pciid));
+ return 0;
+}
+
+int shell_pci_getdev(int argc, char *argv[], struct shell_pci_modifier *mod)
+{
+ unsigned long pciid;
+ struct pci_dev *dev;
+
+ if (argc != 3)
+ return -1;
+
+ pciid = get_pciid_from_string(argv[2]);
+ if ((pciid & 0xffff0000) != 0)
+ return -1;
+
+ if (pci_get_dev(pciid, &dev)) {
+ printf(" GETDEV: no device on [%lx:%lx:%lx]\n", PCI_DEV_EXPAND(pciid));
+ return 0;
+ }
+
+ printf(" PCI RAM DEVICE: %p\n", dev);
+ return 0;
+}
+
+int shell_pci_infodev(int argc, char *argv[], struct shell_pci_modifier *mod)
+{
+ unsigned long arg;
+ struct pci_dev *dev;
+ struct pci_bus *bus;
+ struct pci_res *res;
+ char *type_str, *str1, *res_types[3] = {" IO16", "MEMIO", "MEM"};
+ int i, res_avail;
+
+ if (argc != 3)
+ return -1;
+
+ arg = strtoul(argv[2], NULL, 0);
+ if (arg == ULONG_MAX && errno == ERANGE)
+ return -1;
+
+ dev = (struct pci_dev *)arg;
+ if (!dev) {
+ printf(" INFODEV: invalid device\n");
+ return 0;
+ }
+
+ if (dev->flags & PCI_DEV_BRIDGE) {
+ type_str = "PCI-to-PCI BRIDGE";
+ if (!dev->bus)
+ type_str = "PCI HOST BRIDGE";
+ } else
+ type_str = "PCI DEVICE";
+ printf(" %s at [%x:%x:%x]\n", type_str, PCI_DEV_EXPAND(dev->busdevfun));
+
+ bus = (struct pci_bus *)dev;
+ if (bus) {
+ printf(" PRIMARY: BUS 0x%x\n", bus->pri);
+ printf(" SECONDARY: BUS 0x%x\n", bus->num);
+ printf(" SUB ORDINATE: BUS 0x%x\n", bus->sord);
+ }
+
+ printf(" PCIID: 0x%04x\n", dev->busdevfun);
+ bus = dev->bus;
+ if (!bus) {
+ printf(" AT BUS: 0x%x via Host Bridge\n", bus->num);
+ } else {
+ printf(" AT BUS: 0x%x via Bridge at [%x:%x:%x]\n", bus->num,
+ PCI_DEV_EXPAND(bus->dev.busdevfun));
+ }
+ printf(" VENDOR: 0x%04x\n", dev->vendor);
+ printf(" DEVICE: 0x%04x\n", dev->device);
+ printf(" SUB VENDOR: 0x%04x\n", dev->subvendor);
+ printf(" SUB DEVICE: 0x%04x\n", dev->subdevice);
+ printf(" CLASS: 0x%06lx\n", dev->classrev >> 8);
+ printf(" REVISION: 0x%02lx\n", dev->classrev & 0xff);
+ printf(" IRQ: %d\n", dev->sysirq);
+
+ res_avail = 0;
+ for (i = 0; i < DEV_RES_CNT; i++) {
+ res = &dev->resources[i];
+
+ if ((res->flags & PCI_RES_TYPE_MASK) == 0)
+ continue;
+
+ str1 = res_types[(res->flags & PCI_RES_TYPE_MASK) - 1];
+ if (res->flags & PCI_RES_IO32)
+ str1 = " IO32";
+
+ if (res_avail == 0) {
+ puts(" RESOURCES:");
+ res_avail = 1;
+ }
+
+ if (res->flags & PCI_RES_FAIL) {
+ printf(" %s[%d]: NOT ASSIGNED", str1, i);
+ continue;
+ }
+
+ printf(" %s[%d]: %08lx-%08lx\n", str1, i, res->start, res->end - 1);
+ }
+
+ if (res_avail == 0)
+ puts(" NO CONFIGURED RESOURCES AVAILABLE");
+
+ return 0;
+}
+
+int pci_summary(void)
+{
+ char *str;
+ char *cfglib_strs[5] = {"NONE", "AUTO", "STATIC", "READ", "PERIPHERAL"};
+
+ if (pci_system_type == PCI_SYSTEM_HOST)
+ str = "HOST";
+ else if (pci_system_type == PCI_SYSTEM_PERIPHERAL)
+ str = "PERIPHERAL";
+ else
+ str = "UNKNOWN / UNINITIALIZED";
+ printf(" SYSTEM: %s\n", str);
+
+ if (pci_config_lib_type > PCI_CONFIG_LIB_PERIPHERAL) {
+ puts(" Bad configuration library");
+ return 1;
+ }
+ printf(" CFG LIBRARY: %s\n", cfglib_strs[pci_config_lib_type]);
+ printf(" NO. PCI BUSES: %d buses\n", pci_bus_count());
+ printf(" PCI ENDIAN: %s\n", pci_endian ? "Big" : "Little");
+#if (CPU_LITTLE_ENDIAN == TRUE)
+ puts(" MACHINE ENDIAN: Little");
+#else
+ puts(" MACHINE ENDIAN: Big");
+#endif
+
+ return 0;
+}
+
+const char pci_usage_str[] =
+ " usage:\n"
+ " pci ls [bus:dev:fun|PCIID] List one or all devices\n"
+ " pci r{8|16|32} bus:dev:fun OFS Configuration space read\n"
+ " pci r{8|16|32} PCIID OFS Configuration space read\n"
+ " access by PCIID\n"
+ " pci w{8|16|32} bus:dev:fun OFS D Configuration space write\n"
+ " pci w{8|16|32} PCIID OFS D Configuration space write\n"
+ " access by PCIID\n"
+ " pci pciid bus:dev:fun Print PCIID for bus:dev:fun\n"
+ " pci pciid PCIID Print bus:dev:fun for PCIID\n"
+ " pci pcfg Print current PCI config for\n"
+ " static configuration library\n"
+ " pci getdev {PCIID|bus:dev:fun} Get PCI Device from RAM tree\n"
+ " pci infodev DEV_ADR Info about a PCI RAM Device\n"
+ " pci --help\n";
+
+static void usage(void)
+{
+ puts(pci_usage_str);
+}
+
+int shell_pci_usage(int argc, char *argv[], struct shell_pci_modifier *mod)
+{
+ usage();
+ return 0;
+}
+
+#define MODIFIER_NUM 12
+static struct shell_pci_modifier shell_pci_modifiers[MODIFIER_NUM] =
+{
+ {"ls", shell_pci_ls, 0},
+ {"r8", shell_pci_read, 1},
+ {"r16", shell_pci_read, 2},
+ {"r32", shell_pci_read, 4},
+ {"w8", shell_pci_write, 1},
+ {"w16", shell_pci_write, 2},
+ {"w32", shell_pci_write, 4},
+ {"pciid", shell_pci_pciid, 0},
+ {"pcfg", shell_pci_pcfg, 0},
+ {"getdev", shell_pci_getdev, 0},
+ {"infodev", shell_pci_infodev, 0},
+ {"--help", shell_pci_usage},
+};
+
+struct shell_pci_modifier *shell_pci_find_modifier(char *name)
+{
+ struct shell_pci_modifier *mod;
+ int i;
+
+ if (name == NULL)
+ return NULL;
+
+ for (i=0, mod=&shell_pci_modifiers[0]; i<MODIFIER_NUM; i++, mod++) {
+ if (strcmp(name, mod->name) == 0)
+ return mod;
+ }
+
+ return NULL;
+}
+
+int rtems_shell_main_pci(
+ int argc,
+ char *argv[]
+)
+{
+ struct shell_pci_modifier *mod;
+ int rc;
+
+ if (argc < 2) {
+ /* without arguments */
+ pci_summary();
+ rc = 0;
+ } else if ((mod=shell_pci_find_modifier(argv[1])) != NULL) {
+ rc = mod->func(argc, argv, mod);
+ } else {
+ rc = -1;
+ }
+
+ if (rc < 0) {
+ printf(" invalid argument\n");
+ usage();
+ }
+
+ return rc;
+}
+
+rtems_shell_cmd_t rtems_shell_PCI_Command = {
+ "pci", /* name */
+ pci_usage_str, /* usage */
+ "system", /* topic */
+ rtems_shell_main_pci, /* command */
+ NULL, /* alias */
+ NULL /* next */
+};
diff --git a/cpukit/libmisc/shell/shellconfig.h b/cpukit/libmisc/shell/shellconfig.h
index cfc475095e..d9319f2396 100644
--- a/cpukit/libmisc/shell/shellconfig.h
+++ b/cpukit/libmisc/shell/shellconfig.h
@@ -80,6 +80,12 @@ extern rtems_shell_cmd_t rtems_shell_MALLOC_INFO_Command;
extern rtems_shell_cmd_t rtems_shell_NETSTATS_Command;
#endif
+/*
+ * Extern for System commands
+ */
+extern rtems_shell_cmd_t rtems_shell_DRVMGR_Command;
+extern rtems_shell_cmd_t rtems_shell_PCI_Command;
+
extern rtems_shell_cmd_t *rtems_shell_Initial_commands[];
/*
@@ -425,6 +431,25 @@ extern rtems_shell_alias_t *rtems_shell_Initial_aliases[];
#endif
/*
+ * System related commands
+ */
+ #if defined(RTEMS_DRVMGR_STARTUP) || defined(CONFIGURE_SHELL_COMMAND_DRVMGR)
+ #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \
+ !defined(CONFIGURE_SHELL_NO_COMMAND_DRVMGR)) || \
+ defined(CONFIGURE_SHELL_COMMAND_DRVMGR)
+ &rtems_shell_DRVMGR_Command,
+ #endif
+ #endif
+
+ #if defined(RTEMS_PCI_CONFIG_LIB)
+ #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \
+ !defined(CONFIGURE_SHELL_NO_COMMAND_PCI)) || \
+ defined(CONFIGURE_SHELL_COMMAND_PCI)
+ &rtems_shell_PCI_Command,
+ #endif
+ #endif
+
+ /*
* User defined shell commands
*/
#if defined(CONFIGURE_SHELL_USER_COMMANDS)
diff --git a/cpukit/libpci/CHANGES b/cpukit/libpci/CHANGES
new file mode 100644
index 0000000000..46064f0faa
--- /dev/null
+++ b/cpukit/libpci/CHANGES
@@ -0,0 +1,46 @@
+ 2011-03-03, Daniel Hellstrom <daniel@gaisler.com>
+ Added support for ROM BARs at devices and PCI-PCI bridges.
+
+ 2011-02-11, Daniel Hellstrom <daniel@gaisler.com>
+ Split Library into different parts, this enables PCI initialization to be done
+ outside of the PCI Host driver and smaller systems that don't want
+ Configuration Space to be setup.
+ - Access Library (Configuration, Memory and I/O Space read/write routines)
+ - Configuration Libarary
+ A. Auto Config
+ B. Static Config (not implemented yet)
+ - Interrupt Library (shared interrupt support rely on BSP)
+ This file created.
+
+ 2011-02-11, Daniel Hellstrom <daniel@gaisler.com>
+ Changed library to use 16-bit identifiers (pci_dev_t), instead to 3 integers
+ (BUS,SLOT,FUNC), this reduces the footprint.
+
+ 2010-09-29, Kristoffer Glembo <kristoffer@gaisler.com>
+ Fixed I/O BAR size calculation of bridges. Reading/Writing to 0x1C instead of
+ faulty 0x1E.
+
+ 2010-06-10, Daniel Hellstrom <daniel@gaisler.com>
+ Fix in pci_res_insert(), where the above mentioned optimization failed due to
+ bad compare statement. Optimization only affects systems with multiple PCI
+ buses.
+
+ 2010-04-19, Daniel Hellstrom <daniel@gaisler.com>
+ Optimized resource allocation when bridges are present: the resources lists
+ are sorted by boundary instead of size and a reorder aligorithm introduced
+ that move resources into unused areas if possible.
+
+ 2010-04-19, Daniel Hellstrom <daniel@gaisler.com>
+ Fixed autoconf issue when bridges are present
+
+ 2010-02-03, Daniel Hellstrom <daniel@gaisler.com>
+ Fixed initialization problem when first device is a bridge.
+
+ 2010-02-03, Daniel Hellstrom <daniel@gaisler.com>
+ PCI Library rewritten from scratch. Support multiple buses/bridges, print
+ current PCI configuration space setup, BAR assigment sort implementation
+ speeded up drastically (bootup time noticable shorter), interrupt assignment
+ implemented, PCI Host driver extracted from library, support for I/O areas.
+
+
+.... not updated ... lots of more changes
diff --git a/cpukit/libpci/Makefile b/cpukit/libpci/Makefile
new file mode 100644
index 0000000000..f304f893d6
--- /dev/null
+++ b/cpukit/libpci/Makefile
@@ -0,0 +1,31 @@
+### Debug Makefile for just building LIBPCI
+
+CC=/opt/rtems-4.10/bin/sparc-rtems-gcc
+CFLAGS=-Wall -I. -I/opt/rtems-4.10/sparc-rtems/leon3/lib/include -g3 -O3 -c
+
+.PHONY: drvmgr pci
+
+drvmgr:
+ $(CC) $(CFLAGS) pci_bus.c
+
+pci:
+ $(CC) $(CFLAGS) pci_access.c
+ $(CC) $(CFLAGS) pci_access_func.c
+ $(CC) $(CFLAGS) pci_access_io.c
+ $(CC) $(CFLAGS) pci_access_mem_be.c
+ $(CC) $(CFLAGS) pci_access_mem.c
+ $(CC) $(CFLAGS) pci_access_mem_le.c
+ $(CC) $(CFLAGS) pci_cfg_auto.c
+ $(CC) $(CFLAGS) pci_cfg.c
+ $(CC) $(CFLAGS) pci_cfg_peripheral.c
+ $(CC) $(CFLAGS) pci_cfg_print_code.c
+ $(CC) $(CFLAGS) pci_cfg_read.c
+ $(CC) $(CFLAGS) pci_cfg_static.c
+ $(CC) $(CFLAGS) pci_find.c
+ $(CC) $(CFLAGS) pci_find_dev.c
+ $(CC) $(CFLAGS) pci_for_each.c
+ $(CC) $(CFLAGS) pci_for_each_child.c
+ $(CC) $(CFLAGS) pci_for_each_dev.c
+ $(CC) $(CFLAGS) pci_get_dev.c
+ $(CC) $(CFLAGS) pci_irq.c
+ $(CC) $(CFLAGS) pci_print.c
diff --git a/cpukit/libpci/Makefile.am b/cpukit/libpci/Makefile.am
new file mode 100644
index 0000000000..aa08c32c7d
--- /dev/null
+++ b/cpukit/libpci/Makefile.am
@@ -0,0 +1,47 @@
+##
+## $Id: Makefile.am
+##
+
+include $(top_srcdir)/automake/compile.am
+include $(top_srcdir)/automake/multilib.am
+
+EXTRA_DIST=
+
+## PCI Library
+include_HEADERS = pci.h
+include_pcidir = $(includedir)/pci
+include_pci_HEADERS = pci/access.h pci/cfg.h \
+ pci/cfg_auto.h pci/cfg_static.h \
+ pci/cfg_peripheral.h pci/cfg_read.h \
+ pci/ids.h pci/ids_extra.h pci/irq.h
+
+noinst_LIBRARIES = libpci.a
+
+libpci_a_SOURCES = pci_access.c
+libpci_a_SOURCES += pci_access_func.c
+libpci_a_SOURCES += pci_access_io.c
+libpci_a_SOURCES += pci_access_mem.c
+libpci_a_SOURCES += pci_access_mem_be.c
+libpci_a_SOURCES += pci_access_mem_le.c
+libpci_a_SOURCES += pci_cfg.c
+libpci_a_SOURCES += pci_cfg_auto.c
+libpci_a_SOURCES += pci_cfg_print_code.c
+libpci_a_SOURCES += pci_cfg_read.c
+libpci_a_SOURCES += pci_cfg_static.c
+libpci_a_SOURCES += pci_cfg_peripheral.c
+libpci_a_SOURCES += pci_find.c
+libpci_a_SOURCES += pci_find_dev.c
+libpci_a_SOURCES += pci_for_each.c
+libpci_a_SOURCES += pci_for_each_dev.c
+libpci_a_SOURCES += pci_for_each_child.c
+libpci_a_SOURCES += pci_get_dev.c
+libpci_a_SOURCES += pci_irq.c
+libpci_a_SOURCES += pci_print.c
+
+# Driver manager PCI bus
+libpci_a_SOURCES += pci_bus.c
+include_drvmgrdir = $(includedir)/drvmgr
+include_drvmgr_HEADERS = pci_bus.h
+
+include $(srcdir)/preinstall.am
+include $(top_srcdir)/automake/local.am
diff --git a/cpukit/libpci/README b/cpukit/libpci/README
new file mode 100644
index 0000000000..334f3a9271
--- /dev/null
+++ b/cpukit/libpci/README
@@ -0,0 +1,4 @@
+PCI Library
+
+LIBPCI is documented in the ../../doc directory, see ../../doc/README how
+to build documentation.
diff --git a/cpukit/libpci/drvmgr/drvmgr.h b/cpukit/libpci/drvmgr/drvmgr.h
new file mode 120000
index 0000000000..ed6d0e7378
--- /dev/null
+++ b/cpukit/libpci/drvmgr/drvmgr.h
@@ -0,0 +1 @@
+../../libdrvmgr/drvmgr.h \ No newline at end of file
diff --git a/cpukit/libpci/drvmgr/drvmgr_confdefs.h b/cpukit/libpci/drvmgr/drvmgr_confdefs.h
new file mode 120000
index 0000000000..2bbeea7c62
--- /dev/null
+++ b/cpukit/libpci/drvmgr/drvmgr_confdefs.h
@@ -0,0 +1 @@
+../../libdrvmgr/drvmgr_confdefs.h \ No newline at end of file
diff --git a/cpukit/libpci/drvmgr/drvmgr_list.h b/cpukit/libpci/drvmgr/drvmgr_list.h
new file mode 120000
index 0000000000..a5268c86d4
--- /dev/null
+++ b/cpukit/libpci/drvmgr/drvmgr_list.h
@@ -0,0 +1 @@
+../../libdrvmgr/drvmgr_list.h \ No newline at end of file
diff --git a/cpukit/libpci/drvmgr/pci_bus.h b/cpukit/libpci/drvmgr/pci_bus.h
new file mode 120000
index 0000000000..6fe4e56579
--- /dev/null
+++ b/cpukit/libpci/drvmgr/pci_bus.h
@@ -0,0 +1 @@
+../pci_bus.h \ No newline at end of file
diff --git a/cpukit/libpci/pci.h b/cpukit/libpci/pci.h
new file mode 100644
index 0000000000..ad656f3e08
--- /dev/null
+++ b/cpukit/libpci/pci.h
@@ -0,0 +1,374 @@
+/*
+ *
+ * PCI defines and function prototypes
+ * Copyright 1994, Drew Eckhardt
+ * Copyright 1997, 1998 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ * Copyright 2009-2011, Aeroflex Gaisler
+ *
+ * For more information, please consult the following manuals (look at
+ * http://www.pcisig.com/ for how to get them):
+ *
+ * PCI BIOS Specification
+ * PCI Local Bus Specification
+ * PCI to PCI Bridge Specification
+ * PCI System Design Guide
+ *
+ * pci.h,v 1.2.4.2 2004/11/10 22:15:01 joel Exp
+ */
+
+#ifndef __PCI_H__
+#define __PCI_H__
+
+#include <pci/ids.h>
+
+/*
+ * Under PCI, each device has 256 bytes of configuration address space,
+ * of which the first 64 bytes are standardized as follows:
+ */
+#define PCI_VENDOR_ID 0x00 /* 16 bits */
+#define PCI_DEVICE_ID 0x02 /* 16 bits */
+#define PCI_COMMAND 0x04 /* 16 bits */
+#define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */
+#define PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */
+#define PCI_COMMAND_MASTER 0x4 /* Enable bus mastering */
+#define PCI_COMMAND_SPECIAL 0x8 /* Enable response to special cycles */
+#define PCI_COMMAND_INVALIDATE 0x10 /* Use memory write and invalidate */
+#define PCI_COMMAND_VGA_PALETTE 0x20 /* Enable palette snooping */
+#define PCI_COMMAND_PARITY 0x40 /* Enable parity checking */
+#define PCI_COMMAND_WAIT 0x80 /* Enable address/data stepping */
+#define PCI_COMMAND_SERR 0x100 /* Enable SERR */
+#define PCI_COMMAND_FAST_BACK 0x200 /* Enable back-to-back writes */
+
+#define PCI_STATUS 0x06 /* 16 bits */
+#define PCI_STATUS_66MHZ 0x20 /* Support 66 Mhz PCI 2.1 bus */
+#define PCI_STATUS_UDF 0x40 /* Support User Definable Features */
+
+#define PCI_STATUS_FAST_BACK 0x80 /* Accept fast-back to back */
+#define PCI_STATUS_PARITY 0x100 /* Detected parity error */
+#define PCI_STATUS_DEVSEL_MASK 0x600 /* DEVSEL timing */
+#define PCI_STATUS_DEVSEL_FAST 0x000
+#define PCI_STATUS_DEVSEL_MEDIUM 0x200
+#define PCI_STATUS_DEVSEL_SLOW 0x400
+#define PCI_STATUS_SIG_TARGET_ABORT 0x800 /* Set on target abort */
+#define PCI_STATUS_REC_TARGET_ABORT 0x1000 /* Master ack of " */
+#define PCI_STATUS_REC_MASTER_ABORT 0x2000 /* Set on master abort */
+#define PCI_STATUS_SIG_SYSTEM_ERROR 0x4000 /* Set when we drive SERR */
+#define PCI_STATUS_DETECTED_PARITY 0x8000 /* Set on parity error */
+
+#define PCI_CLASS_REVISION 0x08 /* High 24 bits are class, low 8
+ revision */
+#define PCI_REVISION_ID 0x08 /* Revision ID */
+#define PCI_CLASS_PROG 0x09 /* Reg. Level Programming Interface */
+#define PCI_CLASS_DEVICE 0x0a /* Device class */
+
+#define PCI_CACHE_LINE_SIZE 0x0c /* 8 bits */
+#define PCI_LATENCY_TIMER 0x0d /* 8 bits */
+#define PCI_HEADER_TYPE 0x0e /* 8 bits */
+#define PCI_HEADER_TYPE_NORMAL 0
+#define PCI_HEADER_TYPE_BRIDGE 1
+#define PCI_HEADER_TYPE_CARDBUS 2
+
+#define PCI_BIST 0x0f /* 8 bits */
+#define PCI_BIST_CODE_MASK 0x0f /* Return result */
+#define PCI_BIST_START 0x40 /* 1 to start BIST, 2 secs or less */
+#define PCI_BIST_CAPABLE 0x80 /* 1 if BIST capable */
+
+/*
+ * Base addresses specify locations in memory or I/O space.
+ * Decoded size can be determined by writing a value of
+ * 0xffffffff to the register, and reading it back. Only
+ * 1 bits are decoded.
+ */
+#define PCI_BASE_ADDRESS_0 0x10 /* 32 bits */
+#define PCI_BASE_ADDRESS_1 0x14 /* 32 bits [htype 0,1 only] */
+#define PCI_BASE_ADDRESS_2 0x18 /* 32 bits [htype 0 only] */
+#define PCI_BASE_ADDRESS_3 0x1c /* 32 bits */
+#define PCI_BASE_ADDRESS_4 0x20 /* 32 bits */
+#define PCI_BASE_ADDRESS_5 0x24 /* 32 bits */
+#define PCI_BASE_ADDRESS_SPACE 0x01 /* 0 = memory, 1 = I/O */
+#define PCI_BASE_ADDRESS_SPACE_IO 0x01
+#define PCI_BASE_ADDRESS_SPACE_MEMORY 0x00
+#define PCI_BASE_ADDRESS_MEM_TYPE_MASK 0x06
+#define PCI_BASE_ADDRESS_MEM_TYPE_32 0x00 /* 32 bit address */
+#define PCI_BASE_ADDRESS_MEM_TYPE_1M 0x02 /* Below 1M */
+#define PCI_BASE_ADDRESS_MEM_TYPE_64 0x04 /* 64 bit address */
+#define PCI_BASE_ADDRESS_MEM_PREFETCH 0x08 /* prefetchable? */
+#define PCI_BASE_ADDRESS_MEM_MASK (~0x0fUL)
+#define PCI_BASE_ADDRESS_IO_MASK (~0x03UL)
+/* bit 1 is reserved if address_space = 1 */
+
+/* Header type 0 (normal devices) */
+#define PCI_CARDBUS_CIS 0x28
+#define PCI_SUBSYSTEM_VENDOR_ID 0x2c
+#define PCI_SUBSYSTEM_ID 0x2e
+#define PCI_ROM_ADDRESS 0x30 /* Bits 31..11 are address, 10..1 reserved */
+#define PCI_ROM_ADDRESS_ENABLE 0x01
+#define PCI_ROM_ADDRESS_MASK (~0x7ffUL)
+
+/* 0x34 Capabilities Pointer (PCI 2.3) */
+#define PCI_CAP_PTR 0x34 /* 8 bits */
+
+/* 0x35-0x3b are reserved */
+#define PCI_INTERRUPT_LINE 0x3c /* 8 bits */
+#define PCI_INTERRUPT_PIN 0x3d /* 8 bits */
+#define PCI_MIN_GNT 0x3e /* 8 bits */
+#define PCI_MAX_LAT 0x3f /* 8 bits */
+
+/* Header type 1 (PCI-to-PCI bridges) */
+#define PCI_PRIMARY_BUS 0x18 /* Primary bus number */
+#define PCI_SECONDARY_BUS 0x19 /* Secondary bus number */
+#define PCI_SUBORDINATE_BUS 0x1a /* Highest bus number behind the bridge */
+#define PCI_SEC_LATENCY_TIMER 0x1b /* Latency timer for secondary interface */
+#define PCI_IO_BASE 0x1c /* I/O range behind the bridge */
+#define PCI_IO_LIMIT 0x1d
+#define PCI_IO_RANGE_TYPE_MASK 0x0f /* I/O bridging type */
+#define PCI_IO_RANGE_TYPE_16 0x00
+#define PCI_IO_RANGE_TYPE_32 0x01
+#define PCI_IO_RANGE_MASK (~0x0f)
+#define PCI_SEC_STATUS 0x1e /* Secondary status register, only bit 14 used */
+#define PCI_MEMORY_BASE 0x20 /* Memory range behind */
+#define PCI_MEMORY_LIMIT 0x22
+#define PCI_MEMORY_RANGE_TYPE_MASK 0x0f
+#define PCI_MEMORY_RANGE_MASK (~0x0f)
+#define PCI_PREF_MEMORY_BASE 0x24 /* Prefetchable memory range behind */
+#define PCI_PREF_MEMORY_LIMIT 0x26
+#define PCI_PREF_RANGE_TYPE_MASK 0x0f
+#define PCI_PREF_RANGE_TYPE_32 0x00
+#define PCI_PREF_RANGE_TYPE_64 0x01
+#define PCI_PREF_RANGE_MASK (~0x0f)
+#define PCI_PREF_BASE_UPPER32 0x28 /* Upper half of prefetchable memory range */
+#define PCI_PREF_LIMIT_UPPER32 0x2c
+#define PCI_IO_BASE_UPPER16 0x30 /* Upper half of I/O addresses */
+#define PCI_IO_LIMIT_UPPER16 0x32
+/* 0x34-0x3b is reserved */
+#define PCI_ROM_ADDRESS1 0x38 /* Same as PCI_ROM_ADDRESS, but for htype 1 */
+/* 0x3c-0x3d are same as for htype 0 */
+#define PCI_BRIDGE_CONTROL 0x3e
+#define PCI_BRIDGE_CTL_PARITY 0x01 /* Enable parity detection on secondary interface */
+#define PCI_BRIDGE_CTL_SERR 0x02 /* The same for SERR forwarding */
+#define PCI_BRIDGE_CTL_NO_ISA 0x04 /* Disable bridging of ISA ports */
+#define PCI_BRIDGE_CTL_VGA 0x08 /* Forward VGA addresses */
+#define PCI_BRIDGE_CTL_MASTER_ABORT 0x20 /* Report master aborts */
+#define PCI_BRIDGE_CTL_BUS_RESET 0x40 /* Secondary bus reset */
+#define PCI_BRIDGE_CTL_FAST_BACK 0x80 /* Fast Back2Back enabled on secondary interface */
+
+/* Header type 2 (CardBus bridges) */
+/* 0x14-0x15 reserved */
+#define PCI_CB_SEC_STATUS 0x16 /* Secondary status */
+#define PCI_CB_PRIMARY_BUS 0x18 /* PCI bus number */
+#define PCI_CB_CARD_BUS 0x19 /* CardBus bus number */
+#define PCI_CB_SUBORDINATE_BUS 0x1a /* Subordinate bus number */
+#define PCI_CB_LATENCY_TIMER 0x1b /* CardBus latency timer */
+#define PCI_CB_MEMORY_BASE_0 0x1c
+#define PCI_CB_MEMORY_LIMIT_0 0x20
+#define PCI_CB_MEMORY_BASE_1 0x24
+#define PCI_CB_MEMORY_LIMIT_1 0x28
+#define PCI_CB_IO_BASE_0 0x2c
+#define PCI_CB_IO_BASE_0_HI 0x2e
+#define PCI_CB_IO_LIMIT_0 0x30
+#define PCI_CB_IO_LIMIT_0_HI 0x32
+#define PCI_CB_IO_BASE_1 0x34
+#define PCI_CB_IO_BASE_1_HI 0x36
+#define PCI_CB_IO_LIMIT_1 0x38
+#define PCI_CB_IO_LIMIT_1_HI 0x3a
+#define PCI_CB_IO_RANGE_MASK (~0x03)
+/* 0x3c-0x3d are same as for htype 0 */
+#define PCI_CB_BRIDGE_CONTROL 0x3e
+#define PCI_CB_BRIDGE_CTL_PARITY 0x01 /* Similar to standard bridge control register */
+#define PCI_CB_BRIDGE_CTL_SERR 0x02
+#define PCI_CB_BRIDGE_CTL_ISA 0x04
+#define PCI_CB_BRIDGE_CTL_VGA 0x08
+#define PCI_CB_BRIDGE_CTL_MASTER_ABORT 0x20
+#define PCI_CB_BRIDGE_CTL_CB_RESET 0x40 /* CardBus reset */
+#define PCI_CB_BRIDGE_CTL_16BIT_INT 0x80 /* Enable interrupt for 16-bit cards */
+#define PCI_CB_BRIDGE_CTL_PREFETCH_MEM0 0x100 /* Prefetch enable for both memory regions */
+#define PCI_CB_BRIDGE_CTL_PREFETCH_MEM1 0x200
+#define PCI_CB_BRIDGE_CTL_POST_WRITES 0x400
+#define PCI_CB_SUBSYSTEM_VENDOR_ID 0x40
+#define PCI_CB_SUBSYSTEM_ID 0x42
+#define PCI_CB_LEGACY_MODE_BASE 0x44 /* 16-bit PC Card legacy mode base address (ExCa) */
+/* 0x48-0x7f reserved */
+
+/* Device classes and subclasses */
+
+#define PCI_CLASS_NOT_DEFINED 0x0000
+#define PCI_CLASS_NOT_DEFINED_VGA 0x0001
+
+#define PCI_BASE_CLASS_STORAGE 0x01
+#define PCI_CLASS_STORAGE_SCSI 0x0100
+#define PCI_CLASS_STORAGE_IDE 0x0101
+#define PCI_CLASS_STORAGE_FLOPPY 0x0102
+#define PCI_CLASS_STORAGE_IPI 0x0103
+#define PCI_CLASS_STORAGE_RAID 0x0104
+#define PCI_CLASS_STORAGE_OTHER 0x0180
+
+#define PCI_BASE_CLASS_NETWORK 0x02
+#define PCI_CLASS_NETWORK_ETHERNET 0x0200
+#define PCI_CLASS_NETWORK_TOKEN_RING 0x0201
+#define PCI_CLASS_NETWORK_FDDI 0x0202
+#define PCI_CLASS_NETWORK_ATM 0x0203
+#define PCI_CLASS_NETWORK_OTHER 0x0280
+
+#define PCI_BASE_CLASS_DISPLAY 0x03
+#define PCI_CLASS_DISPLAY_VGA 0x0300
+#define PCI_CLASS_DISPLAY_XGA 0x0301
+#define PCI_CLASS_DISPLAY_OTHER 0x0380
+
+#define PCI_BASE_CLASS_MULTIMEDIA 0x04
+#define PCI_CLASS_MULTIMEDIA_VIDEO 0x0400
+#define PCI_CLASS_MULTIMEDIA_AUDIO 0x0401
+#define PCI_CLASS_MULTIMEDIA_OTHER 0x0480
+
+#define PCI_BASE_CLASS_MEMORY 0x05
+#define PCI_CLASS_MEMORY_RAM 0x0500
+#define PCI_CLASS_MEMORY_FLASH 0x0501
+#define PCI_CLASS_MEMORY_OTHER 0x0580
+
+#define PCI_BASE_CLASS_BRIDGE 0x06
+#define PCI_CLASS_BRIDGE_HOST 0x0600
+#define PCI_CLASS_BRIDGE_ISA 0x0601
+#define PCI_CLASS_BRIDGE_EISA 0x0602
+#define PCI_CLASS_BRIDGE_MC 0x0603
+#define PCI_CLASS_BRIDGE_PCI 0x0604
+#define PCI_CLASS_BRIDGE_PCMCIA 0x0605
+#define PCI_CLASS_BRIDGE_NUBUS 0x0606
+#define PCI_CLASS_BRIDGE_CARDBUS 0x0607
+#define PCI_CLASS_BRIDGE_OTHER 0x0680
+
+#define PCI_BASE_CLASS_COMMUNICATION 0x07
+#define PCI_CLASS_COMMUNICATION_SERIAL 0x0700
+#define PCI_CLASS_COMMUNICATION_PARALLEL 0x0701
+#define PCI_CLASS_COMMUNICATION_OTHER 0x0780
+
+#define PCI_BASE_CLASS_SYSTEM 0x08
+#define PCI_CLASS_SYSTEM_PIC 0x0800
+#define PCI_CLASS_SYSTEM_DMA 0x0801
+#define PCI_CLASS_SYSTEM_TIMER 0x0802
+#define PCI_CLASS_SYSTEM_RTC 0x0803
+#define PCI_CLASS_SYSTEM_OTHER 0x0880
+
+#define PCI_BASE_CLASS_INPUT 0x09
+#define PCI_CLASS_INPUT_KEYBOARD 0x0900
+#define PCI_CLASS_INPUT_PEN 0x0901
+#define PCI_CLASS_INPUT_MOUSE 0x0902
+#define PCI_CLASS_INPUT_OTHER 0x0980
+
+#define PCI_BASE_CLASS_DOCKING 0x0a
+#define PCI_CLASS_DOCKING_GENERIC 0x0a00
+#define PCI_CLASS_DOCKING_OTHER 0x0a01
+
+#define PCI_BASE_CLASS_PROCESSOR 0x0b
+#define PCI_CLASS_PROCESSOR_386 0x0b00
+#define PCI_CLASS_PROCESSOR_486 0x0b01
+#define PCI_CLASS_PROCESSOR_PENTIUM 0x0b02
+#define PCI_CLASS_PROCESSOR_ALPHA 0x0b10
+#define PCI_CLASS_PROCESSOR_POWERPC 0x0b20
+#define PCI_CLASS_PROCESSOR_CO 0x0b40
+
+#define PCI_BASE_CLASS_SERIAL 0x0c
+#define PCI_CLASS_SERIAL_FIREWIRE 0x0c00
+#define PCI_CLASS_SERIAL_ACCESS 0x0c01
+#define PCI_CLASS_SERIAL_SSA 0x0c02
+#define PCI_CLASS_SERIAL_USB 0x0c03
+#define PCI_CLASS_SERIAL_FIBER 0x0c04
+
+#define PCI_CLASS_OTHERS 0xff
+
+#define PCI_INVALID_VENDORDEVICEID 0xffffffff
+#define PCI_MULTI_FUNCTION 0x80
+
+#define PCI_MAX_DEVICES 32
+#define PCI_MAX_FUNCTIONS 8
+
+#include <pci/access.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* The PCI Library have the following build time configuration options. It is
+ * up to the BSP header file (bsp.h) to set options properly.
+ *
+ * BSP_PCI_BIG_ENDIAN - Access inline routines will be for a big-endian PCI
+ * bus, if not defined the routines will assume that
+ * PCI is as the standard defines: little-endian.
+ *
+ * Note that drivers may be run-time configurable,
+ * meaning that they may adopt to either big-endian or
+ * little-endian PCI bus, the host driver or BSP may
+ * detect endianness during run-time.
+ */
+
+/* Error return values */
+enum {
+ PCISTS_ERR = -1, /* Undefined Error */
+ PCISTS_OK = 0,
+ PCISTS_EINVAL = 1, /* Bad input arguments */
+ PCISTS_MSTABRT = 2, /* CFG space access error (can be ignored) */
+};
+
+/* PCI System type can be used to determine system for drivers. Normally
+ * the system is Host, but the peripheral configuration library also supports
+ * being PCI peripheral not allowed to access configuration space.
+ *
+ * The active configuration Library set this variable.
+ */
+enum {
+ PCI_SYSTEM_NONE = 0,
+ PCI_SYSTEM_HOST = 1,
+ PCI_SYSTEM_PERIPHERAL = 2,
+};
+extern int pci_system_type;
+
+/* PCI Bus Endianness. The PCI specification is little endian, however on some
+ * embedded systems (AT697-LEON2 for example) the PCI bus is defined as big
+ * endian (non-standard) in order to avoid byte-twisting.
+ */
+enum {
+ PCI_LITTLE_ENDIAN = 0,
+ PCI_BIG_ENDIAN = 1,
+};
+extern int pci_endian;
+
+/* Return the number of PCI busses in the system */
+extern int pci_bus_count(void);
+
+/* Scan the PCI bus and print the PCI device/functions/bridges and their
+ * current resources and size to the system console.
+ */
+extern void pci_print(void);
+
+/* Print current configuration of a single PCI device by reading PCI
+ * configuration space
+ */
+extern void pci_print_dev(pci_dev_t dev);
+extern void pci_print_device(int bus, int slot, int function);
+
+/*** PCI Configuration Space direct access routines ***/
+
+/* Function iterates over all PCI buses/devices/functions and calls
+ * func(PCIDEV,arg) for each present device. The iteration is stopped if
+ * func() returns non-zero result the same result is returned. As long
+ * as func() returns zero the function will keep on iterating, when all
+ * devices has been processed the function return zero.
+ *
+ * The function iterates over all devices/functions on all buses by accessing
+ * configuration space directly (PCI RAM data structures not used). This
+ * function is valid to call after PCI buses have been enumrated.
+ */
+extern int pci_for_each(int (*func)(pci_dev_t, void*), void *arg);
+
+/* Get PCI Configuration space BUS|SLOT|FUNC for a device matching PCI
+ * Vendor, Device and instance number 'index'.
+ *
+ * Return Values
+ * -1 pci_find_dev did not find a device matching the criterion.
+ * 0 device was found, *pdev was updated with the device's BUS|SLOT|FUNC
+ */
+extern int pci_find(uint16_t ven, uint16_t dev, int index, pci_dev_t *pdev);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __PCI_H__ */
diff --git a/cpukit/libpci/pci/access.h b/cpukit/libpci/pci/access.h
new file mode 100644
index 0000000000..a3f351f60b
--- /dev/null
+++ b/cpukit/libpci/pci/access.h
@@ -0,0 +1,315 @@
+/* Routines to access PCI memory/configuration space and other PCI related
+ * functions the PCI Library provides.
+ */
+
+#ifndef __PCI_ACCESS_H__
+#define __PCI_ACCESS_H__
+
+#include <stdint.h>
+#include <libcpu/byteorder.h>
+#include <pci.h>
+
+/* Let BSP configure load/store from PCI */
+#include <bsp.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Identification of a PCI configuration space device (16-bit) */
+typedef uint16_t pci_dev_t;
+/* Create a PCI Configuration Space ID */
+#define PCI_DEV(bus, slot, func) (((bus)<<8) | ((slot)<<3) | (func))
+/* Get Bus of a PCI Configuration Space ID */
+#define PCI_DEV_BUS(dev) (((dev) >> 8) & 0xff)
+/* Get Slot/Device of a PCI Configuration Space ID */
+#define PCI_DEV_SLOT(dev) (((dev) >> 3) & 0x1f)
+/* Get Function of a PCI Configuration Space ID */
+#define PCI_DEV_FUNC(dev) ((dev) & 0x7)
+/* Get Device and Function of a PCI Configuration Space ID */
+#define PCI_DEV_DEVFUNC(dev) ((dev) & 0xff)
+/* Expand Device into argument lists */
+#define PCI_DEV_EXPAND(dev) PCI_DEV_BUS((dev)), PCI_DEV_SLOT((dev)), PCI_DEV_FUNC((dev))
+
+/* Configuration Space Read/Write Operations */
+struct pci_cfg_ops {
+ /* Configuration Space Access and Setup Routines */
+ int (*read8)(pci_dev_t dev, int ofs, uint8_t *data);
+ int (*read16)(pci_dev_t dev, int ofs, uint16_t *data);
+ int (*read32)(pci_dev_t dev, int ofs, uint32_t *data);
+ int (*write8)(pci_dev_t dev, int ofs, uint8_t data);
+ int (*write16)(pci_dev_t dev, int ofs, uint16_t data);
+ int (*write32)(pci_dev_t dev, int ofs, uint32_t data);
+};
+
+/* Read a register over PCI I/O Space, and swap it if necessary (due to
+ * PCI endianness)
+ */
+struct pci_io_ops {
+ uint8_t (*read8)(uint8_t *adr);
+ uint16_t(*read16)(uint16_t *adr);
+ uint32_t (*read32)(uint32_t *adr);
+ void (*write8)(uint8_t *adr, uint8_t data);
+ void (*write16)(uint16_t *adr, uint16_t data);
+ void (*write32)(uint32_t *adr, uint32_t data);
+};
+
+/* Read a register over PCI Memory Space (non-prefetchable memory), and
+ * swap it if necessary (due to PCI endianness)
+ */
+struct pci_memreg_ops {
+ uint8_t (*ld8)(uint8_t *adr);
+ void (*st8)(uint8_t *adr, uint8_t data);
+
+ uint16_t(*ld_le16)(uint16_t *adr);
+ void (*st_le16)(uint16_t *adr, uint16_t data);
+ uint16_t(*ld_be16)(uint16_t *adr);
+ void (*st_be16)(uint16_t *adr, uint16_t data);
+
+ uint32_t (*ld_le32)(uint32_t *adr);
+ void (*st_le32)(uint32_t *adr, uint32_t data);
+ uint32_t (*ld_be32)(uint32_t *adr);
+ void (*st_be32)(uint32_t *adr, uint32_t data);
+};
+
+typedef uint8_t (*pci_ld8_t)(uint8_t *adr);
+typedef void (*pci_st8_t)(uint8_t *adr, uint8_t data);
+typedef uint16_t(pci_ld16_t)(uint16_t *adr);
+typedef void (*pci_st16_t)(uint16_t *adr, uint16_t data);
+typedef uint32_t (*pci_ld32_t)(uint32_t *adr);
+typedef void (*pci_st32_t)(uint32_t *adr, uint32_t data);
+
+struct pci_access_drv {
+ /* Configuration */
+ struct pci_cfg_ops cfg;
+
+ /* I/O Access operations */
+ struct pci_io_ops io;
+
+ /* Registers over Memory Access operations. Note that these funcs
+ * are only for code that need to be compatible with both Big-Endian
+ * and Little-Endian PCI bus or for some other reason need function
+ * pointers to access functions. Normally drivers use the inline
+ * functions for Registers-over-Memory access to avoid extra function
+ * call.
+ */
+ struct pci_memreg_ops *memreg;
+
+ /* Translate from PCI address to CPU address (dir=0). Translate
+ * CPU address to PCI address (dir!=0). The address will can be
+ * used to perform I/O access or memory access by CPU or PCI DMA
+ * peripheral.
+ *
+ * address In/Out. CPU address or PCI address.
+ * type Access type. 1=I/O, 2=MEMIO, 3=MEM
+ * dir Translate direction. 0=PCI-to-CPU, 0!=CPU-to-PCI,
+ *
+ * Return Value
+ * 0 = Success
+ * -1 = Requested Address not mapped into other address space
+ * i.e. not accessible
+ */
+ int (*translate)(uint32_t *address, int type, int dir);
+};
+
+/* Access Routines valid after a PCI-Access-Driver has registered */
+extern struct pci_access_drv pci_access_ops;
+
+/* Register PCI Access Driver */
+extern int pci_access_drv_register(struct pci_access_drv *drv);
+
+/* Set/unset bits in command and status register of a PCI device */
+extern void pci_modify_cmdsts(pci_dev_t dev, uint32_t mask, uint32_t val);
+
+/* Enable Memory in command register */
+static inline void pci_mem_enable(pci_dev_t dev)
+{
+ pci_modify_cmdsts(dev, PCI_COMMAND_MEMORY, PCI_COMMAND_MEMORY);
+}
+
+static inline void pci_mem_disable(pci_dev_t dev)
+{
+ pci_modify_cmdsts(dev, PCI_COMMAND_MEMORY, 0);
+}
+
+static inline void pci_io_enable(pci_dev_t dev)
+{
+ pci_modify_cmdsts(dev, PCI_COMMAND_IO, PCI_COMMAND_IO);
+}
+
+static inline void pci_io_disable(pci_dev_t dev)
+{
+ pci_modify_cmdsts(dev, PCI_COMMAND_IO, 0);
+}
+
+static inline void pci_master_enable(pci_dev_t dev)
+{
+ pci_modify_cmdsts(dev, PCI_COMMAND_MASTER, PCI_COMMAND_MASTER);
+}
+
+static inline void pci_master_disable(pci_dev_t dev)
+{
+ pci_modify_cmdsts(dev, PCI_COMMAND_MASTER, 0);
+}
+
+/* Configuration Space Access Read Routines */
+extern int pci_cfg_r8(pci_dev_t dev, int ofs, uint8_t *data);
+extern int pci_cfg_r16(pci_dev_t dev, int ofs, uint16_t *data);
+extern int pci_cfg_r32(pci_dev_t dev, int ofs, uint32_t *data);
+
+/* Configuration Space Access Write Routines */
+extern int pci_cfg_w8(pci_dev_t dev, int ofs, uint8_t data);
+extern int pci_cfg_w16(pci_dev_t dev, int ofs, uint16_t data);
+extern int pci_cfg_w32(pci_dev_t dev, int ofs, uint32_t data);
+
+/* Read a register over PCI I/O Space */
+extern uint8_t pci_io_r8(uint32_t adr);
+extern uint16_t pci_io_r16(uint32_t adr);
+extern uint32_t pci_io_r32(uint32_t adr);
+
+/* Write a register over PCI I/O Space */
+extern void pci_io_w8(uint32_t adr, uint8_t data);
+extern void pci_io_w16(uint32_t adr, uint16_t data);
+extern void pci_io_w32(uint32_t adr, uint32_t data);
+
+/* Translate PCI address into CPU accessible address */
+static inline int pci_pci2cpu(uint32_t *address, int type)
+{
+ return pci_access_ops.translate(address, type, 0);
+}
+
+/* Translate CPU accessible address into PCI address (for DMA) */
+static inline int pci_cpu2pci(uint32_t *address, int type)
+{
+ return pci_access_ops.translate(address, type, 1);
+}
+
+/*** Read/Write a register over PCI Memory Space ***/
+
+static inline uint8_t pci_ld8(volatile uint8_t *addr)
+{
+ return *addr;
+}
+
+static inline void pci_st8(volatile uint8_t *addr, uint8_t val)
+{
+ *addr = val;
+}
+
+#ifdef BSP_PCI_BIG_ENDIAN
+
+/* BSP has decided Big Endian PCI Bus (non-standard) */
+
+static inline uint16_t pci_ld_le16(volatile uint16_t *addr)
+{
+ return ld_be16(addr);
+}
+
+static inline void pci_st_le16(volatile uint16_t *addr, uint16_t val)
+{
+ st_be16(addr, val);
+}
+
+static inline uint32_t pci_ld_le32(volatile uint32_t *addr)
+{
+ return ld_be32(addr);
+}
+
+static inline void pci_st_le32(volatile uint32_t *addr, uint32_t val)
+{
+ st_be32(addr, val);
+}
+
+static inline uint16_t pci_ld_be16(volatile uint16_t *addr)
+{
+ return ld_le16(addr);
+}
+
+static inline void pci_st_be16(volatile uint16_t *addr, uint16_t val)
+{
+ st_le16(addr, val);
+}
+
+static inline uint32_t pci_ld_be32(volatile uint32_t *addr)
+{
+ return ld_le32(addr);
+}
+
+static inline void pci_st_be32(volatile uint32_t *addr, uint32_t val)
+{
+ st_le32(addr, val);
+}
+
+#else
+
+/* Little Endian PCI Bus */
+
+static inline uint16_t pci_ld_le16(volatile uint16_t *addr)
+{
+ return ld_le16(addr);
+}
+
+static inline void pci_st_le16(volatile uint16_t *addr, uint16_t val)
+{
+ st_le16(addr, val);
+}
+
+static inline uint32_t pci_ld_le32(volatile uint32_t *addr)
+{
+ return ld_le32(addr);
+}
+
+static inline void pci_st_le32(volatile uint32_t *addr, uint32_t val)
+{
+ st_le32(addr, val);
+}
+
+static inline uint16_t pci_ld_be16(volatile uint16_t *addr)
+{
+ return ld_be16(addr);
+}
+
+static inline void pci_st_be16(volatile uint16_t *addr, uint16_t val)
+{
+ st_be16(addr, val);
+}
+
+static inline uint32_t pci_ld_be32(volatile uint32_t *addr)
+{
+ return ld_be32(addr);
+}
+
+static inline void pci_st_be32(volatile uint32_t *addr, uint32_t val)
+{
+ st_be32(addr, val);
+}
+
+#endif
+
+/* Get Read/Write function for accessing a register over PCI Memory Space
+ * (non-inline functions).
+ *
+ * Arguments
+ * wr 0(Read), 1(Write)
+ * size 1(Byte), 2(Word), 4(Double Word)
+ * func Where function pointer will be stored
+ * endian PCI_LITTLE_ENDIAN or PCI_BIG_ENDIAN
+ * type 1(I/O), 3(REG over MEM), 4(CFG)
+ *
+ * Return
+ * 0 Found function
+ * others No such function defined by host driver or BSP
+ */
+extern int pci_access_func(int wr, int size, void **func, int endian, int type);
+
+/* Predefined functions for Host drivers or BSPs that define the
+ * register-over-memory space functions operations.
+ */
+extern struct pci_memreg_ops pci_mem_le_ops; /* For Little-Endian PCI bus */
+extern struct pci_memreg_ops pci_mem_be_ops; /* For Big-Endian PCI bus */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !__PCI_ACCESS_H__ */
diff --git a/cpukit/libpci/pci/cfg.h b/cpukit/libpci/pci/cfg.h
new file mode 100644
index 0000000000..6018ca5fa3
--- /dev/null
+++ b/cpukit/libpci/pci/cfg.h
@@ -0,0 +1,237 @@
+/* PCI Configuration Library, two versions of the library exists:
+ * - auto configuration (default)
+ * - static configuration (user defined config)
+ * both versions are defined here.
+ *
+ */
+
+#ifndef __PCI_CFG_H__
+#define __PCI_CFG_H__
+
+#include <pci.h>
+
+/* PCI Configuration library */
+
+/* Return the number of PCI buses in system */
+extern int pci_bus_count(void);
+
+/* PCI Address assigned to BARs which failed to fit into the PCI Window or
+ * is disabled by any other cause.
+ */
+extern uint32_t pci_invalid_address;
+
+/* PCI Configuration Library of the system */
+enum {
+ PCI_CONFIG_LIB_NONE = 0,
+ PCI_CONFIG_LIB_AUTO = 1,
+ PCI_CONFIG_LIB_STATIC = 2,
+ PCI_CONFIG_LIB_READ = 3,
+ PCI_CONFIG_LIB_PERIPHERAL = 4,
+};
+extern const int pci_config_lib_type;
+
+/* Configuration library function pointers, these are set in <rtems/confdefs.h>
+ * by project configuration or by the BSP. The configuration will pull in the
+ * PCI Library needed and the PCI initialization functions will call these
+ * functions on initialization from the host driver.
+ */
+extern int (*pci_config_lib_init)(void);
+extern void (*pci_config_lib_register)(void *config);
+
+/* Configure PCI devices and bridges, and setup the RAM data structures
+ * describing the PCI devices currently present in the system.
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+extern int pci_config_init(void);
+
+/* Register a config-library specific configuration used by the libarary in
+ * pci_config_init().
+ */
+extern void pci_config_register(void *config);
+
+/* Print current PCI configuration (C-code) to terminal, can be used in
+ * static and peripheral PCI configuration library. The configuration is
+ * taken from the current configuration library setup.
+ */
+extern void pci_cfg_print(void);
+
+struct pci_bus; /* Bridge Device and secondary bus information */
+struct pci_dev; /* Device/function */
+struct pci_res; /* Resource: BAR, ROM or Bridge Window */
+
+/* The Host Bridge and all subdevices (the PCI RAM data structure) */
+extern struct pci_bus pci_hb;
+
+/* Iterate over all PCI devices on a bus (see search options) and call func(),
+ * iteration is stopped if a non-zero value is returned by func().
+ *
+ * The function iterates over the PCI RAM data structure, it is not
+ * available until after all devices have been found and pci_hb is populated,
+ * typically after pci_config_init() is called.
+ *
+ * search options: 0 (no child buses), 1 (depth first, recursive)
+ *
+ * Return Values
+ * 0 All PCI devices were processed, func() returned 0 on every call
+ * X func() returned non-zero X value, the search was stopped
+ */
+#define SEARCH_DEPTH 1
+extern int pci_for_each_child(
+ struct pci_bus *bus,
+ int (*func)(struct pci_dev *, void *arg),
+ void *arg,
+ int search);
+
+/* Depth first search of all PCI devices in PCI RAM data structure and call
+ * func(dev, arg), iteration is stopped if a non-zero value is returned by
+ * func().
+ *
+ * The function iterates over the PCI RAM data structure, it is not
+ * available until after all devices have been found and pci_hb is populated,
+ * typically after pci_config_init() is called.
+ *
+ * Return Values
+ * 0 All PCI devices were processed, func() returned 0 on every call
+ * X func() returned non-zero X value, the search was stopped
+ */
+extern int pci_for_each_dev(
+ int (*func)(struct pci_dev *, void *arg),
+ void *arg);
+
+/* Get PCI device from RAM device tree for a device matching PCI Vendor, Device
+ * and instance number 'index'.
+ *
+ * Return Values
+ * -1 pci_find_dev did not find a device matching the criterion.
+ * 0 device was found, *ppdev was updated with the PCI device address
+ */
+extern int pci_find_dev(uint16_t ven, uint16_t dev, int index,
+ struct pci_dev **ppdev);
+
+/* Get PCI device from RAM device tree by BUS|SLOT|FUNC.
+ *
+ * Return Values
+ * -1 pci_get_dev did not find a device matching the criterion
+ * 0 device was found, *ppdev was updated with the PCI device address
+ */
+extern int pci_get_dev(pci_dev_t pcidev, struct pci_dev **ppdev);
+
+/* Resource flags */
+#define PCI_RES_IO 1
+#define PCI_RES_MEMIO 2
+#define PCI_RES_MEM_PREFETCH 1
+#define PCI_RES_MEM (PCI_RES_MEMIO | PCI_RES_MEM_PREFETCH)
+#define PCI_RES_TYPE_MASK 0x3
+#define PCI_RES_IO32 0x08
+#define PCI_RES_FAIL 0x10 /* Alloc Failed */
+
+/* BAR Resouces entry */
+struct pci_res {
+ struct pci_res *next;
+ uint32_t size;
+ uint32_t boundary;
+ unsigned char flags; /* I/O, MEM or MEMIO */
+ unsigned char bar;
+
+ /* Assigned Resource (PCI address), zero if not assigned */
+ uint32_t start;
+ uint32_t end;
+};
+
+/* Get Device from resource pointer */
+#define RES2DEV(res) ((struct pci_dev *) \
+ ((void *)res - (res->bar * (sizeof(struct pci_res)))))
+
+/* Device flags */
+#define PCI_DEV_BRIDGE 0x01 /* Device is a Bridge (struct pci_bus) */
+#define PCI_DEV_RES_FAIL 0x02 /* Resource alloction for device BARs failed */
+
+/* Bus Flags */
+#define PCI_BUS_IO 0x01 /* 16-bit I/O address decoding */
+#define PCI_BUS_MEMIO 0x02 /* Bus support non-prefetchable mem (always) */
+#define PCI_BUS_MEM 0x04 /* Bus support prefetchable memory space */
+#define PCI_BUS_IO32 0x08 /* 32-bit I/O address decoding */
+
+#define BRIDGE_RES_COUNT 2 /* Number of BAR resources a bridge can have */
+#define BUS_RES_START BRIDGE_RES_COUNT
+
+/* Bus Resources Array */
+enum {
+ BUS_RES_IO = 0,
+ BUS_RES_MEMIO = 1,
+ BUS_RES_MEM = 2,
+};
+
+/* Device Resource array index meaning */
+enum {
+ /* A Device has up to 6 BARs and an optional ROM BAR */
+ DEV_RES_BAR1 = 0,
+ DEV_RES_BAR2 = 1,
+ DEV_RES_BAR3 = 2,
+ DEV_RES_BAR4 = 3,
+ DEV_RES_BAR5 = 4,
+ DEV_RES_BAR6 = 5,
+ DEV_RES_ROM = 6,
+
+ /* Bridges have 2 BARs (BAR1 and BAR2) and 3 Windows to secondary bus
+ * and an optional ROM BAR
+ */
+ BRIDGE_RES_BAR1 = 0,
+ BRIDGE_RES_BAR2 = 1,
+ BRIDGE_RES_IO = 2,
+ BRIDGE_RES_MEMIO = 3,
+ BRIDGE_RES_MEM = 4,
+ BRIDGE_RES_UNUSED1 = 5,
+ BRIDGE_RES_ROM = 6,
+};
+
+/* Maximum Number of Resources of a device */
+#define DEV_RES_CNT (DEV_RES_ROM + 1)
+
+/* PCI Device (Bus|Slot|Function) description */
+struct pci_dev {
+ struct pci_res resources[DEV_RES_CNT]; /* must be topmost field */
+ struct pci_dev *next;
+ struct pci_bus *bus;
+ pci_dev_t busdevfun;
+ uint8_t flags;
+ uint8_t sysirq;
+ uint16_t vendor;
+ uint16_t device;
+ uint16_t subvendor;
+ uint16_t subdevice;
+ uint32_t classrev;
+
+ /* static configuration settings */
+ uint16_t command;
+};
+
+/* PCI Bus description */
+struct pci_bus {
+ struct pci_dev dev; /* PCI Bridge */
+ struct pci_dev *devs; /* Devices on child (secondary) Bus */
+ unsigned int flags;
+
+ /* Bridge Information */
+ int num; /* Bus number (0=Root-PCI-bus) */
+ int pri; /* Primary Bus Number */
+ int sord; /* Subordinate Buses (Child bus count) */
+
+#if defined(PCI_CFG_AUTO_LIB)
+ /* Resources of devices on bus. USED INTERNALLY IN AUTO-CFG LIBRARY.
+ *
+ * BUS_RES_IO = 0: I/O resources
+ * BUS_RES_MEMIO = 1: Prefetchable memory resources
+ * BUS_RES_MEM = 2: Non-Prefetchable memory resources
+ */
+ struct pci_res *busres[3];
+#endif
+};
+
+#include <pci/cfg_auto.h>
+#include <pci/cfg_static.h>
+#include <pci/cfg_read.h>
+#include <pci/cfg_peripheral.h>
+
+#endif
diff --git a/cpukit/libpci/pci/cfg_auto.h b/cpukit/libpci/pci/cfg_auto.h
new file mode 100644
index 0000000000..aa55f501f6
--- /dev/null
+++ b/cpukit/libpci/pci/cfg_auto.h
@@ -0,0 +1,51 @@
+/* PCI Auto Configuration Library */
+
+#ifndef __PCI_CFG_AUTO_H__
+#define __PCI_CFG_AUTO_H__
+
+#define CFGOPT_NOSETUP_IRQ 0x1 /* Skip IRQ setup */
+
+/* PCI Memory Layout setup, used by the auto-config library in order to
+ * determine the addresses of PCI BARs and Buses.
+ *
+ * All addresses are in PCI address space, the actual address the CPU access
+ * may be different, and taken care of elsewhere.
+ */
+struct pci_auto_setup {
+ int options;
+
+ /* PCI prefetchable Memory space (OPTIONAL) */
+ uint32_t mem_start;
+ uint32_t mem_size; /* 0 = Use MEMIO space for prefetchable mem BARs */
+
+ /* PCI non-prefetchable Memory */
+ uint32_t memio_start;
+ uint32_t memio_size;
+
+ /* PCI I/O space (OPTIONAL) */
+ uint32_t io_start;
+ uint32_t io_size; /* 0 = No I/O space */
+
+ /* Get System IRQ connected to a PCI line of a PCI device on bus0.
+ * The return IRQ value zero equals no IRQ (IRQ disabled).
+ */
+ uint8_t (*irq_map)(pci_dev_t dev, int irq_pin);
+
+ /* IRQ Bridge routing. Returns the interrupt pin (0..3 = A..D) that
+ * a device is connected to on parent bus.
+ */
+ int (*irq_route)(pci_dev_t dev, int irq_pin);
+};
+
+/* Do PCI initialization: Enumrate buses, scan buses for devices, assign
+ * I/O MEM and MEMIO resources, assign IRQ and so on.
+ */
+extern int pci_config_auto(void);
+
+/* Register a configuration for the auto library (struct pci_auto_setup *) */
+extern void pci_config_auto_register(void *config);
+
+/* PCI memory map */
+extern struct pci_auto_setup pci_auto_cfg;
+
+#endif
diff --git a/cpukit/libpci/pci/cfg_peripheral.h b/cpukit/libpci/pci/cfg_peripheral.h
new file mode 100644
index 0000000000..f54121d40c
--- /dev/null
+++ b/cpukit/libpci/pci/cfg_peripheral.h
@@ -0,0 +1,12 @@
+/* PCI Peripheral Configuration Library */
+
+#ifndef __PCI_CFG_PERIPHERAL_H__
+#define __PCI_CFG_PERIPHERAL_H__
+
+/* The user must provide a PCI configuration using the "struct pci_bus pci_hb"
+ * structure. Nothing else than setting pci_system_type and pci_bus_cnt is done
+ * by the peripheral library.
+ */
+extern int pci_config_peripheral(void);
+
+#endif
diff --git a/cpukit/libpci/pci/cfg_read.h b/cpukit/libpci/pci/cfg_read.h
new file mode 100644
index 0000000000..09fe354736
--- /dev/null
+++ b/cpukit/libpci/pci/cfg_read.h
@@ -0,0 +1,14 @@
+/* PCI Read Configuration Library. Read current config that bootloader/BIOS
+ * has setup.
+ */
+
+#ifndef __PCI_CFG_READ_H__
+#define __PCI_CFG_READ_H__
+
+/* Build PCI device tree in "struct pci_bus pci_hb" according to current setup
+ * in hardware. Devices/buses are created by reading the resource assignments
+ * that the BIOS/bootloader has already setup for us.
+ */
+extern int pci_config_read(void);
+
+#endif
diff --git a/cpukit/libpci/pci/cfg_static.h b/cpukit/libpci/pci/cfg_static.h
new file mode 100644
index 0000000000..7d305c32aa
--- /dev/null
+++ b/cpukit/libpci/pci/cfg_static.h
@@ -0,0 +1,14 @@
+/* Static PCI Auto Configuration Library */
+
+#ifndef __PCI_CFG_STATIC_H__
+#define __PCI_CFG_STATIC_H__
+
+/* This function initializes all buses and device accorind to a user defined
+ * "static" configuration. The configuration can manually created with C
+ * data structures. Or it can be automatically created on a running target
+ * using the pci_cfg_print() routine after the AUTO or READ Configuration
+ * Library has setup the PCI bus
+ */
+extern int pci_config_static(void);
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/include/pci.h b/cpukit/libpci/pci/ids.h
index 35259fb2b8..2d2592bc03 100644
--- a/c/src/lib/libbsp/sparc/shared/include/pci.h
+++ b/cpukit/libpci/pci/ids.h
@@ -1,276 +1,12 @@
-/*
- *
- * PCI defines and function prototypes
- * Copyright 1994, Drew Eckhardt
- * Copyright 1997, 1998 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
- *
- * For more information, please consult the following manuals (look at
- * http://www.pcisig.com/ for how to get them):
- *
- * PCI BIOS Specification
- * PCI Local Bus Specification
- * PCI to PCI Bridge Specification
- * PCI System Design Guide
- *
- * pci.h,v 1.2.4.2 2004/11/10 22:15:01 joel Exp
- */
-
-#ifndef RTEMS_PCI_H
-#define RTEMS_PCI_H
+/* PCI Identifiers - auto generated */
+#ifndef __PCI_IDS_H__
+#define __PCI_IDS_H__
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * Under PCI, each device has 256 bytes of configuration address space,
- * of which the first 64 bytes are standardized as follows:
- */
-#define PCI_VENDOR_ID 0x00 /* 16 bits */
-#define PCI_DEVICE_ID 0x02 /* 16 bits */
-#define PCI_COMMAND 0x04 /* 16 bits */
-#define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */
-#define PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */
-#define PCI_COMMAND_MASTER 0x4 /* Enable bus mastering */
-#define PCI_COMMAND_SPECIAL 0x8 /* Enable response to special cycles */
-#define PCI_COMMAND_INVALIDATE 0x10 /* Use memory write and invalidate */
-#define PCI_COMMAND_VGA_PALETTE 0x20 /* Enable palette snooping */
-#define PCI_COMMAND_PARITY 0x40 /* Enable parity checking */
-#define PCI_COMMAND_WAIT 0x80 /* Enable address/data stepping */
-#define PCI_COMMAND_SERR 0x100 /* Enable SERR */
-#define PCI_COMMAND_FAST_BACK 0x200 /* Enable back-to-back writes */
-
-#define PCI_STATUS 0x06 /* 16 bits */
-#define PCI_STATUS_66MHZ 0x20 /* Support 66 Mhz PCI 2.1 bus */
-#define PCI_STATUS_UDF 0x40 /* Support User Definable Features */
-
-#define PCI_STATUS_FAST_BACK 0x80 /* Accept fast-back to back */
-#define PCI_STATUS_PARITY 0x100 /* Detected parity error */
-#define PCI_STATUS_DEVSEL_MASK 0x600 /* DEVSEL timing */
-#define PCI_STATUS_DEVSEL_FAST 0x000
-#define PCI_STATUS_DEVSEL_MEDIUM 0x200
-#define PCI_STATUS_DEVSEL_SLOW 0x400
-#define PCI_STATUS_SIG_TARGET_ABORT 0x800 /* Set on target abort */
-#define PCI_STATUS_REC_TARGET_ABORT 0x1000 /* Master ack of " */
-#define PCI_STATUS_REC_MASTER_ABORT 0x2000 /* Set on master abort */
-#define PCI_STATUS_SIG_SYSTEM_ERROR 0x4000 /* Set when we drive SERR */
-#define PCI_STATUS_DETECTED_PARITY 0x8000 /* Set on parity error */
-
-#define PCI_CLASS_REVISION 0x08 /* High 24 bits are class, low 8
- revision */
-#define PCI_REVISION_ID 0x08 /* Revision ID */
-#define PCI_CLASS_PROG 0x09 /* Reg. Level Programming Interface */
-#define PCI_CLASS_DEVICE 0x0a /* Device class */
-
-#define PCI_CACHE_LINE_SIZE 0x0c /* 8 bits */
-#define PCI_LATENCY_TIMER 0x0d /* 8 bits */
-#define PCI_HEADER_TYPE 0x0e /* 8 bits */
-#define PCI_HEADER_TYPE_NORMAL 0
-#define PCI_HEADER_TYPE_BRIDGE 1
-#define PCI_HEADER_TYPE_CARDBUS 2
-
-#define PCI_BIST 0x0f /* 8 bits */
-#define PCI_BIST_CODE_MASK 0x0f /* Return result */
-#define PCI_BIST_START 0x40 /* 1 to start BIST, 2 secs or less */
-#define PCI_BIST_CAPABLE 0x80 /* 1 if BIST capable */
+/* Include non-public PCI ids (not auto generated) */
+#include <pci/ids_extra.h>
-/*
- * Base addresses specify locations in memory or I/O space.
- * Decoded size can be determined by writing a value of
- * 0xffffffff to the register, and reading it back. Only
- * 1 bits are decoded.
- */
-#define PCI_BASE_ADDRESS_0 0x10 /* 32 bits */
-#define PCI_BASE_ADDRESS_1 0x14 /* 32 bits [htype 0,1 only] */
-#define PCI_BASE_ADDRESS_2 0x18 /* 32 bits [htype 0 only] */
-#define PCI_BASE_ADDRESS_3 0x1c /* 32 bits */
-#define PCI_BASE_ADDRESS_4 0x20 /* 32 bits */
-#define PCI_BASE_ADDRESS_5 0x24 /* 32 bits */
-#define PCI_BASE_ADDRESS_SPACE 0x01 /* 0 = memory, 1 = I/O */
-#define PCI_BASE_ADDRESS_SPACE_IO 0x01
-#define PCI_BASE_ADDRESS_SPACE_MEMORY 0x00
-#define PCI_BASE_ADDRESS_MEM_TYPE_MASK 0x06
-#define PCI_BASE_ADDRESS_MEM_TYPE_32 0x00 /* 32 bit address */
-#define PCI_BASE_ADDRESS_MEM_TYPE_1M 0x02 /* Below 1M */
-#define PCI_BASE_ADDRESS_MEM_TYPE_64 0x04 /* 64 bit address */
-#define PCI_BASE_ADDRESS_MEM_PREFETCH 0x08 /* prefetchable? */
-#define PCI_BASE_ADDRESS_MEM_MASK (~0x0fUL)
-#define PCI_BASE_ADDRESS_IO_MASK (~0x03UL)
-/* bit 1 is reserved if address_space = 1 */
-
-/* Header type 0 (normal devices) */
-#define PCI_CARDBUS_CIS 0x28
-#define PCI_SUBSYSTEM_VENDOR_ID 0x2c
-#define PCI_SUBSYSTEM_ID 0x2e
-#define PCI_ROM_ADDRESS 0x30 /* Bits 31..11 are address, 10..1 reserved */
-#define PCI_ROM_ADDRESS_ENABLE 0x01
-#define PCI_ROM_ADDRESS_MASK (~0x7ffUL)
-
-/* 0x34-0x3b are reserved */
-#define PCI_INTERRUPT_LINE 0x3c /* 8 bits */
-#define PCI_INTERRUPT_PIN 0x3d /* 8 bits */
-#define PCI_MIN_GNT 0x3e /* 8 bits */
-#define PCI_MAX_LAT 0x3f /* 8 bits */
-
-/* Header type 1 (PCI-to-PCI bridges) */
-#define PCI_PRIMARY_BUS 0x18 /* Primary bus number */
-#define PCI_SECONDARY_BUS 0x19 /* Secondary bus number */
-#define PCI_SUBORDINATE_BUS 0x1a /* Highest bus number behind the bridge */
-#define PCI_SEC_LATENCY_TIMER 0x1b /* Latency timer for secondary interface */
-#define PCI_IO_BASE 0x1c /* I/O range behind the bridge */
-#define PCI_IO_LIMIT 0x1d
-#define PCI_IO_RANGE_TYPE_MASK 0x0f /* I/O bridging type */
-#define PCI_IO_RANGE_TYPE_16 0x00
-#define PCI_IO_RANGE_TYPE_32 0x01
-#define PCI_IO_RANGE_MASK ~0x0f
-#define PCI_SEC_STATUS 0x1e /* Secondary status register, only bit 14 used */
-#define PCI_MEMORY_BASE 0x20 /* Memory range behind */
-#define PCI_MEMORY_LIMIT 0x22
-#define PCI_MEMORY_RANGE_TYPE_MASK 0x0f
-#define PCI_MEMORY_RANGE_MASK ~0x0f
-#define PCI_PREF_MEMORY_BASE 0x24 /* Prefetchable memory range behind */
-#define PCI_PREF_MEMORY_LIMIT 0x26
-#define PCI_PREF_RANGE_TYPE_MASK 0x0f
-#define PCI_PREF_RANGE_TYPE_32 0x00
-#define PCI_PREF_RANGE_TYPE_64 0x01
-#define PCI_PREF_RANGE_MASK ~0x0f
-#define PCI_PREF_BASE_UPPER32 0x28 /* Upper half of prefetchable memory range */
-#define PCI_PREF_LIMIT_UPPER32 0x2c
-#define PCI_IO_BASE_UPPER16 0x30 /* Upper half of I/O addresses */
-#define PCI_IO_LIMIT_UPPER16 0x32
-/* 0x34-0x3b is reserved */
-#define PCI_ROM_ADDRESS1 0x38 /* Same as PCI_ROM_ADDRESS, but for htype 1 */
-/* 0x3c-0x3d are same as for htype 0 */
-#define PCI_BRIDGE_CONTROL 0x3e
-#define PCI_BRIDGE_CTL_PARITY 0x01 /* Enable parity detection on secondary interface */
-#define PCI_BRIDGE_CTL_SERR 0x02 /* The same for SERR forwarding */
-#define PCI_BRIDGE_CTL_NO_ISA 0x04 /* Disable bridging of ISA ports */
-#define PCI_BRIDGE_CTL_VGA 0x08 /* Forward VGA addresses */
-#define PCI_BRIDGE_CTL_MASTER_ABORT 0x20 /* Report master aborts */
-#define PCI_BRIDGE_CTL_BUS_RESET 0x40 /* Secondary bus reset */
-#define PCI_BRIDGE_CTL_FAST_BACK 0x80 /* Fast Back2Back enabled on secondary interface */
-
-/* Header type 2 (CardBus bridges) */
-/* 0x14-0x15 reserved */
-#define PCI_CB_SEC_STATUS 0x16 /* Secondary status */
-#define PCI_CB_PRIMARY_BUS 0x18 /* PCI bus number */
-#define PCI_CB_CARD_BUS 0x19 /* CardBus bus number */
-#define PCI_CB_SUBORDINATE_BUS 0x1a /* Subordinate bus number */
-#define PCI_CB_LATENCY_TIMER 0x1b /* CardBus latency timer */
-#define PCI_CB_MEMORY_BASE_0 0x1c
-#define PCI_CB_MEMORY_LIMIT_0 0x20
-#define PCI_CB_MEMORY_BASE_1 0x24
-#define PCI_CB_MEMORY_LIMIT_1 0x28
-#define PCI_CB_IO_BASE_0 0x2c
-#define PCI_CB_IO_BASE_0_HI 0x2e
-#define PCI_CB_IO_LIMIT_0 0x30
-#define PCI_CB_IO_LIMIT_0_HI 0x32
-#define PCI_CB_IO_BASE_1 0x34
-#define PCI_CB_IO_BASE_1_HI 0x36
-#define PCI_CB_IO_LIMIT_1 0x38
-#define PCI_CB_IO_LIMIT_1_HI 0x3a
-#define PCI_CB_IO_RANGE_MASK ~0x03
-/* 0x3c-0x3d are same as for htype 0 */
-#define PCI_CB_BRIDGE_CONTROL 0x3e
-#define PCI_CB_BRIDGE_CTL_PARITY 0x01 /* Similar to standard bridge control register */
-#define PCI_CB_BRIDGE_CTL_SERR 0x02
-#define PCI_CB_BRIDGE_CTL_ISA 0x04
-#define PCI_CB_BRIDGE_CTL_VGA 0x08
-#define PCI_CB_BRIDGE_CTL_MASTER_ABORT 0x20
-#define PCI_CB_BRIDGE_CTL_CB_RESET 0x40 /* CardBus reset */
-#define PCI_CB_BRIDGE_CTL_16BIT_INT 0x80 /* Enable interrupt for 16-bit cards */
-#define PCI_CB_BRIDGE_CTL_PREFETCH_MEM0 0x100 /* Prefetch enable for both memory regions */
-#define PCI_CB_BRIDGE_CTL_PREFETCH_MEM1 0x200
-#define PCI_CB_BRIDGE_CTL_POST_WRITES 0x400
-#define PCI_CB_SUBSYSTEM_VENDOR_ID 0x40
-#define PCI_CB_SUBSYSTEM_ID 0x42
-#define PCI_CB_LEGACY_MODE_BASE 0x44 /* 16-bit PC Card legacy mode base address (ExCa) */
-/* 0x48-0x7f reserved */
-
-/* Device classes and subclasses */
-
-#define PCI_CLASS_NOT_DEFINED 0x0000
-#define PCI_CLASS_NOT_DEFINED_VGA 0x0001
-
-#define PCI_BASE_CLASS_STORAGE 0x01
-#define PCI_CLASS_STORAGE_SCSI 0x0100
-#define PCI_CLASS_STORAGE_IDE 0x0101
-#define PCI_CLASS_STORAGE_FLOPPY 0x0102
-#define PCI_CLASS_STORAGE_IPI 0x0103
-#define PCI_CLASS_STORAGE_RAID 0x0104
-#define PCI_CLASS_STORAGE_OTHER 0x0180
-
-#define PCI_BASE_CLASS_NETWORK 0x02
-#define PCI_CLASS_NETWORK_ETHERNET 0x0200
-#define PCI_CLASS_NETWORK_TOKEN_RING 0x0201
-#define PCI_CLASS_NETWORK_FDDI 0x0202
-#define PCI_CLASS_NETWORK_ATM 0x0203
-#define PCI_CLASS_NETWORK_OTHER 0x0280
-
-#define PCI_BASE_CLASS_DISPLAY 0x03
-#define PCI_CLASS_DISPLAY_VGA 0x0300
-#define PCI_CLASS_DISPLAY_XGA 0x0301
-#define PCI_CLASS_DISPLAY_OTHER 0x0380
-
-#define PCI_BASE_CLASS_MULTIMEDIA 0x04
-#define PCI_CLASS_MULTIMEDIA_VIDEO 0x0400
-#define PCI_CLASS_MULTIMEDIA_AUDIO 0x0401
-#define PCI_CLASS_MULTIMEDIA_OTHER 0x0480
-
-#define PCI_BASE_CLASS_MEMORY 0x05
-#define PCI_CLASS_MEMORY_RAM 0x0500
-#define PCI_CLASS_MEMORY_FLASH 0x0501
-#define PCI_CLASS_MEMORY_OTHER 0x0580
-
-#define PCI_BASE_CLASS_BRIDGE 0x06
-#define PCI_CLASS_BRIDGE_HOST 0x0600
-#define PCI_CLASS_BRIDGE_ISA 0x0601
-#define PCI_CLASS_BRIDGE_EISA 0x0602
-#define PCI_CLASS_BRIDGE_MC 0x0603
-#define PCI_CLASS_BRIDGE_PCI 0x0604
-#define PCI_CLASS_BRIDGE_PCMCIA 0x0605
-#define PCI_CLASS_BRIDGE_NUBUS 0x0606
-#define PCI_CLASS_BRIDGE_CARDBUS 0x0607
-#define PCI_CLASS_BRIDGE_OTHER 0x0680
-
-#define PCI_BASE_CLASS_COMMUNICATION 0x07
-#define PCI_CLASS_COMMUNICATION_SERIAL 0x0700
-#define PCI_CLASS_COMMUNICATION_PARALLEL 0x0701
-#define PCI_CLASS_COMMUNICATION_OTHER 0x0780
-
-#define PCI_BASE_CLASS_SYSTEM 0x08
-#define PCI_CLASS_SYSTEM_PIC 0x0800
-#define PCI_CLASS_SYSTEM_DMA 0x0801
-#define PCI_CLASS_SYSTEM_TIMER 0x0802
-#define PCI_CLASS_SYSTEM_RTC 0x0803
-#define PCI_CLASS_SYSTEM_OTHER 0x0880
-
-#define PCI_BASE_CLASS_INPUT 0x09
-#define PCI_CLASS_INPUT_KEYBOARD 0x0900
-#define PCI_CLASS_INPUT_PEN 0x0901
-#define PCI_CLASS_INPUT_MOUSE 0x0902
-#define PCI_CLASS_INPUT_OTHER 0x0980
-
-#define PCI_BASE_CLASS_DOCKING 0x0a
-#define PCI_CLASS_DOCKING_GENERIC 0x0a00
-#define PCI_CLASS_DOCKING_OTHER 0x0a01
-
-#define PCI_BASE_CLASS_PROCESSOR 0x0b
-#define PCI_CLASS_PROCESSOR_386 0x0b00
-#define PCI_CLASS_PROCESSOR_486 0x0b01
-#define PCI_CLASS_PROCESSOR_PENTIUM 0x0b02
-#define PCI_CLASS_PROCESSOR_ALPHA 0x0b10
-#define PCI_CLASS_PROCESSOR_POWERPC 0x0b20
-#define PCI_CLASS_PROCESSOR_CO 0x0b40
-
-#define PCI_BASE_CLASS_SERIAL 0x0c
-#define PCI_CLASS_SERIAL_FIREWIRE 0x0c00
-#define PCI_CLASS_SERIAL_ACCESS 0x0c01
-#define PCI_CLASS_SERIAL_SSA 0x0c02
-#define PCI_CLASS_SERIAL_USB 0x0c03
-#define PCI_CLASS_SERIAL_FIBER 0x0c04
-
-#define PCI_CLASS_OTHERS 0xff
+/* Not a valid ID, used to match any device ID */
+#define PCI_ID_ANY 0xffff
/*
* Vendor and card ID's: sort these numerically according to vendor
@@ -1063,117 +799,4 @@ extern "C" {
#define PCI_DEVICE_ID_ARK_STINGARK 0xa099
#define PCI_DEVICE_ID_ARK_2000MT 0xa0a1
-/*
- * The PCI interface treats multi-function devices as independent
- * devices. The slot/function address of each device is encoded
- * in a single byte as follows:
- *
- * 7:3 = slot
- * 2:0 = function
- */
-#define PCI_DEVFN(slot,func) ((((slot) & 0x1f) << 3) | ((func) & 0x07))
-#define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f)
-#define PCI_FUNC(devfn) ((devfn) & 0x07)
-
-/*
- * Error values that may be returned by the PCI bios.
- */
-#define PCIBIOS_SUCCESSFUL 0x00
-#define PCIBIOS_FUNC_NOT_SUPPORTED 0x81
-#define PCIBIOS_BAD_VENDOR_ID 0x83
-#define PCIBIOS_DEVICE_NOT_FOUND 0x86
-#define PCIBIOS_BAD_REGISTER_NUMBER 0x87
-#define PCIBIOS_SET_FAILED 0x88
-#define PCIBIOS_BUFFER_TOO_SMALL 0x89
-
-/* T. Straumann, 7/31/2001: increased to 32 - PMC slots are not
- * scanned on mvme2306 otherwise
- */
-#define PCI_MAX_DEVICES 32
-#define PCI_MAX_FUNCTIONS 8
-
-typedef struct {
- int (*read_config_byte)(unsigned char, unsigned char, unsigned char,
- unsigned char, unsigned char *);
- int (*read_config_word)(unsigned char, unsigned char, unsigned char,
- unsigned char, unsigned short *);
- int (*read_config_dword)(unsigned char, unsigned char, unsigned char,
- unsigned char, unsigned int *);
- int (*write_config_byte)(unsigned char, unsigned char, unsigned char,
- unsigned char, unsigned char);
- int (*write_config_word)(unsigned char, unsigned char, unsigned char,
- unsigned char, unsigned short);
- int (*write_config_dword)(unsigned char, unsigned char, unsigned char,
- unsigned char, unsigned int);
-} pci_config_access_functions;
-
-typedef struct {
- volatile unsigned char* pci_config_addr;
- volatile unsigned char* pci_config_data;
- const pci_config_access_functions* pci_functions;
-} rtems_pci_config_t;
-
-extern rtems_pci_config_t BSP_pci_configuration;
-
-extern inline int
-pci_read_config_byte(unsigned char bus, unsigned char slot, unsigned char function,
- unsigned char where, unsigned char * val) {
- return BSP_pci_configuration.pci_functions->read_config_byte(bus, slot, function, where, val);
-}
-
-extern inline int
-pci_read_config_word(unsigned char bus, unsigned char slot, unsigned char function,
- unsigned char where, unsigned short * val) {
- return BSP_pci_configuration.pci_functions->read_config_word(bus, slot, function, where, val);
-}
-
-extern inline int
-pci_read_config_dword(unsigned char bus, unsigned char slot, unsigned char function,
- unsigned char where, unsigned int * val) {
- return BSP_pci_configuration.pci_functions->read_config_dword(bus, slot, function, where, val);
-}
-
-extern inline int
-pci_write_config_byte(unsigned char bus, unsigned char slot, unsigned char function,
- unsigned char where, unsigned char val) {
- return BSP_pci_configuration.pci_functions->write_config_byte(bus, slot, function, where, val);
-}
-
-extern inline int
-pci_write_config_word(unsigned char bus, unsigned char slot, unsigned char function,
- unsigned char where, unsigned short val) {
- return BSP_pci_configuration.pci_functions->write_config_word(bus, slot, function, where, val);
-}
-
-extern inline int
-pci_write_config_dword(unsigned char bus, unsigned char slot, unsigned char function,
- unsigned char where, unsigned int val) {
- return BSP_pci_configuration.pci_functions->write_config_dword(bus, slot, function, where, val);
-}
-
-/*
- * Return the number of PCI busses in the system
- */
-extern unsigned char BusCountPCI(void);
-extern int init_pci(void);
-
-extern int dma_to_pci(unsigned int addr, unsigned int paddr, unsigned int len);
-extern int dma_from_pci(unsigned int addr, unsigned int paddr, unsigned int len);
-extern void pci_mem_enable(unsigned char bus, unsigned char slot, unsigned char function);
-extern void pci_master_enable(unsigned char bus, unsigned char slot, unsigned char function);
-
-/* scan for a specific device */
-/* find a particular PCI device
- * (currently, only bus0 is scanned for device/fun0)
- *
- * RETURNS: zero on success, bus/dev/fun in *pbus / *pdev / *pfun
- */
-int
-BSP_pciFindDevice(unsigned short vendorid, unsigned short deviceid,
- int instance, int *pbus, int *pdev, int *pfun);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* RTEMS_PCI_H */
+#endif /* !__PCI_IDS_H__ */
diff --git a/cpukit/libpci/pci/ids_extra.h b/cpukit/libpci/pci/ids_extra.h
new file mode 100644
index 0000000000..ffa18cb271
--- /dev/null
+++ b/cpukit/libpci/pci/ids_extra.h
@@ -0,0 +1,19 @@
+/* RTEMS local PCI data base */
+
+/* Only included from pci_ids.h */
+#ifndef __PCI_IDS_H__
+#error pci/ids_extra.h should only be included from pci/ids.h
+#endif
+
+/* Gaisler PCI IDs */
+#define PCIID_VENDOR_GAISLER 0x1AC8
+#define PCIID_VENDOR_GAISLER_OLD 0x16E3
+
+/* Gaisler PCI Devices */
+#define PCIID_DEVICE_GR_RASTA_IO 0x0010 /* GR-RASTA-IO */
+#define PCIID_DEVICE_GR_RASTA_IO_OLD 0x0210 /* old GR-RASTA-IO ID*/
+#define PCIID_DEVICE_GR_RASTA_TMTC 0x0011 /* GR-RASTA-TMTC */
+#define PCIID_DEVICE_GR_RASTA_ADCDAC 0x0014 /* GR-RASTA-ADCDAC */
+#define PCIID_DEVICE_GR_701 0x0701 /* GR-701 */
+#define PCIID_DEVICE_GR_TMTC_1553 0x0198 /* GR-TMTC-1553 */
+#define PCIID_DEVICE_GR_RASTA_SPW_RTR 0x0062 /* GR-RASTA-SPW-ROUTER */
diff --git a/cpukit/libpci/pci/irq.h b/cpukit/libpci/pci/irq.h
new file mode 100644
index 0000000000..87ca154073
--- /dev/null
+++ b/cpukit/libpci/pci/irq.h
@@ -0,0 +1,98 @@
+/* PCI IRQ Library
+ *
+ * IRQ handling does not have so much with PCI to do, this library depends
+ * on the BSP to implement shared interrupts.
+ */
+
+#ifndef __PCI_IRQ_H__
+#define __PCI_IRQ_H__
+
+#include <bsp.h>
+
+/* PCI Handler (ISR) called when IRQ is generated by any of the PCI devices
+ * connected to the same PCI IRQ Pin. This is been defined the same way as
+ * rtems_interrupt_handler in order for BSPs to "direct-map" the register
+ * and unregister functions rtems_interrupt_handler_install/remove
+ */
+typedef void (*pci_isr)(void *arg);
+
+/* Get assigned system IRQ to a PCI Device. If no IRQ 0 is returned */
+extern int pci_dev_irq(pci_dev_t dev);
+
+/* Register shared PCI IRQ handler, but does not enable it. The system interrupt
+ * number is read from the PCI board's PCI configuration space header iline
+ * field. The iline field is initialized by the PCI subsystem during start up,
+ * the ipin field is translated into a system IRQ and written to iline. The
+ * board's driver should use the iline field as the irq argument to this
+ * function.
+ *
+ * Arguments
+ * irq System IRQ number, normally taken from the PCI configuration area
+ * isr Function pointer to the ISR
+ * arg Second argument to function isr
+ */
+static inline int pci_interrupt_register(int irq, const char *info,
+ pci_isr isr, void *arg)
+{
+ return BSP_PCI_shared_interrupt_register(irq, info, isr, arg);
+}
+
+/* Unregister previously registered shared PCI IRQ handler
+ *
+ * Arguments
+ * irq System IRQ number, normally taken from the PCI configuration area
+ * isr Function pointer to the ISR
+ * arg Second argument to function isr
+ */
+static inline int pci_interrupt_unregister(int irq, pci_isr isr, void *arg)
+{
+ return BSP_PCI_shared_interrupt_unregister(irq, isr, arg);
+}
+
+/* Enable shared PCI IRQ handler. This function will unmask the interrupt
+ * controller and mark this interrupt handler ready to handle interrupts. Note
+ * that since it is a shared interrupt handler service the interrupt may
+ * already be enabled, however no calls to this specific handler is made
+ * until it is enabled.
+ *
+ * Arguments
+ * irq System IRQ number, normally taken from the PCI configuration area
+ * isr Function pointer to the ISR
+ * arg Second argument to function isr
+ */
+static inline void pci_interrupt_unmask(int irq)
+{
+ BSP_PCI_shared_interrupt_unmask(irq);
+}
+
+/* Disable shared PCI IRQ handler. This function will mask the interrupt
+ * controller and mark this interrupt handler not ready to receive interrupts.
+ * Note that since it is a shared interrupt handler service the interrupt may
+ * still be enabled, however no calls to this specific handler is made
+ * while it is disabled.
+ *
+ * Arguments
+ * irq System IRQ number, normally taken from the PCI configuration area
+ * isr Function pointer to the ISR
+ * arg Second argument to function isr
+ */
+static inline void pci_interrupt_mask(int irq)
+{
+ BSP_PCI_shared_interrupt_mask(irq);
+}
+
+/* Acknowledge the interrupt controller by writing to the interrupt controller.
+ * Note that since it is a shared interrupt handler service, clearing the
+ * interrupt source may affect other ISRs registered to this IRQ.
+ *
+ * Arguments
+ * irq System IRQ number, normally taken from the PCI configuration area
+ * isr Function pointer to the ISR
+ * arg Second argument to function isr
+ */
+static inline void pci_interrupt_clear(int irq)
+{
+ BSP_PCI_shared_interrupt_clear(irq);
+}
+
+#endif /* !__PCI_IRQ_H__ */
diff --git a/cpukit/libpci/pci_access.c b/cpukit/libpci/pci_access.c
new file mode 100644
index 0000000000..bf14328e06
--- /dev/null
+++ b/cpukit/libpci/pci_access.c
@@ -0,0 +1,77 @@
+/* PCI Access Library
+ *
+ * COPYRIGHT (c) 2010-2011.
+ * Aeroflex Gaisler Research
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2011-02-11, Daniel Hellstrom <daniel@gaisler.com>
+ * created
+ */
+
+#include <pci.h>
+#include <pci/access.h>
+
+/* Access Routines valid after a PCI-Access-Driver has registered */
+struct pci_access_drv pci_access_ops = {
+ .cfg = {.read8 = 0},
+};
+
+/* Read a 8-bit register over configuration space */
+int pci_cfg_r8(pci_dev_t dev, int ofs, uint8_t *data)
+{
+ return pci_access_ops.cfg.read8(dev, ofs, data);
+}
+
+/* Read a 16-bit register over configuration space */
+int pci_cfg_r16(pci_dev_t dev, int ofs, uint16_t *data)
+{
+ return pci_access_ops.cfg.read16(dev, ofs, data);
+}
+
+/* Read a 32-bit register over configuration space */
+int pci_cfg_r32(pci_dev_t dev, int ofs, uint32_t *data)
+{
+ return pci_access_ops.cfg.read32(dev, ofs, data);
+}
+
+/* Write a 8-bit register over configuration space */
+int pci_cfg_w8(pci_dev_t dev, int ofs, uint8_t data)
+{
+ return pci_access_ops.cfg.write8(dev, ofs, data);
+}
+
+/* Write a 16-bit register over configuration space */
+int pci_cfg_w16(pci_dev_t dev, int ofs, uint16_t data)
+{
+ return pci_access_ops.cfg.write16(dev, ofs, data);
+}
+
+/* Write a 32-bit register over configuration space */
+int pci_cfg_w32(pci_dev_t dev, int ofs, uint32_t data)
+{
+ return pci_access_ops.cfg.write32(dev, ofs, data);
+}
+
+void pci_modify_cmdsts(pci_dev_t dev, uint32_t mask, uint32_t val)
+{
+ uint32_t data;
+
+ pci_cfg_r32(dev, PCI_COMMAND, &data);
+ data &= ~mask;
+ data |= val;
+ pci_cfg_w32(dev, PCI_COMMAND, data);
+}
+
+/* Register a driver for handling access to PCI */
+int pci_access_drv_register(struct pci_access_drv *drv)
+{
+ if (pci_access_ops.cfg.read8)
+ return -1; /* Already registered a driver.. */
+
+ pci_access_ops = *drv;
+
+ return 0;
+}
diff --git a/cpukit/libpci/pci_access_func.c b/cpukit/libpci/pci_access_func.c
new file mode 100644
index 0000000000..5ef1a4d223
--- /dev/null
+++ b/cpukit/libpci/pci_access_func.c
@@ -0,0 +1,63 @@
+#include <pci.h>
+
+/* Get PCI I/O or Configuration space access function */
+static int pci_ioc_func(int wr, int size, void **func, void **ops)
+{
+ int ofs;
+
+ ofs = 0;
+ if (wr)
+ ofs += 3;
+ if (size == 4)
+ size = 3;
+ ofs += (size & 0x3) - 1;
+ if (ops[ofs] == NULL)
+ return -1;
+ if (func)
+ *func = ops[ofs];
+ return 0;
+}
+
+/* Get Registers-over-Memory Space access function */
+static int pci_memreg_func(int wr, int size, void **func, int endian)
+{
+ void **ops;
+ int ofs = 0;
+
+ ops = (void **)pci_access_ops.memreg;
+ if (!ops)
+ return -1;
+
+ if (size == 2)
+ ofs += 2;
+ else if (size == 4)
+ ofs += 6;
+
+ if (size != 1 && endian == PCI_BIG_ENDIAN)
+ ofs += 2;
+
+ if (wr)
+ ofs += 1;
+
+ if (ops[ofs] == NULL)
+ return -1;
+ if (func)
+ *func = ops[ofs];
+ return 0;
+}
+
+/* Get function pointer from Host/BSP driver definitions */
+int pci_access_func(int wr, int size, void **func, int endian, int type)
+{
+ switch (type) {
+ default:
+ case 2: /* Memory Space - not implemented */
+ return -1;
+ case 1: /* I/O space */
+ return pci_ioc_func(wr, size, func, (void**)&pci_access_ops.cfg);
+ case 3: /* Registers over Memory space */
+ return pci_memreg_func(wr, size, func, endian);
+ case 4: /* Configuration space */
+ return pci_ioc_func(wr, size, func, (void**)&pci_access_ops.io);
+ }
+}
diff --git a/cpukit/libpci/pci_access_io.c b/cpukit/libpci/pci_access_io.c
new file mode 100644
index 0000000000..4413aee3e1
--- /dev/null
+++ b/cpukit/libpci/pci_access_io.c
@@ -0,0 +1,51 @@
+/* PCI Access Library
+ *
+ * COPYRIGHT (c) 2010-2011.
+ * Aeroflex Gaisler Research
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2011-02-11, Daniel Hellstrom <daniel@gaisler.com>
+ * created
+ */
+
+#include <pci.h>
+#include <pci/access.h>
+
+/* Read a 8-bit register over PCI I/O Space */
+uint8_t pci_io_r8(uint32_t adr)
+{
+ return pci_access_ops.io.read8((uint8_t *)adr);
+}
+
+/* Read a 16-bit I/O Register */
+uint16_t pci_io_r16(uint32_t adr)
+{
+ return pci_access_ops.io.read16((uint16_t *)adr);
+}
+
+/* Read a 32-bit I/O Register */
+uint32_t pci_io_r32(uint32_t adr)
+{
+ return pci_access_ops.io.read32((uint32_t *)adr);
+}
+
+/* Write a 8-bit I/O Register */
+void pci_io_w8(uint32_t adr, uint8_t data)
+{
+ pci_access_ops.io.write8((uint8_t *)adr, data);
+}
+
+/* Write a 16-bit I/O Register */
+void pci_io_w16(uint32_t adr, uint16_t data)
+{
+ pci_access_ops.io.write16((uint16_t *)adr, data);
+}
+
+/* Write a 32-bit I/O Register */
+void pci_io_w32(uint32_t adr, uint32_t data)
+{
+ pci_access_ops.io.write32((uint32_t *)adr, data);
+}
diff --git a/cpukit/libpci/pci_access_mem.c b/cpukit/libpci/pci_access_mem.c
new file mode 100644
index 0000000000..dcdd0a6a15
--- /dev/null
+++ b/cpukit/libpci/pci_access_mem.c
@@ -0,0 +1,11 @@
+#include <pci.h>
+
+uint8_t pci_mem_ld8(uint8_t *adr)
+{
+ return *adr;
+}
+
+void pci_mem_st8(uint8_t *adr, uint8_t data)
+{
+ *adr = data;
+}
diff --git a/cpukit/libpci/pci_access_mem_be.c b/cpukit/libpci/pci_access_mem_be.c
new file mode 100644
index 0000000000..0746588d13
--- /dev/null
+++ b/cpukit/libpci/pci_access_mem_be.c
@@ -0,0 +1,62 @@
+/* Registers-over-Memory Space - Generic Big endian PCI bus definitions */
+
+#include <pci.h>
+
+/* Same for Little and Big endian PCI buses */
+extern uint8_t pci_mem_ld8(uint8_t *adr);
+extern void pci_mem_st8(uint8_t *adr, uint8_t data);
+
+uint16_t pci_mem_be_ld_le16(uint16_t *adr)
+{
+ return ld_be16(adr);
+}
+
+uint16_t pci_mem_be_ld_be16(uint16_t *adr)
+{
+ return ld_le16(adr);
+}
+
+uint32_t pci_mem_be_ld_le32(uint32_t *adr)
+{
+ return ld_be32(adr);
+}
+
+uint32_t pci_mem_be_ld_be32(uint32_t *adr)
+{
+ return ld_le32(adr);
+}
+
+void pci_mem_be_st_le16(uint16_t *adr, uint16_t data)
+{
+ st_be16(adr, data);
+}
+
+void pci_mem_be_st_be16(uint16_t *adr, uint16_t data)
+{
+ st_le16(adr, data);
+}
+
+void pci_mem_be_st_le32(uint32_t *adr, uint32_t data)
+{
+ st_be32(adr, data);
+}
+
+void pci_mem_be_st_be32(uint32_t *adr, uint32_t data)
+{
+ st_le32(adr, data);
+}
+
+struct pci_memreg_ops pci_mem_be_ops = {
+ .ld8 = pci_mem_ld8,
+ .st8 = pci_mem_st8,
+
+ .ld_le16 = pci_mem_be_ld_le16,
+ .st_le16 = pci_mem_be_st_le16,
+ .ld_be16 = pci_mem_be_ld_be16,
+ .st_be16 = pci_mem_be_st_be16,
+
+ .ld_le32 = pci_mem_be_ld_le32,
+ .st_le32 = pci_mem_be_st_le32,
+ .ld_be32 = pci_mem_be_ld_be32,
+ .st_be32 = pci_mem_be_st_be32,
+};
diff --git a/cpukit/libpci/pci_access_mem_le.c b/cpukit/libpci/pci_access_mem_le.c
new file mode 100644
index 0000000000..d00e13121a
--- /dev/null
+++ b/cpukit/libpci/pci_access_mem_le.c
@@ -0,0 +1,61 @@
+/* Registers-over-Memory Space - Generic Little endian PCI bus definitions */
+
+#include <pci.h>
+
+/* Same for Little and Big endian PCI buses */
+extern uint8_t pci_mem_ld8(uint8_t *adr);
+extern void pci_mem_st8(uint8_t *adr, uint8_t data);
+
+uint16_t pci_mem_le_ld_le16(uint16_t *adr)
+{
+ return ld_le16(adr);
+}
+
+uint16_t pci_mem_le_ld_be16(uint16_t *adr)
+{
+ return ld_be16(adr);
+}
+
+uint32_t pci_mem_le_ld_le32(uint32_t *adr)
+{
+ return ld_le32(adr);
+}
+
+uint32_t pci_mem_le_ld_be32(uint32_t *adr)
+{
+ return ld_be32(adr);
+}
+
+void pci_mem_le_st_le16(uint16_t *adr, uint16_t data)
+{
+ st_le16(adr, data);
+}
+
+void pci_mem_le_st_be16(uint16_t *adr, uint16_t data)
+{
+ st_be16(adr, data);
+}
+
+void pci_mem_le_st_le32(uint32_t *adr, uint32_t data)
+{
+ st_le32(adr, data);
+}
+
+void pci_mem_le_st_be32(uint32_t *adr, uint32_t data)
+{
+ st_be32(adr, data);
+}
+
+struct pci_memreg_ops pci_mem_le_ops = {
+ .ld8 = pci_mem_ld8,
+ .st8 = pci_mem_st8,
+
+ .ld_le16 = pci_mem_le_ld_le16,
+ .st_le16 = pci_mem_le_st_le16,
+ .ld_be16 = pci_mem_le_ld_be16,
+ .st_be16 = pci_mem_le_st_be16,
+ .ld_le32 = pci_mem_le_ld_le32,
+ .st_le32 = pci_mem_le_st_le32,
+ .ld_be32 = pci_mem_le_ld_be32,
+ .st_be32 = pci_mem_le_st_be32,
+};
diff --git a/cpukit/libpci/pci_bus.c b/cpukit/libpci/pci_bus.c
new file mode 100644
index 0000000000..b8b4b8bb8d
--- /dev/null
+++ b/cpukit/libpci/pci_bus.c
@@ -0,0 +1,564 @@
+/* PCI bus driver.
+ *
+ * COPYRIGHT (c) 2008.
+ * Aeroflex Gaisler.
+ *
+ * General part of PCI Bus driver. The driver is typically
+ * initialized from the PCI host driver separating the host
+ * driver from the common parts in PCI drivers.
+ * The PCI library must be initialized before starting the
+ * PCI bus driver. The PCI library have set up BARs and
+ * assigned system IRQs for targets.
+ * This PCI bus driver rely on the PCI library (pci.c) for
+ * interrupt registeration (pci_interrupt_register) and PCI
+ * target set up.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2008-12-03, Daniel Hellstrom <daniel@gaisler.com>
+ * Created
+ *
+ */
+
+/* Use PCI Configuration libarary pci_hb RAM device structure to find devices,
+ * undefine to access PCI configuration space directly.
+ */
+#define USE_PCI_CFG_LIB
+
+/* On small systems undefine PCIBUS_INFO to avoid sprintf get dragged in */
+#define PCIBUS_INFO
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <pci.h>
+#ifdef USE_PCI_CFG_LIB
+#include <pci/cfg.h>
+#endif
+#include <pci/irq.h>
+
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/pci_bus.h>
+
+
+#define DBG(args...)
+/*#define DBG(args...) printk(args)*/
+int pcibus_bus_init1(struct drvmgr_bus *bus);
+int pcibus_unite(struct drvmgr_drv *drv, struct drvmgr_dev *dev);
+int pcibus_int_register(
+ struct drvmgr_dev *dev,
+ int index,
+ const char *info,
+ drvmgr_isr isr,
+ void *arg);
+int pcibus_int_unregister(
+ struct drvmgr_dev *dev,
+ int index,
+ drvmgr_isr isr,
+ void *arg);
+int pcibus_int_clear(
+ struct drvmgr_dev *dev,
+ int index);
+int pcibus_freq_get(
+ struct drvmgr_dev *dev,
+ int options,
+ unsigned int *freq_hz);
+
+int pcibus_get_params(struct drvmgr_dev *dev, struct drvmgr_bus_params *params);
+
+void pcibus_dev_info(
+ struct drvmgr_dev *dev,
+ void (*print_line)(void *p, char *str),
+ void *p);
+
+struct drvmgr_bus_ops pcibus_ops = {
+ .init = {
+ pcibus_bus_init1,
+ NULL,
+ NULL,
+ NULL
+ },
+ .remove = NULL,
+ .unite = pcibus_unite,
+ .int_register = pcibus_int_register,
+ .int_unregister = pcibus_int_unregister,
+#if 0
+ .int_enable = pcibus_int_enable,
+ .int_disable = pcibus_int_disable,
+#endif
+ .int_clear = pcibus_int_clear,
+ .int_mask = NULL,
+ .int_unmask = NULL,
+ .get_params = pcibus_get_params,
+ .freq_get = pcibus_freq_get,
+#ifdef PCIBUS_INFO
+ .info_dev = pcibus_dev_info,
+#endif
+};
+
+struct drvmgr_func pcibus_funcs[] = {
+ DRVMGR_FUNC(PCI_FUNC_MREG_R8, NULL),
+ DRVMGR_FUNC(PCI_FUNC_MREG_R16, NULL),
+ DRVMGR_FUNC(PCI_FUNC_MREG_R32, NULL),
+ DRVMGR_FUNC(PCI_FUNC_MREG_W8, NULL),
+ DRVMGR_FUNC(PCI_FUNC_MREG_W16, NULL),
+ DRVMGR_FUNC(PCI_FUNC_MREG_W32, NULL),
+ DRVMGR_FUNC_END
+};
+
+/* Driver resources configuration for the PCI bus. It is declared weak so that
+ * the user may override it from the project file, if the default settings are
+ * not enough.
+ */
+struct drvmgr_bus_res pcibus_drv_resources __attribute__((weak)) = {
+ .next = NULL,
+ .resource = {
+ RES_EMPTY,
+ },
+};
+
+struct pcibus_priv {
+ struct drvmgr_dev *dev;
+};
+
+static int compatible(struct pci_dev_id *id, struct pci_dev_id_match *drv)
+{
+ if (((drv->vendor==PCI_ID_ANY) || (id->vendor==drv->vendor)) &&
+ ((drv->device==PCI_ID_ANY) || (id->device==drv->device)) &&
+ ((drv->subvendor==PCI_ID_ANY) || (id->subvendor==drv->subvendor)) &&
+ ((drv->subdevice==PCI_ID_ANY) || (id->subdevice==drv->subdevice)) &&
+ ((id->class & drv->class_mask) == drv->class))
+ return 1;
+ else
+ return 0;
+}
+
+int pcibus_unite(struct drvmgr_drv *drv,
+ struct drvmgr_dev *dev)
+{
+ struct pci_drv_info *pdrv;
+ struct pci_dev_id_match *drvid;
+ struct pci_dev_info *pci;
+
+ if (!drv || !dev || !dev->parent)
+ return 0;
+
+ if ((drv->bus_type != DRVMGR_BUS_TYPE_PCI) ||
+ (dev->parent->bus_type != DRVMGR_BUS_TYPE_PCI))
+ return 0;
+
+ pci = (struct pci_dev_info *)dev->businfo;
+ if (!pci)
+ return 0;
+
+ pdrv = (struct pci_drv_info *)drv;
+ drvid = pdrv->ids;
+ if (!drvid)
+ return 0;
+ while (drvid->vendor != 0) {
+ if (compatible(&pci->id, drvid)) {
+ /* Unite device and driver */
+ DBG("DRV %p and DEV %p united\n", drv, dev);
+ return 1;
+ }
+ drvid++;
+ }
+
+ return 0;
+}
+
+static int pcibus_int_get(struct drvmgr_dev *dev, int index)
+{
+ int irq;
+
+ /* Relative (positive) or absolute (negative) IRQ number */
+ if (index > 0) {
+ /* PCI devices only have one IRQ per function */
+ return -1;
+ } else if (index == 0) {
+ /* IRQ Index relative to Cores base IRQ */
+
+ /* Get Base IRQ */
+ irq = ((struct pci_dev_info *)dev->businfo)->irq;
+ if (irq <= 0)
+ return -1;
+ } else {
+ /* Absolute IRQ number */
+ irq = -index;
+ }
+ return irq;
+}
+
+/* Use standard PCI facility to register interrupt handler */
+int pcibus_int_register(
+ struct drvmgr_dev *dev,
+ int index,
+ const char *info,
+ drvmgr_isr isr,
+ void *arg)
+{
+ struct drvmgr_dev *busdev;
+ int irq;
+
+ busdev = dev->parent->dev;
+
+ /* Get IRQ number from index and device information */
+ irq = pcibus_int_get(dev, index);
+ if (irq < 0)
+ return -1;
+
+ DBG("Register PCI interrupt on %p for dev %p (IRQ: %d)\n",
+ busdev, dev, irq);
+
+ return pci_interrupt_register(irq, info, isr, arg);
+}
+
+/* Use standard PCI facility to unregister interrupt handler */
+int pcibus_int_unregister(
+ struct drvmgr_dev *dev,
+ int index,
+ drvmgr_isr isr,
+ void *arg)
+{
+ struct drvmgr_dev *busdev;
+ int irq;
+
+ busdev = dev->parent->dev;
+
+ /* Get IRQ number from index and device information */
+ irq = pcibus_int_get(dev, index);
+ if (irq < 0)
+ return -1;
+
+ DBG("Unregister PCI interrupt on %p for dev %p (IRQ: %d)\n",
+ busdev, dev, irq);
+
+ return pci_interrupt_unregister(irq, isr, arg);
+}
+
+/* Use standard PCI facility to clear interrupt */
+int pcibus_int_clear(
+ struct drvmgr_dev *dev,
+ int index)
+{
+ int irq;
+
+ /* Get IRQ number from index and device information */
+ irq = pcibus_int_get(dev, index);
+ if (irq < 0)
+ return -1;
+
+ pci_interrupt_clear(irq);
+
+ return 0;
+}
+
+int pcibus_freq_get(
+ struct drvmgr_dev *dev,
+ int options,
+ unsigned int *freq_hz)
+{
+ /* Standard PCI Bus frequency */
+ *freq_hz = 33000000;
+ return 0;
+}
+
+int pcibus_get_params(struct drvmgr_dev *dev, struct drvmgr_bus_params *params)
+{
+ /* No device prefix */
+ params->dev_prefix = NULL;
+
+ return 0;
+}
+
+#ifdef PCIBUS_INFO
+void pcibus_dev_info(
+ struct drvmgr_dev *dev,
+ void (*print_line)(void *p, char *str),
+ void *p)
+{
+ struct pci_dev_info *devinfo;
+ struct pcibus_res *pcibusres;
+ struct pci_res *res;
+ char buf[64];
+ int i;
+ char *str1, *res_types[3] = {" IO16", "MEMIO", " MEM"};
+ uint32_t pcistart;
+
+ if (!dev)
+ return;
+
+ devinfo = (struct pci_dev_info *)dev->businfo;
+ if (!devinfo)
+ return;
+
+ if ((devinfo->id.class >> 8) == PCI_CLASS_BRIDGE_PCI)
+ print_line(p, "PCI BRIDGE DEVICE");
+ else
+ print_line(p, "PCI DEVICE");
+ sprintf(buf, "LOCATION: BUS:SLOT:FUNCTION [%x:%x:%x]",
+ PCI_DEV_EXPAND(devinfo->pcidev));
+ print_line(p, buf);
+ sprintf(buf, "PCIID 0x%lx", (uint32_t)devinfo->pcidev);
+ print_line(p, buf);
+ sprintf(buf, "VENDOR ID: %04x", devinfo->id.vendor);
+ print_line(p, buf);
+ sprintf(buf, "DEVICE ID: %04x", devinfo->id.device);
+ print_line(p, buf);
+ sprintf(buf, "SUBVEN ID: %04x", devinfo->id.subvendor);
+ print_line(p, buf);
+ sprintf(buf, "SUBDEV ID: %04x", devinfo->id.subdevice);
+ print_line(p, buf);
+ sprintf(buf, "CLASS: %lx", devinfo->id.class);
+ print_line(p, buf);
+ sprintf(buf, "REVISION: %x", devinfo->rev);
+ print_line(p, buf);
+ sprintf(buf, "IRQ: %d", devinfo->irq);
+ print_line(p, buf);
+ sprintf(buf, "PCIDEV ptr: %p", devinfo->pci_device);
+ print_line(p, buf);
+
+ /* List Resources */
+ print_line(p, "RESOURCES");
+ for (i = 0; i < PCIDEV_RES_CNT; i++) {
+ pcibusres = &devinfo->resources[i];
+
+ str1 = " RES";
+ pcistart = -1;
+ res = pcibusres->res;
+ if (res && (res->flags & PCI_RES_TYPE_MASK)) {
+ str1 = res_types[(res->flags & PCI_RES_TYPE_MASK) - 1];
+ if (res->flags & PCI_RES_IO32)
+ str1 = " IO32";
+ pcistart = res->start;
+ }
+
+ if (res && (res->flags & PCI_RES_FAIL)) {
+ sprintf(buf, " %s[%d]: NOT ASSIGNED", str1, i);
+ print_line(p, buf);
+ continue;
+ }
+ if (!pcibusres->size)
+ continue;
+
+ sprintf(buf, " %s[%d]: %08lx-%08lx [PCIADR %lx]",
+ str1, i, pcibusres->address,
+ pcibusres->address + pcibusres->size - 1, pcistart);
+ print_line(p, buf);
+ }
+}
+#endif
+
+#ifdef USE_PCI_CFG_LIB
+
+int pcibus_dev_register(struct pci_dev *dev, void *arg)
+{
+ struct drvmgr_bus *pcibus = arg;
+ struct drvmgr_dev *newdev;
+ struct pci_dev_info *pciinfo;
+ int i, type;
+ struct pcibus_res *pcibusres;
+ struct pci_res *pcires;
+
+ pci_dev_t pcidev = dev->busdevfun;
+
+ DBG("PCI DEV REGISTER: %x:%x:%x\n", PCI_DEV_EXPAND(pcidev));
+
+ /* Allocate a device */
+ drvmgr_alloc_dev(&newdev, 24 + sizeof(struct pci_dev_info));
+ newdev->next = NULL;
+ newdev->parent = pcibus; /* Ourselfs */
+ newdev->minor_drv = 0;
+ newdev->minor_bus = 0;
+ newdev->priv = NULL;
+ newdev->drv = NULL;
+ newdev->name = (char *)(newdev + 1);
+ newdev->next_in_drv = NULL;
+ newdev->bus = NULL;
+
+ /* Init PnP information, Assign Core interfaces with this device */
+ pciinfo = (struct pci_dev_info *)((char *)(newdev + 1) + 24);
+
+ /* Read Device and Vendor */
+ pciinfo->id.vendor = dev->vendor;
+ pciinfo->id.device = dev->device;
+ pciinfo->id.subvendor = dev->subvendor;
+ pciinfo->id.subdevice = dev->subdevice;
+ pciinfo->rev = dev->classrev & 0xff;
+ pciinfo->id.class = (dev->classrev >> 8) & 0xffffff;
+
+ /* Read IRQ information set by PCI layer */
+ pciinfo->irq = dev->sysirq;
+
+ /* Save Location on PCI bus */
+ pciinfo->pcidev = pcidev;
+
+ /* Connect device with PCI data structure */
+ pciinfo->pci_device = dev;
+
+ /* Build resources so that PCI device drivers doesn't have to scan
+ * configuration space themselves, also the address is translated
+ * into CPU accessible addresses.
+ */
+ for (i = 0; i < PCIDEV_RES_CNT; i++) {
+ pcibusres = &pciinfo->resources[i];
+ pcires = &dev->resources[i];
+ type = pcires->flags & PCI_RES_TYPE_MASK;
+ if (type == 0 || (pcires->flags & PCI_RES_FAIL))
+ continue; /* size=0 */
+
+ pcibusres->address = pcires->start;
+ if (pci_pci2cpu(&pcibusres->address, type))
+ continue; /* size=0 */
+ pcibusres->res = pcires;
+ pcibusres->size = pcires->end - pcires->start;
+ }
+
+ /* Connect device with PCI information */
+ newdev->businfo = (void *)pciinfo;
+
+ /* Create Device Name */
+ sprintf(newdev->name, "PCI_%x:%x:%x_%04x:%04x",
+ PCI_DEV_BUS(pcidev), PCI_DEV_SLOT(pcidev), PCI_DEV_FUNC(pcidev),
+ pciinfo->id.vendor, pciinfo->id.device);
+
+ /* Register New Device */
+ drvmgr_dev_register(newdev);
+
+ return 0;
+}
+
+#else
+
+int pcibus_dev_register(pci_dev_t pcidev, void *arg)
+{
+ struct drvmgr_bus *pcibus = arg;
+ struct drvmgr_dev *newdev;
+ struct pci_dev_info *pciinfo;
+
+ DBG("PCI DEV REGISTER: %x:%x:%x\n", PCI_DEV_EXPAND(pcidev));
+
+ /* Allocate a device */
+ drvmgr_alloc_dev(&newdev, 24 + sizeof(struct pci_dev_info));
+ newdev->next = NULL;
+ newdev->parent = pcibus; /* Ourselfs */
+ newdev->minor_drv = 0;
+ newdev->minor_bus = 0;
+ newdev->priv = NULL;
+ newdev->drv = NULL;
+ newdev->name = (char *)(newdev + 1);
+ newdev->next_in_drv = NULL;
+ newdev->bus = NULL;
+
+ /* Init PnP information, Assign Core interfaces with this device */
+ pciinfo = (struct pci_dev_info *)((char *)(newdev + 1) + 24);
+
+ /* Read Device and Vendor */
+ pci_cfg_r16(pcidev, PCI_VENDOR_ID, &pciinfo->id.vendor);
+ pci_cfg_r16(pcidev, PCI_DEVICE_ID, &pciinfo->id.device);
+ pci_cfg_r32(pcidev, PCI_CLASS_REVISION, &pciinfo->id.class);
+ pciinfo->rev = pciinfo->id.class & 0xff;
+ pciinfo->id.class = pciinfo->id.class >> 8;
+
+ /* Devices have subsytem device and vendor ID */
+ if ((pciinfo->id.class >> 8) != PCI_CLASS_BRIDGE_PCI) {
+ pci_cfg_r16(pcidev, PCI_SUBSYSTEM_VENDOR_ID,
+ &pciinfo->id.subvendor);
+ pci_cfg_r16(pcidev, PCI_SUBSYSTEM_ID, &pciinfo->id.subdevice);
+ } else {
+ pciinfo->id.subvendor = 0;
+ pciinfo->id.subdevice = 0;
+ }
+
+ /* Read IRQ information set by PCI layer */
+ pci_cfg_r8(pcidev, PCI_INTERRUPT_LINE, &pciinfo->irq);
+
+ /* Save Location */
+ pciinfo->pcidev = pcidev;
+
+ /* There is no way we can know this information this way */
+ pciinfo->pci_device = NULL;
+
+ /* Connect device with PCI information */
+ newdev->businfo = (void *)pciinfo;
+
+ /* Create Device Name */
+ sprintf(newdev->name, "PCI_%d:%d:%d_%04x:%04x",
+ PCI_DEV_BUS(pcidev), PCI_DEV_SLOT(pcidev), PCI_DEV_FUNC(pcidev),
+ pciinfo->id.vendor, pciinfo->id.device);
+
+ /* Register New Device */
+ drvmgr_dev_register(newdev);
+
+ return 0;
+}
+
+#endif
+
+/* Register all AMBA devices available on the AMBAPP bus */
+static int pcibus_devs_register(struct drvmgr_bus *bus)
+{
+ /* return value 0=DRVMGR_OK works with pci_for_each/pci_for_each_dev */
+#ifdef USE_PCI_CFG_LIB
+ /* Walk the PCI device tree in RAM */
+ return pci_for_each_dev(pcibus_dev_register, bus);
+#else
+ /* Scan PCI Configuration space */
+ return pci_for_each(pcibus_dev_register, bus);
+#endif
+}
+
+/*** DEVICE FUNCTIONS ***/
+
+int pcibus_register(struct drvmgr_dev *dev, struct pcibus_config *config)
+{
+ struct pcibus_priv *priv;
+ int i, fid, rc;
+
+ DBG("PCI BUS: initializing\n");
+
+ /* Create BUS */
+ drvmgr_alloc_bus(&dev->bus, sizeof(struct pcibus_priv));
+ dev->bus->bus_type = DRVMGR_BUS_TYPE_PCI;
+ dev->bus->next = NULL;
+ dev->bus->dev = dev;
+ dev->bus->children = NULL;
+ dev->bus->ops = &pcibus_ops;
+ dev->bus->dev_cnt = 0;
+ dev->bus->reslist = NULL;
+ dev->bus->maps_up = config->maps_up;
+ dev->bus->maps_down = config->maps_down;
+ dev->bus->funcs = &pcibus_funcs[0];
+
+ /* Copy function definitions from PCI Layer */
+ for (i=0; i<6; i++) {
+ fid = pcibus_funcs[i].funcid;
+ rc = pci_access_func(RW_DIR(fid), RW_SIZE(fid),
+ &pcibus_funcs[i].func, PCI_LITTLE_ENDIAN, 3);
+ if (rc != 0)
+ DBG("PCI BUS: MEMREG 0x%x function not defined\n", fid);
+ }
+
+ /* Add resource configuration if user overrided the default empty cfg */
+ if (pcibus_drv_resources.resource[0].drv_id != 0)
+ drvmgr_bus_res_add(dev->bus, &pcibus_drv_resources);
+
+ /* Init BUS private structures */
+ priv = (struct pcibus_priv *)(dev->bus + 1);
+ dev->bus->priv = priv;
+
+ /* Register BUS */
+ drvmgr_bus_register(dev->bus);
+
+ return DRVMGR_OK;
+}
+
+/*** BUS INITIALIZE FUNCTIONS ***/
+
+int pcibus_bus_init1(struct drvmgr_bus *bus)
+{
+ return pcibus_devs_register(bus);
+}
diff --git a/cpukit/libpci/pci_bus.h b/cpukit/libpci/pci_bus.h
new file mode 100644
index 0000000000..76a5e945ac
--- /dev/null
+++ b/cpukit/libpci/pci_bus.h
@@ -0,0 +1,159 @@
+/* PCI bus driver Interface.
+ *
+ * COPYRIGHT (c) 2008.
+ * Aeroflex Gaisler.
+ *
+ * General part of PCI Bus driver. The driver is typically
+ * initialized from the PCI host driver separating the host
+ * driver from the common parts in PCI drivers.
+ * The PCI library must be initialized before starting the
+ * PCI bus driver. The PCI library have set up BARs and
+ * assigned system IRQs for targets.
+ * This PCI bus driver rely on the PCI library (pci.c) for
+ * interrupt registeration (pci_interrupt_register) and PCI
+ * target set up.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ */
+
+#ifndef __PCI_BUS_H__
+#define __PCI_BUS_H__
+
+#include <drvmgr/drvmgr.h>
+#include <pci.h>
+#include <pci/access.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* PCI Driver ID generation (VENDOR: 16-bit, DEVICE: 16-bit) */
+#define DRIVER_PCI_ID(vendor, device) \
+ DRIVER_ID(DRVMGR_BUS_TYPE_PCI, \
+ ((((vendor) & 0xffff) << 16) | ((device) & 0xffff)))
+
+/* PCI Driver ID generation (CLASS: 24-bit) */
+#define DRIVER_PCI_CLASS(class) \
+ DRIVER_ID(DRVMGR_BUS_TYPE_PCI, ((1 << 32) | ((class) & 0xffffff)))
+
+/* PCI driver IDs (DRIVER_PCI_VENDOR_DEVICE or DRIVER_PCI_CLASS_NAME) */
+#define DRIVER_PCI_GAISLER_RASTAIO_ID DRIVER_PCI_ID(PCIID_VENDOR_GAISLER, PCIID_DEVICE_GR_RASTA_IO)
+#define DRIVER_PCI_GAISLER_RASTATMTC_ID DRIVER_PCI_ID(PCIID_VENDOR_GAISLER, PCIID_DEVICE_GR_RASTA_TMTC)
+#define DRIVER_PCI_GAISLER_GR701_ID DRIVER_PCI_ID(PCIID_VENDOR_GAISLER, PCIID_DEVICE_GR_701)
+#define DRIVER_PCI_GAISLER_RASTAADCDAC_ID DRIVER_PCI_ID(PCIID_VENDOR_GAISLER, PCIID_DEVICE_GR_RASTA_ADCDAC)
+#define DRIVER_PCI_GAISLER_TMTC_1553_ID DRIVER_PCI_ID(PCIID_VENDOR_GAISLER, PCIID_DEVICE_GR_TMTC_1553)
+#define DRIVER_PCI_GAISLER_RASTA_SPW_ROUTER_ID DRIVER_PCI_ID(PCIID_VENDOR_GAISLER, PCIID_DEVICE_GR_RASTA_SPW_RTR)
+
+struct pci_dev_id {
+ uint16_t vendor;
+ uint16_t device;
+ uint16_t subvendor;
+ uint16_t subdevice;
+ uint32_t class; /* 24 lower bits */
+};
+
+struct pci_dev_id_match {
+ uint16_t vendor;
+ uint16_t device;
+ uint16_t subvendor;
+ uint16_t subdevice;
+ uint32_t class; /* 24 lower bits */
+ uint32_t class_mask; /* 24 lower bits */
+};
+#define PCIID_DEVVEND(vendor, device) \
+ {vendor, device, PCI_ID_ANY, PCI_ID_ANY, 0, 0}
+#define PCIID_END_TABLE {0, 0, 0, 0, 0, 0}
+
+enum {
+ /* A Device has up to 6 BARs and an optional ROM BAR */
+ PCIDEV_RES_BAR1 = 0,
+ PCIDEV_RES_BAR2 = 1,
+ PCIDEV_RES_BAR3 = 2,
+ PCIDEV_RES_BAR4 = 3,
+ PCIDEV_RES_BAR5 = 4,
+ PCIDEV_RES_BAR6 = 5,
+ PCIDEV_RES_ROM = 6,
+};
+/* Maximum Number of Resources of a device */
+#define PCIDEV_RES_CNT (PCIDEV_RES_ROM + 1)
+
+/* IO, MEMIO or MEM resource. Can be BAR, ROM or Bridge Window */
+struct pcibus_res {
+ uint32_t address; /* Base Address, CPU accessible */
+ uint32_t size; /* 0=Unimplemented, 0!=Resource Size */
+ struct pci_res *res; /* PCI-layer resource */
+};
+
+struct pci_dev_info {
+ struct pci_dev_id id;
+ uint8_t rev;
+ uint8_t irq; /* 0 = NO IRQ */
+ pci_dev_t pcidev;
+ struct pcibus_res resources[PCIDEV_RES_CNT];
+ struct pci_dev *pci_device;
+};
+
+struct pci_drv_info {
+ struct drvmgr_drv general; /* General bus info */
+ /* PCI specific bus information */
+ struct pci_dev_id_match *ids; /* Supported hardware */
+};
+
+/* Access routines */
+struct pcibus_regmem_ops {
+ drvmgr_r8 r8;
+ drvmgr_r16 r16;
+ drvmgr_r32 r32;
+ drvmgr_r64 r64;
+ drvmgr_w8 w8;
+ drvmgr_w16 w16;
+ drvmgr_w32 w32;
+ drvmgr_w64 w64;
+};
+
+/* Let driver configure PCI bus driver */
+struct pcibus_config {
+ struct drvmgr_map_entry *maps_up;
+ struct drvmgr_map_entry *maps_down;
+};
+
+/* PCI Configuration Space Access - Not implemented (use PCI Lib directly) */
+#define PCI_FUNC_CFG_R8 DRVMGR_RWFUNC(RW_SIZE_1|RW_READ|RW_CFG)
+#define PCI_FUNC_CFG_R16 DRVMGR_RWFUNC(RW_SIZE_2|RW_READ|RW_CFG)
+#define PCI_FUNC_CFG_R32 DRVMGR_RWFUNC(RW_SIZE_4|RW_READ|RW_CFG)
+#define PCI_FUNC_CFG_W8 DRVMGR_RWFUNC(RW_SIZE_1|RW_WRITE|RW_CFG)
+#define PCI_FUNC_CFG_W16 DRVMGR_RWFUNC(RW_SIZE_2|RW_WRITE|RW_CFG)
+#define PCI_FUNC_CFG_W32 DRVMGR_RWFUNC(RW_SIZE_4|RW_WRITE|RW_CFG)
+
+/* PCI I/O Register Access - Not implemented (use PCI Lib directly) */
+#define PCI_FUNC_IO_R8 DRVMGR_RWFUNC(RW_SIZE_1|RW_READ|RW_IO)
+#define PCI_FUNC_IO_R16 DRVMGR_RWFUNC(RW_SIZE_2|RW_READ|RW_IO)
+#define PCI_FUNC_IO_R32 DRVMGR_RWFUNC(RW_SIZE_4|RW_READ|RW_IO)
+#define PCI_FUNC_IO_W8 DRVMGR_RWFUNC(RW_SIZE_1|RW_WRITE|RW_IO)
+#define PCI_FUNC_IO_W16 DRVMGR_RWFUNC(RW_SIZE_2|RW_WRITE|RW_IO)
+#define PCI_FUNC_IO_W32 DRVMGR_RWFUNC(RW_SIZE_4|RW_WRITE|RW_IO)
+
+/* PCI Register Access over Memory Space (Little Endian) */
+#define PCI_FUNC_MREG_R8 DRVMGR_RWFUNC(RW_SIZE_1|RW_READ|RW_MEMREG)
+#define PCI_FUNC_MREG_R16 DRVMGR_RWFUNC(RW_SIZE_2|RW_READ|RW_MEMREG|RW_LITTLE)
+#define PCI_FUNC_MREG_R32 DRVMGR_RWFUNC(RW_SIZE_4|RW_READ|RW_MEMREG|RW_LITTLE)
+#define PCI_FUNC_MREG_W8 DRVMGR_RWFUNC(RW_SIZE_1|RW_WRITE|RW_MEMREG)
+#define PCI_FUNC_MREG_W16 DRVMGR_RWFUNC(RW_SIZE_2|RW_WRITE|RW_MEMREG|RW_LITTLE)
+#define PCI_FUNC_MREG_W32 DRVMGR_RWFUNC(RW_SIZE_4|RW_WRITE|RW_MEMREG|RW_LITTLE)
+
+/* Weak default PCI driver resources, override this from project configuration
+ * to set PCI Bus resources used to configure PCI device drivers.
+ */
+extern struct drvmgr_bus_res pcibus_drv_resources;
+
+/* Attach a PCI bus on top of a PCI Host device */
+extern int pcibus_register(struct drvmgr_dev *dev, struct pcibus_config *cfg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/cpukit/libpci/pci_cfg.c b/cpukit/libpci/pci_cfg.c
new file mode 100644
index 0000000000..3aeb5a27df
--- /dev/null
+++ b/cpukit/libpci/pci_cfg.c
@@ -0,0 +1,58 @@
+/* PCI Configuration Library
+ *
+ * COPYRIGHT (c) 2010-2011.
+ * Aeroflex Gaisler Research
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2011-02-11, Daniel Hellstrom <daniel@gaisler.com>
+ * created
+ */
+
+#include <pci/cfg.h>
+
+/* Number of buses. This is set from respective library */
+int pci_bus_cnt = 0;
+
+/* PCI Address assigned to BARs which failed to fit into the PCI Window or
+ * is disabled by any other cause.
+ */
+uint32_t pci_invalid_address = 0;
+
+/* PCI System type. Configuration Library setup this */
+int pci_system_type = PCI_SYSTEM_NONE;
+
+/* PCI Endianness.
+ *
+ * Host driver or BSP must override this be writing here if bus is defined
+ * as non-standard big-endian.
+ */
+int pci_endian = PCI_LITTLE_ENDIAN;
+
+/* Configure PCI devices and bridges, and setup the RAM data structures
+ * describing the PCI devices currently present in the system
+ */
+int pci_config_init(void)
+{
+ if (pci_config_lib_init)
+ return pci_config_lib_init();
+ else
+ return 0;
+}
+
+void pci_config_register(void *config)
+{
+ if (pci_config_lib_register)
+ pci_config_lib_register(config);
+}
+
+/* Return the number of PCI busses available in the system, note that
+ * there are always one bus (bus0) after the PCI library has been
+ * initialized and a driver has been registered.
+ */
+int pci_bus_count(void)
+{
+ return pci_bus_cnt;
+}
diff --git a/cpukit/libpci/pci_cfg_auto.c b/cpukit/libpci/pci_cfg_auto.c
new file mode 100644
index 0000000000..b0f02b0e1e
--- /dev/null
+++ b/cpukit/libpci/pci_cfg_auto.c
@@ -0,0 +1,1040 @@
+/* PCI (Auto) configuration Library. Setup PCI configuration space and IRQ.
+ *
+ * COPYRIGHT (c) 2010-2011.
+ * Aeroflex Gaisler Research
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2010-02-03, Daniel Hellstrom <daniel@gaisler.com>
+ * PCI Library rewritten from scratch. Support multiple buses/bridges,
+ * print current PCI configuration space setup, BAR assigment sort
+ * implementation speeded up drastically (bootup time noticable
+ * shorter), interrupt assignment implemented, PCI Host driver
+ * extracted from library, support for I/O areas.
+ * 2010-02-03, Daniel Hellstrom <daniel@gaisler.com>
+ * Fixed initialization problem when first device is a bridge.
+ * 2010-04-19, Daniel Hellstrom <daniel@gaisler.com>
+ * Fixed autoconf issue when bridges are present
+ * 2010-04-19, Daniel Hellstrom <daniel@gaisler.com>
+ * Optimized resource allocation when bridges are present: the
+ * resources lists are sorted by boundary instead of size and a
+ * reorder aligorithm introduced that move resources into unused
+ * areas if possible.
+ * 2010-06-10, Daniel Hellstrom <daniel@gaisler.com>
+ * Fix in pci_res_insert(), where the above mentioned optimization
+ * failed due to bad compare statement. Optimization only affects
+ * systems with multiple PCI buses.
+ * 2010-09-29, Kristoffer Glembo <kristoffer@gaisler.com>
+ * Fixed I/O BAR size calculation of bridges. Reading/Writing to 0x1C
+ * instead of faulty 0x1E.
+ * 2011-02-11, Daniel Hellstrom <daniel@gaisler.com>
+ * Changed library to use 16-bit identifiers (pci_dev_t), instead to 3
+ * integers (BUS,SLOT,FUNC), this reduces the footprint.
+ * 2011-02-11, Daniel Hellstrom <daniel@gaisler.com>
+ * Split Library into different parts, this enables PCI initialization
+ * to be done outside of the PCI Host driver and smaller systems that
+ * don't want Configuration Space to be setup.
+ * - Access Library (Configuration, Memory and I/O Space read/write
+ * routines)
+ * - Configuration Libarary
+ * A. Auto Config
+ * B. Static Config (not implemented yet)
+ * - Interrupt Library (shared interrupt support rely on BSP)
+ * Added CHANGES file
+ */
+
+#include <rtems.h>
+#include <stdlib.h>
+#include <rtems/bspIo.h>
+#include <string.h>
+
+/* Configure headers */
+#define PCI_CFG_AUTO_LIB
+
+#include <pci.h>
+#include <pci/access.h>
+#include <pci/cfg.h>
+
+/* Define PCI_INFO_ON_STARTUP to get a listing of configured devices at boot
+ * time
+ */
+#undef PCI_INFO_ON_STARTUP
+
+/* #define DEBUG */
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+/* PCI Library
+ * (For debugging it might be good to use other functions or the driver's
+ * directly)
+ */
+#define PCI_CFG_R8(dev, args...) pci_cfg_r8(dev, args)
+#define PCI_CFG_R16(dev, args...) pci_cfg_r16(dev, args)
+#define PCI_CFG_R32(dev, args...) pci_cfg_r32(dev, args)
+#define PCI_CFG_W8(dev, args...) pci_cfg_w8(dev, args)
+#define PCI_CFG_W16(dev, args...) pci_cfg_w16(dev, args)
+#define PCI_CFG_W32(dev, args...) pci_cfg_w32(dev, args)
+
+/* Number of PCI buses */
+extern int pci_bus_cnt;
+
+int pci_config_auto_initialized = 0;
+
+/* Configuration setup */
+struct pci_auto_setup pci_auto_cfg;
+
+/* Insert BAR into the sorted resources list. The BARs are sorted on the
+ * BAR size/alignment need.
+ */
+void pci_res_insert(struct pci_res **root, struct pci_res *res)
+{
+ struct pci_res *curr, *last;
+ unsigned long curr_size_resulting_boundary, size_resulting_boundary;
+ unsigned long boundary, size;
+
+ res->start = 0;
+ res->end = 0;
+ boundary = res->boundary;
+ size = res->size;
+
+ /* Insert the resources depending on the boundary needs
+ * Normally the boundary=size of the BAR, however when
+ * PCI bridges are involved the bridge's boundary may be
+ * smaller that the size due to the fact that a bridge
+ * may have different-sized BARs behind, the largest BAR
+ * (also the BAR with the largest boundary) will decide
+ * the alignment need.
+ */
+ last = NULL;
+ curr = *root;
+
+ /* Order List after boundary, the boundary is maintained
+ * when the size is on an equal boundary, normally it is
+ * but may not be with bridges. So in second hand it is
+ * sorted after resulting boundary - the boundary after
+ * the resource.
+ */
+ while (curr && (curr->boundary >= boundary)) {
+ if (curr->boundary == boundary) {
+ /* Find Resulting boundary of size */
+ size_resulting_boundary = 1;
+ while ((size & size_resulting_boundary) == 0)
+ size_resulting_boundary =
+ size_resulting_boundary << 1;
+
+ /* Find Resulting boundary of curr->size */
+ curr_size_resulting_boundary = 1;
+ while ((curr->size & curr_size_resulting_boundary) == 0)
+ curr_size_resulting_boundary =
+ curr_size_resulting_boundary << 1;
+
+ if (size_resulting_boundary >=
+ curr_size_resulting_boundary)
+ break;
+ }
+ last = curr;
+ curr = curr->next;
+ }
+
+ if (last == NULL) {
+ /* Insert first in list */
+ res->next = *root;
+ *root = res;
+ } else {
+ last->next = res;
+ res->next = curr;
+ }
+}
+
+#ifdef DEBUG
+void pci_res_list_print(struct pci_res *root)
+{
+ if (root == NULL)
+ return;
+
+ printf("RESOURCE LIST:\n");
+ while (root) {
+ printf(" SIZE: 0x%08x, BOUNDARY: 0x%08x\n", root->size,
+ root->boundary);
+ root = root->next;
+ }
+}
+#endif
+
+/* Reorder a size/alignment ordered resources list. The idea is to
+ * avoid unused due to alignment/size restriction.
+ *
+ * NOTE: The first element is always untouched.
+ * NOTE: If less than three elements in list, nothing will be done
+ *
+ * Normally a BAR has the same alignment requirements as the size of the
+ * BAR. However, when bridges are invloved the alignment need may be smaller
+ * that the size, because a bridge resource consist or multiple BARs.
+ * For example, say that a bridge with a 256Mb and a 16Mb BAR is found, then
+ * the alignment is required to be 256Mb but the size 256+16Mb.
+ *
+ * In order to minimize dead space on the bus, the bounadry ordered list
+ * is reordered, example:
+ * BUS0
+ * | BUS1
+ * |------------|
+ * | |-- BAR0: SIZE=256Mb, ALIGNMENT=256MB
+ * | |-- BAR1: SIZE=16Mb, ALIGNMENT=16MB
+ * | |
+ * | |
+ * | |
+ * | | BUS2 (BAR_BRIDGE1: SIZE=256+16, ALIGNEMENT=256)
+ * | |----------|
+ * | | |-- BAR2: SIZE=256Mb, ALIGNMENT=256Mb
+ * | | |-- BAR3: SIZE=16Mb, ALIGNMENT=16MB
+ *
+ * A alignement/boundary ordered list of BUS1 will look like:
+ * - BAR_BRIDGE1
+ * - BAR0 (ALIGMENT NEED 256Mb)
+ * - BAR1
+ *
+ * However, Between BAR_BRIDGE1 and BAR0 will be a unused hole of 256-16Mb.
+ * We can put BAR1 before BAR0 to avoid the problem.
+ */
+void pci_res_reorder(struct pci_res *root)
+{
+ struct pci_res *curr, *last, *curr2, *last2;
+ unsigned int start, start_next, hole_size, hole_boundary;
+
+ if (root == NULL)
+ return;
+
+ /* Make up a start address with the boundary of the
+ * First element.
+ */
+ start = root->boundary + root->size;
+ last = root;
+ curr = root->next;
+ while (curr) {
+
+ /* Find start address of resource */
+ start_next = (start + (curr->boundary - 1)) &
+ ~(curr->boundary - 1);
+
+ /* Find hole size, the unsed space inbetween last resource
+ *and next */
+ hole_size = start_next - start;
+
+ /* Find Boundary of START */
+ hole_boundary = 1;
+ while ((start & hole_boundary) == 0)
+ hole_boundary = hole_boundary<<1;
+
+ /* Detect dead hole */
+ if (hole_size > 0) {
+ /* Step through list and try to find a resource that
+ * can fit into hole. Take into account hole start
+ * boundary and hole size.
+ */
+ last2 = curr;
+ curr2 = curr->next;
+ while (curr2) {
+ if ((curr2->boundary <= hole_boundary) &&
+ (curr2->size <= hole_size)) {
+ /* Found matching resource. Move it
+ * first in the hole. Then rescan, now
+ * that the hole has changed in
+ * size/boundary.
+ */
+ last2->next = curr2->next;
+ curr2->next = curr;
+ last->next = curr2;
+
+ /* New Start address */
+ start_next = (start +
+ (curr2->boundary - 1)) &
+ ~(curr2->boundary - 1);
+ /* Since we inserted the resource before
+ * curr we need to re-evaluate curr one
+ * more, more resources may fit into the
+ * shrunken hole.
+ */
+ curr = curr2;
+ break;
+ }
+ last2 = curr2;
+ curr2 = curr2->next;
+ }
+ }
+
+ /* No hole or nothing fitted into hole. */
+ start = start_next;
+
+ last = curr;
+ curr = curr->next;
+ }
+}
+
+/* Find the total size required in PCI address space needed by a resource list*/
+unsigned int pci_res_size(struct pci_res *root)
+{
+ struct pci_res *curr;
+ unsigned int size;
+
+ /* Get total size of all resources */
+ size = 0;
+ curr = root;
+ while (curr) {
+ size = (size + (curr->boundary - 1)) & ~(curr->boundary - 1);
+ size += curr->size;
+ curr = curr->next;
+ }
+
+ return size;
+}
+
+/* Free a device and secondary bus if device is a bridge */
+void pci_dev_free(struct pci_dev *dev)
+{
+ struct pci_dev *subdev;
+ struct pci_bus *bus;
+
+ if (dev->flags & PCI_DEV_BRIDGE) {
+ bus = (struct pci_bus *)dev;
+ for (subdev = bus->devs; subdev ; subdev = subdev->next)
+ pci_dev_free(dev);
+ }
+
+ free(dev);
+}
+
+struct pci_dev *pci_dev_create(int isbus)
+{
+ void *ptr;
+ int size;
+
+ if (isbus)
+ size = sizeof(struct pci_bus);
+ else
+ size = sizeof(struct pci_dev);
+
+ ptr = malloc(size);
+ if (!ptr)
+ rtems_fatal_error_occurred(RTEMS_NO_MEMORY);
+ memset(ptr, 0, size);
+ return ptr;
+}
+
+void pci_find_devs(struct pci_bus *bus)
+{
+ uint32_t id, tmp;
+ uint8_t header;
+ int slot, func, fail;
+ struct pci_dev *dev, **listptr;
+ struct pci_bus *bridge;
+ pci_dev_t pcidev;
+
+ DBG("Scanning bus %d\n", bus->num);
+
+ listptr = &bus->devs;
+ slot = 0;
+ if (bus->num == 0)
+ slot = 1; /* Skip PCI HOST BRIDGE */
+ for (; slot < PCI_MAX_DEVICES; slot++) {
+
+ /* Slot address */
+ pcidev = PCI_DEV(bus->num, slot, 0);
+
+ for (func = 0; func < PCI_MAX_FUNCTIONS; func++, pcidev++) {
+
+ fail = PCI_CFG_R32(pcidev, PCI_VENDOR_ID, &id);
+ if (fail || id == 0xffffffff || id == 0) {
+ /*
+ * This slot is empty
+ */
+ if (func == 0)
+ break;
+ else
+ continue;
+ }
+
+ DBG("Found PCIDEV 0x%x at (bus %x, slot %x, func %x)\n",
+ id, bus, slot, func);
+
+ /* Set command to reset values, it disables bus
+ * mastering and address responses.
+ */
+ PCI_CFG_W16(pcidev, PCI_COMMAND, 0);
+
+ /* Clear any already set status bits */
+ PCI_CFG_W16(pcidev, PCI_STATUS, 0xf900);
+
+ /* Set latency timer to 64 */
+ PCI_CFG_W8(pcidev, PCI_LATENCY_TIMER, 64);
+
+ PCI_CFG_R32(pcidev, PCI_CLASS_REVISION, &tmp);
+ tmp >>= 16;
+ dev = pci_dev_create(tmp == PCI_CLASS_BRIDGE_PCI);
+ *listptr = dev;
+ listptr = &dev->next;
+
+ dev->busdevfun = pcidev;
+ dev->bus = bus;
+ PCI_CFG_R16(pcidev, PCI_VENDOR_ID, &dev->vendor);
+ PCI_CFG_R16(pcidev, PCI_DEVICE_ID, &dev->device);
+ PCI_CFG_R32(pcidev, PCI_CLASS_REVISION, &dev->classrev);
+
+ if (tmp == PCI_CLASS_BRIDGE_PCI) {
+ DBG("Found PCI-PCI Bridge 0x%x at "
+ "(bus %x, slot %x, func %x)\n",
+ id, bus, slot, func);
+ dev->flags = PCI_DEV_BRIDGE;
+ dev->subvendor = 0;
+ dev->subdevice = 0;
+ bridge = (struct pci_bus *)dev;
+ bridge->num = bus->sord + 1;
+ bridge->pri = bus->num;
+ bridge->sord = bus->sord + 1;
+
+ /* Configure bridge (no support for 64-bit) */
+ PCI_CFG_W32(pcidev, 0x28, 0);
+ PCI_CFG_W32(pcidev, 0x2C, 0);
+ tmp = (64 << 24) | (0xff << 16) |
+ (bridge->num << 8) | bridge->pri;
+ PCI_CFG_W32(pcidev, PCI_PRIMARY_BUS, tmp);
+
+ /* Scan Secondary Bus */
+ pci_find_devs(bridge);
+
+ /* sord might have been updated */
+ PCI_CFG_W8(pcidev, 0x1a, bridge->sord);
+ bus->sord = bridge->sord;
+
+ DBG("PCI-PCI BRIDGE: Primary %x, Secondary %x, "
+ "Subordinate %x\n",
+ bridge->pri, bridge->num, bridge->sord);
+ } else {
+ /* Disable Cardbus CIS Pointer */
+ PCI_CFG_W32(pcidev, PCI_CARDBUS_CIS, 0);
+
+ /* Devices have subsytem device and vendor ID */
+ PCI_CFG_R16(pcidev, PCI_SUBSYSTEM_VENDOR_ID,
+ &dev->subvendor);
+ PCI_CFG_R16(pcidev, PCI_SUBSYSTEM_ID,
+ &dev->subdevice);
+ }
+
+ /* Stop if not a multi-function device */
+ if (func == 0) {
+ pci_cfg_r8(pcidev, PCI_HEADER_TYPE, &header);
+ if ((header & PCI_MULTI_FUNCTION) == 0)
+ break;
+ }
+ }
+ }
+}
+
+void pci_find_bar(struct pci_dev *dev, int bar)
+{
+ uint32_t size, disable, mask;
+ struct pci_res *res = &dev->resources[bar];
+ char *str;
+ pci_dev_t pcidev = dev->busdevfun;
+ int ofs;
+
+ DBG("Bus: %x, Slot: %x, function: %x, bar%d\n",
+ PCI_DEV_EXPAND(pcidev), bar);
+
+ res->bar = bar;
+ if (bar == DEV_RES_ROM) {
+ if (dev->flags & PCI_DEV_BRIDGE)
+ ofs = PCI_ROM_ADDRESS1;
+ else
+ ofs = PCI_ROM_ADDRESS;
+ disable = 0; /* ROM BARs have a unique enable bit per BAR */
+ } else {
+ ofs = PCI_BASE_ADDRESS_0 + (bar << 2);
+ disable = pci_invalid_address;
+ }
+
+ PCI_CFG_W32(pcidev, ofs, 0xffffffff);
+ PCI_CFG_R32(pcidev, ofs, &size);
+ PCI_CFG_W32(pcidev, ofs, disable);
+
+ if (size == 0 || size == 0xffffffff)
+ return;
+ if (bar == DEV_RES_ROM) {
+ mask = PCI_ROM_ADDRESS_MASK;
+ str = "ROM";
+ if (dev->bus->flags & PCI_BUS_MEM)
+ res->flags = PCI_RES_MEM;
+ else
+ res->flags = PCI_RES_MEMIO;
+ } else if (((size & 0x1) == 0) && (size & 0x6)) {
+ /* unsupported Memory type */
+ PCI_CFG_W32(pcidev, ofs, 0);
+ return;
+ } else {
+ mask = ~0xf;
+ if (size & 0x1) {
+ /* I/O */
+ mask = ~0x3;
+ res->flags = PCI_RES_IO;
+ str = "I/O";
+ if (size & 0xffff0000)
+ res->flags |= PCI_RES_IO32;
+ /* Limit size of I/O space to 256 byte */
+ size |= 0xffffff00;
+ if ((dev->bus->flags & PCI_BUS_IO) == 0) {
+ res->flags |= PCI_RES_FAIL;
+ dev->flags |= PCI_DEV_RES_FAIL;
+ }
+ } else {
+ /* Memory. We convert Prefetchable Memory BARs to Memory
+ * BARs in case the Bridge does not support prefetchable
+ * memory.
+ */
+ if ((size & 0x8) && (dev->bus->flags & PCI_BUS_MEM)) {
+ /* Prefetchable and Bus supports it */
+ res->flags = PCI_RES_MEM;
+ str = "MEM";
+ } else {
+ res->flags = PCI_RES_MEMIO;
+ str = "MEMIO";
+ }
+ }
+ }
+ size &= mask;
+ res->size = ~size + 1;
+ res->boundary = ~size + 1;
+
+ DBG("Bus: %x, Slot: %x, function: %x, %s bar%d size: %x\n",
+ PCI_DEV_EXPAND(pcidev), str, bar, res->size);
+}
+
+int pci_find_res_dev(struct pci_dev *dev, void *unused)
+{
+ struct pci_bus *bridge;
+ uint32_t tmp;
+ uint16_t tmp16;
+ pci_dev_t pcidev = dev->busdevfun;
+ int i, maxbars;
+
+ if (dev->flags & PCI_DEV_BRIDGE) {
+ /* PCI-PCI Bridge */
+ bridge = (struct pci_bus *)dev;
+
+ /* Only 2 Bridge BARs */
+ maxbars = 2;
+
+ /* Probe Bridge Spaces (MEMIO space always implemented), the
+ * probe disables all space-decoding at the same time
+ */
+ PCI_CFG_W32(pcidev, 0x30, 0);
+ PCI_CFG_W16(pcidev, 0x1c, 0x00f0);
+ PCI_CFG_R16(pcidev, 0x1c, &tmp16);
+ if (tmp16 != 0) {
+ bridge->flags |= PCI_BUS_IO;
+ if (tmp16 & 0x1)
+ bridge->flags |= PCI_BUS_IO32;
+ }
+
+ PCI_CFG_W32(pcidev, 0x24, 0x0000ffff);
+ PCI_CFG_R32(pcidev, 0x24, &tmp);
+ if (tmp != 0)
+ bridge->flags |= PCI_BUS_MEM;
+
+ PCI_CFG_W32(pcidev, 0x20, 0x0000ffff);
+ bridge->flags |= PCI_BUS_MEMIO;
+ } else {
+ /* Normal PCI Device as max 6 BARs */
+ maxbars = 6;
+ }
+
+ /* Probe BARs */
+ for (i = 0; i < maxbars; i++)
+ pci_find_bar(dev, i);
+ pci_find_bar(dev, DEV_RES_ROM);
+
+ return 0;
+}
+
+int pci_add_res_dev(struct pci_dev *dev, void *arg);
+
+void pci_add_res_bus(struct pci_bus *bus, int type)
+{
+ int tindex = type - 1;
+
+ /* Clear old resources */
+ bus->busres[tindex] = NULL;
+
+ /* Add resources of devices behind bridge if bridge supports
+ * resource type. If MEM space not supported by bridge, they are
+ * converted to MEMIO in the process.
+ */
+ if (!((type == PCI_BUS_IO) && ((bus->flags & PCI_BUS_IO) == 0))) {
+ pci_for_each_child(bus, pci_add_res_dev, (void *)type, 0);
+
+ /* Reorder Bus resources to fit more optimally (avoid dead
+ * PCI space). Currently they are sorted by boundary and size.
+ *
+ * This is especially important when multiple buses (bridges)
+ * are present.
+ */
+ pci_res_reorder(bus->busres[tindex]);
+ }
+}
+
+int pci_add_res_dev(struct pci_dev *dev, void *arg)
+{
+ int tindex, type = (int)arg;
+ struct pci_bus *bridge;
+ struct pci_res *res, *first_busres;
+ int i;
+ uint32_t bbound;
+
+ /* Type index in Bus resource */
+ tindex = type - 1;
+
+ if (dev->flags & PCI_DEV_BRIDGE) {
+ /* PCI-PCI Bridge. Add all sub-bus resources first */
+ bridge = (struct pci_bus *)dev;
+
+ /* Add all child device's resources to this type */
+ pci_add_res_bus(bridge, type);
+
+ /* Propagate the resources from child bus to BAR on
+ * this bus, by adding a "fake" BAR per type.
+ */
+ res = &bridge->dev.resources[BUS_RES_START + tindex];
+ res->bar = BUS_RES_START + tindex;
+ res->start = 0;
+ res->end = 0;
+ res->flags = 0; /* mark BAR resource not available */
+ first_busres = bridge->busres[tindex];
+ if (first_busres) {
+ res->flags = type;
+ res->size = pci_res_size(first_busres);
+ res->boundary = first_busres->boundary;
+ if (type == PCI_RES_IO) {
+ bbound = 0x1000; /* Bridge I/O min 4KB */
+ } else {
+ bbound = 0x100000; /* Bridge MEM min 1MB */
+
+ /* Convert MEM to MEMIO if not supported by
+ * this bridge
+ */
+ if ((bridge->flags & PCI_BUS_MEM) == 0)
+ res->flags = PCI_RES_MEMIO;
+ }
+ /* Fulfil minimum bridge boundary */
+ if (res->boundary < bbound)
+ res->boundary = bbound;
+ /* Make sure that size is atleast bridge boundary */
+ if (res->size > bbound && (res->size & (bbound-1)))
+ res->size = (res->size | (bbound-1)) + 1;
+ }
+ }
+
+ /* Normal PCI Device as max 6 BARs and a ROM Bar.
+ * Insert BARs into the sorted resource list.
+ */
+ for (i = 0; i < DEV_RES_CNT; i++) {
+ res = &dev->resources[i];
+ if ((res->flags & PCI_RES_TYPE_MASK) != type)
+ continue;
+ pci_res_insert(&dev->bus->busres[tindex], res);
+ }
+
+ return 0;
+}
+
+/* Function assumes that base is properly aligned to the requirement of the
+ * largest BAR in the system.
+ */
+uint32_t pci_alloc_res(struct pci_bus *bus, int type,
+ uint32_t start, uint32_t end)
+{
+ struct pci_dev *dev;
+ struct pci_res *res, **prev_next;
+ unsigned long starttmp;
+ struct pci_bus *bridge;
+ int removed, sec_type;
+
+ /* The resources are sorted on their size (size and alignment is the
+ * same)
+ */
+ prev_next = &bus->busres[type - 1];
+ while ((res = *prev_next) != NULL) {
+
+ dev = RES2DEV(res);
+ removed = 0;
+
+ /* Align start to this reource's need, only needed after
+ * a bridge resource has been allocated.
+ */
+ starttmp = (start + (res->boundary-1)) & ~(res->boundary-1);
+
+ if ((starttmp + res->size - 1) > end) {
+ /* Not enough memory available for this resource */
+ printk("PCI[%x:%x:%x]: DEV BAR%d (%d): no resource "
+ "assigned\n",
+ PCI_DEV_EXPAND(dev->busdevfun),
+ res->bar, res->flags & PCI_RES_TYPE_MASK);
+ res->start = res->end = 0;
+
+ /* If this resources is a bridge window to the
+ * secondary bus, the secondary resources are not
+ * changed which has the following effect:
+ * I/O : Will never be assigned
+ * MEMIO : Will never be assigned
+ * MEM : Will stay marked as MEM, but bridge window
+ * is changed into MEMIO, when the window is
+ * assigned a MEMIO address the secondary
+ * resources will also be assigned.
+ */
+
+ if (type == PCI_RES_MEM) {
+ /* Try prefetchable as non-prefetchable mem */
+ res->flags &= ~PCI_RES_MEM_PREFETCH;
+ /* Remove resource from MEM list, ideally we
+ * should regenerate this list in order to fit
+ * the comming BARs more optimially...
+ */
+ *prev_next = res->next;
+ /* We should not update prev_next here since
+ * we just removed the resource from the list
+ */
+ removed = 1;
+ } else {
+ res->flags |= PCI_RES_FAIL;
+ dev->flags |= PCI_DEV_RES_FAIL;
+ }
+ } else {
+ start = starttmp;
+
+ res->start = start;
+ res->end = start + res->size;
+
+ /* "Virtual BAR" on a bridge? A bridge resource need all
+ * its child devices resources allocated
+ */
+ if ((res->bar != DEV_RES_ROM) &&
+ (dev->flags & PCI_DEV_BRIDGE) &&
+ (res->bar >= BUS_RES_START)) {
+ bridge = (struct pci_bus *)dev;
+ /* If MEM bar was changed into a MEMIO the
+ * secondary MEM resources are still set to MEM,
+ */
+ if (type == PCI_BUS_MEMIO &&
+ res->bar == BRIDGE_RES_MEM)
+ sec_type = PCI_RES_MEM;
+ else
+ sec_type = type;
+
+ pci_alloc_res(bridge, sec_type, res->start,
+ res->end);
+ }
+
+ start += res->size;
+ }
+ if (removed == 0)
+ prev_next = &res->next;
+ }
+
+ return start;
+}
+
+void pci_set_bar(struct pci_dev *dev, int residx)
+{
+ uint32_t tmp;
+ uint16_t tmp16;
+ pci_dev_t pcidev;
+ struct pci_res *res;
+ int is_bridge, ofs;
+
+ res = &dev->resources[residx];
+ pcidev = dev->busdevfun;
+
+ if ((res->flags == 0) || (res->flags & PCI_RES_FAIL))
+ return;
+
+ is_bridge = dev->flags & PCI_DEV_BRIDGE;
+
+ if (res->bar == DEV_RES_ROM) {
+ /* ROM: 32-bit prefetchable memory BAR */
+ if (is_bridge)
+ ofs = PCI_ROM_ADDRESS1;
+ else
+ ofs = PCI_ROM_ADDRESS;
+ PCI_CFG_W32(pcidev, ofs, res->start | PCI_ROM_ADDRESS_ENABLE);
+ DBG("PCI[%x:%x:%x]: ROM BAR: 0x%x-0x%x\n",
+ PCI_DEV_EXPAND(pcidev), res->start, res->end);
+ } else if (is_bridge && (res->bar == BRIDGE_RES_IO)) {
+ /* PCI Bridge I/O BAR */
+ DBG("PCI[%x:%x:%x]: BAR 1C: 0x%x-0x%x\n",
+ PCI_DEV_EXPAND(pcidev), res->start, res->end);
+
+ /* Limit and Base */
+ tmp16 = ((res->end-1) & 0x0000f000) |
+ ((res->start & 0x0000f000) >> 8);
+ tmp = ((res->end-1) & 0xffff0000) | (res->start >> 16);
+
+ DBG("PCI[%x:%x:%x]: BRIDGE BAR 0x%x: 0x%08x [0x30: 0x%x]\n",
+ PCI_DEV_EXPAND(pcidev), 0x1C, tmp, tmp2);
+ PCI_CFG_W16(pcidev, 0x1C, tmp16);
+ PCI_CFG_W32(pcidev, 0x30, tmp);
+ } else if (is_bridge && (res->bar >= BRIDGE_RES_MEMIO)) {
+ /* PCI Bridge MEM and MEMIO Space */
+
+ /* Limit and Base */
+ tmp = ((res->end-1) & 0xfff00000) | (res->start >> 16);
+
+ DBG("PCI[%x:%x:%x]: BRIDGE BAR 0x%x: 0x%08x\n",
+ PCI_DEV_EXPAND(pcidev),
+ 0x20 + (res->bar-BRIDGE_RES_MEMIO)*4, tmp);
+ PCI_CFG_W32(pcidev, 0x20+(res->bar-BRIDGE_RES_MEMIO)*4, tmp);
+ } else {
+ /* PCI Device */
+ DBG("PCI[%x:%x:%x]: DEV BAR%d: 0x%08x\n",
+ PCI_DEV_EXPAND(pcidev), res->bar, res->start);
+ ofs = PCI_BASE_ADDRESS_0 + res->bar*4;
+ PCI_CFG_W32(pcidev, ofs, res->start);
+ }
+
+ /* Enable Memory or I/O responses */
+ if ((res->flags & PCI_RES_TYPE_MASK) == PCI_RES_IO)
+ pci_io_enable(pcidev);
+ else
+ pci_mem_enable(pcidev);
+
+ /* Enable Master if bridge */
+ if (is_bridge)
+ pci_master_enable(pcidev);
+}
+
+int pci_set_res_dev(struct pci_dev *dev, void *unused)
+{
+ int i, maxbars;
+
+ if (dev->flags & PCI_DEV_BRIDGE)
+ maxbars = 2 + 3; /* 2 BARs + 3 Bridge-Windows "Virtual BARs" */
+ else
+ maxbars = 6; /* Normal PCI Device as max 6 BARs. */
+
+ /* Set BAR resources with previous allocated values */
+ for (i = 0; i < maxbars; i++)
+ pci_set_bar(dev, i);
+ pci_set_bar(dev, DEV_RES_ROM);
+
+ return 0;
+}
+
+/* Route IRQ through PCI-PCI Bridges */
+int pci_route_irq(pci_dev_t dev, int irq_pin)
+{
+ int slot_grp;
+
+ if (PCI_DEV_BUS(dev) == 0)
+ return irq_pin;
+
+ slot_grp = PCI_DEV_SLOT(dev) & 0x3;
+
+ return (((irq_pin - 1) + slot_grp) & 0x3) + 1;
+}
+
+/* Put assigned system IRQ into PCI interrupt line information field.
+ * This is to make it possible for drivers to read system IRQ / Vector from
+ * configuration space later on.
+ *
+ * 1. Get Interrupt PIN
+ * 2. Route PIN to bus 0, if not on root PCI bus
+ * 3. Get System interrupt number assignment for PIN
+ * 4. Set Interrupt LINE
+ */
+int pci_set_irq_dev(struct pci_dev *dev, void *cfg)
+{
+ struct pci_auto_setup *autocfg = cfg;
+ uint8_t irq_pin, irq_line, *psysirq;
+ pci_dev_t pcidev;
+
+ psysirq = &dev->sysirq;
+ pcidev = dev->busdevfun;
+ PCI_CFG_R8(pcidev, PCI_INTERRUPT_PIN, &irq_pin);
+
+ /* If behind bridge, perform IRQ routing */
+ while (dev->bus->dev.bus && irq_pin != 0) {
+ irq_pin = autocfg->irq_route(dev->busdevfun, irq_pin);
+ dev = &dev->bus->dev;
+ }
+
+ /* Get IRQ from PIN on PCI bus0 */
+ if (irq_pin != 0)
+ irq_line = autocfg->irq_map(dev->busdevfun, irq_pin);
+ else
+ irq_line = 0;
+
+ *psysirq = irq_line;
+
+ /* Set System Interrupt/Vector for device. 0 means no-IRQ */
+ PCI_CFG_W8(pcidev, PCI_INTERRUPT_LINE, irq_line);
+
+ return 0;
+}
+
+/* This routine assumes that PCI access library has been successfully
+ * initialized. All information about the PCI bus needed is found in
+ * the argument.
+ *
+ * The PCI buses are enumerated as bridges are found, PCI devices are
+ * setup with BARs and IRQs, etc.
+ */
+int pci_config_auto(void)
+{
+ uint32_t end;
+ uint32_t startmemio, endmemio;
+ uint32_t startmem, endmem;
+ uint32_t startio, endio;
+ struct pci_auto_setup *autocfg = &pci_auto_cfg;
+#ifdef DEBUG
+ uint32_t start;
+#endif
+
+ if (pci_config_auto_initialized == 0)
+ return -1; /* no config given to library */
+
+#ifdef DEBUG
+ DBG("\n--- PCI MEMORY AVAILABLE ---\n");
+ if (autocfg->mem_size) {
+ start = autocfg->mem_start;
+ end = autocfg->mem_start + autocfg->mem_size - 1;
+ DBG(" MEM AVAIL [0x%08x-0x%08x]\n", start, end);
+ } else {
+ /* One big memory space */
+ DBG(" MEM share the space with MEMIO\n");
+ }
+ /* no-prefetchable memory space need separate memory space.
+ * For example PCI controller maps this region non-cachable.
+ */
+ start = autocfg->memio_start;
+ end = autocfg->memio_start + autocfg->memio_size - 1;
+ DBG(" MEMIO AVAIL [0x%08x-0x%08x]\n", start, end);
+ if (autocfg->io_size) {
+ start = autocfg->io_start;
+ end = autocfg->io_start + autocfg->io_size - 1;
+ DBG(" I/O AVAIL [0x%08x-0x%08x]\n", start, end);
+ } else {
+ DBG(" I/O Space not available\n");
+ }
+#endif
+
+ /* Init Host-Bridge */
+ memset(&pci_hb, 0, sizeof(pci_hb));
+ pci_hb.dev.flags = PCI_DEV_BRIDGE;
+ if (autocfg->memio_size <= 0)
+ return -1;
+ pci_hb.flags = PCI_BUS_MEMIO;
+ if (autocfg->mem_size)
+ pci_hb.flags |= PCI_BUS_MEM;
+ if (autocfg->io_size)
+ pci_hb.flags |= PCI_BUS_IO;
+
+ /* Find all PCI devices/functions on all buses. The buses will be
+ * enumrated (assigned a unique PCI Bus ID 0..255).
+ */
+ DBG("\n--- PCI SCANNING ---\n");
+ pci_find_devs(&pci_hb);
+ pci_bus_cnt = pci_hb.sord + 1;
+ if (pci_hb.devs == NULL)
+ return 0;
+
+ pci_system_type = PCI_SYSTEM_HOST;
+
+ /* Find all resources (MEM/MEMIO/IO BARs) of all devices/functions
+ * on all buses.
+ *
+ * Device resources behind bridges which does not support prefetchable
+ * memory are already marked as non-prefetchable memory.
+ * Devices which as I/O resources behind a bridge that do not support
+ * I/O space are marked DISABLED.
+ *
+ * All BARs and Bridge Spaces are disabled after this. Only the ones
+ * that are allocated an address are initilized later on.
+ */
+ DBG("\n\n--- PCI RESOURCES ---\n");
+ pci_for_each_dev(pci_find_res_dev, 0);
+
+ /* Add all device's resources to bus and sort them to fit in the PCI
+ * Window. The device resources are propagated upwards through bridges
+ * by adding a "virtual" BAR (boundary != BAR size).
+ *
+ * We wait with MEMIO (non-prefetchable memory) resources to after MEM
+ * resources have been allocated, so that MEM resources can be changed
+ * into MEMIO resources if not enough space.
+ */
+ pci_add_res_bus(&pci_hb, PCI_RES_IO);
+ pci_add_res_bus(&pci_hb, PCI_RES_MEM);
+
+ /* Start assigning found resource according to the sorted order. */
+
+ /* Allocate resources to I/O areas */
+ if (pci_hb.busres[BUS_RES_IO]) {
+ startio = autocfg->io_start;
+ end = startio + autocfg->io_size;
+ endio = pci_alloc_res(&pci_hb, PCI_RES_IO, startio, end);
+ }
+
+ /* Allocate resources to prefetchable memory */
+ if (pci_hb.busres[BUS_RES_MEM]) {
+ startmem = autocfg->mem_start;
+ end = startmem + autocfg->mem_size;
+ endmem = pci_alloc_res(&pci_hb, PCI_RES_MEM, startmem, end);
+ }
+
+ /* Add non-prefetchable memory resources and not fitting prefetchable
+ * memory resources.
+ *
+ * Some prefetchable memory resources may not have fitted into PCI
+ * window. Prefetchable memory can be mapped into non-prefetchable
+ * memory window. The failing BARs have been marked as MEMIO instead.
+ */
+ pci_add_res_bus(&pci_hb, PCI_RES_MEMIO);
+
+ /* Allocate resources to non-prefetchable memory */
+ if (pci_hb.busres[BUS_RES_MEMIO]) {
+ startmemio = autocfg->memio_start;
+ end = startmemio + autocfg->memio_size;
+ endmemio = pci_alloc_res(&pci_hb, PCI_RES_MEMIO, startmemio,
+ end);
+ }
+
+ DBG("\n--- PCI ALLOCATED SPACE RANGES ---\n");
+ DBG(" MEM NON-PREFETCHABLE: [0x%08x-0x%08x]\n", startmemio, endmemio);
+ DBG(" MEM PREFETCHABLE: [0x%08x-0x%08x]\n", startmem, endmem);
+ DBG(" I/O: [0x%08x-0x%08x]\n", startio, endio);
+
+ /* Set all allocated BARs and Bridge Windows */
+ pci_for_each_dev(pci_set_res_dev, NULL);
+
+ /* Initialize IRQs of all devices. According to the PCI-PCI bridge
+ * specification the IRQs are routed differently depending on slot
+ * number. On bus 0 PCI IRQs are routed 1:1. Drivers can override
+ * the default routing if a motherboard requires it.
+ */
+ if ((autocfg->options & CFGOPT_NOSETUP_IRQ) == 0) {
+ if (autocfg->irq_route == NULL) /* use standard irq routing */
+ autocfg->irq_route = pci_route_irq;
+ pci_for_each_dev(pci_set_irq_dev, autocfg);
+ }
+
+ DBG("PCI resource allocation done\n");
+
+ return 0;
+}
+
+void pci_config_auto_register(void *config)
+{
+ pci_config_auto_initialized = 1;
+ memcpy(&pci_auto_cfg, config, sizeof(struct pci_auto_setup));
+}
diff --git a/cpukit/libpci/pci_cfg_peripheral.c b/cpukit/libpci/pci_cfg_peripheral.c
new file mode 100644
index 0000000000..bd9c3c2343
--- /dev/null
+++ b/cpukit/libpci/pci_cfg_peripheral.c
@@ -0,0 +1,32 @@
+/* PCI (Peripheral) Configuration Library
+ *
+ * COPYRIGHT (c) 2011.
+ * Aeroflex Gaisler Research
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2011-05-23, Daniel Hellstrom <daniel@gaisler.com>
+ * created
+ *
+ * The Host Bridge bus must be declared by user. It contain the static
+ * configuration used to setup the devices/functions.
+ */
+
+/* Configure headers */
+#define PCI_CFG_PERIPHERAL_LIB
+
+#include <pci/cfg.h>
+
+/* Number of buses */
+extern int pci_bus_cnt;
+
+/* Assume that user has defined static setup array in pci_hb */
+int pci_config_peripheral(void)
+{
+ pci_bus_cnt = pci_hb.sord + 1;
+ pci_system_type = PCI_SYSTEM_PERIPHERAL;
+
+ return 0;
+}
diff --git a/cpukit/libpci/pci_cfg_print_code.c b/cpukit/libpci/pci_cfg_print_code.c
new file mode 100644
index 0000000000..c6d75a96fe
--- /dev/null
+++ b/cpukit/libpci/pci_cfg_print_code.c
@@ -0,0 +1,163 @@
+/* PCI Configuration C code console printout routines */
+
+#include <rtems.h>
+#include <stdio.h>
+#include <pci/cfg.h>
+
+int pci_cfg_print_bus(struct pci_bus *bus);
+
+static void get_bus_name(struct pci_bus *bus, char *buf)
+{
+ if (bus->num == 0)
+ strcpy(buf, "pci_hb");
+ else
+ sprintf(buf, "bus%d", bus->num);
+}
+
+static void get_device_name(struct pci_dev *dev, char *buf)
+{
+ char busname[64];
+
+ if (dev->flags & PCI_DEV_BRIDGE) {
+ get_bus_name((struct pci_bus *)dev, busname);
+ sprintf(buf, "%s.dev", busname);
+ } else {
+ sprintf(buf, "dev_%x_%x_%x", PCI_DEV_EXPAND(dev->busdevfun));
+ }
+}
+
+void pci_cfg_print_resources(struct pci_res *resources, char *prefix)
+{
+ struct pci_res *res;
+ int i;
+
+ for (i = 0; i < DEV_RES_CNT; i++) {
+ res = &resources[i];
+ if (((res->flags & PCI_RES_TYPE_MASK) == 0) ||
+ ((res->flags & PCI_RES_FAIL) == PCI_RES_FAIL)) {
+ printf("%sPCIRES_EMPTY,\n", prefix);
+ continue;
+ }
+ printf("%s{\n", prefix);
+ printf("%s\t.next = NULL,\n", prefix);
+ printf("%s\t.size = 0x%08lx,\n", prefix, res->size);
+ printf("%s\t.boundary = 0x%08lx,\n", prefix, res->boundary);
+ printf("%s\t.flags = 0x%x,\n", prefix, res->flags);
+ printf("%s\t.bar = %d,\n", prefix, i);
+ printf("%s\t.start = 0x%08lx,\n", prefix, res->start);
+ printf("%s\t.end = 0x%08lx,\n", prefix, res->end);
+ printf("%s},\n", prefix);
+ }
+}
+
+void pci_cfg_print_device(struct pci_dev *dev, char *prefix)
+{
+ char name[32];
+ char buf[8];
+ printf("%s.resources = {\n", prefix);
+ strcpy(buf, prefix);
+ strcat(buf, "\t");
+ pci_cfg_print_resources(dev->resources, buf);
+ printf("%s},\n", prefix);
+ if (dev->next == NULL) {
+ printf("%s.next = NULL,\n", prefix);
+ } else {
+ get_device_name(dev->next, name);
+ printf("%s.next = &%s,\n", prefix, name);
+ }
+ if (!dev->bus) { /* Host Bridge? */
+ printf("%s.bus = NULL,\n", prefix);
+ } else {
+ get_bus_name(dev->bus, name);
+ printf("%s.bus = &%s,\n", prefix, name);
+ }
+
+ printf("%s.busdevfun = 0x%04x,\n", prefix, dev->busdevfun);
+ printf("%s.flags = 0x%x,\n", prefix, dev->flags);
+ printf("%s.sysirq = %d,\n", prefix, dev->sysirq);
+ printf("%s.vendor = 0x%04x,\n", prefix, dev->vendor);
+ printf("%s.device = 0x%04x,\n", prefix, dev->device);
+ printf("%s.subvendor = 0x%04x,\n", prefix, dev->subvendor);
+ printf("%s.subdevice = 0x%04x,\n", prefix, dev->subdevice);
+ printf("%s.classrev = 0x%08lx,\n", prefix, dev->classrev);
+ printf("%s.command = 0,\n", prefix);
+}
+
+int pci_cfg_print_dev(struct pci_dev *dev, void *unused)
+{
+ if (dev->flags & PCI_DEV_BRIDGE) {
+ pci_cfg_print_bus((struct pci_bus *)dev);
+ } else {
+ printf("\n\n/* PCI DEV at [%x:%x:%x] */\n",
+ PCI_DEV_EXPAND(dev->busdevfun));
+ printf("static struct pci_dev dev_%x_%x_%x = {\n",
+ PCI_DEV_EXPAND(dev->busdevfun));
+ pci_cfg_print_device(dev, "\t");
+ printf("};\n");
+ }
+ return 0;
+}
+
+int pci_cfg_print_bus(struct pci_bus *bus)
+{
+ char name[32];
+
+ /* Print Bus */
+ printf("\n\n/* PCI BUS %d - Bridge at [%x:%x:%x] */\n\n",
+ bus->num, PCI_DEV_EXPAND(bus->dev.busdevfun));
+ get_bus_name(bus, name);
+ printf("%sstruct pci_bus %s = {\n",
+ bus->num == 0 ? "" : "static ", name);
+ printf("\t.dev = {\n");
+ pci_cfg_print_device(&bus->dev, "\t\t");
+ printf("\t},\n");
+ if (bus->devs == NULL) {
+ printf("\t.devs = NULL,\n");
+ } else {
+ get_device_name(bus->devs, name);
+ printf("\t.devs = &%s,\n", name);
+ }
+ printf("\t.flags = 0x%x,\n", bus->flags);
+ printf("\t.num = %d,\n", bus->num);
+ printf("\t.pri = %d,\n", bus->pri);
+ printf("\t.sord = %d,\n", bus->sord);
+ printf("};\n");
+
+ /* Print all child devices */
+ pci_for_each_child(bus, pci_cfg_print_dev, NULL, 0);
+
+ return 0;
+}
+
+int pci_cfg_print_forw_dev(struct pci_dev *dev, void *unused)
+{
+ if ((dev->flags & PCI_DEV_BRIDGE) == 0) {
+ printf("static struct pci_dev dev_%x_%x_%x;\n",
+ PCI_DEV_EXPAND(dev->busdevfun));
+ }
+ return 0;
+}
+
+void pci_cfg_print(void)
+{
+ int i;
+
+ printf("\n\n/*** PCI Configuration ***/\n\n");
+ printf("#include <stdlib.h>\n");
+ printf("#define PCI_CFG_STATIC_LIB\n");
+ printf("#include <pci/cfg.h>\n\n");
+ printf("#define PCIRES_EMPTY {0}\n\n");
+
+ /* Forward declaration for all devices / buses */
+ printf("/* FORWARD BUS DECLARATIONS */\n");
+ for (i = 0; i < pci_bus_count(); i++) {
+ if (i == 0)
+ printf("struct pci_bus pci_hb;\n");
+ else
+ printf("static struct pci_bus bus%d;\n", i);
+ }
+ printf("\n/* FORWARD DEVICE DECLARATIONS */\n");
+ pci_for_each_dev(pci_cfg_print_forw_dev, NULL);
+
+ pci_cfg_print_bus(&pci_hb);
+}
diff --git a/cpukit/libpci/pci_cfg_read.c b/cpukit/libpci/pci_cfg_read.c
new file mode 100644
index 0000000000..7efcb57282
--- /dev/null
+++ b/cpukit/libpci/pci_cfg_read.c
@@ -0,0 +1,360 @@
+/* Read current PCI configuration that bootloader or BIOS has already setup
+ * and initialize the PCI structures.
+ *
+ * COPYRIGHT (c) 2010-2011.
+ * Aeroflex Gaisler Research
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2011-03-04, Daniel Hellstrom <daniel@gaisler.com>
+ * created
+ */
+
+#include <rtems.h>
+#include <stdlib.h>
+#include <rtems/bspIo.h>
+#include <pci/cfg.h>
+#include <pci/access.h>
+
+/* PCI Library
+ * (For debugging it might be good to use other functions or the driver's
+ * directly)
+ */
+#define PCI_CFG_R8(dev, args...) pci_cfg_r8(dev, args)
+#define PCI_CFG_R16(dev, args...) pci_cfg_r16(dev, args)
+#define PCI_CFG_R32(dev, args...) pci_cfg_r32(dev, args)
+#define PCI_CFG_W8(dev, args...) pci_cfg_w8(dev, args)
+#define PCI_CFG_W16(dev, args...) pci_cfg_w16(dev, args)
+#define PCI_CFG_W32(dev, args...) pci_cfg_w32(dev, args)
+
+#ifdef DEBUG
+#define DBG(args...) printk(args)
+#else
+#define DBG(args...)
+#endif
+
+/* Number of buses */
+extern int pci_bus_cnt;
+
+/* The Host Bridge bus is initialized here */
+extern struct pci_bus pci_hb;
+
+struct pci_dev *pci_dev_create(int isbus)
+{
+ void *ptr;
+ int size;
+
+ if (isbus)
+ size = sizeof(struct pci_bus);
+ else
+ size = sizeof(struct pci_dev);
+
+ ptr = malloc(size);
+ if (!ptr)
+ rtems_fatal_error_occurred(RTEMS_NO_MEMORY);
+ memset(ptr, 0, size);
+ return ptr;
+}
+
+/* Check if address is accessible from host */
+int pci_read_addressable(struct pci_dev *dev, struct pci_res *res)
+{
+ struct pci_bus *bus = dev->bus;
+ int type = res->flags & PCI_RES_TYPE_MASK;
+ struct pci_res *range0, *range1;
+
+ if (type == PCI_BUS_IO && (bus->flags & PCI_BUS_IO) == 0)
+ return 0;
+
+ /* Assume that host bridge can access all */
+ if (bus->pri == 0)
+ return 1;
+
+ range1 = NULL;
+ switch (type) {
+ case PCI_RES_IO:
+ range0 = &bus->dev.resources[BRIDGE_RES_IO];
+ break;
+ case PCI_RES_MEM:
+ range1 = &bus->dev.resources[BRIDGE_RES_MEM];
+ default:
+ case PCI_RES_MEMIO:
+ range0 = &bus->dev.resources[BRIDGE_RES_MEMIO];
+ break;
+ }
+ if ((res->start >= range0->start) && (res->end <= range0->end)) {
+ return pci_read_addressable(&bus->dev, range0);
+ } else if (range1 && (res->start >= range1->start) &&
+ (res->end <= range1->end)) {
+ return pci_read_addressable(&bus->dev, range1);
+ }
+
+ return 0;
+}
+
+void pci_read_bar(struct pci_dev *dev, int bar)
+{
+ uint32_t orig, size, disable, mask;
+ struct pci_res *res = &dev->resources[bar];
+ char *str;
+ pci_dev_t pcidev = dev->busdevfun;
+ int ofs;
+
+ DBG("Bus: %x, Slot: %x, function: %x, bar%d\n",
+ PCI_DEV_EXPAND(pcidev), bar);
+
+ res->bar = bar;
+ if (bar == DEV_RES_ROM) {
+ if (dev->flags & PCI_DEV_BRIDGE)
+ ofs = PCI_ROM_ADDRESS1;
+ else
+ ofs = PCI_ROM_ADDRESS;
+ disable = 0; /* ROM BARs have a unique enable bit per BAR */
+ } else {
+ ofs = PCI_BASE_ADDRESS_0 + (bar << 2);
+ disable = pci_invalid_address;
+ }
+
+ PCI_CFG_R32(pcidev, ofs, &orig);
+ PCI_CFG_W32(pcidev, ofs, 0xffffffff);
+ PCI_CFG_R32(pcidev, ofs, &size);
+ PCI_CFG_W32(pcidev, ofs, orig);
+
+ if (size == 0 || size == 0xffffffff)
+ return;
+ if (bar == DEV_RES_ROM) {
+ mask = PCI_ROM_ADDRESS_MASK;
+ str = "ROM";
+ if (dev->bus->flags & PCI_BUS_MEM)
+ res->flags = PCI_RES_MEM;
+ else
+ res->flags = PCI_RES_MEMIO;
+ } else if (((size & 0x1) == 0) && (size & 0x6)) {
+ /* unsupported Memory type */
+ return;
+ } else {
+ mask = ~0xf;
+ if (size & 0x1) {
+ /* I/O */
+ mask = ~0x3;
+ res->flags = PCI_RES_IO;
+ str = "I/O";
+ if (size & 0xffff0000)
+ res->flags |= PCI_RES_IO32;
+ /* Limit size of I/O space to 256 byte */
+ size |= 0xffffff00;
+ if ((dev->bus->flags & PCI_BUS_IO) == 0) {
+ res->flags |= PCI_RES_FAIL;
+ dev->flags |= PCI_DEV_RES_FAIL;
+ }
+ } else {
+ /* Memory */
+ if (size & 0x8) {
+ /* Prefetchable */
+ res->flags = PCI_RES_MEM;
+ str = "MEM";
+ } else {
+ res->flags = PCI_RES_MEMIO;
+ str = "MEMIO";
+ }
+ }
+ }
+ res->start = orig & mask;
+ size &= mask;
+ res->size = ~size + 1;
+ res->boundary = res->size;
+ res->end = res->start + res->size;
+
+ DBG("Bus: %x, Slot: %x, function: %x, %s bar%d size: %x\n",
+ PCI_DEV_EXPAND(pcidev), str, bar, res->size);
+
+ /* Check if BAR is addressable by host */
+ if (pci_read_addressable(dev, res) == 0) {
+ /* No matching bridge window contains this BAR */
+ res->flags |= PCI_RES_FAIL;
+ dev->flags |= PCI_DEV_RES_FAIL;
+ }
+}
+
+void pci_read_devs(struct pci_bus *bus)
+{
+ uint32_t id, tmp;
+ uint16_t tmp16;
+ uint8_t header;
+ int slot, func, fail, i, maxbars, max_sord;
+ struct pci_dev *dev, **listptr;
+ struct pci_bus *bridge;
+ pci_dev_t pcidev;
+ struct pci_res *res;
+
+ DBG("Scanning bus %d\n", bus->num);
+
+ max_sord = bus->num;
+ listptr = &bus->devs;
+ slot = 0;
+ if (bus->num == 0)
+ slot = 1; /* Skip PCI HOST BRIDGE */
+ for (; slot < PCI_MAX_DEVICES; slot++) {
+
+ /* Slot address */
+ pcidev = PCI_DEV(bus->num, slot, 0);
+
+ for (func = 0; func < PCI_MAX_FUNCTIONS; func++, pcidev++) {
+
+ fail = PCI_CFG_R32(pcidev, PCI_VENDOR_ID, &id);
+ if (fail || id == 0xffffffff || id == 0) {
+ /*
+ * This slot is empty
+ */
+ if (func == 0)
+ break;
+ else
+ continue;
+ }
+
+ DBG("Found PCIDEV 0x%x at (bus %x, slot %x, func %x)\n",
+ id, bus, slot, func);
+
+ PCI_CFG_R32(pcidev, PCI_CLASS_REVISION, &tmp);
+ tmp >>= 16;
+ dev = pci_dev_create(tmp == PCI_CLASS_BRIDGE_PCI);
+ *listptr = dev;
+ listptr = &dev->next;
+
+ dev->busdevfun = pcidev;
+ dev->bus = bus;
+ PCI_CFG_R16(pcidev, PCI_VENDOR_ID, &dev->vendor);
+ PCI_CFG_R16(pcidev, PCI_DEVICE_ID, &dev->device);
+ PCI_CFG_R32(pcidev, PCI_CLASS_REVISION, &dev->classrev);
+
+ if (tmp == PCI_CLASS_BRIDGE_PCI) {
+ DBG("Found PCI-PCI Bridge 0x%x at "
+ "(bus %x, slot %x, func %x)\n",
+ id, bus, slot, func);
+ dev->flags = PCI_DEV_BRIDGE;
+ bridge = (struct pci_bus *)dev;
+
+ PCI_CFG_R32(pcidev, PCI_PRIMARY_BUS, &tmp);
+ bridge->pri = tmp & 0xff;
+ bridge->num = (tmp >> 8) & 0xff;
+ bridge->sord = (tmp >> 16) & 0xff;
+ if (bridge->sord > max_sord)
+ max_sord = bridge->sord;
+
+ DBG(" Primary %x, Secondary %x, "
+ "Subordinate %x\n",
+ bridge->pri, bridge->num, bridge->sord);
+
+ /*** Probe Bridge Spaces ***/
+
+ /* MEMIO Window - always implemented */
+ bridge->flags = PCI_BUS_MEMIO;
+ res = &bridge->dev.resources[BRIDGE_RES_MEMIO];
+ res->flags = PCI_RES_MEMIO;
+ res->bar = BRIDGE_RES_MEMIO;
+ PCI_CFG_R32(pcidev, 0x20, &tmp);
+ res->start = (tmp & 0xfff0) << 16;
+ res->end = 1 + ((tmp & 0xfff00000) | 0xfffff);
+ if (res->end <= res->start) {
+ /* Window disabled */
+ res->end = res->start = 0;
+ }
+ res->size = res->end - res->start;
+
+ /* I/O Window - optional */
+ res = &bridge->dev.resources[BRIDGE_RES_IO];
+ res->bar = BRIDGE_RES_IO;
+ PCI_CFG_R32(pcidev, 0x30, &tmp);
+ PCI_CFG_R16(pcidev, 0x1c, &tmp16);
+ if (tmp != 0 || tmp16 != 0) {
+ bridge->flags |= PCI_BUS_IO;
+ res->flags = PCI_RES_IO;
+ if (tmp16 & 0x1) {
+ bridge->flags |= PCI_BUS_IO32;
+ res->flags |= PCI_RES_IO32;
+ }
+
+ res->start = (tmp & 0xffff) << 16 |
+ (tmp16 & 0xf0) << 8;
+ res->end = 1 + ((tmp & 0xffff0000) |
+ (tmp16 & 0xf000) |
+ 0xfff);
+ if (res->end <= res->start) {
+ /* Window disabled */
+ res->end = res->start = 0;
+ }
+ res->size = res->end - res->start;
+ }
+
+ /* MEM Window - optional */
+ res = &bridge->dev.resources[BRIDGE_RES_MEM];
+ res->bar = BRIDGE_RES_MEM;
+ PCI_CFG_R32(pcidev, 0x24, &tmp);
+ if (tmp != 0) {
+ bridge->flags |= PCI_BUS_MEM;
+ res->flags = PCI_RES_MEM;
+ res->start = (tmp & 0xfff0) << 16;
+ res->end = 1 + ((tmp & 0xfff00000) |
+ 0xfffff);
+ if (res->end <= res->start) {
+ /* Window disabled */
+ res->end = res->start = 0;
+ }
+ res->size = res->end - res->start;
+ }
+
+ /* Scan Secondary Bus */
+ pci_read_devs(bridge);
+
+ /* Only 2 BARs for Bridges */
+ maxbars = 2;
+ } else {
+ /* Devices have subsytem device and vendor ID */
+ PCI_CFG_R16(pcidev, PCI_SUBSYSTEM_VENDOR_ID,
+ &dev->subvendor);
+ PCI_CFG_R16(pcidev, PCI_SUBSYSTEM_ID,
+ &dev->subdevice);
+
+ /* Normal PCI Device has max 6 BARs */
+ maxbars = 6;
+ }
+
+ /* Probe BARs */
+ for (i = 0; i < maxbars; i++)
+ pci_read_bar(dev, i);
+ pci_read_bar(dev, DEV_RES_ROM);
+
+ /* Get System Interrupt/Vector for device.
+ * 0 means no-IRQ
+ */
+ PCI_CFG_R8(pcidev, PCI_INTERRUPT_LINE, &dev->sysirq);
+
+ /* Stop if not a multi-function device */
+ if (func == 0) {
+ pci_cfg_r8(pcidev, PCI_HEADER_TYPE, &header);
+ if ((header & PCI_MULTI_FUNCTION) == 0)
+ break;
+ }
+ }
+ }
+
+ if (bus->num == 0)
+ bus->sord = max_sord;
+}
+
+int pci_config_read(void)
+{
+ pci_system_type = PCI_SYSTEM_HOST;
+
+ /* Find all devices and buses */
+ pci_hb.flags = PCI_BUS_IO|PCI_BUS_MEMIO|PCI_BUS_MEM;
+ pci_hb.dev.flags = PCI_DEV_BRIDGE;
+ pci_read_devs(&pci_hb);
+ pci_bus_cnt = pci_hb.sord + 1;
+ if (pci_hb.devs == NULL)
+ return 0;
+
+ return 0;
+}
diff --git a/cpukit/libpci/pci_cfg_static.c b/cpukit/libpci/pci_cfg_static.c
new file mode 100644
index 0000000000..ff4277cb21
--- /dev/null
+++ b/cpukit/libpci/pci_cfg_static.c
@@ -0,0 +1,158 @@
+/* PCI (Static) Configuration Library
+ *
+ * COPYRIGHT (c) 2010-2011.
+ * Aeroflex Gaisler Research
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2011-02-11, Daniel Hellstrom <daniel@gaisler.com>
+ * created
+ *
+ * The Host Bridge bus must be declared by user. It contains the static
+ * configuration used to setup the devices/functions.
+ */
+
+/* Configure headers */
+#define PCI_CFG_STATIC_LIB
+
+#include <stdlib.h>
+#include <pci.h>
+#include <pci/access.h>
+#include <pci/cfg.h>
+
+#define PCI_CFG_R8(dev, args...) pci_cfg_r8(dev, args)
+#define PCI_CFG_R16(dev, args...) pci_cfg_r16(dev, args)
+#define PCI_CFG_R32(dev, args...) pci_cfg_r32(dev, args)
+#define PCI_CFG_W8(dev, args...) pci_cfg_w8(dev, args)
+#define PCI_CFG_W16(dev, args...) pci_cfg_w16(dev, args)
+#define PCI_CFG_W32(dev, args...) pci_cfg_w32(dev, args)
+
+/* Number of buses */
+extern int pci_bus_cnt;
+
+/* Enumrate one bus if device is a bridge, and all it's subordinate buses */
+static int pci_init_dev(struct pci_dev *dev, void *unused)
+{
+ uint32_t tmp;
+ uint16_t tmp16, cmd;
+ struct pci_bus *bridge;
+ int maxbars, i, romofs;
+ pci_dev_t pcidev = dev->busdevfun;
+ struct pci_res *res;
+
+ /* Init Device */
+
+ /* Set command to reset values, it disables bus
+ * mastering and address responses.
+ */
+ PCI_CFG_W16(pcidev, PCI_COMMAND, 0);
+
+ /* Clear any already set status bits */
+ PCI_CFG_W16(pcidev, PCI_STATUS, 0xf900);
+
+ /* Set latency timer to 64 */
+ PCI_CFG_W8(pcidev, PCI_LATENCY_TIMER, 64);
+
+ /* Set System IRQ of PIN */
+ PCI_CFG_W8(pcidev, PCI_INTERRUPT_LINE, dev->sysirq);
+
+ cmd = dev->command;
+
+ if ((dev->flags & PCI_DEV_BRIDGE) == 0) {
+ /* Disable Cardbus CIS Pointer */
+ PCI_CFG_W32(pcidev, PCI_CARDBUS_CIS, 0);
+
+ romofs = PCI_ROM_ADDRESS;
+ maxbars = 6;
+ } else {
+ /* Init Bridge */
+
+ /* Configure bridge (no support for 64-bit) */
+ PCI_CFG_W32(pcidev, PCI_PREF_BASE_UPPER32, 0);
+ PCI_CFG_W32(pcidev, PCI_PREF_LIMIT_UPPER32, 0);
+
+ bridge = (struct pci_bus *)dev;
+ tmp = (64 << 24) | (bridge->sord << 16) |
+ (bridge->num << 8) | bridge->pri;
+ PCI_CFG_W32(pcidev, PCI_PRIMARY_BUS, tmp);
+
+ /*** Setup I/O Bridge Window ***/
+ res = &dev->resources[BRIDGE_RES_IO];
+ if (res->size > 0) {
+ tmp16 = ((res->end-1) & 0x0000f000) |
+ ((res->start & 0x0000f000) >> 8);
+ tmp = ((res->end-1) & 0xffff0000) | (res->start >> 16);
+ cmd |= PCI_COMMAND_IO;
+ } else {
+ tmp16 = 0x00ff;
+ tmp = 0;
+ }
+ /* I/O Limit and Base */
+ PCI_CFG_W16(pcidev, PCI_IO_BASE, tmp16);
+ PCI_CFG_W32(pcidev, PCI_IO_BASE_UPPER16, tmp);
+
+ /*** Setup MEMIO Bridge Window ***/
+ res = &dev->resources[BRIDGE_RES_MEMIO];
+ if (res->size > 0) {
+ tmp = ((res->end-1) & 0xffff0000) |
+ (res->start >> 16);
+ cmd |= PCI_COMMAND_MEMORY;
+ } else {
+ tmp = 0x0000ffff;
+ }
+ /* MEMIO Limit and Base */
+ PCI_CFG_W32(pcidev, PCI_MEMORY_BASE, tmp);
+
+ /*** Setup MEM Bridge Window ***/
+ res = &dev->resources[BRIDGE_RES_MEM];
+ if (res->size > 0) {
+ tmp = ((res->end-1) & 0xffff0000) |
+ (res->start >> 16);
+ cmd |= PCI_COMMAND_MEMORY;
+ } else {
+ tmp = 0x0000ffff;
+ }
+ /* MEM Limit and Base */
+ PCI_CFG_W32(pcidev, PCI_PREF_MEMORY_BASE, tmp);
+ /* 64-bit space not supported */
+ PCI_CFG_W32(pcidev, PCI_PREF_BASE_UPPER32, 0);
+ PCI_CFG_W32(pcidev, PCI_PREF_LIMIT_UPPER32, 0);
+
+ cmd |= PCI_COMMAND_MASTER;
+ romofs = PCI_ROM_ADDRESS1;
+ maxbars = 2;
+ }
+
+ /* Init BARs */
+ for (i = 0; i < maxbars; i++) {
+ res = &dev->resources[i];
+ if (res->flags & PCI_RES_TYPE_MASK) {
+ PCI_CFG_W32(pcidev, PCI_BASE_ADDRESS_0 + 4*i,
+ res->start);
+ if ((res->flags & PCI_RES_TYPE_MASK) == PCI_RES_IO)
+ cmd |= PCI_COMMAND_IO;
+ else
+ cmd |= PCI_COMMAND_MEMORY;
+ }
+ }
+ res = &dev->resources[DEV_RES_ROM];
+ if (res->flags & PCI_RES_TYPE_MASK) {
+ PCI_CFG_W32(pcidev, romofs, res->start|PCI_ROM_ADDRESS_ENABLE);
+ cmd |= PCI_COMMAND_MEMORY;
+ }
+ PCI_CFG_W16(pcidev, PCI_COMMAND, cmd);
+
+ return 0;
+}
+
+/* Assume that user has defined static setup array in pci_hb */
+int pci_config_static(void)
+{
+ pci_bus_cnt = pci_hb.sord + 1;
+ pci_system_type = PCI_SYSTEM_HOST;
+
+ /* Init all PCI devices according to depth-first search algorithm */
+ return pci_for_each_dev(pci_init_dev, NULL);
+}
diff --git a/cpukit/libpci/pci_find.c b/cpukit/libpci/pci_find.c
new file mode 100644
index 0000000000..bdf711b828
--- /dev/null
+++ b/cpukit/libpci/pci_find.c
@@ -0,0 +1,55 @@
+/* PCI Help function, Find a PCI device by VENDOR/DEVICE ID
+ *
+ * COPYRIGHT (c) 2010-2011.
+ * Aeroflex Gaisler Research
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2011-02-12, Daniel Hellstrom <daniel@gaisler.com>
+ * new implementation based on pci_for_each() to reduce footprint
+ */
+
+#include <pci.h>
+#include <pci/access.h>
+
+struct compare_info {
+ int index;
+ uint16_t vendor;
+ uint16_t device;
+};
+
+static int compare_dev_id(pci_dev_t pcidev, void *arg)
+{
+ struct compare_info *info = arg;
+ uint16_t vid, did;
+
+ pci_cfg_r16(pcidev, PCI_VENDOR_ID, &vid);
+ pci_cfg_r16(pcidev, PCI_DEVICE_ID, &did);
+ if ((vid != info->vendor) || (did != info->device))
+ return 0;
+ if (info->index-- == 0)
+ return pcidev;
+ else
+ return 0;
+}
+
+/* Find a Device in PCI configuration space */
+int pci_find(uint16_t ven, uint16_t dev, int index, pci_dev_t *pdev)
+{
+ struct compare_info info;
+ int result;
+
+ info.index = index;
+ info.vendor = ven;
+ info.device = dev;
+
+ result = pci_for_each(compare_dev_id, &info);
+ if (pdev)
+ *pdev = (pci_dev_t)result;
+ if (result == 0)
+ return -1;
+ else
+ return 0;
+}
diff --git a/cpukit/libpci/pci_find_dev.c b/cpukit/libpci/pci_find_dev.c
new file mode 100644
index 0000000000..f74a126a1e
--- /dev/null
+++ b/cpukit/libpci/pci_find_dev.c
@@ -0,0 +1,52 @@
+/* PCI Help function, Find a PCI device by VENDOR/DEVICE ID
+ *
+ * COPYRIGHT (c) 2010-2011.
+ * Aeroflex Gaisler Research
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2011-02-12, Daniel Hellstrom <daniel@gaisler.com>
+ * new implementation based on pci_for_each() to reduce footprint
+ */
+
+#include <pci.h>
+#include <pci/cfg.h>
+
+struct compare_info {
+ int index;
+ uint16_t vendor;
+ uint16_t device;
+};
+
+static int compare_dev_id(struct pci_dev *dev, void *arg)
+{
+ struct compare_info *info = arg;
+
+ if ((dev->vendor != info->vendor) || (dev->device != info->device))
+ return 0;
+ if (info->index-- == 0)
+ return (int)dev;
+ else
+ return 0;
+}
+
+/* Find a Device in PCI device tree located in RAM */
+int pci_find_dev(uint16_t ven, uint16_t dev, int index, struct pci_dev **ppdev)
+{
+ struct compare_info info;
+ int result;
+
+ info.index = index;
+ info.vendor = ven;
+ info.device = dev;
+
+ result = pci_for_each_dev(compare_dev_id, &info);
+ if (ppdev)
+ *ppdev = (struct pci_dev *)result;
+ if (result == 0)
+ return -1;
+ else
+ return 0;
+}
diff --git a/cpukit/libpci/pci_for_each.c b/cpukit/libpci/pci_for_each.c
new file mode 100644
index 0000000000..195eb17d7c
--- /dev/null
+++ b/cpukit/libpci/pci_for_each.c
@@ -0,0 +1,68 @@
+/* PCI Help Function, Iterate over all PCI devices
+ *
+ * COPYRIGHT (c) 2010-2011.
+ * Aeroflex Gaisler Research
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2011-02-11, Daniel Hellstrom <daniel@gaisler.com>
+ * created from pci_bus.c
+ */
+
+#include <pci.h>
+#include <pci/access.h>
+
+/*#define DEBUG*/
+
+#ifdef DEBUG
+#include <rtems/bspIo.h>
+#define DBG(args...) printk(args)
+#else
+#define DBG(args...)
+#endif
+
+int pci_for_each(int (*func)(pci_dev_t, void*), void *arg)
+{
+ uint32_t id;
+ uint8_t hd;
+ int bus, dev, fun, result, fail;
+ int maxbus = pci_bus_count();
+ pci_dev_t pcidev;
+
+ for (bus = 0; bus < maxbus ; bus++) {
+ dev = 0;
+ if (bus == 0)
+ dev = 1; /* Skip PCI host bridge */
+ for (; dev < PCI_MAX_DEVICES; dev++) {
+ pcidev = PCI_DEV(bus, dev, 0);
+
+ for (fun = 0; fun < PCI_MAX_FUNCTIONS; fun++, pcidev++) {
+ fail = pci_cfg_r32(pcidev, PCI_VENDOR_ID, &id);
+ if (fail || (0xffffffff == id) || (0 == id)) {
+ if (fun == 0)
+ break;
+ else
+ continue;
+ }
+
+ DBG("pcibus_for_each: found 0x%08lx at"
+ " %d/%d/%d\n", id, bus, dev, fun);
+ result = func(pcidev, arg);
+ if (result != 0)
+ return result; /* Stopped */
+
+ /* Stop if not a multi-function device */
+ if (fun == 0) {
+ pci_cfg_r8(pcidev, PCI_HEADER_TYPE,
+ &hd);
+ if ((hd & PCI_MULTI_FUNCTION) == 0)
+ break;
+ }
+ }
+ }
+ }
+
+ return 0; /* scanned all */
+}
diff --git a/cpukit/libpci/pci_for_each_child.c b/cpukit/libpci/pci_for_each_child.c
new file mode 100644
index 0000000000..5730601132
--- /dev/null
+++ b/cpukit/libpci/pci_for_each_child.c
@@ -0,0 +1,31 @@
+#include <pci/cfg.h>
+
+/* Iterate over all PCI devices on a bus (not child buses) and call func(),
+ * iteration is stopped if a non-zero value is returned by func().
+ *
+ * search options: 0 (no child buses), 1 (depth first), 2 (breadth first)
+ */
+int pci_for_each_child(
+ struct pci_bus *bus,
+ int (*func)(struct pci_dev *, void *arg),
+ void *arg,
+ int search)
+{
+ struct pci_dev *dev = bus->devs;
+ int ret;
+
+ while (dev) {
+ ret = func(dev, arg);
+ if (ret)
+ return ret;
+ if (search == SEARCH_DEPTH && (dev->flags & PCI_DEV_BRIDGE)) {
+ ret = pci_for_each_child((struct pci_bus *)dev,
+ func, arg, search);
+ if (ret)
+ return ret;
+ }
+ dev = dev->next;
+ }
+
+ return 0;
+}
diff --git a/cpukit/libpci/pci_for_each_dev.c b/cpukit/libpci/pci_for_each_dev.c
new file mode 100644
index 0000000000..d17f14d416
--- /dev/null
+++ b/cpukit/libpci/pci_for_each_dev.c
@@ -0,0 +1,8 @@
+#include <pci/cfg.h>
+
+int pci_for_each_dev(
+ int (*func)(struct pci_dev *, void *arg),
+ void *arg)
+{
+ return pci_for_each_child(&pci_hb, func, arg, SEARCH_DEPTH);
+}
diff --git a/cpukit/libpci/pci_get_dev.c b/cpukit/libpci/pci_get_dev.c
new file mode 100644
index 0000000000..8be3b07135
--- /dev/null
+++ b/cpukit/libpci/pci_get_dev.c
@@ -0,0 +1,39 @@
+/* PCI Help function, Find a PCI device by BUS|SLOT|FUNCTION
+ *
+ * COPYRIGHT (c) 2010-2011.
+ * Aeroflex Gaisler Research
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2011-07-04, Daniel Hellstrom <daniel@gaisler.com>
+ * Created
+ */
+
+#include <pci.h>
+#include <pci/cfg.h>
+
+static int compare_dev_pcidev(struct pci_dev *dev, void *arg)
+{
+ pci_dev_t pcidev = (unsigned)arg;
+
+ if (dev->busdevfun == pcidev)
+ return (int)dev;
+ else
+ return 0;
+}
+
+/* Get a Device in PCI device tree located in RAM by PCI BUS|SLOT|FUNCTION */
+int pci_get_dev(pci_dev_t pcidev, struct pci_dev **ppdev)
+{
+ int result;
+
+ result = pci_for_each_dev(compare_dev_pcidev, (void *)(unsigned)pcidev);
+ if (ppdev)
+ *ppdev = (struct pci_dev *)result;
+ if (result == 0)
+ return -1;
+ else
+ return 0;
+}
diff --git a/cpukit/libpci/pci_irq.c b/cpukit/libpci/pci_irq.c
new file mode 100644
index 0000000000..8d2a9b3466
--- /dev/null
+++ b/cpukit/libpci/pci_irq.c
@@ -0,0 +1,22 @@
+/* PCI IRQ Library
+ *
+ * COPYRIGHT (c) 2010-2011.
+ * Aeroflex Gaisler Research
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2011-02-11, Daniel Hellstrom <daniel@gaisler.com>
+ * created
+ */
+
+#include <pci.h>
+#include <pci/access.h>
+
+int pci_dev_irq(pci_dev_t dev)
+{
+ uint8_t irq_line;
+ pci_cfg_r8(dev, PCI_INTERRUPT_LINE, &irq_line);
+ return irq_line;
+}
diff --git a/cpukit/libpci/pci_print.c b/cpukit/libpci/pci_print.c
new file mode 100644
index 0000000000..6eaf3b4fae
--- /dev/null
+++ b/cpukit/libpci/pci_print.c
@@ -0,0 +1,197 @@
+/* PCI Print Current Configuration To Terminal
+ *
+ * COPYRIGHT (c) 2010-2011.
+ * Aeroflex Gaisler Research
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * 2011-02-11, Daniel Hellstrom <daniel@gaisler.com>
+ * created from old code
+ */
+
+#include <stdio.h>
+#include <pci.h>
+#include <pci/access.h>
+
+/* PCI Access Library shortcuts */
+#define PCI_CFG_R8(dev, args...) pci_cfg_r8(dev, args)
+#define PCI_CFG_R16(dev, args...) pci_cfg_r16(dev, args)
+#define PCI_CFG_R32(dev, args...) pci_cfg_r32(dev, args)
+#define PCI_CFG_W8(dev, args...) pci_cfg_w8(dev, args)
+#define PCI_CFG_W16(dev, args...) pci_cfg_w16(dev, args)
+#define PCI_CFG_W32(dev, args...) pci_cfg_w32(dev, args)
+
+void pci_print_dev(pci_dev_t dev)
+{
+ int maxbars, pos, romadrs;
+ uint32_t tmp, tmp2, id;
+ uint16_t irq;
+ uint8_t irq_pin;
+ char *str, *str2;
+ uint32_t base, limit;
+
+ maxbars = 6;
+ romadrs = 0x30;
+ str = "";
+ PCI_CFG_R32(dev, PCI_CLASS_REVISION, &tmp);
+ tmp >>= 16;
+ if (tmp == PCI_CLASS_BRIDGE_PCI) {
+ maxbars = 2;
+ romadrs = 0x38;
+ str = "(BRIDGE)";
+ }
+
+ PCI_CFG_R32(dev, PCI_VENDOR_ID, &id);
+ printf("\nBus %x Slot %x function: %x [0x%x] %s\n",
+ PCI_DEV_EXPAND(dev), dev, str);
+ printf("\tVendor id: 0x%lx, device id: 0x%lx\n",
+ id & 0xffff, id >> 16);
+ if (maxbars == 2) {
+ PCI_CFG_R32(dev, PCI_PRIMARY_BUS, &tmp);
+ printf("\tPrimary: %lx Secondary: %lx Subordinate: %lx\n",
+ tmp & 0xff, (tmp >> 8) & 0xff, (tmp >> 16) & 0xff);
+ }
+
+ PCI_CFG_R16(dev, PCI_INTERRUPT_LINE, &irq);
+ irq_pin = irq >> 8;
+ if ((irq_pin > 0) && (irq_pin < 5))
+ printf("\tIRQ INT%c# LINE: %d\n",
+ (irq_pin - 1) + 'A', (irq & 0xff));
+
+ /* Print standard BARs */
+ for (pos = 0; pos < maxbars; pos++) {
+ PCI_CFG_R32(dev, PCI_BASE_ADDRESS_0 + pos*4, &tmp);
+ PCI_CFG_W32(dev, PCI_BASE_ADDRESS_0 + pos*4, 0xffffffff);
+ PCI_CFG_R32(dev, PCI_BASE_ADDRESS_0 + pos*4, &tmp2);
+ PCI_CFG_W32(dev, PCI_BASE_ADDRESS_0 + pos*4, tmp);
+
+ if (tmp2 != 0 && tmp2 != 0xffffffff && ((tmp2 & 0x1) ||
+ ((tmp2 & 0x6) == 0))) {
+ uint32_t mask = ~0xf;
+ if ((tmp2 & 0x1) == 1) {
+ /* I/O Bar */
+ mask = ~3;
+ tmp2 = tmp2 | 0xffffff00;
+ }
+ tmp2 &= mask;
+ tmp2 = ~tmp2+1; /* Size of BAR */
+ if (tmp2 < 0x1000) {
+ str = "B";
+ } else if (tmp2 < 0x100000) {
+ str = "kB";
+ tmp2 = tmp2 / 1024;
+ } else {
+ str = "MB";
+ tmp2 = tmp2 / (1024*1024);
+ }
+ printf("\tBAR %d: %lx [%lu%s]\n", pos, tmp, tmp2, str);
+ }
+ }
+
+ /* Print ROM BARs */
+ PCI_CFG_R32(dev, romadrs, &tmp);
+ PCI_CFG_W32(dev, romadrs, 0xffffffff);
+ PCI_CFG_R32(dev, romadrs, &tmp2);
+ PCI_CFG_W32(dev, romadrs, tmp);
+ if (tmp2 & 1) {
+ /* ROM BAR available */
+ tmp2 &= PCI_ROM_ADDRESS_MASK;
+ tmp2 = (~tmp2 + 1); /* Size of BAR */
+ if (tmp2 < 0x1000) {
+ str = "B";
+ } else if (tmp2 < 0x100000) {
+ str = "kB";
+ tmp2 = tmp2 / 1024;
+ } else {
+ str = "MB";
+ tmp2 = tmp2 / (1024*1024);
+ }
+ str2 = tmp & 1 ? "ENABLED" : "DISABLED";
+ printf("\tROM: %08lx [%lu%s] (%s)\n",
+ tmp, tmp2, str, str2);
+ }
+
+ /* Print Bridge addresses */
+ if (maxbars == 2) {
+ tmp = 0;
+ PCI_CFG_R32(dev, 0x1C, &tmp);
+ if (tmp != 0) {
+ base = (tmp & 0x00f0) << 8;
+ limit = (tmp & 0xf000) | 0xfff;
+ PCI_CFG_R32(dev, 0x30, &tmp);
+ base |= (tmp & 0xffff) << 16;
+ limit |= (tmp & 0xffff0000);
+ str = "ENABLED";
+ if (limit < base)
+ str = "DISABLED";
+ printf("\tI/O: BASE: 0x%08lx, LIMIT: 0x%08lx (%s)\n",
+ base, limit, str);
+ }
+
+ PCI_CFG_R32(dev, 0x20, &tmp);
+ if (tmp != 0) {
+ base = (tmp & 0xfff0) << 16;
+ limit = (tmp & 0xfff00000) | 0xfffff;
+ str = "ENABLED";
+ if (limit < base)
+ str = "DISABLED";
+ printf("\tMEMIO: BASE: 0x%08lx, LIMIT: 0x%08lx (%s)\n",
+ base, limit, str);
+ }
+
+ PCI_CFG_R32(dev, 0x24, &tmp);
+ if (tmp != 0) {
+ base = (tmp & 0xfff0) << 16;
+ limit = (tmp & 0xfff00000) | 0xfffff;
+ str = "ENABLED";
+ if (limit < base)
+ str = "DISABLED";
+ printf("\tMEM: BASE: 0x%08lx, LIMIT: 0x%08lx (%s)\n",
+ base, limit, str);
+ }
+ }
+ printf("\n");
+}
+
+void pci_print_device(int bus, int slot, int function)
+{
+ pci_print_dev(PCI_DEV(bus, slot, function));
+}
+
+void pci_print(void)
+{
+ int fail, bus, slot, func;
+ pci_dev_t dev;
+ uint8_t header;
+ uint32_t id;
+
+ printf("\nPCI devices found and configured:\n");
+ for (bus = 0; bus < pci_bus_count(); bus++) {
+ slot = 0;
+ if (bus == 0)
+ slot = 1;
+ for (; slot < PCI_MAX_DEVICES; slot++) {
+
+ for (func=0; func < PCI_MAX_FUNCTIONS; func++) {
+
+ dev = PCI_DEV(bus, slot, func);
+ fail = PCI_CFG_R32(dev, PCI_VENDOR_ID, &id);
+
+ if (!fail && id != PCI_INVALID_VENDORDEVICEID && id != 0) {
+ pci_print_dev(dev);
+
+ /* Stop if not a multi-function device */
+ if (func == 0) {
+ PCI_CFG_R8(dev, PCI_HEADER_TYPE, &header);
+ if ((header & PCI_MULTI_FUNCTION) == 0)
+ break;
+ }
+ } else if (func == 0)
+ break;
+ }
+ }
+ }
+ printf("\n");
+}
diff --git a/cpukit/libpci/preinstall.am b/cpukit/libpci/preinstall.am
new file mode 100644
index 0000000000..6f378ee3df
--- /dev/null
+++ b/cpukit/libpci/preinstall.am
@@ -0,0 +1,74 @@
+## Automatically generated by ampolish3 - Do not edit
+
+if AMPOLISH3
+$(srcdir)/preinstall.am: Makefile.am
+ $(AMPOLISH3) $(srcdir)/Makefile.am > $(srcdir)/preinstall.am
+endif
+
+PREINSTALL_DIRS =
+DISTCLEANFILES = $(PREINSTALL_DIRS)
+
+all-am: $(PREINSTALL_FILES)
+
+PREINSTALL_FILES =
+CLEANFILES = $(PREINSTALL_FILES)
+
+$(PROJECT_INCLUDE)/$(dirstamp):
+ @$(MKDIR_P) $(PROJECT_INCLUDE)
+ @: > $(PROJECT_INCLUDE)/$(dirstamp)
+PREINSTALL_DIRS += $(PROJECT_INCLUDE)/$(dirstamp)
+
+$(PROJECT_INCLUDE)/pci.h: pci.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/pci.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/pci.h
+
+$(PROJECT_INCLUDE)/pci/$(dirstamp):
+ @$(MKDIR_P) $(PROJECT_INCLUDE)/pci
+ @: > $(PROJECT_INCLUDE)/pci/$(dirstamp)
+PREINSTALL_DIRS += $(PROJECT_INCLUDE)/pci/$(dirstamp)
+
+$(PROJECT_INCLUDE)/pci/access.h: pci/access.h $(PROJECT_INCLUDE)/pci/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/pci/access.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/pci/access.h
+
+$(PROJECT_INCLUDE)/pci/cfg.h: pci/cfg.h $(PROJECT_INCLUDE)/pci/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/pci/cfg.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/pci/cfg.h
+
+$(PROJECT_INCLUDE)/pci/cfg_auto.h: pci/cfg_auto.h $(PROJECT_INCLUDE)/pci/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/pci/cfg_auto.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/pci/cfg_auto.h
+
+$(PROJECT_INCLUDE)/pci/cfg_static.h: pci/cfg_static.h $(PROJECT_INCLUDE)/pci/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/pci/cfg_static.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/pci/cfg_static.h
+
+$(PROJECT_INCLUDE)/pci/cfg_peripheral.h: pci/cfg_peripheral.h $(PROJECT_INCLUDE)/pci/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/pci/cfg_peripheral.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/pci/cfg_peripheral.h
+
+$(PROJECT_INCLUDE)/pci/cfg_read.h: pci/cfg_read.h $(PROJECT_INCLUDE)/pci/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/pci/cfg_read.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/pci/cfg_read.h
+
+$(PROJECT_INCLUDE)/pci/ids.h: pci/ids.h $(PROJECT_INCLUDE)/pci/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/pci/ids.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/pci/ids.h
+
+$(PROJECT_INCLUDE)/pci/ids_extra.h: pci/ids_extra.h $(PROJECT_INCLUDE)/pci/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/pci/ids_extra.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/pci/ids_extra.h
+
+$(PROJECT_INCLUDE)/pci/irq.h: pci/irq.h $(PROJECT_INCLUDE)/pci/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/pci/irq.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/pci/irq.h
+
+$(PROJECT_INCLUDE)/drvmgr/$(dirstamp):
+ @$(MKDIR_P) $(PROJECT_INCLUDE)/drvmgr
+ @: > $(PROJECT_INCLUDE)/drvmgr/$(dirstamp)
+PREINSTALL_DIRS += $(PROJECT_INCLUDE)/drvmgr/$(dirstamp)
+
+$(PROJECT_INCLUDE)/drvmgr/pci_bus.h: pci_bus.h $(PROJECT_INCLUDE)/drvmgr/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/drvmgr/pci_bus.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/drvmgr/pci_bus.h
+
diff --git a/cpukit/preinstall.am b/cpukit/preinstall.am
index b430f793c2..bf691c575a 100644
--- a/cpukit/preinstall.am
+++ b/cpukit/preinstall.am
@@ -376,3 +376,20 @@ $(PROJECT_INCLUDE)/rtems/fsmount.h: libmisc/fsmount/fsmount.h $(PROJECT_INCLUDE)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/fsmount.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/fsmount.h
+$(PROJECT_INCLUDE)/drvmgr/$(dirstamp):
+ @$(MKDIR_P) $(PROJECT_INCLUDE)/drvmgr
+ @: > $(PROJECT_INCLUDE)/drvmgr/$(dirstamp)
+PREINSTALL_DIRS += $(PROJECT_INCLUDE)/drvmgr/$(dirstamp)
+
+$(PROJECT_INCLUDE)/drvmgr/drvmgr.h: libdrvmgr/drvmgr.h $(PROJECT_INCLUDE)/drvmgr/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/drvmgr/drvmgr.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/drvmgr/drvmgr.h
+
+$(PROJECT_INCLUDE)/drvmgr/drvmgr_confdefs.h: libdrvmgr/drvmgr_confdefs.h $(PROJECT_INCLUDE)/drvmgr/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/drvmgr/drvmgr_confdefs.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/drvmgr/drvmgr_confdefs.h
+
+$(PROJECT_INCLUDE)/drvmgr/drvmgr_list.h: libdrvmgr/drvmgr_list.h $(PROJECT_INCLUDE)/drvmgr/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/drvmgr/drvmgr_list.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/drvmgr/drvmgr_list.h
+
diff --git a/cpukit/sapi/include/confdefs.h b/cpukit/sapi/include/confdefs.h
index 929f72643c..6d2509d671 100644
--- a/cpukit/sapi/include/confdefs.h
+++ b/cpukit/sapi/include/confdefs.h
@@ -2234,6 +2234,52 @@ rtems_fs_init_functions_t rtems_fs_init_helper =
#endif
#endif
+/*
+ * Select PCI Configuration Library
+ */
+#ifdef RTEMS_PCI_CONFIG_LIB
+ #ifdef CONFIGURE_INIT
+ #define PCI_LIB_NONE 0
+ #define PCI_LIB_AUTO 1
+ #define PCI_LIB_STATIC 2
+ #define PCI_LIB_READ 3
+ #define PCI_LIB_PERIPHERAL 4
+ #if CONFIGURE_PCI_LIB == PCI_LIB_AUTO
+ #define PCI_CFG_AUTO_LIB
+ #include <pci/cfg.h>
+ struct pci_bus pci_hb;
+ #define PCI_LIB_INIT pci_config_auto
+ #define PCI_LIB_CONFIG pci_config_auto_register
+ #elif CONFIGURE_PCI_LIB == PCI_LIB_STATIC
+ #define PCI_CFG_STATIC_LIB
+ #include <pci/cfg.h>
+ #define PCI_LIB_INIT pci_config_static
+ #define PCI_LIB_CONFIG NULL
+ /* Let user define PCI configuration (struct pci_bus pci_hb) */
+ #elif CONFIGURE_PCI_LIB == PCI_LIB_READ
+ #define PCI_CFG_READ_LIB
+ #include <pci/cfg.h>
+ #define PCI_LIB_INIT pci_config_read
+ #define PCI_LIB_CONFIG NULL
+ struct pci_bus pci_hb;
+ #elif CONFIGURE_PCI_LIB == PCI_LIB_PERIPHERAL
+ #define PCI_LIB_INIT pci_config_peripheral
+ #define PCI_LIB_CONFIG NULL
+ /* Let user define PCI configuration (struct pci_bus pci_hb) */
+ #elif CONFIGURE_PCI_LIB == PCI_LIB_NONE
+ #define PCI_LIB_INIT NULL
+ #define PCI_LIB_CONFIG NULL
+ /* No PCI Configuration at all, user can use/debug access routines */
+ #else
+ #error NO PCI LIBRARY DEFINED
+ #endif
+
+ const int pci_config_lib_type = CONFIGURE_PCI_LIB;
+ int (*pci_config_lib_init)(void) = PCI_LIB_INIT;
+ void (*pci_config_lib_register)(void *config) = PCI_LIB_CONFIG;
+ #endif
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/cpukit/sapi/src/exinit.c b/cpukit/sapi/src/exinit.c
index b0574f3b34..286f58884d 100644
--- a/cpukit/sapi/src/exinit.c
+++ b/cpukit/sapi/src/exinit.c
@@ -58,6 +58,9 @@
#ifdef RTEMS_ITRON_API
#include <rtems/itron/itronapi.h>
#endif
+#ifdef RTEMS_DRVMGR_STARTUP
+ #include <drvmgr/drvmgr.h>
+#endif
Objects_Information *_Internal_Objects[ OBJECTS_INTERNAL_CLASSES_LAST + 1 ];
@@ -91,6 +94,10 @@ void rtems_initialize_data_structures(void)
_System_state_Handler_initialization( FALSE );
#endif
+ #if defined(RTEMS_MULTIPROCESSING)
+ _Objects_MP_Handler_early_initialization();
+ #endif
+
/*
* Initialize any target architecture specific support as early as possible
*/
@@ -146,6 +153,10 @@ void rtems_initialize_data_structures(void)
_IO_Manager_initialization();
+ #ifdef RTEMS_DRVMGR_STARTUP
+ _DRV_Manager_initialization();
+ #endif
+
#ifdef RTEMS_POSIX_API
_POSIX_API_Initialize();
#endif
@@ -193,8 +204,60 @@ void rtems_initialize_device_drivers(void)
* NOTE: The MPCI may be build upon a device driver.
*/
+ #ifdef RTEMS_DRVMGR_STARTUP
+ /* BSPs has already registered their "root bus" driver in the
+ * bsp_predriver hook or so.
+ *
+ * Init Drivers to Level 1, constraints:
+ * - Interrupts and system clock timer does not work.
+ * - malloc() work, however other memory services may not
+ * have been initialized yet.
+ * - initializes most basic stuff
+ *
+ * Typical setup in Level 1:
+ * - Find most devices in system, do PCI scan and configuration.
+ * - Reset hardware if needed.
+ * - Install IRQ driver
+ * - Install Timer driver
+ * - Install console driver and debug printk()
+ * - Install extra memory.
+ */
+ _DRV_Manager_init_level(1);
+ #endif
+
+ /* Initialize I/O drivers.
+ *
+ * Driver Manager note:
+ * All drivers may not be registered yet. Drivers will dynamically
+ * be initialized when registered in level 2,3 and 4.
+ */
_IO_Initialize_all_drivers();
+ #ifdef RTEMS_DRVMGR_STARTUP
+ /* Init Drivers to Level 2, constraints:
+ * - Interrupts can be registered and enabled.
+ * - System Clock is running
+ * - Console may be used.
+ *
+ * This is typically where drivers are initialized
+ * for the first time.
+ */
+ _DRV_Manager_init_level(2);
+
+ /* Init Drivers to Level 3
+ *
+ * This is typically where normal drivers are initialized
+ * for the second time, they may depend on other drivers
+ * API inited in level 2
+ */
+ _DRV_Manager_init_level(3);
+
+ /* Init Drivers to Level 4,
+ * Init drivers that depend on services initialized in Level 3
+ */
+ _DRV_Manager_init_level(4);
+ #endif
+
#if defined(RTEMS_MULTIPROCESSING)
if ( _System_state_Is_multiprocessing ) {
_MPCI_Initialization();
diff --git a/cpukit/sapi/src/io.c b/cpukit/sapi/src/io.c
index 65cb43d568..eb72f69b3b 100644
--- a/cpukit/sapi/src/io.c
+++ b/cpukit/sapi/src/io.c
@@ -24,6 +24,8 @@
#include <string.h>
+int _IO_Manager_drivers_inititalized = 0;
+
/*
* _IO_Manager_initialization
*
@@ -97,6 +99,8 @@ void _IO_Initialize_all_drivers( void )
{
rtems_device_major_number major;
+ _IO_Manager_drivers_inititalized = 1;
+
for ( major=0 ; major < _IO_Number_of_drivers ; major ++ )
(void) rtems_io_initialize( major, 0, NULL );
}
diff --git a/cpukit/sapi/src/ioregisterdriver.c b/cpukit/sapi/src/ioregisterdriver.c
index 30d10eb808..6e505a6a14 100644
--- a/cpukit/sapi/src/ioregisterdriver.c
+++ b/cpukit/sapi/src/ioregisterdriver.c
@@ -28,6 +28,8 @@
#include <rtems/rtems/intr.h>
#include <rtems/score/thread.h>
+extern int _IO_Manager_drivers_inititalized;
+
static inline bool rtems_io_is_empty_table(
const rtems_driver_address_table *table
)
@@ -111,5 +113,15 @@ rtems_status_code rtems_io_register_driver(
_Thread_Enable_dispatch();
- return rtems_io_initialize( major, 0, NULL );
+ if ( _IO_Manager_drivers_inititalized ) {
+ /* Other drivers have already been initialized, we initialize
+ * the driver directly.
+ */
+ return rtems_io_initialize( major, 0, NULL );
+ } else {
+ /* The driver will be initialized together with all other drivers
+ * in a later stage by _IO_Initialize_all_drivers().
+ */
+ return RTEMS_SUCCESSFUL;
+ }
}
diff --git a/cpukit/score/cpu/sparc/cpu_asm.S b/cpukit/score/cpu/sparc/cpu_asm.S
index e5ecc4c084..56e98b1fbe 100644
--- a/cpukit/score/cpu/sparc/cpu_asm.S
+++ b/cpukit/score/cpu/sparc/cpu_asm.S
@@ -56,7 +56,13 @@ SYM(_CPU_Context_save_fp):
or %l1, %lo(SPARC_PSR_EF_MASK), %l1
or %l0, %l1, %l0
mov %l0, %psr ! **** ENABLE FLOAT ACCESS ****
- nop; nop; nop; ! Need three nops before EF is
+ nop; nop; nop; ! Need three nops before EF is
+#ifdef SPARC_DYNAMIC_FPU_DETECTION
+ mov %psr, %l0 ! **** check whether fpu present ****
+ andcc %l0,%l1,%g0
+ beq 1f
+ nop
+#endif
ld [%i0], %l0 ! active due to pipeline delay!!!
std %f0, [%l0 + FO_F1_OFFSET]
std %f2, [%l0 + F2_F3_OFFSET]
@@ -75,7 +81,7 @@ SYM(_CPU_Context_save_fp):
std %f28, [%l0 + F28_F29_OFFSET]
std %f30, [%l0 + F3O_F31_OFFSET]
st %fsr, [%l0 + FSR_OFFSET]
- ret
+1: ret
restore
/*
@@ -105,7 +111,13 @@ SYM(_CPU_Context_restore_fp):
or %l1, %lo(SPARC_PSR_EF_MASK), %l1
or %l0, %l1, %l0
mov %l0, %psr ! **** ENABLE FLOAT ACCESS ****
- nop; nop; nop; ! Need three nops before EF is
+ nop; nop; nop; ! Need three nops before EF is
+#ifdef SPARC_DYNAMIC_FPU_DETECTION
+ mov %psr, %l0 ! **** check whether fpu present ****
+ andcc %l0,%l1,%g0
+ beq 1f
+ nop
+#endif
ld [%i0], %l0 ! active due to pipeline delay!!!
ldd [%l0 + FO_F1_OFFSET], %f0
ldd [%l0 + F2_F3_OFFSET], %f2
@@ -124,7 +136,7 @@ SYM(_CPU_Context_restore_fp):
ldd [%l0 + F28_F29_OFFSET], %f28
ldd [%l0 + F3O_F31_OFFSET], %f30
ld [%l0 + FSR_OFFSET], %fsr
- ret
+1: ret
restore
#endif /* SPARC_HAS_FPU */
@@ -616,9 +628,8 @@ dont_fix_pil2:
! o1 = 2nd arg = address of the ISF
! WAS LOADED WHEN ISF WAS SAVED!!!
- mov %l3, %o0 ! o0 = 1st arg = vector number
call %g4, 0
- nop ! delay slot
+ mov %l3, %o0 ! o0 = 1st arg = vector number
/*
* Redisable traps so we can finish up the interrupt processing.
diff --git a/cpukit/score/cpu/sparc/rtems/score/sparc.h b/cpukit/score/cpu/sparc/rtems/score/sparc.h
index f13470e0ac..a145209139 100644
--- a/cpukit/score/cpu/sparc/rtems/score/sparc.h
+++ b/cpukit/score/cpu/sparc/rtems/score/sparc.h
@@ -64,12 +64,20 @@ extern "C" {
#define SPARC_NUMBER_OF_REGISTER_WINDOWS 8
/*
+ * Compile the SPARC kernel with runtime FPU detection. This is used
+ * by RTEMS kernels built without FPU but still need to be able to
+ * run tasks with FPU enabled. This way the kernel is SPARC (v7/v8)
+ * with or without FPU compatible.
+ */
+
+#define SPARC_DYNAMIC_FPU_DETECTION 1
+
+/*
* This should be determined based on some soft float derived
* cpp predefine but gcc does not currently give us that information.
*/
-
-#if defined(_SOFT_FLOAT)
+#if !defined(SPARC_DYNAMIC_FPU_DETECTION) && defined(_SOFT_FLOAT)
#define SPARC_HAS_FPU 0
#else
#define SPARC_HAS_FPU 1
diff --git a/cpukit/wrapup/Makefile.am b/cpukit/wrapup/Makefile.am
index 9c60f8eee3..abca02a2bd 100644
--- a/cpukit/wrapup/Makefile.am
+++ b/cpukit/wrapup/Makefile.am
@@ -61,6 +61,9 @@ TMP_LIBS += ../libmisc/libuuid.a
TMP_LIBS += ../libi2c/libi2c.a
+TMP_LIBS += ../libpci/libpci.a
+TMP_LIBS += ../libdrvmgr/libdrvmgr.a
+
if LIBNETWORKING
TMP_LIBS += ../libnetworking/libnetworking.a
TMP_LIBS += ../libnetworking/libc.a
diff --git a/doc/ada_user/Makefile.am b/doc/ada_user/Makefile.am
index 822bf0700c..5f1e5b44fd 100644
--- a/doc/ada_user/Makefile.am
+++ b/doc/ada_user/Makefile.am
@@ -19,6 +19,7 @@ COMMON_FILES += \
$(top_builddir)/user/event.texi $(top_builddir)/user/fatal.texi \
$(top_builddir)/user/glossary.texi $(top_builddir)/user/init.texi \
$(top_builddir)/user/intr.texi $(top_builddir)/user/io.texi \
+ $(top_builddir)/user/libpci.texi \
$(top_builddir)/user/mp.texi $(top_builddir)/user/msg.texi \
$(top_builddir)/user/overview.texi $(top_builddir)/user/part.texi \
$(top_builddir)/user/preface.texi $(top_builddir)/user/region.texi \
diff --git a/doc/ada_user/ada_user.texi b/doc/ada_user/ada_user.texi
index 0e73505caa..c7b59d8c28 100644
--- a/doc/ada_user/ada_user.texi
+++ b/doc/ada_user/ada_user.texi
@@ -108,6 +108,7 @@
@include user/userext.texi
@include user/conf.texi
@include user/mp.texi
+@include user/libpci.texi
@include user/stackchk.texi
@include user/cpuuse.texi
@include user/object.texi
@@ -148,6 +149,7 @@ This is the online version of the RTEMS Ada User's Guide.
* User Extensions Manager::
* Configuring a System::
* Multiprocessing Manager::
+* PCI Library::
* Stack Bounds Checker::
* CPU Usage Statistics::
* Object Services::
diff --git a/doc/develenv/direct.t b/doc/develenv/direct.t
index fc0a824efc..78049552c9 100644
--- a/doc/develenv/direct.t
+++ b/doc/develenv/direct.t
@@ -455,6 +455,9 @@ TCP/IP stack to RTEMS.
This directory contains the port of the FreeBSD
RPC/XDR source to RTEMS.
+@item $@{RTEMS_ROOT@}/cpukit/libpci/
+This directory contains RTEMS PCI Library.
+
@item $@{RTEMS_ROOT@}/cpukit/posix/
This directory contains the RTEMS implementation
of the threading portions of the POSIX API.
diff --git a/doc/redo.sh b/doc/redo.sh
new file mode 100644
index 0000000000..f0bf4e79f2
--- /dev/null
+++ b/doc/redo.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+make clean
+make distclean
+../bootstrap
+./configure --enable-maintainer-mode
+cd tools; make
+cd ..
+make info
+make all
diff --git a/doc/user/Makefile.am b/doc/user/Makefile.am
index 47c29b003b..fe5b3dea74 100644
--- a/doc/user/Makefile.am
+++ b/doc/user/Makefile.am
@@ -17,7 +17,7 @@ GENERATED_FILES = overview.texi concepts.texi datatypes.texi init.texi \
task.texi intr.texi clock.texi timer.texi sem.texi msg.texi event.texi \
signal.texi part.texi region.texi dpmem.texi io.texi fatal.texi \
schedule.texi rtmon.texi barrier.texi bsp.texi userext.texi conf.texi \
- mp.texi stackchk.texi cpuuse.texi object.texi chains.texi
+ mp.texi libpci.texi stackchk.texi cpuuse.texi object.texi chains.texi
COMMON_FILES += $(top_srcdir)/common/cpright.texi
@@ -164,10 +164,15 @@ conf.texi: conf.t
mp.texi: mp.t
$(BMENU2) -p "Configuring a System Sizing the RTEMS RAM Workspace" \
-u "Top" \
+ -n "PCI Library" < $< > $@
+
+libpci.texi: libpci.t
+ $(BMENU2) -p "Multiprocessing Manager MULTIPROCESSING_ANNOUNCE - Announce the arrival of a packet" \
+ -u "Top" \
-n "Stack Bounds Checker" < $< > $@
stackchk.texi: stackchk.t
- $(BMENU2) -p "Multiprocessing Manager MULTIPROCESSING_ANNOUNCE - Announce the arrival of a packet" \
+ $(BMENU2) -p "PCI Library PCI Shell command" \
-u "Top" \
-n "CPU Usage Statistics" < $< > $@
@@ -187,7 +192,7 @@ chains.texi: chains.t
-n "Directive Status Codes" < $< > $@
EXTRA_DIST = bsp.t clock.t chains.t concepts.t cpuuse.t datatypes.t conf.t \
- dpmem.t event.t fatal.t init.t intr.t io.t mp.t msg.t overview.t \
+ dpmem.t event.t fatal.t init.t intr.t io.t libpci.t mp.t msg.t overview.t \
part.t region.t rtmon.t sem.t schedule.t signal.t stackchk.t \
task.t timer.t userext.t $(TXT_FILES) $(PNG_FILES) $(EPS_IMAGES) \
$(noinst_DATA)
diff --git a/doc/user/c_user.texi b/doc/user/c_user.texi
index eaaa419567..3eabe7e4ed 100644
--- a/doc/user/c_user.texi
+++ b/doc/user/c_user.texi
@@ -107,6 +107,7 @@
@include userext.texi
@include conf.texi
@include mp.texi
+@include libpci.texi
@include stackchk.texi
@include cpuuse.texi
@include object.texi
@@ -147,6 +148,7 @@ This is the online version of the RTEMS C User's Guide.
* User Extensions Manager::
* Configuring a System::
* Multiprocessing Manager::
+* PCI Library::
* Stack Bounds Checker::
* CPU Usage Statistics::
* Object Services::
diff --git a/doc/user/conf.t b/doc/user/conf.t
index a47ae317a6..56886df36b 100644
--- a/doc/user/conf.t
+++ b/doc/user/conf.t
@@ -926,6 +926,56 @@ implicitly uses the Ada run-time.
@end itemize
+@subsection PCI Library
+
+This section defines the system configuration paramters supported
+by @code{rtems/confdefs.h} related to configuring the PCI Library
+for RTEMS.
+
+The PCI Library startup behaviour can be configured in four diffent
+ways depending on how @code{CONFIGURE_PCI_CONFIG_LIB} is defined:
+
+@itemize @bullet
+@findex PCI_LIB_AUTO
+@item @code{PCI_LIB_AUTO} is used to enable the PCI auto configuration
+software. PCI will be automatically probed, PCI buses enumerated, all
+devices and bridges will be initialized using Plug & Play software
+routines. The PCI device tree will be populated based on the PCI devices
+found in the system, PCI devices will be configured by allocating address
+region resources automatically in PCI space according to the BSP or host
+bridge driver set up.
+
+@findex PCI_LIB_READ
+@item @code{PCI_LIB_READ} is used to enable the PCI read configuration
+software. The current PCI configuration is read to create the RAM
+representation (the PCI device tree) of the PCI devices present. PCI devices
+are assumed to already have been initialized and PCI buses enumrated, it is
+therefore required that a BIOS or a boot loader has set up configuration space
+prior to booting into RTEMS.
+
+@findex PCI_LIB_STATIC
+@item @code{PCI_LIB_STATIC} is used to enable the PCI static configuration
+software. The user provides a PCI tree with information how all PCI devices
+are to be configured at compile time by linking in a custom
+@code{struct pci_bus pci_hb} tree. The static PCI library will not probe PCI
+for devices, instead it will assume that all devices defined by the user is
+present, it will enumerate the PCI buses and configure all PCI devices in
+static configuration accordingly. Since probe and allocation software is not
+needed the startup is faster, have smaller footprint and does not require
+dynamic memory allocation.
+
+@findex PCI_LIB_PERIPHERAL
+@item @code{PCI_LIB_PERIPHERAL} is used to enable the PCI peripheral
+configuration. It is similar to @code{PCI_LIB_STATIC}, but is will never write
+the configuration to the PCI devices since PCI peripherals are not allowed to
+access PCI configuration space.
+
+@end itemize
+
+Note that selecting PCI_LIB_STATIC or PCI_LIB_PERIPHERAL but not defining
+@code{pci_hb} will reuslt in link errors. Note also that in these modes
+Plug & Play is not performed.
+
@section Configuration Table
@cindex Configuration Table
diff --git a/doc/user/libpci.t b/doc/user/libpci.t
new file mode 100644
index 0000000000..1eaca42018
--- /dev/null
+++ b/doc/user/libpci.t
@@ -0,0 +1,409 @@
+@c
+@c COPYRIGHT (c) 2011
+@c Aeroflex Gaisler AB
+@c All rights reserved.
+@c
+@c $Id: libpci.t,v v.vv xxxx/yy/zz xx:yy:zz ? Exp $
+@c
+
+@chapter PCI Library
+
+@cindex libpci
+
+@section Introduction
+
+The Peripheral Component Interconnect (PCI) bus is a very common computer
+bus architecture that is found in almost every PC today. The PCI bus is
+normally located at the motherboard where some PCI devices are soldered
+directly onto the PCB and expansion slots allows the user to add custom
+devices easily. There is a wide range of PCI hardware available implementing
+all sorts of interfaces and functions.
+
+This section describes the PCI Library available in RTEMS used to access the
+PCI bus in a portable way across computer architectures supported by RTEMS.
+
+The PCI Library aims to be compatible with PCI 2.3 with a couple of
+limitations, for example there is no support for hot-plugging, 64-bit
+memory space and cardbus bridges.
+
+In order to support different architectures and with small foot-print embedded
+systems in mind the PCI Library offers four different configuration options
+listed below. It is selected during compile time by defining the appropriate
+macros in confdefs.h. It is also possible to enable NONE (No Configuration)
+which can be used for debuging PCI access functions.
+@itemize @bullet
+@item Auto Configuration (do Plug & Play)
+@item Read Configuration (read BIOS or boot loader configuration)
+@item Static Configuration (write user defined configuration)
+@item Peripheral Configuration (no access to cfg-space)
+@end itemize
+
+@section Background
+
+The PCI bus is constructed in a way where on-board devices and devices
+in expansion slots can be automatically found (probed) and configured
+using Plug & Play completely implemented in software. The bus is set up once
+during boot up. The Plug & Play information can be read and written from
+PCI configuration space. A PCI device is identified in configuration space by
+a unique bus, slot and function number. Each PCI slot can have up to 8
+functions and interface to another PCI sub-bus by implementing a PCI-to-PCI
+bridge according to the PCI Bridge Architecture specification.
+
+Using the unique [bus:slot:func] any device can be configured regardless how PCI
+is currently set up as long as all PCI buses are enumerated correctly. The
+enumration is done during probing, all bridges are given a bus numbers in
+order for the bridges to respond to accesses from both directions. The PCI
+library can assign address ranges to which a PCI device should respond using
+Plug & Play technique or a static user defined configuration. After the
+configuration has been performed the PCI device drivers can find devices by
+the read-only PCI Class type, Vendor ID and Device ID information found in
+configuration space for each device.
+
+In some systems there is a boot loader or BIOS which have already configured
+all PCI devices, but on embedded targets it is quite common that there is no
+BIOS or boot loader, thus RTEMS must configure the PCI bus. Only the PCI host
+may do configuration space access, the host driver or BSP is responsible to
+translate the [bus:slot:func] into a valid PCI configuration space access.
+
+If the target is not a host, but a peripheral, configuration space can not be
+accessed, the peripheral is set up by the host during start up. In complex
+embedded PCI systems the peripheral may need to access other PCI boards than
+then host. In such systems a custom (static) configuration of both the host
+and peripheral may be a convenient solution.
+
+The PCI bus defines four interrupt signals INTA#..INTD#. The interrupt signals
+must be mapped into a system interrupt/vector, it is up to the BSP or host
+driver to know the mapping, however the BIOS or boot loader may use the
+8-bit read/write "Interrupt Line" register to pass the knowledge along to the
+OS.
+
+
+ The PCI standard
+defines and recommends that the backplane route the interupt lines in a
+systematic way, however in
+
+@subsection Software Components
+
+The PCI library is located in cpukit/libpci, it consists of different parts:
+@itemize @bullet
+@item PCI Host bridge driver interface
+@item Configuration routines
+@item Access (Configuration, I/O and Memory space) routines
+@item Interrupt routines (implemented by BSP)
+@item Print routines
+@item Static/peripheral configuration creation
+@item PCI shell command
+@end itemize
+
+@subsection PCI Configuration
+
+During start up the PCI bus must be configured in order for host and peripherals
+to access one another using Memory or I/O accesses and that interrupts are
+properly handled. Three different spaces are defined and mapped separately:
+@enumerate
+@item I/O space (IO)
+@item non-prefetchable Memory space (MEMIO)
+@item prefetchable Memory space (MEM)
+@end enumerate
+
+Regions of the same type (I/O or Memory) may not overlap which is guaranteed
+by the software. MEM regions may be mapped into MEMIO regions, but MEMIO
+regions can not be mapped into MEM, for that could lead to prefetching of
+registers. The interrupt pin which a board is driving can be read out from
+PCI configuration space, however it is up to software to know how interrupt
+signals are routed between PCI-to-PCI bridges and how PCI INT[A..D]# pins are
+mapped to system IRQ. In systems where previous software (boot loader or BIOS)
+has already set up this the configuration overwritten or simply read out.
+
+In order to support different configuration methods the following configuration
+libraries are available can selectable by the user:
+@itemize @bullet
+@item Auto Configuration (run Plug & Play software)
+@item Read Configuration (relies on a boot loader or BIOS)
+@item Static Configuration (write user defined setup, no Plug & Play)
+@item Peripheral Configuration (user defined setup, no access to configuration space)
+@end itemize
+
+A host driver can be made to support all three configuration methods, or any
+combination. It may be defined by the BSP which approach is used.
+
+The configuration software is called from the PCI driver (pci_config_init()).
+
+Regardless of configuration method a PCI device tree is created in RAM during
+initialization, the tree can be accessed to find devices and resources without
+accessing configuration space later on. The user is responsible to create the
+device tree at compile time when using the static/peripheral method.
+
+
+@subsubsection RTEMS Configuration selection
+
+The active configuration method can be selected at compile time in the same
+way as other project parameters by including rtems/confdefs.h and setting
+@itemize @bullet
+@item CONFIGURE_INIT
+@item RTEMS_PCI_CONFIG_LIB
+@item CONFIGURE_PCI_LIB = PCI_LIB_(AUTO,STATIC,READ,PERIPHERAL)
+@end itemize
+
+See the RTEMS configuration section how to setup the PCI library.
+
+
+@subsubsection Auto Configuration
+
+The auto configuration software enumerate PCI buses and initializes all PCI
+devices found using Plug & Play. The auto configuration software requires
+that a configuration setup has been registered by the driver or BSP in order
+to setup the I/O and Memory regions at the correct address ranges. PCI
+interrupt pins can optionally be routed over PCI-to-PCI bridges and mapped
+to a system interrupt number. Resources are sorted by size and required
+alignment, unused "dead" space may be created when PCI bridges are present
+due to the PCI bridge window size does not equal the alignment, to cope with
+that resources are reordered to fit smaller BARs into the dead space to minimize
+the PCI space required. If a BAR or ROM register can not be allocated a PCI
+address region (due to too few resources available) the register will be given
+the value of pci_invalid_address which defaults to 0.
+
+The auto configuration routines support:
+@itemize @bullet
+@item PCI 2.3
+@item Little and big endian PCI bus
+@item one I/O 16 or 32-bit range (IO)
+@item memory space (MEMIO)
+@item prefetchable memory space (MEM), if not present MEM will be mapped into
+ MEMIO
+@item multiple PCI buses - PCI-to-PCI bridges
+@item standard BARs, PCI-to-PCI bridge BARs, ROM BARs
+@item Interrupt routing over bridges
+@item Interrupt pin to system interrupt mapping
+@end itemize
+
+Not supported:
+@itemize @bullet
+@item hot-pluggable devices
+@item Cardbus bridges
+@item 64-bit memory space
+@item 16-bit and 32-bit I/O address ranges at the same time
+@end itemize
+
+In PCI 2.3 there may exist I/O BARs that must be located at the low 64kBytes
+address range, in order to support this the host driver or BSP must make sure
+that I/O addresses region is within this region.
+
+
+@subsubsection Read Configuration
+
+When a BIOS or boot loader already has setup the PCI bus the configuration can
+be read directly from the PCI resource registers and buses are already
+enumerated, this is a much simpler approach than configuring PCI ourselves. The
+PCI device tree is automatically created based on the current configuration and
+devices present. After initialization is done there is no difference between
+the auto or read configuration approaches.
+
+
+@subsubsection Static Configuration
+
+To support custom configurations and small-footprint PCI systems, the user may
+provide the PCI device tree which contains the current configuration. The
+PCI buses are enumerated and all resources are written to PCI devices during
+initialization. When this approach is selected PCI boards must be located at
+the same slots every time and devices can not be removed or added, Plug & Play
+is not performed. Boards of the same type may of course be exchanged.
+
+The user can create a configuration by calling pci_cfg_print() on a running
+system that has had PCI setup by the auto or read configuration routines, it
+can be called from the PCI shell command. The user must provide the PCI device
+tree named pci_hb.
+
+
+@subsubsection Peripheral Configuration
+
+On systems where a peripheral PCI device needs to access other PCI devices than
+the host the peripheral configuration approach may be handy. Most PCI devices
+answers on the PCI host's requests and start DMA accesses into the Hosts memory,
+however in some complex systems PCI devices may want to access other devices
+on the same bus or at another PCI bus.
+
+A PCI peripheral is not allowed to do PCI configuration cycles, which means that
+is must either rely on the host to give it the addresses it needs, or that the
+addresses are predefined.
+
+This configuration approach is very similar to the static option, however the
+configuration is never written to PCI bus, instead it is only used for drivers
+to find PCI devices and resources using the same PCI API as for the host
+
+
+@subsection PCI Access
+
+The PCI access routines are low-level routines provided for drivers,
+configuration software, etc. in order to access different regions in a way
+not dependent upon the host driver, BSP or platform.
+@itemize @bullet
+@item PCI configuration space
+@item PCI I/O space
+@item Registers over PCI memory space
+@item Translate PCI address into CPU accessible address and vice verse
+@end itemize
+
+By using the access routines drivers can be made portable over different
+architectures. The access routines take the architecture endianness into
+consideration and let the host driver or BSP implement I/O space and
+configuration space access.
+
+Some non-standard hardware may also define the PCI bus big-endian, for example
+the LEON2 AT697 PCI host bridge and some LEON3 systems may be configured that
+way. It is up to the BSP to set the appropriate PCI endianness on compile time
+(BSP_PCI_BIG_ENDIAN) in order for inline macros to be correctly defined.
+Another possibility is to use the function pointers defined by the access
+layer to implement drivers that support "run-time endianness detection".
+
+
+@subsubsection Configuration space
+
+Configuration space is accessed using the routines listed below. The
+pci_dev_t type is used to specify a specific PCI bus, device and function. It
+is up to the host driver or BSP to create a valid access to the requested
+PCI slot. Requests made to slots that is not supported by hardware should
+result in PCISTS_MSTABRT and/or data must be ignored (writes) or 0xffffffff
+is always returned (reads).
+
+@example
+ /* Configuration Space Access Read Routines */
+ extern int pci_cfg_r8(pci_dev_t dev, int ofs, uint8_t *data);
+ extern int pci_cfg_r16(pci_dev_t dev, int ofs, uint16_t *data);
+ extern int pci_cfg_r32(pci_dev_t dev, int ofs, uint32_t *data);
+
+ /* Configuration Space Access Write Routines */
+ extern int pci_cfg_w8(pci_dev_t dev, int ofs, uint8_t data);
+ extern int pci_cfg_w16(pci_dev_t dev, int ofs, uint16_t data);
+ extern int pci_cfg_w32(pci_dev_t dev, int ofs, uint32_t data);
+@end example
+
+
+@subsubsection I/O space
+
+The BSP or driver provide special routines in order to access I/O space. Some
+architectures have a special instruction accessing I/O space, others have it
+mapped into a "PCI I/O window" in the standard address space accessed by the
+CPU. The window size may vary and must be taken into consideration by the
+host driver. The below routines must be used to access I/O space. The address
+given to the functions is not the PCI I/O addresses, the caller must have
+translated PCI I/O addresses (available in the PCI BARs) into a BSP or host
+driver custom address, see @ref{Access functions} how addresses are
+translated.
+
+@example
+/* Read a register over PCI I/O Space */
+extern uint8_t pci_io_r8(uint32_t adr);
+extern uint16_t pci_io_r16(uint32_t adr);
+extern uint32_t pci_io_r32(uint32_t adr);
+
+/* Write a register over PCI I/O Space */
+extern void pci_io_w8(uint32_t adr, uint8_t data);
+extern void pci_io_w16(uint32_t adr, uint16_t data);
+extern void pci_io_w32(uint32_t adr, uint32_t data);
+@end example
+
+
+@subsubsection Registers over Memory space
+
+PCI host bridge hardware normally swap data accesses into the endianness of the
+host architecture in order to lower the load of the CPU, peripherals can do DMA
+without swapping. However, the host controller can not separate a standard
+memory access from a memory access to a register, registers may be mapped into
+memory space. This leads to register content being swapped, which must be
+swapped back. The below routines makes it possible to access registers over PCI
+memory space in a portable way on different architectures, the BSP or
+architecture must provide necessary functions in order to implement this.
+
+@example
+ static inline uint16_t pci_ld_le16(volatile uint16_t *addr);
+ static inline void pci_st_le16(volatile uint16_t *addr, uint16_t val);
+ static inline uint32_t pci_ld_le32(volatile uint32_t *addr);
+ static inline void pci_st_le32(volatile uint32_t *addr, uint32_t val);
+ static inline uint16_t pci_ld_be16(volatile uint16_t *addr);
+ static inline void pci_st_be16(volatile uint16_t *addr, uint16_t val);
+ static inline uint32_t pci_ld_be32(volatile uint32_t *addr);
+ static inline void pci_st_be32(volatile uint32_t *addr, uint32_t val);
+@end example
+
+In order to support non-standard big-endian PCI bus the above pci_* functions
+is required, pci_ld_le16 != ld_le16 on big endian PCI buses.
+
+
+@subsubsection Access functions
+
+The PCI Access Library can provide device drivers with function pointers
+executing the above Configuration, I/O and Memory space accesses. The
+functions have the same arguments and return values as the as the above
+functions.
+
+The pci_access_func() function defined below can be used to get a function
+pointer of a specific access type.
+
+@example
+ /* Get Read/Write function for accessing a register over PCI Memory Space
+ * (non-inline functions).
+ *
+ * Arguments
+ * wr 0(Read), 1(Write)
+ * size 1(Byte), 2(Word), 4(Double Word)
+ * func Where function pointer will be stored
+ * endian PCI_LITTLE_ENDIAN or PCI_BIG_ENDIAN
+ * type 1(I/O), 3(REG over MEM), 4(CFG)
+ *
+ * Return
+ * 0 Found function
+ * others No such function defined by host driver or BSP
+ */
+ int pci_access_func(int wr, int size, void **func, int endian, int type);
+@end example
+
+PCI devices drivers may be written to support run-time detection of endianess,
+this is mosly for debugging or for development systems. When the product is
+finally deployed macros switch to using the inline functions instead which
+have been configured for the correct endianness.
+
+
+@subsubsection PCI address translation
+
+When PCI addresses, both I/O and memory space, is not mapped 1:1 address
+translation before access is needed. If drivers read the PCI resources directly
+using configuration space routines or in the device tree, the addresses given
+are PCI addresses. The below functions can be used to translate PCI addresses
+into CPU accessible addresses or vise versa, translation may be different for
+different PCI spaces/regions.
+
+@example
+ /* Translate PCI address into CPU accessible address */
+ static inline int pci_pci2cpu(uint32_t *address, int type);
+
+ /* Translate CPU accessible address into PCI address (for DMA) */
+ static inline int pci_cpu2pci(uint32_t *address, int type);
+@end example
+
+
+@subsection PCI Interrupt
+
+The PCI specification defines four different interrupt lines INTA#..INTD#,
+the interrupts are low level sensitive which make it possible to support
+multiple interrupt sources on the same interrupt line. Since the lines are
+level sensitive the interrupt sources must be acknowledged before clearing the
+interrupt contoller, or the interrupt controller must be masked. The BSP must
+provide a routine for clearing/acknowledging the interrupt controller, it is
+up to the interrupt service routine to acknowledge the interrupt source.
+
+The PCI Library relies on the BSP for implementing shared interrupt handling
+through the BSP_PCI_shared_interrupt_* functions/macros, they must be defined
+when including bsp.h.
+
+PCI device drivers may use the pci_interrupt_ routines in order to call the
+BSP specific functions in a platform independent way. The PCI interrupt
+interface has been made similar to the RTEMS IRQ extension so that a BSP can
+use the standard RTEMS interrupt functions directly.
+
+
+@subsection PCI Shell command
+
+The RTEMS shell have a PCI command 'pci' which makes it possible to read/write
+configuration space, print the current PCI configuration and print out a
+configuration C-file for the static or peripheral library.
diff --git a/testsuites/mptests/mp06/task1.c b/testsuites/mptests/mp06/task1.c
index 8e9fd71b25..976cb85286 100644
--- a/testsuites/mptests/mp06/task1.c
+++ b/testsuites/mptests/mp06/task1.c
@@ -162,6 +162,7 @@ rtems_task Test_task(
if ( Multiprocessing_configuration.node == 2 ) {
/* Flush events */
+ rtems_task_wake_after( 100 );
puts( "Flushing RTEMS_EVENT_16" );
(void) rtems_event_receive(RTEMS_EVENT_16, RTEMS_NO_WAIT, 0, &event_out);
diff --git a/testsuites/psxtests/psxualarm/init.c b/testsuites/psxtests/psxualarm/init.c
index 82a4d8d251..3f278d4177 100644
--- a/testsuites/psxtests/psxualarm/init.c
+++ b/testsuites/psxtests/psxualarm/init.c
@@ -26,12 +26,14 @@ void Signal_handler(
)
{
Signal_count++;
+#if 0
printf(
"Signal: %d caught by 0x%" PRIxpthread_t " (%d)\n",
signo,
pthread_self(),
Signal_count
);
+#endif
Signal_occurred = 1;
}
diff --git a/testsuites/sptests/sp20/task1.c b/testsuites/sptests/sp20/task1.c
index 680cba9f5f..4189659d27 100644
--- a/testsuites/sptests/sp20/task1.c
+++ b/testsuites/sptests/sp20/task1.c
@@ -26,7 +26,7 @@
#define TA6_ITERATIONS 10
#define TA6_PERIOD_FACTOR 10
-uint32_t Periods[7] = { 0, 2, 2, 2, 2, 100, 0 };
+uint32_t Periods[7] = { 0, 20, 20, 20, 20, 1000, 0 };
uint32_t Iterations[7] = { 0, 50, 50, 50, 50, 1, TA6_ITERATIONS };
rtems_task_priority Priorities[7] = { 0, 1, 1, 3, 4, 5, 1 };
@@ -69,7 +69,7 @@ rtems_task Task_1_through_6(
case 4:
while ( FOREVER ) {
status = rtems_rate_monotonic_period( rmid, Periods[ argument ] );
- directive_failed( status, "rtems_rate_monotonic_period" );
+ directive_failed( status, "rtems_rate_monotonic_period 0 of TAN" );
Count.count[ argument ]++;
}