summaryrefslogtreecommitdiff
path: root/src/i830_tv.c
diff options
context:
space:
mode:
authorZhenyu Wang <zhenyu.z.wang@intel.com>2009-03-03 22:55:35 +0800
committerZhenyu Wang <zhenyu.z.wang@intel.com>2009-03-03 22:55:35 +0800
commit42e34e90e2e4048b38481cab61cef46f932eada7 (patch)
treef30be7ebf912daedb9dd17436ca80aef4ed45bc4 /src/i830_tv.c
parentaa9da5e393c804019720503fe58bdd247fe1eabd (diff)
TV: add property control for TV attributes
This is based on Jesse's origin patch for bug #12763. But export integer range to user instead of hardware float point format, and fix different real format on 965G and 945G for contrast and saturation.
Diffstat (limited to 'src/i830_tv.c')
-rw-r--r--src/i830_tv.c211
1 files changed, 201 insertions, 10 deletions
diff --git a/src/i830_tv.c b/src/i830_tv.c
index e7766515..1e3cf7b6 100644
--- a/src/i830_tv.c
+++ b/src/i830_tv.c
@@ -59,6 +59,10 @@ struct i830_tv_priv {
Bool force_type;
char *tv_format;
int margin[4];
+ uint8_t brightness;
+ uint8_t contrast;
+ uint8_t saturation;
+ uint8_t hue;
uint32_t save_TV_H_CTL_1;
uint32_t save_TV_H_CTL_2;
uint32_t save_TV_H_CTL_3;
@@ -1020,6 +1024,96 @@ i830_float_to_luma (float f)
return ret;
}
+static uint8_t
+float_to_float_2_6(float fin)
+{
+ uint8_t exp;
+ uint8_t mant;
+ float f = fin;
+ uint32_t tmp;
+
+ if (f < 0) f = -f;
+
+ tmp = f;
+ for (exp = 0; exp <= 3 && tmp > 0; exp++)
+ tmp /= 2;
+
+ mant = (f * (1 << 6) + 0.5);
+ mant >>= exp;
+ if (mant > (1 << 6))
+ mant = (1 << 6) - 1;
+
+ return (exp << 6) | mant;
+}
+
+static uint8_t
+float_to_fix_2_6(float f)
+{
+ uint8_t ret;
+
+ ret = f * (1 << 6);
+ return ret;
+}
+
+static void
+i830_tv_update_brightness(I830Ptr pI830, uint8_t brightness)
+{
+ /* brightness in 2's comp value */
+ uint32_t val = INREG(TV_CLR_KNOBS) & ~TV_BRIGHTNESS_MASK;
+ int8_t bri = brightness - 128; /* remove bias */
+
+ val |= (bri << TV_BRIGHTNESS_SHIFT) & TV_BRIGHTNESS_MASK;
+ OUTREG(TV_CLR_KNOBS, val);
+}
+
+static void
+i830_tv_update_contrast(I830Ptr pI830, uint8_t contrast)
+{
+ uint32_t val = INREG(TV_CLR_KNOBS) & ~TV_CONTRAST_MASK;;
+ float con;
+ uint8_t c;
+
+ if (IS_I965G(pI830)) {
+ /* 2.6 fixed point */
+ con = 3.0 * ((float) contrast / 255);
+ c = float_to_fix_2_6(con);
+ } else {
+ /* 2.6 floating point */
+ con = 8.875 * ((float) contrast / 255);
+ c = float_to_float_2_6(con);
+ }
+ val |= (c << TV_CONTRAST_SHIFT) & TV_CONTRAST_MASK;
+ OUTREG(TV_CLR_KNOBS, val);
+}
+
+static void
+i830_tv_update_saturation(I830Ptr pI830, uint8_t saturation)
+{
+ uint32_t val = INREG(TV_CLR_KNOBS) & ~TV_SATURATION_MASK;
+ float sat;
+ uint8_t s;
+
+ /* same as contrast */
+ if (IS_I965G(pI830)) {
+ sat = 3.0 * ((float) saturation / 255);
+ s = float_to_fix_2_6(sat);
+ } else {
+ sat = 8.875 * ((float) saturation / 255);
+ s = float_to_float_2_6(sat);
+ }
+ val |= (s << TV_SATURATION_SHIFT) & TV_SATURATION_MASK;
+ OUTREG(TV_CLR_KNOBS, val);
+}
+
+static void
+i830_tv_update_hue(I830Ptr pI830, uint8_t hue)
+{
+ uint32_t val = INREG(TV_CLR_KNOBS) & ~TV_HUE_MASK;
+
+ val |= (hue << TV_HUE_SHIFT) & TV_HUE_MASK;
+ OUTREG(TV_CLR_KNOBS, val);
+}
+
static void
i830_tv_mode_set(xf86OutputPtr output, DisplayModePtr mode,
DisplayModePtr adjusted_mode)
@@ -1181,14 +1275,6 @@ i830_tv_mode_set(xf86OutputPtr output, DisplayModePtr mode,
(i830_float_to_csc(color_conversion->bv) << 16) |
(i830_float_to_luma(color_conversion->av)));
- if (IS_I965G(pI830)) {
- /* 2.6 fixed point value for contrast and saturation modifier,
- use 1 as default */
- OUTREG(TV_CLR_KNOBS, 0x00404000);
- } else {
- /* 915/945 uses 2 bits exponent and 6 bits mantissa format */
- OUTREG(TV_CLR_KNOBS, 0x00606000);
- }
OUTREG(TV_CLR_LEVEL, ((video_levels->black << TV_BLACK_LEVEL_SHIFT) |
(video_levels->blank << TV_BLANK_LEVEL_SHIFT)));
{
@@ -1496,6 +1582,26 @@ static char *margin_names[4] = {
"LEFT", "TOP", "RIGHT", "BOTTOM"
};
+/**
+ * contrast and saturation has different format on 915/945 with 965.
+ * On 915/945, it's 2.6 floating point number.
+ * On 965, it's 2.6 fixed point number.
+ */
+#define TV_BRIGHTNESS_NAME "BRIGHTNESS"
+#define TV_BRIGHTNESS_DEFAULT 128 /* bias */
+static Atom brightness_atom;
+#define TV_CONTRAST_NAME "CONTRAST"
+#define TV_CONTRAST_DEFAULT 0x40
+#define TV_CONTRAST_DEFAULT_945G 0x60
+static Atom contrast_atom;
+#define TV_SATURATION_NAME "SATURATION"
+#define TV_SATURATION_DEFAULT 0x40
+#define TV_SATURATION_DEFAULT_945G 0x60
+static Atom saturation_atom;
+#define TV_HUE_NAME "HUE"
+#define TV_HUE_DEFAULT 0
+static Atom hue_atom;
+
static Bool
i830_tv_format_set_property (xf86OutputPtr output)
{
@@ -1541,6 +1647,62 @@ i830_tv_format_configure_property (xf86OutputPtr output)
num_atoms, (INT32 *) current_atoms);
}
+static void
+i830_tv_color_set_property(xf86OutputPtr output, Atom property,
+ uint8_t val)
+{
+ ScrnInfoPtr pScrn = output->scrn;
+ I830Ptr pI830 = I830PTR(pScrn);
+ I830OutputPrivatePtr intel_output = output->driver_private;
+ struct i830_tv_priv *dev_priv = intel_output->dev_priv;
+
+ if (property == brightness_atom) {
+ dev_priv->brightness = val;
+ i830_tv_update_brightness(pI830, val);
+ } else if (property == contrast_atom) {
+ dev_priv->contrast = val;
+ i830_tv_update_contrast(pI830, val);
+ } else if (property == saturation_atom) {
+ dev_priv->saturation = val;
+ i830_tv_update_saturation(pI830, val);
+ } else if (property == hue_atom) {
+ dev_priv->hue = val;
+ i830_tv_update_hue(pI830, val);
+ }
+}
+
+static void
+i830_tv_color_create_property(xf86OutputPtr output, Atom *property,
+ char *name, int name_len, uint8_t val)
+{
+ ScrnInfoPtr pScrn = output->scrn;
+ INT32 range[2];
+ int err = 0;
+
+ *property = MakeAtom(name, name_len - 1, TRUE);
+ range[0] = 0;
+ range[1] = 255;
+ err = RRConfigureOutputProperty(output->randr_output, *property,
+ FALSE, TRUE, FALSE, 2, range);
+ if (err != 0) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "RRConfigureOutputProperty error, %d\n", err);
+ goto out;
+ }
+ /* Set the current value */
+ i830_tv_color_set_property(output, *property, val);
+
+ err = RRChangeOutputProperty(output->randr_output, *property,
+ XA_INTEGER, 32, PropModeReplace, 1, &val,
+ FALSE, FALSE);
+ if (err != 0) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "RRChangeOutputProperty error, %d\n", err);
+ }
+out:
+ return;
+}
+
#endif /* RANDR_12_INTERFACE */
static void
@@ -1548,10 +1710,10 @@ i830_tv_create_resources(xf86OutputPtr output)
{
#ifdef RANDR_12_INTERFACE
ScrnInfoPtr pScrn = output->scrn;
+ I830Ptr pI830 = I830PTR(pScrn);
I830OutputPrivatePtr intel_output = output->driver_private;
struct i830_tv_priv *dev_priv = intel_output->dev_priv;
- int err;
- int i;
+ int err, i;
/* Set up the tv_format property, which takes effect on mode set
* and accepts strings that match exactly
@@ -1599,6 +1761,23 @@ i830_tv_create_resources(xf86OutputPtr output)
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"RRChangeOutputProperty error, %d\n", err);
}
+
+ i830_tv_color_create_property(output, &brightness_atom,
+ TV_BRIGHTNESS_NAME,
+ sizeof(TV_BRIGHTNESS_NAME),
+ TV_BRIGHTNESS_DEFAULT);
+ i830_tv_color_create_property(output, &contrast_atom,
+ TV_CONTRAST_NAME,
+ sizeof(TV_CONTRAST_NAME),
+ IS_I965G(pI830) ? TV_CONTRAST_DEFAULT :
+ TV_CONTRAST_DEFAULT_945G);
+ i830_tv_color_create_property(output, &saturation_atom,
+ TV_SATURATION_NAME,
+ sizeof(TV_SATURATION_NAME),
+ IS_I965G(pI830) ? TV_SATURATION_DEFAULT :
+ TV_SATURATION_DEFAULT_945G);
+ i830_tv_color_create_property(output, &hue_atom, TV_HUE_NAME,
+ sizeof(TV_HUE_NAME), TV_HUE_DEFAULT);
#endif /* RANDR_12_INTERFACE */
}
@@ -1703,6 +1882,18 @@ i830_tv_set_property(xf86OutputPtr output, Atom property,
return TRUE;
}
}
+ if (property == brightness_atom || property == contrast_atom ||
+ property == saturation_atom || property == hue_atom) {
+ uint8_t val;
+
+ /* Make sure value is sane */
+ if (value->type != XA_INTEGER || value->format != 32 ||
+ value->size != 1)
+ return FALSE;
+
+ memcpy (&val, value->data, 1);
+ i830_tv_color_set_property(output, property, val);
+ }
return TRUE;
}