root/drivers/clk/sifive/sifive-prci.h
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Copyright (C) 2018-2019 SiFive, Inc.
 * Wesley Terpstra
 * Paul Walmsley
 * Zong Li
 */

#ifndef __SIFIVE_CLK_SIFIVE_PRCI_H
#define __SIFIVE_CLK_SIFIVE_PRCI_H

#include <linux/clk/analogbits-wrpll-cln28hpc.h>
#include <linux/clk-provider.h>
#include <linux/reset/reset-simple.h>
#include <linux/platform_device.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)

/* PCIEAUX */
#define PRCI_PCIE_AUX_OFFSET            0x14
#define PRCI_PCIE_AUX_EN_SHIFT          0
#define PRCI_PCIE_AUX_EN_MASK           (0x1 << PRCI_PCIE_AUX_EN_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_DEVICESRESETREG_DDR_CTRL_RST_N_SHIFT               0
#define PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_MASK                        \
                (0x1 << PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_SHIFT)
#define PRCI_DEVICESRESETREG_DDR_AXI_RST_N_SHIFT                1
#define PRCI_DEVICESRESETREG_DDR_AXI_RST_N_MASK                         \
                (0x1 << PRCI_DEVICESRESETREG_DDR_AXI_RST_N_SHIFT)
#define PRCI_DEVICESRESETREG_DDR_AHB_RST_N_SHIFT                2
#define PRCI_DEVICESRESETREG_DDR_AHB_RST_N_MASK                         \
                (0x1 << PRCI_DEVICESRESETREG_DDR_AHB_RST_N_SHIFT)
#define PRCI_DEVICESRESETREG_DDR_PHY_RST_N_SHIFT                3
#define PRCI_DEVICESRESETREG_DDR_PHY_RST_N_MASK                         \
                (0x1 << PRCI_DEVICESRESETREG_DDR_PHY_RST_N_SHIFT)
#define PRCI_DEVICESRESETREG_GEMGXL_RST_N_SHIFT                 5
#define PRCI_DEVICESRESETREG_GEMGXL_RST_N_MASK                          \
                (0x1 << PRCI_DEVICESRESETREG_GEMGXL_RST_N_SHIFT)
#define PRCI_DEVICESRESETREG_CHIPLINK_RST_N_SHIFT               6
#define PRCI_DEVICESRESETREG_CHIPLINK_RST_N_MASK                        \
                (0x1 << PRCI_DEVICESRESETREG_CHIPLINK_RST_N_SHIFT)

#define PRCI_RST_NR                                             7

/* 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      31
#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  31
#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            31
#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

/* PROCMONCFG */
#define PRCI_PROCMONCFG_OFFSET                  0xf0

/*
 * Private structures
 */

/**
 * struct __prci_data - per-device-instance data
 * @va: base virtual address of the PRCI IP block
 * @hw_clks: encapsulates struct clk_hw records
 *
 * PRCI per-device instance data
 */
struct __prci_data {
        void __iomem *va;
        struct reset_simple_data reset;
        struct clk_hw_onecell_data hw_clks;
};

/**
 * 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
 *
 * @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;
};

/**
 * 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 clk_ops for the Linux clock framework to use for control
 * @hw: Linux-private clock data
 * @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 clk_ops *ops;
        struct clk_hw hw;
        struct __prci_wrpll_data *pwd;
        struct __prci_data *pd;
};

#define clk_hw_to_prci_clock(pwd) container_of(pwd, struct __prci_clock, hw)

/*
 * 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;
};

/* 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);

/* Linux clock framework integration */
int sifive_prci_wrpll_determine_rate(struct clk_hw *hw,
                                     struct clk_rate_request *req);
int sifive_prci_wrpll_set_rate(struct clk_hw *hw, unsigned long rate,
                               unsigned long parent_rate);
int sifive_clk_is_enabled(struct clk_hw *hw);
int sifive_prci_clock_enable(struct clk_hw *hw);
void sifive_prci_clock_disable(struct clk_hw *hw);
unsigned long sifive_prci_wrpll_recalc_rate(struct clk_hw *hw,
                                            unsigned long parent_rate);
unsigned long sifive_prci_tlclksel_recalc_rate(struct clk_hw *hw,
                                               unsigned long parent_rate);
unsigned long sifive_prci_hfpclkplldiv_recalc_rate(struct clk_hw *hw,
                                                   unsigned long parent_rate);

int sifive_prci_pcie_aux_clock_is_enabled(struct clk_hw *hw);
int sifive_prci_pcie_aux_clock_enable(struct clk_hw *hw);
void sifive_prci_pcie_aux_clock_disable(struct clk_hw *hw);

#endif /* __SIFIVE_CLK_SIFIVE_PRCI_H */