Ronald G. Minnich (rminnich(a)gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/2931
-gerrit
commit 712bd8c7679cd14a534d6510450a2cecdf54b893
Author: Ronald G. Minnich <rminnich(a)gmail.com>
Date: Mon Mar 18 09:49:54 2013 -0700
samsung/exynos5: add resource functions for the display port (2nd try)
This does NOT turn on the graphics.
The device tree has been changed enough so that, at the very least,
the correct functions are called at the correct time, with the
correct paramaters. We decided to yank the I2C entries as they did
not obvious function and might not even have been correct.
Not working, seemingly, but we need to add a 4M resource for
memory, and it seems it needs to be fixed at the address shown.
This address was chosen from current hardware.
We realized that the display code should be part of the cpu -- that's
how the hardware works!
(Note: this is a re-hash of Ron's previous attempt, but hopefully we
do not break the cbmem tables in this version)
Change-Id: I2caa350f8c0e681f71e9646898dcdb36e10115b2
Signed-off-by: Ronald G. Minnich <rminnich(a)gmail.com>
Signed-off-by: David Hendricks <dhendrix(a)chromium.org>
---
src/cpu/samsung/exynos5-common/Makefile.inc | 1 -
src/cpu/samsung/exynos5-common/displayport/Kconfig | 2 -
.../exynos5-common/displayport/Makefile.inc | 2 -
src/cpu/samsung/exynos5-common/displayport/chip.h | 40 --------
.../exynos5-common/displayport/displayport.c | 107 ---------------------
src/cpu/samsung/exynos5-common/exynos-fb.c | 4 +-
src/cpu/samsung/exynos5250/Kconfig | 2 +-
src/cpu/samsung/exynos5250/chip.h | 40 ++++++++
src/cpu/samsung/exynos5250/cpu.c | 86 ++++++++++++++++-
src/mainboard/google/snow/devicetree.cb | 38 +++-----
10 files changed, 141 insertions(+), 181 deletions(-)
diff --git a/src/cpu/samsung/exynos5-common/Makefile.inc b/src/cpu/samsung/exynos5-common/Makefile.inc
index 7abd75c..eb08fb6 100644
--- a/src/cpu/samsung/exynos5-common/Makefile.inc
+++ b/src/cpu/samsung/exynos5-common/Makefile.inc
@@ -22,4 +22,3 @@ ramstage-y += i2c.c
ramstage-y += s5p-dp-reg.c
ramstage-y += exynos-fb.c
-subdirs-y += displayport
diff --git a/src/cpu/samsung/exynos5-common/displayport/Kconfig b/src/cpu/samsung/exynos5-common/displayport/Kconfig
deleted file mode 100644
index 26d1422..0000000
--- a/src/cpu/samsung/exynos5-common/displayport/Kconfig
+++ /dev/null
@@ -1,2 +0,0 @@
-config EXYNOS_DISPLAYPORT
- bool
diff --git a/src/cpu/samsung/exynos5-common/displayport/Makefile.inc b/src/cpu/samsung/exynos5-common/displayport/Makefile.inc
deleted file mode 100644
index 7c52eaf..0000000
--- a/src/cpu/samsung/exynos5-common/displayport/Makefile.inc
+++ /dev/null
@@ -1,2 +0,0 @@
-ramstage-$(CONFIG_EXYNOS_DISPLAYPORT) += displayport.c
-
diff --git a/src/cpu/samsung/exynos5-common/displayport/chip.h b/src/cpu/samsung/exynos5-common/displayport/chip.h
deleted file mode 100644
index 53b7836..0000000
--- a/src/cpu/samsung/exynos5-common/displayport/chip.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * This file is part of the coreboot project.
- *
- * Copyright 2013 Google Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef CPU_SAMSUNG_EXYNOS5_COMMON_DISPLAYPORT_H
-#define CPU_SAMSUNG_EXYNOS5_COMMON_DISPLAYPORT_H
-
-struct cpu_samsung_exynos5_common_displayport_config {
- /* special magic numbers! */
- int clkval_f;
- int upper_margin;
- int lower_margin;
- int vsync;
- int left_margin;
- int right_margin;
- int hsync;
-
- int xres;
- int yres;
- int bpp;
-
- u32 lcdbase;
-};
-
-#endif /* CPU_SAMSUNG_EXYNOS5-COMMON_DISPLAYPORT_H */
diff --git a/src/cpu/samsung/exynos5-common/displayport/displayport.c b/src/cpu/samsung/exynos5-common/displayport/displayport.c
deleted file mode 100644
index 1c08bc7..0000000
--- a/src/cpu/samsung/exynos5-common/displayport/displayport.c
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * This file is part of the coreboot project.
- *
- * Copyright 2013 Google Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <delay.h>
-#include <arch/io.h>
-#include <device/device.h>
-
-/* we distinguish a display port device from a raw graphics device because there are
- * dramatic differences in startup depending on graphics usage. To make startup fast
- * and easier to understand and debug we explicitly name this common case. The alternate
- * approach, involving lots of machine and callbacks, is hard to debug and verify.
- */
-static void exynos_displayport_init(void)
-{
- struct cpu_samsung_exynos5_common_displayport_config *conf = dev->chip_info;
- /* put these on the stack. If, at some point, we want to move this code to a
- * pre-ram stage, it will be much easier.
- */
- vidinfo_t vi;
- struct exynos5_fimd_panel panel;
- void *lcdbase;
-
- memset(vi, 0, sizeof(vi));
- memset(panel, 0, sizeof(panel));
-
- panel.is_dp = 1; /* Display I/F is eDP */
- /* while it is true that we did a memset to zero,
- * we leave some 'set to zero' entries here to make
- * it clear what's going on. Graphics is confusing.
- */
- panel.is_mipi = 0;
- panel.fixvclk = 0;
- panel.ivclk = 0;
- panel.clkval_f = conf->clkval_f;
- panel.upper_margin = conf->upper_margin;
- panel.lower_margin = conf->lower_margin;
- panel.vsync = conf->vsync;
- panel.left_margin = conf->left_margin;
- panel.right_margin = conf->right_margin;
- panel.hsync = conf->hsync;
-
- vi->vl_col = conf->xres;
- vi->fl_row = conf->yres;
- vi->vl_bpix = conf->bpp;
- vi->cmap = cbmem_reserve(64*1024); /* The size is a magic number from hardware. */
-
- lcdbase = conf->lcdbase;
- printk(BIOS_DEBUG, "Initializing exynos VGA\n");
- ret = lcd_ctrl_init(&vi, &panel, lcdbase);
-#if 0
- ret = board_dp_lcd_vdd(blob, &wait_ms);
- ret = board_dp_bridge_setup(blob, &wait_ms);
- while (tries < 5) {
- ret = board_dp_bridge_init(blob, &wait_ms);
- ret = board_dp_hotplug(blob, &wait_ms);
- if (ret) {
- ret = board_dp_bridge_reset(blob, &wait_ms);
- continue;
- }
- ret = dp_controller_init(blob, &wait_ms);
- ret = board_dp_backlight_vdd(blob, &wait_ms);
- ret = board_dp_backlight_pwm(blob, &wait_ms);
- ret = board_dp_backlight_en(blob, &wait_ms);
- }
-#endif
-}
-
-static void exynos_displayport_noop(device_t dummy)
-{
-}
-
-static struct device_operations exynos_displayport_operations = {
- .read_resources = exynos_displayport_noop,
- .set_resources = exynos_displayport_noop,
- .enable_resources = exynos_displayport_noop,
- .init = exynos_displayport_init,
- .scan_bus = exynos_displayport_noop,
-};
-
-static void exynos_displayport_enable(struct device *dev)
-{
- if (dev->link_list != NULL)
- dev->ops = &exynos_displayport_operations;
-}
-
-struct chip_operations drivers_i2c_exynos_displayport_ops = {
- CHIP_NAME("exynos displayport")
- .enable_dev = exynos_displayport_enable;
-};
diff --git a/src/cpu/samsung/exynos5-common/exynos-fb.c b/src/cpu/samsung/exynos5-common/exynos-fb.c
index 30d0767..990a313 100644
--- a/src/cpu/samsung/exynos5-common/exynos-fb.c
+++ b/src/cpu/samsung/exynos5-common/exynos-fb.c
@@ -100,7 +100,7 @@ static void fimd_bypass(void)
{
struct exynos5_sysreg *sysreg = samsung_get_base_sysreg();
- /*setbits_le32(&sysreg->disp1blk_cfg, FIMDBYPASS_DISP1);*/
+ setbits_le32(&sysreg->disp1blk_cfg, FIMDBYPASS_DISP1);
sysreg->disp1blk_cfg &= ~FIMDBYPASS_DISP1;
}
@@ -586,7 +586,9 @@ int lcd_ctrl_init(vidinfo_t *panel_info, struct exynos5_fimd_panel *panel_data,
//vi->yres = panel_info->vl_row;
fimd_bypass();
+ printk(BIOS_SPEW, "fimd_bypass\n");
fb_init(panel_info, lcdbase, panel_data);
+ printk(BIOS_SPEW, "fb_init(%p, %p, %p\n",panel_info, lcdbase, panel_data);
/* Enable flushing after LCD writes if requested */
// forget it. lcd_set_flush_dcache(1);
diff --git a/src/cpu/samsung/exynos5250/Kconfig b/src/cpu/samsung/exynos5250/Kconfig
index ca306b6..cc67abd 100644
--- a/src/cpu/samsung/exynos5250/Kconfig
+++ b/src/cpu/samsung/exynos5250/Kconfig
@@ -96,4 +96,4 @@ config SYS_TEXT_BASE
config COREBOOT_TABLES_SIZE
hex
- default 0x100000
+ default 0x4000000
diff --git a/src/cpu/samsung/exynos5250/chip.h b/src/cpu/samsung/exynos5250/chip.h
new file mode 100644
index 0000000..798cd26
--- /dev/null
+++ b/src/cpu/samsung/exynos5250/chip.h
@@ -0,0 +1,40 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2013 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef CPU_SAMSUNG_EXYNOS5250_H
+#define CPU_SAMSUNG_EXYNOS5250_H
+
+struct cpu_samsung_exynos5250_config {
+ /* special magic numbers! */
+ int clkval_f;
+ int upper_margin;
+ int lower_margin;
+ int vsync;
+ int left_margin;
+ int right_margin;
+ int hsync;
+
+ int xres;
+ int yres;
+ int bpp;
+
+ u32 lcdbase;
+};
+
+#endif /* CPU_SAMSUNG_EXYNOS5250_H */
diff --git a/src/cpu/samsung/exynos5250/cpu.c b/src/cpu/samsung/exynos5250/cpu.c
index b6eae46..b0e6fc4 100644
--- a/src/cpu/samsung/exynos5250/cpu.c
+++ b/src/cpu/samsung/exynos5250/cpu.c
@@ -1,11 +1,92 @@
+#include <stdlib.h>
+#include <string.h>
+#include <stddef.h>
+#include <delay.h>
#include <console/console.h>
+#include <arch/io.h>
#include <device/device.h>
+#include <cbmem.h>
+#include <cpu/samsung/exynos5250/fimd.h>
+#include <cpu/samsung/exynos5-common/s5p-dp-core.h>
+#include "chip.h"
#define RAM_BASE_KB (CONFIG_SYS_SDRAM_BASE >> 10)
#define RAM_SIZE_KB (CONFIG_DRAM_SIZE_MB << 10UL)
+/* we distinguish a display port device from a raw graphics device because there are
+ * dramatic differences in startup depending on graphics usage. To make startup fast
+ * and easier to understand and debug we explicitly name this common case. The alternate
+ * approach, involving lots of machine and callbacks, is hard to debug and verify.
+ */
+static void exynos_displayport_init(device_t dev)
+{
+ int ret;
+ struct cpu_samsung_exynos5250_config *conf = dev->chip_info;
+ /* put these on the stack. If, at some point, we want to move this code to a
+ * pre-ram stage, it will be much easier.
+ */
+ vidinfo_t vi;
+ struct exynos5_fimd_panel panel;
+ u32 lcdbase;
+
+ printk(BIOS_SPEW, "%s: dev %p, conf %p\n", __func__, dev, conf);
+ memset(&vi, 0, sizeof(vi));
+ memset(&panel, 0, sizeof(panel));
+
+ panel.is_dp = 1; /* Display I/F is eDP */
+ /* while it is true that we did a memset to zero,
+ * we leave some 'set to zero' entries here to make
+ * it clear what's going on. Graphics is confusing.
+ */
+ panel.is_mipi = 0;
+ panel.fixvclk = 0;
+ panel.ivclk = 0;
+ panel.clkval_f = conf->clkval_f;
+ panel.upper_margin = conf->upper_margin;
+ panel.lower_margin = conf->lower_margin;
+ panel.vsync = conf->vsync;
+ panel.left_margin = conf->left_margin;
+ panel.right_margin = conf->right_margin;
+ panel.hsync = conf->hsync;
+
+ vi.vl_col = conf->xres;
+ vi.vl_row = conf->yres;
+ vi.vl_bpix = conf->bpp;
+ /* The size is a magic number from hardware. */
+ lcdbase = (uintptr_t)cbmem_add(CBMEM_ID_CONSOLE, 64*KiB);
+ printk(BIOS_SPEW, "lcd colormap base is %p\n", (void *)(lcdbase));
+// mmio_resource(dev, 0, conf->lcdbase/KiB, 64);
+// vi.cmap = (void *)conf->lcdbase;
+ mmio_resource(dev, 0, lcdbase/KiB, 64);
+ vi.cmap = (void *)lcdbase;
+// lcdbase = conf->lcdbase + 64*KiB;
+
+ lcdbase = (uintptr_t)cbmem_add(CBMEM_ID_CONSOLE, 16*MiB);
+ printk(BIOS_SPEW, "lcd framebuffer base is %p\n", (void *)(lcdbase));
+ mmio_resource(dev, 1, lcdbase/KiB, (conf->xres*conf->yres*4 + (KiB-1))/KiB);
+ printk(BIOS_DEBUG, "Initializing exynos VGA, base %p\n",(void *)lcdbase);
+ ret = lcd_ctrl_init(&vi, &panel, (void *)lcdbase);
+#if 0
+ ret = board_dp_lcd_vdd(blob, &wait_ms);
+ ret = board_dp_bridge_setup(blob, &wait_ms);
+ while (tries < 5) {
+ ret = board_dp_bridge_init(blob, &wait_ms);
+ ret = board_dp_hotplug(blob, &wait_ms);
+ if (ret) {
+ ret = board_dp_bridge_reset(blob, &wait_ms);
+ continue;
+ }
+ ret = dp_controller_init(blob, &wait_ms);
+ ret = board_dp_backlight_vdd(blob, &wait_ms);
+ ret = board_dp_backlight_pwm(blob, &wait_ms);
+ ret = board_dp_backlight_en(blob, &wait_ms);
+ }
+#endif
+}
+
static void cpu_init(device_t dev)
{
+ exynos_displayport_init(dev);
ram_resource(dev, 0, RAM_BASE_KB, RAM_SIZE_KB);
}
@@ -21,15 +102,16 @@ static struct device_operations cpu_ops = {
.scan_bus = 0,
};
-static void enable_dev(device_t dev)
+static void enable_exynos5250_dev(device_t dev)
{
/* Set the operations if it is a special bus type */
if (dev->path.type == DEVICE_PATH_CPU_CLUSTER) {
+ printk(BIOS_SPEW, "%s: CPU_CLUSTER\n", __func__);
dev->ops = &cpu_ops;
}
}
struct chip_operations cpu_samsung_exynos5250_ops = {
CHIP_NAME("CPU Samsung Exynos 5250")
- .enable_dev = enable_dev,
+ .enable_dev = enable_exynos5250_dev,
};
diff --git a/src/mainboard/google/snow/devicetree.cb b/src/mainboard/google/snow/devicetree.cb
index 5ad786e..4cdf47d 100644
--- a/src/mainboard/google/snow/devicetree.cb
+++ b/src/mainboard/google/snow/devicetree.cb
@@ -17,30 +17,18 @@
## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
##
-# FIXME: this is just a stub for now
chip cpu/samsung/exynos5250
-
-device cpu_cluster 0 on
-end
-
-device domain 0 on
- chip drivers/generic/generic # I2C0 controller
- device i2c 6 on end # ?
- device i2c 9 on end # ?
- end
- chip cpu/samsung/exynos5-common/displayport
- register "xres" = "1366"
- register "yres" = "768"
- register "bpp" = "16"
- # complex magic timing!
- register "clkval_f" = "2"
- register "upper_margin" = "14"
- register "lower_margin" = "3"
- register "vsync" = "5"
- register "left_margin" = "80"
- register "right_margin" = "48"
- register "hsync" = "32"
- register "lcdbase" = "0x10000000"
- end
-end
+ device cpu_cluster 0 on end
+ register "xres" = "1366"
+ register "yres" = "768"
+ register "bpp" = "16"
+ # complex magic timing!
+ register "clkval_f" = "2"
+ register "upper_margin" = "14"
+ register "lower_margin" = "3"
+ register "vsync" = "5"
+ register "left_margin" = "80"
+ register "right_margin" = "48"
+ register "hsync" = "32"
+ # register "lcdbase" = "0x50000000"
end
David Hendricks (dhendrix(a)chromium.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/2931
-gerrit
commit b63dde6271a99b12205b488a24724cbef44edd49
Author: Ronald G. Minnich <rminnich(a)gmail.com>
Date: Mon Mar 18 09:49:54 2013 -0700
samsung/exynos5: add resource functions for the display port (2nd try)
This does NOT turn on the graphics.
The device tree has been changed enough so that, at the very least,
the correct functions are called at the correct time, with the
correct paramaters. We decided to yank the I2C entries as they did
not obvious function and might not even have been correct.
Not working, seemingly, but we need to add a 4M resource for
memory, and it seems it needs to be fixed at the address shown.
This address was chosen from current hardware.
We realized that the display code should be part of the cpu -- that's
how the hardware works!
(Note: this is a re-hash of Ron's previous attempt, but hopefully we
do not break the cbmem tables in this version)
Change-Id: I2caa350f8c0e681f71e9646898dcdb36e10115b2
Signed-off-by: Ronald G. Minnich <rminnich(a)gmail.com>
Signed-off-by: David Hendricks <dhendrix(a)chromium.org>
---
src/cpu/samsung/exynos5-common/displayport/Kconfig | 2 -
.../exynos5-common/displayport/Makefile.inc | 2 -
src/cpu/samsung/exynos5-common/displayport/chip.h | 40 --------
.../exynos5-common/displayport/displayport.c | 107 ---------------------
src/cpu/samsung/exynos5-common/exynos-fb.c | 4 +-
src/cpu/samsung/exynos5250/Kconfig | 2 +-
src/cpu/samsung/exynos5250/chip.h | 40 ++++++++
src/cpu/samsung/exynos5250/cpu.c | 86 ++++++++++++++++-
src/mainboard/google/snow/devicetree.cb | 38 +++-----
9 files changed, 141 insertions(+), 180 deletions(-)
diff --git a/src/cpu/samsung/exynos5-common/displayport/Kconfig b/src/cpu/samsung/exynos5-common/displayport/Kconfig
deleted file mode 100644
index 26d1422..0000000
--- a/src/cpu/samsung/exynos5-common/displayport/Kconfig
+++ /dev/null
@@ -1,2 +0,0 @@
-config EXYNOS_DISPLAYPORT
- bool
diff --git a/src/cpu/samsung/exynos5-common/displayport/Makefile.inc b/src/cpu/samsung/exynos5-common/displayport/Makefile.inc
deleted file mode 100644
index 7c52eaf..0000000
--- a/src/cpu/samsung/exynos5-common/displayport/Makefile.inc
+++ /dev/null
@@ -1,2 +0,0 @@
-ramstage-$(CONFIG_EXYNOS_DISPLAYPORT) += displayport.c
-
diff --git a/src/cpu/samsung/exynos5-common/displayport/chip.h b/src/cpu/samsung/exynos5-common/displayport/chip.h
deleted file mode 100644
index 53b7836..0000000
--- a/src/cpu/samsung/exynos5-common/displayport/chip.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * This file is part of the coreboot project.
- *
- * Copyright 2013 Google Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef CPU_SAMSUNG_EXYNOS5_COMMON_DISPLAYPORT_H
-#define CPU_SAMSUNG_EXYNOS5_COMMON_DISPLAYPORT_H
-
-struct cpu_samsung_exynos5_common_displayport_config {
- /* special magic numbers! */
- int clkval_f;
- int upper_margin;
- int lower_margin;
- int vsync;
- int left_margin;
- int right_margin;
- int hsync;
-
- int xres;
- int yres;
- int bpp;
-
- u32 lcdbase;
-};
-
-#endif /* CPU_SAMSUNG_EXYNOS5-COMMON_DISPLAYPORT_H */
diff --git a/src/cpu/samsung/exynos5-common/displayport/displayport.c b/src/cpu/samsung/exynos5-common/displayport/displayport.c
deleted file mode 100644
index 1c08bc7..0000000
--- a/src/cpu/samsung/exynos5-common/displayport/displayport.c
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * This file is part of the coreboot project.
- *
- * Copyright 2013 Google Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <delay.h>
-#include <arch/io.h>
-#include <device/device.h>
-
-/* we distinguish a display port device from a raw graphics device because there are
- * dramatic differences in startup depending on graphics usage. To make startup fast
- * and easier to understand and debug we explicitly name this common case. The alternate
- * approach, involving lots of machine and callbacks, is hard to debug and verify.
- */
-static void exynos_displayport_init(void)
-{
- struct cpu_samsung_exynos5_common_displayport_config *conf = dev->chip_info;
- /* put these on the stack. If, at some point, we want to move this code to a
- * pre-ram stage, it will be much easier.
- */
- vidinfo_t vi;
- struct exynos5_fimd_panel panel;
- void *lcdbase;
-
- memset(vi, 0, sizeof(vi));
- memset(panel, 0, sizeof(panel));
-
- panel.is_dp = 1; /* Display I/F is eDP */
- /* while it is true that we did a memset to zero,
- * we leave some 'set to zero' entries here to make
- * it clear what's going on. Graphics is confusing.
- */
- panel.is_mipi = 0;
- panel.fixvclk = 0;
- panel.ivclk = 0;
- panel.clkval_f = conf->clkval_f;
- panel.upper_margin = conf->upper_margin;
- panel.lower_margin = conf->lower_margin;
- panel.vsync = conf->vsync;
- panel.left_margin = conf->left_margin;
- panel.right_margin = conf->right_margin;
- panel.hsync = conf->hsync;
-
- vi->vl_col = conf->xres;
- vi->fl_row = conf->yres;
- vi->vl_bpix = conf->bpp;
- vi->cmap = cbmem_reserve(64*1024); /* The size is a magic number from hardware. */
-
- lcdbase = conf->lcdbase;
- printk(BIOS_DEBUG, "Initializing exynos VGA\n");
- ret = lcd_ctrl_init(&vi, &panel, lcdbase);
-#if 0
- ret = board_dp_lcd_vdd(blob, &wait_ms);
- ret = board_dp_bridge_setup(blob, &wait_ms);
- while (tries < 5) {
- ret = board_dp_bridge_init(blob, &wait_ms);
- ret = board_dp_hotplug(blob, &wait_ms);
- if (ret) {
- ret = board_dp_bridge_reset(blob, &wait_ms);
- continue;
- }
- ret = dp_controller_init(blob, &wait_ms);
- ret = board_dp_backlight_vdd(blob, &wait_ms);
- ret = board_dp_backlight_pwm(blob, &wait_ms);
- ret = board_dp_backlight_en(blob, &wait_ms);
- }
-#endif
-}
-
-static void exynos_displayport_noop(device_t dummy)
-{
-}
-
-static struct device_operations exynos_displayport_operations = {
- .read_resources = exynos_displayport_noop,
- .set_resources = exynos_displayport_noop,
- .enable_resources = exynos_displayport_noop,
- .init = exynos_displayport_init,
- .scan_bus = exynos_displayport_noop,
-};
-
-static void exynos_displayport_enable(struct device *dev)
-{
- if (dev->link_list != NULL)
- dev->ops = &exynos_displayport_operations;
-}
-
-struct chip_operations drivers_i2c_exynos_displayport_ops = {
- CHIP_NAME("exynos displayport")
- .enable_dev = exynos_displayport_enable;
-};
diff --git a/src/cpu/samsung/exynos5-common/exynos-fb.c b/src/cpu/samsung/exynos5-common/exynos-fb.c
index 30d0767..990a313 100644
--- a/src/cpu/samsung/exynos5-common/exynos-fb.c
+++ b/src/cpu/samsung/exynos5-common/exynos-fb.c
@@ -100,7 +100,7 @@ static void fimd_bypass(void)
{
struct exynos5_sysreg *sysreg = samsung_get_base_sysreg();
- /*setbits_le32(&sysreg->disp1blk_cfg, FIMDBYPASS_DISP1);*/
+ setbits_le32(&sysreg->disp1blk_cfg, FIMDBYPASS_DISP1);
sysreg->disp1blk_cfg &= ~FIMDBYPASS_DISP1;
}
@@ -586,7 +586,9 @@ int lcd_ctrl_init(vidinfo_t *panel_info, struct exynos5_fimd_panel *panel_data,
//vi->yres = panel_info->vl_row;
fimd_bypass();
+ printk(BIOS_SPEW, "fimd_bypass\n");
fb_init(panel_info, lcdbase, panel_data);
+ printk(BIOS_SPEW, "fb_init(%p, %p, %p\n",panel_info, lcdbase, panel_data);
/* Enable flushing after LCD writes if requested */
// forget it. lcd_set_flush_dcache(1);
diff --git a/src/cpu/samsung/exynos5250/Kconfig b/src/cpu/samsung/exynos5250/Kconfig
index ca306b6..cc67abd 100644
--- a/src/cpu/samsung/exynos5250/Kconfig
+++ b/src/cpu/samsung/exynos5250/Kconfig
@@ -96,4 +96,4 @@ config SYS_TEXT_BASE
config COREBOOT_TABLES_SIZE
hex
- default 0x100000
+ default 0x4000000
diff --git a/src/cpu/samsung/exynos5250/chip.h b/src/cpu/samsung/exynos5250/chip.h
new file mode 100644
index 0000000..798cd26
--- /dev/null
+++ b/src/cpu/samsung/exynos5250/chip.h
@@ -0,0 +1,40 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2013 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef CPU_SAMSUNG_EXYNOS5250_H
+#define CPU_SAMSUNG_EXYNOS5250_H
+
+struct cpu_samsung_exynos5250_config {
+ /* special magic numbers! */
+ int clkval_f;
+ int upper_margin;
+ int lower_margin;
+ int vsync;
+ int left_margin;
+ int right_margin;
+ int hsync;
+
+ int xres;
+ int yres;
+ int bpp;
+
+ u32 lcdbase;
+};
+
+#endif /* CPU_SAMSUNG_EXYNOS5250_H */
diff --git a/src/cpu/samsung/exynos5250/cpu.c b/src/cpu/samsung/exynos5250/cpu.c
index b6eae46..b0e6fc4 100644
--- a/src/cpu/samsung/exynos5250/cpu.c
+++ b/src/cpu/samsung/exynos5250/cpu.c
@@ -1,11 +1,92 @@
+#include <stdlib.h>
+#include <string.h>
+#include <stddef.h>
+#include <delay.h>
#include <console/console.h>
+#include <arch/io.h>
#include <device/device.h>
+#include <cbmem.h>
+#include <cpu/samsung/exynos5250/fimd.h>
+#include <cpu/samsung/exynos5-common/s5p-dp-core.h>
+#include "chip.h"
#define RAM_BASE_KB (CONFIG_SYS_SDRAM_BASE >> 10)
#define RAM_SIZE_KB (CONFIG_DRAM_SIZE_MB << 10UL)
+/* we distinguish a display port device from a raw graphics device because there are
+ * dramatic differences in startup depending on graphics usage. To make startup fast
+ * and easier to understand and debug we explicitly name this common case. The alternate
+ * approach, involving lots of machine and callbacks, is hard to debug and verify.
+ */
+static void exynos_displayport_init(device_t dev)
+{
+ int ret;
+ struct cpu_samsung_exynos5250_config *conf = dev->chip_info;
+ /* put these on the stack. If, at some point, we want to move this code to a
+ * pre-ram stage, it will be much easier.
+ */
+ vidinfo_t vi;
+ struct exynos5_fimd_panel panel;
+ u32 lcdbase;
+
+ printk(BIOS_SPEW, "%s: dev %p, conf %p\n", __func__, dev, conf);
+ memset(&vi, 0, sizeof(vi));
+ memset(&panel, 0, sizeof(panel));
+
+ panel.is_dp = 1; /* Display I/F is eDP */
+ /* while it is true that we did a memset to zero,
+ * we leave some 'set to zero' entries here to make
+ * it clear what's going on. Graphics is confusing.
+ */
+ panel.is_mipi = 0;
+ panel.fixvclk = 0;
+ panel.ivclk = 0;
+ panel.clkval_f = conf->clkval_f;
+ panel.upper_margin = conf->upper_margin;
+ panel.lower_margin = conf->lower_margin;
+ panel.vsync = conf->vsync;
+ panel.left_margin = conf->left_margin;
+ panel.right_margin = conf->right_margin;
+ panel.hsync = conf->hsync;
+
+ vi.vl_col = conf->xres;
+ vi.vl_row = conf->yres;
+ vi.vl_bpix = conf->bpp;
+ /* The size is a magic number from hardware. */
+ lcdbase = (uintptr_t)cbmem_add(CBMEM_ID_CONSOLE, 64*KiB);
+ printk(BIOS_SPEW, "lcd colormap base is %p\n", (void *)(lcdbase));
+// mmio_resource(dev, 0, conf->lcdbase/KiB, 64);
+// vi.cmap = (void *)conf->lcdbase;
+ mmio_resource(dev, 0, lcdbase/KiB, 64);
+ vi.cmap = (void *)lcdbase;
+// lcdbase = conf->lcdbase + 64*KiB;
+
+ lcdbase = (uintptr_t)cbmem_add(CBMEM_ID_CONSOLE, 16*MiB);
+ printk(BIOS_SPEW, "lcd framebuffer base is %p\n", (void *)(lcdbase));
+ mmio_resource(dev, 1, lcdbase/KiB, (conf->xres*conf->yres*4 + (KiB-1))/KiB);
+ printk(BIOS_DEBUG, "Initializing exynos VGA, base %p\n",(void *)lcdbase);
+ ret = lcd_ctrl_init(&vi, &panel, (void *)lcdbase);
+#if 0
+ ret = board_dp_lcd_vdd(blob, &wait_ms);
+ ret = board_dp_bridge_setup(blob, &wait_ms);
+ while (tries < 5) {
+ ret = board_dp_bridge_init(blob, &wait_ms);
+ ret = board_dp_hotplug(blob, &wait_ms);
+ if (ret) {
+ ret = board_dp_bridge_reset(blob, &wait_ms);
+ continue;
+ }
+ ret = dp_controller_init(blob, &wait_ms);
+ ret = board_dp_backlight_vdd(blob, &wait_ms);
+ ret = board_dp_backlight_pwm(blob, &wait_ms);
+ ret = board_dp_backlight_en(blob, &wait_ms);
+ }
+#endif
+}
+
static void cpu_init(device_t dev)
{
+ exynos_displayport_init(dev);
ram_resource(dev, 0, RAM_BASE_KB, RAM_SIZE_KB);
}
@@ -21,15 +102,16 @@ static struct device_operations cpu_ops = {
.scan_bus = 0,
};
-static void enable_dev(device_t dev)
+static void enable_exynos5250_dev(device_t dev)
{
/* Set the operations if it is a special bus type */
if (dev->path.type == DEVICE_PATH_CPU_CLUSTER) {
+ printk(BIOS_SPEW, "%s: CPU_CLUSTER\n", __func__);
dev->ops = &cpu_ops;
}
}
struct chip_operations cpu_samsung_exynos5250_ops = {
CHIP_NAME("CPU Samsung Exynos 5250")
- .enable_dev = enable_dev,
+ .enable_dev = enable_exynos5250_dev,
};
diff --git a/src/mainboard/google/snow/devicetree.cb b/src/mainboard/google/snow/devicetree.cb
index 5ad786e..4cdf47d 100644
--- a/src/mainboard/google/snow/devicetree.cb
+++ b/src/mainboard/google/snow/devicetree.cb
@@ -17,30 +17,18 @@
## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
##
-# FIXME: this is just a stub for now
chip cpu/samsung/exynos5250
-
-device cpu_cluster 0 on
-end
-
-device domain 0 on
- chip drivers/generic/generic # I2C0 controller
- device i2c 6 on end # ?
- device i2c 9 on end # ?
- end
- chip cpu/samsung/exynos5-common/displayport
- register "xres" = "1366"
- register "yres" = "768"
- register "bpp" = "16"
- # complex magic timing!
- register "clkval_f" = "2"
- register "upper_margin" = "14"
- register "lower_margin" = "3"
- register "vsync" = "5"
- register "left_margin" = "80"
- register "right_margin" = "48"
- register "hsync" = "32"
- register "lcdbase" = "0x10000000"
- end
-end
+ device cpu_cluster 0 on end
+ register "xres" = "1366"
+ register "yres" = "768"
+ register "bpp" = "16"
+ # complex magic timing!
+ register "clkval_f" = "2"
+ register "upper_margin" = "14"
+ register "lower_margin" = "3"
+ register "vsync" = "5"
+ register "left_margin" = "80"
+ register "right_margin" = "48"
+ register "hsync" = "32"
+ # register "lcdbase" = "0x50000000"
end
David Hendricks (dhendrix(a)chromium.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/2926
-gerrit
commit dacbb737069217455d605296bec67c388cc53471
Author: David Hendricks <dhendrix(a)chromium.org>
Date: Tue Mar 26 17:45:39 2013 -0700
armv7: fix argument when using dccimvac
This passes the incremented value of the loop into dccimvac. D'oh!
Change-Id: I6098440ea48a9b6429380d5913fce6d36e3afb41
Signed-off-by: David Hendricks <dhendrix(a)chromium.org>
---
src/arch/armv7/lib/cache.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/arch/armv7/lib/cache.c b/src/arch/armv7/lib/cache.c
index c93da36..b8f4d88 100644
--- a/src/arch/armv7/lib/cache.c
+++ b/src/arch/armv7/lib/cache.c
@@ -188,7 +188,7 @@ static void dcache_op_mva(unsigned long addr,
for (i = addr & ~(line - 1); i < addr + len; i += line) {
switch(op) {
case OP_DCCIMVAC:
- dccimvac(addr);
+ dccimvac(i);
break;
default:
break;
David Hendricks (dhendrix(a)chromium.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/2929
-gerrit
commit 007e33c7cbb43d68d4ce2ce2a3a4e1f9b0a1cb71
Author: David Hendricks <dhendrix(a)chromium.org>
Date: Tue Mar 26 21:34:01 2013 -0700
armv7: update sync barrier usage in dcache_op_set_way()
This moves the dsb() before the loop to sync any outstanding memory
accesses, and adds an isb() after the loop to ensure all outstanding
instructions are completed.
Change-Id: I1a11b39f104ae780370cfd2db3badcf4e91dc017
Signed-off-by: David Hendricks <dhendrix(a)chromium.org>
---
src/arch/armv7/lib/cache.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/arch/armv7/lib/cache.c b/src/arch/armv7/lib/cache.c
index 0e28ac4..3cd0e0a 100644
--- a/src/arch/armv7/lib/cache.c
+++ b/src/arch/armv7/lib/cache.c
@@ -111,6 +111,8 @@ static void dcache_op_set_way(enum dcache_op op)
/* FIXME: do we need to use CTR.DminLine here? */
linesize_bytes = (1 << ((ccsidr & 0x7) + 2)) * 4;
+ dsb();
+
/*
* Set/way operations require an interesting bit packing. See section
* B4-35 in the ARMv7 Architecture Reference Manual:
@@ -144,8 +146,7 @@ static void dcache_op_set_way(enum dcache_op op)
}
}
}
-
- dsb();
+ isb();
}
void dcache_clean_invalidate_all(void)
David Hendricks (dhendrix(a)chromium.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/2927
-gerrit
commit 2b42a1e4737000467abd5c07a8ef1bc883b16e09
Author: David Hendricks <dhendrix(a)chromium.org>
Date: Tue Mar 26 17:47:05 2013 -0700
armv7: cosmetic changes to dcache_op_mva()
This is just a cosmetic change to dcache_op_mva() to (hopefully) make
it a easier to follow and more difficult to screw up.
Change-Id: Ia348b2d58f2f2bf5c3cafabcfba06bc411937dba
Signed-off-by: David Hendricks <dhendrix(a)chromium.org>
---
src/arch/armv7/lib/cache.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/src/arch/armv7/lib/cache.c b/src/arch/armv7/lib/cache.c
index b8f4d88..0e28ac4 100644
--- a/src/arch/armv7/lib/cache.c
+++ b/src/arch/armv7/lib/cache.c
@@ -180,19 +180,21 @@ static unsigned int line_bytes(void)
static void dcache_op_mva(unsigned long addr,
unsigned long len, enum dcache_op op)
{
- unsigned long line, i;
+ unsigned long line, linesize;
- line = line_bytes();
+ linesize = line_bytes();
+ line = addr & ~(linesize - 1);
dsb();
- for (i = addr & ~(line - 1); i < addr + len; i += line) {
+ while (line < addr + len) {
switch(op) {
case OP_DCCIMVAC:
- dccimvac(i);
+ dccimvac(line);
break;
default:
break;
}
+ line += linesize;
}
isb();
}
David Hendricks (dhendrix(a)chromium.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/2926
-gerrit
commit 6b66dd99315316566ddd4e73e78c675f2eb67a18
Author: David Hendricks <dhendrix(a)chromium.org>
Date: Tue Mar 26 17:45:39 2013 -0700
armv7: fix argument when using dccimvac
This actually passes the page number into dccimvac. D'oh!
Change-Id: I6098440ea48a9b6429380d5913fce6d36e3afb41
Signed-off-by: David Hendricks <dhendrix(a)chromium.org>
---
src/arch/armv7/lib/cache.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/arch/armv7/lib/cache.c b/src/arch/armv7/lib/cache.c
index c93da36..b8f4d88 100644
--- a/src/arch/armv7/lib/cache.c
+++ b/src/arch/armv7/lib/cache.c
@@ -188,7 +188,7 @@ static void dcache_op_mva(unsigned long addr,
for (i = addr & ~(line - 1); i < addr + len; i += line) {
switch(op) {
case OP_DCCIMVAC:
- dccimvac(addr);
+ dccimvac(i);
break;
default:
break;
Aaron Durbin (adurbin(a)google.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/2925
-gerrit
commit 3ebb55348c3660dbc27042858a02daa1e798e599
Author: Aaron Durbin <adurbin(a)chromium.org>
Date: Tue Mar 26 21:27:04 2013 -0500
x86: mtrr: add hole punching support
Some ranges would use less variable MTRRs if an UC area
can be carved off the top of larger WB range. Implement this
approach by doing 3 passes over each region in the addres space:
1. UC default type. Cover non-UC and non-WB regions with respectie type.
Punch UC hole at upper end of larger WB regions with WB type.
2. UC default type. Cover non-UC regions with respective type.
3. WB default type. Cover non-WB regions with respective type.
The hole at upper end of a region uses the same min alignment of 64MiB.
Below are results using a combination of options. The board this was
tested on has 10 variable MTRRs at its disposal. It has 4GiB of RAM.
IO hole config #1: hole starts at 0xad800000
No CACHE_ROM or WRCOMB resources (takes 4 MTRRs):
MTRR: Physical address space:
0x0000000000000000 - 0x00000000000a0000 size 0x000a0000 type 6
0x00000000000a0000 - 0x00000000000c0000 size 0x00020000 type 0
0x00000000000c0000 - 0x00000000ad800000 size 0xad740000 type 6
0x00000000ad800000 - 0x0000000100000000 size 0x52800000 type 0
0x0000000100000000 - 0x000000014f600000 size 0x4f600000 type 6
MTRR: default type WB/UC MTRR counts: 4/9.
MTRR: WB selected as default type.
MTRR: 0 base 0x00000000ad800000 mask 0x0000007fff800000 type 0
MTRR: 1 base 0x00000000ae000000 mask 0x0000007ffe000000 type 0
MTRR: 2 base 0x00000000b0000000 mask 0x0000007ff0000000 type 0
MTRR: 3 base 0x00000000c0000000 mask 0x0000007fc0000000 type 0
No CACHE_ROM. 1 WRCOMB resource (takes 6 MTRRs):
MTRR: Physical address space:
0x0000000000000000 - 0x00000000000a0000 size 0x000a0000 type 6
0x00000000000a0000 - 0x00000000000c0000 size 0x00020000 type 0
0x00000000000c0000 - 0x00000000ad800000 size 0xad740000 type 6
0x00000000ad800000 - 0x00000000d0000000 size 0x22800000 type 0
0x00000000d0000000 - 0x00000000e0000000 size 0x10000000 type 1
0x00000000e0000000 - 0x0000000100000000 size 0x20000000 type 0
0x0000000100000000 - 0x000000014f600000 size 0x4f600000 type 6
MTRR: default type WB/UC MTRR counts: 6/10.
MTRR: WB selected as default type.
MTRR: 0 base 0x00000000ad800000 mask 0x0000007fff800000 type 0
MTRR: 1 base 0x00000000ae000000 mask 0x0000007ffe000000 type 0
MTRR: 2 base 0x00000000b0000000 mask 0x0000007ff0000000 type 0
MTRR: 3 base 0x00000000c0000000 mask 0x0000007ff0000000 type 0
MTRR: 4 base 0x00000000d0000000 mask 0x0000007ff0000000 type 1
MTRR: 5 base 0x00000000e0000000 mask 0x0000007fe0000000 type 0
CACHE_ROM and no WRCOMB resources (taks 10 MTRRs):
MTRR: Physical address space:
0x0000000000000000 - 0x00000000000a0000 size 0x000a0000 type 6
0x00000000000a0000 - 0x00000000000c0000 size 0x00020000 type 0
0x00000000000c0000 - 0x00000000ad800000 size 0xad740000 type 6
0x00000000ad800000 - 0x00000000ff800000 size 0x52000000 type 0
0x00000000ff800000 - 0x0000000100000000 size 0x00800000 type 5
0x0000000100000000 - 0x000000014f600000 size 0x4f600000 type 6
MTRR: default type WB/UC MTRR counts: 11/10.
MTRR: UC selected as default type.
MTRR: 0 base 0x0000000000000000 mask 0x0000007f80000000 type 6
MTRR: 1 base 0x0000000080000000 mask 0x0000007fe0000000 type 6
MTRR: 2 base 0x00000000a0000000 mask 0x0000007ff0000000 type 6
MTRR: 3 base 0x00000000ad800000 mask 0x0000007fff800000 type 0
MTRR: 4 base 0x00000000ae000000 mask 0x0000007ffe000000 type 0
MTRR: 5 base 0x00000000ff800000 mask 0x0000007fff800000 type 0
MTRR: 6 base 0x0000000100000000 mask 0x0000007fc0000000 type 6
MTRR: 7 base 0x0000000140000000 mask 0x0000007ff0000000 type 6
Taking a reserved OS MTRR.
MTRR: 8 base 0x000000014f600000 mask 0x0000007fffe00000 type 0
Taking a reserved OS MTRR.
MTRR: 9 base 0x000000014f800000 mask 0x0000007fff800000 type 0
A combination of CACHE_ROM and WRCOMB just won't work.
IO hole config #2: hole starts at 0x80000000:
No CACHE_ROM or WRCOMB resources (takes 1 MTRR):
MTRR: Physical address space:
0x0000000000000000 - 0x00000000000a0000 size 0x000a0000 type 6
0x00000000000a0000 - 0x00000000000c0000 size 0x00020000 type 0
0x00000000000c0000 - 0x0000000080000000 size 0x7ff40000 type 6
0x0000000080000000 - 0x0000000100000000 size 0x80000000 type 0
0x0000000100000000 - 0x000000017ce00000 size 0x7ce00000 type 6
MTRR: default type WB/UC MTRR counts: 1/5.
MTRR: WB selected as default type.
MTRR: 0 base 0x0000000080000000 mask 0x0000007f80000000 type 0
No CACHE_ROM. 1 WRCOMB resource (takes 4 MTRRs):
MTRR: Physical address space:
0x0000000000000000 - 0x00000000000a0000 size 0x000a0000 type 6
0x00000000000a0000 - 0x00000000000c0000 size 0x00020000 type 0
0x00000000000c0000 - 0x0000000080000000 size 0x7ff40000 type 6
0x0000000080000000 - 0x00000000d0000000 size 0x50000000 type 0
0x00000000d0000000 - 0x00000000e0000000 size 0x10000000 type 1
0x00000000e0000000 - 0x0000000100000000 size 0x20000000 type 0
0x0000000100000000 - 0x000000017ce00000 size 0x7ce00000 type 6
MTRR: default type WB/UC MTRR counts: 4/6.
MTRR: WB selected as default type.
MTRR: 0 base 0x0000000080000000 mask 0x0000007fc0000000 type 0
MTRR: 1 base 0x00000000c0000000 mask 0x0000007ff0000000 type 0
MTRR: 2 base 0x00000000d0000000 mask 0x0000007ff0000000 type 1
MTRR: 3 base 0x00000000e0000000 mask 0x0000007fe0000000 type 0
CACHE_ROM and no WRCOMB resources (takes 6 MTRRs):
MTRR: Physical address space:
0x0000000000000000 - 0x00000000000a0000 size 0x000a0000 type 6
0x00000000000a0000 - 0x00000000000c0000 size 0x00020000 type 0
0x00000000000c0000 - 0x0000000080000000 size 0x7ff40000 type 6
0x0000000080000000 - 0x00000000ff800000 size 0x7f800000 type 0
0x00000000ff800000 - 0x0000000100000000 size 0x00800000 type 5
0x0000000100000000 - 0x000000017ce00000 size 0x7ce00000 type 6
MTRR: default type WB/UC MTRR counts: 9/6.
MTRR: UC selected as default type.
MTRR: 0 base 0x0000000000000000 mask 0x0000007f80000000 type 6
MTRR: 1 base 0x00000000ff800000 mask 0x0000007fff800000 type 0
MTRR: 2 base 0x0000000100000000 mask 0x0000007f80000000 type 6
MTRR: 3 base 0x000000017ce00000 mask 0x0000007fffe00000 type 0
MTRR: 4 base 0x000000017d000000 mask 0x0000007fff000000 type 0
MTRR: 5 base 0x000000017e000000 mask 0x0000007ffe000000 type 0
CACHE_ROM and 1 WRCOMB resource (takes 7 MTRRs):
MTRR: Physical address space:
0x0000000000000000 - 0x00000000000a0000 size 0x000a0000 type 6
0x00000000000a0000 - 0x00000000000c0000 size 0x00020000 type 0
0x00000000000c0000 - 0x0000000080000000 size 0x7ff40000 type 6
0x0000000080000000 - 0x00000000d0000000 size 0x50000000 type 0
0x00000000d0000000 - 0x00000000e0000000 size 0x10000000 type 1
0x00000000e0000000 - 0x00000000ff800000 size 0x1f800000 type 0
0x00000000ff800000 - 0x0000000100000000 size 0x00800000 type 5
0x0000000100000000 - 0x000000017ce00000 size 0x7ce00000 type 6
MTRR: default type WB/UC MTRR counts: 10/7.
MTRR: UC selected as default type.
MTRR: 0 base 0x0000000000000000 mask 0x0000007f80000000 type 6
MTRR: 1 base 0x00000000d0000000 mask 0x0000007ff0000000 type 1
MTRR: 2 base 0x00000000ff800000 mask 0x0000007fff800000 type 0
MTRR: 3 base 0x0000000100000000 mask 0x0000007f80000000 type 6
MTRR: 4 base 0x000000017ce00000 mask 0x0000007fffe00000 type 0
MTRR: 5 base 0x000000017d000000 mask 0x0000007fff000000 type 0
MTRR: 6 base 0x000000017e000000 mask 0x0000007ffe000000 type 0
Change-Id: Iceb9b64991accf558caae2e7b0205951e9bcde44
Signed-off-by: Aaron Durbin <adurbin(a)chromium.org>
---
src/cpu/x86/mtrr/mtrr.c | 233 ++++++++++++++++++++++++++++++++++++++----------
1 file changed, 185 insertions(+), 48 deletions(-)
diff --git a/src/cpu/x86/mtrr/mtrr.c b/src/cpu/x86/mtrr/mtrr.c
index d8c5da1..f1f423b 100644
--- a/src/cpu/x86/mtrr/mtrr.c
+++ b/src/cpu/x86/mtrr/mtrr.c
@@ -122,6 +122,21 @@ static inline unsigned int fls(unsigned int x)
#define RANGE_1MB PHYS_TO_RANGE_ADDR(1 << 20)
#define RANGE_4GB (1 << (ADDR_SHIFT_TO_RANGE_SHIFT(32)))
+/*
+ * The default MTRR type selection uses 3 approaches for selecting the
+ * optimal number of variable MTRRs. For each range do 3 calculations:
+ * 1. UC as default type with no holes at top of range.
+ * 2. UC as default using holes at top of range.
+ * 3. WB as default.
+ * If using holes is optimal for a range when UC is the default type the
+ * tag is updated to direct the commit routine to use a hole at the top
+ * of a range.
+ */
+#define MTRR_ALGO_SHIFT (8)
+#define MTRR_TAG_MASK ((1 << MTRR_ALGO_SHIFT) - 1)
+/* If the default type is UC use the hole carving algorithm for a range. */
+#define MTRR_RANGE_UC_USE_HOLE (1 << MTRR_ALGO_SHIFT)
+
static inline uint32_t range_entry_base_mtrr_addr(struct range_entry *r)
{
return PHYS_TO_RANGE_ADDR(range_entry_base(r));
@@ -132,6 +147,11 @@ static inline uint32_t range_entry_end_mtrr_addr(struct range_entry *r)
return PHYS_TO_RANGE_ADDR(range_entry_end(r));
}
+static inline int range_entry_mtrr_type(struct range_entry *r)
+{
+ return range_entry_tag(r) & MTRR_TAG_MASK;
+}
+
static struct memranges *get_physical_address_space(void)
{
static struct memranges *addr_space;
@@ -491,9 +511,72 @@ static void calc_var_mtrr_range(struct var_mtrr_state *var_state,
}
}
-static void setup_var_mtrrs_by_state(struct var_mtrr_state *var_state)
+static void calc_var_mtrrs_with_hole(struct var_mtrr_state *var_state,
+ struct range_entry *r)
{
- struct range_entry *r;
+ uint32_t a1, a2, b1, b2;
+ int mtrr_type;
+ struct range_entry *next;
+
+ /*
+ * Determine MTRRs based on the following algoirthm for the given entry:
+ * +------------------+ b2 = round_up(end)
+ * | 0 or more bytes | <-- hole is carved out between b1 and b2
+ * +------------------+ a2 = b1 = end
+ * | |
+ * +------------------+ a1 = begin
+ *
+ * Thus, there are 3 sub-ranges to configure variable MTRRs for.
+ */
+ mtrr_type = range_entry_mtrr_type(r);
+
+ a1 = range_entry_base_mtrr_addr(r);
+ a2 = range_entry_end_mtrr_addr(r);
+
+ /* The end address is under 1MiB. The fixed MTRRs take
+ * precedence over the variable ones. Therefore this range
+ * can be ignored. */
+ if (a2 < RANGE_1MB)
+ return;
+
+ /* Again, the fixed MTRRs take precedence so the beginning
+ * of the range can be set to 0 if it starts below 1MiB. */
+ if (a1 < RANGE_1MB)
+ a1 = 0;
+
+ /* If the range starts above 4GiB the processing is done. */
+ if (!var_state->above4gb && a1 >= RANGE_4GB)
+ return;
+
+ /* Clip the upper address to 4GiB if addresses above 4GiB
+ * are not being processed. */
+ if (!var_state->above4gb && a2 > RANGE_4GB)
+ a2 = RANGE_4GB;
+
+ b1 = a2;
+ b2 = round_up(a2, MTRR_MIN_ALIGN);
+
+ /* Check against the next range. If the current range_entry is the
+ * last entry then carving a hole is no problem. If the current entry
+ * isn't the last entry then check that the last entry covers the
+ * entire hole range with the default mtrr type. */
+ next = memranges_next_entry(var_state->addr_space, r);
+ if (next != NULL &&
+ (range_entry_mtrr_type(next) != var_state->def_mtrr_type ||
+ range_entry_end_mtrr_addr(next) < b2)) {
+ calc_var_mtrr_range(var_state, a1, a2 - a1, mtrr_type);
+ return;
+ }
+
+ calc_var_mtrr_range(var_state, a1, b2 - a1, mtrr_type);
+ calc_var_mtrr_range(var_state, b1, b2 - b1, var_state->def_mtrr_type);
+}
+
+static void calc_var_mtrrs_without_hole(struct var_mtrr_state *var_state,
+ struct range_entry *r)
+{
+ uint32_t a1, a2, b1, b2, c1, c2;
+ int mtrr_type;
/*
* For each range that meets the non-default type process it in the
@@ -508,51 +591,44 @@ static void setup_var_mtrrs_by_state(struct var_mtrr_state *var_state)
*
* Thus, there are 3 sub-ranges to configure variable MTRRs for.
*/
- memranges_each_entry(r, var_state->addr_space) {
- uint32_t a1, a2, b1, b2, c1, c2;
- int mtrr_type = range_entry_tag(r);
+ mtrr_type = range_entry_mtrr_type(r);
- /* Skip default type. */
- if (var_state->def_mtrr_type == mtrr_type)
- continue;
-
- a1 = range_entry_base_mtrr_addr(r);
- c2 = range_entry_end_mtrr_addr(r);
+ a1 = range_entry_base_mtrr_addr(r);
+ c2 = range_entry_end_mtrr_addr(r);
- /* The end address is under 1MiB. The fixed MTRRs take
- * precedence over the variable ones. Therefore this range
- * can be ignored. */
- if (c2 < RANGE_1MB)
- continue;
+ /* The end address is under 1MiB. The fixed MTRRs take
+ * precedence over the variable ones. Therefore this range
+ * can be ignored. */
+ if (c2 < RANGE_1MB)
+ return;
- /* Again, the fixed MTRRs take precedence so the beginning
- * of the range can be set to 0 if it starts below 1MiB. */
- if (a1 < RANGE_1MB)
- a1 = 0;
+ /* Again, the fixed MTRRs take precedence so the beginning
+ * of the range can be set to 0 if it starts below 1MiB. */
+ if (a1 < RANGE_1MB)
+ a1 = 0;
- /* If the range starts above 4GiB the processing is done. */
- if (!var_state->above4gb && a1 >= RANGE_4GB)
- break;
+ /* If the range starts above 4GiB the processing is done. */
+ if (!var_state->above4gb && a1 >= RANGE_4GB)
+ return;
- /* Clip the upper address to 4GiB if addresses above 4GiB
- * are not being processed. */
- if (!var_state->above4gb && c2 > RANGE_4GB)
- c2 = RANGE_4GB;
+ /* Clip the upper address to 4GiB if addresses above 4GiB
+ * are not being processed. */
+ if (!var_state->above4gb && c2 > RANGE_4GB)
+ c2 = RANGE_4GB;
- /* Don't align up or down on the range if it is smaller
- * than the minimum granularity. */
- if ((c2 - a1) < MTRR_MIN_ALIGN) {
- calc_var_mtrr_range(var_state, a1, c2 - a1, mtrr_type);
- continue;
- }
+ /* Don't align up or down on the range if it is smaller
+ * than the minimum granularity. */
+ if ((c2 - a1) < MTRR_MIN_ALIGN) {
+ calc_var_mtrr_range(var_state, a1, c2 - a1, mtrr_type);
+ return;
+ }
- b1 = a2 = round_up(a1, MTRR_MIN_ALIGN);
- b2 = c1 = round_down(c2, MTRR_MIN_ALIGN);
+ b1 = a2 = round_up(a1, MTRR_MIN_ALIGN);
+ b2 = c1 = round_down(c2, MTRR_MIN_ALIGN);
- calc_var_mtrr_range(var_state, a1, a2 - a1, mtrr_type);
- calc_var_mtrr_range(var_state, b1, b2 - b1, mtrr_type);
- calc_var_mtrr_range(var_state, c1, c2 - c1, mtrr_type);
- }
+ calc_var_mtrr_range(var_state, a1, a2 - a1, mtrr_type);
+ calc_var_mtrr_range(var_state, b1, b2 - b1, mtrr_type);
+ calc_var_mtrr_range(var_state, c1, c2 - c1, mtrr_type);
}
static int calc_var_mtrrs(struct memranges *addr_space,
@@ -560,6 +636,7 @@ static int calc_var_mtrrs(struct memranges *addr_space,
{
int wb_deftype_count;
int uc_deftype_count;
+ struct range_entry *r;
struct var_mtrr_state var_state;
/* The default MTRR cacheability type is determined by calculating
@@ -570,15 +647,64 @@ static int calc_var_mtrrs(struct memranges *addr_space,
var_state.address_bits = address_bits;
var_state.commit_mtrrs = 0;
- var_state.mtrr_index = 0;
- var_state.def_mtrr_type = MTRR_TYPE_WRBACK;
- setup_var_mtrrs_by_state(&var_state);
- wb_deftype_count = var_state.mtrr_index;
+ wb_deftype_count = 0;
+ uc_deftype_count = 0;
- var_state.mtrr_index = 0;
- var_state.def_mtrr_type = MTRR_TYPE_UNCACHEABLE;
- setup_var_mtrrs_by_state(&var_state);
- uc_deftype_count = var_state.mtrr_index;
+ /*
+ * For each range do 3 calculations:
+ * 1. UC as default type with no holes at top of range.
+ * 2. UC as default using holes at top of range.
+ * 3. WB as default.
+ * The lowest count is then used as default after totalling all
+ * MTRRs. Note that the optimal algoirthm for UC default is marked in
+ * the tag of each range regardless of final decision. UC takes
+ * precedence in the MTRR archiecture. Therefore, only holes can be
+ * used when the type of the region is MTRR_TYPE_WRBACK with
+ * MTRR_TYPE_UNCACHEABLE as the default type.
+ */
+ memranges_each_entry(r, var_state.addr_space) {
+ int mtrr_type;
+
+ mtrr_type = range_entry_mtrr_type(r);
+
+ if (mtrr_type != MTRR_TYPE_UNCACHEABLE) {
+ int uc_hole_count;
+ int uc_no_hole_count;
+
+ var_state.def_mtrr_type = MTRR_TYPE_UNCACHEABLE;
+ var_state.mtrr_index = 0;
+
+ /* No hole calculation. */
+ calc_var_mtrrs_without_hole(&var_state, r);
+ uc_no_hole_count = var_state.mtrr_index;
+
+ /* Hole calculation only if type is WB. */
+ uc_hole_count = INT_MAX;
+ if (mtrr_type == MTRR_TYPE_WRBACK) {
+ var_state.mtrr_index = 0;
+ calc_var_mtrrs_with_hole(&var_state, r);
+ uc_hole_count = var_state.mtrr_index;
+ }
+
+ /* Mark the entry with the optimal algorithm. */
+ if (uc_no_hole_count < uc_hole_count) {
+ uc_deftype_count += uc_no_hole_count;
+ } else {
+ unsigned long new_tag;
+
+ new_tag = mtrr_type | MTRR_RANGE_UC_USE_HOLE;
+ range_entry_update_tag(r, new_tag);
+ uc_deftype_count += uc_hole_count;
+ }
+ }
+
+ if (mtrr_type != MTRR_TYPE_WRBACK) {
+ var_state.mtrr_index = 0;
+ var_state.def_mtrr_type = MTRR_TYPE_WRBACK;
+ calc_var_mtrrs_without_hole(&var_state, r);
+ wb_deftype_count += var_state.mtrr_index;
+ }
+ }
printk(BIOS_DEBUG, "MTRR: default type WB/UC MTRR counts: %d/%d.\n",
wb_deftype_count, uc_deftype_count);
@@ -594,6 +720,7 @@ static int calc_var_mtrrs(struct memranges *addr_space,
static void commit_var_mtrrs(struct memranges *addr_space, int def_type,
int above4gb, int address_bits)
{
+ struct range_entry *r;
struct var_mtrr_state var_state;
int i;
@@ -604,7 +731,17 @@ static void commit_var_mtrrs(struct memranges *addr_space, int def_type,
var_state.commit_mtrrs = 1;
var_state.mtrr_index = 0;
var_state.def_mtrr_type = def_type;
- setup_var_mtrrs_by_state(&var_state);
+
+ memranges_each_entry(r, var_state.addr_space) {
+ if (range_entry_mtrr_type(r) == def_type)
+ continue;
+
+ if (def_type == MTRR_TYPE_UNCACHEABLE &&
+ (range_entry_tag(r) & MTRR_RANGE_UC_USE_HOLE))
+ calc_var_mtrrs_with_hole(&var_state, r);
+ else
+ calc_var_mtrrs_without_hole(&var_state, r);
+ }
/* Clear all remaining variable MTTRs. */
for (i = var_state.mtrr_index; i < total_mtrrs; i++)
Aaron Durbin (adurbin(a)google.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/2925
-gerrit
commit 4f6e81bf66f59073f3aedd1e7c05430a370068e7
Author: Aaron Durbin <adurbin(a)chromium.org>
Date: Tue Mar 26 21:27:04 2013 -0500
x86: mtrr: add hole punching support
Some ranges would use less variable MTRRs if an UC area
can be carved off the top of larger WB range. Implement this
approach by doing 3 passes over each region in the addres space:
1. UC default type. Cover non-UC and non-WB regions with respectie type.
Punch UC hole at upper end of larger WB regions with WB type.
2. UC default type. Cover non-UC regions with respective type.
3. WB default type. Cover non-WB regions with respective type.
The hole at upper end of a region uses the same min alignment of 64MiB.
Below are results using a combination of options. The board this was
tested on has 10 variable MTRRs at its disposal. It has 4GiB of RAM.
IO hole config #1: hole starts at 0xad800000
No CACHE_ROM or WRCOMB resources (take 9 MTRRs):
MTRR: Physical address space:
0x0000000000000000 - 0x00000000000a0000 size 0x000a0000 type 6
0x00000000000a0000 - 0x00000000000c0000 size 0x00020000 type 0
0x00000000000c0000 - 0x00000000ad800000 size 0xad740000 type 6
0x00000000ad800000 - 0x0000000100000000 size 0x52800000 type 0
0x0000000100000000 - 0x000000014f600000 size 0x4f600000 type 6
MTRR: default type WB/UC MTRR counts: 17/9.
MTRR: UC selected as default type.
MTRR: 0 base 0x0000000000000000 mask 0x0000007f80000000 type 6
MTRR: 1 base 0x0000000080000000 mask 0x0000007fe0000000 type 6
MTRR: 2 base 0x00000000a0000000 mask 0x0000007ff0000000 type 6
MTRR: 3 base 0x00000000ad800000 mask 0x0000007fff800000 type 0
MTRR: 4 base 0x00000000ae000000 mask 0x0000007ffe000000 type 0
MTRR: 5 base 0x0000000100000000 mask 0x0000007fc0000000 type 6
MTRR: 6 base 0x0000000140000000 mask 0x0000007ff0000000 type 6
MTRR: 7 base 0x000000014f600000 mask 0x0000007fffe00000 type 0
Taking a reserved OS MTRR.
MTRR: 8 base 0x000000014f800000 mask 0x0000007fff800000 type 0
No CACHE_ROM. 1 WRCOMB resource (takes 10 MTRRs):
MTRR: Physical address space:
0x0000000000000000 - 0x00000000000a0000 size 0x000a0000 type 6
0x00000000000a0000 - 0x00000000000c0000 size 0x00020000 type 0
0x00000000000c0000 - 0x00000000ad800000 size 0xad740000 type 6
0x00000000ad800000 - 0x00000000d0000000 size 0x22800000 type 0
0x00000000d0000000 - 0x00000000e0000000 size 0x10000000 type 1
0x00000000e0000000 - 0x0000000100000000 size 0x20000000 type 0
0x0000000100000000 - 0x000000014f600000 size 0x4f600000 type 6
MTRR: default type WB/UC MTRR counts: 19/10.
MTRR: UC selected as default type.
MTRR: 0 base 0x0000000000000000 mask 0x0000007f80000000 type 6
MTRR: 1 base 0x0000000080000000 mask 0x0000007fe0000000 type 6
MTRR: 2 base 0x00000000a0000000 mask 0x0000007ff0000000 type 6
MTRR: 3 base 0x00000000ad800000 mask 0x0000007fff800000 type 0
MTRR: 4 base 0x00000000ae000000 mask 0x0000007ffe000000 type 0
MTRR: 5 base 0x00000000d0000000 mask 0x0000007ff0000000 type 1
MTRR: 6 base 0x0000000100000000 mask 0x0000007fc0000000 type 6
MTRR: 7 base 0x0000000140000000 mask 0x0000007ff0000000 type 6
Taking a reserved OS MTRR.
MTRR: 8 base 0x000000014f600000 mask 0x0000007fffe00000 type 0
Taking a reserved OS MTRR.
MTRR: 9 base 0x000000014f800000 mask 0x0000007fff800000 type 0
CACHE_ROM and no WRCOMB resources (taks 10 MTRRs):
MTRR: Physical address space:
0x0000000000000000 - 0x00000000000a0000 size 0x000a0000 type 6
0x00000000000a0000 - 0x00000000000c0000 size 0x00020000 type 0
0x00000000000c0000 - 0x00000000ad800000 size 0xad740000 type 6
0x00000000ad800000 - 0x00000000ff800000 size 0x52000000 type 0
0x00000000ff800000 - 0x0000000100000000 size 0x00800000 type 5
0x0000000100000000 - 0x000000014f600000 size 0x4f600000 type 6
MTRR: default type WB/UC MTRR counts: 24/10.
MTRR: UC selected as default type.
MTRR: 0 base 0x0000000000000000 mask 0x0000007f80000000 type 6
MTRR: 1 base 0x0000000080000000 mask 0x0000007fe0000000 type 6
MTRR: 2 base 0x00000000a0000000 mask 0x0000007ff0000000 type 6
MTRR: 3 base 0x00000000ad800000 mask 0x0000007fff800000 type 0
MTRR: 4 base 0x00000000ae000000 mask 0x0000007ffe000000 type 0
MTRR: 5 base 0x00000000ff800000 mask 0x0000007fff800000 type 0
MTRR: 6 base 0x0000000100000000 mask 0x0000007fc0000000 type 6
MTRR: 7 base 0x0000000140000000 mask 0x0000007ff0000000 type 6
Taking a reserved OS MTRR.
MTRR: 8 base 0x000000014f600000 mask 0x0000007fffe00000 type 0
Taking a reserved OS MTRR.
MTRR: 9 base 0x000000014f800000 mask 0x0000007fff800000 type 0
A combination of CACHE_ROM and WRCOMB just won't work.
IO hole config #2: hole starts at 0x80000000:
No CACHE_ROM or WRCOMB resources (takes 5 MTRRs):
MTRR: Physical address space:
0x0000000000000000 - 0x00000000000a0000 size 0x000a0000 type 6
0x00000000000a0000 - 0x00000000000c0000 size 0x00020000 type 0
0x00000000000c0000 - 0x0000000080000000 size 0x7ff40000 type 6
0x0000000080000000 - 0x0000000100000000 size 0x80000000 type 0
0x0000000100000000 - 0x000000017ce00000 size 0x7ce00000 type 6
MTRR: default type WB/UC MTRR counts: 10/5.
MTRR: UC selected as default type.
MTRR: 0 base 0x0000000000000000 mask 0x0000007f80000000 type 6
MTRR: 1 base 0x0000000100000000 mask 0x0000007f80000000 type 6
MTRR: 2 base 0x000000017ce00000 mask 0x0000007fffe00000 type 0
MTRR: 3 base 0x000000017d000000 mask 0x0000007fff000000 type 0
MTRR: 4 base 0x000000017e000000 mask 0x0000007ffe000000 type 0
No CACHE_ROM. 1 WRCOMB resource (takes 6 MTRRs):
MTRR: Physical address space:
0x0000000000000000 - 0x00000000000a0000 size 0x000a0000 type 6
0x00000000000a0000 - 0x00000000000c0000 size 0x00020000 type 0
0x00000000000c0000 - 0x0000000080000000 size 0x7ff40000 type 6
0x0000000080000000 - 0x00000000d0000000 size 0x50000000 type 0
0x00000000d0000000 - 0x00000000e0000000 size 0x10000000 type 1
0x00000000e0000000 - 0x0000000100000000 size 0x20000000 type 0
0x0000000100000000 - 0x000000017ce00000 size 0x7ce00000 type 6
MTRR: default type WB/UC MTRR counts: 13/6.
MTRR: UC selected as default type.
MTRR: 0 base 0x0000000000000000 mask 0x0000007f80000000 type 6
MTRR: 1 base 0x00000000d0000000 mask 0x0000007ff0000000 type 1
MTRR: 2 base 0x0000000100000000 mask 0x0000007f80000000 type 6
MTRR: 3 base 0x000000017ce00000 mask 0x0000007fffe00000 type 0
MTRR: 4 base 0x000000017d000000 mask 0x0000007fff000000 type 0
MTRR: 5 base 0x000000017e000000 mask 0x0000007ffe000000 type 0
CACHE_ROM and no WRCOMB resources (takes 6 MTRRs):
MTRR: Physical address space:
0x0000000000000000 - 0x00000000000a0000 size 0x000a0000 type 6
0x00000000000a0000 - 0x00000000000c0000 size 0x00020000 type 0
0x00000000000c0000 - 0x0000000080000000 size 0x7ff40000 type 6
0x0000000080000000 - 0x00000000ff800000 size 0x7f800000 type 0
0x00000000ff800000 - 0x0000000100000000 size 0x00800000 type 5
0x0000000100000000 - 0x000000017ce00000 size 0x7ce00000 type 6
MTRR: default type WB/UC MTRR counts: 18/6.
MTRR: UC selected as default type.
MTRR: 0 base 0x0000000000000000 mask 0x0000007f80000000 type 6
MTRR: 1 base 0x00000000ff800000 mask 0x0000007fff800000 type 0
MTRR: 2 base 0x0000000100000000 mask 0x0000007f80000000 type 6
MTRR: 3 base 0x000000017ce00000 mask 0x0000007fffe00000 type 0
MTRR: 4 base 0x000000017d000000 mask 0x0000007fff000000 type 0
MTRR: 5 base 0x000000017e000000 mask 0x0000007ffe000000 type 0
CACHE_ROM and 1 WRCOMB resource (takes 7 MTRRs):
MTRR: Physical address space:
0x0000000000000000 - 0x00000000000a0000 size 0x000a0000 type 6
0x00000000000a0000 - 0x00000000000c0000 size 0x00020000 type 0
0x00000000000c0000 - 0x0000000080000000 size 0x7ff40000 type 6
0x0000000080000000 - 0x00000000d0000000 size 0x50000000 type 0
0x00000000d0000000 - 0x00000000e0000000 size 0x10000000 type 1
0x00000000e0000000 - 0x00000000ff800000 size 0x1f800000 type 0
0x00000000ff800000 - 0x0000000100000000 size 0x00800000 type 5
0x0000000100000000 - 0x000000017ce00000 size 0x7ce00000 type 6
MTRR: default type WB/UC MTRR counts: 19/7.
MTRR: UC selected as default type.
MTRR: 0 base 0x0000000000000000 mask 0x0000007f80000000 type 6
MTRR: 1 base 0x00000000d0000000 mask 0x0000007ff0000000 type 1
MTRR: 2 base 0x00000000ff800000 mask 0x0000007fff800000 type 0
MTRR: 3 base 0x0000000100000000 mask 0x0000007f80000000 type 6
MTRR: 4 base 0x000000017ce00000 mask 0x0000007fffe00000 type 0
MTRR: 5 base 0x000000017d000000 mask 0x0000007fff000000 type 0
MTRR: 6 base 0x000000017e000000 mask 0x0000007ffe000000 type 0
Change-Id: Iceb9b64991accf558caae2e7b0205951e9bcde44
Signed-off-by: Aaron Durbin <adurbin(a)chromium.org>
---
src/cpu/x86/mtrr/mtrr.c | 231 ++++++++++++++++++++++++++++++++++++++----------
1 file changed, 183 insertions(+), 48 deletions(-)
diff --git a/src/cpu/x86/mtrr/mtrr.c b/src/cpu/x86/mtrr/mtrr.c
index d8c5da1..c253c5d 100644
--- a/src/cpu/x86/mtrr/mtrr.c
+++ b/src/cpu/x86/mtrr/mtrr.c
@@ -122,6 +122,21 @@ static inline unsigned int fls(unsigned int x)
#define RANGE_1MB PHYS_TO_RANGE_ADDR(1 << 20)
#define RANGE_4GB (1 << (ADDR_SHIFT_TO_RANGE_SHIFT(32)))
+/*
+ * The default MTRR type selection uses 3 approaches for selecting the
+ * optimal number of variable MTRRs. For each range do 3 calculations:
+ * 1. UC as default type with no holes at top of range.
+ * 2. UC as default using holes at top of range.
+ * 3. WB as default.
+ * If using holes is optimal for a range when UC is the default type the
+ * tag is updated to direct the commit routine to use a hole at the top
+ * of a range.
+ */
+#define MTRR_ALGO_SHIFT (8)
+#define MTRR_TAG_MASK ((1 << MTRR_ALGO_SHIFT) - 1)
+/* If the default type is UC use the hole carving algorithm for a range. */
+#define MTRR_RANGE_UC_USE_HOLE (1 << MTRR_ALGO_SHIFT)
+
static inline uint32_t range_entry_base_mtrr_addr(struct range_entry *r)
{
return PHYS_TO_RANGE_ADDR(range_entry_base(r));
@@ -132,6 +147,11 @@ static inline uint32_t range_entry_end_mtrr_addr(struct range_entry *r)
return PHYS_TO_RANGE_ADDR(range_entry_end(r));
}
+static inline int range_entry_mtrr_type(struct range_entry *r)
+{
+ return range_entry_tag(r) & MTRR_TAG_MASK;
+}
+
static struct memranges *get_physical_address_space(void)
{
static struct memranges *addr_space;
@@ -491,9 +511,72 @@ static void calc_var_mtrr_range(struct var_mtrr_state *var_state,
}
}
-static void setup_var_mtrrs_by_state(struct var_mtrr_state *var_state)
+static void calc_var_mtrrs_with_hole(struct var_mtrr_state *var_state,
+ struct range_entry *r)
{
- struct range_entry *r;
+ uint32_t a1, a2, b1, b2;
+ int mtrr_type;
+ struct range_entry *next;
+
+ /*
+ * Determine MTRRs based on the following algoirthm for the given entry:
+ * +------------------+ b2 = round_up(end)
+ * | 0 or more bytes | <-- hole is carved out between b1 and b2
+ * +------------------+ a2 = b1 = end
+ * | |
+ * +------------------+ a1 = begin
+ *
+ * Thus, there are 3 sub-ranges to configure variable MTRRs for.
+ */
+ mtrr_type = range_entry_mtrr_type(r);
+
+ a1 = range_entry_base_mtrr_addr(r);
+ a2 = range_entry_end_mtrr_addr(r);
+
+ /* The end address is under 1MiB. The fixed MTRRs take
+ * precedence over the variable ones. Therefore this range
+ * can be ignored. */
+ if (a2 < RANGE_1MB)
+ return;
+
+ /* Again, the fixed MTRRs take precedence so the beginning
+ * of the range can be set to 0 if it starts below 1MiB. */
+ if (a1 < RANGE_1MB)
+ a1 = 0;
+
+ /* If the range starts above 4GiB the processing is done. */
+ if (!var_state->above4gb && a1 >= RANGE_4GB)
+ return;
+
+ /* Clip the upper address to 4GiB if addresses above 4GiB
+ * are not being processed. */
+ if (!var_state->above4gb && a2 > RANGE_4GB)
+ a2 = RANGE_4GB;
+
+ b1 = a2;
+ b2 = round_up(a2, MTRR_MIN_ALIGN);
+
+ /* Check against the next range. If the current range_entry is the
+ * last entry then carving a hole is no problem. If the current entry
+ * isn't the last entry then check that the last entry covers the
+ * entire hole range with the default mtrr type. */
+ next = memranges_next_entry(var_state->addr_space, r);
+ if (next != NULL &&
+ (range_entry_mtrr_type(next) != var_state->def_mtrr_type ||
+ range_entry_end_mtrr_addr(next) < b2)) {
+ calc_var_mtrr_range(var_state, a1, a2 - a1, mtrr_type);
+ return;
+ }
+
+ calc_var_mtrr_range(var_state, a1, b2 - a1, mtrr_type);
+ calc_var_mtrr_range(var_state, b1, b2 - b1, var_state->def_mtrr_type);
+}
+
+static void calc_var_mtrrs_without_hole(struct var_mtrr_state *var_state,
+ struct range_entry *r)
+{
+ uint32_t a1, a2, b1, b2, c1, c2;
+ int mtrr_type;
/*
* For each range that meets the non-default type process it in the
@@ -508,51 +591,44 @@ static void setup_var_mtrrs_by_state(struct var_mtrr_state *var_state)
*
* Thus, there are 3 sub-ranges to configure variable MTRRs for.
*/
- memranges_each_entry(r, var_state->addr_space) {
- uint32_t a1, a2, b1, b2, c1, c2;
- int mtrr_type = range_entry_tag(r);
+ mtrr_type = range_entry_mtrr_type(r);
- /* Skip default type. */
- if (var_state->def_mtrr_type == mtrr_type)
- continue;
-
- a1 = range_entry_base_mtrr_addr(r);
- c2 = range_entry_end_mtrr_addr(r);
+ a1 = range_entry_base_mtrr_addr(r);
+ c2 = range_entry_end_mtrr_addr(r);
- /* The end address is under 1MiB. The fixed MTRRs take
- * precedence over the variable ones. Therefore this range
- * can be ignored. */
- if (c2 < RANGE_1MB)
- continue;
+ /* The end address is under 1MiB. The fixed MTRRs take
+ * precedence over the variable ones. Therefore this range
+ * can be ignored. */
+ if (c2 < RANGE_1MB)
+ return;
- /* Again, the fixed MTRRs take precedence so the beginning
- * of the range can be set to 0 if it starts below 1MiB. */
- if (a1 < RANGE_1MB)
- a1 = 0;
+ /* Again, the fixed MTRRs take precedence so the beginning
+ * of the range can be set to 0 if it starts below 1MiB. */
+ if (a1 < RANGE_1MB)
+ a1 = 0;
- /* If the range starts above 4GiB the processing is done. */
- if (!var_state->above4gb && a1 >= RANGE_4GB)
- break;
+ /* If the range starts above 4GiB the processing is done. */
+ if (!var_state->above4gb && a1 >= RANGE_4GB)
+ return;
- /* Clip the upper address to 4GiB if addresses above 4GiB
- * are not being processed. */
- if (!var_state->above4gb && c2 > RANGE_4GB)
- c2 = RANGE_4GB;
+ /* Clip the upper address to 4GiB if addresses above 4GiB
+ * are not being processed. */
+ if (!var_state->above4gb && c2 > RANGE_4GB)
+ c2 = RANGE_4GB;
- /* Don't align up or down on the range if it is smaller
- * than the minimum granularity. */
- if ((c2 - a1) < MTRR_MIN_ALIGN) {
- calc_var_mtrr_range(var_state, a1, c2 - a1, mtrr_type);
- continue;
- }
+ /* Don't align up or down on the range if it is smaller
+ * than the minimum granularity. */
+ if ((c2 - a1) < MTRR_MIN_ALIGN) {
+ calc_var_mtrr_range(var_state, a1, c2 - a1, mtrr_type);
+ return;
+ }
- b1 = a2 = round_up(a1, MTRR_MIN_ALIGN);
- b2 = c1 = round_down(c2, MTRR_MIN_ALIGN);
+ b1 = a2 = round_up(a1, MTRR_MIN_ALIGN);
+ b2 = c1 = round_down(c2, MTRR_MIN_ALIGN);
- calc_var_mtrr_range(var_state, a1, a2 - a1, mtrr_type);
- calc_var_mtrr_range(var_state, b1, b2 - b1, mtrr_type);
- calc_var_mtrr_range(var_state, c1, c2 - c1, mtrr_type);
- }
+ calc_var_mtrr_range(var_state, a1, a2 - a1, mtrr_type);
+ calc_var_mtrr_range(var_state, b1, b2 - b1, mtrr_type);
+ calc_var_mtrr_range(var_state, c1, c2 - c1, mtrr_type);
}
static int calc_var_mtrrs(struct memranges *addr_space,
@@ -560,6 +636,7 @@ static int calc_var_mtrrs(struct memranges *addr_space,
{
int wb_deftype_count;
int uc_deftype_count;
+ struct range_entry *r;
struct var_mtrr_state var_state;
/* The default MTRR cacheability type is determined by calculating
@@ -570,15 +647,62 @@ static int calc_var_mtrrs(struct memranges *addr_space,
var_state.address_bits = address_bits;
var_state.commit_mtrrs = 0;
- var_state.mtrr_index = 0;
- var_state.def_mtrr_type = MTRR_TYPE_WRBACK;
- setup_var_mtrrs_by_state(&var_state);
- wb_deftype_count = var_state.mtrr_index;
+ wb_deftype_count = 0;
+ uc_deftype_count = 0;
- var_state.mtrr_index = 0;
- var_state.def_mtrr_type = MTRR_TYPE_UNCACHEABLE;
- setup_var_mtrrs_by_state(&var_state);
- uc_deftype_count = var_state.mtrr_index;
+ /*
+ * For each range do 3 calculations:
+ * 1. UC as default type with no holes at top of range.
+ * 2. UC as default using holes at top of range.
+ * 3. WB as default.
+ * The lowest count is then used as default after totalling all
+ * MTRRs. Note that the optimal algoirthm for UC default is marked in
+ * the tag of each range regardless of final decision. UC takes
+ * precedence in the MTRR archiecture. Therefore, only holes can be
+ * used when the type of the region is MTRR_TYPE_WRBACK with
+ * MTRR_TYPE_UNCACHEABLE as the default type.
+ */
+ memranges_each_entry(r, var_state.addr_space) {
+ int mtrr_type;
+
+ mtrr_type = range_entry_mtrr_type(r);
+
+ if (mtrr_type != MTRR_TYPE_UNCACHEABLE) {
+ int uc_hole_count;
+ int uc_no_hole_count;
+
+ var_state.def_mtrr_type = MTRR_TYPE_UNCACHEABLE;
+ var_state.mtrr_index = 0;
+
+ /* No hole calculation. */
+ calc_var_mtrrs_without_hole(&var_state, r);
+ uc_no_hole_count = var_state.mtrr_index;
+
+ /* Hole calculation only if type is WB. */
+ uc_hole_count = INT_MAX;
+ if (mtrr_type == MTRR_TYPE_WRBACK) {
+ var_state.mtrr_index = 0;
+ calc_var_mtrrs_with_hole(&var_state, r);
+ uc_hole_count = var_state.mtrr_index;
+ }
+
+ /* Mark the entry with the optimal algorithm. */
+ if (uc_no_hole_count < uc_hole_count) {
+ uc_deftype_count += uc_no_hole_count;
+ } else {
+ mtrr_type |= MTRR_RANGE_UC_USE_HOLE;
+ range_entry_update_tag(r, mtrr_type);
+ uc_deftype_count += uc_hole_count;
+ }
+ }
+
+ if (mtrr_type != MTRR_TYPE_WRBACK) {
+ var_state.mtrr_index = 0;
+ var_state.def_mtrr_type = MTRR_TYPE_WRBACK;
+ calc_var_mtrrs_without_hole(&var_state, r);
+ wb_deftype_count += var_state.mtrr_index;
+ }
+ }
printk(BIOS_DEBUG, "MTRR: default type WB/UC MTRR counts: %d/%d.\n",
wb_deftype_count, uc_deftype_count);
@@ -594,6 +718,7 @@ static int calc_var_mtrrs(struct memranges *addr_space,
static void commit_var_mtrrs(struct memranges *addr_space, int def_type,
int above4gb, int address_bits)
{
+ struct range_entry *r;
struct var_mtrr_state var_state;
int i;
@@ -604,7 +729,17 @@ static void commit_var_mtrrs(struct memranges *addr_space, int def_type,
var_state.commit_mtrrs = 1;
var_state.mtrr_index = 0;
var_state.def_mtrr_type = def_type;
- setup_var_mtrrs_by_state(&var_state);
+
+ memranges_each_entry(r, var_state.addr_space) {
+ if (range_entry_mtrr_type(r) == def_type)
+ continue;
+
+ if (def_type == MTRR_TYPE_UNCACHEABLE &&
+ (range_entry_tag(r) & MTRR_RANGE_UC_USE_HOLE))
+ calc_var_mtrrs_with_hole(&var_state, r);
+ else
+ calc_var_mtrrs_without_hole(&var_state, r);
+ }
/* Clear all remaining variable MTTRs. */
for (i = var_state.mtrr_index; i < total_mtrrs; i++)