2014-02-07 13:54:57 -06:00
/***************************************************************************
* Copyright ( C ) 2013 Synapse Product Development *
* Andrey Smirnov < andrew . smironv @ gmail . com > *
2014-06-27 01:13:24 -05:00
* Angus Gratton < gus @ projectgus . com > *
* Erdem U . Altunyurt < spamjunkeater @ gmail . com > *
2014-02-07 13:54:57 -06:00
* *
* This program is free software ; you can redistribute it and / or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation ; either version 2 of the License , or *
* ( at your option ) any later version . *
* *
* This program is distributed in the hope that it will be useful , *
* but WITHOUT ANY WARRANTY ; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the *
* GNU General Public License for more details . *
* *
* You should have received a copy of the GNU General Public License *
2016-05-16 15:41:00 -05:00
* along with this program . If not , see < http : //www.gnu.org/licenses/>. *
2014-02-07 13:54:57 -06:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# ifdef HAVE_CONFIG_H
# include "config.h"
# endif
# include "imp.h"
2014-06-27 01:13:24 -05:00
# include <target/algorithm.h>
# include <target/armv7m.h>
# include <helper/types.h>
2018-08-13 05:35:09 -05:00
# include <helper/time_support.h>
2014-02-07 13:54:57 -06:00
enum {
2017-08-31 14:09:42 -05:00
NRF5_FLASH_BASE = 0x00000000 ,
2014-02-07 13:54:57 -06:00
} ;
2017-08-31 14:09:42 -05:00
enum nrf5_ficr_registers {
NRF5_FICR_BASE = 0x10000000 , /* Factory Information Configuration Registers */
# define NRF5_FICR_REG(offset) (NRF5_FICR_BASE + offset)
NRF5_FICR_CODEPAGESIZE = NRF5_FICR_REG ( 0x010 ) ,
NRF5_FICR_CODESIZE = NRF5_FICR_REG ( 0x014 ) ,
NRF5_FICR_CLENR0 = NRF5_FICR_REG ( 0x028 ) ,
NRF5_FICR_PPFC = NRF5_FICR_REG ( 0x02C ) ,
NRF5_FICR_NUMRAMBLOCK = NRF5_FICR_REG ( 0x034 ) ,
NRF5_FICR_SIZERAMBLOCK0 = NRF5_FICR_REG ( 0x038 ) ,
NRF5_FICR_SIZERAMBLOCK1 = NRF5_FICR_REG ( 0x03C ) ,
NRF5_FICR_SIZERAMBLOCK2 = NRF5_FICR_REG ( 0x040 ) ,
NRF5_FICR_SIZERAMBLOCK3 = NRF5_FICR_REG ( 0x044 ) ,
NRF5_FICR_CONFIGID = NRF5_FICR_REG ( 0x05C ) ,
NRF5_FICR_DEVICEID0 = NRF5_FICR_REG ( 0x060 ) ,
NRF5_FICR_DEVICEID1 = NRF5_FICR_REG ( 0x064 ) ,
NRF5_FICR_ER0 = NRF5_FICR_REG ( 0x080 ) ,
NRF5_FICR_ER1 = NRF5_FICR_REG ( 0x084 ) ,
NRF5_FICR_ER2 = NRF5_FICR_REG ( 0x088 ) ,
NRF5_FICR_ER3 = NRF5_FICR_REG ( 0x08C ) ,
NRF5_FICR_IR0 = NRF5_FICR_REG ( 0x090 ) ,
NRF5_FICR_IR1 = NRF5_FICR_REG ( 0x094 ) ,
NRF5_FICR_IR2 = NRF5_FICR_REG ( 0x098 ) ,
NRF5_FICR_IR3 = NRF5_FICR_REG ( 0x09C ) ,
NRF5_FICR_DEVICEADDRTYPE = NRF5_FICR_REG ( 0x0A0 ) ,
NRF5_FICR_DEVICEADDR0 = NRF5_FICR_REG ( 0x0A4 ) ,
NRF5_FICR_DEVICEADDR1 = NRF5_FICR_REG ( 0x0A8 ) ,
NRF5_FICR_OVERRIDEN = NRF5_FICR_REG ( 0x0AC ) ,
NRF5_FICR_NRF_1MBIT0 = NRF5_FICR_REG ( 0x0B0 ) ,
NRF5_FICR_NRF_1MBIT1 = NRF5_FICR_REG ( 0x0B4 ) ,
NRF5_FICR_NRF_1MBIT2 = NRF5_FICR_REG ( 0x0B8 ) ,
NRF5_FICR_NRF_1MBIT3 = NRF5_FICR_REG ( 0x0BC ) ,
NRF5_FICR_NRF_1MBIT4 = NRF5_FICR_REG ( 0x0C0 ) ,
NRF5_FICR_BLE_1MBIT0 = NRF5_FICR_REG ( 0x0EC ) ,
NRF5_FICR_BLE_1MBIT1 = NRF5_FICR_REG ( 0x0F0 ) ,
NRF5_FICR_BLE_1MBIT2 = NRF5_FICR_REG ( 0x0F4 ) ,
NRF5_FICR_BLE_1MBIT3 = NRF5_FICR_REG ( 0x0F8 ) ,
NRF5_FICR_BLE_1MBIT4 = NRF5_FICR_REG ( 0x0FC ) ,
2014-02-07 13:54:57 -06:00
} ;
2017-08-31 14:09:42 -05:00
enum nrf5_uicr_registers {
NRF5_UICR_BASE = 0x10001000 , /* User Information
2014-02-07 13:54:57 -06:00
* Configuration Regsters */
2017-08-31 14:09:42 -05:00
NRF5_UICR_SIZE = 0x100 ,
2014-03-01 15:40:08 -06:00
2017-08-31 14:09:42 -05:00
# define NRF5_UICR_REG(offset) (NRF5_UICR_BASE + offset)
2014-02-07 13:54:57 -06:00
2017-08-31 14:09:42 -05:00
NRF5_UICR_CLENR0 = NRF5_UICR_REG ( 0x000 ) ,
NRF5_UICR_RBPCONF = NRF5_UICR_REG ( 0x004 ) ,
NRF5_UICR_XTALFREQ = NRF5_UICR_REG ( 0x008 ) ,
NRF5_UICR_FWID = NRF5_UICR_REG ( 0x010 ) ,
2014-02-07 13:54:57 -06:00
} ;
2017-08-31 14:09:42 -05:00
enum nrf5_nvmc_registers {
NRF5_NVMC_BASE = 0x4001E000 , /* Non-Volatile Memory
2014-02-07 13:54:57 -06:00
* Controller Regsters */
2017-08-31 14:09:42 -05:00
# define NRF5_NVMC_REG(offset) (NRF5_NVMC_BASE + offset)
2014-02-07 13:54:57 -06:00
2017-08-31 14:09:42 -05:00
NRF5_NVMC_READY = NRF5_NVMC_REG ( 0x400 ) ,
NRF5_NVMC_CONFIG = NRF5_NVMC_REG ( 0x504 ) ,
NRF5_NVMC_ERASEPAGE = NRF5_NVMC_REG ( 0x508 ) ,
NRF5_NVMC_ERASEALL = NRF5_NVMC_REG ( 0x50C ) ,
NRF5_NVMC_ERASEUICR = NRF5_NVMC_REG ( 0x514 ) ,
2014-02-07 13:54:57 -06:00
} ;
2017-08-31 14:09:42 -05:00
enum nrf5_nvmc_config_bits {
NRF5_NVMC_CONFIG_REN = 0x00 ,
NRF5_NVMC_CONFIG_WEN = 0x01 ,
NRF5_NVMC_CONFIG_EEN = 0x02 ,
2014-02-07 13:54:57 -06:00
} ;
2017-08-31 14:09:42 -05:00
struct nrf5_info {
2014-02-07 13:54:57 -06:00
uint32_t code_page_size ;
2018-07-20 10:14:34 -05:00
uint32_t refcount ;
2014-02-07 13:54:57 -06:00
2018-11-21 07:09:39 -06:00
struct nrf5_bank {
struct nrf5_info * chip ;
2014-03-01 15:40:08 -06:00
bool probed ;
int ( * write ) ( struct flash_bank * bank ,
2017-08-31 14:09:42 -05:00
struct nrf5_info * chip ,
2014-03-01 15:40:08 -06:00
const uint8_t * buffer , uint32_t offset , uint32_t count ) ;
} bank [ 2 ] ;
2014-02-07 13:54:57 -06:00
struct target * target ;
} ;
2017-08-31 14:09:42 -05:00
struct nrf5_device_spec {
2014-02-28 13:35:16 -06:00
uint16_t hwid ;
2016-09-09 06:22:59 -05:00
const char * part ;
2014-02-28 13:35:16 -06:00
const char * variant ;
const char * build_code ;
unsigned int flash_size_kb ;
} ;
2017-08-31 14:09:42 -05:00
# define NRF5_DEVICE_DEF(id, pt, var, bcode, fsize) \
2017-08-31 13:53:57 -05:00
{ \
. hwid = ( id ) , \
. part = pt , \
. variant = var , \
. build_code = bcode , \
. flash_size_kb = ( fsize ) , \
}
2019-01-11 07:40:55 -06:00
/* The known devices table below is derived from the "nRF5x series
* compatibility matrix " documents, which can be found in the " DocLib " of
* nordic :
2015-03-10 08:44:28 -05:00
*
2019-01-11 07:40:55 -06:00
* https : //www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF51/latest/COMP/nrf51/nRF51422_ic_revision_overview
* https : //www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF51/latest/COMP/nrf51/nRF51822_ic_revision_overview
* https : //www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF51/latest/COMP/nrf51/nRF51824_ic_revision_overview
* https : //www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF52810/latest/COMP/nrf52810/nRF52810_ic_revision_overview
* https : //www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF52832/latest/COMP/nrf52832/ic_revision_overview
* https : //www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF52840/latest/COMP/nrf52840/nRF52840_ic_revision_overview
2015-03-10 08:44:28 -05:00
*
* Up to date with Matrix v2 .0 , plus some additional HWIDs .
*
* The additional HWIDs apply where the build code in the matrix is
* shown as Gx0 , Bx0 , etc . In these cases the HWID in the matrix is
* for x = = 0 , x ! = 0 means different ( unspecified ) HWIDs .
*/
2017-08-31 14:09:42 -05:00
static const struct nrf5_device_spec nrf5_known_devices_table [ ] = {
2015-01-28 18:23:16 -06:00
/* nRF51822 Devices (IC rev 1). */
2017-08-31 14:09:42 -05:00
NRF5_DEVICE_DEF ( 0x001D , " 51822 " , " QFAA " , " CA/C0 " , 256 ) ,
NRF5_DEVICE_DEF ( 0x0026 , " 51822 " , " QFAB " , " AA " , 128 ) ,
NRF5_DEVICE_DEF ( 0x0027 , " 51822 " , " QFAB " , " A0 " , 128 ) ,
NRF5_DEVICE_DEF ( 0x0020 , " 51822 " , " CEAA " , " BA " , 256 ) ,
NRF5_DEVICE_DEF ( 0x002F , " 51822 " , " CEAA " , " B0 " , 256 ) ,
2015-01-28 18:23:16 -06:00
2018-02-27 10:51:49 -06:00
/* Some early nRF51-DK (PCA10028) & nRF51-Dongle (PCA10031) boards
with built - in jlink seem to use engineering samples not listed
in the nRF51 Series Compatibility Matrix V1 .0 . */
NRF5_DEVICE_DEF ( 0x0071 , " 51822 " , " QFAC " , " AB " , 256 ) ,
2015-01-28 18:23:16 -06:00
/* nRF51822 Devices (IC rev 2). */
2017-08-31 14:09:42 -05:00
NRF5_DEVICE_DEF ( 0x002A , " 51822 " , " QFAA " , " FA0 " , 256 ) ,
NRF5_DEVICE_DEF ( 0x0044 , " 51822 " , " QFAA " , " GC0 " , 256 ) ,
NRF5_DEVICE_DEF ( 0x003C , " 51822 " , " QFAA " , " G0 " , 256 ) ,
NRF5_DEVICE_DEF ( 0x0057 , " 51822 " , " QFAA " , " G2 " , 256 ) ,
NRF5_DEVICE_DEF ( 0x0058 , " 51822 " , " QFAA " , " G3 " , 256 ) ,
NRF5_DEVICE_DEF ( 0x004C , " 51822 " , " QFAB " , " B0 " , 128 ) ,
NRF5_DEVICE_DEF ( 0x0040 , " 51822 " , " CEAA " , " CA0 " , 256 ) ,
NRF5_DEVICE_DEF ( 0x0047 , " 51822 " , " CEAA " , " DA0 " , 256 ) ,
NRF5_DEVICE_DEF ( 0x004D , " 51822 " , " CEAA " , " D00 " , 256 ) ,
2015-01-28 18:23:16 -06:00
/* nRF51822 Devices (IC rev 3). */
2017-08-31 14:09:42 -05:00
NRF5_DEVICE_DEF ( 0x0072 , " 51822 " , " QFAA " , " H0 " , 256 ) ,
2018-01-13 09:37:19 -06:00
NRF5_DEVICE_DEF ( 0x00D1 , " 51822 " , " QFAA " , " H2 " , 256 ) ,
2017-08-31 14:09:42 -05:00
NRF5_DEVICE_DEF ( 0x007B , " 51822 " , " QFAB " , " C0 " , 128 ) ,
NRF5_DEVICE_DEF ( 0x0083 , " 51822 " , " QFAC " , " A0 " , 256 ) ,
NRF5_DEVICE_DEF ( 0x0084 , " 51822 " , " QFAC " , " A1 " , 256 ) ,
NRF5_DEVICE_DEF ( 0x007D , " 51822 " , " CDAB " , " A0 " , 128 ) ,
NRF5_DEVICE_DEF ( 0x0079 , " 51822 " , " CEAA " , " E0 " , 256 ) ,
NRF5_DEVICE_DEF ( 0x0087 , " 51822 " , " CFAC " , " A0 " , 256 ) ,
2018-02-27 10:51:49 -06:00
NRF5_DEVICE_DEF ( 0x008F , " 51822 " , " QFAA " , " H1 " , 256 ) ,
2015-01-28 18:23:16 -06:00
/* nRF51422 Devices (IC rev 1). */
2017-08-31 14:09:42 -05:00
NRF5_DEVICE_DEF ( 0x001E , " 51422 " , " QFAA " , " CA " , 256 ) ,
NRF5_DEVICE_DEF ( 0x0024 , " 51422 " , " QFAA " , " C0 " , 256 ) ,
NRF5_DEVICE_DEF ( 0x0031 , " 51422 " , " CEAA " , " A0A " , 256 ) ,
2014-02-28 13:35:16 -06:00
2015-01-28 18:23:16 -06:00
/* nRF51422 Devices (IC rev 2). */
2017-08-31 14:09:42 -05:00
NRF5_DEVICE_DEF ( 0x002D , " 51422 " , " QFAA " , " DAA " , 256 ) ,
NRF5_DEVICE_DEF ( 0x002E , " 51422 " , " QFAA " , " E0 " , 256 ) ,
NRF5_DEVICE_DEF ( 0x0061 , " 51422 " , " QFAB " , " A00 " , 128 ) ,
NRF5_DEVICE_DEF ( 0x0050 , " 51422 " , " CEAA " , " B0 " , 256 ) ,
2015-01-28 18:23:16 -06:00
/* nRF51422 Devices (IC rev 3). */
2017-08-31 14:09:42 -05:00
NRF5_DEVICE_DEF ( 0x0073 , " 51422 " , " QFAA " , " F0 " , 256 ) ,
NRF5_DEVICE_DEF ( 0x007C , " 51422 " , " QFAB " , " B0 " , 128 ) ,
NRF5_DEVICE_DEF ( 0x0085 , " 51422 " , " QFAC " , " A0 " , 256 ) ,
NRF5_DEVICE_DEF ( 0x0086 , " 51422 " , " QFAC " , " A1 " , 256 ) ,
NRF5_DEVICE_DEF ( 0x007E , " 51422 " , " CDAB " , " A0 " , 128 ) ,
NRF5_DEVICE_DEF ( 0x007A , " 51422 " , " CEAA " , " C0 " , 256 ) ,
NRF5_DEVICE_DEF ( 0x0088 , " 51422 " , " CFAC " , " A0 " , 256 ) ,
2014-02-28 13:35:16 -06:00
2018-09-25 14:18:53 -05:00
/* nRF52810 Devices */
NRF5_DEVICE_DEF ( 0x0142 , " 52810 " , " QFAA " , " B0 " , 192 ) ,
NRF5_DEVICE_DEF ( 0x0143 , " 52810 " , " QCAA " , " C0 " , 192 ) ,
2017-08-31 15:34:16 -05:00
/* nRF52832 Devices */
NRF5_DEVICE_DEF ( 0x00C7 , " 52832 " , " QFAA " , " B0 " , 512 ) ,
2018-07-16 03:27:03 -05:00
NRF5_DEVICE_DEF ( 0x0139 , " 52832 " , " QFAA " , " E0 " , 512 ) ,
2019-01-11 07:48:58 -06:00
NRF5_DEVICE_DEF ( 0x00E3 , " 52832 " , " CIAA " , " B0 " , 512 ) ,
2018-08-13 05:35:47 -05:00
/* nRF52840 Devices */
NRF5_DEVICE_DEF ( 0x0150 , " 52840 " , " QIAA " , " C0 " , 1024 ) ,
2014-02-28 13:35:16 -06:00
} ;
2017-08-31 14:09:42 -05:00
static int nrf5_bank_is_probed ( struct flash_bank * bank )
2014-03-01 15:40:08 -06:00
{
2018-11-21 07:09:39 -06:00
struct nrf5_bank * nbank = bank - > driver_priv ;
2014-03-01 15:40:08 -06:00
2018-11-21 07:09:39 -06:00
assert ( nbank ! = NULL ) ;
2014-03-01 15:40:08 -06:00
2018-11-21 07:09:39 -06:00
return nbank - > probed ;
2014-03-01 15:40:08 -06:00
}
2017-08-31 14:09:42 -05:00
static int nrf5_probe ( struct flash_bank * bank ) ;
2014-02-07 13:54:57 -06:00
2017-08-31 14:09:42 -05:00
static int nrf5_get_probed_chip_if_halted ( struct flash_bank * bank , struct nrf5_info * * chip )
2014-02-07 13:54:57 -06:00
{
if ( bank - > target - > state ! = TARGET_HALTED ) {
LOG_ERROR ( " Target not halted " ) ;
return ERROR_TARGET_NOT_HALTED ;
}
2018-11-21 07:09:39 -06:00
struct nrf5_bank * nbank = bank - > driver_priv ;
* chip = nbank - > chip ;
2014-02-07 13:54:57 -06:00
2017-08-31 14:09:42 -05:00
int probed = nrf5_bank_is_probed ( bank ) ;
2014-03-01 15:40:08 -06:00
if ( probed < 0 )
return probed ;
else if ( ! probed )
2017-08-31 14:09:42 -05:00
return nrf5_probe ( bank ) ;
2014-03-01 15:40:08 -06:00
else
return ERROR_OK ;
2014-02-07 13:54:57 -06:00
}
2017-08-31 14:09:42 -05:00
static int nrf5_wait_for_nvmc ( struct nrf5_info * chip )
2014-02-07 13:54:57 -06:00
{
uint32_t ready ;
int res ;
2018-12-26 07:09:10 -06:00
int timeout_ms = 340 ;
2018-08-13 05:35:09 -05:00
int64_t ts_start = timeval_ms ( ) ;
2014-02-07 13:54:57 -06:00
do {
2017-08-31 14:09:42 -05:00
res = target_read_u32 ( chip - > target , NRF5_NVMC_READY , & ready ) ;
2014-02-07 13:54:57 -06:00
if ( res ! = ERROR_OK ) {
LOG_ERROR ( " Couldn't read NVMC_READY register " ) ;
return res ;
}
if ( ready = = 0x00000001 )
return ERROR_OK ;
2018-08-13 05:35:09 -05:00
keep_alive ( ) ;
} while ( ( timeval_ms ( ) - ts_start ) < timeout_ms ) ;
2014-02-07 13:54:57 -06:00
2014-06-27 01:13:24 -05:00
LOG_DEBUG ( " Timed out waiting for NVMC_READY " ) ;
2014-02-07 13:54:57 -06:00
return ERROR_FLASH_BUSY ;
}
2017-08-31 14:09:42 -05:00
static int nrf5_nvmc_erase_enable ( struct nrf5_info * chip )
2014-02-07 13:54:57 -06:00
{
int res ;
res = target_write_u32 ( chip - > target ,
2017-08-31 14:09:42 -05:00
NRF5_NVMC_CONFIG ,
NRF5_NVMC_CONFIG_EEN ) ;
2014-02-07 13:54:57 -06:00
if ( res ! = ERROR_OK ) {
LOG_ERROR ( " Failed to enable erase operation " ) ;
return res ;
}
/*
According to NVMC examples in Nordic SDK busy status must be
checked after writing to NVMC_CONFIG
*/
2017-08-31 14:09:42 -05:00
res = nrf5_wait_for_nvmc ( chip ) ;
2014-02-07 13:54:57 -06:00
if ( res ! = ERROR_OK )
LOG_ERROR ( " Erase enable did not complete " ) ;
return res ;
}
2017-08-31 14:09:42 -05:00
static int nrf5_nvmc_write_enable ( struct nrf5_info * chip )
2014-02-07 13:54:57 -06:00
{
int res ;
res = target_write_u32 ( chip - > target ,
2017-08-31 14:09:42 -05:00
NRF5_NVMC_CONFIG ,
NRF5_NVMC_CONFIG_WEN ) ;
2014-02-07 13:54:57 -06:00
if ( res ! = ERROR_OK ) {
LOG_ERROR ( " Failed to enable write operation " ) ;
return res ;
}
/*
According to NVMC examples in Nordic SDK busy status must be
checked after writing to NVMC_CONFIG
*/
2017-08-31 14:09:42 -05:00
res = nrf5_wait_for_nvmc ( chip ) ;
2014-02-07 13:54:57 -06:00
if ( res ! = ERROR_OK )
LOG_ERROR ( " Write enable did not complete " ) ;
return res ;
}
2017-08-31 14:09:42 -05:00
static int nrf5_nvmc_read_only ( struct nrf5_info * chip )
2014-02-07 13:54:57 -06:00
{
int res ;
res = target_write_u32 ( chip - > target ,
2017-08-31 14:09:42 -05:00
NRF5_NVMC_CONFIG ,
NRF5_NVMC_CONFIG_REN ) ;
2014-02-07 13:54:57 -06:00
if ( res ! = ERROR_OK ) {
LOG_ERROR ( " Failed to enable read-only operation " ) ;
return res ;
}
/*
According to NVMC examples in Nordic SDK busy status must be
checked after writing to NVMC_CONFIG
*/
2017-08-31 14:09:42 -05:00
res = nrf5_wait_for_nvmc ( chip ) ;
2014-02-07 13:54:57 -06:00
if ( res ! = ERROR_OK )
LOG_ERROR ( " Read only enable did not complete " ) ;
return res ;
}
2017-08-31 14:09:42 -05:00
static int nrf5_nvmc_generic_erase ( struct nrf5_info * chip ,
2014-02-07 13:54:57 -06:00
uint32_t erase_register , uint32_t erase_value )
{
int res ;
2017-08-31 14:09:42 -05:00
res = nrf5_nvmc_erase_enable ( chip ) ;
2014-02-07 13:54:57 -06:00
if ( res ! = ERROR_OK )
goto error ;
res = target_write_u32 ( chip - > target ,
erase_register ,
erase_value ) ;
if ( res ! = ERROR_OK )
goto set_read_only ;
2017-08-31 14:09:42 -05:00
res = nrf5_wait_for_nvmc ( chip ) ;
2014-02-07 13:54:57 -06:00
if ( res ! = ERROR_OK )
goto set_read_only ;
2017-08-31 14:09:42 -05:00
return nrf5_nvmc_read_only ( chip ) ;
2014-02-07 13:54:57 -06:00
set_read_only :
2017-08-31 14:09:42 -05:00
nrf5_nvmc_read_only ( chip ) ;
2014-02-07 13:54:57 -06:00
error :
LOG_ERROR ( " Failed to erase reg: 0x%08 " PRIx32 " val: 0x%08 " PRIx32 ,
erase_register , erase_value ) ;
return ERROR_FAIL ;
}
2017-08-31 14:09:42 -05:00
static int nrf5_protect_check ( struct flash_bank * bank )
2014-02-07 13:54:57 -06:00
{
int res ;
uint32_t clenr0 ;
2014-03-01 15:40:08 -06:00
/* UICR cannot be write protected so just return early */
2017-08-31 14:09:42 -05:00
if ( bank - > base = = NRF5_UICR_BASE )
2014-03-01 15:40:08 -06:00
return ERROR_OK ;
2018-11-21 07:09:39 -06:00
struct nrf5_bank * nbank = bank - > driver_priv ;
struct nrf5_info * chip = nbank - > chip ;
2014-02-07 13:54:57 -06:00
assert ( chip ! = NULL ) ;
2017-08-31 14:09:42 -05:00
res = target_read_u32 ( chip - > target , NRF5_FICR_CLENR0 ,
2014-02-07 13:54:57 -06:00
& clenr0 ) ;
if ( res ! = ERROR_OK ) {
LOG_ERROR ( " Couldn't read code region 0 size[FICR] " ) ;
return res ;
}
if ( clenr0 = = 0xFFFFFFFF ) {
2017-08-31 14:09:42 -05:00
res = target_read_u32 ( chip - > target , NRF5_UICR_CLENR0 ,
2014-02-07 13:54:57 -06:00
& clenr0 ) ;
if ( res ! = ERROR_OK ) {
LOG_ERROR ( " Couldn't read code region 0 size[UICR] " ) ;
return res ;
}
}
for ( int i = 0 ; i < bank - > num_sectors ; i + + )
bank - > sectors [ i ] . is_protected =
clenr0 ! = 0xFFFFFFFF & & bank - > sectors [ i ] . offset < clenr0 ;
return ERROR_OK ;
}
2017-08-31 14:09:42 -05:00
static int nrf5_protect ( struct flash_bank * bank , int set , int first , int last )
2014-02-07 13:54:57 -06:00
{
int res ;
uint32_t clenr0 , ppfc ;
2017-08-31 14:09:42 -05:00
struct nrf5_info * chip ;
2014-02-07 13:54:57 -06:00
2014-03-01 15:40:08 -06:00
/* UICR cannot be write protected so just bail out early */
2017-08-31 14:09:42 -05:00
if ( bank - > base = = NRF5_UICR_BASE )
2014-03-01 15:40:08 -06:00
return ERROR_FAIL ;
2017-08-31 14:09:42 -05:00
res = nrf5_get_probed_chip_if_halted ( bank , & chip ) ;
2014-02-07 13:54:57 -06:00
if ( res ! = ERROR_OK )
return res ;
if ( first ! = 0 ) {
LOG_ERROR ( " Code region 0 must start at the begining of the bank " ) ;
return ERROR_FAIL ;
}
2017-08-31 14:09:42 -05:00
res = target_read_u32 ( chip - > target , NRF5_FICR_PPFC ,
2014-02-07 13:54:57 -06:00
& ppfc ) ;
if ( res ! = ERROR_OK ) {
LOG_ERROR ( " Couldn't read PPFC register " ) ;
return res ;
}
if ( ( ppfc & 0xFF ) = = 0x00 ) {
LOG_ERROR ( " Code region 0 size was pre-programmed at the factory, can't change flash protection settings " ) ;
return ERROR_FAIL ;
2016-02-28 14:21:40 -06:00
}
2014-02-07 13:54:57 -06:00
2017-08-31 14:09:42 -05:00
res = target_read_u32 ( chip - > target , NRF5_UICR_CLENR0 ,
2014-02-07 13:54:57 -06:00
& clenr0 ) ;
if ( res ! = ERROR_OK ) {
LOG_ERROR ( " Couldn't read code region 0 size[UICR] " ) ;
return res ;
}
if ( clenr0 = = 0xFFFFFFFF ) {
2017-08-31 14:09:42 -05:00
res = target_write_u32 ( chip - > target , NRF5_UICR_CLENR0 ,
2014-02-07 13:54:57 -06:00
clenr0 ) ;
if ( res ! = ERROR_OK ) {
LOG_ERROR ( " Couldn't write code region 0 size[UICR] " ) ;
return res ;
}
} else {
LOG_ERROR ( " You need to perform chip erase before changing the protection settings " ) ;
}
2017-08-31 14:09:42 -05:00
nrf5_protect_check ( bank ) ;
2014-02-07 13:54:57 -06:00
return ERROR_OK ;
}
2017-08-31 14:09:42 -05:00
static int nrf5_probe ( struct flash_bank * bank )
2014-02-07 13:54:57 -06:00
{
2014-02-28 13:35:16 -06:00
uint32_t hwid ;
2014-02-07 13:54:57 -06:00
int res ;
2018-11-21 07:09:39 -06:00
struct nrf5_bank * nbank = bank - > driver_priv ;
struct nrf5_info * chip = nbank - > chip ;
2014-02-07 13:54:57 -06:00
2017-08-31 14:09:42 -05:00
res = target_read_u32 ( chip - > target , NRF5_FICR_CONFIGID , & hwid ) ;
2014-02-07 13:54:57 -06:00
if ( res ! = ERROR_OK ) {
2014-02-28 13:35:16 -06:00
LOG_ERROR ( " Couldn't read CONFIGID register " ) ;
2014-02-07 13:54:57 -06:00
return res ;
}
2014-02-28 13:35:16 -06:00
hwid & = 0xFFFF ; /* HWID is stored in the lower two
* bytes of the CONFIGID register */
2017-08-31 14:09:42 -05:00
const struct nrf5_device_spec * spec = NULL ;
for ( size_t i = 0 ; i < ARRAY_SIZE ( nrf5_known_devices_table ) ; i + + ) {
if ( hwid = = nrf5_known_devices_table [ i ] . hwid ) {
spec = & nrf5_known_devices_table [ i ] ;
2014-02-28 13:35:16 -06:00
break ;
}
2016-09-09 06:22:59 -05:00
}
2014-02-28 13:35:16 -06:00
2014-03-01 15:40:08 -06:00
if ( ! chip - > bank [ 0 ] . probed & & ! chip - > bank [ 1 ] . probed ) {
if ( spec )
2016-09-09 06:22:59 -05:00
LOG_INFO ( " nRF%s-%s(build code: %s) %ukB Flash " ,
spec - > part , spec - > variant , spec - > build_code ,
spec - > flash_size_kb ) ;
2014-03-01 15:40:08 -06:00
else
LOG_WARNING ( " Unknown device (HWID 0x%08 " PRIx32 " ) " , hwid ) ;
2014-02-07 13:54:57 -06:00
}
2017-08-31 14:09:42 -05:00
if ( bank - > base = = NRF5_FLASH_BASE ) {
/* The value stored in NRF5_FICR_CODEPAGESIZE is the number of bytes in one page of FLASH. */
res = target_read_u32 ( chip - > target , NRF5_FICR_CODEPAGESIZE ,
2016-05-30 03:54:47 -05:00
& chip - > code_page_size ) ;
2014-03-01 15:40:08 -06:00
if ( res ! = ERROR_OK ) {
LOG_ERROR ( " Couldn't read code page size " ) ;
return res ;
}
2014-02-07 13:54:57 -06:00
2016-05-30 03:54:47 -05:00
/* Note the register name is misleading,
2017-08-31 14:09:42 -05:00
* NRF5_FICR_CODESIZE is the number of pages in flash memory , not the number of bytes ! */
2016-12-29 05:19:11 -06:00
uint32_t num_sectors ;
2017-08-31 14:09:42 -05:00
res = target_read_u32 ( chip - > target , NRF5_FICR_CODESIZE , & num_sectors ) ;
2014-03-01 15:40:08 -06:00
if ( res ! = ERROR_OK ) {
LOG_ERROR ( " Couldn't read code memory size " ) ;
return res ;
}
2014-02-28 13:35:16 -06:00
2016-12-29 05:19:11 -06:00
bank - > num_sectors = num_sectors ;
bank - > size = num_sectors * chip - > code_page_size ;
2016-05-30 03:54:47 -05:00
if ( spec & & bank - > size / 1024 ! = spec - > flash_size_kb )
LOG_WARNING ( " Chip's reported Flash capacity does not match expected one " ) ;
2014-02-07 13:54:57 -06:00
2014-03-01 15:40:08 -06:00
bank - > sectors = calloc ( bank - > num_sectors ,
sizeof ( ( bank - > sectors ) [ 0 ] ) ) ;
if ( ! bank - > sectors )
return ERROR_FLASH_BANK_NOT_PROBED ;
2017-08-31 14:09:42 -05:00
/* Fill out the sector information: all NRF5 sectors are the same size and
2014-03-01 15:40:08 -06:00
* there is always a fixed number of them . */
for ( int i = 0 ; i < bank - > num_sectors ; i + + ) {
bank - > sectors [ i ] . size = chip - > code_page_size ;
bank - > sectors [ i ] . offset = i * chip - > code_page_size ;
/* mark as unknown */
bank - > sectors [ i ] . is_erased = - 1 ;
bank - > sectors [ i ] . is_protected = - 1 ;
}
2014-02-07 13:54:57 -06:00
2017-08-31 14:09:42 -05:00
nrf5_protect_check ( bank ) ;
2014-02-07 13:54:57 -06:00
2014-03-01 15:40:08 -06:00
chip - > bank [ 0 ] . probed = true ;
} else {
2017-08-31 14:09:42 -05:00
bank - > size = NRF5_UICR_SIZE ;
2014-03-01 15:40:08 -06:00
bank - > num_sectors = 1 ;
bank - > sectors = calloc ( bank - > num_sectors ,
sizeof ( ( bank - > sectors ) [ 0 ] ) ) ;
if ( ! bank - > sectors )
return ERROR_FLASH_BANK_NOT_PROBED ;
bank - > sectors [ 0 ] . size = bank - > size ;
bank - > sectors [ 0 ] . offset = 0 ;
2014-02-07 13:54:57 -06:00
2014-03-01 15:40:08 -06:00
bank - > sectors [ 0 ] . is_erased = 0 ;
bank - > sectors [ 0 ] . is_protected = 0 ;
chip - > bank [ 1 ] . probed = true ;
}
2014-02-07 13:54:57 -06:00
return ERROR_OK ;
}
2017-08-31 14:09:42 -05:00
static int nrf5_auto_probe ( struct flash_bank * bank )
2014-02-07 13:54:57 -06:00
{
2017-08-31 14:09:42 -05:00
int probed = nrf5_bank_is_probed ( bank ) ;
2014-02-07 13:54:57 -06:00
2014-03-01 15:40:08 -06:00
if ( probed < 0 )
return probed ;
else if ( probed )
2014-02-07 13:54:57 -06:00
return ERROR_OK ;
2014-03-01 15:40:08 -06:00
else
2017-08-31 14:09:42 -05:00
return nrf5_probe ( bank ) ;
2014-02-07 13:54:57 -06:00
}
2017-08-31 14:09:42 -05:00
static int nrf5_erase_all ( struct nrf5_info * chip )
2014-02-07 13:54:57 -06:00
{
2014-06-27 01:13:24 -05:00
LOG_DEBUG ( " Erasing all non-volatile memory " ) ;
2017-08-31 14:09:42 -05:00
return nrf5_nvmc_generic_erase ( chip ,
NRF5_NVMC_ERASEALL ,
2014-02-07 13:54:57 -06:00
0x00000001 ) ;
}
2017-08-31 14:09:42 -05:00
static int nrf5_erase_page ( struct flash_bank * bank ,
struct nrf5_info * chip ,
2014-10-28 22:15:31 -05:00
struct flash_sector * sector )
2014-02-07 13:54:57 -06:00
{
int res ;
2014-06-27 01:13:24 -05:00
LOG_DEBUG ( " Erasing page at 0x% " PRIx32 , sector - > offset ) ;
if ( sector - > is_protected ) {
2015-03-15 02:18:55 -05:00
LOG_ERROR ( " Cannot erase protected sector at 0x% " PRIx32 , sector - > offset ) ;
2014-02-07 13:54:57 -06:00
return ERROR_FAIL ;
2014-06-27 01:13:24 -05:00
}
2014-02-07 13:54:57 -06:00
2017-08-31 14:09:42 -05:00
if ( bank - > base = = NRF5_UICR_BASE ) {
2014-03-01 15:40:08 -06:00
uint32_t ppfc ;
2017-08-31 14:09:42 -05:00
res = target_read_u32 ( chip - > target , NRF5_FICR_PPFC ,
2014-03-01 15:40:08 -06:00
& ppfc ) ;
if ( res ! = ERROR_OK ) {
LOG_ERROR ( " Couldn't read PPFC register " ) ;
return res ;
}
if ( ( ppfc & 0xFF ) = = 0xFF ) {
2014-10-29 18:00:52 -05:00
/* We can't erase the UICR. Double-check to
see if it ' s already erased before complaining . */
default_flash_blank_check ( bank ) ;
if ( sector - > is_erased = = 1 )
return ERROR_OK ;
2014-03-01 15:40:08 -06:00
LOG_ERROR ( " The chip was not pre-programmed with SoftDevice stack and UICR cannot be erased separately. Please issue mass erase before trying to write to this region " ) ;
return ERROR_FAIL ;
2016-02-28 14:21:40 -06:00
}
2014-03-01 15:40:08 -06:00
2017-08-31 14:09:42 -05:00
res = nrf5_nvmc_generic_erase ( chip ,
NRF5_NVMC_ERASEUICR ,
2014-03-01 15:40:08 -06:00
0x00000001 ) ;
} else {
2017-08-31 14:09:42 -05:00
res = nrf5_nvmc_generic_erase ( chip ,
NRF5_NVMC_ERASEPAGE ,
2014-03-01 15:40:08 -06:00
sector - > offset ) ;
}
2014-02-07 13:54:57 -06:00
return res ;
}
2017-08-31 14:09:42 -05:00
static const uint8_t nrf5_flash_write_code [ ] = {
2014-06-27 01:13:24 -05:00
/* See contrib/loaders/flash/cortex-m0.S */
/* <wait_fifo>: */
0x0d , 0x68 , /* ldr r5, [r1, #0] */
0x00 , 0x2d , /* cmp r5, #0 */
0x0b , 0xd0 , /* beq.n 1e <exit> */
0x4c , 0x68 , /* ldr r4, [r1, #4] */
0xac , 0x42 , /* cmp r4, r5 */
0xf9 , 0xd0 , /* beq.n 0 <wait_fifo> */
0x20 , 0xcc , /* ldmia r4!, {r5} */
0x20 , 0xc3 , /* stmia r3!, {r5} */
0x94 , 0x42 , /* cmp r4, r2 */
0x01 , 0xd3 , /* bcc.n 18 <no_wrap> */
0x0c , 0x46 , /* mov r4, r1 */
0x08 , 0x34 , /* adds r4, #8 */
/* <no_wrap>: */
0x4c , 0x60 , /* str r4, [r1, #4] */
0x04 , 0x38 , /* subs r0, #4 */
0xf0 , 0xd1 , /* bne.n 0 <wait_fifo> */
/* <exit>: */
0x00 , 0xbe /* bkpt 0x0000 */
} ;
2014-03-15 12:40:23 -05:00
2014-06-27 01:13:24 -05:00
/* Start a low level flash write for the specified region */
2017-08-31 14:09:42 -05:00
static int nrf5_ll_flash_write ( struct nrf5_info * chip , uint32_t offset , const uint8_t * buffer , uint32_t bytes )
2014-06-27 01:13:24 -05:00
{
struct target * target = chip - > target ;
uint32_t buffer_size = 8192 ;
struct working_area * write_algorithm ;
struct working_area * source ;
2017-08-31 14:09:42 -05:00
uint32_t address = NRF5_FLASH_BASE + offset ;
2014-06-27 01:13:24 -05:00
struct reg_param reg_params [ 4 ] ;
struct armv7m_algorithm armv7m_info ;
int retval = ERROR_OK ;
LOG_DEBUG ( " Writing buffer to flash offset=0x% " PRIx32 " bytes=0x% " PRIx32 , offset , bytes ) ;
assert ( bytes % 4 = = 0 ) ;
/* allocate working area with flash programming code */
2017-08-31 14:09:42 -05:00
if ( target_alloc_working_area ( target , sizeof ( nrf5_flash_write_code ) ,
2014-06-27 01:13:24 -05:00
& write_algorithm ) ! = ERROR_OK ) {
LOG_WARNING ( " no working area available, falling back to slow memory writes " ) ;
for ( ; bytes > 0 ; bytes - = 4 ) {
retval = target_write_memory ( chip - > target , offset , 4 , 1 , buffer ) ;
if ( retval ! = ERROR_OK )
return retval ;
2017-08-31 14:09:42 -05:00
retval = nrf5_wait_for_nvmc ( chip ) ;
2014-06-27 01:13:24 -05:00
if ( retval ! = ERROR_OK )
return retval ;
offset + = 4 ;
buffer + = 4 ;
}
2014-03-15 12:40:23 -05:00
2014-06-27 01:13:24 -05:00
return ERROR_OK ;
2014-03-15 12:40:23 -05:00
}
2014-06-27 01:13:24 -05:00
LOG_WARNING ( " using fast async flash loader. This is currently supported " ) ;
LOG_WARNING ( " only with ST-Link and CMSIS-DAP. If you have issues, add " ) ;
2017-08-31 14:09:42 -05:00
LOG_WARNING ( " \" set WORKAREASIZE 0 \" before sourcing nrf51.cfg/nrf52.cfg to disable it " ) ;
2014-06-27 01:13:24 -05:00
retval = target_write_buffer ( target , write_algorithm - > address ,
2017-08-31 14:09:42 -05:00
sizeof ( nrf5_flash_write_code ) ,
nrf5_flash_write_code ) ;
2014-06-27 01:13:24 -05:00
if ( retval ! = ERROR_OK )
return retval ;
/* memory buffer */
while ( target_alloc_working_area ( target , buffer_size , & source ) ! = ERROR_OK ) {
buffer_size / = 2 ;
buffer_size & = ~ 3UL ; /* Make sure it's 4 byte aligned */
if ( buffer_size < = 256 ) {
/* free working area, write algorithm already allocated */
target_free_working_area ( target , write_algorithm ) ;
LOG_WARNING ( " No large enough working area available, can't do block memory writes " ) ;
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE ;
}
}
armv7m_info . common_magic = ARMV7M_COMMON_MAGIC ;
armv7m_info . core_mode = ARM_MODE_THREAD ;
init_reg_param ( & reg_params [ 0 ] , " r0 " , 32 , PARAM_IN_OUT ) ; /* byte count */
init_reg_param ( & reg_params [ 1 ] , " r1 " , 32 , PARAM_OUT ) ; /* buffer start */
init_reg_param ( & reg_params [ 2 ] , " r2 " , 32 , PARAM_OUT ) ; /* buffer end */
init_reg_param ( & reg_params [ 3 ] , " r3 " , 32 , PARAM_IN_OUT ) ; /* target address */
buf_set_u32 ( reg_params [ 0 ] . value , 0 , 32 , bytes ) ;
buf_set_u32 ( reg_params [ 1 ] . value , 0 , 32 , source - > address ) ;
buf_set_u32 ( reg_params [ 2 ] . value , 0 , 32 , source - > address + source - > size ) ;
buf_set_u32 ( reg_params [ 3 ] . value , 0 , 32 , address ) ;
retval = target_run_flash_async_algorithm ( target , buffer , bytes / 4 , 4 ,
0 , NULL ,
4 , reg_params ,
source - > address , source - > size ,
write_algorithm - > address , 0 ,
& armv7m_info ) ;
target_free_working_area ( target , source ) ;
target_free_working_area ( target , write_algorithm ) ;
destroy_reg_param ( & reg_params [ 0 ] ) ;
destroy_reg_param ( & reg_params [ 1 ] ) ;
destroy_reg_param ( & reg_params [ 2 ] ) ;
destroy_reg_param ( & reg_params [ 3 ] ) ;
return retval ;
2014-03-15 12:40:23 -05:00
}
2014-06-27 01:13:24 -05:00
/* Check and erase flash sectors in specified range then start a low level page write.
start / end must be sector aligned .
*/
2017-08-31 14:09:42 -05:00
static int nrf5_write_pages ( struct flash_bank * bank , uint32_t start , uint32_t end , const uint8_t * buffer )
2014-02-07 13:54:57 -06:00
{
int res = ERROR_FAIL ;
2018-11-21 07:09:39 -06:00
struct nrf5_bank * nbank = bank - > driver_priv ;
struct nrf5_info * chip = nbank - > chip ;
2014-06-27 01:13:24 -05:00
assert ( start % chip - > code_page_size = = 0 ) ;
assert ( end % chip - > code_page_size = = 0 ) ;
2017-08-31 14:09:42 -05:00
res = nrf5_nvmc_write_enable ( chip ) ;
2014-02-07 13:54:57 -06:00
if ( res ! = ERROR_OK )
goto error ;
2017-08-31 14:09:42 -05:00
res = nrf5_ll_flash_write ( chip , start , buffer , ( end - start ) ) ;
2014-02-07 13:54:57 -06:00
if ( res ! = ERROR_OK )
2018-02-09 10:24:05 -06:00
goto error ;
2014-02-07 13:54:57 -06:00
2017-08-31 14:09:42 -05:00
return nrf5_nvmc_read_only ( chip ) ;
2014-02-07 13:54:57 -06:00
error :
2018-02-09 10:24:05 -06:00
nrf5_nvmc_read_only ( chip ) ;
2017-08-31 14:09:42 -05:00
LOG_ERROR ( " Failed to write to nrf5 flash " ) ;
2014-02-07 13:54:57 -06:00
return res ;
}
2017-08-31 14:09:42 -05:00
static int nrf5_erase ( struct flash_bank * bank , int first , int last )
2014-02-07 13:54:57 -06:00
{
int res ;
2017-08-31 14:09:42 -05:00
struct nrf5_info * chip ;
2014-02-07 13:54:57 -06:00
2017-08-31 14:09:42 -05:00
res = nrf5_get_probed_chip_if_halted ( bank , & chip ) ;
2014-02-07 13:54:57 -06:00
if ( res ! = ERROR_OK )
return res ;
/* For each sector to be erased */
for ( int s = first ; s < = last & & res = = ERROR_OK ; s + + )
2017-08-31 14:09:42 -05:00
res = nrf5_erase_page ( bank , chip , & bank - > sectors [ s ] ) ;
2014-02-07 13:54:57 -06:00
return res ;
}
2017-08-31 14:09:42 -05:00
static int nrf5_code_flash_write ( struct flash_bank * bank ,
struct nrf5_info * chip ,
2014-03-01 15:40:08 -06:00
const uint8_t * buffer , uint32_t offset , uint32_t count )
2014-02-07 13:54:57 -06:00
{
2014-06-27 01:13:24 -05:00
2014-02-07 13:54:57 -06:00
int res ;
2014-06-27 01:13:24 -05:00
/* Need to perform reads to fill any gaps we need to preserve in the first page,
before the start of buffer , or in the last page , after the end of buffer */
uint32_t first_page = offset / chip - > code_page_size ;
uint32_t last_page = DIV_ROUND_UP ( offset + count , chip - > code_page_size ) ;
2014-02-07 13:54:57 -06:00
2014-06-27 01:13:24 -05:00
uint32_t first_page_offset = first_page * chip - > code_page_size ;
uint32_t last_page_offset = last_page * chip - > code_page_size ;
2014-02-07 13:54:57 -06:00
2014-06-27 01:13:24 -05:00
LOG_DEBUG ( " Padding write from 0x%08 " PRIx32 " -0x%08 " PRIx32 " as 0x%08 " PRIx32 " -0x%08 " PRIx32 ,
offset , offset + count , first_page_offset , last_page_offset ) ;
2014-02-07 13:54:57 -06:00
2014-06-27 01:13:24 -05:00
uint32_t page_cnt = last_page - first_page ;
uint8_t buffer_to_flash [ page_cnt * chip - > code_page_size ] ;
2014-02-07 13:54:57 -06:00
2014-06-27 01:13:24 -05:00
/* Fill in any space between start of first page and start of buffer */
uint32_t pre = offset - first_page_offset ;
if ( pre > 0 ) {
2014-02-07 13:54:57 -06:00
res = target_read_memory ( bank - > target ,
2014-06-27 01:13:24 -05:00
first_page_offset ,
1 ,
pre ,
buffer_to_flash ) ;
2014-02-07 13:54:57 -06:00
if ( res ! = ERROR_OK )
return res ;
}
2014-06-27 01:13:24 -05:00
/* Fill in main contents of buffer */
memcpy ( buffer_to_flash + pre , buffer , count ) ;
2014-02-07 13:54:57 -06:00
2014-06-27 01:13:24 -05:00
/* Fill in any space between end of buffer and end of last page */
uint32_t post = last_page_offset - ( offset + count ) ;
if ( post > 0 ) {
2014-02-07 13:54:57 -06:00
/* Retrieve the full row contents from Flash */
res = target_read_memory ( bank - > target ,
2014-06-27 01:13:24 -05:00
offset + count ,
1 ,
post ,
buffer_to_flash + pre + count ) ;
2014-02-07 13:54:57 -06:00
if ( res ! = ERROR_OK )
return res ;
}
2017-08-31 14:09:42 -05:00
return nrf5_write_pages ( bank , first_page_offset , last_page_offset , buffer_to_flash ) ;
2014-02-07 13:54:57 -06:00
}
2017-08-31 14:09:42 -05:00
static int nrf5_uicr_flash_write ( struct flash_bank * bank ,
struct nrf5_info * chip ,
2014-03-01 15:40:08 -06:00
const uint8_t * buffer , uint32_t offset , uint32_t count )
2014-02-07 13:54:57 -06:00
{
2014-03-01 15:40:08 -06:00
int res ;
2017-08-31 14:09:42 -05:00
uint8_t uicr [ NRF5_UICR_SIZE ] ;
2014-03-01 15:40:08 -06:00
struct flash_sector * sector = & bank - > sectors [ 0 ] ;
2014-02-07 13:54:57 -06:00
2017-08-31 14:09:42 -05:00
if ( ( offset + count ) > NRF5_UICR_SIZE )
2014-02-07 13:54:57 -06:00
return ERROR_FAIL ;
2014-03-01 15:40:08 -06:00
res = target_read_memory ( bank - > target ,
2017-08-31 14:09:42 -05:00
NRF5_UICR_BASE ,
2014-03-01 15:40:08 -06:00
1 ,
2017-08-31 14:09:42 -05:00
NRF5_UICR_SIZE ,
2014-03-01 15:40:08 -06:00
uicr ) ;
2014-02-07 13:54:57 -06:00
2014-03-01 15:40:08 -06:00
if ( res ! = ERROR_OK )
return res ;
2018-02-09 10:24:05 -06:00
res = nrf5_erase_page ( bank , chip , sector ) ;
if ( res ! = ERROR_OK )
return res ;
2014-02-07 13:54:57 -06:00
2017-08-31 14:09:42 -05:00
res = nrf5_nvmc_write_enable ( chip ) ;
2014-03-01 15:40:08 -06:00
if ( res ! = ERROR_OK )
return res ;
memcpy ( & uicr [ offset ] , buffer , count ) ;
2017-08-31 14:09:42 -05:00
res = nrf5_ll_flash_write ( chip , NRF5_UICR_BASE , uicr , NRF5_UICR_SIZE ) ;
2014-03-01 15:40:08 -06:00
if ( res ! = ERROR_OK ) {
2017-08-31 14:09:42 -05:00
nrf5_nvmc_read_only ( chip ) ;
2014-03-01 15:40:08 -06:00
return res ;
}
2017-08-31 14:09:42 -05:00
return nrf5_nvmc_read_only ( chip ) ;
2014-03-01 15:40:08 -06:00
}
2017-08-31 14:09:42 -05:00
static int nrf5_write ( struct flash_bank * bank , const uint8_t * buffer ,
2014-03-01 15:40:08 -06:00
uint32_t offset , uint32_t count )
{
int res ;
2018-11-21 07:09:39 -06:00
struct nrf5_bank * nbank = bank - > driver_priv ;
2017-08-31 14:09:42 -05:00
struct nrf5_info * chip ;
2014-03-01 15:40:08 -06:00
2017-08-31 14:09:42 -05:00
res = nrf5_get_probed_chip_if_halted ( bank , & chip ) ;
2014-03-01 15:40:08 -06:00
if ( res ! = ERROR_OK )
return res ;
2018-11-21 07:09:39 -06:00
return nbank - > write ( bank , chip , buffer , offset , count ) ;
2014-03-01 15:40:08 -06:00
}
2018-07-20 10:14:34 -05:00
static void nrf5_free_driver_priv ( struct flash_bank * bank )
{
2018-11-21 07:09:39 -06:00
struct nrf5_bank * nbank = bank - > driver_priv ;
struct nrf5_info * chip = nbank - > chip ;
2018-07-20 10:14:34 -05:00
if ( chip = = NULL )
return ;
chip - > refcount - - ;
if ( chip - > refcount = = 0 ) {
free ( chip ) ;
bank - > driver_priv = NULL ;
}
}
2014-03-01 15:40:08 -06:00
2017-08-31 14:09:42 -05:00
FLASH_BANK_COMMAND_HANDLER ( nrf5_flash_bank_command )
2014-03-01 15:40:08 -06:00
{
2017-08-31 14:09:42 -05:00
static struct nrf5_info * chip ;
2018-11-21 07:09:39 -06:00
struct nrf5_bank * nbank = NULL ;
2014-03-01 15:40:08 -06:00
switch ( bank - > base ) {
2017-08-31 14:09:42 -05:00
case NRF5_FLASH_BASE :
case NRF5_UICR_BASE :
2014-03-01 15:40:08 -06:00
break ;
default :
2019-02-14 19:33:28 -06:00
LOG_ERROR ( " Invalid bank address " TARGET_ADDR_FMT , bank - > base ) ;
2014-02-07 13:54:57 -06:00
return ERROR_FAIL ;
}
2014-03-01 15:40:08 -06:00
if ( ! chip ) {
/* Create a new chip */
chip = calloc ( 1 , sizeof ( * chip ) ) ;
if ( ! chip )
return ERROR_FAIL ;
chip - > target = bank - > target ;
}
switch ( bank - > base ) {
2017-08-31 14:09:42 -05:00
case NRF5_FLASH_BASE :
2018-11-21 07:09:39 -06:00
nbank = & chip - > bank [ 0 ] ;
nbank - > write = nrf5_code_flash_write ;
2014-03-01 15:40:08 -06:00
break ;
2017-08-31 14:09:42 -05:00
case NRF5_UICR_BASE :
2018-11-21 07:09:39 -06:00
nbank = & chip - > bank [ 1 ] ;
nbank - > write = nrf5_uicr_flash_write ;
2014-03-01 15:40:08 -06:00
break ;
}
2018-11-21 07:09:39 -06:00
assert ( nbank ! = NULL ) ;
2014-03-01 15:40:08 -06:00
2018-07-20 10:14:34 -05:00
chip - > refcount + + ;
2018-11-21 07:09:39 -06:00
nbank - > chip = chip ;
nbank - > probed = false ;
bank - > driver_priv = nbank ;
2014-03-01 15:40:08 -06:00
2014-02-07 13:54:57 -06:00
return ERROR_OK ;
}
2017-08-31 14:09:42 -05:00
COMMAND_HANDLER ( nrf5_handle_mass_erase_command )
2014-02-07 13:54:57 -06:00
{
int res ;
2014-03-01 15:40:08 -06:00
struct flash_bank * bank = NULL ;
struct target * target = get_current_target ( CMD_CTX ) ;
2014-02-07 13:54:57 -06:00
2017-08-31 14:09:42 -05:00
res = get_flash_bank_by_addr ( target , NRF5_FLASH_BASE , true , & bank ) ;
2014-02-07 13:54:57 -06:00
if ( res ! = ERROR_OK )
return res ;
2014-03-01 15:40:08 -06:00
assert ( bank ! = NULL ) ;
2017-08-31 14:09:42 -05:00
struct nrf5_info * chip ;
2014-02-07 13:54:57 -06:00
2017-08-31 14:09:42 -05:00
res = nrf5_get_probed_chip_if_halted ( bank , & chip ) ;
2014-02-07 13:54:57 -06:00
if ( res ! = ERROR_OK )
return res ;
uint32_t ppfc ;
2017-08-31 14:09:42 -05:00
res = target_read_u32 ( target , NRF5_FICR_PPFC ,
2014-02-07 13:54:57 -06:00
& ppfc ) ;
if ( res ! = ERROR_OK ) {
LOG_ERROR ( " Couldn't read PPFC register " ) ;
return res ;
}
if ( ( ppfc & 0xFF ) = = 0x00 ) {
LOG_ERROR ( " Code region 0 size was pre-programmed at the factory, "
" mass erase command won't work. " ) ;
return ERROR_FAIL ;
2016-02-28 14:21:40 -06:00
}
2014-02-07 13:54:57 -06:00
2017-08-31 14:09:42 -05:00
res = nrf5_erase_all ( chip ) ;
2014-02-07 13:54:57 -06:00
if ( res ! = ERROR_OK ) {
LOG_ERROR ( " Failed to erase the chip " ) ;
2017-08-31 14:09:42 -05:00
nrf5_protect_check ( bank ) ;
2014-02-07 13:54:57 -06:00
return res ;
}
2017-08-31 14:09:42 -05:00
res = nrf5_protect_check ( bank ) ;
2014-03-01 15:40:08 -06:00
if ( res ! = ERROR_OK ) {
LOG_ERROR ( " Failed to check chip's write protection " ) ;
return res ;
}
2017-08-31 14:09:42 -05:00
res = get_flash_bank_by_addr ( target , NRF5_UICR_BASE , true , & bank ) ;
2014-03-01 15:40:08 -06:00
if ( res ! = ERROR_OK )
return res ;
return ERROR_OK ;
2014-02-07 13:54:57 -06:00
}
2017-08-31 14:09:42 -05:00
static int nrf5_info ( struct flash_bank * bank , char * buf , int buf_size )
2014-02-07 13:54:57 -06:00
{
int res ;
2017-08-31 14:09:42 -05:00
struct nrf5_info * chip ;
2014-02-07 13:54:57 -06:00
2017-08-31 14:09:42 -05:00
res = nrf5_get_probed_chip_if_halted ( bank , & chip ) ;
2014-02-07 13:54:57 -06:00
if ( res ! = ERROR_OK )
return res ;
2014-09-11 16:08:34 -05:00
static struct {
const uint32_t address ;
uint32_t value ;
2014-02-07 13:54:57 -06:00
} ficr [ ] = {
2017-08-31 14:09:42 -05:00
{ . address = NRF5_FICR_CODEPAGESIZE } ,
{ . address = NRF5_FICR_CODESIZE } ,
{ . address = NRF5_FICR_CLENR0 } ,
{ . address = NRF5_FICR_PPFC } ,
{ . address = NRF5_FICR_NUMRAMBLOCK } ,
{ . address = NRF5_FICR_SIZERAMBLOCK0 } ,
{ . address = NRF5_FICR_SIZERAMBLOCK1 } ,
{ . address = NRF5_FICR_SIZERAMBLOCK2 } ,
{ . address = NRF5_FICR_SIZERAMBLOCK3 } ,
{ . address = NRF5_FICR_CONFIGID } ,
{ . address = NRF5_FICR_DEVICEID0 } ,
{ . address = NRF5_FICR_DEVICEID1 } ,
{ . address = NRF5_FICR_ER0 } ,
{ . address = NRF5_FICR_ER1 } ,
{ . address = NRF5_FICR_ER2 } ,
{ . address = NRF5_FICR_ER3 } ,
{ . address = NRF5_FICR_IR0 } ,
{ . address = NRF5_FICR_IR1 } ,
{ . address = NRF5_FICR_IR2 } ,
{ . address = NRF5_FICR_IR3 } ,
{ . address = NRF5_FICR_DEVICEADDRTYPE } ,
{ . address = NRF5_FICR_DEVICEADDR0 } ,
{ . address = NRF5_FICR_DEVICEADDR1 } ,
{ . address = NRF5_FICR_OVERRIDEN } ,
{ . address = NRF5_FICR_NRF_1MBIT0 } ,
{ . address = NRF5_FICR_NRF_1MBIT1 } ,
{ . address = NRF5_FICR_NRF_1MBIT2 } ,
{ . address = NRF5_FICR_NRF_1MBIT3 } ,
{ . address = NRF5_FICR_NRF_1MBIT4 } ,
{ . address = NRF5_FICR_BLE_1MBIT0 } ,
{ . address = NRF5_FICR_BLE_1MBIT1 } ,
{ . address = NRF5_FICR_BLE_1MBIT2 } ,
{ . address = NRF5_FICR_BLE_1MBIT3 } ,
{ . address = NRF5_FICR_BLE_1MBIT4 } ,
2014-02-07 13:54:57 -06:00
} , uicr [ ] = {
2017-08-31 14:09:42 -05:00
{ . address = NRF5_UICR_CLENR0 , } ,
{ . address = NRF5_UICR_RBPCONF } ,
{ . address = NRF5_UICR_XTALFREQ } ,
{ . address = NRF5_UICR_FWID } ,
2014-02-07 13:54:57 -06:00
} ;
for ( size_t i = 0 ; i < ARRAY_SIZE ( ficr ) ; i + + ) {
res = target_read_u32 ( chip - > target , ficr [ i ] . address ,
& ficr [ i ] . value ) ;
if ( res ! = ERROR_OK ) {
LOG_ERROR ( " Couldn't read % " PRIx32 , ficr [ i ] . address ) ;
return res ;
}
}
for ( size_t i = 0 ; i < ARRAY_SIZE ( uicr ) ; i + + ) {
res = target_read_u32 ( chip - > target , uicr [ i ] . address ,
& uicr [ i ] . value ) ;
if ( res ! = ERROR_OK ) {
LOG_ERROR ( " Couldn't read % " PRIx32 , uicr [ i ] . address ) ;
return res ;
}
}
snprintf ( buf , buf_size ,
" \n [factory information control block] \n \n "
" code page size: % " PRIu32 " B \n "
" code memory size: % " PRIu32 " kB \n "
" code region 0 size: % " PRIu32 " kB \n "
" pre-programmed code: %s \n "
" number of ram blocks: % " PRIu32 " \n "
" ram block 0 size: % " PRIu32 " B \n "
" ram block 1 size: % " PRIu32 " B \n "
" ram block 2 size: % " PRIu32 " B \n "
" ram block 3 size: % " PRIu32 " B \n "
2014-02-28 13:27:40 -06:00
" config id: % " PRIx32 " \n "
" device id: 0x% " PRIx32 " %08 " PRIx32 " \n "
2014-02-07 13:54:57 -06:00
" encryption root: 0x%08 " PRIx32 " %08 " PRIx32 " %08 " PRIx32 " %08 " PRIx32 " \n "
" identity root: 0x%08 " PRIx32 " %08 " PRIx32 " %08 " PRIx32 " %08 " PRIx32 " \n "
" device address type: 0x% " PRIx32 " \n "
" device address: 0x% " PRIx32 " %08 " PRIx32 " \n "
2014-02-28 13:27:40 -06:00
" override enable: % " PRIx32 " \n "
2014-02-07 13:54:57 -06:00
" NRF_1MBIT values: % " PRIx32 " % " PRIx32 " % " PRIx32 " % " PRIx32 " % " PRIx32 " \n "
" BLE_1MBIT values: % " PRIx32 " % " PRIx32 " % " PRIx32 " % " PRIx32 " % " PRIx32 " \n "
" \n [user information control block] \n \n "
" code region 0 size: % " PRIu32 " kB \n "
" read back protection configuration: % " PRIx32 " \n "
" reset value for XTALFREQ: % " PRIx32 " \n "
" firmware id: 0x%04 " PRIx32 ,
ficr [ 0 ] . value ,
2016-05-30 03:54:47 -05:00
( ficr [ 1 ] . value * ficr [ 0 ] . value ) / 1024 ,
2014-02-07 13:54:57 -06:00
( ficr [ 2 ] . value = = 0xFFFFFFFF ) ? 0 : ficr [ 2 ] . value / 1024 ,
( ( ficr [ 3 ] . value & 0xFF ) = = 0x00 ) ? " present " : " not present " ,
ficr [ 4 ] . value ,
ficr [ 5 ] . value ,
( ficr [ 6 ] . value = = 0xFFFFFFFF ) ? 0 : ficr [ 6 ] . value ,
( ficr [ 7 ] . value = = 0xFFFFFFFF ) ? 0 : ficr [ 7 ] . value ,
( ficr [ 8 ] . value = = 0xFFFFFFFF ) ? 0 : ficr [ 8 ] . value ,
2014-02-28 13:27:40 -06:00
ficr [ 9 ] . value ,
ficr [ 10 ] . value , ficr [ 11 ] . value ,
ficr [ 12 ] . value , ficr [ 13 ] . value , ficr [ 14 ] . value , ficr [ 15 ] . value ,
ficr [ 16 ] . value , ficr [ 17 ] . value , ficr [ 18 ] . value , ficr [ 19 ] . value ,
ficr [ 20 ] . value ,
ficr [ 21 ] . value , ficr [ 22 ] . value ,
ficr [ 23 ] . value ,
ficr [ 24 ] . value , ficr [ 25 ] . value , ficr [ 26 ] . value , ficr [ 27 ] . value , ficr [ 28 ] . value ,
ficr [ 29 ] . value , ficr [ 30 ] . value , ficr [ 31 ] . value , ficr [ 32 ] . value , ficr [ 33 ] . value ,
2014-02-07 13:54:57 -06:00
( uicr [ 0 ] . value = = 0xFFFFFFFF ) ? 0 : uicr [ 0 ] . value / 1024 ,
uicr [ 1 ] . value & 0xFFFF ,
uicr [ 2 ] . value & 0xFF ,
uicr [ 3 ] . value & 0xFFFF ) ;
return ERROR_OK ;
}
2017-08-31 14:09:42 -05:00
static const struct command_registration nrf5_exec_command_handlers [ ] = {
2014-02-07 13:54:57 -06:00
{
. name = " mass_erase " ,
2017-08-31 14:09:42 -05:00
. handler = nrf5_handle_mass_erase_command ,
2014-02-07 13:54:57 -06:00
. mode = COMMAND_EXEC ,
. help = " Erase all flash contents of the chip. " ,
2019-01-04 11:16:00 -06:00
. usage = " " ,
2014-02-07 13:54:57 -06:00
} ,
COMMAND_REGISTRATION_DONE
} ;
2017-08-31 14:09:42 -05:00
static const struct command_registration nrf5_command_handlers [ ] = {
{
. name = " nrf5 " ,
. mode = COMMAND_ANY ,
. help = " nrf5 flash command group " ,
. usage = " " ,
. chain = nrf5_exec_command_handlers ,
} ,
2014-02-07 13:54:57 -06:00
{
. name = " nrf51 " ,
. mode = COMMAND_ANY ,
. help = " nrf51 flash command group " ,
. usage = " " ,
2017-08-31 14:09:42 -05:00
. chain = nrf5_exec_command_handlers ,
2014-02-07 13:54:57 -06:00
} ,
COMMAND_REGISTRATION_DONE
} ;
2018-12-13 13:53:59 -06:00
const struct flash_driver nrf5_flash = {
2017-08-31 14:09:42 -05:00
. name = " nrf5 " ,
. commands = nrf5_command_handlers ,
. flash_bank_command = nrf5_flash_bank_command ,
. info = nrf5_info ,
. erase = nrf5_erase ,
. protect = nrf5_protect ,
. write = nrf5_write ,
. read = default_flash_read ,
. probe = nrf5_probe ,
. auto_probe = nrf5_auto_probe ,
. erase_check = default_flash_blank_check ,
. protect_check = nrf5_protect_check ,
2018-07-20 10:14:34 -05:00
. free_driver_priv = nrf5_free_driver_priv ,
2017-08-31 14:09:42 -05:00
} ;
/* We need to retain the flash-driver name as well as the commands
* for backwards compatability */
2018-12-13 13:53:59 -06:00
const struct flash_driver nrf51_flash = {
2014-02-07 13:54:57 -06:00
. name = " nrf51 " ,
2017-08-31 14:09:42 -05:00
. commands = nrf5_command_handlers ,
. flash_bank_command = nrf5_flash_bank_command ,
. info = nrf5_info ,
. erase = nrf5_erase ,
. protect = nrf5_protect ,
. write = nrf5_write ,
2014-02-07 13:54:57 -06:00
. read = default_flash_read ,
2017-08-31 14:09:42 -05:00
. probe = nrf5_probe ,
. auto_probe = nrf5_auto_probe ,
2014-02-07 13:54:57 -06:00
. erase_check = default_flash_blank_check ,
2017-08-31 14:09:42 -05:00
. protect_check = nrf5_protect_check ,
2018-07-20 10:14:34 -05:00
. free_driver_priv = nrf5_free_driver_priv ,
2014-02-07 13:54:57 -06:00
} ;