From: Vladimir Serbinenko Date: Sat, 20 Feb 2016 15:26:23 +0000 (+0100) Subject: coreboot X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=a29fb4722c3698cd3ce51415b28222340b2aa298;p=thirdparty%2Fgrub.git coreboot --- diff --git a/gentpl.py b/gentpl.py index edbb13516..ed268178b 100644 --- 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 diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index e379e679f..0e03d9370 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -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; diff --git a/grub-core/kern/arm/coreboot/init.c b/grub-core/kern/arm/coreboot/init.c index eb5068c01..9796c721f 100644 --- a/grub-core/kern/arm/coreboot/init.c +++ b/grub-core/kern/arm/coreboot/init.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -31,20 +32,13 @@ #include #include #include +#include +#include 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 index 000000000..7848e3d00 --- /dev/null +++ b/grub-core/kern/arm/coreboot/timer.c @@ -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 . + */ + +#include +#include +#include +#include +#include +#include +#include + +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"); +} diff --git a/include/grub/arm/coreboot/kernel.h b/include/grub/arm/coreboot/kernel.h index e8fcc9454..46f0b4888 100644 --- a/include/grub/arm/coreboot/kernel.h +++ b/include/grub/arm/coreboot/kernel.h @@ -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