diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2013-02-11 05:06:04 -0500 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2013-02-20 01:00:56 -0500 |
commit | df3ef6a1091fbdfb57306b0205edef33a1f1dcb4 (patch) | |
tree | 87cbc093d868bbcb499ad91cb5e63300ec05b154 /drivers/gpu/drm | |
parent | f63740fd580e0645c5123897891b72ec25b396ef (diff) |
drm/nouveau/i2c: handle i2c/aux mux outside of port lookup function
Not quite how I want it yet, but, I'll fix that at some point. For
right now, it's needed because find() won't necessarily be used right
before a transaction anymore.
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r-- | drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c | 16 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/subdev/i2c/base.c | 41 |
2 files changed, 36 insertions, 21 deletions
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c index dc27e794a851..1a428743cf8e 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c | |||
@@ -150,15 +150,29 @@ out: | |||
150 | return ret; | 150 | return ret; |
151 | } | 151 | } |
152 | 152 | ||
153 | static void | ||
154 | auxch_mux(struct nouveau_i2c_port *port) | ||
155 | { | ||
156 | if (port->dcb & 0x00000100) { | ||
157 | u32 reg = 0x00e500 + (port->drive * 0x50); | ||
158 | /* nfi, but neither auxch or i2c work if it's 1 */ | ||
159 | nv_mask(port->i2c, reg + 0x0c, 0x00000001, 0x00000000); | ||
160 | /* nfi, but switches auxch vs normal i2c */ | ||
161 | nv_mask(port->i2c, reg + 0x00, 0x0000f003, 0x00002002); | ||
162 | } | ||
163 | } | ||
164 | |||
153 | int | 165 | int |
154 | nv_rdaux(struct nouveau_i2c_port *auxch, u32 addr, u8 *data, u8 size) | 166 | nv_rdaux(struct nouveau_i2c_port *auxch, u32 addr, u8 *data, u8 size) |
155 | { | 167 | { |
168 | auxch_mux(auxch); | ||
156 | return auxch_tx(auxch->i2c, auxch->drive, 9, addr, data, size); | 169 | return auxch_tx(auxch->i2c, auxch->drive, 9, addr, data, size); |
157 | } | 170 | } |
158 | 171 | ||
159 | int | 172 | int |
160 | nv_wraux(struct nouveau_i2c_port *auxch, u32 addr, u8 *data, u8 size) | 173 | nv_wraux(struct nouveau_i2c_port *auxch, u32 addr, u8 *data, u8 size) |
161 | { | 174 | { |
175 | auxch_mux(auxch); | ||
162 | return auxch_tx(auxch->i2c, auxch->drive, 8, addr, data, size); | 176 | return auxch_tx(auxch->i2c, auxch->drive, 8, addr, data, size); |
163 | } | 177 | } |
164 | 178 | ||
@@ -169,6 +183,8 @@ aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) | |||
169 | struct i2c_msg *msg = msgs; | 183 | struct i2c_msg *msg = msgs; |
170 | int ret, mcnt = num; | 184 | int ret, mcnt = num; |
171 | 185 | ||
186 | auxch_mux(auxch); | ||
187 | |||
172 | while (mcnt--) { | 188 | while (mcnt--) { |
173 | u8 remaining = msg->len; | 189 | u8 remaining = msg->len; |
174 | u8 *ptr = msg->buf; | 190 | u8 *ptr = msg->buf; |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c index dbfc2abf0cfe..1ee53d3cbd01 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c | |||
@@ -103,29 +103,10 @@ nouveau_i2c_find(struct nouveau_i2c *i2c, u8 index) | |||
103 | 103 | ||
104 | list_for_each_entry(port, &i2c->ports, head) { | 104 | list_for_each_entry(port, &i2c->ports, head) { |
105 | if (port->index == index) | 105 | if (port->index == index) |
106 | break; | 106 | return port; |
107 | } | ||
108 | |||
109 | if (&port->head == &i2c->ports) | ||
110 | return NULL; | ||
111 | |||
112 | if (nv_device(i2c)->card_type >= NV_50 && (port->dcb & 0x00000100)) { | ||
113 | u32 reg = 0x00e500, val; | ||
114 | if (port->type == 6) { | ||
115 | reg += port->drive * 0x50; | ||
116 | val = 0x2002; | ||
117 | } else { | ||
118 | reg += ((port->dcb & 0x1e00) >> 9) * 0x50; | ||
119 | val = 0xe001; | ||
120 | } | ||
121 | |||
122 | /* nfi, but neither auxch or i2c work if it's 1 */ | ||
123 | nv_mask(i2c, reg + 0x0c, 0x00000001, 0x00000000); | ||
124 | /* nfi, but switches auxch vs normal i2c */ | ||
125 | nv_mask(i2c, reg + 0x00, 0x0000f003, val); | ||
126 | } | 107 | } |
127 | 108 | ||
128 | return port; | 109 | return NULL; |
129 | } | 110 | } |
130 | 111 | ||
131 | static int | 112 | static int |
@@ -241,6 +222,23 @@ nouveau_i2c_sense_sda(void *data) | |||
241 | return 0; | 222 | return 0; |
242 | } | 223 | } |
243 | 224 | ||
225 | static int | ||
226 | nouveau_i2c_pre_xfer(struct i2c_adapter *adap) | ||
227 | { | ||
228 | struct nouveau_i2c_port *port = (void *)adap; | ||
229 | struct nouveau_i2c *i2c = port->i2c; | ||
230 | |||
231 | if (nv_device(i2c)->card_type >= NV_50 && (port->dcb & 0x00000100)) { | ||
232 | u32 reg = 0x00e500 + ((port->dcb & 0x1e00) >> 9) * 0x50; | ||
233 | /* nfi, but neither auxch or i2c work if it's 1 */ | ||
234 | nv_mask(i2c, reg + 0x0c, 0x00000001, 0x00000000); | ||
235 | /* nfi, but switches auxch vs normal i2c */ | ||
236 | nv_mask(i2c, reg + 0x00, 0x0000f003, 0x0000e001); | ||
237 | } | ||
238 | |||
239 | return 0; | ||
240 | } | ||
241 | |||
244 | static const u32 nv50_i2c_port[] = { | 242 | static const u32 nv50_i2c_port[] = { |
245 | 0x00e138, 0x00e150, 0x00e168, 0x00e180, | 243 | 0x00e138, 0x00e150, 0x00e168, 0x00e180, |
246 | 0x00e254, 0x00e274, 0x00e764, 0x00e780, | 244 | 0x00e254, 0x00e274, 0x00e764, 0x00e780, |
@@ -347,6 +345,7 @@ nouveau_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | |||
347 | port->bit.setscl = nouveau_i2c_drive_scl; | 345 | port->bit.setscl = nouveau_i2c_drive_scl; |
348 | port->bit.getsda = nouveau_i2c_sense_sda; | 346 | port->bit.getsda = nouveau_i2c_sense_sda; |
349 | port->bit.getscl = nouveau_i2c_sense_scl; | 347 | port->bit.getscl = nouveau_i2c_sense_scl; |
348 | port->bit.pre_xfer = nouveau_i2c_pre_xfer; | ||
350 | ret = i2c_bit_add_bus(&port->adapter); | 349 | ret = i2c_bit_add_bus(&port->adapter); |
351 | } | 350 | } |
352 | } else { | 351 | } else { |