2 * Copyright 2014 Red Hat Inc.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
25 #include <subdev/i2c.h>
32 nvkm_output_dp_train(struct nvkm_output
*base
, u32 datarate
, bool wait
)
34 struct nvkm_output_dp
*outp
= (void *)base
;
40 /* check that the link is trained at a high enough rate */
41 ret
= nv_rdaux(outp
->base
.edid
, DPCD_LC00_LINK_BW_SET
, link
, 2);
43 DBG("failed to read link config, assuming no sink\n");
47 rate
= link
[0] * 27000 * (link
[1] & DPCD_LC01_LANE_COUNT_SET
);
48 if (rate
< ((datarate
/ 8) * 10)) {
49 DBG("link not trained at sufficient rate\n");
53 /* check that link is still trained */
54 ret
= nv_rdaux(outp
->base
.edid
, DPCD_LS02
, stat
, 3);
56 DBG("failed to read link status, assuming no sink\n");
60 if (stat
[2] & DPCD_LS04_INTERLANE_ALIGN_DONE
) {
61 for (i
= 0; i
< (link
[1] & DPCD_LC01_LANE_COUNT_SET
); i
++) {
62 u8 lane
= (stat
[i
>> 1] >> ((i
& 1) * 4)) & 0x0f;
63 if (!(lane
& DPCD_LS02_LANE0_CR_DONE
) ||
64 !(lane
& DPCD_LS02_LANE0_CHANNEL_EQ_DONE
) ||
65 !(lane
& DPCD_LS02_LANE0_SYMBOL_LOCKED
)) {
66 DBG("lane %d not equalised\n", lane
);
72 DBG("no inter-lane alignment\n");
76 if (retrain
|| !atomic_read(&outp
->lt
.done
)) {
77 /* no sink, but still need to configure source */
78 if (outp
->dpcd
[DPCD_RC00_DPCD_REV
] == 0x00) {
79 outp
->dpcd
[DPCD_RC01_MAX_LINK_RATE
] =
80 outp
->base
.info
.dpconf
.link_bw
;
81 outp
->dpcd
[DPCD_RC02
] =
82 outp
->base
.info
.dpconf
.link_nr
;
84 atomic_set(&outp
->lt
.done
, 0);
85 schedule_work(&outp
->lt
.work
);
87 nouveau_event_get(outp
->irq
);
91 if (!wait_event_timeout(outp
->lt
.wait
,
92 atomic_read(&outp
->lt
.done
),
93 msecs_to_jiffies(2000)))
101 nvkm_output_dp_enable(struct nvkm_output_dp
*outp
, bool present
)
103 struct nouveau_i2c_port
*port
= outp
->base
.edid
;
105 if (!outp
->present
) {
106 nouveau_i2c(port
)->acquire_pad(port
, 0);
107 DBG("aux power -> always\n");
108 outp
->present
= true;
110 nvkm_output_dp_train(&outp
->base
, 0, true);
113 nouveau_i2c(port
)->release_pad(port
);
114 DBG("aux power -> demand\n");
115 outp
->present
= false;
117 atomic_set(&outp
->lt
.done
, 0);
122 nvkm_output_dp_detect(struct nvkm_output_dp
*outp
)
124 struct nouveau_i2c_port
*port
= outp
->base
.edid
;
125 int ret
= nouveau_i2c(port
)->acquire_pad(port
, 0);
127 ret
= nv_rdaux(outp
->base
.edid
, DPCD_RC00_DPCD_REV
,
128 outp
->dpcd
, sizeof(outp
->dpcd
));
129 nvkm_output_dp_enable(outp
, ret
== 0);
130 nouveau_i2c(port
)->release_pad(port
);
135 nvkm_output_dp_service_work(struct work_struct
*work
)
137 struct nvkm_output_dp
*outp
= container_of(work
, typeof(*outp
), work
);
138 struct nouveau_disp
*disp
= nouveau_disp(outp
);
139 int type
= atomic_xchg(&outp
->pending
, 0);
142 if (type
& (NVKM_I2C_PLUG
| NVKM_I2C_UNPLUG
)) {
143 nvkm_output_dp_detect(outp
);
144 if (type
& NVKM_I2C_UNPLUG
)
145 send
|= NVKM_HPD_UNPLUG
;
146 if (type
& NVKM_I2C_PLUG
)
147 send
|= NVKM_HPD_PLUG
;
148 nouveau_event_get(outp
->base
.conn
->hpd
.event
);
151 if (type
& NVKM_I2C_IRQ
) {
152 nvkm_output_dp_train(&outp
->base
, 0, true);
153 send
|= NVKM_HPD_IRQ
;
156 nouveau_event_trigger(disp
->hpd
, send
, outp
->base
.info
.connector
);
160 nvkm_output_dp_service(void *data
, u32 type
, int index
)
162 struct nvkm_output_dp
*outp
= data
;
163 DBG("HPD: %d\n", type
);
164 atomic_or(type
, &outp
->pending
);
165 schedule_work(&outp
->work
);
166 return NVKM_EVENT_DROP
;
170 _nvkm_output_dp_fini(struct nouveau_object
*object
, bool suspend
)
172 struct nvkm_output_dp
*outp
= (void *)object
;
173 nouveau_event_put(outp
->irq
);
174 nvkm_output_dp_enable(outp
, false);
175 return nvkm_output_fini(&outp
->base
, suspend
);
179 _nvkm_output_dp_init(struct nouveau_object
*object
)
181 struct nvkm_output_dp
*outp
= (void *)object
;
182 nvkm_output_dp_detect(outp
);
183 return nvkm_output_init(&outp
->base
);
187 _nvkm_output_dp_dtor(struct nouveau_object
*object
)
189 struct nvkm_output_dp
*outp
= (void *)object
;
190 nouveau_event_ref(NULL
, &outp
->irq
);
191 nvkm_output_destroy(&outp
->base
);
195 nvkm_output_dp_create_(struct nouveau_object
*parent
,
196 struct nouveau_object
*engine
,
197 struct nouveau_oclass
*oclass
,
198 struct dcb_output
*info
, int index
,
199 int length
, void **pobject
)
201 struct nouveau_bios
*bios
= nouveau_bios(parent
);
202 struct nouveau_i2c
*i2c
= nouveau_i2c(parent
);
203 struct nvkm_output_dp
*outp
;
208 ret
= nvkm_output_create_(parent
, engine
, oclass
, info
, index
,
214 nouveau_event_ref(NULL
, &outp
->base
.conn
->hpd
.event
);
216 /* access to the aux channel is not optional... */
217 if (!outp
->base
.edid
) {
218 ERR("aux channel not found\n");
222 /* nor is the bios data for this output... */
223 data
= nvbios_dpout_match(bios
, outp
->base
.info
.hasht
,
224 outp
->base
.info
.hashm
, &outp
->version
,
225 &hdr
, &cnt
, &len
, &outp
->info
);
227 ERR("no bios dp data\n");
231 DBG("bios dp %02x %02x %02x %02x\n", outp
->version
, hdr
, cnt
, len
);
234 INIT_WORK(&outp
->lt
.work
, nouveau_dp_train
);
235 init_waitqueue_head(&outp
->lt
.wait
);
236 atomic_set(&outp
->lt
.done
, 0);
238 /* link maintenance */
239 ret
= nouveau_event_new(i2c
->ntfy
, NVKM_I2C_IRQ
, outp
->base
.edid
->index
,
240 nvkm_output_dp_service
, outp
, &outp
->irq
);
242 ERR("error monitoring aux irq event: %d\n", ret
);
246 INIT_WORK(&outp
->work
, nvkm_output_dp_service_work
);
248 /* hotplug detect, replaces gpio-based mechanism with aux events */
249 ret
= nouveau_event_new(i2c
->ntfy
, NVKM_I2C_PLUG
| NVKM_I2C_UNPLUG
,
250 outp
->base
.edid
->index
,
251 nvkm_output_dp_service
, outp
,
252 &outp
->base
.conn
->hpd
.event
);
254 ERR("error monitoring aux hpd events: %d\n", ret
);
262 _nvkm_output_dp_ctor(struct nouveau_object
*parent
,
263 struct nouveau_object
*engine
,
264 struct nouveau_oclass
*oclass
, void *info
, u32 index
,
265 struct nouveau_object
**pobject
)
267 struct nvkm_output_dp
*outp
;
270 ret
= nvkm_output_dp_create(parent
, engine
, oclass
, info
, index
, &outp
);
271 *pobject
= nv_object(outp
);