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

Commit b8207c80 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "platform: msm: Add USB BAM support to ChipIdea/RMNET"

parents 0c0b80d0 21e70acc
Loading
Loading
Loading
Loading
+347 −22
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2011-2020, The Linux Foundation. All rights reserved.
 * Copyright (c) 2011-2020,2021 The Linux Foundation. All rights reserved.
 */

#include <linux/kernel.h>
@@ -15,6 +15,7 @@
#include <linux/dma-mapping.h>
#include <linux/pm_runtime.h>
#include <linux/delay.h>
#include <linux/usb/msm_hsusb.h>

#define USB_THRESHOLD 512
#define USB_BAM_MAX_STR_LEN 50
@@ -60,6 +61,9 @@ do { \
#define log_event_dbg(x, ...) log_event(LOGLEVEL_DEBUG, x, ##__VA_ARGS__)
#define log_event_err(x, ...) log_event(LOGLEVEL_ERR, x, ##__VA_ARGS__)

/* Reset BAM with pipes connected */
#define SPS_BAM_FORCE_RESET         (1UL << 11)

enum usb_bam_event_type {
	USB_BAM_EVENT_WAKEUP_PIPE = 0,	/* Wake a pipe */
	USB_BAM_EVENT_WAKEUP,		/* Wake a bam (first pipe waked) */
@@ -176,6 +180,7 @@ struct msm_usb_bam_data {
	bool reset_on_connect;
	bool reset_on_disconnect;
	bool disable_clk_gating;
	bool ignore_core_reset_ack;
	u32 override_threshold;
	u32 max_mbps_highspeed;
	u32 max_mbps_superspeed;
@@ -219,6 +224,8 @@ struct usb_bam_ctx_type {

static char *bam_enable_strings[MAX_BAMS] = {
	[DWC3_CTRL] = "ssusb",
	[CI_CTRL] = "hsusb",
	[HSIC_CTRL]  = "hsic",
};

struct usb_bam_host_info {
@@ -324,15 +331,25 @@ static void __maybe_unused put_timestamp(char *tbuf)
		nanosec_rem);
}

static inline enum usb_ctrl get_bam_type_from_core_name(const char *name)
void msm_bam_set_hsic_host_dev(struct device *dev)
{
	if (strnstr(name, bam_enable_strings[DWC3_CTRL],
				USB_BAM_MAX_STR_LEN) ||
			strnstr(name, "dwc3", USB_BAM_MAX_STR_LEN))
		return DWC3_CTRL;
	if (dev) {
		/* Hold the device until allowing lpm */
		log_event_dbg("%s: Getting hsic device %pK\n", __func__, dev);
		pm_runtime_get(dev);
	} else if (host_info[HSIC_CTRL].dev) {
		log_event_dbg("%s: Try Putting hsic device %pK, lpm:%d\n",
				__func__, host_info[HSIC_CTRL].dev,
				host_info[HSIC_CTRL].in_lpm);
		/* Just release previous device if not already done */
		if (!host_info[HSIC_CTRL].in_lpm) {
			host_info[HSIC_CTRL].in_lpm = true;
			pm_runtime_put(host_info[HSIC_CTRL].dev);
		}
	}

	log_event_err("%s: invalid BAM name(%s)\n", __func__, name);
	return -EINVAL;
	host_info[HSIC_CTRL].dev = dev;
	host_info[HSIC_CTRL].in_lpm = false;
}

static void usb_bam_set_inactivity_timer(enum usb_ctrl bam)
@@ -379,6 +396,156 @@ void msm_bam_set_usb_host_dev(struct device *dev)
	host_info[CI_CTRL].in_lpm = false;
}

static void _msm_bam_host_notify_on_resume(enum usb_ctrl bam_type)
{
	struct usb_bam_ctx_type *ctx = &msm_usb_bam[bam_type];

	spin_lock(&ctx->usb_bam_lock);
	log_event_dbg("%s: enter bam=%s\n", __func__,
			bam_enable_strings[bam_type]);

	host_info[bam_type].in_lpm = false;

	/*
	 * This function is called to notify the usb bam driver
	 * that the hsic core and hsic bam hw are fully resumed
	 * and clocked on. Therefore we can now set the inactivity
	 * timer to the hsic bam hw.
	 */
	if (ctx->inactivity_timer_ms)
		usb_bam_set_inactivity_timer(bam_type);

	spin_unlock(&ctx->usb_bam_lock);
}

/**
 * msm_bam_hsic_host_pipe_empty - Check all HSIC host BAM pipe state
 *
 * return true if all BAM pipe used for HSIC Host mode is empty.
 */
bool msm_bam_hsic_host_pipe_empty(void)
{
	struct usb_bam_pipe_connect *pipe_connect;
	struct sps_pipe *pipe = NULL;
	enum usb_ctrl bam = HSIC_CTRL;
	struct usb_bam_ctx_type *ctx = &msm_usb_bam[bam];
	int i, ret;
	u32 status;

	log_event_dbg("%s: enter\n", __func__);

	for (i = 0; i < ctx->max_connections; i++) {
		pipe_connect = &ctx->usb_bam_connections[i];
		if (pipe_connect->enabled) {
			pipe = ctx->usb_bam_sps.sps_pipes[i];
			ret = sps_is_pipe_empty(pipe, &status);
			if (ret) {
				log_event_err("%s(): sps_is_pipe_empty() failed\n",
								__func__);
				log_event_err("%s(): SRC index(%d), DEST index(%d):\n",
						__func__,
						pipe_connect->src_pipe_index,
						pipe_connect->dst_pipe_index);
				WARN_ON(1);
			}

			if (!status) {
				log_event_err("%s(): pipe is not empty.\n",
						__func__);
				log_event_err("%s(): SRC index(%d), DEST index(%d):\n",
						__func__,
						pipe_connect->src_pipe_index,
						pipe_connect->dst_pipe_index);
				return false;
			}

			log_event_dbg("%s(): SRC index(%d), DEST index(%d):\n",
				  __func__,
				  pipe_connect->src_pipe_index,
				  pipe_connect->dst_pipe_index);
		}

	}

	if (!pipe)
		log_event_err("%s: Bam %s has no connected pipes\n", __func__,
						bam_enable_strings[bam]);

	return true;
}
EXPORT_SYMBOL(msm_bam_hsic_host_pipe_empty);

static bool msm_bam_host_lpm_ok(enum usb_ctrl bam_type)
{
	struct usb_bam_ctx_type *ctx = &msm_usb_bam[bam_type];
	struct usb_bam_pipe_connect *pipe_iter;
	int i;

	log_event_dbg("%s: enter bam=%s\n", __func__,
			bam_enable_strings[bam_type]);

	if (!host_info[bam_type].dev)
		return true;

	log_event_dbg("%s: Starting hsic full suspend sequence\n",
		__func__);

	log_event_dbg("%s(): checking HSIC Host pipe state\n", __func__);
	if (!msm_bam_hsic_host_pipe_empty()) {
		log_event_err("%s(): HSIC HOST Pipe is not empty\n",
				__func__);
		return false;
	}

	/* HSIC host will go now to lpm */
	log_event_dbg("%s: vote for suspend hsic %pK\n",
		__func__, host_info[bam_type].dev);

	for (i = 0; i < ctx->max_connections; i++) {
		pipe_iter = &ctx->usb_bam_connections[i];
		if (pipe_iter->bam_type == bam_type &&
		    pipe_iter->enabled && !pipe_iter->suspended)
			pipe_iter->suspended = true;
	}

	host_info[bam_type].in_lpm = true;

	return true;
}

bool msm_bam_hsic_lpm_ok(void)
{
	log_event_dbg("%s: enter\n", __func__);

	return msm_bam_host_lpm_ok(HSIC_CTRL);

}
EXPORT_SYMBOL(msm_bam_hsic_lpm_ok);

void msm_bam_hsic_host_notify_on_resume(void)
{
	_msm_bam_host_notify_on_resume(HSIC_CTRL);
}

static inline enum usb_ctrl get_bam_type_from_core_name(const char *name)
{
	if (strnstr(name, bam_enable_strings[DWC3_CTRL],
			USB_BAM_MAX_STR_LEN) ||
		strnstr(name, "dwc3", USB_BAM_MAX_STR_LEN))
		return DWC3_CTRL;
	else if (strnstr(name, bam_enable_strings[HSIC_CTRL],
			USB_BAM_MAX_STR_LEN) ||
		strnstr(name, "ci13xxx_msm_hsic", USB_BAM_MAX_STR_LEN))
		return HSIC_CTRL;
	else if (strnstr(name, bam_enable_strings[CI_CTRL],
			USB_BAM_MAX_STR_LEN) ||
		strnstr(name, "ci", USB_BAM_MAX_STR_LEN))
		return CI_CTRL;

	log_event_err("%s: invalid BAM name(%s)\n", __func__, name);
	return -EINVAL;
}

static int usb_bam_alloc_buffer(struct usb_bam_pipe_connect *pipe_connect)
{
	int ret = 0;
@@ -389,7 +556,7 @@ static int usb_bam_alloc_buffer(struct usb_bam_pipe_connect *pipe_connect)
	struct sg_table data_sgt, desc_sgt;
	dma_addr_t data_iova, desc_iova;

	pr_debug("%s: data_fifo size:%x desc_fifo_size:%x\n",
	log_event_dbg("%s: data_fifo size:%x desc_fifo_size:%x\n",
				__func__, pipe_connect->data_fifo_size,
				pipe_connect->desc_fifo_size);

@@ -563,7 +730,7 @@ int usb_bam_free_fifos(enum usb_ctrl cur_bam, u8 idx)
	struct device *dev = &ctx->usb_bam_pdev->dev;
	u32 data_fifo_size;

	pr_debug("%s(): data size:%x desc size:%x\n",
	log_event_dbg("%s(): data size:%x desc size:%x\n",
			__func__, sps_connection->data.size,
			sps_connection->desc.size);

@@ -1053,7 +1220,6 @@ static int usb_bam_disconnect_ipa_cons(

	if (!pipe_empty) {
		if (inject_zlt) {
			pr_debug("%s: Inject ZLT\n", __func__);
			log_event_dbg("%s: Inject ZLT\n", __func__);
			inject_zlt = false;
			sps_pipe_inject_zlt(sps_connection->destination,
@@ -2071,6 +2237,57 @@ static int usb_bam_set_ipa_perf(enum usb_ctrl cur_bam,
	return ret;
}

static bool _hsic_host_bam_resume_core(void)
{
	log_event_dbg("%s: enter\n", __func__);

	/* Exit from "full suspend" in case of hsic host */
	if (host_info[HSIC_CTRL].dev) {
		log_event_dbg("%s: Getting hsic device %pK\n", __func__,
			host_info[HSIC_CTRL].dev);
		pm_runtime_get(host_info[HSIC_CTRL].dev);
		return true;
	}
	return false;
}

static bool usb_bam_resume_core(enum usb_ctrl bam_type,
	enum usb_bam_mode bam_mode)
{
	log_event_dbg("%s: enter bam=%s\n", __func__,
			bam_enable_strings[bam_type]);

	if ((bam_mode == USB_BAM_DEVICE) || (bam_type != HSIC_CTRL)) {
		log_event_err("%s: Invalid BAM type %d\n", __func__, bam_type);
		return false;
	}

	return _hsic_host_bam_resume_core();
}

static void _msm_bam_wait_for_host_prod_granted(enum usb_ctrl bam_type)
{
	struct usb_bam_ctx_type *ctx = &msm_usb_bam[bam_type];

	spin_lock(&ctx->usb_bam_lock);

	log_event_dbg("%s: enter bam=%s\n", __func__,
			bam_enable_strings[bam_type]);
	ctx->is_bam_inactivity = false;

	/* Get back to resume state including wakeup ipa */
	usb_bam_resume_core(bam_type, USB_BAM_HOST);

	spin_unlock(&ctx->usb_bam_lock);

}

void msm_bam_wait_for_hsic_host_prod_granted(void)
{
	log_event_dbg("%s: start\n", __func__);
	_msm_bam_wait_for_host_prod_granted(HSIC_CTRL);
}

int usb_bam_connect_ipa(enum usb_ctrl cur_bam,
			struct usb_bam_connect_ipa_params *ipa_params)
{
@@ -2170,7 +2387,7 @@ int usb_bam_connect_ipa(enum usb_ctrl cur_bam,
	} else {
		spin_unlock(&ctx->usb_bam_lock);
		if (!ctx->pipes_enabled_per_bam)
			pr_debug("No BAM reset on connect, just pipe reset\n");
			log_event_dbg("No BAM reset on connect, just pipe reset\n");
	}

	if (ipa_params->dir == USB_TO_PEER_PERIPHERAL) {
@@ -2669,6 +2886,17 @@ static struct msm_usb_bam_data *usb_bam_dt_to_data(
	if (!usb_bam_data)
		return NULL;

	rc = of_property_read_u32(node, "qcom,bam-type", &bam);
	if (rc) {
		log_event_err("%s: bam type is missing in device tree\n",
			__func__);
		return NULL;
	}
	if (bam >= MAX_BAMS) {
		log_event_err("%s: Invalid bam type %d in device tree\n",
			__func__, bam);
		return NULL;
	}
	usb_bam_data->bam_type = bam;

	usb_bam_data->reset_on_connect = of_property_read_bool(node,
@@ -2696,7 +2924,8 @@ static struct msm_usb_bam_data *usb_bam_dt_to_data(

	rc = of_property_read_u32(node, "qcom,usb-bam-fifo-baseaddr", &addr);
	if (rc)
		pr_debug("%s: Invalid usb base address property\n", __func__);
		log_event_dbg("%s: Invalid usb base address property\n",
			__func__);
	else
		usb_bam_data->usb_bam_fifo_baseaddr = addr;

@@ -2786,7 +3015,7 @@ static struct msm_usb_bam_data *usb_bam_dt_to_data(
		rc = of_property_read_u32(node, "qcom,pipe-connection-type",
			&usb_bam_connections[i].pipe_type);
		if (rc)
			pr_debug("%s: pipe type is defaulting to bam2bam\n",
			log_event_dbg("%s: pipe type is defaulting to bam2bam\n",
					__func__);

		of_property_read_u32(node, "qcom,peer-bam-physical-address",
@@ -2832,6 +3061,54 @@ static struct msm_usb_bam_data *usb_bam_dt_to_data(
	return NULL;
}

static void msm_usb_bam_update_props(struct sps_bam_props *props,
				struct platform_device *pdev)
{
	struct usb_bam_ctx_type *ctx = dev_get_drvdata(&pdev->dev);
	enum usb_ctrl bam_type = ctx->usb_bam_data->bam_type;
	struct device *dev;

	props->phys_addr = ctx->io_res->start;
	props->virt_addr = NULL;
	props->virt_size = resource_size(ctx->io_res);
	props->irq = ctx->irq;
	props->summing_threshold = ctx->usb_bam_data->override_threshold;
	props->event_threshold = ctx->usb_bam_data->override_threshold;
	props->num_pipes = ctx->usb_bam_data->usb_bam_num_pipes;
	props->callback = usb_bam_sps_events;
	props->user = bam_enable_strings[bam_type];

	/*
	 * HSUSB and HSIC Cores don't support RESET ACK signal to BAMs
	 * Hence, let BAM to ignore acknowledge from USB while resetting PIPE
	 */
	if (ctx->usb_bam_data->ignore_core_reset_ack && bam_type != DWC3_CTRL)
		props->options = SPS_BAM_NO_EXT_P_RST;

	if (ctx->usb_bam_data->disable_clk_gating)
		props->options |= SPS_BAM_NO_LOCAL_CLK_GATING;

	/*
	 * HSUSB BAM is not NDP BAM and it must be enabled before
	 * starting peripheral controller to avoid switching USB core mode
	 * from legacy to BAM with ongoing data transfers.
	 */
	if (bam_type == CI_CTRL) {
		log_event_dbg("Register and enable HSUSB BAM\n");
		props->options |= SPS_BAM_OPT_ENABLE_AT_BOOT;
		props->options |= SPS_BAM_FORCE_RESET;
	}

	dev = &ctx->usb_bam_pdev->dev;
	if (dev && dev->parent && device_property_present(dev->parent, "iommus")
		&& !device_property_present(dev->parent,
						"qcom,smmu-s1-bypass")) {
		pr_info("%s: setting SPS_BAM_SMMU_EN flag with (%s)\n",
						__func__, dev_name(dev));
		props->options |= SPS_BAM_SMMU_EN;
	}
}

static int usb_bam_init(struct platform_device *pdev)
{
	int ret;
@@ -2842,7 +3119,7 @@ static int usb_bam_init(struct platform_device *pdev)

	memset(&props, 0, sizeof(props));

	pr_debug("%s\n", __func__);
	log_event_dbg("%s\n", __func__);

	props.phys_addr = ctx->io_res->start;
	props.virt_size = resource_size(ctx->io_res);
@@ -3120,6 +3397,54 @@ enum usb_ctrl usb_bam_get_bam_type(const char *core_name)
}
EXPORT_SYMBOL(usb_bam_get_bam_type);

bool msm_usb_bam_enable(enum usb_ctrl bam, bool bam_enable)
{
	struct msm_usb_bam_data *usb_bam_data;
	struct usb_bam_ctx_type *ctx = &msm_usb_bam[bam];
	static bool bam_enabled;
	int ret;

	if (!ctx->usb_bam_pdev)
		return false;

	usb_bam_data = ctx->usb_bam_data;
	if (bam != CI_CTRL)
		return false;

	if (bam_enabled == bam_enable) {
		log_event_dbg("%s: USB BAM is already %s\n", __func__,
				bam_enable ? "Registered" : "De-registered");
		return false;
	}

	if (bam_enable) {
		struct sps_bam_props props;

		memset(&props, 0, sizeof(props));
		msm_usb_bam_update_props(&props, ctx->usb_bam_pdev);
		msm_hw_bam_disable(1);
		ret = sps_register_bam_device(&props, &ctx->h_bam);
		bam_enabled = true;
		if (ret < 0) {
			log_event_err("%s: register bam error %d\n",
					__func__, ret);
			return false;
		}
		log_event_dbg("%s: USB BAM Registered\n", __func__);
		msm_hw_bam_disable(0);
	} else {
		msm_hw_soft_reset();
		msm_hw_bam_disable(1);
		sps_device_reset(ctx->h_bam);
		sps_deregister_bam_device(ctx->h_bam);
		log_event_dbg("%s: USB BAM De-registered\n", __func__);
		bam_enabled = false;
	}

	return true;
}
EXPORT_SYMBOL(msm_usb_bam_enable);

static int usb_bam_remove(struct platform_device *pdev)
{
	struct usb_bam_ctx_type *ctx = dev_get_drvdata(&pdev->dev);
+22 −0
Original line number Diff line number Diff line
@@ -313,6 +313,12 @@ int usb_bam_alloc_fifos(enum usb_ctrl cur_bam, u8 idx);
int usb_bam_free_fifos(enum usb_ctrl cur_bam, u8 idx);
int get_qdss_bam_info(enum usb_ctrl cur_bam, u8 idx,
			phys_addr_t *p_addr, u32 *bam_size);
bool msm_usb_bam_enable(enum usb_ctrl ctrl, bool bam_enable);
void msm_bam_set_hsic_host_dev(struct device *dev);
bool msm_bam_hsic_lpm_ok(void);
void msm_bam_hsic_host_notify_on_resume(void);
void msm_bam_wait_for_hsic_host_prod_granted(void);
bool msm_bam_hsic_host_pipe_empty(void);
#else
static inline int usb_bam_connect(enum usb_ctrl bam, u8 idx, u32 *bam_pipe_idx,
							unsigned long iova)
@@ -415,6 +421,22 @@ static inline bool msm_usb_bam_enable(enum usb_ctrl ctrl, bool bam_enable)
	return false;
}

static inline void msm_bam_set_hsic_host_dev(struct device *dev) {}

static inline bool msm_bam_hsic_lpm_ok(void)
{
	return false;
}

static inline void msm_bam_hsic_host_notify_on_resume(void) {}

static inline void msm_bam_wait_for_hsic_host_prod_granted(void) {}

static inline bool msm_bam_hsic_host_pipe_empty(void)
{
	return false;
}

#endif

/* CONFIG_PM */