Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 473af20f authored by Tomi Valkeinen's avatar Tomi Valkeinen
Browse files

Merge branch 'exynos-dp-next' of git://github.com/jingoo/linux into for-linus

Exynos DP changes for the 3.8 merge window.

- Device Tree support for Samsung Exynos DP
- SW Link training is cleaned up.
- HPD interrupt is supported.

* 'exynos-dp-next' of git://github.com/jingoo/linux:
  video: exynos_dp: remove redundant parameters
  video: exynos_dp: Fix incorrect setting for INT_CTL
  video: exynos_dp: Reset and initialize DP before requesting irq
  video: exynos_dp: Enable hotplug interrupts
  video: exynos_dp: Move hotplug into a workqueue
  video: exynos_dp: Remove sink control to D0
  video: exynos_dp: Fix bug when checking dp->irq
  video: exynos_dp: Improve EDID error handling
  video: exynos_dp: Get pll lock before pattern set
  video: exynos_dp: Clean up SW link training
  video: exynos_dp: Check DPCD return codes
  video: exynos_dp: device tree documentation
  video: exynos_dp: Add device tree support to DP driver
parents fa1f9497 3fcb6eb4
Loading
Loading
Loading
Loading
+80 −0
Original line number Diff line number Diff line
The Exynos display port interface should be configured based on
the type of panel connected to it.

We use two nodes:
	-dp-controller node
	-dptx-phy node(defined inside dp-controller node)

For the DP-PHY initialization, we use the dptx-phy node.
Required properties for dptx-phy:
	-reg:
		Base address of DP PHY register.
	-samsung,enable-mask:
		The bit-mask used to enable/disable DP PHY.

For the Panel initialization, we read data from dp-controller node.
Required properties for dp-controller:
	-compatible:
		should be "samsung,exynos5-dp".
	-reg:
		physical base address of the controller and length
		of memory mapped region.
	-interrupts:
		interrupt combiner values.
	-interrupt-parent:
		phandle to Interrupt combiner node.
	-samsung,color-space:
		input video data format.
			COLOR_RGB = 0, COLOR_YCBCR422 = 1, COLOR_YCBCR444 = 2
	-samsung,dynamic-range:
		dynamic range for input video data.
			VESA = 0, CEA = 1
	-samsung,ycbcr-coeff:
		YCbCr co-efficients for input video.
			COLOR_YCBCR601 = 0, COLOR_YCBCR709 = 1
	-samsung,color-depth:
		number of bits per colour component.
			COLOR_6 = 0, COLOR_8 = 1, COLOR_10 = 2, COLOR_12 = 3
	-samsung,link-rate:
		link rate supported by the panel.
			LINK_RATE_1_62GBPS = 0x6, LINK_RATE_2_70GBPS = 0x0A
	-samsung,lane-count:
		number of lanes supported by the panel.
			LANE_COUNT1 = 1, LANE_COUNT2 = 2, LANE_COUNT4 = 4

Optional properties for dp-controller:
	-interlaced:
		interlace scan mode.
			Progressive if defined, Interlaced if not defined
	-vsync-active-high:
		VSYNC polarity configuration.
			High if defined, Low if not defined
	-hsync-active-high:
		HSYNC polarity configuration.
			High if defined, Low if not defined

Example:

SOC specific portion:
	dp-controller {
		compatible = "samsung,exynos5-dp";
		reg = <0x145b0000 0x10000>;
		interrupts = <10 3>;
		interrupt-parent = <&combiner>;

		dptx-phy {
			reg = <0x10040720>;
			samsung,enable-mask = <1>;
		};

	};

Board Specific portion:
	dp-controller {
		samsung,color-space = <0>;
		samsung,dynamic-range = <0>;
		samsung,ycbcr-coeff = <0>;
		samsung,color-depth = <1>;
		samsung,link-rate = <0x0a>;
		samsung,lane-count = <4>;
	};
+439 −258

File changed.

Preview size limit exceeded, changes collapsed.

+14 −7
Original line number Diff line number Diff line
@@ -13,6 +13,13 @@
#ifndef _EXYNOS_DP_CORE_H
#define _EXYNOS_DP_CORE_H

enum dp_irq_type {
	DP_IRQ_TYPE_HP_CABLE_IN,
	DP_IRQ_TYPE_HP_CABLE_OUT,
	DP_IRQ_TYPE_HP_CHANGE,
	DP_IRQ_TYPE_UNKNOWN,
};

struct link_train {
	int eq_loop;
	int cr_loop[4];
@@ -29,9 +36,12 @@ struct exynos_dp_device {
	struct clk		*clock;
	unsigned int		irq;
	void __iomem		*reg_base;
	void __iomem		*phy_addr;
	unsigned int		enable_mask;

	struct video_info	*video_info;
	struct link_train	link_train;
	struct work_struct	hotplug_work;
};

/* exynos_dp_reg.c */
@@ -50,6 +60,8 @@ void exynos_dp_set_analog_power_down(struct exynos_dp_device *dp,
				bool enable);
void exynos_dp_init_analog_func(struct exynos_dp_device *dp);
void exynos_dp_init_hpd(struct exynos_dp_device *dp);
enum dp_irq_type exynos_dp_get_irq_type(struct exynos_dp_device *dp);
void exynos_dp_clear_hotplug_interrupts(struct exynos_dp_device *dp);
void exynos_dp_reset_aux(struct exynos_dp_device *dp);
void exynos_dp_init_aux(struct exynos_dp_device *dp);
int exynos_dp_get_plug_in_status(struct exynos_dp_device *dp);
@@ -107,11 +119,7 @@ u32 exynos_dp_get_lane3_link_training(struct exynos_dp_device *dp);
void exynos_dp_reset_macro(struct exynos_dp_device *dp);
void exynos_dp_init_video(struct exynos_dp_device *dp);

void exynos_dp_set_video_color_format(struct exynos_dp_device *dp,
				u32 color_depth,
				u32 color_space,
				u32 dynamic_range,
				u32 ycbcr_coeff);
void exynos_dp_set_video_color_format(struct exynos_dp_device *dp);
int exynos_dp_is_slave_video_stream_clock_on(struct exynos_dp_device *dp);
void exynos_dp_set_video_cr_mn(struct exynos_dp_device *dp,
			enum clock_recovery_m_value_type type,
@@ -121,8 +129,7 @@ void exynos_dp_set_video_timing_mode(struct exynos_dp_device *dp, u32 type);
void exynos_dp_enable_video_master(struct exynos_dp_device *dp, bool enable);
void exynos_dp_start_video(struct exynos_dp_device *dp);
int exynos_dp_is_video_stream_on(struct exynos_dp_device *dp);
void exynos_dp_config_video_slave_mode(struct exynos_dp_device *dp,
			struct video_info *video_info);
void exynos_dp_config_video_slave_mode(struct exynos_dp_device *dp);
void exynos_dp_enable_scrambling(struct exynos_dp_device *dp);
void exynos_dp_disable_scrambling(struct exynos_dp_device *dp);

+48 −29
Original line number Diff line number Diff line
@@ -19,11 +19,11 @@
#include "exynos_dp_core.h"
#include "exynos_dp_reg.h"

#define COMMON_INT_MASK_1 (0)
#define COMMON_INT_MASK_2 (0)
#define COMMON_INT_MASK_3 (0)
#define COMMON_INT_MASK_4 (0)
#define INT_STA_MASK (0)
#define COMMON_INT_MASK_1	0
#define COMMON_INT_MASK_2	0
#define COMMON_INT_MASK_3	0
#define COMMON_INT_MASK_4	(HOTPLUG_CHG | HPD_LOST | PLUG)
#define INT_STA_MASK		INT_HPD

void exynos_dp_enable_video_mute(struct exynos_dp_device *dp, bool enable)
{
@@ -88,7 +88,7 @@ void exynos_dp_init_analog_param(struct exynos_dp_device *dp)
void exynos_dp_init_interrupt(struct exynos_dp_device *dp)
{
	/* Set interrupt pin assertion polarity as high */
	writel(INT_POL, dp->reg_base + EXYNOS_DP_INT_CTL);
	writel(INT_POL1 | INT_POL0, dp->reg_base + EXYNOS_DP_INT_CTL);

	/* Clear pending regisers */
	writel(0xff, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_1);
@@ -324,7 +324,7 @@ void exynos_dp_init_analog_func(struct exynos_dp_device *dp)
	writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2);
}

void exynos_dp_init_hpd(struct exynos_dp_device *dp)
void exynos_dp_clear_hotplug_interrupts(struct exynos_dp_device *dp)
{
	u32 reg;

@@ -333,12 +333,38 @@ void exynos_dp_init_hpd(struct exynos_dp_device *dp)

	reg = INT_HPD;
	writel(reg, dp->reg_base + EXYNOS_DP_INT_STA);
}

void exynos_dp_init_hpd(struct exynos_dp_device *dp)
{
	u32 reg;

	exynos_dp_clear_hotplug_interrupts(dp);

	reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3);
	reg &= ~(F_HPD | HPD_CTRL);
	writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_3);
}

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 (reg & PLUG)
		return DP_IRQ_TYPE_HP_CABLE_IN;

	if (reg & HPD_LOST)
		return DP_IRQ_TYPE_HP_CABLE_OUT;

	if (reg & HOTPLUG_CHG)
		return DP_IRQ_TYPE_HP_CHANGE;

	return DP_IRQ_TYPE_UNKNOWN;
}

void exynos_dp_reset_aux(struct exynos_dp_device *dp)
{
	u32 reg;
@@ -491,7 +517,7 @@ int exynos_dp_read_byte_from_dpcd(struct exynos_dp_device *dp,
	int i;
	int retval;

	for (i = 0; i < 10; i++) {
	for (i = 0; i < 3; i++) {
		/* Clear AUX CH data buffer */
		reg = BUF_CLR;
		writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL);
@@ -552,7 +578,7 @@ int exynos_dp_write_bytes_to_dpcd(struct exynos_dp_device *dp,
		else
			cur_data_count = count - start_offset;

		for (i = 0; i < 10; i++) {
		for (i = 0; i < 3; i++) {
			/* Select DPCD device address */
			reg = AUX_ADDR_7_0(reg_addr + start_offset);
			writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0);
@@ -617,7 +643,7 @@ int exynos_dp_read_bytes_from_dpcd(struct exynos_dp_device *dp,
			cur_data_count = count - start_offset;

		/* AUX CH Request Transaction process */
		for (i = 0; i < 10; i++) {
		for (i = 0; i < 3; i++) {
			/* Select DPCD device address */
			reg = AUX_ADDR_7_0(reg_addr + start_offset);
			writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0);
@@ -700,17 +726,15 @@ int exynos_dp_read_byte_from_i2c(struct exynos_dp_device *dp,
	int i;
	int retval;

	for (i = 0; i < 10; i++) {
	for (i = 0; i < 3; i++) {
		/* Clear AUX CH data buffer */
		reg = BUF_CLR;
		writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL);

		/* Select EDID device */
		retval = exynos_dp_select_i2c_device(dp, device_addr, reg_addr);
		if (retval != 0) {
			dev_err(dp->dev, "Select EDID device fail!\n");
		if (retval != 0)
			continue;
		}

		/*
		 * Set I2C transaction and read data
@@ -750,7 +774,7 @@ int exynos_dp_read_bytes_from_i2c(struct exynos_dp_device *dp,
	int retval = 0;

	for (i = 0; i < count; i += 16) {
		for (j = 0; j < 100; j++) {
		for (j = 0; j < 3; j++) {
			/* Clear AUX CH data buffer */
			reg = BUF_CLR;
			writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL);
@@ -1034,24 +1058,20 @@ void exynos_dp_init_video(struct exynos_dp_device *dp)
	writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_8);
}

void exynos_dp_set_video_color_format(struct exynos_dp_device *dp,
			u32 color_depth,
			u32 color_space,
			u32 dynamic_range,
			u32 ycbcr_coeff)
void exynos_dp_set_video_color_format(struct exynos_dp_device *dp)
{
	u32 reg;

	/* Configure the input color depth, color space, dynamic range */
	reg = (dynamic_range << IN_D_RANGE_SHIFT) |
		(color_depth << IN_BPC_SHIFT) |
		(color_space << IN_COLOR_F_SHIFT);
	reg = (dp->video_info->dynamic_range << IN_D_RANGE_SHIFT) |
		(dp->video_info->color_depth << IN_BPC_SHIFT) |
		(dp->video_info->color_space << IN_COLOR_F_SHIFT);
	writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_2);

	/* Set Input Color YCbCr Coefficients to ITU601 or ITU709 */
	reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_3);
	reg &= ~IN_YC_COEFFI_MASK;
	if (ycbcr_coeff)
	if (dp->video_info->ycbcr_coeff)
		reg |= IN_YC_COEFFI_ITU709;
	else
		reg |= IN_YC_COEFFI_ITU601;
@@ -1178,8 +1198,7 @@ int exynos_dp_is_video_stream_on(struct exynos_dp_device *dp)
	return 0;
}

void exynos_dp_config_video_slave_mode(struct exynos_dp_device *dp,
			struct video_info *video_info)
void exynos_dp_config_video_slave_mode(struct exynos_dp_device *dp)
{
	u32 reg;

@@ -1190,17 +1209,17 @@ void exynos_dp_config_video_slave_mode(struct exynos_dp_device *dp,

	reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
	reg &= ~INTERACE_SCAN_CFG;
	reg |= (video_info->interlaced << 2);
	reg |= (dp->video_info->interlaced << 2);
	writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);

	reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
	reg &= ~VSYNC_POLARITY_CFG;
	reg |= (video_info->v_sync_polarity << 1);
	reg |= (dp->video_info->v_sync_polarity << 1);
	writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);

	reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
	reg &= ~HSYNC_POLARITY_CFG;
	reg |= (video_info->h_sync_polarity << 0);
	reg |= (dp->video_info->h_sync_polarity << 0);
	writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);

	reg = AUDIO_MODE_SPDIF_MODE | VIDEO_MODE_SLAVE_MODE;
+2 −1
Original line number Diff line number Diff line
@@ -242,7 +242,8 @@

/* EXYNOS_DP_INT_CTL */
#define SOFT_INT_CTRL				(0x1 << 2)
#define INT_POL					(0x1 << 0)
#define INT_POL1				(0x1 << 1)
#define INT_POL0				(0x1 << 0)

/* EXYNOS_DP_SYS_CTL_1 */
#define DET_STA					(0x1 << 2)