Files
raspberrypi/bootloader02/bootloader02.c

201 lines
5.0 KiB
C

//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
//The raspberry pi wants you to not have your kernel.img file loaded
//at address 0x0000. Using a bootloader like this it works just fine
//but to avoid having example binaries that are at 0x8000 for running
//from the sd card and a binary at 0x0000 for loading with the
//bootloader, instead the bootloader is going to default to 0x8000
//as well.
#define ARMBASE 0x8000
extern void PUT32 ( unsigned int, unsigned int );
extern void PUT16 ( unsigned int, unsigned int );
extern void PUT8 ( unsigned int, unsigned int );
extern unsigned int GET32 ( unsigned int );
extern void BRANCHTO ( unsigned int );
extern void dummy ( unsigned int );
#define ARM_TIMER_CTL 0x2000B408
#define ARM_TIMER_CNT 0x2000B420
#define GPFSEL1 0x20200004
#define GPSET0 0x2020001C
#define GPCLR0 0x20200028
#define GPPUD 0x20200094
#define GPPUDCLK0 0x20200098
#define AUX_ENABLES 0x20215004
#define AUX_MU_IO_REG 0x20215040
#define AUX_MU_IER_REG 0x20215044
#define AUX_MU_IIR_REG 0x20215048
#define AUX_MU_LCR_REG 0x2021504C
#define AUX_MU_MCR_REG 0x20215050
#define AUX_MU_LSR_REG 0x20215054
#define AUX_MU_MSR_REG 0x20215058
#define AUX_MU_SCRATCH 0x2021505C
#define AUX_MU_CNTL_REG 0x20215060
#define AUX_MU_STAT_REG 0x20215064
#define AUX_MU_BAUD_REG 0x20215068
//GPIO14 TXD0 and TXD1
//GPIO15 RXD0 and RXD1
//------------------------------------------------------------------------
unsigned int uart_recv ( void )
{
while(1)
{
if(GET32(AUX_MU_LSR_REG)&0x01) break;
}
return(GET32(AUX_MU_IO_REG)&0xFF);
}
//------------------------------------------------------------------------
void uart_send ( unsigned int c )
{
while(1)
{
if(GET32(AUX_MU_LSR_REG)&0x20) break;
}
PUT32(AUX_MU_IO_REG,c);
}
//------------------------------------------------------------------------
void hexstrings ( unsigned int d )
{
//unsigned int ra;
unsigned int rb;
unsigned int rc;
rb=32;
while(1)
{
rb-=4;
rc=(d>>rb)&0xF;
if(rc>9) rc+=0x37; else rc+=0x30;
uart_send(rc);
if(rb==0) break;
}
uart_send(0x20);
}
//------------------------------------------------------------------------
void hexstring ( unsigned int d )
{
hexstrings(d);
uart_send(0x0D);
uart_send(0x0A);
}
//------------------------------------------------------------------------
unsigned char xstring[256];
//------------------------------------------------------------------------
int notmain ( void )
{
unsigned int ra;
//unsigned int rb;
unsigned int rx;
unsigned int addr;
unsigned int block;
unsigned int crc;
PUT32(AUX_ENABLES,1);
PUT32(AUX_MU_IER_REG,0);
PUT32(AUX_MU_CNTL_REG,0);
PUT32(AUX_MU_LCR_REG,3);
PUT32(AUX_MU_MCR_REG,0);
PUT32(AUX_MU_IER_REG,0);
PUT32(AUX_MU_IIR_REG,0xC6);
PUT32(AUX_MU_BAUD_REG,270);
ra=GET32(GPFSEL1);
ra&=~(7<<12); //gpio14
ra|=2<<12; //alt5
ra&=~(7<<15); //gpio15
ra|=2<<15; //alt5
PUT32(GPFSEL1,ra);
PUT32(GPPUD,0);
for(ra=0;ra<150;ra++) dummy(ra);
PUT32(GPPUDCLK0,(1<<14)|(1<<15));
for(ra=0;ra<150;ra++) dummy(ra);
PUT32(GPPUDCLK0,0);
PUT32(AUX_MU_CNTL_REG,3);
PUT32(ARM_TIMER_CTL,0x00F90000);
PUT32(ARM_TIMER_CTL,0x00F90200);
hexstring(0x12345678);
//SOH 0x01
//ACK 0x06
//NAK 0x15
//EOT 0x04
//block numbers start with 1
//132 byte packet
//starts with SOH
//block number byte
//255-block number
//128 bytes of data
//checksum byte (whole packet)
//a single EOT instead of SOH when done, send an ACK on it too
//this is a very crude solution, worked for a small test program though
//if it slips one byte it is all over. Need to make a more robust
//solution.
rx=GET32(ARM_TIMER_CNT);
while(1)
{
ra=GET32(ARM_TIMER_CNT);
if((ra-rx)>=4000000)
{
uart_send(0x15);
rx+=4000000;
}
if(GET32(AUX_MU_LSR_REG)&0x01) break;
}
block=1;
addr=ARMBASE;
while(1)
{
xstring[0]=uart_recv();
if(xstring[0]==0x04)
{
uart_send(0x06);
break;
}
if(xstring[0]!=0x01) break;
crc=0x01;
for(ra=1;ra<132;ra++)
{
xstring[ra]=uart_recv();
crc+=xstring[ra];
}
if(xstring[2]!=(255-xstring[1])) break;
crc-=xstring[131];
crc&=0xFF;
if(xstring[131]!=crc)
{
uart_send(0x15);
}
for(ra=0;ra<128;ra++)
{
PUT8(addr++,xstring[ra+3]);
}
if(addr>0x200000)
{
uart_send(0x15);
break;
}
uart_send(0x06);
block=(block+1)&0xFF;
}
if(xstring[0]==0x04)
{
BRANCHTO(ARMBASE);
}
return(0);
}
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------