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