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>
diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c
index 63c0e82..9e18b35 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 @@
  * 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 @@
 	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->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->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 @@
 
 	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 @@
 	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 @@
 		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 @@
 	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 @@
 	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 @@
 {
 	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 @@
 	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 @@
 
 	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
-};