diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/media/i2c/adv7343.c | 4 | ||||
-rw-r--r-- | drivers/media/i2c/mt9p031.c | 4 | ||||
-rw-r--r-- | drivers/media/i2c/s5k5baf.c | 3 | ||||
-rw-r--r-- | drivers/media/i2c/tvp514x.c | 3 | ||||
-rw-r--r-- | drivers/media/i2c/tvp7002.c | 3 | ||||
-rw-r--r-- | drivers/media/platform/exynos4-is/fimc-is.c | 6 | ||||
-rw-r--r-- | drivers/media/platform/exynos4-is/media-dev.c | 13 | ||||
-rw-r--r-- | drivers/media/platform/exynos4-is/mipi-csis.c | 5 | ||||
-rw-r--r-- | drivers/media/v4l2-core/v4l2-of.c | 133 | ||||
-rw-r--r-- | drivers/of/base.c | 151 | ||||
-rw-r--r-- | drivers/staging/imx-drm/TODO | 5 | ||||
-rw-r--r-- | drivers/staging/imx-drm/imx-drm-core.c | 217 | ||||
-rw-r--r-- | drivers/staging/imx-drm/imx-drm.h | 5 | ||||
-rw-r--r-- | drivers/staging/imx-drm/imx-hdmi.c | 4 | ||||
-rw-r--r-- | drivers/staging/imx-drm/imx-ldb.c | 4 | ||||
-rw-r--r-- | drivers/staging/imx-drm/imx-tve.c | 2 | ||||
-rw-r--r-- | drivers/staging/imx-drm/ipuv3-crtc.c | 47 |
17 files changed, 378 insertions, 231 deletions
diff --git a/drivers/media/i2c/adv7343.c b/drivers/media/i2c/adv7343.c index d4e15a617c3b..9d38f7b36cd1 100644 --- a/drivers/media/i2c/adv7343.c +++ b/drivers/media/i2c/adv7343.c @@ -26,12 +26,12 @@ #include <linux/videodev2.h> #include <linux/uaccess.h> #include <linux/of.h> +#include <linux/of_graph.h> #include <media/adv7343.h> #include <media/v4l2-async.h> #include <media/v4l2-device.h> #include <media/v4l2-ctrls.h> -#include <media/v4l2-of.h> #include "adv7343_regs.h" @@ -410,7 +410,7 @@ adv7343_get_pdata(struct i2c_client *client) if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node) return client->dev.platform_data; - np = v4l2_of_get_next_endpoint(client->dev.of_node, NULL); + np = of_graph_get_next_endpoint(client->dev.of_node, NULL); if (!np) return NULL; diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c index e5ddf47030fd..192c4aad05d6 100644 --- a/drivers/media/i2c/mt9p031.c +++ b/drivers/media/i2c/mt9p031.c @@ -21,6 +21,7 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/of_gpio.h> +#include <linux/of_graph.h> #include <linux/pm.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> @@ -29,7 +30,6 @@ #include <media/mt9p031.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> -#include <media/v4l2-of.h> #include <media/v4l2-subdev.h> #include "aptina-pll.h" @@ -943,7 +943,7 @@ mt9p031_get_pdata(struct i2c_client *client) if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node) return client->dev.platform_data; - np = v4l2_of_get_next_endpoint(client->dev.of_node, NULL); + np = of_graph_get_next_endpoint(client->dev.of_node, NULL); if (!np) return NULL; diff --git a/drivers/media/i2c/s5k5baf.c b/drivers/media/i2c/s5k5baf.c index 77e10e0fd8d6..2d768ef67cc5 100644 --- a/drivers/media/i2c/s5k5baf.c +++ b/drivers/media/i2c/s5k5baf.c @@ -21,6 +21,7 @@ #include <linux/media.h> #include <linux/module.h> #include <linux/of_gpio.h> +#include <linux/of_graph.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> @@ -1855,7 +1856,7 @@ static int s5k5baf_parse_device_node(struct s5k5baf *state, struct device *dev) if (ret < 0) return ret; - node_ep = v4l2_of_get_next_endpoint(node, NULL); + node_ep = of_graph_get_next_endpoint(node, NULL); if (!node_ep) { dev_err(dev, "no endpoint defined at node %s\n", node->full_name); diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c index 83d85df4853a..ca001178c5bf 100644 --- a/drivers/media/i2c/tvp514x.c +++ b/drivers/media/i2c/tvp514x.c @@ -36,6 +36,7 @@ #include <linux/module.h> #include <linux/v4l2-mediabus.h> #include <linux/of.h> +#include <linux/of_graph.h> #include <media/v4l2-async.h> #include <media/v4l2-device.h> @@ -1068,7 +1069,7 @@ tvp514x_get_pdata(struct i2c_client *client) if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node) return client->dev.platform_data; - endpoint = v4l2_of_get_next_endpoint(client->dev.of_node, NULL); + endpoint = of_graph_get_next_endpoint(client->dev.of_node, NULL); if (!endpoint) return NULL; diff --git a/drivers/media/i2c/tvp7002.c b/drivers/media/i2c/tvp7002.c index 912e1cccdd1c..c4e1e2cb3094 100644 --- a/drivers/media/i2c/tvp7002.c +++ b/drivers/media/i2c/tvp7002.c @@ -30,6 +30,7 @@ #include <linux/videodev2.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/of_graph.h> #include <linux/v4l2-dv-timings.h> #include <media/tvp7002.h> #include <media/v4l2-async.h> @@ -957,7 +958,7 @@ tvp7002_get_pdata(struct i2c_client *client) if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node) return client->dev.platform_data; - endpoint = v4l2_of_get_next_endpoint(client->dev.of_node, NULL); + endpoint = of_graph_get_next_endpoint(client->dev.of_node, NULL); if (!endpoint) return NULL; diff --git a/drivers/media/platform/exynos4-is/fimc-is.c b/drivers/media/platform/exynos4-is/fimc-is.c index 13a4228952e3..9bdfa4599bc3 100644 --- a/drivers/media/platform/exynos4-is/fimc-is.c +++ b/drivers/media/platform/exynos4-is/fimc-is.c @@ -24,13 +24,13 @@ #include <linux/i2c.h> #include <linux/of_irq.h> #include <linux/of_address.h> +#include <linux/of_graph.h> #include <linux/of_platform.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/slab.h> #include <linux/types.h> #include <linux/videodev2.h> -#include <media/v4l2-of.h> #include <media/videobuf2-dma-contig.h> #include "media-dev.h" @@ -167,10 +167,10 @@ static int fimc_is_parse_sensor_config(struct fimc_is_sensor *sensor, u32 tmp = 0; int ret; - np = v4l2_of_get_next_endpoint(np, NULL); + np = of_graph_get_next_endpoint(np, NULL); if (!np) return -ENXIO; - np = v4l2_of_get_remote_port(np); + np = of_graph_get_remote_port(np); if (!np) return -ENXIO; diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c index c1bce170df6f..04d6ecdd314c 100644 --- a/drivers/media/platform/exynos4-is/media-dev.c +++ b/drivers/media/platform/exynos4-is/media-dev.c @@ -20,6 +20,7 @@ #include <linux/of.h> #include <linux/of_platform.h> #include <linux/of_device.h> +#include <linux/of_graph.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/types.h> @@ -468,12 +469,12 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd, return 0; v4l2_of_parse_endpoint(ep, &endpoint); - if (WARN_ON(endpoint.port == 0) || index >= FIMC_MAX_SENSORS) + if (WARN_ON(endpoint.base.port == 0) || index >= FIMC_MAX_SENSORS) return -EINVAL; - pd->mux_id = (endpoint.port - 1) & 0x1; + pd->mux_id = (endpoint.base.port - 1) & 0x1; - rem = v4l2_of_get_remote_port_parent(ep); + rem = of_graph_get_remote_port_parent(ep); of_node_put(ep); if (rem == NULL) { v4l2_info(&fmd->v4l2_dev, "Remote device at %s not found\n", @@ -493,13 +494,13 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd, return -EINVAL; } - if (fimc_input_is_parallel(endpoint.port)) { + if (fimc_input_is_parallel(endpoint.base.port)) { if (endpoint.bus_type == V4L2_MBUS_PARALLEL) pd->sensor_bus_type = FIMC_BUS_TYPE_ITU_601; else pd->sensor_bus_type = FIMC_BUS_TYPE_ITU_656; pd->flags = endpoint.bus.parallel.flags; - } else if (fimc_input_is_mipi_csi(endpoint.port)) { + } else if (fimc_input_is_mipi_csi(endpoint.base.port)) { /* * MIPI CSI-2: only input mux selection and * the sensor's clock frequency is needed. @@ -507,7 +508,7 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd, pd->sensor_bus_type = FIMC_BUS_TYPE_MIPI_CSI2; } else { v4l2_err(&fmd->v4l2_dev, "Wrong port id (%u) at node %s\n", - endpoint.port, rem->full_name); + endpoint.base.port, rem->full_name); } /* * For FIMC-IS handled sensors, that are placed under i2c-isp device diff --git a/drivers/media/platform/exynos4-is/mipi-csis.c b/drivers/media/platform/exynos4-is/mipi-csis.c index f3c3591fdc5d..3678ba59725c 100644 --- a/drivers/media/platform/exynos4-is/mipi-csis.c +++ b/drivers/media/platform/exynos4-is/mipi-csis.c @@ -20,6 +20,7 @@ #include <linux/memory.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/of_graph.h> #include <linux/phy/phy.h> #include <linux/platform_data/mipi-csis.h> #include <linux/platform_device.h> @@ -762,7 +763,7 @@ static int s5pcsis_parse_dt(struct platform_device *pdev, &state->max_num_lanes)) return -EINVAL; - node = v4l2_of_get_next_endpoint(node, NULL); + node = of_graph_get_next_endpoint(node, NULL); if (!node) { dev_err(&pdev->dev, "No port node at %s\n", pdev->dev.of_node->full_name); @@ -771,7 +772,7 @@ static int s5pcsis_parse_dt(struct platform_device *pdev, /* Get port node and validate MIPI-CSI channel id. */ v4l2_of_parse_endpoint(node, &endpoint); - state->index = endpoint.port - FIMC_INPUT_MIPI_CSI2_0; + state->index = endpoint.base.port - FIMC_INPUT_MIPI_CSI2_0; if (state->index < 0 || state->index >= CSIS_MAX_ENTITIES) return -ENXIO; diff --git a/drivers/media/v4l2-core/v4l2-of.c b/drivers/media/v4l2-core/v4l2-of.c index 42e3e8a5e361..b4ed9a955fbe 100644 --- a/drivers/media/v4l2-core/v4l2-of.c +++ b/drivers/media/v4l2-core/v4l2-of.c @@ -127,17 +127,9 @@ static void v4l2_of_parse_parallel_bus(const struct device_node *node, int v4l2_of_parse_endpoint(const struct device_node *node, struct v4l2_of_endpoint *endpoint) { - struct device_node *port_node = of_get_parent(node); - - memset(endpoint, 0, offsetof(struct v4l2_of_endpoint, head)); - - endpoint->local_node = node; - /* - * It doesn't matter whether the two calls below succeed. - * If they don't then the default value 0 is used. - */ - of_property_read_u32(port_node, "reg", &endpoint->port); - of_property_read_u32(node, "reg", &endpoint->id); + of_graph_parse_endpoint(node, &endpoint->base); + endpoint->bus_type = 0; + memset(&endpoint->bus, 0, sizeof(endpoint->bus)); v4l2_of_parse_csi_bus(node, endpoint); /* @@ -147,125 +139,6 @@ int v4l2_of_parse_endpoint(const struct device_node *node, if (endpoint->bus.mipi_csi2.flags == 0) v4l2_of_parse_parallel_bus(node, endpoint); - of_node_put(port_node); - return 0; } EXPORT_SYMBOL(v4l2_of_parse_endpoint); - -/** - * v4l2_of_get_next_endpoint() - get next endpoint node - * @parent: pointer to the parent device node - * @prev: previous endpoint node, or NULL to get first - * - * Return: An 'endpoint' node pointer with refcount incremented. Refcount - * of the passed @prev node is not decremented, the caller have to use - * of_node_put() on it when done. - */ -struct device_node *v4l2_of_get_next_endpoint(const struct device_node *parent, - struct device_node *prev) -{ - struct device_node *endpoint; - struct device_node *port = NULL; - - if (!parent) - return NULL; - - if (!prev) { - struct device_node *node; - /* - * It's the first call, we have to find a port subnode - * within this node or within an optional 'ports' node. - */ - node = of_get_child_by_name(parent, "ports"); - if (node) - parent = node; - - port = of_get_child_by_name(parent, "port"); - - if (port) { - /* Found a port, get an endpoint. */ - endpoint = of_get_next_child(port, NULL); - of_node_put(port); - } else { - endpoint = NULL; - } - - if (!endpoint) - pr_err("%s(): no endpoint nodes specified for %s\n", - __func__, parent->full_name); - of_node_put(node); - } else { - port = of_get_parent(prev); - if (!port) - /* Hm, has someone given us the root node ?... */ - return NULL; - - /* Avoid dropping prev node refcount to 0. */ - of_node_get(prev); - endpoint = of_get_next_child(port, prev); - if (endpoint) { - of_node_put(port); - return endpoint; - } - - /* No more endpoints under this port, try the next one. */ - do { - port = of_get_next_child(parent, port); - if (!port) - return NULL; - } while (of_node_cmp(port->name, "port")); - - /* Pick up the first endpoint in this port. */ - endpoint = of_get_next_child(port, NULL); - of_node_put(port); - } - - return endpoint; -} -EXPORT_SYMBOL(v4l2_of_get_next_endpoint); - -/** - * v4l2_of_get_remote_port_parent() - get remote port's parent node - * @node: pointer to a local endpoint device_node - * - * Return: Remote device node associated with remote endpoint node linked - * to @node. Use of_node_put() on it when done. - */ -struct device_node *v4l2_of_get_remote_port_parent( - const struct device_node *node) -{ - struct device_node *np; - unsigned int depth; - - /* Get remote endpoint node. */ - np = of_parse_phandle(node, "remote-endpoint", 0); - - /* Walk 3 levels up only if there is 'ports' node. */ - for (depth = 3; depth && np; depth--) { - np = of_get_next_parent(np); - if (depth == 2 && of_node_cmp(np->name, "ports")) - break; - } - return np; -} -EXPORT_SYMBOL(v4l2_of_get_remote_port_parent); - -/** - * v4l2_of_get_remote_port() - get remote port node - * @node: pointer to a local endpoint device_node - * - * Return: Remote port node associated with remote endpoint node linked - * to @node. Use of_node_put() on it when done. - */ -struct device_node *v4l2_of_get_remote_port(const struct device_node *node) -{ - struct device_node *np; - - /* Get remote endpoint node. */ - np = of_parse_phandle(node, "remote-endpoint", 0); - if (!np) - return NULL; - return of_get_next_parent(np); -} -EXPORT_SYMBOL(v4l2_of_get_remote_port); diff --git a/drivers/of/base.c b/drivers/of/base.c index 89e888a78899..fd4b9c2eaa15 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -21,6 +21,7 @@ #include <linux/cpu.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/of_graph.h> #include <linux/spinlock.h> #include <linux/slab.h> #include <linux/proc_fs.h> @@ -1982,3 +1983,153 @@ struct device_node *of_find_next_cache_node(const struct device_node *np) return NULL; } + +/** + * of_graph_parse_endpoint() - parse common endpoint node properties + * @node: pointer to endpoint device_node + * @endpoint: pointer to the OF endpoint data structure + * + * The caller should hold a reference to @node. + */ +int of_graph_parse_endpoint(const struct device_node *node, + struct of_endpoint *endpoint) +{ + struct device_node *port_node = of_get_parent(node); + + WARN_ONCE(!port_node, "%s(): endpoint %s has no parent node\n", + __func__, node->full_name); + + memset(endpoint, 0, sizeof(*endpoint)); + + endpoint->local_node = node; + /* + * It doesn't matter whether the two calls below succeed. + * If they don't then the default value 0 is used. + */ + of_property_read_u32(port_node, "reg", &endpoint->port); + of_property_read_u32(node, "reg", &endpoint->id); + + of_node_put(port_node); + + return 0; +} +EXPORT_SYMBOL(of_graph_parse_endpoint); + +/** + * of_graph_get_next_endpoint() - get next endpoint node + * @parent: pointer to the parent device node + * @prev: previous endpoint node, or NULL to get first + * + * Return: An 'endpoint' node pointer with refcount incremented. Refcount + * of the passed @prev node is not decremented, the caller have to use + * of_node_put() on it when done. + */ +struct device_node *of_graph_get_next_endpoint(const struct device_node *parent, + struct device_node *prev) +{ + struct device_node *endpoint; + struct device_node *port = NULL; + + if (!parent) + return NULL; + + if (!prev) { + struct device_node *node; + /* + * It's the first call, we have to find a port subnode + * within this node or within an optional 'ports' node. + */ + node = of_get_child_by_name(parent, "ports"); + if (node) + parent = node; + + port = of_get_child_by_name(parent, "port"); + + if (port) { + /* Found a port, get an endpoint. */ + endpoint = of_get_next_child(port, NULL); + of_node_put(port); + } else { + endpoint = NULL; + } + + if (!endpoint) + pr_err("%s(): no endpoint nodes specified for %s\n", + __func__, parent->full_name); + of_node_put(node); + + return endpoint; + } + + port = of_get_parent(prev); + if (WARN_ONCE(!port, "%s(): endpoint %s has no parent node\n", + __func__, prev->full_name)) + return NULL; + + /* Avoid dropping prev node refcount to 0. */ + of_node_get(prev); + endpoint = of_get_next_child(port, prev); + if (endpoint) { + of_node_put(port); + return endpoint; + } + + /* No more endpoints under this port, try the next one. */ + do { + port = of_get_next_child(parent, port); + if (!port) + return NULL; + } while (of_node_cmp(port->name, "port")); + + /* Pick up the first endpoint in this port. */ + endpoint = of_get_next_child(port, NULL); + of_node_put(port); + + return endpoint; +} +EXPORT_SYMBOL(of_graph_get_next_endpoint); + +/** + * of_graph_get_remote_port_parent() - get remote port's parent node + * @node: pointer to a local endpoint device_node + * + * Return: Remote device node associated with remote endpoint node linked + * to @node. Use of_node_put() on it when done. + */ +struct device_node *of_graph_get_remote_port_parent( + const struct device_node *node) +{ + struct device_node *np; + unsigned int depth; + + /* Get remote endpoint node. */ + np = of_parse_phandle(node, "remote-endpoint", 0); + + /* Walk 3 levels up only if there is 'ports' node. */ + for (depth = 3; depth && np; depth--) { + np = of_get_next_parent(np); + if (depth == 2 && of_node_cmp(np->name, "ports")) + break; + } + return np; +} +EXPORT_SYMBOL(of_graph_get_remote_port_parent); + +/** + * of_graph_get_remote_port() - get remote port node + * @node: pointer to a local endpoint device_node + * + * Return: Remote port node associated with remote endpoint node linked + * to @node. Use of_node_put() on it when done. + */ +struct device_node *of_graph_get_remote_port(const struct device_node *node) +{ + struct device_node *np; + + /* Get remote endpoint node. */ + np = of_parse_phandle(node, "remote-endpoint", 0); + if (!np) + return NULL; + return of_get_next_parent(np); +} +EXPORT_SYMBOL(of_graph_get_remote_port); diff --git a/drivers/staging/imx-drm/TODO b/drivers/staging/imx-drm/TODO index 6a9da94c9573..29636fb13959 100644 --- a/drivers/staging/imx-drm/TODO +++ b/drivers/staging/imx-drm/TODO @@ -1,15 +1,10 @@ TODO: - get DRM Maintainer review for this code -- Wait for common display framework to hit mainline and update the IPU - driver to use it. This will most probably make changes to the devicetree - bindings necessary. -- Factor out more code to common helper functions - decide where to put the base driver. It is not specific to a subsystem and would be used by DRM/KMS and media/V4L2 Missing features (not necessarily for moving out of staging): -- Add i.MX6 HDMI support - Add support for IC (Image converter) - Add support for CSI (CMOS Sensor interface) - Add support for VDIC (Video Deinterlacer) diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c index 6b91c8e67174..4144a75e5f71 100644 --- a/drivers/staging/imx-drm/imx-drm-core.c +++ b/drivers/staging/imx-drm/imx-drm-core.c @@ -17,6 +17,7 @@ #include <linux/device.h> #include <linux/fb.h> #include <linux/module.h> +#include <linux/of_graph.h> #include <linux/platform_device.h> #include <drm/drmP.h> #include <drm/drm_fb_helper.h> @@ -30,6 +31,11 @@ struct imx_drm_crtc; +struct imx_drm_component { + struct device_node *of_node; + struct list_head list; +}; + struct imx_drm_device { struct drm_device *drm; struct imx_drm_crtc *crtc[MAX_CRTC]; @@ -41,9 +47,7 @@ struct imx_drm_crtc { struct drm_crtc *crtc; int pipe; struct imx_drm_crtc_helper_funcs imx_drm_helper_funcs; - void *cookie; - int id; - int mux_id; + struct device_node *port; }; static int legacyfb_depth = 16; @@ -341,14 +345,11 @@ err_kms: /* * imx_drm_add_crtc - add a new crtc - * - * The return value if !NULL is a cookie for the caller to pass to - * imx_drm_remove_crtc later. */ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc, struct imx_drm_crtc **new_crtc, const struct imx_drm_crtc_helper_funcs *imx_drm_helper_funcs, - void *cookie, int id) + struct device_node *port) { struct imx_drm_device *imxdrm = drm->dev_private; struct imx_drm_crtc *imx_drm_crtc; @@ -370,9 +371,7 @@ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc, imx_drm_crtc->imx_drm_helper_funcs = *imx_drm_helper_funcs; imx_drm_crtc->pipe = imxdrm->pipes++; - imx_drm_crtc->cookie = cookie; - imx_drm_crtc->id = id; - imx_drm_crtc->mux_id = imx_drm_crtc->pipe; + imx_drm_crtc->port = port; imx_drm_crtc->crtc = crtc; imxdrm->crtc[imx_drm_crtc->pipe] = imx_drm_crtc; @@ -416,49 +415,56 @@ int imx_drm_remove_crtc(struct imx_drm_crtc *imx_drm_crtc) EXPORT_SYMBOL_GPL(imx_drm_remove_crtc); /* - * Find the DRM CRTC possible mask for the device node cookie/id. + * Find the DRM CRTC possible mask for the connected endpoint. * * The encoder possible masks are defined by their position in the * mode_config crtc_list. This means that CRTCs must not be added * or removed once the DRM device has been fully initialised. */ static uint32_t imx_drm_find_crtc_mask(struct imx_drm_device *imxdrm, - void *cookie, int id) + struct device_node *endpoint) { + struct device_node *port; unsigned i; + port = of_graph_get_remote_port(endpoint); + if (!port) + return 0; + of_node_put(port); + for (i = 0; i < MAX_CRTC; i++) { struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[i]; - if (imx_drm_crtc && imx_drm_crtc->id == id && - imx_drm_crtc->cookie == cookie) + if (imx_drm_crtc && imx_drm_crtc->port == port) return drm_crtc_mask(imx_drm_crtc->crtc); } return 0; } +static struct device_node *imx_drm_of_get_next_endpoint( + const struct device_node *parent, struct device_node *prev) +{ + struct device_node *node = of_graph_get_next_endpoint(parent, prev); + of_node_put(prev); + return node; +} + int imx_drm_encoder_parse_of(struct drm_device *drm, struct drm_encoder *encoder, struct device_node *np) { struct imx_drm_device *imxdrm = drm->dev_private; + struct device_node *ep = NULL; uint32_t crtc_mask = 0; - int i, ret = 0; + int i; - for (i = 0; !ret; i++) { - struct of_phandle_args args; - uint32_t mask; - int id; + for (i = 0; ; i++) { + u32 mask; - ret = of_parse_phandle_with_args(np, "crtcs", "#crtc-cells", i, - &args); - if (ret == -ENOENT) + ep = imx_drm_of_get_next_endpoint(np, ep); + if (!ep) break; - if (ret < 0) - return ret; - id = args.args_count > 0 ? args.args[0] : 0; - mask = imx_drm_find_crtc_mask(imxdrm, args.np, id); - of_node_put(args.np); + mask = imx_drm_find_crtc_mask(imxdrm, ep); /* * If we failed to find the CRTC(s) which this encoder is @@ -472,6 +478,11 @@ int imx_drm_encoder_parse_of(struct drm_device *drm, crtc_mask |= mask; } + if (ep) + of_node_put(ep); + if (i == 0) + return -ENOENT; + encoder->possible_crtcs = crtc_mask; /* FIXME: this is the mask of outputs which can clone this output. */ @@ -481,11 +492,36 @@ int imx_drm_encoder_parse_of(struct drm_device *drm, } EXPORT_SYMBOL_GPL(imx_drm_encoder_parse_of); -int imx_drm_encoder_get_mux_id(struct drm_encoder *encoder) +/* + * @node: device tree node containing encoder input ports + * @encoder: drm_encoder + */ +int imx_drm_encoder_get_mux_id(struct device_node *node, + struct drm_encoder *encoder) { struct imx_drm_crtc *imx_crtc = imx_drm_find_crtc(encoder->crtc); + struct device_node *ep = NULL; + struct of_endpoint endpoint; + struct device_node *port; + int ret; - return imx_crtc ? imx_crtc->mux_id : -EINVAL; + if (!node || !imx_crtc) + return -EINVAL; + + do { + ep = imx_drm_of_get_next_endpoint(node, ep); + if (!ep) + break; + + port = of_graph_get_remote_port(ep); + of_node_put(port); + if (port == imx_crtc->port) { + ret = of_graph_parse_endpoint(ep, &endpoint); + return ret ? ret : endpoint.id; + } + } while (ep); + + return -EINVAL; } EXPORT_SYMBOL_GPL(imx_drm_encoder_get_mux_id); @@ -528,48 +564,29 @@ static struct drm_driver imx_drm_driver = { .patchlevel = 0, }; -static int compare_parent_of(struct device *dev, void *data) -{ - struct of_phandle_args *args = data; - return dev->parent && dev->parent->of_node == args->np; -} - static int compare_of(struct device *dev, void *data) { - return dev->of_node == data; -} - -static int imx_drm_add_components(struct device *master, struct master *m) -{ - struct device_node *np = master->of_node; - unsigned i; - int ret; + struct device_node *np = data; - for (i = 0; ; i++) { - struct of_phandle_args args; - - ret = of_parse_phandle_with_fixed_args(np, "crtcs", 1, - i, &args); - if (ret) - break; - - ret = component_master_add_child(m, compare_parent_of, &args); - of_node_put(args.np); - - if (ret) - return ret; + /* Special case for LDB, one device for two channels */ + if (of_node_cmp(np->name, "lvds-channel") == 0) { + np = of_get_parent(np); + of_node_put(np); } - for (i = 0; ; i++) { - struct device_node *node; + return dev->of_node == np; +} - node = of_parse_phandle(np, "connectors", i); - if (!node) - break; +static LIST_HEAD(imx_drm_components); - ret = component_master_add_child(m, compare_of, node); - of_node_put(node); +static int imx_drm_add_components(struct device *master, struct master *m) +{ + struct imx_drm_component *component; + int ret; + list_for_each_entry(component, &imx_drm_components, list) { + ret = component_master_add_child(m, compare_of, + component->of_node); if (ret) return ret; } @@ -592,9 +609,81 @@ static const struct component_master_ops imx_drm_ops = { .unbind = imx_drm_unbind, }; +static struct imx_drm_component *imx_drm_find_component(struct device *dev, + struct device_node *node) +{ + struct imx_drm_component *component; + + list_for_each_entry(component, &imx_drm_components, list) + if (component->of_node == node) + return component; + + return NULL; +} + +static int imx_drm_add_component(struct device *dev, struct device_node *node) +{ + struct imx_drm_component *component; + + if (imx_drm_find_component(dev, node)) + return 0; + + component = devm_kzalloc(dev, sizeof(*component), GFP_KERNEL); + if (!component) + return -ENOMEM; + + component->of_node = node; + list_add_tail(&component->list, &imx_drm_components); + + return 0; +} + static int imx_drm_platform_probe(struct platform_device *pdev) { + struct device_node *ep, *port, *remote; int ret; + int i; + + /* + * Bind the IPU display interface ports first, so that + * imx_drm_encoder_parse_of called from encoder .bind callbacks + * works as expected. + */ + for (i = 0; ; i++) { + port = of_parse_phandle(pdev->dev.of_node, "ports", i); + if (!port) + break; + + ret = imx_drm_add_component(&pdev->dev, port); + if (ret < 0) + return ret; + } + + if (i == 0) { + dev_err(&pdev->dev, "missing 'ports' property\n"); + return -ENODEV; + } + + /* Then bind all encoders */ + for (i = 0; ; i++) { + port = of_parse_phandle(pdev->dev.of_node, "ports", i); + if (!port) + break; + + for_each_child_of_node(port, ep) { + remote = of_graph_get_remote_port_parent(ep); + if (!remote || !of_device_is_available(remote)) { + of_node_put(remote); + continue; + } + + ret = imx_drm_add_component(&pdev->dev, remote); + of_node_put(remote); + if (ret < 0) + return ret; + } + of_node_put(port); + } ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); if (ret) @@ -610,7 +699,7 @@ static int imx_drm_platform_remove(struct platform_device *pdev) } static const struct of_device_id imx_drm_dt_ids[] = { - { .compatible = "fsl,imx-drm", }, + { .compatible = "fsl,imx-display-subsystem", }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, imx_drm_dt_ids); diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h index 035ab6258ad0..a322bac55414 100644 --- a/drivers/staging/imx-drm/imx-drm.h +++ b/drivers/staging/imx-drm/imx-drm.h @@ -26,7 +26,7 @@ struct imx_drm_crtc_helper_funcs { int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc, struct imx_drm_crtc **new_crtc, const struct imx_drm_crtc_helper_funcs *imx_helper_funcs, - void *cookie, int id); + struct device_node *port); int imx_drm_remove_crtc(struct imx_drm_crtc *); int imx_drm_init_drm(struct platform_device *pdev, int preferred_bpp); @@ -45,7 +45,8 @@ int imx_drm_panel_format_pins(struct drm_encoder *encoder, int imx_drm_panel_format(struct drm_encoder *encoder, u32 interface_pix_fmt); -int imx_drm_encoder_get_mux_id(struct drm_encoder *encoder); +int imx_drm_encoder_get_mux_id(struct device_node *node, + struct drm_encoder *encoder); int imx_drm_encoder_parse_of(struct drm_device *drm, struct drm_encoder *encoder, struct device_node *np); diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c index 8384ceab932a..4540a9aa11d8 100644 --- a/drivers/staging/imx-drm/imx-hdmi.c +++ b/drivers/staging/imx-drm/imx-hdmi.c @@ -1459,7 +1459,7 @@ static void imx_hdmi_encoder_prepare(struct drm_encoder *encoder) static void imx_hdmi_encoder_commit(struct drm_encoder *encoder) { struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder); - int mux = imx_drm_encoder_get_mux_id(encoder); + int mux = imx_drm_encoder_get_mux_id(hdmi->dev->of_node, encoder); imx_hdmi_set_ipu_di_mux(hdmi, mux); @@ -1610,7 +1610,7 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data) hdmi->dev_type = device_id->driver_data; } - ddc_node = of_parse_phandle(np, "ddc", 0); + ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0); if (ddc_node) { hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node); if (!hdmi->ddc) diff --git a/drivers/staging/imx-drm/imx-ldb.c b/drivers/staging/imx-drm/imx-ldb.c index daa54df4527f..33d2b8832540 100644 --- a/drivers/staging/imx-drm/imx-ldb.c +++ b/drivers/staging/imx-drm/imx-ldb.c @@ -170,7 +170,7 @@ static void imx_ldb_encoder_prepare(struct drm_encoder *encoder) u32 pixel_fmt; unsigned long serial_clk; unsigned long di_clk = mode->clock * 1000; - int mux = imx_drm_encoder_get_mux_id(encoder); + int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->child, encoder); if (ldb->ldb_ctrl & LDB_SPLIT_MODE_EN) { /* dual channel LVDS mode */ @@ -205,7 +205,7 @@ static void imx_ldb_encoder_commit(struct drm_encoder *encoder) struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder); struct imx_ldb *ldb = imx_ldb_ch->ldb; int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN; - int mux = imx_drm_encoder_get_mux_id(encoder); + int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->child, encoder); if (dual) { clk_prepare_enable(ldb->clk[0]); diff --git a/drivers/staging/imx-drm/imx-tve.c b/drivers/staging/imx-drm/imx-tve.c index 50b25f1a85d5..575533f4fd64 100644 --- a/drivers/staging/imx-drm/imx-tve.c +++ b/drivers/staging/imx-drm/imx-tve.c @@ -582,7 +582,7 @@ static int imx_tve_bind(struct device *dev, struct device *master, void *data) tve->dev = dev; spin_lock_init(&tve->lock); - ddc_node = of_parse_phandle(np, "ddc", 0); + ddc_node = of_parse_phandle(np, "i2c-ddc-bus", 0); if (ddc_node) { tve->ddc = of_find_i2c_adapter_by_node(ddc_node); of_node_put(ddc_node); diff --git a/drivers/staging/imx-drm/ipuv3-crtc.c b/drivers/staging/imx-drm/ipuv3-crtc.c index e646017c32ac..a8d017854615 100644 --- a/drivers/staging/imx-drm/ipuv3-crtc.c +++ b/drivers/staging/imx-drm/ipuv3-crtc.c @@ -350,10 +350,8 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc, return ret; } - ret = imx_drm_add_crtc(drm, &ipu_crtc->base, - &ipu_crtc->imx_crtc, - &ipu_crtc_helper_funcs, - ipu_crtc->dev->parent->of_node, pdata->di); + ret = imx_drm_add_crtc(drm, &ipu_crtc->base, &ipu_crtc->imx_crtc, + &ipu_crtc_helper_funcs, ipu_crtc->dev->of_node); if (ret) { dev_err(ipu_crtc->dev, "adding crtc failed with %d.\n", ret); goto err_put_resources; @@ -401,6 +399,28 @@ err_put_resources: return ret; } +static struct device_node *ipu_drm_get_port_by_id(struct device_node *parent, + int port_id) +{ + struct device_node *port; + int id, ret; + + port = of_get_child_by_name(parent, "port"); + while (port) { + ret = of_property_read_u32(port, "reg", &id); + if (!ret && id == port_id) + return port; + + do { + port = of_get_next_child(parent, port); + if (!port) + return NULL; + } while (of_node_cmp(port->name, "port")); + } + + return NULL; +} + static int ipu_drm_bind(struct device *dev, struct device *master, void *data) { struct ipu_client_platformdata *pdata = dev->platform_data; @@ -441,16 +461,29 @@ static const struct component_ops ipu_crtc_ops = { static int ipu_drm_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; + struct ipu_client_platformdata *pdata = dev->platform_data; int ret; - if (!pdev->dev.platform_data) + if (!dev->platform_data) return -EINVAL; - ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); + if (!dev->of_node) { + /* Associate crtc device with the corresponding DI port node */ + dev->of_node = ipu_drm_get_port_by_id(dev->parent->of_node, + pdata->di + 2); + if (!dev->of_node) { + dev_err(dev, "missing port@%d node in %s\n", + pdata->di + 2, dev->parent->of_node->full_name); + return -ENODEV; + } + } + + ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); if (ret) return ret; - return component_add(&pdev->dev, &ipu_crtc_ops); + return component_add(dev, &ipu_crtc_ops); } static int ipu_drm_remove(struct platform_device *pdev) |