Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  matroxfb_g450.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/*
 *
 * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450.
 *
 * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
 *
 * Portions Copyright (c) 2001 Matrox Graphics Inc.
 *
 * Version: 1.65 2002/08/14
 *
 * See matroxfb_base.c for contributors.
 *
 */


#include <linux/export.h>

#include "matroxfb_base.h"
#include "matroxfb_misc.h"
#include "matroxfb_DAC1064.h"
#include "g450_pll.h"
#include <linux/matroxfb.h>
#include <asm/div64.h>

#include "matroxfb_g450.h"

/* Definition of the various controls */
struct mctl {
 struct v4l2_queryctrl desc;
 size_t control;
};

#define BLMIN 0xF3
#define WLMAX 0x3FF

static const struct mctl g450_controls[] =
{ { { V4L2_CID_BRIGHTNESS, V4L2_CTRL_TYPE_INTEGER,
   "brightness",
   0, WLMAX-BLMIN, 1, 370-BLMIN,
   0,
 }, offsetof(struct matrox_fb_info, altout.tvo_params.brightness) },
 { { V4L2_CID_CONTRAST, V4L2_CTRL_TYPE_INTEGER,
   "contrast",
   0, 1023, 1, 127,
   0,
 }, offsetof(struct matrox_fb_info, altout.tvo_params.contrast) },
 { { V4L2_CID_SATURATION, V4L2_CTRL_TYPE_INTEGER,
   "saturation",
   0, 255, 1, 165,
   0,
 }, offsetof(struct matrox_fb_info, altout.tvo_params.saturation) },
 { { V4L2_CID_HUE, V4L2_CTRL_TYPE_INTEGER,
   "hue",
   0, 255, 1, 0,
   0,
 }, offsetof(struct matrox_fb_info, altout.tvo_params.hue) },
 { { MATROXFB_CID_TESTOUT, V4L2_CTRL_TYPE_BOOLEAN,
   "test output",
   0, 1, 1, 0,
   0,
 }, offsetof(struct matrox_fb_info, altout.tvo_params.testout) },
};

#define G450CTRLS ARRAY_SIZE(g450_controls)

/* Return: positive number: id found
           -EINVAL:         id not found, return failure
   -ENOENT:         id not found, create fake disabled control */

static int get_ctrl_id(__u32 v4l2_id) {
 int i;

 for (i = 0; i < G450CTRLS; i++) {
  if (v4l2_id < g450_controls[i].desc.id) {
   if (g450_controls[i].desc.id == 0x08000000) {
    return -EINVAL;
   }
   return -ENOENT;
  }
  if (v4l2_id == g450_controls[i].desc.id) {
   return i;
  }
 }
 return -EINVAL;
}

static inline int *get_ctrl_ptr(struct matrox_fb_info *minfo, unsigned int idx)
{
 return (int*)((char*)minfo + g450_controls[idx].control);
}

static void tvo_fill_defaults(struct matrox_fb_info *minfo)
{
 unsigned int i;

 for (i = 0; i < G450CTRLS; i++) {
  *get_ctrl_ptr(minfo, i) = g450_controls[i].desc.default_value;
 }
}

static int cve2_get_reg(struct matrox_fb_info *minfo, int reg)
{
 unsigned long flags;
 int val;

 matroxfb_DAC_lock_irqsave(flags);
 matroxfb_DAC_out(minfo, 0x87, reg);
 val = matroxfb_DAC_in(minfo, 0x88);
 matroxfb_DAC_unlock_irqrestore(flags);
 return val;
}

static void cve2_set_reg(struct matrox_fb_info *minfo, int reg, int val)
{
 unsigned long flags;

 matroxfb_DAC_lock_irqsave(flags);
 matroxfb_DAC_out(minfo, 0x87, reg);
 matroxfb_DAC_out(minfo, 0x88, val);
 matroxfb_DAC_unlock_irqrestore(flags);
}

static void cve2_set_reg10(struct matrox_fb_info *minfo, int reg, int val)
{
 unsigned long flags;

 matroxfb_DAC_lock_irqsave(flags);
 matroxfb_DAC_out(minfo, 0x87, reg);
 matroxfb_DAC_out(minfo, 0x88, val >> 2);
 matroxfb_DAC_out(minfo, 0x87, reg + 1);
 matroxfb_DAC_out(minfo, 0x88, val & 3);
 matroxfb_DAC_unlock_irqrestore(flags);
}

static void g450_compute_bwlevel(const struct matrox_fb_info *minfo, int *bl,
     int *wl)
{
 const int b = minfo->altout.tvo_params.brightness + BLMIN;
 const int c = minfo->altout.tvo_params.contrast;

 *bl = max(b - c, BLMIN);
 *wl = min(b + c, WLMAX);
}

static int g450_query_ctrl(void* md, struct v4l2_queryctrl *p) {
 int i;

 i = get_ctrl_id(p->id);
 if (i >= 0) {
  *p = g450_controls[i].desc;
  return 0;
 }
 if (i == -ENOENT) {
  static const struct v4l2_queryctrl disctrl =
   { .flags = V4L2_CTRL_FLAG_DISABLED };

  i = p->id;
  *p = disctrl;
  p->id = i;
  sprintf(p->name, "Ctrl #%08X", i);
  return 0;
 }
 return -EINVAL;
}

static int g450_set_ctrl(void* md, struct v4l2_control *p) {
 int i;
 struct matrox_fb_info *minfo = md;

 i = get_ctrl_id(p->id);
 if (i < 0) return -EINVAL;

 /*
 * Check if changed.
 */

 if (p->value == *get_ctrl_ptr(minfo, i)) return 0;

 /*
 * Check limits.
 */

 if (p->value > g450_controls[i].desc.maximum) return -EINVAL;
 if (p->value < g450_controls[i].desc.minimum) return -EINVAL;

 /*
 * Store new value.
 */

 *get_ctrl_ptr(minfo, i) = p->value;

 switch (p->id) {
  case V4L2_CID_BRIGHTNESS:
  case V4L2_CID_CONTRAST:
   {
    int blacklevel, whitelevel;
    g450_compute_bwlevel(minfo, &blacklevel, &whitelevel);
    cve2_set_reg10(minfo, 0x0e, blacklevel);
    cve2_set_reg10(minfo, 0x1e, whitelevel);
   }
   break;
  case V4L2_CID_SATURATION:
   cve2_set_reg(minfo, 0x20, p->value);
   cve2_set_reg(minfo, 0x22, p->value);
   break;
  case V4L2_CID_HUE:
   cve2_set_reg(minfo, 0x25, p->value);
   break;
  case MATROXFB_CID_TESTOUT:
   {
    unsigned char val = cve2_get_reg(minfo, 0x05);
    if (p->value) val |=  0x02;
    else          val &= ~0x02;
    cve2_set_reg(minfo, 0x05, val);
   }
   break;
 }


 return 0;
}

static int g450_get_ctrl(void* md, struct v4l2_control *p) {
 int i;
 struct matrox_fb_info *minfo = md;

 i = get_ctrl_id(p->id);
 if (i < 0) return -EINVAL;
 p->value = *get_ctrl_ptr(minfo, i);
 return 0;
}

struct output_desc {
 unsigned int h_vis;
 unsigned int h_f_porch;
 unsigned int h_sync;
 unsigned int h_b_porch;
 unsigned long long int chromasc;
 unsigned int burst;
 unsigned int v_total;
};

static void computeRegs(struct matrox_fb_info *minfo, struct mavenregs *r,
   struct my_timming *mt, const struct output_desc *outd)
{
 u_int32_t chromasc;
 u_int32_t hlen;
 u_int32_t hsl;
 u_int32_t hbp;
 u_int32_t hfp;
 u_int32_t hvis;
 unsigned int pixclock;
 unsigned long long piic;
 int mnp;
 int over;

 r->regs[0x80] = 0x03; /* | 0x40 for SCART */

 hvis = ((mt->HDisplay << 1) + 3) & ~3;

 if (hvis >= 2048) {
  hvis = 2044;
 }

 piic = 1000000000ULL * hvis;
 do_div(piic, outd->h_vis);

 dprintk(KERN_DEBUG "Want %u kHz pixclock\n", (unsigned int)piic);

 mnp = matroxfb_g450_setclk(minfo, piic, M_VIDEO_PLL);

 mt->mnp = mnp;
 mt->pixclock = g450_mnp2f(minfo, mnp);

 dprintk(KERN_DEBUG "MNP=%08X\n", mnp);

 pixclock = 1000000000U / mt->pixclock;

 dprintk(KERN_DEBUG "Got %u ps pixclock\n", pixclock);

 piic = outd->chromasc;
 do_div(piic, mt->pixclock);
 chromasc = piic;

 dprintk(KERN_DEBUG "Chroma is %08X\n", chromasc);

 r->regs[0] = piic >> 24;
 r->regs[1] = piic >> 16;
 r->regs[2] = piic >>  8;
 r->regs[3] = piic >>  0;
 hbp = (((outd->h_b_porch + pixclock) / pixclock)) & ~1;
 hfp = (((outd->h_f_porch + pixclock) / pixclock)) & ~1;
 hsl = (((outd->h_sync + pixclock) / pixclock)) & ~1;
 hlen = hvis + hfp + hsl + hbp;
 over = hlen & 0x0F;

 dprintk(KERN_DEBUG "WL: vis=%u, hf=%u, hs=%u, hb=%u, total=%u\n", hvis, hfp, hsl, hbp, hlen);

 if (over) {
  hfp -= over;
  hlen -= over;
  if (over <= 2) {
  } else if (over < 10) {
   hfp += 4;
   hlen += 4;
  } else {
   hfp += 16;
   hlen += 16;
  }
 }

 /* maybe cve2 has requirement 800 < hlen < 1184 */
 r->regs[0x08] = hsl;
 r->regs[0x09] = (outd->burst + pixclock - 1) / pixclock; /* burst length */
 r->regs[0x0A] = hbp;
 r->regs[0x2C] = hfp;
 r->regs[0x31] = hvis / 8;
 r->regs[0x32] = hvis & 7;

 dprintk(KERN_DEBUG "PG: vis=%04X, hf=%02X, hs=%02X, hb=%02X, total=%04X\n", hvis, hfp, hsl, hbp, hlen);

 r->regs[0x84] = 1; /* x sync point */
 r->regs[0x85] = 0;
 hvis = hvis >> 1;
 hlen = hlen >> 1;

 dprintk(KERN_DEBUG "hlen=%u hvis=%u\n", hlen, hvis);

 mt->interlaced = 1;

 mt->HDisplay = hvis & ~7;
 mt->HSyncStart = mt->HDisplay + 8;
 mt->HSyncEnd = (hlen & ~7) - 8;
 mt->HTotal = hlen;

 {
  int upper;
  unsigned int vtotal;
  unsigned int vsyncend;
  unsigned int vdisplay;

  vtotal = mt->VTotal;
  vsyncend = mt->VSyncEnd;
  vdisplay = mt->VDisplay;
  if (vtotal < outd->v_total) {
   unsigned int yovr = outd->v_total - vtotal;

   vsyncend += yovr >> 1;
  } else if (vtotal > outd->v_total) {
   vdisplay = outd->v_total - 4;
   vsyncend = outd->v_total;
  }
  upper = (outd->v_total - vsyncend) >> 1; /* in field lines */
  r->regs[0x17] = outd->v_total / 4;
  r->regs[0x18] = outd->v_total & 3;
  r->regs[0x33] = upper - 1; /* upper blanking */
  r->regs[0x82] = upper;  /* y sync point */
  r->regs[0x83] = upper >> 8;

  mt->VDisplay = vdisplay;
  mt->VSyncStart = outd->v_total - 2;
  mt->VSyncEnd = outd->v_total;
  mt->VTotal = outd->v_total;
 }
}

static void cve2_init_TVdata(int norm, struct mavenregs* data, const struct output_desc** outd) {
 static const struct output_desc paloutd = {
  .h_vis    = 52148148, // ps
  .h_f_porch =  1407407, // ps
  .h_sync    =  4666667, // ps
  .h_b_porch =  5777778, // ps
  .chromasc  = 19042247534182ULL, // 4433618.750 Hz
  .burst     =  2518518, // ps
  .v_total   =      625,
 };
 static const struct output_desc ntscoutd = {
  .h_vis     = 52888889, // ps
  .h_f_porch =  1333333, // ps
  .h_sync    =  4666667, // ps
  .h_b_porch =  4666667, // ps
  .chromasc  = 15374030659475ULL, // 3579545.454 Hz
  .burst     =  2418418, // ps
  .v_total   =      525, // lines
 };

 static const struct mavenregs palregs = { {
  0x2A, 0x09, 0x8A, 0xCB, /* 00: chroma subcarrier */
  0x00,
  0x00, /* test */
  0xF9, /* modified by code (F9 written...) */
  0x00, /* ? not written */
  0x7E, /* 08 */
  0x44, /* 09 */
  0x9C, /* 0A */
  0x2E, /* 0B */
  0x21, /* 0C */
  0x00, /* ? not written */
// 0x3F, 0x03, /* 0E-0F */
  0x3C, 0x03,
  0x3C, 0x03, /* 10-11 */
  0x1A, /* 12 */
  0x2A, /* 13 */
  0x1C, 0x3D, 0x14, /* 14-16 */
  0x9C, 0x01, /* 17-18 */
  0x00, /* 19 */
  0xFE, /* 1A */
  0x7E, /* 1B */
  0x60, /* 1C */
  0x05, /* 1D */
// 0x89, 0x03, /* 1E-1F */
  0xAD, 0x03,
// 0x72, /* 20 */
  0xA5,
  0x07, /* 21 */
// 0x72, /* 22 */
  0xA5,
  0x00, /* 23 */
  0x00, /* 24 */
  0x00, /* 25 */
  0x08, /* 26 */
  0x04, /* 27 */
  0x00, /* 28 */
  0x1A, /* 29 */
  0x55, 0x01, /* 2A-2B */
  0x26, /* 2C */
  0x07, 0x7E, /* 2D-2E */
  0x02, 0x54, /* 2F-30 */
  0xB0, 0x00, /* 31-32 */
  0x14, /* 33 */
  0x49, /* 34 */
  0x00, /* 35 written multiple times */
  0x00, /* 36 not written */
  0xA3, /* 37 */
  0xC8, /* 38 */
  0x22, /* 39 */
  0x02, /* 3A */
  0x22, /* 3B */
  0x3F, 0x03, /* 3C-3D */
  0x00, /* 3E written multiple times */
  0x00, /* 3F not written */
 } };
 static const struct mavenregs ntscregs = { {
  0x21, 0xF0, 0x7C, 0x1F, /* 00: chroma subcarrier */
  0x00,
  0x00, /* test */
  0xF9, /* modified by code (F9 written...) */
  0x00, /* ? not written */
  0x7E, /* 08 */
  0x43, /* 09 */
  0x7E, /* 0A */
  0x3D, /* 0B */
  0x00, /* 0C */
  0x00, /* ? not written */
  0x41, 0x00, /* 0E-0F */
  0x3C, 0x00, /* 10-11 */
  0x17, /* 12 */
  0x21, /* 13 */
  0x1B, 0x1B, 0x24, /* 14-16 */
  0x83, 0x01, /* 17-18 */
  0x00, /* 19 */
  0x0F, /* 1A */
  0x0F, /* 1B */
  0x60, /* 1C */
  0x05, /* 1D */
  //0x89, 0x02, /* 1E-1F */
  0xC0, 0x02, /* 1E-1F */
  //0x5F, /* 20 */
  0x9C, /* 20 */
  0x04, /* 21 */
  //0x5F, /* 22 */
  0x9C, /* 22 */
  0x01, /* 23 */
  0x02, /* 24 */
  0x00, /* 25 */
  0x0A, /* 26 */
  0x05, /* 27 */
  0x00, /* 28 */
  0x10, /* 29 */
  0xFF, 0x03, /* 2A-2B */
  0x24, /* 2C */
  0x0F, 0x78, /* 2D-2E */
  0x00, 0x00, /* 2F-30 */
  0xB2, 0x04, /* 31-32 */
  0x14, /* 33 */
  0x02, /* 34 */
  0x00, /* 35 written multiple times */
  0x00, /* 36 not written */
  0xA3, /* 37 */
  0xC8, /* 38 */
  0x15, /* 39 */
  0x05, /* 3A */
  0x3B, /* 3B */
  0x3C, 0x00, /* 3C-3D */
  0x00, /* 3E written multiple times */
  0x00, /* never written */
 } };

 if (norm == MATROXFB_OUTPUT_MODE_PAL) {
  *data = palregs;
  *outd = &paloutd;
 } else {
    *data = ntscregs;
  *outd = &ntscoutd;
 }
  return;
}

#define LR(x) cve2_set_reg(minfo, (x), m->regs[(x)])
static void cve2_init_TV(struct matrox_fb_info *minfo,
    const struct mavenregs *m)
{
 int i;

 LR(0x80);
 LR(0x82); LR(0x83);
 LR(0x84); LR(0x85);

 cve2_set_reg(minfo, 0x3E, 0x01);

 for (i = 0; i < 0x3E; i++) {
  LR(i);
 }
 cve2_set_reg(minfo, 0x3E, 0x00);
}

static int matroxfb_g450_compute(void* md, struct my_timming* mt) {
 struct matrox_fb_info *minfo = md;

 dprintk(KERN_DEBUG "Computing, mode=%u\n", minfo->outputs[1].mode);

 if (mt->crtc == MATROXFB_SRC_CRTC2 &&
     minfo->outputs[1].mode != MATROXFB_OUTPUT_MODE_MONITOR) {
  const struct output_desc* outd;

  cve2_init_TVdata(minfo->outputs[1].mode, &minfo->hw.maven, &outd);
  {
   int blacklevel, whitelevel;
   g450_compute_bwlevel(minfo, &blacklevel, &whitelevel);
   minfo->hw.maven.regs[0x0E] = blacklevel >> 2;
   minfo->hw.maven.regs[0x0F] = blacklevel & 3;
   minfo->hw.maven.regs[0x1E] = whitelevel >> 2;
   minfo->hw.maven.regs[0x1F] = whitelevel & 3;

   minfo->hw.maven.regs[0x20] =
   minfo->hw.maven.regs[0x22] = minfo->altout.tvo_params.saturation;

   minfo->hw.maven.regs[0x25] = minfo->altout.tvo_params.hue;

   if (minfo->altout.tvo_params.testout) {
    minfo->hw.maven.regs[0x05] |= 0x02;
   }
  }
  computeRegs(minfo, &minfo->hw.maven, mt, outd);
 } else if (mt->mnp < 0) {
  /* We must program clocks before CRTC2, otherwise interlaced mode
   startup may fail */

  mt->mnp = matroxfb_g450_setclk(minfo, mt->pixclock, (mt->crtc == MATROXFB_SRC_CRTC1) ? M_PIXEL_PLL_C : M_VIDEO_PLL);
  mt->pixclock = g450_mnp2f(minfo, mt->mnp);
 }
 dprintk(KERN_DEBUG "Pixclock = %u\n", mt->pixclock);
 return 0;
}

static int matroxfb_g450_program(void* md) {
 struct matrox_fb_info *minfo = md;

 if (minfo->outputs[1].mode != MATROXFB_OUTPUT_MODE_MONITOR) {
  cve2_init_TV(minfo, &minfo->hw.maven);
 }
 return 0;
}

static int matroxfb_g450_verify_mode(void* md, u_int32_t arg) {
 switch (arg) {
  case MATROXFB_OUTPUT_MODE_PAL:
  case MATROXFB_OUTPUT_MODE_NTSC:
  case MATROXFB_OUTPUT_MODE_MONITOR:
   return 0;
 }
 return -EINVAL;
}

static int g450_dvi_compute(void* md, struct my_timming* mt) {
 struct matrox_fb_info *minfo = md;

 if (mt->mnp < 0) {
  mt->mnp = matroxfb_g450_setclk(minfo, mt->pixclock, (mt->crtc == MATROXFB_SRC_CRTC1) ? M_PIXEL_PLL_C : M_VIDEO_PLL);
  mt->pixclock = g450_mnp2f(minfo, mt->mnp);
 }
 return 0;
}

static struct matrox_altout matroxfb_g450_altout = {
 .name  = "Secondary output",
 .compute = matroxfb_g450_compute,
 .program = matroxfb_g450_program,
 .verifymode = matroxfb_g450_verify_mode,
 .getqueryctrl = g450_query_ctrl,
 .getctrl = g450_get_ctrl,
 .setctrl = g450_set_ctrl,
};

static struct matrox_altout matroxfb_g450_dvi = {
 .name  = "DVI output",
 .compute = g450_dvi_compute,
};

void matroxfb_g450_connect(struct matrox_fb_info *minfo)
{
 if (minfo->devflags.g450dac) {
  down_write(&minfo->altout.lock);
  tvo_fill_defaults(minfo);
  minfo->outputs[1].src = minfo->outputs[1].default_src;
  minfo->outputs[1].data = minfo;
  minfo->outputs[1].output = &matroxfb_g450_altout;
  minfo->outputs[1].mode = MATROXFB_OUTPUT_MODE_MONITOR;
  minfo->outputs[2].src = minfo->outputs[2].default_src;
  minfo->outputs[2].data = minfo;
  minfo->outputs[2].output = &matroxfb_g450_dvi;
  minfo->outputs[2].mode = MATROXFB_OUTPUT_MODE_MONITOR;
  up_write(&minfo->altout.lock);
 }
}

void matroxfb_g450_shutdown(struct matrox_fb_info *minfo)
{
 if (minfo->devflags.g450dac) {
  down_write(&minfo->altout.lock);
  minfo->outputs[1].src = MATROXFB_SRC_NONE;
  minfo->outputs[1].output = NULL;
  minfo->outputs[1].data = NULL;
  minfo->outputs[1].mode = MATROXFB_OUTPUT_MODE_MONITOR;
  minfo->outputs[2].src = MATROXFB_SRC_NONE;
  minfo->outputs[2].output = NULL;
  minfo->outputs[2].data = NULL;
  minfo->outputs[2].mode = MATROXFB_OUTPUT_MODE_MONITOR;
  up_write(&minfo->altout.lock);
 }
}

EXPORT_SYMBOL(matroxfb_g450_connect);
EXPORT_SYMBOL(matroxfb_g450_shutdown);

MODULE_AUTHOR("(c) 2000-2002 Petr Vandrovec ");
MODULE_DESCRIPTION("Matrox G450/G550 output driver");
MODULE_LICENSE("GPL");

Messung V0.5
C=94 H=92 G=92

¤ Dauer der Verarbeitung: 0.27 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge