xref: /dflybsd-src/sys/dev/drm/radeon/radeon_i2c.c (revision 7191d6163c85884463981b69f0a1e08823033eb1)
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  *
26926deccbSFrançois Tigeot  * $FreeBSD: head/sys/dev/drm2/radeon/radeon_i2c.c 254885 2013-08-25 19:37:15Z dumbbell $
27926deccbSFrançois Tigeot  */
28926deccbSFrançois Tigeot 
29926deccbSFrançois Tigeot #include <drm/drmP.h>
30926deccbSFrançois Tigeot #include <drm/drm_edid.h>
31926deccbSFrançois Tigeot #include <uapi_drm/radeon_drm.h>
32926deccbSFrançois Tigeot #include <bus/iicbus/iic.h>
33926deccbSFrançois Tigeot #include <bus/iicbus/iiconf.h>
34926deccbSFrançois Tigeot #include <bus/iicbus/iicbus.h>
35926deccbSFrançois Tigeot #include <sys/mplock2.h>
36926deccbSFrançois Tigeot #include "radeon.h"
37926deccbSFrançois Tigeot #include "atom.h"
38926deccbSFrançois Tigeot #include "iicbus_if.h"
39926deccbSFrançois Tigeot #include "iicbb_if.h"
40926deccbSFrançois Tigeot 
41926deccbSFrançois Tigeot /**
42926deccbSFrançois Tigeot  * radeon_ddc_probe
43926deccbSFrançois Tigeot  *
44926deccbSFrançois Tigeot  */
45926deccbSFrançois Tigeot bool radeon_ddc_probe(struct radeon_connector *radeon_connector, bool use_aux)
46926deccbSFrançois Tigeot {
47926deccbSFrançois Tigeot 	u8 out = 0x0;
48926deccbSFrançois Tigeot 	u8 buf[8];
49926deccbSFrançois Tigeot 	int ret;
50926deccbSFrançois Tigeot 	struct iic_msg msgs[] = {
51926deccbSFrançois Tigeot 		{
52926deccbSFrançois Tigeot 			.slave = DDC_ADDR << 1,
53926deccbSFrançois Tigeot 			.flags = 0,
54926deccbSFrançois Tigeot 			.len = 1,
55926deccbSFrançois Tigeot 			.buf = &out,
56926deccbSFrançois Tigeot 		},
57926deccbSFrançois Tigeot 		{
58926deccbSFrançois Tigeot 			.slave = DDC_ADDR << 1,
59926deccbSFrançois Tigeot 			.flags = IIC_M_RD,
60926deccbSFrançois Tigeot 			.len = 8,
61926deccbSFrançois Tigeot 			.buf = buf,
62926deccbSFrançois Tigeot 		}
63926deccbSFrançois Tigeot 	};
64926deccbSFrançois Tigeot 
65926deccbSFrançois Tigeot 	/* on hw with routers, select right port */
66926deccbSFrançois Tigeot 	if (radeon_connector->router.ddc_valid)
67926deccbSFrançois Tigeot 		radeon_router_select_ddc_port(radeon_connector);
68926deccbSFrançois Tigeot 
69926deccbSFrançois Tigeot 	if (use_aux) {
70926deccbSFrançois Tigeot 		struct radeon_connector_atom_dig *dig = radeon_connector->con_priv;
71926deccbSFrançois Tigeot 		ret = iicbus_transfer(dig->dp_i2c_bus->adapter, msgs, 2);
72926deccbSFrançois Tigeot 	} else {
73926deccbSFrançois Tigeot 		ret = iicbus_transfer(radeon_connector->ddc_bus->adapter, msgs, 2);
74926deccbSFrançois Tigeot 	}
75926deccbSFrançois Tigeot 
76926deccbSFrançois Tigeot 	if (ret != 0)
77926deccbSFrançois Tigeot 		/* Couldn't find an accessible DDC on this connector */
78926deccbSFrançois Tigeot 		return false;
79926deccbSFrançois Tigeot 	/* Probe also for valid EDID header
80926deccbSFrançois Tigeot 	 * EDID header starts with:
81926deccbSFrançois Tigeot 	 * 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00.
82926deccbSFrançois Tigeot 	 * Only the first 6 bytes must be valid as
83926deccbSFrançois Tigeot 	 * drm_edid_block_valid() can fix the last 2 bytes */
84926deccbSFrançois Tigeot 	if (drm_edid_header_is_valid(buf) < 6) {
85926deccbSFrançois Tigeot 		/* Couldn't find an accessible EDID on this
86926deccbSFrançois Tigeot 		 * connector */
87926deccbSFrançois Tigeot 		return false;
88926deccbSFrançois Tigeot 	}
89926deccbSFrançois Tigeot 	return true;
90926deccbSFrançois Tigeot }
91926deccbSFrançois Tigeot 
92926deccbSFrançois Tigeot /* bit banging i2c */
93926deccbSFrançois Tigeot 
94926deccbSFrançois Tigeot static int radeon_iicbb_pre_xfer(device_t dev)
95926deccbSFrançois Tigeot {
96926deccbSFrançois Tigeot 	struct radeon_i2c_chan *i2c = device_get_softc(dev);
97926deccbSFrançois Tigeot 	struct radeon_device *rdev = i2c->dev->dev_private;
98926deccbSFrançois Tigeot 	struct radeon_i2c_bus_rec *rec = &i2c->rec;
99926deccbSFrançois Tigeot 	uint32_t temp;
100926deccbSFrançois Tigeot 
101*7191d616Szrj 	lockmgr(&i2c->mutex, LK_EXCLUSIVE);
102*7191d616Szrj 
103926deccbSFrançois Tigeot 	/* RV410 appears to have a bug where the hw i2c in reset
104926deccbSFrançois Tigeot 	 * holds the i2c port in a bad state - switch hw i2c away before
105926deccbSFrançois Tigeot 	 * doing DDC - do this for all r200s/r300s/r400s for safety sake
106926deccbSFrançois Tigeot 	 */
107926deccbSFrançois Tigeot 	if (rec->hw_capable) {
108926deccbSFrançois Tigeot 		if ((rdev->family >= CHIP_R200) && !ASIC_IS_AVIVO(rdev)) {
109926deccbSFrançois Tigeot 			u32 reg;
110926deccbSFrançois Tigeot 
111926deccbSFrançois Tigeot 			if (rdev->family >= CHIP_RV350)
112926deccbSFrançois Tigeot 				reg = RADEON_GPIO_MONID;
113926deccbSFrançois Tigeot 			else if ((rdev->family == CHIP_R300) ||
114926deccbSFrançois Tigeot 				 (rdev->family == CHIP_R350))
115926deccbSFrançois Tigeot 				reg = RADEON_GPIO_DVI_DDC;
116926deccbSFrançois Tigeot 			else
117926deccbSFrançois Tigeot 				reg = RADEON_GPIO_CRT2_DDC;
118926deccbSFrançois Tigeot 
119926deccbSFrançois Tigeot 			lockmgr(&rdev->dc_hw_i2c_mutex, LK_EXCLUSIVE);
120926deccbSFrançois Tigeot 			if (rec->a_clk_reg == reg) {
121926deccbSFrançois Tigeot 				WREG32(RADEON_DVI_I2C_CNTL_0, (RADEON_I2C_SOFT_RST |
122926deccbSFrançois Tigeot 							       R200_DVI_I2C_PIN_SEL(R200_SEL_DDC1)));
123926deccbSFrançois Tigeot 			} else {
124926deccbSFrançois Tigeot 				WREG32(RADEON_DVI_I2C_CNTL_0, (RADEON_I2C_SOFT_RST |
125926deccbSFrançois Tigeot 							       R200_DVI_I2C_PIN_SEL(R200_SEL_DDC3)));
126926deccbSFrançois Tigeot 			}
127926deccbSFrançois Tigeot 			lockmgr(&rdev->dc_hw_i2c_mutex, LK_RELEASE);
128926deccbSFrançois Tigeot 		}
129926deccbSFrançois Tigeot 	}
130926deccbSFrançois Tigeot 
131926deccbSFrançois Tigeot 	/* switch the pads to ddc mode */
132926deccbSFrançois Tigeot 	if (ASIC_IS_DCE3(rdev) && rec->hw_capable) {
133926deccbSFrançois Tigeot 		temp = RREG32(rec->mask_clk_reg);
134926deccbSFrançois Tigeot 		temp &= ~(1 << 16);
135926deccbSFrançois Tigeot 		WREG32(rec->mask_clk_reg, temp);
136926deccbSFrançois Tigeot 	}
137926deccbSFrançois Tigeot 
138926deccbSFrançois Tigeot 	/* clear the output pin values */
139926deccbSFrançois Tigeot 	temp = RREG32(rec->a_clk_reg) & ~rec->a_clk_mask;
140926deccbSFrançois Tigeot 	WREG32(rec->a_clk_reg, temp);
141926deccbSFrançois Tigeot 
142926deccbSFrançois Tigeot 	temp = RREG32(rec->a_data_reg) & ~rec->a_data_mask;
143926deccbSFrançois Tigeot 	WREG32(rec->a_data_reg, temp);
144926deccbSFrançois Tigeot 
145926deccbSFrançois Tigeot 	/* set the pins to input */
146926deccbSFrançois Tigeot 	temp = RREG32(rec->en_clk_reg) & ~rec->en_clk_mask;
147926deccbSFrançois Tigeot 	WREG32(rec->en_clk_reg, temp);
148926deccbSFrançois Tigeot 
149926deccbSFrançois Tigeot 	temp = RREG32(rec->en_data_reg) & ~rec->en_data_mask;
150926deccbSFrançois Tigeot 	WREG32(rec->en_data_reg, temp);
151926deccbSFrançois Tigeot 
152926deccbSFrançois Tigeot 	/* mask the gpio pins for software use */
153926deccbSFrançois Tigeot 	temp = RREG32(rec->mask_clk_reg) | rec->mask_clk_mask;
154926deccbSFrançois Tigeot 	WREG32(rec->mask_clk_reg, temp);
155926deccbSFrançois Tigeot 	temp = RREG32(rec->mask_clk_reg);
156926deccbSFrançois Tigeot 
157926deccbSFrançois Tigeot 	temp = RREG32(rec->mask_data_reg) | rec->mask_data_mask;
158926deccbSFrançois Tigeot 	WREG32(rec->mask_data_reg, temp);
159926deccbSFrançois Tigeot 	temp = RREG32(rec->mask_data_reg);
160926deccbSFrançois Tigeot 
161926deccbSFrançois Tigeot 	return 0;
162926deccbSFrançois Tigeot }
163926deccbSFrançois Tigeot 
164926deccbSFrançois Tigeot static void radeon_iicbb_post_xfer(device_t dev)
165926deccbSFrançois Tigeot {
166926deccbSFrançois Tigeot 	struct radeon_i2c_chan *i2c = device_get_softc(dev);
167926deccbSFrançois Tigeot 	struct radeon_device *rdev = i2c->dev->dev_private;
168926deccbSFrançois Tigeot 	struct radeon_i2c_bus_rec *rec = &i2c->rec;
169926deccbSFrançois Tigeot 	uint32_t temp;
170926deccbSFrançois Tigeot 
171926deccbSFrançois Tigeot 	/* unmask the gpio pins for software use */
172926deccbSFrançois Tigeot 	temp = RREG32(rec->mask_clk_reg) & ~rec->mask_clk_mask;
173926deccbSFrançois Tigeot 	WREG32(rec->mask_clk_reg, temp);
174926deccbSFrançois Tigeot 	temp = RREG32(rec->mask_clk_reg);
175926deccbSFrançois Tigeot 
176926deccbSFrançois Tigeot 	temp = RREG32(rec->mask_data_reg) & ~rec->mask_data_mask;
177926deccbSFrançois Tigeot 	WREG32(rec->mask_data_reg, temp);
178926deccbSFrançois Tigeot 	temp = RREG32(rec->mask_data_reg);
179*7191d616Szrj 
180*7191d616Szrj 	lockmgr(&i2c->mutex, LK_RELEASE);
181926deccbSFrançois Tigeot }
182926deccbSFrançois Tigeot 
183926deccbSFrançois Tigeot static int radeon_iicbb_get_clock(device_t dev)
184926deccbSFrançois Tigeot {
185926deccbSFrançois Tigeot 	struct radeon_i2c_chan *i2c = device_get_softc(dev);
186926deccbSFrançois Tigeot 	struct radeon_device *rdev = i2c->dev->dev_private;
187926deccbSFrançois Tigeot 	struct radeon_i2c_bus_rec *rec = &i2c->rec;
188926deccbSFrançois Tigeot 	uint32_t val;
189926deccbSFrançois Tigeot 
190926deccbSFrançois Tigeot 	/* read the value off the pin */
191926deccbSFrançois Tigeot 	val = RREG32(rec->y_clk_reg);
192926deccbSFrançois Tigeot 	val &= rec->y_clk_mask;
193926deccbSFrançois Tigeot 
194926deccbSFrançois Tigeot 	return (val != 0);
195926deccbSFrançois Tigeot }
196926deccbSFrançois Tigeot 
197926deccbSFrançois Tigeot 
198926deccbSFrançois Tigeot static int radeon_iicbb_get_data(device_t dev)
199926deccbSFrançois Tigeot {
200926deccbSFrançois Tigeot 	struct radeon_i2c_chan *i2c = device_get_softc(dev);
201926deccbSFrançois Tigeot 	struct radeon_device *rdev = i2c->dev->dev_private;
202926deccbSFrançois Tigeot 	struct radeon_i2c_bus_rec *rec = &i2c->rec;
203926deccbSFrançois Tigeot 	uint32_t val;
204926deccbSFrançois Tigeot 
205926deccbSFrançois Tigeot 	/* read the value off the pin */
206926deccbSFrançois Tigeot 	val = RREG32(rec->y_data_reg);
207926deccbSFrançois Tigeot 	val &= rec->y_data_mask;
208926deccbSFrançois Tigeot 
209926deccbSFrançois Tigeot 	return (val != 0);
210926deccbSFrançois Tigeot }
211926deccbSFrançois Tigeot 
212926deccbSFrançois Tigeot static void radeon_iicbb_set_clock(device_t dev, int clock)
213926deccbSFrançois Tigeot {
214926deccbSFrançois Tigeot 	struct radeon_i2c_chan *i2c = device_get_softc(dev);
215926deccbSFrançois Tigeot 	struct radeon_device *rdev = i2c->dev->dev_private;
216926deccbSFrançois Tigeot 	struct radeon_i2c_bus_rec *rec = &i2c->rec;
217926deccbSFrançois Tigeot 	uint32_t val;
218926deccbSFrançois Tigeot 
219926deccbSFrançois Tigeot 	/* set pin direction */
220926deccbSFrançois Tigeot 	val = RREG32(rec->en_clk_reg) & ~rec->en_clk_mask;
221926deccbSFrançois Tigeot 	val |= clock ? 0 : rec->en_clk_mask;
222926deccbSFrançois Tigeot 	WREG32(rec->en_clk_reg, val);
223926deccbSFrançois Tigeot }
224926deccbSFrançois Tigeot 
225926deccbSFrançois Tigeot static void radeon_iicbb_set_data(device_t dev, int data)
226926deccbSFrançois Tigeot {
227926deccbSFrançois Tigeot 	struct radeon_i2c_chan *i2c = device_get_softc(dev);
228926deccbSFrançois Tigeot 	struct radeon_device *rdev = i2c->dev->dev_private;
229926deccbSFrançois Tigeot 	struct radeon_i2c_bus_rec *rec = &i2c->rec;
230926deccbSFrançois Tigeot 	uint32_t val;
231926deccbSFrançois Tigeot 
232926deccbSFrançois Tigeot 	/* set pin direction */
233926deccbSFrançois Tigeot 	val = RREG32(rec->en_data_reg) & ~rec->en_data_mask;
234926deccbSFrançois Tigeot 	val |= data ? 0 : rec->en_data_mask;
235926deccbSFrançois Tigeot 	WREG32(rec->en_data_reg, val);
236926deccbSFrançois Tigeot }
237926deccbSFrançois Tigeot 
238926deccbSFrançois Tigeot static int
239926deccbSFrançois Tigeot radeon_iicbb_probe(device_t dev)
240926deccbSFrançois Tigeot {
241926deccbSFrançois Tigeot 
242926deccbSFrançois Tigeot 	return (BUS_PROBE_DEFAULT);
243926deccbSFrançois Tigeot }
244926deccbSFrançois Tigeot 
245926deccbSFrançois Tigeot static int
246926deccbSFrançois Tigeot radeon_iicbb_attach(device_t dev)
247926deccbSFrançois Tigeot {
248926deccbSFrançois Tigeot 	struct radeon_i2c_chan *i2c;
249926deccbSFrançois Tigeot 	device_t iic_dev;
250926deccbSFrançois Tigeot 
251926deccbSFrançois Tigeot 	i2c = device_get_softc(dev);
252926deccbSFrançois Tigeot 	device_set_desc(dev, i2c->name);
253926deccbSFrançois Tigeot 
254926deccbSFrançois Tigeot 	/* add generic bit-banging code */
255926deccbSFrançois Tigeot 	iic_dev = device_add_child(dev, "iicbb", -1);
256926deccbSFrançois Tigeot 	if (iic_dev == NULL)
257926deccbSFrançois Tigeot 		return (ENXIO);
258926deccbSFrançois Tigeot 	device_quiet(iic_dev);
259926deccbSFrançois Tigeot 
260926deccbSFrançois Tigeot 	/* attach and probe added child */
261926deccbSFrançois Tigeot 	bus_generic_attach(dev);
262926deccbSFrançois Tigeot 
263926deccbSFrançois Tigeot 	return (0);
264926deccbSFrançois Tigeot }
265926deccbSFrançois Tigeot 
266926deccbSFrançois Tigeot static int
267926deccbSFrançois Tigeot radeon_iicbb_detach(device_t dev)
268926deccbSFrançois Tigeot {
269926deccbSFrançois Tigeot 
270926deccbSFrançois Tigeot 	/* detach bit-banding code. */
271926deccbSFrançois Tigeot 	bus_generic_detach(dev);
272926deccbSFrançois Tigeot 
273926deccbSFrançois Tigeot 	/* delete bit-banding code. */
274926deccbSFrançois Tigeot 	device_delete_children(dev);
275926deccbSFrançois Tigeot 	return (0);
276926deccbSFrançois Tigeot }
277926deccbSFrançois Tigeot 
278926deccbSFrançois Tigeot static int
279926deccbSFrançois Tigeot radeon_iicbb_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
280926deccbSFrançois Tigeot {
281926deccbSFrançois Tigeot 
282926deccbSFrançois Tigeot 	/* Not sure what to do here. */
283926deccbSFrançois Tigeot 	return 0;
284926deccbSFrançois Tigeot }
285926deccbSFrançois Tigeot 
286926deccbSFrançois Tigeot static device_method_t radeon_iicbb_methods[] =	{
287926deccbSFrançois Tigeot 	DEVMETHOD(device_probe,		radeon_iicbb_probe),
288926deccbSFrançois Tigeot 	DEVMETHOD(device_attach,	radeon_iicbb_attach),
289926deccbSFrançois Tigeot 	DEVMETHOD(device_detach,	radeon_iicbb_detach),
290926deccbSFrançois Tigeot 
291926deccbSFrançois Tigeot 	DEVMETHOD(bus_add_child,	bus_generic_add_child),
292926deccbSFrançois Tigeot 	DEVMETHOD(bus_print_child,	bus_generic_print_child),
293926deccbSFrançois Tigeot 
294926deccbSFrançois Tigeot 	DEVMETHOD(iicbb_reset,		radeon_iicbb_reset),
295926deccbSFrançois Tigeot 	DEVMETHOD(iicbb_pre_xfer,	radeon_iicbb_pre_xfer),
296926deccbSFrançois Tigeot 	DEVMETHOD(iicbb_post_xfer,	radeon_iicbb_post_xfer),
297926deccbSFrançois Tigeot 	DEVMETHOD(iicbb_setsda,		radeon_iicbb_set_data),
298926deccbSFrançois Tigeot 	DEVMETHOD(iicbb_setscl,		radeon_iicbb_set_clock),
299926deccbSFrançois Tigeot 	DEVMETHOD(iicbb_getsda,		radeon_iicbb_get_data),
300926deccbSFrançois Tigeot 	DEVMETHOD(iicbb_getscl,		radeon_iicbb_get_clock),
301926deccbSFrançois Tigeot 	DEVMETHOD_END
302926deccbSFrançois Tigeot };
303926deccbSFrançois Tigeot 
304926deccbSFrançois Tigeot static driver_t radeon_iicbb_driver = {
305926deccbSFrançois Tigeot 	"radeon_iicbb",
306926deccbSFrançois Tigeot 	radeon_iicbb_methods,
307926deccbSFrançois Tigeot 	0 /* softc will be allocated by parent */
308926deccbSFrançois Tigeot };
309926deccbSFrançois Tigeot static devclass_t radeon_iicbb_devclass;
310926deccbSFrançois Tigeot DRIVER_MODULE_ORDERED(radeon_iicbb, drm, radeon_iicbb_driver,
311aa6ac96eSSascha Wildner     radeon_iicbb_devclass, NULL, NULL, SI_ORDER_FIRST);
3123a25be87SSascha Wildner DRIVER_MODULE(iicbb, radeon_iicbb, iicbb_driver, iicbb_devclass, NULL, NULL);
313926deccbSFrançois Tigeot 
314926deccbSFrançois Tigeot /* hw i2c */
315926deccbSFrançois Tigeot 
316926deccbSFrançois Tigeot static u32 radeon_get_i2c_prescale(struct radeon_device *rdev)
317926deccbSFrançois Tigeot {
318926deccbSFrançois Tigeot 	u32 sclk = rdev->pm.current_sclk;
319926deccbSFrançois Tigeot 	u32 prescale = 0;
320926deccbSFrançois Tigeot 	u32 nm;
321926deccbSFrançois Tigeot 	u8 n, m, loop;
322926deccbSFrançois Tigeot 	int i2c_clock;
323926deccbSFrançois Tigeot 
324926deccbSFrançois Tigeot 	switch (rdev->family) {
325926deccbSFrançois Tigeot 	case CHIP_R100:
326926deccbSFrançois Tigeot 	case CHIP_RV100:
327926deccbSFrançois Tigeot 	case CHIP_RS100:
328926deccbSFrançois Tigeot 	case CHIP_RV200:
329926deccbSFrançois Tigeot 	case CHIP_RS200:
330926deccbSFrançois Tigeot 	case CHIP_R200:
331926deccbSFrançois Tigeot 	case CHIP_RV250:
332926deccbSFrançois Tigeot 	case CHIP_RS300:
333926deccbSFrançois Tigeot 	case CHIP_RV280:
334926deccbSFrançois Tigeot 	case CHIP_R300:
335926deccbSFrançois Tigeot 	case CHIP_R350:
336926deccbSFrançois Tigeot 	case CHIP_RV350:
337926deccbSFrançois Tigeot 		i2c_clock = 60;
338926deccbSFrançois Tigeot 		nm = (sclk * 10) / (i2c_clock * 4);
339926deccbSFrançois Tigeot 		for (loop = 1; loop < 255; loop++) {
340926deccbSFrançois Tigeot 			if ((nm / loop) < loop)
341926deccbSFrançois Tigeot 				break;
342926deccbSFrançois Tigeot 		}
343926deccbSFrançois Tigeot 		n = loop - 1;
344926deccbSFrançois Tigeot 		m = loop - 2;
345926deccbSFrançois Tigeot 		prescale = m | (n << 8);
346926deccbSFrançois Tigeot 		break;
347926deccbSFrançois Tigeot 	case CHIP_RV380:
348926deccbSFrançois Tigeot 	case CHIP_RS400:
349926deccbSFrançois Tigeot 	case CHIP_RS480:
350926deccbSFrançois Tigeot 	case CHIP_R420:
351926deccbSFrançois Tigeot 	case CHIP_R423:
352926deccbSFrançois Tigeot 	case CHIP_RV410:
353926deccbSFrançois Tigeot 		prescale = (((sclk * 10)/(4 * 128 * 100) + 1) << 8) + 128;
354926deccbSFrançois Tigeot 		break;
355926deccbSFrançois Tigeot 	case CHIP_RS600:
356926deccbSFrançois Tigeot 	case CHIP_RS690:
357926deccbSFrançois Tigeot 	case CHIP_RS740:
358926deccbSFrançois Tigeot 		/* todo */
359926deccbSFrançois Tigeot 		break;
360926deccbSFrançois Tigeot 	case CHIP_RV515:
361926deccbSFrançois Tigeot 	case CHIP_R520:
362926deccbSFrançois Tigeot 	case CHIP_RV530:
363926deccbSFrançois Tigeot 	case CHIP_RV560:
364926deccbSFrançois Tigeot 	case CHIP_RV570:
365926deccbSFrançois Tigeot 	case CHIP_R580:
366926deccbSFrançois Tigeot 		i2c_clock = 50;
367926deccbSFrançois Tigeot 		if (rdev->family == CHIP_R520)
368926deccbSFrançois Tigeot 			prescale = (127 << 8) + ((sclk * 10) / (4 * 127 * i2c_clock));
369926deccbSFrançois Tigeot 		else
370926deccbSFrançois Tigeot 			prescale = (((sclk * 10)/(4 * 128 * 100) + 1) << 8) + 128;
371926deccbSFrançois Tigeot 		break;
372926deccbSFrançois Tigeot 	case CHIP_R600:
373926deccbSFrançois Tigeot 	case CHIP_RV610:
374926deccbSFrançois Tigeot 	case CHIP_RV630:
375926deccbSFrançois Tigeot 	case CHIP_RV670:
376926deccbSFrançois Tigeot 		/* todo */
377926deccbSFrançois Tigeot 		break;
378926deccbSFrançois Tigeot 	case CHIP_RV620:
379926deccbSFrançois Tigeot 	case CHIP_RV635:
380926deccbSFrançois Tigeot 	case CHIP_RS780:
381926deccbSFrançois Tigeot 	case CHIP_RS880:
382926deccbSFrançois Tigeot 	case CHIP_RV770:
383926deccbSFrançois Tigeot 	case CHIP_RV730:
384926deccbSFrançois Tigeot 	case CHIP_RV710:
385926deccbSFrançois Tigeot 	case CHIP_RV740:
386926deccbSFrançois Tigeot 		/* todo */
387926deccbSFrançois Tigeot 		break;
388926deccbSFrançois Tigeot 	case CHIP_CEDAR:
389926deccbSFrançois Tigeot 	case CHIP_REDWOOD:
390926deccbSFrançois Tigeot 	case CHIP_JUNIPER:
391926deccbSFrançois Tigeot 	case CHIP_CYPRESS:
392926deccbSFrançois Tigeot 	case CHIP_HEMLOCK:
393926deccbSFrançois Tigeot 		/* todo */
394926deccbSFrançois Tigeot 		break;
395926deccbSFrançois Tigeot 	default:
396926deccbSFrançois Tigeot 		DRM_ERROR("i2c: unhandled radeon chip\n");
397926deccbSFrançois Tigeot 		break;
398926deccbSFrançois Tigeot 	}
399926deccbSFrançois Tigeot 	return prescale;
400926deccbSFrançois Tigeot }
401926deccbSFrançois Tigeot 
402926deccbSFrançois Tigeot 
403926deccbSFrançois Tigeot /* hw i2c engine for r1xx-4xx hardware
404926deccbSFrançois Tigeot  * hw can buffer up to 15 bytes
405926deccbSFrançois Tigeot  */
406926deccbSFrançois Tigeot static int r100_hw_i2c_xfer(struct radeon_i2c_chan *i2c,
407926deccbSFrançois Tigeot 			    struct iic_msg *msgs, int num)
408926deccbSFrançois Tigeot {
409926deccbSFrançois Tigeot 	struct radeon_device *rdev = i2c->dev->dev_private;
410926deccbSFrançois Tigeot 	struct radeon_i2c_bus_rec *rec = &i2c->rec;
411926deccbSFrançois Tigeot 	struct iic_msg *p;
412926deccbSFrançois Tigeot 	int i, j, k, ret = 0;
413926deccbSFrançois Tigeot 	u32 prescale;
414926deccbSFrançois Tigeot 	u32 i2c_cntl_0, i2c_cntl_1, i2c_data;
415926deccbSFrançois Tigeot 	u32 tmp, reg;
416926deccbSFrançois Tigeot 
417926deccbSFrançois Tigeot 	lockmgr(&rdev->dc_hw_i2c_mutex, LK_EXCLUSIVE);
418926deccbSFrançois Tigeot 	/* take the pm lock since we need a constant sclk */
419926deccbSFrançois Tigeot 	lockmgr(&rdev->pm.mutex, LK_EXCLUSIVE);
420926deccbSFrançois Tigeot 
421926deccbSFrançois Tigeot 	prescale = radeon_get_i2c_prescale(rdev);
422926deccbSFrançois Tigeot 
423926deccbSFrançois Tigeot 	reg = ((prescale << RADEON_I2C_PRESCALE_SHIFT) |
424926deccbSFrançois Tigeot 	       RADEON_I2C_DRIVE_EN |
425926deccbSFrançois Tigeot 	       RADEON_I2C_START |
426926deccbSFrançois Tigeot 	       RADEON_I2C_STOP |
427926deccbSFrançois Tigeot 	       RADEON_I2C_GO);
428926deccbSFrançois Tigeot 
429926deccbSFrançois Tigeot 	if (rdev->is_atom_bios) {
430926deccbSFrançois Tigeot 		tmp = RREG32(RADEON_BIOS_6_SCRATCH);
431926deccbSFrançois Tigeot 		WREG32(RADEON_BIOS_6_SCRATCH, tmp | ATOM_S6_HW_I2C_BUSY_STATE);
432926deccbSFrançois Tigeot 	}
433926deccbSFrançois Tigeot 
434926deccbSFrançois Tigeot 	if (rec->mm_i2c) {
435926deccbSFrançois Tigeot 		i2c_cntl_0 = RADEON_I2C_CNTL_0;
436926deccbSFrançois Tigeot 		i2c_cntl_1 = RADEON_I2C_CNTL_1;
437926deccbSFrançois Tigeot 		i2c_data = RADEON_I2C_DATA;
438926deccbSFrançois Tigeot 	} else {
439926deccbSFrançois Tigeot 		i2c_cntl_0 = RADEON_DVI_I2C_CNTL_0;
440926deccbSFrançois Tigeot 		i2c_cntl_1 = RADEON_DVI_I2C_CNTL_1;
441926deccbSFrançois Tigeot 		i2c_data = RADEON_DVI_I2C_DATA;
442926deccbSFrançois Tigeot 
443926deccbSFrançois Tigeot 		switch (rdev->family) {
444926deccbSFrançois Tigeot 		case CHIP_R100:
445926deccbSFrançois Tigeot 		case CHIP_RV100:
446926deccbSFrançois Tigeot 		case CHIP_RS100:
447926deccbSFrançois Tigeot 		case CHIP_RV200:
448926deccbSFrançois Tigeot 		case CHIP_RS200:
449926deccbSFrançois Tigeot 		case CHIP_RS300:
450926deccbSFrançois Tigeot 			switch (rec->mask_clk_reg) {
451926deccbSFrançois Tigeot 			case RADEON_GPIO_DVI_DDC:
452926deccbSFrançois Tigeot 				/* no gpio select bit */
453926deccbSFrançois Tigeot 				break;
454926deccbSFrançois Tigeot 			default:
455926deccbSFrançois Tigeot 				DRM_ERROR("gpio not supported with hw i2c\n");
456926deccbSFrançois Tigeot 				ret = EINVAL;
457926deccbSFrançois Tigeot 				goto done;
458926deccbSFrançois Tigeot 			}
459926deccbSFrançois Tigeot 			break;
460926deccbSFrançois Tigeot 		case CHIP_R200:
461926deccbSFrançois Tigeot 			/* only bit 4 on r200 */
462926deccbSFrançois Tigeot 			switch (rec->mask_clk_reg) {
463926deccbSFrançois Tigeot 			case RADEON_GPIO_DVI_DDC:
464926deccbSFrançois Tigeot 				reg |= R200_DVI_I2C_PIN_SEL(R200_SEL_DDC1);
465926deccbSFrançois Tigeot 				break;
466926deccbSFrançois Tigeot 			case RADEON_GPIO_MONID:
467926deccbSFrançois Tigeot 				reg |= R200_DVI_I2C_PIN_SEL(R200_SEL_DDC3);
468926deccbSFrançois Tigeot 				break;
469926deccbSFrançois Tigeot 			default:
470926deccbSFrançois Tigeot 				DRM_ERROR("gpio not supported with hw i2c\n");
471926deccbSFrançois Tigeot 				ret = EINVAL;
472926deccbSFrançois Tigeot 				goto done;
473926deccbSFrançois Tigeot 			}
474926deccbSFrançois Tigeot 			break;
475926deccbSFrançois Tigeot 		case CHIP_RV250:
476926deccbSFrançois Tigeot 		case CHIP_RV280:
477926deccbSFrançois Tigeot 			/* bits 3 and 4 */
478926deccbSFrançois Tigeot 			switch (rec->mask_clk_reg) {
479926deccbSFrançois Tigeot 			case RADEON_GPIO_DVI_DDC:
480926deccbSFrançois Tigeot 				reg |= R200_DVI_I2C_PIN_SEL(R200_SEL_DDC1);
481926deccbSFrançois Tigeot 				break;
482926deccbSFrançois Tigeot 			case RADEON_GPIO_VGA_DDC:
483926deccbSFrançois Tigeot 				reg |= R200_DVI_I2C_PIN_SEL(R200_SEL_DDC2);
484926deccbSFrançois Tigeot 				break;
485926deccbSFrançois Tigeot 			case RADEON_GPIO_CRT2_DDC:
486926deccbSFrançois Tigeot 				reg |= R200_DVI_I2C_PIN_SEL(R200_SEL_DDC3);
487926deccbSFrançois Tigeot 				break;
488926deccbSFrançois Tigeot 			default:
489926deccbSFrançois Tigeot 				DRM_ERROR("gpio not supported with hw i2c\n");
490926deccbSFrançois Tigeot 				ret = EINVAL;
491926deccbSFrançois Tigeot 				goto done;
492926deccbSFrançois Tigeot 			}
493926deccbSFrançois Tigeot 			break;
494926deccbSFrançois Tigeot 		case CHIP_R300:
495926deccbSFrançois Tigeot 		case CHIP_R350:
496926deccbSFrançois Tigeot 			/* only bit 4 on r300/r350 */
497926deccbSFrançois Tigeot 			switch (rec->mask_clk_reg) {
498926deccbSFrançois Tigeot 			case RADEON_GPIO_VGA_DDC:
499926deccbSFrançois Tigeot 				reg |= R200_DVI_I2C_PIN_SEL(R200_SEL_DDC1);
500926deccbSFrançois Tigeot 				break;
501926deccbSFrançois Tigeot 			case RADEON_GPIO_DVI_DDC:
502926deccbSFrançois Tigeot 				reg |= R200_DVI_I2C_PIN_SEL(R200_SEL_DDC3);
503926deccbSFrançois Tigeot 				break;
504926deccbSFrançois Tigeot 			default:
505926deccbSFrançois Tigeot 				DRM_ERROR("gpio not supported with hw i2c\n");
506926deccbSFrançois Tigeot 				ret = EINVAL;
507926deccbSFrançois Tigeot 				goto done;
508926deccbSFrançois Tigeot 			}
509926deccbSFrançois Tigeot 			break;
510926deccbSFrançois Tigeot 		case CHIP_RV350:
511926deccbSFrançois Tigeot 		case CHIP_RV380:
512926deccbSFrançois Tigeot 		case CHIP_R420:
513926deccbSFrançois Tigeot 		case CHIP_R423:
514926deccbSFrançois Tigeot 		case CHIP_RV410:
515926deccbSFrançois Tigeot 		case CHIP_RS400:
516926deccbSFrançois Tigeot 		case CHIP_RS480:
517926deccbSFrançois Tigeot 			/* bits 3 and 4 */
518926deccbSFrançois Tigeot 			switch (rec->mask_clk_reg) {
519926deccbSFrançois Tigeot 			case RADEON_GPIO_VGA_DDC:
520926deccbSFrançois Tigeot 				reg |= R200_DVI_I2C_PIN_SEL(R200_SEL_DDC1);
521926deccbSFrançois Tigeot 				break;
522926deccbSFrançois Tigeot 			case RADEON_GPIO_DVI_DDC:
523926deccbSFrançois Tigeot 				reg |= R200_DVI_I2C_PIN_SEL(R200_SEL_DDC2);
524926deccbSFrançois Tigeot 				break;
525926deccbSFrançois Tigeot 			case RADEON_GPIO_MONID:
526926deccbSFrançois Tigeot 				reg |= R200_DVI_I2C_PIN_SEL(R200_SEL_DDC3);
527926deccbSFrançois Tigeot 				break;
528926deccbSFrançois Tigeot 			default:
529926deccbSFrançois Tigeot 				DRM_ERROR("gpio not supported with hw i2c\n");
530926deccbSFrançois Tigeot 				ret = EINVAL;
531926deccbSFrançois Tigeot 				goto done;
532926deccbSFrançois Tigeot 			}
533926deccbSFrançois Tigeot 			break;
534926deccbSFrançois Tigeot 		default:
535926deccbSFrançois Tigeot 			DRM_ERROR("unsupported asic\n");
536926deccbSFrançois Tigeot 			ret = EINVAL;
537926deccbSFrançois Tigeot 			goto done;
538926deccbSFrançois Tigeot 			break;
539926deccbSFrançois Tigeot 		}
540926deccbSFrançois Tigeot 	}
541926deccbSFrançois Tigeot 
542926deccbSFrançois Tigeot 	/* check for bus probe */
543926deccbSFrançois Tigeot 	p = &msgs[0];
544926deccbSFrançois Tigeot 	if ((num == 1) && (p->len == 0)) {
545926deccbSFrançois Tigeot 		WREG32(i2c_cntl_0, (RADEON_I2C_DONE |
546926deccbSFrançois Tigeot 				    RADEON_I2C_NACK |
547926deccbSFrançois Tigeot 				    RADEON_I2C_HALT |
548926deccbSFrançois Tigeot 				    RADEON_I2C_SOFT_RST));
549926deccbSFrançois Tigeot 		WREG32(i2c_data, (p->slave << 1) & 0xff);
550926deccbSFrançois Tigeot 		WREG32(i2c_data, 0);
551926deccbSFrançois Tigeot 		WREG32(i2c_cntl_1, ((1 << RADEON_I2C_DATA_COUNT_SHIFT) |
552926deccbSFrançois Tigeot 				    (1 << RADEON_I2C_ADDR_COUNT_SHIFT) |
553926deccbSFrançois Tigeot 				    RADEON_I2C_EN |
554926deccbSFrançois Tigeot 				    (48 << RADEON_I2C_TIME_LIMIT_SHIFT)));
555926deccbSFrançois Tigeot 		WREG32(i2c_cntl_0, reg);
556926deccbSFrançois Tigeot 		for (k = 0; k < 32; k++) {
557c4ef309bSzrj 			udelay(10);
558926deccbSFrançois Tigeot 			tmp = RREG32(i2c_cntl_0);
559926deccbSFrançois Tigeot 			if (tmp & RADEON_I2C_GO)
560926deccbSFrançois Tigeot 				continue;
561926deccbSFrançois Tigeot 			tmp = RREG32(i2c_cntl_0);
562926deccbSFrançois Tigeot 			if (tmp & RADEON_I2C_DONE)
563926deccbSFrançois Tigeot 				break;
564926deccbSFrançois Tigeot 			else {
565926deccbSFrançois Tigeot 				DRM_DEBUG("i2c write error 0x%08x\n", tmp);
566926deccbSFrançois Tigeot 				WREG32(i2c_cntl_0, tmp | RADEON_I2C_ABORT);
567926deccbSFrançois Tigeot 				ret = EIO;
568926deccbSFrançois Tigeot 				goto done;
569926deccbSFrançois Tigeot 			}
570926deccbSFrançois Tigeot 		}
571926deccbSFrançois Tigeot 		goto done;
572926deccbSFrançois Tigeot 	}
573926deccbSFrançois Tigeot 
574926deccbSFrançois Tigeot 	for (i = 0; i < num; i++) {
575926deccbSFrançois Tigeot 		p = &msgs[i];
576926deccbSFrançois Tigeot 		for (j = 0; j < p->len; j++) {
577926deccbSFrançois Tigeot 			if (p->flags & IIC_M_RD) {
578926deccbSFrançois Tigeot 				WREG32(i2c_cntl_0, (RADEON_I2C_DONE |
579926deccbSFrançois Tigeot 						    RADEON_I2C_NACK |
580926deccbSFrançois Tigeot 						    RADEON_I2C_HALT |
581926deccbSFrançois Tigeot 						    RADEON_I2C_SOFT_RST));
582926deccbSFrançois Tigeot 				WREG32(i2c_data, ((p->slave << 1) & 0xff) | 0x1);
583926deccbSFrançois Tigeot 				WREG32(i2c_cntl_1, ((1 << RADEON_I2C_DATA_COUNT_SHIFT) |
584926deccbSFrançois Tigeot 						    (1 << RADEON_I2C_ADDR_COUNT_SHIFT) |
585926deccbSFrançois Tigeot 						    RADEON_I2C_EN |
586926deccbSFrançois Tigeot 						    (48 << RADEON_I2C_TIME_LIMIT_SHIFT)));
587926deccbSFrançois Tigeot 				WREG32(i2c_cntl_0, reg | RADEON_I2C_RECEIVE);
588926deccbSFrançois Tigeot 				for (k = 0; k < 32; k++) {
589c4ef309bSzrj 					udelay(10);
590926deccbSFrançois Tigeot 					tmp = RREG32(i2c_cntl_0);
591926deccbSFrançois Tigeot 					if (tmp & RADEON_I2C_GO)
592926deccbSFrançois Tigeot 						continue;
593926deccbSFrançois Tigeot 					tmp = RREG32(i2c_cntl_0);
594926deccbSFrançois Tigeot 					if (tmp & RADEON_I2C_DONE)
595926deccbSFrançois Tigeot 						break;
596926deccbSFrançois Tigeot 					else {
597926deccbSFrançois Tigeot 						DRM_DEBUG("i2c read error 0x%08x\n", tmp);
598926deccbSFrançois Tigeot 						WREG32(i2c_cntl_0, tmp | RADEON_I2C_ABORT);
599926deccbSFrançois Tigeot 						ret = EIO;
600926deccbSFrançois Tigeot 						goto done;
601926deccbSFrançois Tigeot 					}
602926deccbSFrançois Tigeot 				}
603926deccbSFrançois Tigeot 				p->buf[j] = RREG32(i2c_data) & 0xff;
604926deccbSFrançois Tigeot 			} else {
605926deccbSFrançois Tigeot 				WREG32(i2c_cntl_0, (RADEON_I2C_DONE |
606926deccbSFrançois Tigeot 						    RADEON_I2C_NACK |
607926deccbSFrançois Tigeot 						    RADEON_I2C_HALT |
608926deccbSFrançois Tigeot 						    RADEON_I2C_SOFT_RST));
609926deccbSFrançois Tigeot 				WREG32(i2c_data, (p->slave << 1) & 0xff);
610926deccbSFrançois Tigeot 				WREG32(i2c_data, p->buf[j]);
611926deccbSFrançois Tigeot 				WREG32(i2c_cntl_1, ((1 << RADEON_I2C_DATA_COUNT_SHIFT) |
612926deccbSFrançois Tigeot 						    (1 << RADEON_I2C_ADDR_COUNT_SHIFT) |
613926deccbSFrançois Tigeot 						    RADEON_I2C_EN |
614926deccbSFrançois Tigeot 						    (48 << RADEON_I2C_TIME_LIMIT_SHIFT)));
615926deccbSFrançois Tigeot 				WREG32(i2c_cntl_0, reg);
616926deccbSFrançois Tigeot 				for (k = 0; k < 32; k++) {
617c4ef309bSzrj 					udelay(10);
618926deccbSFrançois Tigeot 					tmp = RREG32(i2c_cntl_0);
619926deccbSFrançois Tigeot 					if (tmp & RADEON_I2C_GO)
620926deccbSFrançois Tigeot 						continue;
621926deccbSFrançois Tigeot 					tmp = RREG32(i2c_cntl_0);
622926deccbSFrançois Tigeot 					if (tmp & RADEON_I2C_DONE)
623926deccbSFrançois Tigeot 						break;
624926deccbSFrançois Tigeot 					else {
625926deccbSFrançois Tigeot 						DRM_DEBUG("i2c write error 0x%08x\n", tmp);
626926deccbSFrançois Tigeot 						WREG32(i2c_cntl_0, tmp | RADEON_I2C_ABORT);
627926deccbSFrançois Tigeot 						ret = EIO;
628926deccbSFrançois Tigeot 						goto done;
629926deccbSFrançois Tigeot 					}
630926deccbSFrançois Tigeot 				}
631926deccbSFrançois Tigeot 			}
632926deccbSFrançois Tigeot 		}
633926deccbSFrançois Tigeot 	}
634926deccbSFrançois Tigeot 
635926deccbSFrançois Tigeot done:
636926deccbSFrançois Tigeot 	WREG32(i2c_cntl_0, 0);
637926deccbSFrançois Tigeot 	WREG32(i2c_cntl_1, 0);
638926deccbSFrançois Tigeot 	WREG32(i2c_cntl_0, (RADEON_I2C_DONE |
639926deccbSFrançois Tigeot 			    RADEON_I2C_NACK |
640926deccbSFrançois Tigeot 			    RADEON_I2C_HALT |
641926deccbSFrançois Tigeot 			    RADEON_I2C_SOFT_RST));
642926deccbSFrançois Tigeot 
643926deccbSFrançois Tigeot 	if (rdev->is_atom_bios) {
644926deccbSFrançois Tigeot 		tmp = RREG32(RADEON_BIOS_6_SCRATCH);
645926deccbSFrançois Tigeot 		tmp &= ~ATOM_S6_HW_I2C_BUSY_STATE;
646926deccbSFrançois Tigeot 		WREG32(RADEON_BIOS_6_SCRATCH, tmp);
647926deccbSFrançois Tigeot 	}
648926deccbSFrançois Tigeot 
649926deccbSFrançois Tigeot 	lockmgr(&rdev->pm.mutex, LK_RELEASE);
650926deccbSFrançois Tigeot 	lockmgr(&rdev->dc_hw_i2c_mutex, LK_RELEASE);
651926deccbSFrançois Tigeot 
652926deccbSFrançois Tigeot 	return ret;
653926deccbSFrançois Tigeot }
654926deccbSFrançois Tigeot 
655926deccbSFrançois Tigeot /* hw i2c engine for r5xx hardware
656926deccbSFrançois Tigeot  * hw can buffer up to 15 bytes
657926deccbSFrançois Tigeot  */
658926deccbSFrançois Tigeot static int r500_hw_i2c_xfer(struct radeon_i2c_chan *i2c,
659926deccbSFrançois Tigeot 			    struct iic_msg *msgs, int num)
660926deccbSFrançois Tigeot {
661926deccbSFrançois Tigeot 	struct radeon_device *rdev = i2c->dev->dev_private;
662926deccbSFrançois Tigeot 	struct radeon_i2c_bus_rec *rec = &i2c->rec;
663926deccbSFrançois Tigeot 	struct iic_msg *p;
664926deccbSFrançois Tigeot 	int i, j, remaining, current_count, buffer_offset, ret = 0;
665926deccbSFrançois Tigeot 	u32 prescale;
666926deccbSFrançois Tigeot 	u32 tmp, reg;
667926deccbSFrançois Tigeot 	u32 saved1, saved2;
668926deccbSFrançois Tigeot 
669926deccbSFrançois Tigeot 	lockmgr(&rdev->dc_hw_i2c_mutex, LK_EXCLUSIVE);
670926deccbSFrançois Tigeot 	/* take the pm lock since we need a constant sclk */
671926deccbSFrançois Tigeot 	lockmgr(&rdev->pm.mutex, LK_EXCLUSIVE);
672926deccbSFrançois Tigeot 
673926deccbSFrançois Tigeot 	prescale = radeon_get_i2c_prescale(rdev);
674926deccbSFrançois Tigeot 
675926deccbSFrançois Tigeot 	/* clear gpio mask bits */
676926deccbSFrançois Tigeot 	tmp = RREG32(rec->mask_clk_reg);
677926deccbSFrançois Tigeot 	tmp &= ~rec->mask_clk_mask;
678926deccbSFrançois Tigeot 	WREG32(rec->mask_clk_reg, tmp);
679926deccbSFrançois Tigeot 	tmp = RREG32(rec->mask_clk_reg);
680926deccbSFrançois Tigeot 
681926deccbSFrançois Tigeot 	tmp = RREG32(rec->mask_data_reg);
682926deccbSFrançois Tigeot 	tmp &= ~rec->mask_data_mask;
683926deccbSFrançois Tigeot 	WREG32(rec->mask_data_reg, tmp);
684926deccbSFrançois Tigeot 	tmp = RREG32(rec->mask_data_reg);
685926deccbSFrançois Tigeot 
686926deccbSFrançois Tigeot 	/* clear pin values */
687926deccbSFrançois Tigeot 	tmp = RREG32(rec->a_clk_reg);
688926deccbSFrançois Tigeot 	tmp &= ~rec->a_clk_mask;
689926deccbSFrançois Tigeot 	WREG32(rec->a_clk_reg, tmp);
690926deccbSFrançois Tigeot 	tmp = RREG32(rec->a_clk_reg);
691926deccbSFrançois Tigeot 
692926deccbSFrançois Tigeot 	tmp = RREG32(rec->a_data_reg);
693926deccbSFrançois Tigeot 	tmp &= ~rec->a_data_mask;
694926deccbSFrançois Tigeot 	WREG32(rec->a_data_reg, tmp);
695926deccbSFrançois Tigeot 	tmp = RREG32(rec->a_data_reg);
696926deccbSFrançois Tigeot 
697926deccbSFrançois Tigeot 	/* set the pins to input */
698926deccbSFrançois Tigeot 	tmp = RREG32(rec->en_clk_reg);
699926deccbSFrançois Tigeot 	tmp &= ~rec->en_clk_mask;
700926deccbSFrançois Tigeot 	WREG32(rec->en_clk_reg, tmp);
701926deccbSFrançois Tigeot 	tmp = RREG32(rec->en_clk_reg);
702926deccbSFrançois Tigeot 
703926deccbSFrançois Tigeot 	tmp = RREG32(rec->en_data_reg);
704926deccbSFrançois Tigeot 	tmp &= ~rec->en_data_mask;
705926deccbSFrançois Tigeot 	WREG32(rec->en_data_reg, tmp);
706926deccbSFrançois Tigeot 	tmp = RREG32(rec->en_data_reg);
707926deccbSFrançois Tigeot 
708926deccbSFrançois Tigeot 	/* */
709926deccbSFrançois Tigeot 	tmp = RREG32(RADEON_BIOS_6_SCRATCH);
710926deccbSFrançois Tigeot 	WREG32(RADEON_BIOS_6_SCRATCH, tmp | ATOM_S6_HW_I2C_BUSY_STATE);
711926deccbSFrançois Tigeot 	saved1 = RREG32(AVIVO_DC_I2C_CONTROL1);
712926deccbSFrançois Tigeot 	saved2 = RREG32(0x494);
713926deccbSFrançois Tigeot 	WREG32(0x494, saved2 | 0x1);
714926deccbSFrançois Tigeot 
715926deccbSFrançois Tigeot 	WREG32(AVIVO_DC_I2C_ARBITRATION, AVIVO_DC_I2C_SW_WANTS_TO_USE_I2C);
716926deccbSFrançois Tigeot 	for (i = 0; i < 50; i++) {
717c4ef309bSzrj 		udelay(1);
718926deccbSFrançois Tigeot 		if (RREG32(AVIVO_DC_I2C_ARBITRATION) & AVIVO_DC_I2C_SW_CAN_USE_I2C)
719926deccbSFrançois Tigeot 			break;
720926deccbSFrançois Tigeot 	}
721926deccbSFrançois Tigeot 	if (i == 50) {
722926deccbSFrançois Tigeot 		DRM_ERROR("failed to get i2c bus\n");
723926deccbSFrançois Tigeot 		ret = EBUSY;
724926deccbSFrançois Tigeot 		goto done;
725926deccbSFrançois Tigeot 	}
726926deccbSFrançois Tigeot 
727926deccbSFrançois Tigeot 	reg = AVIVO_DC_I2C_START | AVIVO_DC_I2C_STOP | AVIVO_DC_I2C_EN;
728926deccbSFrançois Tigeot 	switch (rec->mask_clk_reg) {
729926deccbSFrançois Tigeot 	case AVIVO_DC_GPIO_DDC1_MASK:
730926deccbSFrançois Tigeot 		reg |= AVIVO_DC_I2C_PIN_SELECT(AVIVO_SEL_DDC1);
731926deccbSFrançois Tigeot 		break;
732926deccbSFrançois Tigeot 	case AVIVO_DC_GPIO_DDC2_MASK:
733926deccbSFrançois Tigeot 		reg |= AVIVO_DC_I2C_PIN_SELECT(AVIVO_SEL_DDC2);
734926deccbSFrançois Tigeot 		break;
735926deccbSFrançois Tigeot 	case AVIVO_DC_GPIO_DDC3_MASK:
736926deccbSFrançois Tigeot 		reg |= AVIVO_DC_I2C_PIN_SELECT(AVIVO_SEL_DDC3);
737926deccbSFrançois Tigeot 		break;
738926deccbSFrançois Tigeot 	default:
739926deccbSFrançois Tigeot 		DRM_ERROR("gpio not supported with hw i2c\n");
740926deccbSFrançois Tigeot 		ret = EINVAL;
741926deccbSFrançois Tigeot 		goto done;
742926deccbSFrançois Tigeot 	}
743926deccbSFrançois Tigeot 
744926deccbSFrançois Tigeot 	/* check for bus probe */
745926deccbSFrançois Tigeot 	p = &msgs[0];
746926deccbSFrançois Tigeot 	if ((num == 1) && (p->len == 0)) {
747926deccbSFrançois Tigeot 		WREG32(AVIVO_DC_I2C_STATUS1, (AVIVO_DC_I2C_DONE |
748926deccbSFrançois Tigeot 					      AVIVO_DC_I2C_NACK |
749926deccbSFrançois Tigeot 					      AVIVO_DC_I2C_HALT));
750926deccbSFrançois Tigeot 		WREG32(AVIVO_DC_I2C_RESET, AVIVO_DC_I2C_SOFT_RESET);
751c4ef309bSzrj 		udelay(1);
752926deccbSFrançois Tigeot 		WREG32(AVIVO_DC_I2C_RESET, 0);
753926deccbSFrançois Tigeot 
754926deccbSFrançois Tigeot 		WREG32(AVIVO_DC_I2C_DATA, (p->slave << 1) & 0xff);
755926deccbSFrançois Tigeot 		WREG32(AVIVO_DC_I2C_DATA, 0);
756926deccbSFrançois Tigeot 
757926deccbSFrançois Tigeot 		WREG32(AVIVO_DC_I2C_CONTROL3, AVIVO_DC_I2C_TIME_LIMIT(48));
758926deccbSFrançois Tigeot 		WREG32(AVIVO_DC_I2C_CONTROL2, (AVIVO_DC_I2C_ADDR_COUNT(1) |
759926deccbSFrançois Tigeot 					       AVIVO_DC_I2C_DATA_COUNT(1) |
760926deccbSFrançois Tigeot 					       (prescale << 16)));
761926deccbSFrançois Tigeot 		WREG32(AVIVO_DC_I2C_CONTROL1, reg);
762926deccbSFrançois Tigeot 		WREG32(AVIVO_DC_I2C_STATUS1, AVIVO_DC_I2C_GO);
763926deccbSFrançois Tigeot 		for (j = 0; j < 200; j++) {
764c4ef309bSzrj 			udelay(50);
765926deccbSFrançois Tigeot 			tmp = RREG32(AVIVO_DC_I2C_STATUS1);
766926deccbSFrançois Tigeot 			if (tmp & AVIVO_DC_I2C_GO)
767926deccbSFrançois Tigeot 				continue;
768926deccbSFrançois Tigeot 			tmp = RREG32(AVIVO_DC_I2C_STATUS1);
769926deccbSFrançois Tigeot 			if (tmp & AVIVO_DC_I2C_DONE)
770926deccbSFrançois Tigeot 				break;
771926deccbSFrançois Tigeot 			else {
772926deccbSFrançois Tigeot 				DRM_DEBUG("i2c write error 0x%08x\n", tmp);
773926deccbSFrançois Tigeot 				WREG32(AVIVO_DC_I2C_RESET, AVIVO_DC_I2C_ABORT);
774926deccbSFrançois Tigeot 				ret = EIO;
775926deccbSFrançois Tigeot 				goto done;
776926deccbSFrançois Tigeot 			}
777926deccbSFrançois Tigeot 		}
778926deccbSFrançois Tigeot 		goto done;
779926deccbSFrançois Tigeot 	}
780926deccbSFrançois Tigeot 
781926deccbSFrançois Tigeot 	for (i = 0; i < num; i++) {
782926deccbSFrançois Tigeot 		p = &msgs[i];
783926deccbSFrançois Tigeot 		remaining = p->len;
784926deccbSFrançois Tigeot 		buffer_offset = 0;
785926deccbSFrançois Tigeot 		if (p->flags & IIC_M_RD) {
786926deccbSFrançois Tigeot 			while (remaining) {
787926deccbSFrançois Tigeot 				if (remaining > 15)
788926deccbSFrançois Tigeot 					current_count = 15;
789926deccbSFrançois Tigeot 				else
790926deccbSFrançois Tigeot 					current_count = remaining;
791926deccbSFrançois Tigeot 				WREG32(AVIVO_DC_I2C_STATUS1, (AVIVO_DC_I2C_DONE |
792926deccbSFrançois Tigeot 							      AVIVO_DC_I2C_NACK |
793926deccbSFrançois Tigeot 							      AVIVO_DC_I2C_HALT));
794926deccbSFrançois Tigeot 				WREG32(AVIVO_DC_I2C_RESET, AVIVO_DC_I2C_SOFT_RESET);
795c4ef309bSzrj 				udelay(1);
796926deccbSFrançois Tigeot 				WREG32(AVIVO_DC_I2C_RESET, 0);
797926deccbSFrançois Tigeot 
798926deccbSFrançois Tigeot 				WREG32(AVIVO_DC_I2C_DATA, ((p->slave << 1) & 0xff) | 0x1);
799926deccbSFrançois Tigeot 				WREG32(AVIVO_DC_I2C_CONTROL3, AVIVO_DC_I2C_TIME_LIMIT(48));
800926deccbSFrançois Tigeot 				WREG32(AVIVO_DC_I2C_CONTROL2, (AVIVO_DC_I2C_ADDR_COUNT(1) |
801926deccbSFrançois Tigeot 							       AVIVO_DC_I2C_DATA_COUNT(current_count) |
802926deccbSFrançois Tigeot 							       (prescale << 16)));
803926deccbSFrançois Tigeot 				WREG32(AVIVO_DC_I2C_CONTROL1, reg | AVIVO_DC_I2C_RECEIVE);
804926deccbSFrançois Tigeot 				WREG32(AVIVO_DC_I2C_STATUS1, AVIVO_DC_I2C_GO);
805926deccbSFrançois Tigeot 				for (j = 0; j < 200; j++) {
806c4ef309bSzrj 					udelay(50);
807926deccbSFrançois Tigeot 					tmp = RREG32(AVIVO_DC_I2C_STATUS1);
808926deccbSFrançois Tigeot 					if (tmp & AVIVO_DC_I2C_GO)
809926deccbSFrançois Tigeot 						continue;
810926deccbSFrançois Tigeot 					tmp = RREG32(AVIVO_DC_I2C_STATUS1);
811926deccbSFrançois Tigeot 					if (tmp & AVIVO_DC_I2C_DONE)
812926deccbSFrançois Tigeot 						break;
813926deccbSFrançois Tigeot 					else {
814926deccbSFrançois Tigeot 						DRM_DEBUG("i2c read error 0x%08x\n", tmp);
815926deccbSFrançois Tigeot 						WREG32(AVIVO_DC_I2C_RESET, AVIVO_DC_I2C_ABORT);
816926deccbSFrançois Tigeot 						ret = EIO;
817926deccbSFrançois Tigeot 						goto done;
818926deccbSFrançois Tigeot 					}
819926deccbSFrançois Tigeot 				}
820926deccbSFrançois Tigeot 				for (j = 0; j < current_count; j++)
821926deccbSFrançois Tigeot 					p->buf[buffer_offset + j] = RREG32(AVIVO_DC_I2C_DATA) & 0xff;
822926deccbSFrançois Tigeot 				remaining -= current_count;
823926deccbSFrançois Tigeot 				buffer_offset += current_count;
824926deccbSFrançois Tigeot 			}
825926deccbSFrançois Tigeot 		} else {
826926deccbSFrançois Tigeot 			while (remaining) {
827926deccbSFrançois Tigeot 				if (remaining > 15)
828926deccbSFrançois Tigeot 					current_count = 15;
829926deccbSFrançois Tigeot 				else
830926deccbSFrançois Tigeot 					current_count = remaining;
831926deccbSFrançois Tigeot 				WREG32(AVIVO_DC_I2C_STATUS1, (AVIVO_DC_I2C_DONE |
832926deccbSFrançois Tigeot 							      AVIVO_DC_I2C_NACK |
833926deccbSFrançois Tigeot 							      AVIVO_DC_I2C_HALT));
834926deccbSFrançois Tigeot 				WREG32(AVIVO_DC_I2C_RESET, AVIVO_DC_I2C_SOFT_RESET);
835c4ef309bSzrj 				udelay(1);
836926deccbSFrançois Tigeot 				WREG32(AVIVO_DC_I2C_RESET, 0);
837926deccbSFrançois Tigeot 
838926deccbSFrançois Tigeot 				WREG32(AVIVO_DC_I2C_DATA, (p->slave << 1) & 0xff);
839926deccbSFrançois Tigeot 				for (j = 0; j < current_count; j++)
840926deccbSFrançois Tigeot 					WREG32(AVIVO_DC_I2C_DATA, p->buf[buffer_offset + j]);
841926deccbSFrançois Tigeot 
842926deccbSFrançois Tigeot 				WREG32(AVIVO_DC_I2C_CONTROL3, AVIVO_DC_I2C_TIME_LIMIT(48));
843926deccbSFrançois Tigeot 				WREG32(AVIVO_DC_I2C_CONTROL2, (AVIVO_DC_I2C_ADDR_COUNT(1) |
844926deccbSFrançois Tigeot 							       AVIVO_DC_I2C_DATA_COUNT(current_count) |
845926deccbSFrançois Tigeot 							       (prescale << 16)));
846926deccbSFrançois Tigeot 				WREG32(AVIVO_DC_I2C_CONTROL1, reg);
847926deccbSFrançois Tigeot 				WREG32(AVIVO_DC_I2C_STATUS1, AVIVO_DC_I2C_GO);
848926deccbSFrançois Tigeot 				for (j = 0; j < 200; j++) {
849c4ef309bSzrj 					udelay(50);
850926deccbSFrançois Tigeot 					tmp = RREG32(AVIVO_DC_I2C_STATUS1);
851926deccbSFrançois Tigeot 					if (tmp & AVIVO_DC_I2C_GO)
852926deccbSFrançois Tigeot 						continue;
853926deccbSFrançois Tigeot 					tmp = RREG32(AVIVO_DC_I2C_STATUS1);
854926deccbSFrançois Tigeot 					if (tmp & AVIVO_DC_I2C_DONE)
855926deccbSFrançois Tigeot 						break;
856926deccbSFrançois Tigeot 					else {
857926deccbSFrançois Tigeot 						DRM_DEBUG("i2c write error 0x%08x\n", tmp);
858926deccbSFrançois Tigeot 						WREG32(AVIVO_DC_I2C_RESET, AVIVO_DC_I2C_ABORT);
859926deccbSFrançois Tigeot 						ret = EIO;
860926deccbSFrançois Tigeot 						goto done;
861926deccbSFrançois Tigeot 					}
862926deccbSFrançois Tigeot 				}
863926deccbSFrançois Tigeot 				remaining -= current_count;
864926deccbSFrançois Tigeot 				buffer_offset += current_count;
865926deccbSFrançois Tigeot 			}
866926deccbSFrançois Tigeot 		}
867926deccbSFrançois Tigeot 	}
868926deccbSFrançois Tigeot 
869926deccbSFrançois Tigeot done:
870926deccbSFrançois Tigeot 	WREG32(AVIVO_DC_I2C_STATUS1, (AVIVO_DC_I2C_DONE |
871926deccbSFrançois Tigeot 				      AVIVO_DC_I2C_NACK |
872926deccbSFrançois Tigeot 				      AVIVO_DC_I2C_HALT));
873926deccbSFrançois Tigeot 	WREG32(AVIVO_DC_I2C_RESET, AVIVO_DC_I2C_SOFT_RESET);
874c4ef309bSzrj 	udelay(1);
875926deccbSFrançois Tigeot 	WREG32(AVIVO_DC_I2C_RESET, 0);
876926deccbSFrançois Tigeot 
877926deccbSFrançois Tigeot 	WREG32(AVIVO_DC_I2C_ARBITRATION, AVIVO_DC_I2C_SW_DONE_USING_I2C);
878926deccbSFrançois Tigeot 	WREG32(AVIVO_DC_I2C_CONTROL1, saved1);
879926deccbSFrançois Tigeot 	WREG32(0x494, saved2);
880926deccbSFrançois Tigeot 	tmp = RREG32(RADEON_BIOS_6_SCRATCH);
881926deccbSFrançois Tigeot 	tmp &= ~ATOM_S6_HW_I2C_BUSY_STATE;
882926deccbSFrançois Tigeot 	WREG32(RADEON_BIOS_6_SCRATCH, tmp);
883926deccbSFrançois Tigeot 
884926deccbSFrançois Tigeot 	lockmgr(&rdev->pm.mutex, LK_RELEASE);
885926deccbSFrançois Tigeot 	lockmgr(&rdev->dc_hw_i2c_mutex, LK_RELEASE);
886926deccbSFrançois Tigeot 
887926deccbSFrançois Tigeot 	return ret;
888926deccbSFrançois Tigeot }
889926deccbSFrançois Tigeot 
890926deccbSFrançois Tigeot static int radeon_hw_i2c_xfer(device_t dev,
891926deccbSFrançois Tigeot 			      struct iic_msg *msgs, uint32_t num)
892926deccbSFrançois Tigeot {
893926deccbSFrançois Tigeot 	struct radeon_i2c_chan *i2c = device_get_softc(dev);
894926deccbSFrançois Tigeot 	struct radeon_device *rdev = i2c->dev->dev_private;
895926deccbSFrançois Tigeot 	struct radeon_i2c_bus_rec *rec = &i2c->rec;
896926deccbSFrançois Tigeot 	int ret = 0;
897926deccbSFrançois Tigeot 
898*7191d616Szrj 	lockmgr(&i2c->mutex, LK_EXCLUSIVE);
899*7191d616Szrj 
900926deccbSFrançois Tigeot 	switch (rdev->family) {
901926deccbSFrançois Tigeot 	case CHIP_R100:
902926deccbSFrançois Tigeot 	case CHIP_RV100:
903926deccbSFrançois Tigeot 	case CHIP_RS100:
904926deccbSFrançois Tigeot 	case CHIP_RV200:
905926deccbSFrançois Tigeot 	case CHIP_RS200:
906926deccbSFrançois Tigeot 	case CHIP_R200:
907926deccbSFrançois Tigeot 	case CHIP_RV250:
908926deccbSFrançois Tigeot 	case CHIP_RS300:
909926deccbSFrançois Tigeot 	case CHIP_RV280:
910926deccbSFrançois Tigeot 	case CHIP_R300:
911926deccbSFrançois Tigeot 	case CHIP_R350:
912926deccbSFrançois Tigeot 	case CHIP_RV350:
913926deccbSFrançois Tigeot 	case CHIP_RV380:
914926deccbSFrançois Tigeot 	case CHIP_R420:
915926deccbSFrançois Tigeot 	case CHIP_R423:
916926deccbSFrançois Tigeot 	case CHIP_RV410:
917926deccbSFrançois Tigeot 	case CHIP_RS400:
918926deccbSFrançois Tigeot 	case CHIP_RS480:
919926deccbSFrançois Tigeot 		ret = r100_hw_i2c_xfer(i2c, msgs, num);
920926deccbSFrançois Tigeot 		break;
921926deccbSFrançois Tigeot 	case CHIP_RS600:
922926deccbSFrançois Tigeot 	case CHIP_RS690:
923926deccbSFrançois Tigeot 	case CHIP_RS740:
924926deccbSFrançois Tigeot 		/* XXX fill in hw i2c implementation */
925926deccbSFrançois Tigeot 		break;
926926deccbSFrançois Tigeot 	case CHIP_RV515:
927926deccbSFrançois Tigeot 	case CHIP_R520:
928926deccbSFrançois Tigeot 	case CHIP_RV530:
929926deccbSFrançois Tigeot 	case CHIP_RV560:
930926deccbSFrançois Tigeot 	case CHIP_RV570:
931926deccbSFrançois Tigeot 	case CHIP_R580:
932926deccbSFrançois Tigeot 		if (rec->mm_i2c)
933926deccbSFrançois Tigeot 			ret = r100_hw_i2c_xfer(i2c, msgs, num);
934926deccbSFrançois Tigeot 		else
935926deccbSFrançois Tigeot 			ret = r500_hw_i2c_xfer(i2c, msgs, num);
936926deccbSFrançois Tigeot 		break;
937926deccbSFrançois Tigeot 	case CHIP_R600:
938926deccbSFrançois Tigeot 	case CHIP_RV610:
939926deccbSFrançois Tigeot 	case CHIP_RV630:
940926deccbSFrançois Tigeot 	case CHIP_RV670:
941926deccbSFrançois Tigeot 		/* XXX fill in hw i2c implementation */
942926deccbSFrançois Tigeot 		break;
943926deccbSFrançois Tigeot 	case CHIP_RV620:
944926deccbSFrançois Tigeot 	case CHIP_RV635:
945926deccbSFrançois Tigeot 	case CHIP_RS780:
946926deccbSFrançois Tigeot 	case CHIP_RS880:
947926deccbSFrançois Tigeot 	case CHIP_RV770:
948926deccbSFrançois Tigeot 	case CHIP_RV730:
949926deccbSFrançois Tigeot 	case CHIP_RV710:
950926deccbSFrançois Tigeot 	case CHIP_RV740:
951926deccbSFrançois Tigeot 		/* XXX fill in hw i2c implementation */
952926deccbSFrançois Tigeot 		break;
953926deccbSFrançois Tigeot 	case CHIP_CEDAR:
954926deccbSFrançois Tigeot 	case CHIP_REDWOOD:
955926deccbSFrançois Tigeot 	case CHIP_JUNIPER:
956926deccbSFrançois Tigeot 	case CHIP_CYPRESS:
957926deccbSFrançois Tigeot 	case CHIP_HEMLOCK:
958926deccbSFrançois Tigeot 		/* XXX fill in hw i2c implementation */
959926deccbSFrançois Tigeot 		break;
960926deccbSFrançois Tigeot 	default:
961926deccbSFrançois Tigeot 		DRM_ERROR("i2c: unhandled radeon chip\n");
962926deccbSFrançois Tigeot 		ret = EIO;
963926deccbSFrançois Tigeot 		break;
964926deccbSFrançois Tigeot 	}
965926deccbSFrançois Tigeot 
966*7191d616Szrj 	lockmgr(&i2c->mutex, LK_RELEASE);
967*7191d616Szrj 
968926deccbSFrançois Tigeot 	return ret;
969926deccbSFrançois Tigeot }
970926deccbSFrançois Tigeot 
971926deccbSFrançois Tigeot static int
972926deccbSFrançois Tigeot radeon_hw_i2c_probe(device_t dev)
973926deccbSFrançois Tigeot {
974926deccbSFrançois Tigeot 
975926deccbSFrançois Tigeot 	return (BUS_PROBE_SPECIFIC);
976926deccbSFrançois Tigeot }
977926deccbSFrançois Tigeot 
978926deccbSFrançois Tigeot static int
979926deccbSFrançois Tigeot radeon_hw_i2c_attach(device_t dev)
980926deccbSFrançois Tigeot {
981926deccbSFrançois Tigeot 	struct radeon_i2c_chan *i2c;
982926deccbSFrançois Tigeot 	device_t iic_dev;
983926deccbSFrançois Tigeot 
984926deccbSFrançois Tigeot 	i2c = device_get_softc(dev);
985926deccbSFrançois Tigeot 	device_set_desc(dev, i2c->name);
986926deccbSFrançois Tigeot 
987926deccbSFrançois Tigeot 	/* add generic bit-banging code */
988926deccbSFrançois Tigeot 	iic_dev = device_add_child(dev, "iicbus", -1);
989926deccbSFrançois Tigeot 	if (iic_dev == NULL)
990926deccbSFrançois Tigeot 		return (ENXIO);
991926deccbSFrançois Tigeot 	device_quiet(iic_dev);
992926deccbSFrançois Tigeot 
993926deccbSFrançois Tigeot 	/* attach and probe added child */
994926deccbSFrançois Tigeot 	bus_generic_attach(dev);
995926deccbSFrançois Tigeot 
996926deccbSFrançois Tigeot 	return (0);
997926deccbSFrançois Tigeot }
998926deccbSFrançois Tigeot 
999926deccbSFrançois Tigeot static int
1000926deccbSFrançois Tigeot radeon_hw_i2c_detach(device_t dev)
1001926deccbSFrançois Tigeot {
1002926deccbSFrançois Tigeot 
1003926deccbSFrançois Tigeot 	/* detach bit-banding code. */
1004926deccbSFrançois Tigeot 	bus_generic_detach(dev);
1005926deccbSFrançois Tigeot 
1006926deccbSFrançois Tigeot 	/* delete bit-banding code. */
1007926deccbSFrançois Tigeot 	device_delete_children(dev);
1008926deccbSFrançois Tigeot 	return (0);
1009926deccbSFrançois Tigeot }
1010926deccbSFrançois Tigeot 
1011926deccbSFrançois Tigeot static int
1012926deccbSFrançois Tigeot radeon_hw_i2c_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
1013926deccbSFrançois Tigeot {
1014926deccbSFrançois Tigeot 
1015926deccbSFrançois Tigeot 	/* Not sure what to do here. */
1016926deccbSFrançois Tigeot 	return 0;
1017926deccbSFrançois Tigeot }
1018926deccbSFrançois Tigeot 
1019926deccbSFrançois Tigeot 
1020926deccbSFrançois Tigeot static device_method_t radeon_hw_i2c_methods[] = {
1021926deccbSFrançois Tigeot 	DEVMETHOD(device_probe,		radeon_hw_i2c_probe),
1022926deccbSFrançois Tigeot 	DEVMETHOD(device_attach,	radeon_hw_i2c_attach),
1023926deccbSFrançois Tigeot 	DEVMETHOD(device_detach,	radeon_hw_i2c_detach),
1024926deccbSFrançois Tigeot 	DEVMETHOD(iicbus_reset,		radeon_hw_i2c_reset),
1025926deccbSFrançois Tigeot 	DEVMETHOD(iicbus_transfer,	radeon_hw_i2c_xfer),
1026926deccbSFrançois Tigeot 	DEVMETHOD_END
1027926deccbSFrançois Tigeot };
1028926deccbSFrançois Tigeot 
1029926deccbSFrançois Tigeot static driver_t radeon_hw_i2c_driver = {
1030926deccbSFrançois Tigeot 	"radeon_hw_i2c",
1031926deccbSFrançois Tigeot 	radeon_hw_i2c_methods,
1032926deccbSFrançois Tigeot 	0 /* softc will be allocated by parent */
1033926deccbSFrançois Tigeot };
1034926deccbSFrançois Tigeot 
1035926deccbSFrançois Tigeot static devclass_t radeon_hw_i2c_devclass;
1036926deccbSFrançois Tigeot DRIVER_MODULE_ORDERED(radeon_hw_i2c, drm, radeon_hw_i2c_driver,
1037aa6ac96eSSascha Wildner     radeon_hw_i2c_devclass, NULL, NULL, SI_ORDER_FIRST);
10383a25be87SSascha Wildner DRIVER_MODULE(iicbus, radeon_hw_i2c, iicbus_driver, iicbus_devclass, NULL, NULL);
1039926deccbSFrançois Tigeot 
1040926deccbSFrançois Tigeot struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev,
1041926deccbSFrançois Tigeot 					  struct radeon_i2c_bus_rec *rec,
1042926deccbSFrançois Tigeot 					  const char *name)
1043926deccbSFrançois Tigeot {
1044926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
1045926deccbSFrançois Tigeot 	struct radeon_i2c_chan *i2c;
1046926deccbSFrançois Tigeot 	device_t iicbus_dev;
1047926deccbSFrançois Tigeot 	int ret;
1048926deccbSFrançois Tigeot 
1049926deccbSFrançois Tigeot 	/* don't add the mm_i2c bus unless hw_i2c is enabled */
1050926deccbSFrançois Tigeot 	if (rec->mm_i2c && (radeon_hw_i2c == 0))
1051926deccbSFrançois Tigeot 		return NULL;
1052926deccbSFrançois Tigeot 
1053c4ef309bSzrj 	i2c = kzalloc(sizeof(struct radeon_i2c_chan), GFP_KERNEL);
1054926deccbSFrançois Tigeot 	if (i2c == NULL)
1055926deccbSFrançois Tigeot 		return NULL;
1056926deccbSFrançois Tigeot 
1057926deccbSFrançois Tigeot 	/*
1058926deccbSFrançois Tigeot 	 * Grab Giant before messing with newbus devices, just in case
1059926deccbSFrançois Tigeot 	 * we do not hold it already.
1060926deccbSFrançois Tigeot 	 */
1061926deccbSFrançois Tigeot 	get_mplock();
1062926deccbSFrançois Tigeot 
1063926deccbSFrançois Tigeot 	i2c->rec = *rec;
1064926deccbSFrançois Tigeot 	i2c->dev = dev;
1065*7191d616Szrj 	lockinit(&i2c->mutex, "ri2cmtx", 0, LK_CANRECURSE);
1066926deccbSFrançois Tigeot 	if (rec->mm_i2c ||
1067926deccbSFrançois Tigeot 	    (rec->hw_capable &&
1068926deccbSFrançois Tigeot 	     radeon_hw_i2c &&
1069926deccbSFrançois Tigeot 	     ((rdev->family <= CHIP_RS480) ||
1070926deccbSFrançois Tigeot 	      ((rdev->family >= CHIP_RV515) && (rdev->family <= CHIP_R580))))) {
1071926deccbSFrançois Tigeot 		/* set the radeon hw i2c adapter */
1072926deccbSFrançois Tigeot 		ksnprintf(i2c->name, sizeof(i2c->name),
1073926deccbSFrançois Tigeot 			  "Radeon i2c hw bus %s", name);
10746df74fa7SFrançois Tigeot 		iicbus_dev = device_add_child(dev->dev, "radeon_hw_i2c", -1);
1075926deccbSFrançois Tigeot 		if (iicbus_dev == NULL) {
1076926deccbSFrançois Tigeot 			DRM_ERROR("Failed to create bridge for hw i2c %s\n",
1077926deccbSFrançois Tigeot 			    name);
1078926deccbSFrançois Tigeot 			goto out_free;
1079926deccbSFrançois Tigeot 		}
1080926deccbSFrançois Tigeot 		device_quiet(iicbus_dev);
1081926deccbSFrançois Tigeot 		device_set_softc(iicbus_dev, i2c);
1082926deccbSFrançois Tigeot 
1083926deccbSFrançois Tigeot 		ret = device_probe_and_attach(iicbus_dev);
1084926deccbSFrançois Tigeot 		if (ret != 0) {
1085926deccbSFrançois Tigeot 			DRM_ERROR("Attach failed for bridge for hw i2c %s\n",
1086926deccbSFrançois Tigeot 			    name);
10876df74fa7SFrançois Tigeot 			device_delete_child(dev->dev, iicbus_dev);
1088926deccbSFrançois Tigeot 			goto out_free;
1089926deccbSFrançois Tigeot 		}
1090926deccbSFrançois Tigeot 
1091926deccbSFrançois Tigeot 		i2c->adapter = device_find_child(iicbus_dev, "iicbus", -1);
1092926deccbSFrançois Tigeot 		if (i2c->adapter == NULL) {
1093926deccbSFrançois Tigeot 			DRM_ERROR("hw i2c bridge doesn't have iicbus child\n");
10946df74fa7SFrançois Tigeot 			device_delete_child(dev->dev, iicbus_dev);
1095926deccbSFrançois Tigeot 			goto out_free;
1096926deccbSFrançois Tigeot 		}
1097926deccbSFrançois Tigeot 	} else if (rec->hw_capable &&
1098926deccbSFrançois Tigeot 		   radeon_hw_i2c &&
1099926deccbSFrançois Tigeot 		   ASIC_IS_DCE3(rdev)) {
1100926deccbSFrançois Tigeot 		/* hw i2c using atom */
1101926deccbSFrançois Tigeot 		ksnprintf(i2c->name, sizeof(i2c->name),
1102926deccbSFrançois Tigeot 			  "Radeon i2c hw bus %s", name);
11036df74fa7SFrançois Tigeot 		iicbus_dev = device_add_child(dev->dev, "radeon_atom_hw_i2c", -1);
1104926deccbSFrançois Tigeot 		if (iicbus_dev == NULL) {
1105926deccbSFrançois Tigeot 			DRM_ERROR("Failed to create bridge for hw i2c %s\n",
1106926deccbSFrançois Tigeot 			    name);
1107926deccbSFrançois Tigeot 			goto out_free;
1108926deccbSFrançois Tigeot 		}
1109926deccbSFrançois Tigeot 		device_quiet(iicbus_dev);
1110926deccbSFrançois Tigeot 		device_set_softc(iicbus_dev, i2c);
1111926deccbSFrançois Tigeot 
1112926deccbSFrançois Tigeot 		ret = device_probe_and_attach(iicbus_dev);
1113926deccbSFrançois Tigeot 		if (ret != 0) {
1114926deccbSFrançois Tigeot 			DRM_ERROR("Attach failed for bridge for hw i2c %s\n",
1115926deccbSFrançois Tigeot 			    name);
11166df74fa7SFrançois Tigeot 			device_delete_child(dev->dev, iicbus_dev);
1117926deccbSFrançois Tigeot 			goto out_free;
1118926deccbSFrançois Tigeot 		}
1119926deccbSFrançois Tigeot 
1120926deccbSFrançois Tigeot 		i2c->adapter = device_find_child(iicbus_dev, "iicbus", -1);
1121926deccbSFrançois Tigeot 		if (i2c->adapter == NULL) {
1122926deccbSFrançois Tigeot 			DRM_ERROR("hw i2c bridge doesn't have iicbus child\n");
11236df74fa7SFrançois Tigeot 			device_delete_child(dev->dev, iicbus_dev);
1124926deccbSFrançois Tigeot 			goto out_free;
1125926deccbSFrançois Tigeot 		}
1126926deccbSFrançois Tigeot 	} else {
1127926deccbSFrançois Tigeot 		device_t iicbb_dev;
1128926deccbSFrançois Tigeot 
1129926deccbSFrançois Tigeot 		/* set the radeon bit adapter */
1130926deccbSFrançois Tigeot 		ksnprintf(i2c->name, sizeof(i2c->name),
1131926deccbSFrançois Tigeot 			  "Radeon i2c bit bus %s", name);
11326df74fa7SFrançois Tigeot 		iicbus_dev = device_add_child(dev->dev, "radeon_iicbb", -1);
1133926deccbSFrançois Tigeot 		if (iicbus_dev == NULL) {
1134926deccbSFrançois Tigeot 			DRM_ERROR("Failed to create bridge for bb i2c %s\n",
1135926deccbSFrançois Tigeot 			    name);
1136926deccbSFrançois Tigeot 			goto out_free;
1137926deccbSFrançois Tigeot 		}
1138926deccbSFrançois Tigeot 		device_quiet(iicbus_dev);
1139926deccbSFrançois Tigeot 		device_set_softc(iicbus_dev, i2c);
1140926deccbSFrançois Tigeot 
1141926deccbSFrançois Tigeot 		ret = device_probe_and_attach(iicbus_dev);
1142926deccbSFrançois Tigeot 		if (ret != 0) {
1143926deccbSFrançois Tigeot 			DRM_ERROR("Attach failed for bridge for bb i2c %s\n",
1144926deccbSFrançois Tigeot 			    name);
11456df74fa7SFrançois Tigeot 			device_delete_child(dev->dev, iicbus_dev);
1146926deccbSFrançois Tigeot 			goto out_free;
1147926deccbSFrançois Tigeot 		}
1148926deccbSFrançois Tigeot 
1149926deccbSFrançois Tigeot 		iicbb_dev = device_find_child(iicbus_dev, "iicbb", -1);
1150926deccbSFrançois Tigeot 		if (iicbb_dev == NULL) {
1151926deccbSFrançois Tigeot 			DRM_ERROR("bb i2c bridge doesn't have iicbb child\n");
11526df74fa7SFrançois Tigeot 			device_delete_child(dev->dev, iicbus_dev);
1153926deccbSFrançois Tigeot 			goto out_free;
1154926deccbSFrançois Tigeot 		}
1155926deccbSFrançois Tigeot 
1156926deccbSFrançois Tigeot 		i2c->adapter = device_find_child(iicbb_dev, "iicbus", -1);
1157926deccbSFrançois Tigeot 		if (i2c->adapter == NULL) {
1158926deccbSFrançois Tigeot 			DRM_ERROR(
1159926deccbSFrançois Tigeot 			    "bbbus bridge doesn't have iicbus grandchild\n");
11606df74fa7SFrançois Tigeot 			device_delete_child(dev->dev, iicbus_dev);
1161926deccbSFrançois Tigeot 			goto out_free;
1162926deccbSFrançois Tigeot 		}
1163926deccbSFrançois Tigeot 	}
1164926deccbSFrançois Tigeot 
1165926deccbSFrançois Tigeot 	i2c->iic_bus = iicbus_dev;
1166926deccbSFrançois Tigeot 
1167926deccbSFrançois Tigeot 	rel_mplock();
1168926deccbSFrançois Tigeot 
1169926deccbSFrançois Tigeot 	return i2c;
1170926deccbSFrançois Tigeot out_free:
1171926deccbSFrançois Tigeot 	rel_mplock();
1172c4ef309bSzrj 	kfree(i2c);
1173926deccbSFrançois Tigeot 	return NULL;
1174926deccbSFrançois Tigeot 
1175926deccbSFrançois Tigeot }
1176926deccbSFrançois Tigeot 
1177926deccbSFrançois Tigeot struct radeon_i2c_chan *radeon_i2c_create_dp(struct drm_device *dev,
1178926deccbSFrançois Tigeot 					     struct radeon_i2c_bus_rec *rec,
1179926deccbSFrançois Tigeot 					     const char *name)
1180926deccbSFrançois Tigeot {
1181926deccbSFrançois Tigeot 	struct radeon_i2c_chan *i2c;
1182926deccbSFrançois Tigeot 	int ret;
1183926deccbSFrançois Tigeot 
1184c4ef309bSzrj 	i2c = kzalloc(sizeof(struct radeon_i2c_chan), GFP_KERNEL);
1185926deccbSFrançois Tigeot 	if (i2c == NULL)
1186926deccbSFrançois Tigeot 		return NULL;
1187926deccbSFrançois Tigeot 
1188926deccbSFrançois Tigeot 	i2c->rec = *rec;
1189926deccbSFrançois Tigeot 	i2c->dev = dev;
1190926deccbSFrançois Tigeot 	ksnprintf(i2c->name, sizeof(i2c->name), "Radeon aux bus %s", name);
11916df74fa7SFrançois Tigeot 	ret = iic_dp_aux_add_bus(dev->dev, i2c->name,
1192926deccbSFrançois Tigeot 	    radeon_dp_i2c_aux_ch, i2c, &i2c->iic_bus,
1193926deccbSFrançois Tigeot 	    &i2c->adapter);
1194926deccbSFrançois Tigeot 	if (ret) {
1195926deccbSFrançois Tigeot 		DRM_INFO("Failed to register i2c %s\n", name);
1196926deccbSFrançois Tigeot 		goto out_free;
1197926deccbSFrançois Tigeot 	}
1198926deccbSFrançois Tigeot 
1199926deccbSFrançois Tigeot 	return i2c;
1200926deccbSFrançois Tigeot out_free:
1201c4ef309bSzrj 	kfree(i2c);
1202926deccbSFrançois Tigeot 	return NULL;
1203926deccbSFrançois Tigeot 
1204926deccbSFrançois Tigeot }
1205926deccbSFrançois Tigeot 
1206926deccbSFrançois Tigeot void radeon_i2c_destroy(struct radeon_i2c_chan *i2c)
1207926deccbSFrançois Tigeot {
1208926deccbSFrançois Tigeot 	if (!i2c)
1209926deccbSFrançois Tigeot 		return;
1210926deccbSFrançois Tigeot 	if (i2c->iic_bus != NULL) {
1211926deccbSFrançois Tigeot 		int ret;
1212926deccbSFrançois Tigeot 
1213926deccbSFrançois Tigeot 		get_mplock();
12146df74fa7SFrançois Tigeot 		ret = device_delete_child(i2c->dev->dev, i2c->iic_bus);
1215926deccbSFrançois Tigeot 		rel_mplock();
1216926deccbSFrançois Tigeot 		KASSERT(ret == 0, ("unable to detach iic bus %s: %d",
1217926deccbSFrançois Tigeot 		    i2c->name, ret));
1218926deccbSFrançois Tigeot 	}
1219c4ef309bSzrj 	kfree(i2c);
1220926deccbSFrançois Tigeot }
1221926deccbSFrançois Tigeot 
1222926deccbSFrançois Tigeot /* Add the default buses */
1223926deccbSFrançois Tigeot void radeon_i2c_init(struct radeon_device *rdev)
1224926deccbSFrançois Tigeot {
1225c6f73aabSFrançois Tigeot 	if (radeon_hw_i2c)
1226c6f73aabSFrançois Tigeot 		DRM_INFO("hw_i2c forced on, you may experience display detection problems!\n");
1227c6f73aabSFrançois Tigeot 
1228926deccbSFrançois Tigeot 	if (rdev->is_atom_bios)
1229926deccbSFrançois Tigeot 		radeon_atombios_i2c_init(rdev);
1230926deccbSFrançois Tigeot 	else
1231926deccbSFrançois Tigeot 		radeon_combios_i2c_init(rdev);
1232926deccbSFrançois Tigeot }
1233926deccbSFrançois Tigeot 
1234926deccbSFrançois Tigeot /* remove all the buses */
1235926deccbSFrançois Tigeot void radeon_i2c_fini(struct radeon_device *rdev)
1236926deccbSFrançois Tigeot {
1237926deccbSFrançois Tigeot 	int i;
1238926deccbSFrançois Tigeot 
1239926deccbSFrançois Tigeot 	for (i = 0; i < RADEON_MAX_I2C_BUS; i++) {
1240926deccbSFrançois Tigeot 		if (rdev->i2c_bus[i]) {
1241926deccbSFrançois Tigeot 			radeon_i2c_destroy(rdev->i2c_bus[i]);
1242926deccbSFrançois Tigeot 			rdev->i2c_bus[i] = NULL;
1243926deccbSFrançois Tigeot 		}
1244926deccbSFrançois Tigeot 	}
1245926deccbSFrançois Tigeot }
1246926deccbSFrançois Tigeot 
1247926deccbSFrançois Tigeot /* Add additional buses */
1248926deccbSFrançois Tigeot void radeon_i2c_add(struct radeon_device *rdev,
1249926deccbSFrançois Tigeot 		    struct radeon_i2c_bus_rec *rec,
1250926deccbSFrançois Tigeot 		    const char *name)
1251926deccbSFrançois Tigeot {
1252926deccbSFrançois Tigeot 	struct drm_device *dev = rdev->ddev;
1253926deccbSFrançois Tigeot 	int i;
1254926deccbSFrançois Tigeot 
1255926deccbSFrançois Tigeot 	for (i = 0; i < RADEON_MAX_I2C_BUS; i++) {
1256926deccbSFrançois Tigeot 		if (!rdev->i2c_bus[i]) {
1257926deccbSFrançois Tigeot 			rdev->i2c_bus[i] = radeon_i2c_create(dev, rec, name);
1258926deccbSFrançois Tigeot 			return;
1259926deccbSFrançois Tigeot 		}
1260926deccbSFrançois Tigeot 	}
1261926deccbSFrançois Tigeot }
1262926deccbSFrançois Tigeot 
1263926deccbSFrançois Tigeot /* looks up bus based on id */
1264926deccbSFrançois Tigeot struct radeon_i2c_chan *radeon_i2c_lookup(struct radeon_device *rdev,
1265926deccbSFrançois Tigeot 					  struct radeon_i2c_bus_rec *i2c_bus)
1266926deccbSFrançois Tigeot {
1267926deccbSFrançois Tigeot 	int i;
1268926deccbSFrançois Tigeot 
1269926deccbSFrançois Tigeot 	for (i = 0; i < RADEON_MAX_I2C_BUS; i++) {
1270926deccbSFrançois Tigeot 		if (rdev->i2c_bus[i] &&
1271926deccbSFrançois Tigeot 		    (rdev->i2c_bus[i]->rec.i2c_id == i2c_bus->i2c_id)) {
1272926deccbSFrançois Tigeot 			return rdev->i2c_bus[i];
1273926deccbSFrançois Tigeot 		}
1274926deccbSFrançois Tigeot 	}
1275926deccbSFrançois Tigeot 	return NULL;
1276926deccbSFrançois Tigeot }
1277926deccbSFrançois Tigeot 
1278926deccbSFrançois Tigeot struct drm_encoder *radeon_best_encoder(struct drm_connector *connector)
1279926deccbSFrançois Tigeot {
1280926deccbSFrançois Tigeot 	return NULL;
1281926deccbSFrançois Tigeot }
1282926deccbSFrançois Tigeot 
1283926deccbSFrançois Tigeot void radeon_i2c_get_byte(struct radeon_i2c_chan *i2c_bus,
1284926deccbSFrançois Tigeot 			 u8 slave_addr,
1285926deccbSFrançois Tigeot 			 u8 addr,
1286926deccbSFrançois Tigeot 			 u8 *val)
1287926deccbSFrançois Tigeot {
1288926deccbSFrançois Tigeot 	u8 out_buf[2];
1289926deccbSFrançois Tigeot 	u8 in_buf[2];
1290926deccbSFrançois Tigeot 	struct iic_msg msgs[] = {
1291926deccbSFrançois Tigeot 		{
1292926deccbSFrançois Tigeot 			.slave = slave_addr << 1,
1293926deccbSFrançois Tigeot 			.flags = 0,
1294926deccbSFrançois Tigeot 			.len = 1,
1295926deccbSFrançois Tigeot 			.buf = out_buf,
1296926deccbSFrançois Tigeot 		},
1297926deccbSFrançois Tigeot 		{
1298926deccbSFrançois Tigeot 			.slave = slave_addr << 1,
1299926deccbSFrançois Tigeot 			.flags = IIC_M_RD,
1300926deccbSFrançois Tigeot 			.len = 1,
1301926deccbSFrançois Tigeot 			.buf = in_buf,
1302926deccbSFrançois Tigeot 		}
1303926deccbSFrançois Tigeot 	};
1304926deccbSFrançois Tigeot 
1305926deccbSFrançois Tigeot 	out_buf[0] = addr;
1306926deccbSFrançois Tigeot 	out_buf[1] = 0;
1307926deccbSFrançois Tigeot 
1308926deccbSFrançois Tigeot 	if (iicbus_transfer(i2c_bus->adapter, msgs, 2) == 0) {
1309926deccbSFrançois Tigeot 		*val = in_buf[0];
1310926deccbSFrançois Tigeot 		DRM_DEBUG("val = 0x%02x\n", *val);
1311926deccbSFrançois Tigeot 	} else {
1312926deccbSFrançois Tigeot 		DRM_DEBUG("i2c 0x%02x 0x%02x read failed\n",
1313926deccbSFrançois Tigeot 			  addr, *val);
1314926deccbSFrançois Tigeot 	}
1315926deccbSFrançois Tigeot }
1316926deccbSFrançois Tigeot 
1317926deccbSFrançois Tigeot void radeon_i2c_put_byte(struct radeon_i2c_chan *i2c_bus,
1318926deccbSFrançois Tigeot 			 u8 slave_addr,
1319926deccbSFrançois Tigeot 			 u8 addr,
1320926deccbSFrançois Tigeot 			 u8 val)
1321926deccbSFrançois Tigeot {
1322926deccbSFrançois Tigeot 	uint8_t out_buf[2];
1323926deccbSFrançois Tigeot 	struct iic_msg msg = {
1324926deccbSFrançois Tigeot 		.slave = slave_addr << 1,
1325926deccbSFrançois Tigeot 		.flags = 0,
1326926deccbSFrançois Tigeot 		.len = 2,
1327926deccbSFrançois Tigeot 		.buf = out_buf,
1328926deccbSFrançois Tigeot 	};
1329926deccbSFrançois Tigeot 
1330926deccbSFrançois Tigeot 	out_buf[0] = addr;
1331926deccbSFrançois Tigeot 	out_buf[1] = val;
1332926deccbSFrançois Tigeot 
1333926deccbSFrançois Tigeot 	if (iicbus_transfer(i2c_bus->adapter, &msg, 1) != 0)
1334926deccbSFrançois Tigeot 		DRM_DEBUG("i2c 0x%02x 0x%02x write failed\n",
1335926deccbSFrançois Tigeot 			  addr, val);
1336926deccbSFrançois Tigeot }
1337926deccbSFrançois Tigeot 
1338926deccbSFrançois Tigeot /* ddc router switching */
1339926deccbSFrançois Tigeot void radeon_router_select_ddc_port(struct radeon_connector *radeon_connector)
1340926deccbSFrançois Tigeot {
1341926deccbSFrançois Tigeot 	u8 val;
1342926deccbSFrançois Tigeot 
1343926deccbSFrançois Tigeot 	if (!radeon_connector->router.ddc_valid)
1344926deccbSFrançois Tigeot 		return;
1345926deccbSFrançois Tigeot 
1346926deccbSFrançois Tigeot 	if (!radeon_connector->router_bus)
1347926deccbSFrançois Tigeot 		return;
1348926deccbSFrançois Tigeot 
1349926deccbSFrançois Tigeot 	radeon_i2c_get_byte(radeon_connector->router_bus,
1350926deccbSFrançois Tigeot 			    radeon_connector->router.i2c_addr,
1351926deccbSFrançois Tigeot 			    0x3, &val);
1352926deccbSFrançois Tigeot 	val &= ~radeon_connector->router.ddc_mux_control_pin;
1353926deccbSFrançois Tigeot 	radeon_i2c_put_byte(radeon_connector->router_bus,
1354926deccbSFrançois Tigeot 			    radeon_connector->router.i2c_addr,
1355926deccbSFrançois Tigeot 			    0x3, val);
1356926deccbSFrançois Tigeot 	radeon_i2c_get_byte(radeon_connector->router_bus,
1357926deccbSFrançois Tigeot 			    radeon_connector->router.i2c_addr,
1358926deccbSFrançois Tigeot 			    0x1, &val);
1359926deccbSFrançois Tigeot 	val &= ~radeon_connector->router.ddc_mux_control_pin;
1360926deccbSFrançois Tigeot 	val |= radeon_connector->router.ddc_mux_state;
1361926deccbSFrançois Tigeot 	radeon_i2c_put_byte(radeon_connector->router_bus,
1362926deccbSFrançois Tigeot 			    radeon_connector->router.i2c_addr,
1363926deccbSFrançois Tigeot 			    0x1, val);
1364926deccbSFrançois Tigeot }
1365926deccbSFrançois Tigeot 
1366926deccbSFrançois Tigeot /* clock/data router switching */
1367926deccbSFrançois Tigeot void radeon_router_select_cd_port(struct radeon_connector *radeon_connector)
1368926deccbSFrançois Tigeot {
1369926deccbSFrançois Tigeot 	u8 val;
1370926deccbSFrançois Tigeot 
1371926deccbSFrançois Tigeot 	if (!radeon_connector->router.cd_valid)
1372926deccbSFrançois Tigeot 		return;
1373926deccbSFrançois Tigeot 
1374926deccbSFrançois Tigeot 	if (!radeon_connector->router_bus)
1375926deccbSFrançois Tigeot 		return;
1376926deccbSFrançois Tigeot 
1377926deccbSFrançois Tigeot 	radeon_i2c_get_byte(radeon_connector->router_bus,
1378926deccbSFrançois Tigeot 			    radeon_connector->router.i2c_addr,
1379926deccbSFrançois Tigeot 			    0x3, &val);
1380926deccbSFrançois Tigeot 	val &= ~radeon_connector->router.cd_mux_control_pin;
1381926deccbSFrançois Tigeot 	radeon_i2c_put_byte(radeon_connector->router_bus,
1382926deccbSFrançois Tigeot 			    radeon_connector->router.i2c_addr,
1383926deccbSFrançois Tigeot 			    0x3, val);
1384926deccbSFrançois Tigeot 	radeon_i2c_get_byte(radeon_connector->router_bus,
1385926deccbSFrançois Tigeot 			    radeon_connector->router.i2c_addr,
1386926deccbSFrançois Tigeot 			    0x1, &val);
1387926deccbSFrançois Tigeot 	val &= ~radeon_connector->router.cd_mux_control_pin;
1388926deccbSFrançois Tigeot 	val |= radeon_connector->router.cd_mux_state;
1389926deccbSFrançois Tigeot 	radeon_i2c_put_byte(radeon_connector->router_bus,
1390926deccbSFrançois Tigeot 			    radeon_connector->router.i2c_addr,
1391926deccbSFrançois Tigeot 			    0x1, val);
1392926deccbSFrançois Tigeot }
1393926deccbSFrançois Tigeot 
1394