/*
* Time.
*
* HZ should divide 1000 evenly, ideally.
* 100, 125, 200, 250 and 333 are okay.
*/
#define HZ              100                     /* clock frequency */
#define MS2HZ           (1000/HZ)               /* millisec per clock tick */
#define TK2SEC(t)       ((t)/HZ)                /* ticks to seconds */

enum {
       Mhz     = 1000 * 1000,
       Dogsectimeout = 4,              /* must be ≤ 34 s. to fit in a ulong */
};

/*
* More accurate time
*/
#define MS2TMR(t)       ((ulong)(((uvlong)(t) * m->cpuhz)/1000))
#define US2TMR(t)       ((ulong)(((uvlong)(t) * m->cpuhz)/1000000))

#define CONSOLE 0

typedef struct Conf     Conf;
typedef struct Confmem  Confmem;
typedef struct FPsave   FPsave;
typedef struct PFPU     PFPU;
typedef struct ISAConf  ISAConf;
typedef struct Isolated Isolated;
typedef struct Label    Label;
typedef struct Lock     Lock;
typedef struct Lowmemcache Lowmemcache;
typedef struct Memcache Memcache;
typedef struct MMMU     MMMU;
typedef struct Mach     Mach;
typedef u32int Mreg;                            /* Msr - bloody UART */
typedef struct Page     Page;
typedef struct Pcisiz Pcisiz;
typedef struct Pcidev Pcidev;
typedef struct PhysUart PhysUart;
typedef struct PMMU     PMMU;
typedef struct Proc     Proc;
typedef u32int          PTE;
typedef struct Soc      Soc;
typedef struct Uart     Uart;
typedef struct Ureg     Ureg;
typedef uvlong          Tval;

#pragma incomplete Pcidev
#pragma incomplete Ureg

#define MAXSYSARG       5       /* for mount(fd, mpt, flag, arg, srv) */

/*
*  parameters for sysproc.c
*/
#define AOUT_MAGIC      (E_MAGIC)

struct Lock
{
       ulong   key;
       u32int  sr;
       uintptr pc;
       Proc*   p;
       Mach*   m;
       int     isilock;
};

struct Label
{
       uintptr sp;
       uintptr pc;
};

/*
* emulated or vfp3 floating point
*/
enum {
       Maxfpregs       = 32,   /* could be 16 or 32, see Mach.fpnregs */
       Nfpctlregs      = 16,
};

struct FPsave
{
       ulong   status;
       ulong   control;
       /*
        * vfp3 with ieee fp regs; uvlong is sufficient for hardware but
        * each must be able to hold an Internal from fpi.h for sw emulation.
        */
       ulong   regs[Maxfpregs][3];

       int     fpstate;
       uintptr pc;             /* of failed fp instr. */
};

struct PFPU
{
       int     fpstate;
       FPsave  fpsave[1];
};

enum
{
       FPinit,
       FPactive,
       FPinactive,
       FPemu,

       /* bit or'd with the state */
       FPillegal= 0x100,
};

struct Confmem
{
       uintptr base;
       usize   npage;
       uintptr limit;
       uintptr kbase;
       uintptr klimit;
};

struct Conf
{
       ulong   nmach;          /* processors */
       ulong   nproc;          /* processes */
       Confmem mem[1];         /* physical memory */
       ulong   npage;          /* total physical pages of memory */
       usize   upages;         /* user page pool */
       ulong   copymode;       /* 0 is copy on write, 1 is copy on reference */
       ulong   ialloc;         /* max interrupt time allocation in bytes */
       ulong   pipeqsize;      /* size in bytes of pipe queues */
       ulong   nimage;         /* number of page cache image headers */
       ulong   nswap;          /* number of swap pages */
       int     nswppo;         /* max # of pageouts per segment pass */
       ulong   hz;             /* processor cycle freq */
       ulong   mhz;
       int     monitor;        /* flag */
};

/*
*  MMU stuff in Mach.
*/
struct MMMU
{
       PTE*    mmul1;          /* l1 for this processor */
       int     mmul1lo;
       int     mmul1hi;
       int     mmupid;
};

/*
*  MMU stuff in proc
*/
#define NCOLOR  1               /* 1 level cache, don't worry about VCE's */
struct PMMU
{
       Page*   mmul2;
       Page*   mmul2cache;     /* free mmu pages */
};

#include "../port/portdat.h"

struct Mach
{
       /* offsets known to asm */
       int     machno;                 /* physical id of processor */
       uintptr splpc;                  /* pc of last caller to splhi */

       Proc*   proc;                   /* current process */

       MMMU;
       /* end of offsets known to asm */
       int     flushmmu;               /* flush current proc mmu state */

       ulong   ticks;                  /* of the clock since boot time */
       Label   sched;                  /* scheduler wakeup */
       Lock    alarmlock;              /* access to alarm list */
       void*   alarm;                  /* alarms bound to this clock */
       int     inclockintr;

       Proc*   readied;                /* for runproc */
       ulong   schedticks;             /* next forced context switch */

       int     cputype;
       ulong   delayloop;

       /* stats */
       int     tlbfault;
       int     tlbpurge;
       int     pfault;
       int     cs;
       int     syscall;
       int     load;
       int     intr;
       uvlong  fastclock;              /* last sampled value */
       uvlong  inidle;                 /* time spent in idlehands() */
       ulong   spuriousintr;
       int     lastintr;
       int     ilockdepth;
       Perf    perf;                   /* performance counters */

       int     probing;                /* probeaddr() state */
       int     trapped;
       Lock    probelock;
       int     inidlehands;

       int     cpumhz;
       uvlong  cpuhz;                  /* speed of cpu */
       uvlong  cyclefreq;              /* Frequency of user readable cycle counter */

       /* vfp3 fpu */
       int     havefp;
       int     havefpvalid;
       int     fpon;
       int     fpconfiged;
       int     fpnregs;
       ulong   fpscr;                  /* sw copy */
       int     fppid;                  /* pid of last fault */
       uintptr fppc;                   /* addr of last fault */
       int     fpcnt;                  /* how many consecutive at that addr */

       /* save areas for exceptions, hold R0-R4 */
       u32int  sfiq[5];
       u32int  sirq[5];
       u32int  sund[5];
       u32int  sabt[5];
       u32int  smon[5];                /* probably not needed */
       u32int  ssys[5];

       int     stack[1];
};

/*
* Fake kmap.
*/
typedef void            KMap;
#define VA(k)           ((uintptr)(k))
#define kmap(p)         (KMap*)((p)->pa|kseg0)
#define kunmap(k)

struct
{
       Lock;
       char    machs[MAXMACH];         /* active CPUs */
       int     wfi;                    /* bitmap of CPUs in WFI state */
       int     stopped;                /* bitmap of CPUs stopped */
       int     exiting;                /* shutdown */
}active;

extern register Mach* m;                        /* R10 */
extern register Proc* up;                       /* R9 */

/* an object guaranteed to be in its own cache line */
typedef uchar Cacheline[CACHELINESZ];
struct Isolated {
       Cacheline c0;
       ulong   word;
       Cacheline c1;
};

extern Memcache cachel[];               /* arm arch v7 supports 1-7 */
extern ulong intrcount[MAXMACH];
extern int irqtooearly;
extern uintptr kseg0;
extern Isolated l1ptstable;
extern uchar *l2pages;
extern Mach* machaddr[MAXMACH];
extern ulong memsize;
extern int navailcpus;
extern int normalprint;

/*
*  a parsed plan9.ini line
*/
#define NISAOPT         8

struct ISAConf {
       char    *type;
       ulong   port;
       int     irq;
       ulong   dma;
       ulong   mem;
       ulong   size;
       ulong   freq;

       int     nopt;
       char    *opt[NISAOPT];
};

#define MACHP(n) machaddr[n]

/*
* Horrid. But the alternative is 'defined'.
*/
#ifdef _DBGC_
#define DBGFLG          (dbgflg[_DBGC_])
#else
#define DBGFLG          (0)
#endif /* _DBGC_ */

int vflag;
extern char dbgflg[256];

#define dbgprint        print           /* for now */

/*
*  hardware info about a device
*/
typedef struct {
       ulong   port;
       int     size;
} Devport;

struct DevConf
{
       ulong   intnum;                 /* interrupt number */
       char    *type;                  /* card type, malloced */
       int     nports;                 /* Number of ports */
       Devport *ports;                 /* The ports themselves */
};

/* characteristics of a given arm cache level */
struct Memcache {
       uint    waysh;          /* shifts for set/way register */
       uint    setsh;

       uint    log2linelen;

       uint    level;          /* 1 is nearest processor, 2 further away */
       uint    type;
       uint    external;       /* flag */
       uint    l1ip;           /* l1 I policy */

       uint    nways;          /* associativity */
       uint    nsets;
       uint    linelen;        /* bytes per cache line */
       uint    setsways;
};
enum Cachetype {
       Nocache,
       Ionly,
       Donly,
       Splitid,
       Unified,
};
enum {
       Intcache,
       Extcache,
};

/*
* characteristics of cache level, kept at low, fixed address (CACHECONF).
* all offsets are known to cache.v7.s.
*/
struct Lowmemcache {
       uint    l1waysh;                /* shifts for set/way register */
       uint    l1setsh;
       uint    l2waysh;
       uint    l2setsh;
};

/*
* cache capabilities.  write-back vs write-through is controlled
* by the Buffered bit in PTEs.
*
* see cache.v7.s and Memcache in dat.h
*/
enum {
       Cawt    = 1 << 31,
       Cawb    = 1 << 30,
       Cara    = 1 << 29,
       Cawa    = 1 << 28,
};

/* non-architectural L2 cache */
typedef struct Cacheimpl Cacheimpl;
struct Cacheimpl {
       void    (*info)(Memcache *);
       void    (*on)(void);
       void    (*off)(void);

       void    (*inv)(void);
       void    (*wb)(void);
       void    (*wbinv)(void);

       void    (*invse)(void *, int);
       void    (*wbse)(void *, int);
       void    (*wbinvse)(void *, int);
};
/* extern */ Cacheimpl *l2cache, *allcache, *nocache, *l1cache;

enum Dmamode {
       Const,
       Postincr,
       Index,
       Index2,
};

/* pmu = power management unit */
enum Irqs {
       /*
        * 1st 32 gic irqs reserved for cpu; private interrupts.
        *  0—15 are software-generated by other cpus;
        * 16—31 are private peripheral intrs.
        */
       Cpu0irq         = 0,
       Cpu1irq,
       /* ... */
       Cpu15irq        = 15,
       Glbtmrirq       = 27,
       Loctmrirq       = 29,
       Wdtmrirq        = 30,

       /* shared interrupts */
       Ctlr0base       = (1+0)*32,             /* primary ctlr */
       Tn0irq          = Ctlr0base + 0,        /* tegra timers */
       Tn1irq          = Ctlr0base + 1,
       Rtcirq          = Ctlr0base + 2,

       Ctlr1base       = (1+1)*32,             /* secondary ctlr */
       Uartirq         = Ctlr1base + 4,
       Tn2irq          = Ctlr1base + 9,        /* tegra timers */
       Tn3irq          = Ctlr1base + 10,
       /* +24 is cpu0_pmu_intr, +25 is cpu1_pum_intr */

       Ctlr2base       = (1+2)*32,             /* ternary ctlr */
       Extpmuirq       = Ctlr2base + 22,

       Ctlr3base       = (1+3)*32,             /* quad ctlr */
       Pcieirq         = Ctlr3base + 2,
};

struct Soc {                    /* addr's of SoC controllers */
       uintptr clkrst;
       uintptr power;
       uintptr exceptvec;
       uintptr sema;
       uintptr l2cache;
       uintptr flow;

       /* private memory region */
       uintptr scu;
       uintptr intr;           /* `cpu interface' */
       /* private-peripheral-interrupt cortex-a clocks */
       uintptr glbtmr;
       uintptr loctmr;

       uintptr intrdist;

       uintptr uart[5];

       /* shared-peripheral-interrupt tegra2 clocks */
       uintptr rtc;            /* real-time clock */
       uintptr tmr[4];
       uintptr µs;

       uintptr pci;
       uintptr ether;

       uintptr ehci;
       uintptr ide;

       uintptr nand;
       uintptr nor;

       uintptr spi[4];
       uintptr twsi;
       uintptr mmc[4];
       uintptr gpio[7];
} soc;
extern Soc soc;