#ifndef C665X_XMC_H
#define C665X_XMC_H

#include <stdint.h>

/* Some definitions for the extended memory controller */

/* We want to map logical addr 0x50000000 to 0x0C00000 (MSMC),
 * because then we can disable Caching and Prefetching */

#define MSMC_START_ADDR 0x0C000000
#define MSMC_ALIAS_ADDR 0x50000000
#define DDR3_START_ADDR 0x80000000
#define DDR3_END_ADDR   0x9FFFFFFF

/* Extended Memory Protection and Address Extension registers */

/* These map a 32 bit logical memory address to a 36 bit physical memory
 * address.
 * There are 16 reg pairs XMPAX{L,H} usable for mapping entries.
 * The first two (XMPAXL0, XMPAXH0, XMPAXL1, XMPAXH1) are set on reset and
 * remap the following:
 *
 * XMPAX{L,H}0:
 *  Logical 0x0C00'0000-0x7FFF'FFFF => Physical 0x0'0C00'0000-0x0'7FFF'FFFF
 *
 *  BADDR = 0x0000'0000 (Logical) => RADDR (physical) 0x0000'0000 [ << 1]
 *
 * XMPAX{L,H}1:
 *  Logical 0x8000'0000-0xFFFF'FFFF => Physical 0x8'0000'0000-0x8'7FFF'FFFF

 *  BADDR = 0x8000'0000 (logical) => RADDR (physical) 0x8000'0000 [ << 1 ]
 *
 *
 * The BADDR entry [XMPAXH 31:12] describes the upper bits of the
 * logical address, which is matched by the XMC on mem access.
 * The number of bits compared depends on the segment size!
 *
 * The RADDR entry [XMPAXL 31:8] describe the upper bits of the
 * physical address, hence 0x00C0'0000 means to 0x0C00'0000,
 * denoted by [ << 1] above
 *
 * NOTE: Higher numbered XMPAX{L,H} registers take precedence over
 * lower numbered if multiple matches occur for logical addresses.
 * */

 /* MPAXHn
  *
  * 31      28    24   20   16     12 11          5 4           0
  * |------------------------------------------------------------|
  * | BADDR (logical) bits 31..12    |   Reserved  |    SEGSZ    |
  * |------------------------------------------------------------|
  *
  * MPAXLn
  *
  * 31                                       8 7                0
  * |------------------------------------------------------------|
  * | RADDR (physical) bits 36..12            |        PERM      |
  * |------------------------------------------------------------|
*/

#define XMPAXL0 0x08000000
#define XMPAXH0 0x08000004

#define Reg volatile uint32_t *

#define XMPAXL_Reg(N) *((Reg)(XMPAXL0 + (8*(N))))
#define XMPAXH_Reg(N) *((Reg)(XMPAXH0 + (8*(N))))

/* Beware these are octal constants */
/* it is superuser rwx, user rwx */
/*    00rwxrwx   */
/*    00SSSUUU   */
#define XMC_PERM_RWXRWX 077
#define XMC_PERM_RW_RW_ 066
#define XMC_PERM_R__R__ 044

#define XMC_SEGSZ_1M 0x13 /* 1MB Size (LOG2(1048576) - 1) */

#define XMC_REMAP(n, logical, physical, size, perm) \
    XMPAXL_Reg(n) = (((physical) >> 4) & 0xFFFFFF00) | perm; \
    XMPAXH_Reg(n) = ((logical) &  0xFFFFF000) | size;


/* There are 256 Memory Attribute Registers, where the reg
 * number is given by the upper 8 bits of the logical address
 *
 * Every MAR only has two bits of interest
 *
 * Bit 0 = Enable Caching, Bit 3 = Enable Prefetching */

#define XMC_MAR 0x01848000
#define XMC_MAR_Reg(N) *((Reg)(XMC_MAR + (N * 4)))

#define XMC_MAR_PFX 0x08
#define XMC_MAR_PC  0x01

#define XMC_LADDR_TO_MAR(laddr) ((laddr) >> 24)


/* MSMC_ALIAS(X) takes a symbol as argument and returns the
 * alias address of this symbol */

/* ARE: actually this is strange, since we always take the difference
 * 0x50000000 - 0x0C000000 and add it to the symbol as the
 * Anti Alias Macro shows below */
#define MSMC_ALIAS(X)      (MSMC_ALIAS_ADDR + &(X))

/* MSMC_ANTI_ALIAS(A) is the opposite of ALIAS, except, the address
 * provided is relative to MSMC_START_ADDR */

#define MSMC_ALIAS_CORR (MSMC_ALIAS_ADDR - MSMC_START_ADDR)

#define MSMC_ANTI_ALIAS(A) ((A) - \
                       (((A) & 0xF0000000) == MSMC_ALIAS_ADDR ? \
                        MSMC_ALIAS_CORR : 0UL))

#endif
