| .. | .. |
|---|
| 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"); |
|---|