lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <cfaab4fc-f646-e38e-be57-8a6142ca28ec@suse.de>
Date:   Fri, 11 Feb 2022 13:44:30 +0100
From:   Thomas Zimmermann <tzimmermann@...e.de>
To:     Javier Martinez Canillas <javierm@...hat.com>,
        linux-kernel@...r.kernel.org
Cc:     linux-pwm@...r.kernel.org, linux-fbdev@...r.kernel.org,
        David Airlie <airlied@...ux.ie>,
        Daniel Vetter <daniel.vetter@...ll.ch>,
        dri-devel@...ts.freedesktop.org,
        Noralf Trønnes <noralf@...nnes.org>,
        Geert Uytterhoeven <geert@...ux-m68k.org>,
        Maxime Ripard <maxime@...no.tech>,
        Uwe Kleine-König <u.kleine-koenig@...gutronix.de>,
        Thierry Reding <thierry.reding@...il.com>,
        Lee Jones <lee.jones@...aro.org>,
        Andy Shevchenko <andriy.shevchenko@...ux.intel.com>,
        Sam Ravnborg <sam@...nborg.org>
Subject: Re: [PATCH v4 3/6] drm: Add driver for Solomon SSD130x OLED displays

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@...hat.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@...hat.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

Download attachment "OpenPGP_signature" of type "application/pgp-signature" (841 bytes)

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ