Thread (26 messages) 26 messages, 6 authors, 2016-02-25

Re: [PATCH v9 02/14] drm/mediatek: Add DRM Driver for Mediatek SoC MT8173.

From: Daniel Kurtz <hidden>
Date: 2016-02-02 17:09:15
Also in: dri-devel, linux-mediatek

Hi Philipp,

Some more potential bugs I discovered today while trying to configure
Mediatek DRM to use just the MIPI/DSI path (no HDMI).

On Tue, Jan 12, 2016 at 11:15 PM, Philipp Zabel [off-list ref]
wrote:
From: CK Hu <redacted>

This patch adds an initial DRM driver for the Mediatek MT8173 DISP
subsystem. It currently supports two fixed output streams from the
OVL0/OVL1 sources to the DSI0/DPI0 sinks, respectively.

Signed-off-by: CK Hu <redacted>
Signed-off-by: YT Shen <redacted>
Signed-off-by: Daniel Kurtz <redacted>
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
[snip]
+int mtk_drm_crtc_create(struct drm_device *drm_dev,
+                       const enum mtk_ddp_comp_id *path, unsigned int
path_len)
+{
+       struct mtk_drm_private *priv = drm_dev->dev_private;
+       struct device *dev = drm_dev->dev;
+       struct mtk_drm_crtc *mtk_crtc;
+       enum drm_plane_type type;
+       unsigned int zpos;
+       int pipe = priv->num_pipes;
+       int ret;
+       int i;
+
+       mtk_crtc = devm_kzalloc(dev, sizeof(*mtk_crtc), GFP_KERNEL);
+       if (!mtk_crtc)
+               return -ENOMEM;
+
+       mtk_crtc->config_regs = priv->config_regs;
+       mtk_crtc->ddp_comp_nr = path_len;
+       mtk_crtc->ddp_comp = devm_kmalloc_array(dev,
mtk_crtc->ddp_comp_nr,
+
sizeof(*mtk_crtc->ddp_comp),
+                                               GFP_KERNEL);
+
+       mtk_crtc->mutex = mtk_disp_mutex_get(priv->mutex_dev, pipe);
+       if (IS_ERR(mtk_crtc->mutex)) {
+               ret = PTR_ERR(mtk_crtc->mutex);
+               dev_err(dev, "Failed to get mutex: %d\n", ret);
+               return ret;
+       }
+
+       for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
+               enum mtk_ddp_comp_id comp_id = path[i];
+               struct mtk_ddp_comp *comp;
+
+               comp = priv->ddp_comp[comp_id];
+               if (!comp) {
+                       dev_err(dev, "Component %s not initialized\n",
+                               priv->comp_node[comp_id]->full_name);
If one of the components is disabled in .dtsi, then its
priv->comp_node[comp_id] will be NULL here, and trying to full_name will
OOPS.

+                       ret = -ENODEV;
+                       goto unprepare;
+               }
+
+               ret = clk_prepare(comp->clk);
+               if (ret) {
+                       dev_err(dev,
+                               "Failed to prepare clock for component
%s: %d\n",
+                               priv->comp_node[comp_id]->full_name, ret);
+                       goto unprepare;
+               }
+
+               mtk_crtc->ddp_comp[i] = comp;
+       }
+
+       for (zpos = 0; zpos < OVL_LAYER_NR; zpos++) {
+               type = (zpos == 0) ? DRM_PLANE_TYPE_PRIMARY :
+                               (zpos == 1) ? DRM_PLANE_TYPE_CURSOR :
+                                               DRM_PLANE_TYPE_OVERLAY;
+               ret = mtk_plane_init(drm_dev, &mtk_crtc->planes[zpos],
+                                    BIT(pipe), type, zpos);
+               if (ret)
+                       goto unprepare;
+       }
+
+       ret = mtk_drm_crtc_init(drm_dev, mtk_crtc,
&mtk_crtc->planes[0].base,
+                               &mtk_crtc->planes[1].base, pipe);
+       if (ret < 0)
+               goto unprepare;
+
+       priv->crtc[pipe] = &mtk_crtc->base;
+       priv->num_pipes++;
+
+       return 0;
+
+unprepare:
+       while (--i >= 0)
+               clk_unprepare(mtk_crtc->ddp_comp[i]->clk);
+
+       return ret;
+}
quoted hunk ↗ jump to hunk
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
quoted hunk ↗ jump to hunk
new file mode 100644
index 0000000..9db22b4
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
[snip]
+static struct drm_driver mtk_drm_driver = {
+       .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME |
+                          DRIVER_ATOMIC,
+       .unload = mtk_drm_unload,
+       .set_busid = drm_platform_set_busid,
I think using drm_platform_set_busid() as our .set_busid may cause an OOPs
if
userspace does DRM_IOCTL_SET_VERSION.

drm_setversion() will calls drm_set_busid(), which calls
dev->driver->set_busid()
drm_platform_set_busid() accesses dev->platformdev->id.

However, dev->platformdev is only set by:
  drm_platform_init()->drm_get_platform_dev()

And, since mtk_drm_bind() does the drm_dev_alloc() / drm_dev_register()
itself instead
of calling drm_get_platform_dev(), so dev->platformdev will still be NULL.

So, why don't we call drm_platform_init() instead and implement a .load
callback
to do mtk_drm_kms_init()?
+
+       .get_vblank_counter = drm_vblank_count,
+       .enable_vblank = mtk_drm_crtc_enable_vblank,
+       .disable_vblank = mtk_drm_crtc_disable_vblank,
+
+       .gem_free_object = mtk_drm_gem_free_object,
+       .gem_vm_ops = &mtk_drm_gem_vm_ops,
+       .dumb_create = mtk_drm_gem_dumb_create,
+       .dumb_map_offset = mtk_drm_gem_dumb_map_offset,
+       .dumb_destroy = drm_gem_dumb_destroy,
+
+       .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
+       .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
+       .gem_prime_export = drm_gem_prime_export,
+       .gem_prime_import = drm_gem_prime_import,
+       .gem_prime_get_sg_table = mtk_gem_prime_get_sg_table,
+       .gem_prime_mmap = mtk_drm_gem_mmap_buf,
+       .fops = &mtk_drm_fops,
+
+       .name = DRIVER_NAME,
+       .desc = DRIVER_DESC,
+       .date = DRIVER_DATE,
+       .major = DRIVER_MAJOR,
+       .minor = DRIVER_MINOR,
+};
+
+static int compare_of(struct device *dev, void *data)
+{
+       return dev->of_node == data;
+}
+
+static int mtk_drm_bind(struct device *dev)
+{
+       struct mtk_drm_private *private = dev_get_drvdata(dev);
+       struct drm_device *drm;
+       int ret;
+
+       drm = drm_dev_alloc(&mtk_drm_driver, dev);
+       if (!drm)
+               return -ENOMEM;
+
+       drm_dev_set_unique(drm, dev_name(dev));
+
+       ret = drm_dev_register(drm, 0);
+       if (ret < 0)
+               goto err_free;
+
+       drm->dev_private = private;
+       private->drm = drm;
+
+       ret = mtk_drm_kms_init(drm);
+       if (ret < 0)
+               goto err_unregister;
+
+       return 0;
+
+err_unregister:
+       drm_dev_unregister(drm);
+err_free:
+       drm_dev_unref(drm);
+       return ret;
+}
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help