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