Hardware Hangs When Trying To Read Mmsp2 Status Register


gfoot

Member
Joined
Nov 15, 2005
Messages
218
Hi guys,

I've been looking at why the hardware accelerated Allegro doesn't work, and I've narrowed it down to a very short segment of code. This fragment is a standalone program, and I've inlined all the MMIO addresses and register numbers so it's very straightforward. The code does basically the same thing that the hardware accelerated SDL initialization code does. It's at the end of the post, for reference. On my setup, it hangs after printing "reading...", at which point it should be reading the MMSP2's status register.

I started off just opening /dev/mem, mmapping the MMSP2 blitter regs (size 0x100 at 0xe0020000), and reading the register. Since then I've added various other things the SDL code does, in case it makes some difference - it now also maps the GPIO registers, and sets the two clock bits that the SDL code sets; it also opens the framebuffer device (but doesn't do anything with it); and I added a few memory sync points just to be sure that wasn't affecting anything. None of this changes the result. It also doesn't seem to matter whether I kill the gp2xmenu before running my program.

My hardware is using firmware 2. I'd appreciate it if anyone else could compile and run this sample and say whether it terminates properly, or whether it crashes like mine does. When the crash happens, the whole device stops working - SMB shares, telnet, and all. I added the "sleep" lines to give it time to send the printouts down the telnet link before crashing.

Here's the code:

Code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>

int mem_fd;
char *gpio_regs;
char *mmsp2_regs;
int value;

int main(void)
{
	int fb_fd = open( "/dev/fb0", O_RDWR );
	if( fb_fd < 0 )
	{
		printf( "failed to open /dev/fb0\n" );
		return -1;
	}

	mem_fd = open( "/dev/mem", O_RDWR );
	if( mem_fd < 0 )
	{
		printf( "failed to open /dev/mem\n" );
		return -1;
	}

	gpio_regs = mmap( NULL, 0x10000, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, 0xc0000000 );
	if( gpio_regs == MAP_FAILED )
	{
		printf( "gpio mmap failed\n" );
		return -1;
	}

	mmsp2_regs = mmap( NULL, 0x10000, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, 0xe0020000 );
	if( mmsp2_regs == MAP_FAILED )
	{
		printf( "mmsp2 mmap failed\n" );
		return -1;
	}

	printf( "setup...\n" );
	sleep(1);

	asm volatile ("":::"memory");
	*(short*)(gpio_regs + 0x0904) |= (1 << 10);
	asm volatile ("":::"memory");
	*(short*)(gpio_regs + 0x090A) |= (1 << 2);
	asm volatile ("":::"memory");


	printf( "reading...\n" );
	sleep(1);

	value = *(int *)(mmsp2_regs + 0x34);

	printf( "done, read %d\n", value );
	sleep(1);

	return 0;
}
 
That normally happens if you try and read from a peripheral whose clock isn't enabled, and thus the device locks up solid waiting for a response it'll never get.

Try this before you "reading" :

*(short*)(gpio_regs + 0x090A) = 0xFFFF;

or my preferred method - make gpio_regs a short and use it as an array:

unsigned short *gpio_regs;

gpio_regs[0x090A >> 1] = 0xFFFF;

Looks much better then than all the casting and stuff :)
 
Hmm, Allegro was originally setting it to 0xFFFF, based on the old SDL code which has now been changed to just set the GRPCLK bit (1<<2). I'll give that another go tonight though, thanks.

I don't like the unsigned short array approach either really - in practice I use an inline function to hide everything. I just wrote it out this way to make the test program short and sweet. :)

Do you know if there are any contention issues between the OS and programs accessing the blitter and graphics setup registers directly? I guess if the menu was still running all hell would break loose, but if we're accessing hardware registers directly there's no way the OS can mediate.
 
gfoot posted on Aug 14 2006 at 03:35 PM said:
Do you know if there are any contention issues between the OS and programs accessing the blitter and graphics setup registers directly? I guess if the menu was still running all hell would break loose, but if we're accessing hardware registers directly there's no way the OS can mediate.
The menu doesn't use the blitter at all, as far as I know the only GPH program that could use it is the 940 code of mplayer. All of GPH's programs use their SDL which (as of yet, if ever) doesn't use the blitter at all. If the menu was running then you'd have a few problems like the menu will still register all joystick movements and button presses, and the display will be constantly being re-set to default values.
 
Last edited by a moderator:
I'm going to scream. I was building my code with the rubbish old GPH compiler, which is incapable of doing short reads/writes to hardware registers properly. Verifying the written values showed that nothing was getting written, and inspecting the assembly output shows it's using ldrb/strb and bitshifts to do the reads and writes - ARGH.

It wouldn't be so bad if I hadn't found exactly the same thing back in January, how did I forget?

Anyway, thanks guys - it's now successfully setting the clock bits, and the status read works again.
 
Back
Top