Beispiel #1
0
void efm32_flash_lock(void)
{
  /* Disable writing to the flash */

  bitband_set_peripheral(EFM32_MSC_WRITECTRL, _MSC_WRITECTRL_WREN_SHIFT, 0);

  /* Unlock the EFM32_MSC */

  putreg32(0, EFM32_MSC_LOCK);
}
Beispiel #2
0
void efm32_flash_unlock(void)
{
  uint32_t regval;

  /* Unlock the EFM32_MSC */

  putreg32(MSC_UNLOCK_CODE, EFM32_MSC_LOCK);

  /* Disable writing to the flash */

  bitband_set_peripheral(EFM32_MSC_WRITECTRL, _MSC_WRITECTRL_WREN_SHIFT, 0);

#if defined(_MSC_TIMEBASE_MASK)

  regval = getreg32(EFM32_MSC_TIMEBASE);
  regval &= ~(_MSC_TIMEBASE_BASE_MASK | _MSC_TIMEBASE_PERIOD_MASK);

  /* Configure EFM32_MSC_TIMEBASE according to selected frequency */

  if (BOARD_AUXCLK_FREQUENCY > 7000000)
    {
      uint32_t freq;
      uint32_t cycles;

      /* Calculate number of clock cycles for 1us as base period */

      freq   = (BOARD_AUXCLK_FREQUENCY * 11) / 10;
      cycles = (freq / 1000000) + 1;

      /* Configure clock cycles for flash timing */

      regval |= MSC_TIMEBASE_PERIOD_1US;
      regval |= (cycles << _MSC_TIMEBASE_BASE_SHIFT);
    }
  else
    {
      uint32_t freq;
      uint32_t cycles;

      /* Calculate number of clock cycles for 5us as base period */

      freq   = (BOARD_AUXCLK_FREQUENCY * 5 * 11) / 10;
      cycles = (freq / 1000000) + 1;

      /* Configure clock cycles for flash timing */

      regval |= MSC_TIMEBASE_PERIOD_5US;
      regval |= (cycles << _MSC_TIMEBASE_BASE_SHIFT);
    }

  putreg32(regval, EFM32_MSC_TIMEBASE);

#endif
}
void efm32_gpioirqclear(int irq)
{
  if (irq >= EFM32_IRQ_EXTI0 && irq <= EFM32_IRQ_EXTI15)
    {
      /* Enable the interrupt associated with the pin */

#ifndef CONFIG_EFM32_BITBAND
      irqstate_t flags;
      uint32_t regval;
      uint32_t bit;

      bit     = ((uint32_t)1 << (irq - EFM32_IRQ_EXTI0));
      flags   = irqsave();
      regval  = getreg32(EFM32_GPIO_IFC);
      regval |= bit;
      putreg32(regval, EFM32_GPIO_IFC);
      irqrestore(flags);
#else
      bitband_set_peripheral(EFM32_GPIO_IFC, (irq - EFM32_IRQ_EXTI0), 1);
#endif
    }
}
Beispiel #4
0
static void efm32_rtc_burtc_init(void)
{
  uint32_t regval;
  uint32_t regval2;

  regval = g_efm32_rstcause;
  regval2 = getreg32(EFM32_BURTC_CTRL);

  burtcdbg("BURTC RESETCAUSE=0x%08X BURTC_CTRL=0x%08X\n", regval, regval2);

  if (!(regval2 & BURTC_CTRL_RSTEN) &&
      !(regval  & RMU_RSTCAUSE_BUBODREG) &&
      !(regval  & RMU_RSTCAUSE_BUBODUNREG) &&
      !(regval  & RMU_RSTCAUSE_BUBODBUVIN) &&
      !(regval  & RMU_RSTCAUSE_EXTRST) &&
      !(regval  & RMU_RSTCAUSE_PORST))
    {
      g_efm32_burtc_reset_status = getreg32(EFM32_BURTC_STATUS);

      /* Reset timestamp BURTC clear status */

      putreg32(BURTC_CMD_CLRSTATUS, EFM32_BURTC_CMD);

      /* restore saved base time */

      burtcdbg("BURTC OK\n");
      return;
    }

  burtcdbg("BURTC RESETED\n");

  /* Disable reset of BackupDomain */

  bitband_set_peripheral(EFM32_RMU_CTRL, _RMU_CTRL_BURSTEN_SHIFT, 0);

  /* Make sure all registers are updated simultaneously */

  putreg32(BURTC_FREEZE_REGFREEZE_FREEZE, EFM32_BURTC_FREEZE);

  /* Restore all not setted BURTC registers to default value */

//  putreg32(_BURTC_LPMODE_RESETVALUE,      EFM32_BURTC_LPMODE);
//  putreg32(_BURTC_LFXOFDET_RESETVALUE,    EFM32_BURTC_LFXOFDET);
//  putreg32(_BURTC_COMP0_RESETVALUE,       EFM32_BURTC_COMP0);

  /* New configuration */

  regval = ((BOARD_BURTC_MODE) |
            (BURTC_CTRL_DEBUGRUN_DEFAULT) |
            (BURTC_CTRL_COMP0TOP_DEFAULT) |
            (BURTC_CTRL_LPCOMP_DEFAULT) |
            (BOARD_BURTC_PRESC) |
            (BOARD_BURTC_CLKSRC) |
            (BURTC_CTRL_BUMODETSEN_DEFAULT));

  /* Clear interrupts */

  putreg32(0xFFFFFFFF, EFM32_BURTC_IFC);

  /* Set new configuration */

  putreg32(regval | BURTC_CTRL_RSTEN, EFM32_BURTC_CTRL);

  /* Clear freeze */

  putreg32(0, EFM32_BURTC_FREEZE);

  /* To enable BURTC counter, we need to disable reset */

  putreg32(regval, EFM32_BURTC_CTRL);

  /* Enable BURTC interrupt on compare match and counter overflow */

  putreg32(BURTC_IF_OF | BURTC_IF_LFXOFAIL, EFM32_BURTC_IEN);

  /* Lock BURTC to avoid modification */

  putreg32(BURTC_LOCK_LOCKKEY_LOCK, EFM32_BURTC_LOCK);

  /* reset BURTC retention REG used */

  putreg32(0, __CNT_CARRY_REG);
  putreg32(0, __CNT_ZERO_REG);

  /* inform rest of software that BURTC was reset at boot */

  g_efm32_burtc_reseted = true;
}
Beispiel #5
0
ssize_t __ramfunc__ up_progmem_write(size_t addr, const void *buf, size_t size)
{
  int       ret = 0;
  int       word_count;
  int       num_words;
  int       page_words;
  uint32_t *p_data;
  uint32_t *address = (uint32_t *)addr;
  uint32_t  num_bytes = size;

  /* EFM32 requires word access */

  if (addr & 3)
    {
      return -EINVAL;
    }

  /* EFM32 requires word access */

  if (num_bytes & 3)
    {
      return -EINVAL;
    }

  efm32_flash_unlock();

  /* enable writing to the flash */

  bitband_set_peripheral(EFM32_MSC_WRITECTRL, _MSC_WRITECTRL_WREN_SHIFT, 1);

  /* Convert bytes to words */

  num_words = num_bytes >> 2;

  /* The following loop splits the data into chunks corresponding to flash pages.
   * The address is loaded only once per page, because the hardware automatically
   * increments the address internally for each data load inside a page.
   */

  for (word_count = 0, p_data = (uint32_t *)buf; word_count < num_words; )
    {
      int page_bytes;
      ssize_t page_idx;
      irqstate_t flags;

      /* Compute the number of words to write to the current page. */

      page_idx = up_progmem_getpage((size_t)address+(word_count << 2));
      if (page_idx < 0)
        {
          ret = -EINVAL;
          break;
        }

      page_bytes = up_progmem_pagesize(page_idx);
      if (page_bytes < 0)
        {
          ret = -EINVAL;
          break;
        }

      page_words = (page_bytes - (((uint32_t) (address + word_count)) & \
                    (page_bytes-1))) / sizeof(uint32_t);

      if (page_words > num_words - word_count)
        {
          page_words = num_words - word_count;
        }

      flags = enter_critical_section();

      /* First we load address. The address is auto-incremented within a page.
       * Therefore the address phase is only needed once for each page.
       */

      ret = msc_load_verify_address(address + word_count);

      /* Now write the data in the current page. */

      if (ret == 0)
        {
          ret = msc_load_write_data(p_data, page_words, true);
        }

      leave_critical_section(flags);

      if (ret != 0)
        {
          break;
        }

      word_count += page_words;
      p_data += page_words;
    }

  /* Disable writing to the MSC */

  bitband_set_peripheral(EFM32_MSC_WRITECTRL, _MSC_WRITECTRL_WREN_SHIFT, 0);

#if (defined(CONFIG_EFM32_EFM32GG) || defined(CONFIG_EFM32_EFM32WG)) && (2==WORDS_PER_DATA_PHASE)

  /* Turn off double word write cycle support. */

  bitband_set_peripheral(EFM32_MSC_WRITECTRL, _MSC_WRITECTRL_WDOUBLE_SHIFT, 0);

#endif

  if (ret < 0)
    {
      return ret;
    }

  return word_count;
}
Beispiel #6
0
ssize_t __ramfunc__ up_progmem_erasepage(size_t page)
{
  int ret = 0;
  int timeout;
  uint32_t regval;
  irqstate_t flags;

  if (page >= (EFM32_FLASH_NPAGES+EFM32_USERDATA_NPAGES))
    {
      return -EFAULT;
    }

  efm32_flash_unlock();

  flags = enter_critical_section();

  /* enable writing to the flash */

  bitband_set_peripheral(EFM32_MSC_WRITECTRL, _MSC_WRITECTRL_WREN_SHIFT, 1);

  /* Load address */

  putreg32((uint32_t)up_progmem_getaddress(page), EFM32_MSC_ADDRB);
  putreg32(MSC_WRITECMD_LADDRIM, EFM32_MSC_WRITECMD);

  regval = getreg32(EFM32_MSC_STATUS);

  /* Check for invalid address */

  if (regval & MSC_STATUS_INVADDR)
    {
      ret = -EINVAL;
    }

  /* Check for write protected page */

  if ((ret == 0) && (regval & MSC_STATUS_LOCKED))
    {
      ret = -EPERM;
    }

  /* Send erase page command */

  if (ret == 0)
    {
      putreg32(MSC_WRITECMD_ERASEPAGE, EFM32_MSC_WRITECMD);

      /* Wait for the erase to complete */

      timeout = MSC_PROGRAM_TIMEOUT;
      while ((getreg32(EFM32_MSC_STATUS) & MSC_STATUS_BUSY) && (timeout != 0))
        {
          timeout--;
        }

      if (timeout == 0)
        {
          ret = -ETIMEDOUT;
        }
    }

  /* Disable writing to the MSC */

  bitband_set_peripheral(EFM32_MSC_WRITECTRL, _MSC_WRITECTRL_WREN_SHIFT, 0);

  if (ret == 0)
    {
      /* Verify */

      if (up_progmem_ispageerased(page) != 0)
        {
          ret = -EIO;
        }
    }

  leave_critical_section(flags);

  if (ret != 0)
    {
      return ret;
    }

  /* Success */

  return up_progmem_pagesize(page);
}
Beispiel #7
0
int __ramfunc__ msc_load_write_data(uint32_t *data, uint32_t num_words,
                                    bool write_strategy_safe)
{
  int timeout;
  int word_index;
  int words_per_data_phase;
  int ret = 0;

#if defined(_MSC_WRITECTRL_LPWRITE_MASK) && defined(_MSC_WRITECTRL_WDOUBLE_MASK)

  /* If LPWRITE (Low Power Write) is NOT enabled, set WDOUBLE (Write Double word) */

  if (!(getreg32(EFM32_MSC_WRITECTRL) & MSC_WRITECTRL_LPWRITE))
    {
      /* If the number of words to be written are odd, we need to align by writing
       * a single word first, before setting the WDOUBLE bit.
       */

      if (num_words & 0x1)
        {
          /* Wait for the msc to be ready for the next word. */

          timeout = MSC_PROGRAM_TIMEOUT;
          while ((!(getreg32(EFM32_MSC_STATUS) & MSC_STATUS_WDATAREADY)) && \
                 (timeout != 0))
            {
              timeout--;
            }

          /* Check for timeout */

          if (timeout == 0)
            {
              return -ETIMEDOUT;
            }

          /* Clear double word option, in order to write one single word. */

          bitband_set_peripheral(EFM32_MSC_WRITECTRL, _MSC_WRITECTRL_WDOUBLE_SHIFT, 0);

          /* Write first data word. */

          putreg32(*data++, EFM32_MSC_WDATA);
          putreg32(MSC_WRITECMD_WRITEONCE, EFM32_MSC_WRITECMD);

          /* Wait for the operation to finish. It may be required to change the
           * WDOUBLE config after the initial write. It should not be changed
           * while BUSY.
           */

          timeout = MSC_PROGRAM_TIMEOUT;
          while ((getreg32(EFM32_MSC_STATUS) & MSC_STATUS_BUSY) && (timeout != 0))
            {
              timeout--;
            }

          /* Check for timeout */

          if (timeout == 0)
            {
              return -ETIMEDOUT;
            }

          /* Subtract this initial odd word for the write loop below */

          num_words --;
          ret = 0;
        }

      /* Now we can set the double word option in order to write two words per
       * data phase.
       */

      bitband_set_peripheral(EFM32_MSC_WRITECTRL, _MSC_WRITECTRL_WDOUBLE_SHIFT, 1);
      words_per_data_phase = 2;
    }
  else
#endif
    {
        words_per_data_phase = 1;
    }

  /* Write the rest as double word write if wordsPerDataPhase == 2 */

  if (num_words > 0)
    {
      /* Write strategy: msc_write_int_safe */

      if (write_strategy_safe)
        {

          /* Requires a system core clock at 1MHz or higher */

          DEBUGASSERT(BOARD_SYSTEM_FREQUENCY >= 1000000);

          word_index = 0;
          while (word_index < num_words)
            {
              putreg32(*data++, EFM32_MSC_WDATA);
              word_index++;
              if (words_per_data_phase == 2)
                {
                  while (!(getreg32(EFM32_MSC_STATUS) & MSC_STATUS_WDATAREADY))
                    {
                    }

                  putreg32(*data++, EFM32_MSC_WDATA);
                  word_index++;
                }

              putreg32(MSC_WRITECMD_WRITEONCE, EFM32_MSC_WRITECMD);

              /* Wait for the transaction to finish. */

              timeout = MSC_PROGRAM_TIMEOUT;
              while ((getreg32(EFM32_MSC_STATUS) & MSC_STATUS_BUSY) && \
                     (timeout != 0))
                {
                  timeout--;
                }

              /* Check for timeout */

              if (timeout == 0)
                {
                  ret = -ETIMEDOUT;
                  break;
                }

#if defined(CONFIG_EFM32_EFM32G)
              putreg32(getreg32(EFM32_MSC_ADDRB)+4, EFM32_MSC_ADDRB);
              putreg32(MSC_WRITECMD_LADDRIM, EFM32_MSC_WRITECMD);
#endif
            }
        }

      /* Write strategy: msc_write_fast */

      else
        {
#if defined(CONFIG_EFM32_EFM32G)

          /* Gecko does not have auto-increment of ADDR. */

          DEBUGASSERT(0);
#else

          /* Requires a system core clock at 14MHz or higher */

          DEBUGASSERT(BOARD_SYSTEM_FREQUENCY >= 14000000);

          word_index = 0;

          while (word_index < num_words)
            {

              /* Wait for the MSC to be ready for the next word. */

              while (!(getreg32(EFM32_MSC_STATUS) & MSC_STATUS_WDATAREADY))
                {
                  uint32_t regval;

                  /* If the write to MSC->WDATA below missed the 30us timeout
                   * and the following MSC_WRITECMD_WRITETRIG command arrived
                   * while MSC_STATUS_BUSY is 1, then the MSC_WRITECMD_WRITETRIG
                   * could be ignored by the MSC. In this case,
                   * MSC_STATUS_WORDTIMEOUT is set to 1 and MSC_STATUS_BUSY is
                   * 0. A new trigger is therefore needed here to complete write
                   * of data in MSC->WDATA. If WDATAREADY became high since
                   * entry into this loop, exit and continue to the next WDATA
                   * write.
                   */

                  regval = getreg32(EFM32_MSC_STATUS);
                  regval &= MSC_STATUS_WORDTIMEOUT;
                  regval &= MSC_STATUS_BUSY;
                  regval &= MSC_STATUS_WDATAREADY;
                  if (regval == MSC_STATUS_WORDTIMEOUT)
                    {
                      putreg32(MSC_WRITECMD_WRITETRIG, EFM32_MSC_WRITECMD);
                    }
                }

              putreg32(*data, EFM32_MSC_WDATA);
              if ((words_per_data_phase == 1) || \
                  ((words_per_data_phase == 2) && (word_index & 0x1)))
                {
                  putreg32(MSC_WRITECMD_WRITETRIG, EFM32_MSC_WRITECMD);
                }

              data++;
              word_index++;
            }

          /* Wait for the transaction to finish. */

          timeout = MSC_PROGRAM_TIMEOUT;
          while ((getreg32(EFM32_MSC_STATUS) & MSC_STATUS_BUSY) && \
                 (timeout != 0))
            {
              timeout--;
            }

          /* Check for timeout */

          if (timeout == 0)
            {
              ret = -ETIMEDOUT;
            }
#endif
        }
    }
#ifdef _MSC_WRITECTRL_WDOUBLE_MASK

  /* Clear double word option, which should not be left on when returning. */

  bitband_set_peripheral(EFM32_MSC_WRITECTRL, _MSC_WRITECTRL_WDOUBLE_SHIFT, 0);

#endif

  return ret;
}