aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Yan <andy.yan@rock-chips.com>2014-12-05 01:25:05 -0500
committerPhilipp Zabel <p.zabel@pengutronix.de>2015-01-06 11:36:16 -0500
commit3d1b35a3d9f3d6de690b237995d5aa858e349648 (patch)
tree341c0519e5498f911035d7035f56ba675c4764b6
parentc2c3848851a723a0e5e0fec22df395a885edf459 (diff)
drm: imx: imx-hdmi: convert imx-hdmi to drm_bridge mode
IMX6 and Rockchip RK3288 and JZ4780 (Ingenic Xburst/MIPS) use the interface compatible Designware HDMI IP, but they also have some lightly differences, such as phy pll configuration, register width, 4K support, clk useage, and the crtc mux configuration is also platform specific. To reuse the imx hdmi driver, convert it to drm_bridge handle encoder in imx-hdmi_pltfm.c, as most of the encoder operation are platform specific such as crtc select and panel format set This patch depends on Russell King's patch: drm: imx: convert imx-drm to use the generic DRM OF helper http://driverdev.linuxdriverproject.org/pipermail/driverdev-devel/2014-July/053484.html Signed-off-by: Andy Yan <andy.yan@rock-chips.com> Signed-off-by: Yakir Yang <ykk@rock-chips.com> Tested-by: Russell King <rmk+kernel@arm.linux.org.uk> Acked-by: Russell King <rmk+kernel@arm.linux.org.uk> Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
-rw-r--r--drivers/gpu/drm/imx/Makefile2
-rw-r--r--drivers/gpu/drm/imx/imx-hdmi.c257
-rw-r--r--drivers/gpu/drm/imx/imx-hdmi.h15
-rw-r--r--drivers/gpu/drm/imx/imx-hdmi_pltfm.c203
4 files changed, 315 insertions, 162 deletions
diff --git a/drivers/gpu/drm/imx/Makefile b/drivers/gpu/drm/imx/Makefile
index 582c438d8cbd..63cf56ad5c61 100644
--- a/drivers/gpu/drm/imx/Makefile
+++ b/drivers/gpu/drm/imx/Makefile
@@ -9,4 +9,4 @@ obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o
9 9
10imx-ipuv3-crtc-objs := ipuv3-crtc.o ipuv3-plane.o 10imx-ipuv3-crtc-objs := ipuv3-crtc.o ipuv3-plane.o
11obj-$(CONFIG_DRM_IMX_IPUV3) += imx-ipuv3-crtc.o 11obj-$(CONFIG_DRM_IMX_IPUV3) += imx-ipuv3-crtc.o
12obj-$(CONFIG_DRM_IMX_HDMI) += imx-hdmi.o 12obj-$(CONFIG_DRM_IMX_HDMI) += imx-hdmi.o imx-hdmi_pltfm.o
diff --git a/drivers/gpu/drm/imx/imx-hdmi.c b/drivers/gpu/drm/imx/imx-hdmi.c
index 3118dde3ea62..9f2f0feb7b75 100644
--- a/drivers/gpu/drm/imx/imx-hdmi.c
+++ b/drivers/gpu/drm/imx/imx-hdmi.c
@@ -12,25 +12,20 @@
12 * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de> 12 * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
13 */ 13 */
14 14
15#include <linux/component.h>
16#include <linux/irq.h> 15#include <linux/irq.h>
17#include <linux/delay.h> 16#include <linux/delay.h>
18#include <linux/err.h> 17#include <linux/err.h>
19#include <linux/clk.h> 18#include <linux/clk.h>
20#include <linux/hdmi.h> 19#include <linux/hdmi.h>
21#include <linux/regmap.h>
22#include <linux/mfd/syscon.h>
23#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
24#include <linux/of_device.h> 20#include <linux/of_device.h>
25 21
22#include <drm/drm_of.h>
26#include <drm/drmP.h> 23#include <drm/drmP.h>
27#include <drm/drm_crtc_helper.h> 24#include <drm/drm_crtc_helper.h>
28#include <drm/drm_edid.h> 25#include <drm/drm_edid.h>
29#include <drm/drm_encoder_slave.h> 26#include <drm/drm_encoder_slave.h>
30#include <video/imx-ipu-v3.h>
31 27
32#include "imx-hdmi.h" 28#include "imx-hdmi.h"
33#include "imx-drm.h"
34 29
35#define HDMI_EDID_LEN 512 30#define HDMI_EDID_LEN 512
36 31
@@ -54,11 +49,6 @@ enum hdmi_datamap {
54 YCbCr422_12B = 0x12, 49 YCbCr422_12B = 0x12,
55}; 50};
56 51
57enum imx_hdmi_devtype {
58 IMX6Q_HDMI,
59 IMX6DL_HDMI,
60};
61
62static const u16 csc_coeff_default[3][4] = { 52static const u16 csc_coeff_default[3][4] = {
63 { 0x2000, 0x0000, 0x0000, 0x0000 }, 53 { 0x2000, 0x0000, 0x0000, 0x0000 },
64 { 0x0000, 0x2000, 0x0000, 0x0000 }, 54 { 0x0000, 0x2000, 0x0000, 0x0000 },
@@ -113,7 +103,8 @@ struct hdmi_data_info {
113 103
114struct imx_hdmi { 104struct imx_hdmi {
115 struct drm_connector connector; 105 struct drm_connector connector;
116 struct drm_encoder encoder; 106 struct drm_encoder *encoder;
107 struct drm_bridge *bridge;
117 108
118 enum imx_hdmi_devtype dev_type; 109 enum imx_hdmi_devtype dev_type;
119 struct device *dev; 110 struct device *dev;
@@ -121,6 +112,7 @@ struct imx_hdmi {
121 struct clk *iahb_clk; 112 struct clk *iahb_clk;
122 113
123 struct hdmi_data_info hdmi_data; 114 struct hdmi_data_info hdmi_data;
115 const struct imx_hdmi_plat_data *plat_data;
124 int vic; 116 int vic;
125 117
126 u8 edid[HDMI_EDID_LEN]; 118 u8 edid[HDMI_EDID_LEN];
@@ -137,13 +129,6 @@ struct imx_hdmi {
137 int ratio; 129 int ratio;
138}; 130};
139 131
140static void imx_hdmi_set_ipu_di_mux(struct imx_hdmi *hdmi, int ipu_di)
141{
142 regmap_update_bits(hdmi->regmap, IOMUXC_GPR3,
143 IMX6Q_GPR3_HDMI_MUX_CTL_MASK,
144 ipu_di << IMX6Q_GPR3_HDMI_MUX_CTL_SHIFT);
145}
146
147static inline void hdmi_writeb(struct imx_hdmi *hdmi, u8 val, int offset) 132static inline void hdmi_writeb(struct imx_hdmi *hdmi, u8 val, int offset)
148{ 133{
149 writeb(val, hdmi->regs + offset); 134 writeb(val, hdmi->regs + offset);
@@ -1371,6 +1356,50 @@ static void imx_hdmi_poweroff(struct imx_hdmi *hdmi)
1371 imx_hdmi_phy_disable(hdmi); 1356 imx_hdmi_phy_disable(hdmi);
1372} 1357}
1373 1358
1359static void imx_hdmi_bridge_mode_set(struct drm_bridge *bridge,
1360 struct drm_display_mode *mode,
1361 struct drm_display_mode *adjusted_mode)
1362{
1363 struct imx_hdmi *hdmi = bridge->driver_private;
1364
1365 imx_hdmi_setup(hdmi, mode);
1366
1367 /* Store the display mode for plugin/DKMS poweron events */
1368 memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode));
1369}
1370
1371static bool imx_hdmi_bridge_mode_fixup(struct drm_bridge *bridge,
1372 const struct drm_display_mode *mode,
1373 struct drm_display_mode *adjusted_mode)
1374{
1375 return true;
1376}
1377
1378static void imx_hdmi_bridge_disable(struct drm_bridge *bridge)
1379{
1380 struct imx_hdmi *hdmi = bridge->driver_private;
1381
1382 imx_hdmi_poweroff(hdmi);
1383}
1384
1385static void imx_hdmi_bridge_enable(struct drm_bridge *bridge)
1386{
1387 struct imx_hdmi *hdmi = bridge->driver_private;
1388
1389 imx_hdmi_poweron(hdmi);
1390}
1391
1392static void imx_hdmi_bridge_destroy(struct drm_bridge *bridge)
1393{
1394 drm_bridge_cleanup(bridge);
1395 kfree(bridge);
1396}
1397
1398static void imx_hdmi_bridge_nop(struct drm_bridge *bridge)
1399{
1400 /* do nothing */
1401}
1402
1374static enum drm_connector_status imx_hdmi_connector_detect(struct drm_connector 1403static enum drm_connector_status imx_hdmi_connector_detect(struct drm_connector
1375 *connector, bool force) 1404 *connector, bool force)
1376{ 1405{
@@ -1412,78 +1441,20 @@ static struct drm_encoder *imx_hdmi_connector_best_encoder(struct drm_connector
1412 struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi, 1441 struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
1413 connector); 1442 connector);
1414 1443
1415 return &hdmi->encoder; 1444 return hdmi->encoder;
1416} 1445}
1417 1446
1418static void imx_hdmi_encoder_mode_set(struct drm_encoder *encoder, 1447static void imx_hdmi_connector_destroy(struct drm_connector *connector)
1419 struct drm_display_mode *mode,
1420 struct drm_display_mode *adjusted_mode)
1421{ 1448{
1422 struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder); 1449 drm_connector_unregister(connector);
1423 1450 drm_connector_cleanup(connector);
1424 imx_hdmi_setup(hdmi, mode);
1425
1426 /* Store the display mode for plugin/DKMS poweron events */
1427 memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode));
1428} 1451}
1429 1452
1430static bool imx_hdmi_encoder_mode_fixup(struct drm_encoder *encoder,
1431 const struct drm_display_mode *mode,
1432 struct drm_display_mode *adjusted_mode)
1433{
1434 return true;
1435}
1436
1437static void imx_hdmi_encoder_disable(struct drm_encoder *encoder)
1438{
1439}
1440
1441static void imx_hdmi_encoder_dpms(struct drm_encoder *encoder, int mode)
1442{
1443 struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
1444
1445 if (mode)
1446 imx_hdmi_poweroff(hdmi);
1447 else
1448 imx_hdmi_poweron(hdmi);
1449}
1450
1451static void imx_hdmi_encoder_prepare(struct drm_encoder *encoder)
1452{
1453 struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
1454
1455 imx_hdmi_poweroff(hdmi);
1456 imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24);
1457}
1458
1459static void imx_hdmi_encoder_commit(struct drm_encoder *encoder)
1460{
1461 struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
1462 int mux = imx_drm_encoder_get_mux_id(hdmi->dev->of_node, encoder);
1463
1464 imx_hdmi_set_ipu_di_mux(hdmi, mux);
1465
1466 imx_hdmi_poweron(hdmi);
1467}
1468
1469static struct drm_encoder_funcs imx_hdmi_encoder_funcs = {
1470 .destroy = imx_drm_encoder_destroy,
1471};
1472
1473static struct drm_encoder_helper_funcs imx_hdmi_encoder_helper_funcs = {
1474 .dpms = imx_hdmi_encoder_dpms,
1475 .prepare = imx_hdmi_encoder_prepare,
1476 .commit = imx_hdmi_encoder_commit,
1477 .mode_set = imx_hdmi_encoder_mode_set,
1478 .mode_fixup = imx_hdmi_encoder_mode_fixup,
1479 .disable = imx_hdmi_encoder_disable,
1480};
1481
1482static struct drm_connector_funcs imx_hdmi_connector_funcs = { 1453static struct drm_connector_funcs imx_hdmi_connector_funcs = {
1483 .dpms = drm_helper_connector_dpms, 1454 .dpms = drm_helper_connector_dpms,
1484 .fill_modes = drm_helper_probe_single_connector_modes, 1455 .fill_modes = drm_helper_probe_single_connector_modes,
1485 .detect = imx_hdmi_connector_detect, 1456 .detect = imx_hdmi_connector_detect,
1486 .destroy = imx_drm_connector_destroy, 1457 .destroy = imx_hdmi_connector_destroy,
1487}; 1458};
1488 1459
1489static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = { 1460static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = {
@@ -1491,6 +1462,16 @@ static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = {
1491 .best_encoder = imx_hdmi_connector_best_encoder, 1462 .best_encoder = imx_hdmi_connector_best_encoder,
1492}; 1463};
1493 1464
1465struct drm_bridge_funcs imx_hdmi_bridge_funcs = {
1466 .enable = imx_hdmi_bridge_enable,
1467 .disable = imx_hdmi_bridge_disable,
1468 .pre_enable = imx_hdmi_bridge_nop,
1469 .post_disable = imx_hdmi_bridge_nop,
1470 .mode_set = imx_hdmi_bridge_mode_set,
1471 .mode_fixup = imx_hdmi_bridge_mode_fixup,
1472 .destroy = imx_hdmi_bridge_destroy,
1473};
1474
1494static irqreturn_t imx_hdmi_hardirq(int irq, void *dev_id) 1475static irqreturn_t imx_hdmi_hardirq(int irq, void *dev_id)
1495{ 1476{
1496 struct imx_hdmi *hdmi = dev_id; 1477 struct imx_hdmi *hdmi = dev_id;
@@ -1539,74 +1520,61 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
1539 1520
1540static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi) 1521static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
1541{ 1522{
1523 struct drm_encoder *encoder = hdmi->encoder;
1524 struct drm_bridge *bridge;
1542 int ret; 1525 int ret;
1543 1526
1544 ret = imx_drm_encoder_parse_of(drm, &hdmi->encoder, 1527 bridge = devm_kzalloc(drm->dev, sizeof(*bridge), GFP_KERNEL);
1545 hdmi->dev->of_node); 1528 if (!bridge) {
1546 if (ret) 1529 DRM_ERROR("Failed to allocate drm bridge\n");
1547 return ret; 1530 return -ENOMEM;
1531 }
1548 1532
1549 hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD; 1533 hdmi->bridge = bridge;
1534 bridge->driver_private = hdmi;
1535
1536 ret = drm_bridge_init(drm, bridge, &imx_hdmi_bridge_funcs);
1537 if (ret) {
1538 DRM_ERROR("Failed to initialize bridge with drm\n");
1539 return -EINVAL;
1540 }
1550 1541
1551 drm_encoder_helper_add(&hdmi->encoder, &imx_hdmi_encoder_helper_funcs); 1542 encoder->bridge = bridge;
1552 drm_encoder_init(drm, &hdmi->encoder, &imx_hdmi_encoder_funcs, 1543 hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
1553 DRM_MODE_ENCODER_TMDS);
1554 1544
1555 drm_connector_helper_add(&hdmi->connector, 1545 drm_connector_helper_add(&hdmi->connector,
1556 &imx_hdmi_connector_helper_funcs); 1546 &imx_hdmi_connector_helper_funcs);
1557 drm_connector_init(drm, &hdmi->connector, &imx_hdmi_connector_funcs, 1547 drm_connector_init(drm, &hdmi->connector, &imx_hdmi_connector_funcs,
1558 DRM_MODE_CONNECTOR_HDMIA); 1548 DRM_MODE_CONNECTOR_HDMIA);
1559 1549
1560 hdmi->connector.encoder = &hdmi->encoder; 1550 hdmi->connector.encoder = encoder;
1561 1551
1562 drm_mode_connector_attach_encoder(&hdmi->connector, &hdmi->encoder); 1552 drm_mode_connector_attach_encoder(&hdmi->connector, encoder);
1563 1553
1564 return 0; 1554 return 0;
1565} 1555}
1566 1556
1567static struct platform_device_id imx_hdmi_devtype[] = { 1557int imx_hdmi_bind(struct device *dev, struct device *master,
1568 { 1558 void *data, struct drm_encoder *encoder,
1569 .name = "imx6q-hdmi", 1559 struct resource *iores, int irq,
1570 .driver_data = IMX6Q_HDMI, 1560 const struct dw_hdmi_plat_data *plat_data)
1571 }, {
1572 .name = "imx6dl-hdmi",
1573 .driver_data = IMX6DL_HDMI,
1574 }, { /* sentinel */ }
1575};
1576MODULE_DEVICE_TABLE(platform, imx_hdmi_devtype);
1577
1578static const struct of_device_id imx_hdmi_dt_ids[] = {
1579{ .compatible = "fsl,imx6q-hdmi", .data = &imx_hdmi_devtype[IMX6Q_HDMI], },
1580{ .compatible = "fsl,imx6dl-hdmi", .data = &imx_hdmi_devtype[IMX6DL_HDMI], },
1581{ /* sentinel */ }
1582};
1583MODULE_DEVICE_TABLE(of, imx_hdmi_dt_ids);
1584
1585static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
1586{ 1561{
1587 struct platform_device *pdev = to_platform_device(dev);
1588 const struct of_device_id *of_id =
1589 of_match_device(imx_hdmi_dt_ids, dev);
1590 struct drm_device *drm = data; 1562 struct drm_device *drm = data;
1591 struct device_node *np = dev->of_node; 1563 struct device_node *np = dev->of_node;
1592 struct device_node *ddc_node; 1564 struct device_node *ddc_node;
1593 struct imx_hdmi *hdmi; 1565 struct imx_hdmi *hdmi;
1594 struct resource *iores; 1566 int ret;
1595 int ret, irq;
1596 1567
1597 hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL); 1568 hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
1598 if (!hdmi) 1569 if (!hdmi)
1599 return -ENOMEM; 1570 return -ENOMEM;
1600 1571
1572 hdmi->plat_data = plat_data;
1601 hdmi->dev = dev; 1573 hdmi->dev = dev;
1574 hdmi->dev_type = plat_data->dev_type;
1602 hdmi->sample_rate = 48000; 1575 hdmi->sample_rate = 48000;
1603 hdmi->ratio = 100; 1576 hdmi->ratio = 100;
1604 1577 hdmi->encoder = encoder;
1605 if (of_id) {
1606 const struct platform_device_id *device_id = of_id->data;
1607
1608 hdmi->dev_type = device_id->driver_data;
1609 }
1610 1578
1611 ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0); 1579 ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
1612 if (ddc_node) { 1580 if (ddc_node) {
@@ -1621,25 +1589,16 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
1621 dev_dbg(hdmi->dev, "no ddc property found\n"); 1589 dev_dbg(hdmi->dev, "no ddc property found\n");
1622 } 1590 }
1623 1591
1624 irq = platform_get_irq(pdev, 0);
1625 if (irq < 0)
1626 return irq;
1627
1628 ret = devm_request_threaded_irq(dev, irq, imx_hdmi_hardirq, 1592 ret = devm_request_threaded_irq(dev, irq, imx_hdmi_hardirq,
1629 imx_hdmi_irq, IRQF_SHARED, 1593 imx_hdmi_irq, IRQF_SHARED,
1630 dev_name(dev), hdmi); 1594 dev_name(dev), hdmi);
1631 if (ret) 1595 if (ret)
1632 return ret; 1596 return ret;
1633 1597
1634 iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1635 hdmi->regs = devm_ioremap_resource(dev, iores); 1598 hdmi->regs = devm_ioremap_resource(dev, iores);
1636 if (IS_ERR(hdmi->regs)) 1599 if (IS_ERR(hdmi->regs))
1637 return PTR_ERR(hdmi->regs); 1600 return PTR_ERR(hdmi->regs);
1638 1601
1639 hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
1640 if (IS_ERR(hdmi->regmap))
1641 return PTR_ERR(hdmi->regmap);
1642
1643 hdmi->isfr_clk = devm_clk_get(hdmi->dev, "isfr"); 1602 hdmi->isfr_clk = devm_clk_get(hdmi->dev, "isfr");
1644 if (IS_ERR(hdmi->isfr_clk)) { 1603 if (IS_ERR(hdmi->isfr_clk)) {
1645 ret = PTR_ERR(hdmi->isfr_clk); 1604 ret = PTR_ERR(hdmi->isfr_clk);
@@ -1713,9 +1672,9 @@ err_isfr:
1713 1672
1714 return ret; 1673 return ret;
1715} 1674}
1675EXPORT_SYMBOL_GPL(imx_hdmi_bind);
1716 1676
1717static void imx_hdmi_unbind(struct device *dev, struct device *master, 1677void imx_hdmi_unbind(struct device *dev, struct device *master, void *data)
1718 void *data)
1719{ 1678{
1720 struct imx_hdmi *hdmi = dev_get_drvdata(dev); 1679 struct imx_hdmi *hdmi = dev_get_drvdata(dev);
1721 1680
@@ -1723,41 +1682,17 @@ static void imx_hdmi_unbind(struct device *dev, struct device *master,
1723 hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0); 1682 hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
1724 1683
1725 hdmi->connector.funcs->destroy(&hdmi->connector); 1684 hdmi->connector.funcs->destroy(&hdmi->connector);
1726 hdmi->encoder.funcs->destroy(&hdmi->encoder); 1685 hdmi->encoder->funcs->destroy(hdmi->encoder);
1727 1686
1728 clk_disable_unprepare(hdmi->iahb_clk); 1687 clk_disable_unprepare(hdmi->iahb_clk);
1729 clk_disable_unprepare(hdmi->isfr_clk); 1688 clk_disable_unprepare(hdmi->isfr_clk);
1730 i2c_put_adapter(hdmi->ddc); 1689 i2c_put_adapter(hdmi->ddc);
1731} 1690}
1732 1691EXPORT_SYMBOL_GPL(imx_hdmi_unbind);
1733static const struct component_ops hdmi_ops = {
1734 .bind = imx_hdmi_bind,
1735 .unbind = imx_hdmi_unbind,
1736};
1737
1738static int imx_hdmi_platform_probe(struct platform_device *pdev)
1739{
1740 return component_add(&pdev->dev, &hdmi_ops);
1741}
1742
1743static int imx_hdmi_platform_remove(struct platform_device *pdev)
1744{
1745 component_del(&pdev->dev, &hdmi_ops);
1746 return 0;
1747}
1748
1749static struct platform_driver imx_hdmi_driver = {
1750 .probe = imx_hdmi_platform_probe,
1751 .remove = imx_hdmi_platform_remove,
1752 .driver = {
1753 .name = "imx-hdmi",
1754 .of_match_table = imx_hdmi_dt_ids,
1755 },
1756};
1757
1758module_platform_driver(imx_hdmi_driver);
1759 1692
1760MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); 1693MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
1694MODULE_AUTHOR("Andy Yan <andy.yan@rock-chips.com>");
1695MODULE_AUTHOR("Yakir Yang <ykk@rock-chips.com>");
1761MODULE_DESCRIPTION("i.MX6 HDMI transmitter driver"); 1696MODULE_DESCRIPTION("i.MX6 HDMI transmitter driver");
1762MODULE_LICENSE("GPL"); 1697MODULE_LICENSE("GPL");
1763MODULE_ALIAS("platform:imx-hdmi"); 1698MODULE_ALIAS("platform:imx-hdmi");
diff --git a/drivers/gpu/drm/imx/imx-hdmi.h b/drivers/gpu/drm/imx/imx-hdmi.h
index 39b677689db6..86c6c5bbc950 100644
--- a/drivers/gpu/drm/imx/imx-hdmi.h
+++ b/drivers/gpu/drm/imx/imx-hdmi.h
@@ -1029,4 +1029,19 @@ enum {
1029 HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_HIGH = 0x2, 1029 HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_HIGH = 0x2,
1030 HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_LOW = 0x0, 1030 HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_LOW = 0x0,
1031}; 1031};
1032
1033enum imx_hdmi_devtype {
1034 IMX6Q_HDMI,
1035 IMX6DL_HDMI,
1036};
1037
1038struct imx_hdmi_plat_data {
1039 enum imx_hdmi_devtype dev_type;
1040};
1041
1042int imx_hdmi_bind(struct device *dev, struct device *master,
1043 void *data, struct drm_encoder *encoder,
1044 struct resource *iores, int irq,
1045 const struct imx_hdmi_plat_data *plat_data);
1046void imx_hdmi_unbind(struct device *dev, struct device *master, void *data);
1032#endif /* __IMX_HDMI_H__ */ 1047#endif /* __IMX_HDMI_H__ */
diff --git a/drivers/gpu/drm/imx/imx-hdmi_pltfm.c b/drivers/gpu/drm/imx/imx-hdmi_pltfm.c
new file mode 100644
index 000000000000..690181df71eb
--- /dev/null
+++ b/drivers/gpu/drm/imx/imx-hdmi_pltfm.c
@@ -0,0 +1,203 @@
1/* Copyright (C) 2011-2013 Freescale Semiconductor, Inc.
2 *
3 * derived from imx-hdmi.c
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 */
9#include <linux/module.h>
10#include <linux/platform_device.h>
11#include <linux/component.h>
12#include <linux/mfd/syscon.h>
13#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
14#include <video/imx-ipu-v3.h>
15#include <linux/regmap.h>
16#include <drm/drm_of.h>
17#include <drm/drmP.h>
18#include <drm/drm_crtc_helper.h>
19#include <drm/drm_edid.h>
20#include <drm/drm_encoder_slave.h>
21
22#include "imx-drm.h"
23#include "imx-hdmi.h"
24
25struct imx_hdmi_priv {
26 struct device *dev;
27 struct drm_encoder encoder;
28 struct regmap *regmap;
29};
30
31static int imx_hdmi_parse_dt(struct imx_hdmi_priv *hdmi)
32{
33 struct device_node *np = hdmi->dev->of_node;
34
35 hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
36 if (IS_ERR(hdmi->regmap)) {
37 dev_err(hdmi->dev, "Unable to get gpr\n");
38 return PTR_ERR(hdmi->regmap);
39 }
40
41 return 0;
42}
43
44static void imx_hdmi_encoder_disable(struct drm_encoder *encoder)
45{
46}
47
48static bool imx_hdmi_encoder_mode_fixup(struct drm_encoder *encoder,
49 const struct drm_display_mode *mode,
50 struct drm_display_mode *adj_mode)
51{
52 return true;
53}
54
55static void imx_hdmi_encoder_mode_set(struct drm_encoder *encoder,
56 struct drm_display_mode *mode,
57 struct drm_display_mode *adj_mode)
58{
59}
60
61static void imx_hdmi_encoder_commit(struct drm_encoder *encoder)
62{
63 struct imx_hdmi_priv *hdmi = container_of(encoder,
64 struct imx_hdmi_priv,
65 encoder);
66 int mux = imx_drm_encoder_get_mux_id(hdmi->dev->of_node, encoder);
67
68 regmap_update_bits(hdmi->regmap, IOMUXC_GPR3,
69 IMX6Q_GPR3_HDMI_MUX_CTL_MASK,
70 mux << IMX6Q_GPR3_HDMI_MUX_CTL_SHIFT);
71}
72
73static void imx_hdmi_encoder_prepare(struct drm_encoder *encoder)
74{
75 imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24);
76}
77
78static struct drm_encoder_helper_funcs imx_hdmi_encoder_helper_funcs = {
79 .mode_fixup = imx_hdmi_encoder_mode_fixup,
80 .mode_set = imx_hdmi_encoder_mode_set,
81 .prepare = imx_hdmi_encoder_prepare,
82 .commit = imx_hdmi_encoder_commit,
83 .disable = imx_hdmi_encoder_disable,
84};
85
86static struct drm_encoder_funcs imx_hdmi_encoder_funcs = {
87 .destroy = drm_encoder_cleanup,
88};
89
90static struct imx_hdmi_plat_data imx6q_hdmi_drv_data = {
91 .dev_type = IMX6Q_HDMI,
92};
93
94static struct imx_hdmi_plat_data imx6dl_hdmi_drv_data = {
95 .dev_type = IMX6DL_HDMI,
96};
97
98static const struct of_device_id imx_hdmi_dt_ids[] = {
99 { .compatible = "fsl,imx6q-hdmi",
100 .data = &imx6q_hdmi_drv_data
101 }, {
102 .compatible = "fsl,imx6dl-hdmi",
103 .data = &imx6dl_hdmi_drv_data
104 },
105 {},
106};
107MODULE_DEVICE_TABLE(of, imx_hdmi_dt_ids);
108
109static int imx_hdmi_pltfm_bind(struct device *dev, struct device *master,
110 void *data)
111{
112 struct platform_device *pdev = to_platform_device(dev);
113 const struct imx_hdmi_plat_data *plat_data;
114 const struct of_device_id *match;
115 struct drm_device *drm = data;
116 struct drm_encoder *encoder;
117 struct imx_hdmi_priv *hdmi;
118 struct resource *iores;
119 int irq;
120 int ret;
121
122 if (!pdev->dev.of_node)
123 return -ENODEV;
124
125 hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
126 if (!hdmi)
127 return -ENOMEM;
128
129 match = of_match_node(imx_hdmi_dt_ids, pdev->dev.of_node);
130 plat_data = match->data;
131 hdmi->dev = &pdev->dev;
132 encoder = &hdmi->encoder;
133
134 irq = platform_get_irq(pdev, 0);
135 if (irq < 0)
136 return irq;
137
138 iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
139 if (!iores)
140 return -ENXIO;
141
142 platform_set_drvdata(pdev, hdmi);
143
144 encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
145 /*
146 * If we failed to find the CRTC(s) which this encoder is
147 * supposed to be connected to, it's because the CRTC has
148 * not been registered yet. Defer probing, and hope that
149 * the required CRTC is added later.
150 */
151 if (encoder->possible_crtcs == 0)
152 return -EPROBE_DEFER;
153
154 ret = imx_hdmi_parse_dt(hdmi);
155 if (ret < 0)
156 return ret;
157
158 drm_encoder_helper_add(encoder, &imx_hdmi_encoder_helper_funcs);
159 drm_encoder_init(drm, encoder, &imx_hdmi_encoder_funcs,
160 DRM_MODE_ENCODER_TMDS);
161
162 return imx_hdmi_bind(dev, master, data, encoder, iores, irq, plat_data);
163}
164
165static void imx_hdmi_pltfm_unbind(struct device *dev, struct device *master,
166 void *data)
167{
168 return imx_hdmi_unbind(dev, master, data);
169}
170
171static const struct component_ops imx_hdmi_ops = {
172 .bind = imx_hdmi_pltfm_bind,
173 .unbind = imx_hdmi_pltfm_unbind,
174};
175
176static int imx_hdmi_probe(struct platform_device *pdev)
177{
178 return component_add(&pdev->dev, &imx_hdmi_ops);
179}
180
181static int imx_hdmi_remove(struct platform_device *pdev)
182{
183 component_del(&pdev->dev, &imx_hdmi_ops);
184
185 return 0;
186}
187
188static struct platform_driver imx_hdmi_pltfm_driver = {
189 .probe = imx_hdmi_probe,
190 .remove = imx_hdmi_remove,
191 .driver = {
192 .name = "hdmi-imx",
193 .of_match_table = imx_hdmi_dt_ids,
194 },
195};
196
197module_platform_driver(imx_hdmi_pltfm_driver);
198
199MODULE_AUTHOR("Andy Yan <andy.yan@rock-chips.com>");
200MODULE_AUTHOR("Yakir Yang <ykk@rock-chips.com>");
201MODULE_DESCRIPTION("IMX6 Specific DW-HDMI Driver Extension");
202MODULE_LICENSE("GPL");
203MODULE_ALIAS("platform:hdmi-imx");