<HTML><BODY><p>Hello, Sam!<br>Thank you for the comments.<br><br>>> +#include <drm/drmP.h><br>> Please do not use drmP.h in new drivers. We are trying to get rid of it.<br>It can be replaced by these headers:<br><br>#include <drm/drm_connector.h><br>#include <drm/drm_modes.h><br>#include <uapi/linux/media-bus-format.h><br><br>> Use DRM_DEV_ERROR(...) to have consistent error message for the drm drivers.<br>> This is general for the whole file.<br>Good idea, I think. So, this header is needed:<br><br>#include <drm/drm_print.h><br><br>>> + /* Reset */<br> >> + msleep(20);<br> >> + gpiod_set_value(ctx->gpios.power, 1);<br> >> + msleep(20);<br> >> + gpiod_set_value(ctx->gpios.reset, 1);<br> >> + msleep(20);<br>>To verify the above pointer to a datasheet would be nice.<br>I looked the datasheet again, looks like the reset should be first. But I didn't find information about timings. It's needed to be checked on hardware. The power pin is named "STBYB" originally.<br><br>> height and width missing here. Seems better to add them here than hiding in code below.<br> > Is it on purpose that no flags are specified?<br>I sure, this algorithm was copied from the ilitek driver. The default_mode (drm_display_mode) variable and panel->connector->display_info (drm_display_info) variable has a different types, I'm not sure about this point. The bpc is not not applicable for the drm_display_mode.<br><br>>> + mode = drm_mode_duplicate(panel->drm, &default_mode);<br> >> + if (!mode) {<br> >> + dev_err(&ctx->dsi->dev, "failed to add mode %ux%ux@%u\n",<br> >> + default_mode.hdisplay, default_mode.vdisplay,<br> >> + default_mode.vrefresh);<br> > Use"<br>> DRM_DEV_ERROR(&ctx->dsi->dev,<br> > "failed to add mode" DRM_MODE_FMT,<br> > DRM_MODE_ARG(mode));<br>Not sure because the mode is NULL. May the default_mode be used for print?<br><br>>> + ctx->gpios.updn = devm_gpiod_get(&dsi->dev, "updn", GPIOD_OUT_LOW);<br> >> + if (IS_ERR(ctx->gpios.updn)) {<br> >> + dev_err(&dsi->dev, "Couldn't get our updn GPIO\n");<br> >> + return PTR_ERR(ctx->gpios.updn);<br> >> + }<br> > This gpio is never used, it is only read from DT<br>The gpio is initialized with low state. The state may be inverted by DT. The same for the "shlr".<br>It is a vertical / horizontal inversion.<br><br>> Use devm_of_find_backlight()<br>I agree with you.<br><br>The lastly, I think the rondo should be replaced by ronbo, because the company name is Ronbo Electronics Ltd.<br><a href="http://www.ronboe.com/about.html">http://www.ronboe.com/about.html</a> <br><br><br></p><blockquote style="border-left:1px solid #0857A6; margin:10px; padding:0 0 0 10px;">
Суббота, 26 января 2019, 22:39 +07:00 от Sam Ravnborg <sam@ravnborg.org>:<br>
<br>
<div id="">
<div class="js-helper js-readmsg-msg">
<style type="text/css"></style>
<div>
<base target="_self" href="https://e.mail.ru/">
<div id="style_15485171920000000748_BODY">Hi Maxime / Konstantin.<br>
<br>
Nice welstructured and small driver.<br>
Please see a few comments below<br>
<br>
Some of the comments in the following apply to a lot of<br>
the existing panel drivers as well.<br>
But lets see if we can get new drivers to be even better.<br>
<br>
Sam <br>
<br>
On Wed, Jan 23, 2019 at 04:54:24PM +0100, Maxime Ripard wrote:<br>
> From: Konstantin Sudakov <<a href="mailto:k.sudakov@integrasources.com">k.sudakov@integrasources.com</a>><br>
> <br>
> The Rondo RB070D30 panel is a MIPI-DSI panel based on a Fitipower EK79007<br>
> controller and a 1024x600 panel.<br>
> <br>
> Signed-off-by: Konstantin Sudakov <<a href="mailto:k.sudakov@integrasources.com">k.sudakov@integrasources.com</a>><br>
> Signed-off-by: Maxime Ripard <<a href="mailto:maxime.ripard@bootlin.com">maxime.ripard@bootlin.com</a>><br>
> ---<br>
> drivers/gpu/drm/panel/Kconfig | 9 +-<br>
> drivers/gpu/drm/panel/Makefile | 1 +-<br>
> drivers/gpu/drm/panel/panel-rondo-rb070d30.c | 258 ++++++++++++++++++++-<br>
> 3 files changed, 268 insertions(+)<br>
> create mode 100644 drivers/gpu/drm/panel/panel-rondo-rb070d30.c<br>
> <br>
> diff --git a/drivers/gpu/drm/panel/panel-rondo-rb070d30.c b/drivers/gpu/drm/panel/panel-rondo-rb070d30.c<br>
> new file mode 100644<br>
> index 000000000000..4f8e63f367b1<br>
> --- /dev/null<br>
> +++ b/drivers/gpu/drm/panel/panel-rondo-rb070d30.c<br>
> @@ -0,0 +1,258 @@<br>
> +// SPDX-License-Identifier: GPL-2.0+<br>
> +/*<br>
> + * Copyright (C) 2018, Bridge Systems BV<br>
> + * Copyright (C) 2018, Bootlin<br>
> + * Copyright (C) 2017, Free Electrons<br>
> + *<br>
> + * This file based on panel-ilitek-ili9881c.c<br>
> + */<br>
> +<br>
> +#include <linux/backlight.h><br>
> +#include <linux/delay.h><br>
> +#include <linux/device.h><br>
> +#include <linux/err.h><br>
> +#include <linux/errno.h><br>
> +#include <linux/fb.h><br>
> +#include <linux/kernel.h><br>
> +#include <linux/module.h><br>
> +<br>
> +#include <linux/gpio/consumer.h><br>
> +#include <linux/regulator/consumer.h><br>
> +<br>
> +#include <drm/drm_mipi_dsi.h><br>
> +#include <drm/drmP.h><br>
> +#include <drm/drm_panel.h><br>
Please do not use drmP.h in new drivers. We are trying to get rid of it.<br>
<br>
> +<br>
> +#include <video/mipi_display.h><br>
> +#include <video/of_display_timing.h><br>
> +#include <video/videomode.h><br>
> +<br>
> +struct rb070d30_panel {<br>
> + struct drm_panel panel;<br>
> + struct mipi_dsi_device *dsi;<br>
> + struct backlight_device *backlight;<br>
> + struct regulator *supply;<br>
> +<br>
> + struct {<br>
> + struct gpio_desc *power;<br>
> + struct gpio_desc *reset;<br>
> + struct gpio_desc *updn;<br>
> + struct gpio_desc *shlr;<br>
> + } gpios;<br>
> +};<br>
> +<br>
> +static inline struct rb070d30_panel *panel_to_rb070d30_panel(struct drm_panel *panel)<br>
> +{<br>
> + return container_of(panel, struct rb070d30_panel, panel);<br>
> +}<br>
> +<br>
> +static int rb070d30_panel_prepare(struct drm_panel *panel)<br>
> +{<br>
> + struct rb070d30_panel *ctx = panel_to_rb070d30_panel(panel);<br>
> + int ret;<br>
> +<br>
> + ret = regulator_enable(ctx->supply);<br>
> + if (ret < 0) {<br>
> + dev_err(&ctx->dsi->dev, "Failed to enable supply: %d\n", ret);<br>
Use DRM_DEV_ERROR(...) to have consistent error message for the drm drivers.<br>
This is general for the whole file.<br>
<br>
> + return ret;<br>
> + }<br>
> +<br>
> + /* Reset */<br>
> + msleep(20);<br>
> + gpiod_set_value(ctx->gpios.power, 1);<br>
> + msleep(20);<br>
> + gpiod_set_value(ctx->gpios.reset, 1);<br>
> + msleep(20);<br>
> + return 0;<br>
> +}<br>
To verify the above pointer to a datasheet would be nice.<br>
<br>
<br>
> +<br>
> +static int rb070d30_panel_unprepare(struct drm_panel *panel)<br>
> +{<br>
> + struct rb070d30_panel *ctx = panel_to_rb070d30_panel(panel);<br>
> +<br>
> + gpiod_set_value(ctx->gpios.power, 0);<br>
> + gpiod_set_value(ctx->gpios.reset, 0);<br>
> + regulator_disable(ctx->supply);<br>
> +<br>
> + return 0;<br>
> +}<br>
There is sometimes timing constrains after deassert reset..<br>
The order is not strictly reverse of prepare - is that on purpose?<br>
<br>
<br>
> +<br>
> +static int rb070d30_panel_enable(struct drm_panel *panel)<br>
> +{<br>
> + struct rb070d30_panel *ctx = panel_to_rb070d30_panel(panel);<br>
> + int ret;<br>
> +<br>
> + ret = mipi_dsi_dcs_exit_sleep_mode(ctx->dsi);<br>
> + if (ret)<br>
> + return ret;<br>
> +<br>
> + ret = backlight_enable(ctx->backlight);<br>
> + if (ret)<br>
> + goto out;<br>
> +<br>
> + return 0;<br>
> +<br>
> +out:<br>
> + mipi_dsi_dcs_enter_sleep_mode(ctx->dsi);<br>
> + return ret;<br>
> +}<br>
> +<br>
> +static int rb070d30_panel_disable(struct drm_panel *panel)<br>
> +{<br>
> + struct rb070d30_panel *ctx = panel_to_rb070d30_panel(panel);<br>
> +<br>
> + backlight_disable(ctx->backlight);<br>
> + return mipi_dsi_dcs_enter_sleep_mode(ctx->dsi);<br>
> +}<br>
> +<br>
> +/* Default timings */<br>
> +static const struct drm_display_mode default_mode = {<br>
> + .clock = 51206,<br>
> + .hdisplay = 1024,<br>
> + .hsync_start = 1024 + 160,<br>
> + .hsync_end = 1024 + 160 + 80,<br>
> + .htotal = 1024 + 160 + 80 + 80,<br>
> + .vdisplay = 600,<br>
> + .vsync_start = 600 + 12,<br>
> + .vsync_end = 600 + 12 + 10,<br>
> + .vtotal = 600 + 12 + 10 + 13,<br>
> + .vrefresh = 60,<br>
> +};<br>
height and width missing here. Seems better to add them here than hiding in code below.<br>
Is it on purpose that no flags are specified?<br>
<br>
> +<br>
> +static int rb070d30_panel_get_modes(struct drm_panel *panel)<br>
> +{<br>
> + struct drm_connector *connector = panel->connector;<br>
> + struct rb070d30_panel *ctx = panel_to_rb070d30_panel(panel);<br>
> + struct drm_display_mode *mode;<br>
> + static const u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;<br>
> +<br>
> + mode = drm_mode_duplicate(panel->drm, &default_mode);<br>
> + if (!mode) {<br>
> + dev_err(&ctx->dsi->dev, "failed to add mode %ux%ux@%u\n",<br>
> + default_mode.hdisplay, default_mode.vdisplay,<br>
> + default_mode.vrefresh);<br>
Use"<br>
DRM_DEV_ERROR(&ctx->dsi->dev,<br>
"failed to add mode" DRM_MODE_FMT,<br>
DRM_MODE_ARG(mode));<br>
> + return -EINVAL;<br>
> + }<br>
> +<br>
> + drm_mode_set_name(mode);<br>
> +<br>
> + mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;<br>
> + drm_mode_probed_add(connector, mode);<br>
> +<br>
> + panel->connector->display_info.bpc = 8;<br>
> + panel->connector->display_info.width_mm = 154;<br>
> + panel->connector->display_info.height_mm = 85;<br>
See comment on height above.<br>
Same goes for bpc<br>
<br>
> + drm_display_info_set_bus_formats(&connector->display_info,<br>
> + &bus_format, 1);<br>
> +<br>
> + return 1;<br>
> +}<br>
> +<br>
> +static const struct drm_panel_funcs rb070d30_panel_funcs = {<br>
> + .get_modes = rb070d30_panel_get_modes,<br>
> + .prepare = rb070d30_panel_prepare,<br>
> + .enable = rb070d30_panel_enable,<br>
> + .disable = rb070d30_panel_disable,<br>
> + .unprepare = rb070d30_panel_unprepare,<br>
> +};<br>
> +<br>
> +static int rb070d30_panel_dsi_probe(struct mipi_dsi_device *dsi)<br>
> +{<br>
> + struct device_node *np;<br>
> + struct rb070d30_panel *ctx;<br>
> + int ret;<br>
> +<br>
> + ctx = devm_kzalloc(&dsi->dev, sizeof(*ctx), GFP_KERNEL);<br>
> + if (!ctx)<br>
> + return -ENOMEM;<br>
> +<br>
> + ctx->supply = devm_regulator_get(&dsi->dev, "vcc-lcd");<br>
> + if (IS_ERR(ctx->supply))<br>
> + return PTR_ERR(ctx->supply);<br>
> +<br>
> + mipi_dsi_set_drvdata(dsi, ctx);<br>
> + ctx->dsi = dsi;<br>
> +<br>
> + drm_panel_init(&ctx->panel);<br>
> + ctx->panel.dev = &dsi->dev;<br>
> + ctx->panel.funcs = &rb070d30_panel_funcs;<br>
> +<br>
> + ctx->gpios.reset = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW);<br>
> + if (IS_ERR(ctx->gpios.reset)) {<br>
> + dev_err(&dsi->dev, "Couldn't get our reset GPIO\n");<br>
> + return PTR_ERR(ctx->gpios.reset);<br>
> + }<br>
> +<br>
> + ctx->gpios.power = devm_gpiod_get(&dsi->dev, "power", GPIOD_OUT_LOW);<br>
> + if (IS_ERR(ctx->gpios.power)) {<br>
> + dev_err(&dsi->dev, "Couldn't get our power GPIO\n");<br>
> + return PTR_ERR(ctx->gpios.power);<br>
> + }<br>
> +<br>
> + ctx->gpios.updn = devm_gpiod_get(&dsi->dev, "updn", GPIOD_OUT_LOW);<br>
> + if (IS_ERR(ctx->gpios.updn)) {<br>
> + dev_err(&dsi->dev, "Couldn't get our updn GPIO\n");<br>
> + return PTR_ERR(ctx->gpios.updn);<br>
> + }<br>
This gpio is never used, it is only read from DT<br>
<br>
<br>
> +<br>
> + ctx->gpios.shlr = devm_gpiod_get(&dsi->dev, "shlr", GPIOD_OUT_LOW);<br>
> + if (IS_ERR(ctx->gpios.shlr)) {<br>
> + dev_err(&dsi->dev, "Couldn't get our shlr GPIO\n");<br>
> + return PTR_ERR(ctx->gpios.shlr);<br>
> + }<br>
This gpio is never used, it is only read from DT<br>
<br>
> +<br>
> + np = of_parse_phandle(dsi->dev.of_node, "backlight", 0);<br>
> + if (np) {<br>
> + ctx->backlight = of_find_backlight_by_node(np);<br>
> + of_node_put(np);<br>
> +<br>
> + if (!ctx->backlight)<br>
> + return -EPROBE_DEFER;<br>
> + }<br>
Use devm_of_find_backlight()<br>
<br>
> +<br>
> + ret = drm_panel_add(&ctx->panel);<br>
> + if (ret < 0)<br>
> + goto free_backlight;<br>
> +<br>
> + dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_LPM;<br>
> + dsi->format = MIPI_DSI_FMT_RGB888;<br>
> + dsi->lanes = 4;<br>
> +<br>
> + return mipi_dsi_attach(dsi);<br>
> +<br>
> +free_backlight:<br>
> + backlight_put(ctx->backlight);<br>
If devm_of_find_backlight() is used this can go.<br>
<br>
> + return ret;<br>
> +}<br>
> +<br>
> +static int rb070d30_panel_dsi_remove(struct mipi_dsi_device *dsi)<br>
> +{<br>
> + struct rb070d30_panel *ctx = mipi_dsi_get_drvdata(dsi);<br>
> +<br>
> + mipi_dsi_detach(dsi);<br>
> + drm_panel_remove(&ctx->panel);<br>
> + backlight_put(ctx->backlight);<br>
If devm_of_find_backlight() is used this can go.<br>
<br>
> +<br>
> + return 0;<br>
> +}<br>
> +<br>
> +static const struct of_device_id rb070d30_panel_of_match[] = {<br>
> + { .compatible = "rondo,rb070d30" },<br>
> + { /* sentinel */ },<br>
> +};<br>
> +MODULE_DEVICE_TABLE(of, rb070d30_panel_of_match);<br>
> +<br>
> +static struct mipi_dsi_driver rb070d30_panel_driver = {<br>
> + .probe = rb070d30_panel_dsi_probe,<br>
> + .remove = rb070d30_panel_dsi_remove,<br>
> + .driver = {<br>
> + .name = "panel-rondo-rb070d30",<br>
> + .of_match_table = rb070d30_panel_of_match,<br>
> + },<br>
> +};<br>
> +module_mipi_dsi_driver(rb070d30_panel_driver);<br>
> +<br>
> +MODULE_AUTHOR("Boris Brezillon <<a href="mailto:boris.brezillon@bootlin.com">boris.brezillon@bootlin.com</a>>");<br>
> +MODULE_AUTHOR("Konstantin Sudakov <<a href="mailto:k.sudakov@integrasources.com">k.sudakov@integrasources.com</a>>");<br>
> +MODULE_DESCRIPTION("Rondo RB070D30 Panel Driver");<br>
> +MODULE_LICENSE("GPL");<br>
> -- <br>
> git-series 0.9.1<br>
> _______________________________________________<br>
> dri-devel mailing list<br>
> <a href="mailto:dri-devel@lists.freedesktop.org">dri-devel@lists.freedesktop.org</a><br>
> <a href="https://lists.freedesktop.org/mailman/listinfo/dri-devel" target="_blank">https://lists.freedesktop.org/mailman/listinfo/dri-devel</a><br>
</div>
<base target="_self" href="https://e.mail.ru/">
</div>
</div>
</div>
</blockquote>
<br>
<br>-- <br>Konstantin Sudakov<br></BODY></HTML>