aboutsummaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/sun4i/sun4i_drv.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2017-09-28 05:45:27 +1000
committerDave Airlie <airlied@redhat.com>2017-09-28 05:46:15 +1000
commit29baa82aa55f40d67cfc8138c944fd8880c27e8e (patch)
tree19119a07d3ec8eb1407a68b48ec627239ee3e681 /drivers/gpu/drm/sun4i/sun4i_drv.c
parente19b205be43d11bff638cad4487008c48d21c103 (diff)
parentac6c35a4d8c77083525044a192cb1a8711381e94 (diff)
downloadlinux-29baa82aa55f40d67cfc8138c944fd8880c27e8e.tar.gz
Merge tag 'drm-misc-next-2017-09-20' of git://anongit.freedesktop.org/git/drm-misc into drm-next
UAPI Changes: Cross-subsystem Changes: Core Changes: - DP SDP defines (Ville) - polish for scdc helpers (Thierry Reding) - fix lifetimes for connector/plane state across crtc changes (Maarten Lankhorst). - sparse fixes (Ville+Thierry) - make legacy kms ioctls all interruptible (Maarten) - push edid override into the edid helpers (out of probe helpers) (Jani) - DP ESI defines for link status (DK) Driver Changes: - drm-panel is now in drm-misc! - minor panel-simple cleanups/refactoring by various folks - drm_bridge_add cleanup (Inki Dae) - constify a few i2c_device_id structs (Arvind Yadav) - More patches from Noralf's fb/gem helper cleanup - bridge/synopsis: reset fix (Philippe Cornu) - fix tracepoint include handling in drivers (Thierry) - rockchip: lvds support (Sandy Huang) - move sun4i into drm-misc fold (Maxime Ripard) - sun4i: refactor driver load + support TCON backend/layer muxing (Chen-Yu Tsai) - pl111: support more pl11x variants (Linus Walleij) - bridge/adv7511: robustify probing/edid handling (Lars-Petersen Clausen) New hw support: - S6E63J0X03 panel (Hoegeun Kwon) - OTM8009A panel (Philippe CORNU) - Seiko 43WVF1G panel (Marco Franchi) - tve200 driver (Linus Walleij) Plus assorted of tiny patches all over, including our first outreachy patches from applicants for the winter round! * tag 'drm-misc-next-2017-09-20' of git://anongit.freedesktop.org/git/drm-misc: (101 commits) drm: add backwards compatibility support for drm_kms_helper.edid_firmware drm: handle override and firmware EDID at drm_do_get_edid() level drm/dp: DPCD register defines for link status within ESI field drm/rockchip: Replace dev_* with DRM_DEV_* drm/tinydrm: Drop driver registered message drm/gem-fb-helper: Use debug message on gem lookup failure drm/imx: Use drm_gem_fb_create() and drm_gem_fb_prepare_fb() drm/bridge: adv7511: Constify HDMI CODEC platform data drm/bridge: adv7511: Enable connector polling when no interrupt is specified drm/bridge: adv7511: Remove private copy of the EDID drm/bridge: adv7511: Properly update EDID when no EDID was found drm/crtc: Convert setcrtc ioctl locking to interruptible. drm/atomic: Convert pageflip ioctl locking to interruptible. drm/legacy: Convert setplane ioctl locking to interruptible. drm/legacy: Convert cursor ioctl locking to interruptible. drm/atomic: Convert atomic ioctl locking to interruptible. drm/atomic: Prepare drm_modeset_lock infrastructure for interruptible waiting, v2. drm/tve200: Clean up panel bridging drm/doc: Update todo.rst drm/dp/mst: Sideband message transaction to power up/down nodes ...
Diffstat (limited to 'drivers/gpu/drm/sun4i/sun4i_drv.c')
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_drv.c91
1 files changed, 77 insertions, 14 deletions
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c
index ace59651892f..a2012638d5f7 100644
--- a/drivers/gpu/drm/sun4i/sun4i_drv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
@@ -106,11 +106,6 @@ static int sun4i_drv_bind(struct device *dev)
goto free_drm;
}
- /* drm_vblank_init calls kcalloc, which can fail */
- ret = drm_vblank_init(drm, 1);
- if (ret)
- goto free_mem_region;
-
drm_mode_config_init(drm);
ret = component_bind_all(drm->dev, drm);
@@ -119,6 +114,11 @@ static int sun4i_drv_bind(struct device *dev)
goto cleanup_mode_config;
}
+ /* drm_vblank_init calls kcalloc, which can fail */
+ ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
+ if (ret)
+ goto free_mem_region;
+
drm->irq_enabled = true;
/* Remove early framebuffers (ie. simplefb) */
@@ -200,11 +200,39 @@ static int compare_of(struct device *dev, void *data)
return dev->of_node == data;
}
+/*
+ * The encoder drivers use drm_of_find_possible_crtcs to get upstream
+ * crtcs from the device tree using of_graph. For the results to be
+ * correct, encoders must be probed/bound after _all_ crtcs have been
+ * created. The existing code uses a depth first recursive traversal
+ * of the of_graph, which means the encoders downstream of the TCON
+ * get add right after the first TCON. The second TCON or CRTC will
+ * never be properly associated with encoders connected to it.
+ *
+ * Also, in a dual display pipeline setup, both frontends can feed
+ * either backend, and both backends can feed either TCON, we want
+ * all components of the same type to be added before the next type
+ * in the pipeline. Fortunately, the pipelines are perfectly symmetric,
+ * i.e. components of the same type are at the same depth when counted
+ * from the frontend. The only exception is the third pipeline in
+ * the A80 SoC, which we do not support anyway.
+ *
+ * Hence we can use a breadth first search traversal order to add
+ * components. We do not need to check for duplicates. The component
+ * matching system handles this for us.
+ */
+struct endpoint_list {
+ struct device_node *node;
+ struct list_head list;
+};
+
static int sun4i_drv_add_endpoints(struct device *dev,
+ struct list_head *endpoints,
struct component_match **match,
struct device_node *node)
{
struct device_node *port, *ep, *remote;
+ struct endpoint_list *endpoint;
int count = 0;
/*
@@ -264,10 +292,15 @@ static int sun4i_drv_add_endpoints(struct device *dev,
}
}
- /* Walk down our tree */
- count += sun4i_drv_add_endpoints(dev, match, remote);
+ /* Add downstream nodes to the queue */
+ endpoint = kzalloc(sizeof(*endpoint), GFP_KERNEL);
+ if (!endpoint) {
+ of_node_put(remote);
+ return -ENOMEM;
+ }
- of_node_put(remote);
+ endpoint->node = remote;
+ list_add_tail(&endpoint->list, endpoints);
}
return count;
@@ -277,7 +310,9 @@ static int sun4i_drv_probe(struct platform_device *pdev)
{
struct component_match *match = NULL;
struct device_node *np = pdev->dev.of_node;
- int i, count = 0;
+ struct endpoint_list *endpoint, *endpoint_temp;
+ int i, ret, count = 0;
+ LIST_HEAD(endpoints);
for (i = 0;; i++) {
struct device_node *pipeline = of_parse_phandle(np,
@@ -286,12 +321,31 @@ static int sun4i_drv_probe(struct platform_device *pdev)
if (!pipeline)
break;
- count += sun4i_drv_add_endpoints(&pdev->dev, &match,
- pipeline);
- of_node_put(pipeline);
+ endpoint = kzalloc(sizeof(*endpoint), GFP_KERNEL);
+ if (!endpoint) {
+ ret = -ENOMEM;
+ goto err_free_endpoints;
+ }
- DRM_DEBUG_DRIVER("Queued %d outputs on pipeline %d\n",
- count, i);
+ endpoint->node = pipeline;
+ list_add_tail(&endpoint->list, &endpoints);
+ }
+
+ list_for_each_entry_safe(endpoint, endpoint_temp, &endpoints, list) {
+ /* process this endpoint */
+ ret = sun4i_drv_add_endpoints(&pdev->dev, &endpoints, &match,
+ endpoint->node);
+
+ /* sun4i_drv_add_endpoints can fail to allocate memory */
+ if (ret < 0)
+ goto err_free_endpoints;
+
+ count += ret;
+
+ /* delete and cleanup the current entry */
+ list_del(&endpoint->list);
+ of_node_put(endpoint->node);
+ kfree(endpoint);
}
if (count)
@@ -300,6 +354,15 @@ static int sun4i_drv_probe(struct platform_device *pdev)
match);
else
return 0;
+
+err_free_endpoints:
+ list_for_each_entry_safe(endpoint, endpoint_temp, &endpoints, list) {
+ list_del(&endpoint->list);
+ of_node_put(endpoint->node);
+ kfree(endpoint);
+ }
+
+ return ret;
}
static int sun4i_drv_remove(struct platform_device *pdev)