All layers of chips support this, the only variable is the base address
of the lookup table in the register map.

Signed-off-by: Peter Rosin <p...@axentia.se>
---
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c  | 48 +++++++++++++++++++++++++
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c    | 13 +++++++
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h    | 16 +++++++++
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c |  5 +++
 4 files changed, 82 insertions(+)

diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c 
b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
index 5348985..75871b5 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
@@ -61,6 +61,7 @@ struct atmel_hlcdc_crtc {
        struct atmel_hlcdc_dc *dc;
        struct drm_pending_vblank_event *event;
        int id;
+       u32 clut[ATMEL_HLCDC_CLUT_SIZE];
 };
 
 static inline struct atmel_hlcdc_crtc *
@@ -140,6 +141,46 @@ static void atmel_hlcdc_crtc_mode_set_nofb(struct drm_crtc 
*c)
                           cfg);
 }
 
+static void
+atmel_hlcdc_crtc_load_lut(struct drm_crtc *c)
+{
+       struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
+       struct atmel_hlcdc_dc *dc = crtc->dc;
+       int layer;
+       int idx;
+
+       for (layer = 0; layer < ATMEL_HLCDC_MAX_LAYERS; layer++) {
+               if (!dc->layers[layer])
+                       continue;
+               for (idx = 0; idx < ATMEL_HLCDC_CLUT_SIZE; idx++)
+                       atmel_hlcdc_layer_write_clut(dc->layers[layer],
+                                                    idx, crtc->clut[idx]);
+       }
+}
+
+static void
+atmel_hlcdc_crtc_flush_lut(struct drm_crtc *c)
+{
+       struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
+       struct drm_crtc_state *state = c->state;
+       struct drm_color_lut *lut;
+       int idx;
+
+       if (!state->gamma_lut)
+               return;
+
+       lut = (struct drm_color_lut *)state->gamma_lut->data;
+
+       for (idx = 0; idx < ATMEL_HLCDC_CLUT_SIZE; idx++) {
+               crtc->clut[idx] =
+                       ((lut[idx].red << 8) & 0xff0000) |
+                       (lut[idx].green & 0xff00) |
+                       (lut[idx].blue >> 8);
+       }
+
+       atmel_hlcdc_crtc_load_lut(c);
+}
+
 static enum drm_mode_status
 atmel_hlcdc_crtc_mode_valid(struct drm_crtc *c,
                            const struct drm_display_mode *mode)
@@ -312,6 +353,9 @@ static void atmel_hlcdc_crtc_atomic_flush(struct drm_crtc 
*crtc,
                                          struct drm_crtc_state *old_s)
 {
        /* TODO: write common plane control register if available */
+
+       if (crtc->state->color_mgmt_changed)
+               atmel_hlcdc_crtc_flush_lut(crtc);
 }
 
 static const struct drm_crtc_helper_funcs lcdc_crtc_helper_funcs = {
@@ -429,6 +473,7 @@ static const struct drm_crtc_funcs atmel_hlcdc_crtc_funcs = 
{
        .atomic_destroy_state = atmel_hlcdc_crtc_destroy_state,
        .enable_vblank = atmel_hlcdc_crtc_enable_vblank,
        .disable_vblank = atmel_hlcdc_crtc_disable_vblank,
+       .set_property = drm_atomic_helper_crtc_set_property,
 };
 
 int atmel_hlcdc_crtc_create(struct drm_device *dev)
@@ -484,6 +529,9 @@ int atmel_hlcdc_crtc_create(struct drm_device *dev)
        drm_crtc_helper_add(&crtc->base, &lcdc_crtc_helper_funcs);
        drm_crtc_vblank_reset(&crtc->base);
 
+       drm_mode_crtc_set_gamma_size(&crtc->base, ATMEL_HLCDC_CLUT_SIZE);
+       drm_crtc_enable_color_mgmt(&crtc->base, 0, false, 
ATMEL_HLCDC_CLUT_SIZE);
+
        dc->crtc = &crtc->base;
 
        return 0;
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c 
b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
index 30dbffd..4f6ef07 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
@@ -42,6 +42,7 @@ static const struct atmel_hlcdc_layer_desc 
atmel_hlcdc_at91sam9n12_layers[] = {
                        .default_color = 3,
                        .general_config = 4,
                },
+               .clut_offset = 0x400,
        },
 };
 
@@ -73,6 +74,7 @@ static const struct atmel_hlcdc_layer_desc 
atmel_hlcdc_at91sam9x5_layers[] = {
                        .disc_pos = 5,
                        .disc_size = 6,
                },
+               .clut_offset = 0x400,
        },
        {
                .name = "overlay1",
@@ -91,6 +93,7 @@ static const struct atmel_hlcdc_layer_desc 
atmel_hlcdc_at91sam9x5_layers[] = {
                        .chroma_key_mask = 8,
                        .general_config = 9,
                },
+               .clut_offset = 0x800,
        },
        {
                .name = "high-end-overlay",
@@ -112,6 +115,7 @@ static const struct atmel_hlcdc_layer_desc 
atmel_hlcdc_at91sam9x5_layers[] = {
                        .scaler_config = 13,
                        .csc = 14,
                },
+               .clut_offset = 0x1000,
        },
        {
                .name = "cursor",
@@ -131,6 +135,7 @@ static const struct atmel_hlcdc_layer_desc 
atmel_hlcdc_at91sam9x5_layers[] = {
                        .chroma_key_mask = 8,
                        .general_config = 9,
                },
+               .clut_offset = 0x1400,
        },
 };
 
@@ -162,6 +167,7 @@ static const struct atmel_hlcdc_layer_desc 
atmel_hlcdc_sama5d3_layers[] = {
                        .disc_pos = 5,
                        .disc_size = 6,
                },
+               .clut_offset = 0x600,
        },
        {
                .name = "overlay1",
@@ -180,6 +186,7 @@ static const struct atmel_hlcdc_layer_desc 
atmel_hlcdc_sama5d3_layers[] = {
                        .chroma_key_mask = 8,
                        .general_config = 9,
                },
+               .clut_offset = 0xa00,
        },
        {
                .name = "overlay2",
@@ -198,6 +205,7 @@ static const struct atmel_hlcdc_layer_desc 
atmel_hlcdc_sama5d3_layers[] = {
                        .chroma_key_mask = 8,
                        .general_config = 9,
                },
+               .clut_offset = 0xe00,
        },
        {
                .name = "high-end-overlay",
@@ -223,6 +231,7 @@ static const struct atmel_hlcdc_layer_desc 
atmel_hlcdc_sama5d3_layers[] = {
                        },
                        .csc = 14,
                },
+               .clut_offset = 0x1200,
        },
        {
                .name = "cursor",
@@ -244,6 +253,7 @@ static const struct atmel_hlcdc_layer_desc 
atmel_hlcdc_sama5d3_layers[] = {
                        .general_config = 9,
                        .scaler_config = 13,
                },
+               .clut_offset = 0x1600,
        },
 };
 
@@ -275,6 +285,7 @@ static const struct atmel_hlcdc_layer_desc 
atmel_hlcdc_sama5d4_layers[] = {
                        .disc_pos = 5,
                        .disc_size = 6,
                },
+               .clut_offset = 0x600,
        },
        {
                .name = "overlay1",
@@ -293,6 +304,7 @@ static const struct atmel_hlcdc_layer_desc 
atmel_hlcdc_sama5d4_layers[] = {
                        .chroma_key_mask = 8,
                        .general_config = 9,
                },
+               .clut_offset = 0xa00,
        },
        {
                .name = "overlay2",
@@ -336,6 +348,7 @@ static const struct atmel_hlcdc_layer_desc 
atmel_hlcdc_sama5d4_layers[] = {
                        },
                        .csc = 14,
                },
+               .clut_offset = 0x1200,
        },
 };
 
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h 
b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
index b0596a8..709f7b9 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
@@ -88,6 +88,11 @@
 #define ATMEL_HLCDC_YUV422SWP                  BIT(17)
 #define ATMEL_HLCDC_DSCALEOPT                  BIT(20)
 
+#define ATMEL_HLCDC_C1_MODE                    ATMEL_HLCDC_CLUT_MODE(0)
+#define ATMEL_HLCDC_C2_MODE                    ATMEL_HLCDC_CLUT_MODE(1)
+#define ATMEL_HLCDC_C4_MODE                    ATMEL_HLCDC_CLUT_MODE(2)
+#define ATMEL_HLCDC_C8_MODE                    ATMEL_HLCDC_CLUT_MODE(3)
+
 #define ATMEL_HLCDC_XRGB4444_MODE              ATMEL_HLCDC_RGB_MODE(0)
 #define ATMEL_HLCDC_ARGB4444_MODE              ATMEL_HLCDC_RGB_MODE(1)
 #define ATMEL_HLCDC_RGBA4444_MODE              ATMEL_HLCDC_RGB_MODE(2)
@@ -142,6 +147,8 @@
 #define ATMEL_HLCDC_DMA_CHANNEL_DSCR_DONE      BIT(2)
 #define ATMEL_HLCDC_DMA_CHANNEL_DSCR_OVERRUN   BIT(3)
 
+#define ATMEL_HLCDC_CLUT_SIZE                  256
+
 #define ATMEL_HLCDC_MAX_LAYERS                 6
 
 /**
@@ -259,6 +266,7 @@ struct atmel_hlcdc_layer_desc {
        int id;
        int regs_offset;
        int cfgs_offset;
+       int clut_offset;
        struct atmel_hlcdc_formats *formats;
        struct atmel_hlcdc_layer_cfg_layout layout;
        int max_width;
@@ -414,6 +422,14 @@ static inline u32 atmel_hlcdc_layer_read_cfg(struct 
atmel_hlcdc_layer *layer,
                                          (cfgid * sizeof(u32)));
 }
 
+static inline void atmel_hlcdc_layer_write_clut(struct atmel_hlcdc_layer 
*layer,
+                                               unsigned int c, u32 val)
+{
+       atmel_hlcdc_layer_write_reg(layer,
+                                   layer->desc->clut_offset + c * sizeof(u32),
+                                   val);
+}
+
 static inline void atmel_hlcdc_layer_init(struct atmel_hlcdc_layer *layer,
                                const struct atmel_hlcdc_layer_desc *desc,
                                struct regmap *regmap)
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c 
b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
index 1124200..5537843 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
@@ -83,6 +83,7 @@ drm_plane_state_to_atmel_hlcdc_plane_state(struct 
drm_plane_state *s)
 #define SUBPIXEL_MASK                  0xffff
 
 static uint32_t rgb_formats[] = {
+       DRM_FORMAT_C8,
        DRM_FORMAT_XRGB4444,
        DRM_FORMAT_ARGB4444,
        DRM_FORMAT_RGBA4444,
@@ -100,6 +101,7 @@ struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_formats = {
 };
 
 static uint32_t rgb_and_yuv_formats[] = {
+       DRM_FORMAT_C8,
        DRM_FORMAT_XRGB4444,
        DRM_FORMAT_ARGB4444,
        DRM_FORMAT_RGBA4444,
@@ -128,6 +130,9 @@ struct atmel_hlcdc_formats 
atmel_hlcdc_plane_rgb_and_yuv_formats = {
 static int atmel_hlcdc_format_to_plane_mode(u32 format, u32 *mode)
 {
        switch (format) {
+       case DRM_FORMAT_C8:
+               *mode = ATMEL_HLCDC_C8_MODE;
+               break;
        case DRM_FORMAT_XRGB4444:
                *mode = ATMEL_HLCDC_XRGB4444_MODE;
                break;
-- 
2.1.4

Reply via email to