Merge "remoteproc: qcom: pas: Use SOCCP_SPARE register to check D0 state"
This commit is contained in:
commit
f91dd38c9a
@ -33,7 +33,6 @@ struct qcom_q6v5 {
|
||||
int ready_irq;
|
||||
int handover_irq;
|
||||
int stop_irq;
|
||||
int active_state_ack_irq;
|
||||
|
||||
struct rproc_subdev *ssr_subdev;
|
||||
|
||||
@ -43,7 +42,6 @@ struct qcom_q6v5 {
|
||||
|
||||
struct completion start_done;
|
||||
struct completion stop_done;
|
||||
struct completion running_ack;
|
||||
|
||||
int crash_reason;
|
||||
|
||||
|
@ -61,6 +61,7 @@ static bool recovery_set_cb;
|
||||
#define SOCCP_SLEEP_US 100
|
||||
#define SOCCP_TIMEOUT_US 10000
|
||||
#define SOCCP_STATE_MASK 0x600
|
||||
#define SPARE_REG_SOCCP_D0 0x1
|
||||
#define SOCCP_D0 0x2
|
||||
#define SOCCP_D1 0x4
|
||||
#define SOCCP_D3 0x8
|
||||
@ -164,7 +165,8 @@ struct qcom_adsp {
|
||||
unsigned int wake_bit;
|
||||
unsigned int sleep_bit;
|
||||
int current_users;
|
||||
void *config_addr;
|
||||
void *tcsr_addr;
|
||||
void *spare_reg_addr;
|
||||
bool check_status;
|
||||
};
|
||||
|
||||
@ -814,48 +816,37 @@ static int adsp_start(struct rproc *rproc)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static irqreturn_t soccp_running_ack(int irq, void *data)
|
||||
{
|
||||
struct qcom_q6v5 *q6v5 = data;
|
||||
|
||||
complete(&q6v5->running_ack);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* rproc_config_check() - Check back the config register
|
||||
* @state: new state of the rproc
|
||||
*
|
||||
* Call this function after there has been a request to change of
|
||||
* state of rproc. This function takes in the new state to which the
|
||||
* rproc has transitioned, and poll the WFI status register to check
|
||||
* if the state request change has been accepted successfully by the
|
||||
* rproc. The poll is timed out after 10 milliseconds.
|
||||
* Polled read on a register till with a 5ms timeout and 100-200Us interval.
|
||||
* Returns immediately if the expected value is read back from the addr.
|
||||
*
|
||||
* Return: 0 if the WFI status register reflects the requested state.
|
||||
* state: new state of the rproc
|
||||
*
|
||||
* addr: Address to poll on
|
||||
*
|
||||
* return: 0 if the expected value is read back from the address
|
||||
* -ETIMEDOUT is the value was not read in 5ms
|
||||
*/
|
||||
static int rproc_config_check(struct qcom_adsp *adsp, u32 state)
|
||||
static int rproc_config_check(struct qcom_adsp *adsp, u32 state, void *addr)
|
||||
{
|
||||
unsigned int retry_num = 50;
|
||||
u32 val;
|
||||
|
||||
do {
|
||||
usleep_range(SOCCP_SLEEP_US, SOCCP_SLEEP_US + 100);
|
||||
/* Making sure the mem mapped io is read correctly*/
|
||||
dsb(sy);
|
||||
val = readl(adsp->config_addr);
|
||||
if ((state == SOCCP_D0) && (val == SOCCP_D1))
|
||||
return 0;
|
||||
} while (val != state && --retry_num);
|
||||
val = readl(addr);
|
||||
} while (!(val && state) && --retry_num);
|
||||
|
||||
return (val == state) ? 0 : -ETIMEDOUT;
|
||||
return (val & state) ? 0 : -ETIMEDOUT;
|
||||
}
|
||||
static int rproc_config_check_atomic(struct qcom_adsp *adsp, u32 state)
|
||||
static int rproc_config_check_atomic(struct qcom_adsp *adsp, u32 state, void *addr)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
return readx_poll_timeout_atomic(readl, adsp->config_addr, val,
|
||||
return readx_poll_timeout_atomic(readl, addr, val,
|
||||
val == state, SOCCP_SLEEP_US, SOCCP_TIMEOUT_US);
|
||||
}
|
||||
|
||||
@ -871,31 +862,49 @@ static int rproc_find_status_register(struct qcom_adsp *adsp)
|
||||
{
|
||||
struct device_node *tcsr;
|
||||
struct device_node *np = adsp->dev->of_node;
|
||||
u32 offset;
|
||||
struct resource res;
|
||||
u32 offset, addr;
|
||||
int ret;
|
||||
void *tcsr_base;
|
||||
|
||||
tcsr = of_parse_phandle(np, "soccp-config", 0);
|
||||
tcsr = of_parse_phandle(np, "soccp-tcsr", 0);
|
||||
if (!tcsr) {
|
||||
dev_err(adsp->dev, "Unable to find the soccp config register\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
tcsr_base = of_iomap(tcsr, 0);
|
||||
ret = of_address_to_resource(tcsr, 0, &res);
|
||||
of_node_put(tcsr);
|
||||
if (ret) {
|
||||
dev_err(adsp->dev, "Unable to find the tcsr base addr\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
tcsr_base = ioremap_wc(res.start, resource_size(&res));
|
||||
if (!tcsr_base) {
|
||||
dev_err(adsp->dev, "Unable to find the tcsr base addr\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32_index(np, "soccp-config", 1, &offset);
|
||||
ret = of_property_read_u32_index(np, "soccp-tcsr", 1, &offset);
|
||||
if (ret < 0) {
|
||||
dev_err(adsp->dev, "Unable to find the tcsr offset addr\n");
|
||||
dev_err(adsp->dev, "Unable to find the tcsr config offset addr\n");
|
||||
iounmap(tcsr_base);
|
||||
return ret;
|
||||
}
|
||||
adsp->tcsr_addr = tcsr_base + offset;
|
||||
|
||||
adsp->config_addr = tcsr_base + offset;
|
||||
ret = of_property_read_u32(np, "soccp-spare", &addr);
|
||||
if (!addr) {
|
||||
dev_err(adsp->dev, "Unable to find the running config register\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
adsp->spare_reg_addr = ioremap_wc(addr, 4);
|
||||
if (!adsp->spare_reg_addr) {
|
||||
dev_err(adsp->dev, "Unable to find the tcsr base addr\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -971,8 +980,6 @@ int rproc_set_state(struct rproc *rproc, bool state)
|
||||
goto soccp_out;
|
||||
}
|
||||
|
||||
reinit_completion(&(adsp->q6v5.running_ack));
|
||||
|
||||
ret = qcom_smem_state_update_bits(adsp->wake_state,
|
||||
SOCCP_STATE_MASK,
|
||||
BIT(adsp->wake_bit));
|
||||
@ -981,22 +988,25 @@ int rproc_set_state(struct rproc *rproc, bool state)
|
||||
goto soccp_out;
|
||||
}
|
||||
|
||||
ret = rproc_config_check(adsp, SOCCP_D0);
|
||||
ret = rproc_config_check(adsp, SOCCP_D0 | SOCCP_D1, adsp->tcsr_addr);
|
||||
if (ret) {
|
||||
dsb(sy);
|
||||
dev_err(adsp->dev, "%s requested D3->D0: soccp failed to update tcsr val=%d\n",
|
||||
current->comm, readl(adsp->config_addr));
|
||||
current->comm, readl(adsp->tcsr_addr));
|
||||
goto soccp_out;
|
||||
}
|
||||
|
||||
ret = wait_for_completion_timeout(&adsp->q6v5.running_ack, msecs_to_jiffies(5));
|
||||
if (!ret) {
|
||||
dev_err(adsp->dev, "%s requested D3->D0: failed to get wake ack\n",
|
||||
current->comm);
|
||||
ret = -ETIMEDOUT;
|
||||
ret = rproc_config_check(adsp, SPARE_REG_SOCCP_D0, adsp->spare_reg_addr);
|
||||
if (ret) {
|
||||
ret = qcom_smem_state_update_bits(adsp->wake_state,
|
||||
SOCCP_STATE_MASK,
|
||||
!BIT(adsp->wake_bit));
|
||||
if (ret)
|
||||
dev_err(adsp->dev, "failed to clear smem bits after a failed D0 request\n");
|
||||
|
||||
dev_err(adsp->dev, "%s requested D3->D0: soccp failed to update spare reg val=%d\n",
|
||||
current->comm, readl(adsp->spare_reg_addr));
|
||||
goto soccp_out;
|
||||
} else
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
adsp->current_users = 1;
|
||||
} else {
|
||||
@ -1013,11 +1023,16 @@ int rproc_set_state(struct rproc *rproc, bool state)
|
||||
goto soccp_out;
|
||||
}
|
||||
|
||||
ret = rproc_config_check(adsp, SOCCP_D3);
|
||||
ret = rproc_config_check(adsp, SOCCP_D3, adsp->tcsr_addr);
|
||||
if (ret) {
|
||||
dsb(sy);
|
||||
ret = qcom_smem_state_update_bits(adsp->sleep_state,
|
||||
SOCCP_STATE_MASK,
|
||||
!BIT(adsp->sleep_bit));
|
||||
if (ret)
|
||||
dev_err(adsp->dev, "failed to clear smem bits after a failed D3 request\n");
|
||||
|
||||
dev_err(adsp->dev, "%s requested D0->D3 failed: TCSR value:%d\n",
|
||||
current->comm, readl(adsp->config_addr));
|
||||
current->comm, readl(adsp->tcsr_addr));
|
||||
goto soccp_out;
|
||||
}
|
||||
disable_regulators(adsp);
|
||||
@ -1062,7 +1077,11 @@ static int rproc_panic_handler(struct notifier_block *this,
|
||||
dev_err(adsp->dev, "failed to update smem bits for D3 to D0\n");
|
||||
goto done;
|
||||
}
|
||||
ret = rproc_config_check_atomic(adsp, SOCCP_D0);
|
||||
ret = rproc_config_check_atomic(adsp, SOCCP_D0, adsp->tcsr_addr);
|
||||
if (ret)
|
||||
dev_err(adsp->dev, "failed to change to D0\n");
|
||||
|
||||
ret = rproc_config_check_atomic(adsp, SPARE_REG_SOCCP_D0, adsp->spare_reg_addr);
|
||||
if (ret)
|
||||
dev_err(adsp->dev, "failed to change to D0\n");
|
||||
done:
|
||||
@ -1075,14 +1094,13 @@ static void qcom_pas_handover(struct qcom_q6v5 *q6v5)
|
||||
int ret;
|
||||
|
||||
if (adsp->check_status) {
|
||||
ret = rproc_config_check(adsp, SOCCP_D3);
|
||||
dsb(sy);
|
||||
ret = rproc_config_check(adsp, SOCCP_D3, adsp->tcsr_addr);
|
||||
if (ret)
|
||||
dev_err(adsp->dev, "state not changed in handover TCSR val = %d\n",
|
||||
readl(adsp->config_addr));
|
||||
readl(adsp->tcsr_addr));
|
||||
else
|
||||
dev_info(adsp->dev, "state changed in handover for soccp! TCSR val = %d\n",
|
||||
readl(adsp->config_addr));
|
||||
readl(adsp->tcsr_addr));
|
||||
}
|
||||
disable_regulators(adsp);
|
||||
clk_disable_unprepare(adsp->aggre2_clk);
|
||||
@ -1736,26 +1754,9 @@ static int adsp_probe(struct platform_device *pdev)
|
||||
goto detach_proxy_pds;
|
||||
}
|
||||
|
||||
adsp->q6v5.active_state_ack_irq = platform_get_irq_byname(pdev, "wake-ack");
|
||||
if (adsp->q6v5.active_state_ack_irq < 0) {
|
||||
dev_err(&pdev->dev, "failed to acquire readyack irq\n");
|
||||
goto detach_proxy_pds;
|
||||
}
|
||||
|
||||
ret = devm_request_threaded_irq(&pdev->dev, adsp->q6v5.active_state_ack_irq,
|
||||
NULL, soccp_running_ack,
|
||||
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
|
||||
"qcom_q6v5_pas", &adsp->q6v5);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to acquire ready ack IRQ\n");
|
||||
goto detach_proxy_pds;
|
||||
}
|
||||
|
||||
mutex_init(&adsp->adsp_lock);
|
||||
|
||||
init_completion(&(adsp->q6v5.running_ack));
|
||||
adsp->current_users = 0;
|
||||
|
||||
}
|
||||
|
||||
qcom_q6v5_register_ssr_subdev(&adsp->q6v5, &adsp->ssr_subdev.subdev);
|
||||
|
Loading…
Reference in New Issue
Block a user