Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2ff9c2fd authored by Yue Ma's avatar Yue Ma Committed by Lin Bai
Browse files

cnss2: Set WLAON_QFPROM_PWR_CTRL_REG during power on and off



After device power on and link config, clear VDD4BLOW_EN bit
of WLAON_QFPROM_PWR_CTRL_REG register to disable OTP write.
Before device link suspend and power off, clear VDD4BLOW_EN bit
and set SHUTDOWN_EN bit. Also add a 1ms sleep after writing
WLAON_QFPROM_PWR_CTRL_REG register.

Add a DTSI entry to control above operations.

Change-Id: Icb307a85bb5d283b78bdd7615f9a4757867c8075
CRs-Fixed: 2601850
Signed-off-by: default avatarYue Ma <yuem@codeaurora.org>
parent 0a650460
Loading
Loading
Loading
Loading
+13 −1
Original line number Diff line number Diff line
/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
/* Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -1944,6 +1944,17 @@ static void cnss_init_control_params(struct cnss_plat_data *plat_priv)
	plat_priv->ctrl_params.bdf_type = CNSS_BDF_TYPE_DEFAULT;
}

static void cnss_get_wlaon_pwr_ctrl_info(struct cnss_plat_data *plat_priv)
{
	struct device *dev = &plat_priv->plat_dev->dev;

	plat_priv->set_wlaon_pwr_ctrl =
		of_property_read_bool(dev->of_node, "qcom,set-wlaon-pwr-ctrl");

	cnss_pr_dbg("set_wlaon_pwr_ctrl is %d\n",
		    plat_priv->set_wlaon_pwr_ctrl);
}

static const struct platform_device_id cnss_platform_id_table[] = {
	{ .name = "qca6174", .driver_data = QCA6174_DEVICE_ID, },
	{ .name = "qca6290", .driver_data = QCA6290_DEVICE_ID, },
@@ -2052,6 +2063,7 @@ static int cnss_probe(struct platform_device *plat_dev)
	platform_set_drvdata(plat_dev, plat_priv);
	INIT_LIST_HEAD(&plat_priv->vreg_list);

	cnss_get_wlaon_pwr_ctrl_info(plat_priv);
	cnss_init_control_params(plat_priv);

	ret = cnss_get_resources(plat_priv);
+2 −1
Original line number Diff line number Diff line
/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
/* Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -316,6 +316,7 @@ struct cnss_plat_data {
	struct cnss_control_params ctrl_params;
	u32 is_converged_dt;
	struct device_node *dev_node;
	u8 set_wlaon_pwr_ctrl;
};

struct cnss_plat_data *cnss_get_plat_priv(struct platform_device *plat_dev);
+143 −0
Original line number Diff line number Diff line
@@ -127,6 +127,17 @@ static DEFINE_SPINLOCK(pci_reg_window_lock);
#define WINDOW_START				MAX_UNWINDOWED_ADDRESS
#define WINDOW_RANGE_MASK			0x7FFFF

#define WLAON_PWR_CTRL_SHUTDOWN_DELAY_MIN_US	1000
#define WLAON_PWR_CTRL_SHUTDOWN_DELAY_MAX_US	2000
#define QFPROM_PWR_CTRL_VDD4BLOW_SW_EN_MASK	0x4
#define QFPROM_PWR_CTRL_SHUTDOWN_EN_MASK	0x1

#define FORCE_WAKE_DELAY_MIN_US			4000
#define FORCE_WAKE_DELAY_MAX_US			6000
#define FORCE_WAKE_DELAY_TIMEOUT_US		60000

#define QCA6390_WLAON_QFPROM_PWR_CTRL_REG	0x1F8031C

static struct cnss_pci_reg ce_src[] = {
	{ "SRC_RING_BASE_LSB", QCA6390_CE_SRC_RING_BASE_LSB_OFFSET },
	{ "SRC_RING_BASE_MSB", QCA6390_CE_SRC_RING_BASE_MSB_OFFSET },
@@ -238,6 +249,33 @@ static int cnss_pci_reg_read(struct cnss_pci_data *pci_priv,
	return 0;
}

static int cnss_pci_reg_write(struct cnss_pci_data *pci_priv, u32 offset,
			      u32 val)
{
	int ret;

	if (!in_interrupt() && !irqs_disabled()) {
		ret = cnss_pci_check_link_status(pci_priv);
		if (ret)
			return ret;
	}

	if (pci_priv->pci_dev->device == QCA6174_DEVICE_ID ||
	    offset < MAX_UNWINDOWED_ADDRESS) {
		writel_relaxed(val, pci_priv->bar + offset);
		return 0;
	}

	spin_lock_bh(&pci_reg_window_lock);
	cnss_pci_select_window(pci_priv, offset);

	writel_relaxed(val, pci_priv->bar + WINDOW_START +
		       (offset & WINDOW_RANGE_MASK));
	spin_unlock_bh(&pci_reg_window_lock);

	return 0;
}

static void cnss_pci_disable_l1(struct cnss_pci_data *pci_priv)
{
	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
@@ -795,6 +833,100 @@ static int cnss_qca6174_ramdump(struct cnss_pci_data *pci_priv)
	return ret;
}

static int cnss_pci_force_wake_get(struct cnss_pci_data *pci_priv)
{
	struct device *dev = &pci_priv->pci_dev->dev;
	u32 timeout = 0;
	int ret;

	ret = cnss_pci_force_wake_request(dev);
	if (ret) {
		cnss_pr_err("Failed to request force wake\n");
		return ret;
	}

	while (!cnss_pci_is_device_awake(dev) &&
	       timeout <= FORCE_WAKE_DELAY_TIMEOUT_US) {
		usleep_range(FORCE_WAKE_DELAY_MIN_US, FORCE_WAKE_DELAY_MAX_US);
		timeout += FORCE_WAKE_DELAY_MAX_US;
	}

	if (cnss_pci_is_device_awake(dev) != true) {
		cnss_pr_err("Timed out to request force wake\n");
		return -ETIMEDOUT;
	}

	return 0;
}

static int cnss_pci_force_wake_put(struct cnss_pci_data *pci_priv)
{
	struct device *dev = &pci_priv->pci_dev->dev;
	int ret;

	ret = cnss_pci_force_wake_release(dev);
	if (ret)
		cnss_pr_err("Failed to release force wake\n");

	return ret;
}

static void cnss_pci_set_wlaon_pwr_ctrl(struct cnss_pci_data *pci_priv,
					bool set_vddd4blow, bool set_shutdown,
					bool do_force_wake)
{
	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
	int ret;
	u32 val;

	if (!plat_priv->set_wlaon_pwr_ctrl)
		return;

	if (do_force_wake)
		if (cnss_pci_force_wake_get(pci_priv))
			return;

	ret = cnss_pci_reg_read(pci_priv, QCA6390_WLAON_QFPROM_PWR_CTRL_REG,
				&val);
	if (ret) {
		cnss_pr_err("Failed to read register offset 0x%x, err = %d\n",
			    QCA6390_WLAON_QFPROM_PWR_CTRL_REG, ret);
		goto force_wake_put;
	}

	cnss_pr_dbg("Read register offset 0x%x, val = 0x%x\n",
		    QCA6390_WLAON_QFPROM_PWR_CTRL_REG, val);

	if (set_vddd4blow)
		val |= QFPROM_PWR_CTRL_VDD4BLOW_SW_EN_MASK;
	else
		val &= ~QFPROM_PWR_CTRL_VDD4BLOW_SW_EN_MASK;

	if (set_shutdown)
		val |= QFPROM_PWR_CTRL_SHUTDOWN_EN_MASK;
	else
		val &= ~QFPROM_PWR_CTRL_SHUTDOWN_EN_MASK;

	ret = cnss_pci_reg_write(pci_priv, QCA6390_WLAON_QFPROM_PWR_CTRL_REG,
				 val);
	if (ret) {
		cnss_pr_err("Failed to write register offset 0x%x, err = %d\n",
			    QCA6390_WLAON_QFPROM_PWR_CTRL_REG, ret);
		goto force_wake_put;
	}

	cnss_pr_dbg("Write val 0x%x to register offset 0x%x\n", val,
		    QCA6390_WLAON_QFPROM_PWR_CTRL_REG);

	if (set_shutdown)
		usleep_range(WLAON_PWR_CTRL_SHUTDOWN_DELAY_MIN_US,
			     WLAON_PWR_CTRL_SHUTDOWN_DELAY_MAX_US);

force_wake_put:
	if (do_force_wake)
		cnss_pci_force_wake_put(pci_priv);
}

static int cnss_qca6290_powerup(struct cnss_pci_data *pci_priv)
{
	int ret = 0;
@@ -819,6 +951,7 @@ static int cnss_qca6290_powerup(struct cnss_pci_data *pci_priv)
		goto power_off;
	}

	cnss_pci_set_wlaon_pwr_ctrl(pci_priv, false, false, false);
	timeout = cnss_get_boot_timeout(&pci_priv->pci_dev->dev);

	ret = cnss_pci_start_mhi(pci_priv);
@@ -852,6 +985,7 @@ static int cnss_qca6290_powerup(struct cnss_pci_data *pci_priv)
	return 0;

stop_mhi:
	cnss_pci_set_wlaon_pwr_ctrl(pci_priv, false, true, true);
	cnss_pci_stop_mhi(pci_priv);
	cnss_suspend_pci_link(pci_priv);
power_off:
@@ -864,6 +998,7 @@ static int cnss_qca6290_shutdown(struct cnss_pci_data *pci_priv)
{
	int ret = 0;
	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
	int do_force_wake = true;

	cnss_pm_request_resume(pci_priv);

@@ -885,6 +1020,10 @@ static int cnss_qca6290_shutdown(struct cnss_pci_data *pci_priv)
		cnss_pci_collect_dump(pci_priv);
	}

	if (test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state))
		do_force_wake = false;

	cnss_pci_set_wlaon_pwr_ctrl(pci_priv, false, true, do_force_wake);
	cnss_pci_stop_mhi(pci_priv);

	ret = cnss_suspend_pci_link(pci_priv);
@@ -3239,6 +3378,7 @@ static int cnss_pci_probe(struct pci_dev *pci_dev,
		break;
	case QCA6290_DEVICE_ID:
	case QCA6390_DEVICE_ID:
		cnss_pci_set_wlaon_pwr_ctrl(pci_priv, false, false, false);
	case QCN7605_DEVICE_ID:
		setup_timer(&pci_priv->dev_rddm_timer,
			    cnss_dev_rddm_timeout_hdlr,
@@ -3263,6 +3403,9 @@ static int cnss_pci_probe(struct pci_dev *pci_dev,

		if (EMULATION_HW)
			break;
		if (pci_dev->device != QCN7605_DEVICE_ID)
			cnss_pci_set_wlaon_pwr_ctrl(pci_priv, false,
						    true, false);
		ret = cnss_suspend_pci_link(pci_priv);
		if (ret)
			cnss_pr_err("Failed to suspend PCI link, err = %d\n",