aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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");