code:
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * arch/alpha/lib/strncpy.S
 * Contributed by Richard Henderson (rth@tamu.edu)
 *
 * Copy no more than COUNT bytes of the null-terminated string from
 * SRC to DST.  If SRC does not cover all of COUNT, the balance is
 * zeroed.
 *
 * Or, rather, if the kernel cared about that weird ANSI quirk.  This
 * version has cropped that bit o' nastiness as well as assuming that
 * __stxncpy is in range of a branch.
 */
#include <asm/export.h>
	.set noat
	.set noreorder

	.text

	.align 4
	.globl strncpy
	.ent strncpy
strncpy:
	.frame $30, 0, $26
	.prologue 0

	mov	$16, $0		# set return value now
	beq	$18, $zerolen
	unop
	bsr	$23, __stxncpy	# do the work of the copy

	unop
	bne	$18, $multiword	# do we have full words left?
	subq	$24, 1, $3	# nope
	subq	$27, 1, $4

	or	$3, $24, $3	# clear the bits between the last
	or	$4, $27, $4	# written byte and the last byte in COUNT
	andnot	$3, $4, $4
	zap	$1, $4, $1

	stq_u	$1, 0($16)
	ret

	.align	4
$multiword:
	subq	$27, 1, $2	# clear the final bits in the prev word
	or	$2, $27, $2
	zapnot	$1, $2, $1
	subq	$18, 1, $18

	stq_u	$1, 0($16)
	addq	$16, 8, $16
	unop
	beq	$18, 1f

	nop
	unop
	nop
	blbc	$18, 0f

	stq_u	$31, 0($16)	# zero one word
	subq	$18, 1, $18
	addq	$16, 8, $16
	beq	$18, 1f

0:	stq_u	$31, 0($16)	# zero two words
	subq	$18, 2, $18
	stq_u	$31, 8($16)
	addq	$16, 16, $16
	bne	$18, 0b

1:	ldq_u	$1, 0($16)	# clear the leading bits in the final word
	subq	$24, 1, $2
	or	$2, $24, $2

	zap	$1, $2, $1
	stq_u	$1, 0($16)
$zerolen:
	ret

	.end	strncpy
	EXPORT_SYMBOL(strncpy)


code:
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * arch/alpha/lib/strrchr.S
 * Contributed by Richard Henderson (rth@tamu.edu)
 *
 * Return the address of the last occurrence of a given character
 * within a null-terminated string, or null if it is not found.
 */
#include <asm/export.h>
#include <asm/regdef.h>

	.set noreorder
	.set noat

	.align 3
	.ent strrchr
	.globl strrchr
strrchr:
	.frame sp, 0, ra
	.prologue 0

	zapnot	a1, 1, a1	# e0    : zero extend our test character
	mov	zero, t6	# .. e1 : t6 is last match aligned addr
	sll	a1, 8, t5	# e0    : replicate our test character
	mov	zero, t8	# .. e1 : t8 is last match byte compare mask
	or	t5, a1, a1	# e0    :
	ldq_u   t0, 0(a0)	# .. e1 : load first quadword
	sll	a1, 16, t5	# e0    :
	andnot  a0, 7, v0	# .. e1 : align source addr
	or	t5, a1, a1	# e0    :
	lda	t4, -1		# .. e1 : build garbage mask
	sll	a1, 32, t5	# e0    :
	cmpbge  zero, t0, t1	# .. e1 : bits set iff byte == zero
	mskqh	t4, a0, t4	# e0    :
	or	t5, a1, a1	# .. e1 : character replication complete
	xor	t0, a1, t2	# e0    : make bytes == c zero
	cmpbge	zero, t4, t4	# .. e1 : bits set iff byte is garbage
	cmpbge  zero, t2, t3	# e0    : bits set iff byte == c
	andnot	t1, t4, t1	# .. e1 : clear garbage from null test
	andnot	t3, t4, t3	# e0    : clear garbage from char test
	bne	t1, $eos	# .. e1 : did we already hit the terminator?

	/* Character search main loop */
$loop:
	ldq	t0, 8(v0)	# e0    : load next quadword
	cmovne	t3, v0, t6	# .. e1 : save previous comparisons match
	cmovne	t3, t3, t8	# e0    :
	addq	v0, 8, v0	# .. e1 :
	xor	t0, a1, t2	# e0    :
	cmpbge	zero, t0, t1	# .. e1 : bits set iff byte == zero
	cmpbge	zero, t2, t3	# e0    : bits set iff byte == c
	beq	t1, $loop	# .. e1 : if we havnt seen a null, loop

	/* Mask out character matches after terminator */
$eos:
	negq	t1, t4		# e0    : isolate first null byte match
	and	t1, t4, t4	# e1    :
	subq	t4, 1, t5	# e0    : build a mask of the bytes up to...
	or	t4, t5, t4	# e1    : ... and including the null

	and	t3, t4, t3	# e0    : mask out char matches after null
	cmovne	t3, t3, t8	# .. e1 : save it, if match found
	cmovne	t3, v0, t6	# e0    :

	/* Locate the address of the last matched character */

	/* Retain the early exit for the ev4 -- the ev5 mispredict penalty
	   is 5 cycles -- the same as just falling through.  */
	beq	t8, $retnull	# .. e1 :

	and	t8, 0xf0, t2	# e0    : binary search for the high bit set
	cmovne	t2, t2, t8	# .. e1 (zdb)
	cmovne	t2, 4, t2	# e0    :
	and	t8, 0xcc, t1	# .. e1 :
	cmovne	t1, t1, t8	# e0    :
	cmovne	t1, 2, t1	# .. e1 :
	and	t8, 0xaa, t0	# e0    :
	cmovne	t0, 1, t0	# .. e1 (zdb)
	addq	t2, t1, t1	# e0    :
	addq	t6, t0, v0	# .. e1 : add our aligned base ptr to the mix
	addq	v0, t1, v0	# e0    :
	ret			# .. e1 :

$retnull:
	mov	zero, v0	# e0    :
	ret			# .. e1 :

	.end strrchr
	EXPORT_SYMBOL(strrchr)

repo_name: angery/linux


code:
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * arch/alpha/lib/stxcpy.S
 * Contributed by Richard Henderson (rth@tamu.edu)
 *
 * Copy a null-terminated string from SRC to DST.
 *
 * This is an internal routine used by strcpy, stpcpy, and strcat.
 * As such, it uses special linkage conventions to make implementation
 * of these public functions more efficient.
 *
 * On input:
 *	t9 = return address
 *	a0 = DST
 *	a1 = SRC
 *
 * On output:
 *	t12 = bitmask (with one bit set) indicating the last byte written
 *	a0  = unaligned address of the last *word* written
 *
 * Furthermore, v0, a3-a5, t11, and t12 are untouched.
 */

#include <asm/regdef.h>

	.set noat
	.set noreorder

	.text

/* There is a problem with either gdb (as of 4.16) or gas (as of 2.7) that
   doesn't like putting the entry point for a procedure somewhere in the
   middle of the procedure descriptor.  Work around this by putting the
   aligned copy in its own procedure descriptor */

	.ent stxcpy_aligned
	.align 3
stxcpy_aligned:
	.frame sp, 0, t9
	.prologue 0

	/* On entry to this basic block:
	   t0 == the first destination word for masking back in
	   t1 == the first source word.  */

	/* Create the 1st output word and detect 0's in the 1st input word.  */
	lda	t2, -1		# e1    : build a mask against false zero
	mskqh	t2, a1, t2	# e0    :   detection in the src word
	mskqh	t1, a1, t3	# e0    :
	ornot	t1, t2, t2	# .. e1 :
	mskql	t0, a1, t0	# e0    : assemble the first output word
	cmpbge	zero, t2, t8	# .. e1 : bits set iff null found
	or	t0, t3, t1	# e0    :
	bne	t8, $a_eos	# .. e1 :

	/* On entry to this basic block:
	   t0 == the first destination word for masking back in
	   t1 == a source word not containing a null.  */

$a_loop:
	stq_u	t1, 0(a0)	# e0    :
	addq	a0, 8, a0	# .. e1 :
	ldq_u	t1, 0(a1)	# e0    :
	addq	a1, 8, a1	# .. e1 :
	cmpbge	zero, t1, t8	# e0 (stall)
	beq	t8, $a_loop	# .. e1 (zdb)

	/* Take care of the final (partial) word store.
	   On entry to this basic block we have:
	   t1 == the source word containing the null
	   t8 == the cmpbge mask that found it.  */
$a_eos:
	negq	t8, t6		# e0    : find low bit set
	and	t8, t6, t12	# e1 (stall)

	/* For the sake of the cache, don't read a destination word
	   if we're not going to need it.  */
	and	t12, 0x80, t6	# e0    :
	bne	t6, 1f		# .. e1 (zdb)

	/* We're doing a partial word store and so need to combine
	   our source and original destination words.  */
	ldq_u	t0, 0(a0)	# e0    :
	subq	t12, 1, t6	# .. e1 :
	zapnot	t1, t6, t1	# e0    : clear src bytes >= null
	or	t12, t6, t8	# .. e1 :
	zap	t0, t8, t0	# e0    : clear dst bytes <= null
	or	t0, t1, t1	# e1    :

1:	stq_u	t1, 0(a0)	# e0    :
	ret	(t9)		# .. e1 :

	.end stxcpy_aligned

	.align 3
	.ent __stxcpy
	.globl __stxcpy
__stxcpy:
	.frame sp, 0, t9
	.prologue 0

	/* Are source and destination co-aligned?  */
	xor	a0, a1, t0	# e0    :
	unop			#       :
	and	t0, 7, t0	# e0    :
	bne	t0, $unaligned	# .. e1 :

	/* We are co-aligned; take care of a partial first word.  */
	ldq_u	t1, 0(a1)	# e0    : load first src word
	and	a0, 7, t0	# .. e1 : take care not to load a word ...
	addq	a1, 8, a1		# e0    :
	beq	t0, stxcpy_aligned	# .. e1 : ... if we wont need it
	ldq_u	t0, 0(a0)	# e0    :
	br	stxcpy_aligned	# .. e1 :

/* The source and destination are not co-aligned.  Align the destination
   and cope.  We have to be very careful about not reading too much and
   causing a SEGV.  */

	.align 3
$u_head:
	/* We know just enough now to be able to assemble the first
	   full source word.  We can still find a zero at the end of it
	   that prevents us from outputting the whole thing.

	   On entry to this basic block:
	   t0 == the first dest word, for masking back in, if needed else 0
	   t1 == the low bits of the first source word
	   t6 == bytemask that is -1 in dest word bytes */

	ldq_u	t2, 8(a1)	# e0    :
	addq	a1, 8, a1	# .. e1 :

	extql	t1, a1, t1	# e0    :
	extqh	t2, a1, t4	# e0    :
	mskql	t0, a0, t0	# e0    :
	or	t1, t4, t1	# .. e1 :
	mskqh	t1, a0, t1	# e0    :
	or	t0, t1, t1	# e1    :

	or	t1, t6, t6	# e0    :
	cmpbge	zero, t6, t8	# .. e1 :
	lda	t6, -1		# e0    : for masking just below
	bne	t8, $u_final	# .. e1 :

	mskql	t6, a1, t6		# e0    : mask out the bits we have
	or	t6, t2, t2		# e1    :   already extracted before
	cmpbge	zero, t2, t8		# e0    :   testing eos
	bne	t8, $u_late_head_exit	# .. e1 (zdb)

	/* Finally, we've got all the stupid leading edge cases taken care
	   of and we can set up to enter the main loop.  */

	stq_u	t1, 0(a0)	# e0    : store first output word
	addq	a0, 8, a0	# .. e1 :
	extql	t2, a1, t0	# e0    : position ho-bits of lo word
	ldq_u	t2, 8(a1)	# .. e1 : read next high-order source word
	addq	a1, 8, a1	# e0    :
	cmpbge	zero, t2, t8	# .. e1 :
	nop			# e0    :
	bne	t8, $u_eos	# .. e1 :

	/* Unaligned copy main loop.  In order to avoid reading too much,
	   the loop is structured to detect zeros in aligned source words.
	   This has, unfortunately, effectively pulled half of a loop
	   iteration out into the head and half into the tail, but it does
	   prevent nastiness from accumulating in the very thing we want
	   to run as fast as possible.

	   On entry to this basic block:
	   t0 == the shifted high-order bits from the previous source word
	   t2 == the unshifted current source word

	   We further know that t2 does not contain a null terminator.  */

	.align 3
$u_loop:
	extqh	t2, a1, t1	# e0    : extract high bits for current word
	addq	a1, 8, a1	# .. e1 :
	extql	t2, a1, t3	# e0    : extract low bits for next time
	addq	a0, 8, a0	# .. e1 :
	or	t0, t1, t1	# e0    : current dst word now complete
	ldq_u	t2, 0(a1)	# .. e1 : load high word for next time
	stq_u	t1, -8(a0)	# e0    : save the current word
	mov	t3, t0		# .. e1 :
	cmpbge	zero, t2, t8	# e0    : test new word for eos
	beq	t8, $u_loop	# .. e1 :

	/* We've found a zero somewhere in the source word we just read.
	   If it resides in the lower half, we have one (probably partial)
	   word to write out, and if it resides in the upper half, we
	   have one full and one partial word left to write out.

	   On entry to this basic block:
	   t0 == the shifted high-order bits from the previous source word
	   t2 == the unshifted current source word.  */
$u_eos:
	extqh	t2, a1, t1	# e0    :
	or	t0, t1, t1	# e1    : first (partial) source word complete

	cmpbge	zero, t1, t8	# e0    : is the null in this first bit?
	bne	t8, $u_final	# .. e1 (zdb)

$u_late_head_exit:
	stq_u	t1, 0(a0)	# e0    : the null was in the high-order bits
	addq	a0, 8, a0	# .. e1 :
	extql	t2, a1, t1	# e0    :
	cmpbge	zero, t1, t8	# .. e1 :

	/* Take care of a final (probably partial) result word.
	   On entry to this basic block:
	   t1 == assembled source word
	   t8 == cmpbge mask that found the null.  */
$u_final:
	negq	t8, t6		# e0    : isolate low bit set
	and	t6, t8, t12	# e1    :

	and	t12, 0x80, t6	# e0    : avoid dest word load if we can
	bne	t6, 1f		# .. e1 (zdb)

	ldq_u	t0, 0(a0)	# e0    :
	subq	t12, 1, t6	# .. e1 :
	or	t6, t12, t8	# e0    :
	zapnot	t1, t6, t1	# .. e1 : kill source bytes >= null
	zap	t0, t8, t0	# e0    : kill dest bytes <= null
	or	t0, t1, t1	# e1    :

1:	stq_u	t1, 0(a0)	# e0    :
	ret	(t9)		# .. e1 :

	/* Unaligned copy entry point.  */
	.align 3
$unaligned:

	ldq_u	t1, 0(a1)	# e0    : load first source word

	and	a0, 7, t4	# .. e1 : find dest misalignment
	and	a1, 7, t5	# e0    : find src misalignment

	/* Conditionally load the first destination word and a bytemask
	   with 0xff indicating that the destination byte is sacrosanct.  */

	mov	zero, t0	# .. e1 :
	mov	zero, t6	# e0    :
	beq	t4, 1f		# .. e1 :
	ldq_u	t0, 0(a0)	# e0    :
	lda	t6, -1		# .. e1 :
	mskql	t6, a0, t6	# e0    :
1:
	subq	a1, t4, a1	# .. e1 : sub dest misalignment from src addr

	/* If source misalignment is larger than dest misalignment, we need
	   extra startup checks to avoid SEGV.  */

	cmplt	t4, t5, t12	# e0    :
	beq	t12, $u_head	# .. e1 (zdb)

	lda	t2, -1		# e1    : mask out leading garbage in source
	mskqh	t2, t5, t2	# e0    :
	nop			# e0    :
	ornot	t1, t2, t3	# .. e1 :
	cmpbge	zero, t3, t8	# e0    : is there a zero?
	beq	t8, $u_head	# .. e1 (zdb)

	/* At this point we've found a zero in the first partial word of
	   the source.  We need to isolate the valid source data and mask
	   it into the original destination data.  (Incidentally, we know
	   that we'll need at least one byte of that original dest word.) */

	ldq_u	t0, 0(a0)	# e0    :

	negq	t8, t6		# .. e1 : build bitmask of bytes <= zero
	and	t6, t8, t12	# e0    :
	and	a1, 7, t5	# .. e1 :
	subq	t12, 1, t6	# e0    :
	or	t6, t12, t8	# e1    :
	srl	t12, t5, t12	# e0    : adjust final null return value

	zapnot	t2, t8, t2	# .. e1 : prepare source word; mirror changes
	and	t1, t2, t1	# e1    : to source validity mask
	extql	t2, a1, t2	# .. e0 :
	extql	t1, a1, t1	# e0    :

	andnot	t0, t2, t0	# .. e1 : zero place for source to reside
	or	t0, t1, t1	# e1    : and put it there
	stq_u	t1, 0(a0)	# .. e0 :
	ret	(t9)		# e1    :

	.end __stxcpy


code:
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * arch/alpha/lib/stxncpy.S
 * Contributed by Richard Henderson (rth@tamu.edu)
 *
 * Copy no more than COUNT bytes of the null-terminated string from
 * SRC to DST.
 *
 * This is an internal routine used by strncpy, stpncpy, and strncat.
 * As such, it uses special linkage conventions to make implementation
 * of these public functions more efficient.
 *
 * On input:
 *	t9 = return address
 *	a0 = DST
 *	a1 = SRC
 *	a2 = COUNT
 *
 * Furthermore, COUNT may not be zero.
 *
 * On output:
 *	t0  = last word written
 *	t10 = bitmask (with one bit set) indicating the byte position of
 *	      the end of the range specified by COUNT
 *	t12 = bitmask (with one bit set) indicating the last byte written
 *	a0  = unaligned address of the last *word* written
 *	a2  = the number of full words left in COUNT
 *
 * Furthermore, v0, a3-a5, t11, and $at are untouched.
 */

#include <asm/regdef.h>

	.set noat
	.set noreorder

	.text

/* There is a problem with either gdb (as of 4.16) or gas (as of 2.7) that
   doesn't like putting the entry point for a procedure somewhere in the
   middle of the procedure descriptor.  Work around this by putting the
   aligned copy in its own procedure descriptor */

	.ent stxncpy_aligned
	.align 3
stxncpy_aligned:
	.frame sp, 0, t9, 0
	.prologue 0

	/* On entry to this basic block:
	   t0 == the first destination word for masking back in
	   t1 == the first source word.  */

	/* Create the 1st output word and detect 0's in the 1st input word.  */
	lda	t2, -1		# e1    : build a mask against false zero
	mskqh	t2, a1, t2	# e0    :   detection in the src word
	mskqh	t1, a1, t3	# e0    :
	ornot	t1, t2, t2	# .. e1 :
	mskql	t0, a1, t0	# e0    : assemble the first output word
	cmpbge	zero, t2, t8	# .. e1 : bits set iff null found
	or	t0, t3, t0	# e0    :
	beq	a2, $a_eoc	# .. e1 :
	bne	t8, $a_eos	# .. e1 :

	/* On entry to this basic block:
	   t0 == a source word not containing a null.  */

$a_loop:
	stq_u	t0, 0(a0)	# e0    :
	addq	a0, 8, a0	# .. e1 :
	ldq_u	t0, 0(a1)	# e0    :
	addq	a1, 8, a1	# .. e1 :
	subq	a2, 1, a2	# e0    :
	cmpbge	zero, t0, t8	# .. e1 (stall)
	beq	a2, $a_eoc      # e1    :
	beq	t8, $a_loop	# e1    :

	/* Take care of the final (partial) word store.  At this point
	   the end-of-count bit is set in t8 iff it applies.

	   On entry to this basic block we have:
	   t0 == the source word containing the null
	   t8 == the cmpbge mask that found it.  */

$a_eos:
	negq	t8, t12		# e0    : find low bit set
	and	t8, t12, t12	# e1 (stall)

	/* For the sake of the cache, don't read a destination word
	   if we're not going to need it.  */
	and	t12, 0x80, t6	# e0    :
	bne	t6, 1f		# .. e1 (zdb)

	/* We're doing a partial word store and so need to combine
	   our source and original destination words.  */
	ldq_u	t1, 0(a0)	# e0    :
	subq	t12, 1, t6	# .. e1 :
	or	t12, t6, t8	# e0    :
	unop			#
	zapnot	t0, t8, t0	# e0    : clear src bytes > null
	zap	t1, t8, t1	# .. e1 : clear dst bytes <= null
	or	t0, t1, t0	# e1    :

1:	stq_u	t0, 0(a0)	# e0    :
	ret	(t9)		# e1    :

	/* Add the end-of-count bit to the eos detection bitmask.  */
$a_eoc:
	or	t10, t8, t8
	br	$a_eos

	.end stxncpy_aligned

	.align 3
	.ent __stxncpy
	.globl __stxncpy
__stxncpy:
	.frame sp, 0, t9, 0
	.prologue 0

	/* Are source and destination co-aligned?  */
	xor	a0, a1, t1	# e0    :
	and	a0, 7, t0	# .. e1 : find dest misalignment
	and	t1, 7, t1	# e0    :
	addq	a2, t0, a2	# .. e1 : bias count by dest misalignment
	subq	a2, 1, a2	# e0    :
	and	a2, 7, t2	# e1    :
	srl	a2, 3, a2	# e0    : a2 = loop counter = (count - 1)/8
	addq	zero, 1, t10	# .. e1 :
	sll	t10, t2, t10	# e0    : t10 = bitmask of last count byte
	bne	t1, $unaligned	# .. e1 :

	/* We are co-aligned; take care of a partial first word.  */

	ldq_u	t1, 0(a1)	# e0    : load first src word
	addq	a1, 8, a1	# .. e1 :

	beq	t0, stxncpy_aligned     # avoid loading dest word if not needed
	ldq_u	t0, 0(a0)	# e0    :
	br	stxncpy_aligned	# .. e1 :

/* The source and destination are not co-aligned.  Align the destination
   and cope.  We have to be very careful about not reading too much and
   causing a SEGV.  */

	.align 3
$u_head:
	/* We know just enough now to be able to assemble the first
	   full source word.  We can still find a zero at the end of it
	   that prevents us from outputting the whole thing.

	   On entry to this basic block:
	   t0 == the first dest word, unmasked
	   t1 == the shifted low bits of the first source word
	   t6 == bytemask that is -1 in dest word bytes */

	ldq_u	t2, 8(a1)	# e0    : load second src word
	addq	a1, 8, a1	# .. e1 :
	mskql	t0, a0, t0	# e0    : mask trailing garbage in dst
	extqh	t2, a1, t4	# e0    :
	or	t1, t4, t1	# e1    : first aligned src word complete
	mskqh	t1, a0, t1	# e0    : mask leading garbage in src
	or	t0, t1, t0	# e0    : first output word complete
	or	t0, t6, t6	# e1    : mask original data for zero test
	cmpbge	zero, t6, t8	# e0    :
	beq	a2, $u_eocfin	# .. e1 :
	lda	t6, -1		# e0    :
	bne	t8, $u_final	# .. e1 :

	mskql	t6, a1, t6	# e0    : mask out bits already seen
	nop			# .. e1 :
	stq_u	t0, 0(a0)	# e0    : store first output word
	or      t6, t2, t2	# .. e1 :
	cmpbge	zero, t2, t8	# e0    : find nulls in second partial
	addq	a0, 8, a0	# .. e1 :
	subq	a2, 1, a2	# e0    :
	bne	t8, $u_late_head_exit	# .. e1 :

	/* Finally, we've got all the stupid leading edge cases taken care
	   of and we can set up to enter the main loop.  */

	extql	t2, a1, t1	# e0    : position hi-bits of lo word
	beq	a2, $u_eoc	# .. e1 :
	ldq_u	t2, 8(a1)	# e0    : read next high-order source word
	addq	a1, 8, a1	# .. e1 :
	extqh	t2, a1, t0	# e0    : position lo-bits of hi word (stall)
	cmpbge	zero, t2, t8	# .. e1 :
	nop			# e0    :
	bne	t8, $u_eos	# .. e1 :

	/* Unaligned copy main loop.  In order to avoid reading too much,
	   the loop is structured to detect zeros in aligned source words.
	   This has, unfortunately, effectively pulled half of a loop
	   iteration out into the head and half into the tail, but it does
	   prevent nastiness from accumulating in the very thing we want
	   to run as fast as possible.

	   On entry to this basic block:
	   t0 == the shifted low-order bits from the current source word
	   t1 == the shifted high-order bits from the previous source word
	   t2 == the unshifted current source word

	   We further know that t2 does not contain a null terminator.  */

	.align 3
$u_loop:
	or	t0, t1, t0	# e0    : current dst word now complete
	subq	a2, 1, a2	# .. e1 : decrement word count
	stq_u	t0, 0(a0)	# e0    : save the current word
	addq	a0, 8, a0	# .. e1 :
	extql	t2, a1, t1	# e0    : extract high bits for next time
	beq	a2, $u_eoc	# .. e1 :
	ldq_u	t2, 8(a1)	# e0    : load high word for next time
	addq	a1, 8, a1	# .. e1 :
	nop			# e0    :
	cmpbge	zero, t2, t8	# e1    : test new word for eos (stall)
	extqh	t2, a1, t0	# e0    : extract low bits for current word
	beq	t8, $u_loop	# .. e1 :

	/* We've found a zero somewhere in the source word we just read.
	   If it resides in the lower half, we have one (probably partial)
	   word to write out, and if it resides in the upper half, we
	   have one full and one partial word left to write out.

	   On entry to this basic block:
	   t0 == the shifted low-order bits from the current source word
	   t1 == the shifted high-order bits from the previous source word
	   t2 == the unshifted current source word.  */
$u_eos:
	or	t0, t1, t0	# e0    : first (partial) source word complete
	nop			# .. e1 :
	cmpbge	zero, t0, t8	# e0    : is the null in this first bit?
	bne	t8, $u_final	# .. e1 (zdb)

	stq_u	t0, 0(a0)	# e0    : the null was in the high-order bits
	addq	a0, 8, a0	# .. e1 :
	subq	a2, 1, a2	# e1    :

$u_late_head_exit:
	extql	t2, a1, t0	# .. e0 :
	cmpbge	zero, t0, t8	# e0    :
	or	t8, t10, t6	# e1    :
	cmoveq	a2, t6, t8	# e0    :
	nop			# .. e1 :

	/* Take care of a final (probably partial) result word.
	   On entry to this basic block:
	   t0 == assembled source word
	   t8 == cmpbge mask that found the null.  */
$u_final:
	negq	t8, t6		# e0    : isolate low bit set
	and	t6, t8, t12	# e1    :

	and	t12, 0x80, t6	# e0    : avoid dest word load if we can
	bne	t6, 1f		# .. e1 (zdb)

	ldq_u	t1, 0(a0)	# e0    :
	subq	t12, 1, t6	# .. e1 :
	or	t6, t12, t8	# e0    :
	zapnot	t0, t8, t0	# .. e1 : kill source bytes > null
	zap	t1, t8, t1	# e0    : kill dest bytes <= null
	or	t0, t1, t0	# e1    :

1:	stq_u	t0, 0(a0)	# e0    :
	ret	(t9)		# .. e1 :

	/* Got to end-of-count before end of string.
	   On entry to this basic block:
	   t1 == the shifted high-order bits from the previous source word  */
$u_eoc:
	and	a1, 7, t6	# e1    :
	sll	t10, t6, t6	# e0    :
	and	t6, 0xff, t6	# e0    :
	bne	t6, 1f		# .. e1 :

	ldq_u	t2, 8(a1)	# e0    : load final src word
	nop			# .. e1 :
	extqh	t2, a1, t0	# e0    : extract low bits for last word
	or	t1, t0, t1	# e1    :

1:	cmpbge	zero, t1, t8
	mov	t1, t0

$u_eocfin:			# end-of-count, final word
	or	t10, t8, t8
	br	$u_final

	/* Unaligned copy entry point.  */
	.align 3
$unaligned:

	ldq_u	t1, 0(a1)	# e0    : load first source word

	and	a0, 7, t4	# .. e1 : find dest misalignment
	and	a1, 7, t5	# e0    : find src misalignment

	/* Conditionally load the first destination word and a bytemask
	   with 0xff indicating that the destination byte is sacrosanct.  */

	mov	zero, t0	# .. e1 :
	mov	zero, t6	# e0    :
	beq	t4, 1f		# .. e1 :
	ldq_u	t0, 0(a0)	# e0    :
	lda	t6, -1		# .. e1 :
	mskql	t6, a0, t6	# e0    :
	subq	a1, t4, a1	# .. e1 : sub dest misalignment from src addr

	/* If source misalignment is larger than dest misalignment, we need
	   extra startup checks to avoid SEGV.  */

1:	cmplt	t4, t5, t12	# e1    :
	extql	t1, a1, t1	# .. e0 : shift src into place
	lda	t2, -1		# e0    : for creating masks later
	beq	t12, $u_head	# .. e1 :

	extql	t2, a1, t2	# e0    :
	cmpbge	zero, t1, t8	# .. e1 : is there a zero?
	andnot	t2, t6, t2	# e0    : dest mask for a single word copy
	or	t8, t10, t5	# .. e1 : test for end-of-count too
	cmpbge	zero, t2, t3	# e0    :
	cmoveq	a2, t5, t8	# .. e1 :
	andnot	t8, t3, t8	# e0    :
	beq	t8, $u_head	# .. e1 (zdb)

	/* At this point we've found a zero in the first partial word of
	   the source.  We need to isolate the valid source data and mask
	   it into the original destination data.  (Incidentally, we know
	   that we'll need at least one byte of that original dest word.) */

	ldq_u	t0, 0(a0)	# e0    :
	negq	t8, t6		# .. e1 : build bitmask of bytes <= zero
	mskqh	t1, t4, t1	# e0    :
	and	t6, t8, t12	# .. e1 :
	subq	t12, 1, t6	# e0    :
	or	t6, t12, t8	# e1    :

	zapnot	t2, t8, t2	# e0    : prepare source word; mirror changes
	zapnot	t1, t8, t1	# .. e1 : to source validity mask

	andnot	t0, t2, t0	# e0    : zero place for source to reside
	or	t0, t1, t0	# e1    : and put it there
	stq_u	t0, 0(a0)	# e0    :
	ret	(t9)		# .. e1 :

	.end __stxncpy


code:
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (C) 1993, 2000 Linus Torvalds
 *
 * Delay routines, using a pre-computed "loops_per_jiffy" value.
 */

#include <linux/module.h>
#include <linux/sched.h> /* for udelay's use of smp_processor_id */
#include <asm/param.h>
#include <asm/smp.h>
#include <linux/delay.h>

/*
 * Use only for very small delays (< 1 msec).
 *
 * The active part of our cycle counter is only 32-bits wide, and
 * we're treating the difference between two marks as signed.  On
 * a 1GHz box, that's about 2 seconds.
 */

void
__delay(int loops)
{
	int tmp;
	__asm__ __volatile__(
		"	rpcc %0\n"
		"	addl %1,%0,%1\n"
		"1:	rpcc %0\n"
		"	subl %1,%0,%0\n"
		"	bgt %0,1b"
		: "=&r" (tmp), "=r" (loops) : "1"(loops));
}
EXPORT_SYMBOL(__delay);

#ifdef CONFIG_SMP
#define LPJ	 cpu_data[smp_processor_id()].loops_per_jiffy
#else
#define LPJ	 loops_per_jiffy
#endif

void
udelay(unsigned long usecs)
{
	usecs *= (((unsigned long)HZ << 32) / 1000000) * LPJ;
	__delay((long)usecs >> 32);
}
EXPORT_SYMBOL(udelay);

void
ndelay(unsigned long nsecs)
{
	nsecs *= (((unsigned long)HZ << 32) / 1000000000) * LPJ;
	__delay((long)nsecs >> 32);
}
EXPORT_SYMBOL(ndelay);


code:
 # Alpha 21064 __udiv_qrnnd
 # Copyright (C) 1992, 1994, 1995, 2000 Free Software Foundation, Inc.

 # This file is part of GCC.

 # The GNU MP Library 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.

 # In addition to the permissions in the GNU General Public License, the
 # Free Software Foundation gives you unlimited permission to link the
 # compiled version of this file with other programs, and to distribute
 # those programs without any restriction coming from the use of this
 # file.  (The General Public License restrictions do apply in other
 # respects; for example, they cover modification of the file, and
 # distribution when not linked into another program.)

 # This file 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 Library General Public
 # License for more details.

 # You should have received a copy of the GNU General Public License
 # along with GCC; see the file COPYING.  If not, write to the
 # Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 # MA 02111-1307, USA.
#include <asm/export.h>

        .set noreorder
        .set noat

	.text

	.globl __udiv_qrnnd
	.ent __udiv_qrnnd
__udiv_qrnnd:
	.frame $30,0,$26,0
	.prologue 0

#define cnt	$2
#define tmp	$3
#define rem_ptr	$16
#define n1	$17
#define n0	$18
#define d	$19
#define qb	$20
#define AT	$at

	ldiq	cnt,16
	blt	d,$largedivisor

$loop1:	cmplt	n0,0,tmp
	addq	n1,n1,n1
	bis	n1,tmp,n1
	addq	n0,n0,n0
	cmpule	d,n1,qb
	subq	n1,d,tmp
	cmovne	qb,tmp,n1
	bis	n0,qb,n0
	cmplt	n0,0,tmp
	addq	n1,n1,n1
	bis	n1,tmp,n1
	addq	n0,n0,n0
	cmpule	d,n1,qb
	subq	n1,d,tmp
	cmovne	qb,tmp,n1
	bis	n0,qb,n0
	cmplt	n0,0,tmp
	addq	n1,n1,n1
	bis	n1,tmp,n1
	addq	n0,n0,n0
	cmpule	d,n1,qb
	subq	n1,d,tmp
	cmovne	qb,tmp,n1
	bis	n0,qb,n0
	cmplt	n0,0,tmp
	addq	n1,n1,n1
	bis	n1,tmp,n1
	addq	n0,n0,n0
	cmpule	d,n1,qb
	subq	n1,d,tmp
	cmovne	qb,tmp,n1
	bis	n0,qb,n0
	subq	cnt,1,cnt
	bgt	cnt,$loop1
	stq	n1,0(rem_ptr)
	bis	$31,n0,$0
	ret	$31,($26),1

$largedivisor:
	and	n0,1,$4

	srl	n0,1,n0
	sll	n1,63,tmp
	or	tmp,n0,n0
	srl	n1,1,n1

	and	d,1,$6
	srl	d,1,$5
	addq	$5,$6,$5

$loop2:	cmplt	n0,0,tmp
	addq	n1,n1,n1
	bis	n1,tmp,n1
	addq	n0,n0,n0
	cmpule	$5,n1,qb
	subq	n1,$5,tmp
	cmovne	qb,tmp,n1
	bis	n0,qb,n0
	cmplt	n0,0,tmp
	addq	n1,n1,n1
	bis	n1,tmp,n1
	addq	n0,n0,n0
	cmpule	$5,n1,qb
	subq	n1,$5,tmp
	cmovne	qb,tmp,n1
	bis	n0,qb,n0
	cmplt	n0,0,tmp
	addq	n1,n1,n1
	bis	n1,tmp,n1
	addq	n0,n0,n0
	cmpule	$5,n1,qb
	subq	n1,$5,tmp
	cmovne	qb,tmp,n1
	bis	n0,qb,n0
	cmplt	n0,0,tmp
	addq	n1,n1,n1
	bis	n1,tmp,n1
	addq	n0,n0,n0
	cmpule	$5,n1,qb
	subq	n1,$5,tmp
	cmovne	qb,tmp,n1
	bis	n0,qb,n0
	subq	cnt,1,cnt
	bgt	cnt,$loop2

	addq	n1,n1,n1
	addq	$4,n1,n1
	bne	$6,$Odd
	stq	n1,0(rem_ptr)
	bis	$31,n0,$0
	ret	$31,($26),1

$Odd:
	/* q' in n0. r' in n1 */
	addq	n1,n0,n1

	cmpult	n1,n0,tmp	# tmp := carry from addq
	subq	n1,d,AT
	addq	n0,tmp,n0
	cmovne	tmp,AT,n1

	cmpult	n1,d,tmp
	addq	n0,1,AT
	cmoveq	tmp,AT,n0
	subq	n1,d,AT
	cmoveq	tmp,AT,n1

	stq	n1,0(rem_ptr)
	bis	$31,n0,$0
	ret	$31,($26),1

	.end	__udiv_qrnnd
EXPORT_SYMBOL(__udiv_qrnnd)


code:
# SPDX-License-Identifier: GPL-2.0-only
#
# Makefile for the FPU instruction emulation.
#

ccflags-y := -w

obj-$(CONFIG_MATHEMU) += math-emu.o

math-emu-objs := math.o

path: arch/alpha/math-emu/Makefile


code:
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <asm/ptrace.h>

#include <linux/uaccess.h>

#include "sfp-util.h"
#include <math-emu/soft-fp.h>
#include <math-emu/single.h>
#include <math-emu/double.h>

#define	OPC_PAL		0x00
#define OPC_INTA	0x10
#define OPC_INTL	0x11
#define OPC_INTS	0x12
#define OPC_INTM	0x13
#define OPC_FLTC	0x14
#define OPC_FLTV	0x15
#define OPC_FLTI	0x16
#define OPC_FLTL	0x17
#define OPC_MISC	0x18
#define	OPC_JSR		0x1a

#define FOP_SRC_S	0
#define FOP_SRC_T	2
#define FOP_SRC_Q	3

#define FOP_FNC_ADDx	0
#define FOP_FNC_CVTQL	0
#define FOP_FNC_SUBx	1
#define FOP_FNC_MULx	2
#define FOP_FNC_DIVx	3
#define FOP_FNC_CMPxUN	4
#define FOP_FNC_CMPxEQ	5
#define FOP_FNC_CMPxLT	6
#define FOP_FNC_CMPxLE	7
#define FOP_FNC_SQRTx	11
#define FOP_FNC_CVTxS	12
#define FOP_FNC_CVTxT	14
#define FOP_FNC_CVTxQ	15

#define MISC_TRAPB	0x0000
#define MISC_EXCB	0x0400

extern unsigned long alpha_read_fp_reg (unsigned long reg);
extern void alpha_write_fp_reg (unsigned long reg, unsigned long val);
extern unsigned long alpha_read_fp_reg_s (unsigned long reg);
extern void alpha_write_fp_reg_s (unsigned long reg, unsigned long val);

#ifdef MODULE

MODULE_DESCRIPTION("FP Software completion module");
MODULE_LICENSE("GPL v2");

extern long (*alpha_fp_emul_imprecise)(struct pt_regs *, unsigned long);
extern long (*alpha_fp_emul) (unsigned long pc);

static long (*save_emul_imprecise)(struct pt_regs *, unsigned long);
static long (*save_emul) (unsigned long pc);

long do_alpha_fp_emul_imprecise(struct pt_regs *, unsigned long);
long do_alpha_fp_emul(unsigned long);

static int alpha_fp_emul_init_module(void)
{
	save_emul_imprecise = alpha_fp_emul_imprecise;
	save_emul = alpha_fp_emul;
	alpha_fp_emul_imprecise = do_alpha_fp_emul_imprecise;
	alpha_fp_emul = do_alpha_fp_emul;
	return 0;
}
module_init(alpha_fp_emul_init_module);

static void alpha_fp_emul_cleanup_module(void)
{
	alpha_fp_emul_imprecise = save_emul_imprecise;
	alpha_fp_emul = save_emul;
}
module_exit(alpha_fp_emul_cleanup_module);

#undef  alpha_fp_emul_imprecise
#define alpha_fp_emul_imprecise		do_alpha_fp_emul_imprecise
#undef  alpha_fp_emul
#define alpha_fp_emul			do_alpha_fp_emul

#endif /* MODULE */

/*
 * Emulate the floating point instruction at address PC.  Returns -1 if the
 * instruction to be emulated is illegal (such as with the opDEC trap), else
 * the SI_CODE for a SIGFPE signal, else 0 if everything's ok.
 *
 * Notice that the kernel does not and cannot use FP regs.  This is good
 * because it means that instead of saving/restoring all fp regs, we simply
 * stick the result of the operation into the appropriate register.
 */
long
alpha_fp_emul (unsigned long pc)
{
	FP_DECL_EX;
	FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
	FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);

	unsigned long fa, fb, fc, func, mode, src;
	unsigned long res, va, vb, vc, swcr, fpcr;
	__u32 insn;
	long si_code;

	get_user(insn, (__u32 __user *)pc);
	fc     = (insn >>  0) & 0x1f;	/* destination register */
	fb     = (insn >> 16) & 0x1f;
	fa     = (insn >> 21) & 0x1f;
	func   = (insn >>  5) & 0xf;
	src    = (insn >>  9) & 0x3;
	mode   = (insn >> 11) & 0x3;

	fpcr = rdfpcr();
	swcr = swcr_update_status(current_thread_info()->ieee_state, fpcr);

	if (mode == 3) {
		/* Dynamic -- get rounding mode from fpcr.  */
		mode = (fpcr >> FPCR_DYN_SHIFT) & 3;
	}

	switch (src) {
	case FOP_SRC_S:
		va = alpha_read_fp_reg_s(fa);
		vb = alpha_read_fp_reg_s(fb);

		FP_UNPACK_SP(SA, &va);
		FP_UNPACK_SP(SB, &vb);

		switch (func) {
		case FOP_FNC_SUBx:
			FP_SUB_S(SR, SA, SB);
			goto pack_s;

		case FOP_FNC_ADDx:
			FP_ADD_S(SR, SA, SB);
			goto pack_s;

		case FOP_FNC_MULx:
			FP_MUL_S(SR, SA, SB);
			goto pack_s;

		case FOP_FNC_DIVx:
			FP_DIV_S(SR, SA, SB);
			goto pack_s;

		case FOP_FNC_SQRTx:
			FP_SQRT_S(SR, SB);
			goto pack_s;
		}
		goto bad_insn;

	case FOP_SRC_T:
		va = alpha_read_fp_reg(fa);
		vb = alpha_read_fp_reg(fb);

		if ((func & ~3) == FOP_FNC_CMPxUN) {
			FP_UNPACK_RAW_DP(DA, &va);
			FP_UNPACK_RAW_DP(DB, &vb);
			if (!DA_e && !_FP_FRAC_ZEROP_1(DA)) {
				FP_SET_EXCEPTION(FP_EX_DENORM);
				if (FP_DENORM_ZERO)
					_FP_FRAC_SET_1(DA, _FP_ZEROFRAC_1);
			}
			if (!DB_e && !_FP_FRAC_ZEROP_1(DB)) {
				FP_SET_EXCEPTION(FP_EX_DENORM);
				if (FP_DENORM_ZERO)
					_FP_FRAC_SET_1(DB, _FP_ZEROFRAC_1);
			}
			FP_CMP_D(res, DA, DB, 3);
			vc = 0x4000000000000000UL;
			/* CMPTEQ, CMPTUN don't trap on QNaN,
			   while CMPTLT and CMPTLE do */
			if (res == 3
			    && ((func & 3) >= 2
				|| FP_ISSIGNAN_D(DA)
				|| FP_ISSIGNAN_D(DB))) {
				FP_SET_EXCEPTION(FP_EX_INVALID);
			}
			switch (func) {
			case FOP_FNC_CMPxUN: if (res != 3) vc = 0; break;
			case FOP_FNC_CMPxEQ: if (res) vc = 0; break;
			case FOP_FNC_CMPxLT: if (res != -1) vc = 0; break;
			case FOP_FNC_CMPxLE: if ((long)res > 0) vc = 0; break;
			}
			goto done_d;
		}

		FP_UNPACK_DP(DA, &va);
		FP_UNPACK_DP(DB, &vb);

		switch (func) {
		case FOP_FNC_SUBx:
			FP_SUB_D(DR, DA, DB);
			goto pack_d;

		case FOP_FNC_ADDx:
			FP_ADD_D(DR, DA, DB);
			goto pack_d;

		case FOP_FNC_MULx:
			FP_MUL_D(DR, DA, DB);
			goto pack_d;

		case FOP_FNC_DIVx:
			FP_DIV_D(DR, DA, DB);
			goto pack_d;

		case FOP_FNC_SQRTx:
			FP_SQRT_D(DR, DB);
			goto pack_d;

		case FOP_FNC_CVTxS:
			/* It is irritating that DEC encoded CVTST with
			   SRC == T_floating.  It is also interesting that
			   the bit used to tell the two apart is /U... */
			if (insn & 0x2000) {
				FP_CONV(S,D,1,1,SR,DB);
				goto pack_s;
			} else {
				vb = alpha_read_fp_reg_s(fb);
				FP_UNPACK_SP(SB, &vb);
				DR_c = DB_c;
				DR_s = DB_s;
				DR_e = DB_e + (1024 - 128);
				DR_f = SB_f << (52 - 23);
				goto pack_d;
			}

		case FOP_FNC_CVTxQ:
			if (DB_c == FP_CLS_NAN
			    && (_FP_FRAC_HIGH_RAW_D(DB) & _FP_QNANBIT_D)) {
			  /* AAHB Table B-2 says QNaN should not trigger INV */
				vc = 0;
			} else
				FP_TO_INT_ROUND_D(vc, DB, 64, 2);
			goto done_d;
		}
		goto bad_insn;

	case FOP_SRC_Q:
		vb = alpha_read_fp_reg(fb);

		switch (func) {
		case FOP_FNC_CVTQL:
			/* Notice: We can get here only due to an integer
			   overflow.  Such overflows are reported as invalid
			   ops.  We return the result the hw would have
			   computed.  */
			vc = ((vb & 0xc0000000) << 32 |	/* sign and msb */
			      (vb & 0x3fffffff) << 29);	/* rest of the int */
			FP_SET_EXCEPTION (FP_EX_INVALID);
			goto done_d;

		case FOP_FNC_CVTxS:
			FP_FROM_INT_S(SR, ((long)vb), 64, long);
			goto pack_s;

		case FOP_FNC_CVTxT:
			FP_FROM_INT_D(DR, ((long)vb), 64, long);
			goto pack_d;
		}
		goto bad_insn;
	}
	goto bad_insn;

pack_s:
	FP_PACK_SP(&vc, SR);
	if ((_fex & FP_EX_UNDERFLOW) && (swcr & IEEE_MAP_UMZ))
		vc = 0;
	alpha_write_fp_reg_s(fc, vc);
	goto done;

pack_d:
	FP_PACK_DP(&vc, DR);
	if ((_fex & FP_EX_UNDERFLOW) && (swcr & IEEE_MAP_UMZ))
		vc = 0;
done_d:
	alpha_write_fp_reg(fc, vc);
	goto done;

	/*
	 * Take the appropriate action for each possible
	 * floating-point result:
	 *
	 *	- Set the appropriate bits in the FPCR
	 *	- If the specified exception is enabled in the FPCR,
	 *	  return.  The caller (entArith) will dispatch
	 *	  the appropriate signal to the translated program.
	 *
	 * In addition, properly track the exception state in software
	 * as described in the Alpha Architecture Handbook section 4.7.7.3.
	 */
done:
	if (_fex) {
		/* Record exceptions in software control word.  */
		swcr |= (_fex << IEEE_STATUS_TO_EXCSUM_SHIFT);
		current_thread_info()->ieee_state
		  |= (_fex << IEEE_STATUS_TO_EXCSUM_SHIFT);

		/* Update hardware control register.  */
		fpcr &= (~FPCR_MASK | FPCR_DYN_MASK);
		fpcr |= ieee_swcr_to_fpcr(swcr);
		wrfpcr(fpcr);

		/* Do we generate a signal?  */
		_fex = _fex & swcr & IEEE_TRAP_ENABLE_MASK;
		si_code = 0;
		if (_fex) {
			if (_fex & IEEE_TRAP_ENABLE_DNO) si_code = FPE_FLTUND;
			if (_fex & IEEE_TRAP_ENABLE_INE) si_code = FPE_FLTRES;
			if (_fex & IEEE_TRAP_ENABLE_UNF) si_code = FPE_FLTUND;
			if (_fex & IEEE_TRAP_ENABLE_OVF) si_code = FPE_FLTOVF;
			if (_fex & IEEE_TRAP_ENABLE_DZE) si_code = FPE_FLTDIV;
			if (_fex & IEEE_TRAP_ENABLE_INV) si_code = FPE_FLTINV;
		}

		return si_code;
	}

	/* We used to write the destination register here, but DEC FORTRAN
	   requires that the result *always* be written... so we do the write
	   immediately after the operations above.  */

	return 0;

bad_insn:
	printk(KERN_ERR "alpha_fp_emul: Invalid FP insn %#x at %#lx\n",
	       insn, pc);
	return -1;
}

long
alpha_fp_emul_imprecise (struct pt_regs *regs, unsigned long write_mask)
{
	unsigned long trigger_pc = regs->pc - 4;
	unsigned long insn, opcode, rc, si_code = 0;

	/*
	 * Turn off the bits corresponding to registers that are the
	 * target of instructions that set bits in the exception
	 * summary register.  We have some slack doing this because a
	 * register that is the target of a trapping instruction can
	 * be written at most once in the trap shadow.
	 *
	 * Branches, jumps, TRAPBs, EXCBs and calls to PALcode all
	 * bound the trap shadow, so we need not look any further than
	 * up to the first occurrence of such an instruction.
	 */
	while (write_mask) {
		get_user(insn, (__u32 __user *)(trigger_pc));
		opcode = insn >> 26;
		rc = insn & 0x1f;

		switch (opcode) {
		      case OPC_PAL:
		      case OPC_JSR:
		      case 0x30 ... 0x3f:	/* branches */
			goto egress;

		      case OPC_MISC:
			switch (insn & 0xffff) {
			      case MISC_TRAPB:
			      case MISC_EXCB:
				goto egress;

			      default:
				break;
			}
			break;

		      case OPC_INTA:
		      case OPC_INTL:
		      case OPC_INTS:
		      case OPC_INTM:
			write_mask &= ~(1UL << rc);
			break;

		      case OPC_FLTC:
		      case OPC_FLTV:
		      case OPC_FLTI:
		      case OPC_FLTL:
			write_mask &= ~(1UL << (rc + 32));
			break;
		}
		if (!write_mask) {
			/* Re-execute insns in the trap-shadow.  */
			regs->pc = trigger_pc + 4;
			si_code = alpha_fp_emul(trigger_pc);
			goto egress;
		}
		trigger_pc -= 4;
	}

egress:
	return si_code;
}


code:
/* SPDX-License-Identifier: GPL-2.0 */
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <asm/byteorder.h>
#include <asm/fpu.h>

#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
  ((sl) = (al) + (bl), (sh) = (ah) + (bh) + ((sl) < (al)))

#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
  ((sl) = (al) - (bl), (sh) = (ah) - (bh) - ((al) < (bl)))

#define umul_ppmm(wh, wl, u, v)			\
  __asm__ ("mulq %2,%3,%1; umulh %2,%3,%0"	\
	   : "=r" ((UDItype)(wh)),		\
	     "=&r" ((UDItype)(wl))		\
	   : "r" ((UDItype)(u)),		\
	     "r" ((UDItype)(v)))

#define udiv_qrnnd(q, r, n1, n0, d)				\
  do { unsigned long __r;					\
    (q) = __udiv_qrnnd (&__r, (n1), (n0), (d));			\
    (r) = __r;							\
  } while (0)
extern unsigned long __udiv_qrnnd (unsigned long *, unsigned long,
				   unsigned long , unsigned long);

#define UDIV_NEEDS_NORMALIZATION 1

#define abort()			goto bad_insn

#ifndef __LITTLE_ENDIAN
#define __LITTLE_ENDIAN -1
#endif
#define __BYTE_ORDER __LITTLE_ENDIAN


code:
# SPDX-License-Identifier: GPL-2.0-only
#
# Makefile for the linux alpha-specific parts of the memory manager.
#

ccflags-y := -Werror

obj-y	:= init.o fault.o

path: arch/alpha/mm/Makefile


code:
// SPDX-License-Identifier: GPL-2.0
/*
 *  linux/arch/alpha/mm/fault.c
 *
 *  Copyright (C) 1995  Linus Torvalds
 */

#include <linux/sched/signal.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <asm/io.h>

#define __EXTERN_INLINE inline
#include <asm/mmu_context.h>
#include <asm/tlbflush.h>
#undef  __EXTERN_INLINE

#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/types.h>
#include <linux/ptrace.h>
#include <linux/mman.h>
#include <linux/smp.h>
#include <linux/interrupt.h>
#include <linux/extable.h>
#include <linux/uaccess.h>
#include <linux/perf_event.h>

extern void die_if_kernel(char *,struct pt_regs *,long, unsigned long *);

/*
 * Force a new ASN for a task.
 */

#ifndef CONFIG_SMP
unsigned long last_asn = ASN_FIRST_VERSION;
#endif

void
__load_new_mm_context(struct mm_struct *next_mm)
{
	unsigned long mmc;
	struct pcb_struct *pcb;

	mmc = __get_new_mm_context(next_mm, smp_processor_id());
	next_mm->context[smp_processor_id()] = mmc;

	pcb = &current_thread_info()->pcb;
	pcb->asn = mmc & HARDWARE_ASN_MASK;
	pcb->ptbr = ((unsigned long) next_mm->pgd - IDENT_ADDR) >> PAGE_SHIFT;

	__reload_thread(pcb);
}

/*
 * This routine handles page faults.  It determines the address,
 * and the problem, and then passes it off to handle_mm_fault().
 *
 * mmcsr:
 *	0 = translation not valid
 *	1 = access violation
 *	2 = fault-on-read
 *	3 = fault-on-execute
 *	4 = fault-on-write
 *
 * cause:
 *	-1 = instruction fetch
 *	0 = load
 *	1 = store
 *
 * Registers $9 through $15 are saved in a block just prior to `regs' and
 * are saved and restored around the call to allow exception code to
 * modify them.
 */

/* Macro for exception fixup code to access integer registers.  */
#define dpf_reg(r)							\
	(((unsigned long *)regs)[(r) <= 8 ? (r) : (r) <= 15 ? (r)-16 :	\
				 (r) <= 18 ? (r)+10 : (r)-10])

asmlinkage void
do_page_fault(unsigned long address, unsigned long mmcsr,
	      long cause, struct pt_regs *regs)
{
	struct vm_area_struct * vma;
	struct mm_struct *mm = current->mm;
	const struct exception_table_entry *fixup;
	int si_code = SEGV_MAPERR;
	vm_fault_t fault;
	unsigned int flags = FAULT_FLAG_DEFAULT;

	/* As of EV6, a load into $31/$f31 is a prefetch, and never faults
	   (or is suppressed by the PALcode).  Support that for older CPUs
	   by ignoring such an instruction.  */
	if (cause == 0) {
		unsigned int insn;
		__get_user(insn, (unsigned int __user *)regs->pc);
		if ((insn >> 21 & 0x1f) == 0x1f &&
		    /* ldq ldl ldt lds ldg ldf ldwu ldbu */
		    (1ul << (insn >> 26) & 0x30f00001400ul)) {
			regs->pc += 4;
			return;
		}
	}

	/* If we're in an interrupt context, or have no user context,
	   we must not take the fault.  */
	if (!mm || faulthandler_disabled())
		goto no_context;

#ifdef CONFIG_ALPHA_LARGE_VMALLOC
	if (address >= TASK_SIZE)
		goto vmalloc_fault;
#endif
	if (user_mode(regs))
		flags |= FAULT_FLAG_USER;
	perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
retry:
	mmap_read_lock(mm);
	vma = find_vma(mm, address);
	if (!vma)
		goto bad_area;
	if (vma->vm_start <= address)
		goto good_area;
	if (!(vma->vm_flags & VM_GROWSDOWN))
		goto bad_area;
	if (expand_stack(vma, address))
		goto bad_area;

	/* Ok, we have a good vm_area for this memory access, so
	   we can handle it.  */
 good_area:
	si_code = SEGV_ACCERR;
	if (cause < 0) {
		if (!(vma->vm_flags & VM_EXEC))
			goto bad_area;
	} else if (!cause) {
		/* Allow reads even for write-only mappings */
		if (!(vma->vm_flags & (VM_READ | VM_WRITE)))
			goto bad_area;
	} else {
		if (!(vma->vm_flags & VM_WRITE))
			goto bad_area;
		flags |= FAULT_FLAG_WRITE;
	}

	/* If for any reason at all we couldn't handle the fault,
	   make sure we exit gracefully rather than endlessly redo
	   the fault.  */
	fault = handle_mm_fault(vma, address, flags, regs);

	if (fault_signal_pending(fault, regs))
		return;

	/* The fault is fully completed (including releasing mmap lock) */
	if (fault & VM_FAULT_COMPLETED)
		return;

	if (unlikely(fault & VM_FAULT_ERROR)) {
		if (fault & VM_FAULT_OOM)
			goto out_of_memory;
		else if (fault & VM_FAULT_SIGSEGV)
			goto bad_area;
		else if (fault & VM_FAULT_SIGBUS)
			goto do_sigbus;
		BUG();
	}

	if (fault & VM_FAULT_RETRY) {
		flags |= FAULT_FLAG_TRIED;

		/* No need to mmap_read_unlock(mm) as we would
		 * have already released it in __lock_page_or_retry
		 * in mm/filemap.c.
		 */

		goto retry;
	}

	mmap_read_unlock(mm);

	return;

	/* Something tried to access memory that isn't in our memory map.
	   Fix it, but check if it's kernel or user first.  */
 bad_area:
	mmap_read_unlock(mm);

	if (user_mode(regs))
		goto do_sigsegv;

 no_context:
	/* Are we prepared to handle this fault as an exception?  */
	if ((fixup = search_exception_tables(regs->pc)) != 0) {
		unsigned long newpc;
		newpc = fixup_exception(dpf_reg, fixup, regs->pc);
		regs->pc = newpc;
		return;
	}

	/* Oops. The kernel tried to access some bad page. We'll have to
	   terminate things with extreme prejudice.  */
	printk(KERN_ALERT "Unable to handle kernel paging request at "
	       "virtual address %016lx\n", address);
	die_if_kernel("Oops", regs, cause, (unsigned long*)regs - 16);
	make_task_dead(SIGKILL);

	/* We ran out of memory, or some other thing happened to us that
	   made us unable to handle the page fault gracefully.  */
 out_of_memory:
	mmap_read_unlock(mm);
	if (!user_mode(regs))
		goto no_context;
	pagefault_out_of_memory();
	return;

 do_sigbus:
	mmap_read_unlock(mm);
	/* Send a sigbus, regardless of whether we were in kernel
	   or user mode.  */
	force_sig_fault(SIGBUS, BUS_ADRERR, (void __user *) address);
	if (!user_mode(regs))
		goto no_context;
	return;

 do_sigsegv:
	force_sig_fault(SIGSEGV, si_code, (void __user *) address);
	return;

#ifdef CONFIG_ALPHA_LARGE_VMALLOC
 vmalloc_fault:
	if (user_mode(regs))
		goto do_sigsegv;
	else {
		/* Synchronize this task's top level page-table
		   with the "reference" page table from init.  */
		long index = pgd_index(address);
		pgd_t *pgd, *pgd_k;

		pgd = current->active_mm->pgd + index;
		pgd_k = swapper_pg_dir + index;
		if (!pgd_present(*pgd) && pgd_present(*pgd_k)) {
			pgd_val(*pgd) = pgd_val(*pgd_k);
			return;
		}
		goto no_context;
	}
#endif
}


code:
// SPDX-License-Identifier: GPL-2.0
/*
 *  linux/arch/alpha/mm/init.c
 *
 *  Copyright (C) 1995  Linus Torvalds
 */

/* 2.3.x zone allocator, 1999 Andrea Arcangeli <andrea@suse.de> */

#include <linux/pagemap.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/types.h>
#include <linux/ptrace.h>
#include <linux/mman.h>
#include <linux/mm.h>
#include <linux/swap.h>
#include <linux/init.h>
#include <linux/memblock.h> /* max_low_pfn */
#include <linux/vmalloc.h>
#include <linux/gfp.h>

#include <linux/uaccess.h>
#include <asm/pgalloc.h>
#include <asm/hwrpb.h>
#include <asm/dma.h>
#include <asm/mmu_context.h>
#include <asm/console.h>
#include <asm/tlb.h>
#include <asm/setup.h>
#include <asm/sections.h>

extern void die_if_kernel(char *,struct pt_regs *,long);

static struct pcb_struct original_pcb;

pgd_t *
pgd_alloc(struct mm_struct *mm)
{
	pgd_t *ret, *init;

	ret = (pgd_t *)__get_free_page(GFP_KERNEL | __GFP_ZERO);
	init = pgd_offset(&init_mm, 0UL);
	if (ret) {
#ifdef CONFIG_ALPHA_LARGE_VMALLOC
		memcpy (ret + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
			(PTRS_PER_PGD - USER_PTRS_PER_PGD - 1)*sizeof(pgd_t));
#else
		pgd_val(ret[PTRS_PER_PGD-2]) = pgd_val(init[PTRS_PER_PGD-2]);
#endif

		/* The last PGD entry is the VPTB self-map.  */
		pgd_val(ret[PTRS_PER_PGD-1])
		  = pte_val(mk_pte(virt_to_page(ret), PAGE_KERNEL));
	}
	return ret;
}

/*
 * BAD_PAGE is the page that is used for page faults when linux
 * is out-of-memory. Older versions of linux just did a
 * do_exit(), but using this instead means there is less risk
 * for a process dying in kernel mode, possibly leaving an inode
 * unused etc..
 *
 * BAD_PAGETABLE is the accompanying page-table: it is initialized
 * to point to BAD_PAGE entries.
 *
 * ZERO_PAGE is a special page that is used for zero-initialized
 * data and COW.
 */
pmd_t *
__bad_pagetable(void)
{
	memset(absolute_pointer(EMPTY_PGT), 0, PAGE_SIZE);
	return (pmd_t *) EMPTY_PGT;
}

pte_t
__bad_page(void)
{
	memset(absolute_pointer(EMPTY_PGE), 0, PAGE_SIZE);
	return pte_mkdirty(mk_pte(virt_to_page(EMPTY_PGE), PAGE_SHARED));
}

static inline unsigned long
load_PCB(struct pcb_struct *pcb)
{
	register unsigned long sp __asm__("$30");
	pcb->ksp = sp;
	return __reload_thread(pcb);
}

/* Set up initial PCB, VPTB, and other such nicities.  */

static inline void
switch_to_system_map(void)
{
	unsigned long newptbr;
	unsigned long original_pcb_ptr;

	/* Initialize the kernel's page tables.  Linux puts the vptb in
	   the last slot of the L1 page table.  */
	memset(swapper_pg_dir, 0, PAGE_SIZE);
	newptbr = ((unsigned long) swapper_pg_dir - PAGE_OFFSET) >> PAGE_SHIFT;
	pgd_val(swapper_pg_dir[1023]) =
		(newptbr << 32) | pgprot_val(PAGE_KERNEL);

	/* Set the vptb.  This is often done by the bootloader, but
	   shouldn't be required.  */
	if (hwrpb->vptb != 0xfffffffe00000000UL) {
		wrvptptr(0xfffffffe00000000UL);
		hwrpb->vptb = 0xfffffffe00000000UL;
		hwrpb_update_checksum(hwrpb);
	}

	/* Also set up the real kernel PCB while we're at it.  */
	init_thread_info.pcb.ptbr = newptbr;
	init_thread_info.pcb.flags = 1;	/* set FEN, clear everything else */
	original_pcb_ptr = load_PCB(&init_thread_info.pcb);
	tbia();

	/* Save off the contents of the original PCB so that we can
	   restore the original console's page tables for a clean reboot.

	   Note that the PCB is supposed to be a physical address, but
	   since KSEG values also happen to work, folks get confused.
	   Check this here.  */

	if (original_pcb_ptr < PAGE_OFFSET) {
		original_pcb_ptr = (unsigned long)
			phys_to_virt(original_pcb_ptr);
	}
	original_pcb = *(struct pcb_struct *) original_pcb_ptr;
}

int callback_init_done;

void * __init
callback_init(void * kernel_end)
{
	struct crb_struct * crb;
	pgd_t *pgd;
	p4d_t *p4d;
	pud_t *pud;
	pmd_t *pmd;
	void *two_pages;

	/* Starting at the HWRPB, locate the CRB. */
	crb = (struct crb_struct *)((char *)hwrpb + hwrpb->crb_offset);

	if (alpha_using_srm) {
		/* Tell the console whither it is to be remapped. */
		if (srm_fixup(VMALLOC_START, (unsigned long)hwrpb))
			__halt();		/* "We're boned."  --Bender */

		/* Edit the procedure descriptors for DISPATCH and FIXUP. */
		crb->dispatch_va = (struct procdesc_struct *)
			(VMALLOC_START + (unsigned long)crb->dispatch_va
			 - crb->map[0].va);
		crb->fixup_va = (struct procdesc_struct *)
			(VMALLOC_START + (unsigned long)crb->fixup_va
			 - crb->map[0].va);
	}

	switch_to_system_map();

	/* Allocate one PGD and one PMD.  In the case of SRM, we'll need
	   these to actually remap the console.  There is an assumption
	   here that only one of each is needed, and this allows for 8MB.
	   On systems with larger consoles, additional pages will be
	   allocated as needed during the mapping process.

	   In the case of not SRM, but not CONFIG_ALPHA_LARGE_VMALLOC,
	   we need to allocate the PGD we use for vmalloc before we start
	   forking other tasks.  */

	two_pages = (void *)
	  (((unsigned long)kernel_end + ~PAGE_MASK) & PAGE_MASK);
	kernel_end = two_pages + 2*PAGE_SIZE;
	memset(two_pages, 0, 2*PAGE_SIZE);

	pgd = pgd_offset_k(VMALLOC_START);
	p4d = p4d_offset(pgd, VMALLOC_START);
	pud = pud_offset(p4d, VMALLOC_START);
	pud_set(pud, (pmd_t *)two_pages);
	pmd = pmd_offset(pud, VMALLOC_START);
	pmd_set(pmd, (pte_t *)(two_pages + PAGE_SIZE));

	if (alpha_using_srm) {
		static struct vm_struct console_remap_vm;
		unsigned long nr_pages = 0;
		unsigned long vaddr;
		unsigned long i, j;

		/* calculate needed size */
		for (i = 0; i < crb->map_entries; ++i)
			nr_pages += crb->map[i].count;

		/* register the vm area */
		console_remap_vm.flags = VM_ALLOC;
		console_remap_vm.size = nr_pages << PAGE_SHIFT;
		vm_area_register_early(&console_remap_vm, PAGE_SIZE);

		vaddr = (unsigned long)console_remap_vm.addr;

		/* Set up the third level PTEs and update the virtual
		   addresses of the CRB entries.  */
		for (i = 0; i < crb->map_entries; ++i) {
			unsigned long pfn = crb->map[i].pa >> PAGE_SHIFT;
			crb->map[i].va = vaddr;
			for (j = 0; j < crb->map[i].count; ++j) {
				/* Newer consoles (especially on larger
				   systems) may require more pages of
				   PTEs. Grab additional pages as needed. */
				if (pmd != pmd_offset(pud, vaddr)) {
					memset(kernel_end, 0, PAGE_SIZE);
					pmd = pmd_offset(pud, vaddr);
					pmd_set(pmd, (pte_t *)kernel_end);
					kernel_end += PAGE_SIZE;
				}
				set_pte(pte_offset_kernel(pmd, vaddr),
					pfn_pte(pfn, PAGE_KERNEL));
				pfn++;
				vaddr += PAGE_SIZE;
			}
		}
	}

	callback_init_done = 1;
	return kernel_end;
}

/*
 * paging_init() sets up the memory map.
 */
void __init paging_init(void)
{
	unsigned long max_zone_pfn[MAX_NR_ZONES] = {0, };
	unsigned long dma_pfn;

	dma_pfn = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
	max_pfn = max_low_pfn;

	max_zone_pfn[ZONE_DMA] = dma_pfn;
	max_zone_pfn[ZONE_NORMAL] = max_pfn;

	/* Initialize mem_map[].  */
	free_area_init(max_zone_pfn);

	/* Initialize the kernel's ZERO_PGE. */
	memset(absolute_pointer(ZERO_PGE), 0, PAGE_SIZE);
}

#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SRM)
void
srm_paging_stop (void)
{
	/* Move the vptb back to where the SRM console expects it.  */
	swapper_pg_dir[1] = swapper_pg_dir[1023];
	tbia();
	wrvptptr(0x200000000UL);
	hwrpb->vptb = 0x200000000UL;
	hwrpb_update_checksum(hwrpb);

	/* Reload the page tables that the console had in use.  */
	load_PCB(&original_pcb);
	tbia();
}
#endif

void __init
mem_init(void)
{
	set_max_mapnr(max_low_pfn);
	high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
	memblock_free_all();
}

static const pgprot_t protection_map[16] = {
	[VM_NONE]					= _PAGE_P(_PAGE_FOE | _PAGE_FOW |
								  _PAGE_FOR),
	[VM_READ]					= _PAGE_P(_PAGE_FOE | _PAGE_FOW),
	[VM_WRITE]					= _PAGE_P(_PAGE_FOE),
	[VM_WRITE | VM_READ]				= _PAGE_P(_PAGE_FOE),
	[VM_EXEC]					= _PAGE_P(_PAGE_FOW | _PAGE_FOR),
	[VM_EXEC | VM_READ]				= _PAGE_P(_PAGE_FOW),
	[VM_EXEC | VM_WRITE]				= _PAGE_P(0),
	[VM_EXEC | VM_WRITE | VM_READ]			= _PAGE_P(0),
	[VM_SHARED]					= _PAGE_S(_PAGE_FOE | _PAGE_FOW |
								  _PAGE_FOR),
	[VM_SHARED | VM_READ]				= _PAGE_S(_PAGE_FOE | _PAGE_FOW),
	[VM_SHARED | VM_WRITE]				= _PAGE_S(_PAGE_FOE),
	[VM_SHARED | VM_WRITE | VM_READ]		= _PAGE_S(_PAGE_FOE),
	[VM_SHARED | VM_EXEC]				= _PAGE_S(_PAGE_FOW | _PAGE_FOR),
	[VM_SHARED | VM_EXEC | VM_READ]			= _PAGE_S(_PAGE_FOW),
	[VM_SHARED | VM_EXEC | VM_WRITE]		= _PAGE_S(0),
	[VM_SHARED | VM_EXEC | VM_WRITE | VM_READ]	= _PAGE_S(0)
};
DECLARE_VM_GET_PAGE_PROT


code:
# SPDX-License-Identifier: GPL-2.0
obj-y += kernel/
obj-y += mm/

# for cleaning
subdir- += boot

path: arch/arc/Kbuild


code:
# SPDX-License-Identifier: GPL-2.0-only
#
# Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
#

config ARC
	def_bool y
	select ARC_TIMERS
	select ARCH_HAS_CACHE_LINE_SIZE
	select ARCH_HAS_DEBUG_VM_PGTABLE
	select ARCH_HAS_DMA_PREP_COHERENT
	select ARCH_HAS_PTE_SPECIAL
	select ARCH_HAS_SETUP_DMA_OPS
	select ARCH_HAS_SYNC_DMA_FOR_CPU
	select ARCH_HAS_SYNC_DMA_FOR_DEVICE
	select ARCH_SUPPORTS_ATOMIC_RMW if ARC_HAS_LLSC
	select ARCH_32BIT_OFF_T
	select BUILDTIME_TABLE_SORT
	select CLONE_BACKWARDS
	select COMMON_CLK
	select DMA_DIRECT_REMAP
	select GENERIC_ATOMIC64 if !ISA_ARCV2 || !(ARC_HAS_LL64 && ARC_HAS_LLSC)
	# for now, we don't need GENERIC_IRQ_PROBE, CONFIG_GENERIC_IRQ_CHIP
	select GENERIC_IRQ_SHOW
	select GENERIC_PCI_IOMAP
	select GENERIC_PENDING_IRQ if SMP
	select GENERIC_SCHED_CLOCK
	select GENERIC_SMP_IDLE_THREAD
	select HAVE_ARCH_KGDB
	select HAVE_ARCH_TRACEHOOK
	select HAVE_ARCH_TRANSPARENT_HUGEPAGE if ARC_MMU_V4
	select HAVE_DEBUG_STACKOVERFLOW
	select HAVE_DEBUG_KMEMLEAK
	select HAVE_IOREMAP_PROT
	select HAVE_KERNEL_GZIP
	select HAVE_KERNEL_LZMA
	select HAVE_KPROBES
	select HAVE_KRETPROBES
	select HAVE_REGS_AND_STACK_ACCESS_API
	select HAVE_MOD_ARCH_SPECIFIC
	select HAVE_PERF_EVENTS
	select HAVE_SYSCALL_TRACEPOINTS
	select IRQ_DOMAIN
	select MODULES_USE_ELF_RELA
	select OF
	select OF_EARLY_FLATTREE
	select PCI_SYSCALL if PCI
	select PERF_USE_VMALLOC if ARC_CACHE_VIPT_ALIASING
	select HAVE_ARCH_JUMP_LABEL if ISA_ARCV2 && !CPU_ENDIAN_BE32
	select TRACE_IRQFLAGS_SUPPORT

config LOCKDEP_SUPPORT
	def_bool y

config SCHED_OMIT_FRAME_POINTER
	def_bool y

config GENERIC_CSUM
	def_bool y

config ARCH_FLATMEM_ENABLE
	def_bool y

config MMU
	def_bool y

config NO_IOPORT_MAP
	def_bool y

config GENERIC_CALIBRATE_DELAY
	def_bool y

config GENERIC_HWEIGHT
	def_bool y

config STACKTRACE_SUPPORT
	def_bool y
	select STACKTRACE

menu "ARC Architecture Configuration"

menu "ARC Platform/SoC/Board"

source "arch/arc/plat-tb10x/Kconfig"
source "arch/arc/plat-axs10x/Kconfig"
source "arch/arc/plat-hsdk/Kconfig"

endmenu

choice
	prompt "ARC Instruction Set"
	default ISA_ARCV2

config ISA_ARCOMPACT
	bool "ARCompact ISA"
	select CPU_NO_EFFICIENT_FFS
	help
	  The original ARC ISA of ARC600/700 cores

config ISA_ARCV2
	bool "ARC ISA v2"
	select ARC_TIMERS_64BIT
	help
	  ISA for the Next Generation ARC-HS cores

endchoice

menu "ARC CPU Configuration"

choice
	prompt "ARC Core"
	default ARC_CPU_770 if ISA_ARCOMPACT
	default ARC_CPU_HS if ISA_ARCV2

config ARC_CPU_770
	bool "ARC770"
	depends on ISA_ARCOMPACT
	select ARC_HAS_SWAPE
	help
	  Support for ARC770 core introduced with Rel 4.10 (Summer 2011)
	  This core has a bunch of cool new features:
	  -MMU-v3: Variable Page Sz (4k, 8k, 16k), bigger J-TLB (128x4)
	           Shared Address Spaces (for sharing TLB entries in MMU)
	  -Caches: New Prog Model, Region Flush
	  -Insns: endian swap, load-locked/store-conditional, time-stamp-ctr

config ARC_CPU_HS
	bool "ARC-HS"
	depends on ISA_ARCV2
	help
	  Support for ARC HS38x Cores based on ARCv2 ISA
	  The notable features are:
	    - SMP configurations of up to 4 cores with coherency
	    - Optional L2 Cache and IO-Coherency
	    - Revised Interrupt Architecture (multiple priorites, reg banks,
	        auto stack switch, auto regfile save/restore)
	    - MMUv4 (PIPT dcache, Huge Pages)
	    - Instructions for
		* 64bit load/store: LDD, STD
		* Hardware assisted divide/remainder: DIV, REM
		* Function prologue/epilogue: ENTER_S, LEAVE_S
		* IRQ enable/disable: CLRI, SETI
		* pop count: FFS, FLS
		* SETcc, BMSKN, XBFU...

endchoice

config ARC_TUNE_MCPU
	string "Override default -mcpu compiler flag"
	default ""
	help
	  Override default -mcpu=xxx compiler flag (which is set depending on
	  the ISA version) with the specified value.
	  NOTE: If specified flag isn't supported by current compiler the
	  ISA default value will be used as a fallback.

config CPU_BIG_ENDIAN
	bool "Enable Big Endian Mode"
	help
	  Build kernel for Big Endian Mode of ARC CPU

config SMP
	bool "Symmetric Multi-Processing"
	select ARC_MCIP if ISA_ARCV2
	help
	  This enables support for systems with more than one CPU.

if SMP

config NR_CPUS
	int "Maximum number of CPUs (2-4096)"
	range 2 4096
	default "4"

config ARC_SMP_HALT_ON_RESET
	bool "Enable Halt-on-reset boot mode"
	help
	  In SMP configuration cores can be configured as Halt-on-reset
	  or they could all start at same time. For Halt-on-reset, non
	  masters are parked until Master kicks them so they can start off
	  at designated entry point. For other case, all jump to common
	  entry point and spin wait for Master's signal.

endif #SMP

config ARC_MCIP
	bool "ARConnect Multicore IP (MCIP) Support "
	depends on ISA_ARCV2
	default y if SMP
	help
	  This IP block enables SMP in ARC-HS38 cores.
	  It provides for cross-core interrupts, multi-core debug
	  hardware semaphores, shared memory,....

menuconfig ARC_CACHE
	bool "Enable Cache Support"
	default y

if ARC_CACHE

config ARC_CACHE_LINE_SHIFT
	int "Cache Line Length (as power of 2)"
	range 5 7
	default "6"
	help
	  Starting with ARC700 4.9, Cache line length is configurable,
	  This option specifies "N", with Line-len = 2 power N
	  So line lengths of 32, 64, 128 are specified by 5,6,7, respectively
	  Linux only supports same line lengths for I and D caches.

config ARC_HAS_ICACHE
	bool "Use Instruction Cache"
	default y

config ARC_HAS_DCACHE
	bool "Use Data Cache"
	default y

config ARC_CACHE_PAGES
	bool "Per Page Cache Control"
	default y
	depends on ARC_HAS_ICACHE || ARC_HAS_DCACHE
	help
	  This can be used to over-ride the global I/D Cache Enable on a
	  per-page basis (but only for pages accessed via MMU such as
	  Kernel Virtual address or User Virtual Address)
	  TLB entries have a per-page Cache Enable Bit.
	  Note that Global I/D ENABLE + Per Page DISABLE works but corollary
	  Global DISABLE + Per Page ENABLE won't work

config ARC_CACHE_VIPT_ALIASING
	bool "Support VIPT Aliasing D$"
	depends on ARC_HAS_DCACHE && ISA_ARCOMPACT

endif #ARC_CACHE

config ARC_HAS_ICCM
	bool "Use ICCM"
	help
	  Single Cycle RAMS to store Fast Path Code

config ARC_ICCM_SZ
	int "ICCM Size in KB"
	default "64"
	depends on ARC_HAS_ICCM

config ARC_HAS_DCCM
	bool "Use DCCM"
	help
	  Single Cycle RAMS to store Fast Path Data

config ARC_DCCM_SZ
	int "DCCM Size in KB"
	default "64"
	depends on ARC_HAS_DCCM

config ARC_DCCM_BASE
	hex "DCCM map address"
	default "0xA0000000"
	depends on ARC_HAS_DCCM

choice
	prompt "MMU Version"
	default ARC_MMU_V3 if ISA_ARCOMPACT
	default ARC_MMU_V4 if ISA_ARCV2

config ARC_MMU_V3
	bool "MMU v3"
	depends on ISA_ARCOMPACT
	help
	  Introduced with ARC700 4.10: New Features
	  Variable Page size (1k-16k), var JTLB size 128 x (2 or 4)
	  Shared Address Spaces (SASID)

config ARC_MMU_V4
	bool "MMU v4"
	depends on ISA_ARCV2

endchoice

choice
	prompt "MMU Page Size"
	default ARC_PAGE_SIZE_8K

config ARC_PAGE_SIZE_8K
	bool "8KB"
	help
	  Choose between 8k vs 16k

config ARC_PAGE_SIZE_16K
	bool "16KB"

config ARC_PAGE_SIZE_4K
	bool "4KB"
	depends on ARC_MMU_V3 || ARC_MMU_V4

endchoice

choice
	prompt "MMU Super Page Size"
	depends on ISA_ARCV2 && TRANSPARENT_HUGEPAGE
	default ARC_HUGEPAGE_2M

config ARC_HUGEPAGE_2M
	bool "2MB"

config ARC_HUGEPAGE_16M
	bool "16MB"

endchoice

config PGTABLE_LEVELS
	int "Number of Page table levels"
	default 2

config ARC_COMPACT_IRQ_LEVELS
	depends on ISA_ARCOMPACT
	bool "Setup Timer IRQ as high Priority"
	# if SMP, LV2 enabled ONLY if ARC implementation has LV2 re-entrancy
	depends on !SMP

config ARC_FPU_SAVE_RESTORE
	bool "Enable FPU state persistence across context switch"
	help
	  ARCompact FPU has internal registers to assist with Double precision
	  Floating Point operations. There are control and stauts registers
	  for floating point exceptions and rounding modes. These are
	  preserved across task context switch when enabled.

config ARC_CANT_LLSC
	def_bool n

config ARC_HAS_LLSC
	bool "Insn: LLOCK/SCOND (efficient atomic ops)"
	default y
	depends on !ARC_CANT_LLSC

config ARC_HAS_SWAPE
	bool "Insn: SWAPE (endian-swap)"
	default y

if ISA_ARCV2

config ARC_USE_UNALIGNED_MEM_ACCESS
	bool "Enable unaligned access in HW"
	default y
	select HAVE_EFFICIENT_UNALIGNED_ACCESS
	help
	  The ARC HS architecture supports unaligned memory access
	  which is disabled by default. Enable unaligned access in
	  hardware and use software to use it

config ARC_HAS_LL64
	bool "Insn: 64bit LDD/STD"
	help
	  Enable gcc to generate 64-bit load/store instructions
	  ISA mandates even/odd registers to allow encoding of two
	  dest operands with 2 possible source operands.
	default y

config ARC_HAS_DIV_REM
	bool "Insn: div, divu, rem, remu"
	default y

config ARC_HAS_ACCL_REGS
	bool "Reg Pair ACCL:ACCH (FPU and/or MPY > 6 and/or DSP)"
	default y
	help
	  Depending on the configuration, CPU can contain accumulator reg-pair
	  (also referred to as r58:r59). These can also be used by gcc as GPR so
	  kernel needs to save/restore per process

config ARC_DSP_HANDLED
	def_bool n

config ARC_DSP_SAVE_RESTORE_REGS
	def_bool n

choice
	prompt "DSP support"
	default ARC_DSP_NONE
	help
	  Depending on the configuration, CPU can contain DSP registers
	  (ACC0_GLO, ACC0_GHI, DSP_BFLY0, DSP_CTRL, DSP_FFT_CTRL).
	  Below are options describing how to handle these registers in
	  interrupt entry / exit and in context switch.

config ARC_DSP_NONE
	bool "No DSP extension presence in HW"
	help
	  No DSP extension presence in HW

config ARC_DSP_KERNEL
	bool "DSP extension in HW, no support for userspace"
	select ARC_HAS_ACCL_REGS
	select ARC_DSP_HANDLED
	help
	  DSP extension presence in HW, no support for DSP-enabled userspace
	  applications. We don't save / restore DSP registers and only do
	  some minimal preparations so userspace won't be able to break kernel

config ARC_DSP_USERSPACE
	bool "Support DSP for userspace apps"
	select ARC_HAS_ACCL_REGS
	select ARC_DSP_HANDLED
	select ARC_DSP_SAVE_RESTORE_REGS
	help
	  DSP extension presence in HW, support save / restore DSP registers to
	  run DSP-enabled userspace applications

config ARC_DSP_AGU_USERSPACE
	bool "Support DSP with AGU for userspace apps"
	select ARC_HAS_ACCL_REGS
	select ARC_DSP_HANDLED
	select ARC_DSP_SAVE_RESTORE_REGS
	help
	  DSP and AGU extensions presence in HW, support save / restore DSP
	  and AGU registers to run DSP-enabled userspace applications
endchoice

config ARC_IRQ_NO_AUTOSAVE
	bool "Disable hardware autosave regfile on interrupts"
	default n
	help
	  On HS cores, taken interrupt auto saves the regfile on stack.
	  This is programmable and can be optionally disabled in which case
	  software INTERRUPT_PROLOGUE/EPILGUE do the needed work

config ARC_LPB_DISABLE
	bool "Disable loop buffer (LPB)"
	help
	  On HS cores, loop buffer (LPB) is programmable in runtime and can
	  be optionally disabled.

endif # ISA_ARCV2

endmenu   # "ARC CPU Configuration"

config LINUX_LINK_BASE
	hex "Kernel link address"
	default "0x80000000"
	help
	  ARC700 divides the 32 bit phy address space into two equal halves
	  -Lower 2G (0 - 0x7FFF_FFFF ) is user virtual, translated by MMU
	  -Upper 2G (0x8000_0000 onwards) is untranslated, for kernel
	  Typically Linux kernel is linked at the start of untransalted addr,
	  hence the default value of 0x8zs.
	  However some customers have peripherals mapped at this addr, so
	  Linux needs to be scooted a bit.
	  If you don't know what the above means, leave this setting alone.
	  This needs to match memory start address specified in Device Tree

config LINUX_RAM_BASE
	hex "RAM base address"
	default LINUX_LINK_BASE
	help
	  By default Linux is linked at base of RAM. However in some special
	  cases (such as HSDK), Linux can't be linked at start of DDR, hence
	  this option.

config HIGHMEM
	bool "High Memory Support"
	select HAVE_ARCH_PFN_VALID
	select KMAP_LOCAL
	help
	  With ARC 2G:2G address split, only upper 2G is directly addressable by
	  kernel. Enable this to potentially allow access to rest of 2G and PAE
	  in future

config ARC_HAS_PAE40
	bool "Support for the 40-bit Physical Address Extension"
	depends on ISA_ARCV2
	select HIGHMEM
	select PHYS_ADDR_T_64BIT
	help
	  Enable access to physical memory beyond 4G, only supported on
	  ARC cores with 40 bit Physical Addressing support

config ARC_KVADDR_SIZE
	int "Kernel Virtual Address Space size (MB)"
	range 0 512
	default "256"
	help
	  The kernel address space is carved out of 256MB of translated address
	  space for catering to vmalloc, modules, pkmap, fixmap. This however may
	  not suffice vmalloc requirements of a 4K CPU EZChip system. So allow
	  this to be stretched to 512 MB (by extending into the reserved
	  kernel-user gutter)

config ARC_CURR_IN_REG
	bool "Dedicate Register r25 for current_task pointer"
	default y
	help
	  This reserved Register R25 to point to Current Task in
	  kernel mode. This saves memory access for each such access

config ARC_EMUL_UNALIGNED
	bool "Emulate unaligned memory access (userspace only)"
	select SYSCTL_ARCH_UNALIGN_NO_WARN
	select SYSCTL_ARCH_UNALIGN_ALLOW
	depends on ISA_ARCOMPACT
	help
	  This enables misaligned 16 & 32 bit memory access from user space.
	  Use ONLY-IF-ABS-NECESSARY as it will be very slow and also can hide
	  potential bugs in code

config HZ
	int "Timer Frequency"
	default 100

config ARC_METAWARE_HLINK
	bool "Support for Metaware debugger assisted Host access"
	help
	  This options allows a Linux userland apps to directly access
	  host file system (open/creat/read/write etc) with help from
	  Metaware Debugger. This can come in handy for Linux-host communication
	  when there is no real usable peripheral such as EMAC.

menuconfig ARC_DBG
	bool "ARC debugging"
	default y

if ARC_DBG

config ARC_DW2_UNWIND
	bool "Enable DWARF specific kernel stack unwind"
	default y
	select KALLSYMS
	help
	  Compiles the kernel with DWARF unwind information and can be used
	  to get stack backtraces.

	  If you say Y here the resulting kernel image will be slightly larger
	  but not slower, and it will give very useful debugging information.
	  If you don't debug the kernel, you can say N, but we may not be able
	  to solve problems without frame unwind information

config ARC_DBG_JUMP_LABEL
	bool "Paranoid checks in Static Keys (jump labels) code"
	depends on JUMP_LABEL
	default y if STATIC_KEYS_SELFTEST
	help
	  Enable paranoid checks and self-test of both ARC-specific and generic
	  part of static keys (jump labels) related code.
endif

config ARC_BUILTIN_DTB_NAME
	string "Built in DTB"
	help
	  Set the name of the DTB to embed in the vmlinux binary
	  Leaving it blank selects the minimal "skeleton" dtb

endmenu	 # "ARC Architecture Configuration"

config ARCH_FORCE_MAX_ORDER
	int "Maximum zone order"
	default "12" if ARC_HUGEPAGE_16M
	default "11"

source "kernel/power/Kconfig"

path: arch/arc/Kconfig


code:
# SPDX-License-Identifier: GPL-2.0

config 16KSTACKS
	bool "Use 16Kb for kernel stacks instead of 8Kb"
	help
	  If you say Y here the kernel will use a  16Kb stacksize for the
	  kernel stack attached to each process/thread. The default is 8K.
	  This increases the resident kernel footprint and will cause less
	  threads to run on the system and also increase the pressure
	  on the VM subsystem for higher order allocations.


code:
# SPDX-License-Identifier: GPL-2.0-only
#
# Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
#

KBUILD_DEFCONFIG := haps_hs_smp_defconfig

ifeq ($(CROSS_COMPILE),)
CROSS_COMPILE := $(call cc-cross-prefix, arc-linux- arceb-linux-)
endif

cflags-y	+= -fno-common -pipe -fno-builtin -mmedium-calls -D__linux__

tune-mcpu-def-$(CONFIG_ISA_ARCOMPACT)	:= -mcpu=arc700
tune-mcpu-def-$(CONFIG_ISA_ARCV2)	:= -mcpu=hs38

ifeq ($(CONFIG_ARC_TUNE_MCPU),)
cflags-y				+= $(tune-mcpu-def-y)
else
tune-mcpu				:= $(CONFIG_ARC_TUNE_MCPU)
ifneq ($(call cc-option,$(tune-mcpu)),)
cflags-y				+= $(tune-mcpu)
else
# The flag provided by 'CONFIG_ARC_TUNE_MCPU' option isn't known by this compiler
# (probably the compiler is too old). Use ISA default mcpu flag instead as a safe option.
$(warning ** WARNING ** CONFIG_ARC_TUNE_MCPU flag '$(tune-mcpu)' is unknown, fallback to '$(tune-mcpu-def-y)')
cflags-y				+= $(tune-mcpu-def-y)
endif
endif

ifdef CONFIG_ARC_CURR_IN_REG
# For a global register definition, make sure it gets passed to every file
# We had a customer reported bug where some code built in kernel was NOT using
# any kernel headers, and missing the r25 global register
# Can't do unconditionally because of recursive include issues
# due to <linux/thread_info.h>
LINUXINCLUDE	+=  -include $(srctree)/arch/arc/include/asm/current.h
endif

cflags-y				+= -fsection-anchors

cflags-$(CONFIG_ARC_HAS_LLSC)		+= -mlock
cflags-$(CONFIG_ARC_HAS_SWAPE)		+= -mswape

ifdef CONFIG_ISA_ARCV2

ifdef CONFIG_ARC_USE_UNALIGNED_MEM_ACCESS
cflags-y				+= -munaligned-access
else
cflags-y				+= -mno-unaligned-access
endif

ifndef CONFIG_ARC_HAS_LL64
cflags-y				+= -mno-ll64
endif

ifndef CONFIG_ARC_HAS_DIV_REM
cflags-y				+= -mno-div-rem
endif

endif

cfi := $(call as-instr,.cfi_startproc\n.cfi_endproc,-DARC_DW2_UNWIND_AS_CFI)
cflags-$(CONFIG_ARC_DW2_UNWIND)		+= -fasynchronous-unwind-tables $(cfi)

# small data is default for elf32 tool-chain. If not usable, disable it
# This also allows repurposing GP as scratch reg to gcc reg allocator
disable_small_data := y
cflags-$(disable_small_data)		+= -mno-sdata -fcall-used-gp

cflags-$(CONFIG_CPU_BIG_ENDIAN)		+= -mbig-endian
ldflags-$(CONFIG_CPU_BIG_ENDIAN)	+= -EB

LIBGCC	= $(shell $(CC) $(cflags-y) --print-libgcc-file-name)

# Modules with short calls might break for calls into builtin-kernel
KBUILD_CFLAGS_MODULE	+= -mlong-calls -mno-millicode

# Finally dump eveything into kernel build system
KBUILD_CFLAGS	+= $(cflags-y)
KBUILD_AFLAGS	+= $(KBUILD_CFLAGS)
KBUILD_LDFLAGS	+= $(ldflags-y)

# w/o this dtb won't embed into kernel binary
core-y		+= arch/arc/boot/dts/

core-y				+= arch/arc/plat-sim/
core-$(CONFIG_ARC_PLAT_TB10X)	+= arch/arc/plat-tb10x/
core-$(CONFIG_ARC_PLAT_AXS10X)	+= arch/arc/plat-axs10x/
core-$(CONFIG_ARC_SOC_HSDK)	+= arch/arc/plat-hsdk/

libs-y		+= arch/arc/lib/ $(LIBGCC)

boot		:= arch/arc/boot

boot_targets := uImage.bin uImage.gz uImage.lzma

PHONY += $(boot_targets)
$(boot_targets): vmlinux
	$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@

uimage-default-y			:= uImage.bin
uimage-default-$(CONFIG_KERNEL_GZIP)	:= uImage.gz
uimage-default-$(CONFIG_KERNEL_LZMA)	:= uImage.lzma

PHONY += uImage
uImage: $(uimage-default-y)
	@ln -sf $< $(boot)/uImage
	@$(kecho) '  Image $(boot)/uImage is ready'

CLEAN_FILES += $(boot)/uImage

path: arch/arc/Makefile


code:
# SPDX-License-Identifier: GPL-2.0-only
uImage


code:
# SPDX-License-Identifier: GPL-2.0

# uImage build relies on mkimage being availble on your host for ARC target
# You will need to build u-boot for ARC, rename mkimage to arc-elf32-mkimage
# and make sure it's reacable from your PATH

OBJCOPYFLAGS= -O binary -R .note -R .note.gnu.build-id -R .comment -S

LINUX_START_TEXT = $$($(READELF) -h vmlinux | \
			grep "Entry point address" | grep -o 0x.*)

UIMAGE_LOADADDR    = $(CONFIG_LINUX_LINK_BASE)
UIMAGE_ENTRYADDR   = $(LINUX_START_TEXT)

targets += vmlinux.bin
targets += vmlinux.bin.gz
targets += vmlinux.bin.lzma
targets += uImage.bin
targets += uImage.gz
targets += uImage.lzma

$(obj)/vmlinux.bin: vmlinux FORCE
	$(call if_changed,objcopy)

$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
	$(call if_changed,gzip)

$(obj)/vmlinux.bin.lzma: $(obj)/vmlinux.bin FORCE
	$(call if_changed,lzma)

$(obj)/uImage.bin: $(obj)/vmlinux.bin FORCE
	$(call if_changed,uimage,none)

$(obj)/uImage.gz: $(obj)/vmlinux.bin.gz FORCE
	$(call if_changed,uimage,gzip)

$(obj)/uImage.lzma: $(obj)/vmlinux.bin.lzma FORCE
	$(call if_changed,uimage,lzma)

path: arch/arc/boot/Makefile


code:
# SPDX-License-Identifier: GPL-2.0
# Built-in dtb
builtindtb-y		:= nsim_700

ifneq ($(CONFIG_ARC_BUILTIN_DTB_NAME),)
	builtindtb-y	:= $(CONFIG_ARC_BUILTIN_DTB_NAME)
endif

obj-y   += $(builtindtb-y).dtb.o
dtb-y := $(builtindtb-y).dtb

# for CONFIG_OF_ALL_DTBS test
dtstree	:= $(srctree)/$(src)
dtb-	:= $(patsubst $(dtstree)/%.dts,%.dtb, $(wildcard $(dtstree)/*.dts))

# board-specific dtc flags
DTC_FLAGS_hsdk += --pad 20

path: arch/arc/boot/dts/Makefile


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Abilis Systems TB100 SOC device tree
 *
 * Copyright (C) Abilis Systems 2013
 *
 * Author: Christian Ruppert <christian.ruppert@abilis.com>
 */

/include/ "abilis_tb10x.dtsi"

/ {
	soc100 {
		bus-frequency	= <166666666>;

		pll0: oscillator {
			clock-frequency  = <1000000000>;
		};
		cpu_clk: clkdiv_cpu {
			clock-mult = <1>;
			clock-div = <2>;
		};
		ahb_clk: clkdiv_ahb {
			clock-mult = <1>;
			clock-div = <6>;
		};

		iomux: iomux@ff10601c {
			/* Port 1 */
			pctl_tsin_s0: pctl-tsin-s0 {   /* Serial TS-in 0 */
				abilis,function = "mis0";
			};
			pctl_tsin_s1: pctl-tsin-s1 {   /* Serial TS-in 1 */
				abilis,function = "mis1";
			};
			pctl_gpio_a: pctl-gpio-a {     /* GPIO bank A */
				abilis,function = "gpioa";
			};
			pctl_tsin_p1: pctl-tsin-p1 {   /* Parallel TS-in 1 */
				abilis,function = "mip1";
			};
			/* Port 2 */
			pctl_tsin_s2: pctl-tsin-s2 {   /* Serial TS-in 2 */
				abilis,function = "mis2";
			};
			pctl_tsin_s3: pctl-tsin-s3 {   /* Serial TS-in 3 */
				abilis,function = "mis3";
			};
			pctl_gpio_c: pctl-gpio-c {     /* GPIO bank C */
				abilis,function = "gpioc";
			};
			pctl_tsin_p3: pctl-tsin-p3 {   /* Parallel TS-in 3 */
				abilis,function = "mip3";
			};
			/* Port 3 */
			pctl_tsin_s4: pctl-tsin-s4 {   /* Serial TS-in 4 */
				abilis,function = "mis4";
			};
			pctl_tsin_s5: pctl-tsin-s5 {   /* Serial TS-in 5 */
				abilis,function = "mis5";
			};
			pctl_gpio_e: pctl-gpio-e {     /* GPIO bank E */
				abilis,function = "gpioe";
			};
			pctl_tsin_p5: pctl-tsin-p5 {   /* Parallel TS-in 5 */
				abilis,function = "mip5";
			};
			/* Port 4 */
			pctl_tsin_s6: pctl-tsin-s6 {   /* Serial TS-in 6 */
				abilis,function = "mis6";
			};
			pctl_tsin_s7: pctl-tsin-s7 {   /* Serial TS-in 7 */
				abilis,function = "mis7";
			};
			pctl_gpio_g: pctl-gpio-g {     /* GPIO bank G */
				abilis,function = "gpiog";
			};
			pctl_tsin_p7: pctl-tsin-p7 {   /* Parallel TS-in 7 */
				abilis,function = "mip7";
			};
			/* Port 5 */
			pctl_gpio_j: pctl-gpio-j {     /* GPIO bank J */
				abilis,function = "gpioj";
			};
			pctl_gpio_k: pctl-gpio-k {     /* GPIO bank K */
				abilis,function = "gpiok";
			};
			pctl_ciplus: pctl-ciplus {     /* CI+ interface */
				abilis,function = "ciplus";
			};
			pctl_mcard: pctl-mcard {       /* M-Card interface */
				abilis,function = "mcard";
			};
			/* Port 6 */
			pctl_tsout_p: pctl-tsout-p {   /* Parallel TS-out */
				abilis,function = "mop";
			};
			pctl_tsout_s0: pctl-tsout-s0 { /* Serial TS-out 0 */
				abilis,function = "mos0";
			};
			pctl_tsout_s1: pctl-tsout-s1 { /* Serial TS-out 1 */
				abilis,function = "mos1";
			};
			pctl_tsout_s2: pctl-tsout-s2 { /* Serial TS-out 2 */
				abilis,function = "mos2";
			};
			pctl_tsout_s3: pctl-tsout-s3 { /* Serial TS-out 3 */
				abilis,function = "mos3";
			};
			/* Port 7 */
			pctl_uart0: pctl-uart0 {       /* UART 0 */
				abilis,function = "uart0";
			};
			pctl_uart1: pctl-uart1 {       /* UART 1 */
				abilis,function = "uart1";
			};
			pctl_gpio_l: pctl-gpio-l {     /* GPIO bank L */
				abilis,function = "gpiol";
			};
			pctl_gpio_m: pctl-gpio-m {     /* GPIO bank M */
				abilis,function = "gpiom";
			};
			/* Port 8 */
			pctl_spi3: pctl-spi3 {
				abilis,function = "spi3";
			};
			/* Port 9 */
			pctl_spi1: pctl-spi1 {
				abilis,function = "spi1";
			};
			pctl_gpio_n: pctl-gpio-n {
				abilis,function = "gpion";
			};
			/* Unmuxed GPIOs */
			pctl_gpio_b: pctl-gpio-b {
				abilis,function = "gpiob";
			};
			pctl_gpio_d: pctl-gpio-d {
				abilis,function = "gpiod";
			};
			pctl_gpio_f: pctl-gpio-f {
				abilis,function = "gpiof";
			};
			pctl_gpio_h: pctl-gpio-h {
				abilis,function = "gpioh";
			};
			pctl_gpio_i: pctl-gpio-i {
				abilis,function = "gpioi";
			};
		};

		gpioa: gpio@ff140000 {
			compatible = "abilis,tb10x-gpio";
			interrupt-controller;
			#interrupt-cells = <1>;
			interrupt-parent = <&tb10x_ictl>;
			interrupts = <27 2>;
			reg = <0xff140000 0x1000>;
			gpio-controller;
			#gpio-cells = <2>;
			abilis,ngpio = <3>;
			gpio-ranges = <&iomux 0 0 0>;
			gpio-ranges-group-names = "gpioa";
		};
		gpiob: gpio@ff141000 {
			compatible = "abilis,tb10x-gpio";
			interrupt-controller;
			#interrupt-cells = <1>;
			interrupt-parent = <&tb10x_ictl>;
			interrupts = <27 2>;
			reg = <0xff141000 0x1000>;
			gpio-controller;
			#gpio-cells = <2>;
			abilis,ngpio = <2>;
			gpio-ranges = <&iomux 0 0 0>;
			gpio-ranges-group-names = "gpiob";
		};
		gpioc: gpio@ff142000 {
			compatible = "abilis,tb10x-gpio";
			interrupt-controller;
			#interrupt-cells = <1>;
			interrupt-parent = <&tb10x_ictl>;
			interrupts = <27 2>;
			reg = <0xff142000 0x1000>;
			gpio-controller;
			#gpio-cells = <2>;
			abilis,ngpio = <3>;
			gpio-ranges = <&iomux 0 0 0>;
			gpio-ranges-group-names = "gpioc";
		};
		gpiod: gpio@ff143000 {
			compatible = "abilis,tb10x-gpio";
			interrupt-controller;
			#interrupt-cells = <1>;
			interrupt-parent = <&tb10x_ictl>;
			interrupts = <27 2>;
			reg = <0xff143000 0x1000>;
			gpio-controller;
			#gpio-cells = <2>;
			abilis,ngpio = <2>;
			gpio-ranges = <&iomux 0 0 0>;
			gpio-ranges-group-names = "gpiod";
		};
		gpioe: gpio@ff144000 {
			compatible = "abilis,tb10x-gpio";
			interrupt-controller;
			#interrupt-cells = <1>;
			interrupt-parent = <&tb10x_ictl>;
			interrupts = <27 2>;
			reg = <0xff144000 0x1000>;
			gpio-controller;
			#gpio-cells = <2>;
			abilis,ngpio = <3>;
			gpio-ranges = <&iomux 0 0 0>;
			gpio-ranges-group-names = "gpioe";
		};
		gpiof: gpio@ff145000 {
			compatible = "abilis,tb10x-gpio";
			interrupt-controller;
			#interrupt-cells = <1>;
			interrupt-parent = <&tb10x_ictl>;
			interrupts = <27 2>;
			reg = <0xff145000 0x1000>;
			gpio-controller;
			#gpio-cells = <2>;
			abilis,ngpio = <2>;
			gpio-ranges = <&iomux 0 0 0>;
			gpio-ranges-group-names = "gpiof";
		};
		gpiog: gpio@ff146000 {
			compatible = "abilis,tb10x-gpio";
			interrupt-controller;
			#interrupt-cells = <1>;
			interrupt-parent = <&tb10x_ictl>;
			interrupts = <27 2>;
			reg = <0xff146000 0x1000>;
			gpio-controller;
			#gpio-cells = <2>;
			abilis,ngpio = <3>;
			gpio-ranges = <&iomux 0 0 0>;
			gpio-ranges-group-names = "gpiog";
		};
		gpioh: gpio@ff147000 {
			compatible = "abilis,tb10x-gpio";
			interrupt-controller;
			#interrupt-cells = <1>;
			interrupt-parent = <&tb10x_ictl>;
			interrupts = <27 2>;
			reg = <0xff147000 0x1000>;
			gpio-controller;
			#gpio-cells = <2>;
			abilis,ngpio = <2>;
			gpio-ranges = <&iomux 0 0 0>;
			gpio-ranges-group-names = "gpioh";
		};
		gpioi: gpio@ff148000 {
			compatible = "abilis,tb10x-gpio";
			interrupt-controller;
			#interrupt-cells = <1>;
			interrupt-parent = <&tb10x_ictl>;
			interrupts = <27 2>;
			reg = <0xff148000 0x1000>;
			gpio-controller;
			#gpio-cells = <2>;
			abilis,ngpio = <12>;
			gpio-ranges = <&iomux 0 0 0>;
			gpio-ranges-group-names = "gpioi";
		};
		gpioj: gpio@ff149000 {
			compatible = "abilis,tb10x-gpio";
			interrupt-controller;
			#interrupt-cells = <1>;
			interrupt-parent = <&tb10x_ictl>;
			interrupts = <27 2>;
			reg = <0xff149000 0x1000>;
			gpio-controller;
			#gpio-cells = <2>;
			abilis,ngpio = <32>;
			gpio-ranges = <&iomux 0 0 0>;
			gpio-ranges-group-names = "gpioj";
		};
		gpiok: gpio@ff14a000 {
			compatible = "abilis,tb10x-gpio";
			interrupt-controller;
			#interrupt-cells = <1>;
			interrupt-parent = <&tb10x_ictl>;
			interrupts = <27 2>;
			reg = <0xff14a000 0x1000>;
			gpio-controller;
			#gpio-cells = <2>;
			abilis,ngpio = <22>;
			gpio-ranges = <&iomux 0 0 0>;
			gpio-ranges-group-names = "gpiok";
		};
		gpiol: gpio@ff14b000 {
			compatible = "abilis,tb10x-gpio";
			interrupt-controller;
			#interrupt-cells = <1>;
			interrupt-parent = <&tb10x_ictl>;
			interrupts = <27 2>;
			reg = <0xff14b000 0x1000>;
			gpio-controller;
			#gpio-cells = <2>;
			abilis,ngpio = <4>;
			gpio-ranges = <&iomux 0 0 0>;
			gpio-ranges-group-names = "gpiol";
		};
		gpiom: gpio@ff14c000 {
			compatible = "abilis,tb10x-gpio";
			interrupt-controller;
			#interrupt-cells = <1>;
			interrupt-parent = <&tb10x_ictl>;
			interrupts = <27 2>;
			reg = <0xff14c000 0x1000>;
			gpio-controller;
			#gpio-cells = <2>;
			abilis,ngpio = <4>;
			gpio-ranges = <&iomux 0 0 0>;
			gpio-ranges-group-names = "gpiom";
		};
		gpion: gpio@ff14d000 {
			compatible = "abilis,tb10x-gpio";
			interrupt-controller;
			#interrupt-cells = <1>;
			interrupt-parent = <&tb10x_ictl>;
			interrupts = <27 2>;
			reg = <0xff14d000 0x1000>;
			gpio-controller;
			#gpio-cells = <2>;
			abilis,ngpio = <5>;
			gpio-ranges = <&iomux 0 0 0>;
			gpio-ranges-group-names = "gpion";
		};
	};
};


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Abilis Systems TB100 Development Kit PCB device tree
 *
 * Copyright (C) Abilis Systems 2013
 *
 * Author: Christian Ruppert <christian.ruppert@abilis.com>
 */

/dts-v1/;

/include/ "abilis_tb100.dtsi"

/ {
	model = "abilis,tb100";
	chosen {
		bootargs = "earlycon=uart8250,mmio32,0xff100000,9600n8 console=ttyS0,9600n8";
	};

	aliases { };

	memory {
		device_type = "memory";
		reg = <0x80000000 0x08000000>;	/* 128M */
	};

	soc100 {
		uart@ff100000 {
			pinctrl-names = "default";
			pinctrl-0 = <&pctl_uart0>;
		};
		ethernet@fe100000 {
			phy-mode = "rgmii";
		};

		i2c0: i2c@ff120000 {
			i2c-sda-hold-time-ns = <432>;
		};
		i2c1: i2c@ff121000 {
			i2c-sda-hold-time-ns = <432>;
		};
		i2c2: i2c@ff122000 {
			i2c-sda-hold-time-ns = <432>;
		};
		i2c3: i2c@ff123000 {
			i2c-sda-hold-time-ns = <432>;
		};
		i2c4: i2c@ff124000 {
			i2c-sda-hold-time-ns = <432>;
		};

		leds {
			compatible = "gpio-leds";
			power {
				label = "Power";
				gpios = <&gpioi 0 0>;
				linux,default-trigger = "default-on";
			};
			heartbeat {
				label = "Heartbeat";
				gpios = <&gpioi 1 0>;
				linux,default-trigger = "heartbeat";
			};
			led2 {
				label = "LED2";
				gpios = <&gpioi 2 0>;
				default-state = "off";
			};
			led3 {
				label = "LED3";
				gpios = <&gpioi 3 0>;
				default-state = "off";
			};
			led4 {
				label = "LED4";
				gpios = <&gpioi 4 0>;
				default-state = "off";
			};
			led5 {
				label = "LED5";
				gpios = <&gpioi 5 0>;
				default-state = "off";
			};
			led6 {
				label = "LED6";
				gpios = <&gpioi 6 0>;
				default-state = "off";
			};
			led7 {
				label = "LED7";
				gpios = <&gpioi 7 0>;
				default-state = "off";
			};
			led8 {
				label = "LED8";
				gpios = <&gpioi 8 0>;
				default-state = "off";
			};
			led9 {
				label = "LED9";
				gpios = <&gpioi 9 0>;
				default-state = "off";
			};
			led10 {
				label = "LED10";
				gpios = <&gpioi 10 0>;
				default-state = "off";
			};
			led11 {
				label = "LED11";
				gpios = <&gpioi 11 0>;
				default-state = "off";
			};
		};
	};
};


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Abilis Systems TB101 SOC device tree
 *
 * Copyright (C) Abilis Systems 2013
 *
 * Author: Christian Ruppert <christian.ruppert@abilis.com>
 */

/include/ "abilis_tb10x.dtsi"

/ {
	soc100 {
		bus-frequency	= <166666666>;

		pll0: oscillator {
			clock-frequency  = <1000000000>;
		};
		cpu_clk: clkdiv_cpu {
			clock-mult = <1>;
			clock-div = <2>;
		};
		ahb_clk: clkdiv_ahb {
			clock-mult = <1>;
			clock-div = <6>;
		};

		iomux: iomux@ff10601c {
			/* Port 1 */
			pctl_tsin_s0: pctl-tsin-s0 {   /* Serial TS-in 0 */
				abilis,function = "mis0";
			};
			pctl_tsin_s1: pctl-tsin-s1 {   /* Serial TS-in 1 */
				abilis,function = "mis1";
			};
			pctl_gpio_a: pctl-gpio-a {     /* GPIO bank A */
				abilis,function = "gpioa";
			};
			pctl_tsin_p1: pctl-tsin-p1 {   /* Parallel TS-in 1 */
				abilis,function = "mip1";
			};
			/* Port 2 */
			pctl_tsin_s2: pctl-tsin-s2 {   /* Serial TS-in 2 */
				abilis,function = "mis2";
			};
			pctl_tsin_s3: pctl-tsin-s3 {   /* Serial TS-in 3 */
				abilis,function = "mis3";
			};
			pctl_gpio_c: pctl-gpio-c {     /* GPIO bank C */
				abilis,function = "gpioc";
			};
			pctl_tsin_p3: pctl-tsin-p3 {   /* Parallel TS-in 3 */
				abilis,function = "mip3";
			};
			/* Port 3 */
			pctl_tsin_s4: pctl-tsin-s4 {   /* Serial TS-in 4 */
				abilis,function = "mis4";
			};
			pctl_tsin_s5: pctl-tsin-s5 {   /* Serial TS-in 5 */
				abilis,function = "mis5";
			};
			pctl_gpio_e: pctl-gpio-e {     /* GPIO bank E */
				abilis,function = "gpioe";
			};
			pctl_tsin_p5: pctl-tsin-p5 {   /* Parallel TS-in 5 */
				abilis,function = "mip5";
			};
			/* Port 4 */
			pctl_tsin_s6: pctl-tsin-s6 {   /* Serial TS-in 6 */
				abilis,function = "mis6";
			};
			pctl_tsin_s7: pctl-tsin-s7 {   /* Serial TS-in 7 */
				abilis,function = "mis7";
			};
			pctl_gpio_g: pctl-gpio-g {     /* GPIO bank G */
				abilis,function = "gpiog";
			};
			pctl_tsin_p7: pctl-tsin-p7 {   /* Parallel TS-in 7 */
				abilis,function = "mip7";
			};
			/* Port 5 */
			pctl_gpio_j: pctl-gpio-j {     /* GPIO bank J */
				abilis,function = "gpioj";
			};
			pctl_gpio_k: pctl-gpio-k {     /* GPIO bank K */
				abilis,function = "gpiok";
			};
			pctl_ciplus: pctl-ciplus {     /* CI+ interface */
				abilis,function = "ciplus";
			};
			pctl_mcard: pctl-mcard {       /* M-Card interface */
				abilis,function = "mcard";
			};
			pctl_stc0: pctl-stc0 {         /* Smart card I/F 0 */
				abilis,function = "stc0";
			};
			pctl_stc1: pctl-stc1 {         /* Smart card I/F 1 */
				abilis,function = "stc1";
			};
			/* Port 6 */
			pctl_tsout_p: pctl-tsout-p {   /* Parallel TS-out */
				abilis,function = "mop";
			};
			pctl_tsout_s0: pctl-tsout-s0 { /* Serial TS-out 0 */
				abilis,function = "mos0";
			};
			pctl_tsout_s1: pctl-tsout-s1 { /* Serial TS-out 1 */
				abilis,function = "mos1";
			};
			pctl_tsout_s2: pctl-tsout-s2 { /* Serial TS-out 2 */
				abilis,function = "mos2";
			};
			pctl_tsout_s3: pctl-tsout-s3 { /* Serial TS-out 3 */
				abilis,function = "mos3";
			};
			/* Port 7 */
			pctl_uart0: pctl-uart0 {       /* UART 0 */
				abilis,function = "uart0";
			};
			pctl_uart1: pctl-uart1 {       /* UART 1 */
				abilis,function = "uart1";
			};
			pctl_gpio_l: pctl-gpio-l {     /* GPIO bank L */
				abilis,function = "gpiol";
			};
			pctl_gpio_m: pctl-gpio-m {     /* GPIO bank M */
				abilis,function = "gpiom";
			};
			/* Port 8 */
			pctl_spi3: pctl-spi3 {
				abilis,function = "spi3";
			};
			pctl_jtag: pctl-jtag {
				abilis,function = "jtag";
			};
			/* Port 9 */
			pctl_spi1: pctl-spi1 {
				abilis,function = "spi1";
			};
			pctl_gpio_n: pctl-gpio-n {
				abilis,function = "gpion";
			};
			/* Unmuxed GPIOs */
			pctl_gpio_b: pctl-gpio-b {
				abilis,function = "gpiob";
			};
			pctl_gpio_d: pctl-gpio-d {
				abilis,function = "gpiod";
			};
			pctl_gpio_f: pctl-gpio-f {
				abilis,function = "gpiof";
			};
			pctl_gpio_h: pctl-gpio-h {
				abilis,function = "gpioh";
			};
			pctl_gpio_i: pctl-gpio-i {
				abilis,function = "gpioi";
			};
		};

		gpioa: gpio@ff140000 {
			compatible = "abilis,tb10x-gpio";
			interrupt-controller;
			#interrupt-cells = <1>;
			interrupt-parent = <&tb10x_ictl>;
			interrupts = <27 2>;
			reg = <0xff140000 0x1000>;
			gpio-controller;
			#gpio-cells = <2>;
			abilis,ngpio = <3>;
			gpio-ranges = <&iomux 0 0 0>;
			gpio-ranges-group-names = "gpioa";
		};
		gpiob: gpio@ff141000 {
			compatible = "abilis,tb10x-gpio";
			interrupt-controller;
			#interrupt-cells = <1>;
			interrupt-parent = <&tb10x_ictl>;
			interrupts = <27 2>;
			reg = <0xff141000 0x1000>;
			gpio-controller;
			#gpio-cells = <2>;
			abilis,ngpio = <2>;
			gpio-ranges = <&iomux 0 0 0>;
			gpio-ranges-group-names = "gpiob";
		};
		gpioc: gpio@ff142000 {
			compatible = "abilis,tb10x-gpio";
			interrupt-controller;
			#interrupt-cells = <1>;
			interrupt-parent = <&tb10x_ictl>;
			interrupts = <27 2>;
			reg = <0xff142000 0x1000>;
			gpio-controller;
			#gpio-cells = <2>;
			abilis,ngpio = <3>;
			gpio-ranges = <&iomux 0 0 0>;
			gpio-ranges-group-names = "gpioc";
		};
		gpiod: gpio@ff143000 {
			compatible = "abilis,tb10x-gpio";
			interrupt-controller;
			#interrupt-cells = <1>;
			interrupt-parent = <&tb10x_ictl>;
			interrupts = <27 2>;
			reg = <0xff143000 0x1000>;
			gpio-controller;
			#gpio-cells = <2>;
			abilis,ngpio = <2>;
			gpio-ranges = <&iomux 0 0 0>;
			gpio-ranges-group-names = "gpiod";
		};
		gpioe: gpio@ff144000 {
			compatible = "abilis,tb10x-gpio";
			interrupt-controller;
			#interrupt-cells = <1>;
			interrupt-parent = <&tb10x_ictl>;
			interrupts = <27 2>;
			reg = <0xff144000 0x1000>;
			gpio-controller;
			#gpio-cells = <2>;
			abilis,ngpio = <3>;
			gpio-ranges = <&iomux 0 0 0>;
			gpio-ranges-group-names = "gpioe";
		};
		gpiof: gpio@ff145000 {
			compatible = "abilis,tb10x-gpio";
			interrupt-controller;
			#interrupt-cells = <1>;
			interrupt-parent = <&tb10x_ictl>;
			interrupts = <27 2>;
			reg = <0xff145000 0x1000>;
			gpio-controller;
			#gpio-cells = <2>;
			abilis,ngpio = <2>;
			gpio-ranges = <&iomux 0 0 0>;
			gpio-ranges-group-names = "gpiof";
		};
		gpiog: gpio@ff146000 {
			compatible = "abilis,tb10x-gpio";
			interrupt-controller;
			#interrupt-cells = <1>;
			interrupt-parent = <&tb10x_ictl>;
			interrupts = <27 2>;
			reg = <0xff146000 0x1000>;
			gpio-controller;
			#gpio-cells = <2>;
			abilis,ngpio = <3>;
			gpio-ranges = <&iomux 0 0 0>;
			gpio-ranges-group-names = "gpiog";
		};
		gpioh: gpio@ff147000 {
			compatible = "abilis,tb10x-gpio";
			interrupt-controller;
			#interrupt-cells = <1>;
			interrupt-parent = <&tb10x_ictl>;
			interrupts = <27 2>;
			reg = <0xff147000 0x1000>;
			gpio-controller;
			#gpio-cells = <2>;
			abilis,ngpio = <2>;
			gpio-ranges = <&iomux 0 0 0>;
			gpio-ranges-group-names = "gpioh";
		};
		gpioi: gpio@ff148000 {
			compatible = "abilis,tb10x-gpio";
			interrupt-controller;
			#interrupt-cells = <1>;
			interrupt-parent = <&tb10x_ictl>;
			interrupts = <27 2>;
			reg = <0xff148000 0x1000>;
			gpio-controller;
			#gpio-cells = <2>;
			abilis,ngpio = <12>;
			gpio-ranges = <&iomux 0 0 0>;
			gpio-ranges-group-names = "gpioi";
		};
		gpioj: gpio@ff149000 {
			compatible = "abilis,tb10x-gpio";
			interrupt-controller;
			#interrupt-cells = <1>;
			interrupt-parent = <&tb10x_ictl>;
			interrupts = <27 2>;
			reg = <0xff149000 0x1000>;
			gpio-controller;
			#gpio-cells = <2>;
			abilis,ngpio = <32>;
			gpio-ranges = <&iomux 0 0 0>;
			gpio-ranges-group-names = "gpioj";
		};
		gpiok: gpio@ff14a000 {
			compatible = "abilis,tb10x-gpio";
			interrupt-controller;
			#interrupt-cells = <1>;
			interrupt-parent = <&tb10x_ictl>;
			interrupts = <27 2>;
			reg = <0xff14a000 0x1000>;
			gpio-controller;
			#gpio-cells = <2>;
			abilis,ngpio = <22>;
			gpio-ranges = <&iomux 0 0 0>;
			gpio-ranges-group-names = "gpiok";
		};
		gpiol: gpio@ff14b000 {
			compatible = "abilis,tb10x-gpio";
			interrupt-controller;
			#interrupt-cells = <1>;
			interrupt-parent = <&tb10x_ictl>;
			interrupts = <27 2>;
			reg = <0xff14b000 0x1000>;
			gpio-controller;
			#gpio-cells = <2>;
			abilis,ngpio = <4>;
			gpio-ranges = <&iomux 0 0 0>;
			gpio-ranges-group-names = "gpiol";
		};
		gpiom: gpio@ff14c000 {
			compatible = "abilis,tb10x-gpio";
			interrupt-controller;
			#interrupt-cells = <1>;
			interrupt-parent = <&tb10x_ictl>;
			interrupts = <27 2>;
			reg = <0xff14c000 0x1000>;
			gpio-controller;
			#gpio-cells = <2>;
			abilis,ngpio = <4>;
			gpio-ranges = <&iomux 0 0 0>;
			gpio-ranges-group-names = "gpiom";
		};
		gpion: gpio@ff14d000 {
			compatible = "abilis,tb10x-gpio";
			interrupt-controller;
			#interrupt-cells = <1>;
			interrupt-parent = <&tb10x_ictl>;
			interrupts = <27 2>;
			reg = <0xff14d000 0x1000>;
			gpio-controller;
			#gpio-cells = <2>;
			abilis,ngpio = <5>;
			gpio-ranges = <&iomux 0 0 0>;
			gpio-ranges-group-names = "gpion";
		};
	};
};


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Abilis Systems TB101 Development Kit PCB device tree
 *
 * Copyright (C) Abilis Systems 2013
 *
 * Author: Christian Ruppert <christian.ruppert@abilis.com>
 */

/dts-v1/;

/include/ "abilis_tb101.dtsi"

/ {
	model = "abilis,tb101";
	chosen {
		bootargs = "earlycon=uart8250,mmio32,0xff100000,9600n8 console=ttyS0,9600n8";
	};

	aliases { };

	memory {
		device_type = "memory";
		reg = <0x80000000 0x08000000>;	/* 128M */
	};

	soc100 {
		uart@ff100000 {
			pinctrl-names = "default";
			pinctrl-0 = <&pctl_uart0>;
		};
		ethernet@fe100000 {
			phy-mode = "rgmii";
		};

		i2c0: i2c@ff120000 {
			i2c-sda-hold-time-ns = <432>;
		};
		i2c1: i2c@ff121000 {
			i2c-sda-hold-time-ns = <432>;
		};
		i2c2: i2c@ff122000 {
			i2c-sda-hold-time-ns = <432>;
		};
		i2c3: i2c@ff123000 {
			i2c-sda-hold-time-ns = <432>;
		};
		i2c4: i2c@ff124000 {
			i2c-sda-hold-time-ns = <432>;
		};

		leds {
			compatible = "gpio-leds";
			power {
				label = "Power";
				gpios = <&gpioi 0 0>;
				linux,default-trigger = "default-on";
			};
			heartbeat {
				label = "Heartbeat";
				gpios = <&gpioi 1 0>;
				linux,default-trigger = "heartbeat";
			};
			led2 {
				label = "LED2";
				gpios = <&gpioi 2 0>;
				default-state = "off";
			};
			led3 {
				label = "LED3";
				gpios = <&gpioi 3 0>;
				default-state = "off";
			};
			led4 {
				label = "LED4";
				gpios = <&gpioi 4 0>;
				default-state = "off";
			};
			led5 {
				label = "LED5";
				gpios = <&gpioi 5 0>;
				default-state = "off";
			};
			led6 {
				label = "LED6";
				gpios = <&gpioi 6 0>;
				default-state = "off";
			};
			led7 {
				label = "LED7";
				gpios = <&gpioi 7 0>;
				default-state = "off";
			};
			led8 {
				label = "LED8";
				gpios = <&gpioi 8 0>;
				default-state = "off";
			};
			led9 {
				label = "LED9";
				gpios = <&gpioi 9 0>;
				default-state = "off";
			};
			led10 {
				label = "LED10";
				gpios = <&gpioi 10 0>;
				default-state = "off";
			};
			led11 {
				label = "LED11";
				gpios = <&gpioi 11 0>;
				default-state = "off";
			};
		};
	};
};