xref: /openbmc/linux/drivers/hwtracing/intel_th/gth.c (revision 762f99f4f3cb41a775b5157dd761217beba65873)
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(&gth->gth_lock);
153b27a6a3fSAlexander Shishkin 	port = gth->master[ma->master];
154b27a6a3fSAlexander Shishkin 	spin_unlock(&gth->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(&gth->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(&gth->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(&gth->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(&gth->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(&gth->gth_lock);
359b27a6a3fSAlexander Shishkin 	gth_output_parm_set(gth, oa->port, oa->parm, config);
360b27a6a3fSAlexander Shishkin 	spin_unlock(&gth->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(&gth->dev->kobj, &gth->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(&gth->dev->kobj, &gth->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(&gth->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(&gth->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(&gth->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(&gth->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(&gth->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(&gth->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(&gth->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(&gth->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(&gth->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(&gth->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(&gth->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(&gth->dev->kobj, &gth->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(&gth->dev->kobj, &gth->output_group);
824b27a6a3fSAlexander Shishkin 	sysfs_remove_group(&gth->dev->kobj, &gth->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