4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2010 PathScale Inc. All rights reserved.
24 * Use is subject to license terms.
28 #include "nouveau_drv.h"
29 #include "pscnv_engine.h"
30 #include "pscnv_chan.h"
31 #include "nv50_chan.h"
33 #include "nv98_crypt.fuc.h"
35 struct nv98_crypt_engine
{
36 struct pscnv_engine base
;
40 struct nv98_crypt_chan
{
41 struct pscnv_bo
*crctx
;
44 #define nv98_crypt(x) container_of(x, struct nv98_crypt_engine, base)
46 static int nv98_crypt_oclasses
[] = {
51 void nv98_crypt_takedown(struct pscnv_engine
*eng
);
52 void nv98_crypt_irq_handler(struct drm_device
*dev
, int irq
);
53 int nv98_crypt_tlb_flush(struct pscnv_engine
*eng
, struct pscnv_vspace
*vs
);
54 int nv86_crypt_tlb_flush(struct pscnv_engine
*eng
, struct pscnv_vspace
*vs
);
55 int nv98_crypt_chan_alloc(struct pscnv_engine
*eng
, struct pscnv_chan
*ch
);
56 void nv98_crypt_chan_free(struct pscnv_engine
*eng
, struct pscnv_chan
*ch
);
57 void nv98_crypt_chan_kill(struct pscnv_engine
*eng
, struct pscnv_chan
*ch
);
58 int nv98_crypt_chan_obj_new(struct pscnv_engine
*eng
, struct pscnv_chan
*ch
, uint32_t handle
, uint32_t oclass
, uint32_t flags
);
60 int nv98_crypt_init(struct drm_device
*dev
) {
61 struct drm_nouveau_private
*dev_priv
= dev
->dev_private
;
62 struct nv98_crypt_engine
*res
= kzalloc(sizeof *res
, GFP_KERNEL
);
66 NV_ERROR(dev
, "PCRYPT: Couldn't allocate engine!\n");
71 res
->base
.oclasses
= nv98_crypt_oclasses
;
72 res
->base
.takedown
= nv98_crypt_takedown
;
73 res
->base
.tlb_flush
= nv98_crypt_tlb_flush
;
74 res
->base
.chan_alloc
= nv98_crypt_chan_alloc
;
75 res
->base
.chan_kill
= nv98_crypt_chan_kill
;
76 res
->base
.chan_free
= nv98_crypt_chan_free
;
77 res
->base
.chan_obj_new
= nv98_crypt_chan_obj_new
;
78 spin_lock_init(&res
->lock
);
80 /* reset everything */
81 nv_wr32(dev
, 0x200, 0xffffbfff);
82 nv_wr32(dev
, 0x200, 0xffffffff);
84 while (!(nv_rd32(dev
, 0x87008) & 0x10));
85 nv_wr32(dev
, 0x87004, 0x10);
87 nv_wr32(dev
, 0x87ff8, 0x00100000);
88 for (i
= 0; i
< sizeof(nv98_pcrypt_code
); i
+= 4)
89 nv_wr32(dev
, 0x87ff4, nv98_pcrypt_code
[i
] | nv98_pcrypt_code
[i
+1] << 8 | nv98_pcrypt_code
[i
+2] << 16 | nv98_pcrypt_code
[i
+3] << 24);
90 nv_wr32(dev
, 0x87ff8, 0x00000000);
91 for (i
= 0; i
< sizeof(nv98_pcrypt_data
); i
+= 4)
92 nv_wr32(dev
, 0x87ff4, nv98_pcrypt_data
[i
] | nv98_pcrypt_data
[i
+1] << 8 | nv98_pcrypt_data
[i
+2] << 16 | nv98_pcrypt_data
[i
+3] << 24);
94 dev_priv
->engines
[PSCNV_ENGINE_CRYPT
] = &res
->base
;
96 nouveau_irq_register(dev
, 14, nv98_crypt_irq_handler
);
98 nv_wr32(dev
, 0x8710c, 0);
99 nv_wr32(dev
, 0x87104, 0); /* ENTRY */
100 nv_wr32(dev
, 0x87100, 2); /* TRIGGER */
104 void nv98_crypt_takedown(struct pscnv_engine
*eng
) {
105 struct drm_nouveau_private
*dev_priv
= eng
->dev
->dev_private
;
106 nv_wr32(eng
->dev
, 0x87014, -1); /* INTR_EN */
107 nouveau_irq_unregister(eng
->dev
, 14);
110 dev_priv
->engines
[PSCNV_ENGINE_CRYPT
] = 0;
113 int nv98_crypt_chan_alloc(struct pscnv_engine
*eng
, struct pscnv_chan
*ch
) {
114 struct drm_device
*dev
= eng
->dev
;
115 struct drm_nouveau_private
*dev_priv
= dev
->dev_private
;
119 struct nv98_crypt_chan
*crch
= kzalloc(sizeof *crch
, GFP_KERNEL
);
122 NV_ERROR(dev
, "PCRYPT: Couldn't allocate channel!\n");
127 crch
->crctx
= pscnv_mem_alloc(dev
, 0x100, PSCNV_GEM_CONTIG
, 0, 0xc7c07e47);
129 NV_ERROR(dev
, "PCRYPT: No VRAM for context!\n");
133 for (i
= 0; i
< 0x100; i
+= 4)
134 nv_wv32(crch
->crctx
, i
, 0);
135 limit
= crch
->crctx
->start
+ 0x80 - 1;
137 nv_wv32(ch
->bo
, hdr
+ 0x00, 0x00190000);
138 nv_wv32(ch
->bo
, hdr
+ 0x04, limit
);
139 nv_wv32(ch
->bo
, hdr
+ 0x08, crch
->crctx
->start
);
140 nv_wv32(ch
->bo
, hdr
+ 0x0c, (limit
>> 32) << 24 | (crch
->crctx
->start
>> 32));
141 nv_wv32(ch
->bo
, hdr
+ 0x10, 0);
142 nv_wv32(ch
->bo
, hdr
+ 0x14, 0);
143 dev_priv
->vm
->bar_flush(dev
);
145 nv50_vs(ch
->vspace
)->engref
[PSCNV_ENGINE_CRYPT
]++;
146 ch
->engdata
[PSCNV_ENGINE_CRYPT
] = crch
;
150 int nv98_crypt_tlb_flush(struct pscnv_engine
*eng
, struct pscnv_vspace
*vs
) {
151 return nv50_vm_flush(eng
->dev
, 0xa);
154 void nv98_crypt_chan_kill(struct pscnv_engine
*eng
, struct pscnv_chan
*ch
) {
155 struct drm_device
*dev
= eng
->dev
;
156 struct nv98_crypt_engine
*crypt
= nv98_crypt(eng
);
159 spin_lock_irqsave(&crypt
->lock
, flags
);
160 start
= nv04_timer_read(dev
);
161 /* disable PFIFO access */
162 nv_wr32(dev
, 0x87048, 0);
163 /* check if the channel we're freeing is active on PCRYPT. */
164 if (nv_rd32(dev
, 0x87050) == (0x40000000 | ch
->bo
->start
>> 12)) {
165 NV_INFO(dev
, "Kicking channel %d off PCRYPT.\n", ch
->cid
);
166 nv_wr32(dev
, 0x87050, 0);
168 /* or maybe it was just going to be loaded in? */
169 if (nv_rd32(dev
, 0x87054) == (0x40000000 | ch
->bo
->start
>> 12)) {
170 nv_wr32(dev
, 0x87054, 0);
172 /* back to normal state. */
173 nv_wr32(dev
, 0x87048, 0x3);
174 spin_unlock_irqrestore(&crypt
->lock
, flags
);
177 void nv98_crypt_chan_free(struct pscnv_engine
*eng
, struct pscnv_chan
*ch
) {
178 struct nv98_crypt_chan
*crch
= ch
->engdata
[PSCNV_ENGINE_CRYPT
];
179 pscnv_mem_free(crch
->crctx
);
181 nv50_vs(ch
->vspace
)->engref
[PSCNV_ENGINE_CRYPT
]--;
182 ch
->engdata
[PSCNV_ENGINE_CRYPT
] = 0;
183 nv98_crypt_tlb_flush(eng
, ch
->vspace
);
186 int nv98_crypt_chan_obj_new(struct pscnv_engine
*eng
, struct pscnv_chan
*ch
, uint32_t handle
, uint32_t oclass
, uint32_t flags
) {
187 uint32_t inst
= nv50_chan_iobj_new(ch
, 0x20);
191 nv_wv32(ch
->bo
, inst
, oclass
);
192 nv_wv32(ch
->bo
, inst
+ 4, 0);
193 nv_wv32(ch
->bo
, inst
+ 8, 0);
194 nv_wv32(ch
->bo
, inst
+ 0xc, 0);
195 nv_wv32(ch
->bo
, inst
+ 0x10, 0);
196 nv_wv32(ch
->bo
, inst
+ 0x14, 0);
197 nv_wv32(ch
->bo
, inst
+ 0x18, 0);
198 nv_wv32(ch
->bo
, inst
+ 0x1c, 0);
199 return pscnv_ramht_insert (&ch
->ramht
, handle
, 0x500000 | inst
>> 4);
202 void nv98_crypt_irq_handler(struct drm_device
*dev
, int irq
) {
203 struct drm_nouveau_private
*dev_priv
= dev
->dev_private
;
204 struct nv98_crypt_engine
*crypt
= nv98_crypt(dev_priv
->engines
[PSCNV_ENGINE_CRYPT
]);
205 uint32_t status
, dispatch
;
207 uint32_t chandle
, data
, addr
, subc
, mthd
, ecode
;
209 spin_lock_irqsave(&crypt
->lock
, flags
);
210 dispatch
= nv_rd32(dev
, 0x8701c);
211 status
= nv_rd32(dev
, 0x87008) & dispatch
& ~(dispatch
>> 16);
212 addr
= nv_rd32(dev
, 0x87040) >> 16;
213 ecode
= nv_rd32(dev
, 0x87040) & 0xffff;
215 data
= nv_rd32(dev
, 0x87044);
216 mthd
= addr
<< 2 & 0x1ffc;
217 subc
= addr
>> 11 & 7;
218 chandle
= nv_rd32(dev
, 0x87050) & 0x3fffffff;
219 cid
= pscnv_chan_handle_lookup(dev
, chandle
);
221 NV_ERROR(dev
, "PCRYPT: UNKNOWN channel %x active!\n", chandle
);
227 NV_ERROR(dev
, "PCRYPT_ILLEGAL_MTHD: ch %d subc %d mthd %04x data %08x\n", cid
, subc
, mthd
, data
);
230 NV_ERROR(dev
, "PCRYPT_INVALID_BITFIELD: ch %d subc %d mthd %04x data %08x\n", cid
, subc
, mthd
, data
);
233 NV_ERROR(dev
, "PCRYPT_INVALID_ENUM: ch %d subc %d mthd %04x data %08x\n", cid
, subc
, mthd
, data
);
236 NV_ERROR(dev
, "PCRYPT_QUERY: ch %d subc %d mthd %04x data %08x\n", cid
, subc
, mthd
, data
);
239 NV_ERROR(dev
, "PCRYPT_DISPATCH_ERROR [%x]: ch %d subc %d mthd %04x data %08x\n", ecode
, cid
, subc
, mthd
, data
);
242 nv_wr32(dev
, 0x87004, 0x40);
246 if (status
& 0x200) {
247 NV_ERROR(dev
, "PCRYPT_FAULT: ch %d\n", cid
);
248 nv_wr32(dev
, 0x87004, 0x200);
253 NV_ERROR(dev
, "Unknown PCRYPT interrupt %08x\n", status
);
254 NV_ERROR(dev
, "PCRYPT: ch %d\n", cid
);
255 nv_wr32(dev
, 0x87004, status
);
258 spin_unlock_irqrestore(&crypt
->lock
, flags
);