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