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