All of lore.kernel.org
 help / color / mirror / Atom feed
From: csd@broadcom.com (Christian Daudt)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH] ARM: bcm281xx: Add L2 support for Rev A2 chips
Date: Tue, 30 Apr 2013 11:38:09 -0700	[thread overview]
Message-ID: <1367347089-23788-1-git-send-email-csd@broadcom.com> (raw)

Rev A2 SoCs have an unorthodox memory re-mapping and this needs
to be reflected in the cache operations.
This patch adds new outer cache functions for the l2x0 driver
to support this SoC revision. It also adds a new compatible
value for the cache to enable this functionality.

Signed-off-by: Christian Daudt <csd@broadcom.com>

diff --git a/Documentation/devicetree/bindings/arm/l2cc.txt b/Documentation/devicetree/bindings/arm/l2cc.txt
index cbef09b..69ddf9f 100644
--- a/Documentation/devicetree/bindings/arm/l2cc.txt
+++ b/Documentation/devicetree/bindings/arm/l2cc.txt
@@ -16,6 +16,9 @@ Required properties:
      performs the same operation).
 	"marvell,"aurora-outer-cache: Marvell Controller designed to be
 	 compatible with the ARM one with outer cache mode.
+	"bcm,bcm11351-a2-pl310-cache": For Broadcom bcm11351 chipset where an
+	offset needs to be added to the address before passing down to the L2
+	cache controller
 - cache-unified : Specifies the cache is a unified cache.
 - cache-level : Should be set to 2 for a level 2 cache.
 - reg : Physical base address and size of cache controller's memory mapped
diff --git a/arch/arm/boot/dts/bcm11351.dtsi b/arch/arm/boot/dts/bcm11351.dtsi
index 41b2c6c..5e48c85 100644
--- a/arch/arm/boot/dts/bcm11351.dtsi
+++ b/arch/arm/boot/dts/bcm11351.dtsi
@@ -47,10 +47,10 @@
 	};
 
 	L2: l2-cache {
-		    compatible = "arm,pl310-cache";
-		    reg = <0x3ff20000 0x1000>;
-		    cache-unified;
-		    cache-level = <2>;
+		compatible = "bcm,bcm11351-a2-pl310-cache";
+		reg = <0x3ff20000 0x1000>;
+		cache-unified;
+		cache-level = <2>;
 	};
 
 	timer at 35006000 {
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index c465fac..6edba13 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -523,6 +523,162 @@ static void aurora_flush_range(unsigned long start, unsigned long end)
 	}
 }
 
+/*
+ * For certain Broadcom SoCs, depending on the address range, different offsets
+ * need to be added to the address before passing it to L2 for
+ * invalidation/clean/flush
+ *
+ * Section Address Range              Offset        EMI
+ *   1     0x00000000 - 0x3FFFFFFF    0x80000000    VC
+ *   2     0x40000000 - 0xBFFFFFFF    0x40000000    SYS
+ *   3     0xC0000000 - 0xFFFFFFFF    0x80000000    VC
+ *
+ * When the start and end addresses have crossed two different sections, we
+ * need to break the L2 operation into two, each within its own section.
+ * For example, if we need to invalidate addresses starts at 0xBFFF0000 and
+ * ends at 0xC0001000, we need do invalidate 1) 0xBFFF0000 - 0xBFFFFFFF and 2)
+ * 0xC0000000 - 0xC0001000
+ *
+ * Note 1:
+ * By breaking a single L2 operation into two, we may potentially suffer some
+ * performance hit, but keep in mind the cross section case is very rare
+ *
+ * Note 2:
+ * We do not need to handle the case when the start address is in
+ * Section 1 and the end address is in Section 3, since it is not a valid use
+ * case
+ */
+
+#define BCM_VC_EMI_SEC1_START_ADDR    0x00000000UL
+#define BCM_VC_EMI_SEC1_END_ADDR      0x3FFFFFFFUL
+#define BCM_SYS_EMI_START_ADDR        0x40000000UL
+#define BCM_SYS_EMI_END_ADDR          0xBFFFFFFFUL
+#define BCM_VC_EMI_SEC3_START_ADDR    0xC0000000UL
+#define BCM_VC_EMI_SEC3_END_ADDR      0xFFFFFFFFUL
+
+#define BCM_SYS_EMI_OFFSET            0x40000000UL
+#define BCM_VC_EMI_OFFSET             0x80000000UL
+
+static inline int bcm_addr_is_sys_emi(unsigned long addr)
+{
+	return (addr >= BCM_SYS_EMI_START_ADDR) &&
+		(addr <= BCM_SYS_EMI_END_ADDR);
+}
+
+static inline unsigned long bcm_l2_phys_addr(unsigned long addr)
+{
+	if (bcm_addr_is_sys_emi(addr))
+		return addr + BCM_SYS_EMI_OFFSET;
+	else
+		return addr + BCM_VC_EMI_OFFSET;
+}
+
+static void bcm_inv_range(unsigned long start, unsigned long end)
+{
+	unsigned long new_start, new_end;
+
+	if (unlikely(end <= start))
+		return;
+
+	new_start = bcm_l2_phys_addr(start);
+	new_end = bcm_l2_phys_addr(end);
+
+	/* normal case, no cross section between start and end */
+	if (likely((bcm_addr_is_sys_emi(start) && bcm_addr_is_sys_emi(end)) ||
+		(!bcm_addr_is_sys_emi(start) && !bcm_addr_is_sys_emi(end)))) {
+		l2x0_inv_range(new_start, new_end);
+		return;
+	}
+
+	if (bcm_addr_is_sys_emi(start)) {
+		/* start address in Section 2. end address in Section 3 */
+		l2x0_inv_range(new_start,
+				bcm_l2_phys_addr(BCM_SYS_EMI_END_ADDR));
+		l2x0_inv_range(bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR),
+				new_end);
+	} else {
+		/* start address in Section 1. end address in Section 2 */
+		l2x0_inv_range(new_start,
+				bcm_l2_phys_addr(BCM_VC_EMI_SEC1_END_ADDR));
+		l2x0_inv_range(bcm_l2_phys_addr(BCM_SYS_EMI_START_ADDR),
+				new_end);
+	}
+}
+
+static void bcm_clean_range(unsigned long start, unsigned long end)
+{
+	unsigned long new_start, new_end;
+
+	if (unlikely(end <= start))
+		return;
+
+	if ((end - start) >= l2x0_size) {
+		l2x0_clean_all();
+		return;
+	}
+
+	new_start = bcm_l2_phys_addr(start);
+	new_end = bcm_l2_phys_addr(end);
+
+	/* normal case, no cross section between start and end */
+	if (likely((bcm_addr_is_sys_emi(start) && bcm_addr_is_sys_emi(end)) ||
+		(!bcm_addr_is_sys_emi(start) && !bcm_addr_is_sys_emi(end)))) {
+		l2x0_clean_range(new_start, new_end);
+		return;
+	}
+
+	if (bcm_addr_is_sys_emi(start)) {
+		/* start address in Section 2. end address in Section 3 */
+		l2x0_clean_range(new_start,
+				bcm_l2_phys_addr(BCM_SYS_EMI_END_ADDR));
+		l2x0_clean_range(bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR),
+				new_end);
+	} else {
+		/* start address in Section 1. end address in Section 2 */
+		l2x0_clean_range(new_start,
+				bcm_l2_phys_addr(BCM_VC_EMI_SEC1_END_ADDR));
+		l2x0_clean_range(bcm_l2_phys_addr(BCM_SYS_EMI_START_ADDR),
+				new_end);
+	}
+}
+
+static void bcm_flush_range(unsigned long start, unsigned long end)
+{
+	unsigned long new_start, new_end;
+
+	if (unlikely(end <= start))
+		return;
+
+	if ((end - start) >= l2x0_size) {
+		l2x0_flush_all();
+		return;
+	}
+
+	new_start = bcm_l2_phys_addr(start);
+	new_end = bcm_l2_phys_addr(end);
+
+	/* normal case, no cross section between start and end */
+	if (likely((bcm_addr_is_sys_emi(start) && bcm_addr_is_sys_emi(end)) ||
+		(!bcm_addr_is_sys_emi(start) && !bcm_addr_is_sys_emi(end)))) {
+		l2x0_flush_range(new_start, new_end);
+		return;
+	}
+
+	if (bcm_addr_is_sys_emi(start)) {
+		/* start address in Section 2. end address in Section 3 */
+		l2x0_flush_range(new_start,
+				bcm_l2_phys_addr(BCM_SYS_EMI_END_ADDR));
+		l2x0_flush_range(bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR),
+				new_end);
+	} else {
+		/* start address in Section 1. end address in Section 2 */
+		l2x0_flush_range(new_start,
+				bcm_l2_phys_addr(BCM_VC_EMI_SEC1_END_ADDR));
+		l2x0_flush_range(bcm_l2_phys_addr(BCM_SYS_EMI_START_ADDR),
+				new_end);
+	}
+}
+
 static void __init l2x0_of_setup(const struct device_node *np,
 				 u32 *aux_val, u32 *aux_mask)
 {
@@ -765,6 +921,21 @@ static const struct l2x0_of_data aurora_no_outer_data = {
 	},
 };
 
+static const struct l2x0_of_data bcm_l2x0_data = {
+	.setup = pl310_of_setup,
+	.save  = pl310_save,
+	.outer_cache = {
+		.resume      = pl310_resume,
+		.inv_range   = bcm_inv_range,
+		.clean_range = bcm_clean_range,
+		.flush_range = bcm_flush_range,
+		.sync        = l2x0_cache_sync,
+		.flush_all   = l2x0_flush_all,
+		.inv_all     = l2x0_inv_all,
+		.disable     = l2x0_disable,
+	},
+};
+
 static const struct of_device_id l2x0_ids[] __initconst = {
 	{ .compatible = "arm,pl310-cache", .data = (void *)&pl310_data },
 	{ .compatible = "arm,l220-cache", .data = (void *)&l2x0_data },
@@ -773,6 +944,8 @@ static const struct of_device_id l2x0_ids[] __initconst = {
 	  .data = (void *)&aurora_no_outer_data},
 	{ .compatible = "marvell,aurora-outer-cache",
 	  .data = (void *)&aurora_with_outer_data},
+	{ .compatible = "bcm,bcm11351-a2-pl310-cache",
+	  .data = (void *)&bcm_l2x0_data},
 	{}
 };
 
-- 
1.7.10.4

WARNING: multiple messages have this Message-ID (diff)
From: "Christian Daudt" <csd@broadcom.com>
To: Russell King <linux@arm.linux.org.uk>,
	John Stultz <johnstul@us.ibm.com>,
	Thomas Gleixner <tglx@linutronix.de>,
	Olof Johansson <olof@lixom.net>, Arnd Bergmann <arnd@arndb.de>,
	Stephen Warren <swarren@wwwdotorg.org>,
	Will Deacon <will.deacon@arm.com>
Cc: Christian Daudt <csd@broadcom.com>,
	"arm@kernel.org" <arm@kernel.org>,
	linux-arm-kernel@lists.infradead.org, csd_b@daudt.org,
	Rob Herring <rob.herring@calxeda.com>,
	Rob Landley <rob@landley.net>,
	Josh Cartwright <josh.cartwright@ni.com>,
	Yehuda Yitschak <yehuday@marvell.com>,
	Gregory CLEMENT <gregory.clement@free-electrons.com>,
	John Stultz <john.stultz@linaro.org>,
	devicetree-discuss@lists.ozlabs.org, linux-doc@vger.kernel.org,
	linux-kernel@vger.kernel.org
Subject: [PATCH] ARM: bcm281xx: Add L2 support for Rev A2 chips
Date: Tue, 30 Apr 2013 11:38:09 -0700	[thread overview]
Message-ID: <1367347089-23788-1-git-send-email-csd@broadcom.com> (raw)

Rev A2 SoCs have an unorthodox memory re-mapping and this needs
to be reflected in the cache operations.
This patch adds new outer cache functions for the l2x0 driver
to support this SoC revision. It also adds a new compatible
value for the cache to enable this functionality.

Signed-off-by: Christian Daudt <csd@broadcom.com>

diff --git a/Documentation/devicetree/bindings/arm/l2cc.txt b/Documentation/devicetree/bindings/arm/l2cc.txt
index cbef09b..69ddf9f 100644
--- a/Documentation/devicetree/bindings/arm/l2cc.txt
+++ b/Documentation/devicetree/bindings/arm/l2cc.txt
@@ -16,6 +16,9 @@ Required properties:
      performs the same operation).
 	"marvell,"aurora-outer-cache: Marvell Controller designed to be
 	 compatible with the ARM one with outer cache mode.
+	"bcm,bcm11351-a2-pl310-cache": For Broadcom bcm11351 chipset where an
+	offset needs to be added to the address before passing down to the L2
+	cache controller
 - cache-unified : Specifies the cache is a unified cache.
 - cache-level : Should be set to 2 for a level 2 cache.
 - reg : Physical base address and size of cache controller's memory mapped
diff --git a/arch/arm/boot/dts/bcm11351.dtsi b/arch/arm/boot/dts/bcm11351.dtsi
index 41b2c6c..5e48c85 100644
--- a/arch/arm/boot/dts/bcm11351.dtsi
+++ b/arch/arm/boot/dts/bcm11351.dtsi
@@ -47,10 +47,10 @@
 	};
 
 	L2: l2-cache {
-		    compatible = "arm,pl310-cache";
-		    reg = <0x3ff20000 0x1000>;
-		    cache-unified;
-		    cache-level = <2>;
+		compatible = "bcm,bcm11351-a2-pl310-cache";
+		reg = <0x3ff20000 0x1000>;
+		cache-unified;
+		cache-level = <2>;
 	};
 
 	timer@35006000 {
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index c465fac..6edba13 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -523,6 +523,162 @@ static void aurora_flush_range(unsigned long start, unsigned long end)
 	}
 }
 
+/*
+ * For certain Broadcom SoCs, depending on the address range, different offsets
+ * need to be added to the address before passing it to L2 for
+ * invalidation/clean/flush
+ *
+ * Section Address Range              Offset        EMI
+ *   1     0x00000000 - 0x3FFFFFFF    0x80000000    VC
+ *   2     0x40000000 - 0xBFFFFFFF    0x40000000    SYS
+ *   3     0xC0000000 - 0xFFFFFFFF    0x80000000    VC
+ *
+ * When the start and end addresses have crossed two different sections, we
+ * need to break the L2 operation into two, each within its own section.
+ * For example, if we need to invalidate addresses starts at 0xBFFF0000 and
+ * ends at 0xC0001000, we need do invalidate 1) 0xBFFF0000 - 0xBFFFFFFF and 2)
+ * 0xC0000000 - 0xC0001000
+ *
+ * Note 1:
+ * By breaking a single L2 operation into two, we may potentially suffer some
+ * performance hit, but keep in mind the cross section case is very rare
+ *
+ * Note 2:
+ * We do not need to handle the case when the start address is in
+ * Section 1 and the end address is in Section 3, since it is not a valid use
+ * case
+ */
+
+#define BCM_VC_EMI_SEC1_START_ADDR    0x00000000UL
+#define BCM_VC_EMI_SEC1_END_ADDR      0x3FFFFFFFUL
+#define BCM_SYS_EMI_START_ADDR        0x40000000UL
+#define BCM_SYS_EMI_END_ADDR          0xBFFFFFFFUL
+#define BCM_VC_EMI_SEC3_START_ADDR    0xC0000000UL
+#define BCM_VC_EMI_SEC3_END_ADDR      0xFFFFFFFFUL
+
+#define BCM_SYS_EMI_OFFSET            0x40000000UL
+#define BCM_VC_EMI_OFFSET             0x80000000UL
+
+static inline int bcm_addr_is_sys_emi(unsigned long addr)
+{
+	return (addr >= BCM_SYS_EMI_START_ADDR) &&
+		(addr <= BCM_SYS_EMI_END_ADDR);
+}
+
+static inline unsigned long bcm_l2_phys_addr(unsigned long addr)
+{
+	if (bcm_addr_is_sys_emi(addr))
+		return addr + BCM_SYS_EMI_OFFSET;
+	else
+		return addr + BCM_VC_EMI_OFFSET;
+}
+
+static void bcm_inv_range(unsigned long start, unsigned long end)
+{
+	unsigned long new_start, new_end;
+
+	if (unlikely(end <= start))
+		return;
+
+	new_start = bcm_l2_phys_addr(start);
+	new_end = bcm_l2_phys_addr(end);
+
+	/* normal case, no cross section between start and end */
+	if (likely((bcm_addr_is_sys_emi(start) && bcm_addr_is_sys_emi(end)) ||
+		(!bcm_addr_is_sys_emi(start) && !bcm_addr_is_sys_emi(end)))) {
+		l2x0_inv_range(new_start, new_end);
+		return;
+	}
+
+	if (bcm_addr_is_sys_emi(start)) {
+		/* start address in Section 2. end address in Section 3 */
+		l2x0_inv_range(new_start,
+				bcm_l2_phys_addr(BCM_SYS_EMI_END_ADDR));
+		l2x0_inv_range(bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR),
+				new_end);
+	} else {
+		/* start address in Section 1. end address in Section 2 */
+		l2x0_inv_range(new_start,
+				bcm_l2_phys_addr(BCM_VC_EMI_SEC1_END_ADDR));
+		l2x0_inv_range(bcm_l2_phys_addr(BCM_SYS_EMI_START_ADDR),
+				new_end);
+	}
+}
+
+static void bcm_clean_range(unsigned long start, unsigned long end)
+{
+	unsigned long new_start, new_end;
+
+	if (unlikely(end <= start))
+		return;
+
+	if ((end - start) >= l2x0_size) {
+		l2x0_clean_all();
+		return;
+	}
+
+	new_start = bcm_l2_phys_addr(start);
+	new_end = bcm_l2_phys_addr(end);
+
+	/* normal case, no cross section between start and end */
+	if (likely((bcm_addr_is_sys_emi(start) && bcm_addr_is_sys_emi(end)) ||
+		(!bcm_addr_is_sys_emi(start) && !bcm_addr_is_sys_emi(end)))) {
+		l2x0_clean_range(new_start, new_end);
+		return;
+	}
+
+	if (bcm_addr_is_sys_emi(start)) {
+		/* start address in Section 2. end address in Section 3 */
+		l2x0_clean_range(new_start,
+				bcm_l2_phys_addr(BCM_SYS_EMI_END_ADDR));
+		l2x0_clean_range(bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR),
+				new_end);
+	} else {
+		/* start address in Section 1. end address in Section 2 */
+		l2x0_clean_range(new_start,
+				bcm_l2_phys_addr(BCM_VC_EMI_SEC1_END_ADDR));
+		l2x0_clean_range(bcm_l2_phys_addr(BCM_SYS_EMI_START_ADDR),
+				new_end);
+	}
+}
+
+static void bcm_flush_range(unsigned long start, unsigned long end)
+{
+	unsigned long new_start, new_end;
+
+	if (unlikely(end <= start))
+		return;
+
+	if ((end - start) >= l2x0_size) {
+		l2x0_flush_all();
+		return;
+	}
+
+	new_start = bcm_l2_phys_addr(start);
+	new_end = bcm_l2_phys_addr(end);
+
+	/* normal case, no cross section between start and end */
+	if (likely((bcm_addr_is_sys_emi(start) && bcm_addr_is_sys_emi(end)) ||
+		(!bcm_addr_is_sys_emi(start) && !bcm_addr_is_sys_emi(end)))) {
+		l2x0_flush_range(new_start, new_end);
+		return;
+	}
+
+	if (bcm_addr_is_sys_emi(start)) {
+		/* start address in Section 2. end address in Section 3 */
+		l2x0_flush_range(new_start,
+				bcm_l2_phys_addr(BCM_SYS_EMI_END_ADDR));
+		l2x0_flush_range(bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR),
+				new_end);
+	} else {
+		/* start address in Section 1. end address in Section 2 */
+		l2x0_flush_range(new_start,
+				bcm_l2_phys_addr(BCM_VC_EMI_SEC1_END_ADDR));
+		l2x0_flush_range(bcm_l2_phys_addr(BCM_SYS_EMI_START_ADDR),
+				new_end);
+	}
+}
+
 static void __init l2x0_of_setup(const struct device_node *np,
 				 u32 *aux_val, u32 *aux_mask)
 {
@@ -765,6 +921,21 @@ static const struct l2x0_of_data aurora_no_outer_data = {
 	},
 };
 
+static const struct l2x0_of_data bcm_l2x0_data = {
+	.setup = pl310_of_setup,
+	.save  = pl310_save,
+	.outer_cache = {
+		.resume      = pl310_resume,
+		.inv_range   = bcm_inv_range,
+		.clean_range = bcm_clean_range,
+		.flush_range = bcm_flush_range,
+		.sync        = l2x0_cache_sync,
+		.flush_all   = l2x0_flush_all,
+		.inv_all     = l2x0_inv_all,
+		.disable     = l2x0_disable,
+	},
+};
+
 static const struct of_device_id l2x0_ids[] __initconst = {
 	{ .compatible = "arm,pl310-cache", .data = (void *)&pl310_data },
 	{ .compatible = "arm,l220-cache", .data = (void *)&l2x0_data },
@@ -773,6 +944,8 @@ static const struct of_device_id l2x0_ids[] __initconst = {
 	  .data = (void *)&aurora_no_outer_data},
 	{ .compatible = "marvell,aurora-outer-cache",
 	  .data = (void *)&aurora_with_outer_data},
+	{ .compatible = "bcm,bcm11351-a2-pl310-cache",
+	  .data = (void *)&bcm_l2x0_data},
 	{}
 };
 
-- 
1.7.10.4



             reply	other threads:[~2013-04-30 18:38 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-04-30 18:38 Christian Daudt [this message]
2013-04-30 18:38 ` [PATCH] ARM: bcm281xx: Add L2 support for Rev A2 chips Christian Daudt
2013-05-01 10:37 ` Will Deacon
2013-05-01 10:37   ` Will Deacon
2013-05-01 18:09   ` Christian Daudt
2013-05-01 18:09     ` Christian Daudt
2013-05-01 18:09     ` Christian Daudt

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1367347089-23788-1-git-send-email-csd@broadcom.com \
    --to=csd@broadcom.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.