#pragma once
#include <stdint.h>
#include <stdbool.h>
// CAUTION: DO NOT MODIFY REGISTERS FROM PRU unless you can be
// absolutely certain that linux will not modify the register around the
// same time, otherwise you'll create a race condition that may randomly
// cause register writes to be lost.
//
// The only exceptions are CLEARDATAOUT and SETDATAOUT which are
// write-only registers that perform atomic operations on the DATAOUT
// register and are therefore safe for concurrent use by pru and linux.
// (This also applies to IRQSTATUS_SET/CLR but obviously you shouldn't
// mess with interrupt handling registers used by linux, with or without
// race condition.)
//
typedef struct {
/*000*/ uint32_t volatile REVISION;
/*004*/ uint32_t volatile rsvd004[(0x010-0x004)/4];
/*010*/ uint32_t volatile SYSCONFIG;
/*014*/ uint32_t volatile rsvd014[(0x020-0x014)/4];
/*020*/ uint32_t volatile EOI;
/*024*/ uint32_t volatile IRQSTATUS_RAW[2];
/*02c*/ uint32_t volatile IRQSTATUS[2];
/*034*/ uint32_t volatile IRQSTATUS_SET[2];
/*03c*/ uint32_t volatile IRQSTATUS_CLR[2];
/*044*/ uint32_t volatile IRQWAKEN[2];
/*04c*/ uint32_t volatile rsvd04c[(0x114-0x04c)/4];
/*114*/ uint32_t volatile SYSSTATUS;
/*118*/ uint32_t volatile rsvd118[(0x130-0x118)/4];
/*130*/ uint32_t volatile CTRL;
/*134*/ uint32_t volatile OE;
/*138*/ uint32_t volatile DATAIN;
/*13c*/ uint32_t volatile DATAOUT;
/*140*/ uint32_t volatile LEVELDETECT0;
/*144*/ uint32_t volatile LEVELDETECT1;
/*148*/ uint32_t volatile RISINGDETECT;
/*14c*/ uint32_t volatile FALLINGDETECT;
/*150*/ uint32_t volatile DEBOUNCENABLE;
/*154*/ uint32_t volatile DEBOUNCINGTIME;
/*158*/ uint32_t volatile rsvd158[(0x190-0x158)/4];
/*190*/ uint32_t volatile CLEARDATAOUT;
/*194*/ uint32_t volatile SETDATAOUT;
} sysGpio;
#define GPIO0 (*(sysGpio *)0x44e07000)
#define GPIO1 (*(sysGpio *)0x4804c000)
#define GPIO2 (*(sysGpio *)0x481ac000)
#define GPIO3 (*(sysGpio *)0x481ae000)
//------------------ Safe wrapper functions ---------------------------------------------------
//
// The first argument must always be one of: &GPIO0, &GPIO1, &GPIO2, &GPIO3.
//
// For efficiency you can act on multiple gpios of one controller at the same time, with the
// 32 gpios of one controller represented by the bits of an uint32_t. Convenience wrappers
// that act on a single gpio are also provided further down.
//
// It is unsafe to change gpio direction from PRU so I'm not making a wrapper for that, set the
// gpio direction from linux instead. Output values of gpios configured as input are ignored.
// read all gpios of one gpio controller.
static inline uint32_t gpio_read( sysGpio *dev )
{
return dev->DATAIN;
}
// set output value to 0 for one or more gpios of one gpio controller.
static inline void gpio_set_low( sysGpio *dev, uint32_t mask )
{
dev->CLEARDATAOUT = mask;
}
// set output value to 1 for one or more gpios of one gpio controller.
static inline void gpio_set_high( sysGpio *dev, uint32_t mask )
{
dev->SETDATAOUT = mask;
}
// combines gpio_set_low() and gpio_set_high(), but optimized to use only a single bus write.
// this minimizes the delay between the two actions.
static inline void gpio_set_low_set_high( sysGpio *dev, uint32_t low_mask, uint32_t high_mask )
{
*(uint64_t volatile *)&dev->CLEARDATAOUT = low_mask | (uint64_t)high_mask << 32;
}
// set output value for one or more gpios of one gpio controller, with value specified per gpio.
static inline void gpio_set( sysGpio *dev, uint32_t mask, uint32_t values )
{
gpio_set_low_set_high( dev, mask & ~values, mask & values );
}
// set output value for one or more gpios of one gpio controller, using same value for all.
static inline void gpio_fill( sysGpio *dev, uint32_t mask, bool value )
{
(&dev->CLEARDATAOUT)[ value ] = mask;
}
// Convenience wrappers for accessing a single gpio (0..31) of a gpio controller:
// read one gpio
static inline bool gpio_read_one( sysGpio *dev, uint8_t gpio )
{
return ( gpio_read( dev ) >> gpio ) & 1;
}
// set output value of one gpio to 0
static inline void gpio_set_one_low( sysGpio *dev, uint8_t gpio )
{
gpio_set_low( dev, 1u << gpio );
}
// set output value of one gpio to 1
static inline void gpio_set_one_high( sysGpio *dev, uint8_t gpio )
{
gpio_set_high( dev, 1u << gpio );
}
// set output value of one gpio
static inline void gpio_set_one( sysGpio *dev, uint8_t gpio, bool value )
{
gpio_fill( dev, 1u << gpio, value );
}
Comments