xref: /openbmc/linux/drivers/hwtracing/intel_th/sth.c (revision 4b4193256c8d3bc3a5397b5cd9494c2ad386317d)
150352fa7SAlexander Shishkin // SPDX-License-Identifier: GPL-2.0
2f04e449fSAlexander Shishkin /*
3f04e449fSAlexander Shishkin  * Intel(R) Trace Hub Software Trace Hub support
4f04e449fSAlexander Shishkin  *
5f04e449fSAlexander Shishkin  * Copyright (C) 2014-2015 Intel Corporation.
6f04e449fSAlexander Shishkin  */
7f04e449fSAlexander Shishkin 
8f04e449fSAlexander Shishkin #define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
9f04e449fSAlexander Shishkin 
10f04e449fSAlexander Shishkin #include <linux/types.h>
11f04e449fSAlexander Shishkin #include <linux/module.h>
12f04e449fSAlexander Shishkin #include <linux/device.h>
13f04e449fSAlexander Shishkin #include <linux/io.h>
14f04e449fSAlexander Shishkin #include <linux/mm.h>
15f04e449fSAlexander Shishkin #include <linux/slab.h>
16f04e449fSAlexander Shishkin #include <linux/stm.h>
17f04e449fSAlexander Shishkin 
18f04e449fSAlexander Shishkin #include "intel_th.h"
19f04e449fSAlexander Shishkin #include "sth.h"
20f04e449fSAlexander Shishkin 
21f04e449fSAlexander Shishkin struct sth_device {
22f04e449fSAlexander Shishkin 	void __iomem	*base;
23f04e449fSAlexander Shishkin 	void __iomem	*channels;
24f04e449fSAlexander Shishkin 	phys_addr_t	channels_phys;
25f04e449fSAlexander Shishkin 	struct device	*dev;
26f04e449fSAlexander Shishkin 	struct stm_data	stm;
27f04e449fSAlexander Shishkin 	unsigned int	sw_nmasters;
28f04e449fSAlexander Shishkin };
29f04e449fSAlexander Shishkin 
30f04e449fSAlexander Shishkin static struct intel_th_channel __iomem *
sth_channel(struct sth_device * sth,unsigned int master,unsigned int channel)31f04e449fSAlexander Shishkin sth_channel(struct sth_device *sth, unsigned int master, unsigned int channel)
32f04e449fSAlexander Shishkin {
33f04e449fSAlexander Shishkin 	struct intel_th_channel __iomem *sw_map = sth->channels;
34f04e449fSAlexander Shishkin 
35f04e449fSAlexander Shishkin 	return &sw_map[(master - sth->stm.sw_start) * sth->stm.sw_nchannels +
36f04e449fSAlexander Shishkin 		       channel];
37f04e449fSAlexander Shishkin }
38f04e449fSAlexander Shishkin 
sth_iowrite(void __iomem * dest,const unsigned char * payload,unsigned int size)39f04e449fSAlexander Shishkin static void sth_iowrite(void __iomem *dest, const unsigned char *payload,
40f04e449fSAlexander Shishkin 			unsigned int size)
41f04e449fSAlexander Shishkin {
42f04e449fSAlexander Shishkin 	switch (size) {
43f04e449fSAlexander Shishkin #ifdef CONFIG_64BIT
44f04e449fSAlexander Shishkin 	case 8:
45f04e449fSAlexander Shishkin 		writeq_relaxed(*(u64 *)payload, dest);
46f04e449fSAlexander Shishkin 		break;
47f04e449fSAlexander Shishkin #endif
48f04e449fSAlexander Shishkin 	case 4:
49f04e449fSAlexander Shishkin 		writel_relaxed(*(u32 *)payload, dest);
50f04e449fSAlexander Shishkin 		break;
51f04e449fSAlexander Shishkin 	case 2:
52f04e449fSAlexander Shishkin 		writew_relaxed(*(u16 *)payload, dest);
53f04e449fSAlexander Shishkin 		break;
54f04e449fSAlexander Shishkin 	case 1:
55f04e449fSAlexander Shishkin 		writeb_relaxed(*(u8 *)payload, dest);
56f04e449fSAlexander Shishkin 		break;
57f04e449fSAlexander Shishkin 	default:
58f04e449fSAlexander Shishkin 		break;
59f04e449fSAlexander Shishkin 	}
60f04e449fSAlexander Shishkin }
61f04e449fSAlexander Shishkin 
sth_stm_packet(struct stm_data * stm_data,unsigned int master,unsigned int channel,unsigned int packet,unsigned int flags,unsigned int size,const unsigned char * payload)6222975be2SChunyan Zhang static ssize_t notrace sth_stm_packet(struct stm_data *stm_data,
6322975be2SChunyan Zhang 				      unsigned int master,
6422975be2SChunyan Zhang 				      unsigned int channel,
6522975be2SChunyan Zhang 				      unsigned int packet,
6622975be2SChunyan Zhang 				      unsigned int flags,
6722975be2SChunyan Zhang 				      unsigned int size,
68f04e449fSAlexander Shishkin 				      const unsigned char *payload)
69f04e449fSAlexander Shishkin {
70f04e449fSAlexander Shishkin 	struct sth_device *sth = container_of(stm_data, struct sth_device, stm);
71f04e449fSAlexander Shishkin 	struct intel_th_channel __iomem *out =
72f04e449fSAlexander Shishkin 		sth_channel(sth, master, channel);
73f04e449fSAlexander Shishkin 	u64 __iomem *outp = &out->Dn;
74f04e449fSAlexander Shishkin 	unsigned long reg = REG_STH_TRIG;
75f04e449fSAlexander Shishkin 
76f04e449fSAlexander Shishkin #ifndef CONFIG_64BIT
77f04e449fSAlexander Shishkin 	if (size > 4)
78f04e449fSAlexander Shishkin 		size = 4;
79f04e449fSAlexander Shishkin #endif
80f04e449fSAlexander Shishkin 
81f04e449fSAlexander Shishkin 	size = rounddown_pow_of_two(size);
82f04e449fSAlexander Shishkin 
83f04e449fSAlexander Shishkin 	switch (packet) {
84f04e449fSAlexander Shishkin 	/* Global packets (GERR, XSYNC, TRIG) are sent with register writes */
85f04e449fSAlexander Shishkin 	case STP_PACKET_GERR:
86f04e449fSAlexander Shishkin 		reg += 4;
87*df561f66SGustavo A. R. Silva 		fallthrough;
888d86f6b4SGustavo A. R. Silva 
89f04e449fSAlexander Shishkin 	case STP_PACKET_XSYNC:
90f04e449fSAlexander Shishkin 		reg += 8;
91*df561f66SGustavo A. R. Silva 		fallthrough;
928d86f6b4SGustavo A. R. Silva 
93f04e449fSAlexander Shishkin 	case STP_PACKET_TRIG:
94f04e449fSAlexander Shishkin 		if (flags & STP_PACKET_TIMESTAMPED)
95f04e449fSAlexander Shishkin 			reg += 4;
9697007500SAlexander Shishkin 		writeb_relaxed(*payload, sth->base + reg);
97f04e449fSAlexander Shishkin 		break;
98f04e449fSAlexander Shishkin 
99f04e449fSAlexander Shishkin 	case STP_PACKET_MERR:
10097007500SAlexander Shishkin 		if (size > 4)
10197007500SAlexander Shishkin 			size = 4;
10297007500SAlexander Shishkin 
103f04e449fSAlexander Shishkin 		sth_iowrite(&out->MERR, payload, size);
104f04e449fSAlexander Shishkin 		break;
105f04e449fSAlexander Shishkin 
106f04e449fSAlexander Shishkin 	case STP_PACKET_FLAG:
107f04e449fSAlexander Shishkin 		if (flags & STP_PACKET_TIMESTAMPED)
108f04e449fSAlexander Shishkin 			outp = (u64 __iomem *)&out->FLAG_TS;
109f04e449fSAlexander Shishkin 		else
110f04e449fSAlexander Shishkin 			outp = (u64 __iomem *)&out->FLAG;
111f04e449fSAlexander Shishkin 
11297007500SAlexander Shishkin 		size = 0;
11397007500SAlexander Shishkin 		writeb_relaxed(0, outp);
114f04e449fSAlexander Shishkin 		break;
115f04e449fSAlexander Shishkin 
116f04e449fSAlexander Shishkin 	case STP_PACKET_USER:
117f04e449fSAlexander Shishkin 		if (flags & STP_PACKET_TIMESTAMPED)
118f04e449fSAlexander Shishkin 			outp = &out->USER_TS;
119f04e449fSAlexander Shishkin 		else
120f04e449fSAlexander Shishkin 			outp = &out->USER;
121f04e449fSAlexander Shishkin 		sth_iowrite(outp, payload, size);
122f04e449fSAlexander Shishkin 		break;
123f04e449fSAlexander Shishkin 
124f04e449fSAlexander Shishkin 	case STP_PACKET_DATA:
125f04e449fSAlexander Shishkin 		outp = &out->Dn;
126f04e449fSAlexander Shishkin 
127f04e449fSAlexander Shishkin 		if (flags & STP_PACKET_TIMESTAMPED)
128f04e449fSAlexander Shishkin 			outp += 2;
129f04e449fSAlexander Shishkin 		if (flags & STP_PACKET_MARKED)
130f04e449fSAlexander Shishkin 			outp++;
131f04e449fSAlexander Shishkin 
132f04e449fSAlexander Shishkin 		sth_iowrite(outp, payload, size);
133f04e449fSAlexander Shishkin 		break;
13497007500SAlexander Shishkin 	default:
13597007500SAlexander Shishkin 		return -ENOTSUPP;
136f04e449fSAlexander Shishkin 	}
137f04e449fSAlexander Shishkin 
138f04e449fSAlexander Shishkin 	return size;
139f04e449fSAlexander Shishkin }
140f04e449fSAlexander Shishkin 
141f04e449fSAlexander Shishkin static phys_addr_t
sth_stm_mmio_addr(struct stm_data * stm_data,unsigned int master,unsigned int channel,unsigned int nr_chans)142f04e449fSAlexander Shishkin sth_stm_mmio_addr(struct stm_data *stm_data, unsigned int master,
143f04e449fSAlexander Shishkin 		  unsigned int channel, unsigned int nr_chans)
144f04e449fSAlexander Shishkin {
145f04e449fSAlexander Shishkin 	struct sth_device *sth = container_of(stm_data, struct sth_device, stm);
146f04e449fSAlexander Shishkin 	phys_addr_t addr;
147f04e449fSAlexander Shishkin 
148f04e449fSAlexander Shishkin 	master -= sth->stm.sw_start;
149f04e449fSAlexander Shishkin 	addr = sth->channels_phys + (master * sth->stm.sw_nchannels + channel) *
150f04e449fSAlexander Shishkin 		sizeof(struct intel_th_channel);
151f04e449fSAlexander Shishkin 
152f04e449fSAlexander Shishkin 	if (offset_in_page(addr) ||
153f04e449fSAlexander Shishkin 	    offset_in_page(nr_chans * sizeof(struct intel_th_channel)))
154f04e449fSAlexander Shishkin 		return 0;
155f04e449fSAlexander Shishkin 
156f04e449fSAlexander Shishkin 	return addr;
157f04e449fSAlexander Shishkin }
158f04e449fSAlexander Shishkin 
sth_stm_link(struct stm_data * stm_data,unsigned int master,unsigned int channel)159f04e449fSAlexander Shishkin static int sth_stm_link(struct stm_data *stm_data, unsigned int master,
160f04e449fSAlexander Shishkin 			 unsigned int channel)
161f04e449fSAlexander Shishkin {
162f04e449fSAlexander Shishkin 	struct sth_device *sth = container_of(stm_data, struct sth_device, stm);
163f04e449fSAlexander Shishkin 
164e78e1fdbSAlexander Shishkin 	return intel_th_set_output(to_intel_th_device(sth->dev), master);
165f04e449fSAlexander Shishkin }
166f04e449fSAlexander Shishkin 
intel_th_sw_init(struct sth_device * sth)167f04e449fSAlexander Shishkin static int intel_th_sw_init(struct sth_device *sth)
168f04e449fSAlexander Shishkin {
169f04e449fSAlexander Shishkin 	u32 reg;
170f04e449fSAlexander Shishkin 
171f04e449fSAlexander Shishkin 	reg = ioread32(sth->base + REG_STH_STHCAP1);
172f04e449fSAlexander Shishkin 	sth->stm.sw_nchannels = reg & 0xff;
173f04e449fSAlexander Shishkin 
174f04e449fSAlexander Shishkin 	reg = ioread32(sth->base + REG_STH_STHCAP0);
175f04e449fSAlexander Shishkin 	sth->stm.sw_start = reg & 0xffff;
176f04e449fSAlexander Shishkin 	sth->stm.sw_end = reg >> 16;
177f04e449fSAlexander Shishkin 
178f04e449fSAlexander Shishkin 	sth->sw_nmasters = sth->stm.sw_end - sth->stm.sw_start;
179f04e449fSAlexander Shishkin 	dev_dbg(sth->dev, "sw_start: %x sw_end: %x masters: %x nchannels: %x\n",
180f04e449fSAlexander Shishkin 		sth->stm.sw_start, sth->stm.sw_end, sth->sw_nmasters,
181f04e449fSAlexander Shishkin 		sth->stm.sw_nchannels);
182f04e449fSAlexander Shishkin 
183f04e449fSAlexander Shishkin 	return 0;
184f04e449fSAlexander Shishkin }
185f04e449fSAlexander Shishkin 
intel_th_sth_probe(struct intel_th_device * thdev)186f04e449fSAlexander Shishkin static int intel_th_sth_probe(struct intel_th_device *thdev)
187f04e449fSAlexander Shishkin {
188f04e449fSAlexander Shishkin 	struct device *dev = &thdev->dev;
189f04e449fSAlexander Shishkin 	struct sth_device *sth;
190f04e449fSAlexander Shishkin 	struct resource *res;
191f04e449fSAlexander Shishkin 	void __iomem *base, *channels;
192f04e449fSAlexander Shishkin 	int err;
193f04e449fSAlexander Shishkin 
194f04e449fSAlexander Shishkin 	res = intel_th_device_get_resource(thdev, IORESOURCE_MEM, 0);
195f04e449fSAlexander Shishkin 	if (!res)
196f04e449fSAlexander Shishkin 		return -ENODEV;
197f04e449fSAlexander Shishkin 
198f04e449fSAlexander Shishkin 	base = devm_ioremap(dev, res->start, resource_size(res));
19973061da0SDan Carpenter 	if (!base)
20073061da0SDan Carpenter 		return -ENOMEM;
201f04e449fSAlexander Shishkin 
202f04e449fSAlexander Shishkin 	res = intel_th_device_get_resource(thdev, IORESOURCE_MEM, 1);
203f04e449fSAlexander Shishkin 	if (!res)
204f04e449fSAlexander Shishkin 		return -ENODEV;
205f04e449fSAlexander Shishkin 
206f04e449fSAlexander Shishkin 	channels = devm_ioremap(dev, res->start, resource_size(res));
20773061da0SDan Carpenter 	if (!channels)
20873061da0SDan Carpenter 		return -ENOMEM;
209f04e449fSAlexander Shishkin 
210f04e449fSAlexander Shishkin 	sth = devm_kzalloc(dev, sizeof(*sth), GFP_KERNEL);
211f04e449fSAlexander Shishkin 	if (!sth)
212f04e449fSAlexander Shishkin 		return -ENOMEM;
213f04e449fSAlexander Shishkin 
214f04e449fSAlexander Shishkin 	sth->dev = dev;
215f04e449fSAlexander Shishkin 	sth->base = base;
216f04e449fSAlexander Shishkin 	sth->channels = channels;
217f04e449fSAlexander Shishkin 	sth->channels_phys = res->start;
218f04e449fSAlexander Shishkin 	sth->stm.name = dev_name(dev);
219f04e449fSAlexander Shishkin 	sth->stm.packet = sth_stm_packet;
220f04e449fSAlexander Shishkin 	sth->stm.mmio_addr = sth_stm_mmio_addr;
221f04e449fSAlexander Shishkin 	sth->stm.sw_mmiosz = sizeof(struct intel_th_channel);
222f04e449fSAlexander Shishkin 	sth->stm.link = sth_stm_link;
223f04e449fSAlexander Shishkin 
224f04e449fSAlexander Shishkin 	err = intel_th_sw_init(sth);
225f04e449fSAlexander Shishkin 	if (err)
226f04e449fSAlexander Shishkin 		return err;
227f04e449fSAlexander Shishkin 
228f04e449fSAlexander Shishkin 	err = stm_register_device(dev, &sth->stm, THIS_MODULE);
229f04e449fSAlexander Shishkin 	if (err) {
230f04e449fSAlexander Shishkin 		dev_err(dev, "stm_register_device failed\n");
231f04e449fSAlexander Shishkin 		return err;
232f04e449fSAlexander Shishkin 	}
233f04e449fSAlexander Shishkin 
234f04e449fSAlexander Shishkin 	dev_set_drvdata(dev, sth);
235f04e449fSAlexander Shishkin 
236f04e449fSAlexander Shishkin 	return 0;
237f04e449fSAlexander Shishkin }
238f04e449fSAlexander Shishkin 
intel_th_sth_remove(struct intel_th_device * thdev)239f04e449fSAlexander Shishkin static void intel_th_sth_remove(struct intel_th_device *thdev)
240f04e449fSAlexander Shishkin {
241f04e449fSAlexander Shishkin 	struct sth_device *sth = dev_get_drvdata(&thdev->dev);
242f04e449fSAlexander Shishkin 
243f04e449fSAlexander Shishkin 	stm_unregister_device(&sth->stm);
244f04e449fSAlexander Shishkin }
245f04e449fSAlexander Shishkin 
246f04e449fSAlexander Shishkin static struct intel_th_driver intel_th_sth_driver = {
247f04e449fSAlexander Shishkin 	.probe	= intel_th_sth_probe,
248f04e449fSAlexander Shishkin 	.remove	= intel_th_sth_remove,
249f04e449fSAlexander Shishkin 	.driver	= {
250f04e449fSAlexander Shishkin 		.name	= "sth",
251f04e449fSAlexander Shishkin 		.owner	= THIS_MODULE,
252f04e449fSAlexander Shishkin 	},
253f04e449fSAlexander Shishkin };
254f04e449fSAlexander Shishkin 
255f04e449fSAlexander Shishkin module_driver(intel_th_sth_driver,
256f04e449fSAlexander Shishkin 	      intel_th_driver_register,
257f04e449fSAlexander Shishkin 	      intel_th_driver_unregister);
258f04e449fSAlexander Shishkin 
259f04e449fSAlexander Shishkin MODULE_LICENSE("GPL v2");
260f04e449fSAlexander Shishkin MODULE_DESCRIPTION("Intel(R) Trace Hub Software Trace Hub driver");
261f04e449fSAlexander Shishkin MODULE_AUTHOR("Alexander Shishkin <alexander.shishkin@intel.com>");
262