linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 0/6] drm: Add driver for Solomon SSD130x OLED displays
@ 2022-02-11  9:19 Javier Martinez Canillas
  2022-02-11  9:19 ` [PATCH v4 1/6] drm/format-helper: Add drm_fb_xrgb8888_to_gray8_line() Javier Martinez Canillas
                   ` (5 more replies)
  0 siblings, 6 replies; 43+ messages in thread
From: Javier Martinez Canillas @ 2022-02-11  9:19 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-fbdev, Geert Uytterhoeven, Andy Shevchenko, Maxime Ripard,
	Daniel Vetter, dri-devel, Thomas Zimmermann, Sam Ravnborg,
	Noralf Trønnes, Javier Martinez Canillas, Daniel Vetter,
	David Airlie, Lee Jones, Maarten Lankhorst, Maxime Ripard,
	Rob Herring, Thierry Reding, Uwe Kleine-König, devicetree,
	linux-pwm

This patch series adds a DRM driver for the Solomon OLED SSD1305, SSD1306,
SSD1307 and SSD1309 displays. It is a port of the ssd1307fb fbdev driver.

Using the DRM fbdev emulation, all the tests from Geert Uytterhoeven repo
(https://git.kernel.org/pub/scm/linux/kernel/git/geert/fbtest.git) passes.

I've also tested it using the display as a VT output and even though fbcon
seems to work, it is mostly unusable on a 128x64 SSD1306 display.

This is a v4 that addresses the issues pointed in v3. Thanks a lot to all
reviewers that gave me feedback and comments.

I didn't include the patch that adds the SPI support this time, because it
will require changes in the existing Device Tree binding. And I wanted to
avoid that bikesheeding for now, to focus on the core and I2C parts.

Once this series land, I'll post patches for the SPI support. But the WIP
patch posted in v3 should still apply cleanly on top of this v4:

https://patchwork.kernel.org/project/dri-devel/patch/20220209091204.2513437-1-javierm@redhat.com/

Patch #1 splits per-line conversion logic in drm_fb_xrgb8888_to_gray8() to
a separate drm_fb_xrgb8888_to_gray8_line() helper function.

Patch #2 adds a new drm_fb_xrgb8888_to_mono_reversed() helper function to
convert from XR24 to reversed monochrome. The latter internally converts
each line first to 8-bit grayscale and then to 1-bit reversed monochrome.

Patch #3 adds the driver. This only has the core support and doesn't have
any bus specific code, separate drivers are needed for the transport used.

Patch #4 adds a driver to use the I2C bus to communicate with the device.

Patch #5 adds a MAINTAINERS entry for the DRM driver and patch #6 adds
myself as co-maintainer of the existing DT binding for the ssd1307fb,
since the same DT binding is used for both the fbdev and DRM drivers.

Best regards,
Javier

Changes in v4:
- Rename end_offset to end_len (Thomas Zimmermann)
- Warn once if dst_pitch is not a multiple of 8 (Thomas Zimmermann)
- Drop drm_fb_gray8_to_mono_reversed() that's not used (Thomas Zimmermann)
- Allocate single buffer for both copy cma memory and gray8 (Thomas Zimmermann)
- Add Thomas Zimmermann Reviewed-by tag to patch adding XR24 -> mono helper.
- Rename vbat supply to vcc since is how's labeled in the device (Mark Brown)
- Don't make the regulator option since is always needed (Mark Brown)
- Add solomon Kconfig source and directory inclusion sorted (Andy Shevchenko)
- Use SSD130x instead of SSD130X to denote is not a model name (Andy Shevchenko)
- Check if there's a reset pin in the callee and not the caller (Andy Shevchenko)
- Define missing commands instead of using magic numbers (Andy Shevchenko)
- Use GENMASK() and FIELD_PREP() macros when possible (Andy Shevchenko)
- Avoid using ternary operators to ease code readablity (Andy Shevchenko)
- Use i++ instead of --i on some for loops (Andy Shevchenko)
- Remove redundant blank lines (Andy Shevchenko)
- Rename power_off label to out_power_off (Andy Shevchenko)
- Use dev_err_probe() even if no -EPROBE_DEFER (Andy Shevchenko)
- Don't use plural Authors if there's only one (Andy Shevchenko)
- Remove unnecessary casting (Geert Uytterhoeven)
- Remove redundant blank lines (Andy Shevchenko)
- Remove comma after of_device_id table terminator (Andy Shevchenko)
- Add Rob Herring Acked-by tag to patch adding as DT binding co-maintainer.

Changes in v3:
- Add a drm_fb_xrgb8888_to_gray8_line() helper function (Thomas Zimmermann)
- Also add a drm_fb_xrgb8888_to_mono_reversed() helper (Thomas Zimmermann)
- Split lines copy to drm_fb_gray8_to_mono_reversed_line() (Thomas Zimmermann)
- Handle case where the source buffer is not aligned to 8 (Thomas Zimmermann)
- Move driver from tiny sub-dir to drivers/gpu/drm/solomon (Sam Ravnborg)
- Split driver in a bus agnostic core and bus specific (Andy Shevchenko)
- Use regmap to access the chip registers (Andy Shevchenko)
- Remove unnecessary blank lines (Andy Shevchenko)
- Remove unneeded inline specifier in functions (Andy Shevchenko)
- Add a comment about always returning a single mode (Andy Shevchenko)
- Change write command logic to use do while loop (Andy Shevchenko)
- Use "firmware description" instead of "device tree" (Andy Shevchenko)
- Use return foo() instead of returning the return value (Andy Shevchenko)
- Don't split lines longer than 80 chars if makes less readable (Andy Shevchenko)
- Remove redundant else statements in .mode_valid callback (Andy Shevchenko)
- Rename powero{n,ff}() functions to power_o{n,ff)() (Andy Shevchenko)
- Use dev_err_probe() to prevent spam logs on probe deferral (Andy Shevchenko)
- Remove ',' after sentinel terminator in array (Andy Shevchenko)
- Fix a bug when doing partial updates (Geert Uytterhoeven)
- Add a separate driver for SSD130X chips I2C support (Andy Shevchenko)
- Adapt MAINTAINERS entry to point to the new drivers/gpu/drm/solomon directory.

Changes in v2:
- Drop patch that was adding a DRM_MODE_CONNECTOR_I2C type.
- Invert order of backlight {en,dis}able and display {on,off} (Sam Ravnborg)
- Don't clear the screen and turn on display on probe (Sam Ravnborg)
- Use backlight_get_brightness() macro to get BL brightness (Sam Ravnborg)
- Use dev managed version of devm_backlight_device_register() (Sam Ravnborg)
- Use dev_name(dev) for backlight name instead of an array (Sam Ravnborg)
- Drop the .get_brightness callback since isn't needed  (Sam Ravnborg)
- Rename driver to ssd130x since supports a display family (Thomas Zimmermann)
- Drop the TINY prefix from the Kconfig symbol (Thomas Zimmermann)
- Sort the Kconfig symbol dependencies alphabetically (Thomas Zimmermann)
- Rename struct ssd130x_array to struct ssd130x_i2c_msg (Thomas Zimmermann)
- Rename struct ssd130x_i2c_msg .type member to .cmd (Thomas Zimmermann)
- Use sizeof(*foo) instead of sizeof(struct foo) (Thomas Zimmermann)
- Use struct_size() macro to calculate sizeof(*foo) + len (Thomas Zimmermann)
- Use kcalloc() instead of kmalloc_array() + memset() (Thomas Zimmermann)
- Use shadow plane helpers virtual screen support (Thomas Zimmermann)
- Remove unused goto label in ssd1307_fb_blit_rect() (Thomas Zimmermann)
- Use drm_set_preferred_mode() inset of manually set (Thomas Zimmermann)
- Use shadow plane helpers virtual screen support (Thomas Zimmermann)
- Remove unused goto label in ssd1307_fb_blit_rect() (Thomas Zimmermann)
- Use drm_set_preferred_mode() inset of manually set (Thomas Zimmermann)
- Reorganize code in probe to make it more legible (Thomas Zimmermann)
- ssd130x_write_cmd() uses varargs to simplify I2C code (Thomas Zimmermann)
- Move regulator/pwm init logic to display pipe enable callback.
- Add Sam Ravnborg's acked-by to patch adding a MAINTAINERS entry (Sam Ravnborg)
- Add myself as co-maintainer of the ssd1370fb DT binding (Sam Ravnborg).

Javier Martinez Canillas (6):
  drm/format-helper: Add drm_fb_xrgb8888_to_gray8_line()
  drm/format-helper: Add drm_fb_xrgb8888_to_mono_reversed()
  drm: Add driver for Solomon SSD130x OLED displays
  drm/solomon: Add SSD130x OLED displays I2C support
  MAINTAINERS: Add entry for Solomon SSD130x OLED displays DRM driver
  dt-bindings: display: ssd1307fb: Add myself as binding co-maintainer

 .../bindings/display/solomon,ssd1307fb.yaml   |   1 +
 MAINTAINERS                                   |   7 +
 drivers/gpu/drm/Kconfig                       |   2 +
 drivers/gpu/drm/Makefile                      |   1 +
 drivers/gpu/drm/drm_format_helper.c           | 138 ++-
 drivers/gpu/drm/solomon/Kconfig               |  21 +
 drivers/gpu/drm/solomon/Makefile              |   2 +
 drivers/gpu/drm/solomon/ssd130x-i2c.c         | 116 +++
 drivers/gpu/drm/solomon/ssd130x.c             | 852 ++++++++++++++++++
 drivers/gpu/drm/solomon/ssd130x.h             |  76 ++
 include/drm/drm_format_helper.h               |   4 +
 11 files changed, 1208 insertions(+), 12 deletions(-)
 create mode 100644 drivers/gpu/drm/solomon/Kconfig
 create mode 100644 drivers/gpu/drm/solomon/Makefile
 create mode 100644 drivers/gpu/drm/solomon/ssd130x-i2c.c
 create mode 100644 drivers/gpu/drm/solomon/ssd130x.c
 create mode 100644 drivers/gpu/drm/solomon/ssd130x.h

-- 
2.34.1


^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH v4 1/6] drm/format-helper: Add drm_fb_xrgb8888_to_gray8_line()
  2022-02-11  9:19 [PATCH v4 0/6] drm: Add driver for Solomon SSD130x OLED displays Javier Martinez Canillas
@ 2022-02-11  9:19 ` Javier Martinez Canillas
  2022-02-11  9:29   ` Thomas Zimmermann
  2022-02-11 10:28   ` Andy Shevchenko
  2022-02-11  9:19 ` [PATCH v4 2/6] drm/format-helper: Add drm_fb_xrgb8888_to_mono_reversed() Javier Martinez Canillas
                   ` (4 subsequent siblings)
  5 siblings, 2 replies; 43+ messages in thread
From: Javier Martinez Canillas @ 2022-02-11  9:19 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-fbdev, Geert Uytterhoeven, Andy Shevchenko, Maxime Ripard,
	Daniel Vetter, dri-devel, Thomas Zimmermann, Sam Ravnborg,
	Noralf Trønnes, Javier Martinez Canillas, Daniel Vetter,
	David Airlie, Maarten Lankhorst, Maxime Ripard

Pull the per-line conversion logic into a separate helper function.

This will allow to do line-by-line conversion in other helpers that
convert to a gray8 format.

Suggested-by: Thomas Zimmermann <tzimmermann@suse.de>
Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
---

(no changes since v3)

Changes in v3:
- Add a drm_fb_xrgb8888_to_gray8_line() helper function (Thomas Zimmermann)

 drivers/gpu/drm/drm_format_helper.c | 31 ++++++++++++++++++-----------
 1 file changed, 19 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/drm_format_helper.c b/drivers/gpu/drm/drm_format_helper.c
index 0f28dd2bdd72..b981712623d3 100644
--- a/drivers/gpu/drm/drm_format_helper.c
+++ b/drivers/gpu/drm/drm_format_helper.c
@@ -464,6 +464,21 @@ void drm_fb_xrgb8888_to_xrgb2101010_toio(void __iomem *dst,
 }
 EXPORT_SYMBOL(drm_fb_xrgb8888_to_xrgb2101010_toio);
 
+static void drm_fb_xrgb8888_to_gray8_line(u8 *dst, const u32 *src, unsigned int pixels)
+{
+	unsigned int x;
+
+	for (x = 0; x < pixels; x++) {
+		u8 r = (*src & 0x00ff0000) >> 16;
+		u8 g = (*src & 0x0000ff00) >> 8;
+		u8 b =  *src & 0x000000ff;
+
+		/* ITU BT.601: Y = 0.299 R + 0.587 G + 0.114 B */
+		*dst++ = (3 * r + 6 * g + b) / 10;
+		src++;
+	}
+}
+
 /**
  * drm_fb_xrgb8888_to_gray8 - Convert XRGB8888 to grayscale
  * @dst: 8-bit grayscale destination buffer
@@ -484,8 +499,9 @@ EXPORT_SYMBOL(drm_fb_xrgb8888_to_xrgb2101010_toio);
 void drm_fb_xrgb8888_to_gray8(void *dst, unsigned int dst_pitch, const void *vaddr,
 			      const struct drm_framebuffer *fb, const struct drm_rect *clip)
 {
-	unsigned int len = (clip->x2 - clip->x1) * sizeof(u32);
-	unsigned int x, y;
+	unsigned int linepixels = clip->x2 - clip->x1;
+	unsigned int len = linepixels * sizeof(u32);
+	unsigned int y;
 	void *buf;
 	u8 *dst8;
 	u32 *src32;
@@ -508,16 +524,7 @@ void drm_fb_xrgb8888_to_gray8(void *dst, unsigned int dst_pitch, const void *vad
 	for (y = clip->y1; y < clip->y2; y++) {
 		dst8 = dst;
 		src32 = memcpy(buf, vaddr, len);
-		for (x = clip->x1; x < clip->x2; x++) {
-			u8 r = (*src32 & 0x00ff0000) >> 16;
-			u8 g = (*src32 & 0x0000ff00) >> 8;
-			u8 b =  *src32 & 0x000000ff;
-
-			/* ITU BT.601: Y = 0.299 R + 0.587 G + 0.114 B */
-			*dst8++ = (3 * r + 6 * g + b) / 10;
-			src32++;
-		}
-
+		drm_fb_xrgb8888_to_gray8_line(dst8, src32, linepixels);
 		vaddr += fb->pitches[0];
 		dst += dst_pitch;
 	}
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH v4 2/6] drm/format-helper: Add drm_fb_xrgb8888_to_mono_reversed()
  2022-02-11  9:19 [PATCH v4 0/6] drm: Add driver for Solomon SSD130x OLED displays Javier Martinez Canillas
  2022-02-11  9:19 ` [PATCH v4 1/6] drm/format-helper: Add drm_fb_xrgb8888_to_gray8_line() Javier Martinez Canillas
@ 2022-02-11  9:19 ` Javier Martinez Canillas
  2022-02-11 11:10   ` Andy Shevchenko
  2022-02-11 12:46   ` Thomas Zimmermann
  2022-02-11  9:19 ` [PATCH v4 3/6] drm: Add driver for Solomon SSD130x OLED displays Javier Martinez Canillas
                   ` (3 subsequent siblings)
  5 siblings, 2 replies; 43+ messages in thread
From: Javier Martinez Canillas @ 2022-02-11  9:19 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-fbdev, Geert Uytterhoeven, Andy Shevchenko, Maxime Ripard,
	Daniel Vetter, dri-devel, Thomas Zimmermann, Sam Ravnborg,
	Noralf Trønnes, Javier Martinez Canillas, Daniel Vetter,
	David Airlie, Maarten Lankhorst, Maxime Ripard

Add support to convert from XR24 to reversed monochrome for drivers that
control monochromatic display panels, that only have 1 bit per pixel.

The function does a line-by-line conversion doing an intermediate step
first from XR24 to 8-bit grayscale and then to reversed monochrome.

The drm_fb_gray8_to_mono_reversed_line() helper was based on code from
drivers/gpu/drm/tiny/repaper.c driver.

Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
Reviewed-by: Thomas Zimmermann <tzimmermann@suse.de>
---

Changes in v4:
- Rename end_offset to end_len (Thomas Zimmermann)
- Warn once if dst_pitch is not a multiple of 8 (Thomas Zimmermann)
- Drop drm_fb_gray8_to_mono_reversed() that's not used (Thomas Zimmermann)
- Allocate single buffer for both copy cma memory and gray8 (Thomas Zimmermann)
- Add Thomas Zimmermann Reviewed-by tag to patch adding XR24 -> mono helper.

Changes in v3:
- Also add a drm_fb_xrgb8888_to_mono_reversed() helper (Thomas Zimmermann)
- Split lines copy to drm_fb_gray8_to_mono_reversed_line() (Thomas Zimmermann)
- Handle case where the source buffer is not aligned to 8 (Thomas Zimmermann)

 drivers/gpu/drm/drm_format_helper.c | 107 ++++++++++++++++++++++++++++
 include/drm/drm_format_helper.h     |   4 ++
 2 files changed, 111 insertions(+)

diff --git a/drivers/gpu/drm/drm_format_helper.c b/drivers/gpu/drm/drm_format_helper.c
index b981712623d3..ec4e3724ee79 100644
--- a/drivers/gpu/drm/drm_format_helper.c
+++ b/drivers/gpu/drm/drm_format_helper.c
@@ -591,3 +591,110 @@ int drm_fb_blit_toio(void __iomem *dst, unsigned int dst_pitch, uint32_t dst_for
 	return -EINVAL;
 }
 EXPORT_SYMBOL(drm_fb_blit_toio);
+
+static void drm_fb_gray8_to_mono_reversed_line(u8 *dst, const u8 *src, unsigned int pixels,
+					       unsigned int start_offset, unsigned int end_len)
+{
+	unsigned int xb, i;
+
+	for (xb = 0; xb < pixels; xb++) {
+		unsigned int start = 0, end = 8;
+		u8 byte = 0x00;
+
+		if (xb == 0 && start_offset)
+			start = start_offset;
+
+		if (xb == pixels - 1 && end_len)
+			end = end_len;
+
+		for (i = start; i < end; i++) {
+			unsigned int x = xb * 8 + i;
+
+			byte >>= 1;
+			if (src[x] >> 7)
+				byte |= BIT(7);
+		}
+		*dst++ = byte;
+	}
+}
+
+/**
+ * drm_fb_xrgb8888_to_mono_reversed - Convert XRGB8888 to reversed monochrome
+ * @dst: reversed monochrome destination buffer
+ * @dst_pitch: Number of bytes between two consecutive scanlines within dst
+ * @src: XRGB8888 source buffer
+ * @fb: DRM framebuffer
+ * @clip: Clip rectangle area to copy
+ *
+ * DRM doesn't have native monochrome support.
+ * Such drivers can announce the commonly supported XR24 format to userspace
+ * and use this function to convert to the native format.
+ *
+ * This function uses drm_fb_xrgb8888_to_gray8() to convert to grayscale and
+ * then the result is converted from grayscale to reversed monohrome.
+ */
+void drm_fb_xrgb8888_to_mono_reversed(void *dst, unsigned int dst_pitch, const void *vaddr,
+				      const struct drm_framebuffer *fb, const struct drm_rect *clip)
+{
+	unsigned int linepixels = drm_rect_width(clip);
+	unsigned int lines = clip->y2 - clip->y1;
+	unsigned int cpp = fb->format->cpp[0];
+	unsigned int len_src32 = linepixels * cpp;
+	unsigned int start_offset, end_len;
+	unsigned int y;
+	u8 *mono = dst, *gray8;
+	u32 *src32;
+
+	if (WARN_ON(fb->format->format != DRM_FORMAT_XRGB8888))
+		return;
+
+	/*
+	 * The reversed mono destination buffer contains 1 bit per pixel
+	 * and destination scanlines have to be in multiple of 8 pixels.
+	 */
+	if (!dst_pitch)
+		dst_pitch = DIV_ROUND_UP(linepixels, 8);
+
+	WARN_ONCE(dst_pitch % 8 != 0, "dst_pitch is not a multiple of 8\n");
+
+	/*
+	 * The cma memory is write-combined so reads are uncached.
+	 * Speed up by fetching one line at a time.
+	 *
+	 * Also, format conversion from XR24 to reversed monochrome
+	 * are done line-by-line but are converted to 8-bit grayscale
+	 * as an intermediate step.
+	 *
+	 * Allocate a buffer to be used for both copying from the cma
+	 * memory and to store the intermediate grayscale line pixels.
+	 */
+	src32 = kmalloc(len_src32 + linepixels, GFP_KERNEL);
+	if (!src32)
+		return;
+
+	gray8 = (u8 *)src32 + len_src32;
+
+	/*
+	 * For damage handling, it is possible that only parts of the source
+	 * buffer is copied and this could lead to start and end pixels that
+	 * are not aligned to multiple of 8.
+	 *
+	 * Calculate if the start and end pixels are not aligned and set the
+	 * offsets for the reversed mono line conversion function to adjust.
+	 */
+	start_offset = clip->x1 % 8;
+	end_len = clip->x2 % 8;
+
+	vaddr += clip_offset(clip, fb->pitches[0], cpp);
+	for (y = 0; y < lines; y++) {
+		src32 = memcpy(src32, vaddr, len_src32);
+		drm_fb_xrgb8888_to_gray8_line(gray8, src32, linepixels);
+		drm_fb_gray8_to_mono_reversed_line(mono, gray8, dst_pitch,
+						   start_offset, end_len);
+		vaddr += fb->pitches[0];
+		mono += dst_pitch;
+	}
+
+	kfree(src32);
+}
+EXPORT_SYMBOL(drm_fb_xrgb8888_to_mono_reversed);
diff --git a/include/drm/drm_format_helper.h b/include/drm/drm_format_helper.h
index b30ed5de0a33..0b0937c0b2f6 100644
--- a/include/drm/drm_format_helper.h
+++ b/include/drm/drm_format_helper.h
@@ -43,4 +43,8 @@ int drm_fb_blit_toio(void __iomem *dst, unsigned int dst_pitch, uint32_t dst_for
 		     const void *vmap, const struct drm_framebuffer *fb,
 		     const struct drm_rect *rect);
 
+void drm_fb_xrgb8888_to_mono_reversed(void *dst, unsigned int dst_pitch, const void *src,
+				      const struct drm_framebuffer *fb,
+				      const struct drm_rect *clip);
+
 #endif /* __LINUX_DRM_FORMAT_HELPER_H */
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH v4 3/6] drm: Add driver for Solomon SSD130x OLED displays
  2022-02-11  9:19 [PATCH v4 0/6] drm: Add driver for Solomon SSD130x OLED displays Javier Martinez Canillas
  2022-02-11  9:19 ` [PATCH v4 1/6] drm/format-helper: Add drm_fb_xrgb8888_to_gray8_line() Javier Martinez Canillas
  2022-02-11  9:19 ` [PATCH v4 2/6] drm/format-helper: Add drm_fb_xrgb8888_to_mono_reversed() Javier Martinez Canillas
@ 2022-02-11  9:19 ` Javier Martinez Canillas
  2022-02-11 11:33   ` Andy Shevchenko
  2022-02-11 12:44   ` Thomas Zimmermann
  2022-02-11  9:19 ` [PATCH v4 4/6] drm/solomon: Add SSD130x OLED displays I2C support Javier Martinez Canillas
                   ` (2 subsequent siblings)
  5 siblings, 2 replies; 43+ messages in thread
From: Javier Martinez Canillas @ 2022-02-11  9:19 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-fbdev, Geert Uytterhoeven, Andy Shevchenko, Maxime Ripard,
	Daniel Vetter, dri-devel, Thomas Zimmermann, Sam Ravnborg,
	Noralf Trønnes, Javier Martinez Canillas, Daniel Vetter,
	David Airlie, Lee Jones, Maarten Lankhorst, Maxime Ripard,
	Thierry Reding, Uwe Kleine-König, linux-pwm

This adds a DRM driver for SSD1305, SSD1306, SSD1307 and SSD1309 Solomon
OLED display controllers.

It's only the core part of the driver and a bus specific driver is needed
for each transport interface supported by the display controllers.

Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
---

Changes in v4:
- Rename vbat supply to vcc since is how's labeled in the device (Mark Brown)
- Don't make the regulator option since is always needed (Mark Brown)
- Add solomon Kconfig source and directory inclusion sorted (Andy Shevchenko)
- Use SSD130x instead of SSD130X to denote is not a model name (Andy Shevchenko)
- Check if there's a reset pin in the callee and not the caller (Andy Shevchenko)
- Define missing commands instead of using magic numbers (Andy Shevchenko)
- Use GENMASK() and FIELD_PREP() macros when possible (Andy Shevchenko)
- Avoid using ternary operators to ease code readablity (Andy Shevchenko)
- Use i++ instead of --i on some for loops (Andy Shevchenko)
- Remove redundant blank lines (Andy Shevchenko)
- Rename power_off label to out_power_off (Andy Shevchenko)
- Use dev_err_probe() even if no -EPROBE_DEFER (Andy Shevchenko)
- Don't use plural Authors if there's only one (Andy Shevchenko)

Changes in v3:
- Move driver from tiny sub-dir to drivers/gpu/drm/solomon (Sam Ravnborg)
- Split driver in a bus agnostic core and bus specific (Andy Shevchenko)
- Use regmap to access the chip registers (Andy Shevchenko)
- Remove unnecessary blank lines (Andy Shevchenko)
- Remove unneeded inline specifier in functions (Andy Shevchenko)
- Add a comment about always returning a single mode (Andy Shevchenko)
- Change write command logic to use do while loop (Andy Shevchenko)
- Use "firmware description" instead of "device tree" (Andy Shevchenko)
- Use return foo() instead of returning the return value (Andy Shevchenko)
- Don't split lines longer than 80 chars if makes less readable (Andy Shevchenko)
- Remove redundant else statements in .mode_valid callback (Andy Shevchenko)
- Rename powero{n,ff}() functions to power_o{n,ff)() (Andy Shevchenko)
- Use dev_err_probe() to prevent spam logs on probe deferral (Andy Shevchenko)
- Remove ',' after sentinel terminator in array (Andy Shevchenko)
- Fix a bug when doing partial updates (Geert Uytterhoeven)

Changes in v2:
- Drop patch that was adding a DRM_MODE_CONNECTOR_I2C type.
- Invert order of backlight {en,dis}able and display {on,off} (Sam Ravnborg)
- Don't clear the screen and turn on display on probe (Sam Ravnborg)
- Use backlight_get_brightness() macro to get BL brightness (Sam Ravnborg)
- Use dev managed version of devm_backlight_device_register() (Sam Ravnborg)
- Use dev_name(dev) for backlight name instead of an array (Sam Ravnborg)
- Drop the .get_brightness callback since isn't needed  (Sam Ravnborg)
- Rename driver to ssd130x since supports a display family (Thomas Zimmermann)
- Drop the TINY prefix from the Kconfig symbol (Thomas Zimmermann)
- Sort the Kconfig symbol dependencies alphabetically (Thomas Zimmermann)
- Rename struct ssd130x_array to struct ssd130x_i2c_msg (Thomas Zimmermann)
- Rename struct ssd130x_i2c_msg .type member to .cmd (Thomas Zimmermann)
- Use sizeof(*foo) instead of sizeof(struct foo) (Thomas Zimmermann)
- Use struct_size() macro to calculate sizeof(*foo) + len (Thomas Zimmermann)
- Use kcalloc() instead of kmalloc_array() + memset() (Thomas Zimmermann)
- Use shadow plane helpers virtual screen support (Thomas Zimmermann)
- Remove unused goto label in ssd1307_fb_blit_rect() (Thomas Zimmermann)
- Use drm_set_preferred_mode() inset of manually set (Thomas Zimmermann)
- Use shadow plane helpers virtual screen support (Thomas Zimmermann)
- Remove unused goto label in ssd1307_fb_blit_rect() (Thomas Zimmermann)
- Use drm_set_preferred_mode() inset of manually set (Thomas Zimmermann)
- Reorganize code in probe to make it more legible (Thomas Zimmermann)
- ssd130x_write_cmd() uses varargs to simplify I2C code (Thomas Zimmermann)
- Move regulator/pwm init logic to display pipe enable callback.

 drivers/gpu/drm/Kconfig           |   2 +
 drivers/gpu/drm/Makefile          |   1 +
 drivers/gpu/drm/solomon/Kconfig   |  12 +
 drivers/gpu/drm/solomon/Makefile  |   1 +
 drivers/gpu/drm/solomon/ssd130x.c | 852 ++++++++++++++++++++++++++++++
 drivers/gpu/drm/solomon/ssd130x.h |  76 +++
 6 files changed, 944 insertions(+)
 create mode 100644 drivers/gpu/drm/solomon/Kconfig
 create mode 100644 drivers/gpu/drm/solomon/Makefile
 create mode 100644 drivers/gpu/drm/solomon/ssd130x.c
 create mode 100644 drivers/gpu/drm/solomon/ssd130x.h

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index dfdd3ec5f793..763355330b17 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -403,6 +403,8 @@ source "drivers/gpu/drm/xlnx/Kconfig"
 
 source "drivers/gpu/drm/gud/Kconfig"
 
+source "drivers/gpu/drm/solomon/Kconfig"
+
 source "drivers/gpu/drm/sprd/Kconfig"
 
 config DRM_HYPERV
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 8675c2af7ae1..c2ef5f9fce54 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -132,4 +132,5 @@ obj-$(CONFIG_DRM_TIDSS) += tidss/
 obj-y			+= xlnx/
 obj-y			+= gud/
 obj-$(CONFIG_DRM_HYPERV) += hyperv/
+obj-y			+= solomon/
 obj-$(CONFIG_DRM_SPRD) += sprd/
diff --git a/drivers/gpu/drm/solomon/Kconfig b/drivers/gpu/drm/solomon/Kconfig
new file mode 100644
index 000000000000..7720a7039e8d
--- /dev/null
+++ b/drivers/gpu/drm/solomon/Kconfig
@@ -0,0 +1,12 @@
+config DRM_SSD130X
+	tristate "DRM support for Solomon SSD130x OLED displays"
+	depends on DRM
+	select BACKLIGHT_CLASS_DEVICE
+	select DRM_GEM_SHMEM_HELPER
+	select DRM_KMS_HELPER
+	help
+	  DRM driver for the SSD1305, SSD1306, SSD1307 and SSD1309 Solomon
+	  OLED controllers. This is only for the core driver, a driver for
+	  the appropriate bus transport in your chip also must be selected.
+
+	  If M is selected the module will be called ssd130x.
diff --git a/drivers/gpu/drm/solomon/Makefile b/drivers/gpu/drm/solomon/Makefile
new file mode 100644
index 000000000000..f685addb19fe
--- /dev/null
+++ b/drivers/gpu/drm/solomon/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_DRM_SSD130X)	+= ssd130x.o
diff --git a/drivers/gpu/drm/solomon/ssd130x.c b/drivers/gpu/drm/solomon/ssd130x.c
new file mode 100644
index 000000000000..e17cf52b222e
--- /dev/null
+++ b/drivers/gpu/drm/solomon/ssd130x.c
@@ -0,0 +1,852 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * DRM driver for Solomon SSD130x OLED displays
+ *
+ * Copyright 2022 Red Hat Inc.
+ * Author: Javier Martinez Canillas <javierm@redhat.com>
+ *
+ * Based on drivers/video/fbdev/ssd1307fb.c
+ * Copyright 2012 Free Electrons
+ */
+
+#include <linux/backlight.h>
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/property.h>
+#include <linux/pwm.h>
+#include <linux/regulator/consumer.h>
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_damage_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_format_helper.h>
+#include <drm/drm_gem_atomic_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_gem_shmem_helper.h>
+#include <drm/drm_managed.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_rect.h>
+#include <drm/drm_probe_helper.h>
+
+#include "ssd130x.h"
+
+#define DRIVER_NAME	"ssd130x"
+#define DRIVER_DESC	"DRM driver for Solomon SSD130x OLED displays"
+#define DRIVER_DATE	"20220131"
+#define DRIVER_MAJOR	1
+#define DRIVER_MINOR	0
+
+#define SSD130X_DATA				0x40
+#define SSD130X_COMMAND				0x80
+
+#define SSD130X_SET_ADDRESS_MODE		0x20
+#define SSD130X_SET_COL_RANGE			0x21
+#define SSD130X_SET_PAGE_RANGE			0x22
+#define SSD130X_CONTRAST			0x81
+#define SSD130X_SET_LOOKUP_TABLE		0x91
+#define SSD130X_CHARGE_PUMP			0x8d
+#define SSD130X_SEG_REMAP_ON			0xa1
+#define SSD130X_DISPLAY_OFF			0xae
+#define SSD130X_SET_MULTIPLEX_RATIO		0xa8
+#define SSD130X_DISPLAY_ON			0xaf
+#define SSD130X_START_PAGE_ADDRESS		0xb0
+#define SSD130X_SET_COM_SCAN_DIR		0xc0
+#define SSD130X_SET_DISPLAY_OFFSET		0xd3
+#define SSD130X_SET_CLOCK_FREQ			0xd5
+#define SSD130X_SET_AREA_COLOR_MODE		0xd8
+#define SSD130X_SET_PRECHARGE_PERIOD		0xd9
+#define SSD130X_SET_COM_PINS_CONFIG		0xda
+#define SSD130X_SET_VCOMH			0xdb
+
+#define SSD130X_SET_COM_SCAN_DIR_MASK		GENMASK(3, 2)
+#define SSD130X_SET_COM_SCAN_DIR_SET(val)	FIELD_PREP(SSD130X_SET_COM_SCAN_DIR_MASK, (val))
+#define SSD130X_SET_CLOCK_DIV_MASK		GENMASK(3, 0)
+#define SSD130X_SET_CLOCK_DIV_SET(val)		FIELD_PREP(SSD130X_SET_CLOCK_DIV_MASK, (val))
+#define SSD130X_SET_CLOCK_FREQ_MASK		GENMASK(7, 4)
+#define SSD130X_SET_CLOCK_FREQ_SET(val)		FIELD_PREP(SSD130X_SET_CLOCK_FREQ_MASK, (val))
+#define SSD130X_SET_PRECHARGE_PERIOD1_MASK	GENMASK(3, 0)
+#define SSD130X_SET_PRECHARGE_PERIOD1_SET(val)	FIELD_PREP(SSD130X_SET_PRECHARGE_PERIOD1_MASK, (val))
+#define SSD130X_SET_PRECHARGE_PERIOD2_MASK	GENMASK(7, 4)
+#define SSD130X_SET_PRECHARGE_PERIOD2_SET(val)	FIELD_PREP(SSD130X_SET_PRECHARGE_PERIOD2_MASK, (val))
+#define SSD130X_SET_COM_PINS_CONFIG1_MASK	GENMASK(4, 4)
+#define SSD130X_SET_COM_PINS_CONFIG1_SET(val)	FIELD_PREP(SSD130X_SET_COM_PINS_CONFIG1_MASK, (!val))
+#define SSD130X_SET_COM_PINS_CONFIG2_MASK	GENMASK(5, 5)
+#define SSD130X_SET_COM_PINS_CONFIG2_SET(val)	FIELD_PREP(SSD130X_SET_COM_PINS_CONFIG2_MASK, (val))
+
+#define SSD130X_SET_ADDRESS_MODE_HORIZONTAL	(0x00)
+#define SSD130X_SET_ADDRESS_MODE_VERTICAL	(0x01)
+#define SSD130X_SET_ADDRESS_MODE_PAGE		(0x02)
+
+#define SSD130X_SET_AREA_COLOR_MODE_ENABLE	(0x1e)
+#define SSD130X_SET_AREA_COLOR_MODE_LOW_POWER	(0x05)
+
+#define MAX_CONTRAST 255
+
+static inline struct ssd130x_device *drm_to_ssd130x(struct drm_device *drm)
+{
+	return container_of(drm, struct ssd130x_device, drm);
+}
+
+/*
+ * Helper to write data (SSD130X_DATA) to the device.
+ */
+static int ssd130x_write_data(struct ssd130x_device *ssd130x, u8 *values, int count)
+{
+	int ret;
+
+	ret = regmap_bulk_write(ssd130x->regmap, SSD130X_DATA, values, count);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+/*
+ * Helper to write command (SSD130X_COMMAND). The fist variadic argument
+ * is the command to write and the following are the command options.
+ */
+static int ssd130x_write_cmd(struct ssd130x_device *ssd130x, int count,
+				    /* u8 cmd, u8 option, ... */...)
+{
+	va_list ap;
+	u8 value;
+	int ret;
+
+	va_start(ap, count);
+
+	do {
+		value = va_arg(ap, int);
+		ret = regmap_write(ssd130x->regmap, SSD130X_COMMAND, (u8)value);
+		if (ret)
+			goto out_end;
+	} while (--count);
+
+out_end:
+	va_end(ap);
+
+	return ret;
+}
+
+static int ssd130x_set_col_range(struct ssd130x_device *ssd130x,
+				 u8 col_start, u8 cols)
+{
+	u8 col_end = col_start + cols - 1;
+	int ret;
+
+	if (col_start == ssd130x->col_start && col_end == ssd130x->col_end)
+		return 0;
+
+	ret = ssd130x_write_cmd(ssd130x, 3, SSD130X_SET_COL_RANGE, col_start, col_end);
+	if (ret < 0)
+		return ret;
+
+	ssd130x->col_start = col_start;
+	ssd130x->col_end = col_end;
+	return 0;
+}
+
+static int ssd130x_set_page_range(struct ssd130x_device *ssd130x,
+				  u8 page_start, u8 pages)
+{
+	u8 page_end = page_start + pages - 1;
+	int ret;
+
+	if (page_start == ssd130x->page_start && page_end == ssd130x->page_end)
+		return 0;
+
+	ret = ssd130x_write_cmd(ssd130x, 3, SSD130X_SET_PAGE_RANGE, page_start, page_end);
+	if (ret < 0)
+		return ret;
+
+	ssd130x->page_start = page_start;
+	ssd130x->page_end = page_end;
+	return 0;
+}
+
+static int ssd130x_pwm_enable(struct ssd130x_device *ssd130x)
+{
+	struct device *dev = ssd130x->dev;
+	struct pwm_state pwmstate;
+
+	ssd130x->pwm = pwm_get(dev, NULL);
+	if (IS_ERR(ssd130x->pwm)) {
+		dev_err(dev, "Could not get PWM from firmware description!\n");
+		return PTR_ERR(ssd130x->pwm);
+	}
+
+	pwm_init_state(ssd130x->pwm, &pwmstate);
+	pwm_set_relative_duty_cycle(&pwmstate, 50, 100);
+	pwm_apply_state(ssd130x->pwm, &pwmstate);
+
+	/* Enable the PWM */
+	pwm_enable(ssd130x->pwm);
+
+	dev_dbg(dev, "Using PWM%d with a %lluns period.\n",
+		ssd130x->pwm->pwm, pwm_get_period(ssd130x->pwm));
+
+	return 0;
+}
+
+static void ssd130x_reset(struct ssd130x_device *ssd130x)
+{
+	if (!ssd130x->reset)
+		return;
+
+	/* Reset the screen */
+	gpiod_set_value_cansleep(ssd130x->reset, 1);
+	udelay(4);
+	gpiod_set_value_cansleep(ssd130x->reset, 0);
+	udelay(4);
+}
+
+static int ssd130x_power_on(struct ssd130x_device *ssd130x)
+{
+	struct device *dev = ssd130x->dev;
+	int ret;
+
+	ssd130x_reset(ssd130x);
+
+	ret = regulator_enable(ssd130x->vcc_reg);
+	if (ret) {
+		dev_err(dev, "Failed to enable VCC: %d\n", ret);
+		return ret;
+	}
+
+	if (ssd130x->device_info->need_pwm) {
+		ret = ssd130x_pwm_enable(ssd130x);
+		if (ret) {
+			dev_err(dev, "Failed to enable PWM: %d\n", ret);
+			regulator_disable(ssd130x->vcc_reg);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static void ssd130x_power_off(struct ssd130x_device *ssd130x)
+{
+	if (ssd130x->device_info->need_pwm) {
+		pwm_disable(ssd130x->pwm);
+		pwm_put(ssd130x->pwm);
+	}
+
+	regulator_disable(ssd130x->vcc_reg);
+}
+
+static int ssd130x_init(struct ssd130x_device *ssd130x)
+{
+	u32 precharge, dclk, com_invdir, compins, chargepump;
+	int ret;
+
+	/* Set initial contrast */
+	ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_CONTRAST, ssd130x->contrast);
+	if (ret < 0)
+		return ret;
+
+	/* Set segment re-map */
+	if (ssd130x->seg_remap) {
+		ret = ssd130x_write_cmd(ssd130x, 1, SSD130X_SEG_REMAP_ON);
+		if (ret < 0)
+			return ret;
+	}
+
+	/* Set COM direction */
+	com_invdir = (SSD130X_SET_COM_SCAN_DIR |
+		      SSD130X_SET_COM_SCAN_DIR_SET(ssd130x->com_invdir));
+	ret = ssd130x_write_cmd(ssd130x,  1, com_invdir);
+	if (ret < 0)
+		return ret;
+
+	/* Set multiplex ratio value */
+	ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_MULTIPLEX_RATIO, ssd130x->height - 1);
+	if (ret < 0)
+		return ret;
+
+	/* set display offset value */
+	ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_DISPLAY_OFFSET, ssd130x->com_offset);
+	if (ret < 0)
+		return ret;
+
+	/* Set clock frequency */
+	dclk = (SSD130X_SET_CLOCK_DIV_SET(ssd130x->dclk_div - 1) |
+		SSD130X_SET_CLOCK_FREQ_SET(ssd130x->dclk_frq));
+	ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_CLOCK_FREQ, dclk);
+	if (ret < 0)
+		return ret;
+
+	/* Set Area Color Mode ON/OFF & Low Power Display Mode */
+	if (ssd130x->area_color_enable || ssd130x->low_power) {
+		u32 mode = 0;
+
+		if (ssd130x->area_color_enable)
+			mode |= SSD130X_SET_AREA_COLOR_MODE_ENABLE;
+
+		if (ssd130x->low_power)
+			mode |= SSD130X_SET_AREA_COLOR_MODE_LOW_POWER;
+
+		ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_AREA_COLOR_MODE, mode);
+		if (ret < 0)
+			return ret;
+	}
+
+	/* Set precharge period in number of ticks from the internal clock */
+	precharge = (SSD130X_SET_PRECHARGE_PERIOD1_SET(ssd130x->prechargep1) |
+		     SSD130X_SET_PRECHARGE_PERIOD1_SET(ssd130x->prechargep2));
+	ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_PRECHARGE_PERIOD, precharge);
+	if (ret < 0)
+		return ret;
+
+	/* Set COM pins configuration */
+	compins = BIT(1);
+	compins |= (SSD130X_SET_COM_PINS_CONFIG1_SET(ssd130x->com_seq) |
+		    SSD130X_SET_COM_PINS_CONFIG2_SET(ssd130x->com_lrremap));
+	ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_COM_PINS_CONFIG, compins);
+	if (ret < 0)
+		return ret;
+
+
+	/* Set VCOMH */
+	ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_VCOMH, ssd130x->vcomh);
+	if (ret < 0)
+		return ret;
+
+	/* Turn on the DC-DC Charge Pump */
+	chargepump = BIT(4);
+
+	if (ssd130x->device_info->need_chargepump)
+		chargepump |= BIT(2);
+
+	ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_CHARGE_PUMP, chargepump);
+	if (ret < 0)
+		return ret;
+
+	/* Set lookup table */
+	if (ssd130x->lookup_table_set) {
+		int i;
+
+		ret = ssd130x_write_cmd(ssd130x, 1, SSD130X_SET_LOOKUP_TABLE);
+		if (ret < 0)
+			return ret;
+
+		for (i = 0; i < ARRAY_SIZE(ssd130x->lookup_table); i++) {
+			u8 val = ssd130x->lookup_table[i];
+
+			if (val < 31 || val > 63)
+				dev_warn(ssd130x->dev,
+					 "lookup table index %d value out of range 31 <= %d <= 63\n",
+					 i, val);
+			ret = ssd130x_write_cmd(ssd130x, 1, val);
+			if (ret < 0)
+				return ret;
+		}
+	}
+
+	/* Switch to horizontal addressing mode */
+	return ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_ADDRESS_MODE,
+				 SSD130X_SET_ADDRESS_MODE_HORIZONTAL);
+}
+
+static int ssd130x_update_rect(struct ssd130x_device *ssd130x, u8 *buf,
+			       struct drm_rect *rect)
+{
+	unsigned int x = rect->x1;
+	unsigned int y = rect->y1;
+	unsigned int width = drm_rect_width(rect);
+	unsigned int height = drm_rect_height(rect);
+	unsigned int line_length = DIV_ROUND_UP(width, 8);
+	unsigned int pages = DIV_ROUND_UP(y % 8 + height, 8);
+	u32 array_idx = 0;
+	int ret, i, j, k;
+	u8 *data_array = NULL;
+
+	data_array = kcalloc(width, pages, GFP_KERNEL);
+	if (!data_array)
+		return -ENOMEM;
+
+	/*
+	 * The screen is divided in pages, each having a height of 8
+	 * pixels, and the width of the screen. When sending a byte of
+	 * data to the controller, it gives the 8 bits for the current
+	 * column. I.e, the first byte are the 8 bits of the first
+	 * column, then the 8 bits for the second column, etc.
+	 *
+	 *
+	 * Representation of the screen, assuming it is 5 bits
+	 * wide. Each letter-number combination is a bit that controls
+	 * one pixel.
+	 *
+	 * A0 A1 A2 A3 A4
+	 * B0 B1 B2 B3 B4
+	 * C0 C1 C2 C3 C4
+	 * D0 D1 D2 D3 D4
+	 * E0 E1 E2 E3 E4
+	 * F0 F1 F2 F3 F4
+	 * G0 G1 G2 G3 G4
+	 * H0 H1 H2 H3 H4
+	 *
+	 * If you want to update this screen, you need to send 5 bytes:
+	 *  (1) A0 B0 C0 D0 E0 F0 G0 H0
+	 *  (2) A1 B1 C1 D1 E1 F1 G1 H1
+	 *  (3) A2 B2 C2 D2 E2 F2 G2 H2
+	 *  (4) A3 B3 C3 D3 E3 F3 G3 H3
+	 *  (5) A4 B4 C4 D4 E4 F4 G4 H4
+	 */
+
+	ret = ssd130x_set_col_range(ssd130x, ssd130x->col_offset + x, width);
+	if (ret < 0)
+		goto out_free;
+
+	ret = ssd130x_set_page_range(ssd130x, ssd130x->page_offset + y / 8, pages);
+	if (ret < 0)
+		goto out_free;
+
+	for (i = y / 8; i < y / 8 + pages; i++) {
+		int m = 8;
+
+		/* Last page may be partial */
+		if (8 * (i + 1) > ssd130x->height)
+			m = ssd130x->height % 8;
+		for (j = x; j < x + width; j++) {
+			u8 data = 0;
+
+			for (k = 0; k < m; k++) {
+				u8 byte = buf[(8 * i + k) * line_length + j / 8];
+				u8 bit = (byte >> (j % 8)) & 1;
+
+				data |= bit << k;
+			}
+			data_array[array_idx++] = data;
+		}
+	}
+
+	ret = ssd130x_write_data(ssd130x, data_array, width * pages);
+
+out_free:
+	kfree(data_array);
+	return ret;
+}
+
+static void ssd130x_clear_screen(struct ssd130x_device *ssd130x)
+{
+	u8 *buf = NULL;
+	struct drm_rect fullscreen = {
+		.x1 = 0,
+		.x2 = ssd130x->width,
+		.y1 = 0,
+		.y2 = ssd130x->height,
+	};
+
+	buf = kcalloc(ssd130x->width, ssd130x->height, GFP_KERNEL);
+	if (!buf)
+		return;
+
+	ssd130x_update_rect(ssd130x, buf, &fullscreen);
+
+	kfree(buf);
+}
+
+static int ssd130x_fb_blit_rect(struct drm_framebuffer *fb, const struct dma_buf_map *map,
+				struct drm_rect *rect)
+{
+	struct ssd130x_device *ssd130x = drm_to_ssd130x(fb->dev);
+	void *vmap = map->vaddr; /* TODO: Use mapping abstraction properly */
+	int ret = 0;
+	u8 *buf = NULL;
+
+	buf = kcalloc(fb->width, fb->height, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	drm_fb_xrgb8888_to_mono_reversed(buf, 0, vmap, fb, rect);
+
+	ssd130x_update_rect(ssd130x, buf, rect);
+
+	kfree(buf);
+
+	return ret;
+}
+
+static int ssd130x_display_pipe_mode_valid(struct drm_simple_display_pipe *pipe,
+					   const struct drm_display_mode *mode)
+{
+	struct ssd130x_device *ssd130x = drm_to_ssd130x(pipe->crtc.dev);
+
+	if (mode->hdisplay != ssd130x->mode.hdisplay &&
+	    mode->vdisplay != ssd130x->mode.vdisplay)
+		return MODE_ONE_SIZE;
+
+	if (mode->hdisplay != ssd130x->mode.hdisplay)
+		return MODE_ONE_WIDTH;
+
+	if (mode->vdisplay != ssd130x->mode.vdisplay)
+		return MODE_ONE_HEIGHT;
+
+	return MODE_OK;
+}
+
+static void ssd130x_display_pipe_enable(struct drm_simple_display_pipe *pipe,
+					struct drm_crtc_state *crtc_state,
+					struct drm_plane_state *plane_state)
+{
+	struct ssd130x_device *ssd130x = drm_to_ssd130x(pipe->crtc.dev);
+	struct drm_device *drm = &ssd130x->drm;
+	int idx, ret;
+
+	ret = ssd130x_power_on(ssd130x);
+	if (ret)
+		return;
+
+	ret = ssd130x_init(ssd130x);
+	if (ret)
+		goto out_power_off;
+
+	if (!drm_dev_enter(drm, &idx))
+		goto out_power_off;
+
+	ssd130x_clear_screen(ssd130x);
+
+	ssd130x_write_cmd(ssd130x, 1, SSD130X_DISPLAY_ON);
+
+	backlight_enable(ssd130x->bl_dev);
+
+	drm_dev_exit(idx);
+
+	return;
+out_power_off:
+	ssd130x_power_off(ssd130x);
+}
+
+static void ssd130x_display_pipe_disable(struct drm_simple_display_pipe *pipe)
+{
+	struct ssd130x_device *ssd130x = drm_to_ssd130x(pipe->crtc.dev);
+	struct drm_device *drm = &ssd130x->drm;
+	int idx;
+
+	if (!drm_dev_enter(drm, &idx))
+		return;
+
+	ssd130x_clear_screen(ssd130x);
+
+	backlight_disable(ssd130x->bl_dev);
+
+	ssd130x_write_cmd(ssd130x, 1, SSD130X_DISPLAY_OFF);
+
+	ssd130x_power_off(ssd130x);
+
+	drm_dev_exit(idx);
+}
+
+static void ssd130x_display_pipe_update(struct drm_simple_display_pipe *pipe,
+					struct drm_plane_state *old_plane_state)
+{
+	struct ssd130x_device *ssd130x = drm_to_ssd130x(pipe->crtc.dev);
+	struct drm_plane_state *plane_state = pipe->plane.state;
+	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
+	struct drm_framebuffer *fb = plane_state->fb;
+	struct drm_device *drm = &ssd130x->drm;
+	struct drm_rect src_clip, dst_clip;
+	int idx;
+
+	if (!fb)
+		return;
+
+	if (!pipe->crtc.state->active)
+		return;
+
+	if (!drm_atomic_helper_damage_merged(old_plane_state, plane_state, &src_clip))
+		return;
+
+	dst_clip = plane_state->dst;
+	if (!drm_rect_intersect(&dst_clip, &src_clip))
+		return;
+
+	if (!drm_dev_enter(drm, &idx))
+		return;
+
+	ssd130x_fb_blit_rect(plane_state->fb, &shadow_plane_state->data[0], &dst_clip);
+
+	drm_dev_exit(idx);
+}
+
+static const struct drm_simple_display_pipe_funcs ssd130x_pipe_funcs = {
+	.mode_valid = ssd130x_display_pipe_mode_valid,
+	.enable = ssd130x_display_pipe_enable,
+	.disable = ssd130x_display_pipe_disable,
+	.update = ssd130x_display_pipe_update,
+	DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS,
+};
+
+static int ssd130x_connector_get_modes(struct drm_connector *connector)
+{
+	struct ssd130x_device *ssd130x = drm_to_ssd130x(connector->dev);
+	struct drm_display_mode *mode = &ssd130x->mode;
+	struct device *dev = ssd130x->dev;
+
+	mode = drm_mode_duplicate(connector->dev, &ssd130x->mode);
+	if (!mode) {
+		dev_err(dev, "Failed to duplicated mode\n");
+		return 0;
+	}
+
+	drm_mode_probed_add(connector, mode);
+	drm_set_preferred_mode(connector, mode->hdisplay, mode->vdisplay);
+
+	/* There is only a single mode */
+	return 1;
+}
+
+static const struct drm_connector_helper_funcs ssd130x_connector_helper_funcs = {
+	.get_modes = ssd130x_connector_get_modes,
+};
+
+static const struct drm_connector_funcs ssd130x_connector_funcs = {
+	.reset = drm_atomic_helper_connector_reset,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.destroy = drm_connector_cleanup,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static const struct drm_mode_config_funcs ssd130x_mode_config_funcs = {
+	.fb_create = drm_gem_fb_create_with_dirty,
+	.atomic_check = drm_atomic_helper_check,
+	.atomic_commit = drm_atomic_helper_commit,
+};
+
+static const uint32_t ssd130x_formats[] = {
+	DRM_FORMAT_XRGB8888,
+};
+
+DEFINE_DRM_GEM_FOPS(ssd130x_fops);
+
+static const struct drm_driver ssd130x_drm_driver = {
+	DRM_GEM_SHMEM_DRIVER_OPS,
+	.name			= DRIVER_NAME,
+	.desc			= DRIVER_DESC,
+	.date			= DRIVER_DATE,
+	.major			= DRIVER_MAJOR,
+	.minor			= DRIVER_MINOR,
+	.driver_features	= DRIVER_ATOMIC | DRIVER_GEM | DRIVER_MODESET,
+	.fops			= &ssd130x_fops,
+};
+
+static int ssd130x_update_bl(struct backlight_device *bdev)
+{
+	struct ssd130x_device *ssd130x = bl_get_data(bdev);
+	int brightness = backlight_get_brightness(bdev);
+	int ret;
+
+	ssd130x->contrast = brightness;
+
+	ret = ssd130x_write_cmd(ssd130x, 1, SSD130X_CONTRAST);
+	if (ret < 0)
+		return ret;
+
+	ret = ssd130x_write_cmd(ssd130x, 1, ssd130x->contrast);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static const struct backlight_ops ssd130xfb_bl_ops = {
+	.update_status	= ssd130x_update_bl,
+};
+
+static void ssd130x_parse_properties(struct ssd130x_device *ssd130x)
+{
+	struct device *dev = ssd130x->dev;
+
+	if (device_property_read_u32(dev, "solomon,width", &ssd130x->width))
+		ssd130x->width = 96;
+
+	if (device_property_read_u32(dev, "solomon,height", &ssd130x->height))
+		ssd130x->height = 16;
+
+	if (device_property_read_u32(dev, "solomon,page-offset", &ssd130x->page_offset))
+		ssd130x->page_offset = 1;
+
+	if (device_property_read_u32(dev, "solomon,col-offset", &ssd130x->col_offset))
+		ssd130x->col_offset = 0;
+
+	if (device_property_read_u32(dev, "solomon,com-offset", &ssd130x->com_offset))
+		ssd130x->com_offset = 0;
+
+	if (device_property_read_u32(dev, "solomon,prechargep1", &ssd130x->prechargep1))
+		ssd130x->prechargep1 = 2;
+
+	if (device_property_read_u32(dev, "solomon,prechargep2", &ssd130x->prechargep2))
+		ssd130x->prechargep2 = 2;
+
+	if (!device_property_read_u8_array(dev, "solomon,lookup-table",
+					   ssd130x->lookup_table,
+					   ARRAY_SIZE(ssd130x->lookup_table)))
+		ssd130x->lookup_table_set = 1;
+
+	ssd130x->seg_remap = !device_property_read_bool(dev, "solomon,segment-no-remap");
+	ssd130x->com_seq = device_property_read_bool(dev, "solomon,com-seq");
+	ssd130x->com_lrremap = device_property_read_bool(dev, "solomon,com-lrremap");
+	ssd130x->com_invdir = device_property_read_bool(dev, "solomon,com-invdir");
+	ssd130x->area_color_enable =
+		device_property_read_bool(dev, "solomon,area-color-enable");
+	ssd130x->low_power = device_property_read_bool(dev, "solomon,low-power");
+
+	ssd130x->contrast = 127;
+	ssd130x->vcomh = ssd130x->device_info->default_vcomh;
+
+	/* Setup display timing */
+	if (device_property_read_u32(dev, "solomon,dclk-div", &ssd130x->dclk_div))
+		ssd130x->dclk_div = ssd130x->device_info->default_dclk_div;
+	if (device_property_read_u32(dev, "solomon,dclk-frq", &ssd130x->dclk_frq))
+		ssd130x->dclk_frq = ssd130x->device_info->default_dclk_frq;
+}
+
+static int ssd130x_init_modeset(struct ssd130x_device *ssd130x)
+{
+	struct drm_display_mode *mode = &ssd130x->mode;
+	struct device *dev = ssd130x->dev;
+	struct drm_device *drm = &ssd130x->drm;
+	unsigned long max_width, max_height;
+	int ret;
+
+	ret = drmm_mode_config_init(drm);
+	if (ret) {
+		dev_err(dev, "DRM mode config init failed: %d\n", ret);
+		return ret;
+	}
+
+	mode->type = DRM_MODE_TYPE_DRIVER;
+	mode->clock = 1;
+	mode->hdisplay = mode->htotal = ssd130x->width;
+	mode->hsync_start = mode->hsync_end = ssd130x->width;
+	mode->vdisplay = mode->vtotal = ssd130x->height;
+	mode->vsync_start = mode->vsync_end = ssd130x->height;
+	mode->width_mm = 27;
+	mode->height_mm = 27;
+
+	max_width = max_t(unsigned long, mode->hdisplay, DRM_SHADOW_PLANE_MAX_WIDTH);
+	max_height = max_t(unsigned long, mode->vdisplay, DRM_SHADOW_PLANE_MAX_HEIGHT);
+
+	drm->mode_config.min_width = mode->hdisplay;
+	drm->mode_config.max_width = max_width;
+	drm->mode_config.min_height = mode->vdisplay;
+	drm->mode_config.max_height = max_height;
+	drm->mode_config.preferred_depth = 32;
+	drm->mode_config.funcs = &ssd130x_mode_config_funcs;
+
+	ret = drm_connector_init(drm, &ssd130x->connector, &ssd130x_connector_funcs,
+				 DRM_MODE_CONNECTOR_Unknown);
+	if (ret) {
+		dev_err(dev, "DRM connector init failed: %d\n", ret);
+		return ret;
+	}
+
+	drm_connector_helper_add(&ssd130x->connector, &ssd130x_connector_helper_funcs);
+
+	ret = drm_simple_display_pipe_init(drm, &ssd130x->pipe, &ssd130x_pipe_funcs,
+					   ssd130x_formats, ARRAY_SIZE(ssd130x_formats),
+					   NULL, &ssd130x->connector);
+	if (ret) {
+		dev_err(dev, "DRM simple display pipeline init failed: %d\n", ret);
+		return ret;
+	}
+
+	drm_plane_enable_fb_damage_clips(&ssd130x->pipe.plane);
+
+	drm_mode_config_reset(drm);
+
+	return 0;
+}
+
+static int ssd130x_get_resources(struct ssd130x_device *ssd130x)
+{
+	struct device *dev = ssd130x->dev;
+
+	ssd130x->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
+	if (IS_ERR(ssd130x->reset))
+		return dev_err_probe(dev, PTR_ERR(ssd130x->reset),
+				     "Failed to get reset gpio\n");
+
+	ssd130x->vcc_reg = devm_regulator_get(dev, "vcc");
+	if (IS_ERR(ssd130x->vcc_reg))
+		return dev_err_probe(dev, PTR_ERR(ssd130x->vcc_reg),
+				     "Failed to get VCC regulator\n");
+
+	return 0;
+}
+
+struct ssd130x_device *ssd130x_probe(struct device *dev, struct regmap *regmap)
+{
+	struct ssd130x_device *ssd130x;
+	struct backlight_device *bl;
+	struct drm_device *drm;
+	int ret;
+
+	ssd130x = devm_drm_dev_alloc(dev, &ssd130x_drm_driver,
+				     struct ssd130x_device, drm);
+	if (IS_ERR(ssd130x)) {
+		dev_err_probe(dev, PTR_ERR(ssd130x),
+			      "Failed to allocate DRM device\n");
+		return ssd130x;
+	}
+
+	drm = &ssd130x->drm;
+
+	ssd130x->dev = dev;
+	ssd130x->regmap = regmap;
+	ssd130x->device_info = device_get_match_data(dev);
+
+	ssd130x_parse_properties(ssd130x);
+
+	ret = ssd130x_get_resources(ssd130x);
+	if (ret)
+		return ERR_PTR(ret);
+
+	bl = devm_backlight_device_register(dev, dev_name(dev), dev, ssd130x,
+					    &ssd130xfb_bl_ops, NULL);
+	if (IS_ERR(bl)) {
+		ret = PTR_ERR(bl);
+		dev_err_probe(dev, ret, "Unable to register backlight device\n");
+		return ERR_PTR(ret);
+	}
+
+	bl->props.brightness = ssd130x->contrast;
+	bl->props.max_brightness = MAX_CONTRAST;
+	ssd130x->bl_dev = bl;
+
+	ret = ssd130x_init_modeset(ssd130x);
+	if (ret)
+		return ERR_PTR(ret);
+
+	ret = drm_dev_register(drm, 0);
+	if (ret) {
+		dev_err_probe(dev, ret, "DRM device register failed\n");
+		return ERR_PTR(ret);
+	}
+
+	drm_fbdev_generic_setup(drm, 0);
+
+	return ssd130x;
+}
+EXPORT_SYMBOL_GPL(ssd130x_probe);
+
+int ssd130x_remove(struct ssd130x_device *ssd130x)
+{
+	drm_dev_unplug(&ssd130x->drm);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ssd130x_remove);
+
+void ssd130x_shutdown(struct ssd130x_device *ssd130x)
+{
+	drm_atomic_helper_shutdown(&ssd130x->drm);
+}
+EXPORT_SYMBOL_GPL(ssd130x_shutdown);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Javier Martinez Canillas <javierm@redhat.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/solomon/ssd130x.h b/drivers/gpu/drm/solomon/ssd130x.h
new file mode 100644
index 000000000000..754953b261b0
--- /dev/null
+++ b/drivers/gpu/drm/solomon/ssd130x.h
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Header file for:
+ * DRM driver for Solomon SSD130x OLED displays
+ *
+ * Copyright 2022 Red Hat Inc.
+ * Authors: Javier Martinez Canillas <javierm@redhat.com>
+ *
+ * Based on drivers/video/fbdev/ssd1307fb.c
+ * Copyright 2012 Free Electrons
+ */
+
+#ifndef __SSD1307X_H__
+#define __SSD1307X_H__
+
+#include <drm/drm_drv.h>
+#include <drm/drm_simple_kms_helper.h>
+
+#include <linux/regmap.h>
+
+struct ssd130x_deviceinfo {
+	u32 default_vcomh;
+	u32 default_dclk_div;
+	u32 default_dclk_frq;
+	int need_pwm;
+	int need_chargepump;
+};
+
+struct ssd130x_device {
+	struct drm_device drm;
+	struct device *dev;
+	struct drm_simple_display_pipe pipe;
+	struct drm_display_mode mode;
+	struct drm_connector connector;
+	struct i2c_client *client;
+
+	struct regmap *regmap;
+
+	const struct ssd130x_deviceinfo *device_info;
+
+	unsigned area_color_enable : 1;
+	unsigned com_invdir : 1;
+	unsigned com_lrremap : 1;
+	unsigned com_seq : 1;
+	unsigned lookup_table_set : 1;
+	unsigned low_power : 1;
+	unsigned seg_remap : 1;
+	u32 com_offset;
+	u32 contrast;
+	u32 dclk_div;
+	u32 dclk_frq;
+	u32 height;
+	u8 lookup_table[4];
+	u32 page_offset;
+	u32 col_offset;
+	u32 prechargep1;
+	u32 prechargep2;
+
+	struct backlight_device *bl_dev;
+	struct pwm_device *pwm;
+	struct gpio_desc *reset;
+	struct regulator *vcc_reg;
+	u32 vcomh;
+	u32 width;
+	/* Cached address ranges */
+	u8 col_start;
+	u8 col_end;
+	u8 page_start;
+	u8 page_end;
+};
+
+struct ssd130x_device *ssd130x_probe(struct device *dev, struct regmap *regmap);
+int ssd130x_remove(struct ssd130x_device *ssd130x);
+void ssd130x_shutdown(struct ssd130x_device *ssd130x);
+
+#endif /* __SSD1307X_H__ */
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH v4 4/6] drm/solomon: Add SSD130x OLED displays I2C support
  2022-02-11  9:19 [PATCH v4 0/6] drm: Add driver for Solomon SSD130x OLED displays Javier Martinez Canillas
                   ` (2 preceding siblings ...)
  2022-02-11  9:19 ` [PATCH v4 3/6] drm: Add driver for Solomon SSD130x OLED displays Javier Martinez Canillas
@ 2022-02-11  9:19 ` Javier Martinez Canillas
  2022-02-11 11:16   ` Andy Shevchenko
  2022-02-11  9:21 ` [PATCH v4 5/6] MAINTAINERS: Add entry for Solomon SSD130x OLED displays DRM driver Javier Martinez Canillas
  2022-02-11  9:22 ` [PATCH v4 6/6] dt-bindings: display: ssd1307fb: Add myself as binding co-maintainer Javier Martinez Canillas
  5 siblings, 1 reply; 43+ messages in thread
From: Javier Martinez Canillas @ 2022-02-11  9:19 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-fbdev, Geert Uytterhoeven, Andy Shevchenko, Maxime Ripard,
	Daniel Vetter, dri-devel, Thomas Zimmermann, Sam Ravnborg,
	Noralf Trønnes, Javier Martinez Canillas, Daniel Vetter,
	David Airlie

The ssd130x driver only provides the core support for these devices but it
does not have any bus transport logic. Add a driver to interface over I2C.

Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
---

Changes in v4:
- Remove unnecessary casting (Geert Uytterhoeven)
- Remove redundant blank lines (Andy Shevchenko)
- Remove comma after of_device_id table terminator (Andy Shevchenko)

Changes in v3:
- Add a separate driver for SSD130X chips I2C support (Andy Shevchenko)

 drivers/gpu/drm/solomon/Kconfig       |   9 ++
 drivers/gpu/drm/solomon/Makefile      |   1 +
 drivers/gpu/drm/solomon/ssd130x-i2c.c | 116 ++++++++++++++++++++++++++
 3 files changed, 126 insertions(+)
 create mode 100644 drivers/gpu/drm/solomon/ssd130x-i2c.c

diff --git a/drivers/gpu/drm/solomon/Kconfig b/drivers/gpu/drm/solomon/Kconfig
index 7720a7039e8d..5861c3ab7c45 100644
--- a/drivers/gpu/drm/solomon/Kconfig
+++ b/drivers/gpu/drm/solomon/Kconfig
@@ -10,3 +10,12 @@ config DRM_SSD130X
 	  the appropriate bus transport in your chip also must be selected.
 
 	  If M is selected the module will be called ssd130x.
+
+config DRM_SSD130X_I2C
+	tristate "DRM support for Solomon SSD130x OLED displays (I2C bus)"
+	depends on DRM_SSD130X && I2C
+	select REGMAP_I2C
+	help
+	  Say Y here if the SSD130x OLED display is connected via I2C bus.
+
+	  If M is selected the module will be called ssd130x-i2c.
diff --git a/drivers/gpu/drm/solomon/Makefile b/drivers/gpu/drm/solomon/Makefile
index f685addb19fe..4bfc5acb0447 100644
--- a/drivers/gpu/drm/solomon/Makefile
+++ b/drivers/gpu/drm/solomon/Makefile
@@ -1 +1,2 @@
 obj-$(CONFIG_DRM_SSD130X)	+= ssd130x.o
+obj-$(CONFIG_DRM_SSD130X_I2C)	+= ssd130x-i2c.o
diff --git a/drivers/gpu/drm/solomon/ssd130x-i2c.c b/drivers/gpu/drm/solomon/ssd130x-i2c.c
new file mode 100644
index 000000000000..3126aeda4ced
--- /dev/null
+++ b/drivers/gpu/drm/solomon/ssd130x-i2c.c
@@ -0,0 +1,116 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * DRM driver for Solomon SSD130x OLED displays (I2C bus)
+ *
+ * Copyright 2022 Red Hat Inc.
+ * Author: Javier Martinez Canillas <javierm@redhat.com>
+ *
+ * Based on drivers/video/fbdev/ssd1307fb.c
+ * Copyright 2012 Free Electrons
+ */
+#include <linux/i2c.h>
+#include <linux/module.h>
+
+#include "ssd130x.h"
+
+#define DRIVER_NAME	"ssd130x-i2c"
+#define DRIVER_DESC	"DRM driver for Solomon SSD130x OLED displays (I2C)"
+
+static const struct regmap_config ssd130x_i2c_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+};
+
+static int ssd130x_i2c_probe(struct i2c_client *client)
+{
+	struct ssd130x_device *ssd130x;
+	struct regmap *regmap;
+
+	regmap = devm_regmap_init_i2c(client, &ssd130x_i2c_regmap_config);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	ssd130x = ssd130x_probe(&client->dev, regmap);
+	if (IS_ERR(ssd130x))
+		return PTR_ERR(ssd130x);
+
+	i2c_set_clientdata(client, ssd130x);
+
+	return 0;
+}
+
+static int ssd130x_i2c_remove(struct i2c_client *client)
+{
+	struct ssd130x_device *ssd130x = i2c_get_clientdata(client);
+
+	return ssd130x_remove(ssd130x);
+}
+
+static void ssd130x_i2c_shutdown(struct i2c_client *client)
+{
+	struct ssd130x_device *ssd130x = i2c_get_clientdata(client);
+
+	ssd130x_shutdown(ssd130x);
+}
+
+static struct ssd130x_deviceinfo ssd130x_ssd1305_deviceinfo = {
+	.default_vcomh = 0x34,
+	.default_dclk_div = 1,
+	.default_dclk_frq = 7,
+};
+
+static struct ssd130x_deviceinfo ssd130x_ssd1306_deviceinfo = {
+	.default_vcomh = 0x20,
+	.default_dclk_div = 1,
+	.default_dclk_frq = 8,
+	.need_chargepump = 1,
+};
+
+static struct ssd130x_deviceinfo ssd130x_ssd1307_deviceinfo = {
+	.default_vcomh = 0x20,
+	.default_dclk_div = 2,
+	.default_dclk_frq = 12,
+	.need_pwm = 1,
+};
+
+static struct ssd130x_deviceinfo ssd130x_ssd1309_deviceinfo = {
+	.default_vcomh = 0x34,
+	.default_dclk_div = 1,
+	.default_dclk_frq = 10,
+};
+
+static const struct of_device_id ssd130x_of_match[] = {
+	{
+		.compatible = "solomon,ssd1305fb-i2c",
+		.data = &ssd130x_ssd1305_deviceinfo,
+	},
+	{
+		.compatible = "solomon,ssd1306fb-i2c",
+		.data = &ssd130x_ssd1306_deviceinfo,
+	},
+	{
+		.compatible = "solomon,ssd1307fb-i2c",
+		.data = &ssd130x_ssd1307_deviceinfo,
+	},
+	{
+		.compatible = "solomon,ssd1309fb-i2c",
+		.data = &ssd130x_ssd1309_deviceinfo,
+	},
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, ssd130x_of_match);
+
+static struct i2c_driver ssd130x_i2c_driver = {
+	.driver = {
+		.name = DRIVER_NAME,
+		.of_match_table = ssd130x_of_match,
+	},
+	.probe_new = ssd130x_i2c_probe,
+	.remove = ssd130x_i2c_remove,
+	.shutdown = ssd130x_i2c_shutdown,
+};
+module_i2c_driver(ssd130x_i2c_driver);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Javier Martinez Canillas <javierm@redhat.com>");
+MODULE_LICENSE("GPL v2");
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH v4 5/6] MAINTAINERS: Add entry for Solomon SSD130x OLED displays DRM driver
  2022-02-11  9:19 [PATCH v4 0/6] drm: Add driver for Solomon SSD130x OLED displays Javier Martinez Canillas
                   ` (3 preceding siblings ...)
  2022-02-11  9:19 ` [PATCH v4 4/6] drm/solomon: Add SSD130x OLED displays I2C support Javier Martinez Canillas
@ 2022-02-11  9:21 ` Javier Martinez Canillas
  2022-02-11 11:34   ` Andy Shevchenko
  2022-02-11  9:22 ` [PATCH v4 6/6] dt-bindings: display: ssd1307fb: Add myself as binding co-maintainer Javier Martinez Canillas
  5 siblings, 1 reply; 43+ messages in thread
From: Javier Martinez Canillas @ 2022-02-11  9:21 UTC (permalink / raw)
  To: linux-kernel
  Cc: Andy Shevchenko, Daniel Vetter, Geert Uytterhoeven,
	Maxime Ripard, Noralf Trønnes, dri-devel, linux-fbdev,
	Javier Martinez Canillas, Sam Ravnborg

To make sure that tools like the get_maintainer.pl script will suggest
to Cc me if patches are posted for this driver.

Also include the Device Tree binding for the old ssd1307fb fbdev driver
since the new DRM driver was made compatible with the existing binding.

Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
Acked-by: Sam Ravnborg <sam@ravnborg.org>
---

(no changes since v3)

Changes in v3:
- Adapt MAINTAINERS entry to point to the new drivers/gpu/drm/solomon directory.

Changes in v2:
- Add Sam Ravnborg's acked-by to patch adding a MAINTAINERS entry (Sam Ravnborg)

 MAINTAINERS | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index d03ad8da1f36..05c306986ab0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6102,6 +6102,13 @@ T:	git git://anongit.freedesktop.org/drm/drm-misc
 F:	Documentation/devicetree/bindings/display/repaper.txt
 F:	drivers/gpu/drm/tiny/repaper.c
 
+DRM DRIVER FOR SOLOMON SSD130X OLED DISPLAYS
+M:	Javier Martinez Canillas <javierm@redhat.com>
+S:	Maintained
+T:	git git://anongit.freedesktop.org/drm/drm-misc
+F:	Documentation/devicetree/bindings/display/solomon,ssd1307fb.yaml
+F:	drivers/gpu/drm/solomon/ssd130x*
+
 DRM DRIVER FOR QEMU'S CIRRUS DEVICE
 M:	Dave Airlie <airlied@redhat.com>
 M:	Gerd Hoffmann <kraxel@redhat.com>
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH v4 6/6] dt-bindings: display: ssd1307fb: Add myself as binding co-maintainer
  2022-02-11  9:19 [PATCH v4 0/6] drm: Add driver for Solomon SSD130x OLED displays Javier Martinez Canillas
                   ` (4 preceding siblings ...)
  2022-02-11  9:21 ` [PATCH v4 5/6] MAINTAINERS: Add entry for Solomon SSD130x OLED displays DRM driver Javier Martinez Canillas
@ 2022-02-11  9:22 ` Javier Martinez Canillas
  2022-02-11 11:35   ` Andy Shevchenko
  5 siblings, 1 reply; 43+ messages in thread
From: Javier Martinez Canillas @ 2022-02-11  9:22 UTC (permalink / raw)
  To: linux-kernel
  Cc: Andy Shevchenko, Daniel Vetter, Geert Uytterhoeven,
	Maxime Ripard, Noralf Trønnes, dri-devel, linux-fbdev,
	Javier Martinez Canillas, Sam Ravnborg, Rob Herring

The ssd130x DRM driver also makes use of this Device Tree binding to allow
existing users of the fbdev driver to migrate without the need to change
their Device Trees.

Add myself as another maintainer of the binding, to make sure that I will
be on Cc when patches are proposed for it.

Suggested-by: Sam Ravnborg <sam@ravnborg.org>
Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
Acked-by: Rob Herring <robh@kernel.org>
---

Changes in v4:
- Add Rob Herring Acked-by tag to patch adding as DT binding co-maintainer.

Changes in v2:
- Add myself as co-maintainer of the ssd1370fb DT binding (Sam Ravnborg).

 Documentation/devicetree/bindings/display/solomon,ssd1307fb.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/display/solomon,ssd1307fb.yaml b/Documentation/devicetree/bindings/display/solomon,ssd1307fb.yaml
index 2ed2a7d0ca2f..9baafd0c42dd 100644
--- a/Documentation/devicetree/bindings/display/solomon,ssd1307fb.yaml
+++ b/Documentation/devicetree/bindings/display/solomon,ssd1307fb.yaml
@@ -8,6 +8,7 @@ title: Solomon SSD1307 OLED Controller Framebuffer
 
 maintainers:
   - Maxime Ripard <mripard@kernel.org>
+  - Javier Martinez Canillas <javierm@redhat.com>
 
 properties:
   compatible:
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 1/6] drm/format-helper: Add drm_fb_xrgb8888_to_gray8_line()
  2022-02-11  9:19 ` [PATCH v4 1/6] drm/format-helper: Add drm_fb_xrgb8888_to_gray8_line() Javier Martinez Canillas
@ 2022-02-11  9:29   ` Thomas Zimmermann
  2022-02-11 10:28   ` Andy Shevchenko
  1 sibling, 0 replies; 43+ messages in thread
From: Thomas Zimmermann @ 2022-02-11  9:29 UTC (permalink / raw)
  To: Javier Martinez Canillas, linux-kernel
  Cc: linux-fbdev, David Airlie, Daniel Vetter, dri-devel,
	Noralf Trønnes, Geert Uytterhoeven, Maxime Ripard,
	Andy Shevchenko, Sam Ravnborg


[-- Attachment #1.1: Type: text/plain, Size: 2934 bytes --]



Am 11.02.22 um 10:19 schrieb Javier Martinez Canillas:
> Pull the per-line conversion logic into a separate helper function.
> 
> This will allow to do line-by-line conversion in other helpers that
> convert to a gray8 format.
> 
> Suggested-by: Thomas Zimmermann <tzimmermann@suse.de>
> Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>

Reviewed-by: Thomas Zimmermann <tzimmermann@suse.de>

> ---
> 
> (no changes since v3)
> 
> Changes in v3:
> - Add a drm_fb_xrgb8888_to_gray8_line() helper function (Thomas Zimmermann)
> 
>   drivers/gpu/drm/drm_format_helper.c | 31 ++++++++++++++++++-----------
>   1 file changed, 19 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_format_helper.c b/drivers/gpu/drm/drm_format_helper.c
> index 0f28dd2bdd72..b981712623d3 100644
> --- a/drivers/gpu/drm/drm_format_helper.c
> +++ b/drivers/gpu/drm/drm_format_helper.c
> @@ -464,6 +464,21 @@ void drm_fb_xrgb8888_to_xrgb2101010_toio(void __iomem *dst,
>   }
>   EXPORT_SYMBOL(drm_fb_xrgb8888_to_xrgb2101010_toio);
>   
> +static void drm_fb_xrgb8888_to_gray8_line(u8 *dst, const u32 *src, unsigned int pixels)
> +{
> +	unsigned int x;
> +
> +	for (x = 0; x < pixels; x++) {
> +		u8 r = (*src & 0x00ff0000) >> 16;
> +		u8 g = (*src & 0x0000ff00) >> 8;
> +		u8 b =  *src & 0x000000ff;
> +
> +		/* ITU BT.601: Y = 0.299 R + 0.587 G + 0.114 B */
> +		*dst++ = (3 * r + 6 * g + b) / 10;
> +		src++;
> +	}
> +}
> +
>   /**
>    * drm_fb_xrgb8888_to_gray8 - Convert XRGB8888 to grayscale
>    * @dst: 8-bit grayscale destination buffer
> @@ -484,8 +499,9 @@ EXPORT_SYMBOL(drm_fb_xrgb8888_to_xrgb2101010_toio);
>   void drm_fb_xrgb8888_to_gray8(void *dst, unsigned int dst_pitch, const void *vaddr,
>   			      const struct drm_framebuffer *fb, const struct drm_rect *clip)
>   {
> -	unsigned int len = (clip->x2 - clip->x1) * sizeof(u32);
> -	unsigned int x, y;
> +	unsigned int linepixels = clip->x2 - clip->x1;
> +	unsigned int len = linepixels * sizeof(u32);
> +	unsigned int y;
>   	void *buf;
>   	u8 *dst8;
>   	u32 *src32;
> @@ -508,16 +524,7 @@ void drm_fb_xrgb8888_to_gray8(void *dst, unsigned int dst_pitch, const void *vad
>   	for (y = clip->y1; y < clip->y2; y++) {
>   		dst8 = dst;
>   		src32 = memcpy(buf, vaddr, len);
> -		for (x = clip->x1; x < clip->x2; x++) {
> -			u8 r = (*src32 & 0x00ff0000) >> 16;
> -			u8 g = (*src32 & 0x0000ff00) >> 8;
> -			u8 b =  *src32 & 0x000000ff;
> -
> -			/* ITU BT.601: Y = 0.299 R + 0.587 G + 0.114 B */
> -			*dst8++ = (3 * r + 6 * g + b) / 10;
> -			src32++;
> -		}
> -
> +		drm_fb_xrgb8888_to_gray8_line(dst8, src32, linepixels);
>   		vaddr += fb->pitches[0];
>   		dst += dst_pitch;
>   	}

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Ivo Totev

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 1/6] drm/format-helper: Add drm_fb_xrgb8888_to_gray8_line()
  2022-02-11  9:19 ` [PATCH v4 1/6] drm/format-helper: Add drm_fb_xrgb8888_to_gray8_line() Javier Martinez Canillas
  2022-02-11  9:29   ` Thomas Zimmermann
@ 2022-02-11 10:28   ` Andy Shevchenko
  2022-02-11 10:40     ` Javier Martinez Canillas
  1 sibling, 1 reply; 43+ messages in thread
From: Andy Shevchenko @ 2022-02-11 10:28 UTC (permalink / raw)
  To: Javier Martinez Canillas
  Cc: linux-kernel, linux-fbdev, Geert Uytterhoeven, Maxime Ripard,
	Daniel Vetter, dri-devel, Thomas Zimmermann, Sam Ravnborg,
	Noralf Trønnes, Daniel Vetter, David Airlie,
	Maarten Lankhorst, Maxime Ripard

On Fri, Feb 11, 2022 at 10:19:22AM +0100, Javier Martinez Canillas wrote:
> Pull the per-line conversion logic into a separate helper function.
> 
> This will allow to do line-by-line conversion in other helpers that
> convert to a gray8 format.

...

> +static void drm_fb_xrgb8888_to_gray8_line(u8 *dst, const u32 *src, unsigned int pixels)
> +{
> +	unsigned int x;
> +
> +	for (x = 0; x < pixels; x++) {
> +		u8 r = (*src & 0x00ff0000) >> 16;
> +		u8 g = (*src & 0x0000ff00) >> 8;
> +		u8 b =  *src & 0x000000ff;
> +
> +		/* ITU BT.601: Y = 0.299 R + 0.587 G + 0.114 B */
> +		*dst++ = (3 * r + 6 * g + b) / 10;
> +		src++;
> +	}

Can be done as

	while (pixels--) {
		...
	}

or

	do {
		...
	} while (--pixels);

> +}


-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 1/6] drm/format-helper: Add drm_fb_xrgb8888_to_gray8_line()
  2022-02-11 10:28   ` Andy Shevchenko
@ 2022-02-11 10:40     ` Javier Martinez Canillas
  2022-02-11 11:12       ` Andy Shevchenko
  0 siblings, 1 reply; 43+ messages in thread
From: Javier Martinez Canillas @ 2022-02-11 10:40 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: linux-kernel, linux-fbdev, Geert Uytterhoeven, Maxime Ripard,
	Daniel Vetter, dri-devel, Thomas Zimmermann, Sam Ravnborg,
	Noralf Trønnes, Daniel Vetter, David Airlie,
	Maarten Lankhorst, Maxime Ripard

Hello Andy,

On 2/11/22 11:28, Andy Shevchenko wrote:
> On Fri, Feb 11, 2022 at 10:19:22AM +0100, Javier Martinez Canillas wrote:
>> Pull the per-line conversion logic into a separate helper function.
>>
>> This will allow to do line-by-line conversion in other helpers that
>> convert to a gray8 format.
> 
> ...
> 
>> +static void drm_fb_xrgb8888_to_gray8_line(u8 *dst, const u32 *src, unsigned int pixels)
>> +{
>> +	unsigned int x;
>> +
>> +	for (x = 0; x < pixels; x++) {
>> +		u8 r = (*src & 0x00ff0000) >> 16;
>> +		u8 g = (*src & 0x0000ff00) >> 8;
>> +		u8 b =  *src & 0x000000ff;
>> +
>> +		/* ITU BT.601: Y = 0.299 R + 0.587 G + 0.114 B */
>> +		*dst++ = (3 * r + 6 * g + b) / 10;
>> +		src++;
>> +	}
> 
> Can be done as
> 
> 	while (pixels--) {
> 		...
> 	}
> 
> or
> 
> 	do {
> 		...
> 	} while (--pixels);
> 

I don't see why a while loop would be an improvement here TBH.

In any case, I just pulled the line conversion logic as a separate
function with minimal code changes since doing that should be in a
separate patch.

Feel free to post a patch if you want to change that while loop.

Best regards,
-- 
Javier Martinez Canillas
Linux Engineering
Red Hat


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 2/6] drm/format-helper: Add drm_fb_xrgb8888_to_mono_reversed()
  2022-02-11  9:19 ` [PATCH v4 2/6] drm/format-helper: Add drm_fb_xrgb8888_to_mono_reversed() Javier Martinez Canillas
@ 2022-02-11 11:10   ` Andy Shevchenko
  2022-02-11 11:50     ` Javier Martinez Canillas
  2022-02-11 11:59     ` Thomas Zimmermann
  2022-02-11 12:46   ` Thomas Zimmermann
  1 sibling, 2 replies; 43+ messages in thread
From: Andy Shevchenko @ 2022-02-11 11:10 UTC (permalink / raw)
  To: Javier Martinez Canillas
  Cc: linux-kernel, linux-fbdev, Geert Uytterhoeven, Maxime Ripard,
	Daniel Vetter, dri-devel, Thomas Zimmermann, Sam Ravnborg,
	Noralf Trønnes, Daniel Vetter, David Airlie,
	Maarten Lankhorst, Maxime Ripard

On Fri, Feb 11, 2022 at 10:19:23AM +0100, Javier Martinez Canillas wrote:
> Add support to convert from XR24 to reversed monochrome for drivers that
> control monochromatic display panels, that only have 1 bit per pixel.
> 
> The function does a line-by-line conversion doing an intermediate step
> first from XR24 to 8-bit grayscale and then to reversed monochrome.
> 
> The drm_fb_gray8_to_mono_reversed_line() helper was based on code from
> drivers/gpu/drm/tiny/repaper.c driver.

...

> +static void drm_fb_gray8_to_mono_reversed_line(u8 *dst, const u8 *src, unsigned int pixels,
> +					       unsigned int start_offset, unsigned int end_len)
> +{
> +	unsigned int xb, i;
> +
> +	for (xb = 0; xb < pixels; xb++) {
> +		unsigned int start = 0, end = 8;
> +		u8 byte = 0x00;

> +		if (xb == 0 && start_offset)
> +			start = start_offset;

This is invariant to the loop, can be moved out.

> +		if (xb == pixels - 1 && end_len)
> +			end = end_len;

Ditto. However it may require to factor out the following loop to a helper.

> +		for (i = start; i < end; i++) {
> +			unsigned int x = xb * 8 + i;
> +
> +			byte >>= 1;
> +			if (src[x] >> 7)
> +				byte |= BIT(7);
> +		}
> +		*dst++ = byte;
> +	}
> +}

...

> +	/*
> +	 * The reversed mono destination buffer contains 1 bit per pixel
> +	 * and destination scanlines have to be in multiple of 8 pixels.
> +	 */
> +	if (!dst_pitch)
> +		dst_pitch = DIV_ROUND_UP(linepixels, 8);

round_up() ?

> +	WARN_ONCE(dst_pitch % 8 != 0, "dst_pitch is not a multiple of 8\n");


I would move this to the if conditional, i.e.

	if (dst_pitch)
		WARN_ONCE(dst_pitch % 8 != 0, "dst_pitch is not a multiple of 8\n");
	else
		dst_pitch = round_up(linepixels, 8);

> +	/*
> +	 * The cma memory is write-combined so reads are uncached.

CMA

> +	 * Speed up by fetching one line at a time.
> +	 *
> +	 * Also, format conversion from XR24 to reversed monochrome
> +	 * are done line-by-line but are converted to 8-bit grayscale
> +	 * as an intermediate step.
> +	 *
> +	 * Allocate a buffer to be used for both copying from the cma
> +	 * memory and to store the intermediate grayscale line pixels.
> +	 */
> +	src32 = kmalloc(len_src32 + linepixels, GFP_KERNEL);

size_add() ?

> +	if (!src32)
> +		return;

...

> +	/*
> +	 * For damage handling, it is possible that only parts of the source
> +	 * buffer is copied and this could lead to start and end pixels that
> +	 * are not aligned to multiple of 8.
> +	 *
> +	 * Calculate if the start and end pixels are not aligned and set the
> +	 * offsets for the reversed mono line conversion function to adjust.
> +	 */
> +	start_offset = clip->x1 % 8;
> +	end_len = clip->x2 % 8;

ALIGN() ?

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 1/6] drm/format-helper: Add drm_fb_xrgb8888_to_gray8_line()
  2022-02-11 10:40     ` Javier Martinez Canillas
@ 2022-02-11 11:12       ` Andy Shevchenko
  2022-02-11 11:54         ` Thomas Zimmermann
  0 siblings, 1 reply; 43+ messages in thread
From: Andy Shevchenko @ 2022-02-11 11:12 UTC (permalink / raw)
  To: Javier Martinez Canillas
  Cc: linux-kernel, linux-fbdev, Geert Uytterhoeven, Maxime Ripard,
	Daniel Vetter, dri-devel, Thomas Zimmermann, Sam Ravnborg,
	Noralf Trønnes, Daniel Vetter, David Airlie,
	Maarten Lankhorst, Maxime Ripard

On Fri, Feb 11, 2022 at 11:40:13AM +0100, Javier Martinez Canillas wrote:
> On 2/11/22 11:28, Andy Shevchenko wrote:
> > On Fri, Feb 11, 2022 at 10:19:22AM +0100, Javier Martinez Canillas wrote:

...

> >> +static void drm_fb_xrgb8888_to_gray8_line(u8 *dst, const u32 *src, unsigned int pixels)
> >> +{
> >> +	unsigned int x;
> >> +
> >> +	for (x = 0; x < pixels; x++) {
> >> +		u8 r = (*src & 0x00ff0000) >> 16;
> >> +		u8 g = (*src & 0x0000ff00) >> 8;
> >> +		u8 b =  *src & 0x000000ff;
> >> +
> >> +		/* ITU BT.601: Y = 0.299 R + 0.587 G + 0.114 B */
> >> +		*dst++ = (3 * r + 6 * g + b) / 10;
> >> +		src++;
> >> +	}
> > 
> > Can be done as
> > 
> > 	while (pixels--) {
> > 		...
> > 	}
> > 
> > or
> > 
> > 	do {
> > 		...
> > 	} while (--pixels);
> > 
> 
> I don't see why a while loop would be an improvement here TBH.

Less letters to parse when reading the code.

> In any case, I just pulled the line conversion logic as a separate
> function with minimal code changes since doing that should be in a
> separate patch.


> Feel free to post a patch if you want to change that while loop.

Perhaps some day :-)

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 4/6] drm/solomon: Add SSD130x OLED displays I2C support
  2022-02-11  9:19 ` [PATCH v4 4/6] drm/solomon: Add SSD130x OLED displays I2C support Javier Martinez Canillas
@ 2022-02-11 11:16   ` Andy Shevchenko
  0 siblings, 0 replies; 43+ messages in thread
From: Andy Shevchenko @ 2022-02-11 11:16 UTC (permalink / raw)
  To: Javier Martinez Canillas
  Cc: linux-kernel, linux-fbdev, Geert Uytterhoeven, Maxime Ripard,
	Daniel Vetter, dri-devel, Thomas Zimmermann, Sam Ravnborg,
	Noralf Trønnes, Daniel Vetter, David Airlie

On Fri, Feb 11, 2022 at 10:19:25AM +0100, Javier Martinez Canillas wrote:
> The ssd130x driver only provides the core support for these devices but it
> does not have any bus transport logic. Add a driver to interface over I2C.

Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>

> Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
> ---
> 
> Changes in v4:
> - Remove unnecessary casting (Geert Uytterhoeven)
> - Remove redundant blank lines (Andy Shevchenko)
> - Remove comma after of_device_id table terminator (Andy Shevchenko)
> 
> Changes in v3:
> - Add a separate driver for SSD130X chips I2C support (Andy Shevchenko)
> 
>  drivers/gpu/drm/solomon/Kconfig       |   9 ++
>  drivers/gpu/drm/solomon/Makefile      |   1 +
>  drivers/gpu/drm/solomon/ssd130x-i2c.c | 116 ++++++++++++++++++++++++++
>  3 files changed, 126 insertions(+)
>  create mode 100644 drivers/gpu/drm/solomon/ssd130x-i2c.c
> 
> diff --git a/drivers/gpu/drm/solomon/Kconfig b/drivers/gpu/drm/solomon/Kconfig
> index 7720a7039e8d..5861c3ab7c45 100644
> --- a/drivers/gpu/drm/solomon/Kconfig
> +++ b/drivers/gpu/drm/solomon/Kconfig
> @@ -10,3 +10,12 @@ config DRM_SSD130X
>  	  the appropriate bus transport in your chip also must be selected.
>  
>  	  If M is selected the module will be called ssd130x.
> +
> +config DRM_SSD130X_I2C
> +	tristate "DRM support for Solomon SSD130x OLED displays (I2C bus)"
> +	depends on DRM_SSD130X && I2C
> +	select REGMAP_I2C
> +	help
> +	  Say Y here if the SSD130x OLED display is connected via I2C bus.
> +
> +	  If M is selected the module will be called ssd130x-i2c.
> diff --git a/drivers/gpu/drm/solomon/Makefile b/drivers/gpu/drm/solomon/Makefile
> index f685addb19fe..4bfc5acb0447 100644
> --- a/drivers/gpu/drm/solomon/Makefile
> +++ b/drivers/gpu/drm/solomon/Makefile
> @@ -1 +1,2 @@
>  obj-$(CONFIG_DRM_SSD130X)	+= ssd130x.o
> +obj-$(CONFIG_DRM_SSD130X_I2C)	+= ssd130x-i2c.o
> diff --git a/drivers/gpu/drm/solomon/ssd130x-i2c.c b/drivers/gpu/drm/solomon/ssd130x-i2c.c
> new file mode 100644
> index 000000000000..3126aeda4ced
> --- /dev/null
> +++ b/drivers/gpu/drm/solomon/ssd130x-i2c.c
> @@ -0,0 +1,116 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * DRM driver for Solomon SSD130x OLED displays (I2C bus)
> + *
> + * Copyright 2022 Red Hat Inc.
> + * Author: Javier Martinez Canillas <javierm@redhat.com>
> + *
> + * Based on drivers/video/fbdev/ssd1307fb.c
> + * Copyright 2012 Free Electrons
> + */
> +#include <linux/i2c.h>
> +#include <linux/module.h>
> +
> +#include "ssd130x.h"
> +
> +#define DRIVER_NAME	"ssd130x-i2c"
> +#define DRIVER_DESC	"DRM driver for Solomon SSD130x OLED displays (I2C)"
> +
> +static const struct regmap_config ssd130x_i2c_regmap_config = {
> +	.reg_bits = 8,
> +	.val_bits = 8,
> +};
> +
> +static int ssd130x_i2c_probe(struct i2c_client *client)
> +{
> +	struct ssd130x_device *ssd130x;
> +	struct regmap *regmap;
> +
> +	regmap = devm_regmap_init_i2c(client, &ssd130x_i2c_regmap_config);
> +	if (IS_ERR(regmap))
> +		return PTR_ERR(regmap);
> +
> +	ssd130x = ssd130x_probe(&client->dev, regmap);
> +	if (IS_ERR(ssd130x))
> +		return PTR_ERR(ssd130x);
> +
> +	i2c_set_clientdata(client, ssd130x);
> +
> +	return 0;
> +}
> +
> +static int ssd130x_i2c_remove(struct i2c_client *client)
> +{
> +	struct ssd130x_device *ssd130x = i2c_get_clientdata(client);
> +
> +	return ssd130x_remove(ssd130x);
> +}
> +
> +static void ssd130x_i2c_shutdown(struct i2c_client *client)
> +{
> +	struct ssd130x_device *ssd130x = i2c_get_clientdata(client);
> +
> +	ssd130x_shutdown(ssd130x);
> +}
> +
> +static struct ssd130x_deviceinfo ssd130x_ssd1305_deviceinfo = {
> +	.default_vcomh = 0x34,
> +	.default_dclk_div = 1,
> +	.default_dclk_frq = 7,
> +};
> +
> +static struct ssd130x_deviceinfo ssd130x_ssd1306_deviceinfo = {
> +	.default_vcomh = 0x20,
> +	.default_dclk_div = 1,
> +	.default_dclk_frq = 8,
> +	.need_chargepump = 1,
> +};
> +
> +static struct ssd130x_deviceinfo ssd130x_ssd1307_deviceinfo = {
> +	.default_vcomh = 0x20,
> +	.default_dclk_div = 2,
> +	.default_dclk_frq = 12,
> +	.need_pwm = 1,
> +};
> +
> +static struct ssd130x_deviceinfo ssd130x_ssd1309_deviceinfo = {
> +	.default_vcomh = 0x34,
> +	.default_dclk_div = 1,
> +	.default_dclk_frq = 10,
> +};
> +
> +static const struct of_device_id ssd130x_of_match[] = {
> +	{
> +		.compatible = "solomon,ssd1305fb-i2c",
> +		.data = &ssd130x_ssd1305_deviceinfo,
> +	},
> +	{
> +		.compatible = "solomon,ssd1306fb-i2c",
> +		.data = &ssd130x_ssd1306_deviceinfo,
> +	},
> +	{
> +		.compatible = "solomon,ssd1307fb-i2c",
> +		.data = &ssd130x_ssd1307_deviceinfo,
> +	},
> +	{
> +		.compatible = "solomon,ssd1309fb-i2c",
> +		.data = &ssd130x_ssd1309_deviceinfo,
> +	},
> +	{ /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, ssd130x_of_match);
> +
> +static struct i2c_driver ssd130x_i2c_driver = {
> +	.driver = {
> +		.name = DRIVER_NAME,
> +		.of_match_table = ssd130x_of_match,
> +	},
> +	.probe_new = ssd130x_i2c_probe,
> +	.remove = ssd130x_i2c_remove,
> +	.shutdown = ssd130x_i2c_shutdown,
> +};
> +module_i2c_driver(ssd130x_i2c_driver);
> +
> +MODULE_DESCRIPTION(DRIVER_DESC);
> +MODULE_AUTHOR("Javier Martinez Canillas <javierm@redhat.com>");
> +MODULE_LICENSE("GPL v2");
> -- 
> 2.34.1
> 

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 3/6] drm: Add driver for Solomon SSD130x OLED displays
  2022-02-11  9:19 ` [PATCH v4 3/6] drm: Add driver for Solomon SSD130x OLED displays Javier Martinez Canillas
@ 2022-02-11 11:33   ` Andy Shevchenko
  2022-02-11 12:05     ` Javier Martinez Canillas
  2022-02-11 12:44   ` Thomas Zimmermann
  1 sibling, 1 reply; 43+ messages in thread
From: Andy Shevchenko @ 2022-02-11 11:33 UTC (permalink / raw)
  To: Javier Martinez Canillas
  Cc: linux-kernel, linux-fbdev, Geert Uytterhoeven, Maxime Ripard,
	Daniel Vetter, dri-devel, Thomas Zimmermann, Sam Ravnborg,
	Noralf Trønnes, Daniel Vetter, David Airlie, Lee Jones,
	Maarten Lankhorst, Maxime Ripard, Thierry Reding,
	Uwe Kleine-König, linux-pwm

On Fri, Feb 11, 2022 at 10:19:24AM +0100, Javier Martinez Canillas wrote:
> This adds a DRM driver for SSD1305, SSD1306, SSD1307 and SSD1309 Solomon
> OLED display controllers.
> 
> It's only the core part of the driver and a bus specific driver is needed
> for each transport interface supported by the display controllers.

...

> +#include <linux/backlight.h>
> +#include <linux/bitfield.h>

bits.h
(FYI, specifically sent a patch few days ago to add explicitly the inclusions
 that needed for bitfield operations in the example inside bitfield.h).

> +#include <linux/delay.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/property.h>
> +#include <linux/pwm.h>
> +#include <linux/regulator/consumer.h>

...

> +#define SSD130X_SET_ADDRESS_MODE_HORIZONTAL	(0x00)
> +#define SSD130X_SET_ADDRESS_MODE_VERTICAL	(0x01)
> +#define SSD130X_SET_ADDRESS_MODE_PAGE		(0x02)
> +
> +#define SSD130X_SET_AREA_COLOR_MODE_ENABLE	(0x1e)
> +#define SSD130X_SET_AREA_COLOR_MODE_LOW_POWER	(0x05)

Do the parentheses add anything here?

...

> +/*
> + * Helper to write command (SSD130X_COMMAND). The fist variadic argument
> + * is the command to write and the following are the command options.

This is not correct explanation. Please, rephrase to show that _each_ of the
options is sent with a preceding command.

> + */
> +static int ssd130x_write_cmd(struct ssd130x_device *ssd130x, int count,
> +				    /* u8 cmd, u8 option, ... */...)
> +{
> +	va_list ap;
> +	u8 value;
> +	int ret;
> +
> +	va_start(ap, count);
> +
> +	do {
> +		value = va_arg(ap, int);
> +		ret = regmap_write(ssd130x->regmap, SSD130X_COMMAND, (u8)value);
> +		if (ret)
> +			goto out_end;
> +	} while (--count);
> +
> +out_end:
> +	va_end(ap);
> +
> +	return ret;
> +}

...

> +	if (ssd130x->device_info->need_pwm) {

Yeah, unfortunately we still don't have pwm_get_optional()...

> +		ret = ssd130x_pwm_enable(ssd130x);
> +		if (ret) {
> +			dev_err(dev, "Failed to enable PWM: %d\n", ret);
> +			regulator_disable(ssd130x->vcc_reg);
> +			return ret;
> +		}
> +	}

...

> +static void ssd130x_power_off(struct ssd130x_device *ssd130x)
> +{

> +	if (ssd130x->device_info->need_pwm) {

Redundant check. The two below are NULL-aware.

> +		pwm_disable(ssd130x->pwm);
> +		pwm_put(ssd130x->pwm);
> +	}
> +
> +	regulator_disable(ssd130x->vcc_reg);
> +}

...

> +	ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_COM_PINS_CONFIG, compins);
> +	if (ret < 0)
> +		return ret;

> +
> +

One blank line is enough.

...

> +	for (i = y / 8; i < y / 8 + pages; i++) {
> +		int m = 8;
> +
> +		/* Last page may be partial */
> +		if (8 * (i + 1) > ssd130x->height)
> +			m = ssd130x->height % 8;

Perhaps it can be moved out of the loop with refactored piece below.

> +		for (j = x; j < x + width; j++) {
> +			u8 data = 0;
> +
> +			for (k = 0; k < m; k++) {
> +				u8 byte = buf[(8 * i + k) * line_length + j / 8];
> +				u8 bit = (byte >> (j % 8)) & 1;
> +
> +				data |= bit << k;
> +			}
> +			data_array[array_idx++] = data;
> +		}
> +	}

...

> +	bl = devm_backlight_device_register(dev, dev_name(dev), dev, ssd130x,
> +					    &ssd130xfb_bl_ops, NULL);
> +	if (IS_ERR(bl)) {

> +		ret = PTR_ERR(bl);
> +		dev_err_probe(dev, ret, "Unable to register backlight device\n");
> +		return ERR_PTR(ret);

		dev_err_probe(dev, PTR_ERR(bl), "Unable to register backlight device\n");
		return bl;

?

> +	}

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 5/6] MAINTAINERS: Add entry for Solomon SSD130x OLED displays DRM driver
  2022-02-11  9:21 ` [PATCH v4 5/6] MAINTAINERS: Add entry for Solomon SSD130x OLED displays DRM driver Javier Martinez Canillas
@ 2022-02-11 11:34   ` Andy Shevchenko
  0 siblings, 0 replies; 43+ messages in thread
From: Andy Shevchenko @ 2022-02-11 11:34 UTC (permalink / raw)
  To: Javier Martinez Canillas
  Cc: linux-kernel, Daniel Vetter, Geert Uytterhoeven, Maxime Ripard,
	Noralf Trønnes, dri-devel, linux-fbdev, Sam Ravnborg

On Fri, Feb 11, 2022 at 10:21:57AM +0100, Javier Martinez Canillas wrote:
> To make sure that tools like the get_maintainer.pl script will suggest
> to Cc me if patches are posted for this driver.
> 
> Also include the Device Tree binding for the old ssd1307fb fbdev driver
> since the new DRM driver was made compatible with the existing binding.

Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>

> Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
> Acked-by: Sam Ravnborg <sam@ravnborg.org>
> ---
> 
> (no changes since v3)
> 
> Changes in v3:
> - Adapt MAINTAINERS entry to point to the new drivers/gpu/drm/solomon directory.
> 
> Changes in v2:
> - Add Sam Ravnborg's acked-by to patch adding a MAINTAINERS entry (Sam Ravnborg)
> 
>  MAINTAINERS | 7 +++++++
>  1 file changed, 7 insertions(+)
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index d03ad8da1f36..05c306986ab0 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -6102,6 +6102,13 @@ T:	git git://anongit.freedesktop.org/drm/drm-misc
>  F:	Documentation/devicetree/bindings/display/repaper.txt
>  F:	drivers/gpu/drm/tiny/repaper.c
>  
> +DRM DRIVER FOR SOLOMON SSD130X OLED DISPLAYS
> +M:	Javier Martinez Canillas <javierm@redhat.com>
> +S:	Maintained
> +T:	git git://anongit.freedesktop.org/drm/drm-misc
> +F:	Documentation/devicetree/bindings/display/solomon,ssd1307fb.yaml
> +F:	drivers/gpu/drm/solomon/ssd130x*
> +
>  DRM DRIVER FOR QEMU'S CIRRUS DEVICE
>  M:	Dave Airlie <airlied@redhat.com>
>  M:	Gerd Hoffmann <kraxel@redhat.com>
> -- 
> 2.34.1
> 

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 6/6] dt-bindings: display: ssd1307fb: Add myself as binding co-maintainer
  2022-02-11  9:22 ` [PATCH v4 6/6] dt-bindings: display: ssd1307fb: Add myself as binding co-maintainer Javier Martinez Canillas
@ 2022-02-11 11:35   ` Andy Shevchenko
  0 siblings, 0 replies; 43+ messages in thread
From: Andy Shevchenko @ 2022-02-11 11:35 UTC (permalink / raw)
  To: Javier Martinez Canillas
  Cc: linux-kernel, Daniel Vetter, Geert Uytterhoeven, Maxime Ripard,
	Noralf Trønnes, dri-devel, linux-fbdev, Sam Ravnborg,
	Rob Herring

On Fri, Feb 11, 2022 at 10:22:53AM +0100, Javier Martinez Canillas wrote:
> The ssd130x DRM driver also makes use of this Device Tree binding to allow
> existing users of the fbdev driver to migrate without the need to change
> their Device Trees.
> 
> Add myself as another maintainer of the binding, to make sure that I will
> be on Cc when patches are proposed for it.

Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>

> Suggested-by: Sam Ravnborg <sam@ravnborg.org>
> Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
> Acked-by: Rob Herring <robh@kernel.org>
> ---
> 
> Changes in v4:
> - Add Rob Herring Acked-by tag to patch adding as DT binding co-maintainer.
> 
> Changes in v2:
> - Add myself as co-maintainer of the ssd1370fb DT binding (Sam Ravnborg).
> 
>  Documentation/devicetree/bindings/display/solomon,ssd1307fb.yaml | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/Documentation/devicetree/bindings/display/solomon,ssd1307fb.yaml b/Documentation/devicetree/bindings/display/solomon,ssd1307fb.yaml
> index 2ed2a7d0ca2f..9baafd0c42dd 100644
> --- a/Documentation/devicetree/bindings/display/solomon,ssd1307fb.yaml
> +++ b/Documentation/devicetree/bindings/display/solomon,ssd1307fb.yaml
> @@ -8,6 +8,7 @@ title: Solomon SSD1307 OLED Controller Framebuffer
>  
>  maintainers:
>    - Maxime Ripard <mripard@kernel.org>
> +  - Javier Martinez Canillas <javierm@redhat.com>
>  
>  properties:
>    compatible:
> -- 
> 2.34.1
> 

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 2/6] drm/format-helper: Add drm_fb_xrgb8888_to_mono_reversed()
  2022-02-11 11:10   ` Andy Shevchenko
@ 2022-02-11 11:50     ` Javier Martinez Canillas
  2022-02-11 15:55       ` Andy Shevchenko
  2022-02-11 11:59     ` Thomas Zimmermann
  1 sibling, 1 reply; 43+ messages in thread
From: Javier Martinez Canillas @ 2022-02-11 11:50 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: linux-kernel, linux-fbdev, Geert Uytterhoeven, Maxime Ripard,
	Daniel Vetter, dri-devel, Thomas Zimmermann, Sam Ravnborg,
	Noralf Trønnes, Daniel Vetter, David Airlie,
	Maarten Lankhorst, Maxime Ripard

Hello Andy,

Thanks for your feedback.

On 2/11/22 12:10, Andy Shevchenko wrote:

[snip]

>> +static void drm_fb_gray8_to_mono_reversed_line(u8 *dst, const u8 *src, unsigned int pixels,
>> +					       unsigned int start_offset, unsigned int end_len)
>> +{
>> +	unsigned int xb, i;
>> +
>> +	for (xb = 0; xb < pixels; xb++) {
>> +		unsigned int start = 0, end = 8;
>> +		u8 byte = 0x00;
> 
>> +		if (xb == 0 && start_offset)
>> +			start = start_offset;
> 
> This is invariant to the loop, can be moved out.
> 
>> +		if (xb == pixels - 1 && end_len)
>> +			end = end_len;
> 
> Ditto. However it may require to factor out the following loop to a helper.
>

Not sure I'm following, it's not invariant since it depends on the
loop iterator value. It only applies to the first and last pixels.
 
[snip]

>> +	/*
>> +	 * The reversed mono destination buffer contains 1 bit per pixel
>> +	 * and destination scanlines have to be in multiple of 8 pixels.
>> +	 */
>> +	if (!dst_pitch)
>> +		dst_pitch = DIV_ROUND_UP(linepixels, 8);
> 
> round_up() ?
> 

But it's not a round up operation but a div and round up.

>> +	WARN_ONCE(dst_pitch % 8 != 0, "dst_pitch is not a multiple of 8\n");
> 
> 
> I would move this to the if conditional, i.e.
> 
> 	if (dst_pitch)
> 		WARN_ONCE(dst_pitch % 8 != 0, "dst_pitch is not a multiple of 8\n");
> 	else
> 		dst_pitch = round_up(linepixels, 8);
>

No, because we always need to div and round up. The warning is just printed to
let know that the dst pitch is not a multiple of 8 as it should be. So callers
could be fixed.

>> +	/*
>> +	 * The cma memory is write-combined so reads are uncached.
> 
> CMA
>

Yes, this bug me too. But other format helpers (e.g: drm_fb_xrgb8888_to_rgb565
and drm_fb_xrgb8888_to_gray8) had this comment with CMA in lower case. So did
the same for consistency.

>> +	 * Speed up by fetching one line at a time.
>> +	 *
>> +	 * Also, format conversion from XR24 to reversed monochrome
>> +	 * are done line-by-line but are converted to 8-bit grayscale
>> +	 * as an intermediate step.
>> +	 *
>> +	 * Allocate a buffer to be used for both copying from the cma
>> +	 * memory and to store the intermediate grayscale line pixels.
>> +	 */
>> +	src32 = kmalloc(len_src32 + linepixels, GFP_KERNEL);
> 
> size_add() ?
>

I wasn't familiar with this macro and git grep returned nothing. Then I noticed
that it is fairly new, introduced in commit a66866cff71c ("overflow: Implement
size_t saturating arithmetic helpers").

git tag --contains a66866cff71c | head -1
next-20220207

So I can't really use it since isn't yet in the latest drm-misc-next base tag :)

>> +	if (!src32)
>> +		return;
> 
> ...
> 
>> +	/*
>> +	 * For damage handling, it is possible that only parts of the source
>> +	 * buffer is copied and this could lead to start and end pixels that
>> +	 * are not aligned to multiple of 8.
>> +	 *
>> +	 * Calculate if the start and end pixels are not aligned and set the
>> +	 * offsets for the reversed mono line conversion function to adjust.
>> +	 */
>> +	start_offset = clip->x1 % 8;
>> +	end_len = clip->x2 % 8;
> 
> ALIGN() ?
> 

But we don't want to align here but to know what's the start and end if is
not aligned since that would mean converting to mono in the middle of a byte.

Best regards,
-- 
Javier Martinez Canillas
Linux Engineering
Red Hat


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 1/6] drm/format-helper: Add drm_fb_xrgb8888_to_gray8_line()
  2022-02-11 11:12       ` Andy Shevchenko
@ 2022-02-11 11:54         ` Thomas Zimmermann
  2022-02-11 12:05           ` Jani Nikula
  0 siblings, 1 reply; 43+ messages in thread
From: Thomas Zimmermann @ 2022-02-11 11:54 UTC (permalink / raw)
  To: Andy Shevchenko, Javier Martinez Canillas
  Cc: linux-kernel, linux-fbdev, Geert Uytterhoeven, Maxime Ripard,
	Daniel Vetter, dri-devel, Sam Ravnborg, Noralf Trønnes,
	Daniel Vetter, David Airlie, Maarten Lankhorst, Maxime Ripard


[-- Attachment #1.1: Type: text/plain, Size: 1558 bytes --]

Hi

Am 11.02.22 um 12:12 schrieb Andy Shevchenko:
> On Fri, Feb 11, 2022 at 11:40:13AM +0100, Javier Martinez Canillas wrote:
>> On 2/11/22 11:28, Andy Shevchenko wrote:
>>> On Fri, Feb 11, 2022 at 10:19:22AM +0100, Javier Martinez Canillas wrote:
> 
> ...
> 
>>>> +static void drm_fb_xrgb8888_to_gray8_line(u8 *dst, const u32 *src, unsigned int pixels)
>>>> +{
>>>> +	unsigned int x;
>>>> +
>>>> +	for (x = 0; x < pixels; x++) {
>>>> +		u8 r = (*src & 0x00ff0000) >> 16;
>>>> +		u8 g = (*src & 0x0000ff00) >> 8;
>>>> +		u8 b =  *src & 0x000000ff;
>>>> +
>>>> +		/* ITU BT.601: Y = 0.299 R + 0.587 G + 0.114 B */
>>>> +		*dst++ = (3 * r + 6 * g + b) / 10;
>>>> +		src++;
>>>> +	}
>>>
>>> Can be done as
>>>
>>> 	while (pixels--) {
>>> 		...
>>> 	}
>>>
>>> or
>>>
>>> 	do {
>>> 		...
>>> 	} while (--pixels);
>>>
>>
>> I don't see why a while loop would be an improvement here TBH.
> 
> Less letters to parse when reading the code.

It's a simple refactoring of code that has worked well so far. Let's 
leave it as-is for now.

Best regards
Thomas

> 
>> In any case, I just pulled the line conversion logic as a separate
>> function with minimal code changes since doing that should be in a
>> separate patch.
> 
> 
>> Feel free to post a patch if you want to change that while loop.
> 
> Perhaps some day :-)
> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Ivo Totev

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 2/6] drm/format-helper: Add drm_fb_xrgb8888_to_mono_reversed()
  2022-02-11 11:10   ` Andy Shevchenko
  2022-02-11 11:50     ` Javier Martinez Canillas
@ 2022-02-11 11:59     ` Thomas Zimmermann
  1 sibling, 0 replies; 43+ messages in thread
From: Thomas Zimmermann @ 2022-02-11 11:59 UTC (permalink / raw)
  To: Andy Shevchenko, Javier Martinez Canillas
  Cc: linux-kernel, linux-fbdev, Geert Uytterhoeven, Maxime Ripard,
	Daniel Vetter, dri-devel, Sam Ravnborg, Noralf Trønnes,
	Daniel Vetter, David Airlie, Maarten Lankhorst, Maxime Ripard


[-- Attachment #1.1: Type: text/plain, Size: 3342 bytes --]

Hi

Am 11.02.22 um 12:10 schrieb Andy Shevchenko:
> On Fri, Feb 11, 2022 at 10:19:23AM +0100, Javier Martinez Canillas wrote:
>> Add support to convert from XR24 to reversed monochrome for drivers that
>> control monochromatic display panels, that only have 1 bit per pixel.
>>
>> The function does a line-by-line conversion doing an intermediate step
>> first from XR24 to 8-bit grayscale and then to reversed monochrome.
>>
>> The drm_fb_gray8_to_mono_reversed_line() helper was based on code from
>> drivers/gpu/drm/tiny/repaper.c driver.
> 
> ...
> 
>> +static void drm_fb_gray8_to_mono_reversed_line(u8 *dst, const u8 *src, unsigned int pixels,
>> +					       unsigned int start_offset, unsigned int end_len)
>> +{
>> +	unsigned int xb, i;
>> +
>> +	for (xb = 0; xb < pixels; xb++) {
>> +		unsigned int start = 0, end = 8;
>> +		u8 byte = 0x00;
> 
>> +		if (xb == 0 && start_offset)
>> +			start = start_offset;
> 
> This is invariant to the loop, can be moved out.
> 
>> +		if (xb == pixels - 1 && end_len)
>> +			end = end_len;
> 
> Ditto. However it may require to factor out the following loop to a helper.

Splitting the loop is much nicer, but leaves corner cases where start 
and end is in the same byte. Doing this sounds like a premature 
optimization to me.

Best regards
Thomas

> 
>> +		for (i = start; i < end; i++) {
>> +			unsigned int x = xb * 8 + i;
>> +
>> +			byte >>= 1;
>> +			if (src[x] >> 7)
>> +				byte |= BIT(7);
>> +		}
>> +		*dst++ = byte;
>> +	}
>> +}
> 
> ...
> 
>> +	/*
>> +	 * The reversed mono destination buffer contains 1 bit per pixel
>> +	 * and destination scanlines have to be in multiple of 8 pixels.
>> +	 */
>> +	if (!dst_pitch)
>> +		dst_pitch = DIV_ROUND_UP(linepixels, 8);
> 
> round_up() ?
> 
>> +	WARN_ONCE(dst_pitch % 8 != 0, "dst_pitch is not a multiple of 8\n");
> 
> 
> I would move this to the if conditional, i.e.
> 
> 	if (dst_pitch)
> 		WARN_ONCE(dst_pitch % 8 != 0, "dst_pitch is not a multiple of 8\n");
> 	else
> 		dst_pitch = round_up(linepixels, 8);
> 
>> +	/*
>> +	 * The cma memory is write-combined so reads are uncached.
> 
> CMA
> 
>> +	 * Speed up by fetching one line at a time.
>> +	 *
>> +	 * Also, format conversion from XR24 to reversed monochrome
>> +	 * are done line-by-line but are converted to 8-bit grayscale
>> +	 * as an intermediate step.
>> +	 *
>> +	 * Allocate a buffer to be used for both copying from the cma
>> +	 * memory and to store the intermediate grayscale line pixels.
>> +	 */
>> +	src32 = kmalloc(len_src32 + linepixels, GFP_KERNEL);
> 
> size_add() ?
> 
>> +	if (!src32)
>> +		return;
> 
> ...
> 
>> +	/*
>> +	 * For damage handling, it is possible that only parts of the source
>> +	 * buffer is copied and this could lead to start and end pixels that
>> +	 * are not aligned to multiple of 8.
>> +	 *
>> +	 * Calculate if the start and end pixels are not aligned and set the
>> +	 * offsets for the reversed mono line conversion function to adjust.
>> +	 */
>> +	start_offset = clip->x1 % 8;
>> +	end_len = clip->x2 % 8;
> 
> ALIGN() ?
> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Ivo Totev

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 1/6] drm/format-helper: Add drm_fb_xrgb8888_to_gray8_line()
  2022-02-11 11:54         ` Thomas Zimmermann
@ 2022-02-11 12:05           ` Jani Nikula
  2022-02-11 12:11             ` Javier Martinez Canillas
                               ` (2 more replies)
  0 siblings, 3 replies; 43+ messages in thread
From: Jani Nikula @ 2022-02-11 12:05 UTC (permalink / raw)
  To: Thomas Zimmermann, Andy Shevchenko, Javier Martinez Canillas
  Cc: linux-fbdev, David Airlie, Daniel Vetter, linux-kernel,
	dri-devel, Noralf Trønnes, Geert Uytterhoeven,
	Maxime Ripard, Sam Ravnborg

On Fri, 11 Feb 2022, Thomas Zimmermann <tzimmermann@suse.de> wrote:
> Hi
>
> Am 11.02.22 um 12:12 schrieb Andy Shevchenko:
>> On Fri, Feb 11, 2022 at 11:40:13AM +0100, Javier Martinez Canillas wrote:
>>> On 2/11/22 11:28, Andy Shevchenko wrote:
>>>> On Fri, Feb 11, 2022 at 10:19:22AM +0100, Javier Martinez Canillas wrote:
>> 
>> ...
>> 
>>>>> +static void drm_fb_xrgb8888_to_gray8_line(u8 *dst, const u32 *src, unsigned int pixels)
>>>>> +{
>>>>> +	unsigned int x;
>>>>> +
>>>>> +	for (x = 0; x < pixels; x++) {
>>>>> +		u8 r = (*src & 0x00ff0000) >> 16;
>>>>> +		u8 g = (*src & 0x0000ff00) >> 8;
>>>>> +		u8 b =  *src & 0x000000ff;
>>>>> +
>>>>> +		/* ITU BT.601: Y = 0.299 R + 0.587 G + 0.114 B */
>>>>> +		*dst++ = (3 * r + 6 * g + b) / 10;
>>>>> +		src++;
>>>>> +	}
>>>>
>>>> Can be done as
>>>>
>>>> 	while (pixels--) {
>>>> 		...
>>>> 	}
>>>>
>>>> or
>>>>
>>>> 	do {
>>>> 		...
>>>> 	} while (--pixels);
>>>>
>>>
>>> I don't see why a while loop would be an improvement here TBH.
>> 
>> Less letters to parse when reading the code.
>
> It's a simple refactoring of code that has worked well so far. Let's 
> leave it as-is for now.

IMO *always* prefer a for loop over while or do-while.

The for (i = 0; i < N; i++) is such a strong paradigm in C. You
instantly know how many times you're going to loop, at a glance. Not so
with with the alternatives, which should be used sparingly.

And yes, the do-while suggested above is buggy, and you actually need to
stop and think to see why.


BR,
Jani.



>
> Best regards
> Thomas
>
>> 
>>> In any case, I just pulled the line conversion logic as a separate
>>> function with minimal code changes since doing that should be in a
>>> separate patch.
>> 
>> 
>>> Feel free to post a patch if you want to change that while loop.
>> 
>> Perhaps some day :-)
>> 

-- 
Jani Nikula, Intel Open Source Graphics Center

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 3/6] drm: Add driver for Solomon SSD130x OLED displays
  2022-02-11 11:33   ` Andy Shevchenko
@ 2022-02-11 12:05     ` Javier Martinez Canillas
  2022-02-11 12:23       ` Geert Uytterhoeven
  2022-02-11 15:49       ` Andy Shevchenko
  0 siblings, 2 replies; 43+ messages in thread
From: Javier Martinez Canillas @ 2022-02-11 12:05 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: linux-kernel, linux-fbdev, Geert Uytterhoeven, Maxime Ripard,
	Daniel Vetter, dri-devel, Thomas Zimmermann, Sam Ravnborg,
	Noralf Trønnes, Daniel Vetter, David Airlie, Lee Jones,
	Maarten Lankhorst, Maxime Ripard, Thierry Reding,
	Uwe Kleine-König, linux-pwm

On 2/11/22 12:33, Andy Shevchenko wrote:
> On Fri, Feb 11, 2022 at 10:19:24AM +0100, Javier Martinez Canillas wrote:
>> This adds a DRM driver for SSD1305, SSD1306, SSD1307 and SSD1309 Solomon
>> OLED display controllers.
>>
>> It's only the core part of the driver and a bus specific driver is needed
>> for each transport interface supported by the display controllers.
> 
> ...
> 
>> +#include <linux/backlight.h>
>> +#include <linux/bitfield.h>
> 
> bits.h

Ok, missed that both weren't in the same macro.

> (FYI, specifically sent a patch few days ago to add explicitly the inclusions
>  that needed for bitfield operations in the example inside bitfield.h).
> 
>> +#include <linux/delay.h>
>> +#include <linux/gpio/consumer.h>
>> +#include <linux/property.h>
>> +#include <linux/pwm.h>
>> +#include <linux/regulator/consumer.h>
> 
> ...
> 
>> +#define SSD130X_SET_ADDRESS_MODE_HORIZONTAL	(0x00)
>> +#define SSD130X_SET_ADDRESS_MODE_VERTICAL	(0x01)
>> +#define SSD130X_SET_ADDRESS_MODE_PAGE		(0x02)
>> +
>> +#define SSD130X_SET_AREA_COLOR_MODE_ENABLE	(0x1e)
>> +#define SSD130X_SET_AREA_COLOR_MODE_LOW_POWER	(0x05)
> 
> Do the parentheses add anything here?
>

Not really, the fbdev driver used it and I understood that was
a convention to denote that these are command options and not a
command or register. I'll drop them.

> ...
> 
>> +/*
>> + * Helper to write command (SSD130X_COMMAND). The fist variadic argument
>> + * is the command to write and the following are the command options.
> 
> This is not correct explanation. Please, rephrase to show that _each_ of the
> options is sent with a preceding command.
>

It's a correct explanation IMO from the caller point of view. The first argument
is the command sent (i.e: SSD130X_SET_ADDRESS_MODE) and the next ones are the
the command options (i.e: SSD130X_SET_ADDRESS_MODE_HORIZONTAL).

The fact that each command and options are preceding with a SSD130X_COMMAND
value is part of the protocol of the device and a detail that's abstracted
away by this helper function to the callers.

>> + */
>> +static int ssd130x_write_cmd(struct ssd130x_device *ssd130x, int count,
>> +				    /* u8 cmd, u8 option, ... */...)
>> +{
>> +	va_list ap;
>> +	u8 value;
>> +	int ret;
>> +
>> +	va_start(ap, count);
>> +
>> +	do {
>> +		value = va_arg(ap, int);
>> +		ret = regmap_write(ssd130x->regmap, SSD130X_COMMAND, (u8)value);
>> +		if (ret)
>> +			goto out_end;
>> +	} while (--count);
>> +
>> +out_end:
>> +	va_end(ap);
>> +
>> +	return ret;
>> +}
> 
> ...
> 
>> +	if (ssd130x->device_info->need_pwm) {
> 
> Yeah, unfortunately we still don't have pwm_get_optional()...
> 
>> +		ret = ssd130x_pwm_enable(ssd130x);
>> +		if (ret) {
>> +			dev_err(dev, "Failed to enable PWM: %d\n", ret);
>> +			regulator_disable(ssd130x->vcc_reg);
>> +			return ret;
>> +		}
>> +	}
> 
> ...
> 
>> +static void ssd130x_power_off(struct ssd130x_device *ssd130x)
>> +{
> 
>> +	if (ssd130x->device_info->need_pwm) {
> 
> Redundant check. The two below are NULL-aware.
>

Ok, I'll drop it.

>> +		pwm_disable(ssd130x->pwm);
>> +		pwm_put(ssd130x->pwm);
>> +	}
>> +
>> +	regulator_disable(ssd130x->vcc_reg);
>> +}
> 
> ...
> 
>> +	ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_COM_PINS_CONFIG, compins);
>> +	if (ret < 0)
>> +		return ret;
> 
>> +
>> +
> 
> One blank line is enough.
>

Indeed, that was a left over when changing this to use the macros.
 
> ...
> 
>> +	for (i = y / 8; i < y / 8 + pages; i++) {
>> +		int m = 8;
>> +
>> +		/* Last page may be partial */
>> +		if (8 * (i + 1) > ssd130x->height)
>> +			m = ssd130x->height % 8;
> 
> Perhaps it can be moved out of the loop with refactored piece below.
>

Not sure I'm following since it depends on the for loop iterator value.

[snip]

>> +	bl = devm_backlight_device_register(dev, dev_name(dev), dev, ssd130x,
>> +					    &ssd130xfb_bl_ops, NULL);
>> +	if (IS_ERR(bl)) {
> 
>> +		ret = PTR_ERR(bl);
>> +		dev_err_probe(dev, ret, "Unable to register backlight device\n");
>> +		return ERR_PTR(ret);
> 
> 		dev_err_probe(dev, PTR_ERR(bl), "Unable to register backlight device\n");
> 		return bl;
> 
> ?

No, because this function's return value is a struct ssd130x_device pointer,
not a struct backlight_device pointer.

Best regards,
-- 
Javier Martinez Canillas
Linux Engineering
Red Hat


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 1/6] drm/format-helper: Add drm_fb_xrgb8888_to_gray8_line()
  2022-02-11 12:05           ` Jani Nikula
@ 2022-02-11 12:11             ` Javier Martinez Canillas
  2022-02-11 12:27             ` Geert Uytterhoeven
  2022-02-11 15:41             ` Andy Shevchenko
  2 siblings, 0 replies; 43+ messages in thread
From: Javier Martinez Canillas @ 2022-02-11 12:11 UTC (permalink / raw)
  To: Jani Nikula, Thomas Zimmermann, Andy Shevchenko
  Cc: linux-fbdev, David Airlie, Daniel Vetter, linux-kernel,
	dri-devel, Noralf Trønnes, Geert Uytterhoeven,
	Maxime Ripard, Sam Ravnborg

Hello Jani,

On 2/11/22 13:05, Jani Nikula wrote:

[snip]

>>>> I don't see why a while loop would be an improvement here TBH.
>>>
>>> Less letters to parse when reading the code.
>>
>> It's a simple refactoring of code that has worked well so far. Let's 
>> leave it as-is for now.
> 
> IMO *always* prefer a for loop over while or do-while.
> 
> The for (i = 0; i < N; i++) is such a strong paradigm in C. You
> instantly know how many times you're going to loop, at a glance. Not so
> with with the alternatives, which should be used sparingly.
> 
> And yes, the do-while suggested above is buggy, and you actually need to
> stop and think to see why.
>

Absolutely agree.

These format conversion helpers are not trivial to read and understand (at
least for me). In my opinion the code should be written in a way that ease
readability and make as robust and less error prone as possible.
 
> 
> BR,
> Jani.
Best regards,
-- 
Javier Martinez Canillas
Linux Engineering
Red Hat


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 3/6] drm: Add driver for Solomon SSD130x OLED displays
  2022-02-11 12:05     ` Javier Martinez Canillas
@ 2022-02-11 12:23       ` Geert Uytterhoeven
  2022-02-11 12:27         ` Javier Martinez Canillas
  2022-02-11 15:49       ` Andy Shevchenko
  1 sibling, 1 reply; 43+ messages in thread
From: Geert Uytterhoeven @ 2022-02-11 12:23 UTC (permalink / raw)
  To: Javier Martinez Canillas
  Cc: Andy Shevchenko, Linux Kernel Mailing List,
	Linux Fbdev development list, Maxime Ripard, Daniel Vetter,
	DRI Development, Thomas Zimmermann, Sam Ravnborg,
	Noralf Trønnes, Daniel Vetter, David Airlie, Lee Jones,
	Maarten Lankhorst, Maxime Ripard, Thierry Reding,
	Uwe Kleine-König, Linux PWM List

Hi Javier,

On Fri, Feb 11, 2022 at 1:06 PM Javier Martinez Canillas
<javierm@redhat.com> wrote:
> On 2/11/22 12:33, Andy Shevchenko wrote:
> > On Fri, Feb 11, 2022 at 10:19:24AM +0100, Javier Martinez Canillas wrote:
> >> This adds a DRM driver for SSD1305, SSD1306, SSD1307 and SSD1309 Solomon
> >> OLED display controllers.
> >>
> >> It's only the core part of the driver and a bus specific driver is needed
> >> for each transport interface supported by the display controllers.

> >> +    bl = devm_backlight_device_register(dev, dev_name(dev), dev, ssd130x,
> >> +                                        &ssd130xfb_bl_ops, NULL);
> >> +    if (IS_ERR(bl)) {
> >
> >> +            ret = PTR_ERR(bl);
> >> +            dev_err_probe(dev, ret, "Unable to register backlight device\n");
> >> +            return ERR_PTR(ret);
> >
> >               dev_err_probe(dev, PTR_ERR(bl), "Unable to register backlight device\n");
> >               return bl;
> >
> > ?
>
> No, because this function's return value is a struct ssd130x_device pointer,
> not a struct backlight_device pointer.

Hence

    return ERR_PTR(dev_err_probe(dev, PTR_ERR(bl),
                                 "Unable to register backlight device\n"));

?

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 3/6] drm: Add driver for Solomon SSD130x OLED displays
  2022-02-11 12:23       ` Geert Uytterhoeven
@ 2022-02-11 12:27         ` Javier Martinez Canillas
  0 siblings, 0 replies; 43+ messages in thread
From: Javier Martinez Canillas @ 2022-02-11 12:27 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Andy Shevchenko, Linux Kernel Mailing List,
	Linux Fbdev development list, Maxime Ripard, Daniel Vetter,
	DRI Development, Thomas Zimmermann, Sam Ravnborg,
	Noralf Trønnes, Daniel Vetter, David Airlie, Lee Jones,
	Maarten Lankhorst, Maxime Ripard, Thierry Reding,
	Uwe Kleine-König, Linux PWM List

Hello Geert,

On 2/11/22 13:23, Geert Uytterhoeven wrote:

[snip]

>>>> +    if (IS_ERR(bl)) {
>>>
>>>> +            ret = PTR_ERR(bl);
>>>> +            dev_err_probe(dev, ret, "Unable to register backlight device\n");
>>>> +            return ERR_PTR(ret);
>>>
>>>               dev_err_probe(dev, PTR_ERR(bl), "Unable to register backlight device\n");
>>>               return bl;
>>>
>>> ?
>>
>> No, because this function's return value is a struct ssd130x_device pointer,
>> not a struct backlight_device pointer.
> 
> Hence
> 
>     return ERR_PTR(dev_err_probe(dev, PTR_ERR(bl),
>                                  "Unable to register backlight device\n"));
> 
> ?
> 

Thanks, that would work.

Best regards,
-- 
Javier Martinez Canillas
Linux Engineering
Red Hat


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 1/6] drm/format-helper: Add drm_fb_xrgb8888_to_gray8_line()
  2022-02-11 12:05           ` Jani Nikula
  2022-02-11 12:11             ` Javier Martinez Canillas
@ 2022-02-11 12:27             ` Geert Uytterhoeven
  2022-02-11 15:41             ` Andy Shevchenko
  2 siblings, 0 replies; 43+ messages in thread
From: Geert Uytterhoeven @ 2022-02-11 12:27 UTC (permalink / raw)
  To: Jani Nikula
  Cc: Thomas Zimmermann, Andy Shevchenko, Javier Martinez Canillas,
	Linux Fbdev development list, David Airlie, Daniel Vetter,
	Linux Kernel Mailing List, DRI Development, Noralf Trønnes,
	Maxime Ripard, Sam Ravnborg

Hi Jani,

On Fri, Feb 11, 2022 at 1:06 PM Jani Nikula <jani.nikula@linux.intel.com> wrote:
> On Fri, 11 Feb 2022, Thomas Zimmermann <tzimmermann@suse.de> wrote:
> > Am 11.02.22 um 12:12 schrieb Andy Shevchenko:
> >> On Fri, Feb 11, 2022 at 11:40:13AM +0100, Javier Martinez Canillas wrote:
> >>> On 2/11/22 11:28, Andy Shevchenko wrote:
> >>>> On Fri, Feb 11, 2022 at 10:19:22AM +0100, Javier Martinez Canillas wrote:
> >>
> >> ...
> >>
> >>>>> +static void drm_fb_xrgb8888_to_gray8_line(u8 *dst, const u32 *src, unsigned int pixels)
> >>>>> +{
> >>>>> + unsigned int x;
> >>>>> +
> >>>>> + for (x = 0; x < pixels; x++) {
> >>>>> +         u8 r = (*src & 0x00ff0000) >> 16;
> >>>>> +         u8 g = (*src & 0x0000ff00) >> 8;
> >>>>> +         u8 b =  *src & 0x000000ff;
> >>>>> +
> >>>>> +         /* ITU BT.601: Y = 0.299 R + 0.587 G + 0.114 B */
> >>>>> +         *dst++ = (3 * r + 6 * g + b) / 10;
> >>>>> +         src++;
> >>>>> + }
> >>>>
> >>>> Can be done as
> >>>>
> >>>>    while (pixels--) {
> >>>>            ...
> >>>>    }
> >>>>
> >>>> or
> >>>>
> >>>>    do {
> >>>>            ...
> >>>>    } while (--pixels);
> >>>>
> >>>
> >>> I don't see why a while loop would be an improvement here TBH.
> >>
> >> Less letters to parse when reading the code.
> >
> > It's a simple refactoring of code that has worked well so far. Let's
> > leave it as-is for now.
>
> IMO *always* prefer a for loop over while or do-while.

(guess what ;-) I tend to disagree.

> The for (i = 0; i < N; i++) is such a strong paradigm in C. You
> instantly know how many times you're going to loop, at a glance. Not so
> with with the alternatives, which should be used sparingly.

In this case it's fairly obvious, and you get rid of the extra variable x.
Less code, less variables, what can go wrong? ;-)

> And yes, the do-while suggested above is buggy, and you actually need to
> stop and think to see why.

Yes, that one is wrong.

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 3/6] drm: Add driver for Solomon SSD130x OLED displays
  2022-02-11  9:19 ` [PATCH v4 3/6] drm: Add driver for Solomon SSD130x OLED displays Javier Martinez Canillas
  2022-02-11 11:33   ` Andy Shevchenko
@ 2022-02-11 12:44   ` Thomas Zimmermann
  1 sibling, 0 replies; 43+ messages in thread
From: Thomas Zimmermann @ 2022-02-11 12:44 UTC (permalink / raw)
  To: Javier Martinez Canillas, linux-kernel
  Cc: linux-pwm, linux-fbdev, David Airlie, Daniel Vetter, dri-devel,
	Noralf Trønnes, Geert Uytterhoeven, Maxime Ripard,
	Uwe Kleine-König, Thierry Reding, Lee Jones,
	Andy Shevchenko, Sam Ravnborg


[-- Attachment #1.1: Type: text/plain, Size: 14150 bytes --]

Hi

Am 11.02.22 um 10:19 schrieb Javier Martinez Canillas:
...
> +
> +static void ssd130x_display_pipe_enable(struct drm_simple_display_pipe *pipe,
> +					struct drm_crtc_state *crtc_state,
> +					struct drm_plane_state *plane_state)
> +{
> +	struct ssd130x_device *ssd130x = drm_to_ssd130x(pipe->crtc.dev);
> +	struct drm_device *drm = &ssd130x->drm;
> +	int idx, ret;
> +
> +	ret = ssd130x_power_on(ssd130x);
> +	if (ret)
> +		return;
> +
> +	ret = ssd130x_init(ssd130x);
> +	if (ret)
> +		goto out_power_off;
> +
> +	if (!drm_dev_enter(drm, &idx))
> +		goto out_power_off;
> +
> +	ssd130x_clear_screen(ssd130x);

Rather than clearing the screen, send the whole fb onto the display.

Best regards
Thomas

> +
> +	ssd130x_write_cmd(ssd130x, 1, SSD130X_DISPLAY_ON);
> +
> +	backlight_enable(ssd130x->bl_dev);
> +
> +	drm_dev_exit(idx);
> +
> +	return;
> +out_power_off:
> +	ssd130x_power_off(ssd130x);
> +}
> +
> +static void ssd130x_display_pipe_disable(struct drm_simple_display_pipe *pipe)
> +{
> +	struct ssd130x_device *ssd130x = drm_to_ssd130x(pipe->crtc.dev);
> +	struct drm_device *drm = &ssd130x->drm;
> +	int idx;
> +
> +	if (!drm_dev_enter(drm, &idx))
> +		return;
> +
> +	ssd130x_clear_screen(ssd130x);
> +
> +	backlight_disable(ssd130x->bl_dev);
> +
> +	ssd130x_write_cmd(ssd130x, 1, SSD130X_DISPLAY_OFF);
> +
> +	ssd130x_power_off(ssd130x);
> +
> +	drm_dev_exit(idx);
> +}
> +
> +static void ssd130x_display_pipe_update(struct drm_simple_display_pipe *pipe,
> +					struct drm_plane_state *old_plane_state)
> +{
> +	struct ssd130x_device *ssd130x = drm_to_ssd130x(pipe->crtc.dev);
> +	struct drm_plane_state *plane_state = pipe->plane.state;
> +	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
> +	struct drm_framebuffer *fb = plane_state->fb;
> +	struct drm_device *drm = &ssd130x->drm;
> +	struct drm_rect src_clip, dst_clip;
> +	int idx;
> +
> +	if (!fb)
> +		return;
> +
> +	if (!pipe->crtc.state->active)
> +		return;
> +
> +	if (!drm_atomic_helper_damage_merged(old_plane_state, plane_state, &src_clip))
> +		return;
> +
> +	dst_clip = plane_state->dst;
> +	if (!drm_rect_intersect(&dst_clip, &src_clip))
> +		return;
> +
> +	if (!drm_dev_enter(drm, &idx))
> +		return;
> +
> +	ssd130x_fb_blit_rect(plane_state->fb, &shadow_plane_state->data[0], &dst_clip);
> +
> +	drm_dev_exit(idx);
> +}
> +
> +static const struct drm_simple_display_pipe_funcs ssd130x_pipe_funcs = {
> +	.mode_valid = ssd130x_display_pipe_mode_valid,
> +	.enable = ssd130x_display_pipe_enable,
> +	.disable = ssd130x_display_pipe_disable,
> +	.update = ssd130x_display_pipe_update,
> +	DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS,
> +};
> +
> +static int ssd130x_connector_get_modes(struct drm_connector *connector)
> +{
> +	struct ssd130x_device *ssd130x = drm_to_ssd130x(connector->dev);
> +	struct drm_display_mode *mode = &ssd130x->mode;
> +	struct device *dev = ssd130x->dev;
> +
> +	mode = drm_mode_duplicate(connector->dev, &ssd130x->mode);
> +	if (!mode) {
> +		dev_err(dev, "Failed to duplicated mode\n");
> +		return 0;
> +	}
> +
> +	drm_mode_probed_add(connector, mode);
> +	drm_set_preferred_mode(connector, mode->hdisplay, mode->vdisplay);
> +
> +	/* There is only a single mode */
> +	return 1;
> +}
> +
> +static const struct drm_connector_helper_funcs ssd130x_connector_helper_funcs = {
> +	.get_modes = ssd130x_connector_get_modes,
> +};
> +
> +static const struct drm_connector_funcs ssd130x_connector_funcs = {
> +	.reset = drm_atomic_helper_connector_reset,
> +	.fill_modes = drm_helper_probe_single_connector_modes,
> +	.destroy = drm_connector_cleanup,
> +	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
> +	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> +};
> +
> +static const struct drm_mode_config_funcs ssd130x_mode_config_funcs = {
> +	.fb_create = drm_gem_fb_create_with_dirty,
> +	.atomic_check = drm_atomic_helper_check,
> +	.atomic_commit = drm_atomic_helper_commit,
> +};
> +
> +static const uint32_t ssd130x_formats[] = {
> +	DRM_FORMAT_XRGB8888,
> +};
> +
> +DEFINE_DRM_GEM_FOPS(ssd130x_fops);
> +
> +static const struct drm_driver ssd130x_drm_driver = {
> +	DRM_GEM_SHMEM_DRIVER_OPS,
> +	.name			= DRIVER_NAME,
> +	.desc			= DRIVER_DESC,
> +	.date			= DRIVER_DATE,
> +	.major			= DRIVER_MAJOR,
> +	.minor			= DRIVER_MINOR,
> +	.driver_features	= DRIVER_ATOMIC | DRIVER_GEM | DRIVER_MODESET,
> +	.fops			= &ssd130x_fops,
> +};
> +
> +static int ssd130x_update_bl(struct backlight_device *bdev)
> +{
> +	struct ssd130x_device *ssd130x = bl_get_data(bdev);
> +	int brightness = backlight_get_brightness(bdev);
> +	int ret;
> +
> +	ssd130x->contrast = brightness;
> +
> +	ret = ssd130x_write_cmd(ssd130x, 1, SSD130X_CONTRAST);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = ssd130x_write_cmd(ssd130x, 1, ssd130x->contrast);
> +	if (ret < 0)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static const struct backlight_ops ssd130xfb_bl_ops = {
> +	.update_status	= ssd130x_update_bl,
> +};
> +
> +static void ssd130x_parse_properties(struct ssd130x_device *ssd130x)
> +{
> +	struct device *dev = ssd130x->dev;
> +
> +	if (device_property_read_u32(dev, "solomon,width", &ssd130x->width))
> +		ssd130x->width = 96;
> +
> +	if (device_property_read_u32(dev, "solomon,height", &ssd130x->height))
> +		ssd130x->height = 16;
> +
> +	if (device_property_read_u32(dev, "solomon,page-offset", &ssd130x->page_offset))
> +		ssd130x->page_offset = 1;
> +
> +	if (device_property_read_u32(dev, "solomon,col-offset", &ssd130x->col_offset))
> +		ssd130x->col_offset = 0;
> +
> +	if (device_property_read_u32(dev, "solomon,com-offset", &ssd130x->com_offset))
> +		ssd130x->com_offset = 0;
> +
> +	if (device_property_read_u32(dev, "solomon,prechargep1", &ssd130x->prechargep1))
> +		ssd130x->prechargep1 = 2;
> +
> +	if (device_property_read_u32(dev, "solomon,prechargep2", &ssd130x->prechargep2))
> +		ssd130x->prechargep2 = 2;
> +
> +	if (!device_property_read_u8_array(dev, "solomon,lookup-table",
> +					   ssd130x->lookup_table,
> +					   ARRAY_SIZE(ssd130x->lookup_table)))
> +		ssd130x->lookup_table_set = 1;
> +
> +	ssd130x->seg_remap = !device_property_read_bool(dev, "solomon,segment-no-remap");
> +	ssd130x->com_seq = device_property_read_bool(dev, "solomon,com-seq");
> +	ssd130x->com_lrremap = device_property_read_bool(dev, "solomon,com-lrremap");
> +	ssd130x->com_invdir = device_property_read_bool(dev, "solomon,com-invdir");
> +	ssd130x->area_color_enable =
> +		device_property_read_bool(dev, "solomon,area-color-enable");
> +	ssd130x->low_power = device_property_read_bool(dev, "solomon,low-power");
> +
> +	ssd130x->contrast = 127;
> +	ssd130x->vcomh = ssd130x->device_info->default_vcomh;
> +
> +	/* Setup display timing */
> +	if (device_property_read_u32(dev, "solomon,dclk-div", &ssd130x->dclk_div))
> +		ssd130x->dclk_div = ssd130x->device_info->default_dclk_div;
> +	if (device_property_read_u32(dev, "solomon,dclk-frq", &ssd130x->dclk_frq))
> +		ssd130x->dclk_frq = ssd130x->device_info->default_dclk_frq;
> +}
> +
> +static int ssd130x_init_modeset(struct ssd130x_device *ssd130x)
> +{
> +	struct drm_display_mode *mode = &ssd130x->mode;
> +	struct device *dev = ssd130x->dev;
> +	struct drm_device *drm = &ssd130x->drm;
> +	unsigned long max_width, max_height;
> +	int ret;
> +
> +	ret = drmm_mode_config_init(drm);
> +	if (ret) {
> +		dev_err(dev, "DRM mode config init failed: %d\n", ret);
> +		return ret;
> +	}
> +
> +	mode->type = DRM_MODE_TYPE_DRIVER;
> +	mode->clock = 1;
> +	mode->hdisplay = mode->htotal = ssd130x->width;
> +	mode->hsync_start = mode->hsync_end = ssd130x->width;
> +	mode->vdisplay = mode->vtotal = ssd130x->height;
> +	mode->vsync_start = mode->vsync_end = ssd130x->height;
> +	mode->width_mm = 27;
> +	mode->height_mm = 27;
> +
> +	max_width = max_t(unsigned long, mode->hdisplay, DRM_SHADOW_PLANE_MAX_WIDTH);
> +	max_height = max_t(unsigned long, mode->vdisplay, DRM_SHADOW_PLANE_MAX_HEIGHT);
> +
> +	drm->mode_config.min_width = mode->hdisplay;
> +	drm->mode_config.max_width = max_width;
> +	drm->mode_config.min_height = mode->vdisplay;
> +	drm->mode_config.max_height = max_height;
> +	drm->mode_config.preferred_depth = 32;
> +	drm->mode_config.funcs = &ssd130x_mode_config_funcs;
> +
> +	ret = drm_connector_init(drm, &ssd130x->connector, &ssd130x_connector_funcs,
> +				 DRM_MODE_CONNECTOR_Unknown);
> +	if (ret) {
> +		dev_err(dev, "DRM connector init failed: %d\n", ret);
> +		return ret;
> +	}
> +
> +	drm_connector_helper_add(&ssd130x->connector, &ssd130x_connector_helper_funcs);
> +
> +	ret = drm_simple_display_pipe_init(drm, &ssd130x->pipe, &ssd130x_pipe_funcs,
> +					   ssd130x_formats, ARRAY_SIZE(ssd130x_formats),
> +					   NULL, &ssd130x->connector);
> +	if (ret) {
> +		dev_err(dev, "DRM simple display pipeline init failed: %d\n", ret);
> +		return ret;
> +	}
> +
> +	drm_plane_enable_fb_damage_clips(&ssd130x->pipe.plane);
> +
> +	drm_mode_config_reset(drm);
> +
> +	return 0;
> +}
> +
> +static int ssd130x_get_resources(struct ssd130x_device *ssd130x)
> +{
> +	struct device *dev = ssd130x->dev;
> +
> +	ssd130x->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
> +	if (IS_ERR(ssd130x->reset))
> +		return dev_err_probe(dev, PTR_ERR(ssd130x->reset),
> +				     "Failed to get reset gpio\n");
> +
> +	ssd130x->vcc_reg = devm_regulator_get(dev, "vcc");
> +	if (IS_ERR(ssd130x->vcc_reg))
> +		return dev_err_probe(dev, PTR_ERR(ssd130x->vcc_reg),
> +				     "Failed to get VCC regulator\n");
> +
> +	return 0;
> +}
> +
> +struct ssd130x_device *ssd130x_probe(struct device *dev, struct regmap *regmap)
> +{
> +	struct ssd130x_device *ssd130x;
> +	struct backlight_device *bl;
> +	struct drm_device *drm;
> +	int ret;
> +
> +	ssd130x = devm_drm_dev_alloc(dev, &ssd130x_drm_driver,
> +				     struct ssd130x_device, drm);
> +	if (IS_ERR(ssd130x)) {
> +		dev_err_probe(dev, PTR_ERR(ssd130x),
> +			      "Failed to allocate DRM device\n");
> +		return ssd130x;
> +	}
> +
> +	drm = &ssd130x->drm;
> +
> +	ssd130x->dev = dev;
> +	ssd130x->regmap = regmap;
> +	ssd130x->device_info = device_get_match_data(dev);
> +
> +	ssd130x_parse_properties(ssd130x);
> +
> +	ret = ssd130x_get_resources(ssd130x);
> +	if (ret)
> +		return ERR_PTR(ret);
> +
> +	bl = devm_backlight_device_register(dev, dev_name(dev), dev, ssd130x,
> +					    &ssd130xfb_bl_ops, NULL);
> +	if (IS_ERR(bl)) {
> +		ret = PTR_ERR(bl);
> +		dev_err_probe(dev, ret, "Unable to register backlight device\n");
> +		return ERR_PTR(ret);
> +	}
> +
> +	bl->props.brightness = ssd130x->contrast;
> +	bl->props.max_brightness = MAX_CONTRAST;
> +	ssd130x->bl_dev = bl;
> +
> +	ret = ssd130x_init_modeset(ssd130x);
> +	if (ret)
> +		return ERR_PTR(ret);
> +
> +	ret = drm_dev_register(drm, 0);
> +	if (ret) {
> +		dev_err_probe(dev, ret, "DRM device register failed\n");
> +		return ERR_PTR(ret);
> +	}
> +
> +	drm_fbdev_generic_setup(drm, 0);
> +
> +	return ssd130x;
> +}
> +EXPORT_SYMBOL_GPL(ssd130x_probe);
> +
> +int ssd130x_remove(struct ssd130x_device *ssd130x)
> +{
> +	drm_dev_unplug(&ssd130x->drm);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(ssd130x_remove);
> +
> +void ssd130x_shutdown(struct ssd130x_device *ssd130x)
> +{
> +	drm_atomic_helper_shutdown(&ssd130x->drm);
> +}
> +EXPORT_SYMBOL_GPL(ssd130x_shutdown);
> +
> +MODULE_DESCRIPTION(DRIVER_DESC);
> +MODULE_AUTHOR("Javier Martinez Canillas <javierm@redhat.com>");
> +MODULE_LICENSE("GPL v2");
> diff --git a/drivers/gpu/drm/solomon/ssd130x.h b/drivers/gpu/drm/solomon/ssd130x.h
> new file mode 100644
> index 000000000000..754953b261b0
> --- /dev/null
> +++ b/drivers/gpu/drm/solomon/ssd130x.h
> @@ -0,0 +1,76 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Header file for:
> + * DRM driver for Solomon SSD130x OLED displays
> + *
> + * Copyright 2022 Red Hat Inc.
> + * Authors: Javier Martinez Canillas <javierm@redhat.com>
> + *
> + * Based on drivers/video/fbdev/ssd1307fb.c
> + * Copyright 2012 Free Electrons
> + */
> +
> +#ifndef __SSD1307X_H__
> +#define __SSD1307X_H__
> +
> +#include <drm/drm_drv.h>
> +#include <drm/drm_simple_kms_helper.h>
> +
> +#include <linux/regmap.h>
> +
> +struct ssd130x_deviceinfo {
> +	u32 default_vcomh;
> +	u32 default_dclk_div;
> +	u32 default_dclk_frq;
> +	int need_pwm;
> +	int need_chargepump;
> +};
> +
> +struct ssd130x_device {
> +	struct drm_device drm;
> +	struct device *dev;
> +	struct drm_simple_display_pipe pipe;
> +	struct drm_display_mode mode;
> +	struct drm_connector connector;
> +	struct i2c_client *client;
> +
> +	struct regmap *regmap;
> +
> +	const struct ssd130x_deviceinfo *device_info;
> +
> +	unsigned area_color_enable : 1;
> +	unsigned com_invdir : 1;
> +	unsigned com_lrremap : 1;
> +	unsigned com_seq : 1;
> +	unsigned lookup_table_set : 1;
> +	unsigned low_power : 1;
> +	unsigned seg_remap : 1;
> +	u32 com_offset;
> +	u32 contrast;
> +	u32 dclk_div;
> +	u32 dclk_frq;
> +	u32 height;
> +	u8 lookup_table[4];
> +	u32 page_offset;
> +	u32 col_offset;
> +	u32 prechargep1;
> +	u32 prechargep2;
> +
> +	struct backlight_device *bl_dev;
> +	struct pwm_device *pwm;
> +	struct gpio_desc *reset;
> +	struct regulator *vcc_reg;
> +	u32 vcomh;
> +	u32 width;
> +	/* Cached address ranges */
> +	u8 col_start;
> +	u8 col_end;
> +	u8 page_start;
> +	u8 page_end;
> +};
> +
> +struct ssd130x_device *ssd130x_probe(struct device *dev, struct regmap *regmap);
> +int ssd130x_remove(struct ssd130x_device *ssd130x);
> +void ssd130x_shutdown(struct ssd130x_device *ssd130x);
> +
> +#endif /* __SSD1307X_H__ */

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Ivo Totev

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 2/6] drm/format-helper: Add drm_fb_xrgb8888_to_mono_reversed()
  2022-02-11  9:19 ` [PATCH v4 2/6] drm/format-helper: Add drm_fb_xrgb8888_to_mono_reversed() Javier Martinez Canillas
  2022-02-11 11:10   ` Andy Shevchenko
@ 2022-02-11 12:46   ` Thomas Zimmermann
  1 sibling, 0 replies; 43+ messages in thread
From: Thomas Zimmermann @ 2022-02-11 12:46 UTC (permalink / raw)
  To: Javier Martinez Canillas, linux-kernel
  Cc: linux-fbdev, Geert Uytterhoeven, Andy Shevchenko, Maxime Ripard,
	Daniel Vetter, dri-devel, Sam Ravnborg, Noralf Trønnes,
	Daniel Vetter, David Airlie, Maarten Lankhorst, Maxime Ripard


[-- Attachment #1.1: Type: text/plain, Size: 6452 bytes --]

Hi

Am 11.02.22 um 10:19 schrieb Javier Martinez Canillas:
> Add support to convert from XR24 to reversed monochrome for drivers that
> control monochromatic display panels, that only have 1 bit per pixel.
> 
> The function does a line-by-line conversion doing an intermediate step
> first from XR24 to 8-bit grayscale and then to reversed monochrome.
> 
> The drm_fb_gray8_to_mono_reversed_line() helper was based on code from
> drivers/gpu/drm/tiny/repaper.c driver.
> 
> Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
> Reviewed-by: Thomas Zimmermann <tzimmermann@suse.de>
> ---
> 
> Changes in v4:
> - Rename end_offset to end_len (Thomas Zimmermann)
> - Warn once if dst_pitch is not a multiple of 8 (Thomas Zimmermann)
> - Drop drm_fb_gray8_to_mono_reversed() that's not used (Thomas Zimmermann)
> - Allocate single buffer for both copy cma memory and gray8 (Thomas Zimmermann)
> - Add Thomas Zimmermann Reviewed-by tag to patch adding XR24 -> mono helper.
> 
> Changes in v3:
> - Also add a drm_fb_xrgb8888_to_mono_reversed() helper (Thomas Zimmermann)
> - Split lines copy to drm_fb_gray8_to_mono_reversed_line() (Thomas Zimmermann)
> - Handle case where the source buffer is not aligned to 8 (Thomas Zimmermann)
> 
>   drivers/gpu/drm/drm_format_helper.c | 107 ++++++++++++++++++++++++++++
>   include/drm/drm_format_helper.h     |   4 ++
>   2 files changed, 111 insertions(+)
> 
> diff --git a/drivers/gpu/drm/drm_format_helper.c b/drivers/gpu/drm/drm_format_helper.c
> index b981712623d3..ec4e3724ee79 100644
> --- a/drivers/gpu/drm/drm_format_helper.c
> +++ b/drivers/gpu/drm/drm_format_helper.c
> @@ -591,3 +591,110 @@ int drm_fb_blit_toio(void __iomem *dst, unsigned int dst_pitch, uint32_t dst_for
>   	return -EINVAL;
>   }
>   EXPORT_SYMBOL(drm_fb_blit_toio);
> +
> +static void drm_fb_gray8_to_mono_reversed_line(u8 *dst, const u8 *src, unsigned int pixels,
> +					       unsigned int start_offset, unsigned int end_len)
> +{
> +	unsigned int xb, i;
> +
> +	for (xb = 0; xb < pixels; xb++) {
> +		unsigned int start = 0, end = 8;
> +		u8 byte = 0x00;
> +
> +		if (xb == 0 && start_offset)
> +			start = start_offset;
> +
> +		if (xb == pixels - 1 && end_len)
> +			end = end_len;
> +
> +		for (i = start; i < end; i++) {
> +			unsigned int x = xb * 8 + i;
> +
> +			byte >>= 1;
> +			if (src[x] >> 7)
> +				byte |= BIT(7);
> +		}
> +		*dst++ = byte;
> +	}
> +}
> +
> +/**
> + * drm_fb_xrgb8888_to_mono_reversed - Convert XRGB8888 to reversed monochrome
> + * @dst: reversed monochrome destination buffer
> + * @dst_pitch: Number of bytes between two consecutive scanlines within dst
> + * @src: XRGB8888 source buffer
> + * @fb: DRM framebuffer
> + * @clip: Clip rectangle area to copy
> + *
> + * DRM doesn't have native monochrome support.
> + * Such drivers can announce the commonly supported XR24 format to userspace
> + * and use this function to convert to the native format.
> + *
> + * This function uses drm_fb_xrgb8888_to_gray8() to convert to grayscale and
> + * then the result is converted from grayscale to reversed monohrome.
> + */
> +void drm_fb_xrgb8888_to_mono_reversed(void *dst, unsigned int dst_pitch, const void *vaddr,
> +				      const struct drm_framebuffer *fb, const struct drm_rect *clip)
> +{
> +	unsigned int linepixels = drm_rect_width(clip);
> +	unsigned int lines = clip->y2 - clip->y1;
> +	unsigned int cpp = fb->format->cpp[0];
> +	unsigned int len_src32 = linepixels * cpp;
> +	unsigned int start_offset, end_len;
> +	unsigned int y;
> +	u8 *mono = dst, *gray8;
> +	u32 *src32;
> +
> +	if (WARN_ON(fb->format->format != DRM_FORMAT_XRGB8888))
> +		return;

These WARN macros are deprecated. Use drm_warn, drm_WARN_ONCE, etc instead.

Best regards
Thomas

> +
> +	/*
> +	 * The reversed mono destination buffer contains 1 bit per pixel
> +	 * and destination scanlines have to be in multiple of 8 pixels.
> +	 */
> +	if (!dst_pitch)
> +		dst_pitch = DIV_ROUND_UP(linepixels, 8);
> +
> +	WARN_ONCE(dst_pitch % 8 != 0, "dst_pitch is not a multiple of 8\n");
> +
> +	/*
> +	 * The cma memory is write-combined so reads are uncached.
> +	 * Speed up by fetching one line at a time.
> +	 *
> +	 * Also, format conversion from XR24 to reversed monochrome
> +	 * are done line-by-line but are converted to 8-bit grayscale
> +	 * as an intermediate step.
> +	 *
> +	 * Allocate a buffer to be used for both copying from the cma
> +	 * memory and to store the intermediate grayscale line pixels.
> +	 */
> +	src32 = kmalloc(len_src32 + linepixels, GFP_KERNEL);
> +	if (!src32)
> +		return;
> +
> +	gray8 = (u8 *)src32 + len_src32;
> +
> +	/*
> +	 * For damage handling, it is possible that only parts of the source
> +	 * buffer is copied and this could lead to start and end pixels that
> +	 * are not aligned to multiple of 8.
> +	 *
> +	 * Calculate if the start and end pixels are not aligned and set the
> +	 * offsets for the reversed mono line conversion function to adjust.
> +	 */
> +	start_offset = clip->x1 % 8;
> +	end_len = clip->x2 % 8;
> +
> +	vaddr += clip_offset(clip, fb->pitches[0], cpp);
> +	for (y = 0; y < lines; y++) {
> +		src32 = memcpy(src32, vaddr, len_src32);
> +		drm_fb_xrgb8888_to_gray8_line(gray8, src32, linepixels);
> +		drm_fb_gray8_to_mono_reversed_line(mono, gray8, dst_pitch,
> +						   start_offset, end_len);
> +		vaddr += fb->pitches[0];
> +		mono += dst_pitch;
> +	}
> +
> +	kfree(src32);
> +}
> +EXPORT_SYMBOL(drm_fb_xrgb8888_to_mono_reversed);
> diff --git a/include/drm/drm_format_helper.h b/include/drm/drm_format_helper.h
> index b30ed5de0a33..0b0937c0b2f6 100644
> --- a/include/drm/drm_format_helper.h
> +++ b/include/drm/drm_format_helper.h
> @@ -43,4 +43,8 @@ int drm_fb_blit_toio(void __iomem *dst, unsigned int dst_pitch, uint32_t dst_for
>   		     const void *vmap, const struct drm_framebuffer *fb,
>   		     const struct drm_rect *rect);
>   
> +void drm_fb_xrgb8888_to_mono_reversed(void *dst, unsigned int dst_pitch, const void *src,
> +				      const struct drm_framebuffer *fb,
> +				      const struct drm_rect *clip);
> +
>   #endif /* __LINUX_DRM_FORMAT_HELPER_H */

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Ivo Totev

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 1/6] drm/format-helper: Add drm_fb_xrgb8888_to_gray8_line()
  2022-02-11 12:05           ` Jani Nikula
  2022-02-11 12:11             ` Javier Martinez Canillas
  2022-02-11 12:27             ` Geert Uytterhoeven
@ 2022-02-11 15:41             ` Andy Shevchenko
  2022-02-11 16:25               ` Jani Nikula
  2022-02-14  9:03               ` Thomas Zimmermann
  2 siblings, 2 replies; 43+ messages in thread
From: Andy Shevchenko @ 2022-02-11 15:41 UTC (permalink / raw)
  To: Jani Nikula
  Cc: Thomas Zimmermann, Javier Martinez Canillas, linux-fbdev,
	David Airlie, Daniel Vetter, linux-kernel, dri-devel,
	Noralf Trønnes, Geert Uytterhoeven, Maxime Ripard,
	Sam Ravnborg

On Fri, Feb 11, 2022 at 02:05:56PM +0200, Jani Nikula wrote:
> On Fri, 11 Feb 2022, Thomas Zimmermann <tzimmermann@suse.de> wrote:
> > Am 11.02.22 um 12:12 schrieb Andy Shevchenko:
> >> On Fri, Feb 11, 2022 at 11:40:13AM +0100, Javier Martinez Canillas wrote:
> >>> On 2/11/22 11:28, Andy Shevchenko wrote:
> >>>> On Fri, Feb 11, 2022 at 10:19:22AM +0100, Javier Martinez Canillas wrote:

...

> >>>>> +static void drm_fb_xrgb8888_to_gray8_line(u8 *dst, const u32 *src, unsigned int pixels)
> >>>>> +{
> >>>>> +	unsigned int x;
> >>>>> +
> >>>>> +	for (x = 0; x < pixels; x++) {
> >>>>> +		u8 r = (*src & 0x00ff0000) >> 16;
> >>>>> +		u8 g = (*src & 0x0000ff00) >> 8;
> >>>>> +		u8 b =  *src & 0x000000ff;
> >>>>> +
> >>>>> +		/* ITU BT.601: Y = 0.299 R + 0.587 G + 0.114 B */
> >>>>> +		*dst++ = (3 * r + 6 * g + b) / 10;
> >>>>> +		src++;
> >>>>> +	}
> >>>>
> >>>> Can be done as
> >>>>
> >>>> 	while (pixels--) {
> >>>> 		...
> >>>> 	}
> >>>>
> >>>> or
> >>>>
> >>>> 	do {
> >>>> 		...
> >>>> 	} while (--pixels);
> >>>>
> >>>
> >>> I don't see why a while loop would be an improvement here TBH.
> >> 
> >> Less letters to parse when reading the code.
> >
> > It's a simple refactoring of code that has worked well so far. Let's 
> > leave it as-is for now.
> 
> IMO *always* prefer a for loop over while or do-while.
> 
> The for (i = 0; i < N; i++) is such a strong paradigm in C. You
> instantly know how many times you're going to loop, at a glance. Not so
> with with the alternatives, which should be used sparingly.

while () {}  _is_ a paradigm, for-loop is syntax sugar on top of it.

> And yes, the do-while suggested above is buggy, and you actually need to
> stop and think to see why.

It depends if pixels can be 0 or not and if it's not, then does it contain last
or number.

The do {} while (--pixels); might be buggy iff pixels may be 0.

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 3/6] drm: Add driver for Solomon SSD130x OLED displays
  2022-02-11 12:05     ` Javier Martinez Canillas
  2022-02-11 12:23       ` Geert Uytterhoeven
@ 2022-02-11 15:49       ` Andy Shevchenko
  1 sibling, 0 replies; 43+ messages in thread
From: Andy Shevchenko @ 2022-02-11 15:49 UTC (permalink / raw)
  To: Javier Martinez Canillas
  Cc: linux-kernel, linux-fbdev, Geert Uytterhoeven, Maxime Ripard,
	Daniel Vetter, dri-devel, Thomas Zimmermann, Sam Ravnborg,
	Noralf Trønnes, Daniel Vetter, David Airlie, Lee Jones,
	Maarten Lankhorst, Maxime Ripard, Thierry Reding,
	Uwe Kleine-König, linux-pwm

On Fri, Feb 11, 2022 at 01:05:57PM +0100, Javier Martinez Canillas wrote:
> On 2/11/22 12:33, Andy Shevchenko wrote:
> > On Fri, Feb 11, 2022 at 10:19:24AM +0100, Javier Martinez Canillas wrote:

...

> >> + * Helper to write command (SSD130X_COMMAND). The fist variadic argument
> >> + * is the command to write and the following are the command options.
> > 
> > This is not correct explanation. Please, rephrase to show that _each_ of the
> > options is sent with a preceding command.
> >
> 
> It's a correct explanation IMO from the caller point of view. The first argument
> is the command sent (i.e: SSD130X_SET_ADDRESS_MODE) and the next ones are the
> the command options (i.e: SSD130X_SET_ADDRESS_MODE_HORIZONTAL).
> 
> The fact that each command and options are preceding with a SSD130X_COMMAND
> value is part of the protocol of the device and a detail that's abstracted
> away by this helper function to the callers.

My previous suggestion about bulk transaction was purely based on this
(misinterpreted) description. Can we make sure somehow that another reader
don't trap into the same?

...


> >> +	bl = devm_backlight_device_register(dev, dev_name(dev), dev, ssd130x,
> >> +					    &ssd130xfb_bl_ops, NULL);
> >> +	if (IS_ERR(bl)) {
> > 
> >> +		ret = PTR_ERR(bl);
> >> +		dev_err_probe(dev, ret, "Unable to register backlight device\n");
> >> +		return ERR_PTR(ret);
> > 
> > 		dev_err_probe(dev, PTR_ERR(bl), "Unable to register backlight device\n");
> > 		return bl;
> > 
> > ?
> 
> No, because this function's return value is a struct ssd130x_device pointer,
> not a struct backlight_device pointer.

	return ERR_CAST(bl);

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 2/6] drm/format-helper: Add drm_fb_xrgb8888_to_mono_reversed()
  2022-02-11 11:50     ` Javier Martinez Canillas
@ 2022-02-11 15:55       ` Andy Shevchenko
  0 siblings, 0 replies; 43+ messages in thread
From: Andy Shevchenko @ 2022-02-11 15:55 UTC (permalink / raw)
  To: Javier Martinez Canillas
  Cc: linux-kernel, linux-fbdev, Geert Uytterhoeven, Maxime Ripard,
	Daniel Vetter, dri-devel, Thomas Zimmermann, Sam Ravnborg,
	Noralf Trønnes, Daniel Vetter, David Airlie,
	Maarten Lankhorst, Maxime Ripard

On Fri, Feb 11, 2022 at 12:50:04PM +0100, Javier Martinez Canillas wrote:
> On 2/11/22 12:10, Andy Shevchenko wrote:

...

> >> +	for (xb = 0; xb < pixels; xb++) {
> >> +		unsigned int start = 0, end = 8;
> >> +		u8 byte = 0x00;
> > 
> >> +		if (xb == 0 && start_offset)
> >> +			start = start_offset;
> > 
> > This is invariant to the loop, can be moved out.
> > 
> >> +		if (xb == pixels - 1 && end_len)
> >> +			end = end_len;
> > 
> > Ditto. However it may require to factor out the following loop to a helper.
> 
> Not sure I'm following, it's not invariant since it depends on the
> loop iterator value. It only applies to the first and last pixels.

It's. You simply does it at the last iteration which may be perfectly done
outside of the main (aligned) loop.

...

> >> +		dst_pitch = DIV_ROUND_UP(linepixels, 8);
> > 
> > round_up() ?
> 
> But it's not a round up operation but a div and round up.

Indeed.

...

> >> +	WARN_ONCE(dst_pitch % 8 != 0, "dst_pitch is not a multiple of 8\n");
> > 
> > 
> > I would move this to the if conditional, i.e.
> > 
> > 	if (dst_pitch)
> > 		WARN_ONCE(dst_pitch % 8 != 0, "dst_pitch is not a multiple of 8\n");
> > 	else
> > 		dst_pitch = round_up(linepixels, 8);
> 
> No, because we always need to div and round up. The warning is just printed to
> let know that the dst pitch is not a multiple of 8 as it should be. So callers
> could be fixed.

Okay, you expect that linepixels to be multiple of 64? Otherwise I didn't get
what's going on with this warning.

...

> >> +	start_offset = clip->x1 % 8;
> >> +	end_len = clip->x2 % 8;
> > 
> > ALIGN() ?
> 
> But we don't want to align here but to know what's the start and end if is
> not aligned since that would mean converting to mono in the middle of a byte.

Indeed. Somehow I missed that it's a complimentary to ALIGN().

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 1/6] drm/format-helper: Add drm_fb_xrgb8888_to_gray8_line()
  2022-02-11 15:41             ` Andy Shevchenko
@ 2022-02-11 16:25               ` Jani Nikula
  2022-02-11 17:27                 ` Andy Shevchenko
  2022-02-14  9:03               ` Thomas Zimmermann
  1 sibling, 1 reply; 43+ messages in thread
From: Jani Nikula @ 2022-02-11 16:25 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Thomas Zimmermann, Javier Martinez Canillas, linux-fbdev,
	David Airlie, Daniel Vetter, linux-kernel, dri-devel,
	Noralf Trønnes, Geert Uytterhoeven, Maxime Ripard,
	Sam Ravnborg

On Fri, 11 Feb 2022, Andy Shevchenko <andriy.shevchenko@linux.intel.com> wrote:
> On Fri, Feb 11, 2022 at 02:05:56PM +0200, Jani Nikula wrote:
>> On Fri, 11 Feb 2022, Thomas Zimmermann <tzimmermann@suse.de> wrote:
>> > Am 11.02.22 um 12:12 schrieb Andy Shevchenko:
>> >> On Fri, Feb 11, 2022 at 11:40:13AM +0100, Javier Martinez Canillas wrote:
>> >>> On 2/11/22 11:28, Andy Shevchenko wrote:
>> >>>> On Fri, Feb 11, 2022 at 10:19:22AM +0100, Javier Martinez Canillas wrote:
>
> ...
>
>> >>>>> +static void drm_fb_xrgb8888_to_gray8_line(u8 *dst, const u32 *src, unsigned int pixels)
>> >>>>> +{
>> >>>>> +	unsigned int x;
>> >>>>> +
>> >>>>> +	for (x = 0; x < pixels; x++) {
>> >>>>> +		u8 r = (*src & 0x00ff0000) >> 16;
>> >>>>> +		u8 g = (*src & 0x0000ff00) >> 8;
>> >>>>> +		u8 b =  *src & 0x000000ff;
>> >>>>> +
>> >>>>> +		/* ITU BT.601: Y = 0.299 R + 0.587 G + 0.114 B */
>> >>>>> +		*dst++ = (3 * r + 6 * g + b) / 10;
>> >>>>> +		src++;
>> >>>>> +	}
>> >>>>
>> >>>> Can be done as
>> >>>>
>> >>>> 	while (pixels--) {
>> >>>> 		...
>> >>>> 	}
>> >>>>
>> >>>> or
>> >>>>
>> >>>> 	do {
>> >>>> 		...
>> >>>> 	} while (--pixels);
>> >>>>
>> >>>
>> >>> I don't see why a while loop would be an improvement here TBH.
>> >> 
>> >> Less letters to parse when reading the code.
>> >
>> > It's a simple refactoring of code that has worked well so far. Let's 
>> > leave it as-is for now.
>> 
>> IMO *always* prefer a for loop over while or do-while.
>> 
>> The for (i = 0; i < N; i++) is such a strong paradigm in C. You
>> instantly know how many times you're going to loop, at a glance. Not so
>> with with the alternatives, which should be used sparingly.
>
> while () {}  _is_ a paradigm, for-loop is syntax sugar on top of it.

And while() is just syntax sugar for goto. :p

The for loop written as for (i = 0; i < N; i++) is hands down the most
obvious counting loop pattern there is in C.

>> And yes, the do-while suggested above is buggy, and you actually need to
>> stop and think to see why.
>
> It depends if pixels can be 0 or not and if it's not, then does it contain last
> or number.
>
> The do {} while (--pixels); might be buggy iff pixels may be 0.

Yeah. And how long does it take to figure that out?


BR,
Jani.

-- 
Jani Nikula, Intel Open Source Graphics Center

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 1/6] drm/format-helper: Add drm_fb_xrgb8888_to_gray8_line()
  2022-02-11 16:25               ` Jani Nikula
@ 2022-02-11 17:27                 ` Andy Shevchenko
  2022-02-14  9:17                   ` Pekka Paalanen
  0 siblings, 1 reply; 43+ messages in thread
From: Andy Shevchenko @ 2022-02-11 17:27 UTC (permalink / raw)
  To: Jani Nikula
  Cc: Thomas Zimmermann, Javier Martinez Canillas, linux-fbdev,
	David Airlie, Daniel Vetter, linux-kernel, dri-devel,
	Noralf Trønnes, Geert Uytterhoeven, Maxime Ripard,
	Sam Ravnborg

On Fri, Feb 11, 2022 at 06:25:17PM +0200, Jani Nikula wrote:
> On Fri, 11 Feb 2022, Andy Shevchenko <andriy.shevchenko@linux.intel.com> wrote:
> > On Fri, Feb 11, 2022 at 02:05:56PM +0200, Jani Nikula wrote:
> >> On Fri, 11 Feb 2022, Thomas Zimmermann <tzimmermann@suse.de> wrote:
> >> > Am 11.02.22 um 12:12 schrieb Andy Shevchenko:
> >> >> On Fri, Feb 11, 2022 at 11:40:13AM +0100, Javier Martinez Canillas wrote:
> >> >>> On 2/11/22 11:28, Andy Shevchenko wrote:
> >> >>>> On Fri, Feb 11, 2022 at 10:19:22AM +0100, Javier Martinez Canillas wrote:
> >
> > ...
> >
> >> >>>>> +static void drm_fb_xrgb8888_to_gray8_line(u8 *dst, const u32 *src, unsigned int pixels)
> >> >>>>> +{
> >> >>>>> +	unsigned int x;
> >> >>>>> +
> >> >>>>> +	for (x = 0; x < pixels; x++) {
> >> >>>>> +		u8 r = (*src & 0x00ff0000) >> 16;
> >> >>>>> +		u8 g = (*src & 0x0000ff00) >> 8;
> >> >>>>> +		u8 b =  *src & 0x000000ff;
> >> >>>>> +
> >> >>>>> +		/* ITU BT.601: Y = 0.299 R + 0.587 G + 0.114 B */
> >> >>>>> +		*dst++ = (3 * r + 6 * g + b) / 10;
> >> >>>>> +		src++;
> >> >>>>> +	}
> >> >>>>
> >> >>>> Can be done as
> >> >>>>
> >> >>>> 	while (pixels--) {
> >> >>>> 		...
> >> >>>> 	}
> >> >>>>
> >> >>>> or
> >> >>>>
> >> >>>> 	do {
> >> >>>> 		...
> >> >>>> 	} while (--pixels);
> >> >>>>
> >> >>>
> >> >>> I don't see why a while loop would be an improvement here TBH.
> >> >> 
> >> >> Less letters to parse when reading the code.
> >> >
> >> > It's a simple refactoring of code that has worked well so far. Let's 
> >> > leave it as-is for now.
> >> 
> >> IMO *always* prefer a for loop over while or do-while.
> >> 
> >> The for (i = 0; i < N; i++) is such a strong paradigm in C. You
> >> instantly know how many times you're going to loop, at a glance. Not so
> >> with with the alternatives, which should be used sparingly.
> >
> > while () {}  _is_ a paradigm, for-loop is syntax sugar on top of it.
> 
> And while() is just syntax sugar for goto. :p
> 
> The for loop written as for (i = 0; i < N; i++) is hands down the most
> obvious counting loop pattern there is in C.
> 
> >> And yes, the do-while suggested above is buggy, and you actually need to
> >> stop and think to see why.
> >
> > It depends if pixels can be 0 or not and if it's not, then does it contain last
> > or number.
> >
> > The do {} while (--pixels); might be buggy iff pixels may be 0.
> 
> Yeah. And how long does it take to figure that out?

Okay, I made a mistake to drop the explanation. So, I (mistakenly) assumed
that people know this difference between post-decrement and pre-decrement
(note, while-loop here is not what is problematic).

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 1/6] drm/format-helper: Add drm_fb_xrgb8888_to_gray8_line()
  2022-02-11 15:41             ` Andy Shevchenko
  2022-02-11 16:25               ` Jani Nikula
@ 2022-02-14  9:03               ` Thomas Zimmermann
  2022-02-14 10:38                 ` Andy Shevchenko
  1 sibling, 1 reply; 43+ messages in thread
From: Thomas Zimmermann @ 2022-02-14  9:03 UTC (permalink / raw)
  To: Andy Shevchenko, Jani Nikula
  Cc: Javier Martinez Canillas, linux-fbdev, David Airlie,
	Daniel Vetter, linux-kernel, dri-devel, Noralf Trønnes,
	Geert Uytterhoeven, Maxime Ripard, Sam Ravnborg


[-- Attachment #1.1: Type: text/plain, Size: 1078 bytes --]

Hi

Am 11.02.22 um 16:41 schrieb Andy Shevchenko:
[...]
>> IMO *always* prefer a for loop over while or do-while.
>>
>> The for (i = 0; i < N; i++) is such a strong paradigm in C. You
>> instantly know how many times you're going to loop, at a glance. Not so
>> with with the alternatives, which should be used sparingly.
> 
> while () {}  _is_ a paradigm, for-loop is syntax sugar on top of it.

Naw, that's not true. An idiomatic for loop, such as for (i = ...; i < 
N; ++i), is such a strong pattern that it's way better than the 
corresponding while loop.

Best regards
Thomas

> 
>> And yes, the do-while suggested above is buggy, and you actually need to
>> stop and think to see why.
> 
> It depends if pixels can be 0 or not and if it's not, then does it contain last
> or number.
> 
> The do {} while (--pixels); might be buggy iff pixels may be 0.
> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Ivo Totev

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 1/6] drm/format-helper: Add drm_fb_xrgb8888_to_gray8_line()
  2022-02-11 17:27                 ` Andy Shevchenko
@ 2022-02-14  9:17                   ` Pekka Paalanen
  2022-02-14 10:26                     ` Andy Shevchenko
  0 siblings, 1 reply; 43+ messages in thread
From: Pekka Paalanen @ 2022-02-14  9:17 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Jani Nikula, linux-fbdev, David Airlie, Daniel Vetter,
	Javier Martinez Canillas, dri-devel, linux-kernel,
	Noralf Trønnes, Geert Uytterhoeven, Maxime Ripard,
	Thomas Zimmermann, Sam Ravnborg

[-- Attachment #1: Type: text/plain, Size: 3502 bytes --]

On Fri, 11 Feb 2022 19:27:12 +0200
Andy Shevchenko <andriy.shevchenko@linux.intel.com> wrote:

> On Fri, Feb 11, 2022 at 06:25:17PM +0200, Jani Nikula wrote:
> > On Fri, 11 Feb 2022, Andy Shevchenko <andriy.shevchenko@linux.intel.com> wrote:  
> > > On Fri, Feb 11, 2022 at 02:05:56PM +0200, Jani Nikula wrote:  
> > >> On Fri, 11 Feb 2022, Thomas Zimmermann <tzimmermann@suse.de> wrote:  
> > >> > Am 11.02.22 um 12:12 schrieb Andy Shevchenko:  
> > >> >> On Fri, Feb 11, 2022 at 11:40:13AM +0100, Javier Martinez Canillas wrote:  
> > >> >>> On 2/11/22 11:28, Andy Shevchenko wrote:  
> > >> >>>> On Fri, Feb 11, 2022 at 10:19:22AM +0100, Javier Martinez Canillas wrote:  
> > >
> > > ...
> > >  
> > >> >>>>> +static void drm_fb_xrgb8888_to_gray8_line(u8 *dst, const u32 *src, unsigned int pixels)
> > >> >>>>> +{
> > >> >>>>> +	unsigned int x;
> > >> >>>>> +
> > >> >>>>> +	for (x = 0; x < pixels; x++) {
> > >> >>>>> +		u8 r = (*src & 0x00ff0000) >> 16;
> > >> >>>>> +		u8 g = (*src & 0x0000ff00) >> 8;
> > >> >>>>> +		u8 b =  *src & 0x000000ff;
> > >> >>>>> +
> > >> >>>>> +		/* ITU BT.601: Y = 0.299 R + 0.587 G + 0.114 B */
> > >> >>>>> +		*dst++ = (3 * r + 6 * g + b) / 10;
> > >> >>>>> +		src++;
> > >> >>>>> +	}  
> > >> >>>>
> > >> >>>> Can be done as
> > >> >>>>
> > >> >>>> 	while (pixels--) {
> > >> >>>> 		...
> > >> >>>> 	}
> > >> >>>>
> > >> >>>> or
> > >> >>>>
> > >> >>>> 	do {
> > >> >>>> 		...
> > >> >>>> 	} while (--pixels);
> > >> >>>>  
> > >> >>>
> > >> >>> I don't see why a while loop would be an improvement here TBH.  
> > >> >> 
> > >> >> Less letters to parse when reading the code.  
> > >> >
> > >> > It's a simple refactoring of code that has worked well so far. Let's 
> > >> > leave it as-is for now.  
> > >> 
> > >> IMO *always* prefer a for loop over while or do-while.
> > >> 
> > >> The for (i = 0; i < N; i++) is such a strong paradigm in C. You
> > >> instantly know how many times you're going to loop, at a glance. Not so
> > >> with with the alternatives, which should be used sparingly.  
> > >
> > > while () {}  _is_ a paradigm, for-loop is syntax sugar on top of it.  
> > 
> > And while() is just syntax sugar for goto. :p
> > 
> > The for loop written as for (i = 0; i < N; i++) is hands down the most
> > obvious counting loop pattern there is in C.
> >   
> > >> And yes, the do-while suggested above is buggy, and you actually need to
> > >> stop and think to see why.  
> > >
> > > It depends if pixels can be 0 or not and if it's not, then does it contain last
> > > or number.
> > >
> > > The do {} while (--pixels); might be buggy iff pixels may be 0.  
> > 
> > Yeah. And how long does it take to figure that out?  
> 
> Okay, I made a mistake to drop the explanation. So, I (mistakenly) assumed
> that people know this difference between post-decrement and pre-decrement
> (note, while-loop here is not what is problematic).

That was not the question.

The question was, how long does it take to figure out if pixels can or
cannot be zero?

Code is styled for humans other than the author, not for compilers.

Having to stop to think about the difference between post- and
pre-decrement to figure out when the while-loop runs does take me a few
more brain cycles to understand, even though I know the rules very well.

I would call that brain cycle optimization, and leave the CPU cycle
optimization for the compiler in these cases.


Thanks,
pq

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 1/6] drm/format-helper: Add drm_fb_xrgb8888_to_gray8_line()
  2022-02-14  9:17                   ` Pekka Paalanen
@ 2022-02-14 10:26                     ` Andy Shevchenko
  0 siblings, 0 replies; 43+ messages in thread
From: Andy Shevchenko @ 2022-02-14 10:26 UTC (permalink / raw)
  To: Pekka Paalanen
  Cc: Jani Nikula, linux-fbdev, David Airlie, Daniel Vetter,
	Javier Martinez Canillas, dri-devel, linux-kernel,
	Noralf Trønnes, Geert Uytterhoeven, Maxime Ripard,
	Thomas Zimmermann, Sam Ravnborg

On Mon, Feb 14, 2022 at 11:17:11AM +0200, Pekka Paalanen wrote:
> On Fri, 11 Feb 2022 19:27:12 +0200
> Andy Shevchenko <andriy.shevchenko@linux.intel.com> wrote:
> > On Fri, Feb 11, 2022 at 06:25:17PM +0200, Jani Nikula wrote:
> > > On Fri, 11 Feb 2022, Andy Shevchenko <andriy.shevchenko@linux.intel.com> wrote:  
> > > > On Fri, Feb 11, 2022 at 02:05:56PM +0200, Jani Nikula wrote:  
> > > >> On Fri, 11 Feb 2022, Thomas Zimmermann <tzimmermann@suse.de> wrote:  
> > > >> > Am 11.02.22 um 12:12 schrieb Andy Shevchenko:  
> > > >> >> On Fri, Feb 11, 2022 at 11:40:13AM +0100, Javier Martinez Canillas wrote:  
> > > >> >>> On 2/11/22 11:28, Andy Shevchenko wrote:  
> > > >> >>>> On Fri, Feb 11, 2022 at 10:19:22AM +0100, Javier Martinez Canillas wrote:  

...

> > > >> >>>>> +static void drm_fb_xrgb8888_to_gray8_line(u8 *dst, const u32 *src, unsigned int pixels)
> > > >> >>>>> +{
> > > >> >>>>> +	unsigned int x;
> > > >> >>>>> +
> > > >> >>>>> +	for (x = 0; x < pixels; x++) {
> > > >> >>>>> +		u8 r = (*src & 0x00ff0000) >> 16;
> > > >> >>>>> +		u8 g = (*src & 0x0000ff00) >> 8;
> > > >> >>>>> +		u8 b =  *src & 0x000000ff;
> > > >> >>>>> +
> > > >> >>>>> +		/* ITU BT.601: Y = 0.299 R + 0.587 G + 0.114 B */
> > > >> >>>>> +		*dst++ = (3 * r + 6 * g + b) / 10;
> > > >> >>>>> +		src++;
> > > >> >>>>> +	}  
> > > >> >>>>
> > > >> >>>> Can be done as
> > > >> >>>>
> > > >> >>>> 	while (pixels--) {
> > > >> >>>> 		...
> > > >> >>>> 	}
> > > >> >>>>
> > > >> >>>> or
> > > >> >>>>
> > > >> >>>> 	do {
> > > >> >>>> 		...
> > > >> >>>> 	} while (--pixels);
> > > >> >>>>  
> > > >> >>>
> > > >> >>> I don't see why a while loop would be an improvement here TBH.  
> > > >> >> 
> > > >> >> Less letters to parse when reading the code.  
> > > >> >
> > > >> > It's a simple refactoring of code that has worked well so far. Let's 
> > > >> > leave it as-is for now.  
> > > >> 
> > > >> IMO *always* prefer a for loop over while or do-while.
> > > >> 
> > > >> The for (i = 0; i < N; i++) is such a strong paradigm in C. You
> > > >> instantly know how many times you're going to loop, at a glance. Not so
> > > >> with with the alternatives, which should be used sparingly.  
> > > >
> > > > while () {}  _is_ a paradigm, for-loop is syntax sugar on top of it.  
> > > 
> > > And while() is just syntax sugar for goto. :p
> > > 
> > > The for loop written as for (i = 0; i < N; i++) is hands down the most
> > > obvious counting loop pattern there is in C.
> > >   
> > > >> And yes, the do-while suggested above is buggy, and you actually need to
> > > >> stop and think to see why.  
> > > >
> > > > It depends if pixels can be 0 or not and if it's not, then does it contain last
> > > > or number.
> > > >
> > > > The do {} while (--pixels); might be buggy iff pixels may be 0.  
> > > 
> > > Yeah. And how long does it take to figure that out?  
> > 
> > Okay, I made a mistake to drop the explanation. So, I (mistakenly) assumed
> > that people know this difference between post-decrement and pre-decrement
> > (note, while-loop here is not what is problematic).
> 
> That was not the question.
> 
> The question was, how long does it take to figure out if pixels can or
> cannot be zero?

To me these patterns, while() {} and do {} while(), while being shorter,
also give a hint. So if one is familiar with C, the do {} while (--foo)
_gives a hint_ while being shorter. It requires _less_ brain power to get
this.

But I assume my brain is unique and not working as million of others.

> Code is styled for humans other than the author, not for compilers.
> 
> Having to stop to think about the difference between post- and
> pre-decrement to figure out when the while-loop runs does take me a few
> more brain cycles to understand, even though I know the rules very well.
> 
> I would call that brain cycle optimization, and leave the CPU cycle
> optimization for the compiler in these cases.



-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 1/6] drm/format-helper: Add drm_fb_xrgb8888_to_gray8_line()
  2022-02-14  9:03               ` Thomas Zimmermann
@ 2022-02-14 10:38                 ` Andy Shevchenko
  2022-02-14 10:52                   ` Simon Ser
                                     ` (2 more replies)
  0 siblings, 3 replies; 43+ messages in thread
From: Andy Shevchenko @ 2022-02-14 10:38 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: Jani Nikula, Javier Martinez Canillas, linux-fbdev, David Airlie,
	Daniel Vetter, linux-kernel, dri-devel, Noralf Trønnes,
	Geert Uytterhoeven, Maxime Ripard, Sam Ravnborg

On Mon, Feb 14, 2022 at 10:03:53AM +0100, Thomas Zimmermann wrote:
> Am 11.02.22 um 16:41 schrieb Andy Shevchenko:

...

> > > IMO *always* prefer a for loop over while or do-while.
> > > 
> > > The for (i = 0; i < N; i++) is such a strong paradigm in C. You
> > > instantly know how many times you're going to loop, at a glance. Not so
> > > with with the alternatives, which should be used sparingly.
> > 
> > while () {}  _is_ a paradigm, for-loop is syntax sugar on top of it.
> 
> Naw, that's not true.

In the section 3.5 "Loops - While and For" in "The C Programming
Language" 2nd by K&R, the authors said:

	The for statement ... is equivalent to ... while..."

They said that for is equivalent to while, and not otherwise.

Also, syntax sugar by definition declares something that can be written as
a single line of code, which usually is done using more (not always).

> An idiomatic for loop, such as for (i = ...; i < N;
> ++i), is such a strong pattern that it's way better than the corresponding
> while loop.

> > > And yes, the do-while suggested above is buggy, and you actually need to
> > > stop and think to see why.
> > 
> > It depends if pixels can be 0 or not and if it's not, then does it contain last
> > or number.
> > 
> > The do {} while (--pixels); might be buggy iff pixels may be 0.

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 1/6] drm/format-helper: Add drm_fb_xrgb8888_to_gray8_line()
  2022-02-14 10:38                 ` Andy Shevchenko
@ 2022-02-14 10:52                   ` Simon Ser
  2022-02-14 10:57                   ` Geert Uytterhoeven
  2022-02-14 12:12                   ` Thomas Zimmermann
  2 siblings, 0 replies; 43+ messages in thread
From: Simon Ser @ 2022-02-14 10:52 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Thomas Zimmermann, linux-fbdev, David Airlie, Daniel Vetter,
	Javier Martinez Canillas, linux-kernel, Noralf Trønnes,
	Geert Uytterhoeven, dri-devel, Sam Ravnborg, Maxime Ripard

On Monday, February 14th, 2022 at 11:38, Andy Shevchenko <andriy.shevchenko@linux.intel.com> wrote:

> > > > IMO *always* prefer a for loop over while or do-while.
> > > >
> > > > The for (i = 0; i < N; i++) is such a strong paradigm in C. You
> > > > instantly know how many times you're going to loop, at a glance. Not so
> > > > with with the alternatives, which should be used sparingly.
> > >
> > > while () {}  _is_ a paradigm, for-loop is syntax sugar on top of it.
> >
> > Naw, that's not true.
>
> In the section 3.5 "Loops - While and For" in "The C Programming
> Language" 2nd by K&R, the authors said:
>
> 	The for statement ... is equivalent to ... while..."
>
> They said that for is equivalent to while, and not otherwise.
>
> Also, syntax sugar by definition declares something that can be written as
> a single line of code, which usually is done using more (not always).

arr[i] is syntaxic sugar for *(arr + i), yet we keep writing the former,
because it's way more readable. The same goes for the for vs. while loops.
It may be obvious for you because you're a C guru, but to me it just obfuscates
the code. Too many C projects end up becoming completely unreadable because of
patterns like these.

Idiomatic C code isn't written by doing pointless micro-optimizations.

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 1/6] drm/format-helper: Add drm_fb_xrgb8888_to_gray8_line()
  2022-02-14 10:38                 ` Andy Shevchenko
  2022-02-14 10:52                   ` Simon Ser
@ 2022-02-14 10:57                   ` Geert Uytterhoeven
  2022-02-14 12:12                   ` Thomas Zimmermann
  2 siblings, 0 replies; 43+ messages in thread
From: Geert Uytterhoeven @ 2022-02-14 10:57 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Thomas Zimmermann, Jani Nikula, Javier Martinez Canillas,
	linux-fbdev, David Airlie, Daniel Vetter, linux-kernel,
	dri-devel, Noralf Trønnes, Maxime Ripard, Sam Ravnborg

Hi Andy,

On Mon, Feb 14, 2022 at 11:39 AM Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
> On Mon, Feb 14, 2022 at 10:03:53AM +0100, Thomas Zimmermann wrote:
> > Am 11.02.22 um 16:41 schrieb Andy Shevchenko:
> > > > IMO *always* prefer a for loop over while or do-while.
> > > >
> > > > The for (i = 0; i < N; i++) is such a strong paradigm in C. You
> > > > instantly know how many times you're going to loop, at a glance. Not so
> > > > with with the alternatives, which should be used sparingly.
> > >
> > > while () {}  _is_ a paradigm, for-loop is syntax sugar on top of it.
> >
> > Naw, that's not true.
>
> In the section 3.5 "Loops - While and For" in "The C Programming
> Language" 2nd by K&R, the authors said:
>
>         The for statement ... is equivalent to ... while..."
>
> They said that for is equivalent to while, and not otherwise.

When I learned C, people told me to prefer while() over for() when
possible, as several compilers are better at optimizing while()-loops
than for()-loops.

During the last 3 decades, optimizers got better, and all the bad
old compilers went the way of the dodo (see also [1])...
But even for a human, it's still less symbols to decode (and verify
all the details about =/</>/<=/>=/++/--/...) for

    while (n--) { ... }

than for

   for (i = 0; i < n; i++) { ... }

[1] https://lwn.net/Articles/871283/

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 1/6] drm/format-helper: Add drm_fb_xrgb8888_to_gray8_line()
  2022-02-14 10:38                 ` Andy Shevchenko
  2022-02-14 10:52                   ` Simon Ser
  2022-02-14 10:57                   ` Geert Uytterhoeven
@ 2022-02-14 12:12                   ` Thomas Zimmermann
  2022-02-14 12:47                     ` Ville Syrjälä
  2022-02-14 13:59                     ` Andy Shevchenko
  2 siblings, 2 replies; 43+ messages in thread
From: Thomas Zimmermann @ 2022-02-14 12:12 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Jani Nikula, Javier Martinez Canillas, linux-fbdev, David Airlie,
	Daniel Vetter, linux-kernel, dri-devel, Noralf Trønnes,
	Geert Uytterhoeven, Maxime Ripard, Sam Ravnborg


[-- Attachment #1.1: Type: text/plain, Size: 2115 bytes --]

Hi

Am 14.02.22 um 11:38 schrieb Andy Shevchenko:
> On Mon, Feb 14, 2022 at 10:03:53AM +0100, Thomas Zimmermann wrote:
>> Am 11.02.22 um 16:41 schrieb Andy Shevchenko:
> 
> ...
> 
>>>> IMO *always* prefer a for loop over while or do-while.
>>>>
>>>> The for (i = 0; i < N; i++) is such a strong paradigm in C. You
>>>> instantly know how many times you're going to loop, at a glance. Not so
>>>> with with the alternatives, which should be used sparingly.
>>>
>>> while () {}  _is_ a paradigm, for-loop is syntax sugar on top of it.
>>
>> Naw, that's not true.
> 
> In the section 3.5 "Loops - While and For" in "The C Programming
> Language" 2nd by K&R, the authors said:

Year of publication: 1988 . It's not the most up-to-date reference for C 
programming.

> 
> 	The for statement ... is equivalent to ... while..."
> 
> They said that for is equivalent to while, and not otherwise.

Even leaving readability aside, it's not equivalent. You can declare 
variables as part of the for statement. (I know it's not the kernel's 
style.) Also, 'continue' statements are not well-suited in for loops, 
because it's non-obvious if the loop's update statement is being 
executed. (It isn't.)

> 
> Also, syntax sugar by definition declares something that can be written as
> a single line of code, which usually is done using more (not always).

The discussion has entered the phase of hair splitting. Good.

Best regards
Thomas

> 
>> An idiomatic for loop, such as for (i = ...; i < N;
>> ++i), is such a strong pattern that it's way better than the corresponding
>> while loop.
> 
>>>> And yes, the do-while suggested above is buggy, and you actually need to
>>>> stop and think to see why.
>>>
>>> It depends if pixels can be 0 or not and if it's not, then does it contain last
>>> or number.
>>>
>>> The do {} while (--pixels); might be buggy iff pixels may be 0.
> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Ivo Totev

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 1/6] drm/format-helper: Add drm_fb_xrgb8888_to_gray8_line()
  2022-02-14 12:12                   ` Thomas Zimmermann
@ 2022-02-14 12:47                     ` Ville Syrjälä
  2022-02-14 12:54                       ` Thomas Zimmermann
  2022-02-14 13:59                     ` Andy Shevchenko
  1 sibling, 1 reply; 43+ messages in thread
From: Ville Syrjälä @ 2022-02-14 12:47 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: Andy Shevchenko, linux-fbdev, David Airlie, Daniel Vetter,
	Javier Martinez Canillas, linux-kernel, Noralf Trønnes,
	Geert Uytterhoeven, dri-devel, Sam Ravnborg, Maxime Ripard

On Mon, Feb 14, 2022 at 01:12:48PM +0100, Thomas Zimmermann wrote:
> Hi
> 
> Am 14.02.22 um 11:38 schrieb Andy Shevchenko:
> > On Mon, Feb 14, 2022 at 10:03:53AM +0100, Thomas Zimmermann wrote:
> >> Am 11.02.22 um 16:41 schrieb Andy Shevchenko:
> > 
> > ...
> > 
> >>>> IMO *always* prefer a for loop over while or do-while.
> >>>>
> >>>> The for (i = 0; i < N; i++) is such a strong paradigm in C. You
> >>>> instantly know how many times you're going to loop, at a glance. Not so
> >>>> with with the alternatives, which should be used sparingly.
> >>>
> >>> while () {}  _is_ a paradigm, for-loop is syntax sugar on top of it.
> >>
> >> Naw, that's not true.
> > 
> > In the section 3.5 "Loops - While and For" in "The C Programming
> > Language" 2nd by K&R, the authors said:
> 
> Year of publication: 1988 . It's not the most up-to-date reference for C 
> programming.
> 
> > 
> > 	The for statement ... is equivalent to ... while..."
> > 
> > They said that for is equivalent to while, and not otherwise.
> 
> Even leaving readability aside, it's not equivalent. You can declare 
> variables as part of the for statement. (I know it's not the kernel's 
> style.) Also, 'continue' statements are not well-suited in for loops, 
> because it's non-obvious if the loop's update statement is being 
> executed. (It isn't.)

It is.

'continue' is just shorthand for 'goto end_of_loop_body'.

-- 
Ville Syrjälä
Intel

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 1/6] drm/format-helper: Add drm_fb_xrgb8888_to_gray8_line()
  2022-02-14 12:47                     ` Ville Syrjälä
@ 2022-02-14 12:54                       ` Thomas Zimmermann
  2022-02-14 13:07                         ` Ville Syrjälä
  0 siblings, 1 reply; 43+ messages in thread
From: Thomas Zimmermann @ 2022-02-14 12:54 UTC (permalink / raw)
  To: Ville Syrjälä
  Cc: linux-fbdev, David Airlie, Daniel Vetter,
	Javier Martinez Canillas, dri-devel, linux-kernel,
	Noralf Trønnes, Geert Uytterhoeven, Maxime Ripard,
	Andy Shevchenko, Sam Ravnborg


[-- Attachment #1.1: Type: text/plain, Size: 1926 bytes --]

Hi

Am 14.02.22 um 13:47 schrieb Ville Syrjälä:
> On Mon, Feb 14, 2022 at 01:12:48PM +0100, Thomas Zimmermann wrote:
>> Hi
>>
>> Am 14.02.22 um 11:38 schrieb Andy Shevchenko:
>>> On Mon, Feb 14, 2022 at 10:03:53AM +0100, Thomas Zimmermann wrote:
>>>> Am 11.02.22 um 16:41 schrieb Andy Shevchenko:
>>>
>>> ...
>>>
>>>>>> IMO *always* prefer a for loop over while or do-while.
>>>>>>
>>>>>> The for (i = 0; i < N; i++) is such a strong paradigm in C. You
>>>>>> instantly know how many times you're going to loop, at a glance. Not so
>>>>>> with with the alternatives, which should be used sparingly.
>>>>>
>>>>> while () {}  _is_ a paradigm, for-loop is syntax sugar on top of it.
>>>>
>>>> Naw, that's not true.
>>>
>>> In the section 3.5 "Loops - While and For" in "The C Programming
>>> Language" 2nd by K&R, the authors said:
>>
>> Year of publication: 1988 . It's not the most up-to-date reference for C
>> programming.
>>
>>>
>>> 	The for statement ... is equivalent to ... while..."
>>>
>>> They said that for is equivalent to while, and not otherwise.
>>
>> Even leaving readability aside, it's not equivalent. You can declare
>> variables as part of the for statement. (I know it's not the kernel's
>> style.) Also, 'continue' statements are not well-suited in for loops,
>> because it's non-obvious if the loop's update statement is being
>> executed. (It isn't.)
> 
> It is.
> 
> 'continue' is just shorthand for 'goto end_of_loop_body'.

Well, indeed. lol

Fun fact: I actually had to look this up and still got it wrong. Let me 
just count it under proving-my-point: continue in a for statement is a 
bad idea and for isn't equivalent to while.

Best regards
Thomas

> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Ivo Totev

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 1/6] drm/format-helper: Add drm_fb_xrgb8888_to_gray8_line()
  2022-02-14 12:54                       ` Thomas Zimmermann
@ 2022-02-14 13:07                         ` Ville Syrjälä
  0 siblings, 0 replies; 43+ messages in thread
From: Ville Syrjälä @ 2022-02-14 13:07 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: linux-fbdev, David Airlie, Daniel Vetter,
	Javier Martinez Canillas, dri-devel, linux-kernel,
	Noralf Trønnes, Geert Uytterhoeven, Maxime Ripard,
	Andy Shevchenko, Sam Ravnborg

On Mon, Feb 14, 2022 at 01:54:59PM +0100, Thomas Zimmermann wrote:
> Hi
> 
> Am 14.02.22 um 13:47 schrieb Ville Syrjälä:
> > On Mon, Feb 14, 2022 at 01:12:48PM +0100, Thomas Zimmermann wrote:
> >> Hi
> >>
> >> Am 14.02.22 um 11:38 schrieb Andy Shevchenko:
> >>> On Mon, Feb 14, 2022 at 10:03:53AM +0100, Thomas Zimmermann wrote:
> >>>> Am 11.02.22 um 16:41 schrieb Andy Shevchenko:
> >>>
> >>> ...
> >>>
> >>>>>> IMO *always* prefer a for loop over while or do-while.
> >>>>>>
> >>>>>> The for (i = 0; i < N; i++) is such a strong paradigm in C. You
> >>>>>> instantly know how many times you're going to loop, at a glance. Not so
> >>>>>> with with the alternatives, which should be used sparingly.
> >>>>>
> >>>>> while () {}  _is_ a paradigm, for-loop is syntax sugar on top of it.
> >>>>
> >>>> Naw, that's not true.
> >>>
> >>> In the section 3.5 "Loops - While and For" in "The C Programming
> >>> Language" 2nd by K&R, the authors said:
> >>
> >> Year of publication: 1988 . It's not the most up-to-date reference for C
> >> programming.
> >>
> >>>
> >>> 	The for statement ... is equivalent to ... while..."
> >>>
> >>> They said that for is equivalent to while, and not otherwise.
> >>
> >> Even leaving readability aside, it's not equivalent. You can declare
> >> variables as part of the for statement. (I know it's not the kernel's
> >> style.) Also, 'continue' statements are not well-suited in for loops,
> >> because it's non-obvious if the loop's update statement is being
> >> executed. (It isn't.)
> > 
> > It is.
> > 
> > 'continue' is just shorthand for 'goto end_of_loop_body'.
> 
> Well, indeed. lol
> 
> Fun fact: I actually had to look this up and still got it wrong. Let me 
> just count it under proving-my-point: continue in a for statement is a 
> bad idea and for isn't equivalent to while.

Nah. We use 'continue' a *lot* in for loops in kms/atomic code.
I'd be surprised if you can find many loops without a 'continue'.

Looking at the loc stats I was a bit surprised to see more 'break'
but then I realized switch() is bloating up those numbers quite
a bit.

-- 
Ville Syrjälä
Intel

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 1/6] drm/format-helper: Add drm_fb_xrgb8888_to_gray8_line()
  2022-02-14 12:12                   ` Thomas Zimmermann
  2022-02-14 12:47                     ` Ville Syrjälä
@ 2022-02-14 13:59                     ` Andy Shevchenko
  1 sibling, 0 replies; 43+ messages in thread
From: Andy Shevchenko @ 2022-02-14 13:59 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: Jani Nikula, Javier Martinez Canillas, linux-fbdev, David Airlie,
	Daniel Vetter, linux-kernel, dri-devel, Noralf Trønnes,
	Geert Uytterhoeven, Maxime Ripard, Sam Ravnborg

On Mon, Feb 14, 2022 at 01:12:48PM +0100, Thomas Zimmermann wrote:
> Am 14.02.22 um 11:38 schrieb Andy Shevchenko:
> > On Mon, Feb 14, 2022 at 10:03:53AM +0100, Thomas Zimmermann wrote:
> > > Am 11.02.22 um 16:41 schrieb Andy Shevchenko:

...

> > > > > IMO *always* prefer a for loop over while or do-while.
> > > > > 
> > > > > The for (i = 0; i < N; i++) is such a strong paradigm in C. You
> > > > > instantly know how many times you're going to loop, at a glance. Not so
> > > > > with with the alternatives, which should be used sparingly.
> > > > 
> > > > while () {}  _is_ a paradigm, for-loop is syntax sugar on top of it.
> > > 
> > > Naw, that's not true.
> > 
> > In the section 3.5 "Loops - While and For" in "The C Programming
> > Language" 2nd by K&R, the authors said:
> 
> Year of publication: 1988 . It's not the most up-to-date reference for C
> programming.

Yet this makes your above remark invalid, i.e. `for` _is_ syntax sugar despite
what you think it's idiomatic _nowadays_.

> > 	The for statement ... is equivalent to ... while..."
> > 
> > They said that for is equivalent to while, and not otherwise.
> 
> Even leaving readability aside, it's not equivalent. You can declare
> variables as part of the for statement. (I know it's not the kernel's
> style.) Also, 'continue' statements are not well-suited in for loops,
> because it's non-obvious if the loop's update statement is being executed.
> (It isn't.)

It's also written in the book :-)

> > Also, syntax sugar by definition declares something that can be written as
> > a single line of code, which usually is done using more (not always).
> 
> The discussion has entered the phase of hair splitting. Good.

I don't know why we are adding an oil into the flames...

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 43+ messages in thread

end of thread, other threads:[~2022-02-14 14:00 UTC | newest]

Thread overview: 43+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-02-11  9:19 [PATCH v4 0/6] drm: Add driver for Solomon SSD130x OLED displays Javier Martinez Canillas
2022-02-11  9:19 ` [PATCH v4 1/6] drm/format-helper: Add drm_fb_xrgb8888_to_gray8_line() Javier Martinez Canillas
2022-02-11  9:29   ` Thomas Zimmermann
2022-02-11 10:28   ` Andy Shevchenko
2022-02-11 10:40     ` Javier Martinez Canillas
2022-02-11 11:12       ` Andy Shevchenko
2022-02-11 11:54         ` Thomas Zimmermann
2022-02-11 12:05           ` Jani Nikula
2022-02-11 12:11             ` Javier Martinez Canillas
2022-02-11 12:27             ` Geert Uytterhoeven
2022-02-11 15:41             ` Andy Shevchenko
2022-02-11 16:25               ` Jani Nikula
2022-02-11 17:27                 ` Andy Shevchenko
2022-02-14  9:17                   ` Pekka Paalanen
2022-02-14 10:26                     ` Andy Shevchenko
2022-02-14  9:03               ` Thomas Zimmermann
2022-02-14 10:38                 ` Andy Shevchenko
2022-02-14 10:52                   ` Simon Ser
2022-02-14 10:57                   ` Geert Uytterhoeven
2022-02-14 12:12                   ` Thomas Zimmermann
2022-02-14 12:47                     ` Ville Syrjälä
2022-02-14 12:54                       ` Thomas Zimmermann
2022-02-14 13:07                         ` Ville Syrjälä
2022-02-14 13:59                     ` Andy Shevchenko
2022-02-11  9:19 ` [PATCH v4 2/6] drm/format-helper: Add drm_fb_xrgb8888_to_mono_reversed() Javier Martinez Canillas
2022-02-11 11:10   ` Andy Shevchenko
2022-02-11 11:50     ` Javier Martinez Canillas
2022-02-11 15:55       ` Andy Shevchenko
2022-02-11 11:59     ` Thomas Zimmermann
2022-02-11 12:46   ` Thomas Zimmermann
2022-02-11  9:19 ` [PATCH v4 3/6] drm: Add driver for Solomon SSD130x OLED displays Javier Martinez Canillas
2022-02-11 11:33   ` Andy Shevchenko
2022-02-11 12:05     ` Javier Martinez Canillas
2022-02-11 12:23       ` Geert Uytterhoeven
2022-02-11 12:27         ` Javier Martinez Canillas
2022-02-11 15:49       ` Andy Shevchenko
2022-02-11 12:44   ` Thomas Zimmermann
2022-02-11  9:19 ` [PATCH v4 4/6] drm/solomon: Add SSD130x OLED displays I2C support Javier Martinez Canillas
2022-02-11 11:16   ` Andy Shevchenko
2022-02-11  9:21 ` [PATCH v4 5/6] MAINTAINERS: Add entry for Solomon SSD130x OLED displays DRM driver Javier Martinez Canillas
2022-02-11 11:34   ` Andy Shevchenko
2022-02-11  9:22 ` [PATCH v4 6/6] dt-bindings: display: ssd1307fb: Add myself as binding co-maintainer Javier Martinez Canillas
2022-02-11 11:35   ` Andy Shevchenko

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).