diff options
author | Mathieu Poirier <mathieu.poirier@linaro.org> | 2016-05-03 13:33:50 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2016-05-03 17:59:30 -0400 |
commit | 6c6ed1e244c0530fb76a8b52024f199f398ef100 (patch) | |
tree | 8878b571db210fb49f02668e05b3f65062d3ccd8 /drivers/hwtracing | |
parent | a8ab4268e0db93c564ee6ccb770bb3d53af24be9 (diff) |
coresight: tmc: splitting driver in ETB/ETF and ETR components
The TMC block can operate in 3 modes (ETB, ETF and ETR) and accessed
via two interfaces (sysFS and Perf). That makes 6 mode to cover, which
is way too much coupling for a single file.
This patch splits the original TMC driver in 2 halves, one for ETB/ETF
and another one for ETR mode. A common core is kept for functionality
common to all 3 modes.
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/hwtracing')
-rw-r--r-- | drivers/hwtracing/coresight/Makefile | 4 | ||||
-rw-r--r-- | drivers/hwtracing/coresight/coresight-tmc-etf.c | 204 | ||||
-rw-r--r-- | drivers/hwtracing/coresight/coresight-tmc-etr.c | 128 | ||||
-rw-r--r-- | drivers/hwtracing/coresight/coresight-tmc.c | 264 | ||||
-rw-r--r-- | drivers/hwtracing/coresight/coresight-tmc.h | 18 |
5 files changed, 357 insertions, 261 deletions
diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index c6f84b57f52a..af480d9c1441 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile | |||
@@ -3,7 +3,9 @@ | |||
3 | # | 3 | # |
4 | obj-$(CONFIG_CORESIGHT) += coresight.o coresight-etm-perf.o | 4 | obj-$(CONFIG_CORESIGHT) += coresight.o coresight-etm-perf.o |
5 | obj-$(CONFIG_OF) += of_coresight.o | 5 | obj-$(CONFIG_OF) += of_coresight.o |
6 | obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o | 6 | obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o \ |
7 | coresight-tmc-etf.o \ | ||
8 | coresight-tmc-etr.o | ||
7 | obj-$(CONFIG_CORESIGHT_SINK_TPIU) += coresight-tpiu.o | 9 | obj-$(CONFIG_CORESIGHT_SINK_TPIU) += coresight-tpiu.o |
8 | obj-$(CONFIG_CORESIGHT_SINK_ETBV10) += coresight-etb10.o | 10 | obj-$(CONFIG_CORESIGHT_SINK_ETBV10) += coresight-etb10.o |
9 | obj-$(CONFIG_CORESIGHT_LINKS_AND_SINKS) += coresight-funnel.o \ | 11 | obj-$(CONFIG_CORESIGHT_LINKS_AND_SINKS) += coresight-funnel.o \ |
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c new file mode 100644 index 000000000000..467d19221f7b --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c | |||
@@ -0,0 +1,204 @@ | |||
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_etb_enable_hw(struct tmc_drvdata *drvdata) | ||
23 | { | ||
24 | /* Zero out the memory to help with debug */ | ||
25 | memset(drvdata->buf, 0, drvdata->size); | ||
26 | |||
27 | CS_UNLOCK(drvdata->base); | ||
28 | |||
29 | /* Wait for TMCSReady bit to be set */ | ||
30 | tmc_wait_for_tmcready(drvdata); | ||
31 | |||
32 | writel_relaxed(TMC_MODE_CIRCULAR_BUFFER, drvdata->base + TMC_MODE); | ||
33 | writel_relaxed(TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI | | ||
34 | TMC_FFCR_FON_FLIN | TMC_FFCR_FON_TRIG_EVT | | ||
35 | TMC_FFCR_TRIGON_TRIGIN, | ||
36 | drvdata->base + TMC_FFCR); | ||
37 | |||
38 | writel_relaxed(drvdata->trigger_cntr, drvdata->base + TMC_TRG); | ||
39 | tmc_enable_hw(drvdata); | ||
40 | |||
41 | CS_LOCK(drvdata->base); | ||
42 | } | ||
43 | |||
44 | static void tmc_etb_dump_hw(struct tmc_drvdata *drvdata) | ||
45 | { | ||
46 | enum tmc_mem_intf_width memwidth; | ||
47 | u8 memwords; | ||
48 | char *bufp; | ||
49 | u32 read_data; | ||
50 | int i; | ||
51 | |||
52 | memwidth = BMVAL(readl_relaxed(drvdata->base + CORESIGHT_DEVID), 8, 10); | ||
53 | if (memwidth == TMC_MEM_INTF_WIDTH_32BITS) | ||
54 | memwords = 1; | ||
55 | else if (memwidth == TMC_MEM_INTF_WIDTH_64BITS) | ||
56 | memwords = 2; | ||
57 | else if (memwidth == TMC_MEM_INTF_WIDTH_128BITS) | ||
58 | memwords = 4; | ||
59 | else | ||
60 | memwords = 8; | ||
61 | |||
62 | bufp = drvdata->buf; | ||
63 | while (1) { | ||
64 | for (i = 0; i < memwords; i++) { | ||
65 | read_data = readl_relaxed(drvdata->base + TMC_RRD); | ||
66 | if (read_data == 0xFFFFFFFF) | ||
67 | return; | ||
68 | memcpy(bufp, &read_data, 4); | ||
69 | bufp += 4; | ||
70 | } | ||
71 | } | ||
72 | } | ||
73 | |||
74 | void tmc_etb_disable_hw(struct tmc_drvdata *drvdata) | ||
75 | { | ||
76 | CS_UNLOCK(drvdata->base); | ||
77 | |||
78 | tmc_flush_and_stop(drvdata); | ||
79 | tmc_etb_dump_hw(drvdata); | ||
80 | tmc_disable_hw(drvdata); | ||
81 | |||
82 | CS_LOCK(drvdata->base); | ||
83 | } | ||
84 | |||
85 | static void tmc_etf_enable_hw(struct tmc_drvdata *drvdata) | ||
86 | { | ||
87 | CS_UNLOCK(drvdata->base); | ||
88 | |||
89 | /* Wait for TMCSReady bit to be set */ | ||
90 | tmc_wait_for_tmcready(drvdata); | ||
91 | |||
92 | writel_relaxed(TMC_MODE_HARDWARE_FIFO, drvdata->base + TMC_MODE); | ||
93 | writel_relaxed(TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI, | ||
94 | drvdata->base + TMC_FFCR); | ||
95 | writel_relaxed(0x0, drvdata->base + TMC_BUFWM); | ||
96 | tmc_enable_hw(drvdata); | ||
97 | |||
98 | CS_LOCK(drvdata->base); | ||
99 | } | ||
100 | |||
101 | static void tmc_etf_disable_hw(struct tmc_drvdata *drvdata) | ||
102 | { | ||
103 | CS_UNLOCK(drvdata->base); | ||
104 | |||
105 | tmc_flush_and_stop(drvdata); | ||
106 | tmc_disable_hw(drvdata); | ||
107 | |||
108 | CS_LOCK(drvdata->base); | ||
109 | } | ||
110 | |||
111 | static int tmc_enable_etf_sink(struct coresight_device *csdev, u32 mode) | ||
112 | { | ||
113 | unsigned long flags; | ||
114 | struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | ||
115 | |||
116 | spin_lock_irqsave(&drvdata->spinlock, flags); | ||
117 | if (drvdata->reading) { | ||
118 | spin_unlock_irqrestore(&drvdata->spinlock, flags); | ||
119 | return -EBUSY; | ||
120 | } | ||
121 | |||
122 | tmc_etb_enable_hw(drvdata); | ||
123 | drvdata->enable = true; | ||
124 | spin_unlock_irqrestore(&drvdata->spinlock, flags); | ||
125 | |||
126 | dev_info(drvdata->dev, "TMC-ETB/ETF enabled\n"); | ||
127 | return 0; | ||
128 | } | ||
129 | |||
130 | static void tmc_disable_etf_sink(struct coresight_device *csdev) | ||
131 | { | ||
132 | unsigned long flags; | ||
133 | struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | ||
134 | |||
135 | spin_lock_irqsave(&drvdata->spinlock, flags); | ||
136 | if (drvdata->reading) { | ||
137 | spin_unlock_irqrestore(&drvdata->spinlock, flags); | ||
138 | return; | ||
139 | } | ||
140 | |||
141 | tmc_etb_disable_hw(drvdata); | ||
142 | drvdata->enable = false; | ||
143 | spin_unlock_irqrestore(&drvdata->spinlock, flags); | ||
144 | |||
145 | dev_info(drvdata->dev, "TMC-ETB/ETF disabled\n"); | ||
146 | } | ||
147 | |||
148 | static int tmc_enable_etf_link(struct coresight_device *csdev, | ||
149 | int inport, int outport) | ||
150 | { | ||
151 | unsigned long flags; | ||
152 | struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | ||
153 | |||
154 | spin_lock_irqsave(&drvdata->spinlock, flags); | ||
155 | if (drvdata->reading) { | ||
156 | spin_unlock_irqrestore(&drvdata->spinlock, flags); | ||
157 | return -EBUSY; | ||
158 | } | ||
159 | |||
160 | tmc_etf_enable_hw(drvdata); | ||
161 | drvdata->enable = true; | ||
162 | spin_unlock_irqrestore(&drvdata->spinlock, flags); | ||
163 | |||
164 | dev_info(drvdata->dev, "TMC-ETF enabled\n"); | ||
165 | return 0; | ||
166 | } | ||
167 | |||
168 | static void tmc_disable_etf_link(struct coresight_device *csdev, | ||
169 | int inport, int outport) | ||
170 | { | ||
171 | unsigned long flags; | ||
172 | struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | ||
173 | |||
174 | spin_lock_irqsave(&drvdata->spinlock, flags); | ||
175 | if (drvdata->reading) { | ||
176 | spin_unlock_irqrestore(&drvdata->spinlock, flags); | ||
177 | return; | ||
178 | } | ||
179 | |||
180 | tmc_etf_disable_hw(drvdata); | ||
181 | drvdata->enable = false; | ||
182 | spin_unlock_irqrestore(&drvdata->spinlock, flags); | ||
183 | |||
184 | dev_info(drvdata->dev, "TMC disabled\n"); | ||
185 | } | ||
186 | |||
187 | static const struct coresight_ops_sink tmc_etf_sink_ops = { | ||
188 | .enable = tmc_enable_etf_sink, | ||
189 | .disable = tmc_disable_etf_sink, | ||
190 | }; | ||
191 | |||
192 | static const struct coresight_ops_link tmc_etf_link_ops = { | ||
193 | .enable = tmc_enable_etf_link, | ||
194 | .disable = tmc_disable_etf_link, | ||
195 | }; | ||
196 | |||
197 | const struct coresight_ops tmc_etb_cs_ops = { | ||
198 | .sink_ops = &tmc_etf_sink_ops, | ||
199 | }; | ||
200 | |||
201 | const struct coresight_ops tmc_etf_cs_ops = { | ||
202 | .sink_ops = &tmc_etf_sink_ops, | ||
203 | .link_ops = &tmc_etf_link_ops, | ||
204 | }; | ||
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c new file mode 100644 index 000000000000..5d9333ec49ae --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c | |||
@@ -0,0 +1,128 @@ | |||
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 | 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 | }; | ||
diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c index 07e2809d832b..8d7f6d54c9b0 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.c +++ b/drivers/hwtracing/coresight/coresight-tmc.c | |||
@@ -32,7 +32,7 @@ | |||
32 | #include "coresight-priv.h" | 32 | #include "coresight-priv.h" |
33 | #include "coresight-tmc.h" | 33 | #include "coresight-tmc.h" |
34 | 34 | ||
35 | static void tmc_wait_for_tmcready(struct tmc_drvdata *drvdata) | 35 | void tmc_wait_for_tmcready(struct tmc_drvdata *drvdata) |
36 | { | 36 | { |
37 | /* Ensure formatter, unformatter and hardware fifo are empty */ | 37 | /* Ensure formatter, unformatter and hardware fifo are empty */ |
38 | if (coresight_timeout(drvdata->base, | 38 | if (coresight_timeout(drvdata->base, |
@@ -43,7 +43,7 @@ static void tmc_wait_for_tmcready(struct tmc_drvdata *drvdata) | |||
43 | } | 43 | } |
44 | } | 44 | } |
45 | 45 | ||
46 | static void tmc_flush_and_stop(struct tmc_drvdata *drvdata) | 46 | void tmc_flush_and_stop(struct tmc_drvdata *drvdata) |
47 | { | 47 | { |
48 | u32 ffcr; | 48 | u32 ffcr; |
49 | 49 | ||
@@ -63,272 +63,16 @@ static void tmc_flush_and_stop(struct tmc_drvdata *drvdata) | |||
63 | tmc_wait_for_tmcready(drvdata); | 63 | tmc_wait_for_tmcready(drvdata); |
64 | } | 64 | } |
65 | 65 | ||
66 | static void tmc_enable_hw(struct tmc_drvdata *drvdata) | 66 | void tmc_enable_hw(struct tmc_drvdata *drvdata) |
67 | { | 67 | { |
68 | writel_relaxed(TMC_CTL_CAPT_EN, drvdata->base + TMC_CTL); | 68 | writel_relaxed(TMC_CTL_CAPT_EN, drvdata->base + TMC_CTL); |
69 | } | 69 | } |
70 | 70 | ||
71 | static void tmc_disable_hw(struct tmc_drvdata *drvdata) | 71 | void tmc_disable_hw(struct tmc_drvdata *drvdata) |
72 | { | 72 | { |
73 | writel_relaxed(0x0, drvdata->base + TMC_CTL); | 73 | writel_relaxed(0x0, drvdata->base + TMC_CTL); |
74 | } | 74 | } |
75 | 75 | ||
76 | static void tmc_etb_enable_hw(struct tmc_drvdata *drvdata) | ||
77 | { | ||
78 | /* Zero out the memory to help with debug */ | ||
79 | memset(drvdata->buf, 0, drvdata->size); | ||
80 | |||
81 | CS_UNLOCK(drvdata->base); | ||
82 | |||
83 | /* Wait for TMCSReady bit to be set */ | ||
84 | tmc_wait_for_tmcready(drvdata); | ||
85 | |||
86 | writel_relaxed(TMC_MODE_CIRCULAR_BUFFER, drvdata->base + TMC_MODE); | ||
87 | writel_relaxed(TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI | | ||
88 | TMC_FFCR_FON_FLIN | TMC_FFCR_FON_TRIG_EVT | | ||
89 | TMC_FFCR_TRIGON_TRIGIN, | ||
90 | drvdata->base + TMC_FFCR); | ||
91 | |||
92 | writel_relaxed(drvdata->trigger_cntr, drvdata->base + TMC_TRG); | ||
93 | tmc_enable_hw(drvdata); | ||
94 | |||
95 | CS_LOCK(drvdata->base); | ||
96 | } | ||
97 | |||
98 | static void tmc_etr_enable_hw(struct tmc_drvdata *drvdata) | ||
99 | { | ||
100 | u32 axictl; | ||
101 | |||
102 | /* Zero out the memory to help with debug */ | ||
103 | memset(drvdata->vaddr, 0, drvdata->size); | ||
104 | |||
105 | CS_UNLOCK(drvdata->base); | ||
106 | |||
107 | /* Wait for TMCSReady bit to be set */ | ||
108 | tmc_wait_for_tmcready(drvdata); | ||
109 | |||
110 | writel_relaxed(drvdata->size / 4, drvdata->base + TMC_RSZ); | ||
111 | writel_relaxed(TMC_MODE_CIRCULAR_BUFFER, drvdata->base + TMC_MODE); | ||
112 | |||
113 | axictl = readl_relaxed(drvdata->base + TMC_AXICTL); | ||
114 | axictl |= TMC_AXICTL_WR_BURST_16; | ||
115 | writel_relaxed(axictl, drvdata->base + TMC_AXICTL); | ||
116 | axictl &= ~TMC_AXICTL_SCT_GAT_MODE; | ||
117 | writel_relaxed(axictl, drvdata->base + TMC_AXICTL); | ||
118 | axictl = (axictl & | ||
119 | ~(TMC_AXICTL_PROT_CTL_B0 | TMC_AXICTL_PROT_CTL_B1)) | | ||
120 | TMC_AXICTL_PROT_CTL_B1; | ||
121 | writel_relaxed(axictl, drvdata->base + TMC_AXICTL); | ||
122 | |||
123 | writel_relaxed(drvdata->paddr, drvdata->base + TMC_DBALO); | ||
124 | writel_relaxed(0x0, drvdata->base + TMC_DBAHI); | ||
125 | writel_relaxed(TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI | | ||
126 | TMC_FFCR_FON_FLIN | TMC_FFCR_FON_TRIG_EVT | | ||
127 | TMC_FFCR_TRIGON_TRIGIN, | ||
128 | drvdata->base + TMC_FFCR); | ||
129 | writel_relaxed(drvdata->trigger_cntr, drvdata->base + TMC_TRG); | ||
130 | tmc_enable_hw(drvdata); | ||
131 | |||
132 | CS_LOCK(drvdata->base); | ||
133 | } | ||
134 | |||
135 | static void tmc_etf_enable_hw(struct tmc_drvdata *drvdata) | ||
136 | { | ||
137 | CS_UNLOCK(drvdata->base); | ||
138 | |||
139 | /* Wait for TMCSReady bit to be set */ | ||
140 | tmc_wait_for_tmcready(drvdata); | ||
141 | |||
142 | writel_relaxed(TMC_MODE_HARDWARE_FIFO, drvdata->base + TMC_MODE); | ||
143 | writel_relaxed(TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI, | ||
144 | drvdata->base + TMC_FFCR); | ||
145 | writel_relaxed(0x0, drvdata->base + TMC_BUFWM); | ||
146 | tmc_enable_hw(drvdata); | ||
147 | |||
148 | CS_LOCK(drvdata->base); | ||
149 | } | ||
150 | |||
151 | static int tmc_enable(struct tmc_drvdata *drvdata, enum tmc_mode mode) | ||
152 | { | ||
153 | unsigned long flags; | ||
154 | |||
155 | spin_lock_irqsave(&drvdata->spinlock, flags); | ||
156 | if (drvdata->reading) { | ||
157 | spin_unlock_irqrestore(&drvdata->spinlock, flags); | ||
158 | return -EBUSY; | ||
159 | } | ||
160 | |||
161 | if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) { | ||
162 | tmc_etb_enable_hw(drvdata); | ||
163 | } else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) { | ||
164 | tmc_etr_enable_hw(drvdata); | ||
165 | } else { | ||
166 | if (mode == TMC_MODE_CIRCULAR_BUFFER) | ||
167 | tmc_etb_enable_hw(drvdata); | ||
168 | else | ||
169 | tmc_etf_enable_hw(drvdata); | ||
170 | } | ||
171 | drvdata->enable = true; | ||
172 | spin_unlock_irqrestore(&drvdata->spinlock, flags); | ||
173 | |||
174 | dev_info(drvdata->dev, "TMC enabled\n"); | ||
175 | return 0; | ||
176 | } | ||
177 | |||
178 | static int tmc_enable_sink(struct coresight_device *csdev, u32 mode) | ||
179 | { | ||
180 | struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | ||
181 | |||
182 | return tmc_enable(drvdata, TMC_MODE_CIRCULAR_BUFFER); | ||
183 | } | ||
184 | |||
185 | static int tmc_enable_link(struct coresight_device *csdev, int inport, | ||
186 | int outport) | ||
187 | { | ||
188 | struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | ||
189 | |||
190 | return tmc_enable(drvdata, TMC_MODE_HARDWARE_FIFO); | ||
191 | } | ||
192 | |||
193 | static void tmc_etb_dump_hw(struct tmc_drvdata *drvdata) | ||
194 | { | ||
195 | enum tmc_mem_intf_width memwidth; | ||
196 | u8 memwords; | ||
197 | char *bufp; | ||
198 | u32 read_data; | ||
199 | int i; | ||
200 | |||
201 | memwidth = BMVAL(readl_relaxed(drvdata->base + CORESIGHT_DEVID), 8, 10); | ||
202 | if (memwidth == TMC_MEM_INTF_WIDTH_32BITS) | ||
203 | memwords = 1; | ||
204 | else if (memwidth == TMC_MEM_INTF_WIDTH_64BITS) | ||
205 | memwords = 2; | ||
206 | else if (memwidth == TMC_MEM_INTF_WIDTH_128BITS) | ||
207 | memwords = 4; | ||
208 | else | ||
209 | memwords = 8; | ||
210 | |||
211 | bufp = drvdata->buf; | ||
212 | while (1) { | ||
213 | for (i = 0; i < memwords; i++) { | ||
214 | read_data = readl_relaxed(drvdata->base + TMC_RRD); | ||
215 | if (read_data == 0xFFFFFFFF) | ||
216 | return; | ||
217 | memcpy(bufp, &read_data, 4); | ||
218 | bufp += 4; | ||
219 | } | ||
220 | } | ||
221 | } | ||
222 | |||
223 | static void tmc_etb_disable_hw(struct tmc_drvdata *drvdata) | ||
224 | { | ||
225 | CS_UNLOCK(drvdata->base); | ||
226 | |||
227 | tmc_flush_and_stop(drvdata); | ||
228 | tmc_etb_dump_hw(drvdata); | ||
229 | tmc_disable_hw(drvdata); | ||
230 | |||
231 | CS_LOCK(drvdata->base); | ||
232 | } | ||
233 | |||
234 | static void tmc_etr_dump_hw(struct tmc_drvdata *drvdata) | ||
235 | { | ||
236 | u32 rwp, val; | ||
237 | |||
238 | rwp = readl_relaxed(drvdata->base + TMC_RWP); | ||
239 | val = readl_relaxed(drvdata->base + TMC_STS); | ||
240 | |||
241 | /* How much memory do we still have */ | ||
242 | if (val & BIT(0)) | ||
243 | drvdata->buf = drvdata->vaddr + rwp - drvdata->paddr; | ||
244 | else | ||
245 | drvdata->buf = drvdata->vaddr; | ||
246 | } | ||
247 | |||
248 | static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata) | ||
249 | { | ||
250 | CS_UNLOCK(drvdata->base); | ||
251 | |||
252 | tmc_flush_and_stop(drvdata); | ||
253 | tmc_etr_dump_hw(drvdata); | ||
254 | tmc_disable_hw(drvdata); | ||
255 | |||
256 | CS_LOCK(drvdata->base); | ||
257 | } | ||
258 | |||
259 | static void tmc_etf_disable_hw(struct tmc_drvdata *drvdata) | ||
260 | { | ||
261 | CS_UNLOCK(drvdata->base); | ||
262 | |||
263 | tmc_flush_and_stop(drvdata); | ||
264 | tmc_disable_hw(drvdata); | ||
265 | |||
266 | CS_LOCK(drvdata->base); | ||
267 | } | ||
268 | |||
269 | static void tmc_disable(struct tmc_drvdata *drvdata, enum tmc_mode mode) | ||
270 | { | ||
271 | unsigned long flags; | ||
272 | |||
273 | spin_lock_irqsave(&drvdata->spinlock, flags); | ||
274 | if (drvdata->reading) | ||
275 | goto out; | ||
276 | |||
277 | if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) { | ||
278 | tmc_etb_disable_hw(drvdata); | ||
279 | } else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) { | ||
280 | tmc_etr_disable_hw(drvdata); | ||
281 | } else { | ||
282 | if (mode == TMC_MODE_CIRCULAR_BUFFER) | ||
283 | tmc_etb_disable_hw(drvdata); | ||
284 | else | ||
285 | tmc_etf_disable_hw(drvdata); | ||
286 | } | ||
287 | out: | ||
288 | drvdata->enable = false; | ||
289 | spin_unlock_irqrestore(&drvdata->spinlock, flags); | ||
290 | |||
291 | dev_info(drvdata->dev, "TMC disabled\n"); | ||
292 | } | ||
293 | |||
294 | static void tmc_disable_sink(struct coresight_device *csdev) | ||
295 | { | ||
296 | struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | ||
297 | |||
298 | tmc_disable(drvdata, TMC_MODE_CIRCULAR_BUFFER); | ||
299 | } | ||
300 | |||
301 | static void tmc_disable_link(struct coresight_device *csdev, int inport, | ||
302 | int outport) | ||
303 | { | ||
304 | struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | ||
305 | |||
306 | tmc_disable(drvdata, TMC_MODE_HARDWARE_FIFO); | ||
307 | } | ||
308 | |||
309 | static const struct coresight_ops_sink tmc_sink_ops = { | ||
310 | .enable = tmc_enable_sink, | ||
311 | .disable = tmc_disable_sink, | ||
312 | }; | ||
313 | |||
314 | static const struct coresight_ops_link tmc_link_ops = { | ||
315 | .enable = tmc_enable_link, | ||
316 | .disable = tmc_disable_link, | ||
317 | }; | ||
318 | |||
319 | static const struct coresight_ops tmc_etb_cs_ops = { | ||
320 | .sink_ops = &tmc_sink_ops, | ||
321 | }; | ||
322 | |||
323 | static const struct coresight_ops tmc_etr_cs_ops = { | ||
324 | .sink_ops = &tmc_sink_ops, | ||
325 | }; | ||
326 | |||
327 | static const struct coresight_ops tmc_etf_cs_ops = { | ||
328 | .sink_ops = &tmc_sink_ops, | ||
329 | .link_ops = &tmc_link_ops, | ||
330 | }; | ||
331 | |||
332 | static int tmc_read_prepare(struct tmc_drvdata *drvdata) | 76 | static int tmc_read_prepare(struct tmc_drvdata *drvdata) |
333 | { | 77 | { |
334 | int ret = 0; | 78 | int ret = 0; |
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h index 5a60830c8db5..b3017e115c4d 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.h +++ b/drivers/hwtracing/coresight/coresight-tmc.h | |||
@@ -18,6 +18,8 @@ | |||
18 | #ifndef _CORESIGHT_TMC_H | 18 | #ifndef _CORESIGHT_TMC_H |
19 | #define _CORESIGHT_TMC_H | 19 | #define _CORESIGHT_TMC_H |
20 | 20 | ||
21 | #include <linux/miscdevice.h> | ||
22 | |||
21 | #define TMC_RSZ 0x004 | 23 | #define TMC_RSZ 0x004 |
22 | #define TMC_STS 0x00c | 24 | #define TMC_STS 0x00c |
23 | #define TMC_RRD 0x010 | 25 | #define TMC_RRD 0x010 |
@@ -118,4 +120,20 @@ struct tmc_drvdata { | |||
118 | u32 trigger_cntr; | 120 | u32 trigger_cntr; |
119 | }; | 121 | }; |
120 | 122 | ||
123 | /* Generic functions */ | ||
124 | void tmc_wait_for_tmcready(struct tmc_drvdata *drvdata); | ||
125 | void tmc_flush_and_stop(struct tmc_drvdata *drvdata); | ||
126 | void tmc_enable_hw(struct tmc_drvdata *drvdata); | ||
127 | void tmc_disable_hw(struct tmc_drvdata *drvdata); | ||
128 | |||
129 | /* ETB/ETF functions */ | ||
130 | void tmc_etb_enable_hw(struct tmc_drvdata *drvdata); | ||
131 | void tmc_etb_disable_hw(struct tmc_drvdata *drvdata); | ||
132 | extern const struct coresight_ops tmc_etb_cs_ops; | ||
133 | extern const struct coresight_ops tmc_etf_cs_ops; | ||
134 | |||
135 | /* ETR functions */ | ||
136 | void tmc_etr_enable_hw(struct tmc_drvdata *drvdata); | ||
137 | void tmc_etr_disable_hw(struct tmc_drvdata *drvdata); | ||
138 | extern const struct coresight_ops tmc_etr_cs_ops; | ||
121 | #endif | 139 | #endif |