.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (C) 2009 Nokia Corporation |
---|
3 | 4 | * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> |
---|
4 | 5 | * |
---|
5 | 6 | * Some code and ideas taken from drivers/video/omap/ driver |
---|
6 | 7 | * by Imre Deak. |
---|
7 | | - * |
---|
8 | | - * This program is free software; you can redistribute it and/or modify it |
---|
9 | | - * under the terms of the GNU General Public License version 2 as published by |
---|
10 | | - * the Free Software Foundation. |
---|
11 | | - * |
---|
12 | | - * This program is distributed in the hope that it will be useful, but WITHOUT |
---|
13 | | - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
---|
14 | | - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
---|
15 | | - * more details. |
---|
16 | | - * |
---|
17 | | - * You should have received a copy of the GNU General Public License along with |
---|
18 | | - * this program. If not, see <http://www.gnu.org/licenses/>. |
---|
19 | 8 | */ |
---|
20 | 9 | |
---|
21 | 10 | #define DSS_SUBSYS_NAME "DSS" |
---|
.. | .. |
---|
394 | 383 | |
---|
395 | 384 | dss_dump_clocks(dss, s); |
---|
396 | 385 | dispc_dump_clocks(dss->dispc, s); |
---|
397 | | -#ifdef CONFIG_OMAP2_DSS_DSI |
---|
398 | | - dsi_dump_clocks(s); |
---|
399 | | -#endif |
---|
400 | 386 | return 0; |
---|
401 | 387 | } |
---|
402 | 388 | |
---|
.. | .. |
---|
681 | 667 | return dss->feat->fck_freq_max; |
---|
682 | 668 | } |
---|
683 | 669 | |
---|
684 | | -enum omap_dss_output_id dss_get_supported_outputs(struct dss_device *dss, |
---|
685 | | - enum omap_channel channel) |
---|
686 | | -{ |
---|
687 | | - return dss->feat->outputs[channel]; |
---|
688 | | -} |
---|
689 | | - |
---|
690 | 670 | static int dss_setup_default_clock(struct dss_device *dss) |
---|
691 | 671 | { |
---|
692 | 672 | unsigned long max_dss_fck, prate; |
---|
.. | .. |
---|
943 | 923 | void *data) |
---|
944 | 924 | { |
---|
945 | 925 | struct dss_debugfs_entry *entry; |
---|
946 | | - struct dentry *d; |
---|
947 | 926 | |
---|
948 | 927 | entry = kzalloc(sizeof(*entry), GFP_KERNEL); |
---|
949 | 928 | if (!entry) |
---|
.. | .. |
---|
951 | 930 | |
---|
952 | 931 | entry->show_fn = show_fn; |
---|
953 | 932 | entry->data = data; |
---|
| 933 | + entry->dentry = debugfs_create_file(name, 0444, dss->debugfs.root, |
---|
| 934 | + entry, &dss_debug_fops); |
---|
954 | 935 | |
---|
955 | | - d = debugfs_create_file(name, 0444, dss->debugfs.root, entry, |
---|
956 | | - &dss_debug_fops); |
---|
957 | | - if (IS_ERR(d)) { |
---|
958 | | - kfree(entry); |
---|
959 | | - return ERR_PTR(PTR_ERR(d)); |
---|
960 | | - } |
---|
961 | | - |
---|
962 | | - entry->dentry = d; |
---|
963 | 936 | return entry; |
---|
964 | 937 | } |
---|
965 | 938 | |
---|
.. | .. |
---|
1178 | 1151 | .has_lcd_clk_src = true, |
---|
1179 | 1152 | }; |
---|
1180 | 1153 | |
---|
1181 | | -static int dss_init_ports(struct dss_device *dss) |
---|
| 1154 | +static void __dss_uninit_ports(struct dss_device *dss, unsigned int num_ports) |
---|
1182 | 1155 | { |
---|
1183 | 1156 | struct platform_device *pdev = dss->pdev; |
---|
1184 | 1157 | struct device_node *parent = pdev->dev.of_node; |
---|
1185 | 1158 | struct device_node *port; |
---|
1186 | | - int i; |
---|
| 1159 | + unsigned int i; |
---|
1187 | 1160 | |
---|
1188 | | - for (i = 0; i < dss->feat->num_ports; i++) { |
---|
1189 | | - port = of_graph_get_port_by_id(parent, i); |
---|
1190 | | - if (!port) |
---|
1191 | | - continue; |
---|
1192 | | - |
---|
1193 | | - switch (dss->feat->ports[i]) { |
---|
1194 | | - case OMAP_DISPLAY_TYPE_DPI: |
---|
1195 | | - dpi_init_port(dss, pdev, port, dss->feat->model); |
---|
1196 | | - break; |
---|
1197 | | - case OMAP_DISPLAY_TYPE_SDI: |
---|
1198 | | - sdi_init_port(dss, pdev, port); |
---|
1199 | | - break; |
---|
1200 | | - default: |
---|
1201 | | - break; |
---|
1202 | | - } |
---|
1203 | | - } |
---|
1204 | | - |
---|
1205 | | - return 0; |
---|
1206 | | -} |
---|
1207 | | - |
---|
1208 | | -static void dss_uninit_ports(struct dss_device *dss) |
---|
1209 | | -{ |
---|
1210 | | - struct platform_device *pdev = dss->pdev; |
---|
1211 | | - struct device_node *parent = pdev->dev.of_node; |
---|
1212 | | - struct device_node *port; |
---|
1213 | | - int i; |
---|
1214 | | - |
---|
1215 | | - for (i = 0; i < dss->feat->num_ports; i++) { |
---|
| 1161 | + for (i = 0; i < num_ports; i++) { |
---|
1216 | 1162 | port = of_graph_get_port_by_id(parent, i); |
---|
1217 | 1163 | if (!port) |
---|
1218 | 1164 | continue; |
---|
.. | .. |
---|
1227 | 1173 | default: |
---|
1228 | 1174 | break; |
---|
1229 | 1175 | } |
---|
| 1176 | + of_node_put(port); |
---|
1230 | 1177 | } |
---|
| 1178 | +} |
---|
| 1179 | + |
---|
| 1180 | +static int dss_init_ports(struct dss_device *dss) |
---|
| 1181 | +{ |
---|
| 1182 | + struct platform_device *pdev = dss->pdev; |
---|
| 1183 | + struct device_node *parent = pdev->dev.of_node; |
---|
| 1184 | + struct device_node *port; |
---|
| 1185 | + unsigned int i; |
---|
| 1186 | + int r; |
---|
| 1187 | + |
---|
| 1188 | + for (i = 0; i < dss->feat->num_ports; i++) { |
---|
| 1189 | + port = of_graph_get_port_by_id(parent, i); |
---|
| 1190 | + if (!port) |
---|
| 1191 | + continue; |
---|
| 1192 | + |
---|
| 1193 | + switch (dss->feat->ports[i]) { |
---|
| 1194 | + case OMAP_DISPLAY_TYPE_DPI: |
---|
| 1195 | + r = dpi_init_port(dss, pdev, port, dss->feat->model); |
---|
| 1196 | + if (r) |
---|
| 1197 | + goto error; |
---|
| 1198 | + break; |
---|
| 1199 | + |
---|
| 1200 | + case OMAP_DISPLAY_TYPE_SDI: |
---|
| 1201 | + r = sdi_init_port(dss, pdev, port); |
---|
| 1202 | + if (r) |
---|
| 1203 | + goto error; |
---|
| 1204 | + break; |
---|
| 1205 | + |
---|
| 1206 | + default: |
---|
| 1207 | + break; |
---|
| 1208 | + } |
---|
| 1209 | + of_node_put(port); |
---|
| 1210 | + } |
---|
| 1211 | + |
---|
| 1212 | + return 0; |
---|
| 1213 | + |
---|
| 1214 | +error: |
---|
| 1215 | + of_node_put(port); |
---|
| 1216 | + __dss_uninit_ports(dss, i); |
---|
| 1217 | + return r; |
---|
| 1218 | +} |
---|
| 1219 | + |
---|
| 1220 | +static void dss_uninit_ports(struct dss_device *dss) |
---|
| 1221 | +{ |
---|
| 1222 | + __dss_uninit_ports(dss, dss->feat->num_ports); |
---|
1231 | 1223 | } |
---|
1232 | 1224 | |
---|
1233 | 1225 | static int dss_video_pll_probe(struct dss_device *dss) |
---|
.. | .. |
---|
1315 | 1307 | static int dss_bind(struct device *dev) |
---|
1316 | 1308 | { |
---|
1317 | 1309 | struct dss_device *dss = dev_get_drvdata(dev); |
---|
| 1310 | + struct platform_device *drm_pdev; |
---|
1318 | 1311 | int r; |
---|
1319 | 1312 | |
---|
1320 | 1313 | r = component_bind_all(dev, NULL); |
---|
.. | .. |
---|
1323 | 1316 | |
---|
1324 | 1317 | pm_set_vt_switch(0); |
---|
1325 | 1318 | |
---|
1326 | | - omapdss_gather_components(dev); |
---|
1327 | 1319 | omapdss_set_dss(dss); |
---|
| 1320 | + |
---|
| 1321 | + drm_pdev = platform_device_register_simple("omapdrm", 0, NULL, 0); |
---|
| 1322 | + if (IS_ERR(drm_pdev)) { |
---|
| 1323 | + component_unbind_all(dev, NULL); |
---|
| 1324 | + return PTR_ERR(drm_pdev); |
---|
| 1325 | + } |
---|
| 1326 | + |
---|
| 1327 | + dss->drm_pdev = drm_pdev; |
---|
1328 | 1328 | |
---|
1329 | 1329 | return 0; |
---|
1330 | 1330 | } |
---|
1331 | 1331 | |
---|
1332 | 1332 | static void dss_unbind(struct device *dev) |
---|
1333 | 1333 | { |
---|
| 1334 | + struct dss_device *dss = dev_get_drvdata(dev); |
---|
| 1335 | + |
---|
| 1336 | + platform_device_unregister(dss->drm_pdev); |
---|
| 1337 | + |
---|
1334 | 1338 | omapdss_set_dss(NULL); |
---|
1335 | 1339 | |
---|
1336 | 1340 | component_unbind_all(dev, NULL); |
---|
.. | .. |
---|
1347 | 1351 | return dev == child; |
---|
1348 | 1352 | } |
---|
1349 | 1353 | |
---|
| 1354 | +struct dss_component_match_data { |
---|
| 1355 | + struct device *dev; |
---|
| 1356 | + struct component_match **match; |
---|
| 1357 | +}; |
---|
| 1358 | + |
---|
1350 | 1359 | static int dss_add_child_component(struct device *dev, void *data) |
---|
1351 | 1360 | { |
---|
1352 | | - struct component_match **match = data; |
---|
| 1361 | + struct dss_component_match_data *cmatch = data; |
---|
| 1362 | + struct component_match **match = cmatch->match; |
---|
1353 | 1363 | |
---|
1354 | 1364 | /* |
---|
1355 | 1365 | * HACK |
---|
.. | .. |
---|
1360 | 1370 | if (strstr(dev_name(dev), "rfbi")) |
---|
1361 | 1371 | return 0; |
---|
1362 | 1372 | |
---|
1363 | | - component_match_add(dev->parent, match, dss_component_compare, dev); |
---|
| 1373 | + /* |
---|
| 1374 | + * Handle possible interconnect target modules defined within the DSS. |
---|
| 1375 | + * The DSS components can be children of an interconnect target module |
---|
| 1376 | + * after the device tree has been updated for the module data. |
---|
| 1377 | + * See also omapdss_boot_init() for compatible fixup. |
---|
| 1378 | + */ |
---|
| 1379 | + if (strstr(dev_name(dev), "target-module")) |
---|
| 1380 | + return device_for_each_child(dev, cmatch, |
---|
| 1381 | + dss_add_child_component); |
---|
| 1382 | + |
---|
| 1383 | + component_match_add(cmatch->dev, match, dss_component_compare, dev); |
---|
1364 | 1384 | |
---|
1365 | 1385 | return 0; |
---|
1366 | 1386 | } |
---|
.. | .. |
---|
1403 | 1423 | static int dss_probe(struct platform_device *pdev) |
---|
1404 | 1424 | { |
---|
1405 | 1425 | const struct soc_device_attribute *soc; |
---|
| 1426 | + struct dss_component_match_data cmatch; |
---|
1406 | 1427 | struct component_match *match = NULL; |
---|
1407 | 1428 | struct resource *dss_mem; |
---|
1408 | 1429 | struct dss_device *dss; |
---|
.. | .. |
---|
1474 | 1495 | dss); |
---|
1475 | 1496 | |
---|
1476 | 1497 | /* Add all the child devices as components. */ |
---|
1477 | | - device_for_each_child(&pdev->dev, &match, dss_add_child_component); |
---|
1478 | | - |
---|
1479 | | - r = component_master_add_with_match(&pdev->dev, &dss_component_ops, match); |
---|
| 1498 | + r = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); |
---|
1480 | 1499 | if (r) |
---|
1481 | 1500 | goto err_uninit_debugfs; |
---|
1482 | 1501 | |
---|
| 1502 | + omapdss_gather_components(&pdev->dev); |
---|
| 1503 | + |
---|
| 1504 | + cmatch.dev = &pdev->dev; |
---|
| 1505 | + cmatch.match = &match; |
---|
| 1506 | + device_for_each_child(&pdev->dev, &cmatch, dss_add_child_component); |
---|
| 1507 | + |
---|
| 1508 | + r = component_master_add_with_match(&pdev->dev, &dss_component_ops, match); |
---|
| 1509 | + if (r) |
---|
| 1510 | + goto err_of_depopulate; |
---|
| 1511 | + |
---|
1483 | 1512 | return 0; |
---|
| 1513 | + |
---|
| 1514 | +err_of_depopulate: |
---|
| 1515 | + of_platform_depopulate(&pdev->dev); |
---|
1484 | 1516 | |
---|
1485 | 1517 | err_uninit_debugfs: |
---|
1486 | 1518 | dss_debugfs_remove_file(dss->debugfs.clk); |
---|
.. | .. |
---|
1509 | 1541 | static int dss_remove(struct platform_device *pdev) |
---|
1510 | 1542 | { |
---|
1511 | 1543 | struct dss_device *dss = platform_get_drvdata(pdev); |
---|
| 1544 | + |
---|
| 1545 | + of_platform_depopulate(&pdev->dev); |
---|
1512 | 1546 | |
---|
1513 | 1547 | component_master_del(&pdev->dev, &dss_component_ops); |
---|
1514 | 1548 | |
---|
.. | .. |
---|
1539 | 1573 | |
---|
1540 | 1574 | DSSDBG("shutdown\n"); |
---|
1541 | 1575 | |
---|
1542 | | - for_each_dss_dev(dssdev) { |
---|
1543 | | - if (!dssdev->driver) |
---|
1544 | | - continue; |
---|
1545 | | - |
---|
1546 | | - if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) |
---|
1547 | | - dssdev->driver->disable(dssdev); |
---|
| 1576 | + for_each_dss_output(dssdev) { |
---|
| 1577 | + if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE && |
---|
| 1578 | + dssdev->ops && dssdev->ops->disable) |
---|
| 1579 | + dssdev->ops->disable(dssdev); |
---|
1548 | 1580 | } |
---|
1549 | 1581 | } |
---|
1550 | 1582 | |
---|
.. | .. |
---|
1585 | 1617 | static const struct dev_pm_ops dss_pm_ops = { |
---|
1586 | 1618 | .runtime_suspend = dss_runtime_suspend, |
---|
1587 | 1619 | .runtime_resume = dss_runtime_resume, |
---|
| 1620 | + SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) |
---|
1588 | 1621 | }; |
---|
1589 | 1622 | |
---|
1590 | 1623 | struct platform_driver omap_dsshw_driver = { |
---|
.. | .. |
---|
1598 | 1631 | .suppress_bind_attrs = true, |
---|
1599 | 1632 | }, |
---|
1600 | 1633 | }; |
---|
| 1634 | + |
---|
| 1635 | +/* INIT */ |
---|
| 1636 | +static struct platform_driver * const omap_dss_drivers[] = { |
---|
| 1637 | + &omap_dsshw_driver, |
---|
| 1638 | + &omap_dispchw_driver, |
---|
| 1639 | +#ifdef CONFIG_OMAP2_DSS_DSI |
---|
| 1640 | + &omap_dsihw_driver, |
---|
| 1641 | +#endif |
---|
| 1642 | +#ifdef CONFIG_OMAP2_DSS_VENC |
---|
| 1643 | + &omap_venchw_driver, |
---|
| 1644 | +#endif |
---|
| 1645 | +#ifdef CONFIG_OMAP4_DSS_HDMI |
---|
| 1646 | + &omapdss_hdmi4hw_driver, |
---|
| 1647 | +#endif |
---|
| 1648 | +#ifdef CONFIG_OMAP5_DSS_HDMI |
---|
| 1649 | + &omapdss_hdmi5hw_driver, |
---|
| 1650 | +#endif |
---|
| 1651 | +}; |
---|
| 1652 | + |
---|
| 1653 | +static int __init omap_dss_init(void) |
---|
| 1654 | +{ |
---|
| 1655 | + return platform_register_drivers(omap_dss_drivers, |
---|
| 1656 | + ARRAY_SIZE(omap_dss_drivers)); |
---|
| 1657 | +} |
---|
| 1658 | + |
---|
| 1659 | +static void __exit omap_dss_exit(void) |
---|
| 1660 | +{ |
---|
| 1661 | + platform_unregister_drivers(omap_dss_drivers, |
---|
| 1662 | + ARRAY_SIZE(omap_dss_drivers)); |
---|
| 1663 | +} |
---|
| 1664 | + |
---|
| 1665 | +module_init(omap_dss_init); |
---|
| 1666 | +module_exit(omap_dss_exit); |
---|
| 1667 | + |
---|
| 1668 | +MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>"); |
---|
| 1669 | +MODULE_DESCRIPTION("OMAP2/3/4/5 Display Subsystem"); |
---|
| 1670 | +MODULE_LICENSE("GPL v2"); |
---|