]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
coreboot
authorVladimir Serbinenko <phcoder@gmail.com>
Sat, 20 Feb 2016 15:26:23 +0000 (16:26 +0100)
committerVladimir Serbinenko <phcoder@gmail.com>
Sat, 20 Feb 2016 15:26:23 +0000 (16:26 +0100)
gentpl.py
grub-core/Makefile.core.def
grub-core/kern/arm/coreboot/init.c
grub-core/kern/arm/coreboot/timer.c [new file with mode: 0644]
include/grub/arm/coreboot/kernel.h

index edbb13516d043a6b07421139cb84ecb8f48baff0..ed268178b4dbb46f1076d71ff8e2a610738bc2b9 100644 (file)
--- a/gentpl.py
+++ b/gentpl.py
@@ -76,7 +76,7 @@ GROUPS["terminfomodule"]   = GRUB_PLATFORMS[:];
 for i in GROUPS["terminfoinkernel"]: GROUPS["terminfomodule"].remove(i)
 
 # Flattened Device Trees (FDT)
-GROUPS["fdt"] = [ "arm64_efi", "arm_uboot", "arm_efi", "arm_coreboot" ]
+GROUPS["fdt"] = [ "arm64_efi", "arm_uboot", "arm_efi" ]
 
 # Needs software helpers for division
 # Must match GRUB_DIVISION_IN_SOFTWARE in misc.h
index e379e679f01aec64370cf53ff46202d9ebeb33ba..0e03d93707fa6fcb460e4447682044771c5bd1ee 100644 (file)
@@ -156,7 +156,11 @@ kernel = {
   arm_uboot = kern/arm/uboot/uboot.S;
 
   arm_coreboot = kern/arm/coreboot/init.c;
+  arm_coreboot = kern/arm/coreboot/timer.c;
+  arm_coreboot = kern/arm/coreboot/fdt_guess.c;
   arm_coreboot = kern/arm/coreboot/coreboot.S;
+  arm_coreboot = lib/fdt.c;
+  arm_coreboot = bus/fdt.c;
 
   terminfoinkernel = term/terminfo.c;
   terminfoinkernel = term/tparm.c;
index eb5068c0130c48eba20da8a166283e7cad525920..9796c721f4576d0cdd079c74968b75765922c5db 100644 (file)
@@ -20,6 +20,7 @@
 #include <grub/mm.h>
 #include <grub/memory.h>
 #include <grub/machine/console.h>
+#include <grub/machine/kernel.h>
 #include <grub/offsets.h>
 #include <grub/types.h>
 #include <grub/err.h>
 #include <grub/time.h>
 #include <grub/symbol.h>
 #include <grub/video.h>
+#include <grub/coreboot/lbio.h>
+#include <grub/fdtbus.h>
 
 extern grub_uint8_t _start[];
 extern grub_uint8_t _end[];
 extern grub_uint8_t _edata[];
 
-grub_uint64_t
-grub_armv7_get_timer_value(void);
-
-grub_uint32_t
-grub_armv7_get_timer_frequency(void);
-
-grub_uint32_t
-grub_arm_pfr1(void);
-
 void  __attribute__ ((noreturn))
 grub_exit (void)
 {
@@ -88,26 +82,35 @@ heap_init (grub_uint64_t addr, grub_uint64_t size, grub_memory_type_t type,
   return 0;
 }
 
-static grub_uint32_t timer_frequency_in_khz;
-
-static grub_uint64_t
-get_time_ms (void)
-{
-  return grub_divmod64 (grub_armv7_get_timer_value(), timer_frequency_in_khz, 0);
-}
+static char *mobo_vendor, *mobo_part_number;
+static const void *dtb;
+static grub_size_t dtb_size;
 
 static int
-try_generic_timer (void)
+iterate_linuxbios_table (grub_linuxbios_table_item_t table_item, void *data __attribute__ ((unused)))
 {
-  if (((grub_arm_pfr1 () >> 16) & 0xf) != 1)
-    return 0;
-  timer_frequency_in_khz = grub_armv7_get_timer_frequency() / 1000;
-  if (timer_frequency_in_khz == 0)
-    return 0;
-  grub_install_get_time_ms (get_time_ms);
-  return 1;
+  switch (table_item->tag)
+    {
+    case GRUB_LINUXBIOS_MEMBER_MAINBOARD:
+      {
+       struct grub_linuxbios_mainboard *mb;
+       mb = (struct grub_linuxbios_mainboard *) (table_item + 1);
+       mobo_vendor = mb->strings + mb->vendor;
+       mobo_part_number = mb->strings + mb->part_number;
+       return 0;
+      }
+    case GRUB_LINUXBIOS_MEMBER_DTB:
+      if (grub_fdt_check_header (table_item + 1, table_item->size) >= 0)
+       {
+         dtb = table_item + 1;
+         dtb_size = table_item->size;
+       }
+      return 0;
+    }
+  return 0;
 }
 
+
 void
 grub_machine_init (void)
 {
@@ -124,8 +127,25 @@ grub_machine_init (void)
   grub_font_init ();
   grub_gfxterm_init ();
 
-  if (!try_generic_timer ())
-    grub_fatal ("No timer found");
+  grub_linuxbios_table_iterate (iterate_linuxbios_table, 0);
+
+  if (!dtb)
+    {
+      struct grub_fdt_board *cur;
+      for (cur = grub_fdt_boards; cur->dtb; cur++)
+       if (grub_strcmp (cur->vendor, mobo_vendor) == 0
+           && grub_strcmp (cur->part, mobo_part_number) == 0)
+         {
+           dtb = cur->dtb;
+           dtb_size = cur->dtb_size;
+           break;
+         }
+    }
+  if (!dtb)
+    grub_fatal ("No saved DTB found for <%s> <%s> and none is supplied", mobo_vendor, mobo_part_number);
+  grub_fdtbus_init (dtb, dtb_size);
+
+  grub_machine_timer_init ();
 }
 
 void
diff --git a/grub-core/kern/arm/coreboot/timer.c b/grub-core/kern/arm/coreboot/timer.c
new file mode 100644 (file)
index 0000000..7848e3d
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2016  Free Software Foundation, Inc.
+ *
+ *  GRUB 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, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/mm.h>
+#include <grub/machine/kernel.h>
+#include <grub/types.h>
+#include <grub/err.h>
+#include <grub/time.h>
+#include <grub/fdtbus.h>
+#include <grub/misc.h>
+
+grub_uint64_t
+grub_armv7_get_timer_value(void);
+
+grub_uint32_t
+grub_armv7_get_timer_frequency(void);
+
+grub_uint32_t
+grub_arm_pfr1(void);
+
+static int have_timer = 0;
+static volatile grub_uint32_t *sp804_regs;
+
+static grub_uint64_t
+sp804_get_time_ms (void)
+{
+  static grub_uint32_t high, last_low;
+  grub_uint32_t low = ~sp804_regs[1];
+  if (last_low > low)
+    high++;
+  last_low = low;
+  return grub_divmod64 ((((grub_uint64_t) high) << 32) | low,
+                       1000, 0);
+}
+
+static grub_err_t
+sp804_attach(const void *fdt, unsigned int nodeoffset)
+{
+  if (have_timer)
+    return GRUB_ERR_NONE;
+  const grub_uint32_t *reg = grub_fdt_get_prop (fdt, nodeoffset, "reg", 0);
+  sp804_regs = (void *) grub_be_to_cpu32 (*reg);
+  grub_install_get_time_ms (sp804_get_time_ms);
+  have_timer = 1;
+  return GRUB_ERR_NONE;
+}
+
+struct grub_fdtbus_driver sp804 =
+{
+  .compatible = "arm,sp804",
+  .attach = sp804_attach
+};
+
+static grub_uint32_t timer_frequency_in_khz;
+
+static grub_uint64_t
+generic_get_time_ms (void)
+{
+  return grub_divmod64 (grub_armv7_get_timer_value(), timer_frequency_in_khz, 0);
+}
+
+static int
+try_generic_timer (void)
+{
+  if (((grub_arm_pfr1 () >> 16) & 0xf) != 1)
+    return 0;
+  timer_frequency_in_khz = grub_armv7_get_timer_frequency() / 1000;
+  if (timer_frequency_in_khz == 0)
+    return 0;
+  grub_install_get_time_ms (generic_get_time_ms);
+  have_timer = 1;
+  return 1;
+}
+
+void
+grub_machine_timer_init (void)
+{
+  grub_fdtbus_register (&sp804);
+
+  if (!have_timer)
+    try_generic_timer ();
+  if (!have_timer)
+    grub_fatal ("No timer found");
+}
index e8fcc9454c09bc6df071dffad3e90afe228ecd2b..46f0b4888382a275db4298dc73c5f0409a4c6e28 100644 (file)
@@ -32,7 +32,7 @@ struct grub_fdt_board
 };
 
 extern struct grub_fdt_board grub_fdt_boards[];
-
+void grub_machine_timer_init (void);
 #endif /* ! ASM_FILE */
 
 #define GRUB_KERNEL_MACHINE_STACK_SIZE 0x40000