1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2013 Red Hat 4 * Author: Rob Clark <robdclark@gmail.com> 5 */ 6 7 #include <linux/delay.h> 8 #include <linux/gpio/consumer.h> 9 #include <linux/pinctrl/consumer.h> 10 11 #include "msm_kms.h" 12 #include "hdmi.h" 13 14 static void msm_hdmi_phy_reset(struct hdmi *hdmi) 15 { 16 unsigned int val; 17 18 val = hdmi_read(hdmi, REG_HDMI_PHY_CTRL); 19 20 if (val & HDMI_PHY_CTRL_SW_RESET_LOW) { 21 /* pull low */ 22 hdmi_write(hdmi, REG_HDMI_PHY_CTRL, 23 val & ~HDMI_PHY_CTRL_SW_RESET); 24 } else { 25 /* pull high */ 26 hdmi_write(hdmi, REG_HDMI_PHY_CTRL, 27 val | HDMI_PHY_CTRL_SW_RESET); 28 } 29 30 if (val & HDMI_PHY_CTRL_SW_RESET_PLL_LOW) { 31 /* pull low */ 32 hdmi_write(hdmi, REG_HDMI_PHY_CTRL, 33 val & ~HDMI_PHY_CTRL_SW_RESET_PLL); 34 } else { 35 /* pull high */ 36 hdmi_write(hdmi, REG_HDMI_PHY_CTRL, 37 val | HDMI_PHY_CTRL_SW_RESET_PLL); 38 } 39 40 msleep(100); 41 42 if (val & HDMI_PHY_CTRL_SW_RESET_LOW) { 43 /* pull high */ 44 hdmi_write(hdmi, REG_HDMI_PHY_CTRL, 45 val | HDMI_PHY_CTRL_SW_RESET); 46 } else { 47 /* pull low */ 48 hdmi_write(hdmi, REG_HDMI_PHY_CTRL, 49 val & ~HDMI_PHY_CTRL_SW_RESET); 50 } 51 52 if (val & HDMI_PHY_CTRL_SW_RESET_PLL_LOW) { 53 /* pull high */ 54 hdmi_write(hdmi, REG_HDMI_PHY_CTRL, 55 val | HDMI_PHY_CTRL_SW_RESET_PLL); 56 } else { 57 /* pull low */ 58 hdmi_write(hdmi, REG_HDMI_PHY_CTRL, 59 val & ~HDMI_PHY_CTRL_SW_RESET_PLL); 60 } 61 } 62 63 static void enable_hpd_clocks(struct hdmi *hdmi, bool enable) 64 { 65 const struct hdmi_platform_config *config = hdmi->config; 66 struct device *dev = &hdmi->pdev->dev; 67 int i, ret; 68 69 if (enable) { 70 for (i = 0; i < config->hpd_clk_cnt; i++) { 71 if (config->hpd_freq && config->hpd_freq[i]) { 72 ret = clk_set_rate(hdmi->hpd_clks[i], 73 config->hpd_freq[i]); 74 if (ret) 75 dev_warn(dev, 76 "failed to set clk %s (%d)\n", 77 config->hpd_clk_names[i], ret); 78 } 79 80 ret = clk_prepare_enable(hdmi->hpd_clks[i]); 81 if (ret) { 82 DRM_DEV_ERROR(dev, 83 "failed to enable hpd clk: %s (%d)\n", 84 config->hpd_clk_names[i], ret); 85 } 86 } 87 } else { 88 for (i = config->hpd_clk_cnt - 1; i >= 0; i--) 89 clk_disable_unprepare(hdmi->hpd_clks[i]); 90 } 91 } 92 93 int msm_hdmi_hpd_enable(struct drm_bridge *bridge) 94 { 95 struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge); 96 struct hdmi *hdmi = hdmi_bridge->hdmi; 97 const struct hdmi_platform_config *config = hdmi->config; 98 struct device *dev = &hdmi->pdev->dev; 99 uint32_t hpd_ctrl; 100 int ret; 101 unsigned long flags; 102 103 ret = regulator_bulk_enable(config->hpd_reg_cnt, hdmi->hpd_regs); 104 if (ret) { 105 DRM_DEV_ERROR(dev, "failed to enable hpd regulators: %d\n", ret); 106 goto fail; 107 } 108 109 ret = pinctrl_pm_select_default_state(dev); 110 if (ret) { 111 DRM_DEV_ERROR(dev, "pinctrl state chg failed: %d\n", ret); 112 goto fail; 113 } 114 115 if (hdmi->hpd_gpiod) 116 gpiod_set_value_cansleep(hdmi->hpd_gpiod, 1); 117 118 pm_runtime_get_sync(dev); 119 enable_hpd_clocks(hdmi, true); 120 121 msm_hdmi_set_mode(hdmi, false); 122 msm_hdmi_phy_reset(hdmi); 123 msm_hdmi_set_mode(hdmi, true); 124 125 hdmi_write(hdmi, REG_HDMI_USEC_REFTIMER, 0x0001001b); 126 127 /* enable HPD events: */ 128 hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, 129 HDMI_HPD_INT_CTRL_INT_CONNECT | 130 HDMI_HPD_INT_CTRL_INT_EN); 131 132 /* set timeout to 4.1ms (max) for hardware debounce */ 133 spin_lock_irqsave(&hdmi->reg_lock, flags); 134 hpd_ctrl = hdmi_read(hdmi, REG_HDMI_HPD_CTRL); 135 hpd_ctrl |= HDMI_HPD_CTRL_TIMEOUT(0x1fff); 136 137 /* Toggle HPD circuit to trigger HPD sense */ 138 hdmi_write(hdmi, REG_HDMI_HPD_CTRL, 139 ~HDMI_HPD_CTRL_ENABLE & hpd_ctrl); 140 hdmi_write(hdmi, REG_HDMI_HPD_CTRL, 141 HDMI_HPD_CTRL_ENABLE | hpd_ctrl); 142 spin_unlock_irqrestore(&hdmi->reg_lock, flags); 143 144 return 0; 145 146 fail: 147 return ret; 148 } 149 150 void msm_hdmi_hpd_disable(struct hdmi_bridge *hdmi_bridge) 151 { 152 struct hdmi *hdmi = hdmi_bridge->hdmi; 153 const struct hdmi_platform_config *config = hdmi->config; 154 struct device *dev = &hdmi->pdev->dev; 155 int ret; 156 157 /* Disable HPD interrupt */ 158 hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, 0); 159 160 msm_hdmi_set_mode(hdmi, false); 161 162 enable_hpd_clocks(hdmi, false); 163 pm_runtime_put(dev); 164 165 ret = pinctrl_pm_select_sleep_state(dev); 166 if (ret) 167 dev_warn(dev, "pinctrl state chg failed: %d\n", ret); 168 169 ret = regulator_bulk_disable(config->hpd_reg_cnt, hdmi->hpd_regs); 170 if (ret) 171 dev_warn(dev, "failed to disable hpd regulator: %d\n", ret); 172 } 173 174 void msm_hdmi_hpd_irq(struct drm_bridge *bridge) 175 { 176 struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge); 177 struct hdmi *hdmi = hdmi_bridge->hdmi; 178 uint32_t hpd_int_status, hpd_int_ctrl; 179 180 /* Process HPD: */ 181 hpd_int_status = hdmi_read(hdmi, REG_HDMI_HPD_INT_STATUS); 182 hpd_int_ctrl = hdmi_read(hdmi, REG_HDMI_HPD_INT_CTRL); 183 184 if ((hpd_int_ctrl & HDMI_HPD_INT_CTRL_INT_EN) && 185 (hpd_int_status & HDMI_HPD_INT_STATUS_INT)) { 186 bool detected = !!(hpd_int_status & HDMI_HPD_INT_STATUS_CABLE_DETECTED); 187 188 /* ack & disable (temporarily) HPD events: */ 189 hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, 190 HDMI_HPD_INT_CTRL_INT_ACK); 191 192 DBG("status=%04x, ctrl=%04x", hpd_int_status, hpd_int_ctrl); 193 194 /* detect disconnect if we are connected or visa versa: */ 195 hpd_int_ctrl = HDMI_HPD_INT_CTRL_INT_EN; 196 if (!detected) 197 hpd_int_ctrl |= HDMI_HPD_INT_CTRL_INT_CONNECT; 198 hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, hpd_int_ctrl); 199 200 queue_work(hdmi->workq, &hdmi_bridge->hpd_work); 201 } 202 } 203 204 static enum drm_connector_status detect_reg(struct hdmi *hdmi) 205 { 206 uint32_t hpd_int_status; 207 208 pm_runtime_get_sync(&hdmi->pdev->dev); 209 enable_hpd_clocks(hdmi, true); 210 211 hpd_int_status = hdmi_read(hdmi, REG_HDMI_HPD_INT_STATUS); 212 213 enable_hpd_clocks(hdmi, false); 214 pm_runtime_put(&hdmi->pdev->dev); 215 216 return (hpd_int_status & HDMI_HPD_INT_STATUS_CABLE_DETECTED) ? 217 connector_status_connected : connector_status_disconnected; 218 } 219 220 #define HPD_GPIO_INDEX 2 221 static enum drm_connector_status detect_gpio(struct hdmi *hdmi) 222 { 223 return gpiod_get_value(hdmi->hpd_gpiod) ? 224 connector_status_connected : 225 connector_status_disconnected; 226 } 227 228 enum drm_connector_status msm_hdmi_bridge_detect( 229 struct drm_bridge *bridge) 230 { 231 struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge); 232 struct hdmi *hdmi = hdmi_bridge->hdmi; 233 enum drm_connector_status stat_gpio, stat_reg; 234 int retry = 20; 235 236 /* 237 * some platforms may not have hpd gpio. Rely only on the status 238 * provided by REG_HDMI_HPD_INT_STATUS in this case. 239 */ 240 if (!hdmi->hpd_gpiod) 241 return detect_reg(hdmi); 242 243 do { 244 stat_gpio = detect_gpio(hdmi); 245 stat_reg = detect_reg(hdmi); 246 247 if (stat_gpio == stat_reg) 248 break; 249 250 mdelay(10); 251 } while (--retry); 252 253 /* the status we get from reading gpio seems to be more reliable, 254 * so trust that one the most if we didn't manage to get hdmi and 255 * gpio status to agree: 256 */ 257 if (stat_gpio != stat_reg) { 258 DBG("HDMI_HPD_INT_STATUS tells us: %d", stat_reg); 259 DBG("hpd gpio tells us: %d", stat_gpio); 260 } 261 262 return stat_gpio; 263 } 264