LEON: added new drivers to the LEON2/LEON3 BSPs

Most drivers use the Driver Manager for device probing, they
work on AMBA-over-PCI systems if PCI is big-endian.

New APIs:
 * GPIO Library, interfaced to GRGPIO
 * GENIRQ, Generic interrupt service implementation helper

New GRLIB Drivers:
 * ACTEL 1553 RT, user interface is similar to 1553 BRM driver
 * GR1553 (1553 BC, RT and BM core)
 * AHBSTAT (AHB error status core)
 * GRADCDAC (Core interfacing to ADC/DAC hardware)
 * GRGPIO (GPIO port accessed from GPIO Library)
 * MCTRL (Memory controller settings configuration)
 * GRETH (10/100/1000 Ethernet driver using Driver manager)
 * GRPWM (Pulse Width Modulation core)
 * SPICTRL (SPI master interface)
 * GRSPW_ROUTER (SpaceWire Router AMBA configuration interface)
 * GRCTM (SpaceCraft on-board Time Management core)
 * SPWCUC (Time distribution over SpaceWire)
 * GRTC (SpaceCraft up-link Tele core)
 * GRTM (SpaceCraft down-link Tele Metry core)

GR712RC ASIC specific interfaces:
 * GRASCS
 * CANMUX (select between OCCAN and SATCAN)
 * SATCAN
 * SLINK
This commit is contained in:
Daniel Hellstrom
2015-02-23 13:02:39 +01:00
parent fe1aa9c002
commit 3bb41226e0
55 changed files with 21513 additions and 5 deletions

View File

@@ -12,11 +12,15 @@ EXTRA_DIST += shared/start/start.S
# Interrupt
EXTRA_DIST += shared/irq/irq-shared.c
EXTRA_DIST += shared/irq/bsp_isr_handler.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
@@ -58,9 +62,11 @@ 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_router.c
EXTRA_DIST += shared/include/grspw.h
EXTRA_DIST += shared/include/grspw_router.h
# UART
EXTRA_DIST += shared/uart/cons.c
@@ -75,14 +81,58 @@ EXTRA_DIST += shared/can/grcan.c
EXTRA_DIST += shared/include/occan.h
EXTRA_DIST += shared/include/grcan.h
# MEM
EXTRA_DIST += shared/mem/mctrl.c
# MIL-STD-B1553 (Core1553BRM)
EXTRA_DIST += shared/1553/b1553brm.c
EXTRA_DIST += shared/1553/b1553rt.c
EXTRA_DIST += shared/include/b1553brm.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
@@ -96,6 +146,19 @@ EXTRA_DIST += shared/drvmgr/leon2_amba_bus.c
EXTRA_DIST += shared/include/drvmgr/ambapp_bus_grlib.h
EXTRA_DIST += shared/include/drvmgr/ambapp_bus.h
EXTRA_DIST += shared/include/drvmgr/leon2_amba_bus.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/include/grtc.h
EXTRA_DIST += shared/tmtc/grtm.c
EXTRA_DIST += shared/include/grtm.h
include $(top_srcdir)/../../../automake/subdirs.am
include $(top_srcdir)/../../../automake/local.am

View File

@@ -58,6 +58,8 @@ libbsp_a_SOURCES += console/console.c console/debugputs.c
libbsp_a_SOURCES += clock/ckinit.c
libbsp_a_SOURCES += ../../shared/clockdrv_shell.h
# 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 \
@@ -76,6 +78,7 @@ libbsp_a_SOURCES += \
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
@@ -86,6 +89,7 @@ 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
@@ -114,7 +118,20 @@ libbsp_a_SOURCES += ../../sparc/shared/pci/gr_rasta_tmtc.c
# B1553BRM
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
@@ -124,7 +141,9 @@ libbsp_a_SOURCES += ../../sparc/shared/can/occan.c \
# SpaceWire
include_HEADERS += ../../sparc/shared/include/grspw.h
include_HEADERS += ../../sparc/shared/include/grspw_router.h
libbsp_a_SOURCES += ../../sparc/shared/spw/grspw.c
libbsp_a_SOURCES += ../../sparc/shared/spw/grspw_router.c
# UART (RAW)
include_HEADERS += ../../sparc/shared/include/apbuart.h
@@ -134,9 +153,42 @@ libbsp_a_SOURCES += ../../sparc/shared/uart/apbuart.c
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
# 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/grtm.c
# Driver Manager
include_drvmgrdir = $(includedir)/drvmgr
include_drvmgr_HEADERS = ../../sparc/shared/include/drvmgr/ambapp_bus.h
@@ -166,6 +218,14 @@ 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
@@ -178,6 +238,7 @@ libbsp_a_LIBADD = \
../../../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

View File

@@ -227,6 +227,7 @@ int cchip1_register(void);
*/
#define AMBAPPBUS_INFO_AVAIL /* AMBAPP Bus driver */
#define GPTIMER_INFO_AVAIL /* GPTIMER Timer driver */
#define GRETH_INFO_AVAIL /* GRETH Ethernet driver */
#ifdef __cplusplus
}

View File

@@ -81,6 +81,10 @@ $(PROJECT_INCLUDE)/bsp/gnatcommon.h: ../shared/include/gnatcommon.h $(PROJECT_IN
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/gnatcommon.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/gnatcommon.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
@@ -105,6 +109,10 @@ $(PROJECT_INCLUDE)/grlib.h: ../../sparc/shared/include/grlib.h $(PROJECT_INCLUDE
$(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
@@ -133,6 +141,30 @@ $(PROJECT_INCLUDE)/b1553brm.h: ../../sparc/shared/include/b1553brm.h $(PROJECT_I
$(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)/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
@@ -145,6 +177,10 @@ $(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_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)/apbuart.h: ../../sparc/shared/include/apbuart.h $(PROJECT_INCLUDE)/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/apbuart.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/apbuart.h
@@ -153,6 +189,42 @@ $(PROJECT_INCLUDE)/i2cmst.h: ../../sparc/shared/include/i2cmst.h $(PROJECT_INCLU
$(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)/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)/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)
@@ -166,6 +238,11 @@ $(PROJECT_INCLUDE)/drvmgr/leon2_amba_bus.h: ../../sparc/shared/include/drvmgr/le
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/drvmgr/leon2_amba_bus.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/drvmgr/leon2_amba_bus.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

View File

@@ -55,6 +55,7 @@ include_HEADERS += include/amba.h
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 += amba/amba.c
libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp.c
libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp_alloc.c
@@ -66,6 +67,7 @@ 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
@@ -86,12 +88,14 @@ include_HEADERS += ../../sparc/shared/include/cons.h
libbsp_a_SOURCES += console/printk_support.c
# 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 \
../../sparc/shared/irq/bsp_isr_handler.c \
../../shared/src/irq-default-handler.c \
@@ -124,7 +128,20 @@ libbsp_a_SOURCES += ../../sparc/shared/pci/gr_tmtc_1553.c
# B1553BRM
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 \
@@ -134,7 +151,9 @@ libbsp_a_SOURCES += ../../sparc/shared/can/occan.c \
# SpaceWire
include_HEADERS += ../../sparc/shared/include/grspw.h
include_HEADERS += ../../sparc/shared/include/grspw_router.h
libbsp_a_SOURCES += ../../sparc/shared/spw/grspw.c
libbsp_a_SOURCES += ../../sparc/shared/spw/grspw_router.c
# UART
include_HEADERS += ../../sparc/shared/include/apbuart.h \
@@ -146,6 +165,33 @@ libbsp_a_SOURCES += ../../sparc/shared/uart/apbuart.c \
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
# timer
libbsp_a_SOURCES += timer/timer.c
libbsp_a_SOURCES += timer/watchdog.c
@@ -156,6 +202,22 @@ libbsp_a_SOURCES += ../../../libcpu/shared/src/cache_manager.c
libbsp_a_SOURCES += include/cache_.h
libbsp_a_CPPFLAGS = -I$(srcdir)/include
# 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/grtm.c
# Driver Manager
include_drvmgrdir = $(includedir)/drvmgr
include_drvmgr_HEADERS = ../../sparc/shared/include/drvmgr/ambapp_bus_grlib.h
@@ -185,7 +247,9 @@ 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)

View File

@@ -257,6 +257,7 @@ extern const unsigned char LEON3_irq_to_cpu[32];
#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 */
#ifdef __cplusplus
}

View File

@@ -105,6 +105,10 @@ $(PROJECT_INCLUDE)/grlib.h: ../../sparc/shared/include/grlib.h $(PROJECT_INCLUDE
$(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
@@ -113,6 +117,10 @@ $(PROJECT_INCLUDE)/cons.h: ../../sparc/shared/include/cons.h $(PROJECT_INCLUDE)/
$(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
@@ -153,6 +161,30 @@ $(PROJECT_INCLUDE)/b1553brm.h: ../../sparc/shared/include/b1553brm.h $(PROJECT_I
$(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)/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
@@ -165,6 +197,10 @@ $(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_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)/apbuart.h: ../../sparc/shared/include/apbuart.h $(PROJECT_INCLUDE)/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/apbuart.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/apbuart.h
@@ -177,10 +213,62 @@ $(PROJECT_INCLUDE)/i2cmst.h: ../../sparc/shared/include/i2cmst.h $(PROJECT_INCLU
$(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)/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)/watchdog.h: include/watchdog.h $(PROJECT_INCLUDE)/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/watchdog.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/watchdog.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)
@@ -194,6 +282,11 @@ $(PROJECT_INCLUDE)/drvmgr/ambapp_bus.h: ../../sparc/shared/include/drvmgr/ambapp
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/drvmgr/ambapp_bus.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/drvmgr/ambapp_bus.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

View File

@@ -0,0 +1,859 @@
/*
* B1553RT driver implmenetation
*
* COPYRIGHT (c) 2009.
* Cobham 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 <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;
unsigned int 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 = (unsigned int)value->ptr;
if (value && (mem & 1)) {
/* Remote address, address as RT looks at it. */
/* Translate the base address into an address that the the CPU can understand */
pDev->memarea_base = mem & ~1;
drvmgr_translate_check(pDev->dev, DMAMEM_TO_CPU,
(void *)pDev->memarea_base_remote,
(void **)&pDev->memarea_base,
4 * 1024);
} else {
if (!value) {
/* Use dynamically allocated memory,
* 4k DMA memory + 4k for alignment
*/
mem = (char *)malloc(4 * 1024 * 2);
if ( !mem ){
printk("RT: Failed to allocate HW memory\n\r");
return -1;
}
/* align memory to 4k boundary */
pDev->memarea_base = (mem + 0xfff) & ~0xfff;
} else {
pDev->memarea_base = mem;
}
/* Translate the base address into an address that the RT core can understand */
drvmgr_translate_check(pDev->dev, CPUMEM_TO_DMA,
(void *)pDev->memarea_base,
(void **)&pDev->memarea_base_remote,
4 * 1024);
}
/* clear the used memory */
memset((char *)pDev->memarea_base, 0, 4 * 1024);
/* Set base address of all descriptors */
pDev->memarea_base = (unsigned int)mem;
pDev->mem = (volatile unsigned short *)pDev->memarea_base;
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;
}
}

View File

@@ -0,0 +1,305 @@
/* GR1553B driver, used by BC, RT and/or BM driver
*
* COPYRIGHT (c) 2010.
* Cobham 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/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);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,519 @@
/* GR1553B BM driver
*
* COPYRIGHT (c) 2010.
* Cobham 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 <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 ((unsigned int)cfg->buffer_custom & 1) {
/* Custom Address Given in Remote address. We need
* to convert it intoTranslate into Hardware a
* hardware accessible address
*/
priv->buffer_base_hw = (unsigned int)cfg->buffer_custom & ~1;
priv->buffer = cfg->buffer_custom;
drvmgr_translate_check(
*priv->pdev,
DMAMEM_TO_CPU,
(void *)priv->buffer_base_hw,
(void **)&priv->buffer_base,
priv->buffer_size);
} else {
if (cfg->buffer_custom == NULL) {
/* Allocate new buffer dynamically */
priv->buffer = malloc(priv->buffer_size + 8);
if (priv->buffer == NULL)
return -1;
} 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_check(
*priv->pdev,
CPUMEM_TO_DMA,
(void *)priv->buffer_base,
(void **)&priv->buffer_base_hw,
priv->buffer_size);
}
/* 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);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,206 @@
/* AHB Status register driver
*
* COPYRIGHT (c) 2009.
* Cobham 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 <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;
}

View File

@@ -0,0 +1,578 @@
/* ADC / DAC (GRADCDAC) interface implementation
*
* COPYRIGHT (c) 2009.
* Cobham 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 <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;
}

View File

@@ -0,0 +1,615 @@
/* This file contains the GRASCS RTEMS driver
*
* COPYRIGHT (c) 2008.
* Cobham 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 <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;
}

View File

@@ -0,0 +1,197 @@
/*
* CAN_MUX driver. Present in GR712RC.
*
* COPYRIGHT (c) 2008.
* Cobham 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/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;
}

View File

@@ -0,0 +1,714 @@
/*
* SatCAN FPGA driver
*
* COPYRIGHT (c) 2008.
* Cobham 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/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;
}

View File

@@ -0,0 +1,265 @@
/* GPIOLIB interface implementation
*
* COPYRIGHT (c) 2009.
* Cobham 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 <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);
}
/*** Initialization ***/
int gpiolib_initialize(void)
{
if ( gpiolib_initied != 0 )
return 0;
/* Initialize Libarary */
port_nr = 0;
gpiolib_ports = 0;
gpiolib_initied = 1;
return 0;
}

View File

@@ -0,0 +1,437 @@
/* GRGPIO GPIO Driver interface.
*
* COPYRIGHT (c) 2009.
* Cobham 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 <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;
}
}
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;
}

View File

@@ -0,0 +1,73 @@
/* AHBSTAT driver interface
*
* COPYRIGHT (c) 2011.
* Cobham 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 __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

View File

@@ -0,0 +1,74 @@
/* 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__ */

View File

@@ -0,0 +1,32 @@
/*
* Header file for RTEMS CAN_MUX driver
*
* COPYRIGHT (c) 2008.
* Cobham 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 __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__ */

View File

@@ -1,7 +1,7 @@
/* General part of a AMBA Plug & Play bus driver.
*
* COPYRIGHT (c) 2008.
* Cobham Gaisler AB
* Cobham Gaisler AB.
*
* This is the general part of the different AMBA Plug & Play
* drivers. The drivers are wrappers around this driver, making
@@ -28,8 +28,36 @@ extern "C" {
DRIVER_ID(DRVMGR_BUS_TYPE_AMBAPP, ((((vendor) & 0xff) << 16) | ((device) & 0xfff)))
/*** Gaisler Hardware Device Driver IDs ***/
#define DRIVER_AMBAPP_GAISLER_APBUART_ID DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_APBUART)
#define DRIVER_AMBAPP_GAISLER_GPTIMER_ID DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_GPTIMER)
#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_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;

View File

@@ -0,0 +1,107 @@
/* 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.
*
* COPYRIGHT (c) 2008.
* Cobham 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 __GENIRQ_H__
#define __GENIRQ_H__
#ifdef __cplusplus
extern "C" {
#endif
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);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,90 @@
/* GPIO Library interface
*
* COPYRIGHT (c) 2009.
* Cobham 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_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
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

View File

@@ -0,0 +1,365 @@
/* GR1553B driver, used by BC, RT and/or BM driver
*
* COPYRIGHT (c) 2010.
* Cobham 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.
*
* 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.
*
*/
#ifndef __GR1553B_H__
#define __GR1553B_H__
#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__ */

View File

@@ -0,0 +1,250 @@
/* GR1553B BC driver
*
* COPYRIGHT (c) 2010.
* Cobham 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.
*
* 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.
*/
#ifndef __GR1553BC_H__
#define __GR1553BC_H__
#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__ */

View File

@@ -0,0 +1,707 @@
/*
* GR1553B BC driver, Descriptor LIST handling
*
* COPYRIGHT (c) 2010.
* Cobham 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 __GR1553BC_LIST_H__
#define __GR1553BC_LIST_H__
/*!\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__ */

View File

@@ -0,0 +1,204 @@
/* GR1553B BM driver
*
* COPYRIGHT (c) 2010.
* Cobham 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 __GR1553BM_H__
#define __GR1553BM_H__
#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__ */

View File

@@ -0,0 +1,434 @@
/* GR1553B RT driver
*
* COPYRIGHT (c) 2010.
* Cobham 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 __GR1553RT_H__
#define __GR1553RT_H__
/* 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

View File

@@ -0,0 +1,227 @@
/* ADC / DAC (GRADCDAC) interface
/*
* COPYRIGHT (c) 2009.
* Cobham 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

View File

@@ -0,0 +1,92 @@
/*
* Header file for GRASCS RTEMS driver
*
* COPYRIGHT (c) 2008.
* Cobham 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 __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

View File

@@ -0,0 +1,168 @@
/* GRCTM - CCSDS Time Manager - register driver interface.
*
* COPYRIGHT (c) 2009.
* Cobham 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

View File

@@ -0,0 +1,145 @@
/*
* Cobham Gaisler 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.
*/
#ifndef __GRETH_H__
#define __GRETH_H__
#ifdef __cplusplus
extern "C" {
#endif
/* 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 */
/* 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

View File

@@ -0,0 +1,25 @@
/*
* GRGPIO GPIO Driver interface.
*
* COPYRIGHT (c) 2009.
* Cobham 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 __GRGPIO_H__
#define __GRGPIO_H__
#ifdef __cplusplus
extern "C" {
#endif
extern void grgpio_register_drv (void);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,127 @@
/*
* GRPWM PWM Driver interface.
*
* COPYRIGHT (c) 2009.
* Cobham 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 __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

View File

@@ -0,0 +1,148 @@
/*
* Header file for RTEMS GRSLINK SLINK master driver
*
* COPYRIGHT (c) 2009.
* Cobham 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 __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__ */

View File

@@ -0,0 +1,104 @@
/*
* GRSPW ROUTER APB-Register Driver.
*
* COPYRIGHT (c) 2010.
* Cobham 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_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

View File

@@ -0,0 +1,152 @@
/* GRTC Telecommand (TC) decoder driver interface
*
* COPYRIGHT (c) 2007.
* Cobham 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 __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__ */

View File

@@ -0,0 +1,241 @@
/* GRTM Telemetry (TM) driver interface
*
* COPYRIGHT (c) 2007.
* Cobham 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 __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__ */

View File

@@ -0,0 +1,142 @@
/*
* Header file for RTEMS SATCAN FPGA driver
*
* COPYRIGHT (c) 2009.
* Cobham 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 __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__ */

View File

@@ -0,0 +1,126 @@
/*
* SPICTRL SPI Driver interface.
*
* COPYRIGHT (c) 2009.
* Cobham 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 __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

View File

@@ -0,0 +1,188 @@
/* SPWCUC - SpaceWire - CCSDS unsegmented Code Transfer Protocol GRLIB core
* register driver interface.
*
* COPYRIGHT (c) 2009.
* Cobham 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

View File

@@ -0,0 +1,241 @@
/*
* Generic interrupt helpers mainly for GRLIB PCI peripherals
*
* COPYRIGHT (c) 2008.
* Cobham 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 <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);
}
}

View File

@@ -0,0 +1,210 @@
/* Memory Controller driver (FTMTRL, MCTRL)
*
* COPYRIGHT (c) 2008.
* Cobham 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.
*/
/******************* 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;
}

View File

@@ -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.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,847 @@
/*
* GRPWM PWM Driver interface.
*
* COPYRIGHT (c) 2009.
* Cobham 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 <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;
}

View File

@@ -0,0 +1,661 @@
/*
* This file contains the RTEMS GRSLINK SLINK master driver
*
* COPYRIGHT (c) 2009.
* Cobham 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.
*
* 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
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,549 @@
/* GRSPW ROUTER APB-Register Driver.
*
* COPYRIGHT (c) 2010.
* Cobham 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 <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;
}

View File

@@ -0,0 +1,409 @@
/* GRCTM - CCSDS Time Manager - register driver interface.
*
* COPYRIGHT (c) 2009.
* Cobham 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);
}

View File

@@ -0,0 +1,369 @@
/* SPWCUC - SpaceWire - CCSDS unsegmented Code Transfer Protocol GRLIB core
* register driver interface.
*
* COPYRIGHT (c) 2009.
* Cobham 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);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff