1/*	$NetBSD: nouveau_nvkm_subdev_i2c_base.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
25 */
26#include <sys/cdefs.h>
27__KERNEL_RCSID(0, "$NetBSD: nouveau_nvkm_subdev_i2c_base.c,v 1.3 2021/12/18 23:45:40 riastradh Exp $");
28
29#include "priv.h"
30#include "aux.h"
31#include "bus.h"
32#include "pad.h"
33
34#include <core/notify.h>
35#include <core/option.h>
36#include <subdev/bios.h>
37#include <subdev/bios/dcb.h>
38#include <subdev/bios/i2c.h>
39
40static struct nvkm_i2c_pad *
41nvkm_i2c_pad_find(struct nvkm_i2c *i2c, int id)
42{
43	struct nvkm_i2c_pad *pad;
44
45	list_for_each_entry(pad, &i2c->pad, head) {
46		if (pad->id == id)
47			return pad;
48	}
49
50	return NULL;
51}
52
53struct nvkm_i2c_bus *
54nvkm_i2c_bus_find(struct nvkm_i2c *i2c, int id)
55{
56	struct nvkm_bios *bios = i2c->subdev.device->bios;
57	struct nvkm_i2c_bus *bus;
58
59	if (id == NVKM_I2C_BUS_PRI || id == NVKM_I2C_BUS_SEC) {
60		u8  ver, hdr, cnt, len;
61		u16 i2c = dcb_i2c_table(bios, &ver, &hdr, &cnt, &len);
62		if (i2c && ver >= 0x30) {
63			u8 auxidx = nvbios_rd08(bios, i2c + 4);
64			if (id == NVKM_I2C_BUS_PRI)
65				id = NVKM_I2C_BUS_CCB((auxidx & 0x0f) >> 0);
66			else
67				id = NVKM_I2C_BUS_CCB((auxidx & 0xf0) >> 4);
68		} else {
69			id = NVKM_I2C_BUS_CCB(2);
70		}
71	}
72
73	list_for_each_entry(bus, &i2c->bus, head) {
74		if (bus->id == id)
75			return bus;
76	}
77
78	return NULL;
79}
80
81struct nvkm_i2c_aux *
82nvkm_i2c_aux_find(struct nvkm_i2c *i2c, int id)
83{
84	struct nvkm_i2c_aux *aux;
85
86	list_for_each_entry(aux, &i2c->aux, head) {
87		if (aux->id == id)
88			return aux;
89	}
90
91	return NULL;
92}
93
94static void
95nvkm_i2c_intr_fini(struct nvkm_event *event, int type, int id)
96{
97	struct nvkm_i2c *i2c = container_of(event, typeof(*i2c), event);
98	struct nvkm_i2c_aux *aux = nvkm_i2c_aux_find(i2c, id);
99	if (aux)
100		i2c->func->aux_mask(i2c, type, aux->intr, 0);
101}
102
103static void
104nvkm_i2c_intr_init(struct nvkm_event *event, int type, int id)
105{
106	struct nvkm_i2c *i2c = container_of(event, typeof(*i2c), event);
107	struct nvkm_i2c_aux *aux = nvkm_i2c_aux_find(i2c, id);
108	if (aux)
109		i2c->func->aux_mask(i2c, type, aux->intr, aux->intr);
110}
111
112static int
113nvkm_i2c_intr_ctor(struct nvkm_object *object, void *data, u32 size,
114		   struct nvkm_notify *notify)
115{
116	struct nvkm_i2c_ntfy_req *req = data;
117	if (!WARN_ON(size != sizeof(*req))) {
118		notify->size  = sizeof(struct nvkm_i2c_ntfy_rep);
119		notify->types = req->mask;
120		notify->index = req->port;
121		return 0;
122	}
123	return -EINVAL;
124}
125
126static const struct nvkm_event_func
127nvkm_i2c_intr_func = {
128	.ctor = nvkm_i2c_intr_ctor,
129	.init = nvkm_i2c_intr_init,
130	.fini = nvkm_i2c_intr_fini,
131};
132
133static void
134nvkm_i2c_intr(struct nvkm_subdev *subdev)
135{
136	struct nvkm_i2c *i2c = nvkm_i2c(subdev);
137	struct nvkm_i2c_aux *aux;
138	u32 hi, lo, rq, tx;
139
140	if (!i2c->func->aux_stat)
141		return;
142
143	i2c->func->aux_stat(i2c, &hi, &lo, &rq, &tx);
144	if (!hi && !lo && !rq && !tx)
145		return;
146
147	list_for_each_entry(aux, &i2c->aux, head) {
148		u32 mask = 0;
149		if (hi & aux->intr) mask |= NVKM_I2C_PLUG;
150		if (lo & aux->intr) mask |= NVKM_I2C_UNPLUG;
151		if (rq & aux->intr) mask |= NVKM_I2C_IRQ;
152		if (tx & aux->intr) mask |= NVKM_I2C_DONE;
153		if (mask) {
154			struct nvkm_i2c_ntfy_rep rep = {
155				.mask = mask,
156			};
157			nvkm_event_send(&i2c->event, rep.mask, aux->id,
158					&rep, sizeof(rep));
159		}
160	}
161}
162
163static int
164nvkm_i2c_fini(struct nvkm_subdev *subdev, bool suspend)
165{
166	struct nvkm_i2c *i2c = nvkm_i2c(subdev);
167	struct nvkm_i2c_pad *pad;
168	struct nvkm_i2c_bus *bus;
169	struct nvkm_i2c_aux *aux;
170	u32 mask;
171
172	list_for_each_entry(aux, &i2c->aux, head) {
173		nvkm_i2c_aux_fini(aux);
174	}
175
176	list_for_each_entry(bus, &i2c->bus, head) {
177		nvkm_i2c_bus_fini(bus);
178	}
179
180	if ((mask = (1 << i2c->func->aux) - 1), i2c->func->aux_stat) {
181		i2c->func->aux_mask(i2c, NVKM_I2C_ANY, mask, 0);
182		i2c->func->aux_stat(i2c, &mask, &mask, &mask, &mask);
183	}
184
185	list_for_each_entry(pad, &i2c->pad, head) {
186		nvkm_i2c_pad_fini(pad);
187	}
188
189	return 0;
190}
191
192static int
193nvkm_i2c_preinit(struct nvkm_subdev *subdev)
194{
195	struct nvkm_i2c *i2c = nvkm_i2c(subdev);
196	struct nvkm_i2c_bus *bus;
197	struct nvkm_i2c_pad *pad;
198
199	/*
200	 * We init our i2c busses as early as possible, since they may be
201	 * needed by the vbios init scripts on some cards
202	 */
203	list_for_each_entry(pad, &i2c->pad, head)
204		nvkm_i2c_pad_init(pad);
205	list_for_each_entry(bus, &i2c->bus, head)
206		nvkm_i2c_bus_init(bus);
207
208	return 0;
209}
210
211static int
212nvkm_i2c_init(struct nvkm_subdev *subdev)
213{
214	struct nvkm_i2c *i2c = nvkm_i2c(subdev);
215	struct nvkm_i2c_bus *bus;
216	struct nvkm_i2c_pad *pad;
217	struct nvkm_i2c_aux *aux;
218
219	list_for_each_entry(pad, &i2c->pad, head) {
220		nvkm_i2c_pad_init(pad);
221	}
222
223	list_for_each_entry(bus, &i2c->bus, head) {
224		nvkm_i2c_bus_init(bus);
225	}
226
227	list_for_each_entry(aux, &i2c->aux, head) {
228		nvkm_i2c_aux_init(aux);
229	}
230
231	return 0;
232}
233
234static void *
235nvkm_i2c_dtor(struct nvkm_subdev *subdev)
236{
237	struct nvkm_i2c *i2c = nvkm_i2c(subdev);
238
239	nvkm_event_fini(&i2c->event);
240
241	while (!list_empty(&i2c->aux)) {
242		struct nvkm_i2c_aux *aux =
243			list_first_entry(&i2c->aux, typeof(*aux), head);
244		nvkm_i2c_aux_del(&aux);
245	}
246
247	while (!list_empty(&i2c->bus)) {
248		struct nvkm_i2c_bus *bus =
249			list_first_entry(&i2c->bus, typeof(*bus), head);
250		nvkm_i2c_bus_del(&bus);
251	}
252
253	while (!list_empty(&i2c->pad)) {
254		struct nvkm_i2c_pad *pad =
255			list_first_entry(&i2c->pad, typeof(*pad), head);
256		nvkm_i2c_pad_del(&pad);
257	}
258
259	return i2c;
260}
261
262static const struct nvkm_subdev_func
263nvkm_i2c = {
264	.dtor = nvkm_i2c_dtor,
265	.preinit = nvkm_i2c_preinit,
266	.init = nvkm_i2c_init,
267	.fini = nvkm_i2c_fini,
268	.intr = nvkm_i2c_intr,
269};
270
271static const struct nvkm_i2c_drv {
272	u8 bios;
273	u8 addr;
274	int (*pad_new)(struct nvkm_i2c_bus *, int id, u8 addr,
275		       struct nvkm_i2c_pad **);
276}
277nvkm_i2c_drv[] = {
278	{ 0x0d, 0x39, anx9805_pad_new },
279	{ 0x0e, 0x3b, anx9805_pad_new },
280	{}
281};
282
283int
284nvkm_i2c_new_(const struct nvkm_i2c_func *func, struct nvkm_device *device,
285	      int index, struct nvkm_i2c **pi2c)
286{
287	struct nvkm_bios *bios = device->bios;
288	struct nvkm_i2c *i2c;
289	struct dcb_i2c_entry ccbE;
290	struct dcb_output dcbE;
291	u8 ver, hdr;
292	int ret, i;
293
294	if (!(i2c = *pi2c = kzalloc(sizeof(*i2c), GFP_KERNEL)))
295		return -ENOMEM;
296
297	nvkm_subdev_ctor(&nvkm_i2c, device, index, &i2c->subdev);
298	i2c->func = func;
299	INIT_LIST_HEAD(&i2c->pad);
300	INIT_LIST_HEAD(&i2c->bus);
301	INIT_LIST_HEAD(&i2c->aux);
302
303	i = -1;
304	while (!dcb_i2c_parse(bios, ++i, &ccbE)) {
305		struct nvkm_i2c_pad *pad = NULL;
306		struct nvkm_i2c_bus *bus = NULL;
307		struct nvkm_i2c_aux *aux = NULL;
308
309		nvkm_debug(&i2c->subdev, "ccb %02x: type %02x drive %02x "
310			   "sense %02x share %02x auxch %02x\n", i, ccbE.type,
311			   ccbE.drive, ccbE.sense, ccbE.share, ccbE.auxch);
312
313		if (ccbE.share != DCB_I2C_UNUSED) {
314			const int id = NVKM_I2C_PAD_HYBRID(ccbE.share);
315			if (!(pad = nvkm_i2c_pad_find(i2c, id)))
316				ret = func->pad_s_new(i2c, id, &pad);
317			else
318				ret = 0;
319		} else {
320			ret = func->pad_x_new(i2c, NVKM_I2C_PAD_CCB(i), &pad);
321		}
322
323		if (ret) {
324			nvkm_error(&i2c->subdev, "ccb %02x pad, %d\n", i, ret);
325			nvkm_i2c_pad_del(&pad);
326			continue;
327		}
328
329		if (pad->func->bus_new_0 && ccbE.type == DCB_I2C_NV04_BIT) {
330			ret = pad->func->bus_new_0(pad, NVKM_I2C_BUS_CCB(i),
331						   ccbE.drive,
332						   ccbE.sense, &bus);
333		} else
334		if (pad->func->bus_new_4 &&
335		    ( ccbE.type == DCB_I2C_NV4E_BIT ||
336		      ccbE.type == DCB_I2C_NVIO_BIT ||
337		     (ccbE.type == DCB_I2C_PMGR &&
338		      ccbE.drive != DCB_I2C_UNUSED))) {
339			ret = pad->func->bus_new_4(pad, NVKM_I2C_BUS_CCB(i),
340						   ccbE.drive, &bus);
341		}
342
343		if (ret) {
344			nvkm_error(&i2c->subdev, "ccb %02x bus, %d\n", i, ret);
345			nvkm_i2c_bus_del(&bus);
346		}
347
348		if (pad->func->aux_new_6 &&
349		    ( ccbE.type == DCB_I2C_NVIO_AUX ||
350		     (ccbE.type == DCB_I2C_PMGR &&
351		      ccbE.auxch != DCB_I2C_UNUSED))) {
352			ret = pad->func->aux_new_6(pad, NVKM_I2C_BUS_CCB(i),
353						   ccbE.auxch, &aux);
354		} else {
355			ret = 0;
356		}
357
358		if (ret) {
359			nvkm_error(&i2c->subdev, "ccb %02x aux, %d\n", i, ret);
360			nvkm_i2c_aux_del(&aux);
361		}
362
363		if (ccbE.type != DCB_I2C_UNUSED && !bus && !aux) {
364			nvkm_warn(&i2c->subdev, "ccb %02x was ignored\n", i);
365			continue;
366		}
367	}
368
369	i = -1;
370	while (dcb_outp_parse(bios, ++i, &ver, &hdr, &dcbE)) {
371		const struct nvkm_i2c_drv *drv = nvkm_i2c_drv;
372		struct nvkm_i2c_bus *bus;
373		struct nvkm_i2c_pad *pad;
374
375		/* internal outputs handled by native i2c busses (above) */
376		if (!dcbE.location)
377			continue;
378
379		/* we need an i2c bus to talk to the external encoder */
380		bus = nvkm_i2c_bus_find(i2c, dcbE.i2c_index);
381		if (!bus) {
382			nvkm_debug(&i2c->subdev, "dcb %02x no bus\n", i);
383			continue;
384		}
385
386		/* ... and a driver for it */
387		while (drv->pad_new) {
388			if (drv->bios == dcbE.extdev)
389				break;
390			drv++;
391		}
392
393		if (!drv->pad_new) {
394			nvkm_debug(&i2c->subdev, "dcb %02x drv %02x unknown\n",
395				   i, dcbE.extdev);
396			continue;
397		}
398
399		/* find/create an instance of the driver */
400		pad = nvkm_i2c_pad_find(i2c, NVKM_I2C_PAD_EXT(dcbE.extdev));
401		if (!pad) {
402			const int id = NVKM_I2C_PAD_EXT(dcbE.extdev);
403			ret = drv->pad_new(bus, id, drv->addr, &pad);
404			if (ret) {
405				nvkm_error(&i2c->subdev, "dcb %02x pad, %d\n",
406					   i, ret);
407				nvkm_i2c_pad_del(&pad);
408				continue;
409			}
410		}
411
412		/* create any i2c bus / aux channel required by the output */
413		if (pad->func->aux_new_6 && dcbE.type == DCB_OUTPUT_DP) {
414			const int id = NVKM_I2C_AUX_EXT(dcbE.extdev);
415			struct nvkm_i2c_aux *aux = NULL;
416			ret = pad->func->aux_new_6(pad, id, 0, &aux);
417			if (ret) {
418				nvkm_error(&i2c->subdev, "dcb %02x aux, %d\n",
419					   i, ret);
420				nvkm_i2c_aux_del(&aux);
421			}
422		} else
423		if (pad->func->bus_new_4) {
424			const int id = NVKM_I2C_BUS_EXT(dcbE.extdev);
425			struct nvkm_i2c_bus *bus = NULL;
426			ret = pad->func->bus_new_4(pad, id, 0, &bus);
427			if (ret) {
428				nvkm_error(&i2c->subdev, "dcb %02x bus, %d\n",
429					   i, ret);
430				nvkm_i2c_bus_del(&bus);
431			}
432		}
433	}
434
435	return nvkm_event_init(&nvkm_i2c_intr_func, 4, i, &i2c->event);
436}
437