root/drivers/gpu/drm/msm/hdmi/hdmi_connector.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. msm_hdmi_phy_reset
  2. gpio_config
  3. enable_hpd_clocks
  4. msm_hdmi_hpd_enable
  5. hdp_disable
  6. msm_hdmi_hotplug_work
  7. msm_hdmi_connector_irq
  8. detect_reg
  9. detect_gpio
  10. hdmi_connector_detect
  11. hdmi_connector_destroy
  12. msm_hdmi_connector_get_modes
  13. msm_hdmi_connector_mode_valid
  14. msm_hdmi_connector_init

   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 struct hdmi_connector {
  15         struct drm_connector base;
  16         struct hdmi *hdmi;
  17         struct work_struct hpd_work;
  18 };
  19 #define to_hdmi_connector(x) container_of(x, struct hdmi_connector, base)
  20 
  21 static void msm_hdmi_phy_reset(struct hdmi *hdmi)
  22 {
  23         unsigned int val;
  24 
  25         val = hdmi_read(hdmi, REG_HDMI_PHY_CTRL);
  26 
  27         if (val & HDMI_PHY_CTRL_SW_RESET_LOW) {
  28                 /* pull low */
  29                 hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
  30                                 val & ~HDMI_PHY_CTRL_SW_RESET);
  31         } else {
  32                 /* pull high */
  33                 hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
  34                                 val | HDMI_PHY_CTRL_SW_RESET);
  35         }
  36 
  37         if (val & HDMI_PHY_CTRL_SW_RESET_PLL_LOW) {
  38                 /* pull low */
  39                 hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
  40                                 val & ~HDMI_PHY_CTRL_SW_RESET_PLL);
  41         } else {
  42                 /* pull high */
  43                 hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
  44                                 val | HDMI_PHY_CTRL_SW_RESET_PLL);
  45         }
  46 
  47         msleep(100);
  48 
  49         if (val & HDMI_PHY_CTRL_SW_RESET_LOW) {
  50                 /* pull high */
  51                 hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
  52                                 val | HDMI_PHY_CTRL_SW_RESET);
  53         } else {
  54                 /* pull low */
  55                 hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
  56                                 val & ~HDMI_PHY_CTRL_SW_RESET);
  57         }
  58 
  59         if (val & HDMI_PHY_CTRL_SW_RESET_PLL_LOW) {
  60                 /* pull high */
  61                 hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
  62                                 val | HDMI_PHY_CTRL_SW_RESET_PLL);
  63         } else {
  64                 /* pull low */
  65                 hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
  66                                 val & ~HDMI_PHY_CTRL_SW_RESET_PLL);
  67         }
  68 }
  69 
  70 static int gpio_config(struct hdmi *hdmi, bool on)
  71 {
  72         const struct hdmi_platform_config *config = hdmi->config;
  73         int i;
  74 
  75         if (on) {
  76                 for (i = 0; i < HDMI_MAX_NUM_GPIO; i++) {
  77                         struct hdmi_gpio_data gpio = config->gpios[i];
  78 
  79                         if (gpio.gpiod) {
  80                                 if (gpio.output) {
  81                                         gpiod_direction_output(gpio.gpiod,
  82                                                                gpio.value);
  83                                 } else {
  84                                         gpiod_direction_input(gpio.gpiod);
  85                                         gpiod_set_value_cansleep(gpio.gpiod,
  86                                                                  gpio.value);
  87                                 }
  88                         }
  89                 }
  90 
  91                 DBG("gpio on");
  92         } else {
  93                 for (i = 0; i < HDMI_MAX_NUM_GPIO; i++) {
  94                         struct hdmi_gpio_data gpio = config->gpios[i];
  95 
  96                         if (!gpio.gpiod)
  97                                 continue;
  98 
  99                         if (gpio.output) {
 100                                 int value = gpio.value ? 0 : 1;
 101 
 102                                 gpiod_set_value_cansleep(gpio.gpiod, value);
 103                         }
 104                 };
 105 
 106                 DBG("gpio off");
 107         }
 108 
 109         return 0;
 110 }
 111 
 112 static void enable_hpd_clocks(struct hdmi *hdmi, bool enable)
 113 {
 114         const struct hdmi_platform_config *config = hdmi->config;
 115         struct device *dev = &hdmi->pdev->dev;
 116         int i, ret;
 117 
 118         if (enable) {
 119                 for (i = 0; i < config->hpd_clk_cnt; i++) {
 120                         if (config->hpd_freq && config->hpd_freq[i]) {
 121                                 ret = clk_set_rate(hdmi->hpd_clks[i],
 122                                                    config->hpd_freq[i]);
 123                                 if (ret)
 124                                         dev_warn(dev,
 125                                                  "failed to set clk %s (%d)\n",
 126                                                  config->hpd_clk_names[i], ret);
 127                         }
 128 
 129                         ret = clk_prepare_enable(hdmi->hpd_clks[i]);
 130                         if (ret) {
 131                                 DRM_DEV_ERROR(dev,
 132                                         "failed to enable hpd clk: %s (%d)\n",
 133                                         config->hpd_clk_names[i], ret);
 134                         }
 135                 }
 136         } else {
 137                 for (i = config->hpd_clk_cnt - 1; i >= 0; i--)
 138                         clk_disable_unprepare(hdmi->hpd_clks[i]);
 139         }
 140 }
 141 
 142 int msm_hdmi_hpd_enable(struct drm_connector *connector)
 143 {
 144         struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
 145         struct hdmi *hdmi = hdmi_connector->hdmi;
 146         const struct hdmi_platform_config *config = hdmi->config;
 147         struct device *dev = &hdmi->pdev->dev;
 148         uint32_t hpd_ctrl;
 149         int i, ret;
 150         unsigned long flags;
 151 
 152         for (i = 0; i < config->hpd_reg_cnt; i++) {
 153                 ret = regulator_enable(hdmi->hpd_regs[i]);
 154                 if (ret) {
 155                         DRM_DEV_ERROR(dev, "failed to enable hpd regulator: %s (%d)\n",
 156                                         config->hpd_reg_names[i], ret);
 157                         goto fail;
 158                 }
 159         }
 160 
 161         ret = pinctrl_pm_select_default_state(dev);
 162         if (ret) {
 163                 DRM_DEV_ERROR(dev, "pinctrl state chg failed: %d\n", ret);
 164                 goto fail;
 165         }
 166 
 167         ret = gpio_config(hdmi, true);
 168         if (ret) {
 169                 DRM_DEV_ERROR(dev, "failed to configure GPIOs: %d\n", ret);
 170                 goto fail;
 171         }
 172 
 173         pm_runtime_get_sync(dev);
 174         enable_hpd_clocks(hdmi, true);
 175 
 176         msm_hdmi_set_mode(hdmi, false);
 177         msm_hdmi_phy_reset(hdmi);
 178         msm_hdmi_set_mode(hdmi, true);
 179 
 180         hdmi_write(hdmi, REG_HDMI_USEC_REFTIMER, 0x0001001b);
 181 
 182         /* enable HPD events: */
 183         hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL,
 184                         HDMI_HPD_INT_CTRL_INT_CONNECT |
 185                         HDMI_HPD_INT_CTRL_INT_EN);
 186 
 187         /* set timeout to 4.1ms (max) for hardware debounce */
 188         spin_lock_irqsave(&hdmi->reg_lock, flags);
 189         hpd_ctrl = hdmi_read(hdmi, REG_HDMI_HPD_CTRL);
 190         hpd_ctrl |= HDMI_HPD_CTRL_TIMEOUT(0x1fff);
 191 
 192         /* Toggle HPD circuit to trigger HPD sense */
 193         hdmi_write(hdmi, REG_HDMI_HPD_CTRL,
 194                         ~HDMI_HPD_CTRL_ENABLE & hpd_ctrl);
 195         hdmi_write(hdmi, REG_HDMI_HPD_CTRL,
 196                         HDMI_HPD_CTRL_ENABLE | hpd_ctrl);
 197         spin_unlock_irqrestore(&hdmi->reg_lock, flags);
 198 
 199         return 0;
 200 
 201 fail:
 202         return ret;
 203 }
 204 
 205 static void hdp_disable(struct hdmi_connector *hdmi_connector)
 206 {
 207         struct hdmi *hdmi = hdmi_connector->hdmi;
 208         const struct hdmi_platform_config *config = hdmi->config;
 209         struct device *dev = &hdmi->pdev->dev;
 210         int i, ret = 0;
 211 
 212         /* Disable HPD interrupt */
 213         hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, 0);
 214 
 215         msm_hdmi_set_mode(hdmi, false);
 216 
 217         enable_hpd_clocks(hdmi, false);
 218         pm_runtime_put_autosuspend(dev);
 219 
 220         ret = gpio_config(hdmi, false);
 221         if (ret)
 222                 dev_warn(dev, "failed to unconfigure GPIOs: %d\n", ret);
 223 
 224         ret = pinctrl_pm_select_sleep_state(dev);
 225         if (ret)
 226                 dev_warn(dev, "pinctrl state chg failed: %d\n", ret);
 227 
 228         for (i = 0; i < config->hpd_reg_cnt; i++) {
 229                 ret = regulator_disable(hdmi->hpd_regs[i]);
 230                 if (ret)
 231                         dev_warn(dev, "failed to disable hpd regulator: %s (%d)\n",
 232                                         config->hpd_reg_names[i], ret);
 233         }
 234 }
 235 
 236 static void
 237 msm_hdmi_hotplug_work(struct work_struct *work)
 238 {
 239         struct hdmi_connector *hdmi_connector =
 240                 container_of(work, struct hdmi_connector, hpd_work);
 241         struct drm_connector *connector = &hdmi_connector->base;
 242         drm_helper_hpd_irq_event(connector->dev);
 243 }
 244 
 245 void msm_hdmi_connector_irq(struct drm_connector *connector)
 246 {
 247         struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
 248         struct hdmi *hdmi = hdmi_connector->hdmi;
 249         uint32_t hpd_int_status, hpd_int_ctrl;
 250 
 251         /* Process HPD: */
 252         hpd_int_status = hdmi_read(hdmi, REG_HDMI_HPD_INT_STATUS);
 253         hpd_int_ctrl   = hdmi_read(hdmi, REG_HDMI_HPD_INT_CTRL);
 254 
 255         if ((hpd_int_ctrl & HDMI_HPD_INT_CTRL_INT_EN) &&
 256                         (hpd_int_status & HDMI_HPD_INT_STATUS_INT)) {
 257                 bool detected = !!(hpd_int_status & HDMI_HPD_INT_STATUS_CABLE_DETECTED);
 258 
 259                 /* ack & disable (temporarily) HPD events: */
 260                 hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL,
 261                         HDMI_HPD_INT_CTRL_INT_ACK);
 262 
 263                 DBG("status=%04x, ctrl=%04x", hpd_int_status, hpd_int_ctrl);
 264 
 265                 /* detect disconnect if we are connected or visa versa: */
 266                 hpd_int_ctrl = HDMI_HPD_INT_CTRL_INT_EN;
 267                 if (!detected)
 268                         hpd_int_ctrl |= HDMI_HPD_INT_CTRL_INT_CONNECT;
 269                 hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, hpd_int_ctrl);
 270 
 271                 queue_work(hdmi->workq, &hdmi_connector->hpd_work);
 272         }
 273 }
 274 
 275 static enum drm_connector_status detect_reg(struct hdmi *hdmi)
 276 {
 277         uint32_t hpd_int_status;
 278 
 279         pm_runtime_get_sync(&hdmi->pdev->dev);
 280         enable_hpd_clocks(hdmi, true);
 281 
 282         hpd_int_status = hdmi_read(hdmi, REG_HDMI_HPD_INT_STATUS);
 283 
 284         enable_hpd_clocks(hdmi, false);
 285         pm_runtime_put_autosuspend(&hdmi->pdev->dev);
 286 
 287         return (hpd_int_status & HDMI_HPD_INT_STATUS_CABLE_DETECTED) ?
 288                         connector_status_connected : connector_status_disconnected;
 289 }
 290 
 291 #define HPD_GPIO_INDEX  2
 292 static enum drm_connector_status detect_gpio(struct hdmi *hdmi)
 293 {
 294         const struct hdmi_platform_config *config = hdmi->config;
 295         struct hdmi_gpio_data hpd_gpio = config->gpios[HPD_GPIO_INDEX];
 296 
 297         return gpiod_get_value(hpd_gpio.gpiod) ?
 298                         connector_status_connected :
 299                         connector_status_disconnected;
 300 }
 301 
 302 static enum drm_connector_status hdmi_connector_detect(
 303                 struct drm_connector *connector, bool force)
 304 {
 305         struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
 306         struct hdmi *hdmi = hdmi_connector->hdmi;
 307         const struct hdmi_platform_config *config = hdmi->config;
 308         struct hdmi_gpio_data hpd_gpio = config->gpios[HPD_GPIO_INDEX];
 309         enum drm_connector_status stat_gpio, stat_reg;
 310         int retry = 20;
 311 
 312         /*
 313          * some platforms may not have hpd gpio. Rely only on the status
 314          * provided by REG_HDMI_HPD_INT_STATUS in this case.
 315          */
 316         if (!hpd_gpio.gpiod)
 317                 return detect_reg(hdmi);
 318 
 319         do {
 320                 stat_gpio = detect_gpio(hdmi);
 321                 stat_reg  = detect_reg(hdmi);
 322 
 323                 if (stat_gpio == stat_reg)
 324                         break;
 325 
 326                 mdelay(10);
 327         } while (--retry);
 328 
 329         /* the status we get from reading gpio seems to be more reliable,
 330          * so trust that one the most if we didn't manage to get hdmi and
 331          * gpio status to agree:
 332          */
 333         if (stat_gpio != stat_reg) {
 334                 DBG("HDMI_HPD_INT_STATUS tells us: %d", stat_reg);
 335                 DBG("hpd gpio tells us: %d", stat_gpio);
 336         }
 337 
 338         return stat_gpio;
 339 }
 340 
 341 static void hdmi_connector_destroy(struct drm_connector *connector)
 342 {
 343         struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
 344 
 345         hdp_disable(hdmi_connector);
 346 
 347         drm_connector_cleanup(connector);
 348 
 349         kfree(hdmi_connector);
 350 }
 351 
 352 static int msm_hdmi_connector_get_modes(struct drm_connector *connector)
 353 {
 354         struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
 355         struct hdmi *hdmi = hdmi_connector->hdmi;
 356         struct edid *edid;
 357         uint32_t hdmi_ctrl;
 358         int ret = 0;
 359 
 360         hdmi_ctrl = hdmi_read(hdmi, REG_HDMI_CTRL);
 361         hdmi_write(hdmi, REG_HDMI_CTRL, hdmi_ctrl | HDMI_CTRL_ENABLE);
 362 
 363         edid = drm_get_edid(connector, hdmi->i2c);
 364 
 365         hdmi_write(hdmi, REG_HDMI_CTRL, hdmi_ctrl);
 366 
 367         hdmi->hdmi_mode = drm_detect_hdmi_monitor(edid);
 368         drm_connector_update_edid_property(connector, edid);
 369 
 370         if (edid) {
 371                 ret = drm_add_edid_modes(connector, edid);
 372                 kfree(edid);
 373         }
 374 
 375         return ret;
 376 }
 377 
 378 static int msm_hdmi_connector_mode_valid(struct drm_connector *connector,
 379                                  struct drm_display_mode *mode)
 380 {
 381         struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
 382         struct hdmi *hdmi = hdmi_connector->hdmi;
 383         const struct hdmi_platform_config *config = hdmi->config;
 384         struct msm_drm_private *priv = connector->dev->dev_private;
 385         struct msm_kms *kms = priv->kms;
 386         long actual, requested;
 387 
 388         requested = 1000 * mode->clock;
 389         actual = kms->funcs->round_pixclk(kms,
 390                         requested, hdmi_connector->hdmi->encoder);
 391 
 392         /* for mdp5/apq8074, we manage our own pixel clk (as opposed to
 393          * mdp4/dtv stuff where pixel clk is assigned to mdp/encoder
 394          * instead):
 395          */
 396         if (config->pwr_clk_cnt > 0)
 397                 actual = clk_round_rate(hdmi->pwr_clks[0], actual);
 398 
 399         DBG("requested=%ld, actual=%ld", requested, actual);
 400 
 401         if (actual != requested)
 402                 return MODE_CLOCK_RANGE;
 403 
 404         return 0;
 405 }
 406 
 407 static const struct drm_connector_funcs hdmi_connector_funcs = {
 408         .detect = hdmi_connector_detect,
 409         .fill_modes = drm_helper_probe_single_connector_modes,
 410         .destroy = hdmi_connector_destroy,
 411         .reset = drm_atomic_helper_connector_reset,
 412         .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
 413         .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 414 };
 415 
 416 static const struct drm_connector_helper_funcs msm_hdmi_connector_helper_funcs = {
 417         .get_modes = msm_hdmi_connector_get_modes,
 418         .mode_valid = msm_hdmi_connector_mode_valid,
 419 };
 420 
 421 /* initialize connector */
 422 struct drm_connector *msm_hdmi_connector_init(struct hdmi *hdmi)
 423 {
 424         struct drm_connector *connector = NULL;
 425         struct hdmi_connector *hdmi_connector;
 426 
 427         hdmi_connector = kzalloc(sizeof(*hdmi_connector), GFP_KERNEL);
 428         if (!hdmi_connector)
 429                 return ERR_PTR(-ENOMEM);
 430 
 431         hdmi_connector->hdmi = hdmi;
 432         INIT_WORK(&hdmi_connector->hpd_work, msm_hdmi_hotplug_work);
 433 
 434         connector = &hdmi_connector->base;
 435 
 436         drm_connector_init(hdmi->dev, connector, &hdmi_connector_funcs,
 437                         DRM_MODE_CONNECTOR_HDMIA);
 438         drm_connector_helper_add(connector, &msm_hdmi_connector_helper_funcs);
 439 
 440         connector->polled = DRM_CONNECTOR_POLL_CONNECT |
 441                         DRM_CONNECTOR_POLL_DISCONNECT;
 442 
 443         connector->interlace_allowed = 0;
 444         connector->doublescan_allowed = 0;
 445 
 446         drm_connector_attach_encoder(connector, hdmi->encoder);
 447 
 448         return connector;
 449 }

/* [<][>][^][v][top][bottom][index][help] */