Color lookup support for the atmel-hlcdc driver

Peter Rosin peda at axentia.se
Thu Jun 15 23:01:58 UTC 2017


On 2017-06-15 13:54, Boris Brezillon wrote:
> On Thu, 15 Jun 2017 13:47:35 +0200
> Peter Rosin <peda at axentia.se> wrote:
> 
>> On 2017-06-15 12:15, Boris Brezillon wrote:
>>> On Thu, 15 Jun 2017 11:54:29 +0200
>>> Peter Rosin <peda at axentia.se> wrote:
>>>   
>>>> On 2017-06-13 17:30, Boris Brezillon wrote:  
>>>>> Hi Peter,
>>>>>
>>>>> On Tue, 13 Jun 2017 16:34:25 +0200
>>>>> Peter Rosin <peda at axentia.se> wrote:
>>>>>     
>>>>>> Hi!
>>>>>>
>>>>>> I need color lookup support for the atmel-hlcdc driver, and had a peek
>>>>>> at the code. I also looked at the drivers/gpu/drm/stm driver and came
>>>>>> up with the below diff. It compiles, but I have not booted it for the
>>>>>> simple reason that I can't imagine it will work.
>>>>>>
>>>>>> Sure, the code fills the clut registers in the .load_lut helper function
>>>>>> and I think it might even do the right thing when setting up the mode.
>>>>>> I'm less sure DMA will work correctly? It might, but I haven't looked at
>>>>>> it for many seconds...
>>>>>>
>>>>>> The big question is how the color info gets into the new clut array
>>>>>> I created in atmel_hlcdc_crtc? When I look at the stm driver, which does
>>>>>> it just like this AFAICT I just don't see it. So, what I'm I missing?    
>>>>>
>>>>> You should look at drm_atomic_helper_legacy_gamma_set() and its users.    
>>>>
>>>> Ok, thanks. I had a long look and could not get it to work at all.  
>>>
>>> Probably because you're trying to set this up through the emulated
>>> fbdev interface. The solution I proposed is supposed to be accessed
>>> through DRM ioctls.  
>>
>> Yes, that seems like the root cause of most of my troubles. But, the apps
>> I have seem to use the fbdev interface, and if the emulation is poorly
>> done, they won't work right...
>>
>>>> So,
>>>> I did as below instead. However, there are a few glaring problems...  
>>>
>>> Well, I doubt this will be accepted. The fbdev emulation layer is
>>> supposed to be rather dumb, partly because DRM people want developers
>>> to switch to the DRM interface.  
>>
>> Sigh.
>>
>>> Also note that I won't accept a solution that supports setting the LUT
>>> table only through the fbdev interface, so please try to make it work
>>> the DRM way before you even consider modifying the fbdev emulation
>>> layer.  
>>
>> Ok, I'll have another look. But to me, it's a maze...
>>
>>>>
>>>> Something, somewhere, sets up default entries for the 16 first entries
>>>> of the palette and seem to expect them to stay as some kind of safe
>>>> basic palette, and my applications don't handle it too well. When they
>>>> want to draw black, they get a poisonous cyan/green instead etc. But
>>>> it's pretty close. Can anyone provide some clue as to how that is
>>>> supposed to be handled?
>>>>
>>>> Also, I had to change the second argument of the drm_fbdev_cma_init...
>>>> call at the end of atmel_hlcdc_dc.c:atmel_hlcdc_dc_load() from 24 to 8
>>>> to make it possible to set 8-modes. However, doing so fucks up 24-bit
>>>> modes. Which made me suspect that no non-24-bit mode work w/o my patch.
>>>> And I could indeed only get 24-bit modes to work, unless I changed this
>>>> value to 16. Then RGB565 works like a charm, but RGB888 don't. What's
>>>> up with that? Seems like a rather silly limitation, but it's perhaps
>>>> just a bug?  
>>>
>>> I'm pretty sure this is not a bug. AFAIR, prefered_bpp is used when you
>>> don't explicitly specify the video mode you want to use on the cmdline
>>> [1].
>>>
>>> [1]http://elixir.free-electrons.com/linux/v3.11/source/Documentation/fb/modedb.txt
>>>   
>>
>> (Why refer to v3.11 docs?)
>>
>> Let's start with some basics, I tried to add
>>
>> 	video=atmel-hclcd-dc:1024x768-16
>>
>> and
>>
>> 	video=atmel_hclcd_dc:1024x768-16
>>
>> to the kernel cmdline of an unpatched linux-next kernel. No dice, I can
>> still only access RBG888. I'm obviously in need of some hand-holding...
>>
>> How am I supposed to get a 16-bit mode?
> 
> You should have a look at [1].
> 
> [1]https://www.at91.com/linux4sam/bin/view/Linux4SAM/UsingAtmelDRMDriver#Choose_supported_modes
> 

Ahh, it works with video=Unknown-1:1024x768-16

Thanks!

So, is this below better? I'll follow-up with a patch I need for the
fbdev emulation to work.

I can't easily test this newfangled drm stuff, my userspace is oldish, so
I don't know if atmel_hlcdc_crtc_atomic_flush() is the correct place to
call atmel_hlcdc_crtc_flush_lut and have the palette loaded?

What I'm saying is that I have only tested the fbdev emulation, and I
still have trouble with the palette colors (poisonous green/cyan instead
of black etc). But that may only be an issue with fbdev?

Cheers,
peda

diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
index 5348985..68f5e66 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[256];
 };
 
 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 < 256; 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 < 256; 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, 256);
+	drm_crtc_enable_color_mgmt(&crtc->base, 0, false, 256);
+
 	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..a2cc2ab 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)
@@ -259,6 +264,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 +420,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;


More information about the dri-devel mailing list