From 9bf3483559c2d223f4833173d803225bf1ca24df Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Fri, 20 Aug 2010 21:23:27 +0000 Subject: 2010-08-20 * shared/milkymist_ac97/ac97.c, shared/milkymist_clock/ckinit.c, shared/milkymist_clock/clock.h, shared/milkymist_console/console.c, shared/milkymist_console/uart.c, shared/milkymist_console/uart.h, shared/milkymist_framebuffer/framebuffer.c, shared/milkymist_gpio/gpio.c, shared/milkymist_networking/mm_crc32.c, shared/milkymist_networking/network.c, shared/milkymist_networking/network.h, shared/milkymist_timer/timer.c: New files. --- c/src/lib/libbsp/lm32/ChangeLog | 11 + c/src/lib/libbsp/lm32/shared/milkymist_ac97/ac97.c | 119 ++++++ .../libbsp/lm32/shared/milkymist_clock/ckinit.c | 70 ++++ .../lib/libbsp/lm32/shared/milkymist_clock/clock.h | 18 + .../libbsp/lm32/shared/milkymist_console/console.c | 226 ++++++++++++ .../libbsp/lm32/shared/milkymist_console/uart.c | 69 ++++ .../libbsp/lm32/shared/milkymist_console/uart.h | 26 ++ .../shared/milkymist_framebuffer/framebuffer.c | 244 +++++++++++++ c/src/lib/libbsp/lm32/shared/milkymist_gpio/gpio.c | 191 ++++++++++ .../lm32/shared/milkymist_networking/mm_crc32.c | 82 +++++ .../lm32/shared/milkymist_networking/network.c | 401 +++++++++++++++++++++ .../lm32/shared/milkymist_networking/network.h | 80 ++++ .../lib/libbsp/lm32/shared/milkymist_timer/timer.c | 88 +++++ 13 files changed, 1625 insertions(+) create mode 100644 c/src/lib/libbsp/lm32/shared/milkymist_ac97/ac97.c create mode 100644 c/src/lib/libbsp/lm32/shared/milkymist_clock/ckinit.c create mode 100644 c/src/lib/libbsp/lm32/shared/milkymist_clock/clock.h create mode 100644 c/src/lib/libbsp/lm32/shared/milkymist_console/console.c create mode 100644 c/src/lib/libbsp/lm32/shared/milkymist_console/uart.c create mode 100644 c/src/lib/libbsp/lm32/shared/milkymist_console/uart.h create mode 100644 c/src/lib/libbsp/lm32/shared/milkymist_framebuffer/framebuffer.c create mode 100644 c/src/lib/libbsp/lm32/shared/milkymist_gpio/gpio.c create mode 100644 c/src/lib/libbsp/lm32/shared/milkymist_networking/mm_crc32.c create mode 100644 c/src/lib/libbsp/lm32/shared/milkymist_networking/network.c create mode 100644 c/src/lib/libbsp/lm32/shared/milkymist_networking/network.h create mode 100644 c/src/lib/libbsp/lm32/shared/milkymist_timer/timer.c diff --git a/c/src/lib/libbsp/lm32/ChangeLog b/c/src/lib/libbsp/lm32/ChangeLog index 7d60877be8..4f6ea6c28b 100644 --- a/c/src/lib/libbsp/lm32/ChangeLog +++ b/c/src/lib/libbsp/lm32/ChangeLog @@ -1,3 +1,14 @@ +2010-08-20 + + * shared/milkymist_ac97/ac97.c, shared/milkymist_clock/ckinit.c, + shared/milkymist_clock/clock.h, shared/milkymist_console/console.c, + shared/milkymist_console/uart.c, shared/milkymist_console/uart.h, + shared/milkymist_framebuffer/framebuffer.c, + shared/milkymist_gpio/gpio.c, shared/milkymist_networking/mm_crc32.c, + shared/milkymist_networking/network.c, + shared/milkymist_networking/network.h, + shared/milkymist_timer/timer.c: New files. + 2010-08-20 * acinclude.m4, configure.ac: Add Milkymist BSP developed as part of diff --git a/c/src/lib/libbsp/lm32/shared/milkymist_ac97/ac97.c b/c/src/lib/libbsp/lm32/shared/milkymist_ac97/ac97.c new file mode 100644 index 0000000000..671d4f165b --- /dev/null +++ b/c/src/lib/libbsp/lm32/shared/milkymist_ac97/ac97.c @@ -0,0 +1,119 @@ +/* ac97.c + * + * This file is the sound driver for the Milkymist One board + * It does an OSS style character device in /dev/snd + * + * 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) Yann Sionneau (GSoC 2010) + * Telecom SudParis + */ + +#include +#include +#include +#include +#include +#include +#include +#include "../include/system_conf.h" +#include + +#define GPIO_DRIVER_TABLE_ENTRY { ac97_initialize, \ +ac97_open, ac97_close, ac97_read, ac97_write, ac97_control} + +#define SND_DEVICE_NAME "/dev/snd" + +static struct milkymist_ac97 { + rtems_device_minor_number minor; + pthread_mutex_t mutex; +} ac97_driver; + +rtems_device_driver gpio_initialize( +rtems_device_major_number major, +rtems_device_minor_number minor, +void *arg) +{ + rtems_status_code status; + + printk( "ac97 driver initializing..\n" ); + + 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; + + return RTEMS_SUCCESSFUL; +} + +rtems_device_driver gpio_close( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + if (pthread_mutex_unlock(&ac97_driver.mutex) == 0){ + return RTEMS_SUCCESSFUL; + } + return RTEMS_UNSATISFIED; +} + +rtems_device_driver gpio_open( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + if (pthread_mutex_trylock(&ac97_driver.mutex) == 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; + + return RTEMS_SUCCESSFUL; +} + +rtems_device_driver gpio_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; + + return RTEMS_SUCCESSFUL; +} + +rtems_device_driver gpio_control( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + rtems_libio_ioctl_args_t *args = arg; + + switch( args->command ) { + default: + args->ioctl_return = 0; + break; + } + return RTEMS_SUCCESSFUL; +} + diff --git a/c/src/lib/libbsp/lm32/shared/milkymist_clock/ckinit.c b/c/src/lib/libbsp/lm32/shared/milkymist_clock/ckinit.c new file mode 100644 index 0000000000..eb28ead0cc --- /dev/null +++ b/c/src/lib/libbsp/lm32/shared/milkymist_clock/ckinit.c @@ -0,0 +1,70 @@ +/* ckinit.c + * + * Clock device driver for Lattice Mico32 (lm32). + * + * 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) Yann Sionneau (GSoC 2010) + * Telecom SudParis + */ + +#include +#include "../include/system_conf.h" +#include "clock.h" +#include "bspopts.h" + +#if ON_SIMULATOR +#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); \ + } while (0) + +#define Clock_driver_support_install_isr(_new, _old ) \ + do { \ + _old = (rtems_isr_entry) set_vector( _new, CLOCK_VECTOR, 1 ); \ + } 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); +} + +void Clock_driver_support_shutdown_hardware(void) +{ + lm32_interrupt_mask(CLOCK_IRQMASK); + clockwrite(MM_TIMER0_CONTROL, 0); +} + +#include "../../../shared/clockdrv_shell.h" + diff --git a/c/src/lib/libbsp/lm32/shared/milkymist_clock/clock.h b/c/src/lib/libbsp/lm32/shared/milkymist_clock/clock.h new file mode 100644 index 0000000000..c4db361804 --- /dev/null +++ b/c/src/lib/libbsp/lm32/shared/milkymist_clock/clock.h @@ -0,0 +1,18 @@ +/* + * This file contains definitions for LatticeMico32 Timer (Clock) + * + * 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) Yann Sionneau (GSoC 2010) + * Telecom SudParis + */ + +#ifndef _BSPCLOCK_H +#define _BSPCLOCK_H + + +#endif /* _BSPCLOCK_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 new file mode 100644 index 0000000000..05ac7803df --- /dev/null +++ b/c/src/lib/libbsp/lm32/shared/milkymist_console/console.c @@ -0,0 +1,226 @@ +/* + * Console driver for Lattice Mico32 (lm32). + * + * 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$ + * + * Jukka Pietarinen , 2008, + * Micro-Research Finland Oy + * + * COPYRIGHT (c) Yann Sionneau , GSoc 2010 + * Telecom SudParis + */ + +#define NO_BSP_INIT + +#include +#include +#include + +void BSP_uart_polled_write(char ch); +int BSP_uart_polled_read( void ); +char BSP_uart_is_character_ready(char *ch); + +/* console_initialize + * + * This routine initializes the console IO driver. + * + * Input parameters: NONE + * + * Output parameters: NONE + * + * Return values: + */ + +rtems_device_driver console_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + rtems_status_code status; + + printk("console_initialize\n"); + + status = rtems_io_register_name( + "/dev/console", + major, + (rtems_device_minor_number) 0 + ); + + if (status != RTEMS_SUCCESSFUL) + rtems_fatal_error_occurred(status); + + return RTEMS_SUCCESSFUL; +} + +/* is_character_ready + * + * This routine returns TRUE if a character is available. + * + * Input parameters: NONE + * + * Output parameters: NONE + * + * Return values: + */ + +bool is_character_ready( + char *ch +) +{ + return BSP_uart_is_character_ready(ch); +} + +/* inbyte + * + * This routine reads a character from the SOURCE. + * + * Input parameters: NONE + * + * Output parameters: NONE + * + * Return values: + * character read from SOURCE + */ + +int inbyte( void ) +{ + /* + * If polling, wait until a character is available. + */ + + return BSP_uart_polled_read(); +} + +/* 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 + */ + +void outbyte( + char ch +) +{ + /* + * If polling, wait for the transmitter to be ready. + * Check for flow control requests and process. + * Then output the character. + */ + + BSP_uart_polled_write(ch); +} + +/* + * Open entry point + */ + +rtems_device_driver console_open( + rtems_device_major_number major, + rtems_device_minor_number minor, + void * arg +) +{ + return RTEMS_SUCCESSFUL; +} + +/* + * Close entry point + */ + +rtems_device_driver console_close( + rtems_device_major_number major, + rtems_device_minor_number minor, + void * arg +) +{ + return RTEMS_SUCCESSFUL; +} + +/* + * 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 +) +{ + 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; +} + +/* + * 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 +) +{ + 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; +} + +/* + * IO Control entry point + */ + +rtems_device_driver console_control( + rtems_device_major_number major, + rtems_device_minor_number minor, + void * arg +) +{ + return RTEMS_SUCCESSFUL; +} + +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 new file mode 100644 index 0000000000..229ee40985 --- /dev/null +++ b/c/src/lib/libbsp/lm32/shared/milkymist_console/uart.c @@ -0,0 +1,69 @@ +/* + * Uart driver for Lattice Mico32 (lm32) UART + * + * 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) Yann Sionneau (GSoC 2010) + * Telecom SudParis + */ + +#include "../include/system_conf.h" +#include "uart.h" +#include + +static inline int uartread(unsigned int reg) +{ + return *((int*)(reg)); +} + +static inline void uartwrite(unsigned int reg, int value) +{ + *((int*)(reg)) = value; +} + +void BSP_uart_init(int baud) +{ + + /* Set baud rate */ + uartwrite(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); + do { + lm32_read_interrupts(ip); + } while (! (ip & MM_IRQ_UARTTX) ); + lm32_interrupt_ack(MM_IRQ_UARTTX); +} + +char BSP_uart_polled_read( void ) +{ + int ip; + /* Wait until there is a byte in RBR */ + do { + lm32_read_interrupts(ip); + } while(! (ip & MM_IRQ_UARTRX) ); + lm32_interrupt_ack(MM_IRQ_UARTRX); + return (char) uartread(MM_UART_RXTX); +} + +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; +} diff --git a/c/src/lib/libbsp/lm32/shared/milkymist_console/uart.h b/c/src/lib/libbsp/lm32/shared/milkymist_console/uart.h new file mode 100644 index 0000000000..1aded4231d --- /dev/null +++ b/c/src/lib/libbsp/lm32/shared/milkymist_console/uart.h @@ -0,0 +1,26 @@ +/* + * This file contains definitions for LatticeMico32 UART + * + * 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) Yann Sionneau (GSoC 2010) + * Telecom SudParis + */ + +#ifndef _BSPUART_H +#define _BSPUART_H + +void BSP_uart_init(int baud); + +#define MM_UART_RXTX (0xe0000000) + +#define MM_UART_DIV (0xe0000004) + +#define MM_IRQ_UARTTX (0x00000010) /* 4 */ +#define MM_IRQ_UARTRX (0x00000008) /* 3 */ + +#endif /* _BSPUART_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 new file mode 100644 index 0000000000..2fbb9c0eca --- /dev/null +++ b/c/src/lib/libbsp/lm32/shared/milkymist_framebuffer/framebuffer.c @@ -0,0 +1,244 @@ +/* framebuffer.c + * + * This file is the framebuffer driver for the Milkymist VGA IP-core + * This VGA Core is a part of Milkymist System-on-Chip + * + * 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) Yann Sionneau (GSoC 2010) + * Telecom SudParis + */ + +#include +#include +#include +#include +#include +#include +#include +#include "../include/system_conf.h" +#include +#include + +#define FRAMEBUFFER_DEVICE_NAME "/dev/fb" + +pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + +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 = 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 = +{ + .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 int get_fix_screen_info( struct fb_fix_screeninfo *info ) +{ + *info = fb_fix; + return 0; +} + +static int get_var_screen_info( struct fb_var_screeninfo *info ) +{ + *info = fb_var; + return 0; +} + + +rtems_device_driver frame_buffer_initialize( +rtems_device_major_number major, +rtems_device_minor_number minor, +void *arg) +{ + rtems_status_code status; + + printk( "frame buffer driver initializing..\n" ); + + fb_fix.smem_start = (volatile char *)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) + { + 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, + 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; +} + +rtems_device_driver frame_buffer_open( + 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); +} + +rtems_device_driver frame_buffer_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 = ((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_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); + return RTEMS_SUCCESSFUL; +} + +rtems_device_driver frame_buffer_control( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + rtems_libio_ioctl_args_t *args = arg; + + switch( args->command ) { + case FBIOGET_FSCREENINFO: + args->ioctl_return = get_fix_screen_info( ( struct fb_fix_screeninfo * ) args->buffer ); + break; + 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; + case FBIOSWAPBUFFERS: + vga_swap_buffers(); + args->ioctl_return = 0; + break; + case FBIOSETBUFFERMODE: + args->ioctl_return = 0; + switch ( (unsigned int)args->buffer ) { + case FB_SINGLE_BUFFERED: + fb_fix.smem_start = (volatile char *)frontbuffer; + break; + case FB_TRIPLE_BUFFERED: + fb_fix.smem_start = (volatile char *)backbuffer; + break; + default: + printk("[framebuffer] : error no such buffer mode\n"); + } + break; + default: + args->ioctl_return = 0; + break; + } + 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 new file mode 100644 index 0000000000..430d36514c --- /dev/null +++ b/c/src/lib/libbsp/lm32/shared/milkymist_gpio/gpio.c @@ -0,0 +1,191 @@ +/* gpio.c + * + * This file is the 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 + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + * + * COPYRIGHT (c) Yann Sionneau (GSoC 2010) + * Telecom SudParis + */ + +#include +#include +#include +#include +#include +#include +#include +#include "../include/system_conf.h" +#include + +#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" + +static struct milkymist_gpio { + rtems_device_minor_number minor; + unsigned int *address; + unsigned int offset; + uint8_t readonly; + pthread_mutex_t mutex; +} gpio[5]; + +rtems_device_driver gpio_initialize( +rtems_device_major_number major, +rtems_device_minor_number minor, +void *arg) +{ + rtems_status_code status; + + 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 ); + } + + 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, + void *arg +) +{ + if (pthread_mutex_unlock(&gpio[minor].mutex) == 0){ + return RTEMS_SUCCESSFUL; + } + return RTEMS_UNSATISFIED; +} + +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){ + 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; + else + *(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 +) +{ + rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *)arg; + rw_args->bytes_moved = 1; + + if (gpio[minor].readonly) + return RTEMS_UNSATISFIED; + + if ( *(uint8_t *)rw_args->buffer ) + *gpio[minor].address |= gpio[minor].offset; + else + *gpio[minor].address &= ~gpio[minor].offset; + + return RTEMS_SUCCESSFUL; +} + +rtems_device_driver gpio_control( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + rtems_libio_ioctl_args_t *args = arg; + + switch( args->command ) { + default: + args->ioctl_return = 0; + break; + } + return RTEMS_SUCCESSFUL; +} + diff --git a/c/src/lib/libbsp/lm32/shared/milkymist_networking/mm_crc32.c b/c/src/lib/libbsp/lm32/shared/milkymist_networking/mm_crc32.c new file mode 100644 index 0000000000..6489c005d9 --- /dev/null +++ b/c/src/lib/libbsp/lm32/shared/milkymist_networking/mm_crc32.c @@ -0,0 +1,82 @@ +/* crc32.c -- compute the CRC-32 of a data stream + * COPYRIGHT (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * $Id$ + * + */ + +const unsigned int crc_table[256] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL +}; + +#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); +#define DO2(buf) DO1(buf); DO1(buf); +#define DO4(buf) DO2(buf); DO2(buf); +#define DO8(buf) DO4(buf); DO4(buf); + +unsigned int mm_ether_crc32(const unsigned char *buffer, unsigned int len) +{ + unsigned int crc; + crc = 0; + crc = crc ^ 0xffffffffL; + while(len >= 8) { + DO8(buffer); + len -= 8; + } + if(len) do { + DO1(buffer); + } while(--len); + return crc ^ 0xffffffffL; +} diff --git a/c/src/lib/libbsp/lm32/shared/milkymist_networking/network.c b/c/src/lib/libbsp/lm32/shared/milkymist_networking/network.c new file mode 100644 index 0000000000..9899777d1b --- /dev/null +++ b/c/src/lib/libbsp/lm32/shared/milkymist_networking/network.c @@ -0,0 +1,401 @@ +/* + * RTEMS driver for Minimac 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 + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + * + * COPYRIGHT (c) Yann Sionneau (GSoC 2010) + * Telecom SudParis, France + */ + + +#include +#include "../include/system_conf.h" +#include "bspopts.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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; + +static uint32_t rx_slot_state[4] = {MM_MINIMAC_STATE0, MM_MINIMAC_STATE1, + MM_MINIMAC_STATE2, MM_MINIMAC_STATE3}; + +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 + */ + +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 inline int minimac_read(unsigned int reg) +{ + return *((int*)(reg)); +} + +static inline void minimac_write(unsigned int reg, int value) +{ + *((int*)reg) = value; +} + +int rtems_minimac_driver_attach (struct rtems_bsdnet_ifconfig *config, + int attaching) +{ + struct minimac_softc *sc; + struct ifnet *ifp; + + + if (!attaching) { + printk ("MINIMAC driver cannot be detached.\n"); + return 0; + } + + sc = &minimac_softc; + ifp = &(sc->arpcom.ac_if); + + if (sc->registered) { + printk ("Driver already in use.\n"); + return 0; + } + + 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; + ifp->if_mtu = ETHERMTU; + ifp->if_unit = 0; + ifp->if_name = "minimac"; + ifp->if_init = minimac_init; + ifp->if_ioctl = minimac_ioctl; + ifp->if_start = minimac_start; + ifp->if_output = ether_output; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; + ifp->if_snd.ifq_maxlen = ifqmaxlen; + + if_attach (ifp); + ether_ifattach(ifp); + printk("[minimac] Ethernet driver attached\n"); + return 1; +} + +static void minimac_start(struct ifnet *ifp) +{ + struct minimac_softc *sc = ifp->if_softc; + rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT); + ifp->if_flags |= IFF_OACTIVE; +// printk("[minimac] start();\n"); +} + +/* + * Initialize and start the device + */ +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. + */ + 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) +{ + struct ifnet *ifp = &sc->arpcom.ac_if; + unsigned char j; + 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) +{ + + 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; + + /* + * FIXME: All sorts of multicast commands need to be added here! + */ + default: + error = EINVAL; + break; + } + return error; + + +} + +rtems_isr minimac_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 + } +} + +rtems_isr minimac_tx_interrupt_handler(rtems_vector_number vector) +{ + 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 + } +} + + +static void minimac_rxDaemon(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 + } + + 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); + } + } + 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); + } + ifp->if_flags &= ~IFF_OACTIVE; + } +} + +static void minimac_stats(struct minimac_softc *sc) +{ + +} + + +static void minimac_sendpacket(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 crc; + uint8_t i; + for (i = 0 ; i < 7 ; i++) // Preamble + p.preamble[i] = 0x55; + p.preamble[7] = 0xd5; + + 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; + } + + } while ( (nm = nm->m_next) != 0 ); + for ( ; len < 60 ; len++) + p.raw_data[len] = 0x00; // Padding + + crc = mm_ether_crc32((uint8_t *)p.raw_data, len); // CRC32 + + 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 + + if (len + 8 < 64) { + printk("[minimac] Packet is too small !\n"); + sc->txErrors++; // update stats + return; + } + + minimac_write(MM_MINIMAC_TXADR, (unsigned int)&p); + minimac_write(MM_MINIMAC_TXREMAINING, (unsigned int)(len + 8)); +} diff --git a/c/src/lib/libbsp/lm32/shared/milkymist_networking/network.h b/c/src/lib/libbsp/lm32/shared/milkymist_networking/network.h new file mode 100644 index 0000000000..6d967c5b6c --- /dev/null +++ b/c/src/lib/libbsp/lm32/shared/milkymist_networking/network.h @@ -0,0 +1,80 @@ +/* network.h + * + * RTEMS driver for Minimac 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 + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + * + * COPYRIGHT (c) Yann Sionneau (GSoC 2010) + * Telecom SudParis, France + */ + + +#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; +}; + +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_timer/timer.c b/c/src/lib/libbsp/lm32/shared/milkymist_timer/timer.c new file mode 100644 index 0000000000..d1af0dd382 --- /dev/null +++ b/c/src/lib/libbsp/lm32/shared/milkymist_timer/timer.c @@ -0,0 +1,88 @@ +/* timer.c + * + * This file manages the benchmark timer used by the RTEMS Timing + * Test Suite. Each measured time period is demarcated by calls to + * benchmark_timer_initialize() and benchmark_timer_read(). + * benchmark_timer_read() usually returns the number of microseconds + * since benchmark_timer_initialize() exitted. + * + * NOTE: It is important that the timer start/stop overhead be + * determined when porting or modifying this code. + * + * 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) Yann Sionneau (GSoC 2010) + * Telecom SudParis + */ + +#include +#include +#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 ) +{ + timerwrite(MM_TIMER1_COMPARE, 0xffffffff); + timerwrite(MM_TIMER1_COUNTER, 0); + timerwrite(MM_TIMER1_CONTROL, TIMER_ENABLE); +} + +/* + * The following controls the behavior of benchmark_timer_read(). + * + * AVG_OVEREHAD is the overhead for starting and stopping the timer. It + * is usually deducted from the number returned. + * + * LEAST_VALID is the lowest number this routine should trust. Numbers + * below this are "noise" and zero is returned. + */ + +#define AVG_OVERHEAD 4 /* It typically takes X.X microseconds */ + /* (Y countdowns) to start/stop the timer. */ + /* This value is in microseconds. */ +#define LEAST_VALID 4 /* Don't trust a clicks value lower than this */ + +int benchmark_timer_read( void ) +{ + uint32_t ticks; + uint32_t total; + ticks = timerread(MM_TIMER1_COUNTER); + if (ticks == 0xffffffff) + printk("Timer overflow!\n"); + + total = ticks / (CPU_FREQUENCY / 1000000); + + if ( benchmark_timer_find_average_overhead == true ) + return total; + else + { + if ( total < LEAST_VALID ) + return 0; + + return (total - AVG_OVERHEAD); + + } +} + +void benchmark_timer_disable_subtracting_average_overhead( + bool find_flag +) +{ + benchmark_timer_find_average_overhead = find_flag; +} -- cgit v1.2.3