Skip to content

Commit 17302ca

Browse files
authored
targets: add implementation for Tillitis TKey device (#4631)
* initial implementation for Tillitis TKey device * add UART implementation for TKey * add Pin interface implementation for TKey touch sensor * add RNG interface implementation for TKey * add helpful machine package functions to return identifiers such as name and version for TKey * use built-in timer for sleep timing on TKey * modify UART implementation for TKey to implement Serialer interface * implement BLAKE2s ROM function call for TKey device * handle abort by triggering TKey device fault using illegal instruction to halt CPU * simplify TKey implementation by inheriting from existing riscv32 target * return error for trying to configure invalid baudrates on UART * add tkey to builder test * be very specific for features passed to LLVM for specific config in use for TKey * handle feedback items from TKey device code review Signed-off-by: deadprogram <ron@hybridgroup.com>
1 parent f246599 commit 17302ca

File tree

12 files changed

+550
-3
lines changed

12 files changed

+550
-3
lines changed

GNUmakefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -853,6 +853,8 @@ endif
853853
@$(MD5SUM) test.hex
854854
$(TINYGO) build -size short -o test.hex -target=maixbit examples/blinky1
855855
@$(MD5SUM) test.hex
856+
$(TINYGO) build -size short -o test.hex -target=tkey examples/blinky1
857+
@$(MD5SUM) test.hex
856858
ifneq ($(WASM), 0)
857859
$(TINYGO) build -size short -o wasm.wasm -target=wasm examples/wasm/export
858860
$(TINYGO) build -size short -o wasm.wasm -target=wasm examples/wasm/main

builder/builder_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ func TestClangAttributes(t *testing.T) {
3333
"k210",
3434
"nintendoswitch",
3535
"riscv-qemu",
36+
"tkey",
3637
"wasip1",
3738
"wasip2",
3839
"wasm",

src/crypto/rand/rand_baremetal.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//go:build nrf || (stm32 && !(stm32f103 || stm32l0x1)) || (sam && atsamd51) || (sam && atsame5x) || esp32c3
1+
//go:build nrf || (stm32 && !(stm32f103 || stm32l0x1)) || (sam && atsamd51) || (sam && atsame5x) || esp32c3 || tkey
22

33
// If you update the above build constraint, you'll probably also need to update
44
// src/runtime/rand_hwrng.go.

src/device/tkey/tkey.go

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
//go:build tkey
2+
3+
// Hand written file based on https://github.com/tillitis/tkey-libs/blob/main/include/tkey/tk1_mem.h
4+
5+
package tkey
6+
7+
import (
8+
"runtime/volatile"
9+
"unsafe"
10+
)
11+
12+
// Peripherals
13+
var (
14+
TRNG = (*TRNG_Type)(unsafe.Pointer(TK1_MMIO_TRNG_BASE))
15+
16+
TIMER = (*TIMER_Type)(unsafe.Pointer(TK1_MMIO_TIMER_BASE))
17+
18+
UDS = (*UDS_Type)(unsafe.Pointer(TK1_MMIO_UDS_BASE))
19+
20+
UART = (*UART_Type)(unsafe.Pointer(TK1_MMIO_UART_BASE))
21+
22+
TOUCH = (*TOUCH_Type)(unsafe.Pointer(TK1_MMIO_TOUCH_BASE))
23+
24+
TK1 = (*TK1_Type)(unsafe.Pointer(TK1_MMIO_TK1_BASE))
25+
)
26+
27+
// Memory sections
28+
const (
29+
TK1_ROM_BASE uintptr = 0x00000000
30+
31+
TK1_RAM_BASE uintptr = 0x40000000
32+
33+
TK1_MMIO_BASE uintptr = 0xc0000000
34+
35+
TK1_MMIO_TRNG_BASE uintptr = 0xc0000000
36+
37+
TK1_MMIO_TIMER_BASE uintptr = 0xc1000000
38+
39+
TK1_MMIO_UDS_BASE uintptr = 0xc2000000
40+
41+
TK1_MMIO_UART_BASE uintptr = 0xc3000000
42+
43+
TK1_MMIO_TOUCH_BASE uintptr = 0xc4000000
44+
45+
TK1_MMIO_FW_RAM_BASE uintptr = 0xd0000000
46+
47+
TK1_MMIO_TK1_BASE uintptr = 0xff000000
48+
)
49+
50+
// Memory section sizes
51+
const (
52+
TK1_RAM_SIZE uintptr = 0x20000
53+
54+
TK1_MMIO_SIZE uintptr = 0x3fffffff
55+
)
56+
57+
type TRNG_Type struct {
58+
_ [36]byte
59+
STATUS volatile.Register32
60+
_ [88]byte
61+
ENTROPY volatile.Register32
62+
}
63+
64+
type TIMER_Type struct {
65+
_ [32]byte
66+
CTRL volatile.Register32
67+
STATUS volatile.Register32
68+
PRESCALER volatile.Register32
69+
TIMER volatile.Register32
70+
}
71+
72+
type UDS_Type struct {
73+
_ [64]byte
74+
DATA [8]volatile.Register32
75+
}
76+
77+
type UART_Type struct {
78+
_ [128]byte
79+
RX_STATUS volatile.Register32
80+
RX_DATA volatile.Register32
81+
RX_BYTES volatile.Register32
82+
_ [116]byte
83+
TX_STATUS volatile.Register32
84+
TX_DATA volatile.Register32
85+
}
86+
87+
type TOUCH_Type struct {
88+
_ [36]byte
89+
STATUS volatile.Register32
90+
}
91+
92+
type TK1_Type struct {
93+
NAME0 volatile.Register32
94+
NAME1 volatile.Register32
95+
VERSION volatile.Register32
96+
_ [16]byte
97+
SWITCH_APP volatile.Register32
98+
_ [4]byte
99+
LED volatile.Register32
100+
GPIO volatile.Register16
101+
APP_ADDR volatile.Register32
102+
APP_SIZE volatile.Register32
103+
BLAKE2S volatile.Register32
104+
_ [72]byte
105+
CDI_FIRST [8]volatile.Register32
106+
_ [32]byte
107+
UDI_FIRST [2]volatile.Register32
108+
_ [62]byte
109+
RAM_ADDR_RAND volatile.Register16
110+
_ [2]byte
111+
RAM_DATA_RAND volatile.Register16
112+
_ [126]byte
113+
CPU_MON_CTRL volatile.Register16
114+
_ [2]byte
115+
CPU_MON_FIRST volatile.Register32
116+
CPU_MON_LAST volatile.Register32
117+
_ [60]byte
118+
SYSTEM_RESET volatile.Register16
119+
_ [66]byte
120+
SPI_EN volatile.Register32
121+
SPI_XFER volatile.Register32
122+
SPI_DATA volatile.Register32
123+
}
124+
125+
const (
126+
TK1_MMIO_TIMER_CTRL_START_BIT = 0
127+
TK1_MMIO_TIMER_CTRL_STOP_BIT = 1
128+
TK1_MMIO_TIMER_CTRL_START = 1 << TK1_MMIO_TIMER_CTRL_START_BIT
129+
TK1_MMIO_TIMER_CTRL_STOP = 1 << TK1_MMIO_TIMER_CTRL_STOP_BIT
130+
131+
TK1_MMIO_TK1_LED_R_BIT = 2
132+
TK1_MMIO_TK1_LED_G_BIT = 1
133+
TK1_MMIO_TK1_LED_B_BIT = 0
134+
135+
TK1_MMIO_TK1_GPIO1_BIT = 0
136+
TK1_MMIO_TK1_GPIO2_BIT = 1
137+
TK1_MMIO_TK1_GPIO3_BIT = 2
138+
TK1_MMIO_TK1_GPIO4_BIT = 3
139+
)

src/machine/machine_tkey.go

Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
//go:build tkey
2+
3+
package machine
4+
5+
import (
6+
"device/tkey"
7+
"errors"
8+
"strconv"
9+
)
10+
11+
const deviceName = "TKey"
12+
13+
// GPIO pins modes are only here to match the Pin interface.
14+
// The actual configuration is fixed in the hardware.
15+
const (
16+
PinOutput PinMode = iota
17+
PinInput
18+
PinInputPullup
19+
PinInputPulldown
20+
)
21+
22+
const (
23+
LED_BLUE = Pin(tkey.TK1_MMIO_TK1_LED_B_BIT)
24+
LED_GREEN = Pin(tkey.TK1_MMIO_TK1_LED_G_BIT)
25+
LED_RED = Pin(tkey.TK1_MMIO_TK1_LED_R_BIT)
26+
27+
LED = LED_GREEN
28+
29+
TKEY_TOUCH = Pin(3) // 3 is unused, but we need a value here to match the Pin interface.
30+
BUTTON = TKEY_TOUCH
31+
32+
GPIO1 = Pin(tkey.TK1_MMIO_TK1_GPIO1_BIT + 8)
33+
GPIO2 = Pin(tkey.TK1_MMIO_TK1_GPIO2_BIT + 8)
34+
GPIO3 = Pin(tkey.TK1_MMIO_TK1_GPIO3_BIT + 8)
35+
GPIO4 = Pin(tkey.TK1_MMIO_TK1_GPIO4_BIT + 8)
36+
)
37+
38+
var touchConfig, gpio1Config, gpio2Config PinConfig
39+
40+
// No config needed for TKey, just to match the Pin interface.
41+
func (p Pin) Configure(config PinConfig) {
42+
switch p {
43+
case BUTTON:
44+
touchConfig = config
45+
46+
// Clear any pending touch events.
47+
tkey.TOUCH.STATUS.Set(0)
48+
case GPIO1:
49+
gpio1Config = config
50+
case GPIO2:
51+
gpio2Config = config
52+
}
53+
}
54+
55+
// Set pin to high or low.
56+
func (p Pin) Set(high bool) {
57+
switch p {
58+
case LED_BLUE, LED_GREEN, LED_RED:
59+
if high {
60+
tkey.TK1.LED.SetBits(1 << uint(p))
61+
} else {
62+
tkey.TK1.LED.ClearBits(1 << uint(p))
63+
}
64+
case GPIO3, GPIO4:
65+
if high {
66+
tkey.TK1.GPIO.SetBits(1 << uint(p-8))
67+
} else {
68+
tkey.TK1.GPIO.ClearBits(1 << uint(p-8))
69+
}
70+
}
71+
}
72+
73+
// Get returns the current value of a pin.
74+
func (p Pin) Get() bool {
75+
pushed := false
76+
mode := PinInput
77+
78+
switch p {
79+
case BUTTON:
80+
mode = touchConfig.Mode
81+
if tkey.TOUCH.STATUS.HasBits(1) {
82+
tkey.TOUCH.STATUS.Set(0)
83+
pushed = true
84+
}
85+
case GPIO1:
86+
mode = gpio1Config.Mode
87+
pushed = tkey.TK1.GPIO.HasBits(1 << uint(p-8))
88+
case GPIO2:
89+
mode = gpio2Config.Mode
90+
pushed = tkey.TK1.GPIO.HasBits(1 << uint(p-8))
91+
case GPIO3, GPIO4:
92+
mode = PinOutput
93+
pushed = tkey.TK1.GPIO.HasBits(1 << uint(p-8))
94+
case LED_BLUE, LED_GREEN, LED_RED:
95+
mode = PinOutput
96+
pushed = tkey.TK1.LED.HasBits(1 << uint(p))
97+
}
98+
99+
switch mode {
100+
case PinInputPullup:
101+
return !pushed
102+
case PinInput, PinInputPulldown, PinOutput:
103+
return pushed
104+
}
105+
106+
return false
107+
}
108+
109+
type UART struct {
110+
Bus *tkey.UART_Type
111+
}
112+
113+
var (
114+
DefaultUART = UART0
115+
UART0 = &_UART0
116+
_UART0 = UART{Bus: tkey.UART}
117+
)
118+
119+
// The TKey UART is fixed at 62500 baud, 8N1.
120+
func (uart *UART) Configure(config UARTConfig) error {
121+
if !(config.BaudRate == 62500 || config.BaudRate == 0) {
122+
return errors.New("uart: only 62500 baud rate is supported")
123+
}
124+
125+
return nil
126+
}
127+
128+
// Write a slice of data bytes to the UART.
129+
func (uart *UART) Write(data []byte) (n int, err error) {
130+
for _, c := range data {
131+
if err := uart.WriteByte(c); err != nil {
132+
return n, err
133+
}
134+
}
135+
return len(data), nil
136+
}
137+
138+
// WriteByte writes a byte of data to the UART.
139+
func (uart *UART) WriteByte(c byte) error {
140+
for uart.Bus.TX_STATUS.Get() == 0 {
141+
}
142+
143+
uart.Bus.TX_DATA.Set(uint32(c))
144+
145+
return nil
146+
}
147+
148+
// Buffered returns the number of bytes buffered in the UART.
149+
func (uart *UART) Buffered() int {
150+
return int(uart.Bus.RX_BYTES.Get())
151+
}
152+
153+
// ReadByte reads a byte of data from the UART.
154+
func (uart *UART) ReadByte() (byte, error) {
155+
for uart.Bus.RX_STATUS.Get() == 0 {
156+
}
157+
158+
return byte(uart.Bus.RX_DATA.Get()), nil
159+
}
160+
161+
// DTR is not available on the TKey.
162+
func (uart *UART) DTR() bool {
163+
return false
164+
}
165+
166+
// RTS is not available on the TKey.
167+
func (uart *UART) RTS() bool {
168+
return false
169+
}
170+
171+
// GetRNG returns 32 bits of cryptographically secure random data
172+
func GetRNG() (uint32, error) {
173+
for tkey.TRNG.STATUS.Get() == 0 {
174+
}
175+
176+
return uint32(tkey.TRNG.ENTROPY.Get()), nil
177+
}
178+
179+
// DesignName returns the FPGA design name.
180+
func DesignName() (string, string) {
181+
n0 := tkey.TK1.NAME0.Get()
182+
name0 := string([]byte{byte(n0 >> 24), byte(n0 >> 16), byte(n0 >> 8), byte(n0)})
183+
n1 := tkey.TK1.NAME1.Get()
184+
name1 := string([]byte{byte(n1 >> 24), byte(n1 >> 16), byte(n1 >> 8), byte(n1)})
185+
186+
return name0, name1
187+
}
188+
189+
// DesignVersion returns the FPGA design version.
190+
func DesignVersion() string {
191+
version := tkey.TK1.VERSION.Get()
192+
193+
return strconv.Itoa(int(version))
194+
}
195+
196+
// CDI returns 8 words of Compound Device Identifier (CDI) generated and written by the firmware when the application is loaded.
197+
func CDI() []byte {
198+
cdi := make([]byte, 32)
199+
for i := 0; i < 8; i++ {
200+
c := tkey.TK1.CDI_FIRST[i].Get()
201+
cdi[i*4] = byte(c >> 24)
202+
cdi[i*4+1] = byte(c >> 16)
203+
cdi[i*4+2] = byte(c >> 8)
204+
cdi[i*4+3] = byte(c)
205+
}
206+
return cdi
207+
}
208+
209+
// UDI returns 2 words of Unique Device Identifier (UDI). Only available in firmware mode.
210+
func UDI() []byte {
211+
udi := make([]byte, 8)
212+
for i := 0; i < 2; i++ {
213+
c := tkey.TK1.UDI_FIRST[i].Get()
214+
udi[i*4] = byte(c >> 24)
215+
udi[i*4+1] = byte(c >> 16)
216+
udi[i*4+2] = byte(c >> 8)
217+
udi[i*4+3] = byte(c)
218+
}
219+
return udi
220+
}
221+
222+
// UDS returns 8 words of Unique Device Secret. Part of the FPGA design, changed when provisioning a TKey.
223+
// Only available in firmware mode. UDS is only readable once per power cycle.
224+
func UDS() []byte {
225+
uds := make([]byte, 32)
226+
for i := 0; i < 8; i++ {
227+
c := tkey.UDS.DATA[i].Get()
228+
uds[i*4] = byte(c >> 24)
229+
uds[i*4+1] = byte(c >> 16)
230+
uds[i*4+2] = byte(c >> 8)
231+
uds[i*4+3] = byte(c)
232+
}
233+
return uds
234+
}

0 commit comments

Comments
 (0)