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 -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJWXUoqAAoJEFDCiBxwnmDrNuUQALDHJMfmAxWpHxVn/YnT8/Yp 6FD4+7FJDNG11NLXdZ4+ZdoZvHaI5yc7AVxsfrrFSHajVHlJQNrU9MdLGfxS3Ctg Yr3sH/EPoH9l3Dkjxko9/5D56XeiQSc7elSxDQRLyaKxC4V7Lq8S6cK8Y91oU+NG KJK60iTAi8JU6j5DlfDZjHmlcvimuGwm2Kyp0WC21Ks1O6y0WuQdnn6z+ZoJXUe/ ReIfEBSainrNR9mZF2d9aBIAR2AkmHUOTnpXlbTFs7HFgQBfsu7J80OL6MRYui8S KBe3YE7hscKijVpjPZE2t4nW99ft2bXvHab+MIL5Crqz5XeJblhqERPoUm9iGmRe oLVEofXXhZ9mljDg2oKIVEX2YKjEnjxo8AzuGmeIK9UaBIB0PYQazf/626IHUT1P jADtKL5nO1jMtkrlogs8BSOnlbkodwqfiqYIyjLnO/HdUHNoOofq4szbTH7/sGoZ cUnRfwh7SAigmdxT1L0I2tRRv3BIKtZ/OYfyyRqOfgWALYFVdPI/ISDN7/CpwzNR qhgPFAJ59bN6riqrVJF3pq4+vmDQ30OL0TFFf9petZOm7OmsV5Bvfo2BgbatyOUo 77NLMztA2s5ugUT8gjDjOjZPAe+pByMCOg4ZRvyaE1JMyJI7ITXVLlCGk4obakDx yoSkRn2LiE2IKAVDalm5 =iEJU -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
f46e699cb6
@ -63,8 +63,7 @@ static void imx_drm_driver_lastclose(struct drm_device *drm)
|
||||
#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
|
||||
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
|
||||
}
|
||||
|
||||
@ -340,7 +339,7 @@ err_kms:
|
||||
* imx_drm_add_crtc - add a new 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,
|
||||
struct device_node *port)
|
||||
{
|
||||
@ -379,7 +378,7 @@ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
|
||||
drm_crtc_helper_add(crtc,
|
||||
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);
|
||||
|
||||
return 0;
|
||||
|
@ -9,6 +9,7 @@ struct drm_display_mode;
|
||||
struct drm_encoder;
|
||||
struct drm_fbdev_cma;
|
||||
struct drm_framebuffer;
|
||||
struct drm_plane;
|
||||
struct imx_drm_crtc;
|
||||
struct platform_device;
|
||||
|
||||
@ -24,7 +25,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,
|
||||
struct imx_drm_crtc **new_crtc, struct drm_plane *primary_plane,
|
||||
const struct imx_drm_crtc_helper_funcs *imx_helper_funcs,
|
||||
struct device_node *port);
|
||||
int imx_drm_remove_crtc(struct imx_drm_crtc *);
|
||||
|
@ -721,6 +721,7 @@ static const struct of_device_id imx_tve_dt_ids[] = {
|
||||
{ .compatible = "fsl,imx53-tve", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, imx_tve_dt_ids);
|
||||
|
||||
static struct platform_driver imx_tve_driver = {
|
||||
.probe = imx_tve_probe,
|
||||
|
@ -212,7 +212,8 @@ static void ipu_crtc_handle_pageflip(struct ipu_crtc *ipu_crtc)
|
||||
|
||||
spin_lock_irqsave(&drm->event_lock, flags);
|
||||
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;
|
||||
imx_drm_crtc_vblank_put(ipu_crtc->imx_crtc);
|
||||
spin_unlock_irqrestore(&drm->event_lock, flags);
|
||||
@ -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);
|
||||
int dp = -EINVAL;
|
||||
int ret;
|
||||
int id;
|
||||
|
||||
ret = ipu_get_resources(ipu_crtc, pdata);
|
||||
if (ret) {
|
||||
@ -358,18 +358,23 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
|
||||
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,
|
||||
&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) {
|
||||
dev_err(ipu_crtc->dev, "adding crtc failed with %d.\n", ret);
|
||||
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]);
|
||||
if (ret) {
|
||||
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,
|
||||
|
||||
/* If this crtc is using the DP, add an overlay plane */
|
||||
if (pdata->dp >= 0 && pdata->dma[1] > 0) {
|
||||
ipu_crtc->plane[1] = ipu_plane_init(ipu_crtc->base.dev, ipu,
|
||||
pdata->dma[1],
|
||||
IPU_DP_FLOW_SYNC_FG,
|
||||
BIT(id), false);
|
||||
ipu_crtc->plane[1] = ipu_plane_init(drm, ipu, pdata->dma[1],
|
||||
IPU_DP_FLOW_SYNC_FG,
|
||||
drm_crtc_mask(&ipu_crtc->base),
|
||||
DRM_PLANE_TYPE_OVERLAY);
|
||||
if (IS_ERR(ipu_crtc->plane[1]))
|
||||
ipu_crtc->plane[1] = NULL;
|
||||
}
|
||||
@ -407,28 +412,6 @@ 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;
|
||||
@ -470,23 +453,11 @@ 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 (!dev->platform_data)
|
||||
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));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -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,
|
||||
int dma, int dp, unsigned int possible_crtcs,
|
||||
bool priv)
|
||||
enum drm_plane_type type)
|
||||
{
|
||||
struct ipu_plane *ipu_plane;
|
||||
int ret;
|
||||
@ -399,10 +399,9 @@ struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
|
||||
ipu_plane->dma = dma;
|
||||
ipu_plane->dp_flow = dp;
|
||||
|
||||
ret = drm_plane_init(dev, &ipu_plane->base, possible_crtcs,
|
||||
&ipu_plane_funcs, ipu_plane_formats,
|
||||
ARRAY_SIZE(ipu_plane_formats),
|
||||
priv);
|
||||
ret = drm_universal_plane_init(dev, &ipu_plane->base, possible_crtcs,
|
||||
&ipu_plane_funcs, ipu_plane_formats,
|
||||
ARRAY_SIZE(ipu_plane_formats), type);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to initialize plane\n");
|
||||
kfree(ipu_plane);
|
||||
|
@ -34,7 +34,7 @@ struct ipu_plane {
|
||||
|
||||
struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
|
||||
int dma, int dp, unsigned int possible_crtcs,
|
||||
bool priv);
|
||||
enum drm_plane_type type);
|
||||
|
||||
/* Init IDMAC, DMFC, DP */
|
||||
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)
|
||||
|
||||
if (imxpd->panel && imxpd->panel->funcs &&
|
||||
imxpd->panel->funcs->get_modes) {
|
||||
struct drm_display_info *di = &connector->display_info;
|
||||
|
||||
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)
|
||||
return num_modes;
|
||||
}
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include <linux/irqchip/chained_irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_graph.h>
|
||||
|
||||
#include <drm/drm_fourcc.h>
|
||||
|
||||
@ -993,11 +994,25 @@ static void platform_device_unregister_children(struct platform_device *pdev)
|
||||
struct ipu_platform_reg {
|
||||
struct ipu_client_platformdata pdata;
|
||||
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[] = {
|
||||
{
|
||||
.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 = {
|
||||
.di = 0,
|
||||
.dc = 5,
|
||||
@ -1015,22 +1030,6 @@ static const struct ipu_platform_reg client_reg[] = {
|
||||
.dma[1] = -EINVAL,
|
||||
},
|
||||
.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)
|
||||
for (i = 0; i < ARRAY_SIZE(client_reg); i++) {
|
||||
const struct ipu_platform_reg *reg = &client_reg[i];
|
||||
struct platform_device *pdev;
|
||||
struct resource res;
|
||||
|
||||
if (reg->reg_offset) {
|
||||
memset(&res, 0, sizeof(res));
|
||||
res.flags = IORESOURCE_MEM;
|
||||
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,
|
||||
id++, &res, 1, ®->pdata, sizeof(reg->pdata));
|
||||
} else {
|
||||
pdev = platform_device_register_data(dev, reg->name,
|
||||
id++, ®->pdata, sizeof(reg->pdata));
|
||||
pdev = platform_device_alloc(reg->name, id++);
|
||||
if (!pdev) {
|
||||
ret = -ENOMEM;
|
||||
goto err_register;
|
||||
}
|
||||
|
||||
if (IS_ERR(pdev)) {
|
||||
ret = PTR_ERR(pdev);
|
||||
pdev->dev.parent = dev;
|
||||
|
||||
/* Associate subdevice with the corresponding port node */
|
||||
pdev->dev.of_node = of_graph_get_port_by_id(dev->of_node, i);
|
||||
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;
|
||||
}
|
||||
|
||||
ret = platform_device_add_data(pdev, ®->pdata,
|
||||
sizeof(reg->pdata));
|
||||
if (!ret)
|
||||
ret = platform_device_add(pdev);
|
||||
if (ret) {
|
||||
platform_device_put(pdev);
|
||||
goto err_register;
|
||||
}
|
||||
}
|
||||
|
@ -343,7 +343,6 @@ struct ipu_client_platformdata {
|
||||
int di;
|
||||
int dc;
|
||||
int dp;
|
||||
int dmfc;
|
||||
int dma[2];
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user