1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2016 Synopsys, Inc. All rights reserved.
4  */
5 
6 #include <dm.h>
7 #include <errno.h>
8 #include <timer.h>
9 #include <asm/arcregs.h>
10 #include <asm/global_data.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)29 static u64 arc_timer_get_count(struct udevice *dev)
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 	return timer_conv_64(val);
43 }
44 
arc_timer_probe(struct udevice * dev)45 static int arc_timer_probe(struct udevice *dev)
46 {
47 	int id;
48 	struct arc_timer_priv *priv = dev_get_priv(dev);
49 
50 	/* Get registers offset and size */
51 	id = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "reg", -1);
52 	if (id < 0)
53 		return -EINVAL;
54 
55 	if (id > 1)
56 		return -ENXIO;
57 
58 	priv->timer_id = (uint)id;
59 
60 	/*
61 	 * In ARC core there're special registers (Auxiliary or AUX) in its
62 	 * separate memory space that are used for accessing some hardware
63 	 * features of the core. They are not mapped in normal memory space
64 	 * and also always have the same location regardless core configuration.
65 	 * Thus to simplify understanding of the programming model we chose to
66 	 * access AUX regs of Timer0 and Timer1 separately instead of using
67 	 * offsets from some base address.
68 	 */
69 
70 	switch (priv->timer_id) {
71 	case 0:
72 		/* Disable timer if CPU is halted */
73 		write_aux_reg(ARC_AUX_TIMER0_CTRL, NH_MODE);
74 		/* Set max value for counter/timer */
75 		write_aux_reg(ARC_AUX_TIMER0_LIMIT, 0xffffffff);
76 		/* Set initial count value and restart counter/timer */
77 		write_aux_reg(ARC_AUX_TIMER0_CNT, 0);
78 		break;
79 	case 1:
80 		/* Disable timer if CPU is halted */
81 		write_aux_reg(ARC_AUX_TIMER1_CTRL, NH_MODE);
82 		/* Set max value for counter/timer */
83 		write_aux_reg(ARC_AUX_TIMER1_LIMIT, 0xffffffff);
84 		/* Set initial count value and restart counter/timer */
85 		write_aux_reg(ARC_AUX_TIMER1_CNT, 0);
86 		break;
87 	}
88 
89 	return 0;
90 }
91 
92 static const struct timer_ops arc_timer_ops = {
93 	.get_count = arc_timer_get_count,
94 };
95 
96 static const struct udevice_id arc_timer_ids[] = {
97 	{ .compatible = "snps,arc-timer" },
98 	{}
99 };
100 
101 U_BOOT_DRIVER(arc_timer) = {
102 	.name	= "arc_timer",
103 	.id	= UCLASS_TIMER,
104 	.of_match = arc_timer_ids,
105 	.probe = arc_timer_probe,
106 	.ops	= &arc_timer_ops,
107 	.priv_auto	= sizeof(struct arc_timer_priv),
108 };
109