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

Commit 1b9c8d36 authored by Girish Mahadevan's avatar Girish Mahadevan
Browse files

msm: msm_bus: Allow QOS address offset to be configurable



Currently the QOS base address for NOC is assumed to be at an
offset of 0x3000 from the base address of the NOC device. But this is not
the case in some chipsets. Make the QOS address offset a configurable
platform parameter.

Change-Id: If0adb8839b525c3ede0f5a61a65fd27826834377
Signed-off-by: default avatarGirish Mahadevan <girishm@codeaurora.org>
parent 08a9c39e
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -21,10 +21,12 @@ The following properties are optional as a bus might not support
these features:

qcom,ntieredslaves:	Number of tiered slaves on the bus.
qcom,qos-freq:		QoS frequency (In Hz)
qcom,qos-freq:		QoS frequency (In KHz)
qcom,hw-sel:		A string which decides whether QoS data
			should be sent to RPM, set using BIMC or NoCs.
			It can be set to "RPM", "NoC" or "BIMC".
qcom,qos-baseoffset:	Base address offset of QoS registers from the bus device
			base address.
qcom,rpm-en:		A boolean flag indicating whether RPM transactions are
			supported for nodes of the bus.
qcom,ahb:		A boolean flag indicating whether the bus is ahb type.
+2 −1
Original line number Diff line number Diff line
/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
/* Copyright (c) 2010-2014, 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
@@ -41,6 +41,7 @@ struct msm_bus_fabric_registration {
	int hw_sel;
	void *hw_data;
	uint32_t qos_freq;
	uint32_t qos_baseoffset;
	bool virt;
};

+58 −35
Original line number Diff line number Diff line
/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2014, 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
@@ -22,12 +22,14 @@
#define __CLZ(x) ((8 * sizeof(uint32_t)) - 1 - __fls(x))
#define SAT_SCALE 16	/* 16 bytes minimum for saturation */
#define BW_SCALE  256	/* 1/256 byte per cycle unit */
#define QOS_DEFAULT_BASEOFFSET		0x00003000
#define MAX_BW_FIELD (NOC_QOS_BWn_BW_BMSK >> NOC_QOS_BWn_BW_SHFT)
#define MAX_SAT_FIELD (NOC_QOS_SATn_SAT_BMSK >> NOC_QOS_SATn_SAT_SHFT)

#define NOC_QOS_REG_BASE(b)		((b) + 0x00003000)
#define NOC_QOS_REG_BASE(b, o)		((b) + (o))

#define NOC_QOS_ID_COREIDn_ADDR(b, n)	(NOC_QOS_REG_BASE(b) + 0x80 * (n))
#define NOC_QOS_ID_COREIDn_ADDR(b, o, n) \
	(NOC_QOS_REG_BASE(b, o) + 0x80 * (n))
enum noc_qos_id_coreidn {
	NOC_QOS_ID_COREIDn_RMSK			= 0xffffffff,
	NOC_QOS_ID_COREIDn_MAXn			= 32,
@@ -37,8 +39,8 @@ enum noc_qos_id_coreidn {
	NOC_QOS_ID_COREIDn_CORETYPEID_SHFT	= 0x0,
};

#define NOC_QOS_ID_REVISIONIDn_ADDR(b, n) \
	(NOC_QOS_REG_BASE(b) + 0x4 + 0x80 * (n))
#define NOC_QOS_ID_REVISIONIDn_ADDR(b, o, n) \
	(NOC_QOS_REG_BASE(b, o) + 0x4 + 0x80 * (n))
enum noc_qos_id_revisionidn {
	NOC_QOS_ID_REVISIONIDn_RMSK		= 0xffffffff,
	NOC_QOS_ID_REVISIONIDn_MAXn		= 32,
@@ -48,8 +50,8 @@ enum noc_qos_id_revisionidn {
	NOC_QOS_ID_REVISIONIDn_USERID_SHFT	= 0x0,
};

#define NOC_QOS_PRIORITYn_ADDR(b, n)	\
	(NOC_QOS_REG_BASE(b) + 0x8 + 0x80 * (n))
#define NOC_QOS_PRIORITYn_ADDR(b, o, n)	\
	(NOC_QOS_REG_BASE(b, o) + 0x8 + 0x80 * (n))
enum noc_qos_id_priorityn {
	NOC_QOS_PRIORITYn_RMSK		= 0x0000000f,
	NOC_QOS_PRIORITYn_MAXn		= 32,
@@ -59,8 +61,8 @@ enum noc_qos_id_priorityn {
	NOC_QOS_PRIORITYn_P0_SHFT	= 0x0,
};

#define NOC_QOS_MODEn_ADDR(b, n) \
	(NOC_QOS_REG_BASE(b) + 0xC + 0x80 * (n))
#define NOC_QOS_MODEn_ADDR(b, o, n) \
	(NOC_QOS_REG_BASE(b, o) + 0xC + 0x80 * (n))
enum noc_qos_id_moden_rmsk {
	NOC_QOS_MODEn_RMSK		= 0x00000003,
	NOC_QOS_MODEn_MAXn		= 32,
@@ -68,8 +70,8 @@ enum noc_qos_id_moden_rmsk {
	NOC_QOS_MODEn_MODE_SHFT		= 0x0,
};

#define NOC_QOS_BWn_ADDR(b, n) \
	(NOC_QOS_REG_BASE(b) + 0x10 + 0x80 * (n))
#define NOC_QOS_BWn_ADDR(b, o, n) \
	(NOC_QOS_REG_BASE(b, o) + 0x10 + 0x80 * (n))
enum noc_qos_id_bwn {
	NOC_QOS_BWn_RMSK		= 0x0000ffff,
	NOC_QOS_BWn_MAXn		= 32,
@@ -78,8 +80,8 @@ enum noc_qos_id_bwn {
};

/* QOS Saturation registers */
#define NOC_QOS_SATn_ADDR(b, n) \
	(NOC_QOS_REG_BASE(b) + 0x14 + 0x80 * (n))
#define NOC_QOS_SATn_ADDR(b, o, n) \
	(NOC_QOS_REG_BASE(b, o) + 0x14 + 0x80 * (n))
enum noc_qos_id_saturationn {
	NOC_QOS_SATn_RMSK		= 0x000003ff,
	NOC_QOS_SATn_MAXn		= 32,
@@ -196,10 +198,11 @@ static void noc_set_qos_mode(struct msm_bus_noc_info *ninfo, uint32_t mport,
		uint32_t reg_val;

		reg_val = readl_relaxed(NOC_QOS_MODEn_ADDR(ninfo->base,
			mport)) & NOC_QOS_MODEn_RMSK;
			ninfo->qos_baseoffset, mport)) & NOC_QOS_MODEn_RMSK;
		writel_relaxed(((reg_val & (~(NOC_QOS_MODEn_MODE_BMSK))) |
			(mode & NOC_QOS_MODEn_MODE_BMSK)),
			NOC_QOS_MODEn_ADDR(ninfo->base, mport));
			NOC_QOS_MODEn_ADDR(ninfo->base, ninfo->qos_baseoffset,
						mport));
	}
	/* Ensure qos mode is set before exiting */
	wmb();
@@ -210,18 +213,23 @@ static void noc_set_qos_priority(struct msm_bus_noc_info *ninfo, uint32_t mport,
{
	uint32_t reg_val, val;

	reg_val = readl_relaxed(NOC_QOS_PRIORITYn_ADDR(ninfo->base, mport))
	reg_val = readl_relaxed(NOC_QOS_PRIORITYn_ADDR(ninfo->base,
						ninfo->qos_baseoffset, mport))
				& NOC_QOS_PRIORITYn_RMSK;
	val = priority->p1 << NOC_QOS_PRIORITYn_P1_SHFT;
	writel_relaxed(((reg_val & (~(NOC_QOS_PRIORITYn_P1_BMSK))) |
		(val & NOC_QOS_PRIORITYn_P1_BMSK)),
		NOC_QOS_PRIORITYn_ADDR(ninfo->base, mport));
		NOC_QOS_PRIORITYn_ADDR(ninfo->base, ninfo->qos_baseoffset,
								mport));

	reg_val = readl_relaxed(NOC_QOS_PRIORITYn_ADDR(ninfo->base, mport))
	reg_val = readl_relaxed(NOC_QOS_PRIORITYn_ADDR(ninfo->base,
							ninfo->qos_baseoffset,
							mport))
				& NOC_QOS_PRIORITYn_RMSK;
	writel_relaxed(((reg_val & (~(NOC_QOS_PRIORITYn_P0_BMSK))) |
		(priority->p0 & NOC_QOS_PRIORITYn_P0_BMSK)),
		NOC_QOS_PRIORITYn_ADDR(ninfo->base, mport));
		NOC_QOS_PRIORITYn_ADDR(ninfo->base, ninfo->qos_baseoffset,
						mport));
	/* Ensure qos priority is set before exiting */
	wmb();
}
@@ -251,33 +259,38 @@ static void msm_bus_noc_set_qos_bw(struct msm_bus_noc_info *ninfo,
		 * Clear QoS accumulator
		 **/
		mode = readl_relaxed(NOC_QOS_MODEn_ADDR(ninfo->base,
			mport)) & NOC_QOS_MODEn_MODE_BMSK;
			ninfo->qos_baseoffset, mport))
					& NOC_QOS_MODEn_MODE_BMSK;
		if (mode == NOC_QOS_MODE_REGULATOR || mode ==
			NOC_QOS_MODE_LIMITER) {
			reg_val = readl_relaxed(NOC_QOS_MODEn_ADDR(ninfo->
				base, mport));
				base, ninfo->qos_baseoffset, mport));
			val = NOC_QOS_MODE_FIXED;
			writel_relaxed((reg_val & (~(NOC_QOS_MODEn_MODE_BMSK)))
				| (val & NOC_QOS_MODEn_MODE_BMSK),
				NOC_QOS_MODEn_ADDR(ninfo->base, mport));
				NOC_QOS_MODEn_ADDR(ninfo->base,
						ninfo->qos_baseoffset, mport));
		}

		reg_val = readl_relaxed(NOC_QOS_BWn_ADDR(ninfo->base, mport));
		reg_val = readl_relaxed(NOC_QOS_BWn_ADDR(ninfo->base,
						ninfo->qos_baseoffset, mport));
		val = bw_val << NOC_QOS_BWn_BW_SHFT;
		writel_relaxed(((reg_val & (~(NOC_QOS_BWn_BW_BMSK))) |
			(val & NOC_QOS_BWn_BW_BMSK)),
			NOC_QOS_BWn_ADDR(ninfo->base, mport));
			NOC_QOS_BWn_ADDR(ninfo->base, ninfo->qos_baseoffset,
								mport));

		MSM_BUS_DBG("NOC: BW: Wrote value: 0x%x\n", ((reg_val &
			(~NOC_QOS_BWn_BW_BMSK)) | (val &
			NOC_QOS_BWn_BW_BMSK)));

		reg_val = readl_relaxed(NOC_QOS_SATn_ADDR(ninfo->base,
			mport));
			ninfo->qos_baseoffset, mport));
		val = sat_val << NOC_QOS_SATn_SAT_SHFT;
		writel_relaxed(((reg_val & (~(NOC_QOS_SATn_SAT_BMSK))) |
			(val & NOC_QOS_SATn_SAT_BMSK)),
			NOC_QOS_SATn_ADDR(ninfo->base, mport));
			NOC_QOS_SATn_ADDR(ninfo->base, ninfo->qos_baseoffset,
									mport));

		MSM_BUS_DBG("NOC: SAT: Wrote value: 0x%x\n", ((reg_val &
			(~NOC_QOS_SATn_SAT_BMSK)) | (val &
@@ -285,10 +298,11 @@ static void msm_bus_noc_set_qos_bw(struct msm_bus_noc_info *ninfo,

		/* Set mode back to what it was initially */
		reg_val = readl_relaxed(NOC_QOS_MODEn_ADDR(ninfo->base,
			mport));
				ninfo->qos_baseoffset, mport));
		writel_relaxed((reg_val & (~(NOC_QOS_MODEn_MODE_BMSK)))
			| (mode & NOC_QOS_MODEn_MODE_BMSK),
			NOC_QOS_MODEn_ADDR(ninfo->base, mport));
			NOC_QOS_MODEn_ADDR(ninfo->base, ninfo->qos_baseoffset,
							mport));
		/* Ensure that all writes for bandwidth registers have
		 * completed before returning
		 */
@@ -301,7 +315,8 @@ uint8_t msm_bus_noc_get_qos_mode(struct msm_bus_noc_info *ninfo,
{
	if (NOC_QOS_MODES_ALL_PERM == perm_mode)
		return readl_relaxed(NOC_QOS_MODEn_ADDR(ninfo->base,
			mport)) & NOC_QOS_MODEn_MODE_BMSK;
			ninfo->qos_baseoffset, mport)) &
						NOC_QOS_MODEn_MODE_BMSK;
	else
		return 31 - __CLZ(mode &
			NOC_QOS_MODES_ALL_PERM);
@@ -311,11 +326,11 @@ void msm_bus_noc_get_qos_priority(struct msm_bus_noc_info *ninfo,
	uint32_t mport, struct msm_bus_noc_qos_priority *priority)
{
	priority->p1 = (readl_relaxed(NOC_QOS_PRIORITYn_ADDR(ninfo->base,
		mport)) & NOC_QOS_PRIORITYn_P1_BMSK) >>
		ninfo->qos_baseoffset, mport)) & NOC_QOS_PRIORITYn_P1_BMSK) >>
		NOC_QOS_PRIORITYn_P1_SHFT;

	priority->p0 = (readl_relaxed(NOC_QOS_PRIORITYn_ADDR(ninfo->base,
		mport)) & NOC_QOS_PRIORITYn_P0_BMSK) >>
		ninfo->qos_baseoffset, mport)) & NOC_QOS_PRIORITYn_P0_BMSK) >>
		NOC_QOS_PRIORITYn_P0_SHFT;
}

@@ -325,9 +340,11 @@ void msm_bus_noc_get_qos_bw(struct msm_bus_noc_info *ninfo,
	if (perm_mode & (NOC_QOS_PERM_MODE_LIMITER |
		NOC_QOS_PERM_MODE_REGULATOR)) {
		uint32_t bw_val = readl_relaxed(NOC_QOS_BWn_ADDR(ninfo->
			base, mport)) & NOC_QOS_BWn_BW_BMSK;
			base, ninfo->qos_baseoffset, mport)) &
							NOC_QOS_BWn_BW_BMSK;
		uint32_t sat = readl_relaxed(NOC_QOS_SATn_ADDR(ninfo->
			base, mport)) & NOC_QOS_SATn_SAT_BMSK;
			base, ninfo->qos_baseoffset, mport)) &
						NOC_QOS_SATn_SAT_BMSK;

		qbw->bw = noc_bw(bw_val, ninfo->qos_freq);
		qbw->ws = noc_ws(qbw->bw, sat, ninfo->qos_freq);
@@ -431,6 +448,12 @@ static void *msm_bus_noc_allocate_noc_data(struct platform_device *pdev,
	ninfo->nqos_masters = fab_pdata->nmasters;
	ninfo->nslaves = fab_pdata->nslaves;
	ninfo->qos_freq = fab_pdata->qos_freq;

	if (!fab_pdata->qos_baseoffset)
		ninfo->qos_baseoffset = QOS_DEFAULT_BASEOFFSET;
	else
		ninfo->qos_baseoffset = fab_pdata->qos_baseoffset;

	ninfo->mas_modes = kzalloc(sizeof(uint32_t) * fab_pdata->nmasters,
		GFP_KERNEL);
	if (!ninfo->mas_modes) {
+2 −1
Original line number Diff line number Diff line
/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2014, 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
@@ -44,6 +44,7 @@ struct msm_bus_noc_info {
	uint32_t nqos_masters;
	uint32_t nslaves;
	uint32_t qos_freq; /* QOS Clock in KHz */
	uint32_t qos_baseoffset;
	uint32_t *mas_modes;
	struct msm_bus_noc_commit cdata[NUM_CTX];
};
+6 −1
Original line number Diff line number Diff line
/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2014, 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
@@ -572,6 +572,11 @@ struct msm_bus_fabric_registration
	if (of_property_read_bool(of_node, "qcom,virt"))
		pdata->virt = true;

	ret = of_property_read_u32(of_node, "qcom,qos-baseoffset",
						&pdata->qos_baseoffset);
	if (ret)
		pr_debug("%s:qos_baseoffset not available\n", __func__);

	if (of_property_read_bool(of_node, "qcom,rpm-en"))
		pdata->rpm_enabled = 1;