/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 */

#include "ascend_platform.h"
#include "ascend_dev_num.h"
#include "ascend_kernel_hal.h"
#include "devdrv_hardware_version.h"
#include "ka_kernel_def_pub.h"
#include "ka_task_pub.h"
#include "pbl_spod_info.h"
#include "pbl_uda.h"
#include "pbl_soc_res_attr.h"
#include "pbl_soc_res.h"
#include "pbl_chip_config.h"
#include "uda_pub_def.h"

#ifdef DRV_HOST

static KA_TASK_DEFINE_SPINLOCK(dev_base_info_spinlock);
static struct dbl_dev_base_info g_dev_base_info[ASCEND_DEV_MAX_NUM] = {{U32_MAX, U32_MAX, U32_MAX, U32_MAX, 0}};

void dbl_set_dev_base_info(u32 dev_id, struct dbl_dev_base_info dev_base_info)
{
    if (dev_id >= ASCEND_DEV_MAX_NUM) {
        uda_err("Invalid device id. (dev_id=%u)\n", dev_id);
        return;
    }
    ka_task_spin_lock(&dev_base_info_spinlock);
    g_dev_base_info[dev_id].chip_id = dev_base_info.chip_id;
    g_dev_base_info[dev_id].die_id = dev_base_info.die_id;
    g_dev_base_info[dev_id].addr_mode = dev_base_info.addr_mode;
    g_dev_base_info[dev_id].multi_die = dev_base_info.multi_die;
    g_dev_base_info[dev_id].dev_ready = dev_base_info.dev_ready;
    ka_task_spin_unlock(&dev_base_info_spinlock);
}
KA_EXPORT_SYMBOL_GPL(dbl_set_dev_base_info);

void dbl_dev_base_info_init(u32 dev_id)
{
    if (dev_id >= ASCEND_DEV_MAX_NUM) {
        uda_err("Invalid device id. (dev_id=%u)\n", dev_id);
        return;
    }
    ka_task_spin_lock(&dev_base_info_spinlock);
    g_dev_base_info[dev_id].dev_ready = 0;
    ka_task_spin_unlock(&dev_base_info_spinlock);
}
KA_EXPORT_SYMBOL_GPL(dbl_dev_base_info_init);

struct dbl_dev_base_info *dbl_get_dev_base_info(u32 dev_id)
{
    struct dbl_dev_base_info *dev_base_info = NULL;

    if (dev_id >= ASCEND_DEV_MAX_NUM) {
        uda_err("Invalid device id. (dev_id=%u)\n", dev_id);
        return NULL;
    }
    ka_task_spin_lock(&dev_base_info_spinlock);
    if (g_dev_base_info[dev_id].dev_ready == 0) {
        return NULL;
    }
    dev_base_info = &g_dev_base_info[dev_id];
    ka_task_spin_unlock(&dev_base_info_spinlock);
    return dev_base_info;
}
KA_EXPORT_SYMBOL_GPL(dbl_get_dev_base_info);

int hal_kernel_get_device_chip_die_id(u32 dev_id, u32 *chip_id, u32 *die_id)
{
    struct dbl_dev_base_info *dev_base_info = NULL;

    if ((chip_id == NULL) ||
        (die_id == NULL) ||
        (!uda_is_udevid_exist(dev_id))) {
        uda_err("Invalid parameter. (dev_id=%u; chip_id=%s; die_id=%s)\n",
                dev_id, (chip_id == NULL) ? "NULL" : "OK", (die_id == NULL) ? "NULL" : "OK");
        return -EINVAL;
    }

    dev_base_info = dbl_get_dev_base_info(dev_id);
    if (dev_base_info == NULL) {
        uda_err("Device is not initialized. (dev_id=%u)\n", dev_id);
        return -EINVAL;
    }
    *chip_id = dev_base_info->chip_id;
    *die_id = dev_base_info->die_id;
    return 0;
}
KA_EXPORT_SYMBOL_GPL(hal_kernel_get_device_chip_die_id);

int hal_kernel_get_soc_type(u32 dev_id, u32 *soc_type)
{
    u32 chip_type;
    struct dbl_dev_base_info *dev_base_info = NULL;

    /*
     * soc type map from uda definition to hal kernel
     ****   uda chip type ******* hal soc type ******
     * HISI_MINI_V1  (0)          SOC_TYPE_MINI
     * HISI_CLOUD_V1 (1)          SOC_TYPE_CLOUD
     * HISI_MINI_V2  (2)          SOC_TYPE_DC
     * HISI_CLOUD_V2 (3)          SOC_TYPE_CLOUD_V2 or SOC_TYPE_CLOUD_V3
     * HISI_MINI_V3  (4)          SOC_TYPE_MINI_V3
     * HISI_CLOUD_V4 (6)          SOC_TYPE_CLOUD_V4
     * HISI_CLOUD_V5 (7)          SOC_TYPE_CLOUD_V5
     * HISI_CHIP_NUM (9)          SOC_TYPE_MAX
     * HISI_CHIP_UNKNOWN (10)      SOC_TYPE_MAX
     */
    u32 chip_type_map[HISI_CHIP_NUM] = {SOC_TYPE_MINI, SOC_TYPE_CLOUD, SOC_TYPE_DC,
                                        SOC_TYPE_CLOUD_V2, SOC_TYPE_MINI_V3, SOC_TYPE_RSVD_4, SOC_TYPE_CLOUD_V4, SOC_TYPE_CLOUD_V5, SOC_TYPE_RSVD_6};

    if ((soc_type == NULL) ||
        (!uda_is_udevid_exist(dev_id))) {
        uda_err("Invalid parameter. (dev_id=%u; soc_type=%s)\n",
                dev_id, (soc_type == NULL) ? "NULL" : "OK");
        return -EINVAL;
    }

    chip_type = uda_get_chip_type(dev_id);
    dev_base_info = dbl_get_dev_base_info(dev_id);
    if (dev_base_info == NULL) {
        uda_err("Device is not initialized. (dev_id=%u)\n", dev_id);
        return -EINVAL;
    }

    if (chip_type >= HISI_CHIP_NUM) {
        *soc_type = SOC_TYPE_MAX;
    }
    else if (chip_type == HISI_CLOUD_V2) {
        *soc_type = (dev_base_info->multi_die == 1) ? SOC_TYPE_CLOUD_V3 : CHIP_CLOUD_V2;
    }
    else {
        *soc_type = chip_type_map[chip_type];
    }

    return 0;
}
KA_EXPORT_SYMBOL_GPL(hal_kernel_get_soc_type);
#endif

int hal_kernel_get_device_addr_mode(u32 dev_id, HAL_KERNEL_ADDR_MODE *addr_mode)
{
#ifdef DRV_HOST
    struct dbl_dev_base_info *dev_base_info = NULL;
#else
    int ret;
    struct devdrv_hardware_info hardware_info = {0};
#endif

    if ((addr_mode == NULL) || (!uda_is_udevid_exist(dev_id))) {
        uda_err("Invalid parameter. (dev_id=%u; addr_mode=%s)\n",
                dev_id, (addr_mode == NULL) ? "NULL" : "OK");
        return -EINVAL;
    }

#ifdef DRV_HOST
    dev_base_info = dbl_get_dev_base_info(dev_id);
    if (dev_base_info == NULL) {
        uda_err("Device is not initialized. (dev_id=%u)\n", dev_id);
        return -EINVAL;
    }
    *addr_mode = (HAL_KERNEL_ADDR_MODE)dev_base_info->addr_mode;
#else
    ret = hal_kernel_get_hardware_info(dev_id, &hardware_info);
    if (ret != 0) {
        uda_err("Device is not initialized. (dev_id=%u)\n", dev_id);
        return -EINVAL;
    }
    *addr_mode = (HAL_KERNEL_ADDR_MODE)hardware_info.base_hw_info.addr_mode;
#endif
    return 0;
}
KA_EXPORT_SYMBOL_GPL(hal_kernel_get_device_addr_mode);

int __attribute__((weak)) hal_kernel_get_spod_node_status(u32 dev_id, u32 sdid, u32 *status)
{
    (void) dev_id;
    (void) sdid;
    (void) status;
    return -EOPNOTSUPP;
}
KA_EXPORT_SYMBOL_GPL(hal_kernel_get_spod_node_status);