Commit 0c343737 authored by Siew Chin Lim's avatar Siew Chin Lim Committed by Anas Nashif
Browse files

drivers: clock_control: Add clock driver for Intel SoC FPGA Agilex



Add clock driver for Intel SoC FPGA Agilex.

Signed-off-by: default avatarSiew Chin Lim <elly.siew.chin.lim@intel.com>
parent 5b6c5939
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -48,3 +48,6 @@ else()
  zephyr_library_sources_ifdef(CONFIG_SOC_SERIES_STM32WLX clock_stm32l4_l5_wb_wl.c)
endif()
endif()

zephyr_library_sources_ifdef(CONFIG_SOC_SERIES_AGILEX clock_agilex_ll.c)
zephyr_library_sources_ifdef(CONFIG_SOC_SERIES_AGILEX clock_agilex.c)
+57 −0
Original line number Diff line number Diff line
/*
 * SPDX-License-Identifier: Apache-2.0
 *
 * Copyright (C) 2021, Intel Corporation
 *
 */

#include <drivers/clock_control.h>
#include <drivers/clock_control/clock_agilex_ll.h>
#include <dt-bindings/clock/intel_socfpga_clock.h>
#include <logging/log.h>
#include <soc.h>

LOG_MODULE_REGISTER(clock_control, CONFIG_CLOCK_CONTROL_LOG_LEVEL);

static int clk_init(const struct device *dev)
{
	ARG_UNUSED(dev);
	LOG_INF("Intel Clock driver initialized");
	return 0;
}

static int clk_get_rate(const struct device *dev,
			clock_control_subsys_t sub_system,
			uint32_t *rate)
{
	ARG_UNUSED(dev);

	struct clock_attr *attr = (struct clock_attr *)(sub_system);

	switch (attr->clock_id) {
	case INTEL_SOCFPGA_CLOCK_MPU:
		*rate = get_mpu_clk();
		break;
	case INTEL_SOCFPGA_CLOCK_WDT:
		*rate = get_wdt_clk();
		break;
	case INTEL_SOCFPGA_CLOCK_UART:
		*rate = get_uart_clk();
		break;
	case INTEL_SOCFPGA_CLOCK_MMC:
		*rate = get_mmc_clk();
		break;
	default:
		return -ENOTSUP;
	}

	return 0;
}

static const struct clock_control_driver_api clk_api = {
	.get_rate = clk_get_rate
};

DEVICE_DT_DEFINE(DT_NODELABEL(clock), clk_init, NULL, NULL, NULL,
		 PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
		 &clk_api);
+144 −0
Original line number Diff line number Diff line
/*
 * Copyright (c) 2019-2021, Intel Corporation. All rights reserved.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <arch/cpu.h>
#include <arch/common/sys_bitops.h>
#include <drivers/clock_control/clock_agilex_ll.h>
#include <socfpga_system_manager.h>

/*
 * Intel SoC re-use Arm Trusted Firmware (ATF) driver code in Zephyr.
 * The migrated ATF driver code uses mmio_X macro to access the register.
 * The following macros map mmio_X to Zephyr compatible function for
 * register access. This allow Zephyr to re-use the ATF driver codes
 * without massive changes.
 */
#define mmio_write_32(addr, data)	sys_write32((data), (addr))
#define mmio_read_32(addr)		sys_read32((addr))
#define mmio_setbits_32(addr, mask)	sys_set_bits((addr), (mask))
#define mmio_clrbits_32(addr, mask)	sys_clear_bits((addr), (mask))

/* Extract reference clock from platform clock source */
uint32_t get_ref_clk(uint32_t pllglob)
{
	uint32_t arefclkdiv, ref_clk;
	uint32_t scr_reg;

	switch (CLKMGR_PSRC(pllglob)) {
	case CLKMGR_PLLGLOB_PSRC_EOSC1:
		scr_reg = SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_1);
		ref_clk = mmio_read_32(scr_reg);
		break;
	case CLKMGR_PLLGLOB_PSRC_INTOSC:
		ref_clk = CLKMGR_INTOSC_HZ;
		break;
	case CLKMGR_PLLGLOB_PSRC_F2S:
		scr_reg = SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_2);
		ref_clk = mmio_read_32(scr_reg);
		break;
	default:
		ref_clk = 0;
		break;
	}

	arefclkdiv = CLKMGR_PLLGLOB_AREFCLKDIV(pllglob);
	ref_clk /= arefclkdiv;

	return ref_clk;
}

/* Calculate clock frequency based on parameter */
uint32_t get_clk_freq(uint32_t psrc_reg, uint32_t main_pllc, uint32_t per_pllc)
{
	uint32_t clk_psrc, mdiv, ref_clk;
	uint32_t pllm_reg, pllc_reg, pllc_div, pllglob_reg;

	clk_psrc = mmio_read_32(CLKMGR_MAINPLL + psrc_reg);

	switch (CLKMGR_PSRC(clk_psrc)) {
	case CLKMGR_PSRC_MAIN:
		pllm_reg = CLKMGR_MAINPLL + CLKMGR_MAINPLL_PLLM;
		pllc_reg = CLKMGR_MAINPLL + main_pllc;
		pllglob_reg = CLKMGR_MAINPLL + CLKMGR_MAINPLL_PLLGLOB;
		break;
	case CLKMGR_PSRC_PER:
		pllm_reg = CLKMGR_PERPLL + CLKMGR_PERPLL_PLLM;
		pllc_reg = CLKMGR_PERPLL + per_pllc;
		pllglob_reg = CLKMGR_PERPLL + CLKMGR_PERPLL_PLLGLOB;
		break;
	default:
		return 0;
	}

	ref_clk = get_ref_clk(mmio_read_32(pllglob_reg));
	mdiv = CLKMGR_PLLM_MDIV(mmio_read_32(pllm_reg));
	ref_clk *= mdiv;

	pllc_div = mmio_read_32(pllc_reg) & 0x7ff;

	return ref_clk / pllc_div;
}

/* Return L3 interconnect clock */
uint32_t get_l3_clk(void)
{
	uint32_t l3_clk;

	l3_clk = get_clk_freq(CLKMGR_MAINPLL_NOCCLK, CLKMGR_MAINPLL_PLLC1,
				CLKMGR_PERPLL_PLLC1);
	return l3_clk;
}

/* Calculate clock frequency to be used for mpu */
uint32_t get_mpu_clk(void)
{
	uint32_t mpu_clk = 0;

	mpu_clk = get_clk_freq(CLKMGR_MAINPLL_MPUCLK, CLKMGR_MAINPLL_PLLC0,
				CLKMGR_PERPLL_PLLC0);
	return mpu_clk;
}

/* Calculate clock frequency to be used for watchdog timer */
uint32_t get_wdt_clk(void)
{
	uint32_t l3_clk, l4_sys_clk;

	l3_clk = get_l3_clk();
	l4_sys_clk = l3_clk / 4;

	return l4_sys_clk;
}

/* Calculate clock frequency to be used for UART driver */
uint32_t get_uart_clk(void)
{
	uint32_t data32, l3_clk, l4_sp_clk;

	l3_clk = get_l3_clk();

	data32 = mmio_read_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_NOCDIV);
	data32 = (data32 >> 16) & 0x3;

	l4_sp_clk = l3_clk >> data32;

	return l4_sp_clk;
}

/* Calculate clock frequency to be used for SDMMC driver */
uint32_t get_mmc_clk(void)
{
	uint32_t data32, mmc_clk;

	mmc_clk = get_clk_freq(CLKMGR_ALTERA_SDMMCCTR,
		CLKMGR_MAINPLL_PLLC3, CLKMGR_PERPLL_PLLC3);

	data32 = mmio_read_32(CLKMGR_ALTERA + CLKMGR_ALTERA_SDMMCCTR);
	data32 = (data32 & 0x7ff) + 1;
	mmc_clk = (mmc_clk / data32) / 4;

	return mmc_clk;
}
+130 −0
Original line number Diff line number Diff line
/*
 * Copyright (c) 2019-2021, Intel Corporation. All rights reserved.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#ifndef CLOCKMANAGER_H
#define CLOCKMANAGER_H

#include <socfpga_handoff.h>

/* Clock Manager Registers */
#define CLKMGR_OFFSET				0xffd10000

#define CLKMGR_CTRL				0x0
#define CLKMGR_STAT				0x4
#define CLKMGR_INTRCLR				0x14

/* Main PLL Group */
#define CLKMGR_MAINPLL				0xffd10024
#define CLKMGR_MAINPLL_EN			0x0
#define CLKMGR_MAINPLL_BYPASS			0xc
#define CLKMGR_MAINPLL_MPUCLK			0x18
#define CLKMGR_MAINPLL_NOCCLK			0x1c
#define CLKMGR_MAINPLL_NOCDIV			0x20
#define CLKMGR_MAINPLL_PLLGLOB			0x24
#define CLKMGR_MAINPLL_FDBCK			0x28
#define CLKMGR_MAINPLL_MEM			0x2c
#define CLKMGR_MAINPLL_MEMSTAT			0x30
#define CLKMGR_MAINPLL_PLLC0			0x34
#define CLKMGR_MAINPLL_PLLC1			0x38
#define CLKMGR_MAINPLL_VCOCALIB			0x3c
#define CLKMGR_MAINPLL_PLLC2			0x40
#define CLKMGR_MAINPLL_PLLC3			0x44
#define CLKMGR_MAINPLL_PLLM			0x48
#define CLKMGR_MAINPLL_LOSTLOCK			0x54

/* Peripheral PLL Group */
#define CLKMGR_PERPLL				0xffd1007c
#define CLKMGR_PERPLL_EN			0x0
#define CLKMGR_PERPLL_BYPASS			0xc
#define CLKMGR_PERPLL_EMACCTL			0x18
#define CLKMGR_PERPLL_GPIODIV			0x1c
#define CLKMGR_PERPLL_PLLGLOB			0x20
#define CLKMGR_PERPLL_FDBCK			0x24
#define CLKMGR_PERPLL_MEM			0x28
#define CLKMGR_PERPLL_MEMSTAT			0x2c
#define CLKMGR_PERPLL_PLLC0			0x30
#define CLKMGR_PERPLL_PLLC1			0x34
#define CLKMGR_PERPLL_VCOCALIB			0x38
#define CLKMGR_PERPLL_PLLC2			0x3c
#define CLKMGR_PERPLL_PLLC3			0x40
#define CLKMGR_PERPLL_PLLM			0x44
#define CLKMGR_PERPLL_LOSTLOCK			0x50

/* Altera Group */
#define CLKMGR_ALTERA				0xffd100d0
#define CLKMGR_ALTERA_JTAG			0x0
#define CLKMGR_ALTERA_EMACACTR			0x4
#define CLKMGR_ALTERA_EMACBCTR			0x8
#define CLKMGR_ALTERA_EMACPTPCTR		0xc
#define CLKMGR_ALTERA_GPIODBCTR			0x10
#define CLKMGR_ALTERA_SDMMCCTR			0x14
#define CLKMGR_ALTERA_S2FUSER0CTR		0x18
#define CLKMGR_ALTERA_S2FUSER1CTR		0x1c
#define CLKMGR_ALTERA_PSIREFCTR			0x20
#define CLKMGR_ALTERA_EXTCNTRST			0x24

/* Membus */
#define CLKMGR_MEM_REQ				BIT(24)
#define CLKMGR_MEM_WR				BIT(25)
#define CLKMGR_MEM_ERR				BIT(26)
#define CLKMGR_MEM_WDAT_OFFSET			16
#define CLKMGR_MEM_ADDR				0x4027
#define CLKMGR_MEM_WDAT				0x80

/* Clock Manager Macros */
#define CLKMGR_CTRL_BOOTMODE_SET_MSK		0x00000001
#define CLKMGR_STAT_BUSY_E_BUSY			0x1
#define CLKMGR_STAT_BUSY(x)			(((x) & 0x00000001) >> 0)
#define CLKMGR_STAT_MAINPLLLOCKED(x)		(((x) & 0x00000100) >> 8)
#define CLKMGR_STAT_PERPLLLOCKED(x)		(((x) & 0x00010000) >> 16)
#define CLKMGR_INTRCLR_MAINLOCKLOST_SET_MSK	0x00000004
#define CLKMGR_INTRCLR_PERLOCKLOST_SET_MSK	0x00000008
#define CLKMGR_INTOSC_HZ			460000000

/* Main PLL Macros */
#define CLKMGR_MAINPLL_EN_RESET			0x000000ff

/* Peripheral PLL Macros */
#define CLKMGR_PERPLL_EN_RESET			0x00000fff
#define CLKMGR_PERPLL_EN_SDMMCCLK		BIT(5)
#define CLKMGR_PERPLL_GPIODIV_GPIODBCLK_SET(x)	(((x) << 0) & 0x0000ffff)

/* Altera Macros */
#define CLKMGR_ALTERA_EXTCNTRST_RESET		0xff

/* Shared Macros */
#define CLKMGR_PSRC(x)				(((x) & 0x00030000) >> 16)
#define CLKMGR_PSRC_MAIN			0
#define CLKMGR_PSRC_PER				1

#define CLKMGR_PLLGLOB_PSRC_EOSC1		0x0
#define CLKMGR_PLLGLOB_PSRC_INTOSC		0x1
#define CLKMGR_PLLGLOB_PSRC_F2S			0x2

#define CLKMGR_PLLM_MDIV(x)			((x) & 0x000003ff)
#define CLKMGR_PLLGLOB_PD_SET_MSK		0x00000001
#define CLKMGR_PLLGLOB_RST_SET_MSK		0x00000002

#define CLKMGR_PLLGLOB_REFCLKDIV(x)		(((x) & 0x00003f00) >> 8)
#define CLKMGR_PLLGLOB_AREFCLKDIV(x)		(((x) & 0x00000f00) >> 8)
#define CLKMGR_PLLGLOB_DREFCLKDIV(x)		(((x) & 0x00003000) >> 12)

#define CLKMGR_VCOCALIB_HSCNT_SET(x)		(((x) << 0) & 0x000003ff)
#define CLKMGR_VCOCALIB_MSCNT_SET(x)		(((x) << 16) & 0x00ff0000)

#define CLKMGR_CLR_LOSTLOCK_BYPASS		0x20000000

struct clock_attr {
	uint32_t clock_id;
};

void config_clkmgr_handoff(struct handoff *hoff_ptr);
uint32_t get_mpu_clk(void);
uint32_t get_wdt_clk(void);
uint32_t get_uart_clk(void);
uint32_t get_mmc_clk(void);

#endif
+16 −0
Original line number Diff line number Diff line
/*
 * SPDX-License-Identifier: Apache-2.0
 *
 * Copyright (C) 2021, Intel Corporation
 *
 */

#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_INTEL_SOCFPGA_CLOCK_H_
#define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_INTEL_SOCFPGA_CLOCK_H_

#define INTEL_SOCFPGA_CLOCK_MPU        0
#define INTEL_SOCFPGA_CLOCK_WDT        1
#define INTEL_SOCFPGA_CLOCK_UART       2
#define INTEL_SOCFPGA_CLOCK_MMC        3

#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_INTEL_SOCFPGA_CLOCK_H_ */