-Initial import
This commit is contained in:
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
fw
|
||||||
|
fw.bin
|
||||||
|
fw.img
|
||||||
43
Makefile
Normal file
43
Makefile
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
CC=arm-none-eabi-gcc
|
||||||
|
AS=arm-none-eabi-as
|
||||||
|
OBJCOPY=arm-none-eabi-objcopy
|
||||||
|
OBJDUMP=arm-none-eabi-objdump
|
||||||
|
|
||||||
|
CFLAGS=-march=armv7-a -mcpu=cortex-a8 -mfloat-abi=softfp -mfpu=neon --std=gnu99 -ggdb -Wall -Wextra -pedantic -Wno-unused-parameter -O1 -flto
|
||||||
|
LDFLAGS=
|
||||||
|
C_SRCS=cortexa8.c drv_omap35x_gpt.c main.c omap35x.c omap35x_intc.c uart.c syscall.c
|
||||||
|
S_SRCS=cortexa8_asm.s syscall_asm.s
|
||||||
|
|
||||||
|
OBJS=$(addprefix objs/,$(C_SRCS:.c=.o)) $(addprefix objs/,$(S_SRCS:.s=.o))
|
||||||
|
|
||||||
|
all: fw.img
|
||||||
|
|
||||||
|
fw: $(OBJS) fw.ld
|
||||||
|
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS) -lc -T fw.ld
|
||||||
|
|
||||||
|
fw.bin: fw
|
||||||
|
$(OBJCOPY) -O binary $< $@
|
||||||
|
|
||||||
|
fw.img: fw.bin
|
||||||
|
./mkimage -A arm -O linux -T kernel -C none -a 0x80008000 -e `$(OBJDUMP) -f fw | grep "start address" | cut -d\ -f 3` -n none -d $< $@
|
||||||
|
|
||||||
|
beagle-nand.bin: fw.img
|
||||||
|
./bb_nandflash.sh $< $@ kernel >/dev/null 2>&1
|
||||||
|
./bb_nandflash_ecc $@ 0x0 0xe80000 || true
|
||||||
|
|
||||||
|
qemu: beagle-nand.bin
|
||||||
|
qemu-system-arm -M beagle -m 256M -mtdblock beagle-nand.bin -nographic
|
||||||
|
|
||||||
|
objs/%.o: %.c
|
||||||
|
$(CC) $(CFLAGS) -c -MMD -MP -o $@ $<
|
||||||
|
@cp objs/$*.d objs/$*.P; rm -f objs/$*.d
|
||||||
|
|
||||||
|
objs/%.o: %.s
|
||||||
|
$(AS) $(ASOPTS) -o $@ $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(OBJS) fw fw.bin fw.img
|
||||||
|
|
||||||
|
.PSEUDO=all clean qemu
|
||||||
|
|
||||||
|
-include $(addprefix objs/,$(C_SRCS:.c=.P))
|
||||||
147
bb_nandflash.sh
Executable file
147
bb_nandflash.sh
Executable file
@@ -0,0 +1,147 @@
|
|||||||
|
#! /bin/sh
|
||||||
|
# Copyright (C) 2008 yajin (yajin@vm-kernel.org)
|
||||||
|
#
|
||||||
|
# Put the xloader,u-boot,kernel and rootfs into nand flash image.
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# bb_nandflash.sh <x-loader-image> <nandflashimage> x-loader
|
||||||
|
# bb_nandflash.sh <u-boot-image> <nandflashimage> u-boot
|
||||||
|
# bb_nandflash.sh <kernel-image> <nandflashimage> kernel
|
||||||
|
# bb_nandflash.sh <rootfs> <nandflashimage> rootfs
|
||||||
|
|
||||||
|
# We assume that rootfs image has oob info
|
||||||
|
# while xloader u-boot and kernel image does not have oob info.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if [ ! -r "$1" ]; then
|
||||||
|
echo "Usage: $0 <image> <destimage> [<partition>]"
|
||||||
|
exit -1
|
||||||
|
fi
|
||||||
|
if [ 3 -ne "$#" ]; then
|
||||||
|
echo "Usage: $0 <image> <destimage> [<partition>]"
|
||||||
|
exit -1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Nand flash partitions
|
||||||
|
# 0x00000000-0x00080000 : "X-Loader"
|
||||||
|
# 0x00080000-0x00260000 : "U-Boot"
|
||||||
|
# 0x00260000-0x00280000 : "U-Boot Env"
|
||||||
|
# 0x00280000-0x00680000 : "Kernel"
|
||||||
|
# 0x00680000-0x10000000 : "File System"
|
||||||
|
|
||||||
|
flash_page_size=2048
|
||||||
|
flash_oob_size=64
|
||||||
|
flash_image_pages=131072
|
||||||
|
|
||||||
|
xloader_page_offset=0
|
||||||
|
uboot_page_offset=256
|
||||||
|
kernel_page_offset=1280
|
||||||
|
rootfs_page_offset=3328
|
||||||
|
|
||||||
|
|
||||||
|
flash_image_name=$2
|
||||||
|
xloader_image_name=$1
|
||||||
|
uboot_image_name=$1
|
||||||
|
kernel_image_name=$1
|
||||||
|
rootfs_image_name=$1
|
||||||
|
|
||||||
|
echo "flash image name:"$flash_image_name
|
||||||
|
|
||||||
|
#beagle board's NAND flash is 2G bit(256M bytes)
|
||||||
|
if [ ! -e "$2" ]; then
|
||||||
|
echo $flash_image_name" does not exist.Create it!"
|
||||||
|
echo -en \\0377\\0377\\0377\\0377\\0377\\0377\\0377\\0377 > .8b
|
||||||
|
cat .8b .8b > .16b
|
||||||
|
cat .16b .16b >.32b
|
||||||
|
cat .32b .32b >.64b #OOB is 64 bytes
|
||||||
|
cat .64b .64b .64b .64b .64b .64b .64b .64b > .512b
|
||||||
|
cat .512b .512b .512b .512b .64b>.page # A page is 2K bytes of data + 64bytes OOB
|
||||||
|
cat .page .page .page .page .page .page .page .page >.8page
|
||||||
|
cat .8page .8page .8page .8page .8page .8page .8page .8page >.block # a block = 64 pages
|
||||||
|
cat .block .block .block .block .block .block .block .block >.8block
|
||||||
|
cat .8block .8block .8block .8block .8block .8block .8block .8block >.64block
|
||||||
|
cat .64block .64block .64block .64block .64block .64block .64block .64block >.512block
|
||||||
|
cat .512block .512block .512block .512block >$flash_image_name
|
||||||
|
rm -rf .8b .16b .32b .64b .page .8page .64sec .block .8block .64block .512block
|
||||||
|
fi
|
||||||
|
|
||||||
|
put_no_oob()
|
||||||
|
{
|
||||||
|
#echo $1
|
||||||
|
#echo $2
|
||||||
|
image_name=$1
|
||||||
|
image_page_offset=$2
|
||||||
|
image_len=`du -shb $image_name |awk '{print $1}'`
|
||||||
|
image_pages=$[$image_len/2048]
|
||||||
|
|
||||||
|
if [ 0 -ne $[$image_len%$flash_page_size] ]; then
|
||||||
|
image_pages=$[$image_pages+1]
|
||||||
|
fi
|
||||||
|
|
||||||
|
#echo $image_len
|
||||||
|
#echo $image_pages
|
||||||
|
i=0
|
||||||
|
while [ $i -lt $image_pages ]
|
||||||
|
do
|
||||||
|
#echo $i
|
||||||
|
out_offset=$[$image_page_offset+$i]
|
||||||
|
in_offset=$i
|
||||||
|
#echo "out_offset:"$out_offset
|
||||||
|
#echo "in_offset:"$in_offset
|
||||||
|
dd if=$image_name of=$flash_image_name conv=notrunc count=1 obs=$[$flash_page_size+$flash_oob_size] ibs=$flash_page_size seek=$out_offset skip=$in_offset
|
||||||
|
i=$[$i + 1]
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
put_xloader()
|
||||||
|
{
|
||||||
|
echo "xloader image name:"$xloader_image_name
|
||||||
|
put_no_oob $1 $xloader_page_offset
|
||||||
|
echo "put xloader into flash image done!"
|
||||||
|
}
|
||||||
|
put_uboot()
|
||||||
|
{
|
||||||
|
echo "uboot image name:"$uboot_image_name
|
||||||
|
put_no_oob $1 $uboot_page_offset
|
||||||
|
echo "put u-boot into flash image done!"
|
||||||
|
}
|
||||||
|
put_kernel()
|
||||||
|
{
|
||||||
|
echo "Linux kernel image name:"$kernel_image_name
|
||||||
|
put_no_oob $1 $kernel_page_offset
|
||||||
|
echo "put Linux kernel into flash image done!"
|
||||||
|
}
|
||||||
|
put_rootfs()
|
||||||
|
{
|
||||||
|
echo "rootfs image name:"$rootfs_image_name
|
||||||
|
put_no_oob $1 $rootfs_page_offset
|
||||||
|
echo "put rootfs into flash image done!"
|
||||||
|
}
|
||||||
|
case "$3" in
|
||||||
|
x-loader)
|
||||||
|
put_xloader $1
|
||||||
|
;;
|
||||||
|
u-boot)
|
||||||
|
put_uboot $1
|
||||||
|
;;
|
||||||
|
kernel)
|
||||||
|
put_kernel $1
|
||||||
|
;;
|
||||||
|
rootfs)
|
||||||
|
put_rootfs $1
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown partition $3"
|
||||||
|
exit -1
|
||||||
|
esac
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
BIN
bb_nandflash_ecc
Executable file
BIN
bb_nandflash_ecc
Executable file
Binary file not shown.
224
cortexa8.c
Normal file
224
cortexa8.c
Normal file
@@ -0,0 +1,224 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "uart.h"
|
||||||
|
#include "cortexa8.h"
|
||||||
|
|
||||||
|
uint32_t cortexa8_read_cpuid(int reg) {
|
||||||
|
uint32_t rval;
|
||||||
|
switch(reg) {
|
||||||
|
case CORTEXA8_CPUID_MAINID:
|
||||||
|
__asm__ __volatile__ ("mrc 15, 0, %[res], c0, c0, 0"
|
||||||
|
: [res] "=r"(rval));
|
||||||
|
break;
|
||||||
|
case CORTEXA8_CPUID_CACHETYPE:
|
||||||
|
__asm__ __volatile__ ("mrc 15, 0, %[res], c0, c0, 1"
|
||||||
|
: [res] "=r"(rval));
|
||||||
|
break;
|
||||||
|
case CORTEXA8_CPUID_TLBTYPE:
|
||||||
|
__asm__ __volatile__ ("mrc 15, 0, %[res], c0, c0, 3"
|
||||||
|
: [res] "=r"(rval));
|
||||||
|
break;
|
||||||
|
case CORTEXA8_CPUID_PFR0:
|
||||||
|
__asm__ __volatile__ ("mrc 15, 0, %[res], c0, c1, 0"
|
||||||
|
: [res] "=r"(rval));
|
||||||
|
break;
|
||||||
|
case CORTEXA8_CPUID_PFR1:
|
||||||
|
__asm__ __volatile__ ("mrc 15, 0, %[res], c0, c1, 1"
|
||||||
|
: [res] "=r"(rval));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
rval = 0xdeadbeef;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cortexa8_enable_icache() {
|
||||||
|
uint32_t reg;
|
||||||
|
|
||||||
|
__asm__ __volatile__ ("mrc 15, 0, %[reg], c1, c0, 0; orr %[reg], %[reg], #0x1000; mcr 15, 0, %[reg], c1, c0, 0; isb"
|
||||||
|
: [reg] "=r"(reg));
|
||||||
|
}
|
||||||
|
|
||||||
|
void cortexa8_enable_dcache() {
|
||||||
|
uint32_t reg;
|
||||||
|
|
||||||
|
__asm__ __volatile__ ("mrc 15, 0, %[reg], c1, c0, 0; orr %[reg], %[reg], #0x4; mcr 15, 0, %[reg], c1, c0, 0"
|
||||||
|
: [reg] "=r"(reg));
|
||||||
|
}
|
||||||
|
|
||||||
|
void cortexa8_disable_icache() {
|
||||||
|
uint32_t reg;
|
||||||
|
|
||||||
|
__asm__ __volatile__ ("mrc 15, 0, %[reg], c1, c0, 0; bic %[reg], %[reg], #0x1000; mcr 15, 0, %[reg], c1, c0, 0; isb"
|
||||||
|
: [reg] "=r"(reg));
|
||||||
|
}
|
||||||
|
|
||||||
|
void cortexa8_disable_dcache() {
|
||||||
|
uint32_t reg;
|
||||||
|
|
||||||
|
__asm__ __volatile__ ("mrc 15, 0, %[reg], c1, c0, 0; bic %[reg], %[reg], #0x4; mcr 15, 0, %[reg], c1, c0, 0"
|
||||||
|
: [reg] "=r"(reg));
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned :1;
|
||||||
|
unsigned one:1;
|
||||||
|
unsigned b:1;
|
||||||
|
unsigned c:1;
|
||||||
|
unsigned xn:1;
|
||||||
|
unsigned domain:4;
|
||||||
|
unsigned :1;
|
||||||
|
unsigned ap:2;
|
||||||
|
unsigned tex:3;
|
||||||
|
unsigned ap2:1;
|
||||||
|
unsigned s:1;
|
||||||
|
unsigned ng:1;
|
||||||
|
unsigned :1;
|
||||||
|
unsigned ns:1;
|
||||||
|
unsigned baseadr:12;
|
||||||
|
} ptentry_section_t;
|
||||||
|
|
||||||
|
static ptentry_section_t ttable1[4096] __attribute__((aligned(16384)));
|
||||||
|
|
||||||
|
void cortexa8_init_ttable() {
|
||||||
|
// Create 1:1 translation table for entire address space with appropriate memory types
|
||||||
|
memset((void*)ttable1, 0, 16384);
|
||||||
|
|
||||||
|
// 0x00000000..0x7fffffff MMIO (Non-cacheable)
|
||||||
|
for(int i = 0;i < 2048;++i) {
|
||||||
|
ttable1[i].baseadr = i;
|
||||||
|
ttable1[i].one = 1;
|
||||||
|
|
||||||
|
// Read/write at any privilege
|
||||||
|
ttable1[i].ap2 = 0;
|
||||||
|
ttable1[i].ap = 0x3;
|
||||||
|
// Shareable device
|
||||||
|
ttable1[i].tex = 0;
|
||||||
|
ttable1[i].c = 0;
|
||||||
|
ttable1[1].b = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 0x80000000..0x8fffffff RAM (Cacheable)
|
||||||
|
for(int i = 2048;i < 2304;++i) {
|
||||||
|
ttable1[i].baseadr = i;
|
||||||
|
ttable1[i].one = 1;
|
||||||
|
|
||||||
|
// Read/write at any privilege
|
||||||
|
ttable1[i].ap2 = 0;
|
||||||
|
ttable1[i].ap = 0x3;
|
||||||
|
// Cacheable
|
||||||
|
ttable1[i].tex = 0x5;
|
||||||
|
ttable1[i].c = 0;
|
||||||
|
ttable1[i].b = 1;
|
||||||
|
ttable1[i].s = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 0x90000000..0xffffffff ??? (Non-cacheable)
|
||||||
|
for(int i = 2304;i < 4095;++i) {
|
||||||
|
ttable1[i].baseadr = i;
|
||||||
|
ttable1[i].one = 1;
|
||||||
|
|
||||||
|
// Read/write at any privilege
|
||||||
|
ttable1[i].ap2 = 0;
|
||||||
|
ttable1[i].ap = 0x3;
|
||||||
|
// Shareable device
|
||||||
|
ttable1[i].tex = 0;
|
||||||
|
ttable1[i].c = 0;
|
||||||
|
ttable1[1].b = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void cortexa8_init_mmu() {
|
||||||
|
cortexa8_init_ttable();
|
||||||
|
|
||||||
|
// Set Translation Table base Ptr 0
|
||||||
|
uint32_t reg = ((uint32_t)ttable1) & 0xffffc000u;
|
||||||
|
reg |= 0xb;
|
||||||
|
__asm__ __volatile__ ("mcr 15, 0, %[val], c2, c0, 0"
|
||||||
|
: : [val] "r"(reg));
|
||||||
|
|
||||||
|
// Set domains register
|
||||||
|
__asm__ __volatile__ ("mcr 15, 0, %[val], c3, c0, 0"
|
||||||
|
: : [val] "r"(0x1));
|
||||||
|
|
||||||
|
// Flush trans. table from L1$
|
||||||
|
for(int i = 0;i < 256;++i) {
|
||||||
|
reg = ((uint32_t)ttable1)+i*64;
|
||||||
|
__asm__ __volatile__ ("mcr 15, 0, %[val], c7, c11, 1"
|
||||||
|
: : [val] "r"(reg));
|
||||||
|
}
|
||||||
|
__asm__ __volatile__ ("dsb");
|
||||||
|
|
||||||
|
// Invalidate TLBs
|
||||||
|
__asm__ __volatile__ ("mcr 15, 0, r0, c8, c5, 0 ; mcr 15, 0, r0, c8, c6, 0; isb");
|
||||||
|
|
||||||
|
// Enable MMU
|
||||||
|
__asm__ __volatile__ ("mrc 15, 0, %[reg], c1, c0, 0; orr %[reg], %[reg], #0x1; mcr 15, 0, %[reg], c1, c0, 0; isb"
|
||||||
|
: [reg] "=r"(reg));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern uint32_t __stack_excp;
|
||||||
|
extern uint32_t __stack_int;
|
||||||
|
extern void _vect_table;
|
||||||
|
void cortexa8_init_handlers() {
|
||||||
|
// Set stack pointers
|
||||||
|
cortexa8_set_und_sp(&__stack_excp);
|
||||||
|
cortexa8_set_abt_sp(&__stack_excp);
|
||||||
|
cortexa8_set_irq_sp(&__stack_int);
|
||||||
|
cortexa8_set_fiq_sp(&__stack_int);
|
||||||
|
|
||||||
|
// Set VBAR
|
||||||
|
__asm__ __volatile__("mcr 15, 0, %[reg], c12, c0, 0"
|
||||||
|
: : [reg] "r"(&_vect_table));
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void cortexa8_excp_data_abt() __attribute__((interrupt ("ABORT")));
|
||||||
|
void cortexa8_excp_data_abt() {
|
||||||
|
uint32_t lr, dfar, dfsr;
|
||||||
|
__asm__ ("mov %[lr], lr; mrc 15, 0, %[dfsr], c5, c0, 0; mrc 15, 0, %[dfar], c6, c0, 0"
|
||||||
|
: [lr] "=r"(lr), [dfsr] "=r"(dfsr), [dfar] "=r"(dfar));
|
||||||
|
printf("ERROR: Data abort\n");
|
||||||
|
printf("PC: %.8lx Fault Address: %.8lx Fault code: %.lx\n",
|
||||||
|
lr-8, dfar, dfsr&0x4);
|
||||||
|
while(1) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cortexa8_excp_pf_abt() __attribute__((interrupt ("ABORT")));
|
||||||
|
void cortexa8_excp_pf_abt() {
|
||||||
|
uint32_t lr, ifar, ifsr;
|
||||||
|
__asm__ ("mov %[lr], lr; mrc 15, 0, %[ifsr], c5, c0, 1; mrc 15, 0, %[ifar], c6, c0, 2"
|
||||||
|
: [lr] "=r"(lr), [ifsr] "=r"(ifsr), [ifar] "=r"(ifar));
|
||||||
|
printf("ERROR: Prefetch abort\n");
|
||||||
|
printf("PC: %.8lx Fault Address: %.8lx Fault code: %.lx\n",
|
||||||
|
lr-4, ifar, ifsr&0x4);
|
||||||
|
while(1) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cortexa8_excp_undef() __attribute__((interrupt ("UNDEF")));
|
||||||
|
void cortexa8_excp_undef() {
|
||||||
|
uint32_t lr, spsr;
|
||||||
|
__asm__ ("mov %[lr], lr"
|
||||||
|
: [lr] "=r"(lr));
|
||||||
|
spsr = cortexa8_get_spsr();
|
||||||
|
printf("ERROR: Undefined instruction\n");
|
||||||
|
printf("PC: %.8lx\n",
|
||||||
|
lr-((spsr&0x20)?2:4));
|
||||||
|
while(1) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cortexa8_syscall() __attribute__((interrupt ("SWI")));
|
||||||
|
void cortexa8_syscall() {
|
||||||
|
uart_write("Syscall NYI\n", 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cortexa8_unhandled_fiq() __attribute__((interrupt ("FIQ")));
|
||||||
|
void cortexa8_unhandled_fiq() {
|
||||||
|
uart_write("UNHANDLED FINTERRUPT\n", 21);
|
||||||
|
}
|
||||||
37
cortexa8.h
Normal file
37
cortexa8.h
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
#ifndef _CORTEXA8_H_
|
||||||
|
#define _CORTEXA8_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#define CORTEXA8_CPUID_MAINID 0
|
||||||
|
#define CORTEXA8_CPUID_CACHETYPE 1
|
||||||
|
#define CORTEXA8_CPUID_TLBTYPE 2
|
||||||
|
#define CORTEXA8_CPUID_PFR0 3
|
||||||
|
#define CORTEXA8_CPUID_PFR1 4
|
||||||
|
|
||||||
|
uint32_t cortexa8_read_cpuid(int reg);
|
||||||
|
|
||||||
|
void cortexa8_enable_icache();
|
||||||
|
void cortexa8_enable_dcache();
|
||||||
|
void cortexa8_disable_icache();
|
||||||
|
void cortexa8_disable_dcache();
|
||||||
|
|
||||||
|
void cortexa8_init_mmu();
|
||||||
|
|
||||||
|
void cortexa8_init_handlers();
|
||||||
|
|
||||||
|
// Implemented in cortexa8_asm.s
|
||||||
|
void cortexa8_ena_int();
|
||||||
|
void cortexa8_dis_int();
|
||||||
|
bool cortexa8_get_int();
|
||||||
|
|
||||||
|
void cortexa8_set_usr_sp(uint32_t *sp);
|
||||||
|
void cortexa8_set_abt_sp(uint32_t *sp);
|
||||||
|
void cortexa8_set_und_sp(uint32_t *sp);
|
||||||
|
void cortexa8_set_irq_sp(uint32_t *sp);
|
||||||
|
void cortexa8_set_fiq_sp(uint32_t *sp);
|
||||||
|
|
||||||
|
uint32_t cortexa8_get_spsr();
|
||||||
|
|
||||||
|
#endif
|
||||||
131
cortexa8_asm.s
Normal file
131
cortexa8_asm.s
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
.global cortexa8_ena_int
|
||||||
|
cortexa8_ena_int:
|
||||||
|
mrs r0, cpsr
|
||||||
|
bic r0, r0, #0x80
|
||||||
|
msr cpsr, r0
|
||||||
|
bx lr
|
||||||
|
|
||||||
|
.global cortexa8_dis_int
|
||||||
|
cortexa8_dis_int:
|
||||||
|
mrs r0, cpsr
|
||||||
|
orr r0, r0, #0x80
|
||||||
|
msr cpsr, r0
|
||||||
|
bx lr
|
||||||
|
|
||||||
|
.global cortexa8_get_int
|
||||||
|
cortexa8_get_int:
|
||||||
|
mrs r0, cpsr
|
||||||
|
ands r0, r0, #0x80
|
||||||
|
moveq r0, #1
|
||||||
|
movne r0, #0
|
||||||
|
bx lr
|
||||||
|
|
||||||
|
.global cortexa8_set_usr_sp
|
||||||
|
cortexa8_set_usr_sp:
|
||||||
|
/* Read and save CPSR */
|
||||||
|
mrs r1, cpsr
|
||||||
|
mov r2, r1
|
||||||
|
/* Set mode to USR */
|
||||||
|
bfc r1, #0, #5
|
||||||
|
orr r1, r1, #0x10
|
||||||
|
/* Write CPSR */
|
||||||
|
msr cpsr, r1
|
||||||
|
/* Set SP in USR mode */
|
||||||
|
mov sp, r0
|
||||||
|
/* Restore original CPSR */
|
||||||
|
msr cpsr, r2
|
||||||
|
/* Return */
|
||||||
|
bx lr
|
||||||
|
|
||||||
|
.global cortexa8_set_abt_sp
|
||||||
|
cortexa8_set_abt_sp:
|
||||||
|
/* Read and save CPSR */
|
||||||
|
mrs r1, cpsr
|
||||||
|
mov r2, r1
|
||||||
|
/* Set mode to ABT */
|
||||||
|
bfc r1, #0, #5
|
||||||
|
orr r1, r1, #0x17
|
||||||
|
/* Write CPSR */
|
||||||
|
msr cpsr, r1
|
||||||
|
/* Set SP in ABT mode */
|
||||||
|
mov sp, r0
|
||||||
|
/* Restore original CPSR */
|
||||||
|
msr cpsr, r2
|
||||||
|
/* Return */
|
||||||
|
bx lr
|
||||||
|
|
||||||
|
.global cortexa8_set_und_sp
|
||||||
|
cortexa8_set_und_sp:
|
||||||
|
/* Read and save CPSR */
|
||||||
|
mrs r1, cpsr
|
||||||
|
mov r2, r1
|
||||||
|
/* Set mode to UND */
|
||||||
|
bfc r1, #0, #5
|
||||||
|
orr r1, r1, #0x1b
|
||||||
|
/* Write CPSR */
|
||||||
|
msr cpsr, r1
|
||||||
|
/* Set SP in UND mode */
|
||||||
|
mov sp, r0
|
||||||
|
/* Restore original CPSR */
|
||||||
|
msr cpsr, r2
|
||||||
|
/* Return */
|
||||||
|
bx lr
|
||||||
|
|
||||||
|
.global cortexa8_set_irq_sp
|
||||||
|
cortexa8_set_irq_sp:
|
||||||
|
/* Read and save CPSR */
|
||||||
|
mrs r1, cpsr
|
||||||
|
mov r2, r1
|
||||||
|
/* Set mode to IRQ */
|
||||||
|
bfc r1, #0, #5
|
||||||
|
orr r1, r1, #0x12
|
||||||
|
/* Write CPSR */
|
||||||
|
msr cpsr, r1
|
||||||
|
/* Set SP in IRQ mode */
|
||||||
|
mov sp, r0
|
||||||
|
/* Restore original CPSR */
|
||||||
|
msr cpsr, r2
|
||||||
|
/* Return */
|
||||||
|
bx lr
|
||||||
|
|
||||||
|
.global cortexa8_set_fiq_sp
|
||||||
|
cortexa8_set_fiq_sp:
|
||||||
|
/* Read and save CPSR */
|
||||||
|
mrs r1, cpsr
|
||||||
|
mov r2, r1
|
||||||
|
/* Set mode to FIQ */
|
||||||
|
bfc r1, #0, #5
|
||||||
|
orr r1, r1, #0x11
|
||||||
|
/* Write CPSR */
|
||||||
|
msr cpsr, r1
|
||||||
|
/* Set SP in FIQ mode */
|
||||||
|
mov sp, r0
|
||||||
|
/* Restore original CPSR */
|
||||||
|
msr cpsr, r2
|
||||||
|
/* Return */
|
||||||
|
bx lr
|
||||||
|
|
||||||
|
.global cortexa8_get_spsr
|
||||||
|
cortexa8_get_spsr:
|
||||||
|
mrs r0, spsr
|
||||||
|
bx lr
|
||||||
|
|
||||||
|
.global _vect_table
|
||||||
|
.align 5
|
||||||
|
_vect_table:
|
||||||
|
/* Reset / unused */
|
||||||
|
nop
|
||||||
|
/* Undefined instruction */
|
||||||
|
b cortexa8_excp_undef
|
||||||
|
/* Supervisor call */
|
||||||
|
b cortexa8_syscall
|
||||||
|
/* Prefetch abort */
|
||||||
|
b cortexa8_excp_pf_abt
|
||||||
|
/* Data abort */
|
||||||
|
b cortexa8_excp_data_abt
|
||||||
|
/* Unused */
|
||||||
|
nop
|
||||||
|
/* IRQ */
|
||||||
|
b omap35x_intc_handler
|
||||||
|
/* FIQ */
|
||||||
|
b cortexa8_unhandled_fiq
|
||||||
60
drv_omap35x_gpt.c
Normal file
60
drv_omap35x_gpt.c
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "drv_omap35x_gpt.h"
|
||||||
|
#include "omap35x_intc.h"
|
||||||
|
|
||||||
|
#define TIOCP_CFG 4
|
||||||
|
#define TISR 6
|
||||||
|
#define TIER 7
|
||||||
|
#define TWER 8
|
||||||
|
#define TCLR 9
|
||||||
|
#define TCRR 10
|
||||||
|
#define TLDR 11
|
||||||
|
#define TPIR 18
|
||||||
|
#define TNIR 19
|
||||||
|
|
||||||
|
int omap35x_gpt_init(omap35x_gpt_handle* handle, uint32_t base, int irq) {
|
||||||
|
assert(handle != NULL);
|
||||||
|
|
||||||
|
handle->base = (uint32_t*)base;
|
||||||
|
handle->irq = irq;
|
||||||
|
handle->handler = NULL;
|
||||||
|
handle->handler_data = NULL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _omap35x_gpt_irqhandler(void *data);
|
||||||
|
|
||||||
|
int omap35x_gpt_ticktimer(omap35x_gpt_handle* handle, omap35x_intc_hfunc handler, void *data) {
|
||||||
|
assert(handle != NULL);
|
||||||
|
|
||||||
|
handle->base[TIOCP_CFG] = 0x215; // Clockactiviy = 2, emufree = 0, idlemode = 2 (smartidle), wakeup = ena, autoidle = 1
|
||||||
|
handle->base[TLDR] = -327;
|
||||||
|
handle->base[TCRR] = -327;
|
||||||
|
handle->base[TPIR] = 320000;
|
||||||
|
handle->base[TNIR] = -680000;
|
||||||
|
|
||||||
|
handle->handler = handler;
|
||||||
|
handle->handler_data = data;
|
||||||
|
omap35x_intc_register(handle->irq, &_omap35x_gpt_irqhandler, (void*)handle, 0);
|
||||||
|
|
||||||
|
handle->base[TCLR] = 0x3; // autoreload = 1, start = 1
|
||||||
|
|
||||||
|
handle->base[TIER] = 0x2; // Overflow int = enable
|
||||||
|
handle->base[TWER] = 0x2; // Overflow wakeup = enable
|
||||||
|
|
||||||
|
omap35x_intc_ena(handle->irq);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _omap35x_gpt_irqhandler(void *data) {
|
||||||
|
omap35x_gpt_handle *handle = (omap35x_gpt_handle*)data;
|
||||||
|
if(handle->handler != NULL)
|
||||||
|
handle->handler(handle->handler_data);
|
||||||
|
|
||||||
|
handle->base[TISR] = 0x2;
|
||||||
|
}
|
||||||
22
drv_omap35x_gpt.h
Normal file
22
drv_omap35x_gpt.h
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
#ifndef _DRV_OMAP35X_GPT_H_
|
||||||
|
#define _DRV_OMAP35X_GPT_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "omap35x_intc.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t* base;
|
||||||
|
int irq;
|
||||||
|
omap35x_intc_hfunc handler;
|
||||||
|
void *handler_data;
|
||||||
|
} omap35x_gpt_handle;
|
||||||
|
|
||||||
|
// Initialize a General-Purpose Timer
|
||||||
|
int omap35x_gpt_init(omap35x_gpt_handle* handle, uint32_t base, int irq);
|
||||||
|
|
||||||
|
// Configure the GPT 'handle' as the system tick timer (10 ms)
|
||||||
|
// The GPT must be GPTIMER1, GPTIMER2 or GPTIMER10 because the 1ms-Tick functionality is needed
|
||||||
|
int omap35x_gpt_ticktimer(omap35x_gpt_handle* handle, omap35x_intc_hfunc handler, void *data);
|
||||||
|
|
||||||
|
#endif
|
||||||
39
fw.ld
Normal file
39
fw.ld
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
. = 0x80008000;
|
||||||
|
.init :
|
||||||
|
{
|
||||||
|
KEEP (*(SORT_NONE(.init)))
|
||||||
|
}
|
||||||
|
.plt : { *(.plt) }
|
||||||
|
.iplt : { *(.iplt) }
|
||||||
|
.text : {
|
||||||
|
/* startup.o (.text) */
|
||||||
|
*(.text)
|
||||||
|
}
|
||||||
|
.fini :
|
||||||
|
{
|
||||||
|
KEEP (*(SORT_NONE(.fini)))
|
||||||
|
}
|
||||||
|
.data : {
|
||||||
|
*(.rodata)
|
||||||
|
*(.data)
|
||||||
|
*(COMMON)
|
||||||
|
}
|
||||||
|
.bss (NOLOAD) : {
|
||||||
|
. = ALIGN(32 / 8);
|
||||||
|
__bss_start__ = .;
|
||||||
|
*(.bss)
|
||||||
|
__bss_end__ = . ;
|
||||||
|
}
|
||||||
|
. = ALIGN(64);
|
||||||
|
. = . + 0x200000; /* 2MiB stack should be enough... */
|
||||||
|
__stack = .;
|
||||||
|
. = . + 0x10000; /* 64KiB exception stack */
|
||||||
|
__stack_excp = .;
|
||||||
|
. = . + 0x10000; /* 64KiB interrupt stack */
|
||||||
|
__stack_int = .;
|
||||||
|
__heap_start = .; /* for _sbrk */
|
||||||
|
/* Rest until end of RAM is heap */
|
||||||
|
__heap_end = 0x90000000;
|
||||||
|
}
|
||||||
89
main.c
Normal file
89
main.c
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
|
||||||
|
#include "drv_omap35x_gpt.h"
|
||||||
|
#include "omap35x.h"
|
||||||
|
#include "omap35x_intc.h"
|
||||||
|
#include "cortexa8.h"
|
||||||
|
|
||||||
|
static volatile uint32_t *const prcm_fclken_per = (uint32_t*)0x48005000;
|
||||||
|
static volatile uint32_t *const prcm_iclken_per = (uint32_t*)0x48005010;
|
||||||
|
static volatile uint32_t *const prcm_autoidle_per = (uint32_t*)0x48005030;
|
||||||
|
static volatile uint32_t *const prcm_clksel_per = (uint32_t*)0x48005040;
|
||||||
|
static volatile uint32_t *const prcm_sleepdep_per = (uint32_t*)0x48005044;
|
||||||
|
static volatile uint32_t *const prcm_clkstctrl_per = (uint32_t*)0x48005048;
|
||||||
|
static volatile uint32_t *const prcm_mpugrpsel_per = (uint32_t*)0x483070a4;
|
||||||
|
|
||||||
|
static volatile uint32_t *const prcm_clkstctrl_mpu = (uint32_t*)0x48004948;
|
||||||
|
|
||||||
|
|
||||||
|
static volatile uint32_t tickctr = 0;
|
||||||
|
void tickfunc(void* data) {
|
||||||
|
++tickctr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char* argv[]) {
|
||||||
|
omap35x_print_chip_id();
|
||||||
|
|
||||||
|
// Enable caches
|
||||||
|
cortexa8_enable_icache();
|
||||||
|
cortexa8_enable_dcache();
|
||||||
|
|
||||||
|
printf("1\n");
|
||||||
|
|
||||||
|
// Configure interrrupt & exception handling
|
||||||
|
cortexa8_init_handlers();
|
||||||
|
omap35x_intc_init();
|
||||||
|
|
||||||
|
printf("2\n");
|
||||||
|
|
||||||
|
cortexa8_init_mmu();
|
||||||
|
|
||||||
|
printf("3\n");
|
||||||
|
|
||||||
|
// Enable interrupts
|
||||||
|
cortexa8_ena_int();
|
||||||
|
|
||||||
|
printf("4\n");
|
||||||
|
|
||||||
|
// Prepare GPTIMER2
|
||||||
|
*prcm_fclken_per |= (1<<3); // Enable GPT2 fclk
|
||||||
|
*prcm_iclken_per |= (1<<3); // Enable GPT2 iclk
|
||||||
|
*prcm_autoidle_per |= (1<<3); // Enable GPT2 iclk autoidle
|
||||||
|
*prcm_clksel_per &= ~(1<<0); // GPT2 fclk = 32.768kHz
|
||||||
|
|
||||||
|
*prcm_mpugrpsel_per |= (1<<3); // GPT2 wakes up MPU
|
||||||
|
//*prcm_mpugrpsel_per |= (1<<11); // UART3 wakes up MPU
|
||||||
|
|
||||||
|
*prcm_sleepdep_per |= (1<<1); // Enable PER-MPU sleep dep.
|
||||||
|
*prcm_clkstctrl_per |= 0x3; // Enable autosleep
|
||||||
|
|
||||||
|
printf("5\n");
|
||||||
|
|
||||||
|
omap35x_gpt_handle gpt2;
|
||||||
|
omap35x_gpt_init(&gpt2, 0x49032000, 38);
|
||||||
|
|
||||||
|
omap35x_gpt_ticktimer(&gpt2, &tickfunc, NULL);
|
||||||
|
|
||||||
|
printf("6\n");
|
||||||
|
|
||||||
|
*prcm_clkstctrl_mpu = 0x3;
|
||||||
|
|
||||||
|
printf("7\n");
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
__asm__ __volatile__ ("wfi");
|
||||||
|
if(tickctr%100 == 0) {
|
||||||
|
printf(".");
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
malloc_stats();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
2
objs/.gitignore
vendored
Normal file
2
objs/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
*.o
|
||||||
|
*.P
|
||||||
52
omap35x.c
Normal file
52
omap35x.c
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "omap35x.h"
|
||||||
|
|
||||||
|
static volatile uint32_t *const omap35x_omap_sr = (uint32_t*)0x4800244c; // 1 word
|
||||||
|
static volatile uint32_t *const omap35x_idcode = (uint32_t*)0x4830a204; // 1 dword
|
||||||
|
static volatile uint32_t *const omap35x_die_id = (uint32_t*)0x4830a218; // 4 dwords
|
||||||
|
static volatile uint32_t *const omap35x_skuid = (uint32_t*)0x4830a20c; // 1 dword
|
||||||
|
|
||||||
|
static const char *const omap_names[] = {"OMAP3530", "OMAP3525", "OMAP3515", "OMAP3503", "UNKNOWN"};
|
||||||
|
static const char *const omap_ver[] = {"ES 1.0", "ES 2.0", "ES 2.1", "ES 3.0", "ES 3.1", "UNKNOWN", "UNKNOWN", "ES 3.1.2"};
|
||||||
|
|
||||||
|
void omap35x_print_chip_id() {
|
||||||
|
uint16_t omapsr = *omap35x_omap_sr&0xffffu;
|
||||||
|
int omapsr_idx;
|
||||||
|
switch(omapsr) {
|
||||||
|
case 0x0c00:
|
||||||
|
omapsr_idx = 0;
|
||||||
|
break;
|
||||||
|
case 0x4c00:
|
||||||
|
omapsr_idx = 1;
|
||||||
|
break;
|
||||||
|
case 0x1c00:
|
||||||
|
omapsr_idx = 2;
|
||||||
|
break;
|
||||||
|
case 0x5c00:
|
||||||
|
omapsr_idx = 3;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("Warning: Unknown OMAP35x type (%.8lx)\n", *omap35x_omap_sr);
|
||||||
|
omapsr_idx = 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t idcode = *omap35x_idcode;
|
||||||
|
int id_idx = (idcode&0xf0000000u)>>28;
|
||||||
|
if(id_idx > 7) // Versions 8..15 are unknown
|
||||||
|
id_idx = 6;
|
||||||
|
if(id_idx == 5 || id_idx == 6)
|
||||||
|
printf("Warning: Unknown OMAP35x version (%.8lx)\n", idcode);
|
||||||
|
|
||||||
|
bool highfreq = false;
|
||||||
|
if((*omap35x_skuid&0xf) == 0x8)
|
||||||
|
highfreq = true;
|
||||||
|
|
||||||
|
printf("%s %s %s Serial# %.8lx%.8lx%.8lx%.8lx\n",
|
||||||
|
omap_names[omapsr_idx], omap_ver[id_idx],
|
||||||
|
highfreq?"720 MHz":"600 MHz",
|
||||||
|
omap35x_die_id[3], omap35x_die_id[2], omap35x_die_id[1], omap35x_die_id[0]);
|
||||||
|
}
|
||||||
6
omap35x.h
Normal file
6
omap35x.h
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#ifndef _OMAP35X_H_
|
||||||
|
#define _OMAP35X_H_
|
||||||
|
|
||||||
|
void omap35x_print_chip_id();
|
||||||
|
|
||||||
|
#endif
|
||||||
87
omap35x_intc.c
Normal file
87
omap35x_intc.c
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "omap35x_intc.h"
|
||||||
|
#include "cortexa8.h"
|
||||||
|
|
||||||
|
static volatile uint32_t *const intc_sysconfig = (uint32_t*)0x48200010;
|
||||||
|
static volatile uint32_t *const intc_idle = (uint32_t*)0x48200050;
|
||||||
|
static volatile uint32_t *const intc_mir_clear0 = (uint32_t*)0x48200088;
|
||||||
|
static volatile uint32_t *const intc_mir_clear1 = (uint32_t*)0x482000a8;
|
||||||
|
static volatile uint32_t *const intc_mir_clear2 = (uint32_t*)0x482000c8;
|
||||||
|
static volatile uint32_t *const intc_mir_set0 = (uint32_t*)0x4820008c;
|
||||||
|
static volatile uint32_t *const intc_mir_set1 = (uint32_t*)0x482000ac;
|
||||||
|
static volatile uint32_t *const intc_mir_set2 = (uint32_t*)0x482000cc;
|
||||||
|
static volatile uint32_t *const intc_sir_irq = (uint32_t*)0x48200040;
|
||||||
|
static volatile uint32_t *const intc_control = (uint32_t*)0x48200048;
|
||||||
|
static volatile uint32_t *const intc_ilr = (uint32_t*)0x48200100; // 96 words
|
||||||
|
|
||||||
|
static omap35x_intc_hfunc handler_tbl[96];
|
||||||
|
static void* handler_data[96];
|
||||||
|
|
||||||
|
void omap35x_intc_init() {
|
||||||
|
// Interrupts should (still) be disabled from boot
|
||||||
|
assert(!cortexa8_get_int());
|
||||||
|
|
||||||
|
memset(handler_tbl, 0, sizeof(omap35x_intc_hfunc)*96);
|
||||||
|
|
||||||
|
*intc_sysconfig = 0x1; // Autoidle = 1
|
||||||
|
*intc_idle = 0x2; // Turbo = 1, Funcidle = 0
|
||||||
|
|
||||||
|
// Disable all ints
|
||||||
|
*intc_mir_set0 = 0xffffffff;
|
||||||
|
*intc_mir_set1 = 0xffffffff;
|
||||||
|
*intc_mir_set2 = 0xffffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
void omap35x_intc_register(int irq, omap35x_intc_hfunc handler, void *data, int prio) {
|
||||||
|
assert(irq >= 0 && irq <= 95);
|
||||||
|
assert(prio >= 0 && prio <= 63);
|
||||||
|
|
||||||
|
handler_tbl[irq] = handler;
|
||||||
|
handler_data[irq] = data;
|
||||||
|
intc_ilr[irq] = prio<<2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void omap35x_intc_ena(int irq) {
|
||||||
|
assert(irq >= 0 && irq <= 95);
|
||||||
|
assert(handler_tbl[irq] != NULL);
|
||||||
|
int i = irq/32, j = irq%32;
|
||||||
|
if(i == 0)
|
||||||
|
*intc_mir_clear0 = (1<<j);
|
||||||
|
else if(i == 1)
|
||||||
|
*intc_mir_clear1 = (1<<j);
|
||||||
|
else //if(i == 2)
|
||||||
|
*intc_mir_clear2 = (1<<j);
|
||||||
|
}
|
||||||
|
|
||||||
|
void omap35x_intc_dis(int irq) {
|
||||||
|
assert(irq >= 0 && irq <= 95);
|
||||||
|
int i = irq/32, j = irq%32;
|
||||||
|
if(i == 0)
|
||||||
|
*intc_mir_set0 = (1<<j);
|
||||||
|
else if(i == 1)
|
||||||
|
*intc_mir_set1 = (1<<j);
|
||||||
|
else //if(i == 2)
|
||||||
|
*intc_mir_set2 = (1<<j);
|
||||||
|
}
|
||||||
|
|
||||||
|
void omap35x_intc_handler() __attribute__((interrupt ("IRQ")));
|
||||||
|
void omap35x_intc_handler() {
|
||||||
|
uint32_t sir = *intc_sir_irq;
|
||||||
|
int irq = sir&0x7f;
|
||||||
|
|
||||||
|
if(sir&0xffffff80) {
|
||||||
|
printf("WARNING: Spurious interrupt (%.8lx)\n", sir);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(irq >= 0 && irq <= 95);
|
||||||
|
assert(handler_tbl[irq] != NULL);
|
||||||
|
|
||||||
|
handler_tbl[irq](handler_data[irq]);
|
||||||
|
|
||||||
|
*intc_control = 0x1;
|
||||||
|
__asm__ __volatile__ ("dsb");
|
||||||
|
}
|
||||||
13
omap35x_intc.h
Normal file
13
omap35x_intc.h
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#ifndef OMAP35X_INTC_H
|
||||||
|
#define OMAP35X_INTC_H
|
||||||
|
|
||||||
|
typedef void (*omap35x_intc_hfunc)(void*);
|
||||||
|
|
||||||
|
void omap35x_intc_init();
|
||||||
|
|
||||||
|
void omap35x_intc_register(int irq, omap35x_intc_hfunc handler, void* data, int prio);
|
||||||
|
|
||||||
|
void omap35x_intc_ena(int irq);
|
||||||
|
void omap35x_intc_dis(int irq);
|
||||||
|
|
||||||
|
#endif
|
||||||
72
syscall.c
Normal file
72
syscall.c
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
#include <sys/stat.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#undef errno
|
||||||
|
extern int errno;
|
||||||
|
|
||||||
|
#include "uart.h"
|
||||||
|
|
||||||
|
int _close(int file) __attribute__((used));
|
||||||
|
int _close(int file) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _lseek(int file, int ptr, int dir) __attribute__((used));
|
||||||
|
int _lseek(int file, int ptr, int dir) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _fstat(int file, struct stat *st) __attribute__((used));
|
||||||
|
int _fstat(int file, struct stat *st) {
|
||||||
|
st->st_mode = S_IFCHR;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _isatty(int file) __attribute__((used));
|
||||||
|
int _isatty(int file) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _read(int file, char *ptr, int len) __attribute__((used));
|
||||||
|
int _read(int file, char *ptr, int len) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _write(int file, char *ptr, int len) __attribute__((used));
|
||||||
|
int _write(int file, char *ptr, int len) {
|
||||||
|
// if(file != 1 && file != 2) // Only stdout supported
|
||||||
|
//return 0;
|
||||||
|
|
||||||
|
uart_write(ptr, len);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern char __heap_end, __heap_start;
|
||||||
|
caddr_t _sbrk(int incr) __attribute__((used));
|
||||||
|
caddr_t _sbrk(int incr) {
|
||||||
|
static caddr_t heap_end = 0;
|
||||||
|
|
||||||
|
if(heap_end == 0)
|
||||||
|
heap_end = &__heap_start;
|
||||||
|
|
||||||
|
caddr_t prev_heap_end = heap_end;
|
||||||
|
if(heap_end + incr > &__heap_end) {
|
||||||
|
_write(1, "Out of memory\n", 14);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
heap_end += incr;
|
||||||
|
return prev_heap_end;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _kill(int pid, int sig) __attribute__((used));
|
||||||
|
int _kill(int pid, int sig) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _getpid(void) __attribute__((used));
|
||||||
|
int _getpid(void) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
6
syscall_asm.s
Normal file
6
syscall_asm.s
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
.global _exit
|
||||||
|
_exit:
|
||||||
|
mrs r1, CPSR
|
||||||
|
wfi
|
||||||
|
b _exit
|
||||||
|
|
||||||
20
uart.c
Normal file
20
uart.c
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "uart.h"
|
||||||
|
|
||||||
|
static volatile uint32_t *const uart_data = (uint32_t*)0x49020000;
|
||||||
|
static volatile uint32_t *const uart_status = (uint32_t*)0x49020044;
|
||||||
|
|
||||||
|
static void _uart_wait_txnotfull() {
|
||||||
|
while(*uart_status & 0x1) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
void uart_sendb(char b) {
|
||||||
|
_uart_wait_txnotfull();
|
||||||
|
*uart_data = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uart_write(const char *data, int len) {
|
||||||
|
for(int i = 0;i < len;++i)
|
||||||
|
uart_sendb(*data++);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user