Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

targets: add implementation for Tillitis TKey device #4631

Merged
merged 15 commits into from
Dec 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions GNUmakefile
Original file line number Diff line number Diff line change
Expand Up @@ -853,6 +853,8 @@ endif
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=maixbit examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=tkey examples/blinky1
@$(MD5SUM) test.hex
ifneq ($(WASM), 0)
$(TINYGO) build -size short -o wasm.wasm -target=wasm examples/wasm/export
$(TINYGO) build -size short -o wasm.wasm -target=wasm examples/wasm/main
Expand Down
1 change: 1 addition & 0 deletions builder/builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ func TestClangAttributes(t *testing.T) {
"k210",
"nintendoswitch",
"riscv-qemu",
"tkey",
"wasip1",
"wasip2",
"wasm",
Expand Down
2 changes: 1 addition & 1 deletion src/crypto/rand/rand_baremetal.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build nrf || (stm32 && !(stm32f103 || stm32l0x1)) || (sam && atsamd51) || (sam && atsame5x) || esp32c3
//go:build nrf || (stm32 && !(stm32f103 || stm32l0x1)) || (sam && atsamd51) || (sam && atsame5x) || esp32c3 || tkey

// If you update the above build constraint, you'll probably also need to update
// src/runtime/rand_hwrng.go.
Expand Down
139 changes: 139 additions & 0 deletions src/device/tkey/tkey.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
//go:build tkey

// Hand written file based on https://github.com/tillitis/tkey-libs/blob/main/include/tkey/tk1_mem.h
deadprogram marked this conversation as resolved.
Show resolved Hide resolved

package tkey

import (
"runtime/volatile"
"unsafe"
)

// Peripherals
var (
TRNG = (*TRNG_Type)(unsafe.Pointer(TK1_MMIO_TRNG_BASE))

TIMER = (*TIMER_Type)(unsafe.Pointer(TK1_MMIO_TIMER_BASE))

UDS = (*UDS_Type)(unsafe.Pointer(TK1_MMIO_UDS_BASE))

UART = (*UART_Type)(unsafe.Pointer(TK1_MMIO_UART_BASE))

TOUCH = (*TOUCH_Type)(unsafe.Pointer(TK1_MMIO_TOUCH_BASE))

TK1 = (*TK1_Type)(unsafe.Pointer(TK1_MMIO_TK1_BASE))
)

// Memory sections
const (
TK1_ROM_BASE uintptr = 0x00000000

TK1_RAM_BASE uintptr = 0x40000000

TK1_MMIO_BASE uintptr = 0xc0000000

TK1_MMIO_TRNG_BASE uintptr = 0xc0000000

TK1_MMIO_TIMER_BASE uintptr = 0xc1000000

TK1_MMIO_UDS_BASE uintptr = 0xc2000000

TK1_MMIO_UART_BASE uintptr = 0xc3000000

TK1_MMIO_TOUCH_BASE uintptr = 0xc4000000

TK1_MMIO_FW_RAM_BASE uintptr = 0xd0000000

TK1_MMIO_TK1_BASE uintptr = 0xff000000
)

// Memory section sizes
const (
TK1_RAM_SIZE uintptr = 0x20000

TK1_MMIO_SIZE uintptr = 0x3fffffff
)

type TRNG_Type struct {
_ [36]byte
STATUS volatile.Register32
_ [88]byte
ENTROPY volatile.Register32
}

type TIMER_Type struct {
_ [32]byte
CTRL volatile.Register32
STATUS volatile.Register32
PRESCALER volatile.Register32
TIMER volatile.Register32
}

type UDS_Type struct {
_ [64]byte
DATA [8]volatile.Register32
}

type UART_Type struct {
_ [128]byte
RX_STATUS volatile.Register32
RX_DATA volatile.Register32
RX_BYTES volatile.Register32
_ [116]byte
TX_STATUS volatile.Register32
TX_DATA volatile.Register32
}

type TOUCH_Type struct {
_ [36]byte
STATUS volatile.Register32
}

type TK1_Type struct {
NAME0 volatile.Register32
NAME1 volatile.Register32
VERSION volatile.Register32
_ [16]byte
SWITCH_APP volatile.Register32
_ [4]byte
LED volatile.Register32
GPIO volatile.Register16
APP_ADDR volatile.Register32
APP_SIZE volatile.Register32
BLAKE2S volatile.Register32
_ [72]byte
CDI_FIRST [8]volatile.Register32
_ [32]byte
UDI_FIRST [2]volatile.Register32
_ [62]byte
RAM_ADDR_RAND volatile.Register16
_ [2]byte
RAM_DATA_RAND volatile.Register16
_ [126]byte
CPU_MON_CTRL volatile.Register16
_ [2]byte
CPU_MON_FIRST volatile.Register32
CPU_MON_LAST volatile.Register32
_ [60]byte
SYSTEM_RESET volatile.Register16
_ [66]byte
SPI_EN volatile.Register32
SPI_XFER volatile.Register32
SPI_DATA volatile.Register32
}

const (
TK1_MMIO_TIMER_CTRL_START_BIT = 0
TK1_MMIO_TIMER_CTRL_STOP_BIT = 1
TK1_MMIO_TIMER_CTRL_START = 1 << TK1_MMIO_TIMER_CTRL_START_BIT
TK1_MMIO_TIMER_CTRL_STOP = 1 << TK1_MMIO_TIMER_CTRL_STOP_BIT

TK1_MMIO_TK1_LED_R_BIT = 2
TK1_MMIO_TK1_LED_G_BIT = 1
TK1_MMIO_TK1_LED_B_BIT = 0

TK1_MMIO_TK1_GPIO1_BIT = 0
TK1_MMIO_TK1_GPIO2_BIT = 1
TK1_MMIO_TK1_GPIO3_BIT = 2
TK1_MMIO_TK1_GPIO4_BIT = 3
)
234 changes: 234 additions & 0 deletions src/machine/machine_tkey.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
//go:build tkey

package machine

import (
"device/tkey"
"errors"
"strconv"
)

const deviceName = "TKey"
deadprogram marked this conversation as resolved.
Show resolved Hide resolved

// GPIO pins modes are only here to match the Pin interface.
// The actual configuration is fixed in the hardware.
const (
PinOutput PinMode = iota
PinInput
PinInputPullup
PinInputPulldown
)

const (
LED_BLUE = Pin(tkey.TK1_MMIO_TK1_LED_B_BIT)
LED_GREEN = Pin(tkey.TK1_MMIO_TK1_LED_G_BIT)
LED_RED = Pin(tkey.TK1_MMIO_TK1_LED_R_BIT)

LED = LED_GREEN

TKEY_TOUCH = Pin(3) // 3 is unused, but we need a value here to match the Pin interface.
BUTTON = TKEY_TOUCH

GPIO1 = Pin(tkey.TK1_MMIO_TK1_GPIO1_BIT + 8)
GPIO2 = Pin(tkey.TK1_MMIO_TK1_GPIO2_BIT + 8)
GPIO3 = Pin(tkey.TK1_MMIO_TK1_GPIO3_BIT + 8)
GPIO4 = Pin(tkey.TK1_MMIO_TK1_GPIO4_BIT + 8)
)

var touchConfig, gpio1Config, gpio2Config PinConfig

// No config needed for TKey, just to match the Pin interface.
func (p Pin) Configure(config PinConfig) {
switch p {
case BUTTON:
touchConfig = config

// Clear any pending touch events.
tkey.TOUCH.STATUS.Set(0)
case GPIO1:
gpio1Config = config
case GPIO2:
gpio2Config = config
}
}

// Set pin to high or low.
func (p Pin) Set(high bool) {
switch p {
case LED_BLUE, LED_GREEN, LED_RED:
if high {
tkey.TK1.LED.SetBits(1 << uint(p))
} else {
tkey.TK1.LED.ClearBits(1 << uint(p))
}
case GPIO3, GPIO4:
if high {
tkey.TK1.GPIO.SetBits(1 << uint(p-8))
} else {
tkey.TK1.GPIO.ClearBits(1 << uint(p-8))
}
}
}

// Get returns the current value of a pin.
func (p Pin) Get() bool {
pushed := false
mode := PinInput

switch p {
case BUTTON:
mode = touchConfig.Mode
if tkey.TOUCH.STATUS.HasBits(1) {
tkey.TOUCH.STATUS.Set(0)
pushed = true
}
case GPIO1:
mode = gpio1Config.Mode
pushed = tkey.TK1.GPIO.HasBits(1 << uint(p-8))
case GPIO2:
mode = gpio2Config.Mode
pushed = tkey.TK1.GPIO.HasBits(1 << uint(p-8))
case GPIO3, GPIO4:
mode = PinOutput
pushed = tkey.TK1.GPIO.HasBits(1 << uint(p-8))
case LED_BLUE, LED_GREEN, LED_RED:
mode = PinOutput
pushed = tkey.TK1.LED.HasBits(1 << uint(p))
}

switch mode {
case PinInputPullup:
return !pushed
case PinInput, PinInputPulldown, PinOutput:
return pushed
}

return false
}

type UART struct {
Bus *tkey.UART_Type
}

var (
DefaultUART = UART0
UART0 = &_UART0
_UART0 = UART{Bus: tkey.UART}
)

// The TKey UART is fixed at 62500 baud, 8N1.
func (uart *UART) Configure(config UARTConfig) error {
if !(config.BaudRate == 62500 || config.BaudRate == 0) {
return errors.New("uart: only 62500 baud rate is supported")
}

return nil
}

// Write a slice of data bytes to the UART.
func (uart *UART) Write(data []byte) (n int, err error) {
deadprogram marked this conversation as resolved.
Show resolved Hide resolved
for _, c := range data {
if err := uart.WriteByte(c); err != nil {
return n, err
}
}
return len(data), nil
}

// WriteByte writes a byte of data to the UART.
func (uart *UART) WriteByte(c byte) error {
for uart.Bus.TX_STATUS.Get() == 0 {
}

uart.Bus.TX_DATA.Set(uint32(c))

return nil
}

// Buffered returns the number of bytes buffered in the UART.
func (uart *UART) Buffered() int {
return int(uart.Bus.RX_BYTES.Get())
}

// ReadByte reads a byte of data from the UART.
func (uart *UART) ReadByte() (byte, error) {
for uart.Bus.RX_STATUS.Get() == 0 {
}

return byte(uart.Bus.RX_DATA.Get()), nil
}

// DTR is not available on the TKey.
func (uart *UART) DTR() bool {
return false
}

// RTS is not available on the TKey.
func (uart *UART) RTS() bool {
return false
}

// GetRNG returns 32 bits of cryptographically secure random data
func GetRNG() (uint32, error) {
for tkey.TRNG.STATUS.Get() == 0 {
}

return uint32(tkey.TRNG.ENTROPY.Get()), nil
}

// DesignName returns the FPGA design name.
func DesignName() (string, string) {
n0 := tkey.TK1.NAME0.Get()
name0 := string([]byte{byte(n0 >> 24), byte(n0 >> 16), byte(n0 >> 8), byte(n0)})
n1 := tkey.TK1.NAME1.Get()
name1 := string([]byte{byte(n1 >> 24), byte(n1 >> 16), byte(n1 >> 8), byte(n1)})

return name0, name1
}

// DesignVersion returns the FPGA design version.
func DesignVersion() string {
version := tkey.TK1.VERSION.Get()

return strconv.Itoa(int(version))
}

// CDI returns 8 words of Compound Device Identifier (CDI) generated and written by the firmware when the application is loaded.
func CDI() []byte {
cdi := make([]byte, 32)
for i := 0; i < 8; i++ {
c := tkey.TK1.CDI_FIRST[i].Get()
cdi[i*4] = byte(c >> 24)
cdi[i*4+1] = byte(c >> 16)
cdi[i*4+2] = byte(c >> 8)
cdi[i*4+3] = byte(c)
}
return cdi
}

// UDI returns 2 words of Unique Device Identifier (UDI). Only available in firmware mode.
func UDI() []byte {
udi := make([]byte, 8)
for i := 0; i < 2; i++ {
c := tkey.TK1.UDI_FIRST[i].Get()
udi[i*4] = byte(c >> 24)
udi[i*4+1] = byte(c >> 16)
udi[i*4+2] = byte(c >> 8)
udi[i*4+3] = byte(c)
}
return udi
}

// UDS returns 8 words of Unique Device Secret. Part of the FPGA design, changed when provisioning a TKey.
// Only available in firmware mode. UDS is only readable once per power cycle.
func UDS() []byte {
uds := make([]byte, 32)
for i := 0; i < 8; i++ {
c := tkey.UDS.DATA[i].Get()
uds[i*4] = byte(c >> 24)
uds[i*4+1] = byte(c >> 16)
uds[i*4+2] = byte(c >> 8)
uds[i*4+3] = byte(c)
}
return uds
}
Loading
Loading