diff options
author | Joel Sherrill <joel.sherrill@OARcorp.com> | 2011-08-01 13:48:40 +0000 |
---|---|---|
committer | Joel Sherrill <joel.sherrill@OARcorp.com> | 2011-08-01 13:48:40 +0000 |
commit | dce1032b6cdc2cd3c4e6b0ca3695aca6558c56c3 (patch) | |
tree | e485d78b238db7255395470e037305af8b8a642c /c/src/lib/libbsp/lm32 | |
parent | 2011-08-01 Jennifer Averett <Jennifer.Averett@OARcorp.com> (diff) | |
download | rtems-dce1032b6cdc2cd3c4e6b0ca3695aca6558c56c3.tar.bz2 |
2011-08-01 Sebastien Bourdeauducq <sebastien.bourdeauducq@gmail.com>
PR 1869/bsps
* startup/bspclean.c: New file.
* include/tm27.h: Removed.
* ChangeLog, Makefile.am, README, preinstall.am, include/bsp.h,
include/system_conf.h, make/custom/milkymist.cfg, startup/linkcmds:
Complete BSP for Milkymist One supporting Milkymist SOC 1.0.x.
Includes new or updated drivers for:
- Multi-standard video input (PAL/SECAM/NTSC)
- Two DMX512 (RS485) ports
- MIDI IN and MIDI OUT ports
- VGA output
- AC'97 audio
- NOR flash
- 10/100 Ethernet
- Memory card (experimental and incomplete)
- USB host connectors (input devices only)
- RC5 infrared receiver
- RS232 debug port
Diffstat (limited to 'c/src/lib/libbsp/lm32')
52 files changed, 4640 insertions, 1088 deletions
diff --git a/c/src/lib/libbsp/lm32/milkymist/ChangeLog b/c/src/lib/libbsp/lm32/milkymist/ChangeLog index d4008aa6cb..eb7582ed24 100644 --- a/c/src/lib/libbsp/lm32/milkymist/ChangeLog +++ b/c/src/lib/libbsp/lm32/milkymist/ChangeLog @@ -1,3 +1,24 @@ +2011-08-01 Sebastien Bourdeauducq <sebastien.bourdeauducq@gmail.com> + + PR 1869/bsps + * startup/bspclean.c: New file. + * include/tm27.h: Removed. + * ChangeLog, Makefile.am, README, preinstall.am, include/bsp.h, + include/system_conf.h, make/custom/milkymist.cfg, startup/linkcmds: + Complete BSP for Milkymist One supporting Milkymist SOC 1.0.x. + Includes new or updated drivers for: + - Multi-standard video input (PAL/SECAM/NTSC) + - Two DMX512 (RS485) ports + - MIDI IN and MIDI OUT ports + - VGA output + - AC'97 audio + - NOR flash + - 10/100 Ethernet + - Memory card (experimental and incomplete) + - USB host connectors (input devices only) + - RC5 infrared receiver + - RS232 debug port + 2011-02-02 Ralf Corsépius <ralf.corsepius@rtems.org> * configure.ac: Require autoconf-2.68, automake-1.11.1. @@ -13,5 +34,3 @@ preinstall.am, Documentation/uart.txt, include/.cvsignore, include/bsp.h, include/system_conf.h, include/tm27.h, make/custom/milkymist.cfg, startup/linkcmds: New files. - -08 / 12 / 2010 : <Yann Sionneau> Added Milkymist BSP diff --git a/c/src/lib/libbsp/lm32/milkymist/Makefile.am b/c/src/lib/libbsp/lm32/milkymist/Makefile.am index 0e09d57949..5d4d5580c3 100644 --- a/c/src/lib/libbsp/lm32/milkymist/Makefile.am +++ b/c/src/lib/libbsp/lm32/milkymist/Makefile.am @@ -10,8 +10,25 @@ include_bspdir = $(includedir)/bsp dist_project_lib_DATA = bsp_specs -include_HEADERS = include/bsp.h -include_HEADERS += include/tm27.h +include_HEADERS = include/bsp.h +include_HEADERS += ../../shared/include/coverhd.h +include_HEADERS += ../../shared/include/tm27.h + +include_bsp_HEADERS = ../../lm32/shared/include/irq.h +include_bsp_HEADERS += ../../shared/include/irq-generic.h +include_bsp_HEADERS += ../../lm32/shared/milkymist_gpio/milkymist_gpio.h +include_bsp_HEADERS += ../../lm32/shared/milkymist_buttons/milkymist_buttons.h +include_bsp_HEADERS += ../../lm32/shared/milkymist_ac97/milkymist_ac97.h +include_bsp_HEADERS += ../../lm32/shared/milkymist_usbinput/milkymist_usbinput.h +include_bsp_HEADERS += ../../lm32/shared/milkymist_pfpu/milkymist_pfpu.h +include_bsp_HEADERS += ../../lm32/shared/milkymist_tmu/milkymist_tmu.h +include_bsp_HEADERS += ../../lm32/shared/milkymist_memcard/milkymist_memcard.h +include_bsp_HEADERS += ../../lm32/shared/milkymist_flash/milkymist_flash.h +include_bsp_HEADERS += ../../lm32/shared/milkymist_dmx/milkymist_dmx.h +include_bsp_HEADERS += ../../lm32/shared/milkymist_midi/milkymist_midi.h +include_bsp_HEADERS += ../../lm32/shared/milkymist_ir/milkymist_ir.h +include_bsp_HEADERS += ../../lm32/shared/milkymist_video/milkymist_video.h +include_bsp_HEADERS += ../../lm32/shared/milkymist_versions/milkymist_versions.h nodist_include_HEADERS = include/bspopts.h nodist_include_bsp_HEADERS = ../../shared/include/bootcard.h @@ -19,7 +36,6 @@ DISTCLEANFILES = include/bspopts.h noinst_PROGRAMS = -include_HEADERS += ../../shared/include/coverhd.h include_HEADERS += include/system_conf.h noinst_LIBRARIES = libbspstart.a @@ -33,33 +49,74 @@ libbsp_a_SOURCES = libbsp_a_LIBADD = # startup -libbsp_a_SOURCES += ../../shared/bspclean.c ../../shared/bsplibc.c \ - ../../shared/bsppost.c ../shared/startup/bspstart.c \ - ../../shared/bspreset.c ../../shared/bsppretaskinghook.c \ - ../../shared/bspgetworkarea.c ../../shared/bootcard.c \ - ../../shared/sbrk.c ../../lm32/shared/startup/setvec.c \ - ../../shared/gnatinstallhandler.c +libbsp_a_SOURCES += startup/bspclean.c +libbsp_a_SOURCES += ../../shared/bsplibc.c +libbsp_a_SOURCES += ../../shared/bsppost.c +libbsp_a_SOURCES += ../shared/startup/bspstart.c +libbsp_a_SOURCES += ../../shared/bsppretaskinghook.c +libbsp_a_SOURCES += ../../shared/bspgetworkarea.c +libbsp_a_SOURCES += ../../shared/bootcard.c +libbsp_a_SOURCES += ../../shared/sbrk.c +libbsp_a_SOURCES += ../../shared/gnatinstallhandler.c + +# irq +libbsp_a_SOURCES += ../../lm32/shared/irq/irq.c # clock - libbsp_a_SOURCES += ../../lm32/shared/milkymist_clock/ckinit.c # console -libbsp_a_SOURCES += ../../lm32/shared/milkymist_console/console.c \ - ../../lm32/shared/milkymist_console/uart.c +libbsp_a_SOURCES += ../../lm32/shared/milkymist_console/console.c +libbsp_a_SOURCES += ../../lm32/shared/milkymist_console/uart.c + # timer libbsp_a_SOURCES += ../../lm32/shared/milkymist_timer/timer.c # framebuffer libbsp_a_SOURCES += ../../lm32/shared/milkymist_framebuffer/framebuffer.c -# gpio +# GPIO libbsp_a_SOURCES += ../../lm32/shared/milkymist_gpio/gpio.c +# buttons +libbsp_a_SOURCES += ../../lm32/shared/milkymist_buttons/buttons.c + +# ac97 +libbsp_a_SOURCES += ../../lm32/shared/milkymist_ac97/ac97.c + +# usbinput +libbsp_a_SOURCES += ../../lm32/shared/milkymist_usbinput/usbinput.c + +# PFPU +libbsp_a_SOURCES += ../../lm32/shared/milkymist_pfpu/pfpu.c + +# TMU +libbsp_a_SOURCES += ../../lm32/shared/milkymist_tmu/tmu.c + +# memory card +libbsp_a_SOURCES += ../../lm32/shared/milkymist_memcard/memcard.c + +# flash +libbsp_a_SOURCES += ../../lm32/shared/milkymist_flash/flash.c + +# DMX +libbsp_a_SOURCES += ../../lm32/shared/milkymist_dmx/dmx.c + +# MIDI +libbsp_a_SOURCES += ../../lm32/shared/milkymist_midi/midi.c + +# IR +libbsp_a_SOURCES += ../../lm32/shared/milkymist_ir/ir.c + +# video input +libbsp_a_SOURCES += ../../lm32/shared/milkymist_video/video.c + +# versions +libbsp_a_SOURCES += ../../lm32/shared/milkymist_versions/versions.c + if HAS_NETWORKING noinst_PROGRAMS += network.rel -network_rel_SOURCES = ../../lm32/shared/milkymist_networking/network.c \ - ../../lm32/shared/milkymist_networking/mm_crc32.c +network_rel_SOURCES = ../../lm32/shared/milkymist_networking/network.c network_rel_CPPFLAGS = $(AM_CPPFLAGS) -D__INSIDE_RTEMS_BSD_TCPIP_STACK__ network_rel_LDFLAGS = $(RTEMS_RELLDFLAGS) libbsp_a_LIBADD += network.rel diff --git a/c/src/lib/libbsp/lm32/milkymist/README b/c/src/lib/libbsp/lm32/milkymist/README index 20568ee496..b44d3735c2 100644 --- a/c/src/lib/libbsp/lm32/milkymist/README +++ b/c/src/lib/libbsp/lm32/milkymist/README @@ -2,20 +2,19 @@ # $Id$ # -This is a BSP written by Yann Sionneau <yann.sionneau@telecom-sudparis.eu> -as part of Google Summer of Code 2010. +Full RTEMS port to the Milkymist One. Supports Milkymist SoC 1.0.x. -This is a BSP to make RTEMS run on Milkymist One board using Milkymist SoC +Includes drivers for: +- Multi-standard video input (PAL/SECAM/NTSC) +- Two DMX512 (RS485) ports +- MIDI IN and MIDI OUT ports +- VGA output +- AC'97 audio +- NOR flash +- 10/100 Ethernet +- Memory card (experimental and incomplete) +- USB host connectors (input devices only, using the softusb-input firmware) +- RC5 infrared receiver +- RS232 debug port -It provides driver for timer, uart, ethernet, framebuffer so far. - -Milkymist SoC is running @ 83 MHz with 128 MB of 32-bit DDR400 SDRAM -The SoC is based on a XC6SLX45 Spartan-6 FPGA running -the LatticeMico32 softcore. - -More informations available at : http://www.milkymist.org/ - -Information about the porting can be found in Yann Sionneau's blog -at http://sionneau.net/ - -Milkymist is a project leaded by Sebastien Bourdeauducq (aka lekernel) +For more information: http://www.milkymist.org/ diff --git a/c/src/lib/libbsp/lm32/milkymist/include/bsp.h b/c/src/lib/libbsp/lm32/milkymist/include/bsp.h index 2d5a91c7c0..940e280fa2 100644 --- a/c/src/lib/libbsp/lm32/milkymist/include/bsp.h +++ b/c/src/lib/libbsp/lm32/milkymist/include/bsp.h @@ -8,8 +8,7 @@ * * $Id$ * - * Yann Sionneau <yann.sionneau@telecom-sudparis.eu>, (GSoC 2010) - * Telecom SudParis + * COPYRIGHT (c) 2011 Sebastien Bourdeauducq */ #ifndef _BSP_H @@ -22,22 +21,16 @@ #include <rtems/console.h> #include <rtems/clockdrv.h> - #ifdef __cplusplus extern "C" { #endif -#define BSP_DIRTY_MEMORY 1 - #define BSP_HAS_FRAME_BUFFER 1 -#define GPIO_DRIVER_TABLE_ENTRY { gpio_initialize, \ -gpio_open, gpio_close, gpio_read, gpio_write, gpio_control} - - /* - * lm32 requires certain aligment of mbuf because unaligned uint32_t - * accesses are not handled properly. - */ +/* + * lm32 requires certain aligment of mbuf because unaligned uint32_t + * accesses are not handled properly. + */ #define CPU_U32_FIX @@ -50,25 +43,8 @@ extern int rtems_minimac_driver_attach (struct rtems_bsdnet_ifconfig *config, #define RTEMS_BSP_NETWORK_DRIVER_NAME "minimac0" #endif - /* - * Simple spin delay in microsecond units for device drivers. - * This is very dependent on the clock speed of the target. - */ - -#define rtems_bsp_delay( microseconds ) \ - { \ - } - -/* functions */ -lm32_isr_entry set_vector( /* returns old vector */ - rtems_isr_entry handler, /* isr routine */ - rtems_vector_number vector, /* vector number */ - int type /* RTEMS or RAW intr */ -); - #ifdef __cplusplus } #endif #endif -/* end of include file */ diff --git a/c/src/lib/libbsp/lm32/milkymist/include/system_conf.h b/c/src/lib/libbsp/lm32/milkymist/include/system_conf.h index 5f49c91f76..6588e8f5eb 100644 --- a/c/src/lib/libbsp/lm32/milkymist/include/system_conf.h +++ b/c/src/lib/libbsp/lm32/milkymist/include/system_conf.h @@ -1,56 +1,304 @@ /* system_conf.h * Global System conf - * + * * Milkymist port of RTEMS * - * The license and distribution terms for this file may be + * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at * http://www.rtems.com/license/LICENSE. * * $Id$ * + * COPYRIGHT (c) 2010, 2011 Sebastien Bourdeauducq */ #ifndef __SYSTEM_CONFIG_H_ #define __SYSTEM_CONFIG_H_ -#define CPU_FREQUENCY (83333333) -#define UART_BAUD_RATE (115200) +#define CPU_FREQUENCY (80000000) +#define UART_BAUD_RATE (115200) + +/* FML bridge */ +#define FMLBRG_FLUSH_BASE (0xc8000000) +#define FMLBRG_LINE_LENGTH (32) +#define FMLBRG_LINE_COUNT (512) + +/* UART */ +#define MM_UART_RXTX (0xe0000000) +#define MM_UART_DIV (0xe0000004) + +/* Timers */ +#define MM_TIMER1_COMPARE (0xe0001024) +#define MM_TIMER1_COUNTER (0xe0001028) +#define MM_TIMER1_CONTROL (0xe0001020) + +#define MM_TIMER0_COMPARE (0xe0001014) +#define MM_TIMER0_COUNTER (0xe0001018) +#define MM_TIMER0_CONTROL (0xe0001010) + +#define TIMER_ENABLE (0x01) +#define TIMER_AUTORESTART (0x02) + +/* GPIO */ +#define MM_GPIO_IN (0xe0001000) +#define MM_GPIO_OUT (0xe0001004) +#define MM_GPIO_INTEN (0xe0001008) + +#define GPIO_BTN1 (0x00000001) +#define GPIO_BTN2 (0x00000002) +#define GPIO_BTN3 (0x00000004) +#define GPIO_PCBREV0 (0x00000008) +#define GPIO_PCBREV1 (0x00000010) +#define GPIO_PCBREV2 (0x00000020) +#define GPIO_PCBREV3 (0x00000040) +#define GPIO_LED1 (0x00000001) +#define GPIO_LED2 (0x00000002) -#define MM_TIMER1_COMPARE (0xe0001024) -#define MM_TIMER1_COUNTER (0xe0001028) -#define MM_TIMER1_CONTROL (0xe0001020) +/* System ID and reset */ +#define MM_SYSTEM_ID (0xe000103c) -#define MM_TIMER0_COMPARE (0xe0001014) -#define MM_TIMER0_COUNTER (0xe0001018) -#define MM_TIMER0_CONTROL (0xe0001010) +/* ICAP */ +#define MM_ICAP (0xe0001034) -#define TIMER_ENABLE (0x01) -#define TIMER_AUTORESTART (0x02) +#define ICAP_READY (0x01) +#define ICAP_CE (0x10000) +#define ICAP_WRITE (0x20000) -#define MM_VGA_RESET_MODE (0x01) -#define MM_VGA_RESET (0xe0003000) -#define MM_VGA_BASEADDRESS (0xe0003024) +/* VGA */ +#define MM_VGA_RESET (0xe0003000) + +#define MM_VGA_HRES (0xe0003004) +#define MM_VGA_HSYNC_START (0xe0003008) +#define MM_VGA_HSYNC_END (0xe000300C) +#define MM_VGA_HSCAN (0xe0003010) + +#define MM_VGA_VRES (0xe0003014) +#define MM_VGA_VSYNC_START (0xe0003018) +#define MM_VGA_VSYNC_END (0xe000301C) +#define MM_VGA_VSCAN (0xe0003020) + +#define MM_VGA_BASEADDRESS (0xe0003024) #define MM_VGA_BASEADDRESS_ACT (0xe0003028) -#define MM_MINIMAC_SETUP (0xe0009000) -#define MM_MINIMAC_STATE0 (0xe0009008) -#define MM_MINIMAC_ADDR0 (0xe000900C) -#define MM_MINIMAC_COUNT0 (0xe0009010) +#define MM_VGA_BURST_COUNT (0xe000302C) + +#define MM_VGA_DDC (0xe0003030) + +#define MM_VGA_CLKSEL (0xe0003034) + +#define VGA_RESET (0x01) +#define VGA_DDC_SDAIN (0x1) +#define VGA_DDC_SDAOUT (0x2) +#define VGA_DDC_SDAOE (0x4) +#define VGA_DDC_SDC (0x8) + +/* Ethernet */ +#define MM_MINIMAC_SETUP (0xe0008000) +#define MM_MINIMAC_MDIO (0xe0008004) + +#define MM_MINIMAC_STATE0 (0xe0008008) +#define MM_MINIMAC_COUNT0 (0xe000800C) +#define MM_MINIMAC_STATE1 (0xe0008010) +#define MM_MINIMAC_COUNT1 (0xe0008014) + +#define MM_MINIMAC_TXCOUNT (0xe0008018) + +#define MINIMAC_RX0_BASE (0xb0000000) +#define MINIMAC_RX1_BASE (0xb0000800) +#define MINIMAC_TX_BASE (0xb0001000) + +#define MINIMAC_SETUP_PHYRST (0x1) + +#define MINIMAC_STATE_EMPTY (0x0) +#define MINIMAC_STATE_LOADED (0x1) +#define MINIMAC_STATE_PENDING (0x2) + +/* AC97 */ +#define MM_AC97_CRCTL (0xe0005000) + +#define AC97_CRCTL_RQEN (0x01) +#define AC97_CRCTL_WRITE (0x02) + +#define MM_AC97_CRADDR (0xe0005004) +#define MM_AC97_CRDATAOUT (0xe0005008) +#define MM_AC97_CRDATAIN (0xe000500C) + +#define MM_AC97_DCTL (0xe0005010) +#define MM_AC97_DADDRESS (0xe0005014) +#define MM_AC97_DREMAINING (0xe0005018) + +#define MM_AC97_UCTL (0xe0005020) +#define MM_AC97_UADDRESS (0xe0005024) +#define MM_AC97_UREMAINING (0xe0005028) + +#define AC97_SCTL_EN (0x01) + +#define AC97_MAX_DMASIZE (0x3fffc) + +/* SoftUSB */ +#define MM_SOFTUSB_CONTROL (0xe000f000) + +#define SOFTUSB_CONTROL_RESET (0x1) + +#define MM_SOFTUSB_PMEM_BASE (0xa0000000) +#define MM_SOFTUSB_DMEM_BASE (0xa0020000) + +#define SOFTUSB_PMEM_SIZE (1 << 12) +#define SOFTUSB_DMEM_SIZE (1 << 13) + +/* PFPU */ +#define MM_PFPU_CTL (0xe0006000) +#define PFPU_CTL_START (0x01) +#define PFPU_CTL_BUSY (0x01) + +#define MM_PFPU_MESHBASE (0xe0006004) +#define MM_PFPU_HMESHLAST (0xe0006008) +#define MM_PFPU_VMESHLAST (0xe000600C) + +#define MM_PFPU_CODEPAGE (0xe0006010) + +#define MM_PFPU_DREGBASE (0xe0006400) +#define MM_PFPU_CODEBASE (0xe0006800) + +#define PFPU_PAGESIZE (512) +#define PFPU_SPREG_COUNT (2) +#define PFPU_REG_X (0) +#define PFPU_REG_Y (1) + +/* TMU */ +#define MM_TMU_CTL (0xe0007000) +#define TMU_CTL_START (0x01) +#define TMU_CTL_BUSY (0x01) +#define TMU_CTL_CHROMAKEY (0x02) + +#define MM_TMU_HMESHLAST (0xe0007004) +#define MM_TMU_VMESHLAST (0xe0007008) +#define MM_TMU_BRIGHTNESS (0xe000700C) +#define MM_TMU_CHROMAKEY (0xe0007010) + +#define MM_TMU_VERTICESADR (0xe0007014) +#define MM_TMU_TEXFBUF (0xe0007018) +#define MM_TMU_TEXHRES (0xe000701C) +#define MM_TMU_TEXVRES (0xe0007020) +#define MM_TMU_TEXHMASK (0xe0007024) +#define MM_TMU_TEXVMASK (0xe0007028) + +#define MM_TMU_DSTFBUF (0xe000702C) +#define MM_TMU_DSTHRES (0xe0007030) +#define MM_TMU_DSTVRES (0xe0007034) +#define MM_TMU_DSTHOFFSET (0xe0007038) +#define MM_TMU_DSTVOFFSET (0xe000703C) +#define MM_TMU_DSTSQUAREW (0xe0007040) +#define MM_TMU_DSTSQUAREH (0xe0007044) + +#define MM_TMU_ALPHA (0xe0007048) + +/* Memory card */ +#define MM_MEMCARD_CLK2XDIV (0xe0004000) + +#define MM_MEMCARD_ENABLE (0xe0004004) + +#define MEMCARD_ENABLE_CMD_TX (0x1) +#define MEMCARD_ENABLE_CMD_RX (0x2) +#define MEMCARD_ENABLE_DAT_TX (0x4) +#define MEMCARD_ENABLE_DAT_RX (0x8) + +#define MM_MEMCARD_PENDING (0xe0004008) + +#define MEMCARD_PENDING_CMD_TX (0x1) +#define MEMCARD_PENDING_CMD_RX (0x2) +#define MEMCARD_PENDING_DAT_TX (0x4) +#define MEMCARD_PENDING_DAT_RX (0x8) + +#define MM_MEMCARD_START (0xe000400c) + +#define MEMCARD_START_CMD_RX (0x1) +#define MEMCARD_START_DAT_RX (0x2) + +#define MM_MEMCARD_CMD (0xe0004010) +#define MM_MEMCARD_DAT (0xe0004014) + +/* DMX */ +#define MM_DMX_TX(x) (0xe000c000+4*(x)) +#define MM_DMX_THRU (0xe000c800) +#define MM_DMX_RX(x) (0xe000d000+4*(x)) + +/* MIDI */ +#define MM_MIDI_RXTX (0xe000b000) +#define MM_MIDI_DIVISOR (0xe000b004) +#define MM_MIDI_THRU (0xe000b008) + +/* IR */ +#define MM_IR_RX (0xe000e000) + +/* Video input */ +#define MM_BT656_I2C (0xe000a000) +#define MM_BT656_FILTERSTATUS (0xe000a004) +#define MM_BT656_BASE (0xe000a008) +#define MM_BT656_MAXBURSTS (0xe000a00c) +#define MM_BT656_DONEBURSTS (0xe000a010) + +#define BT656_I2C_SDAIN (0x1) +#define BT656_I2C_SDAOUT (0x2) +#define BT656_I2C_SDAOE (0x4) +#define BT656_I2C_SDC (0x8) + +#define BT656_FILTER_FIELD1 (0x1) +#define BT656_FILTER_FIELD2 (0x2) +#define BT656_FILTER_INFRAME (0x4) + +/* Interrupts */ +#define MM_IRQ_UARTRX (0) +#define MM_IRQ_UARTTX (1) +#define MM_IRQ_GPIO (2) +#define MM_IRQ_TIMER0 (3) +#define MM_IRQ_TIMER1 (4) +#define MM_IRQ_AC97CRREQUEST (5) +#define MM_IRQ_AC97CRREPLY (6) +#define MM_IRQ_AC97DMAR (7) +#define MM_IRQ_AC97DMAW (8) +#define MM_IRQ_PFPU (9) +#define MM_IRQ_TMU (10) +#define MM_IRQ_ETHRX (11) +#define MM_IRQ_ETHTX (12) +#define MM_IRQ_VIDEOIN (13) +#define MM_IRQ_MIDIRX (14) +#define MM_IRQ_MIDITX (15) +#define MM_IRQ_IR (16) +#define MM_IRQ_USB (17) + +/* Flash layout */ +#define FLASH_BASE (0x80000000) + +#define FLASH_OFFSET_STANDBY_BITSTREAM (0x80000000) + +#define FLASH_OFFSET_RESCUE_BITSTREAM (0x800A0000) +#define FLASH_OFFSET_RESCUE_BIOS (0x80220000) +#define FLASH_OFFSET_MAC_ADDRESS (0x802200E0) +#define FLASH_OFFSET_RESCUE_SPLASH (0x80240000) +#define FLASH_OFFSET_RESCUE_APP (0x802E0000) + +#define FLASH_OFFSET_REGULAR_BITSTREAM (0x806E0000) +#define FLASH_OFFSET_REGULAR_BIOS (0x80860000) +#define FLASH_OFFSET_REGULAR_SPLASH (0x80880000) +#define FLASH_OFFSET_REGULAR_APP (0x80920000) + +/* MMIO */ +#define MM_READ(reg) (*((volatile unsigned int *)(reg))) +#define MM_WRITE(reg, val) *((volatile unsigned int *)(reg)) = val -#define MM_MINIMAC_STATE1 (0xe0009014) -#define MM_MINIMAC_ADDR1 (0xe0009018) -#define MM_MINIMAC_COUNT1 (0xe000901C) +/* Flash partitions */ -#define MM_MINIMAC_STATE2 (0xe0009020) -#define MM_MINIMAC_ADDR2 (0xe0009024) -#define MM_MINIMAC_COUNT2 (0xe0009028) +#define FLASH_SECTOR_SIZE (128*1024) -#define MM_MINIMAC_STATE3 (0xe000902C) -#define MM_MINIMAC_ADDR3 (0xe0009030) -#define MM_MINIMAC_COUNT3 (0xe0009034) +#define FLASH_PARTITION_COUNT (5) -#define MM_MINIMAC_TXREMAINING (0xe000903C) -#define MM_MINIMAC_TXADR (0xe0009038) +#define FLASH_PARTITIONS { \ + { .start_address = 0x806E0000, .length = 0x0180000 }, \ + { .start_address = 0x80860000, .length = 0x0020000 }, \ + { .start_address = 0x80880000, .length = 0x00A0000 }, \ + { .start_address = 0x80920000, .length = 0x0400000 }, \ + { .start_address = 0x80D20000, .length = 0x12E0000 }, \ +} #endif /* __SYSTEM_CONFIG_H_ */ diff --git a/c/src/lib/libbsp/lm32/milkymist/include/tm27.h b/c/src/lib/libbsp/lm32/milkymist/include/tm27.h deleted file mode 100644 index a10e11cab1..0000000000 --- a/c/src/lib/libbsp/lm32/milkymist/include/tm27.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * tm27.h - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.com/license/LICENSE. - * - * $Id$ - */ - -#ifndef _RTEMS_TMTEST27 -#error "This is an RTEMS internal file you must not include directly." -#endif - -#ifndef __tm27_h -#define __tm27_h - -/* - * Stuff for Time Test 27 - */ - -#define MUST_WAIT_FOR_INTERRUPT 0 - -#define Install_tm27_vector( handler ) set_vector( (handler), 0, 1 ) - -#define Cause_tm27_intr() /* empty */ - -#define Clear_tm27_intr() /* empty */ - -#define Lower_tm27_intr() /* empty */ - -#endif diff --git a/c/src/lib/libbsp/lm32/milkymist/make/custom/milkymist.cfg b/c/src/lib/libbsp/lm32/milkymist/make/custom/milkymist.cfg index 5571f7b113..5a44658389 100644 --- a/c/src/lib/libbsp/lm32/milkymist/make/custom/milkymist.cfg +++ b/c/src/lib/libbsp/lm32/milkymist/make/custom/milkymist.cfg @@ -18,7 +18,6 @@ CPU_CFLAGS = -mbarrel-shift-enabled -mmultiply-enabled \ -mdivide-enabled -msign-extend-enabled # optimize flag: typically -O2 -# ATM, doesn't work with optimization levels > 0 CFLAGS_OPTIMIZE_V = -O2 -g define bsp-post-link diff --git a/c/src/lib/libbsp/lm32/milkymist/preinstall.am b/c/src/lib/libbsp/lm32/milkymist/preinstall.am index b3375ceee9..c3217ef01a 100644 --- a/c/src/lib/libbsp/lm32/milkymist/preinstall.am +++ b/c/src/lib/libbsp/lm32/milkymist/preinstall.am @@ -41,10 +41,74 @@ $(PROJECT_INCLUDE)/bsp.h: include/bsp.h $(PROJECT_INCLUDE)/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp.h -$(PROJECT_INCLUDE)/tm27.h: include/tm27.h $(PROJECT_INCLUDE)/$(dirstamp) +$(PROJECT_INCLUDE)/coverhd.h: ../../shared/include/coverhd.h $(PROJECT_INCLUDE)/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/coverhd.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/coverhd.h + +$(PROJECT_INCLUDE)/tm27.h: ../../shared/include/tm27.h $(PROJECT_INCLUDE)/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/tm27.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/tm27.h +$(PROJECT_INCLUDE)/bsp/irq.h: ../../lm32/shared/include/irq.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/irq.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/irq.h + +$(PROJECT_INCLUDE)/bsp/irq-generic.h: ../../shared/include/irq-generic.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/irq-generic.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/irq-generic.h + +$(PROJECT_INCLUDE)/bsp/milkymist_gpio.h: ../../lm32/shared/milkymist_gpio/milkymist_gpio.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/milkymist_gpio.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/milkymist_gpio.h + +$(PROJECT_INCLUDE)/bsp/milkymist_buttons.h: ../../lm32/shared/milkymist_buttons/milkymist_buttons.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/milkymist_buttons.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/milkymist_buttons.h + +$(PROJECT_INCLUDE)/bsp/milkymist_ac97.h: ../../lm32/shared/milkymist_ac97/milkymist_ac97.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/milkymist_ac97.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/milkymist_ac97.h + +$(PROJECT_INCLUDE)/bsp/milkymist_usbinput.h: ../../lm32/shared/milkymist_usbinput/milkymist_usbinput.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/milkymist_usbinput.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/milkymist_usbinput.h + +$(PROJECT_INCLUDE)/bsp/milkymist_pfpu.h: ../../lm32/shared/milkymist_pfpu/milkymist_pfpu.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/milkymist_pfpu.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/milkymist_pfpu.h + +$(PROJECT_INCLUDE)/bsp/milkymist_tmu.h: ../../lm32/shared/milkymist_tmu/milkymist_tmu.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/milkymist_tmu.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/milkymist_tmu.h + +$(PROJECT_INCLUDE)/bsp/milkymist_memcard.h: ../../lm32/shared/milkymist_memcard/milkymist_memcard.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/milkymist_memcard.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/milkymist_memcard.h + +$(PROJECT_INCLUDE)/bsp/milkymist_flash.h: ../../lm32/shared/milkymist_flash/milkymist_flash.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/milkymist_flash.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/milkymist_flash.h + +$(PROJECT_INCLUDE)/bsp/milkymist_dmx.h: ../../lm32/shared/milkymist_dmx/milkymist_dmx.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/milkymist_dmx.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/milkymist_dmx.h + +$(PROJECT_INCLUDE)/bsp/milkymist_midi.h: ../../lm32/shared/milkymist_midi/milkymist_midi.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/milkymist_midi.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/milkymist_midi.h + +$(PROJECT_INCLUDE)/bsp/milkymist_ir.h: ../../lm32/shared/milkymist_ir/milkymist_ir.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/milkymist_ir.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/milkymist_ir.h + +$(PROJECT_INCLUDE)/bsp/milkymist_video.h: ../../lm32/shared/milkymist_video/milkymist_video.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/milkymist_video.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/milkymist_video.h + +$(PROJECT_INCLUDE)/bsp/milkymist_versions.h: ../../lm32/shared/milkymist_versions/milkymist_versions.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/milkymist_versions.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/milkymist_versions.h + $(PROJECT_INCLUDE)/bspopts.h: include/bspopts.h $(PROJECT_INCLUDE)/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bspopts.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/bspopts.h @@ -53,10 +117,6 @@ $(PROJECT_INCLUDE)/bsp/bootcard.h: ../../shared/include/bootcard.h $(PROJECT_INC $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/bootcard.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/bootcard.h -$(PROJECT_INCLUDE)/coverhd.h: ../../shared/include/coverhd.h $(PROJECT_INCLUDE)/$(dirstamp) - $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/coverhd.h -PREINSTALL_FILES += $(PROJECT_INCLUDE)/coverhd.h - $(PROJECT_INCLUDE)/system_conf.h: include/system_conf.h $(PROJECT_INCLUDE)/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/system_conf.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/system_conf.h diff --git a/c/src/lib/libbsp/lm32/milkymist/startup/bspclean.c b/c/src/lib/libbsp/lm32/milkymist/startup/bspclean.c new file mode 100644 index 0000000000..202ff47c0d --- /dev/null +++ b/c/src/lib/libbsp/lm32/milkymist/startup/bspclean.c @@ -0,0 +1,56 @@ +/* bspclean.c + * + * Milkymist shutdown routine + * + * COPYRIGHT (c) 2010 Sebastien Bourdeauducq + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#include <rtems.h> +#include "../include/system_conf.h" + +static void reboot(void) +{ + /* Writing to CSR_SYSTEM_ID causes a system reset */ + MM_WRITE(MM_SYSTEM_ID, 1); +} + +static void icap_write(int val, unsigned int w) +{ + while (!(MM_READ(MM_ICAP) & ICAP_READY)); + if (!val) + w |= ICAP_CE|ICAP_WRITE; + MM_WRITE(MM_ICAP, w); +} +static void reconf(void) +{ + icap_write(0, 0xffff); /* dummy word */ + icap_write(0, 0xffff); /* dummy word */ + icap_write(0, 0xffff); /* dummy word */ + icap_write(0, 0xffff); /* dummy word */ + icap_write(1, 0xaa99); /* sync word part 1 */ + icap_write(1, 0x5566); /* sync word part 2 */ + icap_write(1, 0x30a1); /* write to command register */ + icap_write(1, 0x0000); /* null command */ + icap_write(1, 0x30a1); /* write to command register */ + icap_write(1, 0x000e); /* reboot command */ + icap_write(1, 0x2000); /* NOP */ + icap_write(1, 0x2000); /* NOP */ + icap_write(1, 0x2000); /* NOP */ + icap_write(1, 0x2000); /* NOP */ + icap_write(0, 0x1111); /* NULL */ + icap_write(0, 0xffff); /* dummy word */ +} + +void bsp_cleanup(uint32_t status) +{ + if (status) + reconf(); + else + reboot(); +} diff --git a/c/src/lib/libbsp/lm32/milkymist/startup/linkcmds b/c/src/lib/libbsp/lm32/milkymist/startup/linkcmds index 490ae6093a..aeebec78d1 100644 --- a/c/src/lib/libbsp/lm32/milkymist/startup/linkcmds +++ b/c/src/lib/libbsp/lm32/milkymist/startup/linkcmds @@ -9,13 +9,13 @@ ENTRY(_start) * Declare some sizes. Heap is sized at whatever ram space is left. */ RamBase = DEFINED(RamBase) ? RamBase : 0x40000000; -RamSize = DEFINED(RamSize) ? RamSize : 64M; -HeapSize = DEFINED(HeapSize) ? HeapSize : 2M; +RamSize = DEFINED(RamSize) ? RamSize : 128M; +HeapSize = DEFINED(HeapSize) ? HeapSize : 92M; _StackSize = DEFINED(_StackSize) ? _StackSize : 0x2000; PROVIDE (__stack = 0); MEMORY { - sdram : ORIGIN = 0x40000000 , LENGTH = 64M + sdram : ORIGIN = 0x40000000 , LENGTH = 128M } SECTIONS { diff --git a/c/src/lib/libbsp/lm32/shared/ChangeLog b/c/src/lib/libbsp/lm32/shared/ChangeLog new file mode 100644 index 0000000000..c7fa29ca85 --- /dev/null +++ b/c/src/lib/libbsp/lm32/shared/ChangeLog @@ -0,0 +1,21 @@ +2011-08-01 Sebastien Bourdeauducq <sebastien.bourdeauducq@gmail.com> + + PR 1869/bsps + * startup/bspclean.c: New file. + * include/tm27.h: Removed. + * ChangeLog, Makefile.am, README, preinstall.am, include/bsp.h, + include/system_conf.h, make/custom/milkymist.cfg, startup/linkcmds: + Complete BSP for Milkymist One supporting Milkymist SOC 1.0.x. + Includes new or updated drivers for: + - Multi-standard video input (PAL/SECAM/NTSC) + - Two DMX512 (RS485) ports + - MIDI IN and MIDI OUT ports + - VGA output + - AC'97 audio + - NOR flash + - 10/100 Ethernet + - Memory card (experimental and incomplete) + - USB host connectors (input devices only) + - RC5 infrared receiver + - RS232 debug port + diff --git a/c/src/lib/libbsp/lm32/shared/gdbstub/lm32-stub.c b/c/src/lib/libbsp/lm32/shared/gdbstub/lm32-stub.c index b1d453e691..a4dc3f66f0 100644 --- a/c/src/lib/libbsp/lm32/shared/gdbstub/lm32-stub.c +++ b/c/src/lib/libbsp/lm32/shared/gdbstub/lm32-stub.c @@ -25,6 +25,8 @@ * SUCH DAMAGE. */ +/* $Id$ */ + #include <bsp.h> #include <string.h> #include <signal.h> diff --git a/c/src/lib/libbsp/lm32/shared/include/irq.h b/c/src/lib/libbsp/lm32/shared/include/irq.h new file mode 100644 index 0000000000..784b0c0221 --- /dev/null +++ b/c/src/lib/libbsp/lm32/shared/include/irq.h @@ -0,0 +1,49 @@ +/** + * @file + * + * @ingroup bsp_interrupt + * + * @brief BSP interrupt support for LM32. + */ + +/* + * Based on concepts of Pavel Pisa, Till Straumann and Eric Valette. + * + * Copyright (c) 2008, 2009, 2010 + * embedded brains GmbH + * Obere Lagerstr. 30 + * D-82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifndef LIBBSP_LM32_IRQ_CONFIG_H +#define LIBBSP_LM32_IRQ_CONFIG_H + +#include <stdint.h> + +/** + * @addtogroup bsp_interrupt + * + * @{ + */ + +/** + * @brief Minimum vector number. + */ +#define BSP_INTERRUPT_VECTOR_MIN 0 + +/** + * @brief Maximum vector number. + */ +#define BSP_INTERRUPT_VECTOR_MAX 31 + +/** @} */ + +#endif /* LIBBSP_LM32_IRQ_CONFIG_H */ diff --git a/c/src/lib/libbsp/lm32/shared/irq/irq.c b/c/src/lib/libbsp/lm32/shared/irq/irq.c new file mode 100644 index 0000000000..f5d9f82050 --- /dev/null +++ b/c/src/lib/libbsp/lm32/shared/irq/irq.c @@ -0,0 +1,37 @@ +/* irq.c + * + * Copyright (c) 2010 Sebastien Bourdeauducq + * + * The license and distribution terms for this file may be + * found in found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#include <bsp.h> +#include <rtems/score/cpu.h> +#include <bsp/irq.h> +#include <bsp/irq-generic.h> + +rtems_status_code bsp_interrupt_facility_initialize(void) +{ + return RTEMS_SUCCESSFUL; +} + +rtems_status_code bsp_interrupt_vector_enable(rtems_vector_number vector) +{ + lm32_interrupt_unmask(1 << vector); + return RTEMS_SUCCESSFUL; +} + +rtems_status_code bsp_interrupt_vector_disable(rtems_vector_number vector) +{ + lm32_interrupt_mask(1 << vector); + return RTEMS_SUCCESSFUL; +} + +void bsp_interrupt_handler_default(rtems_vector_number vector) +{ + printk("spurious interrupt: %u\n", vector); +} diff --git a/c/src/lib/libbsp/lm32/shared/milkymist_ac97/ac97.c b/c/src/lib/libbsp/lm32/shared/milkymist_ac97/ac97.c index 671d4f165b..b467538122 100644 --- a/c/src/lib/libbsp/lm32/shared/milkymist_ac97/ac97.c +++ b/c/src/lib/libbsp/lm32/shared/milkymist_ac97/ac97.c @@ -1,7 +1,6 @@ /* ac97.c * - * This file is the sound driver for the Milkymist One board - * It does an OSS style character device in /dev/snd + * Sound driver for Milkymist SoC * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at @@ -9,111 +8,419 @@ * * $Id$ * - * COPYRIGHT (c) Yann Sionneau <yann.sionneau@telecom-sudparis.eu> (GSoC 2010) - * Telecom SudParis + * COPYRIGHT (c) 2010, 2011 Sebastien Bourdeauducq */ -#include <stdlib.h> -#include <stdio.h> -#include <errno.h> -#include <sys/types.h> -#include <pthread.h> +#define RTEMS_STATUS_CHECKS_USE_PRINTK + #include <rtems.h> #include <bsp.h> -#include "../include/system_conf.h" +#include <bsp/irq-generic.h> #include <rtems/libio.h> +#include <rtems/status-checks.h> +#include "../include/system_conf.h" +#include "milkymist_ac97.h" -#define GPIO_DRIVER_TABLE_ENTRY { ac97_initialize, \ -ac97_open, ac97_close, ac97_read, ac97_write, ac97_control} +#define SND_DEVICE_NAME "/dev/snd" +#define MIXER_DEVICE_NAME "/dev/mixer" -#define SND_DEVICE_NAME "/dev/snd" +static rtems_id cr_write_sem; +static rtems_id cr_read_sem; -static struct milkymist_ac97 { - rtems_device_minor_number minor; - pthread_mutex_t mutex; -} ac97_driver; +static rtems_isr crrequest_handler(rtems_vector_number n) +{ + rtems_semaphore_release(cr_write_sem); + lm32_interrupt_ack(1 << MM_IRQ_AC97CRREQUEST); +} -rtems_device_driver gpio_initialize( -rtems_device_major_number major, -rtems_device_minor_number minor, -void *arg) +static rtems_isr crreply_handler(rtems_vector_number n) { - rtems_status_code status; + rtems_semaphore_release(cr_read_sem); + lm32_interrupt_ack(1 << MM_IRQ_AC97CRREPLY); +} - printk( "ac97 driver initializing..\n" ); +/* queued playback buffers */ +#define PLAY_Q_SIZE 8 +#define PLAY_Q_MASK (PLAY_Q_SIZE-1) - status = rtems_io_register_name(SND_DEVICE_NAME, major, 0); - if (status != RTEMS_SUCCESSFUL) - { - printk("Error registering /dev/snd ac97 device \n"); - rtems_fatal_error_occurred( status ); - } - gpio[0].minor = 0; - gpio[0].mutex = PTHREAD_MUTEX_INITIALIZER; +static struct snd_buffer *play_q[PLAY_Q_SIZE]; +static int play_produce; +static int play_consume; +static int play_level; - return RTEMS_SUCCESSFUL; +/* buffers played, for application to collect */ +static rtems_id play_q_done; + +static void play_start(struct snd_buffer *buf) +{ + if (buf->nsamples > (AC97_MAX_DMASIZE/4)) + buf->nsamples = AC97_MAX_DMASIZE/4; + + MM_WRITE(MM_AC97_DADDRESS, (unsigned int)buf->samples); + MM_WRITE(MM_AC97_DREMAINING, buf->nsamples*4); + MM_WRITE(MM_AC97_DCTL, AC97_SCTL_EN); +} + +static rtems_isr pcmplay_handler(rtems_vector_number n) +{ + lm32_interrupt_ack(1 << MM_IRQ_AC97DMAR); + + rtems_message_queue_send(play_q_done, &play_q[play_consume], + sizeof(void *)); + + play_consume = (play_consume + 1) & PLAY_Q_MASK; + play_level--; + + if(play_level > 0) + play_start(play_q[play_consume]); + else + MM_WRITE(MM_AC97_DCTL, 0); +} + +/* queued record buffers */ +#define RECORD_Q_SIZE 8 +#define RECORD_Q_MASK (RECORD_Q_SIZE-1) + +static struct snd_buffer *record_q[RECORD_Q_SIZE]; +static int record_produce; +static int record_consume; +static int record_level; + +/* buffers recorded, for application to collect */ +static rtems_id record_q_done; + +static void record_start(struct snd_buffer *buf) +{ + if (buf->nsamples > (AC97_MAX_DMASIZE/4)) + buf->nsamples = AC97_MAX_DMASIZE/4; + + MM_WRITE(MM_AC97_UADDRESS, (unsigned int)buf->samples); + MM_WRITE(MM_AC97_UREMAINING, buf->nsamples*4); + MM_WRITE(MM_AC97_UCTL, AC97_SCTL_EN); +} + +static rtems_isr pcmrecord_handler(rtems_vector_number n) +{ + lm32_interrupt_ack(1 << MM_IRQ_AC97DMAW); + + __asm__ volatile( /* Invalidate Level-1 data cache */ + "wcsr DCC, r0\n" + "nop\n" + ); + + rtems_message_queue_send(record_q_done, &record_q[record_consume], + sizeof(void *)); + + record_consume = (record_consume + 1) & RECORD_Q_MASK; + record_level--; + + if(record_level > 0) + record_start(record_q[record_consume]); + else + MM_WRITE(MM_AC97_UCTL, 0); } -rtems_device_driver gpio_close( - rtems_device_major_number major, - rtems_device_minor_number minor, +rtems_device_driver ac97_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor, void *arg ) { - if (pthread_mutex_unlock(&ac97_driver.mutex) == 0){ - return RTEMS_SUCCESSFUL; + rtems_status_code sc; + rtems_isr_entry dummy; + + sc = rtems_io_register_name(SND_DEVICE_NAME, major, 0); + RTEMS_CHECK_SC(sc, "create snd device"); + + sc = rtems_io_register_name(MIXER_DEVICE_NAME, major, 1); + RTEMS_CHECK_SC(sc, "create mixer device"); + + sc = rtems_semaphore_create( + rtems_build_name('C', 'R', 'W', 'S'), + 0, + RTEMS_SIMPLE_BINARY_SEMAPHORE, + 0, + &cr_write_sem + ); + RTEMS_CHECK_SC(sc, "create AC97 register write semaphore"); + + sc = rtems_semaphore_create( + rtems_build_name('C', 'R', 'R', 'S'), + 0, + RTEMS_SIMPLE_BINARY_SEMAPHORE, + 0, + &cr_read_sem + ); + RTEMS_CHECK_SC(sc, "create AC97 register read semaphore"); + + sc = rtems_message_queue_create( + rtems_build_name('P', 'L', 'Y', 'Q'), + PLAY_Q_SIZE*2, + sizeof(void *), + 0, + &play_q_done + ); + RTEMS_CHECK_SC(sc, "create playback done queue"); + + sc = rtems_message_queue_create( + rtems_build_name('R', 'E', 'C', 'Q'), + RECORD_Q_SIZE*2, + sizeof(void *), + 0, + &record_q_done + ); + RTEMS_CHECK_SC(sc, "create record done queue"); + + rtems_interrupt_catch(crrequest_handler, MM_IRQ_AC97CRREQUEST, &dummy); + rtems_interrupt_catch(crreply_handler, MM_IRQ_AC97CRREPLY, &dummy); + rtems_interrupt_catch(pcmplay_handler, MM_IRQ_AC97DMAR, &dummy); + rtems_interrupt_catch(pcmrecord_handler, MM_IRQ_AC97DMAW, &dummy); + bsp_interrupt_vector_enable(MM_IRQ_AC97CRREQUEST); + bsp_interrupt_vector_enable(MM_IRQ_AC97CRREPLY); + bsp_interrupt_vector_enable(MM_IRQ_AC97DMAR); + bsp_interrupt_vector_enable(MM_IRQ_AC97DMAW); + + play_produce = 0; + play_consume = 0; + play_level = 0; + + record_produce = 0; + record_consume = 0; + record_level = 0; + + return RTEMS_SUCCESSFUL; +} + +static rtems_status_code submit_play(struct snd_buffer *buf) +{ + bsp_interrupt_vector_disable(MM_IRQ_AC97DMAR); + if (play_level == PLAY_Q_SIZE) { + bsp_interrupt_vector_enable(MM_IRQ_AC97DMAR); + return RTEMS_UNSATISFIED; } - return RTEMS_UNSATISFIED; + play_q[play_produce] = buf; + play_produce = (play_produce + 1) & PLAY_Q_MASK; + play_level++; + + if (play_level == 1) + play_start(buf); + + bsp_interrupt_vector_enable(MM_IRQ_AC97DMAR); + return RTEMS_SUCCESSFUL; } -rtems_device_driver gpio_open( - rtems_device_major_number major, - rtems_device_minor_number minor, - void *arg -) +static rtems_status_code collect_play(struct snd_buffer **buf) { - if (pthread_mutex_trylock(&ac97_driver.mutex) == 0){ - return RTEMS_SUCCESSFUL; + size_t s; + + return rtems_message_queue_receive( + play_q_done, + buf, + &s, + RTEMS_WAIT, + RTEMS_NO_TIMEOUT + ); +} + +static rtems_status_code submit_record(struct snd_buffer *buf) +{ + bsp_interrupt_vector_disable(MM_IRQ_AC97DMAW); + if (record_level == RECORD_Q_SIZE) { + bsp_interrupt_vector_enable(MM_IRQ_AC97DMAW); + return RTEMS_UNSATISFIED; } - return RTEMS_UNSATISFIED; + record_q[record_produce] = buf; + record_produce = (record_produce + 1) & RECORD_Q_MASK; + record_level++; + + if (record_level == 1) + record_start(buf); + + bsp_interrupt_vector_enable(MM_IRQ_AC97DMAW); + return RTEMS_SUCCESSFUL; +} + +static rtems_status_code collect_record(struct snd_buffer **buf) +{ + size_t s; + + return rtems_message_queue_receive( + record_q_done, + buf, + &s, + RTEMS_WAIT, + RTEMS_NO_TIMEOUT + ); } +#define CR_TIMEOUT 10 + +static int read_cr(unsigned int adr) +{ + rtems_status_code sc; + + MM_WRITE(MM_AC97_CRADDR, adr); + MM_WRITE(MM_AC97_CRCTL, AC97_CRCTL_RQEN); + sc = rtems_semaphore_obtain(cr_write_sem, RTEMS_WAIT, CR_TIMEOUT); + if (sc != RTEMS_SUCCESSFUL) + return -1; + sc = rtems_semaphore_obtain(cr_read_sem, RTEMS_WAIT, CR_TIMEOUT); + if (sc != RTEMS_SUCCESSFUL) + return -1; + return MM_READ(MM_AC97_CRDATAIN); +} + +static int write_cr(unsigned int adr, unsigned int val) +{ + rtems_status_code sc; + + MM_WRITE(MM_AC97_CRADDR, adr); + MM_WRITE(MM_AC97_CRDATAOUT, val); + MM_WRITE(MM_AC97_CRCTL, AC97_CRCTL_RQEN|AC97_CRCTL_WRITE); + sc = rtems_semaphore_obtain(cr_write_sem, RTEMS_WAIT, CR_TIMEOUT); + if (sc != RTEMS_SUCCESSFUL) + return 0; + return 1; +} -rtems_device_driver gpio_read( - rtems_device_major_number major, - rtems_device_minor_number minor, - void *arg +rtems_device_driver ac97_open( + 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; + int codec_id; - return RTEMS_SUCCESSFUL; + if (minor == 0) { + /* snd */ + return RTEMS_SUCCESSFUL; + } else { + /* mixer */ + codec_id = read_cr(0x00); + if ((codec_id != 0x0d50) && (codec_id != 0x6150)) { + printk("AC97 codec detection failed\n"); + return RTEMS_UNSATISFIED; + } + write_cr(0x02, 0x0000); /* master volume */ + write_cr(0x04, 0x0f0f); /* headphones volume */ + write_cr(0x18, 0x0000); /* PCM out volume */ + write_cr(0x1c, 0x0f0f); /* record gain */ + + write_cr(0x1a, 0x0505); /* record select: stereo mix */ + + return RTEMS_SUCCESSFUL; + } } -rtems_device_driver gpio_write( - rtems_device_major_number major, - rtems_device_minor_number minor, - void *arg -) +static rtems_status_code ioctl_read_channel(void *buf, + unsigned int chan, int mono) { - rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *)arg; + unsigned int *val = (unsigned int *)buf; + int codec; + int left, right; + codec = read_cr(chan); + if (codec < 0) + return RTEMS_UNSATISFIED; + if (codec & 0x8000) { + /* muted */ + *val = 0; + return RTEMS_SUCCESSFUL; + } + if (mono) { + right = left = 100-(((codec & 0x1f) + 1)*100)/32; + } else { + right = 100-(((codec & 0x1f) + 1)*100)/32; + left = 100-((((codec & 0x1f00) >> 8) + 1)*100)/32; + } + *val = left | (right << 8); return RTEMS_SUCCESSFUL; } -rtems_device_driver gpio_control( - rtems_device_major_number major, - rtems_device_minor_number minor, - void *arg +static rtems_status_code ioctl_write_channel(void *buf, + unsigned int chan, int mono) +{ + unsigned int *val = (unsigned int *)buf; + int left, right; + int codec; + rtems_status_code sc; + + left = *val & 0xff; + left = (left*32)/100 - 1; + if(left < 0) + left = 0; + + if (mono) + right = 31; + else { + right = (*val >> 8) & 0xff; + right = (right*32)/100 - 1; + if(right < 0) + right = 0; + } + + if ((left == 0) && (right == 0)) + /* mute */ + codec = 0x8000; + else + codec = (31-left) | ((31-right) << 8); + + if (!write_cr(chan, codec)) + sc = RTEMS_UNSATISFIED; + else + sc = RTEMS_SUCCESSFUL; + return sc; +} + +rtems_device_driver ac97_control( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg ) { rtems_libio_ioctl_args_t *args = arg; + rtems_status_code sc; - switch( args->command ) { - default: - args->ioctl_return = 0; - break; + args->ioctl_return = -1; + if(minor == 0) { + /* dsp */ + switch (args->command) { + case SOUND_SND_SUBMIT_PLAY: + return submit_play((struct snd_buffer *)args->buffer); + case SOUND_SND_COLLECT_PLAY: + return collect_play((struct snd_buffer **)args->buffer); + case SOUND_SND_SUBMIT_RECORD: + return submit_record((struct snd_buffer *)args->buffer); + case SOUND_SND_COLLECT_RECORD: + return collect_record((struct snd_buffer **)args->buffer); + default: + return RTEMS_UNSATISFIED; + } + } else { + /* mixer */ + switch (args->command) { + case SOUND_MIXER_READ(SOUND_MIXER_MIC): + sc = ioctl_read_channel(args->buffer, 0x0e, 1); + if(sc == RTEMS_SUCCESSFUL) + args->ioctl_return = 0; + return sc; + case SOUND_MIXER_READ(SOUND_MIXER_LINE): + sc = ioctl_read_channel(args->buffer, 0x10, 0); + if(sc == RTEMS_SUCCESSFUL) + args->ioctl_return = 0; + return sc; + case SOUND_MIXER_WRITE(SOUND_MIXER_MIC): + sc = ioctl_write_channel(args->buffer, 0x0e, 1); + if(sc == RTEMS_SUCCESSFUL) + args->ioctl_return = 0; + return sc; + case SOUND_MIXER_WRITE(SOUND_MIXER_LINE): + sc = ioctl_write_channel(args->buffer, 0x10, 0); + if(sc == RTEMS_SUCCESSFUL) + args->ioctl_return = 0; + return sc; + default: + return RTEMS_UNSATISFIED; + } } - return RTEMS_SUCCESSFUL; } - diff --git a/c/src/lib/libbsp/lm32/shared/milkymist_ac97/milkymist_ac97.h b/c/src/lib/libbsp/lm32/shared/milkymist_ac97/milkymist_ac97.h new file mode 100644 index 0000000000..a13a0481ee --- /dev/null +++ b/c/src/lib/libbsp/lm32/shared/milkymist_ac97/milkymist_ac97.h @@ -0,0 +1,63 @@ +/* milkymist_ac97.h + * + * Milkymist AC97 driver for RTEMS + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + * + * COPYRIGHT (c) 2010 Sebastien Bourdeauducq + */ + +#ifndef __MILKYMIST_AC97_H_ +#define __MILKYMIST_AC97_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Ioctls. 0x41 is 'A' */ +#define SOUND_MIXER_MIC 0x0 +#define SOUND_MIXER_LINE 0x1 +#define SOUND_MIXER_READ(x) (0x4100+x) +#define SOUND_MIXER_WRITE(x) (0x4110+x) + +#define SOUND_SND_SUBMIT_PLAY 0x4120 +#define SOUND_SND_COLLECT_PLAY 0x4121 +#define SOUND_SND_SUBMIT_RECORD 0x4122 +#define SOUND_SND_COLLECT_RECORD 0x4123 + +struct snd_buffer { + unsigned int nsamples; + void *user; + unsigned int samples[]; +}; + +rtems_device_driver ac97_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +); + +rtems_device_driver ac97_open( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +); + +rtems_device_driver ac97_control( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +); + +#define AC97_DRIVER_TABLE_ENTRY {ac97_initialize, \ +ac97_open, NULL, NULL, NULL, ac97_control} + +#ifdef __cplusplus +} +#endif + +#endif /* __MILKYMIST_AC97_H_ */ diff --git a/c/src/lib/libbsp/lm32/shared/milkymist_buttons/buttons.c b/c/src/lib/libbsp/lm32/shared/milkymist_buttons/buttons.c new file mode 100644 index 0000000000..5772a781a1 --- /dev/null +++ b/c/src/lib/libbsp/lm32/shared/milkymist_buttons/buttons.c @@ -0,0 +1,132 @@ +/* buttons.c + * + * Buttons driver for the Milkymist One board + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + * + * COPYRIGHT (c) 2011 Sebastien Bourdeauducq + */ + +#define RTEMS_STATUS_CHECKS_USE_PRINTK + +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <sys/types.h> +#include <rtems.h> +#include <rtems/status-checks.h> +#include <bsp.h> +#include <bsp/irq-generic.h> +#include <rtems/libio.h> +#include "../include/system_conf.h" +#include "milkymist_buttons.h" + +#define DEVICE_NAME "/dev/buttons" + +static rtems_id event_q; + +static void send_byte(char b) +{ + rtems_message_queue_send(event_q, &b, 1); +} + +static rtems_isr interrupt_handler(rtems_vector_number n) +{ + static unsigned int previous_keys; + unsigned int keys, pushed_keys, released_keys; + + keys = MM_READ(MM_GPIO_IN) & (GPIO_BTN1|GPIO_BTN2|GPIO_BTN3); + pushed_keys = keys & ~previous_keys; + released_keys = previous_keys & ~keys; + previous_keys = keys; + + if(pushed_keys & GPIO_BTN1) + send_byte('A'); + if(pushed_keys & GPIO_BTN2) + send_byte('B'); + if(pushed_keys & GPIO_BTN3) + send_byte('C'); + + if(released_keys & GPIO_BTN1) + send_byte('a'); + if(released_keys & GPIO_BTN2) + send_byte('b'); + if(released_keys & GPIO_BTN3) + send_byte('c'); + + lm32_interrupt_ack(1 << MM_IRQ_GPIO); +} + +rtems_device_driver buttons_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + rtems_status_code sc; + rtems_isr_entry dummy; + + sc = rtems_io_register_name(DEVICE_NAME, major, 0); + RTEMS_CHECK_SC(sc, "create buttons device"); + + sc = rtems_message_queue_create( + rtems_build_name('B', 'T', 'N', 'Q'), + 24, + 1, + 0, + &event_q + ); + RTEMS_CHECK_SC(sc, "create buttons event queue"); + + rtems_interrupt_catch(interrupt_handler, MM_IRQ_GPIO, &dummy); + bsp_interrupt_vector_enable(MM_IRQ_GPIO); + MM_WRITE(MM_GPIO_INTEN, GPIO_BTN1|GPIO_BTN2|GPIO_BTN3); + + return RTEMS_SUCCESSFUL; +} + +rtems_device_driver buttons_open( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + uint32_t count; + + rtems_message_queue_flush(event_q, &count); + return RTEMS_SUCCESSFUL; +} + +rtems_device_driver buttons_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; + rtems_status_code sc; + + if(rw_args->count < 1) { + rw_args->bytes_moved = 0; + return RTEMS_UNSATISFIED; + } + + sc = rtems_message_queue_receive( + event_q, + rw_args->buffer, + (size_t *)&rw_args->bytes_moved, + RTEMS_WAIT, + RTEMS_NO_TIMEOUT + ); + + if(sc == RTEMS_SUCCESSFUL) + return RTEMS_SUCCESSFUL; + else { + rw_args->bytes_moved = 0; + return RTEMS_UNSATISFIED; + } +} diff --git a/c/src/lib/libbsp/lm32/shared/milkymist_buttons/milkymist_buttons.h b/c/src/lib/libbsp/lm32/shared/milkymist_buttons/milkymist_buttons.h new file mode 100644 index 0000000000..59eedb1e4b --- /dev/null +++ b/c/src/lib/libbsp/lm32/shared/milkymist_buttons/milkymist_buttons.h @@ -0,0 +1,46 @@ +/* milkymist_buttons.h + * + * Milkymist buttons driver for RTEMS + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + * + * COPYRIGHT (c) 2011 Sebastien Bourdeauducq + */ + +#ifndef __MILKYMIST_BUTTONS_H_ +#define __MILKYMIST_BUTTONS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +rtems_device_driver buttons_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +); + +rtems_device_driver buttons_open( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +); + +rtems_device_driver buttons_read( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +); + +#define BUTTONS_DRIVER_TABLE_ENTRY { buttons_initialize, \ +buttons_open, NULL, buttons_read, NULL, NULL} + +#ifdef __cplusplus +} +#endif + +#endif /* __MILKYMIST_BUTTONS_H_ */ diff --git a/c/src/lib/libbsp/lm32/shared/milkymist_clock/ckinit.c b/c/src/lib/libbsp/lm32/shared/milkymist_clock/ckinit.c index eb28ead0cc..72c770b608 100644 --- a/c/src/lib/libbsp/lm32/shared/milkymist_clock/ckinit.c +++ b/c/src/lib/libbsp/lm32/shared/milkymist_clock/ckinit.c @@ -13,6 +13,7 @@ */ #include <bsp.h> +#include <bsp/irq-generic.h> #include "../include/system_conf.h" #include "clock.h" #include "bspopts.h" @@ -21,50 +22,29 @@ #define CLOCK_DRIVER_USE_FAST_IDLE #endif -static inline int clockread(unsigned int reg) -{ - return *((int*)(reg)); -} - -static inline void clockwrite(unsigned int reg, int value) -{ - *((int*)reg) = value; -} - -/* - * The interrupt vector number associated with the clock tick device - * driver. - */ - -#define TIMER0_IRQ (1) - -#define CLOCK_VECTOR ( TIMER0_IRQ ) -#define CLOCK_IRQMASK ( 1 << CLOCK_VECTOR ) - #define Clock_driver_support_at_tick() \ do { \ - lm32_interrupt_ack(CLOCK_IRQMASK); \ + lm32_interrupt_ack(1 << MM_IRQ_TIMER0); \ } while (0) #define Clock_driver_support_install_isr(_new, _old ) \ do { \ - _old = (rtems_isr_entry) set_vector( _new, CLOCK_VECTOR, 1 ); \ + rtems_interrupt_catch(_new, MM_IRQ_TIMER0, &_old); \ } while (0) void Clock_driver_support_initialize_hardware(void) { - clockwrite(MM_TIMER0_COMPARE, (CPU_FREQUENCY / (1000000 / rtems_configuration_get_microseconds_per_tick()))); - - clockwrite(MM_TIMER0_COUNTER, 0); - clockwrite(MM_TIMER0_CONTROL, TIMER_ENABLE | TIMER_AUTORESTART); - lm32_interrupt_unmask(CLOCK_IRQMASK); + MM_WRITE(MM_TIMER0_COMPARE, + (CPU_FREQUENCY/(1000000/rtems_configuration_get_microseconds_per_tick()))); + MM_WRITE(MM_TIMER0_COUNTER, 0); + MM_WRITE(MM_TIMER0_CONTROL, TIMER_ENABLE | TIMER_AUTORESTART); + bsp_interrupt_vector_enable(MM_IRQ_TIMER0); } void Clock_driver_support_shutdown_hardware(void) { - lm32_interrupt_mask(CLOCK_IRQMASK); - clockwrite(MM_TIMER0_CONTROL, 0); + bsp_interrupt_vector_disable(MM_IRQ_TIMER0); + MM_WRITE(MM_TIMER0_CONTROL, 0); } #include "../../../shared/clockdrv_shell.h" - diff --git a/c/src/lib/libbsp/lm32/shared/milkymist_console/console.c b/c/src/lib/libbsp/lm32/shared/milkymist_console/console.c index 05ac7803df..6a000090f2 100644 --- a/c/src/lib/libbsp/lm32/shared/milkymist_console/console.c +++ b/c/src/lib/libbsp/lm32/shared/milkymist_console/console.c @@ -1,5 +1,5 @@ /* - * Console driver for Lattice Mico32 (lm32). + * Console driver for Milkymist * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at @@ -7,220 +7,214 @@ * * $Id$ * - * Jukka Pietarinen <jukka.pietarinen@mrf.fi>, 2008, - * Micro-Research Finland Oy - * - * COPYRIGHT (c) Yann Sionneau <yann.sionneau@telecom-sudparis.eu>, GSoc 2010 - * Telecom SudParis + * COPYRIGHT (c) 2010 Sebastien Bourdeauducq */ -#define NO_BSP_INIT +#include <unistd.h> +#include <termios.h> #include <rtems.h> -#include <bsp.h> #include <rtems/libio.h> +#include <rtems/console.h> +#include <rtems/termiostypes.h> +#include <bsp/irq-generic.h> -void BSP_uart_polled_write(char ch); -int BSP_uart_polled_read( void ); -char BSP_uart_is_character_ready(char *ch); +#include "../include/system_conf.h" +#include "uart.h" -/* console_initialize - * - * This routine initializes the console IO driver. - * - * Input parameters: NONE - * - * Output parameters: NONE - * - * Return values: - */ +BSP_output_char_function_type BSP_output_char = BSP_uart_polled_write; +BSP_polling_getchar_function_type BSP_poll_char = BSP_uart_polled_read; -rtems_device_driver console_initialize( - rtems_device_major_number major, - rtems_device_minor_number minor, - void *arg -) +static struct rtems_termios_tty *tty; + +static int mmconsole_first_open(int major, int minor, void *arg) { - rtems_status_code status; + tty = ((rtems_libio_open_close_args_t *) arg)->iop->data1; + return rtems_termios_set_initial_baud(tty, UART_BAUD_RATE); +} - printk("console_initialize\n"); +static int mmconsole_last_close(int major, int minor, void *arg) +{ + return 0; +} - status = rtems_io_register_name( - "/dev/console", - major, - (rtems_device_minor_number) 0 - ); +static int mmconsole_set_attributes(int minor, const struct termios *t) +{ + int baud; - if (status != RTEMS_SUCCESSFUL) - rtems_fatal_error_occurred(status); + switch (t->c_cflag & CBAUD) { + case B0: + baud = 0; + break; + case B50: + baud = 50; + break; + case B75: + baud = 75; + break; + case B110: + baud = 110; + break; + case B134: + baud = 134; + break; + case B150: + baud = 150; + break; + case B200: + baud = 200; + break; + case B300: + baud = 300; + break; + case B600: + baud = 600; + break; + case B1200: + baud = 1200; + break; + case B1800: + baud = 1800; + break; + case B2400: + baud = 2400; + break; + case B4800: + baud = 4800; + break; + case B9600: + baud = 9600; + break; + case B19200: + baud = 19200; + break; + case B38400: + baud = 38400; + break; + case B57600: + baud = 57600; + break; + case B115200: + baud = 115200; + break; + case B230400: + baud = 230400; + break; + case B460800: + baud = 460800; + break; + default: + baud = -1; + break; + } - return RTEMS_SUCCESSFUL; -} + if (baud > 0) + MM_WRITE(MM_UART_DIV, CPU_FREQUENCY/baud/16); -/* is_character_ready - * - * This routine returns TRUE if a character is available. - * - * Input parameters: NONE - * - * Output parameters: NONE - * - * Return values: - */ + return 0; +} -bool is_character_ready( - char *ch -) +static ssize_t mmconsole_write(int minor, const char *buf, size_t n) { - return BSP_uart_is_character_ready(ch); -} + rtems_interrupt_level level; -/* inbyte - * - * This routine reads a character from the SOURCE. - * - * Input parameters: NONE - * - * Output parameters: NONE - * - * Return values: - * character read from SOURCE - */ + rtems_interrupt_disable(level); + BSP_uart_txbusy = true; + MM_WRITE(MM_UART_RXTX, *buf); + rtems_interrupt_enable(level); + return 0; +} -int inbyte( void ) +static rtems_isr mmconsole_txdone(rtems_vector_number n) { - /* - * If polling, wait until a character is available. - */ + BSP_uart_txbusy = false; + lm32_interrupt_ack(1 << MM_IRQ_UARTTX); + rtems_termios_dequeue_characters(tty, 1); +} - return BSP_uart_polled_read(); +static rtems_isr mmconsole_rxdone(rtems_vector_number n) +{ + char c; + c = MM_READ(MM_UART_RXTX); + lm32_interrupt_ack(1 << MM_IRQ_UARTRX); + rtems_termios_enqueue_raw_characters(tty, &c, 1); } -/* outbyte - * - * This routine transmits a character out the SOURCE. It may support - * XON/XOFF flow control. - * - * Input parameters: - * ch - character to be transmitted - * - * Output parameters: NONE - */ +static const rtems_termios_callbacks mmconsole_callbacks = { + .firstOpen = mmconsole_first_open, + .lastClose = mmconsole_last_close, + .pollRead = NULL, + .write = mmconsole_write, + .setAttributes = mmconsole_set_attributes, + .stopRemoteTx = NULL, + .startRemoteTx = NULL, + .outputUsesInterrupts = TERMIOS_IRQ_DRIVEN +}; -void outbyte( - char ch +rtems_device_driver console_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg ) { - /* - * If polling, wait for the transmitter to be ready. - * Check for flow control requests and process. - * Then output the character. - */ + rtems_status_code status; + rtems_isr_entry dummy; - BSP_uart_polled_write(ch); -} + rtems_termios_initialize(); -/* - * Open entry point - */ + status = rtems_io_register_name("/dev/console", major, 0); + if (status != RTEMS_SUCCESSFUL) + rtems_fatal_error_occurred(status); + + rtems_interrupt_catch(mmconsole_txdone, MM_IRQ_UARTTX, &dummy); + rtems_interrupt_catch(mmconsole_rxdone, MM_IRQ_UARTRX, &dummy); + bsp_interrupt_vector_enable(MM_IRQ_UARTTX); + bsp_interrupt_vector_enable(MM_IRQ_UARTRX); + + return RTEMS_SUCCESSFUL; +} rtems_device_driver console_open( rtems_device_major_number major, rtems_device_minor_number minor, - void * arg + void *arg ) { - return RTEMS_SUCCESSFUL; + return rtems_termios_open(major, minor, arg, &mmconsole_callbacks); } -/* - * Close entry point - */ - rtems_device_driver console_close( rtems_device_major_number major, rtems_device_minor_number minor, - void * arg + void *arg ) { - return RTEMS_SUCCESSFUL; + return rtems_termios_close(arg); } -/* - * read bytes from the serial port. We only have stdin. - */ - rtems_device_driver console_read( rtems_device_major_number major, rtems_device_minor_number minor, - void * arg + void *arg ) { - rtems_libio_rw_args_t *rw_args; - char *buffer; - int maximum; - int count = 0; - - rw_args = (rtems_libio_rw_args_t *) arg; - - buffer = rw_args->buffer; - maximum = rw_args->count; - - for (count = 0; count < maximum; count++) { - buffer[ count ] = inbyte(); - if (buffer[ count ] == '\n' || buffer[ count ] == '\r') { - buffer[ count++ ] = '\n'; - break; - } - } - - rw_args->bytes_moved = count; - return (count >= 0) ? RTEMS_SUCCESSFUL : RTEMS_UNSATISFIED; + return rtems_termios_read(arg); } -/* - * write bytes to the serial port. Stdout and stderr are the same. - */ - rtems_device_driver console_write( rtems_device_major_number major, rtems_device_minor_number minor, - void * arg + void *arg ) { - int count; - int maximum; - rtems_libio_rw_args_t *rw_args; - char *buffer; - - rw_args = (rtems_libio_rw_args_t *) arg; - - buffer = rw_args->buffer; - maximum = rw_args->count; - - for (count = 0; count < maximum; count++) { - if ( buffer[ count ] == '\n') { - outbyte('\r'); - } - outbyte( buffer[ count ] ); - } - - rw_args->bytes_moved = maximum; - return 0; + return rtems_termios_write(arg); } -/* - * IO Control entry point - */ - rtems_device_driver console_control( rtems_device_major_number major, rtems_device_minor_number minor, - void * arg + void *arg ) { - return RTEMS_SUCCESSFUL; + return rtems_termios_ioctl(arg); } - -BSP_output_char_function_type BSP_output_char = BSP_uart_polled_write; -BSP_polling_getchar_function_type BSP_poll_char = BSP_uart_polled_read; diff --git a/c/src/lib/libbsp/lm32/shared/milkymist_console/uart.c b/c/src/lib/libbsp/lm32/shared/milkymist_console/uart.c index 229ee40985..f32a1615fd 100644 --- a/c/src/lib/libbsp/lm32/shared/milkymist_console/uart.c +++ b/c/src/lib/libbsp/lm32/shared/milkymist_console/uart.c @@ -1,5 +1,5 @@ /* - * Uart driver for Lattice Mico32 (lm32) UART + * Driver for Milkymist UART * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at @@ -7,63 +7,60 @@ * * $Id$ * + * COPYRIGHT (c) 2010 Sebastien Bourdeauducq * COPYRIGHT (c) Yann Sionneau <yann.sionneau@telecom-sudparis.eu> (GSoC 2010) * Telecom SudParis */ +#include <rtems.h> +#include <rtems/libio.h> #include "../include/system_conf.h" #include "uart.h" -#include <rtems/libio.h> -static inline int uartread(unsigned int reg) -{ - return *((int*)(reg)); -} - -static inline void uartwrite(unsigned int reg, int value) -{ - *((int*)(reg)) = value; -} +bool BSP_uart_txbusy; void BSP_uart_init(int baud) { - - /* Set baud rate */ - uartwrite(MM_UART_DIV, CPU_FREQUENCY/baud/16); + MM_WRITE(MM_UART_DIV, CPU_FREQUENCY/baud/16); } void BSP_uart_polled_write(char ch) { int ip; - /* Wait until THR is empty. */ - uartwrite(MM_UART_RXTX, ch); + rtems_interrupt_level level; + + rtems_interrupt_disable(level); + if (BSP_uart_txbusy) { + /* wait for the end of the transmission by the IRQ-based driver */ + do { + lm32_read_interrupts(ip); + } while (!(ip & (1 << MM_IRQ_UARTTX))); + lm32_interrupt_ack(1 << MM_IRQ_UARTTX); + } + MM_WRITE(MM_UART_RXTX, ch); do { lm32_read_interrupts(ip); - } while (! (ip & MM_IRQ_UARTTX) ); - lm32_interrupt_ack(MM_IRQ_UARTTX); + } while (!(ip & (1 << MM_IRQ_UARTTX))); + /* if TX was busy, do not ack the IRQ + * so that the IRQ-based driver ISR is run */ + if (!BSP_uart_txbusy) + lm32_interrupt_ack(1 << MM_IRQ_UARTTX); + rtems_interrupt_enable(level); } -char BSP_uart_polled_read( void ) +int BSP_uart_polled_read(void) { int ip; - /* Wait until there is a byte in RBR */ + char r; + rtems_interrupt_level level; + + rtems_interrupt_disable(level); do { lm32_read_interrupts(ip); - } while(! (ip & MM_IRQ_UARTRX) ); - lm32_interrupt_ack(MM_IRQ_UARTRX); - return (char) uartread(MM_UART_RXTX); -} + } while (!(ip & (1 << MM_IRQ_UARTRX))); + lm32_interrupt_ack(1 << MM_IRQ_UARTRX); + r = MM_READ(MM_UART_RXTX); + rtems_interrupt_enable(level); -char BSP_uart_is_character_ready(char *ch) -{ - int ip; - lm32_read_interrupts(ip); - if (ip & MM_IRQ_UARTRX) - { - *ch = (char) uartread(MM_UART_RXTX); - lm32_interrupt_ack(MM_IRQ_UARTRX); - return true; - } - *ch = '0'; - return false; + return r; } diff --git a/c/src/lib/libbsp/lm32/shared/milkymist_console/uart.h b/c/src/lib/libbsp/lm32/shared/milkymist_console/uart.h index 1aded4231d..806f491bba 100644 --- a/c/src/lib/libbsp/lm32/shared/milkymist_console/uart.h +++ b/c/src/lib/libbsp/lm32/shared/milkymist_console/uart.h @@ -14,13 +14,10 @@ #ifndef _BSPUART_H #define _BSPUART_H -void BSP_uart_init(int baud); - -#define MM_UART_RXTX (0xe0000000) +extern bool BSP_uart_txbusy; -#define MM_UART_DIV (0xe0000004) - -#define MM_IRQ_UARTTX (0x00000010) /* 4 */ -#define MM_IRQ_UARTRX (0x00000008) /* 3 */ +void BSP_uart_init(int baud); +void BSP_uart_polled_write(char ch); +int BSP_uart_polled_read(void); #endif /* _BSPUART_H */ diff --git a/c/src/lib/libbsp/lm32/shared/milkymist_dmx/dmx.c b/c/src/lib/libbsp/lm32/shared/milkymist_dmx/dmx.c new file mode 100644 index 0000000000..a51d17da1c --- /dev/null +++ b/c/src/lib/libbsp/lm32/shared/milkymist_dmx/dmx.c @@ -0,0 +1,130 @@ +/* dmx.c + * + * Milkymist DMX512 driver for RTEMS + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + * + * COPYRIGHT (c) 2010, 2011 Sebastien Bourdeauducq + */ + +#define RTEMS_STATUS_CHECKS_USE_PRINTK + +#include <stdlib.h> +#include <sys/types.h> +#include <rtems.h> +#include <rtems/status-checks.h> +#include <bsp.h> +#include <rtems/libio.h> +#include "../include/system_conf.h" +#include "milkymist_dmx.h" + +#define IN_DEVICE_NAME "/dev/dmx_in" +#define OUT_DEVICE_NAME "/dev/dmx_out" + +rtems_device_driver dmx_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + rtems_status_code sc; + + sc = rtems_io_register_name(IN_DEVICE_NAME, major, 0); + RTEMS_CHECK_SC(sc, "create DMX input device"); + + sc = rtems_io_register_name(OUT_DEVICE_NAME, major, 1); + RTEMS_CHECK_SC(sc, "create DMX output device"); + + return RTEMS_SUCCESSFUL; +} + +rtems_device_driver dmx_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; + int len; + unsigned int i; + unsigned char *values = (unsigned char *)rw_args->buffer; + + len = 512 - rw_args->offset; + if (len < 0) { + rw_args->bytes_moved = 0; + return RTEMS_SUCCESSFUL; + } + if (len > rw_args->count) + len = rw_args->count; + + if (minor == 0) { + for (i=0;i<len;i++) + values[i] = MM_READ(MM_DMX_RX((unsigned int)rw_args->offset+i)); + } else { + for (i=0;i<len;i++) + values[i] = MM_READ(MM_DMX_TX((unsigned int)rw_args->offset+i)); + } + + rw_args->bytes_moved = len; + + return RTEMS_SUCCESSFUL; +} + +rtems_device_driver dmx_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; + int len; + unsigned int i; + unsigned char *values = (unsigned char *)rw_args->buffer; + + if (minor == 0) { + rw_args->bytes_moved = 0; + return RTEMS_UNSATISFIED; + } + + len = 512 - rw_args->offset; + if (len < 0) { + rw_args->bytes_moved = 0; + return RTEMS_SUCCESSFUL; + } + if (len > rw_args->count) + len = rw_args->count; + + for (i=0;i<len;i++) + MM_WRITE(MM_DMX_TX((unsigned int)rw_args->offset+i), values[i]); + + rw_args->bytes_moved = len; + + return RTEMS_SUCCESSFUL; +} + +rtems_device_driver dmx_control( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + rtems_libio_ioctl_args_t *args = arg; + + switch (args->command) { + case DMX_SET_THRU: + args->ioctl_return = 0; + MM_WRITE(MM_DMX_THRU, (unsigned int)args->buffer); + return RTEMS_SUCCESSFUL; + case DMX_GET_THRU: + args->ioctl_return = 0; + *((unsigned int *)args->buffer) = MM_READ(MM_DMX_THRU); + return RTEMS_SUCCESSFUL; + default: + args->ioctl_return = -1; + return RTEMS_UNSATISFIED; + } +} diff --git a/c/src/lib/libbsp/lm32/shared/milkymist_dmx/milkymist_dmx.h b/c/src/lib/libbsp/lm32/shared/milkymist_dmx/milkymist_dmx.h new file mode 100644 index 0000000000..dd4177d7a4 --- /dev/null +++ b/c/src/lib/libbsp/lm32/shared/milkymist_dmx/milkymist_dmx.h @@ -0,0 +1,55 @@ +/* milkymist_dmx.h + * + * Milkymist DMX512 driver for RTEMS + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + * + * COPYRIGHT (c) 2010 Sebastien Bourdeauducq + */ + +#ifndef __MILKYMIST_DMX_H_ +#define __MILKYMIST_DMX_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define DMX_SET_THRU 0x4400 +#define DMX_GET_THRU 0x4401 + +rtems_device_driver dmx_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +); + +rtems_device_driver dmx_read( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +); + +rtems_device_driver dmx_write( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +); + +rtems_device_driver dmx_control( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +); + +#define DMX_DRIVER_TABLE_ENTRY {dmx_initialize, \ +NULL, NULL, dmx_read, dmx_write, dmx_control} + +#ifdef __cplusplus +} +#endif + +#endif /* __MILKYMIST_DMX_H_ */ diff --git a/c/src/lib/libbsp/lm32/shared/milkymist_flash/flash.c b/c/src/lib/libbsp/lm32/shared/milkymist_flash/flash.c new file mode 100644 index 0000000000..2efc08c458 --- /dev/null +++ b/c/src/lib/libbsp/lm32/shared/milkymist_flash/flash.c @@ -0,0 +1,195 @@ +/* flash.c + * + * Milkymist flash driver for RTEMS + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + * + * COPYRIGHT (c) 2010, 2011 Sebastien Bourdeauducq + */ + +#define RTEMS_STATUS_CHECKS_USE_PRINTK + +#include <rtems.h> +#include <stdio.h> +#include <bsp.h> +#include <string.h> +#include <rtems/libio.h> +#include <rtems/status-checks.h> +#include "../include/system_conf.h" +#include "milkymist_flash.h" + +static struct flash_partition partitions[FLASH_PARTITION_COUNT] + = FLASH_PARTITIONS; + +static rtems_id flash_lock; + +rtems_device_driver flash_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + rtems_status_code sc; + int i; + char devname[16]; + + for (i=0;i<FLASH_PARTITION_COUNT;i++) { + sprintf(devname, "/dev/flash%d", i+1); + sc = rtems_io_register_name(devname, major, i); + RTEMS_CHECK_SC(sc, "Create flash device"); + } + + sc = rtems_semaphore_create( + rtems_build_name('F', 'L', 'S', 'H'), + 1, + RTEMS_SIMPLE_BINARY_SEMAPHORE, + 0, + &flash_lock + ); + RTEMS_CHECK_SC(sc, "create semaphore"); + + return RTEMS_SUCCESSFUL; +} + +rtems_device_driver flash_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; + void *startaddr; + int len; + + if (minor >= FLASH_PARTITION_COUNT) + return RTEMS_UNSATISFIED; + + startaddr = (void *)(partitions[minor].start_address + + (unsigned int)rw_args->offset); + len = partitions[minor].length - rw_args->offset; + if (len > rw_args->count) + len = rw_args->count; + if (len <= 0) { + rw_args->bytes_moved = 0; + return RTEMS_SUCCESSFUL; + } + + rtems_semaphore_obtain(flash_lock, RTEMS_WAIT, RTEMS_NO_TIMEOUT); + memcpy(rw_args->buffer, startaddr, len); + rtems_semaphore_release(flash_lock); + + rw_args->bytes_moved = len; + return RTEMS_SUCCESSFUL; +} + +rtems_device_driver flash_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; + volatile unsigned short *startaddr; + unsigned short *srcdata; + int len; + int this_time; + int remaining; + int i; + + if (minor >= FLASH_PARTITION_COUNT) + return RTEMS_UNSATISFIED; + + startaddr = (unsigned short *)(partitions[minor].start_address + + (unsigned int)rw_args->offset); + len = partitions[minor].length - rw_args->offset; + if (len > rw_args->count) + len = rw_args->count; + if (len <= 2) { + rw_args->bytes_moved = 0; + return RTEMS_SUCCESSFUL; + } + len /= 2; + srcdata = (unsigned short *)rw_args->buffer; + remaining = len; + + rtems_semaphore_obtain(flash_lock, RTEMS_WAIT, RTEMS_NO_TIMEOUT); + while (remaining > 0) { + this_time = remaining; + if (this_time > 256) + this_time = 256; + /* Issue "Buffered Programming Setup" command + * and wait for buffer available. + */ + do { + *startaddr = 0x00e8; + } while (!(*startaddr & 0x0080)); + /* Load word count */ + *startaddr = this_time-1; + /* Fill buffer */ + for(i=0;i<this_time;i++) + startaddr[i] = srcdata[i]; + /* Issue "Buffer Programming Confirm" command */ + *startaddr = 0x00d0; + while (!(*startaddr & 0x0080)); /* read status register, wait for ready */ + *startaddr = 0x0050; /* clear status register */ + /* update state */ + startaddr += this_time; + srcdata += this_time; + remaining -= this_time; + } + *startaddr = 0x00ff; /* back to read array mode */ + rtems_semaphore_release(flash_lock); + + rw_args->bytes_moved = 2*len; + return RTEMS_SUCCESSFUL; +} + +rtems_device_driver flash_control( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + rtems_libio_ioctl_args_t *args = arg; + unsigned int eraseaddr_i; + volatile unsigned short *eraseaddr; + + if (minor >= FLASH_PARTITION_COUNT) { + args->ioctl_return = -1; + return RTEMS_UNSATISFIED; + } + + switch (args->command) { + case FLASH_GET_SIZE: + *((unsigned int *)args->buffer) = partitions[minor].length; + break; + case FLASH_GET_BLOCKSIZE: + *((unsigned int *)args->buffer) = 128*1024; + break; + case FLASH_ERASE_BLOCK: + eraseaddr_i = (unsigned int)args->buffer; + if (eraseaddr_i >= partitions[minor].length) { + args->ioctl_return = -1; + return RTEMS_UNSATISFIED; + } + eraseaddr_i = eraseaddr_i + partitions[minor].start_address; + eraseaddr = (unsigned short *)eraseaddr_i; + rtems_semaphore_obtain(flash_lock, RTEMS_WAIT, RTEMS_NO_TIMEOUT); + *eraseaddr = 0x0020; /* erase */ + *eraseaddr = 0x00d0; + while(!(*eraseaddr & 0x0080)); /* read status register, wait for ready */ + *eraseaddr = 0x0050; /* clear status register */ + *eraseaddr = 0x00ff; /* back to read array mode */ + rtems_semaphore_release(flash_lock); + break; + default: + args->ioctl_return = -1; + return RTEMS_UNSATISFIED; + } + args->ioctl_return = 0; + return RTEMS_SUCCESSFUL; +} diff --git a/c/src/lib/libbsp/lm32/shared/milkymist_flash/milkymist_flash.h b/c/src/lib/libbsp/lm32/shared/milkymist_flash/milkymist_flash.h new file mode 100644 index 0000000000..f8d5532f84 --- /dev/null +++ b/c/src/lib/libbsp/lm32/shared/milkymist_flash/milkymist_flash.h @@ -0,0 +1,53 @@ +/* milkymist_flash.h + * + * Copyright (C) 2010 Sebastien Bourdeauducq + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + * + */ + +#ifndef __MILKYMIST_FLASH_H_ +#define __MILKYMIST_FLASH_H_ + +/* Ioctls */ +#define FLASH_GET_SIZE 0x4600 +#define FLASH_GET_BLOCKSIZE 0x4601 +#define FLASH_ERASE_BLOCK 0x4602 + +struct flash_partition { + unsigned int start_address; + unsigned int length; +}; + +rtems_device_driver flash_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +); + +rtems_device_driver flash_read( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +); + +rtems_device_driver flash_write( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +); + +rtems_device_driver flash_control( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +); + +#define FLASH_DRIVER_TABLE_ENTRY {flash_initialize, \ +NULL, NULL, flash_read, flash_write, flash_control} + +#endif /* __MILKYMIST_FLASH_H_ */ diff --git a/c/src/lib/libbsp/lm32/shared/milkymist_framebuffer/framebuffer.c b/c/src/lib/libbsp/lm32/shared/milkymist_framebuffer/framebuffer.c index 2fbb9c0eca..b1d0612e51 100644 --- a/c/src/lib/libbsp/lm32/shared/milkymist_framebuffer/framebuffer.c +++ b/c/src/lib/libbsp/lm32/shared/milkymist_framebuffer/framebuffer.c @@ -11,13 +11,13 @@ * * COPYRIGHT (c) Yann Sionneau <yann.sionneau@telecom-sudparis.eu> (GSoC 2010) * Telecom SudParis + * Copyright (c) 2011 Sebastien Bourdeauducq */ #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <sys/types.h> -#include <pthread.h> #include <rtems.h> #include <bsp.h> #include "../include/system_conf.h" @@ -26,45 +26,30 @@ #define FRAMEBUFFER_DEVICE_NAME "/dev/fb" -pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +static unsigned short int framebufferA[1024*768] + __attribute__((aligned(32))); +static unsigned short int framebufferB[1024*768] + __attribute__((aligned(32))); +static unsigned short int framebufferC[1024*768] + __attribute__((aligned(32))); -static unsigned short int framebufferA[640*480] __attribute__((aligned(32))); -static unsigned short int framebufferB[640*480] __attribute__((aligned(32))); -static unsigned short int framebufferC[640*480] __attribute__((aligned(32))); +static unsigned short int *frontbuffer; +static unsigned short int *backbuffer; +static unsigned short int *lastbuffer; -static unsigned short int *frontbuffer = framebufferA; -static unsigned short int *backbuffer = framebufferB; -static unsigned short int *lastbuffer = framebufferC; - -static inline void fb_write(unsigned int reg, int value) -{ - *((int*)reg) = value; -} - -static inline int fb_read(unsigned int reg) -{ - return *((int*)(reg)); -} - -/* screen information for the VGA driver */ -static struct fb_var_screeninfo fb_var = -{ +static struct fb_var_screeninfo fb_var = { .xres = 640, .yres = 480, .bits_per_pixel = 16 }; -static struct fb_fix_screeninfo fb_fix = -{ -// this is initialized at start-up - .smem_len = 640 * 480 * 2, /* buffer size */ -// 2 bytes per pixels - .type = FB_TYPE_VGA_PLANES, /* type of display */ - .visual = FB_VISUAL_TRUECOLOR, /* color scheme used */ - .line_length = 80 /* chars per line */ +static struct fb_fix_screeninfo fb_fix = { + .smem_len = 1024 * 768 * 2, + .type = FB_TYPE_VGA_PLANES, + .visual = FB_VISUAL_TRUECOLOR, + .line_length = 80 }; - static int get_fix_screen_info( struct fb_fix_screeninfo *info ) { *info = fb_fix; @@ -77,168 +62,191 @@ static int get_var_screen_info( struct fb_var_screeninfo *info ) return 0; } +static void init_buffers(void) +{ + frontbuffer = framebufferA; + backbuffer = framebufferB; + lastbuffer = framebufferC; +} + +static void swap_buffers(void) +{ + unsigned short int *p; + + /* Make sure last buffer swap has been executed */ + while (MM_READ(MM_VGA_BASEADDRESS_ACT) != MM_READ(MM_VGA_BASEADDRESS)); + + p = frontbuffer; + frontbuffer = backbuffer; + backbuffer = lastbuffer; + lastbuffer = p; + + fb_fix.smem_start = (volatile char *)backbuffer; + MM_WRITE(MM_VGA_BASEADDRESS, (unsigned int)frontbuffer); +} + +static void set_video_mode(int mode) +{ + int hres, vres; + + MM_WRITE(MM_VGA_RESET, VGA_RESET); + hres = vres = 0; + switch(mode) { + case 0: // 640x480, pixel clock: 25MHz + hres = 640; + vres = 480; + MM_WRITE(MM_VGA_HSYNC_START, 656); + MM_WRITE(MM_VGA_HSYNC_END, 752); + MM_WRITE(MM_VGA_HSCAN, 799); + MM_WRITE(MM_VGA_VSYNC_START, 491); + MM_WRITE(MM_VGA_VSYNC_END, 493); + MM_WRITE(MM_VGA_VSCAN, 523); + MM_WRITE(MM_VGA_CLKSEL, 0); + break; + case 1: // 800x600, pixel clock: 50MHz + hres = 800; + vres = 600; + MM_WRITE(MM_VGA_HSYNC_START, 848); + MM_WRITE(MM_VGA_HSYNC_END, 976); + MM_WRITE(MM_VGA_HSCAN, 1040); + MM_WRITE(MM_VGA_VSYNC_START, 637); + MM_WRITE(MM_VGA_VSYNC_END, 643); + MM_WRITE(MM_VGA_VSCAN, 666); + MM_WRITE(MM_VGA_CLKSEL, 1); + break; + case 2: // 1024x768, pixel clock: 65MHz + hres = 1024; + vres = 768; + MM_WRITE(MM_VGA_HSYNC_START, 1048); + MM_WRITE(MM_VGA_HSYNC_END, 1184); + MM_WRITE(MM_VGA_HSCAN, 1344); + MM_WRITE(MM_VGA_VSYNC_START, 771); + MM_WRITE(MM_VGA_VSYNC_END, 777); + MM_WRITE(MM_VGA_VSCAN, 806); + MM_WRITE(MM_VGA_CLKSEL, 2); + break; + } + if((hres != 0) && (vres != 0)) { + MM_WRITE(MM_VGA_HRES, hres); + MM_WRITE(MM_VGA_VRES, vres); + fb_var.xres = hres; + fb_var.yres = vres; + memset(framebufferA, 0, hres*vres*2); + memset(framebufferB, 0, hres*vres*2); + memset(framebufferC, 0, hres*vres*2); + MM_WRITE(MM_VGA_BURST_COUNT, hres*vres/16); + MM_WRITE(MM_VGA_RESET, 0); + } /* otherwise, leave the VGA controller in reset */ +} rtems_device_driver frame_buffer_initialize( -rtems_device_major_number major, -rtems_device_minor_number minor, -void *arg) + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) { rtems_status_code status; - printk( "frame buffer driver initializing..\n" ); - + init_buffers(); fb_fix.smem_start = (volatile char *)frontbuffer; + MM_WRITE(MM_VGA_BASEADDRESS, (unsigned int)frontbuffer); - fb_write(MM_VGA_BASEADDRESS, (unsigned int)frontbuffer); - fb_write(MM_VGA_RESET, (unsigned int)0); - - /* - * Register the device - */ status = rtems_io_register_name(FRAMEBUFFER_DEVICE_NAME, major, 0); - if (status != RTEMS_SUCCESSFUL) - { + if (status != RTEMS_SUCCESSFUL) { printk("Error registering frame buffer device!\n"); rtems_fatal_error_occurred( status ); } - printk("VGA: initialized at resolution %dx%d\n", fb_var.xres, fb_var.yres); - printk("VGA: framebuffers at 0x%08x 0x%08x 0x%08x\n", - (unsigned int)frontbuffer, (unsigned int)backbuffer, - (unsigned int)lastbuffer); - - /* - * graphics hardware initialization goes here for non-console - * devices - */ return RTEMS_SUCCESSFUL; } rtems_device_driver frame_buffer_close( - rtems_device_major_number major, - rtems_device_minor_number minor, + rtems_device_major_number major, + rtems_device_minor_number minor, void *arg ) { - if (pthread_mutex_unlock(&mutex) == 0){ - /* restore previous state. for VGA this means return to text mode. - * leave out if graphics hardware has been initialized in - * frame_buffer_initialize() */ - fb_write(MM_VGA_RESET, MM_VGA_RESET_MODE); - return RTEMS_SUCCESSFUL; - } - return RTEMS_UNSATISFIED; + return RTEMS_SUCCESSFUL; } rtems_device_driver frame_buffer_open( - rtems_device_major_number major, - rtems_device_minor_number minor, + rtems_device_major_number major, + rtems_device_minor_number minor, void *arg ) { - if (pthread_mutex_trylock(&mutex) == 0){ - fb_write(MM_VGA_RESET, (unsigned int)0); - return RTEMS_SUCCESSFUL; - } - return RTEMS_UNSATISFIED; -} - -static void vga_swap_buffers(void) -{ - unsigned short int *p; - - /* - * Make sure last buffer swap has been executed. - * Beware, DMA address registers of vgafb are incomplete - * (only LSBs are present) so don't compare them directly - * with CPU pointers. - */ - while( fb_read(MM_VGA_BASEADDRESS_ACT) != fb_read(MM_VGA_BASEADDRESS) ); - - p = frontbuffer; - frontbuffer = backbuffer; - backbuffer = lastbuffer; - lastbuffer = p; - - fb_fix.smem_start = (volatile char *)backbuffer; - - fb_write(MM_VGA_BASEADDRESS, (unsigned int)frontbuffer); + return RTEMS_SUCCESSFUL; } rtems_device_driver frame_buffer_read( - rtems_device_major_number major, - rtems_device_minor_number minor, - void *arg + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg ) { rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *)arg; - rw_args->bytes_moved = ((rw_args->offset + rw_args->count) > fb_fix.smem_len ) ? (fb_fix.smem_len - rw_args->offset) : rw_args->count; - memcpy(rw_args->buffer, (const void *) (fb_fix.smem_start + rw_args->offset), rw_args->bytes_moved); + rw_args->bytes_moved = ((rw_args->offset + rw_args->count) > fb_fix.smem_len) + ? (fb_fix.smem_len - rw_args->offset) : rw_args->count; + memcpy(rw_args->buffer, (const void *)(fb_fix.smem_start + rw_args->offset), + rw_args->bytes_moved); return RTEMS_SUCCESSFUL; } rtems_device_driver frame_buffer_write( - rtems_device_major_number major, - rtems_device_minor_number minor, - void *arg + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg ) { rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *)arg; - rw_args->bytes_moved = ((rw_args->offset + rw_args->count) > fb_fix.smem_len ) ? (fb_fix.smem_len - rw_args->offset) : rw_args->count; - memcpy( (void *) (fb_fix.smem_start + rw_args->offset), rw_args->buffer, rw_args->bytes_moved); + rw_args->bytes_moved = ((rw_args->offset + rw_args->count) > fb_fix.smem_len) + ? (fb_fix.smem_len - rw_args->offset) : rw_args->count; + memcpy((void *)(fb_fix.smem_start + rw_args->offset), rw_args->buffer, + rw_args->bytes_moved); return RTEMS_SUCCESSFUL; } rtems_device_driver frame_buffer_control( - rtems_device_major_number major, - rtems_device_minor_number minor, - void *arg + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg ) { rtems_libio_ioctl_args_t *args = arg; - switch( args->command ) { + switch (args->command) { case FBIOGET_FSCREENINFO: - args->ioctl_return = get_fix_screen_info( ( struct fb_fix_screeninfo * ) args->buffer ); - break; + args->ioctl_return = + get_fix_screen_info((struct fb_fix_screeninfo *)args->buffer); + return RTEMS_SUCCESSFUL; case FBIOGET_VSCREENINFO: - args->ioctl_return = get_var_screen_info( ( struct fb_var_screeninfo * ) args->buffer ); - break; - case FBIOPUT_VSCREENINFO: - /* not implemented yet */ - args->ioctl_return = -1; - return RTEMS_UNSATISFIED; - case FBIOGETCMAP: - /* not implemented yet */ - args->ioctl_return = -1; - return RTEMS_UNSATISFIED; - break; - case FBIOPUTCMAP: - /* not implemented yet */ - args->ioctl_return = -1; - return RTEMS_UNSATISFIED; - break; + args->ioctl_return = + get_var_screen_info((struct fb_var_screeninfo *)args->buffer); + return RTEMS_SUCCESSFUL; case FBIOSWAPBUFFERS: - vga_swap_buffers(); + swap_buffers(); args->ioctl_return = 0; - break; + return RTEMS_SUCCESSFUL; case FBIOSETBUFFERMODE: args->ioctl_return = 0; - switch ( (unsigned int)args->buffer ) { + switch ((unsigned int)args->buffer) { case FB_SINGLE_BUFFERED: + init_buffers(); fb_fix.smem_start = (volatile char *)frontbuffer; - break; - case FB_TRIPLE_BUFFERED: + MM_WRITE(MM_VGA_BASEADDRESS, (unsigned int)frontbuffer); + return RTEMS_SUCCESSFUL; + case FB_TRIPLE_BUFFERED: fb_fix.smem_start = (volatile char *)backbuffer; - break; + return RTEMS_SUCCESSFUL; default: - printk("[framebuffer] : error no such buffer mode\n"); + return RTEMS_UNSATISFIED; } - break; + case FBIOSETVIDEOMODE: + set_video_mode((int)args->buffer); + return RTEMS_SUCCESSFUL; default: - args->ioctl_return = 0; - break; + args->ioctl_return = -1; + return RTEMS_UNSATISFIED; } - return RTEMS_SUCCESSFUL; } diff --git a/c/src/lib/libbsp/lm32/shared/milkymist_gpio/gpio.c b/c/src/lib/libbsp/lm32/shared/milkymist_gpio/gpio.c index 430d36514c..5112897e4a 100644 --- a/c/src/lib/libbsp/lm32/shared/milkymist_gpio/gpio.c +++ b/c/src/lib/libbsp/lm32/shared/milkymist_gpio/gpio.c @@ -1,6 +1,6 @@ /* gpio.c * - * This file is the gpio driver for the Milkymist One board + * GPIO driver for the Milkymist One board * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at @@ -8,184 +8,114 @@ * * $Id$ * + * COPYRIGHT (c) 2010, 2011 Sebastien Bourdeauducq * COPYRIGHT (c) Yann Sionneau <yann.sionneau@telecom-sudparis.eu> (GSoC 2010) * Telecom SudParis */ +#define RTEMS_STATUS_CHECKS_USE_PRINTK + #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <sys/types.h> -#include <pthread.h> #include <rtems.h> +#include <rtems/status-checks.h> #include <bsp.h> -#include "../include/system_conf.h" #include <rtems/libio.h> +#include "../include/system_conf.h" +#include "milkymist_gpio.h" -#define GPIO_DRIVER_TABLE_ENTRY { gpio_initialize, \ -gpio_open, gpio_close, gpio_read, gpio_write, gpio_control} - -#define LED1_DEVICE_NAME "/dev/led1" -#define LED2_DEVICE_NAME "/dev/led2" -#define BTN1_DEVICE_NAME "/dev/btn1" -#define BTN2_DEVICE_NAME "/dev/btn2" -#define BTN3_DEVICE_NAME "/dev/btn3" +struct milkymist_gpio { + char *name; + unsigned int mask; + bool readonly; +}; -static struct milkymist_gpio { - rtems_device_minor_number minor; - unsigned int *address; - unsigned int offset; - uint8_t readonly; - pthread_mutex_t mutex; -} gpio[5]; +static const struct milkymist_gpio gpio[] = { + { + .name = "/dev/led1", + .mask = GPIO_LED1, + .readonly = false + }, + { + .name = "/dev/led2", + .mask = GPIO_LED2, + .readonly = false + }, +}; rtems_device_driver gpio_initialize( -rtems_device_major_number major, -rtems_device_minor_number minor, -void *arg) + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) { - rtems_status_code status; + rtems_status_code sc; + int i; - printk( "gpio driver initializing..\n" ); - - status = rtems_io_register_name(LED1_DEVICE_NAME, major, 0); - if (status != RTEMS_SUCCESSFUL) - { - printk("Error registering gpio device led1\n"); - rtems_fatal_error_occurred( status ); - } - gpio[0].minor = 0; - gpio[0].readonly = 0; - gpio[0].offset = 0x00000001; - gpio[0].address = (unsigned int *)0xe0001004; - gpio[0].mutex = PTHREAD_MUTEX_INITIALIZER; - - status = rtems_io_register_name(LED2_DEVICE_NAME, major, 1); - if (status != RTEMS_SUCCESSFUL) - { - printk("Error registering gpio device led2\n"); - rtems_fatal_error_occurred( status ); - } - gpio[1].minor = 1; - gpio[1].readonly = 0; - gpio[1].offset = 0x00000002; - gpio[1].address = (unsigned int *)0xe0001004; - gpio[1].mutex = PTHREAD_MUTEX_INITIALIZER; - - status = rtems_io_register_name(BTN1_DEVICE_NAME, major, 2); - if (status != RTEMS_SUCCESSFUL) - { - printk("Error registering gpio device btn1\n"); - rtems_fatal_error_occurred( status ); - } - gpio[2].minor = 2; - gpio[2].readonly = 1; - gpio[2].offset = 0x00000001; - gpio[2].address = (unsigned int *)0xe0001000; - gpio[2].mutex = PTHREAD_MUTEX_INITIALIZER; - status = rtems_io_register_name(BTN2_DEVICE_NAME, major, 3); - if (status != RTEMS_SUCCESSFUL) - { - printk("Error registering gpio device btn2\n"); - rtems_fatal_error_occurred( status ); - } - gpio[3].minor = 3; - gpio[3].readonly = 1; - gpio[3].address = (unsigned int *)0xe0001000; - gpio[3].offset = 0x00000002; - gpio[3].mutex = PTHREAD_MUTEX_INITIALIZER; - - status = rtems_io_register_name(BTN3_DEVICE_NAME, major, 4); - if (status != RTEMS_SUCCESSFUL) - { - printk("Error registering gpio device btn3\n"); - rtems_fatal_error_occurred( status ); + for (i=0;i<sizeof(gpio)/sizeof(struct milkymist_gpio);i++) { + sc = rtems_io_register_name(gpio[i].name, major, i); + RTEMS_CHECK_SC(sc, "create GPIO device"); } - gpio[4].minor = 4; - gpio[4].readonly = 1; - gpio[4].offset = 0x00000004; - gpio[4].address = (unsigned int *)0xe0001000; - gpio[4].mutex = PTHREAD_MUTEX_INITIALIZER; - return RTEMS_SUCCESSFUL; } -rtems_device_driver gpio_close( - rtems_device_major_number major, - rtems_device_minor_number minor, +rtems_device_driver gpio_read( + rtems_device_major_number major, + rtems_device_minor_number minor, void *arg ) { - if (pthread_mutex_unlock(&gpio[minor].mutex) == 0){ - return RTEMS_SUCCESSFUL; - } - return RTEMS_UNSATISFIED; -} + unsigned int data; -rtems_device_driver gpio_open( - rtems_device_major_number major, - rtems_device_minor_number minor, - void *arg -) -{ - if (pthread_mutex_trylock(&gpio[minor].mutex) == 0){ + rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *)arg; + + if (rw_args->offset > 0) { + rw_args->bytes_moved = 0; return RTEMS_SUCCESSFUL; } - return RTEMS_UNSATISFIED; -} - -rtems_device_driver gpio_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 = 1; - - if ( *gpio[minor].address & gpio[minor].offset ) - *(uint8_t *)rw_args->buffer = 1; + + if (gpio[minor].readonly) + data = MM_READ(MM_GPIO_IN); + else + data = MM_READ(MM_GPIO_OUT); + + if (data & gpio[minor].mask) + *(uint8_t *)rw_args->buffer = '1'; else - *(uint8_t *)rw_args->buffer = 0; - + *(uint8_t *)rw_args->buffer = '0'; + return RTEMS_SUCCESSFUL; } rtems_device_driver gpio_write( rtems_device_major_number major, rtems_device_minor_number minor, - void *arg + void *arg ) { rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *)arg; - rw_args->bytes_moved = 1; - if (gpio[minor].readonly) + if (gpio[minor].readonly) { + rw_args->bytes_moved = 0; return RTEMS_UNSATISFIED; + } - if ( *(uint8_t *)rw_args->buffer ) - *gpio[minor].address |= gpio[minor].offset; - else - *gpio[minor].address &= ~gpio[minor].offset; + if (rw_args->offset > 0) { + rw_args->bytes_moved = 0; + return RTEMS_SUCCESSFUL; + } - return RTEMS_SUCCESSFUL; -} + rw_args->bytes_moved = 1; -rtems_device_driver gpio_control( - rtems_device_major_number major, - rtems_device_minor_number minor, - void *arg -) -{ - rtems_libio_ioctl_args_t *args = arg; + if (*(uint8_t *)rw_args->buffer == '1') + MM_WRITE(MM_GPIO_OUT, MM_READ(MM_GPIO_OUT)|gpio[minor].mask); + else + MM_WRITE(MM_GPIO_OUT, MM_READ(MM_GPIO_OUT) & ~gpio[minor].mask); - switch( args->command ) { - default: - args->ioctl_return = 0; - break; - } return RTEMS_SUCCESSFUL; } - diff --git a/c/src/lib/libbsp/lm32/shared/milkymist_gpio/milkymist_gpio.h b/c/src/lib/libbsp/lm32/shared/milkymist_gpio/milkymist_gpio.h new file mode 100644 index 0000000000..f83f79e583 --- /dev/null +++ b/c/src/lib/libbsp/lm32/shared/milkymist_gpio/milkymist_gpio.h @@ -0,0 +1,46 @@ +/* milkymist_gpio.h + * + * Milkymist GPIO driver for RTEMS + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + * + * COPYRIGHT (c) 2010 Sebastien Bourdeauducq + */ + +#ifndef __MILKYMIST_GPIO_H_ +#define __MILKYMIST_GPIO_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +rtems_device_driver gpio_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +); + +rtems_device_driver gpio_read( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +); + +rtems_device_driver gpio_write( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +); + +#define GPIO_DRIVER_TABLE_ENTRY { gpio_initialize, \ +NULL, NULL, gpio_read, gpio_write, NULL} + +#ifdef __cplusplus +} +#endif + +#endif /* __MILKYMIST_GPIO_H_ */ diff --git a/c/src/lib/libbsp/lm32/shared/milkymist_ir/ir.c b/c/src/lib/libbsp/lm32/shared/milkymist_ir/ir.c new file mode 100644 index 0000000000..0a7f215cb8 --- /dev/null +++ b/c/src/lib/libbsp/lm32/shared/milkymist_ir/ir.c @@ -0,0 +1,106 @@ +/* ir.c + * + * Milkymist RC5 IR driver for RTEMS + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + * + * COPYRIGHT (c) 2010, 2011 Sebastien Bourdeauducq + */ + +#define RTEMS_STATUS_CHECKS_USE_PRINTK + +#include <stdlib.h> +#include <sys/types.h> +#include <rtems.h> +#include <rtems/status-checks.h> +#include <bsp.h> +#include <bsp/irq-generic.h> +#include <rtems/libio.h> +#include "../include/system_conf.h" +#include "milkymist_ir.h" + +#define DEVICE_NAME "/dev/ir" + +static rtems_id ir_q; + +static rtems_isr interrupt_handler(rtems_vector_number n) +{ + unsigned short int msg; + + lm32_interrupt_ack(1 << MM_IRQ_IR); + msg = MM_READ(MM_IR_RX); + rtems_message_queue_send(ir_q, &msg, 2); +} + +rtems_device_driver ir_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + rtems_status_code sc; + rtems_isr_entry dummy; + + sc = rtems_io_register_name(DEVICE_NAME, major, 0); + RTEMS_CHECK_SC(sc, "create IR input device"); + + sc = rtems_message_queue_create( + rtems_build_name('R', 'C', '5', 'Q'), + 64, + 2, + 0, + &ir_q + ); + RTEMS_CHECK_SC(sc, "create IR queue"); + + rtems_interrupt_catch(interrupt_handler, MM_IRQ_IR, &dummy); + bsp_interrupt_vector_enable(MM_IRQ_IR); + + return RTEMS_SUCCESSFUL; +} + +rtems_device_driver ir_open( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + uint32_t count; + + rtems_message_queue_flush(ir_q, &count); + return RTEMS_SUCCESSFUL; +} + +rtems_device_driver ir_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; + rtems_status_code sc; + + if (rw_args->count < 2) { + rw_args->bytes_moved = 0; + return RTEMS_UNSATISFIED; + } + + sc = rtems_message_queue_receive( + ir_q, + rw_args->buffer, + (size_t *)&rw_args->bytes_moved, + RTEMS_WAIT, + RTEMS_NO_TIMEOUT + ); + + if(sc == RTEMS_SUCCESSFUL) + return RTEMS_SUCCESSFUL; + else { + rw_args->bytes_moved = 0; + return RTEMS_UNSATISFIED; + } +} diff --git a/c/src/lib/libbsp/lm32/shared/milkymist_ir/milkymist_ir.h b/c/src/lib/libbsp/lm32/shared/milkymist_ir/milkymist_ir.h new file mode 100644 index 0000000000..9464ac92b6 --- /dev/null +++ b/c/src/lib/libbsp/lm32/shared/milkymist_ir/milkymist_ir.h @@ -0,0 +1,46 @@ +/* milkymist_ir.h + * + * Milkymist RC5 IR driver for RTEMS + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + * + * COPYRIGHT (c) 2010 Sebastien Bourdeauducq + */ + +#ifndef __MILKYMIST_IR_H_ +#define __MILKYMIST_IR_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +rtems_device_driver ir_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +); + +rtems_device_driver ir_open( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +); + +rtems_device_driver ir_read( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +); + +#define IR_DRIVER_TABLE_ENTRY {ir_initialize, \ +ir_open, NULL, ir_read, NULL, NULL} + +#ifdef __cplusplus +} +#endif + +#endif /* __MILKYMIST_IR_H_ */ diff --git a/c/src/lib/libbsp/lm32/shared/milkymist_memcard/memcard.c b/c/src/lib/libbsp/lm32/shared/milkymist_memcard/memcard.c new file mode 100644 index 0000000000..6ad1268d58 --- /dev/null +++ b/c/src/lib/libbsp/lm32/shared/milkymist_memcard/memcard.c @@ -0,0 +1,370 @@ +/* memcard.c + * + * Milkymist memory card driver for RTEMS + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + * + * COPYRIGHT (c) 2010, 2011 Sebastien Bourdeauducq + */ + +#define RTEMS_STATUS_CHECKS_USE_PRINTK + +#include <rtems.h> +#include <rtems/libio.h> +#include <rtems/diskdevs.h> +#include <rtems/blkdev.h> +#include <rtems/status-checks.h> +#include <errno.h> +#include <bsp.h> +#include "../include/system_conf.h" +#include "milkymist_memcard.h" + +//#define MEMCARD_DEBUG + +#define BLOCK_SIZE 512 + +static void memcard_start_cmd_tx(void) +{ + MM_WRITE(MM_MEMCARD_ENABLE, MEMCARD_ENABLE_CMD_TX); +} + +static void memcard_start_cmd_rx(void) +{ + MM_WRITE(MM_MEMCARD_PENDING, MEMCARD_PENDING_CMD_RX); + MM_WRITE(MM_MEMCARD_START, MEMCARD_START_CMD_RX); + MM_WRITE(MM_MEMCARD_ENABLE, MEMCARD_ENABLE_CMD_RX); +} + +static void memcard_start_cmd_dat_rx(void) +{ + MM_WRITE(MM_MEMCARD_PENDING, MEMCARD_PENDING_CMD_RX|MEMCARD_PENDING_DAT_RX); + MM_WRITE(MM_MEMCARD_START, MEMCARD_START_CMD_RX|MEMCARD_START_DAT_RX); + MM_WRITE(MM_MEMCARD_ENABLE, MEMCARD_ENABLE_CMD_RX|MEMCARD_ENABLE_DAT_RX); +} + +static void memcard_send_command(unsigned char cmd, unsigned int arg) +{ + unsigned char packet[6]; + int a; + int i; + unsigned char data; + unsigned char crc; + + packet[0] = cmd | 0x40; + packet[1] = ((arg >> 24) & 0xff); + packet[2] = ((arg >> 16) & 0xff); + packet[3] = ((arg >> 8) & 0xff); + packet[4] = (arg & 0xff); + + crc = 0; + for(a=0;a<5;a++) { + data = packet[a]; + for(i=0;i<8;i++) { + crc <<= 1; + if((data & 0x80) ^ (crc & 0x80)) + crc ^= 0x09; + data <<= 1; + } + } + crc = (crc<<1) | 1; + + packet[5] = crc; + +#ifdef MEMCARD_DEBUG + printk(">> %02x %02x %02x %02x %02x %02x\n", + packet[0], packet[1], packet[2], packet[3], packet[4], packet[5]); +#endif + + for(i=0;i<6;i++) { + MM_WRITE(MM_MEMCARD_CMD, packet[i]); + while(MM_READ(MM_MEMCARD_PENDING) & MEMCARD_PENDING_CMD_TX); + } +} + +static void memcard_send_dummy(void) +{ + MM_WRITE(MM_MEMCARD_CMD, 0xff); + while(MM_READ(MM_MEMCARD_PENDING) & MEMCARD_PENDING_CMD_TX); +} + +static bool memcard_receive_command(unsigned char *buffer, int len) +{ + int i; + int timeout; + + for(i=0;i<len;i++) { + timeout = 2000000; + while(!(MM_READ(MM_MEMCARD_PENDING) & MEMCARD_PENDING_CMD_RX)) { + timeout--; + if(timeout == 0) { + #ifdef MEMCARD_DEBUG + printk("Command receive timeout\n"); + #endif + return false; + } + } + buffer[i] = MM_READ(MM_MEMCARD_CMD); + MM_WRITE(MM_MEMCARD_PENDING, MEMCARD_PENDING_CMD_RX); + } + + while(!(MM_READ(MM_MEMCARD_PENDING) & MEMCARD_PENDING_CMD_RX)); + + #ifdef MEMCARD_DEBUG + printk("<< "); + for(i=0;i<len;i++) + printk("%02x ", buffer[i]); + printk("\n"); + #endif + + return true; +} + +static bool memcard_receive_command_data(unsigned char *command, + unsigned int *data) +{ + int i, j; + int timeout; + + i = 0; + j = 0; + while(j < 128) { + timeout = 2000000; + while(!(MM_READ(MM_MEMCARD_PENDING) & + (MEMCARD_PENDING_CMD_RX|MEMCARD_PENDING_DAT_RX))) { + timeout--; + if(timeout == 0) { + #ifdef MEMCARD_DEBUG + printk("Command receive timeout\n"); + #endif + return false; + } + } + if(MM_READ(MM_MEMCARD_PENDING) & MEMCARD_PENDING_CMD_RX) { + command[i++] = MM_READ(MM_MEMCARD_CMD); + MM_WRITE(MM_MEMCARD_PENDING, MEMCARD_PENDING_CMD_RX); + if(i == 6) + /* disable command RX */ + MM_WRITE(MM_MEMCARD_ENABLE, MEMCARD_ENABLE_DAT_RX); + } + if(MM_READ(MM_MEMCARD_PENDING) & MEMCARD_PENDING_DAT_RX) { + data[j++] = MM_READ(MM_MEMCARD_DAT); + MM_WRITE(MM_MEMCARD_PENDING, MEMCARD_PENDING_DAT_RX); + } + } + + /* Get CRC (ignored) */ + for(i=0;i<2;i++) { + while(!(MM_READ(MM_MEMCARD_PENDING) & MEMCARD_PENDING_DAT_RX)); + #ifdef MEMCARD_DEBUG + printk("CRC: %08x\n", MM_READ(MM_MEMCARD_DAT)); + #endif + MM_WRITE(MM_MEMCARD_PENDING, MEMCARD_PENDING_DAT_RX); + } + + while(!(MM_READ(MM_MEMCARD_PENDING) & MEMCARD_PENDING_DAT_RX)); + + #ifdef MEMCARD_DEBUG + printk("<< %02x %02x %02x %02x %02x %02x\n", + command[0], command[1], command[2], command[3], command[4], command[5]); + #endif + + //for(i=0;i<128;i++) + // printk("%08x ", data[i]); + //printk("\n"); + + return true; +} + +static unsigned int block_count; + +static int memcard_disk_block_read(rtems_blkdev_request *r) +{ + unsigned char b[6]; + unsigned int i, nblocks; + unsigned int block; + + block = RTEMS_BLKDEV_START_BLOCK(r); + nblocks = r->bufnum; + + for(i=0;i<nblocks;i++) { + /* CMD17 - read block */ + memcard_start_cmd_tx(); + memcard_send_command(17, (block+i)*BLOCK_SIZE); + memcard_start_cmd_dat_rx(); + if(!memcard_receive_command_data(b, (unsigned int *)r->bufs[i].buffer)) + return -RTEMS_IO_ERROR; + } + + r->req_done(r->done_arg, RTEMS_SUCCESSFUL); + + return 0; +} + +static int memcard_disk_block_write(rtems_blkdev_request *r) +{ + return -RTEMS_IO_ERROR; +} + +static rtems_status_code memcard_init(void) +{ + unsigned char b[17]; + unsigned int rca; + unsigned int block_shift; + unsigned int c_size; + unsigned int c_size_mult; + + MM_WRITE(MM_MEMCARD_CLK2XDIV, 250); + + /* CMD0 */ + memcard_start_cmd_tx(); + memcard_send_command(0, 0); + + memcard_send_dummy(); + + /* CMD8 */ + memcard_send_command(8, 0x1aa); + memcard_start_cmd_rx(); + if(!memcard_receive_command(b, 6)) return RTEMS_IO_ERROR; + + /* ACMD41 - initialize */ + while(1) { + memcard_start_cmd_tx(); + memcard_send_command(55, 0); + memcard_start_cmd_rx(); + if(!memcard_receive_command(b, 6)) return RTEMS_IO_ERROR; + memcard_start_cmd_tx(); + memcard_send_command(41, 0x00300000); + memcard_start_cmd_rx(); + if(!memcard_receive_command(b, 6)) return RTEMS_IO_ERROR; + if(b[1] & 0x80) break; + #ifdef MEMCARD_DEBUG + printk("Card is busy, retrying\n"); + #endif + } + + /* CMD2 - get CID */ + memcard_start_cmd_tx(); + memcard_send_command(2, 0); + memcard_start_cmd_rx(); + if(!memcard_receive_command(b, 17)) return RTEMS_IO_ERROR; + + /* CMD3 - get RCA */ + memcard_start_cmd_tx(); + memcard_send_command(3, 0); + memcard_start_cmd_rx(); + if(!memcard_receive_command(b, 6)) return RTEMS_IO_ERROR; + rca = (((unsigned int)b[1]) << 8)|((unsigned int)b[2]); + #ifdef MEMCARD_DEBUG + printk("RCA: %04x\n", rca); + #endif + + /* CMD9 - get CSD */ + memcard_start_cmd_tx(); + memcard_send_command(9, rca << 16); + memcard_start_cmd_rx(); + if(!memcard_receive_command(b, 17)) return RTEMS_IO_ERROR; + + if(((b)[0] >> 6) != 0) + return RTEMS_IO_ERROR; + + block_shift = ((unsigned int)(b)[5] & 0xf); + c_size = ((((unsigned int)(b)[6] & 0x3) << 10) + + (((unsigned int)(b)[7]) << 2) + + ((((unsigned int)(b)[8]) >> 6) & 0x3)); + c_size_mult = ((((b)[9] & 0x3) << 1) + (((b)[10] >> 7) & 0x1)); + block_count = (c_size + 1) * (1U << (c_size_mult + 2)); + + /* convert to 512-byte blocks for the sake of simplicity */ + if(block_shift < 9) + return RTEMS_IO_ERROR; + block_count <<= block_shift - 9; + + /* CMD7 - select card */ + memcard_start_cmd_tx(); + memcard_send_command(7, rca << 16); + memcard_start_cmd_rx(); + if(!memcard_receive_command(b, 6)) return RTEMS_IO_ERROR; + + /* ACMD6 - set bus width */ + memcard_start_cmd_tx(); + memcard_send_command(55, rca << 16); + memcard_start_cmd_rx(); + if(!memcard_receive_command(b, 6)) return RTEMS_IO_ERROR; + memcard_start_cmd_tx(); + memcard_send_command(6, 2); + memcard_start_cmd_rx(); + if(!memcard_receive_command(b, 6)) return RTEMS_IO_ERROR; + + MM_WRITE(MM_MEMCARD_CLK2XDIV, 3); + + return RTEMS_SUCCESSFUL; +} + +static int memcard_disk_ioctl(rtems_disk_device *dd, uint32_t req, void *arg) +{ + if (req == RTEMS_BLKIO_REQUEST) { + rtems_blkdev_request *r = (rtems_blkdev_request *)arg; + switch (r->req) { + case RTEMS_BLKDEV_REQ_READ: + return memcard_disk_block_read(r); + case RTEMS_BLKDEV_REQ_WRITE: + return memcard_disk_block_write(r); + default: + errno = EINVAL; + return -1; + } + } else if (req == RTEMS_BLKIO_CAPABILITIES) { + *(uint32_t *)arg = RTEMS_BLKDEV_CAP_MULTISECTOR_CONT; + return 0; + } else { + errno = EINVAL; + return -1; + } +} + +static rtems_status_code memcard_disk_init( + rtems_device_major_number major, rtems_device_minor_number minor, + void *arg) +{ + rtems_status_code sc; + dev_t dev; + + sc = rtems_disk_io_initialize(); + RTEMS_CHECK_SC(sc, "Initialize RTEMS disk IO"); + + dev = rtems_filesystem_make_dev_t(major, 0); + + sc = memcard_init(); + RTEMS_CHECK_SC(sc, "Initialize memory card"); + + sc = rtems_disk_create_phys(dev, BLOCK_SIZE, block_count, memcard_disk_ioctl, + NULL, "/dev/memcard"); + RTEMS_CHECK_SC(sc, "Create disk device"); + + return RTEMS_SUCCESSFUL; +} + + +static const rtems_driver_address_table memcard_disk_ops = { + .initialization_entry = memcard_disk_init, + .open_entry = rtems_blkdev_generic_open, + .close_entry = rtems_blkdev_generic_close, + .read_entry = rtems_blkdev_generic_read, + .write_entry = rtems_blkdev_generic_write, + .control_entry = rtems_blkdev_generic_ioctl +}; + +rtems_status_code memcard_register(void) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + rtems_device_major_number major = 0; + + sc = rtems_io_register_driver(0, &memcard_disk_ops, &major); + RTEMS_CHECK_SC(sc, "Register disk memory card driver"); + + return RTEMS_SUCCESSFUL; +} diff --git a/c/src/lib/libbsp/lm32/shared/milkymist_memcard/milkymist_memcard.h b/c/src/lib/libbsp/lm32/shared/milkymist_memcard/milkymist_memcard.h new file mode 100644 index 0000000000..252a3ded45 --- /dev/null +++ b/c/src/lib/libbsp/lm32/shared/milkymist_memcard/milkymist_memcard.h @@ -0,0 +1,19 @@ +/* milkymist_memcard.h + * + * Milkymist memory card driver for RTEMS + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + * + * COPYRIGHT (c) 2010 Sebastien Bourdeauducq + */ + +#ifndef __MILKYMIST_MEMCARD_H_ +#define __MILKYMIST_MEMCARD_H_ + +rtems_status_code memcard_register(void); + +#endif /* __MILKYMIST_MEMCARD_H_ */ diff --git a/c/src/lib/libbsp/lm32/shared/milkymist_midi/midi.c b/c/src/lib/libbsp/lm32/shared/milkymist_midi/midi.c new file mode 100644 index 0000000000..e71350bf1f --- /dev/null +++ b/c/src/lib/libbsp/lm32/shared/milkymist_midi/midi.c @@ -0,0 +1,104 @@ +/* midi.c + * + * Milkymist MIDI driver for RTEMS + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + * + * COPYRIGHT (c) 2010, 2011 Sebastien Bourdeauducq + */ + +#define RTEMS_STATUS_CHECKS_USE_PRINTK + +#include <stdlib.h> +#include <sys/types.h> +#include <rtems.h> +#include <rtems/status-checks.h> +#include <bsp.h> +#include <bsp/irq-generic.h> +#include <rtems/libio.h> +#include "../include/system_conf.h" +#include "milkymist_midi.h" + +#define DEVICE_NAME "/dev/midi" + +static rtems_id midi_q; + +static rtems_isr interrupt_handler(rtems_vector_number n) +{ + unsigned char msg; + + lm32_interrupt_ack(1 << MM_IRQ_MIDIRX); + msg = MM_READ(MM_MIDI_RXTX); + rtems_message_queue_send(midi_q, &msg, 1); +} + +rtems_device_driver midi_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + rtems_status_code sc; + rtems_isr_entry dummy; + + sc = rtems_io_register_name(DEVICE_NAME, major, 0); + RTEMS_CHECK_SC(sc, "create MIDI input device"); + + sc = rtems_message_queue_create( + rtems_build_name('M', 'I', 'D', 'I'), + 64, + 1, + 0, + &midi_q + ); + RTEMS_CHECK_SC(sc, "create MIDI queue"); + + rtems_interrupt_catch(interrupt_handler, MM_IRQ_MIDIRX, &dummy); + bsp_interrupt_vector_enable(MM_IRQ_MIDIRX); + + /* Only MIDI THRU mode is supported atm */ + MM_WRITE(MM_MIDI_THRU, 1); + + return RTEMS_SUCCESSFUL; +} + +rtems_device_driver midi_open( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + uint32_t count; + + rtems_message_queue_flush(midi_q, &count); + return RTEMS_SUCCESSFUL; +} + +rtems_device_driver midi_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; + rtems_status_code sc; + + sc = rtems_message_queue_receive( + midi_q, + rw_args->buffer, + (size_t *)&rw_args->bytes_moved, + RTEMS_WAIT, + RTEMS_NO_TIMEOUT + ); + + if(sc == RTEMS_SUCCESSFUL) + return RTEMS_SUCCESSFUL; + else { + rw_args->bytes_moved = 0; + return RTEMS_UNSATISFIED; + } +} diff --git a/c/src/lib/libbsp/lm32/shared/milkymist_midi/milkymist_midi.h b/c/src/lib/libbsp/lm32/shared/milkymist_midi/milkymist_midi.h new file mode 100644 index 0000000000..203a945e6d --- /dev/null +++ b/c/src/lib/libbsp/lm32/shared/milkymist_midi/milkymist_midi.h @@ -0,0 +1,46 @@ +/* milkymist_midi.h + * + * Milkymist MIDI driver for RTEMS + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + * + * COPYRIGHT (c) 2010 Sebastien Bourdeauducq + */ + +#ifndef __MILKYMIST_MIDI_H_ +#define __MILKYMIST_MIDI_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +rtems_device_driver midi_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +); + +rtems_device_driver midi_open( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +); + +rtems_device_driver midi_read( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +); + +#define MIDI_DRIVER_TABLE_ENTRY {midi_initialize, \ +midi_open, NULL, midi_read, NULL, NULL} + +#ifdef __cplusplus +} +#endif + +#endif /* __MILKYMIST_MIDI_H_ */ diff --git a/c/src/lib/libbsp/lm32/shared/milkymist_networking/network.c b/c/src/lib/libbsp/lm32/shared/milkymist_networking/network.c index 81ac56a7a7..5624cd2c50 100644 --- a/c/src/lib/libbsp/lm32/shared/milkymist_networking/network.c +++ b/c/src/lib/libbsp/lm32/shared/milkymist_networking/network.c @@ -1,5 +1,5 @@ /* - * RTEMS driver for Minimac ethernet IP-core of Milkymist SoC + * RTEMS driver for Minimac2 ethernet IP-core of Milkymist SoC * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at @@ -9,121 +9,94 @@ * * COPYRIGHT (c) Yann Sionneau <yann.sionneau@telecom-sudparis.eu> (GSoC 2010) * Telecom SudParis, France + * Copyright (C) 2011 Sebastien Bourdeauducq */ +#define RTEMS_STATUS_CHECKS_USE_PRINTK #include <bsp.h> -#include "../include/system_conf.h" -#include "bspopts.h" +#include <bsp/irq-generic.h> #include <stdio.h> +#include <string.h> #include <rtems/rtems_bsdnet.h> +#include <rtems/status-checks.h> #include <sys/param.h> #include <sys/mbuf.h> #include <sys/socket.h> #include <sys/sockio.h> #include <net/if.h> +#include <net/ethernet.h> #include <netinet/in.h> #include <netinet/if_ether.h> #include <rtems.h> +#include "bspopts.h" +#include "../include/system_conf.h" #include "network.h" -unsigned int mm_ether_crc32(const unsigned char *buffer, unsigned int len); -static char rxbuff0[ETHERNET_FRAME_LENGTH] __attribute__((aligned (4))); -static char rxbuff1[ETHERNET_FRAME_LENGTH] __attribute__((aligned (4))); -static char rxbuff2[ETHERNET_FRAME_LENGTH] __attribute__((aligned (4))); -static char rxbuff3[ETHERNET_FRAME_LENGTH] __attribute__((aligned (4))); - -static char *rxbuffs[4] = {rxbuff0, rxbuff1, rxbuff2, rxbuff3}; - -static struct minimac_softc minimac_softc; +#define CTS_EVENT RTEMS_EVENT_1 +#define RX_EVENT RTEMS_EVENT_1 +#define START_TRANSMIT_EVENT RTEMS_EVENT_2 -static uint32_t rx_slot_state[4] = {MM_MINIMAC_STATE0, MM_MINIMAC_STATE1, - MM_MINIMAC_STATE2, MM_MINIMAC_STATE3}; +static struct arpcom arpcom; +static rtems_id rx_daemon_id; +static rtems_id tx_daemon_id; -static uint32_t rx_slot_addr[4] = {MM_MINIMAC_ADDR0, MM_MINIMAC_ADDR1, - MM_MINIMAC_ADDR2, MM_MINIMAC_ADDR3}; - -static uint32_t rx_slot_count[4] = {MM_MINIMAC_COUNT0, MM_MINIMAC_COUNT1, - MM_MINIMAC_COUNT2, MM_MINIMAC_COUNT3}; -#ifdef CPU_U32_FIX - -/* - * Routine to align the received packet so that the ip header - * is on a 32-bit boundary. Necessary for cpu's that do not - * allow unaligned loads and stores and when the 32-bit DMA - * mode is used. - * - * Transfers are done on word basis to avoid possibly slow byte - * and half-word writes. - * - * Copied over from sonic.c driver - */ +static void minimac_init(void *arg); +static int minimac_ioctl(struct ifnet *ifp, ioctl_command_t command, + caddr_t data); +static void minimac_start(struct ifnet *ifp); -void ipalign(struct mbuf *m) -{ - unsigned int *first, *last, data; - unsigned int tmp = 0; - - if ((((int) m->m_data) & 2) && (m->m_len)) { - last = (unsigned int *) ((((int) m->m_data) + m->m_len + 8) & ~3); - first = (unsigned int *) (((int) m->m_data) & ~3); - tmp = *first << 16; - first++; - do { - data = *first; - *first = tmp | (data >> 16); - tmp = data << 16; - first++; - } while (first <= last); - - m->m_data = (caddr_t)(((int) m->m_data) + 2); - } -} -#endif +static void rx_daemon(void *arg); +static void tx_daemon(void *arg); +static rtems_isr rx_interrupt_handler(rtems_vector_number vector); +static rtems_isr tx_interrupt_handler(rtems_vector_number vector); -static inline int minimac_read(unsigned int reg) +static bool validate_mac(const char *m) { - return *((int*)(reg)); + int i; + + for(i=0;i<6;i++) + if((m[i] != 0x00) && (m[i] != 0xff)) + return true; + return false; } -static inline void minimac_write(unsigned int reg, int value) +static const char *get_mac_address(void) { - *((int*)reg) = value; + const char *flash_mac = (const char *)FLASH_OFFSET_MAC_ADDRESS; + static const char fallback_mac[6] = { 0x10, 0xe2, 0xd5, 0x00, 0x00, 0x00 }; + + if(validate_mac(flash_mac)) + return flash_mac; + else { + printk("Warning: using fallback MAC address\n"); + return fallback_mac; + } } -int rtems_minimac_driver_attach (struct rtems_bsdnet_ifconfig *config, +int rtems_minimac_driver_attach(struct rtems_bsdnet_ifconfig *config, int attaching) { - struct minimac_softc *sc; struct ifnet *ifp; - + rtems_isr_entry dummy; + int i; + static int registered; + uint8_t *tx_buffer = (uint8_t *)MINIMAC_TX_BASE; - if (!attaching) { - printk ("MINIMAC driver cannot be detached.\n"); + if(!attaching) { + printk("Minimac driver cannot be detached.\n"); return 0; } - sc = &minimac_softc; - ifp = &(sc->arpcom.ac_if); + ifp = &(arpcom.ac_if); - if (sc->registered) { - printk ("Driver already in use.\n"); + if(registered) { + printk("Minimac driver already in use.\n"); return 0; } + registered = 1; - sc->registered = 1; - - /* - * Mac address of Milkymist One board is 1 by default - */ - - sc->arpcom.ac_enaddr[0] = 0x00; - sc->arpcom.ac_enaddr[1] = 0x23; - sc->arpcom.ac_enaddr[2] = 0x8b; - sc->arpcom.ac_enaddr[3] = 0x47; - sc->arpcom.ac_enaddr[4] = 0x86; - sc->arpcom.ac_enaddr[5] = 0x20; - ifp->if_softc = sc; + memcpy(arpcom.ac_enaddr, get_mac_address(), 6); ifp->if_mtu = ETHERMTU; ifp->if_unit = 0; ifp->if_name = "minimac"; @@ -134,268 +107,213 @@ int rtems_minimac_driver_attach (struct rtems_bsdnet_ifconfig *config, ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; ifp->if_snd.ifq_maxlen = ifqmaxlen; - if_attach (ifp); + if_attach(ifp); ether_ifattach(ifp); - printk("[minimac] Ethernet driver attached\n"); + + rx_daemon_id = rtems_bsdnet_newproc("mrxd", 4096, rx_daemon, NULL); + tx_daemon_id = rtems_bsdnet_newproc("mtxd", 4096, tx_daemon, NULL); + rtems_interrupt_catch(rx_interrupt_handler, MM_IRQ_ETHRX, &dummy); + rtems_interrupt_catch(tx_interrupt_handler, MM_IRQ_ETHTX, &dummy); + + MM_WRITE(MM_MINIMAC_STATE0, MINIMAC_STATE_LOADED); + MM_WRITE(MM_MINIMAC_STATE1, MINIMAC_STATE_LOADED); + + for(i=0;i<7; i++) + tx_buffer[i] = 0x55; + tx_buffer[7] = 0xd5; + MM_WRITE(MM_MINIMAC_SETUP, 0); + rtems_event_send(tx_daemon_id, CTS_EVENT); + + bsp_interrupt_vector_enable(MM_IRQ_ETHRX); + bsp_interrupt_vector_enable(MM_IRQ_ETHTX); + return 1; } static void minimac_start(struct ifnet *ifp) { - struct minimac_softc *sc = ifp->if_softc; - rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT); + rtems_event_send(tx_daemon_id, START_TRANSMIT_EVENT); ifp->if_flags |= IFF_OACTIVE; -// printk("[minimac] start();\n"); } -/* - * Initialize and start the device - */ -static void minimac_init (void *arg) +static void minimac_init(void *arg) { - struct minimac_softc *sc = arg; - struct ifnet *ifp = &sc->arpcom.ac_if; - unsigned char j; - if (sc->txDaemonTid == 0) { - sc->txDaemonTid = rtems_bsdnet_newproc ("MINIMACtx", 4096, minimac_txDaemon, sc); - sc->rxDaemonTid = rtems_bsdnet_newproc ("MINIMACrx", 4096, minimac_rxDaemon, sc); - set_vector(minimac_rx_interrupt_handler, IRQ_ETHRX, 1); - set_vector(minimac_tx_interrupt_handler, IRQ_ETHTX, 1); - lm32_interrupt_unmask(MM_ETHRX_IRQMASK); - lm32_interrupt_unmask(MM_ETHTX_IRQMASK); - } - - /* - * Tell the world that we're running. - */ + struct ifnet *ifp = &arpcom.ac_if; ifp->if_flags |= IFF_RUNNING; - - /* - * Start the receiver and transmitter - */ - - lm32_interrupt_ack( MM_ETHTX_IRQMASK | MM_ETHRX_IRQMASK ); - minimac_write(MM_MINIMAC_TXREMAINING, 0); - - for (j = 0 ; j < NB_RX_SLOTS ; j++) { - minimac_write(rx_slot_addr[j], (unsigned int)rxbuffs[j]); - minimac_write(rx_slot_state[j], MINIMAC_STATE_LOADED); - } - - - minimac_write(MM_MINIMAC_SETUP, 0); - rtems_event_send(sc->rxDaemonTid, INTERRUPT_EVENT); } -static void minimac_stop (struct minimac_softc *sc) +static void minimac_stop(void) { - struct ifnet *ifp = &sc->arpcom.ac_if; - unsigned char j; + struct ifnet *ifp = &arpcom.ac_if; ifp->if_flags &= ~IFF_RUNNING; - - /* - * Shuts down receiver and transmitter - */ - for (j = 0 ; j < NB_RX_SLOTS ; j++) - minimac_write(rx_slot_state[j], MINIMAC_STATE_EMPTY); - minimac_write(MM_MINIMAC_TXREMAINING, 0); - minimac_write(MM_MINIMAC_SETUP, MINIMAC_SETUP_RXRST | MINIMAC_SETUP_TXRST); } -static int minimac_ioctl(struct ifnet *ifp, ioctl_command_t command, caddr_t data) +static int minimac_ioctl(struct ifnet *ifp, ioctl_command_t command, + caddr_t data) { - - struct minimac_softc *sc = ifp->if_softc; - int error = 0; - switch (command) { - case SIOCGIFADDR: - case SIOCSIFADDR: - ether_ioctl (ifp, command, data); - break; - - case SIOCSIFFLAGS: - switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) { - case IFF_RUNNING: - minimac_stop (sc); - break; - - case IFF_UP: - minimac_init (sc); - break; - - case IFF_UP | IFF_RUNNING: - minimac_stop (sc); - minimac_init (sc); - break; - - default: - break; - } - break; - - case SIO_RTEMS_SHOW_STATS: - minimac_stats (sc); - break; + int error; - /* - * FIXME: All sorts of multicast commands need to be added here! - */ + error = 0; + switch (command) { + case SIOCGIFADDR: + case SIOCSIFADDR: + ether_ioctl(ifp, command, data); + break; + + case SIOCSIFFLAGS: + switch(ifp->if_flags & (IFF_UP | IFF_RUNNING)) { + case IFF_RUNNING: + minimac_stop(); + break; + case IFF_UP: + minimac_init(NULL); + break; + case IFF_UP | IFF_RUNNING: + minimac_stop(); + minimac_init(NULL); + break; default: - error = EINVAL; - break; - } - return error; - + break; + } + break; + default: + error = EINVAL; + break; + } + return error; } -rtems_isr minimac_rx_interrupt_handler(rtems_vector_number vector) + +static rtems_isr rx_interrupt_handler(rtems_vector_number vector) { - unsigned int ip; - struct minimac_softc *sc = &minimac_softc; - lm32_read_interrupts(ip); - if (ip & MM_ETHRX_IRQMASK) { - lm32_interrupt_mask(MM_ETHRX_IRQMASK); - rtems_event_send(sc->rxDaemonTid, INTERRUPT_EVENT); - sc->rxInterrupts++; // update stats - } + /* Deassert IRQ line. + * The RX daemon will then read all the slots we marked as empty. + */ + if(MM_READ(MM_MINIMAC_STATE0) == MINIMAC_STATE_PENDING) + MM_WRITE(MM_MINIMAC_STATE0, MINIMAC_STATE_EMPTY); + if(MM_READ(MM_MINIMAC_STATE1) == MINIMAC_STATE_PENDING) + MM_WRITE(MM_MINIMAC_STATE1, MINIMAC_STATE_EMPTY); + + rtems_event_send(rx_daemon_id, RX_EVENT); + + lm32_interrupt_ack(1 << MM_IRQ_ETHRX); } -rtems_isr minimac_tx_interrupt_handler(rtems_vector_number vector) +static void receive_packet(uint8_t *buffer, int length) { - int ip; - struct minimac_softc *sc = &minimac_softc; - lm32_read_interrupts(ip); - if (ip & MM_ETHTX_IRQMASK) { - lm32_interrupt_ack(MM_ETHTX_IRQMASK); - rtems_event_send(sc->txDaemonTid, INTERRUPT_EVENT); - sc->txInterrupts++; // update stats + struct ifnet *ifp = &arpcom.ac_if; + struct mbuf *m; + struct ether_header *eh; + uint32_t computed_crc, net_crc; + + if(length < 64) { + printk("Warning: Ethernet packet too short\n"); + return; } -} + length -= 4; /* strip CRC */ + net_crc = ((uint32_t)buffer[length]) + | ((uint32_t)buffer[length+1] << 8) + | ((uint32_t)buffer[length+2] << 16) + | ((uint32_t)buffer[length+3] << 24); + length -= 8; /* strip preamble */ + computed_crc = ether_crc32_le(&buffer[8], length) ^ 0xffffffff; + if(computed_crc == net_crc) { + MGETHDR(m, M_WAIT, MT_DATA); + MCLGET(m, M_WAIT); + length -= sizeof(struct ether_header); /* strip Ethernet header */ + memcpy(m->m_data, &buffer[8+sizeof(struct ether_header)], length); + m->m_len = m->m_pkthdr.len = length; + m->m_pkthdr.rcvif = ifp; + eh = (struct ether_header *)&buffer[8]; + ether_input(ifp, eh, m); + } else + printk("Ethernet CRC error: got %08x expected %08x (len=%d)\n", + net_crc, computed_crc, length); +} -static void minimac_rxDaemon(void *arg) +static void rx_daemon(void *arg) { - struct ifnet *ifp = &minimac_softc.arpcom.ac_if; rtems_event_set events; - struct minimac_softc *sc = &minimac_softc; - for (;;) { - uint32_t *buf; - int rxlen; - uint8_t j; - struct mbuf *m; - struct ether_header *eh; - rtems_bsdnet_event_receive( RTEMS_ALL_EVENTS, - RTEMS_WAIT | RTEMS_EVENT_ANY, RTEMS_NO_TIMEOUT, &events); - if(minimac_read(MM_MINIMAC_SETUP) & MINIMAC_SETUP_RXRST ) { - printk("Minimac RX FIFO overflow!\n"); - minimac_write(MM_MINIMAC_SETUP, 0); - lm32_interrupt_ack(MM_ETHRX_IRQMASK); - lm32_interrupt_unmask(MM_ETHRX_IRQMASK); - sc->txFifoFull++; // update stats - } + + while(1) { + rtems_bsdnet_event_receive(RX_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, + RTEMS_NO_TIMEOUT, &events); - for (j = 0 ; j < NB_RX_SLOTS ; j++) { - if (minimac_read(rx_slot_state[j]) == MINIMAC_STATE_PENDING) { - __asm__ volatile( /* Invalidate Level-1 data cache */ - "wcsr DCC, r0\n" - "nop\n" - ); - rxlen = minimac_read(rx_slot_count[j]); - rxlen -= 8; // we drop the preamble - MGETHDR(m, M_WAIT, MT_DATA); - MCLGET(m, M_WAIT); - m->m_pkthdr.rcvif = ifp; - buf = (uint32_t *) mtod(m, uint32_t*); - memcpy(buf, (uint8_t *)minimac_read(rx_slot_addr[j]) + 8, rxlen); - m->m_len = m->m_pkthdr.len = rxlen - sizeof(uint32_t) - sizeof(struct ether_header); - - minimac_write(rx_slot_state[j], MINIMAC_STATE_EMPTY); - minimac_write(rx_slot_state[j], MINIMAC_STATE_LOADED); - eh = mtod(m, struct ether_header*); - m->m_data += sizeof(struct ether_header); -#ifdef CPU_U32_FIX - ipalign(m); -#endif - ether_input(ifp, eh, m); - } + if(MM_READ(MM_MINIMAC_STATE0) == MINIMAC_STATE_EMPTY) { + receive_packet((uint8_t *)MINIMAC_RX0_BASE, MM_READ(MM_MINIMAC_COUNT0)); + MM_WRITE(MM_MINIMAC_STATE0, MINIMAC_STATE_LOADED); } - lm32_interrupt_ack(MM_ETHRX_IRQMASK); // we ack once for all the rx interruptions - lm32_interrupt_unmask(MM_ETHRX_IRQMASK); - } -} -static void minimac_txDaemon(void *arg) -{ - struct ifnet *ifp = &minimac_softc.arpcom.ac_if; - rtems_event_set events; - struct mbuf *m; - int txq; - - for (;;) { - rtems_bsdnet_event_receive (START_TRANSMIT_EVENT | INTERRUPT_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, RTEMS_NO_TIMEOUT, &events); - for (;;) { - txq = 2048; - - if (txq < ifp->if_mtu) - break; - - IF_DEQUEUE(&ifp->if_snd, m); - - if (!m) - break; - minimac_sendpacket(ifp, m); - m_freem(m); + if(MM_READ(MM_MINIMAC_STATE1) == MINIMAC_STATE_EMPTY) { + receive_packet((uint8_t *)MINIMAC_RX1_BASE, MM_READ(MM_MINIMAC_COUNT1)); + MM_WRITE(MM_MINIMAC_STATE1, MINIMAC_STATE_LOADED); } - ifp->if_flags &= ~IFF_OACTIVE; } } -static void minimac_stats(struct minimac_softc *sc) +/* RTEMS apparently doesn't support m_length() ... */ +static int copy_mbuf_chain(struct mbuf *m, uint8_t *target) { + int len; + len = 0; + while(m != NULL) { + if(m->m_len > 0) { + m_copydata(m, 0, m->m_len, (caddr_t)(target + len)); + len += m->m_len; + } + m = m->m_next; + } + return len; } - -static void minimac_sendpacket(struct ifnet *ifp, struct mbuf *m) +static void send_packet(struct ifnet *ifp, struct mbuf *m) { - struct mbuf *nm = m; - struct minimac_softc *sc = &minimac_softc; - unsigned int len = 0; - struct mm_packet p; + unsigned int len; unsigned int crc; - uint8_t i; - for (i = 0 ; i < 7 ; i++) // Preamble - p.preamble[i] = 0x55; - p.preamble[7] = 0xd5; + uint8_t *tx_buffer = (uint8_t *)(MINIMAC_TX_BASE+8); - do - { - unsigned int mlen; - mlen = nm->m_len; - if (nm->m_len > 0) { - m_copydata(nm, 0, mlen, p.raw_data + len); - len += nm->m_len; - } + len = copy_mbuf_chain(m, tx_buffer); + for(;len<60;len++) + tx_buffer[len] = 0x00; // Padding - } while ( (nm = nm->m_next) != 0 ); - for ( ; len < 60 ; len++) - p.raw_data[len] = 0x00; // Padding + crc = ether_crc32_le(tx_buffer, len) ^ 0xffffffff; - crc = mm_ether_crc32((uint8_t *)p.raw_data, len); // CRC32 + tx_buffer[len] = crc & 0xff; + tx_buffer[len+1] = (crc & 0xff00) >> 8; + tx_buffer[len+2] = (crc & 0xff0000) >> 16; + tx_buffer[len+3] = crc >> 24; - p.raw_data[len] = crc & 0xff; - p.raw_data[len+1] = (crc & 0xff00) >> 8; - p.raw_data[len+2] = (crc & 0xff0000) >> 16; - p.raw_data[len+3] = crc >> 24; - - len += 4; // We add 4 bytes of CRC32 + len += 4; // We add 4 bytes of CRC32 - if (len + 8 < 64) { - printk("[minimac] Packet is too small !\n"); - sc->txErrors++; // update stats - return; + MM_WRITE(MM_MINIMAC_TXCOUNT, len + 8); +} + +static rtems_isr tx_interrupt_handler(rtems_vector_number vector) +{ + lm32_interrupt_ack(1 << MM_IRQ_ETHTX); + rtems_event_send(tx_daemon_id, CTS_EVENT); +} + +static void tx_daemon(void *arg) +{ + struct ifnet *ifp = &arpcom.ac_if; + rtems_event_set events; + struct mbuf *m; + + while(1) { + rtems_bsdnet_event_receive(START_TRANSMIT_EVENT, + RTEMS_EVENT_ANY | RTEMS_WAIT, RTEMS_NO_TIMEOUT, &events); + while(1) { + IF_DEQUEUE(&ifp->if_snd, m); + if(m == NULL) + break; + rtems_bsdnet_event_receive(CTS_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, + RTEMS_NO_TIMEOUT, &events); + send_packet(ifp, m); + m_freem(m); } - - minimac_write(MM_MINIMAC_TXADR, (unsigned int)&p); - minimac_write(MM_MINIMAC_TXREMAINING, (unsigned int)(len + 8)); + ifp->if_flags &= ~IFF_OACTIVE; + } } diff --git a/c/src/lib/libbsp/lm32/shared/milkymist_networking/network.h b/c/src/lib/libbsp/lm32/shared/milkymist_networking/network.h index 6d967c5b6c..3cdde6838c 100644 --- a/c/src/lib/libbsp/lm32/shared/milkymist_networking/network.h +++ b/c/src/lib/libbsp/lm32/shared/milkymist_networking/network.h @@ -13,68 +13,9 @@ */ -#ifndef _MM_NETWORKING_H_ -#define _MM_NETWORKING_H_ - -#include "../include/system_conf.h" - -#define IRQ_ETHRX 11 -#define IRQ_ETHTX 12 - -#define INTERRUPT_EVENT RTEMS_EVENT_1 -#define START_TRANSMIT_EVENT RTEMS_EVENT_2 - -#define MINIMAC_STATE_EMPTY (0x0) -#define MINIMAC_STATE_LOADED (0x1) -#define MINIMAC_STATE_PENDING (0x2) - -#define MINIMAC_SETUP_RXRST (0x1) -#define MINIMAC_SETUP_TXRST (0x2) - -#define NB_RX_SLOTS 4 - -#define MM_ETHTX_IRQMASK (1 << IRQ_ETHTX) -#define MM_ETHRX_IRQMASK (1 << IRQ_ETHRX) -#define ETHERNET_FRAME_LENGTH 1532 - -struct mm_packet { - unsigned char preamble[8]; - char raw_data[MLEN]; -} __attribute__((aligned(4), packed)); - -struct minimac_softc { - - struct arpcom arpcom; - uint8_t registered; - - /* - * Statistics - */ - - rtems_id rxDaemonTid; - rtems_id txDaemonTid; - - unsigned long int rxInterrupts; - unsigned long int txInterrupts; - unsigned long int rxedPackets; - unsigned long int txFifoFull; - unsigned long int txErrors; -}; +#ifndef __MILKYMIST_NETWORKING_H_ +#define __MILKYMIST_NETWORKING_H_ int rtems_minimac_driver_attach (struct rtems_bsdnet_ifconfig *, int); -static void minimac_start(struct ifnet *); -static void minimac_init(void *); -static int minimac_ioctl(struct ifnet *, ioctl_command_t, caddr_t); -static void minimac_stop(struct minimac_softc *); - -static void minimac_txDaemon(void *); -static void minimac_rxDaemon(void *); -static void minimac_sendpacket(struct ifnet *, struct mbuf *); - -static rtems_isr minimac_rx_interrupt_handler (rtems_vector_number); -static rtems_isr minimac_tx_interrupt_handler (rtems_vector_number); - -static void minimac_stats(struct minimac_softc *); - #endif diff --git a/c/src/lib/libbsp/lm32/shared/milkymist_pfpu/milkymist_pfpu.h b/c/src/lib/libbsp/lm32/shared/milkymist_pfpu/milkymist_pfpu.h new file mode 100644 index 0000000000..a9c8bd58b9 --- /dev/null +++ b/c/src/lib/libbsp/lm32/shared/milkymist_pfpu/milkymist_pfpu.h @@ -0,0 +1,57 @@ +/* milkymist_pfpu.h + * + * Milkymist PFPU driver for RTEMS + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + * + * COPYRIGHT (c) 2010 Sebastien Bourdeauducq + */ + +#ifndef __MILKYMIST_PFPU_H_ +#define __MILKYMIST_PFPU_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Ioctls */ +#define PFPU_EXECUTE 0x4600 + +#define PFPU_PROGSIZE (2048) +#define PFPU_REG_COUNT (128) + +struct pfpu_td { + unsigned int *output; + unsigned int hmeshlast; + unsigned int vmeshlast; + unsigned int *program; + unsigned int progsize; + float *registers; + bool update; /* < shall we update the "registers" array after completion */ + bool invalidate; /* < shall we invalidate L1 data cache after completion */ +}; + +rtems_device_driver pfpu_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +); + +rtems_device_driver pfpu_control( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +); + +#define PFPU_DRIVER_TABLE_ENTRY {pfpu_initialize, \ +NULL, NULL, NULL, NULL, pfpu_control} + +#ifdef __cplusplus +} +#endif + +#endif /* __MILKYMIST_PFPU_H_ */ diff --git a/c/src/lib/libbsp/lm32/shared/milkymist_pfpu/pfpu.c b/c/src/lib/libbsp/lm32/shared/milkymist_pfpu/pfpu.c new file mode 100644 index 0000000000..ae0df355ea --- /dev/null +++ b/c/src/lib/libbsp/lm32/shared/milkymist_pfpu/pfpu.c @@ -0,0 +1,144 @@ +/* pfpu.c + * + * Milkymist PFPU driver for RTEMS + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + * + * COPYRIGHT (c) 2010, 2011 Sebastien Bourdeauducq + */ + +#define RTEMS_STATUS_CHECKS_USE_PRINTK + +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <sys/types.h> +#include <rtems.h> +#include <bsp.h> +#include <bsp/irq-generic.h> +#include <rtems/libio.h> +#include <rtems/status-checks.h> +#include "../include/system_conf.h" +#include "milkymist_pfpu.h" + +#define DEVICE_NAME "/dev/pfpu" + +static rtems_id done_sem; + +static rtems_isr done_handler(rtems_vector_number n) +{ + rtems_semaphore_release(done_sem); + lm32_interrupt_ack(1 << MM_IRQ_PFPU); +} + +rtems_device_driver pfpu_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + rtems_status_code sc; + rtems_isr_entry dummy; + + sc = rtems_io_register_name(DEVICE_NAME, major, 0); + RTEMS_CHECK_SC(sc, "create PFPU device"); + + sc = rtems_semaphore_create( + rtems_build_name('P', 'F', 'P', 'U'), + 0, + RTEMS_SIMPLE_BINARY_SEMAPHORE, + 0, + &done_sem + ); + RTEMS_CHECK_SC(sc, "create PFPU done semaphore"); + + rtems_interrupt_catch(done_handler, MM_IRQ_PFPU, &dummy); + bsp_interrupt_vector_enable(MM_IRQ_PFPU); + + return RTEMS_SUCCESSFUL; +} + +static void load_program(unsigned int *program, int size) +{ + int page; + int word; + volatile unsigned int *pfpu_prog = (unsigned int *)MM_PFPU_CODEBASE; + + for (page=0;page<(PFPU_PROGSIZE/PFPU_PAGESIZE);page++) { + MM_WRITE(MM_PFPU_CODEPAGE, page); + for (word=0;word<PFPU_PAGESIZE;word++) { + if (size == 0) return; + pfpu_prog[word] = *program; + program++; + size--; + } + } +} + +static void load_registers(float *registers) +{ + volatile float *pfpu_regs = (float *)MM_PFPU_DREGBASE; + int i; + + for (i=PFPU_SPREG_COUNT;i<PFPU_REG_COUNT;i++) + pfpu_regs[i] = registers[i]; +} + +static void update_registers(float *registers) +{ + volatile float *pfpu_regs = (float *)MM_PFPU_DREGBASE; + int i; + + for (i=PFPU_SPREG_COUNT;i<PFPU_REG_COUNT;i++) + registers[i] = pfpu_regs[i]; +} + +static rtems_status_code pfpu_execute(struct pfpu_td *td) +{ + rtems_status_code sc; + + load_program(td->program, td->progsize); + load_registers(td->registers); + MM_WRITE(MM_PFPU_MESHBASE, (unsigned int)td->output); + MM_WRITE(MM_PFPU_HMESHLAST, td->hmeshlast); + MM_WRITE(MM_PFPU_VMESHLAST, td->vmeshlast); + MM_WRITE(MM_PFPU_CTL, PFPU_CTL_START); + + sc = rtems_semaphore_obtain(done_sem, RTEMS_WAIT, 10); + if (sc != RTEMS_SUCCESSFUL) + return sc; + + if (td->update) + update_registers(td->registers); + if (td->invalidate) { + __asm__ volatile( /* Invalidate Level-1 data cache */ + "wcsr DCC, r0\n" + "nop\n" + ); + } + + return RTEMS_SUCCESSFUL; +} + +rtems_device_driver pfpu_control( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + rtems_libio_ioctl_args_t *args = arg; + + args->ioctl_return = -1; + if (args->command != PFPU_EXECUTE) + return RTEMS_UNSATISFIED; + + if (pfpu_execute((struct pfpu_td *)args->buffer) != RTEMS_SUCCESSFUL) + return RTEMS_UNSATISFIED; + + args->ioctl_return = 0; + return RTEMS_SUCCESSFUL; +} diff --git a/c/src/lib/libbsp/lm32/shared/milkymist_timer/timer.c b/c/src/lib/libbsp/lm32/shared/milkymist_timer/timer.c index bf9134fa75..ece2cf3912 100644 --- a/c/src/lib/libbsp/lm32/shared/milkymist_timer/timer.c +++ b/c/src/lib/libbsp/lm32/shared/milkymist_timer/timer.c @@ -25,23 +25,13 @@ #include "../include/system_conf.h" #include "../../shared/clock/clock.h" -static inline int timerread(unsigned int reg) -{ - return *((int*)(reg)); -} - -static inline void timerwrite(unsigned int reg, int value) -{ - *((int*)reg) = value; -} - bool benchmark_timer_find_average_overhead; -void benchmark_timer_initialize( void ) +void benchmark_timer_initialize(void) { - timerwrite(MM_TIMER1_COMPARE, 0xffffffff); - timerwrite(MM_TIMER1_COUNTER, 0); - timerwrite(MM_TIMER1_CONTROL, TIMER_ENABLE); + MM_WRITE(MM_TIMER1_COMPARE, 0xffffffff); + MM_WRITE(MM_TIMER1_COUNTER, 0); + MM_WRITE(MM_TIMER1_CONTROL, TIMER_ENABLE); } /* @@ -59,25 +49,25 @@ void benchmark_timer_initialize( void ) /* This value is in microseconds. */ #define LEAST_VALID 4 /* Don't trust a clicks value lower than this */ -uint32_t benchmark_timer_read( void ) +uint32_t benchmark_timer_read(void) { uint32_t ticks; uint32_t total; - ticks = timerread(MM_TIMER1_COUNTER); + + ticks = MM_READ(MM_TIMER1_COUNTER); if (ticks == 0xffffffff) printk("Timer overflow!\n"); total = ticks / (CPU_FREQUENCY / 1000000); - if ( benchmark_timer_find_average_overhead == true ) + if (benchmark_timer_find_average_overhead) return total; else { - if ( total < LEAST_VALID ) + if (total < LEAST_VALID) return 0; return (total - AVG_OVERHEAD); - } } diff --git a/c/src/lib/libbsp/lm32/shared/milkymist_tmu/milkymist_tmu.h b/c/src/lib/libbsp/lm32/shared/milkymist_tmu/milkymist_tmu.h new file mode 100644 index 0000000000..71f544e498 --- /dev/null +++ b/c/src/lib/libbsp/lm32/shared/milkymist_tmu/milkymist_tmu.h @@ -0,0 +1,85 @@ +/* milkymist_tmu.h + * + * Milkymist TMU driver for RTEMS + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + * + * COPYRIGHT (c) 2010 Sebastien Bourdeauducq + */ + +#ifndef __MILKYMIST_TMU_H_ +#define __MILKYMIST_TMU_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Ioctls */ +#define TMU_EXECUTE 0x5400 +#define TMU_EXECUTE_NONBLOCK 0x5401 +#define TMU_EXECUTE_WAIT 0x5402 + +struct tmu_vertex { + int x; + int y; +} __attribute__((packed)); + +struct tmu_td { + unsigned int flags; + unsigned int hmeshlast; + unsigned int vmeshlast; + unsigned int brightness; + unsigned short chromakey; + struct tmu_vertex *vertices; + unsigned short *texfbuf; + unsigned int texhres; + unsigned int texvres; + unsigned int texhmask; + unsigned int texvmask; + unsigned short *dstfbuf; + unsigned int dsthres; + unsigned int dstvres; + int dsthoffset; + int dstvoffset; + unsigned int dstsquarew; + unsigned int dstsquareh; + unsigned int alpha; + + bool invalidate_before; + bool invalidate_after; +}; + +#define TMU_BRIGHTNESS_MAX (63) +#define TMU_MASK_NOFILTER (0x3ffc0) +#define TMU_MASK_FULL (0x3ffff) +#define TMU_FIXEDPOINT_SHIFT (6) +#define TMU_ALPHA_MAX (63) +#define TMU_MESH_MAXSIZE (128) + +#define TMU_FLAG_CHROMAKEY (2) +#define TMU_FLAG_ADDITIVE (4) + +rtems_device_driver tmu_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +); + +rtems_device_driver tmu_control( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +); + +#define TMU_DRIVER_TABLE_ENTRY {tmu_initialize, \ +NULL, NULL, NULL, NULL, tmu_control} + +#ifdef __cplusplus +} +#endif + +#endif /* __MILKYMIST_TMU_H_ */ diff --git a/c/src/lib/libbsp/lm32/shared/milkymist_tmu/tmu.c b/c/src/lib/libbsp/lm32/shared/milkymist_tmu/tmu.c new file mode 100644 index 0000000000..b057fc9582 --- /dev/null +++ b/c/src/lib/libbsp/lm32/shared/milkymist_tmu/tmu.c @@ -0,0 +1,163 @@ +/* tmu.c + * + * Milkymist TMU driver for RTEMS + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + * + * COPYRIGHT (c) 2010, 2011 Sebastien Bourdeauducq + */ + +#define RTEMS_STATUS_CHECKS_USE_PRINTK + +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <sys/types.h> +#include <rtems.h> +#include <bsp.h> +#include <bsp/irq-generic.h> +#include <rtems/libio.h> +#include <rtems/status-checks.h> +#include "../include/system_conf.h" +#include "milkymist_tmu.h" + +#define DEVICE_NAME "/dev/tmu" + +static rtems_id done_sem; + +static rtems_isr done_handler(rtems_vector_number n) +{ + rtems_semaphore_release(done_sem); + lm32_interrupt_ack(1 << MM_IRQ_TMU); +} + +rtems_device_driver tmu_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + rtems_status_code sc; + rtems_isr_entry dummy; + + sc = rtems_io_register_name(DEVICE_NAME, major, 0); + RTEMS_CHECK_SC(sc, "create TMU device"); + + sc = rtems_semaphore_create( + rtems_build_name('T', 'M', 'U', ' '), + 0, + RTEMS_SIMPLE_BINARY_SEMAPHORE, + 0, + &done_sem + ); + RTEMS_CHECK_SC(sc, "create TMU done semaphore"); + + rtems_interrupt_catch(done_handler, MM_IRQ_TMU, &dummy); + bsp_interrupt_vector_enable(MM_IRQ_TMU); + + return RTEMS_SUCCESSFUL; +} + +static void invalidate_l2(void) +{ + volatile char *flushbase = (char *)FMLBRG_FLUSH_BASE; + int i, offset; + + offset = 0; + for (i=0;i<FMLBRG_LINE_COUNT;i++) { + flushbase[offset] = 0; + offset += FMLBRG_LINE_LENGTH; + } +} + +static bool invalidate_after; + +static void tmu_start(struct tmu_td *td) +{ + if (td->invalidate_before) + invalidate_l2(); + + MM_WRITE(MM_TMU_HMESHLAST, td->hmeshlast); + MM_WRITE(MM_TMU_VMESHLAST, td->vmeshlast); + MM_WRITE(MM_TMU_BRIGHTNESS, td->brightness); + MM_WRITE(MM_TMU_CHROMAKEY, td->chromakey); + + MM_WRITE(MM_TMU_VERTICESADR, (unsigned int)td->vertices); + MM_WRITE(MM_TMU_TEXFBUF, (unsigned int)td->texfbuf); + MM_WRITE(MM_TMU_TEXHRES, td->texhres); + MM_WRITE(MM_TMU_TEXVRES, td->texvres); + MM_WRITE(MM_TMU_TEXHMASK, td->texhmask); + MM_WRITE(MM_TMU_TEXVMASK, td->texvmask); + + MM_WRITE(MM_TMU_DSTFBUF, (unsigned int)td->dstfbuf); + MM_WRITE(MM_TMU_DSTHRES, td->dsthres); + MM_WRITE(MM_TMU_DSTVRES, td->dstvres); + MM_WRITE(MM_TMU_DSTHOFFSET, td->dsthoffset); + MM_WRITE(MM_TMU_DSTVOFFSET, td->dstvoffset); + MM_WRITE(MM_TMU_DSTSQUAREW, td->dstsquarew); + MM_WRITE(MM_TMU_DSTSQUAREH, td->dstsquareh); + + MM_WRITE(MM_TMU_ALPHA, td->alpha); + + MM_WRITE(MM_TMU_CTL, td->flags|TMU_CTL_START); + + invalidate_after = td->invalidate_after; +} + +static rtems_status_code tmu_finalize(void) +{ + rtems_status_code sc; + + sc = rtems_semaphore_obtain(done_sem, RTEMS_WAIT, 100); + if (sc != RTEMS_SUCCESSFUL) + return sc; + + if (invalidate_after) { + invalidate_l2(); + __asm__ volatile( /* Invalidate Level-1 data cache */ + "wcsr DCC, r0\n" + "nop\n" + ); + } + + return RTEMS_SUCCESSFUL; +} + +rtems_device_driver tmu_control( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + rtems_libio_ioctl_args_t *args = arg; + struct tmu_td *td = (struct tmu_td *)args->buffer; + rtems_status_code sc; + + switch (args->command) { + case TMU_EXECUTE: + tmu_start(td); + sc = tmu_finalize(); + break; + case TMU_EXECUTE_NONBLOCK: + tmu_start(td); + sc = RTEMS_SUCCESSFUL; + break; + case TMU_EXECUTE_WAIT: + sc = tmu_finalize(); + break; + default: + sc = RTEMS_UNSATISFIED; + break; + } + + if (sc == RTEMS_SUCCESSFUL) + args->ioctl_return = 0; + else + args->ioctl_return = -1; + + return sc; +} diff --git a/c/src/lib/libbsp/lm32/shared/milkymist_usbinput/comloc.h b/c/src/lib/libbsp/lm32/shared/milkymist_usbinput/comloc.h new file mode 100644 index 0000000000..538022b30d --- /dev/null +++ b/c/src/lib/libbsp/lm32/shared/milkymist_usbinput/comloc.h @@ -0,0 +1,26 @@ +/* comloc.h + * + * Milkymist USB input devices driver for RTEMS + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + * + * COPYRIGHT (c) 2010 Sebastien Bourdeauducq + */ + +#ifndef __COMLOC_H_ +#define __COMLOC_H_ + +#define COMLOCV(x) (*(volatile unsigned char *)(x)) + +#define COMLOC_DEBUG_PRODUCE COMLOCV(MM_SOFTUSB_DMEM_BASE+0x1000) +#define COMLOC_DEBUG(offset) COMLOCV(MM_SOFTUSB_DMEM_BASE+0x1001+offset) +#define COMLOC_MEVT_PRODUCE COMLOCV(MM_SOFTUSB_DMEM_BASE+0x1101) +#define COMLOC_MEVT(offset) COMLOCV(MM_SOFTUSB_DMEM_BASE+0x1102+offset) +#define COMLOC_KEVT_PRODUCE COMLOCV(MM_SOFTUSB_DMEM_BASE+0x1142) +#define COMLOC_KEVT(offset) COMLOCV(MM_SOFTUSB_DMEM_BASE+0x1143+offset) + +#endif /* __COMLOC_H_ */ diff --git a/c/src/lib/libbsp/lm32/shared/milkymist_usbinput/milkymist_usbinput.h b/c/src/lib/libbsp/lm32/shared/milkymist_usbinput/milkymist_usbinput.h new file mode 100644 index 0000000000..dc912124de --- /dev/null +++ b/c/src/lib/libbsp/lm32/shared/milkymist_usbinput/milkymist_usbinput.h @@ -0,0 +1,46 @@ +/* milkymist_usbinput.h + * + * Milkymist USB input devices driver for RTEMS + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + * + * COPYRIGHT (c) 2010 Sebastien Bourdeauducq + */ + +#ifndef __MILKYMIST_USBINPUT_H_ +#define __MILKYMIST_USBINPUT_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +rtems_device_driver usbinput_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +); + +rtems_device_driver usbinput_open( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +); + +rtems_device_driver usbinput_read( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +); + +#define USBINPUT_DRIVER_TABLE_ENTRY {usbinput_initialize, \ +usbinput_open, NULL, usbinput_read, NULL, NULL} + +#ifdef __cplusplus +} +#endif + +#endif /* __MILKYMIST_USBINPUT_H_ */ diff --git a/c/src/lib/libbsp/lm32/shared/milkymist_usbinput/softusb-input.h b/c/src/lib/libbsp/lm32/shared/milkymist_usbinput/softusb-input.h new file mode 100644 index 0000000000..26feda0459 --- /dev/null +++ b/c/src/lib/libbsp/lm32/shared/milkymist_usbinput/softusb-input.h @@ -0,0 +1,329 @@ +/* softusb-input.h + * + * Milkymist USB input devices driver for RTEMS + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + * + * COPYRIGHT (c) 2010, 2011 Sebastien Bourdeauducq + */ + + 0x0f, 0xef, 0x0e, 0xbf, 0x0f, 0xe1, 0x0d, 0xbf, 0xfb, 0xd5, 0x27, 0xc4, + 0x5d, 0xc4, 0x76, 0xc4, 0x87, 0xc4, 0xa3, 0xc4, 0xda, 0xc4, 0x32, 0xc5, + 0x52, 0xc5, 0x73, 0x6f, 0x66, 0x74, 0x75, 0x73, 0x62, 0x2d, 0x69, 0x6e, + 0x70, 0x75, 0x74, 0x20, 0x76, 0x31, 0x2e, 0x30, 0x52, 0x43, 0x31, 0x0a, + 0x00, 0x46, 0x75, 0x6c, 0x6c, 0x20, 0x73, 0x70, 0x65, 0x65, 0x64, 0x20, + 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x20, 0x6f, 0x6e, 0x20, 0x70, 0x6f, + 0x72, 0x74, 0x20, 0x00, 0x4c, 0x6f, 0x77, 0x20, 0x73, 0x70, 0x65, 0x65, + 0x64, 0x20, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x20, 0x6f, 0x6e, 0x20, + 0x70, 0x6f, 0x72, 0x74, 0x20, 0x00, 0x56, 0x49, 0x44, 0x3a, 0x20, 0x00, + 0x2c, 0x20, 0x50, 0x49, 0x44, 0x3a, 0x20, 0x00, 0x46, 0x6f, 0x75, 0x6e, + 0x64, 0x20, 0x00, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, + 0x65, 0x64, 0x20, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x0a, 0x00, 0x6b, + 0x65, 0x79, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x0a, 0x00, 0x6d, 0x6f, 0x75, + 0x73, 0x65, 0x0a, 0x00, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x20, 0x64, + 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x20, 0x6f, 0x6e, + 0x20, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x00, 0x43, 0x6f, 0x6e, 0x74, 0x72, + 0x6f, 0x6c, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x20, + 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x3a, 0x0a, 0x00, 0x53, 0x45, 0x54, + 0x55, 0x50, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x79, 0x3a, 0x0a, 0x00, 0x49, + 0x4e, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x79, 0x3a, 0x0a, 0x00, 0x4f, 0x55, + 0x54, 0x2f, 0x44, 0x41, 0x54, 0x41, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x79, + 0x3a, 0x0a, 0x00, 0x28, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x29, 0x0a, 0x00, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, + 0x65, 0x72, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x3a, 0x20, 0x00, 0x52, + 0x58, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x20, 0x65, 0x72, + 0x72, 0x6f, 0x72, 0x0a, 0x00, 0x52, 0x58, 0x20, 0x62, 0x69, 0x74, 0x73, + 0x74, 0x75, 0x66, 0x66, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x0a, 0x00, + 0x52, 0x65, 0x74, 0x72, 0x79, 0x20, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x20, + 0x65, 0x78, 0x63, 0x65, 0x65, 0x64, 0x65, 0x64, 0x2c, 0x20, 0x64, 0x69, + 0x73, 0x61, 0x62, 0x6c, 0x69, 0x6e, 0x67, 0x20, 0x64, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x2e, 0x0a, 0x00, 0x44, 0x41, 0x54, 0x41, 0x78, 0x20, 0x6d, + 0x69, 0x73, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x0a, 0x00, 0x28, 0x6e, 0x6f, + 0x20, 0x64, 0x61, 0x74, 0x61, 0x29, 0x0a, 0x00, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, + 0x00, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x01, 0xc0, 0x80, + 0x41, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x00, 0xc1, 0x81, + 0x40, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x01, 0xc0, 0x80, + 0x41, 0x00, 0xc1, 0x81, 0x40, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, + 0x41, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x01, 0xc0, 0x80, + 0x41, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x00, 0xc1, 0x81, + 0x40, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x00, 0xc1, 0x81, + 0x40, 0x01, 0xc0, 0x80, 0x41, 0x01, 0xc0, 0x80, 0x41, 0x00, 0xc1, 0x81, + 0x40, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x01, 0xc0, 0x80, + 0x41, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x00, 0xc1, 0x81, + 0x40, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x01, 0xc0, 0x80, + 0x41, 0x00, 0xc1, 0x81, 0x40, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, + 0x41, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x01, 0xc0, 0x80, + 0x41, 0x00, 0xc1, 0x81, 0x40, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, + 0x41, 0x01, 0xc0, 0x80, 0x41, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, + 0x41, 0x00, 0xc1, 0x81, 0x40, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, + 0x41, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x01, 0xc0, 0x80, + 0x41, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x00, 0xc1, 0x81, + 0x40, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x01, 0xc0, 0x80, + 0x41, 0x00, 0xc1, 0x81, 0x40, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, + 0x41, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x01, 0xc0, 0x80, + 0x41, 0x00, 0xc1, 0x81, 0x40, 0x00, 0xc0, 0xc1, 0x01, 0xc3, 0x03, 0x02, + 0xc2, 0xc6, 0x06, 0x07, 0xc7, 0x05, 0xc5, 0xc4, 0x04, 0xcc, 0x0c, 0x0d, + 0xcd, 0x0f, 0xcf, 0xce, 0x0e, 0x0a, 0xca, 0xcb, 0x0b, 0xc9, 0x09, 0x08, + 0xc8, 0xd8, 0x18, 0x19, 0xd9, 0x1b, 0xdb, 0xda, 0x1a, 0x1e, 0xde, 0xdf, + 0x1f, 0xdd, 0x1d, 0x1c, 0xdc, 0x14, 0xd4, 0xd5, 0x15, 0xd7, 0x17, 0x16, + 0xd6, 0xd2, 0x12, 0x13, 0xd3, 0x11, 0xd1, 0xd0, 0x10, 0xf0, 0x30, 0x31, + 0xf1, 0x33, 0xf3, 0xf2, 0x32, 0x36, 0xf6, 0xf7, 0x37, 0xf5, 0x35, 0x34, + 0xf4, 0x3c, 0xfc, 0xfd, 0x3d, 0xff, 0x3f, 0x3e, 0xfe, 0xfa, 0x3a, 0x3b, + 0xfb, 0x39, 0xf9, 0xf8, 0x38, 0x28, 0xe8, 0xe9, 0x29, 0xeb, 0x2b, 0x2a, + 0xea, 0xee, 0x2e, 0x2f, 0xef, 0x2d, 0xed, 0xec, 0x2c, 0xe4, 0x24, 0x25, + 0xe5, 0x27, 0xe7, 0xe6, 0x26, 0x22, 0xe2, 0xe3, 0x23, 0xe1, 0x21, 0x20, + 0xe0, 0xa0, 0x60, 0x61, 0xa1, 0x63, 0xa3, 0xa2, 0x62, 0x66, 0xa6, 0xa7, + 0x67, 0xa5, 0x65, 0x64, 0xa4, 0x6c, 0xac, 0xad, 0x6d, 0xaf, 0x6f, 0x6e, + 0xae, 0xaa, 0x6a, 0x6b, 0xab, 0x69, 0xa9, 0xa8, 0x68, 0x78, 0xb8, 0xb9, + 0x79, 0xbb, 0x7b, 0x7a, 0xba, 0xbe, 0x7e, 0x7f, 0xbf, 0x7d, 0xbd, 0xbc, + 0x7c, 0xb4, 0x74, 0x75, 0xb5, 0x77, 0xb7, 0xb6, 0x76, 0x72, 0xb2, 0xb3, + 0x73, 0xb1, 0x71, 0x70, 0xb0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, + 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9c, 0x5c, 0x5d, + 0x9d, 0x5f, 0x9f, 0x9e, 0x5e, 0x5a, 0x9a, 0x9b, 0x5b, 0x99, 0x59, 0x58, + 0x98, 0x88, 0x48, 0x49, 0x89, 0x4b, 0x8b, 0x8a, 0x4a, 0x4e, 0x8e, 0x8f, + 0x4f, 0x8d, 0x4d, 0x4c, 0x8c, 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, + 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80, 0x40, 0x00, 0x28, 0x2f, + 0x39, 0x2f, 0x80, 0xe8, 0x84, 0xb9, 0x85, 0xb1, 0x88, 0x23, 0xe9, 0xf7, + 0xe2, 0x2f, 0xf3, 0x2f, 0x90, 0xe0, 0x07, 0xc0, 0x80, 0x81, 0x84, 0xb9, + 0x85, 0xb1, 0x88, 0x23, 0xe9, 0xf7, 0x9f, 0x5f, 0x31, 0x96, 0x96, 0x17, + 0xb8, 0xf3, 0x80, 0xe0, 0x86, 0xb9, 0x87, 0xb1, 0x88, 0x23, 0xe9, 0xf7, + 0x08, 0x95, 0x48, 0x2f, 0x59, 0x2f, 0x2f, 0xef, 0x3f, 0xe0, 0x10, 0xc0, + 0x21, 0x15, 0x31, 0x05, 0x21, 0xf4, 0x8e, 0xe0, 0x91, 0xe0, 0x60, 0xd4, + 0x20, 0xc0, 0x8c, 0xb1, 0x88, 0x23, 0x21, 0xf0, 0x8e, 0xe0, 0x91, 0xe0, + 0x59, 0xd4, 0x10, 0xc0, 0x21, 0x50, 0x30, 0x40, 0x8a, 0xb1, 0x88, 0x23, + 0x69, 0xf3, 0x24, 0x2f, 0x35, 0x2f, 0xe2, 0x2f, 0xf3, 0x2f, 0x90, 0xe0, + 0x2f, 0xef, 0x3f, 0xe0, 0x12, 0xc0, 0x8c, 0xb1, 0x88, 0x23, 0x19, 0xf0, + 0x81, 0xe3, 0x91, 0xe0, 0x08, 0xc0, 0x8b, 0xb1, 0x88, 0x23, 0x99, 0xf0, + 0x21, 0x15, 0x31, 0x05, 0x21, 0xf4, 0x8f, 0xe1, 0x91, 0xe0, 0x3c, 0xd4, + 0x0b, 0xc0, 0x21, 0x50, 0x30, 0x40, 0x8a, 0xb1, 0x88, 0x23, 0x59, 0xf3, + 0x96, 0x17, 0x21, 0xf0, 0x89, 0xb1, 0x81, 0x93, 0x9f, 0x5f, 0xe2, 0xcf, + 0x90, 0xe0, 0x89, 0x2f, 0x08, 0x95, 0xcf, 0x93, 0xdf, 0x93, 0xc8, 0x2f, + 0xd9, 0x2f, 0x8b, 0x81, 0x8f, 0x5f, 0x8b, 0x83, 0x81, 0x50, 0x85, 0x31, + 0x2c, 0xf0, 0x84, 0xe4, 0x91, 0xe0, 0x20, 0xd4, 0x88, 0xe0, 0x88, 0x83, + 0xdf, 0x91, 0xcf, 0x91, 0x08, 0x95, 0xff, 0x92, 0x0f, 0x93, 0x1f, 0x93, + 0x04, 0x2f, 0x15, 0x2f, 0xe4, 0x2f, 0xf5, 0x2f, 0x80, 0x83, 0x61, 0x83, + 0x60, 0x70, 0x77, 0x70, 0xf7, 0x2e, 0x72, 0x83, 0x81, 0x81, 0x67, 0x2f, + 0xbb, 0xd4, 0x88, 0x0f, 0x88, 0x0f, 0x88, 0x0f, 0xf8, 0x2a, 0xe0, 0x2f, + 0xf1, 0x2f, 0xf2, 0x82, 0x1f, 0x91, 0x0f, 0x91, 0xff, 0x90, 0x08, 0x95, + 0x2f, 0x92, 0x3f, 0x92, 0x4f, 0x92, 0x5f, 0x92, 0x6f, 0x92, 0x7f, 0x92, + 0x8f, 0x92, 0x9f, 0x92, 0xaf, 0x92, 0xbf, 0x92, 0xcf, 0x92, 0xdf, 0x92, + 0xef, 0x92, 0xff, 0x92, 0x0f, 0x93, 0x1f, 0x93, 0xdf, 0x93, 0xcf, 0x93, + 0xcd, 0xb7, 0xde, 0xb7, 0x2b, 0x97, 0xde, 0xbf, 0xcd, 0xbf, 0x38, 0x2e, + 0xf6, 0x2e, 0xe7, 0x2e, 0x24, 0x2e, 0xa2, 0x2e, 0xb3, 0x2e, 0x40, 0x2e, + 0x51, 0x2e, 0x8d, 0xe2, 0x63, 0x2d, 0x70, 0xe0, 0x0c, 0x2f, 0x1d, 0x2f, + 0x0f, 0x5f, 0x1f, 0x4f, 0x40, 0x2f, 0x51, 0x2f, 0xbc, 0xdf, 0x80, 0x2f, + 0x91, 0x2f, 0x63, 0xe0, 0x4e, 0xdf, 0x83, 0xec, 0x89, 0x83, 0xac, 0x2f, + 0xbd, 0x2f, 0x12, 0x96, 0x8f, 0x2d, 0x9e, 0x2d, 0xe8, 0x2f, 0xf9, 0x2f, + 0x88, 0xe0, 0x01, 0x90, 0x0d, 0x92, 0x81, 0x50, 0xe1, 0xf7, 0x32, 0xe0, + 0x83, 0x2e, 0x91, 0x2c, 0x8c, 0x0e, 0x9d, 0x1e, 0x88, 0x2d, 0x99, 0x2d, + 0x68, 0xe0, 0x4c, 0x2f, 0x5d, 0x2f, 0x46, 0x5f, 0x5f, 0x4f, 0x88, 0xd4, + 0x0c, 0x2f, 0x1d, 0x2f, 0x0f, 0x5f, 0x1f, 0x4f, 0x80, 0x2f, 0x91, 0x2f, + 0x6b, 0xe0, 0x2b, 0xdf, 0x80, 0x2f, 0x91, 0x2f, 0x6b, 0xe0, 0x41, 0xdf, + 0xf8, 0x2e, 0x41, 0xe0, 0x84, 0x17, 0x19, 0xf4, 0x89, 0x81, 0x82, 0x3d, + 0x31, 0xf0, 0x8b, 0xeb, 0x90, 0xe0, 0xa2, 0xd3, 0x85, 0xed, 0x90, 0xe0, + 0x5b, 0xc0, 0x22, 0x20, 0x09, 0xf4, 0x66, 0xc0, 0xdd, 0x24, 0xcc, 0x24, + 0xc3, 0x94, 0x60, 0x2e, 0x71, 0x2e, 0x88, 0x2d, 0x99, 0x2d, 0x99, 0x2e, + 0x64, 0x2d, 0x6d, 0x19, 0x09, 0xf4, 0xb5, 0xc0, 0xe6, 0x2e, 0x58, 0xe0, + 0x56, 0x17, 0x14, 0xf4, 0x28, 0xe0, 0xe2, 0x2e, 0x81, 0xee, 0x63, 0x2d, + 0x70, 0xe0, 0x46, 0x2d, 0x57, 0x2d, 0x69, 0xdf, 0x86, 0x2d, 0x97, 0x2d, + 0x63, 0xe0, 0xfb, 0xde, 0x80, 0xe0, 0xcc, 0x20, 0x09, 0xf4, 0x81, 0xe0, + 0xc8, 0x2e, 0x88, 0x23, 0x11, 0xf4, 0x8b, 0xe4, 0x01, 0xc0, 0x83, 0xec, + 0x89, 0x83, 0x0e, 0x2d, 0x11, 0x27, 0x07, 0xfd, 0x10, 0x95, 0x88, 0x2d, + 0x99, 0x2d, 0x6a, 0x2d, 0x7b, 0x2d, 0x40, 0x2f, 0x51, 0x2f, 0x62, 0xd4, + 0x40, 0x2f, 0x51, 0x2f, 0x4f, 0x5f, 0x5f, 0x4f, 0x46, 0x0d, 0x57, 0x1d, + 0x88, 0x2d, 0x99, 0x2d, 0x6e, 0x2d, 0x30, 0xd4, 0x6e, 0x2d, 0x6d, 0x5f, + 0x86, 0x2d, 0x97, 0x2d, 0xd6, 0xde, 0x86, 0x2d, 0x97, 0x2d, 0x6b, 0xe0, + 0xec, 0xde, 0xf8, 0x2e, 0x81, 0xe0, 0xf8, 0x16, 0x21, 0xf4, 0x89, 0x81, + 0x82, 0x3d, 0x19, 0xf4, 0x11, 0xc0, 0x1f, 0x14, 0x24, 0xf4, 0x89, 0x81, + 0x8a, 0x35, 0x09, 0xf4, 0xb5, 0xcf, 0x8b, 0xeb, 0x90, 0xe0, 0x46, 0xd3, + 0x83, 0xee, 0x90, 0xe0, 0x43, 0xd3, 0x8c, 0x2f, 0x9d, 0x2f, 0x01, 0x96, + 0x6f, 0x2d, 0xca, 0xc0, 0xde, 0x0c, 0x48, 0xe0, 0xe4, 0x16, 0x09, 0xf0, + 0x5e, 0xc0, 0xa0, 0x0e, 0xb1, 0x1e, 0xa2, 0xcf, 0x41, 0x14, 0x51, 0x04, + 0x11, 0xf4, 0xdd, 0x24, 0x54, 0xc0, 0xdd, 0x24, 0x80, 0x2f, 0x91, 0x2f, + 0xc0, 0x2e, 0xe9, 0x2e, 0x88, 0x2d, 0x99, 0x2d, 0x99, 0x2e, 0x92, 0xed, + 0x79, 0x2e, 0x89, 0xe6, 0x63, 0x2d, 0x70, 0xe0, 0x4c, 0x2d, 0x5e, 0x2d, + 0x06, 0xdf, 0x8c, 0x2d, 0x9e, 0x2d, 0x63, 0xe0, 0x98, 0xde, 0x8c, 0x2d, + 0x9e, 0x2d, 0x6b, 0xe0, 0xae, 0xde, 0x18, 0x2f, 0x83, 0x30, 0x34, 0xf0, + 0x89, 0x81, 0x83, 0x3c, 0x59, 0xf0, 0x8b, 0x34, 0x19, 0xf4, 0x08, 0xc0, + 0x18, 0x16, 0x1c, 0xf4, 0x89, 0x81, 0x8a, 0x35, 0x21, 0xf3, 0x8b, 0xeb, + 0x90, 0xe0, 0x59, 0xc0, 0x8d, 0xef, 0xf8, 0x2e, 0xf1, 0x0e, 0x8f, 0x2d, + 0x99, 0x27, 0x87, 0xfd, 0x90, 0x95, 0x2d, 0x2d, 0x33, 0x27, 0x27, 0xfd, + 0x30, 0x95, 0x44, 0x2d, 0x55, 0x2d, 0x42, 0x1b, 0x53, 0x0b, 0x48, 0x17, + 0x59, 0x07, 0x14, 0xf4, 0xf4, 0x2c, 0xfd, 0x18, 0x0f, 0x2d, 0x11, 0x27, + 0x07, 0xfd, 0x10, 0x95, 0x8a, 0x2d, 0x9b, 0x2d, 0x68, 0x2d, 0x79, 0x2d, + 0x40, 0x2f, 0x51, 0x2f, 0xe1, 0xd3, 0x79, 0x82, 0x8c, 0x2d, 0x9e, 0x2d, + 0x61, 0xe0, 0x5f, 0xde, 0xdf, 0x0c, 0x57, 0xe0, 0x5f, 0x15, 0x1c, 0xf4, + 0xa0, 0x0e, 0xb1, 0x1e, 0xb6, 0xcf, 0xcc, 0x24, 0xc3, 0x94, 0xec, 0x2e, + 0xfd, 0x2e, 0x08, 0x94, 0xe1, 0x1c, 0xf1, 0x1c, 0x22, 0x20, 0x11, 0xf4, + 0x81, 0xee, 0x01, 0xc0, 0x89, 0xe6, 0x63, 0x2d, 0x70, 0xe0, 0x4e, 0x2d, + 0x5f, 0x2d, 0xb1, 0xde, 0x8e, 0x2d, 0x9f, 0x2d, 0x63, 0xe0, 0x43, 0xde, + 0x22, 0x20, 0x19, 0xf1, 0x8e, 0x2d, 0x9f, 0x2d, 0x6b, 0xe0, 0x57, 0xde, + 0x18, 0x2f, 0x83, 0x30, 0x31, 0xf4, 0x89, 0x81, 0x83, 0x3c, 0x89, 0xf0, + 0x8b, 0x34, 0x19, 0xf4, 0x0e, 0xc0, 0x18, 0x16, 0x1c, 0xf4, 0x89, 0x81, + 0x8a, 0x35, 0xf1, 0xf2, 0x8b, 0xeb, 0x90, 0xe0, 0xb1, 0xd2, 0x8f, 0xef, + 0x90, 0xe0, 0xae, 0xd2, 0x8e, 0xee, 0x90, 0xe0, 0x32, 0xc0, 0x82, 0xed, + 0x89, 0x83, 0x8c, 0x2f, 0x9d, 0x2f, 0x01, 0x96, 0x61, 0xe0, 0x1f, 0xde, + 0x32, 0xc0, 0x80, 0xe0, 0xcc, 0x20, 0x09, 0xf4, 0x81, 0xe0, 0xc8, 0x2e, + 0x88, 0x23, 0x11, 0xf4, 0x8b, 0xe4, 0x01, 0xc0, 0x83, 0xec, 0x89, 0x83, + 0x1b, 0x82, 0x1a, 0x82, 0x8e, 0x2d, 0x9f, 0x2d, 0x63, 0xe0, 0x0d, 0xde, + 0x8e, 0x2d, 0x9f, 0x2d, 0x6b, 0xe0, 0x23, 0xde, 0x18, 0x2f, 0x81, 0x30, + 0x21, 0xf4, 0x89, 0x81, 0x82, 0x3d, 0x19, 0xf4, 0x16, 0xc0, 0x18, 0x16, + 0x24, 0xf4, 0x89, 0x81, 0x8a, 0x35, 0x09, 0xf4, 0xad, 0xcf, 0x8b, 0xeb, + 0x90, 0xe0, 0x7e, 0xd2, 0x8f, 0xef, 0x90, 0xe0, 0x7b, 0xd2, 0x83, 0xee, + 0x90, 0xe0, 0x78, 0xd2, 0x8c, 0x2f, 0x9d, 0x2f, 0x01, 0x96, 0x61, 0x2f, + 0xb5, 0xd2, 0xdd, 0x24, 0xda, 0x94, 0x8d, 0x2d, 0x2b, 0x96, 0xde, 0xbf, + 0xcd, 0xbf, 0xcf, 0x91, 0xdf, 0x91, 0x1f, 0x91, 0x0f, 0x91, 0xff, 0x90, + 0xef, 0x90, 0xdf, 0x90, 0xcf, 0x90, 0xbf, 0x90, 0xaf, 0x90, 0x9f, 0x90, + 0x8f, 0x90, 0x7f, 0x90, 0x6f, 0x90, 0x5f, 0x90, 0x4f, 0x90, 0x3f, 0x90, + 0x2f, 0x90, 0x08, 0x95, 0xcf, 0x92, 0xdf, 0x92, 0xef, 0x92, 0xff, 0x92, + 0x0f, 0x93, 0x1f, 0x93, 0xdf, 0x93, 0xcf, 0x93, 0xcd, 0xb7, 0xde, 0xb7, + 0xc4, 0x5a, 0xd0, 0x40, 0xde, 0xbf, 0xcd, 0xbf, 0xe8, 0x2e, 0xf9, 0x2e, + 0x06, 0x2f, 0xe8, 0x2f, 0xf9, 0x2f, 0x80, 0x81, 0x82, 0x30, 0x8c, 0xf0, + 0x61, 0x34, 0x11, 0xf4, 0x80, 0xb1, 0x01, 0xc0, 0x81, 0xb1, 0x88, 0x23, + 0x51, 0xf4, 0x80, 0xea, 0x90, 0xe0, 0x3a, 0xd2, 0x80, 0x2f, 0x2b, 0xd2, + 0x8a, 0xe0, 0x29, 0xd2, 0xee, 0x2d, 0xff, 0x2d, 0x10, 0x82, 0xee, 0x2d, + 0xff, 0x2d, 0x80, 0x81, 0xe8, 0x2f, 0xff, 0x27, 0xe7, 0xfd, 0xf0, 0x95, + 0xe8, 0x30, 0xf1, 0x05, 0x08, 0xf0, 0xc9, 0xc1, 0xeb, 0x5f, 0xff, 0x4f, + 0x09, 0x94, 0x01, 0x34, 0x11, 0xf4, 0x10, 0xb1, 0x01, 0xc0, 0x11, 0xb1, + 0x11, 0x30, 0x61, 0xf4, 0x81, 0xe3, 0x90, 0xe0, 0x1b, 0xd2, 0x80, 0x2f, + 0x0c, 0xd2, 0x8a, 0xe0, 0x0a, 0xd2, 0xee, 0x2d, 0xff, 0x2d, 0x11, 0x83, + 0x88, 0xe0, 0x3c, 0xc0, 0x12, 0x30, 0x09, 0xf0, 0xb0, 0xc1, 0x8c, 0xe4, + 0x90, 0xe0, 0x0c, 0xd2, 0x80, 0x2f, 0xfd, 0xd1, 0x8a, 0xe0, 0xfb, 0xd1, + 0xee, 0x2d, 0xff, 0x2d, 0x11, 0x82, 0x01, 0x34, 0x21, 0xf4, 0x88, 0xb1, + 0x81, 0x60, 0x88, 0xb9, 0x03, 0xc0, 0x88, 0xb1, 0x82, 0x60, 0x88, 0xb9, + 0x81, 0xe0, 0xee, 0x2d, 0xff, 0x2d, 0x80, 0x83, 0x80, 0x91, 0x0e, 0x00, + 0x90, 0x91, 0x0f, 0x00, 0x82, 0x5a, 0x9e, 0x4f, 0x97, 0x70, 0x95, 0x83, + 0x84, 0x83, 0x8f, 0xc1, 0x20, 0x91, 0x0e, 0x00, 0x30, 0x91, 0x0f, 0x00, + 0xee, 0x2d, 0xff, 0x2d, 0x84, 0x81, 0x95, 0x81, 0x28, 0x17, 0x39, 0x07, + 0x09, 0xf0, 0x83, 0xc1, 0x01, 0x34, 0x21, 0xf4, 0x88, 0xb1, 0x82, 0x70, + 0x88, 0xb9, 0x03, 0xc0, 0x88, 0xb1, 0x81, 0x70, 0x88, 0xb9, 0x82, 0xe0, + 0xee, 0x2d, 0xff, 0x2d, 0x80, 0x83, 0x75, 0xc1, 0xee, 0x2d, 0xff, 0x2d, + 0x84, 0x81, 0x95, 0x81, 0x86, 0x50, 0x9f, 0x4f, 0x97, 0x70, 0x20, 0x91, + 0x0e, 0x00, 0x30, 0x91, 0x0f, 0x00, 0x28, 0x17, 0x39, 0x07, 0x09, 0xf0, + 0x66, 0xc1, 0x13, 0x82, 0x83, 0xe0, 0xec, 0xcf, 0x19, 0x82, 0x85, 0xe0, + 0x8a, 0x83, 0x81, 0xe0, 0x8b, 0x83, 0x1c, 0x82, 0x1d, 0x82, 0x1e, 0x82, + 0x1f, 0x82, 0x18, 0x86, 0x80, 0xe0, 0x6c, 0x2f, 0x7d, 0x2f, 0x6f, 0x5f, + 0x7f, 0x4f, 0x41, 0xe0, 0x20, 0xe0, 0x30, 0xe0, 0x00, 0xe0, 0x10, 0xe0, + 0xad, 0xdd, 0x88, 0x23, 0x09, 0xf0, 0xb3, 0xc0, 0xee, 0x2d, 0xff, 0x2d, + 0x13, 0x82, 0x84, 0xe0, 0xad, 0xc0, 0x80, 0xe8, 0x89, 0x83, 0x86, 0xe0, + 0x8a, 0x83, 0x1b, 0x82, 0x81, 0xe0, 0x8c, 0x83, 0x1d, 0x82, 0x1e, 0x82, + 0x82, 0xe1, 0x8f, 0x83, 0x18, 0x86, 0x81, 0xe0, 0x6c, 0x2f, 0x7d, 0x2f, + 0x6f, 0x5f, 0x7f, 0x4f, 0x40, 0xe0, 0x2c, 0x2f, 0x3d, 0x2f, 0x2c, 0x5e, + 0x3f, 0x4f, 0x02, 0xe1, 0x10, 0xe0, 0x8c, 0xdd, 0x87, 0xfd, 0x93, 0xc0, + 0xee, 0x2d, 0xff, 0x2d, 0x13, 0x82, 0x86, 0xe6, 0x90, 0xe0, 0x84, 0xd1, + 0x8d, 0x8d, 0x9a, 0xd1, 0x8c, 0x8d, 0x98, 0xd1, 0x8c, 0xe6, 0x90, 0xe0, + 0x7d, 0xd1, 0x8f, 0x8d, 0x93, 0xd1, 0x8e, 0x8d, 0x91, 0xd1, 0x8a, 0xe0, + 0x6a, 0xd1, 0x88, 0x8d, 0x88, 0x23, 0x09, 0xf0, 0x4d, 0xc0, 0x89, 0x8d, + 0x88, 0x23, 0x09, 0xf0, 0x49, 0xc0, 0x85, 0xe0, 0x56, 0xc0, 0x80, 0xe8, + 0x89, 0x83, 0x86, 0xe0, 0x8a, 0x83, 0x1b, 0x82, 0x82, 0xe0, 0x8c, 0x83, + 0x1d, 0x82, 0x1e, 0x82, 0x8f, 0xe7, 0x8f, 0x83, 0x18, 0x86, 0x46, 0xe2, + 0xc4, 0x2e, 0xd1, 0x2c, 0xcc, 0x0e, 0xdd, 0x1e, 0x81, 0xe0, 0x6c, 0x2f, + 0x7d, 0x2f, 0x6f, 0x5f, 0x7f, 0x4f, 0x40, 0xe0, 0x2c, 0x2d, 0x3d, 0x2d, + 0x0f, 0xe7, 0x10, 0xe0, 0x51, 0xdd, 0x48, 0x2f, 0x87, 0xfd, 0x57, 0xc0, + 0xee, 0x2d, 0xff, 0x2d, 0x13, 0x82, 0x90, 0xe0, 0x2c, 0x2d, 0x3d, 0x2d, + 0x1f, 0xc0, 0xe9, 0x2f, 0xff, 0x27, 0xe7, 0xfd, 0xf0, 0x95, 0xe2, 0x0f, + 0xf3, 0x1f, 0x81, 0x81, 0x84, 0x30, 0xa1, 0xf4, 0x85, 0x81, 0x83, 0x30, + 0xa9, 0xf4, 0x86, 0x81, 0x81, 0x30, 0x91, 0xf4, 0x87, 0x81, 0x81, 0x30, + 0x19, 0xf0, 0x82, 0x30, 0x69, 0xf4, 0x04, 0xc0, 0xee, 0x2d, 0xff, 0x2d, + 0x82, 0x83, 0xc5, 0xc0, 0xee, 0x2d, 0xff, 0x2d, 0x12, 0x82, 0xc1, 0xc0, + 0x80, 0x81, 0x98, 0x0f, 0x94, 0x17, 0xfc, 0xf2, 0x84, 0xe7, 0x90, 0xe0, + 0x23, 0xd1, 0x8b, 0xe7, 0x90, 0xe0, 0x20, 0xd1, 0x88, 0xe0, 0x07, 0xc0, + 0x8f, 0xe8, 0x90, 0xe0, 0x02, 0xc0, 0x89, 0xe9, 0x90, 0xe0, 0x18, 0xd1, + 0x86, 0xe0, 0xee, 0x2d, 0xff, 0x2d, 0x1c, 0xc0, 0x19, 0x82, 0x89, 0xe0, + 0x8a, 0x83, 0x81, 0xe0, 0x8b, 0x83, 0x1c, 0x82, 0x1d, 0x82, 0x1e, 0x82, + 0x1f, 0x82, 0x18, 0x86, 0x6c, 0x2f, 0x7d, 0x2f, 0x6f, 0x5f, 0x7f, 0x4f, + 0x41, 0xe0, 0x20, 0xe0, 0x30, 0xe0, 0x00, 0xe0, 0x10, 0xe0, 0x00, 0xdd, + 0x88, 0x23, 0x39, 0xf4, 0xee, 0x2d, 0xff, 0x2d, 0x13, 0x82, 0x83, 0xec, + 0x86, 0x83, 0x87, 0xe0, 0x80, 0x83, 0x8e, 0x2d, 0x9f, 0x2d, 0xc7, 0xdc, + 0x94, 0xc0, 0x0c, 0x2f, 0x1d, 0x2f, 0x07, 0x5f, 0x1f, 0x4f, 0x89, 0xe6, + 0x61, 0xe8, 0x70, 0xe0, 0x40, 0x2f, 0x51, 0x2f, 0xce, 0xdc, 0x80, 0x2f, + 0x91, 0x2f, 0x63, 0xe0, 0x60, 0xdc, 0x80, 0x2f, 0x91, 0x2f, 0x6b, 0xe0, + 0x76, 0xdc, 0xd8, 0x2e, 0xf6, 0xe0, 0xf8, 0x17, 0x08, 0xf0, 0x7d, 0xc0, + 0x99, 0x85, 0xee, 0x2d, 0xff, 0x2d, 0x86, 0x81, 0x98, 0x17, 0x81, 0xf0, + 0x93, 0x3c, 0x19, 0xf0, 0x9b, 0x34, 0x09, 0xf0, 0x72, 0xc0, 0x82, 0xed, + 0x89, 0x87, 0x8c, 0x2f, 0x9d, 0x2f, 0x09, 0x96, 0x61, 0xe0, 0x45, 0xdc, + 0x8d, 0xe6, 0x91, 0xe0, 0xc7, 0xd0, 0x67, 0xc0, 0x82, 0xed, 0x89, 0x87, + 0x80, 0x2f, 0x91, 0x2f, 0x61, 0xe0, 0x3b, 0xdc, 0xee, 0x2d, 0xff, 0x2d, + 0x86, 0x81, 0x83, 0x3c, 0x11, 0xf4, 0x8b, 0xe4, 0x03, 0xc0, 0x83, 0xec, + 0xee, 0x2d, 0xff, 0x2d, 0x86, 0x83, 0xee, 0x2d, 0xff, 0x2d, 0x82, 0x81, + 0x88, 0x23, 0x29, 0xf1, 0xf8, 0xe0, 0xfd, 0x15, 0x08, 0xf0, 0x40, 0xc0, + 0x90, 0x91, 0x42, 0x11, 0x89, 0x2f, 0x88, 0x0f, 0x88, 0x0f, 0x88, 0x0f, + 0xac, 0x2f, 0xbd, 0x2f, 0x1a, 0x96, 0x29, 0xe3, 0x31, 0xe1, 0x2c, 0x1b, + 0x3d, 0x0b, 0x28, 0x0f, 0x31, 0x1d, 0x4c, 0x2f, 0x5d, 0x2f, 0x4e, 0x5e, + 0x5f, 0x4f, 0xe2, 0x2f, 0xf3, 0x2f, 0xea, 0x0f, 0xfb, 0x1f, 0x8d, 0x91, + 0x80, 0x83, 0xa4, 0x17, 0xb5, 0x07, 0xb9, 0xf7, 0x9f, 0x5f, 0x97, 0x70, + 0x90, 0x93, 0x42, 0x11, 0x1f, 0xc0, 0x90, 0x91, 0x01, 0x11, 0x89, 0x2f, + 0x88, 0x0f, 0x88, 0x0f, 0xac, 0x2f, 0xbd, 0x2f, 0x1a, 0x96, 0x28, 0xef, + 0x30, 0xe1, 0x2c, 0x1b, 0x3d, 0x0b, 0x28, 0x0f, 0x31, 0x1d, 0x4c, 0x2f, + 0x5d, 0x2f, 0x42, 0x5f, 0x5f, 0x4f, 0xe2, 0x2f, 0xf3, 0x2f, 0xea, 0x0f, + 0xfb, 0x1f, 0x8d, 0x91, 0x80, 0x83, 0xa4, 0x17, 0xb5, 0x07, 0xb9, 0xf7, + 0x9f, 0x5f, 0x9f, 0x70, 0x90, 0x93, 0x01, 0x11, 0x81, 0xe0, 0x85, 0xbb, + 0x0a, 0xc0, 0x84, 0xe7, 0x90, 0xe0, 0x66, 0xd0, 0xee, 0x2d, 0xff, 0x2d, + 0x82, 0x81, 0x88, 0x23, 0x09, 0xf0, 0x42, 0xcf, 0x44, 0xcf, 0xcc, 0x55, + 0xdf, 0x4f, 0xde, 0xbf, 0xcd, 0xbf, 0xcf, 0x91, 0xdf, 0x91, 0x1f, 0x91, + 0x0f, 0x91, 0xff, 0x90, 0xef, 0x90, 0xdf, 0x90, 0xcf, 0x90, 0x08, 0x95, + 0xff, 0x92, 0x0f, 0x93, 0x1f, 0x93, 0x8a, 0xe1, 0x90, 0xe0, 0x4c, 0xd0, + 0x81, 0xe0, 0x8d, 0xb9, 0x83, 0xe0, 0x8e, 0xb9, 0x80, 0xe0, 0x81, 0xbb, + 0x00, 0xe0, 0x11, 0xe0, 0x52, 0xe0, 0xf5, 0x2e, 0x82, 0xb3, 0x8b, 0x3b, + 0xe8, 0xf3, 0x81, 0xb3, 0x80, 0x37, 0xd0, 0xf3, 0x01, 0xbb, 0x90, 0xe0, + 0x80, 0x91, 0x00, 0x00, 0x82, 0x30, 0x09, 0xf4, 0x91, 0xe0, 0x80, 0x91, + 0x07, 0x00, 0x82, 0x30, 0x09, 0xf4, 0x92, 0x60, 0x93, 0xb9, 0x1f, 0xb9, + 0x87, 0xb1, 0x88, 0x23, 0xe9, 0xf7, 0x00, 0x00, 0x8f, 0x5f, 0x80, 0x38, + 0xe1, 0xf7, 0x02, 0xb9, 0x13, 0xb9, 0x80, 0xe0, 0x90, 0xe0, 0x61, 0xe4, + 0xc7, 0xdd, 0x87, 0xb1, 0x88, 0x23, 0xe9, 0xf7, 0x12, 0xb9, 0xf3, 0xb8, + 0x87, 0xe0, 0x90, 0xe0, 0x62, 0xe4, 0xbe, 0xdd, 0x80, 0x91, 0x0e, 0x00, + 0x90, 0x91, 0x0f, 0x00, 0x01, 0x96, 0x97, 0x70, 0x90, 0x93, 0x0f, 0x00, + 0x80, 0x93, 0x0e, 0x00, 0xcb, 0xcf, 0xa0, 0xe0, 0xb0, 0xe1, 0x9c, 0x91, + 0xe9, 0x2f, 0xf0, 0xe0, 0xef, 0x5f, 0xff, 0x4e, 0x80, 0x83, 0x9f, 0x5f, + 0x9c, 0x93, 0x81, 0xe0, 0x85, 0xbb, 0x08, 0x95, 0x28, 0x2f, 0x39, 0x2f, + 0x41, 0xe0, 0x0d, 0xc0, 0x80, 0x91, 0x00, 0x10, 0xe8, 0x2f, 0xf0, 0xe0, + 0xef, 0x5f, 0xff, 0x4e, 0x90, 0x83, 0x8f, 0x5f, 0x80, 0x93, 0x00, 0x10, + 0x45, 0xbb, 0x2f, 0x5f, 0x3f, 0x4f, 0xe2, 0x2f, 0xf3, 0x2f, 0xc8, 0x95, + 0x90, 0x2d, 0x99, 0x23, 0x69, 0xf7, 0x08, 0x95, 0x28, 0x2f, 0x82, 0x95, + 0x8f, 0x70, 0xe8, 0xe8, 0xf1, 0xe0, 0xe8, 0x0f, 0xf1, 0x1d, 0xc8, 0x95, + 0x90, 0x2d, 0xa0, 0xe0, 0xb0, 0xe1, 0x8c, 0x91, 0xe8, 0x2f, 0xf0, 0xe0, + 0xef, 0x5f, 0xff, 0x4e, 0x90, 0x83, 0x8f, 0x5f, 0x8c, 0x93, 0x81, 0xe0, + 0x85, 0xbb, 0xe2, 0x2f, 0xf0, 0xe0, 0xef, 0x70, 0xf0, 0x70, 0xe8, 0x57, + 0xfe, 0x4f, 0xc8, 0x95, 0x90, 0x2d, 0xa0, 0xe0, 0xb0, 0xe1, 0x8c, 0x91, + 0xe8, 0x2f, 0xf0, 0xe0, 0xef, 0x5f, 0xff, 0x4e, 0x90, 0x83, 0x8f, 0x5f, + 0x8c, 0x93, 0x81, 0xe0, 0x85, 0xbb, 0x08, 0x95, 0xdf, 0x92, 0xef, 0x92, + 0xff, 0x92, 0x0f, 0x93, 0x1f, 0x93, 0xcf, 0x93, 0xdf, 0x93, 0x28, 0x2f, + 0x39, 0x2f, 0x06, 0x2f, 0x66, 0x23, 0x51, 0xf0, 0xc2, 0x2f, 0xd3, 0x2f, + 0x10, 0xe0, 0x90, 0xe2, 0xd9, 0x2e, 0xff, 0x24, 0xf3, 0x94, 0x8a, 0xe0, + 0xe8, 0x2e, 0x20, 0xc0, 0x8d, 0xe7, 0x91, 0xe0, 0xa5, 0xdf, 0x2d, 0xc0, + 0x88, 0x81, 0xba, 0xdf, 0x81, 0x2f, 0x8f, 0x70, 0x51, 0xf4, 0x11, 0x23, + 0x41, 0xf0, 0x80, 0x91, 0x00, 0x10, 0xe8, 0x2f, 0xf0, 0xe0, 0xef, 0x5f, + 0xff, 0x4e, 0xe0, 0x82, 0x07, 0xc0, 0x80, 0x91, 0x00, 0x10, 0xe8, 0x2f, + 0xf0, 0xe0, 0xef, 0x5f, 0xff, 0x4e, 0xd0, 0x82, 0x8f, 0x5f, 0x80, 0x93, + 0x00, 0x10, 0xf5, 0xba, 0x1f, 0x5f, 0x21, 0x96, 0x10, 0x17, 0x10, 0xf3, + 0x0f, 0x70, 0x69, 0xf0, 0x90, 0x91, 0x00, 0x10, 0xe9, 0x2f, 0xf0, 0xe0, + 0xef, 0x5f, 0xff, 0x4e, 0x8a, 0xe0, 0x80, 0x83, 0x9f, 0x5f, 0x90, 0x93, + 0x00, 0x10, 0x81, 0xe0, 0x85, 0xbb, 0xdf, 0x91, 0xcf, 0x91, 0x1f, 0x91, + 0x0f, 0x91, 0xff, 0x90, 0xef, 0x90, 0xdf, 0x90, 0x08, 0x95, 0x98, 0xe0, + 0x96, 0x1b, 0x38, 0x2f, 0x01, 0xc0, 0x33, 0x0f, 0x9a, 0x95, 0xea, 0xf7, + 0x20, 0xe0, 0x41, 0xe0, 0x12, 0xc0, 0x93, 0x2f, 0x99, 0x1f, 0x99, 0x27, + 0x99, 0x1f, 0x90, 0x5d, 0x80, 0x91, 0x00, 0x10, 0xe8, 0x2f, 0xf0, 0xe0, + 0xef, 0x5f, 0xff, 0x4e, 0x90, 0x83, 0x8f, 0x5f, 0x80, 0x93, 0x00, 0x10, + 0x45, 0xbb, 0x33, 0x0f, 0x2f, 0x5f, 0x26, 0x17, 0x60, 0xf3, 0x08, 0x95, + 0x48, 0x2f, 0x2f, 0xe1, 0x30, 0xe0, 0x54, 0xe1, 0x94, 0x2f, 0x91, 0x70, + 0x46, 0x95, 0x82, 0x2f, 0x81, 0x70, 0x26, 0x95, 0x98, 0x13, 0x25, 0x27, + 0x3f, 0x5f, 0x38, 0x30, 0xa9, 0xf7, 0x30, 0xe0, 0x44, 0xe1, 0x96, 0x2f, + 0x91, 0x70, 0x66, 0x95, 0x82, 0x2f, 0x81, 0x70, 0x26, 0x95, 0x98, 0x13, + 0x24, 0x27, 0x3f, 0x5f, 0x33, 0x30, 0xa9, 0xf7, 0x20, 0x95, 0x82, 0x2f, + 0x8f, 0x71, 0x08, 0x95, 0xcf, 0x93, 0xdf, 0x93, 0xc4, 0x2f, 0xd5, 0x2f, + 0xa8, 0x2f, 0xb9, 0x2f, 0x9f, 0xef, 0x2f, 0xef, 0x30, 0xe0, 0x15, 0xc0, + 0x8d, 0x91, 0x98, 0x27, 0x49, 0x2f, 0x50, 0xe0, 0x84, 0x2f, 0x95, 0x2f, + 0x87, 0x56, 0x9e, 0x4f, 0xe8, 0x2f, 0xf9, 0x2f, 0xc8, 0x95, 0x90, 0x2d, + 0x92, 0x27, 0x47, 0x56, 0x5d, 0x4f, 0xe4, 0x2f, 0xf5, 0x2f, 0xc8, 0x95, + 0x80, 0x2d, 0x3f, 0x5f, 0x28, 0x2f, 0x36, 0x17, 0x48, 0xf3, 0x90, 0x95, + 0x98, 0x83, 0x20, 0x95, 0x29, 0x83, 0xdf, 0x91, 0xcf, 0x91, 0x08, 0x95, + 0xcf, 0x93, 0xdf, 0x93, 0xc8, 0x2f, 0xd9, 0x2f, 0x20, 0xe0, 0x30, 0xe0, + 0x0c, 0xc0, 0xec, 0x2f, 0xfd, 0x2f, 0xe2, 0x0f, 0xf3, 0x1f, 0xa6, 0x2f, + 0xb7, 0x2f, 0xa2, 0x0f, 0xb3, 0x1f, 0x8c, 0x91, 0x80, 0x83, 0x2f, 0x5f, + 0x3f, 0x4f, 0x24, 0x17, 0x35, 0x07, 0x8c, 0xf3, 0x8c, 0x2f, 0x9d, 0x2f, + 0xdf, 0x91, 0xcf, 0x91, 0x08, 0x95 diff --git a/c/src/lib/libbsp/lm32/shared/milkymist_usbinput/usbinput.c b/c/src/lib/libbsp/lm32/shared/milkymist_usbinput/usbinput.c new file mode 100644 index 0000000000..022d7306f6 --- /dev/null +++ b/c/src/lib/libbsp/lm32/shared/milkymist_usbinput/usbinput.c @@ -0,0 +1,149 @@ +/* usbinput.c + * + * Milkymist USB input devices driver for RTEMS + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + * + * COPYRIGHT (c) 2010, 2011 Sebastien Bourdeauducq + */ + +#define RTEMS_STATUS_CHECKS_USE_PRINTK + +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <sys/types.h> +#include <rtems.h> +#include <bsp.h> +#include <bsp/irq-generic.h> +#include <rtems/libio.h> +#include <rtems/status-checks.h> +#include "../include/system_conf.h" +#include "milkymist_usbinput.h" + +static const unsigned char input_firmware[] = { +#include "softusb-input.h" +}; + +#include "comloc.h" + +#define DEVICE_NAME "/dev/usbinput" + +static int mouse_consume; +static int keyboard_consume; + +static rtems_id event_q; + +static rtems_isr interrupt_handler(rtems_vector_number n) +{ + unsigned char msg[8]; + int i; + + lm32_interrupt_ack(1 << MM_IRQ_USB); + + while(mouse_consume != COMLOC_MEVT_PRODUCE) { + for(i=0;i<4;i++) + msg[i] = COMLOC_MEVT(4*mouse_consume+i); + rtems_message_queue_send(event_q, msg, 4); + mouse_consume = (mouse_consume + 1) & 0x0f; + } + + while(keyboard_consume != COMLOC_KEVT_PRODUCE) { + for(i=0;i<8;i++) + msg[i] = COMLOC_KEVT(8*keyboard_consume+i); + rtems_message_queue_send(event_q, msg, 8); + keyboard_consume = (keyboard_consume + 1) & 0x07; + } +} + +rtems_device_driver usbinput_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + rtems_status_code sc; + volatile unsigned int *usb_dmem + = (volatile unsigned int *)MM_SOFTUSB_DMEM_BASE; + volatile unsigned int *usb_pmem + = (volatile unsigned int *)MM_SOFTUSB_PMEM_BASE; + int i, nwords; + rtems_isr_entry dummy; + + MM_WRITE(MM_SOFTUSB_CONTROL, SOFTUSB_CONTROL_RESET); + for(i=0;i<SOFTUSB_DMEM_SIZE/4;i++) + usb_dmem[i] = 0; + for(i=0;i<SOFTUSB_PMEM_SIZE/2;i++) + usb_pmem[i] = 0; + nwords = (sizeof(input_firmware)+1)/2; + for(i=0;i<nwords;i++) + usb_pmem[i] = ((unsigned int)(input_firmware[2*i])) + |((unsigned int)(input_firmware[2*i+1]) << 8); + MM_WRITE(MM_SOFTUSB_CONTROL, 0); + + mouse_consume = 0; + keyboard_consume = 0; + + sc = rtems_io_register_name(DEVICE_NAME, major, 0); + RTEMS_CHECK_SC(sc, "create USB input device"); + + sc = rtems_message_queue_create( + rtems_build_name('U', 'S', 'B', 'I'), + 64, + 8, + 0, + &event_q + ); + RTEMS_CHECK_SC(sc, "create USB event queue"); + + rtems_interrupt_catch(interrupt_handler, MM_IRQ_USB, &dummy); + bsp_interrupt_vector_enable(MM_IRQ_USB); + + return RTEMS_SUCCESSFUL; +} + +rtems_device_driver usbinput_open( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + uint32_t count; + + rtems_message_queue_flush(event_q, &count); + return RTEMS_SUCCESSFUL; +} + +rtems_device_driver usbinput_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; + rtems_status_code sc; + + if(rw_args->count < 8) { + rw_args->bytes_moved = 0; + return RTEMS_UNSATISFIED; + } + + sc = rtems_message_queue_receive( + event_q, + rw_args->buffer, + (size_t *)&rw_args->bytes_moved, + RTEMS_WAIT, + RTEMS_NO_TIMEOUT + ); + + if(sc == RTEMS_SUCCESSFUL) + return RTEMS_SUCCESSFUL; + else { + rw_args->bytes_moved = 0; + return RTEMS_UNSATISFIED; + } +} diff --git a/c/src/lib/libbsp/lm32/shared/milkymist_versions/milkymist_versions.h b/c/src/lib/libbsp/lm32/shared/milkymist_versions/milkymist_versions.h new file mode 100644 index 0000000000..9799ad44c6 --- /dev/null +++ b/c/src/lib/libbsp/lm32/shared/milkymist_versions/milkymist_versions.h @@ -0,0 +1,40 @@ +/* milkymist_versions.h + * + * Milkymist versioning driver for RTEMS + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + * + * COPYRIGHT (c) 2010 Sebastien Bourdeauducq + */ + +#ifndef __MILKYMIST_VERSIONS_H_ +#define __MILKYMIST_VERSIONS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +rtems_device_driver versions_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +); + +rtems_device_driver versions_read( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +); + +#define VERSIONS_DRIVER_TABLE_ENTRY {versions_initialize, \ +NULL, NULL, versions_read, NULL, NULL} + +#ifdef __cplusplus +} +#endif + +#endif /* __MILKYMIST_VERSIONS_H_ */ diff --git a/c/src/lib/libbsp/lm32/shared/milkymist_versions/versions.c b/c/src/lib/libbsp/lm32/shared/milkymist_versions/versions.c new file mode 100644 index 0000000000..421419e77b --- /dev/null +++ b/c/src/lib/libbsp/lm32/shared/milkymist_versions/versions.c @@ -0,0 +1,133 @@ +/* versions.c + * + * Milkymist versioning driver for RTEMS + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + * + * COPYRIGHT (c) 2010, 2011 Sebastien Bourdeauducq + */ + +#define RTEMS_STATUS_CHECKS_USE_PRINTK + +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <rtems.h> +#include <rtems/status-checks.h> +#include <bsp.h> +#include <rtems/libio.h> +#include "../include/system_conf.h" +#include "milkymist_versions.h" + +#define SOC_DEVICE_NAME "/dev/soc" +#define PCB_DEVICE_NAME "/dev/pcb" +#define PCBREV_DEVICE_NAME "/dev/pcb_rev" + +rtems_device_driver versions_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + rtems_status_code sc; + + sc = rtems_io_register_name(SOC_DEVICE_NAME, major, 0); + RTEMS_CHECK_SC(sc, "create SoC version device"); + sc = rtems_io_register_name(PCB_DEVICE_NAME, major, 1); + RTEMS_CHECK_SC(sc, "create PCB type device"); + sc = rtems_io_register_name(PCBREV_DEVICE_NAME, major, 2); + RTEMS_CHECK_SC(sc, "create PCB revision device"); + + return RTEMS_SUCCESSFUL; +} + +static int get_soc_version(char *buffer) +{ + char fmt[13]; + char *version; + int len; + unsigned int id; + unsigned int major, minor, subminor, rc; + + id = MM_READ(MM_SYSTEM_ID); + major = (id & 0xf0000000) >> 28; + minor = (id & 0x0f000000) >> 24; + subminor = (id & 0x00f00000) >> 20; + rc = (id & 0x000f0000) >> 16; + + version = fmt; + version += sprintf(version, "%u.%u", major, minor); + if (subminor != 0) + version += sprintf(version, ".%u", subminor); + if (rc != 0) + version += sprintf(version, "RC%u", rc); + + len = version - fmt; + memcpy(buffer, fmt, len); + return len; +} + +static int get_pcb_type(char *buffer) +{ + unsigned int id; + + id = MM_READ(MM_SYSTEM_ID); + buffer[0] = (id & 0x0000ff00) >> 8; + buffer[1] = id & 0x000000ff; + return 2; +} + +static int get_pcb_revision(char *buffer) +{ + unsigned int v; + + v = MM_READ(MM_GPIO_IN); + v = (v & 0x78) >> 3; + buffer[0] = '0' + v; + return 1; +} + +rtems_device_driver versions_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; + + if(rw_args->offset != 0) { + rw_args->bytes_moved = 0; + return RTEMS_SUCCESSFUL; + } + + switch (minor) { + case 0: + if (rw_args->count < 12) { + rw_args->bytes_moved = 0; + return RTEMS_UNSATISFIED; + } + rw_args->bytes_moved = get_soc_version((char *)rw_args->buffer); + return RTEMS_SUCCESSFUL; + case 1: + if (rw_args->count < 2) { + rw_args->bytes_moved = 0; + return RTEMS_UNSATISFIED; + } + rw_args->bytes_moved = get_pcb_type((char *)rw_args->buffer); + return RTEMS_SUCCESSFUL; + case 2: + if (rw_args->count < 1) { + rw_args->bytes_moved = 0; + return RTEMS_UNSATISFIED; + } + rw_args->bytes_moved = get_pcb_revision((char *)rw_args->buffer); + return RTEMS_SUCCESSFUL; + } + + rw_args->bytes_moved = 0; + return RTEMS_UNSATISFIED; +} diff --git a/c/src/lib/libbsp/lm32/shared/milkymist_video/milkymist_video.h b/c/src/lib/libbsp/lm32/shared/milkymist_video/milkymist_video.h new file mode 100644 index 0000000000..8f8090872c --- /dev/null +++ b/c/src/lib/libbsp/lm32/shared/milkymist_video/milkymist_video.h @@ -0,0 +1,67 @@ +/* milkymist_video.h + * + * Milkymist video input driver for RTEMS + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + * + * COPYRIGHT (c) 2010 Sebastien Bourdeauducq + */ + +#ifndef __MILKYMIST_VIDEO_H_ +#define __MILKYMIST_VIDEO_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Ioctls */ +#define VIDEO_BUFFER_LOCK 0x5600 +#define VIDEO_BUFFER_UNLOCK 0x5601 + +#define VIDEO_SET_BRIGHTNESS 0x5602 +#define VIDEO_GET_BRIGHTNESS 0x5603 +#define VIDEO_SET_CONTRAST 0x5604 +#define VIDEO_GET_CONTRAST 0x5605 +#define VIDEO_SET_HUE 0x5606 +#define VIDEO_GET_HUE 0x5607 +#define VIDEO_GET_SIGNAL 0x5608 + +#define VIDEO_SET_REGISTER 0x5609 +#define VIDEO_GET_REGISTER 0x560a + +rtems_device_driver video_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +); + +rtems_device_driver video_open( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +); + +rtems_device_driver video_close( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +); + +rtems_device_driver video_control( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +); + +#define VIDEO_DRIVER_TABLE_ENTRY {video_initialize, \ +video_open, video_close, NULL, NULL, video_control} + +#ifdef __cplusplus +} +#endif + +#endif /* __MILKYMIST_VIDEO_H_ */ diff --git a/c/src/lib/libbsp/lm32/shared/milkymist_video/video.c b/c/src/lib/libbsp/lm32/shared/milkymist_video/video.c new file mode 100644 index 0000000000..d8d706baaf --- /dev/null +++ b/c/src/lib/libbsp/lm32/shared/milkymist_video/video.c @@ -0,0 +1,356 @@ +/* video.c + * + * Milkymist video input driver for RTEMS + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + * + * COPYRIGHT (c) 2010, 2011 Sebastien Bourdeauducq + */ + +#define RTEMS_STATUS_CHECKS_USE_PRINTK + +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <sys/types.h> +#include <rtems.h> +#include <bsp.h> +#include <bsp/irq-generic.h> +#include <rtems/libio.h> +#include <rtems/status-checks.h> +#include "../include/system_conf.h" +#include "milkymist_video.h" + +#define DEVICE_NAME "/dev/video" +#define N_BUFFERS 3 +#define FRAME_W 720 +#define FRAME_H 288 + +static bool buffers_locked[N_BUFFERS]; +static void *buffers[N_BUFFERS]; +static int last_buffer; +static int current_buffer; + +static rtems_isr frame_handler(rtems_vector_number n) +{ + int remaining_attempts; + + lm32_interrupt_ack(1 << MM_IRQ_VIDEOIN); + + last_buffer = current_buffer; + + /* get a new buffer */ + remaining_attempts = N_BUFFERS; + do { + current_buffer++; + if(current_buffer == N_BUFFERS) + current_buffer = 0; + remaining_attempts--; + } while(buffers_locked[current_buffer] && (remaining_attempts > 0)); + + MM_WRITE(MM_BT656_BASE, (unsigned int)buffers[current_buffer]); + + if(buffers_locked[current_buffer]) + printk("Failed to find unlocked buffer\n"); +} + +static void i2c_delay(void) +{ + unsigned int i; + + for(i=0;i<1000;i++) __asm__("nop"); +} + +/* I2C bit-banging functions from http://en.wikipedia.org/wiki/I2c */ +static unsigned int i2c_read_bit(void) +{ + unsigned int bit; + + /* Let the slave drive data */ + MM_WRITE(MM_BT656_I2C, 0); + i2c_delay(); + MM_WRITE(MM_BT656_I2C, BT656_I2C_SDC); + i2c_delay(); + bit = MM_READ(MM_BT656_I2C) & BT656_I2C_SDAIN; + i2c_delay(); + MM_WRITE(MM_BT656_I2C, 0); + return bit; +} + +static void i2c_write_bit(unsigned int bit) +{ + if(bit) { + MM_WRITE(MM_BT656_I2C, BT656_I2C_SDAOE|BT656_I2C_SDAOUT); + } else { + MM_WRITE(MM_BT656_I2C, BT656_I2C_SDAOE); + } + i2c_delay(); + MM_WRITE(MM_BT656_I2C, MM_READ(MM_BT656_I2C) | BT656_I2C_SDC); + i2c_delay(); + MM_WRITE(MM_BT656_I2C, MM_READ(MM_BT656_I2C) & ~BT656_I2C_SDC); +} + +static int i2c_started; + +static void i2c_start_cond(void) +{ + if(i2c_started) { + /* set SDA to 1 */ + MM_WRITE(MM_BT656_I2C, BT656_I2C_SDAOE|BT656_I2C_SDAOUT); + i2c_delay(); + MM_WRITE(MM_BT656_I2C, MM_READ(MM_BT656_I2C) | BT656_I2C_SDC); + } + /* SCL is high, set SDA from 1 to 0 */ + MM_WRITE(MM_BT656_I2C, BT656_I2C_SDAOE|BT656_I2C_SDC); + i2c_delay(); + MM_WRITE(MM_BT656_I2C, BT656_I2C_SDAOE); + i2c_started = 1; +} + +static void i2c_stop_cond(void) +{ + /* set SDA to 0 */ + MM_WRITE(MM_BT656_I2C, BT656_I2C_SDAOE); + i2c_delay(); + /* Clock stretching */ + MM_WRITE(MM_BT656_I2C, BT656_I2C_SDAOE|BT656_I2C_SDC); + /* SCL is high, set SDA from 0 to 1 */ + MM_WRITE(MM_BT656_I2C, BT656_I2C_SDC); + i2c_delay(); + i2c_started = 0; +} + +static unsigned int i2c_write(unsigned char byte) +{ + unsigned int bit; + unsigned int ack; + + for(bit = 0; bit < 8; bit++) { + i2c_write_bit(byte & 0x80); + byte <<= 1; + } + ack = !i2c_read_bit(); + return ack; +} + +static unsigned char i2c_read(int ack) +{ + unsigned char byte = 0; + unsigned int bit; + + for(bit = 0; bit < 8; bit++) { + byte <<= 1; + byte |= i2c_read_bit(); + } + i2c_write_bit(!ack); + return byte; +} + +static unsigned char read_reg(unsigned char addr) +{ + unsigned char r; + + i2c_start_cond(); + i2c_write(0x40); + i2c_write(addr); + i2c_start_cond(); + i2c_write(0x41); + r = i2c_read(0); + i2c_stop_cond(); + + return r; +} + +static void write_reg(unsigned char addr, unsigned char val) +{ + i2c_start_cond(); + i2c_write(0x40); + i2c_write(addr); + i2c_write(val); + i2c_stop_cond(); +} + +static const char vreg_addr[] = { + 0x1d, 0xc3, 0xc4 +}; + +static const char vreg_dat[] = { + 0x40, 0x05, 0x80 +}; + +rtems_device_driver video_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + rtems_status_code sc; + rtems_isr_entry dummy; + int i; + + MM_WRITE(MM_BT656_I2C, BT656_I2C_SDC); + + sc = rtems_io_register_name(DEVICE_NAME, major, 0); + RTEMS_CHECK_SC(sc, "create video input device"); + + rtems_interrupt_catch(frame_handler, MM_IRQ_VIDEOIN, &dummy); + bsp_interrupt_vector_enable(MM_IRQ_VIDEOIN); + + for(i=0;i<sizeof(vreg_addr);i++) + write_reg(vreg_addr[i], vreg_dat[i]); + + return RTEMS_SUCCESSFUL; +} + +rtems_device_driver video_open( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + int i; + int status; + + for(i=0;i<N_BUFFERS;i++) { + status = posix_memalign(&buffers[i], 32, 2*FRAME_W*FRAME_H); + if(status != 0) { + i--; + while(i > 0) { + free(buffers[i]); + i--; + } + return RTEMS_UNSATISFIED; + } + } + + last_buffer = -1; + current_buffer = 0; + + MM_WRITE(MM_BT656_BASE, (unsigned int)buffers[current_buffer]); + MM_WRITE(MM_BT656_FILTERSTATUS, BT656_FILTER_FIELD1); + + return RTEMS_SUCCESSFUL; +} + +rtems_device_driver video_close( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + int i; + + MM_WRITE(MM_BT656_FILTERSTATUS, 0); + while(MM_READ(MM_BT656_FILTERSTATUS) & BT656_FILTER_INFRAME); + for(i=0;i<N_BUFFERS;i++) + free(buffers[i]); + return RTEMS_SUCCESSFUL; +} + +static void invalidate_caches(void) +{ + volatile char *flushbase = (char *)FMLBRG_FLUSH_BASE; + int i, offset; + + offset = 0; + for (i=0;i<FMLBRG_LINE_COUNT;i++) { + flushbase[offset] = 0; + offset += FMLBRG_LINE_LENGTH; + } + __asm__ volatile( /* Invalidate Level-1 data cache */ + "wcsr DCC, r0\n" + "nop\n" + ); +} + +rtems_device_driver video_control( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + rtems_libio_ioctl_args_t *args = arg; + unsigned int *a = (unsigned int *)args->buffer; + rtems_status_code sc; + + switch (args->command) { + case VIDEO_BUFFER_LOCK: + if (last_buffer == -1) { + *a = 0; + } else { + bsp_interrupt_vector_disable(MM_IRQ_VIDEOIN); + if(*a) invalidate_caches(); + *a = (unsigned int)buffers[last_buffer]; + buffers_locked[last_buffer] = true; + bsp_interrupt_vector_enable(MM_IRQ_VIDEOIN); + } + sc = RTEMS_SUCCESSFUL; + break; + case VIDEO_BUFFER_UNLOCK: { + int i; + for(i=0;i<N_BUFFERS;i++) { + if ((unsigned int)buffers[i] == (unsigned int)a) { + buffers_locked[i] = false; + break; + } + } + sc = RTEMS_SUCCESSFUL; + break; + } + + case VIDEO_SET_BRIGHTNESS: + write_reg(0x0a, (unsigned int)a); + sc = RTEMS_SUCCESSFUL; + break; + case VIDEO_GET_BRIGHTNESS: + *a = read_reg(0x0a); + sc = RTEMS_SUCCESSFUL; + break; + case VIDEO_SET_CONTRAST: + write_reg(0x08, (unsigned int)a); + sc = RTEMS_SUCCESSFUL; + break; + case VIDEO_GET_CONTRAST: + *a = read_reg(0x08); + sc = RTEMS_SUCCESSFUL; + break; + case VIDEO_SET_HUE: + write_reg(0x0b, (unsigned int)a); + sc = RTEMS_SUCCESSFUL; + break; + case VIDEO_GET_HUE: + *a = read_reg(0x0b); + sc = RTEMS_SUCCESSFUL; + break; + + case VIDEO_GET_SIGNAL: + *a = read_reg(0x10); + sc = RTEMS_SUCCESSFUL; + break; + + case VIDEO_SET_REGISTER: + write_reg(((unsigned int )a & 0xffff0000) >> 16, + (unsigned int)a & 0x0000ffff); + sc = RTEMS_SUCCESSFUL; + break; + case VIDEO_GET_REGISTER: + *a = read_reg(*a); + sc = RTEMS_SUCCESSFUL; + break; + + default: + sc = RTEMS_UNSATISFIED; + break; + } + + if (sc == RTEMS_SUCCESSFUL) + args->ioctl_return = 0; + else + args->ioctl_return = -1; + + return sc; +} diff --git a/c/src/lib/libbsp/lm32/shared/start/start.S b/c/src/lib/libbsp/lm32/shared/start/start.S index e155852b37..cd5cbe02ba 100644 --- a/c/src/lib/libbsp/lm32/shared/start/start.S +++ b/c/src/lib/libbsp/lm32/shared/start/start.S @@ -145,24 +145,18 @@ crt0: bi .clear_bss .end_clear_bss: mvi r1, 0 + be r4, r0, .no_rescue + mvhi r1, hi(.rescue_str) + ori r1, r1, lo(.rescue_str) +.no_rescue: mvhi r7, hi(boot_card) ori r7, r7, lo(boot_card) call r7 # boot_card returns when RTEMS is shutdown -#if ON_SIMULATOR - #if defined(ON_GDB_SIM) - #define SYS_exit 1 - mvi r8, SYS_exit - scall - #else - # on qemu-lm32 - #define SYS_CTRL_REG 0xffff0000 - mvhi r7, hi(SYS_CTRL_REG) - ori r7, r7, lo(SYS_CTRL_REG) - sw (r7+0), r0 - #endif -#endif - .dead_end: bi .dead_end +.section .rodata +.rescue_str: + .ascii "rescue" + diff --git a/c/src/lib/libbsp/lm32/shared/startup/bspstart.c b/c/src/lib/libbsp/lm32/shared/startup/bspstart.c index 770d8d81b4..e2b118a73d 100644 --- a/c/src/lib/libbsp/lm32/shared/startup/bspstart.c +++ b/c/src/lib/libbsp/lm32/shared/startup/bspstart.c @@ -35,10 +35,9 @@ * This routine does the bulk of the system initialization. */ -void bsp_start( void ) +void bsp_start(void) { - /* Setup console baud rate which we derive from - Mico System Builder (MSB) generated system_conf.h */ + /* Setup console baud rate */ BSP_uart_init(UART_BAUD_RATE); } |