diff options
| author | Dave Airlie <airlied@redhat.com> | 2015-01-20 19:17:16 -0500 |
|---|---|---|
| committer | Dave Airlie <airlied@redhat.com> | 2015-01-20 19:17:16 -0500 |
| commit | fc83975348ebce07793e6b9f780edc3cbcffa9fc (patch) | |
| tree | 0fc7972c181cebed1c344852bb8b1a96607d3b15 /drivers/gpu/drm | |
| parent | b2eb0489809cf0b824357b6fa85aab1aabe3f063 (diff) | |
| parent | d50141d8072e5322ee0518a8c967b5c9caf463d2 (diff) | |
Merge tag 'imx-drm-next-2015-01-09' of git://git.pengutronix.de/git/pza/linux into drm-next
imx-drm mode fixup support, imx-hdmi bridge conversion and imx-drm cleanup
- Implement mode_fixup for a DI vertical timing limitation
- Use generic DRM OF helpers in DRM core
- Convert imx-hdmi to dw_hdmi drm_bridge and add rockchip
driver
- Add DC use counter to fix multi-display support
- Simplify handling of DI clock flags
- A few small fixes and cleanup
* tag 'imx-drm-next-2015-01-09' of git://git.pengutronix.de/git/pza/linux: (26 commits)
imx-drm: core: handling of DI clock flags to ipu_crtc_mode_set()
gpu: ipu-di: Switch to DIV_ROUND_CLOSEST for DI clock divider calc
gpu: ipu-v3: Use videomode in struct ipu_di_signal_cfg
imx-drm: encoder prepare/mode_set must use adjusted mode
imx-drm: ipuv3-crtc: Implement mode_fixup
drm_modes: add drm_display_mode_to_videomode
gpu: ipu-di: remove some non-functional code
gpu: ipu-di: Add ipu_di_adjust_videomode()
drm: rockchip: export functions needed by rockchip dw_hdmi bridge driver
drm: bridge/dw_hdmi: request interrupt only after initializing the mutes
drm: bridge/dw_hdmi: add rockchip rk3288 support
dt-bindings: Add documentation for rockchip dw hdmi
drm: bridge/dw_hdmi: add function dw_hdmi_phy_enable_spare
drm: bridge/dw_hdmi: clear i2cmphy_stat0 reg in hdmi_phy_wait_i2c_done
drm: bridge/dw_hdmi: add mode_valid support
drm: bridge/dw_hdmi: add support for multi-byte register width access
dt-bindings: add document for dw_hdmi
drm: imx: imx-hdmi: move imx-hdmi to bridge/dw_hdmi
drm: imx: imx-hdmi: split phy configuration to platform driver
drm: imx: imx-hdmi: convert imx-hdmi to drm_bridge mode
...
Diffstat (limited to 'drivers/gpu/drm')
| -rw-r--r-- | drivers/gpu/drm/bridge/Kconfig | 5 | ||||
| -rw-r--r-- | drivers/gpu/drm/bridge/Makefile | 1 | ||||
| -rw-r--r-- | drivers/gpu/drm/bridge/dw_hdmi.c (renamed from drivers/gpu/drm/imx/imx-hdmi.c) | 724 | ||||
| -rw-r--r-- | drivers/gpu/drm/bridge/dw_hdmi.h (renamed from drivers/gpu/drm/imx/imx-hdmi.h) | 4 | ||||
| -rw-r--r-- | drivers/gpu/drm/drm_modes.c | 40 | ||||
| -rw-r--r-- | drivers/gpu/drm/imx/Kconfig | 1 | ||||
| -rw-r--r-- | drivers/gpu/drm/imx/Makefile | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/imx/dw_hdmi-imx.c | 258 | ||||
| -rw-r--r-- | drivers/gpu/drm/imx/imx-drm-core.c | 87 | ||||
| -rw-r--r-- | drivers/gpu/drm/imx/imx-drm.h | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/imx/imx-ldb.c | 8 | ||||
| -rw-r--r-- | drivers/gpu/drm/imx/imx-tve.c | 4 | ||||
| -rw-r--r-- | drivers/gpu/drm/imx/ipuv3-crtc.c | 78 | ||||
| -rw-r--r-- | drivers/gpu/drm/imx/parallel-display.c | 7 | ||||
| -rw-r--r-- | drivers/gpu/drm/rockchip/Kconfig | 10 | ||||
| -rw-r--r-- | drivers/gpu/drm/rockchip/Makefile | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 341 | ||||
| -rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 1 | ||||
| -rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 1 |
19 files changed, 1073 insertions, 503 deletions
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index 884923f982d9..b70f3c8d4e8a 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig | |||
| @@ -3,3 +3,8 @@ config DRM_PTN3460 | |||
| 3 | depends on DRM | 3 | depends on DRM |
| 4 | select DRM_KMS_HELPER | 4 | select DRM_KMS_HELPER |
| 5 | ---help--- | 5 | ---help--- |
| 6 | |||
| 7 | config DRM_DW_HDMI | ||
| 8 | tristate | ||
| 9 | depends on DRM | ||
| 10 | select DRM_KMS_HELPER | ||
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile index b4733e1fbd2e..d8a8cfd12fbb 100644 --- a/drivers/gpu/drm/bridge/Makefile +++ b/drivers/gpu/drm/bridge/Makefile | |||
| @@ -1,3 +1,4 @@ | |||
| 1 | ccflags-y := -Iinclude/drm | 1 | ccflags-y := -Iinclude/drm |
| 2 | 2 | ||
| 3 | obj-$(CONFIG_DRM_PTN3460) += ptn3460.o | 3 | obj-$(CONFIG_DRM_PTN3460) += ptn3460.o |
| 4 | obj-$(CONFIG_DRM_DW_HDMI) += dw_hdmi.o | ||
diff --git a/drivers/gpu/drm/imx/imx-hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c index ddc53e039530..6ea000504173 100644 --- a/drivers/gpu/drm/imx/imx-hdmi.c +++ b/drivers/gpu/drm/bridge/dw_hdmi.c | |||
| @@ -6,31 +6,26 @@ | |||
| 6 | * the Free Software Foundation; either version 2 of the License, or | 6 | * the Free Software Foundation; either version 2 of the License, or |
| 7 | * (at your option) any later version. | 7 | * (at your option) any later version. |
| 8 | * | 8 | * |
| 9 | * SH-Mobile High-Definition Multimedia Interface (HDMI) driver | 9 | * Designware High-Definition Multimedia Interface (HDMI) driver |
| 10 | * for SLISHDMI13T and SLIPHDMIT IP cores | ||
| 11 | * | 10 | * |
| 12 | * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de> | 11 | * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de> |
| 13 | */ | 12 | */ |
| 14 | 13 | #include <linux/module.h> | |
| 15 | #include <linux/component.h> | ||
| 16 | #include <linux/irq.h> | 14 | #include <linux/irq.h> |
| 17 | #include <linux/delay.h> | 15 | #include <linux/delay.h> |
| 18 | #include <linux/err.h> | 16 | #include <linux/err.h> |
| 19 | #include <linux/clk.h> | 17 | #include <linux/clk.h> |
| 20 | #include <linux/hdmi.h> | 18 | #include <linux/hdmi.h> |
| 21 | #include <linux/regmap.h> | ||
| 22 | #include <linux/mfd/syscon.h> | ||
| 23 | #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> | ||
| 24 | #include <linux/of_device.h> | 19 | #include <linux/of_device.h> |
| 25 | 20 | ||
| 21 | #include <drm/drm_of.h> | ||
| 26 | #include <drm/drmP.h> | 22 | #include <drm/drmP.h> |
| 27 | #include <drm/drm_crtc_helper.h> | 23 | #include <drm/drm_crtc_helper.h> |
| 28 | #include <drm/drm_edid.h> | 24 | #include <drm/drm_edid.h> |
| 29 | #include <drm/drm_encoder_slave.h> | 25 | #include <drm/drm_encoder_slave.h> |
| 30 | #include <video/imx-ipu-v3.h> | 26 | #include <drm/bridge/dw_hdmi.h> |
| 31 | 27 | ||
| 32 | #include "imx-hdmi.h" | 28 | #include "dw_hdmi.h" |
| 33 | #include "imx-drm.h" | ||
| 34 | 29 | ||
| 35 | #define HDMI_EDID_LEN 512 | 30 | #define HDMI_EDID_LEN 512 |
| 36 | 31 | ||
| @@ -54,11 +49,6 @@ enum hdmi_datamap { | |||
| 54 | YCbCr422_12B = 0x12, | 49 | YCbCr422_12B = 0x12, |
| 55 | }; | 50 | }; |
| 56 | 51 | ||
| 57 | enum imx_hdmi_devtype { | ||
| 58 | IMX6Q_HDMI, | ||
| 59 | IMX6DL_HDMI, | ||
| 60 | }; | ||
| 61 | |||
| 62 | static const u16 csc_coeff_default[3][4] = { | 52 | static const u16 csc_coeff_default[3][4] = { |
| 63 | { 0x2000, 0x0000, 0x0000, 0x0000 }, | 53 | { 0x2000, 0x0000, 0x0000, 0x0000 }, |
| 64 | { 0x0000, 0x2000, 0x0000, 0x0000 }, | 54 | { 0x0000, 0x2000, 0x0000, 0x0000 }, |
| @@ -111,16 +101,19 @@ struct hdmi_data_info { | |||
| 111 | struct hdmi_vmode video_mode; | 101 | struct hdmi_vmode video_mode; |
| 112 | }; | 102 | }; |
| 113 | 103 | ||
| 114 | struct imx_hdmi { | 104 | struct dw_hdmi { |
| 115 | struct drm_connector connector; | 105 | struct drm_connector connector; |
| 116 | struct drm_encoder encoder; | 106 | struct drm_encoder *encoder; |
| 107 | struct drm_bridge *bridge; | ||
| 117 | 108 | ||
| 118 | enum imx_hdmi_devtype dev_type; | 109 | enum dw_hdmi_devtype dev_type; |
| 119 | struct device *dev; | 110 | struct device *dev; |
| 120 | struct clk *isfr_clk; | 111 | struct clk *isfr_clk; |
| 121 | struct clk *iahb_clk; | 112 | struct clk *iahb_clk; |
| 122 | 113 | ||
| 123 | struct hdmi_data_info hdmi_data; | 114 | struct hdmi_data_info hdmi_data; |
| 115 | const struct dw_hdmi_plat_data *plat_data; | ||
| 116 | |||
| 124 | int vic; | 117 | int vic; |
| 125 | 118 | ||
| 126 | u8 edid[HDMI_EDID_LEN]; | 119 | u8 edid[HDMI_EDID_LEN]; |
| @@ -135,26 +128,42 @@ struct imx_hdmi { | |||
| 135 | 128 | ||
| 136 | unsigned int sample_rate; | 129 | unsigned int sample_rate; |
| 137 | int ratio; | 130 | int ratio; |
| 131 | |||
| 132 | void (*write)(struct dw_hdmi *hdmi, u8 val, int offset); | ||
| 133 | u8 (*read)(struct dw_hdmi *hdmi, int offset); | ||
| 138 | }; | 134 | }; |
| 139 | 135 | ||
| 140 | static void imx_hdmi_set_ipu_di_mux(struct imx_hdmi *hdmi, int ipu_di) | 136 | static void dw_hdmi_writel(struct dw_hdmi *hdmi, u8 val, int offset) |
| 141 | { | 137 | { |
| 142 | regmap_update_bits(hdmi->regmap, IOMUXC_GPR3, | 138 | writel(val, hdmi->regs + (offset << 2)); |
| 143 | IMX6Q_GPR3_HDMI_MUX_CTL_MASK, | ||
| 144 | ipu_di << IMX6Q_GPR3_HDMI_MUX_CTL_SHIFT); | ||
| 145 | } | 139 | } |
| 146 | 140 | ||
| 147 | static inline void hdmi_writeb(struct imx_hdmi *hdmi, u8 val, int offset) | 141 | static u8 dw_hdmi_readl(struct dw_hdmi *hdmi, int offset) |
| 142 | { | ||
| 143 | return readl(hdmi->regs + (offset << 2)); | ||
| 144 | } | ||
| 145 | |||
| 146 | static void dw_hdmi_writeb(struct dw_hdmi *hdmi, u8 val, int offset) | ||
| 148 | { | 147 | { |
| 149 | writeb(val, hdmi->regs + offset); | 148 | writeb(val, hdmi->regs + offset); |
| 150 | } | 149 | } |
| 151 | 150 | ||
| 152 | static inline u8 hdmi_readb(struct imx_hdmi *hdmi, int offset) | 151 | static u8 dw_hdmi_readb(struct dw_hdmi *hdmi, int offset) |
| 153 | { | 152 | { |
| 154 | return readb(hdmi->regs + offset); | 153 | return readb(hdmi->regs + offset); |
| 155 | } | 154 | } |
| 156 | 155 | ||
| 157 | static void hdmi_modb(struct imx_hdmi *hdmi, u8 data, u8 mask, unsigned reg) | 156 | static inline void hdmi_writeb(struct dw_hdmi *hdmi, u8 val, int offset) |
| 157 | { | ||
| 158 | hdmi->write(hdmi, val, offset); | ||
| 159 | } | ||
| 160 | |||
| 161 | static inline u8 hdmi_readb(struct dw_hdmi *hdmi, int offset) | ||
| 162 | { | ||
| 163 | return hdmi->read(hdmi, offset); | ||
| 164 | } | ||
| 165 | |||
| 166 | static void hdmi_modb(struct dw_hdmi *hdmi, u8 data, u8 mask, unsigned reg) | ||
| 158 | { | 167 | { |
| 159 | u8 val = hdmi_readb(hdmi, reg) & ~mask; | 168 | u8 val = hdmi_readb(hdmi, reg) & ~mask; |
| 160 | 169 | ||
| @@ -162,13 +171,13 @@ static void hdmi_modb(struct imx_hdmi *hdmi, u8 data, u8 mask, unsigned reg) | |||
| 162 | hdmi_writeb(hdmi, val, reg); | 171 | hdmi_writeb(hdmi, val, reg); |
| 163 | } | 172 | } |
| 164 | 173 | ||
| 165 | static void hdmi_mask_writeb(struct imx_hdmi *hdmi, u8 data, unsigned int reg, | 174 | static void hdmi_mask_writeb(struct dw_hdmi *hdmi, u8 data, unsigned int reg, |
| 166 | u8 shift, u8 mask) | 175 | u8 shift, u8 mask) |
| 167 | { | 176 | { |
| 168 | hdmi_modb(hdmi, data << shift, mask, reg); | 177 | hdmi_modb(hdmi, data << shift, mask, reg); |
| 169 | } | 178 | } |
| 170 | 179 | ||
| 171 | static void hdmi_set_clock_regenerator_n(struct imx_hdmi *hdmi, | 180 | static void hdmi_set_clock_regenerator_n(struct dw_hdmi *hdmi, |
| 172 | unsigned int value) | 181 | unsigned int value) |
| 173 | { | 182 | { |
| 174 | hdmi_writeb(hdmi, value & 0xff, HDMI_AUD_N1); | 183 | hdmi_writeb(hdmi, value & 0xff, HDMI_AUD_N1); |
| @@ -179,7 +188,7 @@ static void hdmi_set_clock_regenerator_n(struct imx_hdmi *hdmi, | |||
| 179 | hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_N_SHIFT_MASK, HDMI_AUD_CTS3); | 188 | hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_N_SHIFT_MASK, HDMI_AUD_CTS3); |
| 180 | } | 189 | } |
| 181 | 190 | ||
| 182 | static void hdmi_regenerate_cts(struct imx_hdmi *hdmi, unsigned int cts) | 191 | static void hdmi_regenerate_cts(struct dw_hdmi *hdmi, unsigned int cts) |
| 183 | { | 192 | { |
| 184 | /* Must be set/cleared first */ | 193 | /* Must be set/cleared first */ |
| 185 | hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3); | 194 | hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3); |
| @@ -326,8 +335,8 @@ static unsigned int hdmi_compute_cts(unsigned int freq, unsigned long pixel_clk, | |||
| 326 | return (cts * ratio) / 100; | 335 | return (cts * ratio) / 100; |
| 327 | } | 336 | } |
| 328 | 337 | ||
| 329 | static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi, | 338 | static void hdmi_set_clk_regenerator(struct dw_hdmi *hdmi, |
| 330 | unsigned long pixel_clk) | 339 | unsigned long pixel_clk) |
| 331 | { | 340 | { |
| 332 | unsigned int clk_n, clk_cts; | 341 | unsigned int clk_n, clk_cts; |
| 333 | 342 | ||
| @@ -338,7 +347,7 @@ static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi, | |||
| 338 | 347 | ||
| 339 | if (!clk_cts) { | 348 | if (!clk_cts) { |
| 340 | dev_dbg(hdmi->dev, "%s: pixel clock not supported: %lu\n", | 349 | dev_dbg(hdmi->dev, "%s: pixel clock not supported: %lu\n", |
| 341 | __func__, pixel_clk); | 350 | __func__, pixel_clk); |
| 342 | return; | 351 | return; |
| 343 | } | 352 | } |
| 344 | 353 | ||
| @@ -350,12 +359,12 @@ static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi, | |||
| 350 | hdmi_regenerate_cts(hdmi, clk_cts); | 359 | hdmi_regenerate_cts(hdmi, clk_cts); |
| 351 | } | 360 | } |
| 352 | 361 | ||
| 353 | static void hdmi_init_clk_regenerator(struct imx_hdmi *hdmi) | 362 | static void hdmi_init_clk_regenerator(struct dw_hdmi *hdmi) |
| 354 | { | 363 | { |
| 355 | hdmi_set_clk_regenerator(hdmi, 74250000); | 364 | hdmi_set_clk_regenerator(hdmi, 74250000); |
| 356 | } | 365 | } |
| 357 | 366 | ||
| 358 | static void hdmi_clk_regenerator_update_pixel_clock(struct imx_hdmi *hdmi) | 367 | static void hdmi_clk_regenerator_update_pixel_clock(struct dw_hdmi *hdmi) |
| 359 | { | 368 | { |
| 360 | hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock); | 369 | hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock); |
| 361 | } | 370 | } |
| @@ -367,7 +376,7 @@ static void hdmi_clk_regenerator_update_pixel_clock(struct imx_hdmi *hdmi) | |||
| 367 | * pin{31~24} <==> G[7:0] | 376 | * pin{31~24} <==> G[7:0] |
| 368 | * pin{15~8} <==> B[7:0] | 377 | * pin{15~8} <==> B[7:0] |
| 369 | */ | 378 | */ |
| 370 | static void hdmi_video_sample(struct imx_hdmi *hdmi) | 379 | static void hdmi_video_sample(struct dw_hdmi *hdmi) |
| 371 | { | 380 | { |
| 372 | int color_format = 0; | 381 | int color_format = 0; |
| 373 | u8 val; | 382 | u8 val; |
| @@ -423,12 +432,12 @@ static void hdmi_video_sample(struct imx_hdmi *hdmi) | |||
| 423 | hdmi_writeb(hdmi, 0x0, HDMI_TX_BCBDATA1); | 432 | hdmi_writeb(hdmi, 0x0, HDMI_TX_BCBDATA1); |
| 424 | } | 433 | } |
| 425 | 434 | ||
| 426 | static int is_color_space_conversion(struct imx_hdmi *hdmi) | 435 | static int is_color_space_conversion(struct dw_hdmi *hdmi) |
| 427 | { | 436 | { |
| 428 | return hdmi->hdmi_data.enc_in_format != hdmi->hdmi_data.enc_out_format; | 437 | return hdmi->hdmi_data.enc_in_format != hdmi->hdmi_data.enc_out_format; |
| 429 | } | 438 | } |
| 430 | 439 | ||
| 431 | static int is_color_space_decimation(struct imx_hdmi *hdmi) | 440 | static int is_color_space_decimation(struct dw_hdmi *hdmi) |
| 432 | { | 441 | { |
| 433 | if (hdmi->hdmi_data.enc_out_format != YCBCR422_8BITS) | 442 | if (hdmi->hdmi_data.enc_out_format != YCBCR422_8BITS) |
| 434 | return 0; | 443 | return 0; |
| @@ -438,7 +447,7 @@ static int is_color_space_decimation(struct imx_hdmi *hdmi) | |||
| 438 | return 0; | 447 | return 0; |
| 439 | } | 448 | } |
| 440 | 449 | ||
| 441 | static int is_color_space_interpolation(struct imx_hdmi *hdmi) | 450 | static int is_color_space_interpolation(struct dw_hdmi *hdmi) |
| 442 | { | 451 | { |
| 443 | if (hdmi->hdmi_data.enc_in_format != YCBCR422_8BITS) | 452 | if (hdmi->hdmi_data.enc_in_format != YCBCR422_8BITS) |
| 444 | return 0; | 453 | return 0; |
| @@ -448,7 +457,7 @@ static int is_color_space_interpolation(struct imx_hdmi *hdmi) | |||
| 448 | return 0; | 457 | return 0; |
| 449 | } | 458 | } |
| 450 | 459 | ||
| 451 | static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi) | 460 | static void dw_hdmi_update_csc_coeffs(struct dw_hdmi *hdmi) |
| 452 | { | 461 | { |
| 453 | const u16 (*csc_coeff)[3][4] = &csc_coeff_default; | 462 | const u16 (*csc_coeff)[3][4] = &csc_coeff_default; |
| 454 | unsigned i; | 463 | unsigned i; |
| @@ -477,13 +486,11 @@ static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi) | |||
| 477 | u16 coeff_b = (*csc_coeff)[1][i]; | 486 | u16 coeff_b = (*csc_coeff)[1][i]; |
| 478 | u16 coeff_c = (*csc_coeff)[2][i]; | 487 | u16 coeff_c = (*csc_coeff)[2][i]; |
| 479 | 488 | ||
| 480 | hdmi_writeb(hdmi, coeff_a & 0xff, | 489 | hdmi_writeb(hdmi, coeff_a & 0xff, HDMI_CSC_COEF_A1_LSB + i * 2); |
| 481 | HDMI_CSC_COEF_A1_LSB + i * 2); | ||
| 482 | hdmi_writeb(hdmi, coeff_a >> 8, HDMI_CSC_COEF_A1_MSB + i * 2); | 490 | hdmi_writeb(hdmi, coeff_a >> 8, HDMI_CSC_COEF_A1_MSB + i * 2); |
| 483 | hdmi_writeb(hdmi, coeff_b & 0xff, HDMI_CSC_COEF_B1_LSB + i * 2); | 491 | hdmi_writeb(hdmi, coeff_b & 0xff, HDMI_CSC_COEF_B1_LSB + i * 2); |
| 484 | hdmi_writeb(hdmi, coeff_b >> 8, HDMI_CSC_COEF_B1_MSB + i * 2); | 492 | hdmi_writeb(hdmi, coeff_b >> 8, HDMI_CSC_COEF_B1_MSB + i * 2); |
| 485 | hdmi_writeb(hdmi, coeff_c & 0xff, | 493 | hdmi_writeb(hdmi, coeff_c & 0xff, HDMI_CSC_COEF_C1_LSB + i * 2); |
| 486 | HDMI_CSC_COEF_C1_LSB + i * 2); | ||
| 487 | hdmi_writeb(hdmi, coeff_c >> 8, HDMI_CSC_COEF_C1_MSB + i * 2); | 494 | hdmi_writeb(hdmi, coeff_c >> 8, HDMI_CSC_COEF_C1_MSB + i * 2); |
| 488 | } | 495 | } |
| 489 | 496 | ||
| @@ -491,7 +498,7 @@ static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi) | |||
| 491 | HDMI_CSC_SCALE); | 498 | HDMI_CSC_SCALE); |
| 492 | } | 499 | } |
| 493 | 500 | ||
| 494 | static void hdmi_video_csc(struct imx_hdmi *hdmi) | 501 | static void hdmi_video_csc(struct dw_hdmi *hdmi) |
| 495 | { | 502 | { |
| 496 | int color_depth = 0; | 503 | int color_depth = 0; |
| 497 | int interpolation = HDMI_CSC_CFG_INTMODE_DISABLE; | 504 | int interpolation = HDMI_CSC_CFG_INTMODE_DISABLE; |
| @@ -519,7 +526,7 @@ static void hdmi_video_csc(struct imx_hdmi *hdmi) | |||
| 519 | hdmi_modb(hdmi, color_depth, HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK, | 526 | hdmi_modb(hdmi, color_depth, HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK, |
| 520 | HDMI_CSC_SCALE); | 527 | HDMI_CSC_SCALE); |
| 521 | 528 | ||
| 522 | imx_hdmi_update_csc_coeffs(hdmi); | 529 | dw_hdmi_update_csc_coeffs(hdmi); |
| 523 | } | 530 | } |
| 524 | 531 | ||
| 525 | /* | 532 | /* |
| @@ -527,7 +534,7 @@ static void hdmi_video_csc(struct imx_hdmi *hdmi) | |||
| 527 | * for example, if input is YCC422 mode or repeater is used, | 534 | * for example, if input is YCC422 mode or repeater is used, |
| 528 | * data should be repacked this module can be bypassed. | 535 | * data should be repacked this module can be bypassed. |
| 529 | */ | 536 | */ |
| 530 | static void hdmi_video_packetize(struct imx_hdmi *hdmi) | 537 | static void hdmi_video_packetize(struct dw_hdmi *hdmi) |
| 531 | { | 538 | { |
| 532 | unsigned int color_depth = 0; | 539 | unsigned int color_depth = 0; |
| 533 | unsigned int remap_size = HDMI_VP_REMAP_YCC422_16bit; | 540 | unsigned int remap_size = HDMI_VP_REMAP_YCC422_16bit; |
| @@ -535,21 +542,22 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi) | |||
| 535 | struct hdmi_data_info *hdmi_data = &hdmi->hdmi_data; | 542 | struct hdmi_data_info *hdmi_data = &hdmi->hdmi_data; |
| 536 | u8 val, vp_conf; | 543 | u8 val, vp_conf; |
| 537 | 544 | ||
| 538 | if (hdmi_data->enc_out_format == RGB | 545 | if (hdmi_data->enc_out_format == RGB || |
| 539 | || hdmi_data->enc_out_format == YCBCR444) { | 546 | hdmi_data->enc_out_format == YCBCR444) { |
| 540 | if (!hdmi_data->enc_color_depth) | 547 | if (!hdmi_data->enc_color_depth) { |
| 541 | output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS; | 548 | output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS; |
| 542 | else if (hdmi_data->enc_color_depth == 8) { | 549 | } else if (hdmi_data->enc_color_depth == 8) { |
| 543 | color_depth = 4; | 550 | color_depth = 4; |
| 544 | output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS; | 551 | output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS; |
| 545 | } else if (hdmi_data->enc_color_depth == 10) | 552 | } else if (hdmi_data->enc_color_depth == 10) { |
| 546 | color_depth = 5; | 553 | color_depth = 5; |
| 547 | else if (hdmi_data->enc_color_depth == 12) | 554 | } else if (hdmi_data->enc_color_depth == 12) { |
| 548 | color_depth = 6; | 555 | color_depth = 6; |
| 549 | else if (hdmi_data->enc_color_depth == 16) | 556 | } else if (hdmi_data->enc_color_depth == 16) { |
| 550 | color_depth = 7; | 557 | color_depth = 7; |
| 551 | else | 558 | } else { |
| 552 | return; | 559 | return; |
| 560 | } | ||
| 553 | } else if (hdmi_data->enc_out_format == YCBCR422_8BITS) { | 561 | } else if (hdmi_data->enc_out_format == YCBCR422_8BITS) { |
| 554 | if (!hdmi_data->enc_color_depth || | 562 | if (!hdmi_data->enc_color_depth || |
| 555 | hdmi_data->enc_color_depth == 8) | 563 | hdmi_data->enc_color_depth == 8) |
| @@ -561,8 +569,9 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi) | |||
| 561 | else | 569 | else |
| 562 | return; | 570 | return; |
| 563 | output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422; | 571 | output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422; |
| 564 | } else | 572 | } else { |
| 565 | return; | 573 | return; |
| 574 | } | ||
| 566 | 575 | ||
| 567 | /* set the packetizer registers */ | 576 | /* set the packetizer registers */ |
| 568 | val = ((color_depth << HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET) & | 577 | val = ((color_depth << HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET) & |
| @@ -622,182 +631,132 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi) | |||
| 622 | HDMI_VP_CONF); | 631 | HDMI_VP_CONF); |
| 623 | } | 632 | } |
| 624 | 633 | ||
| 625 | static inline void hdmi_phy_test_clear(struct imx_hdmi *hdmi, | 634 | static inline void hdmi_phy_test_clear(struct dw_hdmi *hdmi, |
| 626 | unsigned char bit) | 635 | unsigned char bit) |
| 627 | { | 636 | { |
| 628 | hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLR_OFFSET, | 637 | hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLR_OFFSET, |
| 629 | HDMI_PHY_TST0_TSTCLR_MASK, HDMI_PHY_TST0); | 638 | HDMI_PHY_TST0_TSTCLR_MASK, HDMI_PHY_TST0); |
| 630 | } | 639 | } |
| 631 | 640 | ||
| 632 | static inline void hdmi_phy_test_enable(struct imx_hdmi *hdmi, | 641 | static inline void hdmi_phy_test_enable(struct dw_hdmi *hdmi, |
| 633 | unsigned char bit) | 642 | unsigned char bit) |
| 634 | { | 643 | { |
| 635 | hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTEN_OFFSET, | 644 | hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTEN_OFFSET, |
| 636 | HDMI_PHY_TST0_TSTEN_MASK, HDMI_PHY_TST0); | 645 | HDMI_PHY_TST0_TSTEN_MASK, HDMI_PHY_TST0); |
| 637 | } | 646 | } |
| 638 | 647 | ||
| 639 | static inline void hdmi_phy_test_clock(struct imx_hdmi *hdmi, | 648 | static inline void hdmi_phy_test_clock(struct dw_hdmi *hdmi, |
| 640 | unsigned char bit) | 649 | unsigned char bit) |
| 641 | { | 650 | { |
| 642 | hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLK_OFFSET, | 651 | hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLK_OFFSET, |
| 643 | HDMI_PHY_TST0_TSTCLK_MASK, HDMI_PHY_TST0); | 652 | HDMI_PHY_TST0_TSTCLK_MASK, HDMI_PHY_TST0); |
| 644 | } | 653 | } |
| 645 | 654 | ||
| 646 | static inline void hdmi_phy_test_din(struct imx_hdmi *hdmi, | 655 | static inline void hdmi_phy_test_din(struct dw_hdmi *hdmi, |
| 647 | unsigned char bit) | 656 | unsigned char bit) |
| 648 | { | 657 | { |
| 649 | hdmi_writeb(hdmi, bit, HDMI_PHY_TST1); | 658 | hdmi_writeb(hdmi, bit, HDMI_PHY_TST1); |
| 650 | } | 659 | } |
| 651 | 660 | ||
| 652 | static inline void hdmi_phy_test_dout(struct imx_hdmi *hdmi, | 661 | static inline void hdmi_phy_test_dout(struct dw_hdmi *hdmi, |
| 653 | unsigned char bit) | 662 | unsigned char bit) |
| 654 | { | 663 | { |
| 655 | hdmi_writeb(hdmi, bit, HDMI_PHY_TST2); | 664 | hdmi_writeb(hdmi, bit, HDMI_PHY_TST2); |
| 656 | } | 665 | } |
| 657 | 666 | ||
| 658 | static bool hdmi_phy_wait_i2c_done(struct imx_hdmi *hdmi, int msec) | 667 | static bool hdmi_phy_wait_i2c_done(struct dw_hdmi *hdmi, int msec) |
| 659 | { | 668 | { |
| 660 | while ((hdmi_readb(hdmi, HDMI_IH_I2CMPHY_STAT0) & 0x3) == 0) { | 669 | u32 val; |
| 670 | |||
| 671 | while ((val = hdmi_readb(hdmi, HDMI_IH_I2CMPHY_STAT0) & 0x3) == 0) { | ||
| 661 | if (msec-- == 0) | 672 | if (msec-- == 0) |
| 662 | return false; | 673 | return false; |
| 663 | udelay(1000); | 674 | udelay(1000); |
| 664 | } | 675 | } |
| 676 | hdmi_writeb(hdmi, val, HDMI_IH_I2CMPHY_STAT0); | ||
| 677 | |||
| 665 | return true; | 678 | return true; |
| 666 | } | 679 | } |
| 667 | 680 | ||
| 668 | static void __hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data, | 681 | static void __hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data, |
| 669 | unsigned char addr) | 682 | unsigned char addr) |
| 670 | { | 683 | { |
| 671 | hdmi_writeb(hdmi, 0xFF, HDMI_IH_I2CMPHY_STAT0); | 684 | hdmi_writeb(hdmi, 0xFF, HDMI_IH_I2CMPHY_STAT0); |
| 672 | hdmi_writeb(hdmi, addr, HDMI_PHY_I2CM_ADDRESS_ADDR); | 685 | hdmi_writeb(hdmi, addr, HDMI_PHY_I2CM_ADDRESS_ADDR); |
| 673 | hdmi_writeb(hdmi, (unsigned char)(data >> 8), | 686 | hdmi_writeb(hdmi, (unsigned char)(data >> 8), |
| 674 | HDMI_PHY_I2CM_DATAO_1_ADDR); | 687 | HDMI_PHY_I2CM_DATAO_1_ADDR); |
| 675 | hdmi_writeb(hdmi, (unsigned char)(data >> 0), | 688 | hdmi_writeb(hdmi, (unsigned char)(data >> 0), |
| 676 | HDMI_PHY_I2CM_DATAO_0_ADDR); | 689 | HDMI_PHY_I2CM_DATAO_0_ADDR); |
| 677 | hdmi_writeb(hdmi, HDMI_PHY_I2CM_OPERATION_ADDR_WRITE, | 690 | hdmi_writeb(hdmi, HDMI_PHY_I2CM_OPERATION_ADDR_WRITE, |
| 678 | HDMI_PHY_I2CM_OPERATION_ADDR); | 691 | HDMI_PHY_I2CM_OPERATION_ADDR); |
| 679 | hdmi_phy_wait_i2c_done(hdmi, 1000); | 692 | hdmi_phy_wait_i2c_done(hdmi, 1000); |
| 680 | } | 693 | } |
| 681 | 694 | ||
| 682 | static int hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data, | 695 | static int hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data, |
| 683 | unsigned char addr) | 696 | unsigned char addr) |
| 684 | { | 697 | { |
| 685 | __hdmi_phy_i2c_write(hdmi, data, addr); | 698 | __hdmi_phy_i2c_write(hdmi, data, addr); |
| 686 | return 0; | 699 | return 0; |
| 687 | } | 700 | } |
| 688 | 701 | ||
| 689 | static void imx_hdmi_phy_enable_power(struct imx_hdmi *hdmi, u8 enable) | 702 | static void dw_hdmi_phy_enable_power(struct dw_hdmi *hdmi, u8 enable) |
| 690 | { | 703 | { |
| 691 | hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0, | 704 | hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0, |
| 692 | HDMI_PHY_CONF0_PDZ_OFFSET, | 705 | HDMI_PHY_CONF0_PDZ_OFFSET, |
| 693 | HDMI_PHY_CONF0_PDZ_MASK); | 706 | HDMI_PHY_CONF0_PDZ_MASK); |
| 694 | } | 707 | } |
| 695 | 708 | ||
| 696 | static void imx_hdmi_phy_enable_tmds(struct imx_hdmi *hdmi, u8 enable) | 709 | static void dw_hdmi_phy_enable_tmds(struct dw_hdmi *hdmi, u8 enable) |
| 697 | { | 710 | { |
| 698 | hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0, | 711 | hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0, |
| 699 | HDMI_PHY_CONF0_ENTMDS_OFFSET, | 712 | HDMI_PHY_CONF0_ENTMDS_OFFSET, |
| 700 | HDMI_PHY_CONF0_ENTMDS_MASK); | 713 | HDMI_PHY_CONF0_ENTMDS_MASK); |
| 701 | } | 714 | } |
| 702 | 715 | ||
| 703 | static void imx_hdmi_phy_gen2_pddq(struct imx_hdmi *hdmi, u8 enable) | 716 | static void dw_hdmi_phy_enable_spare(struct dw_hdmi *hdmi, u8 enable) |
| 717 | { | ||
| 718 | hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0, | ||
| 719 | HDMI_PHY_CONF0_SPARECTRL_OFFSET, | ||
| 720 | HDMI_PHY_CONF0_SPARECTRL_MASK); | ||
| 721 | } | ||
| 722 | |||
| 723 | static void dw_hdmi_phy_gen2_pddq(struct dw_hdmi *hdmi, u8 enable) | ||
| 704 | { | 724 | { |
| 705 | hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0, | 725 | hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0, |
| 706 | HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET, | 726 | HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET, |
| 707 | HDMI_PHY_CONF0_GEN2_PDDQ_MASK); | 727 | HDMI_PHY_CONF0_GEN2_PDDQ_MASK); |
| 708 | } | 728 | } |
| 709 | 729 | ||
| 710 | static void imx_hdmi_phy_gen2_txpwron(struct imx_hdmi *hdmi, u8 enable) | 730 | static void dw_hdmi_phy_gen2_txpwron(struct dw_hdmi *hdmi, u8 enable) |
| 711 | { | 731 | { |
| 712 | hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0, | 732 | hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0, |
| 713 | HDMI_PHY_CONF0_GEN2_TXPWRON_OFFSET, | 733 | HDMI_PHY_CONF0_GEN2_TXPWRON_OFFSET, |
| 714 | HDMI_PHY_CONF0_GEN2_TXPWRON_MASK); | 734 | HDMI_PHY_CONF0_GEN2_TXPWRON_MASK); |
| 715 | } | 735 | } |
| 716 | 736 | ||
| 717 | static void imx_hdmi_phy_sel_data_en_pol(struct imx_hdmi *hdmi, u8 enable) | 737 | static void dw_hdmi_phy_sel_data_en_pol(struct dw_hdmi *hdmi, u8 enable) |
| 718 | { | 738 | { |
| 719 | hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0, | 739 | hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0, |
| 720 | HDMI_PHY_CONF0_SELDATAENPOL_OFFSET, | 740 | HDMI_PHY_CONF0_SELDATAENPOL_OFFSET, |
| 721 | HDMI_PHY_CONF0_SELDATAENPOL_MASK); | 741 | HDMI_PHY_CONF0_SELDATAENPOL_MASK); |
| 722 | } | 742 | } |
| 723 | 743 | ||
| 724 | static void imx_hdmi_phy_sel_interface_control(struct imx_hdmi *hdmi, u8 enable) | 744 | static void dw_hdmi_phy_sel_interface_control(struct dw_hdmi *hdmi, u8 enable) |
| 725 | { | 745 | { |
| 726 | hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0, | 746 | hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0, |
| 727 | HDMI_PHY_CONF0_SELDIPIF_OFFSET, | 747 | HDMI_PHY_CONF0_SELDIPIF_OFFSET, |
| 728 | HDMI_PHY_CONF0_SELDIPIF_MASK); | 748 | HDMI_PHY_CONF0_SELDIPIF_MASK); |
| 729 | } | 749 | } |
| 730 | 750 | ||
| 731 | enum { | 751 | static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep, |
| 732 | RES_8, | ||
| 733 | RES_10, | ||
| 734 | RES_12, | ||
| 735 | RES_MAX, | ||
| 736 | }; | ||
| 737 | |||
| 738 | struct mpll_config { | ||
| 739 | unsigned long mpixelclock; | ||
| 740 | struct { | ||
| 741 | u16 cpce; | ||
| 742 | u16 gmp; | ||
| 743 | } res[RES_MAX]; | ||
| 744 | }; | ||
| 745 | |||
| 746 | static const struct mpll_config mpll_config[] = { | ||
| 747 | { | ||
| 748 | 45250000, { | ||
| 749 | { 0x01e0, 0x0000 }, | ||
| 750 | { 0x21e1, 0x0000 }, | ||
| 751 | { 0x41e2, 0x0000 } | ||
| 752 | }, | ||
| 753 | }, { | ||
| 754 | 92500000, { | ||
| 755 | { 0x0140, 0x0005 }, | ||
| 756 | { 0x2141, 0x0005 }, | ||
| 757 | { 0x4142, 0x0005 }, | ||
| 758 | }, | ||
| 759 | }, { | ||
| 760 | 148500000, { | ||
| 761 | { 0x00a0, 0x000a }, | ||
| 762 | { 0x20a1, 0x000a }, | ||
| 763 | { 0x40a2, 0x000a }, | ||
| 764 | }, | ||
| 765 | }, { | ||
| 766 | ~0UL, { | ||
| 767 | { 0x00a0, 0x000a }, | ||
| 768 | { 0x2001, 0x000f }, | ||
| 769 | { 0x4002, 0x000f }, | ||
| 770 | }, | ||
| 771 | } | ||
| 772 | }; | ||
| 773 | |||
| 774 | struct curr_ctrl { | ||
| 775 | unsigned long mpixelclock; | ||
| 776 | u16 curr[RES_MAX]; | ||
| 777 | }; | ||
| 778 | |||
| 779 | static const struct curr_ctrl curr_ctrl[] = { | ||
| 780 | /* pixelclk bpp8 bpp10 bpp12 */ | ||
| 781 | { | ||
| 782 | 54000000, { 0x091c, 0x091c, 0x06dc }, | ||
| 783 | }, { | ||
| 784 | 58400000, { 0x091c, 0x06dc, 0x06dc }, | ||
| 785 | }, { | ||
| 786 | 72000000, { 0x06dc, 0x06dc, 0x091c }, | ||
| 787 | }, { | ||
| 788 | 74250000, { 0x06dc, 0x0b5c, 0x091c }, | ||
| 789 | }, { | ||
| 790 | 118800000, { 0x091c, 0x091c, 0x06dc }, | ||
| 791 | }, { | ||
| 792 | 216000000, { 0x06dc, 0x0b5c, 0x091c }, | ||
| 793 | } | ||
| 794 | }; | ||
| 795 | |||
| 796 | static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep, | ||
| 797 | unsigned char res, int cscon) | 752 | unsigned char res, int cscon) |
| 798 | { | 753 | { |
| 799 | unsigned res_idx, i; | 754 | unsigned res_idx, i; |
| 800 | u8 val, msec; | 755 | u8 val, msec; |
| 756 | const struct dw_hdmi_mpll_config *mpll_config = | ||
| 757 | hdmi->plat_data->mpll_cfg; | ||
| 758 | const struct dw_hdmi_curr_ctrl *curr_ctrl = hdmi->plat_data->cur_ctr; | ||
| 759 | const struct dw_hdmi_sym_term *sym_term = hdmi->plat_data->sym_term; | ||
| 801 | 760 | ||
| 802 | if (prep) | 761 | if (prep) |
| 803 | return -EINVAL; | 762 | return -EINVAL; |
| @@ -805,13 +764,13 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep, | |||
| 805 | switch (res) { | 764 | switch (res) { |
| 806 | case 0: /* color resolution 0 is 8 bit colour depth */ | 765 | case 0: /* color resolution 0 is 8 bit colour depth */ |
| 807 | case 8: | 766 | case 8: |
| 808 | res_idx = RES_8; | 767 | res_idx = DW_HDMI_RES_8; |
| 809 | break; | 768 | break; |
| 810 | case 10: | 769 | case 10: |
| 811 | res_idx = RES_10; | 770 | res_idx = DW_HDMI_RES_10; |
| 812 | break; | 771 | break; |
| 813 | case 12: | 772 | case 12: |
| 814 | res_idx = RES_12; | 773 | res_idx = DW_HDMI_RES_12; |
| 815 | break; | 774 | break; |
| 816 | default: | 775 | default: |
| 817 | return -EINVAL; | 776 | return -EINVAL; |
| @@ -826,10 +785,10 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep, | |||
| 826 | hdmi_writeb(hdmi, val, HDMI_MC_FLOWCTRL); | 785 | hdmi_writeb(hdmi, val, HDMI_MC_FLOWCTRL); |
| 827 | 786 | ||
| 828 | /* gen2 tx power off */ | 787 | /* gen2 tx power off */ |
| 829 | imx_hdmi_phy_gen2_txpwron(hdmi, 0); | 788 | dw_hdmi_phy_gen2_txpwron(hdmi, 0); |
| 830 | 789 | ||
| 831 | /* gen2 pddq */ | 790 | /* gen2 pddq */ |
| 832 | imx_hdmi_phy_gen2_pddq(hdmi, 1); | 791 | dw_hdmi_phy_gen2_pddq(hdmi, 1); |
| 833 | 792 | ||
| 834 | /* PHY reset */ | 793 | /* PHY reset */ |
| 835 | hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_DEASSERT, HDMI_MC_PHYRSTZ); | 794 | hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_DEASSERT, HDMI_MC_PHYRSTZ); |
| @@ -839,11 +798,11 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep, | |||
| 839 | 798 | ||
| 840 | hdmi_phy_test_clear(hdmi, 1); | 799 | hdmi_phy_test_clear(hdmi, 1); |
| 841 | hdmi_writeb(hdmi, HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2, | 800 | hdmi_writeb(hdmi, HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2, |
| 842 | HDMI_PHY_I2CM_SLAVE_ADDR); | 801 | HDMI_PHY_I2CM_SLAVE_ADDR); |
| 843 | hdmi_phy_test_clear(hdmi, 0); | 802 | hdmi_phy_test_clear(hdmi, 0); |
| 844 | 803 | ||
| 845 | /* PLL/MPLL Cfg - always match on final entry */ | 804 | /* PLL/MPLL Cfg - always match on final entry */ |
| 846 | for (i = 0; i < ARRAY_SIZE(mpll_config) - 1; i++) | 805 | for (i = 0; mpll_config[i].mpixelclock != (~0UL); i++) |
| 847 | if (hdmi->hdmi_data.video_mode.mpixelclock <= | 806 | if (hdmi->hdmi_data.video_mode.mpixelclock <= |
| 848 | mpll_config[i].mpixelclock) | 807 | mpll_config[i].mpixelclock) |
| 849 | break; | 808 | break; |
| @@ -851,15 +810,14 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep, | |||
| 851 | hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].cpce, 0x06); | 810 | hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].cpce, 0x06); |
| 852 | hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].gmp, 0x15); | 811 | hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].gmp, 0x15); |
| 853 | 812 | ||
| 854 | for (i = 0; i < ARRAY_SIZE(curr_ctrl); i++) | 813 | for (i = 0; curr_ctrl[i].mpixelclock != (~0UL); i++) |
| 855 | if (hdmi->hdmi_data.video_mode.mpixelclock <= | 814 | if (hdmi->hdmi_data.video_mode.mpixelclock <= |
| 856 | curr_ctrl[i].mpixelclock) | 815 | curr_ctrl[i].mpixelclock) |
| 857 | break; | 816 | break; |
| 858 | 817 | ||
| 859 | if (i >= ARRAY_SIZE(curr_ctrl)) { | 818 | if (curr_ctrl[i].mpixelclock == (~0UL)) { |
| 860 | dev_err(hdmi->dev, | 819 | dev_err(hdmi->dev, "Pixel clock %d - unsupported by HDMI\n", |
| 861 | "Pixel clock %d - unsupported by HDMI\n", | 820 | hdmi->hdmi_data.video_mode.mpixelclock); |
| 862 | hdmi->hdmi_data.video_mode.mpixelclock); | ||
| 863 | return -EINVAL; | 821 | return -EINVAL; |
| 864 | } | 822 | } |
| 865 | 823 | ||
| @@ -868,24 +826,34 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep, | |||
| 868 | 826 | ||
| 869 | hdmi_phy_i2c_write(hdmi, 0x0000, 0x13); /* PLLPHBYCTRL */ | 827 | hdmi_phy_i2c_write(hdmi, 0x0000, 0x13); /* PLLPHBYCTRL */ |
| 870 | hdmi_phy_i2c_write(hdmi, 0x0006, 0x17); | 828 | hdmi_phy_i2c_write(hdmi, 0x0006, 0x17); |
| 829 | |||
| 830 | for (i = 0; sym_term[i].mpixelclock != (~0UL); i++) | ||
| 831 | if (hdmi->hdmi_data.video_mode.mpixelclock <= | ||
| 832 | sym_term[i].mpixelclock) | ||
| 833 | break; | ||
| 834 | |||
| 871 | /* RESISTANCE TERM 133Ohm Cfg */ | 835 | /* RESISTANCE TERM 133Ohm Cfg */ |
| 872 | hdmi_phy_i2c_write(hdmi, 0x0005, 0x19); /* TXTERM */ | 836 | hdmi_phy_i2c_write(hdmi, sym_term[i].term, 0x19); /* TXTERM */ |
| 873 | /* PREEMP Cgf 0.00 */ | 837 | /* PREEMP Cgf 0.00 */ |
| 874 | hdmi_phy_i2c_write(hdmi, 0x800d, 0x09); /* CKSYMTXCTRL */ | 838 | hdmi_phy_i2c_write(hdmi, sym_term[i].sym_ctr, 0x09); /* CKSYMTXCTRL */ |
| 839 | |||
| 875 | /* TX/CK LVL 10 */ | 840 | /* TX/CK LVL 10 */ |
| 876 | hdmi_phy_i2c_write(hdmi, 0x01ad, 0x0E); /* VLEVCTRL */ | 841 | hdmi_phy_i2c_write(hdmi, 0x01ad, 0x0E); /* VLEVCTRL */ |
| 877 | /* REMOVE CLK TERM */ | 842 | /* REMOVE CLK TERM */ |
| 878 | hdmi_phy_i2c_write(hdmi, 0x8000, 0x05); /* CKCALCTRL */ | 843 | hdmi_phy_i2c_write(hdmi, 0x8000, 0x05); /* CKCALCTRL */ |
| 879 | 844 | ||
| 880 | imx_hdmi_phy_enable_power(hdmi, 1); | 845 | dw_hdmi_phy_enable_power(hdmi, 1); |
| 881 | 846 | ||
| 882 | /* toggle TMDS enable */ | 847 | /* toggle TMDS enable */ |
| 883 | imx_hdmi_phy_enable_tmds(hdmi, 0); | 848 | dw_hdmi_phy_enable_tmds(hdmi, 0); |
| 884 | imx_hdmi_phy_enable_tmds(hdmi, 1); | 849 | dw_hdmi_phy_enable_tmds(hdmi, 1); |
| 885 | 850 | ||
| 886 | /* gen2 tx power on */ | 851 | /* gen2 tx power on */ |
| 887 | imx_hdmi_phy_gen2_txpwron(hdmi, 1); | 852 | dw_hdmi_phy_gen2_txpwron(hdmi, 1); |
| 888 | imx_hdmi_phy_gen2_pddq(hdmi, 0); | 853 | dw_hdmi_phy_gen2_pddq(hdmi, 0); |
| 854 | |||
| 855 | if (hdmi->dev_type == RK3288_HDMI) | ||
| 856 | dw_hdmi_phy_enable_spare(hdmi, 1); | ||
| 889 | 857 | ||
| 890 | /*Wait for PHY PLL lock */ | 858 | /*Wait for PHY PLL lock */ |
| 891 | msec = 5; | 859 | msec = 5; |
| @@ -906,7 +874,7 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep, | |||
| 906 | return 0; | 874 | return 0; |
| 907 | } | 875 | } |
| 908 | 876 | ||
| 909 | static int imx_hdmi_phy_init(struct imx_hdmi *hdmi) | 877 | static int dw_hdmi_phy_init(struct dw_hdmi *hdmi) |
| 910 | { | 878 | { |
| 911 | int i, ret; | 879 | int i, ret; |
| 912 | bool cscon = false; | 880 | bool cscon = false; |
| @@ -917,10 +885,10 @@ static int imx_hdmi_phy_init(struct imx_hdmi *hdmi) | |||
| 917 | 885 | ||
| 918 | /* HDMI Phy spec says to do the phy initialization sequence twice */ | 886 | /* HDMI Phy spec says to do the phy initialization sequence twice */ |
| 919 | for (i = 0; i < 2; i++) { | 887 | for (i = 0; i < 2; i++) { |
| 920 | imx_hdmi_phy_sel_data_en_pol(hdmi, 1); | 888 | dw_hdmi_phy_sel_data_en_pol(hdmi, 1); |
| 921 | imx_hdmi_phy_sel_interface_control(hdmi, 0); | 889 | dw_hdmi_phy_sel_interface_control(hdmi, 0); |
| 922 | imx_hdmi_phy_enable_tmds(hdmi, 0); | 890 | dw_hdmi_phy_enable_tmds(hdmi, 0); |
| 923 | imx_hdmi_phy_enable_power(hdmi, 0); | 891 | dw_hdmi_phy_enable_power(hdmi, 0); |
| 924 | 892 | ||
| 925 | /* Enable CSC */ | 893 | /* Enable CSC */ |
| 926 | ret = hdmi_phy_configure(hdmi, 0, 8, cscon); | 894 | ret = hdmi_phy_configure(hdmi, 0, 8, cscon); |
| @@ -932,7 +900,7 @@ static int imx_hdmi_phy_init(struct imx_hdmi *hdmi) | |||
| 932 | return 0; | 900 | return 0; |
| 933 | } | 901 | } |
| 934 | 902 | ||
| 935 | static void hdmi_tx_hdcp_config(struct imx_hdmi *hdmi) | 903 | static void hdmi_tx_hdcp_config(struct dw_hdmi *hdmi) |
| 936 | { | 904 | { |
| 937 | u8 de; | 905 | u8 de; |
| 938 | 906 | ||
| @@ -951,7 +919,7 @@ static void hdmi_tx_hdcp_config(struct imx_hdmi *hdmi) | |||
| 951 | HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK, HDMI_A_HDCPCFG1); | 919 | HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK, HDMI_A_HDCPCFG1); |
| 952 | } | 920 | } |
| 953 | 921 | ||
| 954 | static void hdmi_config_AVI(struct imx_hdmi *hdmi) | 922 | static void hdmi_config_AVI(struct dw_hdmi *hdmi) |
| 955 | { | 923 | { |
| 956 | u8 val, pix_fmt, under_scan; | 924 | u8 val, pix_fmt, under_scan; |
| 957 | u8 act_ratio, coded_ratio, colorimetry, ext_colorimetry; | 925 | u8 act_ratio, coded_ratio, colorimetry, ext_colorimetry; |
| @@ -1045,7 +1013,7 @@ static void hdmi_config_AVI(struct imx_hdmi *hdmi) | |||
| 1045 | hdmi_writeb(hdmi, 0, HDMI_FC_AVISRB1); | 1013 | hdmi_writeb(hdmi, 0, HDMI_FC_AVISRB1); |
| 1046 | } | 1014 | } |
| 1047 | 1015 | ||
| 1048 | static void hdmi_av_composer(struct imx_hdmi *hdmi, | 1016 | static void hdmi_av_composer(struct dw_hdmi *hdmi, |
| 1049 | const struct drm_display_mode *mode) | 1017 | const struct drm_display_mode *mode) |
| 1050 | { | 1018 | { |
| 1051 | u8 inv_val; | 1019 | u8 inv_val; |
| @@ -1129,19 +1097,19 @@ static void hdmi_av_composer(struct imx_hdmi *hdmi, | |||
| 1129 | hdmi_writeb(hdmi, vsync_len, HDMI_FC_VSYNCINWIDTH); | 1097 | hdmi_writeb(hdmi, vsync_len, HDMI_FC_VSYNCINWIDTH); |
| 1130 | } | 1098 | } |
| 1131 | 1099 | ||
| 1132 | static void imx_hdmi_phy_disable(struct imx_hdmi *hdmi) | 1100 | static void dw_hdmi_phy_disable(struct dw_hdmi *hdmi) |
| 1133 | { | 1101 | { |
| 1134 | if (!hdmi->phy_enabled) | 1102 | if (!hdmi->phy_enabled) |
| 1135 | return; | 1103 | return; |
| 1136 | 1104 | ||
| 1137 | imx_hdmi_phy_enable_tmds(hdmi, 0); | 1105 | dw_hdmi_phy_enable_tmds(hdmi, 0); |
| 1138 | imx_hdmi_phy_enable_power(hdmi, 0); | 1106 | dw_hdmi_phy_enable_power(hdmi, 0); |
| 1139 | 1107 | ||
| 1140 | hdmi->phy_enabled = false; | 1108 | hdmi->phy_enabled = false; |
| 1141 | } | 1109 | } |
| 1142 | 1110 | ||
| 1143 | /* HDMI Initialization Step B.4 */ | 1111 | /* HDMI Initialization Step B.4 */ |
| 1144 | static void imx_hdmi_enable_video_path(struct imx_hdmi *hdmi) | 1112 | static void dw_hdmi_enable_video_path(struct dw_hdmi *hdmi) |
| 1145 | { | 1113 | { |
| 1146 | u8 clkdis; | 1114 | u8 clkdis; |
| 1147 | 1115 | ||
| @@ -1170,13 +1138,13 @@ static void imx_hdmi_enable_video_path(struct imx_hdmi *hdmi) | |||
| 1170 | } | 1138 | } |
| 1171 | } | 1139 | } |
| 1172 | 1140 | ||
| 1173 | static void hdmi_enable_audio_clk(struct imx_hdmi *hdmi) | 1141 | static void hdmi_enable_audio_clk(struct dw_hdmi *hdmi) |
| 1174 | { | 1142 | { |
| 1175 | hdmi_modb(hdmi, 0, HDMI_MC_CLKDIS_AUDCLK_DISABLE, HDMI_MC_CLKDIS); | 1143 | hdmi_modb(hdmi, 0, HDMI_MC_CLKDIS_AUDCLK_DISABLE, HDMI_MC_CLKDIS); |
| 1176 | } | 1144 | } |
| 1177 | 1145 | ||
| 1178 | /* Workaround to clear the overflow condition */ | 1146 | /* Workaround to clear the overflow condition */ |
| 1179 | static void imx_hdmi_clear_overflow(struct imx_hdmi *hdmi) | 1147 | static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi) |
| 1180 | { | 1148 | { |
| 1181 | int count; | 1149 | int count; |
| 1182 | u8 val; | 1150 | u8 val; |
| @@ -1194,19 +1162,19 @@ static void imx_hdmi_clear_overflow(struct imx_hdmi *hdmi) | |||
| 1194 | hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF); | 1162 | hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF); |
| 1195 | } | 1163 | } |
| 1196 | 1164 | ||
| 1197 | static void hdmi_enable_overflow_interrupts(struct imx_hdmi *hdmi) | 1165 | static void hdmi_enable_overflow_interrupts(struct dw_hdmi *hdmi) |
| 1198 | { | 1166 | { |
| 1199 | hdmi_writeb(hdmi, 0, HDMI_FC_MASK2); | 1167 | hdmi_writeb(hdmi, 0, HDMI_FC_MASK2); |
| 1200 | hdmi_writeb(hdmi, 0, HDMI_IH_MUTE_FC_STAT2); | 1168 | hdmi_writeb(hdmi, 0, HDMI_IH_MUTE_FC_STAT2); |
| 1201 | } | 1169 | } |
| 1202 | 1170 | ||
| 1203 | static void hdmi_disable_overflow_interrupts(struct imx_hdmi *hdmi) | 1171 | static void hdmi_disable_overflow_interrupts(struct dw_hdmi *hdmi) |
| 1204 | { | 1172 | { |
| 1205 | hdmi_writeb(hdmi, HDMI_IH_MUTE_FC_STAT2_OVERFLOW_MASK, | 1173 | hdmi_writeb(hdmi, HDMI_IH_MUTE_FC_STAT2_OVERFLOW_MASK, |
| 1206 | HDMI_IH_MUTE_FC_STAT2); | 1174 | HDMI_IH_MUTE_FC_STAT2); |
| 1207 | } | 1175 | } |
| 1208 | 1176 | ||
| 1209 | static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode) | 1177 | static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode) |
| 1210 | { | 1178 | { |
| 1211 | int ret; | 1179 | int ret; |
| 1212 | 1180 | ||
| @@ -1223,21 +1191,21 @@ static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode) | |||
| 1223 | } | 1191 | } |
| 1224 | 1192 | ||
| 1225 | if ((hdmi->vic == 6) || (hdmi->vic == 7) || | 1193 | if ((hdmi->vic == 6) || (hdmi->vic == 7) || |
| 1226 | (hdmi->vic == 21) || (hdmi->vic == 22) || | 1194 | (hdmi->vic == 21) || (hdmi->vic == 22) || |
| 1227 | (hdmi->vic == 2) || (hdmi->vic == 3) || | 1195 | (hdmi->vic == 2) || (hdmi->vic == 3) || |
| 1228 | (hdmi->vic == 17) || (hdmi->vic == 18)) | 1196 | (hdmi->vic == 17) || (hdmi->vic == 18)) |
| 1229 | hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_601; | 1197 | hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_601; |
| 1230 | else | 1198 | else |
| 1231 | hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_709; | 1199 | hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_709; |
| 1232 | 1200 | ||
| 1233 | if ((hdmi->vic == 10) || (hdmi->vic == 11) || | 1201 | if ((hdmi->vic == 10) || (hdmi->vic == 11) || |
| 1234 | (hdmi->vic == 12) || (hdmi->vic == 13) || | 1202 | (hdmi->vic == 12) || (hdmi->vic == 13) || |
| 1235 | (hdmi->vic == 14) || (hdmi->vic == 15) || | 1203 | (hdmi->vic == 14) || (hdmi->vic == 15) || |
| 1236 | (hdmi->vic == 25) || (hdmi->vic == 26) || | 1204 | (hdmi->vic == 25) || (hdmi->vic == 26) || |
| 1237 | (hdmi->vic == 27) || (hdmi->vic == 28) || | 1205 | (hdmi->vic == 27) || (hdmi->vic == 28) || |
| 1238 | (hdmi->vic == 29) || (hdmi->vic == 30) || | 1206 | (hdmi->vic == 29) || (hdmi->vic == 30) || |
| 1239 | (hdmi->vic == 35) || (hdmi->vic == 36) || | 1207 | (hdmi->vic == 35) || (hdmi->vic == 36) || |
| 1240 | (hdmi->vic == 37) || (hdmi->vic == 38)) | 1208 | (hdmi->vic == 37) || (hdmi->vic == 38)) |
| 1241 | hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 1; | 1209 | hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 1; |
| 1242 | else | 1210 | else |
| 1243 | hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 0; | 1211 | hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 0; |
| @@ -1258,17 +1226,17 @@ static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode) | |||
| 1258 | hdmi_av_composer(hdmi, mode); | 1226 | hdmi_av_composer(hdmi, mode); |
| 1259 | 1227 | ||
| 1260 | /* HDMI Initializateion Step B.2 */ | 1228 | /* HDMI Initializateion Step B.2 */ |
| 1261 | ret = imx_hdmi_phy_init(hdmi); | 1229 | ret = dw_hdmi_phy_init(hdmi); |
| 1262 | if (ret) | 1230 | if (ret) |
| 1263 | return ret; | 1231 | return ret; |
| 1264 | 1232 | ||
| 1265 | /* HDMI Initialization Step B.3 */ | 1233 | /* HDMI Initialization Step B.3 */ |
| 1266 | imx_hdmi_enable_video_path(hdmi); | 1234 | dw_hdmi_enable_video_path(hdmi); |
| 1267 | 1235 | ||
| 1268 | /* not for DVI mode */ | 1236 | /* not for DVI mode */ |
| 1269 | if (hdmi->hdmi_data.video_mode.mdvi) | 1237 | if (hdmi->hdmi_data.video_mode.mdvi) { |
| 1270 | dev_dbg(hdmi->dev, "%s DVI mode\n", __func__); | 1238 | dev_dbg(hdmi->dev, "%s DVI mode\n", __func__); |
| 1271 | else { | 1239 | } else { |
| 1272 | dev_dbg(hdmi->dev, "%s CEA mode\n", __func__); | 1240 | dev_dbg(hdmi->dev, "%s CEA mode\n", __func__); |
| 1273 | 1241 | ||
| 1274 | /* HDMI Initialization Step E - Configure audio */ | 1242 | /* HDMI Initialization Step E - Configure audio */ |
| @@ -1284,7 +1252,7 @@ static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode) | |||
| 1284 | hdmi_video_sample(hdmi); | 1252 | hdmi_video_sample(hdmi); |
| 1285 | hdmi_tx_hdcp_config(hdmi); | 1253 | hdmi_tx_hdcp_config(hdmi); |
| 1286 | 1254 | ||
| 1287 | imx_hdmi_clear_overflow(hdmi); | 1255 | dw_hdmi_clear_overflow(hdmi); |
| 1288 | if (hdmi->cable_plugin && !hdmi->hdmi_data.video_mode.mdvi) | 1256 | if (hdmi->cable_plugin && !hdmi->hdmi_data.video_mode.mdvi) |
| 1289 | hdmi_enable_overflow_interrupts(hdmi); | 1257 | hdmi_enable_overflow_interrupts(hdmi); |
| 1290 | 1258 | ||
| @@ -1292,7 +1260,7 @@ static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode) | |||
| 1292 | } | 1260 | } |
| 1293 | 1261 | ||
| 1294 | /* Wait until we are registered to enable interrupts */ | 1262 | /* Wait until we are registered to enable interrupts */ |
| 1295 | static int imx_hdmi_fb_registered(struct imx_hdmi *hdmi) | 1263 | static int dw_hdmi_fb_registered(struct dw_hdmi *hdmi) |
| 1296 | { | 1264 | { |
| 1297 | hdmi_writeb(hdmi, HDMI_PHY_I2CM_INT_ADDR_DONE_POL, | 1265 | hdmi_writeb(hdmi, HDMI_PHY_I2CM_INT_ADDR_DONE_POL, |
| 1298 | HDMI_PHY_I2CM_INT_ADDR); | 1266 | HDMI_PHY_I2CM_INT_ADDR); |
| @@ -1310,7 +1278,7 @@ static int imx_hdmi_fb_registered(struct imx_hdmi *hdmi) | |||
| 1310 | return 0; | 1278 | return 0; |
| 1311 | } | 1279 | } |
| 1312 | 1280 | ||
| 1313 | static void initialize_hdmi_ih_mutes(struct imx_hdmi *hdmi) | 1281 | static void initialize_hdmi_ih_mutes(struct dw_hdmi *hdmi) |
| 1314 | { | 1282 | { |
| 1315 | u8 ih_mute; | 1283 | u8 ih_mute; |
| 1316 | 1284 | ||
| @@ -1362,29 +1330,73 @@ static void initialize_hdmi_ih_mutes(struct imx_hdmi *hdmi) | |||
| 1362 | hdmi_writeb(hdmi, ih_mute, HDMI_IH_MUTE); | 1330 | hdmi_writeb(hdmi, ih_mute, HDMI_IH_MUTE); |
| 1363 | } | 1331 | } |
| 1364 | 1332 | ||
| 1365 | static void imx_hdmi_poweron(struct imx_hdmi *hdmi) | 1333 | static void dw_hdmi_poweron(struct dw_hdmi *hdmi) |
| 1334 | { | ||
| 1335 | dw_hdmi_setup(hdmi, &hdmi->previous_mode); | ||
| 1336 | } | ||
| 1337 | |||
| 1338 | static void dw_hdmi_poweroff(struct dw_hdmi *hdmi) | ||
| 1339 | { | ||
| 1340 | dw_hdmi_phy_disable(hdmi); | ||
| 1341 | } | ||
| 1342 | |||
| 1343 | static void dw_hdmi_bridge_mode_set(struct drm_bridge *bridge, | ||
| 1344 | struct drm_display_mode *orig_mode, | ||
| 1345 | struct drm_display_mode *mode) | ||
| 1346 | { | ||
| 1347 | struct dw_hdmi *hdmi = bridge->driver_private; | ||
| 1348 | |||
| 1349 | dw_hdmi_setup(hdmi, mode); | ||
| 1350 | |||
| 1351 | /* Store the display mode for plugin/DKMS poweron events */ | ||
| 1352 | memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode)); | ||
| 1353 | } | ||
| 1354 | |||
| 1355 | static bool dw_hdmi_bridge_mode_fixup(struct drm_bridge *bridge, | ||
| 1356 | const struct drm_display_mode *mode, | ||
| 1357 | struct drm_display_mode *adjusted_mode) | ||
| 1358 | { | ||
| 1359 | return true; | ||
| 1360 | } | ||
| 1361 | |||
| 1362 | static void dw_hdmi_bridge_disable(struct drm_bridge *bridge) | ||
| 1366 | { | 1363 | { |
| 1367 | imx_hdmi_setup(hdmi, &hdmi->previous_mode); | 1364 | struct dw_hdmi *hdmi = bridge->driver_private; |
| 1365 | |||
| 1366 | dw_hdmi_poweroff(hdmi); | ||
| 1367 | } | ||
| 1368 | |||
| 1369 | static void dw_hdmi_bridge_enable(struct drm_bridge *bridge) | ||
| 1370 | { | ||
| 1371 | struct dw_hdmi *hdmi = bridge->driver_private; | ||
| 1372 | |||
| 1373 | dw_hdmi_poweron(hdmi); | ||
| 1368 | } | 1374 | } |
| 1369 | 1375 | ||
| 1370 | static void imx_hdmi_poweroff(struct imx_hdmi *hdmi) | 1376 | static void dw_hdmi_bridge_destroy(struct drm_bridge *bridge) |
| 1371 | { | 1377 | { |
| 1372 | imx_hdmi_phy_disable(hdmi); | 1378 | drm_bridge_cleanup(bridge); |
| 1379 | kfree(bridge); | ||
| 1373 | } | 1380 | } |
| 1374 | 1381 | ||
| 1375 | static enum drm_connector_status imx_hdmi_connector_detect(struct drm_connector | 1382 | static void dw_hdmi_bridge_nop(struct drm_bridge *bridge) |
| 1376 | *connector, bool force) | ||
| 1377 | { | 1383 | { |
| 1378 | struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi, | 1384 | /* do nothing */ |
| 1385 | } | ||
| 1386 | |||
| 1387 | static enum drm_connector_status | ||
| 1388 | dw_hdmi_connector_detect(struct drm_connector *connector, bool force) | ||
| 1389 | { | ||
| 1390 | struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, | ||
| 1379 | connector); | 1391 | connector); |
| 1380 | 1392 | ||
| 1381 | return hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD ? | 1393 | return hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD ? |
| 1382 | connector_status_connected : connector_status_disconnected; | 1394 | connector_status_connected : connector_status_disconnected; |
| 1383 | } | 1395 | } |
| 1384 | 1396 | ||
| 1385 | static int imx_hdmi_connector_get_modes(struct drm_connector *connector) | 1397 | static int dw_hdmi_connector_get_modes(struct drm_connector *connector) |
| 1386 | { | 1398 | { |
| 1387 | struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi, | 1399 | struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, |
| 1388 | connector); | 1400 | connector); |
| 1389 | struct edid *edid; | 1401 | struct edid *edid; |
| 1390 | int ret; | 1402 | int ret; |
| @@ -1407,94 +1419,61 @@ static int imx_hdmi_connector_get_modes(struct drm_connector *connector) | |||
| 1407 | return 0; | 1419 | return 0; |
| 1408 | } | 1420 | } |
| 1409 | 1421 | ||
| 1410 | static struct drm_encoder *imx_hdmi_connector_best_encoder(struct drm_connector | 1422 | static enum drm_mode_status |
| 1411 | *connector) | 1423 | dw_hdmi_connector_mode_valid(struct drm_connector *connector, |
| 1412 | { | 1424 | struct drm_display_mode *mode) |
| 1413 | struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi, | ||
| 1414 | connector); | ||
| 1415 | |||
| 1416 | return &hdmi->encoder; | ||
| 1417 | } | ||
| 1418 | |||
| 1419 | static void imx_hdmi_encoder_mode_set(struct drm_encoder *encoder, | ||
| 1420 | struct drm_display_mode *mode, | ||
| 1421 | struct drm_display_mode *adjusted_mode) | ||
| 1422 | { | 1425 | { |
| 1423 | struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder); | 1426 | struct dw_hdmi *hdmi = container_of(connector, |
| 1427 | struct dw_hdmi, connector); | ||
| 1428 | enum drm_mode_status mode_status = MODE_OK; | ||
| 1424 | 1429 | ||
| 1425 | imx_hdmi_setup(hdmi, mode); | 1430 | if (hdmi->plat_data->mode_valid) |
| 1431 | mode_status = hdmi->plat_data->mode_valid(connector, mode); | ||
| 1426 | 1432 | ||
| 1427 | /* Store the display mode for plugin/DKMS poweron events */ | 1433 | return mode_status; |
| 1428 | memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode)); | ||
| 1429 | } | ||
| 1430 | |||
| 1431 | static bool imx_hdmi_encoder_mode_fixup(struct drm_encoder *encoder, | ||
| 1432 | const struct drm_display_mode *mode, | ||
| 1433 | struct drm_display_mode *adjusted_mode) | ||
| 1434 | { | ||
| 1435 | return true; | ||
| 1436 | } | ||
| 1437 | |||
| 1438 | static void imx_hdmi_encoder_disable(struct drm_encoder *encoder) | ||
| 1439 | { | ||
| 1440 | } | ||
| 1441 | |||
| 1442 | static void imx_hdmi_encoder_dpms(struct drm_encoder *encoder, int mode) | ||
| 1443 | { | ||
| 1444 | struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder); | ||
| 1445 | |||
| 1446 | if (mode) | ||
| 1447 | imx_hdmi_poweroff(hdmi); | ||
| 1448 | else | ||
| 1449 | imx_hdmi_poweron(hdmi); | ||
| 1450 | } | 1434 | } |
| 1451 | 1435 | ||
| 1452 | static void imx_hdmi_encoder_prepare(struct drm_encoder *encoder) | 1436 | static struct drm_encoder *dw_hdmi_connector_best_encoder(struct drm_connector |
| 1437 | *connector) | ||
| 1453 | { | 1438 | { |
| 1454 | struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder); | 1439 | struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, |
| 1440 | connector); | ||
| 1455 | 1441 | ||
| 1456 | imx_hdmi_poweroff(hdmi); | 1442 | return hdmi->encoder; |
| 1457 | imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24); | ||
| 1458 | } | 1443 | } |
| 1459 | 1444 | ||
| 1460 | static void imx_hdmi_encoder_commit(struct drm_encoder *encoder) | 1445 | static void dw_hdmi_connector_destroy(struct drm_connector *connector) |
| 1461 | { | 1446 | { |
| 1462 | struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder); | 1447 | drm_connector_unregister(connector); |
| 1463 | int mux = imx_drm_encoder_get_mux_id(hdmi->dev->of_node, encoder); | 1448 | drm_connector_cleanup(connector); |
| 1464 | |||
| 1465 | imx_hdmi_set_ipu_di_mux(hdmi, mux); | ||
| 1466 | |||
| 1467 | imx_hdmi_poweron(hdmi); | ||
| 1468 | } | 1449 | } |
| 1469 | 1450 | ||
| 1470 | static struct drm_encoder_funcs imx_hdmi_encoder_funcs = { | 1451 | static struct drm_connector_funcs dw_hdmi_connector_funcs = { |
| 1471 | .destroy = imx_drm_encoder_destroy, | ||
| 1472 | }; | ||
| 1473 | |||
| 1474 | static struct drm_encoder_helper_funcs imx_hdmi_encoder_helper_funcs = { | ||
| 1475 | .dpms = imx_hdmi_encoder_dpms, | ||
| 1476 | .prepare = imx_hdmi_encoder_prepare, | ||
| 1477 | .commit = imx_hdmi_encoder_commit, | ||
| 1478 | .mode_set = imx_hdmi_encoder_mode_set, | ||
| 1479 | .mode_fixup = imx_hdmi_encoder_mode_fixup, | ||
| 1480 | .disable = imx_hdmi_encoder_disable, | ||
| 1481 | }; | ||
| 1482 | |||
| 1483 | static struct drm_connector_funcs imx_hdmi_connector_funcs = { | ||
| 1484 | .dpms = drm_helper_connector_dpms, | 1452 | .dpms = drm_helper_connector_dpms, |
| 1485 | .fill_modes = drm_helper_probe_single_connector_modes, | 1453 | .fill_modes = drm_helper_probe_single_connector_modes, |
| 1486 | .detect = imx_hdmi_connector_detect, | 1454 | .detect = dw_hdmi_connector_detect, |
| 1487 | .destroy = imx_drm_connector_destroy, | 1455 | .destroy = dw_hdmi_connector_destroy, |
| 1456 | }; | ||
| 1457 | |||
| 1458 | static struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = { | ||
| 1459 | .get_modes = dw_hdmi_connector_get_modes, | ||
| 1460 | .mode_valid = dw_hdmi_connector_mode_valid, | ||
| 1461 | .best_encoder = dw_hdmi_connector_best_encoder, | ||
| 1488 | }; | 1462 | }; |
| 1489 | 1463 | ||
| 1490 | static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = { | 1464 | struct drm_bridge_funcs dw_hdmi_bridge_funcs = { |
| 1491 | .get_modes = imx_hdmi_connector_get_modes, | 1465 | .enable = dw_hdmi_bridge_enable, |
| 1492 | .best_encoder = imx_hdmi_connector_best_encoder, | 1466 | .disable = dw_hdmi_bridge_disable, |
| 1467 | .pre_enable = dw_hdmi_bridge_nop, | ||
| 1468 | .post_disable = dw_hdmi_bridge_nop, | ||
| 1469 | .mode_set = dw_hdmi_bridge_mode_set, | ||
| 1470 | .mode_fixup = dw_hdmi_bridge_mode_fixup, | ||
| 1471 | .destroy = dw_hdmi_bridge_destroy, | ||
| 1493 | }; | 1472 | }; |
| 1494 | 1473 | ||
| 1495 | static irqreturn_t imx_hdmi_hardirq(int irq, void *dev_id) | 1474 | static irqreturn_t dw_hdmi_hardirq(int irq, void *dev_id) |
| 1496 | { | 1475 | { |
| 1497 | struct imx_hdmi *hdmi = dev_id; | 1476 | struct dw_hdmi *hdmi = dev_id; |
| 1498 | u8 intr_stat; | 1477 | u8 intr_stat; |
| 1499 | 1478 | ||
| 1500 | intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0); | 1479 | intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0); |
| @@ -1504,9 +1483,9 @@ static irqreturn_t imx_hdmi_hardirq(int irq, void *dev_id) | |||
| 1504 | return intr_stat ? IRQ_WAKE_THREAD : IRQ_NONE; | 1483 | return intr_stat ? IRQ_WAKE_THREAD : IRQ_NONE; |
| 1505 | } | 1484 | } |
| 1506 | 1485 | ||
| 1507 | static irqreturn_t imx_hdmi_irq(int irq, void *dev_id) | 1486 | static irqreturn_t dw_hdmi_irq(int irq, void *dev_id) |
| 1508 | { | 1487 | { |
| 1509 | struct imx_hdmi *hdmi = dev_id; | 1488 | struct dw_hdmi *hdmi = dev_id; |
| 1510 | u8 intr_stat; | 1489 | u8 intr_stat; |
| 1511 | u8 phy_int_pol; | 1490 | u8 phy_int_pol; |
| 1512 | 1491 | ||
| @@ -1520,14 +1499,14 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id) | |||
| 1520 | 1499 | ||
| 1521 | hdmi_modb(hdmi, 0, HDMI_PHY_HPD, HDMI_PHY_POL0); | 1500 | hdmi_modb(hdmi, 0, HDMI_PHY_HPD, HDMI_PHY_POL0); |
| 1522 | 1501 | ||
| 1523 | imx_hdmi_poweron(hdmi); | 1502 | dw_hdmi_poweron(hdmi); |
| 1524 | } else { | 1503 | } else { |
| 1525 | dev_dbg(hdmi->dev, "EVENT=plugout\n"); | 1504 | dev_dbg(hdmi->dev, "EVENT=plugout\n"); |
| 1526 | 1505 | ||
| 1527 | hdmi_modb(hdmi, HDMI_PHY_HPD, HDMI_PHY_HPD, | 1506 | hdmi_modb(hdmi, HDMI_PHY_HPD, HDMI_PHY_HPD, |
| 1528 | HDMI_PHY_POL0); | 1507 | HDMI_PHY_POL0); |
| 1529 | 1508 | ||
| 1530 | imx_hdmi_poweroff(hdmi); | 1509 | dw_hdmi_poweroff(hdmi); |
| 1531 | } | 1510 | } |
| 1532 | drm_helper_hpd_irq_event(hdmi->connector.dev); | 1511 | drm_helper_hpd_irq_event(hdmi->connector.dev); |
| 1533 | } | 1512 | } |
| @@ -1538,147 +1517,140 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id) | |||
| 1538 | return IRQ_HANDLED; | 1517 | return IRQ_HANDLED; |
| 1539 | } | 1518 | } |
| 1540 | 1519 | ||
| 1541 | static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi) | 1520 | static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi) |
| 1542 | { | 1521 | { |
| 1522 | struct drm_encoder *encoder = hdmi->encoder; | ||
| 1523 | struct drm_bridge *bridge; | ||
| 1543 | int ret; | 1524 | int ret; |
| 1544 | 1525 | ||
| 1545 | ret = imx_drm_encoder_parse_of(drm, &hdmi->encoder, | 1526 | bridge = devm_kzalloc(drm->dev, sizeof(*bridge), GFP_KERNEL); |
| 1546 | hdmi->dev->of_node); | 1527 | if (!bridge) { |
| 1547 | if (ret) | 1528 | DRM_ERROR("Failed to allocate drm bridge\n"); |
| 1548 | return ret; | 1529 | return -ENOMEM; |
| 1530 | } | ||
| 1549 | 1531 | ||
| 1550 | hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD; | 1532 | hdmi->bridge = bridge; |
| 1533 | bridge->driver_private = hdmi; | ||
| 1551 | 1534 | ||
| 1552 | drm_encoder_helper_add(&hdmi->encoder, &imx_hdmi_encoder_helper_funcs); | 1535 | ret = drm_bridge_init(drm, bridge, &dw_hdmi_bridge_funcs); |
| 1553 | drm_encoder_init(drm, &hdmi->encoder, &imx_hdmi_encoder_funcs, | 1536 | if (ret) { |
| 1554 | DRM_MODE_ENCODER_TMDS); | 1537 | DRM_ERROR("Failed to initialize bridge with drm\n"); |
| 1538 | return -EINVAL; | ||
| 1539 | } | ||
| 1540 | |||
| 1541 | encoder->bridge = bridge; | ||
| 1542 | hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD; | ||
| 1555 | 1543 | ||
| 1556 | drm_connector_helper_add(&hdmi->connector, | 1544 | drm_connector_helper_add(&hdmi->connector, |
| 1557 | &imx_hdmi_connector_helper_funcs); | 1545 | &dw_hdmi_connector_helper_funcs); |
| 1558 | drm_connector_init(drm, &hdmi->connector, &imx_hdmi_connector_funcs, | 1546 | drm_connector_init(drm, &hdmi->connector, &dw_hdmi_connector_funcs, |
| 1559 | DRM_MODE_CONNECTOR_HDMIA); | 1547 | DRM_MODE_CONNECTOR_HDMIA); |
| 1560 | 1548 | ||
| 1561 | hdmi->connector.encoder = &hdmi->encoder; | 1549 | hdmi->connector.encoder = encoder; |
| 1562 | 1550 | ||
| 1563 | drm_mode_connector_attach_encoder(&hdmi->connector, &hdmi->encoder); | 1551 | drm_mode_connector_attach_encoder(&hdmi->connector, encoder); |
| 1564 | 1552 | ||
| 1565 | return 0; | 1553 | return 0; |
| 1566 | } | 1554 | } |
| 1567 | 1555 | ||
| 1568 | static struct platform_device_id imx_hdmi_devtype[] = { | 1556 | int dw_hdmi_bind(struct device *dev, struct device *master, |
| 1569 | { | 1557 | void *data, struct drm_encoder *encoder, |
| 1570 | .name = "imx6q-hdmi", | 1558 | struct resource *iores, int irq, |
| 1571 | .driver_data = IMX6Q_HDMI, | 1559 | const struct dw_hdmi_plat_data *plat_data) |
| 1572 | }, { | ||
| 1573 | .name = "imx6dl-hdmi", | ||
| 1574 | .driver_data = IMX6DL_HDMI, | ||
| 1575 | }, { /* sentinel */ } | ||
| 1576 | }; | ||
| 1577 | MODULE_DEVICE_TABLE(platform, imx_hdmi_devtype); | ||
| 1578 | |||
| 1579 | static const struct of_device_id imx_hdmi_dt_ids[] = { | ||
| 1580 | { .compatible = "fsl,imx6q-hdmi", .data = &imx_hdmi_devtype[IMX6Q_HDMI], }, | ||
| 1581 | { .compatible = "fsl,imx6dl-hdmi", .data = &imx_hdmi_devtype[IMX6DL_HDMI], }, | ||
| 1582 | { /* sentinel */ } | ||
| 1583 | }; | ||
| 1584 | MODULE_DEVICE_TABLE(of, imx_hdmi_dt_ids); | ||
| 1585 | |||
| 1586 | static int imx_hdmi_bind(struct device *dev, struct device *master, void *data) | ||
| 1587 | { | 1560 | { |
| 1588 | struct platform_device *pdev = to_platform_device(dev); | ||
| 1589 | const struct of_device_id *of_id = | ||
| 1590 | of_match_device(imx_hdmi_dt_ids, dev); | ||
| 1591 | struct drm_device *drm = data; | 1561 | struct drm_device *drm = data; |
| 1592 | struct device_node *np = dev->of_node; | 1562 | struct device_node *np = dev->of_node; |
| 1593 | struct device_node *ddc_node; | 1563 | struct device_node *ddc_node; |
| 1594 | struct imx_hdmi *hdmi; | 1564 | struct dw_hdmi *hdmi; |
| 1595 | struct resource *iores; | 1565 | int ret; |
| 1596 | int ret, irq; | 1566 | u32 val = 1; |
| 1597 | 1567 | ||
| 1598 | hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL); | 1568 | hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL); |
| 1599 | if (!hdmi) | 1569 | if (!hdmi) |
| 1600 | return -ENOMEM; | 1570 | return -ENOMEM; |
| 1601 | 1571 | ||
| 1572 | hdmi->plat_data = plat_data; | ||
| 1602 | hdmi->dev = dev; | 1573 | hdmi->dev = dev; |
| 1574 | hdmi->dev_type = plat_data->dev_type; | ||
| 1603 | hdmi->sample_rate = 48000; | 1575 | hdmi->sample_rate = 48000; |
| 1604 | hdmi->ratio = 100; | 1576 | hdmi->ratio = 100; |
| 1577 | hdmi->encoder = encoder; | ||
| 1605 | 1578 | ||
| 1606 | if (of_id) { | 1579 | of_property_read_u32(np, "reg-io-width", &val); |
| 1607 | const struct platform_device_id *device_id = of_id->data; | ||
| 1608 | 1580 | ||
| 1609 | hdmi->dev_type = device_id->driver_data; | 1581 | switch (val) { |
| 1582 | case 4: | ||
| 1583 | hdmi->write = dw_hdmi_writel; | ||
| 1584 | hdmi->read = dw_hdmi_readl; | ||
| 1585 | break; | ||
| 1586 | case 1: | ||
| 1587 | hdmi->write = dw_hdmi_writeb; | ||
| 1588 | hdmi->read = dw_hdmi_readb; | ||
| 1589 | break; | ||
| 1590 | default: | ||
| 1591 | dev_err(dev, "reg-io-width must be 1 or 4\n"); | ||
| 1592 | return -EINVAL; | ||
| 1610 | } | 1593 | } |
| 1611 | 1594 | ||
| 1612 | ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0); | 1595 | ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0); |
| 1613 | if (ddc_node) { | 1596 | if (ddc_node) { |
| 1614 | hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node); | 1597 | hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node); |
| 1615 | if (!hdmi->ddc) | 1598 | of_node_put(ddc_node); |
| 1599 | if (!hdmi->ddc) { | ||
| 1616 | dev_dbg(hdmi->dev, "failed to read ddc node\n"); | 1600 | dev_dbg(hdmi->dev, "failed to read ddc node\n"); |
| 1601 | return -EPROBE_DEFER; | ||
| 1602 | } | ||
| 1617 | 1603 | ||
| 1618 | of_node_put(ddc_node); | ||
| 1619 | } else { | 1604 | } else { |
| 1620 | dev_dbg(hdmi->dev, "no ddc property found\n"); | 1605 | dev_dbg(hdmi->dev, "no ddc property found\n"); |
| 1621 | } | 1606 | } |
| 1622 | 1607 | ||
| 1623 | irq = platform_get_irq(pdev, 0); | ||
| 1624 | if (irq < 0) | ||
| 1625 | return irq; | ||
| 1626 | |||
| 1627 | ret = devm_request_threaded_irq(dev, irq, imx_hdmi_hardirq, | ||
| 1628 | imx_hdmi_irq, IRQF_SHARED, | ||
| 1629 | dev_name(dev), hdmi); | ||
| 1630 | if (ret) | ||
| 1631 | return ret; | ||
| 1632 | |||
| 1633 | iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 1634 | hdmi->regs = devm_ioremap_resource(dev, iores); | 1608 | hdmi->regs = devm_ioremap_resource(dev, iores); |
| 1635 | if (IS_ERR(hdmi->regs)) | 1609 | if (IS_ERR(hdmi->regs)) |
| 1636 | return PTR_ERR(hdmi->regs); | 1610 | return PTR_ERR(hdmi->regs); |
| 1637 | 1611 | ||
| 1638 | hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "gpr"); | ||
| 1639 | if (IS_ERR(hdmi->regmap)) | ||
| 1640 | return PTR_ERR(hdmi->regmap); | ||
| 1641 | |||
| 1642 | hdmi->isfr_clk = devm_clk_get(hdmi->dev, "isfr"); | 1612 | hdmi->isfr_clk = devm_clk_get(hdmi->dev, "isfr"); |
| 1643 | if (IS_ERR(hdmi->isfr_clk)) { | 1613 | if (IS_ERR(hdmi->isfr_clk)) { |
| 1644 | ret = PTR_ERR(hdmi->isfr_clk); | 1614 | ret = PTR_ERR(hdmi->isfr_clk); |
| 1645 | dev_err(hdmi->dev, | 1615 | dev_err(hdmi->dev, "Unable to get HDMI isfr clk: %d\n", ret); |
| 1646 | "Unable to get HDMI isfr clk: %d\n", ret); | ||
| 1647 | return ret; | 1616 | return ret; |
| 1648 | } | 1617 | } |
| 1649 | 1618 | ||
| 1650 | ret = clk_prepare_enable(hdmi->isfr_clk); | 1619 | ret = clk_prepare_enable(hdmi->isfr_clk); |
| 1651 | if (ret) { | 1620 | if (ret) { |
| 1652 | dev_err(hdmi->dev, | 1621 | dev_err(hdmi->dev, "Cannot enable HDMI isfr clock: %d\n", ret); |
| 1653 | "Cannot enable HDMI isfr clock: %d\n", ret); | ||
| 1654 | return ret; | 1622 | return ret; |
| 1655 | } | 1623 | } |
| 1656 | 1624 | ||
| 1657 | hdmi->iahb_clk = devm_clk_get(hdmi->dev, "iahb"); | 1625 | hdmi->iahb_clk = devm_clk_get(hdmi->dev, "iahb"); |
| 1658 | if (IS_ERR(hdmi->iahb_clk)) { | 1626 | if (IS_ERR(hdmi->iahb_clk)) { |
| 1659 | ret = PTR_ERR(hdmi->iahb_clk); | 1627 | ret = PTR_ERR(hdmi->iahb_clk); |
| 1660 | dev_err(hdmi->dev, | 1628 | dev_err(hdmi->dev, "Unable to get HDMI iahb clk: %d\n", ret); |
| 1661 | "Unable to get HDMI iahb clk: %d\n", ret); | ||
| 1662 | goto err_isfr; | 1629 | goto err_isfr; |
| 1663 | } | 1630 | } |
| 1664 | 1631 | ||
| 1665 | ret = clk_prepare_enable(hdmi->iahb_clk); | 1632 | ret = clk_prepare_enable(hdmi->iahb_clk); |
| 1666 | if (ret) { | 1633 | if (ret) { |
| 1667 | dev_err(hdmi->dev, | 1634 | dev_err(hdmi->dev, "Cannot enable HDMI iahb clock: %d\n", ret); |
| 1668 | "Cannot enable HDMI iahb clock: %d\n", ret); | ||
| 1669 | goto err_isfr; | 1635 | goto err_isfr; |
| 1670 | } | 1636 | } |
| 1671 | 1637 | ||
| 1672 | /* Product and revision IDs */ | 1638 | /* Product and revision IDs */ |
| 1673 | dev_info(dev, | 1639 | dev_info(dev, |
| 1674 | "Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n", | 1640 | "Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n", |
| 1675 | hdmi_readb(hdmi, HDMI_DESIGN_ID), | 1641 | hdmi_readb(hdmi, HDMI_DESIGN_ID), |
| 1676 | hdmi_readb(hdmi, HDMI_REVISION_ID), | 1642 | hdmi_readb(hdmi, HDMI_REVISION_ID), |
| 1677 | hdmi_readb(hdmi, HDMI_PRODUCT_ID0), | 1643 | hdmi_readb(hdmi, HDMI_PRODUCT_ID0), |
| 1678 | hdmi_readb(hdmi, HDMI_PRODUCT_ID1)); | 1644 | hdmi_readb(hdmi, HDMI_PRODUCT_ID1)); |
| 1679 | 1645 | ||
| 1680 | initialize_hdmi_ih_mutes(hdmi); | 1646 | initialize_hdmi_ih_mutes(hdmi); |
| 1681 | 1647 | ||
| 1648 | ret = devm_request_threaded_irq(dev, irq, dw_hdmi_hardirq, | ||
| 1649 | dw_hdmi_irq, IRQF_SHARED, | ||
| 1650 | dev_name(dev), hdmi); | ||
| 1651 | if (ret) | ||
| 1652 | return ret; | ||
| 1653 | |||
| 1682 | /* | 1654 | /* |
| 1683 | * To prevent overflows in HDMI_IH_FC_STAT2, set the clk regenerator | 1655 | * To prevent overflows in HDMI_IH_FC_STAT2, set the clk regenerator |
| 1684 | * N and cts values before enabling phy | 1656 | * N and cts values before enabling phy |
| @@ -1694,11 +1666,11 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data) | |||
| 1694 | /* Clear Hotplug interrupts */ | 1666 | /* Clear Hotplug interrupts */ |
| 1695 | hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0); | 1667 | hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0); |
| 1696 | 1668 | ||
| 1697 | ret = imx_hdmi_fb_registered(hdmi); | 1669 | ret = dw_hdmi_fb_registered(hdmi); |
| 1698 | if (ret) | 1670 | if (ret) |
| 1699 | goto err_iahb; | 1671 | goto err_iahb; |
| 1700 | 1672 | ||
| 1701 | ret = imx_hdmi_register(drm, hdmi); | 1673 | ret = dw_hdmi_register(drm, hdmi); |
| 1702 | if (ret) | 1674 | if (ret) |
| 1703 | goto err_iahb; | 1675 | goto err_iahb; |
| 1704 | 1676 | ||
| @@ -1716,51 +1688,27 @@ err_isfr: | |||
| 1716 | 1688 | ||
| 1717 | return ret; | 1689 | return ret; |
| 1718 | } | 1690 | } |
| 1691 | EXPORT_SYMBOL_GPL(dw_hdmi_bind); | ||
| 1719 | 1692 | ||
| 1720 | static void imx_hdmi_unbind(struct device *dev, struct device *master, | 1693 | void dw_hdmi_unbind(struct device *dev, struct device *master, void *data) |
| 1721 | void *data) | ||
| 1722 | { | 1694 | { |
| 1723 | struct imx_hdmi *hdmi = dev_get_drvdata(dev); | 1695 | struct dw_hdmi *hdmi = dev_get_drvdata(dev); |
| 1724 | 1696 | ||
| 1725 | /* Disable all interrupts */ | 1697 | /* Disable all interrupts */ |
| 1726 | hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0); | 1698 | hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0); |
| 1727 | 1699 | ||
| 1728 | hdmi->connector.funcs->destroy(&hdmi->connector); | 1700 | hdmi->connector.funcs->destroy(&hdmi->connector); |
| 1729 | hdmi->encoder.funcs->destroy(&hdmi->encoder); | 1701 | hdmi->encoder->funcs->destroy(hdmi->encoder); |
| 1730 | 1702 | ||
| 1731 | clk_disable_unprepare(hdmi->iahb_clk); | 1703 | clk_disable_unprepare(hdmi->iahb_clk); |
| 1732 | clk_disable_unprepare(hdmi->isfr_clk); | 1704 | clk_disable_unprepare(hdmi->isfr_clk); |
| 1733 | i2c_put_adapter(hdmi->ddc); | 1705 | i2c_put_adapter(hdmi->ddc); |
| 1734 | } | 1706 | } |
| 1735 | 1707 | EXPORT_SYMBOL_GPL(dw_hdmi_unbind); | |
| 1736 | static const struct component_ops hdmi_ops = { | ||
| 1737 | .bind = imx_hdmi_bind, | ||
| 1738 | .unbind = imx_hdmi_unbind, | ||
| 1739 | }; | ||
| 1740 | |||
| 1741 | static int imx_hdmi_platform_probe(struct platform_device *pdev) | ||
| 1742 | { | ||
| 1743 | return component_add(&pdev->dev, &hdmi_ops); | ||
| 1744 | } | ||
| 1745 | |||
| 1746 | static int imx_hdmi_platform_remove(struct platform_device *pdev) | ||
| 1747 | { | ||
| 1748 | component_del(&pdev->dev, &hdmi_ops); | ||
| 1749 | return 0; | ||
| 1750 | } | ||
| 1751 | |||
| 1752 | static struct platform_driver imx_hdmi_driver = { | ||
| 1753 | .probe = imx_hdmi_platform_probe, | ||
| 1754 | .remove = imx_hdmi_platform_remove, | ||
| 1755 | .driver = { | ||
| 1756 | .name = "imx-hdmi", | ||
| 1757 | .of_match_table = imx_hdmi_dt_ids, | ||
| 1758 | }, | ||
| 1759 | }; | ||
| 1760 | |||
| 1761 | module_platform_driver(imx_hdmi_driver); | ||
| 1762 | 1708 | ||
| 1763 | MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); | 1709 | MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); |
| 1764 | MODULE_DESCRIPTION("i.MX6 HDMI transmitter driver"); | 1710 | MODULE_AUTHOR("Andy Yan <andy.yan@rock-chips.com>"); |
| 1711 | MODULE_AUTHOR("Yakir Yang <ykk@rock-chips.com>"); | ||
| 1712 | MODULE_DESCRIPTION("DW HDMI transmitter driver"); | ||
| 1765 | MODULE_LICENSE("GPL"); | 1713 | MODULE_LICENSE("GPL"); |
| 1766 | MODULE_ALIAS("platform:imx-hdmi"); | 1714 | MODULE_ALIAS("platform:dw-hdmi"); |
diff --git a/drivers/gpu/drm/imx/imx-hdmi.h b/drivers/gpu/drm/bridge/dw_hdmi.h index 39b677689db6..175dbc89a824 100644 --- a/drivers/gpu/drm/imx/imx-hdmi.h +++ b/drivers/gpu/drm/bridge/dw_hdmi.h | |||
| @@ -837,7 +837,8 @@ enum { | |||
| 837 | HDMI_PHY_CONF0_PDZ_OFFSET = 7, | 837 | HDMI_PHY_CONF0_PDZ_OFFSET = 7, |
| 838 | HDMI_PHY_CONF0_ENTMDS_MASK = 0x40, | 838 | HDMI_PHY_CONF0_ENTMDS_MASK = 0x40, |
| 839 | HDMI_PHY_CONF0_ENTMDS_OFFSET = 6, | 839 | HDMI_PHY_CONF0_ENTMDS_OFFSET = 6, |
| 840 | HDMI_PHY_CONF0_SPARECTRL = 0x20, | 840 | HDMI_PHY_CONF0_SPARECTRL_MASK = 0x20, |
| 841 | HDMI_PHY_CONF0_SPARECTRL_OFFSET = 5, | ||
| 841 | HDMI_PHY_CONF0_GEN2_PDDQ_MASK = 0x10, | 842 | HDMI_PHY_CONF0_GEN2_PDDQ_MASK = 0x10, |
| 842 | HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET = 4, | 843 | HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET = 4, |
| 843 | HDMI_PHY_CONF0_GEN2_TXPWRON_MASK = 0x8, | 844 | HDMI_PHY_CONF0_GEN2_TXPWRON_MASK = 0x8, |
| @@ -1029,4 +1030,5 @@ enum { | |||
| 1029 | HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_HIGH = 0x2, | 1030 | HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_HIGH = 0x2, |
| 1030 | HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_LOW = 0x0, | 1031 | HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_LOW = 0x0, |
| 1031 | }; | 1032 | }; |
| 1033 | |||
| 1032 | #endif /* __IMX_HDMI_H__ */ | 1034 | #endif /* __IMX_HDMI_H__ */ |
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index 5125aa91e66f..20d977a52c58 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c | |||
| @@ -615,6 +615,46 @@ void drm_display_mode_from_videomode(const struct videomode *vm, | |||
| 615 | } | 615 | } |
| 616 | EXPORT_SYMBOL_GPL(drm_display_mode_from_videomode); | 616 | EXPORT_SYMBOL_GPL(drm_display_mode_from_videomode); |
| 617 | 617 | ||
| 618 | /** | ||
| 619 | * drm_display_mode_to_videomode - fill in @vm using @dmode, | ||
| 620 | * @dmode: drm_display_mode structure to use as source | ||
| 621 | * @vm: videomode structure to use as destination | ||
| 622 | * | ||
| 623 | * Fills out @vm using the display mode specified in @dmode. | ||
| 624 | */ | ||
| 625 | void drm_display_mode_to_videomode(const struct drm_display_mode *dmode, | ||
| 626 | struct videomode *vm) | ||
| 627 | { | ||
| 628 | vm->hactive = dmode->hdisplay; | ||
| 629 | vm->hfront_porch = dmode->hsync_start - dmode->hdisplay; | ||
| 630 | vm->hsync_len = dmode->hsync_end - dmode->hsync_start; | ||
| 631 | vm->hback_porch = dmode->htotal - dmode->hsync_end; | ||
| 632 | |||
| 633 | vm->vactive = dmode->vdisplay; | ||
| 634 | vm->vfront_porch = dmode->vsync_start - dmode->vdisplay; | ||
| 635 | vm->vsync_len = dmode->vsync_end - dmode->vsync_start; | ||
| 636 | vm->vback_porch = dmode->vtotal - dmode->vsync_end; | ||
| 637 | |||
| 638 | vm->pixelclock = dmode->clock * 1000; | ||
| 639 | |||
| 640 | vm->flags = 0; | ||
| 641 | if (dmode->flags & DRM_MODE_FLAG_PHSYNC) | ||
| 642 | vm->flags |= DISPLAY_FLAGS_HSYNC_HIGH; | ||
| 643 | else if (dmode->flags & DRM_MODE_FLAG_NHSYNC) | ||
| 644 | vm->flags |= DISPLAY_FLAGS_HSYNC_LOW; | ||
| 645 | if (dmode->flags & DRM_MODE_FLAG_PVSYNC) | ||
| 646 | vm->flags |= DISPLAY_FLAGS_VSYNC_HIGH; | ||
| 647 | else if (dmode->flags & DRM_MODE_FLAG_NVSYNC) | ||
| 648 | vm->flags |= DISPLAY_FLAGS_VSYNC_LOW; | ||
| 649 | if (dmode->flags & DRM_MODE_FLAG_INTERLACE) | ||
| 650 | vm->flags |= DISPLAY_FLAGS_INTERLACED; | ||
| 651 | if (dmode->flags & DRM_MODE_FLAG_DBLSCAN) | ||
| 652 | vm->flags |= DISPLAY_FLAGS_DOUBLESCAN; | ||
| 653 | if (dmode->flags & DRM_MODE_FLAG_DBLCLK) | ||
| 654 | vm->flags |= DISPLAY_FLAGS_DOUBLECLK; | ||
| 655 | } | ||
| 656 | EXPORT_SYMBOL_GPL(drm_display_mode_to_videomode); | ||
| 657 | |||
| 618 | #ifdef CONFIG_OF | 658 | #ifdef CONFIG_OF |
| 619 | /** | 659 | /** |
| 620 | * of_get_drm_display_mode - get a drm_display_mode from devicetree | 660 | * of_get_drm_display_mode - get a drm_display_mode from devicetree |
diff --git a/drivers/gpu/drm/imx/Kconfig b/drivers/gpu/drm/imx/Kconfig index ab31848e92cf..5d5e4092d40a 100644 --- a/drivers/gpu/drm/imx/Kconfig +++ b/drivers/gpu/drm/imx/Kconfig | |||
| @@ -49,6 +49,7 @@ config DRM_IMX_IPUV3 | |||
| 49 | 49 | ||
| 50 | config DRM_IMX_HDMI | 50 | config DRM_IMX_HDMI |
| 51 | tristate "Freescale i.MX DRM HDMI" | 51 | tristate "Freescale i.MX DRM HDMI" |
| 52 | select DRM_DW_HDMI | ||
| 52 | depends on DRM_IMX | 53 | depends on DRM_IMX |
| 53 | help | 54 | help |
| 54 | Choose this if you want to use HDMI on i.MX6. | 55 | Choose this if you want to use HDMI on i.MX6. |
diff --git a/drivers/gpu/drm/imx/Makefile b/drivers/gpu/drm/imx/Makefile index 582c438d8cbd..f3ecd8903d97 100644 --- a/drivers/gpu/drm/imx/Makefile +++ b/drivers/gpu/drm/imx/Makefile | |||
| @@ -9,4 +9,4 @@ obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o | |||
| 9 | 9 | ||
| 10 | imx-ipuv3-crtc-objs := ipuv3-crtc.o ipuv3-plane.o | 10 | imx-ipuv3-crtc-objs := ipuv3-crtc.o ipuv3-plane.o |
| 11 | obj-$(CONFIG_DRM_IMX_IPUV3) += imx-ipuv3-crtc.o | 11 | obj-$(CONFIG_DRM_IMX_IPUV3) += imx-ipuv3-crtc.o |
| 12 | obj-$(CONFIG_DRM_IMX_HDMI) += imx-hdmi.o | 12 | obj-$(CONFIG_DRM_IMX_HDMI) += dw_hdmi-imx.o |
diff --git a/drivers/gpu/drm/imx/dw_hdmi-imx.c b/drivers/gpu/drm/imx/dw_hdmi-imx.c new file mode 100644 index 000000000000..121d30ca2d44 --- /dev/null +++ b/drivers/gpu/drm/imx/dw_hdmi-imx.c | |||
| @@ -0,0 +1,258 @@ | |||
| 1 | /* Copyright (C) 2011-2013 Freescale Semiconductor, Inc. | ||
| 2 | * | ||
| 3 | * derived from imx-hdmi.c(renamed to bridge/dw_hdmi.c now) | ||
| 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 | #include <linux/module.h> | ||
| 10 | #include <linux/platform_device.h> | ||
| 11 | #include <linux/component.h> | ||
| 12 | #include <linux/mfd/syscon.h> | ||
| 13 | #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> | ||
| 14 | #include <drm/bridge/dw_hdmi.h> | ||
| 15 | #include <video/imx-ipu-v3.h> | ||
| 16 | #include <linux/regmap.h> | ||
| 17 | #include <drm/drm_of.h> | ||
| 18 | #include <drm/drmP.h> | ||
| 19 | #include <drm/drm_crtc_helper.h> | ||
| 20 | #include <drm/drm_edid.h> | ||
| 21 | #include <drm/drm_encoder_slave.h> | ||
| 22 | |||
| 23 | #include "imx-drm.h" | ||
| 24 | |||
| 25 | struct imx_hdmi { | ||
| 26 | struct device *dev; | ||
| 27 | struct drm_encoder encoder; | ||
| 28 | struct regmap *regmap; | ||
| 29 | }; | ||
| 30 | |||
| 31 | static const struct dw_hdmi_mpll_config imx_mpll_cfg[] = { | ||
| 32 | { | ||
| 33 | 45250000, { | ||
| 34 | { 0x01e0, 0x0000 }, | ||
| 35 | { 0x21e1, 0x0000 }, | ||
| 36 | { 0x41e2, 0x0000 } | ||
| 37 | }, | ||
| 38 | }, { | ||
| 39 | 92500000, { | ||
| 40 | { 0x0140, 0x0005 }, | ||
| 41 | { 0x2141, 0x0005 }, | ||
| 42 | { 0x4142, 0x0005 }, | ||
| 43 | }, | ||
| 44 | }, { | ||
| 45 | 148500000, { | ||
| 46 | { 0x00a0, 0x000a }, | ||
| 47 | { 0x20a1, 0x000a }, | ||
| 48 | { 0x40a2, 0x000a }, | ||
| 49 | }, | ||
| 50 | }, { | ||
| 51 | ~0UL, { | ||
| 52 | { 0x00a0, 0x000a }, | ||
| 53 | { 0x2001, 0x000f }, | ||
| 54 | { 0x4002, 0x000f }, | ||
| 55 | }, | ||
| 56 | } | ||
| 57 | }; | ||
| 58 | |||
| 59 | static const struct dw_hdmi_curr_ctrl imx_cur_ctr[] = { | ||
| 60 | /* pixelclk bpp8 bpp10 bpp12 */ | ||
| 61 | { | ||
| 62 | 54000000, { 0x091c, 0x091c, 0x06dc }, | ||
| 63 | }, { | ||
| 64 | 58400000, { 0x091c, 0x06dc, 0x06dc }, | ||
| 65 | }, { | ||
| 66 | 72000000, { 0x06dc, 0x06dc, 0x091c }, | ||
| 67 | }, { | ||
| 68 | 74250000, { 0x06dc, 0x0b5c, 0x091c }, | ||
| 69 | }, { | ||
| 70 | 118800000, { 0x091c, 0x091c, 0x06dc }, | ||
| 71 | }, { | ||
| 72 | 216000000, { 0x06dc, 0x0b5c, 0x091c }, | ||
| 73 | } | ||
| 74 | }; | ||
| 75 | |||
| 76 | static const struct dw_hdmi_sym_term imx_sym_term[] = { | ||
| 77 | /*pixelclk symbol term*/ | ||
| 78 | { 148500000, 0x800d, 0x0005 }, | ||
| 79 | { ~0UL, 0x0000, 0x0000 } | ||
| 80 | }; | ||
| 81 | |||
| 82 | static int dw_hdmi_imx_parse_dt(struct imx_hdmi *hdmi) | ||
| 83 | { | ||
| 84 | struct device_node *np = hdmi->dev->of_node; | ||
| 85 | |||
| 86 | hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "gpr"); | ||
| 87 | if (IS_ERR(hdmi->regmap)) { | ||
| 88 | dev_err(hdmi->dev, "Unable to get gpr\n"); | ||
| 89 | return PTR_ERR(hdmi->regmap); | ||
| 90 | } | ||
| 91 | |||
| 92 | return 0; | ||
| 93 | } | ||
| 94 | |||
| 95 | static void dw_hdmi_imx_encoder_disable(struct drm_encoder *encoder) | ||
| 96 | { | ||
| 97 | } | ||
| 98 | |||
| 99 | static bool dw_hdmi_imx_encoder_mode_fixup(struct drm_encoder *encoder, | ||
| 100 | const struct drm_display_mode *mode, | ||
| 101 | struct drm_display_mode *adj_mode) | ||
| 102 | { | ||
| 103 | return true; | ||
| 104 | } | ||
| 105 | |||
| 106 | static void dw_hdmi_imx_encoder_mode_set(struct drm_encoder *encoder, | ||
| 107 | struct drm_display_mode *mode, | ||
| 108 | struct drm_display_mode *adj_mode) | ||
| 109 | { | ||
| 110 | } | ||
| 111 | |||
| 112 | static void dw_hdmi_imx_encoder_commit(struct drm_encoder *encoder) | ||
| 113 | { | ||
| 114 | struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder); | ||
| 115 | int mux = imx_drm_encoder_get_mux_id(hdmi->dev->of_node, encoder); | ||
| 116 | |||
| 117 | regmap_update_bits(hdmi->regmap, IOMUXC_GPR3, | ||
| 118 | IMX6Q_GPR3_HDMI_MUX_CTL_MASK, | ||
| 119 | mux << IMX6Q_GPR3_HDMI_MUX_CTL_SHIFT); | ||
| 120 | } | ||
| 121 | |||
| 122 | static void dw_hdmi_imx_encoder_prepare(struct drm_encoder *encoder) | ||
| 123 | { | ||
| 124 | imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24); | ||
| 125 | } | ||
| 126 | |||
| 127 | static struct drm_encoder_helper_funcs dw_hdmi_imx_encoder_helper_funcs = { | ||
| 128 | .mode_fixup = dw_hdmi_imx_encoder_mode_fixup, | ||
| 129 | .mode_set = dw_hdmi_imx_encoder_mode_set, | ||
| 130 | .prepare = dw_hdmi_imx_encoder_prepare, | ||
| 131 | .commit = dw_hdmi_imx_encoder_commit, | ||
| 132 | .disable = dw_hdmi_imx_encoder_disable, | ||
| 133 | }; | ||
| 134 | |||
| 135 | static struct drm_encoder_funcs dw_hdmi_imx_encoder_funcs = { | ||
| 136 | .destroy = drm_encoder_cleanup, | ||
| 137 | }; | ||
| 138 | |||
| 139 | static struct dw_hdmi_plat_data imx6q_hdmi_drv_data = { | ||
| 140 | .mpll_cfg = imx_mpll_cfg, | ||
| 141 | .cur_ctr = imx_cur_ctr, | ||
| 142 | .sym_term = imx_sym_term, | ||
| 143 | .dev_type = IMX6Q_HDMI, | ||
| 144 | }; | ||
| 145 | |||
| 146 | static struct dw_hdmi_plat_data imx6dl_hdmi_drv_data = { | ||
| 147 | .mpll_cfg = imx_mpll_cfg, | ||
| 148 | .cur_ctr = imx_cur_ctr, | ||
| 149 | .sym_term = imx_sym_term, | ||
| 150 | .dev_type = IMX6DL_HDMI, | ||
| 151 | }; | ||
| 152 | |||
| 153 | static const struct of_device_id dw_hdmi_imx_dt_ids[] = { | ||
| 154 | { .compatible = "fsl,imx6q-hdmi", | ||
| 155 | .data = &imx6q_hdmi_drv_data | ||
| 156 | }, { | ||
| 157 | .compatible = "fsl,imx6dl-hdmi", | ||
| 158 | .data = &imx6dl_hdmi_drv_data | ||
| 159 | }, | ||
| 160 | {}, | ||
| 161 | }; | ||
| 162 | MODULE_DEVICE_TABLE(of, dw_hdmi_imx_dt_ids); | ||
| 163 | |||
| 164 | static int dw_hdmi_imx_bind(struct device *dev, struct device *master, | ||
| 165 | void *data) | ||
| 166 | { | ||
| 167 | struct platform_device *pdev = to_platform_device(dev); | ||
| 168 | const struct dw_hdmi_plat_data *plat_data; | ||
| 169 | const struct of_device_id *match; | ||
| 170 | struct drm_device *drm = data; | ||
| 171 | struct drm_encoder *encoder; | ||
| 172 | struct imx_hdmi *hdmi; | ||
| 173 | struct resource *iores; | ||
| 174 | int irq; | ||
| 175 | int ret; | ||
| 176 | |||
| 177 | if (!pdev->dev.of_node) | ||
| 178 | return -ENODEV; | ||
| 179 | |||
| 180 | hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL); | ||
| 181 | if (!hdmi) | ||
| 182 | return -ENOMEM; | ||
| 183 | |||
| 184 | match = of_match_node(dw_hdmi_imx_dt_ids, pdev->dev.of_node); | ||
| 185 | plat_data = match->data; | ||
| 186 | hdmi->dev = &pdev->dev; | ||
| 187 | encoder = &hdmi->encoder; | ||
| 188 | |||
| 189 | irq = platform_get_irq(pdev, 0); | ||
| 190 | if (irq < 0) | ||
| 191 | return irq; | ||
| 192 | |||
| 193 | iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 194 | if (!iores) | ||
| 195 | return -ENXIO; | ||
| 196 | |||
| 197 | platform_set_drvdata(pdev, hdmi); | ||
| 198 | |||
| 199 | encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node); | ||
| 200 | /* | ||
| 201 | * If we failed to find the CRTC(s) which this encoder is | ||
| 202 | * supposed to be connected to, it's because the CRTC has | ||
| 203 | * not been registered yet. Defer probing, and hope that | ||
| 204 | * the required CRTC is added later. | ||
| 205 | */ | ||
| 206 | if (encoder->possible_crtcs == 0) | ||
| 207 | return -EPROBE_DEFER; | ||
| 208 | |||
| 209 | ret = dw_hdmi_imx_parse_dt(hdmi); | ||
| 210 | if (ret < 0) | ||
| 211 | return ret; | ||
| 212 | |||
| 213 | drm_encoder_helper_add(encoder, &dw_hdmi_imx_encoder_helper_funcs); | ||
| 214 | drm_encoder_init(drm, encoder, &dw_hdmi_imx_encoder_funcs, | ||
| 215 | DRM_MODE_ENCODER_TMDS); | ||
| 216 | |||
| 217 | return dw_hdmi_bind(dev, master, data, encoder, iores, irq, plat_data); | ||
| 218 | } | ||
| 219 | |||
| 220 | static void dw_hdmi_imx_unbind(struct device *dev, struct device *master, | ||
| 221 | void *data) | ||
| 222 | { | ||
| 223 | return dw_hdmi_unbind(dev, master, data); | ||
| 224 | } | ||
| 225 | |||
| 226 | static const struct component_ops dw_hdmi_imx_ops = { | ||
| 227 | .bind = dw_hdmi_imx_bind, | ||
| 228 | .unbind = dw_hdmi_imx_unbind, | ||
| 229 | }; | ||
| 230 | |||
| 231 | static int dw_hdmi_imx_probe(struct platform_device *pdev) | ||
| 232 | { | ||
| 233 | return component_add(&pdev->dev, &dw_hdmi_imx_ops); | ||
| 234 | } | ||
| 235 | |||
| 236 | static int dw_hdmi_imx_remove(struct platform_device *pdev) | ||
| 237 | { | ||
| 238 | component_del(&pdev->dev, &dw_hdmi_imx_ops); | ||
| 239 | |||
| 240 | return 0; | ||
| 241 | } | ||
| 242 | |||
| 243 | static struct platform_driver dw_hdmi_imx_platform_driver = { | ||
| 244 | .probe = dw_hdmi_imx_probe, | ||
| 245 | .remove = dw_hdmi_imx_remove, | ||
| 246 | .driver = { | ||
| 247 | .name = "dwhdmi-imx", | ||
| 248 | .of_match_table = dw_hdmi_imx_dt_ids, | ||
| 249 | }, | ||
| 250 | }; | ||
| 251 | |||
| 252 | module_platform_driver(dw_hdmi_imx_platform_driver); | ||
| 253 | |||
| 254 | MODULE_AUTHOR("Andy Yan <andy.yan@rock-chips.com>"); | ||
| 255 | MODULE_AUTHOR("Yakir Yang <ykk@rock-chips.com>"); | ||
| 256 | MODULE_DESCRIPTION("IMX6 Specific DW-HDMI Driver Extension"); | ||
| 257 | MODULE_LICENSE("GPL"); | ||
| 258 | MODULE_ALIAS("platform:dwhdmi-imx"); | ||
diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c index b250130debc8..a002f53aab0e 100644 --- a/drivers/gpu/drm/imx/imx-drm-core.c +++ b/drivers/gpu/drm/imx/imx-drm-core.c | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | #include <drm/drm_gem_cma_helper.h> | 25 | #include <drm/drm_gem_cma_helper.h> |
| 26 | #include <drm/drm_fb_cma_helper.h> | 26 | #include <drm/drm_fb_cma_helper.h> |
| 27 | #include <drm/drm_plane_helper.h> | 27 | #include <drm/drm_plane_helper.h> |
| 28 | #include <drm/drm_of.h> | ||
| 28 | 29 | ||
| 29 | #include "imx-drm.h" | 30 | #include "imx-drm.h" |
| 30 | 31 | ||
| @@ -46,7 +47,6 @@ struct imx_drm_crtc { | |||
| 46 | struct drm_crtc *crtc; | 47 | struct drm_crtc *crtc; |
| 47 | int pipe; | 48 | int pipe; |
| 48 | struct imx_drm_crtc_helper_funcs imx_drm_helper_funcs; | 49 | struct imx_drm_crtc_helper_funcs imx_drm_helper_funcs; |
| 49 | struct device_node *port; | ||
| 50 | }; | 50 | }; |
| 51 | 51 | ||
| 52 | static int legacyfb_depth = 16; | 52 | static int legacyfb_depth = 16; |
| @@ -116,8 +116,7 @@ int imx_drm_panel_format_pins(struct drm_encoder *encoder, | |||
| 116 | helper = &imx_crtc->imx_drm_helper_funcs; | 116 | helper = &imx_crtc->imx_drm_helper_funcs; |
| 117 | if (helper->set_interface_pix_fmt) | 117 | if (helper->set_interface_pix_fmt) |
| 118 | return helper->set_interface_pix_fmt(encoder->crtc, | 118 | return helper->set_interface_pix_fmt(encoder->crtc, |
| 119 | encoder->encoder_type, interface_pix_fmt, | 119 | interface_pix_fmt, hsync_pin, vsync_pin); |
| 120 | hsync_pin, vsync_pin); | ||
| 121 | return 0; | 120 | return 0; |
| 122 | } | 121 | } |
| 123 | EXPORT_SYMBOL_GPL(imx_drm_panel_format_pins); | 122 | EXPORT_SYMBOL_GPL(imx_drm_panel_format_pins); |
| @@ -365,9 +364,10 @@ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc, | |||
| 365 | 364 | ||
| 366 | imx_drm_crtc->imx_drm_helper_funcs = *imx_drm_helper_funcs; | 365 | imx_drm_crtc->imx_drm_helper_funcs = *imx_drm_helper_funcs; |
| 367 | imx_drm_crtc->pipe = imxdrm->pipes++; | 366 | imx_drm_crtc->pipe = imxdrm->pipes++; |
| 368 | imx_drm_crtc->port = port; | ||
| 369 | imx_drm_crtc->crtc = crtc; | 367 | imx_drm_crtc->crtc = crtc; |
| 370 | 368 | ||
| 369 | crtc->port = port; | ||
| 370 | |||
| 371 | imxdrm->crtc[imx_drm_crtc->pipe] = imx_drm_crtc; | 371 | imxdrm->crtc[imx_drm_crtc->pipe] = imx_drm_crtc; |
| 372 | 372 | ||
| 373 | *new_crtc = imx_drm_crtc; | 373 | *new_crtc = imx_drm_crtc; |
| @@ -408,33 +408,28 @@ int imx_drm_remove_crtc(struct imx_drm_crtc *imx_drm_crtc) | |||
| 408 | } | 408 | } |
| 409 | EXPORT_SYMBOL_GPL(imx_drm_remove_crtc); | 409 | EXPORT_SYMBOL_GPL(imx_drm_remove_crtc); |
| 410 | 410 | ||
| 411 | /* | 411 | int imx_drm_encoder_parse_of(struct drm_device *drm, |
| 412 | * Find the DRM CRTC possible mask for the connected endpoint. | 412 | struct drm_encoder *encoder, struct device_node *np) |
| 413 | * | ||
| 414 | * The encoder possible masks are defined by their position in the | ||
| 415 | * mode_config crtc_list. This means that CRTCs must not be added | ||
| 416 | * or removed once the DRM device has been fully initialised. | ||
| 417 | */ | ||
| 418 | static uint32_t imx_drm_find_crtc_mask(struct imx_drm_device *imxdrm, | ||
| 419 | struct device_node *endpoint) | ||
| 420 | { | 413 | { |
| 421 | struct device_node *port; | 414 | uint32_t crtc_mask = drm_of_find_possible_crtcs(drm, np); |
| 422 | unsigned i; | ||
| 423 | 415 | ||
| 424 | port = of_graph_get_remote_port(endpoint); | 416 | /* |
| 425 | if (!port) | 417 | * If we failed to find the CRTC(s) which this encoder is |
| 426 | return 0; | 418 | * supposed to be connected to, it's because the CRTC has |
| 427 | of_node_put(port); | 419 | * not been registered yet. Defer probing, and hope that |
| 420 | * the required CRTC is added later. | ||
| 421 | */ | ||
| 422 | if (crtc_mask == 0) | ||
| 423 | return -EPROBE_DEFER; | ||
| 428 | 424 | ||
| 429 | for (i = 0; i < MAX_CRTC; i++) { | 425 | encoder->possible_crtcs = crtc_mask; |
| 430 | struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[i]; | ||
| 431 | 426 | ||
| 432 | if (imx_drm_crtc && imx_drm_crtc->port == port) | 427 | /* FIXME: this is the mask of outputs which can clone this output. */ |
| 433 | return drm_crtc_mask(imx_drm_crtc->crtc); | 428 | encoder->possible_clones = ~0; |
| 434 | } | ||
| 435 | 429 | ||
| 436 | return 0; | 430 | return 0; |
| 437 | } | 431 | } |
| 432 | EXPORT_SYMBOL_GPL(imx_drm_encoder_parse_of); | ||
| 438 | 433 | ||
| 439 | static struct device_node *imx_drm_of_get_next_endpoint( | 434 | static struct device_node *imx_drm_of_get_next_endpoint( |
| 440 | const struct device_node *parent, struct device_node *prev) | 435 | const struct device_node *parent, struct device_node *prev) |
| @@ -445,48 +440,6 @@ static struct device_node *imx_drm_of_get_next_endpoint( | |||
| 445 | return node; | 440 | return node; |
| 446 | } | 441 | } |
| 447 | 442 | ||
| 448 | int imx_drm_encoder_parse_of(struct drm_device *drm, | ||
| 449 | struct drm_encoder *encoder, struct device_node *np) | ||
| 450 | { | ||
| 451 | struct imx_drm_device *imxdrm = drm->dev_private; | ||
| 452 | struct device_node *ep = NULL; | ||
| 453 | uint32_t crtc_mask = 0; | ||
| 454 | int i; | ||
| 455 | |||
| 456 | for (i = 0; ; i++) { | ||
| 457 | u32 mask; | ||
| 458 | |||
| 459 | ep = imx_drm_of_get_next_endpoint(np, ep); | ||
| 460 | if (!ep) | ||
| 461 | break; | ||
| 462 | |||
| 463 | mask = imx_drm_find_crtc_mask(imxdrm, ep); | ||
| 464 | |||
| 465 | /* | ||
| 466 | * If we failed to find the CRTC(s) which this encoder is | ||
| 467 | * supposed to be connected to, it's because the CRTC has | ||
| 468 | * not been registered yet. Defer probing, and hope that | ||
| 469 | * the required CRTC is added later. | ||
| 470 | */ | ||
| 471 | if (mask == 0) | ||
| 472 | return -EPROBE_DEFER; | ||
| 473 | |||
| 474 | crtc_mask |= mask; | ||
| 475 | } | ||
| 476 | |||
| 477 | of_node_put(ep); | ||
| 478 | if (i == 0) | ||
| 479 | return -ENOENT; | ||
| 480 | |||
| 481 | encoder->possible_crtcs = crtc_mask; | ||
| 482 | |||
| 483 | /* FIXME: this is the mask of outputs which can clone this output. */ | ||
| 484 | encoder->possible_clones = ~0; | ||
| 485 | |||
| 486 | return 0; | ||
| 487 | } | ||
| 488 | EXPORT_SYMBOL_GPL(imx_drm_encoder_parse_of); | ||
| 489 | |||
| 490 | /* | 443 | /* |
| 491 | * @node: device tree node containing encoder input ports | 444 | * @node: device tree node containing encoder input ports |
| 492 | * @encoder: drm_encoder | 445 | * @encoder: drm_encoder |
| @@ -510,7 +463,7 @@ int imx_drm_encoder_get_mux_id(struct device_node *node, | |||
| 510 | 463 | ||
| 511 | port = of_graph_get_remote_port(ep); | 464 | port = of_graph_get_remote_port(ep); |
| 512 | of_node_put(port); | 465 | of_node_put(port); |
| 513 | if (port == imx_crtc->port) { | 466 | if (port == imx_crtc->crtc->port) { |
| 514 | ret = of_graph_parse_endpoint(ep, &endpoint); | 467 | ret = of_graph_parse_endpoint(ep, &endpoint); |
| 515 | return ret ? ret : endpoint.port; | 468 | return ret ? ret : endpoint.port; |
| 516 | } | 469 | } |
diff --git a/drivers/gpu/drm/imx/imx-drm.h b/drivers/gpu/drm/imx/imx-drm.h index 7453ae00c412..3c559ccd6af0 100644 --- a/drivers/gpu/drm/imx/imx-drm.h +++ b/drivers/gpu/drm/imx/imx-drm.h | |||
| @@ -17,7 +17,7 @@ int imx_drm_crtc_id(struct imx_drm_crtc *crtc); | |||
| 17 | struct imx_drm_crtc_helper_funcs { | 17 | struct imx_drm_crtc_helper_funcs { |
| 18 | int (*enable_vblank)(struct drm_crtc *crtc); | 18 | int (*enable_vblank)(struct drm_crtc *crtc); |
| 19 | void (*disable_vblank)(struct drm_crtc *crtc); | 19 | void (*disable_vblank)(struct drm_crtc *crtc); |
| 20 | int (*set_interface_pix_fmt)(struct drm_crtc *crtc, u32 encoder_type, | 20 | int (*set_interface_pix_fmt)(struct drm_crtc *crtc, |
| 21 | u32 pix_fmt, int hsync_pin, int vsync_pin); | 21 | u32 pix_fmt, int hsync_pin, int vsync_pin); |
| 22 | const struct drm_crtc_helper_funcs *crtc_helper_funcs; | 22 | const struct drm_crtc_helper_funcs *crtc_helper_funcs; |
| 23 | const struct drm_crtc_funcs *crtc_funcs; | 23 | const struct drm_crtc_funcs *crtc_funcs; |
diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c index c60460043e24..1b86aac0b341 100644 --- a/drivers/gpu/drm/imx/imx-ldb.c +++ b/drivers/gpu/drm/imx/imx-ldb.c | |||
| @@ -163,7 +163,7 @@ static void imx_ldb_encoder_prepare(struct drm_encoder *encoder) | |||
| 163 | { | 163 | { |
| 164 | struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder); | 164 | struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder); |
| 165 | struct imx_ldb *ldb = imx_ldb_ch->ldb; | 165 | struct imx_ldb *ldb = imx_ldb_ch->ldb; |
| 166 | struct drm_display_mode *mode = &encoder->crtc->mode; | 166 | struct drm_display_mode *mode = &encoder->crtc->hwmode; |
| 167 | u32 pixel_fmt; | 167 | u32 pixel_fmt; |
| 168 | unsigned long serial_clk; | 168 | unsigned long serial_clk; |
| 169 | unsigned long di_clk = mode->clock * 1000; | 169 | unsigned long di_clk = mode->clock * 1000; |
| @@ -241,8 +241,8 @@ static void imx_ldb_encoder_commit(struct drm_encoder *encoder) | |||
| 241 | } | 241 | } |
| 242 | 242 | ||
| 243 | static void imx_ldb_encoder_mode_set(struct drm_encoder *encoder, | 243 | static void imx_ldb_encoder_mode_set(struct drm_encoder *encoder, |
| 244 | struct drm_display_mode *mode, | 244 | struct drm_display_mode *orig_mode, |
| 245 | struct drm_display_mode *adjusted_mode) | 245 | struct drm_display_mode *mode) |
| 246 | { | 246 | { |
| 247 | struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder); | 247 | struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder); |
| 248 | struct imx_ldb *ldb = imx_ldb_ch->ldb; | 248 | struct imx_ldb *ldb = imx_ldb_ch->ldb; |
| @@ -574,6 +574,8 @@ static void imx_ldb_unbind(struct device *dev, struct device *master, | |||
| 574 | 574 | ||
| 575 | channel->connector.funcs->destroy(&channel->connector); | 575 | channel->connector.funcs->destroy(&channel->connector); |
| 576 | channel->encoder.funcs->destroy(&channel->encoder); | 576 | channel->encoder.funcs->destroy(&channel->encoder); |
| 577 | |||
| 578 | kfree(channel->edid); | ||
| 577 | } | 579 | } |
| 578 | } | 580 | } |
| 579 | 581 | ||
diff --git a/drivers/gpu/drm/imx/imx-tve.c b/drivers/gpu/drm/imx/imx-tve.c index a729f4f7074c..b63601d04601 100644 --- a/drivers/gpu/drm/imx/imx-tve.c +++ b/drivers/gpu/drm/imx/imx-tve.c | |||
| @@ -307,8 +307,8 @@ static void imx_tve_encoder_prepare(struct drm_encoder *encoder) | |||
| 307 | } | 307 | } |
| 308 | 308 | ||
| 309 | static void imx_tve_encoder_mode_set(struct drm_encoder *encoder, | 309 | static void imx_tve_encoder_mode_set(struct drm_encoder *encoder, |
| 310 | struct drm_display_mode *mode, | 310 | struct drm_display_mode *orig_mode, |
| 311 | struct drm_display_mode *adjusted_mode) | 311 | struct drm_display_mode *mode) |
| 312 | { | 312 | { |
| 313 | struct imx_tve *tve = enc_to_tve(encoder); | 313 | struct imx_tve *tve = enc_to_tve(encoder); |
| 314 | unsigned long rounded_rate; | 314 | unsigned long rounded_rate; |
diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3-crtc.c index ebee59cb96d8..98551e356e12 100644 --- a/drivers/gpu/drm/imx/ipuv3-crtc.c +++ b/drivers/gpu/drm/imx/ipuv3-crtc.c | |||
| @@ -46,7 +46,6 @@ struct ipu_crtc { | |||
| 46 | struct drm_framebuffer *newfb; | 46 | struct drm_framebuffer *newfb; |
| 47 | int irq; | 47 | int irq; |
| 48 | u32 interface_pix_fmt; | 48 | u32 interface_pix_fmt; |
| 49 | unsigned long di_clkflags; | ||
| 50 | int di_hsync_pin; | 49 | int di_hsync_pin; |
| 51 | int di_vsync_pin; | 50 | int di_vsync_pin; |
| 52 | }; | 51 | }; |
| @@ -141,47 +140,51 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc, | |||
| 141 | int x, int y, | 140 | int x, int y, |
| 142 | struct drm_framebuffer *old_fb) | 141 | struct drm_framebuffer *old_fb) |
| 143 | { | 142 | { |
| 143 | struct drm_device *dev = crtc->dev; | ||
| 144 | struct drm_encoder *encoder; | ||
| 144 | struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); | 145 | struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); |
| 145 | int ret; | ||
| 146 | struct ipu_di_signal_cfg sig_cfg = {}; | 146 | struct ipu_di_signal_cfg sig_cfg = {}; |
| 147 | unsigned long encoder_types = 0; | ||
| 147 | u32 out_pixel_fmt; | 148 | u32 out_pixel_fmt; |
| 149 | int ret; | ||
| 148 | 150 | ||
| 149 | dev_dbg(ipu_crtc->dev, "%s: mode->hdisplay: %d\n", __func__, | 151 | dev_dbg(ipu_crtc->dev, "%s: mode->hdisplay: %d\n", __func__, |
| 150 | mode->hdisplay); | 152 | mode->hdisplay); |
| 151 | dev_dbg(ipu_crtc->dev, "%s: mode->vdisplay: %d\n", __func__, | 153 | dev_dbg(ipu_crtc->dev, "%s: mode->vdisplay: %d\n", __func__, |
| 152 | mode->vdisplay); | 154 | mode->vdisplay); |
| 153 | 155 | ||
| 154 | out_pixel_fmt = ipu_crtc->interface_pix_fmt; | 156 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) |
| 157 | if (encoder->crtc == crtc) | ||
| 158 | encoder_types |= BIT(encoder->encoder_type); | ||
| 155 | 159 | ||
| 156 | if (mode->flags & DRM_MODE_FLAG_INTERLACE) | 160 | dev_dbg(ipu_crtc->dev, "%s: attached to encoder types 0x%lx\n", |
| 157 | sig_cfg.interlaced = 1; | 161 | __func__, encoder_types); |
| 158 | if (mode->flags & DRM_MODE_FLAG_PHSYNC) | 162 | |
| 159 | sig_cfg.Hsync_pol = 1; | 163 | /* |
| 160 | if (mode->flags & DRM_MODE_FLAG_PVSYNC) | 164 | * If we have DAC, TVDAC or LDB, then we need the IPU DI clock |
| 161 | sig_cfg.Vsync_pol = 1; | 165 | * to be the same as the LDB DI clock. |
| 166 | */ | ||
| 167 | if (encoder_types & (BIT(DRM_MODE_ENCODER_DAC) | | ||
| 168 | BIT(DRM_MODE_ENCODER_TVDAC) | | ||
| 169 | BIT(DRM_MODE_ENCODER_LVDS))) | ||
| 170 | sig_cfg.clkflags = IPU_DI_CLKMODE_SYNC | IPU_DI_CLKMODE_EXT; | ||
| 171 | else | ||
| 172 | sig_cfg.clkflags = 0; | ||
| 173 | |||
| 174 | out_pixel_fmt = ipu_crtc->interface_pix_fmt; | ||
| 162 | 175 | ||
| 163 | sig_cfg.enable_pol = 1; | 176 | sig_cfg.enable_pol = 1; |
| 164 | sig_cfg.clk_pol = 0; | 177 | sig_cfg.clk_pol = 0; |
| 165 | sig_cfg.width = mode->hdisplay; | ||
| 166 | sig_cfg.height = mode->vdisplay; | ||
| 167 | sig_cfg.pixel_fmt = out_pixel_fmt; | 178 | sig_cfg.pixel_fmt = out_pixel_fmt; |
| 168 | sig_cfg.h_start_width = mode->htotal - mode->hsync_end; | ||
| 169 | sig_cfg.h_sync_width = mode->hsync_end - mode->hsync_start; | ||
| 170 | sig_cfg.h_end_width = mode->hsync_start - mode->hdisplay; | ||
| 171 | |||
| 172 | sig_cfg.v_start_width = mode->vtotal - mode->vsync_end; | ||
| 173 | sig_cfg.v_sync_width = mode->vsync_end - mode->vsync_start; | ||
| 174 | sig_cfg.v_end_width = mode->vsync_start - mode->vdisplay; | ||
| 175 | sig_cfg.pixelclock = mode->clock * 1000; | ||
| 176 | sig_cfg.clkflags = ipu_crtc->di_clkflags; | ||
| 177 | |||
| 178 | sig_cfg.v_to_h_sync = 0; | 179 | sig_cfg.v_to_h_sync = 0; |
| 179 | |||
| 180 | sig_cfg.hsync_pin = ipu_crtc->di_hsync_pin; | 180 | sig_cfg.hsync_pin = ipu_crtc->di_hsync_pin; |
| 181 | sig_cfg.vsync_pin = ipu_crtc->di_vsync_pin; | 181 | sig_cfg.vsync_pin = ipu_crtc->di_vsync_pin; |
| 182 | 182 | ||
| 183 | ret = ipu_dc_init_sync(ipu_crtc->dc, ipu_crtc->di, sig_cfg.interlaced, | 183 | drm_display_mode_to_videomode(mode, &sig_cfg.mode); |
| 184 | out_pixel_fmt, mode->hdisplay); | 184 | |
| 185 | ret = ipu_dc_init_sync(ipu_crtc->dc, ipu_crtc->di, | ||
| 186 | mode->flags & DRM_MODE_FLAG_INTERLACE, | ||
| 187 | out_pixel_fmt, mode->hdisplay); | ||
| 185 | if (ret) { | 188 | if (ret) { |
| 186 | dev_err(ipu_crtc->dev, | 189 | dev_err(ipu_crtc->dev, |
| 187 | "initializing display controller failed with %d\n", | 190 | "initializing display controller failed with %d\n", |
| @@ -237,6 +240,18 @@ static bool ipu_crtc_mode_fixup(struct drm_crtc *crtc, | |||
| 237 | const struct drm_display_mode *mode, | 240 | const struct drm_display_mode *mode, |
| 238 | struct drm_display_mode *adjusted_mode) | 241 | struct drm_display_mode *adjusted_mode) |
| 239 | { | 242 | { |
| 243 | struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); | ||
| 244 | struct videomode vm; | ||
| 245 | int ret; | ||
| 246 | |||
| 247 | drm_display_mode_to_videomode(adjusted_mode, &vm); | ||
| 248 | |||
| 249 | ret = ipu_di_adjust_videomode(ipu_crtc->di, &vm); | ||
| 250 | if (ret) | ||
| 251 | return false; | ||
| 252 | |||
| 253 | drm_display_mode_from_videomode(&vm, adjusted_mode); | ||
| 254 | |||
| 240 | return true; | 255 | return true; |
| 241 | } | 256 | } |
| 242 | 257 | ||
| @@ -275,7 +290,7 @@ static void ipu_disable_vblank(struct drm_crtc *crtc) | |||
| 275 | ipu_crtc->newfb = NULL; | 290 | ipu_crtc->newfb = NULL; |
| 276 | } | 291 | } |
| 277 | 292 | ||
| 278 | static int ipu_set_interface_pix_fmt(struct drm_crtc *crtc, u32 encoder_type, | 293 | static int ipu_set_interface_pix_fmt(struct drm_crtc *crtc, |
| 279 | u32 pixfmt, int hsync_pin, int vsync_pin) | 294 | u32 pixfmt, int hsync_pin, int vsync_pin) |
| 280 | { | 295 | { |
| 281 | struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); | 296 | struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); |
| @@ -284,19 +299,6 @@ static int ipu_set_interface_pix_fmt(struct drm_crtc *crtc, u32 encoder_type, | |||
| 284 | ipu_crtc->di_hsync_pin = hsync_pin; | 299 | ipu_crtc->di_hsync_pin = hsync_pin; |
| 285 | ipu_crtc->di_vsync_pin = vsync_pin; | 300 | ipu_crtc->di_vsync_pin = vsync_pin; |
| 286 | 301 | ||
| 287 | switch (encoder_type) { | ||
| 288 | case DRM_MODE_ENCODER_DAC: | ||
| 289 | case DRM_MODE_ENCODER_TVDAC: | ||
| 290 | case DRM_MODE_ENCODER_LVDS: | ||
| 291 | ipu_crtc->di_clkflags = IPU_DI_CLKMODE_SYNC | | ||
| 292 | IPU_DI_CLKMODE_EXT; | ||
| 293 | break; | ||
| 294 | case DRM_MODE_ENCODER_TMDS: | ||
| 295 | case DRM_MODE_ENCODER_NONE: | ||
| 296 | ipu_crtc->di_clkflags = 0; | ||
| 297 | break; | ||
| 298 | } | ||
| 299 | |||
| 300 | return 0; | 302 | return 0; |
| 301 | } | 303 | } |
| 302 | 304 | ||
diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c index 796c3c1c170a..5e83e007080f 100644 --- a/drivers/gpu/drm/imx/parallel-display.c +++ b/drivers/gpu/drm/imx/parallel-display.c | |||
| @@ -130,8 +130,8 @@ static void imx_pd_encoder_commit(struct drm_encoder *encoder) | |||
| 130 | } | 130 | } |
| 131 | 131 | ||
| 132 | static void imx_pd_encoder_mode_set(struct drm_encoder *encoder, | 132 | static void imx_pd_encoder_mode_set(struct drm_encoder *encoder, |
| 133 | struct drm_display_mode *mode, | 133 | struct drm_display_mode *orig_mode, |
| 134 | struct drm_display_mode *adjusted_mode) | 134 | struct drm_display_mode *mode) |
| 135 | { | 135 | { |
| 136 | } | 136 | } |
| 137 | 137 | ||
| @@ -257,6 +257,8 @@ static void imx_pd_unbind(struct device *dev, struct device *master, | |||
| 257 | 257 | ||
| 258 | imxpd->encoder.funcs->destroy(&imxpd->encoder); | 258 | imxpd->encoder.funcs->destroy(&imxpd->encoder); |
| 259 | imxpd->connector.funcs->destroy(&imxpd->connector); | 259 | imxpd->connector.funcs->destroy(&imxpd->connector); |
| 260 | |||
| 261 | kfree(imxpd->edid); | ||
| 260 | } | 262 | } |
| 261 | 263 | ||
| 262 | static const struct component_ops imx_pd_ops = { | 264 | static const struct component_ops imx_pd_ops = { |
| @@ -272,6 +274,7 @@ static int imx_pd_probe(struct platform_device *pdev) | |||
| 272 | static int imx_pd_remove(struct platform_device *pdev) | 274 | static int imx_pd_remove(struct platform_device *pdev) |
| 273 | { | 275 | { |
| 274 | component_del(&pdev->dev, &imx_pd_ops); | 276 | component_del(&pdev->dev, &imx_pd_ops); |
| 277 | |||
| 275 | return 0; | 278 | return 0; |
| 276 | } | 279 | } |
| 277 | 280 | ||
diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig index ca9f085efa92..0d87bf6ddd96 100644 --- a/drivers/gpu/drm/rockchip/Kconfig +++ b/drivers/gpu/drm/rockchip/Kconfig | |||
| @@ -15,3 +15,13 @@ config DRM_ROCKCHIP | |||
| 15 | management to userspace. This driver does not provide | 15 | management to userspace. This driver does not provide |
| 16 | 2D or 3D acceleration; acceleration is performed by other | 16 | 2D or 3D acceleration; acceleration is performed by other |
| 17 | IP found on the SoC. | 17 | IP found on the SoC. |
| 18 | |||
| 19 | config ROCKCHIP_DW_HDMI | ||
| 20 | tristate "Rockchip specific extensions for Synopsys DW HDMI" | ||
| 21 | depends on DRM_ROCKCHIP | ||
| 22 | select DRM_DW_HDMI | ||
| 23 | help | ||
| 24 | This selects support for Rockchip SoC specific extensions | ||
| 25 | for the Synopsys DesignWare HDMI driver. If you want to | ||
| 26 | enable HDMI on RK3288 based SoC, you should selet this | ||
| 27 | option. | ||
diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index 2cb0672f57ed..f3d8a19c641f 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile | |||
| @@ -5,4 +5,6 @@ | |||
| 5 | rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o rockchip_drm_fbdev.o \ | 5 | rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o rockchip_drm_fbdev.o \ |
| 6 | rockchip_drm_gem.o | 6 | rockchip_drm_gem.o |
| 7 | 7 | ||
| 8 | obj-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o | ||
| 9 | |||
| 8 | obj-$(CONFIG_DRM_ROCKCHIP) += rockchipdrm.o rockchip_drm_vop.o | 10 | obj-$(CONFIG_DRM_ROCKCHIP) += rockchipdrm.o rockchip_drm_vop.o |
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c new file mode 100644 index 000000000000..d236faa05b19 --- /dev/null +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | |||
| @@ -0,0 +1,341 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License as published by | ||
| 6 | * the Free Software Foundation; either version 2 of the License, or | ||
| 7 | * (at your option) any later version. | ||
| 8 | */ | ||
| 9 | |||
| 10 | #include <linux/module.h> | ||
| 11 | #include <linux/platform_device.h> | ||
| 12 | #include <linux/mfd/syscon.h> | ||
| 13 | #include <linux/regmap.h> | ||
| 14 | #include <drm/drm_of.h> | ||
| 15 | #include <drm/drmP.h> | ||
| 16 | #include <drm/drm_crtc_helper.h> | ||
| 17 | #include <drm/drm_edid.h> | ||
| 18 | #include <drm/drm_encoder_slave.h> | ||
| 19 | #include <drm/bridge/dw_hdmi.h> | ||
| 20 | |||
| 21 | #include "rockchip_drm_drv.h" | ||
| 22 | #include "rockchip_drm_vop.h" | ||
| 23 | |||
| 24 | #define GRF_SOC_CON6 0x025c | ||
| 25 | #define HDMI_SEL_VOP_LIT (1 << 4) | ||
| 26 | |||
| 27 | struct rockchip_hdmi { | ||
| 28 | struct device *dev; | ||
| 29 | struct regmap *regmap; | ||
| 30 | struct drm_encoder encoder; | ||
| 31 | }; | ||
| 32 | |||
| 33 | #define to_rockchip_hdmi(x) container_of(x, struct rockchip_hdmi, x) | ||
| 34 | |||
| 35 | static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = { | ||
| 36 | { | ||
| 37 | 27000000, { | ||
| 38 | { 0x00b3, 0x0000}, | ||
| 39 | { 0x2153, 0x0000}, | ||
| 40 | { 0x40f3, 0x0000} | ||
| 41 | }, | ||
| 42 | }, { | ||
| 43 | 36000000, { | ||
| 44 | { 0x00b3, 0x0000}, | ||
| 45 | { 0x2153, 0x0000}, | ||
| 46 | { 0x40f3, 0x0000} | ||
| 47 | }, | ||
| 48 | }, { | ||
| 49 | 40000000, { | ||
| 50 | { 0x00b3, 0x0000}, | ||
| 51 | { 0x2153, 0x0000}, | ||
| 52 | { 0x40f3, 0x0000} | ||
| 53 | }, | ||
| 54 | }, { | ||
| 55 | 54000000, { | ||
| 56 | { 0x0072, 0x0001}, | ||
| 57 | { 0x2142, 0x0001}, | ||
| 58 | { 0x40a2, 0x0001}, | ||
| 59 | }, | ||
| 60 | }, { | ||
| 61 | 65000000, { | ||
| 62 | { 0x0072, 0x0001}, | ||
| 63 | { 0x2142, 0x0001}, | ||
| 64 | { 0x40a2, 0x0001}, | ||
| 65 | }, | ||
| 66 | }, { | ||
| 67 | 66000000, { | ||
| 68 | { 0x013e, 0x0003}, | ||
| 69 | { 0x217e, 0x0002}, | ||
| 70 | { 0x4061, 0x0002} | ||
| 71 | }, | ||
| 72 | }, { | ||
| 73 | 74250000, { | ||
| 74 | { 0x0072, 0x0001}, | ||
| 75 | { 0x2145, 0x0002}, | ||
| 76 | { 0x4061, 0x0002} | ||
| 77 | }, | ||
| 78 | }, { | ||
| 79 | 83500000, { | ||
| 80 | { 0x0072, 0x0001}, | ||
| 81 | }, | ||
| 82 | }, { | ||
| 83 | 108000000, { | ||
| 84 | { 0x0051, 0x0002}, | ||
| 85 | { 0x2145, 0x0002}, | ||
| 86 | { 0x4061, 0x0002} | ||
| 87 | }, | ||
| 88 | }, { | ||
| 89 | 106500000, { | ||
| 90 | { 0x0051, 0x0002}, | ||
| 91 | { 0x2145, 0x0002}, | ||
| 92 | { 0x4061, 0x0002} | ||
| 93 | }, | ||
| 94 | }, { | ||
| 95 | 146250000, { | ||
| 96 | { 0x0051, 0x0002}, | ||
| 97 | { 0x2145, 0x0002}, | ||
| 98 | { 0x4061, 0x0002} | ||
| 99 | }, | ||
| 100 | }, { | ||
| 101 | 148500000, { | ||
| 102 | { 0x0051, 0x0003}, | ||
| 103 | { 0x214c, 0x0003}, | ||
| 104 | { 0x4064, 0x0003} | ||
| 105 | }, | ||
| 106 | }, { | ||
| 107 | ~0UL, { | ||
| 108 | { 0x00a0, 0x000a }, | ||
| 109 | { 0x2001, 0x000f }, | ||
| 110 | { 0x4002, 0x000f }, | ||
| 111 | }, | ||
| 112 | } | ||
| 113 | }; | ||
| 114 | |||
| 115 | static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr[] = { | ||
| 116 | /* pixelclk bpp8 bpp10 bpp12 */ | ||
| 117 | { | ||
| 118 | 40000000, { 0x0018, 0x0018, 0x0018 }, | ||
| 119 | }, { | ||
| 120 | 65000000, { 0x0028, 0x0028, 0x0028 }, | ||
| 121 | }, { | ||
| 122 | 66000000, { 0x0038, 0x0038, 0x0038 }, | ||
| 123 | }, { | ||
| 124 | 74250000, { 0x0028, 0x0038, 0x0038 }, | ||
| 125 | }, { | ||
| 126 | 83500000, { 0x0028, 0x0038, 0x0038 }, | ||
| 127 | }, { | ||
| 128 | 146250000, { 0x0038, 0x0038, 0x0038 }, | ||
| 129 | }, { | ||
| 130 | 148500000, { 0x0000, 0x0038, 0x0038 }, | ||
| 131 | }, { | ||
| 132 | ~0UL, { 0x0000, 0x0000, 0x0000}, | ||
| 133 | } | ||
| 134 | }; | ||
| 135 | |||
| 136 | static const struct dw_hdmi_sym_term rockchip_sym_term[] = { | ||
| 137 | /*pixelclk symbol term*/ | ||
| 138 | { 74250000, 0x8009, 0x0004 }, | ||
| 139 | { 148500000, 0x8029, 0x0004 }, | ||
| 140 | { 297000000, 0x8039, 0x0005 }, | ||
| 141 | { ~0UL, 0x0000, 0x0000 } | ||
| 142 | }; | ||
| 143 | |||
| 144 | static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi) | ||
| 145 | { | ||
| 146 | struct device_node *np = hdmi->dev->of_node; | ||
| 147 | |||
| 148 | hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); | ||
| 149 | if (IS_ERR(hdmi->regmap)) { | ||
| 150 | dev_err(hdmi->dev, "Unable to get rockchip,grf\n"); | ||
| 151 | return PTR_ERR(hdmi->regmap); | ||
| 152 | } | ||
| 153 | |||
| 154 | return 0; | ||
| 155 | } | ||
| 156 | |||
| 157 | static enum drm_mode_status | ||
| 158 | dw_hdmi_rockchip_mode_valid(struct drm_connector *connector, | ||
| 159 | struct drm_display_mode *mode) | ||
| 160 | { | ||
| 161 | const struct dw_hdmi_mpll_config *mpll_cfg = rockchip_mpll_cfg; | ||
| 162 | int pclk = mode->clock * 1000; | ||
| 163 | bool valid = false; | ||
| 164 | int i; | ||
| 165 | |||
| 166 | for (i = 0; mpll_cfg[i].mpixelclock != (~0UL); i++) { | ||
| 167 | if (pclk == mpll_cfg[i].mpixelclock) { | ||
| 168 | valid = true; | ||
| 169 | break; | ||
| 170 | } | ||
| 171 | } | ||
| 172 | |||
| 173 | return (valid) ? MODE_OK : MODE_BAD; | ||
| 174 | } | ||
| 175 | |||
| 176 | static struct drm_encoder_funcs dw_hdmi_rockchip_encoder_funcs = { | ||
| 177 | .destroy = drm_encoder_cleanup, | ||
| 178 | }; | ||
| 179 | |||
| 180 | static void dw_hdmi_rockchip_encoder_disable(struct drm_encoder *encoder) | ||
| 181 | { | ||
| 182 | } | ||
| 183 | |||
| 184 | static bool | ||
| 185 | dw_hdmi_rockchip_encoder_mode_fixup(struct drm_encoder *encoder, | ||
| 186 | const struct drm_display_mode *mode, | ||
| 187 | struct drm_display_mode *adj_mode) | ||
| 188 | { | ||
| 189 | return true; | ||
| 190 | } | ||
| 191 | |||
| 192 | static void dw_hdmi_rockchip_encoder_mode_set(struct drm_encoder *encoder, | ||
| 193 | struct drm_display_mode *mode, | ||
| 194 | struct drm_display_mode *adj_mode) | ||
| 195 | { | ||
| 196 | } | ||
| 197 | |||
| 198 | static void dw_hdmi_rockchip_encoder_commit(struct drm_encoder *encoder) | ||
| 199 | { | ||
| 200 | struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder); | ||
| 201 | u32 val; | ||
| 202 | int mux; | ||
| 203 | |||
| 204 | mux = rockchip_drm_encoder_get_mux_id(hdmi->dev->of_node, encoder); | ||
| 205 | if (mux) | ||
| 206 | val = HDMI_SEL_VOP_LIT | (HDMI_SEL_VOP_LIT << 16); | ||
| 207 | else | ||
| 208 | val = HDMI_SEL_VOP_LIT << 16; | ||
| 209 | |||
| 210 | regmap_write(hdmi->regmap, GRF_SOC_CON6, val); | ||
| 211 | dev_dbg(hdmi->dev, "vop %s output to hdmi\n", | ||
| 212 | (mux) ? "LIT" : "BIG"); | ||
| 213 | } | ||
| 214 | |||
| 215 | static void dw_hdmi_rockchip_encoder_prepare(struct drm_encoder *encoder) | ||
| 216 | { | ||
| 217 | rockchip_drm_crtc_mode_config(encoder->crtc, DRM_MODE_CONNECTOR_HDMIA, | ||
| 218 | ROCKCHIP_OUT_MODE_AAAA); | ||
| 219 | } | ||
| 220 | |||
| 221 | static struct drm_encoder_helper_funcs dw_hdmi_rockchip_encoder_helper_funcs = { | ||
| 222 | .mode_fixup = dw_hdmi_rockchip_encoder_mode_fixup, | ||
| 223 | .mode_set = dw_hdmi_rockchip_encoder_mode_set, | ||
| 224 | .prepare = dw_hdmi_rockchip_encoder_prepare, | ||
| 225 | .commit = dw_hdmi_rockchip_encoder_commit, | ||
| 226 | .disable = dw_hdmi_rockchip_encoder_disable, | ||
| 227 | }; | ||
| 228 | |||
| 229 | static const struct dw_hdmi_plat_data rockchip_hdmi_drv_data = { | ||
| 230 | .mode_valid = dw_hdmi_rockchip_mode_valid, | ||
| 231 | .mpll_cfg = rockchip_mpll_cfg, | ||
| 232 | .cur_ctr = rockchip_cur_ctr, | ||
| 233 | .sym_term = rockchip_sym_term, | ||
| 234 | .dev_type = RK3288_HDMI, | ||
| 235 | }; | ||
| 236 | |||
| 237 | static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = { | ||
| 238 | { .compatible = "rockchip,rk3288-dw-hdmi", | ||
| 239 | .data = &rockchip_hdmi_drv_data | ||
| 240 | }, | ||
| 241 | {}, | ||
| 242 | }; | ||
| 243 | MODULE_DEVICE_TABLE(of, dw_hdmi_rockchip_dt_ids); | ||
| 244 | |||
| 245 | static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, | ||
| 246 | void *data) | ||
| 247 | { | ||
| 248 | struct platform_device *pdev = to_platform_device(dev); | ||
| 249 | const struct dw_hdmi_plat_data *plat_data; | ||
| 250 | const struct of_device_id *match; | ||
| 251 | struct drm_device *drm = data; | ||
| 252 | struct drm_encoder *encoder; | ||
| 253 | struct rockchip_hdmi *hdmi; | ||
| 254 | struct resource *iores; | ||
| 255 | int irq; | ||
| 256 | int ret; | ||
| 257 | |||
| 258 | if (!pdev->dev.of_node) | ||
| 259 | return -ENODEV; | ||
| 260 | |||
| 261 | hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL); | ||
| 262 | if (!hdmi) | ||
| 263 | return -ENOMEM; | ||
| 264 | |||
| 265 | match = of_match_node(dw_hdmi_rockchip_dt_ids, pdev->dev.of_node); | ||
| 266 | plat_data = match->data; | ||
| 267 | hdmi->dev = &pdev->dev; | ||
| 268 | encoder = &hdmi->encoder; | ||
| 269 | |||
| 270 | irq = platform_get_irq(pdev, 0); | ||
| 271 | if (irq < 0) | ||
| 272 | return irq; | ||
| 273 | |||
| 274 | iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 275 | if (!iores) | ||
| 276 | return -ENXIO; | ||
| 277 | |||
| 278 | platform_set_drvdata(pdev, hdmi); | ||
| 279 | |||
| 280 | encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node); | ||
| 281 | /* | ||
| 282 | * If we failed to find the CRTC(s) which this encoder is | ||
| 283 | * supposed to be connected to, it's because the CRTC has | ||
| 284 | * not been registered yet. Defer probing, and hope that | ||
| 285 | * the required CRTC is added later. | ||
| 286 | */ | ||
| 287 | if (encoder->possible_crtcs == 0) | ||
| 288 | return -EPROBE_DEFER; | ||
| 289 | |||
| 290 | ret = rockchip_hdmi_parse_dt(hdmi); | ||
| 291 | if (ret) { | ||
| 292 | dev_err(hdmi->dev, "Unable to parse OF data\n"); | ||
| 293 | return ret; | ||
| 294 | } | ||
| 295 | |||
| 296 | drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs); | ||
| 297 | drm_encoder_init(drm, encoder, &dw_hdmi_rockchip_encoder_funcs, | ||
| 298 | DRM_MODE_ENCODER_TMDS); | ||
| 299 | |||
| 300 | return dw_hdmi_bind(dev, master, data, encoder, iores, irq, plat_data); | ||
| 301 | } | ||
| 302 | |||
| 303 | static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master, | ||
| 304 | void *data) | ||
| 305 | { | ||
| 306 | return dw_hdmi_unbind(dev, master, data); | ||
| 307 | } | ||
| 308 | |||
| 309 | static const struct component_ops dw_hdmi_rockchip_ops = { | ||
| 310 | .bind = dw_hdmi_rockchip_bind, | ||
| 311 | .unbind = dw_hdmi_rockchip_unbind, | ||
| 312 | }; | ||
| 313 | |||
| 314 | static int dw_hdmi_rockchip_probe(struct platform_device *pdev) | ||
| 315 | { | ||
| 316 | return component_add(&pdev->dev, &dw_hdmi_rockchip_ops); | ||
| 317 | } | ||
| 318 | |||
| 319 | static int dw_hdmi_rockchip_remove(struct platform_device *pdev) | ||
| 320 | { | ||
| 321 | component_del(&pdev->dev, &dw_hdmi_rockchip_ops); | ||
| 322 | |||
| 323 | return 0; | ||
| 324 | } | ||
| 325 | |||
| 326 | static struct platform_driver dw_hdmi_rockchip_pltfm_driver = { | ||
| 327 | .probe = dw_hdmi_rockchip_probe, | ||
| 328 | .remove = dw_hdmi_rockchip_remove, | ||
| 329 | .driver = { | ||
| 330 | .name = "dwhdmi-rockchip", | ||
| 331 | .of_match_table = dw_hdmi_rockchip_dt_ids, | ||
| 332 | }, | ||
| 333 | }; | ||
| 334 | |||
| 335 | module_platform_driver(dw_hdmi_rockchip_pltfm_driver); | ||
| 336 | |||
| 337 | MODULE_AUTHOR("Andy Yan <andy.yan@rock-chips.com>"); | ||
| 338 | MODULE_AUTHOR("Yakir Yang <ykk@rock-chips.com>"); | ||
| 339 | MODULE_DESCRIPTION("Rockchip Specific DW-HDMI Driver Extension"); | ||
| 340 | MODULE_LICENSE("GPL"); | ||
| 341 | MODULE_ALIAS("platform:dwhdmi-rockchip"); | ||
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index a798c7c71f91..21a481b224eb 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c | |||
| @@ -390,6 +390,7 @@ int rockchip_drm_encoder_get_mux_id(struct device_node *node, | |||
| 390 | 390 | ||
| 391 | return -EINVAL; | 391 | return -EINVAL; |
| 392 | } | 392 | } |
| 393 | EXPORT_SYMBOL_GPL(rockchip_drm_encoder_get_mux_id); | ||
| 393 | 394 | ||
| 394 | static int compare_of(struct device *dev, void *data) | 395 | static int compare_of(struct device *dev, void *data) |
| 395 | { | 396 | { |
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index e7ca25b3fb38..9a5c571b95fc 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c | |||
| @@ -735,6 +735,7 @@ int rockchip_drm_crtc_mode_config(struct drm_crtc *crtc, | |||
| 735 | 735 | ||
| 736 | return 0; | 736 | return 0; |
| 737 | } | 737 | } |
| 738 | EXPORT_SYMBOL_GPL(rockchip_drm_crtc_mode_config); | ||
| 738 | 739 | ||
| 739 | static int vop_crtc_enable_vblank(struct drm_crtc *crtc) | 740 | static int vop_crtc_enable_vblank(struct drm_crtc *crtc) |
| 740 | { | 741 | { |
