Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/vt/hw/ofwfb/ofwfb.c
Show First 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | |||||
#include <vm/pmap.h> | #include <vm/pmap.h> | ||||
#include <machine/bus.h> | #include <machine/bus.h> | ||||
#include <machine/cpu.h> | #include <machine/cpu.h> | ||||
#include <dev/ofw/openfirm.h> | #include <dev/ofw/openfirm.h> | ||||
#include <dev/ofw/ofw_bus.h> | #include <dev/ofw/ofw_bus.h> | ||||
#include <dev/ofw/ofw_pci.h> | #include <dev/ofw/ofw_pci.h> | ||||
#include <dev/ofw/ofw_subr.h> | |||||
struct ofwfb_softc { | struct ofwfb_softc { | ||||
struct fb_info fb; | struct fb_info fb; | ||||
phandle_t sc_node; | phandle_t sc_node; | ||||
ihandle_t sc_handle; | ihandle_t sc_handle; | ||||
bus_space_tag_t sc_memt; | bus_space_tag_t sc_memt; | ||||
int iso_palette; | int iso_palette; | ||||
int argb; | |||||
int endian_flip; | |||||
uint32_t vendor_id; | |||||
}; | }; | ||||
#define PCI_VENDOR_ID_NVIDIA 0x10de | |||||
static void ofwfb_initialize(struct vt_device *vd); | static void ofwfb_initialize(struct vt_device *vd); | ||||
static vd_probe_t ofwfb_probe; | static vd_probe_t ofwfb_probe; | ||||
static vd_init_t ofwfb_init; | static vd_init_t ofwfb_init; | ||||
static vd_bitblt_text_t ofwfb_bitblt_text; | static vd_bitblt_text_t ofwfb_bitblt_text; | ||||
static vd_bitblt_bmp_t ofwfb_bitblt_bitmap; | static vd_bitblt_bmp_t ofwfb_bitblt_bitmap; | ||||
static const struct vt_driver vt_ofwfb_driver = { | static const struct vt_driver vt_ofwfb_driver = { | ||||
.vd_name = "ofwfb", | .vd_name = "ofwfb", | ||||
▲ Show 20 Lines • Show All 224 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
static void | static void | ||||
ofwfb_initialize(struct vt_device *vd) | ofwfb_initialize(struct vt_device *vd) | ||||
{ | { | ||||
struct ofwfb_softc *sc = vd->vd_softc; | struct ofwfb_softc *sc = vd->vd_softc; | ||||
int i, err; | int i, err; | ||||
cell_t retval; | cell_t retval; | ||||
uint32_t oldpix; | |||||
sc->fb.fb_cmsize = 16; | sc->fb.fb_cmsize = 16; | ||||
if (sc->fb.fb_flags & FB_FLAG_NOWRITE) | if (sc->fb.fb_flags & FB_FLAG_NOWRITE) | ||||
return; | return; | ||||
/* | /* | ||||
* Set up the color map | * Set up the color map | ||||
*/ | */ | ||||
sc->iso_palette = 0; | sc->iso_palette = 0; | ||||
switch (sc->fb.fb_bpp) { | switch (sc->fb.fb_bpp) { | ||||
case 8: | case 8: | ||||
/* | |||||
* No color format issues here, since we are passing the RGB | |||||
* components separately to Open Firmware. | |||||
*/ | |||||
vt_generate_cons_palette(sc->fb.fb_cmap, COLOR_FORMAT_RGB, 255, | vt_generate_cons_palette(sc->fb.fb_cmap, COLOR_FORMAT_RGB, 255, | ||||
16, 255, 8, 255, 0); | 16, 255, 8, 255, 0); | ||||
for (i = 0; i < 16; i++) { | for (i = 0; i < 16; i++) { | ||||
err = OF_call_method("color!", sc->sc_handle, 4, 1, | err = OF_call_method("color!", sc->sc_handle, 4, 1, | ||||
(cell_t)((sc->fb.fb_cmap[i] >> 16) & 0xff), | (cell_t)((sc->fb.fb_cmap[i] >> 16) & 0xff), | ||||
(cell_t)((sc->fb.fb_cmap[i] >> 8) & 0xff), | (cell_t)((sc->fb.fb_cmap[i] >> 8) & 0xff), | ||||
(cell_t)((sc->fb.fb_cmap[i] >> 0) & 0xff), | (cell_t)((sc->fb.fb_cmap[i] >> 0) & 0xff), | ||||
(cell_t)i, &retval); | (cell_t)i, &retval); | ||||
if (err) | if (err) | ||||
break; | break; | ||||
} | } | ||||
if (i != 16) | if (i != 16) | ||||
sc->iso_palette = 1; | sc->iso_palette = 1; | ||||
break; | break; | ||||
case 32: | case 32: | ||||
/* | /* | ||||
* We bypass the usual bus_space_() accessors here, mostly | * There are two main color formats in use. | ||||
* for performance reasons. In particular, we don't want | * ARGB32 is used mainly on hardware that was designed for | ||||
* any barrier operations that may be performed and handle | * LE systems, and RGBA32 is used mainly on hardware designed | ||||
* endianness slightly different. Figure out the host-view | * for BE systems. | ||||
* endianness of the frame buffer. | * | ||||
* PowerMacs use either, depending on the video card option. | |||||
* NVidia cards tend to be RGBA32, and ATI cards tend to be ARGB32. | |||||
* | |||||
* There is no good way to determine the correct option, as this | |||||
* is independent of endian swapping. | |||||
*/ | */ | ||||
oldpix = bus_space_read_4(sc->sc_memt, sc->fb.fb_vbase, 0); | if (sc->vendor_id == PCI_VENDOR_ID_NVIDIA) | ||||
bus_space_write_4(sc->sc_memt, sc->fb.fb_vbase, 0, 0xff000000); | sc->argb = 0; | ||||
if (*(uint8_t *)(sc->fb.fb_vbase) == 0xff) | else | ||||
sc->argb = 1; | |||||
TUNABLE_INT_FETCH("hw.ofwfb.argb32_pixel", &sc->argb); | |||||
if (sc->endian_flip) { | |||||
if (sc->argb) | |||||
vt_generate_cons_palette(sc->fb.fb_cmap, | vt_generate_cons_palette(sc->fb.fb_cmap, | ||||
COLOR_FORMAT_RGB, 255, 0, 255, 8, 255, 16); | COLOR_FORMAT_RGB, 255, 8, 255, 16, 255, 24); | ||||
else | else | ||||
vt_generate_cons_palette(sc->fb.fb_cmap, | vt_generate_cons_palette(sc->fb.fb_cmap, | ||||
COLOR_FORMAT_RGB, 255, 24, 255, 16, 255, 8); | |||||
} else { | |||||
if (sc->argb) | |||||
vt_generate_cons_palette(sc->fb.fb_cmap, | |||||
COLOR_FORMAT_RGB, 255, 16, 255, 8, 255, 0); | COLOR_FORMAT_RGB, 255, 16, 255, 8, 255, 0); | ||||
bus_space_write_4(sc->sc_memt, sc->fb.fb_vbase, 0, oldpix); | else | ||||
vt_generate_cons_palette(sc->fb.fb_cmap, | |||||
COLOR_FORMAT_RGB, 255, 0, 255, 8, 255, 16); | |||||
} | |||||
break; | break; | ||||
default: | default: | ||||
panic("Unknown color space depth %d", sc->fb.fb_bpp); | panic("Unknown color space depth %d", sc->fb.fb_bpp); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
static int | static int | ||||
ofwfb_init(struct vt_device *vd) | ofwfb_init(struct vt_device *vd) | ||||
{ | { | ||||
struct ofwfb_softc *sc; | struct ofwfb_softc *sc; | ||||
char buf[64]; | char buf[64]; | ||||
phandle_t chosen; | phandle_t chosen; | ||||
phandle_t node; | phandle_t node; | ||||
uint32_t depth, height, width, stride; | uint32_t depth, height, width, stride; | ||||
uint32_t fb_phys; | uint32_t vendor_id = 0; | ||||
int i, len; | cell_t adr[2]; | ||||
uint64_t user_phys; | |||||
bus_addr_t fb_phys; | |||||
bus_size_t fb_phys_size; | |||||
int i, j, len; | |||||
/* Initialize softc */ | /* Initialize softc */ | ||||
vd->vd_softc = sc = &ofwfb_conssoftc; | vd->vd_softc = sc = &ofwfb_conssoftc; | ||||
node = -1; | node = -1; | ||||
chosen = OF_finddevice("/chosen"); | chosen = OF_finddevice("/chosen"); | ||||
if (OF_getprop(chosen, "stdout", &sc->sc_handle, | if (OF_getprop(chosen, "stdout", &sc->sc_handle, | ||||
sizeof(ihandle_t)) == sizeof(ihandle_t)) | sizeof(ihandle_t)) == sizeof(ihandle_t)) | ||||
Show All 12 Lines | if (node == -1) { | ||||
*/ | */ | ||||
node = OF_finddevice("screen"); | node = OF_finddevice("screen"); | ||||
sc->sc_handle = OF_open("screen"); | sc->sc_handle = OF_open("screen"); | ||||
} | } | ||||
OF_getprop(node, "device_type", buf, sizeof(buf)); | OF_getprop(node, "device_type", buf, sizeof(buf)); | ||||
if (strcmp(buf, "display") != 0) | if (strcmp(buf, "display") != 0) | ||||
return (CN_DEAD); | return (CN_DEAD); | ||||
/* | |||||
* Retrieve vendor-id from /chosen parent node, usually pointing to | |||||
* video card device. This is used to select pixel format later on | |||||
* ofwfb_initialize() | |||||
*/ | |||||
if (OF_getprop(OF_parent(node), "vendor-id", &vendor_id, | |||||
luporl: Does this work on LE?
Or does OF_getencprop need to be used instead? | |||||
alfredoAuthorUnsubmitted Done Inline ActionsGood catch, thanks! alfredo: Good catch, thanks!
If possible, please try this latest version as base for your patches, on… | |||||
sizeof(vendor_id)) == sizeof(vendor_id)) | |||||
sc->vendor_id = vendor_id; | |||||
/* Keep track of the OF node */ | /* Keep track of the OF node */ | ||||
sc->sc_node = node; | sc->sc_node = node; | ||||
/* | /* | ||||
* Try to use a 32-bit framebuffer if possible. This may be | * Try to use a 32-bit framebuffer if possible. This may be | ||||
* unimplemented and fail. That's fine -- it just means we are | * unimplemented and fail. That's fine -- it just means we are | ||||
* stuck with the defaults. | * stuck with the defaults. | ||||
*/ | */ | ||||
Show All 12 Lines | ofwfb_init(struct vt_device *vd) | ||||
sc->fb.fb_bpp = sc->fb.fb_depth = depth; | sc->fb.fb_bpp = sc->fb.fb_depth = depth; | ||||
OF_getprop(node, "height", &height, sizeof(height)); | OF_getprop(node, "height", &height, sizeof(height)); | ||||
OF_getprop(node, "width", &width, sizeof(width)); | OF_getprop(node, "width", &width, sizeof(width)); | ||||
if (OF_getprop(node, "linebytes", &stride, sizeof(stride)) != | if (OF_getprop(node, "linebytes", &stride, sizeof(stride)) != | ||||
sizeof(stride)) | sizeof(stride)) | ||||
stride = width*depth/8; | stride = width*depth/8; | ||||
sc->fb.fb_height = height; | sc->fb.fb_height = height; | ||||
sc->fb.fb_width = width; | sc->fb.fb_width = width; | ||||
sc->fb.fb_stride = stride; | sc->fb.fb_stride = stride; | ||||
sc->fb.fb_size = sc->fb.fb_height * sc->fb.fb_stride; | sc->fb.fb_size = sc->fb.fb_height * sc->fb.fb_stride; | ||||
sc->endian_flip = 0; | |||||
/* | |||||
* Grab the physical address of the framebuffer, and then map it | |||||
* into our memory space. If the MMU is not yet up, it will be | |||||
* remapped for us when relocation turns on. | |||||
*/ | |||||
if (OF_getproplen(node, "address") == sizeof(fb_phys)) { | |||||
/* XXX We assume #address-cells is 1 at this point. */ | |||||
OF_getprop(node, "address", &fb_phys, sizeof(fb_phys)); | |||||
#if defined(__powerpc__) | #if defined(__powerpc__) | ||||
if (OF_hasprop(node, "little-endian")) { | |||||
sc->sc_memt = &bs_le_tag; | |||||
#if BYTE_ORDER == BIG_ENDIAN | |||||
sc->endian_flip = 1; | |||||
#endif | |||||
} else if (OF_hasprop(node, "big-endian")) | |||||
sc->sc_memt = &bs_be_tag; | sc->sc_memt = &bs_be_tag; | ||||
bus_space_map(sc->sc_memt, fb_phys, sc->fb.fb_size, | #if BYTE_ORDER == LITTLE_ENDIAN | ||||
BUS_SPACE_MAP_PREFETCHABLE, &sc->fb.fb_vbase); | sc->endian_flip = 1; | ||||
#endif | |||||
else { | |||||
luporlUnsubmitted Done Inline ActionsThis fails to compile on LE, due to missing braces. luporl: This fails to compile on LE, due to missing braces. | |||||
/* Assume the framebuffer is in native endian. */ | |||||
#if BYTE_ORDER == BIG_ENDIAN | |||||
sc->sc_memt = &bs_be_tag; | |||||
#else | |||||
sc->sc_memt = &bs_le_tag; | |||||
#endif | |||||
} | |||||
#elif defined(__arm__) | #elif defined(__arm__) | ||||
sc->sc_memt = fdtbus_bs_tag; | sc->sc_memt = fdtbus_bs_tag; | ||||
bus_space_map(sc->sc_memt, sc->fb.fb_pbase, sc->fb.fb_size, | |||||
BUS_SPACE_MAP_PREFETCHABLE, | |||||
(bus_space_handle_t *)&sc->fb.fb_vbase); | |||||
#else | #else | ||||
#error Unsupported platform! | #error Unsupported platform! | ||||
#endif | #endif | ||||
sc->fb.fb_pbase = fb_phys; | |||||
/* | |||||
* Grab the physical address of the framebuffer, and then map it | |||||
* into our memory space. If the MMU is not yet up, it will be | |||||
* remapped for us when relocation turns on. | |||||
*/ | |||||
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; | |||||
else if (OF_hasprop(node, "address")) { | |||||
switch (OF_getproplen(node, "address")) { | |||||
case 4: | |||||
OF_getencprop(node, "address", adr, 4); | |||||
fb_phys = adr[0]; | |||||
break; | |||||
case 8: | |||||
OF_getencprop(node, "address", adr, 8); | |||||
fb_phys = ((uint64_t)adr[0] << 32) | adr[1]; | |||||
break; | |||||
default: | |||||
/* Bad property? */ | |||||
return (CN_DEAD); | |||||
} | |||||
sc->fb.fb_pbase = (vm_paddr_t)fb_phys; | |||||
} else { | } else { | ||||
#if defined(__powerpc__) | |||||
/* | /* | ||||
* Some IBM systems don't have an address property. Try to | * Some IBM systems don't have an address property. Try to | ||||
* guess the framebuffer region from the assigned addresses. | * guess the framebuffer region from the assigned addresses. | ||||
* This is ugly, but there doesn't seem to be an alternative. | * This is ugly, but there doesn't seem to be an alternative. | ||||
* Linux does the same thing. | * Linux does the same thing. | ||||
*/ | */ | ||||
struct ofw_pci_register pciaddrs[8]; | struct ofw_pci_register pciaddrs[8]; | ||||
Show All 9 Lines | #if defined(__powerpc__) | ||||
if (len == -1) { | if (len == -1) { | ||||
len = OF_getprop(OF_parent(node), "assigned-addresses", | len = OF_getprop(OF_parent(node), "assigned-addresses", | ||||
pciaddrs, sizeof(pciaddrs)); | pciaddrs, sizeof(pciaddrs)); | ||||
} | } | ||||
if (len == -1) | if (len == -1) | ||||
len = 0; | len = 0; | ||||
num_pciaddrs = len / sizeof(struct ofw_pci_register); | num_pciaddrs = len / sizeof(struct ofw_pci_register); | ||||
fb_phys = num_pciaddrs; | j = num_pciaddrs; | ||||
for (i = 0; i < num_pciaddrs; i++) { | for (i = 0; i < num_pciaddrs; i++) { | ||||
/* If it is too small, not the framebuffer */ | /* If it is too small, not the framebuffer */ | ||||
if (pciaddrs[i].size_lo < sc->fb.fb_stride * height) | if (pciaddrs[i].size_lo < sc->fb.fb_stride * height) | ||||
continue; | continue; | ||||
/* If it is not memory, it isn't either */ | /* If it is not memory, it isn't either */ | ||||
if (!(pciaddrs[i].phys_hi & | if (!(pciaddrs[i].phys_hi & | ||||
OFW_PCI_PHYS_HI_SPACE_MEM32)) | OFW_PCI_PHYS_HI_SPACE_MEM32)) | ||||
continue; | continue; | ||||
/* This could be the framebuffer */ | /* This could be the framebuffer */ | ||||
fb_phys = i; | j = i; | ||||
/* If it is prefetchable, it certainly is */ | /* If it is prefetchable, it certainly is */ | ||||
if (pciaddrs[i].phys_hi & OFW_PCI_PHYS_HI_PREFETCHABLE) | if (pciaddrs[i].phys_hi & OFW_PCI_PHYS_HI_PREFETCHABLE) | ||||
break; | break; | ||||
} | } | ||||
if (fb_phys == num_pciaddrs) /* No candidates found */ | if (j == num_pciaddrs) /* No candidates found */ | ||||
return (CN_DEAD); | return (CN_DEAD); | ||||
#if defined(__powerpc__) | if (ofw_reg_to_paddr(node, j, &fb_phys, &fb_phys_size, NULL) < 0) | ||||
OF_decode_addr(node, fb_phys, &sc->sc_memt, &sc->fb.fb_vbase, | return (CN_DEAD); | ||||
NULL); | |||||
sc->fb.fb_pbase = sc->fb.fb_vbase & ~DMAP_BASE_ADDRESS; | sc->fb.fb_pbase = (vm_paddr_t)fb_phys; | ||||
#else | #else | ||||
/* No ability to interpret assigned-addresses otherwise */ | /* No ability to interpret assigned-addresses otherwise */ | ||||
return (CN_DEAD); | return (CN_DEAD); | ||||
#endif | #endif | ||||
} | } | ||||
if (!sc->fb.fb_pbase) | |||||
return (CN_DEAD); | |||||
bus_space_map(sc->sc_memt, sc->fb.fb_pbase, sc->fb.fb_size, | |||||
BUS_SPACE_MAP_PREFETCHABLE, | |||||
(bus_space_handle_t *)&sc->fb.fb_vbase); | |||||
#if defined(__powerpc__) | #if defined(__powerpc__) | ||||
/* | /* | ||||
* If we are running on PowerPC in real mode (supported only on AIM | * If we are running on PowerPC in real mode (supported only on AIM | ||||
* CPUs), the frame buffer may be inaccessible (real mode does not | * CPUs), the frame buffer may be inaccessible (real mode does not | ||||
* necessarily cover all RAM) and may also be mapped with the wrong | * necessarily cover all RAM) and may also be mapped with the wrong | ||||
* cache properties (all real mode accesses are assumed cacheable). | * cache properties (all real mode accesses are assumed cacheable). | ||||
* Just don't write to it for the time being. | * Just don't write to it for the time being. | ||||
Show All 9 Lines |
Does this work on LE?
Or does OF_getencprop need to be used instead?