Skip to content

Commit 07e17a7

Browse files
committed
drm/i915: Add function to output Aksv over GMBUS
Once the Aksv is available in the PCH, we need to get it on the wire to the receiver via DDC. The hardware doesn't allow us to read the value directly, so we need to tell GMBUS to source the Aksv internally and send it to the right offset on the receiver. The way we do this is to initiate an indexed write where the index is the Aksv register offset. We write dummy values to GMBUS3 as if we were sending the key, and the hardware slips in the "real" values when it goes out. Changes in v2: - None Changes in v3: - Uses new index write feature (Ville) Changes in v4: - None Changes in v5: - checkpatch whitespace fix Changes in v6: - None Cc: Ville Syrjälä <[email protected]> Reviewed-by: Daniel Vetter <[email protected]> Signed-off-by: Sean Paul <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
1 parent d02cf0a commit 07e17a7

File tree

3 files changed

+46
-3
lines changed

3 files changed

+46
-3
lines changed

drivers/gpu/drm/i915/i915_drv.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3644,6 +3644,7 @@ extern int intel_setup_gmbus(struct drm_i915_private *dev_priv);
36443644
extern void intel_teardown_gmbus(struct drm_i915_private *dev_priv);
36453645
extern bool intel_gmbus_is_valid_pin(struct drm_i915_private *dev_priv,
36463646
unsigned int pin);
3647+
extern int intel_gmbus_output_aksv(struct i2c_adapter *adapter);
36473648

36483649
extern struct i2c_adapter *
36493650
intel_gmbus_get_adapter(struct drm_i915_private *dev_priv, unsigned int pin);

drivers/gpu/drm/i915/i915_reg.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3043,6 +3043,7 @@ enum i915_power_well_id {
30433043
# define GPIO_DATA_PULLUP_DISABLE (1 << 13)
30443044

30453045
#define GMBUS0 _MMIO(dev_priv->gpio_mmio_base + 0x5100) /* clock/port select */
3046+
#define GMBUS_AKSV_SELECT (1<<11)
30463047
#define GMBUS_RATE_100KHZ (0<<8)
30473048
#define GMBUS_RATE_50KHZ (1<<8)
30483049
#define GMBUS_RATE_400KHZ (2<<8) /* reserved on Pineview */

drivers/gpu/drm/i915/intel_i2c.c

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <linux/i2c-algo-bit.h>
3131
#include <linux/export.h>
3232
#include <drm/drmP.h>
33+
#include <drm/drm_hdcp.h>
3334
#include "intel_drv.h"
3435
#include <drm/i915_drm.h>
3536
#include "i915_drv.h"
@@ -507,7 +508,8 @@ gmbus_index_xfer(struct drm_i915_private *dev_priv, struct i2c_msg *msgs)
507508
}
508509

509510
static int
510-
do_gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
511+
do_gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num,
512+
u32 gmbus0_source)
511513
{
512514
struct intel_gmbus *bus = container_of(adapter,
513515
struct intel_gmbus,
@@ -524,7 +526,7 @@ do_gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
524526
pch_gmbus_clock_gating(dev_priv, false);
525527

526528
retry:
527-
I915_WRITE_FW(GMBUS0, bus->reg0);
529+
I915_WRITE_FW(GMBUS0, gmbus0_source | bus->reg0);
528530

529531
for (; i < num; i += inc) {
530532
inc = 1;
@@ -649,7 +651,7 @@ gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
649651
if (ret < 0)
650652
bus->force_bit &= ~GMBUS_FORCE_BIT_RETRY;
651653
} else {
652-
ret = do_gmbus_xfer(adapter, msgs, num);
654+
ret = do_gmbus_xfer(adapter, msgs, num, 0);
653655
if (ret == -EAGAIN)
654656
bus->force_bit |= GMBUS_FORCE_BIT_RETRY;
655657
}
@@ -659,6 +661,45 @@ gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
659661
return ret;
660662
}
661663

664+
int intel_gmbus_output_aksv(struct i2c_adapter *adapter)
665+
{
666+
struct intel_gmbus *bus = container_of(adapter, struct intel_gmbus,
667+
adapter);
668+
struct drm_i915_private *dev_priv = bus->dev_priv;
669+
int ret;
670+
u8 cmd = DRM_HDCP_DDC_AKSV;
671+
u8 buf[DRM_HDCP_KSV_LEN] = { 0 };
672+
struct i2c_msg msgs[] = {
673+
{
674+
.addr = DRM_HDCP_DDC_ADDR,
675+
.flags = 0,
676+
.len = sizeof(cmd),
677+
.buf = &cmd,
678+
},
679+
{
680+
.addr = DRM_HDCP_DDC_ADDR,
681+
.flags = 0,
682+
.len = sizeof(buf),
683+
.buf = buf,
684+
}
685+
};
686+
687+
intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
688+
mutex_lock(&dev_priv->gmbus_mutex);
689+
690+
/*
691+
* In order to output Aksv to the receiver, use an indexed write to
692+
* pass the i2c command, and tell GMBUS to use the HW-provided value
693+
* instead of sourcing GMBUS3 for the data.
694+
*/
695+
ret = do_gmbus_xfer(adapter, msgs, ARRAY_SIZE(msgs), GMBUS_AKSV_SELECT);
696+
697+
mutex_unlock(&dev_priv->gmbus_mutex);
698+
intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS);
699+
700+
return ret;
701+
}
702+
662703
static u32 gmbus_func(struct i2c_adapter *adapter)
663704
{
664705
return i2c_bit_algo.functionality(adapter) &

0 commit comments

Comments
 (0)