root/drivers/gpu/drm/imx/dw_hdmi-imx.c

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

DEFINITIONS

This source file includes following definitions.
  1. enc_to_imx_hdmi
  2. dw_hdmi_imx_parse_dt
  3. dw_hdmi_imx_encoder_disable
  4. dw_hdmi_imx_encoder_enable
  5. dw_hdmi_imx_atomic_check
  6. imx6q_hdmi_mode_valid
  7. imx6dl_hdmi_mode_valid
  8. dw_hdmi_imx_bind
  9. dw_hdmi_imx_unbind
  10. dw_hdmi_imx_probe
  11. dw_hdmi_imx_remove

   1 // SPDX-License-Identifier: GPL-2.0
   2 /* Copyright (C) 2011-2013 Freescale Semiconductor, Inc.
   3  *
   4  * derived from imx-hdmi.c(renamed to bridge/dw_hdmi.c now)
   5  */
   6 
   7 #include <linux/component.h>
   8 #include <linux/mfd/syscon.h>
   9 #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
  10 #include <linux/module.h>
  11 #include <linux/platform_device.h>
  12 #include <linux/regmap.h>
  13 
  14 #include <video/imx-ipu-v3.h>
  15 
  16 #include <drm/bridge/dw_hdmi.h>
  17 #include <drm/drm_atomic_helper.h>
  18 #include <drm/drm_edid.h>
  19 #include <drm/drm_encoder.h>
  20 #include <drm/drm_of.h>
  21 
  22 #include "imx-drm.h"
  23 
  24 struct imx_hdmi {
  25         struct device *dev;
  26         struct drm_encoder encoder;
  27         struct dw_hdmi *hdmi;
  28         struct regmap *regmap;
  29 };
  30 
  31 static inline struct imx_hdmi *enc_to_imx_hdmi(struct drm_encoder *e)
  32 {
  33         return container_of(e, struct imx_hdmi, encoder);
  34 }
  35 
  36 static const struct dw_hdmi_mpll_config imx_mpll_cfg[] = {
  37         {
  38                 45250000, {
  39                         { 0x01e0, 0x0000 },
  40                         { 0x21e1, 0x0000 },
  41                         { 0x41e2, 0x0000 }
  42                 },
  43         }, {
  44                 92500000, {
  45                         { 0x0140, 0x0005 },
  46                         { 0x2141, 0x0005 },
  47                         { 0x4142, 0x0005 },
  48         },
  49         }, {
  50                 148500000, {
  51                         { 0x00a0, 0x000a },
  52                         { 0x20a1, 0x000a },
  53                         { 0x40a2, 0x000a },
  54                 },
  55         }, {
  56                 216000000, {
  57                         { 0x00a0, 0x000a },
  58                         { 0x2001, 0x000f },
  59                         { 0x4002, 0x000f },
  60                 },
  61         }, {
  62                 ~0UL, {
  63                         { 0x0000, 0x0000 },
  64                         { 0x0000, 0x0000 },
  65                         { 0x0000, 0x0000 },
  66                 },
  67         }
  68 };
  69 
  70 static const struct dw_hdmi_curr_ctrl imx_cur_ctr[] = {
  71         /*      pixelclk     bpp8    bpp10   bpp12 */
  72         {
  73                 54000000, { 0x091c, 0x091c, 0x06dc },
  74         }, {
  75                 58400000, { 0x091c, 0x06dc, 0x06dc },
  76         }, {
  77                 72000000, { 0x06dc, 0x06dc, 0x091c },
  78         }, {
  79                 74250000, { 0x06dc, 0x0b5c, 0x091c },
  80         }, {
  81                 118800000, { 0x091c, 0x091c, 0x06dc },
  82         }, {
  83                 216000000, { 0x06dc, 0x0b5c, 0x091c },
  84         }, {
  85                 ~0UL, { 0x0000, 0x0000, 0x0000 },
  86         },
  87 };
  88 
  89 /*
  90  * Resistance term 133Ohm Cfg
  91  * PREEMP config 0.00
  92  * TX/CK level 10
  93  */
  94 static const struct dw_hdmi_phy_config imx_phy_config[] = {
  95         /*pixelclk   symbol   term   vlev */
  96         { 216000000, 0x800d, 0x0005, 0x01ad},
  97         { ~0UL,      0x0000, 0x0000, 0x0000}
  98 };
  99 
 100 static int dw_hdmi_imx_parse_dt(struct imx_hdmi *hdmi)
 101 {
 102         struct device_node *np = hdmi->dev->of_node;
 103 
 104         hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
 105         if (IS_ERR(hdmi->regmap)) {
 106                 dev_err(hdmi->dev, "Unable to get gpr\n");
 107                 return PTR_ERR(hdmi->regmap);
 108         }
 109 
 110         return 0;
 111 }
 112 
 113 static void dw_hdmi_imx_encoder_disable(struct drm_encoder *encoder)
 114 {
 115 }
 116 
 117 static void dw_hdmi_imx_encoder_enable(struct drm_encoder *encoder)
 118 {
 119         struct imx_hdmi *hdmi = enc_to_imx_hdmi(encoder);
 120         int mux = drm_of_encoder_active_port_id(hdmi->dev->of_node, encoder);
 121 
 122         regmap_update_bits(hdmi->regmap, IOMUXC_GPR3,
 123                            IMX6Q_GPR3_HDMI_MUX_CTL_MASK,
 124                            mux << IMX6Q_GPR3_HDMI_MUX_CTL_SHIFT);
 125 }
 126 
 127 static int dw_hdmi_imx_atomic_check(struct drm_encoder *encoder,
 128                                     struct drm_crtc_state *crtc_state,
 129                                     struct drm_connector_state *conn_state)
 130 {
 131         struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc_state);
 132 
 133         imx_crtc_state->bus_format = MEDIA_BUS_FMT_RGB888_1X24;
 134         imx_crtc_state->di_hsync_pin = 2;
 135         imx_crtc_state->di_vsync_pin = 3;
 136 
 137         return 0;
 138 }
 139 
 140 static const struct drm_encoder_helper_funcs dw_hdmi_imx_encoder_helper_funcs = {
 141         .enable     = dw_hdmi_imx_encoder_enable,
 142         .disable    = dw_hdmi_imx_encoder_disable,
 143         .atomic_check = dw_hdmi_imx_atomic_check,
 144 };
 145 
 146 static const struct drm_encoder_funcs dw_hdmi_imx_encoder_funcs = {
 147         .destroy = drm_encoder_cleanup,
 148 };
 149 
 150 static enum drm_mode_status
 151 imx6q_hdmi_mode_valid(struct drm_connector *con,
 152                       const struct drm_display_mode *mode)
 153 {
 154         if (mode->clock < 13500)
 155                 return MODE_CLOCK_LOW;
 156         /* FIXME: Hardware is capable of 266MHz, but setup data is missing. */
 157         if (mode->clock > 216000)
 158                 return MODE_CLOCK_HIGH;
 159 
 160         return MODE_OK;
 161 }
 162 
 163 static enum drm_mode_status
 164 imx6dl_hdmi_mode_valid(struct drm_connector *con,
 165                        const struct drm_display_mode *mode)
 166 {
 167         if (mode->clock < 13500)
 168                 return MODE_CLOCK_LOW;
 169         /* FIXME: Hardware is capable of 270MHz, but setup data is missing. */
 170         if (mode->clock > 216000)
 171                 return MODE_CLOCK_HIGH;
 172 
 173         return MODE_OK;
 174 }
 175 
 176 static struct dw_hdmi_plat_data imx6q_hdmi_drv_data = {
 177         .mpll_cfg   = imx_mpll_cfg,
 178         .cur_ctr    = imx_cur_ctr,
 179         .phy_config = imx_phy_config,
 180         .mode_valid = imx6q_hdmi_mode_valid,
 181 };
 182 
 183 static struct dw_hdmi_plat_data imx6dl_hdmi_drv_data = {
 184         .mpll_cfg = imx_mpll_cfg,
 185         .cur_ctr  = imx_cur_ctr,
 186         .phy_config = imx_phy_config,
 187         .mode_valid = imx6dl_hdmi_mode_valid,
 188 };
 189 
 190 static const struct of_device_id dw_hdmi_imx_dt_ids[] = {
 191         { .compatible = "fsl,imx6q-hdmi",
 192           .data = &imx6q_hdmi_drv_data
 193         }, {
 194           .compatible = "fsl,imx6dl-hdmi",
 195           .data = &imx6dl_hdmi_drv_data
 196         },
 197         {},
 198 };
 199 MODULE_DEVICE_TABLE(of, dw_hdmi_imx_dt_ids);
 200 
 201 static int dw_hdmi_imx_bind(struct device *dev, struct device *master,
 202                             void *data)
 203 {
 204         struct platform_device *pdev = to_platform_device(dev);
 205         const struct dw_hdmi_plat_data *plat_data;
 206         const struct of_device_id *match;
 207         struct drm_device *drm = data;
 208         struct drm_encoder *encoder;
 209         struct imx_hdmi *hdmi;
 210         int ret;
 211 
 212         if (!pdev->dev.of_node)
 213                 return -ENODEV;
 214 
 215         hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
 216         if (!hdmi)
 217                 return -ENOMEM;
 218 
 219         match = of_match_node(dw_hdmi_imx_dt_ids, pdev->dev.of_node);
 220         plat_data = match->data;
 221         hdmi->dev = &pdev->dev;
 222         encoder = &hdmi->encoder;
 223 
 224         encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
 225         /*
 226          * If we failed to find the CRTC(s) which this encoder is
 227          * supposed to be connected to, it's because the CRTC has
 228          * not been registered yet.  Defer probing, and hope that
 229          * the required CRTC is added later.
 230          */
 231         if (encoder->possible_crtcs == 0)
 232                 return -EPROBE_DEFER;
 233 
 234         ret = dw_hdmi_imx_parse_dt(hdmi);
 235         if (ret < 0)
 236                 return ret;
 237 
 238         drm_encoder_helper_add(encoder, &dw_hdmi_imx_encoder_helper_funcs);
 239         drm_encoder_init(drm, encoder, &dw_hdmi_imx_encoder_funcs,
 240                          DRM_MODE_ENCODER_TMDS, NULL);
 241 
 242         platform_set_drvdata(pdev, hdmi);
 243 
 244         hdmi->hdmi = dw_hdmi_bind(pdev, encoder, plat_data);
 245 
 246         /*
 247          * If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(),
 248          * which would have called the encoder cleanup.  Do it manually.
 249          */
 250         if (IS_ERR(hdmi->hdmi)) {
 251                 ret = PTR_ERR(hdmi->hdmi);
 252                 drm_encoder_cleanup(encoder);
 253         }
 254 
 255         return ret;
 256 }
 257 
 258 static void dw_hdmi_imx_unbind(struct device *dev, struct device *master,
 259                                void *data)
 260 {
 261         struct imx_hdmi *hdmi = dev_get_drvdata(dev);
 262 
 263         dw_hdmi_unbind(hdmi->hdmi);
 264 }
 265 
 266 static const struct component_ops dw_hdmi_imx_ops = {
 267         .bind   = dw_hdmi_imx_bind,
 268         .unbind = dw_hdmi_imx_unbind,
 269 };
 270 
 271 static int dw_hdmi_imx_probe(struct platform_device *pdev)
 272 {
 273         return component_add(&pdev->dev, &dw_hdmi_imx_ops);
 274 }
 275 
 276 static int dw_hdmi_imx_remove(struct platform_device *pdev)
 277 {
 278         component_del(&pdev->dev, &dw_hdmi_imx_ops);
 279 
 280         return 0;
 281 }
 282 
 283 static struct platform_driver dw_hdmi_imx_platform_driver = {
 284         .probe  = dw_hdmi_imx_probe,
 285         .remove = dw_hdmi_imx_remove,
 286         .driver = {
 287                 .name = "dwhdmi-imx",
 288                 .of_match_table = dw_hdmi_imx_dt_ids,
 289         },
 290 };
 291 
 292 module_platform_driver(dw_hdmi_imx_platform_driver);
 293 
 294 MODULE_AUTHOR("Andy Yan <andy.yan@rock-chips.com>");
 295 MODULE_AUTHOR("Yakir Yang <ykk@rock-chips.com>");
 296 MODULE_DESCRIPTION("IMX6 Specific DW-HDMI Driver Extension");
 297 MODULE_LICENSE("GPL");
 298 MODULE_ALIAS("platform:dwhdmi-imx");

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