summaryrefslogtreecommitdiff
path: root/src/libs/mynewt-nimble/nimble/transport/da1469x
diff options
context:
space:
mode:
authorJF <jf@codingfield.com>2020-05-17 10:29:13 +0200
committerGitea <gitea@fake.local>2020-05-17 10:29:13 +0200
commit8a94750e30399bfb204cbec59a769d9d1b6b5baa (patch)
tree8a1a58beae54e238d28aff116c900f3b428b7db4 /src/libs/mynewt-nimble/nimble/transport/da1469x
parent86d5732b960fbe7f81ed711b2de7e6b79293c96a (diff)
parentbe1ad9b07083e656a649d223750ff4b14b781b7b (diff)
Merge branch 'develop' of JF/PineTime into master
Diffstat (limited to 'src/libs/mynewt-nimble/nimble/transport/da1469x')
-rw-r--r--src/libs/mynewt-nimble/nimble/transport/da1469x/.gitignore2
-rw-r--r--src/libs/mynewt-nimble/nimble/transport/da1469x/README13
-rw-r--r--src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/include/cmac_driver/cmac_host.h37
-rw-r--r--src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/pkg.yml27
-rwxr-xr-xsrc/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/scripts/build_libcmac.sh51
-rw-r--r--src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/src/cmac_host.c326
-rw-r--r--src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/syscfg.yml23
-rw-r--r--src/libs/mynewt-nimble/nimble/transport/da1469x/pkg.yml38
-rw-r--r--src/libs/mynewt-nimble/nimble/transport/da1469x/src/da1469x_ble_hci.c368
-rw-r--r--src/libs/mynewt-nimble/nimble/transport/da1469x/syscfg.yml43
10 files changed, 928 insertions, 0 deletions
diff --git a/src/libs/mynewt-nimble/nimble/transport/da1469x/.gitignore b/src/libs/mynewt-nimble/nimble/transport/da1469x/.gitignore
new file mode 100644
index 00000000..bba9f995
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/transport/da1469x/.gitignore
@@ -0,0 +1,2 @@
+/src/libble_stack_da1469x.a
+
diff --git a/src/libs/mynewt-nimble/nimble/transport/da1469x/README b/src/libs/mynewt-nimble/nimble/transport/da1469x/README
new file mode 100644
index 00000000..b30a01c4
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/transport/da1469x/README
@@ -0,0 +1,13 @@
+Integrated BLE Controller (CMAC) requires a binary firmware to be loaded. Such
+firmware is distributed by Dialog Semiconductor in SDK package which has to be
+obtained separately, see:
+https://www.dialog-semiconductor.com/products/da1469x-product-family
+
+Firmware is available as part of following library in SDK package:
+sdk/interfaces/ble/binaries/DA1469x-Release/libble_stack_da1469x.a
+
+By default, CMAC driver will look for this file in its package root directory
+(i.e. nimble/transport/da1469x/cmac_driver) but this can be changed using
+CMAC_IMAGE_FILE_NAME syscfg variable.
+
+Current version of CMAC driver was tested with SDK version 10.0.4.66.
diff --git a/src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/include/cmac_driver/cmac_host.h b/src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/include/cmac_driver/cmac_host.h
new file mode 100644
index 00000000..f623a48a
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/include/cmac_driver/cmac_host.h
@@ -0,0 +1,37 @@
+/*
+ * 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 __CMAC_HOST_H_
+#define __CMAC_HOST_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef int (* cmac_mbox_read_cb)(const uint8_t *, uint16_t len);
+
+void cmac_host_init(void);
+void cmac_mbox_write(const uint8_t *buf, size_t len);
+void cmac_mbox_set_read_cb(cmac_mbox_read_cb cb);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CMAC_HOST_H_ */
diff --git a/src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/pkg.yml b/src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/pkg.yml
new file mode 100644
index 00000000..90a89318
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/pkg.yml
@@ -0,0 +1,27 @@
+#
+# 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/transport/da1469x/cmac_driver
+pkg.description: Driver for Dialog's BLE controller
+pkg.author:
+pkg.homepage:
+pkg.keywords:
+
+pkg.pre_link_cmds.BLE_HOST:
+ scripts/build_libcmac.sh: 100
diff --git a/src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/scripts/build_libcmac.sh b/src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/scripts/build_libcmac.sh
new file mode 100755
index 00000000..659c2b9f
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/scripts/build_libcmac.sh
@@ -0,0 +1,51 @@
+#!/bin/bash
+
+# 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.
+
+if [ ! -f ${MYNEWT_VAL_CMAC_IMAGE_FILE_NAME} ]; then
+ >&2 echo ERROR: BLE stack library not found. Please check nimble/transport/da1469x/README for details.
+ exit 1
+fi
+
+OBJCOPY=${MYNEWT_OBJCOPY_PATH}
+AR=${MYNEWT_AR_PATH}
+LIBBLE_A=$(readlink -e ${MYNEWT_VAL_CMAC_IMAGE_FILE_NAME})
+LIBCMAC_A=${MYNEWT_USER_SRC_DIR}/libcmac.a
+
+BASENAME_ROM=cmac.rom
+BASENAME_RAM=cmac.ram
+
+cd ${MYNEWT_USER_WORK_DIR}
+
+# Extract firmware binary from .a since we do not need to link all other
+# objects with our image.
+${AR} x ${LIBBLE_A} cmac_fw.c.obj
+${OBJCOPY} -O binary --only-section=.cmi_fw_area cmac_fw.c.obj cmac.bin
+
+# We need separate copies for RAM and ROM image since section names are derived
+# from file names. For now files are the same, but it would be possible to
+# link ROM image without data and shared sections which contains zeroes anyway.
+cp cmac.bin ${BASENAME_ROM}.bin
+cp cmac.bin ${BASENAME_RAM}.bin
+
+# Convert both binaries to objects and create archive to link
+${OBJCOPY} -I binary -O elf32-littlearm -B armv8-m.main \
+ --rename-section .data=.libcmac.rom ${BASENAME_ROM}.bin ${BASENAME_ROM}.o
+${OBJCOPY} -I binary -O elf32-littlearm -B armv8-m.main \
+ --rename-section .data=.libcmac.ram ${BASENAME_RAM}.bin ${BASENAME_RAM}.o
+${AR} -rcs ${LIBCMAC_A} ${BASENAME_ROM}.o ${BASENAME_RAM}.o
diff --git a/src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/src/cmac_host.c b/src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/src/cmac_host.c
new file mode 100644
index 00000000..0bfb715e
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/src/cmac_host.c
@@ -0,0 +1,326 @@
+/*
+ * 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 <string.h>
+#include "os/os.h"
+#include "mcu/cmsis_nvic.h"
+#include "mcu/da1469x_lpclk.h"
+#include "mcu/da1469x_hal.h"
+#include "mcu/da1469x_pdc.h"
+#include "mcu/mcu.h"
+#include "cmac_driver/cmac_host.h"
+
+#define CMAC_SYM_CONFIG ((void *)(0x00818f20 + MEMCTRL->CMI_CODE_BASE_REG))
+#define CMAC_SYM_CONFIG_DYN ((void *)(0x00821af8 + MEMCTRL->CMI_CODE_BASE_REG))
+#define CMAC_SYM_MBOX_RX ((void *)(0x008216b0 + MEMCTRL->CMI_CODE_BASE_REG))
+#define CMAC_SYM_MBOX_TX ((void *)(0x008218b0 + MEMCTRL->CMI_CODE_BASE_REG))
+
+#define CMAC_MBOX_SIZE 504
+#define CMAC_MBOX_F_RESET 0x0008
+#define CMAC_MBOX_F_WRITEPENDING 0x0010
+
+struct cmac_config {
+ uint8_t bdaddr[6]; /* Device address */
+
+ uint8_t rf_calibration_delay;
+
+ uint8_t lp_clock_freq; /* Sleep clock frequency (0 = 32768Hz, 1 = 32000Hz) */
+ uint16_t lp_clock_sca; /* Sleep clock accuracy [ppm] */
+
+ uint16_t rx_buf_len; /* RX buffer size */
+ uint16_t tx_buf_len; /* TX buffer size */
+ bool initial_length_req;
+
+ /* Channel assessment algorithm settings */
+ uint16_t chan_assess_itvl;
+ uint8_t chan_assess_itvl_mult;
+ int8_t chan_assess_min_rssi;
+ uint16_t chan_assess_pkt_num;
+ uint16_t chan_assess_bad_pkt_num;
+
+ /* Calibration settings */
+ uint8_t system_tcs_length;
+ uint8_t synth_tcs_length;
+ uint8_t rfcu_tcs_length;
+
+ uint8_t default_tx_power; /* Default TX power for connection/advertising */
+ bool filter_dup_ov_discard; /* Discard unknown devices when filter buffer is full */
+ bool use_hp_1m;
+ bool use_hp_2m;
+};
+
+struct cmac_config_dynamic {
+ bool enable_sleep; /* Enable sleep */
+
+ /* More options here, don't care now */
+};
+
+struct cmac_mbox {
+ volatile uint16_t magic;
+ volatile uint16_t flags;
+ volatile uint16_t wr_off;
+ volatile uint16_t rd_off;
+ uint8_t data[CMAC_MBOX_SIZE];
+};
+
+/* CMAC data */
+extern char _binary_cmac_rom_bin_start[];
+extern char _binary_cmac_rom_bin_end;
+extern char _binary_cmac_ram_bin_start[];
+extern char _binary_cmac_ram_bin_end;
+
+struct cmac_image_info {
+ uint32_t _dummy1;
+ uint32_t size_rom;
+ uint32_t _dummy2;
+ uint32_t magic;
+ uint32_t _dummy3[5];
+};
+
+/* Mailboxes for SYS<->CMAC communication */
+static struct cmac_mbox *cmac_mbox_rx;
+static struct cmac_mbox *cmac_mbox_tx;
+
+/* PDC entry for waking up CMAC */
+static int8_t g_cmac_host_pdc_sys2cmac;
+/* PDC entry for waking up M33 */
+static int8_t g_cmac_host_pdc_cmac2sys;
+/* Callback for data ready from CMAC */
+static cmac_mbox_read_cb g_cmac_mbox_read_cb;
+
+static inline void
+cmac_host_signal2cmac(void)
+{
+ da1469x_pdc_set(g_cmac_host_pdc_sys2cmac);
+}
+
+static void
+cmac2sys_isr(void)
+{
+ uint16_t wr_off;
+ uint16_t rd_off;
+ uint16_t chunk;
+ uint16_t len;
+
+ os_trace_isr_enter();
+
+ /* Clear CMAC2SYS interrupt */
+ *(volatile uint32_t *)0x40002000 = 2;
+
+ if (*(volatile uint32_t *)0x40002000 & 0x1c00) {
+ /* XXX CMAC is in error state, need to recover */
+ assert(0);
+ }
+
+ if (cmac_mbox_rx->flags & CMAC_MBOX_F_RESET) {
+ cmac_mbox_rx->flags &= ~CMAC_MBOX_F_RESET;
+ goto done;
+ }
+
+ if (!g_cmac_mbox_read_cb) {
+ cmac_mbox_rx->rd_off = cmac_mbox_rx->wr_off;
+ goto done;
+ }
+
+ do {
+ rd_off = cmac_mbox_rx->rd_off;
+ wr_off = cmac_mbox_rx->wr_off;
+
+ if (rd_off <= wr_off) {
+ chunk = wr_off - rd_off;
+ } else {
+ chunk = CMAC_MBOX_SIZE - rd_off;
+ }
+
+ while (chunk) {
+ len = g_cmac_mbox_read_cb(&cmac_mbox_rx->data[rd_off], chunk);
+
+ rd_off += len;
+ chunk -= len;
+ };
+
+ cmac_mbox_rx->rd_off = rd_off % CMAC_MBOX_SIZE;
+ } while (cmac_mbox_rx->rd_off != cmac_mbox_rx->wr_off);
+
+done:
+
+ if (cmac_mbox_rx->flags & CMAC_MBOX_F_WRITEPENDING) {
+ cmac_host_signal2cmac();
+ }
+
+ os_trace_isr_exit();
+}
+
+static void
+cmac_host_lpclk_cb(uint32_t freq)
+{
+ struct cmac_config_dynamic *cmac_config_dyn;
+
+ cmac_config_dyn = CMAC_SYM_CONFIG_DYN;
+ cmac_config_dyn->enable_sleep = freq == 32768;
+}
+
+void
+cmac_mbox_write(const uint8_t *buf, size_t len)
+{
+ uint16_t wr_off;
+ uint16_t rd_off;
+ uint16_t chunk;
+ uint32_t primask;
+
+ __HAL_DISABLE_INTERRUPTS(primask);
+
+ while (len) {
+ rd_off = cmac_mbox_tx->rd_off;
+ wr_off = cmac_mbox_tx->wr_off;
+
+ if (rd_off > wr_off) {
+ chunk = min(len, rd_off - wr_off);
+ } else {
+ chunk = min(len, CMAC_MBOX_SIZE - wr_off);
+ }
+
+ if (chunk == 0) {
+ continue;
+ }
+
+ memcpy(&cmac_mbox_tx->data[wr_off], buf, chunk);
+
+ wr_off += chunk;
+ cmac_mbox_tx->wr_off = wr_off % CMAC_MBOX_SIZE;
+
+ cmac_host_signal2cmac();
+
+ len -= chunk;
+ buf += chunk;
+ }
+
+ __HAL_ENABLE_INTERRUPTS(primask);
+}
+
+void
+cmac_mbox_set_read_cb(cmac_mbox_read_cb cb)
+{
+ g_cmac_mbox_read_cb = cb;
+}
+
+void
+cmac_host_init(void)
+{
+ struct cmac_image_info ii;
+ uint32_t cmac_rom_size;
+ uint32_t cmac_ram_size;
+ struct cmac_config *cmac_config;
+ struct cmac_config_dynamic *cmac_config_dyn;
+
+ /* Add PDC entry to wake up CMAC from M33 */
+ g_cmac_host_pdc_sys2cmac = da1469x_pdc_add(MCU_PDC_TRIGGER_MAC_TIMER,
+ MCU_PDC_MASTER_CMAC,
+ MCU_PDC_EN_XTAL);
+ da1469x_pdc_set(g_cmac_host_pdc_sys2cmac);
+ da1469x_pdc_ack(g_cmac_host_pdc_sys2cmac);
+
+ /* Add PDC entry to wake up M33 from CMAC, if does not exist yet */
+ g_cmac_host_pdc_cmac2sys = da1469x_pdc_find(MCU_PDC_TRIGGER_COMBO,
+ MCU_PDC_MASTER_M33, 0);
+ if (g_cmac_host_pdc_cmac2sys < 0) {
+ g_cmac_host_pdc_cmac2sys = da1469x_pdc_add(MCU_PDC_TRIGGER_COMBO,
+ MCU_PDC_MASTER_M33,
+ MCU_PDC_EN_XTAL);
+ da1469x_pdc_set(g_cmac_host_pdc_cmac2sys);
+ da1469x_pdc_ack(g_cmac_host_pdc_cmac2sys);
+ }
+
+ /* Enable Radio LDO */
+ CRG_TOP->POWER_CTRL_REG |= CRG_TOP_POWER_CTRL_REG_LDO_RADIO_ENABLE_Msk;
+
+ /* Enable CMAC, but keep it in reset */
+ CRG_TOP->CLK_RADIO_REG = (1 << CRG_TOP_CLK_RADIO_REG_RFCU_ENABLE_Pos) |
+ (1 << CRG_TOP_CLK_RADIO_REG_CMAC_SYNCH_RESET_Pos) |
+ (0 << CRG_TOP_CLK_RADIO_REG_CMAC_CLK_SEL_Pos) |
+ (1 << CRG_TOP_CLK_RADIO_REG_CMAC_CLK_ENABLE_Pos) |
+ (0 << CRG_TOP_CLK_RADIO_REG_CMAC_DIV_Pos);
+
+ /* Calculate size of ROM and RAM area (for now they should be the same) */
+ cmac_rom_size = &_binary_cmac_rom_bin_end - &_binary_cmac_rom_bin_start[0];
+ cmac_ram_size = &_binary_cmac_ram_bin_end - &_binary_cmac_ram_bin_start[0];
+ assert(cmac_rom_size == cmac_ram_size);
+
+ /* Load image header and check if image can be loaded */
+ memcpy(&ii, &_binary_cmac_rom_bin_start, sizeof(ii));
+ assert(ii.magic == 0x43414d43); /* "CMAC" */
+
+ /* Copy CMAC image to RAM */
+ memset(&_binary_cmac_ram_bin_start, 0, cmac_ram_size);
+ memcpy(&_binary_cmac_ram_bin_start, &_binary_cmac_rom_bin_start[sizeof(ii)],
+ ii.size_rom);
+
+ /*
+ * Setup memory controller for CMAC
+ * Code and data are set to the same address initially since CMAC will
+ * update data address on init. Also shared address is updated on init.
+ */
+ MEMCTRL->CMI_CODE_BASE_REG = (uint32_t)&_binary_cmac_ram_bin_start;
+ MEMCTRL->CMI_DATA_BASE_REG = MEMCTRL->CMI_CODE_BASE_REG;
+ MEMCTRL->CMI_SHARED_BASE_REG = 0;
+ MEMCTRL->CMI_END_REG = (uint32_t)&_binary_cmac_ram_bin_end;
+
+ /* Symbols below are in shared memory, can update them now */
+ cmac_config = CMAC_SYM_CONFIG;
+ cmac_config_dyn = CMAC_SYM_CONFIG_DYN;
+ cmac_mbox_rx = CMAC_SYM_MBOX_RX;
+ cmac_mbox_tx = CMAC_SYM_MBOX_TX;
+
+ /* Update CMAC configuration */
+ cmac_config->lp_clock_freq = 0;
+ cmac_config->lp_clock_sca = 50;
+ cmac_config->rx_buf_len = 251 + 11;
+ cmac_config->tx_buf_len = 251 + 11;
+ cmac_config->initial_length_req = 0;
+ cmac_config->system_tcs_length = 0;
+ cmac_config->synth_tcs_length = 0;
+ cmac_config->rfcu_tcs_length = 0;
+ cmac_config->default_tx_power = 4;
+ cmac_config_dyn->enable_sleep = false;
+
+ /* Release CMAC from reset */
+ CRG_TOP->CLK_RADIO_REG &= ~CRG_TOP_CLK_RADIO_REG_CMAC_SYNCH_RESET_Msk;
+
+ /* Wait for CMAC to update registers */
+ while (MEMCTRL->CMI_DATA_BASE_REG == MEMCTRL->CMI_CODE_BASE_REG);
+ while (MEMCTRL->CMI_SHARED_BASE_REG != (MEMCTRL->CMI_END_REG & 0xfffffc00));
+
+ /* Initialize mailboxes and sync with CMAC */
+ cmac_mbox_tx->flags = CMAC_MBOX_F_RESET;
+ cmac_mbox_tx->wr_off = 0;
+ cmac_mbox_tx->rd_off = 0;
+ cmac_mbox_tx->magic = 0xa55a;
+ while (cmac_mbox_rx->magic != 0xa55a);
+
+ NVIC_SetVector(CMAC2SYS_IRQn, (uint32_t)cmac2sys_isr);
+ NVIC_SetPriority(CMAC2SYS_IRQn, 0);
+ NVIC_EnableIRQ(CMAC2SYS_IRQn);
+
+ cmac_host_signal2cmac();
+
+ da1469x_lpclk_register_cmac_cb(cmac_host_lpclk_cb);
+}
diff --git a/src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/syscfg.yml b/src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/syscfg.yml
new file mode 100644
index 00000000..be2e62d9
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/syscfg.yml
@@ -0,0 +1,23 @@
+# 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:
+ CMAC_IMAGE_FILE_NAME:
+ description: >
+ Path to library with CMAC firmware. See README for details.
+ value: "libble_stack_da1469x.a"
diff --git a/src/libs/mynewt-nimble/nimble/transport/da1469x/pkg.yml b/src/libs/mynewt-nimble/nimble/transport/da1469x/pkg.yml
new file mode 100644
index 00000000..5d9b533c
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/transport/da1469x/pkg.yml
@@ -0,0 +1,38 @@
+#
+# 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/transport/da1469x
+pkg.description: HCI transport for DA1469x
+pkg.author: "Apache Mynewt <dev@mynewt.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+ - ble
+ - bluetooth
+
+pkg.deps:
+ - "@apache-mynewt-nimble/nimble"
+ - "@apache-mynewt-nimble/nimble/transport/da1469x/cmac_driver"
+ - "@apache-mynewt-core/kernel/os"
+
+pkg.apis:
+ - ble_transport
+
+pkg.init:
+ da1469x_ble_hci_init: 100
+ da1469x_ble_hci_cmac_init: 201
diff --git a/src/libs/mynewt-nimble/nimble/transport/da1469x/src/da1469x_ble_hci.c b/src/libs/mynewt-nimble/nimble/transport/da1469x/src/da1469x_ble_hci.c
new file mode 100644
index 00000000..971d0cd0
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/transport/da1469x/src/da1469x_ble_hci.c
@@ -0,0 +1,368 @@
+/*
+ * 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 <string.h>
+#include "os/mynewt.h"
+#include "nimble/ble.h"
+#include "nimble/ble_hci_trans.h"
+#include "nimble/hci_common.h"
+#include "cmac_driver/cmac_host.h"
+
+#define HCI_PKT_NONE 0x00
+#define HCI_PKT_CMD 0x01
+#define HCI_PKT_ACL 0x02
+#define HCI_PKT_EVT 0x04
+
+#define POOL_ACL_BLOCK_SIZE \
+ OS_ALIGN(MYNEWT_VAL(BLE_ACL_BUF_SIZE) + \
+ BLE_MBUF_MEMBLOCK_OVERHEAD + \
+ BLE_HCI_DATA_HDR_SZ, OS_ALIGNMENT)
+
+struct da1469x_ble_hci_host_api {
+ ble_hci_trans_rx_cmd_fn *evt_cb;
+ void *evt_arg;
+ ble_hci_trans_rx_acl_fn *acl_cb;
+ void *acl_arg;
+};
+
+struct da1469x_ble_hci_rx_data {
+ uint8_t type;
+ uint8_t hdr[4];
+ uint8_t min_len;
+ uint16_t len;
+ uint16_t expected_len;
+ union {
+ uint8_t *buf;
+ struct os_mbuf *om;
+ };
+};
+
+struct da1469x_ble_hci_pool_cmd {
+ uint8_t cmd[BLE_HCI_TRANS_CMD_SZ];
+ bool allocated;
+};
+
+/* (Pseudo)pool for HCI commands */
+static struct da1469x_ble_hci_pool_cmd da1469x_ble_hci_pool_cmd;
+
+/* Pools for HCI events (high and low priority) */
+static uint8_t da1469x_ble_hci_pool_evt_hi_buf[ OS_MEMPOOL_BYTES(
+ MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT),
+ MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE)) ];
+static struct os_mempool da1469x_ble_hci_pool_evt_hi;
+static uint8_t da1469x_ble_hci_pool_evt_lo_buf[ OS_MEMPOOL_BYTES(
+ MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT),
+ MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE)) ];
+static struct os_mempool da1469x_ble_hci_pool_evt_lo;
+
+/* Pool for ACL data */
+static uint8_t da1469x_ble_hci_pool_acl_buf[ OS_MEMPOOL_BYTES(
+ MYNEWT_VAL(BLE_ACL_BUF_COUNT),
+ POOL_ACL_BLOCK_SIZE) ];
+static struct os_mempool da1469x_ble_hci_pool_acl;
+static struct os_mbuf_pool da1469x_ble_hci_pool_acl_mbuf;
+
+/* Interface to host */
+static struct da1469x_ble_hci_host_api da1469x_ble_hci_host_api;
+
+/* State of RX currently in progress (needs to reassemble frame) */
+static struct da1469x_ble_hci_rx_data da1469x_ble_hci_rx_data;
+
+int
+ble_hci_trans_reset(void)
+{
+ /* XXX Should we do something with RF and/or BLE core? */
+ return 0;
+}
+
+void
+ble_hci_trans_cfg_hs(ble_hci_trans_rx_cmd_fn *evt_cb, void *evt_arg,
+ ble_hci_trans_rx_acl_fn *acl_cb, void *acl_arg)
+{
+ da1469x_ble_hci_host_api.evt_cb = evt_cb;
+ da1469x_ble_hci_host_api.evt_arg = evt_arg;
+ da1469x_ble_hci_host_api.acl_cb = acl_cb;
+ da1469x_ble_hci_host_api.acl_arg = acl_arg;
+}
+
+uint8_t *
+ble_hci_trans_buf_alloc(int type)
+{
+ uint8_t *buf;
+
+ switch (type) {
+ case BLE_HCI_TRANS_BUF_CMD:
+ assert(!da1469x_ble_hci_pool_cmd.allocated);
+ da1469x_ble_hci_pool_cmd.allocated = 1;
+ buf = da1469x_ble_hci_pool_cmd.cmd;
+ break;
+ case BLE_HCI_TRANS_BUF_EVT_HI:
+ buf = os_memblock_get(&da1469x_ble_hci_pool_evt_hi);
+ if (buf) {
+ break;
+ }
+ /* no break */
+ case BLE_HCI_TRANS_BUF_EVT_LO:
+ buf = os_memblock_get(&da1469x_ble_hci_pool_evt_lo);
+ break;
+ default:
+ assert(0);
+ buf = NULL;
+ }
+
+ return buf;
+}
+
+void
+ble_hci_trans_buf_free(uint8_t *buf)
+{
+ int rc;
+
+ if (buf == da1469x_ble_hci_pool_cmd.cmd) {
+ assert(da1469x_ble_hci_pool_cmd.allocated);
+ da1469x_ble_hci_pool_cmd.allocated = 0;
+ } else if (os_memblock_from(&da1469x_ble_hci_pool_evt_hi, buf)) {
+ rc = os_memblock_put(&da1469x_ble_hci_pool_evt_hi, buf);
+ assert(rc == 0);
+ } else {
+ assert(os_memblock_from(&da1469x_ble_hci_pool_evt_lo, buf));
+ rc = os_memblock_put(&da1469x_ble_hci_pool_evt_lo, buf);
+ assert(rc == 0);
+ }
+}
+
+int
+ble_hci_trans_hs_cmd_tx(uint8_t *cmd)
+{
+ uint8_t ind = HCI_PKT_CMD;
+ int len = 3 + cmd[2];
+
+ cmac_mbox_write(&ind, 1);
+ cmac_mbox_write(cmd, len);
+
+ ble_hci_trans_buf_free(cmd);
+
+ return 0;
+}
+
+int
+ble_hci_trans_hs_acl_tx(struct os_mbuf *om)
+{
+ uint8_t ind = HCI_PKT_ACL;
+ struct os_mbuf *x;
+
+ cmac_mbox_write(&ind, 1);
+
+ x = om;
+ while (x) {
+ cmac_mbox_write(x->om_data, x->om_len);
+ x = SLIST_NEXT(x, om_next);
+ }
+
+ os_mbuf_free_chain(om);
+
+ return 0;
+}
+
+static int
+da1469x_ble_hci_trans_ll_rx(const uint8_t *buf, uint16_t len)
+{
+ struct da1469x_ble_hci_rx_data *rxd = &da1469x_ble_hci_rx_data;
+ void *data;
+ int pool = BLE_HCI_TRANS_BUF_EVT_HI;
+ int rc;
+
+ assert(len);
+
+ if (rxd->type == HCI_PKT_NONE) {
+ rxd->type = buf[0];
+ rxd->len = 0;
+ rxd->expected_len = 0;
+
+ switch (rxd->type) {
+ case HCI_PKT_ACL:
+ rxd->min_len = 4;
+ break;
+ case HCI_PKT_EVT:
+ rxd->min_len = 2;
+ break;
+ default:
+ assert(0);
+ break;
+ }
+
+ return 1;
+ }
+
+ /* Ensure we have minimum length of bytes required to process header */
+ if (rxd->len < rxd->min_len) {
+ len = min(len, rxd->min_len - rxd->len);
+ memcpy(&rxd->hdr[rxd->len], buf, len);
+ rxd->len += len;
+ return len;
+ }
+
+ /* Parse header and allocate proper buffer if not done yet */
+ if (rxd->expected_len == 0) {
+ switch (rxd->type) {
+ case HCI_PKT_ACL:
+ data = os_mbuf_get_pkthdr(&da1469x_ble_hci_pool_acl_mbuf,
+ sizeof(struct ble_mbuf_hdr));
+ if (!data) {
+ return 0;
+ }
+
+ rxd->om = data;
+ os_mbuf_append(rxd->om, rxd->hdr, rxd->len);
+ rxd->expected_len = get_le16(&rxd->hdr[2]) + 4;
+ break;
+ case HCI_PKT_EVT:
+ if (rxd->hdr[0] == BLE_HCI_EVCODE_LE_META) {
+ /* For LE Meta event we need 3 bytes to parse header */
+ if (rxd->min_len < 3) {
+ rxd->min_len = 3;
+ return 0;
+ }
+
+ /* Advertising reports shall be allocated from low-prio pool */
+ if ((rxd->hdr[2] == BLE_HCI_LE_SUBEV_ADV_RPT) ||
+ (rxd->hdr[2] == BLE_HCI_LE_SUBEV_EXT_ADV_RPT)) {
+ pool = BLE_HCI_TRANS_BUF_EVT_LO;
+ }
+ }
+
+ data = ble_hci_trans_buf_alloc(pool);
+ if (!data) {
+ /*
+ * Only care about valid buffer when shall be allocated from
+ * high-prio pool, otherwise NULL is fine and we'll just skip
+ * this event.
+ */
+ if (pool != BLE_HCI_TRANS_BUF_EVT_LO) {
+ data = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO);
+ if (!data) {
+ return 0;
+ }
+ }
+ }
+
+ rxd->buf = data;
+ memcpy(rxd->buf, rxd->hdr, rxd->len);
+ rxd->expected_len = rxd->hdr[1] + 2;
+ break;
+ default:
+ assert(0);
+ return len;
+ }
+ }
+
+ len = min(len, rxd->expected_len - rxd->len);
+
+ switch (rxd->type) {
+ case HCI_PKT_ACL:
+ os_mbuf_append(rxd->om, buf, len);
+ rxd->len += len;
+
+ if (rxd->len == rxd->expected_len) {
+ rc = da1469x_ble_hci_host_api.acl_cb(rxd->om,
+ da1469x_ble_hci_host_api.acl_arg);
+ if (rc != 0) {
+ os_mbuf_free_chain(rxd->om);
+ }
+ rxd->type = HCI_PKT_NONE;
+ }
+ break;
+ case HCI_PKT_EVT:
+ if (rxd->buf) {
+ memcpy(&rxd->buf[rxd->len], buf, len);
+ }
+ rxd->len += len;
+
+ if (rxd->len == rxd->expected_len) {
+ /*
+ * XXX for unknown reason at startup controller sends command
+ * complete for a vendor specific command which we never sent
+ * and this messes up with our ack code - just discard this
+ * event
+ */
+ if ((rxd->buf[0] == 0x0E) && (get_le16(&rxd->buf[3]) == 0xfc11)) {
+ ble_hci_trans_buf_free(rxd->buf);
+ } else if (rxd->buf) {
+ rc = da1469x_ble_hci_host_api.evt_cb(rxd->buf,
+ da1469x_ble_hci_host_api.evt_arg);
+ if (rc != 0) {
+ ble_hci_trans_buf_free(rxd->buf);
+ }
+ }
+ rxd->type = HCI_PKT_NONE;
+ }
+ break;
+ default:
+ assert(0);
+ break;
+ }
+
+ return len;
+}
+
+static int
+da1469x_ble_hci_read_cb(const uint8_t *buf, uint16_t len)
+{
+ return da1469x_ble_hci_trans_ll_rx(buf, len);
+}
+
+void
+da1469x_ble_hci_init(void)
+{
+ int rc;
+
+ SYSINIT_ASSERT_ACTIVE();
+
+ rc = os_mempool_init(&da1469x_ble_hci_pool_acl, MYNEWT_VAL(BLE_ACL_BUF_COUNT),
+ POOL_ACL_BLOCK_SIZE, da1469x_ble_hci_pool_acl_buf,
+ "da1469x_ble_hci_pool_acl");
+ SYSINIT_PANIC_ASSERT(rc == 0);
+
+ rc = os_mbuf_pool_init(&da1469x_ble_hci_pool_acl_mbuf,
+ &da1469x_ble_hci_pool_acl, POOL_ACL_BLOCK_SIZE,
+ MYNEWT_VAL(BLE_ACL_BUF_COUNT));
+ SYSINIT_PANIC_ASSERT(rc == 0);
+
+ rc = os_mempool_init(&da1469x_ble_hci_pool_evt_hi,
+ MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT),
+ MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE),
+ da1469x_ble_hci_pool_evt_hi_buf,
+ "da1469x_ble_hci_pool_evt_hi");
+ SYSINIT_PANIC_ASSERT(rc == 0);
+
+ rc = os_mempool_init(&da1469x_ble_hci_pool_evt_lo,
+ MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT),
+ MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE),
+ da1469x_ble_hci_pool_evt_lo_buf,
+ "da1469x_ble_hci_pool_evt_lo");
+ SYSINIT_PANIC_ASSERT(rc == 0);
+}
+
+void
+da1469x_ble_hci_cmac_init(void)
+{
+ cmac_mbox_set_read_cb(da1469x_ble_hci_read_cb);
+ cmac_host_init();
+}
diff --git a/src/libs/mynewt-nimble/nimble/transport/da1469x/syscfg.yml b/src/libs/mynewt-nimble/nimble/transport/da1469x/syscfg.yml
new file mode 100644
index 00000000..4ea9da9b
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/transport/da1469x/syscfg.yml
@@ -0,0 +1,43 @@
+# 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_HCI_EVT_HI_BUF_COUNT:
+ description: 'Number of high-priority event buffers.'
+ value: 2
+
+ BLE_HCI_EVT_LO_BUF_COUNT:
+ description: 'Number of low-priority event buffers.'
+ value: 8
+
+ BLE_HCI_EVT_BUF_SIZE:
+ description: 'Size of each event buffer, in bytes.'
+ value: 70
+
+ BLE_ACL_BUF_COUNT:
+ description: 'The number of ACL data buffers'
+ value: 4
+
+ BLE_ACL_BUF_SIZE:
+ description: >
+ This is the maximum size of the data portion of HCI ACL data
+ packets. It does not include the HCI data header (of 4 bytes).
+ value: 255
+
+syscfg.vals.BLE_EXT_ADV:
+ BLE_HCI_EVT_BUF_SIZE: 274