video: ssd2828: Allow using 'pclk' as the PLL clock source

Instead of using the internal 'tx_clk' clock source, it is also
possible to use the pixel clock signal from the parallel LCD
interface ('pclk') as the reference clock for PLL.

The 'tx_clk' clock speed may be different on different boards/devices
(the allowed range is 8MHz - 30MHz). Which is not very convenient,
especially considering the need to know the exact 'tx_clk' clock
speed. This clock speed may be difficult to identify without having
device schematics and/or accurate documentation/sources every time.

Using 'pclk' is free from all these problems.

Signed-off-by: Siarhei Siamashka <siarhei.siamashka@gmail.com>
Acked-by: Anatolij Gustschin <agust@denx.de>
Acked-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
This commit is contained in:
Siarhei Siamashka 2015-01-19 05:23:35 +02:00 committed by Hans de Goede
parent aaa6ac5eab
commit dddccd6913
3 changed files with 28 additions and 7 deletions

View file

@ -19,12 +19,14 @@ config VIDEO_LCD_SSD2828
config VIDEO_LCD_SSD2828_TX_CLK config VIDEO_LCD_SSD2828_TX_CLK
int "SSD2828 TX_CLK frequency (in MHz)" int "SSD2828 TX_CLK frequency (in MHz)"
depends on VIDEO_LCD_SSD2828 depends on VIDEO_LCD_SSD2828
default 0
---help--- ---help---
The frequency of the crystal, which is clocking SSD2828. It may be The frequency of the crystal, which is clocking SSD2828. It may be
anything in the 8MHz-30MHz range and the exact value should be anything in the 8MHz-30MHz range and the exact value should be
retrieved from the board schematics. Or in the case of Allwinner retrieved from the board schematics. Or in the case of Allwinner
hardware, it can be usually found as 'lcd_xtal_freq' variable in hardware, it can be usually found as 'lcd_xtal_freq' variable in
FEX files. FEX files. It can be also set to 0 for selecting PCLK from the
parallel LCD interface instead of TX_CLK as the PLL clock source.
config VIDEO_LCD_SSD2828_RESET config VIDEO_LCD_SSD2828_RESET
string "RESET pin of SSD2828" string "RESET pin of SSD2828"

View file

@ -340,7 +340,7 @@ static int ssd2828_configure_video_interface(const struct ssd2828_config *cfg,
int ssd2828_init(const struct ssd2828_config *cfg, int ssd2828_init(const struct ssd2828_config *cfg,
const struct ctfb_res_modes *mode) const struct ctfb_res_modes *mode)
{ {
u32 lp_div, pll_freq_kbps, pll_config; u32 lp_div, pll_freq_kbps, reference_freq_khz, pll_config;
/* The LP clock speed is limited by 10MHz */ /* The LP clock speed is limited by 10MHz */
const u32 mipi_dsi_low_power_clk_khz = 10000; const u32 mipi_dsi_low_power_clk_khz = 10000;
/* /*
@ -373,6 +373,20 @@ int ssd2828_init(const struct ssd2828_config *cfg,
} }
} }
/*
* Pick the reference clock for PLL. If we know the exact 'tx_clk'
* clock speed, then everything is good. If not, then we can fallback
* to 'pclk' (pixel clock from the parallel LCD interface). In the
* case of using this fallback, it is necessary to have parallel LCD
* already initialized and running at this point.
*/
reference_freq_khz = cfg->ssd2828_tx_clk_khz;
if (reference_freq_khz == 0) {
reference_freq_khz = mode->pixclock_khz;
/* Use 'pclk' as the reference clock for PLL */
cfgr_reg |= SSD2828_CFGR_CSS;
}
/* /*
* Setup the parallel LCD timings in the appropriate registers. * Setup the parallel LCD timings in the appropriate registers.
*/ */
@ -390,10 +404,10 @@ int ssd2828_init(const struct ssd2828_config *cfg,
/* PLL Configuration Register */ /* PLL Configuration Register */
pll_config = construct_pll_config( pll_config = construct_pll_config(
cfg->mipi_dsi_bitrate_per_data_lane_mbps * 1000, cfg->mipi_dsi_bitrate_per_data_lane_mbps * 1000,
cfg->ssd2828_tx_clk_khz); reference_freq_khz);
write_hw_register(cfg, SSD2828_PLCR, pll_config); write_hw_register(cfg, SSD2828_PLCR, pll_config);
pll_freq_kbps = decode_pll_config(pll_config, cfg->ssd2828_tx_clk_khz); pll_freq_kbps = decode_pll_config(pll_config, reference_freq_khz);
lp_div = DIV_ROUND_UP(pll_freq_kbps, mipi_dsi_low_power_clk_khz * 8); lp_div = DIV_ROUND_UP(pll_freq_kbps, mipi_dsi_low_power_clk_khz * 8);
/* VC Control Register */ /* VC Control Register */

View file

@ -47,8 +47,12 @@ struct ssd2828_config {
* to TX_CLK_XIO/TX_CLK_XIN pins), which is necessary at least for * to TX_CLK_XIO/TX_CLK_XIN pins), which is necessary at least for
* clocking SPI after reset. The exact clock speed is not strictly, * clocking SPI after reset. The exact clock speed is not strictly,
* defined, but the datasheet says that it must be somewhere in the * defined, but the datasheet says that it must be somewhere in the
* 8MHz - 30MHz range (see "TX_CLK Timing" section). It is used as * 8MHz - 30MHz range (see "TX_CLK Timing" section). It can be also
* a reference clock for PLL and must be set correctly. * used as a reference clock for PLL. If the exact clock frequency
* is known, then it can be specified here. If it is unknown, or the
* information is not trustworthy, then it can be set to 0.
*
* If unsure, set to 0.
*/ */
int ssd2828_tx_clk_khz; int ssd2828_tx_clk_khz;
@ -115,7 +119,8 @@ struct ssd2828_config {
* The right place to insert this function call is after the parallel LCD * The right place to insert this function call is after the parallel LCD
* interface is initialized and before turning on the backlight. This is * interface is initialized and before turning on the backlight. This is
* advised in the "Example for system sleep in and out" section of the * advised in the "Example for system sleep in and out" section of the
* SSD2828 datasheet. * SSD2828 datasheet. And also SS2828 may use 'pclk' as the clock source
* for PLL, which means that the input signal must be already there.
*/ */
int ssd2828_init(const struct ssd2828_config *cfg, int ssd2828_init(const struct ssd2828_config *cfg,
const struct ctfb_res_modes *mode); const struct ctfb_res_modes *mode);