/*
 * Copyright (c) 2016, NVIDIA CORPORATION.
 * Copright 2019, Data61
 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
 * ABN 41 687 119 230.
 *
 * This software may be distributed and modified according to the terms of
 * the GNU General Public License version 2. Note that NO WARRANTY is provided.
 * See "LICENSE_GPLv2.txt" for details.
 *
 * @TAG(DATA61_GPL)
 */

#include <assert.h>
#include <errno.h>
#include <stdbool.h>

#include <platsupport/pmem.h>
#include <tx2bpmp/hsp.h>
#include <utils/util.h>

/* Register holds information about the number of
 * shared mailboxes, shared semaphores etc. */
#define HSP_INT_DIMENSION_OFFSET 0x380
#define HSP_INT_DIMENSION_SM_SHIFT 0
#define HSP_INT_DIMENSION_SS_SHIFT 4
#define HSP_INT_DIMENSION_AS_SHIFT 8
#define HSP_INT_DIMENSION_NUM_MASK 0xf

#define HSP_DOORBELL_BLOCK_STRIDE 0x100

#define HSP_BITMAP_TZ_SECURE_SHFIT 0
#define HSP_BITMAP_TZ_NONSECURE_SHIFT 16

typedef struct tx2_hsp_priv {
    ps_io_ops_t *io_ops;
    void *hsp_base;
    void *doorbell_base;
} tx2_hsp_priv_t;

enum dbell_reg_offset {
    DBELL_TRIGGER = 0x0,
    DBELL_ENABLE = 0x4,
    DBELL_RAW = 0x8,
    DBELL_PENDING = 0xc
};

enum dbell_bitmap_offset {
    CCPLEX_BIT = BIT(1),
    DPMU_BIT = BIT(2),
    BPMP_BIT = BIT(3),
    SPE_BIT = BIT(4),
    CPE_BIT = BIT(5),
    SCE_BIT = CPE_BIT,
    DMA_BIT = BIT(6),
    TSECA_BIT = BIT(7),
    TSECB_BIT = BIT(8),
    JTAGM_BIT = BIT(9),
    CSITE_BIT = BIT(10),
    APE_BIT = BIT(11)
};

static pmem_region_t tx2_hsp_region = {
    .type = PMEM_TYPE_DEVICE,
    .base_addr = TX2_HSP_PADDR,
    .length = TX2_HSP_SIZE
};

static bool check_doorbell_id_is_valid(enum tx2_doorbell_id db_id)
{
    if (CCPLEX_PM_DBELL <= db_id && db_id <= APE_DBELL) {
        return true;
    }
    return false;
}

static uint32_t *hsp_get_doorbell_register(tx2_hsp_priv_t *hsp, enum tx2_doorbell_id db_id,
                                           enum dbell_reg_offset offset)
{
    assert(hsp);
    assert(DBELL_TRIGGER <= offset && offset <= DBELL_PENDING);
    return hsp->doorbell_base + db_id * HSP_DOORBELL_BLOCK_STRIDE + offset;
}

static int hsp_destroy(void *data)
{
    tx2_hsp_priv_t *hsp_priv = data;

    /* The doorbell base is just an offset from the hsp base, so we only need
     * to deallocate the hsp base */
    if (hsp_priv->hsp_base) {
        ps_io_unmap(&hsp_priv->io_ops->io_mapper, hsp_priv->hsp_base, tx2_hsp_region.length);
    }

    ps_io_ops_t *temp_ops = hsp_priv->io_ops;

    ZF_LOGF_IF(ps_free(&temp_ops->malloc_ops, sizeof(*hsp_priv), hsp_priv),
               "Failed to de-allocate the private data for HSP");

    return 0;
}

static int hsp_doorbell_ring(void *data, enum tx2_doorbell_id db_id)
{
    if (!check_doorbell_id_is_valid(db_id)) {
        ZF_LOGE("Invalid doorbell ID!");
        return -EINVAL;
    }

    tx2_hsp_priv_t *hsp_priv = data;

    /* Write any value to the trigger register to 'ring' the doorbell */
    uint32_t *trigger_reg = hsp_get_doorbell_register(hsp_priv, db_id, DBELL_TRIGGER);
    assert(trigger_reg);
    *trigger_reg = 1;

    return 0;
}

static int hsp_doorbell_check(void *data, enum tx2_doorbell_id db_id)
{
    if (!check_doorbell_id_is_valid(db_id)) {
        ZF_LOGE("Invalid doorbell ID!");
        return -EINVAL;
    }

    tx2_hsp_priv_t *hsp_priv = data;

    /* Checking if the doorbell has been 'rung' requires checking for proper
     * bit in the bitfield. The bitfield is also split into TrustZone secure
     * and TZ non-secure. Refer to Figure 75 in Section 14.8.5 for further details. */
    uint32_t *pending_reg = hsp_get_doorbell_register(hsp_priv, db_id, DBELL_PENDING);

    enum dbell_bitmap_offset bitmap_offset;
    switch (db_id) {
    case CCPLEX_PM_DBELL:
    case CCPLEX_TZ_UNSECURE_DBELL:
    case CCPLEX_TZ_SECURE_DBELL:
        bitmap_offset = CCPLEX_BIT;
        break;
    case BPMP_DBELL:
        bitmap_offset = BPMP_BIT;
        break;
    case SPE_DBELL:
        bitmap_offset = SPE_BIT;
        break;
    case SCE_DBELL:
        bitmap_offset = SCE_BIT;
        break;
    case APE_DBELL:
        bitmap_offset = APE_BIT;
        break;
    default:
        ZF_LOGF("We shouldn't get here, doorbell ID is %d", db_id);
    }

    /* Usermode isn't in TrustZone secure, so we just default to TZ non-secure */
    int is_pending = *pending_reg & (bitmap_offset << HSP_BITMAP_TZ_NONSECURE_SHIFT);

    if (is_pending) {
        *pending_reg &= ~(bitmap_offset << HSP_BITMAP_TZ_NONSECURE_SHIFT);
    }

    return (is_pending != 0);
}

int tx2_hsp_init(ps_io_ops_t *io_ops, tx2_hsp_t *hsp)
{
    if (!io_ops || !hsp) {
        ZF_LOGE("Arguments are NULL!");
        return -EINVAL;
    }

    int error = 0;

    tx2_hsp_priv_t *hsp_priv = NULL;
    error = ps_calloc(&io_ops->malloc_ops, 1, sizeof(*hsp_priv), (void **) &hsp_priv);
    if (error) {
        ZF_LOGE("Failed to allocate memory for private data for the HSP");
        return -ENOMEM;
    }

    hsp_priv->hsp_base = ps_pmem_map(io_ops, tx2_hsp_region, false, PS_MEM_NORMAL);
    if (!hsp_priv->hsp_base) {
        ZF_LOGE("Failed to map tx2 HSP module");
        ZF_LOGF_IF(ps_free(&io_ops->malloc_ops, sizeof(*hsp_priv), hsp_priv),
                   "Failed to clean-up after a failed initialisation for the HSP");
        return -ENOMEM;
    }

    /* Get the base addr of the doorbell
     * Section 14.8.5: All doorbell registers are in a single page, doorbell
     * {db} has a register range starting at DB{db}_BASE = HSP_{inst}_BASE +
     * (1+ nSM/2 + nSS + nAS) * 64 KiB + {db} * 0x100. */

    int num_sm = 0, num_ss = 0, num_as = 0;

    uint32_t *int_dim_reg = hsp_priv->hsp_base + HSP_INT_DIMENSION_OFFSET;

    num_sm = (*int_dim_reg >> HSP_INT_DIMENSION_SM_SHIFT) & HSP_INT_DIMENSION_NUM_MASK;
    num_ss = (*int_dim_reg >> HSP_INT_DIMENSION_SS_SHIFT) & HSP_INT_DIMENSION_NUM_MASK;
    num_as = (*int_dim_reg >> HSP_INT_DIMENSION_AS_SHIFT) & HSP_INT_DIMENSION_NUM_MASK;

    hsp_priv->doorbell_base = hsp_priv->hsp_base + (1 + (num_sm / 2) + num_ss + num_as) * 0x10000;
    hsp_priv->io_ops = io_ops;

    hsp->data = hsp_priv;
    hsp->ring = hsp_doorbell_ring;
    hsp->check = hsp_doorbell_check;
    hsp->destroy = hsp_destroy;

    return 0;
}
