@@ -28,6 +28,11 @@ static const struct of_device_id ath12k_ahb_of_match[] = {
MODULE_DEVICE_TABLE(of, ath12k_ahb_of_match);
#define ATH12K_IRQ_CE0_OFFSET 4
+#define ATH12K_MAX_UPDS 1
+#define ATH12K_UPD_IRQ_WRD_LEN 18
+static const char ath12k_userpd_irq[][9] = {"spawn",
+ "ready",
+ "stop-ack"};
static const char *irq_name[ATH12K_IRQ_NUM_MAX] = {
"misc-pulse1",
@@ -608,6 +613,78 @@ static const struct ath12k_hif_ops ath12k_ahb_hif_ops_ipq5332 = {
.map_service_to_pipe = ath12k_ahb_map_service_to_pipe,
};
+static irqreturn_t ath12k_userpd_irq_handler(int irq, void *data)
+{
+ struct ath12k_base *ab = data;
+ struct ath12k_ahb *ab_ahb = ath12k_ab_to_ahb(ab);
+
+ if (irq == ab_ahb->userpd_irq_num[ATH12K_USERPD_SPAWN_IRQ]) {
+ complete(&ab_ahb->userpd_spawned);
+ } else if (irq == ab_ahb->userpd_irq_num[ATH12K_USERPD_READY_IRQ]) {
+ complete(&ab_ahb->userpd_ready);
+ } else if (irq == ab_ahb->userpd_irq_num[ATH12K_USERPD_STOP_ACK_IRQ]) {
+ complete(&ab_ahb->userpd_stopped);
+ } else {
+ ath12k_err(ab, "Invalid userpd interrupt\n");
+ return IRQ_NONE;
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int ath12k_ahb_config_rproc_irq(struct ath12k_base *ab)
+{
+ struct ath12k_ahb *ab_ahb = ath12k_ab_to_ahb(ab);
+ int i, ret;
+ char *upd_irq_name;
+
+ for (i = 0; i < ATH12K_USERPD_MAX_IRQ; i++) {
+ ab_ahb->userpd_irq_num[i] = platform_get_irq_byname(ab->pdev,
+ ath12k_userpd_irq[i]);
+ if (ab_ahb->userpd_irq_num[i] < 0) {
+ ath12k_err(ab, "Failed to get %s irq: %d", ath12k_userpd_irq[i],
+ ab_ahb->userpd_irq_num[i]);
+ return -EINVAL;
+ }
+
+ upd_irq_name = devm_kzalloc(&ab->pdev->dev, ATH12K_UPD_IRQ_WRD_LEN,
+ GFP_KERNEL);
+ if (!upd_irq_name)
+ return -ENOMEM;
+
+ scnprintf(upd_irq_name, ATH12K_UPD_IRQ_WRD_LEN, "UserPD%u-%s",
+ ab_ahb->userpd_id, ath12k_userpd_irq[i]);
+ ret = devm_request_threaded_irq(&ab->pdev->dev, ab_ahb->userpd_irq_num[i],
+ NULL, ath12k_userpd_irq_handler,
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+ upd_irq_name, ab);
+ if (ret) {
+ ath12k_err(ab, "Request %s irq failed: %d\n",
+ ath12k_userpd_irq[i], ret);
+ return ret;
+ }
+ }
+
+ ab_ahb->spawn_state = devm_qcom_smem_state_get(&ab->pdev->dev, "spawn",
+ &ab_ahb->spawn_bit);
+ if (IS_ERR(ab_ahb->spawn_state)) {
+ ath12k_err(ab, "Failed to acquire spawn state\n");
+ return PTR_ERR(ab_ahb->spawn_state);
+ }
+
+ ab_ahb->stop_state = devm_qcom_smem_state_get(&ab->pdev->dev, "stop",
+ &ab_ahb->stop_bit);
+ if (IS_ERR(ab_ahb->stop_state)) {
+ ath12k_err(ab, "Failed to acquire stop state\n");
+ return PTR_ERR(ab_ahb->stop_state);
+ }
+
+ init_completion(&ab_ahb->userpd_spawned);
+ init_completion(&ab_ahb->userpd_ready);
+ init_completion(&ab_ahb->userpd_stopped);
+ return 0;
+}
+
static int ath12k_ahb_root_pd_state_notifier(struct notifier_block *nb,
const unsigned long event, void *data)
{
@@ -719,7 +796,8 @@ static int ath12k_ahb_configure_rproc(struct ath12k_base *ab)
goto unreg_notifier;
}
}
- return 0;
+
+ return ath12k_ahb_config_rproc_irq(ab);
unreg_notifier:
ath12k_ahb_unregister_rproc_notifier(ab);
@@ -893,13 +971,14 @@ static int ath12k_ahb_probe(struct platform_device *pdev)
struct device_node *mem_node;
struct ath12k_ahb *ab_ahb;
enum ath12k_hw_rev hw_rev;
- u32 addr;
+ u32 addr, userpd_id;
int ret;
hw_rev = ath12k_ahb_get_hw_rev(pdev);
switch (hw_rev) {
case ATH12K_HW_IPQ5332_HW10:
hif_ops = &ath12k_ahb_hif_ops_ipq5332;
+ userpd_id = ATH12K_IPQ5332_USERPD_ID;
break;
default:
dev_err(&pdev->dev, "Unsupported device type %d\n", hw_rev);
@@ -925,6 +1004,7 @@ static int ath12k_ahb_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ab);
ab_ahb = ath12k_ab_to_ahb(ab);
ab_ahb->ab = ab;
+ ab_ahb->userpd_id = userpd_id;
/* Set fixed_mem_region to true for platforms that support fixed memory
* reservation from DT. If memory is reserved from DT for FW, ath12k driver
@@ -25,6 +25,13 @@ enum ath12k_ahb_smp2p_msg_id {
ATH12K_AHB_POWER_SAVE_EXIT,
};
+enum ath12k_ahb_userpd_irq {
+ ATH12K_USERPD_SPAWN_IRQ,
+ ATH12K_USERPD_READY_IRQ,
+ ATH12K_USERPD_STOP_ACK_IRQ,
+ ATH12K_USERPD_MAX_IRQ,
+};
+
struct ath12k_base;
struct ath12k_ahb {
@@ -34,6 +41,15 @@ struct ath12k_ahb {
struct completion rootpd_ready;
struct notifier_block root_pd_nb;
void *root_pd_notifier;
+ struct qcom_smem_state *spawn_state;
+ struct qcom_smem_state *stop_state;
+ struct completion userpd_spawned;
+ struct completion userpd_ready;
+ struct completion userpd_stopped;
+ u32 userpd_id;
+ u32 spawn_bit;
+ u32 stop_bit;
+ int userpd_irq_num[ATH12K_USERPD_MAX_IRQ];
};
static inline struct ath12k_ahb *ath12k_ab_to_ahb(struct ath12k_base *ab)
@@ -97,6 +97,7 @@
#define ATH12K_REGDB_FILE_NAME "regdb.bin"
#define ATH12K_PCIE_MAX_PAYLOAD_SIZE 128
+#define ATH12K_IPQ5332_USERPD_ID 1
enum ath12k_hw_rate_cck {
ATH12K_HW_RATE_CCK_LP_11M = 0,