-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