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