Пример #1
0
int __msm_adsp_write(struct msm_adsp_module *module, unsigned dsp_queue_addr,
                     void *cmd_buf, size_t cmd_size)
{
    uint32_t ctrl_word;
    uint32_t dsp_q_addr;
    uint32_t dsp_addr;
    uint32_t cmd_id = 0;
    int cnt = 0;
    int ret_status = 0;
    unsigned long flags;
    struct adsp_info *info;

    if (!module || !cmd_buf) {
        MM_ERR("Called with NULL parameters\n");
        return -EINVAL;
    }
    info = module->info;
    spin_lock_irqsave(&adsp_write_lock, flags);

    if (module->state != ADSP_STATE_ENABLED) {
        spin_unlock_irqrestore(&adsp_write_lock, flags);
        MM_ERR("module %s not enabled before write\n", module->name);
        return -ENODEV;
    }
    if (adsp_validate_module(module->id)) {
        spin_unlock_irqrestore(&adsp_write_lock, flags);
        MM_ERR("module id validation failed %s  %d\n",
               module->name, module->id);
        return -ENXIO;
    }
    if (dsp_queue_addr >= QDSP_MAX_NUM_QUEUES) {
        spin_unlock_irqrestore(&adsp_write_lock, flags);
        MM_ERR("Invalid Queue Index: %d\n", dsp_queue_addr);
        return -ENXIO;
    }
    if (adsp_validate_queue(module->id, dsp_queue_addr, cmd_size)) {
        spin_unlock_irqrestore(&adsp_write_lock, flags);
        return -EINVAL;
    }
    dsp_q_addr = adsp_get_queue_offset(info, dsp_queue_addr);
    dsp_q_addr &= ADSP_RTOS_WRITE_CTRL_WORD_DSP_ADDR_M;

    /* Poll until the ADSP is ready to accept a command.
     * Wait for 100us, return error if it's not responding.
     * If this returns an error, we need to disable ALL modules and
     * then retry.
     */
    while (((ctrl_word = readl(info->write_ctrl)) &
            ADSP_RTOS_WRITE_CTRL_WORD_READY_M) !=
            ADSP_RTOS_WRITE_CTRL_WORD_READY_V) {
        if (cnt > 50) {
            MM_ERR("timeout waiting for DSP write ready\n");
            ret_status = -EIO;
            goto fail;
        }
        MM_DBG("waiting for DSP write ready\n");
        udelay(2);
        cnt++;
    }

    /* Set the mutex bits */
    ctrl_word &= ~(ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_M);
    ctrl_word |=  ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_NAVAIL_V;

    /* Clear the command bits */
    ctrl_word &= ~(ADSP_RTOS_WRITE_CTRL_WORD_CMD_M);

    /* Set the queue address bits */
    ctrl_word &= ~(ADSP_RTOS_WRITE_CTRL_WORD_DSP_ADDR_M);
    ctrl_word |= dsp_q_addr;

    writel(ctrl_word, info->write_ctrl);

    /* Generate an interrupt to the DSP.  This notifies the DSP that
     * we are about to send a command on this particular queue.  The
     * DSP will in response change its state.
     */
    writel(1, info->send_irq);

    /* Poll until the adsp responds to the interrupt; this does not
     * generate an interrupt from the adsp.  This should happen within
     * 5ms.
     */
    cnt = 0;
    while ((readl(info->write_ctrl) &
            ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_M) ==
            ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_NAVAIL_V) {
        if (cnt > 2500) {
            MM_ERR("timeout waiting for adsp ack\n");
            ret_status = -EIO;
            goto fail;
        }
        udelay(2);
        cnt++;
    }

    /* Read the ctrl word */
    ctrl_word = readl(info->write_ctrl);

    if ((ctrl_word & ADSP_RTOS_WRITE_CTRL_WORD_STATUS_M) !=
            ADSP_RTOS_WRITE_CTRL_WORD_NO_ERR_V) {
        ret_status = -EAGAIN;
        goto fail;
    } else {
        /* No error */
        /* Get the DSP buffer address */
        dsp_addr = (ctrl_word & ADSP_RTOS_WRITE_CTRL_WORD_DSP_ADDR_M) +
                   (uint32_t)MSM_AD5_BASE;

        if (dsp_addr < (uint32_t)(MSM_AD5_BASE + QDSP_RAMC_OFFSET)) {
            uint16_t *buf_ptr = (uint16_t *) cmd_buf;
            uint16_t *dsp_addr16 = (uint16_t *)dsp_addr;
            cmd_size /= sizeof(uint16_t);

            /* Save the command ID */
            cmd_id = (uint32_t) buf_ptr[0];

            /* Copy the command to DSP memory */
            cmd_size++;
            while (--cmd_size)
                *dsp_addr16++ = *buf_ptr++;
        } else {
            uint32_t *buf_ptr = (uint32_t *) cmd_buf;
            uint32_t *dsp_addr32 = (uint32_t *)dsp_addr;
            cmd_size /= sizeof(uint32_t);

            /* Save the command ID */
            cmd_id = buf_ptr[0];

            cmd_size++;
            while (--cmd_size)
                *dsp_addr32++ = *buf_ptr++;
        }

        /* Set the mutex bits */
        ctrl_word &= ~(ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_M);
        ctrl_word |=  ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_NAVAIL_V;

        /* Set the command bits to write done */
        ctrl_word &= ~(ADSP_RTOS_WRITE_CTRL_WORD_CMD_M);
        ctrl_word |= ADSP_RTOS_WRITE_CTRL_WORD_CMD_WRITE_DONE_V;

        /* Set the queue address bits */
        ctrl_word &= ~(ADSP_RTOS_WRITE_CTRL_WORD_DSP_ADDR_M);
        ctrl_word |= dsp_q_addr;

        writel(ctrl_word, info->write_ctrl);

        /* Generate an interrupt to the DSP.  It does not respond with
         * an interrupt, and we do not need to wait for it to
         * acknowledge, because it will hold the mutex lock until it's
         * ready to receive more commands again.
         */
        writel(1, info->send_irq);

        module->num_commands++;
    } /* Ctrl word status bits were 00, no error in the ctrl word */

fail:
    spin_unlock_irqrestore(&adsp_write_lock, flags);
    return ret_status;
}
Пример #2
0
int __msm_adsp_write(struct msm_adsp_module *module, unsigned dsp_queue_addr,
		   void *cmd_buf, size_t cmd_size)
{
	uint32_t ctrl_word;
	uint32_t dsp_q_addr;
	uint32_t dsp_addr;
	uint32_t cmd_id = 0;
	int cnt = 0;
	int ret_status = 0;
	unsigned long flags;
	struct adsp_info *info;

	if (!module || !cmd_buf) {
		MM_ERR("Called with NULL parameters\n");
		return -EINVAL;
	}
	info = module->info;
	spin_lock_irqsave(&adsp_write_lock, flags);

	if (module->state != ADSP_STATE_ENABLED) {
		spin_unlock_irqrestore(&adsp_write_lock, flags);
		MM_ERR("module %s not enabled before write\n", module->name);
		return -ENODEV;
	}
	if (adsp_validate_module(module->id)) {
		spin_unlock_irqrestore(&adsp_write_lock, flags);
		MM_ERR("module id validation failed %s  %d\n",
				module->name, module->id);
		return -ENXIO;
	}
	if (dsp_queue_addr >= QDSP_MAX_NUM_QUEUES) {
		spin_unlock_irqrestore(&adsp_write_lock, flags);
		MM_ERR("Invalid Queue Index: %d\n", dsp_queue_addr);
		return -ENXIO;
	}
	if (adsp_validate_queue(module->id, dsp_queue_addr, cmd_size)) {
		spin_unlock_irqrestore(&adsp_write_lock, flags);
		return -EINVAL;
	}
	dsp_q_addr = adsp_get_queue_offset(info, dsp_queue_addr);
	dsp_q_addr &= ADSP_RTOS_WRITE_CTRL_WORD_DSP_ADDR_M;

	
	while (((ctrl_word = readl(info->write_ctrl)) &
		ADSP_RTOS_WRITE_CTRL_WORD_READY_M) !=
		ADSP_RTOS_WRITE_CTRL_WORD_READY_V) {
		if (cnt > 50) {
			MM_ERR("timeout waiting for DSP write ready\n");
			ret_status = -EIO;
			goto fail;
		}
		MM_DBG("waiting for DSP write ready\n");
		udelay(2);
		cnt++;
	}

	
	ctrl_word &= ~(ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_M);
	ctrl_word |=  ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_NAVAIL_V;

	
	ctrl_word &= ~(ADSP_RTOS_WRITE_CTRL_WORD_CMD_M);

	
	ctrl_word &= ~(ADSP_RTOS_WRITE_CTRL_WORD_DSP_ADDR_M);
	ctrl_word |= dsp_q_addr;

	writel(ctrl_word, info->write_ctrl);

	
	writel(1, info->send_irq);

	
	cnt = 0;
	while ((readl(info->write_ctrl) &
		ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_M) ==
		ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_NAVAIL_V) {
		if (cnt > 2500) {
			MM_ERR("timeout waiting for adsp ack\n");
			ret_status = -EIO;
			goto fail;
		}
		udelay(2);
		cnt++;
	}

	
	ctrl_word = readl(info->write_ctrl);

	if ((ctrl_word & ADSP_RTOS_WRITE_CTRL_WORD_STATUS_M) !=
	    ADSP_RTOS_WRITE_CTRL_WORD_NO_ERR_V) {
		ret_status = -EAGAIN;
		goto fail;
	} else {
		
		
		dsp_addr = (ctrl_word & ADSP_RTOS_WRITE_CTRL_WORD_DSP_ADDR_M) +
			   (uint32_t)MSM_AD5_BASE;

		if (dsp_addr < (uint32_t)(MSM_AD5_BASE + QDSP_RAMC_OFFSET)) {
			uint16_t *buf_ptr = (uint16_t *) cmd_buf;
			uint16_t *dsp_addr16 = (uint16_t *)dsp_addr;
			cmd_size /= sizeof(uint16_t);

			
			cmd_id = (uint32_t) buf_ptr[0];

			
			cmd_size++;
			while (--cmd_size)
				*dsp_addr16++ = *buf_ptr++;
		} else {
			uint32_t *buf_ptr = (uint32_t *) cmd_buf;
			uint32_t *dsp_addr32 = (uint32_t *)dsp_addr;
			cmd_size /= sizeof(uint32_t);

			
			cmd_id = buf_ptr[0];

			cmd_size++;
			while (--cmd_size)
				*dsp_addr32++ = *buf_ptr++;
		}

		
		ctrl_word &= ~(ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_M);
		ctrl_word |=  ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_NAVAIL_V;

		
		ctrl_word &= ~(ADSP_RTOS_WRITE_CTRL_WORD_CMD_M);
		ctrl_word |= ADSP_RTOS_WRITE_CTRL_WORD_CMD_WRITE_DONE_V;

		
		ctrl_word &= ~(ADSP_RTOS_WRITE_CTRL_WORD_DSP_ADDR_M);
		ctrl_word |= dsp_q_addr;

		writel(ctrl_word, info->write_ctrl);

		
		writel(1, info->send_irq);

		module->num_commands++;
	} 

fail:
	spin_unlock_irqrestore(&adsp_write_lock, flags);
	return ret_status;
}