xref: /dflybsd-src/sys/dev/drm/radeon/radeon_i2c.c (revision 1dedbd3b06c68f627b7825694444529d5eb2b1bf)
1926deccbSFrançois Tigeot /*
2926deccbSFrançois Tigeot  * Copyright 2007-8 Advanced Micro Devices, Inc.
3926deccbSFrançois Tigeot  * Copyright 2008 Red Hat Inc.
4926deccbSFrançois Tigeot  *
5926deccbSFrançois Tigeot  * Permission is hereby granted, free of charge, to any person obtaining a
6926deccbSFrançois Tigeot  * copy of this software and associated documentation files (the "Software"),
7926deccbSFrançois Tigeot  * to deal in the Software without restriction, including without limitation
8926deccbSFrançois Tigeot  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9926deccbSFrançois Tigeot  * and/or sell copies of the Software, and to permit persons to whom the
10926deccbSFrançois Tigeot  * Software is furnished to do so, subject to the following conditions:
11926deccbSFrançois Tigeot  *
12926deccbSFrançois Tigeot  * The above copyright notice and this permission notice shall be included in
13926deccbSFrançois Tigeot  * all copies or substantial portions of the Software.
14926deccbSFrançois Tigeot  *
15926deccbSFrançois Tigeot  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16926deccbSFrançois Tigeot  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17926deccbSFrançois Tigeot  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18926deccbSFrançois Tigeot  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
19926deccbSFrançois Tigeot  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20926deccbSFrançois Tigeot  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21926deccbSFrançois Tigeot  * OTHER DEALINGS IN THE SOFTWARE.
22926deccbSFrançois Tigeot  *
23926deccbSFrançois Tigeot  * Authors: Dave Airlie
24926deccbSFrançois Tigeot  *          Alex Deucher
25926deccbSFrançois Tigeot  */
265ef6d7b4SFrançois Tigeot #include <linux/export.h>
27926deccbSFrançois Tigeot 
28926deccbSFrançois Tigeot #include <drm/drmP.h>
29926deccbSFrançois Tigeot #include <drm/drm_edid.h>
3083b4b9b9SFrançois Tigeot #include <drm/radeon_drm.h>
31926deccbSFrançois Tigeot #include "radeon.h"
32926deccbSFrançois Tigeot #include "atom.h"
335ef6d7b4SFrançois Tigeot 
345ef6d7b4SFrançois Tigeot extern int radeon_atom_hw_i2c_xfer(struct i2c_adapter *i2c_adap,
355ef6d7b4SFrançois Tigeot 				   struct i2c_msg *msgs, int num);
365ef6d7b4SFrançois Tigeot extern u32 radeon_atom_hw_i2c_func(struct i2c_adapter *adap);
37926deccbSFrançois Tigeot 
38926deccbSFrançois Tigeot /**
39926deccbSFrançois Tigeot  * radeon_ddc_probe
40926deccbSFrançois Tigeot  *
41926deccbSFrançois Tigeot  */
radeon_ddc_probe(struct radeon_connector * radeon_connector,bool use_aux)42926deccbSFrançois Tigeot bool radeon_ddc_probe(struct radeon_connector *radeon_connector, bool use_aux)
43926deccbSFrançois Tigeot {
44926deccbSFrançois Tigeot 	u8 out = 0x0;
45926deccbSFrançois Tigeot 	u8 buf[8];
46926deccbSFrançois Tigeot 	int ret;
475ef6d7b4SFrançois Tigeot 	struct i2c_msg msgs[] = {
48926deccbSFrançois Tigeot 		{
495ef6d7b4SFrançois Tigeot 			.addr = DDC_ADDR,
50926deccbSFrançois Tigeot 			.flags = 0,
51926deccbSFrançois Tigeot 			.len = 1,
52926deccbSFrançois Tigeot 			.buf = &out,
53926deccbSFrançois Tigeot 		},
54926deccbSFrançois Tigeot 		{
555ef6d7b4SFrançois Tigeot 			.addr = DDC_ADDR,
565ef6d7b4SFrançois Tigeot 			.flags = I2C_M_RD,
57926deccbSFrançois Tigeot 			.len = 8,
58926deccbSFrançois Tigeot 			.buf = buf,
59926deccbSFrançois Tigeot 		}
60926deccbSFrançois Tigeot 	};
61926deccbSFrançois Tigeot 
62926deccbSFrançois Tigeot 	/* on hw with routers, select right port */
63926deccbSFrançois Tigeot 	if (radeon_connector->router.ddc_valid)
64926deccbSFrançois Tigeot 		radeon_router_select_ddc_port(radeon_connector);
65926deccbSFrançois Tigeot 
66926deccbSFrançois Tigeot 	if (use_aux) {
675ef6d7b4SFrançois Tigeot 		ret = i2c_transfer(&radeon_connector->ddc_bus->aux.ddc, msgs, 2);
68926deccbSFrançois Tigeot 	} else {
695ef6d7b4SFrançois Tigeot 		ret = i2c_transfer(&radeon_connector->ddc_bus->adapter, msgs, 2);
70926deccbSFrançois Tigeot 	}
71926deccbSFrançois Tigeot 
725ef6d7b4SFrançois Tigeot 	if (ret != 2)
73926deccbSFrançois Tigeot 		/* Couldn't find an accessible DDC on this connector */
74926deccbSFrançois Tigeot 		return false;
75926deccbSFrançois Tigeot 	/* Probe also for valid EDID header
76926deccbSFrançois Tigeot 	 * EDID header starts with:
77926deccbSFrançois Tigeot 	 * 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00.
78926deccbSFrançois Tigeot 	 * Only the first 6 bytes must be valid as
79926deccbSFrançois Tigeot 	 * drm_edid_block_valid() can fix the last 2 bytes */
80926deccbSFrançois Tigeot 	if (drm_edid_header_is_valid(buf) < 6) {
81926deccbSFrançois Tigeot 		/* Couldn't find an accessible EDID on this
82926deccbSFrançois Tigeot 		 * connector */
83926deccbSFrançois Tigeot 		return false;
84926deccbSFrançois Tigeot 	}
85926deccbSFrançois Tigeot 	return true;
86926deccbSFrançois Tigeot }
87926deccbSFrançois Tigeot 
88926deccbSFrançois Tigeot /* bit banging i2c */
89926deccbSFrançois Tigeot 
pre_xfer(struct i2c_adapter * i2c_adap)905ef6d7b4SFrançois Tigeot static int pre_xfer(struct i2c_adapter *i2c_adap)
91926deccbSFrançois Tigeot {
925ef6d7b4SFrançois Tigeot 	struct radeon_i2c_chan *i2c = i2c_get_adapdata(i2c_adap);
93926deccbSFrançois Tigeot 	struct radeon_device *rdev = i2c->dev->dev_private;
94926deccbSFrançois Tigeot 	struct radeon_i2c_bus_rec *rec = &i2c->rec;
95926deccbSFrançois Tigeot 	uint32_t temp;
96926deccbSFrançois Tigeot 
975ef6d7b4SFrançois Tigeot 	mutex_lock(&i2c->mutex);
987191d616Szrj 
99926deccbSFrançois Tigeot 	/* RV410 appears to have a bug where the hw i2c in reset
100926deccbSFrançois Tigeot 	 * holds the i2c port in a bad state - switch hw i2c away before
101926deccbSFrançois Tigeot 	 * doing DDC - do this for all r200s/r300s/r400s for safety sake
102926deccbSFrançois Tigeot 	 */
103926deccbSFrançois Tigeot 	if (rec->hw_capable) {
104926deccbSFrançois Tigeot 		if ((rdev->family >= CHIP_R200) && !ASIC_IS_AVIVO(rdev)) {
105926deccbSFrançois Tigeot 			u32 reg;
106926deccbSFrançois Tigeot 
107926deccbSFrançois Tigeot 			if (rdev->family >= CHIP_RV350)
108926deccbSFrançois Tigeot 				reg = RADEON_GPIO_MONID;
109926deccbSFrançois Tigeot 			else if ((rdev->family == CHIP_R300) ||
110926deccbSFrançois Tigeot 				 (rdev->family == CHIP_R350))
111926deccbSFrançois Tigeot 				reg = RADEON_GPIO_DVI_DDC;
112926deccbSFrançois Tigeot 			else
113926deccbSFrançois Tigeot 				reg = RADEON_GPIO_CRT2_DDC;
114926deccbSFrançois Tigeot 
1155ef6d7b4SFrançois Tigeot 			mutex_lock(&rdev->dc_hw_i2c_mutex);
116926deccbSFrançois Tigeot 			if (rec->a_clk_reg == reg) {
117926deccbSFrançois Tigeot 				WREG32(RADEON_DVI_I2C_CNTL_0, (RADEON_I2C_SOFT_RST |
118926deccbSFrançois Tigeot 							       R200_DVI_I2C_PIN_SEL(R200_SEL_DDC1)));
119926deccbSFrançois Tigeot 			} else {
120926deccbSFrançois Tigeot 				WREG32(RADEON_DVI_I2C_CNTL_0, (RADEON_I2C_SOFT_RST |
121926deccbSFrançois Tigeot 							       R200_DVI_I2C_PIN_SEL(R200_SEL_DDC3)));
122926deccbSFrançois Tigeot 			}
1235ef6d7b4SFrançois Tigeot 			mutex_unlock(&rdev->dc_hw_i2c_mutex);
124926deccbSFrançois Tigeot 		}
125926deccbSFrançois Tigeot 	}
126926deccbSFrançois Tigeot 
127926deccbSFrançois Tigeot 	/* switch the pads to ddc mode */
128926deccbSFrançois Tigeot 	if (ASIC_IS_DCE3(rdev) && rec->hw_capable) {
129926deccbSFrançois Tigeot 		temp = RREG32(rec->mask_clk_reg);
130926deccbSFrançois Tigeot 		temp &= ~(1 << 16);
131926deccbSFrançois Tigeot 		WREG32(rec->mask_clk_reg, temp);
132926deccbSFrançois Tigeot 	}
133926deccbSFrançois Tigeot 
134926deccbSFrançois Tigeot 	/* clear the output pin values */
135926deccbSFrançois Tigeot 	temp = RREG32(rec->a_clk_reg) & ~rec->a_clk_mask;
136926deccbSFrançois Tigeot 	WREG32(rec->a_clk_reg, temp);
137926deccbSFrançois Tigeot 
138926deccbSFrançois Tigeot 	temp = RREG32(rec->a_data_reg) & ~rec->a_data_mask;
139926deccbSFrançois Tigeot 	WREG32(rec->a_data_reg, temp);
140926deccbSFrançois Tigeot 
141926deccbSFrançois Tigeot 	/* set the pins to input */
142926deccbSFrançois Tigeot 	temp = RREG32(rec->en_clk_reg) & ~rec->en_clk_mask;
143926deccbSFrançois Tigeot 	WREG32(rec->en_clk_reg, temp);
144926deccbSFrançois Tigeot 
145926deccbSFrançois Tigeot 	temp = RREG32(rec->en_data_reg) & ~rec->en_data_mask;
146926deccbSFrançois Tigeot 	WREG32(rec->en_data_reg, temp);
147926deccbSFrançois Tigeot 
148926deccbSFrançois Tigeot 	/* mask the gpio pins for software use */
149926deccbSFrançois Tigeot 	temp = RREG32(rec->mask_clk_reg) | rec->mask_clk_mask;
150926deccbSFrançois Tigeot 	WREG32(rec->mask_clk_reg, temp);
151926deccbSFrançois Tigeot 	temp = RREG32(rec->mask_clk_reg);
152926deccbSFrançois Tigeot 
153926deccbSFrançois Tigeot 	temp = RREG32(rec->mask_data_reg) | rec->mask_data_mask;
154926deccbSFrançois Tigeot 	WREG32(rec->mask_data_reg, temp);
155926deccbSFrançois Tigeot 	temp = RREG32(rec->mask_data_reg);
156926deccbSFrançois Tigeot 
157926deccbSFrançois Tigeot 	return 0;
158926deccbSFrançois Tigeot }
159926deccbSFrançois Tigeot 
post_xfer(struct i2c_adapter * i2c_adap)1605ef6d7b4SFrançois Tigeot static void post_xfer(struct i2c_adapter *i2c_adap)
161926deccbSFrançois Tigeot {
1625ef6d7b4SFrançois Tigeot 	struct radeon_i2c_chan *i2c = i2c_get_adapdata(i2c_adap);
163926deccbSFrançois Tigeot 	struct radeon_device *rdev = i2c->dev->dev_private;
164926deccbSFrançois Tigeot 	struct radeon_i2c_bus_rec *rec = &i2c->rec;
165926deccbSFrançois Tigeot 	uint32_t temp;
166926deccbSFrançois Tigeot 
167926deccbSFrançois Tigeot 	/* unmask the gpio pins for software use */
168926deccbSFrançois Tigeot 	temp = RREG32(rec->mask_clk_reg) & ~rec->mask_clk_mask;
169926deccbSFrançois Tigeot 	WREG32(rec->mask_clk_reg, temp);
170926deccbSFrançois Tigeot 	temp = RREG32(rec->mask_clk_reg);
171926deccbSFrançois Tigeot 
172926deccbSFrançois Tigeot 	temp = RREG32(rec->mask_data_reg) & ~rec->mask_data_mask;
173926deccbSFrançois Tigeot 	WREG32(rec->mask_data_reg, temp);
174926deccbSFrançois Tigeot 	temp = RREG32(rec->mask_data_reg);
1757191d616Szrj 
1765ef6d7b4SFrançois Tigeot 	mutex_unlock(&i2c->mutex);
177926deccbSFrançois Tigeot }
178926deccbSFrançois Tigeot 
get_clock(void * i2c_priv)1795ef6d7b4SFrançois Tigeot static int get_clock(void *i2c_priv)
180926deccbSFrançois Tigeot {
1815ef6d7b4SFrançois Tigeot 	struct radeon_i2c_chan *i2c = i2c_priv;
182926deccbSFrançois Tigeot 	struct radeon_device *rdev = i2c->dev->dev_private;
183926deccbSFrançois Tigeot 	struct radeon_i2c_bus_rec *rec = &i2c->rec;
184926deccbSFrançois Tigeot 	uint32_t val;
185926deccbSFrançois Tigeot 
186926deccbSFrançois Tigeot 	/* read the value off the pin */
187926deccbSFrançois Tigeot 	val = RREG32(rec->y_clk_reg);
188926deccbSFrançois Tigeot 	val &= rec->y_clk_mask;
189926deccbSFrançois Tigeot 
190926deccbSFrançois Tigeot 	return (val != 0);
191926deccbSFrançois Tigeot }
192926deccbSFrançois Tigeot 
193926deccbSFrançois Tigeot 
get_data(void * i2c_priv)1945ef6d7b4SFrançois Tigeot static int get_data(void *i2c_priv)
195926deccbSFrançois Tigeot {
1965ef6d7b4SFrançois Tigeot 	struct radeon_i2c_chan *i2c = i2c_priv;
197926deccbSFrançois Tigeot 	struct radeon_device *rdev = i2c->dev->dev_private;
198926deccbSFrançois Tigeot 	struct radeon_i2c_bus_rec *rec = &i2c->rec;
199926deccbSFrançois Tigeot 	uint32_t val;
200926deccbSFrançois Tigeot 
201926deccbSFrançois Tigeot 	/* read the value off the pin */
202926deccbSFrançois Tigeot 	val = RREG32(rec->y_data_reg);
203926deccbSFrançois Tigeot 	val &= rec->y_data_mask;
204926deccbSFrançois Tigeot 
205926deccbSFrançois Tigeot 	return (val != 0);
206926deccbSFrançois Tigeot }
207926deccbSFrançois Tigeot 
set_clock(void * i2c_priv,int clock)2085ef6d7b4SFrançois Tigeot static void set_clock(void *i2c_priv, int clock)
209926deccbSFrançois Tigeot {
2105ef6d7b4SFrançois Tigeot 	struct radeon_i2c_chan *i2c = i2c_priv;
211926deccbSFrançois Tigeot 	struct radeon_device *rdev = i2c->dev->dev_private;
212926deccbSFrançois Tigeot 	struct radeon_i2c_bus_rec *rec = &i2c->rec;
213926deccbSFrançois Tigeot 	uint32_t val;
214926deccbSFrançois Tigeot 
215926deccbSFrançois Tigeot 	/* set pin direction */
216926deccbSFrançois Tigeot 	val = RREG32(rec->en_clk_reg) & ~rec->en_clk_mask;
217926deccbSFrançois Tigeot 	val |= clock ? 0 : rec->en_clk_mask;
218926deccbSFrançois Tigeot 	WREG32(rec->en_clk_reg, val);
219926deccbSFrançois Tigeot }
220926deccbSFrançois Tigeot 
set_data(void * i2c_priv,int data)2215ef6d7b4SFrançois Tigeot static void set_data(void *i2c_priv, int data)
222926deccbSFrançois Tigeot {
2235ef6d7b4SFrançois Tigeot 	struct radeon_i2c_chan *i2c = i2c_priv;
224926deccbSFrançois Tigeot 	struct radeon_device *rdev = i2c->dev->dev_private;
225926deccbSFrançois Tigeot 	struct radeon_i2c_bus_rec *rec = &i2c->rec;
226926deccbSFrançois Tigeot 	uint32_t val;
227926deccbSFrançois Tigeot 
228926deccbSFrançois Tigeot 	/* set pin direction */
229926deccbSFrançois Tigeot 	val = RREG32(rec->en_data_reg) & ~rec->en_data_mask;
230926deccbSFrançois Tigeot 	val |= data ? 0 : rec->en_data_mask;
231926deccbSFrançois Tigeot 	WREG32(rec->en_data_reg, val);
232926deccbSFrançois Tigeot }
233926deccbSFrançois Tigeot 
234926deccbSFrançois Tigeot /* hw i2c */
235926deccbSFrançois Tigeot 
radeon_get_i2c_prescale(struct radeon_device * rdev)236926deccbSFrançois Tigeot static u32 radeon_get_i2c_prescale(struct radeon_device *rdev)
237926deccbSFrançois Tigeot {
238926deccbSFrançois Tigeot 	u32 sclk = rdev->pm.current_sclk;
239926deccbSFrançois Tigeot 	u32 prescale = 0;
240926deccbSFrançois Tigeot 	u32 nm;
241926deccbSFrançois Tigeot 	u8 n, m, loop;
242926deccbSFrançois Tigeot 	int i2c_clock;
243926deccbSFrançois Tigeot 
244926deccbSFrançois Tigeot 	switch (rdev->family) {
245926deccbSFrançois Tigeot 	case CHIP_R100:
246926deccbSFrançois Tigeot 	case CHIP_RV100:
247926deccbSFrançois Tigeot 	case CHIP_RS100:
248926deccbSFrançois Tigeot 	case CHIP_RV200:
249926deccbSFrançois Tigeot 	case CHIP_RS200:
250926deccbSFrançois Tigeot 	case CHIP_R200:
251926deccbSFrançois Tigeot 	case CHIP_RV250:
252926deccbSFrançois Tigeot 	case CHIP_RS300:
253926deccbSFrançois Tigeot 	case CHIP_RV280:
254926deccbSFrançois Tigeot 	case CHIP_R300:
255926deccbSFrançois Tigeot 	case CHIP_R350:
256926deccbSFrançois Tigeot 	case CHIP_RV350:
257926deccbSFrançois Tigeot 		i2c_clock = 60;
258926deccbSFrançois Tigeot 		nm = (sclk * 10) / (i2c_clock * 4);
259926deccbSFrançois Tigeot 		for (loop = 1; loop < 255; loop++) {
260926deccbSFrançois Tigeot 			if ((nm / loop) < loop)
261926deccbSFrançois Tigeot 				break;
262926deccbSFrançois Tigeot 		}
263926deccbSFrançois Tigeot 		n = loop - 1;
264926deccbSFrançois Tigeot 		m = loop - 2;
265926deccbSFrançois Tigeot 		prescale = m | (n << 8);
266926deccbSFrançois Tigeot 		break;
267926deccbSFrançois Tigeot 	case CHIP_RV380:
268926deccbSFrançois Tigeot 	case CHIP_RS400:
269926deccbSFrançois Tigeot 	case CHIP_RS480:
270926deccbSFrançois Tigeot 	case CHIP_R420:
271926deccbSFrançois Tigeot 	case CHIP_R423:
272926deccbSFrançois Tigeot 	case CHIP_RV410:
273926deccbSFrançois Tigeot 		prescale = (((sclk * 10)/(4 * 128 * 100) + 1) << 8) + 128;
274926deccbSFrançois Tigeot 		break;
275926deccbSFrançois Tigeot 	case CHIP_RS600:
276926deccbSFrançois Tigeot 	case CHIP_RS690:
277926deccbSFrançois Tigeot 	case CHIP_RS740:
278926deccbSFrançois Tigeot 		/* todo */
279926deccbSFrançois Tigeot 		break;
280926deccbSFrançois Tigeot 	case CHIP_RV515:
281926deccbSFrançois Tigeot 	case CHIP_R520:
282926deccbSFrançois Tigeot 	case CHIP_RV530:
283926deccbSFrançois Tigeot 	case CHIP_RV560:
284926deccbSFrançois Tigeot 	case CHIP_RV570:
285926deccbSFrançois Tigeot 	case CHIP_R580:
286926deccbSFrançois Tigeot 		i2c_clock = 50;
287926deccbSFrançois Tigeot 		if (rdev->family == CHIP_R520)
288926deccbSFrançois Tigeot 			prescale = (127 << 8) + ((sclk * 10) / (4 * 127 * i2c_clock));
289926deccbSFrançois Tigeot 		else
290926deccbSFrançois Tigeot 			prescale = (((sclk * 10)/(4 * 128 * 100) + 1) << 8) + 128;
291926deccbSFrançois Tigeot 		break;
292926deccbSFrançois Tigeot 	case CHIP_R600:
293926deccbSFrançois Tigeot 	case CHIP_RV610:
294926deccbSFrançois Tigeot 	case CHIP_RV630:
295926deccbSFrançois Tigeot 	case CHIP_RV670:
296926deccbSFrançois Tigeot 		/* todo */
297926deccbSFrançois Tigeot 		break;
298926deccbSFrançois Tigeot 	case CHIP_RV620:
299926deccbSFrançois Tigeot 	case CHIP_RV635:
300926deccbSFrançois Tigeot 	case CHIP_RS780:
301926deccbSFrançois Tigeot 	case CHIP_RS880:
302926deccbSFrançois Tigeot 	case CHIP_RV770:
303926deccbSFrançois Tigeot 	case CHIP_RV730:
304926deccbSFrançois Tigeot 	case CHIP_RV710:
305926deccbSFrançois Tigeot 	case CHIP_RV740:
306926deccbSFrançois Tigeot 		/* todo */
307926deccbSFrançois Tigeot 		break;
308926deccbSFrançois Tigeot 	case CHIP_CEDAR:
309926deccbSFrançois Tigeot 	case CHIP_REDWOOD:
310926deccbSFrançois Tigeot 	case CHIP_JUNIPER:
311926deccbSFrançois Tigeot 	case CHIP_CYPRESS:
312926deccbSFrançois Tigeot 	case CHIP_HEMLOCK:
313926deccbSFrançois Tigeot 		/* todo */
314926deccbSFrançois Tigeot 		break;
315926deccbSFrançois Tigeot 	default:
316926deccbSFrançois Tigeot 		DRM_ERROR("i2c: unhandled radeon chip\n");
317926deccbSFrançois Tigeot 		break;
318926deccbSFrançois Tigeot 	}
319926deccbSFrançois Tigeot 	return prescale;
320926deccbSFrançois Tigeot }
321926deccbSFrançois Tigeot 
322926deccbSFrançois Tigeot 
323926deccbSFrançois Tigeot /* hw i2c engine for r1xx-4xx hardware
324926deccbSFrançois Tigeot  * hw can buffer up to 15 bytes
325926deccbSFrançois Tigeot  */
r100_hw_i2c_xfer(struct i2c_adapter * i2c_adap,struct i2c_msg * msgs,int num)3265ef6d7b4SFrançois Tigeot static int r100_hw_i2c_xfer(struct i2c_adapter *i2c_adap,
3275ef6d7b4SFrançois Tigeot 			    struct i2c_msg *msgs, int num)
328926deccbSFrançois Tigeot {
3295ef6d7b4SFrançois Tigeot 	struct radeon_i2c_chan *i2c = i2c_get_adapdata(i2c_adap);
330926deccbSFrançois Tigeot 	struct radeon_device *rdev = i2c->dev->dev_private;
331926deccbSFrançois Tigeot 	struct radeon_i2c_bus_rec *rec = &i2c->rec;
3325ef6d7b4SFrançois Tigeot 	struct i2c_msg *p;
3335ef6d7b4SFrançois Tigeot 	int i, j, k, ret = num;
334926deccbSFrançois Tigeot 	u32 prescale;
335926deccbSFrançois Tigeot 	u32 i2c_cntl_0, i2c_cntl_1, i2c_data;
336926deccbSFrançois Tigeot 	u32 tmp, reg;
337926deccbSFrançois Tigeot 
3385ef6d7b4SFrançois Tigeot 	mutex_lock(&rdev->dc_hw_i2c_mutex);
339926deccbSFrançois Tigeot 	/* take the pm lock since we need a constant sclk */
3405ef6d7b4SFrançois Tigeot 	mutex_lock(&rdev->pm.mutex);
341926deccbSFrançois Tigeot 
342926deccbSFrançois Tigeot 	prescale = radeon_get_i2c_prescale(rdev);
343926deccbSFrançois Tigeot 
344926deccbSFrançois Tigeot 	reg = ((prescale << RADEON_I2C_PRESCALE_SHIFT) |
345926deccbSFrançois Tigeot 	       RADEON_I2C_DRIVE_EN |
346926deccbSFrançois Tigeot 	       RADEON_I2C_START |
347926deccbSFrançois Tigeot 	       RADEON_I2C_STOP |
348926deccbSFrançois Tigeot 	       RADEON_I2C_GO);
349926deccbSFrançois Tigeot 
350926deccbSFrançois Tigeot 	if (rdev->is_atom_bios) {
351926deccbSFrançois Tigeot 		tmp = RREG32(RADEON_BIOS_6_SCRATCH);
352926deccbSFrançois Tigeot 		WREG32(RADEON_BIOS_6_SCRATCH, tmp | ATOM_S6_HW_I2C_BUSY_STATE);
353926deccbSFrançois Tigeot 	}
354926deccbSFrançois Tigeot 
355926deccbSFrançois Tigeot 	if (rec->mm_i2c) {
356926deccbSFrançois Tigeot 		i2c_cntl_0 = RADEON_I2C_CNTL_0;
357926deccbSFrançois Tigeot 		i2c_cntl_1 = RADEON_I2C_CNTL_1;
358926deccbSFrançois Tigeot 		i2c_data = RADEON_I2C_DATA;
359926deccbSFrançois Tigeot 	} else {
360926deccbSFrançois Tigeot 		i2c_cntl_0 = RADEON_DVI_I2C_CNTL_0;
361926deccbSFrançois Tigeot 		i2c_cntl_1 = RADEON_DVI_I2C_CNTL_1;
362926deccbSFrançois Tigeot 		i2c_data = RADEON_DVI_I2C_DATA;
363926deccbSFrançois Tigeot 
364926deccbSFrançois Tigeot 		switch (rdev->family) {
365926deccbSFrançois Tigeot 		case CHIP_R100:
366926deccbSFrançois Tigeot 		case CHIP_RV100:
367926deccbSFrançois Tigeot 		case CHIP_RS100:
368926deccbSFrançois Tigeot 		case CHIP_RV200:
369926deccbSFrançois Tigeot 		case CHIP_RS200:
370926deccbSFrançois Tigeot 		case CHIP_RS300:
371926deccbSFrançois Tigeot 			switch (rec->mask_clk_reg) {
372926deccbSFrançois Tigeot 			case RADEON_GPIO_DVI_DDC:
373926deccbSFrançois Tigeot 				/* no gpio select bit */
374926deccbSFrançois Tigeot 				break;
375926deccbSFrançois Tigeot 			default:
376926deccbSFrançois Tigeot 				DRM_ERROR("gpio not supported with hw i2c\n");
3775ef6d7b4SFrançois Tigeot 				ret = -EINVAL;
378926deccbSFrançois Tigeot 				goto done;
379926deccbSFrançois Tigeot 			}
380926deccbSFrançois Tigeot 			break;
381926deccbSFrançois Tigeot 		case CHIP_R200:
382926deccbSFrançois Tigeot 			/* only bit 4 on r200 */
383926deccbSFrançois Tigeot 			switch (rec->mask_clk_reg) {
384926deccbSFrançois Tigeot 			case RADEON_GPIO_DVI_DDC:
385926deccbSFrançois Tigeot 				reg |= R200_DVI_I2C_PIN_SEL(R200_SEL_DDC1);
386926deccbSFrançois Tigeot 				break;
387926deccbSFrançois Tigeot 			case RADEON_GPIO_MONID:
388926deccbSFrançois Tigeot 				reg |= R200_DVI_I2C_PIN_SEL(R200_SEL_DDC3);
389926deccbSFrançois Tigeot 				break;
390926deccbSFrançois Tigeot 			default:
391926deccbSFrançois Tigeot 				DRM_ERROR("gpio not supported with hw i2c\n");
3925ef6d7b4SFrançois Tigeot 				ret = -EINVAL;
393926deccbSFrançois Tigeot 				goto done;
394926deccbSFrançois Tigeot 			}
395926deccbSFrançois Tigeot 			break;
396926deccbSFrançois Tigeot 		case CHIP_RV250:
397926deccbSFrançois Tigeot 		case CHIP_RV280:
398926deccbSFrançois Tigeot 			/* bits 3 and 4 */
399926deccbSFrançois Tigeot 			switch (rec->mask_clk_reg) {
400926deccbSFrançois Tigeot 			case RADEON_GPIO_DVI_DDC:
401926deccbSFrançois Tigeot 				reg |= R200_DVI_I2C_PIN_SEL(R200_SEL_DDC1);
402926deccbSFrançois Tigeot 				break;
403926deccbSFrançois Tigeot 			case RADEON_GPIO_VGA_DDC:
404926deccbSFrançois Tigeot 				reg |= R200_DVI_I2C_PIN_SEL(R200_SEL_DDC2);
405926deccbSFrançois Tigeot 				break;
406926deccbSFrançois Tigeot 			case RADEON_GPIO_CRT2_DDC:
407926deccbSFrançois Tigeot 				reg |= R200_DVI_I2C_PIN_SEL(R200_SEL_DDC3);
408926deccbSFrançois Tigeot 				break;
409926deccbSFrançois Tigeot 			default:
410926deccbSFrançois Tigeot 				DRM_ERROR("gpio not supported with hw i2c\n");
4115ef6d7b4SFrançois Tigeot 				ret = -EINVAL;
412926deccbSFrançois Tigeot 				goto done;
413926deccbSFrançois Tigeot 			}
414926deccbSFrançois Tigeot 			break;
415926deccbSFrançois Tigeot 		case CHIP_R300:
416926deccbSFrançois Tigeot 		case CHIP_R350:
417926deccbSFrançois Tigeot 			/* only bit 4 on r300/r350 */
418926deccbSFrançois Tigeot 			switch (rec->mask_clk_reg) {
419926deccbSFrançois Tigeot 			case RADEON_GPIO_VGA_DDC:
420926deccbSFrançois Tigeot 				reg |= R200_DVI_I2C_PIN_SEL(R200_SEL_DDC1);
421926deccbSFrançois Tigeot 				break;
422926deccbSFrançois Tigeot 			case RADEON_GPIO_DVI_DDC:
423926deccbSFrançois Tigeot 				reg |= R200_DVI_I2C_PIN_SEL(R200_SEL_DDC3);
424926deccbSFrançois Tigeot 				break;
425926deccbSFrançois Tigeot 			default:
426926deccbSFrançois Tigeot 				DRM_ERROR("gpio not supported with hw i2c\n");
4275ef6d7b4SFrançois Tigeot 				ret = -EINVAL;
428926deccbSFrançois Tigeot 				goto done;
429926deccbSFrançois Tigeot 			}
430926deccbSFrançois Tigeot 			break;
431926deccbSFrançois Tigeot 		case CHIP_RV350:
432926deccbSFrançois Tigeot 		case CHIP_RV380:
433926deccbSFrançois Tigeot 		case CHIP_R420:
434926deccbSFrançois Tigeot 		case CHIP_R423:
435926deccbSFrançois Tigeot 		case CHIP_RV410:
436926deccbSFrançois Tigeot 		case CHIP_RS400:
437926deccbSFrançois Tigeot 		case CHIP_RS480:
438926deccbSFrançois Tigeot 			/* bits 3 and 4 */
439926deccbSFrançois Tigeot 			switch (rec->mask_clk_reg) {
440926deccbSFrançois Tigeot 			case RADEON_GPIO_VGA_DDC:
441926deccbSFrançois Tigeot 				reg |= R200_DVI_I2C_PIN_SEL(R200_SEL_DDC1);
442926deccbSFrançois Tigeot 				break;
443926deccbSFrançois Tigeot 			case RADEON_GPIO_DVI_DDC:
444926deccbSFrançois Tigeot 				reg |= R200_DVI_I2C_PIN_SEL(R200_SEL_DDC2);
445926deccbSFrançois Tigeot 				break;
446926deccbSFrançois Tigeot 			case RADEON_GPIO_MONID:
447926deccbSFrançois Tigeot 				reg |= R200_DVI_I2C_PIN_SEL(R200_SEL_DDC3);
448926deccbSFrançois Tigeot 				break;
449926deccbSFrançois Tigeot 			default:
450926deccbSFrançois Tigeot 				DRM_ERROR("gpio not supported with hw i2c\n");
4515ef6d7b4SFrançois Tigeot 				ret = -EINVAL;
452926deccbSFrançois Tigeot 				goto done;
453926deccbSFrançois Tigeot 			}
454926deccbSFrançois Tigeot 			break;
455926deccbSFrançois Tigeot 		default:
456926deccbSFrançois Tigeot 			DRM_ERROR("unsupported asic\n");
4575ef6d7b4SFrançois Tigeot 			ret = -EINVAL;
458926deccbSFrançois Tigeot 			goto done;
459926deccbSFrançois Tigeot 			break;
460926deccbSFrançois Tigeot 		}
461926deccbSFrançois Tigeot 	}
462926deccbSFrançois Tigeot 
463926deccbSFrançois Tigeot 	/* check for bus probe */
464926deccbSFrançois Tigeot 	p = &msgs[0];
465926deccbSFrançois Tigeot 	if ((num == 1) && (p->len == 0)) {
466926deccbSFrançois Tigeot 		WREG32(i2c_cntl_0, (RADEON_I2C_DONE |
467926deccbSFrançois Tigeot 				    RADEON_I2C_NACK |
468926deccbSFrançois Tigeot 				    RADEON_I2C_HALT |
469926deccbSFrançois Tigeot 				    RADEON_I2C_SOFT_RST));
4705ef6d7b4SFrançois Tigeot 		WREG32(i2c_data, (p->addr << 1) & 0xff);
471926deccbSFrançois Tigeot 		WREG32(i2c_data, 0);
472926deccbSFrançois Tigeot 		WREG32(i2c_cntl_1, ((1 << RADEON_I2C_DATA_COUNT_SHIFT) |
473926deccbSFrançois Tigeot 				    (1 << RADEON_I2C_ADDR_COUNT_SHIFT) |
474926deccbSFrançois Tigeot 				    RADEON_I2C_EN |
475926deccbSFrançois Tigeot 				    (48 << RADEON_I2C_TIME_LIMIT_SHIFT)));
476926deccbSFrançois Tigeot 		WREG32(i2c_cntl_0, reg);
477926deccbSFrançois Tigeot 		for (k = 0; k < 32; k++) {
478c4ef309bSzrj 			udelay(10);
479926deccbSFrançois Tigeot 			tmp = RREG32(i2c_cntl_0);
480926deccbSFrançois Tigeot 			if (tmp & RADEON_I2C_GO)
481926deccbSFrançois Tigeot 				continue;
482926deccbSFrançois Tigeot 			tmp = RREG32(i2c_cntl_0);
483926deccbSFrançois Tigeot 			if (tmp & RADEON_I2C_DONE)
484926deccbSFrançois Tigeot 				break;
485926deccbSFrançois Tigeot 			else {
486926deccbSFrançois Tigeot 				DRM_DEBUG("i2c write error 0x%08x\n", tmp);
487926deccbSFrançois Tigeot 				WREG32(i2c_cntl_0, tmp | RADEON_I2C_ABORT);
4885ef6d7b4SFrançois Tigeot 				ret = -EIO;
489926deccbSFrançois Tigeot 				goto done;
490926deccbSFrançois Tigeot 			}
491926deccbSFrançois Tigeot 		}
492926deccbSFrançois Tigeot 		goto done;
493926deccbSFrançois Tigeot 	}
494926deccbSFrançois Tigeot 
495926deccbSFrançois Tigeot 	for (i = 0; i < num; i++) {
496926deccbSFrançois Tigeot 		p = &msgs[i];
497926deccbSFrançois Tigeot 		for (j = 0; j < p->len; j++) {
4985ef6d7b4SFrançois Tigeot 			if (p->flags & I2C_M_RD) {
499926deccbSFrançois Tigeot 				WREG32(i2c_cntl_0, (RADEON_I2C_DONE |
500926deccbSFrançois Tigeot 						    RADEON_I2C_NACK |
501926deccbSFrançois Tigeot 						    RADEON_I2C_HALT |
502926deccbSFrançois Tigeot 						    RADEON_I2C_SOFT_RST));
5035ef6d7b4SFrançois Tigeot 				WREG32(i2c_data, ((p->addr << 1) & 0xff) | 0x1);
504926deccbSFrançois Tigeot 				WREG32(i2c_cntl_1, ((1 << RADEON_I2C_DATA_COUNT_SHIFT) |
505926deccbSFrançois Tigeot 						    (1 << RADEON_I2C_ADDR_COUNT_SHIFT) |
506926deccbSFrançois Tigeot 						    RADEON_I2C_EN |
507926deccbSFrançois Tigeot 						    (48 << RADEON_I2C_TIME_LIMIT_SHIFT)));
508926deccbSFrançois Tigeot 				WREG32(i2c_cntl_0, reg | RADEON_I2C_RECEIVE);
509926deccbSFrançois Tigeot 				for (k = 0; k < 32; k++) {
510c4ef309bSzrj 					udelay(10);
511926deccbSFrançois Tigeot 					tmp = RREG32(i2c_cntl_0);
512926deccbSFrançois Tigeot 					if (tmp & RADEON_I2C_GO)
513926deccbSFrançois Tigeot 						continue;
514926deccbSFrançois Tigeot 					tmp = RREG32(i2c_cntl_0);
515926deccbSFrançois Tigeot 					if (tmp & RADEON_I2C_DONE)
516926deccbSFrançois Tigeot 						break;
517926deccbSFrançois Tigeot 					else {
518926deccbSFrançois Tigeot 						DRM_DEBUG("i2c read error 0x%08x\n", tmp);
519926deccbSFrançois Tigeot 						WREG32(i2c_cntl_0, tmp | RADEON_I2C_ABORT);
5205ef6d7b4SFrançois Tigeot 						ret = -EIO;
521926deccbSFrançois Tigeot 						goto done;
522926deccbSFrançois Tigeot 					}
523926deccbSFrançois Tigeot 				}
524926deccbSFrançois Tigeot 				p->buf[j] = RREG32(i2c_data) & 0xff;
525926deccbSFrançois Tigeot 			} else {
526926deccbSFrançois Tigeot 				WREG32(i2c_cntl_0, (RADEON_I2C_DONE |
527926deccbSFrançois Tigeot 						    RADEON_I2C_NACK |
528926deccbSFrançois Tigeot 						    RADEON_I2C_HALT |
529926deccbSFrançois Tigeot 						    RADEON_I2C_SOFT_RST));
5305ef6d7b4SFrançois Tigeot 				WREG32(i2c_data, (p->addr << 1) & 0xff);
531926deccbSFrançois Tigeot 				WREG32(i2c_data, p->buf[j]);
532926deccbSFrançois Tigeot 				WREG32(i2c_cntl_1, ((1 << RADEON_I2C_DATA_COUNT_SHIFT) |
533926deccbSFrançois Tigeot 						    (1 << RADEON_I2C_ADDR_COUNT_SHIFT) |
534926deccbSFrançois Tigeot 						    RADEON_I2C_EN |
535926deccbSFrançois Tigeot 						    (48 << RADEON_I2C_TIME_LIMIT_SHIFT)));
536926deccbSFrançois Tigeot 				WREG32(i2c_cntl_0, reg);
537926deccbSFrançois Tigeot 				for (k = 0; k < 32; k++) {
538c4ef309bSzrj 					udelay(10);
539926deccbSFrançois Tigeot 					tmp = RREG32(i2c_cntl_0);
540926deccbSFrançois Tigeot 					if (tmp & RADEON_I2C_GO)
541926deccbSFrançois Tigeot 						continue;
542926deccbSFrançois Tigeot 					tmp = RREG32(i2c_cntl_0);
543926deccbSFrançois Tigeot 					if (tmp & RADEON_I2C_DONE)
544926deccbSFrançois Tigeot 						break;
545926deccbSFrançois Tigeot 					else {
546926deccbSFrançois Tigeot 						DRM_DEBUG("i2c write error 0x%08x\n", tmp);
547926deccbSFrançois Tigeot 						WREG32(i2c_cntl_0, tmp | RADEON_I2C_ABORT);
5485ef6d7b4SFrançois Tigeot 						ret = -EIO;
549926deccbSFrançois Tigeot 						goto done;
550926deccbSFrançois Tigeot 					}
551926deccbSFrançois Tigeot 				}
552926deccbSFrançois Tigeot 			}
553926deccbSFrançois Tigeot 		}
554926deccbSFrançois Tigeot 	}
555926deccbSFrançois Tigeot 
556926deccbSFrançois Tigeot done:
557926deccbSFrançois Tigeot 	WREG32(i2c_cntl_0, 0);
558926deccbSFrançois Tigeot 	WREG32(i2c_cntl_1, 0);
559926deccbSFrançois Tigeot 	WREG32(i2c_cntl_0, (RADEON_I2C_DONE |
560926deccbSFrançois Tigeot 			    RADEON_I2C_NACK |
561926deccbSFrançois Tigeot 			    RADEON_I2C_HALT |
562926deccbSFrançois Tigeot 			    RADEON_I2C_SOFT_RST));
563926deccbSFrançois Tigeot 
564926deccbSFrançois Tigeot 	if (rdev->is_atom_bios) {
565926deccbSFrançois Tigeot 		tmp = RREG32(RADEON_BIOS_6_SCRATCH);
566926deccbSFrançois Tigeot 		tmp &= ~ATOM_S6_HW_I2C_BUSY_STATE;
567926deccbSFrançois Tigeot 		WREG32(RADEON_BIOS_6_SCRATCH, tmp);
568926deccbSFrançois Tigeot 	}
569926deccbSFrançois Tigeot 
5705ef6d7b4SFrançois Tigeot 	mutex_unlock(&rdev->pm.mutex);
5715ef6d7b4SFrançois Tigeot 	mutex_unlock(&rdev->dc_hw_i2c_mutex);
572926deccbSFrançois Tigeot 
573926deccbSFrançois Tigeot 	return ret;
574926deccbSFrançois Tigeot }
575926deccbSFrançois Tigeot 
576926deccbSFrançois Tigeot /* hw i2c engine for r5xx hardware
577926deccbSFrançois Tigeot  * hw can buffer up to 15 bytes
578926deccbSFrançois Tigeot  */
r500_hw_i2c_xfer(struct i2c_adapter * i2c_adap,struct i2c_msg * msgs,int num)5795ef6d7b4SFrançois Tigeot static int r500_hw_i2c_xfer(struct i2c_adapter *i2c_adap,
5805ef6d7b4SFrançois Tigeot 			    struct i2c_msg *msgs, int num)
581926deccbSFrançois Tigeot {
5825ef6d7b4SFrançois Tigeot 	struct radeon_i2c_chan *i2c = i2c_get_adapdata(i2c_adap);
583926deccbSFrançois Tigeot 	struct radeon_device *rdev = i2c->dev->dev_private;
584926deccbSFrançois Tigeot 	struct radeon_i2c_bus_rec *rec = &i2c->rec;
5855ef6d7b4SFrançois Tigeot 	struct i2c_msg *p;
5865ef6d7b4SFrançois Tigeot 	int i, j, remaining, current_count, buffer_offset, ret = num;
587926deccbSFrançois Tigeot 	u32 prescale;
588926deccbSFrançois Tigeot 	u32 tmp, reg;
589926deccbSFrançois Tigeot 	u32 saved1, saved2;
590926deccbSFrançois Tigeot 
5915ef6d7b4SFrançois Tigeot 	mutex_lock(&rdev->dc_hw_i2c_mutex);
592926deccbSFrançois Tigeot 	/* take the pm lock since we need a constant sclk */
5935ef6d7b4SFrançois Tigeot 	mutex_lock(&rdev->pm.mutex);
594926deccbSFrançois Tigeot 
595926deccbSFrançois Tigeot 	prescale = radeon_get_i2c_prescale(rdev);
596926deccbSFrançois Tigeot 
597926deccbSFrançois Tigeot 	/* clear gpio mask bits */
598926deccbSFrançois Tigeot 	tmp = RREG32(rec->mask_clk_reg);
599926deccbSFrançois Tigeot 	tmp &= ~rec->mask_clk_mask;
600926deccbSFrançois Tigeot 	WREG32(rec->mask_clk_reg, tmp);
601926deccbSFrançois Tigeot 	tmp = RREG32(rec->mask_clk_reg);
602926deccbSFrançois Tigeot 
603926deccbSFrançois Tigeot 	tmp = RREG32(rec->mask_data_reg);
604926deccbSFrançois Tigeot 	tmp &= ~rec->mask_data_mask;
605926deccbSFrançois Tigeot 	WREG32(rec->mask_data_reg, tmp);
606926deccbSFrançois Tigeot 	tmp = RREG32(rec->mask_data_reg);
607926deccbSFrançois Tigeot 
608926deccbSFrançois Tigeot 	/* clear pin values */
609926deccbSFrançois Tigeot 	tmp = RREG32(rec->a_clk_reg);
610926deccbSFrançois Tigeot 	tmp &= ~rec->a_clk_mask;
611926deccbSFrançois Tigeot 	WREG32(rec->a_clk_reg, tmp);
612926deccbSFrançois Tigeot 	tmp = RREG32(rec->a_clk_reg);
613926deccbSFrançois Tigeot 
614926deccbSFrançois Tigeot 	tmp = RREG32(rec->a_data_reg);
615926deccbSFrançois Tigeot 	tmp &= ~rec->a_data_mask;
616926deccbSFrançois Tigeot 	WREG32(rec->a_data_reg, tmp);
617926deccbSFrançois Tigeot 	tmp = RREG32(rec->a_data_reg);
618926deccbSFrançois Tigeot 
619926deccbSFrançois Tigeot 	/* set the pins to input */
620926deccbSFrançois Tigeot 	tmp = RREG32(rec->en_clk_reg);
621926deccbSFrançois Tigeot 	tmp &= ~rec->en_clk_mask;
622926deccbSFrançois Tigeot 	WREG32(rec->en_clk_reg, tmp);
623926deccbSFrançois Tigeot 	tmp = RREG32(rec->en_clk_reg);
624926deccbSFrançois Tigeot 
625926deccbSFrançois Tigeot 	tmp = RREG32(rec->en_data_reg);
626926deccbSFrançois Tigeot 	tmp &= ~rec->en_data_mask;
627926deccbSFrançois Tigeot 	WREG32(rec->en_data_reg, tmp);
628926deccbSFrançois Tigeot 	tmp = RREG32(rec->en_data_reg);
629926deccbSFrançois Tigeot 
630926deccbSFrançois Tigeot 	/* */
631926deccbSFrançois Tigeot 	tmp = RREG32(RADEON_BIOS_6_SCRATCH);
632926deccbSFrançois Tigeot 	WREG32(RADEON_BIOS_6_SCRATCH, tmp | ATOM_S6_HW_I2C_BUSY_STATE);
633926deccbSFrançois Tigeot 	saved1 = RREG32(AVIVO_DC_I2C_CONTROL1);
634926deccbSFrançois Tigeot 	saved2 = RREG32(0x494);
635926deccbSFrançois Tigeot 	WREG32(0x494, saved2 | 0x1);
636926deccbSFrançois Tigeot 
637926deccbSFrançois Tigeot 	WREG32(AVIVO_DC_I2C_ARBITRATION, AVIVO_DC_I2C_SW_WANTS_TO_USE_I2C);
638926deccbSFrançois Tigeot 	for (i = 0; i < 50; i++) {
639c4ef309bSzrj 		udelay(1);
640926deccbSFrançois Tigeot 		if (RREG32(AVIVO_DC_I2C_ARBITRATION) & AVIVO_DC_I2C_SW_CAN_USE_I2C)
641926deccbSFrançois Tigeot 			break;
642926deccbSFrançois Tigeot 	}
643926deccbSFrançois Tigeot 	if (i == 50) {
644926deccbSFrançois Tigeot 		DRM_ERROR("failed to get i2c bus\n");
6455ef6d7b4SFrançois Tigeot 		ret = -EBUSY;
646926deccbSFrançois Tigeot 		goto done;
647926deccbSFrançois Tigeot 	}
648926deccbSFrançois Tigeot 
649926deccbSFrançois Tigeot 	reg = AVIVO_DC_I2C_START | AVIVO_DC_I2C_STOP | AVIVO_DC_I2C_EN;
650926deccbSFrançois Tigeot 	switch (rec->mask_clk_reg) {
651926deccbSFrançois Tigeot 	case AVIVO_DC_GPIO_DDC1_MASK:
652926deccbSFrançois Tigeot 		reg |= AVIVO_DC_I2C_PIN_SELECT(AVIVO_SEL_DDC1);
653926deccbSFrançois Tigeot 		break;
654926deccbSFrançois Tigeot 	case AVIVO_DC_GPIO_DDC2_MASK:
655926deccbSFrançois Tigeot 		reg |= AVIVO_DC_I2C_PIN_SELECT(AVIVO_SEL_DDC2);
656926deccbSFrançois Tigeot 		break;
657926deccbSFrançois Tigeot 	case AVIVO_DC_GPIO_DDC3_MASK:
658926deccbSFrançois Tigeot 		reg |= AVIVO_DC_I2C_PIN_SELECT(AVIVO_SEL_DDC3);
659926deccbSFrançois Tigeot 		break;
660926deccbSFrançois Tigeot 	default:
661926deccbSFrançois Tigeot 		DRM_ERROR("gpio not supported with hw i2c\n");
6625ef6d7b4SFrançois Tigeot 		ret = -EINVAL;
663926deccbSFrançois Tigeot 		goto done;
664926deccbSFrançois Tigeot 	}
665926deccbSFrançois Tigeot 
666926deccbSFrançois Tigeot 	/* check for bus probe */
667926deccbSFrançois Tigeot 	p = &msgs[0];
668926deccbSFrançois Tigeot 	if ((num == 1) && (p->len == 0)) {
669926deccbSFrançois Tigeot 		WREG32(AVIVO_DC_I2C_STATUS1, (AVIVO_DC_I2C_DONE |
670926deccbSFrançois Tigeot 					      AVIVO_DC_I2C_NACK |
671926deccbSFrançois Tigeot 					      AVIVO_DC_I2C_HALT));
672926deccbSFrançois Tigeot 		WREG32(AVIVO_DC_I2C_RESET, AVIVO_DC_I2C_SOFT_RESET);
673c4ef309bSzrj 		udelay(1);
674926deccbSFrançois Tigeot 		WREG32(AVIVO_DC_I2C_RESET, 0);
675926deccbSFrançois Tigeot 
6765ef6d7b4SFrançois Tigeot 		WREG32(AVIVO_DC_I2C_DATA, (p->addr << 1) & 0xff);
677926deccbSFrançois Tigeot 		WREG32(AVIVO_DC_I2C_DATA, 0);
678926deccbSFrançois Tigeot 
679926deccbSFrançois Tigeot 		WREG32(AVIVO_DC_I2C_CONTROL3, AVIVO_DC_I2C_TIME_LIMIT(48));
680926deccbSFrançois Tigeot 		WREG32(AVIVO_DC_I2C_CONTROL2, (AVIVO_DC_I2C_ADDR_COUNT(1) |
681926deccbSFrançois Tigeot 					       AVIVO_DC_I2C_DATA_COUNT(1) |
682926deccbSFrançois Tigeot 					       (prescale << 16)));
683926deccbSFrançois Tigeot 		WREG32(AVIVO_DC_I2C_CONTROL1, reg);
684926deccbSFrançois Tigeot 		WREG32(AVIVO_DC_I2C_STATUS1, AVIVO_DC_I2C_GO);
685926deccbSFrançois Tigeot 		for (j = 0; j < 200; j++) {
686c4ef309bSzrj 			udelay(50);
687926deccbSFrançois Tigeot 			tmp = RREG32(AVIVO_DC_I2C_STATUS1);
688926deccbSFrançois Tigeot 			if (tmp & AVIVO_DC_I2C_GO)
689926deccbSFrançois Tigeot 				continue;
690926deccbSFrançois Tigeot 			tmp = RREG32(AVIVO_DC_I2C_STATUS1);
691926deccbSFrançois Tigeot 			if (tmp & AVIVO_DC_I2C_DONE)
692926deccbSFrançois Tigeot 				break;
693926deccbSFrançois Tigeot 			else {
694926deccbSFrançois Tigeot 				DRM_DEBUG("i2c write error 0x%08x\n", tmp);
695926deccbSFrançois Tigeot 				WREG32(AVIVO_DC_I2C_RESET, AVIVO_DC_I2C_ABORT);
6965ef6d7b4SFrançois Tigeot 				ret = -EIO;
697926deccbSFrançois Tigeot 				goto done;
698926deccbSFrançois Tigeot 			}
699926deccbSFrançois Tigeot 		}
700926deccbSFrançois Tigeot 		goto done;
701926deccbSFrançois Tigeot 	}
702926deccbSFrançois Tigeot 
703926deccbSFrançois Tigeot 	for (i = 0; i < num; i++) {
704926deccbSFrançois Tigeot 		p = &msgs[i];
705926deccbSFrançois Tigeot 		remaining = p->len;
706926deccbSFrançois Tigeot 		buffer_offset = 0;
7075ef6d7b4SFrançois Tigeot 		if (p->flags & I2C_M_RD) {
708926deccbSFrançois Tigeot 			while (remaining) {
709926deccbSFrançois Tigeot 				if (remaining > 15)
710926deccbSFrançois Tigeot 					current_count = 15;
711926deccbSFrançois Tigeot 				else
712926deccbSFrançois Tigeot 					current_count = remaining;
713926deccbSFrançois Tigeot 				WREG32(AVIVO_DC_I2C_STATUS1, (AVIVO_DC_I2C_DONE |
714926deccbSFrançois Tigeot 							      AVIVO_DC_I2C_NACK |
715926deccbSFrançois Tigeot 							      AVIVO_DC_I2C_HALT));
716926deccbSFrançois Tigeot 				WREG32(AVIVO_DC_I2C_RESET, AVIVO_DC_I2C_SOFT_RESET);
717c4ef309bSzrj 				udelay(1);
718926deccbSFrançois Tigeot 				WREG32(AVIVO_DC_I2C_RESET, 0);
719926deccbSFrançois Tigeot 
7205ef6d7b4SFrançois Tigeot 				WREG32(AVIVO_DC_I2C_DATA, ((p->addr << 1) & 0xff) | 0x1);
721926deccbSFrançois Tigeot 				WREG32(AVIVO_DC_I2C_CONTROL3, AVIVO_DC_I2C_TIME_LIMIT(48));
722926deccbSFrançois Tigeot 				WREG32(AVIVO_DC_I2C_CONTROL2, (AVIVO_DC_I2C_ADDR_COUNT(1) |
723926deccbSFrançois Tigeot 							       AVIVO_DC_I2C_DATA_COUNT(current_count) |
724926deccbSFrançois Tigeot 							       (prescale << 16)));
725926deccbSFrançois Tigeot 				WREG32(AVIVO_DC_I2C_CONTROL1, reg | AVIVO_DC_I2C_RECEIVE);
726926deccbSFrançois Tigeot 				WREG32(AVIVO_DC_I2C_STATUS1, AVIVO_DC_I2C_GO);
727926deccbSFrançois Tigeot 				for (j = 0; j < 200; j++) {
728c4ef309bSzrj 					udelay(50);
729926deccbSFrançois Tigeot 					tmp = RREG32(AVIVO_DC_I2C_STATUS1);
730926deccbSFrançois Tigeot 					if (tmp & AVIVO_DC_I2C_GO)
731926deccbSFrançois Tigeot 						continue;
732926deccbSFrançois Tigeot 					tmp = RREG32(AVIVO_DC_I2C_STATUS1);
733926deccbSFrançois Tigeot 					if (tmp & AVIVO_DC_I2C_DONE)
734926deccbSFrançois Tigeot 						break;
735926deccbSFrançois Tigeot 					else {
736926deccbSFrançois Tigeot 						DRM_DEBUG("i2c read error 0x%08x\n", tmp);
737926deccbSFrançois Tigeot 						WREG32(AVIVO_DC_I2C_RESET, AVIVO_DC_I2C_ABORT);
7385ef6d7b4SFrançois Tigeot 						ret = -EIO;
739926deccbSFrançois Tigeot 						goto done;
740926deccbSFrançois Tigeot 					}
741926deccbSFrançois Tigeot 				}
742926deccbSFrançois Tigeot 				for (j = 0; j < current_count; j++)
743926deccbSFrançois Tigeot 					p->buf[buffer_offset + j] = RREG32(AVIVO_DC_I2C_DATA) & 0xff;
744926deccbSFrançois Tigeot 				remaining -= current_count;
745926deccbSFrançois Tigeot 				buffer_offset += current_count;
746926deccbSFrançois Tigeot 			}
747926deccbSFrançois Tigeot 		} else {
748926deccbSFrançois Tigeot 			while (remaining) {
749926deccbSFrançois Tigeot 				if (remaining > 15)
750926deccbSFrançois Tigeot 					current_count = 15;
751926deccbSFrançois Tigeot 				else
752926deccbSFrançois Tigeot 					current_count = remaining;
753926deccbSFrançois Tigeot 				WREG32(AVIVO_DC_I2C_STATUS1, (AVIVO_DC_I2C_DONE |
754926deccbSFrançois Tigeot 							      AVIVO_DC_I2C_NACK |
755926deccbSFrançois Tigeot 							      AVIVO_DC_I2C_HALT));
756926deccbSFrançois Tigeot 				WREG32(AVIVO_DC_I2C_RESET, AVIVO_DC_I2C_SOFT_RESET);
757c4ef309bSzrj 				udelay(1);
758926deccbSFrançois Tigeot 				WREG32(AVIVO_DC_I2C_RESET, 0);
759926deccbSFrançois Tigeot 
7605ef6d7b4SFrançois Tigeot 				WREG32(AVIVO_DC_I2C_DATA, (p->addr << 1) & 0xff);
761926deccbSFrançois Tigeot 				for (j = 0; j < current_count; j++)
762926deccbSFrançois Tigeot 					WREG32(AVIVO_DC_I2C_DATA, p->buf[buffer_offset + j]);
763926deccbSFrançois Tigeot 
764926deccbSFrançois Tigeot 				WREG32(AVIVO_DC_I2C_CONTROL3, AVIVO_DC_I2C_TIME_LIMIT(48));
765926deccbSFrançois Tigeot 				WREG32(AVIVO_DC_I2C_CONTROL2, (AVIVO_DC_I2C_ADDR_COUNT(1) |
766926deccbSFrançois Tigeot 							       AVIVO_DC_I2C_DATA_COUNT(current_count) |
767926deccbSFrançois Tigeot 							       (prescale << 16)));
768926deccbSFrançois Tigeot 				WREG32(AVIVO_DC_I2C_CONTROL1, reg);
769926deccbSFrançois Tigeot 				WREG32(AVIVO_DC_I2C_STATUS1, AVIVO_DC_I2C_GO);
770926deccbSFrançois Tigeot 				for (j = 0; j < 200; j++) {
771c4ef309bSzrj 					udelay(50);
772926deccbSFrançois Tigeot 					tmp = RREG32(AVIVO_DC_I2C_STATUS1);
773926deccbSFrançois Tigeot 					if (tmp & AVIVO_DC_I2C_GO)
774926deccbSFrançois Tigeot 						continue;
775926deccbSFrançois Tigeot 					tmp = RREG32(AVIVO_DC_I2C_STATUS1);
776926deccbSFrançois Tigeot 					if (tmp & AVIVO_DC_I2C_DONE)
777926deccbSFrançois Tigeot 						break;
778926deccbSFrançois Tigeot 					else {
779926deccbSFrançois Tigeot 						DRM_DEBUG("i2c write error 0x%08x\n", tmp);
780926deccbSFrançois Tigeot 						WREG32(AVIVO_DC_I2C_RESET, AVIVO_DC_I2C_ABORT);
7815ef6d7b4SFrançois Tigeot 						ret = -EIO;
782926deccbSFrançois Tigeot 						goto done;
783926deccbSFrançois Tigeot 					}
784926deccbSFrançois Tigeot 				}
785926deccbSFrançois Tigeot 				remaining -= current_count;
786926deccbSFrançois Tigeot 				buffer_offset += current_count;
787926deccbSFrançois Tigeot 			}
788926deccbSFrançois Tigeot 		}
789926deccbSFrançois Tigeot 	}
790926deccbSFrançois Tigeot 
791926deccbSFrançois Tigeot done:
792926deccbSFrançois Tigeot 	WREG32(AVIVO_DC_I2C_STATUS1, (AVIVO_DC_I2C_DONE |
793926deccbSFrançois Tigeot 				      AVIVO_DC_I2C_NACK |
794926deccbSFrançois Tigeot 				      AVIVO_DC_I2C_HALT));
795926deccbSFrançois Tigeot 	WREG32(AVIVO_DC_I2C_RESET, AVIVO_DC_I2C_SOFT_RESET);
796c4ef309bSzrj 	udelay(1);
797926deccbSFrançois Tigeot 	WREG32(AVIVO_DC_I2C_RESET, 0);
798926deccbSFrançois Tigeot 
799926deccbSFrançois Tigeot 	WREG32(AVIVO_DC_I2C_ARBITRATION, AVIVO_DC_I2C_SW_DONE_USING_I2C);
800926deccbSFrançois Tigeot 	WREG32(AVIVO_DC_I2C_CONTROL1, saved1);
801926deccbSFrançois Tigeot 	WREG32(0x494, saved2);
802926deccbSFrançois Tigeot 	tmp = RREG32(RADEON_BIOS_6_SCRATCH);
803926deccbSFrançois Tigeot 	tmp &= ~ATOM_S6_HW_I2C_BUSY_STATE;
804926deccbSFrançois Tigeot 	WREG32(RADEON_BIOS_6_SCRATCH, tmp);
805926deccbSFrançois Tigeot 
8065ef6d7b4SFrançois Tigeot 	mutex_unlock(&rdev->pm.mutex);
8075ef6d7b4SFrançois Tigeot 	mutex_unlock(&rdev->dc_hw_i2c_mutex);
808926deccbSFrançois Tigeot 
809926deccbSFrançois Tigeot 	return ret;
810926deccbSFrançois Tigeot }
811926deccbSFrançois Tigeot 
radeon_hw_i2c_xfer(struct i2c_adapter * i2c_adap,struct i2c_msg * msgs,int num)8125ef6d7b4SFrançois Tigeot static int radeon_hw_i2c_xfer(struct i2c_adapter *i2c_adap,
8135ef6d7b4SFrançois Tigeot 			      struct i2c_msg *msgs, int num)
814926deccbSFrançois Tigeot {
8155ef6d7b4SFrançois Tigeot 	struct radeon_i2c_chan *i2c = i2c_get_adapdata(i2c_adap);
816926deccbSFrançois Tigeot 	struct radeon_device *rdev = i2c->dev->dev_private;
817926deccbSFrançois Tigeot 	struct radeon_i2c_bus_rec *rec = &i2c->rec;
818926deccbSFrançois Tigeot 	int ret = 0;
819926deccbSFrançois Tigeot 
8205ef6d7b4SFrançois Tigeot 	mutex_lock(&i2c->mutex);
8217191d616Szrj 
822926deccbSFrançois Tigeot 	switch (rdev->family) {
823926deccbSFrançois Tigeot 	case CHIP_R100:
824926deccbSFrançois Tigeot 	case CHIP_RV100:
825926deccbSFrançois Tigeot 	case CHIP_RS100:
826926deccbSFrançois Tigeot 	case CHIP_RV200:
827926deccbSFrançois Tigeot 	case CHIP_RS200:
828926deccbSFrançois Tigeot 	case CHIP_R200:
829926deccbSFrançois Tigeot 	case CHIP_RV250:
830926deccbSFrançois Tigeot 	case CHIP_RS300:
831926deccbSFrançois Tigeot 	case CHIP_RV280:
832926deccbSFrançois Tigeot 	case CHIP_R300:
833926deccbSFrançois Tigeot 	case CHIP_R350:
834926deccbSFrançois Tigeot 	case CHIP_RV350:
835926deccbSFrançois Tigeot 	case CHIP_RV380:
836926deccbSFrançois Tigeot 	case CHIP_R420:
837926deccbSFrançois Tigeot 	case CHIP_R423:
838926deccbSFrançois Tigeot 	case CHIP_RV410:
839926deccbSFrançois Tigeot 	case CHIP_RS400:
840926deccbSFrançois Tigeot 	case CHIP_RS480:
8415ef6d7b4SFrançois Tigeot 		ret = r100_hw_i2c_xfer(i2c_adap, msgs, num);
842926deccbSFrançois Tigeot 		break;
843926deccbSFrançois Tigeot 	case CHIP_RS600:
844926deccbSFrançois Tigeot 	case CHIP_RS690:
845926deccbSFrançois Tigeot 	case CHIP_RS740:
846926deccbSFrançois Tigeot 		/* XXX fill in hw i2c implementation */
847926deccbSFrançois Tigeot 		break;
848926deccbSFrançois Tigeot 	case CHIP_RV515:
849926deccbSFrançois Tigeot 	case CHIP_R520:
850926deccbSFrançois Tigeot 	case CHIP_RV530:
851926deccbSFrançois Tigeot 	case CHIP_RV560:
852926deccbSFrançois Tigeot 	case CHIP_RV570:
853926deccbSFrançois Tigeot 	case CHIP_R580:
854926deccbSFrançois Tigeot 		if (rec->mm_i2c)
8555ef6d7b4SFrançois Tigeot 			ret = r100_hw_i2c_xfer(i2c_adap, msgs, num);
856926deccbSFrançois Tigeot 		else
8575ef6d7b4SFrançois Tigeot 			ret = r500_hw_i2c_xfer(i2c_adap, msgs, num);
858926deccbSFrançois Tigeot 		break;
859926deccbSFrançois Tigeot 	case CHIP_R600:
860926deccbSFrançois Tigeot 	case CHIP_RV610:
861926deccbSFrançois Tigeot 	case CHIP_RV630:
862926deccbSFrançois Tigeot 	case CHIP_RV670:
863926deccbSFrançois Tigeot 		/* XXX fill in hw i2c implementation */
864926deccbSFrançois Tigeot 		break;
865926deccbSFrançois Tigeot 	case CHIP_RV620:
866926deccbSFrançois Tigeot 	case CHIP_RV635:
867926deccbSFrançois Tigeot 	case CHIP_RS780:
868926deccbSFrançois Tigeot 	case CHIP_RS880:
869926deccbSFrançois Tigeot 	case CHIP_RV770:
870926deccbSFrançois Tigeot 	case CHIP_RV730:
871926deccbSFrançois Tigeot 	case CHIP_RV710:
872926deccbSFrançois Tigeot 	case CHIP_RV740:
873926deccbSFrançois Tigeot 		/* XXX fill in hw i2c implementation */
874926deccbSFrançois Tigeot 		break;
875926deccbSFrançois Tigeot 	case CHIP_CEDAR:
876926deccbSFrançois Tigeot 	case CHIP_REDWOOD:
877926deccbSFrançois Tigeot 	case CHIP_JUNIPER:
878926deccbSFrançois Tigeot 	case CHIP_CYPRESS:
879926deccbSFrançois Tigeot 	case CHIP_HEMLOCK:
880926deccbSFrançois Tigeot 		/* XXX fill in hw i2c implementation */
881926deccbSFrançois Tigeot 		break;
882926deccbSFrançois Tigeot 	default:
883926deccbSFrançois Tigeot 		DRM_ERROR("i2c: unhandled radeon chip\n");
8845ef6d7b4SFrançois Tigeot 		ret = -EIO;
885926deccbSFrançois Tigeot 		break;
886926deccbSFrançois Tigeot 	}
887926deccbSFrançois Tigeot 
8885ef6d7b4SFrançois Tigeot 	mutex_unlock(&i2c->mutex);
8897191d616Szrj 
890926deccbSFrançois Tigeot 	return ret;
891926deccbSFrançois Tigeot }
892926deccbSFrançois Tigeot 
radeon_hw_i2c_func(struct i2c_adapter * adap)8935ef6d7b4SFrançois Tigeot static u32 radeon_hw_i2c_func(struct i2c_adapter *adap)
894926deccbSFrançois Tigeot {
8955ef6d7b4SFrançois Tigeot 	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
896926deccbSFrançois Tigeot }
897926deccbSFrançois Tigeot 
8985ef6d7b4SFrançois Tigeot static const struct i2c_algorithm radeon_i2c_algo = {
8995ef6d7b4SFrançois Tigeot 	.master_xfer = radeon_hw_i2c_xfer,
9005ef6d7b4SFrançois Tigeot 	.functionality = radeon_hw_i2c_func,
901926deccbSFrançois Tigeot };
902926deccbSFrançois Tigeot 
9035ef6d7b4SFrançois Tigeot static const struct i2c_algorithm radeon_atom_i2c_algo = {
9045ef6d7b4SFrançois Tigeot 	.master_xfer = radeon_atom_hw_i2c_xfer,
9055ef6d7b4SFrançois Tigeot 	.functionality = radeon_atom_hw_i2c_func,
906926deccbSFrançois Tigeot };
907926deccbSFrançois Tigeot 
radeon_i2c_create(struct drm_device * dev,struct radeon_i2c_bus_rec * rec,const char * name)908926deccbSFrançois Tigeot struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev,
909926deccbSFrançois Tigeot 					  struct radeon_i2c_bus_rec *rec,
910926deccbSFrançois Tigeot 					  const char *name)
911926deccbSFrançois Tigeot {
912926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
913926deccbSFrançois Tigeot 	struct radeon_i2c_chan *i2c;
914926deccbSFrançois Tigeot 	int ret;
915926deccbSFrançois Tigeot 
916926deccbSFrançois Tigeot 	/* don't add the mm_i2c bus unless hw_i2c is enabled */
917926deccbSFrançois Tigeot 	if (rec->mm_i2c && (radeon_hw_i2c == 0))
918926deccbSFrançois Tigeot 		return NULL;
919926deccbSFrançois Tigeot 
920c4ef309bSzrj 	i2c = kzalloc(sizeof(struct radeon_i2c_chan), GFP_KERNEL);
921926deccbSFrançois Tigeot 	if (i2c == NULL)
922926deccbSFrançois Tigeot 		return NULL;
923926deccbSFrançois Tigeot 
924926deccbSFrançois Tigeot 	i2c->rec = *rec;
9255ef6d7b4SFrançois Tigeot #if 0
9265ef6d7b4SFrançois Tigeot 	i2c->adapter.owner = THIS_MODULE;
9275ef6d7b4SFrançois Tigeot 	i2c->adapter.class = I2C_CLASS_DDC;
9285ef6d7b4SFrançois Tigeot #endif
9295ef6d7b4SFrançois Tigeot 	i2c->adapter.dev.parent = &dev->pdev->dev;
930926deccbSFrançois Tigeot 	i2c->dev = dev;
9315ef6d7b4SFrançois Tigeot 	i2c_set_adapdata(&i2c->adapter, i2c);
9327191d616Szrj 	lockinit(&i2c->mutex, "ri2cmtx", 0, LK_CANRECURSE);
933926deccbSFrançois Tigeot 	if (rec->mm_i2c ||
934926deccbSFrançois Tigeot 	    (rec->hw_capable &&
935926deccbSFrançois Tigeot 	     radeon_hw_i2c &&
936926deccbSFrançois Tigeot 	     ((rdev->family <= CHIP_RS480) ||
937926deccbSFrançois Tigeot 	      ((rdev->family >= CHIP_RV515) && (rdev->family <= CHIP_R580))))) {
938926deccbSFrançois Tigeot 		/* set the radeon hw i2c adapter */
9395ef6d7b4SFrançois Tigeot 		snprintf(i2c->adapter.name, sizeof(i2c->adapter.name),
940926deccbSFrançois Tigeot 			 "Radeon i2c hw bus %s", name);
9415ef6d7b4SFrançois Tigeot 		i2c->adapter.algo = &radeon_i2c_algo;
9425ef6d7b4SFrançois Tigeot 		ret = i2c_add_adapter(&i2c->adapter);
943*1dedbd3bSFrançois Tigeot 		if (ret)
944926deccbSFrançois Tigeot 			goto out_free;
945926deccbSFrançois Tigeot 	} else if (rec->hw_capable &&
946926deccbSFrançois Tigeot 		   radeon_hw_i2c &&
947926deccbSFrançois Tigeot 		   ASIC_IS_DCE3(rdev)) {
948926deccbSFrançois Tigeot 		/* hw i2c using atom */
9495ef6d7b4SFrançois Tigeot 		snprintf(i2c->adapter.name, sizeof(i2c->adapter.name),
950926deccbSFrançois Tigeot 			 "Radeon i2c hw bus %s", name);
9515ef6d7b4SFrançois Tigeot 		i2c->adapter.algo = &radeon_atom_i2c_algo;
9525ef6d7b4SFrançois Tigeot 		ret = i2c_add_adapter(&i2c->adapter);
953*1dedbd3bSFrançois Tigeot 		if (ret)
954926deccbSFrançois Tigeot 			goto out_free;
955926deccbSFrançois Tigeot 	} else {
956926deccbSFrançois Tigeot 		/* set the radeon bit adapter */
9575ef6d7b4SFrançois Tigeot 		snprintf(i2c->adapter.name, sizeof(i2c->adapter.name),
958926deccbSFrançois Tigeot 			 "Radeon i2c bit bus %s", name);
9595ef6d7b4SFrançois Tigeot 		i2c->adapter.algo_data = &i2c->bit;
9605ef6d7b4SFrançois Tigeot 		i2c->bit.pre_xfer = pre_xfer;
9615ef6d7b4SFrançois Tigeot 		i2c->bit.post_xfer = post_xfer;
9625ef6d7b4SFrançois Tigeot 		i2c->bit.setsda = set_data;
9635ef6d7b4SFrançois Tigeot 		i2c->bit.setscl = set_clock;
9645ef6d7b4SFrançois Tigeot 		i2c->bit.getsda = get_data;
9655ef6d7b4SFrançois Tigeot 		i2c->bit.getscl = get_clock;
9665ef6d7b4SFrançois Tigeot 		i2c->bit.udelay = 10;
9675ef6d7b4SFrançois Tigeot 		i2c->bit.timeout = usecs_to_jiffies(2200);	/* from VESA */
9685ef6d7b4SFrançois Tigeot 		i2c->bit.data = i2c;
9695ef6d7b4SFrançois Tigeot 		ret = i2c_bit_add_bus(&i2c->adapter);
970ee479021SImre Vadász 		if (ret) {
9715ef6d7b4SFrançois Tigeot 			DRM_ERROR("Failed to register bit i2c %s\n", name);
972ee479021SImre Vadász 			goto out_free;
973ee479021SImre Vadász 		}
9745ef6d7b4SFrançois Tigeot 	}
975ee479021SImre Vadász 
976ee479021SImre Vadász 	return i2c;
977ee479021SImre Vadász out_free:
978ee479021SImre Vadász 	kfree(i2c);
979ee479021SImre Vadász 	return NULL;
980ee479021SImre Vadász 
981ee479021SImre Vadász }
982ee479021SImre Vadász 
radeon_i2c_destroy(struct radeon_i2c_chan * i2c)983926deccbSFrançois Tigeot void radeon_i2c_destroy(struct radeon_i2c_chan *i2c)
984926deccbSFrançois Tigeot {
985926deccbSFrançois Tigeot 	if (!i2c)
986926deccbSFrançois Tigeot 		return;
987*1dedbd3bSFrançois Tigeot 	WARN_ON(i2c->has_aux);
9885ef6d7b4SFrançois Tigeot 	i2c_del_adapter(&i2c->adapter);
989c4ef309bSzrj 	kfree(i2c);
990926deccbSFrançois Tigeot }
991926deccbSFrançois Tigeot 
992926deccbSFrançois Tigeot /* Add the default buses */
radeon_i2c_init(struct radeon_device * rdev)993926deccbSFrançois Tigeot void radeon_i2c_init(struct radeon_device *rdev)
994926deccbSFrançois Tigeot {
995c6f73aabSFrançois Tigeot 	if (radeon_hw_i2c)
996c6f73aabSFrançois Tigeot 		DRM_INFO("hw_i2c forced on, you may experience display detection problems!\n");
997c6f73aabSFrançois Tigeot 
998926deccbSFrançois Tigeot 	if (rdev->is_atom_bios)
999926deccbSFrançois Tigeot 		radeon_atombios_i2c_init(rdev);
1000926deccbSFrançois Tigeot 	else
1001926deccbSFrançois Tigeot 		radeon_combios_i2c_init(rdev);
1002926deccbSFrançois Tigeot }
1003926deccbSFrançois Tigeot 
1004926deccbSFrançois Tigeot /* remove all the buses */
radeon_i2c_fini(struct radeon_device * rdev)1005926deccbSFrançois Tigeot void radeon_i2c_fini(struct radeon_device *rdev)
1006926deccbSFrançois Tigeot {
1007926deccbSFrançois Tigeot 	int i;
1008926deccbSFrançois Tigeot 
1009926deccbSFrançois Tigeot 	for (i = 0; i < RADEON_MAX_I2C_BUS; i++) {
1010926deccbSFrançois Tigeot 		if (rdev->i2c_bus[i]) {
1011926deccbSFrançois Tigeot 			radeon_i2c_destroy(rdev->i2c_bus[i]);
1012926deccbSFrançois Tigeot 			rdev->i2c_bus[i] = NULL;
1013926deccbSFrançois Tigeot 		}
1014926deccbSFrançois Tigeot 	}
1015926deccbSFrançois Tigeot }
1016926deccbSFrançois Tigeot 
1017926deccbSFrançois Tigeot /* Add additional buses */
radeon_i2c_add(struct radeon_device * rdev,struct radeon_i2c_bus_rec * rec,const char * name)1018926deccbSFrançois Tigeot void radeon_i2c_add(struct radeon_device *rdev,
1019926deccbSFrançois Tigeot 		    struct radeon_i2c_bus_rec *rec,
1020926deccbSFrançois Tigeot 		    const char *name)
1021926deccbSFrançois Tigeot {
1022926deccbSFrançois Tigeot 	struct drm_device *dev = rdev->ddev;
1023926deccbSFrançois Tigeot 	int i;
1024926deccbSFrançois Tigeot 
1025926deccbSFrançois Tigeot 	for (i = 0; i < RADEON_MAX_I2C_BUS; i++) {
1026926deccbSFrançois Tigeot 		if (!rdev->i2c_bus[i]) {
1027926deccbSFrançois Tigeot 			rdev->i2c_bus[i] = radeon_i2c_create(dev, rec, name);
1028926deccbSFrançois Tigeot 			return;
1029926deccbSFrançois Tigeot 		}
1030926deccbSFrançois Tigeot 	}
1031926deccbSFrançois Tigeot }
1032926deccbSFrançois Tigeot 
1033926deccbSFrançois Tigeot /* looks up bus based on id */
radeon_i2c_lookup(struct radeon_device * rdev,struct radeon_i2c_bus_rec * i2c_bus)1034926deccbSFrançois Tigeot struct radeon_i2c_chan *radeon_i2c_lookup(struct radeon_device *rdev,
1035926deccbSFrançois Tigeot 					  struct radeon_i2c_bus_rec *i2c_bus)
1036926deccbSFrançois Tigeot {
1037926deccbSFrançois Tigeot 	int i;
1038926deccbSFrançois Tigeot 
1039926deccbSFrançois Tigeot 	for (i = 0; i < RADEON_MAX_I2C_BUS; i++) {
1040926deccbSFrançois Tigeot 		if (rdev->i2c_bus[i] &&
1041926deccbSFrançois Tigeot 		    (rdev->i2c_bus[i]->rec.i2c_id == i2c_bus->i2c_id)) {
1042926deccbSFrançois Tigeot 			return rdev->i2c_bus[i];
1043926deccbSFrançois Tigeot 		}
1044926deccbSFrançois Tigeot 	}
1045926deccbSFrançois Tigeot 	return NULL;
1046926deccbSFrançois Tigeot }
1047926deccbSFrançois Tigeot 
radeon_i2c_get_byte(struct radeon_i2c_chan * i2c_bus,u8 slave_addr,u8 addr,u8 * val)1048926deccbSFrançois Tigeot void radeon_i2c_get_byte(struct radeon_i2c_chan *i2c_bus,
1049926deccbSFrançois Tigeot 			 u8 slave_addr,
1050926deccbSFrançois Tigeot 			 u8 addr,
1051926deccbSFrançois Tigeot 			 u8 *val)
1052926deccbSFrançois Tigeot {
1053926deccbSFrançois Tigeot 	u8 out_buf[2];
1054926deccbSFrançois Tigeot 	u8 in_buf[2];
10555ef6d7b4SFrançois Tigeot 	struct i2c_msg msgs[] = {
1056926deccbSFrançois Tigeot 		{
10575ef6d7b4SFrançois Tigeot 			.addr = slave_addr,
1058926deccbSFrançois Tigeot 			.flags = 0,
1059926deccbSFrançois Tigeot 			.len = 1,
1060926deccbSFrançois Tigeot 			.buf = out_buf,
1061926deccbSFrançois Tigeot 		},
1062926deccbSFrançois Tigeot 		{
10635ef6d7b4SFrançois Tigeot 			.addr = slave_addr,
10645ef6d7b4SFrançois Tigeot 			.flags = I2C_M_RD,
1065926deccbSFrançois Tigeot 			.len = 1,
1066926deccbSFrançois Tigeot 			.buf = in_buf,
1067926deccbSFrançois Tigeot 		}
1068926deccbSFrançois Tigeot 	};
1069926deccbSFrançois Tigeot 
1070926deccbSFrançois Tigeot 	out_buf[0] = addr;
1071926deccbSFrançois Tigeot 	out_buf[1] = 0;
1072926deccbSFrançois Tigeot 
10735ef6d7b4SFrançois Tigeot 	if (i2c_transfer(&i2c_bus->adapter, msgs, 2) == 2) {
1074926deccbSFrançois Tigeot 		*val = in_buf[0];
1075926deccbSFrançois Tigeot 		DRM_DEBUG("val = 0x%02x\n", *val);
1076926deccbSFrançois Tigeot 	} else {
1077926deccbSFrançois Tigeot 		DRM_DEBUG("i2c 0x%02x 0x%02x read failed\n",
1078926deccbSFrançois Tigeot 			  addr, *val);
1079926deccbSFrançois Tigeot 	}
1080926deccbSFrançois Tigeot }
1081926deccbSFrançois Tigeot 
radeon_i2c_put_byte(struct radeon_i2c_chan * i2c_bus,u8 slave_addr,u8 addr,u8 val)1082926deccbSFrançois Tigeot void radeon_i2c_put_byte(struct radeon_i2c_chan *i2c_bus,
1083926deccbSFrançois Tigeot 			 u8 slave_addr,
1084926deccbSFrançois Tigeot 			 u8 addr,
1085926deccbSFrançois Tigeot 			 u8 val)
1086926deccbSFrançois Tigeot {
1087926deccbSFrançois Tigeot 	uint8_t out_buf[2];
10885ef6d7b4SFrançois Tigeot 	struct i2c_msg msg = {
10895ef6d7b4SFrançois Tigeot 		.addr = slave_addr,
1090926deccbSFrançois Tigeot 		.flags = 0,
1091926deccbSFrançois Tigeot 		.len = 2,
1092926deccbSFrançois Tigeot 		.buf = out_buf,
1093926deccbSFrançois Tigeot 	};
1094926deccbSFrançois Tigeot 
1095926deccbSFrançois Tigeot 	out_buf[0] = addr;
1096926deccbSFrançois Tigeot 	out_buf[1] = val;
1097926deccbSFrançois Tigeot 
10985ef6d7b4SFrançois Tigeot 	if (i2c_transfer(&i2c_bus->adapter, &msg, 1) != 1)
1099926deccbSFrançois Tigeot 		DRM_DEBUG("i2c 0x%02x 0x%02x write failed\n",
1100926deccbSFrançois Tigeot 			  addr, val);
1101926deccbSFrançois Tigeot }
1102926deccbSFrançois Tigeot 
1103926deccbSFrançois Tigeot /* ddc router switching */
radeon_router_select_ddc_port(struct radeon_connector * radeon_connector)1104926deccbSFrançois Tigeot void radeon_router_select_ddc_port(struct radeon_connector *radeon_connector)
1105926deccbSFrançois Tigeot {
1106926deccbSFrançois Tigeot 	u8 val;
1107926deccbSFrançois Tigeot 
1108926deccbSFrançois Tigeot 	if (!radeon_connector->router.ddc_valid)
1109926deccbSFrançois Tigeot 		return;
1110926deccbSFrançois Tigeot 
1111926deccbSFrançois Tigeot 	if (!radeon_connector->router_bus)
1112926deccbSFrançois Tigeot 		return;
1113926deccbSFrançois Tigeot 
1114926deccbSFrançois Tigeot 	radeon_i2c_get_byte(radeon_connector->router_bus,
1115926deccbSFrançois Tigeot 			    radeon_connector->router.i2c_addr,
1116926deccbSFrançois Tigeot 			    0x3, &val);
1117926deccbSFrançois Tigeot 	val &= ~radeon_connector->router.ddc_mux_control_pin;
1118926deccbSFrançois Tigeot 	radeon_i2c_put_byte(radeon_connector->router_bus,
1119926deccbSFrançois Tigeot 			    radeon_connector->router.i2c_addr,
1120926deccbSFrançois Tigeot 			    0x3, val);
1121926deccbSFrançois Tigeot 	radeon_i2c_get_byte(radeon_connector->router_bus,
1122926deccbSFrançois Tigeot 			    radeon_connector->router.i2c_addr,
1123926deccbSFrançois Tigeot 			    0x1, &val);
1124926deccbSFrançois Tigeot 	val &= ~radeon_connector->router.ddc_mux_control_pin;
1125926deccbSFrançois Tigeot 	val |= radeon_connector->router.ddc_mux_state;
1126926deccbSFrançois Tigeot 	radeon_i2c_put_byte(radeon_connector->router_bus,
1127926deccbSFrançois Tigeot 			    radeon_connector->router.i2c_addr,
1128926deccbSFrançois Tigeot 			    0x1, val);
1129926deccbSFrançois Tigeot }
1130926deccbSFrançois Tigeot 
1131926deccbSFrançois Tigeot /* clock/data router switching */
radeon_router_select_cd_port(struct radeon_connector * radeon_connector)1132926deccbSFrançois Tigeot void radeon_router_select_cd_port(struct radeon_connector *radeon_connector)
1133926deccbSFrançois Tigeot {
1134926deccbSFrançois Tigeot 	u8 val;
1135926deccbSFrançois Tigeot 
1136926deccbSFrançois Tigeot 	if (!radeon_connector->router.cd_valid)
1137926deccbSFrançois Tigeot 		return;
1138926deccbSFrançois Tigeot 
1139926deccbSFrançois Tigeot 	if (!radeon_connector->router_bus)
1140926deccbSFrançois Tigeot 		return;
1141926deccbSFrançois Tigeot 
1142926deccbSFrançois Tigeot 	radeon_i2c_get_byte(radeon_connector->router_bus,
1143926deccbSFrançois Tigeot 			    radeon_connector->router.i2c_addr,
1144926deccbSFrançois Tigeot 			    0x3, &val);
1145926deccbSFrançois Tigeot 	val &= ~radeon_connector->router.cd_mux_control_pin;
1146926deccbSFrançois Tigeot 	radeon_i2c_put_byte(radeon_connector->router_bus,
1147926deccbSFrançois Tigeot 			    radeon_connector->router.i2c_addr,
1148926deccbSFrançois Tigeot 			    0x3, val);
1149926deccbSFrançois Tigeot 	radeon_i2c_get_byte(radeon_connector->router_bus,
1150926deccbSFrançois Tigeot 			    radeon_connector->router.i2c_addr,
1151926deccbSFrançois Tigeot 			    0x1, &val);
1152926deccbSFrançois Tigeot 	val &= ~radeon_connector->router.cd_mux_control_pin;
1153926deccbSFrançois Tigeot 	val |= radeon_connector->router.cd_mux_state;
1154926deccbSFrançois Tigeot 	radeon_i2c_put_byte(radeon_connector->router_bus,
1155926deccbSFrançois Tigeot 			    radeon_connector->router.i2c_addr,
1156926deccbSFrançois Tigeot 			    0x1, val);
1157926deccbSFrançois Tigeot }
1158926deccbSFrançois Tigeot 
1159