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