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 #include "drm.h" 13 14 int tegra_output_connector_get_modes(struct drm_connector *connector) 15 { 16 struct tegra_output *output = connector_to_output(connector); 17 struct edid *edid = NULL; 18 int err = 0; 19 20 /* 21 * If the panel provides one or more modes, use them exclusively and 22 * ignore any other means of obtaining a mode. 23 */ 24 if (output->panel) { 25 err = output->panel->funcs->get_modes(output->panel); 26 if (err > 0) 27 return err; 28 } 29 30 if (output->edid) 31 edid = kmemdup(output->edid, sizeof(*edid), GFP_KERNEL); 32 else if (output->ddc) 33 edid = drm_get_edid(connector, output->ddc); 34 35 drm_mode_connector_update_edid_property(connector, edid); 36 37 if (edid) { 38 err = drm_add_edid_modes(connector, edid); 39 drm_edid_to_eld(connector, edid); 40 kfree(edid); 41 } 42 43 return err; 44 } 45 46 enum drm_connector_status 47 tegra_output_connector_detect(struct drm_connector *connector, bool force) 48 { 49 struct tegra_output *output = connector_to_output(connector); 50 enum drm_connector_status status = connector_status_unknown; 51 52 if (gpio_is_valid(output->hpd_gpio)) { 53 if (output->hpd_gpio_flags & OF_GPIO_ACTIVE_LOW) { 54 if (gpio_get_value(output->hpd_gpio) != 0) 55 status = connector_status_disconnected; 56 else 57 status = connector_status_connected; 58 } else { 59 if (gpio_get_value(output->hpd_gpio) == 0) 60 status = connector_status_disconnected; 61 else 62 status = connector_status_connected; 63 } 64 } else { 65 if (!output->panel) 66 status = connector_status_disconnected; 67 else 68 status = connector_status_connected; 69 } 70 71 return status; 72 } 73 74 void tegra_output_connector_destroy(struct drm_connector *connector) 75 { 76 drm_connector_unregister(connector); 77 drm_connector_cleanup(connector); 78 } 79 80 void tegra_output_encoder_destroy(struct drm_encoder *encoder) 81 { 82 drm_encoder_cleanup(encoder); 83 } 84 85 static irqreturn_t hpd_irq(int irq, void *data) 86 { 87 struct tegra_output *output = data; 88 89 if (output->connector.dev) 90 drm_helper_hpd_irq_event(output->connector.dev); 91 92 return IRQ_HANDLED; 93 } 94 95 int tegra_output_probe(struct tegra_output *output) 96 { 97 struct device_node *ddc, *panel; 98 int err, size; 99 100 if (!output->of_node) 101 output->of_node = output->dev->of_node; 102 103 panel = of_parse_phandle(output->of_node, "nvidia,panel", 0); 104 if (panel) { 105 output->panel = of_drm_find_panel(panel); 106 if (!output->panel) 107 return -EPROBE_DEFER; 108 109 of_node_put(panel); 110 } 111 112 output->edid = of_get_property(output->of_node, "nvidia,edid", &size); 113 114 ddc = of_parse_phandle(output->of_node, "nvidia,ddc-i2c-bus", 0); 115 if (ddc) { 116 output->ddc = of_find_i2c_adapter_by_node(ddc); 117 if (!output->ddc) { 118 err = -EPROBE_DEFER; 119 of_node_put(ddc); 120 return err; 121 } 122 123 of_node_put(ddc); 124 } 125 126 output->hpd_gpio = of_get_named_gpio_flags(output->of_node, 127 "nvidia,hpd-gpio", 0, 128 &output->hpd_gpio_flags); 129 if (gpio_is_valid(output->hpd_gpio)) { 130 unsigned long flags; 131 132 err = gpio_request_one(output->hpd_gpio, GPIOF_DIR_IN, 133 "HDMI hotplug detect"); 134 if (err < 0) { 135 dev_err(output->dev, "gpio_request_one(): %d\n", err); 136 return err; 137 } 138 139 err = gpio_to_irq(output->hpd_gpio); 140 if (err < 0) { 141 dev_err(output->dev, "gpio_to_irq(): %d\n", err); 142 gpio_free(output->hpd_gpio); 143 return err; 144 } 145 146 output->hpd_irq = err; 147 148 flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | 149 IRQF_ONESHOT; 150 151 err = request_threaded_irq(output->hpd_irq, NULL, hpd_irq, 152 flags, "hpd", output); 153 if (err < 0) { 154 dev_err(output->dev, "failed to request IRQ#%u: %d\n", 155 output->hpd_irq, err); 156 gpio_free(output->hpd_gpio); 157 return err; 158 } 159 160 output->connector.polled = DRM_CONNECTOR_POLL_HPD; 161 162 /* 163 * Disable the interrupt until the connector has been 164 * initialized to avoid a race in the hotplug interrupt 165 * handler. 166 */ 167 disable_irq(output->hpd_irq); 168 } 169 170 return 0; 171 } 172 173 void tegra_output_remove(struct tegra_output *output) 174 { 175 if (gpio_is_valid(output->hpd_gpio)) { 176 free_irq(output->hpd_irq, output); 177 gpio_free(output->hpd_gpio); 178 } 179 180 if (output->ddc) 181 put_device(&output->ddc->dev); 182 } 183 184 int tegra_output_init(struct drm_device *drm, struct tegra_output *output) 185 { 186 int err; 187 188 if (output->panel) { 189 err = drm_panel_attach(output->panel, &output->connector); 190 if (err < 0) 191 return err; 192 } 193 194 /* 195 * The connector is now registered and ready to receive hotplug events 196 * so the hotplug interrupt can be enabled. 197 */ 198 if (gpio_is_valid(output->hpd_gpio)) 199 enable_irq(output->hpd_irq); 200 201 return 0; 202 } 203 204 void tegra_output_exit(struct tegra_output *output) 205 { 206 /* 207 * The connector is going away, so the interrupt must be disabled to 208 * prevent the hotplug interrupt handler from potentially crashing. 209 */ 210 if (gpio_is_valid(output->hpd_gpio)) 211 disable_irq(output->hpd_irq); 212 213 if (output->panel) 214 drm_panel_detach(output->panel); 215 } 216