From mboxrd@z Thu Jan 1 00:00:00 1970 From: Ley Foon Tan Date: Fri, 10 May 2019 13:54:41 +0800 Subject: [U-Boot] [PATCH 07/14] arm: socfpga: agilex: Add clock manager support In-Reply-To: <1557467688-73706-1-git-send-email-ley.foon.tan@intel.com> References: <1557467688-73706-1-git-send-email-ley.foon.tan@intel.com> Message-ID: <1557467688-73706-8-git-send-email-ley.foon.tan@intel.com> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de Add clock manager support for Agilex. Signed-off-by: Chee Hong Ang Signed-off-by: Ley Foon Tan --- arch/arm/mach-socfpga/Makefile | 4 + arch/arm/mach-socfpga/clock_manager_agilex.c | 582 ++++++++++++++++++ .../mach-socfpga/include/mach/clock_manager.h | 2 + .../include/mach/clock_manager_agilex.h | 328 ++++++++++ 4 files changed, 916 insertions(+) create mode 100644 arch/arm/mach-socfpga/clock_manager_agilex.c create mode 100644 arch/arm/mach-socfpga/include/mach/clock_manager_agilex.h diff --git a/arch/arm/mach-socfpga/Makefile b/arch/arm/mach-socfpga/Makefile index 11370cf4c4..5bb36d07df 100644 --- a/arch/arm/mach-socfpga/Makefile +++ b/arch/arm/mach-socfpga/Makefile @@ -40,6 +40,10 @@ obj-y += wrap_pinmux_config_s10.o obj-y += wrap_pll_config_s10.o endif +ifdef CONFIG_TARGET_SOCFPGA_AGILEX +obj-y += clock_manager_agilex.o +endif + ifdef CONFIG_SPL_BUILD ifdef CONFIG_TARGET_SOCFPGA_GEN5 obj-y += spl_gen5.o diff --git a/arch/arm/mach-socfpga/clock_manager_agilex.c b/arch/arm/mach-socfpga/clock_manager_agilex.c new file mode 100644 index 0000000000..d45827fd27 --- /dev/null +++ b/arch/arm/mach-socfpga/clock_manager_agilex.c @@ -0,0 +1,582 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 Intel Corporation + * + */ + +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +static const struct socfpga_system_manager *sysmgr_regs = + (struct socfpga_system_manager *)SOCFPGA_SYSMGR_ADDRESS; + +/* Default clock manager settings for handoff structure */ +const struct cm_config cm_default_handoff = { + /* main group */ + /* main_pll_mpuclk: src = MAIN, cnt = 0 */ + 0x00000000, + /* main_pll_nocclk: src = PERI */ + 0x00010000, + /* main_pll_nocdiv: + * cspdbgclk = Div4, cstraceckj = Div1, csclk = Div1 + * l4spclk = Div4, l4mpclk = Div2, l4mainclk = Div1 + */ + 0x10020100, + /* main_pll_pllglob: arefclkdiv = 1, drefclkdiv = 0, modclkdiv = 5 */ + 0x15000101, + /* main_pll_fdbck: fdiv = 0 */ + 0x00000000, + /* main_pll_pllc0: div = 3 */ + 0x00000003 | CLKMGR_PLLCX_EN_SET_MSK, + /* main_pll_pllc1: div = 8, mute = 1 */ + (0x10000008 & ~CLKMGR_PLLCX_MUTE_SET_MSK) | CLKMGR_PLLCX_EN_SET_MSK, + /* main_pll_pllc2: div = 6 */ + 0x00000006 | CLKMGR_PLLCX_EN_SET_MSK, + /* main_pll_pllc3: div = 15, mute = 1 */ + (0x1000000f & ~CLKMGR_PLLCX_MUTE_SET_MSK) | CLKMGR_PLLCX_EN_SET_MSK, + /* main_pll_pllm: mdiv = 120 */ + 0x00000078, + + /* peripheral group */ + /* per_pll_emacctl: + * emac0sel = EMACA, emac1sel = EMACA, emac2sel = EMACA + */ + 0x00000000, + /* per_pll_gpiodiv: gpiodbclk = 1 */ + 0x00000001, + /* per_pll_pllglob: arefclkdiv = 1, drefclkdiv = 0, modclkdiv = 4 */ + 0x14000101, + /* per_pll_fdbck: fdiv = 0 */ + 0x22000000, + /* per_pll_pllc0: div = 2, mute = 1 */ + (0x10000002 & ~CLKMGR_PLLCX_MUTE_SET_MSK) | CLKMGR_PLLCX_EN_SET_MSK, + /* per_pll_pllc1: div = 6 */ + 0x00000006 | CLKMGR_PLLCX_EN_SET_MSK, + /* per_pll_pllc2: div = 5, mute = 1 */ + (0x10000005 & ~CLKMGR_PLLCX_MUTE_SET_MSK) | CLKMGR_PLLCX_EN_SET_MSK, + /* per_pll_pllc3: div = 12 */ + 0x0000000c | CLKMGR_PLLCX_EN_SET_MSK, + /* per_pll_pllm: mdiv = 96 */ + 0x00000060, + + /* altera group */ + /* alt_emacactr: src = MAIN, cnt = 1 */ + 0x00000001, + /* alt_emacbctr: src = PERI, cnt = 3 */ + 0x00010003, + /* alt_emacptpctr: src = PERI, cnt = 1 */ + 0x00010001, + /* alt_gpiodbctr: src = PERI, cnt = 0 */ + 0x00010000, + /* alt_sdmmcctr: src = PERI, cnt = 0 */ + 0x00010000, + /* alt_s2fuser0ctr: src = MAIN, cnt = 0 */ + 0x00000000, + /* alt_s2fuser1ctr: src = MAIN, cnt = 0 */ + 0x00000000, + /* alt_psirefctr: src = MAIN, cnt = 0 */ + 0x00000000, + + /* incoming clock */ + /* hps_osc_clk_hz: 25MHz */ + 0x017d7840, + /* fpga_clk_hz: 200MHz */ + 0x0bebc200, + /* unused */ + { + 0xffffffff, + 0xffffffff, + 0xffffffff + } +}; + +/* + * function to write the bypass register which requires a poll of the + * busy bit + */ +static void cm_write_bypass_mainpll(u32 val) +{ + CM_REG_WRITEL(val, CM_MAINPLL_REG_BYPASS); + cm_wait_for_fsm(); +} + +static void cm_write_bypass_perpll(u32 val) +{ + CM_REG_WRITEL(val, CM_PERPLL_REG_BYPASS); + cm_wait_for_fsm(); +} + +/* function to write the ctrl register which requires a poll of the busy bit */ +static void cm_write_ctrl(u32 val) +{ + CM_REG_WRITEL(val, CM_REG_CTRL); + cm_wait_for_fsm(); +} + +#define MEMBUS_MAINPLL 0 +#define MEMBUS_PERPLL 1 +#define MEMBUS_TIMEOUT 1000 +#define MEMBUS_ADDR_CLKSLICE 0x27 +#define MEMBUS_CLKSLICE_SYNC_MODE_EN 0x80 + +static int membus_wait_for_req(u32 pll, int timeout) +{ + int cnt = 0; + u32 req_status; + + if (pll == MEMBUS_MAINPLL) + req_status = CM_REG_READL(CM_MAINPLL_REG_MEM); + else + req_status = CM_REG_READL(CM_PERPLL_REG_MEM); + + while ((cnt < timeout) && (req_status & CLKMGR_MEM_REQ_SET_MSK)) { + if (pll == MEMBUS_MAINPLL) + req_status = CM_REG_READL(CM_MAINPLL_REG_MEM); + else + req_status = CM_REG_READL(CM_PERPLL_REG_MEM); + cnt++; + } + + if (cnt >= timeout) + return -ETIMEDOUT; + + return 0; +} + +static int membus_write_pll(u32 pll, u32 addr_offset, u32 wdat, int timeout) +{ + u32 addr; + u32 val; + + addr = ((addr_offset | CLKMGR_MEM_ADDR_START) & CLKMGR_MEM_ADDR_MASK); + + val = (CLKMGR_MEM_REQ_SET_MSK | CLKMGR_MEM_WR_SET_MSK | + (wdat << CLKMGR_MEM_WDAT_LSB_OFFSET) | addr); + + if (pll == MEMBUS_MAINPLL) + CM_REG_WRITEL(val, CM_MAINPLL_REG_MEM); + else + CM_REG_WRITEL(val, CM_PERPLL_REG_MEM); + + debug("MEMBUS: Write 0x%08x to addr = 0x%08x\n", wdat, addr); + + return membus_wait_for_req(pll, timeout); +} + +static int membus_read_pll(u32 pll, u32 addr_offset, u32 *rdata, int timeout) +{ + u32 addr; + u32 val; + + addr = ((addr_offset | CLKMGR_MEM_ADDR_START) & CLKMGR_MEM_ADDR_MASK); + + val = ((CLKMGR_MEM_REQ_SET_MSK & ~CLKMGR_MEM_WR_SET_MSK) | addr); + + if (pll == MEMBUS_MAINPLL) + CM_REG_WRITEL(val, CM_MAINPLL_REG_MEM); + else + CM_REG_WRITEL(val, CM_PERPLL_REG_MEM); + + *rdata = 0; + + if (membus_wait_for_req(pll, timeout)) + return -ETIMEDOUT; + + if (pll == MEMBUS_MAINPLL) + *rdata = CM_REG_READL(CM_MAINPLL_REG_MEMSTAT); + else + *rdata = CM_REG_READL(CM_PERPLL_REG_MEMSTAT); + + debug("MEMBUS: Read 0x%08x from addr = 0x%08x\n", *rdata, addr); + + return 0; +} + +static u32 calc_vocalib_pll(u32 pllm, u32 pllglob) +{ + u32 mdiv, refclkdiv, arefclkdiv, drefclkdiv, mscnt, hscnt, vcocalib; + + mdiv = pllm & CLKMGR_PLLM_MDIV_MASK; + arefclkdiv = (pllglob >> CLKMGR_PLLGLOB_AREFCLKDIV_OFFSET) & + CLKMGR_PLLGLOB_AREFCLKDIV_MASK; + drefclkdiv = (pllglob >> CLKMGR_PLLGLOB_DREFCLKDIV_OFFSET) & + CLKMGR_PLLGLOB_DREFCLKDIV_MASK; + refclkdiv = (pllglob >> CLKMGR_PLLGLOB_REFCLKDIV_OFFSET) & + CLKMGR_PLLGLOB_REFCLKDIV_MASK; + mscnt = CLKMGR_VCOCALIB_MSCNT_CONST / (mdiv * BIT(drefclkdiv)); + if (!mscnt) + mscnt = 1; + hscnt = (mdiv * mscnt * BIT(drefclkdiv) / refclkdiv) - + CLKMGR_VCOCALIB_HSCNT_CONST; + vcocalib = (hscnt & CLKMGR_VCOCALIB_HSCNT_MASK) | + ((mscnt & CLKMGR_VCOCALIB_MSCNT_MASK) << + CLKMGR_VCOCALIB_MSCNT_OFFSET); + + /* Dump all the pll calibration settings for debug purposes */ + debug("mdiv : %d\n", mdiv); + debug("arefclkdiv : %d\n", arefclkdiv); + debug("drefclkdiv : %d\n", drefclkdiv); + debug("refclkdiv : %d\n", refclkdiv); + debug("mscnt : %d\n", mscnt); + debug("hscnt : %d\n", hscnt); + debug("vcocalib : 0x%08x\n", vcocalib); + + return vcocalib; +} + +/* + * Setup clocks while making no assumptions about previous state of the clocks. + */ +void cm_basic_init(const struct cm_config * const cfg) +{ + u32 vcocalib; + u32 rdata; + + if (!cfg) + return; + + /* Put both PLLs in bypass */ + cm_write_bypass_mainpll(CLKMGR_BYPASS_MAINPLL_ALL); + cm_write_bypass_perpll(CLKMGR_BYPASS_PERPLL_ALL); + + /* Put both PLLs in Reset and Power Down */ + CM_REG_CLRBITS(CLKMGR_PLLGLOB_PD_MASK | CLKMGR_PLLGLOB_RST_MASK, + CM_MAINPLL_REG_PLLGLOB); + CM_REG_CLRBITS(CLKMGR_PLLGLOB_PD_MASK | CLKMGR_PLLGLOB_RST_MASK, + CM_PERPLL_REG_PLLGLOB); + + /* setup main PLL dividers where calculate the vcocalib value */ + vcocalib = calc_vocalib_pll(cfg->main_pll_pllm, cfg->main_pll_pllglob); + CM_REG_WRITEL(cfg->main_pll_pllglob & ~CLKMGR_PLLGLOB_RST_MASK, + CM_MAINPLL_REG_PLLGLOB); + CM_REG_WRITEL(cfg->main_pll_fdbck, CM_MAINPLL_REG_FDBCK); + CM_REG_WRITEL(vcocalib, CM_MAINPLL_REG_VCOCALIB); + CM_REG_WRITEL(cfg->main_pll_pllc0, CM_MAINPLL_REG_PLLC0); + CM_REG_WRITEL(cfg->main_pll_pllc1, CM_MAINPLL_REG_PLLC1); + CM_REG_WRITEL(cfg->main_pll_pllc2, CM_MAINPLL_REG_PLLC2); + CM_REG_WRITEL(cfg->main_pll_pllc3, CM_MAINPLL_REG_PLLC3); + CM_REG_WRITEL(cfg->main_pll_pllm, CM_MAINPLL_REG_PLLM); + CM_REG_WRITEL(cfg->main_pll_mpuclk, CM_MAINPLL_REG_MPUCLK); + CM_REG_WRITEL(cfg->main_pll_nocclk, CM_MAINPLL_REG_NOCCLK); + CM_REG_WRITEL(cfg->main_pll_nocdiv, CM_MAINPLL_REG_NOCDIV); + + /* setup peripheral PLL dividers where calculate the vcocalib value */ + vcocalib = calc_vocalib_pll(cfg->per_pll_pllm, cfg->per_pll_pllglob); + CM_REG_WRITEL(cfg->per_pll_pllglob & ~CLKMGR_PLLGLOB_RST_MASK, + CM_PERPLL_REG_PLLGLOB); + CM_REG_WRITEL(cfg->per_pll_fdbck, CM_PERPLL_REG_FDBCK); + CM_REG_WRITEL(vcocalib, CM_PERPLL_REG_VCOCALIB); + CM_REG_WRITEL(cfg->per_pll_pllc0, CM_PERPLL_REG_PLLC0); + CM_REG_WRITEL(cfg->per_pll_pllc1, CM_PERPLL_REG_PLLC1); + CM_REG_WRITEL(cfg->per_pll_pllc2, CM_PERPLL_REG_PLLC2); + CM_REG_WRITEL(cfg->per_pll_pllc3, CM_PERPLL_REG_PLLC3); + CM_REG_WRITEL(cfg->per_pll_pllm, CM_PERPLL_REG_PLLM); + CM_REG_WRITEL(cfg->per_pll_emacctl, CM_PERPLL_REG_EMACCTL); + CM_REG_WRITEL(cfg->per_pll_gpiodiv, CM_PERPLL_REG_GPIODIV); + + /* Take both PLL out of reset and power up */ + CM_REG_SETBITS(CLKMGR_PLLGLOB_PD_MASK | CLKMGR_PLLGLOB_RST_MASK, + CM_MAINPLL_REG_PLLGLOB); + CM_REG_SETBITS(CLKMGR_PLLGLOB_PD_MASK | CLKMGR_PLLGLOB_RST_MASK, + CM_PERPLL_REG_PLLGLOB); + + /* Membus programming to set mainpll and perripll to + * source synchronous mode + */ + membus_read_pll(MEMBUS_MAINPLL, MEMBUS_ADDR_CLKSLICE, &rdata, + MEMBUS_TIMEOUT); + membus_write_pll(MEMBUS_MAINPLL, MEMBUS_ADDR_CLKSLICE, + (rdata | MEMBUS_CLKSLICE_SYNC_MODE_EN), + MEMBUS_TIMEOUT); + membus_read_pll(MEMBUS_PERPLL, MEMBUS_ADDR_CLKSLICE, &rdata, + MEMBUS_TIMEOUT); + membus_write_pll(MEMBUS_PERPLL, MEMBUS_ADDR_CLKSLICE, + (rdata | MEMBUS_CLKSLICE_SYNC_MODE_EN), + MEMBUS_TIMEOUT); + + cm_wait_for_lock(CLKMGR_STAT_ALLPLL_LOCKED_MASK); + + /* Configure ping pong counters in altera group */ + CM_REG_WRITEL(cfg->alt_emacactr, CM_ALTERA_REG_EMACACTR); + CM_REG_WRITEL(cfg->alt_emacbctr, CM_ALTERA_REG_EMACBCTR); + CM_REG_WRITEL(cfg->alt_emacptpctr, CM_ALTERA_REG_EMACPTPCTR); + CM_REG_WRITEL(cfg->alt_gpiodbctr, CM_ALTERA_REG_GPIODBCTR); + CM_REG_WRITEL(cfg->alt_sdmmcctr, CM_ALTERA_REG_SDMMCCTR); + CM_REG_WRITEL(cfg->alt_s2fuser0ctr, CM_ALTERA_REG_S2FUSER0CTR); + CM_REG_WRITEL(cfg->alt_s2fuser1ctr, CM_ALTERA_REG_S2FUSER1CTR); + CM_REG_WRITEL(cfg->alt_psirefctr, CM_ALTERA_REG_PSIREFCTR); + + /* Take all PLLs out of bypass */ + cm_write_bypass_mainpll(0); + cm_write_bypass_perpll(0); + + /* Clear the loss of lock bits (write 1 to clear) */ + CM_REG_CLRBITS(CLKMGR_INTER_PERPLLLOST_MASK | + CLKMGR_INTER_MAINPLLLOST_MASK, CM_REG_INTRCLR); + + /* Take all ping pong counters out of reset */ + CM_REG_CLRBITS(CLKMGR_ALT_EXTCNTRST_ALLCNTRST, + CM_ALTERA_REG_EXTCNTRST); + + /* Out of boot mode */ + cm_write_ctrl(CM_REG_READL(CM_REG_CTRL) & ~CLKMGR_CTRL_BOOTMODE); +} + +static u64 cm_get_main_vco_clk_hz(void) +{ + u64 fref, arefdiv, mdiv, reg, vco; + + reg = CM_REG_READL(CM_MAINPLL_REG_PLLGLOB); + + fref = (reg >> CLKMGR_PLLGLOB_VCO_PSRC_OFFSET) & + CLKMGR_PLLGLOB_VCO_PSRC_MASK; + + switch (fref) { + case CLKMGR_VCO_PSRC_EOSC1: + fref = cm_get_osc_clk_hz(); + break; + case CLKMGR_VCO_PSRC_INTOSC: + fref = cm_get_intosc_clk_hz(); + break; + case CLKMGR_VCO_PSRC_F2S: + fref = cm_get_fpga_clk_hz(); + break; + } + + arefdiv = (reg >> CLKMGR_PLLGLOB_AREFCLKDIV_OFFSET) & + CLKMGR_PLLGLOB_AREFCLKDIV_MASK; + + reg = CM_REG_READL(CM_MAINPLL_REG_PLLM); + mdiv = reg & CLKMGR_PLLM_MDIV_MASK; + + vco = fref / arefdiv; + vco = vco * mdiv; + + return vco; +} + +static u64 cm_get_per_vco_clk_hz(void) +{ + u64 fref, arefdiv, mdiv, reg, vco; + + reg = CM_REG_READL(CM_PERPLL_REG_PLLGLOB); + + fref = (reg >> CLKMGR_PLLGLOB_VCO_PSRC_OFFSET) & + CLKMGR_PLLGLOB_VCO_PSRC_MASK; + switch (fref) { + case CLKMGR_VCO_PSRC_EOSC1: + fref = cm_get_osc_clk_hz(); + break; + case CLKMGR_VCO_PSRC_INTOSC: + fref = cm_get_intosc_clk_hz(); + break; + case CLKMGR_VCO_PSRC_F2S: + fref = cm_get_fpga_clk_hz(); + break; + } + + arefdiv = (reg >> CLKMGR_PLLGLOB_AREFCLKDIV_OFFSET) & + CLKMGR_PLLGLOB_AREFCLKDIV_MASK; + + reg = CM_REG_READL(CM_PERPLL_REG_PLLM); + mdiv = reg & CLKMGR_PLLM_MDIV_MASK; + + vco = fref / arefdiv; + vco = vco * mdiv; + + return vco; +} + +static u32 cm_get_5_1_clk_src(u64 reg) +{ + u32 clksrc = CM_REG_READL(reg); + + return (clksrc >> CLKMGR_CLKSRC_OFFSET) & CLKMGR_CLKSRC_MASK; +} + +u64 cm_get_mpu_clk_hz(void) +{ + u64 clock = cm_get_5_1_clk_src(CM_MAINPLL_REG_MPUCLK); + + switch (clock) { + case CLKMGR_CLKSRC_MAIN: + clock = cm_get_main_vco_clk_hz(); + clock /= (CM_REG_READL(CM_MAINPLL_REG_PLLC0) & + CLKMGR_CLKCNT_MSK); + break; + + case CLKMGR_CLKSRC_PER: + clock = cm_get_per_vco_clk_hz(); + clock /= (CM_REG_READL(CM_PERPLL_REG_PLLC0) & + CLKMGR_CLKCNT_MSK); + break; + + case CLKMGR_CLKSRC_OSC1: + clock = cm_get_osc_clk_hz(); + break; + + case CLKMGR_CLKSRC_INTOSC: + clock = cm_get_intosc_clk_hz(); + break; + + case CLKMGR_CLKSRC_FPGA: + clock = cm_get_fpga_clk_hz(); + break; + } + + clock /= 1 + (CM_REG_READL(CM_MAINPLL_REG_MPUCLK) & + CLKMGR_CLKCNT_MSK); + + return clock; +} + +static u32 cm_get_l3_main_clk_hz(void) +{ + u32 clock = cm_get_5_1_clk_src(CM_MAINPLL_REG_NOCCLK); + + switch (clock) { + case CLKMGR_CLKSRC_MAIN: + clock = cm_get_main_vco_clk_hz(); + clock /= (CM_REG_READL(CM_MAINPLL_REG_PLLC1) & + CLKMGR_CLKCNT_MSK); + break; + + case CLKMGR_CLKSRC_PER: + clock = cm_get_per_vco_clk_hz(); + clock /= (CM_REG_READL(CM_PERPLL_REG_PLLC1) & + CLKMGR_CLKCNT_MSK); + break; + + case CLKMGR_CLKSRC_OSC1: + clock = cm_get_osc_clk_hz(); + break; + + case CLKMGR_CLKSRC_INTOSC: + clock = cm_get_intosc_clk_hz(); + break; + + case CLKMGR_CLKSRC_FPGA: + clock = cm_get_fpga_clk_hz(); + break; + } + + return clock; +} + +u32 cm_get_mmc_controller_clk_hz(void) +{ + u32 clock = cm_get_5_1_clk_src(CM_ALTERA_REG_SDMMCCTR); + + switch (clock) { + case CLKMGR_CLKSRC_MAIN: + clock = cm_get_main_vco_clk_hz(); + clock /= (CM_REG_READL(CM_MAINPLL_REG_PLLC3) & + CLKMGR_CLKCNT_MSK); + break; + + case CLKMGR_CLKSRC_PER: + clock = cm_get_main_vco_clk_hz(); + clock /= (CM_REG_READL(CM_PERPLL_REG_PLLC3) & + CLKMGR_CLKCNT_MSK); + break; + + case CLKMGR_CLKSRC_OSC1: + clock = cm_get_osc_clk_hz(); + break; + + case CLKMGR_CLKSRC_INTOSC: + clock = cm_get_intosc_clk_hz(); + break; + + case CLKMGR_CLKSRC_FPGA: + clock = cm_get_fpga_clk_hz(); + break; + } + + clock /= 1 + (CM_REG_READL(CM_ALTERA_REG_SDMMCCTR) & + CLKMGR_CLKCNT_MSK); + + return clock; +} + +u32 cm_get_l4_sp_clk_hz(void) +{ + u32 clock = cm_get_l3_main_clk_hz(); + + clock /= BIT((CM_REG_READL(CM_MAINPLL_REG_NOCDIV) >> + CLKMGR_NOCDIV_L4SPCLK_OFFSET) & + CLKMGR_NOCDIV_DIVIDER_MASK); + + return clock; +} + +static u32 cm_get_l4_mp_clk_hz(void) +{ + u32 clock = cm_get_l3_main_clk_hz(); + + clock /= BIT((CM_REG_READL(CM_MAINPLL_REG_NOCDIV) >> + CLKMGR_NOCDIV_L4MPCLK_OFFSET) & + CLKMGR_NOCDIV_DIVIDER_MASK); + + return clock; +} + +u32 cm_get_qspi_controller_clk_hz(void) +{ + return readl(&sysmgr_regs->boot_scratch_cold0); +} + +u32 cm_get_spi_controller_clk_hz(void) +{ + u32 clock = cm_get_l3_main_clk_hz(); + + clock /= BIT((CM_REG_READL(CM_MAINPLL_REG_NOCDIV) >> + CLKMGR_NOCDIV_L4MAIN_OFFSET) & + CLKMGR_NOCDIV_DIVIDER_MASK); + + return clock; +} + +u32 cm_get_l4_sys_free_clk_hz(void) +{ + if (CM_REG_READL(CM_REG_STAT) & CLKMGR_STAT_BOOTMODE) + return cm_get_l3_main_clk_hz() / 2; + + return cm_get_l3_main_clk_hz() / 4; +} + +static u32 cm_get_main_mod_clk_hz(void) +{ + u32 moddiv = (CM_REG_READL(CM_MAINPLL_REG_PLLGLOB) >> + CLKMGR_PLLGLOB_MODCLKDIV_OFFSET) & + CLKMGR_PLLGLOB_MODCLKDIV_MASK; + + return (u32)cm_get_main_vco_clk_hz() / moddiv; +} + +static u32 cm_get_per_mod_clk_hz(void) +{ + u32 moddiv = (CM_REG_READL(CM_PERPLL_REG_PLLGLOB) >> + CLKMGR_PLLGLOB_MODCLKDIV_OFFSET) & + CLKMGR_PLLGLOB_MODCLKDIV_MASK; + + return (u32)cm_get_per_vco_clk_hz() / moddiv; +} + +void cm_print_clock_quick_summary(void) +{ + printf("Main VCO %d kHz\n", (u32)(cm_get_main_vco_clk_hz() / 1000)); + printf("Per VCO %d kHz\n", (u32)(cm_get_per_vco_clk_hz() / 1000)); + printf("Main Mod %d kHz\n", cm_get_main_mod_clk_hz() / 1000); + printf("Per Mod %d kHz\n", cm_get_per_mod_clk_hz() / 1000); + printf("EOSC1 %d kHz\n", cm_get_osc_clk_hz() / 1000); + printf("MPU %d kHz\n", (u32)(cm_get_mpu_clk_hz() / 1000)); + printf("L3 main %d kHz\n", cm_get_l3_main_clk_hz() / 1000); + printf("L4 MP %d kHz\n", cm_get_l4_mp_clk_hz() / 1000); + printf("HPS MMC %d kHz\n", cm_get_mmc_controller_clk_hz() / 1000); + printf("UART %d kHz\n", cm_get_l4_sp_clk_hz() / 1000); +} diff --git a/arch/arm/mach-socfpga/include/mach/clock_manager.h b/arch/arm/mach-socfpga/include/mach/clock_manager.h index dd80e3a767..a3d5de59d2 100644 --- a/arch/arm/mach-socfpga/include/mach/clock_manager.h +++ b/arch/arm/mach-socfpga/include/mach/clock_manager.h @@ -18,6 +18,8 @@ void cm_print_clock_quick_summary(void); #include #elif defined(CONFIG_TARGET_SOCFPGA_STRATIX10) #include +#elif defined(CONFIG_TARGET_SOCFPGA_AGILEX) +#include #endif #endif /* _CLOCK_MANAGER_H_ */ diff --git a/arch/arm/mach-socfpga/include/mach/clock_manager_agilex.h b/arch/arm/mach-socfpga/include/mach/clock_manager_agilex.h new file mode 100644 index 0000000000..45e6eafc03 --- /dev/null +++ b/arch/arm/mach-socfpga/include/mach/clock_manager_agilex.h @@ -0,0 +1,328 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2019 Intel Corporation + */ + +#ifndef _CLOCK_MANAGER_AGILEX_ +#define _CLOCK_MANAGER_AGILEX_ + +#define CM_REG_READL(reg) \ + readl(SOCFPGA_CLKMGR_ADDRESS + (reg)) + +#define CM_REG_WRITEL(data, reg) \ + writel(data, SOCFPGA_CLKMGR_ADDRESS + (reg)) + +#define CM_REG_CLRBITS(mask, reg) \ + clrbits_le32(SOCFPGA_CLKMGR_ADDRESS + (reg), (mask)) + +#define CM_REG_SETBITS(mask, reg) \ + setbits_le32(SOCFPGA_CLKMGR_ADDRESS + (reg), (mask)) + +#define CM_REG_CLRSETBITS(mask, data, reg) \ + clrsetbits_le32(SOCFPGA_CLKMGR_ADDRESS + (reg), (mask), (data)) + +/* Clock speed accessors */ +u64 cm_get_mpu_clk_hz(void); +u32 cm_get_l4_sp_clk_hz(void); +u32 cm_get_mmc_controller_clk_hz(void); +u32 cm_get_qspi_controller_clk_hz(void); +u32 cm_get_l4_sys_free_clk_hz(void); +u32 cm_get_spi_controller_clk_hz(void); +const unsigned int cm_get_osc_clk_hz(void); +const unsigned int cm_get_intosc_clk_hz(void); +const unsigned int cm_get_fpga_clk_hz(void); + +#define CLKMGR_EOSC1_HZ 25000000 +#define CLKMGR_INTOSC_HZ 400000000 +#define CLKMGR_FPGA_CLK_HZ 50000000 + +/* Clock configuration accessors */ +const struct cm_config * const cm_get_default_config(void); + +struct cm_config { + /* main group */ + u32 main_pll_mpuclk; + u32 main_pll_nocclk; + u32 main_pll_nocdiv; + u32 main_pll_pllglob; + u32 main_pll_fdbck; + u32 main_pll_pllc0; + u32 main_pll_pllc1; + u32 main_pll_pllc2; + u32 main_pll_pllc3; + u32 main_pll_pllm; + + /* peripheral group */ + u32 per_pll_emacctl; + u32 per_pll_gpiodiv; + u32 per_pll_pllglob; + u32 per_pll_fdbck; + u32 per_pll_pllc0; + u32 per_pll_pllc1; + u32 per_pll_pllc2; + u32 per_pll_pllc3; + u32 per_pll_pllm; + + /* altera group */ + u32 alt_emacactr; + u32 alt_emacbctr; + u32 alt_emacptpctr; + u32 alt_gpiodbctr; + u32 alt_sdmmcctr; + u32 alt_s2fuser0ctr; + u32 alt_s2fuser1ctr; + u32 alt_psirefctr; + + /* incoming clock */ + u32 hps_osc_clk_hz; + u32 fpga_clk_hz; + u32 spare[3]; +}; + +void cm_basic_init(const struct cm_config * const cfg); + +/* Register access with structure */ +struct socfpga_clock_manager_main_pll { + u32 en; + u32 ens; + u32 enr; + u32 bypass; + u32 bypasss; + u32 bypassr; + u32 mpuclk; + u32 nocclk; + u32 nocdiv; + u32 pllglob; + u32 fdbck; + u32 mem; + u32 memstat; + u32 pllc0; + u32 pllc1; + u32 vcocalib; + u32 pllc2; + u32 pllc3; + u32 pllm; + u32 fhop; + u32 ssc; + u32 lostlock; +}; + +struct socfpga_clock_manager_per_pll { + u32 en; + u32 ens; + u32 enr; + u32 bypass; + u32 bypasss; + u32 bypassr; + u32 emacctl; + u32 gpiodiv; + u32 pllglob; + u32 fdbck; + u32 mem; + u32 memstat; + u32 pllc0; + u32 pllc1; + u32 vcocalib; + u32 pllc2; + u32 pllc3; + u32 pllm; + u32 fhop; + u32 ssc; + u32 lostlock; +}; + +struct socfpga_clock_manager_alt_pll { + u32 jtag; + u32 emacactr; + u32 emacbctr; + u32 emacptpctr; + u32 gpiodbctr; + u32 sdmmcctr; + u32 s2fuser0ctr; + u32 s2fuser1ctr; + u32 psirefctr; + u32 extcntrst; +}; + +struct socfpga_clock_manager { + u32 ctrl; + u32 stat; + u32 testioctrl; + u32 intrgen; + u32 intrmsk; + u32 intrclr; + u32 intrsts; + u32 intrstk; + u32 intrraw; + struct socfpga_clock_manager_main_pll main_pll; + struct socfpga_clock_manager_per_pll per_pll; + struct socfpga_clock_manager_alt_pll alt_pll; +}; + +/* Register access with macro functions */ +/* Clock Manager registers */ +#define CM_REG_CTRL 0 +#define CM_REG_STAT 4 +#define CM_REG_TESTIOCTRL 8 +#define CM_REG_INTRGEN 0x0c +#define CM_REG_INTRMSK 0x10 +#define CM_REG_INTRCLR 0x14 +#define CM_REG_INTRSTS 0x18 +#define CM_REG_INTRSTK 0x1c +#define CM_REG_INTRRAW 0x20 + +/* Clock Manager Main PPL group registers */ +#define CM_MAINPLL_REG_EN 0x24 +#define CM_MAINPLL_REG_ENS 0x28 +#define CM_MAINPLL_REG_ENR 0x2c +#define CM_MAINPLL_REG_BYPASS 0x30 +#define CM_MAINPLL_REG_BYPASSS 0x34 +#define CM_MAINPLL_REG_BYPASSR 0x38 +#define CM_MAINPLL_REG_MPUCLK 0x3c +#define CM_MAINPLL_REG_NOCCLK 0x40 +#define CM_MAINPLL_REG_NOCDIV 0x44 +#define CM_MAINPLL_REG_PLLGLOB 0x48 +#define CM_MAINPLL_REG_FDBCK 0x4c +#define CM_MAINPLL_REG_MEM 0x50 +#define CM_MAINPLL_REG_MEMSTAT 0x54 +#define CM_MAINPLL_REG_PLLC0 0x58 +#define CM_MAINPLL_REG_PLLC1 0x5c +#define CM_MAINPLL_REG_VCOCALIB 0x60 +#define CM_MAINPLL_REG_PLLC2 0x64 +#define CM_MAINPLL_REG_PLLC3 0x68 +#define CM_MAINPLL_REG_PLLM 0x6c +#define CM_MAINPLL_REG_FHOP 0x70 +#define CM_MAINPLL_REG_SSC 0x74 +#define CM_MAINPLL_REG_LOSTLOCK 0x78 + +/* Clock Manager Peripheral PPL group registers */ +#define CM_PERPLL_REG_EN 0x7c +#define CM_PERPLL_REG_ENS 0x80 +#define CM_PERPLL_REG_ENR 0x84 +#define CM_PERPLL_REG_BYPASS 0x88 +#define CM_PERPLL_REG_BYPASSS 0x8c +#define CM_PERPLL_REG_BYPASSR 0x90 +#define CM_PERPLL_REG_EMACCTL 0x94 +#define CM_PERPLL_REG_GPIODIV 0x98 +#define CM_PERPLL_REG_PLLGLOB 0x9c +#define CM_PERPLL_REG_FDBCK 0xa0 +#define CM_PERPLL_REG_MEM 0xa4 +#define CM_PERPLL_REG_MEMSTAT 0xa8 +#define CM_PERPLL_REG_PLLC0 0xac +#define CM_PERPLL_REG_PLLC1 0xb0 +#define CM_PERPLL_REG_VCOCALIB 0xb4 +#define CM_PERPLL_REG_PLLC2 0xb8 +#define CM_PERPLL_REG_PLLC3 0xbc +#define CM_PERPLL_REG_PLLM 0xc0 +#define CM_PERPLL_REG_FHOP 0xc4 +#define CM_PERPLL_REG_SSC 0xc8 +#define CM_PERPLL_REG_LOSTLOCK 0xcc + +/* Clock Manager Altera group registers */ +#define CM_ALTERA_REG_JTAG 0xd0 +#define CM_ALTERA_REG_EMACACTR 0xd4 +#define CM_ALTERA_REG_EMACBCTR 0xd8 +#define CM_ALTERA_REG_EMACPTPCTR 0xdc +#define CM_ALTERA_REG_GPIODBCTR 0xe0 +#define CM_ALTERA_REG_SDMMCCTR 0xe4 +#define CM_ALTERA_REG_S2FUSER0CTR 0xe8 +#define CM_ALTERA_REG_S2FUSER1CTR 0xec +#define CM_ALTERA_REG_PSIREFCTR 0xf0 +#define CM_ALTERA_REG_EXTCNTRST 0xf4 + +#define CLKMGR_CTRL_BOOTMODE BIT(0) + +#define CLKMGR_STAT_BUSY BIT(0) +#define CLKMGR_STAT_MAINPLL_LOCKED BIT(8) +#define CLKMGR_STAT_MAIN_TRANS BIT(9) +#define CLKMGR_STAT_PERPLL_LOCKED BIT(16) +#define CLKMGR_STAT_PERF_TRANS BIT(17) +#define CLKMGR_STAT_BOOTMODE BIT(24) +#define CLKMGR_STAT_BOOTCLKSRC BIT(25) + +#define CLKMGR_STAT_ALLPLL_LOCKED_MASK \ + (CLKMGR_STAT_MAINPLL_LOCKED | CLKMGR_STAT_PERPLL_LOCKED) + +#define CLKMGR_INTER_MAINPLLLOCKED_MASK 0x00000001 +#define CLKMGR_INTER_PERPLLLOCKED_MASK 0x00000002 +#define CLKMGR_INTER_MAINPLLLOST_MASK 0x00000004 +#define CLKMGR_INTER_PERPLLLOST_MASK 0x00000008 + +#define CLKMGR_CLKSRC_MASK 0x7 +#define CLKMGR_CLKSRC_OFFSET 16 +#define CLKMGR_CLKSRC_MAIN 0 +#define CLKMGR_CLKSRC_PER 1 +#define CLKMGR_CLKSRC_OSC1 2 +#define CLKMGR_CLKSRC_INTOSC 3 +#define CLKMGR_CLKSRC_FPGA 4 +#define CLKMGR_CLKCNT_MSK 0x7ff + +#define CLKMGR_BYPASS_MAINPLL_ALL 0x7 +#define CLKMGR_BYPASS_PERPLL_ALL 0x7f + +#define CLKMGR_NOCDIV_L4MAIN_OFFSET 0 +#define CLKMGR_NOCDIV_L4MPCLK_OFFSET 8 +#define CLKMGR_NOCDIV_L4SPCLK_OFFSET 16 +#define CLKMGR_NOCDIV_CSATCLK_OFFSET 24 +#define CLKMGR_NOCDIV_CSTRACECLK_OFFSET 26 +#define CLKMGR_NOCDIV_CSPDBGCLK_OFFSET 28 +#define CLKMGR_NOCDIV_DIVIDER_MASK 0x3 + +#define CLKMGR_PLLGLOB_PD_MASK 0x00000001 +#define CLKMGR_PLLGLOB_RST_MASK 0x00000002 +#define CLKMGR_PLLGLOB_AREFCLKDIV_MASK 0xf +#define CLKMGR_PLLGLOB_DREFCLKDIV_MASK 0x3 +#define CLKMGR_PLLGLOB_REFCLKDIV_MASK 0x3f +#define CLKMGR_PLLGLOB_MODCLKDIV_MASK 0xf +#define CLKMGR_PLLGLOB_AREFCLKDIV_OFFSET 8 +#define CLKMGR_PLLGLOB_DREFCLKDIV_OFFSET 12 +#define CLKMGR_PLLGLOB_REFCLKDIV_OFFSET 8 +#define CLKMGR_PLLGLOB_MODCLKDIV_OFFSET 24 +#define CLKMGR_PLLGLOB_VCO_PSRC_MASK 0x3 +#define CLKMGR_PLLGLOB_VCO_PSRC_OFFSET 16 + +#define CLKMGR_VCO_PSRC_EOSC1 0 +#define CLKMGR_VCO_PSRC_INTOSC 1 +#define CLKMGR_VCO_PSRC_F2S 2 + +#define CLKMGR_MEM_REQ_SET_MSK BIT(24) +#define CLKMGR_MEM_WR_SET_MSK BIT(25) +#define CLKMGR_MEM_ERR_MSK BIT(26) +#define CLKMGR_MEM_WDAT_LSB_OFFSET 16 +#define CLKMGR_MEM_ADDR_MASK 0xffff +#define CLKMGR_MEM_ADDR_START 0x00004000 + +#define CLKMGR_PLLCX_EN_SET_MSK BIT(27) +#define CLKMGR_PLLCX_MUTE_SET_MSK BIT(28) + +#define CLKMGR_VCOCALIB_MSCNT_MASK 0xff +#define CLKMGR_VCOCALIB_MSCNT_OFFSET 16 +#define CLKMGR_VCOCALIB_HSCNT_MASK 0x3ff +#define CLKMGR_VCOCALIB_MSCNT_CONST 100 +#define CLKMGR_VCOCALIB_HSCNT_CONST 4 + +#define CLKMGR_PLLM_MDIV_MASK 0x3ff + +#define CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK 0x00000020 +#define CLKMGR_PERPLLGRP_EMACCTL_EMAC0SELB BIT(26) +#define CLKMGR_PERPLLGRP_EMACCTL_EMAC1SELB BIT(27) +#define CLKMGR_PERPLLGRP_EMACCTL_EMAC2SELB BIT(28) + +#define CLKMGR_ALT_EXTCNTRST_EMACACNTRST BIT(0) +#define CLKMGR_ALT_EXTCNTRST_EMACBCNTRST BIT(1) +#define CLKMGR_ALT_EXTCNTRST_EMACPTPCNTRST BIT(2) +#define CLKMGR_ALT_EXTCNTRST_GPIODBCNTRST BIT(3) +#define CLKMGR_ALT_EXTCNTRST_SDMMCCNTRST BIT(4) +#define CLKMGR_ALT_EXTCNTRST_S2FUSER0CNTRST BIT(5) +#define CLKMGR_ALT_EXTCNTRST_S2FUSER1CNTRST BIT(6) +#define CLKMGR_ALT_EXTCNTRST_PSIREFCNTRST BIT(7) +#define CLKMGR_ALT_EXTCNTRST_ALLCNTRST \ + (CLKMGR_ALT_EXTCNTRST_EMACACNTRST | \ + CLKMGR_ALT_EXTCNTRST_EMACBCNTRST | \ + CLKMGR_ALT_EXTCNTRST_EMACPTPCNTRST | \ + CLKMGR_ALT_EXTCNTRST_GPIODBCNTRST | \ + CLKMGR_ALT_EXTCNTRST_SDMMCCNTRST | \ + CLKMGR_ALT_EXTCNTRST_S2FUSER0CNTRST | \ + CLKMGR_ALT_EXTCNTRST_S2FUSER1CNTRST | \ + CLKMGR_ALT_EXTCNTRST_PSIREFCNTRST) +#endif /* _CLOCK_MANAGER_AGILEX_ */ -- 2.19.0