2018-07-12 14:56:34 +00:00
|
|
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
2017-06-16 19:31:32 +00:00
|
|
|
From: Vladimir Serbinenko <phcoder@gmail.com>
|
|
|
|
Date: Mon, 8 May 2017 22:10:26 +0200
|
2018-07-10 18:39:10 +00:00
|
|
|
Subject: [PATCH] ehci: Split core code from PCI part.
|
2017-06-16 19:31:32 +00:00
|
|
|
|
|
|
|
On ARM often EHCI is present without PCI and just declared in device
|
|
|
|
tree. So splitcore from PCI part.
|
|
|
|
---
|
|
|
|
grub-core/Makefile.core.def | 1 +
|
|
|
|
grub-core/bus/usb/ehci-pci.c | 208 +++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
grub-core/bus/usb/ehci.c | 201 +++--------------------------------------
|
|
|
|
3 files changed, 223 insertions(+), 187 deletions(-)
|
|
|
|
create mode 100644 grub-core/bus/usb/ehci-pci.c
|
|
|
|
|
|
|
|
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
|
2018-02-27 18:56:41 +00:00
|
|
|
index e4f253a205e..4745eb4d93e 100644
|
2017-06-16 19:31:32 +00:00
|
|
|
--- a/grub-core/Makefile.core.def
|
|
|
|
+++ b/grub-core/Makefile.core.def
|
|
|
|
@@ -593,6 +593,7 @@ module = {
|
|
|
|
module = {
|
|
|
|
name = ehci;
|
|
|
|
common = bus/usb/ehci.c;
|
|
|
|
+ pci = bus/usb/ehci-pci.c;
|
|
|
|
enable = pci;
|
|
|
|
};
|
|
|
|
|
|
|
|
diff --git a/grub-core/bus/usb/ehci-pci.c b/grub-core/bus/usb/ehci-pci.c
|
|
|
|
new file mode 100644
|
2018-02-27 18:56:41 +00:00
|
|
|
index 00000000000..65e6cb57438
|
2017-06-16 19:31:32 +00:00
|
|
|
--- /dev/null
|
|
|
|
+++ b/grub-core/bus/usb/ehci-pci.c
|
|
|
|
@@ -0,0 +1,208 @@
|
|
|
|
+/* ehci.c - EHCI Support. */
|
|
|
|
+/*
|
|
|
|
+ * GRUB -- GRand Unified Bootloader
|
|
|
|
+ * Copyright (C) 2011 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/pci.h>
|
|
|
|
+#include <grub/cpu/pci.h>
|
|
|
|
+#include <grub/cs5536.h>
|
|
|
|
+#include <grub/misc.h>
|
|
|
|
+#include <grub/mm.h>
|
|
|
|
+#include <grub/time.h>
|
|
|
|
+#include <grub/usb.h>
|
|
|
|
+
|
|
|
|
+#define GRUB_EHCI_PCI_SBRN_REG 0x60
|
|
|
|
+#define GRUB_EHCI_ADDR_MEM_MASK (~0xff)
|
|
|
|
+
|
|
|
|
+/* USBLEGSUP bits and related OS OWNED byte offset */
|
|
|
|
+enum
|
|
|
|
+{
|
|
|
|
+ GRUB_EHCI_BIOS_OWNED = (1 << 16),
|
|
|
|
+ GRUB_EHCI_OS_OWNED = (1 << 24)
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+/* PCI iteration function... */
|
|
|
|
+static int
|
|
|
|
+grub_ehci_pci_iter (grub_pci_device_t dev, grub_pci_id_t pciid,
|
|
|
|
+ void *data __attribute__ ((unused)))
|
|
|
|
+{
|
|
|
|
+ volatile grub_uint32_t *regs;
|
|
|
|
+ grub_uint32_t base, base_h;
|
|
|
|
+ grub_uint32_t eecp_offset;
|
|
|
|
+ grub_uint32_t usblegsup = 0;
|
|
|
|
+ grub_uint64_t maxtime;
|
|
|
|
+ grub_uint32_t interf;
|
|
|
|
+ grub_uint32_t subclass;
|
|
|
|
+ grub_uint32_t class;
|
|
|
|
+ grub_uint8_t release;
|
|
|
|
+ grub_uint32_t class_code;
|
|
|
|
+
|
|
|
|
+ grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: begin\n");
|
|
|
|
+
|
|
|
|
+ if (pciid == GRUB_CS5536_PCIID)
|
|
|
|
+ {
|
|
|
|
+ grub_uint64_t basereg;
|
|
|
|
+
|
|
|
|
+ basereg = grub_cs5536_read_msr (dev, GRUB_CS5536_MSR_USB_EHCI_BASE);
|
|
|
|
+ if (!(basereg & GRUB_CS5536_MSR_USB_BASE_MEMORY_ENABLE))
|
|
|
|
+ {
|
|
|
|
+ /* Shouldn't happen. */
|
|
|
|
+ grub_dprintf ("ehci", "No EHCI address is assigned\n");
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+ base = (basereg & GRUB_CS5536_MSR_USB_BASE_ADDR_MASK);
|
|
|
|
+ basereg |= GRUB_CS5536_MSR_USB_BASE_BUS_MASTER;
|
|
|
|
+ basereg &= ~GRUB_CS5536_MSR_USB_BASE_PME_ENABLED;
|
|
|
|
+ basereg &= ~GRUB_CS5536_MSR_USB_BASE_PME_STATUS;
|
|
|
|
+ basereg &= ~GRUB_CS5536_MSR_USB_BASE_SMI_ENABLE;
|
|
|
|
+ grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_USB_EHCI_BASE, basereg);
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ grub_pci_address_t addr;
|
|
|
|
+ addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS);
|
|
|
|
+ class_code = grub_pci_read (addr) >> 8;
|
|
|
|
+ interf = class_code & 0xFF;
|
|
|
|
+ subclass = (class_code >> 8) & 0xFF;
|
|
|
|
+ class = class_code >> 16;
|
|
|
|
+
|
|
|
|
+ /* If this is not an EHCI controller, just return. */
|
|
|
|
+ if (class != 0x0c || subclass != 0x03 || interf != 0x20)
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+ grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: class OK\n");
|
|
|
|
+
|
|
|
|
+ /* Check Serial Bus Release Number */
|
|
|
|
+ addr = grub_pci_make_address (dev, GRUB_EHCI_PCI_SBRN_REG);
|
|
|
|
+ release = grub_pci_read_byte (addr);
|
|
|
|
+ if (release != 0x20)
|
|
|
|
+ {
|
|
|
|
+ grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: Wrong SBRN: %0x\n",
|
|
|
|
+ release);
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+ grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: bus rev. num. OK\n");
|
|
|
|
+
|
|
|
|
+ /* Determine EHCI EHCC registers base address. */
|
|
|
|
+ addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG0);
|
|
|
|
+ base = grub_pci_read (addr);
|
|
|
|
+ addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG1);
|
|
|
|
+ base_h = grub_pci_read (addr);
|
|
|
|
+ /* Stop if registers are mapped above 4G - GRUB does not currently
|
|
|
|
+ * work with registers mapped above 4G */
|
|
|
|
+ if (((base & GRUB_PCI_ADDR_MEM_TYPE_MASK) != GRUB_PCI_ADDR_MEM_TYPE_32)
|
|
|
|
+ && (base_h != 0))
|
|
|
|
+ {
|
|
|
|
+ grub_dprintf ("ehci",
|
|
|
|
+ "EHCI grub_ehci_pci_iter: registers above 4G are not supported\n");
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+ base &= GRUB_PCI_ADDR_MEM_MASK;
|
|
|
|
+ if (!base)
|
|
|
|
+ {
|
|
|
|
+ grub_dprintf ("ehci",
|
|
|
|
+ "EHCI: EHCI is not mapped\n");
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Set bus master - needed for coreboot, VMware, broken BIOSes etc. */
|
|
|
|
+ addr = grub_pci_make_address (dev, GRUB_PCI_REG_COMMAND);
|
|
|
|
+ grub_pci_write_word(addr,
|
|
|
|
+ GRUB_PCI_COMMAND_MEM_ENABLED
|
|
|
|
+ | GRUB_PCI_COMMAND_BUS_MASTER
|
|
|
|
+ | grub_pci_read_word(addr));
|
|
|
|
+
|
|
|
|
+ grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: 32-bit EHCI OK\n");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: iobase of EHCC: %08x\n",
|
|
|
|
+ (base & GRUB_EHCI_ADDR_MEM_MASK));
|
|
|
|
+
|
|
|
|
+ regs = grub_pci_device_map_range (dev,
|
|
|
|
+ (base & GRUB_EHCI_ADDR_MEM_MASK),
|
|
|
|
+ 0x100);
|
|
|
|
+
|
|
|
|
+ /* Is there EECP ? */
|
|
|
|
+ eecp_offset = (grub_le_to_cpu32 (regs[2]) >> 8) & 0xff;
|
|
|
|
+
|
|
|
|
+ /* Determine and change ownership. */
|
|
|
|
+ /* EECP offset valid in HCCPARAMS */
|
|
|
|
+ /* Ownership can be changed via EECP only */
|
|
|
|
+ if (pciid != GRUB_CS5536_PCIID && eecp_offset >= 0x40)
|
|
|
|
+ {
|
|
|
|
+ grub_pci_address_t pciaddr_eecp;
|
|
|
|
+ pciaddr_eecp = grub_pci_make_address (dev, eecp_offset);
|
|
|
|
+
|
|
|
|
+ usblegsup = grub_pci_read (pciaddr_eecp);
|
|
|
|
+ if (usblegsup & GRUB_EHCI_BIOS_OWNED)
|
|
|
|
+ {
|
|
|
|
+ grub_boot_time ("Taking ownership of EHCI controller");
|
|
|
|
+ grub_dprintf ("ehci",
|
|
|
|
+ "EHCI grub_ehci_pci_iter: EHCI owned by: BIOS\n");
|
|
|
|
+ /* Ownership change - set OS_OWNED bit */
|
|
|
|
+ grub_pci_write (pciaddr_eecp, usblegsup | GRUB_EHCI_OS_OWNED);
|
|
|
|
+ /* Ensure PCI register is written */
|
|
|
|
+ grub_pci_read (pciaddr_eecp);
|
|
|
|
+
|
|
|
|
+ /* Wait for finish of ownership change, EHCI specification
|
|
|
|
+ * doesn't say how long it can take... */
|
|
|
|
+ maxtime = grub_get_time_ms () + 1000;
|
|
|
|
+ while ((grub_pci_read (pciaddr_eecp) & GRUB_EHCI_BIOS_OWNED)
|
|
|
|
+ && (grub_get_time_ms () < maxtime));
|
|
|
|
+ if (grub_pci_read (pciaddr_eecp) & GRUB_EHCI_BIOS_OWNED)
|
|
|
|
+ {
|
|
|
|
+ grub_dprintf ("ehci",
|
|
|
|
+ "EHCI grub_ehci_pci_iter: EHCI change ownership timeout");
|
|
|
|
+ /* Change ownership in "hard way" - reset BIOS ownership */
|
|
|
|
+ grub_pci_write (pciaddr_eecp, GRUB_EHCI_OS_OWNED);
|
|
|
|
+ /* Ensure PCI register is written */
|
|
|
|
+ grub_pci_read (pciaddr_eecp);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ else if (usblegsup & GRUB_EHCI_OS_OWNED)
|
|
|
|
+ /* XXX: What to do in this case - nothing ? Can it happen ? */
|
|
|
|
+ grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: EHCI owned by: OS\n");
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ grub_dprintf ("ehci",
|
|
|
|
+ "EHCI grub_ehci_pci_iter: EHCI owned by: NONE\n");
|
|
|
|
+ /* XXX: What to do in this case ? Can it happen ?
|
|
|
|
+ * Is code below correct ? */
|
|
|
|
+ /* Ownership change - set OS_OWNED bit */
|
|
|
|
+ grub_pci_write (pciaddr_eecp, GRUB_EHCI_OS_OWNED);
|
|
|
|
+ /* Ensure PCI register is written */
|
|
|
|
+ grub_pci_read (pciaddr_eecp);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Disable SMI, just to be sure. */
|
|
|
|
+ pciaddr_eecp = grub_pci_make_address (dev, eecp_offset + 4);
|
|
|
|
+ grub_pci_write (pciaddr_eecp, 0);
|
|
|
|
+ /* Ensure PCI register is written */
|
|
|
|
+ grub_pci_read (pciaddr_eecp);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ grub_dprintf ("ehci", "inithw: EHCI grub_ehci_pci_iter: ownership OK\n");
|
|
|
|
+
|
|
|
|
+ grub_ehci_init_device (regs);
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void
|
|
|
|
+grub_ehci_pci_scan (void)
|
|
|
|
+{
|
|
|
|
+ grub_pci_iterate (grub_ehci_pci_iter, NULL);
|
|
|
|
+}
|
|
|
|
diff --git a/grub-core/bus/usb/ehci.c b/grub-core/bus/usb/ehci.c
|
2018-02-27 18:56:41 +00:00
|
|
|
index 5f4297bb21e..c772e76546e 100644
|
2017-06-16 19:31:32 +00:00
|
|
|
--- a/grub-core/bus/usb/ehci.c
|
|
|
|
+++ b/grub-core/bus/usb/ehci.c
|
|
|
|
@@ -22,13 +22,10 @@
|
|
|
|
#include <grub/usb.h>
|
|
|
|
#include <grub/usbtrans.h>
|
|
|
|
#include <grub/misc.h>
|
|
|
|
-#include <grub/pci.h>
|
|
|
|
-#include <grub/cpu/pci.h>
|
|
|
|
-#include <grub/cpu/io.h>
|
|
|
|
#include <grub/time.h>
|
|
|
|
#include <grub/loader.h>
|
|
|
|
-#include <grub/cs5536.h>
|
|
|
|
#include <grub/disk.h>
|
|
|
|
+#include <grub/dma.h>
|
|
|
|
#include <grub/cache.h>
|
|
|
|
|
|
|
|
GRUB_MOD_LICENSE ("GPLv3+");
|
|
|
|
@@ -39,8 +36,6 @@ GRUB_MOD_LICENSE ("GPLv3+");
|
|
|
|
* - is not supporting interrupt transfers
|
|
|
|
*/
|
|
|
|
|
|
|
|
-#define GRUB_EHCI_PCI_SBRN_REG 0x60
|
|
|
|
-
|
|
|
|
/* Capability registers offsets */
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
@@ -54,7 +49,6 @@ enum
|
|
|
|
#define GRUB_EHCI_EECP_MASK (0xff << 8)
|
|
|
|
#define GRUB_EHCI_EECP_SHIFT 8
|
|
|
|
|
|
|
|
-#define GRUB_EHCI_ADDR_MEM_MASK (~0xff)
|
|
|
|
#define GRUB_EHCI_POINTER_MASK (~0x1f)
|
|
|
|
|
|
|
|
/* Capability register SPARAMS bits */
|
|
|
|
@@ -85,13 +79,6 @@ enum
|
|
|
|
|
|
|
|
#define GRUB_EHCI_QH_EMPTY 1
|
|
|
|
|
|
|
|
-/* USBLEGSUP bits and related OS OWNED byte offset */
|
|
|
|
-enum
|
|
|
|
-{
|
|
|
|
- GRUB_EHCI_BIOS_OWNED = (1 << 16),
|
|
|
|
- GRUB_EHCI_OS_OWNED = (1 << 24)
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
/* Operational registers offsets */
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
@@ -455,9 +442,10 @@ grub_ehci_reset (struct grub_ehci *e)
|
|
|
|
|
|
|
|
sync_all_caches (e);
|
|
|
|
|
|
|
|
+ grub_dprintf ("ehci", "reset\n");
|
|
|
|
+
|
|
|
|
grub_ehci_oper_write32 (e, GRUB_EHCI_COMMAND,
|
|
|
|
- GRUB_EHCI_CMD_HC_RESET
|
|
|
|
- | grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND));
|
|
|
|
+ GRUB_EHCI_CMD_HC_RESET);
|
|
|
|
/* Ensure command is written */
|
|
|
|
grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND);
|
|
|
|
/* XXX: How long time could take reset of HC ? */
|
|
|
|
@@ -473,116 +461,24 @@ grub_ehci_reset (struct grub_ehci *e)
|
|
|
|
}
|
|
|
|
|
|
|
|
/* PCI iteration function... */
|
|
|
|
-static int
|
|
|
|
-grub_ehci_pci_iter (grub_pci_device_t dev, grub_pci_id_t pciid,
|
|
|
|
- void *data __attribute__ ((unused)))
|
|
|
|
+void
|
|
|
|
+grub_ehci_init_device (volatile void *regs)
|
|
|
|
{
|
|
|
|
- grub_uint8_t release;
|
|
|
|
- grub_uint32_t class_code;
|
|
|
|
- grub_uint32_t interf;
|
|
|
|
- grub_uint32_t subclass;
|
|
|
|
- grub_uint32_t class;
|
|
|
|
- grub_uint32_t base, base_h;
|
|
|
|
struct grub_ehci *e;
|
|
|
|
- grub_uint32_t eecp_offset;
|
|
|
|
grub_uint32_t fp;
|
|
|
|
int i;
|
|
|
|
- grub_uint32_t usblegsup = 0;
|
|
|
|
- grub_uint64_t maxtime;
|
|
|
|
grub_uint32_t n_ports;
|
|
|
|
grub_uint8_t caplen;
|
|
|
|
|
|
|
|
- grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: begin\n");
|
|
|
|
-
|
|
|
|
- if (pciid == GRUB_CS5536_PCIID)
|
|
|
|
- {
|
|
|
|
- grub_uint64_t basereg;
|
|
|
|
-
|
|
|
|
- basereg = grub_cs5536_read_msr (dev, GRUB_CS5536_MSR_USB_EHCI_BASE);
|
|
|
|
- if (!(basereg & GRUB_CS5536_MSR_USB_BASE_MEMORY_ENABLE))
|
|
|
|
- {
|
|
|
|
- /* Shouldn't happen. */
|
|
|
|
- grub_dprintf ("ehci", "No EHCI address is assigned\n");
|
|
|
|
- return 0;
|
|
|
|
- }
|
|
|
|
- base = (basereg & GRUB_CS5536_MSR_USB_BASE_ADDR_MASK);
|
|
|
|
- basereg |= GRUB_CS5536_MSR_USB_BASE_BUS_MASTER;
|
|
|
|
- basereg &= ~GRUB_CS5536_MSR_USB_BASE_PME_ENABLED;
|
|
|
|
- basereg &= ~GRUB_CS5536_MSR_USB_BASE_PME_STATUS;
|
|
|
|
- basereg &= ~GRUB_CS5536_MSR_USB_BASE_SMI_ENABLE;
|
|
|
|
- grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_USB_EHCI_BASE, basereg);
|
|
|
|
- }
|
|
|
|
- else
|
|
|
|
- {
|
|
|
|
- grub_pci_address_t addr;
|
|
|
|
- addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS);
|
|
|
|
- class_code = grub_pci_read (addr) >> 8;
|
|
|
|
- interf = class_code & 0xFF;
|
|
|
|
- subclass = (class_code >> 8) & 0xFF;
|
|
|
|
- class = class_code >> 16;
|
|
|
|
-
|
|
|
|
- /* If this is not an EHCI controller, just return. */
|
|
|
|
- if (class != 0x0c || subclass != 0x03 || interf != 0x20)
|
|
|
|
- return 0;
|
|
|
|
-
|
|
|
|
- grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: class OK\n");
|
|
|
|
-
|
|
|
|
- /* Check Serial Bus Release Number */
|
|
|
|
- addr = grub_pci_make_address (dev, GRUB_EHCI_PCI_SBRN_REG);
|
|
|
|
- release = grub_pci_read_byte (addr);
|
|
|
|
- if (release != 0x20)
|
|
|
|
- {
|
|
|
|
- grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: Wrong SBRN: %0x\n",
|
|
|
|
- release);
|
|
|
|
- return 0;
|
|
|
|
- }
|
|
|
|
- grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: bus rev. num. OK\n");
|
|
|
|
-
|
|
|
|
- /* Determine EHCI EHCC registers base address. */
|
|
|
|
- addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG0);
|
|
|
|
- base = grub_pci_read (addr);
|
|
|
|
- addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG1);
|
|
|
|
- base_h = grub_pci_read (addr);
|
|
|
|
- /* Stop if registers are mapped above 4G - GRUB does not currently
|
|
|
|
- * work with registers mapped above 4G */
|
|
|
|
- if (((base & GRUB_PCI_ADDR_MEM_TYPE_MASK) != GRUB_PCI_ADDR_MEM_TYPE_32)
|
|
|
|
- && (base_h != 0))
|
|
|
|
- {
|
|
|
|
- grub_dprintf ("ehci",
|
|
|
|
- "EHCI grub_ehci_pci_iter: registers above 4G are not supported\n");
|
|
|
|
- return 0;
|
|
|
|
- }
|
|
|
|
- base &= GRUB_PCI_ADDR_MEM_MASK;
|
|
|
|
- if (!base)
|
|
|
|
- {
|
|
|
|
- grub_dprintf ("ehci",
|
|
|
|
- "EHCI: EHCI is not mapped\n");
|
|
|
|
- return 0;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /* Set bus master - needed for coreboot, VMware, broken BIOSes etc. */
|
|
|
|
- addr = grub_pci_make_address (dev, GRUB_PCI_REG_COMMAND);
|
|
|
|
- grub_pci_write_word(addr,
|
|
|
|
- GRUB_PCI_COMMAND_MEM_ENABLED
|
|
|
|
- | GRUB_PCI_COMMAND_BUS_MASTER
|
|
|
|
- | grub_pci_read_word(addr));
|
|
|
|
-
|
|
|
|
- grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: 32-bit EHCI OK\n");
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
/* Allocate memory for the controller and fill basic values. */
|
|
|
|
e = grub_zalloc (sizeof (*e));
|
|
|
|
if (!e)
|
|
|
|
- return 1;
|
|
|
|
+ return;
|
|
|
|
e->framelist_chunk = NULL;
|
|
|
|
e->td_chunk = NULL;
|
|
|
|
e->qh_chunk = NULL;
|
|
|
|
- e->iobase_ehcc = grub_pci_device_map_range (dev,
|
|
|
|
- (base & GRUB_EHCI_ADDR_MEM_MASK),
|
|
|
|
- 0x100);
|
|
|
|
+ e->iobase_ehcc = regs;
|
|
|
|
|
|
|
|
- grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: iobase of EHCC: %08x\n",
|
|
|
|
- (base & GRUB_EHCI_ADDR_MEM_MASK));
|
|
|
|
grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: CAPLEN: %02x\n",
|
|
|
|
grub_ehci_ehcc_read8 (e, GRUB_EHCI_EHCC_CAPLEN));
|
|
|
|
grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: VERSION: %04x\n",
|
|
|
|
@@ -598,7 +494,7 @@ grub_ehci_pci_iter (grub_pci_device_t dev, grub_pci_id_t pciid,
|
|
|
|
if (caplen & (sizeof (grub_uint32_t) - 1))
|
|
|
|
{
|
|
|
|
grub_dprintf ("ehci", "Unaligned caplen\n");
|
|
|
|
- return 0;
|
|
|
|
+ return;
|
|
|
|
}
|
|
|
|
e->iobase = ((volatile grub_uint32_t *) e->iobase_ehcc
|
|
|
|
+ (caplen / sizeof (grub_uint32_t)));
|
|
|
|
@@ -609,7 +505,7 @@ grub_ehci_pci_iter (grub_pci_device_t dev, grub_pci_id_t pciid,
|
|
|
|
|
|
|
|
grub_dprintf ("ehci",
|
|
|
|
"EHCI grub_ehci_pci_iter: iobase of oper. regs: %08x\n",
|
|
|
|
- (base & GRUB_EHCI_ADDR_MEM_MASK) + caplen);
|
|
|
|
+ (grub_addr_t) e->iobase_ehcc + caplen);
|
|
|
|
grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: COMMAND: %08x\n",
|
|
|
|
grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND));
|
|
|
|
grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: STATUS: %08x\n",
|
|
|
|
@@ -625,10 +521,6 @@ grub_ehci_pci_iter (grub_pci_device_t dev, grub_pci_id_t pciid,
|
|
|
|
grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: CONFIG_FLAG: %08x\n",
|
|
|
|
grub_ehci_oper_read32 (e, GRUB_EHCI_CONFIG_FLAG));
|
|
|
|
|
|
|
|
- /* Is there EECP ? */
|
|
|
|
- eecp_offset = (grub_ehci_ehcc_read32 (e, GRUB_EHCI_EHCC_CPARAMS)
|
|
|
|
- & GRUB_EHCI_EECP_MASK) >> GRUB_EHCI_EECP_SHIFT;
|
|
|
|
-
|
|
|
|
/* Check format of data structures requested by EHCI */
|
|
|
|
/* XXX: In fact it is not used at any place, it is prepared for future
|
|
|
|
* This implementation uses 32-bits pointers only */
|
|
|
|
@@ -732,65 +624,6 @@ grub_ehci_pci_iter (grub_pci_device_t dev, grub_pci_id_t pciid,
|
|
|
|
|
|
|
|
grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: QH/TD init. OK\n");
|
|
|
|
|
|
|
|
- /* Determine and change ownership. */
|
|
|
|
- /* EECP offset valid in HCCPARAMS */
|
|
|
|
- /* Ownership can be changed via EECP only */
|
|
|
|
- if (pciid != GRUB_CS5536_PCIID && eecp_offset >= 0x40)
|
|
|
|
- {
|
|
|
|
- grub_pci_address_t pciaddr_eecp;
|
|
|
|
- pciaddr_eecp = grub_pci_make_address (dev, eecp_offset);
|
|
|
|
-
|
|
|
|
- usblegsup = grub_pci_read (pciaddr_eecp);
|
|
|
|
- if (usblegsup & GRUB_EHCI_BIOS_OWNED)
|
|
|
|
- {
|
|
|
|
- grub_boot_time ("Taking ownership of EHCI controller");
|
|
|
|
- grub_dprintf ("ehci",
|
|
|
|
- "EHCI grub_ehci_pci_iter: EHCI owned by: BIOS\n");
|
|
|
|
- /* Ownership change - set OS_OWNED bit */
|
|
|
|
- grub_pci_write (pciaddr_eecp, usblegsup | GRUB_EHCI_OS_OWNED);
|
|
|
|
- /* Ensure PCI register is written */
|
|
|
|
- grub_pci_read (pciaddr_eecp);
|
|
|
|
-
|
|
|
|
- /* Wait for finish of ownership change, EHCI specification
|
|
|
|
- * doesn't say how long it can take... */
|
|
|
|
- maxtime = grub_get_time_ms () + 1000;
|
|
|
|
- while ((grub_pci_read (pciaddr_eecp) & GRUB_EHCI_BIOS_OWNED)
|
|
|
|
- && (grub_get_time_ms () < maxtime));
|
|
|
|
- if (grub_pci_read (pciaddr_eecp) & GRUB_EHCI_BIOS_OWNED)
|
|
|
|
- {
|
|
|
|
- grub_dprintf ("ehci",
|
|
|
|
- "EHCI grub_ehci_pci_iter: EHCI change ownership timeout");
|
|
|
|
- /* Change ownership in "hard way" - reset BIOS ownership */
|
|
|
|
- grub_pci_write (pciaddr_eecp, GRUB_EHCI_OS_OWNED);
|
|
|
|
- /* Ensure PCI register is written */
|
|
|
|
- grub_pci_read (pciaddr_eecp);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- else if (usblegsup & GRUB_EHCI_OS_OWNED)
|
|
|
|
- /* XXX: What to do in this case - nothing ? Can it happen ? */
|
|
|
|
- grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: EHCI owned by: OS\n");
|
|
|
|
- else
|
|
|
|
- {
|
|
|
|
- grub_dprintf ("ehci",
|
|
|
|
- "EHCI grub_ehci_pci_iter: EHCI owned by: NONE\n");
|
|
|
|
- /* XXX: What to do in this case ? Can it happen ?
|
|
|
|
- * Is code below correct ? */
|
|
|
|
- /* Ownership change - set OS_OWNED bit */
|
|
|
|
- grub_pci_write (pciaddr_eecp, GRUB_EHCI_OS_OWNED);
|
|
|
|
- /* Ensure PCI register is written */
|
|
|
|
- grub_pci_read (pciaddr_eecp);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /* Disable SMI, just to be sure. */
|
|
|
|
- pciaddr_eecp = grub_pci_make_address (dev, eecp_offset + 4);
|
|
|
|
- grub_pci_write (pciaddr_eecp, 0);
|
|
|
|
- /* Ensure PCI register is written */
|
|
|
|
- grub_pci_read (pciaddr_eecp);
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- grub_dprintf ("ehci", "inithw: EHCI grub_ehci_pci_iter: ownership OK\n");
|
|
|
|
-
|
|
|
|
/* Now we can setup EHCI (maybe...) */
|
|
|
|
|
|
|
|
/* Check if EHCI is halted and halt it if not */
|
|
|
|
@@ -864,7 +697,7 @@ grub_ehci_pci_iter (grub_pci_device_t dev, grub_pci_id_t pciid,
|
|
|
|
|
|
|
|
grub_dprintf ("ehci",
|
|
|
|
"EHCI grub_ehci_pci_iter: iobase of oper. regs: %08x\n",
|
|
|
|
- (base & GRUB_EHCI_ADDR_MEM_MASK));
|
|
|
|
+ (grub_addr_t) regs);
|
|
|
|
grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: COMMAND: %08x\n",
|
|
|
|
grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND));
|
|
|
|
grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: STATUS: %08x\n",
|
|
|
|
@@ -880,7 +713,7 @@ grub_ehci_pci_iter (grub_pci_device_t dev, grub_pci_id_t pciid,
|
|
|
|
grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: CONFIG_FLAG: %08x\n",
|
|
|
|
grub_ehci_oper_read32 (e, GRUB_EHCI_CONFIG_FLAG));
|
|
|
|
|
|
|
|
- return 0;
|
|
|
|
+ return;
|
|
|
|
|
|
|
|
fail:
|
|
|
|
if (e)
|
|
|
|
@@ -894,7 +727,7 @@ fail:
|
|
|
|
}
|
|
|
|
grub_free (e);
|
|
|
|
|
|
|
|
- return 0;
|
|
|
|
+ return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
@@ -1891,12 +1724,6 @@ grub_ehci_detect_dev (grub_usb_controller_t dev, int port, int *changed)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
-static void
|
|
|
|
-grub_ehci_inithw (void)
|
|
|
|
-{
|
|
|
|
- grub_pci_iterate (grub_ehci_pci_iter, NULL);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static grub_err_t
|
|
|
|
grub_ehci_restore_hw (void)
|
|
|
|
{
|
|
|
|
@@ -1997,7 +1824,7 @@ GRUB_MOD_INIT (ehci)
|
|
|
|
grub_stop_disk_firmware ();
|
|
|
|
|
|
|
|
grub_boot_time ("Initing EHCI hardware");
|
|
|
|
- grub_ehci_inithw ();
|
|
|
|
+ grub_ehci_pci_scan ();
|
|
|
|
grub_boot_time ("Registering EHCI driver");
|
|
|
|
grub_usb_controller_dev_register (&usb_controller);
|
|
|
|
grub_boot_time ("EHCI driver registered");
|