xref: /openbmc/linux/drivers/misc/echo/fir.h (revision 82c29810)
182c29810SThomas 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