/*
 * QEMU model of the XMPU Xilinx Memory Protection
 *
 * Copyright (c) 2020 Xilinx Inc.
 *
 * Autogenerated by xregqemu.py 2020-01-13.
 * Written by Joe Komlodi <komlodi@xilinx.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#ifndef XLNX_XMPU_H
#define XLNX_XMPU_H

#include "hw/register.h"

#ifndef XILINX_XMPU_ERR_DEBUG
#define XILINX_XMPU_ERR_DEBUG 0
#endif

/* Registers shared between all XMPUs */
REG32(CTRL, 0x0)
    FIELD(CTRL, ALIGNCFG, 3, 1)
    FIELD(CTRL, HIDEALLOWED, 2, 1)
    FIELD(CTRL, DEFWRALLOWED, 1, 1)
    FIELD(CTRL, DEFRDALLOWED, 0, 1)
REG32(ISR, 0x10)
    FIELD(ISR, SECURITYVIO, 3, 1)
    FIELD(ISR, WRPERMVIO, 2, 1)
    FIELD(ISR, RDPERMVIO, 1, 1)
    FIELD(ISR, INV_APB, 0, 1)
REG32(IMR, 0x14)
    FIELD(IMR, SECURITYVIO, 3, 1)
    FIELD(IMR, WRPERMVIO, 2, 1)
    FIELD(IMR, RDPERMVIO, 1, 1)
    FIELD(IMR, INV_APB, 0, 1)
REG32(IEN, 0x18)
    FIELD(IEN, SECURITYVIO, 3, 1)
    FIELD(IEN, WRPERMVIO, 2, 1)
    FIELD(IEN, RDPERMVIO, 1, 1)
    FIELD(IEN, INV_APB, 0, 1)
REG32(IDS, 0x1c)
    FIELD(IDS, SECURITYVIO, 3, 1)
    FIELD(IDS, WRPERMVIO, 2, 1)
    FIELD(IDS, RDPERMVIO, 1, 1)
    FIELD(IDS, INV_APB, 0, 1)
REG32(LOCK, 0x20)
    FIELD(LOCK, REGWRDIS, 0, 1)
REG32(ECO, 0xFC)

#define XMPU_VERSAL_R_MAX 0xA2
#define NR_XMPU_REGIONS 16
#define MAX_NR_MASTERS  8

#define XMPU_ENCLOSE_(...)  __VA_ARGS__  /* Suppress style-check error */

#define XMPU_COMMON_PROPS()  XMPU_ENCLOSE_(                \
    DEFINE_PROP_LINK("mr-0", XMPU, masters[0].parent_mr,   \
                     TYPE_MEMORY_REGION, MemoryRegion *),  \
    DEFINE_PROP_LINK("protected-mr", XMPU, protected_mr,   \
                     TYPE_MEMORY_REGION, MemoryRegion *),  \
    DEFINE_PROP_UINT64("protected-base", XMPU, cfg.base, 0))

typedef struct XMPU XMPU;

typedef struct XMPUMaster {
    XMPU *parent;

    AddressSpace *parent_as;
    MemoryRegion *parent_mr;
    uint64_t size;
    uint64_t base;

    MemoryRegion mr;
    IOMMUMemoryRegion iommu;

    struct {
        struct {
            AddressSpace as;
            MemoryRegion mr;
        } rw, ro, none;
    } down;

    struct {
        MemoryRegion mr[NR_XMPU_REGIONS];
    } err;
    uint8_t curr_region;
} XMPUMaster;

typedef struct XMPURegion {
    uint64_t start;
    uint64_t end;
    uint64_t size;
    union {
        uint32_t u32;
        struct {
            uint16_t mask;
            uint16_t id;
        };
    } master;
    struct {
        bool nschecktype;
        bool regionns;
        bool wrallowed;
        bool rdallowed;
        bool enable;
    } config;
} XMPURegion;

struct XMPU {
    SysBusDevice parent_obj;
    MemoryRegion iomem;

    MemoryRegion *protected_mr;

    /* Dynamically size this one based on attached masters.  */
    XMPUMaster masters[MAX_NR_MASTERS];
    qemu_irq irq_isr;

    struct {
        uint32_t nr_masters;
        /* Will go away with proper MRs.  */
        uint64_t base;

        bool align;
        bool poison;
    } cfg;

    /*
     * Register arrays need to be sized at compile time, so we will give it the
     * max size needed (Versal XMPU size) and store the actual size.
     */
    uint32_t regs[XMPU_VERSAL_R_MAX];
    RegisterInfo regs_info[XMPU_VERSAL_R_MAX];
    size_t regs_size;

    const char *prefix;
    bool enabled;
    bool dis_def_rw;
    qemu_irq enabled_signal;
    uint8_t addr_shift;
    uint64_t addr_mask;

    void (*decode_region)(XMPU *s, XMPURegion *xr, unsigned int region);
    bool (*match)(XMPU *s, XMPURegion *xr, uint16_t master_id, hwaddr addr);

    hwaddr (*regadr_translate)(struct XMPU *, hwaddr);
    char *regadr_variant;
};

void xmpu_update_enabled(XMPU *s);
void xmpu_flush(XMPU *s);
MemTxResult xmpu_read_common(void *opaque, XMPU *s, hwaddr addr, uint64_t *val,
                             unsigned size, MemTxAttrs attr);

MemTxResult xmpu_write_common(void *opaque, XMPU *s, hwaddr addr, uint64_t val,
                              unsigned size, MemTxAttrs attr);
int xmpu_attrs_to_index(IOMMUMemoryRegion *iommu, MemTxAttrs attrs);
int xmpu_num_indexes(IOMMUMemoryRegion *iommu);
IOMMUTLBEntry xmpu_master_translate(XMPUMaster *xm, hwaddr addr,
                                    bool attr_secure, uint16_t master_id,
                                    bool *sec_vio, int *perm);
IOMMUTLBEntry xmpu_translate(IOMMUMemoryRegion *mr, hwaddr addr,
                             IOMMUAccessFlags flags, int iommu_idx);
void xmpu_init_common(XMPU *s, Object *obj, const char *tn,
                      const MemoryRegionOps *ops,
                      const RegisterAccessInfo *regs_info, size_t regs_info_sz);
bool xmpu_parse_reg_common(XMPU *s, const char *tn, const char *iommu_tn,
                           const MemoryRegionOps *zero_ops,
                           FDTGenericRegPropInfo reg, FDTGenericMMap *obj,
                           Error **errp);

#endif
