diff options
author | Dave Airlie <airlied@redhat.com> | 2014-06-04 13:41:11 +1000 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2014-06-04 13:41:11 +1000 |
commit | b33a51e457b7e01e3e25eaa7c99aec32e65c00de (patch) | |
tree | 18db4abbdb05bd0cf97d320ab41e85af0eb2fe89 | |
parent | 1c404d88b26170b82aa274e7a40c91aa33145942 (diff) | |
parent | df5225bc9a87f1589a17797ee8e193608e4f3a9e (diff) |
Merge branch 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos into drm-next
Summary:
- Resolve probe order and deferred probe issue with component framework
support.
- Resolve hdmi dt broken issue.
. HDMI DT support, which was broken since CCF (common clock framework)
support, and considring legacy dt binding.
- Consolidate HDMI part.
. APB based phy support for Exynos5420 and later, and fixups related
to power on/off sequence.
- Consolidate IPP part.
. Mostly bug fixups and code cleanups.
- Trivial fixups and code cleanups.
* 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos: (64 commits)
drm/exynos: consider deferred probe case
drm/exynos: remove unnecessary exynos_hdmi.h file
drm/exynos/fimd: allow multiplatform configuration
drm/exynos: add hdmiphy power on/off sequence
drm/exynos: ipp: remove description of non-existing field
drm/exynos: ipp: update comment for struct drm_ipp_buf_info
drm/exynos: ipp: rearrange c_node->event_lock using routine
drm/exynos: ipp: rearrange c_node->mem_lock using routines
drm/exynos: ipp: add ipp_remove_id()
drm/exynos: ipp: add cmd_lock for cmd_list
drm/exynos: ipp: rename cmd_lock to lock
drm/exynos: ipp: remove duplicated setting
drm/exynos: ipp: remove usless list_empty() functions
drm/exynos: Use PTR_ERR_OR_ZERO in exynos_dp_core.c
drm/exynos: remove hardware overlays disable from fimd probe
drm/exynos: Fix checkpatch warning in exynos_dp_reg.c
drm/exynos: add fimd dependency to fimd related encoders
drm/exynos: remove redundant mutex_unlock
drm/exynos/fimc: simplify and rename fimc_dst_get_buf_seq
drm/exynos/fimc: replace mutex by spinlock
...
30 files changed, 1807 insertions, 1419 deletions
diff --git a/Documentation/devicetree/bindings/video/exynos_dp.txt b/Documentation/devicetree/bindings/video/exynos_dp.txt index 57ccdde02c3..53dbccfa80c 100644 --- a/Documentation/devicetree/bindings/video/exynos_dp.txt +++ b/Documentation/devicetree/bindings/video/exynos_dp.txt @@ -62,6 +62,10 @@ Optional properties for dp-controller: -hsync-active-high: HSYNC polarity configuration. High if defined, Low if not defined + -samsung,hpd-gpio: + Hotplug detect GPIO. + Indicates which GPIO should be used for hotplug + detection Example: diff --git a/Documentation/devicetree/bindings/video/exynos_hdmi.txt b/Documentation/devicetree/bindings/video/exynos_hdmi.txt index f9187a25925..1fd8cf9cbfa 100644 --- a/Documentation/devicetree/bindings/video/exynos_hdmi.txt +++ b/Documentation/devicetree/bindings/video/exynos_hdmi.txt @@ -5,6 +5,7 @@ Required properties: 1) "samsung,exynos5-hdmi" <DEPRECATED> 2) "samsung,exynos4210-hdmi" 3) "samsung,exynos4212-hdmi" + 4) "samsung,exynos5420-hdmi" - reg: physical base address of the hdmi and length of memory mapped region. - interrupts: interrupt number to the cpu. @@ -27,6 +28,7 @@ Required properties: "hdmi", "sclk_hdmi", "sclk_pixel", "sclk_hdmiphy" and "mout_hdmi". - ddc: phandle to the hdmi ddc node - phy: phandle to the hdmi phy node +- samsung,syscon-phandle: phandle for system controller node for PMU. Example: @@ -37,4 +39,5 @@ Example: hpd-gpio = <&gpx3 7 1>; ddc = <&hdmi_ddc_node>; phy = <&hdmi_phy_node>; + samsung,syscon-phandle = <&pmu_system_controller>; }; diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index d1cc2f613a7..f5120046ff8 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -83,6 +83,8 @@ config DRM_KMS_CMA_HELPER source "drivers/gpu/drm/i2c/Kconfig" +source "drivers/gpu/drm/bridge/Kconfig" + config DRM_TDFX tristate "3dfx Banshee/Voodoo3+" depends on DRM && PCI @@ -199,5 +201,3 @@ source "drivers/gpu/drm/msm/Kconfig" source "drivers/gpu/drm/tegra/Kconfig" source "drivers/gpu/drm/panel/Kconfig" - -source "drivers/gpu/drm/bridge/Kconfig" diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig index 5bf5bca94f5..178d2a9672a 100644 --- a/drivers/gpu/drm/exynos/Kconfig +++ b/drivers/gpu/drm/exynos/Kconfig @@ -26,14 +26,14 @@ config DRM_EXYNOS_DMABUF config DRM_EXYNOS_FIMD bool "Exynos DRM FIMD" - depends on DRM_EXYNOS && !FB_S3C && !ARCH_MULTIPLATFORM + depends on DRM_EXYNOS && !FB_S3C select FB_MODE_HELPERS help Choose this option if you want to use Exynos FIMD for DRM. config DRM_EXYNOS_DPI bool "EXYNOS DRM parallel output support" - depends on DRM_EXYNOS + depends on DRM_EXYNOS_FIMD select DRM_PANEL default n help @@ -41,7 +41,7 @@ config DRM_EXYNOS_DPI config DRM_EXYNOS_DSI bool "EXYNOS DRM MIPI-DSI driver support" - depends on DRM_EXYNOS + depends on DRM_EXYNOS_FIMD select DRM_MIPI_DSI select DRM_PANEL default n @@ -50,7 +50,7 @@ config DRM_EXYNOS_DSI config DRM_EXYNOS_DP bool "EXYNOS DRM DP driver support" - depends on DRM_EXYNOS && ARCH_EXYNOS + depends on DRM_EXYNOS_FIMD && ARCH_EXYNOS && (DRM_PTN3460=n || DRM_PTN3460=y || DRM_PTN3460=DRM_EXYNOS) default DRM_EXYNOS help This enables support for DP device. diff --git a/drivers/gpu/drm/exynos/exynos_ddc.c b/drivers/gpu/drm/exynos/exynos_ddc.c deleted file mode 100644 index 6a8c84e7c83..00000000000 --- a/drivers/gpu/drm/exynos/exynos_ddc.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2011 Samsung Electronics Co.Ltd - * Authors: - * Seung-Woo Kim <sw0312.kim@samsung.com> - * Inki Dae <inki.dae@samsung.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ - -#include <drm/drmP.h> - -#include <linux/kernel.h> -#include <linux/i2c.h> -#include <linux/of.h> - -#include "exynos_drm_drv.h" -#include "exynos_hdmi.h" - -static int s5p_ddc_probe(struct i2c_client *client, - const struct i2c_device_id *dev_id) -{ - hdmi_attach_ddc_client(client); - - dev_info(&client->adapter->dev, - "attached %s into i2c adapter successfully\n", - client->name); - - return 0; -} - -static int s5p_ddc_remove(struct i2c_client *client) -{ - dev_info(&client->adapter->dev, - "detached %s from i2c adapter successfully\n", - client->name); - - return 0; -} - -static struct of_device_id hdmiddc_match_types[] = { - { - .compatible = "samsung,exynos5-hdmiddc", - }, { - .compatible = "samsung,exynos4210-hdmiddc", - }, { - /* end node */ - } -}; - -struct i2c_driver ddc_driver = { - .driver = { - .name = "exynos-hdmiddc", - .owner = THIS_MODULE, - .of_match_table = hdmiddc_match_types, - }, - .probe = s5p_ddc_probe, - .remove = s5p_ddc_remove, - .command = NULL, -}; diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c index bb74472b4e4..5e05dbc6008 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_core.c +++ b/drivers/gpu/drm/exynos/exynos_dp_core.c @@ -18,6 +18,9 @@ #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/of.h> +#include <linux/of_gpio.h> +#include <linux/gpio.h> +#include <linux/component.h> #include <linux/phy/phy.h> #include <video/of_display_timing.h> #include <video/of_videomode.h> @@ -141,15 +144,15 @@ static int exynos_dp_read_edid(struct exynos_dp_device *dp) return -EIO; } - exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_TEST_REQUEST, + exynos_dp_read_byte_from_dpcd(dp, DP_TEST_REQUEST, &test_vector); - if (test_vector & DPCD_TEST_EDID_READ) { + if (test_vector & DP_TEST_LINK_EDID_READ) { exynos_dp_write_byte_to_dpcd(dp, - DPCD_ADDR_TEST_EDID_CHECKSUM, + DP_TEST_EDID_CHECKSUM, edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]); exynos_dp_write_byte_to_dpcd(dp, - DPCD_ADDR_TEST_RESPONSE, - DPCD_TEST_EDID_CHECKSUM_WRITE); + DP_TEST_RESPONSE, + DP_TEST_EDID_CHECKSUM_WRITE); } } else { dev_info(dp->dev, "EDID data does not include any extensions.\n"); @@ -171,15 +174,15 @@ static int exynos_dp_read_edid(struct exynos_dp_device *dp) } exynos_dp_read_byte_from_dpcd(dp, - DPCD_ADDR_TEST_REQUEST, + DP_TEST_REQUEST, &test_vector); - if (test_vector & DPCD_TEST_EDID_READ) { + if (test_vector & DP_TEST_LINK_EDID_READ) { exynos_dp_write_byte_to_dpcd(dp, - DPCD_ADDR_TEST_EDID_CHECKSUM, + DP_TEST_EDID_CHECKSUM, edid[EDID_CHECKSUM]); exynos_dp_write_byte_to_dpcd(dp, - DPCD_ADDR_TEST_RESPONSE, - DPCD_TEST_EDID_CHECKSUM_WRITE); + DP_TEST_RESPONSE, + DP_TEST_EDID_CHECKSUM_WRITE); } } @@ -193,8 +196,8 @@ static int exynos_dp_handle_edid(struct exynos_dp_device *dp) int i; int retval; - /* Read DPCD DPCD_ADDR_DPCD_REV~RECEIVE_PORT1_CAP_1 */ - retval = exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_DPCD_REV, + /* Read DPCD DP_DPCD_REV~RECEIVE_PORT1_CAP_1 */ + retval = exynos_dp_read_bytes_from_dpcd(dp, DP_DPCD_REV, 12, buf); if (retval) return retval; @@ -214,14 +217,14 @@ static void exynos_dp_enable_rx_to_enhanced_mode(struct exynos_dp_device *dp, { u8 data; - exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET, &data); + exynos_dp_read_byte_from_dpcd(dp, DP_LANE_COUNT_SET, &data); if (enable) - exynos_dp_write_byte_to_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET, - DPCD_ENHANCED_FRAME_EN | + exynos_dp_write_byte_to_dpcd(dp, DP_LANE_COUNT_SET, + DP_LANE_COUNT_ENHANCED_FRAME_EN | DPCD_LANE_COUNT_SET(data)); else - exynos_dp_write_byte_to_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET, + exynos_dp_write_byte_to_dpcd(dp, DP_LANE_COUNT_SET, DPCD_LANE_COUNT_SET(data)); } @@ -230,7 +233,7 @@ static int exynos_dp_is_enhanced_mode_available(struct exynos_dp_device *dp) u8 data; int retval; - exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LANE_COUNT, &data); + exynos_dp_read_byte_from_dpcd(dp, DP_MAX_LANE_COUNT, &data); retval = DPCD_ENHANCED_FRAME_CAP(data); return retval; @@ -250,8 +253,8 @@ static void exynos_dp_training_pattern_dis(struct exynos_dp_device *dp) exynos_dp_set_training_pattern(dp, DP_NONE); exynos_dp_write_byte_to_dpcd(dp, - DPCD_ADDR_TRAINING_PATTERN_SET, - DPCD_TRAINING_PATTERN_DISABLED); + DP_TRAINING_PATTERN_SET, + DP_TRAINING_PATTERN_DISABLE); } static void exynos_dp_set_lane_lane_pre_emphasis(struct exynos_dp_device *dp, @@ -295,7 +298,7 @@ static int exynos_dp_link_start(struct exynos_dp_device *dp) /* Setup RX configuration */ buf[0] = dp->link_train.link_rate; buf[1] = dp->link_train.lane_count; - retval = exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_LINK_BW_SET, + retval = exynos_dp_write_bytes_to_dpcd(dp, DP_LINK_BW_SET, 2, buf); if (retval) return retval; @@ -322,16 +325,16 @@ static int exynos_dp_link_start(struct exynos_dp_device *dp) /* Set RX training pattern */ retval = exynos_dp_write_byte_to_dpcd(dp, - DPCD_ADDR_TRAINING_PATTERN_SET, - DPCD_SCRAMBLING_DISABLED | DPCD_TRAINING_PATTERN_1); + DP_TRAINING_PATTERN_SET, + DP_LINK_SCRAMBLING_DISABLE | DP_TRAINING_PATTERN_1); if (retval) return retval; for (lane = 0; lane < lane_count; lane++) - buf[lane] = DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0 | - DPCD_VOLTAGE_SWING_PATTERN1_LEVEL0; + buf[lane] = DP_TRAIN_PRE_EMPHASIS_0 | + DP_TRAIN_VOLTAGE_SWING_400; - retval = exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_TRAINING_LANE0_SET, + retval = exynos_dp_write_bytes_to_dpcd(dp, DP_TRAINING_LANE0_SET, lane_count, buf); return retval; @@ -352,7 +355,7 @@ static int exynos_dp_clock_recovery_ok(u8 link_status[2], int lane_count) for (lane = 0; lane < lane_count; lane++) { lane_status = exynos_dp_get_lane_status(link_status, lane); - if ((lane_status & DPCD_LANE_CR_DONE) == 0) + if ((lane_status & DP_LANE_CR_DONE) == 0) return -EINVAL; } return 0; @@ -364,13 +367,13 @@ static int exynos_dp_channel_eq_ok(u8 link_status[2], u8 link_align, int lane; u8 lane_status; - if ((link_align & DPCD_INTERLANE_ALIGN_DONE) == 0) + if ((link_align & DP_INTERLANE_ALIGN_DONE) == 0) return -EINVAL; for (lane = 0; lane < lane_count; lane++) { lane_status = exynos_dp_get_lane_status(link_status, lane); - lane_status &= DPCD_CHANNEL_EQ_BITS; - if (lane_status != DPCD_CHANNEL_EQ_BITS) + lane_status &= DP_CHANNEL_EQ_BITS; + if (lane_status != DP_CHANNEL_EQ_BITS) return -EINVAL; } @@ -468,9 +471,9 @@ static void exynos_dp_get_adjust_training_lane(struct exynos_dp_device *dp, DPCD_PRE_EMPHASIS_SET(pre_emphasis); if (voltage_swing == VOLTAGE_LEVEL_3) - training_lane |= DPCD_MAX_SWING_REACHED; + training_lane |= DP_TRAIN_MAX_SWING_REACHED; if (pre_emphasis == PRE_EMPHASIS_LEVEL_3) - training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED; + training_lane |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED; dp->link_train.training_lane[lane] = training_lane; } @@ -487,12 +490,12 @@ static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp) lane_count = dp->link_train.lane_count; retval = exynos_dp_read_bytes_from_dpcd(dp, - DPCD_ADDR_LANE0_1_STATUS, 2, link_status); + DP_LANE0_1_STATUS, 2, link_status); if (retval) return retval; retval = exynos_dp_read_bytes_from_dpcd(dp, - DPCD_ADDR_ADJUST_REQUEST_LANE0_1, 2, adjust_request); + DP_ADJUST_REQUEST_LANE0_1, 2, adjust_request); if (retval) return retval; @@ -501,9 +504,9 @@ static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp) exynos_dp_set_training_pattern(dp, TRAINING_PTN2); retval = exynos_dp_write_byte_to_dpcd(dp, - DPCD_ADDR_TRAINING_PATTERN_SET, - DPCD_SCRAMBLING_DISABLED | - DPCD_TRAINING_PATTERN_2); + DP_TRAINING_PATTERN_SET, + DP_LINK_SCRAMBLING_DISABLE | + DP_TRAINING_PATTERN_2); if (retval) return retval; @@ -543,7 +546,7 @@ static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp) dp->link_train.training_lane[lane], lane); retval = exynos_dp_write_bytes_to_dpcd(dp, - DPCD_ADDR_TRAINING_LANE0_SET, lane_count, + DP_TRAINING_LANE0_SET, lane_count, dp->link_train.training_lane); if (retval) return retval; @@ -562,7 +565,7 @@ static int exynos_dp_process_equalizer_training(struct exynos_dp_device *dp) lane_count = dp->link_train.lane_count; retval = exynos_dp_read_bytes_from_dpcd(dp, - DPCD_ADDR_LANE0_1_STATUS, 2, link_status); + DP_LANE0_1_STATUS, 2, link_status); if (retval) return retval; @@ -572,12 +575,12 @@ static int exynos_dp_process_equalizer_training(struct exynos_dp_device *dp) } retval = exynos_dp_read_bytes_from_dpcd(dp, - DPCD_ADDR_ADJUST_REQUEST_LANE0_1, 2, adjust_request); + DP_ADJUST_REQUEST_LANE0_1, 2, adjust_request); if (retval) return retval; retval = exynos_dp_read_byte_from_dpcd(dp, - DPCD_ADDR_LANE_ALIGN_STATUS_UPDATED, &link_align); + DP_LANE_ALIGN_STATUS_UPDATED, &link_align); if (retval) return retval; @@ -619,7 +622,7 @@ static int exynos_dp_process_equalizer_training(struct exynos_dp_device *dp) exynos_dp_set_lane_link_training(dp, dp->link_train.training_lane[lane], lane); - retval = exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_TRAINING_LANE0_SET, + retval = exynos_dp_write_bytes_to_dpcd(dp, DP_TRAINING_LANE0_SET, lane_count, dp->link_train.training_lane); return retval; @@ -634,7 +637,7 @@ static void exynos_dp_get_max_rx_bandwidth(struct exynos_dp_device *dp, * For DP rev.1.1, Maximum link rate of Main Link lanes * 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps */ - exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LINK_RATE, &data); + exynos_dp_read_byte_from_dpcd(dp, DP_MAX_LINK_RATE, &data); *bandwidth = data; } @@ -647,7 +650,7 @@ static void exynos_dp_get_max_rx_lane_count(struct exynos_dp_device *dp, * For DP rev.1.1, Maximum number of Main Link lanes * 0x01 = 1 lane, 0x02 = 2 lanes, 0x04 = 4 lanes */ - exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LANE_COUNT, &data); + exynos_dp_read_byte_from_dpcd(dp, DP_MAX_LANE_COUNT, &data); *lane_count = DPCD_MAX_LANE_COUNT(data); } @@ -819,20 +822,20 @@ static void exynos_dp_enable_scramble(struct exynos_dp_device *dp, bool enable) exynos_dp_enable_scrambling(dp); exynos_dp_read_byte_from_dpcd(dp, - DPCD_ADDR_TRAINING_PATTERN_SET, + DP_TRAINING_PATTERN_SET, &data); exynos_dp_write_byte_to_dpcd(dp, - DPCD_ADDR_TRAINING_PATTERN_SET, - (u8)(data & ~DPCD_SCRAMBLING_DISABLED)); + DP_TRAINING_PATTERN_SET, + (u8)(data & ~DP_LINK_SCRAMBLING_DISABLE)); } else { exynos_dp_disable_scrambling(dp); exynos_dp_read_byte_from_dpcd(dp, - DPCD_ADDR_TRAINING_PATTERN_SET, + DP_TRAINING_PATTERN_SET, &data); exynos_dp_write_byte_to_dpcd(dp, - DPCD_ADDR_TRAINING_PATTERN_SET, - (u8)(data | DPCD_SCRAMBLING_DISABLED)); + DP_TRAINING_PATTERN_SET, + (u8)(data | DP_LINK_SCRAMBLING_DISABLE)); } } @@ -962,16 +965,6 @@ static struct drm_connector_helper_funcs exynos_dp_connector_helper_funcs = { .best_encoder = exynos_dp_best_encoder, }; -static int exynos_dp_initialize(struct exynos_drm_display *display, - struct drm_device *drm_dev) -{ - struct exynos_dp_device *dp = display->ctx; - - dp->drm_dev = drm_dev; - - return 0; -} - static bool find_bridge(const char *compat, struct bridge_init *bridge) { bridge->client = NULL; @@ -1099,7 +1092,6 @@ static void exynos_dp_dpms(struct exynos_drm_display *display, int mode) } static struct exynos_drm_display_ops exynos_dp_display_ops = { - .initialize = exynos_dp_initialize, .create_connector = exynos_dp_create_connector, .dpms = exynos_dp_dpms, }; @@ -1116,10 +1108,8 @@ static struct video_info *exynos_dp_dt_parse_pdata(struct device *dev) dp_video_config = devm_kzalloc(dev, sizeof(*dp_video_config), GFP_KERNEL); - if (!dp_video_config) { - dev_err(dev, "memory allocation for video config failed\n"); + if (!dp_video_config) return ERR_PTR(-ENOMEM); - } dp_video_config->h_sync_polarity = of_property_read_bool(dp_node, "hsync-active-high"); @@ -1178,10 +1168,7 @@ static int exynos_dp_dt_parse_phydata(struct exynos_dp_device *dp) dp_phy_node = of_find_node_by_name(dp_phy_node, "dptx-phy"); if (!dp_phy_node) { dp->phy = devm_phy_get(dp->dev, "dp"); - if (IS_ERR(dp->phy)) - return PTR_ERR(dp->phy); - else - return 0; + return PTR_ERR_OR_ZERO(dp->phy); } if (of_property_read_u32(dp_phy_node, "reg", &phy_base)) { @@ -1223,19 +1210,20 @@ static int exynos_dp_dt_parse_panel(struct exynos_dp_device *dp) return 0; } -static int exynos_dp_probe(struct platform_device *pdev) +static int exynos_dp_bind(struct device *dev, struct device *master, void *data) { + struct platform_device *pdev = to_platform_device(dev); + struct drm_device *drm_dev = data; struct resource *res; struct exynos_dp_device *dp; + unsigned int irq_flags; int ret = 0; dp = devm_kzalloc(&pdev->dev, sizeof(struct exynos_dp_device), GFP_KERNEL); - if (!dp) { - dev_err(&pdev->dev, "no memory for device data\n"); + if (!dp) return -ENOMEM; - } dp->dev = &pdev->dev; dp->dpms_mode = DRM_MODE_DPMS_OFF; @@ -1266,7 +1254,30 @@ static int exynos_dp_probe(struct platform_device *pdev) if (IS_ERR(dp->reg_base)) return PTR_ERR(dp->reg_base); - dp->irq = platform_get_irq(pdev, 0); + dp->hpd_gpio = of_get_named_gpio(dev->of_node, "samsung,hpd-gpio", 0); + + if (gpio_is_valid(dp->hpd_gpio)) { + /* + * Set up the hotplug GPIO from the device tree as an interrupt. + * Simply specifying a different interrupt in the device tree + * doesn't work since we handle hotplug rather differently when + * using a GPIO. We also need the actual GPIO specifier so + * that we can get the current state of the GPIO. + */ + ret = devm_gpio_request_one(&pdev->dev, dp->hpd_gpio, GPIOF_IN, + "hpd_gpio"); + if (ret) { + dev_err(&pdev->dev, "failed to get hpd gpio\n"); + return ret; + } + dp->irq = gpio_to_irq(dp->hpd_gpio); + irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING; + } else { + dp->hpd_gpio = -ENODEV; + dp->irq = platform_get_irq(pdev, 0); + irq_flags = 0; + } + if (dp->irq == -ENXIO) { dev_err(&pdev->dev, "failed to get irq\n"); return -ENODEV; @@ -1278,28 +1289,61 @@ static int exynos_dp_probe(struct platform_device *pdev) exynos_dp_init_dp(dp); - ret = devm_request_irq(&pdev->dev, dp->irq, exynos_dp_irq_handler, 0, - "exynos-dp", dp); + ret = devm_request_irq(&pdev->dev, dp->irq, exynos_dp_irq_handler, + irq_flags, "exynos-dp", dp); if (ret) { dev_err(&pdev->dev, "failed to request irq\n"); return ret; } disable_irq(dp->irq); + dp->drm_dev = drm_dev; exynos_dp_display.ctx = dp; platform_set_drvdata(pdev, &exynos_dp_display); - exynos_drm_display_register(&exynos_dp_display); - return 0; + return exynos_drm_create_enc_conn(drm_dev, &exynos_dp_display); } -static int exynos_dp_remove(struct platform_device *pdev) +static void exynos_dp_unbind(struct device *dev, struct device *master, + void *data) { - struct exynos_drm_display *display = platform_get_drvdata(pdev); + struct exynos_drm_display *display = dev_get_drvdata(dev); + struct exynos_dp_device *dp = display->ctx; + struct drm_encoder *encoder = dp->encoder; exynos_dp_dpms(display, DRM_MODE_DPMS_OFF); - exynos_drm_display_unregister(&exynos_dp_display); + + encoder->funcs->destroy(encoder); + drm_connector_cleanup(&dp->connector); +} + +static const struct component_ops exynos_dp_ops = { + .bind = exynos_dp_bind, + .unbind = exynos_dp_unbind, +}; + +static int exynos_dp_probe(struct platform_device *pdev) +{ + int ret; + + ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR, + exynos_dp_display.type); + if (ret) + return ret; + + ret = component_add(&pdev->dev, &exynos_dp_ops); + if (ret) + exynos_drm_component_del(&pdev->dev, + EXYNOS_DEVICE_TYPE_CONNECTOR); + + return ret; +} + +static int exynos_dp_remove(struct platform_device *pdev) +{ + component_del(&pdev->dev, &exynos_dp_ops); + exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR); return 0; } diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.h b/drivers/gpu/drm/exynos/exynos_dp_core.h index d6a900d4ee4..02cc4f9ab90 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_core.h +++ b/drivers/gpu/drm/exynos/exynos_dp_core.h @@ -14,6 +14,7 @@ #define _EXYNOS_DP_CORE_H #include <drm/drm_crtc.h> +#include <drm/drm_dp_helper.h> #include <drm/exynos_drm.h> #define DP_TIMEOUT_LOOP_COUNT 100 @@ -159,6 +160,7 @@ struct exynos_dp_device { struct work_struct hotplug_work; struct phy *phy; int dpms_mode; + int hpd_gpio; struct exynos_drm_panel_info panel; }; @@ -261,69 +263,17 @@ void exynos_dp_disable_scrambling(struct exynos_dp_device *dp); #define EDID_EXTENSION_FLAG 0x7e #define EDID_CHECKSUM 0x7f -/* Definition for DPCD Register */ -#define DPCD_ADDR_DPCD_REV 0x0000 -#define DPCD_ADDR_MAX_LINK_RATE 0x0001 -#define DPCD_ADDR_MAX_LANE_COUNT 0x0002 -#define DPCD_ADDR_LINK_BW_SET 0x0100 -#define DPCD_ADDR_LANE_COUNT_SET 0x0101 -#define DPCD_ADDR_TRAINING_PATTERN_SET 0x0102 -#define DPCD_ADDR_TRAINING_LANE0_SET 0x0103 -#define DPCD_ADDR_LANE0_1_STATUS 0x0202 -#define DPCD_ADDR_LANE_ALIGN_STATUS_UPDATED 0x0204 -#define DPCD_ADDR_ADJUST_REQUEST_LANE0_1 0x0206 -#define DPCD_ADDR_ADJUST_REQUEST_LANE2_3 0x0207 -#define DPCD_ADDR_TEST_REQUEST 0x0218 -#define DPCD_ADDR_TEST_RESPONSE 0x0260 -#define DPCD_ADDR_TEST_EDID_CHECKSUM 0x0261 -#define DPCD_ADDR_SINK_POWER_STATE 0x0600 - -/* DPCD_ADDR_MAX_LANE_COUNT */ +/* DP_MAX_LANE_COUNT */ #define DPCD_ENHANCED_FRAME_CAP(x) (((x) >> 7) & 0x1) #define DPCD_MAX_LANE_COUNT(x) ((x) & 0x1f) -/* DPCD_ADDR_LANE_COUNT_SET */ -#define DPCD_ENHANCED_FRAME_EN (0x1 << 7) +/* DP_LANE_COUNT_SET */ #define DPCD_LANE_COUNT_SET(x) ((x) & 0x1f) -/* DPCD_ADDR_TRAINING_PATTERN_SET */ -#define DPCD_SCRAMBLING_DISABLED (0x1 << 5) -#define DPCD_SCRAMBLING_ENABLED (0x0 << 5) -#define DPCD_TRAINING_PATTERN_2 (0x2 << 0) -#define DPCD_TRAINING_PATTERN_1 (0x1 << 0) -#define DPCD_TRAINING_PATTERN_DISABLED (0x0 << 0) - -/* DPCD_ADDR_TRAINING_LANE0_SET */ -#define DPCD_MAX_PRE_EMPHASIS_REACHED (0x1 << 5) +/* DP_TRAINING_LANE0_SET */ #define DPCD_PRE_EMPHASIS_SET(x) (((x) & 0x3) << 3) #define DPCD_PRE_EMPHASIS_GET(x) (((x) >> 3) & 0x3) -#define DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0 (0x0 << 3) -#define DPCD_MAX_SWING_REACHED (0x1 << 2) #define DPCD_VOLTAGE_SWING_SET(x) (((x) & 0x3) << 0) #define DPCD_VOLTAGE_SWING_GET(x) (((x) >> 0) & 0x3) -#define DPCD_VOLTAGE_SWING_PATTERN1_LEVEL0 (0x0 << 0) - -/* DPCD_ADDR_LANE0_1_STATUS */ -#define DPCD_LANE_SYMBOL_LOCKED (0x1 << 2) -#define DPCD_LANE_CHANNEL_EQ_DONE (0x1 << 1) -#define DPCD_LANE_CR_DONE (0x1 << 0) -#define DPCD_CHANNEL_EQ_BITS (DPCD_LANE_CR_DONE| \ - DPCD_LANE_CHANNEL_EQ_DONE|\ - DPCD_LANE_SYMBOL_LOCKED) - -/* DPCD_ADDR_LANE_ALIGN__STATUS_UPDATED */ -#define DPCD_LINK_STATUS_UPDATED (0x1 << 7) -#define DPCD_DOWNSTREAM_PORT_STATUS_CHANGED (0x1 << 6) -#define DPCD_INTERLANE_ALIGN_DONE (0x1 << 0) - -/* DPCD_ADDR_TEST_REQUEST */ -#define DPCD_TEST_EDID_READ (0x1 << 2) - -/* DPCD_ADDR_TEST_RESPONSE */ -#define DPCD_TEST_EDID_CHECKSUM_WRITE (0x1 << 2) - -/* DPCD_ADDR_SINK_POWER_STATE */ -#define DPCD_SET_POWER_STATE_D0 (0x1 << 0) -#define DPCD_SET_POWER_STATE_D4 (0x2 << 0) #endif /* _EXYNOS_DP_CORE_H */ diff --git a/drivers/gpu/drm/exynos/exynos_dp_reg.c b/drivers/gpu/drm/exynos/exynos_dp_reg.c index b70da5052ff..c1f87a2a928 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_reg.c +++ b/drivers/gpu/drm/exynos/exynos_dp_reg.c @@ -13,6 +13,7 @@ #include <linux/device.h> #include <linux/io.h> #include <linux/delay.h> +#include <linux/gpio.h> #include "exynos_dp_core.h" #include "exynos_dp_reg.h" @@ -326,6 +327,9 @@ void exynos_dp_clear_hotplug_interrupts(struct exynos_dp_device *dp) { u32 reg; + if (gpio_is_valid(dp->hpd_gpio)) + return; + reg = HOTPLUG_CHG | HPD_LOST | PLUG; writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_4); @@ -337,6 +341,9 @@ void exynos_dp_init_hpd(struct exynos_dp_device *dp) { u32 reg; + if (gpio_is_valid(dp->hpd_gpio)) + return; + exynos_dp_clear_hotplug_interrupts(dp); reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3); @@ -348,19 +355,27 @@ enum dp_irq_type exynos_dp_get_irq_type(struct exynos_dp_device *dp) { u32 reg; - /* Parse hotplug interrupt status register */ - reg = readl(dp->reg_base + EXYNOS_DP_COMMON_INT_STA_4); + if (gpio_is_valid(dp->hpd_gpio)) { + reg = gpio_get_value(dp->hpd_gpio); + if (reg) + return DP_IRQ_TYPE_HP_CABLE_IN; + else + return DP_IRQ_TYPE_HP_CABLE_OUT; + } else { + /* Parse hotplug interrupt status register */ + reg = readl(dp->reg_base + EXYNOS_DP_COMMON_INT_STA_4); - if (reg & PLUG) - return DP_IRQ_TYPE_HP_CABLE_IN; + if (reg & PLUG) + return DP_IRQ_TYPE_HP_CABLE_IN; - if (reg & HPD_LOST) - return DP_IRQ_TYPE_HP_CABLE_OUT; + if (reg & HPD_LOST) + return DP_IRQ_TYPE_HP_CABLE_OUT; - if (reg & HOTPLUG_CHG) - return DP_IRQ_TYPE_HP_CHANGE; + if (reg & HOTPLUG_CHG) + return DP_IRQ_TYPE_HP_CHANGE; - return DP_IRQ_TYPE_UNKNOWN; + return DP_IRQ_TYPE_UNKNOWN; + } } void exynos_dp_reset_aux(struct exynos_dp_device *dp) @@ -386,7 +401,7 @@ void exynos_dp_init_aux(struct exynos_dp_device *dp) /* Disable AUX transaction H/W retry */ reg = AUX_BIT_PERIOD_EXPECTED_DELAY(3) | AUX_HW_RETRY_COUNT_SEL(0)| AUX_HW_RETRY_INTERVAL_600_MICROSECONDS; - writel(reg, dp->reg_base + EXYNO |