I am attempting to write a User Mode SPI driver for my AM3896. I am able to mmap the spi address space but when I try to access any of the mapped memory I get a Precise External Abort on non-linefetch error.
I have the McSPI's power and clocks enabled as proved by the ioctl call to the Linux SPI driver. I also know that my mmap call is working properly because I am able to read the GPIO registers by only changing the base address of the mmap.
I am out of ideas of why this wouldn't work so any any help would be appreciated. Thank you in advance.
#include <asm/types.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <fcntl.h>
#include <linux/spi/spidev.h>
#include <sys/mman.h>
#define SPIDEV "/dev/spidev1.1"
static void do_spi_ioctl( void );
static void do_umspi( void );
int main( int argc, char ** argv )
{
//prove the clock and pm are setup correctly
do_spi_ioctl( );
//now error on the user mode version
do_umspi( );
}
static void do_spi_ioctl( )
{
unsigned char tx_buffer[10] = { 0xAA };
unsigned char rx_buffer[10] = { 0 };
unsigned spidev;
/**
struct spi_ioc_transfer {
__u64 tx_buf;
__u64 rx_buf;
__u32 len;
__u32 speed_hz;
__u16 delay_usecs;
__u8 bits_per_word;
__u8 cs_change;
__u32 pad;
};
*/
spidev = open(SPIDEV, O_RDWR);
if (spidev == -1)
{
printf("Unable to open %s.\n", SPIDEV);
}
struct spi_ioc_transfer tr = {
(unsigned)tx_buffer,
(unsigned)rx_buffer,
10,
2000000,
30,
8,
0,
0
};
int ret = ioctl(spidev, SPI_IOC_MESSAGE(1), &tr);
printf ("Read %d and wrote %d bytes to spidev\n", 10, ret);
if (ret < 1)
{
printf ("Unable to send spi message.\n");
}
close(spidev);
}
static void do_umspi( )
{
unsigned * s_spi_ptr;
unsigned base;
unsigned basepage;
unsigned baseoff;
int memoryFD = open( "/dev/mem", O_RDWR );
if ( memoryFD == 0 )
{
printf( "Failed to open /dev/mem.\n" );
return;
}
base = 0x48030000;//spi
//base = 0x48032000;//gpio
baseoff = base % getpagesize();
basepage = base - baseoff;
char *registerPage_ptr = (char *)mmap( 0,
getpagesize(),
( PROT_READ | PROT_WRITE ),
MAP_SHARED,
memoryFD,
basepage );
s_spi_ptr = (unsigned *)(registerPage_ptr + baseoff);
printf( "um_spi_init: after mmap base x%x baseoff x%x basepage x%x registerPage_ptr x%x s_spi_ptr x%x pagesize x%x\n",
base,
baseoff,
basepage,
registerPage_ptr,
s_spi_ptr,
getpagesize() );
if ( (unsigned)registerPage_ptr == 0xFFFFFFFF )
{
printf( "Error while mapping memory.\n" );
return;
}
printf( "spi loc x%x\n", (s_spi_ptr) );
printf( "spi version loc x%x\n", (s_spi_ptr) );
//allow buffer to clear
sleep( 1 );
//the spi hw verion is the first register
printf( "spi version x%x\n", *(s_spi_ptr) );
}
spi output
# ./spi_test.o
Read 10 and wrote 10 bytes to spidev
um_spi_init: after mmap base x48030000 baseoff x0 basepage x48030000 registerPage_ptr x2ad55000 s_spi_ptr x2ad55000 pagesize x1000
spi loc x2ad55000
spi version loc x2ad55000
[ 97.921404] Unhandled fault: Precise External Abort on non-linefetch (0x1018) at 0x2ad55000
Bus error
gpio output
# ./spi_test.o
Read 10 and wrote 10 bytes to spidev
um_spi_init: after mmap base x48032000 baseoff x0 basepage x48032000 registerPage_ptr x2ad31000 s_spi_ptr x2ad31000 pagesize x1000
spi loc x2ad31000
spi version loc x2ad31000
spi version x50600801