2 * Copyright (C) 2015 Texas Instruments
3 * Author: Jyri Sarha <jsarha@ti.com>
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 as published by
7 * the Free Software Foundation.
11 #include <linux/component.h>
12 #include <linux/of_graph.h>
14 #include "tilcdc_drv.h"
15 #include "tilcdc_external.h"
17 static const struct tilcdc_panel_info panel_info_tda998x
= {
30 static int tilcdc_external_mode_valid(struct drm_connector
*connector
,
31 struct drm_display_mode
*mode
)
33 struct tilcdc_drm_private
*priv
= connector
->dev
->dev_private
;
36 ret
= tilcdc_crtc_mode_valid(priv
->crtc
, mode
);
40 for (i
= 0; i
< priv
->num_connectors
&&
41 priv
->connectors
[i
] != connector
; i
++)
44 BUG_ON(priv
->connectors
[i
] != connector
);
45 BUG_ON(!priv
->connector_funcs
[i
]);
47 /* If the connector has its own mode_valid call it. */
48 if (!IS_ERR(priv
->connector_funcs
[i
]) &&
49 priv
->connector_funcs
[i
]->mode_valid
)
50 return priv
->connector_funcs
[i
]->mode_valid(connector
, mode
);
55 static int tilcdc_add_external_encoder(struct drm_device
*dev
,
56 struct drm_connector
*connector
)
58 struct tilcdc_drm_private
*priv
= dev
->dev_private
;
59 struct drm_connector_helper_funcs
*connector_funcs
;
61 priv
->connectors
[priv
->num_connectors
] = connector
;
62 priv
->encoders
[priv
->num_encoders
++] = connector
->encoder
;
64 /* Only tda998x is supported at the moment. */
65 tilcdc_crtc_set_simulate_vesa_sync(priv
->crtc
, true);
66 tilcdc_crtc_set_panel_info(priv
->crtc
, &panel_info_tda998x
);
68 connector_funcs
= devm_kzalloc(dev
->dev
, sizeof(*connector_funcs
),
73 /* connector->helper_private contains always struct
74 * connector_helper_funcs pointer. For tilcdc crtc to have a
75 * say if a specific mode is Ok, we need to install our own
76 * helper functions. In our helper functions we copy
77 * everything else but use our own mode_valid() (above).
79 if (connector
->helper_private
) {
80 priv
->connector_funcs
[priv
->num_connectors
] =
81 connector
->helper_private
;
82 *connector_funcs
= *priv
->connector_funcs
[priv
->num_connectors
];
84 priv
->connector_funcs
[priv
->num_connectors
] = ERR_PTR(-ENOENT
);
86 connector_funcs
->mode_valid
= tilcdc_external_mode_valid
;
87 drm_connector_helper_add(connector
, connector_funcs
);
88 priv
->num_connectors
++;
90 dev_dbg(dev
->dev
, "External encoder '%s' connected\n",
91 connector
->encoder
->name
);
96 int tilcdc_add_external_encoders(struct drm_device
*dev
)
98 struct tilcdc_drm_private
*priv
= dev
->dev_private
;
99 struct drm_connector
*connector
;
100 int num_internal_connectors
= priv
->num_connectors
;
102 list_for_each_entry(connector
, &dev
->mode_config
.connector_list
, head
) {
106 for (i
= 0; i
< num_internal_connectors
; i
++)
107 if (connector
== priv
->connectors
[i
])
110 ret
= tilcdc_add_external_encoder(dev
, connector
);
118 void tilcdc_remove_external_encoders(struct drm_device
*dev
)
120 struct tilcdc_drm_private
*priv
= dev
->dev_private
;
123 /* Restore the original helper functions, if any. */
124 for (i
= 0; i
< priv
->num_connectors
; i
++)
125 if (IS_ERR(priv
->connector_funcs
[i
]))
126 drm_connector_helper_add(priv
->connectors
[i
], NULL
);
127 else if (priv
->connector_funcs
[i
])
128 drm_connector_helper_add(priv
->connectors
[i
],
129 priv
->connector_funcs
[i
]);
132 static int dev_match_of(struct device
*dev
, void *data
)
134 return dev
->of_node
== data
;
137 int tilcdc_get_external_components(struct device
*dev
,
138 struct component_match
**match
)
140 struct device_node
*node
;
141 struct device_node
*ep
= NULL
;
144 /* Avoid error print by of_graph_get_next_endpoint() if there
145 * is no ports present.
147 node
= of_get_child_by_name(dev
->of_node
, "ports");
149 node
= of_get_child_by_name(dev
->of_node
, "port");
154 while ((ep
= of_graph_get_next_endpoint(dev
->of_node
, ep
))) {
155 node
= of_graph_get_remote_port_parent(ep
);
156 if (!node
|| !of_device_is_available(node
)) {
161 dev_dbg(dev
, "Subdevice node '%s' found\n", node
->name
);
163 component_match_add(dev
, match
, dev_match_of
, node
);
169 dev_err(dev
, "Only one external encoder is supported\n");