]> Pileus Git - ~andy/linux/blob - drivers/gpu/drm/nouveau/core/subdev/pwr/base.c
Merge tag 'drm-intel-fixes-2013-11-07' of git://people.freedesktop.org/~danvet/drm...
[~andy/linux] / drivers / gpu / drm / nouveau / core / subdev / pwr / base.c
1 /*
2  * Copyright 2013 Red Hat Inc.
3  *
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:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
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.
21  *
22  * Authors: Ben Skeggs
23  */
24
25 #include <subdev/pwr.h>
26 #include <subdev/timer.h>
27
28 static int
29 nouveau_pwr_send(struct nouveau_pwr *ppwr, u32 reply[2],
30                  u32 process, u32 message, u32 data0, u32 data1)
31 {
32         struct nouveau_subdev *subdev = nv_subdev(ppwr);
33         u32 addr;
34
35         /* we currently only support a single process at a time waiting
36          * on a synchronous reply, take the PPWR mutex and tell the
37          * receive handler what we're waiting for
38          */
39         if (reply) {
40                 mutex_lock(&subdev->mutex);
41                 ppwr->recv.message = message;
42                 ppwr->recv.process = process;
43         }
44
45         /* wait for a free slot in the fifo */
46         addr  = nv_rd32(ppwr, 0x10a4a0);
47         if (!nv_wait_ne(ppwr, 0x10a4b0, 0xffffffff, addr ^ 8))
48                 return -EBUSY;
49
50         /* acquire data segment access */
51         do {
52                 nv_wr32(ppwr, 0x10a580, 0x00000001);
53         } while (nv_rd32(ppwr, 0x10a580) != 0x00000001);
54
55         /* write the packet */
56         nv_wr32(ppwr, 0x10a1c0, 0x01000000 | (((addr & 0x07) << 4) +
57                                 ppwr->send.base));
58         nv_wr32(ppwr, 0x10a1c4, process);
59         nv_wr32(ppwr, 0x10a1c4, message);
60         nv_wr32(ppwr, 0x10a1c4, data0);
61         nv_wr32(ppwr, 0x10a1c4, data1);
62         nv_wr32(ppwr, 0x10a4a0, (addr + 1) & 0x0f);
63
64         /* release data segment access */
65         nv_wr32(ppwr, 0x10a580, 0x00000000);
66
67         /* wait for reply, if requested */
68         if (reply) {
69                 wait_event(ppwr->recv.wait, (ppwr->recv.process == 0));
70                 reply[0] = ppwr->recv.data[0];
71                 reply[1] = ppwr->recv.data[1];
72                 mutex_unlock(&subdev->mutex);
73         }
74
75         return 0;
76 }
77
78 static void
79 nouveau_pwr_recv(struct work_struct *work)
80 {
81         struct nouveau_pwr *ppwr =
82                 container_of(work, struct nouveau_pwr, recv.work);
83         u32 process, message, data0, data1;
84
85         /* nothing to do if GET == PUT */
86         u32 addr =  nv_rd32(ppwr, 0x10a4cc);
87         if (addr == nv_rd32(ppwr, 0x10a4c8))
88                 return;
89
90         /* acquire data segment access */
91         do {
92                 nv_wr32(ppwr, 0x10a580, 0x00000002);
93         } while (nv_rd32(ppwr, 0x10a580) != 0x00000002);
94
95         /* read the packet */
96         nv_wr32(ppwr, 0x10a1c0, 0x02000000 | (((addr & 0x07) << 4) +
97                                 ppwr->recv.base));
98         process = nv_rd32(ppwr, 0x10a1c4);
99         message = nv_rd32(ppwr, 0x10a1c4);
100         data0   = nv_rd32(ppwr, 0x10a1c4);
101         data1   = nv_rd32(ppwr, 0x10a1c4);
102         nv_wr32(ppwr, 0x10a4cc, (addr + 1) & 0x0f);
103
104         /* release data segment access */
105         nv_wr32(ppwr, 0x10a580, 0x00000000);
106
107         /* wake process if it's waiting on a synchronous reply */
108         if (ppwr->recv.process) {
109                 if (process == ppwr->recv.process &&
110                     message == ppwr->recv.message) {
111                         ppwr->recv.data[0] = data0;
112                         ppwr->recv.data[1] = data1;
113                         ppwr->recv.process = 0;
114                         wake_up(&ppwr->recv.wait);
115                         return;
116                 }
117         }
118
119         /* right now there's no other expected responses from the engine,
120          * so assume that any unexpected message is an error.
121          */
122         nv_warn(ppwr, "%c%c%c%c 0x%08x 0x%08x 0x%08x 0x%08x\n",
123                 (char)((process & 0x000000ff) >>  0),
124                 (char)((process & 0x0000ff00) >>  8),
125                 (char)((process & 0x00ff0000) >> 16),
126                 (char)((process & 0xff000000) >> 24),
127                 process, message, data0, data1);
128 }
129
130 static void
131 nouveau_pwr_intr(struct nouveau_subdev *subdev)
132 {
133         struct nouveau_pwr *ppwr = (void *)subdev;
134         u32 disp = nv_rd32(ppwr, 0x10a01c);
135         u32 intr = nv_rd32(ppwr, 0x10a008) & disp & ~(disp >> 16);
136
137         if (intr & 0x00000020) {
138                 u32 stat = nv_rd32(ppwr, 0x10a16c);
139                 if (stat & 0x80000000) {
140                         nv_error(ppwr, "UAS fault at 0x%06x addr 0x%08x\n",
141                                  stat & 0x00ffffff, nv_rd32(ppwr, 0x10a168));
142                         nv_wr32(ppwr, 0x10a16c, 0x00000000);
143                         intr &= ~0x00000020;
144                 }
145         }
146
147         if (intr & 0x00000040) {
148                 schedule_work(&ppwr->recv.work);
149                 nv_wr32(ppwr, 0x10a004, 0x00000040);
150                 intr &= ~0x00000040;
151         }
152
153         if (intr & 0x00000080) {
154                 nv_info(ppwr, "wr32 0x%06x 0x%08x\n", nv_rd32(ppwr, 0x10a7a0),
155                                                       nv_rd32(ppwr, 0x10a7a4));
156                 nv_wr32(ppwr, 0x10a004, 0x00000080);
157                 intr &= ~0x00000080;
158         }
159
160         if (intr) {
161                 nv_error(ppwr, "intr 0x%08x\n", intr);
162                 nv_wr32(ppwr, 0x10a004, intr);
163         }
164 }
165
166 int
167 _nouveau_pwr_fini(struct nouveau_object *object, bool suspend)
168 {
169         struct nouveau_pwr *ppwr = (void *)object;
170
171         nv_wr32(ppwr, 0x10a014, 0x00000060);
172         flush_work(&ppwr->recv.work);
173
174         return nouveau_subdev_fini(&ppwr->base, suspend);
175 }
176
177 int
178 _nouveau_pwr_init(struct nouveau_object *object)
179 {
180         struct nouveau_pwr *ppwr = (void *)object;
181         int ret, i;
182
183         ret = nouveau_subdev_init(&ppwr->base);
184         if (ret)
185                 return ret;
186
187         nv_subdev(ppwr)->intr = nouveau_pwr_intr;
188         ppwr->message = nouveau_pwr_send;
189
190         /* prevent previous ucode from running, wait for idle, reset */
191         nv_wr32(ppwr, 0x10a014, 0x0000ffff); /* INTR_EN_CLR = ALL */
192         nv_wait(ppwr, 0x10a04c, 0xffffffff, 0x00000000);
193         nv_mask(ppwr, 0x000200, 0x00002000, 0x00000000);
194         nv_mask(ppwr, 0x000200, 0x00002000, 0x00002000);
195
196         /* upload data segment */
197         nv_wr32(ppwr, 0x10a1c0, 0x01000000);
198         for (i = 0; i < ppwr->data.size / 4; i++)
199                 nv_wr32(ppwr, 0x10a1c4, ppwr->data.data[i]);
200
201         /* upload code segment */
202         nv_wr32(ppwr, 0x10a180, 0x01000000);
203         for (i = 0; i < ppwr->code.size / 4; i++) {
204                 if ((i & 0x3f) == 0)
205                         nv_wr32(ppwr, 0x10a188, i >> 6);
206                 nv_wr32(ppwr, 0x10a184, ppwr->code.data[i]);
207         }
208
209         /* start it running */
210         nv_wr32(ppwr, 0x10a10c, 0x00000000);
211         nv_wr32(ppwr, 0x10a104, 0x00000000);
212         nv_wr32(ppwr, 0x10a100, 0x00000002);
213
214         /* wait for valid host->pwr ring configuration */
215         if (!nv_wait_ne(ppwr, 0x10a4d0, 0xffffffff, 0x00000000))
216                 return -EBUSY;
217         ppwr->send.base = nv_rd32(ppwr, 0x10a4d0) & 0x0000ffff;
218         ppwr->send.size = nv_rd32(ppwr, 0x10a4d0) >> 16;
219
220         /* wait for valid pwr->host ring configuration */
221         if (!nv_wait_ne(ppwr, 0x10a4dc, 0xffffffff, 0x00000000))
222                 return -EBUSY;
223         ppwr->recv.base = nv_rd32(ppwr, 0x10a4dc) & 0x0000ffff;
224         ppwr->recv.size = nv_rd32(ppwr, 0x10a4dc) >> 16;
225
226         nv_wr32(ppwr, 0x10a010, 0x000000e0);
227         return 0;
228 }
229
230 int
231 nouveau_pwr_create_(struct nouveau_object *parent,
232                     struct nouveau_object *engine,
233                     struct nouveau_oclass *oclass, int length, void **pobject)
234 {
235         struct nouveau_pwr *ppwr;
236         int ret;
237
238         ret = nouveau_subdev_create_(parent, engine, oclass, 0, "PPWR",
239                                      "pwr", length, pobject);
240         ppwr = *pobject;
241         if (ret)
242                 return ret;
243
244         INIT_WORK(&ppwr->recv.work, nouveau_pwr_recv);
245         init_waitqueue_head(&ppwr->recv.wait);
246         return 0;
247 }