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