Browse Source

pac55xx: adding memctl for flash/sram access, and clock/pll configuration functions.

Merge-conflict: took _prior_ verision of CCS_MUXSELR_MASK_PIN as
bracketing of (pin) seemed more correct!
pull/1274/head
Kevin Stefanik 5 years ago
committed by Karl Palsson
parent
commit
253a091936
  1. 246
      include/libopencm3/pac55xx/ccs.h
  2. 163
      include/libopencm3/pac55xx/memctl.h
  3. 2
      lib/pac55xx/Makefile
  4. 261
      lib/pac55xx/ccs.c
  5. 78
      lib/pac55xx/memctl.c

246
include/libopencm3/pac55xx/ccs.h

@ -4,6 +4,7 @@
* @defgroup system_defines Clock Config and System Defines
* @ingroup PAC55xx_defines
* @author Brian Viele <vielster@allocor.tech>
* @author Kevin Stefanik <kevin@allocor.tech>
* LGPL License Terms @ref lgpl_license
* @date 1 Dec 2019
*
@ -26,18 +27,95 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDE_LIBOPENCM3_PAC55XX_CCS_H_
#define INCLUDE_LIBOPENCM3_PAC55XX_CCS_H_
#ifndef LIBOPENCM3_PAC55XX_CCS_H_
#define LIBOPENCM3_PAC55XX_CCS_H_
#include <libopencm3/cm3/common.h>
#include <libopencm3/cm3/memorymap.h>
#include <libopencm3/pac55xx/memorymap.h>
#include <libopencm3/pac55xx/memctl.h>
/**@{*/
/** Clock Control Registers
* @defgroup clock_config_regs Clock Config Registers.
* @{*/
/** @defgroup ccs_frequencies CCS Frequencies
@{*/
/** Ring Oscillator Frequency */
#define CCS_ROSC_FREQ (16000000U)
/** Internally generated and trimmed 4MHz clock */
#define CCS_CLKREF_FREQ ( 4000000U)
/** Maximum external clock frequency */
#define CCS_EXTCLK_MAX_FREQ (20000000U)
/**@}*/
/** @defgroup ccs_ctl_reg Clock Control Register
@{*/
#define CCSCTL MMIO32(SCC_BASE)
#define CCS_CTL_FRCLKMUXSEL_MASK (0x03)
#define CCS_CTL_FRCLKMUXSEL(sel) ((sel) & CCS_CTL_FRCLKMUXSEL_MASK)
#define CCS_CTL_FRCLKMUXSEL_ROSC (0)
#define CCS_CTL_FRCLKMUXSEL_CLKREF (1)
#define CCS_CTL_FRCLKMUXSEL_EXTCLK (3)
#define CCS_CTL_ROSCEN BIT2
#define CCS_CTL_SCLKMUXSEL BIT4
#define CCS_CTL_SCLKMUXSEL_FRCLK (0)
#define CCS_CTL_SCLKMUXSEL_PLLCLK (1)
#define CCS_CTL_CLKFAILEN BIT5
#define CCS_CTL_CLKFAILMUXSEL BIT6
#define CCS_CTL_CLKFAILIF BIT7
#define CCS_CTL_LDOEN BIT8
#define CCS_CTL_SWRESET BIT11
#define CCS_CTL_PCLKEN BIT12
#define CCS_CTL_ACLKEN BIT13
#define CCS_CTL_ADCCLKEN BIT14
#define CCS_CTL_STCLKSLPEN BIT15
#define CCS_CTL_PCLKDIV_MASK (0x07)
#define CCS_CTL_PCLKDIV_SHIFT (16)
/* Supported PCLK divisors: 1-8 */
#define CCS_CTL_PCLKDIV(div) (((div-1) & CCS_CTL_PCLKDIV_MASK) << CCS_CTL_PCLKDIV_SHIFT)
#define CCS_CTL_ACLKDIV_MASK (0x07)
#define CCS_CTL_ACLKDIV_SHIFT (20)
/* Supported ACLK divisors: 1-8 */
#define CCS_CTL_ACLKDIV(div) (((div-1) & CCS_CTL_ACLKDIV_MASK) << CCS_CTL_ACLKDIV_SHIFT)
#define CCS_CTL_HCLKDIV_MASK (0x07)
#define CCS_CTL_HCLKDIV_SHIFT (24)
/* Supported HCLK divisors: 1-8 */
#define CCS_CTL_HCLKDIV(div) (((div-1) & CCS_CTL_HCLKDIV_MASK) << CCS_CTL_HCLKDIV_SHIFT)
#define CCS_CTL_USAMODE BIT28
#define CCS_CTL_USBMODE BIT29
#define CCS_CTL_USCMODE BIT30
#define CCS_CTL_USDMODE BIT31
/**@}*/
/** @defgroup ccs_pllctl_reg CCS PLL Control Register
@{*/
#define CCSPLLCTL MMIO32(SCC_BASE + 0x04)
/** PLL Enable */
#define CCS_PLLCTL_PLLEN BIT0
/** PLL Bypass */
#define CCS_PLLCTL_PLLBP BIT1
#define CCS_PLLCTL_PLLOUTDIV_MASK (0x03)
#define CCS_PLLCTL_PLLOUTDIV_SHIFT (2)
/** PLL Output Divisor */
#define CCS_PLLCTL_PLLOUTDIV(div) (((div) & CCS_PLLCTL_PLLOUTDIV_MASK) << CCS_PLLCTL_PLLOUTDIV_SHIFT)
#define CCS_PLLCTL_PLLOUTDIV1 (0)
#define CCS_PLLCTL_PLLOUTDIV2 (1)
#define CCS_PLLCTL_PLLOUTDIV4 (2)
#define CCS_PLLCTL_PLLOUTDIV8 (3)
#define CCS_PLLCTL_PLLINDIV_MASK (0x0F)
#define CCS_PLLCTL_PLLINDIV_SHIFT (4)
/** PLL Input Divisor */
#define CCS_PLLCTL_PLLINDIV(div) (((div) & CCS_PLLCTL_PLLINDIV_MASK) << CCS_PLLCTL_PLLINDIV_SHIFT)
#define CCS_PLLCTL_PLLFBDIV_MASK (0x3FFF)
#define CCS_PLLCTL_PLLFBDIV_SHIFT (8)
/** PLL Feedback Divisor */
#define CCS_PLLCTL_PLLFBDIV(div) (((div) & CCS_PLLCTL_PLLFBDIV_MASK) << CCS_PLLCTL_PLLFBDIV_SHIFT)
/** PLL Lock */
#define CCS_PLLCTL_PLLLOCK BIT24
/**@}*/
/** @defgroup ccs_rosctrim Ring Oscillator Trim Control Register
@{*/
#define CCSROSCTRIM_MASK (0x7F)
#define CCSROSCTRIM MMIO32(SCC_BASE + 0x08)
/**@}*/
@ -136,6 +214,162 @@ typedef enum {
CCS_DSR_DS_25MA = 0x07,
} ccs_drive_strength_t;
/**@}*/
/**@}*/
BEGIN_DECLS
/**
* @defgroup ccs_api Clock Control System API
* @ingroup peripheral_apis
* @brief <b>PAC5xx CCS Driver</b>
* @author @htmlonly &copy; @endhtmlonly 2020 Kevin Stefanik <kevin@allocor.tech>
* @date March 7, 2020
*
* This library supports the CCS module in the PAC55xx SoC from Qorvo.
*
* LGPL License Terms @ref lgpl_license
*/
/**@{*/
/**
* Select the source for FRCLK.
* @param[in] sel one of:
* - /ref CCS_CTL_FRCLKMUXSEL_ROSC - 16MHz ring oscillator
* - /ref CCS_CTL_FRCLKMUXSEL_CLKREF - trimmed 4MHz clock
* - /ref CCS_CTL_FRCLKMUXSEL_EXTCLK
*/
void ccs_frclkmux_select(uint32_t sel);
/** Enable the 16MHz Ring oscillator */
void ccs_rosc_enable(void);
/** Disable the 16MHz Ring oscillator */
void ccs_rosc_disable(void);
/** Select FRCLK for SCLK */
void ccs_sclkmux_select_frclk(void);
/** Select PLLCLK for SCLK */
void ccs_sclkmux_select_pllclk(void);
/** Enable Clock Fail Detection */
void ccs_clkfail_enable(void);
/** Disable Clock Fail Detection */
void ccs_clkfail_disable(void);
/** Select FRCLK for Clock Fail Detection */
void ccs_clkfailmux_select_frclk(void);
/** Select PLLCLK for Clock Fail Detection */
void ccs_clkfailmux_select_pllclk(void);
/** Enable the LDO */
void ccs_ldo_enable(void);
/** Disable the LDO */
void ccs_ldo_disable(void);
/** Enable the Peripheral Clock */
void ccs_pclk_enable(void);
/** Disable the Peripheral Clock */
void ccs_pclk_disable(void);
/** Enable the Auxiliary Clock */
void ccs_aclk_enable(void);
/** Disable the Auxiliary Clock */
void ccs_aclk_disable(void);
/** Enable the ADC Clock */
void ccs_adcclk_enable(void);
/** Disable the ADC Clock */
void ccs_adcclk_disable(void);
/** Enable SysTick clock gating in deep sleep mode */
void ccs_stclk_sleep_enable(void);
/** Disable SysTick clock gating in deep sleep mode */
void ccs_stclk_sleep_disable(void);
/**
* Set the divisor for the Peripheral Clock.
* @param[in] div PCLK Divisor: 1-8.
*/
void ccs_set_pclkdiv(uint32_t div);
/**
* Set the divisor for the Auxiliary Clock.
* @param[in] div ACLK Divisor: 1-8.
*/
void ccs_set_aclkdiv(uint32_t div);
/**
* Set the divisor for the AHB Clock.
* @param[in] div HCLK Divisor: 1-8.
*/
void ccs_set_hclkdiv(uint32_t div);
/** Enable the PLL */
void ccs_pll_enable(void);
/** Disable the PLL */
void ccs_pll_disable(void);
/** Check if the PLL is locked.
* @return true if locked.
*/
bool ccs_pll_locked(void);
/** Enable the PLL bypass */
void ccs_pll_bypass_enable(void);
/** Disable the PLL bypass */
void ccs_pll_bypass_disable(void);
/**
* Set the output divisor.
* @param[in] div Output divisor, one of:
* - /ref CCS_PLLCTL_PLLOUTDIV1
* - /ref CCS_PLLCTL_PLLOUTDIV2
* - /ref CCS_PLLCTL_PLLOUTDIV4
* - /ref CCS_PLLCTL_PLLOUTDIV8
*/
void ccs_pll_set_outdiv(uint32_t div);
/**
* Set the PLL input divisor.
* @param[in] div Input divisor, 1-15.
*/
void ccs_pll_set_indiv(uint32_t div);
/**
* Set the PLL feedback divisor.
* @param[in] div Feedback divisor, 4-16383.
*/
void ccs_pll_set_fbdiv(uint32_t div);
/**
* Configure the CCS PLL, enable it, and wait for lock.
* @param[in] indiv Input divisor, 1-15.
* @param[in] fbdiv Feedback divisor, 4-16383.
* @param[in] outdiv Output divisor, one of:
* - /ref CCS_PLLCTL_PLLOUTDIV1
* - /ref CCS_PLLCTL_PLLOUTDIV2
* - /ref CCS_PLLCTL_PLLOUTDIV4
* - /ref CCS_PLLCTL_PLLOUTDIV8
*/
void css_pll_config_enable(uint32_t indiv, uint32_t fbdiv, uint32_t outdiv);
/**
* Get the clock rate (in Hz) of the specified peripheral. This will pull the
* proper sources out of the clock tree and calculate the clock for the
* peripheral for return to the user, based on current settings.
* @param[in] periph Peripheral base address to get the clock rate for.
* @param[in] select Peripheral-controlled clock select value. Set to 0 when not applicable.
* @return Clock rate in Hz for the specified peripheral. 0 if undefined or error.
*/
uint32_t ccs_get_peripheral_clk_freq(uint32_t periph, uint32_t select);
/** Restores CCSCTL and CCSPLLCTL registers to default/safe values */
void ccs_reset_clocks(void);
/** CCS Clock Configuration structure. */
struct ccs_clk_config {
uint32_t frclk_source; /**< FRCLK source input selection */
uint32_t extclk_frequency; /**< EXTCLK frequency, 0 if none. */
uint32_t sclk_source; /**< SCLK source selection */
uint32_t pll_indiv; /**< PLL Input Divider 1-15 */
uint32_t pll_fbdiv; /**< PLL Feedback Divider 4-16383 */
uint32_t pll_outdiv; /**< PLL Output Divider */
uint32_t hclkdiv; /**< Divisor from SCLK to HCLK */
uint32_t aclkdiv; /**< Divisor from SCLK to ACLK */
uint32_t pclkdiv; /**< Divisor from HCLK to PCLK */
uint32_t mem_wstate; /**< Number of Flash Read wait states */
uint32_t mem_mclkdiv; /**< Divisor from HCLK to MCLK */
bool mem_mclksel; /**< false: ROSCLK, true: HCLK/MCLK */
bool mem_enable_cache; /**< false: disable cache, true: enable cache */
};
/**
* Setup the PAC55xx clocks with the given struct.
* @param[in] config CCS Clock configuration struct /ref ccs_clk_config
*/
void ccs_configure_clocks(const struct ccs_clk_config *config);
/**@}*/
#endif /* INCLUDE_LIBOPENCM3_PAC55XX_CCS_H_ */
END_DECLS
#endif /* LIBOPENCM3_PAC55XX_CCS_H_ */

163
include/libopencm3/pac55xx/memctl.h

@ -0,0 +1,163 @@
/**
* @brief Memory Controller definitions for the Qorvo PAC55xx series of microcontrollers
*
* @addtogroup PAC55xx_memctl Memory Controller Defines
* @ingroup PAC55xx_defines
* @author Kevin Stefanik <kevin@allocor.tech>
* LGPL License Terms @ref lgpl_license
* @date 17 Mar 2020
*
* Definitions in this file come from the PAC55XX Family User Guide Rev 1.23
* by Active-Semi dated November 19, 2019.
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2020 Kevin Stefanik <kevin@allocor.tech>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBOPENCM3_PAC55XX_MEMCTL_H_
#define LIBOPENCM3_PAC55XX_MEMCTL_H_
#include <libopencm3/cm3/common.h>
#include <libopencm3/pac55xx/memorymap.h>
/**@{*/
/** @defgroup memctl_reg Memory Controller Configuration Register
@{*/
/** Memory Controller Configuration Register */
#define MEMCTL_MEMCTLR MMIO32(MEMCTL_BASE)
#define MEMCTL_MEMCTLR_WSTATE_MASK (0xF)
#define MEMCTL_MEMCTLR_WSTATE(ws) ((ws) & MEMCTL_MEMCTLR_WSTATE_MASK)
#define MEMCTL_MEMCTLR_MCLKDIV_MASK (0xF)
#define MEMCTL_MEMCTLR_MCLKDIV_SHIFT 4
/* Supported MCLK divisors: 1-16 */
#define MEMCTL_MEMCTLR_MCLKDIV(div) (((div-1) & MEMCTL_MEMCTLR_MCLKDIV_MASK) << MEMCTL_MEMCTLR_MCLKDIV_SHIFT)
#define MEMCTL_MEMCTLR_WRITEWORDCNT_MASK (0x3)
#define MEMCTL_MEMCTLR_WRITEWORDCNT_SHIFT 8
#define MEMCTL_MEMCTLR_WRITEWORDCNT(cnt) (((cnt) & MEMCTL_MEMCTLR_WRITEWORDCNT_MASK) << MEMCTL_MEMCTLR_WRITEWORDCNT_SHIFT)
#define MEMCTL_MEMCTLR_SEIE BIT16
#define MEMCTL_MEMCTLR_DEIE BIT17
#define MEMCTL_MEMCTLR_INVADDRIE BIT18
#define MEMCTL_MEMCTLR_STBY BIT19
#define MEMCTL_MEMCTLR_ECCDIS BIT20
#define MEMCTL_MEMCTLR_CACHEDIS BIT21
#define MEMCTL_MEMCTLR_MCLKSEL BIT22
/**@}*/
/** @defgroup memstatus_reg Memory Controller Status Register
@{*/
/** Memory Controller Status Register */
#define MEMCTL_MEMSTATUS MMIO32(MEMCTL_BASE + 0x0004)
#define MEMCTL_MEMSTATUS_WBUSY BIT0
#define MEMCTL_MEMSTATUS_EBUSY BIT1
#define MEMCTL_MEMSTATUS_WRITEWORDCNT_MASK (0x3)
#define MEMCTL_MEMSTATUS_WRITEWORDCNT_SHIFT 8
#define MEMCTL_MEMSTATUS_WRITEWORDCNT ((MEMCTL_MEMSTATUS >> MEMCTL_MEMSTATUS_WRITEWORDCNT_SHIFT) & MEMCTL_MEMSTATUS_WRITEWORDCNT_MASK)
#define MEMCTL_MEMSTATUS_WRITEWORDCNT_4BYTES (0)
#define MEMCTL_MEMSTATUS_WRITEWORDCNT_8BYTES (1)
#define MEMCTL_MEMSTATUS_WRITEWORDCNT_12BYTES (2)
#define MEMCTL_MEMSTATUS_WRITEWORDCNT_16BYTES (3)
#define MEMCTL_MEMSTATUS_SE BIT16
#define MEMCTL_MEMSTATUS_DE BIT17
#define MEMCTL_MEMSTATUS_INVADDR BIT18
/**@}*/
/** @defgroup flashlock_vals Flash Lock/Write Enable Register values
@{*/
/** Flash Lock Access Register */
#define MEMCTL_FLASHLOCK MMIO32(MEMCTL_BASE + 0x0008)
#define MEMCTL_FLASHLOCK_CLEAR (0)
#define MEMCTL_FLASHLOCK_ALLOW_FLASH_WRITE (0x43DF140A)
#define MEMCTL_FLASHLOCK_ALLOW_MEMCTL_WRITE (0xD513B490)
#define MEMCTL_FLASHLOCK_ALLOW_INFO2_SWDFUSE (0x79B4F762)
/**@}*/
/** Flash Page Address Register */
#define MEMCTL_FLASHPAGE MMIO32(MEMCTL_BASE + 0x000C)
/** SWD Unlock Register */
#define MEMCTL_SWDUNLOCK MMIO32(MEMCTL_BASE + 0x0010)
/** @defgroup flasherase_vals Flash Erase Enable Register values
@{*/
/** Flash Erase Enable Register */
#define MEMCTL_FLASHERASE MMIO32(MEMCTL_BASE + 0x0020)
#define MEMCTL_FLASHERASE_PAGE_ERASE (0x8C799CA7)
#define MEMCTL_FLASHERASE_MASS_PAGE_ERASE (0x09EE76C9)
#define MEMCTL_FLASHERASE_INFO3_ERASE (0x1266FF45)
/**@}*/
/**@}*/
BEGIN_DECLS
/**
* @defgroup memctl_api Memory Controller API
* @ingroup peripheral_apis
* @brief <b>PAC5xx MEMCTL Driver</b>
* @author @htmlonly &copy; @endhtmlonly 2020 Kevin Stefanik <kevin@allocor.tech>
* @date March 7, 2020
*
* This library supports the MEMCTL module in the PAC55xx SoC from Qorvo.
*
* LGPL License Terms @ref lgpl_license
*/
/*@{*/
/** Set the number of wait states for Flash reads.
* @param[in] wstate Wait states: 0-15
*/
void memctl_flash_set_wstate(uint32_t wstate);
/** Set the MCLK divisor.
* @param[in] div HCLK to MCLK divisor: 1-16
*/
void memctl_flash_set_mclkdiv(uint32_t div);
/** Set WRITEWORDCOUNT to 0 to reset the Flash write data buffer */
void memctl_flash_reset_write_buffer(void);
/** Enable Flash Standby Mode */
void memctl_flash_standby_mode_enable(void);
/** Disable Flash Standby Mode */
void memctl_flash_standby_mode_disable(void);
/** Enable Flash cache */
void memctl_flash_cache_enable(void);
/** Disable Flash cache */
void memctl_flash_cache_disable(void);
/** Select ROSCCLK as input to Flash Memory Controller */
void memctl_flash_select_roscclk(void);
/** Select MCLK as input to Flash Memory Controller */
void memctl_flash_select_mclk(void);
/** Enable SRAM ECC */
void memctl_sram_ecc_enable(void);
/** Disable SRAM ECC */
void memctl_sram_ecc_disable(void);
/** Enable SRAM ECC Single Bit Detection Interrupt */
void memctl_sram_ecc_single_bit_interrupt_enable(void);
/** Disable SRAM ECC Single Bit Detection Interrupt */
void memctl_sram_ecc_single_bit_interrupt_disable(void);
/** Enable SRAM ECC Dual Bit Detection Interrupt */
void memctl_sram_ecc_dual_bit_interrupt_enable(void);
/** Disable SRAM ECC Dual Bit Detection Interrupt */
void memctl_sram_ecc_dual_bit_interrupt_disable(void);
/** Enable Invalid Memory Access Interrupt */
void memctl_invaddr_interrupt_enable(void);
/** Disable Invalid Memory Access Interrupt */
void memctl_invaddr_interrupt_disable(void);
/**@}*/
END_DECLS
#endif /* LIBOPENCM3_PAC55XX_MEMCTL_H_ */

2
lib/pac55xx/Makefile

@ -36,7 +36,9 @@ TGT_CFLAGS += $(STANDARD_FLAGS)
ARFLAGS = rcs
OBJS += can.o
OBJS += ccs.o
OBJS += gpio.o
OBJS += memctl.o
VPATH += ../cm3

261
lib/pac55xx/ccs.c

@ -0,0 +1,261 @@
/**
* @brief <b>PAC55xxxx CCS Driver</b>
* @author @htmlonly &copy; @endhtmlonly 2020 Kevin Stefanik <kevin@allocor.tech>
* @date March 7, 2020
*
* This library supports the CCS module in the PAC55xx SoC from Qorvo.
*
* LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/pac55xx/ccs.h>
#include <libopencm3/pac55xx/memorymap.h>
#include <libopencm3/pac55xx/memctl.h>
#include <libopencm3/cm3/assert.h>
static volatile uint32_t ccs_extclk_frequency = 0;
static volatile uint32_t ccs_frclk_frequency = CCS_ROSC_FREQ;
static volatile uint32_t ccs_sclk_frequency = CCS_ROSC_FREQ;
static volatile uint32_t ccs_pll_clk_frequency = 0;
static volatile uint32_t ccs_hclk_frequency = CCS_ROSC_FREQ;
static volatile uint32_t ccs_aclk_frequency = CCS_ROSC_FREQ;
static volatile uint32_t ccs_pclk_frequency = CCS_ROSC_FREQ;
void ccs_frclkmux_select(uint32_t sel) {
CCSCTL = (CCSCTL & ~CCS_CTL_FRCLKMUXSEL(CCS_CTL_FRCLKMUXSEL_MASK)) | CCS_CTL_FRCLKMUXSEL(sel);
}
void ccs_rosc_enable(void) {
CCSCTL |= CCS_CTL_ROSCEN;
}
void ccs_rosc_disable(void) {
CCSCTL &= ~CCS_CTL_ROSCEN;
}
void ccs_sclkmux_select_frclk(void) {
CCSCTL &= ~CCS_CTL_SCLKMUXSEL;
}
void ccs_sclkmux_select_pllclk(void) {
CCSCTL |= CCS_CTL_SCLKMUXSEL;
}
void ccs_clkfail_enable(void) {
CCSCTL |= CCS_CTL_CLKFAILEN;
}
void ccs_clkfail_disable(void) {
CCSCTL &= ~CCS_CTL_CLKFAILEN;
}
void ccs_clkfailmux_select_frclk(void) {
CCSCTL &= ~CCS_CTL_CLKFAILMUXSEL;
}
void ccs_clkfailmux_select_pllclk(void) {
CCSCTL |= CCS_CTL_CLKFAILMUXSEL;
}
void ccs_ldo_enable(void) {
CCSCTL |= CCS_CTL_LDOEN;
}
void ccs_ldo_disable(void) {
CCSCTL &= ~CCS_CTL_LDOEN;
}
void ccs_pclk_enable(void) {
CCSCTL |= CCS_CTL_PCLKEN;
}
void ccs_pclk_disable(void) {
CCSCTL &= ~CCS_CTL_PCLKEN;
}
void ccs_aclk_enable(void) {
CCSCTL |= CCS_CTL_ACLKEN;
}
void ccs_aclk_disable(void) {
CCSCTL &= ~CCS_CTL_ACLKEN;
}
void ccs_adcclk_enable(void) {
CCSCTL |= CCS_CTL_ADCCLKEN;
}
void ccs_adcclk_disable(void) {
CCSCTL &= ~CCS_CTL_ADCCLKEN;
}
void ccs_stclk_sleep_enable(void) {
CCSCTL |= CCS_CTL_STCLKSLPEN;
}
void ccs_stclk_sleep_disable(void) {
CCSCTL &= ~CCS_CTL_STCLKSLPEN;
}
void ccs_set_pclkdiv(uint32_t div) {
CCSCTL = (CCSCTL & ~CCS_CTL_PCLKDIV(8)) | CCS_CTL_PCLKDIV(div);
}
void ccs_set_aclkdiv(uint32_t div) {
CCSCTL = (CCSCTL & ~CCS_CTL_ACLKDIV(8)) | CCS_CTL_ACLKDIV(div);
}
void ccs_set_hclkdiv(uint32_t div) {
CCSCTL = (CCSCTL & ~CCS_CTL_HCLKDIV(8)) | CCS_CTL_HCLKDIV(div);
}
void ccs_pll_enable(void) {
CCSPLLCTL |= CCS_PLLCTL_PLLEN;
}
void ccs_pll_disable(void) {
CCSPLLCTL &= ~CCS_PLLCTL_PLLEN;
}
bool ccs_pll_locked(void) {
return (CCSPLLCTL & CCS_PLLCTL_PLLLOCK) == CCS_PLLCTL_PLLLOCK;
}
void ccs_pll_bypass_enable(void) {
CCSPLLCTL |= CCS_PLLCTL_PLLBP;
}
void ccs_pll_bypass_disable(void) {
CCSPLLCTL &= ~CCS_PLLCTL_PLLBP;
}
void ccs_pll_set_outdiv(uint32_t div) {
CCSPLLCTL = (CCSPLLCTL & ~CCS_PLLCTL_PLLOUTDIV(CCS_PLLCTL_PLLOUTDIV_MASK)) | CCS_PLLCTL_PLLOUTDIV(div);
}
void ccs_pll_set_indiv(uint32_t div) {
if (div <= 15 && div >= 1) {
CCSPLLCTL = (CCSPLLCTL & ~CCS_PLLCTL_PLLINDIV(CCS_PLLCTL_PLLINDIV_MASK)) | CCS_PLLCTL_PLLINDIV(div);
} else {
cm3_assert_not_reached();
}
}
void ccs_pll_set_fbdiv(uint32_t div) {
if (div <= 16383 && div >= 4) {
CCSPLLCTL = (CCSPLLCTL & ~CCS_PLLCTL_PLLFBDIV(CCS_PLLCTL_PLLFBDIV_MASK)) | CCS_PLLCTL_PLLFBDIV(div);
} else {
cm3_assert_not_reached();
}
}
void css_pll_config_enable(uint32_t indiv, uint32_t fbdiv, uint32_t outdiv) {
ccs_pll_disable();
ccs_pll_set_fbdiv(fbdiv);
ccs_pll_set_outdiv(outdiv);
ccs_pll_set_indiv(indiv);
ccs_pll_enable();
while (!ccs_pll_locked()) ; /* Wait for PLL lock ~500us */
}
uint32_t ccs_get_peripheral_clk_freq(uint32_t periph, uint32_t select) {
switch (periph) {
case ADC_BASE:
return ccs_sclk_frequency;
case I2C_BASE: /* fall through */
case USARTA_BASE: /* fall through */
case USARTB_BASE: /* fall through */
case USARTC_BASE: /* fall through */
case USARTD_BASE: /* fall through */
case CAN_BASE: /* fall through */
case GPTIMERA_BASE: /* fall through */
case GPTIMERB_BASE:
return ccs_pclk_frequency;
case TIMERA_BASE: /* fall through */
case TIMERB_BASE: /* fall through */
case TIMERC_BASE: /* fall through */
case TIMERD_BASE:
return (select == 0) ? ccs_pclk_frequency : ccs_aclk_frequency;
case MEMCTL_BASE:
return (select == 0) ? CCS_ROSC_FREQ : ccs_hclk_frequency;
case WWDT_BASE:
return (select == 0) ? ccs_frclk_frequency : CCS_ROSC_FREQ;
case RTC_BASE:
return ccs_frclk_frequency;
case CRC_BASE: /* fall through */
case SYS_TICK_BASE:
return ccs_hclk_frequency;
default:
cm3_assert_not_reached();
}
}
void ccs_reset_clocks(void) {
CCSCTL = CCS_CTL_LDOEN | CCS_CTL_ROSCEN |
CCS_CTL_PCLKEN | CCS_CTL_ACLKEN |
CCS_CTL_ADCCLKEN | CCS_CTL_STCLKSLPEN;
CCSPLLCTL = 0;
}
void ccs_configure_clocks(const struct ccs_clk_config *config) {
MEMCTL_FLASHLOCK = MEMCTL_FLASHLOCK_ALLOW_MEMCTL_WRITE;
ccs_reset_clocks(); /* set safe defaults */
ccs_frclkmux_select(CCS_CTL_FRCLKMUXSEL_ROSC);
ccs_sclkmux_select_frclk();
memctl_flash_select_roscclk();
if (config->mem_enable_cache) {
memctl_flash_cache_enable();
} else {
memctl_flash_cache_disable();
}
ccs_frclkmux_select(CCS_CTL_FRCLKMUXSEL_CLKREF); /* switch frclk to 4MHz CLKREF */
switch (config->frclk_source) {
case CCS_CTL_FRCLKMUXSEL_ROSC:
ccs_frclkmux_select(CCS_CTL_FRCLKMUXSEL_ROSC);
ccs_frclk_frequency = CCS_ROSC_FREQ;
break;
case CCS_CTL_FRCLKMUXSEL_CLKREF:
ccs_frclkmux_select(CCS_CTL_FRCLKMUXSEL_CLKREF);
ccs_frclk_frequency = CCS_CLKREF_FREQ;
break;
case CCS_CTL_FRCLKMUXSEL_EXTCLK:
if (config->extclk_frequency > CCS_EXTCLK_MAX_FREQ
|| config->extclk_frequency == 0) {
cm3_assert_not_reached();
}
ccs_frclkmux_select(CCS_CTL_FRCLKMUXSEL_EXTCLK);
ccs_frclk_frequency = ccs_extclk_frequency = config->extclk_frequency;
break;
default:
cm3_assert_not_reached();
}
if (config->sclk_source == CCS_CTL_SCLKMUXSEL_FRCLK) {
ccs_set_hclkdiv(config->hclkdiv);
ccs_set_aclkdiv(config->aclkdiv);
memctl_flash_set_wstate(config->mem_wstate);
ccs_sclkmux_select_frclk();
memctl_flash_set_mclkdiv(config->mem_mclkdiv);
if (config->mem_mclksel == false) {
memctl_flash_select_roscclk();
} else {
memctl_flash_select_mclk();
}
ccs_sclk_frequency = ccs_frclk_frequency;
} else if (config->sclk_source == CCS_CTL_SCLKMUXSEL_PLLCLK) {
css_pll_config_enable(config->pll_indiv, config->pll_fbdiv, config->pll_outdiv);
ccs_set_hclkdiv(config->hclkdiv);
ccs_set_aclkdiv(config->aclkdiv);
memctl_flash_set_wstate(config->mem_wstate);
ccs_sclkmux_select_pllclk();
memctl_flash_set_mclkdiv(config->mem_mclkdiv);
if (config->mem_mclksel == false) {
memctl_flash_select_roscclk();
} else {
memctl_flash_select_mclk();
}
ccs_pll_clk_frequency = ((ccs_frclk_frequency * config->pll_fbdiv) / config->pll_indiv) >> config->pll_outdiv;
ccs_sclk_frequency = ccs_pll_clk_frequency;
} else {
cm3_assert_not_reached();
}
ccs_set_pclkdiv(config->pclkdiv);
ccs_pclk_enable();
ccs_aclk_enable();
ccs_adcclk_enable();
ccs_stclk_sleep_disable();
ccs_hclk_frequency = ccs_sclk_frequency / config->hclkdiv;
ccs_aclk_frequency = ccs_sclk_frequency / config->aclkdiv;
ccs_pclk_frequency = ccs_hclk_frequency / config->pclkdiv;
MEMCTL_FLASHLOCK = MEMCTL_FLASHLOCK_CLEAR;
}

78
lib/pac55xx/memctl.c

@ -0,0 +1,78 @@
/**
* @brief <b>PAC55xxxx Memory Controller Driver</b>
* @author @htmlonly &copy; @endhtmlonly 2020 Kevin Stefanik <kevin@allocor.tech>
* @date April 1, 2020
*
* This library supports the Memory Controller in the PAC55xx SoC from Qorvo.
*
* LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/pac55xx/memctl.h>
void memctl_flash_set_wstate(uint32_t wstate) {
MEMCTL_MEMCTLR = (MEMCTL_MEMCTLR & ~MEMCTL_MEMCTLR_WSTATE(MEMCTL_MEMCTLR_WSTATE_MASK)) | MEMCTL_MEMCTLR_WSTATE(wstate);
}
void memctl_flash_set_mclkdiv(uint32_t div) {
MEMCTL_MEMCTLR = (MEMCTL_MEMCTLR & ~MEMCTL_MEMCTLR_MCLKDIV(16)) | MEMCTL_MEMCTLR_MCLKDIV(div);
}
void memctl_flash_reset_write_buffer(void) {
MEMCTL_MEMCTLR = (MEMCTL_MEMCTLR & ~MEMCTL_MEMCTLR_WRITEWORDCNT(MEMCTL_MEMCTLR_WRITEWORDCNT_MASK));
}
void memctl_flash_standby_mode_enable(void) {
MEMCTL_MEMCTLR |= MEMCTL_MEMCTLR_STBY;
}
void memctl_flash_standby_mode_disable(void) {
MEMCTL_MEMCTLR &= ~MEMCTL_MEMCTLR_STBY;
}
void memctl_flash_cache_enable(void) {
MEMCTL_MEMCTLR &= ~MEMCTL_MEMCTLR_CACHEDIS;
}
void memctl_flash_cache_disable(void) {
MEMCTL_MEMCTLR |= MEMCTL_MEMCTLR_CACHEDIS;
}
void memctl_flash_select_roscclk(void) {
MEMCTL_MEMCTLR &= ~MEMCTL_MEMCTLR_MCLKSEL;
}
void memctl_flash_select_mclk(void) {
MEMCTL_MEMCTLR |= MEMCTL_MEMCTLR_MCLKSEL;
}
void memctl_sram_ecc_enable(void) {
MEMCTL_MEMCTLR &= ~MEMCTL_MEMCTLR_ECCDIS;
}
void memctl_sram_ecc_disable(void) {
MEMCTL_MEMCTLR |= MEMCTL_MEMCTLR_ECCDIS;
}
void memctl_sram_ecc_single_bit_interrupt_enable(void) {
MEMCTL_MEMCTLR |= MEMCTL_MEMCTLR_SEIE;
}
void memctl_sram_ecc_single_bit_interrupt_disable(void) {
MEMCTL_MEMCTLR &= ~MEMCTL_MEMCTLR_SEIE;
}
void memctl_sram_ecc_dual_bit_interrupt_enable(void) {
MEMCTL_MEMCTLR |= MEMCTL_MEMCTLR_DEIE;
}
void memctl_sram_ecc_dual_bit_interrupt_disable(void) {
MEMCTL_MEMCTLR &= ~MEMCTL_MEMCTLR_DEIE;
}
void memctl_invaddr_interrupt_enable(void) {
MEMCTL_MEMCTLR |= MEMCTL_MEMCTLR_INVADDRIE;
}
void memctl_invaddr_interrupt_disable(void) {
MEMCTL_MEMCTLR &= ~MEMCTL_MEMCTLR_INVADDRIE;
}
Loading…
Cancel
Save