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->notifier, 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 (gpio_is_valid(output->hpd_gpio)) { 57 if (output->hpd_gpio_flags & OF_GPIO_ACTIVE_LOW) { 58 if (gpio_get_value(output->hpd_gpio) != 0) 59 status = connector_status_disconnected; 60 else 61 status = connector_status_connected; 62 } else { 63 if (gpio_get_value(output->hpd_gpio) == 0) 64 status = connector_status_disconnected; 65 else 66 status = connector_status_connected; 67 } 68 } else { 69 if (!output->panel) 70 status = connector_status_disconnected; 71 else 72 status = connector_status_connected; 73 } 74 75 if (status != connector_status_connected) 76 cec_notifier_phys_addr_invalidate(output->notifier); 77 78 return status; 79 } 80 81 void tegra_output_connector_destroy(struct drm_connector *connector) 82 { 83 drm_connector_unregister(connector); 84 drm_connector_cleanup(connector); 85 } 86 87 void tegra_output_encoder_destroy(struct drm_encoder *encoder) 88 { 89 drm_encoder_cleanup(encoder); 90 } 91 92 static irqreturn_t hpd_irq(int irq, void *data) 93 { 94 struct tegra_output *output = data; 95 96 if (output->connector.dev) 97 drm_helper_hpd_irq_event(output->connector.dev); 98 99 return IRQ_HANDLED; 100 } 101 102 int tegra_output_probe(struct tegra_output *output) 103 { 104 struct device_node *ddc, *panel; 105 int err, size; 106 107 if (!output->of_node) 108 output->of_node = output->dev->of_node; 109 110 panel = of_parse_phandle(output->of_node, "nvidia,panel", 0); 111 if (panel) { 112 output->panel = of_drm_find_panel(panel); 113 if (IS_ERR(output->panel)) 114 return PTR_ERR(output->panel); 115 116 of_node_put(panel); 117 } 118 119 output->edid = of_get_property(output->of_node, "nvidia,edid", &size); 120 121 ddc = of_parse_phandle(output->of_node, "nvidia,ddc-i2c-bus", 0); 122 if (ddc) { 123 output->ddc = of_find_i2c_adapter_by_node(ddc); 124 if (!output->ddc) { 125 err = -EPROBE_DEFER; 126 of_node_put(ddc); 127 return err; 128 } 129 130 of_node_put(ddc); 131 } 132 133 output->hpd_gpio = of_get_named_gpio_flags(output->of_node, 134 "nvidia,hpd-gpio", 0, 135 &output->hpd_gpio_flags); 136 if (gpio_is_valid(output->hpd_gpio)) { 137 unsigned long flags; 138 139 err = gpio_request_one(output->hpd_gpio, GPIOF_DIR_IN, 140 "HDMI hotplug detect"); 141 if (err < 0) { 142 dev_err(output->dev, "gpio_request_one(): %d\n", err); 143 return err; 144 } 145 146 err = gpio_to_irq(output->hpd_gpio); 147 if (err < 0) { 148 dev_err(output->dev, "gpio_to_irq(): %d\n", err); 149 gpio_free(output->hpd_gpio); 150 return err; 151 } 152 153 output->hpd_irq = err; 154 155 flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | 156 IRQF_ONESHOT; 157 158 err = request_threaded_irq(output->hpd_irq, NULL, hpd_irq, 159 flags, "hpd", output); 160 if (err < 0) { 161 dev_err(output->dev, "failed to request IRQ#%u: %d\n", 162 output->hpd_irq, err); 163 gpio_free(output->hpd_gpio); 164 return err; 165 } 166 167 output->connector.polled = DRM_CONNECTOR_POLL_HPD; 168 169 /* 170 * Disable the interrupt until the connector has been 171 * initialized to avoid a race in the hotplug interrupt 172 * handler. 173 */ 174 disable_irq(output->hpd_irq); 175 } 176 177 return 0; 178 } 179 180 void tegra_output_remove(struct tegra_output *output) 181 { 182 if (gpio_is_valid(output->hpd_gpio)) { 183 free_irq(output->hpd_irq, output); 184 gpio_free(output->hpd_gpio); 185 } 186 187 if (output->ddc) 188 put_device(&output->ddc->dev); 189 } 190 191 int tegra_output_init(struct drm_device *drm, struct tegra_output *output) 192 { 193 int err; 194 195 if (output->panel) { 196 err = drm_panel_attach(output->panel, &output->connector); 197 if (err < 0) 198 return err; 199 } 200 201 /* 202 * The connector is now registered and ready to receive hotplug events 203 * so the hotplug interrupt can be enabled. 204 */ 205 if (gpio_is_valid(output->hpd_gpio)) 206 enable_irq(output->hpd_irq); 207 208 return 0; 209 } 210 211 void tegra_output_exit(struct tegra_output *output) 212 { 213 /* 214 * The connector is going away, so the interrupt must be disabled to 215 * prevent the hotplug interrupt handler from potentially crashing. 216 */ 217 if (gpio_is_valid(output->hpd_gpio)) 218 disable_irq(output->hpd_irq); 219 220 if (output->panel) 221 drm_panel_detach(output->panel); 222 } 223 224 void tegra_output_find_possible_crtcs(struct tegra_output *output, 225 struct drm_device *drm) 226 { 227 struct device *dev = output->dev; 228 struct drm_crtc *crtc; 229 unsigned int mask = 0; 230 231 drm_for_each_crtc(crtc, drm) { 232 struct tegra_dc *dc = to_tegra_dc(crtc); 233 234 if (tegra_dc_has_output(dc, dev)) 235 mask |= drm_crtc_mask(crtc); 236 } 237 238 if (mask == 0) { 239 dev_warn(dev, "missing output definition for heads in DT\n"); 240 mask = 0x3; 241 } 242 243 output->encoder.possible_crtcs = mask; 244 } 245