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 *hdmi) 151 { 152 const struct hdmi_platform_config *config = hdmi->config; 153 struct device *dev = &hdmi->pdev->dev; 154 int ret; 155 156 /* Disable HPD interrupt */ 157 hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, 0); 158 159 msm_hdmi_set_mode(hdmi, false); 160 161 enable_hpd_clocks(hdmi, false); 162 pm_runtime_put(dev); 163 164 ret = pinctrl_pm_select_sleep_state(dev); 165 if (ret) 166 dev_warn(dev, "pinctrl state chg failed: %d\n", ret); 167 168 ret = regulator_bulk_disable(config->hpd_reg_cnt, hdmi->hpd_regs); 169 if (ret) 170 dev_warn(dev, "failed to disable hpd regulator: %d\n", ret); 171 } 172 173 void msm_hdmi_hpd_irq(struct drm_bridge *bridge) 174 { 175 struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge); 176 struct hdmi *hdmi = hdmi_bridge->hdmi; 177 uint32_t hpd_int_status, hpd_int_ctrl; 178 179 /* Process HPD: */ 180 hpd_int_status = hdmi_read(hdmi, REG_HDMI_HPD_INT_STATUS); 181 hpd_int_ctrl = hdmi_read(hdmi, REG_HDMI_HPD_INT_CTRL); 182 183 if ((hpd_int_ctrl & HDMI_HPD_INT_CTRL_INT_EN) && 184 (hpd_int_status & HDMI_HPD_INT_STATUS_INT)) { 185 bool detected = !!(hpd_int_status & HDMI_HPD_INT_STATUS_CABLE_DETECTED); 186 187 /* ack & disable (temporarily) HPD events: */ 188 hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, 189 HDMI_HPD_INT_CTRL_INT_ACK); 190 191 DBG("status=%04x, ctrl=%04x", hpd_int_status, hpd_int_ctrl); 192 193 /* detect disconnect if we are connected or visa versa: */ 194 hpd_int_ctrl = HDMI_HPD_INT_CTRL_INT_EN; 195 if (!detected) 196 hpd_int_ctrl |= HDMI_HPD_INT_CTRL_INT_CONNECT; 197 hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, hpd_int_ctrl); 198 199 queue_work(hdmi->workq, &hdmi_bridge->hpd_work); 200 } 201 } 202 203 static enum drm_connector_status detect_reg(struct hdmi *hdmi) 204 { 205 uint32_t hpd_int_status; 206 207 pm_runtime_get_sync(&hdmi->pdev->dev); 208 enable_hpd_clocks(hdmi, true); 209 210 hpd_int_status = hdmi_read(hdmi, REG_HDMI_HPD_INT_STATUS); 211 212 enable_hpd_clocks(hdmi, false); 213 pm_runtime_put(&hdmi->pdev->dev); 214 215 return (hpd_int_status & HDMI_HPD_INT_STATUS_CABLE_DETECTED) ? 216 connector_status_connected : connector_status_disconnected; 217 } 218 219 #define HPD_GPIO_INDEX 2 220 static enum drm_connector_status detect_gpio(struct hdmi *hdmi) 221 { 222 return gpiod_get_value(hdmi->hpd_gpiod) ? 223 connector_status_connected : 224 connector_status_disconnected; 225 } 226 227 enum drm_connector_status msm_hdmi_bridge_detect( 228 struct drm_bridge *bridge) 229 { 230 struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge); 231 struct hdmi *hdmi = hdmi_bridge->hdmi; 232 enum drm_connector_status stat_gpio, stat_reg; 233 int retry = 20; 234 235 /* 236 * some platforms may not have hpd gpio. Rely only on the status 237 * provided by REG_HDMI_HPD_INT_STATUS in this case. 238 */ 239 if (!hdmi->hpd_gpiod) 240 return detect_reg(hdmi); 241 242 do { 243 stat_gpio = detect_gpio(hdmi); 244 stat_reg = detect_reg(hdmi); 245 246 if (stat_gpio == stat_reg) 247 break; 248 249 mdelay(10); 250 } while (--retry); 251 252 /* the status we get from reading gpio seems to be more reliable, 253 * so trust that one the most if we didn't manage to get hdmi and 254 * gpio status to agree: 255 */ 256 if (stat_gpio != stat_reg) { 257 DBG("HDMI_HPD_INT_STATUS tells us: %d", stat_reg); 258 DBG("hpd gpio tells us: %d", stat_gpio); 259 } 260 261 return stat_gpio; 262 } 263