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_of.h> 12 #include <drm/drm_panel.h> 13 #include <drm/drm_simple_kms_helper.h> 14 15 #include "drm.h" 16 #include "dc.h" 17 18 #include <media/cec-notifier.h> 19 20 int tegra_output_connector_get_modes(struct drm_connector *connector) 21 { 22 struct tegra_output *output = connector_to_output(connector); 23 struct edid *edid = NULL; 24 int err = 0; 25 26 /* 27 * If the panel provides one or more modes, use them exclusively and 28 * ignore any other means of obtaining a mode. 29 */ 30 if (output->panel) { 31 err = drm_panel_get_modes(output->panel, connector); 32 if (err > 0) 33 return err; 34 } 35 36 if (output->edid) 37 edid = kmemdup(output->edid, sizeof(*edid), GFP_KERNEL); 38 else if (output->ddc) 39 edid = drm_get_edid(connector, output->ddc); 40 41 cec_notifier_set_phys_addr_from_edid(output->cec, edid); 42 drm_connector_update_edid_property(connector, edid); 43 44 if (edid) { 45 err = drm_add_edid_modes(connector, edid); 46 kfree(edid); 47 } 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 unsigned long flags; 101 int err, size; 102 103 if (!output->of_node) 104 output->of_node = output->dev->of_node; 105 106 err = drm_of_find_panel_or_bridge(output->of_node, -1, -1, 107 &output->panel, &output->bridge); 108 if (err && err != -ENODEV) 109 return err; 110 111 panel = of_parse_phandle(output->of_node, "nvidia,panel", 0); 112 if (panel) { 113 /* 114 * Don't mix nvidia,panel phandle with the graph in a 115 * device-tree. 116 */ 117 WARN_ON(output->panel || output->bridge); 118 119 output->panel = of_drm_find_panel(panel); 120 of_node_put(panel); 121 122 if (IS_ERR(output->panel)) 123 return PTR_ERR(output->panel); 124 } 125 126 output->edid = of_get_property(output->of_node, "nvidia,edid", &size); 127 128 ddc = of_parse_phandle(output->of_node, "nvidia,ddc-i2c-bus", 0); 129 if (ddc) { 130 output->ddc = of_get_i2c_adapter_by_node(ddc); 131 of_node_put(ddc); 132 133 if (!output->ddc) { 134 err = -EPROBE_DEFER; 135 return err; 136 } 137 } 138 139 output->hpd_gpio = devm_fwnode_gpiod_get(output->dev, 140 of_fwnode_handle(output->of_node), 141 "nvidia,hpd", 142 GPIOD_IN, 143 "HDMI hotplug detect"); 144 if (IS_ERR(output->hpd_gpio)) { 145 if (PTR_ERR(output->hpd_gpio) != -ENOENT) 146 return PTR_ERR(output->hpd_gpio); 147 148 output->hpd_gpio = NULL; 149 } 150 151 if (output->hpd_gpio) { 152 err = gpiod_to_irq(output->hpd_gpio); 153 if (err < 0) { 154 dev_err(output->dev, "gpiod_to_irq(): %d\n", err); 155 return err; 156 } 157 158 output->hpd_irq = err; 159 160 flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | 161 IRQF_ONESHOT; 162 163 err = request_threaded_irq(output->hpd_irq, NULL, hpd_irq, 164 flags, "hpd", output); 165 if (err < 0) { 166 dev_err(output->dev, "failed to request IRQ#%u: %d\n", 167 output->hpd_irq, err); 168 return err; 169 } 170 171 output->connector.polled = DRM_CONNECTOR_POLL_HPD; 172 173 /* 174 * Disable the interrupt until the connector has been 175 * initialized to avoid a race in the hotplug interrupt 176 * handler. 177 */ 178 disable_irq(output->hpd_irq); 179 } 180 181 return 0; 182 } 183 184 void tegra_output_remove(struct tegra_output *output) 185 { 186 if (output->hpd_gpio) 187 free_irq(output->hpd_irq, output); 188 189 if (output->ddc) 190 i2c_put_adapter(output->ddc); 191 } 192 193 int tegra_output_init(struct drm_device *drm, struct tegra_output *output) 194 { 195 int connector_type; 196 197 /* 198 * The connector is now registered and ready to receive hotplug events 199 * so the hotplug interrupt can be enabled. 200 */ 201 if (output->hpd_gpio) 202 enable_irq(output->hpd_irq); 203 204 connector_type = output->connector.connector_type; 205 /* 206 * Create a CEC notifier for HDMI connector. 207 */ 208 if (connector_type == DRM_MODE_CONNECTOR_HDMIA || 209 connector_type == DRM_MODE_CONNECTOR_HDMIB) { 210 struct cec_connector_info conn_info; 211 212 cec_fill_conn_info_from_drm(&conn_info, &output->connector); 213 output->cec = cec_notifier_conn_register(output->dev, NULL, 214 &conn_info); 215 if (!output->cec) 216 return -ENOMEM; 217 } 218 219 return 0; 220 } 221 222 void tegra_output_exit(struct tegra_output *output) 223 { 224 /* 225 * The connector is going away, so the interrupt must be disabled to 226 * prevent the hotplug interrupt handler from potentially crashing. 227 */ 228 if (output->hpd_gpio) 229 disable_irq(output->hpd_irq); 230 } 231 232 void tegra_output_find_possible_crtcs(struct tegra_output *output, 233 struct drm_device *drm) 234 { 235 struct device *dev = output->dev; 236 struct drm_crtc *crtc; 237 unsigned int mask = 0; 238 239 drm_for_each_crtc(crtc, drm) { 240 struct tegra_dc *dc = to_tegra_dc(crtc); 241 242 if (tegra_dc_has_output(dc, dev)) 243 mask |= drm_crtc_mask(crtc); 244 } 245 246 if (mask == 0) { 247 dev_warn(dev, "missing output definition for heads in DT\n"); 248 mask = 0x3; 249 } 250 251 output->encoder.possible_crtcs = mask; 252 } 253 254 int tegra_output_suspend(struct tegra_output *output) 255 { 256 if (output->hpd_irq) 257 disable_irq(output->hpd_irq); 258 259 return 0; 260 } 261 262 int tegra_output_resume(struct tegra_output *output) 263 { 264 if (output->hpd_irq) 265 enable_irq(output->hpd_irq); 266 267 return 0; 268 } 269