2 * Copyright 2013 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.
22 * Authors: Ben Skeggs <bskeggs@redhat.com>
27 struct nvkm_subdev
*subdev
;
37 hwsq_cmd(struct nvkm_hwsq
*hwsq
, int size
, u8 data
[])
39 memcpy(&hwsq
->c
.data
[hwsq
->c
.size
], data
, size
* sizeof(data
[0]));
44 nvkm_hwsq_init(struct nvkm_subdev
*subdev
, struct nvkm_hwsq
**phwsq
)
46 struct nvkm_hwsq
*hwsq
;
48 hwsq
= *phwsq
= kmalloc(sizeof(*hwsq
), GFP_KERNEL
);
50 hwsq
->subdev
= subdev
;
53 memset(hwsq
->c
.data
, 0x7f, sizeof(hwsq
->c
.data
));
57 return hwsq
? 0 : -ENOMEM
;
61 nvkm_hwsq_fini(struct nvkm_hwsq
**phwsq
, bool exec
)
63 struct nvkm_hwsq
*hwsq
= *phwsq
;
66 struct nvkm_subdev
*subdev
= hwsq
->subdev
;
67 struct nvkm_bus
*bus
= subdev
->device
->bus
;
68 hwsq
->c
.size
= (hwsq
->c
.size
+ 4) / 4;
69 if (hwsq
->c
.size
<= bus
->func
->hwsq_size
) {
71 ret
= bus
->func
->hwsq_exec(bus
,
75 nvkm_error(subdev
, "hwsq exec failed: %d\n", ret
);
77 nvkm_error(subdev
, "hwsq ucode too large\n");
81 for (i
= 0; ret
&& i
< hwsq
->c
.size
; i
++)
82 nvkm_error(subdev
, "\t%08x\n", ((u32
*)hwsq
->c
.data
)[i
]);
91 nvkm_hwsq_wr32(struct nvkm_hwsq
*hwsq
, u32 addr
, u32 data
)
93 nvkm_debug(hwsq
->subdev
, "R[%06x] = %08x\n", addr
, data
);
95 if (hwsq
->data
!= data
) {
96 if ((data
& 0xffff0000) != (hwsq
->data
& 0xffff0000)) {
97 hwsq_cmd(hwsq
, 5, (u8
[]){ 0xe2, data
, data
>> 8,
98 data
>> 16, data
>> 24 });
100 hwsq_cmd(hwsq
, 3, (u8
[]){ 0x42, data
, data
>> 8 });
104 if ((addr
& 0xffff0000) != (hwsq
->addr
& 0xffff0000)) {
105 hwsq_cmd(hwsq
, 5, (u8
[]){ 0xe0, addr
, addr
>> 8,
106 addr
>> 16, addr
>> 24 });
108 hwsq_cmd(hwsq
, 3, (u8
[]){ 0x40, addr
, addr
>> 8 });
116 nvkm_hwsq_setf(struct nvkm_hwsq
*hwsq
, u8 flag
, int data
)
118 nvkm_debug(hwsq
->subdev
, " FLAG[%02x] = %d\n", flag
, data
);
124 hwsq_cmd(hwsq
, 1, (u8
[]){ flag
});
128 nvkm_hwsq_wait(struct nvkm_hwsq
*hwsq
, u8 flag
, u8 data
)
130 nvkm_debug(hwsq
->subdev
, " WAIT[%02x] = %d\n", flag
, data
);
131 hwsq_cmd(hwsq
, 3, (u8
[]){ 0x5f, flag
, data
});
135 nvkm_hwsq_wait_vblank(struct nvkm_hwsq
*hwsq
)
137 struct nvkm_subdev
*subdev
= hwsq
->subdev
;
138 struct nvkm_device
*device
= subdev
->device
;
139 u32 heads
, x
, y
, px
= 0;
142 heads
= nvkm_rd32(device
, 0x610050);
143 for (i
= 0; i
< 2; i
++) {
144 /* Heuristic: sync to head with biggest resolution */
145 if (heads
& (2 << (i
<< 3))) {
146 x
= nvkm_rd32(device
, 0x610b40 + (0x540 * i
));
147 y
= (x
& 0xffff0000) >> 16;
157 nvkm_debug(subdev
, "WAIT VBLANK !NO ACTIVE HEAD\n");
161 nvkm_debug(subdev
, "WAIT VBLANK HEAD%d\n", head_sync
);
162 nvkm_hwsq_wait(hwsq
, head_sync
? 0x3 : 0x1, 0x0);
163 nvkm_hwsq_wait(hwsq
, head_sync
? 0x3 : 0x1, 0x1);
167 nvkm_hwsq_nsec(struct nvkm_hwsq
*hwsq
, u32 nsec
)
169 u8 shift
= 0, usec
= nsec
/ 1000;
175 nvkm_debug(hwsq
->subdev
, " DELAY = %d ns\n", nsec
);
176 hwsq_cmd(hwsq
, 1, (u8
[]){ 0x00 | (shift
<< 2) | usec
});