open-src/app/gfx-utils/sun-src/vts/efb/tools.c
author Alan Coopersmith <Alan.Coopersmith@Oracle.COM>
Mon, 25 Apr 2011 14:22:03 -0700
changeset 1117 629ac4b133bc
child 1368 475ce9398539
permissions -rw-r--r--
7039328 Move SPARC Graphics utilities to X consolidation


/*
 * Copyright (c) 2006, 2009, Oracle and/or its affiliates. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

#include <sys/types.h>
#include <stdio.h>
#include <sys/mman.h>

#include "gfx_common.h"		/* GFX Common definitions */
#include "graphicstest.h"
#include "libvtsSUNWefb.h"	/* Common VTS library definitions */

#include "X11/Xlib.h"
#include "gfx_vts.h"		/* VTS Graphics Test common routines */
#include "efb.h"


int
efb_get_pci_info(int fd, struct pci_info *pciInfo)
{
	struct gfx_pci_cfg pciCfg;
	int i;
	unsigned int bar;

	if (ioctl(fd, GFX_IOCTL_GET_PCI_CONFIG, &pciCfg) == -1) {
		return -1;
	}

        pciInfo->deviceID = pciCfg.DeviceID;

	for (i = 0; i < 6; i++) {
	    bar = pciCfg.bar[i];
	    if (bar != 0) {
		if (bar & PCI_MAP_IO) {
		    pciInfo->ioBase[i] = PCIGETIO(bar);
		    pciInfo->type[i] = bar & PCI_MAP_IO_ATTR_MASK;
		} else {
		    pciInfo->type[i] = bar & PCI_MAP_MEMORY_ATTR_MASK;
		    pciInfo->memBase[i] = PCIGETMEMORY(bar);
		    if (PCI_MAP_IS64BITMEM(bar)) {
			if (i == 5) {
			    pciInfo->memBase[i] = 0;
			} else {
			    int bar_hi = pciCfg.bar[i+1];
			    pciInfo->memBase[i] |= (bar_hi << 32);
			    ++i;
			}
		    }
		    pciInfo->size[i] = EFB_REG_SIZE_LOG2;
		}
	    }
	}

	return 0;
}

int
efb_get_mem_info(struct pci_info *pci_info, struct efb_info *pEFB) 
{
	unsigned char reg;

	pEFB->FBPhysAddr = pci_info->memBase[0] & 0xfff00000;
	pEFB->FBMapSize = 0;

	pEFB->MMIOPhysAddr = pci_info->memBase[2] & 0xffff0000;
	pEFB->MMIOMapSize =  1 << pci_info->size[2];

	pEFB->RelocateIO = pci_info->ioBase[1];

	pEFB->ChipSet = pci_info->deviceID;

#ifdef DEBUG
	printf("FBPhysAddr=0x%x FBMapSize=0x%x\n", pEFB->FBPhysAddr, pEFB->FBMapSize);
	printf("MMIOPhysAddr=0x%x MMIOMapSize=0x%x\n", pEFB->MMIOPhysAddr, pEFB->MMIOMapSize);
	printf("RelocateIO=0x%x\n", pEFB->RelocateIO);
#endif

	return 0;
}


int
efb_init_info(struct efb_info *pEFB)
{
	unsigned int v, v2;
	unsigned int status = 0;

        
#if 0
	/* 
	 * first check if the hardware is already initialized.
	 * If not, abort
	 */
	ioctl(pEFB->fd, EFB_GET_STATUS_FLAGS, &status);
	if (!(status & EFB_STATUS_HW_INITIALIZED))
		return -1;
#endif


        v = REGR(CRTC_GEN_CNTL);
	v2 = (v & CRTC_GEN_CNTL__CRTC_PIX_WIDTH_MASK) >> CRTC_GEN_CNTL__CRTC_PIX_WIDTH__SHIFT;
	if (v2 <= 2)
        	pEFB->bitsPerPixel = 8;
	else if (v2 <= 4)
		pEFB->bitsPerPixel = 16;
	else 
		pEFB->bitsPerPixel = 32;


        v = REGR(CRTC_H_TOTAL_DISP);
	v2 = (v & CRTC_H_TOTAL_DISP__CRTC_H_DISP_MASK) >> CRTC_H_TOTAL_DISP__CRTC_H_DISP__SHIFT;
	pEFB->screenWidth = (v2 + 1) * 8;

        v = REGR(CRTC_V_TOTAL_DISP);
	v2 = (v & CRTC_V_TOTAL_DISP__CRTC_V_DISP_MASK) >> CRTC_V_TOTAL_DISP__CRTC_V_DISP__SHIFT;
	pEFB->screenHeight = (v2 + 1);
	pEFB->screenPitch = pEFB->screenWidth * pEFB->bitsPerPixel / 8;


	pEFB->fbLocation = REGR(RADEON_MC_FB_LOCATION);

#ifdef DEBUG
	printf("bpp=%d width=%d height=%d pitch=%d fbLoc=0x%x\n", 
		pEFB->bitsPerPixel, pEFB->screenWidth, pEFB->screenHeight, pEFB->screenPitch, 
		pEFB->fbLocation);
#endif
	return 0;
}

int
efb_map_mem(struct efb_info *pEFB, return_packet *rp, int test)
{
        struct pci_info  pci_info;
        int              pageSize, size;
	int		 fd = pEFB->fd;

        if (efb_get_pci_info(fd, &pci_info) == -1) {
            TraceMessage(VTS_DEBUG, __func__, "get pci info failed\n");
            gfx_vts_set_message(rp, 1, test, "get pci info failed");
            return -1;
        }


        if (efb_get_mem_info(&pci_info, pEFB) == -1) {
            TraceMessage(VTS_DEBUG, __func__, "get mem info failed\n");
            gfx_vts_set_message(rp, 1, test, "get mem info failed");
            return -1;
        }

        /*
         * Map MMIO
         */
        pageSize = getpagesize();
        size = pEFB->MMIOMapSize + (pageSize - 1) & (~(pageSize - 1));

        pEFB->MMIOvaddr = (unsigned char *)mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED,
                                        fd, pEFB->MMIOPhysAddr);

        if (pEFB->MMIOvaddr == MAP_FAILED) {
            TraceMessage(VTS_DEBUG, __func__, "map MMIO failed\n");
            gfx_vts_set_message(rp, 1, test, "map MMIO failed");
            return -1;
        }



	switch (pEFB->ChipSet) {
	case 20825:
	case 20830:
	case 23396:
		pEFB->FBMapSize = REGR(RADEON_CONFIG_MEMSIZE);
		break;
	default:
		pEFB->FBMapSize = REGR(R600_CONFIG_MEMSIZE);
		break;
	}
	

        /*
         * Map framebuffer
         */
        pageSize = getpagesize();
        size = pEFB->FBMapSize + (pageSize - 1) & (~(pageSize - 1));

        pEFB->FBvaddr = (unsigned char *)mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED,
                                        fd, pEFB->FBPhysAddr);

        if (pEFB->FBvaddr == MAP_FAILED) {
            TraceMessage(VTS_DEBUG, __func__, "map framebuffer failed\n");
            gfx_vts_set_message(rp, 1, test, "map framebuffer failed");
            return -1;
        }


	return 0;
}

int
efb_unmap_mem(struct efb_info *pEFB, return_packet *rp, int test)
{
        /*
         * Unmap Frame Buffer
         */

        if (munmap((void *)pEFB->FBvaddr, pEFB->FBMapSize) == -1) {
            TraceMessage(VTS_DEBUG, __func__, "unmap framebuffer failed\n");
            gfx_vts_set_message(rp, 1, test, "unmap framebuffer failed");
            return -1;
        }

        if (munmap((void *)pEFB->MMIOvaddr, pEFB->MMIOMapSize) == -1) {
            TraceMessage(VTS_DEBUG, __func__, "unmap MMIO failed\n");
            gfx_vts_set_message(rp, 1, test, "unmap MMIO failed");
            return -1;
        }

	return 0;
}


#define MASK    RBBM_STATUS__CMDFIFO_AVAIL_MASK

uint32_t
getBPPValue (int bpp)
{
	switch (bpp) {
            case 8:     return (DST_8BPP);
            case 15:    return (DST_15BPP);
            case 16:    return (DST_16BPP);
            case 32:    return (DST_32BPP);
            default:    return (0);
    	}
}

void 
efb_flush_pixel_cache(struct efb_info *pEFB)
{
	int i ;

	// initiate flush
	REGW(RADEON_RB2D_DSTCACHE_CTLSTAT, REGR(RADEON_RB2D_DSTCACHE_CTLSTAT) | 0xf);

	// check for completion but limit looping to 16384 reads
	i = 16384;
	while((REGR(RADEON_RB2D_DSTCACHE_CTLSTAT) & RADEON_RB2D_DC_BUSY) == RADEON_RB2D_DC_BUSY &&
                --i >= 0 ) ;
}

void 
efb_reset_engine (struct efb_info *pEFB)
{
	uint32_t save_genresetcntl, save_clockcntlindex, save_mclkcntl;
	long term_count;

	efb_flush_pixel_cache(pEFB) ;

	save_clockcntlindex = REGR(RADEON_CLOCK_CNTL_INDEX);

	// save GEN_RESET_CNTL register
	save_genresetcntl = REGR(RADEON_DISP_MISC_CNTL);

	// reset by setting bit, add read delay, then clear bit, 
	// add read delay
	REGW(RADEON_DISP_MISC_CNTL, save_genresetcntl |
      	     RADEON_DISP_MISC_CNTL__SOFT_RESET_GRPH_PP);
	REGR(RADEON_DISP_MISC_CNTL);
	REGW(RADEON_DISP_MISC_CNTL, save_genresetcntl &
             ~(RADEON_DISP_MISC_CNTL__SOFT_RESET_GRPH_PP));
	REGR(RADEON_DISP_MISC_CNTL);

	// restore the two registers we changed
	REGW(RADEON_CLOCK_CNTL_INDEX, save_clockcntlindex);
	REGW(RADEON_DISP_MISC_CNTL, save_genresetcntl);

	term_count++;     // for monitoring engine hangs
}

void 
efb_wait_for_fifo(struct efb_info *pEFB, int c)
{
	uint32_t i;
	long limit;

	/* First a short loop, just in case fifo clears out quickly */
	for(limit=100; (REGR(RBBM_STATUS) & MASK) < c && --limit > 0; ) ;

	if((REGR(RBBM_STATUS) & MASK) < c ) {
    		hrtime_t timeout = gethrtime() + (hrtime_t)3000000000;
            	while((REGR(RBBM_STATUS) & MASK) < c && 
					gethrtime() < timeout )
        	    yield();

       	    	if((REGR(RBBM_STATUS) & MASK) < c )
      	    	    efb_reset_engine(pEFB) ;
	}
}

void 
efb_wait_for_idle(struct efb_info *pEFB)
{
	uint32_t i;
	long limit;

	efb_wait_for_fifo(pEFB, 64) ;

	for(limit=10000; (REGR(RBBM_STATUS) & GUI_ACTIVE) && --limit > 0; ) ;

	if( REGR(RBBM_STATUS) & GUI_ACTIVE ) {
    	    hrtime_t timeout = gethrtime() + (hrtime_t)3000000000;
    	    while( (REGR(RBBM_STATUS) & GUI_ACTIVE) && 
				gethrtime() < timeout )
        	yield();

            if( (REGR(RBBM_STATUS) & GUI_ACTIVE) != 0 )
      		efb_reset_engine(pEFB) ;
	}
}