diff options
-rw-r--r-- | drivers/gpu/drm/imx/Makefile | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/imx/imx-hdmi.c | 257 | ||||
-rw-r--r-- | drivers/gpu/drm/imx/imx-hdmi.h | 15 | ||||
-rw-r--r-- | drivers/gpu/drm/imx/imx-hdmi_pltfm.c | 203 |
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 | ||
10 | imx-ipuv3-crtc-objs := ipuv3-crtc.o ipuv3-plane.o | 10 | imx-ipuv3-crtc-objs := ipuv3-crtc.o ipuv3-plane.o |
11 | obj-$(CONFIG_DRM_IMX_IPUV3) += imx-ipuv3-crtc.o | 11 | obj-$(CONFIG_DRM_IMX_IPUV3) += imx-ipuv3-crtc.o |
12 | obj-$(CONFIG_DRM_IMX_HDMI) += imx-hdmi.o | 12 | obj-$(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 | ||
57 | enum imx_hdmi_devtype { | ||
58 | IMX6Q_HDMI, | ||
59 | IMX6DL_HDMI, | ||
60 | }; | ||
61 | |||
62 | static const u16 csc_coeff_default[3][4] = { | 52 | static 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 | ||
114 | struct imx_hdmi { | 104 | struct 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 | ||
140 | static 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 | |||
147 | static inline void hdmi_writeb(struct imx_hdmi *hdmi, u8 val, int offset) | 132 | static 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 | ||
1359 | static 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 | |||
1371 | static 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 | |||
1378 | static 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 | |||
1385 | static 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 | |||
1392 | static void imx_hdmi_bridge_destroy(struct drm_bridge *bridge) | ||
1393 | { | ||
1394 | drm_bridge_cleanup(bridge); | ||
1395 | kfree(bridge); | ||
1396 | } | ||
1397 | |||
1398 | static void imx_hdmi_bridge_nop(struct drm_bridge *bridge) | ||
1399 | { | ||
1400 | /* do nothing */ | ||
1401 | } | ||
1402 | |||
1374 | static enum drm_connector_status imx_hdmi_connector_detect(struct drm_connector | 1403 | static 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 | ||
1418 | static void imx_hdmi_encoder_mode_set(struct drm_encoder *encoder, | 1447 | static 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 | ||
1430 | static 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 | |||
1437 | static void imx_hdmi_encoder_disable(struct drm_encoder *encoder) | ||
1438 | { | ||
1439 | } | ||
1440 | |||
1441 | static 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 | |||
1451 | static 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 | |||
1459 | static 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 | |||
1469 | static struct drm_encoder_funcs imx_hdmi_encoder_funcs = { | ||
1470 | .destroy = imx_drm_encoder_destroy, | ||
1471 | }; | ||
1472 | |||
1473 | static 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 | |||
1482 | static struct drm_connector_funcs imx_hdmi_connector_funcs = { | 1453 | static 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 | ||
1489 | static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = { | 1460 | static 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 | ||
1465 | struct 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 | |||
1494 | static irqreturn_t imx_hdmi_hardirq(int irq, void *dev_id) | 1475 | static 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 | ||
1540 | static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi) | 1521 | static 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 | ||
1567 | static struct platform_device_id imx_hdmi_devtype[] = { | 1557 | int 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 | }; | ||
1576 | MODULE_DEVICE_TABLE(platform, imx_hdmi_devtype); | ||
1577 | |||
1578 | static 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 | }; | ||
1583 | MODULE_DEVICE_TABLE(of, imx_hdmi_dt_ids); | ||
1584 | |||
1585 | static 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 | } |
1675 | EXPORT_SYMBOL_GPL(imx_hdmi_bind); | ||
1716 | 1676 | ||
1717 | static void imx_hdmi_unbind(struct device *dev, struct device *master, | 1677 | void 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 | 1691 | EXPORT_SYMBOL_GPL(imx_hdmi_unbind); | |
1733 | static const struct component_ops hdmi_ops = { | ||
1734 | .bind = imx_hdmi_bind, | ||
1735 | .unbind = imx_hdmi_unbind, | ||
1736 | }; | ||
1737 | |||
1738 | static int imx_hdmi_platform_probe(struct platform_device *pdev) | ||
1739 | { | ||
1740 | return component_add(&pdev->dev, &hdmi_ops); | ||
1741 | } | ||
1742 | |||
1743 | static int imx_hdmi_platform_remove(struct platform_device *pdev) | ||
1744 | { | ||
1745 | component_del(&pdev->dev, &hdmi_ops); | ||
1746 | return 0; | ||
1747 | } | ||
1748 | |||
1749 | static 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 | |||
1758 | module_platform_driver(imx_hdmi_driver); | ||
1759 | 1692 | ||
1760 | MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); | 1693 | MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); |
1694 | MODULE_AUTHOR("Andy Yan <andy.yan@rock-chips.com>"); | ||
1695 | MODULE_AUTHOR("Yakir Yang <ykk@rock-chips.com>"); | ||
1761 | MODULE_DESCRIPTION("i.MX6 HDMI transmitter driver"); | 1696 | MODULE_DESCRIPTION("i.MX6 HDMI transmitter driver"); |
1762 | MODULE_LICENSE("GPL"); | 1697 | MODULE_LICENSE("GPL"); |
1763 | MODULE_ALIAS("platform:imx-hdmi"); | 1698 | MODULE_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 | |||
1033 | enum imx_hdmi_devtype { | ||
1034 | IMX6Q_HDMI, | ||
1035 | IMX6DL_HDMI, | ||
1036 | }; | ||
1037 | |||
1038 | struct imx_hdmi_plat_data { | ||
1039 | enum imx_hdmi_devtype dev_type; | ||
1040 | }; | ||
1041 | |||
1042 | int 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); | ||
1046 | void 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 | |||
25 | struct imx_hdmi_priv { | ||
26 | struct device *dev; | ||
27 | struct drm_encoder encoder; | ||
28 | struct regmap *regmap; | ||
29 | }; | ||
30 | |||
31 | static 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 | |||
44 | static void imx_hdmi_encoder_disable(struct drm_encoder *encoder) | ||
45 | { | ||
46 | } | ||
47 | |||
48 | static 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 | |||
55 | static 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 | |||
61 | static 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 | |||
73 | static void imx_hdmi_encoder_prepare(struct drm_encoder *encoder) | ||
74 | { | ||
75 | imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24); | ||
76 | } | ||
77 | |||
78 | static 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 | |||
86 | static struct drm_encoder_funcs imx_hdmi_encoder_funcs = { | ||
87 | .destroy = drm_encoder_cleanup, | ||
88 | }; | ||
89 | |||
90 | static struct imx_hdmi_plat_data imx6q_hdmi_drv_data = { | ||
91 | .dev_type = IMX6Q_HDMI, | ||
92 | }; | ||
93 | |||
94 | static struct imx_hdmi_plat_data imx6dl_hdmi_drv_data = { | ||
95 | .dev_type = IMX6DL_HDMI, | ||
96 | }; | ||
97 | |||
98 | static 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 | }; | ||
107 | MODULE_DEVICE_TABLE(of, imx_hdmi_dt_ids); | ||
108 | |||
109 | static 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 | |||
165 | static 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 | |||
171 | static const struct component_ops imx_hdmi_ops = { | ||
172 | .bind = imx_hdmi_pltfm_bind, | ||
173 | .unbind = imx_hdmi_pltfm_unbind, | ||
174 | }; | ||
175 | |||
176 | static int imx_hdmi_probe(struct platform_device *pdev) | ||
177 | { | ||
178 | return component_add(&pdev->dev, &imx_hdmi_ops); | ||
179 | } | ||
180 | |||
181 | static int imx_hdmi_remove(struct platform_device *pdev) | ||
182 | { | ||
183 | component_del(&pdev->dev, &imx_hdmi_ops); | ||
184 | |||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | static 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 | |||
197 | module_platform_driver(imx_hdmi_pltfm_driver); | ||
198 | |||
199 | MODULE_AUTHOR("Andy Yan <andy.yan@rock-chips.com>"); | ||
200 | MODULE_AUTHOR("Yakir Yang <ykk@rock-chips.com>"); | ||
201 | MODULE_DESCRIPTION("IMX6 Specific DW-HDMI Driver Extension"); | ||
202 | MODULE_LICENSE("GPL"); | ||
203 | MODULE_ALIAS("platform:hdmi-imx"); | ||