Exemple #1
0
/*
 *
 * Function Name: chal_dsi_init
 *
 * Description:   Initialize DSI Controller  and software interface
 *
 */
CHAL_HANDLE chal_dsi_init(cUInt32 baseAddr, pCHAL_DSI_INIT dsiInit)
{
    struct CHAL_DSI *pDev = NULL;
    cUInt32 i;

    chal_dprintf(CDBG_INFO, "chal_dsi_init\n");

    if (dsiInit->dlCount > DSI_DL_COUNT) {
        chal_dprintf(CDBG_ERRO,
                     "ERROR: chal_dsi_init: DataLine Count\n");
        return (CHAL_HANDLE)NULL;
    }

    for (i = 0; i < DSI_DEV_COUNT; i++) {
        if (dsi_dev[i].init) {
            if (dsi_dev[i].baseAddr == baseAddr) {
                pDev = (struct CHAL_DSI *)&dsi_dev[i];
                break;
            }
        } else {
            pDev = (struct CHAL_DSI *)&dsi_dev[i];
            pDev->init = TRUE;
            pDev->baseAddr = baseAddr;
            pDev->dlCount = dsiInit->dlCount;
            pDev->clkContinuous = dsiInit->clkContinuous;
            break;
        }
    }

    if (pDev == NULL)
        chal_dprintf(CDBG_ERRO, "ERROR: chal_dsi_init: failed ...\n");

    return (CHAL_HANDLE)pDev;
}
Exemple #2
0
/*
 *
 * Function Name:  chalDsiTimingDivAndRoundUp
 *
 * Description:    DSI Timing Counters - Divide & RoundUp Utility
 *                 Checks for Counter Value Overflow
 */
static Boolean chalDsiTimingDivAndRoundUp(struct DSI_COUNTER *pDsiC,
        cUInt32 i,	/* DSI counter index */
        cUInt32 dividend,
        cUInt32 divisor)
{
    cUInt32 counter;
    cUInt32 counter_remaindor;

    counter = dividend / divisor;
    counter_remaindor = dividend % divisor;

    if (counter_remaindor)
        counter++;

    if ((counter % pDsiC[i].counter_step) != 0)
        counter += pDsiC[i].counter_step;

    counter = counter & (~(pDsiC[i].counter_step - 1));

    counter -= pDsiC[i].counter_offs;

    pDsiC[i].counter = counter;

    if (counter > pDsiC[i].counter_max) {
        chal_dprintf(CDBG_ERRO,
                     "[cHAL DSI] chalDsiTimingDivAndRoundUp: "
                     "%s counter value overflow\n\r", pDsiC[i].name);
        return FALSE;
    } else {
        return TRUE;
    }
}
//*****************************************************************************
//
// Function Name: chal_dsi_init
//
// Description:   Initialize DSI Controller  and software interface
//
//*****************************************************************************
CHAL_HANDLE chal_dsi_init ( cUInt32 baseAddr, pCHAL_DSI_INIT dsiInit )
{
    CHAL_DSI_HANDLE pDev = NULL;
         
    chal_dprintf (CDBG_INFO, "chal_dsi_init\n");

    if ( dsiInit->dlCount > DSI_DL_COUNT )
    {
        chal_dprintf (CDBG_ERRO, "ERROR: chal_dsi_init: DataLine Count\n");
        return (CHAL_HANDLE) NULL;
    }
    
    pDev                = (CHAL_DSI_HANDLE) &dsi_dev[0];
    pDev->baseAddr      = baseAddr;
    pDev->dlCount       = dsiInit->dlCount;
    pDev->clkContinuous = dsiInit->clkContinuous;
    
    return (CHAL_HANDLE) pDev;
}
/*
 *
 * Function Name: chal_spivc4l_set_clk_div
 *
 * Description:   Set Clock Divider
 *
 *                Clock Divider =>  SCLK = Core Clock / CDIV
 *                If CDIV is set to 0, the divisor is 65536.
 *                The divisor must be a power of 2. Odd numbers rounded down.
 *
 */
cInt32 chal_spivc4l_set_clk_div(CHAL_HANDLE handle, cUInt32 clk_div)
{
	struct CHAL_SPIVC4L *pDev = (struct CHAL_SPIVC4L *)handle;

	if (clk_div > 0xFFFE) {
		chal_dprintf(CDBG_ERRO, "chal_spivc4l_set_clk_div: "
			     "ERR ClkDiv Oveflow [0x%08X], MAX[0xFFFE]\n",
			     clk_div);
		return -1;
	}

	if ((clk_div % 2) != 0) {
		chal_dprintf(CDBG_ERRO, "chal_spivc4l_set_clk_div: "
			     "ERR ClkDiv[0x%08X] Must Be Even Number\n",
			     clk_div);
		return -1;
	}
	BRCM_WRITE_REG(pDev->baseAddr, SPI_CLK, clk_div);

	return 0;
}				/* chal_spivc4l_set_clk_div */
Exemple #5
0
/**
*
*  @brief  Initialize CHAL DSP PCM
*
*  @param  baseAddr  (in) mapped base address
*
*  @return CHAL handle
*****************************************************************************/
CHAL_HANDLE chal_dsppcm_init(cUInt32 baseAddr)
{
    //chal_dprintf( CDBG_INFO, "chal_dsppcm_init, base=0x%x\n", baseAddr);

    // Don't re-init the block
    if (handle) {
        chal_dprintf(CDBG_ERRO, "ERROR: chal_dsppcm_init: already initialized\n");
        return handle;
    }

    handle = (CHAL_HANDLE)baseAddr;

    return handle;
}
/*
 *
 * Function Name: chal_spivc4l_init
 *
 * Description:   Initialize SPI Controller cHAL Interface
 *
 *
 */
CHAL_HANDLE chal_spivc4l_init(cUInt32 baseAddr)
{
	struct CHAL_SPIVC4L *pDev;

	chal_dprintf(CDBG_INFO, "chal_spivc4l_init\n");

	pDev = (struct CHAL_SPIVC4L *)&spiDev[0];

	if (!pDev->init) {
		pDev->baseAddr = baseAddr;
		pDev->init = TRUE;
	}

	return (CHAL_HANDLE) pDev;
}
//*****************************************************************************
//
// Function Name: chal_lcdc_init
//
// Description:   Initialize LCDC Parallel (Z80/M68 & DBI) Controller
//                and software interface
//
//*****************************************************************************
CHAL_HANDLE chal_lcdc_init (cUInt32 baseAddr)
{
    pCHAL_LCDC_T pDev = NULL;

    chal_dprintf (CDBG_INFO, "chal_lcdc_init\n");

    pDev = (pCHAL_LCDC_T) &lcdcDev.lcdcCtrl[0];

    if( !lcdcDev.init )
    {
        pDev->baseAddr = baseAddr;
        BRCM_WRITE_REG_FIELD ( pDev->baseAddr, LCDC_CR, DMA, 0 );
        lcdcDev.init = TRUE;
    }

    return (CHAL_HANDLE) pDev;
}
Exemple #8
0
/**
*
*  @brief  Set PCM mode
*
*  @param  handle  (in) chal handle
*          mode  (in) mode to set
*          bitfactor/datafactor  (in) used for user mode
*
*  @return none
*****************************************************************************/
cVoid chal_dsppcm_set_mode(CHAL_HANDLE handle, CHAL_DSPPCM_Mode mode, cUInt8 bitfactor, cUInt8 datafactor)
{
    cUInt32 base;
    cUInt16 val;

    if (!handle) {
        chal_dprintf(CDBG_ERRO, "ERROR: chal_dsppcm_set_mode: not initialized\n");
        return;
    }

    //chal_dprintf( CDBG_INFO, "chal_dsppcm_set_mode: %d\n", mode);

    base = (cUInt32)handle;

    val = (mode << DSP_PCM_PCMRATE_R_MOD_SHIFT) & DSP_PCM_PCMRATE_R_MOD_MASK;
    if (mode == CHAL_DSPPCM_Mode_User)
    {
        val |= (bitfactor << DSP_PCM_PCMRATE_R_BITFACTOR_SHIFT) & DSP_PCM_PCMRATE_R_BITFACTOR_MASK;
        val |= (datafactor << DSP_PCM_PCMRATE_R_DATAFACTOR_SHIFT) & DSP_PCM_PCMRATE_R_DATAFACTOR_MASK;
    }

    BRCM_WRITE_REG(base, DSP_PCM_PCMRATE_R, val);
}
//*****************************************************************************
//
// Function Name:  chalDsiTimingDivAndRoundUp
// 
// Description:    DSI Timing Counters - Divide & RoundUp Utility
//                 Checks for Counter Value Overflow
//*****************************************************************************
static Boolean chalDsiTimingDivAndRoundUp ( 
    DSI_COUNTER *       pDsiC,
    cUInt32             i,         // DSI counter index
    float               dividend, 
    float               divisor 
    )
{
    float   counter_f;
    cUInt32 counter;
    
    counter_f  = dividend / divisor;
    counter    = (UInt32)counter_f;
    
    if( counter_f != (float)counter ) 
        counter++;

    if ( (counter % pDsiC[i].counter_step) != 0 )
        counter += pDsiC[i].counter_step;
    
    counter  = counter & (~(pDsiC[i].counter_step - 1));
    
    counter -= pDsiC[i].counter_offs;
    
    pDsiC[i].counter = counter;
    
    if ( counter > pDsiC[i].counter_max ) 
    {
        chal_dprintf ( CDBG_ERRO, "[cHAL DSI] chalDsiTimingDivAndRoundUp: "
            "%s counter value overflow\n\r",  pDsiC[i].name );
        return ( FALSE );
    } 
    else
    {
        return ( TRUE );
    }
}
//*****************************************************************************
//
// Function Name:  chal_dsi_te_cfg
// 
// Description:    Configure & Enable TE Input
//                 
//*****************************************************************************
cInt32 chal_dsi_te_cfg ( CHAL_HANDLE handle, UInt32 teIn, pCHAL_DSI_TE_CFG teCfg )
{
    
    #define TE_VSWIDTH_MAX   (DSI_TE0_VSWIDTH_TE_VSWIDTH_MASK >> DSI_TE0_VSWIDTH_TE_VSWIDTH_SHIFT)
    #define TE_HSLINE_MAX    (DSI_TE0C_HSLINE_MASK >> DSI_TE0C_HSLINE_SHIFT)
    
    CHAL_DSI_HANDLE pDev                = (CHAL_DSI_HANDLE) handle;
    cUInt32         te_ctrl_reg_val     = 0;
    cUInt32         te_ctrl_reg_mask    = 0;

    te_ctrl_reg_mask |=   DSI_TE0C_MODE_MASK   
                        | DSI_TE0C_HSLINE_MASK 
                        | DSI_TE0C_POL_MASK    
                        | DSI_TE0C_TE_EN_MASK;  

    if( teCfg->sync_pol == CHAL_DSI_TE_ACT_POL_HI )
    {
        te_ctrl_reg_val |= DSI_TE0C_POL_MASK;
    }
    
    if ( teCfg->te_mode == CHAL_DSI_TE_MODE_VSYNC_HSYNC )
    {
        te_ctrl_reg_val |= DSI_TE0C_MODE_MASK; 
    
        if ( teCfg->vsync_width > TE_VSWIDTH_MAX )
        {
            chal_dprintf (CDBG_ERRO, "chal_dsi_te_cfg: "
                "VSYNC Width Value[0x%08X] Overflow, Max[0x%08X]\n", 
                teCfg->vsync_width, TE_VSWIDTH_MAX );
            return ( -1 );
        }    
        if ( teCfg->hsync_line > TE_HSLINE_MAX )
        {
            chal_dprintf (CDBG_ERRO, "chal_dsi_te_cfg: "
                "HSYNC Line Value[0x%08X] Overflow, Max[0x%08X]\n", 
                teCfg->hsync_line, TE_HSLINE_MAX  );
            return ( -1 );
        }
        
        te_ctrl_reg_val |= ( teCfg->hsync_line << DSI_TE0C_HSLINE_SHIFT );
    }    
    
    te_ctrl_reg_val |= DSI_TE0C_TE_EN_MASK;
    
    switch ( teIn )
    {
        case CHAL_DSI_TE_IN_0:
            BRCM_WRITE_REG ( pDev->baseAddr, DSI_TE0_VSWIDTH, teCfg->vsync_width );
            BRCM_WRITE_REG ( pDev->baseAddr, DSI_TE0C, te_ctrl_reg_val );
            break;
        case CHAL_DSI_TE_IN_1:
            BRCM_WRITE_REG ( pDev->baseAddr, DSI_TE1_VSWIDTH, teCfg->vsync_width );
            BRCM_WRITE_REG ( pDev->baseAddr, DSI_TE1C, te_ctrl_reg_val );
            break;
        default:
            chal_dprintf (CDBG_ERRO, "chal_dsi_te_cfg: "
                "Invalid TE Input[%d]\n", teIn );
            return ( -1 );    
    }
    
    return ( 0 );
}
//*****************************************************************************
//
// Function Name:  chal_dsi_set_timing
// 
// Description:    Calculate Values Of DSI Timing Counters
//
//                 <in> escClk_MHz      ESC CLK after divider
//                 <in> hsBitRate_Mbps  HS Bit Rate ( eq to DSI PLL/dsiPllDiv ) 
//                 <in> lpBitRate_Mbps  LP Bit Rate, Max 10 Mbps 
//                   
//*****************************************************************************
cBool chal_dsi_set_timing ( 
    CHAL_HANDLE         handle,
    cUInt32             DPHY_SpecRev,
    float               escClk_MHz,              
    float               hsBitRate_Mbps,  
    float               lpBitRate_Mbps  
    )
{
    Boolean res = FALSE;
    
    float           time_min;
    float           time_min1;
    float           time_min2;
    float           time_max;
    float           period;
    float           ui_ns;
    float           escClk_ns;
    cUInt32         i;
    DSI_COUNTER *   pDsiC;
    CHAL_DSI_HANDLE pDev;

	chal_dprintf ( CDBG_INFO, "chal_dsi_set_timing() escClk_MHz:%f hsBitRate_Mbps:%f lpBitRate_Mbps:%f ", escClk_MHz, hsBitRate_Mbps, lpBitRate_Mbps);
    
    pDev        = (CHAL_DSI_HANDLE) handle;
    ui_ns       = 1 / hsBitRate_Mbps  * 1000;
    escClk_ns   = 1 / escClk_MHz * 1000;

    switch ( DPHY_SpecRev )
    {
        case 1:
            pDsiC = &dsi_dphy_0_92[0];
            break;
        default:
            return ( FALSE );
    }

    // LP Symbol Data Rate = esc_clk / esc2lp_ratio
    if( ! chalDsiTimingDivAndRoundUp( pDsiC, DSI_C_ESC2LP_RATIO, 
        (float)escClk_MHz, (float)lpBitRate_Mbps * 2) )
    {
        return ( FALSE );
    }            
       
    for( i=1; i < DSI_C_MAX; i++ )
    {
        // Period_min1 [ns]
        time_min1 =  (float)pDsiC[i].time_min1_ns 
                   + (float)pDsiC[i].time_min1_ui * ui_ns;

        // Period_min2 [ns]
        if( pDsiC[i].mode & DSI_C_MIN_MAX_OF_2 )
            time_min2 = (float)pDsiC[i].time_min2_ns 
                      + (float)pDsiC[i].time_min2_ui * ui_ns;
        else
            time_min2 = 0;
        
        // Period_min [ns] = max(min1, min2)       
        if( time_min1 >= time_min2 )
            time_min = time_min1;
        else
            time_min = time_min2;    

        // Period_max [ns]
        if( pDsiC[i].mode & DSI_C_HAS_MAX )
            time_max = (float)pDsiC[i].time_max_ns 
                     + (float)pDsiC[i].time_max_ui * ui_ns;
        else
            time_max = 0;
        
        // Period_units [ns]
        if ( pDsiC[i].timeBase & DSI_C_TIME_HS )
            period = ui_ns;
        else if ( pDsiC[i].timeBase & DSI_C_TIME_ESC )
            period = escClk_ns;
        else 
            period = 0;
        
        
        pDsiC[i].period = period;
        
        if( period != 0 )
        {
            res = chalDsiTimingDivAndRoundUp ( pDsiC, i, time_min, period );
            if( !res )
                return ( res );
                
            if( pDsiC[i].mode & DSI_C_HAS_MAX )
            {
                if( ((float)pDsiC[i].counter * period ) > time_max )
                {
                    chal_dprintf ( CDBG_ERRO, "[cHAL DSI] chal_dsi_set_timing: "
                        "%s violates MAX D-PHY Spec allowed value\n\r", 
                        pDsiC[i].name );
                    return ( FALSE );
                }
            }
        }              
    }    


    for( i=0; i < DSI_C_MAX; i++ )
    {
        if ( pDsiC[i].timeBase == DSI_C_TIME_ESC2LPDT )
        {
            chal_dprintf ( CDBG_INFO, "[cHAL DSI] chal_dsi_set_timing: "
                "%13s %7d\n\r", pDsiC[i].name, pDsiC[i].counter );
        } 
        else
        {
            chal_dprintf ( CDBG_INFO, "[cHAL DSI] chal_dsi_set_timing: "
                "%13s %7d %10.2f[ns]\n\r", 
                pDsiC[i].name, 
                pDsiC[i].counter, 
                ((float)pDsiC[i].counter + pDsiC[i].counter_offs) 
                * pDsiC[i].period );
        }
    }

    chal_dprintf (CDBG_INFO, "\r\n[cHAL DSI] chal_dsi_set_timing: "
        "HS_DATA_RATE %6.2f[Mbps]\r\n",  hsBitRate_Mbps );
    chal_dprintf (CDBG_INFO, "[cHAL DSI] chal_dsi_set_timing: "
        "LP_DATA_RATE %6.2f[Mbps]\n\r", 
          escClk_MHz 
        / 2 / (   pDsiC [ DSI_C_ESC2LP_RATIO ].counter 
                + pDsiC [ DSI_C_ESC2LP_RATIO ].counter_offs) );
                

    // set ESC 2 LPDT ratio
    BRCM_WRITE_REG_FIELD ( pDev->baseAddr, DSI_PHYC     , 
        ESC_CLK_LPDT, pDsiC [ DSI_C_ESC2LP_RATIO ].counter );

    // INIT
    BRCM_WRITE_REG_FIELD ( pDev->baseAddr, DSI_HS_INIT  , 
        HS_INIT   , pDsiC [ DSI_C_HS_INIT ].counter );
    
    // ULPS WakeUp    
    BRCM_WRITE_REG_FIELD ( pDev->baseAddr, DSI_HS_WUP   , 
        HS_WUP    , pDsiC [ DSI_C_HS_WAKEUP ].counter);
    BRCM_WRITE_REG_FIELD ( pDev->baseAddr, DSI_LP_WUP   , 
        LP_WUP    , pDsiC [ DSI_C_LP_WAKEUP ].counter );


    // HS CLK
    BRCM_WRITE_REG_FIELD ( pDev->baseAddr, DSI_HS_CPRE  , 
        HS_CPRE   , pDsiC [ DSI_C_HS_CLK_PRE ].counter );
#if (CHIP_REVISION >= 20)
    BRCM_WRITE_REG_FIELD ( pDev->baseAddr, DSI_HS_CPREPARE  , 
        HS_CLK_PREP, pDsiC [ DSI_C_HS_CLK_PREPARE ].counter );
#endif        
    BRCM_WRITE_REG_FIELD ( pDev->baseAddr, DSI_HS_CZERO , 
        HS_CZERO  , pDsiC [ DSI_C_HS_CLK_ZERO ].counter );
    BRCM_WRITE_REG_FIELD ( pDev->baseAddr, DSI_HS_CPOST , 
        HS_CPOST  , pDsiC [ DSI_C_HS_CLK_POST ].counter );
    BRCM_WRITE_REG_FIELD ( pDev->baseAddr, DSI_HS_CTRAIL, 
        HS_CTRAIL , pDsiC [ DSI_C_HS_CLK_TRAIL ].counter );

    // HS
    BRCM_WRITE_REG_FIELD ( pDev->baseAddr, DSI_HS_LPX   , 
        HS_LPX    , pDsiC [ DSI_C_HS_LPX ].counter );
    BRCM_WRITE_REG_FIELD ( pDev->baseAddr, DSI_HS_PRE   , 
        HS_PRE    , pDsiC [ DSI_C_HS_PRE ].counter );
    BRCM_WRITE_REG_FIELD ( pDev->baseAddr, DSI_HS_ZERO  , 
        HS_ZERO   , pDsiC [ DSI_C_HS_ZERO ].counter );
    BRCM_WRITE_REG_FIELD ( pDev->baseAddr, DSI_HS_TRAIL , 
        HS_TRAIL  , pDsiC [ DSI_C_HS_TRAIL ].counter );
    BRCM_WRITE_REG_FIELD ( pDev->baseAddr, DSI_HS_EXIT  , 
        HS_EXIT   , pDsiC [ DSI_C_HS_EXIT ].counter  );
    
    // ESC 
    BRCM_WRITE_REG_FIELD ( pDev->baseAddr, DSI_LPX      , 
        LPX       , pDsiC [ DSI_C_LPX ].counter );
        
    // TURN_AROUND     
    BRCM_WRITE_REG_FIELD ( pDev->baseAddr, DSI_TA_GO    , 
        TA_GO     , pDsiC [ DSI_C_LP_TA_GO ].counter);
    BRCM_WRITE_REG_FIELD ( pDev->baseAddr, DSI_TA_SURE  , 
        TA_SURE   , pDsiC [ DSI_C_LP_TA_SURE ].counter );
    BRCM_WRITE_REG_FIELD ( pDev->baseAddr, DSI_TA_GET   , 
        TA_GET    , pDsiC [ DSI_C_LP_TA_GET ].counter );

    return ( TRUE );
}
Exemple #12
0
/*
 *
 * Function Name:  chal_dsi_set_timing
 *
 * Description:    Calculate Values Of DSI Timing Counters
 *
 *                 <in> escClk_MHz      ESC CLK after divider
 *                 <in> hsBitRate_Mbps  HS Bit Rate ( eq to DSI PLL/dsiPllDiv )
 *                 <in> lpBitRate_Mbps  LP Bit Rate, Max 10 Mbps
 *
 */
cBool chal_dsi_set_timing(CHAL_HANDLE handle,
                          cUInt32 DPHY_SpecRev,
                          CHAL_DSI_CLK_SEL_t coreClkSel,
                          cUInt32 escClk_MHz,
                          cUInt32 hsBitRate_Mbps, cUInt32 lpBitRate_Mbps)
{
    Boolean res = FALSE;

    cUInt32 scaled_time_min;
    cUInt32 scaled_time_min1;
    cUInt32 scaled_time_min2;
    cUInt32 scaled_time_max;
    cUInt32 scaled_period;
    cUInt32 scaled_ui_ns;
    cUInt32 scaled_escClk_ns;
    cUInt32 lp_clk_khz;
    cUInt32 i;
    struct DSI_COUNTER *pDsiC;
    struct CHAL_DSI *pDev;
    cUInt32 counter_offs;
    cUInt32 counter_step;
    cUInt32 lp_lpx_ns;

    pDev = (struct CHAL_DSI *)handle;
    scaled_ui_ns = (1000 * 1000) / hsBitRate_Mbps;

    scaled_escClk_ns = (1000 * 1000) / escClk_MHz;

    switch (DPHY_SpecRev) {
    case 1:
        pDsiC = &dsi_dphy_0_92[0];
        break;
    default:
        return FALSE;
    }

    /* figure step & offset for HS counters */
    if (coreClkSel == CHAL_DSI_BIT_CLK_DIV_BY_8) {
        counter_offs = 8;
        counter_step = 8;
    } else if (coreClkSel == CHAL_DSI_BIT_CLK_DIV_BY_4) {
        counter_offs = 4;
        counter_step = 4;
    } else {
        counter_offs = 2;
        counter_step = 2;
    }

    /* init offset & step for HS counters */
    for (i = 1; i < DSI_C_MAX; i++) {
        /* Period_units [ns] */
        if (pDsiC[i].timeBase & DSI_C_TIME_HS) {
            pDsiC[i].counter_offs = counter_offs;
            pDsiC[i].counter_step = counter_step;
        }
    }

    /* LP clk (LP Symbol Data Rate) = esc_clk / esc2lp_ratio */
    /* calculate esc2lp_ratio */
    if (!chalDsiTimingDivAndRoundUp(pDsiC, DSI_C_ESC2LP_RATIO,
                                    escClk_MHz, lpBitRate_Mbps * 2)) {
        return FALSE;
    }
    /* actual lp clock */
    lp_clk_khz = 1000 * escClk_MHz
                 / (pDsiC[DSI_C_ESC2LP_RATIO].counter
                    + pDsiC[DSI_C_ESC2LP_RATIO].counter_offs);

    /* lp_esc_clk == lp_data_clock */
    lp_lpx_ns = (1000 * 1000 / lp_clk_khz);
    /* set LP LPX to be equal to LP bit rate */

    /* set time_min_ns for LP esc_clk counters */
    pDsiC[DSI_C_LPX].time_min1_ns = pDsiC[DSI_C_LPX].time_lpx * lp_lpx_ns;
    pDsiC[DSI_C_LP_TA_GO].time_min1_ns =
        pDsiC[DSI_C_LP_TA_GO].time_lpx * lp_lpx_ns;
    pDsiC[DSI_C_LP_TA_SURE].time_min1_ns =
        pDsiC[DSI_C_LP_TA_SURE].time_lpx * lp_lpx_ns;
    pDsiC[DSI_C_LP_TA_GET].time_min1_ns =
        pDsiC[DSI_C_LP_TA_GET].time_lpx * lp_lpx_ns;

    /* start from 1, skip [0]=esc2lp_ratio */
    for (i = 1; i < DSI_C_MAX; i++) {
        /* Period_min1 [ns] */
        scaled_time_min1 = pDsiC[i].time_min1_ns * 1000
                           + pDsiC[i].time_min1_ui * scaled_ui_ns;

        /* Period_min2 [ns] */
        if (pDsiC[i].mode & DSI_C_MIN_MAX_OF_2)
            scaled_time_min2 = pDsiC[i].time_min2_ns * 1000
                               + pDsiC[i].time_min2_ui * scaled_ui_ns;
        else
            scaled_time_min2 = 0;

        /* Period_min [ns] = max(min1, min2) */
        if (scaled_time_min1 >= scaled_time_min2)
            scaled_time_min = scaled_time_min1;
        else
            scaled_time_min = scaled_time_min2;

        /* Period_max [ns] */
        if (pDsiC[i].mode & DSI_C_HAS_MAX)
            scaled_time_max = pDsiC[i].time_max_ns * 1000
                              + pDsiC[i].time_max_ui * scaled_ui_ns;
        else
            scaled_time_max = 0;

        /* Period_units [ns] */
        if (pDsiC[i].timeBase & DSI_C_TIME_HS)
            scaled_period = scaled_ui_ns;
        else if (pDsiC[i].timeBase & DSI_C_TIME_ESC)
            scaled_period = scaled_escClk_ns;
        else
            scaled_period = 0;

        pDsiC[i].period = scaled_period;

        if (scaled_period != 0) {
            res =
                chalDsiTimingDivAndRoundUp(pDsiC, i,
                                           scaled_time_min,
                                           scaled_period);
            if (!res)
                return res;

            if (pDsiC[i].mode & DSI_C_HAS_MAX) {
                if ((pDsiC[i].counter * scaled_period) >
                        scaled_time_max) {
                    chal_dprintf(CDBG_ERRO,
                                 "[cHAL DSI] chal_dsi_set_timing: "
                                 "%s violates MAX D-PHY Spec allowed value\n\r",
                                 pDsiC[i].name);
                    return FALSE;
                }
            }
        }
    }

    for (i = 0; i < DSI_C_MAX; i++) {
        if (pDsiC[i].timeBase == DSI_C_TIME_ESC2LPDT) {
            chal_dprintf(CDBG_ERRO,
                         "[cHAL DSI] chal_dsi_set_timing: "
                         "%14s %7d => LP clk %u[Mhz]\n\r",
                         pDsiC[i].name, pDsiC[i].counter,
                         escClk_MHz / (pDsiC[i].counter +
                                       pDsiC[i].counter_offs));
        } else {
            chal_dprintf(CDBG_ERRO,
                         "[cHAL DSI] chal_dsi_set_timing: "
                         "%14s %7d => %u[ns]\n\r", pDsiC[i].name,
                         pDsiC[i].counter,
                         (pDsiC[i].counter + pDsiC[i].counter_offs)
                         * pDsiC[i].period / 1000);
        }
    }

    chal_dprintf(CDBG_ERRO, "\r\n[cHAL DSI] chal_dsi_set_timing: "
                 "HS_DATA_RATE %u[Mbps]\r\n", hsBitRate_Mbps);

    chal_dprintf(CDBG_ERRO, "[cHAL DSI] chal_dsi_set_timing: "
                 "LP_DATA_RATE %u[kbps]\n\r", lp_clk_khz / 2);

    /* set ESC 2 LPDT ratio */
    BRCM_WRITE_REG_FIELD(pDev->baseAddr, DSI1_PHYC,
                         ESC_CLK_LPDT, pDsiC[DSI_C_ESC2LP_RATIO].counter);

    /* HS_DLT5  INIT */
    BRCM_WRITE_REG_FIELD(pDev->baseAddr, DSI1_HS_DLT5,
                         HS_INIT, pDsiC[DSI_C_HS_INIT].counter);

    /* HS_CLT2  ULPS WakeUp */
    BRCM_WRITE_REG_FIELD(pDev->baseAddr, DSI1_HS_CLT2,
                         HS_WUP, pDsiC[DSI_C_HS_WAKEUP].counter);
    /* LP_DLT7  ULPS WakeUp */
    BRCM_WRITE_REG_FIELD(pDev->baseAddr, DSI1_LP_DLT7,
                         LP_WUP, pDsiC[DSI_C_LP_WAKEUP].counter);

    /* HS CLK - HS_CLT0 reg */
    BRCM_WRITE_REG_FIELD(pDev->baseAddr, DSI1_HS_CLT0,
                         HS_CZERO, pDsiC[DSI_C_HS_CLK_ZERO].counter);
    BRCM_WRITE_REG_FIELD(pDev->baseAddr, DSI1_HS_CLT0,
                         HS_CPRE, pDsiC[DSI_C_HS_CLK_PRE].counter);
    BRCM_WRITE_REG_FIELD(pDev->baseAddr, DSI1_HS_CLT0,
                         HS_CPREP, pDsiC[DSI_C_HS_CLK_PREPARE].counter);

    /* HS CLK - HS_CLT1 reg */
    BRCM_WRITE_REG_FIELD(pDev->baseAddr, DSI1_HS_CLT1,
                         HS_CTRAIL, pDsiC[DSI_C_HS_CLK_TRAIL].counter);
    BRCM_WRITE_REG_FIELD(pDev->baseAddr, DSI1_HS_CLT1,
                         HS_CPOST, pDsiC[DSI_C_HS_CLK_POST].counter);

    /* HS DATA HS_DLT3 REG */
    BRCM_WRITE_REG_FIELD(pDev->baseAddr, DSI1_HS_DLT3,
                         HS_EXIT, pDsiC[DSI_C_HS_EXIT].counter);
    BRCM_WRITE_REG_FIELD(pDev->baseAddr, DSI1_HS_DLT3,
                         HS_ZERO, pDsiC[DSI_C_HS_ZERO].counter);
    BRCM_WRITE_REG_FIELD(pDev->baseAddr, DSI1_HS_DLT3,
                         HS_PRE, pDsiC[DSI_C_HS_PRE].counter);

    /* HS DATA HS_DLT4 REG */
    /* !!! HS_ANLAT, new in HERA/RHEA, for now init to 0 (DEF) */
    BRCM_WRITE_REG_FIELD(pDev->baseAddr, DSI1_HS_DLT4, HS_ANLAT, 0);
    BRCM_WRITE_REG_FIELD(pDev->baseAddr, DSI1_HS_DLT4,
                         HS_TRAIL, pDsiC[DSI_C_HS_TRAIL].counter);
    BRCM_WRITE_REG_FIELD(pDev->baseAddr, DSI1_HS_DLT4,
                         HS_LPX, pDsiC[DSI_C_HS_LPX].counter);

    /* LP_DLT6 REG */
    BRCM_WRITE_REG_FIELD(pDev->baseAddr, DSI1_LP_DLT6,
                         TA_GET, pDsiC[DSI_C_LP_TA_GET].counter);
    BRCM_WRITE_REG_FIELD(pDev->baseAddr, DSI1_LP_DLT6,
                         TA_SURE, pDsiC[DSI_C_LP_TA_SURE].counter);
    BRCM_WRITE_REG_FIELD(pDev->baseAddr, DSI1_LP_DLT6,
                         TA_GO, pDsiC[DSI_C_LP_TA_GO].counter);
    BRCM_WRITE_REG_FIELD(pDev->baseAddr, DSI1_LP_DLT6,
                         LPX, pDsiC[DSI_C_LPX].counter);

    return TRUE;
}
//******************************************************************************
//
// Function Name:  chal_dma_start_transfer
//
// Description:    Start a DMA transfer by reloading DMA registers
//
//******************************************************************************
void chal_dma_start_transfer(
    CHAL_HANDLE handle, 
    cUInt32 channel,
    cUInt32 assocChan
)
{
    cUInt32 temp;
    ChalDmaLinkNode_t *head;
    DmaChanConfig_t config;
    ChalDmaDev_t *pDmaDev = (ChalDmaDev_t *)handle;
    
    //chal_dprintf(1, "chal_dma_start_transfer, channel = %d, assocChan = %d\n", channel, assocChan);
  
    //
    // wait the channel to be free
    // You must fully initialize the channel before you enable it. Additionally, you must set the
    // Enable bit of the DMAC before you enable any channels.
    //
  
    CHAL_REG_WRITE32(pDmaDev->baseAddr + DMAC_INTTCCLEAR_OFFSET, 0x1<<channel);
    CHAL_REG_WRITE32(pDmaDev->baseAddr + DMAC_INTERRCLR_OFFSET, 0x1<<channel);
  
    do
    {
        temp = CHAL_REG_READ32(pDmaDev->baseAddr + DMAC_ENBLDCHNS_OFFSET);
    }while (temp & (0x1 << channel));
  
    if(assocChan == ASSOC_CHAN_NONE)
    {
    //
    // Mark channel active and enable DMA core 
    //
    chal_dma_mark_channel_active(handle, channel);
  
    // 
    //  1. Clear any pending interrupts on the channel you want to use.
    //     The privious channel operation might have left interrupts active.
    //  2. Write the source address into the SRC Register. 
    //  3. Write the destination address into the DEST Register. 
    //  4. Write the address of the next SRC into the NEXT Register. If the transfer 
    //     consists of a single packet of data, you must write 0 into this register.
    //  5. Write the control information into the CONTROL Register. 
    //  6. Write the channel configuration information into the CONFIG register.
    //  7. Set channel enable bit, then the DMA channel is automatically enabled.
    //
  
    head = pDmaDev->chanInfo[channel].headNode;
    }
    else
    {
        chal_dma_mark_channel_active(handle, TOTAL_DMA_CHANNELS + assocChan);
  
        head = pDmaDev->chanInfo[TOTAL_DMA_CHANNELS + assocChan].headNode;
    }
  

#if 0
    chal_dprintf(1, "chal_dma_start_transfer, head->src = 0x%x\n", head->src);
    chal_dprintf(1, "chal_dma_start_transfer, head->dst = 0x%x\n", head->dst);
    chal_dprintf(1, "chal_dma_start_transfer, head->control.DWord = 0x%x\n", head->control.DWord);
    chal_dprintf(1, "chal_dma_start_transfer, head->next = 0x%x\n", head->next);
#endif

    //
    // set up DMA for transfer
    //
    CHAL_REG_WRITE32(pDmaDev->baseAddr + DMAC_CH0CONTROL_OFFSET 
                        + CHAN_REG_INCREMENT * channel, head->control.DWord);
    CHAL_REG_WRITE32(pDmaDev->baseAddr + DMAC_CH0SRCADDR_OFFSET 
                        + CHAN_REG_INCREMENT * channel, head->src);
    CHAL_REG_WRITE32(pDmaDev->baseAddr + DMAC_CH0DESTADDR_OFFSET 
                        + CHAN_REG_INCREMENT * channel, head->dst);
    CHAL_REG_WRITE32(pDmaDev->baseAddr + DMAC_CH0LLI_OFFSET 
                        + CHAN_REG_INCREMENT * channel, head->next);

    config.DWord = CHAL_REG_READ32(pDmaDev->baseAddr+DMAC_CH0CONFIG_OFFSET 
                                       + CHAN_REG_INCREMENT * channel);

    config.ChanConfigBitField.chanEnabled = 1;

    //chal_dprintf(1, "chal_dma_start_transfer, config.DWord = 0x%x\n", config.DWord);

    CHAL_REG_WRITE32(pDmaDev->baseAddr + DMAC_CH0CONFIG_OFFSET 
                        + CHAN_REG_INCREMENT * channel, config.DWord);
}
//******************************************************************************
//
// Function Name: chal_dma_add_buffer
//
// Description:   Add first buffer to a DMA channel
//
//******************************************************************************
cUInt32 chal_dma_add_buffer(CHAL_HANDLE handle, cUInt32 chan, ChalDmaBufferDesc_t *pDesc,
                            UInt32 lliXferSize)
{
    ChalDmaLinkNode_t *currNode;
    ChalDmaLinkNode_t *nextNode;
    cUInt32 src, dst;
    DmaChanControl_t control;
    cUInt32 xfer;
    ChalDmaDev_t *pDmaDev = (ChalDmaDev_t *)handle;
  
#if 0
    chal_dprintf(CDBG_ERRO, "chal_dma_add_buffer() chan: %d\n", chan);
    chal_dprintf(CDBG_ERRO, "%d, 0x%x, 0x%x, 0x%x\n", 
        pDesc->firstBuffer,
        pDesc->src,
        pDesc->dst,
        pDesc->size
        );
#endif  

    if (lliXferSize < DMA_MAX_XFER_SIZE)
      return 0;
          
    xfer = pDesc->size/TRANSFER_WIDTH[pDesc->control.srcWidth];
    src = pDesc->src;
    dst = pDesc->dst;

    control.DWord = 0;
    control.ChanCtrlBitField.tcIntEnable = 0; //always disabled until last one
    control.ChanCtrlBitField.prot = pDesc->control.prot;
    control.ChanCtrlBitField.dstIncrement = pDesc->control.dstIncrement;
    control.ChanCtrlBitField.srcIncrement = pDesc->control.srcIncrement;
    control.ChanCtrlBitField.srcMaster = pDesc->control.srcMaster;
    control.ChanCtrlBitField.dstMaster = pDesc->control.dstMaster;
    control.ChanCtrlBitField.dstWidth = pDesc->control.dstWidth;
    control.ChanCtrlBitField.srcWidth = pDesc->control.srcWidth;
    control.ChanCtrlBitField.dstBSize = pDesc->control.dstBSize;
    control.ChanCtrlBitField.srcBSize = pDesc->control.srcBSize;
    
    if(pDesc->firstBuffer == 1)
    {
        currNode = chal_dma_get_first_node(handle, chan);
        if(currNode == NULL)
        {
            return pDesc->size; //nothing is added
        }
        
        pDmaDev->chanInfo[chan].headNode = currNode;
    }
    else
    {
        currNode = pDmaDev->chanInfo[chan].currNode;
        
        nextNode = chal_dma_get_next_node(handle, chan);
        if(nextNode == NULL)
        {
            return xfer * TRANSFER_WIDTH[pDesc->control.srcWidth];
        }
         
        currNode->next = chal_dma_get_lli_physical_addr(handle, nextNode); 
        currNode = nextNode;
    }
    
    while(xfer > 0) 
    {        
        currNode->src = src;
        currNode->dst = dst;
        currNode->control.DWord =  control.DWord;
        currNode->next = 0;
        
        if(xfer <= lliXferSize)
        {
            currNode->control.ChanCtrlBitField.xferSize = xfer;
            currNode->control.ChanCtrlBitField.tcIntEnable = pDesc->control.tcIntEnable;
            xfer = 0; //done transfer
            currNode->next = NULL;

#if 0
            chal_dprintf(1, "done currNode->src = 0x%x\n", currNode->src);
            chal_dprintf(1, "done currNode->dst = 0x%x\n", currNode->dst);
            chal_dprintf(1, "done currNode->control.DWord = 0x%x\n", currNode->control.DWord);
            chal_dprintf(1, "done currNode->next = 0x%x\n", currNode->next);
#endif

            break;
        }
        else
        {
            currNode->control.ChanCtrlBitField.xferSize = lliXferSize;
            xfer -= lliXferSize;
        }
        
        //get next node
        nextNode = chal_dma_get_next_node(handle, chan);
        if(nextNode == NULL)
        {

            break;
        }
        
        currNode->next = chal_dma_get_lli_physical_addr(handle, nextNode);
        
#if 0
        chal_dprintf(1, "xfer = 0x%x\n", xfer);
        chal_dprintf(1, "currNode->src = 0x%x\n", currNode->src);
        chal_dprintf(1, "currNode->dst = 0x%x\n", currNode->dst);
        chal_dprintf(1, "currNode->control.DWord = 0x%x\n", currNode->control.DWord);
        chal_dprintf(1, "currNode->next = 0x%x\n", currNode->next);
#endif

        //increment buffer point
        if(control.ChanCtrlBitField.srcIncrement)
        {
            src += lliXferSize * TRANSFER_WIDTH[pDesc->control.srcWidth];
        }
        if(control.ChanCtrlBitField.dstIncrement)
        {
            dst += lliXferSize * TRANSFER_WIDTH[pDesc->control.dstWidth];
        }
        
        currNode = nextNode;
    }
                        
    pDmaDev->chanInfo[chan].currNode = currNode;
    
    //chal_dprintf(1, "chal_dma_add_buffer, OUT xfer = 0x%x\n", xfer);
    return xfer*TRANSFER_WIDTH[pDesc->control.srcWidth];
}