From c50108113d06e7a66e7b5115c025ab90673c62fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Wed, 11 Jan 2023 14:42:09 +0100 Subject: [PATCH] soc: nrf53: Fix extraction of the XOSC32MTRIM.SLOPE bitfield MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The value in this bitfield is provided in the two's complement form, so it requires special handling. Previously, it was read as just an unsigned value and this could result in a wrongly computed CAPVALUE. Signed-off-by: Andrzej Głąbek --- soc/arm/nordic_nrf/nrf53/soc.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/soc/arm/nordic_nrf/nrf53/soc.c b/soc/arm/nordic_nrf/nrf53/soc.c index be318ca8fa4..f0c852e4efa 100644 --- a/soc/arm/nordic_nrf/nrf53/soc.c +++ b/soc/arm/nordic_nrf/nrf53/soc.c @@ -134,16 +134,27 @@ static int nordicsemi_nrf53_init(const struct device *arg) #if defined(CONFIG_SOC_HFXO_CAP_INTERNAL) /* This register is only accessible from secure code. */ uint32_t xosc32mtrim = soc_secure_read_xosc32mtrim(); + /* The SLOPE field is in the two's complement form, hence this special + * handling. Ideally, it would result in just one SBFX instruction for + * extracting the slope value, at least gcc is capable of producing such + * output, but since the compiler apparently tries first to optimize + * additions and subtractions, it generates slightly less than optimal + * code. + */ + uint32_t slope_field = (xosc32mtrim & FICR_XOSC32MTRIM_SLOPE_Msk) + >> FICR_XOSC32MTRIM_SLOPE_Pos; + uint32_t slope_mask = FICR_XOSC32MTRIM_SLOPE_Msk + >> FICR_XOSC32MTRIM_SLOPE_Pos; + uint32_t slope_sign = (slope_mask - (slope_mask >> 1)); + int32_t slope = (int32_t)(slope_field ^ slope_sign) - (int32_t)slope_sign; + uint32_t offset = (xosc32mtrim & FICR_XOSC32MTRIM_OFFSET_Msk) + >> FICR_XOSC32MTRIM_OFFSET_Pos; /* As specified in the nRF5340 PS: * CAPVALUE = (((FICR->XOSC32MTRIM.SLOPE+56)*(CAPACITANCE*2-14)) * +((FICR->XOSC32MTRIM.OFFSET-8)<<4)+32)>>6; * where CAPACITANCE is the desired capacitor value in pF, holding any * value between 7.0 pF and 20.0 pF in 0.5 pF steps. */ - uint32_t slope = (xosc32mtrim & FICR_XOSC32MTRIM_SLOPE_Msk) - >> FICR_XOSC32MTRIM_SLOPE_Pos; - uint32_t offset = (xosc32mtrim & FICR_XOSC32MTRIM_OFFSET_Msk) - >> FICR_XOSC32MTRIM_OFFSET_Pos; uint32_t capvalue = ((slope + 56) * (CONFIG_SOC_HFXO_CAP_INT_VALUE_X2 - 14) + ((offset - 8) << 4) + 32) >> 6;