mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-24 20:31:34 +07:00
ba327b1e52
This adjusts the clockrate for the MTU timer. On the different UX500 variants this rate is different. The platform can also have been set up at hardware initialization, bootloader or early init for different clock speeds. To have the clock framework available early so the timers can use them, the clock initialization for Nomadik and ux500 is moved to IRQ init time. A custom per-clock callback is added to handle special cases like this. This solves a user-visible bug: without this patch the current UX500 platforms will not be synchronized to wall-clock time and the platform will drift in time. Acked-by: Rabin Vincent <rabin.vincent@stericsson.com> Signed-off-by: Linus Walleij <linus.walleij@stericsson.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
148 lines
4.7 KiB
C
148 lines
4.7 KiB
C
/*
|
|
* Copyright (C) 2010 ST-Ericsson
|
|
* Copyright (C) 2009 STMicroelectronics
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*/
|
|
|
|
/**
|
|
* struct clkops - ux500 clock operations
|
|
* @enable: function to enable the clock
|
|
* @disable: function to disable the clock
|
|
* @get_rate: function to get the current clock rate
|
|
*
|
|
* This structure contains function pointers to functions that will be used to
|
|
* control the clock. All of these functions are optional. If get_rate is
|
|
* NULL, the rate in the struct clk will be used.
|
|
*/
|
|
struct clkops {
|
|
void (*enable) (struct clk *);
|
|
void (*disable) (struct clk *);
|
|
unsigned long (*get_rate) (struct clk *);
|
|
};
|
|
|
|
/**
|
|
* struct clk - ux500 clock structure
|
|
* @ops: pointer to clkops struct used to control this clock
|
|
* @name: name, for debugging
|
|
* @enabled: refcount. positive if enabled, zero if disabled
|
|
* @get_rate: custom callback for getting the clock rate
|
|
* @data: custom per-clock data for example for the get_rate
|
|
* callback
|
|
* @rate: fixed rate for clocks which don't implement
|
|
* ops->getrate
|
|
* @prcmu_cg_off: address offset of the combined enable/disable register
|
|
* (used on u8500v1)
|
|
* @prcmu_cg_bit: bit in the combined enable/disable register (used on
|
|
* u8500v1)
|
|
* @prcmu_cg_mgt: address of the enable/disable register (used on
|
|
* u8500ed)
|
|
* @cluster: peripheral cluster number
|
|
* @prcc_bus: bit for the bus clock in the peripheral's CLKRST
|
|
* @prcc_kernel: bit for the kernel clock in the peripheral's CLKRST.
|
|
* -1 if no kernel clock exists.
|
|
* @parent_cluster: pointer to parent's cluster clk struct
|
|
* @parent_periph: pointer to parent's peripheral clk struct
|
|
*
|
|
* Peripherals are organised into clusters, and each cluster has an associated
|
|
* bus clock. Some peripherals also have a parent peripheral clock.
|
|
*
|
|
* In order to enable a clock for a peripheral, we need to enable:
|
|
* (1) the parent cluster (bus) clock at the PRCMU level
|
|
* (2) the parent peripheral clock (if any) at the PRCMU level
|
|
* (3) the peripheral's bus & kernel clock at the PRCC level
|
|
*
|
|
* (1) and (2) are handled by defining clk structs (DEFINE_PRCMU_CLK) for each
|
|
* of the cluster and peripheral clocks, and hooking these as the parents of
|
|
* the individual peripheral clocks.
|
|
*
|
|
* (3) is handled by specifying the bits in the PRCC control registers required
|
|
* to enable these clocks and modifying them in the ->enable and
|
|
* ->disable callbacks of the peripheral clocks (DEFINE_PRCC_CLK).
|
|
*
|
|
* This structure describes both the PRCMU-level clocks and PRCC-level clocks.
|
|
* The prcmu_* fields are only used for the PRCMU clocks, and the cluster,
|
|
* prcc, and parent pointers are only used for the PRCC-level clocks.
|
|
*/
|
|
struct clk {
|
|
const struct clkops *ops;
|
|
const char *name;
|
|
unsigned int enabled;
|
|
unsigned long (*get_rate)(struct clk *);
|
|
void *data;
|
|
|
|
unsigned long rate;
|
|
struct list_head list;
|
|
|
|
/* These three are only for PRCMU clks */
|
|
|
|
unsigned int prcmu_cg_off;
|
|
unsigned int prcmu_cg_bit;
|
|
unsigned int prcmu_cg_mgt;
|
|
|
|
/* The rest are only for PRCC clks */
|
|
|
|
int cluster;
|
|
unsigned int prcc_bus;
|
|
unsigned int prcc_kernel;
|
|
|
|
struct clk *parent_cluster;
|
|
struct clk *parent_periph;
|
|
};
|
|
|
|
#define DEFINE_PRCMU_CLK(_name, _cg_off, _cg_bit, _reg) \
|
|
struct clk clk_##_name = { \
|
|
.name = #_name, \
|
|
.ops = &clk_prcmu_ops, \
|
|
.prcmu_cg_off = _cg_off, \
|
|
.prcmu_cg_bit = _cg_bit, \
|
|
.prcmu_cg_mgt = PRCM_##_reg##_MGT \
|
|
}
|
|
|
|
#define DEFINE_PRCMU_CLK_RATE(_name, _cg_off, _cg_bit, _reg, _rate) \
|
|
struct clk clk_##_name = { \
|
|
.name = #_name, \
|
|
.ops = &clk_prcmu_ops, \
|
|
.prcmu_cg_off = _cg_off, \
|
|
.prcmu_cg_bit = _cg_bit, \
|
|
.rate = _rate, \
|
|
.prcmu_cg_mgt = PRCM_##_reg##_MGT \
|
|
}
|
|
|
|
#define DEFINE_PRCC_CLK(_pclust, _name, _bus_en, _kernel_en, _kernclk) \
|
|
struct clk clk_##_name = { \
|
|
.name = #_name, \
|
|
.ops = &clk_prcc_ops, \
|
|
.cluster = _pclust, \
|
|
.prcc_bus = _bus_en, \
|
|
.prcc_kernel = _kernel_en, \
|
|
.parent_cluster = &clk_per##_pclust##clk, \
|
|
.parent_periph = _kernclk \
|
|
}
|
|
|
|
#define DEFINE_PRCC_CLK_CUSTOM(_pclust, _name, _bus_en, _kernel_en, _kernclk, _callback, _data) \
|
|
struct clk clk_##_name = { \
|
|
.name = #_name, \
|
|
.ops = &clk_prcc_ops, \
|
|
.cluster = _pclust, \
|
|
.prcc_bus = _bus_en, \
|
|
.prcc_kernel = _kernel_en, \
|
|
.parent_cluster = &clk_per##_pclust##clk, \
|
|
.parent_periph = _kernclk, \
|
|
.get_rate = _callback, \
|
|
.data = (void *) _data \
|
|
}
|
|
|
|
|
|
#define CLK(_clk, _devname, _conname) \
|
|
{ \
|
|
.clk = &clk_##_clk, \
|
|
.dev_id = _devname, \
|
|
.con_id = _conname, \
|
|
}
|
|
|
|
int __init clk_db8500_ed_fixup(void);
|
|
int __init clk_init(void);
|