Ejemplo n.º 1
0
/* Write the Configuration Register.
 * This updates the states of the corresponding clocks.  The bit values are not
 * saved - when the register is read, its value will be built using the clock
 * states.
 */
static void stm32_rcc_RCC_CR_write(Stm32Rcc *s, uint32_t new_value, bool init)
{
    bool new_pllon, new_hseon, new_hsion;

    new_pllon = new_value & BIT(RCC_CR_PLLON_BIT);
    if((clktree_is_enabled(s->PLLCLK) && !new_pllon) &&
       s->RCC_CFGR_SW == SW_PLL_SELECTED) {
        stm32_hw_warn("PLL cannot be disabled while it is selected as the system clock.");
    }
    clktree_set_enabled(s->PLL_VCO, new_pllon);
    clktree_set_enabled(s->PLLCLK, new_pllon);

    new_hseon = new_value & BIT(RCC_CR_HSEON_BIT);
    if((clktree_is_enabled(s->HSECLK) && !new_hseon) &&
       (s->RCC_CFGR_SW == SW_HSE_SELECTED ||
        (s->RCC_CFGR_SW == SW_PLL_SELECTED && s->RCC_PLLCFGR_PLLSRC == PLLSRC_HSE_SELECTED)
       )
      ) {
        stm32_hw_warn("HSE oscillator cannot be disabled while it is driving the system clock.");
    }
    clktree_set_enabled(s->HSECLK, new_hseon);

    new_hsion = new_value & BIT(RCC_CR_HSION_BIT);
    if((clktree_is_enabled(s->HSECLK) && !new_hseon) &&
       (s->RCC_CFGR_SW == SW_HSI_SELECTED ||
        (s->RCC_CFGR_SW == SW_PLL_SELECTED && s->RCC_PLLCFGR_PLLSRC == PLLSRC_HSI_SELECTED)
       )
      ) {
        stm32_hw_warn("HSI oscillator cannot be disabled while it is driving the system clock.");
    }
    clktree_set_enabled(s->HSICLK, new_hsion);
}
Ejemplo n.º 2
0
static void stm32_rcc_RCC_PLLCFGR_write(Stm32Rcc *s, uint32_t new_value, bool init)
{
    uint32_t new_PLLSRC, new_PLLP, new_PLLN, new_PLLM;
    /* PLLSRC */
    new_PLLSRC = extract32(new_value, RCC_PLLCFGR_PLLSRC_BIT, 1);
    if(!init) {
        if(clktree_is_enabled(s->PLLCLK) &&
           (new_PLLSRC != s->RCC_PLLCFGR_PLLSRC)) {
            stm32_hw_warn("Can only change PLLSRC while PLL is disabled");
        }
    }
    clktree_set_selected_input(s->PLLCLK, new_PLLSRC);
    s->RCC_PLLCFGR_PLLSRC = new_PLLSRC;

    new_PLLP = extract32(new_value,
                           RCC_PLLCFGR_PLLP_START,
                           RCC_PLLCFGR_PLLP_LENGTH);
    if(!init) {
          if(clktree_is_enabled(s->PLLCLK) &&
           (new_PLLP != s->RCC_PLLCFGR_PLLP)) {
               stm32_hw_warn("Can only change PLLP while PLL is disabled");
          }
    }
    assert(new_PLLP <= 0xf);
    clktree_set_scale(s->PLLCLK, 1, 2 + 2 * new_PLLP);

    s->RCC_PLLCFGR_PLLP = new_PLLP;

    new_PLLM = extract32(new_value,
                           RCC_PLLCFGR_PLLM_START,
                           RCC_PLLCFGR_PLLM_LENGTH);
    new_PLLN = extract32(new_value,
                           RCC_PLLCFGR_PLLN_START,
                           RCC_PLLCFGR_PLLN_LENGTH);

    if(!init) {
          if(clktree_is_enabled(s->PLLCLK) &&
           (new_PLLM != s->RCC_PLLCFGR_PLLM || new_PLLN != s->RCC_PLLCFGR_PLLN)) {
               stm32_hw_warn("Can only change PLLM/N while PLL is disabled");
          }
    }
    if(new_PLLN < 64 || new_PLLN > 432 ||
       new_PLLM < 2) {
       stm32_hw_warn("Invalid PLLM (%u) or PLLN (%u) set", new_PLLM, new_PLLN);
    } else {
        clktree_set_scale(s->PLL_VCO, new_PLLN, new_PLLM);
    }


    s->RCC_PLLCFGR_PLLM = new_PLLM;
    s->RCC_PLLCFGR_PLLN = new_PLLN;
    DPRINT("PLLP=%u, PLLM=%u, PLLN=%u\n", new_PLLP, new_PLLM, new_PLLN);
}
Ejemplo n.º 3
0
/* Enable the peripheral clock if the specified bit is set in the value. */
static void stm32_rcc_periph_enable(
                    Stm32Rcc *s,
                    uint32_t new_value,
                    bool init,
                    int periph,
                    uint32_t bit_pos)
{
    if(s->PERIPHCLK[periph] == NULL)
    {
        stm32_hw_warn("Attempted to enable clock that isn't set: %s", stm32_periph_name(periph));
        return;
    }
    if(new_value & BIT(bit_pos))
    {
        if(!clktree_is_enabled(s->PERIPHCLK[periph]))
            DPRINT("Enabling periphial %s\n", stm32_periph_name(periph));
    }
    else
    {
        if(clktree_is_enabled(s->PERIPHCLK[periph]))
            DPRINT("Disabling periphial %s\n", stm32_periph_name(periph));
    }

    clktree_set_enabled(s->PERIPHCLK[periph], new_value & BIT(bit_pos));
}
Ejemplo n.º 4
0
void stm32_rcc_check_periph_clk(Stm32Rcc *s, stm32_periph_t periph)
{
    Clk clk = s->PERIPHCLK[periph];

    assert(clk != NULL);

    if(!clktree_is_enabled(clk)) {
        /* I assume writing to a peripheral register while the peripheral clock
         * is disabled is a bug and give a warning to unsuspecting programmers.
         * When I made this mistake on real hardware the write had no effect.
         */
        stm32_hw_warn("Warning: You are attempting to use the stm32_rcc peripheral while "
                 "its clock is disabled.\n");
    }
}
Ejemplo n.º 5
0
static void stm32_rcc_RCC_CFGR_write(Stm32Rcc *s, uint32_t new_value, bool init)
{
    uint32_t new_PLLMUL, new_PLLXTPRE, new_PLLSRC;

    /* PLLMUL */
    new_PLLMUL = (new_value & RCC_CFGR_PLLMUL_MASK) >> RCC_CFGR_PLLMUL_START;
    if(!init) {
          if(clktree_is_enabled(s->PLLCLK) &&
           (new_PLLMUL != s->RCC_CFGR_PLLMUL)) {
               stm32_hw_warn("Can only change PLLMUL while PLL is disabled");
          }
    }
    assert(new_PLLMUL <= 0xf);
    if(new_PLLMUL == 0xf) {
        clktree_set_scale(s->PLLCLK, 16, 1);
    } else {
        clktree_set_scale(s->PLLCLK, new_PLLMUL + 2, 1);
    }
    s->RCC_CFGR_PLLMUL = new_PLLMUL;

    /* PLLXTPRE */
    new_PLLXTPRE = GET_BIT_VALUE(new_value, RCC_CFGR_PLLXTPRE_BIT);
    if(!init) {
        if(clktree_is_enabled(s->PLLCLK) &&
           (new_PLLXTPRE != s->RCC_CFGR_PLLXTPRE)) {
            stm32_hw_warn("Can only change PLLXTPRE while PLL is disabled");
        }
    }
    clktree_set_selected_input(s->PLLXTPRECLK, new_PLLXTPRE);
    s->RCC_CFGR_PLLXTPRE = new_PLLXTPRE;

    /* PLLSRC */
    new_PLLSRC = GET_BIT_VALUE(new_value, RCC_CFGR_PLLSRC_BIT);
    if(!init) {
        if(clktree_is_enabled(s->PLLCLK) &&
           (new_PLLSRC != s->RCC_CFGR_PLLSRC)) {
            stm32_hw_warn("Can only change PLLSRC while PLL is disabled");
        }
    }
    clktree_set_selected_input(s->PLLCLK, new_PLLSRC);
    s->RCC_CFGR_PLLSRC = new_PLLSRC;

    /* PPRE2 */
    s->RCC_CFGR_PPRE2 = (new_value & RCC_CFGR_PPRE2_MASK) >> RCC_CFGR_PPRE2_START;
    if(s->RCC_CFGR_PPRE2 < 0x4) {
        clktree_set_scale(s->PCLK2, 1, 1);
    } else {
        clktree_set_scale(s->PCLK2, 1, 2 * (s->RCC_CFGR_PPRE2 - 3));
    }

    /* PPRE1 */
    s->RCC_CFGR_PPRE1 = (new_value & RCC_CFGR_PPRE1_MASK) >> RCC_CFGR_PPRE1_START;
    if(s->RCC_CFGR_PPRE1 < 4) {
        clktree_set_scale(s->PCLK1, 1, 1);
    } else {
        clktree_set_scale(s->PCLK1, 1, 2 * (s->RCC_CFGR_PPRE1 - 3));
    }

    /* HPRE */
    s->RCC_CFGR_HPRE = (new_value & RCC_CFGR_HPRE_MASK) >> RCC_CFGR_HPRE_START;
    if(s->RCC_CFGR_HPRE < 8) {
        clktree_set_scale(s->HCLK, 1, 1);
    } else {
        clktree_set_scale(s->HCLK, 1, 2 * (s->RCC_CFGR_HPRE - 7));
    }

    /* SW */
    s->RCC_CFGR_SW = (new_value & RCC_CFGR_SW_MASK) >> RCC_CFGR_SW_START;
    switch(s->RCC_CFGR_SW) {
        case 0x0:
        case 0x1:
        case 0x2:
            clktree_set_selected_input(s->SYSCLK, s->RCC_CFGR_SW);
            break;
        default:
            hw_error("Invalid input selected for SYSCLK");
            break;
    }
}