150352fa7SAlexander Shishkin // SPDX-License-Identifier: GPL-2.0
2b27a6a3fSAlexander Shishkin /*
3b27a6a3fSAlexander Shishkin * Intel(R) Trace Hub Global Trace Hub
4b27a6a3fSAlexander Shishkin *
5b27a6a3fSAlexander Shishkin * Copyright (C) 2014-2015 Intel Corporation.
6b27a6a3fSAlexander Shishkin */
7b27a6a3fSAlexander Shishkin
8b27a6a3fSAlexander Shishkin #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
9b27a6a3fSAlexander Shishkin
10b27a6a3fSAlexander Shishkin #include <linux/types.h>
11b27a6a3fSAlexander Shishkin #include <linux/module.h>
12b27a6a3fSAlexander Shishkin #include <linux/device.h>
13b27a6a3fSAlexander Shishkin #include <linux/io.h>
14b27a6a3fSAlexander Shishkin #include <linux/mm.h>
15b27a6a3fSAlexander Shishkin #include <linux/slab.h>
16b27a6a3fSAlexander Shishkin #include <linux/bitmap.h>
17142dfeb2SAlexander Shishkin #include <linux/pm_runtime.h>
18b27a6a3fSAlexander Shishkin
19b27a6a3fSAlexander Shishkin #include "intel_th.h"
20b27a6a3fSAlexander Shishkin #include "gth.h"
21b27a6a3fSAlexander Shishkin
22b27a6a3fSAlexander Shishkin struct gth_device;
23b27a6a3fSAlexander Shishkin
24b27a6a3fSAlexander Shishkin /**
25b27a6a3fSAlexander Shishkin * struct gth_output - GTH view on an output port
26b27a6a3fSAlexander Shishkin * @gth: backlink to the GTH device
27b27a6a3fSAlexander Shishkin * @output: link to output device's output descriptor
28b27a6a3fSAlexander Shishkin * @index: output port number
29b27a6a3fSAlexander Shishkin * @port_type: one of GTH_* port type values
30b27a6a3fSAlexander Shishkin * @master: bitmap of masters configured for this output
31b27a6a3fSAlexander Shishkin */
32b27a6a3fSAlexander Shishkin struct gth_output {
33b27a6a3fSAlexander Shishkin struct gth_device *gth;
34b27a6a3fSAlexander Shishkin struct intel_th_output *output;
35b27a6a3fSAlexander Shishkin unsigned int index;
36b27a6a3fSAlexander Shishkin unsigned int port_type;
37b27a6a3fSAlexander Shishkin DECLARE_BITMAP(master, TH_CONFIGURABLE_MASTERS + 1);
38b27a6a3fSAlexander Shishkin };
39b27a6a3fSAlexander Shishkin
40b27a6a3fSAlexander Shishkin /**
41b27a6a3fSAlexander Shishkin * struct gth_device - GTH device
42b27a6a3fSAlexander Shishkin * @dev: driver core's device
43b27a6a3fSAlexander Shishkin * @base: register window base address
44b27a6a3fSAlexander Shishkin * @output_group: attributes describing output ports
45b27a6a3fSAlexander Shishkin * @master_group: attributes describing master assignments
46b27a6a3fSAlexander Shishkin * @output: output ports
47b27a6a3fSAlexander Shishkin * @master: master/output port assignments
48b27a6a3fSAlexander Shishkin * @gth_lock: serializes accesses to GTH bits
49b27a6a3fSAlexander Shishkin */
50b27a6a3fSAlexander Shishkin struct gth_device {
51b27a6a3fSAlexander Shishkin struct device *dev;
52b27a6a3fSAlexander Shishkin void __iomem *base;
53b27a6a3fSAlexander Shishkin
54b27a6a3fSAlexander Shishkin struct attribute_group output_group;
55b27a6a3fSAlexander Shishkin struct attribute_group master_group;
56b27a6a3fSAlexander Shishkin struct gth_output output[TH_POSSIBLE_OUTPUTS];
57b27a6a3fSAlexander Shishkin signed char master[TH_CONFIGURABLE_MASTERS + 1];
58b27a6a3fSAlexander Shishkin spinlock_t gth_lock;
59b27a6a3fSAlexander Shishkin };
60b27a6a3fSAlexander Shishkin
gth_output_set(struct gth_device * gth,int port,unsigned int config)61b27a6a3fSAlexander Shishkin static void gth_output_set(struct gth_device *gth, int port,
62b27a6a3fSAlexander Shishkin unsigned int config)
63b27a6a3fSAlexander Shishkin {
64b27a6a3fSAlexander Shishkin unsigned long reg = port & 4 ? REG_GTH_GTHOPT1 : REG_GTH_GTHOPT0;
65b27a6a3fSAlexander Shishkin u32 val;
66b27a6a3fSAlexander Shishkin int shift = (port & 3) * 8;
67b27a6a3fSAlexander Shishkin
68b27a6a3fSAlexander Shishkin val = ioread32(gth->base + reg);
69b27a6a3fSAlexander Shishkin val &= ~(0xff << shift);
70b27a6a3fSAlexander Shishkin val |= config << shift;
71b27a6a3fSAlexander Shishkin iowrite32(val, gth->base + reg);
72b27a6a3fSAlexander Shishkin }
73b27a6a3fSAlexander Shishkin
gth_output_get(struct gth_device * gth,int port)74b27a6a3fSAlexander Shishkin static unsigned int gth_output_get(struct gth_device *gth, int port)
75b27a6a3fSAlexander Shishkin {
76b27a6a3fSAlexander Shishkin unsigned long reg = port & 4 ? REG_GTH_GTHOPT1 : REG_GTH_GTHOPT0;
77b27a6a3fSAlexander Shishkin u32 val;
78b27a6a3fSAlexander Shishkin int shift = (port & 3) * 8;
79b27a6a3fSAlexander Shishkin
80b27a6a3fSAlexander Shishkin val = ioread32(gth->base + reg);
81b27a6a3fSAlexander Shishkin val &= 0xff << shift;
82b27a6a3fSAlexander Shishkin val >>= shift;
83b27a6a3fSAlexander Shishkin
84b27a6a3fSAlexander Shishkin return val;
85b27a6a3fSAlexander Shishkin }
86b27a6a3fSAlexander Shishkin
gth_smcfreq_set(struct gth_device * gth,int port,unsigned int freq)87b27a6a3fSAlexander Shishkin static void gth_smcfreq_set(struct gth_device *gth, int port,
88b27a6a3fSAlexander Shishkin unsigned int freq)
89b27a6a3fSAlexander Shishkin {
90b27a6a3fSAlexander Shishkin unsigned long reg = REG_GTH_SMCR0 + ((port / 2) * 4);
91b27a6a3fSAlexander Shishkin int shift = (port & 1) * 16;
92b27a6a3fSAlexander Shishkin u32 val;
93b27a6a3fSAlexander Shishkin
94b27a6a3fSAlexander Shishkin val = ioread32(gth->base + reg);
95b27a6a3fSAlexander Shishkin val &= ~(0xffff << shift);
96b27a6a3fSAlexander Shishkin val |= freq << shift;
97b27a6a3fSAlexander Shishkin iowrite32(val, gth->base + reg);
98b27a6a3fSAlexander Shishkin }
99b27a6a3fSAlexander Shishkin
gth_smcfreq_get(struct gth_device * gth,int port)100b27a6a3fSAlexander Shishkin static unsigned int gth_smcfreq_get(struct gth_device *gth, int port)
101b27a6a3fSAlexander Shishkin {
102b27a6a3fSAlexander Shishkin unsigned long reg = REG_GTH_SMCR0 + ((port / 2) * 4);
103b27a6a3fSAlexander Shishkin int shift = (port & 1) * 16;
104b27a6a3fSAlexander Shishkin u32 val;
105b27a6a3fSAlexander Shishkin
106b27a6a3fSAlexander Shishkin val = ioread32(gth->base + reg);
107b27a6a3fSAlexander Shishkin val &= 0xffff << shift;
108b27a6a3fSAlexander Shishkin val >>= shift;
109b27a6a3fSAlexander Shishkin
110b27a6a3fSAlexander Shishkin return val;
111b27a6a3fSAlexander Shishkin }
112b27a6a3fSAlexander Shishkin
113b27a6a3fSAlexander Shishkin /*
114b27a6a3fSAlexander Shishkin * "masters" attribute group
115b27a6a3fSAlexander Shishkin */
116b27a6a3fSAlexander Shishkin
117b27a6a3fSAlexander Shishkin struct master_attribute {
118b27a6a3fSAlexander Shishkin struct device_attribute attr;
119b27a6a3fSAlexander Shishkin struct gth_device *gth;
120b27a6a3fSAlexander Shishkin unsigned int master;
121b27a6a3fSAlexander Shishkin };
122b27a6a3fSAlexander Shishkin
123b27a6a3fSAlexander Shishkin static void
gth_master_set(struct gth_device * gth,unsigned int master,int port)124b27a6a3fSAlexander Shishkin gth_master_set(struct gth_device *gth, unsigned int master, int port)
125b27a6a3fSAlexander Shishkin {
126b27a6a3fSAlexander Shishkin unsigned int reg = REG_GTH_SWDEST0 + ((master >> 1) & ~3u);
127b27a6a3fSAlexander Shishkin unsigned int shift = (master & 0x7) * 4;
128b27a6a3fSAlexander Shishkin u32 val;
129b27a6a3fSAlexander Shishkin
130b27a6a3fSAlexander Shishkin if (master >= 256) {
131b27a6a3fSAlexander Shishkin reg = REG_GTH_GSWTDEST;
132b27a6a3fSAlexander Shishkin shift = 0;
133b27a6a3fSAlexander Shishkin }
134b27a6a3fSAlexander Shishkin
135b27a6a3fSAlexander Shishkin val = ioread32(gth->base + reg);
136b27a6a3fSAlexander Shishkin val &= ~(0xf << shift);
137b27a6a3fSAlexander Shishkin if (port >= 0)
138b27a6a3fSAlexander Shishkin val |= (0x8 | port) << shift;
139b27a6a3fSAlexander Shishkin iowrite32(val, gth->base + reg);
140b27a6a3fSAlexander Shishkin }
141b27a6a3fSAlexander Shishkin
master_attr_show(struct device * dev,struct device_attribute * attr,char * buf)142b27a6a3fSAlexander Shishkin static ssize_t master_attr_show(struct device *dev,
143b27a6a3fSAlexander Shishkin struct device_attribute *attr,
144b27a6a3fSAlexander Shishkin char *buf)
145b27a6a3fSAlexander Shishkin {
146b27a6a3fSAlexander Shishkin struct master_attribute *ma =
147b27a6a3fSAlexander Shishkin container_of(attr, struct master_attribute, attr);
148b27a6a3fSAlexander Shishkin struct gth_device *gth = ma->gth;
149b27a6a3fSAlexander Shishkin size_t count;
150b27a6a3fSAlexander Shishkin int port;
151b27a6a3fSAlexander Shishkin
152b27a6a3fSAlexander Shishkin spin_lock(>h->gth_lock);
153b27a6a3fSAlexander Shishkin port = gth->master[ma->master];
154b27a6a3fSAlexander Shishkin spin_unlock(>h->gth_lock);
155b27a6a3fSAlexander Shishkin
156b27a6a3fSAlexander Shishkin if (port >= 0)
157b27a6a3fSAlexander Shishkin count = snprintf(buf, PAGE_SIZE, "%x\n", port);
158b27a6a3fSAlexander Shishkin else
159b27a6a3fSAlexander Shishkin count = snprintf(buf, PAGE_SIZE, "disabled\n");
160b27a6a3fSAlexander Shishkin
161b27a6a3fSAlexander Shishkin return count;
162b27a6a3fSAlexander Shishkin }
163b27a6a3fSAlexander Shishkin
master_attr_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)164b27a6a3fSAlexander Shishkin static ssize_t master_attr_store(struct device *dev,
165b27a6a3fSAlexander Shishkin struct device_attribute *attr,
166b27a6a3fSAlexander Shishkin const char *buf, size_t count)
167b27a6a3fSAlexander Shishkin {
168b27a6a3fSAlexander Shishkin struct master_attribute *ma =
169b27a6a3fSAlexander Shishkin container_of(attr, struct master_attribute, attr);
170b27a6a3fSAlexander Shishkin struct gth_device *gth = ma->gth;
171b27a6a3fSAlexander Shishkin int old_port, port;
172b27a6a3fSAlexander Shishkin
173b27a6a3fSAlexander Shishkin if (kstrtoint(buf, 10, &port) < 0)
174b27a6a3fSAlexander Shishkin return -EINVAL;
175b27a6a3fSAlexander Shishkin
176b27a6a3fSAlexander Shishkin if (port >= TH_POSSIBLE_OUTPUTS || port < -1)
177b27a6a3fSAlexander Shishkin return -EINVAL;
178b27a6a3fSAlexander Shishkin
179b27a6a3fSAlexander Shishkin spin_lock(>h->gth_lock);
180b27a6a3fSAlexander Shishkin
181b27a6a3fSAlexander Shishkin /* disconnect from the previous output port, if any */
182b27a6a3fSAlexander Shishkin old_port = gth->master[ma->master];
183b27a6a3fSAlexander Shishkin if (old_port >= 0) {
184b27a6a3fSAlexander Shishkin gth->master[ma->master] = -1;
185b27a6a3fSAlexander Shishkin clear_bit(ma->master, gth->output[old_port].master);
186142dfeb2SAlexander Shishkin
187142dfeb2SAlexander Shishkin /*
188142dfeb2SAlexander Shishkin * if the port is active, program this setting,
189142dfeb2SAlexander Shishkin * implies that runtime PM is on
190142dfeb2SAlexander Shishkin */
191b27a6a3fSAlexander Shishkin if (gth->output[old_port].output->active)
192b27a6a3fSAlexander Shishkin gth_master_set(gth, ma->master, -1);
193b27a6a3fSAlexander Shishkin }
194b27a6a3fSAlexander Shishkin
195b27a6a3fSAlexander Shishkin /* connect to the new output port, if any */
196b27a6a3fSAlexander Shishkin if (port >= 0) {
197b27a6a3fSAlexander Shishkin /* check if there's a driver for this port */
198b27a6a3fSAlexander Shishkin if (!gth->output[port].output) {
199b27a6a3fSAlexander Shishkin count = -ENODEV;
200b27a6a3fSAlexander Shishkin goto unlock;
201b27a6a3fSAlexander Shishkin }
202b27a6a3fSAlexander Shishkin
203b27a6a3fSAlexander Shishkin set_bit(ma->master, gth->output[port].master);
204b27a6a3fSAlexander Shishkin
205142dfeb2SAlexander Shishkin /* if the port is active, program this setting, see above */
206b27a6a3fSAlexander Shishkin if (gth->output[port].output->active)
207b27a6a3fSAlexander Shishkin gth_master_set(gth, ma->master, port);
208b27a6a3fSAlexander Shishkin }
209b27a6a3fSAlexander Shishkin
210b27a6a3fSAlexander Shishkin gth->master[ma->master] = port;
211b27a6a3fSAlexander Shishkin
212b27a6a3fSAlexander Shishkin unlock:
213b27a6a3fSAlexander Shishkin spin_unlock(>h->gth_lock);
214b27a6a3fSAlexander Shishkin
215b27a6a3fSAlexander Shishkin return count;
216b27a6a3fSAlexander Shishkin }
217b27a6a3fSAlexander Shishkin
218b27a6a3fSAlexander Shishkin struct output_attribute {
219b27a6a3fSAlexander Shishkin struct device_attribute attr;
220b27a6a3fSAlexander Shishkin struct gth_device *gth;
221b27a6a3fSAlexander Shishkin unsigned int port;
222b27a6a3fSAlexander Shishkin unsigned int parm;
223b27a6a3fSAlexander Shishkin };
224b27a6a3fSAlexander Shishkin
225b27a6a3fSAlexander Shishkin #define OUTPUT_PARM(_name, _mask, _r, _w, _what) \
226b27a6a3fSAlexander Shishkin [TH_OUTPUT_PARM(_name)] = { .name = __stringify(_name), \
227b27a6a3fSAlexander Shishkin .get = gth_ ## _what ## _get, \
228b27a6a3fSAlexander Shishkin .set = gth_ ## _what ## _set, \
229b27a6a3fSAlexander Shishkin .mask = (_mask), \
230b27a6a3fSAlexander Shishkin .readable = (_r), \
231b27a6a3fSAlexander Shishkin .writable = (_w) }
232b27a6a3fSAlexander Shishkin
233b27a6a3fSAlexander Shishkin static const struct output_parm {
234b27a6a3fSAlexander Shishkin const char *name;
235b27a6a3fSAlexander Shishkin unsigned int (*get)(struct gth_device *gth, int port);
236b27a6a3fSAlexander Shishkin void (*set)(struct gth_device *gth, int port,
237b27a6a3fSAlexander Shishkin unsigned int val);
238b27a6a3fSAlexander Shishkin unsigned int mask;
239b27a6a3fSAlexander Shishkin unsigned int readable : 1,
240b27a6a3fSAlexander Shishkin writable : 1;
241b27a6a3fSAlexander Shishkin } output_parms[] = {
242b27a6a3fSAlexander Shishkin OUTPUT_PARM(port, 0x7, 1, 0, output),
243b27a6a3fSAlexander Shishkin OUTPUT_PARM(null, BIT(3), 1, 1, output),
244b27a6a3fSAlexander Shishkin OUTPUT_PARM(drop, BIT(4), 1, 1, output),
245b27a6a3fSAlexander Shishkin OUTPUT_PARM(reset, BIT(5), 1, 0, output),
246b27a6a3fSAlexander Shishkin OUTPUT_PARM(flush, BIT(7), 0, 1, output),
247b27a6a3fSAlexander Shishkin OUTPUT_PARM(smcfreq, 0xffff, 1, 1, smcfreq),
248b27a6a3fSAlexander Shishkin };
249b27a6a3fSAlexander Shishkin
250b27a6a3fSAlexander Shishkin static void
gth_output_parm_set(struct gth_device * gth,int port,unsigned int parm,unsigned int val)251b27a6a3fSAlexander Shishkin gth_output_parm_set(struct gth_device *gth, int port, unsigned int parm,
252b27a6a3fSAlexander Shishkin unsigned int val)
253b27a6a3fSAlexander Shishkin {
254b27a6a3fSAlexander Shishkin unsigned int config = output_parms[parm].get(gth, port);
255b27a6a3fSAlexander Shishkin unsigned int mask = output_parms[parm].mask;
256b27a6a3fSAlexander Shishkin unsigned int shift = __ffs(mask);
257b27a6a3fSAlexander Shishkin
258b27a6a3fSAlexander Shishkin config &= ~mask;
259b27a6a3fSAlexander Shishkin config |= (val << shift) & mask;
260b27a6a3fSAlexander Shishkin output_parms[parm].set(gth, port, config);
261b27a6a3fSAlexander Shishkin }
262b27a6a3fSAlexander Shishkin
263b27a6a3fSAlexander Shishkin static unsigned int
gth_output_parm_get(struct gth_device * gth,int port,unsigned int parm)264b27a6a3fSAlexander Shishkin gth_output_parm_get(struct gth_device *gth, int port, unsigned int parm)
265b27a6a3fSAlexander Shishkin {
266b27a6a3fSAlexander Shishkin unsigned int config = output_parms[parm].get(gth, port);
267b27a6a3fSAlexander Shishkin unsigned int mask = output_parms[parm].mask;
268b27a6a3fSAlexander Shishkin unsigned int shift = __ffs(mask);
269b27a6a3fSAlexander Shishkin
270b27a6a3fSAlexander Shishkin config &= mask;
271b27a6a3fSAlexander Shishkin config >>= shift;
272b27a6a3fSAlexander Shishkin return config;
273b27a6a3fSAlexander Shishkin }
274b27a6a3fSAlexander Shishkin
275b27a6a3fSAlexander Shishkin /*
276b27a6a3fSAlexander Shishkin * Reset outputs and sources
277b27a6a3fSAlexander Shishkin */
intel_th_gth_reset(struct gth_device * gth)278b27a6a3fSAlexander Shishkin static int intel_th_gth_reset(struct gth_device *gth)
279b27a6a3fSAlexander Shishkin {
280a0e7df33SAlexander Shishkin u32 reg;
281b27a6a3fSAlexander Shishkin int port, i;
282b27a6a3fSAlexander Shishkin
283a0e7df33SAlexander Shishkin reg = ioread32(gth->base + REG_GTH_SCRPD0);
284a0e7df33SAlexander Shishkin if (reg & SCRPD_DEBUGGER_IN_USE)
285b27a6a3fSAlexander Shishkin return -EBUSY;
286b27a6a3fSAlexander Shishkin
2874d02ceffSAlexander Shishkin /* Always save/restore STH and TU registers in S0ix entry/exit */
288a0e7df33SAlexander Shishkin reg |= SCRPD_STH_IS_ENABLED | SCRPD_TRIGGER_IS_ENABLED;
289a0e7df33SAlexander Shishkin iowrite32(reg, gth->base + REG_GTH_SCRPD0);
2904d02ceffSAlexander Shishkin
291b27a6a3fSAlexander Shishkin /* output ports */
292b27a6a3fSAlexander Shishkin for (port = 0; port < 8; port++) {
293b27a6a3fSAlexander Shishkin if (gth_output_parm_get(gth, port, TH_OUTPUT_PARM(port)) ==
294b27a6a3fSAlexander Shishkin GTH_NONE)
295b27a6a3fSAlexander Shishkin continue;
296b27a6a3fSAlexander Shishkin
297b27a6a3fSAlexander Shishkin gth_output_set(gth, port, 0);
298b27a6a3fSAlexander Shishkin gth_smcfreq_set(gth, port, 16);
299b27a6a3fSAlexander Shishkin }
300b27a6a3fSAlexander Shishkin /* disable overrides */
301b27a6a3fSAlexander Shishkin iowrite32(0, gth->base + REG_GTH_DESTOVR);
302b27a6a3fSAlexander Shishkin
303b27a6a3fSAlexander Shishkin /* masters swdest_0~31 and gswdest */
304b27a6a3fSAlexander Shishkin for (i = 0; i < 33; i++)
305b27a6a3fSAlexander Shishkin iowrite32(0, gth->base + REG_GTH_SWDEST0 + i * 4);
306b27a6a3fSAlexander Shishkin
307b27a6a3fSAlexander Shishkin /* sources */
308b27a6a3fSAlexander Shishkin iowrite32(0, gth->base + REG_GTH_SCR);
309b27a6a3fSAlexander Shishkin iowrite32(0xfc, gth->base + REG_GTH_SCR2);
310b27a6a3fSAlexander Shishkin
3118116db57SAlexander Shishkin /* setup CTS for single trigger */
3128116db57SAlexander Shishkin iowrite32(CTS_EVENT_ENABLE_IF_ANYTHING, gth->base + REG_CTS_C0S0_EN);
3138116db57SAlexander Shishkin iowrite32(CTS_ACTION_CONTROL_SET_STATE(CTS_STATE_IDLE) |
3148116db57SAlexander Shishkin CTS_ACTION_CONTROL_TRIGGER, gth->base + REG_CTS_C0S0_ACT);
3158116db57SAlexander Shishkin
316b27a6a3fSAlexander Shishkin return 0;
317b27a6a3fSAlexander Shishkin }
318b27a6a3fSAlexander Shishkin
319b27a6a3fSAlexander Shishkin /*
320b27a6a3fSAlexander Shishkin * "outputs" attribute group
321b27a6a3fSAlexander Shishkin */
322b27a6a3fSAlexander Shishkin
output_attr_show(struct device * dev,struct device_attribute * attr,char * buf)323b27a6a3fSAlexander Shishkin static ssize_t output_attr_show(struct device *dev,
324b27a6a3fSAlexander Shishkin struct device_attribute *attr,
325b27a6a3fSAlexander Shishkin char *buf)
326b27a6a3fSAlexander Shishkin {
327b27a6a3fSAlexander Shishkin struct output_attribute *oa =
328b27a6a3fSAlexander Shishkin container_of(attr, struct output_attribute, attr);
329b27a6a3fSAlexander Shishkin struct gth_device *gth = oa->gth;
330b27a6a3fSAlexander Shishkin size_t count;
331b27a6a3fSAlexander Shishkin
332142dfeb2SAlexander Shishkin pm_runtime_get_sync(dev);
333142dfeb2SAlexander Shishkin
334b27a6a3fSAlexander Shishkin spin_lock(>h->gth_lock);
335b27a6a3fSAlexander Shishkin count = snprintf(buf, PAGE_SIZE, "%x\n",
336b27a6a3fSAlexander Shishkin gth_output_parm_get(gth, oa->port, oa->parm));
337b27a6a3fSAlexander Shishkin spin_unlock(>h->gth_lock);
338b27a6a3fSAlexander Shishkin
339142dfeb2SAlexander Shishkin pm_runtime_put(dev);
340142dfeb2SAlexander Shishkin
341b27a6a3fSAlexander Shishkin return count;
342b27a6a3fSAlexander Shishkin }
343b27a6a3fSAlexander Shishkin
output_attr_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)344b27a6a3fSAlexander Shishkin static ssize_t output_attr_store(struct device *dev,
345b27a6a3fSAlexander Shishkin struct device_attribute *attr,
346b27a6a3fSAlexander Shishkin const char *buf, size_t count)
347b27a6a3fSAlexander Shishkin {
348b27a6a3fSAlexander Shishkin struct output_attribute *oa =
349b27a6a3fSAlexander Shishkin container_of(attr, struct output_attribute, attr);
350b27a6a3fSAlexander Shishkin struct gth_device *gth = oa->gth;
351b27a6a3fSAlexander Shishkin unsigned int config;
352b27a6a3fSAlexander Shishkin
353b27a6a3fSAlexander Shishkin if (kstrtouint(buf, 16, &config) < 0)
354b27a6a3fSAlexander Shishkin return -EINVAL;
355b27a6a3fSAlexander Shishkin
356142dfeb2SAlexander Shishkin pm_runtime_get_sync(dev);
357142dfeb2SAlexander Shishkin
358b27a6a3fSAlexander Shishkin spin_lock(>h->gth_lock);
359b27a6a3fSAlexander Shishkin gth_output_parm_set(gth, oa->port, oa->parm, config);
360b27a6a3fSAlexander Shishkin spin_unlock(>h->gth_lock);
361b27a6a3fSAlexander Shishkin
362142dfeb2SAlexander Shishkin pm_runtime_put(dev);
363142dfeb2SAlexander Shishkin
364b27a6a3fSAlexander Shishkin return count;
365b27a6a3fSAlexander Shishkin }
366b27a6a3fSAlexander Shishkin
intel_th_master_attributes(struct gth_device * gth)367b27a6a3fSAlexander Shishkin static int intel_th_master_attributes(struct gth_device *gth)
368b27a6a3fSAlexander Shishkin {
369b27a6a3fSAlexander Shishkin struct master_attribute *master_attrs;
370b27a6a3fSAlexander Shishkin struct attribute **attrs;
371b27a6a3fSAlexander Shishkin int i, nattrs = TH_CONFIGURABLE_MASTERS + 2;
372b27a6a3fSAlexander Shishkin
373b27a6a3fSAlexander Shishkin attrs = devm_kcalloc(gth->dev, nattrs, sizeof(void *), GFP_KERNEL);
374b27a6a3fSAlexander Shishkin if (!attrs)
375b27a6a3fSAlexander Shishkin return -ENOMEM;
376b27a6a3fSAlexander Shishkin
377b27a6a3fSAlexander Shishkin master_attrs = devm_kcalloc(gth->dev, nattrs,
378b27a6a3fSAlexander Shishkin sizeof(struct master_attribute),
379b27a6a3fSAlexander Shishkin GFP_KERNEL);
380b27a6a3fSAlexander Shishkin if (!master_attrs)
381b27a6a3fSAlexander Shishkin return -ENOMEM;
382b27a6a3fSAlexander Shishkin
383b27a6a3fSAlexander Shishkin for (i = 0; i < TH_CONFIGURABLE_MASTERS + 1; i++) {
384b27a6a3fSAlexander Shishkin char *name;
385b27a6a3fSAlexander Shishkin
386b27a6a3fSAlexander Shishkin name = devm_kasprintf(gth->dev, GFP_KERNEL, "%d%s", i,
387b27a6a3fSAlexander Shishkin i == TH_CONFIGURABLE_MASTERS ? "+" : "");
388b27a6a3fSAlexander Shishkin if (!name)
389b27a6a3fSAlexander Shishkin return -ENOMEM;
390b27a6a3fSAlexander Shishkin
391b27a6a3fSAlexander Shishkin master_attrs[i].attr.attr.name = name;
392b27a6a3fSAlexander Shishkin master_attrs[i].attr.attr.mode = S_IRUGO | S_IWUSR;
393b27a6a3fSAlexander Shishkin master_attrs[i].attr.show = master_attr_show;
394b27a6a3fSAlexander Shishkin master_attrs[i].attr.store = master_attr_store;
395b27a6a3fSAlexander Shishkin
396b27a6a3fSAlexander Shishkin sysfs_attr_init(&master_attrs[i].attr.attr);
397b27a6a3fSAlexander Shishkin attrs[i] = &master_attrs[i].attr.attr;
398b27a6a3fSAlexander Shishkin
399b27a6a3fSAlexander Shishkin master_attrs[i].gth = gth;
400b27a6a3fSAlexander Shishkin master_attrs[i].master = i;
401b27a6a3fSAlexander Shishkin }
402b27a6a3fSAlexander Shishkin
403b27a6a3fSAlexander Shishkin gth->master_group.name = "masters";
404b27a6a3fSAlexander Shishkin gth->master_group.attrs = attrs;
405b27a6a3fSAlexander Shishkin
406b27a6a3fSAlexander Shishkin return sysfs_create_group(>h->dev->kobj, >h->master_group);
407b27a6a3fSAlexander Shishkin }
408b27a6a3fSAlexander Shishkin
intel_th_output_attributes(struct gth_device * gth)409b27a6a3fSAlexander Shishkin static int intel_th_output_attributes(struct gth_device *gth)
410b27a6a3fSAlexander Shishkin {
411b27a6a3fSAlexander Shishkin struct output_attribute *out_attrs;
412b27a6a3fSAlexander Shishkin struct attribute **attrs;
413b27a6a3fSAlexander Shishkin int i, j, nouts = TH_POSSIBLE_OUTPUTS;
414b27a6a3fSAlexander Shishkin int nparms = ARRAY_SIZE(output_parms);
415b27a6a3fSAlexander Shishkin int nattrs = nouts * nparms + 1;
416b27a6a3fSAlexander Shishkin
417b27a6a3fSAlexander Shishkin attrs = devm_kcalloc(gth->dev, nattrs, sizeof(void *), GFP_KERNEL);
418b27a6a3fSAlexander Shishkin if (!attrs)
419b27a6a3fSAlexander Shishkin return -ENOMEM;
420b27a6a3fSAlexander Shishkin
421b27a6a3fSAlexander Shishkin out_attrs = devm_kcalloc(gth->dev, nattrs,
422b27a6a3fSAlexander Shishkin sizeof(struct output_attribute),
423b27a6a3fSAlexander Shishkin GFP_KERNEL);
424b27a6a3fSAlexander Shishkin if (!out_attrs)
425b27a6a3fSAlexander Shishkin return -ENOMEM;
426b27a6a3fSAlexander Shishkin
427b27a6a3fSAlexander Shishkin for (i = 0; i < nouts; i++) {
428b27a6a3fSAlexander Shishkin for (j = 0; j < nparms; j++) {
429b27a6a3fSAlexander Shishkin unsigned int idx = i * nparms + j;
430b27a6a3fSAlexander Shishkin char *name;
431b27a6a3fSAlexander Shishkin
432b27a6a3fSAlexander Shishkin name = devm_kasprintf(gth->dev, GFP_KERNEL, "%d_%s", i,
433b27a6a3fSAlexander Shishkin output_parms[j].name);
434b27a6a3fSAlexander Shishkin if (!name)
435b27a6a3fSAlexander Shishkin return -ENOMEM;
436b27a6a3fSAlexander Shishkin
437b27a6a3fSAlexander Shishkin out_attrs[idx].attr.attr.name = name;
438b27a6a3fSAlexander Shishkin
439b27a6a3fSAlexander Shishkin if (output_parms[j].readable) {
440b27a6a3fSAlexander Shishkin out_attrs[idx].attr.attr.mode |= S_IRUGO;
441b27a6a3fSAlexander Shishkin out_attrs[idx].attr.show = output_attr_show;
442b27a6a3fSAlexander Shishkin }
443b27a6a3fSAlexander Shishkin
444b27a6a3fSAlexander Shishkin if (output_parms[j].writable) {
445b27a6a3fSAlexander Shishkin out_attrs[idx].attr.attr.mode |= S_IWUSR;
446b27a6a3fSAlexander Shishkin out_attrs[idx].attr.store = output_attr_store;
447b27a6a3fSAlexander Shishkin }
448b27a6a3fSAlexander Shishkin
449b27a6a3fSAlexander Shishkin sysfs_attr_init(&out_attrs[idx].attr.attr);
450b27a6a3fSAlexander Shishkin attrs[idx] = &out_attrs[idx].attr.attr;
451b27a6a3fSAlexander Shishkin
452b27a6a3fSAlexander Shishkin out_attrs[idx].gth = gth;
453b27a6a3fSAlexander Shishkin out_attrs[idx].port = i;
454b27a6a3fSAlexander Shishkin out_attrs[idx].parm = j;
455b27a6a3fSAlexander Shishkin }
456b27a6a3fSAlexander Shishkin }
457b27a6a3fSAlexander Shishkin
458b27a6a3fSAlexander Shishkin gth->output_group.name = "outputs";
459b27a6a3fSAlexander Shishkin gth->output_group.attrs = attrs;
460b27a6a3fSAlexander Shishkin
461b27a6a3fSAlexander Shishkin return sysfs_create_group(>h->dev->kobj, >h->output_group);
462b27a6a3fSAlexander Shishkin }
463b27a6a3fSAlexander Shishkin
464b27a6a3fSAlexander Shishkin /**
4659958e025SAlexander Shishkin * intel_th_gth_stop() - stop tracing to an output device
4669958e025SAlexander Shishkin * @gth: GTH device
4679958e025SAlexander Shishkin * @output: output device's descriptor
4689958e025SAlexander Shishkin * @capture_done: set when no more traces will be captured
4699958e025SAlexander Shishkin *
4709958e025SAlexander Shishkin * This will stop tracing using force storeEn off signal and wait for the
4719958e025SAlexander Shishkin * pipelines to be empty for the corresponding output port.
4729958e025SAlexander Shishkin */
intel_th_gth_stop(struct gth_device * gth,struct intel_th_output * output,bool capture_done)4739958e025SAlexander Shishkin static void intel_th_gth_stop(struct gth_device *gth,
4749958e025SAlexander Shishkin struct intel_th_output *output,
4759958e025SAlexander Shishkin bool capture_done)
4769958e025SAlexander Shishkin {
4779958e025SAlexander Shishkin struct intel_th_device *outdev =
4789958e025SAlexander Shishkin container_of(output, struct intel_th_device, output);
4799958e025SAlexander Shishkin struct intel_th_driver *outdrv =
4809958e025SAlexander Shishkin to_intel_th_driver(outdev->dev.driver);
4819958e025SAlexander Shishkin unsigned long count;
4829958e025SAlexander Shishkin u32 reg;
4839958e025SAlexander Shishkin u32 scr2 = 0xfc | (capture_done ? 1 : 0);
4849958e025SAlexander Shishkin
4859958e025SAlexander Shishkin iowrite32(0, gth->base + REG_GTH_SCR);
4869958e025SAlexander Shishkin iowrite32(scr2, gth->base + REG_GTH_SCR2);
4879958e025SAlexander Shishkin
4889958e025SAlexander Shishkin /* wait on pipeline empty for the given port */
4899958e025SAlexander Shishkin for (reg = 0, count = GTH_PLE_WAITLOOP_DEPTH;
4909958e025SAlexander Shishkin count && !(reg & BIT(output->port)); count--) {
4919958e025SAlexander Shishkin reg = ioread32(gth->base + REG_GTH_STAT);
4929958e025SAlexander Shishkin cpu_relax();
4939958e025SAlexander Shishkin }
4949958e025SAlexander Shishkin
4959958e025SAlexander Shishkin if (!count)
4969958e025SAlexander Shishkin dev_dbg(gth->dev, "timeout waiting for GTH[%d] PLE\n",
4979958e025SAlexander Shishkin output->port);
4989958e025SAlexander Shishkin
4999958e025SAlexander Shishkin /* wait on output piepline empty */
5009958e025SAlexander Shishkin if (outdrv->wait_empty)
5019958e025SAlexander Shishkin outdrv->wait_empty(outdev);
5029958e025SAlexander Shishkin
5039958e025SAlexander Shishkin /* clear force capture done for next captures */
5049958e025SAlexander Shishkin iowrite32(0xfc, gth->base + REG_GTH_SCR2);
5059958e025SAlexander Shishkin }
5069958e025SAlexander Shishkin
5079958e025SAlexander Shishkin /**
5089958e025SAlexander Shishkin * intel_th_gth_start() - start tracing to an output device
5099958e025SAlexander Shishkin * @gth: GTH device
5109958e025SAlexander Shishkin * @output: output device's descriptor
5119958e025SAlexander Shishkin *
5129958e025SAlexander Shishkin * This will start tracing using force storeEn signal.
5139958e025SAlexander Shishkin */
intel_th_gth_start(struct gth_device * gth,struct intel_th_output * output)5149958e025SAlexander Shishkin static void intel_th_gth_start(struct gth_device *gth,
5159958e025SAlexander Shishkin struct intel_th_output *output)
5169958e025SAlexander Shishkin {
5179958e025SAlexander Shishkin u32 scr = 0xfc0000;
5189958e025SAlexander Shishkin
5199958e025SAlexander Shishkin if (output->multiblock)
5209958e025SAlexander Shishkin scr |= 0xff;
5219958e025SAlexander Shishkin
5229958e025SAlexander Shishkin iowrite32(scr, gth->base + REG_GTH_SCR);
5239958e025SAlexander Shishkin iowrite32(0, gth->base + REG_GTH_SCR2);
5249958e025SAlexander Shishkin }
5259958e025SAlexander Shishkin
5269958e025SAlexander Shishkin /**
52753c189f1SAlexander Shishkin * intel_th_gth_disable() - disable tracing to an output device
528b27a6a3fSAlexander Shishkin * @thdev: GTH device
529b27a6a3fSAlexander Shishkin * @output: output device's descriptor
530b27a6a3fSAlexander Shishkin *
531b27a6a3fSAlexander Shishkin * This will deconfigure all masters set to output to this device,
532b27a6a3fSAlexander Shishkin * disable tracing using force storeEn off signal and wait for the
533b27a6a3fSAlexander Shishkin * "pipeline empty" bit for corresponding output port.
534b27a6a3fSAlexander Shishkin */
intel_th_gth_disable(struct intel_th_device * thdev,struct intel_th_output * output)535b27a6a3fSAlexander Shishkin static void intel_th_gth_disable(struct intel_th_device *thdev,
536b27a6a3fSAlexander Shishkin struct intel_th_output *output)
537b27a6a3fSAlexander Shishkin {
538b27a6a3fSAlexander Shishkin struct gth_device *gth = dev_get_drvdata(&thdev->dev);
539b27a6a3fSAlexander Shishkin int master;
540b27a6a3fSAlexander Shishkin u32 reg;
541b27a6a3fSAlexander Shishkin
542b27a6a3fSAlexander Shishkin spin_lock(>h->gth_lock);
543b27a6a3fSAlexander Shishkin output->active = false;
544b27a6a3fSAlexander Shishkin
545b27a6a3fSAlexander Shishkin for_each_set_bit(master, gth->output[output->port].master,
54618ffbc47SPavel Machek TH_CONFIGURABLE_MASTERS + 1) {
547b27a6a3fSAlexander Shishkin gth_master_set(gth, master, -1);
548b27a6a3fSAlexander Shishkin }
549b27a6a3fSAlexander Shishkin spin_unlock(>h->gth_lock);
550b27a6a3fSAlexander Shishkin
5519958e025SAlexander Shishkin intel_th_gth_stop(gth, output, true);
5524d02ceffSAlexander Shishkin
5534d02ceffSAlexander Shishkin reg = ioread32(gth->base + REG_GTH_SCRPD0);
5544d02ceffSAlexander Shishkin reg &= ~output->scratchpad;
5554d02ceffSAlexander Shishkin iowrite32(reg, gth->base + REG_GTH_SCRPD0);
556b27a6a3fSAlexander Shishkin }
557b27a6a3fSAlexander Shishkin
gth_tscu_resync(struct gth_device * gth)558a0e7df33SAlexander Shishkin static void gth_tscu_resync(struct gth_device *gth)
559a0e7df33SAlexander Shishkin {
560a0e7df33SAlexander Shishkin u32 reg;
561a0e7df33SAlexander Shishkin
562a0e7df33SAlexander Shishkin reg = ioread32(gth->base + REG_TSCU_TSUCTRL);
563a0e7df33SAlexander Shishkin reg &= ~TSUCTRL_CTCRESYNC;
564a0e7df33SAlexander Shishkin iowrite32(reg, gth->base + REG_TSCU_TSUCTRL);
565a0e7df33SAlexander Shishkin }
566a0e7df33SAlexander Shishkin
intel_th_gth_prepare(struct intel_th_device * thdev,struct intel_th_output * output)567*ab1afed7SAlexander Shishkin static void intel_th_gth_prepare(struct intel_th_device *thdev,
568*ab1afed7SAlexander Shishkin struct intel_th_output *output)
569*ab1afed7SAlexander Shishkin {
570*ab1afed7SAlexander Shishkin struct gth_device *gth = dev_get_drvdata(&thdev->dev);
571*ab1afed7SAlexander Shishkin int count;
572*ab1afed7SAlexander Shishkin
573*ab1afed7SAlexander Shishkin /*
574*ab1afed7SAlexander Shishkin * Wait until the output port is in reset before we start
575*ab1afed7SAlexander Shishkin * programming it.
576*ab1afed7SAlexander Shishkin */
577*ab1afed7SAlexander Shishkin for (count = GTH_PLE_WAITLOOP_DEPTH;
578*ab1afed7SAlexander Shishkin count && !(gth_output_get(gth, output->port) & BIT(5)); count--)
579*ab1afed7SAlexander Shishkin cpu_relax();
580*ab1afed7SAlexander Shishkin }
581*ab1afed7SAlexander Shishkin
582b27a6a3fSAlexander Shishkin /**
583b27a6a3fSAlexander Shishkin * intel_th_gth_enable() - enable tracing to an output device
584b27a6a3fSAlexander Shishkin * @thdev: GTH device
585b27a6a3fSAlexander Shishkin * @output: output device's descriptor
586b27a6a3fSAlexander Shishkin *
587b27a6a3fSAlexander Shishkin * This will configure all masters set to output to this device and
588b27a6a3fSAlexander Shishkin * enable tracing using force storeEn signal.
589b27a6a3fSAlexander Shishkin */
intel_th_gth_enable(struct intel_th_device * thdev,struct intel_th_output * output)590b27a6a3fSAlexander Shishkin static void intel_th_gth_enable(struct intel_th_device *thdev,
591b27a6a3fSAlexander Shishkin struct intel_th_output *output)
592b27a6a3fSAlexander Shishkin {
593b27a6a3fSAlexander Shishkin struct gth_device *gth = dev_get_drvdata(&thdev->dev);
594a0e7df33SAlexander Shishkin struct intel_th *th = to_intel_th(thdev);
595b27a6a3fSAlexander Shishkin int master;
5969958e025SAlexander Shishkin u32 scrpd;
597b27a6a3fSAlexander Shishkin
598b27a6a3fSAlexander Shishkin spin_lock(>h->gth_lock);
599b27a6a3fSAlexander Shishkin for_each_set_bit(master, gth->output[output->port].master,
600b27a6a3fSAlexander Shishkin TH_CONFIGURABLE_MASTERS + 1) {
601b27a6a3fSAlexander Shishkin gth_master_set(gth, master, output->port);
602b27a6a3fSAlexander Shishkin }
603b27a6a3fSAlexander Shishkin
604b27a6a3fSAlexander Shishkin output->active = true;
605b27a6a3fSAlexander Shishkin spin_unlock(>h->gth_lock);
606b27a6a3fSAlexander Shishkin
607a0e7df33SAlexander Shishkin if (INTEL_TH_CAP(th, tscu_enable))
608a0e7df33SAlexander Shishkin gth_tscu_resync(gth);
609a0e7df33SAlexander Shishkin
6104d02ceffSAlexander Shishkin scrpd = ioread32(gth->base + REG_GTH_SCRPD0);
6114d02ceffSAlexander Shishkin scrpd |= output->scratchpad;
6124d02ceffSAlexander Shishkin iowrite32(scrpd, gth->base + REG_GTH_SCRPD0);
6134d02ceffSAlexander Shishkin
6149958e025SAlexander Shishkin intel_th_gth_start(gth, output);
615b27a6a3fSAlexander Shishkin }
616b27a6a3fSAlexander Shishkin
617b27a6a3fSAlexander Shishkin /**
6188116db57SAlexander Shishkin * intel_th_gth_switch() - execute a switch sequence
6198116db57SAlexander Shishkin * @thdev: GTH device
6208116db57SAlexander Shishkin * @output: output device's descriptor
6218116db57SAlexander Shishkin *
6228116db57SAlexander Shishkin * This will execute a switch sequence that will trigger a switch window
6238116db57SAlexander Shishkin * when tracing to MSC in multi-block mode.
6248116db57SAlexander Shishkin */
intel_th_gth_switch(struct intel_th_device * thdev,struct intel_th_output * output)6258116db57SAlexander Shishkin static void intel_th_gth_switch(struct intel_th_device *thdev,
6268116db57SAlexander Shishkin struct intel_th_output *output)
6278116db57SAlexander Shishkin {
6288116db57SAlexander Shishkin struct gth_device *gth = dev_get_drvdata(&thdev->dev);
6298116db57SAlexander Shishkin unsigned long count;
6308116db57SAlexander Shishkin u32 reg;
6318116db57SAlexander Shishkin
6328116db57SAlexander Shishkin /* trigger */
6338116db57SAlexander Shishkin iowrite32(0, gth->base + REG_CTS_CTL);
6348116db57SAlexander Shishkin iowrite32(CTS_CTL_SEQUENCER_ENABLE, gth->base + REG_CTS_CTL);
6358116db57SAlexander Shishkin /* wait on trigger status */
6368116db57SAlexander Shishkin for (reg = 0, count = CTS_TRIG_WAITLOOP_DEPTH;
6378116db57SAlexander Shishkin count && !(reg & BIT(4)); count--) {
6388116db57SAlexander Shishkin reg = ioread32(gth->base + REG_CTS_STAT);
6398116db57SAlexander Shishkin cpu_relax();
6408116db57SAlexander Shishkin }
6418116db57SAlexander Shishkin if (!count)
6428116db57SAlexander Shishkin dev_dbg(&thdev->dev, "timeout waiting for CTS Trigger\n");
6438116db57SAlexander Shishkin
64487c0b9c7SAlexander Shishkin /* De-assert the trigger */
64587c0b9c7SAlexander Shishkin iowrite32(0, gth->base + REG_CTS_CTL);
64687c0b9c7SAlexander Shishkin
6478116db57SAlexander Shishkin intel_th_gth_stop(gth, output, false);
6488116db57SAlexander Shishkin intel_th_gth_start(gth, output);
6498116db57SAlexander Shishkin }
6508116db57SAlexander Shishkin
6518116db57SAlexander Shishkin /**
652b27a6a3fSAlexander Shishkin * intel_th_gth_assign() - assign output device to a GTH output port
653b27a6a3fSAlexander Shishkin * @thdev: GTH device
654b27a6a3fSAlexander Shishkin * @othdev: output device
655b27a6a3fSAlexander Shishkin *
656b27a6a3fSAlexander Shishkin * This will match a given output device parameters against present
657b27a6a3fSAlexander Shishkin * output ports on the GTH and fill out relevant bits in output device's
658b27a6a3fSAlexander Shishkin * descriptor.
659b27a6a3fSAlexander Shishkin *
660b27a6a3fSAlexander Shishkin * Return: 0 on success, -errno on error.
661b27a6a3fSAlexander Shishkin */
intel_th_gth_assign(struct intel_th_device * thdev,struct intel_th_device * othdev)662b27a6a3fSAlexander Shishkin static int intel_th_gth_assign(struct intel_th_device *thdev,
663b27a6a3fSAlexander Shishkin struct intel_th_device *othdev)
664b27a6a3fSAlexander Shishkin {
665b27a6a3fSAlexander Shishkin struct gth_device *gth = dev_get_drvdata(&thdev->dev);
666b27a6a3fSAlexander Shishkin int i, id;
667b27a6a3fSAlexander Shishkin
668d4f5f545SAlexander Shishkin if (thdev->host_mode)
669d4f5f545SAlexander Shishkin return -EBUSY;
670d4f5f545SAlexander Shishkin
671b27a6a3fSAlexander Shishkin if (othdev->type != INTEL_TH_OUTPUT)
672b27a6a3fSAlexander Shishkin return -EINVAL;
673b27a6a3fSAlexander Shishkin
674b27a6a3fSAlexander Shishkin for (i = 0, id = 0; i < TH_POSSIBLE_OUTPUTS; i++) {
675b27a6a3fSAlexander Shishkin if (gth->output[i].port_type != othdev->output.type)
676b27a6a3fSAlexander Shishkin continue;
677b27a6a3fSAlexander Shishkin
678b27a6a3fSAlexander Shishkin if (othdev->id == -1 || othdev->id == id)
679b27a6a3fSAlexander Shishkin goto found;
680b27a6a3fSAlexander Shishkin
681b27a6a3fSAlexander Shishkin id++;
682b27a6a3fSAlexander Shishkin }
683b27a6a3fSAlexander Shishkin
684b27a6a3fSAlexander Shishkin return -ENOENT;
685b27a6a3fSAlexander Shishkin
686b27a6a3fSAlexander Shishkin found:
687b27a6a3fSAlexander Shishkin spin_lock(>h->gth_lock);
688b27a6a3fSAlexander Shishkin othdev->output.port = i;
689b27a6a3fSAlexander Shishkin othdev->output.active = false;
690b27a6a3fSAlexander Shishkin gth->output[i].output = &othdev->output;
691b27a6a3fSAlexander Shishkin spin_unlock(>h->gth_lock);
692b27a6a3fSAlexander Shishkin
693b27a6a3fSAlexander Shishkin return 0;
694b27a6a3fSAlexander Shishkin }
695b27a6a3fSAlexander Shishkin
696b27a6a3fSAlexander Shishkin /**
697b27a6a3fSAlexander Shishkin * intel_th_gth_unassign() - deassociate an output device from its output port
698b27a6a3fSAlexander Shishkin * @thdev: GTH device
699b27a6a3fSAlexander Shishkin * @othdev: output device
700b27a6a3fSAlexander Shishkin */
intel_th_gth_unassign(struct intel_th_device * thdev,struct intel_th_device * othdev)701b27a6a3fSAlexander Shishkin static void intel_th_gth_unassign(struct intel_th_device *thdev,
702b27a6a3fSAlexander Shishkin struct intel_th_device *othdev)
703b27a6a3fSAlexander Shishkin {
704b27a6a3fSAlexander Shishkin struct gth_device *gth = dev_get_drvdata(&thdev->dev);
705b27a6a3fSAlexander Shishkin int port = othdev->output.port;
7069ed3f222SAlexander Shishkin int master;
707b27a6a3fSAlexander Shishkin
708d4f5f545SAlexander Shishkin if (thdev->host_mode)
709d4f5f545SAlexander Shishkin return;
710d4f5f545SAlexander Shishkin
711b27a6a3fSAlexander Shishkin spin_lock(>h->gth_lock);
712b27a6a3fSAlexander Shishkin othdev->output.port = -1;
713b27a6a3fSAlexander Shishkin othdev->output.active = false;
714b27a6a3fSAlexander Shishkin gth->output[port].output = NULL;
71518ffbc47SPavel Machek for (master = 0; master < TH_CONFIGURABLE_MASTERS + 1; master++)
7169ed3f222SAlexander Shishkin if (gth->master[master] == port)
7179ed3f222SAlexander Shishkin gth->master[master] = -1;
718b27a6a3fSAlexander Shishkin spin_unlock(>h->gth_lock);
719b27a6a3fSAlexander Shishkin }
720b27a6a3fSAlexander Shishkin
721b27a6a3fSAlexander Shishkin static int
intel_th_gth_set_output(struct intel_th_device * thdev,unsigned int master)722b27a6a3fSAlexander Shishkin intel_th_gth_set_output(struct intel_th_device *thdev, unsigned int master)
723b27a6a3fSAlexander Shishkin {
724b27a6a3fSAlexander Shishkin struct gth_device *gth = dev_get_drvdata(&thdev->dev);
725b27a6a3fSAlexander Shishkin int port = 0; /* FIXME: make default output configurable */
726b27a6a3fSAlexander Shishkin
727b27a6a3fSAlexander Shishkin /*
728b27a6a3fSAlexander Shishkin * everything above TH_CONFIGURABLE_MASTERS is controlled by the
729b27a6a3fSAlexander Shishkin * same register
730b27a6a3fSAlexander Shishkin */
731b27a6a3fSAlexander Shishkin if (master > TH_CONFIGURABLE_MASTERS)
732b27a6a3fSAlexander Shishkin master = TH_CONFIGURABLE_MASTERS;
733b27a6a3fSAlexander Shishkin
734b27a6a3fSAlexander Shishkin spin_lock(>h->gth_lock);
735b27a6a3fSAlexander Shishkin if (gth->master[master] == -1) {
736b27a6a3fSAlexander Shishkin set_bit(master, gth->output[port].master);
737b27a6a3fSAlexander Shishkin gth->master[master] = port;
738b27a6a3fSAlexander Shishkin }
739b27a6a3fSAlexander Shishkin spin_unlock(>h->gth_lock);
740b27a6a3fSAlexander Shishkin
741b27a6a3fSAlexander Shishkin return 0;
742b27a6a3fSAlexander Shishkin }
743b27a6a3fSAlexander Shishkin
intel_th_gth_probe(struct intel_th_device * thdev)744b27a6a3fSAlexander Shishkin static int intel_th_gth_probe(struct intel_th_device *thdev)
745b27a6a3fSAlexander Shishkin {
746b27a6a3fSAlexander Shishkin struct device *dev = &thdev->dev;
747a753bfcfSAlexander Shishkin struct intel_th *th = dev_get_drvdata(dev->parent);
748b27a6a3fSAlexander Shishkin struct gth_device *gth;
749b27a6a3fSAlexander Shishkin struct resource *res;
750b27a6a3fSAlexander Shishkin void __iomem *base;
751b27a6a3fSAlexander Shishkin int i, ret;
752b27a6a3fSAlexander Shishkin
753b27a6a3fSAlexander Shishkin res = intel_th_device_get_resource(thdev, IORESOURCE_MEM, 0);
754b27a6a3fSAlexander Shishkin if (!res)
755b27a6a3fSAlexander Shishkin return -ENODEV;
756b27a6a3fSAlexander Shishkin
757b27a6a3fSAlexander Shishkin base = devm_ioremap(dev, res->start, resource_size(res));
75873061da0SDan Carpenter if (!base)
75973061da0SDan Carpenter return -ENOMEM;
760b27a6a3fSAlexander Shishkin
761b27a6a3fSAlexander Shishkin gth = devm_kzalloc(dev, sizeof(*gth), GFP_KERNEL);
762b27a6a3fSAlexander Shishkin if (!gth)
763b27a6a3fSAlexander Shishkin return -ENOMEM;
764b27a6a3fSAlexander Shishkin
765b27a6a3fSAlexander Shishkin gth->dev = dev;
766b27a6a3fSAlexander Shishkin gth->base = base;
767b27a6a3fSAlexander Shishkin spin_lock_init(>h->gth_lock);
768b27a6a3fSAlexander Shishkin
769a753bfcfSAlexander Shishkin dev_set_drvdata(dev, gth);
770a753bfcfSAlexander Shishkin
771d4f5f545SAlexander Shishkin /*
772d4f5f545SAlexander Shishkin * Host mode can be signalled via SW means or via SCRPD_DEBUGGER_IN_USE
773d4f5f545SAlexander Shishkin * bit. Either way, don't reset HW in this case, and don't export any
774d4f5f545SAlexander Shishkin * capture configuration attributes. Also, refuse to assign output
775d4f5f545SAlexander Shishkin * drivers to ports, see intel_th_gth_assign().
776d4f5f545SAlexander Shishkin */
777d4f5f545SAlexander Shishkin if (thdev->host_mode)
778a753bfcfSAlexander Shishkin return 0;
779d4f5f545SAlexander Shishkin
780b27a6a3fSAlexander Shishkin ret = intel_th_gth_reset(gth);
781d4f5f545SAlexander Shishkin if (ret) {
782d4f5f545SAlexander Shishkin if (ret != -EBUSY)
783b27a6a3fSAlexander Shishkin return ret;
784b27a6a3fSAlexander Shishkin
785d4f5f545SAlexander Shishkin thdev->host_mode = true;
786d4f5f545SAlexander Shishkin
787a753bfcfSAlexander Shishkin return 0;
788d4f5f545SAlexander Shishkin }
789d4f5f545SAlexander Shishkin
790b27a6a3fSAlexander Shishkin for (i = 0; i < TH_CONFIGURABLE_MASTERS + 1; i++)
791b27a6a3fSAlexander Shishkin gth->master[i] = -1;
792b27a6a3fSAlexander Shishkin
793b27a6a3fSAlexander Shishkin for (i = 0; i < TH_POSSIBLE_OUTPUTS; i++) {
794b27a6a3fSAlexander Shishkin gth->output[i].gth = gth;
795b27a6a3fSAlexander Shishkin gth->output[i].index = i;
796b27a6a3fSAlexander Shishkin gth->output[i].port_type =
797b27a6a3fSAlexander Shishkin gth_output_parm_get(gth, i, TH_OUTPUT_PARM(port));
798a753bfcfSAlexander Shishkin if (gth->output[i].port_type == GTH_NONE)
799a753bfcfSAlexander Shishkin continue;
800a753bfcfSAlexander Shishkin
801a753bfcfSAlexander Shishkin ret = intel_th_output_enable(th, gth->output[i].port_type);
802a753bfcfSAlexander Shishkin /* -ENODEV is ok, we just won't have that device enumerated */
803a753bfcfSAlexander Shishkin if (ret && ret != -ENODEV)
804a753bfcfSAlexander Shishkin return ret;
805b27a6a3fSAlexander Shishkin }
806b27a6a3fSAlexander Shishkin
807b27a6a3fSAlexander Shishkin if (intel_th_output_attributes(gth) ||
808b27a6a3fSAlexander Shishkin intel_th_master_attributes(gth)) {
809b27a6a3fSAlexander Shishkin pr_warn("Can't initialize sysfs attributes\n");
810b27a6a3fSAlexander Shishkin
811b27a6a3fSAlexander Shishkin if (gth->output_group.attrs)
812b27a6a3fSAlexander Shishkin sysfs_remove_group(>h->dev->kobj, >h->output_group);
813b27a6a3fSAlexander Shishkin return -ENOMEM;
814b27a6a3fSAlexander Shishkin }
815b27a6a3fSAlexander Shishkin
816b27a6a3fSAlexander Shishkin return 0;
817b27a6a3fSAlexander Shishkin }
818b27a6a3fSAlexander Shishkin
intel_th_gth_remove(struct intel_th_device * thdev)819b27a6a3fSAlexander Shishkin static void intel_th_gth_remove(struct intel_th_device *thdev)
820b27a6a3fSAlexander Shishkin {
821b27a6a3fSAlexander Shishkin struct gth_device *gth = dev_get_drvdata(&thdev->dev);
822b27a6a3fSAlexander Shishkin
823b27a6a3fSAlexander Shishkin sysfs_remove_group(>h->dev->kobj, >h->output_group);
824b27a6a3fSAlexander Shishkin sysfs_remove_group(>h->dev->kobj, >h->master_group);
825b27a6a3fSAlexander Shishkin }
826b27a6a3fSAlexander Shishkin
827b27a6a3fSAlexander Shishkin static struct intel_th_driver intel_th_gth_driver = {
828b27a6a3fSAlexander Shishkin .probe = intel_th_gth_probe,
829b27a6a3fSAlexander Shishkin .remove = intel_th_gth_remove,
830b27a6a3fSAlexander Shishkin .assign = intel_th_gth_assign,
831b27a6a3fSAlexander Shishkin .unassign = intel_th_gth_unassign,
832b27a6a3fSAlexander Shishkin .set_output = intel_th_gth_set_output,
833*ab1afed7SAlexander Shishkin .prepare = intel_th_gth_prepare,
834b27a6a3fSAlexander Shishkin .enable = intel_th_gth_enable,
8358116db57SAlexander Shishkin .trig_switch = intel_th_gth_switch,
836b27a6a3fSAlexander Shishkin .disable = intel_th_gth_disable,
837b27a6a3fSAlexander Shishkin .driver = {
838b27a6a3fSAlexander Shishkin .name = "gth",
839b27a6a3fSAlexander Shishkin .owner = THIS_MODULE,
840b27a6a3fSAlexander Shishkin },
841b27a6a3fSAlexander Shishkin };
842b27a6a3fSAlexander Shishkin
843b27a6a3fSAlexander Shishkin module_driver(intel_th_gth_driver,
844b27a6a3fSAlexander Shishkin intel_th_driver_register,
845b27a6a3fSAlexander Shishkin intel_th_driver_unregister);
846b27a6a3fSAlexander Shishkin
847b27a6a3fSAlexander Shishkin MODULE_ALIAS("intel_th_switch");
848b27a6a3fSAlexander Shishkin MODULE_LICENSE("GPL v2");
849b27a6a3fSAlexander Shishkin MODULE_DESCRIPTION("Intel(R) Trace Hub Global Trace Hub driver");
850b27a6a3fSAlexander Shishkin MODULE_AUTHOR("Alexander Shishkin <alexander.shishkin@linux.intel.com>");
851