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