Skip to content

Commit 8351212

Browse files
committed
arch: arm: Add Microchip CEC1702 SoC
Basic support for the SoC and the UARTs in it. UART divider is reset to register value zero which the chip treats as 3. Thus the default baud rate for the chip is 38400. The SoC has external interrupt controller (EC) which is configured to pass-through all interrupts to NVIC. Support for the EC may need to be implemented better if/when deep sleep modes are implemented. A post-build script cec1702-image.py will create SPI flashable image. Signed-off-by: Timo Teräs <timo.teras@iki.fi>
1 parent 42c5b0a commit 8351212

File tree

12 files changed

+365
-2
lines changed

12 files changed

+365
-2
lines changed

dts/arm/microchip/cec1702.dtsi

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright (c) 2019 Crypta Labs Ltd.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
/dts-v1/;
8+
9+
#include "armv7-m.dtsi"
10+
11+
/ {
12+
compatible = "microchip,cec1702";
13+
14+
cpus {
15+
cpu0 {
16+
compatible = "arm,cortex-m4f";
17+
};
18+
};
19+
20+
flash0: flash@b0000 {
21+
reg = <0x000B0000 0x68000>;
22+
};
23+
24+
sram0: memory@118000 {
25+
compatible = "mmio-sram";
26+
reg = <0x00118000 0x10000>;
27+
};
28+
29+
soc {
30+
uart0: uart@400f2400 {
31+
compatible = "ns16550";
32+
reg = <0x400f2400 0x400>;
33+
interrupts = <40 0>;
34+
clock-frequency = <1843200>;
35+
label = "UART_0";
36+
reg-shift = <0>;
37+
};
38+
uart1: uart@400f2800 {
39+
compatible = "ns16550";
40+
reg = <0x400f2800 0x400>;
41+
interrupts = <41 0>;
42+
clock-frequency = <1843200>;
43+
label = "UART_1";
44+
reg-shift = <0>;
45+
};
46+
};
47+
};
48+
49+
&nvic {
50+
arm,num-irq-priority-bits = <3>;
51+
};

soc/arm/microchip_mec/Kconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Microchip MEC MCU line
1+
# Microchip CEC/MEC MCU line
22

33
# Copyright (c) 2018, Intel Corporation
44
# SPDX-License-Identifier: Apache-2.0
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
zephyr_sources(
4+
soc_config.c
5+
)
6+
7+
set_property(GLOBAL APPEND PROPERTY extra_post_build_commands
8+
COMMAND ${PYTHON_EXECUTABLE} ${SOC_DIR}/${ARCH}/${SOC_PATH}/cec1702-image.py
9+
--img0-image ${PROJECT_BINARY_DIR}/zephyr.bin
10+
--image-out ${PROJECT_BINARY_DIR}/zephyr_spi_image.bin
11+
)
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Microchip CEC1702
2+
3+
# Copyright (c) 2019 Crypta Labs Ltd.
4+
# SPDX-License-Identifier: Apache-2.0
5+
6+
if SOC_CEC1702
7+
8+
config SOC
9+
default "cec1702"
10+
11+
config SYS_CLOCK_HW_CYCLES_PER_SEC
12+
default 48000000
13+
14+
if SERIAL
15+
16+
config UART_NS16550
17+
default y
18+
19+
endif # SERIAL
20+
21+
endif # SOC_CEC1702
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Kconfig - Microchip CEC MCU line
2+
#
3+
# Copyright (c) 2019 Crypta Labs Ltd.
4+
#
5+
# SPDX-License-Identifier: Apache-2.0
6+
7+
if SOC_SERIES_CEC1702
8+
9+
config SOC_SERIES
10+
default "cec1702"
11+
12+
config NUM_IRQS
13+
int
14+
# must be >= the highest interrupt number used
15+
# - include the UART interrupts
16+
default 42
17+
18+
config CORTEX_M_SYSTICK
19+
default y
20+
21+
source "soc/arm/microchip_mec/cec1702/Kconfig.defconfig.cec1702*"
22+
23+
endif
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Kconfig - Microchip CEC MCU line
2+
#
3+
# Copyright (c) 2019 Crypta Labs Ltd.
4+
#
5+
# SPDX-License-Identifier: Apache-2.0
6+
7+
config SOC_SERIES_CEC1702
8+
bool "Microchip CEC1702 Series"
9+
select CPU_CORTEX_M4
10+
select SOC_FAMILY_MEC
11+
select CPU_HAS_FPU
12+
select HAS_MEC_HAL
13+
help
14+
Enable support for Microchip CEC1702 Cortex-M4 MCU series
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Kconfig - Microchip CEC MCU line
2+
#
3+
# Copyright (c) 2019 Crypta Labs Ltd.
4+
#
5+
# SPDX-License-Identifier: Apache-2.0
6+
7+
choice
8+
prompt "CEC1702 Selection"
9+
depends on SOC_SERIES_CEC1702
10+
11+
config SOC_CEC1702
12+
bool "CEC1702"
13+
14+
endchoice
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
#!/usr/bin/python3
2+
3+
# cec1702-image.py - CEC1702 SPI flash image creater utility
4+
# Copyright (c) 2019 Crypta Labs Ltd.
5+
#
6+
# SPDX-License-Identifier: Apache-2.0
7+
8+
import os, argparse, struct, sys, crcmod
9+
from cryptography import x509
10+
from cryptography.hazmat.backends import default_backend
11+
from cryptography.hazmat.primitives import hashes, serialization
12+
from cryptography.hazmat.primitives.asymmetric import ec, utils
13+
14+
backend = default_backend()
15+
16+
def int_to_bytes(val, num_bytes):
17+
# big-endian representation (ROM Addendum documentation is incorrect)
18+
return [(val >> (num_bytes-pos-1)*8) & 0xff for pos in range(num_bytes)]
19+
20+
def digest(hashalg, blob):
21+
d = hashes.Hash(hashalg, backend=backend)
22+
d.update(blob)
23+
return d.finalize()
24+
25+
def sign(blob, sign_key):
26+
# Sign or add checksum according to ROM Addendum
27+
if sign_key:
28+
# Raw EC-DSA signature using secp256R1 EC-key
29+
rfc = sign_key.sign(blob, ec.ECDSA(hashes.SHA256()))
30+
r, s = utils.decode_dss_signature(rfc)
31+
return bytes(bytearray(int_to_bytes(r, 32) + int_to_bytes(s, 32)))
32+
else:
33+
# Raw SHA256 digest
34+
return digest(hashes.SHA256(), blob) + b'\x00'*32
35+
36+
def private_key_to_raw_public_key(p):
37+
# Return RAW Uncompressed format without the leading 0x04 format byte of X962
38+
pubkey = p.public_key()
39+
if not hasattr(serialization.Encoding, 'X962'):
40+
# Old API, deprecated in cryptography 2.5
41+
return pubkey.public_numbers().encode_point()[1:]
42+
return pubkey.public_bytes(serialization.Encoding.X962, serialization.PublicFormat.UncompressedPoint)[1:]
43+
44+
def encrypt(blob, peer_public_key):
45+
from cryptography.hazmat.primitives.kdf.x963kdf import X963KDF
46+
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
47+
48+
# Encrypt firmware image according to ROM Addendum:
49+
# Ephemeral EC-DH over secp256R1, with ANSI X9.63 KDF to generate AES-256-CBC key and IV
50+
# The uncompressed public ephemeral key is appended to the end
51+
ephemeral_key = ec.generate_private_key(ec.SECP256R1(), backend)
52+
shared_secret = ephemeral_key.exchange(ec.ECDH(), peer_public_key)
53+
derived_key = X963KDF(algorithm=hashes.SHA256(), length=48, sharedinfo=None, backend=backend).derive(shared_secret)
54+
enc = Cipher(algorithms.AES(derived_key[0:32]), modes.CBC(derived_key[32:48]), backend=backend).encryptor()
55+
return enc.update(blob) + enc.finalize() + private_key_to_raw_public_key(ephemeral_key)
56+
57+
def bootable_image(opts):
58+
# image size needs to be modulo 64 due to block size requirement
59+
# try to workaround bootloader bug in part C2 by increasing padding as needed
60+
img = opts.image.read()
61+
if opts.encrypt:
62+
img_pad = 256
63+
elif opts.sign:
64+
img_pad = 128
65+
else:
66+
img_pad = 64
67+
x = len(img) % img_pad
68+
if x != 0:
69+
img = img + b'\0' * (img_pad - x)
70+
71+
# header
72+
entry = struct.unpack_from("<L", img, 4)[0] # entry point
73+
vtr_byte = 0x00 # encryption & vtr control
74+
img_len = len(img)
75+
if opts.encrypt:
76+
vtr_byte |= 0x80
77+
img = encrypt(img, opts.encrypt)
78+
79+
# Create CEC boot header
80+
hdr = bytearray(b'\0'*0x40)
81+
struct.pack_into("<4sBBBBLLHHL", hdr, 0,
82+
b"PHCM", # magic
83+
0x00, # version
84+
opts.spi_clock + (opts.spi_drive << 2), # SPI configuration
85+
vtr_byte, # VTR / encryption control
86+
opts.spi_command, # Flash read command
87+
opts.load_address, # Load Address (SRAM)
88+
entry, # Entry Address
89+
img_len // 64, # Image Length (blocks of 64 bytes)
90+
0x0000, # Reserved
91+
opts.image_offset) # HDR size (offset to firmware image)
92+
hdr = bytes(hdr)
93+
hdr_sign = sign(hdr, opts.sign)
94+
img_sign = sign(img, opts.sign)
95+
return hdr + hdr_sign + b'\x00'*(opts.image_offset-len(hdr)-len(hdr_sign)) + img + img_sign
96+
97+
def tag(offset):
98+
offset = offset >> 8
99+
h = crcmod.predefined.Crc('crc-8-itu')
100+
h.update(struct.pack('BBB', offset & 0xff, (offset >> 8) & 0xff, (offset >> 16) & 0xff))
101+
return offset | (ord(h.digest()) << 24)
102+
103+
def flashable_image(args, img0, img1):
104+
img = bytearray(b'\xff' * args.flash_size)
105+
struct.pack_into("<LL", img, 0, tag(args.img0_offset), tag(args.img1_offset))
106+
img[args.img0_offset:args.img0_offset+len(img0)] = img0
107+
img[args.img1_offset:args.img1_offset+len(img1)] = img1
108+
return bytes(img)
109+
110+
def load_file(fn):
111+
return open(fn, 'rb').read()
112+
113+
def load_pem_private_key(fn):
114+
blob = load_file(fn)
115+
for pwd in [ "ECPRIVKEY001", os.getenv("PEM_PASSPHRASE") ]:
116+
try:
117+
return serialization.load_pem_private_key(blob, password=pwd.encode(), backend=backend)
118+
except:
119+
pass
120+
raise argparse.ArgumentTypeError('Invalid private key passphrase')
121+
122+
def load_pem_certificate(fn):
123+
return x509.load_pem_x509_certificate(load_file(fn), backend).public_key()
124+
125+
def get_image_opts(args, n):
126+
opts = dict()
127+
vargs = vars(args)
128+
prefix = "img%d_" % n
129+
for k in vargs:
130+
if k.startswith(prefix):
131+
opts[k[len(prefix):]] = vargs[k]
132+
return argparse.Namespace(**opts)
133+
134+
def main():
135+
ap = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
136+
ap.add_argument("--flash-size", help="Size of the flash", type=int, default=0x200000, metavar="SIZE")
137+
ap.add_argument("--image-out", help="Write raw flash image to file (out)", type=argparse.FileType('wb'), metavar="FILE")
138+
for x, req, offs in ('img0', True, 0x001000), ('img1', False, 0x081000):
139+
g = ap.add_argument_group(x, "Options for %s" % x)
140+
g.add_argument("--%s-image" % x, help="Executable image", type=argparse.FileType('rb'), metavar="IMG", required=req)
141+
g.add_argument("--%s-image-offset" % x, help="Firmware image offset from header", type=int, default=0x100, metavar="OFFSET")
142+
g.add_argument('--%s-load-address' % x, help="Image SRAM load address", type=int, default=0xB0000, metavar="ADDR")
143+
g.add_argument("--%s-offset" % x, help="Image offset in SPI flash", type=int, default=offs, metavar="OFFS")
144+
g.add_argument("--%s-encrypt" % x, help="Encrypt using certificate public key (X.509 PEM)", type=load_pem_certificate, metavar="PEM")
145+
g.add_argument("--%s-sign" % x, help="Signing private key (PEM)", type=load_pem_private_key, metavar="PEM")
146+
g.add_argument("--%s-spi-clock" % x, help="SPI clock (0=48MHz, 1=24MHz, 2=16MHz, 3=12MHz)", choices=range(4), type=int, default=3, metavar="CLK")
147+
g.add_argument("--%s-spi-drive" % x, help="SPI drive strength (0=2mA, 1=4mA, 2=8mA, 3=12mA)", choices=range(4), type=int, default=1, metavar="DRV")
148+
g.add_argument("--%s-spi-command" % x, help="SPI read command (0=normal, 1=fast, 2=double, 3=quad)", choices=range(4), type=int, default=1, metavar="CMD")
149+
g.add_argument("--%s-out" % x, help="Write OTA image to file (out)", type=argparse.FileType('wb'), metavar="FILE")
150+
151+
args = ap.parse_args()
152+
153+
img0 = bootable_image(get_image_opts(args, 0))
154+
if args.img1_image:
155+
img1 = bootable_image(get_image_opts(args, 1))
156+
else:
157+
img1 = img0
158+
159+
if args.image_out:
160+
args.image_out.write(flashable_image(args, img0, img1))
161+
if args.img0_out:
162+
args.img0_out.write(img0)
163+
if args.img1_out:
164+
args.img1_out.write(img1)
165+
166+
if __name__ == "__main__":
167+
main()
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/* linker.ld - Linker command/script file */
2+
3+
/*
4+
* Copyright (c) 2014 Wind River Systems, Inc.
5+
*
6+
* SPDX-License-Identifier: Apache-2.0
7+
*/
8+
9+
#include <arch/arm/cortex_m/scripts/linker.ld>
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/*
2+
* Copyright (c) 2017 Crypta Labs Ltd
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#ifndef CEC_SOC_H
8+
#define CEC_SOC_H
9+
10+
#define SYSCLK_DEFAULT_IOSC_HZ MHZ(48)
11+
12+
#ifndef _ASMLANGUAGE
13+
14+
#include "MCHP_CEC1702_C0.h"
15+
16+
#endif /* !_ASMLANGUAGE */
17+
18+
#endif

0 commit comments

Comments
 (0)