1/*
2 * tbicore.S
3 *
4 * Copyright (C) 2001, 2002, 2007, 2012 Imagination Technologies.
5 *
6 * This program is free software; you can redistribute it and/or modify it under
7 * the terms of the GNU General Public License version 2 as published by the
8 * Free Software Foundation.
9 *
10 * Core functions needed to support use of the thread binary interface for META
11 * processors
12 */
13
14	.file	"tbicore.S"
15/* Get data structures and defines from the TBI C header */
16#include <asm/metag_mem.h>
17#include <asm/metag_regs.h>
18#include <asm/tbx.h>
19
20	.data
21	.balign	8
22	.global	___pTBISegs
23	.type	___pTBISegs,object
24___pTBISegs:
25	.quad	0		/* Segment list pointer with it's */
26	.size	___pTBISegs,.-___pTBISegs
27					/* own id or spin-lock location */
28/*
29 * Return ___pTBISegs value specific to privilege level - not very complicated
30 * at the moment
31 *
32 * Register Usage: D0Re0 is the result, D1Re0 is used as a scratch
33 */
34	.text
35	.balign	4
36	.global	___TBISegList
37	.type	___TBISegList,function
38___TBISegList:
39	MOVT	A1LbP,#HI(___pTBISegs)
40	ADD	A1LbP,A1LbP,#LO(___pTBISegs)
41	GETL	D0Re0,D1Re0,[A1LbP]
42	MOV	PC,D1RtP
43	.size	___TBISegList,.-___TBISegList
44
45/*
46 * Search the segment list for a match given Id, pStart can be NULL
47 *
48 * Register Usage: D1Ar1 is pSeg, D0Ar2 is Id, D0Re0 is the result
49 *                 D0Ar4, D1Ar3 are used as a scratch
50 *                 NB: The PSTAT bit if Id in D0Ar2 may be toggled
51 */
52	.text
53	.balign	4
54	.global	___TBIFindSeg
55	.type	___TBIFindSeg,function
56___TBIFindSeg:
57	MOVT	A1LbP,#HI(___pTBISegs)
58	ADD	A1LbP,A1LbP,#LO(___pTBISegs)
59	GETL	D1Ar3,D0Ar4,[A1LbP]	/* Read segment list head */
60	MOV	D0Re0,TXSTATUS		/* What priv level are we at? */
61	CMP	D1Ar1,#0		/* Is pStart provided? */
62/* Disable privilege adaption for now */
63	ANDT	D0Re0,D0Re0,#0	/*HI(TXSTATUS_PSTAT_BIT)  ; Is PSTAT set? Zero if not */
64	LSL	D0Re0,D0Re0,#(TBID_PSTAT_S-TXSTATUS_PSTAT_S)
65	XOR	D0Ar2,D0Ar2,D0Re0	/* Toggle Id PSTAT if privileged */
66	MOVNZ	D1Ar3,D1Ar1		/* Use pStart if provided */
67$LFindSegLoop:
68	ADDS	D0Re0,D1Ar3,#0		/* End of list? Load result into D0Re0 */
69	MOVZ	PC,D1RtP		/* If result is NULL we leave */
70	GETL	D1Ar3,D0Ar4,[D1Ar3]	/* Read pLink and Id */
71	CMP	D0Ar4,D0Ar2		/* Does it match? */
72	BNZ	$LFindSegLoop		/* Loop if there is no match */
73	TST	D0Re0,D0Re0		/* Clear zero flag - we found it! */
74	MOV	PC,D1RtP		/* Return */
75	.size	___TBIFindSeg,.-___TBIFindSeg
76
77/* Useful offsets to encode the lower bits of the lock/unlock addresses */
78#define UON  (LINSYSEVENT_WR_ATOMIC_LOCK   & 0xFFF8)
79#define UOFF (LINSYSEVENT_WR_ATOMIC_UNLOCK & 0xFFF8)
80
81/*
82 * Perform a whole spin-lock sequence as used by the TBISignal routine
83 *
84 * Register Usage: D1Ar1 is pLock, D0Ar2 is Mask, D0Re0 is the result
85 *                 (All other usage due to ___TBIPoll - D0Ar6, D1Re0)
86 */
87	.text
88	.balign	4
89	.global	___TBISpin
90	.type	___TBISpin,function
91___TBISpin:
92	SETL	[A0StP++],D0FrT,D1RtP	/* Save our return address */
93	ORS	D0Re0,D0Re0,#1		/* Clear zero flag */
94	MOV	D1RtP,PC		/* Setup return address to form loop */
95$LSpinLoop:
96	BNZ	___TBIPoll		/* Keep repeating if fail to set */
97	GETL	D0FrT,D1RtP,[--A0StP]	/* Restore return address */
98	MOV	PC,D1RtP		/* Return */
99	.size	___TBISpin,.-___TBISpin
100
101/*
102 * Perform an attempt to gain access to a spin-lock and set some bits
103 *
104 * Register Usage: D1Ar1 is pLock, D0Ar2 is Mask, D0Re0 is the result
105 *                 !!On return Zero flag is SET if we are sucessfull!!
106 *                 A0.3 is used to hold base address of system event region
107 *                 D1Re0 use to hold TXMASKI while interrupts are off
108 */
109	.text
110	.balign	4
111	.global	___TBIPoll
112	.type	___TBIPoll,function
113___TBIPoll:
114	MOV	D1Re0,#0		/* Prepare to disable ints */
115	MOVT	A0.3,#HI(LINSYSEVENT_WR_ATOMIC_LOCK)
116	SWAP	D1Re0,TXMASKI		/* Really stop ints */
117	LOCK2				/* Gain all locks */
118	SET	[A0.3+#UON],D1RtP	/* Stop shared memory access too */
119	DCACHE	[D1Ar1],A0.3		/* Flush Cache line */
120	GETD	D0Re0,[D1Ar1]		/* Get new state from memory or hit */
121	DCACHE	[D1Ar1],A0.3		/* Flush Cache line */
122	GETD	D0Re0,[D1Ar1]		/* Get current state */
123	TST	D0Re0,D0Ar2		/* Are we clear to send? */
124	ORZ	D0Re0,D0Re0,D0Ar2	/* Yes: So set bits and */
125	SETDZ	[D1Ar1],D0Re0		/*      transmit new state */
126	SET	[A0.3+#UOFF],D1RtP	/* Allow shared memory access */
127	LOCK0				/* Release all locks */
128	MOV	TXMASKI,D1Re0		/* Allow ints */
129$LPollEnd:
130	XORNZ	D0Re0,D0Re0,D0Re0	/* No: Generate zero result */
131	MOV	PC,D1RtP		/* Return (NZ indicates failure) */
132	.size	___TBIPoll,.-___TBIPoll
133
134/*
135 * End of tbicore.S
136 */
137