Alexandru Gagniuc (mr.nuke.me@gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/8281
-gerrit
commit 49a4cf8358e5358d12c72e7a8b1c1106fbd95820 Author: Alexandru Gagniuc mr.nuke.me@gmail.com Date: Mon Jan 26 00:55:51 2015 -0600
NOTFORMERGE: Add infrastructure for radeon native initialization
This is the way that I'm thinking we should integrate native radeon init into coreboot. It doesn't make sense to have one monolithic init block as different parts are common to several architectures. e.g the VGA_MEMORY base registers seem to have been the same for years.
The idea is simple: have a few macro-ops, and dispatch the correct ops to some generic code based on whatever heuristic is appropriate. i.e. we don't have to rely on PCI IDs alone; we can poke the hardware as well before dispatching.
Note that a lot of the API is left undefined, or opaque. We'll see how that evolves as we build up the init code path.
One thing I'm considering is dropping the PCI IDs list and going on an ops-based approach, where the driver fills in several 'radeon_<component>_ops' structures, though we'll end up with some really big structs. Though it's also possible that the complexity of component ops could end up into the dispatcher, so we're back to those really big structs.
If you're looking for some inspiration, I suggest looking at the radeon driver in linux, and doing the exact opposite
Change-Id: Ifa95a8da1abfd430452dca50ed9b7ce4b09bc1c7 Signed-off-by: Alexandru Gagniuc mr.nuke.me@gmail.com --- src/drivers/Kconfig | 1 + src/drivers/Makefile.inc | 1 + src/drivers/amd/Kconfig | 12 +++++ src/drivers/amd/Makefile.inc | 6 +++ src/drivers/amd/radeon/Makefile.inc | 8 +++ src/drivers/amd/radeon/radeon.c | 79 ++++++++++++++++++++++++++++ src/drivers/amd/radeon/radeon.h | 31 +++++++++++ src/drivers/amd/radeon/radeon_dispatcher.c | 35 +++++++++++++ src/drivers/amd/radeon/radeon_private.h | 21 ++++++++ src/drivers/amd/radeon/radeon_util.c | 84 ++++++++++++++++++++++++++++++ 10 files changed, 278 insertions(+)
diff --git a/src/drivers/Kconfig b/src/drivers/Kconfig index 08de415..db74a73 100644 --- a/src/drivers/Kconfig +++ b/src/drivers/Kconfig @@ -17,6 +17,7 @@ ## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ##
+source src/drivers/amd/Kconfig source src/drivers/ams/Kconfig source src/drivers/ati/Kconfig source src/drivers/dec/Kconfig diff --git a/src/drivers/Makefile.inc b/src/drivers/Makefile.inc index 151e3f7..418a3ca 100644 --- a/src/drivers/Makefile.inc +++ b/src/drivers/Makefile.inc @@ -17,6 +17,7 @@ ## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ##
+subdirs-y += amd subdirs-y += ams subdirs-y += ati subdirs-y += dec diff --git a/src/drivers/amd/Kconfig b/src/drivers/amd/Kconfig new file mode 100644 index 0000000..1971c86 --- /dev/null +++ b/src/drivers/amd/Kconfig @@ -0,0 +1,12 @@ +# +# Copyright (C) 2015 Alexandru Gagniuc mr.nuke.me@gmail.com +# Subject to the GNU GPL v2, or (at your option) any later version. +# + +config DRIVER_AMD_RADEON + bool + default n + help + This is a wrapper shim for various radeon functionality. Selecting + this driver does not guarantee that native graphics initialization + will work, or is supported. diff --git a/src/drivers/amd/Makefile.inc b/src/drivers/amd/Makefile.inc new file mode 100644 index 0000000..51ce627 --- /dev/null +++ b/src/drivers/amd/Makefile.inc @@ -0,0 +1,6 @@ +# +# Copyright (C) 2015 Alexandru Gagniuc mr.nuke.me@gmail.com +# Subject to the GNU GPL v2, or (at your option) any later version. +# + +subdirs-$(CONFIG_DRIVER_AMD_RADEON) += radeon/ diff --git a/src/drivers/amd/radeon/Makefile.inc b/src/drivers/amd/radeon/Makefile.inc new file mode 100644 index 0000000..f5d81df --- /dev/null +++ b/src/drivers/amd/radeon/Makefile.inc @@ -0,0 +1,8 @@ +# +# Copyright (C) 2015 Alexandru Gagniuc mr.nuke.me@gmail.com +# Subject to the GNU GPL v2, or (at your option) any later version. +# + +ramstage-y += radeon.c +ramstage-y += radeon_util.c +ramstage-y += radeon_dispatcher.c diff --git a/src/drivers/amd/radeon/radeon.c b/src/drivers/amd/radeon/radeon.c new file mode 100644 index 0000000..2c720b4 --- /dev/null +++ b/src/drivers/amd/radeon/radeon.c @@ -0,0 +1,79 @@ +/* + * Wrapper for radeon utilty functions + * + * Copyright (C) 2015 Alexandru Gagniuc mr.nuke.me@gmail.com + * Subject to the GNU GPL v2, or (at your option) any later version. + */ + +#include <arch/io.h> +#include <console/console.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <stdlib.h> + +#include "radeon.h" + +static void radeon_display_init(struct radeon_device *rdev) +{ + disp_init_t display_init; + struct radeon_disp_path *display; + + display = radeon_get_default_disp_path(); + if (!display) { + printk(BIOS_WARNING, "Could not get a display path\n"); + return; + } + + if (!is_native_init_capable(rdev, display)) { + printk(BIOS_WARNING, "Cannot init given display path\n"); + return; + } + + display_init = dispatch_display_init(rdev); + if (!display) { + printk(BIOS_WARNING, "[BUG!!!] display_init not dispatched\n"); + return; + } + + display_init(rdev, display); +} + +static void radeon_init(device_t dev) +{ + asic_init_t asic_init; + struct radeon_device *rdev; + + printk(BIOS_INFO, "Hello from radeon init\n"); + + rdev = create_radeon_device(dev); + asic_init = dispatch_asic_init(dev); + if (asic_init) + asic_init(rdev); + else + printk(BIOS_WARNING, "No asic_init for this device\n"); + + if (IS_ENABLED(MAINBOARD_DO_NATIVE_VGA_INIT)) + radeon_display_init(rdev); + + pci_dev_init(dev); +} + +static struct device_operations radeon_operations = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = radeon_init, + .disable = device_noop, + .enable = device_noop, + .ops_pci = 0, +}; + +static const uint16_t radeon_ids[] = { + 0 +}; + +static const struct pci_driver radeon_driver __pci_driver = { + .ops = &radeon_operations, + .vendor = PCI_VENDOR_ID_ATI, + .devices = radeon_ids, +}; diff --git a/src/drivers/amd/radeon/radeon.h b/src/drivers/amd/radeon/radeon.h new file mode 100644 index 0000000..824e609 --- /dev/null +++ b/src/drivers/amd/radeon/radeon.h @@ -0,0 +1,31 @@ +/* + * All things radeon + * + * Copyright (C) 2015 Alexandru Gagniuc mr.nuke.me@gmail.com + * Subject to the GNU GPL v2, or (at your option) any later version. + */ + +#ifndef _DRIVERS_AMD_RADEON_RADEON_H +#define _DRIVERS_AMD_RADEON_RADEON_H + +#include <device/device.h> + +/* These structs are intentionally opaque */ +struct radeon_device; +struct radeon_disp_path; + +typedef void (* asic_init_t)(struct radeon_device *); +typedef void (* disp_init_t)(struct radeon_device *, struct radeon_disp_path *); + +asic_init_t dispatch_asic_init(device_t dev); +disp_init_t dispatch_display_init(struct radeon_device *rdev); +struct radeon_device *create_radeon_device(device_t dev); +struct radeon_disp_path *radeon_get_default_disp_path(void); +bool is_native_init_capable(struct radeon_device *, struct radeon_disp_path *); + +void rdev_write(struct radeon_device *rdev, uint32_t reg, uint32_t value); +uint32_t rdev_read(struct radeon_device *rdev, uint32_t reg); +void rdev_mask(struct radeon_device *rdev, uint32_t reg, uint32_t clrbits, + uint32_t setbits); + +#endif /* _DRIVERS_AMD_RADEON_RADEON_H */ diff --git a/src/drivers/amd/radeon/radeon_dispatcher.c b/src/drivers/amd/radeon/radeon_dispatcher.c new file mode 100644 index 0000000..2fa52ae --- /dev/null +++ b/src/drivers/amd/radeon/radeon_dispatcher.c @@ -0,0 +1,35 @@ +/* + * Dispatch initialization functions + * + * Copyright (C) 2015 Alexandru Gagniuc mr.nuke.me@gmail.com + * Subject to the GNU GPL v2, or (at your option) any later version. + */ +#include "radeon.h" +#include "aruba/aruba.h" + +#include <device/pci_ids.h> + +asic_init_t dispatch_asic_init(device_t dev) +{ + if (dev->vendor != PCI_VENDOR_ID_ATI) + return NULL; + + return NULL; +} + +disp_init_t dispatch_display_init(struct radeon_device *rdev) +{ + /* This is a no-op */ + return NULL; +} + +bool is_native_init_capable(struct radeon_device *rdev, + struct radeon_disp_path *display) +{ + return false; +} + +struct radeon_disp_path *radeon_get_default_disp_path(void) +{ + return NULL; +} diff --git a/src/drivers/amd/radeon/radeon_private.h b/src/drivers/amd/radeon/radeon_private.h new file mode 100644 index 0000000..11cb0c9 --- /dev/null +++ b/src/drivers/amd/radeon/radeon_private.h @@ -0,0 +1,21 @@ +/* + * Your code should not need these. If it does, it's wrong. + * + * Copyright (C) 2015 Alexandru Gagniuc mr.nuke.me@gmail.com + * Subject to the GNU GPL v2, or (at your option) any later version. + */ + +#ifndef _RADEON_PRIVATE_H +#define _RADEON_PRIVATE_H + +#include <device/device.h> + +struct radeon_device { + struct device *cb_dev; + uint16_t pio_base; + uint16_t pio_size; + void *mmio_base; + size_t mmio_size; +}; + +#endif /* _RADEON_PRIVATE_H */ diff --git a/src/drivers/amd/radeon/radeon_util.c b/src/drivers/amd/radeon/radeon_util.c new file mode 100644 index 0000000..04f3682 --- /dev/null +++ b/src/drivers/amd/radeon/radeon_util.c @@ -0,0 +1,84 @@ +/* + * Low-level radeon helpers + * + * Copyright (C) 2013 Alexandru Gagniuc mr.nuke.me@gmail.com + * Subject to the GNU GPL v2, or (at your option) any later version. + */ + +#include "radeon.h" +#include "radeon_private.h" + +#include <arch/io.h> +#include <device/pci.h> +#include <stdlib.h> +#include <string.h> +#include <console/console.h> + +struct radeon_device *create_radeon_device(device_t dev) +{ + int num_res_found = 0; + struct radeon_device *rdev; + struct resource *res = dev->resource_list; + + rdev = malloc(sizeof(*rdev)); + if (rdev == NULL) + return NULL; + memset(rdev, 0, sizeof(*rdev)); + + rdev->cb_dev = dev; + + while (res) { + /* Register PIO space */ + if (res->index == PCI_BASE_ADDRESS_1) { + if (!(res->flags & IORESOURCE_IO)) + continue; + rdev->pio_base = res->base; + rdev->pio_size = res->size; + num_res_found++; + } + + /* Get the register MMIO space (not the framebuffer) */ + if (res->index == PCI_BASE_ADDRESS_2) { + if (!(res->flags & IORESOURCE_MEM)) + continue; + rdev->mmio_base = (void *)(uintptr_t)res->base; + rdev->mmio_size = res->size; + num_res_found++; + } + /* We care about the register IO and register MMIO resources */ + if (num_res_found == 2) + break; + + res = res->next; + } + + if (num_res_found < 2) { + /* We're missing either the MMIO or PIO base. Can't continue*/ + free(rdev); + return NULL; + } + + return rdev; +} + + +void rdev_write(struct radeon_device *rdev, uint32_t reg, uint32_t value) +{ + unsigned long mmio = (unsigned long)rdev->mmio_base + reg; + write32(mmio, value); +} + +uint32_t rdev_read(struct radeon_device *rdev, uint32_t reg) +{ + unsigned long mmio = (unsigned long)rdev->mmio_base + reg; + return read32(mmio); +} + +void rdev_mask(struct radeon_device *rdev, uint32_t reg, uint32_t clrbits, + uint32_t setbits) +{ + uint32_t reg32 = rdev_read(rdev, reg); + reg32 &= ~clrbits; + reg32 |= setbits; + rdev_write(rdev, reg, reg32); +}