Logo Search packages:      
Sourcecode: i855-crt version File versions  Download package

i855crt.c

/* 
* This is part of the source for i855crt driver
* copyright(c) Merello Andrea 2004
* <andreamrl@tiscali.it>
*
* this is released under the terms of GPL (General Public Licence)
*
* some parts of this driver are taken/based  from/on the 'i810switch' driver
* many thanks to the original author.
*
* some parts of this driver are taken/based  from/on the 855GM-fb driver
* many thanks to the original author.
* 
* plase note that this driver is still experimental
*
* feedbacks are VERY appreciated
*/

#include "i855crt.h"


#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/cursorfont.h>
#include <X11/extensions/Xv.h>
#include <X11/extensions/Xvlib.h>
#define ROUND_UP_TO(x, y)     (((x) + (y) - 1) / (y) * (y))
#define ROUND_DOWN_TO(x, y)   ((x) / (y) * (y))

#define rd(x) *((volatile int *) (mmio + x))
#define wr(x, y) *((volatile int *) (mmio + x )) = (volatile int) y
#define rdov(x) *((volatile int *) (overlaymmio + x))
#define wrov(x, y) *((volatile int *) (overlaymmio + x )) = (volatile int) y
unsigned char *mmio;
char hwcursor;


static void overlay_select_pipe(int p)
{
      Atom AtomPipe;
      XvAdaptorInfo *info;
      XvAttribute *xvattr;
      Display* d= XOpenDisplay(NULL);
      if (d==NULL) 
            fprintf(stderr,"Xfree connection failed, no XV overlay options available\n");
      else
      {     int succ=0;
            AtomPipe=XInternAtom (d, "XV_PIPE", False);
            int i;
            XvQueryAdaptors(d, DefaultRootWindow(d),&i, &info);  
            if(Success!=XvSetPortAttribute(d,info[0].base_id, AtomPipe, p))
            fprintf(stderr,"Failed to set Xv attribute\n");
            else  fprintf(stderr,"Xv overlay routed to pipe %c\n",p? 'B':'A');
            XFlush(d);
      }
            
      
}
static void raw_i855_mirror(struct vmode *mode) /* this is the core of the driver */
{
      
      printf("Creating display mirror on pipe A\n");
      
      int dac = rd(ADPA);
      int pipe = 0;
      int pipea=rd(PIPEACONF);
      int dspb=rd(DSPBCNTR);
      int dspa=rd(DSPACNTR);
      
      
      /*Mouse cursor handling*/
      if(hwcursor)
      {
            int cursoracontrol=rd(CURSOR_A_CONTROL);  
            int cursorbcontrol=rd(CURSOR_B_CONTROL);
            
            cursorbcontrol &= ~(CURSOR_MODE_MASK | CURSOR_GAMMA_ENABLE | CURSOR_MEM_TYPE_LOCAL | CURSOR_PIPE_SELECT | CURSOR_GAMMA_ENABLE );
            
            cursorbcontrol |= CURSOR_ENABLE;
            /*cursorbcontrol &~(1<<CURSOR_PIPE_SELECT_SHIFT);*/
            
            cursoracontrol = cursoracontrol &(CURSOR_MODE_MASK | CURSOR_GAMMA_ENABLE | CURSOR_MEM_TYPE_LOCAL | CURSOR_GAMMA_ENABLE );
            
            
            cursoracontrol &= ~CURSOR_MODE_MASK;      /*these are actually required..     */
                cursoracontrol |= CURSOR_MODE_64_4C_AX;     /*and i dunno why..           */
            
            
            wr(CURSOR_B_CONTROL,cursorbcontrol|cursoracontrol);
      
            int palette;
            palette = rd(CURSOR_A_PALETTE0) & CURSOR_PALETTE_MASK;
            palette |= rd(CURSOR_B_PALETTE0) &~CURSOR_PALETTE_MASK;
            wr(CURSOR_B_PALETTE0,palette);
            
            palette = rd(CURSOR_A_PALETTE1) & CURSOR_PALETTE_MASK;
            palette |= rd(CURSOR_B_PALETTE1) &~CURSOR_PALETTE_MASK;
            wr(CURSOR_B_PALETTE1,palette);
            
            palette = rd(CURSOR_A_PALETTE2) & CURSOR_PALETTE_MASK;
            palette |= rd(CURSOR_B_PALETTE2) &~CURSOR_PALETTE_MASK;
            wr(CURSOR_B_PALETTE2,palette);
            
            palette = rd(CURSOR_A_PALETTE3) & CURSOR_PALETTE_MASK;
            palette |= rd(CURSOR_B_PALETTE3) &~CURSOR_PALETTE_MASK;
            wr(CURSOR_B_PALETTE3,palette);
            
            
            int cursora = rd(CURSOR_A_BASEADDR);
            int cursorb = rd(CURSOR_B_BASEADDR);
            cursorb = cursorb & ~ CURSOR_BASE_MASK;
            cursora = cursora & CURSOR_BASE_MASK;     
            wr(CURSOR_B_BASEADDR,cursorb |cursora);
      }
      else
      {
            int cursor=rd(CURSOR_B_CONTROL)&~(CURSOR_ENABLE|CURSOR_MODE_MASK);
            cursor= cursor &~CURSOR_MODE_DISABLE;
            wr(CURSOR_B_CONTROL,cursor);
            wr(CURSOR_B_BASEADDR,rd(CURSOR_B_BASEADDR)); /*commit*/
            
      }
      
      /* PLL configuration */
      unsigned m1,m2,n,p1,p2,pixclock;
      pixclock=(int)(mode->clock*1000);
      
      calc_pll_params(pixclock,&m1,&m2,&n,&p1,&p2);
            
      pipe=rd(PIPEACONF); /* disable pipe while messing with pll*/
      pipe=pipe&~PIPE_ENABLE;
      wr(PIPEACONF,pipe);
      
      int pll=rd(DPLL_A);     
      wr(DPLL_A,pll &~ DPLL_VCO_ENABLE); /* disable PLL */
      
      pll=pll & ~ DPLL_RATE_SELECT_MASK;
      pll=pll & ~ DPLL_REFERENCE_SELECT_MASK;
      pll|= DPLL_RATE_SELECT_FP0; 
      pll|= DPLL_REFERENCE_DEFAULT; 
      pll=pll & ~ DPLL_P1_FORCE_DIV2; 
      pll=pll & ~ (DPLL_P2_MASK << DPLL_P2_SHIFT);
      pll=pll & ~ (DPLL_P1_MASK << DPLL_P1_SHIFT);
      pll|= (p1<<DPLL_P1_SHIFT);
      pll|= (p2<<DPLL_P2_SHIFT); 
      pll=pll | DPLL_VGA_MODE_DISABLE; 
      pll=pll &~ DPLL_SYNCLOCK_ENABLE; 
      pll=pll &~ DPLL_2X_CLOCK_ENABLE; 
      /*pll=pll &~ DPLL_VCO_ENABLE;*/
      /* pll=0x90829001 (from win drv)*/
      wr(DPLL_A,pll);

      unsigned fp=rd(FPA0);
      fp = fp & ~(FP_DIVISOR_MASK<<FP_N_DIVISOR_SHIFT); 
      fp = fp & ~(FP_DIVISOR_MASK<<FP_M1_DIVISOR_SHIFT);
      fp = fp & ~(FP_DIVISOR_MASK<<FP_M2_DIVISOR_SHIFT);
      fp |= (n<<FP_N_DIVISOR_SHIFT);
      fp |= (m1<<FP_M1_DIVISOR_SHIFT);
      fp |= (m2<<FP_M2_DIVISOR_SHIFT);
      wr(FPA0,fp);
      
      wr(DPLL_A,pll | DPLL_VCO_ENABLE);/* enable PLL */
      
      
      /*Setting up planes*/   
      dspb=dspb &~DSPCNTR_PIPE;
      dspb=dspb &~DSPCNTR_RESERVED_MASK;
      dspa=dspa & DSPCNTR_RESERVED_MASK;
            
      wr(DSPACNTR,dspb |dspa);
      
      int dspabase=rd(DSPABASE);
      int dspbbase=rd(DSPBBASE);
      dspbbase=dspbbase & ~DSPBASE_RESERVED_MASK;
      dspabase=dspabase & DSPBASE_RESERVED_MASK;
      int stride = rd(DSPBSTRIDE);
      wr(DSPASTRIDE,stride); 
      wr(DSPABASE,dspabase|dspbbase); 
      
                        
      /* Configuring pipe */  
            /* HORIZONTAL REFRESH REGISTERS */
      unsigned xres=mode->hactive;
      unsigned hsyncstart=mode->hsyncstart;
      unsigned hsyncend=mode->hsyncend;
      unsigned htotal=mode->htotal;
      unsigned htot= xres; 
      htot|= ((htotal)<<16);
      htot|= rd(HTOTAL_A) & TOTAL_RESERVED_MASK;
      wr(HTOTAL_A,htot);
      
      unsigned hblank= htot &~(1<<11);
      hblank= hblank &~BLANK_RESERVED_MASK;
      hblank|= rd(HBLANK_A) & BLANK_RESERVED_MASK;
      wr(HBLANK_A,hblank);
      
      unsigned hsync= hsyncstart;
      hsync=hsync | (rd(HSYNC_A) & SYNC_RESERVED_MASK);
      hsync |= ((hsyncend)<<16);
      wr(HSYNC_A,hsync);
      
            /* END OF HORIZONTAL REFRESH REGISTERS */
      
            /* VERTICAL REFRESH REGISTERS - SHOULD BE OK*/
      unsigned yres=mode->vactive;
      unsigned vtotal=mode->vtotal;
      unsigned vsyncstart=mode->vsyncstart;
      unsigned vsyncend=mode->vsyncend;
            
      unsigned vtot = yres;
      vtot |= ((vtotal) << 16); 
      vtot |= rd(VTOTAL_A) & TOTAL_RESERVED_MASK;
      wr(VTOTAL_A,vtot);
      
      unsigned vblank= vtot &~(1<<11);
      vblank = vblank &~BLANK_RESERVED_MASK;
      vblank|= rd(VBLANK_A) & BLANK_RESERVED_MASK;
      wr(VBLANK_A,vblank);
      
      unsigned vsync= vsyncstart;
      vsync=vsync | (rd(VSYNC_A) & SYNC_RESERVED_MASK);
      vsync |= ((vsyncend)<<16);
      wr(VSYNC_A,vsync);
            /* END OF VERTICAL REFRESH REGISTERS */
      
      wr(BCLRPAT_A,rd(BCLRPAT_B));
      wr(PIPEASRC,rd(PIPEBSRC));
                              
      pipea=pipea & PIPEARESERVED_MASK;
      pipe = 0x80000000;
      pipe = pipe & ~PIPEARESERVED_MASK;
      wr(PIPEACONF,pipea | pipe);
      fprintf(stderr,"Enabling CRT and connecting to pipe A\n");
      /* Configuring DAC */
      int adpa=0x80000000 | (0<<30);
      dac=dac & DAC_RESERVED_MASK;
      adpa=adpa&~DAC_RESERVED_MASK;
      
      wr(ADPA, dac|adpa);
                  
}
      
/*this tries to find know video card in lspci output */
char *i810_chip(char **buff_ptr, int *len_ptr, FILE *pci_f) 
{
      int i;
      char *p;

      while (getline(buff_ptr, len_ptr, pci_f) > 0) 
      {
            i = 
            (p = strstr(*buff_ptr, I810STR)) != NULL ||
            (p = strstr(*buff_ptr, I810ESTR)) != NULL ||
            (p = strstr(*buff_ptr, I810_DC100STR_1)) != NULL ||
            (p = strstr(*buff_ptr, I810_DC100STR_2)) != NULL ||
            (p = strstr(*buff_ptr, I810_IGSTR)) != NULL ||
            (p = strstr(*buff_ptr, I810_CFCSTR)) != NULL;
            (p = strstr(*buff_ptr, I830STR)) != NULL ||
            (p = strstr(*buff_ptr, I845STR)) != NULL ||
            (p = strstr(*buff_ptr, I865STR)) != NULL ;
      
            if(i)
            {
                  fprintf(stderr,"This driver is untested with your videocard !\n");  
                  return p;
            }
            
            i = (p = strstr(*buff_ptr, I855STR)) != NULL;
            if (i)      return p;
            
      }
      return NULL;
}

/*this extracts the iomem address of the specified device */
unsigned long i810_addr(char **buff_ptr, int *len_ptr, FILE *pci_f)
{
      char *p;

      while (getline(buff_ptr, len_ptr, pci_f) > 0)
            if (strstr(*buff_ptr, NONPRSTR) != NULL) {
                  p = strstr(*buff_ptr, MEMSTR);
                  if (p != NULL)
                        return strtoul(p+sizeof(MEMSTR), NULL, 16);
            }
      return 0;
}

int print_usage ()
{
      fprintf(stderr, "usage:\ni855crt on [swcursor] [overlaycrt] <mode_name>\n");
      fprintf(stderr, "i855crt off\n");
      fprintf(stderr, "i855crt on rawpipe\n");

      exit (1);
}
/* Split the M parameter into M1 and M2. */
static int splitm(unsigned int m, unsigned int *retm1, unsigned int *retm2)
{
      int m1, m2;

      m1 = (m - 2 - (MIN_M2 + MAX_M2) / 2) / 5 - 2;
      if (m1 < MIN_M1)
            m1 = MIN_M1;
      if (m1 > MAX_M1)
            m1 = MAX_M1;
      m2 = m - 5 * (m1 + 2) - 2;
      if (m2 < MIN_M2 || m2 > MAX_M2 || m2 >= m1) {
            return 1;
      } else {
            *retm1 = (unsigned int)m1;
            *retm2 = (unsigned int)m2;
            return 0;
      }
}

/* Split the P parameter into P1 and P2. */
static int splitp(unsigned int p, unsigned int *retp1, unsigned int *retp2)
{
      int p1, p2;

      if (p % 4 == 0)
            p2 = 1;
      else
            p2 = 0;
      p1 = (p / (1 << (p2 + 1))) - 2;
      if (p % 4 == 0 && p1 < MIN_P1) {
            p2 = 0;
            p1 = (p / (1 << (p2 + 1))) - 2;
      }
      if (p1  < MIN_P1 || p1 > MAX_P1 || (p1 + 2) * (1 << (p2 + 1)) != p) {
            return 1;
      } else {
            *retp1 = (unsigned int)p1;
            *retp2 = (unsigned int)p2;
            return 0;
      }
}
int calc_pll_params(int clock, unsigned *retm1, unsigned *retm2, unsigned *retn, unsigned *retp1,     unsigned *retp2)
{
      unsigned m1, m2, n, p1, p2, n1;
      unsigned f_vco, p, p_best = 0, m, f_out;
      unsigned err_max, err_target, err_best = 10000000;
      unsigned n_best = 0, m_best = 0, f_best, f_err;
      unsigned p_min, p_max, p_inc, div_min, div_max;

      /* Accept 0.5% difference, but aim for 0.1% */
      err_max = 5 * clock / 1000;
      err_target = clock / 1000;

      

      div_max = MAX_VCO_FREQ / clock;
      div_min = ROUND_UP_TO(MIN_VCO_FREQ, clock) / clock;

      if (clock <= P_TRANSITION_CLOCK)
            p_inc = 4;
      else
            p_inc = 2;
      p_min = ROUND_UP_TO(div_min, p_inc);
      p_max = ROUND_DOWN_TO(div_max, p_inc);
      if (p_min < MIN_P)
            p_min = 4;
      if (p_max > MAX_P)
            p_max = 128;


      p = p_min;
      do {
            if (splitp(p, &p1, &p2)) {
                  
                  p += p_inc;
                  continue;
            }
            n = MIN_N;
            f_vco = clock * p;

            do {
                  m = ROUND_UP_TO(f_vco * n, PLL_REFCLK) / PLL_REFCLK;
                  if (m < MIN_M)
                        m = MIN_M;
                  if (m > MAX_M)
                        m = MAX_M;
                  f_out = CALC_VCLOCK3(m, n, p);
                  if (splitm(m, &m1, &m2)) {
                        
                        n++;
                        continue;
                  }
                  if (clock > f_out)
                        f_err = clock - f_out;
                  else
                        f_err = f_out - clock;
                  
                  if (f_err < err_best) {
                        m_best = m;
                        n_best = n;
                        p_best = p;
                        f_best = f_out;
                        err_best = f_err;
                  }
                  n++;
            } while ((n <= MAX_N) && (f_out >= clock));
            p += p_inc;
      } while ((p <= p_max));

      if (!m_best) {
            fprintf(stderr,"cannot find parameters for clock %d\n", clock);
            return 1;
      }
      m = m_best;
      n = n_best;
      p = p_best;
      splitm(m, &m1, &m2);
      splitp(p, &p1, &p2);
      n1 = n - 2;
      
      *retm1 = m1;
      *retm2 = m2;
      *retn = n1;
      *retp1 = p1;
      *retp2 = p2;
      
      
      return 0;
}/*
int _calc_pll_params(int clk, unsigned *m1, unsigned *m2, unsigned *n, unsigned *p1,      unsigned *p2)
{
      
      *m1=21;
      *m2=9;
      *n=2;
      *p2=1;
      *p1=2;
      
      fprintf(stderr,"%d,%d\n", CALC_VCLOCK(*m1, *m2, *n, *p1, *p2),clk);
      return 0;
}
*/

int main (int argc, char *argv[])
{
      int mem;
      unsigned long addr;
      int i, crt,len;
      FILE *pci_f;
      char *buff = NULL;
      char lspcistr[] = CMD_LSPCI " -v -d xxxx:xxxx";
      char *chip;
      short overlay=1;
      struct vmode mode;
      printf("\nIntel 855GM CRT out driver V%s\n",VERSION);
      printf("Copyright (C) Merello Andrea 2004\n\n");
      putenv("PATH=/sbin:/usr/sbin:/bin:/usr/bin");
      hwcursor=1;
      fetch:
      if (argc <2) print_usage();
      if (strcmp(argv[1],"swcursor")==0)
      {
            argc--;
            hwcursor=0;
            argv++;
            goto fetch;
      }
      if (strcmp(argv[1],"overlaycrt") ==0)
      {
            argc--;
            overlay=0;
            argv++;
            goto fetch;
      }
      if (strcmp(argv[1],"off")==0)
            crt=0;
      else if(strcmp(argv[1],"on")==0)
            {
                  if(argc<3) print_usage();
                  else if(0==strcmp(argv[2],"rawpipe"))
                        crt=2;
                  else
                  { 
                        if(!getVMode(argv[2],&mode))return -1;
                        crt=1;
                  }
            }
      
      else print_usage();     
      pci_f = popen(CMD_LSPCI " -n", "r");
      if (!pci_f) 
      {
            fprintf(stderr, "Something is wrong with lspci.\n");
            exit(1);
      }
      chip = i810_chip(&buff, &len, pci_f);
      if (chip == NULL) 
      {
            fprintf(stderr, "No know videocard has been found.\n");
            exit(1);
      }
      pclose(pci_f);

      {
            char *p = strstr(lspcistr, "xxxx:xxxx");
            if (p == 0) 
            {
                  fprintf(stderr, "CMD_LSPCI is wrong.\n");
                  exit(1);
            }
            memcpy(p, chip, 9);
      }

      pci_f = popen(lspcistr, "r");
      if (!pci_f) 
      {
            fprintf(stderr, "Something is wrong with lspci.\n");
            exit(1);
      }
      addr = i810_addr(&buff, &len, pci_f);
      if (addr == 0) 
      {
            fprintf(stderr, "Something is wrong with lspci.\n");
            exit(1);
      }
      pclose(pci_f);

      
      mem = open("/dev/mem", O_RDWR);
      
      if (mem == -1) 
      {
            i = errno;
            perror("/dev/mem");
            if (i == EACCES && geteuid() != 0)
                  fprintf(stderr, "Must have access to `/dev/mem'.\n");
            
            exit(-1);
      }

      
      mmio = mmap(NULL, 512 * 1024,  PROT_WRITE | PROT_READ,MAP_SHARED, mem, addr);
      if ((int)mmio==-1) 
      {
            close(mem);
            exit(-1);
      }
      
      int temp;
      
      switch (crt)
      { 
            
            case 0:
                  printf("Disabling CRT display...\n");
                  temp=rd(ADPA);
                  temp = (temp & ~0x80000000 & ~(1<<30)) | 0xc00;
                  wr(ADPA,temp);
                  overlay_select_pipe(1);
            break;
            
            case 1: raw_i855_mirror(&mode);
                  overlay_select_pipe(overlay);
            break;
            
            case 2:
                  printf("Enabling CRT and connecting to pipe B\n");
                  temp=rd(ADPA);
                  temp = (temp | 0x80000000 | (1<<30) )& ~0xc00;
                  wr(ADPA,temp);
                  overlay_select_pipe(1);
            break;
      }           
      
      close(mem);
      munmap(mmio, 512 * 1024);
      
      return 0;
}


Generated by  Doxygen 1.6.0   Back to index