aboutsummaryrefslogtreecommitdiff
path: root/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_qmath.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/brcm80211/brcmsmac/phy/phy_qmath.c')
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/phy/phy_qmath.c308
1 files changed, 308 insertions, 0 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_qmath.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_qmath.c
new file mode 100644
index 00000000000..faf1ebe7606
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_qmath.c
@@ -0,0 +1,308 @@
+/*
+ * Copyright (c) 2010 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "phy_qmath.h"
+
+/*
+ * Description: This function make 16 bit unsigned multiplication.
+ * To fit the output into 16 bits the 32 bit multiplication result is right
+ * shifted by 16 bits.
+ */
+u16 qm_mulu16(u16 op1, u16 op2)
+{
+ return (u16) (((u32) op1 * (u32) op2) >> 16);
+}
+
+/*
+ * Description: This function make 16 bit multiplication and return the result
+ * in 16 bits. To fit the multiplication result into 16 bits the multiplication
+ * result is right shifted by 15 bits. Right shifting 15 bits instead of 16 bits
+ * is done to remove the extra sign bit formed due to the multiplication.
+ * When both the 16bit inputs are 0x8000 then the output is saturated to
+ * 0x7fffffff.
+ */
+s16 qm_muls16(s16 op1, s16 op2)
+{
+ s32 result;
+ if (op1 == (s16) 0x8000 && op2 == (s16) 0x8000)
+ result = 0x7fffffff;
+ else
+ result = ((s32) (op1) * (s32) (op2));
+
+ return (s16) (result >> 15);
+}
+
+/*
+ * Description: This function add two 32 bit numbers and return the 32bit
+ * result. If the result overflow 32 bits, the output will be saturated to
+ * 32bits.
+ */
+s32 qm_add32(s32 op1, s32 op2)
+{
+ s32 result;
+ result = op1 + op2;
+ if (op1 < 0 && op2 < 0 && result > 0)
+ result = 0x80000000;
+ else if (op1 > 0 && op2 > 0 && result < 0)
+ result = 0x7fffffff;
+
+ return result;
+}
+
+/*
+ * Description: This function add two 16 bit numbers and return the 16bit
+ * result. If the result overflow 16 bits, the output will be saturated to
+ * 16bits.
+ */
+s16 qm_add16(s16 op1, s16 op2)
+{
+ s16 result;
+ s32 temp = (s32) op1 + (s32) op2;
+ if (temp > (s32) 0x7fff)
+ result = (s16) 0x7fff;
+ else if (temp < (s32) 0xffff8000)
+ result = (s16) 0xffff8000;
+ else
+ result = (s16) temp;
+
+ return result;
+}
+
+/*
+ * Description: This function make 16 bit subtraction and return the 16bit
+ * result. If the result overflow 16 bits, the output will be saturated to
+ * 16bits.
+ */
+s16 qm_sub16(s16 op1, s16 op2)
+{
+ s16 result;
+ s32 temp = (s32) op1 - (s32) op2;
+ if (temp > (s32) 0x7fff)
+ result = (s16) 0x7fff;
+ else if (temp < (s32) 0xffff8000)
+ result = (s16) 0xffff8000;
+ else
+ result = (s16) temp;
+
+ return result;
+}
+
+/*
+ * Description: This function make a 32 bit saturated left shift when the
+ * specified shift is +ve. This function will make a 32 bit right shift when
+ * the specified shift is -ve. This function return the result after shifting
+ * operation.
+ */
+s32 qm_shl32(s32 op, int shift)
+{
+ int i;
+ s32 result;
+ result = op;
+ if (shift > 31)
+ shift = 31;
+ else if (shift < -31)
+ shift = -31;
+ if (shift >= 0) {
+ for (i = 0; i < shift; i++)
+ result = qm_add32(result, result);
+ } else {
+ result = result >> (-shift);
+ }
+
+ return result;
+}
+
+/*
+ * Description: This function make a 16 bit saturated left shift when the
+ * specified shift is +ve. This function will make a 16 bit right shift when
+ * the specified shift is -ve. This function return the result after shifting
+ * operation.
+ */
+s16 qm_shl16(s16 op, int shift)
+{
+ int i;
+ s16 result;
+ result = op;
+ if (shift > 15)
+ shift = 15;
+ else if (shift < -15)
+ shift = -15;
+ if (shift > 0) {
+ for (i = 0; i < shift; i++)
+ result = qm_add16(result, result);
+ } else {
+ result = result >> (-shift);
+ }
+
+ return result;
+}
+
+/*
+ * Description: This function make a 16 bit right shift when shift is +ve.
+ * This function make a 16 bit saturated left shift when shift is -ve. This
+ * function return the result of the shift operation.
+ */
+s16 qm_shr16(s16 op, int shift)
+{
+ return qm_shl16(op, -shift);
+}
+
+/*
+ * Description: This function return the number of redundant sign bits in a
+ * 32 bit number. Example: qm_norm32(0x00000080) = 23
+ */
+s16 qm_norm32(s32 op)
+{
+ u16 u16extraSignBits;
+ if (op == 0) {
+ return 31;
+ } else {
+ u16extraSignBits = 0;
+ while ((op >> 31) == (op >> 30)) {
+ u16extraSignBits++;
+ op = op << 1;
+ }
+ }
+ return u16extraSignBits;
+}
+
+/* This table is log2(1+(i/32)) where i=[0:1:31], in q.15 format */
+static const s16 log_table[] = {
+ 0,
+ 1455,
+ 2866,
+ 4236,
+ 5568,
+ 6863,
+ 8124,
+ 9352,
+ 10549,
+ 11716,
+ 12855,
+ 13968,
+ 15055,
+ 16117,
+ 17156,
+ 18173,
+ 19168,
+ 20143,
+ 21098,
+ 22034,
+ 22952,
+ 23852,
+ 24736,
+ 25604,
+ 26455,
+ 27292,
+ 28114,
+ 28922,
+ 29717,
+ 30498,
+ 31267,
+ 32024
+};
+
+#define LOG_TABLE_SIZE 32 /* log_table size */
+#define LOG2_LOG_TABLE_SIZE 5 /* log2(log_table size) */
+#define Q_LOG_TABLE 15 /* qformat of log_table */
+#define LOG10_2 19728 /* log10(2) in q.16 */
+
+/*
+ * Description:
+ * This routine takes the input number N and its q format qN and compute
+ * the log10(N). This routine first normalizes the input no N. Then N is in
+ * mag*(2^x) format. mag is any number in the range 2^30-(2^31 - 1).
+ * Then log2(mag * 2^x) = log2(mag) + x is computed. From that
+ * log10(mag * 2^x) = log2(mag * 2^x) * log10(2) is computed.
+ * This routine looks the log2 value in the table considering
+ * LOG2_LOG_TABLE_SIZE+1 MSBs. As the MSB is always 1, only next
+ * LOG2_OF_LOG_TABLE_SIZE MSBs are used for table lookup. Next 16 MSBs are used
+ * for interpolation.
+ * Inputs:
+ * N - number to which log10 has to be found.
+ * qN - q format of N
+ * log10N - address where log10(N) will be written.
+ * qLog10N - address where log10N qformat will be written.
+ * Note/Problem:
+ * For accurate results input should be in normalized or near normalized form.
+ */
+void qm_log10(s32 N, s16 qN, s16 *log10N, s16 *qLog10N)
+{
+ s16 s16norm, s16tableIndex, s16errorApproximation;
+ u16 u16offset;
+ s32 s32log;
+
+ /* normalize the N. */
+ s16norm = qm_norm32(N);
+ N = N << s16norm;
+
+ /* The qformat of N after normalization.
+ * -30 is added to treat the no as between 1.0 to 2.0
+ * i.e. after adding the -30 to the qformat the decimal point will be
+ * just rigtht of the MSB. (i.e. after sign bit and 1st MSB). i.e.
+ * at the right side of 30th bit.
+ */
+ qN = qN + s16norm - 30;
+
+ /* take the table index as the LOG2_OF_LOG_TABLE_SIZE bits right of the
+ * MSB */
+ s16tableIndex = (s16) (N >> (32 - (2 + LOG2_LOG_TABLE_SIZE)));
+
+ /* remove the MSB. the MSB is always 1 after normalization. */
+ s16tableIndex =
+ s16tableIndex & (s16) ((1 << LOG2_LOG_TABLE_SIZE) - 1);
+
+ /* remove the (1+LOG2_OF_LOG_TABLE_SIZE) MSBs in the N. */
+ N = N & ((1 << (32 - (2 + LOG2_LOG_TABLE_SIZE))) - 1);
+
+ /* take the offset as the 16 MSBS after table index.
+ */
+ u16offset = (u16) (N >> (32 - (2 + LOG2_LOG_TABLE_SIZE + 16)));
+
+ /* look the log value in the table. */
+ s32log = log_table[s16tableIndex]; /* q.15 format */
+
+ /* interpolate using the offset. q.15 format. */
+ s16errorApproximation = (s16) qm_mulu16(u16offset,
+ (u16) (log_table[s16tableIndex + 1] -
+ log_table[s16tableIndex]));
+
+ /* q.15 format */
+ s32log = qm_add16((s16) s32log, s16errorApproximation);
+
+ /* adjust for the qformat of the N as
+ * log2(mag * 2^x) = log2(mag) + x
+ */
+ s32log = qm_add32(s32log, ((s32) -qN) << 15); /* q.15 format */
+
+ /* normalize the result. */
+ s16norm = qm_norm32(s32log);
+
+ /* bring all the important bits into lower 16 bits */
+ /* q.15+s16norm-16 format */
+ s32log = qm_shl32(s32log, s16norm - 16);
+
+ /* compute the log10(N) by multiplying log2(N) with log10(2).
+ * as log10(mag * 2^x) = log2(mag * 2^x) * log10(2)
+ * log10N in q.15+s16norm-16+1 (LOG10_2 is in q.16)
+ */
+ *log10N = qm_muls16((s16) s32log, (s16) LOG10_2);
+
+ /* write the q format of the result. */
+ *qLog10N = 15 + s16norm - 16 + 1;
+
+ return;
+}