[coreboot] AMD Serengeti Cheetah devices

ron minnich rminnich at gmail.com
Wed Oct 8 17:45:31 CEST 2008


OK, let's go through the v2 for this a bit. It's interesting because,
well, I bet few people have bothered with it and I know I forgot.

Here we go.

				chip southbridge/amd/amd8111
					# this "device pci 0.0" is the parent the next one
					# PCI bridge
					device pci 0.0 on
						device pci 0.0 on end
						device pci 0.1 on end
						device pci 0.2 off end
						device pci 1.0 off end
					end
					device pci 1.0 on

So what happens here? The amd8111 is a chip, and it has kids, and it
has this function:
struct chip_operations southbridge_amd_amd8111_ops = {
	CHIP_NAME("AMD-8111 Southbridge")
	/* This only called when this device is listed in the
	* static device tree.
	*/
	.enable_dev = amd8111_enable,
};

enable, and the first code in the enable is this:

void amd8111_enable(device_t dev)
{
	device_t lpc_dev;
	device_t bus_dev;
	unsigned index;
	unsigned reg_old, reg;

	/* See if we are on the behind the amd8111 pci bridge */
	bus_dev = dev->bus->dev;
	if ((bus_dev->vendor == PCI_VENDOR_ID_AMD) &&
	    (bus_dev->device == PCI_DEVICE_ID_AMD_8111_PCI))
	{
		unsigned devfn;
		devfn = bus_dev->path.u.pci.devfn + (1 << 3);
		lpc_dev = dev_find_slot(bus_dev->bus->secondary, devfn);
		index = ((dev->path.u.pci.devfn & ~7) >> 3) + 8;
		if (dev->path.u.pci.devfn == 2) { /* EHCI */
			index = 16;
		}
	} else {
		unsigned devfn;
		devfn = (dev->path.u.pci.devfn) & ~7;
		lpc_dev = dev_find_slot(dev->bus->secondary, devfn);
		index = dev->path.u.pci.devfn & 7;
	}

At this point you might be saying, uh, what? What is this? It's the
kind of code that tends to send people running for the exits.

The entity is a chip, not a device. Recall that a chip can have
multiple devices but there are common chip-level registers that might
need to be set to enable or control devices. If we look at static.c
for v2,

struct device _dev15 = {
	.ops = 0,
	.bus = &_dev8.link[0],
	.path = {.type=DEVICE_PATH_PCI,.u={.pci={ .devfn = PCI_DEVFN(0x0,0)}}},
	.enabled = 1,
	.on_mainboard = 1,
	.link = {
		[0] = {
			.link = 0,
			.dev = &_dev15,
			.children = &_dev16,
		},
	},
	.links = 1,
	.sibling = &_dev20,
	.chip_ops = &southbridge_amd_amd8111_ops,
	.chip_info = &southbridge_amd_amd8111_info_14,
	.next=&_dev16
};
note that in addition to chip_info we have chip_ops.

What is chip_ops? It has one struct member, and it looks like this:

		/* Run the magice enable sequence for the device */
		if (dev->chip_ops && dev->chip_ops->enable_dev) {
			dev->chip_ops->enable_dev(dev);
		}

So the amd8111 enable will be called for each device in this tree
under the amd81111. That's why it has to check its own bus -- it has
to figure out which of its devices it is being called for, then enable
or disable that device.

Now, the pci device is the hardware that supports actual scanning. But
note that structure above:

				chip southbridge/amd/amd8111
					# this "device pci 0.0" is the parent the next one
					# PCI bridge
					device pci 0.0 on
						device pci 0.0 on end
						device pci 0.1 on end
						device pci 0.2 off end
						device pci 1.0 off end
					end
					device pci 1.0 on


The pci 0.0 is the bridge, but the devices it refers to follow it.

What should this look like in dts?

Well, I made several mistakes.

First, the amd8111.c should not have a device struct. It should have
nothing. It's just a function. In v3 we put support for functions like
amd8111_enable right into the device struct:
struct device_operations amd8111_lpc = {
	.id = {.type = DEVICE_ID_PCI,
		{.pci = {.vendor = PCI_VENDOR_ID_AMD,
			      .device = PCI_DEVICE_ID_AMD_8111_ISA}}},
	.constructor		 = default_device_constructor,
	.phase3_scan		 = scan_static_bus,
	.phase4_enable_disable           = amd8111_enable,
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

So the 'chip' keyword is gone as it did not fit well with dts.

So dts becomes this:
			pci at 0,0 {
				/config/("southbridge/amd/amd8111/pci.dts");
				pci{
					/config/("southbridge/amd/amd8111/nic.dts");
				};
			};

because it's the pci device that is a bridge.

Hope this short writeup helps; I am testing this now.

ron




More information about the coreboot mailing list