ar100: Support for ar100 (#6054)
Add files to support AR100 Signed-off-by: Elias Bakken <elias@iagent.no>
This commit is contained in:
parent
d7bd7f1f4b
commit
b7978d37b3
|
@ -354,6 +354,27 @@ micro-controller.
|
|||
| 1 stepper (200Mhz) | 39 |
|
||||
| 3 stepper (200Mhz) | 181 |
|
||||
|
||||
### AR100 step rate benchmark ###
|
||||
|
||||
The following configuration sequence is used on AR100 CPU (Allwinner A64):
|
||||
```
|
||||
allocate_oids count=3
|
||||
config_stepper oid=0 step_pin=PL10 dir_pin=PE14 invert_step=-1 step_pulse_ticks=0
|
||||
config_stepper oid=1 step_pin=PL11 dir_pin=PE15 invert_step=-1 step_pulse_ticks=0
|
||||
config_stepper oid=2 step_pin=PL12 dir_pin=PE16 invert_step=-1 step_pulse_ticks=0
|
||||
finalize_config crc=0
|
||||
|
||||
```
|
||||
|
||||
The test was last run on commit `08d037c6` with gcc version
|
||||
`or1k-linux-musl-gcc (GCC) 9.2.0` on an Allwinner A64-H
|
||||
micro-controller.
|
||||
|
||||
| AR100 R_PIO | ticks |
|
||||
| -------------------- | ----- |
|
||||
| 1 stepper | 85 |
|
||||
| 3 stepper | 359 |
|
||||
|
||||
### RP2040 step rate benchmark
|
||||
|
||||
The following configuration sequence is used on the RP2040:
|
||||
|
@ -425,6 +446,7 @@ hub.
|
|||
| atmega2560 (serial) | 23K | b161a69e | avr-gcc (GCC) 4.8.1 |
|
||||
| sam3x8e (serial) | 23K | b161a69e | arm-none-eabi-gcc (Fedora 7.1.0-5.fc27) 7.1.0 |
|
||||
| at90usb1286 (USB) | 75K | 01d2183f | avr-gcc (GCC) 5.4.0 |
|
||||
| ar100 (serial) | 138K | 08d037c6 | or1k-linux-musl-gcc 9.3.0 |
|
||||
| samd21 (USB) | 223K | 01d2183f | arm-none-eabi-gcc (Fedora 7.4.0-1.fc30) 7.4.0 |
|
||||
| pru (shared memory) | 260K | c5968a08 | pru-gcc (GCC) 8.0.0 20170530 (experimental) |
|
||||
| stm32f103 (USB) | 355K | 01d2183f | arm-none-eabi-gcc (Fedora 7.4.0-1.fc30) 7.4.0 |
|
||||
|
|
|
@ -185,6 +185,7 @@ represent total number of steps per second on the micro-controller.
|
|||
| RP2040 | 2400K | 1636K |
|
||||
| SAM4E8E | 2500K | 1674K |
|
||||
| SAMD51 | 3077K | 1885K |
|
||||
| AR100 | 3529K | 2507K |
|
||||
| STM32F407 | 3652K | 2459K |
|
||||
| STM32F446 | 3913K | 2634K |
|
||||
| STM32H743 | 9091K | 6061K |
|
||||
|
|
|
@ -125,6 +125,10 @@ from the repo's hc-sr04-range-sensor directory. It has been modified
|
|||
so that the IEP definitions compile correctly. See pru_rpmsg.patch for
|
||||
the modifications.
|
||||
|
||||
The ar100 directory contains code from:
|
||||
https://github.com/crust-firmware/crust
|
||||
revision 966124af914ce611aadd06fbbcbc4c36c4a0b240
|
||||
|
||||
The fast-hash directory contains code from:
|
||||
https://github.com/ztanml/fast-hash
|
||||
revision ae3bb53c199fe75619e940b5b6a3584ede99c5fc
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright © 2013-2017, ARM Limited and Contributors. All rights reserved.
|
||||
* Copyright © 2017-2020 The Crust Firmware Authors.
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef MACROS_S
|
||||
#define MACROS_S
|
||||
|
||||
/* This macro marks a global data declaration. */
|
||||
.macro data name
|
||||
.section .data.\name, "aw", @progbits
|
||||
.global \name
|
||||
.type \name, %object
|
||||
.align 4
|
||||
\name:
|
||||
.endm
|
||||
|
||||
/* This macro marks the beginning of a function. */
|
||||
.macro func name
|
||||
.section .text.\name, "ax", @progbits
|
||||
.global \name
|
||||
.type \name, %function
|
||||
.func \name
|
||||
.cfi_sections .debug_frame
|
||||
.cfi_startproc
|
||||
.align 4
|
||||
\name:
|
||||
.endm
|
||||
|
||||
/* This macro marks the end of a function. */
|
||||
.macro endfunc name
|
||||
.cfi_endproc
|
||||
.endfunc
|
||||
.size \name, . - \name
|
||||
.endm
|
||||
|
||||
#endif /* MACROS_S */
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* Copyright © 2017-2020 The Crust Firmware Authors.
|
||||
* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-only
|
||||
*/
|
||||
|
||||
#include <macros.S>
|
||||
|
||||
func __divsi3
|
||||
l.sflts r3, r0
|
||||
l.sw -8(r1), r18
|
||||
l.bnf 1f
|
||||
l.ori r18, r0, 0
|
||||
l.sub r3, r0, r3 # Negate x if it is negative
|
||||
l.addi r18, r18, 1 # Increment the flag if x is negative
|
||||
1: l.sflts r4, r0
|
||||
l.bnf 2f
|
||||
l.sw -4(r1), r9
|
||||
l.sub r4, r0, r4 # Negate y if it is negative
|
||||
l.addi r18, r18, -1 # Decrement the flag if y is negative
|
||||
2: l.jal __udivsi3
|
||||
l.addi r1, r1, -8
|
||||
l.sfne r18, r0
|
||||
l.bnf 3f
|
||||
l.addi r1, r1, 8
|
||||
l.sub r11, r0, r11 # Negate q if the flag is nonzero
|
||||
3: l.lwz r9, -4(r1)
|
||||
l.jr r9
|
||||
l.lwz r18, -8(r1)
|
||||
endfunc __divsi3
|
||||
|
||||
/*
|
||||
* Of the three ORBIS32 32-bit multiplication instructions (l.mul, l.muli, and
|
||||
* l.mulu), only l.mul works. By passing "-msoft-mul" to the compiler, and
|
||||
* delegating to this function, we can force all multiplication to use l.mul.
|
||||
*/
|
||||
func __mulsi3
|
||||
l.jr r9
|
||||
l.mul r11, r3, r4
|
||||
endfunc __mulsi3
|
||||
|
||||
/*
|
||||
* Derived from the "best method for counting bits in a 32-bit integer" at
|
||||
* https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel.
|
||||
*
|
||||
* Signed multiplication is used because l.mulu is broken in hardware. This is
|
||||
* safe because the previous bit masking ensures neither operand is negative.
|
||||
*/
|
||||
func __popcountsi2
|
||||
l.movhi r5, 0x5555 # Statement 1:
|
||||
l.ori r5, r5, 0x5555 # r5 = 0x55555555
|
||||
l.srli r4, r3, 1 # r4 = v >> 1
|
||||
l.and r4, r4, r5 # r4 = (v >> 1) & 0x55555555
|
||||
l.sub r3, r3, r4 # v = v - ((v >> 1) & 0x55555555)
|
||||
l.movhi r5, 0x3333 # Statement 2:
|
||||
l.ori r5, r5, 0x3333 # r5 = 0x33333333
|
||||
l.srli r4, r3, 2 # r4 = v >> 2
|
||||
l.and r4, r4, r5 # r4 = (v >> 2) & 0x33333333
|
||||
l.and r3, r3, r5 # v = v & 0x33333333
|
||||
l.add r3, r3, r4 # v += ((v >> 2) & 0x33333333)
|
||||
l.movhi r5, 0x0f0f # Statement 3:
|
||||
l.ori r5, r5, 0x0f0f # r5 = 0x0f0f0f0f
|
||||
l.srli r4, r3, 4 # r4 = v >> 4
|
||||
l.add r4, r3, r4 # r4 = v + (v >> 4)
|
||||
l.and r4, r4, r5 # r4 = v + (v >> 4) & 0x0f0f0f0f
|
||||
l.movhi r5, 0x0101
|
||||
l.ori r5, r5, 0x0101 # r5 = 0x01010101
|
||||
l.mul r11, r4, r5 # c = r4 * 0x01010101
|
||||
l.jr r9
|
||||
l.srli r11, r11, 24 # return c >> 24
|
||||
endfunc __popcountsi2
|
||||
|
||||
/*
|
||||
* Optimized implementation of the "shift divisor method" algorithm from
|
||||
* T. Rodeheffer. Software Integer Division. Microsoft Research, 2008.
|
||||
*
|
||||
* In addition to returning the quotient in r11, this function also returns
|
||||
* the remainder in r12. __umodsi3 simply copies the remainder into r11.
|
||||
*/
|
||||
func __udivsi3 # u32 __udivsi3(u32 x, u32 y) {
|
||||
l.sfeqi r4, 1 # if (y == 1)
|
||||
l.bf 5f # goto identity;
|
||||
l.ori r12, r3, 0 # u32 r = x;
|
||||
l.ori r5, r4, 0 # u32 y0 = y;
|
||||
l.addi r11, r0, 0 # u32 q = 0;
|
||||
l.sfltu r3, r4 # if (x >= y) {
|
||||
l.bf 2f
|
||||
l.sub r3, r3, r4 # x = x−y;
|
||||
1: l.sfltu r3, r4 # while (x >= y) {
|
||||
l.bf 2f
|
||||
l.sub r3, r3, r4 # x = x−y;
|
||||
l.add r4, r4, r4 # y *= 2;
|
||||
l.j 1b # }
|
||||
2: l.sfltu r12, r4 # } for (;;) {
|
||||
l.bf 3f # if (r >= y) {
|
||||
l.sfeq r4, r5 # [if (y == y0)]
|
||||
l.sub r12, r12, r4 # r = r−y;
|
||||
l.addi r11, r11, 1 # q = q + 1;
|
||||
3: l.bf 4f # } if (y == y0) break;
|
||||
l.srli r4, r4, 1 # y >>= 1;
|
||||
l.j 2b # }
|
||||
l.add r11, r11, r11 # q *= 2;
|
||||
4: l.jr r9 # return q;
|
||||
l.nop
|
||||
5: l.ori r11, r3, 0 # identity:
|
||||
l.jr r9 # return x;
|
||||
l.ori r12, r0, 0 # r = 0;
|
||||
endfunc __udivsi3 # }
|
||||
|
||||
func __umodsi3
|
||||
l.sw -4(r1), r9
|
||||
l.jal __udivsi3
|
||||
l.addi r1, r1, -4
|
||||
l.addi r1, r1, 4
|
||||
l.lwz r9, -4(r1)
|
||||
l.jr r9
|
||||
l.ori r11, r12, 0
|
||||
endfunc __umodsi3
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright © 2017-2020 The Crust Firmware Authors.
|
||||
* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-only
|
||||
*/
|
||||
|
||||
#include <macros.S>
|
||||
#include <asm/spr.h>
|
||||
|
||||
func start
|
||||
l.mfspr r2, r0, SPR_SYS_PPC_ADDR
|
||||
l.sfltui r2, 0x4000 # Size of exception vector area
|
||||
l.bf 1f
|
||||
l.srli r2, r2, 8 # Vector address → exception number
|
||||
l.addi r2, r0, 0 # Set to zero if not an exception
|
||||
1: l.addi r3, r0, 0 # Invalidate instruction cache
|
||||
l.addi r4, r0, 4096 # Cache lines (256) * block size (16)
|
||||
2: l.mtspr r0, r3, SPR_ICACHE_ICBIR_ADDR
|
||||
l.sfltu r3, r4
|
||||
l.bf 2b
|
||||
l.addi r3, r3, 16 # Cache block size
|
||||
l.psync # Flush CPU pipeline
|
||||
l.mfspr r3, r0, SPR_SYS_SR_ADDR # Enable instruction cache
|
||||
l.ori r3, r3, SPR_SYS_SR_ICE_MASK
|
||||
l.mtspr r0, r3, SPR_SYS_SR_ADDR
|
||||
l.nop # One cache block of nops
|
||||
l.nop
|
||||
l.nop
|
||||
l.nop
|
||||
l.movhi r3, hi(__bss_start) # Clear .bss
|
||||
l.ori r3, r3, lo(__bss_start)
|
||||
l.movhi r4, hi(__bss_end)
|
||||
l.ori r4, r4, lo(__bss_end)
|
||||
3: l.sw 0(r3), r0
|
||||
l.sfltu r3, r4
|
||||
l.bf 3b
|
||||
l.addi r3, r3, 4
|
||||
l.movhi r1, hi(__stack_end)
|
||||
l.ori r1, r1, lo(__stack_end) # Initialize stack pointer
|
||||
l.j main # Jump to C entry point
|
||||
l.or r3, r2, r2
|
||||
endfunc start
|
|
@ -8,6 +8,7 @@ set -eu
|
|||
MAIN_DIR=${PWD}
|
||||
BUILD_DIR=${PWD}/ci_build
|
||||
export PATH=${BUILD_DIR}/pru-gcc/bin:${PATH}
|
||||
export PATH=${BUILD_DIR}/or1k-linux-musl-cross/bin:${PATH}
|
||||
PYTHON=${BUILD_DIR}/python-env/bin/python
|
||||
PYTHON2=${BUILD_DIR}/python2-env/bin/python
|
||||
|
||||
|
|
|
@ -47,7 +47,21 @@ else
|
|||
tar xfz ${PRU_FILE}
|
||||
fi
|
||||
|
||||
######################################################################
|
||||
# Install or1k-linux-musl toolchain
|
||||
######################################################################
|
||||
|
||||
echo -e "\n\n=============== Install or1k-linux-musl toolchain\n\n"
|
||||
TOOLCHAIN=or1k-linux-musl-cross
|
||||
TOOLCHAIN_ZIP=${TOOLCHAIN}.tgz
|
||||
GCC_VERSION=10
|
||||
TOOLCHAIN_ZIP_V=${TOOLCHAIN}-${GCC_VERSION}.tgz
|
||||
URL=https://more.musl.cc/${GCC_VERSION}/x86_64-linux-musl/
|
||||
if [ ! -f ${CACHE_DIR}/${TOOLCHAIN_ZIP_V} ]; then
|
||||
curl ${URL}/${TOOLCHAIN_ZIP} -o ${CACHE_DIR}/${TOOLCHAIN_ZIP_V}
|
||||
fi
|
||||
cd ${BUILD_DIR}
|
||||
tar xf ${CACHE_DIR}/${TOOLCHAIN_ZIP_V}
|
||||
######################################################################
|
||||
# Create python3 virtualenv environment
|
||||
######################################################################
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
#!/usr/bin/env python3
|
||||
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
import mmap
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
FW_START = 0x00004000
|
||||
FW_BASE = 0x00040000 + FW_START
|
||||
FW_LIMIT = 0x00054000
|
||||
FW_SIZE = FW_LIMIT - FW_BASE
|
||||
|
||||
EXCEPTIONS_BASE = 0x00040000
|
||||
EXCEPTIONS_LIMIT = 0x00042000
|
||||
EXCEPTIONS_SIZE = EXCEPTIONS_LIMIT - EXCEPTIONS_BASE
|
||||
EXCEPTIONS_JUMP = FW_START # All exceptions reset program
|
||||
NR_OF_EXCEPTIONS = 14
|
||||
|
||||
R_CPU_CFG_PAGE_BASE = 0x01F01000
|
||||
R_CPU_CFG_PAGE_LIMIT = 0x01F02000
|
||||
R_CPU_CFG_SIZE = R_CPU_CFG_PAGE_LIMIT - R_CPU_CFG_PAGE_BASE
|
||||
R_CPU_CFG_OFFSET = 0xC00
|
||||
R_CPU_CLK_OFFSET = 0x400
|
||||
|
||||
parser = argparse.ArgumentParser(description='Flash and reset SRAM A2 of A64')
|
||||
parser.add_argument('filename', nargs='?', help='binary file to write')
|
||||
parser.add_argument('--reset', action='store_true', help='reset the AR100')
|
||||
parser.add_argument('--halt', action='store_true', help='Halt the AR100')
|
||||
parser.add_argument('--bl31', action='store_true', help='write bl31')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
|
||||
def write_exception_vectors():
|
||||
print("Writing exception vectors")
|
||||
with open("/dev/mem", "w+b") as f:
|
||||
exc = mmap.mmap(f.fileno(),
|
||||
length=EXCEPTIONS_SIZE,
|
||||
offset=EXCEPTIONS_BASE)
|
||||
for i in range(NR_OF_EXCEPTIONS):
|
||||
add = i * 0x100
|
||||
exc[add:add + 4] = ((EXCEPTIONS_JUMP - add) >> 2).to_bytes(
|
||||
4, byteorder='little')
|
||||
exc.close()
|
||||
|
||||
|
||||
def assert_deassert_reset(ass):
|
||||
with open("/dev/mem", "w+b") as f:
|
||||
r_cpucfg = mmap.mmap(f.fileno(),
|
||||
length=R_CPU_CFG_SIZE,
|
||||
offset=R_CPU_CFG_PAGE_BASE)
|
||||
if ass:
|
||||
r_cpucfg[R_CPU_CFG_OFFSET] &= ~0x01
|
||||
if r_cpucfg[R_CPU_CFG_OFFSET] & 0x01:
|
||||
print("failed to assert reset")
|
||||
else:
|
||||
r_cpucfg[R_CPU_CFG_OFFSET] |= 0x01
|
||||
if not (r_cpucfg[R_CPU_CFG_OFFSET] & 0x01):
|
||||
print("failed to deassert reset")
|
||||
r_cpucfg.close()
|
||||
|
||||
|
||||
def write_file(filename):
|
||||
with open(filename, "r+b") as fw:
|
||||
data = fw.read()
|
||||
if len(data) > FW_SIZE:
|
||||
print("File does not fit in memory")
|
||||
sys.exit(1)
|
||||
print("Writing file to SRAM A2")
|
||||
with open("/dev/mem", "w+b") as f:
|
||||
sram_a2 = mmap.mmap(f.fileno(), length=FW_SIZE, offset=FW_BASE)
|
||||
sram_a2[0:len(data)] = data
|
||||
sram_a2.close()
|
||||
|
||||
|
||||
def clear_magic_word():
|
||||
with open("/dev/mem", "w+b") as f:
|
||||
sram_a2 = mmap.mmap(f.fileno(), length=FW_SIZE, offset=FW_BASE)
|
||||
sram_a2[0] = 0x0
|
||||
sram_a2.close()
|
||||
|
||||
|
||||
if args.reset:
|
||||
print("Resetting AR100")
|
||||
assert_deassert_reset(1)
|
||||
assert_deassert_reset(0)
|
||||
sys.exit(0)
|
||||
|
||||
if args.filename:
|
||||
if args.bl31:
|
||||
print("writing bl31")
|
||||
assert_deassert_reset(1)
|
||||
write_file(args.filename)
|
||||
else:
|
||||
assert_deassert_reset(1)
|
||||
write_exception_vectors()
|
||||
write_file(args.filename)
|
||||
assert_deassert_reset(0)
|
||||
|
||||
if args.halt:
|
||||
print("Halting AR100")
|
||||
assert_deassert_reset(1)
|
||||
clear_magic_word()
|
|
@ -26,6 +26,8 @@ choice
|
|||
bool "Raspberry Pi RP2040"
|
||||
config MACH_PRU
|
||||
bool "Beaglebone PRU"
|
||||
config MACH_AR100
|
||||
bool "Allwinner A64 AR100"
|
||||
config MACH_LINUX
|
||||
bool "Linux process"
|
||||
config MACH_SIMU
|
||||
|
@ -40,6 +42,7 @@ source "src/stm32/Kconfig"
|
|||
source "src/hc32f460/Kconfig"
|
||||
source "src/rp2040/Kconfig"
|
||||
source "src/pru/Kconfig"
|
||||
source "src/ar100/Kconfig"
|
||||
source "src/linux/Kconfig"
|
||||
source "src/simulator/Kconfig"
|
||||
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
# Kconfig settings for AR100
|
||||
|
||||
if MACH_AR100
|
||||
|
||||
config AR100_SELECT
|
||||
bool
|
||||
default y
|
||||
select HAVE_GPIO
|
||||
select HAVE_GPIO_SPI
|
||||
select HAVE_GPIO_BITBANGING
|
||||
select HAVE_STEPPER_BOTH_EDGE
|
||||
|
||||
config BOARD_DIRECTORY
|
||||
string
|
||||
default "ar100"
|
||||
|
||||
config CLOCK_FREQ
|
||||
int
|
||||
default 300000000
|
||||
|
||||
endif
|
|
@ -0,0 +1,45 @@
|
|||
CROSS_PREFIX=or1k-linux-musl-
|
||||
dirs-y += src/generic src/ar100 lib/ar100
|
||||
|
||||
CFLAGS += -O3
|
||||
CFLAGS += -fno-builtin
|
||||
CFLAGS += -fno-pie
|
||||
CFLAGS += -ffreestanding
|
||||
CFLAGS += -msfimm -mshftimm -msoft-div -msoft-mul
|
||||
CFLAGS += -Ilib/ar100
|
||||
CFLAGS_klipper.elf := $(CFLAGS) -T src/ar100/ar100.ld
|
||||
CFLAGS_klipper.elf += -Wl,--gc-sections -static
|
||||
CFLAGS_klipper.elf += -Wl,--no-dynamic-linker
|
||||
|
||||
SFLAGS = -nostdinc -MMD
|
||||
SFLAGS += -Ilib/ar100
|
||||
|
||||
# Add source files
|
||||
src-y += ar100/main.c ar100/gpio.c ar100/serial.c
|
||||
src-y += ar100/util.c ar100/timer.c
|
||||
src-y += generic/crc16_ccitt.c generic/timer_irq.c
|
||||
|
||||
# Remove files that are not needed to save space
|
||||
src-y := $(filter-out lcd_hd44780.c,$(src-y))
|
||||
src-y := $(filter-out lcd_st7920.c,$(src-y))
|
||||
src-y := $(filter-out sensor_angle.c,$(src-y))
|
||||
src-y := $(filter-out thermocouple.c,$(src-y))
|
||||
|
||||
OBJS_klipper.elf += $(OUT)lib/ar100/start.o
|
||||
OBJS_klipper.elf += $(OUT)lib/ar100/runtime.o
|
||||
|
||||
# Build the AR100 binary
|
||||
target-y += $(OUT)ar100.bin
|
||||
|
||||
$(OUT)lib/ar100/start.o:
|
||||
@echo " Compiling $@"
|
||||
$(Q)$(CC) $(SFLAGS) -c $(PWD)/lib/ar100/start.S -o $@
|
||||
|
||||
$(OUT)lib/ar100/runtime.o:
|
||||
@echo " Compiling $@"
|
||||
$(Q)$(CC) $(SFLAGS) -c $(PWD)/lib/ar100/runtime.S -o $@
|
||||
|
||||
$(OUT)ar100.bin: $(OUT)klipper.elf
|
||||
@echo " Object copy $@"
|
||||
$(OBJCOPY) -O binary -S --reverse-bytes 4 $(OUT)klipper.elf $@
|
||||
truncate -s %8 $@
|
|
@ -0,0 +1,58 @@
|
|||
OUTPUT_ARCH(or1k)
|
||||
OUTPUT_FORMAT(elf32-or1k)
|
||||
ENTRY (start)
|
||||
|
||||
STACK_SIZE = 0x200;
|
||||
SRAM_A2_SIZE = 64K;
|
||||
ORIG = 0x4000;
|
||||
MEMORY {
|
||||
SRAM_A2 (rwx): ORIGIN = ORIG, LENGTH = SRAM_A2_SIZE
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = ORIG;
|
||||
|
||||
.text . : ALIGN(4) {
|
||||
KEEP(*(.text.start))
|
||||
*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.text*)))
|
||||
. = ALIGN(4);
|
||||
} >SRAM_A2
|
||||
|
||||
.data . : ALIGN(4) {
|
||||
*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
|
||||
__data_start = .;
|
||||
*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.data*)))
|
||||
. = ALIGN(4);
|
||||
__data_end = .;
|
||||
} >SRAM_A2
|
||||
|
||||
.copy . : ALIGN(4) {
|
||||
__copy_start = .;
|
||||
. += __data_end - __data_start;
|
||||
__copy_end = .;
|
||||
. = ALIGN(4);
|
||||
} >SRAM_A2
|
||||
|
||||
.bss . : ALIGN(4) {
|
||||
__bss_start = .;
|
||||
*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*)))
|
||||
. = ALIGN(4);
|
||||
__bss_end = .;
|
||||
|
||||
__stack_start = .;
|
||||
. += STACK_SIZE;
|
||||
__stack_end = .;
|
||||
} >SRAM_A2
|
||||
|
||||
ASSERT(. <= (SRAM_A2_SIZE), "Klipper image is too large")
|
||||
|
||||
/DISCARD/ : {
|
||||
*(.comment*)
|
||||
*(.eh_frame_hdr*)
|
||||
*(.iplt*)
|
||||
*(.note*)
|
||||
*(.rela*)
|
||||
*( .compile_time_request )
|
||||
}
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
// GPIO functions on ar100
|
||||
//
|
||||
// Copyright (C) 2020-2021 Elias Bakken <elias@iagent.no>
|
||||
//
|
||||
// This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
|
||||
#include "gpio.h"
|
||||
#include "command.h"
|
||||
#include "internal.h"
|
||||
#include "util.h"
|
||||
|
||||
DECL_ENUMERATION_RANGE("pin", "PL0", 0*32, 13);
|
||||
DECL_ENUMERATION_RANGE("pin", "PB0", 1*32, 10);
|
||||
DECL_ENUMERATION_RANGE("pin", "PC0", 2*32, 17);
|
||||
DECL_ENUMERATION_RANGE("pin", "PD0", 3*32, 25);
|
||||
DECL_ENUMERATION_RANGE("pin", "PE0", 4*32, 18);
|
||||
DECL_ENUMERATION_RANGE("pin", "PF0", 5*32, 7);
|
||||
DECL_ENUMERATION_RANGE("pin", "PG0", 6*32, 14);
|
||||
DECL_ENUMERATION_RANGE("pin", "PH0", 7*32, 12);
|
||||
|
||||
#define BANK(x) (x/32)
|
||||
#define PIN(x) (x%32)
|
||||
#define CFG_REG(x) ((x/8)*4)
|
||||
#define CFG_OFF(x) ((x%8)*4)
|
||||
#define PULLUP_REG(x) 0x1C + ((x/16)*4)
|
||||
#define PULLUP_OFF(x) ((x%16)*2)
|
||||
|
||||
volatile uint32_t data_regs[8];
|
||||
|
||||
struct gpio_mux gpio_mux_setup(uint8_t pin, enum pin_func func){
|
||||
uint8_t bank = BANK(pin);
|
||||
uint8_t p = PIN(pin);
|
||||
uint32_t data_reg = PIO_BASE + bank*0x24 + 0x10;
|
||||
uint32_t cfg_reg = PIO_BASE + bank*0x24 + CFG_REG(p);
|
||||
uint8_t cfg_off = CFG_OFF(p);
|
||||
|
||||
if(bank == 0) { // Handle R_PIO
|
||||
data_reg = R_PIO_BASE + 0x10;
|
||||
cfg_reg = R_PIO_BASE + CFG_REG(p);
|
||||
}
|
||||
|
||||
uint32_t curr_val = read_reg(cfg_reg) & ~(0xF<<cfg_off);
|
||||
write_reg(cfg_reg, curr_val | func<<cfg_off);
|
||||
|
||||
struct gpio_mux ret = {
|
||||
.pin = p,
|
||||
.reg = data_reg,
|
||||
.bank = bank
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct gpio_out gpio_out_setup(uint8_t pin, uint8_t val){
|
||||
|
||||
struct gpio_mux mux = gpio_mux_setup(pin, PIO_OUTPUT);
|
||||
struct gpio_out ret = {
|
||||
.pin = mux.pin,
|
||||
.reg = mux.reg,
|
||||
.bank = mux.bank,
|
||||
};
|
||||
data_regs[ret.bank] = read_reg(ret.reg);
|
||||
gpio_out_write(ret, val);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void gpio_out_write(struct gpio_out pin, uint8_t val){
|
||||
data_regs[pin.bank] &= ~(1<<pin.pin);
|
||||
data_regs[pin.bank] |= ((!!val)<<pin.pin);
|
||||
write_reg(pin.reg, data_regs[pin.bank]);
|
||||
}
|
||||
|
||||
void gpio_out_reset(struct gpio_out pin, uint8_t val){
|
||||
uint8_t p = pin.bank * 32 + pin.pin;
|
||||
gpio_out_setup(p, val);
|
||||
}
|
||||
|
||||
uint8_t gpio_in_read(struct gpio_in pin){
|
||||
data_regs[pin.bank] = read_reg(pin.reg);
|
||||
return !!(data_regs[pin.bank] & (1<<pin.pin));
|
||||
}
|
||||
|
||||
struct gpio_in gpio_in_setup(uint8_t pin, int8_t pull_up){
|
||||
struct gpio_mux mux = gpio_mux_setup(pin, PIO_INPUT);
|
||||
|
||||
uint32_t pullup_reg = PIO_BASE + mux.bank*0x24 + PULLUP_REG(mux.pin);
|
||||
uint8_t pullup_off = PULLUP_OFF(mux.pin);
|
||||
|
||||
if(mux.bank == 0) { // Handle R_PIO
|
||||
pullup_reg = R_PIO_BASE + PULLUP_REG(mux.pin);
|
||||
}
|
||||
|
||||
write_reg(pullup_reg, pull_up<<pullup_off);
|
||||
|
||||
struct gpio_in in = {
|
||||
.pin = mux.pin,
|
||||
.reg = mux.reg,
|
||||
.bank = mux.bank
|
||||
};
|
||||
data_regs[mux.bank] = read_reg(mux.reg);
|
||||
return in;
|
||||
}
|
||||
|
||||
void gpio_in_reset(struct gpio_in pin, int8_t pull_up){
|
||||
uint8_t p = pin.bank * 32 + pin.pin;
|
||||
gpio_in_setup(p, pull_up);
|
||||
}
|
||||
|
||||
void gpio_out_toggle_noirq(struct gpio_out pin){
|
||||
data_regs[pin.bank] ^= (1<<pin.pin);
|
||||
*((volatile uint32_t *)(pin.reg)) = data_regs[pin.bank];
|
||||
}
|
||||
|
||||
void gpio_out_toggle(struct gpio_out pin){
|
||||
gpio_out_toggle_noirq(pin);
|
||||
}
|
||||
|
||||
struct spi_config spi_setup(uint32_t bus, uint8_t mode, uint32_t rate){
|
||||
return (struct spi_config){ };
|
||||
}
|
||||
|
||||
void spi_prepare(struct spi_config config){
|
||||
}
|
||||
|
||||
void spi_transfer(struct spi_config config, uint8_t receive_data
|
||||
, uint8_t len, uint8_t *data){
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
#ifndef __AR100_GPIO_H
|
||||
#define __AR100_GPIO_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct gpio_out {
|
||||
uint8_t pin;
|
||||
uint8_t bank;
|
||||
uint32_t reg;
|
||||
};
|
||||
|
||||
struct gpio_in {
|
||||
uint8_t pin;
|
||||
uint8_t bank;
|
||||
uint32_t reg;
|
||||
};
|
||||
|
||||
extern volatile uint32_t data_regs[8];
|
||||
|
||||
|
||||
struct gpio_in gpio_in_setup(uint8_t pin, int8_t pull_up);
|
||||
void gpio_in_reset(struct gpio_in pin, int8_t pull_up);
|
||||
uint8_t gpio_in_read(struct gpio_in pin);
|
||||
|
||||
struct gpio_out gpio_out_setup(uint8_t pin, uint8_t val);
|
||||
void gpio_out_write(struct gpio_out pin, uint8_t val);
|
||||
void gpio_out_reset(struct gpio_out pin, uint8_t val);
|
||||
void gpio_out_toggle_noirq(struct gpio_out pin);
|
||||
void gpio_out_toggle(struct gpio_out pin);
|
||||
struct gpio_in gpio_in_setup(uint8_t pin, int8_t pull_up);
|
||||
void gpio_in_reset(struct gpio_in pin, int8_t pull_up);
|
||||
uint8_t gpio_in_read(struct gpio_in pin);
|
||||
|
||||
struct spi_config {
|
||||
void *spi;
|
||||
uint32_t spi_cr1;
|
||||
};
|
||||
struct spi_config spi_setup(uint32_t bus, uint8_t mode, uint32_t rate);
|
||||
void spi_prepare(struct spi_config config);
|
||||
void spi_transfer(struct spi_config config, uint8_t receive_data
|
||||
, uint8_t len, uint8_t *data);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,34 @@
|
|||
#ifndef __AR100_INTERNAL_H
|
||||
#define __AR100_INTERNAL_H
|
||||
|
||||
#define R_PIO_BASE 0x01F02C00
|
||||
#define PIO_BASE 0x01C20800
|
||||
|
||||
enum pin_func {
|
||||
PIO_INPUT,
|
||||
PIO_OUTPUT,
|
||||
PIO_ALT1,
|
||||
PIO_ALT2,
|
||||
PIO_ALT3,
|
||||
PIO_ALT4,
|
||||
PIO_ALT5,
|
||||
PIO_DISABLE
|
||||
};
|
||||
|
||||
struct gpio_mux {
|
||||
uint32_t pin;
|
||||
uint8_t bank;
|
||||
uint32_t reg;
|
||||
};
|
||||
|
||||
struct gpio_mux gpio_mux_setup(uint8_t pin, enum pin_func func);
|
||||
static inline unsigned long mfspr(unsigned long add){
|
||||
unsigned long ret;
|
||||
__asm__ __volatile__ ("l.mfspr %0,r0,%1" : "=r" (ret) : "K" (add));
|
||||
return ret;
|
||||
}
|
||||
static inline void mtspr(unsigned long add, unsigned long val){
|
||||
__asm__ __volatile__ ("l.mtspr r0,%1,%0" : : "K" (add), "r" (val));
|
||||
}
|
||||
|
||||
#endif // internal.h
|
|
@ -0,0 +1,157 @@
|
|||
// Main entry point for ar100
|
||||
//
|
||||
// Copyright (C) 2020-2021 Elias Bakken <elias@iagent.no>
|
||||
//
|
||||
// This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
|
||||
#include <stdint.h> // uint32_t
|
||||
#include <string.h>
|
||||
#include "board/misc.h" // dynmem_start
|
||||
#include "board/irq.h" // irq_disable
|
||||
#include "command.h" // shutdown
|
||||
#include "generic/timer_irq.h" // timer_dispatch_many
|
||||
#include "sched.h" // sched_main
|
||||
|
||||
#include "asm/spr.h"
|
||||
#include "util.h"
|
||||
#include "gpio.h"
|
||||
#include "serial.h"
|
||||
#include "timer.h"
|
||||
|
||||
DECL_CONSTANT_STR("MCU", "ar100");
|
||||
|
||||
#define RESET_VECTOR 0x0100
|
||||
|
||||
static struct task_wake console_wake;
|
||||
static uint8_t receive_buf[192];
|
||||
static int receive_pos;
|
||||
static char dynmem_pool[8 * 1024];
|
||||
|
||||
void *
|
||||
dynmem_start(void)
|
||||
{
|
||||
return dynmem_pool;
|
||||
}
|
||||
|
||||
void *
|
||||
dynmem_end(void)
|
||||
{
|
||||
return &dynmem_pool[sizeof(dynmem_pool)];
|
||||
}
|
||||
|
||||
void
|
||||
irq_disable(void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
irq_enable(void)
|
||||
{
|
||||
}
|
||||
|
||||
irqstatus_t
|
||||
irq_save(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
irq_restore(irqstatus_t flag)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
irq_wait(void)
|
||||
{
|
||||
irq_poll();
|
||||
}
|
||||
|
||||
void
|
||||
irq_poll(void)
|
||||
{
|
||||
if(timer_interrupt_pending()) {
|
||||
timer_clear_interrupt();
|
||||
uint32_t next = timer_dispatch_many();
|
||||
timer_set(next);
|
||||
}
|
||||
if(r_uart_fifo_rcv())
|
||||
sched_wake_task(&console_wake);
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
* Console IO
|
||||
****************************************************************/
|
||||
|
||||
// Process any incoming commands
|
||||
void
|
||||
console_task(void)
|
||||
{
|
||||
if (!sched_check_wake(&console_wake))
|
||||
return;
|
||||
|
||||
int ret = 0;
|
||||
for(int i=0; i<r_uart_fifo_rcv(); i++) {
|
||||
receive_buf[receive_pos + ret++] = r_uart_getc();
|
||||
}
|
||||
if(!ret)
|
||||
return;
|
||||
|
||||
int len = receive_pos + ret;
|
||||
uint_fast8_t pop_count, msglen = len > MESSAGE_MAX ? MESSAGE_MAX : len;
|
||||
ret = command_find_and_dispatch(receive_buf, msglen, &pop_count);
|
||||
if (ret) {
|
||||
len -= pop_count;
|
||||
if (len) {
|
||||
memcpy(receive_buf, &receive_buf[pop_count], len);
|
||||
sched_wake_task(&console_wake);
|
||||
}
|
||||
}
|
||||
receive_pos = len;
|
||||
}
|
||||
DECL_TASK(console_task);
|
||||
|
||||
// Encode and transmit a "response" message
|
||||
void
|
||||
console_sendf(const struct command_encoder *ce, va_list args)
|
||||
{
|
||||
uint8_t buf[MESSAGE_MAX];
|
||||
uint_fast8_t msglen = command_encode_and_frame(buf, ce, args);
|
||||
|
||||
for(int i=0; i<msglen; i++) {
|
||||
r_uart_putc(buf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void restore_data(void)
|
||||
{
|
||||
extern char __data_start, __data_end, __copy_start;
|
||||
memcpy (&__data_start, &__copy_start, &__data_end - &__data_start);
|
||||
}
|
||||
|
||||
void
|
||||
command_reset(uint32_t *args)
|
||||
{
|
||||
timer_reset();
|
||||
restore_data();
|
||||
void *reset = (void *)RESET_VECTOR;
|
||||
goto *reset;
|
||||
}
|
||||
DECL_COMMAND_FLAGS(command_reset, HF_IN_SHUTDOWN, "reset");
|
||||
|
||||
void
|
||||
save_data(void)
|
||||
{
|
||||
extern char __data_start, __data_end, __copy_start;
|
||||
memcpy (&__copy_start, &__data_start, &__data_end - &__data_start);
|
||||
}
|
||||
|
||||
__noreturn void
|
||||
main(uint32_t exception);
|
||||
__noreturn void
|
||||
main(uint32_t exception)
|
||||
{
|
||||
save_data();
|
||||
r_uart_init();
|
||||
sched_main();
|
||||
while(1) {} // Stop complaining about noreturn
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
// Uart and r_uart functions for ar100
|
||||
//
|
||||
// Copyright (C) 2020-2021 Elias Bakken <elias@iagent.no>
|
||||
//
|
||||
// This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
|
||||
|
||||
#include "serial.h"
|
||||
#include "util.h"
|
||||
#include "internal.h"
|
||||
#include "gpio.h"
|
||||
|
||||
void r_uart_init(void){
|
||||
// Setup Pins PL2, PL3 as UART IO
|
||||
gpio_mux_setup(2, PIO_ALT1);
|
||||
gpio_mux_setup(3, PIO_ALT1);
|
||||
|
||||
// Enable clock and assert reset
|
||||
clear_bit(APB0_CLK_GATING_REG, 4);
|
||||
set_bit(APB0_SOFT_RST_REG, 4);
|
||||
set_bit(APB0_CLK_GATING_REG, 4);
|
||||
|
||||
// Setup baud rate
|
||||
set_bit(R_UART_LCR, 7); // Enable setting DLH, DLL
|
||||
write_reg(R_UART_DLH, 0x0);
|
||||
write_reg(R_UART_DLL, 0xD); // 1 500 000
|
||||
write_reg(R_UART_LCR, 0x3); // 8 bit data length
|
||||
|
||||
write_reg(R_UART_FCR, 0<<0); // Disable fifo
|
||||
r_uart_getc(); // flush input
|
||||
write_reg(R_UART_FCR, 1<<0); // Enable fifo
|
||||
}
|
||||
|
||||
char r_uart_getc(void){
|
||||
char c = (char) read_reg(R_UART_RBR);
|
||||
return c;
|
||||
}
|
||||
|
||||
uint32_t r_uart_fifo_rcv(void){
|
||||
return read_reg(R_UART_RFL);
|
||||
}
|
||||
|
||||
void r_uart_putc(char c){
|
||||
while(!(read_reg(R_UART_LSR) & 1<<5))
|
||||
;
|
||||
write_reg(R_UART_THR, c);
|
||||
}
|
||||
|
||||
void r_uart_puts(char *s){
|
||||
while(*s){
|
||||
r_uart_putc(*s++);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
#include <stdint.h>
|
||||
|
||||
#define R_UART_BASE 0x01F02800
|
||||
#define R_UART_RBR R_UART_BASE + 0x00 // UART Receive Buffer Register
|
||||
#define R_UART_THR R_UART_BASE + 0x00 // UART Transmit Holding Register
|
||||
#define R_UART_DLL R_UART_BASE + 0x00 // UART Divisor Latch Low Register
|
||||
#define R_UART_DLH R_UART_BASE + 0x04 // UART Divisor Latch High Register
|
||||
#define R_UART_IER R_UART_BASE + 0x04 // UART Interrupt Enable Register
|
||||
#define R_UART_IIR R_UART_BASE + 0x08 // UART Interrupt Identity Register
|
||||
#define R_UART_FCR R_UART_BASE + 0x08 // UART FIFO Control Register
|
||||
#define R_UART_LCR R_UART_BASE + 0x0C // UART Line Control Register
|
||||
#define R_UART_MCR R_UART_BASE + 0x10 // UART Modem Control Register
|
||||
#define R_UART_LSR R_UART_BASE + 0x14 // UART Line Status Register
|
||||
#define R_UART_MSR R_UART_BASE + 0x18 // UART Modem Status Register
|
||||
#define R_UART_SCH R_UART_BASE + 0x1C // UART Scratch Register
|
||||
#define R_UART_USR R_UART_BASE + 0x7C // UART Status Register
|
||||
#define R_UART_TFL R_UART_BASE + 0x80 // UART Transmit FIFO Level
|
||||
#define R_UART_RFL R_UART_BASE + 0x84 // UART_RFL
|
||||
#define R_UART_HLT R_UART_BASE + 0xA4 // UART Halt TX Register
|
||||
|
||||
#define UART0_BASE 0x01C28000
|
||||
#define UART0_RBR UART0_BASE + 0x00 // UART Receive Buffer Register
|
||||
#define UART0_THR UART0_BASE + 0x00 // UART Transmit Holding Register
|
||||
#define UART0_DLL UART0_BASE + 0x00 // UART Divisor Latch Low Register
|
||||
#define UART0_DLH UART0_BASE + 0x04 // UART Divisor Latch High Register
|
||||
#define UART0_IER UART0_BASE + 0x04 // UART Interrupt Enable Register
|
||||
#define UART0_IIR UART0_BASE + 0x08 // UART Interrupt Identity Register
|
||||
#define UART0_FCR UART0_BASE + 0x08 // UART FIFO Control Register
|
||||
#define UART0_LCR UART0_BASE + 0x0C // UART Line Control Register
|
||||
#define UART0_MCR UART0_BASE + 0x10 // UART Modem Control Register
|
||||
#define UART0_LSR UART0_BASE + 0x14 // UART Line Status Register
|
||||
#define UART0_MSR UART0_BASE + 0x18 // UART Modem Status Register
|
||||
#define UART0_SCH UART0_BASE + 0x1C // UART Scratch Register
|
||||
#define UART0_USR UART0_BASE + 0x7C // UART Status Register
|
||||
#define UART0_TFL UART0_BASE + 0x80 // UART Transmit FIFO Level
|
||||
#define UART0_RFL UART0_BASE + 0x84 // UART_RFL
|
||||
#define UART0_HLT UART0_BASE + 0xA4 // UART Halt TX Register
|
||||
|
||||
|
||||
#define R_PRCM_BASE 0x01F01400
|
||||
#define APB0_CLK_GATING_REG R_PRCM_BASE + 0x0028 // APB0 Clock Gating Reg
|
||||
#define APB0_SOFT_RST_REG R_PRCM_BASE + 0x00B0 // APB0 SW Reset Reg
|
||||
|
||||
void r_uart_init(void);
|
||||
void r_uart_putc(char c);
|
||||
char r_uart_getc(void);
|
||||
uint32_t r_uart_fifo_rcv(void);
|
||||
void uart_putc(char c);
|
||||
void uart_puts(char *s);
|
||||
void uart_puti(uint32_t u);
|
|
@ -0,0 +1,52 @@
|
|||
// Timer functions for ar100
|
||||
//
|
||||
// Copyright (C) 2020-2021 Elias Bakken <elias@iagent.no>
|
||||
//
|
||||
// This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
|
||||
#include "timer.h"
|
||||
#include "board/timer_irq.h"
|
||||
#include "board/misc.h"
|
||||
|
||||
volatile static uint32_t timer_compare;
|
||||
static uint8_t interrupt_seen;
|
||||
|
||||
uint8_t timer_interrupt_pending(void){
|
||||
if(interrupt_seen){
|
||||
return 0;
|
||||
}
|
||||
if(timer_is_before(mfspr(SPR_TICK_TTCR_ADDR), timer_compare)){
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
void timer_clear_interrupt(void){
|
||||
interrupt_seen = 1;
|
||||
}
|
||||
// Set the next timer wake up time
|
||||
void timer_set(uint32_t value){
|
||||
timer_compare = value;
|
||||
interrupt_seen = 0;
|
||||
}
|
||||
|
||||
// Return the current time (in absolute clock ticks).
|
||||
uint32_t timer_read_time(void){
|
||||
return mfspr(SPR_TICK_TTCR_ADDR);
|
||||
}
|
||||
|
||||
void timer_reset(void){
|
||||
mtspr(SPR_TICK_TTCR_ADDR, 0);
|
||||
}
|
||||
|
||||
// Activate timer dispatch as soon as possible
|
||||
void timer_kick(void){
|
||||
timer_set(timer_read_time() + 50);
|
||||
}
|
||||
|
||||
void timer_init(void){
|
||||
interrupt_seen = 1;
|
||||
mtspr(SPR_TICK_TTMR_ADDR, 3<<30); // continous
|
||||
timer_kick();
|
||||
}
|
||||
DECL_INIT(timer_init);
|
|
@ -0,0 +1,12 @@
|
|||
#include <stdint.h>
|
||||
#include "asm/spr.h"
|
||||
#include "sched.h"
|
||||
#include "internal.h"
|
||||
|
||||
uint8_t timer_interrupt_pending(void);
|
||||
void timer_set(uint32_t value);
|
||||
uint32_t timer_read_time(void);
|
||||
void timer_reset(void);
|
||||
void timer_clear_interrupt(void);
|
||||
void timer_kick(void);
|
||||
void timer_init(void);
|
|
@ -0,0 +1,34 @@
|
|||
// Helper functions for ar100
|
||||
//
|
||||
// Copyright (C) 2020-2021 Elias Bakken <elias@iagent.no>
|
||||
//
|
||||
// This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
|
||||
#include "util.h"
|
||||
|
||||
void *memcpy(void *restrict dest, const void *restrict src, size_t n){
|
||||
// Typecast src and dest addresses to (char *)
|
||||
char *csrc = (char *)src;
|
||||
char *cdest = (char *)dest;
|
||||
|
||||
// Copy contents of src[] to dest[]
|
||||
for (int i=0; i<n; i++)
|
||||
cdest[i] = csrc[i];
|
||||
return dest;
|
||||
}
|
||||
|
||||
void *memset(void *dest, int c, size_t n){
|
||||
unsigned char *s = dest;
|
||||
for(; n; n--){
|
||||
*s++ = c;
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
void set_bit(uint32_t addr, uint8_t bit){
|
||||
write_reg(addr, read_reg(addr) | (1<<bit));
|
||||
}
|
||||
|
||||
void clear_bit(uint32_t addr, uint8_t bit){
|
||||
write_reg(addr, read_reg(addr) & ~(1<<bit));
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
void *memcpy(void *restrict dest, const void *restrict src, size_t n);
|
||||
void *memset(void *restrict dest, int c, size_t n);
|
||||
|
||||
inline void write_reg(uint32_t addr, uint32_t val){
|
||||
*((volatile unsigned long *)(addr)) = val;
|
||||
}
|
||||
|
||||
inline uint32_t read_reg(uint32_t addr){
|
||||
return *((volatile unsigned long *)(addr));
|
||||
}
|
||||
|
||||
void set_bit(uint32_t addr, uint8_t bit);
|
||||
|
||||
void clear_bit(uint32_t addr, uint8_t bit);
|
|
@ -0,0 +1,2 @@
|
|||
# Base config file for the ar100 CPU
|
||||
CONFIG_MACH_AR100=y
|
Loading…
Reference in New Issue