xref: /openbsd/sys/dev/pci/drm/amd/amdgpu/amdgpu_i2c.c (revision fb4d8502)
1*fb4d8502Sjsg /*
2*fb4d8502Sjsg  * Copyright 2007-8 Advanced Micro Devices, Inc.
3*fb4d8502Sjsg  * Copyright 2008 Red Hat Inc.
4*fb4d8502Sjsg  *
5*fb4d8502Sjsg  * Permission is hereby granted, free of charge, to any person obtaining a
6*fb4d8502Sjsg  * copy of this software and associated documentation files (the "Software"),
7*fb4d8502Sjsg  * to deal in the Software without restriction, including without limitation
8*fb4d8502Sjsg  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9*fb4d8502Sjsg  * and/or sell copies of the Software, and to permit persons to whom the
10*fb4d8502Sjsg  * Software is furnished to do so, subject to the following conditions:
11*fb4d8502Sjsg  *
12*fb4d8502Sjsg  * The above copyright notice and this permission notice shall be included in
13*fb4d8502Sjsg  * all copies or substantial portions of the Software.
14*fb4d8502Sjsg  *
15*fb4d8502Sjsg  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16*fb4d8502Sjsg  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17*fb4d8502Sjsg  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18*fb4d8502Sjsg  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
19*fb4d8502Sjsg  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20*fb4d8502Sjsg  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21*fb4d8502Sjsg  * OTHER DEALINGS IN THE SOFTWARE.
22*fb4d8502Sjsg  *
23*fb4d8502Sjsg  * Authors: Dave Airlie
24*fb4d8502Sjsg  *          Alex Deucher
25*fb4d8502Sjsg  */
26*fb4d8502Sjsg #include <linux/export.h>
27*fb4d8502Sjsg 
28*fb4d8502Sjsg #include <drm/drmP.h>
29*fb4d8502Sjsg #include <drm/drm_edid.h>
30*fb4d8502Sjsg #include <drm/amdgpu_drm.h>
31*fb4d8502Sjsg #include "amdgpu.h"
32*fb4d8502Sjsg #include "amdgpu_i2c.h"
33*fb4d8502Sjsg #include "amdgpu_atombios.h"
34*fb4d8502Sjsg #include "atom.h"
35*fb4d8502Sjsg #include "atombios_dp.h"
36*fb4d8502Sjsg #include "atombios_i2c.h"
37*fb4d8502Sjsg 
38*fb4d8502Sjsg #include <dev/i2c/i2cvar.h>
39*fb4d8502Sjsg #include <dev/i2c/i2c_bitbang.h>
40*fb4d8502Sjsg 
41*fb4d8502Sjsg /* bit banging i2c */
42*fb4d8502Sjsg static int amdgpu_i2c_pre_xfer(struct i2c_adapter *i2c_adap)
43*fb4d8502Sjsg {
44*fb4d8502Sjsg 	struct amdgpu_i2c_chan *i2c = i2c_get_adapdata(i2c_adap);
45*fb4d8502Sjsg 	struct amdgpu_device *adev = i2c->dev->dev_private;
46*fb4d8502Sjsg 	struct amdgpu_i2c_bus_rec *rec = &i2c->rec;
47*fb4d8502Sjsg 	uint32_t temp;
48*fb4d8502Sjsg 
49*fb4d8502Sjsg 	mutex_lock(&i2c->mutex);
50*fb4d8502Sjsg 
51*fb4d8502Sjsg 	/* switch the pads to ddc mode */
52*fb4d8502Sjsg 	if (rec->hw_capable) {
53*fb4d8502Sjsg 		temp = RREG32(rec->mask_clk_reg);
54*fb4d8502Sjsg 		temp &= ~(1 << 16);
55*fb4d8502Sjsg 		WREG32(rec->mask_clk_reg, temp);
56*fb4d8502Sjsg 	}
57*fb4d8502Sjsg 
58*fb4d8502Sjsg 	/* clear the output pin values */
59*fb4d8502Sjsg 	temp = RREG32(rec->a_clk_reg) & ~rec->a_clk_mask;
60*fb4d8502Sjsg 	WREG32(rec->a_clk_reg, temp);
61*fb4d8502Sjsg 
62*fb4d8502Sjsg 	temp = RREG32(rec->a_data_reg) & ~rec->a_data_mask;
63*fb4d8502Sjsg 	WREG32(rec->a_data_reg, temp);
64*fb4d8502Sjsg 
65*fb4d8502Sjsg 	/* set the pins to input */
66*fb4d8502Sjsg 	temp = RREG32(rec->en_clk_reg) & ~rec->en_clk_mask;
67*fb4d8502Sjsg 	WREG32(rec->en_clk_reg, temp);
68*fb4d8502Sjsg 
69*fb4d8502Sjsg 	temp = RREG32(rec->en_data_reg) & ~rec->en_data_mask;
70*fb4d8502Sjsg 	WREG32(rec->en_data_reg, temp);
71*fb4d8502Sjsg 
72*fb4d8502Sjsg 	/* mask the gpio pins for software use */
73*fb4d8502Sjsg 	temp = RREG32(rec->mask_clk_reg) | rec->mask_clk_mask;
74*fb4d8502Sjsg 	WREG32(rec->mask_clk_reg, temp);
75*fb4d8502Sjsg 	temp = RREG32(rec->mask_clk_reg);
76*fb4d8502Sjsg 
77*fb4d8502Sjsg 	temp = RREG32(rec->mask_data_reg) | rec->mask_data_mask;
78*fb4d8502Sjsg 	WREG32(rec->mask_data_reg, temp);
79*fb4d8502Sjsg 	temp = RREG32(rec->mask_data_reg);
80*fb4d8502Sjsg 
81*fb4d8502Sjsg 	return 0;
82*fb4d8502Sjsg }
83*fb4d8502Sjsg 
84*fb4d8502Sjsg static void amdgpu_i2c_post_xfer(struct i2c_adapter *i2c_adap)
85*fb4d8502Sjsg {
86*fb4d8502Sjsg 	struct amdgpu_i2c_chan *i2c = i2c_get_adapdata(i2c_adap);
87*fb4d8502Sjsg 	struct amdgpu_device *adev = i2c->dev->dev_private;
88*fb4d8502Sjsg 	struct amdgpu_i2c_bus_rec *rec = &i2c->rec;
89*fb4d8502Sjsg 	uint32_t temp;
90*fb4d8502Sjsg 
91*fb4d8502Sjsg 	/* unmask the gpio pins for software use */
92*fb4d8502Sjsg 	temp = RREG32(rec->mask_clk_reg) & ~rec->mask_clk_mask;
93*fb4d8502Sjsg 	WREG32(rec->mask_clk_reg, temp);
94*fb4d8502Sjsg 	temp = RREG32(rec->mask_clk_reg);
95*fb4d8502Sjsg 
96*fb4d8502Sjsg 	temp = RREG32(rec->mask_data_reg) & ~rec->mask_data_mask;
97*fb4d8502Sjsg 	WREG32(rec->mask_data_reg, temp);
98*fb4d8502Sjsg 	temp = RREG32(rec->mask_data_reg);
99*fb4d8502Sjsg 
100*fb4d8502Sjsg 	mutex_unlock(&i2c->mutex);
101*fb4d8502Sjsg }
102*fb4d8502Sjsg 
103*fb4d8502Sjsg static int amdgpu_i2c_get_clock(void *i2c_priv)
104*fb4d8502Sjsg {
105*fb4d8502Sjsg 	struct amdgpu_i2c_chan *i2c = i2c_priv;
106*fb4d8502Sjsg 	struct amdgpu_device *adev = i2c->dev->dev_private;
107*fb4d8502Sjsg 	struct amdgpu_i2c_bus_rec *rec = &i2c->rec;
108*fb4d8502Sjsg 	uint32_t val;
109*fb4d8502Sjsg 
110*fb4d8502Sjsg 	/* read the value off the pin */
111*fb4d8502Sjsg 	val = RREG32(rec->y_clk_reg);
112*fb4d8502Sjsg 	val &= rec->y_clk_mask;
113*fb4d8502Sjsg 
114*fb4d8502Sjsg 	return (val != 0);
115*fb4d8502Sjsg }
116*fb4d8502Sjsg 
117*fb4d8502Sjsg 
118*fb4d8502Sjsg static int amdgpu_i2c_get_data(void *i2c_priv)
119*fb4d8502Sjsg {
120*fb4d8502Sjsg 	struct amdgpu_i2c_chan *i2c = i2c_priv;
121*fb4d8502Sjsg 	struct amdgpu_device *adev = i2c->dev->dev_private;
122*fb4d8502Sjsg 	struct amdgpu_i2c_bus_rec *rec = &i2c->rec;
123*fb4d8502Sjsg 	uint32_t val;
124*fb4d8502Sjsg 
125*fb4d8502Sjsg 	/* read the value off the pin */
126*fb4d8502Sjsg 	val = RREG32(rec->y_data_reg);
127*fb4d8502Sjsg 	val &= rec->y_data_mask;
128*fb4d8502Sjsg 
129*fb4d8502Sjsg 	return (val != 0);
130*fb4d8502Sjsg }
131*fb4d8502Sjsg 
132*fb4d8502Sjsg static void amdgpu_i2c_set_clock(void *i2c_priv, int clock)
133*fb4d8502Sjsg {
134*fb4d8502Sjsg 	struct amdgpu_i2c_chan *i2c = i2c_priv;
135*fb4d8502Sjsg 	struct amdgpu_device *adev = i2c->dev->dev_private;
136*fb4d8502Sjsg 	struct amdgpu_i2c_bus_rec *rec = &i2c->rec;
137*fb4d8502Sjsg 	uint32_t val;
138*fb4d8502Sjsg 
139*fb4d8502Sjsg 	/* set pin direction */
140*fb4d8502Sjsg 	val = RREG32(rec->en_clk_reg) & ~rec->en_clk_mask;
141*fb4d8502Sjsg 	val |= clock ? 0 : rec->en_clk_mask;
142*fb4d8502Sjsg 	WREG32(rec->en_clk_reg, val);
143*fb4d8502Sjsg }
144*fb4d8502Sjsg 
145*fb4d8502Sjsg static void amdgpu_i2c_set_data(void *i2c_priv, int data)
146*fb4d8502Sjsg {
147*fb4d8502Sjsg 	struct amdgpu_i2c_chan *i2c = i2c_priv;
148*fb4d8502Sjsg 	struct amdgpu_device *adev = i2c->dev->dev_private;
149*fb4d8502Sjsg 	struct amdgpu_i2c_bus_rec *rec = &i2c->rec;
150*fb4d8502Sjsg 	uint32_t val;
151*fb4d8502Sjsg 
152*fb4d8502Sjsg 	/* set pin direction */
153*fb4d8502Sjsg 	val = RREG32(rec->en_data_reg) & ~rec->en_data_mask;
154*fb4d8502Sjsg 	val |= data ? 0 : rec->en_data_mask;
155*fb4d8502Sjsg 	WREG32(rec->en_data_reg, val);
156*fb4d8502Sjsg }
157*fb4d8502Sjsg 
158*fb4d8502Sjsg void	amdgpu_bb_set_bits(void *, uint32_t);
159*fb4d8502Sjsg void	amdgpu_bb_set_dir(void *, uint32_t);
160*fb4d8502Sjsg uint32_t amdgpu_bb_read_bits(void *);
161*fb4d8502Sjsg 
162*fb4d8502Sjsg int	amdgpu_acquire_bus(void *, int);
163*fb4d8502Sjsg void	amdgpu_release_bus(void *, int);
164*fb4d8502Sjsg int	amdgpu_send_start(void *, int);
165*fb4d8502Sjsg int	amdgpu_send_stop(void *, int);
166*fb4d8502Sjsg int	amdgpu_initiate_xfer(void *, i2c_addr_t, int);
167*fb4d8502Sjsg int	amdgpu_read_byte(void *, u_int8_t *, int);
168*fb4d8502Sjsg int	amdgpu_write_byte(void *, u_int8_t, int);
169*fb4d8502Sjsg 
170*fb4d8502Sjsg #define AMDGPU_BB_SDA		(1 << I2C_BIT_SDA)
171*fb4d8502Sjsg #define AMDGPU_BB_SCL		(1 << I2C_BIT_SCL)
172*fb4d8502Sjsg 
173*fb4d8502Sjsg struct i2c_bitbang_ops amdgpu_bbops = {
174*fb4d8502Sjsg 	amdgpu_bb_set_bits,
175*fb4d8502Sjsg 	amdgpu_bb_set_dir,
176*fb4d8502Sjsg 	amdgpu_bb_read_bits,
177*fb4d8502Sjsg 	{ AMDGPU_BB_SDA, AMDGPU_BB_SCL, 0, 0 }
178*fb4d8502Sjsg };
179*fb4d8502Sjsg 
180*fb4d8502Sjsg void
181*fb4d8502Sjsg amdgpu_bb_set_bits(void *cookie, uint32_t bits)
182*fb4d8502Sjsg {
183*fb4d8502Sjsg 	amdgpu_i2c_set_clock(cookie, bits & AMDGPU_BB_SCL);
184*fb4d8502Sjsg 	amdgpu_i2c_set_data(cookie, bits & AMDGPU_BB_SDA);
185*fb4d8502Sjsg }
186*fb4d8502Sjsg 
187*fb4d8502Sjsg void
188*fb4d8502Sjsg amdgpu_bb_set_dir(void *cookie, uint32_t bits)
189*fb4d8502Sjsg {
190*fb4d8502Sjsg }
191*fb4d8502Sjsg 
192*fb4d8502Sjsg uint32_t
193*fb4d8502Sjsg amdgpu_bb_read_bits(void *cookie)
194*fb4d8502Sjsg {
195*fb4d8502Sjsg 	uint32_t bits = 0;
196*fb4d8502Sjsg 
197*fb4d8502Sjsg 	if (amdgpu_i2c_get_clock(cookie))
198*fb4d8502Sjsg 		bits |= AMDGPU_BB_SCL;
199*fb4d8502Sjsg 	if (amdgpu_i2c_get_data(cookie))
200*fb4d8502Sjsg 		bits |= AMDGPU_BB_SDA;
201*fb4d8502Sjsg 
202*fb4d8502Sjsg 	return bits;
203*fb4d8502Sjsg }
204*fb4d8502Sjsg 
205*fb4d8502Sjsg int
206*fb4d8502Sjsg amdgpu_acquire_bus(void *cookie, int flags)
207*fb4d8502Sjsg {
208*fb4d8502Sjsg 	struct amdgpu_i2c_chan *i2c = cookie;
209*fb4d8502Sjsg 	amdgpu_i2c_pre_xfer(&i2c->adapter);
210*fb4d8502Sjsg 	return (0);
211*fb4d8502Sjsg }
212*fb4d8502Sjsg 
213*fb4d8502Sjsg void
214*fb4d8502Sjsg amdgpu_release_bus(void *cookie, int flags)
215*fb4d8502Sjsg {
216*fb4d8502Sjsg 	struct amdgpu_i2c_chan *i2c = cookie;
217*fb4d8502Sjsg 	amdgpu_i2c_post_xfer(&i2c->adapter);
218*fb4d8502Sjsg }
219*fb4d8502Sjsg 
220*fb4d8502Sjsg int
221*fb4d8502Sjsg amdgpu_send_start(void *cookie, int flags)
222*fb4d8502Sjsg {
223*fb4d8502Sjsg 	return (i2c_bitbang_send_start(cookie, flags, &amdgpu_bbops));
224*fb4d8502Sjsg }
225*fb4d8502Sjsg 
226*fb4d8502Sjsg int
227*fb4d8502Sjsg amdgpu_send_stop(void *cookie, int flags)
228*fb4d8502Sjsg {
229*fb4d8502Sjsg 	return (i2c_bitbang_send_stop(cookie, flags, &amdgpu_bbops));
230*fb4d8502Sjsg }
231*fb4d8502Sjsg 
232*fb4d8502Sjsg int
233*fb4d8502Sjsg amdgpu_initiate_xfer(void *cookie, i2c_addr_t addr, int flags)
234*fb4d8502Sjsg {
235*fb4d8502Sjsg 	return (i2c_bitbang_initiate_xfer(cookie, addr, flags, &amdgpu_bbops));
236*fb4d8502Sjsg }
237*fb4d8502Sjsg 
238*fb4d8502Sjsg int
239*fb4d8502Sjsg amdgpu_read_byte(void *cookie, u_int8_t *bytep, int flags)
240*fb4d8502Sjsg {
241*fb4d8502Sjsg 	return (i2c_bitbang_read_byte(cookie, bytep, flags, &amdgpu_bbops));
242*fb4d8502Sjsg }
243*fb4d8502Sjsg 
244*fb4d8502Sjsg int
245*fb4d8502Sjsg amdgpu_write_byte(void *cookie, u_int8_t byte, int flags)
246*fb4d8502Sjsg {
247*fb4d8502Sjsg 	return (i2c_bitbang_write_byte(cookie, byte, flags, &amdgpu_bbops));
248*fb4d8502Sjsg }
249*fb4d8502Sjsg 
250*fb4d8502Sjsg static const struct i2c_algorithm amdgpu_atombios_i2c_algo = {
251*fb4d8502Sjsg 	.master_xfer = amdgpu_atombios_i2c_xfer,
252*fb4d8502Sjsg 	.functionality = amdgpu_atombios_i2c_func,
253*fb4d8502Sjsg };
254*fb4d8502Sjsg 
255*fb4d8502Sjsg struct amdgpu_i2c_chan *amdgpu_i2c_create(struct drm_device *dev,
256*fb4d8502Sjsg 					  const struct amdgpu_i2c_bus_rec *rec,
257*fb4d8502Sjsg 					  const char *name)
258*fb4d8502Sjsg {
259*fb4d8502Sjsg 	struct amdgpu_i2c_chan *i2c;
260*fb4d8502Sjsg 	int ret;
261*fb4d8502Sjsg 
262*fb4d8502Sjsg 	/* don't add the mm_i2c bus unless hw_i2c is enabled */
263*fb4d8502Sjsg 	if (rec->mm_i2c && (amdgpu_hw_i2c == 0))
264*fb4d8502Sjsg 		return NULL;
265*fb4d8502Sjsg 
266*fb4d8502Sjsg 	i2c = kzalloc(sizeof(struct amdgpu_i2c_chan), GFP_KERNEL);
267*fb4d8502Sjsg 	if (i2c == NULL)
268*fb4d8502Sjsg 		return NULL;
269*fb4d8502Sjsg 
270*fb4d8502Sjsg 	i2c->rec = *rec;
271*fb4d8502Sjsg #ifdef __linux__
272*fb4d8502Sjsg 	i2c->adapter.owner = THIS_MODULE;
273*fb4d8502Sjsg 	i2c->adapter.class = I2C_CLASS_DDC;
274*fb4d8502Sjsg 	i2c->adapter.dev.parent = &dev->pdev->dev;
275*fb4d8502Sjsg #endif
276*fb4d8502Sjsg 	i2c->dev = dev;
277*fb4d8502Sjsg 	i2c_set_adapdata(&i2c->adapter, i2c);
278*fb4d8502Sjsg 	rw_init(&i2c->mutex, "agiic");
279*fb4d8502Sjsg 	if (rec->hw_capable &&
280*fb4d8502Sjsg 	    amdgpu_hw_i2c) {
281*fb4d8502Sjsg 		/* hw i2c using atom */
282*fb4d8502Sjsg 		snprintf(i2c->adapter.name, sizeof(i2c->adapter.name),
283*fb4d8502Sjsg 			 "AMDGPU i2c hw bus %s", name);
284*fb4d8502Sjsg 		i2c->adapter.algo = &amdgpu_atombios_i2c_algo;
285*fb4d8502Sjsg 		ret = i2c_add_adapter(&i2c->adapter);
286*fb4d8502Sjsg 		if (ret)
287*fb4d8502Sjsg 			goto out_free;
288*fb4d8502Sjsg 	} else {
289*fb4d8502Sjsg 		/* set the amdgpu bit adapter */
290*fb4d8502Sjsg 		snprintf(i2c->adapter.name, sizeof(i2c->adapter.name),
291*fb4d8502Sjsg 			 "AMDGPU i2c bit bus %s", name);
292*fb4d8502Sjsg 		i2c->adapter.algo_data = &i2c->bit;
293*fb4d8502Sjsg #ifdef notyet
294*fb4d8502Sjsg 		i2c->bit.pre_xfer = amdgpu_i2c_pre_xfer;
295*fb4d8502Sjsg 		i2c->bit.post_xfer = amdgpu_i2c_post_xfer;
296*fb4d8502Sjsg 		i2c->bit.setsda = amdgpu_i2c_set_data;
297*fb4d8502Sjsg 		i2c->bit.setscl = amdgpu_i2c_set_clock;
298*fb4d8502Sjsg 		i2c->bit.getsda = amdgpu_i2c_get_data;
299*fb4d8502Sjsg 		i2c->bit.getscl = amdgpu_i2c_get_clock;
300*fb4d8502Sjsg 		i2c->bit.udelay = 10;
301*fb4d8502Sjsg 		i2c->bit.timeout = usecs_to_jiffies(2200);	/* from VESA */
302*fb4d8502Sjsg 		i2c->bit.data = i2c;
303*fb4d8502Sjsg #else
304*fb4d8502Sjsg 		i2c->bit.ic.ic_cookie = i2c;
305*fb4d8502Sjsg 		i2c->bit.ic.ic_acquire_bus = amdgpu_acquire_bus;
306*fb4d8502Sjsg 		i2c->bit.ic.ic_release_bus = amdgpu_release_bus;
307*fb4d8502Sjsg 		i2c->bit.ic.ic_send_start = amdgpu_send_start;
308*fb4d8502Sjsg 		i2c->bit.ic.ic_send_stop = amdgpu_send_stop;
309*fb4d8502Sjsg 		i2c->bit.ic.ic_initiate_xfer = amdgpu_initiate_xfer;
310*fb4d8502Sjsg 		i2c->bit.ic.ic_read_byte = amdgpu_read_byte;
311*fb4d8502Sjsg 		i2c->bit.ic.ic_write_byte = amdgpu_write_byte;
312*fb4d8502Sjsg #endif
313*fb4d8502Sjsg 		ret = i2c_bit_add_bus(&i2c->adapter);
314*fb4d8502Sjsg 		if (ret) {
315*fb4d8502Sjsg 			DRM_ERROR("Failed to register bit i2c %s\n", name);
316*fb4d8502Sjsg 			goto out_free;
317*fb4d8502Sjsg 		}
318*fb4d8502Sjsg 	}
319*fb4d8502Sjsg 
320*fb4d8502Sjsg 	return i2c;
321*fb4d8502Sjsg out_free:
322*fb4d8502Sjsg 	kfree(i2c);
323*fb4d8502Sjsg 	return NULL;
324*fb4d8502Sjsg 
325*fb4d8502Sjsg }
326*fb4d8502Sjsg 
327*fb4d8502Sjsg void amdgpu_i2c_destroy(struct amdgpu_i2c_chan *i2c)
328*fb4d8502Sjsg {
329*fb4d8502Sjsg 	if (!i2c)
330*fb4d8502Sjsg 		return;
331*fb4d8502Sjsg 	WARN_ON(i2c->has_aux);
332*fb4d8502Sjsg 	i2c_del_adapter(&i2c->adapter);
333*fb4d8502Sjsg 	kfree(i2c);
334*fb4d8502Sjsg }
335*fb4d8502Sjsg 
336*fb4d8502Sjsg /* Add the default buses */
337*fb4d8502Sjsg void amdgpu_i2c_init(struct amdgpu_device *adev)
338*fb4d8502Sjsg {
339*fb4d8502Sjsg 	if (amdgpu_hw_i2c)
340*fb4d8502Sjsg 		DRM_INFO("hw_i2c forced on, you may experience display detection problems!\n");
341*fb4d8502Sjsg 
342*fb4d8502Sjsg 	amdgpu_atombios_i2c_init(adev);
343*fb4d8502Sjsg }
344*fb4d8502Sjsg 
345*fb4d8502Sjsg /* remove all the buses */
346*fb4d8502Sjsg void amdgpu_i2c_fini(struct amdgpu_device *adev)
347*fb4d8502Sjsg {
348*fb4d8502Sjsg 	int i;
349*fb4d8502Sjsg 
350*fb4d8502Sjsg 	for (i = 0; i < AMDGPU_MAX_I2C_BUS; i++) {
351*fb4d8502Sjsg 		if (adev->i2c_bus[i]) {
352*fb4d8502Sjsg 			amdgpu_i2c_destroy(adev->i2c_bus[i]);
353*fb4d8502Sjsg 			adev->i2c_bus[i] = NULL;
354*fb4d8502Sjsg 		}
355*fb4d8502Sjsg 	}
356*fb4d8502Sjsg }
357*fb4d8502Sjsg 
358*fb4d8502Sjsg /* Add additional buses */
359*fb4d8502Sjsg void amdgpu_i2c_add(struct amdgpu_device *adev,
360*fb4d8502Sjsg 		    const struct amdgpu_i2c_bus_rec *rec,
361*fb4d8502Sjsg 		    const char *name)
362*fb4d8502Sjsg {
363*fb4d8502Sjsg 	struct drm_device *dev = adev->ddev;
364*fb4d8502Sjsg 	int i;
365*fb4d8502Sjsg 
366*fb4d8502Sjsg 	for (i = 0; i < AMDGPU_MAX_I2C_BUS; i++) {
367*fb4d8502Sjsg 		if (!adev->i2c_bus[i]) {
368*fb4d8502Sjsg 			adev->i2c_bus[i] = amdgpu_i2c_create(dev, rec, name);
369*fb4d8502Sjsg 			return;
370*fb4d8502Sjsg 		}
371*fb4d8502Sjsg 	}
372*fb4d8502Sjsg }
373*fb4d8502Sjsg 
374*fb4d8502Sjsg /* looks up bus based on id */
375*fb4d8502Sjsg struct amdgpu_i2c_chan *
376*fb4d8502Sjsg amdgpu_i2c_lookup(struct amdgpu_device *adev,
377*fb4d8502Sjsg 		  const struct amdgpu_i2c_bus_rec *i2c_bus)
378*fb4d8502Sjsg {
379*fb4d8502Sjsg 	int i;
380*fb4d8502Sjsg 
381*fb4d8502Sjsg 	for (i = 0; i < AMDGPU_MAX_I2C_BUS; i++) {
382*fb4d8502Sjsg 		if (adev->i2c_bus[i] &&
383*fb4d8502Sjsg 		    (adev->i2c_bus[i]->rec.i2c_id == i2c_bus->i2c_id)) {
384*fb4d8502Sjsg 			return adev->i2c_bus[i];
385*fb4d8502Sjsg 		}
386*fb4d8502Sjsg 	}
387*fb4d8502Sjsg 	return NULL;
388*fb4d8502Sjsg }
389*fb4d8502Sjsg 
390*fb4d8502Sjsg static void amdgpu_i2c_get_byte(struct amdgpu_i2c_chan *i2c_bus,
391*fb4d8502Sjsg 				 u8 slave_addr,
392*fb4d8502Sjsg 				 u8 addr,
393*fb4d8502Sjsg 				 u8 *val)
394*fb4d8502Sjsg {
395*fb4d8502Sjsg 	u8 out_buf[2];
396*fb4d8502Sjsg 	u8 in_buf[2];
397*fb4d8502Sjsg 	struct i2c_msg msgs[] = {
398*fb4d8502Sjsg 		{
399*fb4d8502Sjsg 			.addr = slave_addr,
400*fb4d8502Sjsg 			.flags = 0,
401*fb4d8502Sjsg 			.len = 1,
402*fb4d8502Sjsg 			.buf = out_buf,
403*fb4d8502Sjsg 		},
404*fb4d8502Sjsg 		{
405*fb4d8502Sjsg 			.addr = slave_addr,
406*fb4d8502Sjsg 			.flags = I2C_M_RD,
407*fb4d8502Sjsg 			.len = 1,
408*fb4d8502Sjsg 			.buf = in_buf,
409*fb4d8502Sjsg 		}
410*fb4d8502Sjsg 	};
411*fb4d8502Sjsg 
412*fb4d8502Sjsg 	out_buf[0] = addr;
413*fb4d8502Sjsg 	out_buf[1] = 0;
414*fb4d8502Sjsg 
415*fb4d8502Sjsg 	if (i2c_transfer(&i2c_bus->adapter, msgs, 2) == 2) {
416*fb4d8502Sjsg 		*val = in_buf[0];
417*fb4d8502Sjsg 		DRM_DEBUG("val = 0x%02x\n", *val);
418*fb4d8502Sjsg 	} else {
419*fb4d8502Sjsg 		DRM_DEBUG("i2c 0x%02x 0x%02x read failed\n",
420*fb4d8502Sjsg 			  addr, *val);
421*fb4d8502Sjsg 	}
422*fb4d8502Sjsg }
423*fb4d8502Sjsg 
424*fb4d8502Sjsg static void amdgpu_i2c_put_byte(struct amdgpu_i2c_chan *i2c_bus,
425*fb4d8502Sjsg 				 u8 slave_addr,
426*fb4d8502Sjsg 				 u8 addr,
427*fb4d8502Sjsg 				 u8 val)
428*fb4d8502Sjsg {
429*fb4d8502Sjsg 	uint8_t out_buf[2];
430*fb4d8502Sjsg 	struct i2c_msg msg = {
431*fb4d8502Sjsg 		.addr = slave_addr,
432*fb4d8502Sjsg 		.flags = 0,
433*fb4d8502Sjsg 		.len = 2,
434*fb4d8502Sjsg 		.buf = out_buf,
435*fb4d8502Sjsg 	};
436*fb4d8502Sjsg 
437*fb4d8502Sjsg 	out_buf[0] = addr;
438*fb4d8502Sjsg 	out_buf[1] = val;
439*fb4d8502Sjsg 
440*fb4d8502Sjsg 	if (i2c_transfer(&i2c_bus->adapter, &msg, 1) != 1)
441*fb4d8502Sjsg 		DRM_DEBUG("i2c 0x%02x 0x%02x write failed\n",
442*fb4d8502Sjsg 			  addr, val);
443*fb4d8502Sjsg }
444*fb4d8502Sjsg 
445*fb4d8502Sjsg /* ddc router switching */
446*fb4d8502Sjsg void
447*fb4d8502Sjsg amdgpu_i2c_router_select_ddc_port(const struct amdgpu_connector *amdgpu_connector)
448*fb4d8502Sjsg {
449*fb4d8502Sjsg 	u8 val;
450*fb4d8502Sjsg 
451*fb4d8502Sjsg 	if (!amdgpu_connector->router.ddc_valid)
452*fb4d8502Sjsg 		return;
453*fb4d8502Sjsg 
454*fb4d8502Sjsg 	if (!amdgpu_connector->router_bus)
455*fb4d8502Sjsg 		return;
456*fb4d8502Sjsg 
457*fb4d8502Sjsg 	amdgpu_i2c_get_byte(amdgpu_connector->router_bus,
458*fb4d8502Sjsg 			    amdgpu_connector->router.i2c_addr,
459*fb4d8502Sjsg 			    0x3, &val);
460*fb4d8502Sjsg 	val &= ~amdgpu_connector->router.ddc_mux_control_pin;
461*fb4d8502Sjsg 	amdgpu_i2c_put_byte(amdgpu_connector->router_bus,
462*fb4d8502Sjsg 			    amdgpu_connector->router.i2c_addr,
463*fb4d8502Sjsg 			    0x3, val);
464*fb4d8502Sjsg 	amdgpu_i2c_get_byte(amdgpu_connector->router_bus,
465*fb4d8502Sjsg 			    amdgpu_connector->router.i2c_addr,
466*fb4d8502Sjsg 			    0x1, &val);
467*fb4d8502Sjsg 	val &= ~amdgpu_connector->router.ddc_mux_control_pin;
468*fb4d8502Sjsg 	val |= amdgpu_connector->router.ddc_mux_state;
469*fb4d8502Sjsg 	amdgpu_i2c_put_byte(amdgpu_connector->router_bus,
470*fb4d8502Sjsg 			    amdgpu_connector->router.i2c_addr,
471*fb4d8502Sjsg 			    0x1, val);
472*fb4d8502Sjsg }
473*fb4d8502Sjsg 
474*fb4d8502Sjsg /* clock/data router switching */
475*fb4d8502Sjsg void
476*fb4d8502Sjsg amdgpu_i2c_router_select_cd_port(const struct amdgpu_connector *amdgpu_connector)
477*fb4d8502Sjsg {
478*fb4d8502Sjsg 	u8 val;
479*fb4d8502Sjsg 
480*fb4d8502Sjsg 	if (!amdgpu_connector->router.cd_valid)
481*fb4d8502Sjsg 		return;
482*fb4d8502Sjsg 
483*fb4d8502Sjsg 	if (!amdgpu_connector->router_bus)
484*fb4d8502Sjsg 		return;
485*fb4d8502Sjsg 
486*fb4d8502Sjsg 	amdgpu_i2c_get_byte(amdgpu_connector->router_bus,
487*fb4d8502Sjsg 			    amdgpu_connector->router.i2c_addr,
488*fb4d8502Sjsg 			    0x3, &val);
489*fb4d8502Sjsg 	val &= ~amdgpu_connector->router.cd_mux_control_pin;
490*fb4d8502Sjsg 	amdgpu_i2c_put_byte(amdgpu_connector->router_bus,
491*fb4d8502Sjsg 			    amdgpu_connector->router.i2c_addr,
492*fb4d8502Sjsg 			    0x3, val);
493*fb4d8502Sjsg 	amdgpu_i2c_get_byte(amdgpu_connector->router_bus,
494*fb4d8502Sjsg 			    amdgpu_connector->router.i2c_addr,
495*fb4d8502Sjsg 			    0x1, &val);
496*fb4d8502Sjsg 	val &= ~amdgpu_connector->router.cd_mux_control_pin;
497*fb4d8502Sjsg 	val |= amdgpu_connector->router.cd_mux_state;
498*fb4d8502Sjsg 	amdgpu_i2c_put_byte(amdgpu_connector->router_bus,
499*fb4d8502Sjsg 			    amdgpu_connector->router.i2c_addr,
500*fb4d8502Sjsg 			    0x1, val);
501*fb4d8502Sjsg }
502