0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024 #include "priv.h"
0025
0026 struct nvkm_hwsq {
0027 struct nvkm_subdev *subdev;
0028 u32 addr;
0029 u32 data;
0030 struct {
0031 u8 data[512];
0032 u16 size;
0033 } c;
0034 };
0035
0036 static void
0037 hwsq_cmd(struct nvkm_hwsq *hwsq, int size, u8 data[])
0038 {
0039 memcpy(&hwsq->c.data[hwsq->c.size], data, size * sizeof(data[0]));
0040 hwsq->c.size += size;
0041 }
0042
0043 int
0044 nvkm_hwsq_init(struct nvkm_subdev *subdev, struct nvkm_hwsq **phwsq)
0045 {
0046 struct nvkm_hwsq *hwsq;
0047
0048 hwsq = *phwsq = kmalloc(sizeof(*hwsq), GFP_KERNEL);
0049 if (hwsq) {
0050 hwsq->subdev = subdev;
0051 hwsq->addr = ~0;
0052 hwsq->data = ~0;
0053 memset(hwsq->c.data, 0x7f, sizeof(hwsq->c.data));
0054 hwsq->c.size = 0;
0055 }
0056
0057 return hwsq ? 0 : -ENOMEM;
0058 }
0059
0060 int
0061 nvkm_hwsq_fini(struct nvkm_hwsq **phwsq, bool exec)
0062 {
0063 struct nvkm_hwsq *hwsq = *phwsq;
0064 int ret = 0, i;
0065 if (hwsq) {
0066 struct nvkm_subdev *subdev = hwsq->subdev;
0067 struct nvkm_bus *bus = subdev->device->bus;
0068 hwsq->c.size = (hwsq->c.size + 4) / 4;
0069 if (hwsq->c.size <= bus->func->hwsq_size) {
0070 if (exec)
0071 ret = bus->func->hwsq_exec(bus,
0072 (u32 *)hwsq->c.data,
0073 hwsq->c.size);
0074 if (ret)
0075 nvkm_error(subdev, "hwsq exec failed: %d\n", ret);
0076 } else {
0077 nvkm_error(subdev, "hwsq ucode too large\n");
0078 ret = -ENOSPC;
0079 }
0080
0081 for (i = 0; ret && i < hwsq->c.size; i++)
0082 nvkm_error(subdev, "\t%08x\n", ((u32 *)hwsq->c.data)[i]);
0083
0084 *phwsq = NULL;
0085 kfree(hwsq);
0086 }
0087 return ret;
0088 }
0089
0090 void
0091 nvkm_hwsq_wr32(struct nvkm_hwsq *hwsq, u32 addr, u32 data)
0092 {
0093 nvkm_debug(hwsq->subdev, "R[%06x] = %08x\n", addr, data);
0094
0095 if (hwsq->data != data) {
0096 if ((data & 0xffff0000) != (hwsq->data & 0xffff0000)) {
0097 hwsq_cmd(hwsq, 5, (u8[]){ 0xe2, data, data >> 8,
0098 data >> 16, data >> 24 });
0099 } else {
0100 hwsq_cmd(hwsq, 3, (u8[]){ 0x42, data, data >> 8 });
0101 }
0102 }
0103
0104 if ((addr & 0xffff0000) != (hwsq->addr & 0xffff0000)) {
0105 hwsq_cmd(hwsq, 5, (u8[]){ 0xe0, addr, addr >> 8,
0106 addr >> 16, addr >> 24 });
0107 } else {
0108 hwsq_cmd(hwsq, 3, (u8[]){ 0x40, addr, addr >> 8 });
0109 }
0110
0111 hwsq->addr = addr;
0112 hwsq->data = data;
0113 }
0114
0115 void
0116 nvkm_hwsq_setf(struct nvkm_hwsq *hwsq, u8 flag, int data)
0117 {
0118 nvkm_debug(hwsq->subdev, " FLAG[%02x] = %d\n", flag, data);
0119 flag += 0x80;
0120 if (data >= 0)
0121 flag += 0x20;
0122 if (data >= 1)
0123 flag += 0x20;
0124 hwsq_cmd(hwsq, 1, (u8[]){ flag });
0125 }
0126
0127 void
0128 nvkm_hwsq_wait(struct nvkm_hwsq *hwsq, u8 flag, u8 data)
0129 {
0130 nvkm_debug(hwsq->subdev, " WAIT[%02x] = %d\n", flag, data);
0131 hwsq_cmd(hwsq, 3, (u8[]){ 0x5f, flag, data });
0132 }
0133
0134 void
0135 nvkm_hwsq_wait_vblank(struct nvkm_hwsq *hwsq)
0136 {
0137 struct nvkm_subdev *subdev = hwsq->subdev;
0138 struct nvkm_device *device = subdev->device;
0139 u32 heads, x, y, px = 0;
0140 int i, head_sync;
0141
0142 heads = nvkm_rd32(device, 0x610050);
0143 for (i = 0; i < 2; i++) {
0144
0145 if (heads & (2 << (i << 3))) {
0146 x = nvkm_rd32(device, 0x610b40 + (0x540 * i));
0147 y = (x & 0xffff0000) >> 16;
0148 x &= 0x0000ffff;
0149 if ((x * y) > px) {
0150 px = (x * y);
0151 head_sync = i;
0152 }
0153 }
0154 }
0155
0156 if (px == 0) {
0157 nvkm_debug(subdev, "WAIT VBLANK !NO ACTIVE HEAD\n");
0158 return;
0159 }
0160
0161 nvkm_debug(subdev, "WAIT VBLANK HEAD%d\n", head_sync);
0162 nvkm_hwsq_wait(hwsq, head_sync ? 0x3 : 0x1, 0x0);
0163 nvkm_hwsq_wait(hwsq, head_sync ? 0x3 : 0x1, 0x1);
0164 }
0165
0166 void
0167 nvkm_hwsq_nsec(struct nvkm_hwsq *hwsq, u32 nsec)
0168 {
0169 u8 shift = 0, usec = nsec / 1000;
0170 while (usec & ~3) {
0171 usec >>= 2;
0172 shift++;
0173 }
0174
0175 nvkm_debug(hwsq->subdev, " DELAY = %d ns\n", nsec);
0176 hwsq_cmd(hwsq, 1, (u8[]){ 0x00 | (shift << 2) | usec });
0177 }