diff --git a/Configure b/Configure
index f7b130d05..b68665323 100755
--- a/Configure
+++ b/Configure
@@ -130,7 +130,7 @@ my $x86_elf_asm="$x86_asm:elf";
 
 my $x86_64_asm="x86_64cpuid.o:x86_64-gcc.o x86_64-mont.o x86_64-mont5.o x86_64-gf2m.o modexp512-x86_64.o::aes-x86_64.o vpaes-x86_64.o bsaes-x86_64.o aesni-x86_64.o aesni-sha1-x86_64.o aesni-sha256-x86_64.o::md5-x86_64.o:sha1-x86_64.o sha256-x86_64.o sha512-x86_64.o::rc4-x86_64.o rc4-md5-x86_64.o:::wp-x86_64.o:cmll-x86_64.o cmll_misc.o:ghash-x86_64.o aesni-gcm-x86_64.o:";
 my $ia64_asm="ia64cpuid.o:bn-ia64.o ia64-mont.o::aes_core.o aes_cbc.o aes-ia64.o::md5-ia64.o:sha1-ia64.o sha256-ia64.o sha512-ia64.o::rc4-ia64.o rc4_skey.o:::::ghash-ia64.o::void";
-my $sparcv9_asm="sparcv9cap.o sparccpuid.o:bn-sparcv9.o sparcv9-mont.o sparcv9a-mont.o:des_enc-sparc.o fcrypt_b.o dest4-sparcv9.o:aes_core.o aes_cbc.o aes-sparcv9.o aest4-sparcv9.o:::sha1-sparcv9.o sha256-sparcv9.o sha512-sparcv9.o:::::::ghash-sparcv9.o::void";
+my $sparcv9_asm="sparcv9cap.o sparccpuid.o:bn-sparcv9.o sparcv9-mont.o sparcv9a-mont.o:des_enc-sparc.o fcrypt_b.o dest4-sparcv9.o:aes_core.o aes_cbc.o aes-sparcv9.o aest4-sparcv9.o:::sha1-sparcv9.o sha256-sparcv9.o sha512-sparcv9.o::::::camellia.o cmll_misc.o cmll_cbc.o cmllt4-sparcv9.o:ghash-sparcv9.o::void";
 my $sparcv8_asm=":sparcv8.o:des_enc-sparc.o fcrypt_b.o:::::::::::::void";
 my $alpha_asm="alphacpuid.o:bn_asm.o alpha-mont.o:::::sha1-alpha.o:::::::ghash-alpha.o::void";
 my $mips64_asm=":bn-mips.o mips-mont.o::aes_cbc.o aes-mips.o:::sha1-mips.o sha256-mips.o sha512-mips.o::::::::";
diff --git a/TABLE b/TABLE
index 5b21bddd3..b81f18ca1 100644
--- a/TABLE
+++ b/TABLE
@@ -185,7 +185,7 @@ $rc4_obj      =
 $rmd160_obj   = 
 $rc5_obj      = 
 $wp_obj       = 
-$cmll_obj     = 
+$cmll_obj     = camellia.o cmll_misc.o cmll_cbc.o cmllt4-sparcv9.o
 $modes_obj    = ghash-sparcv9.o
 $engines_obj  = 
 $perlasm_scheme = void
@@ -2726,7 +2726,7 @@ $rc4_obj      =
 $rmd160_obj   = 
 $rc5_obj      = 
 $wp_obj       = 
-$cmll_obj     = 
+$cmll_obj     = camellia.o cmll_misc.o cmll_cbc.o cmllt4-sparcv9.o
 $modes_obj    = ghash-sparcv9.o
 $engines_obj  = 
 $perlasm_scheme = void
@@ -2759,7 +2759,7 @@ $rc4_obj      =
 $rmd160_obj   = 
 $rc5_obj      = 
 $wp_obj       = 
-$cmll_obj     = 
+$cmll_obj     = camellia.o cmll_misc.o cmll_cbc.o cmllt4-sparcv9.o
 $modes_obj    = ghash-sparcv9.o
 $engines_obj  = 
 $perlasm_scheme = void
@@ -4442,7 +4442,7 @@ $rc4_obj      =
 $rmd160_obj   = 
 $rc5_obj      = 
 $wp_obj       = 
-$cmll_obj     = 
+$cmll_obj     = camellia.o cmll_misc.o cmll_cbc.o cmllt4-sparcv9.o
 $modes_obj    = ghash-sparcv9.o
 $engines_obj  = 
 $perlasm_scheme = void
@@ -4673,7 +4673,7 @@ $rc4_obj      =
 $rmd160_obj   = 
 $rc5_obj      = 
 $wp_obj       = 
-$cmll_obj     = 
+$cmll_obj     = camellia.o cmll_misc.o cmll_cbc.o cmllt4-sparcv9.o
 $modes_obj    = ghash-sparcv9.o
 $engines_obj  = 
 $perlasm_scheme = void
@@ -5531,7 +5531,7 @@ $rc4_obj      =
 $rmd160_obj   = 
 $rc5_obj      = 
 $wp_obj       = 
-$cmll_obj     = 
+$cmll_obj     = camellia.o cmll_misc.o cmll_cbc.o cmllt4-sparcv9.o
 $modes_obj    = ghash-sparcv9.o
 $engines_obj  = 
 $perlasm_scheme = void
@@ -5564,7 +5564,7 @@ $rc4_obj      =
 $rmd160_obj   = 
 $rc5_obj      = 
 $wp_obj       = 
-$cmll_obj     = 
+$cmll_obj     = camellia.o cmll_misc.o cmll_cbc.o cmllt4-sparcv9.o
 $modes_obj    = ghash-sparcv9.o
 $engines_obj  = 
 $perlasm_scheme = void
@@ -5663,7 +5663,7 @@ $rc4_obj      =
 $rmd160_obj   = 
 $rc5_obj      = 
 $wp_obj       = 
-$cmll_obj     = 
+$cmll_obj     = camellia.o cmll_misc.o cmll_cbc.o cmllt4-sparcv9.o
 $modes_obj    = ghash-sparcv9.o
 $engines_obj  = 
 $perlasm_scheme = void
@@ -5696,7 +5696,7 @@ $rc4_obj      =
 $rmd160_obj   = 
 $rc5_obj      = 
 $wp_obj       = 
-$cmll_obj     = 
+$cmll_obj     = camellia.o cmll_misc.o cmll_cbc.o cmllt4-sparcv9.o
 $modes_obj    = ghash-sparcv9.o
 $engines_obj  = 
 $perlasm_scheme = void
diff --git a/crypto/camellia/Makefile b/crypto/camellia/Makefile
index 6ce6fc99c..88535f963 100644
--- a/crypto/camellia/Makefile
+++ b/crypto/camellia/Makefile
@@ -48,6 +48,8 @@ cmll-x86.s:	asm/cmll-x86.pl ../perlasm/x86asm.pl
 	$(PERL) asm/cmll-x86.pl $(PERLASM_SCHEME) $(CFLAGS) $(PROCESSOR) > $@
 cmll-x86_64.s:  asm/cmll-x86_64.pl
 	$(PERL) asm/cmll-x86_64.pl $(PERLASM_SCHEME) > $@
+cmllt4-sparcv9.s: asm/cmllt4-sparcv9.pl
+	$(PERL) asm/cmllt4-sparcv9.pl $(CFLAGS) > $@
 
 files:
 	$(PERL) $(TOP)/util/files.pl Makefile >> $(TOP)/MINFO
diff --git a/crypto/camellia/asm/cmllt4-sparcv9.pl b/crypto/camellia/asm/cmllt4-sparcv9.pl
new file mode 100644
index 000000000..a813168b4
--- /dev/null
+++ b/crypto/camellia/asm/cmllt4-sparcv9.pl
@@ -0,0 +1,929 @@
+#!/usr/bin/env perl
+
+# ====================================================================
+# Written by David S. Miller <davem@devemloft.net> and Andy Polyakov
+# <appro@openssl.org>. The module is licensed under 2-clause BSD
+# license. October 2012. All rights reserved.
+# ====================================================================
+
+######################################################################
+# Camellia for SPARC T4.
+#
+# As with AES below results [for aligned data] are virtually identical
+# to critical path lenths for 3-cycle instruction latency:
+#
+#		128-bit key	192/256-
+# CBC encrypt	4.14/4.21(*)	5.46/5.52
+#			 (*) numbers after slash are for
+#			     misaligned data.
+#
+# As with Intel AES-NI, question is if it's possible to improve
+# performance of parallelizeable modes by interleaving round
+# instructions. In Camellia every instruction is dependent on
+# previous, which means that there is place for 2 additional ones
+# in between two dependent. Can we expect 3x performance improvement?
+# At least one can argue that it should be possible to break 2x
+# barrier... For some reason not even 2x appears to be possible:
+#
+#		128-bit key	192/256-
+# CBC decrypt	2.21/2.74	2.99/3.40
+# CTR		2.15/2.68(*)	2.93/3.34
+#			 (*) numbers after slash are for
+#			     misaligned data.
+#
+# This is for 2x interleave. But compared to 1x interleave CBC decrypt
+# improved by ... 0% for 128-bit key, and 11% for 192/256-bit one.
+# So that out-of-order execution logic can take non-interleaved code
+# to 1.87x, but can't take 2x interleaved one any further. There
+# surely is some explanation... As result 3x interleave was not even
+# attempted. Instead an effort was made to share specific modes
+# implementations with AES module (therefore sparct4_modes.pl).
+#
+# To anchor to something else, software C implementation processes
+# one byte in 38 cycles with 128-bit key on same processor.
+
+$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
+push(@INC,"${dir}","${dir}../../perlasm");
+require "sparcv9_modes.pl";
+
+&asm_init(@ARGV);
+
+$::evp=1;	# if $evp is set to 0, script generates module with
+# Camellia_[en|de]crypt, Camellia_set_key and Camellia_cbc_encrypt
+# entry points. These are fully compatible with openssl/camellia.h.
+
+######################################################################
+# single-round subroutines
+#
+{
+my ($inp,$out,$key,$rounds,$tmp,$mask)=map("%o$_",(0..5));
+
+$code=<<___;
+.text
+
+.globl	cmll_t4_encrypt
+.align	32
+cmll_t4_encrypt:
+	andcc		$inp, 7, %g1		! is input aligned?
+	andn		$inp, 7, $inp
+
+	ldx		[$key + 0], %g4
+	ldx		[$key + 8], %g5
+
+	ldx		[$inp + 0], %o4
+	bz,pt		%icc, 1f
+	ldx		[$inp + 8], %o5
+	ldx		[$inp + 16], $inp
+	sll		%g1, 3, %g1
+	sub		%g0, %g1, %o3
+	sllx		%o4, %g1, %o4
+	sllx		%o5, %g1, %g1
+	srlx		%o5, %o3, %o5
+	srlx		$inp, %o3, %o3
+	or		%o5, %o4, %o4
+	or		%o3, %g1, %o5
+1:
+	ld		[$key + 272], $rounds	! grandRounds, 3 or 4
+	ldd		[$key + 16], %f12
+	ldd		[$key + 24], %f14
+	xor		%g4, %o4, %o4
+	xor		%g5, %o5, %o5
+	ldd		[$key + 32], %f16
+	ldd		[$key + 40], %f18
+	movxtod		%o4, %f0
+	movxtod		%o5, %f2
+	ldd		[$key + 48], %f20
+	ldd		[$key + 56], %f22
+	sub		$rounds, 1, $rounds
+	ldd		[$key + 64], %f24
+	ldd		[$key + 72], %f26
+	add		$key, 80, $key
+
+.Lenc:
+	camellia_f	%f12, %f2, %f0, %f2
+	ldd		[$key + 0], %f12
+	sub		$rounds,1,$rounds
+	camellia_f	%f14, %f0, %f2, %f0
+	ldd		[$key + 8], %f14
+	camellia_f	%f16, %f2, %f0, %f2
+	ldd		[$key + 16], %f16
+	camellia_f	%f18, %f0, %f2, %f0
+	ldd		[$key + 24], %f18
+	camellia_f	%f20, %f2, %f0, %f2
+	ldd		[$key + 32], %f20
+	camellia_f	%f22, %f0, %f2, %f0
+	ldd		[$key + 40], %f22
+	camellia_fl	%f24, %f0, %f0
+	ldd		[$key + 48], %f24
+	camellia_fli	%f26, %f2, %f2
+	ldd		[$key + 56], %f26
+	brnz,pt		$rounds, .Lenc
+	add		$key, 64, $key
+
+	andcc		$out, 7, $tmp		! is output aligned?
+	camellia_f	%f12, %f2, %f0, %f2
+	camellia_f	%f14, %f0, %f2, %f0
+	camellia_f	%f16, %f2, %f0, %f2
+	camellia_f	%f18, %f0, %f2, %f0
+	camellia_f	%f20, %f2, %f0, %f4
+	camellia_f	%f22, %f0, %f4, %f2
+	fxor		%f24, %f4, %f0
+	fxor		%f26, %f2, %f2
+
+	bnz,pn		%icc, 2f
+	nop
+
+	std		%f0, [$out + 0]
+	retl
+	std		%f2, [$out + 8]
+
+2:	alignaddrl	$out, %g0, $out
+	mov		0xff, $mask
+	srl		$mask, $tmp, $mask
+
+	faligndata	%f0, %f0, %f4
+	faligndata	%f0, %f2, %f6
+	faligndata	%f2, %f2, %f8
+
+	stda		%f4, [$out + $mask]0xc0	! partial store
+	std		%f6, [$out + 8]
+	add		$out, 16, $out
+	orn		%g0, $mask, $mask
+	retl
+	stda		%f8, [$out + $mask]0xc0	! partial store
+.type	cmll_t4_encrypt,#function
+.size	cmll_t4_encrypt,.-cmll_t4_encrypt
+
+.globl	cmll_t4_decrypt
+.align	32
+cmll_t4_decrypt:
+	ld		[$key + 272], $rounds	! grandRounds, 3 or 4
+	andcc		$inp, 7, %g1		! is input aligned?
+	andn		$inp, 7, $inp
+
+	sll		$rounds, 6, $rounds
+	add		$rounds, $key, $key
+
+	ldx		[$inp + 0], %o4
+	bz,pt		%icc, 1f
+	ldx		[$inp + 8], %o5
+	ldx		[$inp + 16], $inp
+	sll		%g1, 3, %g1
+	sub		%g0, %g1, %g4
+	sllx		%o4, %g1, %o4
+	sllx		%o5, %g1, %g1
+	srlx		%o5, %g4, %o5
+	srlx		$inp, %g4, %g4
+	or		%o5, %o4, %o4
+	or		%g4, %g1, %o5
+1:
+	ldx		[$key + 0], %g4
+	ldx		[$key + 8], %g5
+	ldd		[$key - 8], %f12
+	ldd		[$key - 16], %f14
+	xor		%g4, %o4, %o4
+	xor		%g5, %o5, %o5
+	ldd		[$key - 24], %f16
+	ldd		[$key - 32], %f18
+	movxtod		%o4, %f0
+	movxtod		%o5, %f2
+	ldd		[$key - 40], %f20
+	ldd		[$key - 48], %f22
+	sub		$rounds, 64, $rounds
+	ldd		[$key - 56], %f24
+	ldd		[$key - 64], %f26
+	sub		$key, 64, $key
+
+.Ldec:
+	camellia_f	%f12, %f2, %f0, %f2
+	ldd		[$key - 8], %f12
+	sub		$rounds, 64, $rounds
+	camellia_f	%f14, %f0, %f2, %f0
+	ldd		[$key - 16], %f14
+	camellia_f	%f16, %f2, %f0, %f2
+	ldd		[$key - 24], %f16
+	camellia_f	%f18, %f0, %f2, %f0
+	ldd		[$key - 32], %f18
+	camellia_f	%f20, %f2, %f0, %f2
+	ldd		[$key - 40], %f20
+	camellia_f	%f22, %f0, %f2, %f0
+	ldd		[$key - 48], %f22
+	camellia_fl	%f24, %f0, %f0
+	ldd		[$key - 56], %f24
+	camellia_fli	%f26, %f2, %f2
+	ldd		[$key - 64], %f26
+	brnz,pt		$rounds, .Ldec
+	sub		$key, 64, $key
+
+	andcc		$out, 7, $tmp		! is output aligned?
+	camellia_f	%f12, %f2, %f0, %f2
+	camellia_f	%f14, %f0, %f2, %f0
+	camellia_f	%f16, %f2, %f0, %f2
+	camellia_f	%f18, %f0, %f2, %f0
+	camellia_f	%f20, %f2, %f0, %f4
+	camellia_f	%f22, %f0, %f4, %f2
+	fxor		%f26, %f4, %f0
+	fxor		%f24, %f2, %f2
+
+	bnz,pn		%icc, 2f
+	nop
+
+	std		%f0, [$out + 0]
+	retl
+	std		%f2, [$out + 8]
+
+2:	alignaddrl	$out, %g0, $out
+	mov		0xff, $mask
+	srl		$mask, $tmp, $mask
+
+	faligndata	%f0, %f0, %f4
+	faligndata	%f0, %f2, %f6
+	faligndata	%f2, %f2, %f8
+
+	stda		%f4, [$out + $mask]0xc0	! partial store
+	std		%f6, [$out + 8]
+	add		$out, 16, $out
+	orn		%g0, $mask, $mask
+	retl
+	stda		%f8, [$out + $mask]0xc0	! partial store
+.type	cmll_t4_decrypt,#function
+.size	cmll_t4_decrypt,.-cmll_t4_decrypt
+___
+}
+
+######################################################################
+# key setup subroutines
+#
+{
+sub ROTL128 {
+  my $rot = shift;
+
+	"srlx	%o4, 64-$rot, %g4\n\t".
+	"sllx	%o4, $rot, %o4\n\t".
+	"srlx	%o5, 64-$rot, %g5\n\t".
+	"sllx	%o5, $rot, %o5\n\t".
+	"or	%o4, %g5, %o4\n\t".
+	"or	%o5, %g4, %o5";
+}
+
+my ($inp,$bits,$out,$tmp)=map("%o$_",(0..5));
+$code.=<<___;
+.globl	cmll_t4_set_key
+.align	32
+cmll_t4_set_key:
+	and		$inp, 7, $tmp
+	alignaddr	$inp, %g0, $inp
+	cmp		$bits, 192
+	ldd		[$inp + 0], %f0
+	bl,pt		%icc,.L128
+	ldd		[$inp + 8], %f2
+
+	be,pt		%icc,.L192
+	ldd		[$inp + 16], %f4
+
+	brz,pt		$tmp, .L256aligned
+	ldd		[$inp + 24], %f6
+
+	ldd		[$inp + 32], %f8
+	faligndata	%f0, %f2, %f0
+	faligndata	%f2, %f4, %f2
+	faligndata	%f4, %f6, %f4
+	b		.L256aligned
+	faligndata	%f6, %f8, %f6
+
+.align	16
+.L192:
+	brz,a,pt	$tmp, .L256aligned
+	fnot2		%f4, %f6
+
+	ldd		[$inp + 24], %f6
+	nop
+	faligndata	%f0, %f2, %f0
+	faligndata	%f2, %f4, %f2
+	faligndata	%f4, %f6, %f4
+	fnot2		%f4, %f6
+
+.L256aligned:
+	std		%f0, [$out + 0]		! k[0, 1]
+	fsrc2		%f0, %f28
+	std		%f2, [$out + 8]		! k[2, 3]
+	fsrc2		%f2, %f30
+	fxor		%f4, %f0, %f0
+	b		.L128key
+	fxor		%f6, %f2, %f2
+
+.align	16
+.L128:
+	brz,pt		$tmp, .L128aligned
+	nop
+
+	ldd		[$inp + 16], %f4
+	nop
+	faligndata	%f0, %f2, %f0
+	faligndata	%f2, %f4, %f2
+
+.L128aligned:
+	std		%f0, [$out + 0]		! k[0, 1]
+	fsrc2		%f0, %f28
+	std		%f2, [$out + 8]		! k[2, 3]
+	fsrc2		%f2, %f30
+
+.L128key:
+	mov		%o7, %o5
+1:	call		.+8
+	add		%o7, SIGMA-1b, %o4
+	mov		%o5, %o7
+
+	ldd		[%o4 + 0], %f16
+	ldd		[%o4 + 8], %f18
+	ldd		[%o4 + 16], %f20
+	ldd		[%o4 + 24], %f22
+
+	camellia_f	%f16, %f2, %f0, %f2
+	camellia_f	%f18, %f0, %f2, %f0
+	fxor		%f28, %f0, %f0
+	fxor		%f30, %f2, %f2
+	camellia_f	%f20, %f2, %f0, %f2
+	camellia_f	%f22, %f0, %f2, %f0
+
+	bge,pn		%icc, .L256key
+	nop
+	std	%f0, [$out + 0x10]	! k[ 4,  5]
+	std	%f2, [$out + 0x18]	! k[ 6,  7]
+
+	movdtox	%f0, %o4
+	movdtox	%f2, %o5
+	`&ROTL128(15)`
+	stx	%o4, [$out + 0x30]	! k[12, 13]
+	stx	%o5, [$out + 0x38]	! k[14, 15]
+	`&ROTL128(15)`
+	stx	%o4, [$out + 0x40]	! k[16, 17]
+	stx	%o5, [$out + 0x48]	! k[18, 19]
+	`&ROTL128(15)`
+	stx	%o4, [$out + 0x60]	! k[24, 25]
+	`&ROTL128(15)`
+	stx	%o4, [$out + 0x70]	! k[28, 29]
+	stx	%o5, [$out + 0x78]	! k[30, 31]
+	`&ROTL128(34)`
+	stx	%o4, [$out + 0xa0]	! k[40, 41]
+	stx	%o5, [$out + 0xa8]	! k[42, 43]
+	`&ROTL128(17)`
+	stx	%o4, [$out + 0xc0]	! k[48, 49]
+	stx	%o5, [$out + 0xc8]	! k[50, 51]
+
+	movdtox	%f28, %o4		! k[ 0,  1]
+	movdtox	%f30, %o5		! k[ 2,  3]
+	`&ROTL128(15)`
+	stx	%o4, [$out + 0x20]	! k[ 8,  9]
+	stx	%o5, [$out + 0x28]	! k[10, 11]
+	`&ROTL128(30)`
+	stx	%o4, [$out + 0x50]	! k[20, 21]
+	stx	%o5, [$out + 0x58]	! k[22, 23]
+	`&ROTL128(15)`
+	stx	%o5, [$out + 0x68]	! k[26, 27]
+	`&ROTL128(17)`
+	stx	%o4, [$out + 0x80]	! k[32, 33]
+	stx	%o5, [$out + 0x88]	! k[34, 35]
+	`&ROTL128(17)`
+	stx	%o4, [$out + 0x90]	! k[36, 37]
+	stx	%o5, [$out + 0x98]	! k[38, 39]
+	`&ROTL128(17)`
+	stx	%o4, [$out + 0xb0]	! k[44, 45]
+	stx	%o5, [$out + 0xb8]	! k[46, 47]
+
+	mov		3, $tmp
+	st		$tmp, [$out + 0x110]
+	retl
+	xor		%o0, %o0, %o0
+
+.align	16
+.L256key:
+	ldd		[%o4 + 32], %f24
+	ldd		[%o4 + 40], %f26
+
+	std		%f0, [$out + 0x30]	! k[12, 13]
+	std		%f2, [$out + 0x38]	! k[14, 15]
+
+	fxor		%f4, %f0, %f0
+	fxor		%f6, %f2, %f2
+	camellia_f	%f24, %f2, %f0, %f2
+	camellia_f	%f26, %f0, %f2, %f0
+
+	std	%f0, [$out + 0x10]	! k[ 4,  5]
+	std	%f2, [$out + 0x18]	! k[ 6,  7]
+
+	movdtox	%f0, %o4
+	movdtox	%f2, %o5
+	`&ROTL128(30)`
+	stx	%o4, [$out + 0x50]	! k[20, 21]
+	stx	%o5, [$out + 0x58]	! k[22, 23]
+	`&ROTL128(30)`
+	stx	%o4, [$out + 0xa0]	! k[40, 41]
+	stx	%o5, [$out + 0xa8]	! k[42, 43]
+	`&ROTL128(51)`
+	stx	%o4, [$out + 0x100]	! k[64, 65]
+	stx	%o5, [$out + 0x108]	! k[66, 67]
+
+	movdtox	%f4, %o4		! k[ 8,  9]
+	movdtox	%f6, %o5		! k[10, 11]
+	`&ROTL128(15)`
+	stx	%o4, [$out + 0x20]	! k[ 8,  9]
+	stx	%o5, [$out + 0x28]	! k[10, 11]
+	`&ROTL128(15)`
+	stx	%o4, [$out + 0x40]	! k[16, 17]
+	stx	%o5, [$out + 0x48]	! k[18, 19]
+	`&ROTL128(30)`
+	stx	%o4, [$out + 0x90]	! k[36, 37]
+	stx	%o5, [$out + 0x98]	! k[38, 39]
+	`&ROTL128(34)`
+	stx	%o4, [$out + 0xd0]	! k[52, 53]
+	stx	%o5, [$out + 0xd8]	! k[54, 55]
+	ldx	[$out + 0x30], %o4	! k[12, 13]
+	ldx	[$out + 0x38], %o5	! k[14, 15]
+	`&ROTL128(15)`
+	stx	%o4, [$out + 0x30]	! k[12, 13]
+	stx	%o5, [$out + 0x38]	! k[14, 15]
+	`&ROTL128(30)`
+	stx	%o4, [$out + 0x70]	! k[28, 29]
+	stx	%o5, [$out + 0x78]	! k[30, 31]
+	srlx	%o4, 32, %g4
+	srlx	%o5, 32, %g5
+	st	%o4, [$out + 0xc0]	! k[48]
+	st	%g5, [$out + 0xc4]	! k[49]
+	st	%o5, [$out + 0xc8]	! k[50]
+	st	%g4, [$out + 0xcc]	! k[51]
+	`&ROTL128(49)`
+	stx	%o4, [$out + 0xe0]	! k[56, 57]
+	stx	%o5, [$out + 0xe8]	! k[58, 59]
+
+	movdtox	%f28, %o4		! k[ 0,  1]
+	movdtox	%f30, %o5		! k[ 2,  3]
+	`&ROTL128(45)`
+	stx	%o4, [$out + 0x60]	! k[24, 25]
+	stx	%o5, [$out + 0x68]	! k[26, 27]
+	`&ROTL128(15)`
+	stx	%o4, [$out + 0x80]	! k[32, 33]
+	stx	%o5, [$out + 0x88]	! k[34, 35]
+	`&ROTL128(17)`
+	stx	%o4, [$out + 0xb0]	! k[44, 45]
+	stx	%o5, [$out + 0xb8]	! k[46, 47]
+	`&ROTL128(34)`
+	stx	%o4, [$out + 0xf0]	! k[60, 61]
+	stx	%o5, [$out + 0xf8]	! k[62, 63]
+
+	mov		4, $tmp
+	st		$tmp, [$out + 0x110]
+	retl
+	xor		%o0, %o0, %o0
+.type	cmll_t4_set_key,#function
+.size	cmll_t4_set_key,.-cmll_t4_set_key
+.align	32
+SIGMA:
+	.long	0xa09e667f, 0x3bcc908b, 0xb67ae858, 0x4caa73b2
+	.long	0xc6ef372f, 0xe94f82be, 0x54ff53a5, 0xf1d36f1c
+	.long	0x10e527fa, 0xde682d1d, 0xb05688c2, 0xb3e6c1fd
+.type	SIGMA,#object
+.size	SIGMA,.-SIGMA
+.asciz	"Camellia for SPARC T4, David S. Miller, Andy Polyakov"
+___
+}
+
+{{{
+my ($inp,$out,$len,$key,$ivec,$enc)=map("%i$_",(0..5));
+my ($ileft,$iright,$ooff,$omask,$ivoff)=map("%l$_",(1..7));
+
+$code.=<<___;
+.align	32
+_cmll128_load_enckey:
+	ldx		[$key + 0], %g4
+	ldx		[$key + 8], %g5
+___
+for ($i=2; $i<26;$i++) {			# load key schedule
+    $code.=<<___;
+	ldd		[$key + `8*$i`], %f`12+2*$i`
+___
+}
+$code.=<<___;
+	retl
+	nop
+.type	_cmll128_load_enckey,#function
+.size	_cmll128_load_enckey,.-_cmll128_load_enckey
+_cmll256_load_enckey=_cmll128_load_enckey
+
+.align	32
+_cmll256_load_deckey:
+	ldd		[$key + 64], %f62
+	ldd		[$key + 72], %f60
+	b		.Load_deckey
+	add		$key, 64, $key
+_cmll128_load_deckey:
+	ldd		[$key + 0], %f60
+	ldd		[$key + 8], %f62
+.Load_deckey:
+___
+for ($i=2; $i<24;$i++) {			# load key schedule
+    $code.=<<___;
+	ldd		[$key + `8*$i`], %f`62-2*$i`
+___
+}
+$code.=<<___;
+	ldx		[$key + 192], %g4
+	retl
+	ldx		[$key + 200], %g5
+.type	_cmll256_load_deckey,#function
+.size	_cmll256_load_deckey,.-_cmll256_load_deckey
+
+.align	32
+_cmll128_encrypt_1x:
+___
+for ($i=0; $i<3; $i++) {
+    $code.=<<___;
+	camellia_f	%f`16+16*$i+0`, %f2, %f0, %f2
+	camellia_f	%f`16+16*$i+2`, %f0, %f2, %f0
+	camellia_f	%f`16+16*$i+4`, %f2, %f0, %f2
+	camellia_f	%f`16+16*$i+6`, %f0, %f2, %f0
+___
+$code.=<<___ if ($i<2);
+	camellia_f	%f`16+16*$i+8`, %f2, %f0, %f2
+	camellia_f	%f`16+16*$i+10`, %f0, %f2, %f0
+	camellia_fl	%f`16+16*$i+12`, %f0,      %f0
+	camellia_fli	%f`16+16*$i+14`, %f2,      %f2
+___
+}
+$code.=<<___;
+	camellia_f	%f56, %f2, %f0, %f4
+	camellia_f	%f58, %f0, %f4, %f2
+	fxor		%f60, %f4, %f0
+	retl
+	fxor		%f62, %f2, %f2
+.type	_cmll128_encrypt_1x,#function
+.size	_cmll128_encrypt_1x,.-_cmll128_encrypt_1x
+_cmll128_decrypt_1x=_cmll128_encrypt_1x
+
+.align	32
+_cmll128_encrypt_2x:
+___
+for ($i=0; $i<3; $i++) {
+    $code.=<<___;
+	camellia_f	%f`16+16*$i+0`, %f2, %f0, %f2
+	camellia_f	%f`16+16*$i+0`, %f6, %f4, %f6
+	camellia_f	%f`16+16*$i+2`, %f0, %f2, %f0
+	camellia_f	%f`16+16*$i+2`, %f4, %f6, %f4
+	camellia_f	%f`16+16*$i+4`, %f2, %f0, %f2
+	camellia_f	%f`16+16*$i+4`, %f6, %f4, %f6
+	camellia_f	%f`16+16*$i+6`, %f0, %f2, %f0
+	camellia_f	%f`16+16*$i+6`, %f4, %f6, %f4
+___
+$code.=<<___ if ($i<2);
+	camellia_f	%f`16+16*$i+8`, %f2, %f0, %f2
+	camellia_f	%f`16+16*$i+8`, %f6, %f4, %f6
+	camellia_f	%f`16+16*$i+10`, %f0, %f2, %f0
+	camellia_f	%f`16+16*$i+10`, %f4, %f6, %f4
+	camellia_fl	%f`16+16*$i+12`, %f0,      %f0
+	camellia_fl	%f`16+16*$i+12`, %f4,      %f4
+	camellia_fli	%f`16+16*$i+14`, %f2,      %f2
+	camellia_fli	%f`16+16*$i+14`, %f6,      %f6
+___
+}
+$code.=<<___;
+	camellia_f	%f56, %f2, %f0, %f8
+	camellia_f	%f56, %f6, %f4, %f10
+	camellia_f	%f58, %f0, %f8, %f2
+	camellia_f	%f58, %f4, %f10, %f6
+	fxor		%f60, %f8, %f0
+	fxor		%f60, %f10, %f4
+	fxor		%f62, %f2, %f2
+	retl
+	fxor		%f62, %f6, %f6
+.type	_cmll128_encrypt_2x,#function
+.size	_cmll128_encrypt_2x,.-_cmll128_encrypt_2x
+_cmll128_decrypt_2x=_cmll128_encrypt_2x
+
+.align	32
+_cmll256_encrypt_1x:
+	camellia_f	%f16, %f2, %f0, %f2
+	camellia_f	%f18, %f0, %f2, %f0
+	ldd		[$key + 208], %f16
+	ldd		[$key + 216], %f18
+	camellia_f	%f20, %f2, %f0, %f2
+	camellia_f	%f22, %f0, %f2, %f0
+	ldd		[$key + 224], %f20
+	ldd		[$key + 232], %f22
+	camellia_f	%f24, %f2, %f0, %f2
+	camellia_f	%f26, %f0, %f2, %f0
+	ldd		[$key + 240], %f24
+	ldd		[$key + 248], %f26
+	camellia_fl	%f28, %f0, %f0
+	camellia_fli	%f30, %f2, %f2
+	ldd		[$key + 256], %f28
+	ldd		[$key + 264], %f30
+___
+for ($i=1; $i<3; $i++) {
+    $code.=<<___;
+	camellia_f	%f`16+16*$i+0`, %f2, %f0, %f2
+	camellia_f	%f`16+16*$i+2`, %f0, %f2, %f0
+	camellia_f	%f`16+16*$i+4`, %f2, %f0, %f2
+	camellia_f	%f`16+16*$i+6`, %f0, %f2, %f0
+	camellia_f	%f`16+16*$i+8`, %f2, %f0, %f2
+	camellia_f	%f`16+16*$i+10`, %f0, %f2, %f0
+	camellia_fl	%f`16+16*$i+12`, %f0,      %f0
+	camellia_fli	%f`16+16*$i+14`, %f2,      %f2
+___
+}
+$code.=<<___;
+	camellia_f	%f16, %f2, %f0, %f2
+	camellia_f	%f18, %f0, %f2, %f0
+	ldd		[$key + 16], %f16
+	ldd		[$key + 24], %f18
+	camellia_f	%f20, %f2, %f0, %f2
+	camellia_f	%f22, %f0, %f2, %f0
+	ldd		[$key + 32], %f20
+	ldd		[$key + 40], %f22
+	camellia_f	%f24, %f2, %f0, %f4
+	camellia_f	%f26, %f0, %f4, %f2
+	ldd		[$key + 48], %f24
+	ldd		[$key + 56], %f26
+	fxor		%f28, %f4, %f0
+	fxor		%f30, %f2, %f2
+	ldd		[$key + 64], %f28
+	retl
+	ldd		[$key + 72], %f30
+.type	_cmll256_encrypt_1x,#function
+.size	_cmll256_encrypt_1x,.-_cmll256_encrypt_1x
+
+.align	32
+_cmll256_encrypt_2x:
+	camellia_f	%f16, %f2, %f0, %f2
+	camellia_f	%f16, %f6, %f4, %f6
+	camellia_f	%f18, %f0, %f2, %f0
+	camellia_f	%f18, %f4, %f6, %f4
+	ldd		[$key + 208], %f16
+	ldd		[$key + 216], %f18
+	camellia_f	%f20, %f2, %f0, %f2
+	camellia_f	%f20, %f6, %f4, %f6
+	camellia_f	%f22, %f0, %f2, %f0
+	camellia_f	%f22, %f4, %f6, %f4
+	ldd		[$key + 224], %f20
+	ldd		[$key + 232], %f22
+	camellia_f	%f24, %f2, %f0, %f2
+	camellia_f	%f24, %f6, %f4, %f6
+	camellia_f	%f26, %f0, %f2, %f0
+	camellia_f	%f26, %f4, %f6, %f4
+	ldd		[$key + 240], %f24
+	ldd		[$key + 248], %f26
+	camellia_fl	%f28, %f0, %f0
+	camellia_fl	%f28, %f4, %f4
+	camellia_fli	%f30, %f2, %f2
+	camellia_fli	%f30, %f6, %f6
+	ldd		[$key + 256], %f28
+	ldd		[$key + 264], %f30
+___
+for ($i=1; $i<3; $i++) {
+    $code.=<<___;
+	camellia_f	%f`16+16*$i+0`, %f2, %f0, %f2
+	camellia_f	%f`16+16*$i+0`, %f6, %f4, %f6
+	camellia_f	%f`16+16*$i+2`, %f0, %f2, %f0
+	camellia_f	%f`16+16*$i+2`, %f4, %f6, %f4
+	camellia_f	%f`16+16*$i+4`, %f2, %f0, %f2
+	camellia_f	%f`16+16*$i+4`, %f6, %f4, %f6
+	camellia_f	%f`16+16*$i+6`, %f0, %f2, %f0
+	camellia_f	%f`16+16*$i+6`, %f4, %f6, %f4
+	camellia_f	%f`16+16*$i+8`, %f2, %f0, %f2
+	camellia_f	%f`16+16*$i+8`, %f6, %f4, %f6
+	camellia_f	%f`16+16*$i+10`, %f0, %f2, %f0
+	camellia_f	%f`16+16*$i+10`, %f4, %f6, %f4
+	camellia_fl	%f`16+16*$i+12`, %f0,      %f0
+	camellia_fl	%f`16+16*$i+12`, %f4,      %f4
+	camellia_fli	%f`16+16*$i+14`, %f2,      %f2
+	camellia_fli	%f`16+16*$i+14`, %f6,      %f6
+___
+}
+$code.=<<___;
+	camellia_f	%f16, %f2, %f0, %f2
+	camellia_f	%f16, %f6, %f4, %f6
+	camellia_f	%f18, %f0, %f2, %f0
+	camellia_f	%f18, %f4, %f6, %f4
+	ldd		[$key + 16], %f16
+	ldd		[$key + 24], %f18
+	camellia_f	%f20, %f2, %f0, %f2
+	camellia_f	%f20, %f6, %f4, %f6
+	camellia_f	%f22, %f0, %f2, %f0
+	camellia_f	%f22, %f4, %f6, %f4
+	ldd		[$key + 32], %f20
+	ldd		[$key + 40], %f22
+	camellia_f	%f24, %f2, %f0, %f8
+	camellia_f	%f24, %f6, %f4, %f10
+	camellia_f	%f26, %f0, %f8, %f2
+	camellia_f	%f26, %f4, %f10, %f6
+	ldd		[$key + 48], %f24
+	ldd		[$key + 56], %f26
+	fxor		%f28, %f8, %f0
+	fxor		%f28, %f10, %f4
+	fxor		%f30, %f2, %f2
+	fxor		%f30, %f6, %f6
+	ldd		[$key + 64], %f28
+	retl
+	ldd		[$key + 72], %f30
+.type	_cmll256_encrypt_2x,#function
+.size	_cmll256_encrypt_2x,.-_cmll256_encrypt_2x
+
+.align	32
+_cmll256_decrypt_1x:
+	camellia_f	%f16, %f2, %f0, %f2
+	camellia_f	%f18, %f0, %f2, %f0
+	ldd		[$key - 8], %f16
+	ldd		[$key - 16], %f18
+	camellia_f	%f20, %f2, %f0, %f2
+	camellia_f	%f22, %f0, %f2, %f0
+	ldd		[$key - 24], %f20
+	ldd		[$key - 32], %f22
+	camellia_f	%f24, %f2, %f0, %f2
+	camellia_f	%f26, %f0, %f2, %f0
+	ldd		[$key - 40], %f24
+	ldd		[$key - 48], %f26
+	camellia_fl	%f28, %f0, %f0
+	camellia_fli	%f30, %f2, %f2
+	ldd		[$key - 56], %f28
+	ldd		[$key - 64], %f30
+___
+for ($i=1; $i<3; $i++) {
+    $code.=<<___;
+	camellia_f	%f`16+16*$i+0`, %f2, %f0, %f2
+	camellia_f	%f`16+16*$i+2`, %f0, %f2, %f0
+	camellia_f	%f`16+16*$i+4`, %f2, %f0, %f2
+	camellia_f	%f`16+16*$i+6`, %f0, %f2, %f0
+	camellia_f	%f`16+16*$i+8`, %f2, %f0, %f2
+	camellia_f	%f`16+16*$i+10`, %f0, %f2, %f0
+	camellia_fl	%f`16+16*$i+12`, %f0,      %f0
+	camellia_fli	%f`16+16*$i+14`, %f2,      %f2
+___
+}
+$code.=<<___;
+	camellia_f	%f16, %f2, %f0, %f2
+	camellia_f	%f18, %f0, %f2, %f0
+	ldd		[$key + 184], %f16
+	ldd		[$key + 176], %f18
+	camellia_f	%f20, %f2, %f0, %f2
+	camellia_f	%f22, %f0, %f2, %f0
+	ldd		[$key + 168], %f20
+	ldd		[$key + 160], %f22
+	camellia_f	%f24, %f2, %f0, %f4
+	camellia_f	%f26, %f0, %f4, %f2
+	ldd		[$key + 152], %f24
+	ldd		[$key + 144], %f26
+	fxor		%f30, %f4, %f0
+	fxor		%f28, %f2, %f2
+	ldd		[$key + 136], %f28
+	retl
+	ldd		[$key + 128], %f30
+.type	_cmll256_decrypt_1x,#function
+.size	_cmll256_decrypt_1x,.-_cmll256_decrypt_1x
+
+.align	32
+_cmll256_decrypt_2x:
+	camellia_f	%f16, %f2, %f0, %f2
+	camellia_f	%f16, %f6, %f4, %f6
+	camellia_f	%f18, %f0, %f2, %f0
+	camellia_f	%f18, %f4, %f6, %f4
+	ldd		[$key - 8], %f16
+	ldd		[$key - 16], %f18
+	camellia_f	%f20, %f2, %f0, %f2
+	camellia_f	%f20, %f6, %f4, %f6
+	camellia_f	%f22, %f0, %f2, %f0
+	camellia_f	%f22, %f4, %f6, %f4
+	ldd		[$key - 24], %f20
+	ldd		[$key - 32], %f22
+	camellia_f	%f24, %f2, %f0, %f2
+	camellia_f	%f24, %f6, %f4, %f6
+	camellia_f	%f26, %f0, %f2, %f0
+	camellia_f	%f26, %f4, %f6, %f4
+	ldd		[$key - 40], %f24
+	ldd		[$key - 48], %f26
+	camellia_fl	%f28, %f0, %f0
+	camellia_fl	%f28, %f4, %f4
+	camellia_fli	%f30, %f2, %f2
+	camellia_fli	%f30, %f6, %f6
+	ldd		[$key - 56], %f28
+	ldd		[$key - 64], %f30
+___
+for ($i=1; $i<3; $i++) {
+    $code.=<<___;
+	camellia_f	%f`16+16*$i+0`, %f2, %f0, %f2
+	camellia_f	%f`16+16*$i+0`, %f6, %f4, %f6
+	camellia_f	%f`16+16*$i+2`, %f0, %f2, %f0
+	camellia_f	%f`16+16*$i+2`, %f4, %f6, %f4
+	camellia_f	%f`16+16*$i+4`, %f2, %f0, %f2
+	camellia_f	%f`16+16*$i+4`, %f6, %f4, %f6
+	camellia_f	%f`16+16*$i+6`, %f0, %f2, %f0
+	camellia_f	%f`16+16*$i+6`, %f4, %f6, %f4
+	camellia_f	%f`16+16*$i+8`, %f2, %f0, %f2
+	camellia_f	%f`16+16*$i+8`, %f6, %f4, %f6
+	camellia_f	%f`16+16*$i+10`, %f0, %f2, %f0
+	camellia_f	%f`16+16*$i+10`, %f4, %f6, %f4
+	camellia_fl	%f`16+16*$i+12`, %f0,      %f0
+	camellia_fl	%f`16+16*$i+12`, %f4,      %f4
+	camellia_fli	%f`16+16*$i+14`, %f2,      %f2
+	camellia_fli	%f`16+16*$i+14`, %f6,      %f6
+___
+}
+$code.=<<___;
+	camellia_f	%f16, %f2, %f0, %f2
+	camellia_f	%f16, %f6, %f4, %f6
+	camellia_f	%f18, %f0, %f2, %f0
+	camellia_f	%f18, %f4, %f6, %f4
+	ldd		[$key + 184], %f16
+	ldd		[$key + 176], %f18
+	camellia_f	%f20, %f2, %f0, %f2
+	camellia_f	%f20, %f6, %f4, %f6
+	camellia_f	%f22, %f0, %f2, %f0
+	camellia_f	%f22, %f4, %f6, %f4
+	ldd		[$key + 168], %f20
+	ldd		[$key + 160], %f22
+	camellia_f	%f24, %f2, %f0, %f8
+	camellia_f	%f24, %f6, %f4, %f10
+	camellia_f	%f26, %f0, %f8, %f2
+	camellia_f	%f26, %f4, %f10, %f6
+	ldd		[$key + 152], %f24
+	ldd		[$key + 144], %f26
+	fxor		%f30, %f8, %f0
+	fxor		%f30, %f10, %f4
+	fxor		%f28, %f2, %f2
+	fxor		%f28, %f6, %f6
+	ldd		[$key + 136], %f28
+	retl
+	ldd		[$key + 128], %f30
+.type	_cmll256_decrypt_2x,#function
+.size	_cmll256_decrypt_2x,.-_cmll256_decrypt_2x
+___
+
+&alg_cbc_encrypt_implement("cmll",128);
+&alg_cbc_encrypt_implement("cmll",256);
+
+&alg_cbc_decrypt_implement("cmll",128);
+&alg_cbc_decrypt_implement("cmll",256);
+
+if ($::evp) {
+    &alg_ctr32_implement("cmll",128);
+    &alg_ctr32_implement("cmll",256);
+}
+}}}
+
+if (!$::evp) {
+$code.=<<___;
+.global	Camellia_encrypt
+Camellia_encrypt=cmll_t4_encrypt
+.global	Camellia_decrypt
+Camellia_decrypt=cmll_t4_decrypt
+.global	Camellia_set_key
+.align	32
+Camellia_set_key:
+	andcc		%o2, 7, %g0		! double-check alignment
+	bnz,a,pn	%icc, 1f
+	mov		-1, %o0
+	brz,a,pn	%o0, 1f
+	mov		-1, %o0
+	brz,a,pn	%o2, 1f
+	mov		-1, %o0
+	andncc		%o1, 0x1c0, %g0
+	bnz,a,pn	%icc, 1f
+	mov		-2, %o0
+	cmp		%o1, 128
+	bl,a,pn		%icc, 1f
+	mov		-2, %o0
+	b		cmll_t4_set_key
+	nop
+1:	retl
+	nop
+.type	Camellia_set_key,#function
+.size	Camellia_set_key,.-Camellia_set_key
+___
+
+my ($inp,$out,$len,$key,$ivec,$enc)=map("%o$_",(0..5));
+
+$code.=<<___;
+.globl	Camellia_cbc_encrypt
+.align	32
+Camellia_cbc_encrypt:
+	ld		[$key + 272], %g1
+	nop
+	brz		$enc, .Lcbc_decrypt
+	cmp		%g1, 3
+
+	be,pt		%icc, cmll128_t4_cbc_encrypt
+	nop
+	ba		cmll256_t4_cbc_encrypt
+	nop
+
+.Lcbc_decrypt:
+	be,pt		%icc, cmll128_t4_cbc_decrypt
+	nop
+	ba		cmll256_t4_cbc_decrypt
+	nop
+.type	Camellia_cbc_encrypt,#function
+.size	Camellia_cbc_encrypt,.-Camellia_cbc_encrypt
+___
+}
+
+&emit_assembler();
+
+close STDOUT;