📄 lh7a404_csc_driver.c
字号:
*
* Processing:
* Based on the passed argument, read and return the CPU, AHB bus,
* or APB bus frequency to the caller.
*
* Parameters:
* clock : Must be CPUCLK, AHBCLK, or APBCLK
*
* Outputs: None
*
* Returns: The selected clock speed in Hz
*
* Notes: None
*
**********************************************************************/
UNS_32 csc_get_clock(CSC_CLOCK_T clock)
{
UNS_32 clkinhz = 0;
switch (clock)
{
case CPUCLK:
clkinhz = csc_get_cpuclk();
break;
case AHBCLK:
clkinhz = csc_get_hclk();
break;
case APBCLK:
clkinhz = csc_get_pclk();
break;
default:
break;
}
return clkinhz;
}
/***********************************************************************
*
* Function: csc_clock_set
*
* Purpose: Set the CSC CLKSET register
*
* Processing:
* Get the existing value of the clock setting register. Set the
* state of the static memory controller clock in the new clock
* setting word to the state from the existing word. If the existing
* clock settings have a bus speed that is a divider (not 1) of the
* CPU speed, the existing mode is set to SYNC mode and the new
* mode is checked to to be FASTBUS or SYNC mode. If the existing
* clock settings have a bus speed that is the same as the CPU
* speed, the existing mode is set to FASTBUS mode and the new
* mode is checked to to be FASTBUS or SYNC mode. If the new and
* existing modes are the same, the clock settings are updated
* and 5 'No operation' instructions are executed to clear the
* pipeline after the clock setting change, as the chip goes into
* standby for a short period of time. If the new and existing
* modes are not the same and the new mode is FASTBUS mode, then
* the set the new clock speed and then set the new bus mode. If
* the new and existing modes are not the same and the new mode
* is SYNC mode, then set the new bus mode and then set the new
* clock speed.
*
* Parameters:
* clkset_register_setting : Value to program into CLKSET
*
* Outputs: None
*
* Returns: Nothing
*
* Notes:
* There are 4 possible conditions for bus clocking mode management
* in this function. The conditions for handling of each condition
* are shown below. The bus clocking mode MUST be configured based
* on the CPU and AHB bus speeds or data loss will occur. For
* clock settings where the CPU and bus speed are the same, the
* FASTBUS clocking mode must be used. For clock settings where the
* CPU speed is greater then the bus speed, the SYNC clocking mode
* must be used.
* Condition 1: Present bus mode is fastbus, new mode is sync
* For this condition, the target system bus speed is a
* divided speed of the CPU speed and the present system bus
* speed is the same as the CPU speed. Prior
* Condition 2: Present bus mode is sync, new mode is fastbus
* Condition 3: Present bus mode is sync, new mode is sync
* For this condition, no bus mode changes are needed.
* Condition 4: Present bus mode is fastbus, new mode is fastbus
* For this condition, no bus mode changes are needed.
*
**********************************************************************/
void csc_clock_set(UNS_32 clkset_register_setting)
{
UNS_32 smc_clk_mode;
/* Save state of static memory controller clock in CLKSET word */
smc_clk_mode = CLKSC->clkset & CSC_SMCROM;
/* Switch to fastbus mode to put CPU and bus clocks at the same
speed */
#ifdef __ICCARM__
{
UNS_32 new_clk_mode;
new_clk_mode = __MRC(15, 0, 1, 0, 0);
new_clk_mode = new_clk_mode & ARM922T_MMU_CONTROL_BUSMASK;
new_clk_mode = new_clk_mode | ARM922T_MMU_CONTROL_FASTBUS;
__MCR(15, 0, new_clk_mode, 1, 0, 0);
__no_operation();
__no_operation();
__no_operation();
__no_operation();
__no_operation();
}
#endif
#ifdef __GNUC__
asm ("MRC p15, 0, r1, c1, c0, 0");
asm ("MOV r2, %0" : : "r" (ARM922T_MMU_CONTROL_FASTBUS));
asm ("AND r1, r1, %0" : : "r" (ARM922T_MMU_CONTROL_BUSMASK));
asm ("ORR r1, r1, r2");
asm ("MCR p15, 0, r1, c1, c0, 0");
asm ("NOP");
asm ("NOP");
asm ("NOP");
asm ("NOP");
asm ("NOP");
#endif
#ifdef __ghs__
change_clkbus_mode (ARM922T_MMU_CONTROL_FASTBUS,
ARM922T_MMU_CONTROL_BUSMASK);
nops5();
#endif
#ifdef __arm
__asm
{
MRC ARM922T_MMU_CP, 0, r1, ARM922T_MMU_REG_CONTROL, c0, 0
MOV r2, #ARM922T_MMU_CONTROL_FASTBUS
AND r1, r1, #ARM922T_MMU_CONTROL_BUSMASK
ORR r1, r1, r2
MCR ARM922T_MMU_CP, 0, r1, ARM922T_MMU_REG_CONTROL, c0, 0
NOP
NOP
NOP
NOP
NOP
}
#endif
/* Set the new clock mode */
CLKSC->clkset = (clkset_register_setting | smc_clk_mode);
/* NOPs to clear the pipeline after coming out of standby */
#ifdef __ICCARM__
__no_operation();
__no_operation();
__no_operation();
__no_operation();
__no_operation();
#endif
#ifdef __GNUC__
asm ("NOP");
asm ("NOP");
asm ("NOP");
asm ("NOP");
asm ("NOP");
#endif
#ifdef __ghs__
nops5();
#endif
#ifdef __arm
__asm
{
NOP
NOP
NOP
NOP
NOP
}
#endif
/* If the CPU and bus clocks are different, switch to SYNC mode */
if ((clkset_register_setting & 0x00000003) != 0)
{
#ifdef __ICCARM__
{
UNS_32 new_clk_mode;
new_clk_mode = __MRC(15, 0, 1, 0, 0);
new_clk_mode = new_clk_mode & ARM922T_MMU_CONTROL_BUSMASK;
new_clk_mode = new_clk_mode | ARM922T_MMU_CONTROL_SYNC;
__MCR(15, 0, new_clk_mode, 1, 0, 0);
__no_operation();
__no_operation();
__no_operation();
__no_operation();
__no_operation();
}
#endif
#ifdef __GNUC__
asm ("MRC p15, 0, r1, c1, c0, 0");
asm ("MOV r2, %0" : : "r" (ARM922T_MMU_CONTROL_SYNC));
asm ("AND r1, r1, %0" : : "r" \
(ARM922T_MMU_CONTROL_BUSMASK));
asm ("ORR r1, r1, r2");
asm ("MCR p15, 0, r1, c1, c0, 0");
asm ("NOP");
asm ("NOP");
asm ("NOP");
asm ("NOP");
asm ("NOP");
#endif
#ifdef __ghs__
change_clkbus_mode (ARM922T_MMU_CONTROL_SYNC,
ARM922T_MMU_CONTROL_BUSMASK);
nops5();
#endif
#ifdef __arm
__asm
{
MRC ARM922T_MMU_CP, 0, r1, ARM922T_MMU_REG_CONTROL, c0, 0
MOV r2, #ARM922T_MMU_CONTROL_SYNC
AND r1, r1, #ARM922T_MMU_CONTROL_BUSMASK
ORR r1, r1, r2
MCR ARM922T_MMU_CP, 0, r1, ARM922T_MMU_REG_CONTROL, c0, 0
NOP
NOP
NOP
NOP
NOP
}
#endif
}
}
/***********************************************************************
*
* Function: csc_stby_wakeup_enable
*
* Purpose: Enable or disable the wakeup signal
*
* Processing:
* Disable the wakeup signal by setting the wakeup disable bit in
* the CSC WRCNT register.
*
* Parameters: None
*
* Outputs: None
*
* Returns: Nothing
*
* Notes: None
*
**********************************************************************/
void csc_stby_wakeup_enable(BOOL_32 enable)
{
if (enable == TRUE)
{
/* Wakeup is enabled */
CLKSC->pwrcnt &= ~CSC_PWRCNT_WAKEDIS;
}
else
{
/* Wakeup is disabled */
CLKSC->pwrcnt |= CSC_PWRCNT_WAKEDIS;
}
}
/***********************************************************************
*
* Function: csc_set_pgmclk_divisor
*
* Purpose: Set the PGMCLK divisor (> 1) or disable it (= 0)
*
* Processing:
* Get the value of the CSC power count register and mask off the
* clock program bits. Or in the new clock program bits into the
* power count register.
*
* Parameters:
* div : Program clock divisor value (0 to 254)
*
* Outputs: None
*
* Returns: Nothing
*
* Notes: None
*
**********************************************************************/
void csc_set_pgmclk_divisor(UNS_8 div)
{
UNS_32 tmp;
/* Get register and mask off clock program bits */
tmp = ((CLKSC->pwrcnt & ~CSC_PWRCNT_PGMCLK(0xFF)) |
CSC_PWRCNT_PGMCLK(div));
CLKSC->pwrcnt = tmp;
}
/***********************************************************************
*
* Function: csc_enable_dma_clock
*
* Purpose: Enable or disable a DMA controller channel clock
*
* Processing:
* If enable is TRUE, enables a selected DMA channel by setting the
* appropriate bit in the CSC PWRCNT register. If enable is FALSE,
* the appropriate bit in the CSC PWRCNT register id disabled.
*
* Parameters:
* channel : Must be of enumeration type CSC_DMA_CHANNEL_T
* enable : Must be TRUE or FALSE
*
* Outputs: None
*
* Returns: Nothing
*
* Notes: None
*
**********************************************************************/
void csc_enable_dma_clock(CSC_DMA_CHANNEL_T channel, BOOL_32 enable)
{
CLKSC->pwrcnt |= (CSC_PWRCNT_DMAPCH1 << (INT_32) channel);
}
/***********************************************************************
*
* Function: csc_usb_reset
*
* Purpose: Issue a USB IO or control reset
*
* Processing:
* Issues a USB control or IO reset by setting the
*
* Parameters:
* reset : Must be USB_IO or USB_CONTROL
*
* Outputs: None
*
* Returns: Nothing
*
* Notes: None
*
**********************************************************************/
void csc_usb_reset(CSC_USB_RESET_T reset)
{
CLKSC->usbreset |= (UNS_32) reset;
}
/***********************************************************************
*
* Function: csc_compute_divider
*
* Purpose:
* Compute the closest divider to the passed input frequency and
* desired target frequency
*
* Processing:
* Start by computing a divider value that will get the closest
* frequency just below the desired target, based on the input
* frequency. If the divider is 1, just return '1'. Otherwise,
* determine if the divider value or the divider value minus 1 is
* a closer match to get the target frequency. Return the closest
* match divider value.
*
* Parameters:
* input_freq : Input frequency (such as AHB bus speed)
* desired_freq : Target frequency
*
* Outputs: None
*
* Returns:
* The closest divider value for (Input frequency) divided by
* (Target frequency)
*
* Notes: None
*
**********************************************************************/
INT_32 csc_compute_divider(UNS_32 input_freq,
UNS_32 desired_freq)
{
UNS_32 div_clock, clock_diff1, clock_diff2;
UNS_32 div = 1;
/* Strt with a divider of 1 */
div_clock = input_freq / div;
/* Try to get the best divider just under the desired frequency */
while (div_clock > desired_freq)
{
div++;
div_clock = input_freq / div;
}
if (div > 1)
{
/* Determine if 'div' or 'div - 1' is closer to desired
frequency */
if (div_clock > desired_freq)
{
clock_diff1 = div_clock - desired_freq;
}
else
{
clock_diff1 = desired_freq - div_clock;
}
div_clock = desired_freq / (div - 1);
if (div_clock > desired_freq)
{
clock_diff2 = div_clock - desired_freq;
}
else
{
clock_diff2 = desired_freq - div_clock;
}
/* If diff1 is greater than diff2, then 'div + 1' is the
closest divider */
if ((clock_diff1 > clock_diff2) && (div > 1))
{
div--;
}
}
return div;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -