Newer
Older
/***************************************************************************
* Copyright (C) 2009 by Duane Ellis *
* openocd@duaneellis.com *
* *
* 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 *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
****************************************************************************/
/* Some of the the lower level code was based on code supplied by
* ATMEL under this copyright. */
/* BEGIN ATMEL COPYRIGHT */
/* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
* ----------------------------------------------------------------------------
* Copyright (c) 2009, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL 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.
* ----------------------------------------------------------------------------
*/
/* END ATMEL COPYRIGHT */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <string.h>
#include <stddef.h>
#include "log.h"
#include "types.h"
#include "flash.h"
#include "target.h"
#include "membuf.h"
#include "at91sam3.h"
#include "time_support.h"
#define REG_NAME_WIDTH (12)
#define FLASH_BANK0_BASE 0x00080000
#define FLASH_BANK1_BASE 0x00100000
#define AT91C_EFC_FCMD_GETD (0x0) // (EFC) Get Flash Descriptor
#define AT91C_EFC_FCMD_WP (0x1) // (EFC) Write Page
#define AT91C_EFC_FCMD_WPL (0x2) // (EFC) Write Page and Lock
#define AT91C_EFC_FCMD_EWP (0x3) // (EFC) Erase Page and Write Page
#define AT91C_EFC_FCMD_EWPL (0x4) // (EFC) Erase Page and Write Page then Lock
#define AT91C_EFC_FCMD_EA (0x5) // (EFC) Erase All
// cmd6 is not present int he at91sam3u4/2/1 data sheet table 17-2
// #define AT91C_EFC_FCMD_EPL (0x6) // (EFC) Erase plane?
// cmd7 is not present int he at91sam3u4/2/1 data sheet table 17-2
// #define AT91C_EFC_FCMD_EPA (0x7) // (EFC) Erase pages?
#define AT91C_EFC_FCMD_SLB (0x8) // (EFC) Set Lock Bit
#define AT91C_EFC_FCMD_CLB (0x9) // (EFC) Clear Lock Bit
#define AT91C_EFC_FCMD_GLB (0xA) // (EFC) Get Lock Bit
#define AT91C_EFC_FCMD_SFB (0xB) // (EFC) Set Fuse Bit
#define AT91C_EFC_FCMD_CFB (0xC) // (EFC) Clear Fuse Bit
#define AT91C_EFC_FCMD_GFB (0xD) // (EFC) Get Fuse Bit
#define AT91C_EFC_FCMD_STUI (0xE) // (EFC) Start Read Unique ID
#define AT91C_EFC_FCMD_SPUI (0xF) // (EFC) Stop Read Unique ID
#define offset_EFC_FMR 0
#define offset_EFC_FCR 4
#define offset_EFC_FSR 8
#define offset_EFC_FRR 12
static float
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
{
float f;
f = ((float)(freq_hz)) / 1000000.0;
return f;
}
// How the chip is configured.
struct sam3_cfg {
uint32_t unique_id[4];
uint32_t slow_freq;
uint32_t rc_freq;
uint32_t mainosc_freq;
uint32_t plla_freq;
uint32_t mclk_freq;
uint32_t cpu_freq;
uint32_t fclk_freq;
uint32_t pclk0_freq;
uint32_t pclk1_freq;
uint32_t pclk2_freq;
#define SAM3_CHIPID_CIDR (0x400E0740)
uint32_t CHIPID_CIDR;
#define SAM3_CHIPID_EXID (0x400E0744)
uint32_t CHIPID_EXID;
#define SAM3_SUPC_CR (0x400E1210)
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#define SAM3_PMC_BASE (0x400E0400)
#define SAM3_PMC_SCSR (SAM3_PMC_BASE + 0x0008)
uint32_t PMC_SCSR;
#define SAM3_PMC_PCSR (SAM3_PMC_BASE + 0x0018)
uint32_t PMC_PCSR;
#define SAM3_CKGR_UCKR (SAM3_PMC_BASE + 0x001c)
uint32_t CKGR_UCKR;
#define SAM3_CKGR_MOR (SAM3_PMC_BASE + 0x0020)
uint32_t CKGR_MOR;
#define SAM3_CKGR_MCFR (SAM3_PMC_BASE + 0x0024)
uint32_t CKGR_MCFR;
#define SAM3_CKGR_PLLAR (SAM3_PMC_BASE + 0x0028)
uint32_t CKGR_PLLAR;
#define SAM3_PMC_MCKR (SAM3_PMC_BASE + 0x0030)
uint32_t PMC_MCKR;
#define SAM3_PMC_PCK0 (SAM3_PMC_BASE + 0x0040)
uint32_t PMC_PCK0;
#define SAM3_PMC_PCK1 (SAM3_PMC_BASE + 0x0044)
uint32_t PMC_PCK1;
#define SAM3_PMC_PCK2 (SAM3_PMC_BASE + 0x0048)
uint32_t PMC_PCK2;
#define SAM3_PMC_SR (SAM3_PMC_BASE + 0x0068)
uint32_t PMC_SR;
#define SAM3_PMC_IMR (SAM3_PMC_BASE + 0x006c)
uint32_t PMC_IMR;
#define SAM3_PMC_FSMR (SAM3_PMC_BASE + 0x0070)
uint32_t PMC_FSMR;
#define SAM3_PMC_FSPR (SAM3_PMC_BASE + 0x0074)
uint32_t PMC_FSPR;
};
struct sam3_bank_private {
int probed;
// DANGER: THERE ARE DRAGONS HERE..
// NOTE: If you add more 'ghost' pointers
// be aware that you must *manually* update
// these pointers in the function sam3_GetDetails()
// See the comment "Here there be dragons"
// so we can find the chip we belong to
struct sam3_chip *pChip;
// so we can find the orginal bank pointer
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
flash_bank_t *pBank;
unsigned bank_number;
uint32_t controller_address;
uint32_t base_address;
bool present;
unsigned size_bytes;
unsigned nsectors;
unsigned sector_size;
unsigned page_size;
};
struct sam3_chip_details {
// THERE ARE DRAGONS HERE..
// note: If you add pointers here
// becareful about them as they
// may need to be updated inside
// the function: "sam3_GetDetails()
// which copy/overwrites the
// 'runtime' copy of this structure
uint32_t chipid_cidr;
const char *name;
unsigned n_gpnvms;
#define SAM3_N_NVM_BITS 3
unsigned gpnvm[SAM3_N_NVM_BITS];
unsigned total_flash_size;
unsigned total_sram_size;
unsigned n_banks;
#define SAM3_MAX_FLASH_BANKS 2
// these are "initialized" from the global const data
struct sam3_bank_private bank[SAM3_MAX_FLASH_BANKS];
};
struct sam3_chip {
struct sam3_chip *next;
int probed;
// this is "initialized" from the global const structure
struct sam3_chip_details details;
target_t *target;
struct sam3_cfg cfg;
struct membuf *mbuf;
};
struct sam3_reg_list {
uint32_t address; size_t struct_offset; const char *name;
void (*explain_func)(struct sam3_chip *pInfo);
};
static struct sam3_chip *all_sam3_chips;
static struct sam3_chip *
get_current_sam3(struct command_context_s *cmd_ctx)
{
target_t *t;
static struct sam3_chip *p;
command_print(cmd_ctx, "No current target?");
return NULL;
}
p = all_sam3_chips;
// this should not happen
// the command is not registered until the chip is created?
command_print(cmd_ctx, "No SAM3 chips exist?");
return p;
}
p = p->next;
}
command_print(cmd_ctx, "Cannot find SAM3 chip?");
return NULL;
}
// these are used to *initialize* the "pChip->details" structure.
static const struct sam3_chip_details all_sam3_details[] = {
{
.chipid_cidr = 0x28100960,
.name = "at91sam3u4e",
.total_flash_size = 256 * 1024,
.total_sram_size = 52 * 1024,
.n_banks = 2,
// System boots at address 0x0
// gpnvm[1] = selects boot code
// if gpnvm[1] == 0
// boot is via "SAMBA" (rom)
// boot is via FLASH
// Selection is via gpnvm[2]
// endif
//
// NOTE: banks 0 & 1 switch places
// if gpnvm[2] == 0
// Bank0 is the boot rom
// else
// Bank1 is the boot rom
// endif
// .bank[0] = {
{
{
.probed = 0,
.pChip = NULL,
.pBank = NULL,
.bank_number = 0,
.controller_address = 0x400e0800,
.present = 1,
.size_bytes = 128 * 1024,
.nsectors = 16,
.sector_size = 8192,
.page_size = 256,
// .bank[1] = {
{
.probed = 0,
.pChip = NULL,
.pBank = NULL,
.bank_number = 1,
.base_address = FLASH_BANK1_BASE,
.controller_address = 0x400e0a00,
.present = 1,
.size_bytes = 128 * 1024,
.nsectors = 16,
.sector_size = 8192,
.page_size = 256,
},
},
{
.chipid_cidr = 0x281a0760,
.name = "at91sam3u2e",
.total_flash_size = 128 * 1024,
.total_sram_size = 36 * 1024,
.n_banks = 1,
// System boots at address 0x0
// gpnvm[1] = selects boot code
// if gpnvm[1] == 0
// boot is via "SAMBA" (rom)
// boot is via FLASH
// Selection is via gpnvm[2]
// endif
// .bank[0] = {
{
{
.probed = 0,
.pChip = NULL,
.pBank = NULL,
.bank_number = 0,
.controller_address = 0x400e0800,
.present = 1,
.size_bytes = 128 * 1024,
.nsectors = 16,
.sector_size = 8192,
.page_size = 256,
},
// .bank[1] = {
{
.present = 0,
.probed = 0,
.bank_number = 1,
},
},
{
.chipid_cidr = 0x28190560,
.name = "at91sam3u1e",
.total_flash_size = 64 * 1024,
.total_sram_size = 20 * 1024,
.n_banks = 1,
// System boots at address 0x0
// gpnvm[1] = selects boot code
// if gpnvm[1] == 0
// boot is via "SAMBA" (rom)
// boot is via FLASH
// Selection is via gpnvm[2]
// endif
//
// .bank[0] = {
{
{
.probed = 0,
.pChip = NULL,
.pBank = NULL,
.bank_number = 0,
.controller_address = 0x400e0800,
.present = 1,
.size_bytes = 64 * 1024,
.nsectors = 8,
.sector_size = 8192,
.page_size = 256,
// .bank[1] = {
{
.present = 0,
.probed = 0,
.bank_number = 1,
{
.chipid_cidr = 0x28000960,
.name = "at91sam3u4c",
.total_flash_size = 256 * 1024,
.total_sram_size = 52 * 1024,
.n_banks = 2,
// System boots at address 0x0
// gpnvm[1] = selects boot code
// if gpnvm[1] == 0
// boot is via "SAMBA" (rom)
// boot is via FLASH
// Selection is via gpnvm[2]
// endif
//
// NOTE: banks 0 & 1 switch places
// if gpnvm[2] == 0
// Bank0 is the boot rom
// else
// Bank1 is the boot rom
// endif
{
{
// .bank[0] = {
.probed = 0,
.pChip = NULL,
.pBank = NULL,
.bank_number = 0,
.controller_address = 0x400e0800,
.present = 1,
.size_bytes = 128 * 1024,
.nsectors = 16,
.sector_size = 8192,
.page_size = 256,
},
// .bank[1] = {
{
.probed = 0,
.pChip = NULL,
.pBank = NULL,
.bank_number = 1,
.base_address = FLASH_BANK1_BASE,
.controller_address = 0x400e0a00,
.present = 1,
.size_bytes = 128 * 1024,
.nsectors = 16,
.sector_size = 8192,
.page_size = 256,
},
},
{
.chipid_cidr = 0x280a0760,
.name = "at91sam3u2c",
.total_flash_size = 128 * 1024,
.total_sram_size = 36 * 1024,
.n_banks = 1,
// System boots at address 0x0
// gpnvm[1] = selects boot code
// if gpnvm[1] == 0
// boot is via "SAMBA" (rom)
// boot is via FLASH
// Selection is via gpnvm[2]
// endif
{
// .bank[0] = {
{
.probed = 0,
.pChip = NULL,
.pBank = NULL,
.bank_number = 0,
.controller_address = 0x400e0800,
.present = 1,
.size_bytes = 128 * 1024,
.nsectors = 16,
.sector_size = 8192,
.page_size = 256,
},
// .bank[1] = {
{
.present = 0,
.probed = 0,
.bank_number = 1,
},
},
{
.chipid_cidr = 0x28090560,
.name = "at91sam3u1c",
.total_flash_size = 64 * 1024,
.total_sram_size = 20 * 1024,
.n_banks = 1,
// System boots at address 0x0
// gpnvm[1] = selects boot code
// if gpnvm[1] == 0
// boot is via "SAMBA" (rom)
// boot is via FLASH
// Selection is via gpnvm[2]
// endif
//
{
// .bank[0] = {
{
.probed = 0,
.pChip = NULL,
.pBank = NULL,
.bank_number = 0,
.controller_address = 0x400e0800,
.present = 1,
.size_bytes = 64 * 1024,
.nsectors = 8,
.sector_size = 8192,
.page_size = 256,
},
// .bank[1] = {
{
.present = 0,
.probed = 0,
.bank_number = 1,
},
},
// terminate
.chipid_cidr = 0,
.name = NULL,
}
};
/* Globals above */
/***********************************************************************
**********************************************************************
**********************************************************************
**********************************************************************
**********************************************************************
**********************************************************************/
/* *ATMEL* style code - from the SAM3 driver code */
/**
* Get the current status of the EEFC and
* the value of some status bits (LOCKE, PROGE).
* @param pPrivate - info about the bank
* @param v - result goes here
*/
EFC_GetStatus(struct sam3_bank_private *pPrivate, uint32_t *v)
r = target_read_u32(pPrivate->pChip->target, pPrivate->controller_address + offset_EFC_FSR, v);
LOG_DEBUG("Status: 0x%08x (lockerror: %d, cmderror: %d, ready: %d)",
(unsigned int)(*v),
((unsigned int)((*v >> 2) & 1)),
((unsigned int)((*v >> 1) & 1)),
((unsigned int)((*v >> 0) & 1)));
/**
* Get the result of the last executed command.
* @param pPrivate - info about the bank
* @param v - result goes here
*/
EFC_GetResult(struct sam3_bank_private *pPrivate, uint32_t *v)
r = target_read_u32(pPrivate->pChip->target, pPrivate->controller_address + offset_EFC_FRR, &rv);
*v = rv;
}
LOG_DEBUG("Result: 0x%08x", ((unsigned int)(rv)));
return r;
}
static int
EFC_StartCommand(struct sam3_bank_private *pPrivate,
{
uint32_t n,v;
int r;
int retry;
retry = 0;
do_retry:
// Check command & argument
switch (command) {
case AT91C_EFC_FCMD_WP:
case AT91C_EFC_FCMD_WPL:
case AT91C_EFC_FCMD_EWPL:
// case AT91C_EFC_FCMD_EPL:
// case AT91C_EFC_FCMD_EPA:
case AT91C_EFC_FCMD_SLB:
case AT91C_EFC_FCMD_CLB:
n = (pPrivate->size_bytes / pPrivate->page_size);
LOG_ERROR("*BUG*: Embedded flash has only %u pages", (unsigned)(n));
}
break;
case AT91C_EFC_FCMD_SFB:
case AT91C_EFC_FCMD_CFB:
if (argument >= pPrivate->pChip->details.n_gpnvms) {
LOG_ERROR("*BUG*: Embedded flash has only %d GPNVMs",
case AT91C_EFC_FCMD_GETD:
case AT91C_EFC_FCMD_EA:
case AT91C_EFC_FCMD_GLB:
case AT91C_EFC_FCMD_GFB:
case AT91C_EFC_FCMD_STUI:
case AT91C_EFC_FCMD_SPUI:
LOG_ERROR("Argument is meaningless for cmd: %d", command);
}
break;
default:
LOG_ERROR("Unknown command %d", command);
break;
}
// this is a very special situation.
// Situation (1) - error/retry - see below
// And we are being called recursively
// Situation (2) - normal, finished reading unique id
} else {
// it should be "ready"
// then it is ready
// we go on
} else {
// we have done this before
// the controller is not responding.
LOG_ERROR("flash controller(%d) is not ready! Error", pPrivate->bank_number);
return ERROR_FAIL;
} else {
retry++;
LOG_ERROR("Flash controller(%d) is not ready, attempting reset",
// we do that by issuing the *STOP* command
EFC_StartCommand(pPrivate, AT91C_EFC_FCMD_SPUI, 0);
// above is recursive, and further recursion is blocked by
// if (command == AT91C_EFC_FCMD_SPUI) above
goto do_retry;
}
}
}
v = (0x5A << 24) | (argument << 8) | command;
LOG_DEBUG("Command: 0x%08x", ((unsigned int)(v)));
r = target_write_u32(pPrivate->pBank->target,
pPrivate->controller_address + offset_EFC_FCR,
v);
LOG_DEBUG("Error Write failed");
}
return r;
}
/**
* Performs the given command and wait until its completion (or an error).
* @param pPrivate - info about the bank
* @param command - Command to perform.
* @param argument - Optional command argument.
* @param status - put command status bits here
*/
static int
EFC_PerformCommand(struct sam3_bank_private *pPrivate,
unsigned command,
unsigned argument,
uint32_t *status)
{
int r;
uint32_t v;
long long ms_now, ms_end;
r = EFC_StartCommand(pPrivate, command, argument);
return r;
}
ms_end = 500 + timeval_ms();
do {
return r;
}
ms_now = timeval_ms();
// error
LOG_ERROR("Command timeout");
return ERROR_FAIL;
}
}
*status = (v & 0x6);
}
return ERROR_OK;
}
/**
* Read the unique ID.
* @param pPrivate - info about the bank
* The unique ID is stored in the 'pPrivate' structure.
*/
static int
FLASHD_ReadUniqueID (struct sam3_bank_private *pPrivate)
{
int r;
uint32_t v;
int x;
// assume 0
pPrivate->pChip->cfg.unique_id[0] = 0;
pPrivate->pChip->cfg.unique_id[1] = 0;
pPrivate->pChip->cfg.unique_id[2] = 0;
pPrivate->pChip->cfg.unique_id[3] = 0;
LOG_DEBUG("Begin");
r = EFC_StartCommand(pPrivate, AT91C_EFC_FCMD_STUI, 0);
r = target_read_u32(pPrivate->pChip->target,
pPrivate->pBank->base + (x * 4),
return r;
}
pPrivate->pChip->cfg.unique_id[x] = v;
}
r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_SPUI, 0, NULL);
LOG_DEBUG("End: R=%d, id = 0x%08x, 0x%08x, 0x%08x, 0x%08x",
(unsigned int)(pPrivate->pChip->cfg.unique_id[0]),
(unsigned int)(pPrivate->pChip->cfg.unique_id[1]),
(unsigned int)(pPrivate->pChip->cfg.unique_id[2]),
(unsigned int)(pPrivate->pChip->cfg.unique_id[3]));
return r;
/**
* Erases the entire flash.
* @param pPrivate - the info about the bank.
*/
static int
FLASHD_EraseEntireBank(struct sam3_bank_private *pPrivate)
return EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_EA, 0, NULL);
/**
* Gets current GPNVM state.
* @param pPrivate - info about the bank.
* @param gpnvm - GPNVM bit index.
* @param puthere - result stored here.
*/
//------------------------------------------------------------------------------
FLASHD_GetGPNVM(struct sam3_bank_private *pPrivate, unsigned gpnvm, unsigned *puthere)
{
uint32_t v;
int r;
LOG_DEBUG("Here");
LOG_ERROR("GPNVM only works with Bank0");
return ERROR_FAIL;
}
LOG_ERROR("Invalid GPNVM %d, max: %d, ignored",
gpnvm,pPrivate->pChip->details.n_gpnvms);
return ERROR_FAIL;
}
// Get GPNVMs status
r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_GFB, 0, NULL);
LOG_ERROR("Failed");
return r;
}
*puthere = (v >> gpnvm) & 1;
}
return r;
}
/**
* Clears the selected GPNVM bit.
* @param pPrivate info about the bank
* @param gpnvm GPNVM index.
* @returns 0 if successful; otherwise returns an error code.
FLASHD_ClrGPNVM(struct sam3_bank_private *pPrivate, unsigned gpnvm)
{
int r;
unsigned v;
LOG_DEBUG("Here");
LOG_ERROR("GPNVM only works with Bank0");
return ERROR_FAIL;
}
LOG_ERROR("Invalid GPNVM %d, max: %d, ignored",
gpnvm,pPrivate->pChip->details.n_gpnvms);
r = FLASHD_GetGPNVM(pPrivate, gpnvm, &v);
LOG_DEBUG("Failed: %d",r);
return r;
}
r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_CFB, gpnvm, NULL);
LOG_DEBUG("End: %d",r);
return r;
}
/**
* Sets the selected GPNVM bit.
* @param pPrivate info about the bank
* @param gpnvm GPNVM index.
FLASHD_SetGPNVM(struct sam3_bank_private *pPrivate, unsigned gpnvm)
{
int r;
unsigned v;
LOG_ERROR("GPNVM only works with Bank0");
return ERROR_FAIL;
}
LOG_ERROR("Invalid GPNVM %d, max: %d, ignored",
gpnvm,pPrivate->pChip->details.n_gpnvms);
r = FLASHD_GetGPNVM(pPrivate, gpnvm, &v);
// already set
r = ERROR_OK;
} else {
// set it
r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_SFB, gpnvm, NULL);
/**
* Returns a bit field (at most 64) of locked regions within a page.
* @param pPrivate info about the bank
* @param v where to store locked bits
FLASHD_GetLockBits(struct sam3_bank_private *pPrivate, uint32_t *v)
{
int r;
LOG_DEBUG("Here");
r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_GLB, 0, NULL);
}
LOG_DEBUG("End: %d",r);
return r;
}
/**
* Unlocks all the regions in the given address range.
* @param pPrivate info about the bank
* @param start_sector first sector to unlock
* @param end_sector last (inclusive) to unlock
FLASHD_Unlock(struct sam3_bank_private *pPrivate,
{
int r;
uint32_t status;
uint32_t pg;
uint32_t pages_per_sector;
pages_per_sector = pPrivate->sector_size / pPrivate->page_size;
/* Unlock all pages */
pg = start_sector * pages_per_sector;
r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_CLB, pg, &status);
if (r != ERROR_OK) {
return r;
}
start_sector++;
}
return ERROR_OK;
}
/**
* Locks regions
* @param pPrivate - info about the bank
* @param start_sector - first sector to lock
* @param end_sector - last sector (inclusive) to lock
*/
FLASHD_Lock(struct sam3_bank_private *pPrivate,
{
uint32_t status;
uint32_t pg;
uint32_t pages_per_sector;
int r;
pages_per_sector = pPrivate->sector_size / pPrivate->page_size;
pg = start_sector * pages_per_sector;
r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_SLB, pg, &status);