1926deccbSFrançois Tigeot /* 2926deccbSFrançois Tigeot * Copyright 2007-8 Advanced Micro Devices, Inc. 3926deccbSFrançois Tigeot * Copyright 2008 Red Hat Inc. 4926deccbSFrançois Tigeot * 5926deccbSFrançois Tigeot * Permission is hereby granted, free of charge, to any person obtaining a 6926deccbSFrançois Tigeot * copy of this software and associated documentation files (the "Software"), 7926deccbSFrançois Tigeot * to deal in the Software without restriction, including without limitation 8926deccbSFrançois Tigeot * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9926deccbSFrançois Tigeot * and/or sell copies of the Software, and to permit persons to whom the 10926deccbSFrançois Tigeot * Software is furnished to do so, subject to the following conditions: 11926deccbSFrançois Tigeot * 12926deccbSFrançois Tigeot * The above copyright notice and this permission notice shall be included in 13926deccbSFrançois Tigeot * all copies or substantial portions of the Software. 14926deccbSFrançois Tigeot * 15926deccbSFrançois Tigeot * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16926deccbSFrançois Tigeot * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17926deccbSFrançois Tigeot * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18926deccbSFrançois Tigeot * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 19926deccbSFrançois Tigeot * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 20926deccbSFrançois Tigeot * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 21926deccbSFrançois Tigeot * OTHER DEALINGS IN THE SOFTWARE. 22926deccbSFrançois Tigeot * 23926deccbSFrançois Tigeot * Authors: Dave Airlie 24926deccbSFrançois Tigeot * Alex Deucher 25926deccbSFrançois Tigeot * 26926deccbSFrançois Tigeot * $FreeBSD: head/sys/dev/drm2/radeon/radeon_i2c.c 254885 2013-08-25 19:37:15Z dumbbell $ 27926deccbSFrançois Tigeot */ 28926deccbSFrançois Tigeot 29926deccbSFrançois Tigeot #include <drm/drmP.h> 30926deccbSFrançois Tigeot #include <drm/drm_edid.h> 31926deccbSFrançois Tigeot #include <uapi_drm/radeon_drm.h> 32926deccbSFrançois Tigeot #include <bus/iicbus/iic.h> 33926deccbSFrançois Tigeot #include <bus/iicbus/iiconf.h> 34926deccbSFrançois Tigeot #include <bus/iicbus/iicbus.h> 35926deccbSFrançois Tigeot #include <sys/mplock2.h> 36926deccbSFrançois Tigeot #include "radeon.h" 37926deccbSFrançois Tigeot #include "atom.h" 38926deccbSFrançois Tigeot #include "iicbus_if.h" 39926deccbSFrançois Tigeot #include "iicbb_if.h" 40926deccbSFrançois Tigeot 41926deccbSFrançois Tigeot /** 42926deccbSFrançois Tigeot * radeon_ddc_probe 43926deccbSFrançois Tigeot * 44926deccbSFrançois Tigeot */ 45926deccbSFrançois Tigeot bool radeon_ddc_probe(struct radeon_connector *radeon_connector, bool use_aux) 46926deccbSFrançois Tigeot { 47926deccbSFrançois Tigeot u8 out = 0x0; 48926deccbSFrançois Tigeot u8 buf[8]; 49926deccbSFrançois Tigeot int ret; 50926deccbSFrançois Tigeot struct iic_msg msgs[] = { 51926deccbSFrançois Tigeot { 52926deccbSFrançois Tigeot .slave = DDC_ADDR << 1, 53926deccbSFrançois Tigeot .flags = 0, 54926deccbSFrançois Tigeot .len = 1, 55926deccbSFrançois Tigeot .buf = &out, 56926deccbSFrançois Tigeot }, 57926deccbSFrançois Tigeot { 58926deccbSFrançois Tigeot .slave = DDC_ADDR << 1, 59926deccbSFrançois Tigeot .flags = IIC_M_RD, 60926deccbSFrançois Tigeot .len = 8, 61926deccbSFrançois Tigeot .buf = buf, 62926deccbSFrançois Tigeot } 63926deccbSFrançois Tigeot }; 64926deccbSFrançois Tigeot 65926deccbSFrançois Tigeot /* on hw with routers, select right port */ 66926deccbSFrançois Tigeot if (radeon_connector->router.ddc_valid) 67926deccbSFrançois Tigeot radeon_router_select_ddc_port(radeon_connector); 68926deccbSFrançois Tigeot 69926deccbSFrançois Tigeot if (use_aux) { 70926deccbSFrançois Tigeot struct radeon_connector_atom_dig *dig = radeon_connector->con_priv; 71926deccbSFrançois Tigeot ret = iicbus_transfer(dig->dp_i2c_bus->adapter, msgs, 2); 72926deccbSFrançois Tigeot } else { 73926deccbSFrançois Tigeot ret = iicbus_transfer(radeon_connector->ddc_bus->adapter, msgs, 2); 74926deccbSFrançois Tigeot } 75926deccbSFrançois Tigeot 76926deccbSFrançois Tigeot if (ret != 0) 77926deccbSFrançois Tigeot /* Couldn't find an accessible DDC on this connector */ 78926deccbSFrançois Tigeot return false; 79926deccbSFrançois Tigeot /* Probe also for valid EDID header 80926deccbSFrançois Tigeot * EDID header starts with: 81926deccbSFrançois Tigeot * 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00. 82926deccbSFrançois Tigeot * Only the first 6 bytes must be valid as 83926deccbSFrançois Tigeot * drm_edid_block_valid() can fix the last 2 bytes */ 84926deccbSFrançois Tigeot if (drm_edid_header_is_valid(buf) < 6) { 85926deccbSFrançois Tigeot /* Couldn't find an accessible EDID on this 86926deccbSFrançois Tigeot * connector */ 87926deccbSFrançois Tigeot return false; 88926deccbSFrançois Tigeot } 89926deccbSFrançois Tigeot return true; 90926deccbSFrançois Tigeot } 91926deccbSFrançois Tigeot 92926deccbSFrançois Tigeot /* bit banging i2c */ 93926deccbSFrançois Tigeot 94926deccbSFrançois Tigeot static int radeon_iicbb_pre_xfer(device_t dev) 95926deccbSFrançois Tigeot { 96926deccbSFrançois Tigeot struct radeon_i2c_chan *i2c = device_get_softc(dev); 97926deccbSFrançois Tigeot struct radeon_device *rdev = i2c->dev->dev_private; 98926deccbSFrançois Tigeot struct radeon_i2c_bus_rec *rec = &i2c->rec; 99926deccbSFrançois Tigeot uint32_t temp; 100926deccbSFrançois Tigeot 101*7191d616Szrj lockmgr(&i2c->mutex, LK_EXCLUSIVE); 102*7191d616Szrj 103926deccbSFrançois Tigeot /* RV410 appears to have a bug where the hw i2c in reset 104926deccbSFrançois Tigeot * holds the i2c port in a bad state - switch hw i2c away before 105926deccbSFrançois Tigeot * doing DDC - do this for all r200s/r300s/r400s for safety sake 106926deccbSFrançois Tigeot */ 107926deccbSFrançois Tigeot if (rec->hw_capable) { 108926deccbSFrançois Tigeot if ((rdev->family >= CHIP_R200) && !ASIC_IS_AVIVO(rdev)) { 109926deccbSFrançois Tigeot u32 reg; 110926deccbSFrançois Tigeot 111926deccbSFrançois Tigeot if (rdev->family >= CHIP_RV350) 112926deccbSFrançois Tigeot reg = RADEON_GPIO_MONID; 113926deccbSFrançois Tigeot else if ((rdev->family == CHIP_R300) || 114926deccbSFrançois Tigeot (rdev->family == CHIP_R350)) 115926deccbSFrançois Tigeot reg = RADEON_GPIO_DVI_DDC; 116926deccbSFrançois Tigeot else 117926deccbSFrançois Tigeot reg = RADEON_GPIO_CRT2_DDC; 118926deccbSFrançois Tigeot 119926deccbSFrançois Tigeot lockmgr(&rdev->dc_hw_i2c_mutex, LK_EXCLUSIVE); 120926deccbSFrançois Tigeot if (rec->a_clk_reg == reg) { 121926deccbSFrançois Tigeot WREG32(RADEON_DVI_I2C_CNTL_0, (RADEON_I2C_SOFT_RST | 122926deccbSFrançois Tigeot R200_DVI_I2C_PIN_SEL(R200_SEL_DDC1))); 123926deccbSFrançois Tigeot } else { 124926deccbSFrançois Tigeot WREG32(RADEON_DVI_I2C_CNTL_0, (RADEON_I2C_SOFT_RST | 125926deccbSFrançois Tigeot R200_DVI_I2C_PIN_SEL(R200_SEL_DDC3))); 126926deccbSFrançois Tigeot } 127926deccbSFrançois Tigeot lockmgr(&rdev->dc_hw_i2c_mutex, LK_RELEASE); 128926deccbSFrançois Tigeot } 129926deccbSFrançois Tigeot } 130926deccbSFrançois Tigeot 131926deccbSFrançois Tigeot /* switch the pads to ddc mode */ 132926deccbSFrançois Tigeot if (ASIC_IS_DCE3(rdev) && rec->hw_capable) { 133926deccbSFrançois Tigeot temp = RREG32(rec->mask_clk_reg); 134926deccbSFrançois Tigeot temp &= ~(1 << 16); 135926deccbSFrançois Tigeot WREG32(rec->mask_clk_reg, temp); 136926deccbSFrançois Tigeot } 137926deccbSFrançois Tigeot 138926deccbSFrançois Tigeot /* clear the output pin values */ 139926deccbSFrançois Tigeot temp = RREG32(rec->a_clk_reg) & ~rec->a_clk_mask; 140926deccbSFrançois Tigeot WREG32(rec->a_clk_reg, temp); 141926deccbSFrançois Tigeot 142926deccbSFrançois Tigeot temp = RREG32(rec->a_data_reg) & ~rec->a_data_mask; 143926deccbSFrançois Tigeot WREG32(rec->a_data_reg, temp); 144926deccbSFrançois Tigeot 145926deccbSFrançois Tigeot /* set the pins to input */ 146926deccbSFrançois Tigeot temp = RREG32(rec->en_clk_reg) & ~rec->en_clk_mask; 147926deccbSFrançois Tigeot WREG32(rec->en_clk_reg, temp); 148926deccbSFrançois Tigeot 149926deccbSFrançois Tigeot temp = RREG32(rec->en_data_reg) & ~rec->en_data_mask; 150926deccbSFrançois Tigeot WREG32(rec->en_data_reg, temp); 151926deccbSFrançois Tigeot 152926deccbSFrançois Tigeot /* mask the gpio pins for software use */ 153926deccbSFrançois Tigeot temp = RREG32(rec->mask_clk_reg) | rec->mask_clk_mask; 154926deccbSFrançois Tigeot WREG32(rec->mask_clk_reg, temp); 155926deccbSFrançois Tigeot temp = RREG32(rec->mask_clk_reg); 156926deccbSFrançois Tigeot 157926deccbSFrançois Tigeot temp = RREG32(rec->mask_data_reg) | rec->mask_data_mask; 158926deccbSFrançois Tigeot WREG32(rec->mask_data_reg, temp); 159926deccbSFrançois Tigeot temp = RREG32(rec->mask_data_reg); 160926deccbSFrançois Tigeot 161926deccbSFrançois Tigeot return 0; 162926deccbSFrançois Tigeot } 163926deccbSFrançois Tigeot 164926deccbSFrançois Tigeot static void radeon_iicbb_post_xfer(device_t dev) 165926deccbSFrançois Tigeot { 166926deccbSFrançois Tigeot struct radeon_i2c_chan *i2c = device_get_softc(dev); 167926deccbSFrançois Tigeot struct radeon_device *rdev = i2c->dev->dev_private; 168926deccbSFrançois Tigeot struct radeon_i2c_bus_rec *rec = &i2c->rec; 169926deccbSFrançois Tigeot uint32_t temp; 170926deccbSFrançois Tigeot 171926deccbSFrançois Tigeot /* unmask the gpio pins for software use */ 172926deccbSFrançois Tigeot temp = RREG32(rec->mask_clk_reg) & ~rec->mask_clk_mask; 173926deccbSFrançois Tigeot WREG32(rec->mask_clk_reg, temp); 174926deccbSFrançois Tigeot temp = RREG32(rec->mask_clk_reg); 175926deccbSFrançois Tigeot 176926deccbSFrançois Tigeot temp = RREG32(rec->mask_data_reg) & ~rec->mask_data_mask; 177926deccbSFrançois Tigeot WREG32(rec->mask_data_reg, temp); 178926deccbSFrançois Tigeot temp = RREG32(rec->mask_data_reg); 179*7191d616Szrj 180*7191d616Szrj lockmgr(&i2c->mutex, LK_RELEASE); 181926deccbSFrançois Tigeot } 182926deccbSFrançois Tigeot 183926deccbSFrançois Tigeot static int radeon_iicbb_get_clock(device_t dev) 184926deccbSFrançois Tigeot { 185926deccbSFrançois Tigeot struct radeon_i2c_chan *i2c = device_get_softc(dev); 186926deccbSFrançois Tigeot struct radeon_device *rdev = i2c->dev->dev_private; 187926deccbSFrançois Tigeot struct radeon_i2c_bus_rec *rec = &i2c->rec; 188926deccbSFrançois Tigeot uint32_t val; 189926deccbSFrançois Tigeot 190926deccbSFrançois Tigeot /* read the value off the pin */ 191926deccbSFrançois Tigeot val = RREG32(rec->y_clk_reg); 192926deccbSFrançois Tigeot val &= rec->y_clk_mask; 193926deccbSFrançois Tigeot 194926deccbSFrançois Tigeot return (val != 0); 195926deccbSFrançois Tigeot } 196926deccbSFrançois Tigeot 197926deccbSFrançois Tigeot 198926deccbSFrançois Tigeot static int radeon_iicbb_get_data(device_t dev) 199926deccbSFrançois Tigeot { 200926deccbSFrançois Tigeot struct radeon_i2c_chan *i2c = device_get_softc(dev); 201926deccbSFrançois Tigeot struct radeon_device *rdev = i2c->dev->dev_private; 202926deccbSFrançois Tigeot struct radeon_i2c_bus_rec *rec = &i2c->rec; 203926deccbSFrançois Tigeot uint32_t val; 204926deccbSFrançois Tigeot 205926deccbSFrançois Tigeot /* read the value off the pin */ 206926deccbSFrançois Tigeot val = RREG32(rec->y_data_reg); 207926deccbSFrançois Tigeot val &= rec->y_data_mask; 208926deccbSFrançois Tigeot 209926deccbSFrançois Tigeot return (val != 0); 210926deccbSFrançois Tigeot } 211926deccbSFrançois Tigeot 212926deccbSFrançois Tigeot static void radeon_iicbb_set_clock(device_t dev, int clock) 213926deccbSFrançois Tigeot { 214926deccbSFrançois Tigeot struct radeon_i2c_chan *i2c = device_get_softc(dev); 215926deccbSFrançois Tigeot struct radeon_device *rdev = i2c->dev->dev_private; 216926deccbSFrançois Tigeot struct radeon_i2c_bus_rec *rec = &i2c->rec; 217926deccbSFrançois Tigeot uint32_t val; 218926deccbSFrançois Tigeot 219926deccbSFrançois Tigeot /* set pin direction */ 220926deccbSFrançois Tigeot val = RREG32(rec->en_clk_reg) & ~rec->en_clk_mask; 221926deccbSFrançois Tigeot val |= clock ? 0 : rec->en_clk_mask; 222926deccbSFrançois Tigeot WREG32(rec->en_clk_reg, val); 223926deccbSFrançois Tigeot } 224926deccbSFrançois Tigeot 225926deccbSFrançois Tigeot static void radeon_iicbb_set_data(device_t dev, int data) 226926deccbSFrançois Tigeot { 227926deccbSFrançois Tigeot struct radeon_i2c_chan *i2c = device_get_softc(dev); 228926deccbSFrançois Tigeot struct radeon_device *rdev = i2c->dev->dev_private; 229926deccbSFrançois Tigeot struct radeon_i2c_bus_rec *rec = &i2c->rec; 230926deccbSFrançois Tigeot uint32_t val; 231926deccbSFrançois Tigeot 232926deccbSFrançois Tigeot /* set pin direction */ 233926deccbSFrançois Tigeot val = RREG32(rec->en_data_reg) & ~rec->en_data_mask; 234926deccbSFrançois Tigeot val |= data ? 0 : rec->en_data_mask; 235926deccbSFrançois Tigeot WREG32(rec->en_data_reg, val); 236926deccbSFrançois Tigeot } 237926deccbSFrançois Tigeot 238926deccbSFrançois Tigeot static int 239926deccbSFrançois Tigeot radeon_iicbb_probe(device_t dev) 240926deccbSFrançois Tigeot { 241926deccbSFrançois Tigeot 242926deccbSFrançois Tigeot return (BUS_PROBE_DEFAULT); 243926deccbSFrançois Tigeot } 244926deccbSFrançois Tigeot 245926deccbSFrançois Tigeot static int 246926deccbSFrançois Tigeot radeon_iicbb_attach(device_t dev) 247926deccbSFrançois Tigeot { 248926deccbSFrançois Tigeot struct radeon_i2c_chan *i2c; 249926deccbSFrançois Tigeot device_t iic_dev; 250926deccbSFrançois Tigeot 251926deccbSFrançois Tigeot i2c = device_get_softc(dev); 252926deccbSFrançois Tigeot device_set_desc(dev, i2c->name); 253926deccbSFrançois Tigeot 254926deccbSFrançois Tigeot /* add generic bit-banging code */ 255926deccbSFrançois Tigeot iic_dev = device_add_child(dev, "iicbb", -1); 256926deccbSFrançois Tigeot if (iic_dev == NULL) 257926deccbSFrançois Tigeot return (ENXIO); 258926deccbSFrançois Tigeot device_quiet(iic_dev); 259926deccbSFrançois Tigeot 260926deccbSFrançois Tigeot /* attach and probe added child */ 261926deccbSFrançois Tigeot bus_generic_attach(dev); 262926deccbSFrançois Tigeot 263926deccbSFrançois Tigeot return (0); 264926deccbSFrançois Tigeot } 265926deccbSFrançois Tigeot 266926deccbSFrançois Tigeot static int 267926deccbSFrançois Tigeot radeon_iicbb_detach(device_t dev) 268926deccbSFrançois Tigeot { 269926deccbSFrançois Tigeot 270926deccbSFrançois Tigeot /* detach bit-banding code. */ 271926deccbSFrançois Tigeot bus_generic_detach(dev); 272926deccbSFrançois Tigeot 273926deccbSFrançois Tigeot /* delete bit-banding code. */ 274926deccbSFrançois Tigeot device_delete_children(dev); 275926deccbSFrançois Tigeot return (0); 276926deccbSFrançois Tigeot } 277926deccbSFrançois Tigeot 278926deccbSFrançois Tigeot static int 279926deccbSFrançois Tigeot radeon_iicbb_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr) 280926deccbSFrançois Tigeot { 281926deccbSFrançois Tigeot 282926deccbSFrançois Tigeot /* Not sure what to do here. */ 283926deccbSFrançois Tigeot return 0; 284926deccbSFrançois Tigeot } 285926deccbSFrançois Tigeot 286926deccbSFrançois Tigeot static device_method_t radeon_iicbb_methods[] = { 287926deccbSFrançois Tigeot DEVMETHOD(device_probe, radeon_iicbb_probe), 288926deccbSFrançois Tigeot DEVMETHOD(device_attach, radeon_iicbb_attach), 289926deccbSFrançois Tigeot DEVMETHOD(device_detach, radeon_iicbb_detach), 290926deccbSFrançois Tigeot 291926deccbSFrançois Tigeot DEVMETHOD(bus_add_child, bus_generic_add_child), 292926deccbSFrançois Tigeot DEVMETHOD(bus_print_child, bus_generic_print_child), 293926deccbSFrançois Tigeot 294926deccbSFrançois Tigeot DEVMETHOD(iicbb_reset, radeon_iicbb_reset), 295926deccbSFrançois Tigeot DEVMETHOD(iicbb_pre_xfer, radeon_iicbb_pre_xfer), 296926deccbSFrançois Tigeot DEVMETHOD(iicbb_post_xfer, radeon_iicbb_post_xfer), 297926deccbSFrançois Tigeot DEVMETHOD(iicbb_setsda, radeon_iicbb_set_data), 298926deccbSFrançois Tigeot DEVMETHOD(iicbb_setscl, radeon_iicbb_set_clock), 299926deccbSFrançois Tigeot DEVMETHOD(iicbb_getsda, radeon_iicbb_get_data), 300926deccbSFrançois Tigeot DEVMETHOD(iicbb_getscl, radeon_iicbb_get_clock), 301926deccbSFrançois Tigeot DEVMETHOD_END 302926deccbSFrançois Tigeot }; 303926deccbSFrançois Tigeot 304926deccbSFrançois Tigeot static driver_t radeon_iicbb_driver = { 305926deccbSFrançois Tigeot "radeon_iicbb", 306926deccbSFrançois Tigeot radeon_iicbb_methods, 307926deccbSFrançois Tigeot 0 /* softc will be allocated by parent */ 308926deccbSFrançois Tigeot }; 309926deccbSFrançois Tigeot static devclass_t radeon_iicbb_devclass; 310926deccbSFrançois Tigeot DRIVER_MODULE_ORDERED(radeon_iicbb, drm, radeon_iicbb_driver, 311aa6ac96eSSascha Wildner radeon_iicbb_devclass, NULL, NULL, SI_ORDER_FIRST); 3123a25be87SSascha Wildner DRIVER_MODULE(iicbb, radeon_iicbb, iicbb_driver, iicbb_devclass, NULL, NULL); 313926deccbSFrançois Tigeot 314926deccbSFrançois Tigeot /* hw i2c */ 315926deccbSFrançois Tigeot 316926deccbSFrançois Tigeot static u32 radeon_get_i2c_prescale(struct radeon_device *rdev) 317926deccbSFrançois Tigeot { 318926deccbSFrançois Tigeot u32 sclk = rdev->pm.current_sclk; 319926deccbSFrançois Tigeot u32 prescale = 0; 320926deccbSFrançois Tigeot u32 nm; 321926deccbSFrançois Tigeot u8 n, m, loop; 322926deccbSFrançois Tigeot int i2c_clock; 323926deccbSFrançois Tigeot 324926deccbSFrançois Tigeot switch (rdev->family) { 325926deccbSFrançois Tigeot case CHIP_R100: 326926deccbSFrançois Tigeot case CHIP_RV100: 327926deccbSFrançois Tigeot case CHIP_RS100: 328926deccbSFrançois Tigeot case CHIP_RV200: 329926deccbSFrançois Tigeot case CHIP_RS200: 330926deccbSFrançois Tigeot case CHIP_R200: 331926deccbSFrançois Tigeot case CHIP_RV250: 332926deccbSFrançois Tigeot case CHIP_RS300: 333926deccbSFrançois Tigeot case CHIP_RV280: 334926deccbSFrançois Tigeot case CHIP_R300: 335926deccbSFrançois Tigeot case CHIP_R350: 336926deccbSFrançois Tigeot case CHIP_RV350: 337926deccbSFrançois Tigeot i2c_clock = 60; 338926deccbSFrançois Tigeot nm = (sclk * 10) / (i2c_clock * 4); 339926deccbSFrançois Tigeot for (loop = 1; loop < 255; loop++) { 340926deccbSFrançois Tigeot if ((nm / loop) < loop) 341926deccbSFrançois Tigeot break; 342926deccbSFrançois Tigeot } 343926deccbSFrançois Tigeot n = loop - 1; 344926deccbSFrançois Tigeot m = loop - 2; 345926deccbSFrançois Tigeot prescale = m | (n << 8); 346926deccbSFrançois Tigeot break; 347926deccbSFrançois Tigeot case CHIP_RV380: 348926deccbSFrançois Tigeot case CHIP_RS400: 349926deccbSFrançois Tigeot case CHIP_RS480: 350926deccbSFrançois Tigeot case CHIP_R420: 351926deccbSFrançois Tigeot case CHIP_R423: 352926deccbSFrançois Tigeot case CHIP_RV410: 353926deccbSFrançois Tigeot prescale = (((sclk * 10)/(4 * 128 * 100) + 1) << 8) + 128; 354926deccbSFrançois Tigeot break; 355926deccbSFrançois Tigeot case CHIP_RS600: 356926deccbSFrançois Tigeot case CHIP_RS690: 357926deccbSFrançois Tigeot case CHIP_RS740: 358926deccbSFrançois Tigeot /* todo */ 359926deccbSFrançois Tigeot break; 360926deccbSFrançois Tigeot case CHIP_RV515: 361926deccbSFrançois Tigeot case CHIP_R520: 362926deccbSFrançois Tigeot case CHIP_RV530: 363926deccbSFrançois Tigeot case CHIP_RV560: 364926deccbSFrançois Tigeot case CHIP_RV570: 365926deccbSFrançois Tigeot case CHIP_R580: 366926deccbSFrançois Tigeot i2c_clock = 50; 367926deccbSFrançois Tigeot if (rdev->family == CHIP_R520) 368926deccbSFrançois Tigeot prescale = (127 << 8) + ((sclk * 10) / (4 * 127 * i2c_clock)); 369926deccbSFrançois Tigeot else 370926deccbSFrançois Tigeot prescale = (((sclk * 10)/(4 * 128 * 100) + 1) << 8) + 128; 371926deccbSFrançois Tigeot break; 372926deccbSFrançois Tigeot case CHIP_R600: 373926deccbSFrançois Tigeot case CHIP_RV610: 374926deccbSFrançois Tigeot case CHIP_RV630: 375926deccbSFrançois Tigeot case CHIP_RV670: 376926deccbSFrançois Tigeot /* todo */ 377926deccbSFrançois Tigeot break; 378926deccbSFrançois Tigeot case CHIP_RV620: 379926deccbSFrançois Tigeot case CHIP_RV635: 380926deccbSFrançois Tigeot case CHIP_RS780: 381926deccbSFrançois Tigeot case CHIP_RS880: 382926deccbSFrançois Tigeot case CHIP_RV770: 383926deccbSFrançois Tigeot case CHIP_RV730: 384926deccbSFrançois Tigeot case CHIP_RV710: 385926deccbSFrançois Tigeot case CHIP_RV740: 386926deccbSFrançois Tigeot /* todo */ 387926deccbSFrançois Tigeot break; 388926deccbSFrançois Tigeot case CHIP_CEDAR: 389926deccbSFrançois Tigeot case CHIP_REDWOOD: 390926deccbSFrançois Tigeot case CHIP_JUNIPER: 391926deccbSFrançois Tigeot case CHIP_CYPRESS: 392926deccbSFrançois Tigeot case CHIP_HEMLOCK: 393926deccbSFrançois Tigeot /* todo */ 394926deccbSFrançois Tigeot break; 395926deccbSFrançois Tigeot default: 396926deccbSFrançois Tigeot DRM_ERROR("i2c: unhandled radeon chip\n"); 397926deccbSFrançois Tigeot break; 398926deccbSFrançois Tigeot } 399926deccbSFrançois Tigeot return prescale; 400926deccbSFrançois Tigeot } 401926deccbSFrançois Tigeot 402926deccbSFrançois Tigeot 403926deccbSFrançois Tigeot /* hw i2c engine for r1xx-4xx hardware 404926deccbSFrançois Tigeot * hw can buffer up to 15 bytes 405926deccbSFrançois Tigeot */ 406926deccbSFrançois Tigeot static int r100_hw_i2c_xfer(struct radeon_i2c_chan *i2c, 407926deccbSFrançois Tigeot struct iic_msg *msgs, int num) 408926deccbSFrançois Tigeot { 409926deccbSFrançois Tigeot struct radeon_device *rdev = i2c->dev->dev_private; 410926deccbSFrançois Tigeot struct radeon_i2c_bus_rec *rec = &i2c->rec; 411926deccbSFrançois Tigeot struct iic_msg *p; 412926deccbSFrançois Tigeot int i, j, k, ret = 0; 413926deccbSFrançois Tigeot u32 prescale; 414926deccbSFrançois Tigeot u32 i2c_cntl_0, i2c_cntl_1, i2c_data; 415926deccbSFrançois Tigeot u32 tmp, reg; 416926deccbSFrançois Tigeot 417926deccbSFrançois Tigeot lockmgr(&rdev->dc_hw_i2c_mutex, LK_EXCLUSIVE); 418926deccbSFrançois Tigeot /* take the pm lock since we need a constant sclk */ 419926deccbSFrançois Tigeot lockmgr(&rdev->pm.mutex, LK_EXCLUSIVE); 420926deccbSFrançois Tigeot 421926deccbSFrançois Tigeot prescale = radeon_get_i2c_prescale(rdev); 422926deccbSFrançois Tigeot 423926deccbSFrançois Tigeot reg = ((prescale << RADEON_I2C_PRESCALE_SHIFT) | 424926deccbSFrançois Tigeot RADEON_I2C_DRIVE_EN | 425926deccbSFrançois Tigeot RADEON_I2C_START | 426926deccbSFrançois Tigeot RADEON_I2C_STOP | 427926deccbSFrançois Tigeot RADEON_I2C_GO); 428926deccbSFrançois Tigeot 429926deccbSFrançois Tigeot if (rdev->is_atom_bios) { 430926deccbSFrançois Tigeot tmp = RREG32(RADEON_BIOS_6_SCRATCH); 431926deccbSFrançois Tigeot WREG32(RADEON_BIOS_6_SCRATCH, tmp | ATOM_S6_HW_I2C_BUSY_STATE); 432926deccbSFrançois Tigeot } 433926deccbSFrançois Tigeot 434926deccbSFrançois Tigeot if (rec->mm_i2c) { 435926deccbSFrançois Tigeot i2c_cntl_0 = RADEON_I2C_CNTL_0; 436926deccbSFrançois Tigeot i2c_cntl_1 = RADEON_I2C_CNTL_1; 437926deccbSFrançois Tigeot i2c_data = RADEON_I2C_DATA; 438926deccbSFrançois Tigeot } else { 439926deccbSFrançois Tigeot i2c_cntl_0 = RADEON_DVI_I2C_CNTL_0; 440926deccbSFrançois Tigeot i2c_cntl_1 = RADEON_DVI_I2C_CNTL_1; 441926deccbSFrançois Tigeot i2c_data = RADEON_DVI_I2C_DATA; 442926deccbSFrançois Tigeot 443926deccbSFrançois Tigeot switch (rdev->family) { 444926deccbSFrançois Tigeot case CHIP_R100: 445926deccbSFrançois Tigeot case CHIP_RV100: 446926deccbSFrançois Tigeot case CHIP_RS100: 447926deccbSFrançois Tigeot case CHIP_RV200: 448926deccbSFrançois Tigeot case CHIP_RS200: 449926deccbSFrançois Tigeot case CHIP_RS300: 450926deccbSFrançois Tigeot switch (rec->mask_clk_reg) { 451926deccbSFrançois Tigeot case RADEON_GPIO_DVI_DDC: 452926deccbSFrançois Tigeot /* no gpio select bit */ 453926deccbSFrançois Tigeot break; 454926deccbSFrançois Tigeot default: 455926deccbSFrançois Tigeot DRM_ERROR("gpio not supported with hw i2c\n"); 456926deccbSFrançois Tigeot ret = EINVAL; 457926deccbSFrançois Tigeot goto done; 458926deccbSFrançois Tigeot } 459926deccbSFrançois Tigeot break; 460926deccbSFrançois Tigeot case CHIP_R200: 461926deccbSFrançois Tigeot /* only bit 4 on r200 */ 462926deccbSFrançois Tigeot switch (rec->mask_clk_reg) { 463926deccbSFrançois Tigeot case RADEON_GPIO_DVI_DDC: 464926deccbSFrançois Tigeot reg |= R200_DVI_I2C_PIN_SEL(R200_SEL_DDC1); 465926deccbSFrançois Tigeot break; 466926deccbSFrançois Tigeot case RADEON_GPIO_MONID: 467926deccbSFrançois Tigeot reg |= R200_DVI_I2C_PIN_SEL(R200_SEL_DDC3); 468926deccbSFrançois Tigeot break; 469926deccbSFrançois Tigeot default: 470926deccbSFrançois Tigeot DRM_ERROR("gpio not supported with hw i2c\n"); 471926deccbSFrançois Tigeot ret = EINVAL; 472926deccbSFrançois Tigeot goto done; 473926deccbSFrançois Tigeot } 474926deccbSFrançois Tigeot break; 475926deccbSFrançois Tigeot case CHIP_RV250: 476926deccbSFrançois Tigeot case CHIP_RV280: 477926deccbSFrançois Tigeot /* bits 3 and 4 */ 478926deccbSFrançois Tigeot switch (rec->mask_clk_reg) { 479926deccbSFrançois Tigeot case RADEON_GPIO_DVI_DDC: 480926deccbSFrançois Tigeot reg |= R200_DVI_I2C_PIN_SEL(R200_SEL_DDC1); 481926deccbSFrançois Tigeot break; 482926deccbSFrançois Tigeot case RADEON_GPIO_VGA_DDC: 483926deccbSFrançois Tigeot reg |= R200_DVI_I2C_PIN_SEL(R200_SEL_DDC2); 484926deccbSFrançois Tigeot break; 485926deccbSFrançois Tigeot case RADEON_GPIO_CRT2_DDC: 486926deccbSFrançois Tigeot reg |= R200_DVI_I2C_PIN_SEL(R200_SEL_DDC3); 487926deccbSFrançois Tigeot break; 488926deccbSFrançois Tigeot default: 489926deccbSFrançois Tigeot DRM_ERROR("gpio not supported with hw i2c\n"); 490926deccbSFrançois Tigeot ret = EINVAL; 491926deccbSFrançois Tigeot goto done; 492926deccbSFrançois Tigeot } 493926deccbSFrançois Tigeot break; 494926deccbSFrançois Tigeot case CHIP_R300: 495926deccbSFrançois Tigeot case CHIP_R350: 496926deccbSFrançois Tigeot /* only bit 4 on r300/r350 */ 497926deccbSFrançois Tigeot switch (rec->mask_clk_reg) { 498926deccbSFrançois Tigeot case RADEON_GPIO_VGA_DDC: 499926deccbSFrançois Tigeot reg |= R200_DVI_I2C_PIN_SEL(R200_SEL_DDC1); 500926deccbSFrançois Tigeot break; 501926deccbSFrançois Tigeot case RADEON_GPIO_DVI_DDC: 502926deccbSFrançois Tigeot reg |= R200_DVI_I2C_PIN_SEL(R200_SEL_DDC3); 503926deccbSFrançois Tigeot break; 504926deccbSFrançois Tigeot default: 505926deccbSFrançois Tigeot DRM_ERROR("gpio not supported with hw i2c\n"); 506926deccbSFrançois Tigeot ret = EINVAL; 507926deccbSFrançois Tigeot goto done; 508926deccbSFrançois Tigeot } 509926deccbSFrançois Tigeot break; 510926deccbSFrançois Tigeot case CHIP_RV350: 511926deccbSFrançois Tigeot case CHIP_RV380: 512926deccbSFrançois Tigeot case CHIP_R420: 513926deccbSFrançois Tigeot case CHIP_R423: 514926deccbSFrançois Tigeot case CHIP_RV410: 515926deccbSFrançois Tigeot case CHIP_RS400: 516926deccbSFrançois Tigeot case CHIP_RS480: 517926deccbSFrançois Tigeot /* bits 3 and 4 */ 518926deccbSFrançois Tigeot switch (rec->mask_clk_reg) { 519926deccbSFrançois Tigeot case RADEON_GPIO_VGA_DDC: 520926deccbSFrançois Tigeot reg |= R200_DVI_I2C_PIN_SEL(R200_SEL_DDC1); 521926deccbSFrançois Tigeot break; 522926deccbSFrançois Tigeot case RADEON_GPIO_DVI_DDC: 523926deccbSFrançois Tigeot reg |= R200_DVI_I2C_PIN_SEL(R200_SEL_DDC2); 524926deccbSFrançois Tigeot break; 525926deccbSFrançois Tigeot case RADEON_GPIO_MONID: 526926deccbSFrançois Tigeot reg |= R200_DVI_I2C_PIN_SEL(R200_SEL_DDC3); 527926deccbSFrançois Tigeot break; 528926deccbSFrançois Tigeot default: 529926deccbSFrançois Tigeot DRM_ERROR("gpio not supported with hw i2c\n"); 530926deccbSFrançois Tigeot ret = EINVAL; 531926deccbSFrançois Tigeot goto done; 532926deccbSFrançois Tigeot } 533926deccbSFrançois Tigeot break; 534926deccbSFrançois Tigeot default: 535926deccbSFrançois Tigeot DRM_ERROR("unsupported asic\n"); 536926deccbSFrançois Tigeot ret = EINVAL; 537926deccbSFrançois Tigeot goto done; 538926deccbSFrançois Tigeot break; 539926deccbSFrançois Tigeot } 540926deccbSFrançois Tigeot } 541926deccbSFrançois Tigeot 542926deccbSFrançois Tigeot /* check for bus probe */ 543926deccbSFrançois Tigeot p = &msgs[0]; 544926deccbSFrançois Tigeot if ((num == 1) && (p->len == 0)) { 545926deccbSFrançois Tigeot WREG32(i2c_cntl_0, (RADEON_I2C_DONE | 546926deccbSFrançois Tigeot RADEON_I2C_NACK | 547926deccbSFrançois Tigeot RADEON_I2C_HALT | 548926deccbSFrançois Tigeot RADEON_I2C_SOFT_RST)); 549926deccbSFrançois Tigeot WREG32(i2c_data, (p->slave << 1) & 0xff); 550926deccbSFrançois Tigeot WREG32(i2c_data, 0); 551926deccbSFrançois Tigeot WREG32(i2c_cntl_1, ((1 << RADEON_I2C_DATA_COUNT_SHIFT) | 552926deccbSFrançois Tigeot (1 << RADEON_I2C_ADDR_COUNT_SHIFT) | 553926deccbSFrançois Tigeot RADEON_I2C_EN | 554926deccbSFrançois Tigeot (48 << RADEON_I2C_TIME_LIMIT_SHIFT))); 555926deccbSFrançois Tigeot WREG32(i2c_cntl_0, reg); 556926deccbSFrançois Tigeot for (k = 0; k < 32; k++) { 557c4ef309bSzrj udelay(10); 558926deccbSFrançois Tigeot tmp = RREG32(i2c_cntl_0); 559926deccbSFrançois Tigeot if (tmp & RADEON_I2C_GO) 560926deccbSFrançois Tigeot continue; 561926deccbSFrançois Tigeot tmp = RREG32(i2c_cntl_0); 562926deccbSFrançois Tigeot if (tmp & RADEON_I2C_DONE) 563926deccbSFrançois Tigeot break; 564926deccbSFrançois Tigeot else { 565926deccbSFrançois Tigeot DRM_DEBUG("i2c write error 0x%08x\n", tmp); 566926deccbSFrançois Tigeot WREG32(i2c_cntl_0, tmp | RADEON_I2C_ABORT); 567926deccbSFrançois Tigeot ret = EIO; 568926deccbSFrançois Tigeot goto done; 569926deccbSFrançois Tigeot } 570926deccbSFrançois Tigeot } 571926deccbSFrançois Tigeot goto done; 572926deccbSFrançois Tigeot } 573926deccbSFrançois Tigeot 574926deccbSFrançois Tigeot for (i = 0; i < num; i++) { 575926deccbSFrançois Tigeot p = &msgs[i]; 576926deccbSFrançois Tigeot for (j = 0; j < p->len; j++) { 577926deccbSFrançois Tigeot if (p->flags & IIC_M_RD) { 578926deccbSFrançois Tigeot WREG32(i2c_cntl_0, (RADEON_I2C_DONE | 579926deccbSFrançois Tigeot RADEON_I2C_NACK | 580926deccbSFrançois Tigeot RADEON_I2C_HALT | 581926deccbSFrançois Tigeot RADEON_I2C_SOFT_RST)); 582926deccbSFrançois Tigeot WREG32(i2c_data, ((p->slave << 1) & 0xff) | 0x1); 583926deccbSFrançois Tigeot WREG32(i2c_cntl_1, ((1 << RADEON_I2C_DATA_COUNT_SHIFT) | 584926deccbSFrançois Tigeot (1 << RADEON_I2C_ADDR_COUNT_SHIFT) | 585926deccbSFrançois Tigeot RADEON_I2C_EN | 586926deccbSFrançois Tigeot (48 << RADEON_I2C_TIME_LIMIT_SHIFT))); 587926deccbSFrançois Tigeot WREG32(i2c_cntl_0, reg | RADEON_I2C_RECEIVE); 588926deccbSFrançois Tigeot for (k = 0; k < 32; k++) { 589c4ef309bSzrj udelay(10); 590926deccbSFrançois Tigeot tmp = RREG32(i2c_cntl_0); 591926deccbSFrançois Tigeot if (tmp & RADEON_I2C_GO) 592926deccbSFrançois Tigeot continue; 593926deccbSFrançois Tigeot tmp = RREG32(i2c_cntl_0); 594926deccbSFrançois Tigeot if (tmp & RADEON_I2C_DONE) 595926deccbSFrançois Tigeot break; 596926deccbSFrançois Tigeot else { 597926deccbSFrançois Tigeot DRM_DEBUG("i2c read error 0x%08x\n", tmp); 598926deccbSFrançois Tigeot WREG32(i2c_cntl_0, tmp | RADEON_I2C_ABORT); 599926deccbSFrançois Tigeot ret = EIO; 600926deccbSFrançois Tigeot goto done; 601926deccbSFrançois Tigeot } 602926deccbSFrançois Tigeot } 603926deccbSFrançois Tigeot p->buf[j] = RREG32(i2c_data) & 0xff; 604926deccbSFrançois Tigeot } else { 605926deccbSFrançois Tigeot WREG32(i2c_cntl_0, (RADEON_I2C_DONE | 606926deccbSFrançois Tigeot RADEON_I2C_NACK | 607926deccbSFrançois Tigeot RADEON_I2C_HALT | 608926deccbSFrançois Tigeot RADEON_I2C_SOFT_RST)); 609926deccbSFrançois Tigeot WREG32(i2c_data, (p->slave << 1) & 0xff); 610926deccbSFrançois Tigeot WREG32(i2c_data, p->buf[j]); 611926deccbSFrançois Tigeot WREG32(i2c_cntl_1, ((1 << RADEON_I2C_DATA_COUNT_SHIFT) | 612926deccbSFrançois Tigeot (1 << RADEON_I2C_ADDR_COUNT_SHIFT) | 613926deccbSFrançois Tigeot RADEON_I2C_EN | 614926deccbSFrançois Tigeot (48 << RADEON_I2C_TIME_LIMIT_SHIFT))); 615926deccbSFrançois Tigeot WREG32(i2c_cntl_0, reg); 616926deccbSFrançois Tigeot for (k = 0; k < 32; k++) { 617c4ef309bSzrj udelay(10); 618926deccbSFrançois Tigeot tmp = RREG32(i2c_cntl_0); 619926deccbSFrançois Tigeot if (tmp & RADEON_I2C_GO) 620926deccbSFrançois Tigeot continue; 621926deccbSFrançois Tigeot tmp = RREG32(i2c_cntl_0); 622926deccbSFrançois Tigeot if (tmp & RADEON_I2C_DONE) 623926deccbSFrançois Tigeot break; 624926deccbSFrançois Tigeot else { 625926deccbSFrançois Tigeot DRM_DEBUG("i2c write error 0x%08x\n", tmp); 626926deccbSFrançois Tigeot WREG32(i2c_cntl_0, tmp | RADEON_I2C_ABORT); 627926deccbSFrançois Tigeot ret = EIO; 628926deccbSFrançois Tigeot goto done; 629926deccbSFrançois Tigeot } 630926deccbSFrançois Tigeot } 631926deccbSFrançois Tigeot } 632926deccbSFrançois Tigeot } 633926deccbSFrançois Tigeot } 634926deccbSFrançois Tigeot 635926deccbSFrançois Tigeot done: 636926deccbSFrançois Tigeot WREG32(i2c_cntl_0, 0); 637926deccbSFrançois Tigeot WREG32(i2c_cntl_1, 0); 638926deccbSFrançois Tigeot WREG32(i2c_cntl_0, (RADEON_I2C_DONE | 639926deccbSFrançois Tigeot RADEON_I2C_NACK | 640926deccbSFrançois Tigeot RADEON_I2C_HALT | 641926deccbSFrançois Tigeot RADEON_I2C_SOFT_RST)); 642926deccbSFrançois Tigeot 643926deccbSFrançois Tigeot if (rdev->is_atom_bios) { 644926deccbSFrançois Tigeot tmp = RREG32(RADEON_BIOS_6_SCRATCH); 645926deccbSFrançois Tigeot tmp &= ~ATOM_S6_HW_I2C_BUSY_STATE; 646926deccbSFrançois Tigeot WREG32(RADEON_BIOS_6_SCRATCH, tmp); 647926deccbSFrançois Tigeot } 648926deccbSFrançois Tigeot 649926deccbSFrançois Tigeot lockmgr(&rdev->pm.mutex, LK_RELEASE); 650926deccbSFrançois Tigeot lockmgr(&rdev->dc_hw_i2c_mutex, LK_RELEASE); 651926deccbSFrançois Tigeot 652926deccbSFrançois Tigeot return ret; 653926deccbSFrançois Tigeot } 654926deccbSFrançois Tigeot 655926deccbSFrançois Tigeot /* hw i2c engine for r5xx hardware 656926deccbSFrançois Tigeot * hw can buffer up to 15 bytes 657926deccbSFrançois Tigeot */ 658926deccbSFrançois Tigeot static int r500_hw_i2c_xfer(struct radeon_i2c_chan *i2c, 659926deccbSFrançois Tigeot struct iic_msg *msgs, int num) 660926deccbSFrançois Tigeot { 661926deccbSFrançois Tigeot struct radeon_device *rdev = i2c->dev->dev_private; 662926deccbSFrançois Tigeot struct radeon_i2c_bus_rec *rec = &i2c->rec; 663926deccbSFrançois Tigeot struct iic_msg *p; 664926deccbSFrançois Tigeot int i, j, remaining, current_count, buffer_offset, ret = 0; 665926deccbSFrançois Tigeot u32 prescale; 666926deccbSFrançois Tigeot u32 tmp, reg; 667926deccbSFrançois Tigeot u32 saved1, saved2; 668926deccbSFrançois Tigeot 669926deccbSFrançois Tigeot lockmgr(&rdev->dc_hw_i2c_mutex, LK_EXCLUSIVE); 670926deccbSFrançois Tigeot /* take the pm lock since we need a constant sclk */ 671926deccbSFrançois Tigeot lockmgr(&rdev->pm.mutex, LK_EXCLUSIVE); 672926deccbSFrançois Tigeot 673926deccbSFrançois Tigeot prescale = radeon_get_i2c_prescale(rdev); 674926deccbSFrançois Tigeot 675926deccbSFrançois Tigeot /* clear gpio mask bits */ 676926deccbSFrançois Tigeot tmp = RREG32(rec->mask_clk_reg); 677926deccbSFrançois Tigeot tmp &= ~rec->mask_clk_mask; 678926deccbSFrançois Tigeot WREG32(rec->mask_clk_reg, tmp); 679926deccbSFrançois Tigeot tmp = RREG32(rec->mask_clk_reg); 680926deccbSFrançois Tigeot 681926deccbSFrançois Tigeot tmp = RREG32(rec->mask_data_reg); 682926deccbSFrançois Tigeot tmp &= ~rec->mask_data_mask; 683926deccbSFrançois Tigeot WREG32(rec->mask_data_reg, tmp); 684926deccbSFrançois Tigeot tmp = RREG32(rec->mask_data_reg); 685926deccbSFrançois Tigeot 686926deccbSFrançois Tigeot /* clear pin values */ 687926deccbSFrançois Tigeot tmp = RREG32(rec->a_clk_reg); 688926deccbSFrançois Tigeot tmp &= ~rec->a_clk_mask; 689926deccbSFrançois Tigeot WREG32(rec->a_clk_reg, tmp); 690926deccbSFrançois Tigeot tmp = RREG32(rec->a_clk_reg); 691926deccbSFrançois Tigeot 692926deccbSFrançois Tigeot tmp = RREG32(rec->a_data_reg); 693926deccbSFrançois Tigeot tmp &= ~rec->a_data_mask; 694926deccbSFrançois Tigeot WREG32(rec->a_data_reg, tmp); 695926deccbSFrançois Tigeot tmp = RREG32(rec->a_data_reg); 696926deccbSFrançois Tigeot 697926deccbSFrançois Tigeot /* set the pins to input */ 698926deccbSFrançois Tigeot tmp = RREG32(rec->en_clk_reg); 699926deccbSFrançois Tigeot tmp &= ~rec->en_clk_mask; 700926deccbSFrançois Tigeot WREG32(rec->en_clk_reg, tmp); 701926deccbSFrançois Tigeot tmp = RREG32(rec->en_clk_reg); 702926deccbSFrançois Tigeot 703926deccbSFrançois Tigeot tmp = RREG32(rec->en_data_reg); 704926deccbSFrançois Tigeot tmp &= ~rec->en_data_mask; 705926deccbSFrançois Tigeot WREG32(rec->en_data_reg, tmp); 706926deccbSFrançois Tigeot tmp = RREG32(rec->en_data_reg); 707926deccbSFrançois Tigeot 708926deccbSFrançois Tigeot /* */ 709926deccbSFrançois Tigeot tmp = RREG32(RADEON_BIOS_6_SCRATCH); 710926deccbSFrançois Tigeot WREG32(RADEON_BIOS_6_SCRATCH, tmp | ATOM_S6_HW_I2C_BUSY_STATE); 711926deccbSFrançois Tigeot saved1 = RREG32(AVIVO_DC_I2C_CONTROL1); 712926deccbSFrançois Tigeot saved2 = RREG32(0x494); 713926deccbSFrançois Tigeot WREG32(0x494, saved2 | 0x1); 714926deccbSFrançois Tigeot 715926deccbSFrançois Tigeot WREG32(AVIVO_DC_I2C_ARBITRATION, AVIVO_DC_I2C_SW_WANTS_TO_USE_I2C); 716926deccbSFrançois Tigeot for (i = 0; i < 50; i++) { 717c4ef309bSzrj udelay(1); 718926deccbSFrançois Tigeot if (RREG32(AVIVO_DC_I2C_ARBITRATION) & AVIVO_DC_I2C_SW_CAN_USE_I2C) 719926deccbSFrançois Tigeot break; 720926deccbSFrançois Tigeot } 721926deccbSFrançois Tigeot if (i == 50) { 722926deccbSFrançois Tigeot DRM_ERROR("failed to get i2c bus\n"); 723926deccbSFrançois Tigeot ret = EBUSY; 724926deccbSFrançois Tigeot goto done; 725926deccbSFrançois Tigeot } 726926deccbSFrançois Tigeot 727926deccbSFrançois Tigeot reg = AVIVO_DC_I2C_START | AVIVO_DC_I2C_STOP | AVIVO_DC_I2C_EN; 728926deccbSFrançois Tigeot switch (rec->mask_clk_reg) { 729926deccbSFrançois Tigeot case AVIVO_DC_GPIO_DDC1_MASK: 730926deccbSFrançois Tigeot reg |= AVIVO_DC_I2C_PIN_SELECT(AVIVO_SEL_DDC1); 731926deccbSFrançois Tigeot break; 732926deccbSFrançois Tigeot case AVIVO_DC_GPIO_DDC2_MASK: 733926deccbSFrançois Tigeot reg |= AVIVO_DC_I2C_PIN_SELECT(AVIVO_SEL_DDC2); 734926deccbSFrançois Tigeot break; 735926deccbSFrançois Tigeot case AVIVO_DC_GPIO_DDC3_MASK: 736926deccbSFrançois Tigeot reg |= AVIVO_DC_I2C_PIN_SELECT(AVIVO_SEL_DDC3); 737926deccbSFrançois Tigeot break; 738926deccbSFrançois Tigeot default: 739926deccbSFrançois Tigeot DRM_ERROR("gpio not supported with hw i2c\n"); 740926deccbSFrançois Tigeot ret = EINVAL; 741926deccbSFrançois Tigeot goto done; 742926deccbSFrançois Tigeot } 743926deccbSFrançois Tigeot 744926deccbSFrançois Tigeot /* check for bus probe */ 745926deccbSFrançois Tigeot p = &msgs[0]; 746926deccbSFrançois Tigeot if ((num == 1) && (p->len == 0)) { 747926deccbSFrançois Tigeot WREG32(AVIVO_DC_I2C_STATUS1, (AVIVO_DC_I2C_DONE | 748926deccbSFrançois Tigeot AVIVO_DC_I2C_NACK | 749926deccbSFrançois Tigeot AVIVO_DC_I2C_HALT)); 750926deccbSFrançois Tigeot WREG32(AVIVO_DC_I2C_RESET, AVIVO_DC_I2C_SOFT_RESET); 751c4ef309bSzrj udelay(1); 752926deccbSFrançois Tigeot WREG32(AVIVO_DC_I2C_RESET, 0); 753926deccbSFrançois Tigeot 754926deccbSFrançois Tigeot WREG32(AVIVO_DC_I2C_DATA, (p->slave << 1) & 0xff); 755926deccbSFrançois Tigeot WREG32(AVIVO_DC_I2C_DATA, 0); 756926deccbSFrançois Tigeot 757926deccbSFrançois Tigeot WREG32(AVIVO_DC_I2C_CONTROL3, AVIVO_DC_I2C_TIME_LIMIT(48)); 758926deccbSFrançois Tigeot WREG32(AVIVO_DC_I2C_CONTROL2, (AVIVO_DC_I2C_ADDR_COUNT(1) | 759926deccbSFrançois Tigeot AVIVO_DC_I2C_DATA_COUNT(1) | 760926deccbSFrançois Tigeot (prescale << 16))); 761926deccbSFrançois Tigeot WREG32(AVIVO_DC_I2C_CONTROL1, reg); 762926deccbSFrançois Tigeot WREG32(AVIVO_DC_I2C_STATUS1, AVIVO_DC_I2C_GO); 763926deccbSFrançois Tigeot for (j = 0; j < 200; j++) { 764c4ef309bSzrj udelay(50); 765926deccbSFrançois Tigeot tmp = RREG32(AVIVO_DC_I2C_STATUS1); 766926deccbSFrançois Tigeot if (tmp & AVIVO_DC_I2C_GO) 767926deccbSFrançois Tigeot continue; 768926deccbSFrançois Tigeot tmp = RREG32(AVIVO_DC_I2C_STATUS1); 769926deccbSFrançois Tigeot if (tmp & AVIVO_DC_I2C_DONE) 770926deccbSFrançois Tigeot break; 771926deccbSFrançois Tigeot else { 772926deccbSFrançois Tigeot DRM_DEBUG("i2c write error 0x%08x\n", tmp); 773926deccbSFrançois Tigeot WREG32(AVIVO_DC_I2C_RESET, AVIVO_DC_I2C_ABORT); 774926deccbSFrançois Tigeot ret = EIO; 775926deccbSFrançois Tigeot goto done; 776926deccbSFrançois Tigeot } 777926deccbSFrançois Tigeot } 778926deccbSFrançois Tigeot goto done; 779926deccbSFrançois Tigeot } 780926deccbSFrançois Tigeot 781926deccbSFrançois Tigeot for (i = 0; i < num; i++) { 782926deccbSFrançois Tigeot p = &msgs[i]; 783926deccbSFrançois Tigeot remaining = p->len; 784926deccbSFrançois Tigeot buffer_offset = 0; 785926deccbSFrançois Tigeot if (p->flags & IIC_M_RD) { 786926deccbSFrançois Tigeot while (remaining) { 787926deccbSFrançois Tigeot if (remaining > 15) 788926deccbSFrançois Tigeot current_count = 15; 789926deccbSFrançois Tigeot else 790926deccbSFrançois Tigeot current_count = remaining; 791926deccbSFrançois Tigeot WREG32(AVIVO_DC_I2C_STATUS1, (AVIVO_DC_I2C_DONE | 792926deccbSFrançois Tigeot AVIVO_DC_I2C_NACK | 793926deccbSFrançois Tigeot AVIVO_DC_I2C_HALT)); 794926deccbSFrançois Tigeot WREG32(AVIVO_DC_I2C_RESET, AVIVO_DC_I2C_SOFT_RESET); 795c4ef309bSzrj udelay(1); 796926deccbSFrançois Tigeot WREG32(AVIVO_DC_I2C_RESET, 0); 797926deccbSFrançois Tigeot 798926deccbSFrançois Tigeot WREG32(AVIVO_DC_I2C_DATA, ((p->slave << 1) & 0xff) | 0x1); 799926deccbSFrançois Tigeot WREG32(AVIVO_DC_I2C_CONTROL3, AVIVO_DC_I2C_TIME_LIMIT(48)); 800926deccbSFrançois Tigeot WREG32(AVIVO_DC_I2C_CONTROL2, (AVIVO_DC_I2C_ADDR_COUNT(1) | 801926deccbSFrançois Tigeot AVIVO_DC_I2C_DATA_COUNT(current_count) | 802926deccbSFrançois Tigeot (prescale << 16))); 803926deccbSFrançois Tigeot WREG32(AVIVO_DC_I2C_CONTROL1, reg | AVIVO_DC_I2C_RECEIVE); 804926deccbSFrançois Tigeot WREG32(AVIVO_DC_I2C_STATUS1, AVIVO_DC_I2C_GO); 805926deccbSFrançois Tigeot for (j = 0; j < 200; j++) { 806c4ef309bSzrj udelay(50); 807926deccbSFrançois Tigeot tmp = RREG32(AVIVO_DC_I2C_STATUS1); 808926deccbSFrançois Tigeot if (tmp & AVIVO_DC_I2C_GO) 809926deccbSFrançois Tigeot continue; 810926deccbSFrançois Tigeot tmp = RREG32(AVIVO_DC_I2C_STATUS1); 811926deccbSFrançois Tigeot if (tmp & AVIVO_DC_I2C_DONE) 812926deccbSFrançois Tigeot break; 813926deccbSFrançois Tigeot else { 814926deccbSFrançois Tigeot DRM_DEBUG("i2c read error 0x%08x\n", tmp); 815926deccbSFrançois Tigeot WREG32(AVIVO_DC_I2C_RESET, AVIVO_DC_I2C_ABORT); 816926deccbSFrançois Tigeot ret = EIO; 817926deccbSFrançois Tigeot goto done; 818926deccbSFrançois Tigeot } 819926deccbSFrançois Tigeot } 820926deccbSFrançois Tigeot for (j = 0; j < current_count; j++) 821926deccbSFrançois Tigeot p->buf[buffer_offset + j] = RREG32(AVIVO_DC_I2C_DATA) & 0xff; 822926deccbSFrançois Tigeot remaining -= current_count; 823926deccbSFrançois Tigeot buffer_offset += current_count; 824926deccbSFrançois Tigeot } 825926deccbSFrançois Tigeot } else { 826926deccbSFrançois Tigeot while (remaining) { 827926deccbSFrançois Tigeot if (remaining > 15) 828926deccbSFrançois Tigeot current_count = 15; 829926deccbSFrançois Tigeot else 830926deccbSFrançois Tigeot current_count = remaining; 831926deccbSFrançois Tigeot WREG32(AVIVO_DC_I2C_STATUS1, (AVIVO_DC_I2C_DONE | 832926deccbSFrançois Tigeot AVIVO_DC_I2C_NACK | 833926deccbSFrançois Tigeot AVIVO_DC_I2C_HALT)); 834926deccbSFrançois Tigeot WREG32(AVIVO_DC_I2C_RESET, AVIVO_DC_I2C_SOFT_RESET); 835c4ef309bSzrj udelay(1); 836926deccbSFrançois Tigeot WREG32(AVIVO_DC_I2C_RESET, 0); 837926deccbSFrançois Tigeot 838926deccbSFrançois Tigeot WREG32(AVIVO_DC_I2C_DATA, (p->slave << 1) & 0xff); 839926deccbSFrançois Tigeot for (j = 0; j < current_count; j++) 840926deccbSFrançois Tigeot WREG32(AVIVO_DC_I2C_DATA, p->buf[buffer_offset + j]); 841926deccbSFrançois Tigeot 842926deccbSFrançois Tigeot WREG32(AVIVO_DC_I2C_CONTROL3, AVIVO_DC_I2C_TIME_LIMIT(48)); 843926deccbSFrançois Tigeot WREG32(AVIVO_DC_I2C_CONTROL2, (AVIVO_DC_I2C_ADDR_COUNT(1) | 844926deccbSFrançois Tigeot AVIVO_DC_I2C_DATA_COUNT(current_count) | 845926deccbSFrançois Tigeot (prescale << 16))); 846926deccbSFrançois Tigeot WREG32(AVIVO_DC_I2C_CONTROL1, reg); 847926deccbSFrançois Tigeot WREG32(AVIVO_DC_I2C_STATUS1, AVIVO_DC_I2C_GO); 848926deccbSFrançois Tigeot for (j = 0; j < 200; j++) { 849c4ef309bSzrj udelay(50); 850926deccbSFrançois Tigeot tmp = RREG32(AVIVO_DC_I2C_STATUS1); 851926deccbSFrançois Tigeot if (tmp & AVIVO_DC_I2C_GO) 852926deccbSFrançois Tigeot continue; 853926deccbSFrançois Tigeot tmp = RREG32(AVIVO_DC_I2C_STATUS1); 854926deccbSFrançois Tigeot if (tmp & AVIVO_DC_I2C_DONE) 855926deccbSFrançois Tigeot break; 856926deccbSFrançois Tigeot else { 857926deccbSFrançois Tigeot DRM_DEBUG("i2c write error 0x%08x\n", tmp); 858926deccbSFrançois Tigeot WREG32(AVIVO_DC_I2C_RESET, AVIVO_DC_I2C_ABORT); 859926deccbSFrançois Tigeot ret = EIO; 860926deccbSFrançois Tigeot goto done; 861926deccbSFrançois Tigeot } 862926deccbSFrançois Tigeot } 863926deccbSFrançois Tigeot remaining -= current_count; 864926deccbSFrançois Tigeot buffer_offset += current_count; 865926deccbSFrançois Tigeot } 866926deccbSFrançois Tigeot } 867926deccbSFrançois Tigeot } 868926deccbSFrançois Tigeot 869926deccbSFrançois Tigeot done: 870926deccbSFrançois Tigeot WREG32(AVIVO_DC_I2C_STATUS1, (AVIVO_DC_I2C_DONE | 871926deccbSFrançois Tigeot AVIVO_DC_I2C_NACK | 872926deccbSFrançois Tigeot AVIVO_DC_I2C_HALT)); 873926deccbSFrançois Tigeot WREG32(AVIVO_DC_I2C_RESET, AVIVO_DC_I2C_SOFT_RESET); 874c4ef309bSzrj udelay(1); 875926deccbSFrançois Tigeot WREG32(AVIVO_DC_I2C_RESET, 0); 876926deccbSFrançois Tigeot 877926deccbSFrançois Tigeot WREG32(AVIVO_DC_I2C_ARBITRATION, AVIVO_DC_I2C_SW_DONE_USING_I2C); 878926deccbSFrançois Tigeot WREG32(AVIVO_DC_I2C_CONTROL1, saved1); 879926deccbSFrançois Tigeot WREG32(0x494, saved2); 880926deccbSFrançois Tigeot tmp = RREG32(RADEON_BIOS_6_SCRATCH); 881926deccbSFrançois Tigeot tmp &= ~ATOM_S6_HW_I2C_BUSY_STATE; 882926deccbSFrançois Tigeot WREG32(RADEON_BIOS_6_SCRATCH, tmp); 883926deccbSFrançois Tigeot 884926deccbSFrançois Tigeot lockmgr(&rdev->pm.mutex, LK_RELEASE); 885926deccbSFrançois Tigeot lockmgr(&rdev->dc_hw_i2c_mutex, LK_RELEASE); 886926deccbSFrançois Tigeot 887926deccbSFrançois Tigeot return ret; 888926deccbSFrançois Tigeot } 889926deccbSFrançois Tigeot 890926deccbSFrançois Tigeot static int radeon_hw_i2c_xfer(device_t dev, 891926deccbSFrançois Tigeot struct iic_msg *msgs, uint32_t num) 892926deccbSFrançois Tigeot { 893926deccbSFrançois Tigeot struct radeon_i2c_chan *i2c = device_get_softc(dev); 894926deccbSFrançois Tigeot struct radeon_device *rdev = i2c->dev->dev_private; 895926deccbSFrançois Tigeot struct radeon_i2c_bus_rec *rec = &i2c->rec; 896926deccbSFrançois Tigeot int ret = 0; 897926deccbSFrançois Tigeot 898*7191d616Szrj lockmgr(&i2c->mutex, LK_EXCLUSIVE); 899*7191d616Szrj 900926deccbSFrançois Tigeot switch (rdev->family) { 901926deccbSFrançois Tigeot case CHIP_R100: 902926deccbSFrançois Tigeot case CHIP_RV100: 903926deccbSFrançois Tigeot case CHIP_RS100: 904926deccbSFrançois Tigeot case CHIP_RV200: 905926deccbSFrançois Tigeot case CHIP_RS200: 906926deccbSFrançois Tigeot case CHIP_R200: 907926deccbSFrançois Tigeot case CHIP_RV250: 908926deccbSFrançois Tigeot case CHIP_RS300: 909926deccbSFrançois Tigeot case CHIP_RV280: 910926deccbSFrançois Tigeot case CHIP_R300: 911926deccbSFrançois Tigeot case CHIP_R350: 912926deccbSFrançois Tigeot case CHIP_RV350: 913926deccbSFrançois Tigeot case CHIP_RV380: 914926deccbSFrançois Tigeot case CHIP_R420: 915926deccbSFrançois Tigeot case CHIP_R423: 916926deccbSFrançois Tigeot case CHIP_RV410: 917926deccbSFrançois Tigeot case CHIP_RS400: 918926deccbSFrançois Tigeot case CHIP_RS480: 919926deccbSFrançois Tigeot ret = r100_hw_i2c_xfer(i2c, msgs, num); 920926deccbSFrançois Tigeot break; 921926deccbSFrançois Tigeot case CHIP_RS600: 922926deccbSFrançois Tigeot case CHIP_RS690: 923926deccbSFrançois Tigeot case CHIP_RS740: 924926deccbSFrançois Tigeot /* XXX fill in hw i2c implementation */ 925926deccbSFrançois Tigeot break; 926926deccbSFrançois Tigeot case CHIP_RV515: 927926deccbSFrançois Tigeot case CHIP_R520: 928926deccbSFrançois Tigeot case CHIP_RV530: 929926deccbSFrançois Tigeot case CHIP_RV560: 930926deccbSFrançois Tigeot case CHIP_RV570: 931926deccbSFrançois Tigeot case CHIP_R580: 932926deccbSFrançois Tigeot if (rec->mm_i2c) 933926deccbSFrançois Tigeot ret = r100_hw_i2c_xfer(i2c, msgs, num); 934926deccbSFrançois Tigeot else 935926deccbSFrançois Tigeot ret = r500_hw_i2c_xfer(i2c, msgs, num); 936926deccbSFrançois Tigeot break; 937926deccbSFrançois Tigeot case CHIP_R600: 938926deccbSFrançois Tigeot case CHIP_RV610: 939926deccbSFrançois Tigeot case CHIP_RV630: 940926deccbSFrançois Tigeot case CHIP_RV670: 941926deccbSFrançois Tigeot /* XXX fill in hw i2c implementation */ 942926deccbSFrançois Tigeot break; 943926deccbSFrançois Tigeot case CHIP_RV620: 944926deccbSFrançois Tigeot case CHIP_RV635: 945926deccbSFrançois Tigeot case CHIP_RS780: 946926deccbSFrançois Tigeot case CHIP_RS880: 947926deccbSFrançois Tigeot case CHIP_RV770: 948926deccbSFrançois Tigeot case CHIP_RV730: 949926deccbSFrançois Tigeot case CHIP_RV710: 950926deccbSFrançois Tigeot case CHIP_RV740: 951926deccbSFrançois Tigeot /* XXX fill in hw i2c implementation */ 952926deccbSFrançois Tigeot break; 953926deccbSFrançois Tigeot case CHIP_CEDAR: 954926deccbSFrançois Tigeot case CHIP_REDWOOD: 955926deccbSFrançois Tigeot case CHIP_JUNIPER: 956926deccbSFrançois Tigeot case CHIP_CYPRESS: 957926deccbSFrançois Tigeot case CHIP_HEMLOCK: 958926deccbSFrançois Tigeot /* XXX fill in hw i2c implementation */ 959926deccbSFrançois Tigeot break; 960926deccbSFrançois Tigeot default: 961926deccbSFrançois Tigeot DRM_ERROR("i2c: unhandled radeon chip\n"); 962926deccbSFrançois Tigeot ret = EIO; 963926deccbSFrançois Tigeot break; 964926deccbSFrançois Tigeot } 965926deccbSFrançois Tigeot 966*7191d616Szrj lockmgr(&i2c->mutex, LK_RELEASE); 967*7191d616Szrj 968926deccbSFrançois Tigeot return ret; 969926deccbSFrançois Tigeot } 970926deccbSFrançois Tigeot 971926deccbSFrançois Tigeot static int 972926deccbSFrançois Tigeot radeon_hw_i2c_probe(device_t dev) 973926deccbSFrançois Tigeot { 974926deccbSFrançois Tigeot 975926deccbSFrançois Tigeot return (BUS_PROBE_SPECIFIC); 976926deccbSFrançois Tigeot } 977926deccbSFrançois Tigeot 978926deccbSFrançois Tigeot static int 979926deccbSFrançois Tigeot radeon_hw_i2c_attach(device_t dev) 980926deccbSFrançois Tigeot { 981926deccbSFrançois Tigeot struct radeon_i2c_chan *i2c; 982926deccbSFrançois Tigeot device_t iic_dev; 983926deccbSFrançois Tigeot 984926deccbSFrançois Tigeot i2c = device_get_softc(dev); 985926deccbSFrançois Tigeot device_set_desc(dev, i2c->name); 986926deccbSFrançois Tigeot 987926deccbSFrançois Tigeot /* add generic bit-banging code */ 988926deccbSFrançois Tigeot iic_dev = device_add_child(dev, "iicbus", -1); 989926deccbSFrançois Tigeot if (iic_dev == NULL) 990926deccbSFrançois Tigeot return (ENXIO); 991926deccbSFrançois Tigeot device_quiet(iic_dev); 992926deccbSFrançois Tigeot 993926deccbSFrançois Tigeot /* attach and probe added child */ 994926deccbSFrançois Tigeot bus_generic_attach(dev); 995926deccbSFrançois Tigeot 996926deccbSFrançois Tigeot return (0); 997926deccbSFrançois Tigeot } 998926deccbSFrançois Tigeot 999926deccbSFrançois Tigeot static int 1000926deccbSFrançois Tigeot radeon_hw_i2c_detach(device_t dev) 1001926deccbSFrançois Tigeot { 1002926deccbSFrançois Tigeot 1003926deccbSFrançois Tigeot /* detach bit-banding code. */ 1004926deccbSFrançois Tigeot bus_generic_detach(dev); 1005926deccbSFrançois Tigeot 1006926deccbSFrançois Tigeot /* delete bit-banding code. */ 1007926deccbSFrançois Tigeot device_delete_children(dev); 1008926deccbSFrançois Tigeot return (0); 1009926deccbSFrançois Tigeot } 1010926deccbSFrançois Tigeot 1011926deccbSFrançois Tigeot static int 1012926deccbSFrançois Tigeot radeon_hw_i2c_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr) 1013926deccbSFrançois Tigeot { 1014926deccbSFrançois Tigeot 1015926deccbSFrançois Tigeot /* Not sure what to do here. */ 1016926deccbSFrançois Tigeot return 0; 1017926deccbSFrançois Tigeot } 1018926deccbSFrançois Tigeot 1019926deccbSFrançois Tigeot 1020926deccbSFrançois Tigeot static device_method_t radeon_hw_i2c_methods[] = { 1021926deccbSFrançois Tigeot DEVMETHOD(device_probe, radeon_hw_i2c_probe), 1022926deccbSFrançois Tigeot DEVMETHOD(device_attach, radeon_hw_i2c_attach), 1023926deccbSFrançois Tigeot DEVMETHOD(device_detach, radeon_hw_i2c_detach), 1024926deccbSFrançois Tigeot DEVMETHOD(iicbus_reset, radeon_hw_i2c_reset), 1025926deccbSFrançois Tigeot DEVMETHOD(iicbus_transfer, radeon_hw_i2c_xfer), 1026926deccbSFrançois Tigeot DEVMETHOD_END 1027926deccbSFrançois Tigeot }; 1028926deccbSFrançois Tigeot 1029926deccbSFrançois Tigeot static driver_t radeon_hw_i2c_driver = { 1030926deccbSFrançois Tigeot "radeon_hw_i2c", 1031926deccbSFrançois Tigeot radeon_hw_i2c_methods, 1032926deccbSFrançois Tigeot 0 /* softc will be allocated by parent */ 1033926deccbSFrançois Tigeot }; 1034926deccbSFrançois Tigeot 1035926deccbSFrançois Tigeot static devclass_t radeon_hw_i2c_devclass; 1036926deccbSFrançois Tigeot DRIVER_MODULE_ORDERED(radeon_hw_i2c, drm, radeon_hw_i2c_driver, 1037aa6ac96eSSascha Wildner radeon_hw_i2c_devclass, NULL, NULL, SI_ORDER_FIRST); 10383a25be87SSascha Wildner DRIVER_MODULE(iicbus, radeon_hw_i2c, iicbus_driver, iicbus_devclass, NULL, NULL); 1039926deccbSFrançois Tigeot 1040926deccbSFrançois Tigeot struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, 1041926deccbSFrançois Tigeot struct radeon_i2c_bus_rec *rec, 1042926deccbSFrançois Tigeot const char *name) 1043926deccbSFrançois Tigeot { 1044926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 1045926deccbSFrançois Tigeot struct radeon_i2c_chan *i2c; 1046926deccbSFrançois Tigeot device_t iicbus_dev; 1047926deccbSFrançois Tigeot int ret; 1048926deccbSFrançois Tigeot 1049926deccbSFrançois Tigeot /* don't add the mm_i2c bus unless hw_i2c is enabled */ 1050926deccbSFrançois Tigeot if (rec->mm_i2c && (radeon_hw_i2c == 0)) 1051926deccbSFrançois Tigeot return NULL; 1052926deccbSFrançois Tigeot 1053c4ef309bSzrj i2c = kzalloc(sizeof(struct radeon_i2c_chan), GFP_KERNEL); 1054926deccbSFrançois Tigeot if (i2c == NULL) 1055926deccbSFrançois Tigeot return NULL; 1056926deccbSFrançois Tigeot 1057926deccbSFrançois Tigeot /* 1058926deccbSFrançois Tigeot * Grab Giant before messing with newbus devices, just in case 1059926deccbSFrançois Tigeot * we do not hold it already. 1060926deccbSFrançois Tigeot */ 1061926deccbSFrançois Tigeot get_mplock(); 1062926deccbSFrançois Tigeot 1063926deccbSFrançois Tigeot i2c->rec = *rec; 1064926deccbSFrançois Tigeot i2c->dev = dev; 1065*7191d616Szrj lockinit(&i2c->mutex, "ri2cmtx", 0, LK_CANRECURSE); 1066926deccbSFrançois Tigeot if (rec->mm_i2c || 1067926deccbSFrançois Tigeot (rec->hw_capable && 1068926deccbSFrançois Tigeot radeon_hw_i2c && 1069926deccbSFrançois Tigeot ((rdev->family <= CHIP_RS480) || 1070926deccbSFrançois Tigeot ((rdev->family >= CHIP_RV515) && (rdev->family <= CHIP_R580))))) { 1071926deccbSFrançois Tigeot /* set the radeon hw i2c adapter */ 1072926deccbSFrançois Tigeot ksnprintf(i2c->name, sizeof(i2c->name), 1073926deccbSFrançois Tigeot "Radeon i2c hw bus %s", name); 10746df74fa7SFrançois Tigeot iicbus_dev = device_add_child(dev->dev, "radeon_hw_i2c", -1); 1075926deccbSFrançois Tigeot if (iicbus_dev == NULL) { 1076926deccbSFrançois Tigeot DRM_ERROR("Failed to create bridge for hw i2c %s\n", 1077926deccbSFrançois Tigeot name); 1078926deccbSFrançois Tigeot goto out_free; 1079926deccbSFrançois Tigeot } 1080926deccbSFrançois Tigeot device_quiet(iicbus_dev); 1081926deccbSFrançois Tigeot device_set_softc(iicbus_dev, i2c); 1082926deccbSFrançois Tigeot 1083926deccbSFrançois Tigeot ret = device_probe_and_attach(iicbus_dev); 1084926deccbSFrançois Tigeot if (ret != 0) { 1085926deccbSFrançois Tigeot DRM_ERROR("Attach failed for bridge for hw i2c %s\n", 1086926deccbSFrançois Tigeot name); 10876df74fa7SFrançois Tigeot device_delete_child(dev->dev, iicbus_dev); 1088926deccbSFrançois Tigeot goto out_free; 1089926deccbSFrançois Tigeot } 1090926deccbSFrançois Tigeot 1091926deccbSFrançois Tigeot i2c->adapter = device_find_child(iicbus_dev, "iicbus", -1); 1092926deccbSFrançois Tigeot if (i2c->adapter == NULL) { 1093926deccbSFrançois Tigeot DRM_ERROR("hw i2c bridge doesn't have iicbus child\n"); 10946df74fa7SFrançois Tigeot device_delete_child(dev->dev, iicbus_dev); 1095926deccbSFrançois Tigeot goto out_free; 1096926deccbSFrançois Tigeot } 1097926deccbSFrançois Tigeot } else if (rec->hw_capable && 1098926deccbSFrançois Tigeot radeon_hw_i2c && 1099926deccbSFrançois Tigeot ASIC_IS_DCE3(rdev)) { 1100926deccbSFrançois Tigeot /* hw i2c using atom */ 1101926deccbSFrançois Tigeot ksnprintf(i2c->name, sizeof(i2c->name), 1102926deccbSFrançois Tigeot "Radeon i2c hw bus %s", name); 11036df74fa7SFrançois Tigeot iicbus_dev = device_add_child(dev->dev, "radeon_atom_hw_i2c", -1); 1104926deccbSFrançois Tigeot if (iicbus_dev == NULL) { 1105926deccbSFrançois Tigeot DRM_ERROR("Failed to create bridge for hw i2c %s\n", 1106926deccbSFrançois Tigeot name); 1107926deccbSFrançois Tigeot goto out_free; 1108926deccbSFrançois Tigeot } 1109926deccbSFrançois Tigeot device_quiet(iicbus_dev); 1110926deccbSFrançois Tigeot device_set_softc(iicbus_dev, i2c); 1111926deccbSFrançois Tigeot 1112926deccbSFrançois Tigeot ret = device_probe_and_attach(iicbus_dev); 1113926deccbSFrançois Tigeot if (ret != 0) { 1114926deccbSFrançois Tigeot DRM_ERROR("Attach failed for bridge for hw i2c %s\n", 1115926deccbSFrançois Tigeot name); 11166df74fa7SFrançois Tigeot device_delete_child(dev->dev, iicbus_dev); 1117926deccbSFrançois Tigeot goto out_free; 1118926deccbSFrançois Tigeot } 1119926deccbSFrançois Tigeot 1120926deccbSFrançois Tigeot i2c->adapter = device_find_child(iicbus_dev, "iicbus", -1); 1121926deccbSFrançois Tigeot if (i2c->adapter == NULL) { 1122926deccbSFrançois Tigeot DRM_ERROR("hw i2c bridge doesn't have iicbus child\n"); 11236df74fa7SFrançois Tigeot device_delete_child(dev->dev, iicbus_dev); 1124926deccbSFrançois Tigeot goto out_free; 1125926deccbSFrançois Tigeot } 1126926deccbSFrançois Tigeot } else { 1127926deccbSFrançois Tigeot device_t iicbb_dev; 1128926deccbSFrançois Tigeot 1129926deccbSFrançois Tigeot /* set the radeon bit adapter */ 1130926deccbSFrançois Tigeot ksnprintf(i2c->name, sizeof(i2c->name), 1131926deccbSFrançois Tigeot "Radeon i2c bit bus %s", name); 11326df74fa7SFrançois Tigeot iicbus_dev = device_add_child(dev->dev, "radeon_iicbb", -1); 1133926deccbSFrançois Tigeot if (iicbus_dev == NULL) { 1134926deccbSFrançois Tigeot DRM_ERROR("Failed to create bridge for bb i2c %s\n", 1135926deccbSFrançois Tigeot name); 1136926deccbSFrançois Tigeot goto out_free; 1137926deccbSFrançois Tigeot } 1138926deccbSFrançois Tigeot device_quiet(iicbus_dev); 1139926deccbSFrançois Tigeot device_set_softc(iicbus_dev, i2c); 1140926deccbSFrançois Tigeot 1141926deccbSFrançois Tigeot ret = device_probe_and_attach(iicbus_dev); 1142926deccbSFrançois Tigeot if (ret != 0) { 1143926deccbSFrançois Tigeot DRM_ERROR("Attach failed for bridge for bb i2c %s\n", 1144926deccbSFrançois Tigeot name); 11456df74fa7SFrançois Tigeot device_delete_child(dev->dev, iicbus_dev); 1146926deccbSFrançois Tigeot goto out_free; 1147926deccbSFrançois Tigeot } 1148926deccbSFrançois Tigeot 1149926deccbSFrançois Tigeot iicbb_dev = device_find_child(iicbus_dev, "iicbb", -1); 1150926deccbSFrançois Tigeot if (iicbb_dev == NULL) { 1151926deccbSFrançois Tigeot DRM_ERROR("bb i2c bridge doesn't have iicbb child\n"); 11526df74fa7SFrançois Tigeot device_delete_child(dev->dev, iicbus_dev); 1153926deccbSFrançois Tigeot goto out_free; 1154926deccbSFrançois Tigeot } 1155926deccbSFrançois Tigeot 1156926deccbSFrançois Tigeot i2c->adapter = device_find_child(iicbb_dev, "iicbus", -1); 1157926deccbSFrançois Tigeot if (i2c->adapter == NULL) { 1158926deccbSFrançois Tigeot DRM_ERROR( 1159926deccbSFrançois Tigeot "bbbus bridge doesn't have iicbus grandchild\n"); 11606df74fa7SFrançois Tigeot device_delete_child(dev->dev, iicbus_dev); 1161926deccbSFrançois Tigeot goto out_free; 1162926deccbSFrançois Tigeot } 1163926deccbSFrançois Tigeot } 1164926deccbSFrançois Tigeot 1165926deccbSFrançois Tigeot i2c->iic_bus = iicbus_dev; 1166926deccbSFrançois Tigeot 1167926deccbSFrançois Tigeot rel_mplock(); 1168926deccbSFrançois Tigeot 1169926deccbSFrançois Tigeot return i2c; 1170926deccbSFrançois Tigeot out_free: 1171926deccbSFrançois Tigeot rel_mplock(); 1172c4ef309bSzrj kfree(i2c); 1173926deccbSFrançois Tigeot return NULL; 1174926deccbSFrançois Tigeot 1175926deccbSFrançois Tigeot } 1176926deccbSFrançois Tigeot 1177926deccbSFrançois Tigeot struct radeon_i2c_chan *radeon_i2c_create_dp(struct drm_device *dev, 1178926deccbSFrançois Tigeot struct radeon_i2c_bus_rec *rec, 1179926deccbSFrançois Tigeot const char *name) 1180926deccbSFrançois Tigeot { 1181926deccbSFrançois Tigeot struct radeon_i2c_chan *i2c; 1182926deccbSFrançois Tigeot int ret; 1183926deccbSFrançois Tigeot 1184c4ef309bSzrj i2c = kzalloc(sizeof(struct radeon_i2c_chan), GFP_KERNEL); 1185926deccbSFrançois Tigeot if (i2c == NULL) 1186926deccbSFrançois Tigeot return NULL; 1187926deccbSFrançois Tigeot 1188926deccbSFrançois Tigeot i2c->rec = *rec; 1189926deccbSFrançois Tigeot i2c->dev = dev; 1190926deccbSFrançois Tigeot ksnprintf(i2c->name, sizeof(i2c->name), "Radeon aux bus %s", name); 11916df74fa7SFrançois Tigeot ret = iic_dp_aux_add_bus(dev->dev, i2c->name, 1192926deccbSFrançois Tigeot radeon_dp_i2c_aux_ch, i2c, &i2c->iic_bus, 1193926deccbSFrançois Tigeot &i2c->adapter); 1194926deccbSFrançois Tigeot if (ret) { 1195926deccbSFrançois Tigeot DRM_INFO("Failed to register i2c %s\n", name); 1196926deccbSFrançois Tigeot goto out_free; 1197926deccbSFrançois Tigeot } 1198926deccbSFrançois Tigeot 1199926deccbSFrançois Tigeot return i2c; 1200926deccbSFrançois Tigeot out_free: 1201c4ef309bSzrj kfree(i2c); 1202926deccbSFrançois Tigeot return NULL; 1203926deccbSFrançois Tigeot 1204926deccbSFrançois Tigeot } 1205926deccbSFrançois Tigeot 1206926deccbSFrançois Tigeot void radeon_i2c_destroy(struct radeon_i2c_chan *i2c) 1207926deccbSFrançois Tigeot { 1208926deccbSFrançois Tigeot if (!i2c) 1209926deccbSFrançois Tigeot return; 1210926deccbSFrançois Tigeot if (i2c->iic_bus != NULL) { 1211926deccbSFrançois Tigeot int ret; 1212926deccbSFrançois Tigeot 1213926deccbSFrançois Tigeot get_mplock(); 12146df74fa7SFrançois Tigeot ret = device_delete_child(i2c->dev->dev, i2c->iic_bus); 1215926deccbSFrançois Tigeot rel_mplock(); 1216926deccbSFrançois Tigeot KASSERT(ret == 0, ("unable to detach iic bus %s: %d", 1217926deccbSFrançois Tigeot i2c->name, ret)); 1218926deccbSFrançois Tigeot } 1219c4ef309bSzrj kfree(i2c); 1220926deccbSFrançois Tigeot } 1221926deccbSFrançois Tigeot 1222926deccbSFrançois Tigeot /* Add the default buses */ 1223926deccbSFrançois Tigeot void radeon_i2c_init(struct radeon_device *rdev) 1224926deccbSFrançois Tigeot { 1225c6f73aabSFrançois Tigeot if (radeon_hw_i2c) 1226c6f73aabSFrançois Tigeot DRM_INFO("hw_i2c forced on, you may experience display detection problems!\n"); 1227c6f73aabSFrançois Tigeot 1228926deccbSFrançois Tigeot if (rdev->is_atom_bios) 1229926deccbSFrançois Tigeot radeon_atombios_i2c_init(rdev); 1230926deccbSFrançois Tigeot else 1231926deccbSFrançois Tigeot radeon_combios_i2c_init(rdev); 1232926deccbSFrançois Tigeot } 1233926deccbSFrançois Tigeot 1234926deccbSFrançois Tigeot /* remove all the buses */ 1235926deccbSFrançois Tigeot void radeon_i2c_fini(struct radeon_device *rdev) 1236926deccbSFrançois Tigeot { 1237926deccbSFrançois Tigeot int i; 1238926deccbSFrançois Tigeot 1239926deccbSFrançois Tigeot for (i = 0; i < RADEON_MAX_I2C_BUS; i++) { 1240926deccbSFrançois Tigeot if (rdev->i2c_bus[i]) { 1241926deccbSFrançois Tigeot radeon_i2c_destroy(rdev->i2c_bus[i]); 1242926deccbSFrançois Tigeot rdev->i2c_bus[i] = NULL; 1243926deccbSFrançois Tigeot } 1244926deccbSFrançois Tigeot } 1245926deccbSFrançois Tigeot } 1246926deccbSFrançois Tigeot 1247926deccbSFrançois Tigeot /* Add additional buses */ 1248926deccbSFrançois Tigeot void radeon_i2c_add(struct radeon_device *rdev, 1249926deccbSFrançois Tigeot struct radeon_i2c_bus_rec *rec, 1250926deccbSFrançois Tigeot const char *name) 1251926deccbSFrançois Tigeot { 1252926deccbSFrançois Tigeot struct drm_device *dev = rdev->ddev; 1253926deccbSFrançois Tigeot int i; 1254926deccbSFrançois Tigeot 1255926deccbSFrançois Tigeot for (i = 0; i < RADEON_MAX_I2C_BUS; i++) { 1256926deccbSFrançois Tigeot if (!rdev->i2c_bus[i]) { 1257926deccbSFrançois Tigeot rdev->i2c_bus[i] = radeon_i2c_create(dev, rec, name); 1258926deccbSFrançois Tigeot return; 1259926deccbSFrançois Tigeot } 1260926deccbSFrançois Tigeot } 1261926deccbSFrançois Tigeot } 1262926deccbSFrançois Tigeot 1263926deccbSFrançois Tigeot /* looks up bus based on id */ 1264926deccbSFrançois Tigeot struct radeon_i2c_chan *radeon_i2c_lookup(struct radeon_device *rdev, 1265926deccbSFrançois Tigeot struct radeon_i2c_bus_rec *i2c_bus) 1266926deccbSFrançois Tigeot { 1267926deccbSFrançois Tigeot int i; 1268926deccbSFrançois Tigeot 1269926deccbSFrançois Tigeot for (i = 0; i < RADEON_MAX_I2C_BUS; i++) { 1270926deccbSFrançois Tigeot if (rdev->i2c_bus[i] && 1271926deccbSFrançois Tigeot (rdev->i2c_bus[i]->rec.i2c_id == i2c_bus->i2c_id)) { 1272926deccbSFrançois Tigeot return rdev->i2c_bus[i]; 1273926deccbSFrançois Tigeot } 1274926deccbSFrançois Tigeot } 1275926deccbSFrançois Tigeot return NULL; 1276926deccbSFrançois Tigeot } 1277926deccbSFrançois Tigeot 1278926deccbSFrançois Tigeot struct drm_encoder *radeon_best_encoder(struct drm_connector *connector) 1279926deccbSFrançois Tigeot { 1280926deccbSFrançois Tigeot return NULL; 1281926deccbSFrançois Tigeot } 1282926deccbSFrançois Tigeot 1283926deccbSFrançois Tigeot void radeon_i2c_get_byte(struct radeon_i2c_chan *i2c_bus, 1284926deccbSFrançois Tigeot u8 slave_addr, 1285926deccbSFrançois Tigeot u8 addr, 1286926deccbSFrançois Tigeot u8 *val) 1287926deccbSFrançois Tigeot { 1288926deccbSFrançois Tigeot u8 out_buf[2]; 1289926deccbSFrançois Tigeot u8 in_buf[2]; 1290926deccbSFrançois Tigeot struct iic_msg msgs[] = { 1291926deccbSFrançois Tigeot { 1292926deccbSFrançois Tigeot .slave = slave_addr << 1, 1293926deccbSFrançois Tigeot .flags = 0, 1294926deccbSFrançois Tigeot .len = 1, 1295926deccbSFrançois Tigeot .buf = out_buf, 1296926deccbSFrançois Tigeot }, 1297926deccbSFrançois Tigeot { 1298926deccbSFrançois Tigeot .slave = slave_addr << 1, 1299926deccbSFrançois Tigeot .flags = IIC_M_RD, 1300926deccbSFrançois Tigeot .len = 1, 1301926deccbSFrançois Tigeot .buf = in_buf, 1302926deccbSFrançois Tigeot } 1303926deccbSFrançois Tigeot }; 1304926deccbSFrançois Tigeot 1305926deccbSFrançois Tigeot out_buf[0] = addr; 1306926deccbSFrançois Tigeot out_buf[1] = 0; 1307926deccbSFrançois Tigeot 1308926deccbSFrançois Tigeot if (iicbus_transfer(i2c_bus->adapter, msgs, 2) == 0) { 1309926deccbSFrançois Tigeot *val = in_buf[0]; 1310926deccbSFrançois Tigeot DRM_DEBUG("val = 0x%02x\n", *val); 1311926deccbSFrançois Tigeot } else { 1312926deccbSFrançois Tigeot DRM_DEBUG("i2c 0x%02x 0x%02x read failed\n", 1313926deccbSFrançois Tigeot addr, *val); 1314926deccbSFrançois Tigeot } 1315926deccbSFrançois Tigeot } 1316926deccbSFrançois Tigeot 1317926deccbSFrançois Tigeot void radeon_i2c_put_byte(struct radeon_i2c_chan *i2c_bus, 1318926deccbSFrançois Tigeot u8 slave_addr, 1319926deccbSFrançois Tigeot u8 addr, 1320926deccbSFrançois Tigeot u8 val) 1321926deccbSFrançois Tigeot { 1322926deccbSFrançois Tigeot uint8_t out_buf[2]; 1323926deccbSFrançois Tigeot struct iic_msg msg = { 1324926deccbSFrançois Tigeot .slave = slave_addr << 1, 1325926deccbSFrançois Tigeot .flags = 0, 1326926deccbSFrançois Tigeot .len = 2, 1327926deccbSFrançois Tigeot .buf = out_buf, 1328926deccbSFrançois Tigeot }; 1329926deccbSFrançois Tigeot 1330926deccbSFrançois Tigeot out_buf[0] = addr; 1331926deccbSFrançois Tigeot out_buf[1] = val; 1332926deccbSFrançois Tigeot 1333926deccbSFrançois Tigeot if (iicbus_transfer(i2c_bus->adapter, &msg, 1) != 0) 1334926deccbSFrançois Tigeot DRM_DEBUG("i2c 0x%02x 0x%02x write failed\n", 1335926deccbSFrançois Tigeot addr, val); 1336926deccbSFrançois Tigeot } 1337926deccbSFrançois Tigeot 1338926deccbSFrançois Tigeot /* ddc router switching */ 1339926deccbSFrançois Tigeot void radeon_router_select_ddc_port(struct radeon_connector *radeon_connector) 1340926deccbSFrançois Tigeot { 1341926deccbSFrançois Tigeot u8 val; 1342926deccbSFrançois Tigeot 1343926deccbSFrançois Tigeot if (!radeon_connector->router.ddc_valid) 1344926deccbSFrançois Tigeot return; 1345926deccbSFrançois Tigeot 1346926deccbSFrançois Tigeot if (!radeon_connector->router_bus) 1347926deccbSFrançois Tigeot return; 1348926deccbSFrançois Tigeot 1349926deccbSFrançois Tigeot radeon_i2c_get_byte(radeon_connector->router_bus, 1350926deccbSFrançois Tigeot radeon_connector->router.i2c_addr, 1351926deccbSFrançois Tigeot 0x3, &val); 1352926deccbSFrançois Tigeot val &= ~radeon_connector->router.ddc_mux_control_pin; 1353926deccbSFrançois Tigeot radeon_i2c_put_byte(radeon_connector->router_bus, 1354926deccbSFrançois Tigeot radeon_connector->router.i2c_addr, 1355926deccbSFrançois Tigeot 0x3, val); 1356926deccbSFrançois Tigeot radeon_i2c_get_byte(radeon_connector->router_bus, 1357926deccbSFrançois Tigeot radeon_connector->router.i2c_addr, 1358926deccbSFrançois Tigeot 0x1, &val); 1359926deccbSFrançois Tigeot val &= ~radeon_connector->router.ddc_mux_control_pin; 1360926deccbSFrançois Tigeot val |= radeon_connector->router.ddc_mux_state; 1361926deccbSFrançois Tigeot radeon_i2c_put_byte(radeon_connector->router_bus, 1362926deccbSFrançois Tigeot radeon_connector->router.i2c_addr, 1363926deccbSFrançois Tigeot 0x1, val); 1364926deccbSFrançois Tigeot } 1365926deccbSFrançois Tigeot 1366926deccbSFrançois Tigeot /* clock/data router switching */ 1367926deccbSFrançois Tigeot void radeon_router_select_cd_port(struct radeon_connector *radeon_connector) 1368926deccbSFrançois Tigeot { 1369926deccbSFrançois Tigeot u8 val; 1370926deccbSFrançois Tigeot 1371926deccbSFrançois Tigeot if (!radeon_connector->router.cd_valid) 1372926deccbSFrançois Tigeot return; 1373926deccbSFrançois Tigeot 1374926deccbSFrançois Tigeot if (!radeon_connector->router_bus) 1375926deccbSFrançois Tigeot return; 1376926deccbSFrançois Tigeot 1377926deccbSFrançois Tigeot radeon_i2c_get_byte(radeon_connector->router_bus, 1378926deccbSFrançois Tigeot radeon_connector->router.i2c_addr, 1379926deccbSFrançois Tigeot 0x3, &val); 1380926deccbSFrançois Tigeot val &= ~radeon_connector->router.cd_mux_control_pin; 1381926deccbSFrançois Tigeot radeon_i2c_put_byte(radeon_connector->router_bus, 1382926deccbSFrançois Tigeot radeon_connector->router.i2c_addr, 1383926deccbSFrançois Tigeot 0x3, val); 1384926deccbSFrançois Tigeot radeon_i2c_get_byte(radeon_connector->router_bus, 1385926deccbSFrançois Tigeot radeon_connector->router.i2c_addr, 1386926deccbSFrançois Tigeot 0x1, &val); 1387926deccbSFrançois Tigeot val &= ~radeon_connector->router.cd_mux_control_pin; 1388926deccbSFrançois Tigeot val |= radeon_connector->router.cd_mux_state; 1389926deccbSFrançois Tigeot radeon_i2c_put_byte(radeon_connector->router_bus, 1390926deccbSFrançois Tigeot radeon_connector->router.i2c_addr, 1391926deccbSFrançois Tigeot 0x1, val); 1392926deccbSFrançois Tigeot } 1393926deccbSFrançois Tigeot 1394