/*
 * soclib_pic.h - soclib PIC driver definition.
 *
 * Author  Alain Greiner (2016,2017)
 *
 * Copyright (c) UPMC Sorbonne Universites
 *
 * This file is part of ALMOS-MKH.
 *
 * ALMOS-MKH is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2.0 of the License.
 *
 * ALMOS-MKH 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.
 *
 * You should have received a copy of the GNU General Public License
 * along with ALMOS-kernel; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 */

#ifndef _SOCLIB_PIC_H_
#define _SOCLIB_PIC_H_

#include <hal_kernel_types.h>

/****  Forward declarations  ****/

struct chdev_s;

/*****************************************************************************************
 * This file defines the driver for the SOCLIB PIC device.
 *
 * The SOCLIB PIC infrastructure contains two types of components:
 *
 * - The IOPIC external controller handles the external IRQs generated by the external
 *   peripherals. The IOPIC controller provides two services:
 *   1) It translate each IRQ hardware signal to a write transactions to a specific
 *      mailbox, for a given core in a giveb cluster, as explained below.
 *   2) It  allows the kernel to selectively enable/disable any external IRQ 
 *      identified by its index.
 *
 * - The XCU internal controller implement the generic local interrupt controller
 *   (LAPIC), replicated in all clusters containing at  least one core.
 *   In each cluster, it concentrates all IRQs destinated to one given core,
 *   and helps the interrupt handler to select the ISR (Interrupt Service Routine)
 *   that must be executed by the target core. It defines three types of IRQs: 
 *   1) HWI : The HardWare Interrupts are generated by local internal peripherals.
 *      They are connected to the local XCU, to be routed to a given local core.
 *   2) WTI : The Write Triggered Interrupts are actually mailboxes implemented in the
 *      local XCU. They are used to implement software IPIs (Inter-Processor-Interrupts),
 *      or to register the write transactions generated by the IOPIC controller.
 *   3) PTI : The Programmable Timer Interrupts are actually timers generating periodic
 *      interrupts controled by softare, contained in the local XCU, and routed to
 *      a local core.
 *   The numbers of interrupts of each type in a given cluster are defined in the 
 *   XCU_CONFIG register of the XCU component, and cannot be larger than the
 *   SOCLIB_MAX_HWI, SOCLIB_MAX_WTI, SOCLIB_MAX_PTI constants defined below.
 *   The XCU controller provides three main services:
 *   1) It allows the kernel to selectively enable/disable any IRQ (identified by its type
 *      and index) for a given core. It is the kernel responsibility to enable a given IRQ
 *      for a single core as a given IRQ event should be handled by only one core.
 *   2) It makes a global OR between all enabled IRQs for a given core, to interrupt
 *      the core when at least one enabled IRQ is active.
 *   3) It is capable to return the highest priority active IRQ of each type.
 *      For each type, the lowest index have the highest priority.
 *
 * To select the ISR to be executed for a given HWI or WTI interrupt, the SOCLIB PIC
 * infrastructure implements for each core two interrupts vectors, called hwi_vector[]
 * and wti_vector[].  Each entry contains a pointer on the local chdev descriptor that
 * is the "source" of the interrupt, and contains itself a link to the ISR to be executed.
 * These interrupt vectors are stored in the core descriptor extension.
 * For the PTI interrupts, there is one PTI per core, and the ISR is simply defined
 * by the soclib_pic_timer_isr() function.
 *
 * There is no specific chdev to describe the current state of a given XCU controller.
 * To store the informations attached to a given XCU (namely the WTI allocator), the
 * SOCLIB PIC implementation attach a specific PIC extension to the cluster manager, 
 * called XCU descriptor.
 *****************************************************************************************/

#define SOCLIB_TYPE_HWI        0
#define SOCLIB_TYPE_WTI        1
#define SOCLIB_TYPE_PTI        2

#define SOCLIB_MAX_HWI         16 
#define SOCLIB_MAX_WTI         16 
#define SOCLIB_MAX_PTI         16 

#define SOCLIB_CYCLES_PER_MS   60    // SystemC virtual prototype at 60 KHz

/******************************************************************************************
 * This define the registers offsets for the  external SOCLIB_IOPIC component. 
 * There is 4 addressable registers for each external input IRQ.
 *****************************************************************************************/

#define IOPIC_ADDRESS          0
#define IOPIC_EXTEND           1
#define IOPIC_STATUS           2
#define IOPIC_MASK             3

#define IOPIC_SPAN             4

/******************************************************************************************
 * This define the registers offsets for the internal SOCLIB_XCU components.
 * There is an XCU component in each cluster.
 *****************************************************************************************/

#define XCU_WTI_REG            0
#define XCU_PTI_PER            1
#define XCU_PTI_VAL            2
#define XCU_PTI_ACK            3
#define XCU_MSK_PTI            4
#define XCU_MSK_PTI_ENABLE     5
#define XCU_MSK_PTI_DISABLE    6
#define XCU_PTI_ACTIVE         6
#define XCU_MSK_HWI            8
#define XCU_MSK_HWI_ENABLE     9
#define XCU_MSK_HWI_DISABLE    10
#define XCU_HWI_ACTIVE         10
#define XCU_MSK_WTI            12
#define XCU_MSK_WTI_ENABLE     13
#define XCU_MSK_WTI_DISABLE    14
#define XCU_WTI_ACTIVE         14
#define XCU_PRIO               15
#define XCU_CONFIG             16

/******************************************************************************************
 * This structure defines the core descriptor extension used by the SOCLIB PIC
 * implementation to store the two HWI / WTI interrupts vectors in the core descriptor.
 * Each entry contains a local pointer on the chdev that is the source of the IRQ.
 * A non allocated entry contains the NULL value.
 *****************************************************************************************/

typedef struct soclib_pic_core_s
{
    struct chdev_s * hwi_vector[SOCLIB_MAX_HWI];    /* HWI interrupt vector             */
    struct chdev_s * wti_vector[SOCLIB_MAX_WTI];    /* WTI interrupt vector             */
}
soclib_pic_core_t;

/******************************************************************************************
 * This structure defines the cluster manager extension used by the SOCLIB PIC
 * implementation to register the local XCU base address, the number of HWI/WTI/PTI,
 * and the WTI allocator. The WTI allocator is very simple, because an allocated WTI
 * mailbox is never released.
 *****************************************************************************************/

typedef struct soclib_pic_cluster_s
{
    uint32_t * xcu_base;           /*! local pointer on xcu segment base                 */
    uint32_t   hwi_nr;             /*! actual number of HWI inputs in XCU                */
    uint32_t   wti_nr;             /*! actual number of HWI inputs in XCU                */
    uint32_t   pti_nr;             /*! actual number of HWI inputs in XCU                */
    uint32_t   first_free_wti;     /*! simple allocator : first free WTI slot index      */
}
soclib_pic_cluster_t;




/******************************************************************************************
 *                      Generic PIC API 
 *****************************************************************************************/

/******************************************************************************************
 * This function disables all input IRQs in the external IOPIC controller. 
 * It must be called by a thread running in the cluster containing the PIC chdev. 
******************************************************************************************
 * @ chdev    : pointer on PIC chdev descriptor.
 *****************************************************************************************/
void   soclib_pic_init( struct chdev_s * pic );

/*****************************************************************************************
 * This function allocates memory from local cluster for the local PIC core extensions
 * of all cores contained in the cluster, initializes the two HWI, WTI interrupt vectors
 * as empty, and registers - for each core - the pointer in core descriptor.
 * Then it allocates memory from local cluster for the PIC cluster extension,
 * and registers the pointer in cluster manager.
 * It accesses the local XCU component to get actual number of HWI / WTI / PTI. 
 * Finally, it disables all HWI/WTI/PTI interrupts for all cores by writing in the
 * relevant mask registers of the local XCU component.
 *****************************************************************************************
 * @ xcu_base  : local pointer on XCU controller segment base.
 ****************************************************************************************/
void soclib_pic_extend_init( uint32_t * xcu_base );

/******************************************************************************************
 * This function configure the PIC device to route the IRQ generated by a local chdev,
 * defined by the <src_chdev> argument, to a local core identified by the <lid> argument.
 * If the source chdev is external (IOC, TXT, NIC, IOB):
 * - it get a WTI mailbox from the XCU.
 * - it enables this WTI in XCU.
 * - it updates the target core WTI interrupt vector.
 * - it link the WTI to the relevant input IRQ in IOPIC.
 * If the source chdev is internal (MMC, DMA):
 * - it enables the HWI in XCU.
 * - it updates the target core HWI interrupt vector.
 * It must be called by a thread running in local cluster.
 ******************************************************************************************
 * @ lid        : target core local index.
 * @ src_chdev  : local pointer on source chdev descriptor.
 *****************************************************************************************/
void soclib_pic_bind_irq( lid_t            lid,
                          struct chdev_s * src_chdev );

/******************************************************************************************
 * This function enables a remote HWI/WTI IRQ, identified by the <src_chdev_xp> argument,
 * that contains information on the IRQ type (HWI/WTI), and IRQ index. 
 * It access the remote XCU mask register, but does not access IOPIC.
 ******************************************************************************************
 * @ lid           : target core local index (in cluster containing the source chdev).
 * @ src_chdev_xp  : extended pointer on source chdev descriptor.
 *****************************************************************************************/
void soclib_pic_enable_irq( lid_t   lid,
                            xptr_t  src_chdev_xp );

/******************************************************************************************
 * This function disables a remote HWI/WTI IRQ, identified by the <src_chdev_xp> argument, 
 * that contains information on the IRQ type (HWI/WTI), and IRQ index.
 * It access the remote XCU mask register, but does not access IOPIC.
 ******************************************************************************************
 * @ lid           : target core local index (in cluster containing the source chdev).
 * @ src_chdev_xp  : extended pointer on source chdev descriptor.
 *****************************************************************************************/
void soclib_pic_disable_irq( lid_t   lid,
                             xptr_t  src_chdev_xp );

/******************************************************************************************
 * This function activates the PTI timer for the calling core.
 * The <period> argument define the number of cycles between IRQs.
 ******************************************************************************************
 * @ period      : number of ticks between IRQs.
 *****************************************************************************************/
void soclib_pic_enable_timer( uint32_t period );

/******************************************************************************************
 * This function activates the WTI[lid] in the local cluster, where lid is the calling
 * core local index.
 *****************************************************************************************/
void soclib_pic_enable_ipi();

/******************************************************************************************
 * This function allows the calling thread to send an IPI to any core in any cluster.
 * It can be called by any thread running on any cluster.
 ******************************************************************************************
 * @ cxy        : target core cluster.
 * @ lid        : target core local index.
 *****************************************************************************************/
void soclib_pic_send_ipi( cxy_t    cxy,
                          lid_t    lid );

/******************************************************************************************
 * This function acknowleges the WTI[lid] in the local cluster, where lid is the calling
 * core local index.
 *****************************************************************************************/
void soclib_pic_ack_ipi();






/******************************************************************************************
 *                    Private PIC API for TSAR.
 *****************************************************************************************/

/******************************************************************************************
 * This function returns the first free WTI mailbox from the XCU descriptor.
 * cluster extension containing the current XCU state. It does not access the
 * hardware XCU component. This WTI allocator is very simple, because an allocated
 * WTI is never released. The first WTIs are preallocated for IPI (wpi_id == lid).
 * This allocator does not use a lock, because there is no risk of concurrent access.
 * If there is no free slot, it means that the total number of external IRQs is too
 * large for the number of cores in the architecture, and the core goes to sleep.
 *****************************************************************************************/
uint32_t soclib_pic_wti_alloc();

/******************************************************************************************
 * This function returns the local pointer on the local XCU base segment.
 *****************************************************************************************/
uint32_t * soclib_pic_xcu_base();

/******************************************************************************************
 * This function returns the local pointer on a remote XCU base segment.
 * It is used by the soclip_pic_enable_irq() and soclib_pic_disable_irq() functions.
 ******************************************************************************************
 * @ cxy  : target cluster identifier.
 *****************************************************************************************/
uint32_t * soclib_pic_remote_xcu_base( cxy_t cxy );

/******************************************************************************************
 * This function returns in the <hwi_status>, <wti_status>, <pti_status> buffers
 * the local XCU status for a given core identidied by the <lid> argument.
 *****************************************************************************************/
void soclib_pic_xcu_status( lid_t      lid,
                            uint32_t * hwi_status,
                            uint32_t * wti_status,
                            uint32_t * pti_status );

/******************************************************************************************
 * This SOCLIB PIC specific is the call-back function is the interrupt handler.
 *****************************************************************************************/
void soclib_pic_irq_handler();







#endif	/* _SOCLIB_PIC_H_ */
