diff --git a/CMakeLinker.x b/CMakeLinker.x new file mode 100644 index 0000000..28c8c24 --- /dev/null +++ b/CMakeLinker.x @@ -0,0 +1,235 @@ +/* Default linker script, for normal executables */ +OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", + "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(_start) +SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR("=/lib"); SEARCH_DIR("=/usr/lib"); +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x8000)); . = SEGMENT_START("text-segment", 0x8000); + .interp : { *(.interp) } + .note.gnu.build-id : { *(.note.gnu.build-id) } + .hash : { *(.hash) } + .gnu.hash : { *(.gnu.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) } + .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) } + .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } + .rel.data.rel.ro : { *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*) } + .rela.data.rel.ro : { *(.rela.data.rel.ro* .rela.gnu.linkonce.d.rel.ro.*) } + .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) } + .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } + .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) } + .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } + .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) } + .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } + .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } + .rel.iplt : + { + PROVIDE_HIDDEN (__rel_iplt_start = .); + *(.rel.iplt) + PROVIDE_HIDDEN (__rel_iplt_end = .); + } + .rela.iplt : + { + PROVIDE_HIDDEN (__rela_iplt_start = .); + *(.rela.iplt) + PROVIDE_HIDDEN (__rela_iplt_end = .); + } + .rel.plt : + { + *(.rel.plt) + } + .rela.plt : + { + *(.rela.plt) + } + .init : + { + KEEP (*(.init)) + } =0 + .plt : { *(.plt) } + .iplt : { *(.iplt) } + .text : + { + *(.text.unlikely .text.*_unlikely) + *(.text.exit .text.exit.*) + *(.text.startup .text.startup.*) + *(.text.hot .text.hot.*) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.glue_7t) *(.glue_7) *(.vfp11_veneer) *(.v4_bx) + } =0 + .fini : + { + KEEP (*(.fini)) + } =0 + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } + PROVIDE_HIDDEN (__exidx_start = .); + .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } + PROVIDE_HIDDEN (__exidx_end = .); + .eh_frame_hdr : { *(.eh_frame_hdr) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table + .gcc_except_table.*) } + /* These sections are generated by the Sun/Oracle C++ compiler. */ + .exception_ranges : ONLY_IF_RO { *(.exception_ranges + .exception_ranges*) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ +/* . = ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)); */ + /* Exception handling */ + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } + .exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) } + /* Thread Local Storage sections */ + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + } + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT(.fini_array.*))) + KEEP (*(.fini_array)) + PROVIDE_HIDDEN (__fini_array_end = .); + } + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) } + .dynamic : { *(.dynamic) } + .got : { *(.got.plt) *(.igot.plt) *(.got) *(.igot) } + .data : + { + __data_start = . ; + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + _edata = .; PROVIDE (edata = .); + __bss_start = .; + __bss_start__ = .; + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. + FIXME: Why do we need it? When there is no .bss section, we don't + pad the .data section. */ + . = ALIGN(. != 0 ? 32 / 8 : 1); + } + _bss_end__ = . ; __bss_end__ = . ; + . = ALIGN(32 / 8); + . = ALIGN(32 / 8); + __end__ = . ; + _end = .; PROVIDE (end = .); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* DWARF 3 */ + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + .stack 0x80000 : + { + _stack = .; + *(.stack) + } + .ARM.attributes 0 : { KEEP (*(.ARM.attributes)) KEEP (*(.gnu.attributes)) } + .note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) } + /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } +} diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..d130834 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,64 @@ + +# 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. + +# CMake build environment for the Valvers Raspberry-Pi bare metal tutorials + +# CMake 2.8.10 Documentation: http://www.cmake.org/cmake/help/v2.8.10/cmake.html + +cmake_minimum_required( VERSION 2.8 ) + +# Mark the language as C so that CMake doesn't try to test the C++ +# cross-compiler's ability to compile a simple program because that will fail +project( bare-metal-rpi-kernel C ASM ) + +# Add any C compiler flags here. The C flags concerned with processor tuning +# are in the toolchain files toolchain-arm-none-eabi-bcm2835.cmake, etc. +set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O4" ) +set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall" ) +set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -nostartfiles" ) +set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I ../includes/" ) + +# Set the linker flags so that we use our "custom" linker script +set( CMAKE_EXE_LINKER_FLAGS "-Wl,-T,${PROJECT_SOURCE_DIR}/CMakeLinker.x" ) + +AUX_SOURCE_DIRECTORY(includes/ kernelIncludes) +AUX_SOURCE_DIRECTORY(includes/rpi rpiIncludes) + +add_executable( kernel.elf + kernel.c + cstartup.c + cstubs.c + armStart.S + ${kernelIncludes} + ${rpiIncludes} +) + +add_custom_command( + TARGET kernel.elf POST_BUILD + COMMAND ${CMAKE_OBJCOPY} ./kernel.elf -O binary ./kernel.img + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + COMMENT "Convert the ELF output file to a binary image" ) diff --git a/cstartup.c b/cstartup.c new file mode 100644 index 0000000..34065b2 --- /dev/null +++ b/cstartup.c @@ -0,0 +1,61 @@ +/* + + Part of the Raspberry-Pi Bare Metal Tutorials + Copyright (c) 2013, 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. + +*/ + +extern int __bss_start__; +extern int __bss_end__; + +extern void kernel_main( unsigned int r0, unsigned int r1, unsigned int atags ); + +void _cstartup( unsigned int r0, unsigned int r1, unsigned int r2 ) +{ + int* bss = &__bss_start__; + int* bss_end = &__bss_end__; + + /* + Clear the BSS section + + See http://en.wikipedia.org/wiki/.bss for further information on the + BSS section + + See https://sourceware.org/newlib/libc.html#Stubs for further + information on the c-library stubs + */ + while( bss < bss_end ) + *bss++ = 0; + + /* We should never return from main ... */ + kernel_main( r0, r1, r2 ); + + /* ... but if we do, safely trap here */ + while(1) + { + /* EMPTY! */ + } +} diff --git a/cstubs.c b/cstubs.c new file mode 100644 index 0000000..d7bba4f --- /dev/null +++ b/cstubs.c @@ -0,0 +1,254 @@ +/* + + Part of the Raspberry-Pi Bare Metal Tutorials + Copyright (c) 2013-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. + +*/ + +/* For more information about this file, please visit: + https://sourceware.org/newlib/libc.html#Stubs + + These are the newlib C-Library stubs for the valvers Raspberry-Pi bare-metal + tutorial */ + +/* + Graceful failure is permitted by returning an error code. A minor + complication arises here: the C library must be compatible with development + environments that supply fully functional versions of these subroutines. + Such environments usually return error codes in a global errno. However, + the Red Hat newlib C library provides a macro definition for errno in the + header file errno.h, as part of its support for reentrant routines (see + Reentrancy). + + The bridge between these two interpretations of errno is straightforward: + the C library routines with OS interface calls capture the errno values + returned globally, and record them in the appropriate field of the + reentrancy structure (so that you can query them using the errno macro from + errno.h). + + This mechanism becomes visible when you write stub routines for OS + interfaces. You must include errno.h, then disable the macro, like this: +*/ +#include +#undef errno +extern int errno; + +/* Required include for fstat() */ +#include + +/* Required include for times() */ +#include + +/* Prototype for the UART write function */ +#include "rpi/aux.h" + +/* A pointer to a list of environment variables and their values. For a minimal + environment, this empty list is adequate: */ +char *__env[1] = {0}; +char **environ = __env; + +/* A helper function written in assembler to aid us in allocating memory */ +extern caddr_t _get_stack_pointer(void); + + +/* Never return from _exit as there's no OS to exit to, so instead we trap + here */ +void _exit( int status ) +{ + /* Stop the compiler complaining about unused variables by "using" it */ + (void)status; + + while(1) + { + /* TRAP HERE */ + } +} + + +/* There's currently no implementation of a file system because there's no + file system! */ +int _close( int file ) +{ + return -1; +} + + +/* Transfer control to a new process. Minimal implementation (for a system + without processes): */ +int execve( char *name, char **argv, char **env ) +{ + errno = ENOMEM; + return -1; +} + + +/* Create a new process. Minimal implementation (for a system without + processes): */ +int fork( void ) +{ + errno = EAGAIN; + return -1; +} + + +/* Status of an open file. For consistency with other minimal implementations + in these examples, all files are regarded as character special devices. The + sys/stat.h header file required is distributed in the include subdirectory + for this C library. */ +int _fstat( int file, struct stat *st ) +{ + st->st_mode = S_IFCHR; + return 0; +} + + +/* Process-ID; this is sometimes used to generate strings unlikely to conflict + with other processes. Minimal implementation, for a system without + processes: */ +int getpid( void ) +{ + return 1; +} + + +/* Query whether output stream is a terminal. For consistency with the other + minimal implementations, which only support output to stdout, this minimal + implementation is suggested: */ +int _isatty(int file) +{ + return 1; +} + + +/* Send a signal. Minimal implementation: */ +int kill( int pid, int sig ) +{ + errno = EINVAL; + return -1; +} + + +/* Establish a new name for an existing file. Minimal implementation: */ +int link( char *old, char *new ) +{ + errno = EMLINK; + return -1; +} + + +/* Set position in a file. Minimal implementation: */ +int _lseek(int file, int ptr, int dir) +{ + return 0; +} + + +/* Open a file. Minimal implementation: */ +int open( const char *name, int flags, int mode ) +{ + return -1; +} + + +/* Read from a file. Minimal implementation: */ +int _read( int file, char *ptr, int len ) +{ + return 0; +} + + +/* Increase program data space. As malloc and related functions depend on this, + it is useful to have a working implementation. The following suffices for a + standalone system; it exploits the symbol _end automatically defined by the + GNU linker. */ +caddr_t _sbrk( int incr ) +{ + extern char _end; + static char* heap_end = 0; + char* prev_heap_end; + + if( heap_end == 0 ) + heap_end = &_end; + + prev_heap_end = heap_end; + heap_end += incr; + + return (caddr_t)prev_heap_end; +} + + +/* Status of a file (by name). Minimal implementation: */ +int stat( const char *file, struct stat *st ) +{ + st->st_mode = S_IFCHR; + return 0; +} + + +/* Timing information for current process. Minimal implementation: */ +clock_t times( struct tms *buf ) +{ + return -1; +} + + +/* Remove a file's directory entry. Minimal implementation: */ +int unlink( char *name ) +{ + errno = ENOENT; + return -1; +} + + +/* Wait for a child process. Minimal implementation: */ +int wait( int *status ) +{ + errno = ECHILD; + return -1; +} + + +void outbyte( char b ) +{ + RPI_AuxMiniUartWrite( b ); +} + +/* Write to a file. libc subroutines will use this system routine for output to + all files, including stdout—so if you need to generate any output, for + example to a serial port for debugging, you should make your minimal write + capable of doing this. The following minimal implementation is an + incomplete example; it relies on a outbyte subroutine (not shown; typically, + you must write this in assembler from examples provided by your hardware + manufacturer) to actually perform the output. */ +int _write( int file, char *ptr, int len ) +{ + int todo; + + for( todo = 0; todo < len; todo++ ) + outbyte(*ptr++); + + return len; +} diff --git a/includes/kernel/util.c b/includes/kernel/util.c new file mode 100644 index 0000000..74c3ae0 --- /dev/null +++ b/includes/kernel/util.c @@ -0,0 +1,42 @@ +/** +arm-016-util.c +*/ +#include "util.h" + +void setColor(volatile unsigned char* fb, colour_t pixel, long x, long y, long pitch) +{ + int pixel_offset = ( x * ( SCREEN_DEPTH >> 3 ) ) + ( y * pitch ); + + int r = (int)( pixel.r * 0xFF ) & 0xFF; + int g = (int)( pixel.g * 0xFF ) & 0xFF; + int b = (int)( pixel.b * 0xFF ) & 0xFF; + int a = (int)( pixel.a * 0xFF ) & 0xFF; + + if( SCREEN_DEPTH == 32 ) + { + /* Four bytes to write */ + fb[ pixel_offset++ ] = r; + fb[ pixel_offset++ ] = g; + fb[ pixel_offset++ ] = b; + fb[ pixel_offset++ ] = a; + } + else if( SCREEN_DEPTH == 24 ) + { + /* Three bytes to write */ + fb[ pixel_offset++ ] = r; + fb[ pixel_offset++ ] = g; + fb[ pixel_offset++ ] = b; + } + else if( SCREEN_DEPTH == 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! */ + } +} + diff --git a/includes/kernel/util.h b/includes/kernel/util.h new file mode 100644 index 0000000..047e4f8 --- /dev/null +++ b/includes/kernel/util.h @@ -0,0 +1,33 @@ +/** +arm-016-util.h +*/ + + +#ifndef arm_016_util +#define arm_016_util + +#define SCREEN_WIDTH 1920 +#define SCREEN_HEIGHT 1080 +#define SCREEN_DEPTH 24 /* 16 or 32-bit */ + +#define COLOUR_DELTA 0.05 /* Float from 0 to 1 incremented by this amount */ + +typedef struct { + float r; + float g; + float b; + float a; + } colour_t; + + +#define dickbuttHeight 352 +#define dickbuttWidth 624 +#define dickbuttBytes 658945 + +extern const int dickbutt[dickbuttBytes]; + + +extern void setColor(volatile unsigned char* fb, colour_t pixel, long x, long y, long pitch); + + +#endif \ No newline at end of file diff --git a/includes/rpi/armtimer.c b/includes/rpi/armtimer.c new file mode 100644 index 0000000..8c7d5ee --- /dev/null +++ b/includes/rpi/armtimer.c @@ -0,0 +1,15 @@ + +#include +#include "armtimer.h" + +static rpi_arm_timer_t* rpiArmTimer = (rpi_arm_timer_t*)RPI_ARMTIMER_BASE; + +rpi_arm_timer_t* RPI_GetArmTimer(void) +{ + return rpiArmTimer; +} + +void RPI_ArmTimerInit(void) +{ + +} diff --git a/includes/rpi/armtimer.h b/includes/rpi/armtimer.h new file mode 100644 index 0000000..f259acc --- /dev/null +++ b/includes/rpi/armtimer.h @@ -0,0 +1,141 @@ +/* + Part of the Raspberry-Pi Bare Metal Tutorials + Copyright (c) 2013-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. + +*/ + +#ifndef RPI_ARMTIMER_H +#define RPI_ARMTIMER_H + +#include + +#include "base.h" + +/** @brief See the documentation for the ARM side timer (Section 14 of the + BCM2835 Peripherals PDF) */ +#define RPI_ARMTIMER_BASE ( PERIPHERAL_BASE + 0xB400 ) + +/** @brief 0 : 16-bit counters - 1 : 23-bit counter */ +#define RPI_ARMTIMER_CTRL_23BIT ( 1 << 1 ) + +#define RPI_ARMTIMER_CTRL_PRESCALE_1 ( 0 << 2 ) +#define RPI_ARMTIMER_CTRL_PRESCALE_16 ( 1 << 2 ) +#define RPI_ARMTIMER_CTRL_PRESCALE_256 ( 2 << 2 ) + +/** @brief 0 : Timer interrupt disabled - 1 : Timer interrupt enabled */ +#define RPI_ARMTIMER_CTRL_INT_ENABLE ( 1 << 5 ) +#define RPI_ARMTIMER_CTRL_INT_DISABLE ( 0 << 5 ) + +/** @brief 0 : Timer disabled - 1 : Timer enabled */ +#define RPI_ARMTIMER_CTRL_ENABLE ( 1 << 7 ) +#define RPI_ARMTIMER_CTRL_DISABLE ( 0 << 7 ) + + +/** @brief Section 14.2 of the BCM2835 Peripherals documentation details + the register layout for the ARM side timer */ +typedef struct { + + /** The timer load register sets the time for the timer to count down. + This value is loaded into the timer value register after the load + register has been written or if the timer-value register has counted + down to 0. */ + volatile uint32_t Load; + + /** This register holds the current timer value and is counted down when + the counter is running. It is counted down each timer clock until the + value 0 is reached. Then the value register is re-loaded from the + timer load register and the interrupt pending bit is set. The timer + count down speed is set by the timer pre-divide register. */ + volatile uint32_t Value; + + /** The standard SP804 timer control register consist of 8 bits but in the + BCM implementation there are more control bits for the extra features. + Control bits 0-7 are identical to the SP804 bits, albeit some + functionality of the SP804 is not implemented. All new control bits + start from bit 8 upwards. */ + volatile uint32_t Control; + + /** The timer IRQ clear register is write only. When writing this register + the interrupt-pending bit is cleared. When reading this register it + returns 0x544D5241 which is the ASCII reversed value for "ARMT". */ + volatile uint32_t IRQClear; + + /** The raw IRQ register is a read-only register. It shows the status of + the interrupt pending bit. 0 : The interrupt pending bits is clear. + 1 : The interrupt pending bit is set. + + The interrupt pending bits is set each time the value register is + counted down to zero. The interrupt pending bit can not by itself + generates interrupts. Interrupts can only be generated if the + interrupt enable bit is set. */ + volatile uint32_t RAWIRQ; + + /** The masked IRQ register is a read-only register. It shows the status + of the interrupt signal. It is simply a logical AND of the interrupt + pending bit and the interrupt enable bit. 0 : Interrupt line not + asserted. 1 :Interrupt line is asserted, (the interrupt pending and + the interrupt enable bit are set.) */ + volatile uint32_t MaskedIRQ; + + /** This register is a copy of the timer load register. The difference is + that a write to this register does not trigger an immediate reload of + the timer value register. Instead the timer load register value is + only accessed if the value register has finished counting down to + zero. */ + volatile uint32_t Reload; + + /** The Pre-divider register is not present in the SP804. The pre-divider + register is 10 bits wide and can be written or read from. This + register has been added as the SP804 expects a 1MHz clock which we do + not have. Instead the pre-divider takes the APB clock and divides it + down according to: + + timer_clock = apb_clock/(pre_divider+1) + + The reset value of this register is 0x7D so gives a divide by 126. */ + volatile uint32_t PreDivider; + + /** The free running counter is not present in the SP804. The free running + counter is a 32 bits wide read only register. The register is enabled + by setting bit 9 of the Timer control register. The free running + counter is incremented immediately after it is enabled. The timer can + not be reset but when enabled, will always increment and roll-over. + + The free running counter is also running from the APB clock and has + its own clock pre-divider controlled by bits 16-23 of the timer + control register. + + This register will be halted too if bit 8 of the control register is + set and the ARM is in Debug Halt mode. */ + volatile uint32_t FreeRunningCounter; + + } rpi_arm_timer_t; + + +extern rpi_arm_timer_t* RPI_GetArmTimer(void); +extern void RPI_ArmTimerInit(void); + +#endif diff --git a/includes/rpi/aux.c b/includes/rpi/aux.c new file mode 100644 index 0000000..2f41bad --- /dev/null +++ b/includes/rpi/aux.c @@ -0,0 +1,79 @@ + +#include "aux.h" +#include "base.h" +#include "gpio.h" + +static aux_t* auxillary = (aux_t*)AUX_BASE; + + +aux_t* RPI_GetAux( void ) +{ + return auxillary; +} + +/* Define the system clock frequency in MHz for the baud rate calculation. + This is clearly defined on the BCM2835 datasheet errata page: + http://elinux.org/BCM2835_datasheet_errata */ +#define SYS_FREQ 250000000 + +void RPI_AuxMiniUartInit( int baud, int bits ) +{ + volatile int i; + + /* As this is a mini uart the configuration is complete! Now just + enable the uart. Note from the documentation in section 2.1.1 of + the ARM peripherals manual: + + If the enable bits are clear you will have no access to a + peripheral. You can not even read or write the registers */ + auxillary->ENABLES = AUX_ENA_MINIUART; + + /* Disable interrupts for now */ + /* auxillary->IRQ &= ~AUX_IRQ_MU; */ + + auxillary->MU_IER = 0; + + /* Disable flow control,enable transmitter and receiver! */ + auxillary->MU_CNTL = 0; + + /* Decide between seven or eight-bit mode */ + if( bits == 8 ) + auxillary->MU_LCR = AUX_MULCR_8BIT_MODE; + else + auxillary->MU_LCR = 0; + + auxillary->MU_MCR = 0; + + /* Disable all interrupts from MU and clear the fifos */ + auxillary->MU_IER = 0; + + auxillary->MU_IIR = 0xC6; + + /* Transposed calculation from Section 2.2.1 of the ARM peripherals + manual */ + auxillary->MU_BAUD = ( SYS_FREQ / ( 8 * baud ) ) - 1; + + /* Setup GPIO 14 and 15 as alternative function 5 which is + UART 1 TXD/RXD. These need to be set before enabling the UART */ + RPI_SetGpioPinFunction( RPI_GPIO14, FS_ALT5 ); + RPI_SetGpioPinFunction( RPI_GPIO15, FS_ALT5 ); + + RPI_GetGpio()->GPPUD = 0; + for( i=0; i<150; i++ ) { } + RPI_GetGpio()->GPPUDCLK0 = ( 1 << 14 ); + for( i=0; i<150; i++ ) { } + RPI_GetGpio()->GPPUDCLK0 = 0; + + /* Disable flow control,enable transmitter and receiver! */ + auxillary->MU_CNTL = AUX_MUCNTL_TX_ENABLE; +} + + +void RPI_AuxMiniUartWrite( char c ) +{ + /* Wait until the UART has an empty space in the FIFO */ + while( ( auxillary->MU_LSR & AUX_MULSR_TX_EMPTY ) == 0 ) { } + + /* Write the character to the FIFO for transmission */ + auxillary->MU_IO = c; +} diff --git a/includes/rpi/aux.h b/includes/rpi/aux.h new file mode 100644 index 0000000..68732d1 --- /dev/null +++ b/includes/rpi/aux.h @@ -0,0 +1,187 @@ +/* + + Part of the Raspberry-Pi Bare Metal Tutorials + Copyright (c) 2013-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. + +*/ + +#ifndef RPI_AUX_H +#define RPI_AUX_H + +#include "base.h" + +/* Although these values were originally from the BCM2835 Arm peripherals PDF + it's clear that was rushed and has some glaring errors - so these values + may appear to be different. These values have been changed due to data on + the elinux BCM2835 datasheet errata: + http://elinux.org/BCM2835_datasheet_errata */ + +#define AUX_BASE ( PERIPHERAL_BASE + 0x215000 ) + +#define AUX_ENA_MINIUART ( 1 << 0 ) +#define AUX_ENA_SPI1 ( 1 << 1 ) +#define AUX_ENA_SPI2 ( 1 << 2 ) + +#define AUX_IRQ_SPI2 ( 1 << 2 ) +#define AUX_IRQ_SPI1 ( 1 << 1 ) +#define AUX_IRQ_MU ( 1 << 0 ) + +#define AUX_MULCR_8BIT_MODE ( 3 << 0 ) /* See errata for this value */ +#define AUX_MULCR_BREAK ( 1 << 6 ) +#define AUX_MULCR_DLAB_ACCESS ( 1 << 7 ) + +#define AUX_MUMCR_RTS ( 1 << 1 ) + +#define AUX_MULSR_DATA_READY ( 1 << 0 ) +#define AUX_MULSR_RX_OVERRUN ( 1 << 1 ) +#define AUX_MULSR_TX_EMPTY ( 1 << 5 ) +#define AUX_MULSR_TX_IDLE ( 1 << 6 ) + +#define AUX_MUMSR_CTS ( 1 << 5 ) + +#define AUX_MUCNTL_RX_ENABLE ( 1 << 0 ) +#define AUX_MUCNTL_TX_ENABLE ( 1 << 1 ) +#define AUX_MUCNTL_RTS_FLOW ( 1 << 2 ) +#define AUX_MUCNTL_CTS_FLOW ( 1 << 3 ) +#define AUX_MUCNTL_RTS_FIFO ( 3 << 4 ) +#define AUX_MUCNTL_RTS_ASSERT ( 1 << 6 ) +#define AUX_MUCNTL_CTS_ASSERT ( 1 << 7 ) + +#define AUX_MUSTAT_SYMBOL_AV ( 1 << 0 ) +#define AUX_MUSTAT_SPACE_AV ( 1 << 1 ) +#define AUX_MUSTAT_RX_IDLE ( 1 << 2 ) +#define AUX_MUSTAT_TX_IDLE ( 1 << 3 ) +#define AUX_MUSTAT_RX_OVERRUN ( 1 << 4 ) +#define AUX_MUSTAT_TX_FIFO_FULL ( 1 << 5 ) +#define AUX_MUSTAT_RTS ( 1 << 6 ) +#define AUX_MUSTAT_CTS ( 1 << 7 ) +#define AUX_MUSTAT_TX_EMPTY ( 1 << 8 ) +#define AUX_MUSTAT_TX_DONE ( 1 << 9 ) +#define AUX_MUSTAT_RX_FIFO_LEVEL ( 7 << 16 ) +#define AUX_MUSTAT_TX_FIFO_LEVEL ( 7 << 24 ) + + +#define FSEL0(x) ( x ) +#define FSEL1(x) ( x << 3 ) +#define FSEL2(x) ( x << 6 ) +#define FSEL3(x) ( x << 9 ) +#define FSEL4(x) ( x << 12 ) +#define FSEL5(x) ( x << 15 ) +#define FSEL6(x) ( x << 18 ) +#define FSEL7(x) ( x << 21 ) +#define FSEL8(x) ( x << 24 ) +#define FSEL9(x) ( x << 27 ) + +#define FSEL10(x) ( x ) +#define FSEL11(x) ( x << 3 ) +#define FSEL12(x) ( x << 6 ) +#define FSEL13(x) ( x << 9 ) +#define FSEL14(x) ( x << 12 ) +#define FSEL15(x) ( x << 15 ) +#define FSEL16(x) ( x << 18 ) +#define FSEL17(x) ( x << 21 ) +#define FSEL18(x) ( x << 24 ) +#define FSEL19(x) ( x << 27 ) + +#define FSEL20(x) ( x ) +#define FSEL21(x) ( x << 3 ) +#define FSEL22(x) ( x << 6 ) +#define FSEL23(x) ( x << 9 ) +#define FSEL24(x) ( x << 12 ) +#define FSEL25(x) ( x << 15 ) +#define FSEL26(x) ( x << 18 ) +#define FSEL27(x) ( x << 21 ) +#define FSEL28(x) ( x << 24 ) +#define FSEL29(x) ( x << 27 ) + +#define FSEL30(x) ( x ) +#define FSEL31(x) ( x << 3 ) +#define FSEL32(x) ( x << 6 ) +#define FSEL33(x) ( x << 9 ) +#define FSEL34(x) ( x << 12 ) +#define FSEL35(x) ( x << 15 ) +#define FSEL36(x) ( x << 18 ) +#define FSEL37(x) ( x << 21 ) +#define FSEL38(x) ( x << 24 ) +#define FSEL39(x) ( x << 27 ) + +#define FSEL40(x) ( x ) +#define FSEL41(x) ( x << 3 ) +#define FSEL42(x) ( x << 6 ) +#define FSEL43(x) ( x << 9 ) +#define FSEL44(x) ( x << 12 ) +#define FSEL45(x) ( x << 15 ) +#define FSEL46(x) ( x << 18 ) +#define FSEL47(x) ( x << 21 ) +#define FSEL48(x) ( x << 24 ) +#define FSEL49(x) ( x << 27 ) + +#define FSEL50(x) ( x ) +#define FSEL51(x) ( x << 3 ) +#define FSEL52(x) ( x << 6 ) +#define FSEL53(x) ( x << 9 ) + + +typedef struct { + volatile unsigned int IRQ; + volatile unsigned int ENABLES; + + volatile unsigned int reserved1[((0x40 - 0x04) / 4) - 1]; + + volatile unsigned int MU_IO; + volatile unsigned int MU_IER; + volatile unsigned int MU_IIR; + volatile unsigned int MU_LCR; + volatile unsigned int MU_MCR; + volatile unsigned int MU_LSR; + volatile unsigned int MU_MSR; + volatile unsigned int MU_SCRATCH; + volatile unsigned int MU_CNTL; + volatile unsigned int MU_STAT; + volatile unsigned int MU_BAUD; + + volatile unsigned int reserved2[(0x80 - 0x68) / 4]; + + volatile unsigned int SPI0_CNTL0; + volatile unsigned int SPI0_CNTL1; + volatile unsigned int SPI0_STAT; + volatile unsigned int SPI0_IO; + volatile unsigned int SPI0_PEEK; + + volatile unsigned int reserved3[(0xC0 - 0x94) / 4]; + + volatile unsigned int SPI1_CNTL0; + volatile unsigned int SPI1_CNTL1; + volatile unsigned int SPI1_STAT; + volatile unsigned int SPI1_IO; + volatile unsigned int SPI1_PEEK; + } aux_t; + +extern aux_t* RPI_GetAux( void ); +extern void RPI_AuxMiniUartInit( int baud, int bits ); +extern void RPI_AuxMiniUartWrite( char c ); + +#endif diff --git a/includes/rpi/base.h b/includes/rpi/base.h new file mode 100644 index 0000000..777ad23 --- /dev/null +++ b/includes/rpi/base.h @@ -0,0 +1,53 @@ +/* + + Part of the Raspberry-Pi Bare Metal Tutorials + Copyright (c) 2013-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. + +*/ + +#ifndef RPI_BASE_H +#define RPI_BASE_H + +#include + +#ifdef RPI2 + #define PERIPHERAL_BASE 0x3F000000UL +#else + #define PERIPHERAL_BASE 0x20000000UL +#endif + +typedef volatile uint32_t rpi_reg_rw_t; +typedef volatile const uint32_t rpi_reg_ro_t; +typedef volatile uint32_t rpi_reg_wo_t; + +typedef volatile uint64_t rpi_wreg_rw_t; +typedef volatile const uint64_t rpi_wreg_ro_t; + + +int GET32(int index); +void PUT32(int index, int value); + +#endif diff --git a/includes/rpi/gpio.c b/includes/rpi/gpio.c new file mode 100644 index 0000000..5cc08e8 --- /dev/null +++ b/includes/rpi/gpio.c @@ -0,0 +1,115 @@ + +#include +#include "gpio.h" + +static rpi_gpio_t* rpiGpio = (rpi_gpio_t*)RPI_GPIO_BASE; + + +rpi_gpio_t* RPI_GetGpio(void) +{ + return rpiGpio; +} + + +void RPI_SetGpioPinFunction( rpi_gpio_pin_t gpio, rpi_gpio_alt_function_t func ) +{ + rpi_reg_rw_t* fsel_reg = &((rpi_reg_rw_t*)rpiGpio)[ gpio / 10 ]; + rpi_reg_rw_t fsel_copy = *fsel_reg; + fsel_copy &= ~( FS_MASK << ( ( gpio % 10 ) * 3 ) ); + fsel_copy |= (func << ( ( gpio % 10 ) * 3 ) ); + *fsel_reg = fsel_copy; +} + + +void RPI_SetGpioOutput( rpi_gpio_pin_t gpio ) +{ + RPI_SetGpioPinFunction( gpio, FS_OUTPUT ); +} + + +void RPI_SetGpioInput( rpi_gpio_pin_t gpio ) +{ + RPI_SetGpioPinFunction( gpio, FS_INPUT ); +} + + +rpi_gpio_value_t RPI_GetGpioValue( rpi_gpio_pin_t gpio ) +{ + rpi_gpio_value_t result = RPI_IO_UNKNOWN; + + switch( gpio / 32 ) + { + case 0: + result = rpiGpio->GPLEV0 & ( 1 << gpio ); + break; + + case 1: + result = rpiGpio->GPLEV1 & ( 1 << ( gpio - 32 ) ); + break; + + default: + break; + } + + if( result != RPI_IO_UNKNOWN ) + { + if( result ) + result = RPI_IO_HI; + } + + return result; +} + + +void RPI_ToggleGpio( rpi_gpio_pin_t gpio ) +{ + if( RPI_GetGpioValue( gpio ) ) + RPI_SetGpioLo( gpio ); + else + RPI_SetGpioHi( gpio ); +} + + +void RPI_SetGpioHi( rpi_gpio_pin_t gpio ) +{ + switch( gpio / 32 ) + { + case 0: + rpiGpio->GPSET0 = ( 1 << gpio ); + break; + + case 1: + rpiGpio->GPSET1 = ( 1 << ( gpio - 32 ) ); + break; + + default: + break; + } +} + + +void RPI_SetGpioLo( rpi_gpio_pin_t gpio ) +{ + switch( gpio / 32 ) + { + case 0: + rpiGpio->GPCLR0 = ( 1 << gpio ); + break; + + case 1: + rpiGpio->GPCLR1 = ( 1 << ( gpio - 32 ) ); + break; + + default: + break; + } +} + + +void RPI_SetGpioValue( rpi_gpio_pin_t gpio, rpi_gpio_value_t value ) +{ + if( ( value == RPI_IO_LO ) || ( value == RPI_IO_OFF ) ) + RPI_SetGpioLo( gpio ); + else if( ( value == RPI_IO_HI ) || ( value == RPI_IO_ON ) ) + RPI_SetGpioHi( gpio ); +} diff --git a/includes/rpi/gpio.h b/includes/rpi/gpio.h new file mode 100644 index 0000000..6205318 --- /dev/null +++ b/includes/rpi/gpio.h @@ -0,0 +1,211 @@ +/* + + Part of the Raspberry-Pi Bare Metal Tutorials + Copyright (c) 2013-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. + +*/ + +#ifndef RPI_GPIO_H +#define RPI_GPIO_H + +#include "base.h" + +/** The base address of the GPIO peripheral (ARM Physical Address) */ +#define RPI_GPIO_BASE ( PERIPHERAL_BASE + 0x200000UL ) + +#if defined( RPIBPLUS ) || defined( RPI2 ) + #define LED_GPFSEL GPFSEL4 + #define LED_GPFBIT 21 + #define LED_GPSET GPSET1 + #define LED_GPCLR GPCLR1 + #define LED_GPIO_BIT 15 + #define LED_ON() do { RPI_GetGpio()->LED_GPCLR = ( 1 << LED_GPIO_BIT ); } while( 0 ) + #define LED_OFF() do { RPI_GetGpio()->LED_GPSET = ( 1 << LED_GPIO_BIT ); } while( 0 ) +#else + #define LED_GPFSEL GPFSEL1 + #define LED_GPFBIT 18 + #define LED_GPSET GPSET0 + #define LED_GPCLR GPCLR0 + #define LED_GPIO_BIT 16 + #define LED_ON() do { RPI_GetGpio()->LED_GPSET = ( 1 << LED_GPIO_BIT ); } while( 0 ) + #define LED_OFF() do { RPI_GetGpio()->LED_GPCLR = ( 1 << LED_GPIO_BIT ); } while( 0 ) +#endif + +typedef enum { + FS_INPUT = 0, + FS_OUTPUT, + FS_ALT5, + FS_ALT4, + FS_ALT0, + FS_ALT1, + FS_ALT2, + FS_ALT3, + } rpi_gpio_alt_function_t; + +/* A mask to be able to clear the bits in the register before setting the + value we require */ +#define FS_MASK (7) + +typedef enum { + RPI_GPIO0 = 0, + RPI_GPIO1, + RPI_GPIO2, + RPI_GPIO3, + RPI_GPIO4, + RPI_GPIO5, + RPI_GPIO6, + RPI_GPIO7, + RPI_GPIO8, + RPI_GPIO9, + RPI_GPIO10 = 10, + RPI_GPIO11, + RPI_GPIO12, + RPI_GPIO13, + RPI_GPIO14, + RPI_GPIO15, + RPI_GPIO16, + RPI_GPIO17, + RPI_GPIO18, + RPI_GPIO19, + RPI_GPIO20 = 20, + RPI_GPIO21, + RPI_GPIO22, + RPI_GPIO23, + RPI_GPIO24, + RPI_GPIO25, + RPI_GPIO26, + RPI_GPIO27, + RPI_GPIO28, + RPI_GPIO29, + RPI_GPIO30 = 30, + RPI_GPIO31, + RPI_GPIO32, + RPI_GPIO33, + RPI_GPIO34, + RPI_GPIO35, + RPI_GPIO36, + RPI_GPIO37, + RPI_GPIO38, + RPI_GPIO39, + RPI_GPIO40 = 40, + RPI_GPIO41, + RPI_GPIO42, + RPI_GPIO43, + RPI_GPIO44, + RPI_GPIO45, + RPI_GPIO46, + RPI_GPIO47, + RPI_GPIO48, + RPI_GPIO49, + RPI_GPIO50 = 50, + RPI_GPIO51, + RPI_GPIO52, + RPI_GPIO53, + } rpi_gpio_pin_t; + + +/** The GPIO Peripheral is described in section 6 of the BCM2835 Peripherals + documentation. + + There are 54 general-purpose I/O (GPIO) lines split into two banks. All + GPIO pins have at least two alternative functions within BCM. The + alternate functions are usually peripheral IO and a single peripheral + may appear in each bank to allow flexibility on the choice of IO voltage. + Details of alternative functions are given in section 6.2. Alternative + Function Assignments. + + The GPIO peripheral has three dedicated interrupt lines. These lines are + triggered by the setting of bits in the event detect status register. Each + bank has its’ own interrupt line with the third line shared between all + bits. + + The Alternate function table also has the pull state (pull-up/pull-down) + which is applied after a power down. */ +typedef struct { + rpi_reg_rw_t GPFSEL0; + rpi_reg_rw_t GPFSEL1; + rpi_reg_rw_t GPFSEL2; + rpi_reg_rw_t GPFSEL3; + rpi_reg_rw_t GPFSEL4; + rpi_reg_rw_t GPFSEL5; + rpi_reg_ro_t Reserved0; + rpi_reg_wo_t GPSET0; + rpi_reg_wo_t GPSET1; + rpi_reg_ro_t Reserved1; + rpi_reg_wo_t GPCLR0; + rpi_reg_wo_t GPCLR1; + rpi_reg_ro_t Reserved2; + rpi_reg_wo_t GPLEV0; + rpi_reg_wo_t GPLEV1; + rpi_reg_ro_t Reserved3; + rpi_reg_wo_t GPEDS0; + rpi_reg_wo_t GPEDS1; + rpi_reg_ro_t Reserved4; + rpi_reg_wo_t GPREN0; + rpi_reg_wo_t GPREN1; + rpi_reg_ro_t Reserved5; + rpi_reg_wo_t GPFEN0; + rpi_reg_wo_t GPFEN1; + rpi_reg_ro_t Reserved6; + rpi_reg_wo_t GPHEN0; + rpi_reg_wo_t GPHEN1; + rpi_reg_ro_t Reserved7; + rpi_reg_wo_t GPLEN0; + rpi_reg_wo_t GPLEN1; + rpi_reg_ro_t Reserved8; + rpi_reg_wo_t GPAREN0; + rpi_reg_wo_t GPAREN1; + rpi_reg_ro_t Reserved9; + rpi_reg_wo_t GPAFEN0; + rpi_reg_wo_t GPAFEN1; + rpi_reg_ro_t Reserved10; + rpi_reg_wo_t GPPUD; + rpi_reg_wo_t GPPUDCLK0; + rpi_reg_wo_t GPPUDCLK1; + rpi_reg_ro_t Reserved11; + } rpi_gpio_t; + + +typedef enum { + RPI_IO_LO = 0, + RPI_IO_HI, + RPI_IO_ON, + RPI_IO_OFF, + RPI_IO_UNKNOWN, + } rpi_gpio_value_t; + + +extern rpi_gpio_t* RPI_GetGpio(void); +extern void RPI_SetGpioPinFunction( rpi_gpio_pin_t gpio, rpi_gpio_alt_function_t func ); +extern void RPI_SetGpioOutput( rpi_gpio_pin_t gpio ); +extern void RPI_SetGpioInput( rpi_gpio_pin_t gpio ); +extern rpi_gpio_value_t RPI_GetGpioValue( rpi_gpio_pin_t gpio ); +extern void RPI_SetGpioHi( rpi_gpio_pin_t gpio ); +extern void RPI_SetGpioLo( rpi_gpio_pin_t gpio ); +extern void RPI_SetGpioValue( rpi_gpio_pin_t gpio, rpi_gpio_value_t value ); +extern void RPI_ToggleGpio( rpi_gpio_pin_t gpio ); + +#endif diff --git a/includes/rpi/interrupts.c b/includes/rpi/interrupts.c new file mode 100644 index 0000000..85bf253 --- /dev/null +++ b/includes/rpi/interrupts.c @@ -0,0 +1,177 @@ + +#include +#include + +#include "armtimer.h" +#include "base.h" +#include "gpio.h" +#include "interrupts.h" + +/** @brief The BCM2835/6 Interupt controller peripheral at it's base address */ +static rpi_irq_controller_t* rpiIRQController = + (rpi_irq_controller_t*)RPI_INTERRUPT_CONTROLLER_BASE; + +volatile int calculate_frame_count = 0; + +/** + @brief Return the IRQ Controller register set +*/ +rpi_irq_controller_t* RPI_GetIrqController( void ) +{ + return rpiIRQController; +} + + +/** + @brief The Reset vector interrupt handler + + This can never be called, since an ARM core reset would also reset the + GPU and therefore cause the GPU to start running code again until + the ARM is handed control at the end of boot loading +*/ +void __attribute__((interrupt("ABORT"))) reset_vector(void) +{ + while( 1 ) + { + LED_ON(); + } +} + +/** + @brief The undefined instruction interrupt handler + + If an undefined intstruction is encountered, the CPU will start + executing this function. Just trap here as a debug solution. +*/ +void __attribute__((interrupt("UNDEF"))) undefined_instruction_vector(void) +{ + while( 1 ) + { + /* Do Nothing! */ + LED_ON(); + } +} + + +/** + @brief The supervisor call interrupt handler + + The CPU will start executing this function. Just trap here as a debug + solution. +*/ +void __attribute__((interrupt("SWI"))) software_interrupt_vector(void) +{ + while( 1 ) + { + /* Do Nothing! */ + LED_ON(); + } +} + + +/** + @brief The prefetch abort interrupt handler + + The CPU will start executing this function. Just trap here as a debug + solution. +*/ +void __attribute__((interrupt("ABORT"))) prefetch_abort_vector(void) +{ + while( 1 ) + { + LED_ON(); + } +} + + +/** + @brief The Data Abort interrupt handler + + The CPU will start executing this function. Just trap here as a debug + solution. +*/ +void __attribute__((interrupt("ABORT"))) data_abort_vector(void) +{ + while( 1 ) + { + LED_ON(); + } +} + + +/** + @brief The IRQ Interrupt handler + + This handler is run every time an interrupt source is triggered. It's + up to the handler to determine the source of the interrupt and most + importantly clear the interrupt flag so that the interrupt won't + immediately put us back into the start of the handler again. +*/ +void __attribute__((interrupt("IRQ"))) interrupt_vector(void) +{ + static int lit = 0; + static int ticks = 0; + static int seconds = 0; + + /* Clear the ARM Timer interrupt - it's the only interrupt we have + enabled, so we want don't have to work out which interrupt source + caused us to interrupt */ + RPI_GetArmTimer()->IRQClear = 1; + + ticks++; + if( ticks > 1 ) + { + ticks = 0; + + /* Calculate the FPS once a minute */ + seconds++; + if( seconds > 59 ) + { + seconds = 0; + calculate_frame_count = 1; + } + } + + /* Flip the LED */ + if( lit ) + { + LED_OFF(); + lit = 0; + } + else + { + LED_ON(); + lit = 1; + } +} + + +/** + @brief The FIQ Interrupt Handler + + The FIQ handler can only be allocated to one interrupt source. The FIQ has + a full CPU shadow register set. Upon entry to this function the CPU + switches to the shadow register set so that there is no need to save + registers before using them in the interrupt. + + In C you can't see the difference between the IRQ and the FIQ interrupt + handlers except for the FIQ knowing it's source of interrupt as there can + only be one source, but the prologue and epilogue code is quite different. + It's much faster on the FIQ interrupt handler. + + The prologue is the code that the compiler inserts at the start of the + function, if you like, think of the opening curly brace of the function as + being the prologue code. For the FIQ interrupt handler this is nearly + empty because the CPU has switched to a fresh set of registers, there's + nothing we need to save. + + The epilogue is the code that the compiler inserts at the end of the + function, if you like, think of the closing curly brace of the function as + being the epilogue code. For the FIQ interrupt handler this is nearly + empty because the CPU has switched to a fresh set of registers and so has + not altered the main set of registers. +*/ +void __attribute__((interrupt("FIQ"))) fast_interrupt_vector(void) +{ + +} diff --git a/includes/rpi/interrupts.h b/includes/rpi/interrupts.h new file mode 100644 index 0000000..34e3705 --- /dev/null +++ b/includes/rpi/interrupts.h @@ -0,0 +1,76 @@ +/* + + Part of the Raspberry-Pi Bare Metal Tutorials + Copyright (c) 2013, 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. + +*/ + +#ifndef RPI_INTERRUPTS_H +#define RPI_INTERRUPTS_H + +#include + +#include "base.h" + +/** @brief See Section 7.5 of the BCM2836 ARM Peripherals documentation, the base + address of the controller is actually xxxxB000, but there is a 0x200 offset + to the first addressable register for the interrupt controller, so offset the + base to the first register */ +#define RPI_INTERRUPT_CONTROLLER_BASE ( PERIPHERAL_BASE + 0xB200 ) + +/** @brief Bits in the Enable_Basic_IRQs register to enable various interrupts. + See the BCM2835 ARM Peripherals manual, section 7.5 */ +#define RPI_BASIC_ARM_TIMER_IRQ (1 << 0) +#define RPI_BASIC_ARM_MAILBOX_IRQ (1 << 1) +#define RPI_BASIC_ARM_DOORBELL_0_IRQ (1 << 2) +#define RPI_BASIC_ARM_DOORBELL_1_IRQ (1 << 3) +#define RPI_BASIC_GPU_0_HALTED_IRQ (1 << 4) +#define RPI_BASIC_GPU_1_HALTED_IRQ (1 << 5) +#define RPI_BASIC_ACCESS_ERROR_1_IRQ (1 << 6) +#define RPI_BASIC_ACCESS_ERROR_0_IRQ (1 << 7) + + +/** @brief The interrupt controller memory mapped register set */ +typedef struct { + volatile uint32_t IRQ_basic_pending; + volatile uint32_t IRQ_pending_1; + volatile uint32_t IRQ_pending_2; + volatile uint32_t FIQ_control; + volatile uint32_t Enable_IRQs_1; + volatile uint32_t Enable_IRQs_2; + volatile uint32_t Enable_Basic_IRQs; + volatile uint32_t Disable_IRQs_1; + volatile uint32_t Disable_IRQs_2; + volatile uint32_t Disable_Basic_IRQs; + } rpi_irq_controller_t; + +extern volatile int calculate_frame_count; + +/* Found in the *start.S file, implemented in assembler */ +extern void _enable_interrupts( void ); +extern rpi_irq_controller_t* RPI_GetIrqController( void ); + +#endif diff --git a/includes/rpi/mailbox-interface.c b/includes/rpi/mailbox-interface.c new file mode 100644 index 0000000..5d19eb7 --- /dev/null +++ b/includes/rpi/mailbox-interface.c @@ -0,0 +1,252 @@ +/* + + 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 +#include +#include + +#include "mailbox.h" +#include "mailbox-interface.h" + +/* Make sure the property tag buffer is aligned to a 16-byte boundary because + we only have 28-bits available in the property interface protocol to pass + the address of the buffer to the VC. */ +static int pt[8192] __attribute__((aligned(16))); +static int pt_index = 0; + + +void RPI_PropertyInit( void ) +{ + /* Fill in the size on-the-fly */ + pt[PT_OSIZE] = 12; + + /* Process request (All other values are reserved!) */ + pt[PT_OREQUEST_OR_RESPONSE] = 0; + + /* First available data slot */ + pt_index = 2; + + /* NULL tag to terminate tag list */ + pt[pt_index] = 0; +} + +/** + @brief Add a property tag to the current tag list. Data can be included. All data is uint32_t + @param tag +*/ +void RPI_PropertyAddTag( rpi_mailbox_tag_t tag, ... ) +{ + va_list vl; + va_start( vl, tag ); + + pt[pt_index++] = tag; + + switch( tag ) + { + case TAG_GET_FIRMWARE_VERSION: + case TAG_GET_BOARD_MODEL: + case TAG_GET_BOARD_REVISION: + case TAG_GET_BOARD_MAC_ADDRESS: + case TAG_GET_BOARD_SERIAL: + case TAG_GET_ARM_MEMORY: + case TAG_GET_VC_MEMORY: + case TAG_GET_DMA_CHANNELS: + /* Provide an 8-byte buffer for the response */ + pt[pt_index++] = 8; + pt[pt_index++] = 0; /* Request */ + pt_index += 2; + break; + + case TAG_GET_CLOCKS: + case TAG_GET_COMMAND_LINE: + /* Provide a 256-byte buffer */ + pt[pt_index++] = 256; + pt[pt_index++] = 0; /* Request */ + pt_index += 256 >> 2; + break; + + case TAG_ALLOCATE_BUFFER: + case TAG_GET_MAX_CLOCK_RATE: + case TAG_GET_MIN_CLOCK_RATE: + case TAG_GET_CLOCK_RATE: + pt[pt_index++] = 8; + pt[pt_index++] = 0; /* Request */ + pt[pt_index++] = va_arg( vl, int ); + pt[pt_index++] = 0; + break; + + case TAG_SET_CLOCK_RATE: + pt[pt_index++] = 12; + pt[pt_index++] = 0; /* Request */ + pt[pt_index++] = va_arg( vl, int ); /* Clock ID */ + pt[pt_index++] = va_arg( vl, int ); /* Rate (in Hz) */ + pt[pt_index++] = va_arg( vl, int ); /* Skip turbo setting if == 1 */ + break; + + case TAG_GET_PHYSICAL_SIZE: + case TAG_SET_PHYSICAL_SIZE: + case TAG_TEST_PHYSICAL_SIZE: + case TAG_GET_VIRTUAL_SIZE: + case TAG_SET_VIRTUAL_SIZE: + case TAG_TEST_VIRTUAL_SIZE: + case TAG_GET_VIRTUAL_OFFSET: + case TAG_SET_VIRTUAL_OFFSET: + pt[pt_index++] = 8; + pt[pt_index++] = 0; /* Request */ + + if( ( tag == TAG_SET_PHYSICAL_SIZE ) || + ( tag == TAG_SET_VIRTUAL_SIZE ) || + ( tag == TAG_SET_VIRTUAL_OFFSET ) || + ( tag == TAG_TEST_PHYSICAL_SIZE ) || + ( tag == TAG_TEST_VIRTUAL_SIZE ) ) + { + pt[pt_index++] = va_arg( vl, int ); /* Width */ + pt[pt_index++] = va_arg( vl, int ); /* Height */ + } + else + { + pt_index += 2; + } + break; + + case TAG_GET_ALPHA_MODE: + case TAG_SET_ALPHA_MODE: + case TAG_GET_DEPTH: + case TAG_SET_DEPTH: + case TAG_GET_PIXEL_ORDER: + case TAG_SET_PIXEL_ORDER: + case TAG_GET_PITCH: + pt[pt_index++] = 4; + pt[pt_index++] = 0; /* Request */ + + if( ( tag == TAG_SET_DEPTH ) || + ( tag == TAG_SET_PIXEL_ORDER ) || + ( tag == TAG_SET_ALPHA_MODE ) ) + { + /* Colour Depth, bits-per-pixel \ Pixel Order State */ + pt[pt_index++] = va_arg( vl, int ); + } + else + { + pt_index += 1; + } + break; + + case TAG_GET_OVERSCAN: + case TAG_SET_OVERSCAN: + pt[pt_index++] = 16; + pt[pt_index++] = 0; /* Request */ + + if( ( tag == TAG_SET_OVERSCAN ) ) + { + pt[pt_index++] = va_arg( vl, int ); /* Top pixels */ + pt[pt_index++] = va_arg( vl, int ); /* Bottom pixels */ + pt[pt_index++] = va_arg( vl, int ); /* Left pixels */ + pt[pt_index++] = va_arg( vl, int ); /* Right pixels */ + } + else + { + pt_index += 4; + } + break; + + default: + /* Unsupported tags, just remove the tag from the list */ + pt_index--; + break; + } + + /* Make sure the tags are 0 terminated to end the list and update the buffer size */ + pt[pt_index] = 0; + + va_end( vl ); +} + + +int RPI_PropertyProcess( void ) +{ + int result; + +#if( PRINT_PROP_DEBUG == 1 ) + printf( "%s Length: %d\r\n", __func__, pt[PT_OSIZE] ); +#endif + /* Fill in the size of the buffer */ + pt[PT_OSIZE] = ( pt_index + 1 ) << 2; + pt[PT_OREQUEST_OR_RESPONSE] = 0; + +#if( PRINT_PROP_DEBUG == 1 ) + for( i = 0; i < (pt[PT_OSIZE] >> 2); i++ ) + printf( "Request: %3d %8.8X\r\n", i, pt[i] ); +#endif + RPI_Mailbox0Write( MB0_TAGS_ARM_TO_VC, (unsigned int)pt ); + + result = RPI_Mailbox0Read( MB0_TAGS_ARM_TO_VC ); + +#if( PRINT_PROP_DEBUG == 1 ) + for( i = 0; i < (pt[PT_OSIZE] >> 2); i++ ) + printf( "Response: %3d %8.8X\r\n", i, pt[i] ); +#endif + return result; +} + + +rpi_mailbox_property_t* RPI_PropertyGet( rpi_mailbox_tag_t tag ) +{ + static rpi_mailbox_property_t property; + int* tag_buffer = NULL; + + property.tag = tag; + + /* Get the tag from the buffer. Start at the first tag position */ + int index = 2; + + while( index < ( pt[PT_OSIZE] >> 2 ) ) + { + /* printf( "Test Tag: [%d] %8.8X\r\n", index, pt[index] ); */ + if( pt[index] == tag ) + { + tag_buffer = &pt[index]; + break; + } + + /* Progress to the next tag if we haven't yet discovered the tag */ + index += ( pt[index + 1] >> 2 ) + 3; + } + + /* Return NULL of the property tag cannot be found in the buffer */ + if( tag_buffer == NULL ) + return NULL; + + /* Return the required data */ + property.byte_length = tag_buffer[T_ORESPONSE] & 0xFFFF; + memcpy( property.data.buffer_8, &tag_buffer[T_OVALUE], property.byte_length ); + + return &property; +} diff --git a/includes/rpi/mailbox-interface.h b/includes/rpi/mailbox-interface.h new file mode 100644 index 0000000..b6b024a --- /dev/null +++ b/includes/rpi/mailbox-interface.h @@ -0,0 +1,170 @@ +/* + + 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. + +*/ + +#ifndef RPI_MAILBOX_INTERFACE_H +#define RPI_MAILBOX_INTERFACE_H + +/** + @brief An enum of the RPI->Videocore firmware mailbox property interface + properties. Further details are available from + https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface +*/ +typedef enum { + /* Videocore */ + TAG_GET_FIRMWARE_VERSION = 0x1, + + /* Hardware */ + TAG_GET_BOARD_MODEL = 0x10001, + TAG_GET_BOARD_REVISION, + TAG_GET_BOARD_MAC_ADDRESS, + TAG_GET_BOARD_SERIAL, + TAG_GET_ARM_MEMORY, + TAG_GET_VC_MEMORY, + TAG_GET_CLOCKS, + + /* Config */ + TAG_GET_COMMAND_LINE = 0x50001, + + /* Shared resource management */ + TAG_GET_DMA_CHANNELS = 0x60001, + + /* Power */ + TAG_GET_POWER_STATE = 0x20001, + TAG_GET_TIMING, + TAG_SET_POWER_STATE = 0x28001, + + /* Clocks */ + TAG_GET_CLOCK_STATE = 0x30001, + TAG_SET_CLOCK_STATE = 0x38001, + TAG_GET_CLOCK_RATE = 0x30002, + TAG_SET_CLOCK_RATE = 0x38002, + TAG_GET_MAX_CLOCK_RATE = 0x30004, + TAG_GET_MIN_CLOCK_RATE = 0x30007, + TAG_GET_TURBO = 0x30009, + TAG_SET_TURBO = 0x38009, + + /* Voltage */ + TAG_GET_VOLTAGE = 0x30003, + TAG_SET_VOLTAGE = 0x38003, + TAG_GET_MAX_VOLTAGE = 0x30005, + TAG_GET_MIN_VOLTAGE = 0x30008, + TAG_GET_TEMPERATURE = 0x30006, + TAG_GET_MAX_TEMPERATURE = 0x3000A, + TAG_ALLOCATE_MEMORY = 0x3000C, + TAG_LOCK_MEMORY = 0x3000D, + TAG_UNLOCK_MEMORY = 0x3000E, + TAG_RELEASE_MEMORY = 0x3000F, + TAG_EXECUTE_CODE = 0x30010, + TAG_GET_DISPMANX_MEM_HANDLE = 0x30014, + TAG_GET_EDID_BLOCK = 0x30020, + + /* Framebuffer */ + TAG_ALLOCATE_BUFFER = 0x40001, + TAG_RELEASE_BUFFER = 0x48001, + TAG_BLANK_SCREEN = 0x40002, + TAG_GET_PHYSICAL_SIZE = 0x40003, + TAG_TEST_PHYSICAL_SIZE = 0x44003, + TAG_SET_PHYSICAL_SIZE = 0x48003, + TAG_GET_VIRTUAL_SIZE = 0x40004, + TAG_TEST_VIRTUAL_SIZE = 0x44004, + TAG_SET_VIRTUAL_SIZE = 0x48004, + TAG_GET_DEPTH = 0x40005, + TAG_TEST_DEPTH = 0x44005, + TAG_SET_DEPTH = 0x48005, + TAG_GET_PIXEL_ORDER = 0x40006, + TAG_TEST_PIXEL_ORDER = 0x44006, + TAG_SET_PIXEL_ORDER = 0x48006, + TAG_GET_ALPHA_MODE = 0x40007, + TAG_TEST_ALPHA_MODE = 0x44007, + TAG_SET_ALPHA_MODE = 0x48007, + TAG_GET_PITCH = 0x40008, + TAG_GET_VIRTUAL_OFFSET = 0x40009, + TAG_TEST_VIRTUAL_OFFSET = 0x44009, + TAG_SET_VIRTUAL_OFFSET = 0x48009, + TAG_GET_OVERSCAN = 0x4000A, + TAG_TEST_OVERSCAN = 0x4400A, + TAG_SET_OVERSCAN = 0x4800A, + TAG_GET_PALETTE = 0x4000B, + TAG_TEST_PALETTE = 0x4400B, + TAG_SET_PALETTE = 0x4800B, + TAG_SET_CURSOR_INFO = 0x8011, + TAG_SET_CURSOR_STATE = 0x8010 + + } rpi_mailbox_tag_t; + + +typedef enum { + TAG_STATE_REQUEST = 0, + TAG_STATE_RESPONSE = 1, + } rpi_tag_state_t; + + +typedef enum { + PT_OSIZE = 0, + PT_OREQUEST_OR_RESPONSE = 1, + } rpi_tag_buffer_offset_t; + +typedef enum { + T_OIDENT = 0, + T_OVALUE_SIZE = 1, + T_ORESPONSE = 2, + T_OVALUE = 3, + } rpi_tag_offset_t; + +typedef struct { + int tag; + int byte_length; + union { + int value_32; + unsigned char buffer_8[256]; + int buffer_32[64]; + } data; + } rpi_mailbox_property_t; + +typedef enum { + TAG_CLOCK_RESERVED = 0, + TAG_CLOCK_EMMC, + TAG_CLOCK_UART, + TAG_CLOCK_ARM, + TAG_CLOCK_CORE, + TAG_CLOCK_V3D, + TAG_CLOCK_H264, + TAG_CLOCK_ISP, + TAG_CLOCK_SDRAM, + TAG_CLOCK_PIXEL, + TAG_CLOCK_PWM, + } rpi_tag_clock_id_t; + +extern void RPI_PropertyInit( void ); +extern void RPI_PropertyAddTag( rpi_mailbox_tag_t tag, ... ); +extern int RPI_PropertyProcess( void ); +extern rpi_mailbox_property_t* RPI_PropertyGet( rpi_mailbox_tag_t tag ); + +#endif diff --git a/includes/rpi/mailbox.c b/includes/rpi/mailbox.c new file mode 100644 index 0000000..5c3110c --- /dev/null +++ b/includes/rpi/mailbox.c @@ -0,0 +1,77 @@ +/* + + 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 + +#include "gpio.h" +#include "mailbox.h" + +/* Mailbox 0 mapped to it's base address */ +static mailbox_t* rpiMailbox0 = (mailbox_t*)RPI_MAILBOX0_BASE; + +void RPI_Mailbox0Write( mailbox0_channel_t channel, int value ) +{ + /* For information about accessing mailboxes, see: + https://github.com/raspberrypi/firmware/wiki/Accessing-mailboxes */ + + /* Add the channel number into the lower 4 bits */ + value &= ~(0xF); + value |= channel; + + /* Wait until the mailbox becomes available and then write to the mailbox + channel */ + while( ( rpiMailbox0->Status & ARM_MS_FULL ) != 0 ) { } + + /* Write the modified value + channel number into the write register */ + rpiMailbox0->Write = value; +} + + +int RPI_Mailbox0Read( mailbox0_channel_t channel ) +{ + /* For information about accessing mailboxes, see: + https://github.com/raspberrypi/firmware/wiki/Accessing-mailboxes */ + int value = -1; + + /* Keep reading the register until the desired channel gives us a value */ + while( ( value & 0xF ) != channel ) + { + /* Wait while the mailbox is empty because otherwise there's no value + to read! */ + while( rpiMailbox0->Status & ARM_MS_EMPTY ) { } + + /* Extract the value from the Read register of the mailbox. The value + is actually in the upper 28 bits */ + value = rpiMailbox0->Read; + } + + /* Return just the value (the upper 28-bits) */ + return value >> 4; +} diff --git a/includes/rpi/mailbox.h b/includes/rpi/mailbox.h new file mode 100644 index 0000000..c8c60b0 --- /dev/null +++ b/includes/rpi/mailbox.h @@ -0,0 +1,77 @@ +/* + + 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. + +*/ + +#ifndef RPI_MAILBOX_H +#define RPI_MAILBOX_H + +#include "base.h" + +#define RPI_MAILBOX0_BASE ( PERIPHERAL_BASE + 0xB880 ) + +/* The available mailbox channels in the BCM2835 Mailbox interface. + See https://github.com/raspberrypi/firmware/wiki/Mailboxes for + information */ +typedef enum { + MB0_POWER_MANAGEMENT = 0, + MB0_FRAMEBUFFER, + MB0_VIRTUAL_UART, + MB0_VCHIQ, + MB0_LEDS, + MB0_BUTTONS, + MB0_TOUCHSCREEN, + MB0_UNUSED, + MB0_TAGS_ARM_TO_VC, + MB0_TAGS_VC_TO_ARM, +} mailbox0_channel_t; + +/* These defines come from the Broadcom Videocode driver source code, see: + brcm_usrlib/dag/vmcsx/vcinclude/bcm2708_chip/arm_control.h */ +enum mailbox_status_reg_bits { + ARM_MS_FULL = 0x80000000, + ARM_MS_EMPTY = 0x40000000, + ARM_MS_LEVEL = 0x400000FF, +}; + +/* Define a structure which defines the register access to a mailbox. + Not all mailboxes support the full register set! */ +typedef struct { + volatile unsigned int Read; + volatile unsigned int reserved1[((0x90 - 0x80) / 4) - 1]; + volatile unsigned int Poll; + volatile unsigned int Sender; + volatile unsigned int Status; + volatile unsigned int Configuration; + volatile unsigned int Write; + } mailbox_t; + +extern void RPI_Mailbox0Write( mailbox0_channel_t channel, int value ); +extern int RPI_Mailbox0Read( mailbox0_channel_t channel ); + +#endif diff --git a/includes/rpi/systimer.c b/includes/rpi/systimer.c new file mode 100644 index 0000000..ba01b13 --- /dev/null +++ b/includes/rpi/systimer.c @@ -0,0 +1,20 @@ + +#include +#include "systimer.h" + +static rpi_sys_timer_t* rpiSystemTimer = (rpi_sys_timer_t*)RPI_SYSTIMER_BASE; + +rpi_sys_timer_t* RPI_GetSystemTimer(void) +{ + return rpiSystemTimer; +} + +void RPI_WaitMicroSeconds( uint32_t us ) +{ + volatile uint32_t ts = rpiSystemTimer->counter_lo; + + while( ( rpiSystemTimer->counter_lo - ts ) < us ) + { + /* BLANK */ + } +} diff --git a/includes/rpi/systimer.h b/includes/rpi/systimer.h new file mode 100644 index 0000000..1e1a6b7 --- /dev/null +++ b/includes/rpi/systimer.h @@ -0,0 +1,54 @@ +/* + Part of the Raspberry-Pi Bare Metal Tutorials + Copyright (c) 2013-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. + +*/ + +#ifndef RPI_SYSTIMER_H +#define RPI_SYSTIMER_H + +#include + +#include "base.h" + +#define RPI_SYSTIMER_BASE ( PERIPHERAL_BASE + 0x3000 ) + + +typedef struct { + volatile uint32_t control_status; + volatile uint32_t counter_lo; + volatile uint32_t counter_hi; + volatile uint32_t compare0; + volatile uint32_t compare1; + volatile uint32_t compare2; + volatile uint32_t compare3; + } rpi_sys_timer_t; + + +extern rpi_sys_timer_t* RPI_GetSystemTimer(void); +extern void RPI_WaitMicroSeconds( uint32_t us ); + +#endif diff --git a/kernel.c b/kernel.c new file mode 100644 index 0000000..672883f --- /dev/null +++ b/kernel.c @@ -0,0 +1,272 @@ +/* + + 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 +#include +#include + +#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; + } + } +} diff --git a/scripts/configure_rpi.bat b/scripts/configure_rpi.bat new file mode 100644 index 0000000..4089d1d --- /dev/null +++ b/scripts/configure_rpi.bat @@ -0,0 +1 @@ +cmake -G "CodeBlocks - MinGW Makefiles" -DCMAKE_TOOLCHAIN_FILE=../toolchain-arm-none-eabi-rpi.cmake ../ diff --git a/scripts/configure_rpi.sh b/scripts/configure_rpi.sh new file mode 100644 index 0000000..94192c4 --- /dev/null +++ b/scripts/configure_rpi.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +cmake -G "CodeBlocks - Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE=../toolchain-arm-none-eabi-rpi.cmake ../ diff --git a/scripts/configure_rpi2.bat b/scripts/configure_rpi2.bat new file mode 100644 index 0000000..a8f264f --- /dev/null +++ b/scripts/configure_rpi2.bat @@ -0,0 +1 @@ +cmake -G "CodeBlocks - MinGW Makefiles" -DCMAKE_TOOLCHAIN_FILE=../toolchain-arm-none-eabi-rpi2.cmake ../ diff --git a/scripts/configure_rpi2.sh b/scripts/configure_rpi2.sh new file mode 100644 index 0000000..2a37f55 --- /dev/null +++ b/scripts/configure_rpi2.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +cmake -G "CodeBlocks - Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE=../toolchain-arm-none-eabi-rpi2.cmake ../ diff --git a/scripts/configure_rpibplus.bat b/scripts/configure_rpibplus.bat new file mode 100644 index 0000000..9a52027 --- /dev/null +++ b/scripts/configure_rpibplus.bat @@ -0,0 +1 @@ +cmake -G "CodeBlocks - MinGW Makefiles" -DCMAKE_TOOLCHAIN_FILE=../toolchain-arm-none-eabi-rpibplus.cmake ../ diff --git a/scripts/configure_rpibplus.sh b/scripts/configure_rpibplus.sh new file mode 100644 index 0000000..8b9af90 --- /dev/null +++ b/scripts/configure_rpibplus.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +cmake -G "CodeBlocks - Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE=../toolchain-arm-none-eabi-rpibplus.cmake ../ diff --git a/toolchain-arm-none-eabi-rpi.cmake b/toolchain-arm-none-eabi-rpi.cmake new file mode 100644 index 0000000..492f655 --- /dev/null +++ b/toolchain-arm-none-eabi-rpi.cmake @@ -0,0 +1,67 @@ + +# Part of the Raspberry-Pi Bare Metal Tutorials +# Copyright (c) 2013-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. + +# A CMake toolchain file so we can cross-compile for the Rapsberry-Pi bare-metal + +include(CMakeForceCompiler) + +# usage +# cmake -DCMAKE_TOOLCHAIN_FILE=../toolchain-arm-none-eabi.cmake ../ + +# The Generic system name is used for embedded targets (targets without OS) in +# CMake +set( CMAKE_SYSTEM_NAME Generic ) +set( CMAKE_SYSTEM_PROCESSOR BCM2835 ) + +# Set a toolchain path. You only need to set this if the toolchain isn't in +# your system path. Don't forget a trailing path separator! +set( TC_PATH "" ) + +# The toolchain prefix for all toolchain executables +set( CROSS_COMPILE arm-none-eabi- ) + +# specify the cross compiler. We force the compiler so that CMake doesn't +# attempt to build a simple test program as this will fail without us using +# the -nostartfiles option on the command line +CMAKE_FORCE_C_COMPILER( ${TC_PATH}${CROSS_COMPILE}gcc GNU ) + +# We must set the OBJCOPY setting into cache so that it's available to the +# whole project. Otherwise, this does not get set into the CACHE and therefore +# the build doesn't know what the OBJCOPY filepath is +set( CMAKE_OBJCOPY ${TC_PATH}${CROSS_COMPILE}objcopy + CACHE FILEPATH "The toolchain objcopy command " FORCE ) + +# Set the CMAKE C flags (which should also be used by the assembler! +set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfpu=vfp" ) +set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfloat-abi=hard" ) +set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=armv6zk" ) +set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mtune=arm1176jzf-s" ) + +set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS}" CACHE STRING "" ) +set( CMAKE_ASM_FLAGS "${CMAKE_C_FLAGS}" CACHE STRING "" ) + + diff --git a/toolchain-arm-none-eabi-rpi2.cmake b/toolchain-arm-none-eabi-rpi2.cmake new file mode 100644 index 0000000..5d2f1b4 --- /dev/null +++ b/toolchain-arm-none-eabi-rpi2.cmake @@ -0,0 +1,68 @@ + +# Part of the Raspberry-Pi Bare Metal Tutorials +# Copyright (c) 2013-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. + +# A CMake toolchain file so we can cross-compile for the Rapsberry-Pi bare-metal + +include(CMakeForceCompiler) + +# usage +# cmake -DCMAKE_TOOLCHAIN_FILE=../toolchain-arm-none-eabi.cmake ../ + +# The Generic system name is used for embedded targets (targets without OS) in +# CMake +set( CMAKE_SYSTEM_NAME Generic ) +set( CMAKE_SYSTEM_PROCESSOR BCM2836 ) + +# Set a toolchain path. You only need to set this if the toolchain isn't in +# your system path. Don't forget a trailing path separator! +set( TC_PATH "" ) + +# The toolchain prefix for all toolchain executables +set( CROSS_COMPILE arm-none-eabi- ) + +# specify the cross compiler. We force the compiler so that CMake doesn't +# attempt to build a simple test program as this will fail without us using +# the -nostartfiles option on the command line +CMAKE_FORCE_C_COMPILER( ${TC_PATH}${CROSS_COMPILE}gcc GNU ) + +# We must set the OBJCOPY setting into cache so that it's available to the +# whole project. Otherwise, this does not get set into the CACHE and therefore +# the build doesn't know what the OBJCOPY filepath is +set( CMAKE_OBJCOPY ${TC_PATH}${CROSS_COMPILE}objcopy + CACHE FILEPATH "The toolchain objcopy command " FORCE ) + +# Set the CMAKE C flags (which should also be used by the assembler! +set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfpu=neon-vfpv4" ) +set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfloat-abi=hard" ) +set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=armv7-a" ) +set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mtune=cortex-a7" ) + +set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS}" CACHE STRING "" ) +set( CMAKE_ASM_FLAGS "${CMAKE_C_FLAGS}" CACHE STRING "" ) + +# Add the raspberry-pi 2 definition so conditional compilation works +add_definitions( -DRPI2=1 ) diff --git a/toolchain-arm-none-eabi-rpibplus.cmake b/toolchain-arm-none-eabi-rpibplus.cmake new file mode 100644 index 0000000..077d847 --- /dev/null +++ b/toolchain-arm-none-eabi-rpibplus.cmake @@ -0,0 +1,69 @@ + +# Part of the Raspberry-Pi Bare Metal Tutorials +# Copyright (c) 2013-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. + +# A CMake toolchain file so we can cross-compile for the Rapsberry-Pi bare-metal + +include(CMakeForceCompiler) + +# usage +# cmake -DCMAKE_TOOLCHAIN_FILE=../toolchain-arm-none-eabi.cmake ../ + +# The Generic system name is used for embedded targets (targets without OS) in +# CMake +set( CMAKE_SYSTEM_NAME Generic ) +set( CMAKE_SYSTEM_PROCESSOR BCM2835 ) + +# Set a toolchain path. You only need to set this if the toolchain isn't in +# your system path. Don't forget a trailing path separator! +set( TC_PATH "" ) + +# The toolchain prefix for all toolchain executables +set( CROSS_COMPILE arm-none-eabi- ) + +# specify the cross compiler. We force the compiler so that CMake doesn't +# attempt to build a simple test program as this will fail without us using +# the -nostartfiles option on the command line +CMAKE_FORCE_C_COMPILER( ${TC_PATH}${CROSS_COMPILE}gcc GNU ) + +# We must set the OBJCOPY setting into cache so that it's available to the +# whole project. Otherwise, this does not get set into the CACHE and therefore +# the build doesn't know what the OBJCOPY filepath is +set( CMAKE_OBJCOPY ${TC_PATH}${CROSS_COMPILE}objcopy + CACHE FILEPATH "The toolchain objcopy command " FORCE ) + +# Set the CMAKE C flags (which should also be used by the assembler! +set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfpu=vfp" ) +set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfloat-abi=hard" ) +set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=armv6zk" ) +set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mtune=arm1176jzf-s" ) + +set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS}" CACHE STRING "" ) +set( CMAKE_ASM_FLAGS "${CMAKE_C_FLAGS}" CACHE STRING "" ) + +# Just add the BPLUS definition for conditional compiling +add_definitions( -DRPIBPLUS=1 ) +