/*
* Copyright (c) 2014 - 2016 MediaTek Inc.
*
* 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 __MT_DRV_FWK_H__
#define __MT_DRV_FWK_H__

#include <core/driver.h>
#include <drv_defs.h>
#include <errno.h>
#include <limits.h>
#include <print_no_alloc.h>
#include <stdio.h>
#include <tee_interrupt.h>


/* Callbacks that should be defined in secure driver */
struct msee_drv_device {
    unsigned char name[32];
    unsigned int driver_id;
    int (*init)(const struct msee_drv_device *dev);
    int (*invoke_command)(unsigned int sid, unsigned int cmd, unsigned long args);
    int (*ree_command)(unsigned int cmd, unsigned long args);
    int (*open_session)(unsigned int sid, unsigned long args);
    int (*close_session)(unsigned int sid);
};
typedef struct msee_drv_device msee_drv_device_t;

enum tdriver_state {
    INIT = 0,
    TEE_ONLY,
    REE_TO_TEE,
    TEE_TO_REE,
};

enum tdriver_mode {
    READY = 0,
    IOCTL_KERNEL_CMD,
};

enum tdriver_cmd {
    MAP_IWSHMEM = 0,
    UNMAP_IWSHMEM,
    REE_COMMAND,
    TEE_COMMAND,
};

struct tdriver_device {
    enum tdriver_state my_driver_state;
    enum tdriver_mode my_driver_mode;
    struct drv_info *my_drv_info;
    void *iwshmem;
    size_t iwshmem_size;
    unsigned int iwnotify_flag;
};

struct tdriver_msg {
    uint32_t cmd;
    uint32_t arg;
    int32_t iwshmem_id;
    int32_t result;
};

#define MSEE_IOCTL_RANGE 4096
#define MSEE_IOCTL_SHIFT (INT_MIN + MSEE_IOCTL_RANGE)

/* System API of driver framework */

/* Memory API of driver framework */
#define MSEE_MAP_READABLE            (1U << 0) /* read access attribute */
#define MSEE_MAP_WRITABLE            (1U << 1) /* write access attribute */
#define MSEE_MAP_EXECUTABLE          (1U << 2) /* program execution attribute */
#define MSEE_MAP_UNCACHED            (1U << 3) /* uncached memory access attribute */
#define MSEE_MAP_IO                  (1U << 4) /* device memory attribute */
#define MSEE_MAP_ALLOW_NONSECURE     (1U << 7) /* non-secure attribute, used only to map client task buffers using msee_map_user */
#define MSEE_MAP_HARDWARE            (MSEE_MAP_READABLE | MSEE_MAP_WRITABLE | MSEE_MAP_IO)
#define MSEE_MAP_USER_DEFAULT        (MSEE_MAP_READABLE | MSEE_MAP_WRITABLE | MSEE_MAP_ALLOW_NONSECURE)
void msee_clean_dcache_all(void);
void msee_clean_invalidate_dcache_all(void);
void msee_clean_dcache_range(unsigned long addr, unsigned long size);
void msee_clean_invalidate_dcache_range(unsigned long addr, unsigned long size);
MSEE_Result msee_map_user(void **to, const void *from, unsigned long size, unsigned int flags);
MSEE_Result msee_unmap_user(void *to);
MSEE_Result msee_mmap_region(unsigned long long pa, void **va, unsigned long size, unsigned int flags);
MSEE_Result msee_unmmap_region(void *va, unsigned long size);
void* msee_malloc(unsigned long size);
void* msee_realloc(void *buf, unsigned long size);
void msee_free(void *buf);

/* Thread API of driver framework */

/* Interrupt API of driver framework */
#define MSEE_INTR_MODE_MASK_TRIGGER     (1U<<0)
#define MSEE_INTR_MODE_TRIGGER_LEVEL        MSEE_INTR_MODE_MASK_TRIGGER
#define MSEE_INTR_MODE_TRIGGER_EDGE     0
#define MSEE_INTR_MODE_MASK_CONDITION       (1U<<1)
#define MSEE_INTR_MODE_CONDITION_FALLING    MSEE_INTR_MODE_MASK_CONDITION
#define MSEE_INTR_MODE_CONDITION_LOW        MSEE_INTR_MODE_MASK_CONDITION
#define MSEE_INTR_MODE_CONDITION_RISING     0
#define MSEE_INTR_MODE_CONDITION_HIGH       0
#define MSEE_INTR_MODE_RAISING_EDGE     (MSEE_INTR_MODE_TRIGGER_EDGE | MSEE_INTR_MODE_CONDITION_RISING)
#define MSEE_INTR_MODE_FALLING_EDGE     (MSEE_INTR_MODE_TRIGGER_EDGE | MSEE_INTR_MODE_CONDITION_FALLING)
#define MSEE_INTR_MODE_LOW_LEVEL        (MSEE_INTR_MODE_TRIGGER_LEVEL | MSEE_INTR_MODE_CONDITION_LOW)
#define MSEE_INTR_MODE_HIGH_LEVEL       (MSEE_INTR_MODE_TRIGGER_LEVEL | MSEE_INTR_MODE_CONDITION_HIGH)
enum MSEE_IRQ_STATUS {
    MSEE_IRQ_TIMEOUT = -1,
    MSEE_IRQ_FAIL = -2,
    MSEE_IRQ_MAX_ERROR = 0xFFFFFFFF,
};
/* typedef void (*msee_irq_handler_t)(struct intrinfo *); */
typedef int (*msee_irq_handler_t)(int, void *);
MSEE_Result msee_request_irq(unsigned int irq, msee_irq_handler_t handler, unsigned long flags, unsigned int timeout_ms /*ms*/, void *data);
void msee_free_irq(unsigned int irq);
MSEE_Result msee_wait_for_irq_complete(void);

/* IPC API of driver framework */
void* msee_get_ree_shared_msg(void);
int msee_notify_ree(void);

/* Log API of driver framework */
void msee_printf(const char *format, ...);

#if defined(__INCLUDE_DEBUG) || defined(DEBUG)
    #define msee_logd(...)  msee_printf(__VA_ARGS__)    /* debug message */
    #define msee_loge(...)  msee_printf(__VA_ARGS__)    /* error message */
#else
    #define msee_logd(...)  do{}while(0)                /* debug message */
    #define msee_loge(...)  msee_printf(__VA_ARGS__)    /* error message */
#endif // __INCLUDE_DEBUG

#if 0
int mtee_vprintf(const char *format, va_list ap);
#define mtee_dbg_vprintf mtee_printf(__VA_ARGS__)
#define mtee_dbg_printf mtee_printf(__VA_ARGS__)
#endif

/* Time API of driver framework */
struct msee_time {
    unsigned int s;
    unsigned int ms;
};
typedef struct msee_time msee_time_t;
void msee_get_system_time(msee_time_t *time);

/* Utils API of driver framework */
char* msee_strncpy(char *dest, const char *src, unsigned long n);
unsigned long msee_strlen(const char *str);
void *msee_memcpy(void *dest, const void *src, unsigned long n);
void *msee_memset(void *s, int c, unsigned long n);
//TODO: if we need smc call interface, need to ask TEEgris team to provide header/lib
#if 1
/* SMC Call API */
int msee_smc_call(uint32_t smc_nr, uint32_t args0, uint32_t args1,
                  uint32_t args2, uint32_t *smc_ret);
#endif
/* Platform API of driver framework */
unsigned int msee_get_chip_hw_code(void);

#if 0
/* defined in common/hal/.../mpu/... */
int msee_set_emi_mpu_protection(unsigned long long start, unsigned long long end, int region, unsigned int access_permission);

#define MSEE_SET_ACCESS_PERMISSON(lock, d7, d6, d5, d4, d3, d2, d1, d0) (((d7) << 21) | ((d6) << 18) | ((d5) << 15) | ((d4) << 12) | ((d3) << 9) | ((d2) << 6) | ((d1) << 3) | (d0) | (lock << 31))
#define MSEE_SHARED_SECURE_MEMORY_MPU_REGION_ID  2
#define MSEE_TUI_MEMORY_MPU_REGION_ID  3

#define MSEE_EMI_MPU_LOCK                1
#define MSEE_EMI_MPU_UNLOCK              0

#define MSEE_EMI_MPU_NO_PROTECTION       0
#define MSEE_EMI_MPU_SEC_RW              1
#define MSEE_EMI_MPU_SEC_RW_NSEC_R       2
#define MSEE_EMI_MPU_SEC_RW_NSEC_W       3
#define MSEE_EMI_MPU_SEC_R_NSEC_R        4
#define MSEE_EMI_MPU_FORBIDDEN           5
#define MSEE_EMI_MPU_SEC_R_NSEC_RW       6

int msee_4g_enabled(void);
#define INTERAL_MAPPING_OFFSET (0x40000000)
#define INTERAL_MAPPING_LIMIT (INTERAL_MAPPING_OFFSET + 0x80000000)

#define MAPPING_DRAM_ACCESS_ADDR(phy_addr) \
    do { \
        if (msee_4g_enabled()) {\
            if (phy_addr >= INTERAL_MAPPING_OFFSET && phy_addr < INTERAL_MAPPING_LIMIT) \
                phy_addr += INTERAL_MAPPING_OFFSET; \
            } \
    } while (0)\

#endif
/* end of msee_set_emi_mpu_* related definitions */

#define DUMMY_FUNTIONS

#ifdef DUMMY_FUNTIONS
/* Dummy Functions */
#define THREADID_TO_TASKID(...) 0
//#define drApiLogPrintf(fmt, ...) msee_printf((fmt), ##__VA_ARGS__)
#define drApiLogPrintf msee_printf
#define drDbgvPrintf(...)
#define drDbgPrintf(...)
#define drApiMapTaskBuffer(...) 0
#define drApiUnmapTaskBuffers(...)
#define drApiIpcUnknownMessage(...)
#define drApiIpcCallToIPCH(...) 0
#define drApiExtractMsgCmd(...) 0
#define drApiGetTaskid() 0
#define drApiIpcSignal(a) (a)
#define drApiTaskidGetThreadid(a, b) (a)
#define drApiIpcSigWait() 0
#define drApiCacheDataCleanAll(...)
#define drApiCacheDataCleanInvalidateAll(...)
#define drApiCacheDataCleanRange(...)
#define drApiCacheDataCleanInvalidateRange(...)
#define drApiMapPhysicalBuffer(...) 0
#define drApiUnmapBuffer(...)
#define drApiMalloc(...) 0
#define drApiRealloc(...) 0
#define drApiFree(...)
#define drApiStartThread(...) 0
#define drApiGetSecureTimestamp(...)
#define drApiIntrDetach(a) (a)
#define drApiGetLocalThreadid(a) (a)

#endif /* DUMMY_FUNTIONS */

#endif //__MT_DRV_FWK_H__

