/**
 * adreno_drawctxt_detach(): detach a context from the GPU
 * @context: Generic KGSL context container for the context
 *
 */
void adreno_drawctxt_detach(struct kgsl_context *context)
{
	struct kgsl_device *device;
	struct adreno_device *adreno_dev;
	struct adreno_context *drawctxt;

	if (context == NULL)
		return;

	device = context->device;
	adreno_dev = ADRENO_DEVICE(device);
	drawctxt = ADRENO_CONTEXT(context);
	/* deactivate context */
	if (adreno_dev->drawctxt_active == drawctxt) {
		/* no need to save GMEM or shader, the context is
		 * being destroyed.
		 */
		drawctxt->flags &= ~(CTXT_FLAGS_GMEM_SAVE |
				     CTXT_FLAGS_SHADER_SAVE |
				     CTXT_FLAGS_GMEM_SHADOW |
				     CTXT_FLAGS_STATE_SHADOW);

		drawctxt->flags |= CTXT_FLAGS_BEING_DESTROYED;

		adreno_drawctxt_switch(adreno_dev, NULL, 0);
	}

	if (device->state != KGSL_STATE_HUNG)
		adreno_idle(device);

	adreno_profile_process_results(device);

	kgsl_sharedmem_free(&drawctxt->gpustate);
	kgsl_sharedmem_free(&drawctxt->context_gmem_shadow.gmemshadow);
}
void adreno_drawctxt_destroy(struct kgsl_device *device,
			  struct kgsl_context *context)
{
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
	struct adreno_context *drawctxt = context->devctxt;

	if (drawctxt == NULL)
		return;

	/* deactivate context */
	if (adreno_dev->drawctxt_active == drawctxt) {
		/* no need to save GMEM or shader, the context is
		 * being destroyed.
		 */
		drawctxt->flags &= ~(CTXT_FLAGS_GMEM_SAVE |
				     CTXT_FLAGS_SHADER_SAVE |
				     CTXT_FLAGS_GMEM_SHADOW |
				     CTXT_FLAGS_STATE_SHADOW);

		adreno_drawctxt_switch(adreno_dev, NULL, 0);
	}

	adreno_idle(device, KGSL_TIMEOUT_DEFAULT);

	kgsl_sharedmem_free(&drawctxt->gpustate);
	kgsl_sharedmem_free(&drawctxt->context_gmem_shadow.gmemshadow);

	kfree(drawctxt);
	context->devctxt = NULL;
}
Beispiel #3
0
void adreno_drawctxt_destroy(struct kgsl_device *device,
			  struct kgsl_context *context)
{
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
	struct adreno_context *drawctxt;

	if (context == NULL || context->devctxt == NULL)
		return;

	drawctxt = context->devctxt;
	
	if (adreno_dev->drawctxt_active == drawctxt) {
		drawctxt->flags &= ~(CTXT_FLAGS_GMEM_SAVE |
				     CTXT_FLAGS_SHADER_SAVE |
				     CTXT_FLAGS_GMEM_SHADOW |
				     CTXT_FLAGS_STATE_SHADOW);
#ifdef CONFIG_MSM_KGSL_GPU_USAGE
		device->current_process_priv = NULL;
#endif
		adreno_drawctxt_switch(adreno_dev, NULL, 0);
	}

	if (device->state != KGSL_STATE_HUNG)
		adreno_idle(device);

	if (adreno_is_a20x(adreno_dev) && adreno_dev->drawctxt_active)
		kgsl_setstate(&device->mmu, adreno_dev->drawctxt_active->id,
			KGSL_MMUFLAGS_PTUPDATE);

	kgsl_sharedmem_free(&drawctxt->gpustate);
	kgsl_sharedmem_free(&drawctxt->context_gmem_shadow.gmemshadow);

	kfree(drawctxt);
	context->devctxt = NULL;
}
void adreno_drawctxt_destroy(struct kgsl_device *device,
			  struct kgsl_context *context)
{
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
	struct adreno_context *drawctxt;

	if (context == NULL || context->devctxt == NULL)
		return;

	drawctxt = context->devctxt;
	
	if (adreno_dev->drawctxt_active == drawctxt) {
		drawctxt->flags &= ~(CTXT_FLAGS_GMEM_SAVE |
				     CTXT_FLAGS_SHADER_SAVE |
				     CTXT_FLAGS_GMEM_SHADOW |
				     CTXT_FLAGS_STATE_SHADOW);

		adreno_drawctxt_switch(adreno_dev, NULL, 0);
	}

	adreno_idle(device);

	kgsl_sharedmem_free(&drawctxt->gpustate);
	kgsl_sharedmem_free(&drawctxt->context_gmem_shadow.gmemshadow);

	kfree(drawctxt);
	context->devctxt = NULL;
}
Beispiel #5
0
static void a4xx_idle(struct msm_gpu *gpu)
{
	/* wait for ringbuffer to drain: */
	adreno_idle(gpu);

	/* then wait for GPU to finish: */
	if (spin_until(!(gpu_read(gpu, REG_A4XX_RBBM_STATUS) &
					A4XX_RBBM_STATUS_GPU_BUSY)))
		DRM_ERROR("%s: timeout waiting for GPU to idle!\n", gpu->name);

	/* TODO maybe we need to reset GPU here to recover from hang? */
}
Beispiel #6
0
/* create buffers for saving/restoring registers, constants, & GMEM */
static int a2xx_ctxt_gmem_shadow(struct adreno_device *adreno_dev,
			struct adreno_context *drawctxt)
{
	int result;

	calc_gmemsize(&drawctxt->context_gmem_shadow,
		adreno_dev->gmemspace.sizebytes);
	tmp_ctx.gmem_base = adreno_dev->gmemspace.gpu_base;

	result = kgsl_allocate(&drawctxt->context_gmem_shadow.gmemshadow,
		drawctxt->pagetable, drawctxt->context_gmem_shadow.size);

	if (result)
		return result;

	/* we've allocated the shadow, when swapped out, GMEM must be saved. */
	drawctxt->flags |= CTXT_FLAGS_GMEM_SHADOW | CTXT_FLAGS_GMEM_SAVE;

	/* blank out gmem shadow. */
	kgsl_sharedmem_set(&drawctxt->context_gmem_shadow.gmemshadow, 0, 0,
			   drawctxt->context_gmem_shadow.size);

	/* build quad vertex buffer */
	build_quad_vtxbuff(drawctxt, &drawctxt->context_gmem_shadow,
		&tmp_ctx.cmd);

	/* build TP0_CHICKEN register restore command buffer */
	tmp_ctx.cmd = build_chicken_restore_cmds(drawctxt);

	/* build indirect command buffers to save & restore gmem */
	/* Idle because we are reading PM override registers */
	adreno_idle(&adreno_dev->dev, KGSL_TIMEOUT_DEFAULT);
	drawctxt->context_gmem_shadow.gmem_save_commands = tmp_ctx.cmd;
	tmp_ctx.cmd =
	    build_gmem2sys_cmds(adreno_dev, drawctxt,
				&drawctxt->context_gmem_shadow);
	drawctxt->context_gmem_shadow.gmem_restore_commands = tmp_ctx.cmd;
	tmp_ctx.cmd =
	    build_sys2gmem_cmds(adreno_dev, drawctxt,
				&drawctxt->context_gmem_shadow);

	kgsl_cache_range_op(&drawctxt->context_gmem_shadow.gmemshadow,
			    KGSL_CACHE_OP_FLUSH);

	kgsl_cffdump_syncmem(NULL,
			&drawctxt->context_gmem_shadow.gmemshadow,
			drawctxt->context_gmem_shadow.gmemshadow.gpuaddr,
			drawctxt->context_gmem_shadow.gmemshadow.size, false);

	return 0;
}
/**
 * adreno_context_restore() - generic context restore handler
 * @rb: The RB in which context is to be restored
 *
 * Basic context restore handler that writes the context identifier
 * to the ringbuffer and issues pagetable switch commands if necessary.
 */
static void adreno_context_restore(struct adreno_ringbuffer *rb)
{
	struct kgsl_device *device = rb->device;
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
	struct adreno_context *drawctxt = rb->drawctxt_active;
	unsigned int cmds[11];
	int ret;

	if (!drawctxt)
		return;
	/*
	 * write the context identifier to the ringbuffer, write to both
	 * the global index and the index of the RB in which the context
	 * operates. The global values will always be reliable since we
	 * could be in middle of RB switch in which case the RB value may
	 * not be accurate
	 */
	cmds[0] = cp_nop_packet(1);
	cmds[1] = KGSL_CONTEXT_TO_MEM_IDENTIFIER;
	cmds[2] = cp_type3_packet(CP_MEM_WRITE, 2);
	cmds[3] = device->memstore.gpuaddr +
		KGSL_MEMSTORE_RB_OFFSET(rb, current_context);
	cmds[4] = drawctxt->base.id;
	cmds[5] = cp_type3_packet(CP_MEM_WRITE, 2);
	cmds[6] = device->memstore.gpuaddr +
		KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
					current_context);
	cmds[7] = drawctxt->base.id;
	/* Flush the UCHE for new context */
	cmds[8] = cp_type0_packet(
		adreno_getreg(adreno_dev, ADRENO_REG_UCHE_INVALIDATE0), 2);
	cmds[9] = 0;
	if (adreno_is_a4xx(adreno_dev))
		cmds[10] = 0x12;
	else if (adreno_is_a3xx(adreno_dev))
		cmds[10] = 0x90000000;
	ret = adreno_ringbuffer_issuecmds(rb, KGSL_CMD_FLAGS_NONE, cmds, 11);
	if (ret) {
		/*
		 * A failure to submit commands to ringbuffer means RB may
		 * be full, in this case wait for idle and use CPU
		 */
		ret = adreno_idle(device);
		BUG_ON(ret);
		_adreno_context_restore_cpu(rb, drawctxt);
	}
}
Beispiel #8
0
void adreno_drawctxt_destroy(struct kgsl_device *device,
			  struct kgsl_context *context)
{
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
	struct adreno_context *drawctxt;

	if (context == NULL || context->devctxt == NULL)
		return;

	drawctxt = context->devctxt;
	/* deactivate context */
	if (adreno_dev->drawctxt_active == drawctxt) {
		/* no need to save GMEM or shader, the context is
		 * being destroyed.
		 */
		drawctxt->flags &= ~(CTXT_FLAGS_GMEM_SAVE |
				     CTXT_FLAGS_SHADER_SAVE |
				     CTXT_FLAGS_GMEM_SHADOW |
				     CTXT_FLAGS_STATE_SHADOW);

		drawctxt->flags |= CTXT_FLAGS_BEING_DESTOYED;

		adreno_drawctxt_switch(adreno_dev, NULL, 0);
	}

	if (device->state != KGSL_STATE_HUNG)
		adreno_idle(device);

	if (adreno_is_a20x(adreno_dev) && adreno_dev->drawctxt_active)
		kgsl_setstate(&device->mmu, adreno_dev->drawctxt_active->id,
			KGSL_MMUFLAGS_PTUPDATE);

	kgsl_sharedmem_free(&drawctxt->gpustate);
	kgsl_sharedmem_free(&drawctxt->context_gmem_shadow.gmemshadow);

	kfree(drawctxt);
	context->devctxt = NULL;
}
Beispiel #9
0
/* create buffers for saving/restoring registers, constants, & GMEM */
static int a2xx_ctxt_gpustate_shadow(struct adreno_device *adreno_dev,
			struct adreno_context *drawctxt)
{
	int result;

	/* Allocate vmalloc memory to store the gpustate */
	result = kgsl_allocate(&drawctxt->gpustate,
		drawctxt->pagetable, _context_size(adreno_dev));

	if (result)
		return result;

	drawctxt->flags |= CTXT_FLAGS_STATE_SHADOW;

	/* Blank out h/w register, constant, and command buffer shadows. */
	kgsl_sharedmem_set(&drawctxt->gpustate, 0, 0,
			   _context_size(adreno_dev));

	/* set-up command and vertex buffer pointers */
	tmp_ctx.cmd = tmp_ctx.start
	    = (unsigned int *)((char *)drawctxt->gpustate.hostptr + CMD_OFFSET);

	/* build indirect command buffers to save & restore regs/constants */
	adreno_idle(&adreno_dev->dev, KGSL_TIMEOUT_DEFAULT);
	build_regrestore_cmds(adreno_dev, drawctxt);
	build_regsave_cmds(adreno_dev, drawctxt);

	build_shader_save_restore_cmds(adreno_dev, drawctxt);

	kgsl_cache_range_op(&drawctxt->gpustate,
			    KGSL_CACHE_OP_FLUSH);

	kgsl_cffdump_syncmem(NULL, &drawctxt->gpustate,
			drawctxt->gpustate.gpuaddr,
			drawctxt->gpustate.size, false);
	return 0;
}
Beispiel #10
0
/* create buffers for saving/restoring registers, constants, & GMEM */
static int
create_gpustate_shadow(struct kgsl_device *device,
		       struct adreno_context *drawctxt,
		       struct tmp_ctx *ctx)
{
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
	int result;

	/* Allocate vmalloc memory to store the gpustate */
	result = kgsl_allocate(&drawctxt->gpustate,
		drawctxt->pagetable, CONTEXT_SIZE);

	if (result)
		return result;

	drawctxt->flags |= CTXT_FLAGS_STATE_SHADOW;

	/* Blank out h/w register, constant, and command buffer shadows. */
	kgsl_sharedmem_set(&drawctxt->gpustate, 0, 0, CONTEXT_SIZE);

	/* set-up command and vertex buffer pointers */
	ctx->cmd = ctx->start
	    = (unsigned int *)((char *)drawctxt->gpustate.hostptr + CMD_OFFSET);

	/* build indirect command buffers to save & restore regs/constants */
	adreno_idle(device, KGSL_TIMEOUT_DEFAULT);
	build_regrestore_cmds(adreno_dev, drawctxt, ctx);
	build_regsave_cmds(adreno_dev, drawctxt, ctx);

	build_shader_save_restore_cmds(drawctxt, ctx);

	kgsl_cache_range_op(&drawctxt->gpustate,
			    KGSL_CACHE_OP_FLUSH);

	return 0;
}
Beispiel #11
0
int adreno_ringbuffer_start(struct adreno_ringbuffer *rb, unsigned int init_ram)
{
    int status;
    /*cp_rb_cntl_u cp_rb_cntl; */
    union reg_cp_rb_cntl cp_rb_cntl;
    unsigned int rb_cntl;
    struct kgsl_device *device = rb->device;
    struct adreno_device *adreno_dev = ADRENO_DEVICE(device);

    if (rb->flags & KGSL_FLAGS_STARTED)
        return 0;

    if (init_ram)
        rb->timestamp[KGSL_MEMSTORE_GLOBAL] = 0;

    kgsl_sharedmem_set(&rb->memptrs_desc, 0, 0,
                       sizeof(struct kgsl_rbmemptrs));

    kgsl_sharedmem_set(&rb->buffer_desc, 0, 0xAA,
                       (rb->sizedwords << 2));

    if (adreno_is_a2xx(adreno_dev)) {
        adreno_regwrite(device, REG_CP_RB_WPTR_BASE,
                        (rb->memptrs_desc.gpuaddr
                         + GSL_RB_MEMPTRS_WPTRPOLL_OFFSET));

        /* setup WPTR delay */
        adreno_regwrite(device, REG_CP_RB_WPTR_DELAY,
                        0 /*0x70000010 */);
    }

    /*setup REG_CP_RB_CNTL */
    adreno_regread(device, REG_CP_RB_CNTL, &rb_cntl);
    cp_rb_cntl.val = rb_cntl;

    /*
     * The size of the ringbuffer in the hardware is the log2
     * representation of the size in quadwords (sizedwords / 2)
     */
    cp_rb_cntl.f.rb_bufsz = ilog2(rb->sizedwords >> 1);

    /*
     * Specify the quadwords to read before updating mem RPTR.
     * Like above, pass the log2 representation of the blocksize
     * in quadwords.
    */
    cp_rb_cntl.f.rb_blksz = ilog2(KGSL_RB_BLKSIZE >> 3);

    if (adreno_is_a2xx(adreno_dev)) {
        /* WPTR polling */
        cp_rb_cntl.f.rb_poll_en = GSL_RB_CNTL_POLL_EN;
    }

    /* mem RPTR writebacks */
    cp_rb_cntl.f.rb_no_update =  GSL_RB_CNTL_NO_UPDATE;

    adreno_regwrite(device, REG_CP_RB_CNTL, cp_rb_cntl.val);

    adreno_regwrite(device, REG_CP_RB_BASE, rb->buffer_desc.gpuaddr);

    adreno_regwrite(device, REG_CP_RB_RPTR_ADDR,
                    rb->memptrs_desc.gpuaddr +
                    GSL_RB_MEMPTRS_RPTR_OFFSET);

    if (adreno_is_a3xx(adreno_dev)) {
        /* enable access protection to privileged registers */
        adreno_regwrite(device, A3XX_CP_PROTECT_CTRL, 0x00000007);

        /* RBBM registers */
        adreno_regwrite(device, A3XX_CP_PROTECT_REG_0, 0x63000040);
        adreno_regwrite(device, A3XX_CP_PROTECT_REG_1, 0x62000080);
        adreno_regwrite(device, A3XX_CP_PROTECT_REG_2, 0x600000CC);
        adreno_regwrite(device, A3XX_CP_PROTECT_REG_3, 0x60000108);
        adreno_regwrite(device, A3XX_CP_PROTECT_REG_4, 0x64000140);
        adreno_regwrite(device, A3XX_CP_PROTECT_REG_5, 0x66000400);

        /* CP registers */
        adreno_regwrite(device, A3XX_CP_PROTECT_REG_6, 0x65000700);
        adreno_regwrite(device, A3XX_CP_PROTECT_REG_7, 0x610007D8);
        adreno_regwrite(device, A3XX_CP_PROTECT_REG_8, 0x620007E0);
        adreno_regwrite(device, A3XX_CP_PROTECT_REG_9, 0x61001178);
        adreno_regwrite(device, A3XX_CP_PROTECT_REG_A, 0x64001180);

        /* RB registers */
        adreno_regwrite(device, A3XX_CP_PROTECT_REG_B, 0x60003300);

        /* VBIF registers */
        adreno_regwrite(device, A3XX_CP_PROTECT_REG_C, 0x6B00C000);
    }

    if (adreno_is_a2xx(adreno_dev)) {
        /* explicitly clear all cp interrupts */
        adreno_regwrite(device, REG_CP_INT_ACK, 0xFFFFFFFF);
    }

    /* setup scratch/timestamp */
    adreno_regwrite(device, REG_SCRATCH_ADDR, device->memstore.gpuaddr +
                    KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
                                         soptimestamp));

    adreno_regwrite(device, REG_SCRATCH_UMSK,
                    GSL_RB_MEMPTRS_SCRATCH_MASK);

    /* load the CP ucode */

    status = adreno_ringbuffer_load_pm4_ucode(device);
    if (status != 0)
        return status;

    /* load the prefetch parser ucode */
    status = adreno_ringbuffer_load_pfp_ucode(device);
    if (status != 0)
        return status;

    if (adreno_is_a305(adreno_dev) || adreno_is_a320(adreno_dev))
        adreno_regwrite(device, REG_CP_QUEUE_THRESHOLDS, 0x000F0602);

    rb->rptr = 0;
    rb->wptr = 0;

    /* clear ME_HALT to start micro engine */
    adreno_regwrite(device, REG_CP_ME_CNTL, 0);

    /* ME init is GPU specific, so jump into the sub-function */
    adreno_dev->gpudev->rb_init(adreno_dev, rb);

    /* idle device to validate ME INIT */
    status = adreno_idle(device, KGSL_TIMEOUT_DEFAULT);

    if (status == 0)
        rb->flags |= KGSL_FLAGS_STARTED;

    return status;
}
int adreno_ringbuffer_start(struct adreno_ringbuffer *rb, unsigned int init_ram)
{
	int status;
	/*cp_rb_cntl_u cp_rb_cntl; */
	union reg_cp_rb_cntl cp_rb_cntl;
	unsigned int rb_cntl;
	struct kgsl_device *device = rb->device;
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);

	if (rb->flags & KGSL_FLAGS_STARTED)
		return 0;

	if (init_ram)
		rb->timestamp[KGSL_MEMSTORE_GLOBAL] = 0;

	kgsl_sharedmem_set(&rb->memptrs_desc, 0, 0,
			   sizeof(struct kgsl_rbmemptrs));

	kgsl_sharedmem_set(&rb->buffer_desc, 0, 0xAA,
			   (rb->sizedwords << 2));

	if (adreno_is_a2xx(adreno_dev)) {
		adreno_regwrite(device, REG_CP_RB_WPTR_BASE,
			(rb->memptrs_desc.gpuaddr
			+ GSL_RB_MEMPTRS_WPTRPOLL_OFFSET));

		/* setup WPTR delay */
		adreno_regwrite(device, REG_CP_RB_WPTR_DELAY,
			0 /*0x70000010 */);
	}

	/*setup REG_CP_RB_CNTL */
	adreno_regread(device, REG_CP_RB_CNTL, &rb_cntl);
	cp_rb_cntl.val = rb_cntl;

	/*
	 * The size of the ringbuffer in the hardware is the log2
	 * representation of the size in quadwords (sizedwords / 2)
	 */
	cp_rb_cntl.f.rb_bufsz = ilog2(rb->sizedwords >> 1);

	/*
	 * Specify the quadwords to read before updating mem RPTR.
	 * Like above, pass the log2 representation of the blocksize
	 * in quadwords.
	*/
	cp_rb_cntl.f.rb_blksz = ilog2(KGSL_RB_BLKSIZE >> 3);

	if (adreno_is_a2xx(adreno_dev)) {
		/* WPTR polling */
		cp_rb_cntl.f.rb_poll_en = GSL_RB_CNTL_POLL_EN;
	}

	/* mem RPTR writebacks */
	cp_rb_cntl.f.rb_no_update =  GSL_RB_CNTL_NO_UPDATE;

	adreno_regwrite(device, REG_CP_RB_CNTL, cp_rb_cntl.val);

	adreno_regwrite(device, REG_CP_RB_BASE, rb->buffer_desc.gpuaddr);

	adreno_regwrite(device, REG_CP_RB_RPTR_ADDR,
			     rb->memptrs_desc.gpuaddr +
			     GSL_RB_MEMPTRS_RPTR_OFFSET);

	if (adreno_is_a2xx(adreno_dev)) {
		/* explicitly clear all cp interrupts */
		adreno_regwrite(device, REG_CP_INT_ACK, 0xFFFFFFFF);
	}

	/* setup scratch/timestamp */
	adreno_regwrite(device, REG_SCRATCH_ADDR, device->memstore.gpuaddr +
			     KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
				     soptimestamp));

	adreno_regwrite(device, REG_SCRATCH_UMSK,
			     GSL_RB_MEMPTRS_SCRATCH_MASK);

	/* load the CP ucode */

	status = adreno_ringbuffer_load_pm4_ucode(device);
	if (status != 0)
		return status;

	/* load the prefetch parser ucode */
	status = adreno_ringbuffer_load_pfp_ucode(device);
	if (status != 0)
		return status;

	rb->rptr = 0;
	rb->wptr = 0;

	/* clear ME_HALT to start micro engine */
	adreno_regwrite(device, REG_CP_ME_CNTL, 0);

	/* ME init is GPU specific, so jump into the sub-function */
	adreno_dev->gpudev->rb_init(adreno_dev, rb);

	/* idle device to validate ME INIT */
	status = adreno_idle(device);

	if (status == 0)
		rb->flags |= KGSL_FLAGS_STARTED;

	return status;
}
int adreno_ringbuffer_start(struct adreno_ringbuffer *rb, unsigned int init_ram)
{
	int status;
	/*cp_rb_cntl_u cp_rb_cntl; */
	union reg_cp_rb_cntl cp_rb_cntl;
	unsigned int *cmds, rb_cntl;
	struct kgsl_device *device = rb->device;
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
	uint cmds_gpu;

	if (rb->flags & KGSL_FLAGS_STARTED)
		return 0;

	if (init_ram) {
		rb->timestamp = 0;
		GSL_RB_INIT_TIMESTAMP(rb);
	}

	kgsl_sharedmem_set(&rb->memptrs_desc, 0, 0,
			   sizeof(struct kgsl_rbmemptrs));

	kgsl_sharedmem_set(&rb->buffer_desc, 0, 0xAA,
			   (rb->sizedwords << 2));

	adreno_regwrite(device, REG_CP_RB_WPTR_BASE,
			     (rb->memptrs_desc.gpuaddr
			      + GSL_RB_MEMPTRS_WPTRPOLL_OFFSET));

	/* setup WPTR delay */
	adreno_regwrite(device, REG_CP_RB_WPTR_DELAY, 0 /*0x70000010 */);

	/*setup REG_CP_RB_CNTL */
	adreno_regread(device, REG_CP_RB_CNTL, &rb_cntl);
	cp_rb_cntl.val = rb_cntl;

	/*
	 * The size of the ringbuffer in the hardware is the log2
	 * representation of the size in quadwords (sizedwords / 2)
	 */
	cp_rb_cntl.f.rb_bufsz = ilog2(rb->sizedwords >> 1);

	/*
	 * Specify the quadwords to read before updating mem RPTR.
	 * Like above, pass the log2 representation of the blocksize
	 * in quadwords.
	*/
	cp_rb_cntl.f.rb_blksz = ilog2(KGSL_RB_BLKSIZE >> 3);

	cp_rb_cntl.f.rb_poll_en = GSL_RB_CNTL_POLL_EN; /* WPTR polling */
	/* mem RPTR writebacks */
	cp_rb_cntl.f.rb_no_update =  GSL_RB_CNTL_NO_UPDATE;

	adreno_regwrite(device, REG_CP_RB_CNTL, cp_rb_cntl.val);

	adreno_regwrite(device, REG_CP_RB_BASE, rb->buffer_desc.gpuaddr);

	adreno_regwrite(device, REG_CP_RB_RPTR_ADDR,
			     rb->memptrs_desc.gpuaddr +
			     GSL_RB_MEMPTRS_RPTR_OFFSET);

	/* explicitly clear all cp interrupts */
	adreno_regwrite(device, REG_CP_INT_ACK, 0xFFFFFFFF);

	/* setup scratch/timestamp */
	adreno_regwrite(device, REG_SCRATCH_ADDR,
			     device->memstore.gpuaddr +
			     KGSL_DEVICE_MEMSTORE_OFFSET(soptimestamp));

	adreno_regwrite(device, REG_SCRATCH_UMSK,
			     GSL_RB_MEMPTRS_SCRATCH_MASK);

	/* update the eoptimestamp field with the last retired timestamp */
	kgsl_sharedmem_writel(&device->memstore,
			     KGSL_DEVICE_MEMSTORE_OFFSET(eoptimestamp),
			     rb->timestamp);

	/* load the CP ucode */

	status = adreno_ringbuffer_load_pm4_ucode(device);
	if (status != 0)
		return status;

	/* load the prefetch parser ucode */
	status = adreno_ringbuffer_load_pfp_ucode(device);
	if (status != 0)
		return status;

	adreno_regwrite(device, REG_CP_QUEUE_THRESHOLDS, 0x000C0804);

	rb->rptr = 0;
	rb->wptr = 0;

	/* clear ME_HALT to start micro engine */
	adreno_regwrite(device, REG_CP_ME_CNTL, 0);

	/* ME_INIT */
	cmds = adreno_ringbuffer_allocspace(rb, 19);
	cmds_gpu = rb->buffer_desc.gpuaddr + sizeof(uint)*(rb->wptr-19);

	GSL_RB_WRITE(cmds, cmds_gpu, CP_HDR_ME_INIT);
	/* All fields present (bits 9:0) */
	GSL_RB_WRITE(cmds, cmds_gpu, 0x000003ff);
	/* Disable/Enable Real-Time Stream processing (present but ignored) */
	GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
	/* Enable (2D <-> 3D) implicit synchronization (present but ignored) */
	GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);

	GSL_RB_WRITE(cmds, cmds_gpu,
		SUBBLOCK_OFFSET(REG_RB_SURFACE_INFO));
	GSL_RB_WRITE(cmds, cmds_gpu,
		SUBBLOCK_OFFSET(REG_PA_SC_WINDOW_OFFSET));
	GSL_RB_WRITE(cmds, cmds_gpu,
		SUBBLOCK_OFFSET(REG_VGT_MAX_VTX_INDX));
	GSL_RB_WRITE(cmds, cmds_gpu,
		SUBBLOCK_OFFSET(REG_SQ_PROGRAM_CNTL));
	GSL_RB_WRITE(cmds, cmds_gpu,
		SUBBLOCK_OFFSET(REG_RB_DEPTHCONTROL));
	GSL_RB_WRITE(cmds, cmds_gpu,
		SUBBLOCK_OFFSET(REG_PA_SU_POINT_SIZE));
	GSL_RB_WRITE(cmds, cmds_gpu,
		SUBBLOCK_OFFSET(REG_PA_SC_LINE_CNTL));
	GSL_RB_WRITE(cmds, cmds_gpu,
		SUBBLOCK_OFFSET(REG_PA_SU_POLY_OFFSET_FRONT_SCALE));

	/* Instruction memory size: */
	GSL_RB_WRITE(cmds, cmds_gpu,
		     (adreno_encode_istore_size(adreno_dev)
		      | adreno_dev->pix_shader_start));
	/* Maximum Contexts */
	GSL_RB_WRITE(cmds, cmds_gpu, 0x00000001);
	/* Write Confirm Interval and The CP will wait the
	* wait_interval * 16 clocks between polling  */
	GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);

	/* NQ and External Memory Swap */
	GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
	/* Protected mode error checking */
	GSL_RB_WRITE(cmds, cmds_gpu, GSL_RB_PROTECTED_MODE_CONTROL);
	/* Disable header dumping and Header dump address */
	GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
	/* Header dump size */
	GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);

	adreno_ringbuffer_submit(rb);

	/* idle device to validate ME INIT */
	status = adreno_idle(device);

	if (status == 0)
		rb->flags |= KGSL_FLAGS_STARTED;

	return status;
}
int adreno_ringbuffer_start(struct adreno_ringbuffer *rb, unsigned int init_ram)
{
	int status;
	
	union reg_cp_rb_cntl cp_rb_cntl;
	unsigned int rb_cntl;
	struct kgsl_device *device = rb->device;
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);

	if (rb->flags & KGSL_FLAGS_STARTED)
		return 0;

	if (init_ram)
		rb->timestamp[KGSL_MEMSTORE_GLOBAL] = 0;

	kgsl_sharedmem_set(&rb->memptrs_desc, 0, 0,
			   sizeof(struct kgsl_rbmemptrs));

	kgsl_sharedmem_set(&rb->buffer_desc, 0, 0xAA,
			   (rb->sizedwords << 2));

	if (adreno_is_a2xx(adreno_dev)) {
		adreno_regwrite(device, REG_CP_RB_WPTR_BASE,
			(rb->memptrs_desc.gpuaddr
			+ GSL_RB_MEMPTRS_WPTRPOLL_OFFSET));

		
		adreno_regwrite(device, REG_CP_RB_WPTR_DELAY,
			0 );
	}

	
	adreno_regread(device, REG_CP_RB_CNTL, &rb_cntl);
	cp_rb_cntl.val = rb_cntl;

	cp_rb_cntl.f.rb_bufsz = ilog2(rb->sizedwords >> 1);

	cp_rb_cntl.f.rb_blksz = ilog2(KGSL_RB_BLKSIZE >> 3);

	if (adreno_is_a2xx(adreno_dev)) {
		
		cp_rb_cntl.f.rb_poll_en = GSL_RB_CNTL_POLL_EN;
	}

	
	cp_rb_cntl.f.rb_no_update =  GSL_RB_CNTL_NO_UPDATE;

	adreno_regwrite(device, REG_CP_RB_CNTL, cp_rb_cntl.val);

	adreno_regwrite(device, REG_CP_RB_BASE, rb->buffer_desc.gpuaddr);

	adreno_regwrite(device, REG_CP_RB_RPTR_ADDR,
			     rb->memptrs_desc.gpuaddr +
			     GSL_RB_MEMPTRS_RPTR_OFFSET);

	if (adreno_is_a3xx(adreno_dev)) {
		
		adreno_regwrite(device, A3XX_CP_PROTECT_CTRL, 0x00000007);

		
		adreno_regwrite(device, A3XX_CP_PROTECT_REG_0, 0x63000040);
		adreno_regwrite(device, A3XX_CP_PROTECT_REG_1, 0x62000080);
		adreno_regwrite(device, A3XX_CP_PROTECT_REG_2, 0x600000CC);
		adreno_regwrite(device, A3XX_CP_PROTECT_REG_3, 0x60000108);
		adreno_regwrite(device, A3XX_CP_PROTECT_REG_4, 0x64000140);
		adreno_regwrite(device, A3XX_CP_PROTECT_REG_5, 0x66000400);

		
		adreno_regwrite(device, A3XX_CP_PROTECT_REG_6, 0x65000700);
		adreno_regwrite(device, A3XX_CP_PROTECT_REG_7, 0x610007D8);
		adreno_regwrite(device, A3XX_CP_PROTECT_REG_8, 0x620007E0);
		adreno_regwrite(device, A3XX_CP_PROTECT_REG_9, 0x61001178);
		adreno_regwrite(device, A3XX_CP_PROTECT_REG_A, 0x64001180);

		
		adreno_regwrite(device, A3XX_CP_PROTECT_REG_B, 0x60003300);

		
		adreno_regwrite(device, A3XX_CP_PROTECT_REG_C, 0x6B00C000);
	}

	if (adreno_is_a2xx(adreno_dev)) {
		
		adreno_regwrite(device, REG_CP_INT_ACK, 0xFFFFFFFF);
	}

	
	adreno_regwrite(device, REG_SCRATCH_ADDR, device->memstore.gpuaddr +
			     KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
				     soptimestamp));

	adreno_regwrite(device, REG_SCRATCH_UMSK,
			     GSL_RB_MEMPTRS_SCRATCH_MASK);

	

	status = adreno_ringbuffer_load_pm4_ucode(device);
	if (status != 0)
		return status;

	
	status = adreno_ringbuffer_load_pfp_ucode(device);
	if (status != 0)
		return status;

	
	if (adreno_is_a305(adreno_dev) || adreno_is_a320(adreno_dev))
		adreno_regwrite(device, REG_CP_QUEUE_THRESHOLDS, 0x000E0602);

	rb->rptr = 0;
	rb->wptr = 0;

	
	adreno_regwrite(device, REG_CP_ME_CNTL, 0);

	
	adreno_dev->gpudev->rb_init(adreno_dev, rb);

	
	status = adreno_idle(device, KGSL_TIMEOUT_DEFAULT);

	if (status == 0)
		rb->flags |= KGSL_FLAGS_STARTED;

	return status;
}