mirror of https://gitee.com/openkylin/linux.git
Enhancements for dw_apb_timer:
- use DECLARE_CLOCKSOURCE_OF and convert its users - handle the sptimer not being present as sched_clock - add optional handling of timer clocks -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.12 (GNU/Linux) iQEcBAABCAAGBQJRuGStAAoJEPOmecmc0R2BLWcH/iHYyHg0IimZFFngD5H50F+S WO+R3xVUz9Y1/Hlsh9IQK9R2f/z2QUje1sQOVZhx4WYMAarUTAsX/oDs7TnPyoZ6 MaFJHKsAysXukiWWrrb1MaG8NGUqh4nt4YwCVsBHkG02i9dA3qy55+3BoMg3YiKP afWyXbJ/9IP1q9U9/tIjYO7fHDUmHtKRIo1MTx7erCm3gBSMUw7fWvs0Gc0QqUAn cfCnwilK8/BAnCTOi8RiTdUmQaI5CqGrNcBTw47E88HmoQVkp5W6BCY0brw4CfE8 XeqchZH6wEH89hRmf/0+zGuLT4qQ+jBL8bM88+KEbnsXREiIKFU/oZYygqskY60= =geqn -----END PGP SIGNATURE----- Merge tag 'dw_apb_timer_of' of git://github.com/mmind/linux-rockchip into next/drivers From Heiko Stuebner, enhancements for dw_apb_timer: - use DECLARE_CLOCKSOURCE_OF and convert its users - handle the sptimer not being present as sched_clock - add optional handling of timer clocks * tag 'dw_apb_timer_of' of git://github.com/mmind/linux-rockchip: clocksource: dw_apb_timer_of: use clocksource_of_init clocksource: dw_apb_timer_of: select DW_APB_TIMER clocksource: dw_apb_timer_of: add clock-handling clocksource: dw_apb_timer_of: enable the use the clocksource as sched clock
This commit is contained in:
commit
7d428ce284
|
@ -5,9 +5,20 @@ Required properties:
|
|||
- reg: physical base address of the controller and length of memory mapped
|
||||
region.
|
||||
- interrupts: IRQ line for the timer.
|
||||
- either clocks+clock-names or clock-frequency properties
|
||||
|
||||
Optional properties:
|
||||
- clocks : list of clock specifiers, corresponding to entries in
|
||||
the clock-names property;
|
||||
- clock-names : should contain "timer" and "pclk" entries, matching entries
|
||||
in the clocks property.
|
||||
- clock-frequency: The frequency in HZ of the timer.
|
||||
- clock-freq: For backwards compatibility with picoxcell
|
||||
|
||||
If using the clock specifiers, the pclk clock is optional, as not all
|
||||
systems may use one.
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
timer1: timer@ffc09000 {
|
||||
|
@ -23,3 +34,11 @@ Example:
|
|||
clock-frequency = <200000000>;
|
||||
reg = <0xffd00000 0x1000>;
|
||||
};
|
||||
|
||||
timer3: timer@ffe00000 {
|
||||
compatible = "snps,dw-apb-timer-osc";
|
||||
interrupts = <0 170 4>;
|
||||
reg = <0xffe00000 0x1000>;
|
||||
clocks = <&timer_clk>, <&timer_pclk>;
|
||||
clock-names = "timer", "pclk";
|
||||
};
|
||||
|
|
|
@ -4,7 +4,6 @@ config ARCH_PICOXCELL
|
|||
select ARM_PATCH_PHYS_VIRT
|
||||
select ARM_VIC
|
||||
select CPU_V6K
|
||||
select DW_APB_TIMER
|
||||
select DW_APB_TIMER_OF
|
||||
select GENERIC_CLOCKEVENTS
|
||||
select HAVE_TCM
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/dw_apb_timer.h>
|
||||
|
||||
#include <asm/mach/arch.h>
|
||||
#include <asm/mach/map.h>
|
||||
|
@ -88,7 +87,6 @@ DT_MACHINE_START(PICOXCELL, "Picochip picoXcell")
|
|||
.map_io = picoxcell_map_io,
|
||||
.nr_irqs = NR_IRQS_LEGACY,
|
||||
.init_irq = irqchip_init,
|
||||
.init_time = dw_apb_timer_init,
|
||||
.init_machine = picoxcell_init_machine,
|
||||
.dt_compat = picoxcell_dt_match,
|
||||
.restart = picoxcell_wdt_restart,
|
||||
|
|
|
@ -7,7 +7,6 @@ config ARCH_SOCFPGA
|
|||
select CLKDEV_LOOKUP
|
||||
select COMMON_CLK
|
||||
select CPU_V7
|
||||
select DW_APB_TIMER
|
||||
select DW_APB_TIMER_OF
|
||||
select GENERIC_CLOCKEVENTS
|
||||
select GPIO_PL061 if GPIOLIB
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <linux/dw_apb_timer.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/irqchip.h>
|
||||
#include <linux/of_address.h>
|
||||
|
@ -120,7 +119,6 @@ DT_MACHINE_START(SOCFPGA, "Altera SOCFPGA")
|
|||
.smp = smp_ops(socfpga_smp_ops),
|
||||
.map_io = socfpga_map_io,
|
||||
.init_irq = socfpga_init_irq,
|
||||
.init_time = dw_apb_timer_init,
|
||||
.init_machine = socfpga_cyclone5_init,
|
||||
.restart = socfpga_cyclone5_restart,
|
||||
.dt_compat = altera_dt_match,
|
||||
|
|
|
@ -21,6 +21,8 @@ config DW_APB_TIMER
|
|||
|
||||
config DW_APB_TIMER_OF
|
||||
bool
|
||||
select DW_APB_TIMER
|
||||
select CLKSRC_OF
|
||||
|
||||
config ARMADA_370_XP_TIMER
|
||||
bool
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
#include <asm/mach/time.h>
|
||||
#include <asm/sched_clock.h>
|
||||
|
@ -27,14 +28,37 @@
|
|||
static void timer_get_base_and_rate(struct device_node *np,
|
||||
void __iomem **base, u32 *rate)
|
||||
{
|
||||
struct clk *timer_clk;
|
||||
struct clk *pclk;
|
||||
|
||||
*base = of_iomap(np, 0);
|
||||
|
||||
if (!*base)
|
||||
panic("Unable to map regs for %s", np->name);
|
||||
|
||||
/*
|
||||
* Not all implementations use a periphal clock, so don't panic
|
||||
* if it's not present
|
||||
*/
|
||||
pclk = of_clk_get_by_name(np, "pclk");
|
||||
if (!IS_ERR(pclk))
|
||||
if (clk_prepare_enable(pclk))
|
||||
pr_warn("pclk for %s is present, but could not be activated\n",
|
||||
np->name);
|
||||
|
||||
timer_clk = of_clk_get_by_name(np, "timer");
|
||||
if (IS_ERR(timer_clk))
|
||||
goto try_clock_freq;
|
||||
|
||||
if (!clk_prepare_enable(timer_clk)) {
|
||||
*rate = clk_get_rate(timer_clk);
|
||||
return;
|
||||
}
|
||||
|
||||
try_clock_freq:
|
||||
if (of_property_read_u32(np, "clock-freq", rate) &&
|
||||
of_property_read_u32(np, "clock-frequency", rate))
|
||||
panic("No clock-frequency property for %s", np->name);
|
||||
panic("No clock nor clock-frequency property for %s", np->name);
|
||||
}
|
||||
|
||||
static void add_clockevent(struct device_node *event_timer)
|
||||
|
@ -57,6 +81,9 @@ static void add_clockevent(struct device_node *event_timer)
|
|||
dw_apb_clockevent_register(ced);
|
||||
}
|
||||
|
||||
static void __iomem *sched_io_base;
|
||||
static u32 sched_rate;
|
||||
|
||||
static void add_clocksource(struct device_node *source_timer)
|
||||
{
|
||||
void __iomem *iobase;
|
||||
|
@ -71,9 +98,15 @@ static void add_clocksource(struct device_node *source_timer)
|
|||
|
||||
dw_apb_clocksource_start(cs);
|
||||
dw_apb_clocksource_register(cs);
|
||||
}
|
||||
|
||||
static void __iomem *sched_io_base;
|
||||
/*
|
||||
* Fallback to use the clocksource as sched_clock if no separate
|
||||
* timer is found. sched_io_base then points to the current_value
|
||||
* register of the clocksource timer.
|
||||
*/
|
||||
sched_io_base = iobase + 0x04;
|
||||
sched_rate = rate;
|
||||
}
|
||||
|
||||
static u32 read_sched_clock(void)
|
||||
{
|
||||
|
@ -89,39 +122,37 @@ static const struct of_device_id sptimer_ids[] __initconst = {
|
|||
static void init_sched_clock(void)
|
||||
{
|
||||
struct device_node *sched_timer;
|
||||
u32 rate;
|
||||
|
||||
sched_timer = of_find_matching_node(NULL, sptimer_ids);
|
||||
if (!sched_timer)
|
||||
panic("No RTC for sched clock to use");
|
||||
if (sched_timer) {
|
||||
timer_get_base_and_rate(sched_timer, &sched_io_base,
|
||||
&sched_rate);
|
||||
of_node_put(sched_timer);
|
||||
}
|
||||
|
||||
timer_get_base_and_rate(sched_timer, &sched_io_base, &rate);
|
||||
of_node_put(sched_timer);
|
||||
|
||||
setup_sched_clock(read_sched_clock, 32, rate);
|
||||
setup_sched_clock(read_sched_clock, 32, sched_rate);
|
||||
}
|
||||
|
||||
static const struct of_device_id osctimer_ids[] __initconst = {
|
||||
{ .compatible = "picochip,pc3x2-timer" },
|
||||
{ .compatible = "snps,dw-apb-timer-osc" },
|
||||
{},
|
||||
};
|
||||
|
||||
void __init dw_apb_timer_init(void)
|
||||
static int num_called;
|
||||
static void __init dw_apb_timer_init(struct device_node *timer)
|
||||
{
|
||||
struct device_node *event_timer, *source_timer;
|
||||
switch (num_called) {
|
||||
case 0:
|
||||
pr_debug("%s: found clockevent timer\n", __func__);
|
||||
add_clockevent(timer);
|
||||
of_node_put(timer);
|
||||
break;
|
||||
case 1:
|
||||
pr_debug("%s: found clocksource timer\n", __func__);
|
||||
add_clocksource(timer);
|
||||
of_node_put(timer);
|
||||
init_sched_clock();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
event_timer = of_find_matching_node(NULL, osctimer_ids);
|
||||
if (!event_timer)
|
||||
panic("No timer for clockevent");
|
||||
add_clockevent(event_timer);
|
||||
|
||||
source_timer = of_find_matching_node(event_timer, osctimer_ids);
|
||||
if (!source_timer)
|
||||
panic("No timer for clocksource");
|
||||
add_clocksource(source_timer);
|
||||
|
||||
of_node_put(source_timer);
|
||||
|
||||
init_sched_clock();
|
||||
num_called++;
|
||||
}
|
||||
CLOCKSOURCE_OF_DECLARE(pc3x2_timer, "picochip,pc3x2-timer", dw_apb_timer_init);
|
||||
CLOCKSOURCE_OF_DECLARE(apb_timer, "snps,dw-apb-timer-osc", dw_apb_timer_init);
|
||||
|
|
|
@ -53,5 +53,4 @@ void dw_apb_clocksource_start(struct dw_apb_clocksource *dw_cs);
|
|||
cycle_t dw_apb_clocksource_read(struct dw_apb_clocksource *dw_cs);
|
||||
void dw_apb_clocksource_unregister(struct dw_apb_clocksource *dw_cs);
|
||||
|
||||
extern void dw_apb_timer_init(void);
|
||||
#endif /* __DW_APB_TIMER_H__ */
|
||||
|
|
Loading…
Reference in New Issue