Index: sys/dev/vt/hw/ofwfb/ofwfb.c =================================================================== --- sys/dev/vt/hw/ofwfb/ofwfb.c +++ sys/dev/vt/hw/ofwfb/ofwfb.c @@ -61,7 +61,8 @@ uint32_t vendor_id; }; -#define PCI_VENDOR_ID_NVIDIA 0x10de +#define PCI_VID_NVIDIA 0x10de /* NVIDIA Corporation */ +#define PCI_VID_ASPEED 0x1a03 /* ASPEED Technology, Inc. */ static void ofwfb_initialize(struct vt_device *vd); static vd_probe_t ofwfb_probe; @@ -90,6 +91,8 @@ static struct ofwfb_softc ofwfb_conssoftc; VT_DRIVER_DECLARE(vt_ofwfb, vt_ofwfb_driver); +uint64_t asmedia_fb_address(phandle_t node); + static int ofwfb_probe(struct vt_device *vd) { @@ -297,6 +300,91 @@ #endif } +static uint64_t +parse_ranges(phandle_t pcinode) +{ + if (!OF_hasprop(pcinode, "ranges")){ + return -1; + } + + struct simplebus_range { + uint64_t bus; + uint64_t host; + uint64_t size; + }; + + struct simplebus_range *ranges; + int nranges; + pcell_t acells, scells; + + int host_address_cells; + cell_t *base_ranges; + + ssize_t nbase_ranges; + int i, j, k; + + if (OF_getencprop(pcinode, "#address-cells", &acells, sizeof(acells)) != + sizeof(acells)) + return -1; + + if (OF_getencprop(pcinode, "#size-cells", &scells, sizeof(scells)) != + sizeof(scells)) + return -1; + + if (OF_searchencprop(OF_parent(pcinode), "#address-cells", + &host_address_cells, sizeof(host_address_cells)) != + sizeof(host_address_cells)) + return -1; + + nbase_ranges = OF_getproplen(pcinode, "ranges"); + nranges = nbase_ranges / sizeof(cell_t) / (acells + host_address_cells + scells); + + struct simplebus_range buf[4]; + ranges = (struct simplebus_range *)&buf; + + cell_t buf2[64]; + base_ranges = (cell_t *)&buf2; + + OF_getencprop(pcinode, "ranges", base_ranges, nbase_ranges); + for (i = 0, j = 0; i < nranges; i++) { + ranges[i].bus = 0; + for (k = 0; k < acells; k++) { + ranges[i].bus <<= 32; + ranges[i].bus |= base_ranges[j++]; + } + + ranges[i].host = 0; + for (k = 0; k < host_address_cells; k++) { + ranges[i].host <<= 32; + ranges[i].host |= base_ranges[j++]; + } + ranges[i].size = 0; + for (k = 0; k < scells; k++) { + ranges[i].size <<= 32; + ranges[i].size |= base_ranges[j++]; + } + + return ranges[i].host; + } + return -1; +} + +uint64_t +asmedia_fb_address(phandle_t node) +{ + while (node) { + if (OF_hasprop(node, "ranges")) { + uint64_t addr = parse_ranges(node); + node = OF_parent(node); + if (addr != 0) + return addr; + } else + node = OF_parent(node); + } + + return 0; +} + static void ofwfb_initialize(struct vt_device *vd) { @@ -350,7 +438,7 @@ * There is no good way to determine the correct option, as this * is independent of endian swapping. */ - if (sc->vendor_id == PCI_VENDOR_ID_NVIDIA) + if (sc->vendor_id == PCI_VID_NVIDIA) sc->argb = 0; else sc->argb = 1; @@ -430,7 +518,6 @@ sizeof(vendor_id)) == sizeof(vendor_id)) sc->vendor_id = vendor_id; - /* Keep track of the OF node */ sc->sc_node = node; @@ -500,9 +587,11 @@ */ user_phys = 0; TUNABLE_UINT64_FETCH("hw.ofwfb.physaddr", &user_phys); - fb_phys = (bus_addr_t)user_phys; - if (fb_phys) - sc->fb.fb_pbase = (vm_paddr_t)fb_phys; + + if (user_phys) { + sc->fb.fb_pbase = (vm_paddr_t)user_phys; + } else if (sc->vendor_id == PCI_VID_ASPEED) + sc->fb.fb_pbase = (bus_addr_t)asmedia_fb_address(node); else if (OF_hasprop(node, "address")) { switch (OF_getproplen(node, "address")) {