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 |
|
| 1 stepper (200Mhz) | 39 |
|
||||||
| 3 stepper (200Mhz) | 181 |
|
| 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
|
### RP2040 step rate benchmark
|
||||||
|
|
||||||
The following configuration sequence is used on the RP2040:
|
The following configuration sequence is used on the RP2040:
|
||||||
|
@ -425,6 +446,7 @@ hub.
|
||||||
| atmega2560 (serial) | 23K | b161a69e | avr-gcc (GCC) 4.8.1 |
|
| 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 |
|
| 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 |
|
| 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 |
|
| 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) |
|
| 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 |
|
| 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 |
|
| RP2040 | 2400K | 1636K |
|
||||||
| SAM4E8E | 2500K | 1674K |
|
| SAM4E8E | 2500K | 1674K |
|
||||||
| SAMD51 | 3077K | 1885K |
|
| SAMD51 | 3077K | 1885K |
|
||||||
|
| AR100 | 3529K | 2507K |
|
||||||
| STM32F407 | 3652K | 2459K |
|
| STM32F407 | 3652K | 2459K |
|
||||||
| STM32F446 | 3913K | 2634K |
|
| STM32F446 | 3913K | 2634K |
|
||||||
| STM32H743 | 9091K | 6061K |
|
| 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
|
so that the IEP definitions compile correctly. See pru_rpmsg.patch for
|
||||||
the modifications.
|
the modifications.
|
||||||
|
|
||||||
|
The ar100 directory contains code from:
|
||||||
|
https://github.com/crust-firmware/crust
|
||||||
|
revision 966124af914ce611aadd06fbbcbc4c36c4a0b240
|
||||||
|
|
||||||
The fast-hash directory contains code from:
|
The fast-hash directory contains code from:
|
||||||
https://github.com/ztanml/fast-hash
|
https://github.com/ztanml/fast-hash
|
||||||
revision ae3bb53c199fe75619e940b5b6a3584ede99c5fc
|
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}
|
MAIN_DIR=${PWD}
|
||||||
BUILD_DIR=${PWD}/ci_build
|
BUILD_DIR=${PWD}/ci_build
|
||||||
export PATH=${BUILD_DIR}/pru-gcc/bin:${PATH}
|
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
|
PYTHON=${BUILD_DIR}/python-env/bin/python
|
||||||
PYTHON2=${BUILD_DIR}/python2-env/bin/python
|
PYTHON2=${BUILD_DIR}/python2-env/bin/python
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,21 @@ else
|
||||||
tar xfz ${PRU_FILE}
|
tar xfz ${PRU_FILE}
|
||||||
fi
|
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
|
# 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"
|
bool "Raspberry Pi RP2040"
|
||||||
config MACH_PRU
|
config MACH_PRU
|
||||||
bool "Beaglebone PRU"
|
bool "Beaglebone PRU"
|
||||||
|
config MACH_AR100
|
||||||
|
bool "Allwinner A64 AR100"
|
||||||
config MACH_LINUX
|
config MACH_LINUX
|
||||||
bool "Linux process"
|
bool "Linux process"
|
||||||
config MACH_SIMU
|
config MACH_SIMU
|
||||||
|
@ -40,6 +42,7 @@ source "src/stm32/Kconfig"
|
||||||
source "src/hc32f460/Kconfig"
|
source "src/hc32f460/Kconfig"
|
||||||
source "src/rp2040/Kconfig"
|
source "src/rp2040/Kconfig"
|
||||||
source "src/pru/Kconfig"
|
source "src/pru/Kconfig"
|
||||||
|
source "src/ar100/Kconfig"
|
||||||
source "src/linux/Kconfig"
|
source "src/linux/Kconfig"
|
||||||
source "src/simulator/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