blob: 4e18e6f165e7b96bce4f869403cef7e74be5367c [file] [log] [blame]
/**
* \file
*
* \brief Static Memory Controller (SMC) driver for SAM.
*
* Copyright (c) 2011-2013 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \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 microcontroller 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.
*
* \asf_license_stop
*
*/
#include "smc.h"
#include "board.h"
/// @cond 0
/**INDENT-OFF**/
#ifdef __cplusplus
extern "C" {
#endif
/**INDENT-ON**/
/// @endcond
/**
* \defgroup sam_drivers_smc_group Static Memory Controller (SMC)
*
* Driver for the Static Memory Controller. It provides functions for configuring
* and using the on-chip SMC.
*
* @{
*/
#if ((SAM3S) || (SAM3U) || (SAM3XA) || (SAM4S) || (SAM4E))
#define SMC_WPKEY_VALUE (0x534D43)
/**
* \brief Configure the SMC Setup timing for the specified Chip Select.
*
* \param p_smc Pointer to an SMC instance.
* \param ul_cs Chip Select number to be set.
* \param ul_setup_timing Setup timing for NWE, NCS, NRD.
*/
void smc_set_setup_timing(Smc *p_smc, uint32_t ul_cs,
uint32_t ul_setup_timing)
{
p_smc->SMC_CS_NUMBER[ul_cs].SMC_SETUP = ul_setup_timing;
}
/**
* \brief Configure the SMC pulse timing for the specified Chip Select.
*
* \param p_smc Pointer to an SMC instance.
* \param ul_cs Chip Select number to be set.
* \param ul_pulse_timing Pulse timing for NWE,NCS,NRD.
*/
void smc_set_pulse_timing(Smc *p_smc, uint32_t ul_cs,
uint32_t ul_pulse_timing)
{
p_smc->SMC_CS_NUMBER[ul_cs].SMC_PULSE = ul_pulse_timing;
}
/**
* \brief Configure the SMC cycle timing for the specified Chip Select.
*
* \param p_smc Pointer to an SMC instance.
* \param ul_cs Chip Select number to be set.
* \param ul_cycle_timing Cycle timing for NWE and NRD.
*/
void smc_set_cycle_timing(Smc *p_smc, uint32_t ul_cs,
uint32_t ul_cycle_timing)
{
p_smc->SMC_CS_NUMBER[ul_cs].SMC_CYCLE = ul_cycle_timing;
}
/**
* \brief Configure the SMC mode for the specified Chip Select.
*
* \param p_smc Pointer to an SMC instance.
* \param ul_cs Chip select number to be set.
* \param ul_mode SMC mode.
*/
void smc_set_mode(Smc *p_smc, uint32_t ul_cs, uint32_t ul_mode)
{
p_smc->SMC_CS_NUMBER[ul_cs].SMC_MODE = ul_mode;
}
/**
* \brief Get the SMC mode of the specified Chip Select.
*
* \param p_smc Pointer to an SMC instance.
* \param ul_cs Chip select number to be set.
*
* \return SMC mode.
*/
uint32_t smc_get_mode(Smc *p_smc, uint32_t ul_cs)
{
return p_smc->SMC_CS_NUMBER[ul_cs].SMC_MODE;
}
/**
* \brief Set write protection of SMC registers.
*
* \param p_smc Pointer to an SMC instance.
* \param ul_enable 1 to enable, 0 to disable.
*/
void smc_enable_writeprotect(Smc *p_smc, uint32_t ul_enable)
{
#if (SAM3S || SAM4S || SAM4E)
if (ul_enable)
p_smc->SMC_WPMR =
SMC_WPMR_WPKEY(SMC_WPKEY_VALUE) | SMC_WPMR_WPEN;
else
p_smc->SMC_WPMR = SMC_WPMR_WPKEY(SMC_WPKEY_VALUE);
#else
if (ul_enable)
p_smc->SMC_WPCR =
SMC_WPCR_WP_KEY(SMC_WPKEY_VALUE) |
SMC_WPCR_WP_EN;
else
p_smc->SMC_WPCR = SMC_WPCR_WP_KEY(SMC_WPKEY_VALUE);
#endif
}
/**
* \brief Get the status of SMC write protection register.
*
* \param p_smc Pointer to an SMC instance.
*
* \return Write protect status.
*/
uint32_t smc_get_writeprotect_status(Smc *p_smc)
{
return p_smc->SMC_WPSR;
}
#endif /* ((SAM3S) || (SAM3U) || (SAM3XA)) */
#if ((SAM3U) || (SAM3XA))
/**
* \brief Configure the SMC nand timing for the specified Chip Select.
* \param p_smc Pointer to an SMC instance.
* \param ul_cs Chip Select number to be set.
* \param ul_nand_timing nand timing for related signal.
*/
void smc_set_nand_timing(Smc *p_smc, uint32_t ul_cs,
uint32_t ul_nand_timing)
{
p_smc->SMC_CS_NUMBER[ul_cs].SMC_TIMINGS= ul_nand_timing;
}
/**
* \brief Initialize NFC configuration.
* \param p_smc Pointer to an SMC instance.
* \param ul_config SMC NFC Configuration.
*/
void smc_nfc_init(Smc *p_smc, uint32_t ul_config)
{
p_smc->SMC_CFG = ul_config;
}
/**
* \brief Set NFC page size.
*
* \param p_smc Pointer to an SMC instance.
* \param ul_page_size Use pattern defined in the device header file.
*/
void smc_nfc_set_page_size(Smc *p_smc, uint32_t ul_page_size)
{
p_smc->SMC_CFG &= (~SMC_CFG_PAGESIZE_Msk);
p_smc->SMC_CFG |= ul_page_size;
}
/**
* \brief Enable NFC controller to read both main and spare area in read mode.
*
* \param p_smc Pointer to an SMC instance.
*/
void smc_nfc_enable_spare_read(Smc *p_smc)
{
p_smc->SMC_CFG |= SMC_CFG_RSPARE;
}
/**
* \brief Prevent NFC controller from reading the spare area in read mode.
*
* \param p_smc Pointer to an SMC instance.
*/
void smc_nfc_disable_spare_read(Smc *p_smc)
{
p_smc->SMC_CFG &= (~SMC_CFG_RSPARE);
}
/**
* \brief Enable NFC controller to write both main and spare area in write mode.
*
* \param p_smc Pointer to an SMC instance.
*/
void smc_nfc_enable_spare_write(Smc *p_smc)
{
p_smc->SMC_CFG |= SMC_CFG_WSPARE;
}
/**
* \brief Prevent NFC controller from writing the spare area in read mode.
*
* \param p_smc Pointer to an SMC instance.
*/
void smc_nfc_disable_spare_write(Smc *p_smc)
{
p_smc->SMC_CFG &= (~SMC_CFG_WSPARE);
}
/**
* \brief Enable NFC controller.
*
* \param p_smc Pointer to an SMC instance.
*/
void smc_nfc_enable(Smc *p_smc)
{
p_smc->SMC_CTRL = SMC_CTRL_NFCEN;
}
/**
* \brief Disable NFC controller.
*
* \param p_smc Pointer to an SMC instance.
*/
void smc_nfc_disable(Smc *p_smc)
{
p_smc->SMC_CTRL = SMC_CTRL_NFCDIS;
}
/**
* \brief Get the NFC Status.
*
* \param p_smc Pointer to an SMC instance.
*
* \return Returns the current status register of SMC NFC Status Register.
* This resets the internal value of the status register, so further
* read may yield different values.
*/
uint32_t smc_nfc_get_status(Smc *p_smc)
{
return p_smc->SMC_SR;
}
/**
* \brief Enable SMC interrupts.
*
* \param p_smc Pointer to an SMC instance.
* \param ul_sources Interrupt source bitmap.
*/
void smc_nfc_enable_interrupt(Smc *p_smc, uint32_t ul_sources)
{
p_smc->SMC_IER = ul_sources;
}
/**
* \brief Disable SMC interrupts.
*
* \param p_smc Pointer to an SMC instance.
* \param ul_sources Interrupt source bitmap.
*/
void smc_nfc_disable_interrupt(Smc *p_smc, uint32_t ul_sources)
{
p_smc->SMC_IDR = ul_sources;
}
/**
* \brief Get the interrupt mask.
*
* \param p_smc Pointer to an SMC instance.
*
* \return Interrupt mask bitmap.
*/
uint32_t smc_nfc_get_interrupt_mask(Smc *p_smc)
{
return p_smc->SMC_IMR;
}
/**
* \brief Set flash cycle 0 address.
*
* \param p_smc Pointer to an SMC instance.
* \param uc_address0 Address cycle 0 in 5 address cycles.
*/
void smc_nfc_set_address0(Smc *p_smc, uint8_t uc_address0)
{
p_smc->SMC_ADDR = uc_address0;
}
/**
* \brief Set NFC sram bank.
*
* \param p_smc Pointer to an SMC instance.
* \param ul_bank NFC sram bank.
*/
void smc_nfc_set_bank(Smc *p_smc, uint32_t ul_bank)
{
p_smc->SMC_BANK = SMC_BANK_BANK(ul_bank);
}
/**
* \brief Use the HOST nandflash controller to send a command.
*
* \param p_smc Pointer to an SMC instance.
* \param ul_cmd Command to send.
* \param ul_address_cycle Address cycle when command access is decoded.
* \param ul_cycle0 Address at first cycle.
*/
void smc_nfc_send_command(Smc *p_smc, uint32_t ul_cmd,
uint32_t ul_address_cycle, uint32_t ul_cycle0)
{
volatile uint32_t *p_command_address;
/* Wait until host controller is not busy. */
while (((*((volatile uint32_t *)(BOARD_NF_DATA_ADDR + NFCADDR_CMD_NFCCMD)))
& NFC_BUSY_FLAG) == NFC_BUSY_FLAG) {
}
/* Send the command plus the ADDR_CYCLE. */
p_command_address = (volatile uint32_t *)(ul_cmd + BOARD_NF_DATA_ADDR);
p_smc->SMC_ADDR = ul_cycle0;
*p_command_address = ul_address_cycle;
while (!((p_smc->SMC_SR & SMC_SR_CMDDONE) == SMC_SR_CMDDONE)) {
}
}
/**
* \brief Initialize ECC mode.
*
* \param p_smc Pointer to an SMC instance.
* \param ul_type Type of correction, use pattern defined in the device header file.
* \param ul_pagesize Page size of NAND Flash device, use pattern defined in
* the device header file.
*/
void smc_ecc_init(Smc *p_smc, uint32_t ul_type, uint32_t ul_pagesize)
{
/* Software Reset ECC. */
p_smc->SMC_ECC_CTRL = SMC_ECC_CTRL_SWRST;
p_smc->SMC_ECC_MD = ul_type | ul_pagesize;
}
/**
* \brief Get ECC status by giving ecc number.
*
* \param p_smc Pointer to an SMC instance.
* \param ul_parity_number ECC parity number from 0 to 15.
*
* \return ECC status by giving ECC number.
*/
uint32_t smc_ecc_get_status(Smc *p_smc, uint32_t ul_parity_number)
{
uint32_t status;
if (ul_parity_number < 8) {
status = p_smc->SMC_ECC_SR1;
} else {
status = p_smc->SMC_ECC_SR2;
ul_parity_number -= 8;
}
return ((status >> (ul_parity_number * 4)) & ECC_STATUS_MASK);
}
/**
* \brief Get all ECC parity registers value.
*
* \param p_smc Pointer to an SMC instance.
* \param p_ecc Pointer to a parity buffer.
*/
void smc_ecc_get_value(Smc *p_smc, uint32_t *p_ecc)
{
p_ecc[0] = p_smc->SMC_ECC_PR0;
p_ecc[1] = p_smc->SMC_ECC_PR1;
p_ecc[2] = p_smc->SMC_ECC_PR2;
p_ecc[3] = p_smc->SMC_ECC_PR3;
p_ecc[4] = p_smc->SMC_ECC_PR4;
p_ecc[5] = p_smc->SMC_ECC_PR5;
p_ecc[6] = p_smc->SMC_ECC_PR6;
p_ecc[7] = p_smc->SMC_ECC_PR7;
p_ecc[8] = p_smc->SMC_ECC_PR8;
p_ecc[9] = p_smc->SMC_ECC_PR9;
p_ecc[10] = p_smc->SMC_ECC_PR10;
p_ecc[11] = p_smc->SMC_ECC_PR11;
p_ecc[12] = p_smc->SMC_ECC_PR12;
p_ecc[13] = p_smc->SMC_ECC_PR13;
p_ecc[14] = p_smc->SMC_ECC_PR14;
p_ecc[15] = p_smc->SMC_ECC_PR15;
}
#endif /* ((SAM3U) || (SAM3XA)) */
//@}
/// @cond 0
/**INDENT-OFF**/
#ifdef __cplusplus
}
#endif
/**INDENT-ON**/
/// @endcond