brintos

brintos / linux-shallow public Read only

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