1 /* 2 * Copyright (C) 2012 Avionic Design GmbH 3 * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. 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 10 #include <drm/drm_atomic_helper.h> 11 #include <drm/drm_panel.h> 12 13 #include "drm.h" 14 #include "dc.h" 15 16 #include <media/cec-notifier.h> 17 18 int tegra_output_connector_get_modes(struct drm_connector *connector) 19 { 20 struct tegra_output *output = connector_to_output(connector); 21 struct edid *edid = NULL; 22 int err = 0; 23 24 /* 25 * If the panel provides one or more modes, use them exclusively and 26 * ignore any other means of obtaining a mode. 27 */ 28 if (output->panel) { 29 err = output->panel->funcs->get_modes(output->panel); 30 if (err > 0) 31 return err; 32 } 33 34 if (output->edid) 35 edid = kmemdup(output->edid, sizeof(*edid), GFP_KERNEL); 36 else if (output->ddc) 37 edid = drm_get_edid(connector, output->ddc); 38 39 cec_notifier_set_phys_addr_from_edid(output->cec, edid); 40 drm_connector_update_edid_property(connector, edid); 41 42 if (edid) { 43 err = drm_add_edid_modes(connector, edid); 44 kfree(edid); 45 } 46 47 return err; 48 } 49 50 enum drm_connector_status 51 tegra_output_connector_detect(struct drm_connector *connector, bool force) 52 { 53 struct tegra_output *output = connector_to_output(connector); 54 enum drm_connector_status status = connector_status_unknown; 55 56 if (output->hpd_gpio) { 57 if (gpiod_get_value(output->hpd_gpio) == 0) 58 status = connector_status_disconnected; 59 else 60 status = connector_status_connected; 61 } else { 62 if (!output->panel) 63 status = connector_status_disconnected; 64 else 65 status = connector_status_connected; 66 } 67 68 if (status != connector_status_connected) 69 cec_notifier_phys_addr_invalidate(output->cec); 70 71 return status; 72 } 73 74 void tegra_output_connector_destroy(struct drm_connector *connector) 75 { 76 drm_connector_unregister(connector); 77 drm_connector_cleanup(connector); 78 } 79 80 void tegra_output_encoder_destroy(struct drm_encoder *encoder) 81 { 82 drm_encoder_cleanup(encoder); 83 } 84 85 static irqreturn_t hpd_irq(int irq, void *data) 86 { 87 struct tegra_output *output = data; 88 89 if (output->connector.dev) 90 drm_helper_hpd_irq_event(output->connector.dev); 91 92 return IRQ_HANDLED; 93 } 94 95 int tegra_output_probe(struct tegra_output *output) 96 { 97 struct device_node *ddc, *panel; 98 unsigned long flags; 99 int err, size; 100 101 if (!output->of_node) 102 output->of_node = output->dev->of_node; 103 104 panel = of_parse_phandle(output->of_node, "nvidia,panel", 0); 105 if (panel) { 106 output->panel = of_drm_find_panel(panel); 107 if (IS_ERR(output->panel)) 108 return PTR_ERR(output->panel); 109 110 of_node_put(panel); 111 } 112 113 output->edid = of_get_property(output->of_node, "nvidia,edid", &size); 114 115 ddc = of_parse_phandle(output->of_node, "nvidia,ddc-i2c-bus", 0); 116 if (ddc) { 117 output->ddc = of_find_i2c_adapter_by_node(ddc); 118 if (!output->ddc) { 119 err = -EPROBE_DEFER; 120 of_node_put(ddc); 121 return err; 122 } 123 124 of_node_put(ddc); 125 } 126 127 output->hpd_gpio = devm_gpiod_get_from_of_node(output->dev, 128 output->of_node, 129 "nvidia,hpd-gpio", 0, 130 GPIOD_IN, 131 "HDMI hotplug detect"); 132 if (IS_ERR(output->hpd_gpio)) 133 return PTR_ERR(output->hpd_gpio); 134 135 if (output->hpd_gpio) { 136 err = gpiod_to_irq(output->hpd_gpio); 137 if (err < 0) { 138 dev_err(output->dev, "gpiod_to_irq(): %d\n", err); 139 return err; 140 } 141 142 output->hpd_irq = err; 143 144 flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | 145 IRQF_ONESHOT; 146 147 err = request_threaded_irq(output->hpd_irq, NULL, hpd_irq, 148 flags, "hpd", output); 149 if (err < 0) { 150 dev_err(output->dev, "failed to request IRQ#%u: %d\n", 151 output->hpd_irq, err); 152 return err; 153 } 154 155 output->connector.polled = DRM_CONNECTOR_POLL_HPD; 156 157 /* 158 * Disable the interrupt until the connector has been 159 * initialized to avoid a race in the hotplug interrupt 160 * handler. 161 */ 162 disable_irq(output->hpd_irq); 163 } 164 165 output->cec = cec_notifier_get(output->dev); 166 if (!output->cec) 167 return -ENOMEM; 168 169 return 0; 170 } 171 172 void tegra_output_remove(struct tegra_output *output) 173 { 174 if (output->cec) 175 cec_notifier_put(output->cec); 176 177 if (output->hpd_gpio) 178 free_irq(output->hpd_irq, output); 179 180 if (output->ddc) 181 put_device(&output->ddc->dev); 182 } 183 184 int tegra_output_init(struct drm_device *drm, struct tegra_output *output) 185 { 186 int err; 187 188 if (output->panel) { 189 err = drm_panel_attach(output->panel, &output->connector); 190 if (err < 0) 191 return err; 192 } 193 194 /* 195 * The connector is now registered and ready to receive hotplug events 196 * so the hotplug interrupt can be enabled. 197 */ 198 if (output->hpd_gpio) 199 enable_irq(output->hpd_irq); 200 201 return 0; 202 } 203 204 void tegra_output_exit(struct tegra_output *output) 205 { 206 /* 207 * The connector is going away, so the interrupt must be disabled to 208 * prevent the hotplug interrupt handler from potentially crashing. 209 */ 210 if (output->hpd_gpio) 211 disable_irq(output->hpd_irq); 212 213 if (output->panel) 214 drm_panel_detach(output->panel); 215 } 216 217 void tegra_output_find_possible_crtcs(struct tegra_output *output, 218 struct drm_device *drm) 219 { 220 struct device *dev = output->dev; 221 struct drm_crtc *crtc; 222 unsigned int mask = 0; 223 224 drm_for_each_crtc(crtc, drm) { 225 struct tegra_dc *dc = to_tegra_dc(crtc); 226 227 if (tegra_dc_has_output(dc, dev)) 228 mask |= drm_crtc_mask(crtc); 229 } 230 231 if (mask == 0) { 232 dev_warn(dev, "missing output definition for heads in DT\n"); 233 mask = 0x3; 234 } 235 236 output->encoder.possible_crtcs = mask; 237 } 238