aboutsummaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/sun4i/sun8i_csc.c
diff options
context:
space:
mode:
authorJernej Skrabec <jernej.skrabec@siol.net>2017-12-01 07:05:46 +0100
committerMaxime Ripard <maxime.ripard@free-electrons.com>2017-12-05 13:22:44 +0100
commit8830293905504dba3a50bf34287697c5fe088f9b (patch)
tree90ba1ced298fc31a17ba871f3616c755948da430 /drivers/gpu/drm/sun4i/sun8i_csc.c
parentbd3bcb9112894bc0fa29ad4b0c4b534932efeab0 (diff)
downloadlinux-8830293905504dba3a50bf34287697c5fe088f9b.tar.gz
drm/sun4i: Add DE2 CSC library
DE2 have many CSC units - channel input CSC, channel output CSC and mixer output CSC and maybe more. Fortunately, they have all same register layout, only base offsets differs. Add support only for channel output CSC for now. Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com> Link: https://patchwork.freedesktop.org/patch/msgid/20171201060550.10392-24-jernej.skrabec@siol.net
Diffstat (limited to 'drivers/gpu/drm/sun4i/sun8i_csc.c')
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_csc.c93
1 files changed, 93 insertions, 0 deletions
diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.c b/drivers/gpu/drm/sun4i/sun8i_csc.c
new file mode 100644
index 000000000000..b14925b40ccf
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) Jernej Skrabec <jernej.skrabec@siol.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+#include <drm/drmP.h>
+
+#include "sun8i_csc.h"
+#include "sun8i_mixer.h"
+
+static const u32 ccsc_base[2][2] = {
+ {CCSC00_OFFSET, CCSC01_OFFSET},
+ {CCSC10_OFFSET, CCSC11_OFFSET},
+};
+
+/*
+ * Factors are in two's complement format, 10 bits for fractinal part.
+ * First tree values in each line are multiplication factor and last
+ * value is constant, which is added at the end.
+ */
+static const u32 yuv2rgb[] = {
+ 0x000004A8, 0x00000000, 0x00000662, 0xFFFC845A,
+ 0x000004A8, 0xFFFFFE6F, 0xFFFFFCBF, 0x00021DF4,
+ 0x000004A8, 0x00000813, 0x00000000, 0xFFFBAC4A,
+};
+
+static const u32 yvu2rgb[] = {
+ 0x000004A8, 0x00000662, 0x00000000, 0xFFFC845A,
+ 0x000004A8, 0xFFFFFCBF, 0xFFFFFE6F, 0x00021DF4,
+ 0x000004A8, 0x00000000, 0x00000813, 0xFFFBAC4A,
+};
+
+static void sun8i_csc_set_coefficients(struct regmap *map, u32 base,
+ enum sun8i_csc_mode mode)
+{
+ const u32 *table;
+ int i, data;
+
+ switch (mode) {
+ case SUN8I_CSC_MODE_YUV2RGB:
+ table = yuv2rgb;
+ break;
+ case SUN8I_CSC_MODE_YVU2RGB:
+ table = yvu2rgb;
+ break;
+ default:
+ DRM_WARN("Wrong CSC mode specified.\n");
+ return;
+ }
+
+ for (i = 0; i < 12; i++) {
+ data = table[i];
+ /* For some reason, 0x200 must be added to constant parts */
+ if (((i + 1) & 3) == 0)
+ data += 0x200;
+ regmap_write(map, SUN8I_CSC_COEFF(base, i), data);
+ }
+}
+
+static void sun8i_csc_enable(struct regmap *map, u32 base, bool enable)
+{
+ u32 val;
+
+ if (enable)
+ val = SUN8I_CSC_CTRL_EN;
+ else
+ val = 0;
+
+ regmap_update_bits(map, SUN8I_CSC_CTRL(base), SUN8I_CSC_CTRL_EN, val);
+}
+
+void sun8i_csc_set_ccsc_coefficients(struct sun8i_mixer *mixer, int layer,
+ enum sun8i_csc_mode mode)
+{
+ u32 base;
+
+ base = ccsc_base[mixer->cfg->ccsc][layer];
+
+ sun8i_csc_set_coefficients(mixer->engine.regs, base, mode);
+}
+
+void sun8i_csc_enable_ccsc(struct sun8i_mixer *mixer, int layer, bool enable)
+{
+ u32 base;
+
+ base = ccsc_base[mixer->cfg->ccsc][layer];
+
+ sun8i_csc_enable(mixer->engine.regs, base, enable);
+}