2022-10-23 23:45:43 -07:00

564 lines
21 KiB
C

//*****************************************************************************
//
// am_hal_mcuctrl.c
//! @file
//!
//! @brief Functions for interfacing with the MCUCTRL.
//!
//! @addtogroup mcuctrl3 MCU Control (MCUCTRL)
//! @ingroup apollo3hal
//! @{
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. 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.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// 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 HOLDER 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.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#include <stdint.h>
#include <stdbool.h>
#include "am_mcu_apollo.h"
//*****************************************************************************
//
// Global Variables.
//
//*****************************************************************************
//
// Define the flash sizes from CHIPPN.
//
const uint32_t
g_am_hal_mcuctrl_flash_size[AM_HAL_MCUCTRL_CHIPPN_FLASH_SIZE_N] =
{
16 * 1024, /* 0x0 0x00004000 16 KB */
32 * 1024, /* 0x1 0x00008000 32 KB */
64 * 1024, /* 0x2 0x00010000 64 KB */
128 * 1024, /* 0x3 0x00020000 128 KB */
256 * 1024, /* 0x4 0x00040000 256 KB */
512 * 1024, /* 0x5 0x00080000 512 KB */
1 * 1024 * 1024, /* 0x6 0x00100000 1 MB */
2 * 1024 * 1024, /* 0x7 0x00200000 2 MB */
3 * 1024 * 1024 / 2, /* 0x8 0x00600000 1.5 MB */
0, 0, 0, 0, 0, 0, 0
};
const uint32_t
g_am_hal_mcuctrl_sram_size[AM_HAL_MCUCTRL_CHIPPN_SRAM_SIZE_N] =
{
16 * 1024, /* 0x0 0x00004000 16 KB */
32 * 1024, /* 0x1 0x00008000 32 KB */
64 * 1024, /* 0x2 0x00010000 64 KB */
128 * 1024, /* 0x3 0x00020000 128 KB */
256 * 1024, /* 0x4 0x00040000 256 KB */
512 * 1024, /* 0x5 0x00080000 512 KB */
1 * 1024 * 1024, /* 0x6 0x00100000 1 MB */
384 * 1024, /* 0x7 0x00200000 384 KB */
768 * 1024, /* 0x8 0x000C0000 768 KB */
0, 0, 0, 0, 0, 0, 0
};
// ****************************************************************************
//
// device_info_get()
// Gets all relevant device information.
//
// ****************************************************************************
static void
device_info_get(am_hal_mcuctrl_device_t *psDevice)
{
//
// Read the Part Number.
//
psDevice->ui32ChipPN = MCUCTRL->CHIPPN;
//
// Read the Chip ID0.
//
psDevice->ui32ChipID0 = MCUCTRL->CHIPID0;
//
// Read the Chip ID1.
//
psDevice->ui32ChipID1 = MCUCTRL->CHIPID1;
//
// Read the Chip Revision.
//
psDevice->ui32ChipRev = MCUCTRL->CHIPREV;
//
// Read the Chip VENDOR ID.
//
psDevice->ui32VendorID = MCUCTRL->VENDORID;
//
// Read the SKU (new for Apollo3).
//
psDevice->ui32SKU = MCUCTRL->SKU;
//
// Qualified from Part Number.
//
psDevice->ui32Qualified = (psDevice->ui32ChipPN >> MCUCTRL_CHIPPN_PARTNUM_QUAL_S) & 0x1;
//
// Flash size from Part Number.
//
psDevice->ui32FlashSize =
g_am_hal_mcuctrl_flash_size[
(psDevice->ui32ChipPN & MCUCTRL_CHIPPN_PARTNUM_FLASHSIZE_M) >>
MCUCTRL_CHIPPN_PARTNUM_FLASHSIZE_S];
//
// SRAM size from Part Number.
//
psDevice->ui32SRAMSize =
g_am_hal_mcuctrl_sram_size[
(psDevice->ui32ChipPN & MCUCTRL_CHIPPN_PARTNUM_SRAMSIZE_M) >>
MCUCTRL_CHIPPN_PARTNUM_SRAMSIZE_S];
//
// Now, let's look at the JEDEC info.
// The full partnumber is 12 bits total, but is scattered across 2 registers.
// Bits [11:8] are 0xE.
// Bits [7:4] are 0xE for Apollo, 0xD for Apollo2, 0xC for Apollo3.
// Bits [3:0] are defined differently for Apollo and Apollo2/Apollo3.
// For Apollo, the low nibble is 0x0.
// For Apollo2/Apollo3, the low nibble indicates flash and SRAM size.
//
psDevice->ui32JedecPN = JEDEC->PID0_b.PNL8 << 0;
psDevice->ui32JedecPN |= JEDEC->PID1_b.PNH4 << 8;
//
// JEPID is the JEP-106 Manufacturer ID Code, which is assigned to Ambiq as
// 0x1B, with parity bit is 0x9B. It is 8 bits located across 2 registers.
//
psDevice->ui32JedecJEPID = JEDEC->PID1_b.JEPIDL << 0;
psDevice->ui32JedecJEPID |= JEDEC->PID2_b.JEPIDH << 4;
//
// CHIPREV is 8 bits located across 2 registers.
//
psDevice->ui32JedecCHIPREV = JEDEC->PID2_b.CHIPREVH4 << 4;
psDevice->ui32JedecCHIPREV |= JEDEC->PID3_b.CHIPREVL4 << 0;
//
// Let's get the Coresight ID (32-bits across 4 registers)
// For Apollo and Apollo2, it's expected to be 0xB105100D.
//
psDevice->ui32JedecCID = JEDEC->CID3_b.CID << 24;
psDevice->ui32JedecCID |= JEDEC->CID2_b.CID << 16;
psDevice->ui32JedecCID |= JEDEC->CID1_b.CID << 8;
psDevice->ui32JedecCID |= JEDEC->CID0_b.CID << 0;
} // device_info_get()
//*****************************************************************************
//
// mcuctrl_fault_status()
// Gets the fault status and capture registers.
//
//*****************************************************************************
static void
mcuctrl_fault_status(am_hal_mcuctrl_fault_t *psFault)
{
uint32_t ui32FaultStat;
//
// Read the Fault Status Register.
//
ui32FaultStat = MCUCTRL->FAULTSTATUS;
psFault->bICODE = (bool)(ui32FaultStat & MCUCTRL_FAULTSTATUS_ICODEFAULT_Msk);
psFault->bDCODE = (bool)(ui32FaultStat & MCUCTRL_FAULTSTATUS_DCODEFAULT_Msk);
psFault->bSYS = (bool)(ui32FaultStat & MCUCTRL_FAULTSTATUS_SYSFAULT_Msk);
//
// Read the DCODE fault capture address register.
//
psFault->ui32DCODE = MCUCTRL->DCODEFAULTADDR;
//
// Read the ICODE fault capture address register.
//
psFault->ui32ICODE |= MCUCTRL->ICODEFAULTADDR;
//
// Read the ICODE fault capture address register.
//
psFault->ui32SYS |= MCUCTRL->SYSFAULTADDR;
} // mcuctrl_fault_status()
// ****************************************************************************
//
// am_hal_mcuctrl_control()
// Apply various specific commands/controls on the MCUCTRL module.
//
// ****************************************************************************
uint32_t
am_hal_mcuctrl_control(am_hal_mcuctrl_control_e eControl, void *pArgs)
{
uint32_t ui32Tbl;
switch ( eControl )
{
case AM_HAL_MCUCTRL_CONTROL_FAULT_CAPTURE_ENABLE:
//
// Enable the Fault Capture registers.
//
MCUCTRL->FAULTCAPTUREEN_b.FAULTCAPTUREEN = 1;
break;
case AM_HAL_MCUCTRL_CONTROL_FAULT_CAPTURE_DISABLE:
//
// Disable the Fault Capture registers.
//
MCUCTRL->FAULTCAPTUREEN_b.FAULTCAPTUREEN = 0;
break;
case AM_HAL_MCUCTRL_CONTROL_EXTCLK32K_ENABLE:
//
// Configure the bits in XTALCTRL that enable external 32KHz clock.
//
MCUCTRL->XTALCTRL &=
~(MCUCTRL_XTALCTRL_PDNBCMPRXTAL_Msk |
MCUCTRL_XTALCTRL_PDNBCOREXTAL_Msk |
MCUCTRL_XTALCTRL_BYPCMPRXTAL_Msk |
MCUCTRL_XTALCTRL_FDBKDSBLXTAL_Msk |
MCUCTRL_XTALCTRL_XTALSWE_Msk);
MCUCTRL->XTALCTRL |=
_VAL2FLD(MCUCTRL_XTALCTRL_PDNBCMPRXTAL, MCUCTRL_XTALCTRL_PDNBCMPRXTAL_PWRDNCOMP) |
_VAL2FLD(MCUCTRL_XTALCTRL_PDNBCOREXTAL, MCUCTRL_XTALCTRL_PDNBCOREXTAL_PWRDNCORE) |
_VAL2FLD(MCUCTRL_XTALCTRL_BYPCMPRXTAL, MCUCTRL_XTALCTRL_BYPCMPRXTAL_BYPCOMP) |
_VAL2FLD(MCUCTRL_XTALCTRL_FDBKDSBLXTAL, MCUCTRL_XTALCTRL_FDBKDSBLXTAL_DIS) |
_VAL2FLD(MCUCTRL_XTALCTRL_XTALSWE, MCUCTRL_XTALCTRL_XTALSWE_OVERRIDE_EN);
break;
case AM_HAL_MCUCTRL_CONTROL_EXTCLK32K_DISABLE:
//
// Configure the bits in XTALCTRL that disable external 32KHz
// clock, thus re-configuring for the crystal.
//
MCUCTRL->XTALCTRL &=
~(MCUCTRL_XTALCTRL_PDNBCMPRXTAL_Msk |
MCUCTRL_XTALCTRL_PDNBCOREXTAL_Msk |
MCUCTRL_XTALCTRL_BYPCMPRXTAL_Msk |
MCUCTRL_XTALCTRL_FDBKDSBLXTAL_Msk |
MCUCTRL_XTALCTRL_XTALSWE_Msk);
MCUCTRL->XTALCTRL |=
_VAL2FLD(MCUCTRL_XTALCTRL_PDNBCMPRXTAL, MCUCTRL_XTALCTRL_PDNBCMPRXTAL_PWRUPCOMP) |
_VAL2FLD(MCUCTRL_XTALCTRL_PDNBCOREXTAL, MCUCTRL_XTALCTRL_PDNBCOREXTAL_PWRUPCORE) |
_VAL2FLD(MCUCTRL_XTALCTRL_BYPCMPRXTAL, MCUCTRL_XTALCTRL_BYPCMPRXTAL_USECOMP) |
_VAL2FLD(MCUCTRL_XTALCTRL_FDBKDSBLXTAL, MCUCTRL_XTALCTRL_FDBKDSBLXTAL_EN) |
_VAL2FLD(MCUCTRL_XTALCTRL_XTALSWE, MCUCTRL_XTALCTRL_XTALSWE_OVERRIDE_DIS);
break;
case AM_HAL_MCUCTRL_CONTROL_SRAM_PREFETCH:
{
uint32_t ui32SramPrefetch = *(uint32_t*)pArgs;
uint32_t ui32SetMsk, ui32ClrMsk, ui32SRAMreg;
//
// Validate the input flags.
//
if ( ui32SramPrefetch &
~(AM_HAL_MCUCTRL_SRAM_PREFETCH_INSTR |
AM_HAL_MCUCTRL_SRAM_PREFETCH_INSTRCACHE |
AM_HAL_MCUCTRL_SRAM_PREFETCH_DATA |
AM_HAL_MCUCTRL_SRAM_PREFETCH_DATACACHE |
AM_HAL_MCUCTRL_SRAM_NOPREFETCH_INSTR |
AM_HAL_MCUCTRL_SRAM_NOPREFETCH_INSTRCACHE |
AM_HAL_MCUCTRL_SRAM_NOPREFETCH_DATA |
AM_HAL_MCUCTRL_SRAM_NOPREFETCH_DATACACHE) )
{
return AM_HAL_STATUS_INVALID_ARG;
}
//
// Given the rule that NOxxx overrides xxx, and keeping in mind
// that the cache settings cannot be set unless the regular
// prefetch is also being set or is already set, the following
// truth table results.
// Note - this same TT also applies to data settings.
// nc=no change.
// I IC NI NIC: I IC
// 0x0: 0 0 0 0 : nc nc
// 0x1: 0 0 0 1 : nc 0
// 0x2: 0 0 1 0 : 0 0
// 0x3: 0 0 1 1 : 0 0
// 0x4: 0 1 0 0 : INVALID
// 0x5: 0 1 0 1 : nc nc
// 0x6: 0 1 1 0 : INVALID
// 0x7: 0 1 1 1 : 0 0
// 0x8: 1 0 0 0 : 1 0
// 0x9: 1 0 0 1 : 1 0
// 0xA: 1 0 1 0 : 0 0
// 0xB: 1 0 1 1 : 0 0
// 0xC: 1 1 0 0 : 1 1
// 0xD: 1 1 0 1 : 1 0
// 0xE: 1 1 1 0 : INVALID
// 0xF: 1 1 1 1 : 0 0
//
ui32Tbl = 0;
ui32Tbl |= (ui32SramPrefetch & AM_HAL_MCUCTRL_SRAM_PREFETCH_INSTR) ? (1 << 3) : 0;
ui32Tbl |= (ui32SramPrefetch & AM_HAL_MCUCTRL_SRAM_PREFETCH_INSTRCACHE) ? (1 << 2) : 0;
ui32Tbl |= (ui32SramPrefetch & AM_HAL_MCUCTRL_SRAM_NOPREFETCH_INSTR) ? (1 << 1) : 0;
ui32Tbl |= (ui32SramPrefetch & AM_HAL_MCUCTRL_SRAM_NOPREFETCH_INSTRCACHE) ? (1 << 0) : 0;
//
// Now augment the table entries with current register settings.
//
ui32SRAMreg = MCUCTRL->SRAMMODE;
ui32Tbl |= ui32SRAMreg & MCUCTRL_SRAMMODE_IPREFETCH_Msk ? (1 << 3) : 0;
ui32Tbl |= ui32SRAMreg & MCUCTRL_SRAMMODE_IPREFETCH_CACHE_Msk ? (1 << 2) : 0;
ui32SetMsk = ui32ClrMsk = 0;
switch ( ui32Tbl )
{
case 0x0:
case 0x5:
break;
case 0x1:
ui32ClrMsk = MCUCTRL_SRAMMODE_IPREFETCH_CACHE_Msk;
break;
case 0x2:
case 0x3:
case 0x7:
case 0xA:
case 0xB:
case 0xF:
ui32ClrMsk = MCUCTRL_SRAMMODE_IPREFETCH_Msk | MCUCTRL_SRAMMODE_IPREFETCH_CACHE_Msk;
break;
case 0x4:
case 0x6:
case 0xE:
return AM_HAL_STATUS_INVALID_OPERATION;
case 0x8:
case 0x9:
case 0xD:
ui32SetMsk = MCUCTRL_SRAMMODE_IPREFETCH_Msk;
ui32ClrMsk = MCUCTRL_SRAMMODE_IPREFETCH_CACHE_Msk;
break;
case 0xC:
ui32SetMsk = MCUCTRL_SRAMMODE_IPREFETCH_Msk | MCUCTRL_SRAMMODE_IPREFETCH_CACHE_Msk;
break;
default:
return AM_HAL_STATUS_INVALID_ARG;
} // switch()
//
// Now, repeat with data settings.
//
ui32Tbl = 0;
ui32Tbl |= (ui32SramPrefetch & AM_HAL_MCUCTRL_SRAM_PREFETCH_DATA) ? (1 << 3) : 0;
ui32Tbl |= (ui32SramPrefetch & AM_HAL_MCUCTRL_SRAM_PREFETCH_DATACACHE) ? (1 << 2) : 0;
ui32Tbl |= (ui32SramPrefetch & AM_HAL_MCUCTRL_SRAM_NOPREFETCH_DATA) ? (1 << 1) : 0;
ui32Tbl |= (ui32SramPrefetch & AM_HAL_MCUCTRL_SRAM_NOPREFETCH_DATACACHE) ? (1 << 0) : 0;
//
// Now augment the table entries with current register settings.
//
ui32Tbl |= ui32SRAMreg & MCUCTRL_SRAMMODE_DPREFETCH_Msk ? (1 << 3) : 0;
ui32Tbl |= ui32SRAMreg & MCUCTRL_SRAMMODE_DPREFETCH_CACHE_Msk ? (1 << 2) : 0;
switch ( ui32Tbl )
{
case 0x0:
case 0x5:
break;
case 0x1:
ui32ClrMsk = MCUCTRL_SRAMMODE_DPREFETCH_CACHE_Msk;
break;
case 0x2:
case 0x3:
case 0x7:
case 0xA:
case 0xB:
case 0xF:
ui32ClrMsk = MCUCTRL_SRAMMODE_DPREFETCH_Msk | MCUCTRL_SRAMMODE_DPREFETCH_CACHE_Msk;
break;
case 0x4:
case 0x6:
case 0xE:
return AM_HAL_STATUS_INVALID_OPERATION;
case 0x8:
case 0x9:
case 0xD:
ui32SetMsk = MCUCTRL_SRAMMODE_DPREFETCH_Msk;
ui32ClrMsk = MCUCTRL_SRAMMODE_DPREFETCH_CACHE_Msk;
break;
case 0xC:
ui32SetMsk = MCUCTRL_SRAMMODE_DPREFETCH_Msk | MCUCTRL_SRAMMODE_DPREFETCH_CACHE_Msk;
break;
default:
return AM_HAL_STATUS_INVALID_ARG;
} // switch()
//
// Arrange the register update such that clrmsk will have precedence
// over setmsk.
//
AM_CRITICAL_BEGIN
ui32SRAMreg = MCUCTRL->SRAMMODE;
ui32SRAMreg |= ui32SetMsk;
ui32SRAMreg &= ~ui32ClrMsk;
MCUCTRL->SRAMMODE = ui32SRAMreg;
AM_CRITICAL_END
} // case AM_HAL_MCUCTRL_CONTROL_SRAM_PREFETCH
break;
default:
return AM_HAL_STATUS_INVALID_ARG;
}
//
// Return success status.
//
return AM_HAL_STATUS_SUCCESS;
} // am_hal_mcuctrl_control()
// ****************************************************************************
//
// am_hal_mcuctrl_status_get()
//! This function returns current status of the MCUCTRL as obtained from
//! various registers of the MCUCTRL block.
//
// ****************************************************************************
uint32_t
am_hal_mcuctrl_status_get(am_hal_mcuctrl_status_t *psStatus)
{
uint32_t ui32Status;
if ( psStatus == NULL )
{
return AM_HAL_STATUS_INVALID_ARG;
}
ui32Status = MCUCTRL->FEATUREENABLE;
psStatus->bBurstAck =
_FLD2VAL(MCUCTRL_FEATUREENABLE_BURSTACK, ui32Status);
psStatus->bBLEAck =
_FLD2VAL(MCUCTRL_FEATUREENABLE_BLEACK, ui32Status);
psStatus->bDebuggerLockout =
_FLD2VAL(MCUCTRL_DEBUGGER_LOCKOUT, MCUCTRL->DEBUGGER);
psStatus->bADCcalibrated =
_FLD2VAL(MCUCTRL_ADCCAL_ADCCALIBRATED, MCUCTRL->ADCCAL);
psStatus->bBattLoadEnabled =
_FLD2VAL(MCUCTRL_ADCBATTLOAD_BATTLOAD, MCUCTRL->ADCBATTLOAD);
ui32Status = MCUCTRL->BOOTLOADER;
psStatus->bSecBootOnColdRst =
_FLD2VAL(MCUCTRL_BOOTLOADER_SECBOOT, ui32Status);
psStatus->bSecBootOnWarmRst =
_FLD2VAL(MCUCTRL_BOOTLOADER_SECBOOTONRST, ui32Status);
return AM_HAL_STATUS_SUCCESS;
} // am_hal_mcuctrl_status_get()
// ****************************************************************************
//
// am_hal_mcuctrl_info_get()
// Get information of the given MCUCTRL item.
//
// ****************************************************************************
uint32_t
am_hal_mcuctrl_info_get(am_hal_mcuctrl_infoget_e eInfoGet, void *pInfo)
{
am_hal_mcuctrl_feature_t *psFeature;
uint32_t ui32Feature;
if ( pInfo == NULL )
{
return AM_HAL_STATUS_INVALID_ARG;
}
switch ( eInfoGet )
{
case AM_HAL_MCUCTRL_INFO_FEATURES_AVAIL:
psFeature = (am_hal_mcuctrl_feature_t*)pInfo;
ui32Feature = MCUCTRL->FEATUREENABLE;
psFeature->bBurstAvail =
_FLD2VAL(MCUCTRL_FEATUREENABLE_BURSTAVAIL, ui32Feature);
psFeature->bBLEavail =
_FLD2VAL(MCUCTRL_FEATUREENABLE_BLEAVAIL, ui32Feature);
ui32Feature = MCUCTRL->BOOTLOADER;
psFeature->ui8SecBootFeature =
_FLD2VAL(MCUCTRL_BOOTLOADER_SECBOOTFEATURE, ui32Feature);
ui32Feature = MCUCTRL->SKU;
psFeature->bBLEFeature =
_FLD2VAL(MCUCTRL_SKU_ALLOWBLE, ui32Feature);
psFeature->bBurstFeature =
_FLD2VAL(MCUCTRL_SKU_ALLOWBURST, ui32Feature);
break;
case AM_HAL_MCUCTRL_INFO_DEVICEID:
device_info_get((am_hal_mcuctrl_device_t *)pInfo);
break;
case AM_HAL_MCUCTRL_INFO_FAULT_STATUS:
mcuctrl_fault_status((am_hal_mcuctrl_fault_t*)pInfo);
break;
default:
return AM_HAL_STATUS_INVALID_ARG;
}
//
// Return success status.
//
return AM_HAL_STATUS_SUCCESS;
} // am_hal_mcuctrl_info_get()
//*****************************************************************************
//
// End Doxygen group.
//! @}
//
//*****************************************************************************