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