Path: blob/master/drivers/gpu/drm/nouveau/nouveau_i2c.c
15112 views
/*1* Copyright 2009 Red Hat Inc.2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice shall be included in11* all copies or substantial portions of the Software.12*13* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR14* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,15* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL16* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR17* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,18* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR19* OTHER DEALINGS IN THE SOFTWARE.20*21* Authors: Ben Skeggs22*/2324#include "drmP.h"25#include "nouveau_drv.h"26#include "nouveau_i2c.h"27#include "nouveau_hw.h"2829static void30nv04_i2c_setscl(void *data, int state)31{32struct nouveau_i2c_chan *i2c = data;33struct drm_device *dev = i2c->dev;34uint8_t val;3536val = (NVReadVgaCrtc(dev, 0, i2c->wr) & 0xd0) | (state ? 0x20 : 0);37NVWriteVgaCrtc(dev, 0, i2c->wr, val | 0x01);38}3940static void41nv04_i2c_setsda(void *data, int state)42{43struct nouveau_i2c_chan *i2c = data;44struct drm_device *dev = i2c->dev;45uint8_t val;4647val = (NVReadVgaCrtc(dev, 0, i2c->wr) & 0xe0) | (state ? 0x10 : 0);48NVWriteVgaCrtc(dev, 0, i2c->wr, val | 0x01);49}5051static int52nv04_i2c_getscl(void *data)53{54struct nouveau_i2c_chan *i2c = data;55struct drm_device *dev = i2c->dev;5657return !!(NVReadVgaCrtc(dev, 0, i2c->rd) & 4);58}5960static int61nv04_i2c_getsda(void *data)62{63struct nouveau_i2c_chan *i2c = data;64struct drm_device *dev = i2c->dev;6566return !!(NVReadVgaCrtc(dev, 0, i2c->rd) & 8);67}6869static void70nv4e_i2c_setscl(void *data, int state)71{72struct nouveau_i2c_chan *i2c = data;73struct drm_device *dev = i2c->dev;74uint8_t val;7576val = (nv_rd32(dev, i2c->wr) & 0xd0) | (state ? 0x20 : 0);77nv_wr32(dev, i2c->wr, val | 0x01);78}7980static void81nv4e_i2c_setsda(void *data, int state)82{83struct nouveau_i2c_chan *i2c = data;84struct drm_device *dev = i2c->dev;85uint8_t val;8687val = (nv_rd32(dev, i2c->wr) & 0xe0) | (state ? 0x10 : 0);88nv_wr32(dev, i2c->wr, val | 0x01);89}9091static int92nv4e_i2c_getscl(void *data)93{94struct nouveau_i2c_chan *i2c = data;95struct drm_device *dev = i2c->dev;9697return !!((nv_rd32(dev, i2c->rd) >> 16) & 4);98}99100static int101nv4e_i2c_getsda(void *data)102{103struct nouveau_i2c_chan *i2c = data;104struct drm_device *dev = i2c->dev;105106return !!((nv_rd32(dev, i2c->rd) >> 16) & 8);107}108109static int110nv50_i2c_getscl(void *data)111{112struct nouveau_i2c_chan *i2c = data;113struct drm_device *dev = i2c->dev;114115return !!(nv_rd32(dev, i2c->rd) & 1);116}117118119static int120nv50_i2c_getsda(void *data)121{122struct nouveau_i2c_chan *i2c = data;123struct drm_device *dev = i2c->dev;124125return !!(nv_rd32(dev, i2c->rd) & 2);126}127128static void129nv50_i2c_setscl(void *data, int state)130{131struct nouveau_i2c_chan *i2c = data;132struct drm_device *dev = i2c->dev;133134nv_wr32(dev, i2c->wr, 4 | (i2c->data ? 2 : 0) | (state ? 1 : 0));135}136137static void138nv50_i2c_setsda(void *data, int state)139{140struct nouveau_i2c_chan *i2c = data;141struct drm_device *dev = i2c->dev;142143nv_wr32(dev, i2c->wr,144(nv_rd32(dev, i2c->rd) & 1) | 4 | (state ? 2 : 0));145i2c->data = state;146}147148static const uint32_t nv50_i2c_port[] = {1490x00e138, 0x00e150, 0x00e168, 0x00e180,1500x00e254, 0x00e274, 0x00e764, 0x00e780,1510x00e79c, 0x00e7b8152};153#define NV50_I2C_PORTS ARRAY_SIZE(nv50_i2c_port)154155int156nouveau_i2c_init(struct drm_device *dev, struct dcb_i2c_entry *entry, int index)157{158struct drm_nouveau_private *dev_priv = dev->dev_private;159struct nouveau_i2c_chan *i2c;160int ret;161162if (entry->chan)163return -EEXIST;164165if (dev_priv->card_type >= NV_50 && entry->read >= NV50_I2C_PORTS) {166NV_ERROR(dev, "unknown i2c port %d\n", entry->read);167return -EINVAL;168}169170i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);171if (i2c == NULL)172return -ENOMEM;173174switch (entry->port_type) {175case 0:176i2c->bit.setsda = nv04_i2c_setsda;177i2c->bit.setscl = nv04_i2c_setscl;178i2c->bit.getsda = nv04_i2c_getsda;179i2c->bit.getscl = nv04_i2c_getscl;180i2c->rd = entry->read;181i2c->wr = entry->write;182break;183case 4:184i2c->bit.setsda = nv4e_i2c_setsda;185i2c->bit.setscl = nv4e_i2c_setscl;186i2c->bit.getsda = nv4e_i2c_getsda;187i2c->bit.getscl = nv4e_i2c_getscl;188i2c->rd = 0x600800 + entry->read;189i2c->wr = 0x600800 + entry->write;190break;191case 5:192i2c->bit.setsda = nv50_i2c_setsda;193i2c->bit.setscl = nv50_i2c_setscl;194i2c->bit.getsda = nv50_i2c_getsda;195i2c->bit.getscl = nv50_i2c_getscl;196i2c->rd = nv50_i2c_port[entry->read];197i2c->wr = i2c->rd;198break;199case 6:200i2c->rd = entry->read;201i2c->wr = entry->write;202break;203default:204NV_ERROR(dev, "DCB I2C port type %d unknown\n",205entry->port_type);206kfree(i2c);207return -EINVAL;208}209210snprintf(i2c->adapter.name, sizeof(i2c->adapter.name),211"nouveau-%s-%d", pci_name(dev->pdev), index);212i2c->adapter.owner = THIS_MODULE;213i2c->adapter.dev.parent = &dev->pdev->dev;214i2c->dev = dev;215i2c_set_adapdata(&i2c->adapter, i2c);216217if (entry->port_type < 6) {218i2c->adapter.algo_data = &i2c->bit;219i2c->bit.udelay = 40;220i2c->bit.timeout = usecs_to_jiffies(5000);221i2c->bit.data = i2c;222ret = i2c_bit_add_bus(&i2c->adapter);223} else {224i2c->adapter.algo = &nouveau_dp_i2c_algo;225ret = i2c_add_adapter(&i2c->adapter);226}227228if (ret) {229NV_ERROR(dev, "Failed to register i2c %d\n", index);230kfree(i2c);231return ret;232}233234entry->chan = i2c;235return 0;236}237238void239nouveau_i2c_fini(struct drm_device *dev, struct dcb_i2c_entry *entry)240{241if (!entry->chan)242return;243244i2c_del_adapter(&entry->chan->adapter);245kfree(entry->chan);246entry->chan = NULL;247}248249struct nouveau_i2c_chan *250nouveau_i2c_find(struct drm_device *dev, int index)251{252struct drm_nouveau_private *dev_priv = dev->dev_private;253struct dcb_i2c_entry *i2c = &dev_priv->vbios.dcb.i2c[index];254255if (index >= DCB_MAX_NUM_I2C_ENTRIES)256return NULL;257258if (dev_priv->card_type >= NV_50 && (i2c->entry & 0x00000100)) {259uint32_t reg = 0xe500, val;260261if (i2c->port_type == 6) {262reg += i2c->read * 0x50;263val = 0x2002;264} else {265reg += ((i2c->entry & 0x1e00) >> 9) * 0x50;266val = 0xe001;267}268269nv_wr32(dev, reg, (nv_rd32(dev, reg) & ~0xf003) | val);270}271272if (!i2c->chan && nouveau_i2c_init(dev, i2c, index))273return NULL;274return i2c->chan;275}276277bool278nouveau_probe_i2c_addr(struct nouveau_i2c_chan *i2c, int addr)279{280uint8_t buf[] = { 0 };281struct i2c_msg msgs[] = {282{283.addr = addr,284.flags = 0,285.len = 1,286.buf = buf,287},288{289.addr = addr,290.flags = I2C_M_RD,291.len = 1,292.buf = buf,293}294};295296return i2c_transfer(&i2c->adapter, msgs, 2) == 2;297}298299int300nouveau_i2c_identify(struct drm_device *dev, const char *what,301struct i2c_board_info *info,302bool (*match)(struct nouveau_i2c_chan *,303struct i2c_board_info *),304int index)305{306struct nouveau_i2c_chan *i2c = nouveau_i2c_find(dev, index);307int i;308309NV_DEBUG(dev, "Probing %ss on I2C bus: %d\n", what, index);310311for (i = 0; info[i].addr; i++) {312if (nouveau_probe_i2c_addr(i2c, info[i].addr) &&313(!match || match(i2c, &info[i]))) {314NV_INFO(dev, "Detected %s: %s\n", what, info[i].type);315return i;316}317}318319NV_DEBUG(dev, "No devices found.\n");320321return -ENODEV;322}323324325