Files
bare-metal-pi/kernel.c
T
2016-10-19 00:23:03 -07:00

273 lines
8.8 KiB
C

/*
Part of the Raspberry-Pi Bare Metal Tutorials
Copyright (c) 2015, Brian Sidebotham
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "rpi/aux.h"
#include "rpi/armtimer.h"
#include "rpi/gpio.h"
#include "rpi/interrupts.h"
#include "rpi/mailbox-interface.h"
#include "rpi/systimer.h"
#include "kernel/util.h"
/** Main function - we'll never return from here */
void kernel_main( unsigned int r0, unsigned int r1, unsigned int atags )
{
int width = SCREEN_WIDTH, height = SCREEN_HEIGHT, bpp = SCREEN_DEPTH;
int x, y, pitch = 0;
colour_t current_colour;
volatile unsigned char* fb = NULL;
int pixel_offset;
int r, g, b, a;
float cd = COLOUR_DELTA;
unsigned int frame_count = 0;
/* Write 1 to the LED init nibble in the Function Select GPIO
peripheral register to enable LED pin as an output */
RPI_GetGpio()->LED_GPFSEL |= LED_GPFBIT;
/* Enable the timer interrupt IRQ */
RPI_GetIrqController()->Enable_Basic_IRQs = RPI_BASIC_ARM_TIMER_IRQ;
/* Setup the system timer interrupt */
/* Timer frequency = Clk/256 * 0x400 */
RPI_GetArmTimer()->Load = 0x400;
/* Setup the ARM Timer */
RPI_GetArmTimer()->Control =
RPI_ARMTIMER_CTRL_23BIT |
RPI_ARMTIMER_CTRL_ENABLE |
RPI_ARMTIMER_CTRL_INT_ENABLE |
RPI_ARMTIMER_CTRL_PRESCALE_256;
/* Enable interrupts! */
_enable_interrupts();
/* Initialise the UART */
RPI_AuxMiniUartInit( 115200, 8 );
/* Print to the UART using the standard libc functions */
printf( "Valvers.com ARM Bare Metal Tutorials\r\n" );
printf( "Initialise UART console with standard libc\r\n\n" );
RPI_PropertyInit();
RPI_PropertyAddTag( TAG_GET_BOARD_MODEL );
RPI_PropertyAddTag( TAG_GET_BOARD_REVISION );
RPI_PropertyAddTag( TAG_GET_FIRMWARE_VERSION );
RPI_PropertyAddTag( TAG_GET_BOARD_MAC_ADDRESS );
RPI_PropertyAddTag( TAG_GET_BOARD_SERIAL );
RPI_PropertyAddTag( TAG_GET_MAX_CLOCK_RATE, TAG_CLOCK_ARM );
RPI_PropertyProcess();
rpi_mailbox_property_t* mp;
mp = RPI_PropertyGet( TAG_GET_BOARD_MODEL );
if( mp )
printf( "Board Model: %d\r\n", mp->data.value_32 );
else
printf( "Board Model: NULL\r\n" );
mp = RPI_PropertyGet( TAG_GET_BOARD_REVISION );
if( mp )
printf( "Board Revision: %d\r\n", mp->data.value_32 );
else
printf( "Board Revision: NULL\r\n" );
mp = RPI_PropertyGet( TAG_GET_FIRMWARE_VERSION );
if( mp )
printf( "Firmware Version: %d\r\n", mp->data.value_32 );
else
printf( "Firmware Version: NULL\r\n" );
mp = RPI_PropertyGet( TAG_GET_BOARD_MAC_ADDRESS );
if( mp )
printf( "MAC Address: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\r\n",
mp->data.buffer_8[0], mp->data.buffer_8[1], mp->data.buffer_8[2],
mp->data.buffer_8[3], mp->data.buffer_8[4], mp->data.buffer_8[5] );
else
printf( "MAC Address: NULL\r\n" );
mp = RPI_PropertyGet( TAG_GET_BOARD_SERIAL );
if( mp )
printf( "Serial Number: %8.8X%8.8X\r\n",
mp->data.buffer_32[0], mp->data.buffer_32[1] );
else
printf( "Serial Number: NULL\r\n" );
mp = RPI_PropertyGet( TAG_GET_MAX_CLOCK_RATE );
if( mp )
printf( "Maximum ARM Clock Rate: %dHz\r\n", mp->data.buffer_32[1] );
else
printf( "Maximum ARM Clock Rate: NULL\r\n" );
/* Ensure the ARM is running at it's maximum rate */
RPI_PropertyInit();
RPI_PropertyAddTag( TAG_SET_CLOCK_RATE, TAG_CLOCK_ARM, mp->data.buffer_32[1] );
RPI_PropertyProcess();
RPI_PropertyInit();
RPI_PropertyAddTag( TAG_GET_CLOCK_RATE, TAG_CLOCK_ARM );
RPI_PropertyProcess();
mp = RPI_PropertyGet( TAG_GET_CLOCK_RATE );
if( mp )
printf( "Set ARM Clock Rate: %dHz\r\n", mp->data.buffer_32[1] );
else
printf( "Set ARM Clock Rate: NULL\r\n" );
/* Initialise a framebuffer... */
RPI_PropertyInit();
RPI_PropertyAddTag( TAG_ALLOCATE_BUFFER );
RPI_PropertyAddTag( TAG_SET_PHYSICAL_SIZE, SCREEN_WIDTH, SCREEN_HEIGHT );
RPI_PropertyAddTag( TAG_SET_VIRTUAL_SIZE, SCREEN_WIDTH, SCREEN_HEIGHT * 2 );
RPI_PropertyAddTag( TAG_SET_DEPTH, SCREEN_DEPTH );
RPI_PropertyAddTag( TAG_GET_PITCH );
RPI_PropertyAddTag( TAG_GET_PHYSICAL_SIZE );
RPI_PropertyAddTag( TAG_GET_DEPTH );
RPI_PropertyProcess();
if( ( mp = RPI_PropertyGet( TAG_GET_PHYSICAL_SIZE ) ) )
{
width = mp->data.buffer_32[0];
height = mp->data.buffer_32[1];
printf( "Initialised Framebuffer: %dx%d ", width, height );
}
if( ( mp = RPI_PropertyGet( TAG_GET_DEPTH ) ) )
{
bpp = mp->data.buffer_32[0];
printf( "%dbpp\r\n", bpp );
}
if( ( mp = RPI_PropertyGet( TAG_GET_PITCH ) ) )
{
pitch = mp->data.buffer_32[0];
printf( "Pitch: %d bytes\r\n", pitch );
}
if( ( mp = RPI_PropertyGet( TAG_ALLOCATE_BUFFER ) ) )
{
fb = (unsigned char*)mp->data.buffer_32[0];
printf( "Framebuffer address: %8.8X\r\n", (unsigned int)fb );
}
/* Never exit as there is no OS to exit to! */
current_colour.r = 0x4B;
current_colour.g = 0x00;
current_colour.b = 0x82;
current_colour.a = 0;
while( 1 )
{
/* Produce a colour spread across the screen */
for( y = 0; y < height; y++ )
{
// current_colour.r += ( 1.0 / height );
for( x = 0; x < width; x++ )
{
pixel_offset = ( x * ( bpp >> 3 ) ) + ( y * pitch );
r = (int)( current_colour.r * 0xFF ) & 0xFF;
g = (int)( current_colour.g * 0xFF ) & 0xFF;
b = (int)( current_colour.b * 0xFF ) & 0xFF;
a = (int)( current_colour.a * 0xFF ) & 0xFF;
if( bpp == 32 )
{
/* Four bytes to write */
fb[ pixel_offset++ ] = r;
fb[ pixel_offset++ ] = g;
fb[ pixel_offset++ ] = b;
fb[ pixel_offset++ ] = a;
}
else if( bpp == 24 )
{
/* Three bytes to write */
fb[ pixel_offset++ ] = r;
fb[ pixel_offset++ ] = g;
fb[ pixel_offset++ ] = b;
}
else if( bpp == 16 )
{
/* Two bytes to write */
/* Bit pack RGB565 into the 16-bit pixel offset */
*(unsigned short*)&fb[pixel_offset] = ( (r >> 3) << 11 ) | ( ( g >> 2 ) << 5 ) | ( b >> 3 );
}
else
{
/* Palette mode. TODO: Work out a colour scheme for
packing rgb into an 8-bit palette! */
}
// current_colour.b += ( 1.0 / width );
}
}
/* Scroll through the green colour */
/*
current_colour.g += cd;
if( current_colour.g > 1.0 )
{
current_colour.g = 1.0;
cd = -COLOUR_DELTA;
}
else if( current_colour.g < 0.0 )
{
current_colour.g = 0.0;
cd = COLOUR_DELTA;
}
*/
frame_count++;
if( calculate_frame_count )
{
calculate_frame_count = 0;
/* Number of frames in a minute, divided by seconds per minute */
float fps = (float)frame_count / 60;
printf( "FPS: %.2f\r\n", fps );
frame_count = 0;
}
}
}