blob: f9756ec64516e0abde1425317536780ea387ce0a [file] [log] [blame]
/*
* 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 <ipc_cmac/shm.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;
uint8_t calibrate_req;
};
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_shm_trim.rfcu, g_cmac_shm_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)
{
if (mcu_chip_variant_get() == MCU_CHIP_VARIANT_GF) {
set_reg32_mask(0x40022034, 0x00000018, 0x0215807B);
}
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_shm_trim.synth, g_cmac_shm_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(0x4002103c, 0x0124a21f);
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);
if (mcu_chip_variant_get() == MCU_CHIP_VARIANT_TSMC) {
set_reg32_bits(0x4002001c, 0x0000003f, 47);
} else {
set_reg32_bits(0x4002001c, 0x0000003f, 44);
}
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(0x40022000, 0x00000300);
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 void
ble_rf_calibrate_int(uint8_t mask)
{
__disable_irq();
ble_rf_enable();
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_disable();
__enable_irq();
#if MYNEWT_VAL(CMAC_DEBUG_DATA_ENABLE)
g_cmac_shm_debugdata.cal_res_1 = g_ble_phy_rf_data.cal_res_1;
g_cmac_shm_debugdata.cal_res_2 = g_ble_phy_rf_data.cal_res_2;
#endif
}
bool
ble_rf_try_recalibrate(uint32_t idle_time_us)
{
/* Run recalibration if we have at least 1ms of time to spare and RF is
* currently disabled. Calibration is much shorter than 1ms, but that gives
* us good margin to make sure we can finish before next event.
*/
if (!g_ble_phy_rf_data.calibrate_req || (idle_time_us < 1000) ||
ble_rf_is_enabled()) {
return false;
}
ble_rf_calibrate_int(RF_CALIBRATION_2);
g_ble_phy_rf_data.calibrate_req = 0;
return true;
}
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)
{
static bool done = false;
uint32_t val;
assert(mcu_chip_variant_get());
ble_rf_disable();
if (done) {
return;
}
val = ble_rf_find_trim_reg(g_cmac_shm_trim.rfcu_mode1,
g_cmac_shm_trim.rfcu_mode1_len,
0x4002004c);
g_ble_phy_rf_data.trim_val1_tx_1 = val;
val = ble_rf_find_trim_reg(g_cmac_shm_trim.rfcu_mode2,
g_cmac_shm_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_shm_trim.rfcu,
g_cmac_shm_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_shm_trim.synth,
g_cmac_shm_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_shm_debugdata.trim_val1_tx_1 = g_ble_phy_rf_data.trim_val1_tx_1;
g_cmac_shm_debugdata.trim_val1_tx_2 = g_ble_phy_rf_data.trim_val1_tx_2;
g_cmac_shm_debugdata.trim_val2_tx = g_ble_phy_rf_data.trim_val2_tx;
g_cmac_shm_debugdata.trim_val2_rx = g_ble_phy_rf_data.trim_val2_rx;
#endif
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);
done = true;
}
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;
}
void
ble_rf_calibrate_req(void)
{
g_ble_phy_rf_data.calibrate_req = 1;
}
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;
}