2016-02-19 15:56:13 +00:00
|
|
|
#include <linux/kernel.h>
|
2015-09-22 09:01:17 +00:00
|
|
|
#include <linux/sizes.h>
|
|
|
|
|
2015-03-03 10:51:06 +00:00
|
|
|
#include "ddk750_reg.h"
|
|
|
|
#include "ddk750_chip.h"
|
|
|
|
#include "ddk750_power.h"
|
|
|
|
|
2016-02-19 15:56:14 +00:00
|
|
|
#define MHz(x) ((x) * 1000000)
|
|
|
|
|
2016-10-11 22:43:07 +00:00
|
|
|
static logical_chip_type_t chip;
|
|
|
|
|
2016-09-25 19:58:35 +00:00
|
|
|
logical_chip_type_t sm750_get_chip_type(void)
|
2015-03-03 10:51:06 +00:00
|
|
|
{
|
2016-10-11 22:43:07 +00:00
|
|
|
return chip;
|
|
|
|
}
|
2015-03-03 10:51:06 +00:00
|
|
|
|
2016-11-26 10:20:58 +00:00
|
|
|
void sm750_set_chip_type(unsigned short devId, u8 revId)
|
2016-10-11 22:43:07 +00:00
|
|
|
{
|
2017-02-27 10:03:45 +00:00
|
|
|
if (devId == 0x718) {
|
2015-03-18 09:37:42 +00:00
|
|
|
chip = SM718;
|
2017-02-27 10:03:45 +00:00
|
|
|
} else if (devId == 0x750) {
|
2015-03-18 09:37:42 +00:00
|
|
|
chip = SM750;
|
2015-03-03 10:51:06 +00:00
|
|
|
/* SM750 and SM750LE are different in their revision ID only. */
|
2016-10-11 22:43:07 +00:00
|
|
|
if (revId == SM750LE_REVISION_ID) {
|
2015-03-03 10:51:06 +00:00
|
|
|
chip = SM750LE;
|
2016-10-11 22:43:07 +00:00
|
|
|
pr_info("found sm750le\n");
|
|
|
|
}
|
2017-01-10 02:23:26 +00:00
|
|
|
} else {
|
2015-03-18 09:37:42 +00:00
|
|
|
chip = SM_UNKNOWN;
|
2017-01-10 02:23:26 +00:00
|
|
|
}
|
2015-03-03 10:51:06 +00:00
|
|
|
}
|
|
|
|
|
2015-10-13 06:26:45 +00:00
|
|
|
static unsigned int get_mxclk_freq(void)
|
2015-03-03 10:51:06 +00:00
|
|
|
{
|
2015-10-13 06:26:44 +00:00
|
|
|
unsigned int pll_reg;
|
|
|
|
unsigned int M, N, OD, POD;
|
|
|
|
|
2016-09-25 19:58:35 +00:00
|
|
|
if (sm750_get_chip_type() == SM750LE)
|
2015-03-03 10:51:06 +00:00
|
|
|
return MHz(130);
|
|
|
|
|
2017-02-08 06:48:43 +00:00
|
|
|
pll_reg = peek32(MXCLK_PLL_CTRL);
|
2016-02-10 16:33:58 +00:00
|
|
|
M = (pll_reg & PLL_CTRL_M_MASK) >> PLL_CTRL_M_SHIFT;
|
2017-07-03 12:05:10 +00:00
|
|
|
N = (pll_reg & PLL_CTRL_N_MASK) >> PLL_CTRL_N_SHIFT;
|
2016-02-10 16:33:58 +00:00
|
|
|
OD = (pll_reg & PLL_CTRL_OD_MASK) >> PLL_CTRL_OD_SHIFT;
|
|
|
|
POD = (pll_reg & PLL_CTRL_POD_MASK) >> PLL_CTRL_POD_SHIFT;
|
2015-10-13 06:26:44 +00:00
|
|
|
|
|
|
|
return DEFAULT_INPUT_CLOCK * M / N / (1 << OD) / (1 << POD);
|
2015-03-03 10:51:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This function set up the main chip clock.
|
|
|
|
*
|
|
|
|
* Input: Frequency to be set.
|
|
|
|
*/
|
2016-10-13 22:25:52 +00:00
|
|
|
static void set_chip_clock(unsigned int frequency)
|
2015-03-03 10:51:06 +00:00
|
|
|
{
|
2016-10-06 08:07:44 +00:00
|
|
|
struct pll_value pll;
|
2015-03-18 09:37:42 +00:00
|
|
|
unsigned int ulActualMxClk;
|
2015-10-22 06:38:39 +00:00
|
|
|
|
2015-03-18 09:37:42 +00:00
|
|
|
/* Cheok_0509: For SM750LE, the chip clock is fixed. Nothing to set. */
|
2016-09-25 19:58:35 +00:00
|
|
|
if (sm750_get_chip_type() == SM750LE)
|
2015-03-18 09:37:42 +00:00
|
|
|
return;
|
2015-03-03 10:51:06 +00:00
|
|
|
|
2015-04-02 17:31:04 +00:00
|
|
|
if (frequency) {
|
2015-03-18 09:37:42 +00:00
|
|
|
/*
|
2016-10-23 02:51:29 +00:00
|
|
|
* Set up PLL structure to hold the value to be set in clocks.
|
|
|
|
*/
|
2015-03-18 09:37:42 +00:00
|
|
|
pll.inputFreq = DEFAULT_INPUT_CLOCK; /* Defined in CLOCK.H */
|
|
|
|
pll.clockType = MXCLK_PLL;
|
|
|
|
|
|
|
|
/*
|
2017-02-27 10:05:33 +00:00
|
|
|
* Call sm750_calc_pll_value() to fill the other fields
|
|
|
|
* of the PLL structure. Sometimes, the chip cannot set
|
|
|
|
* up the exact clock required by the User.
|
|
|
|
* Return value of sm750_calc_pll_value gives the actual
|
|
|
|
* possible clock.
|
2016-10-23 02:51:29 +00:00
|
|
|
*/
|
2016-11-09 09:26:27 +00:00
|
|
|
ulActualMxClk = sm750_calc_pll_value(frequency, &pll);
|
2015-03-18 09:37:42 +00:00
|
|
|
|
|
|
|
/* Master Clock Control: MXCLK_PLL */
|
2017-02-08 06:48:43 +00:00
|
|
|
poke32(MXCLK_PLL_CTRL, sm750_format_pll_reg(&pll));
|
2015-03-18 09:37:42 +00:00
|
|
|
}
|
2015-03-03 10:51:06 +00:00
|
|
|
}
|
|
|
|
|
2016-10-13 22:25:52 +00:00
|
|
|
static void set_memory_clock(unsigned int frequency)
|
2015-03-03 10:51:06 +00:00
|
|
|
{
|
2016-01-17 18:04:26 +00:00
|
|
|
unsigned int reg, divisor;
|
2015-10-22 06:38:39 +00:00
|
|
|
|
2016-10-23 02:51:29 +00:00
|
|
|
/*
|
|
|
|
* Cheok_0509: For SM750LE, the memory clock is fixed.
|
2016-06-05 19:09:24 +00:00
|
|
|
* Nothing to set.
|
|
|
|
*/
|
2016-09-25 19:58:35 +00:00
|
|
|
if (sm750_get_chip_type() == SM750LE)
|
2015-03-03 10:51:06 +00:00
|
|
|
return;
|
2015-10-22 06:38:39 +00:00
|
|
|
|
2015-04-02 17:31:04 +00:00
|
|
|
if (frequency) {
|
2016-06-06 19:04:32 +00:00
|
|
|
/*
|
2016-09-15 20:15:50 +00:00
|
|
|
* Set the frequency to the maximum frequency
|
|
|
|
* that the DDR Memory can take which is 336MHz.
|
2016-06-06 19:04:32 +00:00
|
|
|
*/
|
2015-03-18 09:37:42 +00:00
|
|
|
if (frequency > MHz(336))
|
|
|
|
frequency = MHz(336);
|
|
|
|
|
|
|
|
/* Calculate the divisor */
|
2016-10-02 11:04:46 +00:00
|
|
|
divisor = DIV_ROUND_CLOSEST(get_mxclk_freq(), frequency);
|
2015-03-18 09:37:42 +00:00
|
|
|
|
|
|
|
/* Set the corresponding divisor in the register. */
|
2017-02-08 06:48:43 +00:00
|
|
|
reg = peek32(CURRENT_GATE) & ~CURRENT_GATE_M2XCLK_MASK;
|
2015-03-26 17:09:17 +00:00
|
|
|
switch (divisor) {
|
2015-03-18 09:37:42 +00:00
|
|
|
default:
|
|
|
|
case 1:
|
2016-01-17 18:04:27 +00:00
|
|
|
reg |= CURRENT_GATE_M2XCLK_DIV_1;
|
2015-03-18 09:37:42 +00:00
|
|
|
break;
|
|
|
|
case 2:
|
2016-01-17 18:04:27 +00:00
|
|
|
reg |= CURRENT_GATE_M2XCLK_DIV_2;
|
2015-03-18 09:37:42 +00:00
|
|
|
break;
|
|
|
|
case 3:
|
2016-01-17 18:04:27 +00:00
|
|
|
reg |= CURRENT_GATE_M2XCLK_DIV_3;
|
2015-03-18 09:37:42 +00:00
|
|
|
break;
|
|
|
|
case 4:
|
2016-01-17 18:04:27 +00:00
|
|
|
reg |= CURRENT_GATE_M2XCLK_DIV_4;
|
2015-03-18 09:37:42 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2016-11-09 09:26:27 +00:00
|
|
|
sm750_set_current_gate(reg);
|
2015-03-18 09:37:42 +00:00
|
|
|
}
|
2015-03-03 10:51:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This function set up the master clock (MCLK).
|
|
|
|
*
|
|
|
|
* Input: Frequency to be set.
|
|
|
|
*
|
|
|
|
* NOTE:
|
|
|
|
* The maximum frequency the engine can run is 168MHz.
|
|
|
|
*/
|
2016-10-13 22:25:52 +00:00
|
|
|
static void set_master_clock(unsigned int frequency)
|
2015-03-03 10:51:06 +00:00
|
|
|
{
|
2016-01-17 18:04:26 +00:00
|
|
|
unsigned int reg, divisor;
|
2015-10-22 06:38:39 +00:00
|
|
|
|
2016-10-23 02:51:29 +00:00
|
|
|
/*
|
|
|
|
* Cheok_0509: For SM750LE, the memory clock is fixed.
|
2016-06-01 20:34:21 +00:00
|
|
|
* Nothing to set.
|
|
|
|
*/
|
2016-09-25 19:58:35 +00:00
|
|
|
if (sm750_get_chip_type() == SM750LE)
|
2015-03-03 10:51:06 +00:00
|
|
|
return;
|
2015-10-22 06:38:39 +00:00
|
|
|
|
2015-04-02 17:31:04 +00:00
|
|
|
if (frequency) {
|
2016-10-23 02:51:29 +00:00
|
|
|
/*
|
|
|
|
* Set the frequency to the maximum frequency
|
2016-09-15 20:16:11 +00:00
|
|
|
* that the SM750 engine can run, which is about 190 MHz.
|
|
|
|
*/
|
2015-03-18 09:37:42 +00:00
|
|
|
if (frequency > MHz(190))
|
|
|
|
frequency = MHz(190);
|
|
|
|
|
|
|
|
/* Calculate the divisor */
|
2016-10-02 11:04:46 +00:00
|
|
|
divisor = DIV_ROUND_CLOSEST(get_mxclk_freq(), frequency);
|
2015-03-18 09:37:42 +00:00
|
|
|
|
|
|
|
/* Set the corresponding divisor in the register. */
|
2017-02-08 06:48:43 +00:00
|
|
|
reg = peek32(CURRENT_GATE) & ~CURRENT_GATE_MCLK_MASK;
|
2015-03-26 17:09:17 +00:00
|
|
|
switch (divisor) {
|
2015-03-18 09:37:42 +00:00
|
|
|
default:
|
|
|
|
case 3:
|
2016-01-17 18:04:27 +00:00
|
|
|
reg |= CURRENT_GATE_MCLK_DIV_3;
|
2015-03-18 09:37:42 +00:00
|
|
|
break;
|
|
|
|
case 4:
|
2016-01-17 18:04:27 +00:00
|
|
|
reg |= CURRENT_GATE_MCLK_DIV_4;
|
2015-03-18 09:37:42 +00:00
|
|
|
break;
|
|
|
|
case 6:
|
2016-01-17 18:04:27 +00:00
|
|
|
reg |= CURRENT_GATE_MCLK_DIV_6;
|
2015-03-18 09:37:42 +00:00
|
|
|
break;
|
|
|
|
case 8:
|
2016-01-17 18:04:27 +00:00
|
|
|
reg |= CURRENT_GATE_MCLK_DIV_8;
|
2015-03-18 09:37:42 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2016-11-09 09:26:27 +00:00
|
|
|
sm750_set_current_gate(reg);
|
2017-05-16 09:20:17 +00:00
|
|
|
}
|
2015-03-03 10:51:06 +00:00
|
|
|
}
|
|
|
|
|
2016-10-13 22:25:52 +00:00
|
|
|
unsigned int ddk750_get_vm_size(void)
|
2015-03-03 10:51:06 +00:00
|
|
|
{
|
|
|
|
unsigned int reg;
|
|
|
|
unsigned int data;
|
|
|
|
|
|
|
|
/* sm750le only use 64 mb memory*/
|
2016-09-25 19:58:35 +00:00
|
|
|
if (sm750_get_chip_type() == SM750LE)
|
2015-09-22 09:01:17 +00:00
|
|
|
return SZ_64M;
|
2015-03-03 10:51:06 +00:00
|
|
|
|
|
|
|
/* for 750,always use power mode0*/
|
2017-02-08 06:48:43 +00:00
|
|
|
reg = peek32(MODE0_GATE);
|
2016-01-17 18:04:28 +00:00
|
|
|
reg |= MODE0_GATE_GPIO;
|
2017-02-08 06:48:43 +00:00
|
|
|
poke32(MODE0_GATE, reg);
|
2015-03-03 10:51:06 +00:00
|
|
|
|
|
|
|
/* get frame buffer size from GPIO */
|
2017-02-08 06:48:43 +00:00
|
|
|
reg = peek32(MISC_CTRL) & MISC_CTRL_LOCALMEM_SIZE_MASK;
|
2015-03-26 17:09:17 +00:00
|
|
|
switch (reg) {
|
2015-03-26 17:09:19 +00:00
|
|
|
case MISC_CTRL_LOCALMEM_SIZE_8M:
|
2015-09-22 09:01:17 +00:00
|
|
|
data = SZ_8M; break; /* 8 Mega byte */
|
2015-03-26 17:09:19 +00:00
|
|
|
case MISC_CTRL_LOCALMEM_SIZE_16M:
|
2015-09-22 09:01:17 +00:00
|
|
|
data = SZ_16M; break; /* 16 Mega byte */
|
2015-03-26 17:09:19 +00:00
|
|
|
case MISC_CTRL_LOCALMEM_SIZE_32M:
|
2015-09-22 09:01:17 +00:00
|
|
|
data = SZ_32M; break; /* 32 Mega byte */
|
2015-03-26 17:09:19 +00:00
|
|
|
case MISC_CTRL_LOCALMEM_SIZE_64M:
|
2015-09-22 09:01:17 +00:00
|
|
|
data = SZ_64M; break; /* 64 Mega byte */
|
2015-03-26 17:09:19 +00:00
|
|
|
default:
|
2015-04-02 17:27:55 +00:00
|
|
|
data = 0;
|
|
|
|
break;
|
2015-03-03 10:51:06 +00:00
|
|
|
}
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
2016-10-13 22:25:52 +00:00
|
|
|
int ddk750_init_hw(struct initchip_param *pInitParam)
|
2015-03-03 10:51:06 +00:00
|
|
|
{
|
2016-01-17 18:04:20 +00:00
|
|
|
unsigned int reg;
|
2015-03-03 10:51:06 +00:00
|
|
|
|
2015-07-15 04:14:32 +00:00
|
|
|
if (pInitParam->powerMode != 0)
|
2015-03-03 10:51:06 +00:00
|
|
|
pInitParam->powerMode = 0;
|
2016-11-09 09:26:27 +00:00
|
|
|
sm750_set_power_mode(pInitParam->powerMode);
|
2015-03-03 10:51:06 +00:00
|
|
|
|
|
|
|
/* Enable display power gate & LOCALMEM power gate*/
|
2017-02-08 06:48:43 +00:00
|
|
|
reg = peek32(CURRENT_GATE);
|
2016-01-17 18:04:25 +00:00
|
|
|
reg |= (CURRENT_GATE_DISPLAY | CURRENT_GATE_LOCALMEM);
|
2016-11-09 09:26:27 +00:00
|
|
|
sm750_set_current_gate(reg);
|
2015-03-03 10:51:06 +00:00
|
|
|
|
2016-09-25 19:58:35 +00:00
|
|
|
if (sm750_get_chip_type() != SM750LE) {
|
2017-05-16 09:20:17 +00:00
|
|
|
/* set panel pll and graphic mode via mmio_88 */
|
2017-02-08 06:48:43 +00:00
|
|
|
reg = peek32(VGA_CONFIGURATION);
|
2016-02-10 16:34:00 +00:00
|
|
|
reg |= (VGA_CONFIGURATION_PLL | VGA_CONFIGURATION_MODE);
|
2017-02-08 06:48:43 +00:00
|
|
|
poke32(VGA_CONFIGURATION, reg);
|
2015-03-26 17:09:14 +00:00
|
|
|
} else {
|
2015-04-08 16:55:06 +00:00
|
|
|
#if defined(__i386__) || defined(__x86_64__)
|
2015-03-03 10:51:06 +00:00
|
|
|
/* set graphic mode via IO method */
|
2015-03-26 17:09:18 +00:00
|
|
|
outb_p(0x88, 0x3d4);
|
|
|
|
outb_p(0x06, 0x3d5);
|
2015-03-03 10:51:06 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set the Main Chip Clock */
|
2016-10-13 22:25:52 +00:00
|
|
|
set_chip_clock(MHz((unsigned int)pInitParam->chipClock));
|
2015-03-03 10:51:06 +00:00
|
|
|
|
|
|
|
/* Set up memory clock. */
|
2016-10-13 22:25:52 +00:00
|
|
|
set_memory_clock(MHz(pInitParam->memClock));
|
2015-03-03 10:51:06 +00:00
|
|
|
|
|
|
|
/* Set up master clock */
|
2016-10-13 22:25:52 +00:00
|
|
|
set_master_clock(MHz(pInitParam->masterClock));
|
2015-03-03 10:51:06 +00:00
|
|
|
|
2016-10-23 02:51:29 +00:00
|
|
|
/*
|
|
|
|
* Reset the memory controller.
|
2016-09-15 20:16:11 +00:00
|
|
|
* If the memory controller is not reset in SM750,
|
|
|
|
* the system might hang when sw accesses the memory.
|
|
|
|
* The memory should be resetted after changing the MXCLK.
|
2015-03-03 10:51:06 +00:00
|
|
|
*/
|
2015-03-26 17:09:14 +00:00
|
|
|
if (pInitParam->resetMemory == 1) {
|
2017-02-08 06:48:43 +00:00
|
|
|
reg = peek32(MISC_CTRL);
|
2016-01-17 18:04:21 +00:00
|
|
|
reg &= ~MISC_CTRL_LOCALMEM_RESET;
|
2017-02-08 06:48:43 +00:00
|
|
|
poke32(MISC_CTRL, reg);
|
2015-03-03 10:51:06 +00:00
|
|
|
|
2016-01-17 18:04:21 +00:00
|
|
|
reg |= MISC_CTRL_LOCALMEM_RESET;
|
2017-02-08 06:48:43 +00:00
|
|
|
poke32(MISC_CTRL, reg);
|
2015-03-03 10:51:06 +00:00
|
|
|
}
|
|
|
|
|
2015-03-26 17:09:14 +00:00
|
|
|
if (pInitParam->setAllEngOff == 1) {
|
2016-11-09 09:26:27 +00:00
|
|
|
sm750_enable_2d_engine(0);
|
2015-03-03 10:51:06 +00:00
|
|
|
|
|
|
|
/* Disable Overlay, if a former application left it on */
|
2017-02-08 06:48:43 +00:00
|
|
|
reg = peek32(VIDEO_DISPLAY_CTRL);
|
2016-02-10 16:34:08 +00:00
|
|
|
reg &= ~DISPLAY_CTRL_PLANE;
|
2017-02-08 06:48:43 +00:00
|
|
|
poke32(VIDEO_DISPLAY_CTRL, reg);
|
2015-03-03 10:51:06 +00:00
|
|
|
|
|
|
|
/* Disable video alpha, if a former application left it on */
|
2017-02-08 06:48:43 +00:00
|
|
|
reg = peek32(VIDEO_ALPHA_DISPLAY_CTRL);
|
2016-02-10 16:34:08 +00:00
|
|
|
reg &= ~DISPLAY_CTRL_PLANE;
|
2017-02-08 06:48:43 +00:00
|
|
|
poke32(VIDEO_ALPHA_DISPLAY_CTRL, reg);
|
2015-03-03 10:51:06 +00:00
|
|
|
|
|
|
|
/* Disable alpha plane, if a former application left it on */
|
2017-02-08 06:48:43 +00:00
|
|
|
reg = peek32(ALPHA_DISPLAY_CTRL);
|
2016-02-10 16:34:08 +00:00
|
|
|
reg &= ~DISPLAY_CTRL_PLANE;
|
2017-02-08 06:48:43 +00:00
|
|
|
poke32(ALPHA_DISPLAY_CTRL, reg);
|
2015-03-03 10:51:06 +00:00
|
|
|
|
|
|
|
/* Disable DMA Channel, if a former application left it on */
|
2017-02-08 06:48:43 +00:00
|
|
|
reg = peek32(DMA_ABORT_INTERRUPT);
|
2016-02-10 16:34:17 +00:00
|
|
|
reg |= DMA_ABORT_INTERRUPT_ABORT_1;
|
2017-02-08 06:48:43 +00:00
|
|
|
poke32(DMA_ABORT_INTERRUPT, reg);
|
2015-03-03 10:51:06 +00:00
|
|
|
|
|
|
|
/* Disable DMA Power, if a former application left it on */
|
2016-11-09 09:26:27 +00:00
|
|
|
sm750_enable_dma(0);
|
2015-03-03 10:51:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* We can add more initialization as needed. */
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2016-09-15 20:16:11 +00:00
|
|
|
* monk liu @ 4/6/2011:
|
|
|
|
* re-write the calculatePLL function of ddk750.
|
|
|
|
* the original version function does not use
|
|
|
|
* some mathematics tricks and shortcut
|
|
|
|
* when it doing the calculation of the best N,M,D combination
|
|
|
|
* I think this version gives a little upgrade in speed
|
|
|
|
*
|
|
|
|
* 750 pll clock formular:
|
|
|
|
* Request Clock = (Input Clock * M )/(N * X)
|
|
|
|
*
|
|
|
|
* Input Clock = 14318181 hz
|
|
|
|
* X = 2 power D
|
|
|
|
* D ={0,1,2,3,4,5,6}
|
|
|
|
* M = {1,...,255}
|
|
|
|
* N = {2,...,15}
|
|
|
|
*/
|
2017-05-16 09:20:17 +00:00
|
|
|
unsigned int sm750_calc_pll_value(unsigned int request_orig,
|
|
|
|
struct pll_value *pll)
|
2015-03-03 10:51:06 +00:00
|
|
|
{
|
2016-10-23 02:51:29 +00:00
|
|
|
/*
|
|
|
|
* as sm750 register definition,
|
2016-09-15 20:15:50 +00:00
|
|
|
* N located in 2,15 and M located in 1,255
|
|
|
|
*/
|
2015-03-26 17:09:18 +00:00
|
|
|
int N, M, X, d;
|
2015-10-09 20:44:27 +00:00
|
|
|
int mini_diff;
|
2015-03-26 17:09:18 +00:00
|
|
|
unsigned int RN, quo, rem, fl_quo;
|
|
|
|
unsigned int input, request;
|
|
|
|
unsigned int tmpClock, ret;
|
2015-10-22 06:38:40 +00:00
|
|
|
const int max_OD = 3;
|
2016-03-29 16:53:23 +00:00
|
|
|
int max_d = 6;
|
2015-03-03 10:51:06 +00:00
|
|
|
|
2016-09-25 19:58:35 +00:00
|
|
|
if (sm750_get_chip_type() == SM750LE) {
|
2016-10-23 02:51:29 +00:00
|
|
|
/*
|
|
|
|
* SM750LE don't have
|
2016-09-15 20:16:11 +00:00
|
|
|
* programmable PLL and M/N values to work on.
|
|
|
|
* Just return the requested clock.
|
|
|
|
*/
|
2015-03-18 09:37:42 +00:00
|
|
|
return request_orig;
|
|
|
|
}
|
2015-03-03 10:51:06 +00:00
|
|
|
|
|
|
|
ret = 0;
|
2015-10-09 20:44:27 +00:00
|
|
|
mini_diff = ~0;
|
2015-03-03 10:51:06 +00:00
|
|
|
request = request_orig / 1000;
|
|
|
|
input = pll->inputFreq / 1000;
|
|
|
|
|
2016-10-23 02:51:29 +00:00
|
|
|
/*
|
|
|
|
* for MXCLK register,
|
2016-09-15 20:15:50 +00:00
|
|
|
* no POD provided, so need be treated differently
|
|
|
|
*/
|
2015-10-22 06:38:40 +00:00
|
|
|
if (pll->clockType == MXCLK_PLL)
|
|
|
|
max_d = 3;
|
2015-03-03 10:51:06 +00:00
|
|
|
|
2015-03-26 17:09:15 +00:00
|
|
|
for (N = 15; N > 1; N--) {
|
2016-10-23 02:51:29 +00:00
|
|
|
/*
|
|
|
|
* RN will not exceed maximum long
|
2016-09-15 20:15:50 +00:00
|
|
|
* if @request <= 285 MHZ (for 32bit cpu)
|
|
|
|
*/
|
2015-03-03 10:51:06 +00:00
|
|
|
RN = N * request;
|
|
|
|
quo = RN / input;
|
|
|
|
rem = RN % input;/* rem always small than 14318181 */
|
2017-03-04 12:56:02 +00:00
|
|
|
fl_quo = rem * 10000 / input;
|
2015-03-03 10:51:06 +00:00
|
|
|
|
2015-10-22 06:38:40 +00:00
|
|
|
for (d = max_d; d >= 0; d--) {
|
2016-09-20 12:06:29 +00:00
|
|
|
X = BIT(d);
|
2015-10-04 14:42:30 +00:00
|
|
|
M = quo * X;
|
2015-03-03 10:51:06 +00:00
|
|
|
M += fl_quo * X / 10000;
|
|
|
|
/* round step */
|
2015-10-04 14:48:32 +00:00
|
|
|
M += (fl_quo * X % 10000) > 5000 ? 1 : 0;
|
2015-03-26 17:09:16 +00:00
|
|
|
if (M < 256 && M > 0) {
|
2015-03-03 10:51:06 +00:00
|
|
|
unsigned int diff;
|
2015-07-15 04:14:48 +00:00
|
|
|
|
2015-07-15 04:14:40 +00:00
|
|
|
tmpClock = pll->inputFreq * M / N / X;
|
2016-02-19 15:56:13 +00:00
|
|
|
diff = abs(tmpClock - request_orig);
|
2015-10-09 20:44:27 +00:00
|
|
|
if (diff < mini_diff) {
|
2015-03-03 10:51:06 +00:00
|
|
|
pll->M = M;
|
|
|
|
pll->N = N;
|
2015-10-22 06:38:40 +00:00
|
|
|
pll->POD = 0;
|
|
|
|
if (d > max_OD)
|
|
|
|
pll->POD = d - max_OD;
|
|
|
|
pll->OD = d - pll->POD;
|
2015-10-09 20:44:27 +00:00
|
|
|
mini_diff = diff;
|
2015-03-03 10:51:06 +00:00
|
|
|
ret = tmpClock;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-11-09 09:26:27 +00:00
|
|
|
unsigned int sm750_format_pll_reg(struct pll_value *pPLL)
|
2015-03-03 10:51:06 +00:00
|
|
|
{
|
2016-02-10 16:33:58 +00:00
|
|
|
#ifndef VALIDATION_CHIP
|
|
|
|
unsigned int POD = pPLL->POD;
|
|
|
|
#endif
|
|
|
|
unsigned int OD = pPLL->OD;
|
|
|
|
unsigned int M = pPLL->M;
|
|
|
|
unsigned int N = pPLL->N;
|
2016-02-10 16:33:53 +00:00
|
|
|
unsigned int reg = 0;
|
2015-03-03 10:51:06 +00:00
|
|
|
|
2016-02-10 16:33:54 +00:00
|
|
|
/*
|
|
|
|
* Note that all PLL's have the same format. Here, we just use
|
|
|
|
* Panel PLL parameter to work out the bit fields in the
|
|
|
|
* register. On returning a 32 bit number, the value can be
|
|
|
|
* applied to any PLL in the calling function.
|
|
|
|
*/
|
2016-02-10 16:33:58 +00:00
|
|
|
reg = PLL_CTRL_POWER |
|
2015-03-03 10:51:06 +00:00
|
|
|
#ifndef VALIDATION_CHIP
|
2016-02-10 16:33:58 +00:00
|
|
|
((POD << PLL_CTRL_POD_SHIFT) & PLL_CTRL_POD_MASK) |
|
2015-03-03 10:51:06 +00:00
|
|
|
#endif
|
2016-02-10 16:33:58 +00:00
|
|
|
((OD << PLL_CTRL_OD_SHIFT) & PLL_CTRL_OD_MASK) |
|
|
|
|
((N << PLL_CTRL_N_SHIFT) & PLL_CTRL_N_MASK) |
|
|
|
|
((M << PLL_CTRL_M_SHIFT) & PLL_CTRL_M_MASK);
|
2015-03-03 10:51:06 +00:00
|
|
|
|
2016-02-10 16:33:53 +00:00
|
|
|
return reg;
|
2015-03-03 10:51:06 +00:00
|
|
|
}
|