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