/*
 * dev_mmc.h - MMC (Generic L2 cache controller) device API definition.
 *
 * Authors   Alain Greiner  (2016)
 *
 * 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-MKH; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 */

#ifndef _DEV_MMC_H_
#define _DEV_MMC_H_

#include <almos_config.h>
#include <hal_types.h>
#include <spinlock.h>

/*****************************************************************************************
 *     Generic L2 cache controller definition
 *
 * The MMC (Memory Cache Controller) device describes an internal peripheral, 
 * acting in all clusters containing a level 2 cache controller.
 *
 * It supports  five command types: 
 * - MMC_CC_INVAL   : invalidate all cache lines covering a given buffer in L2 cache.
 * - MMC_CC_SYNC    : synchronize all cache lines covering a given buffer to L3 cache.
 * - MMC_GET_ERROR  : return content of a given error signaling register.
 * - MMC_SET_ERROR  : set a given error signaling register.
 * - MMC_GET_INSTRU : return content of a given instrumentation register.
 *
 * As all L2 caches can be accessed by any thread running in any cluster, a calling
 * thread must get exclusive access to the MMC configuration interface.
 * As these operations consume few cycles, and access conflicts are expected to be 
 * rare events, the calling threads use a busy waiting strategy to get the device
 * spinlock, but do not register in the device waiting queue, and no server thread
 * is used for this device.
 ****************************************************************************************/
 
/****  Forward declarations  ****/

struct chdev_s;

/******************************************************************************************
 * This enum defines the various implementations of the generic MMC peripheral.
 * It must be kept consistent with the define in arch_info.h file.
 *****************************************************************************************/

enum mmc_impl_e
{
    IMPL_MMC_TSR =   0,     
}
mmc_impl_t;

/*****************************************************************************************
 * This structure defines the (implementation independant) command pased to the driver.
 * To have a fixed format, the arguments interpretation depends on the command type.
 ****************************************************************************************/

enum
{
    MMC_CC_INVAL   = 0,
    MMC_CC_SYNC    = 1,
    MMC_GET_ERROR  = 2,
    MMC_SET_ERROR  = 3,
    MMC_GET_INSTRU = 4,
};

typedef struct mmc_command_s
{
    xptr_t      dev_xp;     /*! extended pointer on the relevant MMC device descriptor  */
    uint32_t    type;       /*! CC_INVAL / CC_SYNC / GET_ERROR / SET_ERROR / GET_INSTRU */
    paddr_t     buf_paddr;  /*! buffer physical address          (used by INVAL/SYNC)   */
    uint32_t    buf_size;   /*! buffer size in bytes             (used by INVAL/SYNC)   */
    uint32_t    reg_index;  /*! register index in MMC peripheral (used by SET/GET)      */
    uint32_t  * reg_ptr;    /*! local pointer on src/dst buffer  (used by SET/GET)      */
    error_t     error;      /*! operation status (0 if success)                         */
}
mmc_command_t;

/*****************************************************************************************
 * This function initializes the driver specific fields in the generic MMC device 
 * descriptor, and the implementation specific driver.
 * It must be executed once in any cluster containing an L2 cache.
 *****************************************************************************************
 * @ chdev      : pointer on MMC device descriptor.
 ****************************************************************************************/
void dev_mmc_init( struct chdev_s * chdev );

/*****************************************************************************************
 * This function invalidates all cache lines covering a memory buffer 
 * in the physical address space. 
 * It can be executed by any thread in any cluster, because it uses remote accesses
 * to access both the MMC device descriptor, and the L2 cache configuration interface.
 *****************************************************************************************
 * @ buf_paddr  : buffer local physical addresse.
 * @ buf_size   : buffer size (bytes).
 * @ return 0 if success / return EINVAL if failure
 ****************************************************************************************/
error_t dev_mmc_inval( paddr_t   buf_paddr,
                       uint32_t  buf_size );

/*****************************************************************************************
 * This function forces the L2 cache to synchronize the L3 cache for all cache lines
 * covering a memory buffer in the physical address space. 
 * It can be executed by any thread in any cluster, because it uses remote accesses
 * to access both the MMC device descriptor, and the L2 cache configuration interface.
 *****************************************************************************************
 * @ buf_paddr  : buffer local physical addresse.
 * @ buf_size   : buffer size (bytes).
 * @ return 0 if success / return EINVAL if failure
 ****************************************************************************************/
error_t dev_mmc_sync( paddr_t    buf_paddr,
                      uint32_t   buf_size );
                        
/*****************************************************************************************
 * This function set a value in one error signaling MMC register.
 * It can be executed by any thread in any cluster, because it uses remote accesses
 * to access the L2 cache instrumentation interface in any cluster.
 *****************************************************************************************
 * @ cxy     : MMC cluster identifier.
 * @ index   : register index in MMC peripheral.
 * @ wdata   : value to be written.
 * @ return 0 if success / return EINVAL if failure
 ****************************************************************************************/
error_t dev_mmc_set_error( cxy_t    cxy,
                           uint32_t index,
                           uint32_t wdata );
              
/*****************************************************************************************
 * This function returns the value contained in one error signaling MMC register.
 * It can be executed by any thread in any cluster, because it uses remote accesses
 * to access the L2 cache instrumentation interface in any cluster.
 *****************************************************************************************
 * @ cxy     : MMC cluster identifier.
 * @ index   : error register index in MMC peripheral.
 * @ rdata   : local pointer on buffer for returned value.
 * @ return 0 if success / return EINVAL if failure
 ****************************************************************************************/
error_t dev_mmc_get_error( cxy_t      cxy,
                           uint32_t   index, 
                           uint32_t * rdata );
              

/*****************************************************************************************
 * This function returns the value contained in one instrumentation MMC register.
 * It can be executed by any thread in any cluster, because it uses remote accesses
 * to access the L2 cache configuration interface in any cluster.
 *****************************************************************************************
 * @ cxy     : MMC cluster identifier.
 * @ index   : instrumentation register index in MMC peripheral.
 * @ rdata   : local pointer on buffer for returned value.
 * @ return 0 if success / return EINVAL if failure
 ****************************************************************************************/
error_t dev_mmc_get_instrumentation( cxy_t      cxy,
                                     uint32_t   index,
                                     uint32_t * rdata );

#endif  /* _DEV_MMC_H_ */
