/** | |
* \file | |
* | |
* \brief In system programming to control security, memories and fuses | |
* | |
* Copyright (C) 2009 Atmel Corporation. All rights reserved. | |
* | |
* \page License | |
* | |
* 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. The name of Atmel may not be used to endorse or promote products derived | |
* from this software without specific prior written permission. | |
* | |
* 4. This software may only be redistributed and used in connection with an | |
* Atmel AVR product. | |
* | |
* 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 | |
* EXPRESSLY AND SPECIFICALLY 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. | |
*/ | |
#include "conf_isp.h" | |
#include "board.h" | |
#include "isp.h" | |
#include "boot.h" | |
#include "string.h" | |
#include "flash_api.h" | |
#include "udc.h" | |
#if UC3C || UC3D | |
// These defines are missing from or wrong | |
// in the toolchain header file ip_xxx.h or part.h | |
#ifndef AVR32_WDT_KEY_VALUE | |
#define AVR32_WDT_KEY_VALUE 0x00000055 | |
#endif | |
// These defines are missing from or wrong | |
// in the toolchain header file ip_xxx.h or part.h | |
#ifndef AVR32_SCIF_RCOSC_FREQUENCY | |
#define AVR32_SCIF_RCOSC_FREQUENCY 115200 | |
#endif | |
#endif | |
extern void sysclk_reset(void); | |
/** | |
* \name Memory APIs | |
*/ | |
//@{ | |
//! Memory signature which store information about device | |
static isp_mem_signature_t mem_signature; | |
//! Memory bootloader which store information about bootloader | |
static isp_mem_bootloader_t mem_bootloader = { | |
.version = BOOTLOADER_VERSION, | |
.id1 = 0, | |
.id2 = 0, | |
}; | |
void mem_flash_read(void *dst, uint32_t src, uint16_t nbytes) | |
{ | |
memcpy(dst, FLASH_API_BASE_ADDRESS + src, nbytes); | |
} | |
void mem_flash_write(uint32_t dst, const void *src, uint16_t nbytes) | |
{ | |
flash_api_memcpy(FLASH_API_BASE_ADDRESS + dst, src, nbytes, FALSE); | |
} | |
void mem_security_read(void *dst, uint32_t src, uint16_t nbytes) | |
{ | |
if (nbytes) { | |
*(U8 *) dst = flash_api_is_security_bit_active(); | |
} | |
} | |
void mem_security_write(uint32_t dst, const void *src, uint16_t nbytes) | |
{ | |
if (nbytes && *(U8 *) src) { | |
flash_api_activate_security_bit(); | |
} | |
} | |
void mem_configuration_read(void *dst, uint32_t src, uint16_t nbytes) | |
{ | |
U8 *dest = dst; | |
while (nbytes--) { | |
*dest++ = flash_api_read_gp_fuse_bit(src++); | |
} | |
} | |
void mem_configuration_write(uint32_t dst, const void *src, uint16_t nbytes) | |
{ | |
const U8 *source = src; | |
while (nbytes--) { | |
flash_api_set_gp_fuse_bit(dst++, *source++); | |
} | |
} | |
static void mem_bootloader_read(void *dst, uint32_t src, uint16_t nbytes) | |
{ | |
memcpy(dst, &mem_bootloader + src, nbytes); | |
} | |
void mem_signature_read(void *dst, uint32_t src, uint16_t nbytes) | |
{ | |
memcpy(dst, &mem_signature + src, nbytes); | |
} | |
void mem_user_read(void *dst, uint32_t src, uint16_t nbytes) | |
{ | |
memcpy(dst, (U8 *) FLASH_API_USER_PAGE + src, nbytes); | |
} | |
void mem_user_write(uint32_t dst, const void *src, uint16_t nbytes) | |
{ | |
flash_api_memcpy(FLASH_API_USER_PAGE + dst, src, nbytes, TRUE); | |
} | |
//! Interface for memory flash | |
const isp_mem_t isp_flash = { | |
.size = FLASH_API_SIZE, | |
.fnct_read = mem_flash_read, | |
.fnct_write = mem_flash_write, | |
}; | |
//! Interface for bit security | |
const isp_mem_t isp_security = { | |
.size = 1, | |
.fnct_read = mem_security_read, | |
.fnct_write = mem_security_write, | |
}; | |
//! Interface for memory configuration | |
const isp_mem_t isp_conf = { | |
.size = FLASH_API_GPF_NUM, | |
.fnct_read = mem_configuration_read, | |
.fnct_write = mem_configuration_write, | |
}; | |
//! Interface for memory bootloader | |
const isp_mem_t isp_bootloader = { | |
.size = sizeof(mem_bootloader), | |
.fnct_read = mem_bootloader_read, | |
.fnct_write = NULL, | |
}; | |
//! Interface for memory signature | |
const isp_mem_t isp_signature = { | |
.size = sizeof(mem_signature), | |
.fnct_read = mem_signature_read, | |
.fnct_write = NULL, | |
}; | |
//! Interface for memory user | |
const isp_mem_t isp_user = { | |
.size = FLASH_API_USER_PAGE_SIZE, | |
.fnct_read = mem_user_read, | |
.fnct_write = mem_user_write, | |
}; | |
//! Interface for memory no available | |
const isp_mem_t isp_no_available = { | |
.size = 0, | |
.fnct_read = NULL, | |
.fnct_write = NULL, | |
}; | |
const isp_mems_t isp_memories = { | |
.flash = &isp_flash, | |
.eeprom = &isp_no_available, | |
.security = &isp_security, | |
.conf = &isp_conf, | |
.bootloader = &isp_bootloader, | |
.signature = &isp_signature, | |
.user = &isp_user, | |
.int_ram = &isp_no_available, | |
.ext_mem_cs0 = &isp_no_available, | |
.ext_mem_cs1 = &isp_no_available, | |
.ext_mem_cs2 = &isp_no_available, | |
.ext_mem_cs3 = &isp_no_available, | |
.ext_mem_cs4 = &isp_no_available, | |
.ext_mem_cs5 = &isp_no_available, | |
.ext_mem_cs6 = &isp_no_available, | |
.ext_mem_cs7 = &isp_no_available, | |
.ext_mem_df = &isp_no_available, | |
}; | |
//@} | |
void isp_init(void) | |
{ | |
uint32_t did_reg = Get_debug_register(AVR32_DID); | |
mem_signature.manufacture = | |
Rd_bitfield(did_reg, AVR32_DID_MID_MASK); | |
mem_signature.product_number_msb = | |
Rd_bitfield(did_reg, AVR32_DID_PN_MASK)>>8; | |
mem_signature.product_number_lsb = | |
Rd_bitfield(did_reg, AVR32_DID_PN_MASK); | |
mem_signature.product_revision = | |
Rd_bitfield(did_reg, AVR32_DID_RN_MASK); | |
} | |
bool isp_is_security(void) | |
{ | |
uint8_t value; | |
isp_security.fnct_read(&value, 0, 1); | |
return value; | |
} | |
#ifdef UDI_DFU_ATMEL_PROTOCOL_2_SPLIT_ERASE_CHIP | |
bool isp_erase_chip(void) | |
{ | |
static uint16_t isp_page_number=0; | |
uint8_t isp_page_number_split; | |
if (isp_page_number==0) { | |
isp_page_number = flash_api_get_page_count(); | |
flash_api_lock_all_regions(FALSE); | |
} | |
isp_page_number_split = 128; | |
while (isp_page_number && isp_page_number_split) { | |
flash_api_erase_page(--isp_page_number, FALSE); | |
isp_page_number_split--; | |
} | |
return (isp_page_number==0); | |
} | |
#else | |
bool isp_erase_chip(void) | |
{ | |
flash_api_lock_all_regions(FALSE); | |
flash_api_erase_all_pages(FALSE); | |
return true; | |
} | |
#endif | |
void isp_start_appli_rst(void) | |
{ | |
cpu_irq_disable(); | |
AVR32_WDT.ctrl = AVR32_WDT_CTRL_EN_MASK | | |
(10 << AVR32_WDT_CTRL_PSEL_OFFSET) | | |
#if (UC3C || UC3D) | |
AVR32_WDT_CTRL_CEN_MASK | AVR32_WDT_CTRL_DAR_MASK | | |
#endif | |
(AVR32_WDT_KEY_VALUE << AVR32_WDT_CTRL_KEY_OFFSET); | |
AVR32_WDT.ctrl = AVR32_WDT_CTRL_EN_MASK | | |
(10 << AVR32_WDT_CTRL_PSEL_OFFSET) | | |
#if (UC3C || UC3D) | |
AVR32_WDT_CTRL_CEN_MASK | AVR32_WDT_CTRL_DAR_MASK | | |
#endif | |
((~AVR32_WDT_KEY_VALUE << AVR32_WDT_CTRL_KEY_OFFSET) & | |
AVR32_WDT_CTRL_KEY_MASK); | |
while (1); | |
} | |
void isp_start_appli_norst(void) | |
{ | |
udc_stop(); // Stop USB device | |
sysclk_reset(); // Reset system clock | |
boot_program(); | |
} | |
/** | |
* Calculates the CRC-8-CCITT. | |
* | |
* CRC-8-CCITT is defined to be x^8 + x^2 + x + 1 | |
* | |
* To use this function use the following template: | |
* | |
* crc = Crc8( crc, data ); | |
*/ | |
#define POLYNOMIAL (ISP_CFG1_CRC8_POLYNOMIAL << 7) | |
static U8 Crc8(U8 inCrc, U8 inData) | |
{ | |
int i; | |
U16 data; | |
data = inCrc ^ inData; | |
data <<= 8; | |
for (i = 0; i < 8; i++) { | |
if ((data & 0x8000) != 0) { | |
data = data ^ POLYNOMIAL; | |
} | |
data = data << 1; | |
} | |
return (unsigned char)(data >> 8); | |
} | |
void isp_force_isp(bool force) | |
{ | |
uint32_t tempo; | |
U8 crc8 = 0; | |
int i; | |
// 1) Read the config word1 and set the ISP_FORCE bit to force. | |
tempo = (ISP_CFG1 & ~ISP_CFG1_FORCE_MASK) | |
| ((force << ISP_CFG1_FORCE_OFFSET) & ISP_CFG1_FORCE_MASK); | |
// 2) Compute the CRC8 and update the config word1 | |
for (i = 24; i; i -= 8) // Compute the CRC8 on the 3 upper Bytes of the word. | |
crc8 = Crc8(crc8, tempo >> i); | |
tempo = (tempo & ~ISP_CFG1_CRC8_MASK) | |
| ((crc8 << ISP_CFG1_CRC8_OFFSET) & ISP_CFG1_CRC8_MASK); | |
// 3) Write the config word1 | |
mem_user_write(ISP_CFG1_OFFSET, &tempo, 4); | |
} | |