HP Visualize FX

The Visualize FX is a workstation graphics card manufactured by HP, and commonly found in HP PA-RISC workstations. It comes in PCI variants for PA-RISC, and an AGP variant for use in some x86 HP workstations. Unfortunately, no documentation is available for the card, so we’re working more-or-less blind.

A GPL driver is available for the x86-AGP variant, unfortunately it simply sets up DRI in order to allow a binary X driver to card initialization, etc. However, the register list it provides has been useful.

KyleMcMartin has been working on reverse engineering the card, but there’s no working code yet.

Physical Characteristics

  • Visualize FX 2, 4, 6 all have EVC connectors, which require an adapter to go to standard HD-15 VGA monitors.

  • Visualize FX 2, 4, 6 all have a small white connector for attaching peripherals such as the “Video Out Board” (A4556A).

  • Visualize FX 4, 6 also have a long thin connector for connecting texture memory.

  • Visualize FX 6 has a connector on the back to add the geometry accelerator card which is interesting in and of itself as it has RJ45-looking ports labelled “COVE mode” on it’s geometry accelerator.

  • Visualize FX 5, 10 have no connectors onboard, but are still full length cards.

  • Visualize FXe has neither of these connectors, is much smaller (only one IC) and has HD-15 VGA output.

Chipset Info

Card

Family

GAs

TMUs

RASTs

Visualize FX2

Summit

TODO

TODO

TODO

Visualize FX4

Summit

TODO

TODO

TODO

Visualize FX6

Summit

TODO

TODO

TODO

Visualize FX5

Lego

TODO

TODO

Visualize FX10

Lego

TODO

TODO

Visualize FXe

Pinnacle

TODO

TODO

TODO

Note

Visualize FX5 and FX10 apparently combined the texture and rasterizer units into one unit.

Video Out Board (A4556A)

One input port, and three output ports. Input port labelled Genlock for synching to an external clock. Output ports labelled S-Video, CVBS, and Beta SP.

Interrupts

Visualize FX {2,4,5,6,10} do not get issued a PCI INT# line. Instead, they interrupt by writing to eim_addr.

Visualize FXe does get issued a PCI INT# line.

STI Graphics IDs

id 2fc1066b-9a02587, conforms to spec rev. 8.09 <- Visualize FX2 in B180
id 2fc1066b-9a02587, conforms to spec rev. 8.09 <- Visualize FX4 in C3000
id 2fc1066b-9a02587, conforms to spec rev. 8.09 <- Visualize FX6 in C3000
id 35acda30-9a02587, conforms to spec rev. 8.0d <- Visualize FX5 in J6000, A1299 (Fx10pro?) (4 chips), A1262A -> FX5 (3 chips)
id 35acda16-9a02587, conforms to spec rev. 8.0c <- Visualize FXe in J6000, A4982B

lspci output

  • Visualize FXe in J6000

    0000:01:01.0 3D controller: Hewlett-Packard Company Visualize FXe (rev 02)
    Subsystem: Hewlett-Packard Company: Unknown device 108c
    Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr+
             Stepping- SERR- FastB2B-
    Status: Cap- 66MHz+ UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort-
             <TAbort- <MAbort- >SERR- <PERR-
    Latency: 255
    Interrupt: pin A routed to IRQ 22
    Region 0: Memory at fb000000 (64-bit, prefetchable) [size=16M]
    Region 2: Memory at fa000000 (64-bit, non-prefetchable) [size=16M]
    Expansion ROM at f5000000 [disabled] [size=128K]
    
  • Visualize FX5 in J6000

    0000:01:01.0 Display controller: Hewlett-Packard Company Visualize FX4 (rev 02)
    Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr+
             Stepping- SERR+ FastB2B-
    Status: Cap- 66MHz+ UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort-
             <TAbort- <MAbort- >SERR- <PERR-
    Latency: 255
    Region 0: Memory at fa000000 (64-bit, non-prefetchable) [size=32M]
    Expansion ROM at f5000000 [disabled] [size=2M]
    
  • Visualize FX2 in B180 - I suppose Interrupt is bogosity, as this FX2 also interrupts using IO_EIM.

    0000:00:01.0 Display controller: Hewlett-Packard Company Visualize FX4 (rev 02)
    Control: I/O- Mem+ BusMaster- SpecCycle- MemWINV- VGASnoop- ParErr+
             Stepping- SERR+ FastB2B-
    Status: Cap- 66MHz+ UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort-
             <MAbort- >SERR- <PERR-
    Interrupt: pin ? routed to IRQ 22
    Region 0: Memory at f4000000 (64-bit, non-prefetchable) [size=32M]
    Expansion ROM at f0c00000 [disabled] [size=2M]
    
  • Visualize FX4 in C3000

    0000:03:02.0 Display controller: Hewlett-Packard Company Visualize FX4 (rev 02)
    Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr+ Stepping-
             SERR+ FastB2B-
    Status: Cap- 66MHz+ UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort-
            <MAbort- >SERR- <PERR-
    Latency: 255
    Region 0: Memory at fa000000 (64-bit, non-prefetchable) [size=32M]
    Expansion ROM at f7000000 [disabled] [size=2M]
    

Note

Annoyingly, it appears all Lego/Summit cards get the same PCI Id (103c:1008). The database should probably be updated someday to account for this. However, the STI graphics id will be different for each card family, and the number of GA/TMU for each card.

Modus Operandi

HP-UX has interesting behaviour with these cards, observable by using the kernel debugger. FX4 at least hits functions in libgraf.a named such things as summit_init_graph, etc. With my FX5, I cannot hit breakpoints set on these functions, so I would assume that the STI ROM on board the FX4 is buggy, and instead of using the onboard, a software one is used. (TODO: check to see if FX5/HP-UX hits some kind of internal STI call that FX4 doesn’t.)

It’s worth mentioning that while experimenting, I noticed that my HP-UX 11v1 Dec 2003 release does not appear to support the FXe. With graphical console configured, the installer won’t even load, complaining during the ITE initialization and then rebooting more quickly than I can read. (Is this a buggy card, or an unsupported card?) If you swap in an installed HP-UX disk, it seems to hang after ISL when booting with a FXe installed (maybe it’s still running, just console-less?). Don’t yet know what the deal with this is.

Spaces

Registers can be addressed in a number of ways, via different paths, depending on what the hardware has mapped at any given time. Names and addresses come from lego_address.h in the hpgraphics source rpm.

Base Addresses

Address

Notes

SUMMIT_BASE

0x0000’0000

((SAM_BASE << 25) & 0xfe000000)

CTL_BASE

0x0000’0000

SUMMIT_BASE + 0x0000’0000

MISC_CTL_BASE

0x0000’0000

CTL_BASE + 0x0000’0000

STI_BASE

0x0000’0000

MISC_CTL_BASE + 0x0000’0000

UNBUF_PRIV_BASE

0x0020’0000

MISC_CTL_BASE + 0x0020’0000

BUF_PRIV_BASE

0x0028’0000

MISC_CTL_BASE + 0x0028’0000

PRIV_CD_DIRECT

0x0030’0000

MISC_CTL_BASE + 0x0030’0000

DIRECT_CD_BASE

0x0038’0000

MISC_CTL_BASE + 0x0038’0000

UNBUF_CTL_BASE

0x0040’0000

CTL_BASE + 0x0040’0000

BUF2D_CTL_BASE

0x0080’0000

CTL_BASE + 0x0080’0000

BUF3D_CTL_BASE

0x00c0’0000

CTL_BASE + 0x00c0’0000

FB_BASE

0x0100’0000

SUMMIT_BASE + 0x0100’0000

FB1_BASE

0x0200’0000

SUMMIT_BASE + 0x0200’0000

FB2_BASE

0x0300’0000

SUMMIT_BASE + 0x0300’0000

The following category selectors give register position inside each base address.

Category

Selector

Notes

SAM_VDP

0x00

Video Display Processor

SAM_VIDEO_OUT

0x01

Video Out

SAM_GA_A

0x04

Geometry Accelerator A

SAM_GA_B

0x05

Geometry Accelerator B

SAM_FTF

0x06

Float to Fix Conversion

SAM_TM

0x07

Texture Mapping

SAM_RASTER

0x08

Rasterizer

SAM_FBC

0x09

Frame Buffer Controller

SAM_IMAGE

0x0c

Imaging

SAM_VOLUME

0x0d

Volumetric

SAM_RETARG

0x0e

Retargeter

SAM_SHARED

0x10

Shared

SAM_HOSTIF

0x12

Host Interface

SAM_BINC

0x13

Summit Binc

SAM_DMA

0x15

DMA Controller

SAM_OFU

0x16

Object Function Unit

SAM_OGL_ST

0x17

OpenGL State

SAM_MFU

0x18

Macro Function Unit

SAM_MFU_REMAP

0x19

Macro Function Remapped

Unbuffered privileged base addresses, (UNBUF_PRIV_BASE | (SAM_* << 14))

UP_BASE

Address

Notes

UP_VDP_BASE

0x0020’0000

UP_VIDEO_OUT_BASE

0x0020’4000

UP_FTF_BASE

0x0021’8000

UP_TM_BASE

0x0021’c000

UP_RASTER_BASE

0x0022’0000

UP_FBC_BASE

0x0022’4000

UP_IMAGE_BASE

0x0023’0000

UP_VOLUME_BASE

0x0023’4000

UP_RETARG_BASE

0x0023’8000

UP_SHARED_BASE

0x0024’0000

UP_HOSTIF_BASE

0x0024’8000

UP_BINC_BASE

0x0024’c000

UP_DMA_BASE

0x0025’4000

UP_OFU_BASE

0x0025’8000

UP_OGL_ST_BASE

0x0025’c000

UP_MFU_BASE

0x0026’0000

UP_MFU_REMAP_BASE

0x0026’4000

Buffered privileged base addresses, (BUF_PRIV_BASE | (SAM_* << 14))

BP_BASE

Address

Notes

BP_VDP_BASE

0x0028’0000

BP_VIDEO_OUT_BASE

0x0028’4000

BP_FTF_BASE

0x0029’8000

BP_TM_BASE

0x0029’c000

BP_RASTER_BASE

0x002a’0000

BP_FBC_BASE

0x002a’4000

BP_IMAGE_BASE

0x002b’0000

BP_VOLUME_BASE

0x002b’4000

BP_RETARG_BASE

0x002b’8000

BP_SHARED_BASE

0x002c’0000

BP_HOSTIF_BASE

0x002c’8000

BP_BINC_BASE

0x002c’c000

BP_DMA_BASE

0x002d’4000

BP_OFU_BASE

0x002d’8000

BP_OGL_ST_BASE

0x002d’c000

BP_MFU_BASE

0x002e’0000

BP_MFU_REMAP_BASE

0x002e’4000

Unbuffered base addresses, (UNBUF_CTL_BASE | (SAM_* << 17))

UB_BASE

Address

Notes

UB_VDP_BASE

0x0040’0000

UB_VIDEO_OUT_BASE

0x0042’0000

UB_TM_BASE

0x004e’0000

UB_RASTER_BASE

0x0050’0000

UB_FBC_BASE

0x0052’0000

UB_IMAGE_BASE

0x0058’0000

UB_VOLUME_BASE

0x005a’0000

UB_RETARG_BASE

0x005c’0000

UB_SHARED_BASE

0x0060’0000

UB_HOSTIF_BASE

0x0064’0000

UB_BINC_BASE

0x0066’0000

UB_DMA_BASE

0x006a’0000

UB_OGL_ST_BASE

0x006e’0000

2d buffered base addresses, (BUF2D_CTL_BASE | (SAM_* << 17))

B2_BASE

Address

Notes

B2_VDP_BASE

0x0080’0000

B2_VIDEO_OUT_BASE

0x0082’0000

B2_FTF_BASE

0x008c’0000

B2_TM_BASE

0x008e’0000

B2_RASTER_BASE

0x0090’0000

B2_FBC_BASE

0x0092’0000

B2_IMAGE_BASE

0x0098’0000

B2_VOLUME_BASE

0x009a’0000

B2_RETARG_BASE

0x009c’0000

B2_SHARED_BASE

0x00a0’0000

B2_HOSTIF_BASE

0x00a4’0000

B2_BINC_BASE

0x00a6’0000

B2_DMA_BASE

0x00aa’0000

B2_OFU_BASE

0x00ac’0000

B2_OGL_ST_BASE

0x00ae’0000

B2_MFU_BASE

0x00b0’0000

B2_MFU_REMAP_BASE

0x00b2’0000

3d buffered base addresses, (BUF3D_CTL_BASE | (SAM_* << 17))

B3_BASE

Address

Notes

B3_GA_A_BASE

0x00c8’0000

B3_GA_B_BASE

0x00ca’0000

B3_FTF_BASE

0x00cc’0000

B3_TM_BASE

0x00ce’0000

B3_RASTER_BASE

0x00d0’0000

B3_IMAGE_BASE

0x00d8’0000

B3_VOLUME_BASE

0x00da’0000

B3_RETARG_BASE

0x00dc’0000

B3_SHARED_BASE

0x00e0’0000

B3_HOSTIF_BASE

0x00e4’0000

B3_DMA_BASE

0x00ea’0000

B3_OGL_ST_BASE

0x00ee’0000

CD Buffers

<lamont> concept is that you spew an address, indication of
         whether or not to increment as you go, and a number of
         data words to write (starting) at that address
<lamont> followed by the data
<lamont> the hardware then turns that into the actual writes.
<lamont> the specific design issue that it is dealing with is:
         weakly orderd I/O space writes.
<lamont> since the CD buffer space is a nice contiguous block of
         I/O space, and is written sequentially, you can (1)
         have the hardware notice what registers haven't been
         written yet, and not process past that, and (2) you can
         DMA the CD buffer to the card, rather than using PIO.

The following comes from hpgraphics/headers/lego_hw_macros.h:316 from the hpgraphics DRI driver.

/*
 * First we want a macro that will create a CD packet header. This header has
 * three fields:
 *
 *   o bits 27-31 : The number of data words in this packet
 *   o bit  25    : Flag telling us whether to increment the address every time
 *                  we write the packet data. 0 means increment.
 *   o bit  24    : Flag telling us to wrap the hardware CD buffer pointer back to
 *                  the top of the CD buffer. This needs to be done every time we
 *                  wrap the software CD buffer pointer.
 *   o bits 0-23  : The starting address where we will write the packet data
 *
 * For more information, refer to section 3.5.1 in the Lego96 ERS
 */
#define CREATE_CD_PACKET_HEADER(_count, _noCount, _wrap, _addr) \
    (((_count) << 27) | ((_noCount) << 25) | ((_wrap) << 24) | (_addr))

So basically we build a packet saying how much data we are going to write, what 24-bit address on the card we want to write to, and whether to increment the address, and write all of it to CD Buffer space on the card.

Thanks to LaMontJones for clarifying this.

Registers

  • TODO: Check endianness

UP_CONTROL (0x0024’9000)

typedef union {
        struct {
                unsigned res0   :1;     /* <31> reserved */
                unsigned him    :1;     /* <30> ??? */
                unsigned hwie   :1;     /* <29> ? HWC interrupt enable */
                unsigned lwie   :1;     /* <28> ? LWC interrupt enable */
                unsigned tmie   :1;     /* <27> ? TMU interrupt enable */
                unsigned vbie   :1;     /* <26> ? VIDBUS interrupt enable */
                unsigned udce   :1;     /* <25> ??? */
                unsigned bdce   :1;     /* <24> ??? */
                unsigned res1   :1;     /* <23> reserved */
                unsigned hic    :1;     /* <22> ??? */
                unsigned hwic   :1;     /* <21> ??? */
                unsigned lwic   :1;     /* <20> ??? */
                unsigned tmic   :1;     /* <19> ??? */
                unsigned vbic   :1;     /* <18> ??? */
                unsigned udcc   :1;     /* <17> ??? */
                unsigned bdcc   :1;     /* <16> ??? */
                unsigned udpc   :1;     /* <15> ??? */
                unsigned bdpc   :1;     /* <14> ??? */
                unsigned to     :1;     /* <13> Time Out prevented, must RST */
                unsigned tce    :1;     /* <12> Timeout Circuit Enable */
                unsigned udpe   :1;     /* <11> ??? */
                unsigned bdpe   :1;     /* <10> ??? */
                unsigned wfc    :1;     /* <9> Write Fifo Control */
                unsigned rst    :1;     /* <8> Soft RST */
                unsigned scratch:8;     /* <7:0> scratch */
        } bits;
        unsigned all;
} control_t;

UP_INT_ADDR (0x0024’9200)

CPU Address interrupts will be targeted at. Use txn_alloc_irq(5) to generate a suitable address. The register is 32-bits wide, so clearly some piece hardware will F-extend before driving the address onto the system bus.

UP_INT_DATA (0x0024’9240)

Payload of write to CPU Interrupt space @ address INT_ADDR.

UP_PSTI_SCRATCH1 (0x0024’9180)

UP_PSTI_SCRATCH2 (0x0024’91a0)

UP_PSTI_SCRATCH3 (0x0024’91c0)

UP_PSTI_SCRATCH4 (0x0024’91e0)

UB_PSTI_SCRATCH1 (0x0064’1180)

UB_PSTI_SCRATCH2 (0x0064’11a0)

UB_PSTI_SCRATCH3 (0x0064’11c0)

UB_PSTI_SCRATCH4 (0x0064’11e0)

UB_STI_SCRATCH1 (0x0064’1580) also UB_CLIP_PLANE_STAMP (Lego only?)

UB_STI_SCRATCH2 (0x0064’15a0)

UB_STI_SCRATCH3 (0x0064’15c0)

UB_STI_SCRATCH4 (0x0064’15e0)

These appear to be temporary registers used to set flags that can be passed between routines.

UB_STATUS (0x0064’1400)

from hpgraphics/headers/lego_hw.h:87:

typedef union {
    struct {
        BITFIELD_18(
        Uint32      UBDRdy  : 2,    /* <31:30> UnBuffered Data Ready */
        Uint32      BDRdy   : 2,    /* <29:28> Buffered Data Ready */
        Uint32      Fault   : 1,    /* <27> Fault Detected */
        Uint32      Ubuff   : 1,    /* <26> Unbuffered Pipe Busy */
        Uint32      IMODE   : 1,    /* <25> Input Model (1=>CD Buffer) */
        Uint32      WPNE    : 1,    /* <24> Write Pipe Not Empty */
        Uint32      HIS     : 1,    /* <23> Host Interrupt Sent */
        Uint32      res22   : 1,    /* <22> reserved (was FIR) */
        Uint32      HWIR    : 1,    /* <21> High Water Interrupt Req. */
        Uint32      LWIR    : 1,    /* <20> Low Water Interrupt Req. */
        Uint32      TMIR    : 1,    /* <19> Texture Map Interrupt Req. */
        Uint32      VBIR    : 1,    /* <18> Vertical Blank Interrupt Req. */
        Uint32      UDCR    : 1,    /* <17> Unbuffered DMA Complete Req. */
        Uint32      BDCR    : 1,    /* <16> Buffered DMA Complete Req. */
        Uint32      UDPR    : 1,    /* <15> Unbuff Priv DMA Complete Req.*/
        Uint32      BDPR    : 1,    /* <14> Buff Priv  DMA Complete Req. */
        Uint32      res12   : 2,    /* <13:12> reserved */
        Uint32      ffc12   : 12    /* <11:0> FIFO Free Count (LSBs) */
        )
    }       fields;
    Uint32 bits;
} STATUS_Type;

Valid bits for UBDRdy/BDRdy, this means the READ_DATA registers has either a requested single or double word waiting in it:

#define STATUS_WordRdy      (1)
#define STATUS_DoubleRdy    (3)

UB_IRC (0x0064’3030)

UB_UIRC (0x0064’3034)

B2_IRC (0x00A4’3030)

B3_IRC (0x00E4’3030)

Buffered/Unbuffered Indirect Read Control registers.

/* PDU IRC (indirect Read Control) */
typedef union {
    struct {
        BITFIELD_3(
        Uint32      unused1         : 29,
        Uint32      op              :  2,   /* opcode for setting WTR function    */
        Uint32      WTR             :  1    /* Write To Read state flag           */
        )
    } fields;
    Uint32  bits;
} IRC_Type;

Valid IRC_type.fields.op functions:

#define PDU_IRC_NOOP        0   /* write is ignored */
#define PDU_IRC_IREAD       1   /* indirect read of IRC register */
#define PDU_IRC_CLEAR       2   /* clear WTR function (disable it) */
#define PDU_IRC_SET 3   /* set WTR function (enable it) */

B2_OTR - Overlay Transparency Register (0x0092’1148)

  • ??? It seems 3 is written to this during initialization in summit_init_graph.

  • It’s also written about the time the texture mapping system is setup with some other value.

B2_WORG (0x00a0’0818)

Zero is always stored to this inside the kernel, apparently.

UB_UREAD_DATA (0x0064’14c0)

B2_READ_DATA (0x00a4’1480)

B3_READ_DATA (0x00e4’1480)

These registers contain the result of the latest indirect (write-to-read) read request. Check for validity with UBDRdy/BDRdy in the STATUS registers. Typically code sequences look like write -1 to a register, call wait_buf_data, check it’s return, and then read the appropriate READ_DATA register.

Glossary

  • Antero - Summit texture engine.

  • B7 - Geometry accelerator on Lego cards.

  • Blitzen - Geometry accelerator on Summit cards.

  • CD buffer - Command-Data buffers, can be host side (DMA), or card side (CD Space).

  • Concorde - Command processor on Summit cards.

  • Donner - Codename of the Visualize FX6.

  • Durango - Codename of the Visualize FX5?

  • Eolus - Rasterizer on Summit cards.

  • Heathrow - Command processor on Lego cards.

  • ITE - Internal Terminal Emulator. The thingy that provides console on HP-UX.

  • Lego - Architecture of later VisFX (e/5/10).

  • Pinnacle - Codename of the Visualize FXe, comes in two flavours, Pinnacle I, and Pinnacle II.

  • Rockwood - Codename of Lego? Rockwood/Silverton/Durango are all related to railways in southwest Colorado.

  • RT - Raster/Texture engine on Lego cards.

  • Silverton - Codename of the Visualize FX10?

  • Summit - Architecture of early VisFX (2/4/6).

  • WarpDrive - Codename of the Visualize FX (WarpDrive24 == FX2/ WarpDrive48 == FX4).