forked from paraka/rpi-mske
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
326 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
/*** Memory barriers or data cache invalidation/flushing may be required around mailbox accesses ***/ | ||
|
||
#ifndef _MEM_BARRIER_H | ||
#define _MEM_BARRIER_H | ||
|
||
/* Invalidate Entire Data Cache */ | ||
#define invalidate_cache() asm volatile \ | ||
("mcr p15, #0, %[zero], c7, c6, #0" : : [zero] "r" (0) ) | ||
|
||
/* Clean Entire Data Cache */ | ||
#define clear_cache() asm volatile \ | ||
("mcr p15, #0, %[zero], c7, c10, #0" : : [zero] "r" (0) ) | ||
|
||
/* Clean and Invalidate Entire Data Cache */ /* TODO use before read mailbox and check if really needed */ | ||
#define flush_cache() asm volatile \ | ||
("mcr p15, #0, %[zero], c7, c14, #0" : : [zero] "r" (0) ) | ||
|
||
/* Data Synchronization Barrier: No instruction after the DSB can run until all instructions before it have */ | ||
#define data_sb() asm volatile \ | ||
("mcr p15, #0, %[zero], c7, c10, #4" : : [zero] "r" (0) ) | ||
|
||
/* Data Memory Barrier: No memory access after the DMB can run until all memory accesses before it have completed */ | ||
#define data_mb() asm volatile \ | ||
("mcr p15, #0, %[zero], c7, c10, #5" : : [zero] "r" (0) ) | ||
|
||
#endif /* _MEM_BARRIER_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
#include <memory/mailbox.h> | ||
|
||
#include <memory/barrier.h> | ||
#include <memory/memory.h> | ||
|
||
static volatile mske_mailbox* const mailbox0 = (mske_mailbox*)MAILBOX0_ADDRESS; | ||
|
||
unsigned int read_mailbox(unsigned int channel) | ||
{ | ||
/* default data error */ | ||
unsigned int data = 0xffffffff; | ||
unsigned int count = 0; | ||
|
||
/* Check if channel is no greater than 4 bits */ | ||
if(channel > 15) | ||
{ | ||
return data; | ||
} | ||
|
||
/* Repeat until match the channel number desired. If nothing recieved, it eventually give up and returns 0xffffffff */ | ||
while(1) | ||
{ | ||
/* Read the status register until the empty flag is not set, wait for the mailbox to be available to read */ | ||
while (mailbox0->status & MAILBOX_EMPTY) | ||
{ | ||
/* Need to check if this is the right thing to do */ | ||
flush_cache(); | ||
|
||
/* This is an arbitrary large number */ | ||
if(count++ >(1<<25)) | ||
{ | ||
return data; | ||
} | ||
} | ||
/* Read data from the read register */ | ||
data_mb(); | ||
data = mailbox0->read; | ||
data_mb(); | ||
|
||
/* Check if is the channel number desired */ | ||
if ((data & 0xF) == channel) | ||
{ | ||
data >>= 4; /* TODO check if correct --> The upper 28 bits are the returned data */ | ||
return data; | ||
} | ||
} | ||
} | ||
|
||
int write_mailbox(unsigned int channel, unsigned int data) | ||
{ | ||
/* default data error */ | ||
unsigned int result = -1; | ||
|
||
/* Check if data override channel bits */ | ||
if(data & 0x0f) | ||
{ | ||
return result; | ||
} | ||
|
||
/* Check if channel is no greater than 4 bits */ | ||
if(channel > 15) | ||
{ | ||
return result; | ||
} | ||
|
||
/* Read the status register until the full flag is not set, wait for the mailbox to be available to write */ | ||
data_mb(); | ||
while( mailbox0->status & MAILBOX_FULL ) | ||
{ | ||
data_mb(); | ||
} | ||
|
||
/* Write the data (shifted into the upper 28 bits) and channel (in the lower four bits) */ | ||
data_mb(); | ||
mailbox0->write = data | channel; | ||
result = 0; | ||
return result; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
/* | ||
* Mailbox: | ||
* Each mailbox is an 8-deep FIFO of 32-bit words, which can be read (popped)/written (pushed) by the ARM and VideoCore and defines the following channels: | ||
* 0: Power management | ||
* 1: Framebuffer | ||
* 2: Virtual UART | ||
* 3: VCHIQ | ||
* 4: LEDs | ||
* 5: Buttons | ||
* 6: Touch screen | ||
* 7: | ||
* 8: Property tags (ARM -> VideoCore) | ||
* 9: Property tags (VideoCore -> ARM) | ||
* | ||
* Mailbox Peek Read/Write Status Sender Config | ||
* 0 0x10 0x00 0x18 0x14 0x1c | ||
* 1 0x30 0x20 0x38 0x34 0x3c | ||
* | ||
* All registers are unsigned int (32 bits) little-endian. | ||
* | ||
* More info: https://github.com/raspberrypi/firmware/wiki/Accessing-mailboxes | ||
* | ||
*/ | ||
#ifndef _MAILBOX_H | ||
#define _MAILBOX_H | ||
|
||
#include <common/peripherals.h> | ||
|
||
/* Base address for the mailbox registers */ | ||
#define MAILBOX_ADDRESS_BASE 0xB880 | ||
#define MAILBOX0_ADDRESS (PERIPHERALS_BASE + MAILBOX_ADDRESS_BASE) | ||
|
||
/* Mailbox full: Bit 31 is set in the status register if there is no space to write into the mailbox */ | ||
#define MAILBOX_FULL 0x80000000 | ||
|
||
/* Mailbox empty: Bit 30 is set in the status register if there is nothing to read from the mailbox */ | ||
#define MAILBOX_EMPTY 0x40000000 | ||
|
||
/* Define channels */ | ||
#define MAILBOX_CHANNEL_ARM2VC 8 | ||
#define MAILBOX_CHANNEL_VC2ARM 9 | ||
|
||
typedef struct | ||
{ | ||
unsigned int read; | ||
unsigned int unused1; | ||
unsigned int unused2; | ||
unsigned int unused3; | ||
unsigned int poll; | ||
unsigned int sender; | ||
unsigned int status; | ||
unsigned int configuration; | ||
unsigned int write; | ||
} mske_mailbox; | ||
|
||
/* Read a channel. The channel must be zero to 15 */ | ||
extern unsigned int read_mailbox(unsigned int channel); | ||
|
||
/* Write the given data to the channel. The channel must be zero to 15 and value in last 4 bits */ | ||
extern int write_mailbox(unsigned int channel, unsigned int data); | ||
|
||
#endif /* _MAILBOX_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
#include <memory/memory.h> | ||
|
||
#include <common/io.h> | ||
|
||
#define MEMORY_SIZE 64 | ||
#define MEMORY_ALIGN 256 | ||
|
||
|
||
/* Translation table 0: First 64 MB in memory. Needs to be aligned to its size (i.e: 64*4 bytes) */ | ||
unsigned int pagetable0[MEMORY_SIZE] __attribute__ ((aligned (MEMORY_ALIGN))); | ||
|
||
/* Need to access the page table, etc as physical memory */ | ||
static unsigned int *pagetable = (unsigned int * const) mem_p2v(0x4000); /* 16k */ | ||
|
||
void init_memory(void) | ||
{ | ||
printk("Initializing memory...\n"); | ||
|
||
unsigned int x; | ||
unsigned int pagetable0_address; | ||
|
||
/* Translation table 0 - covers the first 64 MB, currently nothing mapped in it. */ | ||
for(x = 0; x < MEMORY_SIZE; x++) | ||
{ | ||
pagetable0[x] = 0; | ||
} | ||
printk("Created pagetable with %d MBs.\n", MEMORY_SIZE); | ||
|
||
/* Get physical address of pagetable 0 */ | ||
pagetable0_address = mem_v2p((unsigned int) &pagetable0); | ||
|
||
/* Use translation table 0 up to 64MB */ | ||
asm volatile("mcr p15, 0, %[n], c2, c0, 2" : : [n] "r" (6)); | ||
|
||
/* Translation table 0 - ARM1176JZF-S manual, 3-57 */ | ||
asm volatile("mcr p15, 0, %[addr], c2, c0, 0" : : [addr] "r" (pagetable0_address)); | ||
|
||
/* Invalidate the translation lookaside buffer (TLB): ARM1176JZF-S manual, p. 3-86 */ | ||
asm volatile("mcr p15, 0, %[data], c8, c7, 0" : : [data] "r" (0)); | ||
|
||
printk("Memory initialized!\n"); | ||
} | ||
|
||
unsigned int mem_v2p(unsigned int virtual_address) | ||
{ | ||
unsigned int pagetable_data = pagetable[virtual_address >> 20]; | ||
unsigned int type_of_entry = pagetable_data & 3; | ||
|
||
/* Translation fault */ | ||
if(type_of_entry == 0) | ||
{ | ||
return 0xffffffff; | ||
} | ||
|
||
/* Coarse page table */ | ||
if(type_of_entry == 1) | ||
{ | ||
unsigned int coarse_pagetable_data; | ||
coarse_pagetable_data = ((unsigned int *)(VIRTUAL_ADDRESS_BASE + (pagetable_data & 0xfffffc00)))[(virtual_address >> 12) & 0xff]; | ||
|
||
/* Nothing mapped */ | ||
if((coarse_pagetable_data & 3) == 0) | ||
{ | ||
return 0xffffffff; | ||
} | ||
|
||
/* Small (4k) page */ | ||
if(coarse_pagetable_data & 2) | ||
{ | ||
return (coarse_pagetable_data & 0xfffff000) + (virtual_address & 0xfff); | ||
} | ||
|
||
/* Large 64k page */ | ||
return (coarse_pagetable_data & 0xffff0000) + (virtual_address & 0xffff); | ||
} | ||
|
||
/* Sections */ | ||
if(type_of_entry == 2) | ||
{ | ||
unsigned int physical_address; | ||
|
||
/* SuperSection base */ | ||
physical_address = pagetable_data & 0xfff00000; | ||
|
||
if(pagetable_data & (1<<18)) | ||
{ | ||
/* 16MB Supersection */ | ||
physical_address += virtual_address & 0x00ffffff; | ||
} | ||
else | ||
{ | ||
/* 1MB Section */ | ||
physical_address += virtual_address & 0x000fffff; | ||
} | ||
return physical_address; | ||
} | ||
|
||
/* Reserved */ | ||
if(type_of_entry == 3) | ||
{ | ||
return 0xffffffff; | ||
} | ||
/* Unknown problem, cannot come here */ | ||
return 0xffffffff; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
/* | ||
* The ARM section of the RAM starts at 0x00000000 and the VideoCore section of the RAM is mapped in only if the system is configured to support a memory mapped display. | ||
* The bus addresses for RAM are set up to map onto the uncached bus address range on the VideoCore starting at 0xC0000000. | ||
* | ||
* Bus: | ||
* The bus addresses for peripherals are set up to map onto the peripheral bus address range starting at 0x7E000000. | ||
* | ||
* Physical addresses: | ||
* Peripherals will range from 0x20000000 to 0x20FFFFFF. Use peripherals.h to manage. | ||
* | ||
* Virtual addresses: (Check arm-c-virtual-addresses figure or BCM2835 ARM peripherals) | ||
* Virtual addresses in user mode (i.e. seen by processes running in ARM Linux) will range between 0x00000000 and 0xBFFFFFFF. | ||
* Virtual addresses in kernel mode will range between 0xC0000000 and 0xEFFFFFFF. | ||
* | ||
* DMA: use Direct access memory. DMA allows certain hardware subsystems to access main system memory (RAM) independent of the central processing unit (CPU). It is needed to ... | ||
* | ||
* Memory addresses summary: | ||
* User process memory | 0x00000000 - 0x7fffffff = 0 - 2GB | ||
* Peripherals | 0x20000000 - 0x20ffffff | ||
* Physical memory | 0x80000000 - 0xa0ffffff | ||
* Kernel data | 0xc0000000 - 0xefffffff | ||
* Kernel code | 0xf0000000 - 0xffffffff | ||
*/ | ||
#ifndef _MEMORY_H | ||
#define _MEMORY_H | ||
|
||
/*** Memory management ***/ | ||
|
||
/* Virtual addresses range defined as 0x80000000 offset */ | ||
#define VIRTUAL_ADDRESS_BASE 0x80000000 | ||
|
||
/* Initialise memory: Set up first 64MB of RAM as unmapped pagetable */ | ||
extern void init_memory(void); | ||
|
||
/* Convert a physical address to a virtual one */ | ||
#define mem_p2v(X) (X+VIRTUAL_ADDRESS_BASE) | ||
|
||
/* Convert a virtual address to a physical one by following the page table. Returns physical address, or 0xffffffff if the virtual address does not map - ARM1176-TZJS page 6-39 */ | ||
extern unsigned int mem_v2p(unsigned int virtual_address); | ||
|
||
#endif /* _MEMORY_H */ |