/*
* bbb - gpmc - test
*
* Copyright ( C ) 2014 Timothy Pearson < kb9vqf @ pearsoncomputing . net > ( Beaglebone Black )
*
* Permission to use , copy , modify , and / or distribute this software for any
* purpose with or without fee is hereby granted , provided that the above
* copyright notice and this permission notice appear in all copies .
*
* THE SOFTWARE IS PROVIDED " AS IS " AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS . IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL , DIRECT , INDIRECT , OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE , DATA OR PROFITS , WHETHER IN AN
* ACTION OF CONTRACT , NEGLIGENCE OR OTHER TORTIOUS ACTION , ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE .
*
*/
# include <sys/time.h>
# include <unistd.h>
# include <string.h>
# include <stdlib.h>
# include <stdio.h>
# include <errno.h>
/** BEGIN: Low-Level I/O Implementation **/
// Beaglebone Black GPMC driver
# include <sys/types.h>
# include <sys/stat.h>
# include <sys/mman.h>
# include <fcntl.h>
# define MEMORY_SPACE_ADDRESS_BITS 16
# define GPMC_BASE 0x50000000
# define GPMC_REGLEN 0x10000000
# define GPMC_CHIPSELECTCONFIGDISPLACEMENT (0x30 / 4)
# define GPMC_CONFIG (0x50 / 4)
# define GPMC_CONFIG1 (0x60 / 4)
# define GPMC_CONFIG2 (0x64 / 4)
# define GPMC_CONFIG3 (0x68 / 4)
# define GPMC_CONFIG4 (0x6c / 4)
# define GPMC_CONFIG5 (0x70 / 4)
# define GPMC_CONFIG6 (0x74 / 4)
# define GPMC_CONFIG7 (0x78 / 4)
# define MEMORY_SIZE (1 << MEMORY_SPACE_ADDRESS_BITS)
int mem_fd = 0 ;
int gpmc_mem_fd = 0 ;
char * gpio_mem , * gpio_map , * gpmc_map ;
// I/O access
static volatile unsigned int * gpio = NULL ;
static volatile unsigned char * gpio_char = NULL ;
static volatile unsigned long long * gpio_longlong = NULL ;
static volatile unsigned int * gpmc = NULL ;
static void gpmc_mapregisters ( )
{
/* open /dev/mem */
if ( ( gpmc_mem_fd = open ( " /dev/mem " , O_RDWR | O_SYNC ) ) < 0 ) {
printf ( " can't open /dev/mem \n " ) ;
exit ( - 1 ) ;
}
/* mmap GPMC */
gpmc_map = ( char * ) mmap (
0 ,
GPMC_REGLEN ,
PROT_READ | PROT_WRITE ,
MAP_SHARED ,
gpmc_mem_fd ,
GPMC_BASE
) ;
if ( gpmc_map = = MAP_FAILED ) {
printf ( " mmap error %d \n " , ( int ) gpmc_map ) ;
exit ( - 1 ) ;
}
// Always use volatile pointer!
gpmc = ( volatile unsigned * ) gpmc_map ;
}
static void gpmc_unmapregisters ( )
{
munmap ( ( void * ) gpmc , GPMC_REGLEN ) ;
if ( gpmc_mem_fd ! = - 1 ) {
close ( gpmc_mem_fd ) ;
}
}
static void gpmc_setup ( void )
{
// WARNING: The GPMC runs at the L3 clock frequency!
// It is not well documented, but that frequency seems to be 200MHz on the AM335x series of chips
gpmc_mapregisters ( ) ;
if ( gpmc ! = NULL ) {
int chipselect = 0 ;
int displacement = GPMC_CHIPSELECTCONFIGDISPLACEMENT * chipselect ;
// disable before playing with the registers
* ( gpmc + displacement + GPMC_CONFIG7 ) = 0x00000000 ;
* ( gpmc + displacement + GPMC_CONFIG ) = 0x00000000 ; // Unlimited address space
* ( gpmc + displacement + GPMC_CONFIG1 ) = 0x00000000 ; // No burst, async, 8-bit, non multiplexed
// *(gpmc + displacement + GPMC_CONFIG1) = 0x00000010; // No burst, async, 8-bit, non multiplexed, x2 slowed cycle timing
// // 200MHz compatible SRAM device
// *(gpmc + displacement + GPMC_CONFIG2) = 0x00000800; // Assert CS on fclk 0, deassert CS on fclk 8
// *(gpmc + displacement + GPMC_CONFIG3) = 0x00000200; // Assert ADV on fclk0, deassert ADV on fclk2
// *(gpmc + displacement + GPMC_CONFIG4) = 0x06020802; // Assert WE on fclk2, deassert WE on fclk6, assert OE on fclk2, deassert OE on fclk8
// *(gpmc + displacement + GPMC_CONFIG5) = 0x00060808; // Data valid on fclk 6, cycle time 8 fclks
// // 100MHz compatible SRAM device
// *(gpmc + displacement + GPMC_CONFIG2) = 0x00001000; // Assert CS on fclk0, deassert CS on fclk16
// *(gpmc + displacement + GPMC_CONFIG3) = 0x00000400; // Assert ADV on fclk 0, deassert ADV on fclk 4
// *(gpmc + displacement + GPMC_CONFIG4) = 0x0c041004; // Assert WE on fclk4, deassert WE on fclk12, assert OE on fclk4, deassert OE on fclk16
// *(gpmc + displacement + GPMC_CONFIG5) = 0x000c1010; // Data valid on fclk 12, cycle time 16 fclks
// 50MHz compatible SRAM device
* ( gpmc + displacement + GPMC_CONFIG2 ) = 0x00001f00 ; // Assert CS on fclk0, deassert CS on fclk31
* ( gpmc + displacement + GPMC_CONFIG3 ) = 0x00000400 ; // Assert ADV on fclk 0, deassert ADV on fclk 4
* ( gpmc + displacement + GPMC_CONFIG4 ) = 0x1f041f04 ; // Assert WE on fclk4, deassert WE on fclk31, assert OE on fclk4, deassert OE on fclk31
* ( gpmc + displacement + GPMC_CONFIG5 ) = 0x00101f1f ; // Data valid on fclk 16, cycle time 31 fclks
* ( gpmc + displacement + GPMC_CONFIG6 ) = 0x00000000 ; // No back to back cycle restrictions
* ( gpmc + displacement + GPMC_CONFIG7 ) = 0x00000e50 ; // CS0: Set base address 0x10000000, 32MB region, and enable CS
gpmc_unmapregisters ( ) ;
}
}
void gpmc_dump_registers ( void )
{
gpmc_mapregisters ( ) ;
if ( gpmc ! = NULL ) {
int chipselect = 0 ;
int displacement = GPMC_CHIPSELECTCONFIGDISPLACEMENT * chipselect ;
printf ( " GPMC_CONFIG0: %08x \n " , * ( gpmc + displacement + GPMC_CONFIG ) ) ;
printf ( " GPMC_CONFIG1: %08x \n " , * ( gpmc + displacement + GPMC_CONFIG1 ) ) ;
printf ( " GPMC_CONFIG2: %08x \n " , * ( gpmc + displacement + GPMC_CONFIG2 ) ) ;
printf ( " GPMC_CONFIG3: %08x \n " , * ( gpmc + displacement + GPMC_CONFIG3 ) ) ;
printf ( " GPMC_CONFIG4: %08x \n " , * ( gpmc + displacement + GPMC_CONFIG4 ) ) ;
printf ( " GPMC_CONFIG5: %08x \n " , * ( gpmc + displacement + GPMC_CONFIG5 ) ) ;
printf ( " GPMC_CONFIG6: %08x \n " , * ( gpmc + displacement + GPMC_CONFIG6 ) ) ;
printf ( " GPMC_CONFIG7: %08x \n " , * ( gpmc + displacement + GPMC_CONFIG7 ) ) ;
}
gpmc_unmapregisters ( ) ;
}
static void io_setup ( void )
{
printf ( " sizeof int: \t %d \n " , sizeof ( int ) ) ;
/* open /dev/mem */
if ( ( mem_fd = open ( " /dev/mem " , O_RDWR | O_SYNC ) ) < 0 ) {
printf ( " can't open /dev/mem \n " ) ;
exit ( - 1 ) ;
}
/* mmap GPIO */
gpio_map = ( char * ) mmap (
0 ,
MEMORY_SIZE ,
PROT_READ | PROT_WRITE ,
MAP_SHARED ,
mem_fd ,
0x10000000
) ;
if ( gpio_map = = MAP_FAILED ) {
printf ( " mmap error %d \n " , ( int ) gpio_map ) ;
exit ( - 1 ) ;
}
// Always use volatile pointer!
gpio = ( volatile unsigned * ) gpio_map ;
gpio_char = ( volatile unsigned char * ) gpio_map ;
gpio_longlong = ( volatile unsigned long long * ) gpio_map ;
// Select a test from the following blocks of code...
// // DEBUG ONLY
// // Clear out the mapped memory
// int i;
// for (i=0;i<0x3ff; i++) {
// *(gpio + i) = 0x00000000;
// }
// DEBUG ONLY
// Fill the mapped memory with a test pattern
// int j;
// for (j=0;j<0x00001000; j++) {
// *(gpio + j) = j;
// }
// int j;
// for (j=0;j<0x3ff; j++) {
// *(gpio + j) = j;
// }
#if 0
// DEBUG ONLY
// Looping memory test
unsigned int test_base = ( MEMORY_SIZE / 2 ) ;
unsigned int test_length = ( MEMORY_SIZE / 2 ) ;
unsigned int total_errors ;
unsigned char error_count [ MEMORY_SIZE ] ;
int i ;
int loop ;
unsigned int overall_total_errors ;
overall_total_errors = 0 ;
for ( loop = 0 ; loop < 10 ; loop + + ) {
printf ( " Memory test loop %d \n " , loop ) ;
for ( i = 0 ; i < test_length ; i + + ) {
error_count [ i ] = 0 ;
}
printf ( " \t Testing inversion pattern \n " ) ;
// Test with 0xaa
for ( i = 0 ; i < test_length ; i + + ) {
* ( gpio_char + test_base + i ) = 0xaa ;
}
for ( i = 0 ; i < test_length ; i + + ) {
unsigned char result = * ( gpio_char + test_base + i ) ;
if ( ( result ! = 0xaa ) ) {
error_count [ i ] = error_count [ i ] + 1 ;
printf ( " \t error detected at offset 0x%02x (was 0x%02x, expected 0x%02x, second read attempt returned 0x%02x) \n " , i , result , 0xaa , ( * ( gpio_char + test_base + i ) ) ) ;
}
}
// Test with 0x55
for ( i = 0 ; i < test_length ; i + + ) {
* ( gpio_char + test_base + i ) = 0x55 ;
}
for ( i = 0 ; i < test_length ; i + + ) {
unsigned char result = * ( gpio_char + test_base + i ) ;
if ( ( result ! = 0x55 ) ) {
error_count [ i ] = error_count [ i ] + 1 ;
printf ( " \t error detected at offset 0x%02x (was 0x%02x, expected 0x%02x, second read attempt returned 0x%02x) \n " , i , result , 0x55 , ( * ( gpio_char + test_base + i ) ) ) ;
}
}
total_errors = 0 ;
for ( i = 0 ; i < test_length ; i + + ) {
total_errors = total_errors + error_count [ i ] ;
if ( error_count [ i ] > 0 ) {
printf ( " \t %d \t error(s) found at offset 0x%02x \n " , error_count [ i ] , i ) ;
}
}
printf ( " \t Testing all ones/zeros \n " ) ;
// Test with 0xff
for ( i = 0 ; i < test_length ; i + + ) {
* ( gpio_char + test_base + i ) = 0xff ;
}
for ( i = 0 ; i < test_length ; i + + ) {
unsigned char result = * ( gpio_char + test_base + i ) ;
if ( ( result ! = 0xff ) ) {
error_count [ i ] = error_count [ i ] + 1 ;
printf ( " \t error detected at offset 0x%02x (was 0x%02x, expected 0x%02x, second read attempt returned 0x%02x) \n " , i , result , 0xff , ( * ( gpio_char + test_base + i ) ) ) ;
}
}
// Test with 0x00
for ( i = 0 ; i < test_length ; i + + ) {
* ( gpio_char + test_base + i ) = 0x00 ;
}
for ( i = 0 ; i < test_length ; i + + ) {
unsigned char result = * ( gpio_char + test_base + i ) ;
if ( ( result ! = 0x00 ) ) {
error_count [ i ] = error_count [ i ] + 1 ;
printf ( " \t error detected at offset 0x%02x (was 0x%02x, expected 0x%02x, second read attempt returned 0x%02x) \n " , i , result , 0x00 , ( * ( gpio_char + test_base + i ) ) ) ;
}
}
printf ( " \t Testing alternating ones/zeros \n " ) ;
// Test with 0xff
for ( i = 0 ; i < test_length ; i = i + 2 ) {
* ( gpio_char + test_base + i ) = 0xff ;
* ( gpio_char + test_base + i + 1 ) = 0x00 ;
}
for ( i = 0 ; i < test_length ; i = i + 2 ) {
unsigned char result ;
result = * ( gpio_char + test_base + i ) ;
if ( ( result ! = 0xff ) ) {
error_count [ i ] = error_count [ i ] + 1 ;
printf ( " \t error detected at offset 0x%02x (was 0x%02x, expected 0x%02x, second read attempt returned 0x%02x) \n " , i , result , 0xff , ( * ( gpio_char + test_base + i ) ) ) ;
}
result = * ( gpio_char + test_base + i + 1 ) ;
if ( ( result ! = 0x00 ) ) {
error_count [ i ] = error_count [ i ] + 1 ;
printf ( " \t error detected at offset 0x%02x (was 0x%02x, expected 0x%02x, second read attempt returned 0x%02x) \n " , i , result , 0x00 , ( * ( gpio_char + test_base + i ) ) ) ;
}
}
total_errors = 0 ;
for ( i = 0 ; i < test_length ; i + + ) {
total_errors = total_errors + error_count [ i ] ;
if ( error_count [ i ] > 0 ) {
printf ( " \t %d \t error(s) found at offset 0x%02x \n " , error_count [ i ] , i ) ;
}
}
printf ( " \t Test region size: \t %d \n " , test_length ) ;
printf ( " \t Total errors found: \t %d \n " , total_errors ) ;
fflush ( stdout ) ;
overall_total_errors = overall_total_errors + total_errors ;
}
for ( i = 0 ; i < MEMORY_SIZE ; i + + ) {
* ( gpio_char + i ) = 0 ;
}
printf ( " Total errors found over all loops: \t %d \n " , overall_total_errors ) ;
fflush ( stdout ) ;
return ;
# endif
int j ;
for ( j = 0 ; j < MEMORY_SIZE ; j + + ) {
* ( gpio_char + j ) = ( ( unsigned char ) j ) ;
}
// // DEBUG ONLY
// // Prints the contents of the mapped memory
// int k;
// for (k=0;k<(MEMORY_SIZE/4); k++) {
// printf("0x%08x\t%08x\n", k, *(gpio + k));
// }
// fflush(stdout);
// DEBUG ONLY
// Prints the contents of the mapped memory
int k ;
for ( k = 0 ; k < ( MEMORY_SIZE / 8 ) ; k + + ) {
printf ( " 0x%08x \t %016llx \n " , k , * ( gpio_longlong + k ) ) ;
}
fflush ( stdout ) ;
// // DEBUG ONLY
// // Excercise the memory space
// int l;
// while (1) {
// for (l=0;l<(MEMORY_SIZE/4); l++) {
// k = *(gpio + l);
// }
// }
// while (1) {
// printf("0x%08x\t0x%08x\t0x%08x\t0x%08x\r", *(gpio + 0), *(gpio + 1), *(gpio + 2), *(gpio + 3));
// usleep(1);
// }
// while (1) {
// printf("0x%08x\t0x%08x\t0x%08x\t0x%08x\r", *(gpio + 3), *(gpio + 2), *(gpio + 1), *(gpio + 0));
// usleep(1);
// }
// printf("0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\n\r", *(gpio_char + 0), *(gpio_char + 0), *(gpio_char + 0), *(gpio_char + 0), *(gpio_char + 0), *(gpio_char + 0), *(gpio_char + 0), *(gpio_char + 0));
//
gpmc_dump_registers ( ) ;
while ( 1 ) {
// printf("0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\r", *(gpio_char + 0), *(gpio_char + 1), *(gpio_char + 2), *(gpio_char + 3), *(gpio_char + 4), *(gpio_char + 5), *(gpio_char + 6), *(gpio_char + 7));
// printf("0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\r", *(gpio_char + 0), *(gpio_char + 1), *(gpio_char + 2), *(gpio_char + 3), *(gpio_char + 0x1000), *(gpio_char + 0x1001), *(gpio_char + 0x1002), *(gpio_char + 0x1003));
// printf("0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\r", *(gpio_char + 0), *(gpio_char + 1), *(gpio_char + 2), *(gpio_char + 3), *(gpio_char + 0x4000), *(gpio_char + 0x4001), *(gpio_char + 0x4002), *(gpio_char + 0x4003));
printf ( " 0x%02x \t 0x%02x \t 0x%02x \t 0x%02x \t 0x%02x \t 0x%02x \t 0x%02x \t 0x%02x \r " , * ( gpio_char + 0 ) , * ( gpio_char + 1 ) , * ( gpio_char + 2 ) , * ( gpio_char + 3 ) , * ( gpio_char + 0x0a ) , * ( gpio_char + 0x0b ) , * ( gpio_char + 0x0c ) , * ( gpio_char + 0x0d ) ) ;
// printf("0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\r", *(gpio_char + 0x4000), *(gpio_char + 0x4001), *(gpio_char + 0x4002), *(gpio_char + 0x4003), *(gpio_char + 0x4004), *(gpio_char + 0x4005), *(gpio_char + 0x4006), *(gpio_char + 0x4007));
usleep ( 10 ) ;
}
}
static void io_shutdown ( void )
{
//
}
/** END: Low-Level I/O Implementation **/
int main ( int argc , char * * argv )
{
gpmc_setup ( ) ;
printf ( " GPMC setup complete! \n " ) ; fflush ( stdout ) ;
io_setup ( ) ;
return 0 ;
}