2 * Intel(R) Trace Hub Global Trace Hub
4 * Copyright (C) 2014-2015 Intel Corporation.
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
18 #include <linux/types.h>
19 #include <linux/module.h>
20 #include <linux/device.h>
23 #include <linux/slab.h>
24 #include <linux/bitmap.h>
32 * struct gth_output - GTH view on an output port
33 * @gth: backlink to the GTH device
34 * @output: link to output device's output descriptor
35 * @index: output port number
36 * @port_type: one of GTH_* port type values
37 * @master: bitmap of masters configured for this output
40 struct gth_device
*gth
;
41 struct intel_th_output
*output
;
43 unsigned int port_type
;
44 DECLARE_BITMAP(master
, TH_CONFIGURABLE_MASTERS
+ 1);
48 * struct gth_device - GTH device
49 * @dev: driver core's device
50 * @base: register window base address
51 * @output_group: attributes describing output ports
52 * @master_group: attributes describing master assignments
53 * @output: output ports
54 * @master: master/output port assignments
55 * @gth_lock: serializes accesses to GTH bits
61 struct attribute_group output_group
;
62 struct attribute_group master_group
;
63 struct gth_output output
[TH_POSSIBLE_OUTPUTS
];
64 signed char master
[TH_CONFIGURABLE_MASTERS
+ 1];
68 static void gth_output_set(struct gth_device
*gth
, int port
,
71 unsigned long reg
= port
& 4 ? REG_GTH_GTHOPT1
: REG_GTH_GTHOPT0
;
73 int shift
= (port
& 3) * 8;
75 val
= ioread32(gth
->base
+ reg
);
76 val
&= ~(0xff << shift
);
77 val
|= config
<< shift
;
78 iowrite32(val
, gth
->base
+ reg
);
81 static unsigned int gth_output_get(struct gth_device
*gth
, int port
)
83 unsigned long reg
= port
& 4 ? REG_GTH_GTHOPT1
: REG_GTH_GTHOPT0
;
85 int shift
= (port
& 3) * 8;
87 val
= ioread32(gth
->base
+ reg
);
94 static void gth_smcfreq_set(struct gth_device
*gth
, int port
,
97 unsigned long reg
= REG_GTH_SMCR0
+ ((port
/ 2) * 4);
98 int shift
= (port
& 1) * 16;
101 val
= ioread32(gth
->base
+ reg
);
102 val
&= ~(0xffff << shift
);
103 val
|= freq
<< shift
;
104 iowrite32(val
, gth
->base
+ reg
);
107 static unsigned int gth_smcfreq_get(struct gth_device
*gth
, int port
)
109 unsigned long reg
= REG_GTH_SMCR0
+ ((port
/ 2) * 4);
110 int shift
= (port
& 1) * 16;
113 val
= ioread32(gth
->base
+ reg
);
114 val
&= 0xffff << shift
;
121 * "masters" attribute group
124 struct master_attribute
{
125 struct device_attribute attr
;
126 struct gth_device
*gth
;
131 gth_master_set(struct gth_device
*gth
, unsigned int master
, int port
)
133 unsigned int reg
= REG_GTH_SWDEST0
+ ((master
>> 1) & ~3u);
134 unsigned int shift
= (master
& 0x7) * 4;
138 reg
= REG_GTH_GSWTDEST
;
142 val
= ioread32(gth
->base
+ reg
);
143 val
&= ~(0xf << shift
);
145 val
|= (0x8 | port
) << shift
;
146 iowrite32(val
, gth
->base
+ reg
);
149 static ssize_t
master_attr_show(struct device
*dev
,
150 struct device_attribute
*attr
,
153 struct master_attribute
*ma
=
154 container_of(attr
, struct master_attribute
, attr
);
155 struct gth_device
*gth
= ma
->gth
;
159 spin_lock(>h
->gth_lock
);
160 port
= gth
->master
[ma
->master
];
161 spin_unlock(>h
->gth_lock
);
164 count
= snprintf(buf
, PAGE_SIZE
, "%x\n", port
);
166 count
= snprintf(buf
, PAGE_SIZE
, "disabled\n");
171 static ssize_t
master_attr_store(struct device
*dev
,
172 struct device_attribute
*attr
,
173 const char *buf
, size_t count
)
175 struct master_attribute
*ma
=
176 container_of(attr
, struct master_attribute
, attr
);
177 struct gth_device
*gth
= ma
->gth
;
180 if (kstrtoint(buf
, 10, &port
) < 0)
183 if (port
>= TH_POSSIBLE_OUTPUTS
|| port
< -1)
186 spin_lock(>h
->gth_lock
);
188 /* disconnect from the previous output port, if any */
189 old_port
= gth
->master
[ma
->master
];
191 gth
->master
[ma
->master
] = -1;
192 clear_bit(ma
->master
, gth
->output
[old_port
].master
);
193 if (gth
->output
[old_port
].output
->active
)
194 gth_master_set(gth
, ma
->master
, -1);
197 /* connect to the new output port, if any */
199 /* check if there's a driver for this port */
200 if (!gth
->output
[port
].output
) {
205 set_bit(ma
->master
, gth
->output
[port
].master
);
207 /* if the port is active, program this setting */
208 if (gth
->output
[port
].output
->active
)
209 gth_master_set(gth
, ma
->master
, port
);
212 gth
->master
[ma
->master
] = port
;
215 spin_unlock(>h
->gth_lock
);
220 struct output_attribute
{
221 struct device_attribute attr
;
222 struct gth_device
*gth
;
227 #define OUTPUT_PARM(_name, _mask, _r, _w, _what) \
228 [TH_OUTPUT_PARM(_name)] = { .name = __stringify(_name), \
229 .get = gth_ ## _what ## _get, \
230 .set = gth_ ## _what ## _set, \
235 static const struct output_parm
{
237 unsigned int (*get
)(struct gth_device
*gth
, int port
);
238 void (*set
)(struct gth_device
*gth
, int port
,
241 unsigned int readable
: 1,
244 OUTPUT_PARM(port
, 0x7, 1, 0, output
),
245 OUTPUT_PARM(null
, BIT(3), 1, 1, output
),
246 OUTPUT_PARM(drop
, BIT(4), 1, 1, output
),
247 OUTPUT_PARM(reset
, BIT(5), 1, 0, output
),
248 OUTPUT_PARM(flush
, BIT(7), 0, 1, output
),
249 OUTPUT_PARM(smcfreq
, 0xffff, 1, 1, smcfreq
),
253 gth_output_parm_set(struct gth_device
*gth
, int port
, unsigned int parm
,
256 unsigned int config
= output_parms
[parm
].get(gth
, port
);
257 unsigned int mask
= output_parms
[parm
].mask
;
258 unsigned int shift
= __ffs(mask
);
261 config
|= (val
<< shift
) & mask
;
262 output_parms
[parm
].set(gth
, port
, config
);
266 gth_output_parm_get(struct gth_device
*gth
, int port
, unsigned int parm
)
268 unsigned int config
= output_parms
[parm
].get(gth
, port
);
269 unsigned int mask
= output_parms
[parm
].mask
;
270 unsigned int shift
= __ffs(mask
);
278 * Reset outputs and sources
280 static int intel_th_gth_reset(struct gth_device
*gth
)
285 scratchpad
= ioread32(gth
->base
+ REG_GTH_SCRPD0
);
286 if (scratchpad
& SCRPD_DEBUGGER_IN_USE
)
289 /* Always save/restore STH and TU registers in S0ix entry/exit */
290 scratchpad
|= SCRPD_STH_IS_ENABLED
| SCRPD_TRIGGER_IS_ENABLED
;
291 iowrite32(scratchpad
, gth
->base
+ REG_GTH_SCRPD0
);
294 for (port
= 0; port
< 8; port
++) {
295 if (gth_output_parm_get(gth
, port
, TH_OUTPUT_PARM(port
)) ==
299 gth_output_set(gth
, port
, 0);
300 gth_smcfreq_set(gth
, port
, 16);
302 /* disable overrides */
303 iowrite32(0, gth
->base
+ REG_GTH_DESTOVR
);
305 /* masters swdest_0~31 and gswdest */
306 for (i
= 0; i
< 33; i
++)
307 iowrite32(0, gth
->base
+ REG_GTH_SWDEST0
+ i
* 4);
310 iowrite32(0, gth
->base
+ REG_GTH_SCR
);
311 iowrite32(0xfc, gth
->base
+ REG_GTH_SCR2
);
317 * "outputs" attribute group
320 static ssize_t
output_attr_show(struct device
*dev
,
321 struct device_attribute
*attr
,
324 struct output_attribute
*oa
=
325 container_of(attr
, struct output_attribute
, attr
);
326 struct gth_device
*gth
= oa
->gth
;
329 spin_lock(>h
->gth_lock
);
330 count
= snprintf(buf
, PAGE_SIZE
, "%x\n",
331 gth_output_parm_get(gth
, oa
->port
, oa
->parm
));
332 spin_unlock(>h
->gth_lock
);
337 static ssize_t
output_attr_store(struct device
*dev
,
338 struct device_attribute
*attr
,
339 const char *buf
, size_t count
)
341 struct output_attribute
*oa
=
342 container_of(attr
, struct output_attribute
, attr
);
343 struct gth_device
*gth
= oa
->gth
;
346 if (kstrtouint(buf
, 16, &config
) < 0)
349 spin_lock(>h
->gth_lock
);
350 gth_output_parm_set(gth
, oa
->port
, oa
->parm
, config
);
351 spin_unlock(>h
->gth_lock
);
356 static int intel_th_master_attributes(struct gth_device
*gth
)
358 struct master_attribute
*master_attrs
;
359 struct attribute
**attrs
;
360 int i
, nattrs
= TH_CONFIGURABLE_MASTERS
+ 2;
362 attrs
= devm_kcalloc(gth
->dev
, nattrs
, sizeof(void *), GFP_KERNEL
);
366 master_attrs
= devm_kcalloc(gth
->dev
, nattrs
,
367 sizeof(struct master_attribute
),
372 for (i
= 0; i
< TH_CONFIGURABLE_MASTERS
+ 1; i
++) {
375 name
= devm_kasprintf(gth
->dev
, GFP_KERNEL
, "%d%s", i
,
376 i
== TH_CONFIGURABLE_MASTERS
? "+" : "");
380 master_attrs
[i
].attr
.attr
.name
= name
;
381 master_attrs
[i
].attr
.attr
.mode
= S_IRUGO
| S_IWUSR
;
382 master_attrs
[i
].attr
.show
= master_attr_show
;
383 master_attrs
[i
].attr
.store
= master_attr_store
;
385 sysfs_attr_init(&master_attrs
[i
].attr
.attr
);
386 attrs
[i
] = &master_attrs
[i
].attr
.attr
;
388 master_attrs
[i
].gth
= gth
;
389 master_attrs
[i
].master
= i
;
392 gth
->master_group
.name
= "masters";
393 gth
->master_group
.attrs
= attrs
;
395 return sysfs_create_group(>h
->dev
->kobj
, >h
->master_group
);
398 static int intel_th_output_attributes(struct gth_device
*gth
)
400 struct output_attribute
*out_attrs
;
401 struct attribute
**attrs
;
402 int i
, j
, nouts
= TH_POSSIBLE_OUTPUTS
;
403 int nparms
= ARRAY_SIZE(output_parms
);
404 int nattrs
= nouts
* nparms
+ 1;
406 attrs
= devm_kcalloc(gth
->dev
, nattrs
, sizeof(void *), GFP_KERNEL
);
410 out_attrs
= devm_kcalloc(gth
->dev
, nattrs
,
411 sizeof(struct output_attribute
),
416 for (i
= 0; i
< nouts
; i
++) {
417 for (j
= 0; j
< nparms
; j
++) {
418 unsigned int idx
= i
* nparms
+ j
;
421 name
= devm_kasprintf(gth
->dev
, GFP_KERNEL
, "%d_%s", i
,
422 output_parms
[j
].name
);
426 out_attrs
[idx
].attr
.attr
.name
= name
;
428 if (output_parms
[j
].readable
) {
429 out_attrs
[idx
].attr
.attr
.mode
|= S_IRUGO
;
430 out_attrs
[idx
].attr
.show
= output_attr_show
;
433 if (output_parms
[j
].writable
) {
434 out_attrs
[idx
].attr
.attr
.mode
|= S_IWUSR
;
435 out_attrs
[idx
].attr
.store
= output_attr_store
;
438 sysfs_attr_init(&out_attrs
[idx
].attr
.attr
);
439 attrs
[idx
] = &out_attrs
[idx
].attr
.attr
;
441 out_attrs
[idx
].gth
= gth
;
442 out_attrs
[idx
].port
= i
;
443 out_attrs
[idx
].parm
= j
;
447 gth
->output_group
.name
= "outputs";
448 gth
->output_group
.attrs
= attrs
;
450 return sysfs_create_group(>h
->dev
->kobj
, >h
->output_group
);
454 * intel_th_gth_disable() - enable tracing to an output device
456 * @output: output device's descriptor
458 * This will deconfigure all masters set to output to this device,
459 * disable tracing using force storeEn off signal and wait for the
460 * "pipeline empty" bit for corresponding output port.
462 static void intel_th_gth_disable(struct intel_th_device
*thdev
,
463 struct intel_th_output
*output
)
465 struct gth_device
*gth
= dev_get_drvdata(&thdev
->dev
);
470 spin_lock(>h
->gth_lock
);
471 output
->active
= false;
473 for_each_set_bit(master
, gth
->output
[output
->port
].master
,
474 TH_CONFIGURABLE_MASTERS
) {
475 gth_master_set(gth
, master
, -1);
477 spin_unlock(>h
->gth_lock
);
479 iowrite32(0, gth
->base
+ REG_GTH_SCR
);
480 iowrite32(0xfd, gth
->base
+ REG_GTH_SCR2
);
482 /* wait on pipeline empty for the given port */
483 for (reg
= 0, count
= GTH_PLE_WAITLOOP_DEPTH
;
484 count
&& !(reg
& BIT(output
->port
)); count
--) {
485 reg
= ioread32(gth
->base
+ REG_GTH_STAT
);
489 /* clear force capture done for next captures */
490 iowrite32(0xfc, gth
->base
+ REG_GTH_SCR2
);
493 dev_dbg(&thdev
->dev
, "timeout waiting for GTH[%d] PLE\n",
496 reg
= ioread32(gth
->base
+ REG_GTH_SCRPD0
);
497 reg
&= ~output
->scratchpad
;
498 iowrite32(reg
, gth
->base
+ REG_GTH_SCRPD0
);
502 * intel_th_gth_enable() - enable tracing to an output device
504 * @output: output device's descriptor
506 * This will configure all masters set to output to this device and
507 * enable tracing using force storeEn signal.
509 static void intel_th_gth_enable(struct intel_th_device
*thdev
,
510 struct intel_th_output
*output
)
512 struct gth_device
*gth
= dev_get_drvdata(&thdev
->dev
);
513 u32 scr
= 0xfc0000, scrpd
;
516 spin_lock(>h
->gth_lock
);
517 for_each_set_bit(master
, gth
->output
[output
->port
].master
,
518 TH_CONFIGURABLE_MASTERS
+ 1) {
519 gth_master_set(gth
, master
, output
->port
);
522 if (output
->multiblock
)
525 output
->active
= true;
526 spin_unlock(>h
->gth_lock
);
528 scrpd
= ioread32(gth
->base
+ REG_GTH_SCRPD0
);
529 scrpd
|= output
->scratchpad
;
530 iowrite32(scrpd
, gth
->base
+ REG_GTH_SCRPD0
);
532 iowrite32(scr
, gth
->base
+ REG_GTH_SCR
);
533 iowrite32(0, gth
->base
+ REG_GTH_SCR2
);
537 * intel_th_gth_assign() - assign output device to a GTH output port
539 * @othdev: output device
541 * This will match a given output device parameters against present
542 * output ports on the GTH and fill out relevant bits in output device's
545 * Return: 0 on success, -errno on error.
547 static int intel_th_gth_assign(struct intel_th_device
*thdev
,
548 struct intel_th_device
*othdev
)
550 struct gth_device
*gth
= dev_get_drvdata(&thdev
->dev
);
553 if (othdev
->type
!= INTEL_TH_OUTPUT
)
556 for (i
= 0, id
= 0; i
< TH_POSSIBLE_OUTPUTS
; i
++) {
557 if (gth
->output
[i
].port_type
!= othdev
->output
.type
)
560 if (othdev
->id
== -1 || othdev
->id
== id
)
569 spin_lock(>h
->gth_lock
);
570 othdev
->output
.port
= i
;
571 othdev
->output
.active
= false;
572 gth
->output
[i
].output
= &othdev
->output
;
573 spin_unlock(>h
->gth_lock
);
579 * intel_th_gth_unassign() - deassociate an output device from its output port
581 * @othdev: output device
583 static void intel_th_gth_unassign(struct intel_th_device
*thdev
,
584 struct intel_th_device
*othdev
)
586 struct gth_device
*gth
= dev_get_drvdata(&thdev
->dev
);
587 int port
= othdev
->output
.port
;
589 spin_lock(>h
->gth_lock
);
590 othdev
->output
.port
= -1;
591 othdev
->output
.active
= false;
592 gth
->output
[port
].output
= NULL
;
593 spin_unlock(>h
->gth_lock
);
597 intel_th_gth_set_output(struct intel_th_device
*thdev
, unsigned int master
)
599 struct gth_device
*gth
= dev_get_drvdata(&thdev
->dev
);
600 int port
= 0; /* FIXME: make default output configurable */
603 * everything above TH_CONFIGURABLE_MASTERS is controlled by the
606 if (master
> TH_CONFIGURABLE_MASTERS
)
607 master
= TH_CONFIGURABLE_MASTERS
;
609 spin_lock(>h
->gth_lock
);
610 if (gth
->master
[master
] == -1) {
611 set_bit(master
, gth
->output
[port
].master
);
612 gth
->master
[master
] = port
;
614 spin_unlock(>h
->gth_lock
);
619 static int intel_th_gth_probe(struct intel_th_device
*thdev
)
621 struct device
*dev
= &thdev
->dev
;
622 struct gth_device
*gth
;
623 struct resource
*res
;
627 res
= intel_th_device_get_resource(thdev
, IORESOURCE_MEM
, 0);
631 base
= devm_ioremap(dev
, res
->start
, resource_size(res
));
635 gth
= devm_kzalloc(dev
, sizeof(*gth
), GFP_KERNEL
);
641 spin_lock_init(>h
->gth_lock
);
643 ret
= intel_th_gth_reset(gth
);
647 for (i
= 0; i
< TH_CONFIGURABLE_MASTERS
+ 1; i
++)
650 for (i
= 0; i
< TH_POSSIBLE_OUTPUTS
; i
++) {
651 gth
->output
[i
].gth
= gth
;
652 gth
->output
[i
].index
= i
;
653 gth
->output
[i
].port_type
=
654 gth_output_parm_get(gth
, i
, TH_OUTPUT_PARM(port
));
657 if (intel_th_output_attributes(gth
) ||
658 intel_th_master_attributes(gth
)) {
659 pr_warn("Can't initialize sysfs attributes\n");
661 if (gth
->output_group
.attrs
)
662 sysfs_remove_group(>h
->dev
->kobj
, >h
->output_group
);
666 dev_set_drvdata(dev
, gth
);
671 static void intel_th_gth_remove(struct intel_th_device
*thdev
)
673 struct gth_device
*gth
= dev_get_drvdata(&thdev
->dev
);
675 sysfs_remove_group(>h
->dev
->kobj
, >h
->output_group
);
676 sysfs_remove_group(>h
->dev
->kobj
, >h
->master_group
);
679 static struct intel_th_driver intel_th_gth_driver
= {
680 .probe
= intel_th_gth_probe
,
681 .remove
= intel_th_gth_remove
,
682 .assign
= intel_th_gth_assign
,
683 .unassign
= intel_th_gth_unassign
,
684 .set_output
= intel_th_gth_set_output
,
685 .enable
= intel_th_gth_enable
,
686 .disable
= intel_th_gth_disable
,
689 .owner
= THIS_MODULE
,
693 module_driver(intel_th_gth_driver
,
694 intel_th_driver_register
,
695 intel_th_driver_unregister
);
697 MODULE_ALIAS("intel_th_switch");
698 MODULE_LICENSE("GPL v2");
699 MODULE_DESCRIPTION("Intel(R) Trace Hub Global Trace Hub driver");
700 MODULE_AUTHOR("Alexander Shishkin <alexander.shishkin@linux.intel.com>");