xref: /OK3568_Linux_fs/kernel/sound/firewire/fireface/amdtp-ff.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * amdtp-ff.c - a part of driver for RME Fireface series
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (c) 2015-2017 Takashi Sakamoto
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include <sound/pcm.h>
9*4882a593Smuzhiyun #include "ff.h"
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun struct amdtp_ff {
12*4882a593Smuzhiyun 	unsigned int pcm_channels;
13*4882a593Smuzhiyun };
14*4882a593Smuzhiyun 
amdtp_ff_set_parameters(struct amdtp_stream * s,unsigned int rate,unsigned int pcm_channels)15*4882a593Smuzhiyun int amdtp_ff_set_parameters(struct amdtp_stream *s, unsigned int rate,
16*4882a593Smuzhiyun 			    unsigned int pcm_channels)
17*4882a593Smuzhiyun {
18*4882a593Smuzhiyun 	struct amdtp_ff *p = s->protocol;
19*4882a593Smuzhiyun 	unsigned int data_channels;
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun 	if (amdtp_stream_running(s))
22*4882a593Smuzhiyun 		return -EBUSY;
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun 	p->pcm_channels = pcm_channels;
25*4882a593Smuzhiyun 	data_channels = pcm_channels;
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun 	return amdtp_stream_set_parameters(s, rate, data_channels);
28*4882a593Smuzhiyun }
29*4882a593Smuzhiyun 
write_pcm_s32(struct amdtp_stream * s,struct snd_pcm_substream * pcm,__le32 * buffer,unsigned int frames,unsigned int pcm_frames)30*4882a593Smuzhiyun static void write_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm,
31*4882a593Smuzhiyun 			  __le32 *buffer, unsigned int frames,
32*4882a593Smuzhiyun 			  unsigned int pcm_frames)
33*4882a593Smuzhiyun {
34*4882a593Smuzhiyun 	struct amdtp_ff *p = s->protocol;
35*4882a593Smuzhiyun 	unsigned int channels = p->pcm_channels;
36*4882a593Smuzhiyun 	struct snd_pcm_runtime *runtime = pcm->runtime;
37*4882a593Smuzhiyun 	unsigned int pcm_buffer_pointer;
38*4882a593Smuzhiyun 	int remaining_frames;
39*4882a593Smuzhiyun 	const u32 *src;
40*4882a593Smuzhiyun 	int i, c;
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun 	pcm_buffer_pointer = s->pcm_buffer_pointer + pcm_frames;
43*4882a593Smuzhiyun 	pcm_buffer_pointer %= runtime->buffer_size;
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun 	src = (void *)runtime->dma_area +
46*4882a593Smuzhiyun 				frames_to_bytes(runtime, pcm_buffer_pointer);
47*4882a593Smuzhiyun 	remaining_frames = runtime->buffer_size - pcm_buffer_pointer;
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun 	for (i = 0; i < frames; ++i) {
50*4882a593Smuzhiyun 		for (c = 0; c < channels; ++c) {
51*4882a593Smuzhiyun 			buffer[c] = cpu_to_le32(*src);
52*4882a593Smuzhiyun 			src++;
53*4882a593Smuzhiyun 		}
54*4882a593Smuzhiyun 		buffer += s->data_block_quadlets;
55*4882a593Smuzhiyun 		if (--remaining_frames == 0)
56*4882a593Smuzhiyun 			src = (void *)runtime->dma_area;
57*4882a593Smuzhiyun 	}
58*4882a593Smuzhiyun }
59*4882a593Smuzhiyun 
read_pcm_s32(struct amdtp_stream * s,struct snd_pcm_substream * pcm,__le32 * buffer,unsigned int frames,unsigned int pcm_frames)60*4882a593Smuzhiyun static void read_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm,
61*4882a593Smuzhiyun 			 __le32 *buffer, unsigned int frames,
62*4882a593Smuzhiyun 			 unsigned int pcm_frames)
63*4882a593Smuzhiyun {
64*4882a593Smuzhiyun 	struct amdtp_ff *p = s->protocol;
65*4882a593Smuzhiyun 	unsigned int channels = p->pcm_channels;
66*4882a593Smuzhiyun 	struct snd_pcm_runtime *runtime = pcm->runtime;
67*4882a593Smuzhiyun 	unsigned int pcm_buffer_pointer;
68*4882a593Smuzhiyun 	int remaining_frames;
69*4882a593Smuzhiyun 	u32 *dst;
70*4882a593Smuzhiyun 	int i, c;
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun 	pcm_buffer_pointer = s->pcm_buffer_pointer + pcm_frames;
73*4882a593Smuzhiyun 	pcm_buffer_pointer %= runtime->buffer_size;
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun 	dst  = (void *)runtime->dma_area +
76*4882a593Smuzhiyun 				frames_to_bytes(runtime, pcm_buffer_pointer);
77*4882a593Smuzhiyun 	remaining_frames = runtime->buffer_size - pcm_buffer_pointer;
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 	for (i = 0; i < frames; ++i) {
80*4882a593Smuzhiyun 		for (c = 0; c < channels; ++c) {
81*4882a593Smuzhiyun 			*dst = le32_to_cpu(buffer[c]) & 0xffffff00;
82*4882a593Smuzhiyun 			dst++;
83*4882a593Smuzhiyun 		}
84*4882a593Smuzhiyun 		buffer += s->data_block_quadlets;
85*4882a593Smuzhiyun 		if (--remaining_frames == 0)
86*4882a593Smuzhiyun 			dst = (void *)runtime->dma_area;
87*4882a593Smuzhiyun 	}
88*4882a593Smuzhiyun }
89*4882a593Smuzhiyun 
write_pcm_silence(struct amdtp_stream * s,__le32 * buffer,unsigned int frames)90*4882a593Smuzhiyun static void write_pcm_silence(struct amdtp_stream *s,
91*4882a593Smuzhiyun 			      __le32 *buffer, unsigned int frames)
92*4882a593Smuzhiyun {
93*4882a593Smuzhiyun 	struct amdtp_ff *p = s->protocol;
94*4882a593Smuzhiyun 	unsigned int i, c, channels = p->pcm_channels;
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 	for (i = 0; i < frames; ++i) {
97*4882a593Smuzhiyun 		for (c = 0; c < channels; ++c)
98*4882a593Smuzhiyun 			buffer[c] = cpu_to_le32(0x00000000);
99*4882a593Smuzhiyun 		buffer += s->data_block_quadlets;
100*4882a593Smuzhiyun 	}
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun 
amdtp_ff_add_pcm_hw_constraints(struct amdtp_stream * s,struct snd_pcm_runtime * runtime)103*4882a593Smuzhiyun int amdtp_ff_add_pcm_hw_constraints(struct amdtp_stream *s,
104*4882a593Smuzhiyun 				    struct snd_pcm_runtime *runtime)
105*4882a593Smuzhiyun {
106*4882a593Smuzhiyun 	int err;
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun 	err = snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
109*4882a593Smuzhiyun 	if (err < 0)
110*4882a593Smuzhiyun 		return err;
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun 	return amdtp_stream_add_pcm_hw_constraints(s, runtime);
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun 
process_it_ctx_payloads(struct amdtp_stream * s,const struct pkt_desc * descs,unsigned int packets,struct snd_pcm_substream * pcm)115*4882a593Smuzhiyun static unsigned int process_it_ctx_payloads(struct amdtp_stream *s,
116*4882a593Smuzhiyun 					   const struct pkt_desc *descs,
117*4882a593Smuzhiyun 					   unsigned int packets,
118*4882a593Smuzhiyun 					   struct snd_pcm_substream *pcm)
119*4882a593Smuzhiyun {
120*4882a593Smuzhiyun 	unsigned int pcm_frames = 0;
121*4882a593Smuzhiyun 	int i;
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 	for (i = 0; i < packets; ++i) {
124*4882a593Smuzhiyun 		const struct pkt_desc *desc = descs + i;
125*4882a593Smuzhiyun 		__le32 *buf = (__le32 *)desc->ctx_payload;
126*4882a593Smuzhiyun 		unsigned int data_blocks = desc->data_blocks;
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 		if (pcm) {
129*4882a593Smuzhiyun 			write_pcm_s32(s, pcm, buf, data_blocks, pcm_frames);
130*4882a593Smuzhiyun 			pcm_frames += data_blocks;
131*4882a593Smuzhiyun 		} else {
132*4882a593Smuzhiyun 			write_pcm_silence(s, buf, data_blocks);
133*4882a593Smuzhiyun 		}
134*4882a593Smuzhiyun 	}
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 	return pcm_frames;
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun 
process_ir_ctx_payloads(struct amdtp_stream * s,const struct pkt_desc * descs,unsigned int packets,struct snd_pcm_substream * pcm)139*4882a593Smuzhiyun static unsigned int process_ir_ctx_payloads(struct amdtp_stream *s,
140*4882a593Smuzhiyun 					    const struct pkt_desc *descs,
141*4882a593Smuzhiyun 					    unsigned int packets,
142*4882a593Smuzhiyun 					    struct snd_pcm_substream *pcm)
143*4882a593Smuzhiyun {
144*4882a593Smuzhiyun 	unsigned int pcm_frames = 0;
145*4882a593Smuzhiyun 	int i;
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	for (i = 0; i < packets; ++i) {
148*4882a593Smuzhiyun 		const struct pkt_desc *desc = descs + i;
149*4882a593Smuzhiyun 		__le32 *buf = (__le32 *)desc->ctx_payload;
150*4882a593Smuzhiyun 		unsigned int data_blocks = desc->data_blocks;
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 		if (pcm) {
153*4882a593Smuzhiyun 			read_pcm_s32(s, pcm, buf, data_blocks, pcm_frames);
154*4882a593Smuzhiyun 			pcm_frames += data_blocks;
155*4882a593Smuzhiyun 		}
156*4882a593Smuzhiyun 	}
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 	return pcm_frames;
159*4882a593Smuzhiyun }
160*4882a593Smuzhiyun 
amdtp_ff_init(struct amdtp_stream * s,struct fw_unit * unit,enum amdtp_stream_direction dir)161*4882a593Smuzhiyun int amdtp_ff_init(struct amdtp_stream *s, struct fw_unit *unit,
162*4882a593Smuzhiyun 		  enum amdtp_stream_direction dir)
163*4882a593Smuzhiyun {
164*4882a593Smuzhiyun 	amdtp_stream_process_ctx_payloads_t process_ctx_payloads;
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 	if (dir == AMDTP_IN_STREAM)
167*4882a593Smuzhiyun 		process_ctx_payloads = process_ir_ctx_payloads;
168*4882a593Smuzhiyun 	else
169*4882a593Smuzhiyun 		process_ctx_payloads = process_it_ctx_payloads;
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 	return amdtp_stream_init(s, unit, dir, CIP_NO_HEADER, 0,
172*4882a593Smuzhiyun 				 process_ctx_payloads, sizeof(struct amdtp_ff));
173*4882a593Smuzhiyun }
174