1*82c29810SThomas Gleixner /* SPDX-License-Identifier: GPL-2.0-only */
26e2055a9SGreg Kroah-Hartman /*
36e2055a9SGreg Kroah-Hartman * SpanDSP - a series of DSP components for telephony
46e2055a9SGreg Kroah-Hartman *
56e2055a9SGreg Kroah-Hartman * fir.h - General telephony FIR routines
66e2055a9SGreg Kroah-Hartman *
76e2055a9SGreg Kroah-Hartman * Written by Steve Underwood <steveu@coppice.org>
86e2055a9SGreg Kroah-Hartman *
96e2055a9SGreg Kroah-Hartman * Copyright (C) 2002 Steve Underwood
106e2055a9SGreg Kroah-Hartman *
116e2055a9SGreg Kroah-Hartman * All rights reserved.
126e2055a9SGreg Kroah-Hartman */
136e2055a9SGreg Kroah-Hartman
146e2055a9SGreg Kroah-Hartman #if !defined(_FIR_H_)
156e2055a9SGreg Kroah-Hartman #define _FIR_H_
166e2055a9SGreg Kroah-Hartman
176e2055a9SGreg Kroah-Hartman /*
186e2055a9SGreg Kroah-Hartman Ideas for improvement:
196e2055a9SGreg Kroah-Hartman
206e2055a9SGreg Kroah-Hartman 1/ Rewrite filter for dual MAC inner loop. The issue here is handling
216e2055a9SGreg Kroah-Hartman history sample offsets that are 16 bit aligned - the dual MAC needs
226e2055a9SGreg Kroah-Hartman 32 bit aligmnent. There are some good examples in libbfdsp.
236e2055a9SGreg Kroah-Hartman
246e2055a9SGreg Kroah-Hartman 2/ Use the hardware circular buffer facility tohalve memory usage.
256e2055a9SGreg Kroah-Hartman
266e2055a9SGreg Kroah-Hartman 3/ Consider using internal memory.
276e2055a9SGreg Kroah-Hartman
286e2055a9SGreg Kroah-Hartman Using less memory might also improve speed as cache misses will be
296e2055a9SGreg Kroah-Hartman reduced. A drop in MIPs and memory approaching 50% should be
306e2055a9SGreg Kroah-Hartman possible.
316e2055a9SGreg Kroah-Hartman
326e2055a9SGreg Kroah-Hartman The foreground and background filters currenlty use a total of
336e2055a9SGreg Kroah-Hartman about 10 MIPs/ch as measured with speedtest.c on a 256 TAP echo
346e2055a9SGreg Kroah-Hartman can.
356e2055a9SGreg Kroah-Hartman */
366e2055a9SGreg Kroah-Hartman
376e2055a9SGreg Kroah-Hartman /*
386e2055a9SGreg Kroah-Hartman * 16 bit integer FIR descriptor. This defines the working state for a single
396e2055a9SGreg Kroah-Hartman * instance of an FIR filter using 16 bit integer coefficients.
406e2055a9SGreg Kroah-Hartman */
416e2055a9SGreg Kroah-Hartman struct fir16_state_t {
426e2055a9SGreg Kroah-Hartman int taps;
436e2055a9SGreg Kroah-Hartman int curr_pos;
446e2055a9SGreg Kroah-Hartman const int16_t *coeffs;
456e2055a9SGreg Kroah-Hartman int16_t *history;
466e2055a9SGreg Kroah-Hartman };
476e2055a9SGreg Kroah-Hartman
486e2055a9SGreg Kroah-Hartman /*
496e2055a9SGreg Kroah-Hartman * 32 bit integer FIR descriptor. This defines the working state for a single
506e2055a9SGreg Kroah-Hartman * instance of an FIR filter using 32 bit integer coefficients, and filtering
516e2055a9SGreg Kroah-Hartman * 16 bit integer data.
526e2055a9SGreg Kroah-Hartman */
536e2055a9SGreg Kroah-Hartman struct fir32_state_t {
546e2055a9SGreg Kroah-Hartman int taps;
556e2055a9SGreg Kroah-Hartman int curr_pos;
566e2055a9SGreg Kroah-Hartman const int32_t *coeffs;
576e2055a9SGreg Kroah-Hartman int16_t *history;
586e2055a9SGreg Kroah-Hartman };
596e2055a9SGreg Kroah-Hartman
606e2055a9SGreg Kroah-Hartman /*
616e2055a9SGreg Kroah-Hartman * Floating point FIR descriptor. This defines the working state for a single
626e2055a9SGreg Kroah-Hartman * instance of an FIR filter using floating point coefficients and data.
636e2055a9SGreg Kroah-Hartman */
646e2055a9SGreg Kroah-Hartman struct fir_float_state_t {
656e2055a9SGreg Kroah-Hartman int taps;
666e2055a9SGreg Kroah-Hartman int curr_pos;
676e2055a9SGreg Kroah-Hartman const float *coeffs;
686e2055a9SGreg Kroah-Hartman float *history;
696e2055a9SGreg Kroah-Hartman };
706e2055a9SGreg Kroah-Hartman
fir16_create(struct fir16_state_t * fir,const int16_t * coeffs,int taps)716e2055a9SGreg Kroah-Hartman static inline const int16_t *fir16_create(struct fir16_state_t *fir,
726e2055a9SGreg Kroah-Hartman const int16_t *coeffs, int taps)
736e2055a9SGreg Kroah-Hartman {
746e2055a9SGreg Kroah-Hartman fir->taps = taps;
756e2055a9SGreg Kroah-Hartman fir->curr_pos = taps - 1;
766e2055a9SGreg Kroah-Hartman fir->coeffs = coeffs;
776e2055a9SGreg Kroah-Hartman fir->history = kcalloc(taps, sizeof(int16_t), GFP_KERNEL);
786e2055a9SGreg Kroah-Hartman return fir->history;
796e2055a9SGreg Kroah-Hartman }
806e2055a9SGreg Kroah-Hartman
fir16_flush(struct fir16_state_t * fir)816e2055a9SGreg Kroah-Hartman static inline void fir16_flush(struct fir16_state_t *fir)
826e2055a9SGreg Kroah-Hartman {
836e2055a9SGreg Kroah-Hartman memset(fir->history, 0, fir->taps * sizeof(int16_t));
846e2055a9SGreg Kroah-Hartman }
856e2055a9SGreg Kroah-Hartman
fir16_free(struct fir16_state_t * fir)866e2055a9SGreg Kroah-Hartman static inline void fir16_free(struct fir16_state_t *fir)
876e2055a9SGreg Kroah-Hartman {
886e2055a9SGreg Kroah-Hartman kfree(fir->history);
896e2055a9SGreg Kroah-Hartman }
906e2055a9SGreg Kroah-Hartman
fir16(struct fir16_state_t * fir,int16_t sample)916e2055a9SGreg Kroah-Hartman static inline int16_t fir16(struct fir16_state_t *fir, int16_t sample)
926e2055a9SGreg Kroah-Hartman {
936e2055a9SGreg Kroah-Hartman int32_t y;
946e2055a9SGreg Kroah-Hartman int i;
956e2055a9SGreg Kroah-Hartman int offset1;
966e2055a9SGreg Kroah-Hartman int offset2;
976e2055a9SGreg Kroah-Hartman
986e2055a9SGreg Kroah-Hartman fir->history[fir->curr_pos] = sample;
996e2055a9SGreg Kroah-Hartman
1006e2055a9SGreg Kroah-Hartman offset2 = fir->curr_pos;
1016e2055a9SGreg Kroah-Hartman offset1 = fir->taps - offset2;
1026e2055a9SGreg Kroah-Hartman y = 0;
1036e2055a9SGreg Kroah-Hartman for (i = fir->taps - 1; i >= offset1; i--)
1046e2055a9SGreg Kroah-Hartman y += fir->coeffs[i] * fir->history[i - offset1];
1056e2055a9SGreg Kroah-Hartman for (; i >= 0; i--)
1066e2055a9SGreg Kroah-Hartman y += fir->coeffs[i] * fir->history[i + offset2];
1076e2055a9SGreg Kroah-Hartman if (fir->curr_pos <= 0)
1086e2055a9SGreg Kroah-Hartman fir->curr_pos = fir->taps;
1096e2055a9SGreg Kroah-Hartman fir->curr_pos--;
1106e2055a9SGreg Kroah-Hartman return (int16_t) (y >> 15);
1116e2055a9SGreg Kroah-Hartman }
1126e2055a9SGreg Kroah-Hartman
fir32_create(struct fir32_state_t * fir,const int32_t * coeffs,int taps)1136e2055a9SGreg Kroah-Hartman static inline const int16_t *fir32_create(struct fir32_state_t *fir,
1146e2055a9SGreg Kroah-Hartman const int32_t *coeffs, int taps)
1156e2055a9SGreg Kroah-Hartman {
1166e2055a9SGreg Kroah-Hartman fir->taps = taps;
1176e2055a9SGreg Kroah-Hartman fir->curr_pos = taps - 1;
1186e2055a9SGreg Kroah-Hartman fir->coeffs = coeffs;
1196e2055a9SGreg Kroah-Hartman fir->history = kcalloc(taps, sizeof(int16_t), GFP_KERNEL);
1206e2055a9SGreg Kroah-Hartman return fir->history;
1216e2055a9SGreg Kroah-Hartman }
1226e2055a9SGreg Kroah-Hartman
fir32_flush(struct fir32_state_t * fir)1236e2055a9SGreg Kroah-Hartman static inline void fir32_flush(struct fir32_state_t *fir)
1246e2055a9SGreg Kroah-Hartman {
1256e2055a9SGreg Kroah-Hartman memset(fir->history, 0, fir->taps * sizeof(int16_t));
1266e2055a9SGreg Kroah-Hartman }
1276e2055a9SGreg Kroah-Hartman
fir32_free(struct fir32_state_t * fir)1286e2055a9SGreg Kroah-Hartman static inline void fir32_free(struct fir32_state_t *fir)
1296e2055a9SGreg Kroah-Hartman {
1306e2055a9SGreg Kroah-Hartman kfree(fir->history);
1316e2055a9SGreg Kroah-Hartman }
1326e2055a9SGreg Kroah-Hartman
fir32(struct fir32_state_t * fir,int16_t sample)1336e2055a9SGreg Kroah-Hartman static inline int16_t fir32(struct fir32_state_t *fir, int16_t sample)
1346e2055a9SGreg Kroah-Hartman {
1356e2055a9SGreg Kroah-Hartman int i;
1366e2055a9SGreg Kroah-Hartman int32_t y;
1376e2055a9SGreg Kroah-Hartman int offset1;
1386e2055a9SGreg Kroah-Hartman int offset2;
1396e2055a9SGreg Kroah-Hartman
1406e2055a9SGreg Kroah-Hartman fir->history[fir->curr_pos] = sample;
1416e2055a9SGreg Kroah-Hartman offset2 = fir->curr_pos;
1426e2055a9SGreg Kroah-Hartman offset1 = fir->taps - offset2;
1436e2055a9SGreg Kroah-Hartman y = 0;
1446e2055a9SGreg Kroah-Hartman for (i = fir->taps - 1; i >= offset1; i--)
1456e2055a9SGreg Kroah-Hartman y += fir->coeffs[i] * fir->history[i - offset1];
1466e2055a9SGreg Kroah-Hartman for (; i >= 0; i--)
1476e2055a9SGreg Kroah-Hartman y += fir->coeffs[i] * fir->history[i + offset2];
1486e2055a9SGreg Kroah-Hartman if (fir->curr_pos <= 0)
1496e2055a9SGreg Kroah-Hartman fir->curr_pos = fir->taps;
1506e2055a9SGreg Kroah-Hartman fir->curr_pos--;
1516e2055a9SGreg Kroah-Hartman return (int16_t) (y >> 15);
1526e2055a9SGreg Kroah-Hartman }
1536e2055a9SGreg Kroah-Hartman
1546e2055a9SGreg Kroah-Hartman #endif
155