/* * * 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; }
/* * * 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 */
/** * * @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; }
/** * * @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 ); }
/* * * 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]; }