diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 9bf41e6f32..c2e9e8213d 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -114,7 +114,6 @@ STAGE2_LIB_OBJ = $(obj)/stage2.o $(obj)/clog2.o $(obj)/mem.o $(obj)/malloc $(obj)/tables.o $(obj)/delay.o $(obj)/compute_ip_checksum.o STAGE2_ARCH_X86_OBJ = $(obj)/archtables.o $(obj)/linuxbios_table.o $(obj)/udelay_io.o STAGE2_ARCH_X86_OBJ += $(obj)/pci_ops_auto.o $(obj)/pci_ops_conf1.o $(obj)/pci_ops_conf2.o -STAGE2_MAINBOARD_OBJ = $(obj)/mainboard.o STAGE2_DYNAMIC_OBJ = $(obj)/statictree.o STAGE2_OBJ := $(STAGE2_LIB_OBJ) $(STAGE2_DEVICE_OBJ) $(STAGE2_ARCH_X86_OBJ) diff --git a/device/device.c b/device/device.c index d151d990d7..3aa18918d3 100644 --- a/device/device.c +++ b/device/device.c @@ -72,10 +72,96 @@ dev_init(void) } } +/** + * @brief The default constructor, which simply allocates and sets the ops pointer + * + * Allocte a new device structure and initalize device->ops. + * + * @param A pointer to a struct constructor + * + * @return pointer to the newly created device structure. + * + * @see + */ + +struct device *default_device_constructor(struct constructor *constructor){ + struct device *dev; + dev = malloc(sizeof(*dev)); + if (dev == 0) { + die("DEV: out of memory.\n"); + } + memset(dev, 0, sizeof(dev)); + dev->ops = constructor->ops; + return dev; +} + +/** + * @brief Given a path, find a constructor + * + * Given a path, locate the constructor for it from all_constructors + * + * @param path path to the device to be created. + * + * @return pointer to the constructor or 0, if none found + * + * @see device_path + */ +struct constructor *find_constructor(struct device_id *id){ + extern struct constructor *all_constructors[]; + struct constructor *c; + int i; + printk(BIOS_SPEW, "%s: find %s\n", __func__, dev_id_string(id)); + for(i = 0; all_constructors[i]; i++) { + printk(BIOS_SPEW, "%s: check all_constructors[i] 0x%lx\n", __func__, all_constructors[i]); + for(c = all_constructors[i]; c->ops; c++) { + printk(BIOS_SPEW, "%s: cons 0x%lx, cons id %s\n", __func__, c, dev_id_string(&c->id)); + if ((! c->ops) || (!c->ops->constructor)) { + printk(BIOS_ERR, "Constructor for %s with missing ops or ops->constructor!\n", + dev_id_string(&c->id)); + continue; + } + if (id_eq(&c->id, id)){ + printk(BIOS_SPEW, "%s: match\n", __func__); + return c; + } + } + } + + return 0; +} + +/** + * @brief Given a path, find a constructor, and run it + * + * Given a path, call find_constructor to find it call that + * constructor via constructor->ops->constructor, with itself as a parameter; + * return the result. + * + * @param path path to the device to be created. + * + * @return pointer to the newly created device structure. + * + * @see device_path + */ +struct device *constructor(struct device_id *id){ + struct constructor *c; + struct device *dev = 0; + + c = find_constructor(id); + printk(BIOS_INFO, "%s constructor is 0x%lx\n", __func__, c); + if (! c) + return 0; + + dev = c->ops->constructor(c); + printk(BIOS_INFO, "%s returns 0x%lx\n", __func__, dev); + return dev; +} + + /** * @brief Allocate a new device structure. * - * Allocte a new device structure and attached it to the device tree as a + * Allocate a new device structure and attached it to the device tree as a * child of the parent bus. * * @param parent parent bus the newly created device attached to. @@ -86,7 +172,7 @@ dev_init(void) * @see device_path */ //static spinlock_t dev_lock = SPIN_LOCK_UNLOCKED; -struct device * alloc_dev(struct bus *parent, struct device_path *path) +struct device * alloc_dev(struct bus *parent, struct device_path *path, struct device_id *devid) { struct device * dev, *child; int link; @@ -98,11 +184,15 @@ struct device * alloc_dev(struct bus *parent, struct device_path *path) child = child->sibling; } - dev = malloc(sizeof(*dev)); - if (dev == 0) { - die("DEV: out of memory.\n"); - } - memset(dev, 0, sizeof(*dev)); + dev = constructor(devid); + if (! dev) + printk(BIOS_INFO, "%s: No constructor, going with empty dev", dev_id_string(devid)); + dev = malloc(sizeof(*dev)); + if (dev == 0) { + die("DEV: alloc_dev: out of memory.\n"); + } + memset(dev, 0, sizeof(*dev)); + memcpy(&dev->path, path, sizeof(*path)); /* Initialize the back pointers in the link fields */ @@ -559,6 +649,7 @@ void dev_phase5(struct device *dev) printk(BIOS_ERR, "%s: %s(%s) ops are missing phase5_enable_resources\n", __FUNCTION__, dev->dtsname, dev_path(dev)); return; } + dev->ops->phase5_enable_resources(dev); } @@ -597,13 +688,12 @@ void dev_phase1(void) post_code(0x31); for(dev = all_devices; dev; dev = dev->next) { - if (dev->ops && dev->ops->phase1) + if (dev->ops && dev->ops->phase1_set_device_operations) { - dev->ops->phase1(dev); + dev->ops->phase1_set_device_operations(dev); } } post_code(0x3e); - /* printk should be working at this point ... */ printk(BIOS_INFO, "Phase 1: done\n"); post_code(0x3f); } @@ -623,19 +713,19 @@ void dev_phase2(void) printk(BIOS_INFO, "Phase 2: Early setup...\n"); for(dev = all_devices; dev; dev = dev->next) { printk(BIOS_SPEW, "%s: dev %s: ", __FUNCTION__, dev->dtsname); - if (dev->ops && dev->ops->phase1) { - printk(BIOS_SPEW, "Calling phase2 .."); - dev->ops->phase2(dev); + if (dev->ops && dev->ops->phase2_setup_scan_bus) { + printk(BIOS_SPEW, "Calling phase2 phase2_setup_scan_bus .."); + dev->ops->phase2_setup_scan_bus(dev); printk(BIOS_SPEW, " DONE"); } printk(BIOS_SPEW, "\n"); } + post_code(0x4e); printk(BIOS_INFO, "Phase 2: Done.\n"); post_code(0x4f); } - /** * @brief Scan for devices on a bus. * @@ -665,6 +755,10 @@ unsigned int dev_phase3_scan(struct device * busdevice, unsigned int max) printk(BIOS_INFO, "%s: can not scan from here, returning %d\n", __FUNCTION__, max); return max; } + + if (busdevice->ops->phase3_enable_scan) + busdevice->ops->phase3_enable_scan(busdevice); + do_phase3 = 1; while(do_phase3) { int link; @@ -715,8 +809,9 @@ void dev_root_phase3(void) unsigned subordinate; printk(BIOS_INFO, "Phase 3: Enumerating buses...\n"); root = &dev_root; - if (root->chip_ops && root->chip_ops->enable_dev) { - root->chip_ops->enable_dev(root); + + if (root->ops && root->ops->phase3_enable_scan) { + root->ops->phase3_enable_scan(root); } post_code(0x41); if (!root->ops) { diff --git a/device/device_util.c b/device/device_util.c index 6a625b72da..f837d7ef02 100644 --- a/device/device_util.c +++ b/device/device_util.c @@ -50,12 +50,12 @@ struct device * find_dev_path(struct bus *parent, struct device_path *path) * @param path The relative path from the bus to the appropriate device * @return pointer to a device structure for the device on bus at path */ -struct device * alloc_find_dev(struct bus *parent, struct device_path *path) +struct device * alloc_find_dev(struct bus *parent, struct device_path *path, struct device_id *id) { struct device * child; child = find_dev_path(parent, path); if (!child) { - child = alloc_dev(parent, path); + child = alloc_dev(parent, path, id); } return child; } @@ -145,6 +145,7 @@ struct device *dev_find_class(unsigned int class, struct device *from) } +/* WARNING: NOT SMP-safe!*/ const char *dev_path(struct device * dev) { static char buffer[DEVICE_PATH_MAX]; @@ -203,6 +204,54 @@ const char *dev_path(struct device * dev) return buffer; } +/* WARNING: NOT SMP-safe!*/ +const char *dev_id_string(struct device_id *id) +{ + static char buffer[DEVICE_ID_MAX]; + buffer[0] = '\0'; + if (!id) { + memcpy(buffer, "", 7); + } + else { + switch(id->type) { + case DEVICE_ID_ROOT: + memcpy(buffer, "Root Device", 12); + break; + case DEVICE_ID_PCI: + sprintf(buffer, "PCI: %02x:%02x",id->u.pci.vendor, id->u.pci.device); + break; + case DEVICE_ID_PNP: + sprintf(buffer, "PNP: %04x", id->u.pnp.device); + break; + case DEVICE_ID_I2C: + sprintf(buffer, "I2C: %04x", id->u.i2c.id); + break; + case DEVICE_ID_APIC: + sprintf(buffer, "APIC: %02x:%02x",id->u.apic.vendor, id->u.apic.device); + break; + case DEVICE_ID_PCI_DOMAIN: + sprintf(buffer, "PCI_DOMAIN: %02x:%02x",id->u.pci_domain.vendor, id->u.pci_domain.device); + break; + case DEVICE_ID_APIC_CLUSTER: + sprintf(buffer, "APIC_CLUSTER: %02x:%02x",id->u.apic_cluster.vendor, id->u.apic_cluster.device); + break; + case DEVICE_ID_CPU: + sprintf(buffer, "CPU", id->u.cpu.cpuid[0], id->u.cpu.cpuid[1], id->u.cpu.cpuid[2]); + break; + case DEVICE_ID_CPU_BUS: + sprintf(buffer, "CPU_BUS: %02x:%02x",id->u.cpu_bus.vendor, id->u.cpu_bus.device); + break; + default: + printk(BIOS_ERR, "%s: Unknown device id type: %d\n", __func__, id->type); + memcpy(buffer, "Unknown", 8); + break; + } + } + return buffer; +} + + + const char *bus_path(struct bus *bus) { static char buffer[BUS_PATH_MAX]; @@ -254,6 +303,49 @@ int path_eq(struct device_path *path1, struct device_path *path2) return equal; } +int id_eq(struct device_id *path1, struct device_id *path2) +{ + int equal = 0; + if (path1->type == path2->type) { + switch(path1->type) { + case DEVICE_ID_NONE: + break; + case DEVICE_ID_ROOT: + equal = 1; + break; + case DEVICE_ID_PCI: + equal = (path1->u.pci.vendor == path2->u.pci.vendor) && (path1->u.pci.device == path2->u.pci.device); + break; + case DEVICE_ID_PNP: + equal = (path1->u.pnp.device == path2->u.pnp.device); + break; + case DEVICE_ID_I2C: + equal = (path1->u.i2c.id == path2->u.i2c.id); + break; + case DEVICE_ID_APIC: + equal = (path1->u.apic.vendor == path2->u.apic.vendor) && (path1->u.apic.device == path2->u.apic.device); + break; + case DEVICE_ID_PCI_DOMAIN: + equal = (path1->u.pci_domain.vendor == path2->u.pci_domain.vendor) && (path1->u.pci_domain.device == path2->u.pci_domain.device); + break; + case DEVICE_ID_APIC_CLUSTER: + equal = (path1->u.apic_cluster.vendor == path2->u.apic_cluster.vendor) && (path1->u.apic_cluster.device == path2->u.apic_cluster.device); + break; + case DEVICE_ID_CPU: + equal = (path1->u.cpu.cpuid == path2->u.cpu.cpuid); + break; + case DEVICE_ID_CPU_BUS: + equal = (path1->u.cpu_bus.vendor == path2->u.cpu_bus.vendor) && (path1->u.cpu_bus.device == path2->u.cpu_bus.device); + break; + default: + printk(BIOS_ERR, "Uknown device type: %d\n", path1->type); + break; + } + } + return equal; +} + + /** * See if we have unused but allocated resource structures. * If so remove the allocation. @@ -538,9 +630,6 @@ void dev_set_enabled(struct device * dev, int enable) if (dev->ops && dev->ops->phase5_enable_resources) { dev->ops->phase5_enable_resources(dev); } - else if (dev->chip_ops && dev->chip_ops->enable_dev) { - dev->chip_ops->enable_dev(dev); - } } void disable_children(struct bus *bus) diff --git a/device/pci_device.c b/device/pci_device.c index c439a030c6..8f2d305bd1 100644 --- a/device/pci_device.c +++ b/device/pci_device.c @@ -671,7 +671,7 @@ void pci_dev_init(struct device *dev) } /** Default device operation for PCI devices */ -static struct pci_operations pci_dev_ops_pci = { +struct pci_operations pci_dev_ops_pci = { .set_subsystem = pci_dev_set_subsystem, }; @@ -686,7 +686,7 @@ struct device_operations default_pci_ops_dev = { }; /** Default device operations for PCI bridges */ -static struct pci_operations pci_bus_ops_pci = { +struct pci_operations pci_bus_ops_pci = { .set_subsystem = 0, }; @@ -779,32 +779,29 @@ static struct device_operations *get_pci_bridge_ops(struct device * dev) */ static void set_pci_ops(struct device *dev) { -#if 0 - struct pci_driver *driver; -#endif + struct constructor *c; + struct device_id id = {.type = DEVICE_ID_PCI}; + if (dev->ops) { - printk(BIOS_INFO, "%s: dev %p(%s) already has ops %p\n", __func__, dev, dev->dtsname, dev->ops); + printk(BIOS_SPEW, "%s: dev %p(%s) already has ops %p\n", __func__, dev, dev->dtsname, dev->ops); return; } -#warning "need to fix this leftover PCI bogosity from V2" -#if 0 + /* we need to make the id in the device a device_id type ... */ + id.u.pci.vendor = dev->vendor; + id.u.pci.device = dev->device; /* Look through the list of setup drivers and find one for * this pci device */ - for(driver = &pci_drivers[0]; driver != &epci_drivers[0]; driver++) { - if ((driver->vendor == dev->vendor) && - (driver->device == dev->device)) - { - dev->ops = driver->ops; - printk(BIOS_SPEW,"%s [%04x/%04x] %sops\n", - dev_path(dev), - driver->vendor, driver->device, - (driver->ops->phase3_scan?"bus ":"")); - return; - } + c = find_constructor(&id); + if (c) { + dev->ops = c->ops; + printk(BIOS_SPEW,"%s id %s [%04x/%04x] %sops\n", + dev_path(dev), dev_id_string(&id), dev->vendor, dev->device, + (dev->ops->phase3_scan?"bus ":"")); + return; } -#endif + /* If I don't have a specific driver use the default operations */ switch(dev->hdr_type & 0x7f) { /* header type */ case PCI_HEADER_TYPE_NORMAL: /* standard header */ @@ -913,6 +910,7 @@ struct device * pci_probe_dev(struct device * dev, struct bus *bus, unsigned dev /* Detect if a device is present */ if (!dev) { struct device dummy; + struct device_id devid; dummy.bus = bus; dummy.path.type = DEVICE_PATH_PCI; dummy.path.u.pci.devfn = devfn; @@ -926,7 +924,10 @@ struct device * pci_probe_dev(struct device * dev, struct bus *bus, unsigned dev printk(BIOS_SPEW,"PCI: devfn 0x%x, bad id 0x%x\n", devfn, id); return NULL; } - dev = alloc_dev(bus, &dummy.path); + devid.type = DEVICE_PATH_PCI; + devid.u.pci.vendor = id & 0xffff; + devid.u.pci.device = id >> 16; + dev = alloc_dev(bus, &dummy.path, &devid); } else { /* Enable/disable the device. Once we have @@ -942,8 +943,8 @@ struct device * pci_probe_dev(struct device * dev, struct bus *bus, unsigned dev * */ /* Run the magice enable sequence for the device */ - if (dev->chip_ops && dev->chip_ops->enable_dev) { - dev->chip_ops->enable_dev(dev); + if (dev->ops && dev->ops->phase3_enable_scan) { + dev->ops->phase3_enable_scan(dev); } /* Now read the vendor and device id */ id = pci_read_config32(dev, PCI_VENDOR_ID); diff --git a/device/pnp_device.c b/device/pnp_device.c index 12f4f08799..133c83fcd3 100644 --- a/device/pnp_device.c +++ b/device/pnp_device.c @@ -144,7 +144,7 @@ struct device_operations pnp_ops = { .enable = pnp_enable, }; -/* PNP chip opertations */ +/* PNP chip operations */ static void pnp_get_ioresource(device_t dev, unsigned index, struct io_info *info) { diff --git a/device/root_device.c b/device/root_device.c index 8f8c8864db..408328f563 100644 --- a/device/root_device.c +++ b/device/root_device.c @@ -107,8 +107,8 @@ unsigned int scan_static_bus(struct device * busdevice, unsigned int max) busdevice->link[link].secondary = ++smbus_max; } for(child = busdevice->link[link].children; child; child = child->sibling) { - if (child->chip_ops && child->chip_ops->enable_dev) { - child->chip_ops->enable_dev(child); + if (child->ops && child->ops->phase3_enable_scan) { + child->ops->phase3_enable_scan(child); } /* sigh. Have to enable to scan ... */ if (child->ops && child->ops->phase5_enable_resources) { @@ -192,8 +192,9 @@ void root_dev_reset(struct bus *bus) * @brief Default device operation for root device * * This is the default device operation for root devices. These operations - * should be fully usable as is. However the chip_operations::enable_dev() - * of a motherboard can override this if you want non-default behavior. + * should be fully usable as is. If you need something else, set up your own ops + * in (e.g.) the mainboard, and initialize it in the dts in the mainboard directory. + * */ struct device_operations default_dev_ops_root = { .phase4_read_resources = root_dev_read_resources, diff --git a/include/device/device.h b/include/device/device.h index c203606c7e..a9d72bcae4 100644 --- a/include/device/device.h +++ b/include/device/device.h @@ -1,5 +1,6 @@ /* * This file is part of the LinuxBIOS project. + * Copyright (C) 2007 Ronald G. Minnich * * 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 @@ -23,37 +24,114 @@ #include #include +#define DEVICE_ID_MAX 64 +enum device_id_type { + DEVICE_ID_NONE = 0, + DEVICE_ID_ROOT, + DEVICE_ID_PCI, + DEVICE_ID_PNP, + DEVICE_ID_I2C, + DEVICE_ID_APIC, + DEVICE_ID_PCI_DOMAIN, + DEVICE_ID_APIC_CLUSTER, + DEVICE_ID_CPU, + DEVICE_ID_CPU_BUS, +}; struct device; struct pci_operations; struct pci_bus_operations; struct smbus_bus_operations; - -/* Chip operations */ -struct chip_operations { - void (*enable_dev)(struct device *dev); - char *name; -}; - struct bus; -/* we are moving from the confusing naming scheme to a numbering scheme. We are hoping - * this makes it easier for people to know the order of operations. - * So far, it is not clear. We may actually want to have names like dev_phase5_enable_resources. - * The numbering is nice, the naming is nice, what to do? - */ + + +struct pci_domain_id +{ + u16 vendor, device; +}; + +struct pci_id +{ + u16 vendor, device; +}; + +struct pnp_id +{ + u32 device; +}; + +struct i2c_id +{ + u32 id; +}; + +struct apic_id +{ + u16 vendor, device; +}; + +struct apic_cluster_id +{ + u16 vendor, device; +}; + +struct cpu_id +{ + u32 cpuid[3]; +}; + +struct cpu_bus_id +{ + u16 vendor, device; +}; + +struct device_id { + enum device_id_type type; + union { + struct pci_id pci; + struct pnp_id pnp; + struct i2c_id i2c; + struct apic_id apic; + struct pci_domain_id pci_domain; + struct apic_cluster_id apic_cluster; + struct cpu_id cpu; + struct cpu_bus_id cpu_bus; + } u; +}; + + +struct constructor { + struct device_id id; + struct device_operations *ops; +}; + struct device_operations { /* for now, we leave these, since they seem generic */ void (*set_link)(struct device * dev, unsigned int link); void (*reset_bus)(struct bus *bus); - /* phase1 is called ONLY if you CAN NEVER use printk. Only very early console needs this now */ - void (*phase1)(struct device * dev); + /* a constructor. The constructor for a given device is defined in the device source file. + * When is this called? Not for the static tree. When the scan bus code finds a new device, it must + * create it and insert it into the device tree. To do this, it calls a device constructor. + * The set of all device constructors is concatenated into the constructors array of structures via the usual + * gcc hack of naming a segment. + * The dev_constructor code in device.c iterates over the constructors array. + * A match consists of a path type, a vendor (which may be ignored if the constructo vendor value is 0), + * and a device id. + * When it finds a match, the dev_constructor calls the + * function constructors->constructor(constructors->constructor) and a new device is created. + */ + struct device *(*constructor)(struct constructor *); + + /* set device ops */ + void (*phase1_set_device_operations)(struct device *dev); /* phase 2 is for any magic you have to do before the busses are scanned */ - void (*phase2)(struct device * dev); + void (*phase2_setup_scan_bus)(struct device * dev); /* phase 3 is for scanning the bus, if needed. */ + void (*phase3_enable_scan)(struct device *dev); unsigned int (*phase3_scan)(struct device * bus, unsigned int max); /* typically used by phase4 */ @@ -127,8 +205,7 @@ struct device { unsigned int links; struct device_operations *ops; - struct chip_operations *chip_ops; - void *chip_info; + void *device_configuration; }; extern struct device dev_root; /* root bus */ @@ -136,7 +213,8 @@ extern struct device *all_devices; /* list of all devices */ /* Generic device interface functions */ -struct device * alloc_dev(struct bus *parent, struct device_path *path); +struct constructor *find_constructor(struct device_id *id); +struct device * alloc_dev(struct bus *parent, struct device_path *path, struct device_id *id); void dev_enumerate(void); void dev_configure(void); void dev_enable(void); @@ -153,17 +231,19 @@ void enable_resources(struct device *dev); void enumerate_static_device(void); void enumerate_static_devices(void); const char *dev_path(struct device * dev); +const char *dev_id_string(struct device_id *id); const char *bus_path(struct bus *bus); void dev_set_enabled(struct device * dev, int enable); void disable_children(struct bus *bus); /* Helper functions */ struct device * find_dev_path(struct bus *parent, struct device_path *path); -struct device * alloc_find_dev(struct bus *parent, struct device_path *path); +struct device * alloc_find_dev(struct bus *parent, struct device_path *path, struct device_id *id); struct device * dev_find_device (unsigned int vendor, unsigned int device, struct device * from); struct device * dev_find_class (unsigned int class, struct device * from); struct device * dev_find_slot (unsigned int bus, unsigned int devfn); struct device * dev_find_slot_on_smbus (unsigned int bus, unsigned int addr); +struct device *default_device_constructor(struct constructor *constructor); /* Rounding for boundaries. @@ -174,6 +254,7 @@ struct device * dev_find_slot_on_smbus (unsigned int bus, unsigned int addr); extern struct device_operations default_dev_ops_root; +extern int id_eq(struct device_id *id1, struct device_id *id2); void root_dev_read_resources(struct device * dev); void root_dev_set_resources(struct device * dev); unsigned int scan_static_bus(struct device * bus, unsigned int max); diff --git a/include/device/pci.h b/include/device/pci.h index 8ef0cf045a..82e6de88c7 100644 --- a/include/device/pci.h +++ b/include/device/pci.h @@ -71,6 +71,8 @@ extern struct pci_driver epci_drivers[]; extern struct device_operations default_pci_ops_dev; extern struct device_operations default_pci_ops_bus; +extern struct pci_operations pci_dev_ops_pci; +extern struct pci_operations pci_bus_ops_pci; void pci_dev_read_resources(struct device * dev); void pci_bus_read_resources(struct device * dev); diff --git a/mainboard/emulation/qemu-x86/Kconfig b/mainboard/emulation/qemu-x86/Kconfig index 10f44fddda..6738bcd11f 100644 --- a/mainboard/emulation/qemu-x86/Kconfig +++ b/mainboard/emulation/qemu-x86/Kconfig @@ -6,3 +6,4 @@ config MAINBOARD_NAME This is the default mainboard name. source northbridge/intel/i440bxemulation/Kconfig + diff --git a/mainboard/emulation/qemu-x86/Makefile b/mainboard/emulation/qemu-x86/Makefile index 8ef72143a0..fa646d6c2b 100644 --- a/mainboard/emulation/qemu-x86/Makefile +++ b/mainboard/emulation/qemu-x86/Makefile @@ -58,7 +58,10 @@ $(obj)/statictree.o: $(obj)/statictree.c $(obj)/statictree.c: mainboard/$(MAINBOARDDIR)/dts $(obj)/util/dtc/dtc $(Q)$(obj)/util/dtc/dtc -O lb mainboard/$(MAINBOARDDIR)/dts >$(obj)/statictree.c +STAGE2_MAINBOARD_OBJ = $(obj)/mainboard.o STAGE2_CHIPSET_OBJ = + # chipset include $(src)/northbridge/intel/i440bxemulation/Makefile +include $(src)/southbridge/intel/i82371eb/Makefile diff --git a/mainboard/emulation/qemu-x86/config.h b/mainboard/emulation/qemu-x86/config.h index f3fee40a60..6a7e61ead0 100644 --- a/mainboard/emulation/qemu-x86/config.h +++ b/mainboard/emulation/qemu-x86/config.h @@ -1,5 +1,3 @@ -extern struct chip_operations mainboard_emulation_qemu_x86_ops; - struct mainboard_emulation_qemu_x86_config { int nothing; }; diff --git a/mainboard/emulation/qemu-x86/dts b/mainboard/emulation/qemu-x86/dts index c707429281..33ba972d48 100644 --- a/mainboard/emulation/qemu-x86/dts +++ b/mainboard/emulation/qemu-x86/dts @@ -1,3 +1,22 @@ +/* + * This file is part of the LinuxBIOS project. + * + * Copyright (C) 2007 Ronald G. Minnich + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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 + */ /{ config="mainboard,emulation,qemu-x86"; enabled; @@ -25,6 +44,8 @@ %% +#include + struct mainboard_emulation_qemu_x86_config root = { .nothing = 1, }; @@ -32,3 +53,7 @@ struct mainboard_emulation_qemu_x86_config root = { struct northbridge_intel_i440bx_config domain0 = { .ramsize = CONFIG_NORTHBRIDGE_INTEL_I440BXEMULATION_RAMSIZE, }; + +struct constructor *all_constructors[] ={ + i440bx_constructors, i82371eb_constructors, 0 +}; diff --git a/mainboard/emulation/qemu-x86/mainboard.c b/mainboard/emulation/qemu-x86/mainboard.c index b4c57da3cd..69fb53fb3a 100644 --- a/mainboard/emulation/qemu-x86/mainboard.c +++ b/mainboard/emulation/qemu-x86/mainboard.c @@ -14,18 +14,6 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include -#include +const char *mainboard_vendor = "Emulation"; +const char *mainboard_part_number = "QEMU x86"; -const char *mainboard_vendor = "emulation"; -const char *mainboard_part_number = "qemu-x86"; - -static void enable_dev(struct device *dev) -{ - printk(BIOS_INFO, "qemu-x86 enable_dev done\n"); -} - -struct chip_operations mainboard_emulation_qemu_x86_ops = { - .name = "QEMU Mainboard", - .enable_dev = enable_dev -}; diff --git a/northbridge/intel/i440bxemulation/config.h b/northbridge/intel/i440bxemulation/config.h index a46fdccc6f..d36de9eb5d 100644 --- a/northbridge/intel/i440bxemulation/config.h +++ b/northbridge/intel/i440bxemulation/config.h @@ -18,9 +18,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -extern struct chip_operations northbridge_intel_i440bxemulation_ops; extern struct device_operations i440bxemulation_pcidomainops; - +extern struct constructor i440bx_constructors[]; struct northbridge_intel_i440bx_config { /* The various emulators don't always get 440BX right. So we are * going to allow users to set the RAM size via Kconfig. diff --git a/northbridge/intel/i440bxemulation/i440bx.c b/northbridge/intel/i440bxemulation/i440bx.c index 5dcfc3a7d9..025401c4c1 100644 --- a/northbridge/intel/i440bxemulation/i440bx.c +++ b/northbridge/intel/i440bxemulation/i440bx.c @@ -27,59 +27,47 @@ #include "config.h" #include "i440bx.h" -static void i440bxemulation_enable_dev(struct device *dev) +/* Here are the ops for 440BX as a PCI domain. */ +/* a PCI domain contains the I/O and memory resource address space below it. */ + +static void pci_domain_read_resources(struct device * dev) { - printk(BIOS_INFO, "%s: \n", __FUNCTION__); - printk(BIOS_INFO, "%s: Done.\n", __FUNCTION__); + struct resource *resource; + + /* Initialize the system wide I/O space constraints. */ + resource = new_resource(dev, IOINDEX_SUBTRACTIVE(0,0)); + resource->limit = 0xffffUL; + resource->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED; + + /* Initialize the system wide memory resources constraints. */ + resource = new_resource(dev, IOINDEX_SUBTRACTIVE(1,0)); + resource->limit = 0xffffffffULL; + resource->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED; } -/* Here are the ops for 440BX as a PCI domain. - * A PCI domain contains the I/O and memory resource address space below it. - * Currently, the only functions in here are for the domain. If device - * functions are needed, they will come later. - */ - -static void pci_domain_read_resources(struct device *dev) +static void ram_resource(struct device * dev, unsigned long index, + unsigned long basek, unsigned long sizek) { - struct resource *resource; + struct resource *resource; - /* Initialize the system wide I/O space constraints. */ - resource = new_resource(dev, IOINDEX_SUBTRACTIVE(0, 0)); - resource->limit = 0xffffUL; - resource->flags = - IORESOURCE_IO | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED; - - /* Initialize the system wide memory resources constraints. */ - resource = new_resource(dev, IOINDEX_SUBTRACTIVE(1, 0)); - resource->limit = 0xffffffffULL; - resource->flags = - IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED; + if (!sizek) { + return; + } + resource = new_resource(dev, index); + resource->base = ((resource_t)basek) << 10; + resource->size = ((resource_t)sizek) << 10; + resource->flags = IORESOURCE_MEM | IORESOURCE_CACHEABLE | \ + IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED; + printk(BIOS_INFO, "%s: add ram resoource %d bytes\n", __func__, resource->size); } -static void ram_resource(struct device *dev, unsigned long index, - unsigned long basek, unsigned long sizek) +static void pci_domain_set_resources(struct device * dev) { - struct resource *resource; - - if (!sizek) { - return; - } - resource = new_resource(dev, index); - resource->base = ((resource_t) basek) << 10; - resource->size = ((resource_t) sizek) << 10; - resource->flags = IORESOURCE_MEM | IORESOURCE_CACHEABLE | - IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED; - printk(BIOS_INFO, "%s: add RAM ressource %d bytes\n", __func__, - resource->size); -} - -static void pci_domain_set_resources(struct device *dev) -{ - struct device *mc_dev; - u32 tolmk; /* Top of low mem, Kbytes. */ + struct device * mc_dev; + u32 tolmk; /* Top of low mem, Kbytes. */ int idx; - struct northbridge_intel_i440bx_config *chip_info = dev->chip_info; - tolmk = chip_info->ramsize * 1024; + struct northbridge_intel_i440bx_config *device_configuration = dev->device_configuration; + tolmk = device_configuration->ramsize * 1024; mc_dev = dev->link[0].children; if (mc_dev) { idx = 10; @@ -88,25 +76,33 @@ static void pci_domain_set_resources(struct device *dev) phase4_assign_resources(&dev->link[0]); } -static unsigned int pci_domain_scan_bus(struct device *dev, unsigned int max) +static unsigned int pci_domain_scan_bus(struct device * dev, unsigned int max) { - max = pci_scan_bus(&dev->link[0], PCI_DEVFN(0, 0), 0xff, max); - return max; + /* there is only one link on this device, and it is always link 0 */ + max = pci_scan_bus(&dev->link[0], PCI_DEVFN(0, 0), 0xff, max); + return max; } -/* Here are the chip operations. These are for the chip-specific functions. */ -struct chip_operations northbridge_intel_i440bxemulation_ops = { - .name = "Intel 440BX Northbridge Emulation", - .enable_dev = i440bxemulation_enable_dev, +/* here are the operations for when the northbridge is running a pci domain. */ +/* see emulation/qemu-x86 for an example of how these are used. */ +struct device_operations i440bxemulation_pcidomainops = { + .constructor = default_device_constructor, + .phase3_scan = pci_domain_scan_bus, + .phase4_read_resources = pci_domain_read_resources, + .phase4_set_resources = pci_domain_set_resources, + .phase5_enable_resources = enable_childrens_resources, + .phase6_init = 0, + .ops_pci_bus = &pci_cf8_conf1, + }; -/* Here are the operations for when the northbridge is running a PCI domain. */ -/* See emulation/qemu-x86 for an example of how these are used. */ -struct device_operations i440bxemulation_pcidomainops = { - .phase4_read_resources = pci_domain_read_resources, - .phase4_set_resources = pci_domain_set_resources, - .phase5_enable_resources = enable_childrens_resources, - .phase6_init = 0, - .phase3_scan = pci_domain_scan_bus, - .ops_pci_bus = &pci_cf8_conf1, +/* the constructor for the device. */ +/* the plain PCI device uses the standard PCI operations. */ + +struct constructor i440bx_constructors[] = { + {.id={.type=DEVICE_ID_PCI_DOMAIN, .u={.pci={.vendor=0x8086, .device=0x7190}}}, + &i440bxemulation_pcidomainops}, + {.id={.type=DEVICE_ID_PCI, .u={.pci={.vendor=0x8086, .device=0x7190}}}, + &default_pci_ops_bus}, + {.ops = 0}, }; diff --git a/southbridge/intel/i82371eb/Makefile b/southbridge/intel/i82371eb/Makefile new file mode 100644 index 0000000000..4c61d54e51 --- /dev/null +++ b/southbridge/intel/i82371eb/Makefile @@ -0,0 +1,25 @@ +## +## This file is part of the LinuxBIOS project. +## +## Copyright (C) 2007 Ronald G. Minnich +## +## 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; either version 2 of the License, or +## (at your option) any later version. +## +## 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 +## + +$(obj)/%.o: $(src)/southbridge/intel/i82371eb/%.c + $(Q)$(CC) $(INITCFLAGS) -c $< -o $@ + +STAGE2_CHIPSET_OBJ += $(obj)/i82371eb.o + diff --git a/southbridge/intel/i82371eb/config.h b/southbridge/intel/i82371eb/config.h new file mode 100644 index 0000000000..39d64223f1 --- /dev/null +++ b/southbridge/intel/i82371eb/config.h @@ -0,0 +1,26 @@ +/* + * This file is part of the LinuxBIOS project. + * + * Copyright (C) 2007 Ronald G. Minnich + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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 + */ + +extern struct constructor i82371eb_constructors[]; +struct southbridge_intel_i82371eb_config +{ + int ide; +}; + diff --git a/southbridge/intel/i82371eb/i82371eb.c b/southbridge/intel/i82371eb/i82371eb.c new file mode 100644 index 0000000000..570f2575a1 --- /dev/null +++ b/southbridge/intel/i82371eb/i82371eb.c @@ -0,0 +1,60 @@ +/* + * This file is part of the LinuxBIOS project. + * + * Copyright (C) 2007 Ronald G. Minnich + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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 +#include +#include +#include +#include +#include +#include "config.h" +// #include "i82371eb.h" + + +/* The plain PCI device uses the standard PCI operations. */ + +/* Note that this structure is not necessary (yet), + * but is here as an example of how you can set up your own ops + */ + +/* You can override or extend each of these operations as needed for the device. */ +static struct device_operations i82371eb_pci_ops_dev = { + .constructor = default_device_constructor, + .phase3_scan = 0, + .phase4_read_resources = pci_dev_read_resources, + .phase4_set_resources = pci_dev_set_resources, + .phase4_enable_disable = 0, + .phase5_enable_resources = pci_dev_enable_resources, + .phase6_init = pci_dev_init, + .ops_pci = &pci_dev_ops_pci, +}; + + +struct constructor i82371eb_constructors[] = { + {.id={.type=DEVICE_ID_PCI, .u={.pci={.vendor=0x8086, .device=0x7110}}}, + &i82371eb_pci_ops_dev}, + {.id={.type=DEVICE_ID_PCI, .u={.pci={.vendor=0x8086, .device=0x7111}}}, + &i82371eb_pci_ops_dev}, + {.id={.type=DEVICE_ID_PCI, .u={.pci={.vendor=0x8086, .device=0x7112}}}, + &i82371eb_pci_ops_dev}, + {.id={.type=DEVICE_ID_PCI, .u={.pci={.vendor=0x8086, .device=0x7113}}}, + &i82371eb_pci_ops_dev}, + {.ops = 0}, +}; diff --git a/util/dtc/flattree.c b/util/dtc/flattree.c index 366c6c6f19..f7172f5ae3 100644 --- a/util/dtc/flattree.c +++ b/util/dtc/flattree.c @@ -528,8 +528,7 @@ static void linuxbios_emit_special(FILE *e, struct node *tree) } if (streq(prop->name, "config")){ - fprintf(f, "\t.chip_ops = &%s_ops,\n", clean(prop->val.val, 0)); - fprintf(f, "\t.chip_info = &%s,\n", clean(tree->label, 1)); + fprintf(f, "\t.device_configuration = &%s,\n", clean(tree->label, 1)); } if (streq(prop->name, "ops")){