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