1/*
2 * Copyright 2014, General Dynamics C4 Systems
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 */
6
7#include <plat/machine/hardware.h>
8#include <arch/user_access.h>
9#include <mode/machine/debug.h>
10
11#define PMUSERENR_ENABLE BIT(0)
12
13#define CNTKCTL_PL0PCTEN BIT(0)
14#define CNTKCTL_PL0VCTEN BIT(1)
15#define CNTKCTL_PL0VTEN  BIT(8)
16#define CNTKCTL_PL0PTEN  BIT(9)
17
18#define ID_DFR0_PMU_MASK (0xful << 28)
19#define ID_DFR0_PMU_NONE (0xful << 28)
20
21#define ID_PFR1_GENERIC_TIMER BIT(16)
22
23
24
25static void check_export_pmu(void)
26{
27#if defined CONFIG_EXPORT_PMU_USER || defined CONFIG_ENABLE_BENCHMARKS
28    /* Export performance counters */
29    uint32_t v;
30    MRC(PMUSERENR, v);
31    v |= PMUSERENR_ENABLE;
32    MCR(PMUSERENR, v);
33
34    /* enable user-level pmu event counter if we're in secure mode */
35    if (!(readDscrCp() & DBGDSCR_SECURE_MODE_DISABLED)) {
36        MRC(DBGSDER, v);
37        v |= DBGSDER_ENABLE_SECURE_USER_NON_INVASIVE_DEBUG;
38        MCR(DBGSDER, v);
39    }
40#endif
41}
42
43
44static void check_export_arch_timer(void)
45{
46    uint32_t v = 0;
47#ifdef CONFIG_EXPORT_PCNT_USER
48    v |= CNTKCTL_PL0PCTEN;
49#endif
50#ifdef CONFIG_EXPORT_VCNT_USER
51    v |= CNTKCTL_PL0VCTEN;
52#endif
53    MCR(CNTKCTL, v);
54}
55
56
57void armv_init_user_access(void)
58{
59    uint32_t v;
60    /* Performance Monitoring Unit */
61    MRC(ID_DFR0, v);
62    if ((v & ID_DFR0_PMU_MASK) != ID_DFR0_PMU_NONE) {
63        check_export_pmu();
64    }
65    /* Arch timers */
66    MRC(ID_PFR1, v);
67    if (v & ID_PFR1_GENERIC_TIMER) {
68        check_export_arch_timer();
69    }
70}
71
72