aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/radeon
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/radeon')
-rw-r--r--drivers/gpu/drm/radeon/r500_reg.h3
-rw-r--r--drivers/gpu/drm/radeon/r600_cs.c125
-rw-r--r--drivers/gpu/drm/radeon/radeon_reg.h1
3 files changed, 128 insertions, 1 deletions
diff --git a/drivers/gpu/drm/radeon/r500_reg.h b/drivers/gpu/drm/radeon/r500_reg.h
index e1d5e0331e19..868add6e166d 100644
--- a/drivers/gpu/drm/radeon/r500_reg.h
+++ b/drivers/gpu/drm/radeon/r500_reg.h
@@ -445,6 +445,8 @@
445#define AVIVO_D1MODE_VBLANK_STATUS 0x6534 445#define AVIVO_D1MODE_VBLANK_STATUS 0x6534
446# define AVIVO_VBLANK_ACK (1 << 4) 446# define AVIVO_VBLANK_ACK (1 << 4)
447#define AVIVO_D1MODE_VLINE_START_END 0x6538 447#define AVIVO_D1MODE_VLINE_START_END 0x6538
448#define AVIVO_D1MODE_VLINE_STATUS 0x653c
449# define AVIVO_D1MODE_VLINE_STAT (1 << 12)
448#define AVIVO_DxMODE_INT_MASK 0x6540 450#define AVIVO_DxMODE_INT_MASK 0x6540
449# define AVIVO_D1MODE_INT_MASK (1 << 0) 451# define AVIVO_D1MODE_INT_MASK (1 << 0)
450# define AVIVO_D2MODE_INT_MASK (1 << 8) 452# define AVIVO_D2MODE_INT_MASK (1 << 8)
@@ -502,6 +504,7 @@
502 504
503#define AVIVO_D2MODE_VBLANK_STATUS 0x6d34 505#define AVIVO_D2MODE_VBLANK_STATUS 0x6d34
504#define AVIVO_D2MODE_VLINE_START_END 0x6d38 506#define AVIVO_D2MODE_VLINE_START_END 0x6d38
507#define AVIVO_D2MODE_VLINE_STATUS 0x6d3c
505#define AVIVO_D2MODE_VIEWPORT_START 0x6d80 508#define AVIVO_D2MODE_VIEWPORT_START 0x6d80
506#define AVIVO_D2MODE_VIEWPORT_SIZE 0x6d84 509#define AVIVO_D2MODE_VIEWPORT_SIZE 0x6d84
507#define AVIVO_D2MODE_EXT_OVERSCAN_LEFT_RIGHT 0x6d88 510#define AVIVO_D2MODE_EXT_OVERSCAN_LEFT_RIGHT 0x6d88
diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c
index dd009da0e7a0..20eb66dbb3a4 100644
--- a/drivers/gpu/drm/radeon/r600_cs.c
+++ b/drivers/gpu/drm/radeon/r600_cs.c
@@ -177,13 +177,136 @@ static int r600_cs_packet_next_reloc_nomm(struct radeon_cs_parser *p,
177 return 0; 177 return 0;
178} 178}
179 179
180/**
181 * r600_cs_packet_next_vline() - parse userspace VLINE packet
182 * @parser: parser structure holding parsing context.
183 *
184 * Userspace sends a special sequence for VLINE waits.
185 * PACKET0 - VLINE_START_END + value
186 * PACKET3 - WAIT_REG_MEM poll vline status reg
187 * RELOC (P3) - crtc_id in reloc.
188 *
189 * This function parses this and relocates the VLINE START END
190 * and WAIT_REG_MEM packets to the correct crtc.
191 * It also detects a switched off crtc and nulls out the
192 * wait in that case.
193 */
194static int r600_cs_packet_parse_vline(struct radeon_cs_parser *p)
195{
196 struct drm_mode_object *obj;
197 struct drm_crtc *crtc;
198 struct radeon_crtc *radeon_crtc;
199 struct radeon_cs_packet p3reloc, wait_reg_mem;
200 int crtc_id;
201 int r;
202 uint32_t header, h_idx, reg, wait_reg_mem_info;
203 volatile uint32_t *ib;
204
205 ib = p->ib->ptr;
206
207 /* parse the WAIT_REG_MEM */
208 r = r600_cs_packet_parse(p, &wait_reg_mem, p->idx);
209 if (r)
210 return r;
211
212 /* check its a WAIT_REG_MEM */
213 if (wait_reg_mem.type != PACKET_TYPE3 ||
214 wait_reg_mem.opcode != PACKET3_WAIT_REG_MEM) {
215 DRM_ERROR("vline wait missing WAIT_REG_MEM segment\n");
216 r = -EINVAL;
217 return r;
218 }
219
220 wait_reg_mem_info = radeon_get_ib_value(p, wait_reg_mem.idx + 1);
221 /* bit 4 is reg (0) or mem (1) */
222 if (wait_reg_mem_info & 0x10) {
223 DRM_ERROR("vline WAIT_REG_MEM waiting on MEM rather than REG\n");
224 r = -EINVAL;
225 return r;
226 }
227 /* waiting for value to be equal */
228 if ((wait_reg_mem_info & 0x7) != 0x3) {
229 DRM_ERROR("vline WAIT_REG_MEM function not equal\n");
230 r = -EINVAL;
231 return r;
232 }
233 if ((radeon_get_ib_value(p, wait_reg_mem.idx + 2) << 2) != AVIVO_D1MODE_VLINE_STATUS) {
234 DRM_ERROR("vline WAIT_REG_MEM bad reg\n");
235 r = -EINVAL;
236 return r;
237 }
238
239 if (radeon_get_ib_value(p, wait_reg_mem.idx + 5) != AVIVO_D1MODE_VLINE_STAT) {
240 DRM_ERROR("vline WAIT_REG_MEM bad bit mask\n");
241 r = -EINVAL;
242 return r;
243 }
244
245 /* jump over the NOP */
246 r = r600_cs_packet_parse(p, &p3reloc, p->idx + wait_reg_mem.count + 2);
247 if (r)
248 return r;
249
250 h_idx = p->idx - 2;
251 p->idx += wait_reg_mem.count + 2;
252 p->idx += p3reloc.count + 2;
253
254 header = radeon_get_ib_value(p, h_idx);
255 crtc_id = radeon_get_ib_value(p, h_idx + 2 + 7 + 1);
256 reg = header >> 2;
257 mutex_lock(&p->rdev->ddev->mode_config.mutex);
258 obj = drm_mode_object_find(p->rdev->ddev, crtc_id, DRM_MODE_OBJECT_CRTC);
259 if (!obj) {
260 DRM_ERROR("cannot find crtc %d\n", crtc_id);
261 r = -EINVAL;
262 goto out;
263 }
264 crtc = obj_to_crtc(obj);
265 radeon_crtc = to_radeon_crtc(crtc);
266 crtc_id = radeon_crtc->crtc_id;
267
268 if (!crtc->enabled) {
269 /* if the CRTC isn't enabled - we need to nop out the WAIT_REG_MEM */
270 ib[h_idx + 2] = PACKET2(0);
271 ib[h_idx + 3] = PACKET2(0);
272 ib[h_idx + 4] = PACKET2(0);
273 ib[h_idx + 5] = PACKET2(0);
274 ib[h_idx + 6] = PACKET2(0);
275 ib[h_idx + 7] = PACKET2(0);
276 ib[h_idx + 8] = PACKET2(0);
277 } else if (crtc_id == 1) {
278 switch (reg) {
279 case AVIVO_D1MODE_VLINE_START_END:
280 header &= ~R600_CP_PACKET0_REG_MASK;
281 header |= AVIVO_D2MODE_VLINE_START_END >> 2;
282 break;
283 default:
284 DRM_ERROR("unknown crtc reloc\n");
285 r = -EINVAL;
286 goto out;
287 }
288 ib[h_idx] = header;
289 ib[h_idx + 4] = AVIVO_D2MODE_VLINE_STATUS >> 2;
290 }
291out:
292 mutex_unlock(&p->rdev->ddev->mode_config.mutex);
293 return r;
294}
295
180static int r600_packet0_check(struct radeon_cs_parser *p, 296static int r600_packet0_check(struct radeon_cs_parser *p,
181 struct radeon_cs_packet *pkt, 297 struct radeon_cs_packet *pkt,
182 unsigned idx, unsigned reg) 298 unsigned idx, unsigned reg)
183{ 299{
300 int r;
301
184 switch (reg) { 302 switch (reg) {
185 case AVIVO_D1MODE_VLINE_START_END: 303 case AVIVO_D1MODE_VLINE_START_END:
186 case AVIVO_D2MODE_VLINE_START_END: 304 r = r600_cs_packet_parse_vline(p);
305 if (r) {
306 DRM_ERROR("No reloc for ib[%d]=0x%04X\n",
307 idx, reg);
308 return r;
309 }
187 break; 310 break;
188 default: 311 default:
189 printk(KERN_ERR "Forbidden register 0x%04X in cs at %d\n", 312 printk(KERN_ERR "Forbidden register 0x%04X in cs at %d\n",
diff --git a/drivers/gpu/drm/radeon/radeon_reg.h b/drivers/gpu/drm/radeon/radeon_reg.h
index 21da871a793c..bfa1ab9c93e1 100644
--- a/drivers/gpu/drm/radeon/radeon_reg.h
+++ b/drivers/gpu/drm/radeon/radeon_reg.h
@@ -3333,6 +3333,7 @@
3333# define RADEON_CP_PACKET_MAX_DWORDS (1 << 12) 3333# define RADEON_CP_PACKET_MAX_DWORDS (1 << 12)
3334# define RADEON_CP_PACKET0_REG_MASK 0x000007ff 3334# define RADEON_CP_PACKET0_REG_MASK 0x000007ff
3335# define R300_CP_PACKET0_REG_MASK 0x00001fff 3335# define R300_CP_PACKET0_REG_MASK 0x00001fff
3336# define R600_CP_PACKET0_REG_MASK 0x0000ffff
3336# define RADEON_CP_PACKET1_REG0_MASK 0x000007ff 3337# define RADEON_CP_PACKET1_REG0_MASK 0x000007ff
3337# define RADEON_CP_PACKET1_REG1_MASK 0x003ff800 3338# define RADEON_CP_PACKET1_REG1_MASK 0x003ff800
3338 3339