17bb09086SDavid du Colombier /*
27bb09086SDavid du Colombier * arm co-processors
37bb09086SDavid du Colombier * CP15 (system control) is the one that gets used the most in practice.
47bb09086SDavid du Colombier */
57bb09086SDavid du Colombier #include "u.h"
67bb09086SDavid du Colombier #include "../port/lib.h"
77bb09086SDavid du Colombier #include "mem.h"
87bb09086SDavid du Colombier #include "dat.h"
97bb09086SDavid du Colombier #include "fns.h"
107bb09086SDavid du Colombier #include "io.h"
117bb09086SDavid du Colombier
127bb09086SDavid du Colombier #include "arm.h"
137bb09086SDavid du Colombier
147bb09086SDavid du Colombier #define MAP2PCSPACE(va, pc) ((uintptr)(va) & ~KSEGM | (pc) & KSEGM)
157bb09086SDavid du Colombier
167bb09086SDavid du Colombier enum {
177bb09086SDavid du Colombier /* alternates: 0xe12fff1e BX (R14); last e is R14 */
187bb09086SDavid du Colombier /* 0xe28ef000 B 0(R14); second e is R14 (ken) */
197bb09086SDavid du Colombier Retinst = 0xe1a0f00e, /* MOV R14, R15 */
207bb09086SDavid du Colombier };
217bb09086SDavid du Colombier
227bb09086SDavid du Colombier void
cpwr(int cp,int op1,int crn,int crm,int op2,ulong val)237bb09086SDavid du Colombier cpwr(int cp, int op1, int crn, int crm, int op2, ulong val)
247bb09086SDavid du Colombier {
257bb09086SDavid du Colombier volatile ulong instr[2];
267bb09086SDavid du Colombier void *pcaddr;
277bb09086SDavid du Colombier void (*fp)(ulong);
287bb09086SDavid du Colombier
297bb09086SDavid du Colombier op1 &= 7;
307bb09086SDavid du Colombier op2 &= 7;
317bb09086SDavid du Colombier crn &= 017;
327bb09086SDavid du Colombier crm &= 017;
337bb09086SDavid du Colombier cp &= 017;
347bb09086SDavid du Colombier /* MCR. Rt will be R0. */
357bb09086SDavid du Colombier instr[0] = 0xee000010 |
367bb09086SDavid du Colombier op1 << 21 | crn << 16 | cp << 8 | op2 << 5 | crm;
377bb09086SDavid du Colombier instr[1] = Retinst;
387bb09086SDavid du Colombier
397bb09086SDavid du Colombier pcaddr = (void *)MAP2PCSPACE(instr, getcallerpc(&cp));
407bb09086SDavid du Colombier cachedwbse(pcaddr, sizeof instr);
417bb09086SDavid du Colombier cacheiinv();
427bb09086SDavid du Colombier
437bb09086SDavid du Colombier fp = (void (*)(ulong))pcaddr;
447bb09086SDavid du Colombier (*fp)(val);
457bb09086SDavid du Colombier coherence();
467bb09086SDavid du Colombier }
477bb09086SDavid du Colombier
487bb09086SDavid du Colombier void
cpwrsc(int op1,int crn,int crm,int op2,ulong val)497bb09086SDavid du Colombier cpwrsc(int op1, int crn, int crm, int op2, ulong val)
507bb09086SDavid du Colombier {
517bb09086SDavid du Colombier cpwr(CpSC, op1, crn, crm, op2, val);
527bb09086SDavid du Colombier }
537bb09086SDavid du Colombier
547bb09086SDavid du Colombier ulong
cprd(int cp,int op1,int crn,int crm,int op2)557bb09086SDavid du Colombier cprd(int cp, int op1, int crn, int crm, int op2)
567bb09086SDavid du Colombier {
577bb09086SDavid du Colombier volatile ulong instr[2];
587bb09086SDavid du Colombier void *pcaddr;
597bb09086SDavid du Colombier ulong (*fp)(void);
607bb09086SDavid du Colombier
617bb09086SDavid du Colombier op1 &= 7;
627bb09086SDavid du Colombier op2 &= 7;
637bb09086SDavid du Colombier crn &= 017;
647bb09086SDavid du Colombier crm &= 017;
657bb09086SDavid du Colombier /*
667bb09086SDavid du Colombier * MRC. return value will be in R0, which is convenient.
677bb09086SDavid du Colombier * Rt will be R0.
687bb09086SDavid du Colombier */
697bb09086SDavid du Colombier instr[0] = 0xee100010 |
707bb09086SDavid du Colombier op1 << 21 | crn << 16 | cp << 8 | op2 << 5 | crm;
717bb09086SDavid du Colombier instr[1] = Retinst;
727bb09086SDavid du Colombier
737bb09086SDavid du Colombier pcaddr = (void *)MAP2PCSPACE(instr, getcallerpc(&cp));
747bb09086SDavid du Colombier cachedwbse(pcaddr, sizeof instr);
757bb09086SDavid du Colombier cacheiinv();
767bb09086SDavid du Colombier
777bb09086SDavid du Colombier fp = (ulong (*)(void))pcaddr;
78*ad6b799dSDavid du Colombier return (*fp)();
797bb09086SDavid du Colombier }
807bb09086SDavid du Colombier
817bb09086SDavid du Colombier ulong
cprdsc(int op1,int crn,int crm,int op2)827bb09086SDavid du Colombier cprdsc(int op1, int crn, int crm, int op2)
837bb09086SDavid du Colombier {
847bb09086SDavid du Colombier return cprd(CpSC, op1, crn, crm, op2);
857bb09086SDavid du Colombier }
867bb09086SDavid du Colombier
877bb09086SDavid du Colombier /* floating point */
887bb09086SDavid du Colombier
897bb09086SDavid du Colombier ulong
fprd(int fpreg)907bb09086SDavid du Colombier fprd(int fpreg)
917bb09086SDavid du Colombier {
927bb09086SDavid du Colombier volatile ulong instr[2];
937bb09086SDavid du Colombier void *pcaddr;
947bb09086SDavid du Colombier ulong (*fp)(void);
957bb09086SDavid du Colombier
967bb09086SDavid du Colombier fpreg &= 017;
977bb09086SDavid du Colombier /*
987bb09086SDavid du Colombier * VMRS. return value will be in R0, which is convenient.
997bb09086SDavid du Colombier * Rt will be R0.
1007bb09086SDavid du Colombier */
1017bb09086SDavid du Colombier instr[0] = 0xeef00a10 | fpreg << 16 | 0 << 12;
1027bb09086SDavid du Colombier instr[1] = Retinst;
1037bb09086SDavid du Colombier coherence();
1047bb09086SDavid du Colombier
1057bb09086SDavid du Colombier pcaddr = (void *)MAP2PCSPACE(instr, getcallerpc(&fpreg));
1067bb09086SDavid du Colombier cachedwbse(pcaddr, sizeof instr);
1077bb09086SDavid du Colombier cacheiinv();
1087bb09086SDavid du Colombier
1097bb09086SDavid du Colombier fp = (ulong (*)(void))pcaddr;
110*ad6b799dSDavid du Colombier return (*fp)();
1117bb09086SDavid du Colombier }
1127bb09086SDavid du Colombier
1137bb09086SDavid du Colombier void
fpwr(int fpreg,ulong val)1147bb09086SDavid du Colombier fpwr(int fpreg, ulong val)
1157bb09086SDavid du Colombier {
1167bb09086SDavid du Colombier volatile ulong instr[2];
1177bb09086SDavid du Colombier void *pcaddr;
1187bb09086SDavid du Colombier void (*fp)(ulong);
1197bb09086SDavid du Colombier
1207bb09086SDavid du Colombier fpreg &= 017;
1217bb09086SDavid du Colombier /* VMSR. Rt will be R0. */
1227bb09086SDavid du Colombier instr[0] = 0xeee00a10 | fpreg << 16 | 0 << 12;
1237bb09086SDavid du Colombier instr[1] = Retinst;
1247bb09086SDavid du Colombier coherence();
1257bb09086SDavid du Colombier
1267bb09086SDavid du Colombier pcaddr = (void *)MAP2PCSPACE(instr, getcallerpc(&fpreg));
1277bb09086SDavid du Colombier cachedwbse(pcaddr, sizeof instr);
1287bb09086SDavid du Colombier cacheiinv();
1297bb09086SDavid du Colombier
1307bb09086SDavid du Colombier fp = (void (*)(ulong))pcaddr;
1317bb09086SDavid du Colombier (*fp)(val);
1327bb09086SDavid du Colombier coherence();
1337bb09086SDavid du Colombier }
134