summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/nouveau/nouveau_dp.c
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2012-07-10 14:36:38 +1000
committerBen Skeggs <bskeggs@redhat.com>2012-10-03 13:12:46 +1000
commit4196faa8623264b79279a06fd186654c959f2767 (patch)
treed84bb1e28744a3dfbafc1e9203a2ea1fda43eb86 /drivers/gpu/drm/nouveau/nouveau_dp.c
parente0996aea4c349ba302b63203b7d5cab6034dbdca (diff)
drm/nouveau/i2c: port to subdev interfaces
v2/v3: Ben Skeggs <bskeggs@redhat.com> - fix typo in default bus selection - fix accidental loss of destructor v4: Dmitry Eremin-Solenikov <dmitry_eremin@mentor.com> - fix typo causing incorrect default i2c port settings when no BMP data Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_dp.c')
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_dp.c219
1 files changed, 16 insertions, 203 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c
index 63c0e827c302..9e18b35803a8 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dp.c
+++ b/drivers/gpu/drm/nouveau/nouveau_dp.c
@@ -23,143 +23,13 @@
*/
#include "drmP.h"
+#include "drm_dp_helper.h"
#include "nouveau_drv.h"
-#include <subdev/i2c.h>
#include "nouveau_connector.h"
#include "nouveau_encoder.h"
#include "nouveau_crtc.h"
-/******************************************************************************
- * aux channel util functions
- *****************************************************************************/
-#define AUX_DBG(fmt, args...) do { \
- if (nouveau_reg_debug & NOUVEAU_REG_DEBUG_AUXCH) { \
- NV_PRINTK(KERN_DEBUG, dev, "AUXCH(%d): " fmt, ch, ##args); \
- } \
-} while (0)
-#define AUX_ERR(fmt, args...) NV_ERROR(dev, "AUXCH(%d): " fmt, ch, ##args)
-
-static void
-auxch_fini(struct drm_device *dev, int ch)
-{
- nv_mask(dev, 0x00e4e4 + (ch * 0x50), 0x00310000, 0x00000000);
-}
-
-static int
-auxch_init(struct drm_device *dev, int ch)
-{
- const u32 unksel = 1; /* nfi which to use, or if it matters.. */
- const u32 ureq = unksel ? 0x00100000 : 0x00200000;
- const u32 urep = unksel ? 0x01000000 : 0x02000000;
- u32 ctrl, timeout;
-
- /* wait up to 1ms for any previous transaction to be done... */
- timeout = 1000;
- do {
- ctrl = nv_rd32(dev, 0x00e4e4 + (ch * 0x50));
- udelay(1);
- if (!timeout--) {
- AUX_ERR("begin idle timeout 0x%08x", ctrl);
- return -EBUSY;
- }
- } while (ctrl & 0x03010000);
-
- /* set some magic, and wait up to 1ms for it to appear */
- nv_mask(dev, 0x00e4e4 + (ch * 0x50), 0x00300000, ureq);
- timeout = 1000;
- do {
- ctrl = nv_rd32(dev, 0x00e4e4 + (ch * 0x50));
- udelay(1);
- if (!timeout--) {
- AUX_ERR("magic wait 0x%08x\n", ctrl);
- auxch_fini(dev, ch);
- return -EBUSY;
- }
- } while ((ctrl & 0x03000000) != urep);
-
- return 0;
-}
-
-static int
-auxch_tx(struct drm_device *dev, int ch, u8 type, u32 addr, u8 *data, u8 size)
-{
- u32 ctrl, stat, timeout, retries;
- u32 xbuf[4] = {};
- int ret, i;
-
- AUX_DBG("%d: 0x%08x %d\n", type, addr, size);
-
- ret = auxch_init(dev, ch);
- if (ret)
- goto out;
-
- stat = nv_rd32(dev, 0x00e4e8 + (ch * 0x50));
- if (!(stat & 0x10000000)) {
- AUX_DBG("sink not detected\n");
- ret = -ENXIO;
- goto out;
- }
-
- if (!(type & 1)) {
- memcpy(xbuf, data, size);
- for (i = 0; i < 16; i += 4) {
- AUX_DBG("wr 0x%08x\n", xbuf[i / 4]);
- nv_wr32(dev, 0x00e4c0 + (ch * 0x50) + i, xbuf[i / 4]);
- }
- }
-
- ctrl = nv_rd32(dev, 0x00e4e4 + (ch * 0x50));
- ctrl &= ~0x0001f0ff;
- ctrl |= type << 12;
- ctrl |= size - 1;
- nv_wr32(dev, 0x00e4e0 + (ch * 0x50), addr);
-
- /* retry transaction a number of times on failure... */
- ret = -EREMOTEIO;
- for (retries = 0; retries < 32; retries++) {
- /* reset, and delay a while if this is a retry */
- nv_wr32(dev, 0x00e4e4 + (ch * 0x50), 0x80000000 | ctrl);
- nv_wr32(dev, 0x00e4e4 + (ch * 0x50), 0x00000000 | ctrl);
- if (retries)
- udelay(400);
-
- /* transaction request, wait up to 1ms for it to complete */
- nv_wr32(dev, 0x00e4e4 + (ch * 0x50), 0x00010000 | ctrl);
-
- timeout = 1000;
- do {
- ctrl = nv_rd32(dev, 0x00e4e4 + (ch * 0x50));
- udelay(1);
- if (!timeout--) {
- AUX_ERR("tx req timeout 0x%08x\n", ctrl);
- goto out;
- }
- } while (ctrl & 0x00010000);
-
- /* read status, and check if transaction completed ok */
- stat = nv_mask(dev, 0x00e4e8 + (ch * 0x50), 0, 0);
- if (!(stat & 0x000f0f00)) {
- ret = 0;
- break;
- }
-
- AUX_DBG("%02d 0x%08x 0x%08x\n", retries, ctrl, stat);
- }
-
- if (type & 1) {
- for (i = 0; i < 16; i += 4) {
- xbuf[i / 4] = nv_rd32(dev, 0x00e4d0 + (ch * 0x50) + i);
- AUX_DBG("rd 0x%08x\n", xbuf[i / 4]);
- }
- memcpy(data, xbuf, size);
- }
-
-out:
- auxch_fini(dev, ch);
- return ret;
-}
-
u8 *
nouveau_dp_bios_data(struct drm_device *dev, struct dcb_entry *dcb, u8 **entry)
{
@@ -208,9 +78,9 @@ nouveau_dp_bios_data(struct drm_device *dev, struct dcb_entry *dcb, u8 **entry)
* link training
*****************************************************************************/
struct dp_state {
+ struct nouveau_i2c_port *auxch;
struct dp_train_func *func;
struct dcb_entry *dcb;
- int auxch;
int crtc;
u8 *dpcd;
int link_nr;
@@ -236,7 +106,7 @@ dp_set_link_config(struct drm_device *dev, struct dp_state *dp)
if (dp->dpcd[2] & DP_ENHANCED_FRAME_CAP)
sink[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
- auxch_tx(dev, dp->auxch, 8, DP_LINK_BW_SET, sink, 2);
+ auxch_wr(dev, dp->auxch, DP_LINK_BW_SET, sink, 2);
}
static void
@@ -248,10 +118,10 @@ dp_set_training_pattern(struct drm_device *dev, struct dp_state *dp, u8 pattern)
dp->func->train_set(dev, dp->dcb, pattern);
- auxch_tx(dev, dp->auxch, 9, DP_TRAINING_PATTERN_SET, &sink_tp, 1);
+ auxch_rd(dev, dp->auxch, DP_TRAINING_PATTERN_SET, &sink_tp, 1);
sink_tp &= ~DP_TRAINING_PATTERN_MASK;
sink_tp |= pattern;
- auxch_tx(dev, dp->auxch, 8, DP_TRAINING_PATTERN_SET, &sink_tp, 1);
+ auxch_wr(dev, dp->auxch, DP_TRAINING_PATTERN_SET, &sink_tp, 1);
}
static int
@@ -274,7 +144,7 @@ dp_link_train_commit(struct drm_device *dev, struct dp_state *dp)
dp->func->train_adj(dev, dp->dcb, i, lvsw, lpre);
}
- return auxch_tx(dev, dp->auxch, 8, DP_TRAINING_LANE0_SET, dp->conf, 4);
+ return auxch_wr(dev, dp->auxch, DP_TRAINING_LANE0_SET, dp->conf, 4);
}
static int
@@ -284,7 +154,7 @@ dp_link_train_update(struct drm_device *dev, struct dp_state *dp, u32 delay)
udelay(delay);
- ret = auxch_tx(dev, dp->auxch, 9, DP_LANE0_1_STATUS, dp->stat, 6);
+ ret = auxch_rd(dev, dp->auxch, DP_LANE0_1_STATUS, dp->stat, 6);
if (ret)
return ret;
@@ -417,19 +287,17 @@ nouveau_dp_link_train(struct drm_encoder *encoder, u32 datarate,
struct nouveau_connector *nv_connector =
nouveau_encoder_connector_get(nv_encoder);
struct drm_device *dev = encoder->dev;
- struct nouveau_i2c_chan *auxch;
const u32 bw_list[] = { 270000, 162000, 0 };
const u32 *link_bw = bw_list;
struct dp_state dp;
- auxch = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index);
- if (!auxch)
+ dp.auxch = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index);
+ if (!dp.auxch)
return false;
dp.func = func;
dp.dcb = nv_encoder->dcb;
dp.crtc = nv_crtc->index;
- dp.auxch = auxch->drive;
dp.dpcd = nv_encoder->dp.dpcd;
/* adjust required bandwidth for 8B/10B coding overhead */
@@ -491,7 +359,7 @@ nouveau_dp_dpms(struct drm_encoder *encoder, int mode, u32 datarate,
struct dp_train_func *func)
{
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
- struct nouveau_i2c_chan *auxch;
+ struct nouveau_i2c_port *auxch;
u8 status;
auxch = nouveau_i2c_find(encoder->dev, nv_encoder->dcb->i2c_index);
@@ -503,14 +371,14 @@ nouveau_dp_dpms(struct drm_encoder *encoder, int mode, u32 datarate,
else
status = DP_SET_POWER_D3;
- nouveau_dp_auxch(auxch, 8, DP_SET_POWER, &status, 1);
+ auxch_wr(encoder->dev, auxch, DP_SET_POWER, &status, 1);
if (mode == DRM_MODE_DPMS_ON)
nouveau_dp_link_train(encoder, datarate, func);
}
static void
-nouveau_dp_probe_oui(struct drm_device *dev, struct nouveau_i2c_chan *auxch,
+nouveau_dp_probe_oui(struct drm_device *dev, struct nouveau_i2c_port *auxch,
u8 *dpcd)
{
u8 buf[3];
@@ -518,11 +386,11 @@ nouveau_dp_probe_oui(struct drm_device *dev, struct nouveau_i2c_chan *auxch,
if (!(dpcd[DP_DOWN_STREAM_PORT_COUNT] & DP_OUI_SUPPORT))
return;
- if (!auxch_tx(dev, auxch->drive, 9, DP_SINK_OUI, buf, 3))
+ if (!auxch_rd(dev, auxch, DP_SINK_OUI, buf, 3))
NV_DEBUG_KMS(dev, "Sink OUI: %02hx%02hx%02hx\n",
buf[0], buf[1], buf[2]);
- if (!auxch_tx(dev, auxch->drive, 9, DP_BRANCH_OUI, buf, 3))
+ if (!auxch_rd(dev, auxch, DP_BRANCH_OUI, buf, 3))
NV_DEBUG_KMS(dev, "Branch OUI: %02hx%02hx%02hx\n",
buf[0], buf[1], buf[2]);
@@ -533,7 +401,7 @@ nouveau_dp_detect(struct drm_encoder *encoder)
{
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
struct drm_device *dev = encoder->dev;
- struct nouveau_i2c_chan *auxch;
+ struct nouveau_i2c_port *auxch;
u8 *dpcd = nv_encoder->dp.dpcd;
int ret;
@@ -541,7 +409,7 @@ nouveau_dp_detect(struct drm_encoder *encoder)
if (!auxch)
return false;
- ret = auxch_tx(dev, auxch->drive, 9, DP_DPCD_REV, dpcd, 8);
+ ret = auxch_rd(dev, auxch, DP_DPCD_REV, dpcd, 8);
if (ret)
return false;
@@ -566,58 +434,3 @@ nouveau_dp_detect(struct drm_encoder *encoder)
return true;
}
-
-int
-nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr,
- uint8_t *data, int data_nr)
-{
- return auxch_tx(auxch->dev, auxch->drive, cmd, addr, data, data_nr);
-}
-
-static int
-nouveau_dp_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
-{
- struct nouveau_i2c_chan *auxch = (struct nouveau_i2c_chan *)adap;
- struct i2c_msg *msg = msgs;
- int ret, mcnt = num;
-
- while (mcnt--) {
- u8 remaining = msg->len;
- u8 *ptr = msg->buf;
-
- while (remaining) {
- u8 cnt = (remaining > 16) ? 16 : remaining;
- u8 cmd;
-
- if (msg->flags & I2C_M_RD)
- cmd = AUX_I2C_READ;
- else
- cmd = AUX_I2C_WRITE;
-
- if (mcnt || remaining > 16)
- cmd |= AUX_I2C_MOT;
-
- ret = nouveau_dp_auxch(auxch, cmd, msg->addr, ptr, cnt);
- if (ret < 0)
- return ret;
-
- ptr += cnt;
- remaining -= cnt;
- }
-
- msg++;
- }
-
- return num;
-}
-
-static u32
-nouveau_dp_i2c_func(struct i2c_adapter *adap)
-{
- return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
-}
-
-const struct i2c_algorithm nouveau_dp_i2c_algo = {
- .master_xfer = nouveau_dp_i2c_xfer,
- .functionality = nouveau_dp_i2c_func
-};