-- Copyright (c) 2024 Huawei Technologies Co., Ltd.
-- openUBMC is licensed under Mulan PSL v2.
-- You can use this software according to the terms and conditions of the Mulan PSL v2.
-- You may obtain a copy of Mulan PSL v2 at: http://license.coscl.org.cn/MulanPSL2
-- THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
-- EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
-- MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
-- See the Mulan PSL v2 for more details.

local ipmi = require 'ipmi'
local bs = require 'mc.bitstring'
local log = require 'mc.logging'
local enums = require 'mc.ipmi.enums'
local imu_cmd = {}

local channel_type = enums.ChannelType
local comp_code = ipmi.types.Cc
local GET_ARM_NPU_CMD<const> = 0x17
local DMP_LAST_REQ<const> = 0x80
local INVALID_READING<const> = 0x8000

local npu_dmp_set_npu_cap_req = bs.new([[<<
    0xDB0700:3/unit:8,
    cmd:1/unit:8,
    lun:1/unit:8,
    para:1/unit:8,
    op_cmd:1/unit:8,
    op_fun:1/unit:8,
    offset:4/unit:8,
    data_length:4/unit:8,
    parameter:4/unit:8
    >>]])
-- 设置NPU的功耗封顶
function imu_cmd.set_npu_cap_param(bus, module_id, direction_power)
    local req_data = npu_dmp_set_npu_cap_req:pack({
        cmd = GET_ARM_NPU_CMD,
        lun = DMP_LAST_REQ,
        para = 0,
        op_cmd = 0x26,
        op_fun = 0x06,
        offset = 0,
        data_length = 0x08,
        parameter = direction_power
    })
    local id = module_id * 2 - 1 --根据模组id获取对应模组的主die id，当前硬件只支持通过主die设置模组功耗封顶
    local result, _ = ipmi.request(
        bus,{channel_type.CT_ME:value(), id},
        {DestNetFn = 0x30, Cmd = 0x98, Payload = req_data}
    )
    if result == comp_code.Success then
        log:debug('set npu%s consumption to %s success!', id, direction_power)
        return result
    end
    log:debug('update npu%d power consumption to %s failed! cc=%s', id, direction_power, result)
    return result
end

local npu_dmp_req = bs.new([[<<
    0xDB0700:3/unit:8,
    cmd:1/unit:8,
    lun:1/unit:8,
    para:1/unit:8,
    op_cmd:1/unit:8,
    op_fun:1/unit:8,
    offset:4/unit:8,
    data_length:4/unit:8
    >>]])

local rspNpuPowerCap = bs.new([[<<
    head:3/unit:8,
    total_length:4/little-unit:8,
    respond_length:4/little-unit:8,
    power_cap:4/little-unit:8,
    max_power_cap:4/little-unit:8,
    tail/binary
    >>]])

local reqNpuPowerCap = {DestNetFn = 0x30, Cmd = 0x98, Payload = npu_dmp_req:pack({
    cmd = GET_ARM_NPU_CMD,
    lun = DMP_LAST_REQ,
    para = 0,
    op_cmd = 0x27,
    op_fun = 0x06,
    offset = 0,
    data_length = 8
})}

-- 获取NPU功耗封顶值
function imu_cmd.get_npu_mpdule_power_cap(bus, id)
    local result, payload = ipmi.request(bus, {channel_type.CT_ME:value(), id}, reqNpuPowerCap)
    if result == comp_code.Success then
        local data = INVALID_READING
        local max_data = nil
        local rsp = rspNpuPowerCap:unpack(payload)
        if rsp and rsp.power_cap then
            data = rsp.power_cap
            log:debug('Npu%s power_cap is %s', id, data)
        end
        if rsp and rsp.max_power_cap and rsp.max_power_cap < INVALID_READING and rsp.max_power_cap > 0 then
            max_data = rsp.max_power_cap
            log:debug('Npu%s max_power_cap is %s', id, max_data)
        end
        return result, data, max_data
    end
    return result
end


return imu_cmd