/*  ****************************************************************************
 *  File: astris_awl.h
 *
 *  Astris AWL Declaration
 *
 ****************************************************************************
 *
 *  Copyright (C) 2021
 *
 *  This document is the property of Apple Inc.
 *  It is considered confidential and proprietary.
 *
 *  This document may not be reproduced or transmitted in any form,
 *  in whole or in part, without the express written permission of
 *  Apple Inc.
 ************************************************************************* */

#ifndef astris_awl_h
#define astris_awl_h

#include <stdio.h>
#include <string>
#include <vector>

#include "astris_api.h"
#include "astris_awl_target.h"
#include "bitfields.h"

class AWL_t {
public:

    AWL_t(AXchip_t *chip);
    virtual ~AWL_t();

    void         add_target(AWLTarget_t *new_target);
    AWLTarget_t *get_target(AXawl_tgt_info_t *tgt);
    AWLTarget_t *target_at(uint8_t tgt);
    uint8_t      get_num_targets();

    int awl_send_message(uint8_t tgt, uint8_t die, uint32_t *msg, uint8_t len);
    int awl_receive_message(uint8_t tgt, uint8_t die, uint32_t **msg, uint8_t *len);
    int awl_wait_for_message_sent();
    int awl_wait_for_message_received();

    typedef enum {
        K_AWL_HW_CAP,
        K_AWL_MSG_CTL,
        K_AWL_MSG_STATUS,
        K_AWL_TGT_SEL,
        K_AWL_MSG_IN,
        K_AWL_MSG_OUT
    } awl_reg_name_t;

    typedef std::map <awl_reg_name_t, AXmemaddr_t> AWLRegsInfo_t;
    int init(const AWLRegsInfo_t &awl_regs);

    int init(const AXmemaddr_t base);

    void multidie_supported(bool multidie_support);

protected:
    AXap_t *m_ap;
    const char *_log_key = AXLOG_M_AWL;
    bool m_innited;
    uint32_t m_hw_msg_size_bits;
    uint32_t m_hw_msg_size_words;
    bool m_multidie_supported;

    std::vector <AWLTarget_t *> m_awl_targets;

    AXmemaddr_t m_awl_hw_cap_reg;
    AXmemaddr_t m_awl_msg_ctl_reg;
    AXmemaddr_t m_awl_msg_status_reg;
    AXmemaddr_t m_awl_tgt_sel_reg;
    AXmemaddr_t m_awl_msg_in_reg;
    AXmemaddr_t m_awl_msg_out_reg;

    int fetch_hw_msg_size();
    int poll_helper(AXmemaddr_t reg_addr, uint32_t mask, uint32_t shift, uint32_t match, const char *wait_desc);

    static constexpr uint32_t S_MSG_SIZE = 0;
    static constexpr uint32_t M_MSG_SIZE = (0x7FF << S_MSG_SIZE);

    static constexpr uint32_t S_MSG_CTL_SEND = 0;
    static constexpr uint32_t M_MSG_CTL_SEND = (0x1 << S_MSG_CTL_SEND);

    static constexpr uint32_t S_MSG_CTL_IE = 16;
    static constexpr uint32_t M_MSG_CTL_IE = (0x1 << S_MSG_CTL_IE);

    static constexpr uint32_t S_MSG_TGT_SEL = 0;
    static constexpr uint32_t M_MSG_TGT_SEL = _MM_MAKEMASK(3, S_MSG_TGT_SEL);

    static constexpr uint32_t S_MSG_TGT_DIE_ID = 8;
    static constexpr uint32_t M_MSG_TGT_DIE_ID = _MM_MAKEMASK(2, S_MSG_TGT_DIE_ID);

    static constexpr uint32_t S_MSG_STATUS_TGT = 0;
    static constexpr uint32_t M_MSG_STATUS_TGT = _MM_MAKEMASK(3, S_MSG_STATUS_TGT);

    static constexpr uint32_t S_MSG_STATUS_NEW = 16;
    static constexpr uint32_t M_MSG_STATUS_NEW = (0x1 << S_MSG_STATUS_NEW);

    static constexpr uint32_t IE_DISABLE    = 0x0;
    static constexpr uint32_t MSG_SEND_BIT  = 0x1;
    static constexpr uint32_t CLEAR_NEW_BIT = 0x1;
};

#endif /* astris_awl_h */
