1 /* $NetBSD: nouveau_nvkm_subdev_i2c_anx9805.c,v 1.3 2021/12/18 23:45:40 riastradh Exp $ */
2
3 /*
4 * Copyright 2013 Red Hat Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * Authors: Ben Skeggs <bskeggs@redhat.com>
25 */
26 #include <sys/cdefs.h>
27 __KERNEL_RCSID(0, "$NetBSD: nouveau_nvkm_subdev_i2c_anx9805.c,v 1.3 2021/12/18 23:45:40 riastradh Exp $");
28
29 #define anx9805_pad(p) container_of((p), struct anx9805_pad, base)
30 #define anx9805_bus(p) container_of((p), struct anx9805_bus, base)
31 #define anx9805_aux(p) container_of((p), struct anx9805_aux, base)
32 #include "aux.h"
33 #include "bus.h"
34
35 struct anx9805_pad {
36 struct nvkm_i2c_pad base;
37 struct nvkm_i2c_bus *bus;
38 u8 addr;
39 };
40
41 struct anx9805_bus {
42 struct nvkm_i2c_bus base;
43 struct anx9805_pad *pad;
44 u8 addr;
45 };
46
47 static int
anx9805_bus_xfer(struct nvkm_i2c_bus * base,struct i2c_msg * msgs,int num)48 anx9805_bus_xfer(struct nvkm_i2c_bus *base, struct i2c_msg *msgs, int num)
49 {
50 struct anx9805_bus *bus = anx9805_bus(base);
51 struct anx9805_pad *pad = bus->pad;
52 struct i2c_adapter *adap = &pad->bus->i2c;
53 struct i2c_msg *msg = msgs;
54 int ret = -ETIMEDOUT;
55 int i, j, cnt = num;
56 u8 seg = 0x00, off = 0x00, tmp;
57
58 tmp = nvkm_rdi2cr(adap, pad->addr, 0x07) & ~0x10;
59 nvkm_wri2cr(adap, pad->addr, 0x07, tmp | 0x10);
60 nvkm_wri2cr(adap, pad->addr, 0x07, tmp);
61 nvkm_wri2cr(adap, bus->addr, 0x43, 0x05);
62 mdelay(5);
63
64 while (cnt--) {
65 if ( (msg->flags & I2C_M_RD) && msg->addr == 0x50) {
66 nvkm_wri2cr(adap, bus->addr, 0x40, msg->addr << 1);
67 nvkm_wri2cr(adap, bus->addr, 0x41, seg);
68 nvkm_wri2cr(adap, bus->addr, 0x42, off);
69 nvkm_wri2cr(adap, bus->addr, 0x44, msg->len);
70 nvkm_wri2cr(adap, bus->addr, 0x45, 0x00);
71 nvkm_wri2cr(adap, bus->addr, 0x43, 0x01);
72 for (i = 0; i < msg->len; i++) {
73 j = 0;
74 while (nvkm_rdi2cr(adap, bus->addr, 0x46) & 0x10) {
75 mdelay(5);
76 if (j++ == 32)
77 goto done;
78 }
79 msg->buf[i] = nvkm_rdi2cr(adap, bus->addr, 0x47);
80 }
81 } else
82 if (!(msg->flags & I2C_M_RD)) {
83 if (msg->addr == 0x50 && msg->len == 0x01) {
84 off = msg->buf[0];
85 } else
86 if (msg->addr == 0x30 && msg->len == 0x01) {
87 seg = msg->buf[0];
88 } else
89 goto done;
90 } else {
91 goto done;
92 }
93 msg++;
94 }
95
96 ret = num;
97 done:
98 nvkm_wri2cr(adap, bus->addr, 0x43, 0x00);
99 return ret;
100 }
101
102 static const struct nvkm_i2c_bus_func
103 anx9805_bus_func = {
104 .xfer = anx9805_bus_xfer,
105 };
106
107 static int
anx9805_bus_new(struct nvkm_i2c_pad * base,int id,u8 drive,struct nvkm_i2c_bus ** pbus)108 anx9805_bus_new(struct nvkm_i2c_pad *base, int id, u8 drive,
109 struct nvkm_i2c_bus **pbus)
110 {
111 struct anx9805_pad *pad = anx9805_pad(base);
112 struct anx9805_bus *bus;
113 int ret;
114
115 if (!(bus = kzalloc(sizeof(*bus), GFP_KERNEL)))
116 return -ENOMEM;
117 *pbus = &bus->base;
118 bus->pad = pad;
119
120 ret = nvkm_i2c_bus_ctor(&anx9805_bus_func, &pad->base, id, &bus->base);
121 if (ret)
122 return ret;
123
124 switch (pad->addr) {
125 case 0x39: bus->addr = 0x3d; break;
126 case 0x3b: bus->addr = 0x3f; break;
127 default:
128 return -ENOSYS;
129 }
130
131 return 0;
132 }
133
134 struct anx9805_aux {
135 struct nvkm_i2c_aux base;
136 struct anx9805_pad *pad;
137 u8 addr;
138 };
139
140 static int
anx9805_aux_xfer(struct nvkm_i2c_aux * base,bool retry,u8 type,u32 addr,u8 * data,u8 * size)141 anx9805_aux_xfer(struct nvkm_i2c_aux *base, bool retry,
142 u8 type, u32 addr, u8 *data, u8 *size)
143 {
144 struct anx9805_aux *aux = anx9805_aux(base);
145 struct anx9805_pad *pad = aux->pad;
146 struct i2c_adapter *adap = &pad->bus->i2c;
147 int i, ret = -ETIMEDOUT;
148 u8 buf[16] = {};
149 u8 tmp;
150
151 AUX_DBG(&aux->base, "%02x %05x %d", type, addr, *size);
152
153 tmp = nvkm_rdi2cr(adap, pad->addr, 0x07) & ~0x04;
154 nvkm_wri2cr(adap, pad->addr, 0x07, tmp | 0x04);
155 nvkm_wri2cr(adap, pad->addr, 0x07, tmp);
156 nvkm_wri2cr(adap, pad->addr, 0xf7, 0x01);
157
158 nvkm_wri2cr(adap, aux->addr, 0xe4, 0x80);
159 if (!(type & 1)) {
160 memcpy(buf, data, *size);
161 AUX_DBG(&aux->base, "%16ph", buf);
162 for (i = 0; i < *size; i++)
163 nvkm_wri2cr(adap, aux->addr, 0xf0 + i, buf[i]);
164 }
165 nvkm_wri2cr(adap, aux->addr, 0xe5, ((*size - 1) << 4) | type);
166 nvkm_wri2cr(adap, aux->addr, 0xe6, (addr & 0x000ff) >> 0);
167 nvkm_wri2cr(adap, aux->addr, 0xe7, (addr & 0x0ff00) >> 8);
168 nvkm_wri2cr(adap, aux->addr, 0xe8, (addr & 0xf0000) >> 16);
169 nvkm_wri2cr(adap, aux->addr, 0xe9, 0x01);
170
171 i = 0;
172 while ((tmp = nvkm_rdi2cr(adap, aux->addr, 0xe9)) & 0x01) {
173 mdelay(5);
174 if (i++ == 32)
175 goto done;
176 }
177
178 if ((tmp = nvkm_rdi2cr(adap, pad->addr, 0xf7)) & 0x01) {
179 ret = -EIO;
180 goto done;
181 }
182
183 if (type & 1) {
184 for (i = 0; i < *size; i++)
185 buf[i] = nvkm_rdi2cr(adap, aux->addr, 0xf0 + i);
186 AUX_DBG(&aux->base, "%16ph", buf);
187 memcpy(data, buf, *size);
188 }
189
190 ret = 0;
191 done:
192 nvkm_wri2cr(adap, pad->addr, 0xf7, 0x01);
193 return ret;
194 }
195
196 static int
anx9805_aux_lnk_ctl(struct nvkm_i2c_aux * base,int link_nr,int link_bw,bool enh)197 anx9805_aux_lnk_ctl(struct nvkm_i2c_aux *base,
198 int link_nr, int link_bw, bool enh)
199 {
200 struct anx9805_aux *aux = anx9805_aux(base);
201 struct anx9805_pad *pad = aux->pad;
202 struct i2c_adapter *adap = &pad->bus->i2c;
203 u8 tmp, i;
204
205 AUX_DBG(&aux->base, "ANX9805 train %d %02x %d",
206 link_nr, link_bw, enh);
207
208 nvkm_wri2cr(adap, aux->addr, 0xa0, link_bw);
209 nvkm_wri2cr(adap, aux->addr, 0xa1, link_nr | (enh ? 0x80 : 0x00));
210 nvkm_wri2cr(adap, aux->addr, 0xa2, 0x01);
211 nvkm_wri2cr(adap, aux->addr, 0xa8, 0x01);
212
213 i = 0;
214 while ((tmp = nvkm_rdi2cr(adap, aux->addr, 0xa8)) & 0x01) {
215 mdelay(5);
216 if (i++ == 100) {
217 AUX_ERR(&aux->base, "link training timeout");
218 return -ETIMEDOUT;
219 }
220 }
221
222 if (tmp & 0x70) {
223 AUX_ERR(&aux->base, "link training failed");
224 return -EIO;
225 }
226
227 return 0;
228 }
229
230 static const struct nvkm_i2c_aux_func
231 anx9805_aux_func = {
232 .xfer = anx9805_aux_xfer,
233 .lnk_ctl = anx9805_aux_lnk_ctl,
234 };
235
236 static int
anx9805_aux_new(struct nvkm_i2c_pad * base,int id,u8 drive,struct nvkm_i2c_aux ** pbus)237 anx9805_aux_new(struct nvkm_i2c_pad *base, int id, u8 drive,
238 struct nvkm_i2c_aux **pbus)
239 {
240 struct anx9805_pad *pad = anx9805_pad(base);
241 struct anx9805_aux *aux;
242 int ret;
243
244 if (!(aux = kzalloc(sizeof(*aux), GFP_KERNEL)))
245 return -ENOMEM;
246 *pbus = &aux->base;
247 aux->pad = pad;
248
249 ret = nvkm_i2c_aux_ctor(&anx9805_aux_func, &pad->base, id, &aux->base);
250 if (ret)
251 return ret;
252
253 switch (pad->addr) {
254 case 0x39: aux->addr = 0x38; break;
255 case 0x3b: aux->addr = 0x3c; break;
256 default:
257 return -ENOSYS;
258 }
259
260 return 0;
261 }
262
263 static const struct nvkm_i2c_pad_func
264 anx9805_pad_func = {
265 .bus_new_4 = anx9805_bus_new,
266 .aux_new_6 = anx9805_aux_new,
267 };
268
269 int
anx9805_pad_new(struct nvkm_i2c_bus * bus,int id,u8 addr,struct nvkm_i2c_pad ** ppad)270 anx9805_pad_new(struct nvkm_i2c_bus *bus, int id, u8 addr,
271 struct nvkm_i2c_pad **ppad)
272 {
273 struct anx9805_pad *pad;
274
275 if (!(pad = kzalloc(sizeof(*pad), GFP_KERNEL)))
276 return -ENOMEM;
277 *ppad = &pad->base;
278
279 nvkm_i2c_pad_ctor(&anx9805_pad_func, bus->pad->i2c, id, &pad->base);
280 pad->bus = bus;
281 pad->addr = addr;
282 return 0;
283 }
284