Linux Audio

Check our new training course

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