linux/drivers/clk/bcm/clk-bcm2835.c

// SPDX-License-Identifier: GPL-2.0+
/*
 * Copyright (C) 2010,2015 Broadcom
 * Copyright (C) 2012 Stephen Warren
 */

/**
 * DOC: BCM2835 CPRMAN (clock manager for the "audio" domain)
 *
 * The clock tree on the 2835 has several levels.  There's a root
 * oscillator running at 19.2Mhz.  After the oscillator there are 5
 * PLLs, roughly divided as "camera", "ARM", "core", "DSI displays",
 * and "HDMI displays".  Those 5 PLLs each can divide their output to
 * produce up to 4 channels.  Finally, there is the level of clocks to
 * be consumed by other hardware components (like "H264" or "HDMI
 * state machine"), which divide off of some subset of the PLL
 * channels.
 *
 * All of the clocks in the tree are exposed in the DT, because the DT
 * may want to make assignments of the final layer of clocks to the
 * PLL channels, and some components of the hardware will actually
 * skip layers of the tree (for example, the pixel clock comes
 * directly from the PLLH PIX channel without using a CM_*CTL clock
 * generator).
 */

#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/clk.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/math.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <dt-bindings/clock/bcm2835.h>

#define CM_PASSWORD

#define CM_GNRICCTL
#define CM_GNRICDIV
#define CM_DIV_FRAC_BITS
#define CM_DIV_FRAC_MASK

#define CM_VPUCTL
#define CM_VPUDIV
#define CM_SYSCTL
#define CM_SYSDIV
#define CM_PERIACTL
#define CM_PERIADIV
#define CM_PERIICTL
#define CM_PERIIDIV
#define CM_H264CTL
#define CM_H264DIV
#define CM_ISPCTL
#define CM_ISPDIV
#define CM_V3DCTL
#define CM_V3DDIV
#define CM_CAM0CTL
#define CM_CAM0DIV
#define CM_CAM1CTL
#define CM_CAM1DIV
#define CM_CCP2CTL
#define CM_CCP2DIV
#define CM_DSI0ECTL
#define CM_DSI0EDIV
#define CM_DSI0PCTL
#define CM_DSI0PDIV
#define CM_DPICTL
#define CM_DPIDIV
#define CM_GP0CTL
#define CM_GP0DIV
#define CM_GP1CTL
#define CM_GP1DIV
#define CM_GP2CTL
#define CM_GP2DIV
#define CM_HSMCTL
#define CM_HSMDIV
#define CM_OTPCTL
#define CM_OTPDIV
#define CM_PCMCTL
#define CM_PCMDIV
#define CM_PWMCTL
#define CM_PWMDIV
#define CM_SLIMCTL
#define CM_SLIMDIV
#define CM_SMICTL
#define CM_SMIDIV
/* no definition for 0x0b8  and 0x0bc */
#define CM_TCNTCTL
#define CM_TCNT_SRC1_SHIFT
#define CM_TCNTCNT
#define CM_TECCTL
#define CM_TECDIV
#define CM_TD0CTL
#define CM_TD0DIV
#define CM_TD1CTL
#define CM_TD1DIV
#define CM_TSENSCTL
#define CM_TSENSDIV
#define CM_TIMERCTL
#define CM_TIMERDIV
#define CM_UARTCTL
#define CM_UARTDIV
#define CM_VECCTL
#define CM_VECDIV
#define CM_PULSECTL
#define CM_PULSEDIV
#define CM_SDCCTL
#define CM_SDCDIV
#define CM_ARMCTL
#define CM_AVEOCTL
#define CM_AVEODIV
#define CM_EMMCCTL
#define CM_EMMCDIV
#define CM_EMMC2CTL
#define CM_EMMC2DIV

/* General bits for the CM_*CTL regs */
#define CM_ENABLE
#define CM_KILL
#define CM_GATE_BIT
#define CM_GATE
#define CM_BUSY
#define CM_BUSYD
#define CM_FRAC
#define CM_SRC_SHIFT
#define CM_SRC_BITS
#define CM_SRC_MASK
#define CM_SRC_GND
#define CM_SRC_OSC
#define CM_SRC_TESTDEBUG0
#define CM_SRC_TESTDEBUG1
#define CM_SRC_PLLA_CORE
#define CM_SRC_PLLA_PER
#define CM_SRC_PLLC_CORE0
#define CM_SRC_PLLC_PER
#define CM_SRC_PLLC_CORE1
#define CM_SRC_PLLD_CORE
#define CM_SRC_PLLD_PER
#define CM_SRC_PLLH_AUX
#define CM_SRC_PLLC_CORE1
#define CM_SRC_PLLC_CORE2

#define CM_OSCCOUNT

#define CM_PLLA
#define CM_PLL_ANARST
#define CM_PLLA_HOLDPER
#define CM_PLLA_LOADPER
#define CM_PLLA_HOLDCORE
#define CM_PLLA_LOADCORE
#define CM_PLLA_HOLDCCP2
#define CM_PLLA_LOADCCP2
#define CM_PLLA_HOLDDSI0
#define CM_PLLA_LOADDSI0

#define CM_PLLC
#define CM_PLLC_HOLDPER
#define CM_PLLC_LOADPER
#define CM_PLLC_HOLDCORE2
#define CM_PLLC_LOADCORE2
#define CM_PLLC_HOLDCORE1
#define CM_PLLC_LOADCORE1
#define CM_PLLC_HOLDCORE0
#define CM_PLLC_LOADCORE0

#define CM_PLLD
#define CM_PLLD_HOLDPER
#define CM_PLLD_LOADPER
#define CM_PLLD_HOLDCORE
#define CM_PLLD_LOADCORE
#define CM_PLLD_HOLDDSI1
#define CM_PLLD_LOADDSI1
#define CM_PLLD_HOLDDSI0
#define CM_PLLD_LOADDSI0

#define CM_PLLH
#define CM_PLLH_LOADRCAL
#define CM_PLLH_LOADAUX
#define CM_PLLH_LOADPIX

#define CM_LOCK
#define CM_LOCK_FLOCKH
#define CM_LOCK_FLOCKD
#define CM_LOCK_FLOCKC
#define CM_LOCK_FLOCKB
#define CM_LOCK_FLOCKA

#define CM_EVENT
#define CM_DSI1ECTL
#define CM_DSI1EDIV
#define CM_DSI1PCTL
#define CM_DSI1PDIV
#define CM_DFTCTL
#define CM_DFTDIV

#define CM_PLLB
#define CM_PLLB_HOLDARM
#define CM_PLLB_LOADARM

#define A2W_PLLA_CTRL
#define A2W_PLLC_CTRL
#define A2W_PLLD_CTRL
#define A2W_PLLH_CTRL
#define A2W_PLLB_CTRL
#define A2W_PLL_CTRL_PRST_DISABLE
#define A2W_PLL_CTRL_PWRDN
#define A2W_PLL_CTRL_PDIV_MASK
#define A2W_PLL_CTRL_PDIV_SHIFT
#define A2W_PLL_CTRL_NDIV_MASK
#define A2W_PLL_CTRL_NDIV_SHIFT

#define A2W_PLLA_ANA0
#define A2W_PLLC_ANA0
#define A2W_PLLD_ANA0
#define A2W_PLLH_ANA0
#define A2W_PLLB_ANA0

#define A2W_PLL_KA_SHIFT
#define A2W_PLL_KA_MASK
#define A2W_PLL_KI_SHIFT
#define A2W_PLL_KI_MASK
#define A2W_PLL_KP_SHIFT
#define A2W_PLL_KP_MASK

#define A2W_PLLH_KA_SHIFT
#define A2W_PLLH_KA_MASK
#define A2W_PLLH_KI_LOW_SHIFT
#define A2W_PLLH_KI_LOW_MASK
#define A2W_PLLH_KI_HIGH_SHIFT
#define A2W_PLLH_KI_HIGH_MASK
#define A2W_PLLH_KP_SHIFT
#define A2W_PLLH_KP_MASK

#define A2W_XOSC_CTRL
#define A2W_XOSC_CTRL_PLLB_ENABLE
#define A2W_XOSC_CTRL_PLLA_ENABLE
#define A2W_XOSC_CTRL_PLLD_ENABLE
#define A2W_XOSC_CTRL_DDR_ENABLE
#define A2W_XOSC_CTRL_CPR1_ENABLE
#define A2W_XOSC_CTRL_USB_ENABLE
#define A2W_XOSC_CTRL_HDMI_ENABLE
#define A2W_XOSC_CTRL_PLLC_ENABLE

#define A2W_PLLA_FRAC
#define A2W_PLLC_FRAC
#define A2W_PLLD_FRAC
#define A2W_PLLH_FRAC
#define A2W_PLLB_FRAC
#define A2W_PLL_FRAC_MASK
#define A2W_PLL_FRAC_BITS

#define A2W_PLL_CHANNEL_DISABLE
#define A2W_PLL_DIV_BITS
#define A2W_PLL_DIV_SHIFT

#define A2W_PLLA_DSI0
#define A2W_PLLA_CORE
#define A2W_PLLA_PER
#define A2W_PLLA_CCP2

#define A2W_PLLC_CORE2
#define A2W_PLLC_CORE1
#define A2W_PLLC_PER
#define A2W_PLLC_CORE0

#define A2W_PLLD_DSI0
#define A2W_PLLD_CORE
#define A2W_PLLD_PER
#define A2W_PLLD_DSI1

#define A2W_PLLH_AUX
#define A2W_PLLH_RCAL
#define A2W_PLLH_PIX
#define A2W_PLLH_STS

#define A2W_PLLH_CTRLR
#define A2W_PLLH_FRACR
#define A2W_PLLH_AUXR
#define A2W_PLLH_RCALR
#define A2W_PLLH_PIXR
#define A2W_PLLH_STSR

#define A2W_PLLB_ARM
#define A2W_PLLB_SP0
#define A2W_PLLB_SP1
#define A2W_PLLB_SP2

#define LOCK_TIMEOUT_NS
#define BCM2835_MAX_FB_RATE

#define SOC_BCM2835
#define SOC_BCM2711
#define SOC_ALL

/*
 * Names of clocks used within the driver that need to be replaced
 * with an external parent's name.  This array is in the order that
 * the clocks node in the DT references external clocks.
 */
static const char *const cprman_parent_names[] =;

struct bcm2835_cprman {};

struct cprman_plat_data {};

static inline void cprman_write(struct bcm2835_cprman *cprman, u32 reg, u32 val)
{}

static inline u32 cprman_read(struct bcm2835_cprman *cprman, u32 reg)
{}

/* Does a cycle of measuring a clock through the TCNT clock, which may
 * source from many other clocks in the system.
 */
static unsigned long bcm2835_measure_tcnt_mux(struct bcm2835_cprman *cprman,
					      u32 tcnt_mux)
{}

static void bcm2835_debugfs_regset(struct bcm2835_cprman *cprman, u32 base,
				   const struct debugfs_reg32 *regs,
				   size_t nregs, struct dentry *dentry)
{}

struct bcm2835_pll_data {};

struct bcm2835_pll_ana_bits {};

static const struct bcm2835_pll_ana_bits bcm2835_ana_default =;

static const struct bcm2835_pll_ana_bits bcm2835_ana_pllh =;

struct bcm2835_pll_divider_data {};

struct bcm2835_clock_data {};

struct bcm2835_gate_data {};

struct bcm2835_pll {};

static int bcm2835_pll_is_on(struct clk_hw *hw)
{}

static u32 bcm2835_pll_get_prediv_mask(struct bcm2835_cprman *cprman,
				       const struct bcm2835_pll_data *data)
{}

static void bcm2835_pll_choose_ndiv_and_fdiv(unsigned long rate,
					     unsigned long parent_rate,
					     u32 *ndiv, u32 *fdiv)
{}

static long bcm2835_pll_rate_from_divisors(unsigned long parent_rate,
					   u32 ndiv, u32 fdiv, u32 pdiv)
{}

static long bcm2835_pll_round_rate(struct clk_hw *hw, unsigned long rate,
				   unsigned long *parent_rate)
{}

static unsigned long bcm2835_pll_get_rate(struct clk_hw *hw,
					  unsigned long parent_rate)
{}

static void bcm2835_pll_off(struct clk_hw *hw)
{}

static int bcm2835_pll_on(struct clk_hw *hw)
{}

static void
bcm2835_pll_write_ana(struct bcm2835_cprman *cprman, u32 ana_reg_base, u32 *ana)
{}

static int bcm2835_pll_set_rate(struct clk_hw *hw,
				unsigned long rate, unsigned long parent_rate)
{}

static void bcm2835_pll_debug_init(struct clk_hw *hw,
				  struct dentry *dentry)
{}

static const struct clk_ops bcm2835_pll_clk_ops =;

struct bcm2835_pll_divider {};

static struct bcm2835_pll_divider *
bcm2835_pll_divider_from_hw(struct clk_hw *hw)
{}

static int bcm2835_pll_divider_is_on(struct clk_hw *hw)
{}

static int bcm2835_pll_divider_determine_rate(struct clk_hw *hw,
					      struct clk_rate_request *req)
{}

static unsigned long bcm2835_pll_divider_get_rate(struct clk_hw *hw,
						  unsigned long parent_rate)
{}

static void bcm2835_pll_divider_off(struct clk_hw *hw)
{}

static int bcm2835_pll_divider_on(struct clk_hw *hw)
{}

static int bcm2835_pll_divider_set_rate(struct clk_hw *hw,
					unsigned long rate,
					unsigned long parent_rate)
{}

static void bcm2835_pll_divider_debug_init(struct clk_hw *hw,
					   struct dentry *dentry)
{}

static const struct clk_ops bcm2835_pll_divider_clk_ops =;

/*
 * The CM dividers do fixed-point division, so we can't use the
 * generic integer divider code like the PLL dividers do (and we can't
 * fake it by having some fixed shifts preceding it in the clock tree,
 * because we'd run out of bits in a 32-bit unsigned long).
 */
struct bcm2835_clock {};

static struct bcm2835_clock *bcm2835_clock_from_hw(struct clk_hw *hw)
{}

static int bcm2835_clock_is_on(struct clk_hw *hw)
{}

static u32 bcm2835_clock_choose_div(struct clk_hw *hw,
				    unsigned long rate,
				    unsigned long parent_rate)
{}

static unsigned long bcm2835_clock_rate_from_divisor(struct bcm2835_clock *clock,
						     unsigned long parent_rate,
						     u32 div)
{}

static unsigned long bcm2835_round_rate(unsigned long rate)
{}

static unsigned long bcm2835_clock_get_rate(struct clk_hw *hw,
					    unsigned long parent_rate)
{}

static void bcm2835_clock_wait_busy(struct bcm2835_clock *clock)
{}

static void bcm2835_clock_off(struct clk_hw *hw)
{}

static int bcm2835_clock_on(struct clk_hw *hw)
{}

static int bcm2835_clock_set_rate(struct clk_hw *hw,
				  unsigned long rate, unsigned long parent_rate)
{}

static bool
bcm2835_clk_is_pllc(struct clk_hw *hw)
{}

static unsigned long bcm2835_clock_choose_div_and_prate(struct clk_hw *hw,
							int parent_idx,
							unsigned long rate,
							u32 *div,
							unsigned long *prate,
							unsigned long *avgrate)
{}

static int bcm2835_clock_determine_rate(struct clk_hw *hw,
					struct clk_rate_request *req)
{}

static int bcm2835_clock_set_parent(struct clk_hw *hw, u8 index)
{}

static u8 bcm2835_clock_get_parent(struct clk_hw *hw)
{}

static const struct debugfs_reg32 bcm2835_debugfs_clock_reg32[] =;

static void bcm2835_clock_debug_init(struct clk_hw *hw,
				    struct dentry *dentry)
{}

static const struct clk_ops bcm2835_clock_clk_ops =;

static int bcm2835_vpu_clock_is_on(struct clk_hw *hw)
{}

/*
 * The VPU clock can never be disabled (it doesn't have an ENABLE
 * bit), so it gets its own set of clock ops.
 */
static const struct clk_ops bcm2835_vpu_clock_clk_ops =;

static struct clk_hw *bcm2835_register_pll(struct bcm2835_cprman *cprman,
					   const void *data)
{}

static struct clk_hw *
bcm2835_register_pll_divider(struct bcm2835_cprman *cprman,
			     const void *data)
{}

static struct clk_hw *bcm2835_register_clock(struct bcm2835_cprman *cprman,
					     const void *data)
{}

static struct clk_hw *bcm2835_register_gate(struct bcm2835_cprman *cprman,
					    const void *data)
{}

struct bcm2835_clk_desc {};

/* assignment helper macros for different clock types */
#define _REGISTER(f, s, ...)
#define REGISTER_PLL(s, ...)
#define REGISTER_PLL_DIV(s, ...)
#define REGISTER_CLK(s, ...)
#define REGISTER_GATE(s, ...)

/* parent mux arrays plus helper macros */

/* main oscillator parent mux */
static const char *const bcm2835_clock_osc_parents[] =;

#define REGISTER_OSC_CLK(s, ...)

/* main peripherial parent mux */
static const char *const bcm2835_clock_per_parents[] =;

#define REGISTER_PER_CLK(s, ...)

/*
 * Restrict clock sources for the PCM peripheral to the oscillator and
 * PLLD_PER because other source may have varying rates or be switched
 * off.
 *
 * Prevent other sources from being selected by replacing their names in
 * the list of potential parents with dummy entries (entry index is
 * significant).
 */
static const char *const bcm2835_pcm_per_parents[] =;

#define REGISTER_PCM_CLK(s, ...)

/* main vpu parent mux */
static const char *const bcm2835_clock_vpu_parents[] =;

#define REGISTER_VPU_CLK(s, ...)

/*
 * DSI parent clocks.  The DSI byte/DDR/DDR2 clocks come from the DSI
 * analog PHY.  The _inv variants are generated internally to cprman,
 * but we don't use them so they aren't hooked up.
 */
static const char *const bcm2835_clock_dsi0_parents[] =;

static const char *const bcm2835_clock_dsi1_parents[] =;

#define REGISTER_DSI0_CLK(s, ...)

#define REGISTER_DSI1_CLK(s, ...)

/*
 * the real definition of all the pll, pll_dividers and clocks
 * these make use of the above REGISTER_* macros
 */
static const struct bcm2835_clk_desc clk_desc_array[] =;

/*
 * Permanently take a reference on the parent of the SDRAM clock.
 *
 * While the SDRAM is being driven by its dedicated PLL most of the
 * time, there is a little loop running in the firmware that
 * periodically switches the SDRAM to using our CM clock to do PVT
 * recalibration, with the assumption that the previously configured
 * SDRAM parent is still enabled and running.
 */
static int bcm2835_mark_sdc_parent_critical(struct clk *sdc)
{}

static int bcm2835_clk_probe(struct platform_device *pdev)
{}

static const struct cprman_plat_data cprman_bcm2835_plat_data =;

static const struct cprman_plat_data cprman_bcm2711_plat_data =;

static const struct of_device_id bcm2835_clk_of_match[] =;
MODULE_DEVICE_TABLE(of, bcm2835_clk_of_match);

static struct platform_driver bcm2835_clk_driver =;

builtin_platform_driver();

MODULE_AUTHOR();
MODULE_DESCRIPTION();