0001
0002
0003
0004
0005
0006
0007 #include <drm/drm_atomic_helper.h>
0008 #include <drm/drm_of.h>
0009 #include <drm/drm_panel.h>
0010 #include <drm/drm_simple_kms_helper.h>
0011
0012 #include "drm.h"
0013 #include "dc.h"
0014
0015 #include <media/cec-notifier.h>
0016
0017 int tegra_output_connector_get_modes(struct drm_connector *connector)
0018 {
0019 struct tegra_output *output = connector_to_output(connector);
0020 struct edid *edid = NULL;
0021 int err = 0;
0022
0023
0024
0025
0026
0027 if (output->panel) {
0028 err = drm_panel_get_modes(output->panel, connector);
0029 if (err > 0)
0030 return err;
0031 }
0032
0033 if (output->edid)
0034 edid = kmemdup(output->edid, sizeof(*edid), GFP_KERNEL);
0035 else if (output->ddc)
0036 edid = drm_get_edid(connector, output->ddc);
0037
0038 cec_notifier_set_phys_addr_from_edid(output->cec, edid);
0039 drm_connector_update_edid_property(connector, edid);
0040
0041 if (edid) {
0042 err = drm_add_edid_modes(connector, edid);
0043 kfree(edid);
0044 }
0045
0046 return err;
0047 }
0048
0049 enum drm_connector_status
0050 tegra_output_connector_detect(struct drm_connector *connector, bool force)
0051 {
0052 struct tegra_output *output = connector_to_output(connector);
0053 enum drm_connector_status status = connector_status_unknown;
0054
0055 if (output->hpd_gpio) {
0056 if (gpiod_get_value(output->hpd_gpio) == 0)
0057 status = connector_status_disconnected;
0058 else
0059 status = connector_status_connected;
0060 } else {
0061 if (!output->panel)
0062 status = connector_status_disconnected;
0063 else
0064 status = connector_status_connected;
0065 }
0066
0067 if (status != connector_status_connected)
0068 cec_notifier_phys_addr_invalidate(output->cec);
0069
0070 return status;
0071 }
0072
0073 void tegra_output_connector_destroy(struct drm_connector *connector)
0074 {
0075 struct tegra_output *output = connector_to_output(connector);
0076
0077 if (output->cec)
0078 cec_notifier_conn_unregister(output->cec);
0079
0080 drm_connector_unregister(connector);
0081 drm_connector_cleanup(connector);
0082 }
0083
0084 static irqreturn_t hpd_irq(int irq, void *data)
0085 {
0086 struct tegra_output *output = data;
0087
0088 if (output->connector.dev)
0089 drm_helper_hpd_irq_event(output->connector.dev);
0090
0091 return IRQ_HANDLED;
0092 }
0093
0094 int tegra_output_probe(struct tegra_output *output)
0095 {
0096 struct device_node *ddc, *panel;
0097 unsigned long flags;
0098 int err, size;
0099
0100 if (!output->of_node)
0101 output->of_node = output->dev->of_node;
0102
0103 err = drm_of_find_panel_or_bridge(output->of_node, -1, -1,
0104 &output->panel, &output->bridge);
0105 if (err && err != -ENODEV)
0106 return err;
0107
0108 panel = of_parse_phandle(output->of_node, "nvidia,panel", 0);
0109 if (panel) {
0110
0111
0112
0113
0114 WARN_ON(output->panel || output->bridge);
0115
0116 output->panel = of_drm_find_panel(panel);
0117 of_node_put(panel);
0118
0119 if (IS_ERR(output->panel))
0120 return PTR_ERR(output->panel);
0121 }
0122
0123 output->edid = of_get_property(output->of_node, "nvidia,edid", &size);
0124
0125 ddc = of_parse_phandle(output->of_node, "nvidia,ddc-i2c-bus", 0);
0126 if (ddc) {
0127 output->ddc = of_get_i2c_adapter_by_node(ddc);
0128 of_node_put(ddc);
0129
0130 if (!output->ddc) {
0131 err = -EPROBE_DEFER;
0132 return err;
0133 }
0134 }
0135
0136 output->hpd_gpio = devm_gpiod_get_from_of_node(output->dev,
0137 output->of_node,
0138 "nvidia,hpd-gpio", 0,
0139 GPIOD_IN,
0140 "HDMI hotplug detect");
0141 if (IS_ERR(output->hpd_gpio)) {
0142 if (PTR_ERR(output->hpd_gpio) != -ENOENT)
0143 return PTR_ERR(output->hpd_gpio);
0144
0145 output->hpd_gpio = NULL;
0146 }
0147
0148 if (output->hpd_gpio) {
0149 err = gpiod_to_irq(output->hpd_gpio);
0150 if (err < 0) {
0151 dev_err(output->dev, "gpiod_to_irq(): %d\n", err);
0152 return err;
0153 }
0154
0155 output->hpd_irq = err;
0156
0157 flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
0158 IRQF_ONESHOT;
0159
0160 err = request_threaded_irq(output->hpd_irq, NULL, hpd_irq,
0161 flags, "hpd", output);
0162 if (err < 0) {
0163 dev_err(output->dev, "failed to request IRQ#%u: %d\n",
0164 output->hpd_irq, err);
0165 return err;
0166 }
0167
0168 output->connector.polled = DRM_CONNECTOR_POLL_HPD;
0169
0170
0171
0172
0173
0174
0175 disable_irq(output->hpd_irq);
0176 }
0177
0178 return 0;
0179 }
0180
0181 void tegra_output_remove(struct tegra_output *output)
0182 {
0183 if (output->hpd_gpio)
0184 free_irq(output->hpd_irq, output);
0185
0186 if (output->ddc)
0187 i2c_put_adapter(output->ddc);
0188 }
0189
0190 int tegra_output_init(struct drm_device *drm, struct tegra_output *output)
0191 {
0192 int connector_type;
0193
0194
0195
0196
0197
0198 if (output->hpd_gpio)
0199 enable_irq(output->hpd_irq);
0200
0201 connector_type = output->connector.connector_type;
0202
0203
0204
0205 if (connector_type == DRM_MODE_CONNECTOR_HDMIA ||
0206 connector_type == DRM_MODE_CONNECTOR_HDMIB) {
0207 struct cec_connector_info conn_info;
0208
0209 cec_fill_conn_info_from_drm(&conn_info, &output->connector);
0210 output->cec = cec_notifier_conn_register(output->dev, NULL,
0211 &conn_info);
0212 if (!output->cec)
0213 return -ENOMEM;
0214 }
0215
0216 return 0;
0217 }
0218
0219 void tegra_output_exit(struct tegra_output *output)
0220 {
0221
0222
0223
0224
0225 if (output->hpd_gpio)
0226 disable_irq(output->hpd_irq);
0227 }
0228
0229 void tegra_output_find_possible_crtcs(struct tegra_output *output,
0230 struct drm_device *drm)
0231 {
0232 struct device *dev = output->dev;
0233 struct drm_crtc *crtc;
0234 unsigned int mask = 0;
0235
0236 drm_for_each_crtc(crtc, drm) {
0237 struct tegra_dc *dc = to_tegra_dc(crtc);
0238
0239 if (tegra_dc_has_output(dc, dev))
0240 mask |= drm_crtc_mask(crtc);
0241 }
0242
0243 if (mask == 0) {
0244 dev_warn(dev, "missing output definition for heads in DT\n");
0245 mask = 0x3;
0246 }
0247
0248 output->encoder.possible_crtcs = mask;
0249 }
0250
0251 int tegra_output_suspend(struct tegra_output *output)
0252 {
0253 if (output->hpd_irq)
0254 disable_irq(output->hpd_irq);
0255
0256 return 0;
0257 }
0258
0259 int tegra_output_resume(struct tegra_output *output)
0260 {
0261 if (output->hpd_irq)
0262 enable_irq(output->hpd_irq);
0263
0264 return 0;
0265 }