summaryrefslogtreecommitdiff
path: root/arch/blackfin/lib
diff options
context:
space:
mode:
Diffstat (limited to 'arch/blackfin/lib')
-rw-r--r--arch/blackfin/lib/Makefile11
-rw-r--r--arch/blackfin/lib/ashldi3.c58
-rw-r--r--arch/blackfin/lib/ashrdi3.c59
-rw-r--r--arch/blackfin/lib/checksum.c140
-rw-r--r--arch/blackfin/lib/divsi3.S216
-rw-r--r--arch/blackfin/lib/gcclib.h47
-rw-r--r--arch/blackfin/lib/ins.S69
-rw-r--r--arch/blackfin/lib/lshrdi3.c72
-rw-r--r--arch/blackfin/lib/memchr.S70
-rw-r--r--arch/blackfin/lib/memcmp.S110
-rw-r--r--arch/blackfin/lib/memcpy.S142
-rw-r--r--arch/blackfin/lib/memmove.S103
-rw-r--r--arch/blackfin/lib/memset.S109
-rw-r--r--arch/blackfin/lib/modsi3.S79
-rw-r--r--arch/blackfin/lib/muldi3.c99
-rw-r--r--arch/blackfin/lib/outs.S62
-rw-r--r--arch/blackfin/lib/smulsi3_highpart.S30
-rw-r--r--arch/blackfin/lib/strcmp.c11
-rw-r--r--arch/blackfin/lib/strcpy.c11
-rw-r--r--arch/blackfin/lib/strncmp.c11
-rw-r--r--arch/blackfin/lib/strncpy.c11
-rw-r--r--arch/blackfin/lib/udivsi3.S298
-rw-r--r--arch/blackfin/lib/umodsi3.S66
-rw-r--r--arch/blackfin/lib/umulsi3_highpart.S23
24 files changed, 1907 insertions, 0 deletions
diff --git a/arch/blackfin/lib/Makefile b/arch/blackfin/lib/Makefile
new file mode 100644
index 000000000000..635288fc5f54
--- /dev/null
+++ b/arch/blackfin/lib/Makefile
@@ -0,0 +1,11 @@
+#
+# arch/blackfin/lib/Makefile
+#
+
+lib-y := \
+ ashldi3.o ashrdi3.o lshrdi3.o \
+ muldi3.o divsi3.o udivsi3.o modsi3.o umodsi3.o \
+ checksum.o memcpy.o memset.o memcmp.o memchr.o memmove.o \
+ strcmp.o strcpy.o strncmp.o strncpy.o \
+ umulsi3_highpart.o smulsi3_highpart.o \
+ ins.o outs.o
diff --git a/arch/blackfin/lib/ashldi3.c b/arch/blackfin/lib/ashldi3.c
new file mode 100644
index 000000000000..a8c279e9b192
--- /dev/null
+++ b/arch/blackfin/lib/ashldi3.c
@@ -0,0 +1,58 @@
+/*
+ * File: arch/blackfin/lib/ashldi3.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "gcclib.h"
+
+#ifdef CONFIG_ARITHMETIC_OPS_L1
+DItype __ashldi3(DItype u, word_type b)__attribute__((l1_text));
+#endif
+
+DItype __ashldi3(DItype u, word_type b)
+{
+ DIunion w;
+ word_type bm;
+ DIunion uu;
+
+ if (b == 0)
+ return u;
+
+ uu.ll = u;
+
+ bm = (sizeof(SItype) * BITS_PER_UNIT) - b;
+ if (bm <= 0) {
+ w.s.low = 0;
+ w.s.high = (USItype) uu.s.low << -bm;
+ } else {
+ USItype carries = (USItype) uu.s.low >> bm;
+ w.s.low = (USItype) uu.s.low << b;
+ w.s.high = ((USItype) uu.s.high << b) | carries;
+ }
+
+ return w.ll;
+}
diff --git a/arch/blackfin/lib/ashrdi3.c b/arch/blackfin/lib/ashrdi3.c
new file mode 100644
index 000000000000..a0d3419329ca
--- /dev/null
+++ b/arch/blackfin/lib/ashrdi3.c
@@ -0,0 +1,59 @@
+/*
+ * File: arch/blackfin/lib/ashrdi3.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "gcclib.h"
+
+#ifdef CONFIG_ARITHMETIC_OPS_L1
+DItype __ashrdi3(DItype u, word_type b)__attribute__((l1_text));
+#endif
+
+DItype __ashrdi3(DItype u, word_type b)
+{
+ DIunion w;
+ word_type bm;
+ DIunion uu;
+
+ if (b == 0)
+ return u;
+
+ uu.ll = u;
+
+ bm = (sizeof(SItype) * BITS_PER_UNIT) - b;
+ if (bm <= 0) {
+ /* w.s.high = 1..1 or 0..0 */
+ w.s.high = uu.s.high >> (sizeof(SItype) * BITS_PER_UNIT - 1);
+ w.s.low = uu.s.high >> -bm;
+ } else {
+ USItype carries = (USItype) uu.s.high << bm;
+ w.s.high = uu.s.high >> b;
+ w.s.low = ((USItype) uu.s.low >> b) | carries;
+ }
+
+ return w.ll;
+}
diff --git a/arch/blackfin/lib/checksum.c b/arch/blackfin/lib/checksum.c
new file mode 100644
index 000000000000..42768e0c80ca
--- /dev/null
+++ b/arch/blackfin/lib/checksum.c
@@ -0,0 +1,140 @@
+/*
+ * File: arch/blackfin/lib/checksum.c
+ * Based on: none - original work
+ * Author:
+ *
+ * Created:
+ * Description: An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <net/checksum.h>
+#include <asm/checksum.h>
+
+#ifdef CONFIG_IP_CHECKSUM_L1
+static unsigned short do_csum(const unsigned char *buff, int len)__attribute__((l1_text));
+#endif
+
+static unsigned short do_csum(const unsigned char *buff, int len)
+{
+ register unsigned long sum = 0;
+ int swappem = 0;
+
+ if (1 & (unsigned long)buff) {
+ sum = *buff << 8;
+ buff++;
+ len--;
+ ++swappem;
+ }
+
+ while (len > 1) {
+ sum += *(unsigned short *)buff;
+ buff += 2;
+ len -= 2;
+ }
+
+ if (len > 0)
+ sum += *buff;
+
+ /* Fold 32-bit sum to 16 bits */
+ while (sum >> 16)
+ sum = (sum & 0xffff) + (sum >> 16);
+
+ if (swappem)
+ sum = ((sum & 0xff00) >> 8) + ((sum & 0x00ff) << 8);
+
+ return sum;
+
+}
+
+/*
+ * This is a version of ip_compute_csum() optimized for IP headers,
+ * which always checksum on 4 octet boundaries.
+ */
+unsigned short ip_fast_csum(unsigned char *iph, unsigned int ihl)
+{
+ return ~do_csum(iph, ihl * 4);
+}
+
+/*
+ * computes the checksum of a memory block at buff, length len,
+ * and adds in "sum" (32-bit)
+ *
+ * returns a 32-bit number suitable for feeding into itself
+ * or csum_tcpudp_magic
+ *
+ * this function must be called with even lengths, except
+ * for the last fragment, which may be odd
+ *
+ * it's best to have buff aligned on a 32-bit boundary
+ */
+unsigned int csum_partial(const unsigned char *buff, int len, unsigned int sum)
+{
+ /*
+ * Just in case we get nasty checksum data...
+ * Like 0xffff6ec3 in the case of our IPv6 multicast header.
+ * We fold to begin with, as well as at the end.
+ */
+ sum = (sum & 0xffff) + (sum >> 16);
+
+ sum += do_csum(buff, len);
+
+ sum = (sum & 0xffff) + (sum >> 16);
+
+ return sum;
+}
+
+/*
+ * this routine is used for miscellaneous IP-like checksums, mainly
+ * in icmp.c
+ */
+unsigned short ip_compute_csum(const unsigned char *buff, int len)
+{
+ return ~do_csum(buff, len);
+}
+
+/*
+ * copy from fs while checksumming, otherwise like csum_partial
+ */
+
+unsigned int
+csum_partial_copy_from_user(const unsigned char *src, unsigned char *dst,
+ int len, int sum, int *csum_err)
+{
+ if (csum_err)
+ *csum_err = 0;
+ memcpy(dst, src, len);
+ return csum_partial(dst, len, sum);
+}
+
+/*
+ * copy from ds while checksumming, otherwise like csum_partial
+ */
+
+unsigned int csum_partial_copy(const unsigned char *src, unsigned char *dst,
+ int len, int sum)
+{
+ memcpy(dst, src, len);
+ return csum_partial(dst, len, sum);
+}
diff --git a/arch/blackfin/lib/divsi3.S b/arch/blackfin/lib/divsi3.S
new file mode 100644
index 000000000000..3e29861852b2
--- /dev/null
+++ b/arch/blackfin/lib/divsi3.S
@@ -0,0 +1,216 @@
+/*
+ * File: arch/blackfin/lib/divsi3.S
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description: 16 / 32 bit signed division.
+ * Special cases :
+ * 1) If(numerator == 0)
+ * return 0
+ * 2) If(denominator ==0)
+ * return positive max = 0x7fffffff
+ * 3) If(numerator == denominator)
+ * return 1
+ * 4) If(denominator ==1)
+ * return numerator
+ * 5) If(denominator == -1)
+ * return -numerator
+ *
+ * Operand : R0 - Numerator (i)
+ * R1 - Denominator (i)
+ * R0 - Quotient (o)
+ * Registers Used : R2-R7,P0-P2
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+.global ___divsi3;
+
+#ifdef CONFIG_ARITHMETIC_OPS_L1
+.section .l1.text
+#else
+.text
+#endif
+
+.align 2;
+___divsi3 :
+
+
+ R3 = R0 ^ R1;
+ R0 = ABS R0;
+
+ CC = V;
+
+ r3 = rot r3 by -1;
+ r1 = abs r1; /* now both positive, r3.30 means "negate result",
+ ** r3.31 means overflow, add one to result
+ */
+ cc = r0 < r1;
+ if cc jump .Lret_zero;
+ r2 = r1 >> 15;
+ cc = r2;
+ if cc jump .Lidents;
+ r2 = r1 << 16;
+ cc = r2 <= r0;
+ if cc jump .Lidents;
+
+ DIVS(R0, R1);
+ DIVQ(R0, R1);
+ DIVQ(R0, R1);
+ DIVQ(R0, R1);
+ DIVQ(R0, R1);
+ DIVQ(R0, R1);
+ DIVQ(R0, R1);
+ DIVQ(R0, R1);
+ DIVQ(R0, R1);
+ DIVQ(R0, R1);
+ DIVQ(R0, R1);
+ DIVQ(R0, R1);
+ DIVQ(R0, R1);
+ DIVQ(R0, R1);
+ DIVQ(R0, R1);
+ DIVQ(R0, R1);
+ DIVQ(R0, R1);
+
+ R0 = R0.L (Z);
+ r1 = r3 >> 31; /* add overflow issue back in */
+ r0 = r0 + r1;
+ r1 = -r0;
+ cc = bittst(r3, 30);
+ if cc r0 = r1;
+ RTS;
+
+/* Can't use the primitives. Test common identities.
+** If the identity is true, return the value in R2.
+*/
+
+.Lidents:
+ CC = R1 == 0; /* check for divide by zero */
+ IF CC JUMP .Lident_return;
+
+ CC = R0 == 0; /* check for division of zero */
+ IF CC JUMP .Lzero_return;
+
+ CC = R0 == R1; /* check for identical operands */
+ IF CC JUMP .Lident_return;
+
+ CC = R1 == 1; /* check for divide by 1 */
+ IF CC JUMP .Lident_return;
+
+ R2.L = ONES R1;
+ R2 = R2.L (Z);
+ CC = R2 == 1;
+ IF CC JUMP .Lpower_of_two;
+
+ /* Identities haven't helped either.
+ ** Perform the full division process.
+ */
+
+ P1 = 31; /* Set loop counter */
+
+ [--SP] = (R7:5); /* Push registers R5-R7 */
+ R2 = -R1;
+ [--SP] = R2;
+ R2 = R0 << 1; /* R2 lsw of dividend */
+ R6 = R0 ^ R1; /* Get sign */
+ R5 = R6 >> 31; /* Shift sign to LSB */
+
+ R0 = 0 ; /* Clear msw partial remainder */
+ R2 = R2 | R5; /* Shift quotient bit */
+ R6 = R0 ^ R1; /* Get new quotient bit */
+
+ LSETUP(.Llst,.Llend) LC0 = P1; /* Setup loop */
+.Llst: R7 = R2 >> 31; /* record copy of carry from R2 */
+ R2 = R2 << 1; /* Shift 64 bit dividend up by 1 bit */
+ R0 = R0 << 1 || R5 = [SP];
+ R0 = R0 | R7; /* and add carry */
+ CC = R6 < 0; /* Check quotient(AQ) */
+ /* we might be subtracting divisor (AQ==0) */
+ IF CC R5 = R1; /* or we might be adding divisor (AQ==1)*/
+ R0 = R0 + R5; /* do add or subtract, as indicated by AQ */
+ R6 = R0 ^ R1; /* Generate next quotient bit */
+ R5 = R6 >> 31;
+ /* Assume AQ==1, shift in zero */
+ BITTGL(R5,0); /* tweak AQ to be what we want to shift in */
+.Llend: R2 = R2 + R5; /* and then set shifted-in value to
+ ** tweaked AQ.
+ */
+ r1 = r3 >> 31;
+ r2 = r2 + r1;
+ cc = bittst(r3,30);
+ r0 = -r2;
+ if !cc r0 = r2;
+ SP += 4;
+ (R7:5)= [SP++]; /* Pop registers R6-R7 */
+ RTS;
+
+.Lident_return:
+ CC = R1 == 0; /* check for divide by zero => 0x7fffffff */
+ R2 = -1 (X);
+ R2 >>= 1;
+ IF CC JUMP .Ltrue_ident_return;
+
+ CC = R0 == R1; /* check for identical operands => 1 */
+ R2 = 1 (Z);
+ IF CC JUMP .Ltrue_ident_return;
+
+ R2 = R0; /* assume divide by 1 => numerator */
+ /*FALLTHRU*/
+
+.Ltrue_ident_return:
+ R0 = R2; /* Return an identity value */
+ R2 = -R2;
+ CC = bittst(R3,30);
+ IF CC R0 = R2;
+.Lzero_return:
+ RTS; /* ...including zero */
+
+.Lpower_of_two:
+ /* Y has a single bit set, which means it's a power of two.
+ ** That means we can perform the division just by shifting
+ ** X to the right the appropriate number of bits
+ */
+
+ /* signbits returns the number of sign bits, minus one.
+ ** 1=>30, 2=>29, ..., 0x40000000=>0. Which means we need
+ ** to shift right n-signbits spaces. It also means 0x80000000
+ ** is a special case, because that *also* gives a signbits of 0
+ */
+
+ R2 = R0 >> 31;
+ CC = R1 < 0;
+ IF CC JUMP .Ltrue_ident_return;
+
+ R1.l = SIGNBITS R1;
+ R1 = R1.L (Z);
+ R1 += -30;
+ R0 = LSHIFT R0 by R1.L;
+ r1 = r3 >> 31;
+ r0 = r0 + r1;
+ R2 = -R0; // negate result if necessary
+ CC = bittst(R3,30);
+ IF CC R0 = R2;
+ RTS;
+
+.Lret_zero:
+ R0 = 0;
+ RTS;
diff --git a/arch/blackfin/lib/gcclib.h b/arch/blackfin/lib/gcclib.h
new file mode 100644
index 000000000000..9ccd39a135ee
--- /dev/null
+++ b/arch/blackfin/lib/gcclib.h
@@ -0,0 +1,47 @@
+/*
+ * File: arch/blackfin/lib/gcclib.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define BITS_PER_UNIT 8
+#define SI_TYPE_SIZE (sizeof (SItype) * BITS_PER_UNIT)
+
+typedef unsigned int UQItype __attribute__ ((mode(QI)));
+typedef int SItype __attribute__ ((mode(SI)));
+typedef unsigned int USItype __attribute__ ((mode(SI)));
+typedef int DItype __attribute__ ((mode(DI)));
+typedef int word_type __attribute__ ((mode(__word__)));
+typedef unsigned int UDItype __attribute__ ((mode(DI)));
+
+struct DIstruct {
+ SItype low, high;
+};
+
+typedef union {
+ struct DIstruct s;
+ DItype ll;
+} DIunion;
diff --git a/arch/blackfin/lib/ins.S b/arch/blackfin/lib/ins.S
new file mode 100644
index 000000000000..730d2b427538
--- /dev/null
+++ b/arch/blackfin/lib/ins.S
@@ -0,0 +1,69 @@
+/*
+ * File: arch/blackfin/lib/ins.S
+ * Based on:
+ * Author: Bas Vermeulen <bas@buyways.nl>
+ *
+ * Created: Tue Mar 22 15:27:24 CEST 2005
+ * Description: Implementation of ins{bwl} for BlackFin processors using zero overhead loops.
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ * Copyright (C) 2005 Bas Vermeulen, BuyWays BV <bas@buyways.nl>
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/linkage.h>
+
+.align 2
+
+ENTRY(_insl)
+ P0 = R0; /* P0 = port */
+ cli R3;
+ P1 = R1; /* P1 = address */
+ P2 = R2; /* P2 = count */
+ SSYNC;
+ LSETUP( .Llong_loop_s, .Llong_loop_e) LC0 = P2;
+.Llong_loop_s: R0 = [P0];
+.Llong_loop_e: [P1++] = R0;
+ sti R3;
+ RTS;
+
+ENTRY(_insw)
+ P0 = R0; /* P0 = port */
+ cli R3;
+ P1 = R1; /* P1 = address */
+ P2 = R2; /* P2 = count */
+ SSYNC;
+ LSETUP( .Lword_loop_s, .Lword_loop_e) LC0 = P2;
+.Lword_loop_s: R0 = W[P0];
+.Lword_loop_e: W[P1++] = R0;
+ sti R3;
+ RTS;
+
+ENTRY(_insb)
+ P0 = R0; /* P0 = port */
+ cli R3;
+ P1 = R1; /* P1 = address */
+ P2 = R2; /* P2 = count */
+ SSYNC;
+ LSETUP( .Lbyte_loop_s, .Lbyte_loop_e) LC0 = P2;
+.Lbyte_loop_s: R0 = B[P0];
+.Lbyte_loop_e: B[P1++] = R0;
+ sti R3;
+ RTS;
diff --git a/arch/blackfin/lib/lshrdi3.c b/arch/blackfin/lib/lshrdi3.c
new file mode 100644
index 000000000000..84b9c5592220
--- /dev/null
+++ b/arch/blackfin/lib/lshrdi3.c
@@ -0,0 +1,72 @@
+/*
+ * File: arch/blackfin/lib/lshrdi3.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define BITS_PER_UNIT 8
+
+typedef int SItype __attribute__ ((mode(SI)));
+typedef unsigned int USItype __attribute__ ((mode(SI)));
+typedef int DItype __attribute__ ((mode(DI)));
+typedef int word_type __attribute__ ((mode(__word__)));
+
+struct DIstruct {
+ SItype high, low;
+};
+
+typedef union {
+ struct DIstruct s;
+ DItype ll;
+} DIunion;
+
+#ifdef CONFIG_ARITHMETIC_OPS_L1
+DItype __lshrdi3(DItype u, word_type b)__attribute__((l1_text));
+#endif
+
+DItype __lshrdi3(DItype u, word_type b)
+{
+ DIunion w;
+ word_type bm;
+ DIunion uu;
+
+ if (b == 0)
+ return u;
+
+ uu.ll = u;
+
+ bm = (sizeof(SItype) * BITS_PER_UNIT) - b;
+ if (bm <= 0) {
+ w.s.high = 0;
+ w.s.low = (USItype) uu.s.high >> -bm;
+ } else {
+ USItype carries = (USItype) uu.s.high << bm;
+ w.s.high = (USItype) uu.s.high >> b;
+ w.s.low = ((USItype) uu.s.low >> b) | carries;
+ }
+
+ return w.ll;
+}
diff --git a/arch/blackfin/lib/memchr.S b/arch/blackfin/lib/memchr.S
new file mode 100644
index 000000000000..498122250d07
--- /dev/null
+++ b/arch/blackfin/lib/memchr.S
@@ -0,0 +1,70 @@
+/*
+ * File: arch/blackfin/lib/memchr.S
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/linkage.h>
+
+/* void *memchr(const void *s, int c, size_t n);
+ * R0 = address (s)
+ * R1 = sought byte (c)
+ * R2 = count (n)
+ *
+ * Returns pointer to located character.
+ */
+
+.text
+
+.align 2
+
+ENTRY(_memchr)
+ P0 = R0; /* P0 = address */
+ P2 = R2; /* P2 = count */
+ R1 = R1.B(Z);
+ CC = R2 == 0;
+ IF CC JUMP .Lfailed;
+
+.Lbytes:
+ LSETUP (.Lbyte_loop_s, .Lbyte_loop_e) LC0=P2;
+
+.Lbyte_loop_s:
+ R3 = B[P0++](Z);
+ CC = R3 == R1;
+ IF CC JUMP .Lfound;
+.Lbyte_loop_e:
+ NOP;
+
+.Lfailed:
+ R0=0;
+ RTS;
+
+.Lfound:
+ R0 = P0;
+ R0 += -1;
+ RTS;
+
+.size _memchr,.-_memchr
diff --git a/arch/blackfin/lib/memcmp.S b/arch/blackfin/lib/memcmp.S
new file mode 100644
index 000000000000..5b9502368fc6
--- /dev/null
+++ b/arch/blackfin/lib/memcmp.S
@@ -0,0 +1,110 @@
+/*
+ * File: arch/blackfin/lib/memcmp.S
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/linkage.h>
+
+/* int memcmp(const void *s1, const void *s2, size_t n);
+ * R0 = First Address (s1)
+ * R1 = Second Address (s2)
+ * R2 = count (n)
+ *
+ * Favours word aligned data.
+ */
+
+.text
+
+.align 2
+
+ENTRY(_memcmp)
+ I1 = P3;
+ P0 = R0; /* P0 = s1 address */
+ P3 = R1; /* P3 = s2 Address */
+ P2 = R2 ; /* P2 = count */
+ CC = R2 <= 7(IU);
+ IF CC JUMP .Ltoo_small;
+ I0 = R1; /* s2 */
+ R1 = R1 | R0; /* OR addresses together */
+ R1 <<= 30; /* check bottom two bits */
+ CC = AZ; /* AZ set if zero. */
+ IF !CC JUMP .Lbytes ; /* Jump if addrs not aligned. */
+
+ P1 = P2 >> 2; /* count = n/4 */
+ R3 = 3;
+ R2 = R2 & R3; /* remainder */
+ P2 = R2; /* set remainder */
+
+ LSETUP (.Lquad_loop_s, .Lquad_loop_e) LC0=P1;
+.Lquad_loop_s:
+ MNOP || R0 = [P0++] || R1 = [I0++];
+ CC = R0 == R1;
+ IF !CC JUMP .Lquad_different;
+.Lquad_loop_e:
+ NOP;
+
+ P3 = I0; /* s2 */
+.Ltoo_small:
+ CC = P2 == 0; /* Check zero count*/
+ IF CC JUMP .Lfinished; /* very unlikely*/
+
+.Lbytes:
+ LSETUP (.Lbyte_loop_s, .Lbyte_loop_e) LC0=P2;
+.Lbyte_loop_s:
+ R1 = B[P3++](Z); /* *s2 */
+ R0 = B[P0++](Z); /* *s1 */
+ CC = R0 == R1;
+ IF !CC JUMP .Ldifferent;
+.Lbyte_loop_e:
+ NOP;
+
+.Ldifferent:
+ R0 = R0 - R1;
+ P3 = I1;
+ RTS;
+
+.Lquad_different:
+ /* We've read two quads which don't match.
+ * Can't just compare them, because we're
+ * a little-endian machine, so the MSBs of
+ * the regs occur at later addresses in the
+ * string.
+ * Arrange to re-read those two quads again,
+ * byte-by-byte.
+ */
+ P0 += -4; /* back up to the start of the */
+ P3 = I0; /* quads, and increase the*/
+ P2 += 4; /* remainder count*/
+ P3 += -4;
+ JUMP .Lbytes;
+
+.Lfinished:
+ R0 = 0;
+ P3 = I1;
+ RTS;
+
+.size _memcmp,.-_memcmp
diff --git a/arch/blackfin/lib/memcpy.S b/arch/blackfin/lib/memcpy.S
new file mode 100644
index 000000000000..c1e00eff541c
--- /dev/null
+++ b/arch/blackfin/lib/memcpy.S
@@ -0,0 +1,142 @@
+/*
+ * File: arch/blackfin/lib/memcpy.S
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description: internal version of memcpy(), issued by the compiler
+ * to copy blocks of data around.
+ * This is really memmove() - it has to be able to deal with
+ * possible overlaps, because that ambiguity is when the compiler
+ * gives up and calls a function. We have our own, internal version
+ * so that we get something we trust, even if the user has redefined
+ * the normal symbol.
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/linkage.h>
+
+/* void *memcpy(void *dest, const void *src, size_t n);
+ * R0 = To Address (dest) (leave unchanged to form result)
+ * R1 = From Address (src)
+ * R2 = count
+ *
+ * Note: Favours word alignment
+ */
+
+#ifdef CONFIG_MEMCPY_L1
+.section .l1.text
+#else
+.text
+#endif
+
+.align 2
+
+ENTRY(_memcpy)
+ CC = R2 <= 0; /* length not positive? */
+ IF CC JUMP .L_P1L2147483647; /* Nothing to do */
+
+ P0 = R0 ; /* dst*/
+ P1 = R1 ; /* src*/
+ P2 = R2 ; /* length */
+
+ /* check for overlapping data */
+ CC = R1 < R0; /* src < dst */
+ IF !CC JUMP .Lno_overlap;
+ R3 = R1 + R2;
+ CC = R0 < R3; /* and dst < src+len */
+ IF CC JUMP .Lhas_overlap;
+
+.Lno_overlap:
+ /* Check for aligned data.*/
+
+ R3 = R1 | R0;
+ R0 = 0x3;
+ R3 = R3 & R0;
+ CC = R3; /* low bits set on either address? */
+ IF CC JUMP .Lnot_aligned;
+
+ /* Both addresses are word-aligned, so we can copy
+ at least part of the data using word copies.*/
+ P2 = P2 >> 2;
+ CC = P2 <= 2;
+ IF !CC JUMP .Lmore_than_seven;
+ /* less than eight bytes... */
+ P2 = R2;
+ LSETUP(.Lthree_start, .Lthree_end) LC0=P2;
+ R0 = R1; /* setup src address for return */
+.Lthree_start:
+ R3 = B[P1++] (X);
+.Lthree_end:
+ B[P0++] = R3;
+
+ RTS;
+
+.Lmore_than_seven:
+ /* There's at least eight bytes to copy. */
+ P2 += -1; /* because we unroll one iteration */
+ LSETUP(.Lword_loop, .Lword_loop) LC0=P2;
+ R0 = R1;
+ I1 = P1;
+ R3 = [I1++];
+.Lword_loop:
+ MNOP || [P0++] = R3 || R3 = [I1++];
+
+ [P0++] = R3;
+ /* Any remaining bytes to copy? */
+ R3 = 0x3;
+ R3 = R2 & R3;
+ CC = R3 == 0;
+ P1 = I1; /* in case there's something left, */
+ IF !CC JUMP .Lbytes_left;
+ RTS;
+.Lbytes_left: P2 = R3;
+.Lnot_aligned:
+ /* From here, we're copying byte-by-byte. */
+ LSETUP (.Lbyte_start, .Lbyte_end) LC0=P2;
+ R0 = R1; /* Save src address for return */
+.Lbyte_start:
+ R1 = B[P1++] (X);
+.Lbyte_end:
+ B[P0++] = R1;
+
+.L_P1L2147483647:
+ RTS;
+
+.Lhas_overlap:
+ /* Need to reverse the copying, because the
+ * dst would clobber the src.
+ * Don't bother to work out alignment for
+ * the reverse case.
+ */
+ R0 = R1; /* save src for later. */
+ P0 = P0 + P2;
+ P0 += -1;
+ P1 = P1 + P2;
+ P1 += -1;
+ LSETUP(.Lover_start, .Lover_end) LC0=P2;
+.Lover_start:
+ R1 = B[P1--] (X);
+.Lover_end:
+ B[P0--] = R1;
+
+ RTS;
diff --git a/arch/blackfin/lib/memmove.S b/arch/blackfin/lib/memmove.S
new file mode 100644
index 000000000000..2e5fb7f8df13
--- /dev/null
+++ b/arch/blackfin/lib/memmove.S
@@ -0,0 +1,103 @@
+/*
+ * File: arch/blackfin/lib/memmove.S
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/linkage.h>
+
+.align 2
+
+/*
+ * C Library function MEMMOVE
+ * R0 = To Address (leave unchanged to form result)
+ * R1 = From Address
+ * R2 = count
+ * Data may overlap
+ */
+
+ENTRY(_memmove)
+ I1 = P3;
+ P0 = R0; /* P0 = To address */
+ P3 = R1; /* P3 = From Address */
+ P2 = R2; /* P2 = count */
+ CC = P2 == 0; /* Check zero count*/
+ IF CC JUMP .Lfinished; /* very unlikely */
+
+ CC = R1 < R0 (IU); /* From < To */
+ IF !CC JUMP .Lno_overlap;
+ R3 = R1 + R2;
+ CC = R0 <= R3 (IU); /* (From+len) >= To */
+ IF CC JUMP .Loverlap;
+.Lno_overlap:
+ R3 = 11;
+ CC = R2 <= R3;
+ IF CC JUMP .Lbytes;
+ R3 = R1 | R0; /* OR addresses together */
+ R3 <<= 30; /* check bottom two bits */
+ CC = AZ; /* AZ set if zero.*/
+ IF !CC JUMP .Lbytes; /* Jump if addrs not aligned.*/
+
+ I0 = P3;
+ P1 = P2 >> 2; /* count = n/4 */
+ P1 += -1;
+ R3 = 3;
+ R2 = R2 & R3; /* remainder */
+ P2 = R2; /* set remainder */
+ R1 = [I0++];
+
+ LSETUP (.Lquad_loop, .Lquad_loop) LC0=P1;
+.Lquad_loop: MNOP || [P0++] = R1 || R1 = [I0++];
+ [P0++] = R1;
+
+ CC = P2 == 0; /* any remaining bytes? */
+ P3 = I0; /* Ammend P3 to updated ptr. */
+ IF !CC JUMP .Lbytes;
+ P3 = I1;
+ RTS;
+
+.Lbytes: LSETUP (.Lbyte2_s, .Lbyte2_e) LC0=P2;
+.Lbyte2_s: R1 = B[P3++](Z);
+.Lbyte2_e: B[P0++] = R1;
+
+.Lfinished: P3 = I1;
+ RTS;
+
+.Loverlap:
+ P2 += -1;
+ P0 = P0 + P2;
+ P3 = P3 + P2;
+ R1 = B[P3--] (Z);
+ CC = P2 == 0;
+ IF CC JUMP .Lno_loop;
+ LSETUP (.Lol_s, .Lol_e) LC0 = P2;
+.Lol_s: B[P0--] = R1;
+.Lol_e: R1 = B[P3--] (Z);
+.Lno_loop: B[P0] = R1;
+ P3 = I1;
+ RTS;
+
+.size _memmove,.-_memmove
diff --git a/arch/blackfin/lib/memset.S b/arch/blackfin/lib/memset.S
new file mode 100644
index 000000000000..ba6d047568dd
--- /dev/null
+++ b/arch/blackfin/lib/memset.S
@@ -0,0 +1,109 @@
+/*
+ * File: arch/blackfin/lib/memset.S
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/linkage.h>
+
+.align 2
+
+#ifdef CONFIG_MEMSET_L1
+.section .l1.text
+#else
+.text
+#endif
+
+/*
+ * C Library function MEMSET
+ * R0 = address (leave unchanged to form result)
+ * R1 = filler byte
+ * R2 = count
+ * Favours word aligned data.
+ */
+
+ENTRY(_memset)
+ P0 = R0 ; /* P0 = address */
+ P2 = R2 ; /* P2 = count */
+ R3 = R0 + R2; /* end */
+ CC = R2 <= 7(IU);
+ IF CC JUMP .Ltoo_small;
+ R1 = R1.B (Z); /* R1 = fill char */
+ R2 = 3;
+ R2 = R0 & R2; /* addr bottom two bits */
+ CC = R2 == 0; /* AZ set if zero. */
+ IF !CC JUMP .Lforce_align ; /* Jump if addr not aligned. */
+
+.Laligned:
+ P1 = P2 >> 2; /* count = n/4 */
+ R2 = R1 << 8; /* create quad filler */
+ R2.L = R2.L + R1.L(NS);
+ R2.H = R2.L + R1.H(NS);
+ P2 = R3;
+
+ LSETUP (.Lquad_loop , .Lquad_loop) LC0=P1;
+.Lquad_loop:
+ [P0++] = R2;
+
+ CC = P0 == P2;
+ IF !CC JUMP .Lbytes_left;
+ RTS;
+
+.Lbytes_left:
+ R2 = R3; /* end point */
+ R3 = P0; /* current position */
+ R2 = R2 - R3; /* bytes left */
+ P2 = R2;
+
+.Ltoo_small:
+ CC = P2 == 0; /* Check zero count */
+ IF CC JUMP .Lfinished; /* Unusual */
+
+.Lbytes:
+ LSETUP (.Lbyte_loop , .Lbyte_loop) LC0=P2;
+.Lbyte_loop:
+ B[P0++] = R1;
+
+.Lfinished:
+ RTS;
+
+.Lforce_align:
+ CC = BITTST (R0, 0); /* odd byte */
+ R0 = 4;
+ R0 = R0 - R2;
+ P1 = R0;
+ R0 = P0; /* Recover return address */
+ IF !CC JUMP .Lskip1;
+ B[P0++] = R1;
+.Lskip1:
+ CC = R2 <= 2; /* 2 bytes */
+ P2 -= P1; /* reduce count */
+ IF !CC JUMP .Laligned;
+ B[P0++] = R1;
+ B[P0++] = R1;
+ JUMP .Laligned;
+
+.size _memset,.-_memset
diff --git a/arch/blackfin/lib/modsi3.S b/arch/blackfin/lib/modsi3.S
new file mode 100644
index 000000000000..528b8b1ccb34
--- /dev/null
+++ b/arch/blackfin/lib/modsi3.S
@@ -0,0 +1,79 @@
+/*
+ * File: arch/blackfin/lib/modsi3.S
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description: This program computes 32 bit signed remainder. It calls div32 function
+ * for quotient estimation.
+ *
+ * Registers used :
+ * Numerator/ Denominator in R0, R1
+ * R0 - returns remainder.
+ * R2-R7
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+.global ___modsi3;
+.type ___modsi3, STT_FUNC;
+.extern ___divsi3;
+.type ___divsi3, STT_FUNC;
+
+#ifdef CONFIG_ARITHMETIC_OPS_L1
+.section .l1.text
+#else
+.text
+#endif
+
+___modsi3:
+
+ CC=R0==0;
+ IF CC JUMP .LRETURN_R0; /* Return 0, if numerator == 0 */
+ CC=R1==0;
+ IF CC JUMP .LRETURN_ZERO; /* Return 0, if denominator == 0 */
+ CC=R0==R1;
+ IF CC JUMP .LRETURN_ZERO; /* Return 0, if numerator == denominator */
+ CC = R1 == 1;
+ IF CC JUMP .LRETURN_ZERO; /* Return 0, if denominator == 1 */
+ CC = R1 == -1;
+ IF CC JUMP .LRETURN_ZERO; /* Return 0, if denominator == -1 */
+
+ /* Valid input. Use __divsi3() to compute the quotient, and then
+ * derive the remainder from that. */
+
+ [--SP] = (R7:6); /* Push R7 and R6 */
+ [--SP] = RETS; /* and return address */
+ R7 = R0; /* Copy of R0 */
+ R6 = R1; /* Save for later */
+ SP += -12; /* Should always provide this space */
+ CALL ___divsi3; /* Compute signed quotient using ___divsi3()*/
+ SP += 12;
+ R0 *= R6; /* Quotient * divisor */
+ R0 = R7 - R0; /* Dividend - (quotient * divisor) */
+ RETS = [SP++]; /* Get back return address */
+ (R7:6) = [SP++]; /* Pop registers R7 and R4 */
+ RTS; /* Store remainder */
+
+.LRETURN_ZERO:
+ R0 = 0;
+.LRETURN_R0:
+ RTS;
diff --git a/arch/blackfin/lib/muldi3.c b/arch/blackfin/lib/muldi3.c
new file mode 100644
index 000000000000..303d0c6a6dba
--- /dev/null
+++ b/arch/blackfin/lib/muldi3.c
@@ -0,0 +1,99 @@
+/*
+ * File: arch/blackfin/lib/muldi3.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef SI_TYPE_SIZE
+#define SI_TYPE_SIZE 32
+#endif
+#define __ll_b (1L << (SI_TYPE_SIZE / 2))
+#define __ll_lowpart(t) ((usitype) (t) % __ll_b)
+#define __ll_highpart(t) ((usitype) (t) / __ll_b)
+#define BITS_PER_UNIT 8
+
+#if !defined(umul_ppmm)
+#define umul_ppmm(w1, w0, u, v) \
+ do { \
+ usitype __x0, __x1, __x2, __x3; \
+ usitype __ul, __vl, __uh, __vh; \
+ \
+ __ul = __ll_lowpart (u); \
+ __uh = __ll_highpart (u); \
+ __vl = __ll_lowpart (v); \
+ __vh = __ll_highpart (v); \
+ \
+ __x0 = (usitype) __ul * __vl; \
+ __x1 = (usitype) __ul * __vh; \
+ __x2 = (usitype) __uh * __vl; \
+ __x3 = (usitype) __uh * __vh; \
+ \
+ __x1 += __ll_highpart (__x0);/* this can't give carry */ \
+ __x1 += __x2; /* but this indeed can */ \
+ if (__x1 < __x2) /* did we get it? */ \
+ __x3 += __ll_b; /* yes, add it in the proper pos. */ \
+ \
+ (w1) = __x3 + __ll_highpart (__x1); \
+ (w0) = __ll_lowpart (__x1) * __ll_b + __ll_lowpart (__x0); \
+ } while (0)
+#endif
+
+#if !defined(__umulsidi3)
+#define __umulsidi3(u, v) \
+ ({diunion __w; \
+ umul_ppmm (__w.s.high, __w.s.low, u, v); \
+ __w.ll; })
+#endif
+
+typedef unsigned int usitype __attribute__ ((mode(SI)));
+typedef int sitype __attribute__ ((mode(SI)));
+typedef int ditype __attribute__ ((mode(DI)));
+typedef int word_type __attribute__ ((mode(__word__)));
+
+struct distruct {
+ sitype low, high;
+};
+typedef union {
+ struct distruct s;
+ ditype ll;
+} diunion;
+
+#ifdef CONFIG_ARITHMETIC_OPS_L1
+ditype __muldi3(ditype u, ditype v)__attribute__((l1_text));
+#endif
+
+ditype __muldi3(ditype u, ditype v)
+{
+ diunion w;
+ diunion uu, vv;
+
+ uu.ll = u, vv.ll = v;
+ w.ll = __umulsidi3(uu.s.low, vv.s.low);
+ w.s.high += ((usitype) uu.s.low * (usitype) vv.s.high
+ + (usitype) uu.s.high * (usitype) vv.s.low);
+
+ return w.ll;
+}
diff --git a/arch/blackfin/lib/outs.S b/arch/blackfin/lib/outs.S
new file mode 100644
index 000000000000..f8c876fe8930
--- /dev/null
+++ b/arch/blackfin/lib/outs.S
@@ -0,0 +1,62 @@
+/*
+ * File: arch/blackfin/lib/outs.S
+ * Based on:
+ * Author: Bas Vermeulen <bas@buyways.nl>
+ *
+ * Created: Tue Mar 22 15:27:24 CEST 2005
+ * Description: Implementation of outs{bwl} for BlackFin processors using zero overhead loops.
+ *
+ * Modified: Copyright (C) 2005 Bas Vermeulen, BuyWays BV <bas@buyways.nl>
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/linkage.h>
+
+.align 2
+
+ENTRY(_outsl)
+ P0 = R0; /* P0 = port */
+ P1 = R1; /* P1 = address */
+ P2 = R2; /* P2 = count */
+
+ LSETUP( .Llong_loop_s, .Llong_loop_e) LC0 = P2;
+.Llong_loop_s: R0 = [P1++];
+.Llong_loop_e: [P0] = R0;
+ RTS;
+
+ENTRY(_outsw)
+ P0 = R0; /* P0 = port */
+ P1 = R1; /* P1 = address */
+ P2 = R2; /* P2 = count */
+
+ LSETUP( .Lword_loop_s, .Lword_loop_e) LC0 = P2;
+.Lword_loop_s: R0 = W[P1++];
+.Lword_loop_e: W[P0] = R0;
+ RTS;
+
+ENTRY(_outsb)
+ P0 = R0; /* P0 = port */
+ P1 = R1; /* P1 = address */
+ P2 = R2; /* P2 = count */
+
+ LSETUP( .Lbyte_loop_s, .Lbyte_loop_e) LC0 = P2;
+.Lbyte_loop_s: R0 = B[P1++];
+.Lbyte_loop_e: B[P0] = R0;
+ RTS;
diff --git a/arch/blackfin/lib/smulsi3_highpart.S b/arch/blackfin/lib/smulsi3_highpart.S
new file mode 100644
index 000000000000..10b8f8da576f
--- /dev/null
+++ b/arch/blackfin/lib/smulsi3_highpart.S
@@ -0,0 +1,30 @@
+.align 2
+.global ___smulsi3_highpart;
+.type ___smulsi3_highpart, STT_FUNC;
+
+#ifdef CONFIG_ARITHMETIC_OPS_L1
+.section .l1.text
+#else
+.text
+#endif
+
+___smulsi3_highpart:
+ R2 = R1.L * R0.L (FU);
+ R3 = R1.H * R0.L (IS,M);
+ R0 = R0.H * R1.H, R1 = R0.H * R1.L (IS,M);
+
+ R1.L = R2.H + R1.L;
+ cc = ac0;
+ R2 = cc;
+
+ R1.L = R1.L + R3.L;
+ cc = ac0;
+ R1 >>>= 16;
+ R3 >>>= 16;
+ R1 = R1 + R3;
+ R1 = R1 + R2;
+ R2 = cc;
+ R1 = R1 + R2;
+
+ R0 = R0 + R1;
+ RTS;
diff --git a/arch/blackfin/lib/strcmp.c b/arch/blackfin/lib/strcmp.c
new file mode 100644
index 000000000000..2ad47c4254ba
--- /dev/null
+++ b/arch/blackfin/lib/strcmp.c
@@ -0,0 +1,11 @@
+#include <linux/types.h>
+
+#define strcmp __inline_strcmp
+#include <asm/string.h>
+#undef strcmp
+
+int strcmp(const char *dest, const char *src)
+{
+ return __inline_strcmp(dest, src);
+}
+
diff --git a/arch/blackfin/lib/strcpy.c b/arch/blackfin/lib/strcpy.c
new file mode 100644
index 000000000000..4dc835a8a19b
--- /dev/null
+++ b/arch/blackfin/lib/strcpy.c
@@ -0,0 +1,11 @@
+#include <linux/types.h>
+
+#define strcpy __inline_strcpy
+#include <asm/string.h>
+#undef strcpy
+
+char *strcpy(char *dest, const char *src)
+{
+ return __inline_strcpy(dest, src);
+}
+
diff --git a/arch/blackfin/lib/strncmp.c b/arch/blackfin/lib/strncmp.c
new file mode 100644
index 000000000000..947bcfe3f3bb
--- /dev/null
+++ b/arch/blackfin/lib/strncmp.c
@@ -0,0 +1,11 @@
+#include <linux/types.h>
+
+#define strncmp __inline_strncmp
+#include <asm/string.h>
+#undef strncmp
+
+int strncmp(const char *cs, const char *ct, size_t count)
+{
+ return __inline_strncmp(cs, ct, count);
+}
+
diff --git a/arch/blackfin/lib/strncpy.c b/arch/blackfin/lib/strncpy.c
new file mode 100644
index 000000000000..77a9b2e95097
--- /dev/null
+++ b/arch/blackfin/lib/strncpy.c
@@ -0,0 +1,11 @@
+#include <linux/types.h>
+
+#define strncpy __inline_strncpy
+#include <asm/string.h>
+#undef strncpy
+
+char *strncpy(char *dest, const char *src, size_t n)
+{
+ return __inline_strncpy(dest, src, n);
+}
+
diff --git a/arch/blackfin/lib/udivsi3.S b/arch/blackfin/lib/udivsi3.S
new file mode 100644
index 000000000000..d39a12916259
--- /dev/null
+++ b/arch/blackfin/lib/udivsi3.S
@@ -0,0 +1,298 @@
+/*
+ * File: arch/blackfin/lib/udivsi3.S
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/linkage.h>
+
+#define CARRY AC0
+
+#ifdef CONFIG_ARITHMETIC_OPS_L1
+.section .l1.text
+#else
+.text
+#endif
+
+
+ENTRY(___udivsi3)
+
+ CC = R0 < R1 (IU); /* If X < Y, always return 0 */
+ IF CC JUMP .Lreturn_ident;
+
+ R2 = R1 << 16;
+ CC = R2 <= R0 (IU);
+ IF CC JUMP .Lidents;
+
+ R2 = R0 >> 31; /* if X is a 31-bit number */
+ R3 = R1 >> 15; /* and Y is a 15-bit number */
+ R2 = R2 | R3; /* then it's okay to use the DIVQ builtins (fallthrough to fast)*/
+ CC = R2;
+ IF CC JUMP .Ly_16bit;
+
+/* METHOD 1: FAST DIVQ
+ We know we have a 31-bit dividend, and 15-bit divisor so we can use the
+ simple divq approach (first setting AQ to 0 - implying unsigned division,
+ then 16 DIVQ's).
+*/
+
+ AQ = CC; /* Clear AQ (CC==0) */
+
+/* ISR States: When dividing two integers (32.0/16.0) using divide primitives,
+ we need to shift the dividend one bit to the left.
+ We have already checked that we have a 31-bit number so we are safe to do
+ that.
+*/
+ R0 <<= 1;
+ DIVQ(R0, R1); // 1
+ DIVQ(R0, R1); // 2
+ DIVQ(R0, R1); // 3
+ DIVQ(R0, R1); // 4
+ DIVQ(R0, R1); // 5
+ DIVQ(R0, R1); // 6
+ DIVQ(R0, R1); // 7
+ DIVQ(R0, R1); // 8
+ DIVQ(R0, R1); // 9
+ DIVQ(R0, R1); // 10
+ DIVQ(R0, R1); // 11
+ DIVQ(R0, R1); // 12
+ DIVQ(R0, R1); // 13
+ DIVQ(R0, R1); // 14
+ DIVQ(R0, R1); // 15
+ DIVQ(R0, R1); // 16
+ R0 = R0.L (Z);
+ RTS;
+
+.Ly_16bit:
+ /* We know that the upper 17 bits of Y might have bits set,
+ ** or that the sign bit of X might have a bit. If Y is a
+ ** 16-bit number, but not bigger, then we can use the builtins
+ ** with a post-divide correction.
+ ** R3 currently holds Y>>15, which means R3's LSB is the
+ ** bit we're interested in.
+ */
+
+ /* According to the ISR, to use the Divide primitives for
+ ** unsigned integer divide, the useable range is 31 bits
+ */
+ CC = ! BITTST(R0, 31);
+
+ /* IF condition is true we can scale our inputs and use the divide primitives,
+ ** with some post-adjustment
+ */
+ R3 += -1; /* if so, Y is 0x00008nnn */
+ CC &= AZ;
+
+ /* If condition is true we can scale our inputs and use the divide primitives,
+ ** with some post-adjustment
+ */
+ R3 = R1 >> 1; /* Pre-scaled divisor for primitive case */
+ R2 = R0 >> 16;
+
+ R2 = R3 - R2; /* shifted divisor < upper 16 bits of dividend */
+ CC &= CARRY;
+ IF CC JUMP .Lshift_and_correct;
+
+ /* Fall through to the identities */
+
+/* METHOD 2: identities and manual calculation
+ We are not able to use the divide primites, but may still catch some special
+ cases.
+*/
+.Lidents:
+ /* Test for common identities. Value to be returned is placed in R2. */
+ CC = R0 == 0; /* 0/Y => 0 */
+ IF CC JUMP .Lreturn_r0;
+ CC = R0 == R1; /* X==Y => 1 */
+ IF CC JUMP .Lreturn_ident;
+ CC = R1 == 1; /* X/1 => X */
+ IF CC JUMP .Lreturn_ident;
+
+ R2.L = ONES R1;
+ R2 = R2.L (Z);
+ CC = R2 == 1;
+ IF CC JUMP .Lpower_of_two;
+
+ [--SP] = (R7:5); /* Push registers R5-R7 */
+
+ /* Idents don't match. Go for the full operation. */
+
+
+ R6 = 2; /* assume we'll shift two */
+ R3 = 1;
+
+ P2 = R1;
+ /* If either R0 or R1 have sign set, */
+ /* divide them by two, and note it's */
+ /* been done. */
+ CC = R1 < 0;
+ R2 = R1 >> 1;
+ IF CC R1 = R2; /* Possibly-shifted R1 */
+ IF !CC R6 = R3; /* R1 doesn't, so at most 1 shifted */
+
+ P0 = 0;
+ R3 = -R1;
+ [--SP] = R3;
+ R2 = R0 >> 1;
+ R2 = R0 >> 1;
+ CC = R0 < 0;
+ IF CC P0 = R6; /* Number of values divided */
+ IF !CC R2 = R0; /* Shifted R0 */
+
+ /* P0 is 0, 1 (NR/=2) or 2 (NR/=2, DR/=2) */
+
+ /* r2 holds Copy dividend */
+ R3 = 0; /* Clear partial remainder */
+ R7 = 0; /* Initialise quotient bit */
+
+ P1 = 32; /* Set loop counter */
+ LSETUP(.Lulst, .Lulend) LC0 = P1; /* Set loop counter */
+.Lulst: R6 = R2 >> 31; /* R6 = sign bit of R2, for carry */
+ R2 = R2 << 1; /* Shift 64 bit dividend up by 1 bit */
+ R3 = R3 << 1 || R5 = [SP];
+ R3 = R3 | R6; /* Include any carry */
+ CC = R7 < 0; /* Check quotient(AQ) */
+ /* If AQ==0, we'll sub divisor */
+ IF CC R5 = R1; /* and if AQ==1, we'll add it. */
+ R3 = R3 + R5; /* Add/sub divsor to partial remainder */
+ R7 = R3 ^ R1; /* Generate next quotient bit */
+
+ R5 = R7 >> 31; /* Get AQ */
+ BITTGL(R5, 0); /* Invert it, to get what we'll shift */
+.Lulend: R2 = R2 + R5; /* and "shift" it in. */
+
+ CC = P0 == 0; /* Check how many inputs we shifted */
+ IF CC JUMP .Lno_mult; /* if none... */
+ R6 = R2 << 1;
+ CC = P0 == 1;
+ IF CC R2 = R6; /* if 1, Q = Q*2 */
+ IF !CC R1 = P2; /* if 2, restore stored divisor */
+
+ R3 = R2; /* Copy of R2 */
+ R3 *= R1; /* Q * divisor */
+ R5 = R0 - R3; /* Z = (dividend - Q * divisor) */
+ CC = R1 <= R5 (IU); /* Check if divisor <= Z? */
+ R6 = CC; /* if yes, R6 = 1 */
+ R2 = R2 + R6; /* if yes, add one to quotient(Q) */
+.Lno_mult:
+ SP += 4;
+ (R7:5) = [SP++]; /* Pop registers R5-R7 */
+ R0 = R2; /* Store quotient */
+ RTS;
+
+.Lreturn_ident:
+ CC = R0 < R1 (IU); /* If X < Y, always return 0 */
+ R2 = 0;
+ IF CC JUMP .Ltrue_return_ident;
+ R2 = -1 (X); /* X/0 => 0xFFFFFFFF */
+ CC = R1 == 0;
+ IF CC JUMP .Ltrue_return_ident;
+ R2 = -R2; /* R2 now 1 */
+ CC = R0 == R1; /* X==Y => 1 */
+ IF CC JUMP .Ltrue_return_ident;
+ R2 = R0; /* X/1 => X */
+ /*FALLTHRU*/
+
+.Ltrue_return_ident:
+ R0 = R2;
+.Lreturn_r0:
+ RTS;
+
+.Lpower_of_two:
+ /* Y has a single bit set, which means it's a power of two.
+ ** That means we can perform the division just by shifting
+ ** X to the right the appropriate number of bits
+ */
+
+ /* signbits returns the number of sign bits, minus one.
+ ** 1=>30, 2=>29, ..., 0x40000000=>0. Which means we need
+ ** to shift right n-signbits spaces. It also means 0x80000000
+ ** is a special case, because that *also* gives a signbits of 0
+ */
+
+ R2 = R0 >> 31;
+ CC = R1 < 0;
+ IF CC JUMP .Ltrue_return_ident;
+
+ R1.l = SIGNBITS R1;
+ R1 = R1.L (Z);
+ R1 += -30;
+ R0 = LSHIFT R0 by R1.L;
+ RTS;
+
+/* METHOD 3: PRESCALE AND USE THE DIVIDE PRIMITIVES WITH SOME POST-CORRECTION
+ Two scaling operations are required to use the divide primitives with a
+ divisor > 0x7FFFF.
+ Firstly (as in method 1) we need to shift the dividend 1 to the left for
+ integer division.
+ Secondly we need to shift both the divisor and dividend 1 to the right so
+ both are in range for the primitives.
+ The left/right shift of the dividend does nothing so we can skip it.
+*/
+.Lshift_and_correct:
+ R2 = R0;
+ // R3 is already R1 >> 1
+ CC=!CC;
+ AQ = CC; /* Clear AQ, got here with CC = 0 */
+ DIVQ(R2, R3); // 1
+ DIVQ(R2, R3); // 2
+ DIVQ(R2, R3); // 3
+ DIVQ(R2, R3); // 4
+ DIVQ(R2, R3); // 5
+ DIVQ(R2, R3); // 6
+ DIVQ(R2, R3); // 7
+ DIVQ(R2, R3); // 8
+ DIVQ(R2, R3); // 9
+ DIVQ(R2, R3); // 10
+ DIVQ(R2, R3); // 11
+ DIVQ(R2, R3); // 12
+ DIVQ(R2, R3); // 13
+ DIVQ(R2, R3); // 14
+ DIVQ(R2, R3); // 15
+ DIVQ(R2, R3); // 16
+
+ /* According to the Instruction Set Reference:
+ To divide by a divisor > 0x7FFF,
+ 1. prescale and perform divide to obtain quotient (Q) (done above),
+ 2. multiply quotient by unscaled divisor (result M)
+ 3. subtract the product from the divident to get an error (E = X - M)
+ 4. if E < divisor (Y) subtract 1, if E > divisor (Y) add 1, else return quotient (Q)
+ */
+ R3 = R2.L (Z); /* Q = X' / Y' */
+ R2 = R3; /* Preserve Q */
+ R2 *= R1; /* M = Q * Y */
+ R2 = R0 - R2; /* E = X - M */
+ R0 = R3; /* Copy Q into result reg */
+
+/* Correction: If result of the multiply is negative, we overflowed
+ and need to correct the result by subtracting 1 from the result.*/
+ R3 = 0xFFFF (Z);
+ R2 = R2 >> 16; /* E >> 16 */
+ CC = R2 == R3;
+ R3 = 1 ;
+ R1 = R0 - R3;
+ IF CC R0 = R1;
+ RTS;
diff --git a/arch/blackfin/lib/umodsi3.S b/arch/blackfin/lib/umodsi3.S
new file mode 100644
index 000000000000..b55ce96ab89f
--- /dev/null
+++ b/arch/blackfin/lib/umodsi3.S
@@ -0,0 +1,66 @@
+/*
+ * File: arch/blackfin/lib/umodsi3.S
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description: libgcc1 routines for Blackfin 5xx
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifdef CONFIG_ARITHMETIC_OPS_L1
+.section .l1.text
+#else
+.text
+#endif
+
+.extern ___udivsi3;
+.globl ___umodsi3
+___umodsi3:
+
+ CC=R0==0;
+ IF CC JUMP .LRETURN_R0; /* Return 0, if NR == 0 */
+ CC= R1==0;
+ IF CC JUMP .LRETURN_ZERO_VAL; /* Return 0, if DR == 0 */
+ CC=R0==R1;
+ IF CC JUMP .LRETURN_ZERO_VAL; /* Return 0, if NR == DR */
+ CC = R1 == 1;
+ IF CC JUMP .LRETURN_ZERO_VAL; /* Return 0, if DR == 1 */
+ CC = R0<R1 (IU);
+ IF CC JUMP .LRETURN_R0; /* Return dividend (R0),IF NR<DR */
+
+ [--SP] = (R7:6); /* Push registers and */
+ [--SP] = RETS; /* Return address */
+ R7 = R0; /* Copy of R0 */
+ R6 = R1;
+ SP += -12; /* Should always provide this space */
+ CALL ___udivsi3; /* Compute unsigned quotient using ___udiv32()*/
+ SP += 12;
+ R0 *= R6; /* Quotient * divisor */
+ R0 = R7 - R0; /* Dividend - (quotient * divisor) */
+ RETS = [SP++]; /* Pop return address */
+ ( R7:6) = [SP++]; /* And registers */
+ RTS; /* Return remainder */
+.LRETURN_ZERO_VAL:
+ R0 = 0;
+.LRETURN_R0:
+ RTS;
diff --git a/arch/blackfin/lib/umulsi3_highpart.S b/arch/blackfin/lib/umulsi3_highpart.S
new file mode 100644
index 000000000000..aac8218fb258
--- /dev/null
+++ b/arch/blackfin/lib/umulsi3_highpart.S
@@ -0,0 +1,23 @@
+.align 2
+.global ___umulsi3_highpart;
+.type ___umulsi3_highpart, STT_FUNC;
+
+#ifdef CONFIG_ARITHMETIC_OPS_L1
+.section .l1.text
+#else
+.text
+#endif
+
+___umulsi3_highpart:
+ R2 = R1.H * R0.H, R3 = R1.L * R0.H (FU);
+ R0 = R1.L * R0.L, R1 = R1.H * R0.L (FU);
+ R0 >>= 16;
+ /* Unsigned multiplication has the nice property that we can
+ ignore carry on this first addition. */
+ R0 = R0 + R3;
+ R0 = R0 + R1;
+ cc = ac0;
+ R1 = cc;
+ R1 = PACK(R1.l,R0.h);
+ R0 = R1 + R2;
+ RTS;