/*****************************************************************************
* Copyright (c) 2007 Digi International Inc., All Rights Reserved
* 
* This software contains proprietary and confidential information of Digi
* International Inc.  By accepting transfer of this copy, Recipient agrees
* to retain this software in confidence, to prevent disclosure to others,
* and to make no use of this software other than that for which it was
* delivered.  This is an unpublished copyrighted work of Digi International
* Inc.  Except as permitted by federal law, 17 USC 117, copying is strictly
* prohibited.
* 
* Restricted Rights Legend
*
* Use, duplication, or disclosure by the Government is subject to
* restrictions set forth in sub-paragraph (c)(1)(ii) of The Rights in
* Technical Data and Computer Software clause at DFARS 252.227-7031 or
* subparagraphs (c)(1) and (2) of the Commercial Computer Software -
* Restricted Rights at 48 CFR 52.227-19, as applicable.
*
* Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343
*
*****************************************************************************/


#include "fwtypes.h"
#include "iop_api.h"
#include "sdioTable.h"
#include "sdioPic.h"
#include "scm_reg.h"
#include "reg_def.h"
#include "iop_reg.h"



NaSdioTable2Type_t naSdioTable2[NA_SDIO_MAX_INTERFACES];

static void getSemaphore(void *context)
{
    unsigned interface = (unsigned) context;
    
    naSdioTable[interface].getSemaphore(interface, naSdioTable2[interface].picSemaphoreContext);
}

static void releaseSemaphore(void *context)
{
    unsigned interface = (unsigned) context;
    
    naSdioTable[interface].releaseSemaphore(interface, naSdioTable2[interface].picSemaphoreContext);
}

void naSdioDrvrGetSemaphore(void *context)
{
    unsigned interface = (unsigned) context;
    
    naSdioTable[interface].getSemaphore(interface,
				   	naSdioTable2[interface].semaphoreContext);
}

void naSdioDrvrReleaseSemaphore(void *context)
{
    unsigned interface = (unsigned) context;
    
    naSdioTable[interface].releaseSemaphore(interface,
				   	naSdioTable2[interface].semaphoreContext);
}

/*
 * This function is called from netosStartup to initialize the SDIO driver.
 */
NaStatus naSdioInitialize(unsigned interface)
{
    NaStatus ccode = NASTATUS_SDIO_BAD_INTERFACE;
    NaSdioTable_t *sdConf;
    NaSdioTable2Type_t *clkConf;
    static unsigned char first_time[NA_IOP_MAX_PICS] = {1,1};

    if (interface >= naSdioTableSize)
        return ccode;

    sdConf  = &naSdioTable[interface];
    clkConf = &naSdioTable2[interface];
            
    /*
     * Make sure clock to I/O processor is turned on.  BSP turns them off by
     * default.
     */
    if (sdConf->processor == NA_IOP_PROCESSOR_PIC0)
    {
        narm_write_reg(NA_SCM_CCR_REG, NA_SCM_CCR_ADDRESS, iop0, SCM_CCR_ENABLE_CLOCK);
    }
    else if (sdConf->processor == NA_IOP_PROCESSOR_PIC1)
    {
        narm_write_reg(NA_SCM_CCR_REG, NA_SCM_CCR_ADDRESS, iop1, SCM_CCR_ENABLE_CLOCK);
    }
    else
    {
        panic_num("Invalid I/O processor", ERROR_SDIO, ERROR_SDIO_INITIALIZATION);
        return ccode;
    }

    /*
     * The SDIO program in the I/O processor has two configuration registers.  One
     * register controls a clock divisor, the other enables and disables interrupts
     * from the processor.  Set up pointer variables to these configuration registers.
     */
    clkConf->clockDivisor = NA_IOP_CONTROL_REG_getAddress(sdConf->processor, NA_SDIO_DIVISOR_REGISTER);
    clkConf->interruptControl = NA_IOP_CONTROL_REG_getAddress(sdConf->processor, NA_SDIO_INTERRUPT_CONTROL_REGISTER);

    if (first_time[interface])
    {
        /*
         * Create a semaphore for this SDIO interface.
         */
        sdConf->createSemaphore(interface, &clkConf->semaphoreContext);
    
        /*
         * Create a semaphore for the IOP driver.
         */
        sdConf->createSemaphore(interface, &clkConf->picSemaphoreContext);
        
        first_time[interface] = 0;
    }

    ccode = naIopRegisterSemaphore(sdConf->processor, 
                                   getSemaphore,
                                   releaseSemaphore, 
                                   (void *) interface);
    if (ccode != NASTATUS_SUCCESS)
    {
        panic_num("naIopRegisterSemaphore failed", ERROR_SDIO, ERROR_SDIO_INITIALIZATION);
        return ccode;
    }

    /*
     * Stop the processor so we can download its program.
     */
    ccode = naIopProcessorStopAndReset(sdConf->processor);
    if (ccode != NASTATUS_SUCCESS)
    {
        panic_num("naIopProcessorStopAndReset failed", ERROR_SDIO, ERROR_SDIO_INITIALIZATION);
        return ccode;
    }
    
    /*
     * Download the code to the I/O processor.
     */
    ccode = naIopProcessorDownloadPicProgram(sdConf->processor, sdConf->program);
    if (ccode != NASTATUS_SUCCESS)
    {
        panic_num("naIopProcessorDownloadProgram failed", ERROR_SDIO, ERROR_SDIO_INITIALIZATION);
        return ccode;
    }

    /*
     * Flush the IOP API's DMA queues.
     */
    ccode = naIopDmaFlushQueue(sdConf->processor, TRUE);
    if (ccode != NASTATUS_SUCCESS)
    {
        panic_num("naIopDmaFlushQueue failed", ERROR_SDIO, ERROR_SDIO_INITIALIZATION);
        return ccode;
    }
    ccode = naIopDmaFlushQueue(sdConf->processor, FALSE);
    if (ccode != NASTATUS_SUCCESS)
    {
        panic_num("naIopDmaFlushQueue failed", ERROR_SDIO, ERROR_SDIO_INITIALIZATION);
        return ccode;
    }

    /*
     * Set the I/O configuration.  Set the clock divisor to use during initialization
     * with the card, and disable interrupts.
     */
    *clkConf->clockDivisor = NA_SDIO_RECOMMENDED_INITIAL_CLOCK_DIVISOR;
    *clkConf->interruptControl = NA_SDIO_INTERRUPT_DISABLE;
    
    /*
     * Let her rip.
     */
    ccode = naIopProcessorStartAtZero(sdConf->processor);
    if (ccode != NASTATUS_SUCCESS)
    {
        panic_num("naIopProcessorDownloadProgram failed", ERROR_SDIO, ERROR_SDIO_INITIALIZATION);
        return ccode;
    }
    
    return ccode;
}


