1 // SPDX-License-Identifier: GPL-2.0
3 * Intel(R) Trace Hub Software Trace Hub support
5 * Copyright (C) 2014-2015 Intel Corporation.
8 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
10 #include <linux/types.h>
11 #include <linux/module.h>
12 #include <linux/device.h>
15 #include <linux/slab.h>
16 #include <linux/stm.h>
23 void __iomem
*channels
;
24 phys_addr_t channels_phys
;
27 unsigned int sw_nmasters
;
30 static struct intel_th_channel __iomem
*
31 sth_channel(struct sth_device
*sth
, unsigned int master
, unsigned int channel
)
33 struct intel_th_channel __iomem
*sw_map
= sth
->channels
;
35 return &sw_map
[(master
- sth
->stm
.sw_start
) * sth
->stm
.sw_nchannels
+
39 static void sth_iowrite(void __iomem
*dest
, const unsigned char *payload
,
45 writeq_relaxed(*(u64
*)payload
, dest
);
49 writel_relaxed(*(u32
*)payload
, dest
);
52 writew_relaxed(*(u16
*)payload
, dest
);
55 writeb_relaxed(*(u8
*)payload
, dest
);
62 static ssize_t notrace
sth_stm_packet(struct stm_data
*stm_data
,
68 const unsigned char *payload
)
70 struct sth_device
*sth
= container_of(stm_data
, struct sth_device
, stm
);
71 struct intel_th_channel __iomem
*out
=
72 sth_channel(sth
, master
, channel
);
73 u64 __iomem
*outp
= &out
->Dn
;
74 unsigned long reg
= REG_STH_TRIG
;
81 size
= rounddown_pow_of_two(size
);
84 /* Global packets (GERR, XSYNC, TRIG) are sent with register writes */
89 case STP_PACKET_XSYNC
:
94 if (flags
& STP_PACKET_TIMESTAMPED
)
96 writeb_relaxed(*payload
, sth
->base
+ reg
);
103 sth_iowrite(&out
->MERR
, payload
, size
);
106 case STP_PACKET_FLAG
:
107 if (flags
& STP_PACKET_TIMESTAMPED
)
108 outp
= (u64 __iomem
*)&out
->FLAG_TS
;
110 outp
= (u64 __iomem
*)&out
->FLAG
;
113 writeb_relaxed(0, outp
);
116 case STP_PACKET_USER
:
117 if (flags
& STP_PACKET_TIMESTAMPED
)
118 outp
= &out
->USER_TS
;
121 sth_iowrite(outp
, payload
, size
);
124 case STP_PACKET_DATA
:
127 if (flags
& STP_PACKET_TIMESTAMPED
)
129 if (flags
& STP_PACKET_MARKED
)
132 sth_iowrite(outp
, payload
, size
);
142 sth_stm_mmio_addr(struct stm_data
*stm_data
, unsigned int master
,
143 unsigned int channel
, unsigned int nr_chans
)
145 struct sth_device
*sth
= container_of(stm_data
, struct sth_device
, stm
);
148 master
-= sth
->stm
.sw_start
;
149 addr
= sth
->channels_phys
+ (master
* sth
->stm
.sw_nchannels
+ channel
) *
150 sizeof(struct intel_th_channel
);
152 if (offset_in_page(addr
) ||
153 offset_in_page(nr_chans
* sizeof(struct intel_th_channel
)))
159 static int sth_stm_link(struct stm_data
*stm_data
, unsigned int master
,
160 unsigned int channel
)
162 struct sth_device
*sth
= container_of(stm_data
, struct sth_device
, stm
);
164 return intel_th_set_output(to_intel_th_device(sth
->dev
), master
);
167 static int intel_th_sw_init(struct sth_device
*sth
)
171 reg
= ioread32(sth
->base
+ REG_STH_STHCAP1
);
172 sth
->stm
.sw_nchannels
= reg
& 0xff;
174 reg
= ioread32(sth
->base
+ REG_STH_STHCAP0
);
175 sth
->stm
.sw_start
= reg
& 0xffff;
176 sth
->stm
.sw_end
= reg
>> 16;
178 sth
->sw_nmasters
= sth
->stm
.sw_end
- sth
->stm
.sw_start
;
179 dev_dbg(sth
->dev
, "sw_start: %x sw_end: %x masters: %x nchannels: %x\n",
180 sth
->stm
.sw_start
, sth
->stm
.sw_end
, sth
->sw_nmasters
,
181 sth
->stm
.sw_nchannels
);
186 static int intel_th_sth_probe(struct intel_th_device
*thdev
)
188 struct device
*dev
= &thdev
->dev
;
189 struct sth_device
*sth
;
190 struct resource
*res
;
191 void __iomem
*base
, *channels
;
194 res
= intel_th_device_get_resource(thdev
, IORESOURCE_MEM
, 0);
198 base
= devm_ioremap(dev
, res
->start
, resource_size(res
));
202 res
= intel_th_device_get_resource(thdev
, IORESOURCE_MEM
, 1);
206 channels
= devm_ioremap(dev
, res
->start
, resource_size(res
));
210 sth
= devm_kzalloc(dev
, sizeof(*sth
), GFP_KERNEL
);
216 sth
->channels
= channels
;
217 sth
->channels_phys
= res
->start
;
218 sth
->stm
.name
= dev_name(dev
);
219 sth
->stm
.packet
= sth_stm_packet
;
220 sth
->stm
.mmio_addr
= sth_stm_mmio_addr
;
221 sth
->stm
.sw_mmiosz
= sizeof(struct intel_th_channel
);
222 sth
->stm
.link
= sth_stm_link
;
224 err
= intel_th_sw_init(sth
);
228 err
= stm_register_device(dev
, &sth
->stm
, THIS_MODULE
);
230 dev_err(dev
, "stm_register_device failed\n");
234 dev_set_drvdata(dev
, sth
);
239 static void intel_th_sth_remove(struct intel_th_device
*thdev
)
241 struct sth_device
*sth
= dev_get_drvdata(&thdev
->dev
);
243 stm_unregister_device(&sth
->stm
);
246 static struct intel_th_driver intel_th_sth_driver
= {
247 .probe
= intel_th_sth_probe
,
248 .remove
= intel_th_sth_remove
,
251 .owner
= THIS_MODULE
,
255 module_driver(intel_th_sth_driver
,
256 intel_th_driver_register
,
257 intel_th_driver_unregister
);
259 MODULE_LICENSE("GPL v2");
260 MODULE_DESCRIPTION("Intel(R) Trace Hub Software Trace Hub driver");
261 MODULE_AUTHOR("Alexander Shishkin <alexander.shishkin@intel.com>");