Line 32... |
Line 32... |
#include "gpio_i.h"
|
#include "gpio_i.h"
|
#include "sim-config.h"
|
#include "sim-config.h"
|
#include "pic.h"
|
#include "pic.h"
|
#include "vapi.h"
|
#include "vapi.h"
|
#include "debug.h"
|
#include "debug.h"
|
|
#include "sched.h"
|
static struct gpio_device gpios[MAX_GPIOS];
|
|
|
|
static void gpio_vapi_read( unsigned long id, unsigned long data, void *dat );
|
static void gpio_vapi_read( unsigned long id, unsigned long data, void *dat );
|
static uint32_t gpio_read32( oraddr_t addr, void *dat );
|
static uint32_t gpio_read32( oraddr_t addr, void *dat );
|
static void gpio_write32( oraddr_t addr, uint32_t value, void *dat );
|
static void gpio_write32( oraddr_t addr, uint32_t value, void *dat );
|
|
|
static void gpio_external_clock( unsigned long value );
|
static void gpio_external_clock( unsigned long value, struct gpio_device *gpio );
|
static void gpio_device_clock( struct gpio_device *gpio );
|
static void gpio_device_clock( struct gpio_device *gpio );
|
static int gpio_find_device( oraddr_t addr, struct gpio_device **gpio, oraddr_t *reladdr );
|
|
static struct gpio_device *gpio_find_vapi_device( unsigned long id, unsigned *which_vapi );
|
|
|
|
/* Initialize all parameters and state */
|
/* Initialize all parameters and state */
|
void gpio_reset( void )
|
void gpio_reset( void *dat )
|
{
|
{
|
static int first_time = 1;
|
struct gpio_device *gpio = dat;
|
unsigned i;
|
|
|
|
if ( first_time ) {
|
|
memset( gpios, 0, sizeof(gpios) );
|
|
first_time = 0;
|
|
}
|
|
|
|
for ( i = 0; i < config.ngpios; ++ i ) {
|
|
struct gpio_device *gpio = &(gpios[i]);
|
|
|
|
gpio->gpio_number = i;
|
|
gpio->baseaddr = config.gpios[i].baseaddr;
|
|
|
|
if ( gpio->baseaddr != 0 ) {
|
if ( gpio->baseaddr != 0 ) {
|
/* Get IRQ */
|
|
gpio->irq = config.gpios[i].irq;
|
|
|
|
/* Register memory range */
|
|
register_memoryarea( gpio->baseaddr, GPIO_ADDR_SPACE, 4, 0, gpio_read32, gpio_write32, NULL );
|
|
|
|
/* Possibly connect to VAPI */
|
/* Possibly connect to VAPI */
|
if ( config.gpios[i].base_vapi_id ) {
|
if ( gpio->base_vapi_id ) {
|
gpio->base_vapi_id = config.gpios[i].base_vapi_id;
|
vapi_install_multi_handler( gpio->base_vapi_id, GPIO_NUM_VAPI_IDS, gpio_vapi_read, dat );
|
vapi_install_multi_handler( gpio->base_vapi_id, GPIO_NUM_VAPI_IDS, gpio_vapi_read, NULL );
|
|
}
|
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
|
|
/* Dump status */
|
/* Dump status */
|
void gpio_status( void )
|
void gpio_status( void *dat )
|
{
|
{
|
unsigned i;
|
struct gpio_device *gpio = dat;
|
|
|
for ( i = 0; i < config.ngpios; ++ i ) {
|
|
struct gpio_device *gpio = &(gpios[i]);
|
|
|
|
if ( gpio->baseaddr == 0 )
|
if ( gpio->baseaddr == 0 )
|
continue;
|
return;
|
|
|
PRINTF( "\nGPIO %u at 0x%"PRIxADDR":\n", i, gpio->baseaddr );
|
PRINTF( "\nGPIO at 0x%"PRIxADDR":\n", gpio->baseaddr );
|
PRINTF( "RGPIO_IN : 0x%08lX\n", gpio->curr.in );
|
PRINTF( "RGPIO_IN : 0x%08lX\n", gpio->curr.in );
|
PRINTF( "RGPIO_OUT : 0x%08lX\n", gpio->curr.out );
|
PRINTF( "RGPIO_OUT : 0x%08lX\n", gpio->curr.out );
|
PRINTF( "RGPIO_OE : 0x%08lX\n", gpio->curr.oe );
|
PRINTF( "RGPIO_OE : 0x%08lX\n", gpio->curr.oe );
|
PRINTF( "RGPIO_INTE : 0x%08lX\n", gpio->curr.inte );
|
PRINTF( "RGPIO_INTE : 0x%08lX\n", gpio->curr.inte );
|
PRINTF( "RGPIO_PTRIG : 0x%08lX\n", gpio->curr.ptrig );
|
PRINTF( "RGPIO_PTRIG : 0x%08lX\n", gpio->curr.ptrig );
|
PRINTF( "RGPIO_AUX : 0x%08lX\n", gpio->curr.aux );
|
PRINTF( "RGPIO_AUX : 0x%08lX\n", gpio->curr.aux );
|
PRINTF( "RGPIO_CTRL : 0x%08lX\n", gpio->curr.ctrl );
|
PRINTF( "RGPIO_CTRL : 0x%08lX\n", gpio->curr.ctrl );
|
PRINTF( "RGPIO_INTS : 0x%08lX\n", gpio->curr.ints );
|
PRINTF( "RGPIO_INTS : 0x%08lX\n", gpio->curr.ints );
|
}
|
}
|
}
|
|
|
|
|
|
/* Convert a memory address to a device struct and relative address.
|
|
* Return nonzero on success */
|
|
int gpio_find_device( oraddr_t addr, struct gpio_device **gpio, oraddr_t *reladdr )
|
|
{
|
|
unsigned i;
|
|
*gpio = NULL;
|
|
|
|
for ( i = 0; i < config.ngpios && *gpio == NULL; ++ i ) {
|
|
if ( (addr >= gpios[i].baseaddr) && (addr < gpios[i].baseaddr + GPIO_ADDR_SPACE) )
|
|
*gpio = &(gpios[i]);
|
|
}
|
|
|
|
/* verify we found a device */
|
|
if ( *gpio == NULL )
|
|
return 0;
|
|
|
|
/* Verify legal address */
|
|
if ( (addr - (*gpio)->baseaddr) % 4 != 0 )
|
|
return 0;
|
|
|
|
*reladdr = addr - (*gpio)->baseaddr;
|
|
return 1;
|
|
}
|
|
|
|
|
|
/* Find device by vapi id */
|
|
struct gpio_device *gpio_find_vapi_device( unsigned long id, unsigned *which )
|
|
{
|
|
unsigned i;
|
|
|
|
for ( i = 0; i < config.ngpios; ++ i )
|
|
if ( (id >= gpios[i].base_vapi_id) && (id < gpios[i].base_vapi_id + GPIO_NUM_VAPI_IDS) ) {
|
|
*which = id - gpios[i].base_vapi_id;
|
|
return &(gpios[i]);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/* Wishbone read */
|
/* Wishbone read */
|
uint32_t gpio_read32( oraddr_t addr, void *dat )
|
uint32_t gpio_read32( oraddr_t addr, void *dat )
|
{
|
{
|
struct gpio_device *gpio;
|
struct gpio_device *gpio = dat;
|
if ( !gpio_find_device( addr, &gpio, &addr ) ) {
|
|
debug( 2, "gpio_read32( 0x%"PRIxADDR" ): Not in registered range(s)\n", addr );
|
addr -= gpio->baseaddr;
|
return 0;
|
|
}
|
|
|
|
switch( addr ) {
|
switch( addr ) {
|
case RGPIO_IN: return gpio->curr.in | gpio->curr.out;
|
case RGPIO_IN: return gpio->curr.in | gpio->curr.out;
|
case RGPIO_OUT: return gpio->curr.out;
|
case RGPIO_OUT: return gpio->curr.out;
|
case RGPIO_OE: return gpio->curr.oe;
|
case RGPIO_OE: return gpio->curr.oe;
|
Line 161... |
Line 92... |
case RGPIO_PTRIG: return gpio->curr.ptrig;
|
case RGPIO_PTRIG: return gpio->curr.ptrig;
|
case RGPIO_AUX: return gpio->curr.aux;
|
case RGPIO_AUX: return gpio->curr.aux;
|
case RGPIO_CTRL: return gpio->curr.ctrl;
|
case RGPIO_CTRL: return gpio->curr.ctrl;
|
case RGPIO_INTS: return gpio->curr.ints;
|
case RGPIO_INTS: return gpio->curr.ints;
|
}
|
}
|
|
|
|
return 0;
|
}
|
}
|
|
|
|
|
/* Wishbone write */
|
/* Wishbone write */
|
void gpio_write32( oraddr_t addr, uint32_t value, void *dat )
|
void gpio_write32( oraddr_t addr, uint32_t value, void *dat )
|
{
|
{
|
struct gpio_device *gpio;
|
struct gpio_device *gpio = dat;
|
if ( !gpio_find_device( addr, &gpio, &addr ) ) {
|
|
debug( 2, "gpio_write32( 0x%"PRIxADDR" ): Not in registered range(s)\n", addr );
|
addr -= gpio->baseaddr;
|
return;
|
|
}
|
|
|
|
switch( addr ) {
|
switch( addr ) {
|
case RGPIO_IN: debug( 5, "GPIO: Cannot write to RGPIO_IN\n" ); break;
|
case RGPIO_IN: debug( 5, "GPIO: Cannot write to RGPIO_IN\n" ); break;
|
case RGPIO_OUT: gpio->next.out = value; break;
|
case RGPIO_OUT: gpio->next.out = value; break;
|
case RGPIO_OE: gpio->next.oe = value; break;
|
case RGPIO_OE: gpio->next.oe = value; break;
|
Line 190... |
Line 121... |
|
|
/* Input from "outside world" */
|
/* Input from "outside world" */
|
void gpio_vapi_read( unsigned long id, unsigned long data, void *dat )
|
void gpio_vapi_read( unsigned long id, unsigned long data, void *dat )
|
{
|
{
|
unsigned which;
|
unsigned which;
|
struct gpio_device *gpio = gpio_find_vapi_device( id, &which );
|
struct gpio_device *gpio = dat;
|
|
|
debug( 5, "GPIO: id %08lx, data %08lx\n", id, data );
|
debug( 5, "GPIO: id %08lx, data %08lx\n", id, data );
|
|
|
if ( !gpio ) {
|
which = id - gpio->base_vapi_id;
|
debug( 1, "GPIO: VAPI ID %08lx is not ours!\n", id );
|
|
return;
|
|
}
|
|
|
|
switch( which ) {
|
switch( which ) {
|
case GPIO_VAPI_DATA:
|
case GPIO_VAPI_DATA:
|
debug( 4, "GPIO: Next input from VAPI = 0x%08lx (RGPIO_OE = 0x%08lx)\n",
|
debug( 4, "GPIO: Next input from VAPI = 0x%08lx (RGPIO_OE = 0x%08lx)\n",
|
data, gpio->next.oe );
|
data, gpio->next.oe );
|
Line 224... |
Line 152... |
break;
|
break;
|
case GPIO_VAPI_RGPIO_CTRL:
|
case GPIO_VAPI_RGPIO_CTRL:
|
gpio->next.ctrl = data;
|
gpio->next.ctrl = data;
|
break;
|
break;
|
case GPIO_VAPI_CLOCK:
|
case GPIO_VAPI_CLOCK:
|
gpio_external_clock( data );
|
gpio_external_clock( data, gpio );
|
break;
|
break;
|
}
|
}
|
}
|
|
|
|
/* System Clock. */
|
/* Clock the device */
|
void gpio_clock( void )
|
if ( !(gpio->curr.ctrl & RGPIO_CTRL_ECLK) )
|
{
|
gpio_device_clock( gpio );
|
unsigned i;
|
|
|
|
for ( i = 0; i < config.ngpios; ++ i )
|
|
if ( !(gpios[i].curr.ctrl & RGPIO_CTRL_ECLK) )
|
|
gpio_device_clock( &(gpios[i]) );
|
|
}
|
}
|
|
|
/* External Clock. */
|
/* External Clock. */
|
void gpio_external_clock( unsigned long value )
|
static void gpio_external_clock( unsigned long value, struct gpio_device *gpio )
|
{
|
{
|
unsigned i;
|
int use_external_clock = ((gpio->curr.ctrl & RGPIO_CTRL_ECLK) == RGPIO_CTRL_ECLK);
|
|
int negative_edge = ((gpio->curr.ctrl & RGPIO_CTRL_NEC) == RGPIO_CTRL_NEC);
|
|
|
/* "Normalize" clock value */
|
/* "Normalize" clock value */
|
value = (value != 0);
|
value = (value != 0);
|
|
|
for ( i = 0; i < config.ngpios; ++ i ) {
|
|
struct gpio_device *gpio = &(gpios[i]);
|
|
|
|
int use_external_clock = ((gpio->curr.ctrl & RGPIO_CTRL_ECLK) == RGPIO_CTRL_ECLK);
|
|
int negative_edge = ((gpio->curr.ctrl & RGPIO_CTRL_NEC) == RGPIO_CTRL_NEC);
|
|
|
|
gpio->next.external_clock = value;
|
gpio->next.external_clock = value;
|
|
|
if ( use_external_clock && (gpio->next.external_clock != gpio->curr.external_clock) && (value != negative_edge) )
|
if ( use_external_clock && (gpio->next.external_clock != gpio->curr.external_clock) && (value != negative_edge) )
|
|
/* Make sure that in vapi_read, we don't clock the device */
|
|
if ( gpio->curr.ctrl & RGPIO_CTRL_ECLK )
|
gpio_device_clock( gpio );
|
gpio_device_clock( gpio );
|
}
|
}
|
}
|
|
|
|
|
/* Report an interrupt to the sim */
|
|
void gpio_do_int( void *dat )
|
|
{
|
|
struct gpio_device *gpio = dat;
|
|
|
|
report_interrupt( gpio->irq );
|
|
}
|
|
|
/* Clock as handld by one device. */
|
/* Clock as handld by one device. */
|
void gpio_device_clock( struct gpio_device *gpio )
|
static void gpio_device_clock( struct gpio_device *gpio )
|
{
|
{
|
/* Calculate new inputs and outputs */
|
/* Calculate new inputs and outputs */
|
gpio->next.in &= ~gpio->next.oe; /* Only input bits */
|
gpio->next.in &= ~gpio->next.oe; /* Only input bits */
|
/* Replace requested output bits with aux input */
|
/* Replace requested output bits with aux input */
|
gpio->next.out = (gpio->next.out & ~gpio->next.aux) | (gpio->auxiliary_inputs & gpio->next.aux);
|
gpio->next.out = (gpio->next.out & ~gpio->next.aux) | (gpio->auxiliary_inputs & gpio->next.aux);
|
Line 290... |
Line 215... |
unsigned cleared_bits = changed_bits & gpio->curr.in; /* inputs that have been cleared */
|
unsigned cleared_bits = changed_bits & gpio->curr.in; /* inputs that have been cleared */
|
unsigned relevant_bits = (gpio->next.ptrig & set_bits) | (~gpio->next.ptrig & cleared_bits);
|
unsigned relevant_bits = (gpio->next.ptrig & set_bits) | (~gpio->next.ptrig & cleared_bits);
|
|
|
if ( relevant_bits & gpio->next.inte ) {
|
if ( relevant_bits & gpio->next.inte ) {
|
debug( 3, "GPIO: Reporting interrupt %d\n", gpio->irq );
|
debug( 3, "GPIO: Reporting interrupt %d\n", gpio->irq );
|
report_interrupt( gpio->irq );
|
|
gpio->next.ctrl |= RGPIO_CTRL_INTS;
|
gpio->next.ctrl |= RGPIO_CTRL_INTS;
|
gpio->next.ints |= relevant_bits & gpio->next.inte;
|
gpio->next.ints |= relevant_bits & gpio->next.inte;
|
|
/* Since we can't report an interrupt during a readmem/writemem
|
|
* schedule the scheduler to do it. Read the comment above
|
|
* report_interrupt in pic/pic.c */
|
|
SCHED_ADD( gpio_do_int, gpio, runtime.sim.cycles + 1 );
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
/* Switch to values for next clock */
|
/* Switch to values for next clock */
|
memcpy( &(gpio->curr), &(gpio->next), sizeof(gpio->curr) );
|
memcpy( &(gpio->curr), &(gpio->next), sizeof(gpio->curr) );
|
}
|
}
|
|
|
/*---------------------------------------------------[ GPIO configuration ]---*/
|
/*---------------------------------------------------[ GPIO configuration ]---*/
|
void gpio_ngpios(union param_val val, void *dat)
|
|
{
|
|
if (val.int_val >= 0 && val.int_val < MAX_GPIOS)
|
|
config.ngpios = val.int_val;
|
|
else
|
|
CONFIG_ERROR("invalid number of devices.");
|
|
}
|
|
|
|
void gpio_baseaddr(union param_val val, void *dat)
|
void gpio_baseaddr(union param_val val, void *dat)
|
{
|
{
|
if (current_device >= 0 && current_device < config.ngpios)
|
struct gpio_device *gpio = dat;
|
config.gpios[current_device].baseaddr = val.int_val;
|
gpio->baseaddr = val.addr_val;
|
else
|
|
CONFIG_ERROR("invalid device number.");
|
|
}
|
}
|
|
|
void gpio_irq(union param_val val, void *dat)
|
void gpio_irq(union param_val val, void *dat)
|
{
|
{
|
if (current_device >= 0 && current_device < config.ngpios)
|
struct gpio_device *gpio = dat;
|
config.gpios[current_device].irq = val.int_val;
|
gpio->irq = val.int_val;
|
else
|
|
CONFIG_ERROR("invalid device number.");
|
|
}
|
}
|
|
|
void gpio_base_vapi_id(union param_val val, void *dat)
|
void gpio_base_vapi_id(union param_val val, void *dat)
|
{
|
{
|
if (current_device >= 0 && current_device < config.ngpios)
|
struct gpio_device *gpio = dat;
|
config.gpios[current_device].base_vapi_id = val.int_val;
|
gpio->base_vapi_id = val.int_val;
|
else
|
}
|
CONFIG_ERROR("invalid device number.");
|
|
|
void *gpio_sec_start(void)
|
|
{
|
|
struct gpio_device *new = malloc(sizeof(struct gpio_device));
|
|
|
|
if(!new) {
|
|
fprintf(stderr, "Peripheral Test: Run out of memory\n");
|
|
exit(-1);
|
|
}
|
|
|
|
new->auxiliary_inputs = 0;
|
|
memset(&new->curr, 0, sizeof(new->curr));
|
|
memset(&new->next, 0, sizeof(new->next));
|
|
|
|
return new;
|
|
}
|
|
|
|
void gpio_sec_end(void *dat)
|
|
{
|
|
struct gpio_device *gpio = dat;
|
|
|
|
/* Register memory range */
|
|
register_memoryarea( gpio->baseaddr, GPIO_ADDR_SPACE, 4, 0, gpio_read32, gpio_write32, dat );
|
|
|
|
reg_sim_reset(gpio_reset, dat);
|
|
reg_sim_stat(gpio_status, dat);
|
}
|
}
|
|
|
void reg_gpio_sec(void)
|
void reg_gpio_sec(void)
|
{
|
{
|
struct config_section *sec = reg_config_sec("gpio", NULL, NULL);
|
struct config_section *sec = reg_config_sec("gpio", NULL, NULL);
|
|
|
reg_config_param(sec, "ngpios", paramt_int, gpio_ngpios);
|
|
reg_config_param(sec, "device", paramt_int, change_device);
|
|
reg_config_param(sec, "baseaddr", paramt_addr, gpio_baseaddr);
|
reg_config_param(sec, "baseaddr", paramt_addr, gpio_baseaddr);
|
reg_config_param(sec, "irq", paramt_int, gpio_irq);
|
reg_config_param(sec, "irq", paramt_int, gpio_irq);
|
reg_config_param(sec, "base_vapi_id", paramt_int, gpio_base_vapi_id);
|
reg_config_param(sec, "base_vapi_id", paramt_int, gpio_base_vapi_id);
|
reg_config_param(sec, "enddevice", paramt_none, end_device);
|
|
}
|
}
|
|
|
No newline at end of file
|
No newline at end of file
|