blob: 35b7ca3e94b0092b329c8f4d94efe655faca5aac [file] [log] [blame]
/**
* \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);
}