From: Andrzej Hajda <a.hajda@samsung.com>
To: Thierry Reding <thierry.reding@gmail.com>
Cc: tomi.valkeinen@ti.com, Kyungmin Park <kyungmin.park@samsung.com>,
Thierry Reding <treding@nvidia.com>,
dri-devel@lists.freedesktop.org
Subject: Re: [RFC v2 PATCH] mipi-dsi-bus: add MIPI DSI bus support
Date: Mon, 25 Nov 2013 16:05:41 +0100 [thread overview]
Message-ID: <52936745.1070209@samsung.com> (raw)
In-Reply-To: <20131122174127.GA30591@ulmo.nvidia.com>
Hi Thierry,
Thanks for the review.
On 11/22/2013 06:41 PM, Thierry Reding wrote:
> On Mon, Nov 18, 2013 at 05:25:23PM +0100, Andrzej Hajda wrote:
>> MIPI DSI bus allows to model DSI hosts
>> and DSI devices using Linux bus.
> This looks somewhat terse. Any chance you could be more verbose about
> what exactly this does? You could mention for instance that it allows
> DSI devices to be instantiated from device tree and manually. That a
> Linux bus type is provided and device drivers can use that to bind to
> DSI devices.
OK.
>
>> Signed-off-by: Andrzej Hajda <a.hajda@samsung.com>
>> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
>> ---
>> Hi,
>>
>> This is my implementation of mipi dsi bus.
>> The first time it was posted as a part of CDF infrastructure [1],
>> but if it can be merged independently I will be glad.
>>
>> I have not addressed yet Bert's comments, but I think it should
>> be easy, once we have agreement how to implement it.
>>
>> There are also working drivers which uses this bus:
>> - Exynos DSI master,
>> - s6e8aa0 panel.
>> I will post them later.
>>
>> [1] http://www.mail-archive.com/dri-devel@lists.freedesktop.org/msg45252.html
>>
>> Changes:
>> v2:
>> - set_power callback removed (its role is passed to RUNTIME_PM),
>> - changed transfer ops parameters to struct,
>> - changed source location,
>> - minor fixes
>>
>> Regards
>> Andrzej
>>
>> ---
>> drivers/gpu/drm/Kconfig | 4 +
>> drivers/gpu/drm/Makefile | 2 +
>> drivers/gpu/drm/drm_mipi_dsi.c | 344 +++++++++++++++++++++++++++++++++++++++++
>> include/drm/drm_mipi_dsi.h | 154 ++++++++++++++++++
>> 4 files changed, 504 insertions(+)
>> create mode 100644 drivers/gpu/drm/drm_mipi_dsi.c
>> create mode 100644 include/drm/drm_mipi_dsi.h
> This seems to be missing a device tree binding document. That could
> probably be rather small since there's not a lot there right now. I
> volunteer to draft that document if you don't have the time to do
> that.
>
>> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
>> index f864275..58a603d 100644
>> --- a/drivers/gpu/drm/Kconfig
>> +++ b/drivers/gpu/drm/Kconfig
>> @@ -20,6 +20,10 @@ menuconfig DRM
>> details. You should also select and configure AGP
>> (/dev/agpgart) support if it is available for your platform.
>>
>> +config DRM_MIPI_DSI
>> + tristate
>> + default y
> Shouldn't this remain off by default? And only be selected by drivers
> that actually need it. I think that DSI host drivers could select this
> symbol and DSI peripheral drivers can depend on it. That way you'll
> automatically be able to only select peripheral drivers if there's at
> least one DSI host driver enabled.
Yes, of course. I just forgot to set it back properly after last tests.
>
>> diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c
> [...]
>> +/*
>> + * MIPI DSI Bus
>> + *
>> + * Copyright (C) 2012, Samsung Electronics, Co., Ltd.
> Perhaps this should now be "2012-2013"?
Yes, thanks.
>
>> + * Andrzej Hajda <a.hajda@samsung.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +
>> +#include <linux/device.h>
>> +#include <linux/export.h>
>> +#include <linux/kernel.h>
>> +#include <linux/list.h>
>> +#include <linux/of_device.h>
>> +#include <linux/module.h>
>> +#include <linux/mutex.h>
>> +#include <linux/slab.h>
>> +#include <linux/pm.h>
>> +#include <linux/pm_runtime.h>
> Can these please be ordered alphabetically?
OK
>
>> +/* -----------------------------------------------------------------------------
>> + * Bus operations
>> + */
> Nitpick: I'm not a huge fan of these separators. They have a tendency to
> get in the way when people add new functions and then all of a sudden
> they no longer fit into that category...
>
>> +int mipi_dsi_init(struct mipi_dsi_device *dev)
>> +{
> [...]
>> +}
>> +EXPORT_SYMBOL_GPL(mipi_dsi_init);
>> +
>> +int mipi_dsi_set_stream(struct mipi_dsi_device *dev, bool on)
>> +{
> [...]
>> +}
>> +EXPORT_SYMBOL_GPL(mipi_dsi_set_stream);
> These are missing documentation. It's not clear at all what they are
> supposed to do.
>
>> +int mipi_dsi_dcs_write(struct mipi_dsi_device *dev, int channel, const u8 *data,
> unsigned int for channel, please. And const void * for data so that the
> same type is used consistently.
>
>> +static struct device_attribute mipi_dsi_dev_attrs[] = {
> static const?
>
> I also believe these now need to be done using attribute groups. Look at
> commit d06262e58546 (driver-core: platform: convert bus code to use
> dev_groups) for an example of how to do that.
>> +static const struct dev_pm_ops mipi_dsi_dev_pm_ops = {
>> + .runtime_suspend = pm_generic_runtime_suspend,
>> + .runtime_resume = pm_generic_runtime_resume,
>> + .suspend = pm_generic_suspend,
>> + .resume = pm_generic_resume,
>> + .freeze = pm_generic_freeze,
>> + .thaw = pm_generic_thaw,
>> + .poweroff = pm_generic_poweroff,
>> + .restore = pm_generic_restore,
>> +};
>> +
>> +static struct bus_type mipi_dsi_bus_type = {
>> + .name = "mipi-dsi",
>> + .dev_attrs = mipi_dsi_dev_attrs,
>> + .match = mipi_dsi_match,
>> + .uevent = mipi_dsi_uevent,
>> + .pm = &mipi_dsi_dev_pm_ops,
>> +};
> Can we please stick to one style for these structures? I personally
> prefer the one you used for mipi_dsi_dev_pm_ops because the other one
> falls apart when you need to initialize a new field that exceeds the
> size of the indentation that you've chosen. It also wastes screen space
> and doesn't really make the code more readable in my opinion.
OK, for all above.
>
>> +void mipi_dsi_dev_release(struct device *_dev)
>> +{
>> + struct mipi_dsi_device *dev = to_mipi_dsi_device(_dev);
>> +
>> + kfree(dev);
>> +}
>> +
>> +static struct device_type mipi_dsi_dev_type = {
>> + .release = mipi_dsi_dev_release,
>> +};
> Also, is there any reason why you've switched to the mipi_dsi_dev prefix
> instead of mipi_dsi_device all of a sudden?
Ups, will be fixed.
>
>> +/**
>> + * mipi_dsi_device_register - register a DSI device
>> + * @dev: DSI device we're registering
>> + */
>> +int mipi_dsi_device_register(struct mipi_dsi_device *dev,
>> + struct mipi_dsi_bus *bus)
>> +{
>> + device_initialize(&dev->dev);
>> +
>> + dev->bus = bus;
>> + dev->dev.bus = &mipi_dsi_bus_type;
>> + dev->dev.parent = bus->dev;
>> + dev->dev.type = &mipi_dsi_dev_type;
>> +
>> + if (dev->id != -1)
> Does that case actually make sense in the context of DSI? There's a
> defined hierarchy in DSI, so shouldn't we construct the names in a more
> hierarchical way? I'm not sure if the ID is useful at all, perhaps it
> should really be the virtual channel?
>
> The patch that I proposed used the following to make up the device name:
>
> dev_set_name(&dsi->dev, "%s.%u", dev_name(host->dev), dsi->channel);
>
> That has the advantage of reflecting the bus topology.
>
> It seems like your code was copied mostly from platform_device, for
> which there's no well-defined topology and therefore having an ID makes
> sense to differentiate between multiple instances of the same device.
> But for DSI any host/bus can only have a single device with a given
> channel, so that makes for a pretty good for unique name.
Code was based on mipi_dbi_bus.c from CDF.
I am not sure about hardwiring devices to virtual channels.
There could be devices which uses more than one virtual channel,
in fact exynos-drm docs suggests that such hardware exists.
I can also imagine scenarios when dynamic virtual channel (re-)association
can be useful and DSI specs are not against it AFAIK.
Anyway the whole 'multiple devs on one DSI master' thing seems to me
quite unspecified.
>
>> +/**
>> + * mipi_dsi_device_unregister - unregister a DSI device
>> + * @dev: DSI device we're unregistering
>> + */
>> +void mipi_dsi_device_unregister(struct mipi_dsi_device *dev)
>> +{
>> + device_del(&dev->dev);
>> + put_device(&dev->dev);
> That's actually device_unregister().
>
>> +}
>> +EXPORT_SYMBOL_GPL(mipi_dsi_device_unregister);
> In general DRM doesn't use GPL-only symbols in order to make it easier
> to port the code to other operating systems.
>
>> +struct mipi_dsi_device *of_mipi_dsi_register_device(struct mipi_dsi_bus *bus,
>> + struct device_node *node)
>> +{
>> + struct mipi_dsi_device *d = NULL;
> Perhaps "dev" instead of "d", as the former is used everywhere else.
>
>> + int ret;
>> +
>> + d = kzalloc(sizeof(*d), GFP_KERNEL);
>> + if (!d)
>> + return ERR_PTR(-ENOMEM);
>> +
>> + ret = of_modalias_node(node, d->name, sizeof(d->name));
>> + if (ret) {
>> + dev_err(bus->dev, "modalias failure on %s\n", node->full_name);
>> + goto err_free;
>> + }
>> +
>> + d->dev.of_node = of_node_get(node);
>> + if (!d->dev.of_node)
>> + goto err_free;
>> +
>> + ret = mipi_dsi_device_register(d, bus);
>> +
>> + if (!ret)
>> + return d;
>> +
>> + of_node_put(node);
>> +err_free:
>> + kfree(d);
>> +
>> + return ERR_PTR(ret);
>> +}
> The cleanup looks somewhat weird here. I think the more canonical form
> would be:
>
> ret = mipi_dsi_device_register(dev, bus);
> if (ret)
> goto err_put;
>
> return dev;
>
> err_put:
> of_node_put(node);
> err_free:
> kfree(dev);
>
> return ERR_PTR(ret);
OK for all above
>
> Also I think we'll need to have a reg property and parse that to allow a
> device tree node to be matched to a virtual channel.
reg property means device is at fixed virtual channel.
DSI specs says nothing about it IMHO.
>> +static int __init mipi_dsi_bus_init(void)
>> +{
>> + return bus_register(&mipi_dsi_bus_type);
>> +}
>> +
>> +static void __exit mipi_dsi_bus_exit(void)
>> +{
>> + bus_unregister(&mipi_dsi_bus_type);
>> +}
>> +
>> +module_init(mipi_dsi_bus_init);
>> +module_exit(mipi_dsi_bus_exit)
> I don't think module_init() will work here. The reason is that the probe
> order for built-in drivers is determined primarily by link-order, so if
> any DSI device drivers end up linked in earlier than the DSI bus
> infrastructure, then the bus won't have been initialized yet when that
> driver is probed and registering a device or bus with it will fail.
>
>> +MODULE_LICENSE("GPL v2");
> I think this needs to be "GPL and additional rights" to be used within
> DRM.
>
>> diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h
> [...]
>> +#ifndef __DRM_MIPI_DSI_H__
>> +#define __DRM_MIPI_DSI_H__
>> +
>> +#include <linux/device.h>
>> +#include <video/videomode.h>
>> +
>> +struct mipi_dsi_bus;
>> +struct mipi_dsi_device;
>> +
>> +struct mipi_dsi_msg {
>> + u8 channel;
>> + u8 type;
>> +
>> + size_t tx_len;
>> + const void *tx_buf;
>> +
>> + size_t rx_len;
>> + void *rx_buf;
>> +};
>> +
>> +struct mipi_dsi_bus_ops {
>> + int (*init)(struct mipi_dsi_bus *bus, struct mipi_dsi_device *dev);
>> + int (*set_stream)(struct mipi_dsi_bus *bus, struct mipi_dsi_device *dev,
>> + bool on);
> Again, these should really be documented. I can somewhat guess what
> .init() is supposed to do. But I have no idea what .set_stream() is,
> though I think I've seen that in CDF patches. Perhaps that's a relic
> from when this was based on CDF?
OK, beside documenting I will add drivers for dsi and panel in the next
iteration
to show it in use.
>
>> + ssize_t (*transfer)(struct mipi_dsi_bus *bus,
>> + struct mipi_dsi_device *dev,
>> + struct mipi_dsi_msg *msg);
> Why do we need the dev parameter? There's already a channel field in the
> mipi_dsi_msg structure. Isn't that all that the transfer function needs
> to know about the device?
For simple HSI transfers, yes. In case transfer would depend on dev state
it would be useful, but I have no use case yet, so it could be removed.
>
>> +#define DSI_MODE_VIDEO (1 << 0)
>> +#define DSI_MODE_VIDEO_BURST (1 << 1)
>> +#define DSI_MODE_VIDEO_SYNC_PULSE (1 << 2)
>> +#define DSI_MODE_VIDEO_AUTO_VERT (1 << 3)
>> +#define DSI_MODE_VIDEO_HSE (1 << 4)
>> +#define DSI_MODE_VIDEO_HFP (1 << 5)
>> +#define DSI_MODE_VIDEO_HBP (1 << 6)
>> +#define DSI_MODE_VIDEO_HSA (1 << 7)
>> +#define DSI_MODE_VSYNC_FLUSH (1 << 8)
>> +#define DSI_MODE_EOT_PACKET (1 << 9)
> It should be documented how these are used.
OK
>
>> +enum mipi_dsi_pixel_format {
>> + DSI_FMT_RGB888,
>> + DSI_FMT_RGB666,
>> + DSI_FMT_RGB666_PACKED,
>> + DSI_FMT_RGB565,
>> +};
>> +
>> +struct mipi_dsi_interface_params {
>> + enum mipi_dsi_pixel_format format;
>> + unsigned long mode;
> I assume this is a bitmask of DSI_MODE_*. In that case perhaps "modes"
> would be a more accurate name?
Yes
>
>> + unsigned long hs_clk_freq;
>> + unsigned long esc_clk_freq;
> How are these interface parameters? The frequencies can certainly vary
> depending on the display mode, so why would a device specify that as a
> parameter?
>
>> + unsigned char data_lanes;
>> + unsigned char cmd_allow;
> What's cmd_allow?
For sure it requires documentation:)
In this particular case it is a number of lines where DSI-master allows
to send commands in video mode.
>
>> +};
> Any reason these parameters cannot be moved to the mipi_dsi_device
> structure?
I agree, it is again heritage of CDF.
>
>> +struct mipi_dsi_bus {
> I'd prefer this to be called mipi_dsi_host, because that's the name used
> everywhere in the specification.
>
>> + struct device *dev;
>> + const struct mipi_dsi_bus_ops *ops;
>> +};
>> +
>> +#define MIPI_DSI_MODULE_PREFIX "mipi-dsi:"
>> +#define MIPI_DSI_NAME_SIZE 32
> Do we really need this? Can't we allocate the name dynamically...
>
>> +struct mipi_dsi_device_id {
>> + char name[MIPI_DSI_NAME_SIZE];
> ... or use const char * here?
>
>> + __kernel_ulong_t driver_data /* Data private to the driver */
>> + __aligned(sizeof(__kernel_ulong_t));
> I don't think the explicit aligned attribute is necessary here.
>
>> +};
>> +
>> +struct mipi_dsi_device {
>> + char name[MIPI_DSI_NAME_SIZE];
>> + int id;
>> + struct device dev;
>> +
>> + const struct mipi_dsi_device_id *id_entry;
>> + struct mipi_dsi_bus *bus;
>> + struct videomode vm;
> Why is the videomode part of this structure? What if a device supports
> more than a single mode?
This is the current video mode. If we want to change mode,
we call:
ops->set_stream(false);
dev->vm =...new mode
ops->set_stream(true);
>
>> +int of_mipi_dsi_register_devices(struct mipi_dsi_bus *bus);
> Perhaps there ought to be a dummy implementation for this in case OF
> isn't selected?
>
> In fact, I think we should be hiding all those details from users. They
> shouldn't bother about manually registering with OF. Instead this should
> be mipi_dsi_register_bus/host()...
OK
>
>> +void mipi_dsi_unregister_devices(struct mipi_dsi_bus *bus);
> ... and this mipi_dsi_unregister_bus/host(). That way registration with
> OF (and instantiation of devices from DT) can be done automatically as
> needed.
>
>> +
>> +/* module_mipi_dsi_driver() - Helper macro for drivers that don't do
>> + * anything special in module init/exit. This eliminates a lot of
>> + * boilerplate. Each module may only use this macro once, and
>> + * calling it replaces module_init() and module_exit()
>> + */
> The correct style for block comments for kernel-doc is:
>
> /**
> * module_mipi_dsi_driver() - ...
> * ...
> */
>
>> +#define mipi_dsi_dcs_write_seq(dev, channel, seq...) \
>> +({\
>> + const u8 d[] = { seq };\
>> + BUILD_BUG_ON_MSG(ARRAY_SIZE(d) > 64, "DCS sequence too long for stack");\
>> + mipi_dsi_dcs_write(dev, channel, d, ARRAY_SIZE(d));\
>> +})
>> +
>> +#define mipi_dsi_dcs_write_static_seq(dev, channel, seq...) \
>> +({\
>> + static const u8 d[] = { seq };\
>> + mipi_dsi_dcs_write(dev, channel, d, ARRAY_SIZE(d));\
>> +})
> Can we drop these please? I'd rather have drivers construct buffers
> explicitly than use these.
I like those two. It removes lots of boiler-plate code. Please compare
implementations
of s6e8aa panel drivers without it [1] and with it [2], look for
calls to dsi_dcs_write.
[1] http://lists.freedesktop.org/archives/dri-devel/2013-January/034212.html
[2] https://linuxtv.org/patch/20215/
Andrzej
>
> Thierry
next prev parent reply other threads:[~2013-11-25 15:05 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-11-18 16:25 [RFC v2 PATCH] mipi-dsi-bus: add MIPI DSI bus support Andrzej Hajda
2013-11-22 17:41 ` Thierry Reding
2013-11-25 15:05 ` Andrzej Hajda [this message]
2013-11-27 10:54 ` Thierry Reding
2013-11-29 15:28 ` Andrzej Hajda
2013-12-02 10:22 ` Thierry Reding
2013-12-05 14:37 ` Tomi Valkeinen
2013-12-06 12:54 ` Thierry Reding
2013-12-09 11:34 ` Tomi Valkeinen
2013-12-09 13:10 ` Thierry Reding
2013-12-09 15:05 ` Tomi Valkeinen
2013-12-09 16:10 ` Thierry Reding
2013-12-10 9:19 ` Tomi Valkeinen
2013-12-12 12:19 ` Thierry Reding
2013-12-13 11:21 ` Tomi Valkeinen
2013-12-13 11:22 ` Andrzej Hajda
2013-12-13 11:29 ` Tomi Valkeinen
2013-12-13 12:06 ` Thierry Reding
2013-12-13 12:23 ` Tomi Valkeinen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=52936745.1070209@samsung.com \
--to=a.hajda@samsung.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=kyungmin.park@samsung.com \
--cc=thierry.reding@gmail.com \
--cc=tomi.valkeinen@ti.com \
--cc=treding@nvidia.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.