3483d139a4ac24d6cd2182e7c661e54637150fa8
[cascardo/linux.git] / drivers / hwtracing / coresight / coresight-tmc-etr.c
1 /*
2  * Copyright(C) 2016 Linaro Limited. All rights reserved.
3  * Author: Mathieu Poirier <mathieu.poirier@linaro.org>
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 as published by
7  * the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12  * more details.
13  *
14  * You should have received a copy of the GNU General Public License along with
15  * this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 #include <linux/coresight.h>
19 #include "coresight-priv.h"
20 #include "coresight-tmc.h"
21
22 void tmc_etr_enable_hw(struct tmc_drvdata *drvdata)
23 {
24         u32 axictl;
25
26         /* Zero out the memory to help with debug */
27         memset(drvdata->vaddr, 0, drvdata->size);
28
29         CS_UNLOCK(drvdata->base);
30
31         /* Wait for TMCSReady bit to be set */
32         tmc_wait_for_tmcready(drvdata);
33
34         writel_relaxed(drvdata->size / 4, drvdata->base + TMC_RSZ);
35         writel_relaxed(TMC_MODE_CIRCULAR_BUFFER, drvdata->base + TMC_MODE);
36
37         axictl = readl_relaxed(drvdata->base + TMC_AXICTL);
38         axictl |= TMC_AXICTL_WR_BURST_16;
39         writel_relaxed(axictl, drvdata->base + TMC_AXICTL);
40         axictl &= ~TMC_AXICTL_SCT_GAT_MODE;
41         writel_relaxed(axictl, drvdata->base + TMC_AXICTL);
42         axictl = (axictl &
43                   ~(TMC_AXICTL_PROT_CTL_B0 | TMC_AXICTL_PROT_CTL_B1)) |
44                   TMC_AXICTL_PROT_CTL_B1;
45         writel_relaxed(axictl, drvdata->base + TMC_AXICTL);
46
47         writel_relaxed(drvdata->paddr, drvdata->base + TMC_DBALO);
48         writel_relaxed(0x0, drvdata->base + TMC_DBAHI);
49         writel_relaxed(TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI |
50                        TMC_FFCR_FON_FLIN | TMC_FFCR_FON_TRIG_EVT |
51                        TMC_FFCR_TRIGON_TRIGIN,
52                        drvdata->base + TMC_FFCR);
53         writel_relaxed(drvdata->trigger_cntr, drvdata->base + TMC_TRG);
54         tmc_enable_hw(drvdata);
55
56         CS_LOCK(drvdata->base);
57 }
58
59 static void tmc_etr_dump_hw(struct tmc_drvdata *drvdata)
60 {
61         u32 rwp, val;
62
63         rwp = readl_relaxed(drvdata->base + TMC_RWP);
64         val = readl_relaxed(drvdata->base + TMC_STS);
65
66         /* How much memory do we still have */
67         if (val & BIT(0))
68                 drvdata->buf = drvdata->vaddr + rwp - drvdata->paddr;
69         else
70                 drvdata->buf = drvdata->vaddr;
71 }
72
73 static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
74 {
75         CS_UNLOCK(drvdata->base);
76
77         tmc_flush_and_stop(drvdata);
78         tmc_etr_dump_hw(drvdata);
79         tmc_disable_hw(drvdata);
80
81         CS_LOCK(drvdata->base);
82 }
83
84 static int tmc_enable_etr_sink(struct coresight_device *csdev, u32 mode)
85 {
86         unsigned long flags;
87         struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
88
89         spin_lock_irqsave(&drvdata->spinlock, flags);
90         if (drvdata->reading) {
91                 spin_unlock_irqrestore(&drvdata->spinlock, flags);
92                 return -EBUSY;
93         }
94
95         tmc_etr_enable_hw(drvdata);
96         drvdata->enable = true;
97         spin_unlock_irqrestore(&drvdata->spinlock, flags);
98
99         dev_info(drvdata->dev, "TMC-ETR enabled\n");
100         return 0;
101 }
102
103 static void tmc_disable_etr_sink(struct coresight_device *csdev)
104 {
105         unsigned long flags;
106         struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
107
108         spin_lock_irqsave(&drvdata->spinlock, flags);
109         if (drvdata->reading) {
110                 spin_unlock_irqrestore(&drvdata->spinlock, flags);
111                 return;
112         }
113
114         tmc_etr_disable_hw(drvdata);
115         drvdata->enable = false;
116         spin_unlock_irqrestore(&drvdata->spinlock, flags);
117
118         dev_info(drvdata->dev, "TMC-ETR disabled\n");
119 }
120
121 static const struct coresight_ops_sink tmc_etr_sink_ops = {
122         .enable         = tmc_enable_etr_sink,
123         .disable        = tmc_disable_etr_sink,
124 };
125
126 const struct coresight_ops tmc_etr_cs_ops = {
127         .sink_ops       = &tmc_etr_sink_ops,
128 };
129
130 int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
131 {
132         unsigned long flags;
133
134         /* config types are set a boot time and never change */
135         if (WARN_ON_ONCE(drvdata->config_type != TMC_CONFIG_TYPE_ETR))
136                 return -EINVAL;
137
138         spin_lock_irqsave(&drvdata->spinlock, flags);
139
140         /* Disable the TMC if need be */
141         if (drvdata->enable)
142                 tmc_etr_disable_hw(drvdata);
143
144         drvdata->reading = true;
145         spin_unlock_irqrestore(&drvdata->spinlock, flags);
146
147         return 0;
148 }
149
150 int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata)
151 {
152         unsigned long flags;
153
154         /* config types are set a boot time and never change */
155         if (WARN_ON_ONCE(drvdata->config_type != TMC_CONFIG_TYPE_ETR))
156                 return -EINVAL;
157
158         spin_lock_irqsave(&drvdata->spinlock, flags);
159
160         /* RE-enable the TMC if need be */
161         if (drvdata->enable)
162                 tmc_etr_enable_hw(drvdata);
163
164         drvdata->reading = false;
165         spin_unlock_irqrestore(&drvdata->spinlock, flags);
166
167         return 0;
168 }