162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright 2007-8 Advanced Micro Devices, Inc. 362306a36Sopenharmony_ci * Copyright 2008 Red Hat Inc. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 662306a36Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 762306a36Sopenharmony_ci * to deal in the Software without restriction, including without limitation 862306a36Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 962306a36Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 1062306a36Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 1362306a36Sopenharmony_ci * all copies or substantial portions of the Software. 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1662306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1762306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1862306a36Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 1962306a36Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 2062306a36Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 2162306a36Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE. 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * Authors: Dave Airlie 2462306a36Sopenharmony_ci * Alex Deucher 2562306a36Sopenharmony_ci */ 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#include <linux/export.h> 2862306a36Sopenharmony_ci#include <linux/pci.h> 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#include <drm/drm_edid.h> 3162306a36Sopenharmony_ci#include <drm/amdgpu_drm.h> 3262306a36Sopenharmony_ci#include "amdgpu.h" 3362306a36Sopenharmony_ci#include "amdgpu_i2c.h" 3462306a36Sopenharmony_ci#include "amdgpu_atombios.h" 3562306a36Sopenharmony_ci#include "atom.h" 3662306a36Sopenharmony_ci#include "atombios_dp.h" 3762306a36Sopenharmony_ci#include "atombios_i2c.h" 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci/* bit banging i2c */ 4062306a36Sopenharmony_cistatic int amdgpu_i2c_pre_xfer(struct i2c_adapter *i2c_adap) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci struct amdgpu_i2c_chan *i2c = i2c_get_adapdata(i2c_adap); 4362306a36Sopenharmony_ci struct amdgpu_device *adev = drm_to_adev(i2c->dev); 4462306a36Sopenharmony_ci struct amdgpu_i2c_bus_rec *rec = &i2c->rec; 4562306a36Sopenharmony_ci uint32_t temp; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci mutex_lock(&i2c->mutex); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci /* switch the pads to ddc mode */ 5062306a36Sopenharmony_ci if (rec->hw_capable) { 5162306a36Sopenharmony_ci temp = RREG32(rec->mask_clk_reg); 5262306a36Sopenharmony_ci temp &= ~(1 << 16); 5362306a36Sopenharmony_ci WREG32(rec->mask_clk_reg, temp); 5462306a36Sopenharmony_ci } 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci /* clear the output pin values */ 5762306a36Sopenharmony_ci temp = RREG32(rec->a_clk_reg) & ~rec->a_clk_mask; 5862306a36Sopenharmony_ci WREG32(rec->a_clk_reg, temp); 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci temp = RREG32(rec->a_data_reg) & ~rec->a_data_mask; 6162306a36Sopenharmony_ci WREG32(rec->a_data_reg, temp); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci /* set the pins to input */ 6462306a36Sopenharmony_ci temp = RREG32(rec->en_clk_reg) & ~rec->en_clk_mask; 6562306a36Sopenharmony_ci WREG32(rec->en_clk_reg, temp); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci temp = RREG32(rec->en_data_reg) & ~rec->en_data_mask; 6862306a36Sopenharmony_ci WREG32(rec->en_data_reg, temp); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci /* mask the gpio pins for software use */ 7162306a36Sopenharmony_ci temp = RREG32(rec->mask_clk_reg) | rec->mask_clk_mask; 7262306a36Sopenharmony_ci WREG32(rec->mask_clk_reg, temp); 7362306a36Sopenharmony_ci temp = RREG32(rec->mask_clk_reg); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci temp = RREG32(rec->mask_data_reg) | rec->mask_data_mask; 7662306a36Sopenharmony_ci WREG32(rec->mask_data_reg, temp); 7762306a36Sopenharmony_ci temp = RREG32(rec->mask_data_reg); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci return 0; 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistatic void amdgpu_i2c_post_xfer(struct i2c_adapter *i2c_adap) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci struct amdgpu_i2c_chan *i2c = i2c_get_adapdata(i2c_adap); 8562306a36Sopenharmony_ci struct amdgpu_device *adev = drm_to_adev(i2c->dev); 8662306a36Sopenharmony_ci struct amdgpu_i2c_bus_rec *rec = &i2c->rec; 8762306a36Sopenharmony_ci uint32_t temp; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci /* unmask the gpio pins for software use */ 9062306a36Sopenharmony_ci temp = RREG32(rec->mask_clk_reg) & ~rec->mask_clk_mask; 9162306a36Sopenharmony_ci WREG32(rec->mask_clk_reg, temp); 9262306a36Sopenharmony_ci temp = RREG32(rec->mask_clk_reg); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci temp = RREG32(rec->mask_data_reg) & ~rec->mask_data_mask; 9562306a36Sopenharmony_ci WREG32(rec->mask_data_reg, temp); 9662306a36Sopenharmony_ci temp = RREG32(rec->mask_data_reg); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci mutex_unlock(&i2c->mutex); 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic int amdgpu_i2c_get_clock(void *i2c_priv) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci struct amdgpu_i2c_chan *i2c = i2c_priv; 10462306a36Sopenharmony_ci struct amdgpu_device *adev = drm_to_adev(i2c->dev); 10562306a36Sopenharmony_ci struct amdgpu_i2c_bus_rec *rec = &i2c->rec; 10662306a36Sopenharmony_ci uint32_t val; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci /* read the value off the pin */ 10962306a36Sopenharmony_ci val = RREG32(rec->y_clk_reg); 11062306a36Sopenharmony_ci val &= rec->y_clk_mask; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci return (val != 0); 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic int amdgpu_i2c_get_data(void *i2c_priv) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci struct amdgpu_i2c_chan *i2c = i2c_priv; 11962306a36Sopenharmony_ci struct amdgpu_device *adev = drm_to_adev(i2c->dev); 12062306a36Sopenharmony_ci struct amdgpu_i2c_bus_rec *rec = &i2c->rec; 12162306a36Sopenharmony_ci uint32_t val; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci /* read the value off the pin */ 12462306a36Sopenharmony_ci val = RREG32(rec->y_data_reg); 12562306a36Sopenharmony_ci val &= rec->y_data_mask; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci return (val != 0); 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic void amdgpu_i2c_set_clock(void *i2c_priv, int clock) 13162306a36Sopenharmony_ci{ 13262306a36Sopenharmony_ci struct amdgpu_i2c_chan *i2c = i2c_priv; 13362306a36Sopenharmony_ci struct amdgpu_device *adev = drm_to_adev(i2c->dev); 13462306a36Sopenharmony_ci struct amdgpu_i2c_bus_rec *rec = &i2c->rec; 13562306a36Sopenharmony_ci uint32_t val; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci /* set pin direction */ 13862306a36Sopenharmony_ci val = RREG32(rec->en_clk_reg) & ~rec->en_clk_mask; 13962306a36Sopenharmony_ci val |= clock ? 0 : rec->en_clk_mask; 14062306a36Sopenharmony_ci WREG32(rec->en_clk_reg, val); 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cistatic void amdgpu_i2c_set_data(void *i2c_priv, int data) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci struct amdgpu_i2c_chan *i2c = i2c_priv; 14662306a36Sopenharmony_ci struct amdgpu_device *adev = drm_to_adev(i2c->dev); 14762306a36Sopenharmony_ci struct amdgpu_i2c_bus_rec *rec = &i2c->rec; 14862306a36Sopenharmony_ci uint32_t val; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci /* set pin direction */ 15162306a36Sopenharmony_ci val = RREG32(rec->en_data_reg) & ~rec->en_data_mask; 15262306a36Sopenharmony_ci val |= data ? 0 : rec->en_data_mask; 15362306a36Sopenharmony_ci WREG32(rec->en_data_reg, val); 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_cistatic const struct i2c_algorithm amdgpu_atombios_i2c_algo = { 15762306a36Sopenharmony_ci .master_xfer = amdgpu_atombios_i2c_xfer, 15862306a36Sopenharmony_ci .functionality = amdgpu_atombios_i2c_func, 15962306a36Sopenharmony_ci}; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistruct amdgpu_i2c_chan *amdgpu_i2c_create(struct drm_device *dev, 16262306a36Sopenharmony_ci const struct amdgpu_i2c_bus_rec *rec, 16362306a36Sopenharmony_ci const char *name) 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci struct amdgpu_i2c_chan *i2c; 16662306a36Sopenharmony_ci int ret; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci /* don't add the mm_i2c bus unless hw_i2c is enabled */ 16962306a36Sopenharmony_ci if (rec->mm_i2c && (amdgpu_hw_i2c == 0)) 17062306a36Sopenharmony_ci return NULL; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci i2c = kzalloc(sizeof(struct amdgpu_i2c_chan), GFP_KERNEL); 17362306a36Sopenharmony_ci if (i2c == NULL) 17462306a36Sopenharmony_ci return NULL; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci i2c->rec = *rec; 17762306a36Sopenharmony_ci i2c->adapter.owner = THIS_MODULE; 17862306a36Sopenharmony_ci i2c->adapter.class = I2C_CLASS_DDC; 17962306a36Sopenharmony_ci i2c->adapter.dev.parent = dev->dev; 18062306a36Sopenharmony_ci i2c->dev = dev; 18162306a36Sopenharmony_ci i2c_set_adapdata(&i2c->adapter, i2c); 18262306a36Sopenharmony_ci mutex_init(&i2c->mutex); 18362306a36Sopenharmony_ci if (rec->hw_capable && 18462306a36Sopenharmony_ci amdgpu_hw_i2c) { 18562306a36Sopenharmony_ci /* hw i2c using atom */ 18662306a36Sopenharmony_ci snprintf(i2c->adapter.name, sizeof(i2c->adapter.name), 18762306a36Sopenharmony_ci "AMDGPU i2c hw bus %s", name); 18862306a36Sopenharmony_ci i2c->adapter.algo = &amdgpu_atombios_i2c_algo; 18962306a36Sopenharmony_ci ret = i2c_add_adapter(&i2c->adapter); 19062306a36Sopenharmony_ci if (ret) 19162306a36Sopenharmony_ci goto out_free; 19262306a36Sopenharmony_ci } else { 19362306a36Sopenharmony_ci /* set the amdgpu bit adapter */ 19462306a36Sopenharmony_ci snprintf(i2c->adapter.name, sizeof(i2c->adapter.name), 19562306a36Sopenharmony_ci "AMDGPU i2c bit bus %s", name); 19662306a36Sopenharmony_ci i2c->adapter.algo_data = &i2c->bit; 19762306a36Sopenharmony_ci i2c->bit.pre_xfer = amdgpu_i2c_pre_xfer; 19862306a36Sopenharmony_ci i2c->bit.post_xfer = amdgpu_i2c_post_xfer; 19962306a36Sopenharmony_ci i2c->bit.setsda = amdgpu_i2c_set_data; 20062306a36Sopenharmony_ci i2c->bit.setscl = amdgpu_i2c_set_clock; 20162306a36Sopenharmony_ci i2c->bit.getsda = amdgpu_i2c_get_data; 20262306a36Sopenharmony_ci i2c->bit.getscl = amdgpu_i2c_get_clock; 20362306a36Sopenharmony_ci i2c->bit.udelay = 10; 20462306a36Sopenharmony_ci i2c->bit.timeout = usecs_to_jiffies(2200); /* from VESA */ 20562306a36Sopenharmony_ci i2c->bit.data = i2c; 20662306a36Sopenharmony_ci ret = i2c_bit_add_bus(&i2c->adapter); 20762306a36Sopenharmony_ci if (ret) { 20862306a36Sopenharmony_ci DRM_ERROR("Failed to register bit i2c %s\n", name); 20962306a36Sopenharmony_ci goto out_free; 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci return i2c; 21462306a36Sopenharmony_ciout_free: 21562306a36Sopenharmony_ci kfree(i2c); 21662306a36Sopenharmony_ci return NULL; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_civoid amdgpu_i2c_destroy(struct amdgpu_i2c_chan *i2c) 22162306a36Sopenharmony_ci{ 22262306a36Sopenharmony_ci if (!i2c) 22362306a36Sopenharmony_ci return; 22462306a36Sopenharmony_ci WARN_ON(i2c->has_aux); 22562306a36Sopenharmony_ci i2c_del_adapter(&i2c->adapter); 22662306a36Sopenharmony_ci kfree(i2c); 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci/* Add the default buses */ 23062306a36Sopenharmony_civoid amdgpu_i2c_init(struct amdgpu_device *adev) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci if (amdgpu_hw_i2c) 23362306a36Sopenharmony_ci DRM_INFO("hw_i2c forced on, you may experience display detection problems!\n"); 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci amdgpu_atombios_i2c_init(adev); 23662306a36Sopenharmony_ci} 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci/* remove all the buses */ 23962306a36Sopenharmony_civoid amdgpu_i2c_fini(struct amdgpu_device *adev) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci int i; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci for (i = 0; i < AMDGPU_MAX_I2C_BUS; i++) { 24462306a36Sopenharmony_ci if (adev->i2c_bus[i]) { 24562306a36Sopenharmony_ci amdgpu_i2c_destroy(adev->i2c_bus[i]); 24662306a36Sopenharmony_ci adev->i2c_bus[i] = NULL; 24762306a36Sopenharmony_ci } 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci/* Add additional buses */ 25262306a36Sopenharmony_civoid amdgpu_i2c_add(struct amdgpu_device *adev, 25362306a36Sopenharmony_ci const struct amdgpu_i2c_bus_rec *rec, 25462306a36Sopenharmony_ci const char *name) 25562306a36Sopenharmony_ci{ 25662306a36Sopenharmony_ci struct drm_device *dev = adev_to_drm(adev); 25762306a36Sopenharmony_ci int i; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci for (i = 0; i < AMDGPU_MAX_I2C_BUS; i++) { 26062306a36Sopenharmony_ci if (!adev->i2c_bus[i]) { 26162306a36Sopenharmony_ci adev->i2c_bus[i] = amdgpu_i2c_create(dev, rec, name); 26262306a36Sopenharmony_ci return; 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci/* looks up bus based on id */ 26862306a36Sopenharmony_cistruct amdgpu_i2c_chan * 26962306a36Sopenharmony_ciamdgpu_i2c_lookup(struct amdgpu_device *adev, 27062306a36Sopenharmony_ci const struct amdgpu_i2c_bus_rec *i2c_bus) 27162306a36Sopenharmony_ci{ 27262306a36Sopenharmony_ci int i; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci for (i = 0; i < AMDGPU_MAX_I2C_BUS; i++) { 27562306a36Sopenharmony_ci if (adev->i2c_bus[i] && 27662306a36Sopenharmony_ci (adev->i2c_bus[i]->rec.i2c_id == i2c_bus->i2c_id)) { 27762306a36Sopenharmony_ci return adev->i2c_bus[i]; 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci return NULL; 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_cistatic void amdgpu_i2c_get_byte(struct amdgpu_i2c_chan *i2c_bus, 28462306a36Sopenharmony_ci u8 slave_addr, 28562306a36Sopenharmony_ci u8 addr, 28662306a36Sopenharmony_ci u8 *val) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci u8 out_buf[2]; 28962306a36Sopenharmony_ci u8 in_buf[2]; 29062306a36Sopenharmony_ci struct i2c_msg msgs[] = { 29162306a36Sopenharmony_ci { 29262306a36Sopenharmony_ci .addr = slave_addr, 29362306a36Sopenharmony_ci .flags = 0, 29462306a36Sopenharmony_ci .len = 1, 29562306a36Sopenharmony_ci .buf = out_buf, 29662306a36Sopenharmony_ci }, 29762306a36Sopenharmony_ci { 29862306a36Sopenharmony_ci .addr = slave_addr, 29962306a36Sopenharmony_ci .flags = I2C_M_RD, 30062306a36Sopenharmony_ci .len = 1, 30162306a36Sopenharmony_ci .buf = in_buf, 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci }; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci out_buf[0] = addr; 30662306a36Sopenharmony_ci out_buf[1] = 0; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci if (i2c_transfer(&i2c_bus->adapter, msgs, 2) == 2) { 30962306a36Sopenharmony_ci *val = in_buf[0]; 31062306a36Sopenharmony_ci DRM_DEBUG("val = 0x%02x\n", *val); 31162306a36Sopenharmony_ci } else { 31262306a36Sopenharmony_ci DRM_DEBUG("i2c 0x%02x 0x%02x read failed\n", 31362306a36Sopenharmony_ci addr, *val); 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci} 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_cistatic void amdgpu_i2c_put_byte(struct amdgpu_i2c_chan *i2c_bus, 31862306a36Sopenharmony_ci u8 slave_addr, 31962306a36Sopenharmony_ci u8 addr, 32062306a36Sopenharmony_ci u8 val) 32162306a36Sopenharmony_ci{ 32262306a36Sopenharmony_ci uint8_t out_buf[2]; 32362306a36Sopenharmony_ci struct i2c_msg msg = { 32462306a36Sopenharmony_ci .addr = slave_addr, 32562306a36Sopenharmony_ci .flags = 0, 32662306a36Sopenharmony_ci .len = 2, 32762306a36Sopenharmony_ci .buf = out_buf, 32862306a36Sopenharmony_ci }; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci out_buf[0] = addr; 33162306a36Sopenharmony_ci out_buf[1] = val; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci if (i2c_transfer(&i2c_bus->adapter, &msg, 1) != 1) 33462306a36Sopenharmony_ci DRM_DEBUG("i2c 0x%02x 0x%02x write failed\n", 33562306a36Sopenharmony_ci addr, val); 33662306a36Sopenharmony_ci} 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci/* ddc router switching */ 33962306a36Sopenharmony_civoid 34062306a36Sopenharmony_ciamdgpu_i2c_router_select_ddc_port(const struct amdgpu_connector *amdgpu_connector) 34162306a36Sopenharmony_ci{ 34262306a36Sopenharmony_ci u8 val = 0; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci if (!amdgpu_connector->router.ddc_valid) 34562306a36Sopenharmony_ci return; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci if (!amdgpu_connector->router_bus) 34862306a36Sopenharmony_ci return; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci amdgpu_i2c_get_byte(amdgpu_connector->router_bus, 35162306a36Sopenharmony_ci amdgpu_connector->router.i2c_addr, 35262306a36Sopenharmony_ci 0x3, &val); 35362306a36Sopenharmony_ci val &= ~amdgpu_connector->router.ddc_mux_control_pin; 35462306a36Sopenharmony_ci amdgpu_i2c_put_byte(amdgpu_connector->router_bus, 35562306a36Sopenharmony_ci amdgpu_connector->router.i2c_addr, 35662306a36Sopenharmony_ci 0x3, val); 35762306a36Sopenharmony_ci amdgpu_i2c_get_byte(amdgpu_connector->router_bus, 35862306a36Sopenharmony_ci amdgpu_connector->router.i2c_addr, 35962306a36Sopenharmony_ci 0x1, &val); 36062306a36Sopenharmony_ci val &= ~amdgpu_connector->router.ddc_mux_control_pin; 36162306a36Sopenharmony_ci val |= amdgpu_connector->router.ddc_mux_state; 36262306a36Sopenharmony_ci amdgpu_i2c_put_byte(amdgpu_connector->router_bus, 36362306a36Sopenharmony_ci amdgpu_connector->router.i2c_addr, 36462306a36Sopenharmony_ci 0x1, val); 36562306a36Sopenharmony_ci} 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci/* clock/data router switching */ 36862306a36Sopenharmony_civoid 36962306a36Sopenharmony_ciamdgpu_i2c_router_select_cd_port(const struct amdgpu_connector *amdgpu_connector) 37062306a36Sopenharmony_ci{ 37162306a36Sopenharmony_ci u8 val; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci if (!amdgpu_connector->router.cd_valid) 37462306a36Sopenharmony_ci return; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci if (!amdgpu_connector->router_bus) 37762306a36Sopenharmony_ci return; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci amdgpu_i2c_get_byte(amdgpu_connector->router_bus, 38062306a36Sopenharmony_ci amdgpu_connector->router.i2c_addr, 38162306a36Sopenharmony_ci 0x3, &val); 38262306a36Sopenharmony_ci val &= ~amdgpu_connector->router.cd_mux_control_pin; 38362306a36Sopenharmony_ci amdgpu_i2c_put_byte(amdgpu_connector->router_bus, 38462306a36Sopenharmony_ci amdgpu_connector->router.i2c_addr, 38562306a36Sopenharmony_ci 0x3, val); 38662306a36Sopenharmony_ci amdgpu_i2c_get_byte(amdgpu_connector->router_bus, 38762306a36Sopenharmony_ci amdgpu_connector->router.i2c_addr, 38862306a36Sopenharmony_ci 0x1, &val); 38962306a36Sopenharmony_ci val &= ~amdgpu_connector->router.cd_mux_control_pin; 39062306a36Sopenharmony_ci val |= amdgpu_connector->router.cd_mux_state; 39162306a36Sopenharmony_ci amdgpu_i2c_put_byte(amdgpu_connector->router_bus, 39262306a36Sopenharmony_ci amdgpu_connector->router.i2c_addr, 39362306a36Sopenharmony_ci 0x1, val); 39462306a36Sopenharmony_ci} 395