- Add clk_set_source_freq field to struct ti_clock_dev so clock device

consumers can configure clock frequency
- Add ti_prcm_clk_set_source_freq wrapper for clk_set_source_freq
- Add am335x_clk_set_arm_disp_freq function to control pixel clock
   frequency for LCD and HDMI output. Both of them are sensitive
   to frequency skews and we need to get pixel clock matching requested
   frequency as close to possible
This commit is contained in:
Oleksandr Tymoshenko 2015-06-17 23:26:00 +00:00
parent 1e68ee21e0
commit a08b6d1141
4 changed files with 113 additions and 29 deletions

View File

@ -151,6 +151,7 @@ static int am335x_clk_hsmmc_get_source_freq(struct ti_clock_dev *clkdev, unsign
static int am335x_clk_get_sysclk_freq(struct ti_clock_dev *clkdev, unsigned int *freq);
static int am335x_clk_get_arm_fclk_freq(struct ti_clock_dev *clkdev, unsigned int *freq);
static int am335x_clk_get_arm_disp_freq(struct ti_clock_dev *clkdev, unsigned int *freq);
static int am335x_clk_set_arm_disp_freq(struct ti_clock_dev *clkdev, unsigned int freq);
static void am335x_prcm_reset(void);
static int am335x_clk_cpsw_activate(struct ti_clock_dev *clkdev);
static int am335x_clk_musb0_activate(struct ti_clock_dev *clkdev);
@ -163,7 +164,8 @@ static int am335x_clk_pruss_activate(struct ti_clock_dev *clkdev);
.clk_deactivate = am335x_clk_noop_deactivate, \
.clk_set_source = am335x_clk_noop_set_source, \
.clk_accessible = NULL, \
.clk_get_source_freq = NULL \
.clk_get_source_freq = NULL, \
.clk_set_source_freq = NULL \
}
#define AM335X_GENERIC_CLOCK_DEV(i) \
@ -172,7 +174,8 @@ static int am335x_clk_pruss_activate(struct ti_clock_dev *clkdev);
.clk_deactivate = am335x_clk_generic_deactivate, \
.clk_set_source = am335x_clk_generic_set_source, \
.clk_accessible = NULL, \
.clk_get_source_freq = NULL \
.clk_get_source_freq = NULL, \
.clk_set_source_freq = NULL \
}
#define AM335X_GPIO_CLOCK_DEV(i) \
@ -181,7 +184,8 @@ static int am335x_clk_pruss_activate(struct ti_clock_dev *clkdev);
.clk_deactivate = am335x_clk_generic_deactivate, \
.clk_set_source = am335x_clk_generic_set_source, \
.clk_accessible = NULL, \
.clk_get_source_freq = NULL \
.clk_get_source_freq = NULL, \
.clk_set_source_freq = NULL \
}
#define AM335X_MMCHS_CLOCK_DEV(i) \
@ -190,7 +194,8 @@ static int am335x_clk_pruss_activate(struct ti_clock_dev *clkdev);
.clk_deactivate = am335x_clk_generic_deactivate, \
.clk_set_source = am335x_clk_generic_set_source, \
.clk_accessible = NULL, \
.clk_get_source_freq = am335x_clk_hsmmc_get_source_freq \
.clk_get_source_freq = am335x_clk_hsmmc_get_source_freq, \
.clk_set_source_freq = NULL \
}
struct ti_clock_dev ti_am335x_clk_devmap[] = {
@ -201,6 +206,7 @@ struct ti_clock_dev ti_am335x_clk_devmap[] = {
.clk_set_source = NULL,
.clk_accessible = NULL,
.clk_get_source_freq = am335x_clk_get_sysclk_freq,
.clk_set_source_freq = NULL,
},
/* MPU (ARM) core clocks */
{ .id = MPU_CLK,
@ -209,6 +215,7 @@ struct ti_clock_dev ti_am335x_clk_devmap[] = {
.clk_set_source = NULL,
.clk_accessible = NULL,
.clk_get_source_freq = am335x_clk_get_arm_fclk_freq,
.clk_set_source_freq = NULL,
},
/* CPSW Ethernet Switch core clocks */
{ .id = CPSW_CLK,
@ -217,6 +224,7 @@ struct ti_clock_dev ti_am335x_clk_devmap[] = {
.clk_set_source = NULL,
.clk_accessible = NULL,
.clk_get_source_freq = NULL,
.clk_set_source_freq = NULL,
},
/* Mentor USB HS controller core clocks */
@ -226,6 +234,7 @@ struct ti_clock_dev ti_am335x_clk_devmap[] = {
.clk_set_source = NULL,
.clk_accessible = NULL,
.clk_get_source_freq = NULL,
.clk_set_source_freq = NULL,
},
/* LCD controller clocks */
@ -235,6 +244,7 @@ struct ti_clock_dev ti_am335x_clk_devmap[] = {
.clk_set_source = NULL,
.clk_accessible = NULL,
.clk_get_source_freq = am335x_clk_get_arm_disp_freq,
.clk_set_source_freq = am335x_clk_set_arm_disp_freq,
},
/* UART */
@ -296,6 +306,7 @@ struct ti_clock_dev ti_am335x_clk_devmap[] = {
.clk_set_source = NULL,
.clk_accessible = NULL,
.clk_get_source_freq = NULL,
.clk_set_source_freq = NULL,
},
/* RTC */
@ -627,6 +638,8 @@ am335x_clk_get_sysclk_freq(struct ti_clock_dev *clkdev, unsigned int *freq)
#define DPLL_BYP_CLKSEL(reg) ((reg>>23) & 1)
#define DPLL_DIV(reg) ((reg & 0x7f)+1)
#define DPLL_MULT(reg) ((reg>>8) & 0x7FF)
#define DPLL_MAX_MUL 0x800
#define DPLL_MAX_DIV 0x80
static int
am335x_clk_get_arm_fclk_freq(struct ti_clock_dev *clkdev, unsigned int *freq)
@ -662,6 +675,52 @@ am335x_clk_get_arm_disp_freq(struct ti_clock_dev *clkdev, unsigned int *freq)
return(0);
}
static int
am335x_clk_set_arm_disp_freq(struct ti_clock_dev *clkdev, unsigned int freq)
{
uint32_t sysclk;
uint32_t mul, div;
uint32_t i, j;
unsigned int delta, min_delta;
am335x_clk_get_sysclk_freq(NULL, &sysclk);
/* Bypass mode */
prcm_write_4(CM_WKUP_CM_CLKMODE_DPLL_DISP, 0x4);
/* Make sure it's in bypass mode */
while (!(prcm_read_4(CM_WKUP_CM_IDLEST_DPLL_DISP)
& (1 << 8)))
DELAY(10);
/* Dumb and non-optimal implementation */
min_delta = freq;
for (i = 1; i < DPLL_MAX_MUL; i++) {
for (j = 1; j < DPLL_MAX_DIV; j++) {
delta = abs(freq - i*(sysclk/j));
if (delta < min_delta) {
mul = i;
div = j;
min_delta = delta;
}
if (min_delta == 0)
break;
}
}
prcm_write_4(CM_WKUP_CM_CLKSEL_DPLL_DISP, (mul << 8) | (div - 1));
/* Locked mode */
prcm_write_4(CM_WKUP_CM_CLKMODE_DPLL_DISP, 0x7);
int timeout = 10000;
while ((!(prcm_read_4(CM_WKUP_CM_IDLEST_DPLL_DISP)
& (1 << 0))) && timeout--)
DELAY(10);
return(0);
}
static void
am335x_prcm_reset(void)
{
@ -724,27 +783,10 @@ am335x_clk_lcdc_activate(struct ti_clock_dev *clkdev)
if (sc == NULL)
return (ENXIO);
/* Bypass mode */
prcm_write_4(CM_WKUP_CM_CLKMODE_DPLL_DISP, 0x4);
/* Make sure it's in bypass mode */
while (!(prcm_read_4(CM_WKUP_CM_IDLEST_DPLL_DISP)
& (1 << 8)))
DELAY(10);
/*
* For now set frequency to 99*SYSFREQ/8 which is twice as
* HDMI 1080p pixel clock (minimum LCDC freq divisor is 2)
* For now set frequency to 2*VGA_PIXEL_CLOCK
*/
prcm_write_4(CM_WKUP_CM_CLKSEL_DPLL_DISP, (99 << 8) | 8);
/* Locked mode */
prcm_write_4(CM_WKUP_CM_CLKMODE_DPLL_DISP, 0x7);
int timeout = 10000;
while ((!(prcm_read_4(CM_WKUP_CM_IDLEST_DPLL_DISP)
& (1 << 0))) && timeout--)
DELAY(10);
am335x_clk_set_arm_disp_freq(clkdev, 25175000*2);
/*set MODULEMODE to ENABLE(2) */
prcm_write_4(CM_PER_LCDC_CLKCTRL, 2);

View File

@ -217,7 +217,8 @@ static int omap4_clk_get_arm_fclk_freq(struct ti_clock_dev *clkdev, unsigned int
.clk_deactivate = omap4_clk_generic_deactivate, \
.clk_set_source = omap4_clk_generic_set_source, \
.clk_accessible = omap4_clk_generic_accessible, \
.clk_get_source_freq = omap4_clk_generic_get_source_freq \
.clk_get_source_freq = omap4_clk_generic_get_source_freq, \
.clk_set_source_freq = NULL \
}
#define OMAP4_GPTIMER_CLOCK_DEV(i) \
@ -226,7 +227,8 @@ static int omap4_clk_get_arm_fclk_freq(struct ti_clock_dev *clkdev, unsigned int
.clk_deactivate = omap4_clk_generic_deactivate, \
.clk_set_source = omap4_clk_gptimer_set_source, \
.clk_accessible = omap4_clk_generic_accessible, \
.clk_get_source_freq = omap4_clk_gptimer_get_source_freq \
.clk_get_source_freq = omap4_clk_gptimer_get_source_freq, \
.clk_set_source_freq = NULL \
}
#define OMAP4_HSMMC_CLOCK_DEV(i) \
@ -235,7 +237,8 @@ static int omap4_clk_get_arm_fclk_freq(struct ti_clock_dev *clkdev, unsigned int
.clk_deactivate = omap4_clk_generic_deactivate, \
.clk_set_source = omap4_clk_hsmmc_set_source, \
.clk_accessible = omap4_clk_generic_accessible, \
.clk_get_source_freq = omap4_clk_hsmmc_get_source_freq \
.clk_get_source_freq = omap4_clk_hsmmc_get_source_freq, \
.clk_set_source_freq = NULL \
}
#define OMAP4_HSUSBHOST_CLOCK_DEV(i) \
@ -244,7 +247,8 @@ static int omap4_clk_get_arm_fclk_freq(struct ti_clock_dev *clkdev, unsigned int
.clk_deactivate = omap4_clk_hsusbhost_deactivate, \
.clk_set_source = omap4_clk_hsusbhost_set_source, \
.clk_accessible = omap4_clk_hsusbhost_accessible, \
.clk_get_source_freq = NULL \
.clk_get_source_freq = NULL, \
.clk_set_source_freq = NULL \
}
@ -257,6 +261,7 @@ struct ti_clock_dev ti_omap4_clk_devmap[] = {
.clk_set_source = NULL,
.clk_accessible = NULL,
.clk_get_source_freq = omap4_clk_get_sysclk_freq,
.clk_set_source_freq = NULL,
},
/* MPU (ARM) core clocks */
{ .id = MPU_CLK,
@ -265,6 +270,7 @@ struct ti_clock_dev ti_omap4_clk_devmap[] = {
.clk_set_source = NULL,
.clk_accessible = NULL,
.clk_get_source_freq = omap4_clk_get_arm_fclk_freq,
.clk_set_source_freq = NULL,
},

View File

@ -285,7 +285,7 @@ ti_prcm_clk_set_source(clk_ident_t clk, clk_src_t clksrc)
* @clk: identifier for the module to enable, see ti_prcm.h for a list
* of possible modules.
* @freq: pointer to an integer that upon return will contain the src freq
*
*
* This function returns the frequency of the source clock.
*
* The real work done to enable the clock is really done in the callback
@ -319,6 +319,39 @@ ti_prcm_clk_get_source_freq(clk_ident_t clk, unsigned int *freq)
ret = clk_dev->clk_get_source_freq(clk_dev, freq);
else
ret = EINVAL;
return (ret);
}
/**
* ti_prcm_clk_set_source_freq - sets the source clock frequency as close to freq as possible
* @clk: identifier for the module to enable, see ti_prcm.h for a list
* of possible modules.
* @freq: requested freq
*
* LOCKING:
* Internally locks the driver context.
*
* RETURNS:
* Returns 0 on success or positive error code on failure.
*/
int
ti_prcm_clk_set_source_freq(clk_ident_t clk, unsigned int freq)
{
struct ti_clock_dev *clk_dev;
int ret;
clk_dev = ti_prcm_clk_dev(clk);
/* Sanity check we managed to find the clock */
if (clk_dev == NULL)
return (EINVAL);
/* Get the source frequency of the clock */
if (clk_dev->clk_set_source_freq)
ret = clk_dev->clk_set_source_freq(clk_dev, freq);
else
ret = EINVAL;
return (ret);
}

View File

@ -184,6 +184,8 @@ struct ti_clock_dev {
int (*clk_set_source)(struct ti_clock_dev *clkdev,
clk_src_t clksrc);
int (*clk_accessible)(struct ti_clock_dev *clkdev);
int (*clk_set_source_freq)(struct ti_clock_dev *clkdev,
unsigned int freq);
int (*clk_get_source_freq)(struct ti_clock_dev *clkdev,
unsigned int *freq);
};
@ -194,6 +196,7 @@ int ti_prcm_clk_disable(clk_ident_t clk);
int ti_prcm_clk_accessible(clk_ident_t clk);
int ti_prcm_clk_disable_autoidle(clk_ident_t clk);
int ti_prcm_clk_set_source(clk_ident_t clk, clk_src_t clksrc);
int ti_prcm_clk_set_source_freq(clk_ident_t clk, unsigned int freq);
int ti_prcm_clk_get_source_freq(clk_ident_t clk, unsigned int *freq);
void ti_prcm_reset(void);