These series contains a first batch of clock/PLL patches. There is
still a lot to do (and a lot which can't be done due to missing
documentation) but this should be enough to point in the direction
we are heading. More PLL values have been allowed (in fact as much
as can be done without complete documentation for each platform or
using the knowledge Luc encoded in the Unichrome driver).
A bit restructuring was done to allow later moving the PLL/clock
things to it's own file. Also code was added to manage PLL source
and power but is not used yet as it is platform specific (I think)
and we lack any useful abstraction for it at the moment. Some tests
were performed to verify the documentation is not completly wrong.
All patches are also available at
git://github.com/schandinat/linux-2.6.git viafb-pll
and will also show up in linux-next after the early rc's are done.
Thanks,
Florian Tobias Schandinat
As no caller is interested in the result call viafb_get_clk_value
directly from viafb_set_vclock to encapsulate the hardware dependend
stuff there.
Signed-off-by: Florian Tobias Schandinat <[email protected]>
---
drivers/video/via/hw.c | 32 +++++++++++++++++---------------
drivers/video/via/hw.h | 1 -
drivers/video/via/lcd.c | 7 ++-----
3 files changed, 19 insertions(+), 21 deletions(-)
diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c
index 063ff65..c28ae2e 100644
--- a/drivers/video/via/hw.c
+++ b/drivers/video/via/hw.c
@@ -1474,7 +1474,7 @@ static struct pll_config get_pll_config(struct pll_limit *limits, int size,
return best;
}
-u32 viafb_get_clk_value(int clk)
+static u32 viafb_get_clk_value(int clk)
{
u32 value = 0;
@@ -1512,6 +1512,10 @@ u32 viafb_get_clk_value(int clk)
/* Set VCLK*/
void viafb_set_vclock(u32 clk, int set_iga)
{
+ u32 value = viafb_get_clk_value(clk);
+
+ DEBUG_MSG(KERN_INFO "PLL=0x%x", value);
+
/* H.W. Reset : ON */
viafb_write_reg_mask(CR17, VIACR, 0x00, BIT7);
@@ -1520,8 +1524,8 @@ void viafb_set_vclock(u32 clk, int set_iga)
switch (viaparinfo->chip_info->gfx_chip_name) {
case UNICHROME_CLE266:
case UNICHROME_K400:
- via_write_reg(VIASR, SR46, (clk & 0x00FF));
- via_write_reg(VIASR, SR47, (clk & 0xFF00) >> 8);
+ via_write_reg(VIASR, SR46, (value & 0x00FF));
+ via_write_reg(VIASR, SR47, (value & 0xFF00) >> 8);
break;
case UNICHROME_K800:
@@ -1535,9 +1539,9 @@ void viafb_set_vclock(u32 clk, int set_iga)
case UNICHROME_VX800:
case UNICHROME_VX855:
case UNICHROME_VX900:
- via_write_reg(VIASR, SR44, (clk & 0x0000FF));
- via_write_reg(VIASR, SR45, (clk & 0x00FF00) >> 8);
- via_write_reg(VIASR, SR46, (clk & 0xFF0000) >> 16);
+ via_write_reg(VIASR, SR44, (value & 0x0000FF));
+ via_write_reg(VIASR, SR45, (value & 0x00FF00) >> 8);
+ via_write_reg(VIASR, SR46, (value & 0xFF0000) >> 16);
break;
}
}
@@ -1547,8 +1551,8 @@ void viafb_set_vclock(u32 clk, int set_iga)
switch (viaparinfo->chip_info->gfx_chip_name) {
case UNICHROME_CLE266:
case UNICHROME_K400:
- via_write_reg(VIASR, SR44, (clk & 0x00FF));
- via_write_reg(VIASR, SR45, (clk & 0xFF00) >> 8);
+ via_write_reg(VIASR, SR44, (value & 0x00FF));
+ via_write_reg(VIASR, SR45, (value & 0xFF00) >> 8);
break;
case UNICHROME_K800:
@@ -1562,9 +1566,9 @@ void viafb_set_vclock(u32 clk, int set_iga)
case UNICHROME_VX800:
case UNICHROME_VX855:
case UNICHROME_VX900:
- via_write_reg(VIASR, SR4A, (clk & 0x0000FF));
- via_write_reg(VIASR, SR4B, (clk & 0x00FF00) >> 8);
- via_write_reg(VIASR, SR4C, (clk & 0xFF0000) >> 16);
+ via_write_reg(VIASR, SR4A, (value & 0x0000FF));
+ via_write_reg(VIASR, SR4B, (value & 0x00FF00) >> 8);
+ via_write_reg(VIASR, SR4C, (value & 0xFF0000) >> 16);
break;
}
}
@@ -1827,7 +1831,7 @@ void viafb_fill_crtc_timing(struct crt_mode_table *crt_table,
int i;
int index = 0;
int h_addr, v_addr;
- u32 pll_D_N, clock, refresh = viafb_refresh;
+ u32 clock, refresh = viafb_refresh;
if (viafb_SAMM_ON && set_iga == IGA2)
refresh = viafb_refresh1;
@@ -1884,9 +1888,7 @@ void viafb_fill_crtc_timing(struct crt_mode_table *crt_table,
clock = crt_reg.hor_total * crt_reg.ver_total
* crt_table[index].refresh_rate;
- pll_D_N = viafb_get_clk_value(clock);
- DEBUG_MSG(KERN_INFO "PLL=%x", pll_D_N);
- viafb_set_vclock(pll_D_N, set_iga);
+ viafb_set_vclock(clock, set_iga);
}
diff --git a/drivers/video/via/hw.h b/drivers/video/via/hw.h
index 63d8d37..2cdce9b 100644
--- a/drivers/video/via/hw.h
+++ b/drivers/video/via/hw.h
@@ -935,7 +935,6 @@ void viafb_lock_crt(void);
void viafb_unlock_crt(void);
void viafb_load_fetch_count_reg(int h_addr, int bpp_byte, int set_iga);
void viafb_write_regx(struct io_reg RegTable[], int ItemNum);
-u32 viafb_get_clk_value(int clk);
void viafb_load_FIFO_reg(int set_iga, int hor_active, int ver_active);
void viafb_set_dpa_gfx(int output_interface, struct GFX_DPA_SETTING\
*p_gfx_dpa_setting);
diff --git a/drivers/video/via/lcd.c b/drivers/video/via/lcd.c
index 64bc7e7..284e681 100644
--- a/drivers/video/via/lcd.c
+++ b/drivers/video/via/lcd.c
@@ -562,7 +562,7 @@ void viafb_lcd_set_mode(struct crt_mode_table *mode_crt_table,
int set_vres = plvds_setting_info->v_active;
int panel_hres = plvds_setting_info->lcd_panel_hres;
int panel_vres = plvds_setting_info->lcd_panel_vres;
- u32 pll_D_N, clock;
+ u32 clock;
struct display_timing mode_crt_reg, panel_crt_reg;
struct crt_mode_table *panel_crt_table = NULL;
struct VideoModeTable *vmode_tbl = viafb_get_mode(panel_hres,
@@ -613,10 +613,7 @@ void viafb_lcd_set_mode(struct crt_mode_table *mode_crt_table,
viafb_load_FIFO_reg(set_iga, set_hres, set_vres);
fill_lcd_format();
-
- pll_D_N = viafb_get_clk_value(clock);
- DEBUG_MSG(KERN_INFO "PLL=0x%x", pll_D_N);
- viafb_set_vclock(pll_D_N, set_iga);
+ viafb_set_vclock(clock, set_iga);
lcd_patch_skew(plvds_setting_info, plvds_chip_info);
/* If K8M800, enable LCD Prefetch Mode. */
--
1.6.3.2
This patch splits some functionality to extra functions.
Signed-off-by: Florian Tobias Schandinat <[email protected]>
---
drivers/video/via/hw.c | 127 +++++++++++++++++++++++++++++++----------------
1 files changed, 84 insertions(+), 43 deletions(-)
diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c
index c28ae2e..bd28e13 100644
--- a/drivers/video/via/hw.c
+++ b/drivers/video/via/hw.c
@@ -1430,6 +1430,70 @@ static u32 vx855_encode_pll(struct pll_config pll)
| pll.multiplier;
}
+static inline void cle266_set_primary_pll_encoded(u32 data)
+{
+ via_write_reg_mask(VIASR, 0x40, 0x02, 0x02); /* enable reset */
+ via_write_reg(VIASR, 0x46, data & 0xFF);
+ via_write_reg(VIASR, 0x47, (data >> 8) & 0xFF);
+ via_write_reg_mask(VIASR, 0x40, 0x00, 0x02); /* disable reset */
+}
+
+static inline void k800_set_primary_pll_encoded(u32 data)
+{
+ via_write_reg_mask(VIASR, 0x40, 0x02, 0x02); /* enable reset */
+ via_write_reg(VIASR, 0x44, data & 0xFF);
+ via_write_reg(VIASR, 0x45, (data >> 8) & 0xFF);
+ via_write_reg(VIASR, 0x46, (data >> 16) & 0xFF);
+ via_write_reg_mask(VIASR, 0x40, 0x00, 0x02); /* disable reset */
+}
+
+static inline void cle266_set_secondary_pll_encoded(u32 data)
+{
+ via_write_reg_mask(VIASR, 0x40, 0x04, 0x04); /* enable reset */
+ via_write_reg(VIASR, 0x44, data & 0xFF);
+ via_write_reg(VIASR, 0x45, (data >> 8) & 0xFF);
+ via_write_reg_mask(VIASR, 0x40, 0x00, 0x04); /* disable reset */
+}
+
+static inline void k800_set_secondary_pll_encoded(u32 data)
+{
+ via_write_reg_mask(VIASR, 0x40, 0x04, 0x04); /* enable reset */
+ via_write_reg(VIASR, 0x4A, data & 0xFF);
+ via_write_reg(VIASR, 0x4B, (data >> 8) & 0xFF);
+ via_write_reg(VIASR, 0x4C, (data >> 16) & 0xFF);
+ via_write_reg_mask(VIASR, 0x40, 0x00, 0x04); /* disable reset */
+}
+
+static void cle266_set_primary_pll(struct pll_config config)
+{
+ cle266_set_primary_pll_encoded(cle266_encode_pll(config));
+}
+
+static void k800_set_primary_pll(struct pll_config config)
+{
+ k800_set_primary_pll_encoded(k800_encode_pll(config));
+}
+
+static void vx855_set_primary_pll(struct pll_config config)
+{
+ k800_set_primary_pll_encoded(vx855_encode_pll(config));
+}
+
+static void cle266_set_secondary_pll(struct pll_config config)
+{
+ cle266_set_secondary_pll_encoded(cle266_encode_pll(config));
+}
+
+static void k800_set_secondary_pll(struct pll_config config)
+{
+ k800_set_secondary_pll_encoded(k800_encode_pll(config));
+}
+
+static void vx855_set_secondary_pll(struct pll_config config)
+{
+ k800_set_secondary_pll_encoded(vx855_encode_pll(config));
+}
+
static inline u32 get_pll_internal_frequency(u32 ref_freq,
struct pll_config pll)
{
@@ -1474,21 +1538,21 @@ static struct pll_config get_pll_config(struct pll_limit *limits, int size,
return best;
}
-static u32 viafb_get_clk_value(int clk)
+static struct pll_config get_best_pll_config(int clk)
{
- u32 value = 0;
+ struct pll_config config;
switch (viaparinfo->chip_info->gfx_chip_name) {
case UNICHROME_CLE266:
case UNICHROME_K400:
- value = cle266_encode_pll(get_pll_config(cle266_pll_limits,
- ARRAY_SIZE(cle266_pll_limits), clk));
+ config = get_pll_config(cle266_pll_limits,
+ ARRAY_SIZE(cle266_pll_limits), clk);
break;
case UNICHROME_K800:
case UNICHROME_PM800:
case UNICHROME_CN700:
- value = k800_encode_pll(get_pll_config(k800_pll_limits,
- ARRAY_SIZE(k800_pll_limits), clk));
+ config = get_pll_config(k800_pll_limits,
+ ARRAY_SIZE(k800_pll_limits), clk);
break;
case UNICHROME_CX700:
case UNICHROME_CN750:
@@ -1496,38 +1560,31 @@ static u32 viafb_get_clk_value(int clk)
case UNICHROME_P4M890:
case UNICHROME_P4M900:
case UNICHROME_VX800:
- value = k800_encode_pll(get_pll_config(cx700_pll_limits,
- ARRAY_SIZE(cx700_pll_limits), clk));
+ config = get_pll_config(cx700_pll_limits,
+ ARRAY_SIZE(cx700_pll_limits), clk);
break;
case UNICHROME_VX855:
case UNICHROME_VX900:
- value = vx855_encode_pll(get_pll_config(vx855_pll_limits,
- ARRAY_SIZE(vx855_pll_limits), clk));
+ config = get_pll_config(vx855_pll_limits,
+ ARRAY_SIZE(vx855_pll_limits), clk);
break;
}
- return value;
+ return config;
}
/* Set VCLK*/
void viafb_set_vclock(u32 clk, int set_iga)
{
- u32 value = viafb_get_clk_value(clk);
-
- DEBUG_MSG(KERN_INFO "PLL=0x%x", value);
-
- /* H.W. Reset : ON */
- viafb_write_reg_mask(CR17, VIACR, 0x00, BIT7);
+ struct pll_config config = get_best_pll_config(clk);
if (set_iga == IGA1) {
/* Change D,N FOR VCLK */
switch (viaparinfo->chip_info->gfx_chip_name) {
case UNICHROME_CLE266:
case UNICHROME_K400:
- via_write_reg(VIASR, SR46, (value & 0x00FF));
- via_write_reg(VIASR, SR47, (value & 0xFF00) >> 8);
+ cle266_set_primary_pll(config);
break;
-
case UNICHROME_K800:
case UNICHROME_PM800:
case UNICHROME_CN700:
@@ -1537,11 +1594,11 @@ void viafb_set_vclock(u32 clk, int set_iga)
case UNICHROME_P4M890:
case UNICHROME_P4M900:
case UNICHROME_VX800:
+ k800_set_primary_pll(config);
+ break;
case UNICHROME_VX855:
case UNICHROME_VX900:
- via_write_reg(VIASR, SR44, (value & 0x0000FF));
- via_write_reg(VIASR, SR45, (value & 0x00FF00) >> 8);
- via_write_reg(VIASR, SR46, (value & 0xFF0000) >> 16);
+ vx855_set_primary_pll(config);
break;
}
}
@@ -1551,10 +1608,8 @@ void viafb_set_vclock(u32 clk, int set_iga)
switch (viaparinfo->chip_info->gfx_chip_name) {
case UNICHROME_CLE266:
case UNICHROME_K400:
- via_write_reg(VIASR, SR44, (value & 0x00FF));
- via_write_reg(VIASR, SR45, (value & 0xFF00) >> 8);
+ cle266_set_secondary_pll(config);
break;
-
case UNICHROME_K800:
case UNICHROME_PM800:
case UNICHROME_CN700:
@@ -1564,29 +1619,15 @@ void viafb_set_vclock(u32 clk, int set_iga)
case UNICHROME_P4M890:
case UNICHROME_P4M900:
case UNICHROME_VX800:
+ k800_set_secondary_pll(config);
+ break;
case UNICHROME_VX855:
case UNICHROME_VX900:
- via_write_reg(VIASR, SR4A, (value & 0x0000FF));
- via_write_reg(VIASR, SR4B, (value & 0x00FF00) >> 8);
- via_write_reg(VIASR, SR4C, (value & 0xFF0000) >> 16);
+ vx855_set_secondary_pll(config);
break;
}
}
- /* H.W. Reset : OFF */
- viafb_write_reg_mask(CR17, VIACR, 0x80, BIT7);
-
- /* Reset PLL */
- if (set_iga == IGA1) {
- viafb_write_reg_mask(SR40, VIASR, 0x02, BIT1);
- viafb_write_reg_mask(SR40, VIASR, 0x00, BIT1);
- }
-
- if (set_iga == IGA2) {
- viafb_write_reg_mask(SR40, VIASR, 0x04, BIT2);
- viafb_write_reg_mask(SR40, VIASR, 0x00, BIT2);
- }
-
/* Fire! */
via_write_misc_reg_mask(0x0C, 0x0C); /* select external clock */
}
--
1.6.3.2
This patch adds some support for clock source selection as well as
PLL power management. The code is unused at the moment but was
successfully tested as far as possible.
The implementation is according to the documentation for VX700,
VX800, VX855, VX900. Probably the source selection works like this
starting with K800 and the power managemennt at least since VX700.
(guessed based on the initialization in viamode.c)
Signed-off-by: Florian Tobias Schandinat <[email protected]>
---
drivers/video/via/hw.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 88 insertions(+), 0 deletions(-)
diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c
index bd28e13..b38d3b4 100644
--- a/drivers/video/via/hw.c
+++ b/drivers/video/via/hw.c
@@ -1409,6 +1409,42 @@ void viafb_load_FIFO_reg(int set_iga, int hor_active, int ver_active)
}
+static void set_primary_pll_state(u8 state)
+{
+ u8 value;
+
+ switch (state) {
+ case VIA_STATE_ON:
+ value = 0x20;
+ break;
+ case VIA_STATE_OFF:
+ value = 0x00;
+ break;
+ default:
+ return;
+ }
+
+ via_write_reg_mask(VIASR, 0x2D, value, 0x30);
+}
+
+static void set_secondary_pll_state(u8 state)
+{
+ u8 value;
+
+ switch (state) {
+ case VIA_STATE_ON:
+ value = 0x08;
+ break;
+ case VIA_STATE_OFF:
+ value = 0x00;
+ break;
+ default:
+ return;
+ }
+
+ via_write_reg_mask(VIASR, 0x2D, value, 0x08);
+}
+
static u32 cle266_encode_pll(struct pll_config pll)
{
return (pll.multiplier << 8)
@@ -1494,6 +1530,58 @@ static void vx855_set_secondary_pll(struct pll_config config)
k800_set_secondary_pll_encoded(vx855_encode_pll(config));
}
+enum via_clksrc {
+ VIA_CLKSRC_X1 = 0,
+ VIA_CLKSRC_TVX1,
+ VIA_CLKSRC_TVPLL,
+ VIA_CLKSRC_DVP1TVCLKR,
+ VIA_CLKSRC_CAP0,
+ VIA_CLKSRC_CAP1,
+};
+
+static inline u8 set_clock_source_common(enum via_clksrc source, bool use_pll)
+{
+ u8 data = 0;
+
+ switch (source) {
+ case VIA_CLKSRC_X1:
+ data = 0x00;
+ break;
+ case VIA_CLKSRC_TVX1:
+ data = 0x02;
+ break;
+ case VIA_CLKSRC_TVPLL:
+ data = 0x04; /* 0x06 should be the same */
+ break;
+ case VIA_CLKSRC_DVP1TVCLKR:
+ data = 0x0A;
+ break;
+ case VIA_CLKSRC_CAP0:
+ data = 0xC;
+ break;
+ case VIA_CLKSRC_CAP1:
+ data = 0x0E;
+ break;
+ }
+
+ if (!use_pll)
+ data |= 1;
+
+ return data;
+}
+
+static void set_primary_clock_source(enum via_clksrc source, bool use_pll)
+{
+ u8 data = set_clock_source_common(source, use_pll) << 4;
+ via_write_reg_mask(VIACR, 0x6C, data, 0xF0);
+}
+
+static void set_secondary_clock_source(enum via_clksrc source, bool use_pll)
+{
+ u8 data = set_clock_source_common(source, use_pll);
+ via_write_reg_mask(VIACR, 0x6C, data, 0x0F);
+}
+
static inline u32 get_pll_internal_frequency(u32 ref_freq,
struct pll_config pll)
{
--
1.6.3.2
This patch allows calculating the pll multiplier within limits based
on the previous table. All available information supports that it
should be possible/sane to choose the multiplier free within some
ranges.
Storing the multiplier ranges instead of lots of pll configurations
reduces the memory needed and may as well improve the performance.
It is also expected to provide better pll values resulting in better
frequencies for the connected devices.
Signed-off-by: Florian Tobias Schandinat <[email protected]>
---
drivers/video/via/hw.c | 377 +++++++++++++-----------------------------------
drivers/video/via/hw.h | 11 +-
2 files changed, 106 insertions(+), 282 deletions(-)
diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c
index dc4c778..063ff65 100644
--- a/drivers/video/via/hw.c
+++ b/drivers/video/via/hw.c
@@ -22,272 +22,80 @@
#include <linux/via-core.h>
#include "global.h"
-static struct pll_config cle266_pll_config[] = {
- {19, 4, 0},
- {26, 5, 0},
- {28, 5, 0},
- {31, 5, 0},
- {33, 5, 0},
- {55, 5, 0},
- {102, 5, 0},
- {53, 6, 0},
- {92, 6, 0},
- {98, 6, 0},
- {112, 6, 0},
- {41, 7, 0},
- {60, 7, 0},
- {99, 7, 0},
- {100, 7, 0},
- {83, 8, 0},
- {86, 8, 0},
- {108, 8, 0},
- {87, 9, 0},
- {118, 9, 0},
- {95, 12, 0},
- {115, 12, 0},
- {108, 13, 0},
- {83, 17, 0},
- {67, 20, 0},
- {86, 20, 0},
- {98, 20, 0},
- {121, 24, 0},
- {99, 29, 0},
- {33, 3, 1},
- {15, 4, 1},
- {23, 4, 1},
- {37, 5, 1},
- {83, 5, 1},
- {85, 5, 1},
- {94, 5, 1},
- {103, 5, 1},
- {109, 5, 1},
- {113, 5, 1},
- {121, 5, 1},
- {82, 6, 1},
- {31, 7, 1},
- {55, 7, 1},
- {84, 7, 1},
- {83, 8, 1},
- {76, 9, 1},
- {127, 9, 1},
- {33, 4, 2},
- {75, 4, 2},
- {119, 4, 2},
- {121, 4, 2},
- {91, 5, 2},
- {118, 5, 2},
- {83, 6, 2},
- {109, 6, 2},
- {90, 7, 2},
- {93, 2, 3},
- {53, 3, 3},
- {73, 4, 3},
- {89, 4, 3},
- {105, 4, 3},
- {117, 4, 3},
- {101, 5, 3},
- {121, 5, 3},
- {127, 5, 3},
- {99, 7, 3}
+static struct pll_limit cle266_pll_limits[] = {
+ {19, 19, 4, 0},
+ {26, 102, 5, 0},
+ {53, 112, 6, 0},
+ {41, 100, 7, 0},
+ {83, 108, 8, 0},
+ {87, 118, 9, 0},
+ {95, 115, 12, 0},
+ {108, 108, 13, 0},
+ {83, 83, 17, 0},
+ {67, 98, 20, 0},
+ {121, 121, 24, 0},
+ {99, 99, 29, 0},
+ {33, 33, 3, 1},
+ {15, 23, 4, 1},
+ {37, 121, 5, 1},
+ {82, 82, 6, 1},
+ {31, 84, 7, 1},
+ {83, 83, 8, 1},
+ {76, 127, 9, 1},
+ {33, 121, 4, 2},
+ {91, 118, 5, 2},
+ {83, 109, 6, 2},
+ {90, 90, 7, 2},
+ {93, 93, 2, 3},
+ {53, 53, 3, 3},
+ {73, 117, 4, 3},
+ {101, 127, 5, 3},
+ {99, 99, 7, 3}
};
-static struct pll_config k800_pll_config[] = {
- {22, 2, 0},
- {28, 3, 0},
- {81, 3, 1},
- {85, 3, 1},
- {98, 3, 1},
- {112, 3, 1},
- {86, 4, 1},
- {166, 4, 1},
- {109, 5, 1},
- {113, 5, 1},
- {121, 5, 1},
- {131, 5, 1},
- {143, 5, 1},
- {153, 5, 1},
- {66, 3, 2},
- {68, 3, 2},
- {95, 3, 2},
- {106, 3, 2},
- {116, 3, 2},
- {93, 4, 2},
- {119, 4, 2},
- {121, 4, 2},
- {133, 4, 2},
- {137, 4, 2},
- {117, 5, 2},
- {118, 5, 2},
- {120, 5, 2},
- {124, 5, 2},
- {132, 5, 2},
- {137, 5, 2},
- {141, 5, 2},
- {166, 5, 2},
- {170, 5, 2},
- {191, 5, 2},
- {206, 5, 2},
- {208, 5, 2},
- {30, 2, 3},
- {69, 3, 3},
- {82, 3, 3},
- {83, 3, 3},
- {109, 3, 3},
- {114, 3, 3},
- {125, 3, 3},
- {89, 4, 3},
- {103, 4, 3},
- {117, 4, 3},
- {126, 4, 3},
- {150, 4, 3},
- {161, 4, 3},
- {121, 5, 3},
- {127, 5, 3},
- {131, 5, 3},
- {134, 5, 3},
- {148, 5, 3},
- {169, 5, 3},
- {172, 5, 3},
- {182, 5, 3},
- {195, 5, 3},
- {196, 5, 3},
- {208, 5, 3},
- {66, 2, 4},
- {85, 3, 4},
- {141, 4, 4},
- {146, 4, 4},
- {161, 4, 4},
- {177, 5, 4}
+static struct pll_limit k800_pll_limits[] = {
+ {22, 22, 2, 0},
+ {28, 28, 3, 0},
+ {81, 112, 3, 1},
+ {86, 166, 4, 1},
+ {109, 153, 5, 1},
+ {66, 116, 3, 2},
+ {93, 137, 4, 2},
+ {117, 208, 5, 2},
+ {30, 30, 2, 3},
+ {69, 125, 3, 3},
+ {89, 161, 4, 3},
+ {121, 208, 5, 3},
+ {66, 66, 2, 4},
+ {85, 85, 3, 4},
+ {141, 161, 4, 4},
+ {177, 177, 5, 4}
};
-static struct pll_config cx700_pll_config[] = {
- {98, 3, 1},
- {86, 4, 1},
- {109, 5, 1},
- {110, 5, 1},
- {113, 5, 1},
- {121, 5, 1},
- {131, 5, 1},
- {135, 5, 1},
- {142, 5, 1},
- {143, 5, 1},
- {153, 5, 1},
- {187, 5, 1},
- {208, 5, 1},
- {68, 2, 2},
- {95, 3, 2},
- {116, 3, 2},
- {93, 4, 2},
- {119, 4, 2},
- {133, 4, 2},
- {137, 4, 2},
- {151, 4, 2},
- {166, 4, 2},
- {110, 5, 2},
- {112, 5, 2},
- {117, 5, 2},
- {118, 5, 2},
- {120, 5, 2},
- {132, 5, 2},
- {137, 5, 2},
- {141, 5, 2},
- {151, 5, 2},
- {166, 5, 2},
- {175, 5, 2},
- {191, 5, 2},
- {206, 5, 2},
- {174, 7, 2},
- {82, 3, 3},
- {109, 3, 3},
- {117, 4, 3},
- {150, 4, 3},
- {161, 4, 3},
- {112, 5, 3},
- {115, 5, 3},
- {121, 5, 3},
- {127, 5, 3},
- {129, 5, 3},
- {131, 5, 3},
- {134, 5, 3},
- {138, 5, 3},
- {148, 5, 3},
- {157, 5, 3},
- {169, 5, 3},
- {172, 5, 3},
- {190, 5, 3},
- {195, 5, 3},
- {196, 5, 3},
- {208, 5, 3},
- {141, 5, 4},
- {150, 5, 4},
- {166, 5, 4},
- {176, 5, 4},
- {177, 5, 4},
- {183, 5, 4},
- {202, 5, 4}
+static struct pll_limit cx700_pll_limits[] = {
+ {98, 98, 3, 1},
+ {86, 86, 4, 1},
+ {109, 208, 5, 1},
+ {68, 68, 2, 2},
+ {95, 116, 3, 2},
+ {93, 166, 4, 2},
+ {110, 206, 5, 2},
+ {174, 174, 7, 2},
+ {82, 109, 3, 3},
+ {117, 161, 4, 3},
+ {112, 208, 5, 3},
+ {141, 202, 5, 4}
};
-static struct pll_config vx855_pll_config[] = {
- {86, 4, 1},
- {108, 5, 1},
- {110, 5, 1},
- {113, 5, 1},
- {121, 5, 1},
- {131, 5, 1},
- {135, 5, 1},
- {142, 5, 1},
- {143, 5, 1},
- {153, 5, 1},
- {164, 5, 1},
- {187, 5, 1},
- {208, 5, 1},
- {110, 5, 2},
- {112, 5, 2},
- {117, 5, 2},
- {118, 5, 2},
- {124, 5, 2},
- {132, 5, 2},
- {137, 5, 2},
- {141, 5, 2},
- {149, 5, 2},
- {151, 5, 2},
- {159, 5, 2},
- {166, 5, 2},
- {167, 5, 2},
- {172, 5, 2},
- {189, 5, 2},
- {191, 5, 2},
- {194, 5, 2},
- {206, 5, 2},
- {208, 5, 2},
- {83, 3, 3},
- {88, 3, 3},
- {109, 3, 3},
- {112, 3, 3},
- {103, 4, 3},
- {105, 4, 3},
- {161, 4, 3},
- {112, 5, 3},
- {115, 5, 3},
- {121, 5, 3},
- {127, 5, 3},
- {134, 5, 3},
- {137, 5, 3},
- {148, 5, 3},
- {157, 5, 3},
- {169, 5, 3},
- {172, 5, 3},
- {182, 5, 3},
- {191, 5, 3},
- {195, 5, 3},
- {209, 5, 3},
- {142, 4, 4},
- {146, 4, 4},
- {161, 4, 4},
- {141, 5, 4},
- {150, 5, 4},
- {165, 5, 4},
- {176, 5, 4}
+static struct pll_limit vx855_pll_limits[] = {
+ {86, 86, 4, 1},
+ {108, 208, 5, 1},
+ {110, 208, 5, 2},
+ {83, 112, 3, 3},
+ {103, 161, 4, 3},
+ {112, 209, 5, 3},
+ {142, 161, 4, 4},
+ {141, 176, 5, 4}
};
/* according to VIA Technologies these values are based on experiment */
@@ -1633,17 +1441,34 @@ static inline u32 get_pll_output_frequency(u32 ref_freq, struct pll_config pll)
return get_pll_internal_frequency(ref_freq, pll)>>pll.rshift;
}
-static struct pll_config get_pll_config(struct pll_config *config, int size,
+static struct pll_config get_pll_config(struct pll_limit *limits, int size,
int clk)
{
- struct pll_config best = config[0];
+ struct pll_config cur, up, down, best = {0, 1, 0};
const u32 f0 = 14318180; /* X1 frequency */
- int i;
-
- for (i = 1; i < size; i++) {
- if (abs(get_pll_output_frequency(f0, config[i]) - clk)
- < abs(get_pll_output_frequency(f0, best) - clk))
- best = config[i];
+ int i, f;
+
+ for (i = 0; i < size; i++) {
+ cur.rshift = limits[i].rshift;
+ cur.divisor = limits[i].divisor;
+ cur.multiplier = clk / ((f0 / cur.divisor)>>cur.rshift);
+ f = abs(get_pll_output_frequency(f0, cur) - clk);
+ up = down = cur;
+ up.multiplier++;
+ down.multiplier--;
+ if (abs(get_pll_output_frequency(f0, up) - clk) < f)
+ cur = up;
+ else if (abs(get_pll_output_frequency(f0, down) - clk) < f)
+ cur = down;
+
+ if (cur.multiplier < limits[i].multiplier_min)
+ cur.multiplier = limits[i].multiplier_min;
+ else if (cur.multiplier > limits[i].multiplier_max)
+ cur.multiplier = limits[i].multiplier_max;
+
+ f = abs(get_pll_output_frequency(f0, cur) - clk);
+ if (f < abs(get_pll_output_frequency(f0, best) - clk))
+ best = cur;
}
return best;
@@ -1656,14 +1481,14 @@ u32 viafb_get_clk_value(int clk)
switch (viaparinfo->chip_info->gfx_chip_name) {
case UNICHROME_CLE266:
case UNICHROME_K400:
- value = cle266_encode_pll(get_pll_config(cle266_pll_config,
- ARRAY_SIZE(cle266_pll_config), clk));
+ value = cle266_encode_pll(get_pll_config(cle266_pll_limits,
+ ARRAY_SIZE(cle266_pll_limits), clk));
break;
case UNICHROME_K800:
case UNICHROME_PM800:
case UNICHROME_CN700:
- value = k800_encode_pll(get_pll_config(k800_pll_config,
- ARRAY_SIZE(k800_pll_config), clk));
+ value = k800_encode_pll(get_pll_config(k800_pll_limits,
+ ARRAY_SIZE(k800_pll_limits), clk));
break;
case UNICHROME_CX700:
case UNICHROME_CN750:
@@ -1671,13 +1496,13 @@ u32 viafb_get_clk_value(int clk)
case UNICHROME_P4M890:
case UNICHROME_P4M900:
case UNICHROME_VX800:
- value = k800_encode_pll(get_pll_config(cx700_pll_config,
- ARRAY_SIZE(cx700_pll_config), clk));
+ value = k800_encode_pll(get_pll_config(cx700_pll_limits,
+ ARRAY_SIZE(cx700_pll_limits), clk));
break;
case UNICHROME_VX855:
case UNICHROME_VX900:
- value = vx855_encode_pll(get_pll_config(vx855_pll_config,
- ARRAY_SIZE(vx855_pll_config), clk));
+ value = vx855_encode_pll(get_pll_config(vx855_pll_limits,
+ ARRAY_SIZE(vx855_pll_limits), clk));
break;
}
diff --git a/drivers/video/via/hw.h b/drivers/video/via/hw.h
index 8858593..63d8d37 100644
--- a/drivers/video/via/hw.h
+++ b/drivers/video/via/hw.h
@@ -738,12 +738,11 @@ struct pll_config {
u8 rshift;
};
-struct pll_map {
- u32 clk;
- struct pll_config cle266_pll;
- struct pll_config k800_pll;
- struct pll_config cx700_pll;
- struct pll_config vx855_pll;
+struct pll_limit {
+ u16 multiplier_min;
+ u16 multiplier_max;
+ u8 divisor;
+ u8 rshift;
};
struct rgbLUT {
--
1.6.3.2