xref: /openbmc/linux/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c (revision fdebffeba8b877368ddcc139c26278c1c97931a4)
1c39f472eSBen Skeggs /*
2c39f472eSBen Skeggs  * Copyright 2013 Red Hat Inc.
3c39f472eSBen Skeggs  *
4c39f472eSBen Skeggs  * Permission is hereby granted, free of charge, to any person obtaining a
5c39f472eSBen Skeggs  * copy of this software and associated documentation files (the "Software"),
6c39f472eSBen Skeggs  * to deal in the Software without restriction, including without limitation
7c39f472eSBen Skeggs  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8c39f472eSBen Skeggs  * and/or sell copies of the Software, and to permit persons to whom the
9c39f472eSBen Skeggs  * Software is furnished to do so, subject to the following conditions:
10c39f472eSBen Skeggs  *
11c39f472eSBen Skeggs  * The above copyright notice and this permission notice shall be included in
12c39f472eSBen Skeggs  * all copies or substantial portions of the Software.
13c39f472eSBen Skeggs  *
14c39f472eSBen Skeggs  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15c39f472eSBen Skeggs  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16c39f472eSBen Skeggs  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17c39f472eSBen Skeggs  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18c39f472eSBen Skeggs  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19c39f472eSBen Skeggs  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20c39f472eSBen Skeggs  * OTHER DEALINGS IN THE SOFTWARE.
21c39f472eSBen Skeggs  *
22c39f472eSBen Skeggs  * Authors: Ben Skeggs
23c39f472eSBen Skeggs  */
24c39f472eSBen Skeggs #include "priv.h"
252aa5eac5SBen Skeggs #include "aux.h"
262aa5eac5SBen Skeggs #include "bus.h"
27c39f472eSBen Skeggs #include "pad.h"
28c39f472eSBen Skeggs 
29b9ec1424SBen Skeggs #include <core/option.h>
30b9ec1424SBen Skeggs #include <subdev/bios.h>
31b9ec1424SBen Skeggs #include <subdev/bios/dcb.h>
322aa5eac5SBen Skeggs #include <subdev/bios/i2c.h>
33b9ec1424SBen Skeggs 
342aa5eac5SBen Skeggs static struct nvkm_i2c_pad *
nvkm_i2c_pad_find(struct nvkm_i2c * i2c,int id)352aa5eac5SBen Skeggs nvkm_i2c_pad_find(struct nvkm_i2c *i2c, int id)
36c39f472eSBen Skeggs {
372aa5eac5SBen Skeggs 	struct nvkm_i2c_pad *pad;
382aa5eac5SBen Skeggs 
392aa5eac5SBen Skeggs 	list_for_each_entry(pad, &i2c->pad, head) {
402aa5eac5SBen Skeggs 		if (pad->id == id)
412aa5eac5SBen Skeggs 			return pad;
42c39f472eSBen Skeggs 	}
43c39f472eSBen Skeggs 
442aa5eac5SBen Skeggs 	return NULL;
45c39f472eSBen Skeggs }
46c39f472eSBen Skeggs 
472aa5eac5SBen Skeggs struct nvkm_i2c_bus *
nvkm_i2c_bus_find(struct nvkm_i2c * i2c,int id)482aa5eac5SBen Skeggs nvkm_i2c_bus_find(struct nvkm_i2c *i2c, int id)
49c39f472eSBen Skeggs {
502aa5eac5SBen Skeggs 	struct nvkm_bios *bios = i2c->subdev.device->bios;
512aa5eac5SBen Skeggs 	struct nvkm_i2c_bus *bus;
52c39f472eSBen Skeggs 
532aa5eac5SBen Skeggs 	if (id == NVKM_I2C_BUS_PRI || id == NVKM_I2C_BUS_SEC) {
54c39f472eSBen Skeggs 		u8  ver, hdr, cnt, len;
55c39f472eSBen Skeggs 		u16 i2c = dcb_i2c_table(bios, &ver, &hdr, &cnt, &len);
56c39f472eSBen Skeggs 		if (i2c && ver >= 0x30) {
577f5f518fSBen Skeggs 			u8 auxidx = nvbios_rd08(bios, i2c + 4);
582aa5eac5SBen Skeggs 			if (id == NVKM_I2C_BUS_PRI)
592aa5eac5SBen Skeggs 				id = NVKM_I2C_BUS_CCB((auxidx & 0x0f) >> 0);
60c39f472eSBen Skeggs 			else
612aa5eac5SBen Skeggs 				id = NVKM_I2C_BUS_CCB((auxidx & 0xf0) >> 4);
62c39f472eSBen Skeggs 		} else {
632aa5eac5SBen Skeggs 			id = NVKM_I2C_BUS_CCB(2);
64c39f472eSBen Skeggs 		}
65c39f472eSBen Skeggs 	}
66c39f472eSBen Skeggs 
672aa5eac5SBen Skeggs 	list_for_each_entry(bus, &i2c->bus, head) {
682aa5eac5SBen Skeggs 		if (bus->id == id)
692aa5eac5SBen Skeggs 			return bus;
70c39f472eSBen Skeggs 	}
71c39f472eSBen Skeggs 
72c39f472eSBen Skeggs 	return NULL;
73c39f472eSBen Skeggs }
74c39f472eSBen Skeggs 
752aa5eac5SBen Skeggs struct nvkm_i2c_aux *
nvkm_i2c_aux_find(struct nvkm_i2c * i2c,int id)762aa5eac5SBen Skeggs nvkm_i2c_aux_find(struct nvkm_i2c *i2c, int id)
77c39f472eSBen Skeggs {
782aa5eac5SBen Skeggs 	struct nvkm_i2c_aux *aux;
79c39f472eSBen Skeggs 
802aa5eac5SBen Skeggs 	list_for_each_entry(aux, &i2c->aux, head) {
812aa5eac5SBen Skeggs 		if (aux->id == id)
822aa5eac5SBen Skeggs 			return aux;
83c39f472eSBen Skeggs 	}
84c39f472eSBen Skeggs 
85c39f472eSBen Skeggs 	return NULL;
86c39f472eSBen Skeggs }
87c39f472eSBen Skeggs 
88c39f472eSBen Skeggs static void
nvkm_i2c_intr_fini(struct nvkm_event * event,int type,int id)892aa5eac5SBen Skeggs nvkm_i2c_intr_fini(struct nvkm_event *event, int type, int id)
90c39f472eSBen Skeggs {
91b9ec1424SBen Skeggs 	struct nvkm_i2c *i2c = container_of(event, typeof(*i2c), event);
922aa5eac5SBen Skeggs 	struct nvkm_i2c_aux *aux = nvkm_i2c_aux_find(i2c, id);
932aa5eac5SBen Skeggs 	if (aux)
9449bd8da5SBen Skeggs 		i2c->func->aux_mask(i2c, type, aux->intr, 0);
95c39f472eSBen Skeggs }
96c39f472eSBen Skeggs 
97c39f472eSBen Skeggs static void
nvkm_i2c_intr_init(struct nvkm_event * event,int type,int id)982aa5eac5SBen Skeggs nvkm_i2c_intr_init(struct nvkm_event *event, int type, int id)
99c39f472eSBen Skeggs {
100b9ec1424SBen Skeggs 	struct nvkm_i2c *i2c = container_of(event, typeof(*i2c), event);
1012aa5eac5SBen Skeggs 	struct nvkm_i2c_aux *aux = nvkm_i2c_aux_find(i2c, id);
1022aa5eac5SBen Skeggs 	if (aux)
10349bd8da5SBen Skeggs 		i2c->func->aux_mask(i2c, type, aux->intr, aux->intr);
104c39f472eSBen Skeggs }
105c39f472eSBen Skeggs 
10649bd8da5SBen Skeggs static const struct nvkm_event_func
10749bd8da5SBen Skeggs nvkm_i2c_intr_func = {
10849bd8da5SBen Skeggs 	.init = nvkm_i2c_intr_init,
10949bd8da5SBen Skeggs 	.fini = nvkm_i2c_intr_fini,
11049bd8da5SBen Skeggs };
11149bd8da5SBen Skeggs 
112c39f472eSBen Skeggs static void
nvkm_i2c_intr(struct nvkm_subdev * subdev)11349bd8da5SBen Skeggs nvkm_i2c_intr(struct nvkm_subdev *subdev)
114c39f472eSBen Skeggs {
11549bd8da5SBen Skeggs 	struct nvkm_i2c *i2c = nvkm_i2c(subdev);
1162aa5eac5SBen Skeggs 	struct nvkm_i2c_aux *aux;
1172aa5eac5SBen Skeggs 	u32 hi, lo, rq, tx;
118c39f472eSBen Skeggs 
11949bd8da5SBen Skeggs 	if (!i2c->func->aux_stat)
1202aa5eac5SBen Skeggs 		return;
1212aa5eac5SBen Skeggs 
12249bd8da5SBen Skeggs 	i2c->func->aux_stat(i2c, &hi, &lo, &rq, &tx);
1232aa5eac5SBen Skeggs 	if (!hi && !lo && !rq && !tx)
1242aa5eac5SBen Skeggs 		return;
125c39f472eSBen Skeggs 
1262aa5eac5SBen Skeggs 	list_for_each_entry(aux, &i2c->aux, head) {
1272aa5eac5SBen Skeggs 		u32 mask = 0;
1282aa5eac5SBen Skeggs 		if (hi & aux->intr) mask |= NVKM_I2C_PLUG;
1292aa5eac5SBen Skeggs 		if (lo & aux->intr) mask |= NVKM_I2C_UNPLUG;
1302aa5eac5SBen Skeggs 		if (rq & aux->intr) mask |= NVKM_I2C_IRQ;
1312aa5eac5SBen Skeggs 		if (tx & aux->intr) mask |= NVKM_I2C_DONE;
132773eb04dSBen Skeggs 		if (mask)
13399d0701aSBen Skeggs 			nvkm_event_ntfy(&i2c->event, aux->id, mask);
134c39f472eSBen Skeggs 	}
135c39f472eSBen Skeggs }
136c39f472eSBen Skeggs 
13749bd8da5SBen Skeggs static int
nvkm_i2c_fini(struct nvkm_subdev * subdev,bool suspend)13849bd8da5SBen Skeggs nvkm_i2c_fini(struct nvkm_subdev *subdev, bool suspend)
139c39f472eSBen Skeggs {
14049bd8da5SBen Skeggs 	struct nvkm_i2c *i2c = nvkm_i2c(subdev);
1412aa5eac5SBen Skeggs 	struct nvkm_i2c_pad *pad;
142342406e4SLyude Paul 	struct nvkm_i2c_bus *bus;
143342406e4SLyude Paul 	struct nvkm_i2c_aux *aux;
144c39f472eSBen Skeggs 	u32 mask;
145c39f472eSBen Skeggs 
146342406e4SLyude Paul 	list_for_each_entry(aux, &i2c->aux, head) {
147342406e4SLyude Paul 		nvkm_i2c_aux_fini(aux);
148342406e4SLyude Paul 	}
149342406e4SLyude Paul 
150342406e4SLyude Paul 	list_for_each_entry(bus, &i2c->bus, head) {
151342406e4SLyude Paul 		nvkm_i2c_bus_fini(bus);
152342406e4SLyude Paul 	}
153342406e4SLyude Paul 
15449bd8da5SBen Skeggs 	if ((mask = (1 << i2c->func->aux) - 1), i2c->func->aux_stat) {
15549bd8da5SBen Skeggs 		i2c->func->aux_mask(i2c, NVKM_I2C_ANY, mask, 0);
15649bd8da5SBen Skeggs 		i2c->func->aux_stat(i2c, &mask, &mask, &mask, &mask);
157c39f472eSBen Skeggs 	}
158c39f472eSBen Skeggs 
1592aa5eac5SBen Skeggs 	list_for_each_entry(pad, &i2c->pad, head) {
1602aa5eac5SBen Skeggs 		nvkm_i2c_pad_fini(pad);
161c39f472eSBen Skeggs 	}
162c39f472eSBen Skeggs 
16349bd8da5SBen Skeggs 	return 0;
164c39f472eSBen Skeggs }
165c39f472eSBen Skeggs 
16649bd8da5SBen Skeggs static int
nvkm_i2c_preinit(struct nvkm_subdev * subdev)1677cb95eeeSLyude Paul nvkm_i2c_preinit(struct nvkm_subdev *subdev)
1687cb95eeeSLyude Paul {
1697cb95eeeSLyude Paul 	struct nvkm_i2c *i2c = nvkm_i2c(subdev);
1707cb95eeeSLyude Paul 	struct nvkm_i2c_bus *bus;
1717cb95eeeSLyude Paul 	struct nvkm_i2c_pad *pad;
1727cb95eeeSLyude Paul 
1737cb95eeeSLyude Paul 	/*
1747cb95eeeSLyude Paul 	 * We init our i2c busses as early as possible, since they may be
1757cb95eeeSLyude Paul 	 * needed by the vbios init scripts on some cards
1767cb95eeeSLyude Paul 	 */
1777cb95eeeSLyude Paul 	list_for_each_entry(pad, &i2c->pad, head)
1787cb95eeeSLyude Paul 		nvkm_i2c_pad_init(pad);
1797cb95eeeSLyude Paul 	list_for_each_entry(bus, &i2c->bus, head)
1807cb95eeeSLyude Paul 		nvkm_i2c_bus_init(bus);
1817cb95eeeSLyude Paul 
1827cb95eeeSLyude Paul 	return 0;
1837cb95eeeSLyude Paul }
1847cb95eeeSLyude Paul 
1857cb95eeeSLyude Paul static int
nvkm_i2c_init(struct nvkm_subdev * subdev)18649bd8da5SBen Skeggs nvkm_i2c_init(struct nvkm_subdev *subdev)
187c39f472eSBen Skeggs {
18849bd8da5SBen Skeggs 	struct nvkm_i2c *i2c = nvkm_i2c(subdev);
1892aa5eac5SBen Skeggs 	struct nvkm_i2c_bus *bus;
1902aa5eac5SBen Skeggs 	struct nvkm_i2c_pad *pad;
191342406e4SLyude Paul 	struct nvkm_i2c_aux *aux;
1922aa5eac5SBen Skeggs 
1932aa5eac5SBen Skeggs 	list_for_each_entry(pad, &i2c->pad, head) {
1942aa5eac5SBen Skeggs 		nvkm_i2c_pad_init(pad);
195c39f472eSBen Skeggs 	}
196c39f472eSBen Skeggs 
1972aa5eac5SBen Skeggs 	list_for_each_entry(bus, &i2c->bus, head) {
1982aa5eac5SBen Skeggs 		nvkm_i2c_bus_init(bus);
199c39f472eSBen Skeggs 	}
200c39f472eSBen Skeggs 
201342406e4SLyude Paul 	list_for_each_entry(aux, &i2c->aux, head) {
202342406e4SLyude Paul 		nvkm_i2c_aux_init(aux);
203342406e4SLyude Paul 	}
204342406e4SLyude Paul 
2052aa5eac5SBen Skeggs 	return 0;
206c39f472eSBen Skeggs }
207c39f472eSBen Skeggs 
20849bd8da5SBen Skeggs static void *
nvkm_i2c_dtor(struct nvkm_subdev * subdev)20949bd8da5SBen Skeggs nvkm_i2c_dtor(struct nvkm_subdev *subdev)
210c39f472eSBen Skeggs {
21149bd8da5SBen Skeggs 	struct nvkm_i2c *i2c = nvkm_i2c(subdev);
212c39f472eSBen Skeggs 
213c39f472eSBen Skeggs 	nvkm_event_fini(&i2c->event);
214c39f472eSBen Skeggs 
2152aa5eac5SBen Skeggs 	while (!list_empty(&i2c->aux)) {
2162aa5eac5SBen Skeggs 		struct nvkm_i2c_aux *aux =
2172aa5eac5SBen Skeggs 			list_first_entry(&i2c->aux, typeof(*aux), head);
2182aa5eac5SBen Skeggs 		nvkm_i2c_aux_del(&aux);
2192aa5eac5SBen Skeggs 	}
2202aa5eac5SBen Skeggs 
2212aa5eac5SBen Skeggs 	while (!list_empty(&i2c->bus)) {
2222aa5eac5SBen Skeggs 		struct nvkm_i2c_bus *bus =
2232aa5eac5SBen Skeggs 			list_first_entry(&i2c->bus, typeof(*bus), head);
2242aa5eac5SBen Skeggs 		nvkm_i2c_bus_del(&bus);
2252aa5eac5SBen Skeggs 	}
2262aa5eac5SBen Skeggs 
2272aa5eac5SBen Skeggs 	while (!list_empty(&i2c->pad)) {
2282aa5eac5SBen Skeggs 		struct nvkm_i2c_pad *pad =
2292aa5eac5SBen Skeggs 			list_first_entry(&i2c->pad, typeof(*pad), head);
2302aa5eac5SBen Skeggs 		nvkm_i2c_pad_del(&pad);
231c39f472eSBen Skeggs 	}
232c39f472eSBen Skeggs 
23349bd8da5SBen Skeggs 	return i2c;
234c39f472eSBen Skeggs }
235c39f472eSBen Skeggs 
23649bd8da5SBen Skeggs static const struct nvkm_subdev_func
23749bd8da5SBen Skeggs nvkm_i2c = {
23849bd8da5SBen Skeggs 	.dtor = nvkm_i2c_dtor,
2397cb95eeeSLyude Paul 	.preinit = nvkm_i2c_preinit,
24049bd8da5SBen Skeggs 	.init = nvkm_i2c_init,
24149bd8da5SBen Skeggs 	.fini = nvkm_i2c_fini,
24249bd8da5SBen Skeggs 	.intr = nvkm_i2c_intr,
24349bd8da5SBen Skeggs };
24449bd8da5SBen Skeggs 
2452aa5eac5SBen Skeggs static const struct nvkm_i2c_drv {
2462aa5eac5SBen Skeggs 	u8 bios;
2472aa5eac5SBen Skeggs 	u8 addr;
2482aa5eac5SBen Skeggs 	int (*pad_new)(struct nvkm_i2c_bus *, int id, u8 addr,
2492aa5eac5SBen Skeggs 		       struct nvkm_i2c_pad **);
2502aa5eac5SBen Skeggs }
2512aa5eac5SBen Skeggs nvkm_i2c_drv[] = {
2522aa5eac5SBen Skeggs 	{ 0x0d, 0x39, anx9805_pad_new },
2532aa5eac5SBen Skeggs 	{ 0x0e, 0x3b, anx9805_pad_new },
2542aa5eac5SBen Skeggs 	{}
255c39f472eSBen Skeggs };
256c39f472eSBen Skeggs 
257c39f472eSBen Skeggs int
nvkm_i2c_new_(const struct nvkm_i2c_func * func,struct nvkm_device * device,enum nvkm_subdev_type type,int inst,struct nvkm_i2c ** pi2c)25849bd8da5SBen Skeggs nvkm_i2c_new_(const struct nvkm_i2c_func *func, struct nvkm_device *device,
259c6ce0861SBen Skeggs 	      enum nvkm_subdev_type type, int inst, struct nvkm_i2c **pi2c)
260c39f472eSBen Skeggs {
2612aa5eac5SBen Skeggs 	struct nvkm_bios *bios = device->bios;
262b9ec1424SBen Skeggs 	struct nvkm_i2c *i2c;
263*752a2810SBen Skeggs 	struct nvkm_i2c_aux *aux;
2642aa5eac5SBen Skeggs 	struct dcb_i2c_entry ccbE;
2652aa5eac5SBen Skeggs 	struct dcb_output dcbE;
266c39f472eSBen Skeggs 	u8 ver, hdr;
267*752a2810SBen Skeggs 	int ret, i, ids;
268c39f472eSBen Skeggs 
26949bd8da5SBen Skeggs 	if (!(i2c = *pi2c = kzalloc(sizeof(*i2c), GFP_KERNEL)))
27049bd8da5SBen Skeggs 		return -ENOMEM;
271c39f472eSBen Skeggs 
272c6ce0861SBen Skeggs 	nvkm_subdev_ctor(&nvkm_i2c, device, type, inst, &i2c->subdev);
27349bd8da5SBen Skeggs 	i2c->func = func;
2742aa5eac5SBen Skeggs 	INIT_LIST_HEAD(&i2c->pad);
2752aa5eac5SBen Skeggs 	INIT_LIST_HEAD(&i2c->bus);
2762aa5eac5SBen Skeggs 	INIT_LIST_HEAD(&i2c->aux);
2772aa5eac5SBen Skeggs 
278c39f472eSBen Skeggs 	i = -1;
2792aa5eac5SBen Skeggs 	while (!dcb_i2c_parse(bios, ++i, &ccbE)) {
2802aa5eac5SBen Skeggs 		struct nvkm_i2c_pad *pad = NULL;
2812aa5eac5SBen Skeggs 		struct nvkm_i2c_bus *bus = NULL;
2822aa5eac5SBen Skeggs 		struct nvkm_i2c_aux *aux = NULL;
2832aa5eac5SBen Skeggs 
2842aa5eac5SBen Skeggs 		nvkm_debug(&i2c->subdev, "ccb %02x: type %02x drive %02x "
2852aa5eac5SBen Skeggs 			   "sense %02x share %02x auxch %02x\n", i, ccbE.type,
2862aa5eac5SBen Skeggs 			   ccbE.drive, ccbE.sense, ccbE.share, ccbE.auxch);
2872aa5eac5SBen Skeggs 
2882aa5eac5SBen Skeggs 		if (ccbE.share != DCB_I2C_UNUSED) {
2892aa5eac5SBen Skeggs 			const int id = NVKM_I2C_PAD_HYBRID(ccbE.share);
2902aa5eac5SBen Skeggs 			if (!(pad = nvkm_i2c_pad_find(i2c, id)))
29149bd8da5SBen Skeggs 				ret = func->pad_s_new(i2c, id, &pad);
2922aa5eac5SBen Skeggs 			else
2932aa5eac5SBen Skeggs 				ret = 0;
2942aa5eac5SBen Skeggs 		} else {
29549bd8da5SBen Skeggs 			ret = func->pad_x_new(i2c, NVKM_I2C_PAD_CCB(i), &pad);
2962aa5eac5SBen Skeggs 		}
2972aa5eac5SBen Skeggs 
2982aa5eac5SBen Skeggs 		if (ret) {
2992aa5eac5SBen Skeggs 			nvkm_error(&i2c->subdev, "ccb %02x pad, %d\n", i, ret);
3002aa5eac5SBen Skeggs 			nvkm_i2c_pad_del(&pad);
3012aa5eac5SBen Skeggs 			continue;
3022aa5eac5SBen Skeggs 		}
3032aa5eac5SBen Skeggs 
3042aa5eac5SBen Skeggs 		if (pad->func->bus_new_0 && ccbE.type == DCB_I2C_NV04_BIT) {
3052aa5eac5SBen Skeggs 			ret = pad->func->bus_new_0(pad, NVKM_I2C_BUS_CCB(i),
3062aa5eac5SBen Skeggs 						   ccbE.drive,
3072aa5eac5SBen Skeggs 						   ccbE.sense, &bus);
3082aa5eac5SBen Skeggs 		} else
3092aa5eac5SBen Skeggs 		if (pad->func->bus_new_4 &&
3102aa5eac5SBen Skeggs 		    ( ccbE.type == DCB_I2C_NV4E_BIT ||
3112aa5eac5SBen Skeggs 		      ccbE.type == DCB_I2C_NVIO_BIT ||
3122aa5eac5SBen Skeggs 		     (ccbE.type == DCB_I2C_PMGR &&
3132aa5eac5SBen Skeggs 		      ccbE.drive != DCB_I2C_UNUSED))) {
3142aa5eac5SBen Skeggs 			ret = pad->func->bus_new_4(pad, NVKM_I2C_BUS_CCB(i),
3152aa5eac5SBen Skeggs 						   ccbE.drive, &bus);
3162aa5eac5SBen Skeggs 		}
3172aa5eac5SBen Skeggs 
3182aa5eac5SBen Skeggs 		if (ret) {
3192aa5eac5SBen Skeggs 			nvkm_error(&i2c->subdev, "ccb %02x bus, %d\n", i, ret);
3202aa5eac5SBen Skeggs 			nvkm_i2c_bus_del(&bus);
3212aa5eac5SBen Skeggs 		}
3222aa5eac5SBen Skeggs 
3232aa5eac5SBen Skeggs 		if (pad->func->aux_new_6 &&
3242aa5eac5SBen Skeggs 		    ( ccbE.type == DCB_I2C_NVIO_AUX ||
3252aa5eac5SBen Skeggs 		     (ccbE.type == DCB_I2C_PMGR &&
3262aa5eac5SBen Skeggs 		      ccbE.auxch != DCB_I2C_UNUSED))) {
3272aa5eac5SBen Skeggs 			ret = pad->func->aux_new_6(pad, NVKM_I2C_BUS_CCB(i),
3282aa5eac5SBen Skeggs 						   ccbE.auxch, &aux);
3292aa5eac5SBen Skeggs 		} else {
3302aa5eac5SBen Skeggs 			ret = 0;
3312aa5eac5SBen Skeggs 		}
3322aa5eac5SBen Skeggs 
3332aa5eac5SBen Skeggs 		if (ret) {
3342aa5eac5SBen Skeggs 			nvkm_error(&i2c->subdev, "ccb %02x aux, %d\n", i, ret);
3352aa5eac5SBen Skeggs 			nvkm_i2c_aux_del(&aux);
3362aa5eac5SBen Skeggs 		}
3372aa5eac5SBen Skeggs 
3382aa5eac5SBen Skeggs 		if (ccbE.type != DCB_I2C_UNUSED && !bus && !aux) {
3392aa5eac5SBen Skeggs 			nvkm_warn(&i2c->subdev, "ccb %02x was ignored\n", i);
3402aa5eac5SBen Skeggs 			continue;
3412aa5eac5SBen Skeggs 		}
3422aa5eac5SBen Skeggs 	}
3432aa5eac5SBen Skeggs 
3442aa5eac5SBen Skeggs 	i = -1;
3452aa5eac5SBen Skeggs 	while (dcb_outp_parse(bios, ++i, &ver, &hdr, &dcbE)) {
3462aa5eac5SBen Skeggs 		const struct nvkm_i2c_drv *drv = nvkm_i2c_drv;
3472aa5eac5SBen Skeggs 		struct nvkm_i2c_bus *bus;
3482aa5eac5SBen Skeggs 		struct nvkm_i2c_pad *pad;
3492aa5eac5SBen Skeggs 
3502aa5eac5SBen Skeggs 		/* internal outputs handled by native i2c busses (above) */
3512aa5eac5SBen Skeggs 		if (!dcbE.location)
352c39f472eSBen Skeggs 			continue;
353c39f472eSBen Skeggs 
3542aa5eac5SBen Skeggs 		/* we need an i2c bus to talk to the external encoder */
3552aa5eac5SBen Skeggs 		bus = nvkm_i2c_bus_find(i2c, dcbE.i2c_index);
3562aa5eac5SBen Skeggs 		if (!bus) {
3572aa5eac5SBen Skeggs 			nvkm_debug(&i2c->subdev, "dcb %02x no bus\n", i);
3582aa5eac5SBen Skeggs 			continue;
3592aa5eac5SBen Skeggs 		}
3602aa5eac5SBen Skeggs 
3612aa5eac5SBen Skeggs 		/* ... and a driver for it */
3622aa5eac5SBen Skeggs 		while (drv->pad_new) {
3632aa5eac5SBen Skeggs 			if (drv->bios == dcbE.extdev)
364c39f472eSBen Skeggs 				break;
3652aa5eac5SBen Skeggs 			drv++;
3662aa5eac5SBen Skeggs 		}
3672aa5eac5SBen Skeggs 
3682aa5eac5SBen Skeggs 		if (!drv->pad_new) {
3692aa5eac5SBen Skeggs 			nvkm_debug(&i2c->subdev, "dcb %02x drv %02x unknown\n",
3702aa5eac5SBen Skeggs 				   i, dcbE.extdev);
371c39f472eSBen Skeggs 			continue;
372c39f472eSBen Skeggs 		}
373c39f472eSBen Skeggs 
3742aa5eac5SBen Skeggs 		/* find/create an instance of the driver */
3752aa5eac5SBen Skeggs 		pad = nvkm_i2c_pad_find(i2c, NVKM_I2C_PAD_EXT(dcbE.extdev));
3762aa5eac5SBen Skeggs 		if (!pad) {
3772aa5eac5SBen Skeggs 			const int id = NVKM_I2C_PAD_EXT(dcbE.extdev);
3782aa5eac5SBen Skeggs 			ret = drv->pad_new(bus, id, drv->addr, &pad);
3792aa5eac5SBen Skeggs 			if (ret) {
3802aa5eac5SBen Skeggs 				nvkm_error(&i2c->subdev, "dcb %02x pad, %d\n",
3812aa5eac5SBen Skeggs 					   i, ret);
3822aa5eac5SBen Skeggs 				nvkm_i2c_pad_del(&pad);
383c39f472eSBen Skeggs 				continue;
384c39f472eSBen Skeggs 			}
385c39f472eSBen Skeggs 		}
386c39f472eSBen Skeggs 
3872aa5eac5SBen Skeggs 		/* create any i2c bus / aux channel required by the output */
3882aa5eac5SBen Skeggs 		if (pad->func->aux_new_6 && dcbE.type == DCB_OUTPUT_DP) {
3892aa5eac5SBen Skeggs 			const int id = NVKM_I2C_AUX_EXT(dcbE.extdev);
3902aa5eac5SBen Skeggs 			struct nvkm_i2c_aux *aux = NULL;
3912aa5eac5SBen Skeggs 			ret = pad->func->aux_new_6(pad, id, 0, &aux);
3922aa5eac5SBen Skeggs 			if (ret) {
3932aa5eac5SBen Skeggs 				nvkm_error(&i2c->subdev, "dcb %02x aux, %d\n",
3942aa5eac5SBen Skeggs 					   i, ret);
3952aa5eac5SBen Skeggs 				nvkm_i2c_aux_del(&aux);
3962aa5eac5SBen Skeggs 			}
3972aa5eac5SBen Skeggs 		} else
3982aa5eac5SBen Skeggs 		if (pad->func->bus_new_4) {
3992aa5eac5SBen Skeggs 			const int id = NVKM_I2C_BUS_EXT(dcbE.extdev);
4002aa5eac5SBen Skeggs 			struct nvkm_i2c_bus *bus = NULL;
4012aa5eac5SBen Skeggs 			ret = pad->func->bus_new_4(pad, id, 0, &bus);
4022aa5eac5SBen Skeggs 			if (ret) {
4032aa5eac5SBen Skeggs 				nvkm_error(&i2c->subdev, "dcb %02x bus, %d\n",
4042aa5eac5SBen Skeggs 					   i, ret);
4052aa5eac5SBen Skeggs 				nvkm_i2c_bus_del(&bus);
4062aa5eac5SBen Skeggs 			}
4072aa5eac5SBen Skeggs 		}
4082aa5eac5SBen Skeggs 	}
4092aa5eac5SBen Skeggs 
410*752a2810SBen Skeggs 	ids = 0;
411*752a2810SBen Skeggs 	list_for_each_entry(aux, &i2c->aux, head)
412*752a2810SBen Skeggs 		ids = max(ids, aux->id + 1);
413*752a2810SBen Skeggs 	if (!ids)
414*752a2810SBen Skeggs 		return 0;
415*752a2810SBen Skeggs 
416*752a2810SBen Skeggs 	return nvkm_event_init(&nvkm_i2c_intr_func, &i2c->subdev, 4, ids, &i2c->event);
417c39f472eSBen Skeggs }
418