Merge "remoteproc: qcom: pas: Use SOCCP_SPARE register to check D0 state"

This commit is contained in:
QCTECMDR Service 2024-08-26 07:45:38 -07:00 committed by Gerrit - the friendly Code Review server
commit f91dd38c9a
2 changed files with 70 additions and 71 deletions

View File

@ -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;

View File

@ -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);