This is an automated email from the ASF dual-hosted git repository. xiaoxiang pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push: new 1452f32b14 zynq-mpsoc: add support for pll 1452f32b14 is described below commit 1452f32b14ebde8b19b07d820dbb15108486dc2a Author: zouboan <zoub...@hotmail.com> AuthorDate: Mon Jan 27 00:25:46 2025 +0800 zynq-mpsoc: add support for pll --- arch/arm64/src/zynq-mpsoc/Kconfig | 6 - arch/arm64/src/zynq-mpsoc/Make.defs | 2 +- arch/arm64/src/zynq-mpsoc/hardware/zynq_pll.h | 102 ++++ arch/arm64/src/zynq-mpsoc/zynq_pll.c | 778 +++++++++++++++++++++++++ arch/arm64/src/zynq-mpsoc/zynq_serial.c | 13 +- boards/arm64/zynq-mpsoc/zcu111/include/board.h | 25 + 6 files changed, 913 insertions(+), 13 deletions(-) diff --git a/arch/arm64/src/zynq-mpsoc/Kconfig b/arch/arm64/src/zynq-mpsoc/Kconfig index 56836b8709..ff99b4701b 100644 --- a/arch/arm64/src/zynq-mpsoc/Kconfig +++ b/arch/arm64/src/zynq-mpsoc/Kconfig @@ -17,12 +17,6 @@ config XPAR_CPU_CORTEXA53_0_TIMESTAMP_CLK_FREQ ---help--- Canonical definitions for peripheral PSU_CORTEXA53_0. -config XPAR_PSU_UART_0_UART_CLK_FREQ_HZ - int "Zynq Mpsoc uart0 clock" - default 99999001 - ---help--- - Clock definitions for uart0. - menu "XILINX ZYNQ_MPSOC Peripheral Selection" config ZYNQ_MPSOC_UART0 diff --git a/arch/arm64/src/zynq-mpsoc/Make.defs b/arch/arm64/src/zynq-mpsoc/Make.defs index bc4c9145e8..c3df6cded4 100644 --- a/arch/arm64/src/zynq-mpsoc/Make.defs +++ b/arch/arm64/src/zynq-mpsoc/Make.defs @@ -23,7 +23,7 @@ include common/Make.defs # Rockchip zynq mpsoc specific C source files -CHIP_CSRCS = zynq_boot.c zynq_serial.c zynq_mio.c zynq_timer.c +CHIP_CSRCS = zynq_boot.c zynq_serial.c zynq_mio.c zynq_timer.c zynq_pll.c ifeq ($(CONFIG_ARCH_EARLY_PRINT),y) CHIP_ASRCS = zynq_lowputc.S diff --git a/arch/arm64/src/zynq-mpsoc/hardware/zynq_pll.h b/arch/arm64/src/zynq-mpsoc/hardware/zynq_pll.h new file mode 100644 index 0000000000..398f5b3476 --- /dev/null +++ b/arch/arm64/src/zynq-mpsoc/hardware/zynq_pll.h @@ -0,0 +1,102 @@ +/**************************************************************************** + * arch/arm64/src/zynq-mpsoc/hardware/zynq_pll.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM64_SRC_ZYNQ_MPSOC_HARDWARE_ZYNQ_PLL_H +#define __ARCH_ARM64_SRC_ZYNQ_MPSOC_HARDWARE_ZYNQ_PLL_H + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* NOTE: The PLL input (IN) clocks are not available in clock tree */ + +enum mpsoc_clk +{ + iopll, rpll, + apll, dpll, vpll, + iopll_to_fpd, rpll_to_fpd, apll_to_lpd, dpll_to_lpd, vpll_to_lpd, + acpu, acpu_half, + dbg_fpd, dbg_lpd, dbg_trace, dbg_tstmp, + dp_video_ref, dp_audio_ref, + dp_stc_ref, gdma_ref, dpdma_ref, + ddr_ref, sata_ref, pcie_ref, + gpu_ref, gpu_pp0_ref, gpu_pp1_ref, + topsw_main, topsw_lsbus, + gtgref0_ref, + lpd_switch, lpd_lsbus, + usb0_bus_ref, usb1_bus_ref, usb3_dual_ref, usb0, usb1, + cpu_r5, cpu_r5_core, + csu_spb, csu_pll, pcap, + iou_switch, + gem_tsu_ref, gem_tsu, + gem0_ref, gem1_ref, gem2_ref, gem3_ref, + gem0_rx, gem1_rx, gem2_rx, gem3_rx, + qspi_ref, + sdio0_ref, sdio1_ref, + uart0_ref, uart1_ref, + spi0_ref, spi1_ref, + nand_ref, + i2c0_ref, i2c1_ref, can0_ref, can1_ref, can0, can1, + dll_ref, + adma_ref, + timestamp_ref, + ams_ref, + pl0, pl1, pl2, pl3, + wdt, + ttc0_ref, ttc1_ref, ttc2_ref, ttc3_ref, + clk_max, +}; + +/**************************************************************************** + * Function: mpsoc_clk_rate_get + * + * Description: + * Get controller running frequence + * + * Input Parameters: + * clk - peripheral clock ID + * + * Returned Value: + * Running frequence. + * + ****************************************************************************/ + +uintptr_t mpsoc_clk_rate_get(enum mpsoc_clk clk); + +/**************************************************************************** + * Function: mpsoc_clk_rate_set + * + * Description: + * Set running frequence + * + * Input Parameters: + * clk - peripheral clock ID + * rate - clock freq + * + * Returned Value: + * peripheral running frequence. + * + ****************************************************************************/ + +uintptr_t mpsoc_clk_rate_set(enum mpsoc_clk clk, uintptr_t rate); + +#endif /* __ARCH_ARM54_SRC_ZYNQ_MPSOC_HARDWARE_ZYNQ_PLL_H */ diff --git a/arch/arm64/src/zynq-mpsoc/zynq_pll.c b/arch/arm64/src/zynq-mpsoc/zynq_pll.c new file mode 100644 index 0000000000..2ce894cde0 --- /dev/null +++ b/arch/arm64/src/zynq-mpsoc/zynq_pll.c @@ -0,0 +1,778 @@ +/**************************************************************************** + * arch/arm64/src/zynq-mpsoc/zynq_pll.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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 <inttypes.h> +#include <stdint.h> +#include <stdbool.h> +#include <string.h> +#include <assert.h> +#include <debug.h> +#include <errno.h> +#include "arm64_internal.h" +#include "chip.h" +#include "hardware/zynq_memorymap.h" + +#include "hardware/zynq_pll.h" +#include <arch/board/board.h> + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Register definitions of clock source + ****************************************************************************/ + +#define MPSOC_CLK_MAXDIV 0x3f +#define CLK_CTRL_DIV1_SHIFT 16 +#define CLK_CTRL_DIV1_MASK (MPSOC_CLK_MAXDIV << CLK_CTRL_DIV1_SHIFT) +#define CLK_CTRL_DIV0_SHIFT 8 +#define CLK_CTRL_DIV0_MASK (MPSOC_CLK_MAXDIV << CLK_CTRL_DIV0_SHIFT) +#define CLK_CTRL_SRCSEL_SHIFT 0 +#define CLK_CTRL_SRCSEL_MASK (0x3 << CLK_CTRL_SRCSEL_SHIFT) + +#define PLLCTRL_BYPASS_MASK (0x1 << 3) +#define PLLCTRL_RESET_SHIFT 0 +#define PLLCTRL_RESET_MASK (0x01 << PLLCTRL_RESET_SHIFT) +#define PLLCTRL_FBDIV_SHIFT 8 +#define PLLCTRL_FBDIV_MASK (0x7f << PLLCTRL_FBDIV_SHIFT) +#define PLLCTRL_DIV2_SHIFT 16 +#define PLLCTRL_DIV2_MASK (0x01 << PLLCTRL_DIV2_SHIFT) +#define PLLCTRL_POST_SRC_SHFT 24 +#define PLLCTRL_POST_SRC_MASK (0x7 << PLLCTRL_POST_SRC_SHFT) + +#define SRCSEL_CPU_APLL 0 +#define SRCSEL_CPU_DPLL 2 +#define SRCSEL_CPU_VPLL 3 +#define SRCSEL_PER_IOPLL 0 +#define SRCSEL_PER_RPLL 2 +#define SRCSEL_PER_DPLL_CLK_TO_LPD 3 +#define SRCSEL_DDR_DPLL 0 +#define SRCSEL_DDR_VPLL 1 + +#define POST_SRC_PS_REF_CLK 0 +#define POST_SRC_VIDEO_REF_CLK 4 +#define POST_SRC_ALT_REF_CLK 5 +#define POST_SRC_AUX_REF_CLK 6 +#define POST_SRC_GT_REF_CLK 7 + +/**************************************************************************** + * Full power domain clocks + ****************************************************************************/ + +#define CRF_APB_APLL_CTRL (ZYNQ_MPSOC_CRF_APB_CLKC_ADDR + 0x20) +#define CRF_APB_DPLL_CTRL (ZYNQ_MPSOC_CRF_APB_CLKC_ADDR + 0x2C) +#define CRF_APB_VPLL_CTRL (ZYNQ_MPSOC_CRF_APB_CLKC_ADDR + 0x38) +#define CRF_APB_PLL_STATUS (ZYNQ_MPSOC_CRF_APB_CLKC_ADDR + 0x44) +#define CRF_APB_APLL_TO_LPD_CTRL (ZYNQ_MPSOC_CRF_APB_CLKC_ADDR + 0x48) +#define CRF_APB_DPLL_TO_LPD_CTRL (ZYNQ_MPSOC_CRF_APB_CLKC_ADDR + 0x4C) +#define CRF_APB_VPLL_TO_LPD_CTRL (ZYNQ_MPSOC_CRF_APB_CLKC_ADDR + 0x50) + +/**************************************************************************** + * Peripheral clocks + ****************************************************************************/ + +#define CRF_APB_ACPU_CTRL (ZYNQ_MPSOC_CRF_APB_CLKC_ADDR + 0x60) +#define CRF_APB_DBG_TRACE_CTRL (ZYNQ_MPSOC_CRF_APB_CLKC_ADDR + 0x64) +#define CRF_APB_DBG_FPD_CTRL (ZYNQ_MPSOC_CRF_APB_CLKC_ADDR + 0x68) +#define CRF_APB_DP_VIDEO_REF_CTRL (ZYNQ_MPSOC_CRF_APB_CLKC_ADDR + 0x70) +#define CRF_APB_DP_AUDIO_REF_CTRL (ZYNQ_MPSOC_CRF_APB_CLKC_ADDR + 0x74) +#define CRF_APB_DP_STC_REF_CTRL (ZYNQ_MPSOC_CRF_APB_CLKC_ADDR + 0x7C) +#define CRF_APB_DDR_CTRL (ZYNQ_MPSOC_CRF_APB_CLKC_ADDR + 0x80) +#define CRF_APB_GPU_REF_CTRL (ZYNQ_MPSOC_CRF_APB_CLKC_ADDR + 0x84) +#define CRF_APB_SATA_REF_CTRL (ZYNQ_MPSOC_CRF_APB_CLKC_ADDR + 0xA0) +#define CRF_APB_PCIE_REF_CTRL (ZYNQ_MPSOC_CRF_APB_CLKC_ADDR + 0xB4) +#define CRF_APB_GDMA_REF_CTRL (ZYNQ_MPSOC_CRF_APB_CLKC_ADDR + 0xB8) +#define CRF_APB_DPDMA_REF_CTRL (ZYNQ_MPSOC_CRF_APB_CLKC_ADDR + 0xBC) +#define CRF_APB_TOPSW_MAIN_CTRL (ZYNQ_MPSOC_CRF_APB_CLKC_ADDR + 0xC0) +#define CRF_APB_TOPSW_LSBUS_CTRL (ZYNQ_MPSOC_CRF_APB_CLKC_ADDR + 0xC4) +#define CRF_APB_DBG_TSTMP_CTRL (ZYNQ_MPSOC_CRF_APB_CLKC_ADDR + 0xF8) + +/**************************************************************************** + * Low power domain clocks + ****************************************************************************/ + +#define CRL_APB_IOPLL_CTRL (ZYNQ_MPSOC_CRL_APB_CLKC_ADDR + 0x20) +#define CRL_APB_RPLL_CTRL (ZYNQ_MPSOC_CRL_APB_CLKC_ADDR + 0x30) +#define CRL_APB_PLL_STATUS (ZYNQ_MPSOC_CRL_APB_CLKC_ADDR + 0x40) +#define CRL_APB_IOPLL_TO_FPD_CTRL (ZYNQ_MPSOC_CRL_APB_CLKC_ADDR + 0x44) +#define CRL_APB_RPLL_TO_FPD_CTRL (ZYNQ_MPSOC_CRL_APB_CLKC_ADDR + 0x48) + +/**************************************************************************** + * Peripheral clocks + ****************************************************************************/ + +#define CRL_APB_USB3_DUAL_REF_CTRL (ZYNQ_MPSOC_CRL_APB_CLKC_ADDR + 0x4C) +#define CRL_APB_GEM0_REF_CTRL (ZYNQ_MPSOC_CRL_APB_CLKC_ADDR + 0x50) +#define CRL_APB_GEM1_REF_CTRL (ZYNQ_MPSOC_CRL_APB_CLKC_ADDR + 0x54) +#define CRL_APB_GEM2_REF_CTRL (ZYNQ_MPSOC_CRL_APB_CLKC_ADDR + 0x58) +#define CRL_APB_GEM3_REF_CTRL (ZYNQ_MPSOC_CRL_APB_CLKC_ADDR + 0x5C) +#define CRL_APB_USB0_BUS_REF_CTRL (ZYNQ_MPSOC_CRL_APB_CLKC_ADDR + 0x60) +#define CRL_APB_USB1_BUS_REF_CTRL (ZYNQ_MPSOC_CRL_APB_CLKC_ADDR + 0x64) +#define CRL_APB_QSPI_REF_CTRL (ZYNQ_MPSOC_CRL_APB_CLKC_ADDR + 0x68) +#define CRL_APB_SDIO0_REF_CTRL (ZYNQ_MPSOC_CRL_APB_CLKC_ADDR + 0x6C) +#define CRL_APB_SDIO1_REF_CTRL (ZYNQ_MPSOC_CRL_APB_CLKC_ADDR + 0x70) +#define CRL_APB_UART0_REF_CTRL (ZYNQ_MPSOC_CRL_APB_CLKC_ADDR + 0x74) +#define CRL_APB_UART1_REF_CTRL (ZYNQ_MPSOC_CRL_APB_CLKC_ADDR + 0x78) +#define CRL_APB_SPI0_REF_CTRL (ZYNQ_MPSOC_CRL_APB_CLKC_ADDR + 0x7C) +#define CRL_APB_SPI1_REF_CTRL (ZYNQ_MPSOC_CRL_APB_CLKC_ADDR + 0x80) +#define CRL_APB_CAN0_REF_CTRL (ZYNQ_MPSOC_CRL_APB_CLKC_ADDR + 0x84) +#define CRL_APB_CAN1_REF_CTRL (ZYNQ_MPSOC_CRL_APB_CLKC_ADDR + 0x88) +#define CRL_APB_CPU_R5_CTRL (ZYNQ_MPSOC_CRL_APB_CLKC_ADDR + 0x90) +#define CRL_APB_IOU_SWITCH_CTRL (ZYNQ_MPSOC_CRL_APB_CLKC_ADDR + 0x9C) +#define CRL_APB_CSU_PLL_CTRL (ZYNQ_MPSOC_CRL_APB_CLKC_ADDR + 0xA0) +#define CRL_APB_PCAP_CTRL (ZYNQ_MPSOC_CRL_APB_CLKC_ADDR + 0xA4) +#define CRL_APB_LPD_SWITCH_CTRL (ZYNQ_MPSOC_CRL_APB_CLKC_ADDR + 0xA8) +#define CRL_APB_LPD_LSBUS_CTRL (ZYNQ_MPSOC_CRL_APB_CLKC_ADDR + 0xAC) +#define CRL_APB_DBG_LPD_CTRL (ZYNQ_MPSOC_CRL_APB_CLKC_ADDR + 0xB0) +#define CRL_APB_NAND_REF_CTRL (ZYNQ_MPSOC_CRL_APB_CLKC_ADDR + 0xB4) +#define CRL_APB_ADMA_REF_CTRL (ZYNQ_MPSOC_CRL_APB_CLKC_ADDR + 0xB8) +#define CRL_APB_PL0_REF_CTRL (ZYNQ_MPSOC_CRL_APB_CLKC_ADDR + 0xC0) +#define CRL_APB_PL1_REF_CTRL (ZYNQ_MPSOC_CRL_APB_CLKC_ADDR + 0xC4) +#define CRL_APB_PL2_REF_CTRL (ZYNQ_MPSOC_CRL_APB_CLKC_ADDR + 0xC8) +#define CRL_APB_PL3_REF_CTRL (ZYNQ_MPSOC_CRL_APB_CLKC_ADDR + 0xCC) +#define CRL_APB_PL0_THR_CNT (ZYNQ_MPSOC_CRL_APB_CLKC_ADDR + 0xD4) +#define CRL_APB_PL1_THR_CNT (ZYNQ_MPSOC_CRL_APB_CLKC_ADDR + 0xDC) +#define CRL_APB_PL2_THR_CNT (ZYNQ_MPSOC_CRL_APB_CLKC_ADDR + 0xE4) +#define CRL_APB_PL3_THR_CNT (ZYNQ_MPSOC_CRL_APB_CLKC_ADDR + 0xFC) +#define CRL_APB_GEM_TSU_REF_CTRL (ZYNQ_MPSOC_CRL_APB_CLKC_ADDR + 0x100) +#define CRL_APB_DLL_REF_CTRL (ZYNQ_MPSOC_CRL_APB_CLKC_ADDR + 0x104) +#define CRL_APB_AMS_REF_CTRL (ZYNQ_MPSOC_CRL_APB_CLKC_ADDR + 0x108) +#define CRL_APB_I2C0_REF_CTRL (ZYNQ_MPSOC_CRL_APB_CLKC_ADDR + 0x120) +#define CRL_APB_I2C1_REF_CTRL (ZYNQ_MPSOC_CRL_APB_CLKC_ADDR + 0x124) +#define CRL_APB_TIMESTAMP_REF_CTRL (ZYNQ_MPSOC_CRL_APB_CLKC_ADDR + 0x128) + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: mpsoc_clk_register_get + * + * Description: + * Get register of the give closk source. + * + * Input Parameters: + * clk_pll - Clock source + * + * Returned Value: + * Ctrl register address of input clock source. + * + * Assumptions: + * + ****************************************************************************/ + +static uint32_t mpsoc_clk_register_get(enum mpsoc_clk clk_pll) +{ + switch (clk_pll) + { + case iopll: + return CRL_APB_IOPLL_CTRL; + case rpll: + return CRL_APB_RPLL_CTRL; + case apll: + return CRF_APB_APLL_CTRL; + case dpll: + return CRF_APB_DPLL_CTRL; + case vpll: + return CRF_APB_VPLL_CTRL; + case acpu: + return CRF_APB_ACPU_CTRL; + case ddr_ref: + return CRF_APB_DDR_CTRL; + case qspi_ref: + return CRL_APB_QSPI_REF_CTRL; + case gem0_ref: + return CRL_APB_GEM0_REF_CTRL; + case gem1_ref: + return CRL_APB_GEM1_REF_CTRL; + case gem2_ref: + return CRL_APB_GEM2_REF_CTRL; + case gem3_ref: + return CRL_APB_GEM3_REF_CTRL; + case uart0_ref: + return CRL_APB_UART0_REF_CTRL; + case uart1_ref: + return CRL_APB_UART1_REF_CTRL; + case sdio0_ref: + return CRL_APB_SDIO0_REF_CTRL; + case sdio1_ref: + return CRL_APB_SDIO1_REF_CTRL; + case spi0_ref: + return CRL_APB_SPI0_REF_CTRL; + case spi1_ref: + return CRL_APB_SPI1_REF_CTRL; + case nand_ref: + return CRL_APB_NAND_REF_CTRL; + case i2c0_ref: + return CRL_APB_I2C0_REF_CTRL; + case i2c1_ref: + return CRL_APB_I2C1_REF_CTRL; + case can0_ref: + return CRL_APB_CAN0_REF_CTRL; + case can1_ref: + return CRL_APB_CAN1_REF_CTRL; + case sata_ref: + return CRF_APB_SATA_REF_CTRL; + default: + _err("Invalid clk id%d\n", clk_pll); + } + + return 0; +} + +/**************************************************************************** + * Function: mpsoc_clk_pll_get + * + * Description: + * Get clock source post frequence + * + * Input Parameters: + * clk_ctrl - Ctrl register value of clock source. + * + * Returned Value: + * Clock source post frequence. + * + ****************************************************************************/ + +static uintptr_t mpsoc_clk_pll_get(uintptr_t clk_ctrl) +{ + uint32_t src_sel; + + src_sel = (clk_ctrl & PLLCTRL_POST_SRC_MASK) >> + PLLCTRL_POST_SRC_SHFT; /* get pass-thru clock source */ + + switch (src_sel) + { + case POST_SRC_VIDEO_REF_CLK: /* Clock src is Video Ref Clk */ + return CLK_CCF_VIDEO_CLK; + + case POST_SRC_ALT_REF_CLK: /* Clock src is Alt Ref Clk */ + return CLK_CCF_ALT_REF_CLK; + + case POST_SRC_AUX_REF_CLK: /* Clock src is Aux Ref Clk */ + return CLK_CCF_AUX_REF_CLK; + + case POST_SRC_GT_REF_CLK: /* Clock src is GT Ref Clk */ + return CLK_CCF_GT_CRX_REF_CLK; + + default: /* Clock src is PS Ref Clk */ + return CLK_CCF_PSS_REF_CLK; + } +} + +/**************************************************************************** + * Function: mpsoc_clk_pll_rate_get + * + * Description: + * Get clock source pll output frequence + * + * Input Parameters: + * clk_pll - clock source pll. + * + * Returned Value: + * Pll output frequence. + * + ****************************************************************************/ + +static uintptr_t mpsoc_clk_pll_rate_get(enum mpsoc_clk clk_pll) +{ + uint32_t clkctrl; + uint32_t reset; + uint32_t mul; + uintptr_t freq; + + clkctrl = getreg32(mpsoc_clk_register_get(clk_pll)); /* Get clock source config */ + freq = mpsoc_clk_pll_get(clkctrl); /* Get clock source post freq */ + + reset = (clkctrl & PLLCTRL_RESET_MASK) >> PLLCTRL_RESET_SHIFT; /* Get PLL reset status */ + if (reset && !(clkctrl & PLLCTRL_BYPASS_MASK)) /* PLL is reset state */ + { + return 0; /* return immediately */ + } + + mul = (clkctrl & PLLCTRL_FBDIV_MASK) >> PLLCTRL_FBDIV_SHIFT; /* Get PLL clock Feedback */ + freq *= mul; + + if (clkctrl & PLLCTRL_DIV2_MASK) /* Is Div2 enabled? */ + { + freq /= 2; + } + + return freq; +} + +/**************************************************************************** + * Function: mpsoc_cpu_clk_pll_get + * + * Description: + * Get clock source pll of ARM CPU + * + * Input Parameters: + * clkctrl - Ctrl register value of cpu clock source. + * + * Returned Value: + * Clock source pll of ARM CPU. + * + ****************************************************************************/ + +static enum mpsoc_clk mpsoc_cpu_clk_pll_get(uint32_t clkctrl) +{ + /* Get clock source pll of CPU */ + + uint32_t src_sel = (clkctrl & CLK_CTRL_SRCSEL_MASK) >> + CLK_CTRL_SRCSEL_SHIFT; + + switch (src_sel) + { + case SRCSEL_CPU_DPLL: /* clock source is DPLL */ + return dpll; + + case SRCSEL_CPU_VPLL: /* clock source is VPLL */ + return vpll; + + case SRCSEL_CPU_APLL: /* clock source is APLL */ + default: + return apll; + } +} + +/**************************************************************************** + * Function: mpsoc_ddr_clk_pll_get + * + * Description: + * Get clock source pll of DDR + * + * Input Parameters: + * clkctrl - Ctrl register value of ddr clock source. + * + * Returned Value: + * Clock source pll of DDR. + * + ****************************************************************************/ + +static enum mpsoc_clk mpsoc_ddr_clk_pll_get(uint32_t clkctrl) +{ + /* Get clock source pll of DDR */ + + uint32_t src_sel = (clkctrl & CLK_CTRL_SRCSEL_MASK) >> + CLK_CTRL_SRCSEL_SHIFT; + + switch (src_sel) + { + case SRCSEL_DDR_VPLL: /* clock source is VPLL */ + return vpll; + + case SRCSEL_DDR_DPLL: /* clock source is DPLL */ + default: + return dpll; + } +} + +/**************************************************************************** + * Function: mpsoc_peripheral_clk_pll_set + * + * Description: + * Get clock source pll of peripheral + * + * Input Parameters: + * clkctrl - Ctrl register value of peripheral clock source. + * + * Returned Value: + * Clock source pll of peripheral. + * + ****************************************************************************/ + +static enum mpsoc_clk mpsoc_peripheral_clk_pll_set(uint32_t clkctrl) +{ + /* Get clock source pll of peripheral */ + + uint32_t src_sel = (clkctrl & CLK_CTRL_SRCSEL_MASK) >> + CLK_CTRL_SRCSEL_SHIFT; + + switch (src_sel) + { + case SRCSEL_PER_RPLL: + return rpll; + + case SRCSEL_PER_DPLL_CLK_TO_LPD: + return dpll; + + case SRCSEL_PER_IOPLL: + default: + return iopll; + } +} + +/**************************************************************************** + * Function: mpsoc_cpu_clk_get + * + * Description: + * Get ARM CPU running frequence + * + * Input Parameters: + * none. + * + * Returned Value: + * ARM CPU running frequence. + * + ****************************************************************************/ + +static uint32_t mpsoc_cpu_clk_get(void) +{ + uint32_t div; + uint32_t clkctrl; + enum mpsoc_clk pllsrc; + uint32_t pll_rate; + + clkctrl = getreg32(CRF_APB_ACPU_CTRL); + + /* Get CPU clock divisor value */ + + div = (clkctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT; + + pllsrc = mpsoc_cpu_clk_pll_get(clkctrl); /* Get CPU pll src */ + pll_rate = mpsoc_clk_pll_rate_get(pllsrc); /* Get CPU clock div freq */ + + return div_round_closest(pll_rate, div); +} + +/**************************************************************************** + * Function: mpsoc_ddr_clk_get + * + * Description: + * Get DDR running frequence + * + * Input Parameters: + * none. + * + * Returned Value: + * DDR running frequence. + * + ****************************************************************************/ + +static uint32_t mpsoc_ddr_clk_get(void) +{ + uint32_t div; + uint32_t clkctrl; + enum mpsoc_clk pllsrc; + uint32_t pll_rate; + + clkctrl = getreg32(CRF_APB_DDR_CTRL); + + /* Get DDR clock division */ + + div = (clkctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT; + + pllsrc = mpsoc_ddr_clk_pll_get(clkctrl); /* Get DDR clock src */ + pll_rate = mpsoc_clk_pll_rate_get(pllsrc); /* Get DDR running freq */ + + return div_round_closest(pll_rate, div); +} + +/**************************************************************************** + * Function: mpsoc_peripheral_clk_get + * + * Description: + * Get peripheral running frequence + * + * Input Parameters: + * peripheral clock ID. + * + * Returned Value: + * peripheral running frequence. + * + ****************************************************************************/ + +static uint32_t mpsoc_peripheral_clk_get(enum mpsoc_clk clk) +{ + enum mpsoc_clk pll; + uint32_t clkctrl; + uint32_t div0; + uint32_t div1; + uintptr_t pll_rate; + + clkctrl = getreg32(mpsoc_clk_register_get(clk)); + + div0 = (clkctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT; + if (!div0) + { + div0 = 1; /* if divisor0 is 0, set it as 1 */ + } + + div1 = (clkctrl & CLK_CTRL_DIV1_MASK) >> CLK_CTRL_DIV1_SHIFT; + if (!div1) + { + div1 = 1; /* if divisor1 is 0, set it as 1 */ + } + + pll = mpsoc_peripheral_clk_pll_set(clkctrl); + pll_rate = mpsoc_clk_pll_rate_get(pll); + + return div_round_closest(div_round_closest(pll_rate, div0), div1); +} + +/**************************************************************************** + * Function: mpsoc_peripheral_clk_two_divs_calc + * + * Description: + * Get peripheral running frequence + * + * Input Parameters: + * rate - clock freq + * ulPllRate - pll freq + * div0 - divisor0 + * div1 - divisor1 + * + * Returned Value: + * best running frequence. + * + ****************************************************************************/ + +static uintptr_t mpsoc_peripheral_clk_two_divs_calc(uintptr_t rate, + uintptr_t pll_rate, + uint32_t *div0, + uint32_t *div1) +{ + uint32_t id0; + uint32_t id1; + uintptr_t new_rate; + uintptr_t best_rate = 0; + intptr_t new_err; + intptr_t best_err = (intptr_t)(~0UL >> 1); + + for (id0 = 1; id0 <= MPSOC_CLK_MAXDIV; id0++) + { + for (id1 = 1; id1 <= MPSOC_CLK_MAXDIV >> 1; id1++) + { + new_rate = div_round_closest(div_round_closest(pll_rate, id0), + id1); + new_err = abs(new_rate - rate); + + if (new_err < best_err) + { + *div0 = id0; + *div1 = id1; + best_err = new_err; + best_rate = new_rate; + } + } + } + + return best_rate; +} + +/**************************************************************************** + * Function: mpsoc_peripheral_clk_set + * + * Description: + * Set peripheral running frequence + * + * Input Parameters: + * clk - peripheral clock ID + * rate - clock freq + * + * Returned Value: + * New peripheral running frequence. + * + ****************************************************************************/ + +static uint32_t mpsoc_peripheral_clk_set(enum mpsoc_clk clk, uintptr_t rate) +{ + uint32_t clkctrl; + uint32_t new_rate; + uint32_t div0 = 0; + uint32_t div1 = 0; + uint32_t mask; + uint32_t regval; + uint32_t regadd; + enum mpsoc_clk pll; + uintptr_t pll_rate; + + regadd = mpsoc_clk_register_get(clk); + clkctrl = getreg32(regadd); + + pll = mpsoc_peripheral_clk_pll_set(clkctrl); + pll_rate = mpsoc_clk_pll_rate_get(pll); + + clkctrl &= ~CLK_CTRL_DIV0_MASK; + clkctrl &= ~CLK_CTRL_DIV1_MASK; + + new_rate = mpsoc_peripheral_clk_two_divs_calc(rate, pll_rate, + &div0, &div1); + clkctrl |= div1 << CLK_CTRL_DIV1_SHIFT; + clkctrl |= div0 << CLK_CTRL_DIV0_SHIFT; + + mask = (MPSOC_CLK_MAXDIV << CLK_CTRL_DIV0_SHIFT) | + (MPSOC_CLK_MAXDIV << CLK_CTRL_DIV1_SHIFT); + + regval = getreg32(regadd); + regval &= ~mask; + regval |= clkctrl; + + putreg32(regval, regadd); + + return new_rate; +} + +/**************************************************************************** + * Function: mpsoc_ttc_clk_get + * + * Description: + * Get ttc controller running frequence + * + * Input Parameters: + * clk - peripheral clock ID + * + * Returned Value: + * PLL frequence. + * + ****************************************************************************/ + +static uint32_t mpsoc_ttc_clk_get(enum mpsoc_clk clk) +{ + uint32_t clk_sel; + uint32_t clkctrl = 0; + uintptr_t freq = 0; + + /* Get IOU_TTC_APB_CLK */ + + clk_sel = getreg32(ZYNQ_MPSOC_IOU_SLCR_ADDR + 0x380); + clk_sel = (clk_sel >> (clk - ttc0_ref)) & 0x3; + + switch (clk_sel) + { + case 0: + clkctrl = getreg32(CRL_APB_LPD_LSBUS_CTRL); /* Get LPD LSBUS clock src config */ + break; + + case 0x1: + freq = mpsoc_clk_pll_get(POST_SRC_PS_REF_CLK); + break; + + case 0x2: + clkctrl = getreg32(CRL_APB_CPU_R5_CTRL); /* Get RPU clock src config */ + break; + + case 0x3: + break; + default: + break; + } + + if (!clkctrl) + { + return (freq); + } + + if ((clkctrl & 0x3) == 0x00) + { + return mpsoc_clk_pll_rate_get(rpll); + } + else if ((clkctrl & 0x3) == 0x2) + { + return mpsoc_clk_pll_rate_get(iopll); + } + else + { + return mpsoc_clk_pll_rate_get(dpll); + } + + return freq; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: mpsoc_clk_rate_get + * + * Description: + * Get controller running frequence + * + * Input Parameters: + * clk - peripheral clock ID + * + * Returned Value: + * Running frequence. + * + ****************************************************************************/ + +uintptr_t mpsoc_clk_rate_get(enum mpsoc_clk clk) +{ + switch (clk) + { + case iopll ... vpll: + return mpsoc_clk_pll_rate_get(clk); + + case acpu: + return mpsoc_cpu_clk_get(); + + case ddr_ref: + return mpsoc_ddr_clk_get(); + + case gem0_ref ... gem3_ref: + case qspi_ref ... can1_ref: + return mpsoc_peripheral_clk_get(clk); + + case ttc0_ref ... ttc3_ref: + return mpsoc_ttc_clk_get(clk); + + default: + return -ENXIO; + } +} + +/**************************************************************************** + * Function: mpsoc_clk_rate_set + * + * Description: + * Set running frequence + * + * Input Parameters: + * clk - peripheral clock ID + * rate - clock freq + * + * Returned Value: + * peripheral running frequence. + * + ****************************************************************************/ + +uintptr_t mpsoc_clk_rate_set(enum mpsoc_clk clk, uintptr_t rate) +{ + switch (clk) + { + case gem0_ref ... gem3_ref: + case qspi_ref ... can1_ref: + return mpsoc_peripheral_clk_set(clk, rate); + + default: + return -ENXIO; + } +} diff --git a/arch/arm64/src/zynq-mpsoc/zynq_serial.c b/arch/arm64/src/zynq-mpsoc/zynq_serial.c index 5ebe2b066e..8b58718cfc 100644 --- a/arch/arm64/src/zynq-mpsoc/zynq_serial.c +++ b/arch/arm64/src/zynq-mpsoc/zynq_serial.c @@ -52,6 +52,7 @@ #include "arm64_arch_timer.h" #include "zynq_boot.h" #include "arm64_gic.h" +#include "hardware/zynq_pll.h" #ifdef USE_SERIALDRIVER @@ -502,7 +503,7 @@ static int zynq_uart_irq_handler(int irq, void *context, void *arg) return OK; } -static int zynq_uart_baudrate(struct uart_dev_s *dev, uint32_t in_clk) +static int zynq_uart_baudrate(struct uart_dev_s *dev) { struct zynq_uart_port_s *port = (struct zynq_uart_port_s *)dev->priv; const struct zynq_uart_config *config = &port->config; @@ -524,11 +525,13 @@ static int zynq_uart_baudrate(struct uart_dev_s *dev, uint32_t in_clk) DEBUGASSERT(data->baud_rate <= (uint32_t)XUARTPS_MAX_RATE); DEBUGASSERT(data->baud_rate >= (uint32_t)XUARTPS_MIN_RATE); + input_clk = mpsoc_clk_rate_get(uart0_ref); + /* Make sure the baud rate is not impossilby large. * Fastest possible baud rate is Input Clock / 2. */ - if ((data->baud_rate * 2) > in_clk) + if ((data->baud_rate * 2) > input_clk) { return ERROR; } @@ -537,10 +540,9 @@ static int zynq_uart_baudrate(struct uart_dev_s *dev, uint32_t in_clk) reg = getreg32(config->uart + XUARTPS_MR_OFFSET); - input_clk = in_clk; if (reg & XUARTPS_MR_CLKSEL) { - input_clk = in_clk / 8; + input_clk = input_clk / 8; } /* Determine the Baud divider. It can be 4to 254. @@ -638,8 +640,7 @@ static int zynq_uart_setup(struct uart_dev_s *dev) DEBUGASSERT(data != NULL); - if (zynq_uart_baudrate(dev, CONFIG_XPAR_PSU_UART_0_UART_CLK_FREQ_HZ) - != OK) + if (zynq_uart_baudrate(dev) != OK) { return ERROR; } diff --git a/boards/arm64/zynq-mpsoc/zcu111/include/board.h b/boards/arm64/zynq-mpsoc/zcu111/include/board.h index 701f14a951..b72cbc7709 100644 --- a/boards/arm64/zynq-mpsoc/zcu111/include/board.h +++ b/boards/arm64/zynq-mpsoc/zcu111/include/board.h @@ -75,4 +75,29 @@ #define LED_ASSERTION 2 #define LED_PANIC 1 +/**************************************************************************** + * The clock of MPSOC include low power field and Full power field + * The low power field include: + * I/O PLL(IOPLL) and RPU PLL(RPLL) + * The full power field include: + * APU PLL(APLL) Video PLL(VPLL) and DDR PLL(DPLL) + + * There are 5 clock source: + * 1. PS_REF_CLK (device pin, normal source). + * 2. ALT_REF_CLK (one of two MIO pins). + * 3. VIDEO_REF_CLK (one of two MIO pins). + * 4. AUX_REF_CLK (PL fabric source). + * 5. GTR_REF_CLK (multiplexer output from GTR serial unit). + ****************************************************************************/ + +/**************************************************************************** + * Clock frequence defnition + ****************************************************************************/ + +#define CLK_CCF_VIDEO_CLK 27000000 +#define CLK_CCF_PSS_REF_CLK 33333333 +#define CLK_CCF_GT_CRX_REF_CLK 108000000 +#define CLK_CCF_AUX_REF_CLK 27000000 +#define CLK_CCF_ALT_REF_CLK 0 + #endif /* __BOARDS_ARM64_ZYNQ_MPSOC_ZCU111_INCLUDE_BOARD_H */