/*
 * soclib_iob.c - soclib IOB driver API implementation.
 *
 * Alain Greiner    (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-MKH; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 */

#include <kernel_config.h>
#include <hal_kernel_types.h>
#include <hal_remote.h>
#include <soclib_iob.h>

///////////////////////////////////////
void soclib_iob_init( chdev_t * chdev )
{
    // desactivate IOMMU
    hal_remote_sw( chdev->base + (IOB_IOMMU_ACTIVE<<2) , 0 );
}

////////////////////////////////////////////
void soclib_iob_set_active( xptr_t   iob_xp,
                            uint32_t value )
{
    // get IOX device cluster and local pointer
    cxy_t     iob_cxy = GET_CXY( iob_xp );
    chdev_t * iob_ptr = (chdev_t *)GET_PTR( iob_xp );

    // get extended pointer on SOCLIB_IOB base_xp segment
    xptr_t base_xp = (xptr_t)hal_remote_lwd( XPTR( iob_cxy , &iob_ptr->base ) );

    // set ACTIVE register
    hal_remote_sw( base_xp + (IOB_IOMMU_ACTIVE<<2) , value );
}

//////////////////////////////////////////
void soclib_iob_set_ptpr( xptr_t   iob_xp,
                          uint32_t value )
{
    // get IOX device cluster and local pointer
    cxy_t     iob_cxy = GET_CXY( iob_xp );
    chdev_t * iob_ptr = (chdev_t *)GET_PTR( iob_xp );

    // get extended pointer on SOCLIB_IOB base_xp segment
    xptr_t base_xp = (xptr_t)hal_remote_lwd( XPTR( iob_cxy , &iob_ptr->base ) );

    // set PTPR register
    hal_remote_sw( base_xp + (IOB_IOMMU_PTPR<<2) , value );
}

///////////////////////////////////////////
void soclib_iob_inval_page( xptr_t  iob_xp,
                            vpn_t   vpn )
{
    // get IOX device cluster and local pointer
    cxy_t     iob_cxy = GET_CXY( iob_xp );
    chdev_t * iob_ptr = (chdev_t *)GET_PTR( iob_xp );

    // get extended pointer on SOCLIB_IOB base_xp segment
    xptr_t base_xp = (xptr_t)hal_remote_lwd( XPTR( iob_cxy , &iob_ptr->base ) );

    // invalidate TLB entry
    hal_remote_sw( base_xp + (IOB_INVAL_PTE<<2) , vpn );
}

//////////////////////////////////////////////
uint32_t soclib_iob_get_bvar( xptr_t  iob_xp )
{
    // get IOX device cluster and local pointer
    cxy_t     iob_cxy = GET_CXY( iob_xp );
    chdev_t * iob_ptr = (chdev_t *)GET_PTR( iob_xp );

    // get extended pointer on SOCLIB_IOB base_xp segment
    xptr_t base_xp = (xptr_t)hal_remote_lwd( XPTR( iob_cxy , &iob_ptr->base ) );

    // get BVAR register
    return hal_remote_lw( base_xp + (IOB_IOMMU_BVAR<<2) );
}

///////////////////////////////////////////////
uint32_t soclib_iob_get_srcid( xptr_t  iob_xp )
{
    // get IOX device cluster and local pointer
    cxy_t     iob_cxy = GET_CXY( iob_xp );
    chdev_t * iob_ptr = (chdev_t *)GET_PTR( iob_xp );

    // get extended pointer on SOCLIB_IOB base_xp segment
    xptr_t base_xp = (xptr_t)hal_remote_lwd( XPTR( iob_cxy , &iob_ptr->base ) );

    // get BVAR register
    return hal_remote_lw( base_xp + (IOB_IOMMU_SRCID<<2) );
}

///////////////////////////////////////////////
uint32_t soclib_iob_get_error( xptr_t  iob_xp )
{
    // get IOX device cluster and local pointer
    cxy_t     iob_cxy = GET_CXY( iob_xp );
    chdev_t * iob_ptr = (chdev_t *)GET_PTR( iob_xp );

    // get extended pointer on SOCLIB_IOB base_xp segment
    xptr_t base_xp = (xptr_t)hal_remote_lwd( XPTR( iob_cxy , &iob_ptr->base ) );

    // get BVAR register
    return hal_remote_lw( base_xp + (IOB_IOMMU_ERROR<<2) );
}


// Local Variables:
// tab-width: 4
// c-basic-offset: 4
// c-file-offsets:((innamespace . 0)(inline-open . 0))
// indent-tabs-mode: nil
// End:
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4

