13d4c7aa0SDavid du Colombier /*
23d4c7aa0SDavid du Colombier * arm co-processors
33d4c7aa0SDavid du Colombier * CP15 (system control) is the one that gets used the most in practice.
43d4c7aa0SDavid du Colombier */
53d4c7aa0SDavid du Colombier #include "u.h"
63d4c7aa0SDavid du Colombier #include "../port/lib.h"
73d4c7aa0SDavid du Colombier #include "mem.h"
83d4c7aa0SDavid du Colombier #include "dat.h"
93d4c7aa0SDavid du Colombier #include "fns.h"
103d4c7aa0SDavid du Colombier #include "io.h"
113d4c7aa0SDavid du Colombier
123d4c7aa0SDavid du Colombier #include "arm.h"
133d4c7aa0SDavid du Colombier
143d4c7aa0SDavid du Colombier #define MAP2PCSPACE(va, pc) ((uintptr)(va) & ~KSEGM | (pc) & KSEGM)
153d4c7aa0SDavid du Colombier
163d4c7aa0SDavid du Colombier enum {
173d4c7aa0SDavid du Colombier /* alternates: 0xe12fff1e BX (R14); last e is R14 */
183d4c7aa0SDavid du Colombier /* 0xe28ef000 B 0(R14); second e is R14 (ken) */
19*84860c5dSDavid du Colombier Retinst = 0xe1a0f00e, /* MOVW R14, R15 */
20*84860c5dSDavid du Colombier
21*84860c5dSDavid du Colombier Fpproc = 10, /* for vfp 3+; also 11 for doubles */
223d4c7aa0SDavid du Colombier };
233d4c7aa0SDavid du Colombier
243d4c7aa0SDavid du Colombier void
cpwr(int cp,int op1,int crn,int crm,int op2,ulong val)253d4c7aa0SDavid du Colombier cpwr(int cp, int op1, int crn, int crm, int op2, ulong val)
263d4c7aa0SDavid du Colombier {
273d4c7aa0SDavid du Colombier int s;
283d4c7aa0SDavid du Colombier volatile ulong instr[2];
293d4c7aa0SDavid du Colombier void *pcaddr;
303d4c7aa0SDavid du Colombier void (*fp)(ulong);
313d4c7aa0SDavid du Colombier
323d4c7aa0SDavid du Colombier s = splhi();
333d4c7aa0SDavid du Colombier op1 &= 7;
343d4c7aa0SDavid du Colombier op2 &= 7;
353d4c7aa0SDavid du Colombier crn &= 017;
363d4c7aa0SDavid du Colombier crm &= 017;
373d4c7aa0SDavid du Colombier cp &= 017;
383d4c7aa0SDavid du Colombier /* MCR. Rt will be R0. */
393d4c7aa0SDavid du Colombier instr[0] = 0xee000010 |
403d4c7aa0SDavid du Colombier op1 << 21 | crn << 16 | cp << 8 | op2 << 5 | crm;
413d4c7aa0SDavid du Colombier instr[1] = Retinst;
423d4c7aa0SDavid du Colombier coherence();
433d4c7aa0SDavid du Colombier
443d4c7aa0SDavid du Colombier pcaddr = (void *)MAP2PCSPACE(instr, getcallerpc(&cp));
453d4c7aa0SDavid du Colombier cachedwbse(pcaddr, sizeof instr);
463d4c7aa0SDavid du Colombier cacheiinv();
473d4c7aa0SDavid du Colombier
483d4c7aa0SDavid du Colombier fp = (void (*)(ulong))pcaddr;
493d4c7aa0SDavid du Colombier (*fp)(val);
503d4c7aa0SDavid du Colombier coherence();
513d4c7aa0SDavid du Colombier splx(s);
523d4c7aa0SDavid du Colombier }
533d4c7aa0SDavid du Colombier
543d4c7aa0SDavid du Colombier void
cpwrsc(int op1,int crn,int crm,int op2,ulong val)553d4c7aa0SDavid du Colombier cpwrsc(int op1, int crn, int crm, int op2, ulong val)
563d4c7aa0SDavid du Colombier {
573d4c7aa0SDavid du Colombier cpwr(CpSC, op1, crn, crm, op2, val);
583d4c7aa0SDavid du Colombier }
593d4c7aa0SDavid du Colombier
603d4c7aa0SDavid du Colombier ulong
cprd(int cp,int op1,int crn,int crm,int op2)613d4c7aa0SDavid du Colombier cprd(int cp, int op1, int crn, int crm, int op2)
623d4c7aa0SDavid du Colombier {
633d4c7aa0SDavid du Colombier int s;
643d4c7aa0SDavid du Colombier ulong res;
653d4c7aa0SDavid du Colombier volatile ulong instr[2];
663d4c7aa0SDavid du Colombier void *pcaddr;
673d4c7aa0SDavid du Colombier ulong (*fp)(void);
683d4c7aa0SDavid du Colombier
693d4c7aa0SDavid du Colombier s = splhi();
703d4c7aa0SDavid du Colombier op1 &= 7;
713d4c7aa0SDavid du Colombier op2 &= 7;
723d4c7aa0SDavid du Colombier crn &= 017;
733d4c7aa0SDavid du Colombier crm &= 017;
743d4c7aa0SDavid du Colombier /*
753d4c7aa0SDavid du Colombier * MRC. return value will be in R0, which is convenient.
763d4c7aa0SDavid du Colombier * Rt will be R0.
773d4c7aa0SDavid du Colombier */
783d4c7aa0SDavid du Colombier instr[0] = 0xee100010 |
793d4c7aa0SDavid du Colombier op1 << 21 | crn << 16 | cp << 8 | op2 << 5 | crm;
803d4c7aa0SDavid du Colombier instr[1] = Retinst;
813d4c7aa0SDavid du Colombier coherence();
823d4c7aa0SDavid du Colombier
833d4c7aa0SDavid du Colombier pcaddr = (void *)MAP2PCSPACE(instr, getcallerpc(&cp));
843d4c7aa0SDavid du Colombier cachedwbse(pcaddr, sizeof instr);
853d4c7aa0SDavid du Colombier cacheiinv();
863d4c7aa0SDavid du Colombier
873d4c7aa0SDavid du Colombier fp = (ulong (*)(void))pcaddr;
883d4c7aa0SDavid du Colombier res = (*fp)();
893d4c7aa0SDavid du Colombier splx(s);
903d4c7aa0SDavid du Colombier return res;
913d4c7aa0SDavid du Colombier }
923d4c7aa0SDavid du Colombier
933d4c7aa0SDavid du Colombier ulong
cprdsc(int op1,int crn,int crm,int op2)943d4c7aa0SDavid du Colombier cprdsc(int op1, int crn, int crm, int op2)
953d4c7aa0SDavid du Colombier {
963d4c7aa0SDavid du Colombier return cprd(CpSC, op1, crn, crm, op2);
973d4c7aa0SDavid du Colombier }
983d4c7aa0SDavid du Colombier
993d4c7aa0SDavid du Colombier /* floating point */
1003d4c7aa0SDavid du Colombier
1013d4c7aa0SDavid du Colombier ulong
fprd(int fpreg)1023d4c7aa0SDavid du Colombier fprd(int fpreg)
1033d4c7aa0SDavid du Colombier {
1043d4c7aa0SDavid du Colombier int s;
1053d4c7aa0SDavid du Colombier ulong res;
1063d4c7aa0SDavid du Colombier volatile ulong instr[2];
1073d4c7aa0SDavid du Colombier void *pcaddr;
1083d4c7aa0SDavid du Colombier ulong (*fp)(void);
1093d4c7aa0SDavid du Colombier
1103d4c7aa0SDavid du Colombier s = splhi();
1113d4c7aa0SDavid du Colombier fpreg &= 017;
1123d4c7aa0SDavid du Colombier /*
1133d4c7aa0SDavid du Colombier * VMRS. return value will be in R0, which is convenient.
1143d4c7aa0SDavid du Colombier * Rt will be R0.
1153d4c7aa0SDavid du Colombier */
116*84860c5dSDavid du Colombier instr[0] = 0xeef00010 | fpreg << 16 | 0 << 12 | Fpproc << 8;
1173d4c7aa0SDavid du Colombier instr[1] = Retinst;
1183d4c7aa0SDavid du Colombier coherence();
1193d4c7aa0SDavid du Colombier
1203d4c7aa0SDavid du Colombier pcaddr = (void *)MAP2PCSPACE(instr, getcallerpc(&fpreg));
1213d4c7aa0SDavid du Colombier cachedwbse(pcaddr, sizeof instr);
1223d4c7aa0SDavid du Colombier cacheiinv();
1233d4c7aa0SDavid du Colombier
1243d4c7aa0SDavid du Colombier fp = (ulong (*)(void))pcaddr;
1253d4c7aa0SDavid du Colombier res = (*fp)();
1263d4c7aa0SDavid du Colombier splx(s);
1273d4c7aa0SDavid du Colombier return res;
1283d4c7aa0SDavid du Colombier }
1293d4c7aa0SDavid du Colombier
1303d4c7aa0SDavid du Colombier void
fpwr(int fpreg,ulong val)1313d4c7aa0SDavid du Colombier fpwr(int fpreg, ulong val)
1323d4c7aa0SDavid du Colombier {
1333d4c7aa0SDavid du Colombier int s;
1343d4c7aa0SDavid du Colombier volatile ulong instr[2];
1353d4c7aa0SDavid du Colombier void *pcaddr;
1363d4c7aa0SDavid du Colombier void (*fp)(ulong);
1373d4c7aa0SDavid du Colombier
1383d4c7aa0SDavid du Colombier s = splhi();
1393d4c7aa0SDavid du Colombier fpreg &= 017;
1403d4c7aa0SDavid du Colombier /* VMSR. Rt will be R0. */
141*84860c5dSDavid du Colombier instr[0] = 0xeee00010 | fpreg << 16 | 0 << 12 | Fpproc << 8;
1423d4c7aa0SDavid du Colombier instr[1] = Retinst;
1433d4c7aa0SDavid du Colombier coherence();
1443d4c7aa0SDavid du Colombier
1453d4c7aa0SDavid du Colombier pcaddr = (void *)MAP2PCSPACE(instr, getcallerpc(&fpreg));
1463d4c7aa0SDavid du Colombier cachedwbse(pcaddr, sizeof instr);
1473d4c7aa0SDavid du Colombier cacheiinv();
1483d4c7aa0SDavid du Colombier
1493d4c7aa0SDavid du Colombier fp = (void (*)(ulong))pcaddr;
1503d4c7aa0SDavid du Colombier (*fp)(val);
1513d4c7aa0SDavid du Colombier coherence();
1523d4c7aa0SDavid du Colombier splx(s);
1533d4c7aa0SDavid du Colombier }
154