Commit f46e699c authored by Dave Airlie's avatar Dave Airlie

Merge tag 'imx-drm-fixes-2015-12-01' of git://git.pengutronix.de/git/pza/linux into drm-fixes

imx-drm crtc, plane, parallel panel, and TV encoder fixes

- Use drm_crtc_send_vblank_event to fix per crtc vblank handling
- Move the crtc device of_node assignment out of the ipuv3-crtc driver into
  ipu-common code, where the devices are created.
- Fix parallel display support with simple-panels
- Remove some unused fields and superfluous checks
- Switch to universal planes and add error handling for primary plane creation
- Fix module autoload for TV encoder driver

* tag 'imx-drm-fixes-2015-12-01' of git://git.pengutronix.de/git/pza/linux:
  drm: imx: imx-tve: Fix module autoload for OF platform driver
  drm: imx: convert to drm_crtc_send_vblank_event()
  GPU-DRM-IMX: Delete an unnecessary check before drm_fbdev_cma_restore_mode()
  drm/imx: Remove of_node assignment from ipuv3-crtc driver probe
  gpu: ipu-v3: Assign of_node of child platform devices to corresponding ports
  gpu: ipu-v3: Remove reg_offset field
  gpu: ipu-v3: drop unused dmfc field from client platform data
  drm/imx: parallel-display: allow to determine bus format from the connected panel
  drm/imx: ipuv3-crtc: Return error if ipu_plane_init() fails for primary plane
  drm/imx: switch to universal planes
parents 00b83070 5e4789d3
...@@ -63,8 +63,7 @@ static void imx_drm_driver_lastclose(struct drm_device *drm) ...@@ -63,8 +63,7 @@ static void imx_drm_driver_lastclose(struct drm_device *drm)
#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER) #if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
struct imx_drm_device *imxdrm = drm->dev_private; struct imx_drm_device *imxdrm = drm->dev_private;
if (imxdrm->fbhelper) drm_fbdev_cma_restore_mode(imxdrm->fbhelper);
drm_fbdev_cma_restore_mode(imxdrm->fbhelper);
#endif #endif
} }
...@@ -340,7 +339,7 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags) ...@@ -340,7 +339,7 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
* imx_drm_add_crtc - add a new crtc * imx_drm_add_crtc - add a new crtc
*/ */
int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc, int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
struct imx_drm_crtc **new_crtc, struct imx_drm_crtc **new_crtc, struct drm_plane *primary_plane,
const struct imx_drm_crtc_helper_funcs *imx_drm_helper_funcs, const struct imx_drm_crtc_helper_funcs *imx_drm_helper_funcs,
struct device_node *port) struct device_node *port)
{ {
...@@ -379,7 +378,7 @@ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc, ...@@ -379,7 +378,7 @@ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
drm_crtc_helper_add(crtc, drm_crtc_helper_add(crtc,
imx_drm_crtc->imx_drm_helper_funcs.crtc_helper_funcs); imx_drm_crtc->imx_drm_helper_funcs.crtc_helper_funcs);
drm_crtc_init(drm, crtc, drm_crtc_init_with_planes(drm, crtc, primary_plane, NULL,
imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs); imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs);
return 0; return 0;
......
...@@ -9,6 +9,7 @@ struct drm_display_mode; ...@@ -9,6 +9,7 @@ struct drm_display_mode;
struct drm_encoder; struct drm_encoder;
struct drm_fbdev_cma; struct drm_fbdev_cma;
struct drm_framebuffer; struct drm_framebuffer;
struct drm_plane;
struct imx_drm_crtc; struct imx_drm_crtc;
struct platform_device; struct platform_device;
...@@ -24,7 +25,7 @@ struct imx_drm_crtc_helper_funcs { ...@@ -24,7 +25,7 @@ struct imx_drm_crtc_helper_funcs {
}; };
int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc, int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
struct imx_drm_crtc **new_crtc, struct imx_drm_crtc **new_crtc, struct drm_plane *primary_plane,
const struct imx_drm_crtc_helper_funcs *imx_helper_funcs, const struct imx_drm_crtc_helper_funcs *imx_helper_funcs,
struct device_node *port); struct device_node *port);
int imx_drm_remove_crtc(struct imx_drm_crtc *); int imx_drm_remove_crtc(struct imx_drm_crtc *);
......
...@@ -721,6 +721,7 @@ static const struct of_device_id imx_tve_dt_ids[] = { ...@@ -721,6 +721,7 @@ static const struct of_device_id imx_tve_dt_ids[] = {
{ .compatible = "fsl,imx53-tve", }, { .compatible = "fsl,imx53-tve", },
{ /* sentinel */ } { /* sentinel */ }
}; };
MODULE_DEVICE_TABLE(of, imx_tve_dt_ids);
static struct platform_driver imx_tve_driver = { static struct platform_driver imx_tve_driver = {
.probe = imx_tve_probe, .probe = imx_tve_probe,
......
...@@ -212,7 +212,8 @@ static void ipu_crtc_handle_pageflip(struct ipu_crtc *ipu_crtc) ...@@ -212,7 +212,8 @@ static void ipu_crtc_handle_pageflip(struct ipu_crtc *ipu_crtc)
spin_lock_irqsave(&drm->event_lock, flags); spin_lock_irqsave(&drm->event_lock, flags);
if (ipu_crtc->page_flip_event) if (ipu_crtc->page_flip_event)
drm_send_vblank_event(drm, -1, ipu_crtc->page_flip_event); drm_crtc_send_vblank_event(&ipu_crtc->base,
ipu_crtc->page_flip_event);
ipu_crtc->page_flip_event = NULL; ipu_crtc->page_flip_event = NULL;
imx_drm_crtc_vblank_put(ipu_crtc->imx_crtc); imx_drm_crtc_vblank_put(ipu_crtc->imx_crtc);
spin_unlock_irqrestore(&drm->event_lock, flags); spin_unlock_irqrestore(&drm->event_lock, flags);
...@@ -349,7 +350,6 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc, ...@@ -349,7 +350,6 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent); struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
int dp = -EINVAL; int dp = -EINVAL;
int ret; int ret;
int id;
ret = ipu_get_resources(ipu_crtc, pdata); ret = ipu_get_resources(ipu_crtc, pdata);
if (ret) { if (ret) {
...@@ -358,18 +358,23 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc, ...@@ -358,18 +358,23 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
return ret; return ret;
} }
if (pdata->dp >= 0)
dp = IPU_DP_FLOW_SYNC_BG;
ipu_crtc->plane[0] = ipu_plane_init(drm, ipu, pdata->dma[0], dp, 0,
DRM_PLANE_TYPE_PRIMARY);
if (IS_ERR(ipu_crtc->plane[0])) {
ret = PTR_ERR(ipu_crtc->plane[0]);
goto err_put_resources;
}
ret = imx_drm_add_crtc(drm, &ipu_crtc->base, &ipu_crtc->imx_crtc, ret = imx_drm_add_crtc(drm, &ipu_crtc->base, &ipu_crtc->imx_crtc,
&ipu_crtc_helper_funcs, ipu_crtc->dev->of_node); &ipu_crtc->plane[0]->base, &ipu_crtc_helper_funcs,
ipu_crtc->dev->of_node);
if (ret) { if (ret) {
dev_err(ipu_crtc->dev, "adding crtc failed with %d.\n", ret); dev_err(ipu_crtc->dev, "adding crtc failed with %d.\n", ret);
goto err_put_resources; goto err_put_resources;
} }
if (pdata->dp >= 0)
dp = IPU_DP_FLOW_SYNC_BG;
id = imx_drm_crtc_id(ipu_crtc->imx_crtc);
ipu_crtc->plane[0] = ipu_plane_init(ipu_crtc->base.dev, ipu,
pdata->dma[0], dp, BIT(id), true);
ret = ipu_plane_get_resources(ipu_crtc->plane[0]); ret = ipu_plane_get_resources(ipu_crtc->plane[0]);
if (ret) { if (ret) {
dev_err(ipu_crtc->dev, "getting plane 0 resources failed with %d.\n", dev_err(ipu_crtc->dev, "getting plane 0 resources failed with %d.\n",
...@@ -379,10 +384,10 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc, ...@@ -379,10 +384,10 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
/* If this crtc is using the DP, add an overlay plane */ /* If this crtc is using the DP, add an overlay plane */
if (pdata->dp >= 0 && pdata->dma[1] > 0) { if (pdata->dp >= 0 && pdata->dma[1] > 0) {
ipu_crtc->plane[1] = ipu_plane_init(ipu_crtc->base.dev, ipu, ipu_crtc->plane[1] = ipu_plane_init(drm, ipu, pdata->dma[1],
pdata->dma[1], IPU_DP_FLOW_SYNC_FG,
IPU_DP_FLOW_SYNC_FG, drm_crtc_mask(&ipu_crtc->base),
BIT(id), false); DRM_PLANE_TYPE_OVERLAY);
if (IS_ERR(ipu_crtc->plane[1])) if (IS_ERR(ipu_crtc->plane[1]))
ipu_crtc->plane[1] = NULL; ipu_crtc->plane[1] = NULL;
} }
...@@ -407,28 +412,6 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc, ...@@ -407,28 +412,6 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
return ret; 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) static int ipu_drm_bind(struct device *dev, struct device *master, void *data)
{ {
struct ipu_client_platformdata *pdata = dev->platform_data; struct ipu_client_platformdata *pdata = dev->platform_data;
...@@ -470,23 +453,11 @@ static const struct component_ops ipu_crtc_ops = { ...@@ -470,23 +453,11 @@ static const struct component_ops ipu_crtc_ops = {
static int ipu_drm_probe(struct platform_device *pdev) static int ipu_drm_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct ipu_client_platformdata *pdata = dev->platform_data;
int ret; int ret;
if (!dev->platform_data) if (!dev->platform_data)
return -EINVAL; return -EINVAL;
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)); ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
if (ret) if (ret)
return ret; return ret;
......
...@@ -381,7 +381,7 @@ static struct drm_plane_funcs ipu_plane_funcs = { ...@@ -381,7 +381,7 @@ static struct drm_plane_funcs ipu_plane_funcs = {
struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu, struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
int dma, int dp, unsigned int possible_crtcs, int dma, int dp, unsigned int possible_crtcs,
bool priv) enum drm_plane_type type)
{ {
struct ipu_plane *ipu_plane; struct ipu_plane *ipu_plane;
int ret; int ret;
...@@ -399,10 +399,9 @@ struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu, ...@@ -399,10 +399,9 @@ struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
ipu_plane->dma = dma; ipu_plane->dma = dma;
ipu_plane->dp_flow = dp; ipu_plane->dp_flow = dp;
ret = drm_plane_init(dev, &ipu_plane->base, possible_crtcs, ret = drm_universal_plane_init(dev, &ipu_plane->base, possible_crtcs,
&ipu_plane_funcs, ipu_plane_formats, &ipu_plane_funcs, ipu_plane_formats,
ARRAY_SIZE(ipu_plane_formats), ARRAY_SIZE(ipu_plane_formats), type);
priv);
if (ret) { if (ret) {
DRM_ERROR("failed to initialize plane\n"); DRM_ERROR("failed to initialize plane\n");
kfree(ipu_plane); kfree(ipu_plane);
......
...@@ -34,7 +34,7 @@ struct ipu_plane { ...@@ -34,7 +34,7 @@ struct ipu_plane {
struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu, struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
int dma, int dp, unsigned int possible_crtcs, int dma, int dp, unsigned int possible_crtcs,
bool priv); enum drm_plane_type type);
/* Init IDMAC, DMFC, DP */ /* Init IDMAC, DMFC, DP */
int ipu_plane_mode_set(struct ipu_plane *plane, struct drm_crtc *crtc, int ipu_plane_mode_set(struct ipu_plane *plane, struct drm_crtc *crtc,
......
...@@ -54,7 +54,11 @@ static int imx_pd_connector_get_modes(struct drm_connector *connector) ...@@ -54,7 +54,11 @@ static int imx_pd_connector_get_modes(struct drm_connector *connector)
if (imxpd->panel && imxpd->panel->funcs && if (imxpd->panel && imxpd->panel->funcs &&
imxpd->panel->funcs->get_modes) { imxpd->panel->funcs->get_modes) {
struct drm_display_info *di = &connector->display_info;
num_modes = imxpd->panel->funcs->get_modes(imxpd->panel); num_modes = imxpd->panel->funcs->get_modes(imxpd->panel);
if (!imxpd->bus_format && di->num_bus_formats)
imxpd->bus_format = di->bus_formats[0];
if (num_modes > 0) if (num_modes > 0)
return num_modes; return num_modes;
} }
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <linux/irqchip/chained_irq.h> #include <linux/irqchip/chained_irq.h>
#include <linux/irqdomain.h> #include <linux/irqdomain.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/of_graph.h>
#include <drm/drm_fourcc.h> #include <drm/drm_fourcc.h>
...@@ -993,11 +994,25 @@ static void platform_device_unregister_children(struct platform_device *pdev) ...@@ -993,11 +994,25 @@ static void platform_device_unregister_children(struct platform_device *pdev)
struct ipu_platform_reg { struct ipu_platform_reg {
struct ipu_client_platformdata pdata; struct ipu_client_platformdata pdata;
const char *name; const char *name;
int reg_offset;
}; };
/* These must be in the order of the corresponding device tree port nodes */
static const struct ipu_platform_reg client_reg[] = { static const struct ipu_platform_reg client_reg[] = {
{ {
.pdata = {
.csi = 0,
.dma[0] = IPUV3_CHANNEL_CSI0,
.dma[1] = -EINVAL,
},
.name = "imx-ipuv3-camera",
}, {
.pdata = {
.csi = 1,
.dma[0] = IPUV3_CHANNEL_CSI1,
.dma[1] = -EINVAL,
},
.name = "imx-ipuv3-camera",
}, {
.pdata = { .pdata = {
.di = 0, .di = 0,
.dc = 5, .dc = 5,
...@@ -1015,22 +1030,6 @@ static const struct ipu_platform_reg client_reg[] = { ...@@ -1015,22 +1030,6 @@ static const struct ipu_platform_reg client_reg[] = {
.dma[1] = -EINVAL, .dma[1] = -EINVAL,
}, },
.name = "imx-ipuv3-crtc", .name = "imx-ipuv3-crtc",
}, {
.pdata = {
.csi = 0,
.dma[0] = IPUV3_CHANNEL_CSI0,
.dma[1] = -EINVAL,
},
.reg_offset = IPU_CM_CSI0_REG_OFS,
.name = "imx-ipuv3-camera",
}, {
.pdata = {
.csi = 1,
.dma[0] = IPUV3_CHANNEL_CSI1,
.dma[1] = -EINVAL,
},
.reg_offset = IPU_CM_CSI1_REG_OFS,
.name = "imx-ipuv3-camera",
}, },
}; };
...@@ -1051,22 +1050,30 @@ static int ipu_add_client_devices(struct ipu_soc *ipu, unsigned long ipu_base) ...@@ -1051,22 +1050,30 @@ static int ipu_add_client_devices(struct ipu_soc *ipu, unsigned long ipu_base)
for (i = 0; i < ARRAY_SIZE(client_reg); i++) { for (i = 0; i < ARRAY_SIZE(client_reg); i++) {
const struct ipu_platform_reg *reg = &client_reg[i]; const struct ipu_platform_reg *reg = &client_reg[i];
struct platform_device *pdev; struct platform_device *pdev;
struct resource res;
pdev = platform_device_alloc(reg->name, id++);
if (reg->reg_offset) { if (!pdev) {
memset(&res, 0, sizeof(res)); ret = -ENOMEM;
res.flags = IORESOURCE_MEM; goto err_register;
res.start = ipu_base + ipu->devtype->cm_ofs + reg->reg_offset; }
res.end = res.start + PAGE_SIZE - 1;
pdev = platform_device_register_resndata(dev, reg->name, pdev->dev.parent = dev;
id++, &res, 1, &reg->pdata, sizeof(reg->pdata));
} else { /* Associate subdevice with the corresponding port node */
pdev = platform_device_register_data(dev, reg->name, pdev->dev.of_node = of_graph_get_port_by_id(dev->of_node, i);
id++, &reg->pdata, sizeof(reg->pdata)); if (!pdev->dev.of_node) {
dev_err(dev, "missing port@%d node in %s\n", i,
dev->of_node->full_name);
ret = -ENODEV;
goto err_register;
} }
if (IS_ERR(pdev)) { ret = platform_device_add_data(pdev, &reg->pdata,
ret = PTR_ERR(pdev); sizeof(reg->pdata));
if (!ret)
ret = platform_device_add(pdev);
if (ret) {
platform_device_put(pdev);
goto err_register; goto err_register;
} }
} }
......
...@@ -343,7 +343,6 @@ struct ipu_client_platformdata { ...@@ -343,7 +343,6 @@ struct ipu_client_platformdata {
int di; int di;
int dc; int dc;
int dp; int dp;
int dmfc;
int dma[2]; int dma[2];
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment