xref: /openbmc/u-boot/drivers/timer/arc_timer.c (revision 1d6edcbf)
1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2ad9b5f77SVlad Zakharov /*
3ad9b5f77SVlad Zakharov  * Copyright (C) 2016 Synopsys, Inc. All rights reserved.
4ad9b5f77SVlad Zakharov  */
5ad9b5f77SVlad Zakharov 
6ad9b5f77SVlad Zakharov #include <common.h>
7ad9b5f77SVlad Zakharov #include <dm.h>
8ad9b5f77SVlad Zakharov #include <errno.h>
9ad9b5f77SVlad Zakharov #include <timer.h>
10ad9b5f77SVlad Zakharov #include <asm/arcregs.h>
11ad9b5f77SVlad Zakharov #include <asm/io.h>
12ad9b5f77SVlad Zakharov 
13ad9b5f77SVlad Zakharov DECLARE_GLOBAL_DATA_PTR;
14ad9b5f77SVlad Zakharov 
15ad9b5f77SVlad Zakharov #define NH_MODE (1 << 1)
16ad9b5f77SVlad Zakharov 
17ad9b5f77SVlad Zakharov /*
18ad9b5f77SVlad Zakharov  * ARC timer control registers are mapped to auxiliary address space.
19ad9b5f77SVlad Zakharov  * There are special ARC asm command to access that addresses.
20ad9b5f77SVlad Zakharov  * Therefore we use built-in functions to read from and write to timer
21ad9b5f77SVlad Zakharov  * control register.
22ad9b5f77SVlad Zakharov  */
23ad9b5f77SVlad Zakharov 
24ad9b5f77SVlad Zakharov /* Driver private data. Contains timer id. Could be either 0 or 1. */
25ad9b5f77SVlad Zakharov struct arc_timer_priv {
26ad9b5f77SVlad Zakharov 		uint timer_id;
27ad9b5f77SVlad Zakharov };
28ad9b5f77SVlad Zakharov 
arc_timer_get_count(struct udevice * dev,u64 * count)29ad9b5f77SVlad Zakharov static int arc_timer_get_count(struct udevice *dev, u64 *count)
30ad9b5f77SVlad Zakharov {
31ad9b5f77SVlad Zakharov 	u32 val = 0;
32ad9b5f77SVlad Zakharov 	struct arc_timer_priv *priv = dev_get_priv(dev);
33ad9b5f77SVlad Zakharov 
34ad9b5f77SVlad Zakharov 	switch (priv->timer_id) {
35ad9b5f77SVlad Zakharov 	case 0:
36ad9b5f77SVlad Zakharov 		val = read_aux_reg(ARC_AUX_TIMER0_CNT);
37ad9b5f77SVlad Zakharov 		break;
38ad9b5f77SVlad Zakharov 	case 1:
39ad9b5f77SVlad Zakharov 		val = read_aux_reg(ARC_AUX_TIMER1_CNT);
40ad9b5f77SVlad Zakharov 		break;
41ad9b5f77SVlad Zakharov 	}
42ad9b5f77SVlad Zakharov 	*count = timer_conv_64(val);
43ad9b5f77SVlad Zakharov 
44ad9b5f77SVlad Zakharov 	return 0;
45ad9b5f77SVlad Zakharov }
46ad9b5f77SVlad Zakharov 
arc_timer_probe(struct udevice * dev)47ad9b5f77SVlad Zakharov static int arc_timer_probe(struct udevice *dev)
48ad9b5f77SVlad Zakharov {
49ad9b5f77SVlad Zakharov 	int id;
50ad9b5f77SVlad Zakharov 	struct arc_timer_priv *priv = dev_get_priv(dev);
51ad9b5f77SVlad Zakharov 
52ad9b5f77SVlad Zakharov 	/* Get registers offset and size */
53da409cccSSimon Glass 	id = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "reg", -1);
54ad9b5f77SVlad Zakharov 	if (id < 0)
55ad9b5f77SVlad Zakharov 		return -EINVAL;
56ad9b5f77SVlad Zakharov 
57ad9b5f77SVlad Zakharov 	if (id > 1)
58ad9b5f77SVlad Zakharov 		return -ENXIO;
59ad9b5f77SVlad Zakharov 
60ad9b5f77SVlad Zakharov 	priv->timer_id = (uint)id;
61ad9b5f77SVlad Zakharov 
62ad9b5f77SVlad Zakharov 	/*
63ad9b5f77SVlad Zakharov 	 * In ARC core there're special registers (Auxiliary or AUX) in its
64ad9b5f77SVlad Zakharov 	 * separate memory space that are used for accessing some hardware
65ad9b5f77SVlad Zakharov 	 * features of the core. They are not mapped in normal memory space
66ad9b5f77SVlad Zakharov 	 * and also always have the same location regardless core configuration.
67ad9b5f77SVlad Zakharov 	 * Thus to simplify understanding of the programming model we chose to
68ad9b5f77SVlad Zakharov 	 * access AUX regs of Timer0 and Timer1 separately instead of using
69ad9b5f77SVlad Zakharov 	 * offsets from some base address.
70ad9b5f77SVlad Zakharov 	 */
71ad9b5f77SVlad Zakharov 
72ad9b5f77SVlad Zakharov 	switch (priv->timer_id) {
73ad9b5f77SVlad Zakharov 	case 0:
74ad9b5f77SVlad Zakharov 		/* Disable timer if CPU is halted */
75ad9b5f77SVlad Zakharov 		write_aux_reg(ARC_AUX_TIMER0_CTRL, NH_MODE);
76ad9b5f77SVlad Zakharov 		/* Set max value for counter/timer */
77ad9b5f77SVlad Zakharov 		write_aux_reg(ARC_AUX_TIMER0_LIMIT, 0xffffffff);
78ad9b5f77SVlad Zakharov 		/* Set initial count value and restart counter/timer */
79ad9b5f77SVlad Zakharov 		write_aux_reg(ARC_AUX_TIMER0_CNT, 0);
80ad9b5f77SVlad Zakharov 		break;
81ad9b5f77SVlad Zakharov 	case 1:
82ad9b5f77SVlad Zakharov 		/* Disable timer if CPU is halted */
83ad9b5f77SVlad Zakharov 		write_aux_reg(ARC_AUX_TIMER1_CTRL, NH_MODE);
84ad9b5f77SVlad Zakharov 		/* Set max value for counter/timer */
85ad9b5f77SVlad Zakharov 		write_aux_reg(ARC_AUX_TIMER1_LIMIT, 0xffffffff);
86ad9b5f77SVlad Zakharov 		/* Set initial count value and restart counter/timer */
87ad9b5f77SVlad Zakharov 		write_aux_reg(ARC_AUX_TIMER1_CNT, 0);
88ad9b5f77SVlad Zakharov 		break;
89ad9b5f77SVlad Zakharov 	}
90ad9b5f77SVlad Zakharov 
91ad9b5f77SVlad Zakharov 	return 0;
92ad9b5f77SVlad Zakharov }
93ad9b5f77SVlad Zakharov 
94ad9b5f77SVlad Zakharov 
95ad9b5f77SVlad Zakharov static const struct timer_ops arc_timer_ops = {
96ad9b5f77SVlad Zakharov 	.get_count = arc_timer_get_count,
97ad9b5f77SVlad Zakharov };
98ad9b5f77SVlad Zakharov 
99ad9b5f77SVlad Zakharov static const struct udevice_id arc_timer_ids[] = {
100ad9b5f77SVlad Zakharov 	{ .compatible = "snps,arc-timer" },
101ad9b5f77SVlad Zakharov 	{}
102ad9b5f77SVlad Zakharov };
103ad9b5f77SVlad Zakharov 
104ad9b5f77SVlad Zakharov U_BOOT_DRIVER(arc_timer) = {
105ad9b5f77SVlad Zakharov 	.name	= "arc_timer",
106ad9b5f77SVlad Zakharov 	.id	= UCLASS_TIMER,
107ad9b5f77SVlad Zakharov 	.of_match = arc_timer_ids,
108ad9b5f77SVlad Zakharov 	.probe = arc_timer_probe,
109ad9b5f77SVlad Zakharov 	.ops	= &arc_timer_ops,
110ad9b5f77SVlad Zakharov 	.priv_auto_alloc_size = sizeof(struct arc_timer_priv),
111ad9b5f77SVlad Zakharov };
112