| /**************************************************************************** |
| * arch/arm/src/str71x/str71x_prccu.c |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. The |
| * ASF licenses this file to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance with the |
| * License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations |
| * under the License. |
| * |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Included Files |
| ****************************************************************************/ |
| |
| #include <nuttx/config.h> |
| |
| #include <stdint.h> |
| #include <assert.h> |
| #include <debug.h> |
| |
| #include <nuttx/irq.h> |
| #include <nuttx/arch.h> |
| |
| #include "chip.h" |
| #include "arm_internal.h" |
| #include "str71x.h" |
| |
| /**************************************************************************** |
| * Pre-processor Definitions |
| ****************************************************************************/ |
| |
| /* Select set of peripherals to be enabled */ |
| |
| /* APB1 periperals */ |
| |
| #ifndef CONFIG_STR71X_I2C0 |
| # define APB1EN_I2C0 STR71X_APB1_I2C0 |
| #else |
| # define APB1EN_I2C0 (0) |
| #endif |
| |
| #ifndef CONFIG_STR71X_I2C1 |
| # define APB1EN_I2C1 STR71X_APB1_I2C1 |
| #else |
| # ifndef CONFIG_STR71X_GPIO0 |
| # error "I2C1 requires GPIO0" |
| # endif |
| # ifdef CONFIG_STR71X_BSPI0 |
| # error "I2C1 is incompatible with BSPI0" |
| # endif |
| # define APB1EN_I2C1 (0) |
| #endif |
| |
| #ifndef CONFIG_STR71X_UART0 |
| # define APB1EN_UART0 STR71X_APB1_UART0 |
| #else |
| # ifndef CONFIG_STR71X_GPIO0 |
| # error "CONFIG_STR71X_UART0 requires CONFIG_STR71X_GPIO0" |
| # endif |
| # define APB1EN_UART0 (0) |
| #endif |
| |
| #ifndef CONFIG_STR71X_UART1 |
| # define APB1EN_UART1 STR71X_APB1_UART1 |
| #else |
| # ifndef CONFIG_STR71X_GPIO0 |
| # error "CONFIG_STR71X_UART1 requires CONFIG_STR71X_GPIO0" |
| # endif |
| # define APB1EN_UART1 (0) |
| #endif |
| |
| #ifndef CONFIG_STR71X_UART2 |
| # define APB1EN_UART2 STR71X_APB1_UART2 |
| #else |
| # ifndef CONFIG_STR71X_GPIO0 |
| # error "CONFIG_STR71X_UART2 requires CONFIG_STR71X_GPIO0" |
| # endif |
| # define APB1EN_UART2 (0) |
| #endif |
| |
| #ifndef CONFIG_STR71X_UART3 |
| # define APB1EN_UART3 STR71X_APB1_UART3 |
| #else |
| # ifndef CONFIG_STR71X_GPIO0 |
| # error "UART3 requires GPIO0" |
| # endif |
| # ifdef CONFIG_STR71X_BSPI0 |
| # error "UART3 is incompatible with BSPI0" |
| # endif |
| # define APB1EN_UART3 (0) |
| #endif |
| |
| #ifndef CONFIG_STR71X_USB |
| # define APB1EN_USB STR71X_APB1_USB |
| #else |
| # define APB1EN_USB (0) |
| #endif |
| |
| #ifndef CONFIG_STR71X_CAN |
| # define APB1EN_CAN STR71X_APB1_CAN |
| #else |
| # define APB1EN_CAN (0) |
| #endif |
| |
| #ifndef CONFIG_STR71X_BSPI0 |
| # define APB1EN_BSPI0 STR71X_APB1_BSPI0 |
| #else |
| # ifndef CONFIG_STR71X_GPIO0 |
| # error "BSPI0 requires GPIO0" |
| # endif |
| # ifdef CONFIG_STR71X_UART3 |
| # error "BSPI0 is incompatible with UART3" |
| # endif |
| # ifdef CONFIG_STR71X_I2C1 |
| # error "BSPI0 is incompatible with I2C1" |
| # endif |
| # define APB1EN_BSPI0 (0) |
| #endif |
| |
| #ifndef CONFIG_STR71X_BSPI1 |
| # define APB1EN_BSPI1 STR71X_APB1_BSPI1 |
| #else |
| # ifndef CONFIG_STR71X_GPIO0 |
| # error "BSPI1 requires GPIO0" |
| # endif |
| # define APB1EN_BSPI1 (0) |
| #endif |
| |
| #ifndef CONFIG_STR71X_HDLC |
| # define APB1EN_HDLC STR71X_APB1_HDLC |
| #else |
| # define APB1EN_HDLC (0) |
| #endif |
| |
| #define APB1EN_ALL \ |
| (APB1EN_I2C0 | APB1EN_I2C1 | APB1EN_UART0 | APB1EN_UART1 | \ |
| APB1EN_UART2 | APB1EN_UART3 | APB1EN_USB | APB1EN_CAN | \ |
| APB1EN_BSPI0 | APB1EN_BSPI1 | APB1EN_HDLC) |
| |
| /* APB2 Peripherals */ |
| |
| #ifndef CONFIG_STR71X_XTI |
| # define APB2EN_XTI STR71X_APB2_XTI |
| #else |
| # define APB2EN_XTI (0) |
| #endif |
| |
| #ifndef CONFIG_STR71X_GPIO0 |
| # define APB2EN_GPIO0 STR71X_APB2_GPIO0 |
| #else |
| # define APB2EN_GPIO0 (0) |
| #endif |
| |
| #ifndef CONFIG_STR71X_GPIO1 |
| # define APB2EN_GPIO1 STR71X_APB2_GPIO1 |
| #else |
| # define APB2EN_GPIO1 (0) |
| #endif |
| |
| #ifndef CONFIG_STR71X_GPIO2 |
| # define APB2EN_GPIO2 STR71X_APB2_GPIO2 |
| #else |
| # define APB2EN_GPIO2 (0) |
| #endif |
| |
| #ifndef CONFIG_STR71X_ADC12 |
| # define APB2EN_ADC12 STR71X_APB2_ADC12 |
| #else |
| # define APB2EN_ADC12 (0) |
| #endif |
| |
| #ifndef CONFIG_STR71X_CKOUT |
| # define APB2EN_CKOUT STR71X_APB2_CKOUT |
| #else |
| # define APB2EN_CKOUT (0) |
| #endif |
| |
| #define APB2EN_TIM0 (0) /* System timer -- always enabled */ |
| |
| #ifndef CONFIG_STR71X_TIM1 |
| # define APB2EN_TIM1 STR71X_APB2_TIM1 |
| #else |
| # define APB2EN_TIM1 (0) |
| #endif |
| |
| #ifndef CONFIG_STR71X_TIM2 |
| # define APB2EN_TIM2 STR71X_APB2_TIM2 |
| #else |
| # define APB2EN_TIM2 (0) |
| #endif |
| |
| #ifndef CONFIG_STR71X_TIM3 |
| # define APB2EN_TIM3 STR71X_APB2_TIM3 |
| #else |
| # define APB2EN_TIM3 (0) |
| #endif |
| |
| #ifndef CONFIG_STR71X_RTC |
| # define APB2EN_RTC STR71X_APB2_RTC |
| #else |
| # define APB2EN_RTC (0) |
| #endif |
| |
| #define APB2EN_EIC (0) /* Interrupt controller always enabled */ |
| |
| #define APB2EN_ALL \ |
| (APB2EN_XTI | APB2EN_GPIO0 | APB2EN_GPIO1 | APB2EN_GPIO2 | \ |
| APB2EN_ADC12 | APB2EN_CKOUT | APB2EN_TIM0 | APB2EN_TIM1 | \ |
| APB2EN_TIM2 | APB2EN_TIM3 | APB2EN_RTC | APB2EN_EIC) |
| |
| #if STR71X_PLL1OUT_MUL == 12 |
| # define PLL1MUL STR71X_RCCUPLL1CR_MUL12 |
| #elif STR71X_PLL1OUT_MUL == 16 |
| # define PLL1MUL STR71X_RCCUPLL1CR_MUL16 |
| #elif STR71X_PLL1OUT_MUL == 20 |
| # define PLL1MUL STR71X_RCCUPLL1CR_MUL20 |
| #elif STR71X_PLL1OUT_MUL == 24 |
| # define PLL1MUL STR71X_RCCUPLL1CR_MUL24 |
| #else |
| # error "Unsupported value for STR71X_PLL1OUT_MUL" |
| #endif |
| |
| #if STR71X_PLL1OUT_DIV == 1 |
| # define PLL1DIV STR71X_RCCUPLL1CR_DIV1 |
| #elif STR71X_PLL1OUT_DIV == 2 |
| # define PLL1DIV STR71X_RCCUPLL1CR_DIV2 |
| #elif STR71X_PLL1OUT_DIV == 3 |
| # define PLL1DIV STR71X_RCCUPLL1CR_DIV3 |
| #elif STR71X_PLL1OUT_DIV == 4 |
| # define PLL1DIV STR71X_RCCUPLL1CR_DIV4 |
| #elif STR71X_PLL1OUT_DIV == 5 |
| # define PLL1DIV STR71X_RCCUPLL1CR_DIV5 |
| #elif STR71X_PLL1OUT_DIV == 6 |
| # define PLL1DIV STR71X_RCCUPLL1CR_DIV6 |
| #elif STR71X_PLL1OUT_DIV == 7 |
| # define PLL1DIV STR71X_RCCUPLL1CR_DIV7 |
| #else |
| # error "Unsupported value for STR71X_PLL1OUT_DIV" |
| #endif |
| |
| #if STR71X_APB1_DIV == 1 |
| # define APB1DIV STR71X_PCUPDIVR_APB1DIV1 |
| #elif STR71X_APB1_DIV == 2 |
| # define APB1DIV STR71X_PCUPDIVR_APB1DIV2 |
| #elif STR71X_APB1_DIV == 4 |
| # define APB1DIV STR71X_PCUPDIVR_APB1DIV4 |
| #elif STR71X_APB1_DIV == 8 |
| # define APB1DIV STR71X_PCUPDIVR_APB1DIV8 |
| #else |
| # error "Unsupported value for STR71X_APB1_DIV" |
| #endif |
| |
| #if STR71X_APB2_DIV == 1 |
| # define APB2DIV STR71X_PCUPDIVR_APB2DIV1 |
| #elif STR71X_APB2_DIV == 2 |
| # define APB2DIV STR71X_PCUPDIVR_APB2DIV2 |
| #elif STR71X_APB2_DIV == 4 |
| # define APB2DIV STR71X_PCUPDIVR_APB2DIV4 |
| #elif STR71X_APB2_DIV == 8 |
| # define APB2DIV STR71X_PCUPDIVR_APB2DIV8 |
| #else |
| # error "Unsupported value for STR71X_APB2_DIV" |
| #endif |
| |
| #if STR71X_MCLK_DIV == 1 |
| # define MCLKDIV STR71X_PCUMDIVR_DIV1 |
| #elif STR71X_MCLK_DIV == 2 |
| # define MCLKDIV STR71X_PCUMDIVR_DIV2 |
| #elif STR71X_MCLK_DIV == 4 |
| # define MCLKDIV STR71X_PCUMDIVR_DIV4 |
| #elif STR71X_MCLK_DIV == 8 |
| # define MCLKDIV STR71X_PCUMDIVR_DIV8 |
| #else |
| # error "Unsupported value for STR71X_MCLK_DIV" |
| #endif |
| |
| #if STR71X_PLL2OUT_MUL == 12 |
| # define PLL2MUL STR71X_PCUPPL2CR_MUL12 |
| #elif STR71X_PLL2OUT_MUL == 16 |
| # define PLL2MUL STR71X_PCUPPL2CR_MUL16 |
| #elif STR71X_PLL2OUT_MUL == 20 |
| # define PLL2MUL STR71X_PCUPPL2CR_MUL20 |
| #elif STR71X_PLL2OUT_MUL == 28 |
| # define PLL2MUL STR71X_PCUPPL2CR_MUL28 |
| #else |
| # error "Unsupported value for STR71X_PLL2OUT_MUL" |
| #endif |
| |
| #if STR71X_PLL2OUT_DIV == 1 |
| # define PLL2DIV STR71X_PCUPPL2CR_DIV1 |
| #elif STR71X_PLL2OUT_DIV == 2 |
| # define PLL2DIV STR71X_PCUPPL2CR_DIV2 |
| #elif STR71X_PLL2OUT_DIV == 3 |
| # define PLL2DIV STR71X_PCUPPL2CR_DIV3 |
| #elif STR71X_PLL2OUT_DIV == 4 |
| # define PLL2DIV STR71X_PCUPPL2CR_DIV4 |
| #elif STR71X_PLL2OUT_DIV == 5 |
| # define PLL2DIV STR71X_PCUPPL2CR_DIV5 |
| #elif STR71X_PLL2OUT_DIV == 6 |
| # define PLL2DIV STR71X_PCUPPL2CR_DIV6 |
| #elif STR71X_PLL2OUT_DIV == 7 |
| # define PLL2DIV STR71X_PCUPPL2CR_DIV7 |
| #else |
| # error "Unsupported value for STR71X_PLL2OUT_DIV" |
| #endif |
| |
| /**************************************************************************** |
| * Private Types |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Public Data |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Private Data |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Private Functions |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Public Funstions |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Name: str71x_prccuinit |
| * |
| * Description: |
| * Initialize the PCU/RCCU based on the NuttX configuration and the |
| * board-specific settings in board.h |
| * |
| ****************************************************************************/ |
| |
| void str71x_prccuinit(void) |
| { |
| uint32_t reg32; |
| uint16_t reg16; |
| |
| /* Divide RCLK to obtain PCLK1 & 2 clock for the APB1 & 2 peripherals. |
| * The divider values are provided in board.h |
| */ |
| |
| reg16 = getreg16(STR71X_PCU_PDIVR); |
| reg16 &= ~(STR71X_PCUPDIVR_FACT1MASK | STR71X_PCUPDIVR_FACT2MASK); |
| reg16 |= (APB1DIV | APB2DIV); |
| putreg16(reg16, STR71X_PCU_PDIVR); |
| |
| /* Configure the main system clock (MCLK) divider with value from board.h */ |
| |
| reg16 = getreg16(STR71X_PCU_MDIVR); |
| reg16 &= ~STR71X_PCUMDIVR_FACTMASK; |
| reg16 |= MCLKDIV; |
| putreg16(reg16 , STR71X_PCU_MDIVR); |
| |
| /* Turn off the PLL1 by setting bits DX[2:0] */ |
| |
| putreg32(STR71X_RCCUPLL1CR_CLK2, STR71X_RCCU_PLL1CR); |
| |
| /* Configure the PLL1CR register using the provided multiplier and |
| * divider. The FREF_RANGE bit is also set if the input frequency |
| * (CLK2) is greater than 3MHz. |
| */ |
| |
| #if STR71X_CLK2 > 3000000 |
| putreg32(PLL1MUL | PLL1DIV, STR71X_RCCU_PLL1CR); |
| #else |
| putreg32(PLL1MUL | PLL1DIV | STR71X_RCCUPLL1CR_FREFRANGE, |
| STR71X_RCCU_PLL1CR); |
| #endif |
| |
| /* Wait for the PLL to lock */ |
| |
| while ((getreg16(STR71X_RCCU_CFR) & STR71X_RCCUCFR_LOCK) == 0); |
| |
| /* Set the CK2_16 Bit in the CFR to use CLK2/PLL1OUT as CLK3 */ |
| |
| reg32 = getreg32(STR71X_RCCU_CFR); |
| reg32 |= STR71X_RCCUCFR_CK216; |
| |
| /* Should the main oscillator divided down by 2? */ |
| |
| #ifdef STR71X_PLL1IN_DIV2 |
| reg32 |= STR71X_RCCUCFR_DIV2; |
| #else |
| reg32 &= ~STR71X_RCCUCFR_DIV2; |
| #endif |
| putreg32(reg32, STR71X_RCCU_CFR); |
| |
| /* Wait for the PLL to lock */ |
| |
| while ((getreg16(STR71X_RCCU_CFR) & STR71X_RCCUCFR_LOCK) == 0); |
| |
| /* Select CLK3 (vs the alternative source) for RCLK in the clock |
| * control register (CCR) |
| */ |
| |
| reg16 = getreg16(STR71X_RCCU_CCR); |
| reg16 &= ~STR71X_RCCUCCR_CKAFSEL; |
| putreg16(reg16, STR71X_RCCU_CCR); |
| |
| /* Select PLL1OUT as the CLK3 */ |
| |
| reg32 = getreg32(STR71X_RCCU_CFR); |
| putreg32(reg32 | STR71X_RCCUCFR_CSUCKSEL, STR71X_RCCU_CFR); |
| |
| /* Enable clocking on selected periperals */ |
| |
| putreg32(APB1EN_ALL, STR71X_APB1_CKDIS); |
| putreg32(APB2EN_ALL, STR71X_APB2_CKDIS); |
| |
| /* Configure PLL2 */ |
| |
| #if defined(CONFIG_STR71X_HDLC) || (defined(CONFIG_STR71X_USB) && defined(STR71X_USBIN_PLL2)) |
| reg16 = getreg16(STR71X_PCU_PLL2CR); |
| reg16 &= ~(STR71X_PCUPPL2CR_MXMASK | STR71X_PCUPPL2CR_DXMASK); |
| reg16 |= (PLL2MUL | PLL2DIV); |
| |
| /* Set the PLL2 FRQRNG bit according to the PLL2 input frequency */ |
| |
| #if STR71X_PCU_HCLK_OSC < 3000000 |
| reg16 &= ~STR71X_PCUPPL2CR_FRQRNG; |
| #else |
| reg16 |= STR71X_PCUPPL2CR_FRQRNG; |
| #endif |
| putreg16(reg16, STR71X_PCU_PLL2CR); |
| |
| /* Wait for PLL2 to lock in */ |
| |
| /* while ((getreg16(STR71X_PCU_PLL2CR) & STR71X_PCUPPL2CR_LOCK) == 0); */ |
| |
| #endif |
| |
| /* Select the USB clock source */ |
| |
| #ifdef CONFIG_STR71X_USB |
| reg16 = getreg16(STR71X_PCU_PLL2CR); |
| #ifdef STR71X_USBIN_PLL2 |
| /* PLL2 is the clock source to the USB */ |
| |
| reg16 |= STR71X_PCUPPL2CR_USBEN; |
| #else |
| /* USBCLK pin is the clock source to the USB */ |
| |
| reg16 &= ~STR71X_PCUPPL2CR_USBEN; |
| #endif |
| putreg16(reg16, STR71X_PCU_PLL2CR); |
| #endif |
| } |