d56d79ed27
Add fu740 support. One abstract layer is added for supporting multiple chips such as fu540 and fu740. Signed-off-by: Green Wan <green.wan@sifive.com>
324 lines
11 KiB
C
324 lines
11 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* Copyright (C) 2020-2021 SiFive, Inc.
|
|
* Wesley Terpstra
|
|
* Paul Walmsley
|
|
* Zong Li
|
|
* Pragnesh Patel
|
|
*/
|
|
|
|
#ifndef __SIFIVE_CLK_SIFIVE_PRCI_H
|
|
#define __SIFIVE_CLK_SIFIVE_PRCI_H
|
|
|
|
#include <clk.h>
|
|
#include <linux/clk/analogbits-wrpll-cln28hpc.h>
|
|
|
|
/*
|
|
* EXPECTED_CLK_PARENT_COUNT: how many parent clocks this driver expects:
|
|
* hfclk and rtcclk
|
|
*/
|
|
#define EXPECTED_CLK_PARENT_COUNT 2
|
|
|
|
/*
|
|
* Register offsets and bitmasks
|
|
*/
|
|
|
|
/* COREPLLCFG0 */
|
|
#define PRCI_COREPLLCFG0_OFFSET 0x4
|
|
#define PRCI_COREPLLCFG0_DIVR_SHIFT 0
|
|
#define PRCI_COREPLLCFG0_DIVR_MASK (0x3f << PRCI_COREPLLCFG0_DIVR_SHIFT)
|
|
#define PRCI_COREPLLCFG0_DIVF_SHIFT 6
|
|
#define PRCI_COREPLLCFG0_DIVF_MASK (0x1ff << PRCI_COREPLLCFG0_DIVF_SHIFT)
|
|
#define PRCI_COREPLLCFG0_DIVQ_SHIFT 15
|
|
#define PRCI_COREPLLCFG0_DIVQ_MASK (0x7 << PRCI_COREPLLCFG0_DIVQ_SHIFT)
|
|
#define PRCI_COREPLLCFG0_RANGE_SHIFT 18
|
|
#define PRCI_COREPLLCFG0_RANGE_MASK (0x7 << PRCI_COREPLLCFG0_RANGE_SHIFT)
|
|
#define PRCI_COREPLLCFG0_BYPASS_SHIFT 24
|
|
#define PRCI_COREPLLCFG0_BYPASS_MASK (0x1 << PRCI_COREPLLCFG0_BYPASS_SHIFT)
|
|
#define PRCI_COREPLLCFG0_FSE_SHIFT 25
|
|
#define PRCI_COREPLLCFG0_FSE_MASK (0x1 << PRCI_COREPLLCFG0_FSE_SHIFT)
|
|
#define PRCI_COREPLLCFG0_LOCK_SHIFT 31
|
|
#define PRCI_COREPLLCFG0_LOCK_MASK (0x1 << PRCI_COREPLLCFG0_LOCK_SHIFT)
|
|
|
|
/* COREPLLCFG1 */
|
|
#define PRCI_COREPLLCFG1_OFFSET 0x8
|
|
#define PRCI_COREPLLCFG1_CKE_SHIFT 31
|
|
#define PRCI_COREPLLCFG1_CKE_MASK (0x1 << PRCI_COREPLLCFG1_CKE_SHIFT)
|
|
|
|
/* DDRPLLCFG0 */
|
|
#define PRCI_DDRPLLCFG0_OFFSET 0xc
|
|
#define PRCI_DDRPLLCFG0_DIVR_SHIFT 0
|
|
#define PRCI_DDRPLLCFG0_DIVR_MASK (0x3f << PRCI_DDRPLLCFG0_DIVR_SHIFT)
|
|
#define PRCI_DDRPLLCFG0_DIVF_SHIFT 6
|
|
#define PRCI_DDRPLLCFG0_DIVF_MASK (0x1ff << PRCI_DDRPLLCFG0_DIVF_SHIFT)
|
|
#define PRCI_DDRPLLCFG0_DIVQ_SHIFT 15
|
|
#define PRCI_DDRPLLCFG0_DIVQ_MASK (0x7 << PRCI_DDRPLLCFG0_DIVQ_SHIFT)
|
|
#define PRCI_DDRPLLCFG0_RANGE_SHIFT 18
|
|
#define PRCI_DDRPLLCFG0_RANGE_MASK (0x7 << PRCI_DDRPLLCFG0_RANGE_SHIFT)
|
|
#define PRCI_DDRPLLCFG0_BYPASS_SHIFT 24
|
|
#define PRCI_DDRPLLCFG0_BYPASS_MASK (0x1 << PRCI_DDRPLLCFG0_BYPASS_SHIFT)
|
|
#define PRCI_DDRPLLCFG0_FSE_SHIFT 25
|
|
#define PRCI_DDRPLLCFG0_FSE_MASK (0x1 << PRCI_DDRPLLCFG0_FSE_SHIFT)
|
|
#define PRCI_DDRPLLCFG0_LOCK_SHIFT 31
|
|
#define PRCI_DDRPLLCFG0_LOCK_MASK (0x1 << PRCI_DDRPLLCFG0_LOCK_SHIFT)
|
|
|
|
/* DDRPLLCFG1 */
|
|
#define PRCI_DDRPLLCFG1_OFFSET 0x10
|
|
#define PRCI_DDRPLLCFG1_CKE_SHIFT 31
|
|
#define PRCI_DDRPLLCFG1_CKE_MASK (0x1 << PRCI_DDRPLLCFG1_CKE_SHIFT)
|
|
|
|
/* PCIEAUXCFG1 */
|
|
#define PRCI_PCIEAUXCFG1_OFFSET 0x14
|
|
#define PRCI_PCIEAUXCFG1_SHIFT 0
|
|
#define PRCI_PCIEAUXCFG1_MASK (0x1 << PRCI_PCIEAUXCFG1_SHIFT)
|
|
|
|
/* GEMGXLPLLCFG0 */
|
|
#define PRCI_GEMGXLPLLCFG0_OFFSET 0x1c
|
|
#define PRCI_GEMGXLPLLCFG0_DIVR_SHIFT 0
|
|
#define PRCI_GEMGXLPLLCFG0_DIVR_MASK \
|
|
(0x3f << PRCI_GEMGXLPLLCFG0_DIVR_SHIFT)
|
|
#define PRCI_GEMGXLPLLCFG0_DIVF_SHIFT 6
|
|
#define PRCI_GEMGXLPLLCFG0_DIVF_MASK \
|
|
(0x1ff << PRCI_GEMGXLPLLCFG0_DIVF_SHIFT)
|
|
#define PRCI_GEMGXLPLLCFG0_DIVQ_SHIFT 15
|
|
#define PRCI_GEMGXLPLLCFG0_DIVQ_MASK (0x7 << PRCI_GEMGXLPLLCFG0_DIVQ_SHIFT)
|
|
#define PRCI_GEMGXLPLLCFG0_RANGE_SHIFT 18
|
|
#define PRCI_GEMGXLPLLCFG0_RANGE_MASK \
|
|
(0x7 << PRCI_GEMGXLPLLCFG0_RANGE_SHIFT)
|
|
#define PRCI_GEMGXLPLLCFG0_BYPASS_SHIFT 24
|
|
#define PRCI_GEMGXLPLLCFG0_BYPASS_MASK \
|
|
(0x1 << PRCI_GEMGXLPLLCFG0_BYPASS_SHIFT)
|
|
#define PRCI_GEMGXLPLLCFG0_FSE_SHIFT 25
|
|
#define PRCI_GEMGXLPLLCFG0_FSE_MASK \
|
|
(0x1 << PRCI_GEMGXLPLLCFG0_FSE_SHIFT)
|
|
#define PRCI_GEMGXLPLLCFG0_LOCK_SHIFT 31
|
|
#define PRCI_GEMGXLPLLCFG0_LOCK_MASK (0x1 << PRCI_GEMGXLPLLCFG0_LOCK_SHIFT)
|
|
|
|
/* GEMGXLPLLCFG1 */
|
|
#define PRCI_GEMGXLPLLCFG1_OFFSET 0x20
|
|
#define PRCI_GEMGXLPLLCFG1_CKE_SHIFT 31
|
|
#define PRCI_GEMGXLPLLCFG1_CKE_MASK (0x1 << PRCI_GEMGXLPLLCFG1_CKE_SHIFT)
|
|
|
|
/* CORECLKSEL */
|
|
#define PRCI_CORECLKSEL_OFFSET 0x24
|
|
#define PRCI_CORECLKSEL_CORECLKSEL_SHIFT 0
|
|
#define PRCI_CORECLKSEL_CORECLKSEL_MASK \
|
|
(0x1 << PRCI_CORECLKSEL_CORECLKSEL_SHIFT)
|
|
|
|
/* DEVICESRESETREG */
|
|
#define PRCI_DEVICESRESETREG_OFFSET 0x28
|
|
#define PRCI_DEVICERESETCNT 6
|
|
|
|
/* CLKMUXSTATUSREG */
|
|
#define PRCI_CLKMUXSTATUSREG_OFFSET 0x2c
|
|
#define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT 1
|
|
#define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK \
|
|
(0x1 << PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT)
|
|
|
|
/* CLTXPLLCFG0 */
|
|
#define PRCI_CLTXPLLCFG0_OFFSET 0x30
|
|
#define PRCI_CLTXPLLCFG0_DIVR_SHIFT 0
|
|
#define PRCI_CLTXPLLCFG0_DIVR_MASK (0x3f << PRCI_CLTXPLLCFG0_DIVR_SHIFT)
|
|
#define PRCI_CLTXPLLCFG0_DIVF_SHIFT 6
|
|
#define PRCI_CLTXPLLCFG0_DIVF_MASK (0x1ff << PRCI_CLTXPLLCFG0_DIVF_SHIFT)
|
|
#define PRCI_CLTXPLLCFG0_DIVQ_SHIFT 15
|
|
#define PRCI_CLTXPLLCFG0_DIVQ_MASK (0x7 << PRCI_CLTXPLLCFG0_DIVQ_SHIFT)
|
|
#define PRCI_CLTXPLLCFG0_RANGE_SHIFT 18
|
|
#define PRCI_CLTXPLLCFG0_RANGE_MASK (0x7 << PRCI_CLTXPLLCFG0_RANGE_SHIFT)
|
|
#define PRCI_CLTXPLLCFG0_BYPASS_SHIFT 24
|
|
#define PRCI_CLTXPLLCFG0_BYPASS_MASK (0x1 << PRCI_CLTXPLLCFG0_BYPASS_SHIFT)
|
|
#define PRCI_CLTXPLLCFG0_FSE_SHIFT 25
|
|
#define PRCI_CLTXPLLCFG0_FSE_MASK (0x1 << PRCI_CLTXPLLCFG0_FSE_SHIFT)
|
|
#define PRCI_CLTXPLLCFG0_LOCK_SHIFT 31
|
|
#define PRCI_CLTXPLLCFG0_LOCK_MASK (0x1 << PRCI_CLTXPLLCFG0_LOCK_SHIFT)
|
|
|
|
/* CLTXPLLCFG1 */
|
|
#define PRCI_CLTXPLLCFG1_OFFSET 0x34
|
|
#define PRCI_CLTXPLLCFG1_CKE_SHIFT 24
|
|
#define PRCI_CLTXPLLCFG1_CKE_MASK (0x1 << PRCI_CLTXPLLCFG1_CKE_SHIFT)
|
|
|
|
/* DVFSCOREPLLCFG0 */
|
|
#define PRCI_DVFSCOREPLLCFG0_OFFSET 0x38
|
|
|
|
/* DVFSCOREPLLCFG1 */
|
|
#define PRCI_DVFSCOREPLLCFG1_OFFSET 0x3c
|
|
#define PRCI_DVFSCOREPLLCFG1_CKE_SHIFT 24
|
|
#define PRCI_DVFSCOREPLLCFG1_CKE_MASK (0x1 << PRCI_DVFSCOREPLLCFG1_CKE_SHIFT)
|
|
|
|
/* COREPLLSEL */
|
|
#define PRCI_COREPLLSEL_OFFSET 0x40
|
|
#define PRCI_COREPLLSEL_COREPLLSEL_SHIFT 0
|
|
#define PRCI_COREPLLSEL_COREPLLSEL_MASK \
|
|
(0x1 << PRCI_COREPLLSEL_COREPLLSEL_SHIFT)
|
|
|
|
/* HFPCLKPLLCFG0 */
|
|
#define PRCI_HFPCLKPLLCFG0_OFFSET 0x50
|
|
#define PRCI_HFPCLKPLL_CFG0_DIVR_SHIFT 0
|
|
#define PRCI_HFPCLKPLL_CFG0_DIVR_MASK \
|
|
(0x3f << PRCI_HFPCLKPLLCFG0_DIVR_SHIFT)
|
|
#define PRCI_HFPCLKPLL_CFG0_DIVF_SHIFT 6
|
|
#define PRCI_HFPCLKPLL_CFG0_DIVF_MASK \
|
|
(0x1ff << PRCI_HFPCLKPLLCFG0_DIVF_SHIFT)
|
|
#define PRCI_HFPCLKPLL_CFG0_DIVQ_SHIFT 15
|
|
#define PRCI_HFPCLKPLL_CFG0_DIVQ_MASK \
|
|
(0x7 << PRCI_HFPCLKPLLCFG0_DIVQ_SHIFT)
|
|
#define PRCI_HFPCLKPLL_CFG0_RANGE_SHIFT 18
|
|
#define PRCI_HFPCLKPLL_CFG0_RANGE_MASK \
|
|
(0x7 << PRCI_HFPCLKPLLCFG0_RANGE_SHIFT)
|
|
#define PRCI_HFPCLKPLL_CFG0_BYPASS_SHIFT 24
|
|
#define PRCI_HFPCLKPLL_CFG0_BYPASS_MASK \
|
|
(0x1 << PRCI_HFPCLKPLLCFG0_BYPASS_SHIFT)
|
|
#define PRCI_HFPCLKPLL_CFG0_FSE_SHIFT 25
|
|
#define PRCI_HFPCLKPLL_CFG0_FSE_MASK \
|
|
(0x1 << PRCI_HFPCLKPLLCFG0_FSE_SHIFT)
|
|
#define PRCI_HFPCLKPLL_CFG0_LOCK_SHIFT 31
|
|
#define PRCI_HFPCLKPLL_CFG0_LOCK_MASK \
|
|
(0x1 << PRCI_HFPCLKPLLCFG0_LOCK_SHIFT)
|
|
|
|
/* HFPCLKPLLCFG1 */
|
|
#define PRCI_HFPCLKPLLCFG1_OFFSET 0x54
|
|
#define PRCI_HFPCLKPLLCFG1_CKE_SHIFT 24
|
|
#define PRCI_HFPCLKPLLCFG1_CKE_MASK \
|
|
(0x1 << PRCI_HFPCLKPLLCFG1_CKE_SHIFT)
|
|
|
|
/* HFPCLKPLLSEL */
|
|
#define PRCI_HFPCLKPLLSEL_OFFSET 0x58
|
|
#define PRCI_HFPCLKPLLSEL_HFPCLKPLLSEL_SHIFT 0
|
|
#define PRCI_HFPCLKPLLSEL_HFPCLKPLLSEL_MASK \
|
|
(0x1 << PRCI_HFPCLKPLLSEL_HFPCLKPLLSEL_SHIFT)
|
|
|
|
/* HFPCLKPLLDIV */
|
|
#define PRCI_HFPCLKPLLDIV_OFFSET 0x5c
|
|
|
|
/* PRCIPLL */
|
|
#define PRCI_PRCIPLL_OFFSET 0xe0
|
|
|
|
#define PRCI_PRCIPLL_CLTXPLL (0x1 << 0)
|
|
#define PRCI_PRCIPLL_GEMGXLPLL (0x1 << 1)
|
|
#define PRCI_PRCIPLL_DDRPLL (0x1 << 2)
|
|
#define PRCI_PRCIPLL_HFPCLKPLL (0x1 << 3)
|
|
#define PRCI_PRCIPLL_DVFSCOREPLL (0x1 << 4)
|
|
#define PRCI_PRCIPLL_COREPLL (0x1 << 5)
|
|
|
|
/* PROCMONCFG */
|
|
#define PRCI_PROCMONCFG_OFFSET 0xF0
|
|
#define PRCI_PROCMONCFG_CORE_CLOCK_SHIFT 24
|
|
#define PRCI_PROCMONCFG_CORE_CLOCK_MASK \
|
|
(0x1 << PRCI_PROCMONCFG_CORE_CLOCK_SHIFT)
|
|
|
|
/*
|
|
* Private structures
|
|
*/
|
|
|
|
/**
|
|
* struct __prci_data - per-device-instance data
|
|
* @va: base virtual address of the PRCI IP block
|
|
* @parent: parent clk instance
|
|
*
|
|
* PRCI per-device instance data
|
|
*/
|
|
struct __prci_data {
|
|
void *va;
|
|
struct clk parent_hfclk;
|
|
struct clk parent_rtcclk;
|
|
};
|
|
|
|
/**
|
|
* struct __prci_wrpll_data - WRPLL configuration and integration data
|
|
* @c: WRPLL current configuration record
|
|
* @enable_bypass: fn ptr to code to bypass the WRPLL (if applicable; else NULL)
|
|
* @disable_bypass: fn ptr to code to not bypass the WRPLL (or NULL)
|
|
* @cfg0_offs: WRPLL CFG0 register offset (in bytes) from the PRCI base address
|
|
* @cfg1_offs: WRPLL CFG1 register offset (in bytes) from the PRCI base address
|
|
* @release_reset: fn ptr to code to release clock reset
|
|
*
|
|
* @enable_bypass and @disable_bypass are used for WRPLL instances
|
|
* that contain a separate external glitchless clock mux downstream
|
|
* from the PLL. The WRPLL internal bypass mux is not glitchless.
|
|
*/
|
|
struct __prci_wrpll_data {
|
|
struct wrpll_cfg c;
|
|
void (*enable_bypass)(struct __prci_data *pd);
|
|
void (*disable_bypass)(struct __prci_data *pd);
|
|
u8 cfg0_offs;
|
|
u8 cfg1_offs;
|
|
void (*release_reset)(struct __prci_data *pd);
|
|
};
|
|
|
|
/**
|
|
* struct __prci_clock - describes a clock device managed by PRCI
|
|
* @name: user-readable clock name string - should match the manual
|
|
* @parent_name: parent name for this clock
|
|
* @ops: struct __prci_clock_ops for control
|
|
* @pwd: WRPLL-specific data, associated with this clock (if not NULL)
|
|
* @pd: PRCI-specific data associated with this clock (if not NULL)
|
|
*
|
|
* PRCI clock data. Used by the PRCI driver to register PRCI-provided
|
|
* clocks to the Linux clock infrastructure.
|
|
*/
|
|
struct __prci_clock {
|
|
const char *name;
|
|
const char *parent_name;
|
|
const struct __prci_clock_ops *ops;
|
|
struct __prci_wrpll_data *pwd;
|
|
struct __prci_data *pd;
|
|
};
|
|
|
|
/* struct __prci_clock_ops - clock operations */
|
|
struct __prci_clock_ops {
|
|
int (*set_rate)(struct __prci_clock *pc,
|
|
unsigned long rate,
|
|
unsigned long parent_rate);
|
|
unsigned long (*round_rate)(struct __prci_clock *pc,
|
|
unsigned long rate,
|
|
unsigned long *parent_rate);
|
|
unsigned long (*recalc_rate)(struct __prci_clock *pc,
|
|
unsigned long parent_rate);
|
|
int (*enable_clk)(struct __prci_clock *pc, bool enable);
|
|
};
|
|
|
|
/*
|
|
* struct prci_clk_desc - describes the information of clocks of each SoCs
|
|
* @clks: point to a array of __prci_clock
|
|
* @num_clks: the number of element of clks
|
|
*/
|
|
struct prci_clk_desc {
|
|
struct __prci_clock *clks;
|
|
size_t num_clks;
|
|
};
|
|
|
|
void sifive_prci_ethernet_release_reset(struct __prci_data *pd);
|
|
void sifive_prci_ddr_release_reset(struct __prci_data *pd);
|
|
void sifive_prci_cltx_release_reset(struct __prci_data *pd);
|
|
|
|
/* Core clock mux control */
|
|
void sifive_prci_coreclksel_use_hfclk(struct __prci_data *pd);
|
|
void sifive_prci_coreclksel_use_corepll(struct __prci_data *pd);
|
|
void sifive_prci_coreclksel_use_final_corepll(struct __prci_data *pd);
|
|
void sifive_prci_corepllsel_use_dvfscorepll(struct __prci_data *pd);
|
|
void sifive_prci_corepllsel_use_corepll(struct __prci_data *pd);
|
|
void sifive_prci_hfpclkpllsel_use_hfclk(struct __prci_data *pd);
|
|
void sifive_prci_hfpclkpllsel_use_hfpclkpll(struct __prci_data *pd);
|
|
|
|
unsigned long sifive_prci_wrpll_round_rate(struct __prci_clock *pc,
|
|
unsigned long rate,
|
|
unsigned long *parent_rate);
|
|
|
|
/* Linux clock framework integration */
|
|
int sifive_prci_wrpll_set_rate(struct __prci_clock *pc,
|
|
unsigned long rate,
|
|
unsigned long parent_rate);
|
|
|
|
unsigned long sifive_prci_wrpll_recalc_rate(struct __prci_clock *pc,
|
|
unsigned long parent_rate);
|
|
|
|
unsigned long sifive_prci_tlclksel_recalc_rate(struct __prci_clock *pc,
|
|
unsigned long parent_rate);
|
|
|
|
unsigned long sifive_prci_hfpclkplldiv_recalc_rate(struct __prci_clock *pc,
|
|
unsigned long parent_rate);
|
|
|
|
int sifive_prci_clock_enable(struct __prci_clock *pc, bool enable);
|
|
|
|
#endif /* __SIFIVE_CLK_SIFIVE_PRCI_H */
|