[PATCH u-boot-sunxi 1/2] sunxi: dram: Support more DRAM clock speeds (396, 468, 496, 512, 540)

84 views
Skip to first unread message

Siarhei Siamashka

unread,
Apr 20, 2014, 10:32:30 PM4/20/14
to linux...@googlegroups.com
These are some additional interesting DRAM clock frequencies. And
they can be supported, while keeping the PLL5P clock speed at least
not higher than the DRAM clock speed. PLL5P output is used to
clock a lot of peripherals, so we need to be careful not to
break them (or more like some buggy code in the sunxi-3.4
kernel, which just sets hardcoded divisors in some places).

Having 396MHz is nice. It can be used with the tight DDR3-800
timings (CL-tRCD-tRP-tRAS). For comparison, moving to 408MHz
requires extra cycles for many of these timing parameters,
which results in a latency increase.

Having 512MHz and 540MHz is also useful, because they provide better
granularity of the DRAM clock frequency selection around DDR3-1066
speed. And this is an interesting DRAM overclocking target.

The extra five branches add ~120 bytes of code if compiled
for ARM and ~90 bytes of code if compiled for Thumb2.

Signed-off-by: Siarhei Siamashka <siarhei....@gmail.com>
---
arch/arm/cpu/armv7/sunxi/dram.c | 41 +++++++++++++++++++++++++++++++++++++----
1 file changed, 37 insertions(+), 4 deletions(-)

diff --git a/arch/arm/cpu/armv7/sunxi/dram.c b/arch/arm/cpu/armv7/sunxi/dram.c
index 921f683..0fdab2f 100644
--- a/arch/arm/cpu/armv7/sunxi/dram.c
+++ b/arch/arm/cpu/armv7/sunxi/dram.c
@@ -200,13 +200,46 @@ static void mctl_setup_dram_clock(u32 clk)
/* setup DRAM PLL */
reg_val = readl(&ccm->pll5_cfg);
reg_val &= ~CCM_PLL5_CTRL_M_MASK; /* set M to 0 (x1) */
- reg_val |= CCM_PLL5_CTRL_M(CCM_PLL5_CTRL_M_X(2));
reg_val &= ~CCM_PLL5_CTRL_K_MASK; /* set K to 0 (x1) */
- reg_val |= CCM_PLL5_CTRL_K(CCM_PLL5_CTRL_K_X(2));
reg_val &= ~CCM_PLL5_CTRL_N_MASK; /* set N to 0 (x0) */
- reg_val |= CCM_PLL5_CTRL_N(CCM_PLL5_CTRL_N_X(clk / 24));
reg_val &= ~CCM_PLL5_CTRL_P_MASK; /* set P to 0 (x1) */
- reg_val |= CCM_PLL5_CTRL_P(CCM_PLL5_CTRL_P_X(2));
+ if (clk >= 540 && clk < 552) {
+ /* dram = 540MHz, pll5p = 540MHz */
+ reg_val |= CCM_PLL5_CTRL_M(CCM_PLL5_CTRL_M_X(2));
+ reg_val |= CCM_PLL5_CTRL_K(CCM_PLL5_CTRL_K_X(3));
+ reg_val |= CCM_PLL5_CTRL_N(CCM_PLL5_CTRL_N_X(15));
+ reg_val |= CCM_PLL5_CTRL_P(1);
+ } else if (clk >= 512 && clk < 528) {
+ /* dram = 512MHz, pll5p = 384MHz */
+ reg_val |= CCM_PLL5_CTRL_M(CCM_PLL5_CTRL_M_X(3));
+ reg_val |= CCM_PLL5_CTRL_K(CCM_PLL5_CTRL_K_X(4));
+ reg_val |= CCM_PLL5_CTRL_N(CCM_PLL5_CTRL_N_X(16));
+ reg_val |= CCM_PLL5_CTRL_P(2);
+ } else if (clk >= 496 && clk < 504) {
+ /* dram = 496MHz, pll5p = 372MHz */
+ reg_val |= CCM_PLL5_CTRL_M(CCM_PLL5_CTRL_M_X(3));
+ reg_val |= CCM_PLL5_CTRL_K(CCM_PLL5_CTRL_K_X(2));
+ reg_val |= CCM_PLL5_CTRL_N(CCM_PLL5_CTRL_N_X(31));
+ reg_val |= CCM_PLL5_CTRL_P(2);
+ } else if (clk >= 468 && clk < 480) {
+ /* dram = 468MHz, pll5p = 468MHz */
+ reg_val |= CCM_PLL5_CTRL_M(CCM_PLL5_CTRL_M_X(2));
+ reg_val |= CCM_PLL5_CTRL_K(CCM_PLL5_CTRL_K_X(3));
+ reg_val |= CCM_PLL5_CTRL_N(CCM_PLL5_CTRL_N_X(13));
+ reg_val |= CCM_PLL5_CTRL_P(1);
+ } else if (clk >= 396 && clk < 408) {
+ /* dram = 396MHz, pll5p = 396MHz */
+ reg_val |= CCM_PLL5_CTRL_M(CCM_PLL5_CTRL_M_X(2));
+ reg_val |= CCM_PLL5_CTRL_K(CCM_PLL5_CTRL_K_X(3));
+ reg_val |= CCM_PLL5_CTRL_N(CCM_PLL5_CTRL_N_X(11));
+ reg_val |= CCM_PLL5_CTRL_P(1);
+ } else {
+ /* any other frequency that is a multiple of 24 */
+ reg_val |= CCM_PLL5_CTRL_M(CCM_PLL5_CTRL_M_X(2));
+ reg_val |= CCM_PLL5_CTRL_K(CCM_PLL5_CTRL_K_X(2));
+ reg_val |= CCM_PLL5_CTRL_N(CCM_PLL5_CTRL_N_X(clk / 24));
+ reg_val |= CCM_PLL5_CTRL_P(CCM_PLL5_CTRL_P_X(2));
+ }
reg_val &= ~CCM_PLL5_CTRL_VCO_GAIN; /* PLL VCO Gain off */
reg_val |= CCM_PLL5_CTRL_EN; /* PLL On */
writel(reg_val, &ccm->pll5_cfg);
--
1.8.3.2

Siarhei Siamashka

unread,
Apr 20, 2014, 10:32:31 PM4/20/14
to linux...@googlegroups.com
This ifdef wrapped code apparently was introduced as a unification
of sun4i/sun5i and sun7i codebases and assumed that the non-sun7i
part of it was correct. However experiments show that this 4-bit
bitfield behaves in the same way at least on sun4i and sun7i.

Also see the definition in 'include/synopsys/dwcddr21mctl.h':
#define DWCDDR21MCTL_DLLCR_PHASE(x) (((x) & 0xf) << 14)

Signed-off-by: Siarhei Siamashka <siarhei....@gmail.com>
---
arch/arm/cpu/armv7/sunxi/dram.c | 4 ----
1 file changed, 4 deletions(-)

diff --git a/arch/arm/cpu/armv7/sunxi/dram.c b/arch/arm/cpu/armv7/sunxi/dram.c
index 0fdab2f..caf94e9 100644
--- a/arch/arm/cpu/armv7/sunxi/dram.c
+++ b/arch/arm/cpu/armv7/sunxi/dram.c
@@ -122,11 +122,7 @@ static void mctl_enable_dllx(u32 phase)
n = DRAM_DCR_NR_DLLCR_16BIT;

for (i = 1; i < n; i++) {
-#ifdef CONFIG_SUN7I
clrsetbits_le32(&dram->dllcr[i], 0xf << 14,
-#else
- clrsetbits_le32(&dram->dllcr[i], 0x4 << 14,
-#endif
(phase & 0xf) << 14);
clrsetbits_le32(&dram->dllcr[i], DRAM_DLLCR_NRESET,
DRAM_DLLCR_DISABLE);
--
1.8.3.2

Siarhei Siamashka

unread,
Apr 20, 2014, 10:45:37 PM4/20/14
to Siarhei Siamashka, linux...@googlegroups.com
These clock frequencies have been selected by trying all the possible
multipliers and applying a set of rules with the following script:

#!/usr/bin/env ruby

freq_list = {}
0.upto(31) {|n|
1.upto(4) {|k|
1.upto(4) {|m|
[1, 2, 4, 8].each {|p|
dram_freq = 24 * n * k / m
pll5p_freq = 24 * n * k / p
next if 24 * n * k < 240 or 24 * n * k > 1550
next if dram_freq > 600 or dram_freq < 396
next if pll5p_freq > dram_freq or pll5p_freq < 360
next if freq_list.has_key?(dram_freq) and
freq_list[dram_freq][4] >= pll5p_freq
freq_list[dram_freq] = [n, k, m, p, pll5p_freq]
}
}
}
}
prev_freq = 1000
print("\t")
freq_list.to_a.sort.reverse.each {|x|
upper_limit = [(x[0] + 23) / 24 * 24, prev_freq].min
next if upper_limit == x[0]
p_val = {1 => 0, 2 => 1, 4 => 2, 8 => 3}[x[1][3]]
print("if (clk >= #{x[0]} && clk < #{upper_limit}) {
/* dram = #{x[0]}MHz, pll5p = #{x[1][4]}MHz */
reg_val |= CCM_PLL5_CTRL_M(CCM_PLL5_CTRL_M_X(#{x[1][2]}));
reg_val |= CCM_PLL5_CTRL_K(CCM_PLL5_CTRL_K_X(#{x[1][1]}));
reg_val |= CCM_PLL5_CTRL_N(CCM_PLL5_CTRL_N_X(#{x[1][0]}));
reg_val |= CCM_PLL5_CTRL_P(#{p_val});
} else ")
prev_freq = x[0]
}
print "\t{\n\t}\n"


--
Best regards,
Siarhei Siamashka

Hans de Goede

unread,
Apr 23, 2014, 6:23:07 AM4/23/14
to linux...@googlegroups.com
Hi all,

On 04/21/2014 04:32 AM, Siarhei Siamashka wrote:
> These are some additional interesting DRAM clock frequencies. And
> they can be supported, while keeping the PLL5P clock speed at least
> not higher than the DRAM clock speed. PLL5P output is used to
> clock a lot of peripherals, so we need to be careful not to
> break them (or more like some buggy code in the sunxi-3.4
> kernel, which just sets hardcoded divisors in some places).
>
> Having 396MHz is nice. It can be used with the tight DDR3-800
> timings (CL-tRCD-tRP-tRAS). For comparison, moving to 408MHz
> requires extra cycles for many of these timing parameters,
> which results in a latency increase.
>
> Having 512MHz and 540MHz is also useful, because they provide better
> granularity of the DRAM clock frequency selection around DDR3-1066
> speed. And this is an interesting DRAM overclocking target.
>
> The extra five branches add ~120 bytes of code if compiled
> for ARM and ~90 bytes of code if compiled for Thumb2.
>
> Signed-off-by: Siarhei Siamashka <siarhei....@gmail.com>

Thanks!

Both patches looks good to me, if I receive no objections I'll be pushing
these to u-boot-sunxi.git sunxi branch during one of the coming days.

Regards,

Hans

Ian Campbell

unread,
Apr 23, 2014, 3:14:24 PM4/23/14
to linux...@googlegroups.com
On Mon, 2014-04-21 at 05:32 +0300, Siarhei Siamashka wrote:
> + if (clk >= 540 && clk < 552) {

If you wanted I think you could replace this if/else tree with
switch (clk) {
case 540 ... 551:
/*stuff*/
case 512 ... 527:
/*stuff*/
case etc...

up to you if you think that is nicer or not.
Ian.


Hans de Goede

unread,
Apr 26, 2014, 2:21:05 PM4/26/14
to linux...@googlegroups.com
Hi,

On 04/21/2014 04:32 AM, Siarhei Siamashka wrote:
> These are some additional interesting DRAM clock frequencies. And
> they can be supported, while keeping the PLL5P clock speed at least
> not higher than the DRAM clock speed. PLL5P output is used to
> clock a lot of peripherals, so we need to be careful not to
> break them (or more like some buggy code in the sunxi-3.4
> kernel, which just sets hardcoded divisors in some places).
>
> Having 396MHz is nice. It can be used with the tight DDR3-800
> timings (CL-tRCD-tRP-tRAS). For comparison, moving to 408MHz
> requires extra cycles for many of these timing parameters,
> which results in a latency increase.
>
> Having 512MHz and 540MHz is also useful, because they provide better
> granularity of the DRAM clock frequency selection around DDR3-1066
> speed. And this is an interesting DRAM overclocking target.
>
> The extra five branches add ~120 bytes of code if compiled
> for ARM and ~90 bytes of code if compiled for Thumb2.
>
> Signed-off-by: Siarhei Siamashka <siarhei....@gmail.com>

Thanks, applied both patches and pushed.

Regards,

Hans
Reply all
Reply to author
Forward
0 new messages