2 * Intel(R) Trace Hub Software Trace Hub support
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/stm.h>
31 void __iomem
*channels
;
32 phys_addr_t channels_phys
;
35 unsigned int sw_nmasters
;
38 static struct intel_th_channel __iomem
*
39 sth_channel(struct sth_device
*sth
, unsigned int master
, unsigned int channel
)
41 struct intel_th_channel __iomem
*sw_map
= sth
->channels
;
43 return &sw_map
[(master
- sth
->stm
.sw_start
) * sth
->stm
.sw_nchannels
+
47 static void sth_iowrite(void __iomem
*dest
, const unsigned char *payload
,
53 writeq_relaxed(*(u64
*)payload
, dest
);
57 writel_relaxed(*(u32
*)payload
, dest
);
60 writew_relaxed(*(u16
*)payload
, dest
);
63 writeb_relaxed(*(u8
*)payload
, dest
);
70 static ssize_t notrace
sth_stm_packet(struct stm_data
*stm_data
,
76 const unsigned char *payload
)
78 struct sth_device
*sth
= container_of(stm_data
, struct sth_device
, stm
);
79 struct intel_th_channel __iomem
*out
=
80 sth_channel(sth
, master
, channel
);
81 u64 __iomem
*outp
= &out
->Dn
;
82 unsigned long reg
= REG_STH_TRIG
;
89 size
= rounddown_pow_of_two(size
);
92 /* Global packets (GERR, XSYNC, TRIG) are sent with register writes */
95 case STP_PACKET_XSYNC
:
98 if (flags
& STP_PACKET_TIMESTAMPED
)
100 writeb_relaxed(*payload
, sth
->base
+ reg
);
103 case STP_PACKET_MERR
:
107 sth_iowrite(&out
->MERR
, payload
, size
);
110 case STP_PACKET_FLAG
:
111 if (flags
& STP_PACKET_TIMESTAMPED
)
112 outp
= (u64 __iomem
*)&out
->FLAG_TS
;
114 outp
= (u64 __iomem
*)&out
->FLAG
;
117 writeb_relaxed(0, outp
);
120 case STP_PACKET_USER
:
121 if (flags
& STP_PACKET_TIMESTAMPED
)
122 outp
= &out
->USER_TS
;
125 sth_iowrite(outp
, payload
, size
);
128 case STP_PACKET_DATA
:
131 if (flags
& STP_PACKET_TIMESTAMPED
)
133 if (flags
& STP_PACKET_MARKED
)
136 sth_iowrite(outp
, payload
, size
);
146 sth_stm_mmio_addr(struct stm_data
*stm_data
, unsigned int master
,
147 unsigned int channel
, unsigned int nr_chans
)
149 struct sth_device
*sth
= container_of(stm_data
, struct sth_device
, stm
);
152 master
-= sth
->stm
.sw_start
;
153 addr
= sth
->channels_phys
+ (master
* sth
->stm
.sw_nchannels
+ channel
) *
154 sizeof(struct intel_th_channel
);
156 if (offset_in_page(addr
) ||
157 offset_in_page(nr_chans
* sizeof(struct intel_th_channel
)))
163 static int sth_stm_link(struct stm_data
*stm_data
, unsigned int master
,
164 unsigned int channel
)
166 struct sth_device
*sth
= container_of(stm_data
, struct sth_device
, stm
);
168 intel_th_set_output(to_intel_th_device(sth
->dev
), master
);
173 static int intel_th_sw_init(struct sth_device
*sth
)
177 reg
= ioread32(sth
->base
+ REG_STH_STHCAP1
);
178 sth
->stm
.sw_nchannels
= reg
& 0xff;
180 reg
= ioread32(sth
->base
+ REG_STH_STHCAP0
);
181 sth
->stm
.sw_start
= reg
& 0xffff;
182 sth
->stm
.sw_end
= reg
>> 16;
184 sth
->sw_nmasters
= sth
->stm
.sw_end
- sth
->stm
.sw_start
;
185 dev_dbg(sth
->dev
, "sw_start: %x sw_end: %x masters: %x nchannels: %x\n",
186 sth
->stm
.sw_start
, sth
->stm
.sw_end
, sth
->sw_nmasters
,
187 sth
->stm
.sw_nchannels
);
192 static int intel_th_sth_probe(struct intel_th_device
*thdev
)
194 struct device
*dev
= &thdev
->dev
;
195 struct sth_device
*sth
;
196 struct resource
*res
;
197 void __iomem
*base
, *channels
;
200 res
= intel_th_device_get_resource(thdev
, IORESOURCE_MEM
, 0);
204 base
= devm_ioremap(dev
, res
->start
, resource_size(res
));
208 res
= intel_th_device_get_resource(thdev
, IORESOURCE_MEM
, 1);
212 channels
= devm_ioremap(dev
, res
->start
, resource_size(res
));
216 sth
= devm_kzalloc(dev
, sizeof(*sth
), GFP_KERNEL
);
222 sth
->channels
= channels
;
223 sth
->channels_phys
= res
->start
;
224 sth
->stm
.name
= dev_name(dev
);
225 sth
->stm
.packet
= sth_stm_packet
;
226 sth
->stm
.mmio_addr
= sth_stm_mmio_addr
;
227 sth
->stm
.sw_mmiosz
= sizeof(struct intel_th_channel
);
228 sth
->stm
.link
= sth_stm_link
;
230 err
= intel_th_sw_init(sth
);
234 err
= stm_register_device(dev
, &sth
->stm
, THIS_MODULE
);
236 dev_err(dev
, "stm_register_device failed\n");
240 dev_set_drvdata(dev
, sth
);
245 static void intel_th_sth_remove(struct intel_th_device
*thdev
)
247 struct sth_device
*sth
= dev_get_drvdata(&thdev
->dev
);
249 stm_unregister_device(&sth
->stm
);
252 static struct intel_th_driver intel_th_sth_driver
= {
253 .probe
= intel_th_sth_probe
,
254 .remove
= intel_th_sth_remove
,
257 .owner
= THIS_MODULE
,
261 module_driver(intel_th_sth_driver
,
262 intel_th_driver_register
,
263 intel_th_driver_unregister
);
265 MODULE_LICENSE("GPL v2");
266 MODULE_DESCRIPTION("Intel(R) Trace Hub Software Trace Hub driver");
267 MODULE_AUTHOR("Alexander Shishkin <alexander.shishkin@intel.com>");