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