162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2021, MediaTek Inc.
462306a36Sopenharmony_ci * Copyright (c) 2021-2022, Intel Corporation.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Authors:
762306a36Sopenharmony_ci *  Haijun Liu <haijun.liu@mediatek.com>
862306a36Sopenharmony_ci *  Sreehari Kancharla <sreehari.kancharla@intel.com>
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * Contributors:
1162306a36Sopenharmony_ci *  Amir Hanania <amir.hanania@intel.com>
1262306a36Sopenharmony_ci *  Ricardo Martinez <ricardo.martinez@linux.intel.com>
1362306a36Sopenharmony_ci */
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <linux/bits.h>
1662306a36Sopenharmony_ci#include <linux/completion.h>
1762306a36Sopenharmony_ci#include <linux/dev_printk.h>
1862306a36Sopenharmony_ci#include <linux/io.h>
1962306a36Sopenharmony_ci#include <linux/irqreturn.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include "t7xx_mhccif.h"
2262306a36Sopenharmony_ci#include "t7xx_modem_ops.h"
2362306a36Sopenharmony_ci#include "t7xx_pci.h"
2462306a36Sopenharmony_ci#include "t7xx_pcie_mac.h"
2562306a36Sopenharmony_ci#include "t7xx_reg.h"
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#define D2H_INT_SR_ACK		(D2H_INT_SUSPEND_ACK |		\
2862306a36Sopenharmony_ci				 D2H_INT_RESUME_ACK |		\
2962306a36Sopenharmony_ci				 D2H_INT_SUSPEND_ACK_AP |	\
3062306a36Sopenharmony_ci				 D2H_INT_RESUME_ACK_AP)
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistatic void t7xx_mhccif_clear_interrupts(struct t7xx_pci_dev *t7xx_dev, u32 mask)
3362306a36Sopenharmony_ci{
3462306a36Sopenharmony_ci	void __iomem *mhccif_pbase = t7xx_dev->base_addr.mhccif_rc_base;
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	/* Clear level 2 interrupt */
3762306a36Sopenharmony_ci	iowrite32(mask, mhccif_pbase + REG_EP2RC_SW_INT_ACK);
3862306a36Sopenharmony_ci	/* Ensure write is complete */
3962306a36Sopenharmony_ci	t7xx_mhccif_read_sw_int_sts(t7xx_dev);
4062306a36Sopenharmony_ci	/* Clear level 1 interrupt */
4162306a36Sopenharmony_ci	t7xx_pcie_mac_clear_int_status(t7xx_dev, MHCCIF_INT);
4262306a36Sopenharmony_ci}
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cistatic irqreturn_t t7xx_mhccif_isr_thread(int irq, void *data)
4562306a36Sopenharmony_ci{
4662306a36Sopenharmony_ci	struct t7xx_pci_dev *t7xx_dev = data;
4762306a36Sopenharmony_ci	u32 int_status, val;
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	val = T7XX_L1_1_BIT(1) | T7XX_L1_2_BIT(1);
5062306a36Sopenharmony_ci	iowrite32(val, IREG_BASE(t7xx_dev) + DISABLE_ASPM_LOWPWR);
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	int_status = t7xx_mhccif_read_sw_int_sts(t7xx_dev);
5362306a36Sopenharmony_ci	if (int_status & D2H_SW_INT_MASK) {
5462306a36Sopenharmony_ci		int ret = t7xx_pci_mhccif_isr(t7xx_dev);
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci		if (ret)
5762306a36Sopenharmony_ci			dev_err(&t7xx_dev->pdev->dev, "PCI MHCCIF ISR failure: %d", ret);
5862306a36Sopenharmony_ci	}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	t7xx_mhccif_clear_interrupts(t7xx_dev, int_status);
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	if (int_status & D2H_INT_DS_LOCK_ACK)
6362306a36Sopenharmony_ci		complete_all(&t7xx_dev->sleep_lock_acquire);
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	if (int_status & D2H_INT_SR_ACK)
6662306a36Sopenharmony_ci		complete(&t7xx_dev->pm_sr_ack);
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	iowrite32(T7XX_L1_BIT(1), IREG_BASE(t7xx_dev) + ENABLE_ASPM_LOWPWR);
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	int_status = t7xx_mhccif_read_sw_int_sts(t7xx_dev);
7162306a36Sopenharmony_ci	if (!int_status) {
7262306a36Sopenharmony_ci		val = T7XX_L1_1_BIT(1) | T7XX_L1_2_BIT(1);
7362306a36Sopenharmony_ci		iowrite32(val, IREG_BASE(t7xx_dev) + ENABLE_ASPM_LOWPWR);
7462306a36Sopenharmony_ci	}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	t7xx_pcie_mac_set_int(t7xx_dev, MHCCIF_INT);
7762306a36Sopenharmony_ci	return IRQ_HANDLED;
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ciu32 t7xx_mhccif_read_sw_int_sts(struct t7xx_pci_dev *t7xx_dev)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	return ioread32(t7xx_dev->base_addr.mhccif_rc_base + REG_EP2RC_SW_INT_STS);
8362306a36Sopenharmony_ci}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_civoid t7xx_mhccif_mask_set(struct t7xx_pci_dev *t7xx_dev, u32 val)
8662306a36Sopenharmony_ci{
8762306a36Sopenharmony_ci	iowrite32(val, t7xx_dev->base_addr.mhccif_rc_base + REG_EP2RC_SW_INT_EAP_MASK_SET);
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_civoid t7xx_mhccif_mask_clr(struct t7xx_pci_dev *t7xx_dev, u32 val)
9162306a36Sopenharmony_ci{
9262306a36Sopenharmony_ci	iowrite32(val, t7xx_dev->base_addr.mhccif_rc_base + REG_EP2RC_SW_INT_EAP_MASK_CLR);
9362306a36Sopenharmony_ci}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ciu32 t7xx_mhccif_mask_get(struct t7xx_pci_dev *t7xx_dev)
9662306a36Sopenharmony_ci{
9762306a36Sopenharmony_ci	return ioread32(t7xx_dev->base_addr.mhccif_rc_base + REG_EP2RC_SW_INT_EAP_MASK);
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistatic irqreturn_t t7xx_mhccif_isr_handler(int irq, void *data)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	return IRQ_WAKE_THREAD;
10362306a36Sopenharmony_ci}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_civoid t7xx_mhccif_init(struct t7xx_pci_dev *t7xx_dev)
10662306a36Sopenharmony_ci{
10762306a36Sopenharmony_ci	t7xx_dev->base_addr.mhccif_rc_base = t7xx_dev->base_addr.pcie_ext_reg_base +
10862306a36Sopenharmony_ci					    MHCCIF_RC_DEV_BASE -
10962306a36Sopenharmony_ci					    t7xx_dev->base_addr.pcie_dev_reg_trsl_addr;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	t7xx_dev->intr_handler[MHCCIF_INT] = t7xx_mhccif_isr_handler;
11262306a36Sopenharmony_ci	t7xx_dev->intr_thread[MHCCIF_INT] = t7xx_mhccif_isr_thread;
11362306a36Sopenharmony_ci	t7xx_dev->callback_param[MHCCIF_INT] = t7xx_dev;
11462306a36Sopenharmony_ci}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_civoid t7xx_mhccif_h2d_swint_trigger(struct t7xx_pci_dev *t7xx_dev, u32 channel)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	void __iomem *mhccif_pbase = t7xx_dev->base_addr.mhccif_rc_base;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	iowrite32(BIT(channel), mhccif_pbase + REG_RC2EP_SW_BSY);
12162306a36Sopenharmony_ci	iowrite32(channel, mhccif_pbase + REG_RC2EP_SW_TCHNUM);
12262306a36Sopenharmony_ci}
123