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