nb/intel/sandybridge: Improve CAS freq selection
The previous code seemed weird and tried to check if its selected
value is supported three times.
This also lower the clock if a selected frequency does not result in a
supported CAS number.
Change-Id: I97244bc3940813c5a5fcbd770d71cca76d21fcae
Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
Reviewed-on: https://review.coreboot.org/19716
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Patrick Rudolph <siro@das-labor.org>
diff --git a/src/include/device/dram/ddr3.h b/src/include/device/dram/ddr3.h
index 11f98c5..9597a31 100644
--- a/src/include/device/dram/ddr3.h
+++ b/src/include/device/dram/ddr3.h
@@ -39,6 +39,8 @@
* These values are in 1/256 ns units.
* @{
*/
+#define NS2MHZ_DIV256 1000 << 8
+
#define TCK_1333MHZ 192
#define TCK_1200MHZ 212
#define TCK_1100MHZ 232
diff --git a/src/northbridge/intel/sandybridge/raminit_sandy.c b/src/northbridge/intel/sandybridge/raminit_sandy.c
index 084c6ec..3acc563 100644
--- a/src/northbridge/intel/sandybridge/raminit_sandy.c
+++ b/src/northbridge/intel/sandybridge/raminit_sandy.c
@@ -136,16 +136,65 @@
return frq_comp2_map[get_FRQ(tCK) - 3];
}
-static void dram_timing(ramctr_timing * ctrl)
+static void snb_normalize_tclk(u32 *tclk)
+{
+ if (*tclk <= TCK_1066MHZ) {
+ *tclk = TCK_1066MHZ;
+ } else if (*tclk <= TCK_933MHZ) {
+ *tclk = TCK_933MHZ;
+ } else if (*tclk <= TCK_800MHZ) {
+ *tclk = TCK_800MHZ;
+ } else if (*tclk <= TCK_666MHZ) {
+ *tclk = TCK_666MHZ;
+ } else if (*tclk <= TCK_533MHZ) {
+ *tclk = TCK_533MHZ;
+ } else if (*tclk <= TCK_400MHZ) {
+ *tclk = TCK_400MHZ;
+ } else {
+ *tclk = 0;
+ }
+}
+
+static void find_cas_tck(ramctr_timing *ctrl)
{
u8 val;
u32 val32;
+ /* Find CAS latency */
+ while (1) {
+ /* Normalising tCK before computing clock could potentially
+ * results in lower selected CAS, which is desired.
+ */
+ snb_normalize_tclk(&(ctrl->tCK));
+ if (!(ctrl->tCK))
+ die("Couldn't find compatible clock / CAS settings\n");
+ val = DIV_ROUND_UP(ctrl->tAA, ctrl->tCK);
+ printk(BIOS_DEBUG, "Trying CAS %u, tCK %u.\n", val, ctrl->tCK);
+ for (; val <= MAX_CAS; val++)
+ if ((ctrl->cas_supported >> (val - MIN_CAS)) & 1)
+ break;
+ if (val == (MAX_CAS + 1)) {
+ ctrl->tCK++;
+ continue;
+ } else {
+ printk(BIOS_DEBUG, "Found compatible clock, CAS pair.\n");
+ break;
+ }
+ }
+
+ val32 = NS2MHZ_DIV256 / ctrl->tCK;
+ printk(BIOS_DEBUG, "Selected DRAM frequency: %u MHz\n", val32);
+
+ printk(BIOS_DEBUG, "Selected CAS latency : %uT\n", val);
+ ctrl->CAS = val;
+}
+
+static void dram_timing(ramctr_timing *ctrl)
+{
/* Maximum supported DDR3 frequency is 1066MHz (DDR3 2133) so make sure
* we cap it if we have faster DIMMs.
* Then, align it to the closest JEDEC standard frequency */
- if (ctrl->tCK <= TCK_1066MHZ) {
- ctrl->tCK = TCK_1066MHZ;
+ if (ctrl->tCK == TCK_1066MHZ) {
ctrl->edge_offset[0] = 16;
ctrl->edge_offset[1] = 7;
ctrl->edge_offset[2] = 7;
@@ -153,8 +202,7 @@
ctrl->timC_offset[1] = 7;
ctrl->timC_offset[2] = 7;
ctrl->reg_320c_range_threshold = 13;
- } else if (ctrl->tCK <= TCK_933MHZ) {
- ctrl->tCK = TCK_933MHZ;
+ } else if (ctrl->tCK == TCK_933MHZ) {
ctrl->edge_offset[0] = 14;
ctrl->edge_offset[1] = 6;
ctrl->edge_offset[2] = 6;
@@ -162,8 +210,7 @@
ctrl->timC_offset[1] = 6;
ctrl->timC_offset[2] = 6;
ctrl->reg_320c_range_threshold = 15;
- } else if (ctrl->tCK <= TCK_800MHZ) {
- ctrl->tCK = TCK_800MHZ;
+ } else if (ctrl->tCK == TCK_800MHZ) {
ctrl->edge_offset[0] = 13;
ctrl->edge_offset[1] = 5;
ctrl->edge_offset[2] = 5;
@@ -171,8 +218,7 @@
ctrl->timC_offset[1] = 5;
ctrl->timC_offset[2] = 5;
ctrl->reg_320c_range_threshold = 15;
- } else if (ctrl->tCK <= TCK_666MHZ) {
- ctrl->tCK = TCK_666MHZ;
+ } else if (ctrl->tCK == TCK_666MHZ) {
ctrl->edge_offset[0] = 10;
ctrl->edge_offset[1] = 4;
ctrl->edge_offset[2] = 4;
@@ -180,8 +226,7 @@
ctrl->timC_offset[1] = 4;
ctrl->timC_offset[2] = 4;
ctrl->reg_320c_range_threshold = 16;
- } else if (ctrl->tCK <= TCK_533MHZ) {
- ctrl->tCK = TCK_533MHZ;
+ } else if (ctrl->tCK == TCK_533MHZ) {
ctrl->edge_offset[0] = 8;
ctrl->edge_offset[1] = 3;
ctrl->edge_offset[2] = 3;
@@ -206,30 +251,6 @@
/* DLL_CONFIG_MDLL_W_TIMER */
ctrl->reg_5064b0 = (128000 / ctrl->tCK) + 3;
- val32 = (1000 << 8) / ctrl->tCK;
- printk(BIOS_DEBUG, "Selected DRAM frequency: %u MHz\n", val32);
-
- /* Find CAS latency */
- val = DIV_ROUND_UP(ctrl->tAA, ctrl->tCK);
- printk(BIOS_DEBUG, "Minimum CAS latency : %uT\n", val);
- /* Find lowest supported CAS latency that satisfies the minimum value */
- while (!((ctrl->cas_supported >> (val - MIN_CAS)) & 1)
- && (ctrl->cas_supported >> (val - MIN_CAS))) {
- val++;
- }
- /* Is CAS supported */
- if (!(ctrl->cas_supported & (1 << (val - MIN_CAS)))) {
- printk(BIOS_ERR, "CAS %uT not supported. ", val);
- val = MAX_CAS;
- /* Find highest supported CAS latency */
- while (!((ctrl->cas_supported >> (val - MIN_CAS)) & 1))
- val--;
-
- printk(BIOS_ERR, "Using CAS %uT instead.\n", val);
- }
-
- printk(BIOS_DEBUG, "Selected CAS latency : %uT\n", val);
- ctrl->CAS = val;
ctrl->CWL = get_CWL(ctrl->tCK);
printk(BIOS_DEBUG, "Selected CWL latency : %uT\n", ctrl->CWL);
@@ -280,32 +301,18 @@
static void dram_freq(ramctr_timing * ctrl)
{
+
if (ctrl->tCK > TCK_400MHZ) {
- printk (BIOS_ERR, "DRAM frequency is under lowest supported "
- "frequency (400 MHz). Increasing to 400 MHz as last resort");
+ printk(BIOS_ERR, "DRAM frequency is under lowest supported "
+ "frequency (400 MHz). Increasing to 400 MHz as last resort");
ctrl->tCK = TCK_400MHZ;
}
+
while (1) {
u8 val2;
u32 reg1 = 0;
- /* Step 1 - Set target PCU frequency */
-
- if (ctrl->tCK <= TCK_1066MHZ) {
- ctrl->tCK = TCK_1066MHZ;
- } else if (ctrl->tCK <= TCK_933MHZ) {
- ctrl->tCK = TCK_933MHZ;
- } else if (ctrl->tCK <= TCK_800MHZ) {
- ctrl->tCK = TCK_800MHZ;
- } else if (ctrl->tCK <= TCK_666MHZ) {
- ctrl->tCK = TCK_666MHZ;
- } else if (ctrl->tCK <= TCK_533MHZ) {
- ctrl->tCK = TCK_533MHZ;
- } else if (ctrl->tCK <= TCK_400MHZ) {
- ctrl->tCK = TCK_400MHZ;
- } else {
- die ("No lock frequency found");
- }
+ find_cas_tck(ctrl);
/* Frequency multiplier. */
u32 FRQ = get_FRQ(ctrl->tCK);
@@ -318,7 +325,7 @@
if (val2)
return;
- /* Step 2 - Select frequency in the MCU */
+ /* Step 1 - Select frequency in the MCU */
reg1 = FRQ;
reg1 |= 0x80000000; // set running bit
MCHBAR32(MC_BIOS_REQ) = reg1;
@@ -331,7 +338,7 @@
}
printk(BIOS_DEBUG, "done in %d us\n", i * 10);
- /* Step 3 - Verify lock frequency */
+ /* Step 2 - Verify lock frequency */
reg1 = MCHBAR32(MC_BIOS_DATA);
val2 = (u8) reg1;
if (val2 >= FRQ) {