HDMI 2.0 spec defines a method to reduce the RF footprint while operating at higher pixel clocks, which is called Scrambling. Scrambling can be controlled over a new set of I2C registers which are accessible over existing DDC I2C lines, called SCDC register set.
This patch series contains 6 patches: - First two patches add generic drm helper functions to read and write into SCDC registers. These patches are written by Thierry, in a patch series published here: https://patchwork.kernel.org/patch/9459051/ Minor changes were done to map the patches into this series. - Next two patches add functions for scrambling detection and scrambling control. - Next two patches use this infrastructure in DRM layer From I915 driver, to enable scrambling on a GLK deivce which sports a native HDMI 2.0 controller.
V2: - addressed review comments from Thierry, Ville and Dhinakaran - added signed-off-by:self in first two patches(Jani N)
Shashank Sharma (4): drm/edid: detect SCDC support in HF-VSDB drm: scrambling support in drm layer drm/i915: enable scrambling drm/i915: allow HDMI 2.0 clock rates
Thierry Reding (2): drm: Add SCDC helpers drm/edid: check for HF-VSDB block
Documentation/gpu/drm-kms-helpers.rst | 12 ++ drivers/gpu/drm/Makefile | 3 +- drivers/gpu/drm/drm_edid.c | 60 ++++++++++ drivers/gpu/drm/drm_scdc_helper.c | 211 ++++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/i915_reg.h | 2 + drivers/gpu/drm/i915/intel_ddi.c | 26 +++++ drivers/gpu/drm/i915/intel_drv.h | 11 ++ drivers/gpu/drm/i915/intel_hdmi.c | 72 ++++++++++++ include/drm/drm_connector.h | 52 +++++++++ include/drm/drm_edid.h | 6 +- include/drm/drm_scdc_helper.h | 152 ++++++++++++++++++++++++ include/linux/hdmi.h | 1 + 12 files changed, 606 insertions(+), 2 deletions(-) create mode 100644 drivers/gpu/drm/drm_scdc_helper.c create mode 100644 include/drm/drm_scdc_helper.h
From: Thierry Reding treding@nvidia.com
SCDC is a mechanism defined in the HDMI 2.0 specification that allows the source and sink devices to communicate.
This commit introduces helpers to access the SCDC and provides the symbolic names for the various registers defined in the specification.
Signed-off-by: Thierry Reding treding@nvidia.com Signed-off-by: Shashank Sharma shashank.sharma@intel.com --- Documentation/gpu/drm-kms-helpers.rst | 12 ++++ drivers/gpu/drm/Makefile | 3 +- drivers/gpu/drm/drm_scdc_helper.c | 111 ++++++++++++++++++++++++++++ include/drm/drm_scdc_helper.h | 132 ++++++++++++++++++++++++++++++++++ 4 files changed, 257 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/drm_scdc_helper.c create mode 100644 include/drm/drm_scdc_helper.h
diff --git a/Documentation/gpu/drm-kms-helpers.rst b/Documentation/gpu/drm-kms-helpers.rst index 03040aa..7592756 100644 --- a/Documentation/gpu/drm-kms-helpers.rst +++ b/Documentation/gpu/drm-kms-helpers.rst @@ -217,6 +217,18 @@ EDID Helper Functions Reference .. kernel-doc:: drivers/gpu/drm/drm_edid.c :export:
+SCDC Helper Functions Reference +=============================== + +.. kernel-doc:: drivers/gpu/drm/drm_scdc_helper.c + :doc: scdc helpers + +.. kernel-doc:: include/drm/drm_scdc_helper.h + :internal: + +.. kernel-doc:: drivers/gpu/drm/drm_scdc_helper.c + :export: + Rectangle Utilities Reference =============================
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 92de399..ad91cd9 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -31,7 +31,8 @@ drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_probe_helper.o \ drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o \ drm_kms_helper_common.o drm_dp_dual_mode_helper.o \ - drm_simple_kms_helper.o drm_modeset_helper.o + drm_simple_kms_helper.o drm_modeset_helper.o \ + drm_scdc_helper.o
drm_kms_helper-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o diff --git a/drivers/gpu/drm/drm_scdc_helper.c b/drivers/gpu/drm/drm_scdc_helper.c new file mode 100644 index 0000000..fe0e121 --- /dev/null +++ b/drivers/gpu/drm/drm_scdc_helper.c @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2015 NVIDIA Corporation. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sub license, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <linux/slab.h> + +#include <drm/drm_scdc_helper.h> + +/** + * DOC: scdc helpers + * + * Status and Control Data Channel (SCDC) is a mechanism introduced by the + * HDMI 2.0 specification. It is a point-to-point protocol that allows the + * HDMI source and HDMI sink to exchange data. The same I2C interface that + * is used to access EDID serves as the transport mechanism for SCDC. + */ + +#define SCDC_I2C_SLAVE_ADDRESS 0x54 + +/** + * drm_scdc_read - read a block of data from SCDC + * @adapter: I2C controller + * @offset: start offset of block to read + * @buffer: return location for the block to read + * @size: size of the block to read + * + * Reads a block of data from SCDC, starting at a given offset. + * + * Returns: + * The number of bytes read from SCDC or a negative error code on failure. + */ +ssize_t drm_scdc_read(struct i2c_adapter *adapter, u8 offset, void *buffer, + size_t size) +{ + struct i2c_msg msgs[2] = { + { + .addr = SCDC_I2C_SLAVE_ADDRESS, + .flags = 0, + .len = 1, + .buf = &offset, + }, { + .addr = SCDC_I2C_SLAVE_ADDRESS, + .flags = I2C_M_RD, + .len = size, + .buf = buffer, + } + }; + + return i2c_transfer(adapter, msgs, ARRAY_SIZE(msgs)); +} +EXPORT_SYMBOL(drm_scdc_read); + +/** + * drm_scdc_write - write a block of data to SCDC + * @adapter: I2C controller + * @offset: start offset of block to write + * @buffer: block of data to write + * @size: size of the block to write + * + * Writes a block of data to SCDC, starting at a given offset. + * + * Returns: + * The number of bytes written to SCDC or a negative error code on failure. + */ +ssize_t drm_scdc_write(struct i2c_adapter *adapter, u8 offset, + const void *buffer, size_t size) +{ + struct i2c_msg msg = { + .addr = SCDC_I2C_SLAVE_ADDRESS, + .flags = 0, + .len = 1 + size, + .buf = NULL, + }; + void *data; + int err; + + data = kmalloc(1 + size, GFP_TEMPORARY); + if (!data) + return -ENOMEM; + + msg.buf = data; + + memcpy(data, &offset, sizeof(offset)); + memcpy(data + 1, buffer, size); + + err = i2c_transfer(adapter, &msg, 1); + + kfree(data); + + return err; +} +EXPORT_SYMBOL(drm_scdc_write); diff --git a/include/drm/drm_scdc_helper.h b/include/drm/drm_scdc_helper.h new file mode 100644 index 0000000..93b07bc --- /dev/null +++ b/include/drm/drm_scdc_helper.h @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2015 NVIDIA Corporation. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sub license, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef DRM_SCDC_HELPER_H +#define DRM_SCDC_HELPER_H + +#include <linux/i2c.h> +#include <linux/types.h> + +#define SCDC_SINK_VERSION 0x01 + +#define SCDC_SOURCE_VERSION 0x02 + +#define SCDC_UPDATE_0 0x10 +#define SCDC_READ_REQUEST_TEST (1 << 2) +#define SCDC_CED_UPDATE (1 << 1) +#define SCDC_STATUS_UPDATE (1 << 0) + +#define SCDC_UPDATE_1 0x11 + +#define SCDC_TMDS_CONFIG 0x20 +#define SCDC_TMDS_BIT_CLOCK_RATIO_BY_40 (1 << 1) +#define SCDC_TMDS_BIT_CLOCK_RATIO_BY_10 (0 << 1) +#define SCDC_SCRAMBLING_ENABLE (1 << 0) + +#define SCDC_SCRAMBLER_STATUS 0x21 +#define SCDC_SCRAMBLING_STATUS (1 << 0) + +#define SCDC_CONFIG_0 0x30 +#define SCDC_READ_REQUEST_ENABLE (1 << 0) + +#define SCDC_STATUS_FLAGS_0 0x40 +#define SCDC_CH2_LOCK (1 < 3) +#define SCDC_CH1_LOCK (1 < 2) +#define SCDC_CH0_LOCK (1 < 1) +#define SCDC_CH_LOCK_MASK (SCDC_CH2_LOCK | SCDC_CH1_LOCK | SCDC_CH0_LOCK) +#define SCDC_CLOCK_DETECT (1 << 0) + +#define SCDC_STATUS_FLAGS_1 0x41 + +#define SCDC_ERR_DET_0_L 0x50 +#define SCDC_ERR_DET_0_H 0x51 +#define SCDC_ERR_DET_1_L 0x52 +#define SCDC_ERR_DET_1_H 0x53 +#define SCDC_ERR_DET_2_L 0x54 +#define SCDC_ERR_DET_2_H 0x55 +#define SCDC_CHANNEL_VALID (1 << 7) + +#define SCDC_ERR_DET_CHECKSUM 0x56 + +#define SCDC_TEST_CONFIG_0 0xc0 +#define SCDC_TEST_READ_REQUEST (1 << 7) +#define SCDC_TEST_READ_REQUEST_DELAY(x) ((x) & 0x7f) + +#define SCDC_MANUFACTURER_IEEE_OUI 0xd0 +#define SCDC_MANUFACTURER_IEEE_OUI_SIZE 3 + +#define SCDC_DEVICE_ID 0xd3 +#define SCDC_DEVICE_ID_SIZE 8 + +#define SCDC_DEVICE_HARDWARE_REVISION 0xdb +#define SCDC_DEVICE_HARDWARE_REVISION_MAJOR(x) (((x) >> 4) & 0xf) +#define SCDC_DEVICE_HARDWARE_REVISION_MINOR(x) (((x) >> 0) & 0xf) + +#define SCDC_DEVICE_SOFTWARE_MAJOR_REVISION 0xdc +#define SCDC_DEVICE_SOFTWARE_MINOR_REVISION 0xdd + +#define SCDC_MANUFACTURER_SPECIFIC 0xde +#define SCDC_MANUFACTURER_SPECIFIC_SIZE 34 + +ssize_t drm_scdc_read(struct i2c_adapter *adapter, u8 offset, void *buffer, + size_t size); +ssize_t drm_scdc_write(struct i2c_adapter *adapter, u8 offset, + const void *buffer, size_t size); + +/** + * drm_scdc_readb - read a single byte from SCDC + * @adapter: I2C adapter + * @offset: offset of register to read + * @value: return location for the register value + * + * Reads a single byte from SCDC. This is a convenience wrapper around the + * drm_scdc_read() function. + * + * Returns: + * 0 on success or a negative error code on failure. + */ +static inline int drm_scdc_readb(struct i2c_adapter *adapter, u8 offset, + u8 *value) +{ + return drm_scdc_read(adapter, offset, value, sizeof(*value)); +} + +/** + * drm_scdc_writeb - write a single byte to SCDC + * @adapter: I2C adapter + * @offset: offset of register to read + * @value: return location for the register value + * + * Writes a single byte to SCDC. This is a convenience wrapper around the + * drm_scdc_write() function. + * + * Returns: + * 0 on success or a negative error code on failure. + */ +static inline int drm_scdc_writeb(struct i2c_adapter *adapter, u8 offset, + u8 value) +{ + return drm_scdc_write(adapter, offset, &value, sizeof(value)); +} + +#endif
Hi Shashank,
Sorry for the late review.
On 06-02-2017 13:59, Shashank Sharma wrote:
From: Thierry Reding treding@nvidia.com
SCDC is a mechanism defined in the HDMI 2.0 specification that allows the source and sink devices to communicate.
This commit introduces helpers to access the SCDC and provides the symbolic names for the various registers defined in the specification.
Signed-off-by: Thierry Reding treding@nvidia.com Signed-off-by: Shashank Sharma shashank.sharma@intel.com
Documentation/gpu/drm-kms-helpers.rst | 12 ++++ drivers/gpu/drm/Makefile | 3 +- drivers/gpu/drm/drm_scdc_helper.c | 111 ++++++++++++++++++++++++++++ include/drm/drm_scdc_helper.h | 132 ++++++++++++++++++++++++++++++++++ 4 files changed, 257 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/drm_scdc_helper.c create mode 100644 include/drm/drm_scdc_helper.h
diff --git a/Documentation/gpu/drm-kms-helpers.rst b/Documentation/gpu/drm-kms-helpers.rst index 03040aa..7592756 100644 --- a/Documentation/gpu/drm-kms-helpers.rst +++ b/Documentation/gpu/drm-kms-helpers.rst @@ -217,6 +217,18 @@ EDID Helper Functions Reference .. kernel-doc:: drivers/gpu/drm/drm_edid.c :export:
+SCDC Helper Functions Reference +===============================
+.. kernel-doc:: drivers/gpu/drm/drm_scdc_helper.c
- :doc: scdc helpers
+.. kernel-doc:: include/drm/drm_scdc_helper.h
- :internal:
+.. kernel-doc:: drivers/gpu/drm/drm_scdc_helper.c
- :export:
Rectangle Utilities Reference
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 92de399..ad91cd9 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -31,7 +31,8 @@ drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_probe_helper.o \ drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o \ drm_kms_helper_common.o drm_dp_dual_mode_helper.o \
drm_simple_kms_helper.o drm_modeset_helper.o
drm_simple_kms_helper.o drm_modeset_helper.o \
drm_scdc_helper.o
drm_kms_helper-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o diff --git a/drivers/gpu/drm/drm_scdc_helper.c b/drivers/gpu/drm/drm_scdc_helper.c new file mode 100644 index 0000000..fe0e121 --- /dev/null +++ b/drivers/gpu/drm/drm_scdc_helper.c @@ -0,0 +1,111 @@ +/*
- Copyright (c) 2015 NVIDIA Corporation. All rights reserved.
- Permission is hereby granted, free of charge, to any person obtaining a
- copy of this software and associated documentation files (the "Software"),
- to deal in the Software without restriction, including without limitation
- the rights to use, copy, modify, merge, publish, distribute, sub license,
- and/or sell copies of the Software, and to permit persons to whom the
- Software is furnished to do so, subject to the following conditions:
- The above copyright notice and this permission notice (including the
- next paragraph) shall be included in all copies or substantial portions
- of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
- THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- DEALINGS IN THE SOFTWARE.
- */
+#include <linux/slab.h>
+#include <drm/drm_scdc_helper.h>
+/**
- DOC: scdc helpers
- Status and Control Data Channel (SCDC) is a mechanism introduced by the
- HDMI 2.0 specification. It is a point-to-point protocol that allows the
- HDMI source and HDMI sink to exchange data. The same I2C interface that
- is used to access EDID serves as the transport mechanism for SCDC.
- */
+#define SCDC_I2C_SLAVE_ADDRESS 0x54
+/**
- drm_scdc_read - read a block of data from SCDC
- @adapter: I2C controller
- @offset: start offset of block to read
- @buffer: return location for the block to read
- @size: size of the block to read
- Reads a block of data from SCDC, starting at a given offset.
- Returns:
- The number of bytes read from SCDC or a negative error code on failure.
- */
+ssize_t drm_scdc_read(struct i2c_adapter *adapter, u8 offset, void *buffer,
size_t size)
+{
- struct i2c_msg msgs[2] = {
{
.addr = SCDC_I2C_SLAVE_ADDRESS,
.flags = 0,
.len = 1,
.len = sizeof(offset) ?
.buf = &offset,
}, {
.addr = SCDC_I2C_SLAVE_ADDRESS,
.flags = I2C_M_RD,
.len = size,
.buf = buffer,
}
- };
- return i2c_transfer(adapter, msgs, ARRAY_SIZE(msgs));
+} +EXPORT_SYMBOL(drm_scdc_read);
+/**
- drm_scdc_write - write a block of data to SCDC
- @adapter: I2C controller
- @offset: start offset of block to write
- @buffer: block of data to write
- @size: size of the block to write
- Writes a block of data to SCDC, starting at a given offset.
- Returns:
- The number of bytes written to SCDC or a negative error code on failure.
- */
+ssize_t drm_scdc_write(struct i2c_adapter *adapter, u8 offset,
const void *buffer, size_t size)
+{
- struct i2c_msg msg = {
.addr = SCDC_I2C_SLAVE_ADDRESS,
.flags = 0,
.len = 1 + size,
.len = sizeof(offset) + size ?
.buf = NULL,
- };
- void *data;
- int err;
- data = kmalloc(1 + size, GFP_TEMPORARY);
Same as above.
- if (!data)
return -ENOMEM;
- msg.buf = data;
- memcpy(data, &offset, sizeof(offset));
- memcpy(data + 1, buffer, size);
Same as above.
Best regards, Jose Miguel Abreu
- err = i2c_transfer(adapter, &msg, 1);
- kfree(data);
- return err;
+} +EXPORT_SYMBOL(drm_scdc_write); diff --git a/include/drm/drm_scdc_helper.h b/include/drm/drm_scdc_helper.h new file mode 100644 index 0000000..93b07bc --- /dev/null +++ b/include/drm/drm_scdc_helper.h @@ -0,0 +1,132 @@ +/*
- Copyright (c) 2015 NVIDIA Corporation. All rights reserved.
- Permission is hereby granted, free of charge, to any person obtaining a
- copy of this software and associated documentation files (the "Software"),
- to deal in the Software without restriction, including without limitation
- the rights to use, copy, modify, merge, publish, distribute, sub license,
- and/or sell copies of the Software, and to permit persons to whom the
- Software is furnished to do so, subject to the following conditions:
- The above copyright notice and this permission notice (including the
- next paragraph) shall be included in all copies or substantial portions
- of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
- THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- DEALINGS IN THE SOFTWARE.
- */
+#ifndef DRM_SCDC_HELPER_H +#define DRM_SCDC_HELPER_H
+#include <linux/i2c.h> +#include <linux/types.h>
+#define SCDC_SINK_VERSION 0x01
+#define SCDC_SOURCE_VERSION 0x02
+#define SCDC_UPDATE_0 0x10 +#define SCDC_READ_REQUEST_TEST (1 << 2) +#define SCDC_CED_UPDATE (1 << 1) +#define SCDC_STATUS_UPDATE (1 << 0)
+#define SCDC_UPDATE_1 0x11
+#define SCDC_TMDS_CONFIG 0x20 +#define SCDC_TMDS_BIT_CLOCK_RATIO_BY_40 (1 << 1) +#define SCDC_TMDS_BIT_CLOCK_RATIO_BY_10 (0 << 1) +#define SCDC_SCRAMBLING_ENABLE (1 << 0)
+#define SCDC_SCRAMBLER_STATUS 0x21 +#define SCDC_SCRAMBLING_STATUS (1 << 0)
+#define SCDC_CONFIG_0 0x30 +#define SCDC_READ_REQUEST_ENABLE (1 << 0)
+#define SCDC_STATUS_FLAGS_0 0x40 +#define SCDC_CH2_LOCK (1 < 3) +#define SCDC_CH1_LOCK (1 < 2) +#define SCDC_CH0_LOCK (1 < 1) +#define SCDC_CH_LOCK_MASK (SCDC_CH2_LOCK | SCDC_CH1_LOCK | SCDC_CH0_LOCK) +#define SCDC_CLOCK_DETECT (1 << 0)
+#define SCDC_STATUS_FLAGS_1 0x41
+#define SCDC_ERR_DET_0_L 0x50 +#define SCDC_ERR_DET_0_H 0x51 +#define SCDC_ERR_DET_1_L 0x52 +#define SCDC_ERR_DET_1_H 0x53 +#define SCDC_ERR_DET_2_L 0x54 +#define SCDC_ERR_DET_2_H 0x55 +#define SCDC_CHANNEL_VALID (1 << 7)
+#define SCDC_ERR_DET_CHECKSUM 0x56
+#define SCDC_TEST_CONFIG_0 0xc0 +#define SCDC_TEST_READ_REQUEST (1 << 7) +#define SCDC_TEST_READ_REQUEST_DELAY(x) ((x) & 0x7f)
+#define SCDC_MANUFACTURER_IEEE_OUI 0xd0 +#define SCDC_MANUFACTURER_IEEE_OUI_SIZE 3
+#define SCDC_DEVICE_ID 0xd3 +#define SCDC_DEVICE_ID_SIZE 8
+#define SCDC_DEVICE_HARDWARE_REVISION 0xdb +#define SCDC_DEVICE_HARDWARE_REVISION_MAJOR(x) (((x) >> 4) & 0xf) +#define SCDC_DEVICE_HARDWARE_REVISION_MINOR(x) (((x) >> 0) & 0xf)
+#define SCDC_DEVICE_SOFTWARE_MAJOR_REVISION 0xdc +#define SCDC_DEVICE_SOFTWARE_MINOR_REVISION 0xdd
+#define SCDC_MANUFACTURER_SPECIFIC 0xde +#define SCDC_MANUFACTURER_SPECIFIC_SIZE 34
+ssize_t drm_scdc_read(struct i2c_adapter *adapter, u8 offset, void *buffer,
size_t size);
+ssize_t drm_scdc_write(struct i2c_adapter *adapter, u8 offset,
const void *buffer, size_t size);
+/**
- drm_scdc_readb - read a single byte from SCDC
- @adapter: I2C adapter
- @offset: offset of register to read
- @value: return location for the register value
- Reads a single byte from SCDC. This is a convenience wrapper around the
- drm_scdc_read() function.
- Returns:
- 0 on success or a negative error code on failure.
- */
+static inline int drm_scdc_readb(struct i2c_adapter *adapter, u8 offset,
u8 *value)
+{
- return drm_scdc_read(adapter, offset, value, sizeof(*value));
+}
+/**
- drm_scdc_writeb - write a single byte to SCDC
- @adapter: I2C adapter
- @offset: offset of register to read
- @value: return location for the register value
- Writes a single byte to SCDC. This is a convenience wrapper around the
- drm_scdc_write() function.
- Returns:
- 0 on success or a negative error code on failure.
- */
+static inline int drm_scdc_writeb(struct i2c_adapter *adapter, u8 offset,
u8 value)
+{
- return drm_scdc_write(adapter, offset, &value, sizeof(value));
+}
+#endif
Thanks for the review Jose, my comments inline.
Regards
Shashank
On 2/7/2017 4:24 PM, Jose Abreu wrote:
Hi Shashank,
Sorry for the late review.
On 06-02-2017 13:59, Shashank Sharma wrote:
From: Thierry Reding treding@nvidia.com
SCDC is a mechanism defined in the HDMI 2.0 specification that allows the source and sink devices to communicate.
This commit introduces helpers to access the SCDC and provides the symbolic names for the various registers defined in the specification.
Signed-off-by: Thierry Reding treding@nvidia.com Signed-off-by: Shashank Sharma shashank.sharma@intel.com
Documentation/gpu/drm-kms-helpers.rst | 12 ++++ drivers/gpu/drm/Makefile | 3 +- drivers/gpu/drm/drm_scdc_helper.c | 111 ++++++++++++++++++++++++++++ include/drm/drm_scdc_helper.h | 132 ++++++++++++++++++++++++++++++++++ 4 files changed, 257 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/drm_scdc_helper.c create mode 100644 include/drm/drm_scdc_helper.h
diff --git a/Documentation/gpu/drm-kms-helpers.rst b/Documentation/gpu/drm-kms-helpers.rst index 03040aa..7592756 100644 --- a/Documentation/gpu/drm-kms-helpers.rst +++ b/Documentation/gpu/drm-kms-helpers.rst @@ -217,6 +217,18 @@ EDID Helper Functions Reference .. kernel-doc:: drivers/gpu/drm/drm_edid.c :export:
+SCDC Helper Functions Reference +===============================
+.. kernel-doc:: drivers/gpu/drm/drm_scdc_helper.c
- :doc: scdc helpers
+.. kernel-doc:: include/drm/drm_scdc_helper.h
- :internal:
+.. kernel-doc:: drivers/gpu/drm/drm_scdc_helper.c
- :export:
Rectangle Utilities Reference
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 92de399..ad91cd9 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -31,7 +31,8 @@ drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_probe_helper.o \ drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o \ drm_kms_helper_common.o drm_dp_dual_mode_helper.o \
drm_simple_kms_helper.o drm_modeset_helper.o
drm_simple_kms_helper.o drm_modeset_helper.o \
drm_scdc_helper.o
drm_kms_helper-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o
diff --git a/drivers/gpu/drm/drm_scdc_helper.c b/drivers/gpu/drm/drm_scdc_helper.c new file mode 100644 index 0000000..fe0e121 --- /dev/null +++ b/drivers/gpu/drm/drm_scdc_helper.c @@ -0,0 +1,111 @@ +/*
- Copyright (c) 2015 NVIDIA Corporation. All rights reserved.
- Permission is hereby granted, free of charge, to any person obtaining a
- copy of this software and associated documentation files (the "Software"),
- to deal in the Software without restriction, including without limitation
- the rights to use, copy, modify, merge, publish, distribute, sub license,
- and/or sell copies of the Software, and to permit persons to whom the
- Software is furnished to do so, subject to the following conditions:
- The above copyright notice and this permission notice (including the
- next paragraph) shall be included in all copies or substantial portions
- of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
- THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- DEALINGS IN THE SOFTWARE.
- */
+#include <linux/slab.h>
+#include <drm/drm_scdc_helper.h>
+/**
- DOC: scdc helpers
- Status and Control Data Channel (SCDC) is a mechanism introduced by the
- HDMI 2.0 specification. It is a point-to-point protocol that allows the
- HDMI source and HDMI sink to exchange data. The same I2C interface that
- is used to access EDID serves as the transport mechanism for SCDC.
- */
+#define SCDC_I2C_SLAVE_ADDRESS 0x54
+/**
- drm_scdc_read - read a block of data from SCDC
- @adapter: I2C controller
- @offset: start offset of block to read
- @buffer: return location for the block to read
- @size: size of the block to read
- Reads a block of data from SCDC, starting at a given offset.
- Returns:
- The number of bytes read from SCDC or a negative error code on failure.
- */
+ssize_t drm_scdc_read(struct i2c_adapter *adapter, u8 offset, void *buffer,
size_t size)
+{
- struct i2c_msg msgs[2] = {
{
.addr = SCDC_I2C_SLAVE_ADDRESS,
.flags = 0,
.len = 1,
.len = sizeof(offset) ?
Technically correct, but wouldn't that mean that we are expecting to have I2C offsets with length more than one byte ?
.buf = &offset,
}, {
.addr = SCDC_I2C_SLAVE_ADDRESS,
.flags = I2C_M_RD,
.len = size,
.buf = buffer,
}
- };
- return i2c_transfer(adapter, msgs, ARRAY_SIZE(msgs));
+} +EXPORT_SYMBOL(drm_scdc_read);
+/**
- drm_scdc_write - write a block of data to SCDC
- @adapter: I2C controller
- @offset: start offset of block to write
- @buffer: block of data to write
- @size: size of the block to write
- Writes a block of data to SCDC, starting at a given offset.
- Returns:
- The number of bytes written to SCDC or a negative error code on failure.
- */
+ssize_t drm_scdc_write(struct i2c_adapter *adapter, u8 offset,
const void *buffer, size_t size)
+{
- struct i2c_msg msg = {
.addr = SCDC_I2C_SLAVE_ADDRESS,
.flags = 0,
.len = 1 + size,
.len = sizeof(offset) + size ?
Same as above.
.buf = NULL,
- };
- void *data;
- int err;
- data = kmalloc(1 + size, GFP_TEMPORARY);
Same as above.
So on ...
- if (!data)
return -ENOMEM;
- msg.buf = data;
- memcpy(data, &offset, sizeof(offset));
- memcpy(data + 1, buffer, size);
Same as above.
So on ..
Best regards, Jose Miguel Abreu
- Shashank
- err = i2c_transfer(adapter, &msg, 1);
- kfree(data);
- return err;
+} +EXPORT_SYMBOL(drm_scdc_write); diff --git a/include/drm/drm_scdc_helper.h b/include/drm/drm_scdc_helper.h new file mode 100644 index 0000000..93b07bc --- /dev/null +++ b/include/drm/drm_scdc_helper.h @@ -0,0 +1,132 @@ +/*
- Copyright (c) 2015 NVIDIA Corporation. All rights reserved.
- Permission is hereby granted, free of charge, to any person obtaining a
- copy of this software and associated documentation files (the "Software"),
- to deal in the Software without restriction, including without limitation
- the rights to use, copy, modify, merge, publish, distribute, sub license,
- and/or sell copies of the Software, and to permit persons to whom the
- Software is furnished to do so, subject to the following conditions:
- The above copyright notice and this permission notice (including the
- next paragraph) shall be included in all copies or substantial portions
- of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
- THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- DEALINGS IN THE SOFTWARE.
- */
+#ifndef DRM_SCDC_HELPER_H +#define DRM_SCDC_HELPER_H
+#include <linux/i2c.h> +#include <linux/types.h>
+#define SCDC_SINK_VERSION 0x01
+#define SCDC_SOURCE_VERSION 0x02
+#define SCDC_UPDATE_0 0x10 +#define SCDC_READ_REQUEST_TEST (1 << 2) +#define SCDC_CED_UPDATE (1 << 1) +#define SCDC_STATUS_UPDATE (1 << 0)
+#define SCDC_UPDATE_1 0x11
+#define SCDC_TMDS_CONFIG 0x20 +#define SCDC_TMDS_BIT_CLOCK_RATIO_BY_40 (1 << 1) +#define SCDC_TMDS_BIT_CLOCK_RATIO_BY_10 (0 << 1) +#define SCDC_SCRAMBLING_ENABLE (1 << 0)
+#define SCDC_SCRAMBLER_STATUS 0x21 +#define SCDC_SCRAMBLING_STATUS (1 << 0)
+#define SCDC_CONFIG_0 0x30 +#define SCDC_READ_REQUEST_ENABLE (1 << 0)
+#define SCDC_STATUS_FLAGS_0 0x40 +#define SCDC_CH2_LOCK (1 < 3) +#define SCDC_CH1_LOCK (1 < 2) +#define SCDC_CH0_LOCK (1 < 1) +#define SCDC_CH_LOCK_MASK (SCDC_CH2_LOCK | SCDC_CH1_LOCK | SCDC_CH0_LOCK) +#define SCDC_CLOCK_DETECT (1 << 0)
+#define SCDC_STATUS_FLAGS_1 0x41
+#define SCDC_ERR_DET_0_L 0x50 +#define SCDC_ERR_DET_0_H 0x51 +#define SCDC_ERR_DET_1_L 0x52 +#define SCDC_ERR_DET_1_H 0x53 +#define SCDC_ERR_DET_2_L 0x54 +#define SCDC_ERR_DET_2_H 0x55 +#define SCDC_CHANNEL_VALID (1 << 7)
+#define SCDC_ERR_DET_CHECKSUM 0x56
+#define SCDC_TEST_CONFIG_0 0xc0 +#define SCDC_TEST_READ_REQUEST (1 << 7) +#define SCDC_TEST_READ_REQUEST_DELAY(x) ((x) & 0x7f)
+#define SCDC_MANUFACTURER_IEEE_OUI 0xd0 +#define SCDC_MANUFACTURER_IEEE_OUI_SIZE 3
+#define SCDC_DEVICE_ID 0xd3 +#define SCDC_DEVICE_ID_SIZE 8
+#define SCDC_DEVICE_HARDWARE_REVISION 0xdb +#define SCDC_DEVICE_HARDWARE_REVISION_MAJOR(x) (((x) >> 4) & 0xf) +#define SCDC_DEVICE_HARDWARE_REVISION_MINOR(x) (((x) >> 0) & 0xf)
+#define SCDC_DEVICE_SOFTWARE_MAJOR_REVISION 0xdc +#define SCDC_DEVICE_SOFTWARE_MINOR_REVISION 0xdd
+#define SCDC_MANUFACTURER_SPECIFIC 0xde +#define SCDC_MANUFACTURER_SPECIFIC_SIZE 34
+ssize_t drm_scdc_read(struct i2c_adapter *adapter, u8 offset, void *buffer,
size_t size);
+ssize_t drm_scdc_write(struct i2c_adapter *adapter, u8 offset,
const void *buffer, size_t size);
+/**
- drm_scdc_readb - read a single byte from SCDC
- @adapter: I2C adapter
- @offset: offset of register to read
- @value: return location for the register value
- Reads a single byte from SCDC. This is a convenience wrapper around the
- drm_scdc_read() function.
- Returns:
- 0 on success or a negative error code on failure.
- */
+static inline int drm_scdc_readb(struct i2c_adapter *adapter, u8 offset,
u8 *value)
+{
- return drm_scdc_read(adapter, offset, value, sizeof(*value));
+}
+/**
- drm_scdc_writeb - write a single byte to SCDC
- @adapter: I2C adapter
- @offset: offset of register to read
- @value: return location for the register value
- Writes a single byte to SCDC. This is a convenience wrapper around the
- drm_scdc_write() function.
- Returns:
- 0 on success or a negative error code on failure.
- */
+static inline int drm_scdc_writeb(struct i2c_adapter *adapter, u8 offset,
u8 value)
+{
- return drm_scdc_write(adapter, offset, &value, sizeof(value));
+}
+#endif
Hi Shashank,
On 07-02-2017 16:09, Sharma, Shashank wrote:
Thanks for the review Jose, my comments inline.
Regards
Shashank
On 2/7/2017 4:24 PM, Jose Abreu wrote:
Hi Shashank,
Sorry for the late review.
On 06-02-2017 13:59, Shashank Sharma wrote:
From: Thierry Reding treding@nvidia.com
SCDC is a mechanism defined in the HDMI 2.0 specification that allows the source and sink devices to communicate.
This commit introduces helpers to access the SCDC and provides the symbolic names for the various registers defined in the specification.
Signed-off-by: Thierry Reding treding@nvidia.com Signed-off-by: Shashank Sharma shashank.sharma@intel.com
Documentation/gpu/drm-kms-helpers.rst | 12 ++++ drivers/gpu/drm/Makefile | 3 +- drivers/gpu/drm/drm_scdc_helper.c | 111 ++++++++++++++++++++++++++++ include/drm/drm_scdc_helper.h | 132 ++++++++++++++++++++++++++++++++++ 4 files changed, 257 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/drm_scdc_helper.c create mode 100644 include/drm/drm_scdc_helper.h
diff --git a/Documentation/gpu/drm-kms-helpers.rst b/Documentation/gpu/drm-kms-helpers.rst index 03040aa..7592756 100644 --- a/Documentation/gpu/drm-kms-helpers.rst +++ b/Documentation/gpu/drm-kms-helpers.rst @@ -217,6 +217,18 @@ EDID Helper Functions Reference .. kernel-doc:: drivers/gpu/drm/drm_edid.c :export: +SCDC Helper Functions Reference +===============================
+.. kernel-doc:: drivers/gpu/drm/drm_scdc_helper.c
- :doc: scdc helpers
+.. kernel-doc:: include/drm/drm_scdc_helper.h
- :internal:
+.. kernel-doc:: drivers/gpu/drm/drm_scdc_helper.c
- :export:
Rectangle Utilities Reference
diff --git a/drivers/gpu/drm/Makefileb/drivers/gpu/drm/Makefile index 92de399..ad91cd9 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -31,7 +31,8 @@ drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_probe_helper.o \ drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o \ drm_kms_helper_common.o drm_dp_dual_mode_helper.o \
drm_simple_kms_helper.o drm_modeset_helper.o
drm_simple_kms_helper.o drm_modeset_helper.o \
drm_kms_helper-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) +=drm_scdc_helper.o
drm_edid_load.o drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o diff --git a/drivers/gpu/drm/drm_scdc_helper.c b/drivers/gpu/drm/drm_scdc_helper.c new file mode 100644 index 0000000..fe0e121 --- /dev/null +++ b/drivers/gpu/drm/drm_scdc_helper.c @@ -0,0 +1,111 @@ +/*
- Copyright (c) 2015 NVIDIA Corporation. All rights reserved.
- Permission is hereby granted, free of charge, to any
person obtaining a
- copy of this software and associated documentation files
(the "Software"),
- to deal in the Software without restriction, including
without limitation
- the rights to use, copy, modify, merge, publish,
distribute, sub license,
- and/or sell copies of the Software, and to permit persons
to whom the
- Software is furnished to do so, subject to the following
conditions:
- The above copyright notice and this permission notice
(including the
- next paragraph) shall be included in all copies or
substantial portions
- of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN
NO EVENT SHALL
- THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING
- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER
- DEALINGS IN THE SOFTWARE.
- */
+#include <linux/slab.h>
+#include <drm/drm_scdc_helper.h>
+/**
- DOC: scdc helpers
- Status and Control Data Channel (SCDC) is a mechanism
introduced by the
- HDMI 2.0 specification. It is a point-to-point protocol
that allows the
- HDMI source and HDMI sink to exchange data. The same I2C
interface that
- is used to access EDID serves as the transport mechanism
for SCDC.
- */
+#define SCDC_I2C_SLAVE_ADDRESS 0x54
+/**
- drm_scdc_read - read a block of data from SCDC
- @adapter: I2C controller
- @offset: start offset of block to read
- @buffer: return location for the block to read
- @size: size of the block to read
- Reads a block of data from SCDC, starting at a given offset.
- Returns:
- The number of bytes read from SCDC or a negative error
code on failure.
- */
+ssize_t drm_scdc_read(struct i2c_adapter *adapter, u8 offset, void *buffer,
size_t size)
+{
- struct i2c_msg msgs[2] = {
{
.addr = SCDC_I2C_SLAVE_ADDRESS,
.flags = 0,
.len = 1,
.len = sizeof(offset) ?
Technically correct, but wouldn't that mean that we are expecting to have I2C offsets with length more than one byte ?
I just commented this because it would be more consistent but indeed you are correct. You can disregard my comment :)
Best regards, Jose Miguel Abreu
.buf = &offset,
}, {
.addr = SCDC_I2C_SLAVE_ADDRESS,
.flags = I2C_M_RD,
.len = size,
.buf = buffer,
}
- };
- return i2c_transfer(adapter, msgs, ARRAY_SIZE(msgs));
+} +EXPORT_SYMBOL(drm_scdc_read);
+/**
- drm_scdc_write - write a block of data to SCDC
- @adapter: I2C controller
- @offset: start offset of block to write
- @buffer: block of data to write
- @size: size of the block to write
- Writes a block of data to SCDC, starting at a given offset.
- Returns:
- The number of bytes written to SCDC or a negative error
code on failure.
- */
+ssize_t drm_scdc_write(struct i2c_adapter *adapter, u8 offset,
const void *buffer, size_t size)
+{
- struct i2c_msg msg = {
.addr = SCDC_I2C_SLAVE_ADDRESS,
.flags = 0,
.len = 1 + size,
.len = sizeof(offset) + size ?
Same as above.
.buf = NULL,
- };
- void *data;
- int err;
- data = kmalloc(1 + size, GFP_TEMPORARY);
Same as above.
So on ...
- if (!data)
return -ENOMEM;
- msg.buf = data;
- memcpy(data, &offset, sizeof(offset));
- memcpy(data + 1, buffer, size);
Same as above.
So on ..
Best regards, Jose Miguel Abreu
- Shashank
- err = i2c_transfer(adapter, &msg, 1);
- kfree(data);
- return err;
+} +EXPORT_SYMBOL(drm_scdc_write); diff --git a/include/drm/drm_scdc_helper.h b/include/drm/drm_scdc_helper.h new file mode 100644 index 0000000..93b07bc --- /dev/null +++ b/include/drm/drm_scdc_helper.h @@ -0,0 +1,132 @@ +/*
- Copyright (c) 2015 NVIDIA Corporation. All rights reserved.
- Permission is hereby granted, free of charge, to any
person obtaining a
- copy of this software and associated documentation files
(the "Software"),
- to deal in the Software without restriction, including
without limitation
- the rights to use, copy, modify, merge, publish,
distribute, sub license,
- and/or sell copies of the Software, and to permit persons
to whom the
- Software is furnished to do so, subject to the following
conditions:
- The above copyright notice and this permission notice
(including the
- next paragraph) shall be included in all copies or
substantial portions
- of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN
NO EVENT SHALL
- THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING
- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER
- DEALINGS IN THE SOFTWARE.
- */
+#ifndef DRM_SCDC_HELPER_H +#define DRM_SCDC_HELPER_H
+#include <linux/i2c.h> +#include <linux/types.h>
+#define SCDC_SINK_VERSION 0x01
+#define SCDC_SOURCE_VERSION 0x02
+#define SCDC_UPDATE_0 0x10 +#define SCDC_READ_REQUEST_TEST (1 << 2) +#define SCDC_CED_UPDATE (1 << 1) +#define SCDC_STATUS_UPDATE (1 << 0)
+#define SCDC_UPDATE_1 0x11
+#define SCDC_TMDS_CONFIG 0x20 +#define SCDC_TMDS_BIT_CLOCK_RATIO_BY_40 (1 << 1) +#define SCDC_TMDS_BIT_CLOCK_RATIO_BY_10 (0 << 1) +#define SCDC_SCRAMBLING_ENABLE (1 << 0)
+#define SCDC_SCRAMBLER_STATUS 0x21 +#define SCDC_SCRAMBLING_STATUS (1 << 0)
+#define SCDC_CONFIG_0 0x30 +#define SCDC_READ_REQUEST_ENABLE (1 << 0)
+#define SCDC_STATUS_FLAGS_0 0x40 +#define SCDC_CH2_LOCK (1 < 3) +#define SCDC_CH1_LOCK (1 < 2) +#define SCDC_CH0_LOCK (1 < 1) +#define SCDC_CH_LOCK_MASK (SCDC_CH2_LOCK | SCDC_CH1_LOCK | SCDC_CH0_LOCK) +#define SCDC_CLOCK_DETECT (1 << 0)
+#define SCDC_STATUS_FLAGS_1 0x41
+#define SCDC_ERR_DET_0_L 0x50 +#define SCDC_ERR_DET_0_H 0x51 +#define SCDC_ERR_DET_1_L 0x52 +#define SCDC_ERR_DET_1_H 0x53 +#define SCDC_ERR_DET_2_L 0x54 +#define SCDC_ERR_DET_2_H 0x55 +#define SCDC_CHANNEL_VALID (1 << 7)
+#define SCDC_ERR_DET_CHECKSUM 0x56
+#define SCDC_TEST_CONFIG_0 0xc0 +#define SCDC_TEST_READ_REQUEST (1 << 7) +#define SCDC_TEST_READ_REQUEST_DELAY(x) ((x) & 0x7f)
+#define SCDC_MANUFACTURER_IEEE_OUI 0xd0 +#define SCDC_MANUFACTURER_IEEE_OUI_SIZE 3
+#define SCDC_DEVICE_ID 0xd3 +#define SCDC_DEVICE_ID_SIZE 8
+#define SCDC_DEVICE_HARDWARE_REVISION 0xdb +#define SCDC_DEVICE_HARDWARE_REVISION_MAJOR(x) (((x) >> 4) & 0xf) +#define SCDC_DEVICE_HARDWARE_REVISION_MINOR(x) (((x) >> 0) & 0xf)
+#define SCDC_DEVICE_SOFTWARE_MAJOR_REVISION 0xdc +#define SCDC_DEVICE_SOFTWARE_MINOR_REVISION 0xdd
+#define SCDC_MANUFACTURER_SPECIFIC 0xde +#define SCDC_MANUFACTURER_SPECIFIC_SIZE 34
+ssize_t drm_scdc_read(struct i2c_adapter *adapter, u8 offset, void *buffer,
size_t size);
+ssize_t drm_scdc_write(struct i2c_adapter *adapter, u8 offset,
const void *buffer, size_t size);
+/**
- drm_scdc_readb - read a single byte from SCDC
- @adapter: I2C adapter
- @offset: offset of register to read
- @value: return location for the register value
- Reads a single byte from SCDC. This is a convenience
wrapper around the
- drm_scdc_read() function.
- Returns:
- 0 on success or a negative error code on failure.
- */
+static inline int drm_scdc_readb(struct i2c_adapter *adapter, u8 offset,
u8 *value)
+{
- return drm_scdc_read(adapter, offset, value,
sizeof(*value)); +}
+/**
- drm_scdc_writeb - write a single byte to SCDC
- @adapter: I2C adapter
- @offset: offset of register to read
- @value: return location for the register value
- Writes a single byte to SCDC. This is a convenience
wrapper around the
- drm_scdc_write() function.
- Returns:
- 0 on success or a negative error code on failure.
- */
+static inline int drm_scdc_writeb(struct i2c_adapter *adapter, u8 offset,
u8 value)
+{
- return drm_scdc_write(adapter, offset, &value,
sizeof(value)); +}
+#endif
Regards
Shashank
On 2/8/2017 4:57 PM, Jose Abreu wrote:
Hi Shashank,
On 07-02-2017 16:09, Sharma, Shashank wrote:
Thanks for the review Jose, my comments inline.
Regards
Shashank
On 2/7/2017 4:24 PM, Jose Abreu wrote:
Hi Shashank,
Sorry for the late review.
On 06-02-2017 13:59, Shashank Sharma wrote:
From: Thierry Reding treding@nvidia.com
SCDC is a mechanism defined in the HDMI 2.0 specification that allows the source and sink devices to communicate.
This commit introduces helpers to access the SCDC and provides the symbolic names for the various registers defined in the specification.
Signed-off-by: Thierry Reding treding@nvidia.com Signed-off-by: Shashank Sharma shashank.sharma@intel.com
Documentation/gpu/drm-kms-helpers.rst | 12 ++++ drivers/gpu/drm/Makefile | 3 +- drivers/gpu/drm/drm_scdc_helper.c | 111 ++++++++++++++++++++++++++++ include/drm/drm_scdc_helper.h | 132 ++++++++++++++++++++++++++++++++++ 4 files changed, 257 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/drm_scdc_helper.c create mode 100644 include/drm/drm_scdc_helper.h
diff --git a/Documentation/gpu/drm-kms-helpers.rst b/Documentation/gpu/drm-kms-helpers.rst index 03040aa..7592756 100644 --- a/Documentation/gpu/drm-kms-helpers.rst +++ b/Documentation/gpu/drm-kms-helpers.rst @@ -217,6 +217,18 @@ EDID Helper Functions Reference .. kernel-doc:: drivers/gpu/drm/drm_edid.c :export: +SCDC Helper Functions Reference +===============================
+.. kernel-doc:: drivers/gpu/drm/drm_scdc_helper.c
- :doc: scdc helpers
+.. kernel-doc:: include/drm/drm_scdc_helper.h
- :internal:
+.. kernel-doc:: drivers/gpu/drm/drm_scdc_helper.c
- :export:
Rectangle Utilities Reference
diff --git a/drivers/gpu/drm/Makefileb/drivers/gpu/drm/Makefile index 92de399..ad91cd9 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -31,7 +31,8 @@ drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_probe_helper.o \ drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o \ drm_kms_helper_common.o drm_dp_dual_mode_helper.o \
drm_simple_kms_helper.o drm_modeset_helper.o
drm_simple_kms_helper.o drm_modeset_helper.o \
drm_kms_helper-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) +=drm_scdc_helper.o
drm_edid_load.o drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o diff --git a/drivers/gpu/drm/drm_scdc_helper.c b/drivers/gpu/drm/drm_scdc_helper.c new file mode 100644 index 0000000..fe0e121 --- /dev/null +++ b/drivers/gpu/drm/drm_scdc_helper.c @@ -0,0 +1,111 @@ +/*
- Copyright (c) 2015 NVIDIA Corporation. All rights reserved.
- Permission is hereby granted, free of charge, to any
person obtaining a
- copy of this software and associated documentation files
(the "Software"),
- to deal in the Software without restriction, including
without limitation
- the rights to use, copy, modify, merge, publish,
distribute, sub license,
- and/or sell copies of the Software, and to permit persons
to whom the
- Software is furnished to do so, subject to the following
conditions:
- The above copyright notice and this permission notice
(including the
- next paragraph) shall be included in all copies or
substantial portions
- of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN
NO EVENT SHALL
- THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING
- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER
- DEALINGS IN THE SOFTWARE.
- */
+#include <linux/slab.h>
+#include <drm/drm_scdc_helper.h>
+/**
- DOC: scdc helpers
- Status and Control Data Channel (SCDC) is a mechanism
introduced by the
- HDMI 2.0 specification. It is a point-to-point protocol
that allows the
- HDMI source and HDMI sink to exchange data. The same I2C
interface that
- is used to access EDID serves as the transport mechanism
for SCDC.
- */
+#define SCDC_I2C_SLAVE_ADDRESS 0x54
+/**
- drm_scdc_read - read a block of data from SCDC
- @adapter: I2C controller
- @offset: start offset of block to read
- @buffer: return location for the block to read
- @size: size of the block to read
- Reads a block of data from SCDC, starting at a given offset.
- Returns:
- The number of bytes read from SCDC or a negative error
code on failure.
- */
+ssize_t drm_scdc_read(struct i2c_adapter *adapter, u8 offset, void *buffer,
size_t size)
+{
- struct i2c_msg msgs[2] = {
{
.addr = SCDC_I2C_SLAVE_ADDRESS,
.flags = 0,
.len = 1,
.len = sizeof(offset) ?
Technically correct, but wouldn't that mean that we are expecting to have I2C offsets with length more than one byte ?
I just commented this because it would be more consistent but indeed you are correct. You can disregard my comment :)
Best regards, Jose Miguel Abreu
Thanks, is everything else works for you, would you mind a r-b ? - Shashank
.buf = &offset,
}, {
.addr = SCDC_I2C_SLAVE_ADDRESS,
.flags = I2C_M_RD,
.len = size,
.buf = buffer,
}
- };
- return i2c_transfer(adapter, msgs, ARRAY_SIZE(msgs));
+} +EXPORT_SYMBOL(drm_scdc_read);
+/**
- drm_scdc_write - write a block of data to SCDC
- @adapter: I2C controller
- @offset: start offset of block to write
- @buffer: block of data to write
- @size: size of the block to write
- Writes a block of data to SCDC, starting at a given offset.
- Returns:
- The number of bytes written to SCDC or a negative error
code on failure.
- */
+ssize_t drm_scdc_write(struct i2c_adapter *adapter, u8 offset,
const void *buffer, size_t size)
+{
- struct i2c_msg msg = {
.addr = SCDC_I2C_SLAVE_ADDRESS,
.flags = 0,
.len = 1 + size,
.len = sizeof(offset) + size ?
Same as above.
.buf = NULL,
- };
- void *data;
- int err;
- data = kmalloc(1 + size, GFP_TEMPORARY);
Same as above.
So on ...
- if (!data)
return -ENOMEM;
- msg.buf = data;
- memcpy(data, &offset, sizeof(offset));
- memcpy(data + 1, buffer, size);
Same as above.
So on ..
Best regards, Jose Miguel Abreu
- Shashank
- err = i2c_transfer(adapter, &msg, 1);
- kfree(data);
- return err;
+} +EXPORT_SYMBOL(drm_scdc_write); diff --git a/include/drm/drm_scdc_helper.h b/include/drm/drm_scdc_helper.h new file mode 100644 index 0000000..93b07bc --- /dev/null +++ b/include/drm/drm_scdc_helper.h @@ -0,0 +1,132 @@ +/*
- Copyright (c) 2015 NVIDIA Corporation. All rights reserved.
- Permission is hereby granted, free of charge, to any
person obtaining a
- copy of this software and associated documentation files
(the "Software"),
- to deal in the Software without restriction, including
without limitation
- the rights to use, copy, modify, merge, publish,
distribute, sub license,
- and/or sell copies of the Software, and to permit persons
to whom the
- Software is furnished to do so, subject to the following
conditions:
- The above copyright notice and this permission notice
(including the
- next paragraph) shall be included in all copies or
substantial portions
- of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN
NO EVENT SHALL
- THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING
- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER
- DEALINGS IN THE SOFTWARE.
- */
+#ifndef DRM_SCDC_HELPER_H +#define DRM_SCDC_HELPER_H
+#include <linux/i2c.h> +#include <linux/types.h>
+#define SCDC_SINK_VERSION 0x01
+#define SCDC_SOURCE_VERSION 0x02
+#define SCDC_UPDATE_0 0x10 +#define SCDC_READ_REQUEST_TEST (1 << 2) +#define SCDC_CED_UPDATE (1 << 1) +#define SCDC_STATUS_UPDATE (1 << 0)
+#define SCDC_UPDATE_1 0x11
+#define SCDC_TMDS_CONFIG 0x20 +#define SCDC_TMDS_BIT_CLOCK_RATIO_BY_40 (1 << 1) +#define SCDC_TMDS_BIT_CLOCK_RATIO_BY_10 (0 << 1) +#define SCDC_SCRAMBLING_ENABLE (1 << 0)
+#define SCDC_SCRAMBLER_STATUS 0x21 +#define SCDC_SCRAMBLING_STATUS (1 << 0)
+#define SCDC_CONFIG_0 0x30 +#define SCDC_READ_REQUEST_ENABLE (1 << 0)
+#define SCDC_STATUS_FLAGS_0 0x40 +#define SCDC_CH2_LOCK (1 < 3) +#define SCDC_CH1_LOCK (1 < 2) +#define SCDC_CH0_LOCK (1 < 1) +#define SCDC_CH_LOCK_MASK (SCDC_CH2_LOCK | SCDC_CH1_LOCK | SCDC_CH0_LOCK) +#define SCDC_CLOCK_DETECT (1 << 0)
+#define SCDC_STATUS_FLAGS_1 0x41
+#define SCDC_ERR_DET_0_L 0x50 +#define SCDC_ERR_DET_0_H 0x51 +#define SCDC_ERR_DET_1_L 0x52 +#define SCDC_ERR_DET_1_H 0x53 +#define SCDC_ERR_DET_2_L 0x54 +#define SCDC_ERR_DET_2_H 0x55 +#define SCDC_CHANNEL_VALID (1 << 7)
+#define SCDC_ERR_DET_CHECKSUM 0x56
+#define SCDC_TEST_CONFIG_0 0xc0 +#define SCDC_TEST_READ_REQUEST (1 << 7) +#define SCDC_TEST_READ_REQUEST_DELAY(x) ((x) & 0x7f)
+#define SCDC_MANUFACTURER_IEEE_OUI 0xd0 +#define SCDC_MANUFACTURER_IEEE_OUI_SIZE 3
+#define SCDC_DEVICE_ID 0xd3 +#define SCDC_DEVICE_ID_SIZE 8
+#define SCDC_DEVICE_HARDWARE_REVISION 0xdb +#define SCDC_DEVICE_HARDWARE_REVISION_MAJOR(x) (((x) >> 4) & 0xf) +#define SCDC_DEVICE_HARDWARE_REVISION_MINOR(x) (((x) >> 0) & 0xf)
+#define SCDC_DEVICE_SOFTWARE_MAJOR_REVISION 0xdc +#define SCDC_DEVICE_SOFTWARE_MINOR_REVISION 0xdd
+#define SCDC_MANUFACTURER_SPECIFIC 0xde +#define SCDC_MANUFACTURER_SPECIFIC_SIZE 34
+ssize_t drm_scdc_read(struct i2c_adapter *adapter, u8 offset, void *buffer,
size_t size);
+ssize_t drm_scdc_write(struct i2c_adapter *adapter, u8 offset,
const void *buffer, size_t size);
+/**
- drm_scdc_readb - read a single byte from SCDC
- @adapter: I2C adapter
- @offset: offset of register to read
- @value: return location for the register value
- Reads a single byte from SCDC. This is a convenience
wrapper around the
- drm_scdc_read() function.
- Returns:
- 0 on success or a negative error code on failure.
- */
+static inline int drm_scdc_readb(struct i2c_adapter *adapter, u8 offset,
u8 *value)
+{
- return drm_scdc_read(adapter, offset, value,
sizeof(*value)); +}
+/**
- drm_scdc_writeb - write a single byte to SCDC
- @adapter: I2C adapter
- @offset: offset of register to read
- @value: return location for the register value
- Writes a single byte to SCDC. This is a convenience
wrapper around the
- drm_scdc_write() function.
- Returns:
- 0 on success or a negative error code on failure.
- */
+static inline int drm_scdc_writeb(struct i2c_adapter *adapter, u8 offset,
u8 value)
+{
- return drm_scdc_write(adapter, offset, &value,
sizeof(value)); +}
+#endif
Hi Shashank,
On 08-02-2017 12:59, Sharma, Shashank wrote:
Regards
Shashank
On 2/8/2017 4:57 PM, Jose Abreu wrote:
Hi Shashank,
On 07-02-2017 16:09, Sharma, Shashank wrote:
Thanks for the review Jose, my comments inline.
Regards
Shashank
On 2/7/2017 4:24 PM, Jose Abreu wrote:
Hi Shashank,
Sorry for the late review.
On 06-02-2017 13:59, Shashank Sharma wrote:
From: Thierry Reding treding@nvidia.com
SCDC is a mechanism defined in the HDMI 2.0 specification that allows the source and sink devices to communicate.
This commit introduces helpers to access the SCDC and provides the symbolic names for the various registers defined in the specification.
Signed-off-by: Thierry Reding treding@nvidia.com Signed-off-by: Shashank Sharma shashank.sharma@intel.com
Documentation/gpu/drm-kms-helpers.rst | 12 ++++ drivers/gpu/drm/Makefile | 3 +- drivers/gpu/drm/drm_scdc_helper.c | 111 ++++++++++++++++++++++++++++ include/drm/drm_scdc_helper.h | 132 ++++++++++++++++++++++++++++++++++ 4 files changed, 257 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/drm_scdc_helper.c create mode 100644 include/drm/drm_scdc_helper.h
diff --git a/Documentation/gpu/drm-kms-helpers.rst b/Documentation/gpu/drm-kms-helpers.rst index 03040aa..7592756 100644 --- a/Documentation/gpu/drm-kms-helpers.rst +++ b/Documentation/gpu/drm-kms-helpers.rst @@ -217,6 +217,18 @@ EDID Helper Functions Reference .. kernel-doc:: drivers/gpu/drm/drm_edid.c :export: +SCDC Helper Functions Reference +===============================
+.. kernel-doc:: drivers/gpu/drm/drm_scdc_helper.c
- :doc: scdc helpers
+.. kernel-doc:: include/drm/drm_scdc_helper.h
- :internal:
+.. kernel-doc:: drivers/gpu/drm/drm_scdc_helper.c
- :export:
Rectangle Utilities Reference
diff --git a/drivers/gpu/drm/Makefileb/drivers/gpu/drm/Makefile index 92de399..ad91cd9 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -31,7 +31,8 @@ drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_probe_helper.o \ drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o \ drm_kms_helper_common.o drm_dp_dual_mode_helper.o \
drm_simple_kms_helper.o drm_modeset_helper.o
drm_simple_kms_helper.o drm_modeset_helper.o \
drm_kms_helper-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) +=drm_scdc_helper.o
drm_edid_load.o drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o diff --git a/drivers/gpu/drm/drm_scdc_helper.c b/drivers/gpu/drm/drm_scdc_helper.c new file mode 100644 index 0000000..fe0e121 --- /dev/null +++ b/drivers/gpu/drm/drm_scdc_helper.c @@ -0,0 +1,111 @@ +/*
- Copyright (c) 2015 NVIDIA Corporation. All rights
reserved.
- Permission is hereby granted, free of charge, to any
person obtaining a
- copy of this software and associated documentation files
(the "Software"),
- to deal in the Software without restriction, including
without limitation
- the rights to use, copy, modify, merge, publish,
distribute, sub license,
- and/or sell copies of the Software, and to permit persons
to whom the
- Software is furnished to do so, subject to the following
conditions:
- The above copyright notice and this permission notice
(including the
- next paragraph) shall be included in all copies or
substantial portions
- of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN
NO EVENT SHALL
- THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING
- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER
- DEALINGS IN THE SOFTWARE.
- */
+#include <linux/slab.h>
+#include <drm/drm_scdc_helper.h>
+/**
- DOC: scdc helpers
- Status and Control Data Channel (SCDC) is a mechanism
introduced by the
- HDMI 2.0 specification. It is a point-to-point protocol
that allows the
- HDMI source and HDMI sink to exchange data. The same I2C
interface that
- is used to access EDID serves as the transport mechanism
for SCDC.
- */
+#define SCDC_I2C_SLAVE_ADDRESS 0x54
+/**
- drm_scdc_read - read a block of data from SCDC
- @adapter: I2C controller
- @offset: start offset of block to read
- @buffer: return location for the block to read
- @size: size of the block to read
- Reads a block of data from SCDC, starting at a given
offset.
- Returns:
- The number of bytes read from SCDC or a negative error
code on failure.
- */
+ssize_t drm_scdc_read(struct i2c_adapter *adapter, u8 offset, void *buffer,
size_t size)
+{
- struct i2c_msg msgs[2] = {
{
.addr = SCDC_I2C_SLAVE_ADDRESS,
.flags = 0,
.len = 1,
.len = sizeof(offset) ?
Technically correct, but wouldn't that mean that we are expecting to have I2C offsets with length more than one byte ?
I just commented this because it would be more consistent but indeed you are correct. You can disregard my comment :)
Best regards, Jose Miguel Abreu
Thanks, is everything else works for you, would you mind a r-b ?
- Shashank
Sure, everything looks nice by me. Maybe wait for more comments.
You can add: Reviewed-by: Jose Abreu joabreu@synopsys.com
Best regards, Jose Miguel Abreu
.buf = &offset,
}, {
.addr = SCDC_I2C_SLAVE_ADDRESS,
.flags = I2C_M_RD,
.len = size,
.buf = buffer,
}
- };
- return i2c_transfer(adapter, msgs, ARRAY_SIZE(msgs));
+} +EXPORT_SYMBOL(drm_scdc_read);
+/**
- drm_scdc_write - write a block of data to SCDC
- @adapter: I2C controller
- @offset: start offset of block to write
- @buffer: block of data to write
- @size: size of the block to write
- Writes a block of data to SCDC, starting at a given
offset.
- Returns:
- The number of bytes written to SCDC or a negative error
code on failure.
- */
+ssize_t drm_scdc_write(struct i2c_adapter *adapter, u8 offset,
const void *buffer, size_t size)
+{
- struct i2c_msg msg = {
.addr = SCDC_I2C_SLAVE_ADDRESS,
.flags = 0,
.len = 1 + size,
.len = sizeof(offset) + size ?
Same as above.
.buf = NULL,
- };
- void *data;
- int err;
- data = kmalloc(1 + size, GFP_TEMPORARY);
Same as above.
So on ...
- if (!data)
return -ENOMEM;
- msg.buf = data;
- memcpy(data, &offset, sizeof(offset));
- memcpy(data + 1, buffer, size);
Same as above.
So on ..
Best regards, Jose Miguel Abreu
- Shashank
- err = i2c_transfer(adapter, &msg, 1);
- kfree(data);
- return err;
+} +EXPORT_SYMBOL(drm_scdc_write); diff --git a/include/drm/drm_scdc_helper.h b/include/drm/drm_scdc_helper.h new file mode 100644 index 0000000..93b07bc --- /dev/null +++ b/include/drm/drm_scdc_helper.h @@ -0,0 +1,132 @@ +/*
- Copyright (c) 2015 NVIDIA Corporation. All rights
reserved.
- Permission is hereby granted, free of charge, to any
person obtaining a
- copy of this software and associated documentation files
(the "Software"),
- to deal in the Software without restriction, including
without limitation
- the rights to use, copy, modify, merge, publish,
distribute, sub license,
- and/or sell copies of the Software, and to permit persons
to whom the
- Software is furnished to do so, subject to the following
conditions:
- The above copyright notice and this permission notice
(including the
- next paragraph) shall be included in all copies or
substantial portions
- of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN
NO EVENT SHALL
- THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING
- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER
- DEALINGS IN THE SOFTWARE.
- */
+#ifndef DRM_SCDC_HELPER_H +#define DRM_SCDC_HELPER_H
+#include <linux/i2c.h> +#include <linux/types.h>
+#define SCDC_SINK_VERSION 0x01
+#define SCDC_SOURCE_VERSION 0x02
+#define SCDC_UPDATE_0 0x10 +#define SCDC_READ_REQUEST_TEST (1 << 2) +#define SCDC_CED_UPDATE (1 << 1) +#define SCDC_STATUS_UPDATE (1 << 0)
+#define SCDC_UPDATE_1 0x11
+#define SCDC_TMDS_CONFIG 0x20 +#define SCDC_TMDS_BIT_CLOCK_RATIO_BY_40 (1 << 1) +#define SCDC_TMDS_BIT_CLOCK_RATIO_BY_10 (0 << 1) +#define SCDC_SCRAMBLING_ENABLE (1 << 0)
+#define SCDC_SCRAMBLER_STATUS 0x21 +#define SCDC_SCRAMBLING_STATUS (1 << 0)
+#define SCDC_CONFIG_0 0x30 +#define SCDC_READ_REQUEST_ENABLE (1 << 0)
+#define SCDC_STATUS_FLAGS_0 0x40 +#define SCDC_CH2_LOCK (1 < 3) +#define SCDC_CH1_LOCK (1 < 2) +#define SCDC_CH0_LOCK (1 < 1) +#define SCDC_CH_LOCK_MASK (SCDC_CH2_LOCK | SCDC_CH1_LOCK | SCDC_CH0_LOCK) +#define SCDC_CLOCK_DETECT (1 << 0)
+#define SCDC_STATUS_FLAGS_1 0x41
+#define SCDC_ERR_DET_0_L 0x50 +#define SCDC_ERR_DET_0_H 0x51 +#define SCDC_ERR_DET_1_L 0x52 +#define SCDC_ERR_DET_1_H 0x53 +#define SCDC_ERR_DET_2_L 0x54 +#define SCDC_ERR_DET_2_H 0x55 +#define SCDC_CHANNEL_VALID (1 << 7)
+#define SCDC_ERR_DET_CHECKSUM 0x56
+#define SCDC_TEST_CONFIG_0 0xc0 +#define SCDC_TEST_READ_REQUEST (1 << 7) +#define SCDC_TEST_READ_REQUEST_DELAY(x) ((x) & 0x7f)
+#define SCDC_MANUFACTURER_IEEE_OUI 0xd0 +#define SCDC_MANUFACTURER_IEEE_OUI_SIZE 3
+#define SCDC_DEVICE_ID 0xd3 +#define SCDC_DEVICE_ID_SIZE 8
+#define SCDC_DEVICE_HARDWARE_REVISION 0xdb +#define SCDC_DEVICE_HARDWARE_REVISION_MAJOR(x) (((x) >> 4) & 0xf) +#define SCDC_DEVICE_HARDWARE_REVISION_MINOR(x) (((x) >> 0) & 0xf)
+#define SCDC_DEVICE_SOFTWARE_MAJOR_REVISION 0xdc +#define SCDC_DEVICE_SOFTWARE_MINOR_REVISION 0xdd
+#define SCDC_MANUFACTURER_SPECIFIC 0xde +#define SCDC_MANUFACTURER_SPECIFIC_SIZE 34
+ssize_t drm_scdc_read(struct i2c_adapter *adapter, u8 offset, void *buffer,
size_t size);
+ssize_t drm_scdc_write(struct i2c_adapter *adapter, u8 offset,
const void *buffer, size_t size);
+/**
- drm_scdc_readb - read a single byte from SCDC
- @adapter: I2C adapter
- @offset: offset of register to read
- @value: return location for the register value
- Reads a single byte from SCDC. This is a convenience
wrapper around the
- drm_scdc_read() function.
- Returns:
- 0 on success or a negative error code on failure.
- */
+static inline int drm_scdc_readb(struct i2c_adapter *adapter, u8 offset,
u8 *value)
+{
- return drm_scdc_read(adapter, offset, value,
sizeof(*value)); +}
+/**
- drm_scdc_writeb - write a single byte to SCDC
- @adapter: I2C adapter
- @offset: offset of register to read
- @value: return location for the register value
- Writes a single byte to SCDC. This is a convenience
wrapper around the
- drm_scdc_write() function.
- Returns:
- 0 on success or a negative error code on failure.
- */
+static inline int drm_scdc_writeb(struct i2c_adapter *adapter, u8 offset,
u8 value)
+{
- return drm_scdc_write(adapter, offset, &value,
sizeof(value)); +}
+#endif
From: Thierry Reding treding@nvidia.com
This patch implements a small function that finds if a given CEA db is hdmi-forum vendor specific data block or not.
Signed-off-by: Thierry Reding treding@nvidia.com Signed-off-by: Shashank Sharma shashank.sharma@intel.com --- drivers/gpu/drm/drm_edid.c | 15 +++++++++++++++ include/linux/hdmi.h | 1 + 2 files changed, 16 insertions(+)
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index baa6ccb..96d3e47 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3239,6 +3239,21 @@ static bool cea_db_is_hdmi_vsdb(const u8 *db) return hdmi_id == HDMI_IEEE_OUI; }
+static bool cea_db_is_hdmi_forum_vsdb(const u8 *db) +{ + unsigned int oui; + + if (cea_db_tag(db) != VENDOR_BLOCK) + return false; + + if (cea_db_payload_len(db) < 7) + return false; + + oui = db[3] << 16 | db[2] << 8 | db[1]; + + return oui == HDMI_FORUM_IEEE_OUI; +} + #define for_each_cea_db(cea, i, start, end) \ for ((i) = (start); (i) < (end) && (i) + cea_db_payload_len(&(cea)[(i)]) < (end); (i) += cea_db_payload_len(&(cea)[(i)]) + 1)
diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h index edbb4fc..d271ff2 100644 --- a/include/linux/hdmi.h +++ b/include/linux/hdmi.h @@ -35,6 +35,7 @@ enum hdmi_infoframe_type { };
#define HDMI_IEEE_OUI 0x000c03 +#define HDMI_FORUM_IEEE_OUI 0xc45dd8 #define HDMI_INFOFRAME_HEADER_SIZE 4 #define HDMI_AVI_INFOFRAME_SIZE 13 #define HDMI_SPD_INFOFRAME_SIZE 25
Hi Shashank,
On 06-02-2017 13:59, Shashank Sharma wrote:
From: Thierry Reding treding@nvidia.com
This patch implements a small function that finds if a given CEA db is hdmi-forum vendor specific data block or not.
Signed-off-by: Thierry Reding treding@nvidia.com Signed-off-by: Shashank Sharma shashank.sharma@intel.com
Reviewed-by: Jose Abreu joabreu@synopsys.com
Best regards, Jose Miguel Abreu
drivers/gpu/drm/drm_edid.c | 15 +++++++++++++++ include/linux/hdmi.h | 1 + 2 files changed, 16 insertions(+)
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index baa6ccb..96d3e47 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3239,6 +3239,21 @@ static bool cea_db_is_hdmi_vsdb(const u8 *db) return hdmi_id == HDMI_IEEE_OUI; }
+static bool cea_db_is_hdmi_forum_vsdb(const u8 *db) +{
- unsigned int oui;
- if (cea_db_tag(db) != VENDOR_BLOCK)
return false;
- if (cea_db_payload_len(db) < 7)
return false;
- oui = db[3] << 16 | db[2] << 8 | db[1];
- return oui == HDMI_FORUM_IEEE_OUI;
+}
#define for_each_cea_db(cea, i, start, end) \ for ((i) = (start); (i) < (end) && (i) + cea_db_payload_len(&(cea)[(i)]) < (end); (i) += cea_db_payload_len(&(cea)[(i)]) + 1)
diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h index edbb4fc..d271ff2 100644 --- a/include/linux/hdmi.h +++ b/include/linux/hdmi.h @@ -35,6 +35,7 @@ enum hdmi_infoframe_type { };
#define HDMI_IEEE_OUI 0x000c03 +#define HDMI_FORUM_IEEE_OUI 0xc45dd8 #define HDMI_INFOFRAME_HEADER_SIZE 4 #define HDMI_AVI_INFOFRAME_SIZE 13 #define HDMI_SPD_INFOFRAME_SIZE 25
This patch does following: - Adds a new structure (drm_hdmi_info) in drm_display_info. This structure will be used to save and indicate if sink supports advanced HDMI 2.0 features - Adds another structure drm_scdc within drm_hdmi_info, to reflect scdc support and capabilities in connected HDMI 2.0 sink. - Checks the HF-VSDB block for presence of SCDC, and marks it in scdc structure - If SCDC is present, checks if sink is capable of generating SCDC read request, and marks it in scdc structure.
V2: Addressed review comments Thierry: - Fix typos in commit message and make abbreviation consistent across the commit message. - Change structure object name from hdmi_info -> hdmi - Fix typos and abbreviations in description of structure drm_hdmi_info end the description with a full stop. - Create a structure drm_scdc, and keep all information related to SCDC register set (supported, read request supported) etc in it.
Ville: - Change rr -> read_request - Call drm_detect_scrambling function drm_parse_hf_vsdb so that all of HF-VSDB parsing can be kept in same function, in incremental patches.
Reviewed-by: Thierry Reding treding@nvidia.com Signed-off-by: Shashank Sharma shashank.sharma@intel.com --- drivers/gpu/drm/drm_edid.c | 14 ++++++++++++++ include/drm/drm_connector.h | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+)
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 96d3e47..a487b80 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3802,6 +3802,18 @@ enum hdmi_quantization_range } EXPORT_SYMBOL(drm_default_rgb_quant_range);
+static void drm_parse_hdmi_forum_vsdb(struct drm_connector *connector, + const u8 *hf_vsdb) +{ + struct drm_hdmi_info *hdmi = &connector->display_info.hdmi; + + if (hf_vsdb[6] & 0x80) { + hdmi->scdc.supported = true; + if (hf_vsdb[6] & 0x40) + hdmi->scdc.read_request = true; + } +} + static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector, const u8 *hdmi) { @@ -3916,6 +3928,8 @@ static void drm_parse_cea_ext(struct drm_connector *connector,
if (cea_db_is_hdmi_vsdb(db)) drm_parse_hdmi_vsdb_video(connector, db); + if (cea_db_is_hdmi_forum_vsdb(db)) + drm_parse_hdmi_forum_vsdb(connector, db); } }
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index e5e1edd..6d5304e 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -87,6 +87,34 @@ enum subpixel_order { SubPixelVerticalRGB, SubPixelVerticalBGR, SubPixelNone, + +}; + +/* + * struct drm_scdc - Information about scdc capabilities of a HDMI 2.0 sink + * + * Provides SCDC register support and capabilities related information on a + * HDMI 2.0 sink. In case of a HDMI 1.4 sink, all parameter must be 0. + */ +struct drm_scdc { + /** + * @supported: status control & data channel present. + */ + bool supported; + /** + * @read_request: sink is capable of generating scdc read request. + */ + bool read_request; +}; + +/** + * struct drm_hdmi_info - runtime information about the connected HDMI sink + * + * Describes if a given display supports advanced HDMI 2.0 features. + * This information is available in CEA-861-F extension blocks (like HF-VSDB). + */ +struct drm_hdmi_info { + struct drm_scdc scdc; };
/** @@ -188,6 +216,11 @@ struct drm_display_info { * @cea_rev: CEA revision of the HDMI sink. */ u8 cea_rev; + + /** + * @hdmi: advance features of a HDMI sink. + */ + struct drm_hdmi_info hdmi; };
int drm_display_info_set_bus_formats(struct drm_display_info *info,
Hi Shashank,
On 06-02-2017 13:59, Shashank Sharma wrote:
This patch does following:
- Adds a new structure (drm_hdmi_info) in drm_display_info. This structure will be used to save and indicate if sink supports advanced HDMI 2.0 features
- Adds another structure drm_scdc within drm_hdmi_info, to reflect scdc support and capabilities in connected HDMI 2.0 sink.
- Checks the HF-VSDB block for presence of SCDC, and marks it in scdc structure
- If SCDC is present, checks if sink is capable of generating SCDC read request, and marks it in scdc structure.
V2: Addressed review comments Thierry:
- Fix typos in commit message and make abbreviation consistent across the commit message.
- Change structure object name from hdmi_info -> hdmi
- Fix typos and abbreviations in description of structure drm_hdmi_info end the description with a full stop.
- Create a structure drm_scdc, and keep all information related to SCDC register set (supported, read request supported) etc in it.
Ville:
- Change rr -> read_request
- Call drm_detect_scrambling function drm_parse_hf_vsdb so that all of HF-VSDB parsing can be kept in same function, in incremental patches.
Reviewed-by: Thierry Reding treding@nvidia.com Signed-off-by: Shashank Sharma shashank.sharma@intel.com
drivers/gpu/drm/drm_edid.c | 14 ++++++++++++++ include/drm/drm_connector.h | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+)
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 96d3e47..a487b80 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3802,6 +3802,18 @@ enum hdmi_quantization_range } EXPORT_SYMBOL(drm_default_rgb_quant_range);
+static void drm_parse_hdmi_forum_vsdb(struct drm_connector *connector,
const u8 *hf_vsdb)
+{
- struct drm_hdmi_info *hdmi = &connector->display_info.hdmi;
- if (hf_vsdb[6] & 0x80) {
BIT(7) ?
hdmi->scdc.supported = true;
if (hf_vsdb[6] & 0x40)
BIT(6) ?
hdmi->scdc.read_request = true;
- }
+}
static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector, const u8 *hdmi) { @@ -3916,6 +3928,8 @@ static void drm_parse_cea_ext(struct drm_connector *connector,
if (cea_db_is_hdmi_vsdb(db)) drm_parse_hdmi_vsdb_video(connector, db);
if (cea_db_is_hdmi_forum_vsdb(db))
}drm_parse_hdmi_forum_vsdb(connector, db);
}
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index e5e1edd..6d5304e 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -87,6 +87,34 @@ enum subpixel_order { SubPixelVerticalRGB, SubPixelVerticalBGR, SubPixelNone,
+};
+/*
- struct drm_scdc - Information about scdc capabilities of a HDMI 2.0 sink
- Provides SCDC register support and capabilities related information on a
- HDMI 2.0 sink. In case of a HDMI 1.4 sink, all parameter must be 0.
- */
+struct drm_scdc {
- /**
* @supported: status control & data channel present.
*/
- bool supported;
- /**
* @read_request: sink is capable of generating scdc read request.
*/
- bool read_request;
+};
+/**
- struct drm_hdmi_info - runtime information about the connected HDMI sink
- Describes if a given display supports advanced HDMI 2.0 features.
- This information is available in CEA-861-F extension blocks (like HF-VSDB).
- */
+struct drm_hdmi_info {
- struct drm_scdc scdc;
};
/** @@ -188,6 +216,11 @@ struct drm_display_info { * @cea_rev: CEA revision of the HDMI sink. */ u8 cea_rev;
- /**
* @hdmi: advance features of a HDMI sink.
Maybe change to the same general description you used above: "Runtime information about the connected HDMI sink" ?
*/
- struct drm_hdmi_info hdmi;
};
int drm_display_info_set_bus_formats(struct drm_display_info *info,
Best regards, Jose Miguel Abreu
Regards
Shashank
On 2/7/2017 4:31 PM, Jose Abreu wrote:
Hi Shashank,
On 06-02-2017 13:59, Shashank Sharma wrote:
This patch does following:
- Adds a new structure (drm_hdmi_info) in drm_display_info. This structure will be used to save and indicate if sink supports advanced HDMI 2.0 features
- Adds another structure drm_scdc within drm_hdmi_info, to reflect scdc support and capabilities in connected HDMI 2.0 sink.
- Checks the HF-VSDB block for presence of SCDC, and marks it in scdc structure
- If SCDC is present, checks if sink is capable of generating SCDC read request, and marks it in scdc structure.
V2: Addressed review comments Thierry:
- Fix typos in commit message and make abbreviation consistent across the commit message.
- Change structure object name from hdmi_info -> hdmi
- Fix typos and abbreviations in description of structure drm_hdmi_info end the description with a full stop.
- Create a structure drm_scdc, and keep all information related to SCDC register set (supported, read request supported) etc in it.
Ville:
- Change rr -> read_request
- Call drm_detect_scrambling function drm_parse_hf_vsdb so that all of HF-VSDB parsing can be kept in same function, in incremental patches.
Reviewed-by: Thierry Reding treding@nvidia.com Signed-off-by: Shashank Sharma shashank.sharma@intel.com
drivers/gpu/drm/drm_edid.c | 14 ++++++++++++++ include/drm/drm_connector.h | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+)
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 96d3e47..a487b80 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3802,6 +3802,18 @@ enum hdmi_quantization_range } EXPORT_SYMBOL(drm_default_rgb_quant_range);
+static void drm_parse_hdmi_forum_vsdb(struct drm_connector *connector,
const u8 *hf_vsdb)
+{
- struct drm_hdmi_info *hdmi = &connector->display_info.hdmi;
- if (hf_vsdb[6] & 0x80) {
BIT(7) ?
Yes, SCDC_present bit is bit 7, byte 6 in HF-VSDB. Am I missing something ?
hdmi->scdc.supported = true;
if (hf_vsdb[6] & 0x40)
BIT(6) ?
Yes, RR_Capable bit is bit 6, byte 6 in HF-VSDB.
hdmi->scdc.read_request = true;
- }
+}
- static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector, const u8 *hdmi) {
@@ -3916,6 +3928,8 @@ static void drm_parse_cea_ext(struct drm_connector *connector,
if (cea_db_is_hdmi_vsdb(db)) drm_parse_hdmi_vsdb_video(connector, db);
if (cea_db_is_hdmi_forum_vsdb(db))
} }drm_parse_hdmi_forum_vsdb(connector, db);
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index e5e1edd..6d5304e 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -87,6 +87,34 @@ enum subpixel_order { SubPixelVerticalRGB, SubPixelVerticalBGR, SubPixelNone,
+};
+/*
- struct drm_scdc - Information about scdc capabilities of a HDMI 2.0 sink
- Provides SCDC register support and capabilities related information on a
- HDMI 2.0 sink. In case of a HDMI 1.4 sink, all parameter must be 0.
- */
+struct drm_scdc {
- /**
* @supported: status control & data channel present.
*/
- bool supported;
- /**
* @read_request: sink is capable of generating scdc read request.
*/
- bool read_request;
+};
+/**
- struct drm_hdmi_info - runtime information about the connected HDMI sink
- Describes if a given display supports advanced HDMI 2.0 features.
- This information is available in CEA-861-F extension blocks (like HF-VSDB).
- */
+struct drm_hdmi_info {
struct drm_scdc scdc; };
/**
@@ -188,6 +216,11 @@ struct drm_display_info { * @cea_rev: CEA revision of the HDMI sink. */ u8 cea_rev;
- /**
* @hdmi: advance features of a HDMI sink.
Maybe change to the same general description you used above: "Runtime information about the connected HDMI sink" ?
Actually the description I used in patch set 1, was similar, but this is based on feedbacks from review set 1. - Shashank
*/
struct drm_hdmi_info hdmi; };
int drm_display_info_set_bus_formats(struct drm_display_info *info,
Best regards, Jose Miguel Abreu
On Tue, Feb 07, 2017 at 09:43:15PM +0530, Sharma, Shashank wrote:
Regards
Shashank
On 2/7/2017 4:31 PM, Jose Abreu wrote:
Hi Shashank,
On 06-02-2017 13:59, Shashank Sharma wrote:
This patch does following:
- Adds a new structure (drm_hdmi_info) in drm_display_info. This structure will be used to save and indicate if sink supports advanced HDMI 2.0 features
- Adds another structure drm_scdc within drm_hdmi_info, to reflect scdc support and capabilities in connected HDMI 2.0 sink.
- Checks the HF-VSDB block for presence of SCDC, and marks it in scdc structure
- If SCDC is present, checks if sink is capable of generating SCDC read request, and marks it in scdc structure.
V2: Addressed review comments Thierry:
- Fix typos in commit message and make abbreviation consistent across the commit message.
- Change structure object name from hdmi_info -> hdmi
- Fix typos and abbreviations in description of structure drm_hdmi_info end the description with a full stop.
- Create a structure drm_scdc, and keep all information related to SCDC register set (supported, read request supported) etc in it.
Ville:
- Change rr -> read_request
- Call drm_detect_scrambling function drm_parse_hf_vsdb so that all of HF-VSDB parsing can be kept in same function, in incremental patches.
Reviewed-by: Thierry Reding treding@nvidia.com Signed-off-by: Shashank Sharma shashank.sharma@intel.com
drivers/gpu/drm/drm_edid.c | 14 ++++++++++++++ include/drm/drm_connector.h | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+)
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 96d3e47..a487b80 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3802,6 +3802,18 @@ enum hdmi_quantization_range } EXPORT_SYMBOL(drm_default_rgb_quant_range); +static void drm_parse_hdmi_forum_vsdb(struct drm_connector *connector,
const u8 *hf_vsdb)
+{
- struct drm_hdmi_info *hdmi = &connector->display_info.hdmi;
- if (hf_vsdb[6] & 0x80) {
BIT(7) ?
Yes, SCDC_present bit is bit 7, byte 6 in HF-VSDB. Am I missing something ?
hdmi->scdc.supported = true;
if (hf_vsdb[6] & 0x40)
BIT(6) ?
Yes, RR_Capable bit is bit 6, byte 6 in HF-VSDB.
I think what Jose was trying to say is that you should be using BIT(7) instead of 0x80 and BIT(6) instead of 0x40. That said, I think either is fine, but perhaps another idea would be to define macros for these. I know that most (all?) of the EDID parsing code uses literals, so this is consistent with existing code. Also usually code will be like:
if (hf_vsdb[X] & 0xYZ) foo_supported = true;
So the meaning of the bit is easy to read from the context. I think literals are fine in this case.
Thierry
Hi,
On 07-02-2017 16:36, Thierry Reding wrote:
On Tue, Feb 07, 2017 at 09:43:15PM +0530, Sharma, Shashank wrote:
Regards
Shashank
On 2/7/2017 4:31 PM, Jose Abreu wrote:
Hi Shashank,
On 06-02-2017 13:59, Shashank Sharma wrote:
This patch does following:
- Adds a new structure (drm_hdmi_info) in drm_display_info. This structure will be used to save and indicate if sink supports advanced HDMI 2.0 features
- Adds another structure drm_scdc within drm_hdmi_info, to reflect scdc support and capabilities in connected HDMI 2.0 sink.
- Checks the HF-VSDB block for presence of SCDC, and marks it in scdc structure
- If SCDC is present, checks if sink is capable of generating SCDC read request, and marks it in scdc structure.
V2: Addressed review comments Thierry:
- Fix typos in commit message and make abbreviation consistent across the commit message.
- Change structure object name from hdmi_info -> hdmi
- Fix typos and abbreviations in description of structure drm_hdmi_info end the description with a full stop.
- Create a structure drm_scdc, and keep all information related to SCDC register set (supported, read request supported) etc in it.
Ville:
- Change rr -> read_request
- Call drm_detect_scrambling function drm_parse_hf_vsdb so that all of HF-VSDB parsing can be kept in same function, in incremental patches.
Reviewed-by: Thierry Reding treding@nvidia.com Signed-off-by: Shashank Sharma shashank.sharma@intel.com
drivers/gpu/drm/drm_edid.c | 14 ++++++++++++++ include/drm/drm_connector.h | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+)
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 96d3e47..a487b80 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3802,6 +3802,18 @@ enum hdmi_quantization_range } EXPORT_SYMBOL(drm_default_rgb_quant_range); +static void drm_parse_hdmi_forum_vsdb(struct drm_connector *connector,
const u8 *hf_vsdb)
+{
- struct drm_hdmi_info *hdmi = &connector->display_info.hdmi;
- if (hf_vsdb[6] & 0x80) {
BIT(7) ?
Yes, SCDC_present bit is bit 7, byte 6 in HF-VSDB. Am I missing something ?
hdmi->scdc.supported = true;
if (hf_vsdb[6] & 0x40)
BIT(6) ?
Yes, RR_Capable bit is bit 6, byte 6 in HF-VSDB.
I think what Jose was trying to say is that you should be using BIT(7) instead of 0x80 and BIT(6) instead of 0x40. That said, I think either is fine, but perhaps another idea would be to define macros for these. I know that most (all?) of the EDID parsing code uses literals, so this is consistent with existing code. Also usually code will be like:
if (hf_vsdb[X] & 0xYZ) foo_supported = true;
So the meaning of the bit is easy to read from the context. I think literals are fine in this case.
Thierry
Thats exactly what I meant :) I think with BIT(x) the code is easier to read (my hex skills are not very good :)). Anyway, if the remaining code uses literals then maybe its better to keep consistency.
Best regards, Jose Miguel Abreu
Regards
Shashank
On 2/8/2017 5:06 PM, Jose Abreu wrote:
Hi,
On 07-02-2017 16:36, Thierry Reding wrote:
On Tue, Feb 07, 2017 at 09:43:15PM +0530, Sharma, Shashank wrote:
Regards
Shashank
On 2/7/2017 4:31 PM, Jose Abreu wrote:
Hi Shashank,
On 06-02-2017 13:59, Shashank Sharma wrote:
This patch does following:
- Adds a new structure (drm_hdmi_info) in drm_display_info. This structure will be used to save and indicate if sink supports advanced HDMI 2.0 features
- Adds another structure drm_scdc within drm_hdmi_info, to reflect scdc support and capabilities in connected HDMI 2.0 sink.
- Checks the HF-VSDB block for presence of SCDC, and marks it in scdc structure
- If SCDC is present, checks if sink is capable of generating SCDC read request, and marks it in scdc structure.
V2: Addressed review comments Thierry:
- Fix typos in commit message and make abbreviation consistent across the commit message.
- Change structure object name from hdmi_info -> hdmi
- Fix typos and abbreviations in description of structure drm_hdmi_info end the description with a full stop.
- Create a structure drm_scdc, and keep all information related to SCDC register set (supported, read request supported) etc in it.
Ville:
- Change rr -> read_request
- Call drm_detect_scrambling function drm_parse_hf_vsdb so that all of HF-VSDB parsing can be kept in same function, in incremental patches.
Reviewed-by: Thierry Reding treding@nvidia.com Signed-off-by: Shashank Sharma shashank.sharma@intel.com
drivers/gpu/drm/drm_edid.c | 14 ++++++++++++++ include/drm/drm_connector.h | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+)
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 96d3e47..a487b80 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3802,6 +3802,18 @@ enum hdmi_quantization_range } EXPORT_SYMBOL(drm_default_rgb_quant_range); +static void drm_parse_hdmi_forum_vsdb(struct drm_connector *connector,
const u8 *hf_vsdb)
+{
- struct drm_hdmi_info *hdmi = &connector->display_info.hdmi;
- if (hf_vsdb[6] & 0x80) {
BIT(7) ?
Yes, SCDC_present bit is bit 7, byte 6 in HF-VSDB. Am I missing something ?
hdmi->scdc.supported = true;
if (hf_vsdb[6] & 0x40)
BIT(6) ?
Yes, RR_Capable bit is bit 6, byte 6 in HF-VSDB.
I think what Jose was trying to say is that you should be using BIT(7) instead of 0x80 and BIT(6) instead of 0x40. That said, I think either is fine, but perhaps another idea would be to define macros for these. I know that most (all?) of the EDID parsing code uses literals, so this is consistent with existing code. Also usually code will be like:
if (hf_vsdb[X] & 0xYZ) foo_supported = true;
So the meaning of the bit is easy to read from the context. I think literals are fine in this case.
Thierry
Thats exactly what I meant :) I think with BIT(x) the code is easier to read (my hex skills are not very good :)). Anyway, if the remaining code uses literals then maybe its better to keep consistency.
Thanks, then we will keep this code, as it is. - Shashank
Best regards, Jose Miguel Abreu
HDMI 2.0 spec mandates scrambling for modes with pixel clock higher than 340 MHz. This patch adds few new functions in drm layer for core drivers to enable/disable scrambling.
This patch adds: - A function to detect scrambling support parsing HF-VSDB - A function to check scrambling status runtime using SCDC read. - Two functions to enable/disable scrambling using SCDC read/write. - Few new bools to reflect scrambling support and status.
V2: Addressed review comments from Thierry, Ville and Dhinakaran Thierry: - Mhz -> MHz in comments and commit message. - i2c -> I2C in comments. - Fix the function documentations, keep in sync with drm_scdc_helper.c - drm_connector -> DRM connector. - Create structure for SCDC, and save scrambling status inside that, in a sub-structure. - Call this sub-structure scrambling instead of scr_info. - low_rates -> low_clocks in scrambling status structure. - Store the return value of I2C read/write and print the error code in case of failure.
Thierry and Ville: - Move the scrambling enable/disable/query functions in drm_scdc_helper.c file. - Add drm_SCDC prefix for the functions. - Optimize the return statement from function drm_SCDC_check_scrambling_status.
Ville: - Dont overwrite saved max TMDS clock value in display_info, if max tmds clock from HF-VSDB is not > 340 MHz. - drm_detect_hdmi_scrambling -> drm_parse_hdmi_forum_vsdb. - Remove dynamic tracking of SCDC status from DRM layer, force bool. - Program clock ratio bit also, while enabling scrambling.
Dhinakaran: - Add a comment about *5000 while extracting max clock supported.
Signed-off-by: Shashank Sharma shashank.sharma@intel.com --- drivers/gpu/drm/drm_edid.c | 33 ++++++++++++- drivers/gpu/drm/drm_scdc_helper.c | 100 ++++++++++++++++++++++++++++++++++++++ include/drm/drm_connector.h | 19 ++++++++ include/drm/drm_edid.h | 6 ++- include/drm/drm_scdc_helper.h | 20 ++++++++ 5 files changed, 176 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index a487b80..dc85eb9 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -37,6 +37,7 @@ #include <drm/drm_edid.h> #include <drm/drm_encoder.h> #include <drm/drm_displayid.h> +#include <drm/drm_scdc_helper.h>
#define version_greater(edid, maj, min) \ (((edid)->version > (maj)) || \ @@ -3805,13 +3806,43 @@ enum hdmi_quantization_range static void drm_parse_hdmi_forum_vsdb(struct drm_connector *connector, const u8 *hf_vsdb) { - struct drm_hdmi_info *hdmi = &connector->display_info.hdmi; + struct drm_display_info *display = &connector->display_info; + struct drm_hdmi_info *hdmi = &display->hdmi;
if (hf_vsdb[6] & 0x80) { hdmi->scdc.supported = true; if (hf_vsdb[6] & 0x40) hdmi->scdc.read_request = true; } + + /* + * All HDMI 2.0 monitors must support scrambling at rates > 340 MHz. + * And as per the spec, three factors confirm this: + * * Availability of a HF-VSDB block in EDID (check) + * * Non zero Max_TMDS_Char_Rate filed in HF-VSDB (let's check) + * * SCDC support available (let's check) + * Lets check it out. + */ + + if (hf_vsdb[5]) { + /* max clock is 5000 KHz times block value */ + u32 max_tmds_clock = hf_vsdb[5] * 5000; + struct drm_scdc *scdc = &hdmi->scdc; + + if (max_tmds_clock > 340000) { + display->max_tmds_clock = max_tmds_clock; + DRM_DEBUG_KMS("HF-VSDB: max TMDS clock %d kHz\n", + display->max_tmds_clock); + } + + if (scdc->supported) { + scdc->scrambling.supported = true; + + /* Few sinks support scrambling for cloks < 340M */ + if ((hf_vsdb[6] & 0x8)) + scdc->scrambling.low_rates = true; + } + } }
static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector, diff --git a/drivers/gpu/drm/drm_scdc_helper.c b/drivers/gpu/drm/drm_scdc_helper.c index fe0e121..311f62e 100644 --- a/drivers/gpu/drm/drm_scdc_helper.c +++ b/drivers/gpu/drm/drm_scdc_helper.c @@ -22,8 +22,10 @@ */
#include <linux/slab.h> +#include <linux/delay.h>
#include <drm/drm_scdc_helper.h> +#include <drm/drmP.h>
/** * DOC: scdc helpers @@ -109,3 +111,101 @@ ssize_t drm_scdc_write(struct i2c_adapter *adapter, u8 offset, return err; } EXPORT_SYMBOL(drm_scdc_write); + +/** + * drm_scdc_check_scrambling_status - what is status of scrambling? + * @adapter: I2C adapter for DDC channel + * + * Reads the scrambler status over SCDC, and checks the + * scrambling status. + * + * Returns: + * True if the scrambling is enabled, false otherwise. + */ + +bool drm_scdc_check_scrambling_status(struct i2c_adapter *adapter) +{ + u8 status; + int ret; + + ret = drm_scdc_readb(adapter, SCDC_SCRAMBLER_STATUS, &status); + if (ret < 0) { + DRM_ERROR("Failed to read scrambling status, error %d\n", ret); + return false; + } + + return status & SCDC_SCRAMBLING_STATUS; +} +EXPORT_SYMBOL(drm_scdc_check_scrambling_status); + +/** + * drm_scdc_enable_scrambling - enable scrambling + * @adapter: I2C adapter for DDC channel + * + * Writes the TMDS config over SCDC channel, and enables scrambling + * Returns: + * True if scrambling is successfully enabled, false otherwise. + */ + +bool drm_scdc_enable_scrambling(struct i2c_adapter *adapter) +{ + u8 config; + int ret; + + ret = drm_scdc_readb(adapter, SCDC_TMDS_CONFIG, &config); + if (ret < 0) { + DRM_ERROR("Failed to read tmds config, err=%d\n", ret); + return false; + } + + config |= (SCDC_SCRAMBLING_ENABLE | SCDC_TMDS_BIT_CLOCK_RATIO_BY_40); + + ret = drm_scdc_writeb(adapter, SCDC_TMDS_CONFIG, config); + if (ret < 0) { + DRM_ERROR("Failed to enable scrambling, error %d\n", ret); + return false; + } + + /* + * The spec says that the source should wait min 1ms and max 100ms + * after writing the TMDS config for clock ratio. Lets obey the spec. + */ + usleep_range(1000, 100000); + return true; +} +EXPORT_SYMBOL(drm_scdc_enable_scrambling); + +/** + * drm_scdc_disable_scrambling - disable scrambling + * @adapter: I2C adapter for DDC channel + * + * Write the TMDS config over SCDC channel, and disable scrambling + * Return: True if scrambling is successfully disabled, false otherwise. + */ +bool drm_scdc_disable_scrambling(struct i2c_adapter *adapter) +{ + u8 config; + int ret; + + ret = drm_scdc_readb(adapter, SCDC_TMDS_CONFIG, &config); + if (ret < 0) { + DRM_ERROR("Failed to read tmds config, error %d\n", ret); + return false; + } + + config &= ~(SCDC_SCRAMBLING_ENABLE | SCDC_TMDS_BIT_CLOCK_RATIO_BY_40); + + ret = drm_scdc_writeb(adapter, SCDC_TMDS_CONFIG, config); + if (ret < 0) { + DRM_ERROR("Failed to enable scrambling, error %d\n", ret); + return false; + } + + /* + * The spec says that the source should wait min 1ms and max 100ms + * after writing the TMDS config for clock ratio. Lets obey the spec. + */ + usleep_range(1000, 100000); + return true; +} +EXPORT_SYMBOL(drm_scdc_disable_scrambling); diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 6d5304e..78618308 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -90,6 +90,20 @@ enum subpixel_order {
};
+/** + * struct drm_scrambling: sink's scrambling support. + */ +struct drm_scrambling { + /** + * @supported: scrambling supported for rates > 340 Mhz. + */ + bool supported; + /** + * @low_rates: scrambling supported for rates <= 340 Mhz. + */ + bool low_rates; +}; + /* * struct drm_scdc - Information about scdc capabilities of a HDMI 2.0 sink * @@ -105,8 +119,13 @@ struct drm_scdc { * @read_request: sink is capable of generating scdc read request. */ bool read_request; + /** + * @scrambling: sink's scrambling capabilities + */ + struct drm_scrambling scrambling; };
+ /** * struct drm_hdmi_info - runtime information about the connected HDMI sink * diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index 43fb0ac..d24c974 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -462,5 +462,9 @@ void drm_edid_get_monitor_name(struct edid *edid, char *name, struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev, int hsize, int vsize, int fresh, bool rb); - +bool drm_enable_scrambling(struct drm_connector *connector, + struct i2c_adapter *adapter, bool force); +bool drm_disable_scrambling(struct drm_connector *connector, + struct i2c_adapter *adapter, bool force); +bool drm_check_scrambling_status(struct i2c_adapter *adapter); #endif /* __DRM_EDID_H__ */ diff --git a/include/drm/drm_scdc_helper.h b/include/drm/drm_scdc_helper.h index 93b07bc..dc727a5 100644 --- a/include/drm/drm_scdc_helper.h +++ b/include/drm/drm_scdc_helper.h @@ -129,4 +129,24 @@ static inline int drm_scdc_writeb(struct i2c_adapter *adapter, u8 offset, return drm_scdc_write(adapter, offset, &value, sizeof(value)); }
+/** + * drm_scdc_enable_scrambling - enable scrambling + * @adapter: I2C adapter for DDC channel + * + * Writes the TMDS config over SCDC channel, and enables scrambling + * Returns: + * True if scrambling is successfully enabled, false otherwise. + */ + +bool drm_scdc_enable_scrambling(struct i2c_adapter *adapter); + +/** + * drm_scdc_disable_scrambling - disable scrambling + * @adapter: I2C adapter for DDC channel + * + * Write the TMDS config over SCDC channel, and disable scrambling + * Return: True if scrambling is successfully disabled, false otherwise. + */ +bool drm_scdc_disable_scrambling(struct i2c_adapter *adapter); + #endif
Hi Shashank,
On 06-02-2017 13:59, Shashank Sharma wrote:
HDMI 2.0 spec mandates scrambling for modes with pixel clock higher than 340 MHz. This patch adds few new functions in drm layer for core drivers to enable/disable scrambling.
This patch adds:
- A function to detect scrambling support parsing HF-VSDB
- A function to check scrambling status runtime using SCDC read.
- Two functions to enable/disable scrambling using SCDC read/write.
- Few new bools to reflect scrambling support and status.
V2: Addressed review comments from Thierry, Ville and Dhinakaran Thierry:
- Mhz -> MHz in comments and commit message.
- i2c -> I2C in comments.
- Fix the function documentations, keep in sync with drm_scdc_helper.c
- drm_connector -> DRM connector.
- Create structure for SCDC, and save scrambling status inside that, in a sub-structure.
- Call this sub-structure scrambling instead of scr_info.
- low_rates -> low_clocks in scrambling status structure.
- Store the return value of I2C read/write and print the error code in case of failure.
Thierry and Ville:
- Move the scrambling enable/disable/query functions in drm_scdc_helper.c file.
- Add drm_SCDC prefix for the functions.
- Optimize the return statement from function drm_SCDC_check_scrambling_status.
Ville:
- Dont overwrite saved max TMDS clock value in display_info, if max tmds clock from HF-VSDB is not > 340 MHz.
- drm_detect_hdmi_scrambling -> drm_parse_hdmi_forum_vsdb.
- Remove dynamic tracking of SCDC status from DRM layer, force bool.
- Program clock ratio bit also, while enabling scrambling.
Dhinakaran:
- Add a comment about *5000 while extracting max clock supported.
Signed-off-by: Shashank Sharma shashank.sharma@intel.com
drivers/gpu/drm/drm_edid.c | 33 ++++++++++++- drivers/gpu/drm/drm_scdc_helper.c | 100 ++++++++++++++++++++++++++++++++++++++ include/drm/drm_connector.h | 19 ++++++++ include/drm/drm_edid.h | 6 ++- include/drm/drm_scdc_helper.h | 20 ++++++++ 5 files changed, 176 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index a487b80..dc85eb9 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -37,6 +37,7 @@ #include <drm/drm_edid.h> #include <drm/drm_encoder.h> #include <drm/drm_displayid.h> +#include <drm/drm_scdc_helper.h>
#define version_greater(edid, maj, min) \ (((edid)->version > (maj)) || \ @@ -3805,13 +3806,43 @@ enum hdmi_quantization_range static void drm_parse_hdmi_forum_vsdb(struct drm_connector *connector, const u8 *hf_vsdb) {
- struct drm_hdmi_info *hdmi = &connector->display_info.hdmi;
struct drm_display_info *display = &connector->display_info;
struct drm_hdmi_info *hdmi = &display->hdmi;
if (hf_vsdb[6] & 0x80) { hdmi->scdc.supported = true; if (hf_vsdb[6] & 0x40) hdmi->scdc.read_request = true; }
/*
* All HDMI 2.0 monitors must support scrambling at rates > 340 MHz.
* And as per the spec, three factors confirm this:
* * Availability of a HF-VSDB block in EDID (check)
* * Non zero Max_TMDS_Char_Rate filed in HF-VSDB (let's check)
* * SCDC support available (let's check)
* Lets check it out.
*/
if (hf_vsdb[5]) {
/* max clock is 5000 KHz times block value */
u32 max_tmds_clock = hf_vsdb[5] * 5000;
struct drm_scdc *scdc = &hdmi->scdc;
if (max_tmds_clock > 340000) {
display->max_tmds_clock = max_tmds_clock;
DRM_DEBUG_KMS("HF-VSDB: max TMDS clock %d kHz\n",
display->max_tmds_clock);
}
if (scdc->supported) {
scdc->scrambling.supported = true;
/* Few sinks support scrambling for cloks < 340M */
if ((hf_vsdb[6] & 0x8))
BIT(3) ?
scdc->scrambling.low_rates = true;
}
- }
}
static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector, diff --git a/drivers/gpu/drm/drm_scdc_helper.c b/drivers/gpu/drm/drm_scdc_helper.c index fe0e121..311f62e 100644 --- a/drivers/gpu/drm/drm_scdc_helper.c +++ b/drivers/gpu/drm/drm_scdc_helper.c @@ -22,8 +22,10 @@ */
#include <linux/slab.h> +#include <linux/delay.h>
#include <drm/drm_scdc_helper.h> +#include <drm/drmP.h>
/**
- DOC: scdc helpers
@@ -109,3 +111,101 @@ ssize_t drm_scdc_write(struct i2c_adapter *adapter, u8 offset, return err; } EXPORT_SYMBOL(drm_scdc_write);
+/**
- drm_scdc_check_scrambling_status - what is status of scrambling?
- @adapter: I2C adapter for DDC channel
- Reads the scrambler status over SCDC, and checks the
- scrambling status.
- Returns:
- True if the scrambling is enabled, false otherwise.
- */
+bool drm_scdc_check_scrambling_status(struct i2c_adapter *adapter) +{
- u8 status;
- int ret;
- ret = drm_scdc_readb(adapter, SCDC_SCRAMBLER_STATUS, &status);
- if (ret < 0) {
DRM_ERROR("Failed to read scrambling status, error %d\n", ret);
return false;
- }
- return status & SCDC_SCRAMBLING_STATUS;
"return (status & SCDC_SCRAMBLING_STATUS) > 0;" ?
+} +EXPORT_SYMBOL(drm_scdc_check_scrambling_status);
+/**
- drm_scdc_enable_scrambling - enable scrambling
- @adapter: I2C adapter for DDC channel
- Writes the TMDS config over SCDC channel, and enables scrambling
- Returns:
- True if scrambling is successfully enabled, false otherwise.
- */
+bool drm_scdc_enable_scrambling(struct i2c_adapter *adapter) +{
- u8 config;
- int ret;
- ret = drm_scdc_readb(adapter, SCDC_TMDS_CONFIG, &config);
- if (ret < 0) {
DRM_ERROR("Failed to read tmds config, err=%d\n", ret);
return false;
- }
- config |= (SCDC_SCRAMBLING_ENABLE | SCDC_TMDS_BIT_CLOCK_RATIO_BY_40);
Hmm, I did not read the spec exhaustively but shouldn't the clock ratio by 40 only be set for data rates above 3.4Gbps?
- ret = drm_scdc_writeb(adapter, SCDC_TMDS_CONFIG, config);
- if (ret < 0) {
DRM_ERROR("Failed to enable scrambling, error %d\n", ret);
return false;
- }
- /*
* The spec says that the source should wait min 1ms and max 100ms
* after writing the TMDS config for clock ratio. Lets obey the spec.
*/
- usleep_range(1000, 100000);
Shall we read here the clock_detected status to make sure the sink is okay?
- return true;
+} +EXPORT_SYMBOL(drm_scdc_enable_scrambling);
+/**
- drm_scdc_disable_scrambling - disable scrambling
- @adapter: I2C adapter for DDC channel
- Write the TMDS config over SCDC channel, and disable scrambling
- Return: True if scrambling is successfully disabled, false otherwise.
- */
+bool drm_scdc_disable_scrambling(struct i2c_adapter *adapter) +{
- u8 config;
- int ret;
- ret = drm_scdc_readb(adapter, SCDC_TMDS_CONFIG, &config);
- if (ret < 0) {
DRM_ERROR("Failed to read tmds config, error %d\n", ret);
return false;
- }
- config &= ~(SCDC_SCRAMBLING_ENABLE | SCDC_TMDS_BIT_CLOCK_RATIO_BY_40);
- ret = drm_scdc_writeb(adapter, SCDC_TMDS_CONFIG, config);
- if (ret < 0) {
DRM_ERROR("Failed to enable scrambling, error %d\n", ret);
return false;
- }
- /*
* The spec says that the source should wait min 1ms and max 100ms
* after writing the TMDS config for clock ratio. Lets obey the spec.
*/
- usleep_range(1000, 100000);
- return true;
+} +EXPORT_SYMBOL(drm_scdc_disable_scrambling); diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 6d5304e..78618308 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -90,6 +90,20 @@ enum subpixel_order {
};
+/**
- struct drm_scrambling: sink's scrambling support.
- */
+struct drm_scrambling {
- /**
* @supported: scrambling supported for rates > 340 Mhz.
*/
- bool supported;
- /**
* @low_rates: scrambling supported for rates <= 340 Mhz.
*/
- bool low_rates;
+};
/*
- struct drm_scdc - Information about scdc capabilities of a HDMI 2.0 sink
@@ -105,8 +119,13 @@ struct drm_scdc { * @read_request: sink is capable of generating scdc read request. */ bool read_request;
- /**
* @scrambling: sink's scrambling capabilities
*/
- struct drm_scrambling scrambling;
};
/**
- struct drm_hdmi_info - runtime information about the connected HDMI sink
diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index 43fb0ac..d24c974 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -462,5 +462,9 @@ void drm_edid_get_monitor_name(struct edid *edid, char *name, struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev, int hsize, int vsize, int fresh, bool rb);
+bool drm_enable_scrambling(struct drm_connector *connector,
struct i2c_adapter *adapter, bool force);
+bool drm_disable_scrambling(struct drm_connector *connector,
struct i2c_adapter *adapter, bool force);
+bool drm_check_scrambling_status(struct i2c_adapter *adapter); #endif /* __DRM_EDID_H__ */ diff --git a/include/drm/drm_scdc_helper.h b/include/drm/drm_scdc_helper.h index 93b07bc..dc727a5 100644 --- a/include/drm/drm_scdc_helper.h +++ b/include/drm/drm_scdc_helper.h @@ -129,4 +129,24 @@ static inline int drm_scdc_writeb(struct i2c_adapter *adapter, u8 offset, return drm_scdc_write(adapter, offset, &value, sizeof(value)); }
+/**
- drm_scdc_enable_scrambling - enable scrambling
- @adapter: I2C adapter for DDC channel
- Writes the TMDS config over SCDC channel, and enables scrambling
- Returns:
- True if scrambling is successfully enabled, false otherwise.
- */
+bool drm_scdc_enable_scrambling(struct i2c_adapter *adapter);
+/**
- drm_scdc_disable_scrambling - disable scrambling
- @adapter: I2C adapter for DDC channel
- Write the TMDS config over SCDC channel, and disable scrambling
- Return: True if scrambling is successfully disabled, false otherwise.
- */
+bool drm_scdc_disable_scrambling(struct i2c_adapter *adapter);
#endif
Best regards, Jose Miguel Abreu
On Tue, 07 Feb 2017, Jose Abreu Jose.Abreu@synopsys.com wrote:
+bool drm_scdc_check_scrambling_status(struct i2c_adapter *adapter) +{
- u8 status;
- int ret;
- ret = drm_scdc_readb(adapter, SCDC_SCRAMBLER_STATUS, &status);
- if (ret < 0) {
DRM_ERROR("Failed to read scrambling status, error %d\n", ret);
return false;
- }
- return status & SCDC_SCRAMBLING_STATUS;
"return (status & SCDC_SCRAMBLING_STATUS) > 0;" ?
What's the point in that?
BR, Jani.
Hi Jani,
On 07-02-2017 13:35, Jani Nikula wrote:
On Tue, 07 Feb 2017, Jose Abreu Jose.Abreu@synopsys.com wrote:
+bool drm_scdc_check_scrambling_status(struct i2c_adapter *adapter) +{
- u8 status;
- int ret;
- ret = drm_scdc_readb(adapter, SCDC_SCRAMBLER_STATUS, &status);
- if (ret < 0) {
DRM_ERROR("Failed to read scrambling status, error %d\n", ret);
return false;
- }
- return status & SCDC_SCRAMBLING_STATUS;
"return (status & SCDC_SCRAMBLING_STATUS) > 0;" ?
What's the point in that?
BR, Jani.
Sorry, I didn't see the SCDC_SCRAMBLING_STATUS is BIT(0). Anyway, my intention was to return either 1 or 0 or else the value of the "and" would be returned. I think in x86 the bool is char, what could happen if SCDC_SCRAMBLING_STATUS was BIT(>7)? Does the cast work as expected?
Best regards, Jose Miguel Abreu
On Tue, 07 Feb 2017, Jose Abreu Jose.Abreu@synopsys.com wrote:
Hi Jani,
On 07-02-2017 13:35, Jani Nikula wrote:
On Tue, 07 Feb 2017, Jose Abreu Jose.Abreu@synopsys.com wrote:
+bool drm_scdc_check_scrambling_status(struct i2c_adapter *adapter) +{
- u8 status;
- int ret;
- ret = drm_scdc_readb(adapter, SCDC_SCRAMBLER_STATUS, &status);
- if (ret < 0) {
DRM_ERROR("Failed to read scrambling status, error %d\n", ret);
return false;
- }
- return status & SCDC_SCRAMBLING_STATUS;
"return (status & SCDC_SCRAMBLING_STATUS) > 0;" ?
What's the point in that?
BR, Jani.
Sorry, I didn't see the SCDC_SCRAMBLING_STATUS is BIT(0). Anyway, my intention was to return either 1 or 0 or else the value of the "and" would be returned. I think in x86 the bool is char, what could happen if SCDC_SCRAMBLING_STATUS was BIT(>7)? Does the cast work as expected?
The implicit type conversion works just fine.
BR, Jani.
Best regards, Jose Miguel Abreu
Hi Jani,
On 07-02-2017 15:09, Jani Nikula wrote:
On Tue, 07 Feb 2017, Jose Abreu Jose.Abreu@synopsys.com wrote:
Hi Jani,
On 07-02-2017 13:35, Jani Nikula wrote:
On Tue, 07 Feb 2017, Jose Abreu Jose.Abreu@synopsys.com wrote:
+bool drm_scdc_check_scrambling_status(struct i2c_adapter *adapter) +{
- u8 status;
- int ret;
- ret = drm_scdc_readb(adapter, SCDC_SCRAMBLER_STATUS, &status);
- if (ret < 0) {
DRM_ERROR("Failed to read scrambling status, error %d\n", ret);
return false;
- }
- return status & SCDC_SCRAMBLING_STATUS;
"return (status & SCDC_SCRAMBLING_STATUS) > 0;" ?
What's the point in that?
BR, Jani.
Sorry, I didn't see the SCDC_SCRAMBLING_STATUS is BIT(0). Anyway, my intention was to return either 1 or 0 or else the value of the "and" would be returned. I think in x86 the bool is char, what could happen if SCDC_SCRAMBLING_STATUS was BIT(>7)? Does the cast work as expected?
The implicit type conversion works just fine.
Hmm, are you sure? I'm reading this thread: http://yarchive.net/comp/linux/bool.html (see Linus last answer).
(This is just for curiosity anyway).
Best regards, Jose Miguel Abreu
BR, Jani.
Best regards, Jose Miguel Abreu
On Wed, 08 Feb 2017, Jose Abreu Jose.Abreu@synopsys.com wrote:
Hi Jani,
On 07-02-2017 15:09, Jani Nikula wrote:
On Tue, 07 Feb 2017, Jose Abreu Jose.Abreu@synopsys.com wrote:
Hi Jani,
On 07-02-2017 13:35, Jani Nikula wrote:
On Tue, 07 Feb 2017, Jose Abreu Jose.Abreu@synopsys.com wrote:
+bool drm_scdc_check_scrambling_status(struct i2c_adapter *adapter) +{
- u8 status;
- int ret;
- ret = drm_scdc_readb(adapter, SCDC_SCRAMBLER_STATUS, &status);
- if (ret < 0) {
DRM_ERROR("Failed to read scrambling status, error %d\n", ret);
return false;
- }
- return status & SCDC_SCRAMBLING_STATUS;
"return (status & SCDC_SCRAMBLING_STATUS) > 0;" ?
What's the point in that?
BR, Jani.
Sorry, I didn't see the SCDC_SCRAMBLING_STATUS is BIT(0). Anyway, my intention was to return either 1 or 0 or else the value of the "and" would be returned. I think in x86 the bool is char, what could happen if SCDC_SCRAMBLING_STATUS was BIT(>7)? Does the cast work as expected?
The implicit type conversion works just fine.
Hmm, are you sure? I'm reading this thread: http://yarchive.net/comp/linux/bool.html (see Linus last answer).
I think you're confusing ABI with what C guarantees. I don't think that thread has any relevance here.
BR, Jani.
(This is just for curiosity anyway).
Best regards, Jose Miguel Abreu
BR, Jani.
Best regards, Jose Miguel Abreu
Regards
Shashank
On 2/7/2017 4:44 PM, Jose Abreu wrote:
Hi Shashank,
On 06-02-2017 13:59, Shashank Sharma wrote:
HDMI 2.0 spec mandates scrambling for modes with pixel clock higher than 340 MHz. This patch adds few new functions in drm layer for core drivers to enable/disable scrambling.
This patch adds:
- A function to detect scrambling support parsing HF-VSDB
- A function to check scrambling status runtime using SCDC read.
- Two functions to enable/disable scrambling using SCDC read/write.
- Few new bools to reflect scrambling support and status.
V2: Addressed review comments from Thierry, Ville and Dhinakaran Thierry:
- Mhz -> MHz in comments and commit message.
- i2c -> I2C in comments.
- Fix the function documentations, keep in sync with drm_scdc_helper.c
- drm_connector -> DRM connector.
- Create structure for SCDC, and save scrambling status inside that, in a sub-structure.
- Call this sub-structure scrambling instead of scr_info.
- low_rates -> low_clocks in scrambling status structure.
- Store the return value of I2C read/write and print the error code in case of failure.
Thierry and Ville:
- Move the scrambling enable/disable/query functions in drm_scdc_helper.c file.
- Add drm_SCDC prefix for the functions.
- Optimize the return statement from function drm_SCDC_check_scrambling_status.
Ville:
- Dont overwrite saved max TMDS clock value in display_info, if max tmds clock from HF-VSDB is not > 340 MHz.
- drm_detect_hdmi_scrambling -> drm_parse_hdmi_forum_vsdb.
- Remove dynamic tracking of SCDC status from DRM layer, force bool.
- Program clock ratio bit also, while enabling scrambling.
Dhinakaran:
- Add a comment about *5000 while extracting max clock supported.
Signed-off-by: Shashank Sharma shashank.sharma@intel.com
drivers/gpu/drm/drm_edid.c | 33 ++++++++++++- drivers/gpu/drm/drm_scdc_helper.c | 100 ++++++++++++++++++++++++++++++++++++++ include/drm/drm_connector.h | 19 ++++++++ include/drm/drm_edid.h | 6 ++- include/drm/drm_scdc_helper.h | 20 ++++++++ 5 files changed, 176 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index a487b80..dc85eb9 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -37,6 +37,7 @@ #include <drm/drm_edid.h> #include <drm/drm_encoder.h> #include <drm/drm_displayid.h> +#include <drm/drm_scdc_helper.h>
#define version_greater(edid, maj, min) \ (((edid)->version > (maj)) || \ @@ -3805,13 +3806,43 @@ enum hdmi_quantization_range static void drm_parse_hdmi_forum_vsdb(struct drm_connector *connector, const u8 *hf_vsdb) {
- struct drm_hdmi_info *hdmi = &connector->display_info.hdmi;
struct drm_display_info *display = &connector->display_info;
struct drm_hdmi_info *hdmi = &display->hdmi;
if (hf_vsdb[6] & 0x80) { hdmi->scdc.supported = true; if (hf_vsdb[6] & 0x40) hdmi->scdc.read_request = true; }
/*
* All HDMI 2.0 monitors must support scrambling at rates > 340 MHz.
* And as per the spec, three factors confirm this:
* * Availability of a HF-VSDB block in EDID (check)
* * Non zero Max_TMDS_Char_Rate filed in HF-VSDB (let's check)
* * SCDC support available (let's check)
* Lets check it out.
*/
if (hf_vsdb[5]) {
/* max clock is 5000 KHz times block value */
u32 max_tmds_clock = hf_vsdb[5] * 5000;
struct drm_scdc *scdc = &hdmi->scdc;
if (max_tmds_clock > 340000) {
display->max_tmds_clock = max_tmds_clock;
DRM_DEBUG_KMS("HF-VSDB: max TMDS clock %d kHz\n",
display->max_tmds_clock);
}
if (scdc->supported) {
scdc->scrambling.supported = true;
/* Few sinks support scrambling for cloks < 340M */
if ((hf_vsdb[6] & 0x8))
BIT(3) ?
Yes, bit 3 is LTE_340Mcsc_scramble, indicating that the sink support scrambling at rates below 340Mhz too, isn't it ?
scdc->scrambling.low_rates = true;
}
} }
static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector,
diff --git a/drivers/gpu/drm/drm_scdc_helper.c b/drivers/gpu/drm/drm_scdc_helper.c index fe0e121..311f62e 100644 --- a/drivers/gpu/drm/drm_scdc_helper.c +++ b/drivers/gpu/drm/drm_scdc_helper.c @@ -22,8 +22,10 @@ */
#include <linux/slab.h> +#include <linux/delay.h>
#include <drm/drm_scdc_helper.h> +#include <drm/drmP.h>
/**
- DOC: scdc helpers
@@ -109,3 +111,101 @@ ssize_t drm_scdc_write(struct i2c_adapter *adapter, u8 offset, return err; } EXPORT_SYMBOL(drm_scdc_write);
+/**
- drm_scdc_check_scrambling_status - what is status of scrambling?
- @adapter: I2C adapter for DDC channel
- Reads the scrambler status over SCDC, and checks the
- scrambling status.
- Returns:
- True if the scrambling is enabled, false otherwise.
- */
+bool drm_scdc_check_scrambling_status(struct i2c_adapter *adapter) +{
- u8 status;
- int ret;
- ret = drm_scdc_readb(adapter, SCDC_SCRAMBLER_STATUS, &status);
- if (ret < 0) {
DRM_ERROR("Failed to read scrambling status, error %d\n", ret);
return false;
- }
- return status & SCDC_SCRAMBLING_STATUS;
"return (status & SCDC_SCRAMBLING_STATUS) > 0;" ?
I think Jani has made an agreement already on this.
+} +EXPORT_SYMBOL(drm_scdc_check_scrambling_status);
+/**
- drm_scdc_enable_scrambling - enable scrambling
- @adapter: I2C adapter for DDC channel
- Writes the TMDS config over SCDC channel, and enables scrambling
- Returns:
- True if scrambling is successfully enabled, false otherwise.
- */
+bool drm_scdc_enable_scrambling(struct i2c_adapter *adapter) +{
- u8 config;
- int ret;
- ret = drm_scdc_readb(adapter, SCDC_TMDS_CONFIG, &config);
- if (ret < 0) {
DRM_ERROR("Failed to read tmds config, err=%d\n", ret);
return false;
- }
- config |= (SCDC_SCRAMBLING_ENABLE | SCDC_TMDS_BIT_CLOCK_RATIO_BY_40);
Hmm, I did not read the spec exhaustively but shouldn't the clock ratio by 40 only be set for data rates above 3.4Gbps?
You are right, for few monitors scrambling can be done below 340 MHz too, and I am not sure if we should set the clock ratio bit on that. Let me check the spec for those cases.
- ret = drm_scdc_writeb(adapter, SCDC_TMDS_CONFIG, config);
- if (ret < 0) {
DRM_ERROR("Failed to enable scrambling, error %d\n", ret);
return false;
- }
- /*
* The spec says that the source should wait min 1ms and max 100ms
* after writing the TMDS config for clock ratio. Lets obey the spec.
*/
- usleep_range(1000, 100000);
Shall we read here the clock_detected status to make sure the sink is okay?
This is optional in spec, so I am afraid few monitors wont implement this, and we will unnecessary add lot of noise in code. Do you think so ?
- Shashank
- return true;
+} +EXPORT_SYMBOL(drm_scdc_enable_scrambling);
+/**
- drm_scdc_disable_scrambling - disable scrambling
- @adapter: I2C adapter for DDC channel
- Write the TMDS config over SCDC channel, and disable scrambling
- Return: True if scrambling is successfully disabled, false otherwise.
- */
+bool drm_scdc_disable_scrambling(struct i2c_adapter *adapter) +{
- u8 config;
- int ret;
- ret = drm_scdc_readb(adapter, SCDC_TMDS_CONFIG, &config);
- if (ret < 0) {
DRM_ERROR("Failed to read tmds config, error %d\n", ret);
return false;
- }
- config &= ~(SCDC_SCRAMBLING_ENABLE | SCDC_TMDS_BIT_CLOCK_RATIO_BY_40);
- ret = drm_scdc_writeb(adapter, SCDC_TMDS_CONFIG, config);
- if (ret < 0) {
DRM_ERROR("Failed to enable scrambling, error %d\n", ret);
return false;
- }
- /*
* The spec says that the source should wait min 1ms and max 100ms
* after writing the TMDS config for clock ratio. Lets obey the spec.
*/
- usleep_range(1000, 100000);
- return true;
+} +EXPORT_SYMBOL(drm_scdc_disable_scrambling); diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 6d5304e..78618308 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -90,6 +90,20 @@ enum subpixel_order {
};
+/**
- struct drm_scrambling: sink's scrambling support.
- */
+struct drm_scrambling {
- /**
* @supported: scrambling supported for rates > 340 Mhz.
*/
- bool supported;
- /**
* @low_rates: scrambling supported for rates <= 340 Mhz.
*/
- bool low_rates;
+};
- /*
- struct drm_scdc - Information about scdc capabilities of a HDMI 2.0 sink
@@ -105,8 +119,13 @@ struct drm_scdc { * @read_request: sink is capable of generating scdc read request. */ bool read_request;
/**
* @scrambling: sink's scrambling capabilities
*/
struct drm_scrambling scrambling; };
/**
- struct drm_hdmi_info - runtime information about the connected HDMI sink
diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index 43fb0ac..d24c974 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -462,5 +462,9 @@ void drm_edid_get_monitor_name(struct edid *edid, char *name, struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev, int hsize, int vsize, int fresh, bool rb);
+bool drm_enable_scrambling(struct drm_connector *connector,
struct i2c_adapter *adapter, bool force);
+bool drm_disable_scrambling(struct drm_connector *connector,
struct i2c_adapter *adapter, bool force);
+bool drm_check_scrambling_status(struct i2c_adapter *adapter); #endif /* __DRM_EDID_H__ */ diff --git a/include/drm/drm_scdc_helper.h b/include/drm/drm_scdc_helper.h index 93b07bc..dc727a5 100644 --- a/include/drm/drm_scdc_helper.h +++ b/include/drm/drm_scdc_helper.h @@ -129,4 +129,24 @@ static inline int drm_scdc_writeb(struct i2c_adapter *adapter, u8 offset, return drm_scdc_write(adapter, offset, &value, sizeof(value)); }
+/**
- drm_scdc_enable_scrambling - enable scrambling
- @adapter: I2C adapter for DDC channel
- Writes the TMDS config over SCDC channel, and enables scrambling
- Returns:
- True if scrambling is successfully enabled, false otherwise.
- */
+bool drm_scdc_enable_scrambling(struct i2c_adapter *adapter);
+/**
- drm_scdc_disable_scrambling - disable scrambling
- @adapter: I2C adapter for DDC channel
- Write the TMDS config over SCDC channel, and disable scrambling
- Return: True if scrambling is successfully disabled, false otherwise.
- */
+bool drm_scdc_disable_scrambling(struct i2c_adapter *adapter);
- #endif
Best regards, Jose Miguel Abreu
Hi Shashank,
On 07-02-2017 16:19, Sharma, Shashank wrote:
Regards
Shashank
On 2/7/2017 4:44 PM, Jose Abreu wrote:
Hi Shashank,
On 06-02-2017 13:59, Shashank Sharma wrote:
HDMI 2.0 spec mandates scrambling for modes with pixel clock higher than 340 MHz. This patch adds few new functions in drm layer for core drivers to enable/disable scrambling.
This patch adds:
- A function to detect scrambling support parsing HF-VSDB
- A function to check scrambling status runtime using SCDC read.
- Two functions to enable/disable scrambling using SCDC
read/write.
- Few new bools to reflect scrambling support and status.
V2: Addressed review comments from Thierry, Ville and Dhinakaran Thierry:
- Mhz -> MHz in comments and commit message.
- i2c -> I2C in comments.
- Fix the function documentations, keep in sync with
drm_scdc_helper.c
- drm_connector -> DRM connector.
- Create structure for SCDC, and save scrambling status
inside that, in a sub-structure.
- Call this sub-structure scrambling instead of scr_info.
- low_rates -> low_clocks in scrambling status structure.
- Store the return value of I2C read/write and print the
error code in case of failure.
Thierry and Ville:
- Move the scrambling enable/disable/query functions in drm_scdc_helper.c file.
- Add drm_SCDC prefix for the functions.
- Optimize the return statement from function drm_SCDC_check_scrambling_status.
Ville:
- Dont overwrite saved max TMDS clock value in display_info, if max tmds clock from HF-VSDB is not > 340 MHz.
- drm_detect_hdmi_scrambling -> drm_parse_hdmi_forum_vsdb.
- Remove dynamic tracking of SCDC status from DRM layer,
force bool.
- Program clock ratio bit also, while enabling scrambling.
Dhinakaran:
- Add a comment about *5000 while extracting max clock
supported.
Signed-off-by: Shashank Sharma shashank.sharma@intel.com
drivers/gpu/drm/drm_edid.c | 33 ++++++++++++- drivers/gpu/drm/drm_scdc_helper.c | 100 ++++++++++++++++++++++++++++++++++++++ include/drm/drm_connector.h | 19 ++++++++ include/drm/drm_edid.h | 6 ++- include/drm/drm_scdc_helper.h | 20 ++++++++ 5 files changed, 176 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index a487b80..dc85eb9 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -37,6 +37,7 @@ #include <drm/drm_edid.h> #include <drm/drm_encoder.h> #include <drm/drm_displayid.h> +#include <drm/drm_scdc_helper.h> #define version_greater(edid, maj, min) \ (((edid)->version > (maj)) || \ @@ -3805,13 +3806,43 @@ enum hdmi_quantization_range static void drm_parse_hdmi_forum_vsdb(struct drm_connector *connector, const u8 *hf_vsdb) {
- struct drm_hdmi_info *hdmi = &connector->display_info.hdmi;
- struct drm_display_info *display =
&connector->display_info;
- struct drm_hdmi_info *hdmi = &display->hdmi; if (hf_vsdb[6] & 0x80) { hdmi->scdc.supported = true; if (hf_vsdb[6] & 0x40) hdmi->scdc.read_request = true; }
- /*
* All HDMI 2.0 monitors must support scrambling at
rates > 340 MHz.
* And as per the spec, three factors confirm this:
* * Availability of a HF-VSDB block in EDID (check)
* * Non zero Max_TMDS_Char_Rate filed in HF-VSDB (let's
check)
* * SCDC support available (let's check)
* Lets check it out.
*/
- if (hf_vsdb[5]) {
/* max clock is 5000 KHz times block value */
u32 max_tmds_clock = hf_vsdb[5] * 5000;
struct drm_scdc *scdc = &hdmi->scdc;
if (max_tmds_clock > 340000) {
display->max_tmds_clock = max_tmds_clock;
DRM_DEBUG_KMS("HF-VSDB: max TMDS clock %d kHz\n",
display->max_tmds_clock);
}
if (scdc->supported) {
scdc->scrambling.supported = true;
/* Few sinks support scrambling for cloks < 340M */
if ((hf_vsdb[6] & 0x8))
BIT(3) ?
Yes, bit 3 is LTE_340Mcsc_scramble, indicating that the sink support scrambling at rates below 340Mhz too, isn't it ?
scdc->scrambling.low_rates = true;
}
- } } static void drm_parse_hdmi_deep_color_info(struct
drm_connector *connector, diff --git a/drivers/gpu/drm/drm_scdc_helper.c b/drivers/gpu/drm/drm_scdc_helper.c index fe0e121..311f62e 100644 --- a/drivers/gpu/drm/drm_scdc_helper.c +++ b/drivers/gpu/drm/drm_scdc_helper.c @@ -22,8 +22,10 @@ */ #include <linux/slab.h> +#include <linux/delay.h> #include <drm/drm_scdc_helper.h> +#include <drm/drmP.h> /**
- DOC: scdc helpers
@@ -109,3 +111,101 @@ ssize_t drm_scdc_write(struct i2c_adapter *adapter, u8 offset, return err; } EXPORT_SYMBOL(drm_scdc_write);
+/**
- drm_scdc_check_scrambling_status - what is status of
scrambling?
- @adapter: I2C adapter for DDC channel
- Reads the scrambler status over SCDC, and checks the
- scrambling status.
- Returns:
- True if the scrambling is enabled, false otherwise.
- */
+bool drm_scdc_check_scrambling_status(struct i2c_adapter *adapter) +{
- u8 status;
- int ret;
- ret = drm_scdc_readb(adapter, SCDC_SCRAMBLER_STATUS,
&status);
- if (ret < 0) {
DRM_ERROR("Failed to read scrambling status, error
%d\n", ret);
return false;
- }
- return status & SCDC_SCRAMBLING_STATUS;
"return (status & SCDC_SCRAMBLING_STATUS) > 0;" ?
I think Jani has made an agreement already on this.
+} +EXPORT_SYMBOL(drm_scdc_check_scrambling_status);
+/**
- drm_scdc_enable_scrambling - enable scrambling
- @adapter: I2C adapter for DDC channel
- Writes the TMDS config over SCDC channel, and enables
scrambling
- Returns:
- True if scrambling is successfully enabled, false otherwise.
- */
+bool drm_scdc_enable_scrambling(struct i2c_adapter *adapter) +{
- u8 config;
- int ret;
- ret = drm_scdc_readb(adapter, SCDC_TMDS_CONFIG, &config);
- if (ret < 0) {
DRM_ERROR("Failed to read tmds config, err=%d\n", ret);
return false;
- }
- config |= (SCDC_SCRAMBLING_ENABLE |
SCDC_TMDS_BIT_CLOCK_RATIO_BY_40);
Hmm, I did not read the spec exhaustively but shouldn't the clock ratio by 40 only be set for data rates above 3.4Gbps?
You are right, for few monitors scrambling can be done below 340 MHz too, and I am not sure if we should set the clock ratio bit on that. Let me check the spec for those cases.
- ret = drm_scdc_writeb(adapter, SCDC_TMDS_CONFIG, config);
- if (ret < 0) {
DRM_ERROR("Failed to enable scrambling, error %d\n",
ret);
return false;
- }
- /*
* The spec says that the source should wait min 1ms and
max 100ms
* after writing the TMDS config for clock ratio. Lets
obey the spec.
*/
- usleep_range(1000, 100000);
Shall we read here the clock_detected status to make sure the sink is okay?
This is optional in spec, so I am afraid few monitors wont implement this, and we will unnecessary add lot of noise in code. Do you think so ?
Hmm, ok. It was the safest thing to do but if we have monitors with scrambling support and without this then its better not to.
Best regards, Jose Miguel Abreu
- Shashank
- return true;
+} +EXPORT_SYMBOL(drm_scdc_enable_scrambling);
+/**
- drm_scdc_disable_scrambling - disable scrambling
- @adapter: I2C adapter for DDC channel
- Write the TMDS config over SCDC channel, and disable
scrambling
- Return: True if scrambling is successfully disabled,
false otherwise.
- */
+bool drm_scdc_disable_scrambling(struct i2c_adapter *adapter) +{
- u8 config;
- int ret;
- ret = drm_scdc_readb(adapter, SCDC_TMDS_CONFIG, &config);
- if (ret < 0) {
DRM_ERROR("Failed to read tmds config, error %d\n",
ret);
return false;
- }
- config &= ~(SCDC_SCRAMBLING_ENABLE |
SCDC_TMDS_BIT_CLOCK_RATIO_BY_40);
- ret = drm_scdc_writeb(adapter, SCDC_TMDS_CONFIG, config);
- if (ret < 0) {
DRM_ERROR("Failed to enable scrambling, error %d\n",
ret);
return false;
- }
- /*
* The spec says that the source should wait min 1ms and
max 100ms
* after writing the TMDS config for clock ratio. Lets
obey the spec.
*/
- usleep_range(1000, 100000);
- return true;
+} +EXPORT_SYMBOL(drm_scdc_disable_scrambling); diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 6d5304e..78618308 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -90,6 +90,20 @@ enum subpixel_order { }; +/**
- struct drm_scrambling: sink's scrambling support.
- */
+struct drm_scrambling {
- /**
* @supported: scrambling supported for rates > 340 Mhz.
*/
- bool supported;
- /**
* @low_rates: scrambling supported for rates <= 340 Mhz.
*/
- bool low_rates;
+};
- /*
- struct drm_scdc - Information about scdc capabilities of
a HDMI 2.0 sink
@@ -105,8 +119,13 @@ struct drm_scdc { * @read_request: sink is capable of generating scdc read request. */ bool read_request;
- /**
* @scrambling: sink's scrambling capabilities
*/
- struct drm_scrambling scrambling; };
/**
- struct drm_hdmi_info - runtime information about the
connected HDMI sink
diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index 43fb0ac..d24c974 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -462,5 +462,9 @@ void drm_edid_get_monitor_name(struct edid *edid, char *name, struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev, int hsize, int vsize, int fresh, bool rb);
+bool drm_enable_scrambling(struct drm_connector *connector,
struct i2c_adapter *adapter, bool force);
+bool drm_disable_scrambling(struct drm_connector *connector,
struct i2c_adapter *adapter, bool force);
+bool drm_check_scrambling_status(struct i2c_adapter *adapter); #endif /* __DRM_EDID_H__ */ diff --git a/include/drm/drm_scdc_helper.h b/include/drm/drm_scdc_helper.h index 93b07bc..dc727a5 100644 --- a/include/drm/drm_scdc_helper.h +++ b/include/drm/drm_scdc_helper.h @@ -129,4 +129,24 @@ static inline int drm_scdc_writeb(struct i2c_adapter *adapter, u8 offset, return drm_scdc_write(adapter, offset, &value, sizeof(value)); } +/**
- drm_scdc_enable_scrambling - enable scrambling
- @adapter: I2C adapter for DDC channel
- Writes the TMDS config over SCDC channel, and enables
scrambling
- Returns:
- True if scrambling is successfully enabled, false otherwise.
- */
+bool drm_scdc_enable_scrambling(struct i2c_adapter *adapter);
+/**
- drm_scdc_disable_scrambling - disable scrambling
- @adapter: I2C adapter for DDC channel
- Write the TMDS config over SCDC channel, and disable
scrambling
- Return: True if scrambling is successfully disabled,
false otherwise.
- */
+bool drm_scdc_disable_scrambling(struct i2c_adapter *adapter);
- #endif
Best regards, Jose Miguel Abreu
Regards
Shashank
On 2/8/2017 5:01 PM, Jose Abreu wrote:
Hi Shashank,
On 07-02-2017 16:19, Sharma, Shashank wrote:
Regards
Shashank
On 2/7/2017 4:44 PM, Jose Abreu wrote:
Hi Shashank,
On 06-02-2017 13:59, Shashank Sharma wrote:
HDMI 2.0 spec mandates scrambling for modes with pixel clock higher than 340 MHz. This patch adds few new functions in drm layer for core drivers to enable/disable scrambling.
This patch adds:
- A function to detect scrambling support parsing HF-VSDB
- A function to check scrambling status runtime using SCDC read.
- Two functions to enable/disable scrambling using SCDC
read/write.
- Few new bools to reflect scrambling support and status.
V2: Addressed review comments from Thierry, Ville and Dhinakaran Thierry:
- Mhz -> MHz in comments and commit message.
- i2c -> I2C in comments.
- Fix the function documentations, keep in sync with
drm_scdc_helper.c
- drm_connector -> DRM connector.
- Create structure for SCDC, and save scrambling status
inside that, in a sub-structure.
- Call this sub-structure scrambling instead of scr_info.
- low_rates -> low_clocks in scrambling status structure.
- Store the return value of I2C read/write and print the
error code in case of failure.
Thierry and Ville:
- Move the scrambling enable/disable/query functions in drm_scdc_helper.c file.
- Add drm_SCDC prefix for the functions.
- Optimize the return statement from function drm_SCDC_check_scrambling_status.
Ville:
- Dont overwrite saved max TMDS clock value in display_info, if max tmds clock from HF-VSDB is not > 340 MHz.
- drm_detect_hdmi_scrambling -> drm_parse_hdmi_forum_vsdb.
- Remove dynamic tracking of SCDC status from DRM layer,
force bool.
- Program clock ratio bit also, while enabling scrambling.
Dhinakaran:
- Add a comment about *5000 while extracting max clock
supported.
Signed-off-by: Shashank Sharma shashank.sharma@intel.com
drivers/gpu/drm/drm_edid.c | 33 ++++++++++++- drivers/gpu/drm/drm_scdc_helper.c | 100 ++++++++++++++++++++++++++++++++++++++ include/drm/drm_connector.h | 19 ++++++++ include/drm/drm_edid.h | 6 ++- include/drm/drm_scdc_helper.h | 20 ++++++++ 5 files changed, 176 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index a487b80..dc85eb9 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -37,6 +37,7 @@ #include <drm/drm_edid.h> #include <drm/drm_encoder.h> #include <drm/drm_displayid.h> +#include <drm/drm_scdc_helper.h> #define version_greater(edid, maj, min) \ (((edid)->version > (maj)) || \ @@ -3805,13 +3806,43 @@ enum hdmi_quantization_range static void drm_parse_hdmi_forum_vsdb(struct drm_connector *connector, const u8 *hf_vsdb) {
- struct drm_hdmi_info *hdmi = &connector->display_info.hdmi;
- struct drm_display_info *display =
&connector->display_info;
- struct drm_hdmi_info *hdmi = &display->hdmi; if (hf_vsdb[6] & 0x80) { hdmi->scdc.supported = true; if (hf_vsdb[6] & 0x40) hdmi->scdc.read_request = true; }
- /*
* All HDMI 2.0 monitors must support scrambling at
rates > 340 MHz.
* And as per the spec, three factors confirm this:
* * Availability of a HF-VSDB block in EDID (check)
* * Non zero Max_TMDS_Char_Rate filed in HF-VSDB (let's
check)
* * SCDC support available (let's check)
* Lets check it out.
*/
- if (hf_vsdb[5]) {
/* max clock is 5000 KHz times block value */
u32 max_tmds_clock = hf_vsdb[5] * 5000;
struct drm_scdc *scdc = &hdmi->scdc;
if (max_tmds_clock > 340000) {
display->max_tmds_clock = max_tmds_clock;
DRM_DEBUG_KMS("HF-VSDB: max TMDS clock %d kHz\n",
display->max_tmds_clock);
}
if (scdc->supported) {
scdc->scrambling.supported = true;
/* Few sinks support scrambling for cloks < 340M */
if ((hf_vsdb[6] & 0x8))
BIT(3) ?
Yes, bit 3 is LTE_340Mcsc_scramble, indicating that the sink support scrambling at rates below 340Mhz too, isn't it ?
scdc->scrambling.low_rates = true;
}
- } } static void drm_parse_hdmi_deep_color_info(struct
drm_connector *connector, diff --git a/drivers/gpu/drm/drm_scdc_helper.c b/drivers/gpu/drm/drm_scdc_helper.c index fe0e121..311f62e 100644 --- a/drivers/gpu/drm/drm_scdc_helper.c +++ b/drivers/gpu/drm/drm_scdc_helper.c @@ -22,8 +22,10 @@ */ #include <linux/slab.h> +#include <linux/delay.h> #include <drm/drm_scdc_helper.h> +#include <drm/drmP.h> /** * DOC: scdc helpers @@ -109,3 +111,101 @@ ssize_t drm_scdc_write(struct i2c_adapter *adapter, u8 offset, return err; } EXPORT_SYMBOL(drm_scdc_write);
+/**
- drm_scdc_check_scrambling_status - what is status of
scrambling?
- @adapter: I2C adapter for DDC channel
- Reads the scrambler status over SCDC, and checks the
- scrambling status.
- Returns:
- True if the scrambling is enabled, false otherwise.
- */
+bool drm_scdc_check_scrambling_status(struct i2c_adapter *adapter) +{
- u8 status;
- int ret;
- ret = drm_scdc_readb(adapter, SCDC_SCRAMBLER_STATUS,
&status);
- if (ret < 0) {
DRM_ERROR("Failed to read scrambling status, error
%d\n", ret);
return false;
- }
- return status & SCDC_SCRAMBLING_STATUS;
"return (status & SCDC_SCRAMBLING_STATUS) > 0;" ?
I think Jani has made an agreement already on this.
+} +EXPORT_SYMBOL(drm_scdc_check_scrambling_status);
+/**
- drm_scdc_enable_scrambling - enable scrambling
- @adapter: I2C adapter for DDC channel
- Writes the TMDS config over SCDC channel, and enables
scrambling
- Returns:
- True if scrambling is successfully enabled, false otherwise.
- */
+bool drm_scdc_enable_scrambling(struct i2c_adapter *adapter) +{
- u8 config;
- int ret;
- ret = drm_scdc_readb(adapter, SCDC_TMDS_CONFIG, &config);
- if (ret < 0) {
DRM_ERROR("Failed to read tmds config, err=%d\n", ret);
return false;
- }
- config |= (SCDC_SCRAMBLING_ENABLE |
SCDC_TMDS_BIT_CLOCK_RATIO_BY_40);
Hmm, I did not read the spec exhaustively but shouldn't the clock ratio by 40 only be set for data rates above 3.4Gbps?
You are right, for few monitors scrambling can be done below 340 MHz too, and I am not sure if we should set the clock ratio bit on that. Let me check the spec for those cases.
You were right here, I will add another function just to add 1/40 TMDS clock stuff, and in this function, we would just enable scrambling.
- Shashank
- ret = drm_scdc_writeb(adapter, SCDC_TMDS_CONFIG, config);
- if (ret < 0) {
DRM_ERROR("Failed to enable scrambling, error %d\n",
ret);
return false;
- }
- /*
* The spec says that the source should wait min 1ms and
max 100ms
* after writing the TMDS config for clock ratio. Lets
obey the spec.
*/
- usleep_range(1000, 100000);
Shall we read here the clock_detected status to make sure the sink is okay?
This is optional in spec, so I am afraid few monitors wont implement this, and we will unnecessary add lot of noise in code. Do you think so ?
Hmm, ok. It was the safest thing to do but if we have monitors with scrambling support and without this then its better not to.
Best regards, Jose Miguel Abreu
- Shashank
- return true;
+} +EXPORT_SYMBOL(drm_scdc_enable_scrambling);
+/**
- drm_scdc_disable_scrambling - disable scrambling
- @adapter: I2C adapter for DDC channel
- Write the TMDS config over SCDC channel, and disable
scrambling
- Return: True if scrambling is successfully disabled,
false otherwise.
- */
+bool drm_scdc_disable_scrambling(struct i2c_adapter *adapter) +{
- u8 config;
- int ret;
- ret = drm_scdc_readb(adapter, SCDC_TMDS_CONFIG, &config);
- if (ret < 0) {
DRM_ERROR("Failed to read tmds config, error %d\n",
ret);
return false;
- }
- config &= ~(SCDC_SCRAMBLING_ENABLE |
SCDC_TMDS_BIT_CLOCK_RATIO_BY_40);
- ret = drm_scdc_writeb(adapter, SCDC_TMDS_CONFIG, config);
- if (ret < 0) {
DRM_ERROR("Failed to enable scrambling, error %d\n",
ret);
return false;
- }
- /*
* The spec says that the source should wait min 1ms and
max 100ms
* after writing the TMDS config for clock ratio. Lets
obey the spec.
*/
- usleep_range(1000, 100000);
- return true;
+} +EXPORT_SYMBOL(drm_scdc_disable_scrambling); diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 6d5304e..78618308 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -90,6 +90,20 @@ enum subpixel_order { }; +/**
- struct drm_scrambling: sink's scrambling support.
- */
+struct drm_scrambling {
- /**
* @supported: scrambling supported for rates > 340 Mhz.
*/
- bool supported;
- /**
* @low_rates: scrambling supported for rates <= 340 Mhz.
*/
- bool low_rates;
+};
- /*
- struct drm_scdc - Information about scdc capabilities of
a HDMI 2.0 sink * @@ -105,8 +119,13 @@ struct drm_scdc { * @read_request: sink is capable of generating scdc read request. */ bool read_request;
- /**
* @scrambling: sink's scrambling capabilities
*/
- struct drm_scrambling scrambling; };
/**
- struct drm_hdmi_info - runtime information about the
connected HDMI sink * diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index 43fb0ac..d24c974 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -462,5 +462,9 @@ void drm_edid_get_monitor_name(struct edid *edid, char *name, struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev, int hsize, int vsize, int fresh, bool rb);
+bool drm_enable_scrambling(struct drm_connector *connector,
struct i2c_adapter *adapter, bool force);
+bool drm_disable_scrambling(struct drm_connector *connector,
struct i2c_adapter *adapter, bool force);
+bool drm_check_scrambling_status(struct i2c_adapter *adapter); #endif /* __DRM_EDID_H__ */ diff --git a/include/drm/drm_scdc_helper.h b/include/drm/drm_scdc_helper.h index 93b07bc..dc727a5 100644 --- a/include/drm/drm_scdc_helper.h +++ b/include/drm/drm_scdc_helper.h @@ -129,4 +129,24 @@ static inline int drm_scdc_writeb(struct i2c_adapter *adapter, u8 offset, return drm_scdc_write(adapter, offset, &value, sizeof(value)); } +/**
- drm_scdc_enable_scrambling - enable scrambling
- @adapter: I2C adapter for DDC channel
- Writes the TMDS config over SCDC channel, and enables
scrambling
- Returns:
- True if scrambling is successfully enabled, false otherwise.
- */
+bool drm_scdc_enable_scrambling(struct i2c_adapter *adapter);
+/**
- drm_scdc_disable_scrambling - disable scrambling
- @adapter: I2C adapter for DDC channel
- Write the TMDS config over SCDC channel, and disable
scrambling
- Return: True if scrambling is successfully disabled,
false otherwise.
- */
+bool drm_scdc_disable_scrambling(struct i2c_adapter *adapter);
- #endif
Best regards, Jose Miguel Abreu
Geminilake platform sports a native HDMI 2.0 controller, and is capable of driving pixel-clocks upto 594Mhz. HDMI 2.0 spec mendates scrambling for these higher clocks, for reduced RF footprint.
This patch checks if the monitor supports scrambling, and if required, enables it during the modeset.
V2: Addressed review comments from Ville: - Do not track scrambling status in DRM layer, track somewhere in driver like in intel_crtc_state. - Don't talk to monitor at such a low layer, set monitor scrambling in intel_enable_ddi() before enabling the port.
Signed-off-by: Shashank Sharma shashank.sharma@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 2 ++ drivers/gpu/drm/i915/intel_ddi.c | 26 +++++++++++++++ drivers/gpu/drm/i915/intel_drv.h | 11 ++++++ drivers/gpu/drm/i915/intel_hdmi.c | 70 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 109 insertions(+)
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 495b789..cc85892 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -7807,6 +7807,8 @@ enum { #define TRANS_DDI_EDP_INPUT_C_ONOFF (6<<12) #define TRANS_DDI_DP_VC_PAYLOAD_ALLOC (1<<8) #define TRANS_DDI_BFI_ENABLE (1<<4) +#define TRANS_DDI_HIGH_TMDS_CHAR_RATE (1<<4) +#define TRANS_DDI_HDMI_SCRAMBLING (1<<0)
/* DisplayPort Transport Control */ #define _DP_TP_CTL_A 0x64040 diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 9a9a670..cc7e091 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1278,6 +1278,11 @@ void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc) temp |= TRANS_DDI_MODE_SELECT_HDMI; else temp |= TRANS_DDI_MODE_SELECT_DVI; + + if (IS_GEMINILAKE(dev_priv)) + temp = intel_hdmi_handle_source_scrambling( + intel_encoder, + &intel_crtc->config->base.adjusted_mode, temp); } else if (type == INTEL_OUTPUT_ANALOG) { temp |= TRANS_DDI_MODE_SELECT_FDI; temp |= (intel_crtc->config->fdi_lanes - 1) << 1; @@ -1845,6 +1850,21 @@ static void intel_enable_ddi(struct intel_encoder *intel_encoder, struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
+ if (IS_GEMINILAKE(dev_priv)) { + /* + * GLK sports a native HDMI 2.0 controller. If required + * clock rate is > 340 Mhz && scrambling is supported + * by monitor, enable scrambling before enabling the + * HDMI 2.0 port. The sink can choose to disable the + * scrambling if it doesn't detect a scrambled within + * 100 ms. + */ + intel_hdmi_handle_monitor_scrambling(intel_encoder, + conn_state->connector, + intel_crtc->config, + true); + } + /* In HDMI/DVI mode, the port width, and swing/emphasis values * are ignored so nothing special needs to be done besides * enabling the port. @@ -1885,6 +1905,12 @@ static void intel_disable_ddi(struct intel_encoder *intel_encoder, intel_display_power_put(dev_priv, POWER_DOMAIN_AUDIO); }
+ if (type == INTEL_OUTPUT_HDMI) { + intel_hdmi_handle_monitor_scrambling(intel_encoder, + old_conn_state->connector, + intel_crtc->config, false); + } + if (type == INTEL_OUTPUT_EDP) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 393f243..300353c 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -681,6 +681,9 @@ struct intel_crtc_state {
/* Gamma mode programmed on the pipe */ uint32_t gamma_mode; + + /* HDMI scrambling status (monitor) */ + bool scrambling; };
struct vlv_wm_state { @@ -1588,6 +1591,14 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, bool intel_hdmi_compute_config(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config, struct drm_connector_state *conn_state); +uint32_t +intel_hdmi_handle_source_scrambling(struct intel_encoder *intel_encoder, + struct drm_display_mode *mode, + uint32_t config); +void intel_hdmi_handle_monitor_scrambling(struct intel_encoder *intel_encoder, + struct drm_connector *connector, + struct intel_crtc_state *config, + bool enable); void intel_dp_dual_mode_set_tmds_output(struct intel_hdmi *hdmi, bool enable);
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index ebae2bd..41d3309 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -34,6 +34,7 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc.h> #include <drm/drm_edid.h> +#include <drm/drm_scdc_helper.h> #include "intel_drv.h" #include <drm/i915_drm.h> #include <drm/intel_lpe_audio.h> @@ -1795,6 +1796,75 @@ static void intel_hdmi_destroy(struct drm_connector *connector) intel_hdmi->aspect_ratio = HDMI_PICTURE_ASPECT_NONE; }
+void intel_hdmi_handle_monitor_scrambling(struct intel_encoder *intel_encoder, + struct drm_connector *connector, + struct intel_crtc_state *config, + bool enable) +{ + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&intel_encoder->base); + struct drm_scdc *scdc = &connector->display_info.hdmi.scdc; + struct drm_scrambling *scrambling = &scdc->scrambling; + struct drm_display_mode *mode = &config->base.adjusted_mode; + struct drm_i915_private *dev_priv = connector->dev->dev_private; + struct i2c_adapter *adptr = intel_gmbus_get_adapter(dev_priv, + intel_hdmi->ddc_bus); + + if (!scrambling->supported) + return; + + DRM_DEBUG_KMS("Setting monitor scrambling for enc:%s connector:%s\n", + intel_encoder->base.name, connector->name); + + /* Enable monitor scrambling */ + if (enable) { + if (mode->clock > 340000 || scrambling->low_rates) { + config->scrambling = drm_scdc_enable_scrambling(adptr); + if (!config->scrambling) + DRM_ERROR("Can't enable monitor scrambling\n"); + } + return; + } + + /* Disable monitor scrambling */ + if (config->scrambling) { + config->scrambling = !(drm_scdc_disable_scrambling(adptr)); + if (config->scrambling) + DRM_ERROR("Can't disable monitor scrambling\n"); + } + +} + +uint32_t +intel_hdmi_handle_source_scrambling(struct intel_encoder *intel_encoder, + struct drm_display_mode *mode, uint32_t hdmi_config) +{ + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&intel_encoder->base); + struct drm_connector *connector = &intel_hdmi->attached_connector->base; + struct drm_hdmi_info *hdmi_info = &connector->display_info.hdmi; + struct drm_scrambling *scrambling = &hdmi_info->scdc.scrambling; + + DRM_DEBUG_KMS("Setting scrambling for enc:%s connector:%s\n", + intel_encoder->base.name, connector->name); + + hdmi_config &= ~TRANS_DDI_HDMI_SCRAMBLING; + hdmi_config &= ~TRANS_DDI_HIGH_TMDS_CHAR_RATE; + + if (mode->clock <= 340000) { + /* Few sinks support scrambling at rate < 340 MHz too */ + if (scrambling->low_rates) + hdmi_config |= TRANS_DDI_HDMI_SCRAMBLING; + return hdmi_config; + } + + /* Scrambling or not, if clock > 340 MHz, set high char rate */ + hdmi_config |= TRANS_DDI_HIGH_TMDS_CHAR_RATE; + + if (scrambling->supported) + hdmi_config |= TRANS_DDI_HDMI_SCRAMBLING; + + return hdmi_config; +} + static u8 intel_hdmi_ddc_pin(struct drm_i915_private *dev_priv, enum port port) {
On Mon, 06 Feb 2017, Shashank Sharma shashank.sharma@intel.com wrote:
Geminilake platform sports a native HDMI 2.0 controller, and is capable of driving pixel-clocks upto 594Mhz. HDMI 2.0 spec mendates scrambling for these higher clocks, for reduced RF footprint.
This patch checks if the monitor supports scrambling, and if required, enables it during the modeset.
Throughout this series, but particularly in this patch, I'd prefer using the term "sink" instead of "monitor" everywhere. The HDMI specifications use source and sink almost exclusively.
BR, Jani.
V2: Addressed review comments from Ville:
- Do not track scrambling status in DRM layer, track somewhere in driver like in intel_crtc_state.
- Don't talk to monitor at such a low layer, set monitor scrambling in intel_enable_ddi() before enabling the port.
Signed-off-by: Shashank Sharma shashank.sharma@intel.com
drivers/gpu/drm/i915/i915_reg.h | 2 ++ drivers/gpu/drm/i915/intel_ddi.c | 26 +++++++++++++++ drivers/gpu/drm/i915/intel_drv.h | 11 ++++++ drivers/gpu/drm/i915/intel_hdmi.c | 70 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 109 insertions(+)
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 495b789..cc85892 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -7807,6 +7807,8 @@ enum { #define TRANS_DDI_EDP_INPUT_C_ONOFF (6<<12) #define TRANS_DDI_DP_VC_PAYLOAD_ALLOC (1<<8) #define TRANS_DDI_BFI_ENABLE (1<<4) +#define TRANS_DDI_HIGH_TMDS_CHAR_RATE (1<<4) +#define TRANS_DDI_HDMI_SCRAMBLING (1<<0)
/* DisplayPort Transport Control */ #define _DP_TP_CTL_A 0x64040 diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 9a9a670..cc7e091 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1278,6 +1278,11 @@ void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc) temp |= TRANS_DDI_MODE_SELECT_HDMI; else temp |= TRANS_DDI_MODE_SELECT_DVI;
if (IS_GEMINILAKE(dev_priv))
temp = intel_hdmi_handle_source_scrambling(
intel_encoder,
} else if (type == INTEL_OUTPUT_ANALOG) { temp |= TRANS_DDI_MODE_SELECT_FDI; temp |= (intel_crtc->config->fdi_lanes - 1) << 1;&intel_crtc->config->base.adjusted_mode, temp);
@@ -1845,6 +1850,21 @@ static void intel_enable_ddi(struct intel_encoder *intel_encoder, struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
if (IS_GEMINILAKE(dev_priv)) {
/*
* GLK sports a native HDMI 2.0 controller. If required
* clock rate is > 340 Mhz && scrambling is supported
* by monitor, enable scrambling before enabling the
* HDMI 2.0 port. The sink can choose to disable the
* scrambling if it doesn't detect a scrambled within
* 100 ms.
*/
intel_hdmi_handle_monitor_scrambling(intel_encoder,
conn_state->connector,
intel_crtc->config,
true);
}
- /* In HDMI/DVI mode, the port width, and swing/emphasis values
- are ignored so nothing special needs to be done besides
- enabling the port.
@@ -1885,6 +1905,12 @@ static void intel_disable_ddi(struct intel_encoder *intel_encoder, intel_display_power_put(dev_priv, POWER_DOMAIN_AUDIO); }
- if (type == INTEL_OUTPUT_HDMI) {
intel_hdmi_handle_monitor_scrambling(intel_encoder,
old_conn_state->connector,
intel_crtc->config, false);
- }
- if (type == INTEL_OUTPUT_EDP) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 393f243..300353c 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -681,6 +681,9 @@ struct intel_crtc_state {
/* Gamma mode programmed on the pipe */ uint32_t gamma_mode;
- /* HDMI scrambling status (monitor) */
- bool scrambling;
};
struct vlv_wm_state { @@ -1588,6 +1591,14 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, bool intel_hdmi_compute_config(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config, struct drm_connector_state *conn_state); +uint32_t +intel_hdmi_handle_source_scrambling(struct intel_encoder *intel_encoder,
struct drm_display_mode *mode,
uint32_t config);
+void intel_hdmi_handle_monitor_scrambling(struct intel_encoder *intel_encoder,
struct drm_connector *connector,
struct intel_crtc_state *config,
bool enable);
void intel_dp_dual_mode_set_tmds_output(struct intel_hdmi *hdmi, bool enable);
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index ebae2bd..41d3309 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -34,6 +34,7 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc.h> #include <drm/drm_edid.h> +#include <drm/drm_scdc_helper.h> #include "intel_drv.h" #include <drm/i915_drm.h> #include <drm/intel_lpe_audio.h> @@ -1795,6 +1796,75 @@ static void intel_hdmi_destroy(struct drm_connector *connector) intel_hdmi->aspect_ratio = HDMI_PICTURE_ASPECT_NONE; }
+void intel_hdmi_handle_monitor_scrambling(struct intel_encoder *intel_encoder,
struct drm_connector *connector,
struct intel_crtc_state *config,
bool enable)
+{
- struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&intel_encoder->base);
- struct drm_scdc *scdc = &connector->display_info.hdmi.scdc;
- struct drm_scrambling *scrambling = &scdc->scrambling;
- struct drm_display_mode *mode = &config->base.adjusted_mode;
- struct drm_i915_private *dev_priv = connector->dev->dev_private;
- struct i2c_adapter *adptr = intel_gmbus_get_adapter(dev_priv,
intel_hdmi->ddc_bus);
- if (!scrambling->supported)
return;
- DRM_DEBUG_KMS("Setting monitor scrambling for enc:%s connector:%s\n",
intel_encoder->base.name, connector->name);
- /* Enable monitor scrambling */
- if (enable) {
if (mode->clock > 340000 || scrambling->low_rates) {
config->scrambling = drm_scdc_enable_scrambling(adptr);
if (!config->scrambling)
DRM_ERROR("Can't enable monitor scrambling\n");
}
return;
- }
- /* Disable monitor scrambling */
- if (config->scrambling) {
config->scrambling = !(drm_scdc_disable_scrambling(adptr));
if (config->scrambling)
DRM_ERROR("Can't disable monitor scrambling\n");
- }
+}
+uint32_t +intel_hdmi_handle_source_scrambling(struct intel_encoder *intel_encoder,
struct drm_display_mode *mode, uint32_t hdmi_config)
+{
- struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&intel_encoder->base);
- struct drm_connector *connector = &intel_hdmi->attached_connector->base;
- struct drm_hdmi_info *hdmi_info = &connector->display_info.hdmi;
- struct drm_scrambling *scrambling = &hdmi_info->scdc.scrambling;
- DRM_DEBUG_KMS("Setting scrambling for enc:%s connector:%s\n",
intel_encoder->base.name, connector->name);
- hdmi_config &= ~TRANS_DDI_HDMI_SCRAMBLING;
- hdmi_config &= ~TRANS_DDI_HIGH_TMDS_CHAR_RATE;
- if (mode->clock <= 340000) {
/* Few sinks support scrambling at rate < 340 MHz too */
if (scrambling->low_rates)
hdmi_config |= TRANS_DDI_HDMI_SCRAMBLING;
return hdmi_config;
- }
- /* Scrambling or not, if clock > 340 MHz, set high char rate */
- hdmi_config |= TRANS_DDI_HIGH_TMDS_CHAR_RATE;
- if (scrambling->supported)
hdmi_config |= TRANS_DDI_HDMI_SCRAMBLING;
- return hdmi_config;
+}
static u8 intel_hdmi_ddc_pin(struct drm_i915_private *dev_priv, enum port port) {
Regards
Shashank
On 2/7/2017 3:51 PM, Jani Nikula wrote:
On Mon, 06 Feb 2017, Shashank Sharma shashank.sharma@intel.com wrote:
Geminilake platform sports a native HDMI 2.0 controller, and is capable of driving pixel-clocks upto 594Mhz. HDMI 2.0 spec mendates scrambling for these higher clocks, for reduced RF footprint.
This patch checks if the monitor supports scrambling, and if required, enables it during the modeset.
Throughout this series, but particularly in this patch, I'd prefer using the term "sink" instead of "monitor" everywhere. The HDMI specifications use source and sink almost exclusively.
BR, Jani.
Sure, can be done. - Shashank
V2: Addressed review comments from Ville:
- Do not track scrambling status in DRM layer, track somewhere in driver like in intel_crtc_state.
- Don't talk to monitor at such a low layer, set monitor scrambling in intel_enable_ddi() before enabling the port.
Signed-off-by: Shashank Sharma shashank.sharma@intel.com
drivers/gpu/drm/i915/i915_reg.h | 2 ++ drivers/gpu/drm/i915/intel_ddi.c | 26 +++++++++++++++ drivers/gpu/drm/i915/intel_drv.h | 11 ++++++ drivers/gpu/drm/i915/intel_hdmi.c | 70 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 109 insertions(+)
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 495b789..cc85892 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -7807,6 +7807,8 @@ enum { #define TRANS_DDI_EDP_INPUT_C_ONOFF (6<<12) #define TRANS_DDI_DP_VC_PAYLOAD_ALLOC (1<<8) #define TRANS_DDI_BFI_ENABLE (1<<4) +#define TRANS_DDI_HIGH_TMDS_CHAR_RATE (1<<4) +#define TRANS_DDI_HDMI_SCRAMBLING (1<<0)
/* DisplayPort Transport Control */ #define _DP_TP_CTL_A 0x64040 diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 9a9a670..cc7e091 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1278,6 +1278,11 @@ void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc) temp |= TRANS_DDI_MODE_SELECT_HDMI; else temp |= TRANS_DDI_MODE_SELECT_DVI;
if (IS_GEMINILAKE(dev_priv))
temp = intel_hdmi_handle_source_scrambling(
intel_encoder,
} else if (type == INTEL_OUTPUT_ANALOG) { temp |= TRANS_DDI_MODE_SELECT_FDI; temp |= (intel_crtc->config->fdi_lanes - 1) << 1;&intel_crtc->config->base.adjusted_mode, temp);
@@ -1845,6 +1850,21 @@ static void intel_enable_ddi(struct intel_encoder *intel_encoder, struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
if (IS_GEMINILAKE(dev_priv)) {
/*
* GLK sports a native HDMI 2.0 controller. If required
* clock rate is > 340 Mhz && scrambling is supported
* by monitor, enable scrambling before enabling the
* HDMI 2.0 port. The sink can choose to disable the
* scrambling if it doesn't detect a scrambled within
* 100 ms.
*/
intel_hdmi_handle_monitor_scrambling(intel_encoder,
conn_state->connector,
intel_crtc->config,
true);
}
- /* In HDMI/DVI mode, the port width, and swing/emphasis values
- are ignored so nothing special needs to be done besides
- enabling the port.
@@ -1885,6 +1905,12 @@ static void intel_disable_ddi(struct intel_encoder *intel_encoder, intel_display_power_put(dev_priv, POWER_DOMAIN_AUDIO); }
- if (type == INTEL_OUTPUT_HDMI) {
intel_hdmi_handle_monitor_scrambling(intel_encoder,
old_conn_state->connector,
intel_crtc->config, false);
- }
- if (type == INTEL_OUTPUT_EDP) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 393f243..300353c 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -681,6 +681,9 @@ struct intel_crtc_state {
/* Gamma mode programmed on the pipe */ uint32_t gamma_mode;
/* HDMI scrambling status (monitor) */
bool scrambling; };
struct vlv_wm_state {
@@ -1588,6 +1591,14 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, bool intel_hdmi_compute_config(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config, struct drm_connector_state *conn_state); +uint32_t +intel_hdmi_handle_source_scrambling(struct intel_encoder *intel_encoder,
struct drm_display_mode *mode,
uint32_t config);
+void intel_hdmi_handle_monitor_scrambling(struct intel_encoder *intel_encoder,
struct drm_connector *connector,
struct intel_crtc_state *config,
void intel_dp_dual_mode_set_tmds_output(struct intel_hdmi *hdmi, bool enable);bool enable);
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index ebae2bd..41d3309 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -34,6 +34,7 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc.h> #include <drm/drm_edid.h> +#include <drm/drm_scdc_helper.h> #include "intel_drv.h" #include <drm/i915_drm.h> #include <drm/intel_lpe_audio.h> @@ -1795,6 +1796,75 @@ static void intel_hdmi_destroy(struct drm_connector *connector) intel_hdmi->aspect_ratio = HDMI_PICTURE_ASPECT_NONE; }
+void intel_hdmi_handle_monitor_scrambling(struct intel_encoder *intel_encoder,
struct drm_connector *connector,
struct intel_crtc_state *config,
bool enable)
+{
- struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&intel_encoder->base);
- struct drm_scdc *scdc = &connector->display_info.hdmi.scdc;
- struct drm_scrambling *scrambling = &scdc->scrambling;
- struct drm_display_mode *mode = &config->base.adjusted_mode;
- struct drm_i915_private *dev_priv = connector->dev->dev_private;
- struct i2c_adapter *adptr = intel_gmbus_get_adapter(dev_priv,
intel_hdmi->ddc_bus);
- if (!scrambling->supported)
return;
- DRM_DEBUG_KMS("Setting monitor scrambling for enc:%s connector:%s\n",
intel_encoder->base.name, connector->name);
- /* Enable monitor scrambling */
- if (enable) {
if (mode->clock > 340000 || scrambling->low_rates) {
config->scrambling = drm_scdc_enable_scrambling(adptr);
if (!config->scrambling)
DRM_ERROR("Can't enable monitor scrambling\n");
}
return;
- }
- /* Disable monitor scrambling */
- if (config->scrambling) {
config->scrambling = !(drm_scdc_disable_scrambling(adptr));
if (config->scrambling)
DRM_ERROR("Can't disable monitor scrambling\n");
- }
+}
+uint32_t +intel_hdmi_handle_source_scrambling(struct intel_encoder *intel_encoder,
struct drm_display_mode *mode, uint32_t hdmi_config)
+{
- struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&intel_encoder->base);
- struct drm_connector *connector = &intel_hdmi->attached_connector->base;
- struct drm_hdmi_info *hdmi_info = &connector->display_info.hdmi;
- struct drm_scrambling *scrambling = &hdmi_info->scdc.scrambling;
- DRM_DEBUG_KMS("Setting scrambling for enc:%s connector:%s\n",
intel_encoder->base.name, connector->name);
- hdmi_config &= ~TRANS_DDI_HDMI_SCRAMBLING;
- hdmi_config &= ~TRANS_DDI_HIGH_TMDS_CHAR_RATE;
- if (mode->clock <= 340000) {
/* Few sinks support scrambling at rate < 340 MHz too */
if (scrambling->low_rates)
hdmi_config |= TRANS_DDI_HDMI_SCRAMBLING;
return hdmi_config;
- }
- /* Scrambling or not, if clock > 340 MHz, set high char rate */
- hdmi_config |= TRANS_DDI_HIGH_TMDS_CHAR_RATE;
- if (scrambling->supported)
hdmi_config |= TRANS_DDI_HDMI_SCRAMBLING;
- return hdmi_config;
+}
- static u8 intel_hdmi_ddc_pin(struct drm_i915_private *dev_priv, enum port port) {
Geminilake has a native HDMI 2.0 controller, which is capable of driving clocks upto 594Mhz. This patch updates the max tmds clock limit for the same.
V2: rebase
Cc: Ander ander.conselvan.de.oliveira@intel.com Signed-off-by: Shashank Sharma shashank.sharma@intel.com --- drivers/gpu/drm/i915/intel_hdmi.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 41d3309..b7277a3 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1210,6 +1210,8 @@ static int intel_hdmi_source_max_tmds_clock(struct drm_i915_private *dev_priv) { if (IS_G4X(dev_priv)) return 165000; + else if (IS_GEMINILAKE(dev_priv)) + return 594000; else if (IS_HASWELL(dev_priv) || INTEL_INFO(dev_priv)->gen >= 8) return 300000; else
dri-devel@lists.freedesktop.org