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 output->panel = of_drm_find_panel(panel); 121 of_node_put(panel); 122 123 if (IS_ERR(output->panel)) 124 return PTR_ERR(output->panel); 125 } 126 127 ddc = of_parse_phandle(output->of_node, "nvidia,ddc-i2c-bus", 0); 128 if (ddc) { 129 output->ddc = of_get_i2c_adapter_by_node(ddc); 130 of_node_put(ddc); 131 132 if (!output->ddc) { 133 err = -EPROBE_DEFER; 134 return err; 135 } 136 } 137 138 edid = of_get_property(output->of_node, "nvidia,edid", &size); 139 output->drm_edid = drm_edid_alloc(edid, size); 140 141 output->hpd_gpio = devm_fwnode_gpiod_get(output->dev, 142 of_fwnode_handle(output->of_node), 143 "nvidia,hpd", 144 GPIOD_IN, 145 "HDMI hotplug detect"); 146 if (IS_ERR(output->hpd_gpio)) { 147 if (PTR_ERR(output->hpd_gpio) != -ENOENT) { 148 err = PTR_ERR(output->hpd_gpio); 149 goto put_i2c; 150 } 151 152 output->hpd_gpio = NULL; 153 } 154 155 if (output->hpd_gpio) { 156 err = gpiod_to_irq(output->hpd_gpio); 157 if (err < 0) { 158 dev_err(output->dev, "gpiod_to_irq(): %d\n", err); 159 goto put_i2c; 160 } 161 162 output->hpd_irq = err; 163 164 flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | 165 IRQF_ONESHOT; 166 167 err = request_threaded_irq(output->hpd_irq, NULL, hpd_irq, 168 flags, "hpd", output); 169 if (err < 0) { 170 dev_err(output->dev, "failed to request IRQ#%u: %d\n", 171 output->hpd_irq, err); 172 goto put_i2c; 173 } 174 175 output->connector.polled = DRM_CONNECTOR_POLL_HPD; 176 177 /* 178 * Disable the interrupt until the connector has been 179 * initialized to avoid a race in the hotplug interrupt 180 * handler. 181 */ 182 disable_irq(output->hpd_irq); 183 } 184 185 return 0; 186 187 put_i2c: 188 if (output->ddc) 189 i2c_put_adapter(output->ddc); 190 191 drm_edid_free(output->drm_edid); 192 193 return err; 194 } 195 196 void tegra_output_remove(struct tegra_output *output) 197 { 198 if (output->hpd_gpio) 199 free_irq(output->hpd_irq, output); 200 201 if (output->ddc) 202 i2c_put_adapter(output->ddc); 203 204 drm_edid_free(output->drm_edid); 205 } 206 207 int tegra_output_init(struct drm_device *drm, struct tegra_output *output) 208 { 209 int connector_type; 210 211 /* 212 * The connector is now registered and ready to receive hotplug events 213 * so the hotplug interrupt can be enabled. 214 */ 215 if (output->hpd_gpio) 216 enable_irq(output->hpd_irq); 217 218 connector_type = output->connector.connector_type; 219 /* 220 * Create a CEC notifier for HDMI connector. 221 */ 222 if (connector_type == DRM_MODE_CONNECTOR_HDMIA || 223 connector_type == DRM_MODE_CONNECTOR_HDMIB) { 224 struct cec_connector_info conn_info; 225 226 cec_fill_conn_info_from_drm(&conn_info, &output->connector); 227 output->cec = cec_notifier_conn_register(output->dev, NULL, 228 &conn_info); 229 if (!output->cec) 230 return -ENOMEM; 231 } 232 233 return 0; 234 } 235 236 void tegra_output_exit(struct tegra_output *output) 237 { 238 /* 239 * The connector is going away, so the interrupt must be disabled to 240 * prevent the hotplug interrupt handler from potentially crashing. 241 */ 242 if (output->hpd_gpio) 243 disable_irq(output->hpd_irq); 244 } 245 246 void tegra_output_find_possible_crtcs(struct tegra_output *output, 247 struct drm_device *drm) 248 { 249 struct device *dev = output->dev; 250 struct drm_crtc *crtc; 251 unsigned int mask = 0; 252 253 drm_for_each_crtc(crtc, drm) { 254 struct tegra_dc *dc = to_tegra_dc(crtc); 255 256 if (tegra_dc_has_output(dc, dev)) 257 mask |= drm_crtc_mask(crtc); 258 } 259 260 if (mask == 0) { 261 dev_warn(dev, "missing output definition for heads in DT\n"); 262 mask = 0x3; 263 } 264 265 output->encoder.possible_crtcs = mask; 266 } 267 268 int tegra_output_suspend(struct tegra_output *output) 269 { 270 if (output->hpd_irq) 271 disable_irq(output->hpd_irq); 272 273 return 0; 274 } 275 276 int tegra_output_resume(struct tegra_output *output) 277 { 278 if (output->hpd_irq) 279 enable_irq(output->hpd_irq); 280 281 return 0; 282 } 283