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