drivers/clocksource/arc_timer.c

Source file repositories/reference/linux-study-clean/drivers/clocksource/arc_timer.c

File Facts

System
Linux kernel
Corpus path
drivers/clocksource/arc_timer.c
Extension
.c
Size
9256 bytes
Lines
374
Domain
Driver Families
Bucket
drivers/clocksource
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (C) 2016-17 Synopsys, Inc. (www.synopsys.com)
 * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
 */

/* ARC700 has two 32bit independent prog Timers: TIMER0 and TIMER1, Each can be
 * programmed to go from @count to @limit and optionally interrupt.
 * We've designated TIMER0 for clockevents and TIMER1 for clocksource
 *
 * ARCv2 based HS38 cores have RTC (in-core) and GFRC (inside ARConnect/MCIP)
 * which are suitable for UP and SMP based clocksources respectively
 */

#include <linux/interrupt.h>
#include <linux/bits.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/clocksource.h>
#include <linux/clockchips.h>
#include <linux/cpu.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/sched_clock.h>

#include <soc/arc/timers.h>
#include <soc/arc/mcip.h>


static unsigned long arc_timer_freq;

static int noinline arc_get_timer_clk(struct device_node *node)
{
	struct clk *clk;
	int ret;

	clk = of_clk_get(node, 0);
	if (IS_ERR(clk)) {
		pr_err("timer missing clk\n");
		return PTR_ERR(clk);
	}

	ret = clk_prepare_enable(clk);
	if (ret) {
		pr_err("Couldn't enable parent clk\n");
		return ret;
	}

	arc_timer_freq = clk_get_rate(clk);

	return 0;
}

/********** Clock Source Device *********/

#ifdef CONFIG_ARC_TIMERS_64BIT

static u64 arc_read_gfrc(struct clocksource *cs)
{
	unsigned long flags;
	u32 l, h;

	/*
	 * From a programming model pov, there seems to be just one instance of
	 * MCIP_CMD/MCIP_READBACK however micro-architecturally there's
	 * an instance PER ARC CORE (not per cluster), and there are dedicated
	 * hardware decode logic (per core) inside ARConnect to handle
	 * simultaneous read/write accesses from cores via those two registers.
	 * So several concurrent commands to ARConnect are OK if they are
	 * trying to access two different sub-components (like GFRC,
	 * inter-core interrupt, etc...). HW also supports simultaneously
	 * accessing GFRC by multiple cores.
	 * That's why it is safe to disable hard interrupts on the local CPU
	 * before access to GFRC instead of taking global MCIP spinlock
	 * defined in arch/arc/kernel/mcip.c
	 */
	local_irq_save(flags);

	__mcip_cmd(CMD_GFRC_READ_LO, 0);
	l = read_aux_reg(ARC_REG_MCIP_READBACK);

	__mcip_cmd(CMD_GFRC_READ_HI, 0);
	h = read_aux_reg(ARC_REG_MCIP_READBACK);

	local_irq_restore(flags);

	return (((u64)h) << 32) | l;
}

static notrace u64 arc_gfrc_clock_read(void)

Annotation

Implementation Notes