nimble/phy: Add PHY for Dialog CMAC

This adds PHY for Dialog CMAC.

This allows to run complete NimBLE controller on Dialog DA1469x MCU
family. 1M and 2M PHYs are supported, Coded support is missing in
hardware at the moment.

Some parts of code that access RF block are obfuscated, but there
are no proprietary binaries used so fixes are possible if necessary.

Co-authored-by: Will San Filippo <[email protected]>
This commit is contained in:
Andrzej Kaczmarek
2020-09-21 13:53:51 +02:00
co-authored by Will San Filippo
parent 4b6f331748
commit e69a66d715
13 changed files with 3571 additions and 0 deletions
@@ -0,0 +1,39 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef H_BLE_XCVR_
#define H_BLE_XCVR_
#ifdef __cplusplus
extern "C" {
#endif
#define XCVR_TX_SCHED_DELAY_USECS (250)
/*
* Define HW whitelist size. This is the total possible whitelist size;
* not necessarily the size that will be used (may be smaller)
*/
#define BLE_HW_WHITE_LIST_SIZE (8)
#ifdef __cplusplus
}
#endif
#endif /* H_BLE_XCVR_ */
+32
View File
@@ -0,0 +1,32 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
pkg.name: nimble/drivers/dialog_cmac
pkg.description: BLE driver for Dialog CMAC
pkg.author: "Apache Mynewt <[email protected]>"
pkg.homepage: "http://mynewt.apache.org/"
pkg.keywords:
- ble
- bluetooth
pkg.deps:
- "@apache-mynewt-nimble/nimble/controller"
pkg.apis:
- ble_driver
pkg.req_apis:
- ble_transport
+130
View File
@@ -0,0 +1,130 @@
/* aes.h - TinyCrypt interface to an AES-128 implementation */
/*
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Intel Corporation nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* @brief -- Interface to an AES-128 implementation.
*
* Overview: AES-128 is a NIST approved block cipher specified in
* FIPS 197. Block ciphers are deterministic algorithms that
* perform a transformation specified by a symmetric key in fixed-
* length data sets, also called blocks.
*
* Security: AES-128 provides approximately 128 bits of security.
*
* Usage: 1) call tc_aes128_set_encrypt/decrypt_key to set the key.
*
* 2) call tc_aes_encrypt/decrypt to process the data.
*/
#ifndef __TC_AES_H__
#define __TC_AES_H__
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#define Nb (4) /* number of columns (32-bit words) comprising the state */
#define Nk (4) /* number of 32-bit words comprising the key */
#define Nr (10) /* number of rounds */
#define TC_AES_BLOCK_SIZE (Nb*Nk)
#define TC_AES_KEY_SIZE (Nb*Nk)
typedef struct tc_aes_key_sched_struct {
unsigned int words[Nb*(Nr+1)];
} *TCAesKeySched_t;
/**
* @brief Set AES-128 encryption key
* Uses key k to initialize s
* @return returns TC_CRYPTO_SUCCESS (1)
* returns TC_CRYPTO_FAIL (0) if: s == NULL or k == NULL
* @note This implementation skips the additional steps required for keys
* larger than 128 bits, and must not be used for AES-192 or
* AES-256 key schedule -- see FIPS 197 for details
* @param s IN/OUT -- initialized struct tc_aes_key_sched_struct
* @param k IN -- points to the AES key
*/
int tc_aes128_set_encrypt_key(TCAesKeySched_t s, const uint8_t *k);
/**
* @brief AES-128 Encryption procedure
* Encrypts contents of in buffer into out buffer under key;
* schedule s
* @note Assumes s was initialized by aes_set_encrypt_key;
* out and in point to 16 byte buffers
* @return returns TC_CRYPTO_SUCCESS (1)
* returns TC_CRYPTO_FAIL (0) if: out == NULL or in == NULL or s == NULL
* @param out IN/OUT -- buffer to receive ciphertext block
* @param in IN -- a plaintext block to encrypt
* @param s IN -- initialized AES key schedule
*/
int tc_aes_encrypt(uint8_t *out, const uint8_t *in,
const TCAesKeySched_t s);
/**
* @brief Set the AES-128 decryption key
* Uses key k to initialize s
* @return returns TC_CRYPTO_SUCCESS (1)
* returns TC_CRYPTO_FAIL (0) if: s == NULL or k == NULL
* @note This is the implementation of the straightforward inverse cipher
* using the cipher documented in FIPS-197 figure 12, not the
* equivalent inverse cipher presented in Figure 15
* @warning This routine skips the additional steps required for keys larger
* than 128, and must not be used for AES-192 or AES-256 key
* schedule -- see FIPS 197 for details
* @param s IN/OUT -- initialized struct tc_aes_key_sched_struct
* @param k IN -- points to the AES key
*/
int tc_aes128_set_decrypt_key(TCAesKeySched_t s, const uint8_t *k);
/**
* @brief AES-128 Encryption procedure
* Decrypts in buffer into out buffer under key schedule s
* @return returns TC_CRYPTO_SUCCESS (1)
* returns TC_CRYPTO_FAIL (0) if: out is NULL or in is NULL or s is NULL
* @note Assumes s was initialized by aes_set_encrypt_key
* out and in point to 16 byte buffers
* @param out IN/OUT -- buffer to receive ciphertext block
* @param in IN -- a plaintext block to encrypt
* @param s IN -- initialized AES key schedule
*/
int tc_aes_decrypt(uint8_t *out, const uint8_t *in,
const TCAesKeySched_t s);
#ifdef __cplusplus
}
#endif
#endif /* __TC_AES_H__ */
@@ -0,0 +1,193 @@
/* aes_encrypt.c - TinyCrypt implementation of AES encryption procedure */
/*
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Intel Corporation nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "aes.h"
#include "utils.h"
#include "constants.h"
static const uint8_t sbox[256] = {
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b,
0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26,
0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2,
0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed,
0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f,
0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec,
0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14,
0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d,
0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f,
0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11,
0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f,
0xb0, 0x54, 0xbb, 0x16
};
static const unsigned int rconst[11] = {
0x00000000, 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000,
0x20000000, 0x40000000, 0x80000000, 0x1b000000, 0x36000000
};
/* AES state and temp buffer */
uint8_t g_aes_state[Nk*Nb];
uint8_t g_t[Nb*Nk];
static inline unsigned int rotword(unsigned int a)
{
return (((a) >> 24)|((a) << 8));
}
#define subbyte(a, o)(sbox[((a) >> (o))&0xff] << (o))
#define subword(a)(subbyte(a, 24)|subbyte(a, 16)|subbyte(a, 8)|subbyte(a, 0))
int tc_aes128_set_encrypt_key(TCAesKeySched_t s, const uint8_t *k)
{
unsigned int i;
unsigned int t;
if (s == (TCAesKeySched_t) 0) {
return TC_CRYPTO_FAIL;
} else if (k == (const uint8_t *) 0) {
return TC_CRYPTO_FAIL;
}
for (i = 0; i < Nk; ++i) {
s->words[i] = (k[Nb*i]<<24) | (k[Nb*i+1]<<16) |
(k[Nb*i+2]<<8) | (k[Nb*i+3]);
}
for (; i < (Nb * (Nr + 1)); ++i) {
t = s->words[i-1];
if ((i % Nk) == 0) {
t = subword(rotword(t)) ^ rconst[i/Nk];
}
s->words[i] = s->words[i-Nk] ^ t;
}
return TC_CRYPTO_SUCCESS;
}
static inline void add_round_key(uint8_t *s, const unsigned int *k)
{
s[0] ^= (uint8_t)(k[0] >> 24); s[1] ^= (uint8_t)(k[0] >> 16);
s[2] ^= (uint8_t)(k[0] >> 8); s[3] ^= (uint8_t)(k[0]);
s[4] ^= (uint8_t)(k[1] >> 24); s[5] ^= (uint8_t)(k[1] >> 16);
s[6] ^= (uint8_t)(k[1] >> 8); s[7] ^= (uint8_t)(k[1]);
s[8] ^= (uint8_t)(k[2] >> 24); s[9] ^= (uint8_t)(k[2] >> 16);
s[10] ^= (uint8_t)(k[2] >> 8); s[11] ^= (uint8_t)(k[2]);
s[12] ^= (uint8_t)(k[3] >> 24); s[13] ^= (uint8_t)(k[3] >> 16);
s[14] ^= (uint8_t)(k[3] >> 8); s[15] ^= (uint8_t)(k[3]);
}
static inline void sub_bytes(uint8_t *s)
{
unsigned int i;
for (i = 0; i < (Nb * Nk); ++i) {
s[i] = sbox[s[i]];
}
}
#define triple(a)(_double_byte(a)^(a))
static inline void mult_row_column(uint8_t *out, const uint8_t *in)
{
out[0] = _double_byte(in[0]) ^ triple(in[1]) ^ in[2] ^ in[3];
out[1] = in[0] ^ _double_byte(in[1]) ^ triple(in[2]) ^ in[3];
out[2] = in[0] ^ in[1] ^ _double_byte(in[2]) ^ triple(in[3]);
out[3] = triple(in[0]) ^ in[1] ^ in[2] ^ _double_byte(in[3]);
}
static inline void mix_columns(uint8_t *s)
{
mult_row_column(g_t, s);
mult_row_column(&g_t[Nb], s+Nb);
mult_row_column(&g_t[2 * Nb], s + (2 * Nb));
mult_row_column(&g_t[3 * Nb], s + (3 * Nb));
(void) _copy(s, sizeof(g_t), g_t, sizeof(g_t));
}
/*
* This shift_rows also implements the matrix flip required for mix_columns, but
* performs it here to reduce the number of memory operations.
*/
static inline void shift_rows(uint8_t *s)
{
g_t[0] = s[0]; g_t[1] = s[5]; g_t[2] = s[10]; g_t[3] = s[15];
g_t[4] = s[4]; g_t[5] = s[9]; g_t[6] = s[14]; g_t[7] = s[3];
g_t[8] = s[8]; g_t[9] = s[13]; g_t[10] = s[2]; g_t[11] = s[7];
g_t[12] = s[12]; g_t[13] = s[1]; g_t[14] = s[6]; g_t[15] = s[11];
(void) _copy(s, sizeof(g_t), g_t, sizeof(g_t));
}
int tc_aes_encrypt(uint8_t *out, const uint8_t *in, const TCAesKeySched_t s)
{
unsigned int i;
if (out == (uint8_t *) 0) {
return TC_CRYPTO_FAIL;
} else if (in == (const uint8_t *) 0) {
return TC_CRYPTO_FAIL;
} else if (s == (TCAesKeySched_t) 0) {
return TC_CRYPTO_FAIL;
}
(void)_copy(g_aes_state, sizeof(g_aes_state), in,
sizeof(g_aes_state));
add_round_key(g_aes_state, s->words);
for (i = 0; i < (Nr - 1); ++i) {
sub_bytes(g_aes_state);
shift_rows(g_aes_state);
mix_columns(g_aes_state);
add_round_key(g_aes_state, s->words + Nb*(i+1));
}
sub_bytes(g_aes_state);
shift_rows(g_aes_state);
add_round_key(g_aes_state, s->words + Nb*(i+1));
(void)_copy(out, sizeof(g_aes_state), g_aes_state,
sizeof(g_aes_state));
/* zeroing out the state buffer */
_set(g_aes_state, TC_ZERO_BYTE, sizeof(g_aes_state));
return TC_CRYPTO_SUCCESS;
}
@@ -0,0 +1,61 @@
/* constants.h - TinyCrypt interface to constants */
/*
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Intel Corporation nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* @brief -- Interface to constants.
*
*/
#ifndef __TC_CONSTANTS_H__
#define __TC_CONSTANTS_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#ifndef NULL
#define NULL ((void *)0)
#endif
#define TC_CRYPTO_SUCCESS 1
#define TC_CRYPTO_FAIL 0
#define TC_ZERO_BYTE 0x00
#ifdef __cplusplus
}
#endif
#endif /* __TC_CONSTANTS_H__ */
@@ -0,0 +1,74 @@
/* utils.c - TinyCrypt platform-dependent run-time operations */
/*
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Intel Corporation nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "utils.h"
#include "constants.h"
#include <string.h>
#define MASK_TWENTY_SEVEN 0x1b
unsigned int _copy(uint8_t *to, unsigned int to_len,
const uint8_t *from, unsigned int from_len)
{
if (from_len <= to_len) {
(void)memcpy(to, from, from_len);
return from_len;
} else {
return TC_CRYPTO_FAIL;
}
}
void _set(void *to, uint8_t val, unsigned int len)
{
(void)memset(to, val, len);
}
/*
* Doubles the value of a byte for values up to 127.
*/
uint8_t _double_byte(uint8_t a)
{
return ((a<<1) ^ ((a>>7) * MASK_TWENTY_SEVEN));
}
int _compare(const uint8_t *a, const uint8_t *b, size_t size)
{
const uint8_t *tempa = a;
const uint8_t *tempb = b;
uint8_t result = 0;
for (unsigned int i = 0; i < size; i++) {
result |= tempa[i] ^ tempb[i];
}
return result;
}
@@ -0,0 +1,95 @@
/* utils.h - TinyCrypt interface to platform-dependent run-time operations */
/*
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Intel Corporation nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* @brief Interface to platform-dependent run-time operations.
*
*/
#ifndef __TC_UTILS_H__
#define __TC_UTILS_H__
#include <stdint.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Copy the the buffer 'from' to the buffer 'to'.
* @return returns TC_CRYPTO_SUCCESS (1)
* returns TC_CRYPTO_FAIL (0) if:
* from_len > to_len.
*
* @param to OUT -- destination buffer
* @param to_len IN -- length of destination buffer
* @param from IN -- origin buffer
* @param from_len IN -- length of origin buffer
*/
unsigned int _copy(uint8_t *to, unsigned int to_len,
const uint8_t *from, unsigned int from_len);
/**
* @brief Set the value 'val' into the buffer 'to', 'len' times.
*
* @param to OUT -- destination buffer
* @param val IN -- value to be set in 'to'
* @param len IN -- number of times the value will be copied
*/
void _set(void *to, uint8_t val, unsigned int len);
/*
* @brief AES specific doubling function, which utilizes
* the finite field used by AES.
* @return Returns a^2
*
* @param a IN/OUT -- value to be doubled
*/
uint8_t _double_byte(uint8_t a);
/*
* @brief Constant-time algorithm to compare if two sequences of bytes are equal
* @return Returns 0 if equal, and non-zero otherwise
*
* @param a IN -- sequence of bytes a
* @param b IN -- sequence of bytes b
* @param size IN -- size of sequences a and b
*/
int _compare(const uint8_t *a, const uint8_t *b, size_t size);
#ifdef __cplusplus
}
#endif
#endif /* __TC_UTILS_H__ */
+340
View File
@@ -0,0 +1,340 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include <assert.h>
#include <stdint.h>
#include "mcu/mcu.h"
#include "nimble/ble.h"
#include "controller/ble_hw.h"
#include "CMAC.h"
#include "cmac_driver/cmac_shared.h"
#include "mcu/mcu.h"
#include "aes/aes.h"
static struct tc_aes_key_sched_struct g_ctx;
int
ble_hw_rng_init(ble_rng_isr_cb_t cb, int bias)
{
cmac_rand_set_isr_cb(cb);
return 0;
}
int
ble_hw_rng_start(void)
{
/* Chime the M33 in case we need random numbers generated */
cmac_rand_start();
CMAC->CM_EV_SET_REG = CMAC_CM_EV_SET_REG_EV1C_CMAC2SYS_IRQ_SET_Msk;
return 0;
}
int
ble_hw_rng_stop(void)
{
cmac_rand_stop();
return 0;
}
#define BLE_HW_RESOLV_LIST_SIZE (MYNEWT_VAL(BLE_LL_RESOLV_LIST_SIZE))
struct ble_hw_resolv_irk {
uint32_t key[4];
};
struct ble_hw_resolv_list {
uint8_t count;
struct ble_hw_resolv_irk irk[BLE_HW_RESOLV_LIST_SIZE];
};
struct ble_hw_resolv_proc {
uint32_t hash;
uint8_t f_configured;
uint8_t f_active;
uint8_t f_match;
uint8_t f_done;
struct ble_hw_resolv_irk *irk;
struct ble_hw_resolv_irk *irk_end;
uint32_t crypto_prand_in[4];
uint32_t crypto_e_out[4];
};
static struct ble_hw_resolv_list g_ble_hw_resolv_list;
static struct ble_hw_resolv_proc g_ble_hw_resolv_proc;
int
ble_hw_get_public_addr(ble_addr_t *addr)
{
return -1;
}
int
ble_hw_get_static_addr(ble_addr_t *addr)
{
return -1;
}
void
ble_hw_whitelist_clear(void)
{
}
int
ble_hw_whitelist_add(const uint8_t *addr, uint8_t addr_type)
{
return 0;
}
void
ble_hw_whitelist_rmv(const uint8_t *addr, uint8_t addr_type)
{
}
uint8_t
ble_hw_whitelist_size(void)
{
return 0;
}
void
ble_hw_whitelist_enable(void)
{
}
void
ble_hw_whitelist_disable(void)
{
}
int
ble_hw_whitelist_match(void)
{
return 0;
}
int
ble_hw_encrypt_block(struct ble_encryption_block *ecb)
{
uint32_t in_addr;
uint32_t out_addr;
/*
* The following code bears some explanation. This function is called by
* the LL task to encrypt blocks and calculate session keys. Address
* resolution also calls this function. Furthermore, during connections,
* the M0 crypto accelerator is used but this function is not called when
* using it. During the entire connection event, the M0 crypto block cannot
* be used as the crypto state (some of it) needs to remain un-changed.
* Note that this is also true when address resolution is enabled: the
* HW crypto block is set up and cannot be modified.
*
* Rather than attempt to share the M0 crypto block between the various
* controller features which require it, we decided to use software to
* perform the encryption task for anything being done at the link-layer
* (outside of an ISR). If this function is called inside an ISR, and it
* is when resolving addresses, the crypto accelerator is not being used
* by a connection event. Thus, we check to see if we are inside of an ISR.
* If so, we use the M0 crypto block. If outside of an ISR, we use the M33
*/
if (!os_arch_in_isr()) {
tc_aes128_set_encrypt_key(&g_ctx, ecb->key);
tc_aes_encrypt(ecb->cipher_text, ecb->plain_text, &g_ctx);
return 0;
}
/* Need to retain state of in/out pointers */
in_addr = CMAC->CM_CRYPTO_IN_ADR2_REG;
out_addr = CMAC->CM_CRYPTO_OUT_ADR_REG;
while (CMAC->CM_CRYPTO_STAT_REG & CMAC_CM_CRYPTO_STAT_REG_CM_CRYPTO_BUSY_Msk);
/* RECB, memory in/out, encryption */
CMAC->CM_CRYPTO_CTRL_REG = CMAC_CM_CRYPTO_CTRL_REG_CM_CRYPTO_ECB_ENC_EN_Msk |
CMAC_CM_CRYPTO_CTRL_REG_CM_CRYPTO_IN_SEL_Msk |
CMAC_CM_CRYPTO_CTRL_REG_CM_CRYPTO_OUT_SEL_Msk |
CMAC_CM_CRYPTO_CTRL_REG_CM_CRYPTO_ENC_DECN_Msk;
CMAC->CM_CRYPTO_KEY_31_0_REG = get_le32(&ecb->key[0]);
CMAC->CM_CRYPTO_KEY_63_32_REG = get_le32(&ecb->key[4]);
CMAC->CM_CRYPTO_KEY_95_64_REG = get_le32(&ecb->key[8]);
CMAC->CM_CRYPTO_KEY_127_96_REG = get_le32(&ecb->key[12]);
CMAC->CM_CRYPTO_IN_ADR2_REG = (uint32_t)ecb->plain_text;
CMAC->CM_CRYPTO_OUT_ADR_REG = (uint32_t)ecb->cipher_text;
CMAC->CM_EXC_STAT_REG = CMAC_CM_EXC_STAT_REG_EXC_CRYPTO_Msk;
CMAC->CM_EV_SET_REG = CMAC_CM_EV_SET_REG_EV_CRYPTO_START_Msk;
while (!(CMAC->CM_EXC_STAT_REG & CMAC_CM_EXC_STAT_REG_EXC_CRYPTO_Msk));
CMAC->CM_EXC_STAT_REG = CMAC_CM_EXC_STAT_REG_EXC_CRYPTO_Msk;
CMAC->CM_CRYPTO_IN_ADR2_REG = in_addr;
CMAC->CM_CRYPTO_OUT_ADR_REG = out_addr;
return 0;
}
void
ble_hw_resolv_list_clear(void)
{
g_ble_hw_resolv_list.count = 0;
}
int
ble_hw_resolv_list_add(uint8_t *irk)
{
struct ble_hw_resolv_irk *e;
if (g_ble_hw_resolv_list.count == BLE_HW_RESOLV_LIST_SIZE) {
return BLE_ERR_MEM_CAPACITY;
}
e = &g_ble_hw_resolv_list.irk[g_ble_hw_resolv_list.count];
/* Prepare key here so we do not need to do it during resolving */
e->key[0] = get_le32(&irk[0]);
e->key[1] = get_le32(&irk[4]);
e->key[2] = get_le32(&irk[8]);
e->key[3] = get_le32(&irk[12]);
g_ble_hw_resolv_list.count++;
return BLE_ERR_SUCCESS;
}
void
ble_hw_resolv_list_rmv(int index)
{
struct ble_hw_resolv_irk *e;
if (index < g_ble_hw_resolv_list.count) {
g_ble_hw_resolv_list.count--;
e = &g_ble_hw_resolv_list.irk[index];
memmove(e, e + 1, (g_ble_hw_resolv_list.count - index) * sizeof(e->key));
}
}
uint8_t
ble_hw_resolv_list_size(void)
{
return BLE_HW_RESOLV_LIST_SIZE;
}
int
ble_hw_resolv_list_match(void)
{
return g_ble_hw_resolv_proc.f_match ?
g_ble_hw_resolv_proc.irk - g_ble_hw_resolv_list.irk : -1;
}
static void
ble_hw_resolv_proc_next(void)
{
void *src = &g_ble_hw_resolv_proc.irk->key;
if (g_ble_hw_resolv_proc.irk == g_ble_hw_resolv_proc.irk_end) {
g_ble_hw_resolv_proc.f_done = 1;
g_ble_hw_resolv_proc.f_active = 0;
} else {
__asm__ volatile (".syntax unified \n"
" ldm %[ptr]!, {r1, r2, r3, r4} \n"
" ldr %[ptr], =%[reg] \n"
" stm %[ptr]!, {r1, r2, r3, r4} \n"
: [ptr] "+l" (src)
: [reg] "i" (&CMAC->CM_CRYPTO_KEY_31_0_REG)
: "r1", "r2", "r3", "r4", "memory");
CMAC->CM_EV_SET_REG = CMAC_CM_EV_SET_REG_EV_CRYPTO_START_Msk;
}
}
void
ble_hw_resolv_proc_enable(void)
{
assert(!g_ble_hw_resolv_proc.f_active);
CMAC->CM_CRYPTO_CTRL_REG = CMAC_CM_CRYPTO_CTRL_REG_CM_CRYPTO_SW_REQ_ABORT_Msk;
CMAC->CM_CRYPTO_CTRL_REG = CMAC_CM_CRYPTO_CTRL_REG_CM_CRYPTO_ECB_ENC_EN_Msk |
CMAC_CM_CRYPTO_CTRL_REG_CM_CRYPTO_IN_SEL_Msk |
CMAC_CM_CRYPTO_CTRL_REG_CM_CRYPTO_OUT_SEL_Msk |
CMAC_CM_CRYPTO_CTRL_REG_CM_CRYPTO_ENC_DECN_Msk;
CMAC->CM_CRYPTO_IN_ADR2_REG = (uint32_t)g_ble_hw_resolv_proc.crypto_prand_in;
CMAC->CM_CRYPTO_OUT_ADR_REG = (uint32_t)g_ble_hw_resolv_proc.crypto_e_out;
g_ble_hw_resolv_proc.irk = g_ble_hw_resolv_list.irk;
g_ble_hw_resolv_proc.irk_end = g_ble_hw_resolv_list.irk +
g_ble_hw_resolv_list.count;
g_ble_hw_resolv_proc.f_configured = 1;
g_ble_hw_resolv_proc.f_active = 0;
/*
* It would be better to enable IRQ in ble_hw_resolv_proc_start, but this
* would introduce a bit of latency when starting resolving procedure and
* we need to save every us possible there in order to be able to resolve
* RPA on time.
*/
NVIC_ClearPendingIRQ(CRYPTO_IRQn);
NVIC_EnableIRQ(CRYPTO_IRQn);
}
void
ble_hw_resolv_proc_disable(void)
{
g_ble_hw_resolv_proc.f_configured = 0;
g_ble_hw_resolv_proc.f_active = 0;
g_ble_hw_resolv_proc.f_match = 0;
g_ble_hw_resolv_proc.f_done = 1;
NVIC_DisableIRQ(CRYPTO_IRQn);
}
void
ble_hw_resolv_proc_start(const uint8_t *addr)
{
assert(g_ble_hw_resolv_proc.f_configured);
/* crypto_prand_in is already zeroed so prand is properly padded */
g_ble_hw_resolv_proc.crypto_prand_in[3] = get_be24(&addr[3]) << 8;
g_ble_hw_resolv_proc.hash = get_be24(&addr[0]);
g_ble_hw_resolv_proc.f_match = 0;
g_ble_hw_resolv_proc.f_done = 0;
g_ble_hw_resolv_proc.f_active = 1;
ble_hw_resolv_proc_next();
}
void
CRYPTO_IRQHandler(void)
{
uint32_t hash;
CMAC->CM_EXC_STAT_REG = CMAC_CM_EXC_STAT_REG_EXC_CRYPTO_Msk;
hash = g_ble_hw_resolv_proc.crypto_e_out[3] >> 8;
if (g_ble_hw_resolv_proc.hash == hash) {
g_ble_hw_resolv_proc.f_active = 0;
g_ble_hw_resolv_proc.f_match = 1;
g_ble_hw_resolv_proc.f_done = 1;
} else {
g_ble_hw_resolv_proc.irk++;
ble_hw_resolv_proc_next();
}
}
@@ -0,0 +1,29 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef _BLE_HW_PRIV_H_
#define _BLE_HW_PRIV_H_
#include <stdint.h>
void ble_hw_resolv_proc_enable(void);
void ble_hw_resolv_proc_disable(void);
void ble_hw_resolv_proc_start(const uint8_t *addr);
#endif /* _BLE_HW_PRIV_H_ */
File diff suppressed because it is too large Load Diff
+729
View File
@@ -0,0 +1,729 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include "mcu/mcu.h"
#include "mcu/cmac_timer.h"
#include "controller/ble_phy.h"
#include "cmac_driver/cmac_shared.h"
#include "ble_rf_priv.h"
#define RF_CALIBRATION_0 (0x01)
#define RF_CALIBRATION_1 (0x02)
#define RF_CALIBRATION_2 (0x04)
static const int8_t g_ble_rf_power_lvls[] = {
-18, -12, -8, -6, -3, -2, -1, 0, 1, 2, 3, 4, 4, 5, 6
};
struct ble_phy_rf_data {
uint8_t tx_power_cfg0;
uint8_t tx_power_cfg1;
uint8_t tx_power_cfg2;
uint8_t tx_power_cfg3;
uint32_t cal_res_1;
uint32_t cal_res_2;
uint32_t trim_val1_tx_1;
uint32_t trim_val1_tx_2;
uint32_t trim_val2_tx;
uint32_t trim_val2_rx;
};
static struct ble_phy_rf_data g_ble_phy_rf_data;
static inline uint32_t
get_reg32(uint32_t addr)
{
volatile uint32_t *reg = (volatile uint32_t *)addr;
return *reg;
}
static inline uint32_t
get_reg32_bits(uint32_t addr, uint32_t mask)
{
volatile uint32_t *reg = (volatile uint32_t *)addr;
return (*reg & mask) >> __builtin_ctz(mask);
}
static inline void
set_reg8(uint32_t addr, uint8_t val)
{
volatile uint8_t *reg = (volatile uint8_t *)addr;
*reg = val;
}
static inline void
set_reg16(uint32_t addr, uint16_t val)
{
volatile uint16_t *reg = (volatile uint16_t *)addr;
*reg = val;
}
static inline void
set_reg32(uint32_t addr, uint32_t val)
{
volatile uint32_t *reg = (volatile uint32_t *)addr;
*reg = val;
}
static inline void
set_reg32_bits(uint32_t addr, uint32_t mask, uint32_t val)
{
volatile uint32_t *reg = (volatile uint32_t *)addr;
*reg = (*reg & (~mask)) | (val << __builtin_ctz(mask));
}
static inline void
set_reg32_mask(uint32_t addr, uint32_t mask, uint32_t val)
{
volatile uint32_t *reg = (volatile uint32_t *)addr;
*reg = (*reg & (~mask)) | (val & mask);
}
static inline void
set_reg16_mask(uint32_t addr, uint16_t mask, uint16_t val)
{
volatile uint16_t *reg = (volatile uint16_t *)addr;
*reg = (*reg & (~mask)) | (val & mask);
}
static void
delay_us(uint32_t delay_us)
{
while (delay_us--) {
__NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
__NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
__NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
__NOP(); __NOP(); __NOP(); __NOP();
}
}
static void
ble_rf_apply_trim(volatile uint32_t *tv, unsigned len)
{
while (len) {
*(volatile uint32_t *)tv[0] = tv[1];
len -= 2;
tv += 2;
}
}
static void
ble_rf_apply_calibration(void)
{
set_reg32(0x40020094, g_ble_phy_rf_data.cal_res_1);
if (g_ble_phy_rf_data.cal_res_2) {
set_reg32_bits(0x40022018, 0xff800000, g_ble_phy_rf_data.cal_res_2);
set_reg32_bits(0x40022018, 0x00007fc0, g_ble_phy_rf_data.cal_res_2);
}
}
static inline void
ble_rf_ldo_on(void)
{
set_reg8(0x40020004, 9);
}
static inline void
ble_rf_ldo_off(void)
{
set_reg8(0x40020004, 0);
}
static inline void
ble_rf_rfcu_enable(void)
{
set_reg32_bits(0x50000010, 0x00000020, 1);
}
static inline void
ble_rf_rfcu_disable(void)
{
set_reg32_bits(0x50000010, 0x00000020, 0);
}
static void
ble_rf_rfcu_apply_recommended_settings(void)
{
set_reg16_mask(0x400200a0, 0x0001, 0x0001);
set_reg16_mask(0x40021020, 0x03f0, 0x02f5);
set_reg32_mask(0x40021018, 0x001fffff, 0x005a5809);
set_reg32_mask(0x4002101c, 0x00001e01, 0x0040128c);
set_reg32_mask(0x40021004, 0xffffff1f, 0x64442404);
set_reg32_mask(0x40021008, 0xfcfcffff, 0x6b676665);
set_reg32_mask(0x4002100c, 0x00fcfcfc, 0x9793736f);
set_reg32_mask(0x40021010, 0x1f1f1c1f, 0x04072646);
set_reg32_mask(0x40020000, 0x001ff000, 0x0f099820);
set_reg16_mask(0x40020348, 0x00ff, 0x0855);
set_reg16(0x40020350, 0x0234);
set_reg16(0x40020354, 0x0a34);
set_reg16(0x40020358, 0x0851);
set_reg16(0x4002035c, 0x0a26);
set_reg16(0x40020360, 0x0858);
set_reg16(0x4002102c, 0xdfe7);
set_reg32_mask(0x4002103c, 0x00c00000, 0x0024a19f);
set_reg16_mask(0x40021000, 0x0008, 0x000b);
set_reg16_mask(0x40020238, 0x03e0, 0x02c0);
set_reg16_mask(0x4002023c, 0x03e0, 0x02c0);
set_reg16_mask(0x40020244, 0x03e0, 0x0250);
set_reg16_mask(0x40020248, 0x03e0, 0x02a0);
set_reg16_mask(0x4002024c, 0x03e0, 0x02c0);
set_reg16_mask(0x40020288, 0x03e0, 0x0300);
set_reg16_mask(0x4002029c, 0x001f, 0x0019);
set_reg16_mask(0x4002003c, 0x6000, 0x0788);
set_reg16_mask(0x40020074, 0x7f00, 0x2007);
set_reg32_mask(0x40020080, 0x00333330, 0x00222224);
set_reg32_mask(0x40020068, 0x00000f0f, 0x00000f0d);
}
static void
ble_rf_rfcu_apply_settings(void)
{
ble_rf_apply_trim(g_cmac_shared_data.trim.rfcu,
g_cmac_shared_data.trim.rfcu_len);
ble_rf_rfcu_apply_recommended_settings();
}
static inline void
ble_rf_synth_enable(void)
{
set_reg8(0x40020005, 3);
}
static inline void
ble_rf_synth_disable(void)
{
set_reg8(0x40020005, 0);
__NOP();
__NOP();
}
static bool
ble_rf_synth_is_enabled(void)
{
return get_reg32_bits(0x40020004, 256);
}
static void
ble_rf_synth_apply_recommended_settings(void)
{
set_reg32_mask(0x40022048, 0x0000000c, 0x000000d5);
set_reg32_mask(0x40022050, 0x00000300, 0x00000300);
set_reg16_mask(0x40022024, 0x0001, 0x0001);
}
static void
ble_rf_synth_apply_settings(void)
{
ble_rf_apply_trim(g_cmac_shared_data.trim.synth,
g_cmac_shared_data.trim.synth_len);
ble_rf_synth_apply_recommended_settings();
}
static void
ble_rf_calibration_0(void)
{
uint32_t bkp[10];
bkp[0] = get_reg32(0x40020208);
bkp[1] = get_reg32(0x40020250);
bkp[2] = get_reg32(0x40020254);
bkp[3] = get_reg32(0x40021028);
bkp[4] = get_reg32(0x40020020);
bkp[5] = get_reg32(0x40020294);
bkp[6] = get_reg32(0x4002103C);
bkp[7] = get_reg32(0x400200A8);
bkp[8] = get_reg32(0x40020000);
bkp[9] = get_reg32(0x40022000);
set_reg32_bits(0x40020000, 0x00000002, 0);
set_reg32_bits(0x40022000, 0x00000001, 0);
set_reg32_mask(0x4002103C, 0x00201c00, 0x00001c00);
set_reg32_bits(0x400200A8, 0x00000001, 1);
set_reg8(0x40020006, 1);
set_reg32(0x40020208, 0);
set_reg32(0x40020250, 0);
set_reg32(0x40020254, 0);
set_reg32(0x40021028, 0x00F8A494);
set_reg32(0x40020020, 8);
set_reg32(0x40020294, 0);
set_reg32(0x40020024, 0);
delay_us(5);
if (get_reg32_bits(0x40020020, 0x00000002)) {
goto done;
}
set_reg32_bits(0x40020020, 0x00000001, 1);
delay_us(15);
if (!get_reg32_bits(0x40020020, 0x00000001)) {
goto done;
}
delay_us(300);
if (get_reg32_bits(0x40020020, 0x00000001)) {
goto done;
}
done:
set_reg32(0x40020024, 0);
set_reg32(0x40020208, bkp[0]);
set_reg32(0x40020250, bkp[1]);
set_reg32(0x40020254, bkp[2]);
set_reg32(0x40021028, bkp[3]);
set_reg32(0x40020020, bkp[4]);
set_reg32(0x40020294, bkp[5]);
set_reg32(0x4002103C, bkp[6]);
set_reg32(0x400200A8, bkp[7]);
set_reg32(0x40020000, bkp[8]);
set_reg32(0x40022000, bkp[9]);
}
static void
ble_rf_calibration_1(void)
{
uint32_t bkp[12];
uint32_t val;
bkp[0] = get_reg32(0x40020020);
bkp[1] = get_reg32(0x40020208);
bkp[2] = get_reg32(0x40020250);
bkp[3] = get_reg32(0x40020254);
bkp[4] = get_reg32(0x40020218);
bkp[5] = get_reg32(0x4002021c);
bkp[6] = get_reg32(0x40020220);
bkp[7] = get_reg32(0x40020270);
bkp[8] = get_reg32(0x4002027c);
bkp[9] = get_reg32(0x4002101c);
bkp[10] = get_reg32(0x40020000);
bkp[11] = get_reg32(0x40022000);
set_reg32(0x40020208, 0);
set_reg32(0x40020250, 0);
set_reg32(0x40020254, 0);
set_reg32(0x40020218, 0);
set_reg32(0x4002021c, 0);
set_reg32(0x40020220, 0);
set_reg32(0x40020270, 0);
set_reg32(0x4002027c, 0);
set_reg32(0x40020000, 0x0f168820);
set_reg32_bits(0x40022000, 0x00000001, 0);
set_reg32_bits(0x4002101c, 0x00001e00, 0);
set_reg32_bits(0x4002001c, 0x0000003f, 47);
set_reg8(0x40020006, 1);
set_reg32(0x40020020, 16);
set_reg32_bits(0x4002003c, 0x00000800, 1);
set_reg32(0x40020024, 0);
delay_us(5);
if (get_reg32_bits(0x40020020, 0x00000002)) {
goto done;
}
set_reg32_bits(0x40020020, 0x00000001, 1);
delay_us(15);
if (!get_reg32_bits(0x40020020, 0x00000001)) {
goto done;
}
delay_us(300);
if (get_reg32_bits(0x40020020, 0x00000001)) {
goto done;
}
val = get_reg32(0x40020090);
set_reg32_bits(0x40020094, 0x0000000f, val);
set_reg32_bits(0x40020094, 0x00000f00, val);
set_reg32_bits(0x40020094, 0x000f0000, val);
set_reg32_bits(0x40020094, 0x0f000000, val);
g_ble_phy_rf_data.cal_res_1 = get_reg32(0x40020094);
done:
set_reg32(0x40020024, 0);
set_reg32(0x40020020, bkp[0]);
set_reg32(0x40020208, bkp[1]);
set_reg32(0x40020250, bkp[2]);
set_reg32(0x40020254, bkp[3]);
set_reg32(0x40020218, bkp[4]);
set_reg32(0x4002021c, bkp[5]);
set_reg32(0x40020220, bkp[6]);
set_reg32(0x40020270, bkp[7]);
set_reg32(0x4002027c, bkp[8]);
set_reg32(0x4002101c, bkp[9]);
set_reg32(0x40020000, bkp[10]);
set_reg32(0x40022000, bkp[11]);
set_reg32_bits(0x4002003c, 0x00000800, 0);
}
static void
ble_rf_calibration_2(void)
{
uint32_t bkp[2];
uint32_t k1;
set_reg8(0x40020005, 3);
set_reg32_bits(0x40022004, 0x0000007f, 20);
bkp[0] = get_reg32(0x40022040);
set_reg32(0x40022040, 0xffffffff);
set_reg32_bits(0x40022018, 0x0000003f, 0);
set_reg32_bits(0x40022018, 0x00008000, 0);
set_reg32_bits(0x4002201c, 0x00000600, 2);
set_reg32_bits(0x4002201c, 0x00000070, 4);
set_reg32_bits(0x40022030, 0x3f000000, 22);
set_reg32_bits(0x40022030, 0x00000fc0, 24);
set_reg32_bits(0x40022030, 0x0000003f, 24);
set_reg8(0x4002201c, 0x43);
set_reg8(0x40020006, 2);
delay_us(2);
bkp[1] = get_reg32_bits(0x4002024c, 0x000003e0);
set_reg32_bits(0x4002024c, 0x000003e0, 0);
set_reg8(0x40020006, 1);
set_reg32_bits(0x400200ac, 0x00000003, 3);
delay_us(30);
delay_us(100);
set_reg8(0x40020005, 3);
k1 = get_reg32_bits(0x40022088, 0x000001ff);
set_reg32(0x400200ac, 0);
delay_us(20);
set_reg32_bits(0x4002024c, 0x000003e0, bkp[1]);
delay_us(10);
set_reg32_bits(0x40022018, 0xff800000, k1);
set_reg32_bits(0x40022018, 0x00007fc0, k1);
set_reg8(0x4002201c, 0x41);
set_reg32_bits(0x4002201c, 0x00000600, 2);
set_reg8(0x40020006, 2);
delay_us(2);
bkp[1] = get_reg32_bits(0x4002024c, 0x000003e0);
set_reg32_bits(0x4002024c, 0x000003e0, 0);
set_reg8(0x40020006, 1);
set_reg32_bits(0x400200ac, 0x00000003, 3);
delay_us(30);
delay_us(100);
set_reg8(0x40020005, 3);
k1 = get_reg32_bits(0x40022088, 0x1ff);
set_reg32(0x400200ac, 0);
delay_us(20);
set_reg32_bits(0x4002024c, 0x000003e0, bkp[1]);
delay_us(10);
set_reg32_bits(0x40022018, 0xff800000, k1);
set_reg32_bits(0x40022018, 0x00007fc0, k1);
set_reg8(0x4002201c, 0x41);
set_reg32_bits(0x4002201c, 0x00000600, 2);
set_reg8(0x40020006, 2);
delay_us(2);
bkp[1] = get_reg32_bits(0x4002024c, 0x000003e0);
set_reg32_bits(0x4002024c, 0x000003e0, 0);
set_reg8(0x40020006, 1);
set_reg32_bits(0x400200ac, 0x00000003, 3);
delay_us(30);
delay_us(100);
set_reg8(0x40020005, 3);
k1 = get_reg32_bits(0x40022088, 0x000001ff);
set_reg32_bits(0x40022018, 0xff800000, k1);
set_reg32_bits(0x40022018, 0x00007fc0, k1);
set_reg32_bits(0x4002201c, 0x00000001, 0);
set_reg32(0x40022040, bkp[0]);
set_reg32_bits(0x40022018, 0x0000003f, 0x1c);
set_reg32_bits(0x40022018, 0x00008000, 0);
set_reg32_bits(0x40022030, 0x3f000000, 28);
set_reg32_bits(0x40022030, 0x00000fc0, 30);
set_reg32_bits(0x40022030, 0x0000003f, 30);
set_reg32(0x400200ac, 0);
delay_us(20);
set_reg32_bits(0x4002024c, 0x000003e0, bkp[1]);
delay_us(10);
g_ble_phy_rf_data.cal_res_2 = k1;
}
static uint32_t
ble_rf_find_trim_reg(volatile uint32_t *tv, unsigned len, uint32_t reg)
{
while (len) {
if (tv[0] == reg) {
return tv[1];
}
len -= 2;
tv += 2;
}
return 0;
}
void
ble_rf_init(void)
{
uint32_t val;
val = ble_rf_find_trim_reg(g_cmac_shared_data.trim.rfcu_mode1,
g_cmac_shared_data.trim.rfcu_mode1_len,
0x4002004c);
g_ble_phy_rf_data.trim_val1_tx_1 = val;
val = ble_rf_find_trim_reg(g_cmac_shared_data.trim.rfcu_mode2,
g_cmac_shared_data.trim.rfcu_mode2_len,
0x4002004c);
g_ble_phy_rf_data.trim_val1_tx_2 = val;
if (!g_ble_phy_rf_data.trim_val1_tx_1 || !g_ble_phy_rf_data.trim_val1_tx_2) {
val = ble_rf_find_trim_reg(g_cmac_shared_data.trim.rfcu,
g_cmac_shared_data.trim.rfcu_len,
0x4002004c);
if (!val) {
val = 0x0300;
}
g_ble_phy_rf_data.trim_val1_tx_1 = val;
g_ble_phy_rf_data.trim_val1_tx_2 = val;
}
val = ble_rf_find_trim_reg(g_cmac_shared_data.trim.synth,
g_cmac_shared_data.trim.synth_len,
0x40022038);
if (!val) {
val = 0x0198ff03;
}
g_ble_phy_rf_data.trim_val2_rx = val;
g_ble_phy_rf_data.trim_val2_tx = val;
set_reg32_bits((uint32_t)&g_ble_phy_rf_data.trim_val2_tx, 0x0001ff00, 0x87);
#if MYNEWT_VAL(CMAC_DEBUG_DATA_ENABLE)
g_cmac_shared_data.debug.trim_val1_tx_1 = g_ble_phy_rf_data.trim_val1_tx_1;
g_cmac_shared_data.debug.trim_val1_tx_2 = g_ble_phy_rf_data.trim_val1_tx_2;
g_cmac_shared_data.debug.trim_val2_tx = g_ble_phy_rf_data.trim_val2_tx;
g_cmac_shared_data.debug.trim_val2_rx = g_ble_phy_rf_data.trim_val2_rx;
#endif
}
void
ble_rf_enable(void)
{
if (ble_rf_is_enabled()) {
return;
}
ble_rf_rfcu_enable();
ble_rf_rfcu_apply_settings();
ble_rf_ldo_on();
}
void
ble_rf_configure(void)
{
if (ble_rf_synth_is_enabled()) {
return;
}
ble_rf_synth_enable();
ble_rf_synth_apply_settings();
}
void
ble_rf_stop(void)
{
ble_rf_synth_disable();
set_reg8(0x40020006, 0);
}
void
ble_rf_disable(void)
{
ble_rf_stop();
ble_rf_ldo_off();
ble_rf_rfcu_disable();
}
bool
ble_rf_is_enabled(void)
{
return get_reg32_bits(0x40020008, 5) == 5;
}
static void
ble_rf_calibrate_int(uint8_t mask)
{
ble_rf_rfcu_enable();
ble_rf_rfcu_apply_settings();
ble_rf_ldo_on();
delay_us(20);
ble_rf_synth_disable();
ble_rf_synth_enable();
ble_rf_synth_apply_settings();
set_reg8(0x40020005, 1);
if (mask & RF_CALIBRATION_0) {
ble_rf_calibration_0();
}
if (mask & RF_CALIBRATION_1) {
ble_rf_calibration_1();
}
if (mask & RF_CALIBRATION_2) {
ble_rf_calibration_2();
}
ble_rf_ldo_off();
ble_rf_rfcu_disable();
#if MYNEWT_VAL(CMAC_DEBUG_DATA_ENABLE)
g_cmac_shared_data.debug.cal_res_1 = g_ble_phy_rf_data.cal_res_1;
g_cmac_shared_data.debug.cal_res_2 = g_ble_phy_rf_data.cal_res_2;
#endif
}
void
ble_rf_calibrate(void)
{
ble_rf_calibrate_int(RF_CALIBRATION_1 | RF_CALIBRATION_2);
}
void
ble_rf_calibrate_once(void)
{
static bool calibrated = false;
if (calibrated) {
return;
}
ble_rf_rfcu_enable();
ble_rf_rfcu_apply_settings();
g_ble_phy_rf_data.tx_power_cfg1 = get_reg32_bits(0x500000a4, 0xf0);
g_ble_phy_rf_data.tx_power_cfg2 = get_reg32_bits(0x40020238, 0x000003e0);
g_ble_phy_rf_data.tx_power_cfg3 = 0;
ble_rf_rfcu_disable();
ble_rf_calibrate_int(RF_CALIBRATION_0 | RF_CALIBRATION_1 | RF_CALIBRATION_2);
calibrated = true;
}
void
ble_rf_setup_tx(uint8_t rf_chan, uint8_t phy_mode)
{
set_reg32_bits(0x40020000, 0x0f000000, g_ble_phy_rf_data.tx_power_cfg0);
set_reg32_bits(0x500000a4, 0x000000f0, g_ble_phy_rf_data.tx_power_cfg1);
set_reg32_bits(0x40020238, 0x000003e0, g_ble_phy_rf_data.tx_power_cfg2);
set_reg32_bits(0x40020234, 0x000003e0, g_ble_phy_rf_data.tx_power_cfg3);
if (g_ble_phy_rf_data.tx_power_cfg0 < 13) {
set_reg32(0x4002004c, g_ble_phy_rf_data.trim_val1_tx_1);
} else {
set_reg32(0x4002004c, g_ble_phy_rf_data.trim_val1_tx_2);
}
set_reg8(0x40020005, 3);
set_reg8(0x40022004, rf_chan);
if (phy_mode == BLE_PHY_MODE_2M) {
#if MYNEWT_VAL(BLE_PHY_RF_HP_MODE)
set_reg32(0x40022000, 0x00000303);
#else
set_reg32(0x40022000, 0x00000003);
#endif
} else {
#if MYNEWT_VAL(BLE_PHY_RF_HP_MODE)
set_reg32(0x40022000, 0x00000300);
#else
set_reg32(0x40022000, 0x00000000);
#endif
}
ble_rf_apply_calibration();
set_reg32_bits(0x40022050, 0x00000200, 1);
set_reg32_bits(0x40022050, 0x00000100, 0);
set_reg32_bits(0x40022048, 0x01ffff00, 0x7700);
set_reg32(0x40022038, g_ble_phy_rf_data.trim_val2_tx);
set_reg8(0x40020006, 3);
}
void
ble_rf_setup_rx(uint8_t rf_chan, uint8_t phy_mode)
{
set_reg32_bits(0x500000a4, 0x000000f0, g_ble_phy_rf_data.tx_power_cfg1);
set_reg8(0x40020005, 3);
set_reg8(0x40022004, rf_chan);
if (phy_mode == BLE_PHY_MODE_2M) {
#if MYNEWT_VAL(BLE_PHY_RF_HP_MODE)
set_reg32(0x40022000, 0x00000303);
set_reg32(0x40020000, 0x0f11b823);
set_reg32(0x4002103c, 0x0125261b);
#else
set_reg32(0x40022000, 0x00000003);
set_reg32(0x40020000, 0x0f0c2803);
set_reg32(0x4002103c, 0x0125a61b);
#endif
set_reg32(0x40021020, 0x000002f5);
set_reg32(0x4002102c, 0x0000d1d5);
} else {
#if MYNEWT_VAL(BLE_PHY_RF_HP_MODE)
set_reg32(0x40022000, 0x00000300);
set_reg32(0x40020000, 0x0f099820);
set_reg32(0x4002103c, 0x0124a21f);
#else
set_reg32(0x40022000, 0x00000000);
set_reg32(0x40020000, 0x0f062800);
set_reg32(0x4002103c, 0x01051e1f);
#endif
set_reg32(0x40021020, 0x000002f5);
set_reg32(0x4002102c, 0x0000dfe7);
}
ble_rf_apply_calibration();
set_reg32_bits(0x40022050, 0x00000200, 1);
set_reg32_bits(0x40022050, 0x00000100, 1);
set_reg32_bits(0x40022048, 0x01ffff00, 0);
set_reg32(0x40022038, g_ble_phy_rf_data.trim_val2_rx);
set_reg8(0x40020006, 3);
}
void
ble_rf_set_tx_power(int dbm)
{
int i;
for (i = 0; i < ARRAY_SIZE(g_ble_rf_power_lvls); i++) {
if (g_ble_rf_power_lvls[i] >= dbm) {
break;
}
}
g_ble_phy_rf_data.tx_power_cfg0 = i + 1;
}
int8_t
ble_rf_get_rssi(void)
{
return (501 * get_reg32_bits(0x40021038, 0x000003ff) - 493000) / 4096;
}
@@ -0,0 +1,39 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef _BLE_RF_PRIV_H_
#define _BLE_RF_PRIV_H_
void ble_rf_init(void);
void ble_rf_enable(void);
void ble_rf_stop(void);
void ble_rf_disable(void);
bool ble_rf_is_enabled(void);
void ble_rf_configure(void);
void ble_rf_calibrate(void);
void ble_rf_calibrate_once(void);
void ble_rf_setup_tx(uint8_t rf_chan, uint8_t mode);
void ble_rf_setup_rx(uint8_t rf_chan, uint8_t mode);
void ble_rf_set_tx_power(int dbm);
int8_t ble_rf_get_rssi(void);
#endif /* _BLE_RF_PRIV_H_ */
+29
View File
@@ -0,0 +1,29 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
syscfg.defs:
BLE_PHY_RF_HP_MODE:
description: Enable high-performance RF mode.
value: 1
BLE_PHY_DEBUG_DSER:
description: Enable DSER output from PHY
value: 0
syscfg.restrictions:
- BLE_LL_RFMGMT_ENABLE_TIME == 0 || BLE_LL_RFMGMT_ENABLE_TIME >= 20