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