From david.daney@cavium.com Fri Jul  1 00:31:11 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 01 Jul 2011 00:31:19 +0200 (CEST)
Received: from mail3.caviumnetworks.com ([12.108.191.235]:13672 "EHLO
        mail3.caviumnetworks.com" rhost-flags-OK-OK-OK-OK)
        by eddie.linux-mips.org with ESMTP id S1491162Ab1F3WbL (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Fri, 1 Jul 2011 00:31:11 +0200
Received: from caexch01.caveonetworks.com (Not Verified[192.168.16.9]) by mail3.caviumnetworks.com with MailMarshal (v6,7,2,8378)
        id <B4e0cf96f0000>; Thu, 30 Jun 2011 15:32:15 -0700
Received: from caexch01.caveonetworks.com ([192.168.16.9]) by caexch01.caveonetworks.com with Microsoft SMTPSVC(6.0.3790.4675);
         Thu, 30 Jun 2011 15:31:08 -0700
Received: from dd1.caveonetworks.com ([12.108.191.236]) by caexch01.caveonetworks.com over TLS secured channel with Microsoft SMTPSVC(6.0.3790.4675);
         Thu, 30 Jun 2011 15:31:07 -0700
Received: from dd1.caveonetworks.com (localhost.localdomain [127.0.0.1])
        by dd1.caveonetworks.com (8.14.4/8.14.3) with ESMTP id p5UMV4FQ011074;
        Thu, 30 Jun 2011 15:31:05 -0700
Received: (from ddaney@localhost)
        by dd1.caveonetworks.com (8.14.4/8.14.4/Submit) id p5UMV47f011073;
        Thu, 30 Jun 2011 15:31:04 -0700
From:   David Daney <david.daney@cavium.com>
To:     linux-mips@linux-mips.org, ralf@linux-mips.org
Cc:     David Daney <david.daney@cavium.com>
Subject: [PATCH] MIPS: Close races in TLB modify handlers.
Date:   Thu, 30 Jun 2011 15:31:02 -0700
Message-Id: <1309473062-11041-1-git-send-email-david.daney@cavium.com>
X-Mailer: git-send-email 1.7.2.3
X-OriginalArrivalTime: 30 Jun 2011 22:31:08.0017 (UTC) FILETIME=[67DD7610:01CC3775]
X-archive-position: 30572
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: david.daney@cavium.com
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                 
X-UID: 97
Content-Length: 17707
Lines: 521

Page table entries are made invalid by writing a zero into the the PTE
slot in a page table.  This creates a race condition with the TLB
modify handlers when they are updating the PTE.

CPU0                              CPU1

Test for _PAGE_PRESENT
.                                 set to not _PAGE_PRESENT (zero)
Set to _PAGE_VALID

So now the page not present value (zero) is suddenly valid and user
space programs have access to physical page zero.

We close the race by putting the test for _PAGE_PRESENT and setting of
_PAGE_VALID into an atomic LL/SC section.  This requires more
registers than just K0 and K1 in the handlers, so we need to save some
registers to a save area and then restore them when we are done.

The save area is an array of cacheline aligned structures that should
not suffer cache line bouncing as they are CPU private.

Signed-off-by: David Daney <david.daney@cavium.com>
---
 arch/mips/mm/tlbex.c |  251 +++++++++++++++++++++++++++++++-------------------
 1 files changed, 157 insertions(+), 94 deletions(-)

diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
index 424ed4b..5335901 100644
--- a/arch/mips/mm/tlbex.c
+++ b/arch/mips/mm/tlbex.c
@@ -42,6 +42,18 @@
 extern void tlb_do_page_fault_0(void);
 extern void tlb_do_page_fault_1(void);
 
+struct work_registers {
+	int r1;
+	int r2;
+	int r3;
+};
+
+struct tlb_reg_save {
+	unsigned long a;
+	unsigned long b;
+} ____cacheline_aligned_in_smp;
+
+static struct tlb_reg_save handler_reg_save[NR_CPUS];
 
 static inline int r45k_bvahwbug(void)
 {
@@ -197,6 +209,7 @@ static inline void dump_handler(const u32 *handler, int count)
 #define C0_BADVADDR	8, 0
 #define C0_ENTRYHI	10, 0
 #define C0_EPC		14, 0
+#define C0_EBASE	15, 1
 #define C0_XCONTEXT	20, 0
 
 #ifdef CONFIG_64BIT
@@ -227,6 +240,38 @@ static int check_for_high_segbits __cpuinitdata;
 
 static unsigned int kscratch_used_mask __cpuinitdata;
 
+static struct work_registers __cpuinit build_get_work_registers(u32 **p)
+{
+	struct work_registers r;
+
+#ifdef CONFIG_SMP
+	/* Mask CPU number out of EBase */
+	UASM_i_MFC0(p, K0, C0_EBASE);
+	uasm_i_andi(p, K0, K0, 0x3ff);
+	/* handler_reg_save index in K0 */
+	UASM_i_SLL(p, K0, K0, ilog2(sizeof(struct tlb_reg_save)));
+
+	UASM_i_LA(p, K1, (long)&handler_reg_save);
+	UASM_i_ADDU(p, K0, K0, K1);
+#else
+	UASM_i_LA(p, K0, (long)&handler_reg_save);
+#endif
+	/* K0 now points to save area, save $1 and $2  */
+	UASM_i_SW(p, 1, offsetof(struct tlb_reg_save, a), K0);
+	UASM_i_SW(p, 2, offsetof(struct tlb_reg_save, b), K0);
+
+	r.r1 = K1;
+	r.r2 = 1;
+	r.r3 = 2;
+	return r;
+}
+static void __cpuinit build_restore_work_registers(u32 **p)
+{
+	/* K0 already points to save area, restore $1 and $2  */
+	UASM_i_LW(p, 1, offsetof(struct tlb_reg_save, a), K0);
+	UASM_i_LW(p, 2, offsetof(struct tlb_reg_save, b), K0);
+}
+
 static int __cpuinit allocate_kscratch(void)
 {
 	int r;
@@ -1462,22 +1507,28 @@ iPTE_SW(u32 **p, struct uasm_reloc **r, unsigned int pte, unsigned int ptr,
  */
 static void __cpuinit
 build_pte_present(u32 **p, struct uasm_reloc **r,
-		  unsigned int pte, unsigned int ptr, enum label_id lid)
+		  int pte, int ptr, int scratch, enum label_id lid)
 {
+	int t = scratch >= 0 ? scratch : pte;
+
 	if (kernel_uses_smartmips_rixi) {
 		if (use_bbit_insns()) {
 			uasm_il_bbit0(p, r, pte, ilog2(_PAGE_PRESENT), lid);
 			uasm_i_nop(p);
 		} else {
-			uasm_i_andi(p, pte, pte, _PAGE_PRESENT);
-			uasm_il_beqz(p, r, pte, lid);
-			iPTE_LW(p, pte, ptr);
+			uasm_i_andi(p, t, pte, _PAGE_PRESENT);
+			uasm_il_beqz(p, r, t, lid);
+			if (pte == t)
+				/* You lose the SMP race :-(*/
+				iPTE_LW(p, pte, ptr);
 		}
 	} else {
-		uasm_i_andi(p, pte, pte, _PAGE_PRESENT | _PAGE_READ);
-		uasm_i_xori(p, pte, pte, _PAGE_PRESENT | _PAGE_READ);
-		uasm_il_bnez(p, r, pte, lid);
-		iPTE_LW(p, pte, ptr);
+		uasm_i_andi(p, t, pte, _PAGE_PRESENT | _PAGE_READ);
+		uasm_i_xori(p, t, t, _PAGE_PRESENT | _PAGE_READ);
+		uasm_il_bnez(p, r, t, lid);
+		if (pte == t)
+			/* You lose the SMP race :-(*/
+			iPTE_LW(p, pte, ptr);
 	}
 }
 
@@ -1497,19 +1548,19 @@ build_make_valid(u32 **p, struct uasm_reloc **r, unsigned int pte,
  */
 static void __cpuinit
 build_pte_writable(u32 **p, struct uasm_reloc **r,
-		   unsigned int pte, unsigned int ptr, enum label_id lid)
+		   unsigned int pte, unsigned int ptr, int scratch,
+		   enum label_id lid)
 {
-	if (use_bbit_insns()) {
-		uasm_il_bbit0(p, r, pte, ilog2(_PAGE_PRESENT), lid);
-		uasm_i_nop(p);
-		uasm_il_bbit0(p, r, pte, ilog2(_PAGE_WRITE), lid);
-		uasm_i_nop(p);
-	} else {
-		uasm_i_andi(p, pte, pte, _PAGE_PRESENT | _PAGE_WRITE);
-		uasm_i_xori(p, pte, pte, _PAGE_PRESENT | _PAGE_WRITE);
-		uasm_il_bnez(p, r, pte, lid);
+	int t = scratch >= 0 ? scratch : pte;
+
+	uasm_i_andi(p, t, pte, _PAGE_PRESENT | _PAGE_WRITE);
+	uasm_i_xori(p, t, t, _PAGE_PRESENT | _PAGE_WRITE);
+	uasm_il_bnez(p, r, t, lid);
+	if (pte == t)
+		/* You lose the SMP race :-(*/
 		iPTE_LW(p, pte, ptr);
-	}
+	else
+		uasm_i_nop(p);
 }
 
 /* Make PTE writable, update software status bits as well, then store
@@ -1531,15 +1582,19 @@ build_make_write(u32 **p, struct uasm_reloc **r, unsigned int pte,
  */
 static void __cpuinit
 build_pte_modifiable(u32 **p, struct uasm_reloc **r,
-		     unsigned int pte, unsigned int ptr, enum label_id lid)
+		     unsigned int pte, unsigned int ptr, int scratch,
+		     enum label_id lid)
 {
 	if (use_bbit_insns()) {
 		uasm_il_bbit0(p, r, pte, ilog2(_PAGE_WRITE), lid);
 		uasm_i_nop(p);
 	} else {
-		uasm_i_andi(p, pte, pte, _PAGE_WRITE);
-		uasm_il_beqz(p, r, pte, lid);
-		iPTE_LW(p, pte, ptr);
+		int t = scratch >= 0 ? scratch : pte;
+		uasm_i_andi(p, t, pte, _PAGE_WRITE);
+		uasm_il_beqz(p, r, t, lid);
+		if (pte == t)
+			/* You lose the SMP race :-(*/
+			iPTE_LW(p, pte, ptr);
 	}
 }
 
@@ -1619,7 +1674,7 @@ static void __cpuinit build_r3000_tlb_load_handler(void)
 	memset(relocs, 0, sizeof(relocs));
 
 	build_r3000_tlbchange_handler_head(&p, K0, K1);
-	build_pte_present(&p, &r, K0, K1, label_nopage_tlbl);
+	build_pte_present(&p, &r, K0, K1, -1, label_nopage_tlbl);
 	uasm_i_nop(&p); /* load delay */
 	build_make_valid(&p, &r, K0, K1);
 	build_r3000_tlb_reload_write(&p, &l, &r, K0, K1);
@@ -1649,7 +1704,7 @@ static void __cpuinit build_r3000_tlb_store_handler(void)
 	memset(relocs, 0, sizeof(relocs));
 
 	build_r3000_tlbchange_handler_head(&p, K0, K1);
-	build_pte_writable(&p, &r, K0, K1, label_nopage_tlbs);
+	build_pte_writable(&p, &r, K0, K1, -1, label_nopage_tlbs);
 	uasm_i_nop(&p); /* load delay */
 	build_make_write(&p, &r, K0, K1);
 	build_r3000_tlb_reload_write(&p, &l, &r, K0, K1);
@@ -1702,15 +1757,16 @@ static void __cpuinit build_r3000_tlb_modify_handler(void)
 /*
  * R4000 style TLB load/store/modify handlers.
  */
-static void __cpuinit
+static struct work_registers __cpuinit
 build_r4000_tlbchange_handler_head(u32 **p, struct uasm_label **l,
-				   struct uasm_reloc **r, unsigned int pte,
-				   unsigned int ptr)
+				   struct uasm_reloc **r)
 {
+	struct work_registers wr = build_get_work_registers(p);
+
 #ifdef CONFIG_64BIT
-	build_get_pmde64(p, l, r, pte, ptr); /* get pmd in ptr */
+	build_get_pmde64(p, l, r, wr.r1, wr.r2); /* get pmd in ptr */
 #else
-	build_get_pgde32(p, pte, ptr); /* get pgd in ptr */
+	build_get_pgde32(p, wr.r1, wr.r2); /* get pgd in ptr */
 #endif
 
 #ifdef CONFIG_HUGETLB_PAGE
@@ -1719,21 +1775,22 @@ build_r4000_tlbchange_handler_head(u32 **p, struct uasm_label **l,
 	 * instead contains the tlb pte. Check the PAGE_HUGE bit and
 	 * see if we need to jump to huge tlb processing.
 	 */
-	build_is_huge_pte(p, r, pte, ptr, label_tlb_huge_update);
+	build_is_huge_pte(p, r, wr.r1, wr.r2, label_tlb_huge_update);
 #endif
 
-	UASM_i_MFC0(p, pte, C0_BADVADDR);
-	UASM_i_LW(p, ptr, 0, ptr);
-	UASM_i_SRL(p, pte, pte, PAGE_SHIFT + PTE_ORDER - PTE_T_LOG2);
-	uasm_i_andi(p, pte, pte, (PTRS_PER_PTE - 1) << PTE_T_LOG2);
-	UASM_i_ADDU(p, ptr, ptr, pte);
+	UASM_i_MFC0(p, wr.r1, C0_BADVADDR);
+	UASM_i_LW(p, wr.r2, 0, wr.r2);
+	UASM_i_SRL(p, wr.r1, wr.r1, PAGE_SHIFT + PTE_ORDER - PTE_T_LOG2);
+	uasm_i_andi(p, wr.r1, wr.r1, (PTRS_PER_PTE - 1) << PTE_T_LOG2);
+	UASM_i_ADDU(p, wr.r2, wr.r2, wr.r1);
 
 #ifdef CONFIG_SMP
 	uasm_l_smp_pgtable_change(l, *p);
 #endif
-	iPTE_LW(p, pte, ptr); /* get even pte */
+	iPTE_LW(p, wr.r1, wr.r2); /* get even pte */
 	if (!m4kc_tlbp_war())
 		build_tlb_probe_entry(p);
+	return wr;
 }
 
 static void __cpuinit
@@ -1746,6 +1803,7 @@ build_r4000_tlbchange_handler_tail(u32 **p, struct uasm_label **l,
 	build_update_entries(p, tmp, ptr);
 	build_tlb_write_entry(p, l, r, tlb_indexed);
 	uasm_l_leave(l, *p);
+	build_restore_work_registers(p);
 	uasm_i_eret(p); /* return from trap */
 
 #ifdef CONFIG_64BIT
@@ -1758,6 +1816,7 @@ static void __cpuinit build_r4000_tlb_load_handler(void)
 	u32 *p = handle_tlbl;
 	struct uasm_label *l = labels;
 	struct uasm_reloc *r = relocs;
+	struct work_registers wr;
 
 	memset(handle_tlbl, 0, sizeof(handle_tlbl));
 	memset(labels, 0, sizeof(labels));
@@ -1777,8 +1836,8 @@ static void __cpuinit build_r4000_tlb_load_handler(void)
 		/* No need for uasm_i_nop */
 	}
 
-	build_r4000_tlbchange_handler_head(&p, &l, &r, K0, K1);
-	build_pte_present(&p, &r, K0, K1, label_nopage_tlbl);
+	wr = build_r4000_tlbchange_handler_head(&p, &l, &r);
+	build_pte_present(&p, &r, wr.r1, wr.r2, wr.r3, label_nopage_tlbl);
 	if (m4kc_tlbp_war())
 		build_tlb_probe_entry(&p);
 
@@ -1788,44 +1847,43 @@ static void __cpuinit build_r4000_tlb_load_handler(void)
 		 * have triggered it.  Skip the expensive test..
 		 */
 		if (use_bbit_insns()) {
-			uasm_il_bbit0(&p, &r, K0, ilog2(_PAGE_VALID),
+			uasm_il_bbit0(&p, &r, wr.r1, ilog2(_PAGE_VALID),
 				      label_tlbl_goaround1);
 		} else {
-			uasm_i_andi(&p, K0, K0, _PAGE_VALID);
-			uasm_il_beqz(&p, &r, K0, label_tlbl_goaround1);
+			uasm_i_andi(&p, wr.r3, wr.r1, _PAGE_VALID);
+			uasm_il_beqz(&p, &r, wr.r3, label_tlbl_goaround1);
 		}
 		uasm_i_nop(&p);
 
 		uasm_i_tlbr(&p);
 		/* Examine  entrylo 0 or 1 based on ptr. */
 		if (use_bbit_insns()) {
-			uasm_i_bbit0(&p, K1, ilog2(sizeof(pte_t)), 8);
+			uasm_i_bbit0(&p, wr.r2, ilog2(sizeof(pte_t)), 8);
 		} else {
-			uasm_i_andi(&p, K0, K1, sizeof(pte_t));
-			uasm_i_beqz(&p, K0, 8);
+			uasm_i_andi(&p, wr.r3, wr.r2, sizeof(pte_t));
+			uasm_i_beqz(&p, wr.r3, 8);
 		}
-
-		UASM_i_MFC0(&p, K0, C0_ENTRYLO0); /* load it in the delay slot*/
-		UASM_i_MFC0(&p, K0, C0_ENTRYLO1); /* load it if ptr is odd */
+		/* load it in the delay slot*/
+		UASM_i_MFC0(&p, wr.r3, C0_ENTRYLO0);
+		/* load it if ptr is odd */
+		UASM_i_MFC0(&p, wr.r3, C0_ENTRYLO1);
 		/*
-		 * If the entryLo (now in K0) is valid (bit 1), RI or
+		 * If the entryLo (now in wr.r3) is valid (bit 1), RI or
 		 * XI must have triggered it.
 		 */
 		if (use_bbit_insns()) {
-			uasm_il_bbit1(&p, &r, K0, 1, label_nopage_tlbl);
-			/* Reload the PTE value */
-			iPTE_LW(&p, K0, K1);
+			uasm_il_bbit1(&p, &r, wr.r3, 1, label_nopage_tlbl);
+			uasm_i_nop(&p);
 			uasm_l_tlbl_goaround1(&l, p);
 		} else {
-			uasm_i_andi(&p, K0, K0, 2);
-			uasm_il_bnez(&p, &r, K0, label_nopage_tlbl);
-			uasm_l_tlbl_goaround1(&l, p);
-			/* Reload the PTE value */
-			iPTE_LW(&p, K0, K1);
+			uasm_i_andi(&p, wr.r3, wr.r3, 2);
+			uasm_il_bnez(&p, &r, wr.r3, label_nopage_tlbl);
+			uasm_i_nop(&p);
 		}
+		uasm_l_tlbl_goaround1(&l, p);
 	}
-	build_make_valid(&p, &r, K0, K1);
-	build_r4000_tlbchange_handler_tail(&p, &l, &r, K0, K1);
+	build_make_valid(&p, &r, wr.r1, wr.r2);
+	build_r4000_tlbchange_handler_tail(&p, &l, &r, wr.r1, wr.r2);
 
 #ifdef CONFIG_HUGETLB_PAGE
 	/*
@@ -1833,8 +1891,8 @@ static void __cpuinit build_r4000_tlb_load_handler(void)
 	 * spots a huge page.
 	 */
 	uasm_l_tlb_huge_update(&l, p);
-	iPTE_LW(&p, K0, K1);
-	build_pte_present(&p, &r, K0, K1, label_nopage_tlbl);
+	iPTE_LW(&p, wr.r1, wr.r2);
+	build_pte_present(&p, &r, wr.r1, wr.r2, wr.r3, label_nopage_tlbl);
 	build_tlb_probe_entry(&p);
 
 	if (kernel_uses_smartmips_rixi) {
@@ -1843,50 +1901,51 @@ static void __cpuinit build_r4000_tlb_load_handler(void)
 		 * have triggered it.  Skip the expensive test..
 		 */
 		if (use_bbit_insns()) {
-			uasm_il_bbit0(&p, &r, K0, ilog2(_PAGE_VALID),
+			uasm_il_bbit0(&p, &r, wr.r1, ilog2(_PAGE_VALID),
 				      label_tlbl_goaround2);
 		} else {
-			uasm_i_andi(&p, K0, K0, _PAGE_VALID);
-			uasm_il_beqz(&p, &r, K0, label_tlbl_goaround2);
+			uasm_i_andi(&p, wr.r3, wr.r1, _PAGE_VALID);
+			uasm_il_beqz(&p, &r, wr.r3, label_tlbl_goaround2);
 		}
 		uasm_i_nop(&p);
 
 		uasm_i_tlbr(&p);
 		/* Examine  entrylo 0 or 1 based on ptr. */
 		if (use_bbit_insns()) {
-			uasm_i_bbit0(&p, K1, ilog2(sizeof(pte_t)), 8);
+			uasm_i_bbit0(&p, wr.r2, ilog2(sizeof(pte_t)), 8);
 		} else {
-			uasm_i_andi(&p, K0, K1, sizeof(pte_t));
-			uasm_i_beqz(&p, K0, 8);
+			uasm_i_andi(&p, wr.r3, wr.r2, sizeof(pte_t));
+			uasm_i_beqz(&p, wr.r3, 8);
 		}
-		UASM_i_MFC0(&p, K0, C0_ENTRYLO0); /* load it in the delay slot*/
-		UASM_i_MFC0(&p, K0, C0_ENTRYLO1); /* load it if ptr is odd */
+		/* load it in the delay slot*/
+		UASM_i_MFC0(&p, wr.r3, C0_ENTRYLO0);
+		/* load it if ptr is odd */
+		UASM_i_MFC0(&p, wr.r3, C0_ENTRYLO1);
 		/*
-		 * If the entryLo (now in K0) is valid (bit 1), RI or
+		 * If the entryLo (now in wr.r3) is valid (bit 1), RI or
 		 * XI must have triggered it.
 		 */
 		if (use_bbit_insns()) {
-			uasm_il_bbit0(&p, &r, K0, 1, label_tlbl_goaround2);
+			uasm_il_bbit0(&p, &r, wr.r3, 1, label_tlbl_goaround2);
 		} else {
-			uasm_i_andi(&p, K0, K0, 2);
-			uasm_il_beqz(&p, &r, K0, label_tlbl_goaround2);
+			uasm_i_andi(&p, wr.r3, wr.r3, 2);
+			uasm_il_beqz(&p, &r, wr.r3, label_tlbl_goaround2);
 		}
-		/* Reload the PTE value */
-		iPTE_LW(&p, K0, K1);
 
 		/*
 		 * We clobbered C0_PAGEMASK, restore it.  On the other branch
 		 * it is restored in build_huge_tlb_write_entry.
 		 */
-		build_restore_pagemask(&p, &r, K0, label_nopage_tlbl, 0);
+		build_restore_pagemask(&p, &r, wr.r3, label_nopage_tlbl, 0);
 
 		uasm_l_tlbl_goaround2(&l, p);
 	}
-	uasm_i_ori(&p, K0, K0, (_PAGE_ACCESSED | _PAGE_VALID));
-	build_huge_handler_tail(&p, &r, &l, K0, K1);
+	uasm_i_ori(&p, wr.r1, wr.r1, (_PAGE_ACCESSED | _PAGE_VALID));
+	build_huge_handler_tail(&p, &r, &l, wr.r1, wr.r2);
 #endif
 
 	uasm_l_nopage_tlbl(&l, p);
+	build_restore_work_registers(&p);
 	uasm_i_j(&p, (unsigned long)tlb_do_page_fault_0 & 0x0fffffff);
 	uasm_i_nop(&p);
 
@@ -1905,17 +1964,18 @@ static void __cpuinit build_r4000_tlb_store_handler(void)
 	u32 *p = handle_tlbs;
 	struct uasm_label *l = labels;
 	struct uasm_reloc *r = relocs;
+	struct work_registers wr;
 
 	memset(handle_tlbs, 0, sizeof(handle_tlbs));
 	memset(labels, 0, sizeof(labels));
 	memset(relocs, 0, sizeof(relocs));
 
-	build_r4000_tlbchange_handler_head(&p, &l, &r, K0, K1);
-	build_pte_writable(&p, &r, K0, K1, label_nopage_tlbs);
+	wr = build_r4000_tlbchange_handler_head(&p, &l, &r);
+	build_pte_writable(&p, &r, wr.r1, wr.r2, wr.r3, label_nopage_tlbs);
 	if (m4kc_tlbp_war())
 		build_tlb_probe_entry(&p);
-	build_make_write(&p, &r, K0, K1);
-	build_r4000_tlbchange_handler_tail(&p, &l, &r, K0, K1);
+	build_make_write(&p, &r, wr.r1, wr.r2);
+	build_r4000_tlbchange_handler_tail(&p, &l, &r, wr.r1, wr.r2);
 
 #ifdef CONFIG_HUGETLB_PAGE
 	/*
@@ -1923,15 +1983,16 @@ static void __cpuinit build_r4000_tlb_store_handler(void)
 	 * build_r4000_tlbchange_handler_head spots a huge page.
 	 */
 	uasm_l_tlb_huge_update(&l, p);
-	iPTE_LW(&p, K0, K1);
-	build_pte_writable(&p, &r, K0, K1, label_nopage_tlbs);
+	iPTE_LW(&p, wr.r1, wr.r2);
+	build_pte_writable(&p, &r, wr.r1, wr.r2, wr.r3, label_nopage_tlbs);
 	build_tlb_probe_entry(&p);
-	uasm_i_ori(&p, K0, K0,
+	uasm_i_ori(&p, wr.r1, wr.r1,
 		   _PAGE_ACCESSED | _PAGE_MODIFIED | _PAGE_VALID | _PAGE_DIRTY);
-	build_huge_handler_tail(&p, &r, &l, K0, K1);
+	build_huge_handler_tail(&p, &r, &l, wr.r1, wr.r2);
 #endif
 
 	uasm_l_nopage_tlbs(&l, p);
+	build_restore_work_registers(&p);
 	uasm_i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff);
 	uasm_i_nop(&p);
 
@@ -1950,18 +2011,19 @@ static void __cpuinit build_r4000_tlb_modify_handler(void)
 	u32 *p = handle_tlbm;
 	struct uasm_label *l = labels;
 	struct uasm_reloc *r = relocs;
+	struct work_registers wr;
 
 	memset(handle_tlbm, 0, sizeof(handle_tlbm));
 	memset(labels, 0, sizeof(labels));
 	memset(relocs, 0, sizeof(relocs));
 
-	build_r4000_tlbchange_handler_head(&p, &l, &r, K0, K1);
-	build_pte_modifiable(&p, &r, K0, K1, label_nopage_tlbm);
+	wr = build_r4000_tlbchange_handler_head(&p, &l, &r);
+	build_pte_modifiable(&p, &r, wr.r1, wr.r2, wr.r3, label_nopage_tlbm);
 	if (m4kc_tlbp_war())
 		build_tlb_probe_entry(&p);
 	/* Present and writable bits set, set accessed and dirty bits. */
-	build_make_write(&p, &r, K0, K1);
-	build_r4000_tlbchange_handler_tail(&p, &l, &r, K0, K1);
+	build_make_write(&p, &r, wr.r1, wr.r2);
+	build_r4000_tlbchange_handler_tail(&p, &l, &r, wr.r1, wr.r2);
 
 #ifdef CONFIG_HUGETLB_PAGE
 	/*
@@ -1969,15 +2031,16 @@ static void __cpuinit build_r4000_tlb_modify_handler(void)
 	 * build_r4000_tlbchange_handler_head spots a huge page.
 	 */
 	uasm_l_tlb_huge_update(&l, p);
-	iPTE_LW(&p, K0, K1);
-	build_pte_modifiable(&p, &r, K0, K1, label_nopage_tlbm);
+	iPTE_LW(&p, wr.r1, wr.r2);
+	build_pte_modifiable(&p, &r, wr.r1, wr.r2,  wr.r3, label_nopage_tlbm);
 	build_tlb_probe_entry(&p);
-	uasm_i_ori(&p, K0, K0,
+	uasm_i_ori(&p, wr.r1, wr.r1,
 		   _PAGE_ACCESSED | _PAGE_MODIFIED | _PAGE_VALID | _PAGE_DIRTY);
-	build_huge_handler_tail(&p, &r, &l, K0, K1);
+	build_huge_handler_tail(&p, &r, &l, wr.r1, wr.r2);
 #endif
 
 	uasm_l_nopage_tlbm(&l, p);
+	build_restore_work_registers(&p);
 	uasm_i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff);
 	uasm_i_nop(&p);
 
-- 
1.7.2.3


From macro@linux-mips.org Fri Jul  1 01:34:09 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 01 Jul 2011 01:34:15 +0200 (CEST)
Received: from localhost.localdomain ([127.0.0.1]:47603 "EHLO
        localhost.localdomain" rhost-flags-OK-OK-OK-OK)
        by eddie.linux-mips.org with ESMTP id S1491163Ab1F3XeJ (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Fri, 1 Jul 2011 01:34:09 +0200
Date:   Fri, 1 Jul 2011 00:34:09 +0100 (BST)
From:   "Maciej W. Rozycki" <macro@linux-mips.org>
To:     David Daney <david.daney@cavium.com>
cc:     linux-mips@linux-mips.org, ralf@linux-mips.org
Subject: Re: [PATCH] MIPS: Close races in TLB modify handlers.
In-Reply-To: <1309473062-11041-1-git-send-email-david.daney@cavium.com>
Message-ID: <alpine.LFD.2.00.1106302358550.29709@eddie.linux-mips.org>
References: <1309473062-11041-1-git-send-email-david.daney@cavium.com>
User-Agent: Alpine 2.00 (LFD 1167 2008-08-23)
MIME-Version: 1.0
Content-Type: TEXT/PLAIN; charset=US-ASCII
X-archive-position: 30573
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: macro@linux-mips.org
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 124
Content-Length: 1007
Lines: 26

Hi David,

> Page table entries are made invalid by writing a zero into the the PTE
> slot in a page table.  This creates a race condition with the TLB
> modify handlers when they are updating the PTE.
> 
> CPU0                              CPU1
> 
> Test for _PAGE_PRESENT
> .                                 set to not _PAGE_PRESENT (zero)
> Set to _PAGE_VALID
> 
> So now the page not present value (zero) is suddenly valid and user
> space programs have access to physical page zero.
> 
> We close the race by putting the test for _PAGE_PRESENT and setting of
> _PAGE_VALID into an atomic LL/SC section.  This requires more
> registers than just K0 and K1 in the handlers, so we need to save some
> registers to a save area and then restore them when we are done.

 Hmm, good catch, but doesn't your change pessimise the UP case?  It looks 
to me like you save & restore the scratch registers even though the race 
does not apply to UP (you can't interrupt a TLB handler, not at this 
stage).

  Maciej

From david.daney@cavium.com Fri Jul  1 01:58:12 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 01 Jul 2011 01:58:25 +0200 (CEST)
Received: from mail3.caviumnetworks.com ([12.108.191.235]:15883 "EHLO
        mail3.caviumnetworks.com" rhost-flags-OK-OK-OK-OK)
        by eddie.linux-mips.org with ESMTP id S1491186Ab1F3X6M (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Fri, 1 Jul 2011 01:58:12 +0200
Received: from caexch01.caveonetworks.com (Not Verified[192.168.16.9]) by mail3.caviumnetworks.com with MailMarshal (v6,7,2,8378)
        id <B4e0d0dd50000>; Thu, 30 Jun 2011 16:59:17 -0700
Received: from caexch01.caveonetworks.com ([192.168.16.9]) by caexch01.caveonetworks.com with Microsoft SMTPSVC(6.0.3790.4675);
         Thu, 30 Jun 2011 16:58:09 -0700
Received: from dd1.caveonetworks.com ([12.108.191.236]) by caexch01.caveonetworks.com over TLS secured channel with Microsoft SMTPSVC(6.0.3790.4675);
         Thu, 30 Jun 2011 16:58:09 -0700
Message-ID: <4E0D0D8C.7000200@cavium.com>
Date:   Thu, 30 Jun 2011 16:58:04 -0700
From:   David Daney <david.daney@cavium.com>
User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.15) Gecko/20101027 Fedora/3.0.10-1.fc12 Thunderbird/3.0.10
MIME-Version: 1.0
To:     "Maciej W. Rozycki" <macro@linux-mips.org>
CC:     linux-mips@linux-mips.org, ralf@linux-mips.org
Subject: Re: [PATCH] MIPS: Close races in TLB modify handlers.
References: <1309473062-11041-1-git-send-email-david.daney@cavium.com> <alpine.LFD.2.00.1106302358550.29709@eddie.linux-mips.org>
In-Reply-To: <alpine.LFD.2.00.1106302358550.29709@eddie.linux-mips.org>
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
X-OriginalArrivalTime: 30 Jun 2011 23:58:09.0598 (UTC) FILETIME=[902B7DE0:01CC3781]
X-archive-position: 30574
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: david.daney@cavium.com
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 144
Content-Length: 1277
Lines: 36

On 06/30/2011 04:34 PM, Maciej W. Rozycki wrote:
> Hi David,
>
>> Page table entries are made invalid by writing a zero into the the PTE
>> slot in a page table.  This creates a race condition with the TLB
>> modify handlers when they are updating the PTE.
>>
>> CPU0                              CPU1
>>
>> Test for _PAGE_PRESENT
>> .                                 set to not _PAGE_PRESENT (zero)
>> Set to _PAGE_VALID
>>
>> So now the page not present value (zero) is suddenly valid and user
>> space programs have access to physical page zero.
>>
>> We close the race by putting the test for _PAGE_PRESENT and setting of
>> _PAGE_VALID into an atomic LL/SC section.  This requires more
>> registers than just K0 and K1 in the handlers, so we need to save some
>> registers to a save area and then restore them when we are done.
>
>   Hmm, good catch, but doesn't your change pessimise the UP case?

It may, It is really just a first version of the patch.  I am looking 
for feedback and testing.

> It looks
> to me like you save&  restore the scratch registers even though the race
> does not apply to UP (you can't interrupt a TLB handler, not at this
> stage).

That's right.  I will look at trying to generate the old code sequences 
for non-SMP.

Thanks,
David Daney

From ralf@linux-mips.org Fri Jul  1 10:27:15 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 01 Jul 2011 10:27:22 +0200 (CEST)
Received: from h5.dl5rb.org.uk ([81.2.74.5]:58113 "EHLO linux-mips.org"
        rhost-flags-OK-OK-OK-FAIL) by eddie.linux-mips.org with ESMTP
        id S1490989Ab1GAI1P (ORCPT <rfc822;linux-mips@linux-mips.org>);
        Fri, 1 Jul 2011 10:27:15 +0200
Received: from duck.linux-mips.net (duck.linux-mips.net [127.0.0.1])
        by duck.linux-mips.net (8.14.4/8.14.4) with ESMTP id p618R7Bw005250;
        Fri, 1 Jul 2011 09:27:07 +0100
Received: (from ralf@localhost)
        by duck.linux-mips.net (8.14.4/8.14.4/Submit) id p618R6Hl005248;
        Fri, 1 Jul 2011 09:27:06 +0100
Date:   Fri, 1 Jul 2011 09:27:06 +0100
From:   Ralf Baechle <ralf@linux-mips.org>
To:     David Daney <david.daney@cavium.com>
Cc:     "Maciej W. Rozycki" <macro@linux-mips.org>,
        linux-mips@linux-mips.org
Subject: Re: [PATCH] MIPS: Close races in TLB modify handlers.
Message-ID: <20110701082706.GA8308@linux-mips.org>
References: <1309473062-11041-1-git-send-email-david.daney@cavium.com>
 <alpine.LFD.2.00.1106302358550.29709@eddie.linux-mips.org>
 <4E0D0D8C.7000200@cavium.com>
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
In-Reply-To: <4E0D0D8C.7000200@cavium.com>
User-Agent: Mutt/1.5.21 (2010-09-15)
X-archive-position: 30575
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ralf@linux-mips.org
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 390
Content-Length: 1765
Lines: 46

On Thu, Jun 30, 2011 at 04:58:04PM -0700, David Daney wrote:

> On 06/30/2011 04:34 PM, Maciej W. Rozycki wrote:
> >Hi David,
> >
> >>Page table entries are made invalid by writing a zero into the the PTE
> >>slot in a page table.  This creates a race condition with the TLB
> >>modify handlers when they are updating the PTE.
> >>
> >>CPU0                              CPU1
> >>
> >>Test for _PAGE_PRESENT
> >>.                                 set to not _PAGE_PRESENT (zero)
> >>Set to _PAGE_VALID
> >>
> >>So now the page not present value (zero) is suddenly valid and user
> >>space programs have access to physical page zero.
> >>
> >>We close the race by putting the test for _PAGE_PRESENT and setting of
> >>_PAGE_VALID into an atomic LL/SC section.  This requires more
> >>registers than just K0 and K1 in the handlers, so we need to save some
> >>registers to a save area and then restore them when we are done.
> >
> >  Hmm, good catch, but doesn't your change pessimise the UP case?
> 
> It may, It is really just a first version of the patch.  I am
> looking for feedback and testing.
> 
> >It looks
> >to me like you save&  restore the scratch registers even though the race
> >does not apply to UP (you can't interrupt a TLB handler, not at this
> >stage).
> 
> That's right.  I will look at trying to generate the old code
> sequences for non-SMP.

We can replace all the CONFIG_SMPs in tlbex.c (existing and those added
by your patch) with num_possible_cpus > 1 which will improve readability
and give SMP kernels running on a single processor the uniprocessor TLB
exception handler.

But that's something for a followup patch; your patch is big enough as it
is, it's not as straight forward as it may sound and the 3.0 clock is
ticking ...

  Ralf

From dhowells@redhat.com Fri Jul  1 17:31:48 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 01 Jul 2011 17:31:56 +0200 (CEST)
Received: from mx1.redhat.com ([209.132.183.28]:10333 "EHLO mx1.redhat.com"
        rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org with ESMTP
        id S1491131Ab1GAPbs (ORCPT <rfc822;linux-mips@linux-mips.org>);
        Fri, 1 Jul 2011 17:31:48 +0200
Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23])
        by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id p61FVQJG017817
        (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK);
        Fri, 1 Jul 2011 11:31:26 -0400
Received: from redhat.com ([10.3.112.11])
        by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id p61FVJDT013041;
        Fri, 1 Jul 2011 11:31:20 -0400
Organization: Red Hat UK Ltd. Registered Address: Red Hat UK Ltd, Amberley
        Place, 107-111 Peascod Street, Windsor, Berkshire, SI4 1TE, United
        Kingdom.
        Registered in England and Wales under Company Registration No. 3798903
From:   David Howells <dhowells@redhat.com>
In-Reply-To: <s5hiprnwjf4.wl%tiwai@suse.de>
References: <s5hiprnwjf4.wl%tiwai@suse.de> <20110630091754.GA12119@linux-mips.org> <s5h8vsjy68z.wl%tiwai@suse.de> <20110630105254.GA25732@linux-mips.org> <s5h39iry3xp.wl%tiwai@suse.de> <s5hy60jwocc.wl%tiwai@suse.de> <20110630123212.GA6690@linux-mips.org> <s5hoc1fwl37.wl%tiwai@suse.de> <20110630124333.GA9727@linux-mips.org> 
To:     Takashi Iwai <tiwai@suse.de>
Cc:     dhowells@redhat.com, Ralf Baechle <ralf@linux-mips.org>,
        Jaroslav Kysela <perex@perex.cz>, alsa-devel@alsa-project.org,
        linux-kernel@vger.kernel.org, linux-mips@linux-mips.org,
        florian@linux-mips.org, Florian Fainelli <florian@openwrt.org>,
        linux-arch@vger.kernel.org, Richard Henderson <rth@twiddle.net>,
        Ivan Kokshaysky <ink@jurassic.park.msu.ru>,
        Matt Turner <mattst88@gmail.com>,
        Benjamin Herrenschmidt <benh@kernel.crashing.org>,
        Paul Mackerras <paulus@samba.org>,
        "David S. Miller" <davem@davemloft.net>, sparclinux@vger.kernel.org
Subject: Re: SB16 build error.
Date:   Fri, 01 Jul 2011 16:31:18 +0100
Message-ID: <3602.1309534278@redhat.com>
X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23
X-archive-position: 30577
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: dhowells@redhat.com
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 739
Content-Length: 109
Lines: 5

Takashi Iwai <tiwai@suse.de> wrote:

> OK, here is the patch.

Acked-by: David Howells <dhowells@redhat.com>

From david.s.daney@gmail.com Fri Jul  1 18:38:29 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 01 Jul 2011 18:38:33 +0200 (CEST)
Received: from mail-iy0-f177.google.com ([209.85.210.177]:55810 "EHLO
        mail-iy0-f177.google.com" rhost-flags-OK-OK-OK-OK)
        by eddie.linux-mips.org with ESMTP id S1491131Ab1GAQi3 (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Fri, 1 Jul 2011 18:38:29 +0200
Received: by iyn15 with SMTP id 15so3621623iyn.36
        for <multiple recipients>; Fri, 01 Jul 2011 09:38:22 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=gmail.com; s=gamma;
        h=message-id:date:from:user-agent:mime-version:to:cc:subject
         :references:in-reply-to:content-type:content-transfer-encoding;
        bh=G3qdoLXXYsZfcnccEWUXUicBs/Y+DKY9dYcD70Z14po=;
        b=qGHrpsSchskvTzE20VTfiuT3erD0+Cf5CLpTg611zNgQTPVO1rnWBMCBsezaq95hZJ
         C4f5FzSS2iOr9Vg5+U//40zA/M+hZHHQTD0Js3KjkoZeLwsXuW9l+3v8SGwxN/XpuUpH
         ZL5PEconH/ShbeImvj7T5oI8A04cvfmbR8ouE=
Received: by 10.42.117.134 with SMTP id t6mr3678241icq.458.1309538302731;
        Fri, 01 Jul 2011 09:38:22 -0700 (PDT)
Received: from dd_xps.caveonetworks.com (adsl-67-127-56-230.dsl.pltn13.pacbell.net [67.127.56.230])
        by mx.google.com with ESMTPS id vn4sm3492245icb.19.2011.07.01.09.38.21
        (version=TLSv1/SSLv3 cipher=OTHER);
        Fri, 01 Jul 2011 09:38:21 -0700 (PDT)
Message-ID: <4E0DF7FC.7010007@gmail.com>
Date:   Fri, 01 Jul 2011 09:38:20 -0700
From:   David Daney <david.s.daney@gmail.com>
User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.17) Gecko/20110428 Fedora/3.1.10-1.fc13 Thunderbird/3.1.10
MIME-Version: 1.0
To:     Ralf Baechle <ralf@linux-mips.org>
CC:     David Daney <david.daney@cavium.com>,
        "Maciej W. Rozycki" <macro@linux-mips.org>,
        linux-mips@linux-mips.org
Subject: Re: [PATCH] MIPS: Close races in TLB modify handlers.
References: <1309473062-11041-1-git-send-email-david.daney@cavium.com> <alpine.LFD.2.00.1106302358550.29709@eddie.linux-mips.org> <4E0D0D8C.7000200@cavium.com> <20110701082706.GA8308@linux-mips.org>
In-Reply-To: <20110701082706.GA8308@linux-mips.org>
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
X-archive-position: 30578
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: david.s.daney@gmail.com
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 791
Content-Length: 2061
Lines: 47

On 07/01/2011 01:27 AM, Ralf Baechle wrote:
> On Thu, Jun 30, 2011 at 04:58:04PM -0700, David Daney wrote:
>
>> On 06/30/2011 04:34 PM, Maciej W. Rozycki wrote:
>>> Hi David,
>>>
>>>> Page table entries are made invalid by writing a zero into the the PTE
>>>> slot in a page table.  This creates a race condition with the TLB
>>>> modify handlers when they are updating the PTE.
>>>>
>>>> CPU0                              CPU1
>>>>
>>>> Test for _PAGE_PRESENT
>>>> .                                 set to not _PAGE_PRESENT (zero)
>>>> Set to _PAGE_VALID
>>>>
>>>> So now the page not present value (zero) is suddenly valid and user
>>>> space programs have access to physical page zero.
>>>>
>>>> We close the race by putting the test for _PAGE_PRESENT and setting of
>>>> _PAGE_VALID into an atomic LL/SC section.  This requires more
>>>> registers than just K0 and K1 in the handlers, so we need to save some
>>>> registers to a save area and then restore them when we are done.
>>>   Hmm, good catch, but doesn't your change pessimise the UP case?
>> It may, It is really just a first version of the patch.  I am
>> looking for feedback and testing.
>>
>>> It looks
>>> to me like you save&   restore the scratch registers even though the race
>>> does not apply to UP (you can't interrupt a TLB handler, not at this
>>> stage).
>> That's right.  I will look at trying to generate the old code
>> sequences for non-SMP.
> We can replace all the CONFIG_SMPs in tlbex.c (existing and those added
> by your patch) with num_possible_cpus>  1 which will improve readability
> and give SMP kernels running on a single processor the uniprocessor TLB
> exception handler.
>
> But that's something for a followup patch; your patch is big enough as it
> is, it's not as straight forward as it may sound and the 3.0 clock is
> ticking ...

I am testing a slight revision (using Context/XContext to get the 
logical CPU number instead of physical CPU number from EBase).  I will 
not send this revision until Tuesday because we are on holiday until then.

David Daney

From greg@kroah.com Fri Jul  1 23:16:34 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 01 Jul 2011 23:16:41 +0200 (CEST)
Received: from out3.smtp.messagingengine.com ([66.111.4.27]:55124 "EHLO
        out3.smtp.messagingengine.com" rhost-flags-OK-OK-OK-OK)
        by eddie.linux-mips.org with ESMTP id S1491167Ab1GAVQe (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Fri, 1 Jul 2011 23:16:34 +0200
Received: from compute3.internal (compute3.nyi.mail.srv.osa [10.202.2.43])
        by gateway1.messagingengine.com (Postfix) with ESMTP id 81DF120ACB;
        Fri,  1 Jul 2011 17:16:32 -0400 (EDT)
Received: from frontend2.messagingengine.com ([10.202.2.161])
  by compute3.internal (MEProxy); Fri, 01 Jul 2011 17:16:32 -0400
DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=messagingengine.com; h=date:from:to:cc:subject:message-id:references:mime-version:content-type:in-reply-to; s=smtpout; bh=Wxlwi/0Cd3o36rDgKRGEGs8L8So=; b=rij09KpTU6yJXREeTMQDk+lrSLIyLKehzsRvnDqtn+n2EDnhcTlRQOGyUUot5GGvwZEduoItG3bOhqs7HHI/mt1irxgrU745uSEhPOGy5T6BVer31KuYd55qRCzssHN4VL1Bh+rolvvpxY8Oks+NtdsB8sXeAKwXrkCovoU96Uo=
X-Sasl-enc: qAV+PXdGEXOz1DG3L9lAVP1iqnVf3T5qIB7BtV1P9bK1 1309554992
Received: from localhost (c-76-121-69-168.hsd1.wa.comcast.net [76.121.69.168])
        by mail.messagingengine.com (Postfix) with ESMTPSA id 0EFE34433B9;
        Fri,  1 Jul 2011 17:16:31 -0400 (EDT)
Date:   Fri, 1 Jul 2011 14:11:23 -0700
From:   Greg KH <greg@kroah.com>
To:     Alan Cox <alan@lxorguk.ukuu.org.uk>
Cc:     Gabor Juhos <juhosg@openwrt.org>,
        Ralf Baechle <ralf@linux-mips.org>, linux-mips@linux-mips.org,
        Kathy Giori <kgiori@qca.qualcomm.com>,
        "Luis R. Rodriguez" <rodrigue@qca.qualcomm.com>,
        linux-serial@vger.kernel.org
Subject: Re: [PATCH 11/13] serial: add driver for the built-in UART of the
 AR933X SoC
Message-ID: <20110701211123.GA19805@kroah.com>
References: <1308597973-6037-1-git-send-email-juhosg@openwrt.org>
 <1308597973-6037-12-git-send-email-juhosg@openwrt.org>
 <20110621095951.7dc1c9ee@lxorguk.ukuu.org.uk>
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
In-Reply-To: <20110621095951.7dc1c9ee@lxorguk.ukuu.org.uk>
User-Agent: Mutt/1.5.21 (2010-09-15)
X-archive-position: 30579
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: greg@kroah.com
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 1077
Content-Length: 242
Lines: 9

On Tue, Jun 21, 2011 at 09:59:51AM +0100, Alan Cox wrote:
> Looks good to me
> 
> Signed-off-by: Alan Cox <alan@linux.intel.com>
> 
> and no problem here with it going via the MIPS tree (but make sure GregKH
> is happy)

I'm happy with this.

From ohad@wizery.com Tue Jul  5 16:07:05 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Tue, 05 Jul 2011 16:07:15 +0200 (CEST)
Received: from mail-ww0-f43.google.com ([74.125.82.43]:39364 "EHLO
        mail-ww0-f43.google.com" rhost-flags-OK-OK-OK-OK)
        by eddie.linux-mips.org with ESMTP id S1491977Ab1GEOHF (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Tue, 5 Jul 2011 16:07:05 +0200
Received: by wwi18 with SMTP id 18so5060942wwi.24
        for <multiple recipients>; Tue, 05 Jul 2011 07:07:00 -0700 (PDT)
Received: by 10.216.66.149 with SMTP id h21mr6133405wed.103.1309874818764;
        Tue, 05 Jul 2011 07:06:58 -0700 (PDT)
Received: from localhost.localdomain (93-172-172-9.bb.netvision.net.il [93.172.172.9])
        by mx.google.com with ESMTPS id u64sm3685418weq.4.2011.07.05.07.06.52
        (version=TLSv1/SSLv3 cipher=OTHER);
        Tue, 05 Jul 2011 07:06:57 -0700 (PDT)
From:   Ohad Ben-Cohen <ohad@wizery.com>
To:     Rusty Russell <rusty@rustcorp.com.au>,
        virtualization@lists.linux-foundation.org
Cc:     Grant Likely <grant.likely@secretlab.ca>,
        Arnd Bergmann <arnd@arndb.de>,
        <linux-arm-kernel@lists.infradead.org>,
        <linux-omap@vger.kernel.org>,
        Xiantao Zhang <xiantao.zhang@intel.com>,
        Avi Kivity <avi@redhat.com>,
        Marcelo Tosatti <mtosatti@redhat.com>,
        Tony Luck <tony.luck@intel.com>,
        Fenghua Yu <fenghua.yu@intel.com>,
        Ralf Baechle <ralf@linux-mips.org>,
        Alexander Graf <agraf@suse.de>,
        Benjamin Herrenschmidt <benh@kernel.crashing.org>,
        Paul Mackerras <paulus@samba.org>,
        Carsten Otte <cotte@de.ibm.com>,
        Christian Borntraeger <borntraeger@de.ibm.com>,
        linux390@de.ibm.com, Martin Schwidefsky <schwidefsky@de.ibm.com>,
        Heiko Carstens <heiko.carstens@de.ibm.com>,
        Paul Mundt <lethal@linux-sh.org>,
        Chris Metcalf <cmetcalf@tilera.com>,
        Thomas Gleixner <tglx@linutronix.de>,
        Ingo Molnar <mingo@redhat.com>,
        "H. Peter Anvin" <hpa@zytor.com>, x86@kernel.org,
        "Michael S. Tsirkin" <mst@redhat.com>,
        Ohad Ben-Cohen <ohad@wizery.com>,
        Russell King <rmk+kernel@arm.linux.org.uk>,
        John Stultz <john.stultz@linaro.org>,
        Andrew Morton <akpm@linux-foundation.org>,
        kvm-ia64@vger.kernel.org, kvm@vger.kernel.org,
        linux-ia64@vger.kernel.org, linux-kernel@vger.kernel.org,
        linux-mips@linux-mips.org, kvm-ppc@vger.kernel.org,
        linuxppc-dev@lists.ozlabs.org, linux-s390@vger.kernel.org,
        linux-sh@vger.kernel.org
Subject: [RFC] virtio: expose for non-virtualization users too
Date:   Tue,  5 Jul 2011 17:06:14 +0300
Message-Id: <1309874774-31689-1-git-send-email-ohad@wizery.com>
X-Mailer: git-send-email 1.7.1
X-archive-position: 30581
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ohad@wizery.com
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 3060
Content-Length: 5274
Lines: 180

virtio has been so far used only in the context of virtualization,
and the virtio Kconfig was sourced directly by the relevant arch
Kconfigs when VIRTUALIZATION was selected.

Now that we start using virtio for inter-processor communications,
we need to source the virtio Kconfig outside of the virtualization
scope too.

Moreover, some architectures might use virtio for both virtualization
and inter-processor communications, so directly sourcing virtio
might yield unexpected results due to conflicting selections.

The simple solution offered by this patch is to always source virtio's
Kconfig in drivers/Kconfig, and remove it from the appropriate arch
Kconfigs. Additionally, a virtio menu entry has been added so virtio
drivers don't show up in the general drivers menu.

This way anyone can use virtio, though it's arguably less accessible
(and neat!) for virtualization users now.

Note: some architectures (mips and sh) seem to have a VIRTUALIZATION
menu merely for sourcing virtio's Kconfig, so that menu is removed too.

Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
---
The motivation behind this patch is: https://lkml.org/lkml/2011/6/21/47

If the general approach is agreed upon, we can either merge the patch
independently, or add it to the AMP patch set.

 arch/ia64/kvm/Kconfig    |    1 -
 arch/mips/Kconfig        |   16 ----------------
 arch/powerpc/kvm/Kconfig |    1 -
 arch/s390/kvm/Kconfig    |    1 -
 arch/sh/Kconfig          |   16 ----------------
 arch/tile/kvm/Kconfig    |    1 -
 arch/x86/kvm/Kconfig     |    1 -
 drivers/Kconfig          |    2 ++
 drivers/virtio/Kconfig   |    3 +++
 9 files changed, 5 insertions(+), 37 deletions(-)

diff --git a/arch/ia64/kvm/Kconfig b/arch/ia64/kvm/Kconfig
index fa4d1e5..9806e55 100644
--- a/arch/ia64/kvm/Kconfig
+++ b/arch/ia64/kvm/Kconfig
@@ -49,6 +49,5 @@ config KVM_INTEL
 	  extensions.
 
 source drivers/vhost/Kconfig
-source drivers/virtio/Kconfig
 
 endif # VIRTUALIZATION
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 653da62..a627a2c 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -2489,20 +2489,4 @@ source "security/Kconfig"
 
 source "crypto/Kconfig"
 
-menuconfig VIRTUALIZATION
-	bool "Virtualization"
-	default n
-	---help---
-	  Say Y here to get to see options for using your Linux host to run other
-	  operating systems inside virtual machines (guests).
-	  This option alone does not add any kernel code.
-
-	  If you say N, all options in this submenu will be skipped and disabled.
-
-if VIRTUALIZATION
-
-source drivers/virtio/Kconfig
-
-endif # VIRTUALIZATION
-
 source "lib/Kconfig"
diff --git a/arch/powerpc/kvm/Kconfig b/arch/powerpc/kvm/Kconfig
index b7baff7..105b691 100644
--- a/arch/powerpc/kvm/Kconfig
+++ b/arch/powerpc/kvm/Kconfig
@@ -99,6 +99,5 @@ config KVM_E500
 	  If unsure, say N.
 
 source drivers/vhost/Kconfig
-source drivers/virtio/Kconfig
 
 endif # VIRTUALIZATION
diff --git a/arch/s390/kvm/Kconfig b/arch/s390/kvm/Kconfig
index f66a1bd..a216341 100644
--- a/arch/s390/kvm/Kconfig
+++ b/arch/s390/kvm/Kconfig
@@ -37,6 +37,5 @@ config KVM
 # OK, it's a little counter-intuitive to do this, but it puts it neatly under
 # the virtualization menu.
 source drivers/vhost/Kconfig
-source drivers/virtio/Kconfig
 
 endif # VIRTUALIZATION
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index bbdeb48..748ff19 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -897,20 +897,4 @@ source "security/Kconfig"
 
 source "crypto/Kconfig"
 
-menuconfig VIRTUALIZATION
-	bool "Virtualization"
-	default n
-	---help---
-	  Say Y here to get to see options for using your Linux host to run other
-	  operating systems inside virtual machines (guests).
-	  This option alone does not add any kernel code.
-
-	  If you say N, all options in this submenu will be skipped and disabled.
-
-if VIRTUALIZATION
-
-source drivers/virtio/Kconfig
-
-endif # VIRTUALIZATION
-
 source "lib/Kconfig"
diff --git a/arch/tile/kvm/Kconfig b/arch/tile/kvm/Kconfig
index b88f9c0..669fcdb 100644
--- a/arch/tile/kvm/Kconfig
+++ b/arch/tile/kvm/Kconfig
@@ -33,6 +33,5 @@ config KVM
 	  If unsure, say N.
 
 source drivers/vhost/Kconfig
-source drivers/virtio/Kconfig
 
 endif # VIRTUALIZATION
diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig
index 50f6364..65cf823 100644
--- a/arch/x86/kvm/Kconfig
+++ b/arch/x86/kvm/Kconfig
@@ -76,6 +76,5 @@ config KVM_MMU_AUDIT
 # the virtualization menu.
 source drivers/vhost/Kconfig
 source drivers/lguest/Kconfig
-source drivers/virtio/Kconfig
 
 endif # VIRTUALIZATION
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 3bb154d..795218e 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -114,6 +114,8 @@ source "drivers/uio/Kconfig"
 
 source "drivers/vlynq/Kconfig"
 
+source "drivers/virtio/Kconfig"
+
 source "drivers/xen/Kconfig"
 
 source "drivers/staging/Kconfig"
diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig
index 3dd6294..57e493b 100644
--- a/drivers/virtio/Kconfig
+++ b/drivers/virtio/Kconfig
@@ -7,6 +7,8 @@ config VIRTIO_RING
 	tristate
 	depends on VIRTIO
 
+menu "Virtio drivers"
+
 config VIRTIO_PCI
 	tristate "PCI driver for virtio devices (EXPERIMENTAL)"
 	depends on PCI && EXPERIMENTAL
@@ -33,3 +35,4 @@ config VIRTIO_BALLOON
 
 	 If unsure, say M.
 
+endmenu
-- 
1.7.1


From hpa@zytor.com Wed Jul  6 00:36:19 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Wed, 06 Jul 2011 00:36:28 +0200 (CEST)
Received: from terminus.zytor.com ([198.137.202.10]:52568 "EHLO mail.zytor.com"
        rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org with ESMTP
        id S1492018Ab1GEWgT (ORCPT <rfc822;linux-mips@linux-mips.org>);
        Wed, 6 Jul 2011 00:36:19 +0200
Received: from hanvin-mobl4.sc.intel.com (hpa@localhost [127.0.0.1])
        (authenticated bits=0)
        by mail.zytor.com (8.14.4/8.14.4) with ESMTP id p65MZkqp029009
        (version=TLSv1/SSLv3 cipher=DHE-RSA-CAMELLIA256-SHA bits=256 verify=NO);
        Tue, 5 Jul 2011 15:35:47 -0700
Message-ID: <4E1391C2.2090904@zytor.com>
Date:   Tue, 05 Jul 2011 15:35:46 -0700
From:   "H. Peter Anvin" <hpa@zytor.com>
User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.17) Gecko/20110428 Fedora/3.1.10-1.fc15 Thunderbird/3.1.10
MIME-Version: 1.0
To:     Ohad Ben-Cohen <ohad@wizery.com>
CC:     Rusty Russell <rusty@rustcorp.com.au>,
        virtualization@lists.linux-foundation.org,
        Grant Likely <grant.likely@secretlab.ca>,
        Arnd Bergmann <arnd@arndb.de>,
        linux-arm-kernel@lists.infradead.org, linux-omap@vger.kernel.org,
        Xiantao Zhang <xiantao.zhang@intel.com>,
        Avi Kivity <avi@redhat.com>,
        Marcelo Tosatti <mtosatti@redhat.com>,
        Tony Luck <tony.luck@intel.com>,
        Fenghua Yu <fenghua.yu@intel.com>,
        Ralf Baechle <ralf@linux-mips.org>,
        Alexander Graf <agraf@suse.de>,
        Benjamin Herrenschmidt <benh@kernel.crashing.org>,
        Paul Mackerras <paulus@samba.org>,
        Carsten Otte <cotte@de.ibm.com>,
        Christian Borntraeger <borntraeger@de.ibm.com>,
        linux390@de.ibm.com, Martin Schwidefsky <schwidefsky@de.ibm.com>,
        Heiko Carstens <heiko.carstens@de.ibm.com>,
        Paul Mundt <lethal@linux-sh.org>,
        Chris Metcalf <cmetcalf@tilera.com>,
        Thomas Gleixner <tglx@linutronix.de>,
        Ingo Molnar <mingo@redhat.com>, x86@kernel.org,
        "Michael S. Tsirkin" <mst@redhat.com>,
        Russell King <rmk+kernel@arm.linux.org.uk>,
        John Stultz <john.stultz@linaro.org>,
        Andrew Morton <akpm@linux-foundation.org>,
        kvm-ia64@vger.kernel.org, kvm@vger.kernel.org,
        linux-ia64@vger.kernel.org, linux-kernel@vger.kernel.org,
        linux-mips@linux-mips.org, kvm-ppc@vger.kernel.org,
        linuxppc-dev@lists.ozlabs.org, linux-s390@vger.kernel.org,
        linux-sh@vger.kernel.org
Subject: Re: [RFC] virtio: expose for non-virtualization users too
References: <1309874774-31689-1-git-send-email-ohad@wizery.com>
In-Reply-To: <1309874774-31689-1-git-send-email-ohad@wizery.com>
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit
X-archive-position: 30582
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: hpa@zytor.com
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 3582
Content-Length: 416
Lines: 13

On 07/05/2011 07:06 AM, Ohad Ben-Cohen wrote:
> virtio has been so far used only in the context of virtualization,
> and the virtio Kconfig was sourced directly by the relevant arch
> Kconfigs when VIRTUALIZATION was selected.
> 
> Now that we start using virtio for inter-processor communications,
> we need to source the virtio Kconfig outside of the virtualization
> scope too.
> 

Seems reasonable to me.

	-hpa

From david.daney@cavium.com Wed Jul  6 01:34:56 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Wed, 06 Jul 2011 01:35:03 +0200 (CEST)
Received: from mail3.caviumnetworks.com ([12.108.191.235]:1464 "EHLO
        mail3.caviumnetworks.com" rhost-flags-OK-OK-OK-OK)
        by eddie.linux-mips.org with ESMTP id S1492023Ab1GEXe4 (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Wed, 6 Jul 2011 01:34:56 +0200
Received: from caexch01.caveonetworks.com (Not Verified[192.168.16.9]) by mail3.caviumnetworks.com with MailMarshal (v6,7,2,8378)
        id <B4e139fe10000>; Tue, 05 Jul 2011 16:36:01 -0700
Received: from caexch01.caveonetworks.com ([192.168.16.9]) by caexch01.caveonetworks.com with Microsoft SMTPSVC(6.0.3790.4675);
         Tue, 5 Jul 2011 16:34:53 -0700
Received: from dd1.caveonetworks.com ([12.108.191.236]) by caexch01.caveonetworks.com over TLS secured channel with Microsoft SMTPSVC(6.0.3790.4675);
         Tue, 5 Jul 2011 16:34:53 -0700
Received: from dd1.caveonetworks.com (localhost.localdomain [127.0.0.1])
        by dd1.caveonetworks.com (8.14.4/8.14.3) with ESMTP id p65NYmM1001659;
        Tue, 5 Jul 2011 16:34:48 -0700
Received: (from ddaney@localhost)
        by dd1.caveonetworks.com (8.14.4/8.14.4/Submit) id p65NYlmo001658;
        Tue, 5 Jul 2011 16:34:47 -0700
From:   David Daney <david.daney@cavium.com>
To:     linux-mips@linux-mips.org, ralf@linux-mips.org
Cc:     David Daney <david.daney@cavium.com>
Subject: [PATCH 1/2] MIPS: Add uasm UASM_i_SRL_SAFE macro.
Date:   Tue,  5 Jul 2011 16:34:45 -0700
Message-Id: <1309908886-1624-1-git-send-email-david.daney@cavium.com>
X-Mailer: git-send-email 1.7.2.3
X-OriginalArrivalTime: 05 Jul 2011 23:34:53.0402 (UTC) FILETIME=[2409A3A0:01CC3B6C]
X-archive-position: 30583
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: david.daney@cavium.com
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 3612
Content-Length: 1578
Lines: 31

This can be used from either 32-bit or 64-bit code to generate logical
right shifts of any constant amount.

Signed-off-by: David Daney <david.daney@cavium.com>
---
 arch/mips/include/asm/uasm.h |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/arch/mips/include/asm/uasm.h b/arch/mips/include/asm/uasm.h
index dcbd4bb..504d40a 100644
--- a/arch/mips/include/asm/uasm.h
+++ b/arch/mips/include/asm/uasm.h
@@ -150,6 +150,7 @@ static inline void __uasminit uasm_l##lb(struct uasm_label **lab, u32 *addr) \
 # define UASM_i_SLL(buf, rs, rt, sh) uasm_i_dsll(buf, rs, rt, sh)
 # define UASM_i_SRA(buf, rs, rt, sh) uasm_i_dsra(buf, rs, rt, sh)
 # define UASM_i_SRL(buf, rs, rt, sh) uasm_i_dsrl(buf, rs, rt, sh)
+# define UASM_i_SRL_SAFE(buf, rs, rt, sh) uasm_i_dsrl_safe(buf, rs, rt, sh)
 # define UASM_i_ROTR(buf, rs, rt, sh) uasm_i_drotr(buf, rs, rt, sh)
 # define UASM_i_MFC0(buf, rt, rd...) uasm_i_dmfc0(buf, rt, rd)
 # define UASM_i_MTC0(buf, rt, rd...) uasm_i_dmtc0(buf, rt, rd)
@@ -165,6 +166,7 @@ static inline void __uasminit uasm_l##lb(struct uasm_label **lab, u32 *addr) \
 # define UASM_i_SLL(buf, rs, rt, sh) uasm_i_sll(buf, rs, rt, sh)
 # define UASM_i_SRA(buf, rs, rt, sh) uasm_i_sra(buf, rs, rt, sh)
 # define UASM_i_SRL(buf, rs, rt, sh) uasm_i_srl(buf, rs, rt, sh)
+# define UASM_i_SRL_SAFE(buf, rs, rt, sh) uasm_i_srl(buf, rs, rt, sh)
 # define UASM_i_ROTR(buf, rs, rt, sh) uasm_i_rotr(buf, rs, rt, sh)
 # define UASM_i_MFC0(buf, rt, rd...) uasm_i_mfc0(buf, rt, rd)
 # define UASM_i_MTC0(buf, rt, rd...) uasm_i_mtc0(buf, rt, rd)
-- 
1.7.2.3


From david.daney@cavium.com Wed Jul  6 01:34:58 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Wed, 06 Jul 2011 01:35:31 +0200 (CEST)
Received: from mail3.caviumnetworks.com ([12.108.191.235]:1465 "EHLO
        mail3.caviumnetworks.com" rhost-flags-OK-OK-OK-OK)
        by eddie.linux-mips.org with ESMTP id S1492024Ab1GEXe6 (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Wed, 6 Jul 2011 01:34:58 +0200
Received: from caexch01.caveonetworks.com (Not Verified[192.168.16.9]) by mail3.caviumnetworks.com with MailMarshal (v6,7,2,8378)
        id <B4e139fe30000>; Tue, 05 Jul 2011 16:36:03 -0700
Received: from caexch01.caveonetworks.com ([192.168.16.9]) by caexch01.caveonetworks.com with Microsoft SMTPSVC(6.0.3790.4675);
         Tue, 5 Jul 2011 16:34:55 -0700
Received: from dd1.caveonetworks.com ([12.108.191.236]) by caexch01.caveonetworks.com over TLS secured channel with Microsoft SMTPSVC(6.0.3790.4675);
         Tue, 5 Jul 2011 16:34:55 -0700
Received: from dd1.caveonetworks.com (localhost.localdomain [127.0.0.1])
        by dd1.caveonetworks.com (8.14.4/8.14.3) with ESMTP id p65NYo2O001663;
        Tue, 5 Jul 2011 16:34:50 -0700
Received: (from ddaney@localhost)
        by dd1.caveonetworks.com (8.14.4/8.14.4/Submit) id p65NYoMI001662;
        Tue, 5 Jul 2011 16:34:50 -0700
From:   David Daney <david.daney@cavium.com>
To:     linux-mips@linux-mips.org, ralf@linux-mips.org
Cc:     David Daney <david.daney@cavium.com>
Subject: [PATCH 2/2 v2] MIPS: Close races in TLB modify handlers.
Date:   Tue,  5 Jul 2011 16:34:46 -0700
Message-Id: <1309908886-1624-2-git-send-email-david.daney@cavium.com>
X-Mailer: git-send-email 1.7.2.3
In-Reply-To: <1309908886-1624-1-git-send-email-david.daney@cavium.com>
References: <1309908886-1624-1-git-send-email-david.daney@cavium.com>
X-OriginalArrivalTime: 05 Jul 2011 23:34:55.0778 (UTC) FILETIME=[25743020:01CC3B6C]
X-archive-position: 30584
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: david.daney@cavium.com
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 3613
Content-Length: 19018
Lines: 569

Page table entries are made invalid by writing a zero into the the PTE
slot in a page table.  This creates a race condition with the TLB
modify handlers when they are updating the PTE.

CPU0                              CPU1

Test for _PAGE_PRESENT
.                                 set to not _PAGE_PRESENT (zero)
Set to _PAGE_VALID

So now the page not present value (zero) is suddenly valid and user
space programs have access to physical page zero.

We close the race by putting the test for _PAGE_PRESENT and setting of
_PAGE_VALID into an atomic LL/SC section.  This requires more
registers than just K0 and K1 in the handlers, so we need to save some
registers to a save area and then restore them when we are done.

The save area is an array of cacheline aligned structures that should
not suffer cache line bouncing as they are CPU private.

Signed-off-by: David Daney <david.daney@cavium.com>
---

v2: Use logical CPU number to index save slots, and use C0_KScratch if available.

 arch/mips/mm/tlbex.c |  289 +++++++++++++++++++++++++++++++++-----------------
 1 files changed, 192 insertions(+), 97 deletions(-)

diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
index 424ed4b..463df40 100644
--- a/arch/mips/mm/tlbex.c
+++ b/arch/mips/mm/tlbex.c
@@ -42,6 +42,18 @@
 extern void tlb_do_page_fault_0(void);
 extern void tlb_do_page_fault_1(void);
 
+struct work_registers {
+	int r1;
+	int r2;
+	int r3;
+};
+
+struct tlb_reg_save {
+	unsigned long a;
+	unsigned long b;
+} ____cacheline_aligned_in_smp;
+
+static struct tlb_reg_save handler_reg_save[NR_CPUS];
 
 static inline int r45k_bvahwbug(void)
 {
@@ -248,6 +260,73 @@ static int scratch_reg __cpuinitdata;
 static int pgd_reg __cpuinitdata;
 enum vmalloc64_mode {not_refill, refill_scratch, refill_noscratch};
 
+static struct work_registers __cpuinit build_get_work_registers(u32 **p)
+{
+	struct work_registers r;
+
+	int smp_processor_id_reg;
+	int smp_processor_id_sel;
+	int smp_processor_id_shift;
+
+	if (scratch_reg > 0) {
+		/* Save in CPU local C0_KScratch? */
+		UASM_i_MTC0(p, 1, 31, scratch_reg);
+		r.r1 = K0;
+		r.r2 = K1;
+		r.r3 = 1;
+		return r;
+	}
+
+	if (num_possible_cpus() > 1) {
+#ifdef CONFIG_MIPS_PGD_C0_CONTEXT
+		smp_processor_id_shift = 51;
+		smp_processor_id_reg = 20; /* XContext */
+		smp_processor_id_sel = 0;
+#else
+# ifdef CONFIG_32BIT
+		smp_processor_id_shift = 25;
+		smp_processor_id_reg = 4; /* Context */
+		smp_processor_id_sel = 0;
+# endif
+# ifdef CONFIG_64BIT
+		smp_processor_id_shift = 26;
+		smp_processor_id_reg = 4; /* Context */
+		smp_processor_id_sel = 0;
+# endif
+#endif
+		/* Get smp_processor_id */
+		UASM_i_MFC0(p, K0, smp_processor_id_reg, smp_processor_id_sel);
+		UASM_i_SRL_SAFE(p, K0, K0, smp_processor_id_shift);
+
+		/* handler_reg_save index in K0 */
+		UASM_i_SLL(p, K0, K0, ilog2(sizeof(struct tlb_reg_save)));
+
+		UASM_i_LA(p, K1, (long)&handler_reg_save);
+		UASM_i_ADDU(p, K0, K0, K1);
+	} else {
+		UASM_i_LA(p, K0, (long)&handler_reg_save);
+	}
+	/* K0 now points to save area, save $1 and $2  */
+	UASM_i_SW(p, 1, offsetof(struct tlb_reg_save, a), K0);
+	UASM_i_SW(p, 2, offsetof(struct tlb_reg_save, b), K0);
+
+	r.r1 = K1;
+	r.r2 = 1;
+	r.r3 = 2;
+	return r;
+}
+
+static void __cpuinit build_restore_work_registers(u32 **p)
+{
+	if (scratch_reg > 0) {
+		UASM_i_MFC0(p, 1, 31, scratch_reg);
+		return;
+	}
+	/* K0 already points to save area, restore $1 and $2  */
+	UASM_i_LW(p, 1, offsetof(struct tlb_reg_save, a), K0);
+	UASM_i_LW(p, 2, offsetof(struct tlb_reg_save, b), K0);
+}
+
 #ifndef CONFIG_MIPS_PGD_C0_CONTEXT
 
 /*
@@ -1160,9 +1239,6 @@ static void __cpuinit build_r4000_tlb_refill_handler(void)
 	memset(relocs, 0, sizeof(relocs));
 	memset(final_handler, 0, sizeof(final_handler));
 
-	if (scratch_reg == 0)
-		scratch_reg = allocate_kscratch();
-
 	if ((scratch_reg > 0 || scratchpad_available()) && use_bbit_insns()) {
 		htlb_info = build_fast_tlb_refill_handler(&p, &l, &r, K0, K1,
 							  scratch_reg);
@@ -1462,22 +1538,28 @@ iPTE_SW(u32 **p, struct uasm_reloc **r, unsigned int pte, unsigned int ptr,
  */
 static void __cpuinit
 build_pte_present(u32 **p, struct uasm_reloc **r,
-		  unsigned int pte, unsigned int ptr, enum label_id lid)
+		  int pte, int ptr, int scratch, enum label_id lid)
 {
+	int t = scratch >= 0 ? scratch : pte;
+
 	if (kernel_uses_smartmips_rixi) {
 		if (use_bbit_insns()) {
 			uasm_il_bbit0(p, r, pte, ilog2(_PAGE_PRESENT), lid);
 			uasm_i_nop(p);
 		} else {
-			uasm_i_andi(p, pte, pte, _PAGE_PRESENT);
-			uasm_il_beqz(p, r, pte, lid);
-			iPTE_LW(p, pte, ptr);
+			uasm_i_andi(p, t, pte, _PAGE_PRESENT);
+			uasm_il_beqz(p, r, t, lid);
+			if (pte == t)
+				/* You lose the SMP race :-(*/
+				iPTE_LW(p, pte, ptr);
 		}
 	} else {
-		uasm_i_andi(p, pte, pte, _PAGE_PRESENT | _PAGE_READ);
-		uasm_i_xori(p, pte, pte, _PAGE_PRESENT | _PAGE_READ);
-		uasm_il_bnez(p, r, pte, lid);
-		iPTE_LW(p, pte, ptr);
+		uasm_i_andi(p, t, pte, _PAGE_PRESENT | _PAGE_READ);
+		uasm_i_xori(p, t, t, _PAGE_PRESENT | _PAGE_READ);
+		uasm_il_bnez(p, r, t, lid);
+		if (pte == t)
+			/* You lose the SMP race :-(*/
+			iPTE_LW(p, pte, ptr);
 	}
 }
 
@@ -1497,19 +1579,19 @@ build_make_valid(u32 **p, struct uasm_reloc **r, unsigned int pte,
  */
 static void __cpuinit
 build_pte_writable(u32 **p, struct uasm_reloc **r,
-		   unsigned int pte, unsigned int ptr, enum label_id lid)
+		   unsigned int pte, unsigned int ptr, int scratch,
+		   enum label_id lid)
 {
-	if (use_bbit_insns()) {
-		uasm_il_bbit0(p, r, pte, ilog2(_PAGE_PRESENT), lid);
-		uasm_i_nop(p);
-		uasm_il_bbit0(p, r, pte, ilog2(_PAGE_WRITE), lid);
-		uasm_i_nop(p);
-	} else {
-		uasm_i_andi(p, pte, pte, _PAGE_PRESENT | _PAGE_WRITE);
-		uasm_i_xori(p, pte, pte, _PAGE_PRESENT | _PAGE_WRITE);
-		uasm_il_bnez(p, r, pte, lid);
+	int t = scratch >= 0 ? scratch : pte;
+
+	uasm_i_andi(p, t, pte, _PAGE_PRESENT | _PAGE_WRITE);
+	uasm_i_xori(p, t, t, _PAGE_PRESENT | _PAGE_WRITE);
+	uasm_il_bnez(p, r, t, lid);
+	if (pte == t)
+		/* You lose the SMP race :-(*/
 		iPTE_LW(p, pte, ptr);
-	}
+	else
+		uasm_i_nop(p);
 }
 
 /* Make PTE writable, update software status bits as well, then store
@@ -1531,15 +1613,19 @@ build_make_write(u32 **p, struct uasm_reloc **r, unsigned int pte,
  */
 static void __cpuinit
 build_pte_modifiable(u32 **p, struct uasm_reloc **r,
-		     unsigned int pte, unsigned int ptr, enum label_id lid)
+		     unsigned int pte, unsigned int ptr, int scratch,
+		     enum label_id lid)
 {
 	if (use_bbit_insns()) {
 		uasm_il_bbit0(p, r, pte, ilog2(_PAGE_WRITE), lid);
 		uasm_i_nop(p);
 	} else {
-		uasm_i_andi(p, pte, pte, _PAGE_WRITE);
-		uasm_il_beqz(p, r, pte, lid);
-		iPTE_LW(p, pte, ptr);
+		int t = scratch >= 0 ? scratch : pte;
+		uasm_i_andi(p, t, pte, _PAGE_WRITE);
+		uasm_il_beqz(p, r, t, lid);
+		if (pte == t)
+			/* You lose the SMP race :-(*/
+			iPTE_LW(p, pte, ptr);
 	}
 }
 
@@ -1619,7 +1705,7 @@ static void __cpuinit build_r3000_tlb_load_handler(void)
 	memset(relocs, 0, sizeof(relocs));
 
 	build_r3000_tlbchange_handler_head(&p, K0, K1);
-	build_pte_present(&p, &r, K0, K1, label_nopage_tlbl);
+	build_pte_present(&p, &r, K0, K1, -1, label_nopage_tlbl);
 	uasm_i_nop(&p); /* load delay */
 	build_make_valid(&p, &r, K0, K1);
 	build_r3000_tlb_reload_write(&p, &l, &r, K0, K1);
@@ -1649,7 +1735,7 @@ static void __cpuinit build_r3000_tlb_store_handler(void)
 	memset(relocs, 0, sizeof(relocs));
 
 	build_r3000_tlbchange_handler_head(&p, K0, K1);
-	build_pte_writable(&p, &r, K0, K1, label_nopage_tlbs);
+	build_pte_writable(&p, &r, K0, K1, -1, label_nopage_tlbs);
 	uasm_i_nop(&p); /* load delay */
 	build_make_write(&p, &r, K0, K1);
 	build_r3000_tlb_reload_write(&p, &l, &r, K0, K1);
@@ -1702,15 +1788,16 @@ static void __cpuinit build_r3000_tlb_modify_handler(void)
 /*
  * R4000 style TLB load/store/modify handlers.
  */
-static void __cpuinit
+static struct work_registers __cpuinit
 build_r4000_tlbchange_handler_head(u32 **p, struct uasm_label **l,
-				   struct uasm_reloc **r, unsigned int pte,
-				   unsigned int ptr)
+				   struct uasm_reloc **r)
 {
+	struct work_registers wr = build_get_work_registers(p);
+
 #ifdef CONFIG_64BIT
-	build_get_pmde64(p, l, r, pte, ptr); /* get pmd in ptr */
+	build_get_pmde64(p, l, r, wr.r1, wr.r2); /* get pmd in ptr */
 #else
-	build_get_pgde32(p, pte, ptr); /* get pgd in ptr */
+	build_get_pgde32(p, wr.r1, wr.r2); /* get pgd in ptr */
 #endif
 
 #ifdef CONFIG_HUGETLB_PAGE
@@ -1719,21 +1806,22 @@ build_r4000_tlbchange_handler_head(u32 **p, struct uasm_label **l,
 	 * instead contains the tlb pte. Check the PAGE_HUGE bit and
 	 * see if we need to jump to huge tlb processing.
 	 */
-	build_is_huge_pte(p, r, pte, ptr, label_tlb_huge_update);
+	build_is_huge_pte(p, r, wr.r1, wr.r2, label_tlb_huge_update);
 #endif
 
-	UASM_i_MFC0(p, pte, C0_BADVADDR);
-	UASM_i_LW(p, ptr, 0, ptr);
-	UASM_i_SRL(p, pte, pte, PAGE_SHIFT + PTE_ORDER - PTE_T_LOG2);
-	uasm_i_andi(p, pte, pte, (PTRS_PER_PTE - 1) << PTE_T_LOG2);
-	UASM_i_ADDU(p, ptr, ptr, pte);
+	UASM_i_MFC0(p, wr.r1, C0_BADVADDR);
+	UASM_i_LW(p, wr.r2, 0, wr.r2);
+	UASM_i_SRL(p, wr.r1, wr.r1, PAGE_SHIFT + PTE_ORDER - PTE_T_LOG2);
+	uasm_i_andi(p, wr.r1, wr.r1, (PTRS_PER_PTE - 1) << PTE_T_LOG2);
+	UASM_i_ADDU(p, wr.r2, wr.r2, wr.r1);
 
 #ifdef CONFIG_SMP
 	uasm_l_smp_pgtable_change(l, *p);
 #endif
-	iPTE_LW(p, pte, ptr); /* get even pte */
+	iPTE_LW(p, wr.r1, wr.r2); /* get even pte */
 	if (!m4kc_tlbp_war())
 		build_tlb_probe_entry(p);
+	return wr;
 }
 
 static void __cpuinit
@@ -1746,6 +1834,7 @@ build_r4000_tlbchange_handler_tail(u32 **p, struct uasm_label **l,
 	build_update_entries(p, tmp, ptr);
 	build_tlb_write_entry(p, l, r, tlb_indexed);
 	uasm_l_leave(l, *p);
+	build_restore_work_registers(p);
 	uasm_i_eret(p); /* return from trap */
 
 #ifdef CONFIG_64BIT
@@ -1758,6 +1847,7 @@ static void __cpuinit build_r4000_tlb_load_handler(void)
 	u32 *p = handle_tlbl;
 	struct uasm_label *l = labels;
 	struct uasm_reloc *r = relocs;
+	struct work_registers wr;
 
 	memset(handle_tlbl, 0, sizeof(handle_tlbl));
 	memset(labels, 0, sizeof(labels));
@@ -1777,8 +1867,8 @@ static void __cpuinit build_r4000_tlb_load_handler(void)
 		/* No need for uasm_i_nop */
 	}
 
-	build_r4000_tlbchange_handler_head(&p, &l, &r, K0, K1);
-	build_pte_present(&p, &r, K0, K1, label_nopage_tlbl);
+	wr = build_r4000_tlbchange_handler_head(&p, &l, &r);
+	build_pte_present(&p, &r, wr.r1, wr.r2, wr.r3, label_nopage_tlbl);
 	if (m4kc_tlbp_war())
 		build_tlb_probe_entry(&p);
 
@@ -1788,44 +1878,43 @@ static void __cpuinit build_r4000_tlb_load_handler(void)
 		 * have triggered it.  Skip the expensive test..
 		 */
 		if (use_bbit_insns()) {
-			uasm_il_bbit0(&p, &r, K0, ilog2(_PAGE_VALID),
+			uasm_il_bbit0(&p, &r, wr.r1, ilog2(_PAGE_VALID),
 				      label_tlbl_goaround1);
 		} else {
-			uasm_i_andi(&p, K0, K0, _PAGE_VALID);
-			uasm_il_beqz(&p, &r, K0, label_tlbl_goaround1);
+			uasm_i_andi(&p, wr.r3, wr.r1, _PAGE_VALID);
+			uasm_il_beqz(&p, &r, wr.r3, label_tlbl_goaround1);
 		}
 		uasm_i_nop(&p);
 
 		uasm_i_tlbr(&p);
 		/* Examine  entrylo 0 or 1 based on ptr. */
 		if (use_bbit_insns()) {
-			uasm_i_bbit0(&p, K1, ilog2(sizeof(pte_t)), 8);
+			uasm_i_bbit0(&p, wr.r2, ilog2(sizeof(pte_t)), 8);
 		} else {
-			uasm_i_andi(&p, K0, K1, sizeof(pte_t));
-			uasm_i_beqz(&p, K0, 8);
+			uasm_i_andi(&p, wr.r3, wr.r2, sizeof(pte_t));
+			uasm_i_beqz(&p, wr.r3, 8);
 		}
-
-		UASM_i_MFC0(&p, K0, C0_ENTRYLO0); /* load it in the delay slot*/
-		UASM_i_MFC0(&p, K0, C0_ENTRYLO1); /* load it if ptr is odd */
+		/* load it in the delay slot*/
+		UASM_i_MFC0(&p, wr.r3, C0_ENTRYLO0);
+		/* load it if ptr is odd */
+		UASM_i_MFC0(&p, wr.r3, C0_ENTRYLO1);
 		/*
-		 * If the entryLo (now in K0) is valid (bit 1), RI or
+		 * If the entryLo (now in wr.r3) is valid (bit 1), RI or
 		 * XI must have triggered it.
 		 */
 		if (use_bbit_insns()) {
-			uasm_il_bbit1(&p, &r, K0, 1, label_nopage_tlbl);
-			/* Reload the PTE value */
-			iPTE_LW(&p, K0, K1);
+			uasm_il_bbit1(&p, &r, wr.r3, 1, label_nopage_tlbl);
+			uasm_i_nop(&p);
 			uasm_l_tlbl_goaround1(&l, p);
 		} else {
-			uasm_i_andi(&p, K0, K0, 2);
-			uasm_il_bnez(&p, &r, K0, label_nopage_tlbl);
-			uasm_l_tlbl_goaround1(&l, p);
-			/* Reload the PTE value */
-			iPTE_LW(&p, K0, K1);
+			uasm_i_andi(&p, wr.r3, wr.r3, 2);
+			uasm_il_bnez(&p, &r, wr.r3, label_nopage_tlbl);
+			uasm_i_nop(&p);
 		}
+		uasm_l_tlbl_goaround1(&l, p);
 	}
-	build_make_valid(&p, &r, K0, K1);
-	build_r4000_tlbchange_handler_tail(&p, &l, &r, K0, K1);
+	build_make_valid(&p, &r, wr.r1, wr.r2);
+	build_r4000_tlbchange_handler_tail(&p, &l, &r, wr.r1, wr.r2);
 
 #ifdef CONFIG_HUGETLB_PAGE
 	/*
@@ -1833,8 +1922,8 @@ static void __cpuinit build_r4000_tlb_load_handler(void)
 	 * spots a huge page.
 	 */
 	uasm_l_tlb_huge_update(&l, p);
-	iPTE_LW(&p, K0, K1);
-	build_pte_present(&p, &r, K0, K1, label_nopage_tlbl);
+	iPTE_LW(&p, wr.r1, wr.r2);
+	build_pte_present(&p, &r, wr.r1, wr.r2, wr.r3, label_nopage_tlbl);
 	build_tlb_probe_entry(&p);
 
 	if (kernel_uses_smartmips_rixi) {
@@ -1843,50 +1932,51 @@ static void __cpuinit build_r4000_tlb_load_handler(void)
 		 * have triggered it.  Skip the expensive test..
 		 */
 		if (use_bbit_insns()) {
-			uasm_il_bbit0(&p, &r, K0, ilog2(_PAGE_VALID),
+			uasm_il_bbit0(&p, &r, wr.r1, ilog2(_PAGE_VALID),
 				      label_tlbl_goaround2);
 		} else {
-			uasm_i_andi(&p, K0, K0, _PAGE_VALID);
-			uasm_il_beqz(&p, &r, K0, label_tlbl_goaround2);
+			uasm_i_andi(&p, wr.r3, wr.r1, _PAGE_VALID);
+			uasm_il_beqz(&p, &r, wr.r3, label_tlbl_goaround2);
 		}
 		uasm_i_nop(&p);
 
 		uasm_i_tlbr(&p);
 		/* Examine  entrylo 0 or 1 based on ptr. */
 		if (use_bbit_insns()) {
-			uasm_i_bbit0(&p, K1, ilog2(sizeof(pte_t)), 8);
+			uasm_i_bbit0(&p, wr.r2, ilog2(sizeof(pte_t)), 8);
 		} else {
-			uasm_i_andi(&p, K0, K1, sizeof(pte_t));
-			uasm_i_beqz(&p, K0, 8);
+			uasm_i_andi(&p, wr.r3, wr.r2, sizeof(pte_t));
+			uasm_i_beqz(&p, wr.r3, 8);
 		}
-		UASM_i_MFC0(&p, K0, C0_ENTRYLO0); /* load it in the delay slot*/
-		UASM_i_MFC0(&p, K0, C0_ENTRYLO1); /* load it if ptr is odd */
+		/* load it in the delay slot*/
+		UASM_i_MFC0(&p, wr.r3, C0_ENTRYLO0);
+		/* load it if ptr is odd */
+		UASM_i_MFC0(&p, wr.r3, C0_ENTRYLO1);
 		/*
-		 * If the entryLo (now in K0) is valid (bit 1), RI or
+		 * If the entryLo (now in wr.r3) is valid (bit 1), RI or
 		 * XI must have triggered it.
 		 */
 		if (use_bbit_insns()) {
-			uasm_il_bbit0(&p, &r, K0, 1, label_tlbl_goaround2);
+			uasm_il_bbit0(&p, &r, wr.r3, 1, label_tlbl_goaround2);
 		} else {
-			uasm_i_andi(&p, K0, K0, 2);
-			uasm_il_beqz(&p, &r, K0, label_tlbl_goaround2);
+			uasm_i_andi(&p, wr.r3, wr.r3, 2);
+			uasm_il_beqz(&p, &r, wr.r3, label_tlbl_goaround2);
 		}
-		/* Reload the PTE value */
-		iPTE_LW(&p, K0, K1);
 
 		/*
 		 * We clobbered C0_PAGEMASK, restore it.  On the other branch
 		 * it is restored in build_huge_tlb_write_entry.
 		 */
-		build_restore_pagemask(&p, &r, K0, label_nopage_tlbl, 0);
+		build_restore_pagemask(&p, &r, wr.r3, label_nopage_tlbl, 0);
 
 		uasm_l_tlbl_goaround2(&l, p);
 	}
-	uasm_i_ori(&p, K0, K0, (_PAGE_ACCESSED | _PAGE_VALID));
-	build_huge_handler_tail(&p, &r, &l, K0, K1);
+	uasm_i_ori(&p, wr.r1, wr.r1, (_PAGE_ACCESSED | _PAGE_VALID));
+	build_huge_handler_tail(&p, &r, &l, wr.r1, wr.r2);
 #endif
 
 	uasm_l_nopage_tlbl(&l, p);
+	build_restore_work_registers(&p);
 	uasm_i_j(&p, (unsigned long)tlb_do_page_fault_0 & 0x0fffffff);
 	uasm_i_nop(&p);
 
@@ -1905,17 +1995,18 @@ static void __cpuinit build_r4000_tlb_store_handler(void)
 	u32 *p = handle_tlbs;
 	struct uasm_label *l = labels;
 	struct uasm_reloc *r = relocs;
+	struct work_registers wr;
 
 	memset(handle_tlbs, 0, sizeof(handle_tlbs));
 	memset(labels, 0, sizeof(labels));
 	memset(relocs, 0, sizeof(relocs));
 
-	build_r4000_tlbchange_handler_head(&p, &l, &r, K0, K1);
-	build_pte_writable(&p, &r, K0, K1, label_nopage_tlbs);
+	wr = build_r4000_tlbchange_handler_head(&p, &l, &r);
+	build_pte_writable(&p, &r, wr.r1, wr.r2, wr.r3, label_nopage_tlbs);
 	if (m4kc_tlbp_war())
 		build_tlb_probe_entry(&p);
-	build_make_write(&p, &r, K0, K1);
-	build_r4000_tlbchange_handler_tail(&p, &l, &r, K0, K1);
+	build_make_write(&p, &r, wr.r1, wr.r2);
+	build_r4000_tlbchange_handler_tail(&p, &l, &r, wr.r1, wr.r2);
 
 #ifdef CONFIG_HUGETLB_PAGE
 	/*
@@ -1923,15 +2014,16 @@ static void __cpuinit build_r4000_tlb_store_handler(void)
 	 * build_r4000_tlbchange_handler_head spots a huge page.
 	 */
 	uasm_l_tlb_huge_update(&l, p);
-	iPTE_LW(&p, K0, K1);
-	build_pte_writable(&p, &r, K0, K1, label_nopage_tlbs);
+	iPTE_LW(&p, wr.r1, wr.r2);
+	build_pte_writable(&p, &r, wr.r1, wr.r2, wr.r3, label_nopage_tlbs);
 	build_tlb_probe_entry(&p);
-	uasm_i_ori(&p, K0, K0,
+	uasm_i_ori(&p, wr.r1, wr.r1,
 		   _PAGE_ACCESSED | _PAGE_MODIFIED | _PAGE_VALID | _PAGE_DIRTY);
-	build_huge_handler_tail(&p, &r, &l, K0, K1);
+	build_huge_handler_tail(&p, &r, &l, wr.r1, wr.r2);
 #endif
 
 	uasm_l_nopage_tlbs(&l, p);
+	build_restore_work_registers(&p);
 	uasm_i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff);
 	uasm_i_nop(&p);
 
@@ -1950,18 +2042,19 @@ static void __cpuinit build_r4000_tlb_modify_handler(void)
 	u32 *p = handle_tlbm;
 	struct uasm_label *l = labels;
 	struct uasm_reloc *r = relocs;
+	struct work_registers wr;
 
 	memset(handle_tlbm, 0, sizeof(handle_tlbm));
 	memset(labels, 0, sizeof(labels));
 	memset(relocs, 0, sizeof(relocs));
 
-	build_r4000_tlbchange_handler_head(&p, &l, &r, K0, K1);
-	build_pte_modifiable(&p, &r, K0, K1, label_nopage_tlbm);
+	wr = build_r4000_tlbchange_handler_head(&p, &l, &r);
+	build_pte_modifiable(&p, &r, wr.r1, wr.r2, wr.r3, label_nopage_tlbm);
 	if (m4kc_tlbp_war())
 		build_tlb_probe_entry(&p);
 	/* Present and writable bits set, set accessed and dirty bits. */
-	build_make_write(&p, &r, K0, K1);
-	build_r4000_tlbchange_handler_tail(&p, &l, &r, K0, K1);
+	build_make_write(&p, &r, wr.r1, wr.r2);
+	build_r4000_tlbchange_handler_tail(&p, &l, &r, wr.r1, wr.r2);
 
 #ifdef CONFIG_HUGETLB_PAGE
 	/*
@@ -1969,15 +2062,16 @@ static void __cpuinit build_r4000_tlb_modify_handler(void)
 	 * build_r4000_tlbchange_handler_head spots a huge page.
 	 */
 	uasm_l_tlb_huge_update(&l, p);
-	iPTE_LW(&p, K0, K1);
-	build_pte_modifiable(&p, &r, K0, K1, label_nopage_tlbm);
+	iPTE_LW(&p, wr.r1, wr.r2);
+	build_pte_modifiable(&p, &r, wr.r1, wr.r2,  wr.r3, label_nopage_tlbm);
 	build_tlb_probe_entry(&p);
-	uasm_i_ori(&p, K0, K0,
+	uasm_i_ori(&p, wr.r1, wr.r1,
 		   _PAGE_ACCESSED | _PAGE_MODIFIED | _PAGE_VALID | _PAGE_DIRTY);
-	build_huge_handler_tail(&p, &r, &l, K0, K1);
+	build_huge_handler_tail(&p, &r, &l, wr.r1, wr.r2);
 #endif
 
 	uasm_l_nopage_tlbm(&l, p);
+	build_restore_work_registers(&p);
 	uasm_i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff);
 	uasm_i_nop(&p);
 
@@ -2036,6 +2130,7 @@ void __cpuinit build_tlb_refill_handler(void)
 
 	default:
 		if (!run_once) {
+			scratch_reg = allocate_kscratch();
 #ifdef CONFIG_MIPS_PGD_C0_CONTEXT
 			build_r4000_setup_pgd();
 #endif
-- 
1.7.2.3


From david.daney@cavium.com Wed Jul  6 01:35:59 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Wed, 06 Jul 2011 01:36:05 +0200 (CEST)
Received: from mail3.caviumnetworks.com ([12.108.191.235]:1495 "EHLO
        mail3.caviumnetworks.com" rhost-flags-OK-OK-OK-OK)
        by eddie.linux-mips.org with ESMTP id S1492026Ab1GEXf7 (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Wed, 6 Jul 2011 01:35:59 +0200
Received: from caexch01.caveonetworks.com (Not Verified[192.168.16.9]) by mail3.caviumnetworks.com with MailMarshal (v6,7,2,8378)
        id <B4e13a0210000>; Tue, 05 Jul 2011 16:37:05 -0700
Received: from caexch01.caveonetworks.com ([192.168.16.9]) by caexch01.caveonetworks.com with Microsoft SMTPSVC(6.0.3790.4675);
         Tue, 5 Jul 2011 16:35:57 -0700
Received: from dd1.caveonetworks.com ([12.108.191.236]) by caexch01.caveonetworks.com over TLS secured channel with Microsoft SMTPSVC(6.0.3790.4675);
         Tue, 5 Jul 2011 16:35:57 -0700
Received: from dd1.caveonetworks.com (localhost.localdomain [127.0.0.1])
        by dd1.caveonetworks.com (8.14.4/8.14.3) with ESMTP id p65NZtDL001764;
        Tue, 5 Jul 2011 16:35:55 -0700
Received: (from ddaney@localhost)
        by dd1.caveonetworks.com (8.14.4/8.14.4/Submit) id p65NZt9N001763;
        Tue, 5 Jul 2011 16:35:55 -0700
From:   David Daney <david.daney@cavium.com>
To:     linux-mips@linux-mips.org, ralf@linux-mips.org
Cc:     David Daney <david.daney@cavium.com>
Subject: [PATCH] MIPS: Octeon: Enable C0_UserLocal probing.
Date:   Tue,  5 Jul 2011 16:35:53 -0700
Message-Id: <1309908953-1726-1-git-send-email-david.daney@cavium.com>
X-Mailer: git-send-email 1.7.2.3
X-OriginalArrivalTime: 05 Jul 2011 23:35:57.0684 (UTC) FILETIME=[4A5A4B40:01CC3B6C]
X-archive-position: 30585
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: david.daney@cavium.com
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 3614
Content-Length: 871
Lines: 24

Octeon2 processor cores have a UserLocal register.  Remove the hard
coded negative probe and allow the standard probing to detect this
feature.

Signed-off-by: David Daney <david.daney@cavium.com>
---
 .../asm/mach-cavium-octeon/cpu-feature-overrides.h |    1 -
 1 files changed, 0 insertions(+), 1 deletions(-)

diff --git a/arch/mips/include/asm/mach-cavium-octeon/cpu-feature-overrides.h b/arch/mips/include/asm/mach-cavium-octeon/cpu-feature-overrides.h
index 0d5a42b..a58addb 100644
--- a/arch/mips/include/asm/mach-cavium-octeon/cpu-feature-overrides.h
+++ b/arch/mips/include/asm/mach-cavium-octeon/cpu-feature-overrides.h
@@ -54,7 +54,6 @@
 #define cpu_has_mips_r2_exec_hazard 0
 #define cpu_has_dsp		0
 #define cpu_has_mipsmt		0
-#define cpu_has_userlocal	0
 #define cpu_has_vint		0
 #define cpu_has_veic		0
 #define cpu_hwrena_impl_bits	0xc0000000
-- 
1.7.2.3


From dvomlehn@cisco.com Thu Jul  7 01:36:27 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 07 Jul 2011 01:36:51 +0200 (CEST)
Received: from sj-iport-5.cisco.com ([171.68.10.87]:42815 "EHLO
        sj-iport-5.cisco.com" rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org
        with ESMTP id S1491175Ab1GFXg1 (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Thu, 7 Jul 2011 01:36:27 +0200
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple;
  d=cisco.com; i=dvomlehn@cisco.com; l=139599; q=dns/txt;
  s=iport; t=1309995383; x=1311204983;
  h=date:from:to:cc:subject:message-id:mime-version;
  bh=7W8L6MKo+E6XN+QluyqwLHJda0m4XDXf1RzW2niEle0=;
  b=AO15J5+nTaTPbNhPBBQMMTmA2Exvrnmz7cSE7OkeH1Ic6WqBGqXsouE0
   HXfnnvkFeUsJWS180gxQyBAcVx5wPbhwCZORelbVIW2zR3inpeFB6GURl
   +ewIQWojKDGVufkVFT5vvT9xw8QcgyPICI8hIaxssGqDDJO5sZD9NboDf
   E=;
X-IronPort-Anti-Spam-Filtered: true
X-IronPort-Anti-Spam-Result: Av0EAMXwFE6rRDoJ/2dsb2JhbABTqAt3rVidfIY3BIdGm1g
X-IronPort-AV: E=Sophos;i="4.65,489,1304294400"; 
   d="scan'208";a="362807677"
Received: from mtv-core-4.cisco.com ([171.68.58.9])
  by sj-iport-5.cisco.com with ESMTP; 06 Jul 2011 23:36:15 +0000
Received: from dvomlehn-lnx2.corp.sa.net (dhcp-171-71-47-241.cisco.com [171.71.47.241])
        by mtv-core-4.cisco.com (8.14.3/8.14.3) with ESMTP id p66NaEIq001369;
        Wed, 6 Jul 2011 23:36:14 GMT
Date:   Wed, 6 Jul 2011 16:36:15 -0700
From:   David VomLehn <dvomlehn@cisco.com>
To:     linux-mips@linux-mips.org
Cc:     ralf@linux-mips.org
Subject: [PATCH 1/1] Pendantic stack backtrace code
Message-ID: <20110706233614.GA19332@dvomlehn-lnx2.corp.sa.net>
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
User-Agent: Mutt/1.5.18 (2008-05-17)
X-archive-position: 30586
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: dvomlehn@cisco.com
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 4599
Content-Length: 135229
Lines: 4370

This is the much updated version of the MIPS stack backtrace code submitted
a few years ago. It has a few bugs fixed and should be easier to understand
as a result of a signficant rewrite. There are some references to 64-bit
support, but support is not complete. As a result, this is only enabled
for 32-bit systems.

The code does code analysis according to the o32 backtracing rules, plus
using information the kernel knows and a few simple heuristics. There are
a few things no such backtracer can do, but it handles quite a large
number of cases.

In addition to simple backtracing, the code also traces over exception
frames.  So, if you have an exception handler that panics, you will be able
to see how the code got to where the exception occurred.

This file contains one cleanpatch.pl false positive:
arch/mips/kernel/backtrace/kernel-backtrace-symbols.c: A preprocessor macro
used to create declarations has "extern" in the macro body.

Signed-off-by: David VomLehn <dvomlehn@cisco.com>
---
 arch/mips/Kconfig.debug                          |   11 +
 arch/mips/include/asm/base-backtrace.h           |  440 ++++++
 arch/mips/include/asm/kernel-backtrace-symbols.h |  151 ++
 arch/mips/include/asm/kernel-backtrace.h         |  101 ++
 arch/mips/include/asm/sigframe.h                 |   39 +
 arch/mips/include/asm/thread-backtrace.h         |   87 ++
 arch/mips/kernel/entry.S                         |   17 +-
 arch/mips/kernel/scall32-o32.S                   |   10 +-
 arch/mips/kernel/signal.c                        |   15 +-
 arch/mips/kernel/traps.c                         |   78 +-
 arch/mips/kernel/vdso.c                          |    8 +-
 arch/mips/lib/Makefile                           |    3 +
 arch/mips/lib/base-backtrace.c                   | 1679 ++++++++++++++++++++++
 arch/mips/lib/kernel-backtrace-symbols.c         |   41 +
 arch/mips/lib/kernel-backtrace.c                 | 1080 ++++++++++++++
 arch/mips/lib/thread-backtrace.c                 |  289 ++++
 scripts/module-common.lds                        |   19 -
 17 files changed, 4020 insertions(+), 48 deletions(-)

diff --git a/arch/mips/Kconfig.debug b/arch/mips/Kconfig.debug
index 83ed00a..af3582c 100644
--- a/arch/mips/Kconfig.debug
+++ b/arch/mips/Kconfig.debug
@@ -121,6 +121,17 @@ config DEBUG_ZBOOT
 	  to reduce the kernel image size and speed up the booting procedure a
 	  little.
 
+config MIPS_PEDANTIC_BACKTRACE
+	bool "More comprehensive backtrace code"
+	default n
+	depends on KALLSYMS && 32BIT
+	help
+	  Use backtrace code that more completely handles the various
+	  complexities of the MIPS processors, including branch delay
+	  slots. This is substantially larger than the standard backtrace
+	  code. It also allows tracing over exception frames, which is
+	  occasionally very useful.
+
 config SPINLOCK_TEST
 	bool "Enable spinlock timing tests in debugfs"
 	depends on DEBUG_FS
diff --git a/arch/mips/include/asm/base-backtrace.h b/arch/mips/include/asm/base-backtrace.h
new file mode 100644
index 0000000..ddc61d1
--- /dev/null
+++ b/arch/mips/include/asm/base-backtrace.h
@@ -0,0 +1,440 @@
+/*
+ * Definitions handling one stack frame's worth of stack backtrace.
+ *
+ * Copyright(C) 2007  Scientific-Atlanta, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef	_BASE_BACKTRACE_H_
+#define	_BASE_BACKTRACE_H_
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/stddef.h>
+#include <linux/module.h>
+#include <linux/string.h>
+
+#include <asm/inst.h>
+#include <asm/ptrace.h>
+#include <asm/errno.h>
+
+#define	dbg_print	printk
+
+#define	PRIORITY	KERN_CRIT
+
+#undef DEBUG
+
+#ifdef	DEBUG
+#define bt_dbg(fmt, ...)	do {					\
+			dbg_print("%s: " fmt, __func__, ##__VA_ARGS__); \
+		} while (0)
+
+static const char *const backtrace_rule[] = {
+	"o32 ABI", "bounded"
+};
+#else
+#define bt_dbg(fmt, ...)	do { } while (0)
+#endif
+
+/*
+ * Value to be returned by functions that processes each frame to indicate
+ * a non-error termination of the backtrace. Errors cause a negative errno
+ * to be returned and a frame that does not terminate the back trace cause
+ * a zero to be returned.
+ */
+#define	BASE_BT_END_NULL_PC	1
+#define BASE_BT_N_END		1
+
+/*
+ * Macros for loading addresses and storing registers:
+ * LOAD_ADDR    Load the address of the given object into the $at register
+ * STORE_REG    Store the given register. Assumes that $at points to the
+ *              location for the store.
+ */
+#ifdef CONFIG_64BIT
+#warning TODO: 64-bit code needs to be verified
+#define LOAD_ADDR(obj)  "dla    $at," #obj "\n"
+#define STORE_REG(reg)  "sd     " #reg ",0($at)\n"
+#endif
+
+#ifdef CONFIG_32BIT
+#define LOAD_ADDR(obj)  "la     $at," #obj "\n"
+#define STORE_REG(reg)  "sw     " #reg ",0($at)\n"
+#endif
+
+/*
+ * __base_backtrace_here - set the PC, SP, and return address for current func
+ * @bbt:	Pointer to the &struct base_bt to set
+ */
+#define __base_backtrace_here(bbt)		do {			\
+			register unsigned long s0 asm("s0");		\
+			register unsigned long s1 asm("s1");		\
+			register unsigned long s2 asm("s2");		\
+			register unsigned long s3 asm("s3");		\
+			register unsigned long s4 asm("s4");		\
+			register unsigned long s5 asm("s5");		\
+			register unsigned long s6 asm("s6");		\
+			register unsigned long s7 asm("s7");		\
+			register unsigned long fp asm("fp");		\
+			register unsigned long gp asm("gp");		\
+			(bbt)->pc = __base_backtrace_here_pc();		\
+			(bbt)->sp = __builtin_frame_address(0);		\
+			(bbt)->ra = __builtin_return_address(0);	\
+			(bbt)->gprs[SREG_S0].value = s0;		\
+			(bbt)->gprs[SREG_S1].value = s1;		\
+			(bbt)->gprs[SREG_S2].value = s2;		\
+			(bbt)->gprs[SREG_S3].value = s3;		\
+			(bbt)->gprs[SREG_S4].value = s4;		\
+			(bbt)->gprs[SREG_S5].value = s5;		\
+			(bbt)->gprs[SREG_S6].value = s6;		\
+			(bbt)->gprs[SREG_S7].value = s7;		\
+			(bbt)->gprs[SREG_S8].value = fp;		\
+			(bbt)->gprs[SREG_GP].value = gp;		\
+			(bbt)->gprs[SREG_RA].value = (unsigned long)(bbt)->ra;\
+			(bbt)->gprs[SREG_S0].read = true;		\
+			(bbt)->gprs[SREG_S1].read = true;		\
+			(bbt)->gprs[SREG_S2].read = true;		\
+			(bbt)->gprs[SREG_S3].read = true;		\
+			(bbt)->gprs[SREG_S4].read = true;		\
+			(bbt)->gprs[SREG_S5].read = true;		\
+			(bbt)->gprs[SREG_S6].read = true;		\
+			(bbt)->gprs[SREG_S7].read = true;		\
+			(bbt)->gprs[SREG_S8].read = true;		\
+			(bbt)->gprs[SREG_GP].read = true;		\
+			(bbt)->gprs[SREG_RA].read = true;		\
+			(bbt)->next_pc = NULL;				\
+		} while (0)
+
+/*
+ * base_backtrace_first - process the first stack frame.
+ * @bt:	Pointer to struct base_bt object.
+ * Returns:	Zero on success, otherwise a negative errno value.
+ *		A value of -ENOSYS indicates that the $pc and $sp are valid
+ *		but we can't continue the backtrace.
+ */
+#define base_backtrace_first(bbt, rule)		({			\
+			memset(bbt, 0, sizeof(*(bbt)));			\
+			__base_backtrace_here(bbt);			\
+			__base_backtrace_analyze_frame(bbt, rule);	\
+		})
+
+/* General purpose register (GPR) numbers */
+enum mips_reg_num {
+	MREG_ZERO,	MREG_AT,	MREG_V0,	MREG_V1,
+	MREG_A0,	MREG_A1,	MREG_A2,	MREG_A3,
+	MREG_T0,	MREG_T1,	MREG_T2,	MREG_T3,
+	MREG_T4,	MREG_T5,	MREG_T6,	MREG_T7,
+	MREG_S0,	MREG_S1,	MREG_S2,	MREG_S3,
+	MREG_S4,	MREG_S5,	MREG_S6,	MREG_S7,
+	MREG_T8,	MREG_T9,	MREG_K0,	MREG_K1,
+	MREG_GP,	MREG_SP,	MREG_S8,	MREG_RA,
+	N_MREGS		/* This last one is the number of GPRs */
+};
+
+/* Indices into list of GPRs that must be saved before use */
+enum saved_gpr_num {
+	SREG_S0,	SREG_S1,	SREG_S2,	SREG_S3,
+	SREG_S4,	SREG_S5,	SREG_S6,	SREG_S7,
+	SREG_GP,	SREG_S8,	SREG_RA,
+	N_SREGS		/* Number of saved gprs */
+};
+
+/* True if the corresponding MIPS register must be saved before use */
+extern const bool save_before_use[N_MREGS];
+
+/* Convert saved_gpr_num to mips_reg_num */
+extern const enum mips_reg_num sreg_to_mreg[N_SREGS];
+
+/* Convert mips_reg_num to saved_gpr_num */
+extern const enum saved_gpr_num mreg_to_sreg[N_MREGS];
+
+/*
+ * Additional instruction formats that might be nice to define in
+ * asm/inst.h
+ * */
+#ifdef	__MIPSEB__
+	struct	any_format {		/* Generic format */
+		unsigned int opcode:6;
+		unsigned int remainder:26;
+	};
+
+	struct syscall_format {
+		unsigned int opcode:6;
+		unsigned int code:20;
+		unsigned int func:6;
+	};
+
+	struct	eret_format {
+		unsigned int opcode:6;
+		unsigned int co:1;
+		unsigned int zero:19;
+		unsigned int func:6;
+	};
+#else
+	struct	any_format {		/* Generic format */
+		unsigned int remainder:26;
+		unsigned int opcode:6;
+	};
+
+	struct syscall_format {
+		unsigned int func:6;
+		unsigned int code:20;
+		unsigned int opcode:6;
+	};
+
+	struct	eret_format {
+		unsigned int func:6;
+		unsigned int zero:19;
+		unsigned int co:1;
+		unsigned int opcode:6;
+	};
+#endif
+
+/* Rules for interpreting a stack frame */
+enum base_bt_rule {
+	BASE_BACKTRACE_O32_ABI,	/* Backtrace using o32 ABI rules */
+	BASE_BACKTRACE_LOOKUP_FUNC,	/* Look up function start and size */
+};
+
+struct base_bt_gpr_info {
+	unsigned long	value;
+	bool		read;
+};
+
+/*
+ * struct base_bt - data passed in to and return from a single frame backtrace
+ * @pc:			Program counter
+ * @sp:			Stack pointer value
+ * @fp:			Start of stack frame, which is the same as @sp if
+ *			the stack pointer is being used as the frame poiner
+ * @frame_size:		Number of bytes in this stack frame
+ * @ra:			Address from which this function was called
+ */
+struct base_bt {
+	mips_instruction	*pc;
+	unsigned long		*sp;
+	unsigned long		*fp;
+	unsigned long		frame_size;
+	mips_instruction	*ra;
+	/* This is data to help set the registers for getting the next frame */
+	int			framepointer;
+	struct base_bt_gpr_info	gprs[N_SREGS];
+	mips_instruction	*next_pc;
+};
+
+/*
+ * Helper functions for code analysis
+ */
+
+/* Opcode: addu */
+static inline int is_addu_noreg(mips_instruction inst)
+{
+	struct r_format	*op_p = (struct r_format *)&inst;
+	return op_p->opcode == spec_op && op_p->func == addu_op &&
+			op_p->re == 0;
+}
+
+/* Opcode: inline addu rd, rs, rt */
+static inline int is_addu(mips_instruction inst, unsigned long rd,
+	unsigned long rs, unsigned long rt)
+{
+	struct r_format	*op_p = (struct r_format *)&inst;
+	return is_addu_noreg(inst) &&
+		op_p->rd == rd && op_p->rs == rs && op_p->rt == rt;
+}
+
+/* Opcode: addiu rs, rt, imm */
+static inline int is_addiu(mips_instruction inst, unsigned long rs,
+	unsigned long rt)
+{
+	struct i_format *op_p = (struct i_format *)&inst;
+	return op_p->opcode == addiu_op &&
+		op_p->rs == rs &&  op_p->rt == rt;
+}
+
+/*
+ * is_li determine whether instruction is from an "li" pseudo-instruction
+ * @inst:	Instruction to check
+ * @rt:		Destination register
+ */
+static inline int is_li(mips_instruction inst, unsigned long rt)
+{
+	return is_addiu(inst, MREG_ZERO, rt);
+}
+
+/* Opcode: eret */
+static inline int is_eret(mips_instruction inst)
+{
+	struct eret_format *op_p = (struct eret_format *)&inst;
+	return op_p->opcode == cop0_op && op_p->func == eret_op &&
+		op_p->co == 1 && op_p->zero == 0;
+}
+
+/*
+ * has_bds - determine whether the instruction has a branch delay slot
+ * @op:	Instruction to check
+ *
+ * Returns true if the instruction has a branch delay slot, false otherwise.
+ */
+static inline bool has_bds(mips_instruction op)
+{
+	struct any_format	*op_p = (struct any_format *)&op;
+	struct r_format		*op_p_r;
+	struct i_format		*op_p_i;
+
+	switch (op_p->opcode) {
+	case j_op:
+	case jal_op:
+	case beq_op:
+	case bne_op:
+	case blez_op:
+	case bgtz_op:
+	case beql_op:
+	case bnel_op:
+	case blezl_op:
+	case bgtzl_op:
+		return true;
+		break;
+
+	case spec_op:
+		op_p_r = (struct r_format *)&op;
+		return (op_p_r->func == jr_op || op_p_r->func == jalr_op) &&
+			op_p_r->rt == 0 && op_p_r->rd == 0;
+		break;
+
+	case bcond_op:
+		op_p_i = (struct i_format *)&op;
+		switch (op_p_i->rt) {
+		case bltz_op:
+		case bgez_op:
+		case bltzl_op:
+		case bgezl_op:
+		case bltzal_op:
+		case bgezal_op:
+		case bltzall_op:
+		case bgezall_op:
+			return true;
+			break;
+
+		default:
+			return false;
+			break;
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	return false;
+}
+
+
+/*
+ * is_bb_end - is the given instruction one that ends basic blocks?
+ * @op:	instruction to check
+ *
+ * Returns true if the instruction is one that ends basic blocks, false
+ * if it is not.
+ *
+ * Basic blocks, at least as defined for MIPS backtracing, are ended by
+ * jumps and branches that don't return, and the ERET instructions
+ */
+static inline bool is_bb_end(mips_instruction op)
+{
+	struct any_format	*op_p = (struct any_format *)&op;
+	struct r_format		*op_p_r;
+	struct i_format		*op_p_i;
+	struct eret_format	*op_p_eret;
+
+	switch (op_p->opcode) {
+	case j_op:
+	case beq_op:
+	case bne_op:
+	case blez_op:
+	case bgtz_op:
+	case beql_op:
+	case bnel_op:
+	case blezl_op:
+	case bgtzl_op:
+		return true;
+		break;
+
+	case spec_op:
+		op_p_r = (struct r_format *)&op;
+		return (op_p_r->func == jr_op) &&
+			op_p_r->rt == 0 && op_p_r->rd == 0;
+		break;
+
+	case bcond_op:
+		op_p_i = (struct i_format *)&op;
+		switch (op_p_i->rt) {
+		case bltz_op:
+		case bgez_op:
+		case bltzl_op:
+		case bgezl_op:
+			return true;
+			break;
+
+		default:
+			return false;
+			break;
+		}
+		break;
+
+	case cop0_op:
+		op_p_eret = (struct eret_format *)&op;
+		if (op_p_eret->func == eret_op && op_p_eret->co == 1 &&
+			op_p_eret->zero == 0)
+			return true;
+		break;
+
+	default:
+		break;
+	}
+
+	return false;
+}
+
+/* Internal backtrace functions */
+extern void __base_backtrace_set_from_pt_regs(struct base_bt *bbt,
+	const struct pt_regs *regs);
+extern mips_instruction *__base_backtrace_here_pc(void);
+extern int __base_backtrace_analyze_frame(struct base_bt *bbt,
+	enum base_bt_rule rule);
+
+/*
+ * Functions that are required by the base-backtrace.c code but which must
+ * be supplied by users of that code.
+ * bt_ip_lookup - Look up the symbol start and size, given an address
+ * bt_get_op - Get an opcode-sized element.
+ * bt_get_reg - Get a register-sized element.
+ */
+extern int bt_symbol_lookup(mips_instruction *ip, mips_instruction **start,
+	unsigned long *size);
+extern int bt_get_op(mips_instruction *ip, mips_instruction *op);
+extern int bt_get_reg(unsigned long *rp, unsigned long *reg);
+
+/* Functions exported from the base backtrace code */
+extern int base_backtrace_pop_frame(struct base_bt *bbt);
+extern int base_backtrace_next(struct base_bt *bbt, enum base_bt_rule rule);
+extern int base_backtrace_first_from_pt_regs(struct base_bt *bt,
+	enum base_bt_rule rule, const struct pt_regs *regs);
+extern int base_backtrace_analyze_frame(struct base_bt *bt,
+	enum base_bt_rule rule);
+extern int base_backtrace_pop_frame(struct base_bt *bbt);
+extern int __base_backtrace_generic_pop_frame(struct base_bt *bbt);
+#endif	/* _BASE_BACKTRACE_H_ */
diff --git a/arch/mips/include/asm/kernel-backtrace-symbols.h b/arch/mips/include/asm/kernel-backtrace-symbols.h
new file mode 100644
index 0000000..ed980f3
--- /dev/null
+++ b/arch/mips/include/asm/kernel-backtrace-symbols.h
@@ -0,0 +1,151 @@
+/*
+ *			kernel-backtrace-symbols.h
+ *
+ * This file contains symbols that need to be handled specially. The
+ * idea is that code will define a macro named SPECIAL_SYMBOL that
+ * appropriately generates code for an external reference, then redefines
+ * it to generate a table with the symbols.
+ *
+ * It should be mentioned that, though this is not especially pretty, having
+ * this list of symbols in only one place makes it impossible to define
+ * the external reference for the symbol and then forget to add it to the
+ * table of symbols, which is a big win on the maintenance front.
+ *
+ * To make this list easier to maintain, it is best to keep the symbols
+ * for a given file together and in the order in which they appear in that
+ * file.
+ *
+ * Copyright (C) 2007  Scientific-Atlanta, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/* The first part is protected against multiple inclusions, but the
+ * rest isn't */
+#ifndef	_KERNEL_BACKTRACE_SYMBOLS_H_
+#define	_KERNEL_BACKTRACE_SYMBOLS_H_
+#include <asm/inst.h>
+#include <asm/kernel-backtrace.h>
+
+struct kern_special_sym {
+	const mips_instruction	*start;
+	enum kernel_bt_type	type;
+};
+
+extern const struct kern_special_sym kernel_backtrace_symbols[];
+extern unsigned kernel_backtrace_symbols_size;
+#endif	/* _KERNEL_BACKTRACE_SYMBOLS_H_ */
+
+/* Only define the symbol list if someone has defined the macro we use
+ * to construct it. This allows the above symbols to be included even by
+ * things which only reference the list. */
+
+#ifdef	SPECIAL_SYMBOL
+/* arch/mips/kernel/entry.S */
+SPECIAL_SYMBOL(ret_from_exception, KERNEL_FRAME_GLUE)
+SPECIAL_SYMBOL(ret_from_irq, KERNEL_FRAME_GLUE)
+SPECIAL_SYMBOL(resume_userspace, KERNEL_FRAME_GLUE)
+#ifdef CONFIG_PREEMPT
+SPECIAL_SYMBOL(resume_kernel, KERNEL_FRAME_GLUE)
+SPECIAL_SYMBOL(_need_resched, KERNEL_FRAME_GLUE)
+#endif
+SPECIAL_SYMBOL(ret_from_fork, KERNEL_FRAME_GLUE)
+SPECIAL_SYMBOL(syscall_exit, KERNEL_FRAME_GLUE)
+SPECIAL_SYMBOL(restore_all, KERNEL_FRAME_GLUE)
+SPECIAL_SYMBOL(restore_partial, KERNEL_FRAME_RESTORE_SOME)
+SPECIAL_SYMBOL(work_pending, KERNEL_FRAME_RESTORE_SOME)
+SPECIAL_SYMBOL(work_resched, KERNEL_FRAME_RESTORE_SOME)
+SPECIAL_SYMBOL(work_notifysig, KERNEL_FRAME_RESTORE_SOME)
+SPECIAL_SYMBOL(syscall_exit_work_partial, KERNEL_FRAME_SAVE_STATIC)
+SPECIAL_SYMBOL(syscall_exit_work, KERNEL_FRAME_GLUE)
+
+/* arch/mips/kernel/genex.S */
+SPECIAL_SYMBOL(except_vec_vi_end, KERNEL_FRAME_GLUE)
+SPECIAL_SYMBOL(except_vec_vi_handler, KERNEL_FRAME_SAVE_STATIC)
+SPECIAL_SYMBOL(handle_adel, KERNEL_FRAME_SAVE_ALL)
+SPECIAL_SYMBOL(handle_adel_int, KERNEL_FRAME_GLUE)
+SPECIAL_SYMBOL(handle_ades, KERNEL_FRAME_SAVE_ALL)
+SPECIAL_SYMBOL(handle_ades_int, KERNEL_FRAME_GLUE)
+SPECIAL_SYMBOL(handle_ibe, KERNEL_FRAME_SAVE_ALL)
+SPECIAL_SYMBOL(handle_ibe_int, KERNEL_FRAME_GLUE)
+SPECIAL_SYMBOL(handle_dbe, KERNEL_FRAME_SAVE_ALL)
+SPECIAL_SYMBOL(handle_dbe_int, KERNEL_FRAME_GLUE)
+SPECIAL_SYMBOL(handle_bp, KERNEL_FRAME_SAVE_ALL)
+SPECIAL_SYMBOL(handle_bp_int, KERNEL_FRAME_GLUE)
+SPECIAL_SYMBOL(handle_ri, KERNEL_FRAME_SAVE_ALL)
+SPECIAL_SYMBOL(handle_ri_int, KERNEL_FRAME_GLUE)
+SPECIAL_SYMBOL(handle_cpu, KERNEL_FRAME_SAVE_ALL)
+SPECIAL_SYMBOL(handle_cpu_int, KERNEL_FRAME_GLUE)
+SPECIAL_SYMBOL(handle_ov, KERNEL_FRAME_SAVE_ALL)
+SPECIAL_SYMBOL(handle_ov_int, KERNEL_FRAME_GLUE)
+SPECIAL_SYMBOL(handle_tr, KERNEL_FRAME_SAVE_ALL)
+SPECIAL_SYMBOL(handle_tr_int, KERNEL_FRAME_GLUE)
+SPECIAL_SYMBOL(handle_fpe, KERNEL_FRAME_SAVE_ALL)
+SPECIAL_SYMBOL(handle_fpe_int, KERNEL_FRAME_GLUE)
+SPECIAL_SYMBOL(handle_mdmx, KERNEL_FRAME_SAVE_ALL)
+SPECIAL_SYMBOL(handle_mdmx_int, KERNEL_FRAME_GLUE)
+SPECIAL_SYMBOL(handle_watch, KERNEL_FRAME_SAVE_ALL)
+SPECIAL_SYMBOL(handle_watch_int, KERNEL_FRAME_GLUE)
+SPECIAL_SYMBOL(handle_mcheck, KERNEL_FRAME_SAVE_ALL)
+SPECIAL_SYMBOL(handle_mcheck_int, KERNEL_FRAME_GLUE)
+SPECIAL_SYMBOL(handle_mt, KERNEL_FRAME_SAVE_ALL)
+SPECIAL_SYMBOL(handle_mt_int, KERNEL_FRAME_GLUE)
+SPECIAL_SYMBOL(handle_dsp, KERNEL_FRAME_SAVE_ALL)
+SPECIAL_SYMBOL(handle_dsp_int, KERNEL_FRAME_GLUE)
+
+/* arch/mips/kernel/scall32-o32.S */
+#ifdef	CONFIG_32BIT
+SPECIAL_SYMBOL(handle_sys, KERNEL_FRAME_SAVE_SOME)
+SPECIAL_SYMBOL(stack_done, KERNEL_FRAME_GLUE)
+SPECIAL_SYMBOL(o32_syscall_exit, KERNEL_FRAME_GLUE)
+SPECIAL_SYMBOL(o32_syscall_exit_work, KERNEL_FRAME_GLUE)
+SPECIAL_SYMBOL(syscall_trace_entry, KERNEL_FRAME_SAVE_STATIC)
+SPECIAL_SYMBOL(stackargs, KERNEL_FRAME_GLUE)
+SPECIAL_SYMBOL(_bad_stack, KERNEL_FRAME_GLUE)
+SPECIAL_SYMBOL(illegal_syscall, KERNEL_FRAME_GLUE)
+SPECIAL_SYMBOL(sys_sysmips, KERNEL_FRAME_GLUE)
+SPECIAL_SYMBOL(sys_syscall, KERNEL_FRAME_GLUE)
+SPECIAL_SYMBOL(einval, KERNEL_FRAME_GLUE)
+#endif
+
+/* arch/mips/kernel/scall64-64.S */
+#ifdef	CONFIG_64BIT
+#warning TODO: include symbols for arch/mips/kernel/scall64-64.S
+#endif
+
+/* arch/mips/kernel/scall64-n32.S */
+#ifdef	CONFIG_MIPS32_N32
+#warning TODO: include symbols for arch/mips/kernel/scall64-n32.S
+#endif
+
+/* arch/mips/kernel/scall64-o32.S */
+#ifdef	CONFIG_MIPS32_O32
+#warning TODO: include symbols for arch/mips/kernel/scall64-o32.S
+#endif
+
+/* arch/mips/kernel/smtc-asm.S */
+#ifdef	CONFIG_MIPS32_MT_SMTC
+#warning TODO: include symbols for arch/mips/kernel/smtc-asm.S
+#endif
+
+/* arch/mips/mm/tlbex-fault.S */
+SPECIAL_SYMBOL(tlb_do_page_fault_0, KERNEL_FRAME_SAVE_ALL)
+SPECIAL_SYMBOL(tlb_do_page_fault_1, KERNEL_FRAME_SAVE_ALL)
+
+/* arch/mips/mm/tlbex.c (Code generated dynamically) */
+SPECIAL_SYMBOL(handle_tlbl, KERNEL_FRAME_K0_K1_ONLY)
+SPECIAL_SYMBOL(handle_tlbm, KERNEL_FRAME_K0_K1_ONLY)
+SPECIAL_SYMBOL(handle_tlbs, KERNEL_FRAME_K0_K1_ONLY)
+#endif	/* SPECIAL_SYMBOL */
diff --git a/arch/mips/include/asm/kernel-backtrace.h b/arch/mips/include/asm/kernel-backtrace.h
new file mode 100644
index 0000000..0b28c31
--- /dev/null
+++ b/arch/mips/include/asm/kernel-backtrace.h
@@ -0,0 +1,101 @@
+/*
+ *				kernel-backtrace.h
+ *
+ * Definitions for stack backtracing in the kernel. In addition to handle
+ * process backtraces, because kernel threads can get signals, too, this has
+ * to handle interrupts and exceptions.
+ *
+ * Copyright (C) 2007  Scientific-Atlanta, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef	_ASM_KERNEL_BACKTRACE_H_
+#define	_ASM_KERNEL_BACKTRACE_H_
+
+#include <asm/thread-backtrace.h>
+
+/* Frame type for kernel frame analysis */
+enum kernel_bt_type {
+	KERNEL_FRAME_THREAD,
+	KERNEL_FRAME_TLB_REFILL,	/* In the general exception vector */
+	KERNEL_FRAME_GENERAL_EXCEPTION,	/* In the general exception vector */
+	KERNEL_FRAME_INTERRUPT,		/* In the general exception vector */
+	KERNEL_FRAME_K0_K1_ONLY,	/* Code uses only $k0 & $k1 registers */
+	KERNEL_FRAME_SAVE_SOME,		/* Code uses SAVE_SOME macro */
+	KERNEL_FRAME_SAVE_STATIC,	/* Code uses SAVE_STATIC macro */
+	KERNEL_FRAME_SAVE_ALL,		/* Code uses SAVE_ALL macro */
+	KERNEL_FRAME_GLUE,		/* Registers saved in struct pt_regs */
+	KERNEL_FRAME_RESTORE_SOME,	/* Code uses RESTORE_SOME macro */
+	KERNEL_FRAME_UNEXPECTED		/* Never expect to be in this code */
+};
+
+/*
+ * Postive, non-zero codes returned for normal termination of backtraces.
+ * These extend the codes returned by other layers of the backtrace code
+ * so a unified presentation of backtrace termination is possible.
+ */
+#define	KERNEL_BT_END_CTX_SWITCH	(BASE_BT_N_END + 1)
+#define KERNEL_BT_END_IN_START_KERNEL	(KERNEL_BT_END_CTX_SWITCH + 1)
+#define KERNEL_BT_END_NULL_PC		(KERNEL_BT_END_IN_START_KERNEL + 1)
+
+/*
+ * __kernel_backtrace_here - gets the PC and SP register values for the invoker
+ * @kbt:	Pointer to the struct kernel_bt structure to set
+ */
+#define __kernel_backtrace_here(kbt)	do {				\
+			__thread_backtrace_here(&(kbt)->tbt);		\
+		} while (0)
+
+/*
+ * Gets the first stack frame.
+ * @kbt:	Pointer to &struct kernel_bt object
+ * Returns:	KERNEL_BACKTRACE_CONTEXT_SWITCH	The backtrace should stop
+ *					because the next frame is from user
+ *					mode.
+ *		Zero			This is a good frame.
+ *		A negative errno value	The backtrace should stop because an
+ *					error has occurred.
+ */
+#define kernel_backtrace_first(kbt)		({			\
+			memset((kbt), 0, sizeof(*(kbt)));		\
+			__kernel_backtrace_here(kbt);			\
+			(kbt)->cp0_status = read_c0_status();		\
+			(kbt)->cp0_epc = (mips_instruction *)read_c0_epc();\
+			__kernel_backtrace_analyze_frame(kbt);		\
+		})
+/*
+ * @_next_ra:		Value from RA register. Same as entry RA unless handling
+ *			exceptions and signals.
+ */
+struct kernel_bt {
+	struct thread_bt	tbt;
+	enum kernel_bt_type	type;
+	u32			cp0_status;
+	mips_instruction	*cp0_epc;
+};
+
+/* Internal backtrace functions */
+extern void __kernel_backtrace_set_from_pt_regs(struct kernel_bt *kbt,
+	 const struct pt_regs *regs);
+extern int __kernel_backtrace_analyze_frame(struct kernel_bt *kbt);
+
+/* External backtrace functions */
+extern int kernel_backtrace_pop_frame(struct kernel_bt *kbt);
+extern int kernel_backtrace_next(struct kernel_bt *kbt);
+extern int kernel_backtrace_first_from_pt_regs(struct kernel_bt *kbt,
+	const struct pt_regs *regs);
+extern int kernel_backtrace_analyze_frame(struct kernel_bt *kbt);
+#endif	/* _KERNEL_BACKTRACE_H_ */
diff --git a/arch/mips/include/asm/sigframe.h b/arch/mips/include/asm/sigframe.h
new file mode 100644
index 0000000..75b6c24
--- /dev/null
+++ b/arch/mips/include/asm/sigframe.h
@@ -0,0 +1,39 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1991, 1992  Linus Torvalds
+ * Copyright (C) 1994 - 2000  Ralf Baechle
+ * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
+ */
+#ifndef _ASM_SIGFRAME_H_
+#define _ASM_SIGFRAME_H_
+
+#include <linux/types.h>
+
+#include <asm/signal.h>
+#include <asm/ucontext.h>
+#include <asm-generic/siginfo.h>
+
+/*
+ * Including <asm/unistd.h> would give use the 64-bit syscall numbers ...
+ */
+#define __NR_O32_sigreturn		4119
+#define __NR_O32_rt_sigreturn		4193
+#define __NR_N32_rt_sigreturn		6211
+
+struct sigframe {
+	u32 sf_ass[4];		/* argument save space for o32 */
+	u32 sf_pad[2];		/* Was: signal trampoline */
+	struct sigcontext sf_sc;
+	sigset_t sf_mask;
+};
+
+struct rt_sigframe {
+	u32 rs_ass[4];		/* argument save space for o32 */
+	u32 rs_pad[2];		/* Was: signal trampoline */
+	struct siginfo rs_info;
+	struct ucontext rs_uc;
+};
+#endif
diff --git a/arch/mips/include/asm/thread-backtrace.h b/arch/mips/include/asm/thread-backtrace.h
new file mode 100644
index 0000000..40fa6fe
--- /dev/null
+++ b/arch/mips/include/asm/thread-backtrace.h
@@ -0,0 +1,87 @@
+/*
+ * Backtrace code for Linux operating system processes. This means that, in
+ * addition to handling the normal ABI-conformant stack frames, it must also
+ * handle Linux-specific signal stack frames.
+ *
+ * Copyright (C) 2007  Scientific-Atlanta, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef	_THREAD_BACKTRACE_H_
+#define	_THREAD_BACKTRACE_H_
+
+#include <asm/sigcontext.h>
+#include <asm/base-backtrace.h>
+
+#define	NUM_SIGARGS	4		/* # of signal function arguments */
+
+/* Stack frame type */
+enum thread_frame_type {THREAD_FRAME_BASE, THREAD_FRAME_SIGNAL,
+	THREAD_FRAME_RT_SIGNAL};
+
+/*
+ * struct thread_bt - information for thread backtracing
+ * @bbt:	Base backtrace information, for frames that are not signal
+ *		frames
+ * @sigargs:	Arguments to the signal handler
+ * @type:	Indicates the frame type
+ */
+struct thread_bt {
+	struct base_bt		bbt;
+	enum thread_frame_type	type;
+	unsigned long		*sigargs; /* Arguments to the signal handler */
+};
+
+/*
+ * __thread_backtrace_here - gets the PC and SP register values for the invoker
+ * @tbt:	Pointer to the struct thread_bt structure to set
+ */
+#define __thread_backtrace_here(tbt)	do {				\
+			__base_backtrace_here(&(tbt)->bbt);		\
+		} while (0)
+
+/*
+ * thread_backtrace_first - Get information for the first stack frame
+ * @tbt:	Pointer to trace_backtrace_t object initialized with
+ *		thread_backtrace_init.
+ * @rule:	Rules to use for analyzing the function
+ * Returns:	Zero on success, a negative errno otherwise.
+ */
+#define thread_backtrace_first(tbt, rule)	({			\
+			memset(tbt, 0, sizeof(*(tbt)));			\
+			__thread_backtrace_here(tbt);			\
+			__thread_backtrace_analyze_frame(tbt, rule);	\
+		})
+
+/* Internal backtrace functions */
+extern void __thread_backtrace_set_from_pt_regs(struct thread_bt *tbt,
+	 const struct pt_regs *regs);
+extern int __thread_backtrace_analyze_frame(struct thread_bt *tbt,
+	enum base_bt_rule rule);
+/*
+ * The following function must be supplied by users of this code:
+ * bt_get_sc_reg - get a signal context register
+ */
+extern int bt_get_sc_reg(unsigned long long *rp, unsigned long *reg);
+
+extern int thread_backtrace_pop_frame(struct thread_bt *tbt);
+extern int thread_backtrace_next(struct thread_bt *tbt,
+	enum base_bt_rule rule);
+extern int thread_backtrace_first_from_pt_regs(struct thread_bt *tbt,
+	enum base_bt_rule rule, const struct pt_regs *regs);
+extern int thread_backtrace_analyze_frame(struct thread_bt *tbt,
+	enum base_bt_rule rule);
+#endif	/* _THREAD_BACKTRACE_H_ */
diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S
index 37acfa0..6548ae3 100644
--- a/arch/mips/kernel/entry.S
+++ b/arch/mips/kernel/entry.S
@@ -40,9 +40,10 @@ FEXPORT(__ret_from_irq)
 	andi	t0, t0, KU_USER
 	beqz	t0, resume_kernel
 
+	.globl	resume_userspace
 resume_userspace:
 	local_irq_disable		# make sure we dont miss an
-					# interrupt setting need_resched
+					# interrupt setting _need_resched
 					# between sampling and return
 	LONG_L	a2, TI_FLAGS($28)	# current->work
 	andi	t0, a2, _TIF_WORK_MASK	# (ignoring syscall_trace)
@@ -50,11 +51,13 @@ resume_userspace:
 	j	restore_all
 
 #ifdef CONFIG_PREEMPT
+	.globl resume_kernel
 resume_kernel:
 	local_irq_disable
 	lw	t0, TI_PRE_COUNT($28)
 	bnez	t0, restore_all
-need_resched:
+	.globl	_need_resched
+_need_resched:
 	LONG_L	t0, TI_FLAGS($28)
 	andi	t1, t0, _TIF_NEED_RESCHED
 	beqz	t1, restore_all
@@ -62,14 +65,14 @@ need_resched:
 	andi	t0, 1
 	beqz	t0, restore_all
 	jal	preempt_schedule_irq
-	b	need_resched
+	b	_need_resched
 #endif
 
 FEXPORT(ret_from_fork)
 	jal	schedule_tail		# a0 = struct task_struct *prev
 
 FEXPORT(syscall_exit)
-	local_irq_disable		# make sure need_resched and
+	local_irq_disable		# make sure _need_resched and
 					# signals dont change between
 					# sampling and return
 	LONG_L	a2, TI_FLAGS($28)	# current->work
@@ -141,13 +144,15 @@ FEXPORT(restore_partial)		# restore partial frame
 	RESTORE_SP_AND_RET
 	.set	at
 
+	.globl	work_pending
 work_pending:
 	andi	t0, a2, _TIF_NEED_RESCHED # a2 is preloaded with TI_FLAGS
 	beqz	t0, work_notifysig
+	.globl	work_resched
 work_resched:
 	jal	schedule
 
-	local_irq_disable		# make sure need_resched and
+	local_irq_disable		# make sure _need_resched and
 					# signals dont change between
 					# sampling and return
 	LONG_L	a2, TI_FLAGS($28)
@@ -157,6 +162,7 @@ work_resched:
 	andi	t0, a2, _TIF_NEED_RESCHED
 	bnez	t0, work_resched
 
+	.globl	work_notifysig
 work_notifysig:				# deal with pending signals and
 					# notify-resume requests
 	move	a0, sp
@@ -166,6 +172,7 @@ work_notifysig:				# deal with pending signals and
 
 FEXPORT(syscall_exit_work_partial)
 	SAVE_STATIC
+	.globl	syscall_exit_work
 syscall_exit_work:
 	li	t0, _TIF_WORK_SYSCALL_EXIT
 	and	t0, a2			# a2 is preloaded with TI_FLAGS
diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S
index 99e656e..a32b0e7 100644
--- a/arch/mips/kernel/scall32-o32.S
+++ b/arch/mips/kernel/scall32-o32.S
@@ -50,6 +50,7 @@ NESTED(handle_sys, PT_SIZE, sp)
 	sw	a3, PT_R26(sp)		# save a3 for syscall restarting
 	bgez	t3, stackargs
 
+	.globl	stack_done
 stack_done:
 	lw	t0, TI_FLAGS($28)	# syscall tracing enabled?
 	li	t1, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT
@@ -68,6 +69,7 @@ stack_done:
 	sw	t1, PT_R0(sp)		# save it for syscall restarting
 1:	sw	v0, PT_R2(sp)		# result
 
+	.globl	o32_syscall_exit
 o32_syscall_exit:
 	local_irq_disable		# make sure need_resched and
 					# signals dont change between
@@ -79,11 +81,13 @@ o32_syscall_exit:
 
 	j	restore_partial
 
+	.globl	o32_syscall_exit_work
 o32_syscall_exit_work:
 	j	syscall_exit_work_partial
 
 /* ------------------------------------------------------------------------ */
 
+	.globl	syscall_trace_entry
 syscall_trace_entry:
 	SAVE_STATIC
 	move	s0, t2
@@ -117,6 +121,7 @@ syscall_trace_entry:
 	 * stack arguments from the user stack to the kernel stack.
 	 * This Sucks (TM).
 	 */
+	 .globl	stackargs
 stackargs:
 	lw	t0, PT_R29(sp)		# get old user stack pointer
 
@@ -167,7 +172,8 @@ stackargs:
 	 * The stackpointer for a call with more than 4 arguments is bad.
 	 * We probably should handle this case a bit more drastic.
 	 */
-bad_stack:
+	 .globl	_bad_stack
+_bad_stack:
 	li	v0, EFAULT
 	sw	v0, PT_R2(sp)
 	li	t0, 1				# set error flag
@@ -177,6 +183,7 @@ bad_stack:
 	/*
 	 * The system call does not exist in this kernel
 	 */
+	.globl	illegal_syscall
 illegal_syscall:
 	li	v0, ENOSYS			# error
 	sw	v0, PT_R2(sp)
@@ -216,6 +223,7 @@ illegal_syscall:
 	jr	t2
 	/* Unreached */
 
+	.globl	einval
 einval:	li	v0, -ENOSYS
 	jr	ra
 	END(sys_syscall)
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index dbbe0ce..713c320 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -33,6 +33,7 @@
 #include <asm/cpu-features.h>
 #include <asm/war.h>
 #include <asm/vdso.h>
+#include <asm/sigframe.h>
 
 #include "signal-common.h"
 
@@ -45,20 +46,6 @@ extern asmlinkage int _restore_fp_context(struct sigcontext __user *sc);
 extern asmlinkage int fpu_emulator_save_context(struct sigcontext __user *sc);
 extern asmlinkage int fpu_emulator_restore_context(struct sigcontext __user *sc);
 
-struct sigframe {
-	u32 sf_ass[4];		/* argument save space for o32 */
-	u32 sf_pad[2];		/* Was: signal trampoline */
-	struct sigcontext sf_sc;
-	sigset_t sf_mask;
-};
-
-struct rt_sigframe {
-	u32 rs_ass[4];		/* argument save space for o32 */
-	u32 rs_pad[2];		/* Was: signal trampoline */
-	struct siginfo rs_info;
-	struct ucontext rs_uc;
-};
-
 /*
  * Helper routines
  */
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index e9b3af2..dbf53b5 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -53,6 +53,7 @@
 #include <asm/mmu_context.h>
 #include <asm/types.h>
 #include <asm/stacktrace.h>
+#include <asm/kernel-backtrace.h>
 #include <asm/uasm.h>
 
 extern void check_wait(void);
@@ -86,6 +87,8 @@ extern int fpu_emulator_cop1Handler(struct pt_regs *xcp,
 				    struct mips_fpu_struct *ctx, int has_fpu,
 				    void *__user *fault_addr);
 
+#define MAX_STACK_FRAMES_PRINTED	100
+
 void (*board_be_init)(void);
 int (*board_be_handler)(struct pt_regs *regs, int is_fixup);
 void (*board_nmi_handler_setup)(void);
@@ -125,7 +128,52 @@ static int __init set_raw_show_trace(char *str)
 __setup("raw_show_trace", set_raw_show_trace);
 #endif
 
-static void show_backtrace(struct task_struct *task, const struct pt_regs *regs)
+#ifdef	CONFIG_MIPS_PEDANTIC_BACKTRACE
+/**
+ * show_unwinding_backtrace - Print the backtrace by unwinding stack frames
+ *	one at a time.
+ * @task:	Pointer to the task structure for the task to be unwound
+ * @regs:	Pointer to &pt_regs structure with the initial registers
+ */
+static void show_unwinding_backtrace(struct task_struct *task,
+	const struct pt_regs *regs)
+{
+	int frame_count = 0;
+	int rc;
+	struct kernel_bt kbt;
+	bool called_prev;		/* Entered prev frame with JAL/JALR? */
+
+	called_prev = true;
+	rc = kernel_backtrace_first_from_pt_regs(&kbt, regs);
+
+	while (rc == 0) {
+		mips_instruction *pc;
+
+		frame_count++;
+		if (frame_count > MAX_STACK_FRAMES_PRINTED) {
+			printk(KERN_WARNING "Exceeded maximum number of "
+				"frames (%u)\n", frame_count);
+			rc = -EINVAL;
+			break;
+		}
+
+		/*
+		 * If the last frame we popped was entered with a JAL or JALR
+		 * we subtract two instruction from this PC so that it points
+		 * at the instruction used to do the call.
+		 * */
+		pc = kbt.tbt.bbt.pc - (called_prev ? 2 : 0);
+		print_ip_sym((unsigned long)pc);
+		rc = kernel_backtrace_next(&kbt);
+	}
+
+	if (rc < 0)
+		printk(KERN_WARNING "Backtrace terminated with error %d\n",
+			rc);
+}
+#else
+static void show_unwinding_backtrace(struct task_struct *task,
+	const struct pt_regs *regs)
 {
 	unsigned long sp = regs->regs[29];
 	unsigned long ra = regs->regs[31];
@@ -140,7 +188,33 @@ static void show_backtrace(struct task_struct *task, const struct pt_regs *regs)
 		print_ip_sym(pc);
 		pc = unwind_stack(task, &sp, pc, &ra);
 	} while (pc);
-	printk("\n");
+}
+#endif
+
+#ifdef CONFIG_MIPS_PEDANTIC_BACKTRACE
+static bool show_raw(const struct pt_regs *regs)
+{
+	unsigned long pc = regs->cp0_epc;
+	return raw_show_trace || !__kernel_text_address(pc);
+}
+#else
+static bool show_raw(const struct pt_regs *void)
+{
+	return raw_show_trace;
+}
+#endif
+
+static void show_backtrace(struct task_struct *task, const struct pt_regs *regs)
+{
+	unsigned long sp = regs->regs[29];
+
+	if (show_raw(regs)) {
+		show_raw_backtrace(sp);
+		return;
+	}
+	pr_crit("Symbolic Call Trace:\n");
+	show_unwinding_backtrace(task, regs);
+	pr_crit("\n");
 }
 
 /*
diff --git a/arch/mips/kernel/vdso.c b/arch/mips/kernel/vdso.c
index e5cdfd6..c2d043d 100644
--- a/arch/mips/kernel/vdso.c
+++ b/arch/mips/kernel/vdso.c
@@ -19,13 +19,7 @@
 
 #include <asm/vdso.h>
 #include <asm/uasm.h>
-
-/*
- * Including <asm/unistd.h> would give use the 64-bit syscall numbers ...
- */
-#define __NR_O32_sigreturn		4119
-#define __NR_O32_rt_sigreturn		4193
-#define __NR_N32_rt_sigreturn		6211
+#include <asm/sigframe.h>
 
 static struct page *vdso_page;
 
diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile
index b2cad4f..027a803 100644
--- a/arch/mips/lib/Makefile
+++ b/arch/mips/lib/Makefile
@@ -32,3 +32,6 @@ obj-$(CONFIG_CPU_XLR)		+= dump_tlb.o
 
 # libgcc-style stuff needed in the kernel
 obj-y += ashldi3.o ashrdi3.o cmpdi2.o lshrdi3.o ucmpdi2.o
+
+obj-$(CONFIG_MIPS_PEDANTIC_BACKTRACE) += kernel-backtrace.o \
+	kernel-backtrace-symbols.o base-backtrace.o thread-backtrace.o
diff --git a/arch/mips/lib/base-backtrace.c b/arch/mips/lib/base-backtrace.c
new file mode 100644
index 0000000..4c847d7
--- /dev/null
+++ b/arch/mips/lib/base-backtrace.c
@@ -0,0 +1,1679 @@
+/*
+ * Implement an analysis and backtrace of stackframes. It only supports
+ * processing a single frame as multiple frame backtracing requires operating
+ * system-depending things like signal frames and/or exception handling.
+ * It knows how to handle "o32" ABI-conformant backtraces and backtraces
+ * where a function start and size may be determined.
+ *
+ * Though this has been designed with some thought towards working in a 64-bit
+ * environment, only the 32-bit implementation is complete.
+ *
+ * Since this completely implements the ABI rules for processing a stack
+ * backtrace, without any OS dependencies, keeping this file a separate entity
+ * will allow reuse in other situations.
+ *
+ * Copyright(C) 2007-2011  Scientific-Atlanta, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Author: David VomLehn
+ */
+
+#define DEBUG
+
+#include <asm/base-backtrace.h>
+
+/*
+ * struct base_bt_ctx - data for one frame's worth of stack backtrace
+ * @rules:			Specifies which rules to use to guide the
+ *				backtrace
+ * @bbt:			Pointer to the backtrace info to be returned
+ *				to the caller
+ * @possible_framepointer:	Register number for the register that may be
+ *				a frame pointer.
+ * @fp_restore:			Pointer to the instruction where the frame
+ *				pointer is restored to the function entry value
+ * @sf_allocation:		Pointer to the instruction that allocated the
+ *				stack frame
+ * @sf_deallocation:		Pointer to instruction that pops the stack frame
+ * @fn_start:			Address of 1st opcode of function
+ * @fn_return:			Address of the function's return instruction
+ * @framepointer:		Actual frame pointer register number
+ * @func_size:			Size of the function, in bytes
+ * @jump_linked:		True if entered with jal or jalr
+ * @saved_this_frame:		Index indicating this saved register has been
+ *				saved in this frame
+ * Once we've finished analyzing a frame, we can toss this information. It
+ * isn't made available to the caller.
+ */
+struct base_bt_ctx {
+	struct base_bt	*bbt;
+	enum base_bt_rule	rule;
+	int			possible_framepointer;
+	mips_instruction	*fp_restore;
+	mips_instruction	*sf_allocation;
+	mips_instruction	*sf_deallocation;
+	mips_instruction	*fn_return;
+	mips_instruction	*fn_start;
+	int			framepointer;
+	unsigned long		func_size;
+	bool			jump_linked;
+	bool			saved_this_frame[N_SREGS];
+};
+
+/* Pointers to functions to analyze the current function. This depends on
+ * the value of the enum base_bt_rule passed to the stack frame
+ * analysis functions */
+struct bt_ops {
+	int(*find_func_start) (struct base_bt_ctx *ctx, mips_instruction *pc);
+	int(*find_return) (struct base_bt_ctx *ctx);
+};
+
+/* True if a register must be saved before use, false otherwise. */
+const bool save_before_use[N_MREGS] = {
+	[MREG_S0] = true,
+	[MREG_S1] = true,
+	[MREG_S2] = true,
+	[MREG_S3] = true,
+	[MREG_S4] = true,
+	[MREG_S5] = true,
+	[MREG_S6] = true,
+	[MREG_S7] = true,
+	[MREG_GP] = true,
+	[MREG_S8] = true,
+	[MREG_RA] = true,
+};
+
+/* Convert SREG number to an MREG number */
+const enum mips_reg_num sreg_to_mreg[N_SREGS] = {
+	[SREG_S0] = MREG_S0,
+	[SREG_S1] = MREG_S1,
+	[SREG_S2] = MREG_S2,
+	[SREG_S3] = MREG_S3,
+	[SREG_S4] = MREG_S4,
+	[SREG_S5] = MREG_S5,
+	[SREG_S6] = MREG_S6,
+	[SREG_S7] = MREG_S7,
+	[SREG_GP] = MREG_GP,
+	[SREG_S8] = MREG_S8,
+	[SREG_RA] = MREG_RA,
+};
+
+/* Convert MREG number to SREG number */
+const enum saved_gpr_num mreg_to_sreg[N_MREGS] = {
+	[MREG_S0] = SREG_S0,
+	[MREG_S1] = SREG_S1,
+	[MREG_S2] = SREG_S2,
+	[MREG_S3] = SREG_S3,
+	[MREG_S4] = SREG_S4,
+	[MREG_S5] = SREG_S5,
+	[MREG_S6] = SREG_S6,
+	[MREG_S7] = SREG_S7,
+	[MREG_GP] = SREG_GP,
+	[MREG_S8] = SREG_S8,
+	[MREG_RA] = SREG_RA,
+};
+
+/*
+ * struct vpc - virtual instruction pointer for hiding branch delay slots
+ * @pc:		Point to the instruction if this vpc does not point into a
+ *		branch delay slot. Otherwise, this points to the instruction
+ *		with the branch delay slot.
+ * @have_bds:	True if the instruction pointed to by @pc has a branch
+ *		delay slot
+ * @in_bds:	If @have_bds is true, this is true to indicate the current
+ *		instruction, in the virtual VPC space, is the one in the
+ *		branch delay slot. Otherwise, the current instruction is the
+ *		one *with* the branch delay slot. Ignored if @have_bds is false.
+ *
+ * The intent of vpcs is to hide branch delay slots from code scanning
+ * instructions. It works in a virtual space in which the instruction in the
+ * branch delay slot appears before the branch. This allows the scanning to
+ * pretend that instructions that end basic blocks are actually the last
+ * instruction in the basic block.
+ *
+ * For example, take the following instruction stream as it is stored in
+ * memory:
+ *	100:	move	a0, t1
+ *	104	bne	t0, label
+ *	108:	move	a1, t2
+ *	10c:	addu	t4, t4, t5
+ * Starting at the beginning, this sequence is executed as though it were:
+ *	vpcaddr				addr
+ *	v100:	move	a0, t1		100
+ *	v104:	move	a1, t2		108
+ *	v108:	bne	t0, label	104
+ *	v10c	addu	t4, t4, t5	10c
+ * where v100, etc are vpc-world addresses. If the current instruction, in
+ * the non-vpc world, does not have a branch delay slot and isn't in a branch
+ * delay slot, the non-vpc and vpc addresses are numerically the same. There
+ * are no branch delay slots in vpc-world, but if the current instruction
+ * has a branch delay slot in the non-vpc world, its vpc-world address is
+ * the non-vpc address plus 4. If an instruction is in a branch delay slot in
+ * the non-vpc world, its vpc-world address is its non-vpc address minus 4.
+ *
+ * Operation if an instruction with a branch delay slot is in a branch delay
+ * slot is undefined, so this code ignores the possibility.
+ *
+ * The VPC has three fields:
+ *	pc	Points to the instruction with the branch delay slot or to
+ *		the instruction if it neither has nor is in a branch delay slot.
+ *	has_bds	Boolean to indicate whether the instruction pointed to by pc
+ *		has a branch delay slot
+ *	in_bds	If has_bds is true, this will be true to indicate that the
+ *		current instructions follows that pointed to by the pc field.
+ *		Otherwise, the current instrution is the one pointed to by
+ *		pc. This is ignored if had_bds is false.
+ * With the code above, vpc values for various instructions are:
+ *					pc	has_bs	in_bds	vpcaddr
+ *	100:	move	a0, t1		100	false	n/a	100
+ *	104	bne	t0, label	104	true	false	108
+ *	108:	move	a1, t2		104	true	true	104
+ *	10c:	addu	t4, t4, t5	10c	false	n/a	10c
+ */
+struct vpc {
+	mips_instruction	*pc;
+	bool			have_bds;
+	bool			in_bds;
+};
+
+static int is_jr(mips_instruction inst, unsigned long rs)
+{
+	struct r_format	*op_p = (struct r_format *)&inst;
+	return op_p->opcode == spec_op && op_p->func == jr_op &&
+		op_p->rs == rs && op_p->rt == 0 && op_p->rd == 0;
+}
+
+static int is_lui(mips_instruction inst, unsigned long rt)
+{
+	struct u_format	*op_p = (struct u_format *)&inst;
+	return op_p->opcode == lui_op && op_p->rs == 0 &&
+		op_p->rt == rt;
+}
+
+/*
+ * Is this the save of a register with an offset from the given frame pointer
+ * register?
+ */
+static inline int is_frame_save(mips_instruction inst,
+	enum mips_reg_num framepointer)
+{
+	struct i_format	*op_p = (struct i_format *) &inst;
+	return op_p->opcode == sw_op &&
+		op_p->rs == framepointer;
+}
+
+/*
+ * Returns the number of the register being saved when the opcode is a frame
+ * save.
+ */
+static inline enum mips_reg_num frame_save_rt(mips_instruction op)
+{
+	struct i_format	*op_p = (struct i_format *) &op;
+	return op_p->rt;
+}
+
+/* Returns the offset in the stack frame for a frame save */
+static inline int frame_save_offset(mips_instruction op)
+{
+	struct i_format *op_p = (struct i_format *) &op;
+	return op_p->simmediate;
+}
+
+/*
+ * Return the vpc-addr, i.e the location in vpc address space where the
+ * instruction in a branch delay slot preceeds the instruction with the
+ * branch delay slot. This should not be used for anything other than
+ * debugging.
+ */
+#ifdef DEBUG
+static mips_instruction __used *vpc_vpcaddr(const struct vpc *vpc)
+{
+	if (!vpc->have_bds)
+		return vpc->pc;
+	else if (vpc->in_bds)
+		return vpc->pc;
+	else
+		return vpc->pc + 1;
+}
+#endif
+
+/*
+ * Set the vpc fields when the current instruction might have a branch
+ * delay slot. For example:
+ *	100:	move	a0, t1
+ *	104	bne	t0, label	<-- current instruction
+ *	108:	move	a1, t2
+ *	10c:	addu	t4, t4, t5
+ */
+static int __vpc_might_have_bds(struct vpc *vpc, mips_instruction *p)
+{
+	mips_instruction op;
+	int rc;
+
+	vpc->pc = p;
+
+	/* Get the current instruction */
+	rc = bt_get_op(p, &op);
+	if (rc != 0)
+		return rc;
+	vpc->have_bds = has_bds(op);
+	vpc->in_bds = true;
+
+	return 0;
+}
+
+/*
+ * Set vpc fields when the current instruction might be in a branch delay
+ * slot, which means we have to look at the instruction that precedes the
+ * current instruction. We must have already excluded the possibility that
+ * the current instruction has a branch delay slot. For example:
+ *	100:	move	a0, t1
+ *	104	bne	t0, label
+ *	108:	move	a1, t2		<-- current instruction
+ *	10c:	addu	t4, t4, t5
+ *
+ * When this function is done, either vpc->have_bds won't be set or it
+ * will be set and vpc->pc will point to an instruction with a branch
+ * delay slot. So, if vpc->have-bds is set, the instruction before
+ * vpc->pc can't be an instruction with a branch delay slot.
+ */
+static int __vpc_might_be_in_bds(struct vpc *vpc, mips_instruction *p)
+{
+	mips_instruction op;
+	int rc;
+
+	vpc->pc = p;
+
+	/* Get the instruction before the current one */
+	rc = bt_get_op(p - 1, &op);
+	if (rc != 0)
+		vpc->have_bds = false;
+	else
+		vpc->have_bds = has_bds(op);
+
+	if (vpc->have_bds) {
+		vpc->in_bds = false;
+		vpc->pc -= 1;		/* Point to the opcode with the BDS */
+	}
+
+	return 0;
+}
+
+/*
+ * vpc_set - Set the virtual PC from virtual address
+ * @vpc:	The virtual IP structure to use
+ * @p:		The address to which to set it
+ *
+ * Returns the pointer to vpc it was passed if successful, otherwise
+ * a NULL value.
+ *
+ * The vpc is set so that, if @pc points to an opcode and you use
+ * vpc_get_op() immediately after the call to vpc_set(), you will get the
+ * same opcode.
+ */
+static int vpc_set(struct vpc *vpc, mips_instruction *p)
+{
+	int rc;
+
+	vpc->pc = p;
+
+	/* Check to see if this instruction has a branch delay slot */
+	rc = __vpc_might_have_bds(vpc, p);
+	if (rc == 0) {
+		/*
+		 * If it doesn't have a branch delay slot, it might be in a
+		 * branch delay slot. It would be undefined to have an
+		 * instruction that both has a branch delay slot and is in a
+		 * branch delay slot, so we ignore the possibility.
+		 */
+		if (!vpc->have_bds)
+			rc = __vpc_might_be_in_bds(vpc, p);
+	}
+
+	return rc;
+}
+
+/*
+ * vpc_get - convert a virtual PC address to a normal virtual address
+ */
+static mips_instruction *vpc_get(const struct vpc *vpc)
+{
+	mips_instruction *res;
+
+	if (vpc->have_bds && vpc->in_bds)
+		res = vpc->pc + 1;
+	else
+		res = vpc->pc;
+	return res;
+}
+
+/*
+ * vpc_get_op - get the instruction at a location specified by a &struct vpc
+ * @vpc:	virtual PC with address from which to get instruction
+ *
+ * Returns the instruction at the given virtual PC location.
+ */
+static int vpc_get_op(const struct vpc *vpc,
+	mips_instruction *op)
+{
+	int rc;
+
+	rc = bt_get_op(vpc_get(vpc), op);
+
+	return rc;
+}
+
+/*
+ * vpc_inc - increment the virtual PC
+ * @vpc:	Pointer to the &struct vpc to increment
+ *
+ * Returns 0 on success, otherwise a negative errno value.
+ *
+ * Recapping the above instruction sequence and ordering the instructions as
+ * vpc presents them:
+ *	vpcaddr				vaddr	pc	have_bds	in_bds
+ *	100:	move	a0, t1		100	100	false		n/a
+ *	104:	move	a1, t2		108	104	true		true
+ *	108:	bne	t0, label	104	104	true		false
+ *	10c	addu	t4, t4, t5	10c	10c	false		n/a
+ * To increment:
+ * 1.	If have_bds is false, just increment vpc->pc.
+ * 2.	If have_bds is true and in_bds is false, add two to vpc->pc so that
+ *	it points to the instruction after the one in the branch delay slot.
+ * 3.	If have_bds is true and in_bds is true, simply set in_bds to false.
+ */
+static int vpc_inc(struct vpc *vpc)
+{
+	int rc = 0;
+
+	/*
+	 * If we do not have a branch delay slot, we also know that the
+	 * following instruction is not in a branch delay slot. If we are
+	 * not at the branch delay slot, we also know that the next instruction
+	 * can't be in a branch delay slot since that would have meant that
+	 * the instruction in our branch delay slot had a branch delay slot.
+	 * That's a no-no, so we don't worry about it.
+	 */
+#if 1
+	if (!vpc->have_bds)
+		rc = __vpc_might_have_bds(vpc, vpc->pc + 1);
+	else if (!vpc->in_bds)
+		rc = __vpc_might_have_bds(vpc, vpc->pc + 2);
+	else
+		vpc->in_bds = false;
+#else
+	if (!vpc->have_bds)
+		rc = __vpc_might_have_bds(vpc, vpc->pc + 1);
+	else if (!vpc->in_bds)
+		rc = __vpc_might_have_bds(vpc, vpc->pc + 2);
+	else
+		vpc->in_bds = false;
+#endif
+
+	return rc;
+}
+
+/*
+ * vpc_dec - decrement the virtual PC
+ * @vpc:	Pointer to the &struct vpc to decrement
+ *
+ * Returns zero on success, otherwise a negative errno value.
+ *
+ * To recap the above example, putting the instructions in order as returned
+ * by vpc:
+ *	vpcaddr				vaddr	pc	have_bds	in_bds
+ *	100:	move	a0, t1		100	100	false		n/a
+ *	104:	move	a1, t2		108	104	true		true
+ *	108:	bne	t0, label	104	104	true		false
+ *	10c	addu	t4, t4, t5	10c	10c	false		n/a
+ * To decrement:
+ * 1.	If have_bds is false, just decrement vpc->pc.
+ * 2.	If have_bds is true and in_bds is true, also decrement vpc->pc
+ * 3.	If have bds is true and in_bds is false, simply set vpc->in_bds to true.
+ */
+static int vpc_dec(struct vpc *vpc)
+{
+	int rc = 0;
+
+	/*
+	 * If we don't have a branch delay slot, then we also know we are
+	 * not in a branch delay slot, so the previous instruction can't be
+	 * a branch. If we are at the instruction with a branch delay slot,
+	 * we know the previous instruction cannot be a branch. In other
+	 * words, we only worry whether the previous instruction is in the
+	 * branch delay slot of the instruction before it.
+	 */
+	if (!vpc->have_bds || vpc->in_bds)
+		rc = __vpc_might_be_in_bds(vpc, vpc->pc - 1);
+	else
+		vpc->in_bds = true;
+
+	return rc;
+}
+
+/*
+ * vpc_get_op_inc - get the opcode pointed to and then increment the pointer
+ * @vpc:	Virtual PC with address from which to get the instruction
+ * @op:		Pointer to the location in which to store the opcode
+ *
+ * Returns zero on success, otherwise a negative errno value
+ */
+static int vpc_get_op_inc(struct vpc *vpc, mips_instruction *op)
+{
+	int rc;
+
+	rc = vpc_get_op(vpc, op);
+	if (rc != 0)
+		return rc;
+	return vpc_inc(vpc);
+}
+
+/*
+ * vpc_dec_get_op - decrement the pointer, then get the opcode pointed to
+ * @vpc:	Virtual PC with address from which to get the instruction
+ * @op:		Pointer to the location in which to store the opcode
+ *
+ * Returns zero on success, otherwise a negative errno value
+ */
+static int vpc_dec_get_op(struct vpc *vpc, mips_instruction *op)
+{
+	int rc;
+
+	rc = vpc_dec(vpc);
+	if (rc != 0)
+		return rc;
+	return vpc_get_op(vpc, op);
+}
+
+/*
+ * __vpc_get_vpc - return the virtual address associated with a vpc
+ * @vpc:	Pointer to the vpc
+ *
+ * Returns the virtual PC address.
+ */
+static void *__vpc_get_vpc(const struct vpc *vpc)
+{
+	void *res;
+
+	if (!vpc->have_bds || vpc->in_bds)
+		res = vpc->pc;
+	else
+		res = vpc->pc + 1;
+
+	return res;
+}
+
+/*
+ * vpc_eq - Compare two struct vpc values for equality
+ */
+static bool vpc_eq(const struct vpc *a, const struct vpc *b)
+{
+	return __vpc_get_vpc(a) == __vpc_get_vpc(b);
+}
+
+/*
+ * vpc_gt - Is one vpc value greater than another?
+ */
+static bool vpc_gt(const struct vpc *a, const struct vpc *b)
+{
+	return __vpc_get_vpc(a) > __vpc_get_vpc(b);
+}
+
+/*
+ * vpc_le - Is one vpc value less than or equal to another?
+ */
+static bool vpc_le(const struct vpc *a, const struct vpc *b)
+{
+	return __vpc_get_vpc(a) <= __vpc_get_vpc(b);
+}
+
+/*
+ * Functions that determine whether the opcode falls into a class of
+ * instructions.
+ */
+/* Is this a move to a register from the stack pointer? This could be
+ * initializing a frame pointer. */
+static int is_move_to_fp(mips_instruction inst)
+{
+	struct r_format	*op_p = (struct r_format *) &inst;
+	return is_addu_noreg(inst) &&
+		op_p->rs == MREG_SP && op_p->rt == MREG_ZERO;
+}
+
+/* Is this a move from a register to the stack pointer? If so, it's a restore
+ * of the stack pointer from a frame pointer. */
+static int is_move_from_fp(mips_instruction inst)
+{
+	struct r_format	*op_p = (struct r_format *) &inst;
+	return is_addu_noreg(inst) &&
+		op_p->rt == MREG_ZERO && op_p->rd == MREG_SP;
+}
+
+/* Is this a decrement of the stack pointer register? */
+static int is_sp_dec(mips_instruction op)
+{
+	struct i_format *op_p = (struct i_format *) &op;
+	return is_addiu(op, MREG_SP, MREG_SP) &&
+		op_p->simmediate < 0;
+}
+
+/* Is this an increment of the stack pointer register? */
+static int is_sp_inc(mips_instruction op)
+{
+	struct i_format *op_p = (struct i_format *) &op;
+	return is_addiu(op, MREG_SP, MREG_SP) &&
+		op_p->simmediate > 0;
+}
+
+/* Is this a jump through the return register $ra? */
+static int is_return(mips_instruction op)
+{
+	return is_jr(op, MREG_RA);
+}
+
+/*
+ * This finishes the analysis of this stack frame, based on the analysis
+ * that has already been done. It assumes that:
+ * o	The stack frame size is correct, if one has been allocated, or zero
+ *	if one has not been allocated.
+ * o	A basic block ending with a function return instruction, "jr ra", has
+ *	been found, the stack frame deallocation has been located, and, if
+ *	a stack frame pointer is in use, the location where it is transferred
+ *	to $sp has been found.
+ * @bt:	Pointer to the struct base_bt object used to keep
+ *			track of the analysis.
+ */
+static void complete_analysis(struct base_bt *bt, struct base_bt_ctx *ctx)
+{
+	bt_dbg("frame_size %ld ra %p\n", bt->frame_size, bt->ra);
+
+	if (bt->frame_size != 0) {
+		struct vpc vpc_pc;
+		struct vpc vpc_fp_restore;
+		struct vpc vpc_fn_return;
+		struct vpc vpc_sf_deallocation;
+
+		vpc_set(&vpc_pc, bt->pc);
+		vpc_set(&vpc_fn_return, ctx->fn_return);
+
+		/*
+		 * If a stack frame pointer has been allocated, have we
+		 * executed the instruction where it is moved back to $sp
+		 * on the way to executing a return?
+		 */
+		if (ctx->fp_restore != NULL) {
+			bt_dbg("have a stack frame, restored to sp?\n");
+			vpc_set(&vpc_fp_restore, ctx->fp_restore);
+
+			if (ctx->bbt->framepointer != MREG_SP &&
+				vpc_gt(&vpc_pc, &vpc_fp_restore) &&
+				vpc_le(&vpc_pc, &vpc_fn_return)) {
+				bt_dbg("After stack frame restored to $sp\n");
+				ctx->bbt->framepointer = MREG_SP;
+			}
+		}
+
+		/*
+		 * If we couldn't spot a place where the stack frame was
+		 * deallocated, assume that we're in a function that
+		 * doesn't return.
+		 */
+		if (ctx->sf_deallocation == NULL) {
+			bt_dbg("No stack frame deallocation; "
+				"using heuristic\n");
+		} else {
+			/* If we have passed the point where the stack frame is
+			 * deallocated on our way to a return from the function,
+			 * the frame size is now effectively zero. */
+			vpc_set(&vpc_sf_deallocation, ctx->sf_deallocation);
+
+			if (vpc_gt(&vpc_pc, &vpc_sf_deallocation) &&
+				vpc_le(&vpc_pc, &vpc_fn_return)) {
+				bt_dbg("After stack frame deallocated\n");
+				bt->frame_size = 0;
+			}
+		}
+	}
+}
+
+/*
+ * match_short_get_got - checks for a match for short GOT recovery code
+ * @in_vpc:	Pointer to the &struct vpc for the instruction at which
+ *		the GOT recovery code may start.
+ *
+ * Returns:	true if it matches, zero if it does not.
+ *
+ * Matches the code fragment:
+ *	li	gp,<value>
+ *	addu	gp, gp, t9
+ * which is a short version of the code used to recover the GOT (global offset
+ * table) pointer from the address of the current function.
+ */
+static bool match_short_get_got(const struct vpc *in_vpc)
+{
+	int rc;
+	mips_instruction op;
+	struct vpc vpc;
+
+	vpc = *in_vpc;
+	rc = vpc_dec_get_op(&vpc, &op);
+	if (rc != 0)
+		return false;
+	if (!is_addu(op, MREG_GP, MREG_GP, MREG_T9))
+		return false;
+
+	rc = vpc_dec_get_op(&vpc, &op);
+	if (rc != 0)
+		return false;
+
+	return is_li(op, MREG_GP);
+}
+
+/*
+ * match_long_get_got - match the long version of the GOT recovery code
+ * @in_vpc:	Pointer to the &struct vpc structure describing the current
+ *		code location.
+ * Returns:	True if it matches, false if it does not.
+ *
+ * Matches the code fragment:
+ *	lui	gp,%hi(<value>)
+ *	addiu	gp,gp,%lo(<value>)
+ *	addu	gp, gp, t9
+ * which is a long version of the code used to recover the GOT (global offset
+ * table) pointer from the address of the current function.
+ */
+static bool match_long_get_got(const struct vpc *in_vpc)
+{
+	int rc;
+	mips_instruction op;
+	struct vpc vpc;
+
+	vpc = *in_vpc;
+	rc = vpc_dec_get_op(&vpc, &op);
+	if (rc != 0 || !is_addu(op, MREG_GP, MREG_GP, MREG_T9))
+		return false;
+
+	rc = vpc_dec_get_op(&vpc, &op);
+	if (rc != 0 || !is_addiu(op, MREG_GP, MREG_GP))
+		return false;
+
+	rc = vpc_dec_get_op(&vpc, &op);
+	if (rc != 0)
+		return false;
+	return is_lui(op, MREG_GP);
+}
+
+/*
+ * find_return_bounded_range - find function return within address limits
+ * @bt:	Points to the current struct base_bt object
+ * @start:	Starting address.
+ * @end:	One instruction past the last instruction to check.
+ *			The address here should not be checked.
+ * Returns zero if no error occurred during the scan, otherwise a
+ *		negative errno value.
+ *
+ * This starts at the given address and looks for a function return. If
+ * it finds one, it sets the fn_return field to its address, otherwise it
+ * sets it to NULL_REG.
+ */
+static int find_return_bounded_range(struct base_bt_ctx *ctx,
+	mips_instruction *start, mips_instruction *end)
+{
+	int rc = 0;	/* Assume success */
+	mips_instruction op;
+	struct vpc vpc;
+	struct vpc end_vpc;
+
+	ctx->fn_return = (unsigned long)NULL;
+	rc = vpc_set(&end_vpc, (mips_instruction *)end);
+	if (rc != 0)
+		return rc;
+	rc = vpc_set(&vpc, (mips_instruction *)start);
+	if (rc != 0)
+		return rc;
+
+	while (!vpc_eq(&vpc, &end_vpc)) {
+		rc = vpc_get_op(&vpc, &op);
+		if (rc != 0)
+			return rc;
+		if (is_return(op))
+			break;
+		rc = vpc_inc(&vpc);
+	}
+
+	if (is_return(op)) {
+		bt_dbg("Function return at %p\n", vpc_get(&vpc));
+		ctx->fn_return = vpc_get(&vpc);
+	}
+
+	return rc;
+}
+
+/*
+ * backup_from_sp_decrement - find beginning of ABI function from setting GP
+ * @ctx:	Pointer to backtrace context
+ * @sp_dec:	Pointer to the stack pointer decrement instruction
+ *
+ * We are trying to find the beginning of a MIPS o32 ABI conformant function
+ * and found a stack pointer decrement at the given address. The means we
+ * must be in the first basic block of the current function. We want to
+ * keep backing up until we reach the beginning of the current function.
+ *
+ * The stack pointer decrement may be the first instruction of this
+ * function, but there is the possibility that we have code that
+ * is used to get the address of the GOT (global offset table) into
+ * the gp register. We look to see if we have such code and, if so,
+ * assume that the beginning of that code is the beginning of this
+ * function. This code will look like:
+ *	la	gp,<value>
+ *	addu	gp,gp,t9
+ * where la might expand into either:
+ *	lui	gp,%hi(<value>)
+ *	addiu	gp,gp,%lo(<value>)
+ * or, if <value> fits, as a signed value, in 16 bits:
+ *	li	gp,<value>	(implement as addiu gp,zero,<value>)
+ *
+ * @bt:	Pointer to struct base_bt object.
+ * @sp_dec:	Location of stack pointer decrement instruction
+ * Returns:	Zero if we found the start of the function and a negative
+ *		errno value if not.
+ */
+static int back_up_from_sp_decrement(struct base_bt_ctx *ctx,
+	mips_instruction *sp_dec)
+{
+	int rc;
+	struct vpc vpc;
+	bool matched;
+
+	rc = vpc_set(&vpc, sp_dec);
+	if (rc != 0)
+		return rc;
+
+	/* Try matching the three instruction GOT code */
+	matched = match_long_get_got(&vpc);
+	if (matched) {
+		ctx->fn_start = sp_dec - 3;
+	} else {
+		matched = match_short_get_got(&vpc);
+		if (matched)
+			ctx->fn_start = sp_dec - 2;
+		else
+			ctx->fn_start = sp_dec;
+	}
+
+	return 0;
+}
+
+/*
+ * Find the beginning of the function in which the given address is found.
+ * @bt:	Points to the struct base_bt object
+ * @addr:	Address for which to locate the function start
+ * Returns:	Zero on success, otherwise:
+ *		-ESRCH	The given address is not in known code(inherited from
+ *			bt_symbol_lookup)
+ */
+static int find_func_start_abi(struct base_bt_ctx *ctx, mips_instruction *addr)
+{
+	int rc;
+	struct vpc vpc;
+	mips_instruction op;
+	mips_instruction *p;
+
+	/* Scan backwards until:
+	 * 1.	We can't read an instruction, which we take to indicate we
+	 *	went one instruction past the beginning of the function,
+	 * 2.	We found a "jr ra", which marks the end of the previous
+	 *	function, or
+	 * 3.	We found a decrement of the sp register, which is the stack
+	 *	frame allocation for this function.
+	 */
+	rc = vpc_set(&vpc, addr);
+	if (rc != 0)
+		return rc;
+
+	for (;;) {
+		rc = vpc_get_op(&vpc, &op);
+		if (rc != 0 || is_return(op) || is_sp_dec(op))
+			break;
+
+		rc = vpc_dec(&vpc);
+		if (rc != 0)
+			break;
+	}
+
+	p = vpc_get(&vpc);
+
+	switch (rc) {
+	case -EFAULT:
+		ctx->fn_start = p + 1;
+		bt_dbg("Found function start at %p by running out of "
+			"code\n", ctx->fn_start);
+		break;
+
+	case 0:
+		if (is_return(op)) {
+			ctx->fn_start = p + 2;
+			bt_dbg("Found function start at %p by "
+				"finding previous function end at %p\n",
+				ctx->fn_start, p);
+		}
+
+		else
+			rc = back_up_from_sp_decrement(ctx, p);
+		break;
+
+	default:				/* Got some other error */
+		ctx->fn_start = NULL;
+		break;
+	}
+
+	return rc;
+}
+
+/*
+ * Find the beginning of the function in which the given address is found.
+ * @bt:	Points to the struct base_bt object
+ * @addr:	Address for which to locate the function start
+ * Returns:	Zero on success, otherwise:
+ *		-ESRCH	The given address is not in known code(inherited from
+ *			bt_symbol_lookup)
+ */
+static int find_func_start_bounded(struct base_bt_ctx *ctx,
+	mips_instruction *addr)
+{
+	int	rc;
+
+	rc = bt_symbol_lookup(addr, &ctx->fn_start,
+		&ctx->func_size);
+
+	return rc;
+}
+
+/*
+ * find_return_abi - Find the end of the function by o32 ABI rules.
+ * @bt:	Pointer to struct base_bt object.
+ * Returns:	Zero if we found the end of the function, a negative errno value
+ *		if we could not.
+ *
+ * If the function was found, ctx->fn_return will point to the "jr ra"
+ * instruction, otherwise it will be set to NULL.
+ * If the function was not found, ctx->fn_return will be set to NULL_REG.
+ */
+static int find_return_abi(struct base_bt_ctx *ctx)
+{
+	int rc;
+	struct vpc vpc;
+	mips_instruction op;
+
+	ctx->fn_return = NULL;
+
+	/* Scan forward to find the "jr ra" that marks the end
+	 * of the current function */
+	rc = vpc_set(&vpc, ctx->bbt->pc);
+	if (rc != 0)
+		return rc;
+
+	for (;;) {
+		rc = vpc_get_op(&vpc, &op);
+		if (is_return(op))
+			break;
+		if (rc != 0)
+			return rc;
+		vpc_inc(&vpc);
+	}
+
+	bt_dbg("Function return at %p\n", vpc_get(&vpc));
+	ctx->fn_return = vpc_get(&vpc);
+
+	return rc;
+}
+
+/*
+ * @bt:	Pointer to a struct base_bt object
+ * Returns:	Zero if successful, otherwise a negative errno value.
+ * Find the return instruction starting at the current instruction, but if
+ * we don't find one by the end of the function, try again at the top.
+ */
+static int find_return_bounded(struct base_bt_ctx *ctx)
+{
+	int rc;
+	mips_instruction *end;
+
+	/* Start the search at the next instruction to be excuted and search to
+	 * the end */
+	end = (mips_instruction *)((char *)ctx->fn_start + ctx->func_size);
+	rc = find_return_bounded_range(ctx, ctx->bbt->pc, end);
+
+	/* Start by scanning forward to find the "jr ra" that marks the end
+	 * of the current function. If we didn't get an error, but didn't
+	 * find the instruction, try again from the beginning. */
+
+	if (rc == 0 && ctx->fn_return == NULL) {
+		mips_instruction *alloc_loc;
+
+		/* We couldn't find a "jr ra" after the current
+		 * location, let's try for one before it. We know that
+		 * it can't be before the stack allocation and the
+		 * stack allocation isn't a return, so start right
+		 *  after that.*/
+		alloc_loc = ctx->sf_allocation + 1;
+		bt_dbg("No return after $pc, try starting at %p\n", alloc_loc);
+		rc = find_return_bounded_range(ctx, alloc_loc,
+			ctx->bbt->pc);
+
+		/* If we failed, return an error code */
+		if (rc == 0 && ctx->fn_return == NULL) {
+			bt_dbg("No function return found\n");
+			bt_dbg("1st search: %p to %p, "
+				"2nd: %p to %p\n", ctx->bbt->pc, end,
+				alloc_loc, ctx->bbt->pc);
+
+			rc = -ENOSYS;
+		}
+	}
+
+	return rc;
+}
+
+static struct bt_ops ops[] = {
+	{find_func_start_abi, find_return_abi},
+	{find_func_start_bounded, find_return_bounded},
+};
+
+/*
+ * Locates the first instruction in the current function. We start by
+ * finding the function containing the instruction to which $pc points. Recall
+ * that $pc is actually the return address from a call. It will normally
+ * point to the same function that contains the call, except in the case
+ * where the call is the last thing in the current function. In that special
+ * case, $pc will actually point to the first instruction in the function
+ * after the current function. This arises when the last thing the current
+ * function did was to call a function defined with __attribute__((noreturn)).
+ *
+ * To detect this special case, note that there are two ways that we can
+ * be doing a stack backtrace with $pc pointing to the first instruction of
+ * a function:
+ * 1.	We got a signal, exception, or interrupt just before executing the
+ *	first instruction of a function.
+ * 2.	We called a function, with a jal or jalr instruction, that, with the
+ *	instruction in its branch delay slot, immediately preceeds the
+ *	function to whose instruction $pc currently points.
+ * In the first case, we called the function from somewhere else and the
+ * value in the the ra register will be something other than the value of
+ * the $pc register. In the second case, however, the ra and $pc register
+ * values will be the same. In that case, the current function is the
+ * function in which the jal or jalr instruction is located, which is two
+ * instructions before the current value of the $pc register.
+ * @bt:	Points to the struct base_bt object. The start
+ *			field will be set to the result.
+ * Returns:	Zero on success, otherwise a negative errno value.
+ */
+static int find_func_start(struct base_bt_ctx *ctx)
+{
+	int	rc;
+
+	ctx->jump_linked = true;
+
+	rc = ops[ctx->rule].find_func_start(ctx, ctx->bbt->pc);
+
+	if (rc == 0) {
+		bt_dbg("Comparing $pc %p with function start %p and "
+			"ra 0x%p\n", ctx->bbt->pc, ctx->fn_start,
+			ctx->bbt->ra);
+		if (ctx->bbt->pc == ctx->fn_start &&
+			ctx->bbt->pc == ctx->bbt->ra) {
+			bt_dbg("Detected call in previous function with "
+				"pc %p\n", ctx->bbt->pc);
+			rc = ops[ctx->rule].find_func_start(ctx,
+				ctx->bbt->pc - 2);
+		}
+	}
+
+	if (rc == 0)
+		bt_dbg("Function start detected at %p\n", ctx->fn_start);
+
+	return rc;
+}
+
+/*
+ * Look for a return from the current function. The search starts with the
+ * current location so that, later on, we can determine whether we are
+ * executing in a basic block that ends with a return. If there isn't
+ * a return in the current function that follows the current location, the
+ * search should look for a return before the current location.
+ *
+ * If successful, ctx->fn_return will be set to the address of the
+ * "jr ra" instruction used to do the return.
+ * @bt:	Pointer to a struct base_bt object.
+ * Returns: Zero on success, otherwise a negative errno value.
+ */
+static int find_return(struct base_bt_ctx *ctx)
+{
+	/* Array, indexed by an enum base_bt_rule value, that holds the
+	 * function analysis function pointers. */
+
+	return ops[ctx->rule].find_return(ctx);
+}
+
+/*
+ * Sets the state to indicate that no stack frame has been allocated.
+ * @bt:	Points to the struct base_bt object to set
+ */
+static void set_no_sf_allocation(struct base_bt_ctx *ctx)
+{
+	ctx->sf_allocation = NULL;
+	ctx->bbt->frame_size = 0;
+}
+
+/*
+ * Sets the state that records where the stack frame is allocated and
+ * the frame size.
+ * @bt:	Points to the struct base_bt object to set
+ * @pc:	Location where the stack frame is allocated
+ * @op:	Opcode used to allocate the stack frame, from which
+ *			the size will be taken.
+ */
+static void set_sf_allocation(struct base_bt_ctx *ctx, mips_instruction *pc,
+	mips_instruction op)
+{
+	struct i_format *op_p;
+
+	ctx->sf_allocation = pc;
+	op_p = (struct i_format *) &op;
+	ctx->bbt->frame_size = -op_p->simmediate;
+	bt_dbg("Found frame allocation for %lu bytes at %p\n",
+		ctx->bbt->frame_size, pc);
+}
+
+/*
+ * Finds the location where the stack frame is allocated. If one was found,
+ * the location is stored in sf_allocation, otherwise sf_allocation is set
+ * to NULL.
+ * @bt:	Points to the struct base_bt object. The start
+ *			field will be set to the result.
+ * Returns:	Zero on success, otherwise a negative errno value.
+ */
+static int find_sf_allocation(struct base_bt_ctx *ctx)
+{
+	int rc = 0;
+	struct vpc vpc;
+	struct vpc pc_vpc;
+	mips_instruction op;
+
+	/* Scan forwards from the start of the function until one of the
+	 * following:
+	 * 1.	We reach the current execution location, in which case
+	 *	no stack frame has been allocated,
+	 * 2.	We fail to read an opcode, which is an error,
+	 * 3.	We see a stack frame decrement instruction, which is how
+	 *	the stack frame is allocated, or
+	 * 4.	We reach an instruction marking the end of a basic block,
+	 *	in which the function does not allocate a stack frame at all.
+	 */
+	vpc_set(&pc_vpc, ctx->bbt->pc);
+	rc = vpc_set(&vpc, ctx->fn_start);
+
+	if (rc == 0) {
+		while (!vpc_eq(&vpc, &pc_vpc)) {
+			rc = vpc_get_op(&vpc, &op);
+			if (rc != 0)
+				return rc;
+			if (is_sp_dec(op) || is_bb_end(op))
+				break;
+			vpc_inc(&vpc);
+		}
+	}
+
+	if (vpc_eq(&vpc, &pc_vpc))
+		set_no_sf_allocation(ctx);
+
+	else {
+		if (is_sp_dec(op))
+			set_sf_allocation(ctx, vpc_get(&vpc), op);
+
+		else {
+			/* We exited the loop because we found the end of
+			 * the basic block. If the instruction that marked
+			 * the end of the basic block uses a branch delay
+			 * slot, we need to examine that instruction to see
+			 * if it allocated a stack frame. */
+
+			vpc_dec(&vpc);	/* Point to inst @ branch delay slot */
+			rc = vpc_get_op(&vpc, &op);
+
+			if (rc == 0) {
+				if (is_sp_dec(op))
+					set_sf_allocation(ctx, vpc_get(&vpc),
+						op);
+
+				else
+					set_no_sf_allocation(ctx);
+			}
+		}
+	}
+
+	return rc;
+}
+
+/*
+ * This looks at the given opcode, which comes from the given address, to see
+ * if it is a move to the stack pointer or a stack pointer increment. If so,
+ * it records that information.
+ *
+ * We assume that the basic block that includes the function return instruction
+ * can have only one move to the $sp register, but don't check for that
+ * fact. We also don't check that the frame pointer restore preceeds the
+ * stack frame deallocation.
+ *
+ * This may set the following struct base_bt fields:
+ *	possible_framepointer	Register number used in "move sp, rx"
+ *				instruction.
+ *	fp_restore		Address of the "move sp, rx" instruction
+ *	sf_deallocation		Address of "addiu sp, sp, framesize" instruction
+ *
+ * @bt:	Pointer to the struct base_bt object.
+ * @pc:	Address of the instruction being analyzed
+ * @op:	Instruction to analyze
+ */
+static void analyze_return_block_op(struct base_bt_ctx *ctx,
+	mips_instruction *pc, mips_instruction op)
+{
+	if (is_move_from_fp(op)) {
+		struct r_format	*op_p = (struct r_format *) &op;
+		ctx->possible_framepointer = op_p->rs;
+		ctx->fp_restore = pc;
+		bt_dbg("possible frame pointer $r%d at %p\n",
+			ctx->possible_framepointer, ctx->fp_restore);
+	}
+
+	else if (is_sp_inc(op)) {
+		ctx->sf_deallocation = pc;
+		bt_dbg("frame deallocation at %p\n", pc);
+	}
+}
+
+/*
+ * This function analyzes a basic block ending with the function return
+ * at fn_return. We do a backwards scan, starting with the "jr ra" instruction
+ * until we reach the end of the previous basic block, or the stack frame
+ * allocation, whichever comes first. If sf_deallocation is NULL when this
+ * returns, no stack deallocation was found.
+ * @bt:	Pointer to the struct base_bt object.
+ * Returns:	Zero on success, otherwise a negative errno value.
+ */
+static int analyze_return_block(struct base_bt_ctx *ctx)
+{
+	int rc;
+	struct vpc vpc;
+	struct vpc sf_allocation_vpc;
+	mips_instruction op;
+
+	ctx->possible_framepointer = MREG_SP;
+	ctx->fp_restore = NULL;
+	ctx->sf_deallocation = NULL;
+	vpc_set(&sf_allocation_vpc, ctx->sf_allocation);
+	vpc_set(&vpc, ctx->fn_return);	/* Point to the jr ra */
+
+	/*
+	 * Scan backwards until we reach the instruction where the stack
+	 * frame was allocated or we reach the beginning of the basic block
+	 */
+	do {
+		rc = vpc_dec_get_op(&vpc, &op);
+		if (rc != 0)
+			return rc;
+		analyze_return_block_op(ctx, vpc_get(&vpc), op);
+	} while (!is_bb_end(op) && !vpc_eq(&vpc, &sf_allocation_vpc));
+
+	return rc;
+}
+
+/*
+ * This looks at the given opcode, which comes from the given address, to see
+ * if it is a move from the stack pointer to another register. If this matches
+ * a move from the same register to the stack pointer in the return block,
+ * this must be initialization of a frame pointer.
+ *
+ * This might set the following struct base_bt fields:
+ *	framepointer	Register being used as a frame pointer.
+ *
+ * @bt:	Pointer to struct base_bt object
+ * @op:	Instruction to examine.
+ */
+static void analyze_procedure_prelude_op(struct base_bt_ctx *ctx,
+	mips_instruction op)
+{
+	if (is_move_to_fp(op)) {
+		enum mips_reg_num	rd;
+		struct r_format	*op_p = (struct r_format *) &op;
+
+		rd = op_p->rd;
+		bt_dbg("Checking $r%d to see if is a frame pointer\n", rd);
+		if (rd == ctx->possible_framepointer) {
+			enum saved_gpr_num	sreg;
+
+			bt_dbg("Confirmed frame pointer $r%d\n", rd);
+			sreg = mreg_to_sreg[rd];
+			ctx->bbt->framepointer = rd;
+			if (ctx->bbt->gprs[sreg].read)
+				ctx->bbt->fp = (unsigned long *)ctx->bbt->
+					gprs[sreg].value;
+			else
+				ctx->bbt->fp = ctx->bbt->sp;
+		}
+	}
+}
+
+/*
+ * analyze_procedure_prelude - analyze the first part of the function
+ * @bt:	Pointer to the struct base_bt object.
+ *
+ * Returns zero on success, otherwise a negative errno value.
+ *
+ * This function analyzes the procedure prelude, which is the first basic
+ * in the function, to see if a frame pointer has been established. It stops
+ * when it sees a frame pointer established, it reaches the end of the basic
+ * block, or when when it reaches $pc. This function assumes that the
+ * framepointer element of the struct base_bt has already been set to
+ * MREG_SP.
+ */
+static int analyze_procedure_prelude(struct base_bt_ctx *ctx)
+{
+	int rc = 0;	/* Assume good result */
+	struct vpc vpc;
+	struct vpc pc_vpc;
+	mips_instruction op;
+
+	vpc_set(&pc_vpc, ctx->bbt->pc);
+
+	/*
+	 * Starting at the instruction after the allocation of the stack
+	 * frame, look at each opcode to see if a frame pointer has been
+	 * established. Continue looking until:
+	 * 1.	We have reached the instruction about to be executed,
+	 * 2.	We have established a frame pointer,
+	 * 3.	We aren't able to read the next opcode, and
+	 * 4.	The opcode we read marks the end of a basic block.
+	 *
+	 * Each time we loop, we check to see if a frame pointer was
+	 * established. This very well may not happen; the stack pointer
+	 * is usually used as a frame pointer.
+	 */
+	rc = vpc_set(&vpc, ctx->sf_allocation);
+	if (rc != 0)
+		return rc;
+
+	while (!vpc_eq(&vpc, &pc_vpc) && ctx->bbt->framepointer == MREG_SP) {
+		rc = vpc_get_op_inc(&vpc, &op);
+		if (rc != 0)
+			return rc;
+		if (is_bb_end(op))
+			break;
+		analyze_procedure_prelude_op(ctx, op);
+	}
+
+	return rc;
+}
+
+/*
+ * read_saved_reg_from_frame - read a register saved in the stack frame
+ * @ctx:	Pointer to base backtrace context
+ * @op:		Opcode that might be saving a register
+ *
+ * Returns 0 on success, otherwise a negative errno value.
+ */
+static int read_saved_reg_from_frame(struct base_bt_ctx *ctx,
+	mips_instruction op)
+{
+	enum mips_reg_num rt;
+	int rc = 0;
+	enum saved_gpr_num sreg;
+
+	rt = frame_save_rt(op);
+	sreg = mreg_to_sreg[rt];
+
+	/* Only worry about the first save. Subsequent saves in this
+	 * function would not be saves of the caller's values for this
+	 * register. */
+	if (save_before_use[rt] && !ctx->saved_this_frame[sreg]) {
+		int offset;		/* Offset from frame pointer */
+		unsigned long *rp;
+		unsigned long reg;
+
+		ctx->bbt->gprs[sreg].read = true;
+		ctx->saved_this_frame[sreg] = true;
+		offset = frame_save_offset(op);
+		rp = (unsigned long *)((char *)ctx->bbt->fp + offset);
+		rc = bt_get_reg(rp, &reg);
+		if (rc == 0)
+			ctx->bbt->gprs[sreg].value = reg;
+	}
+
+	return rc;
+}
+
+/*
+ * read_saved_regs_from_frame - read registers saved on the stack
+ * @ctx:	Pointer to struct base_bt_ctx object.
+ * @op:		Opcode used to save the register through the frame pointer
+ *
+ * Returns zero on success, otherwise a negative errno value.
+ *
+ * If the RA register or the current frame pointer were saved on the
+ * stack by the given instruction, retrieve them.
+ */
+static int read_saved_regs_from_frame(struct base_bt_ctx *ctx,
+	mips_instruction op)
+{
+	int rc = 0;
+
+	/* If the given instruction is a save through the
+	 * frame pointer, retrieve the value from the stack.
+	 *
+	 * Note: the o32 ABI says that the registers will be
+	 * saved through the frame pointer, but the reality is
+	 * that they are saved through the stack pointer.
+	 * Accomodate both. */
+	if (is_frame_save(op, ctx->bbt->framepointer))
+		rc = read_saved_reg_from_frame(ctx, op);
+
+	else if (is_frame_save(op, MREG_SP))
+		rc = read_saved_reg_from_frame(ctx, op);
+
+	return rc;
+}
+
+/*
+ * scan_reg_saves - grab registers saved on the stack before use
+ * @ctx:	Pointer to the base_bt_ctx
+ *
+ * There is a set of registers that must be saved before use, which includes
+ * registers eligible to be frame pointers. Scan the first part of the
+ * function to grab the values of those.
+ */
+static int scan_reg_saves(struct base_bt_ctx *ctx)
+{
+	struct vpc vpc;
+	struct vpc pc_vpc;
+	mips_instruction op;
+	int rc = 0;
+
+
+	if (ctx->bbt->frame_size != 0) {
+		vpc_set(&vpc, ctx->sf_allocation);
+		vpc_set(&pc_vpc, ctx->bbt->pc);
+
+		/*
+		 * Loop through the code, starting with the first instruction
+		 * after the stack frame allocation, and each time a register
+		 * is saved in the stack frame, read its value into the array
+		 * with the general purpose register values. We keep doing
+		 * this until:
+		 * 1.	We have reached the instruction we are about to execute,
+		 * 2.	We can't read the next opcode, or
+		 * 3.	The opcode we read marks the end of a basic block.
+		 */
+		vpc_set(&pc_vpc, ctx->bbt->pc);
+		vpc_set(&vpc, ctx->sf_allocation);
+		vpc_inc(&vpc);
+
+		while (!vpc_eq(&vpc, &pc_vpc)) {
+			rc = vpc_get_op(&vpc, &op);
+			if (rc != 0)
+				return rc;
+			if (is_bb_end(op))
+				break;
+
+			rc = read_saved_regs_from_frame(ctx, op);
+			if (rc != 0)
+				return rc;
+			rc = vpc_inc(&vpc);
+			if (rc != 0)
+				return rc;
+		}
+	}
+
+	return rc;
+}
+
+/*
+ * __base_backtrace_analyze_frame - gather info about the current stack frame.
+ * @bt:	Pointer to the struct base_bt object.
+ *
+ * Returns:	Zero on success, otherwise a negative errno value.
+ *
+ * The base_bt is initialized with the current PC and SP values and only those
+ * values. It analyzes the current frame to get enough information to pop the
+ * frame.
+ */
+int __base_backtrace_analyze_frame(struct base_bt *bbt, enum base_bt_rule rule)
+{
+	int	rc = 0;	/* Assume good backtrace */
+	struct base_bt_ctx ctx;
+	int i;
+
+	/* Initialize for the analysis of the current stack frame */
+	ctx.bbt = bbt;
+	ctx.rule = rule;
+
+	/* Clear old information */
+	bbt->frame_size = 0;
+	for (i = 0; i < ARRAY_SIZE(ctx.saved_this_frame); i++)
+		ctx.saved_this_frame[i] = false;
+
+	rc = find_func_start(&ctx);
+	if (rc != 0)
+		return rc;
+
+	ctx.bbt->framepointer = MREG_SP;/* Default frame pointer is $sp */
+	bbt->fp = bbt->sp;		/* Use a default guess */
+
+	/* Find the place where we allocate the stack fame, if any */
+	rc = find_sf_allocation(&ctx);
+
+	/*
+	 * If we are in a leaf function or early in a non-leaf function, we
+	 * won't have allocated a stack frame at this point. If no stack
+	 * frame has been allocated, use the current stack pointer as the
+	 * caller's stack frame and use the current the return address,
+	 * still in $ra. We are then done with the analysis. Otherwise, get
+	 * the current stack frame pointer and see whether the return address
+	 * has been saved on the stack yet.
+	 */
+	if (rc == 0 && bbt->frame_size != 0) {
+		rc = find_return(&ctx);
+
+		switch (rc) {
+		case 0:
+			rc = analyze_return_block(&ctx);
+			if (rc == 0) {
+				rc = analyze_procedure_prelude(&ctx);
+				if (rc == 0)
+					complete_analysis(bbt, &ctx);
+			}
+			break;
+
+		case -ENOSYS:
+			bt_dbg("No return found, applying heuristic\n");
+			ctx.possible_framepointer = MREG_S8;
+			rc = analyze_procedure_prelude(&ctx);
+			break;
+
+		default:			/* Leave the result unchanged */
+			break;
+		}
+
+		/* Grab registers we need from the stack */
+		if (rc == 0)
+			rc = scan_reg_saves(&ctx);
+	}
+
+	return rc;
+}
+EXPORT_SYMBOL(__base_backtrace_analyze_frame);
+
+/*
+ * Updates the $pc and $sp registers with the new values passed. It checks
+ * for stack loops and NULL values of pc.
+ * @bbt:	Pointer to the struct base_bt object.
+ * Returns:	Zero on success, a positive, non-zero value to terminate
+ *		the stack trace, otherwise a negative errno value.
+ */
+int __base_backtrace_generic_pop_frame(struct base_bt *bbt)
+{
+	mips_instruction *previous_pc;
+	unsigned long *previous_sp;
+
+	bt_dbg("Pop %lu-byte frame@%p ra %p fp %p\n", bbt->frame_size,
+		bbt->sp, bbt->ra, bbt->fp);
+
+	previous_pc = bbt->pc;
+	previous_sp = bbt->sp;
+
+	if (bbt->gprs[SREG_RA].read) {
+		bbt->ra = (mips_instruction *)bbt->gprs[SREG_RA].value;
+		bbt->gprs[SREG_RA].read = false;
+	}
+
+	if (bbt->next_pc != NULL) {
+		bbt->pc = bbt->next_pc;
+		bbt->next_pc = NULL;
+	} else {
+		bbt->pc = bbt->ra;
+	}
+
+	bbt->sp = (unsigned long *)((char *)bbt->fp + bbt->frame_size);
+
+	/* Are we in a stack loop? */
+	if (previous_pc == bbt->pc && previous_sp == bbt->sp) {
+		bt_dbg("Terminating backtrace because of stack loop\n");
+		return -ENOSYS;
+	}
+	if (bbt->pc == NULL) {
+		bt_dbg("Terminating backtrace due to NULL pc value\n");
+		return BASE_BT_END_NULL_PC;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(__base_backtrace_generic_pop_frame);
+
+/*
+ * Updates the $pc and $sp registers, given the current values of the
+ * $ra register and the size of the stack frame.
+ * @bt:	Pointer to the struct base_bt object.
+ * Returns:	Zero on success, otherwise a negative errno value.
+ *
+ * It uses values stored in the structure pointed to by @bt to set the PC
+ * and SP registers to the values for the previous frame.
+ */
+int base_backtrace_pop_frame(struct base_bt *bbt)
+{
+	int rc;
+
+	rc = __base_backtrace_generic_pop_frame(bbt);
+
+	return rc;
+}
+EXPORT_SYMBOL(base_backtrace_pop_frame);
+
+/*
+ * __base_backtrace_here_pc - Determine the PC and SP values of the caller
+ * @bbt:	Pointer to the backtrace information
+ */
+noinline mips_instruction *__base_backtrace_here_pc()
+{
+	return (mips_instruction *)__builtin_return_address(0);
+}
+EXPORT_SYMBOL(__base_backtrace_here_pc);
+
+/*
+ * Process one stack frame. The given register values will be updated
+ * based on the processing of the stack frame.
+ * @bt:	Pointer to copies of the register values that
+ *			apply for this frame.
+ * Returns:	Zero on success, otherwise a negative errno value.
+ *		A value of -ENOSYS indicates that the $pc and $sp are valid
+ *		but we can't continue the backtrace.
+ */
+
+int base_backtrace_next(struct base_bt *bbt, enum base_bt_rule rule)
+{
+	int rc;
+
+	rc = base_backtrace_pop_frame(bbt);
+
+	if (rc == 0)
+		rc = __base_backtrace_analyze_frame(bbt, rule);
+
+	return rc;
+}
+EXPORT_SYMBOL(base_backtrace_next);
+
+/*
+ * __base_backtrace_set_from_pt_regs - set the registers from a struct pt_regs
+ * @bt:		Pointer to the &struct base_bt
+ * @regs:	Pointer to the register values to start with
+ *
+ * Returns zero on success, otherwise a negative errno value.
+ */
+void __base_backtrace_set_from_pt_regs(struct base_bt *bbt,
+	const struct pt_regs *regs)
+{
+	int i;
+
+	memset(bbt, 0, sizeof(*bbt));
+
+	bbt->pc = (mips_instruction *)regs->cp0_epc;
+	bbt->sp = (unsigned long *)regs->regs[MREG_SP];
+	bbt->ra = (mips_instruction *)regs->regs[MREG_RA];
+
+	/* Initialize all of the mandatory save registers. */
+	for (i = 0; i < ARRAY_SIZE(bbt->gprs); i++) {
+		if (save_before_use[i]) {
+			enum saved_gpr_num sreg;
+			sreg = mreg_to_sreg[i];
+			bbt->gprs[sreg].value = regs->regs[i];
+			bbt->gprs[sreg].read = true;
+		}
+	}
+}
+EXPORT_SYMBOL(__base_backtrace_set_from_pt_regs);
+
+/*
+ * base_backtrace_first_from_pt_regs - Initialize base_bt struct from pt_regs
+ * @bt:		Pointer to the &struct base_bt
+ * @rule:	Rules to use for the backtrace
+ * @regs:	Pointer to the register values to start with
+ *
+ * Returns zero on success, otherwise a negative errno value.
+ */
+int base_backtrace_first_from_pt_regs(struct base_bt *bbt,
+	enum base_bt_rule rule, const struct pt_regs *regs)
+{
+	int rc;
+
+	__base_backtrace_set_from_pt_regs(bbt, regs);
+
+	/*
+	 * Analyzing the frame gets us the frame size and the return address.
+	 * Note that, though we have the value of the ra register, this is
+	 * likely not to be the return address for the current function.
+	 */
+	rc = __base_backtrace_analyze_frame(bbt, rule);
+	return rc;
+}
+EXPORT_SYMBOL(base_backtrace_first_from_pt_regs);
diff --git a/arch/mips/lib/kernel-backtrace-symbols.c b/arch/mips/lib/kernel-backtrace-symbols.c
new file mode 100644
index 0000000..46622a2
--- /dev/null
+++ b/arch/mips/lib/kernel-backtrace-symbols.c
@@ -0,0 +1,41 @@
+/*
+ * Array with backtrace symbols for the kernel;
+ *
+ * Copyright (C) 2007  Scientific-Atlanta, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Author: David VomLehn
+ */
+
+#include <linux/kernel.h>
+
+/* Generate external references for the symbols that correspond to pieces
+ * of code that should be handled specially in order to do a proper kernel
+ * backtrace. */
+#define	SPECIAL_SYMBOL(name, type) extern mips_instruction	name[];
+#include <asm/kernel-backtrace-symbols.h>
+#undef SPECIAL_SYMBOL
+
+/* Now generate the table for the symbols that we handle specially */
+#define	SPECIAL_SYMBOL(name, type) \
+	{name, type},
+
+const struct kern_special_sym kernel_backtrace_symbols[] = {
+#include <asm/kernel-backtrace-symbols.h>
+};
+#undef SPECIAL_SYMBOL
+
+unsigned kernel_backtrace_symbols_size = ARRAY_SIZE(kernel_backtrace_symbols);
diff --git a/arch/mips/lib/kernel-backtrace.c b/arch/mips/lib/kernel-backtrace.c
new file mode 100644
index 0000000..5ba012e
--- /dev/null
+++ b/arch/mips/lib/kernel-backtrace.c
@@ -0,0 +1,1080 @@
+/*
+ * Perform backtrace in the kernel. This means that, besides handling signals
+ * (which can happen to kernel threads, too), it must handle backtracing over
+ * exceptions and interrupts.
+ *
+ * Copyright (C)2007  Scientific-Atlanta, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option)any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Author: David VomLehn
+ */
+
+#include <linux/kallsyms.h>
+#include <linux/irq.h>
+
+#include <asm/ptrace.h>
+#include <asm/asm-offsets.h>
+
+#include <asm/kernel-backtrace.h>
+#include <asm/kernel-backtrace-symbols.h>
+
+/* Offsets and sizes in the exception vector */
+#define	TLB_REFILL_OFFSET	0
+#define	TLB_REFILL_SIZE		0x80
+#define	GEN_EX_OFFSET		0x180
+#define	GEN_EX_SIZE		0x80
+#define	INTERRUPT_OFFSET	0x200
+#define	INTERRUPT_SIZE		(NR_IRQS * vectorspacing())
+#define	UNEXPECTED_OFFSET	0x80
+#define	UNEXPECTED_SIZE		0x100
+
+/*
+ * struct kernel_bt_ctx - kernel backtrace context used to analyze frames
+ * @kbt:		Points to the structure used to communicate with the
+ *			caller
+ * @start:		Start of current section of code
+ * @size:		Size of current section of code
+ *
+ * Annotation data passed to the frame handler. This is only good for the
+ * lifetime of the frame.
+ */
+struct kernel_bt_ctx {
+	struct kernel_bt	*kbt;
+	mips_instruction	*start;
+	unsigned long		size;
+};
+
+/* Opcode: move rd, rs. Synonym for addu rd, rs, zero. */
+static int is_move(mips_instruction inst, unsigned long rd, unsigned long rs)
+{
+	return is_addu(inst, rd, rs, MREG_ZERO);
+}
+
+static int is_sw(mips_instruction inst, unsigned long rt, unsigned long base)
+{
+	struct i_format	*op_p = (struct i_format *)&inst;
+	return op_p->opcode == sw_op &&
+		op_p->rs == base && op_p->rt == rt;
+}
+
+/* Returns the offset in the stack frame for a frame save */
+static int frame_save_offset(mips_instruction op)
+{
+	struct i_format *op_p = (struct i_format *)&op;
+	return op_p->simmediate;
+}
+
+/*
+ * Is this the save of a register with an offset from the given frame pointer
+ * register?
+ */
+static int is_frame_save(mips_instruction inst, enum mips_reg_num framepointer)
+{
+	struct i_format	*op_p = (struct i_format *)&inst;
+	return op_p->opcode == sw_op &&
+		op_p->rs == framepointer;
+}
+
+/*
+ * Check to see if a given address is in the start_kernel function.
+ * @addr:	Virtual address to check
+ * Returns false if it couldn't get the address of start_kernel or the address
+ * given is not in start_kernel. Otherwise, it returns true.
+ */
+static bool in_start_kernel(mips_instruction *addr)
+{
+	static unsigned long where;
+	static unsigned long size;
+	static bool lookup_done;
+
+	/* Lookup start_kernel just once */
+	if (!lookup_done) {
+		unsigned long offset;
+
+		lookup_done = true;
+		where = kallsyms_lookup_name("start_kernel");
+
+		if (where)
+			if (!kallsyms_lookup_size_offset(where, &size, &offset))
+				where = 0;
+	}
+
+	return where != 0 && (unsigned long)addr >= where &&
+		(unsigned long)addr - where < size;
+}
+
+/*
+ * Returns the number of bytes in each entry of the interrupt vector.
+ */
+static unsigned vectorspacing(void)
+{
+	const unsigned	M_VS = 0x000003e0;
+	const unsigned	S_VS = 0;
+
+	return (read_c0_intctl() & M_VS) >> S_VS;
+}
+
+/*
+ * Function that determines whether we are in some section of the exception
+ * vector. If no exception vector has been set up, which we determine
+ * by seeing whether ebase has yet been set, we can't be in the exception
+ * vector code.
+ * @pc:		Current program counter
+ *		start	Offset of the start of the section from ebase
+ *		size	Size of the section.
+ * Returns:	Non-zero if we are in the given section, zero otherwise.
+ */
+static int in_exception_vector(mips_instruction *pc, unsigned start,
+	unsigned size)
+{
+	int			result;
+
+	if (ebase == 0)
+		result = 0;
+
+	else {
+		unsigned long	offset;
+
+		offset = (unsigned long)pc - ebase;
+		result = (offset >= start && offset < size);
+	}
+
+	return result;
+}
+
+/*
+ * This looks for the given pc value in the list of pieces of code that must
+ * be handled specially for backtrace purposes. If found, it will store the
+ * symbol start and size.
+ * @pc:		Value of pc to look for
+ *		start	Address of the start of the code section.
+ *		size	Number of bytes in the code section.
+ * Returns:	A pointer to the entry in the table of special symbols
+ *		corresponding to pc if it could be found, NULL if not.
+ */
+static const struct kern_special_sym *special_symbol(mips_instruction *pc,
+	mips_instruction **start, unsigned long *size)
+{
+	const struct kern_special_sym	*result;
+	unsigned long			symbolsize;
+	unsigned long			offset;
+
+	/* We could look up each symbol and then see whether it contained the
+	 * pc, but a faster way is to look up the symbol corresponding to the
+	 * pc, then just quickly go through the table looking for it. This
+	 * could be even faster if the table were sorted by address because
+	 * we would be able to do a binary search of the table, but this is
+	 * simpler and only rarely done. */
+
+	/* Find the symbol corresponding to the pc */
+	if (!kallsyms_lookup_size_offset((unsigned long)pc, &symbolsize,
+		&offset))
+		result = NULL;
+
+	else {
+		size_t		i;
+		mips_instruction	*symbol_start;
+
+		/* Search for the address within our table of special symbols.
+		 * We do a simple linear search, now, but if the table were
+		 * sorted we could use a faster binary search. Ah, someday when
+		 * we have time... */
+		symbol_start = (mips_instruction *)((char *)pc - offset);
+
+		for (i = 0;
+			i < kernel_backtrace_symbols_size &&
+				symbol_start !=
+					kernel_backtrace_symbols[i].start;
+			i++)
+			;
+
+		if (i == kernel_backtrace_symbols_size)
+			result = NULL;
+
+		else {
+			result = &kernel_backtrace_symbols[i];
+			*start = (mips_instruction *)symbol_start;
+			*size = symbolsize;
+		}
+	}
+
+	return result;
+}
+
+/*
+ * read_pt_regs_sp - handle stack pointer stored in pt_regs structure
+ * @ctx:	Pointer to the kernel backtrace context
+ * @regs:	Pointer to the &struct pt_regs structure from which to read
+ *
+ * Returns 0 on success, otherwise a negative errno value.
+ */
+static int read_pt_regs_sp(struct kernel_bt_ctx *ctx, struct pt_regs *regs)
+{
+	int rc;
+	struct base_bt *bbt;
+	unsigned long new_sp;
+
+	bbt = &ctx->kbt->tbt.bbt;
+	rc = bt_get_reg(&regs->regs[MREG_SP], &new_sp);
+
+	if (rc == 0)
+		bbt->frame_size = (char *)new_sp - (char *)bbt->sp;
+
+	return rc;
+}
+
+/*
+ * read_pt_regs_epc - handle an exception PC stored in pt_regs structure
+ * @ctx:	Pointer to the kernel backtrace context
+ * @regs:	Pointer to the &struct pt_regs structure from which to read
+ *
+ * Returns 0 on success, otherwise a negative errno value.
+ */
+static int read_pt_regs_epc(struct kernel_bt_ctx *ctx, struct pt_regs *regs)
+{
+	int rc;
+	struct base_bt *bbt;
+	unsigned long new_cp0_epc;
+
+	bbt = &ctx->kbt->tbt.bbt;
+	rc = bt_get_reg(&regs->cp0_epc, &new_cp0_epc);
+
+	return rc;
+}
+
+/*
+ * read_pt_regs_status - handle CP0 Status register stored in pt_regs structure
+ * @ctx:	Pointer to the kernel backtrace context
+ * @regs:	Pointer to the &struct pt_regs structure from which to read
+ *
+ * Returns 0 on success, otherwise a negative errno value.
+ */
+static int read_pt_regs_status(struct kernel_bt_ctx *ctx, struct pt_regs *regs)
+{
+	int rc;
+	unsigned long new_cp0_status;
+
+	rc = bt_get_reg(&regs->cp0_status, &new_cp0_status);
+
+	if (rc == 0)
+		ctx->kbt->cp0_status = new_cp0_status;
+
+	return rc;
+}
+
+/*
+ * read_pt_regs_sp_epc_status - read SP, EPC, and Status registers
+ */
+static int read_pt_regs_sp_epc_status(struct kernel_bt_ctx *ctx,
+	struct pt_regs *regs)
+{
+	int rc;
+	rc = read_pt_regs_sp(ctx, regs);
+	if (rc != 0)
+		return rc;
+
+	rc = read_pt_regs_epc(ctx, regs);
+	if (rc != 0)
+		return rc;
+
+	rc = read_pt_regs_status(ctx, regs);
+	if (rc != 0)
+		return rc;
+
+	return 0;
+}
+
+/*
+ * read_pt_regs_gpr_by_mreg - reads a register from a struct pt_regs, if saved
+ * @kbt:	Pointer to the struct kernel_bt_ctx object in which
+ *			to store the value.
+ * @reg_num:	The particular register to store.
+ * @ptr:	Location of the value
+ * Returns zero on success, a negative errno value otherwise.
+ */
+static int read_pt_regs_gpr_by_mreg(struct kernel_bt_ctx *ctx,
+	struct pt_regs *regs, enum mips_reg_num mreg)
+{
+	int rc;
+	struct base_bt *bbt;
+
+	if (save_before_use[mreg]) {
+		unsigned long reg;
+
+		bbt = &ctx->kbt->tbt.bbt;
+		rc = bt_get_reg(&regs->regs[mreg], &reg);
+		if (rc == 0) {
+			bbt->gprs[mreg_to_sreg[mreg]].value = reg;
+			bbt->gprs[mreg_to_sreg[mreg]].read = true;
+		}
+	}
+
+	return rc;
+}
+
+/*
+ * read_pt_regs_gpr_by_offset - read the gprs from the stack frame by offset
+ * @kbt:	Pointer to the struct kernel_bt_ctx object
+ * @ptr:	Pointer to the memory location where the struct
+ *		pt_regs object is stored.
+ * @offset:	Offset from the pointer to the value for the
+ *		register we want to read
+ *
+ * Returns zero on success, a negative errno value otherwise.
+ * The current instruction is a save through the frame pointer. Retrieve
+ * the value that was saved. The offset tells us which register to retrieve,
+ * as well as being the offset in the struct pt_regs from which to retrieve it.
+ */
+static int read_pt_regs_gpr_by_offset(struct kernel_bt_ctx *ctx,
+	struct pt_regs *regs, int offset)
+{
+	int result = 0;		/* Assume success */
+
+	/*
+	 * The registers mentioned in this statement are those saved by the
+	 * SAVE_SOME or SAVE_STATIC macros. We only really care about saved
+	 * registers and a few special ones, so only some of the possibilities
+	 * are actually interesting.
+	 */
+	switch (offset) {
+	case PT_R0:	/* MREG_ZERO */				/* SAVE_SOME*/
+	case PT_R2:	/* MREG_V0 */				/* SAVE_SOME*/
+	case PT_R3:	/* MREG_V1 */				/* SAVE_SOME*/
+	case PT_R4:	/* MREG_A0 */				/* SAVE_SOME*/
+	case PT_R5:	/* MREG_A1 */				/* SAVE_SOME*/
+	case PT_R6:	/* MREG_A1 */				/* SAVE_SOME*/
+	case PT_R7:	/* MREG_A3 */				/* SAVE_SOME*/
+	case PT_R25:	/* MREG_T9 */				/* SAVE_SOME */
+	case PT_R31:	/* MREG_T9 */				/* SAVE_SOME */
+		break;
+
+	case PT_R16:						/* SAVE_STATIC*/
+		result = read_pt_regs_gpr_by_offset(ctx, regs, MREG_S0);
+		break;
+	case PT_R17:						/* SAVE_STATIC*/
+		result = read_pt_regs_gpr_by_offset(ctx, regs, MREG_S1);
+		break;
+	case PT_R18:						/* SAVE_STATIC*/
+		result = read_pt_regs_gpr_by_offset(ctx, regs, MREG_S2);
+		break;
+	case PT_R19:						/* SAVE_STATIC*/
+		result = read_pt_regs_gpr_by_offset(ctx, regs, MREG_S3);
+		break;
+	case PT_R20:						/* SAVE_STATIC*/
+		result = read_pt_regs_gpr_by_offset(ctx, regs, MREG_S4);
+		break;
+	case PT_R21:						/* SAVE_STATIC*/
+		result = read_pt_regs_gpr_by_offset(ctx, regs, MREG_S5);
+		break;
+	case PT_R22:						/* SAVE_STATIC*/
+		result = read_pt_regs_gpr_by_offset(ctx, regs, MREG_S6);
+		break;
+	case PT_R23:						/* SAVE_STATIC*/
+		result = read_pt_regs_gpr_by_offset(ctx, regs, MREG_S7);
+		break;
+	case PT_R28:						/* SAVE_SOME */
+		result = read_pt_regs_gpr_by_offset(ctx, regs, MREG_GP);
+		break;
+	case PT_R30:						/* SAVE_STATIC*/
+		result = read_pt_regs_gpr_by_offset(ctx, regs, MREG_S8);
+		break;
+
+	/*
+	 * The following are special cases. They aren't saved registers by
+	 * they greatly affect what follows.
+	 */
+	case PT_R29:						/* SAVE_SOME */
+		result = read_pt_regs_sp(ctx, regs);
+		break;
+	case PT_EPC:						/* SAVE_SOME */
+		result = read_pt_regs_epc(ctx, regs);
+		break;
+	case PT_STATUS:
+		result = read_pt_regs_status(ctx, regs);	/* SAVE_SOME */
+		break;
+	}
+
+	return result;
+}
+
+/*
+ * read_pt_regs_already_saved - read registers saved in a sequence of code
+ * @kbt:	Pointer to the struct kernel_bt_ctx object
+ * @ip:		Pointer to the first instruction to examine to see if
+ *		it is a store.
+ * @ptr:	Pointer to the struct pt_regs object in which values
+ *		are stored.
+ *
+ * Returns zero on success, a negative errno value otherwise.
+ *
+ * At this point the SAVE_SOME or SAVE_STATIC macro has started to save
+ * register values into a struct pt_regs object. We run through the current
+ * code looking for stores relative to the $sp register and restore values
+ * from there.
+ */
+static int read_pt_regs_already_saved(struct kernel_bt_ctx *ctx,
+	mips_instruction *ip, struct pt_regs *regs)
+{
+	int		result = 0;	/* Assume success */
+	mips_instruction	op;
+
+	for (; ip != ctx->kbt->tbt.bbt.pc &&
+			(result = bt_get_op(ip, &op)) == 0 &&
+			!is_bb_end(op);
+			ip += 1) {
+
+		/* If this is a save, we use the offset to determine which
+		 * register is being saved. Since all we want to do is to
+		 * restore the register value, the offset is all we need to
+		 * determine which register is to be restored. */
+		if (is_frame_save(op, MREG_SP))
+			result = read_pt_regs_gpr_by_offset(ctx, regs,
+				frame_save_offset(op));
+	}
+
+	return result;
+}
+
+/*
+ * read_pt_regs_all_saved - read all saved register from a pt_regs structure
+ * @ctx:	Pointer to struct kernel_bt_ctx
+ * @regs:	Pointer to the struct pt_regs
+ */
+static int read_pt_regs_all_saved(struct kernel_bt_ctx *ctx)
+{
+	enum saved_gpr_num i;
+	int rc;
+	struct pt_regs *regs;
+
+	regs = (struct pt_regs *)ctx->kbt->tbt.bbt.sp;
+
+	rc = read_pt_regs_sp_epc_status(ctx, regs);
+	if (rc != 0)
+		return rc;
+
+	/* Loop through the saved registers */
+	for (i = SREG_S0; i < N_SREGS; i++) {
+		rc = read_pt_regs_gpr_by_mreg(ctx, regs, sreg_to_mreg[i]);
+		if (rc != 0)
+			return rc;
+	}
+
+	return 0;
+}
+
+/*
+ * Loads the next register values for code that uses the $k0 and $k1
+ * registers only. In this case, the $pc value is in the CP0 EPC register
+ * and all other registers still have their original values.
+ * @ctx:	Pointer to the current struct kernel_bt_ctx object.
+ * Returns:	KERNEL_BT_END_CTX_SWITCH The backtrace should stop because
+ *					the next frame is from user mode.
+ *		Zero			This is a good frame.
+ *		A negative errno value	The backtrace should stop because an
+ *					error has occurred.
+ */
+static int analyze_k0_k1_only_frame(struct kernel_bt_ctx *ctx)
+{
+	int	result = 0;		/* Assume success */
+
+	ctx->kbt->tbt.bbt.pc = ctx->kbt->cp0_epc;
+
+	return result;
+}
+
+/*
+ * This handles a code section that starts with use of a SAVE_SOME macro and
+ * which *may* then save additional registers using macros like SAVE_STATIC,
+ * etc.
+ * @ctx:	Pointer to the current struct kernel_bt_ctx object.
+ * Returns:	KERNEL_BT_END_CTX_SWITCH The backtrace should stop because
+ *					the next frame is from user mode.
+ *		Zero			This is a good frame.
+ *		A negative errno value	The backtrace should stop because an
+ *					error has occurred.
+ */
+static int analyze_save_some_or_all_frame(struct kernel_bt_ctx *ctx)
+{
+	int		result = 0;	/* Assume success */
+	enum		{OLD_SP_IN_SP, OLD_SP_IN_K0, OLD_SP_ON_STACK} sp_loc;
+	mips_instruction	*ip;
+	mips_instruction	op;
+	struct base_bt	*bbt;
+	struct pt_regs *pt_regs;
+
+	bbt = &ctx->kbt->tbt.bbt;
+	pt_regs = (struct pt_regs *)ctx->kbt->tbt.bbt.sp;
+
+	/* First, loop until the old stack pointer gets stored on the
+	 * stack. No other registers get stored in the struct pt_regs
+	 * object on the stack until after the stack pointer gets
+	 * stored. */
+
+	for (ip = ctx->start, sp_loc = OLD_SP_IN_SP; ; ip += 1) {
+		/* If we reach the current execution point or we have stored
+		 * the old SP on the stack, we are done. */
+		if (ip == bbt->pc ||
+			sp_loc == OLD_SP_ON_STACK)
+			break;
+		result = bt_get_op(ip, &op);
+		if (result != 0)
+			break;
+
+		if (is_move(op, MREG_K0, MREG_SP))
+			sp_loc = OLD_SP_IN_K0;
+
+		else if (sp_loc == OLD_SP_IN_K0 &&
+			is_sw(op, MREG_K0, MREG_SP))
+			sp_loc = OLD_SP_ON_STACK;
+	}
+
+	switch (sp_loc) {
+	case OLD_SP_IN_SP:		/* Nothing to do */
+		bbt->frame_size = (char *)pt_regs->regs[MREG_SP] -
+			(char *)bbt->sp;
+		break;
+
+	case OLD_SP_IN_K0:
+
+		bbt->frame_size = (char *)pt_regs->regs[MREG_K0] -
+			(char *)bbt->sp;
+		break;
+
+	case OLD_SP_ON_STACK:
+		result = read_pt_regs_already_saved(ctx, ip,
+			(struct pt_regs *)bbt->sp);
+		break;
+
+	default:
+		result = -EINVAL;	/* Internal failure: shouldn't happen */
+		bt_dbg("Unexpected sp_loc value: %d\n", sp_loc);
+		break;
+	}
+
+	return result;
+}
+
+/*
+ * Loads the next register values for code that uses the SAVE_SOME macro.
+ * @ctx:	Pointer to the current struct kernel_bt_ctx object.
+ * Returns:	KERNEL_BT_END_CTX_SWITCH The backtrace should stop because the
+ *					next frame is from user mode.
+ *		Zero			This is a good frame.
+ *		A negative errno value	The backtrace should stop because an
+ *					error has occurred.
+ */
+static int analyze_save_some_frame(struct kernel_bt_ctx *ctx)
+{
+	return analyze_save_some_or_all_frame(ctx);
+}
+
+/*
+ * Loads the next register values for code that uses the SAVE_ALL macro. The
+ * SAVE_ALL macro starts by using the SAVE_SOME macro, then saves additional
+ * registers. We could simply have used analyze_save_some_or_all_frame directly,
+ * but this extra, tiny, function allows a more directly mapping from what
+ * appears in the kernel code to the way we break things down here.
+ * @ctx:	Pointer to the current struct kernel_bt_ctx object.
+ * Returns:	KERNEL_BT_END_CTX_SWITCH The backtrace should stop because the
+ *					next frame is from user mode.
+ *		Zero			This is a good frame.
+ *		A negative errno value	The backtrace should stop because an
+ *					error has occurred.
+ */
+static int analyze_save_all_frame(struct kernel_bt_ctx *ctx)
+{
+	return analyze_save_some_or_all_frame(ctx);
+}
+
+/*
+ * Loads the next register values for code that uses the SAVE_STATIC macro.
+ * @ctx:	Pointer to the current struct kernel_bt_ctx object.
+ * Returns:	KERNEL_BT_END_CTX_SWITCH The backtrace should stop because the
+ *					next frame is from user mode.
+ *		Zero			This is a good frame.
+ *		A negative errno value	The backtrace should stop because an
+ *					error has occurred.
+ */
+static int analyze_save_static_frame(struct kernel_bt_ctx *ctx)
+{
+	int rc;
+	struct pt_regs *regs;
+
+	regs = (struct pt_regs *)ctx->kbt->tbt.bbt.sp;
+
+	/* We must have already completed a SAVE_SOME macro in some previous
+	 * section of code, which has saved general purpose registers zero,
+	 * v0-v1, a0-a3, t9, gp, sp, and ra(r0, r2-r7, r25, r28, r29, r31),
+	 * and CP0 registers Cause, EPC, and Status. Only sp and gp of the
+	 * general purpose registers might take place in the backtrace,
+	 * but we do have to read some of the others.
+	 */
+	rc = read_pt_regs_sp_epc_status(ctx, regs);
+	if (rc != 0)
+		return rc;
+
+	rc = read_pt_regs_gpr_by_mreg(ctx, regs, MREG_GP);
+
+	/* Now read the registers which have been saved so far in this
+	 * section of code */
+	rc = read_pt_regs_already_saved(ctx, ctx->start, regs);
+
+	return rc;
+}
+
+/*
+ * Loads the next register values for glue code that is used after SAVE_SOME
+ * and SAVE_STATIC have been called and before RESTORE_SOME is called. This
+ * means that the values for the previous frame are all in a struct pt_regs
+ * object pointed to by $sp.
+ * @ctx:	Pointer to the current struct kernel_bt_ctx object.
+ * Returns:	KERNEL_BT_END_CTX_SWITCH The backtrace should stop because the
+ *					next frame is from user mode.
+ *		Zero			This is a good frame.
+ *		A negative errno value	The backtrace should stop because an
+ *					error has occurred.
+ */
+static int analyze_glue_frame(struct kernel_bt_ctx *ctx)
+{
+	int		result;
+
+	result = read_pt_regs_all_saved(ctx);
+
+	return result;
+}
+
+/*
+ * Loads the next register values for code that uses the RESTORE_SOME macro.
+ * Until we reach the eret instruction, the $sp register points to a struct
+ * pt_regs object from which the values can be fetched. When we get to the
+ * eret, all registers except $pc have been loaded and we get the next $pc
+ * value from the CP0_EPC register.
+ * @ctx:	Pointer to the current struct kernel_bt_ctx object.
+ * Returns:	KERNEL_BT_END_CTX_SWITCH The backtrace should stop because the
+ *					next frame is from user mode.
+ *		Zero			This is a good frame.
+ *		A negative errno value	The backtrace should stop because an
+ *					error has occurred.
+ */
+static int analyze_restore_some_frame(struct kernel_bt_ctx *ctx)
+{
+	int		result;
+	mips_instruction	op;
+
+	/* Check to see whether we got to the eret instruction. If
+	 * not, use the stack pointer to get to the save values.
+	 * Otherwise, use the ones we have. */
+	result = bt_get_op(ctx->start, &op);
+
+	if (result == 0) {
+		if (!is_eret(op))
+			result = read_pt_regs_all_saved(ctx);
+	}
+
+	return result;
+}
+
+/*
+ * analyze_special_frame - analyze frame when the PC is in non-C code
+ * @ctx:	Pointer to &struct kernel_bt_ctx.
+ *
+ * Returns 0 on success, a negative errno otherwise
+ */
+static int analyze_special_frame(struct kernel_bt_ctx *ctx)
+{
+	int	result;
+	struct thread_bt *tbt;
+
+	switch (ctx->kbt->type) {
+	case KERNEL_FRAME_THREAD:
+		tbt = &ctx->kbt->tbt;
+
+		/* Special case if we are in start_kernel. The space for
+		 * the function has been handed to the buddy allocator, so
+		 * we can't say anything about it. It's still useful to
+		 * return the frame, though, so we dummy things up so that
+		 * they shouldn't cause problems. */
+		if (in_start_kernel(tbt->bbt.pc)) {
+			bt_dbg("Passing back frame for start_kernel\n");
+			tbt->bbt.frame_size = 0;
+			tbt->bbt.ra = NULL;
+			result = 0;
+		} else {
+			result = __thread_backtrace_analyze_frame(tbt,
+				BASE_BACKTRACE_LOOKUP_FUNC);
+		}
+		break;
+
+	case KERNEL_FRAME_TLB_REFILL:
+	case KERNEL_FRAME_GENERAL_EXCEPTION:
+	case KERNEL_FRAME_K0_K1_ONLY:
+		result = analyze_k0_k1_only_frame(ctx);
+		break;
+
+	case KERNEL_FRAME_INTERRUPT:
+	case KERNEL_FRAME_SAVE_SOME:
+		result = analyze_save_some_frame(ctx);
+		break;
+
+	case KERNEL_FRAME_SAVE_STATIC:
+		result = analyze_save_static_frame(ctx);
+		break;
+
+	case KERNEL_FRAME_SAVE_ALL:
+		result = analyze_save_all_frame(ctx);
+		break;
+
+	case KERNEL_FRAME_GLUE:
+		result = analyze_glue_frame(ctx);
+		break;
+
+	case KERNEL_FRAME_RESTORE_SOME:
+		result = analyze_restore_some_frame(ctx);
+		break;
+
+	case KERNEL_FRAME_UNEXPECTED:
+		result = -ENOSYS;
+		break;
+
+	default:
+		result = -EINVAL;	/* Internal failure: Shouldn't happen */
+		bt_dbg("Unexpected frame type: %d\n", ctx->kbt->type);
+		break;
+	}
+
+	return result;
+}
+
+static int analyze_unexpected_frame(struct kernel_bt_ctx *ctx)
+{
+	return 0;
+}
+
+/*
+ * This determines the type of the current frame. This is done by looking at
+ * the $pc register and seeing whether it is in some sort of interrupt or
+ * exception frame. If not, it passes the analysis on to the thread_backtrace
+ * code.
+ * @kbt:	Pointer to a struct kernel_bt_ctx object.
+ * Returns zero if it was able to determine the frame type, or a negative
+ *		errno value if an error occurred during processing.
+ */
+int __kernel_backtrace_analyze_frame(struct kernel_bt *kbt)
+{
+	int			result = 0;	/* Assume success */
+	mips_instruction *pc;
+	const struct kern_special_sym	*symbol;
+	struct kernel_bt_ctx ctx;
+
+	ctx.kbt = kbt;
+
+	kbt->tbt.bbt.frame_size = 0;
+	pc = kbt->tbt.bbt.pc;
+	kbt->tbt.bbt.fp = kbt->tbt.bbt.sp;	/* Default frame pointer */
+
+	/* Fake values for start_kernel() */
+	if (in_start_kernel(pc)) {
+		kbt->tbt.bbt.frame_size = 0;
+		kbt->tbt.bbt.ra = 0;
+		return 0;
+	}
+
+	/* Check to see if we came from user mode */
+	if ((kbt->cp0_status & ST0_CU0) == 0) {
+		bt_dbg("Terminate backtrace because exception was in user "
+			"code\n");
+		return KERNEL_BT_END_CTX_SWITCH;
+	}
+
+	/* The kernel is kind enough to arrange things so that the return
+	 * address is NULL if we have reached the end of a kernel stack, so
+	 * if we see that case, we are done. */
+	if (pc == NULL)
+		result = KERNEL_BT_END_NULL_PC;
+
+	else {
+		symbol = special_symbol(pc, &ctx.start, &ctx.size);
+
+		if (symbol != NULL) {
+			ctx.kbt->type = symbol->type;
+			result = analyze_special_frame(&ctx);
+		}
+
+		else if (in_exception_vector(pc, TLB_REFILL_OFFSET,
+			TLB_REFILL_SIZE)) {
+			ctx.kbt->type = KERNEL_FRAME_TLB_REFILL;
+			ctx.start = (mips_instruction *)(ebase +
+				TLB_REFILL_OFFSET);
+			ctx.size = TLB_REFILL_SIZE;
+			result = analyze_k0_k1_only_frame(&ctx);
+		}
+
+		else if (in_exception_vector(pc, GEN_EX_OFFSET, GEN_EX_SIZE)) {
+			ctx.kbt->type = KERNEL_FRAME_GENERAL_EXCEPTION;
+			ctx.start = (mips_instruction *)(ebase + GEN_EX_OFFSET);
+			ctx.size = GEN_EX_SIZE;
+			result = analyze_k0_k1_only_frame(&ctx);
+		}
+
+		else if (in_exception_vector(pc, INTERRUPT_OFFSET,
+			INTERRUPT_SIZE)) {
+			unsigned	offset, irq, spacing;
+			ctx.kbt->type = KERNEL_FRAME_INTERRUPT;
+
+			/* Since we are using the exception vector for handling
+			 * interrupts, i.e. the CP0 Config3 register has VEIC
+			 * or VI set and the CP0 Cause register has the IV bit
+			 * set, we subtract ebase + INTERRUPT_OFFSET from $pc
+			 * to get the offset into the interrupt vector portion.
+			 * We divide this by the space of the interrupt vector
+			 * entries to get the interrupt number. Then the start
+			 * of the entry for this interrupt is computed by
+			 * multiplying the interrupt number by the spacing and
+			 * adding ebase and INTERRUPT_OFFSET back in. The size
+			 * of the entry is given by the spacing of the
+			 * interrupt vector entries. */
+			spacing = vectorspacing();
+			offset = (unsigned long)pc - (ebase + INTERRUPT_OFFSET);
+			irq = offset / spacing;
+			ctx.start = (mips_instruction *)(ebase +
+				INTERRUPT_OFFSET + irq * spacing);
+			ctx.size = spacing;
+			result = analyze_save_some_frame(&ctx);
+		}
+
+		else if (in_exception_vector(pc, UNEXPECTED_OFFSET,
+			UNEXPECTED_SIZE)) {
+			ctx.kbt->type = KERNEL_FRAME_UNEXPECTED;
+			ctx.start = (mips_instruction *)(ebase +
+				UNEXPECTED_OFFSET);
+			ctx.size = UNEXPECTED_SIZE;
+			result = analyze_unexpected_frame(&ctx);
+		}
+
+		else {
+			result = __thread_backtrace_analyze_frame(&ctx.kbt->tbt,
+				BASE_BACKTRACE_LOOKUP_FUNC);
+			ctx.kbt->type = KERNEL_FRAME_THREAD;
+		}
+	}
+
+	return result;
+}
+EXPORT_SYMBOL(__kernel_backtrace_analyze_frame);
+
+/*
+ * Use kallsyms_lookup to find the symbol corresponding to a given address.
+ * All we care about for backtracing is where the section of code starts
+ * and the number of bytes in it.
+ * @ip:		Address for which to find the symbol
+ * @start:	Pointer to location in which to store the starting
+ *		address for the symbol.
+ * @size:	Pointer to location in which to store the size of the
+ *		symbol.
+ *
+ * Returns zero on success, otherwise a negative errno value.
+ */
+int bt_symbol_lookup(mips_instruction *ip, mips_instruction **start,
+	unsigned long *size)
+{
+	int		result;
+	const char	*symname;
+	unsigned long	symbolsize;
+	unsigned long	offset;
+	char		*modname;
+	char		namebuf[KSYM_NAME_LEN + 1];
+
+	symname = kallsyms_lookup((unsigned long)ip, &symbolsize,
+		&offset, &modname, namebuf);
+
+	/* Perhaps, if we couldn't find the symbol, it is a two-instruction
+	 * signal trampoline. It won't hurt to pretend because everything
+	 * validates that the address from which it fetches instructions. */
+	if (symname == NULL) {
+		result = 0;
+		*start = ip;
+		*size = 2 * sizeof(mips_instruction);
+	}
+
+	else {
+		result = 0;
+		*start = (mips_instruction *)((char *)ip - offset);
+		*size = symbolsize;
+	}
+
+	return result;
+}
+
+/*
+ * Read an opcode-sized piece of data.
+ * @ip:	Address from which to read the opcode
+ * @op:	Location in which to store the opcode once it has
+ *	been read.
+ * Returns zero on success, a negative errno value otherwise.
+ */
+int bt_get_op(mips_instruction *ip, mips_instruction *op)
+{
+	int		result;
+
+	result = __get_user(*op, (mips_instruction *)ip);
+
+	return result;
+}
+
+/*
+ * Read an general purpose register-sized piece of data.
+ * @rp:		Address from which to read the data
+ * @reg:	Location in which to store the value once it has
+ *		been read.
+ * Returns zero on success, a negative errno value otherwise.
+ */
+int bt_get_reg(unsigned long *rp, unsigned long *reg)
+{
+	int		result;
+
+	result = __get_user(*reg, rp);
+	return result;
+}
+
+/*
+ * Read an piece of data as big as is used in the struct sigcontext registers.
+ * @rp:		Address from which to read the data
+ * @reg:	Location in which to store the value once it has
+ *		been read.
+ * Returns zero on success, a negative errno value otherwise.
+ */
+int bt_get_sc_reg(unsigned long long *rp, unsigned long *reg)
+{
+	int			result;
+	unsigned long long	sc_reg;
+
+	result = __get_user(sc_reg, rp);
+
+	if (result == 0)
+		*reg = sc_reg;
+
+	return result;
+}
+
+
+/*
+ * Advances to the next frame based on the analysis of the current frame
+ * done by kernel_backtrace_analyze_frame().
+ * @ctx:	Pointer to struct struct kernel_bt_ctx object.
+ * Returns:	KERNEL_BT_END_CTX_SWITCH The backtrace should stop because the
+ *					next frame is from user mode.
+ *		Zero			This is a good frame.
+ *		A negative errno value	The backtrace should stop because an
+ *					error has occurred.
+ */
+int kernel_backtrace_pop_frame(struct kernel_bt *kbt)
+{
+	int rc;
+
+	if (kbt->type == KERNEL_FRAME_THREAD) {
+		rc = thread_backtrace_pop_frame(&kbt->tbt);
+	} else {
+		struct pt_regs *regs;
+		struct base_bt *bbt;
+
+		bbt = &kbt->tbt.bbt;
+		regs = (struct pt_regs *)bbt->sp;
+
+		bbt->pc = (mips_instruction *)regs->cp0_epc;
+		bbt->ra = (mips_instruction *)regs->regs[MREG_RA];
+		bbt->sp = (unsigned long *)regs->regs[MREG_SP];
+
+		rc = 0;
+	}
+
+	return rc;
+}
+
+/*
+ * This handles getting the next kernel stackframe. It checks to see if we are
+ * in an exception or interrupt frame. If not, we just pass it along to the
+ * process backtracing.
+ * @kbt:	Pointer to the struct kernel_bt object
+ *
+ * Returns:	KERNEL_BT_END_IN_START_KERNEL The backtrace should stop
+ *					because the next frame is for
+ *					start_kernel(), whose memory has
+ *					probably been freed and overwritten.
+ *		Zero			This is a good frame.
+ *		A negative errno value	The backtrace should stop because an
+ *					error has occurred.
+ */
+int kernel_backtrace_next(struct kernel_bt *kbt)
+{
+	int	rc;
+
+	/*
+	 * If we're about to go off to start_kernel(), stop. The
+	 * address space for the start_kernel() code was released to
+	 * the buddy allocator and there is no telling what that address
+	 * space might hold.
+	 */
+	if (in_start_kernel(kbt->tbt.bbt.pc)) {
+		bt_dbg("Terminating backtrace because of entering "
+			"start_kernel()\n");
+		return KERNEL_BT_END_IN_START_KERNEL;
+	}
+
+	rc = kernel_backtrace_pop_frame(kbt);
+
+	if (rc == 0)
+		rc = __kernel_backtrace_analyze_frame(kbt);
+
+	return rc;
+}
+EXPORT_SYMBOL(kernel_backtrace_next);
+
+/*
+ * __kernel_backtrace_set_from_pt_regs - set values from struct pt_regs
+ * @bt:		Pointer to the &struct kernel_bt
+ * @regs:	Pointer to the register values to start with
+ */
+void __kernel_backtrace_set_from_pt_regs(struct kernel_bt *kbt,
+	 const struct pt_regs *regs)
+{
+	memset(kbt, 0, sizeof(*kbt));
+	__thread_backtrace_set_from_pt_regs(&kbt->tbt, regs);
+	kbt->cp0_status = regs->cp0_status;
+	kbt->cp0_epc = (mips_instruction *)regs->cp0_epc;
+}
+EXPORT_SYMBOL(__kernel_backtrace_set_from_pt_regs);
+
+/*
+ * kernel_backtrace_first_from_pt_regs - backtrace trace from pt_regs object
+ * @regs:	Pointer to a struct pt_regs object with the initial
+ *		register values to be used for the backtrace
+ * @process:	Function that processes a stack frame
+ * @arg:	Argument passed to the function that processes a
+ *		stack frame
+ *
+ * Returns zero on success, otherwise a negative errno value.
+ */
+int kernel_backtrace_first_from_pt_regs(struct kernel_bt *kbt,
+	const struct pt_regs *regs)
+{
+	int rc;
+
+	__kernel_backtrace_set_from_pt_regs(kbt, regs);
+	rc = __kernel_backtrace_analyze_frame(kbt);
+
+	return rc;
+}
+EXPORT_SYMBOL(kernel_backtrace_first_from_pt_regs);
diff --git a/arch/mips/lib/thread-backtrace.c b/arch/mips/lib/thread-backtrace.c
new file mode 100644
index 0000000..a9eb2e7
--- /dev/null
+++ b/arch/mips/lib/thread-backtrace.c
@@ -0,0 +1,289 @@
+/*
+ *			thread-backtrace.c
+ *
+ * Performs Linux-dependent MIPS processor stack backtracing for processes. It
+ * builds on the MIPS processor ABI-conformant stack backtracing code, but
+ * does the OS-dependent portions that handle signal frames, too. This allows
+ * it to do multi-frame backtracing.
+ *
+ * Copyright(C) 2007  Scientific-Atlanta, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Author: David VomLehn
+ */
+
+#include <asm/thread-backtrace.h>
+#include <asm/sigframe.h>
+
+/*
+ * thread_bt_ctx - info used only while analyzing a single frame
+ * @tbt:			Pointer to the thread_bt structure
+ */
+struct thread_bt_ctx {
+	struct thread_bt	*tbt;
+	enum base_bt_rule	rule;
+};
+
+/*
+ * is_syscall - determine whether op code is a syscall instruction
+ * @inst:	Instruction to check
+ *
+ * Returns true if @inst is a syscall, false otherwise.
+ */
+static inline int is_syscall(mips_instruction inst)
+{
+	struct syscall_format *op_p = (struct syscall_format *) &inst;
+	return op_p->opcode == spec_op &&
+		op_p->func == syscall_op;
+}
+
+/*
+ * analyze_non_signal_frame - analyze an ordinary signal frame
+ * @ctx:	Pointer to the &struct thread_bt_ctx for this frame
+ *
+ * Returns zero on success, otherwise a negative errno value.  Mostly this
+ * consists of handling the work of to the base backtrace code.
+ */
+static int analyze_non_signal_frame(struct thread_bt_ctx *ctx)
+{
+	ctx->tbt->type = THREAD_FRAME_BASE;
+	return __base_backtrace_analyze_frame(&ctx->tbt->bbt, ctx->rule);
+}
+
+/*
+ * analyze_signal_frame - complete analyze of a stack from from a signal
+ * @ctx:		Pointer to the &struct thread_bt_ctx
+ * @type:		Type of the frame
+ * @sc:			Pointer to the &struct sigcontext on the stack
+ * @sigframe_offset	Number of bytes between the address indicated by
+ *			the stack pointer and the arguments to the
+ *			signal handler
+ *
+ * Returns zero on success or a negative errno value.
+ */
+static int analyze_signal_frame(struct thread_bt_ctx *ctx,
+	enum thread_frame_type type, struct sigcontext *sc,
+	unsigned long sigargs_offset)
+{
+	struct base_bt *bbt;
+	unsigned long *next_sp;
+	unsigned long reg;
+	int rc;
+	int i;
+
+	bbt = &ctx->tbt->bbt;
+
+	for (i = 0; i < ARRAY_SIZE(sc->sc_regs); i++) {
+		if (save_before_use[i]) {
+			enum saved_gpr_num sreg;
+
+			sreg = mreg_to_sreg[i];
+			rc = bt_get_sc_reg(&sc->sc_regs[i], &reg);
+			if (rc != 0)
+				return rc;
+			bbt->gprs[sreg].value = reg;
+			bbt->gprs[sreg].read = true;
+		}
+	}
+
+	ctx->tbt->type = type;
+
+	rc = bt_get_sc_reg(&sc->sc_regs[MREG_SP], &reg);
+	if (rc != 0)
+		return rc;
+
+	next_sp = (unsigned long *)reg;
+	bbt->frame_size = (char *)next_sp - (char *)bbt->fp;
+	ctx->tbt->sigargs = (unsigned long *)((char *)ctx->tbt->bbt.sp +
+		sigargs_offset);
+
+	bbt->next_pc = (mips_instruction *)(unsigned long)sc->sc_pc;
+
+	return 0;
+}
+
+/*
+ * __thread_backtrace_analyze_frame - handles possible signal frame
+ * @tbt:	Pointer to backtrace register and other information.
+ * @rule:	Parsing rule to use
+ *
+ * Returns zero if we were able to determine whether we were in a
+ *		signal trampoline and a negative errno value if not.
+ *
+ * Analyzes the current stack frame to see whether we are executing in a
+ * signal trampoline. To do this, we look at the instructions at the
+ * return address. If we have a load of $v0 with one of a few special values,
+ * followed by a syscall, this frame is actually for a signal trampoline.
+ */
+int __thread_backtrace_analyze_frame(struct thread_bt *tbt,
+	enum base_bt_rule rule)
+{
+	int rc;
+	mips_instruction op1, op2;
+	mips_instruction *pc;
+	struct thread_bt_ctx ctx;
+
+	/* Start by trying to read two instructions since that's how long the
+	 * signal trampoline is. */
+	ctx.tbt = tbt;
+	ctx.rule = rule;
+
+	pc = tbt->bbt.pc;
+	rc = bt_get_op(pc, &op1);
+
+	if (rc == 0)
+		rc = bt_get_op(pc + 1, &op2);
+
+	if (rc == 0) {
+		struct base_bt *bbt;
+
+		bbt = &ctx.tbt->bbt;
+
+		/* If we could read the instructions, check to see whether
+		 * they are the right ones for the signal trampoline. */
+		if (!is_li(op1, MREG_V0) || !is_syscall(op2)) {
+			rc = analyze_non_signal_frame(&ctx);
+		} else {
+			unsigned long sigargs_offset;
+
+			/*
+			 * We do have an 'li v0,<value>' followed by a
+			 * syscall. Is the system call we are doing one that
+			 * is involved with signal return processing?
+			 */
+
+			switch (((struct u_format *)&op1)->uimmediate) {
+			case __NR_O32_sigreturn:
+				sigargs_offset = offsetof(struct sigframe,
+					sf_ass);
+				rc = analyze_signal_frame(&ctx,
+					THREAD_FRAME_SIGNAL,
+					&((struct sigframe *)bbt->sp)->sf_sc,
+					sigargs_offset);
+				break;
+
+			case __NR_O32_rt_sigreturn:
+				sigargs_offset = offsetof(struct rt_sigframe,
+					rs_ass);
+				rc = analyze_signal_frame(&ctx,
+					THREAD_FRAME_RT_SIGNAL,
+					&((struct rt_sigframe *)bbt->sp)->
+						rs_uc.uc_mcontext,
+					sigargs_offset);
+				break;
+
+			default:
+				/* Some other type of system call */
+				rc = analyze_non_signal_frame(&ctx);
+				break;
+			}
+		}
+	}
+
+	return rc;
+}
+EXPORT_SYMBOL(__thread_backtrace_analyze_frame);
+
+/*
+ * pop_signal_frame - advance to the next frame after a signal frame
+ */
+static int pop_signal_frame(struct thread_bt *tbt)
+{
+	int rc;
+
+	rc = base_backtrace_pop_frame(&tbt->bbt);
+
+	return rc;
+}
+
+/*
+ * thread_backtrace_pop_frame - Advances to the next stack frame.
+ * @tbt:	Pointer to a struct thread_bt object.
+ * Returns zero on success and a negative errno on failure.
+ */
+int thread_backtrace_pop_frame(struct thread_bt *tbt)
+{
+	int	result;
+
+	switch (tbt->type) {
+	case THREAD_FRAME_BASE:
+		result = base_backtrace_pop_frame(&tbt->bbt);
+		break;
+
+	case THREAD_FRAME_SIGNAL:
+	case THREAD_FRAME_RT_SIGNAL:
+		result = pop_signal_frame(tbt);
+		break;
+
+	default:
+		result = -EINVAL;	/* Internal failure: shouldn't happen */
+		bt_dbg("Unexpected frame type: %d\n", tbt->type);
+		break;
+	}
+
+	return result;
+}
+
+/*
+ * Handle one stack backtrace frame, updating the register according to what
+ * is found.
+ * @tbt:	Pointer to register and backtrace information.
+ * Returns aero on success, a negative errno otherwise.
+ */
+int thread_backtrace_next(struct thread_bt *tbt, enum base_bt_rule rule)
+{
+	int		result;
+
+	result = thread_backtrace_pop_frame(tbt);
+
+	if (result == 0)
+		result = __thread_backtrace_analyze_frame(tbt, rule);
+
+	return result;
+}
+EXPORT_SYMBOL(thread_backtrace_next);
+
+/*
+ * __thread_backtrace_set_from_pt_regs - set values from struct pt_regs
+ * @bt:		Pointer to the &struct thread_bt
+ * @regs:	Pointer to the register values to start with
+ */
+void __thread_backtrace_set_from_pt_regs(struct thread_bt *tbt,
+	 const struct pt_regs *regs)
+{
+	memset(tbt, 0, sizeof(*tbt));
+	__base_backtrace_set_from_pt_regs(&tbt->bbt, regs);
+}
+EXPORT_SYMBOL(__thread_backtrace_set_from_pt_regs);
+
+/*
+ * thread_backtrace_first_from_pt_regs - backtrace starting with struct pt_regs
+ * @bt:		Pointer to the &struct thread_bt
+ * @rule:	Rules to use for the backtrace
+ * @regs:	Pointer to the register values to start with
+ */
+int thread_backtrace_first_from_pt_regs(struct thread_bt *tbt,
+	enum base_bt_rule rule, const struct pt_regs *regs)
+{
+	int rc;
+
+	memset(tbt, 0, sizeof(*tbt));
+	__thread_backtrace_set_from_pt_regs(tbt, regs);
+	rc = __thread_backtrace_analyze_frame(tbt, rule);
+
+	return rc;
+}
+EXPORT_SYMBOL(thread_backtrace_first_from_pt_regs);
diff --git a/scripts/module-common.lds b/scripts/module-common.lds
deleted file mode 100644
index 0865b3e..0000000
--- a/scripts/module-common.lds
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Common module linker script, always used when linking a module.
- * Archs are free to supply their own linker scripts.  ld will
- * combine them automatically.
- */
-SECTIONS {
-	/DISCARD/ : { *(.discard) }
-
-	__ksymtab		: { *(SORT(___ksymtab+*)) }
-	__ksymtab_gpl		: { *(SORT(___ksymtab_gpl+*)) }
-	__ksymtab_unused	: { *(SORT(___ksymtab_unused+*)) }
-	__ksymtab_unused_gpl	: { *(SORT(___ksymtab_unused_gpl+*)) }
-	__ksymtab_gpl_future	: { *(SORT(___ksymtab_gpl_future+*)) }
-	__kcrctab		: { *(SORT(___kcrctab+*)) }
-	__kcrctab_gpl		: { *(SORT(___kcrctab_gpl+*)) }
-	__kcrctab_unused	: { *(SORT(___kcrctab_unused+*)) }
-	__kcrctab_unused_gpl	: { *(SORT(___kcrctab_unused_gpl+*)) }
-	__kcrctab_gpl_future	: { *(SORT(___kcrctab_gpl_future+*)) }
-}

From manuel.lauss@googlemail.com Fri Jul  8 11:18:52 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 08 Jul 2011 11:18:59 +0200 (CEST)
Received: from mail-fx0-f49.google.com ([209.85.161.49]:35603 "EHLO
        mail-fx0-f49.google.com" rhost-flags-OK-OK-OK-OK)
        by eddie.linux-mips.org with ESMTP id S1491144Ab1GHJSw (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Fri, 8 Jul 2011 11:18:52 +0200
Received: by fxd20 with SMTP id 20so1399533fxd.36
        for <multiple recipients>; Fri, 08 Jul 2011 02:18:47 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=googlemail.com; s=gamma;
        h=from:to:cc:subject:date:message-id:x-mailer;
        bh=WZvublSYLPiRlnCcZWhnnSced3gVTAFwfxq4YVzQqLo=;
        b=O5cxLEOaFTwSOih/drl0sTlh7ZNDGYRzr56CoLKAMfVI4bb7KQP9xjm3TffZhwNCMW
         9wgN05PBXDLwsVvSrSuTYmlkk/LIkkz1ni9X0Z66tmzBZzGgrxy/gCL0/a2lYm0HV17z
         CKxc2nJiH4RN1KfFOSJx5h2W2lZW0po7jorPs=
Received: by 10.223.75.138 with SMTP id y10mr2768895faj.36.1310116726932;
        Fri, 08 Jul 2011 02:18:46 -0700 (PDT)
Received: from localhost.localdomain (188-22-147-55.adsl.highway.telekom.at [188.22.147.55])
        by mx.google.com with ESMTPS id k26sm7260413fak.24.2011.07.08.02.18.45
        (version=TLSv1/SSLv3 cipher=OTHER);
        Fri, 08 Jul 2011 02:18:45 -0700 (PDT)
From:   Manuel Lauss <manuel.lauss@googlemail.com>
To:     Linux-MIPS <linux-mips@linux-mips.org>,
        Ralf Baechle <ralf@linux-mips.org>
Cc:     Manuel Lauss <manuel.lauss@googlemail.com>
Subject: [PATCH 0/5] MIPS: Alchemy: misc updates
Date:   Fri,  8 Jul 2011 11:18:38 +0200
Message-Id: <1310116723-8632-1-git-send-email-manuel.lauss@googlemail.com>
X-Mailer: git-send-email 1.7.6
X-archive-position: 30587
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: manuel.lauss@googlemail.com
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 5978
Content-Length: 2388
Lines: 51

[This is a resend of previous patches grouped together]

Misc. updates to various Alchemy parts:
#1: remove hardcoded MAC DMA base from the driver and pass it via
    platform resource information instead.
#2: include the Au1100 in au1000 suspend code
#3: centralize USB block control, to simplify the glues and as a
    preparatory step for Au1300 USB support
#4: do usb setup based on runtime cpu type detection, to get rid of
    a few per-subtype #defines.
#5: with USB out of the way, the rest of the per-subtype peripheral
    base addresses can be removed in favour of a single list.

All run-tested (except 1 and 2 due to lack of hardware) on
DB1200 and DB1300.
Please consider for 3.1.

Manuel Lauss (5):
  net: au1000_eth: pass MACDMA address through platform resource info.
  MIPS: Alchemy: include Au1100 in PM code.
  MIPS: Alchemy: abstract USB block control register access
  MIPS: Alchemy: rewrite USB platform setup.
  MIPS: Alchemy: more base address cleanup

 arch/mips/alchemy/common/Makefile              |    2 +-
 arch/mips/alchemy/common/dma.c                 |   12 +-
 arch/mips/alchemy/common/platform.c            |  225 +++++++---------
 arch/mips/alchemy/common/power.c               |   64 +----
 arch/mips/alchemy/common/usb.c                 |  337 ++++++++++++++++++++++++
 arch/mips/alchemy/devboards/db1200/platform.c  |   52 ++--
 arch/mips/alchemy/devboards/db1x00/platform.c  |   40 ++--
 arch/mips/alchemy/devboards/pb1100/platform.c  |   20 +-
 arch/mips/alchemy/devboards/pb1200/platform.c  |   42 ++--
 arch/mips/alchemy/devboards/pb1500/platform.c  |   22 +-
 arch/mips/alchemy/devboards/pb1550/platform.c  |   40 ++--
 arch/mips/alchemy/xxs1500/platform.c           |   12 +-
 arch/mips/include/asm/mach-au1x00/au1000.h     |  242 +++--------------
 arch/mips/include/asm/mach-au1x00/au1xxx_psc.h |   26 --
 arch/mips/include/asm/mach-db1x00/db1x00.h     |    8 +-
 arch/mips/include/asm/mach-pb1x00/pb1200.h     |    8 +-
 arch/mips/include/asm/mach-pb1x00/pb1550.h     |    8 +-
 drivers/net/au1000_eth.c                       |   48 +++-
 drivers/net/au1000_eth.h                       |    2 +-
 drivers/usb/host/ehci-au1xxx.c                 |   77 +-----
 drivers/usb/host/ohci-au1xxx.c                 |  110 +-------
 21 files changed, 675 insertions(+), 722 deletions(-)
 create mode 100644 arch/mips/alchemy/common/usb.c

-- 
1.7.6


From manuel.lauss@googlemail.com Fri Jul  8 11:18:53 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 08 Jul 2011 11:19:27 +0200 (CEST)
Received: from mail-fx0-f49.google.com ([209.85.161.49]:35603 "EHLO
        mail-fx0-f49.google.com" rhost-flags-OK-OK-OK-OK)
        by eddie.linux-mips.org with ESMTP id S1491763Ab1GHJSx (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Fri, 8 Jul 2011 11:18:53 +0200
Received: by mail-fx0-f49.google.com with SMTP id 20so1399533fxd.36
        for <multiple recipients>; Fri, 08 Jul 2011 02:18:53 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=googlemail.com; s=gamma;
        h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references;
        bh=ZYDblBIKgE+tpt/FjZn4CzFMPJrN5k1wXvTYeDJHEnU=;
        b=QudWau+Go/5xfWbjp6n0UG2iAvuYPm2+GGklyPneKc3kPQkqgQ1Ag6S5vivf5Kizoz
         54hSa32Zmyos5sdP/PJ1vow35xZVNXmiDZ/qmNku6Um/74IgEv68YrFgWsWD7Mq0eLav
         lvWb3j8njXbs8md0sIMHz7kyRSgSE4Cp9aWCQ=
Received: by 10.223.13.10 with SMTP id z10mr2748280faz.69.1310116732996;
        Fri, 08 Jul 2011 02:18:52 -0700 (PDT)
Received: from localhost.localdomain (188-22-147-55.adsl.highway.telekom.at [188.22.147.55])
        by mx.google.com with ESMTPS id k26sm7260413fak.24.2011.07.08.02.18.51
        (version=TLSv1/SSLv3 cipher=OTHER);
        Fri, 08 Jul 2011 02:18:52 -0700 (PDT)
From:   Manuel Lauss <manuel.lauss@googlemail.com>
To:     Linux-MIPS <linux-mips@linux-mips.org>,
        Ralf Baechle <ralf@linux-mips.org>
Cc:     Manuel Lauss <manuel.lauss@googlemail.com>
Subject: [PATCH 4/5] MIPS: Alchemy: rewrite USB platform setup.
Date:   Fri,  8 Jul 2011 11:18:42 +0200
Message-Id: <1310116723-8632-5-git-send-email-manuel.lauss@googlemail.com>
X-Mailer: git-send-email 1.7.6
In-Reply-To: <1310116723-8632-1-git-send-email-manuel.lauss@googlemail.com>
References: <1310116723-8632-1-git-send-email-manuel.lauss@googlemail.com>
X-archive-position: 30588
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: manuel.lauss@googlemail.com
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 5979
Content-Length: 8670
Lines: 310

Use runtime CPU detection to setup all USB parts.
Remove the Au1200 OTG and UDC platform devices since there are no
drivers for them anyway.
Clean up the USB address mess in the au1000 header.

Signed-off-by: Manuel Lauss <manuel.lauss@googlemail.com>
---
 arch/mips/alchemy/common/platform.c        |  183 +++++++++++----------------
 arch/mips/include/asm/mach-au1x00/au1000.h |   55 ---------
 2 files changed, 75 insertions(+), 163 deletions(-)

diff --git a/arch/mips/alchemy/common/platform.c b/arch/mips/alchemy/common/platform.c
index 7400c93..e92a464 100644
--- a/arch/mips/alchemy/common/platform.c
+++ b/arch/mips/alchemy/common/platform.c
@@ -111,34 +111,84 @@ static void __init alchemy_setup_uarts(int ctype)
 		printk(KERN_INFO "Alchemy: failed to register UARTs\n");
 }
 
-/* OHCI (USB full speed host controller) */
-static struct resource au1xxx_usb_ohci_resources[] = {
-	[0] = {
-		.start		= USB_OHCI_BASE,
-		.end		= USB_OHCI_BASE + USB_OHCI_LEN - 1,
-		.flags		= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start		= FOR_PLATFORM_C_USB_HOST_INT,
-		.end		= FOR_PLATFORM_C_USB_HOST_INT,
-		.flags		= IORESOURCE_IRQ,
-	},
-};
 
-/* The dmamask must be set for OHCI to work */
-static u64 ohci_dmamask = DMA_BIT_MASK(32);
+/* The dmamask must be set for OHCI/EHCI to work */
+static u64 alchemy_ohci_dmamask = DMA_BIT_MASK(32);
+static u64 __maybe_unused alchemy_ehci_dmamask = DMA_BIT_MASK(32);
 
-static struct platform_device au1xxx_usb_ohci_device = {
-	.name		= "au1xxx-ohci",
-	.id		= 0,
-	.dev = {
-		.dma_mask		= &ohci_dmamask,
-		.coherent_dma_mask	= DMA_BIT_MASK(32),
-	},
-	.num_resources	= ARRAY_SIZE(au1xxx_usb_ohci_resources),
-	.resource	= au1xxx_usb_ohci_resources,
+static unsigned long alchemy_ohci_data[][2] __initdata = {
+	[ALCHEMY_CPU_AU1000] = { AU1000_USB_OHCI_PHYS_ADDR, AU1000_USB_HOST_INT },
+	[ALCHEMY_CPU_AU1500] = { AU1000_USB_OHCI_PHYS_ADDR, AU1500_USB_HOST_INT },
+	[ALCHEMY_CPU_AU1100] = { AU1000_USB_OHCI_PHYS_ADDR, AU1100_USB_HOST_INT },
+	[ALCHEMY_CPU_AU1550] = { AU1550_USB_OHCI_PHYS_ADDR, AU1550_USB_HOST_INT },
+	[ALCHEMY_CPU_AU1200] = { AU1200_USB_OHCI_PHYS_ADDR, AU1200_USB_INT },
+};
+
+static unsigned long alchemy_ehci_data[][2] __initdata = {
+	[ALCHEMY_CPU_AU1200] = { AU1200_USB_EHCI_PHYS_ADDR, AU1200_USB_INT },
 };
 
+static int __init _new_usbres(struct resource **r, struct platform_device **d)
+{
+	*r = kzalloc(sizeof(struct resource) * 2, GFP_KERNEL);
+	if (!*r)
+		return -ENOMEM;
+	*d = kzalloc(sizeof(struct platform_device), GFP_KERNEL);
+	if (!*d) {
+		kfree(*r);
+		return -ENOMEM;
+	}
+
+	(*d)->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+	(*d)->num_resources = 2;
+	(*d)->resource = *r;
+
+	return 0;
+}
+
+static void __init alchemy_setup_usb(int ctype)
+{
+	struct resource *res;
+	struct platform_device *pdev;
+
+	/* setup OHCI0.  Every variant has one */
+	if (_new_usbres(&res, &pdev))
+		return;
+
+	res[0].start = alchemy_ohci_data[ctype][0];
+	res[0].end = res[0].start + 0x100 - 1;
+	res[0].flags = IORESOURCE_MEM;
+	res[1].start = alchemy_ohci_data[ctype][1];
+	res[1].end = res[1].start;
+	res[1].flags = IORESOURCE_IRQ;
+	pdev->name = "au1xxx-ohci";
+	pdev->id = 0;
+	pdev->dev.dma_mask = &alchemy_ohci_dmamask;
+
+	if (platform_device_register(pdev))
+		printk(KERN_INFO "Alchemy USB: cannot add OHCI0\n");
+
+
+	/* setup EHCI0: Au1200 */
+	if (ctype == ALCHEMY_CPU_AU1200) {
+		if (_new_usbres(&res, &pdev))
+			return;
+
+		res[0].start = alchemy_ehci_data[ctype][0];
+		res[0].end = res[0].start + 0x100 - 1;
+		res[0].flags = IORESOURCE_MEM;
+		res[1].start = alchemy_ehci_data[ctype][1];
+		res[1].end = res[1].start;
+		res[1].flags = IORESOURCE_IRQ;
+		pdev->name = "au1xxx-ehci";
+		pdev->id = 0;
+		pdev->dev.dma_mask = &alchemy_ehci_dmamask;
+
+		if (platform_device_register(pdev))
+			printk(KERN_INFO "Alchemy USB: cannot add EHCI0\n");
+	}
+}
+
 /*** AU1100 LCD controller ***/
 
 #ifdef CONFIG_FB_AU1100
@@ -170,86 +220,6 @@ static struct platform_device au1100_lcd_device = {
 #endif
 
 #ifdef CONFIG_SOC_AU1200
-/* EHCI (USB high speed host controller) */
-static struct resource au1xxx_usb_ehci_resources[] = {
-	[0] = {
-		.start		= USB_EHCI_BASE,
-		.end		= USB_EHCI_BASE + USB_EHCI_LEN - 1,
-		.flags		= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start		= AU1200_USB_INT,
-		.end		= AU1200_USB_INT,
-		.flags		= IORESOURCE_IRQ,
-	},
-};
-
-static u64 ehci_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device au1xxx_usb_ehci_device = {
-	.name		= "au1xxx-ehci",
-	.id		= 0,
-	.dev = {
-		.dma_mask		= &ehci_dmamask,
-		.coherent_dma_mask	= DMA_BIT_MASK(32),
-	},
-	.num_resources	= ARRAY_SIZE(au1xxx_usb_ehci_resources),
-	.resource	= au1xxx_usb_ehci_resources,
-};
-
-/* Au1200 UDC (USB gadget controller) */
-static struct resource au1xxx_usb_gdt_resources[] = {
-	[0] = {
-		.start		= USB_UDC_BASE,
-		.end		= USB_UDC_BASE + USB_UDC_LEN - 1,
-		.flags		= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start		= AU1200_USB_INT,
-		.end		= AU1200_USB_INT,
-		.flags		= IORESOURCE_IRQ,
-	},
-};
-
-static u64 udc_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device au1xxx_usb_gdt_device = {
-	.name		= "au1xxx-udc",
-	.id		= 0,
-	.dev = {
-		.dma_mask		= &udc_dmamask,
-		.coherent_dma_mask	= DMA_BIT_MASK(32),
-	},
-	.num_resources	= ARRAY_SIZE(au1xxx_usb_gdt_resources),
-	.resource	= au1xxx_usb_gdt_resources,
-};
-
-/* Au1200 UOC (USB OTG controller) */
-static struct resource au1xxx_usb_otg_resources[] = {
-	[0] = {
-		.start		= USB_UOC_BASE,
-		.end		= USB_UOC_BASE + USB_UOC_LEN - 1,
-		.flags		= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start		= AU1200_USB_INT,
-		.end		= AU1200_USB_INT,
-		.flags		= IORESOURCE_IRQ,
-	},
-};
-
-static u64 uoc_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device au1xxx_usb_otg_device = {
-	.name		= "au1xxx-uoc",
-	.id		= 0,
-	.dev = {
-		.dma_mask		= &uoc_dmamask,
-		.coherent_dma_mask	= DMA_BIT_MASK(32),
-	},
-	.num_resources	= ARRAY_SIZE(au1xxx_usb_otg_resources),
-	.resource	= au1xxx_usb_otg_resources,
-};
 
 static struct resource au1200_lcd_resources[] = {
 	[0] = {
@@ -534,14 +504,10 @@ static void __init alchemy_setup_macs(int ctype)
 }
 
 static struct platform_device *au1xxx_platform_devices[] __initdata = {
-	&au1xxx_usb_ohci_device,
 #ifdef CONFIG_FB_AU1100
 	&au1100_lcd_device,
 #endif
 #ifdef CONFIG_SOC_AU1200
-	&au1xxx_usb_ehci_device,
-	&au1xxx_usb_gdt_device,
-	&au1xxx_usb_otg_device,
 	&au1200_lcd_device,
 	&au1200_mmc0_device,
 #ifndef CONFIG_MIPS_DB1200
@@ -559,6 +525,7 @@ static int __init au1xxx_platform_init(void)
 
 	alchemy_setup_uarts(ctype);
 	alchemy_setup_macs(ctype);
+	alchemy_setup_usb(ctype);
 
 	err = platform_add_devices(au1xxx_platform_devices,
 				   ARRAY_SIZE(au1xxx_platform_devices));
diff --git a/arch/mips/include/asm/mach-au1x00/au1000.h b/arch/mips/include/asm/mach-au1x00/au1000.h
index 73e0d79..86d39c3 100644
--- a/arch/mips/include/asm/mach-au1x00/au1000.h
+++ b/arch/mips/include/asm/mach-au1x00/au1000.h
@@ -833,56 +833,6 @@ enum soc_au1200_ints {
 #endif
 
 
-
-
-/* Au1000 */
-#ifdef CONFIG_SOC_AU1000
-
-#define USB_OHCI_BASE		0x10100000	/* phys addr for ioremap */
-#define USB_HOST_CONFIG 	0xB017FFFC
-#define FOR_PLATFORM_C_USB_HOST_INT AU1000_USB_HOST_INT
-#endif /* CONFIG_SOC_AU1000 */
-
-/* Au1500 */
-#ifdef CONFIG_SOC_AU1500
-
-#define USB_OHCI_BASE		0x10100000	/* phys addr for ioremap */
-#define USB_HOST_CONFIG 	0xB017fffc
-#define FOR_PLATFORM_C_USB_HOST_INT AU1500_USB_HOST_INT
-#endif /* CONFIG_SOC_AU1500 */
-
-/* Au1100 */
-#ifdef CONFIG_SOC_AU1100
-
-#define USB_OHCI_BASE		0x10100000	/* phys addr for ioremap */
-#define USB_HOST_CONFIG 	0xB017FFFC
-#define FOR_PLATFORM_C_USB_HOST_INT AU1100_USB_HOST_INT
-#endif /* CONFIG_SOC_AU1100 */
-
-#ifdef CONFIG_SOC_AU1550
-
-#define USB_OHCI_BASE		0x14020000	/* phys addr for ioremap */
-#define USB_OHCI_LEN		0x00060000
-#define USB_HOST_CONFIG 	0xB4027ffc
-#define FOR_PLATFORM_C_USB_HOST_INT AU1550_USB_HOST_INT
-#endif /* CONFIG_SOC_AU1550 */
-
-
-#ifdef CONFIG_SOC_AU1200
-
-#define USB_UOC_BASE		0x14020020
-#define USB_UOC_LEN		0x20
-#define USB_OHCI_BASE		0x14020100
-#define USB_OHCI_LEN		0x100
-#define USB_EHCI_BASE		0x14020200
-#define USB_EHCI_LEN		0x100
-#define USB_UDC_BASE		0x14022000
-#define USB_UDC_LEN		0x2000
-
-#define FOR_PLATFORM_C_USB_HOST_INT AU1200_USB_INT
-
-#endif /* CONFIG_SOC_AU1200 */
-
 /* Programmable Counters 0 and 1 */
 #define SYS_BASE		0xB1900000
 #define SYS_COUNTER_CNTRL	(SYS_BASE + 0x14)
@@ -953,11 +903,6 @@ enum soc_au1200_ints {
 #  define I2S_CONTROL_D 	(1 << 1)
 #  define I2S_CONTROL_CE	(1 << 0)
 
-/* USB Host Controller */
-#ifndef USB_OHCI_LEN
-#define USB_OHCI_LEN		0x00100000
-#endif
-
 
 /* Ethernet Controllers  */
 
-- 
1.7.6


From manuel.lauss@googlemail.com Fri Jul  8 11:18:53 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 08 Jul 2011 11:19:59 +0200 (CEST)
Received: from mail-fx0-f49.google.com ([209.85.161.49]:47219 "EHLO
        mail-fx0-f49.google.com" rhost-flags-OK-OK-OK-OK)
        by eddie.linux-mips.org with ESMTP id S1491770Ab1GHJSx (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Fri, 8 Jul 2011 11:18:53 +0200
Received: by fxd20 with SMTP id 20so1399553fxd.36
        for <multiple recipients>; Fri, 08 Jul 2011 02:18:48 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=googlemail.com; s=gamma;
        h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references;
        bh=jkZI6uhT+SrJBDu5XkvuEJ+x45me2bTqVB9bMFqUB4E=;
        b=MibiUWpw5noqzp9Wn6Rz1nU7YKTMB7u54+bECq4AWVaeu4P6DXW8NuDsmQRVUaX02m
         Xujms42VnuE6um80zn+pRPFy7/F++N1893R4yrIgd2UN0YxOmt9SyN1t/xKhJyZAE7Ho
         V26nrr+S7x/g9p1HRf7V0zCLXoE0XvshVxhvQ=
Received: by 10.223.9.217 with SMTP id m25mr2694336fam.122.1310116728320;
        Fri, 08 Jul 2011 02:18:48 -0700 (PDT)
Received: from localhost.localdomain (188-22-147-55.adsl.highway.telekom.at [188.22.147.55])
        by mx.google.com with ESMTPS id k26sm7260413fak.24.2011.07.08.02.18.46
        (version=TLSv1/SSLv3 cipher=OTHER);
        Fri, 08 Jul 2011 02:18:47 -0700 (PDT)
From:   Manuel Lauss <manuel.lauss@googlemail.com>
To:     Linux-MIPS <linux-mips@linux-mips.org>,
        Ralf Baechle <ralf@linux-mips.org>
Cc:     Manuel Lauss <manuel.lauss@googlemail.com>
Subject: [PATCH 1/5] net: au1000_eth: pass MACDMA address through platform resource info.
Date:   Fri,  8 Jul 2011 11:18:39 +0200
Message-Id: <1310116723-8632-2-git-send-email-manuel.lauss@googlemail.com>
X-Mailer: git-send-email 1.7.6
In-Reply-To: <1310116723-8632-1-git-send-email-manuel.lauss@googlemail.com>
References: <1310116723-8632-1-git-send-email-manuel.lauss@googlemail.com>
X-archive-position: 30589
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: manuel.lauss@googlemail.com
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 5980
Content-Length: 7234
Lines: 229

This patch removes the last hardcoded base address from the au1000_eth
driver.  The base address of the MACDMA unit was derived from the
platform device id; if someone registered the MACs in inverse order
both would not work.
So instead pass the base address of the DMA unit to the driver with
the other platform resource information.

Signed-off-by: Manuel Lauss <manuel.lauss@googlemail.com>
Acked-by: David S. Miller <davem@davemloft.net>
---
 arch/mips/alchemy/common/platform.c |   30 +++++++++++++++------
 drivers/net/au1000_eth.c            |   48 ++++++++++++++++++++++++++--------
 drivers/net/au1000_eth.h            |    2 +-
 3 files changed, 58 insertions(+), 22 deletions(-)

diff --git a/arch/mips/alchemy/common/platform.c b/arch/mips/alchemy/common/platform.c
index 3b2c18b..7400c93 100644
--- a/arch/mips/alchemy/common/platform.c
+++ b/arch/mips/alchemy/common/platform.c
@@ -373,8 +373,8 @@ static struct platform_device pbdb_smbus_device = {
 #endif
 
 /* Macro to help defining the Ethernet MAC resources */
-#define MAC_RES_COUNT	3	/* MAC regs base, MAC enable reg, MAC INT */
-#define MAC_RES(_base, _enable, _irq)			\
+#define MAC_RES_COUNT	4	/* MAC regs, MAC en, MAC INT, MACDMA regs */
+#define MAC_RES(_base, _enable, _irq, _macdma)		\
 	{						\
 		.start	= _base,			\
 		.end	= _base + 0xffff,		\
@@ -389,28 +389,37 @@ static struct platform_device pbdb_smbus_device = {
 		.start	= _irq,				\
 		.end	= _irq,				\
 		.flags	= IORESOURCE_IRQ		\
+	},						\
+	{						\
+		.start	= _macdma,			\
+		.end	= _macdma + 0x1ff,		\
+		.flags	= IORESOURCE_MEM,		\
 	}
 
 static struct resource au1xxx_eth0_resources[][MAC_RES_COUNT] __initdata = {
 	[ALCHEMY_CPU_AU1000] = {
 		MAC_RES(AU1000_MAC0_PHYS_ADDR,
 			AU1000_MACEN_PHYS_ADDR,
-			AU1000_MAC0_DMA_INT)
+			AU1000_MAC0_DMA_INT,
+			AU1000_MACDMA0_PHYS_ADDR)
 	},
 	[ALCHEMY_CPU_AU1500] = {
 		MAC_RES(AU1500_MAC0_PHYS_ADDR,
 			AU1500_MACEN_PHYS_ADDR,
-			AU1500_MAC0_DMA_INT)
+			AU1500_MAC0_DMA_INT,
+			AU1000_MACDMA0_PHYS_ADDR)
 	},
 	[ALCHEMY_CPU_AU1100] = {
 		MAC_RES(AU1000_MAC0_PHYS_ADDR,
 			AU1000_MACEN_PHYS_ADDR,
-			AU1100_MAC0_DMA_INT)
+			AU1100_MAC0_DMA_INT,
+			AU1000_MACDMA0_PHYS_ADDR)
 	},
 	[ALCHEMY_CPU_AU1550] = {
 		MAC_RES(AU1000_MAC0_PHYS_ADDR,
 			AU1000_MACEN_PHYS_ADDR,
-			AU1550_MAC0_DMA_INT)
+			AU1550_MAC0_DMA_INT,
+			AU1000_MACDMA0_PHYS_ADDR)
 	},
 };
 
@@ -429,17 +438,20 @@ static struct resource au1xxx_eth1_resources[][MAC_RES_COUNT] __initdata = {
 	[ALCHEMY_CPU_AU1000] = {
 		MAC_RES(AU1000_MAC1_PHYS_ADDR,
 			AU1000_MACEN_PHYS_ADDR + 4,
-			AU1000_MAC1_DMA_INT)
+			AU1000_MAC1_DMA_INT,
+			AU1000_MACDMA1_PHYS_ADDR)
 	},
 	[ALCHEMY_CPU_AU1500] = {
 		MAC_RES(AU1500_MAC1_PHYS_ADDR,
 			AU1500_MACEN_PHYS_ADDR + 4,
-			AU1500_MAC1_DMA_INT)
+			AU1500_MAC1_DMA_INT,
+			AU1000_MACDMA1_PHYS_ADDR)
 	},
 	[ALCHEMY_CPU_AU1550] = {
 		MAC_RES(AU1000_MAC1_PHYS_ADDR,
 			AU1000_MACEN_PHYS_ADDR + 4,
-			AU1550_MAC1_DMA_INT)
+			AU1550_MAC1_DMA_INT,
+			AU1000_MACDMA1_PHYS_ADDR)
 	},
 };
 
diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c
index b9debcf..520f7d3 100644
--- a/drivers/net/au1000_eth.c
+++ b/drivers/net/au1000_eth.c
@@ -541,19 +541,17 @@ static void au1000_reset_mac(struct net_device *dev)
  * these are not descriptors sitting in memory.
  */
 static void
-au1000_setup_hw_rings(struct au1000_private *aup, u32 rx_base, u32 tx_base)
+au1000_setup_hw_rings(struct au1000_private *aup, u32 *tx_base)
 {
 	int i;
 
 	for (i = 0; i < NUM_RX_DMA; i++) {
-		aup->rx_dma_ring[i] =
-			(struct rx_dma *)
-					(rx_base + sizeof(struct rx_dma)*i);
+		aup->rx_dma_ring[i] = (struct rx_dma *)
+			(tx_base + 0x100 + sizeof(struct rx_dma) * i);
 	}
 	for (i = 0; i < NUM_TX_DMA; i++) {
-		aup->tx_dma_ring[i] =
-			(struct tx_dma *)
-					(tx_base + sizeof(struct tx_dma)*i);
+		aup->tx_dma_ring[i] = (struct tx_dma *)
+			(tx_base + sizeof(struct tx_dma) * i);
 	}
 }
 
@@ -1026,7 +1024,7 @@ static int __devinit au1000_probe(struct platform_device *pdev)
 	struct net_device *dev = NULL;
 	struct db_dest *pDB, *pDBfree;
 	int irq, i, err = 0;
-	struct resource *base, *macen;
+	struct resource *base, *macen, *macdma;
 
 	base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!base) {
@@ -1049,6 +1047,13 @@ static int __devinit au1000_probe(struct platform_device *pdev)
 		goto out;
 	}
 
+	macdma = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+	if (!macdma) {
+		dev_err(&pdev->dev, "failed to retrieve MACDMA registers\n");
+		err = -ENODEV;
+		goto out;
+	}
+
 	if (!request_mem_region(base->start, resource_size(base),
 							pdev->name)) {
 		dev_err(&pdev->dev, "failed to request memory region for base registers\n");
@@ -1063,6 +1068,13 @@ static int __devinit au1000_probe(struct platform_device *pdev)
 		goto err_request;
 	}
 
+	if (!request_mem_region(macdma->start, resource_size(macdma),
+							pdev->name)) {
+		dev_err(&pdev->dev, "failed to request MACDMA memory region\n");
+		err = -ENXIO;
+		goto err_macdma;
+	}
+
 	dev = alloc_etherdev(sizeof(struct au1000_private));
 	if (!dev) {
 		dev_err(&pdev->dev, "alloc_etherdev failed\n");
@@ -1109,10 +1121,14 @@ static int __devinit au1000_probe(struct platform_device *pdev)
 	}
 	aup->mac_id = pdev->id;
 
-	if (pdev->id == 0)
-		au1000_setup_hw_rings(aup, MAC0_RX_DMA_ADDR, MAC0_TX_DMA_ADDR);
-	else if (pdev->id == 1)
-		au1000_setup_hw_rings(aup, MAC1_RX_DMA_ADDR, MAC1_TX_DMA_ADDR);
+	aup->macdma = ioremap_nocache(macdma->start, resource_size(macdma));
+	if (!aup->macdma) {
+		dev_err(&pdev->dev, "failed to ioremap MACDMA registers\n");
+		err = -ENXIO;
+		goto err_remap3;
+	}
+
+	au1000_setup_hw_rings(aup, aup->macdma);
 
 	/* set a random MAC now in case platform_data doesn't provide one */
 	random_ether_addr(dev->dev_addr);
@@ -1252,6 +1268,8 @@ err_out:
 err_mdiobus_reg:
 	mdiobus_free(aup->mii_bus);
 err_mdiobus_alloc:
+	iounmap(aup->macdma);
+err_remap3:
 	iounmap(aup->enable);
 err_remap2:
 	iounmap(aup->mac);
@@ -1261,6 +1279,8 @@ err_remap1:
 err_vaddr:
 	free_netdev(dev);
 err_alloc:
+	release_mem_region(macdma->start, resource_size(macdma));
+err_macdma:
 	release_mem_region(macen->start, resource_size(macen));
 err_request:
 	release_mem_region(base->start, resource_size(base));
@@ -1293,9 +1313,13 @@ static int __devexit au1000_remove(struct platform_device *pdev)
 			(NUM_TX_BUFFS + NUM_RX_BUFFS),
 			(void *)aup->vaddr, aup->dma_addr);
 
+	iounmap(aup->macdma);
 	iounmap(aup->mac);
 	iounmap(aup->enable);
 
+	base = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+	release_mem_region(base->start, resource_size(base));
+
 	base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	release_mem_region(base->start, resource_size(base));
 
diff --git a/drivers/net/au1000_eth.h b/drivers/net/au1000_eth.h
index 6229c77..9f28037 100644
--- a/drivers/net/au1000_eth.h
+++ b/drivers/net/au1000_eth.h
@@ -124,7 +124,7 @@ struct au1000_private {
 	 */
 	struct mac_reg *mac;  /* mac registers                      */
 	u32 *enable;     /* address of MAC Enable Register     */
-
+	u32 *macdma;	/* base of MAC DMA port */
 	u32 vaddr;                /* virtual address of rx/tx buffers   */
 	dma_addr_t dma_addr;      /* dma address of rx/tx buffers       */
 
-- 
1.7.6


From manuel.lauss@googlemail.com Fri Jul  8 11:18:54 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 08 Jul 2011 11:20:24 +0200 (CEST)
Received: from mail-fx0-f49.google.com ([209.85.161.49]:40422 "EHLO
        mail-fx0-f49.google.com" rhost-flags-OK-OK-OK-OK)
        by eddie.linux-mips.org with ESMTP id S1491771Ab1GHJSy (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Fri, 8 Jul 2011 11:18:54 +0200
Received: by fxd20 with SMTP id 20so1399570fxd.36
        for <multiple recipients>; Fri, 08 Jul 2011 02:18:49 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=googlemail.com; s=gamma;
        h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references;
        bh=3efbWbcTLeLW9rfV0SCWe038k+uCJfOGEYTyw/HDp/Q=;
        b=BZhKfaMCaHSgvVp0N8b2p8FnZ9lKDWvbKMWaoMWgI24icuNQzZmOPXjJPdzYbVlPyZ
         cYtSUxYFWM2niuN+ephN3iPTNFOFoHCOKPQa32fwKN1XxZk/OkqSYO5tm1sXAw9xOh+V
         HgfDW4lnS6sl9AIjQzPT73UoeOt56JQGLsV0g=
Received: by 10.223.68.22 with SMTP id t22mr2736829fai.145.1310116729618;
        Fri, 08 Jul 2011 02:18:49 -0700 (PDT)
Received: from localhost.localdomain (188-22-147-55.adsl.highway.telekom.at [188.22.147.55])
        by mx.google.com with ESMTPS id k26sm7260413fak.24.2011.07.08.02.18.48
        (version=TLSv1/SSLv3 cipher=OTHER);
        Fri, 08 Jul 2011 02:18:49 -0700 (PDT)
From:   Manuel Lauss <manuel.lauss@googlemail.com>
To:     Linux-MIPS <linux-mips@linux-mips.org>,
        Ralf Baechle <ralf@linux-mips.org>
Cc:     Manuel Lauss <manuel.lauss@googlemail.com>
Subject: [PATCH 2/5] MIPS: Alchemy: include Au1100 in PM code.
Date:   Fri,  8 Jul 2011 11:18:40 +0200
Message-Id: <1310116723-8632-3-git-send-email-manuel.lauss@googlemail.com>
X-Mailer: git-send-email 1.7.6
In-Reply-To: <1310116723-8632-1-git-send-email-manuel.lauss@googlemail.com>
References: <1310116723-8632-1-git-send-email-manuel.lauss@googlemail.com>
X-archive-position: 30590
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: manuel.lauss@googlemail.com
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 5981
Content-Length: 1133
Lines: 45

The current code forgets the Au1100 when looking for the
correct method to suspend the chip.

Signed-off-by: Manuel Lauss <manuel.lauss@googlemail.com>
---
 arch/mips/alchemy/common/power.c |   22 ++++++++++++++--------
 1 files changed, 14 insertions(+), 8 deletions(-)

diff --git a/arch/mips/alchemy/common/power.c b/arch/mips/alchemy/common/power.c
index 647e518..b86324a 100644
--- a/arch/mips/alchemy/common/power.c
+++ b/arch/mips/alchemy/common/power.c
@@ -158,15 +158,21 @@ static void restore_core_regs(void)
 
 void au_sleep(void)
 {
-	int cpuid = alchemy_get_cputype();
-	if (cpuid != ALCHEMY_CPU_UNKNOWN) {
-		save_core_regs();
-		if (cpuid <= ALCHEMY_CPU_AU1500)
-			alchemy_sleep_au1000();
-		else if (cpuid <= ALCHEMY_CPU_AU1200)
-			alchemy_sleep_au1550();
-		restore_core_regs();
+	save_core_regs();
+
+	switch (alchemy_get_cputype()) {
+	case ALCHEMY_CPU_AU1000:
+	case ALCHEMY_CPU_AU1500:
+	case ALCHEMY_CPU_AU1100:
+		alchemy_sleep_au1000();
+		break;
+	case ALCHEMY_CPU_AU1550:
+	case ALCHEMY_CPU_AU1200:
+		alchemy_sleep_au1550();
+		break;
 	}
+
+	restore_core_regs();
 }
 
 #endif	/* CONFIG_PM */
-- 
1.7.6


From manuel.lauss@googlemail.com Fri Jul  8 11:18:55 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 08 Jul 2011 11:20:48 +0200 (CEST)
Received: from mail-fx0-f49.google.com ([209.85.161.49]:35603 "EHLO
        mail-fx0-f49.google.com" rhost-flags-OK-OK-OK-OK)
        by eddie.linux-mips.org with ESMTP id S1491778Ab1GHJSz (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Fri, 8 Jul 2011 11:18:55 +0200
Received: by mail-fx0-f49.google.com with SMTP id 20so1399533fxd.36
        for <multiple recipients>; Fri, 08 Jul 2011 02:18:54 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=googlemail.com; s=gamma;
        h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references;
        bh=N40fm58A+2zvgMbxxb0C0TSX92YJWtvpYzgZBTdYk5w=;
        b=Mk2bVweMZfhAnd44nnlZdKoORoRQ2N0iybUU2dVpbOxWhhfEP0Gorf/9IQgpupwmof
         t/WIy+jBWHutFCIXrGdmVhRlSM06mB7VIb67hH8lqDFL6Kf5jgMdjOcHE0dkHXRXZcXc
         C6tDhh0m8bn6/63w5V5W6wsoiqrq0kvhOVSWw=
Received: by 10.223.5.13 with SMTP id 13mr2796257fat.1.1310116734798;
        Fri, 08 Jul 2011 02:18:54 -0700 (PDT)
Received: from localhost.localdomain (188-22-147-55.adsl.highway.telekom.at [188.22.147.55])
        by mx.google.com with ESMTPS id k26sm7260413fak.24.2011.07.08.02.18.53
        (version=TLSv1/SSLv3 cipher=OTHER);
        Fri, 08 Jul 2011 02:18:54 -0700 (PDT)
From:   Manuel Lauss <manuel.lauss@googlemail.com>
To:     Linux-MIPS <linux-mips@linux-mips.org>,
        Ralf Baechle <ralf@linux-mips.org>
Cc:     Manuel Lauss <manuel.lauss@googlemail.com>
Subject: [PATCH 5/5] MIPS: Alchemy: more base address cleanup
Date:   Fri,  8 Jul 2011 11:18:43 +0200
Message-Id: <1310116723-8632-6-git-send-email-manuel.lauss@googlemail.com>
X-Mailer: git-send-email 1.7.6
In-Reply-To: <1310116723-8632-1-git-send-email-manuel.lauss@googlemail.com>
References: <1310116723-8632-1-git-send-email-manuel.lauss@googlemail.com>
X-archive-position: 30591
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: manuel.lauss@googlemail.com
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 5983
Content-Length: 25148
Lines: 639

remove all redundant peripheral base address defines, fix
all affected boards and drivers.

Signed-off-by: Manuel Lauss <manuel.lauss@googlemail.com>
---
 arch/mips/alchemy/common/platform.c            |   12 ++--
 arch/mips/alchemy/devboards/db1200/platform.c  |   52 ++++++-------
 arch/mips/alchemy/devboards/db1x00/platform.c  |   40 ++++-----
 arch/mips/alchemy/devboards/pb1100/platform.c  |   20 ++---
 arch/mips/alchemy/devboards/pb1200/platform.c  |   42 +++++-----
 arch/mips/alchemy/devboards/pb1500/platform.c  |   22 +++---
 arch/mips/alchemy/devboards/pb1550/platform.c  |   40 ++++-----
 arch/mips/alchemy/xxs1500/platform.c           |   12 ++--
 arch/mips/include/asm/mach-au1x00/au1000.h     |  103 ++++++------------------
 arch/mips/include/asm/mach-au1x00/au1xxx_psc.h |   26 ------
 arch/mips/include/asm/mach-db1x00/db1x00.h     |    8 +-
 arch/mips/include/asm/mach-pb1x00/pb1200.h     |    8 +-
 arch/mips/include/asm/mach-pb1x00/pb1550.h     |    8 +-
 13 files changed, 146 insertions(+), 247 deletions(-)

diff --git a/arch/mips/alchemy/common/platform.c b/arch/mips/alchemy/common/platform.c
index e92a464..a5b37b3 100644
--- a/arch/mips/alchemy/common/platform.c
+++ b/arch/mips/alchemy/common/platform.c
@@ -194,8 +194,8 @@ static void __init alchemy_setup_usb(int ctype)
 #ifdef CONFIG_FB_AU1100
 static struct resource au1100_lcd_resources[] = {
 	[0] = {
-		.start          = LCD_PHYS_ADDR,
-		.end            = LCD_PHYS_ADDR + 0x800 - 1,
+		.start          = AU1100_LCD_PHYS_ADDR,
+		.end            = AU1100_LCD_PHYS_ADDR + 0x800 - 1,
 		.flags          = IORESOURCE_MEM,
 	},
 	[1] = {
@@ -223,8 +223,8 @@ static struct platform_device au1100_lcd_device = {
 
 static struct resource au1200_lcd_resources[] = {
 	[0] = {
-		.start          = LCD_PHYS_ADDR,
-		.end            = LCD_PHYS_ADDR + 0x800 - 1,
+		.start          = AU1200_LCD_PHYS_ADDR,
+		.end            = AU1200_LCD_PHYS_ADDR + 0x800 - 1,
 		.flags          = IORESOURCE_MEM,
 	},
 	[1] = {
@@ -328,8 +328,8 @@ static struct platform_device au1200_mmc1_device = {
 #ifdef SMBUS_PSC_BASE
 static struct resource pbdb_smbus_resources[] = {
 	{
-		.start	= CPHYSADDR(SMBUS_PSC_BASE),
-		.end	= CPHYSADDR(SMBUS_PSC_BASE + 0xfffff),
+		.start	= SMBUS_PSC_BASE,
+		.end	= SMBUS_PSC_BASE + 0xfff,
 		.flags	= IORESOURCE_MEM,
 	},
 };
diff --git a/arch/mips/alchemy/devboards/db1200/platform.c b/arch/mips/alchemy/devboards/db1200/platform.c
index fbb5593..95c7327 100644
--- a/arch/mips/alchemy/devboards/db1200/platform.c
+++ b/arch/mips/alchemy/devboards/db1200/platform.c
@@ -343,8 +343,8 @@ struct au1xmmc_platform_data au1xmmc_platdata[] = {
 
 static struct resource au1200_psc0_res[] = {
 	[0] = {
-		.start	= PSC0_PHYS_ADDR,
-		.end	= PSC0_PHYS_ADDR + 0x000fffff,
+		.start	= AU1550_PSC0_PHYS_ADDR,
+		.end	= AU1550_PSC0_PHYS_ADDR + 0xfff,
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
@@ -401,8 +401,8 @@ static struct platform_device db1200_spi_dev = {
 
 static struct resource au1200_psc1_res[] = {
 	[0] = {
-		.start	= PSC1_PHYS_ADDR,
-		.end	= PSC1_PHYS_ADDR + 0x000fffff,
+		.start	= AU1550_PSC1_PHYS_ADDR,
+		.end	= AU1550_PSC1_PHYS_ADDR + 0xfff,
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
@@ -510,32 +510,28 @@ static int __init db1200_dev_init(void)
 
 	/* Audio PSC clock is supplied externally. (FIXME: platdata!!) */
 	__raw_writel(PSC_SEL_CLK_SERCLK,
-		(void __iomem *)KSEG1ADDR(PSC1_PHYS_ADDR) + PSC_SEL_OFFSET);
+		(void __iomem *)KSEG1ADDR(AU1550_PSC1_PHYS_ADDR) + PSC_SEL_OFFSET);
 	wmb();
 
-	db1x_register_pcmcia_socket(PCMCIA_ATTR_PHYS_ADDR,
-				    PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1,
-				    PCMCIA_MEM_PHYS_ADDR,
-				    PCMCIA_MEM_PHYS_ADDR  + 0x000400000 - 1,
-				    PCMCIA_IO_PHYS_ADDR,
-				    PCMCIA_IO_PHYS_ADDR   + 0x000010000 - 1,
-				    DB1200_PC0_INT,
-				    DB1200_PC0_INSERT_INT,
-				    /*DB1200_PC0_STSCHG_INT*/0,
-				    DB1200_PC0_EJECT_INT,
-				    0);
-
-	db1x_register_pcmcia_socket(PCMCIA_ATTR_PHYS_ADDR + 0x004000000,
-				    PCMCIA_ATTR_PHYS_ADDR + 0x004400000 - 1,
-				    PCMCIA_MEM_PHYS_ADDR  + 0x004000000,
-				    PCMCIA_MEM_PHYS_ADDR  + 0x004400000 - 1,
-				    PCMCIA_IO_PHYS_ADDR   + 0x004000000,
-				    PCMCIA_IO_PHYS_ADDR   + 0x004010000 - 1,
-				    DB1200_PC1_INT,
-				    DB1200_PC1_INSERT_INT,
-				    /*DB1200_PC1_STSCHG_INT*/0,
-				    DB1200_PC1_EJECT_INT,
-				    1);
+	db1x_register_pcmcia_socket(
+		AU1000_PCMCIA_ATTR_PHYS_ADDR,
+		AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1,
+		AU1000_PCMCIA_MEM_PHYS_ADDR,
+		AU1000_PCMCIA_MEM_PHYS_ADDR  + 0x000400000 - 1,
+		AU1000_PCMCIA_IO_PHYS_ADDR,
+		AU1000_PCMCIA_IO_PHYS_ADDR   + 0x000010000 - 1,
+		DB1200_PC0_INT, DB1200_PC0_INSERT_INT,
+		/*DB1200_PC0_STSCHG_INT*/0, DB1200_PC0_EJECT_INT, 0);
+
+	db1x_register_pcmcia_socket(
+		AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x004000000,
+		AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x004400000 - 1,
+		AU1000_PCMCIA_MEM_PHYS_ADDR  + 0x004000000,
+		AU1000_PCMCIA_MEM_PHYS_ADDR  + 0x004400000 - 1,
+		AU1000_PCMCIA_IO_PHYS_ADDR   + 0x004000000,
+		AU1000_PCMCIA_IO_PHYS_ADDR   + 0x004010000 - 1,
+		DB1200_PC1_INT, DB1200_PC1_INSERT_INT,
+		/*DB1200_PC1_STSCHG_INT*/0, DB1200_PC1_EJECT_INT, 1);
 
 	swapped = bcsr_read(BCSR_STATUS) & BCSR_STATUS_DB1200_SWAPBOOT;
 	db1x_register_norflash(64 << 20, 2, swapped);
diff --git a/arch/mips/alchemy/devboards/db1x00/platform.c b/arch/mips/alchemy/devboards/db1x00/platform.c
index 978d5ab..ef8017f 100644
--- a/arch/mips/alchemy/devboards/db1x00/platform.c
+++ b/arch/mips/alchemy/devboards/db1x00/platform.c
@@ -88,29 +88,25 @@
 static int __init db1xxx_dev_init(void)
 {
 #ifdef DB1XXX_HAS_PCMCIA
-	db1x_register_pcmcia_socket(PCMCIA_ATTR_PHYS_ADDR,
-				    PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1,
-				    PCMCIA_MEM_PHYS_ADDR,
-				    PCMCIA_MEM_PHYS_ADDR  + 0x000400000 - 1,
-				    PCMCIA_IO_PHYS_ADDR,
-				    PCMCIA_IO_PHYS_ADDR   + 0x000010000 - 1,
-				    DB1XXX_PCMCIA_CARD0,
-				    DB1XXX_PCMCIA_CD0,
-				    /*DB1XXX_PCMCIA_STSCHG0*/0,
-				    0,
-				    0);
+	db1x_register_pcmcia_socket(
+		AU1000_PCMCIA_ATTR_PHYS_ADDR,
+		AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1,
+		AU1000_PCMCIA_MEM_PHYS_ADDR,
+		AU1000_PCMCIA_MEM_PHYS_ADDR  + 0x000400000 - 1,
+		AU1000_PCMCIA_IO_PHYS_ADDR,
+		AU1000_PCMCIA_IO_PHYS_ADDR   + 0x000010000 - 1,
+		DB1XXX_PCMCIA_CARD0, DB1XXX_PCMCIA_CD0,
+		/*DB1XXX_PCMCIA_STSCHG0*/0, 0, 0);
 
-	db1x_register_pcmcia_socket(PCMCIA_ATTR_PHYS_ADDR + 0x004000000,
-				    PCMCIA_ATTR_PHYS_ADDR + 0x004400000 - 1,
-				    PCMCIA_MEM_PHYS_ADDR  + 0x004000000,
-				    PCMCIA_MEM_PHYS_ADDR  + 0x004400000 - 1,
-				    PCMCIA_IO_PHYS_ADDR   + 0x004000000,
-				    PCMCIA_IO_PHYS_ADDR   + 0x004010000 - 1,
-				    DB1XXX_PCMCIA_CARD1,
-				    DB1XXX_PCMCIA_CD1,
-				    /*DB1XXX_PCMCIA_STSCHG1*/0,
-				    0,
-				    1);
+	db1x_register_pcmcia_socket(
+		AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x004000000,
+		AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x004400000 - 1,
+		AU1000_PCMCIA_MEM_PHYS_ADDR  + 0x004000000,
+		AU1000_PCMCIA_MEM_PHYS_ADDR  + 0x004400000 - 1,
+		AU1000_PCMCIA_IO_PHYS_ADDR   + 0x004000000,
+		AU1000_PCMCIA_IO_PHYS_ADDR   + 0x004010000 - 1,
+		DB1XXX_PCMCIA_CARD1, DB1XXX_PCMCIA_CD1,
+		/*DB1XXX_PCMCIA_STSCHG1*/0, 0, 1);
 #endif
 	db1x_register_norflash(BOARD_FLASH_SIZE, BOARD_FLASH_WIDTH, F_SWAPPED);
 	return 0;
diff --git a/arch/mips/alchemy/devboards/pb1100/platform.c b/arch/mips/alchemy/devboards/pb1100/platform.c
index 2c8dc29..8a4e733 100644
--- a/arch/mips/alchemy/devboards/pb1100/platform.c
+++ b/arch/mips/alchemy/devboards/pb1100/platform.c
@@ -30,17 +30,15 @@ static int __init pb1100_dev_init(void)
 	int swapped;
 
 	/* PCMCIA. single socket, identical to Pb1500 */
-	db1x_register_pcmcia_socket(PCMCIA_ATTR_PHYS_ADDR,
-				    PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1,
-				    PCMCIA_MEM_PHYS_ADDR,
-				    PCMCIA_MEM_PHYS_ADDR  + 0x000400000 - 1,
-				    PCMCIA_IO_PHYS_ADDR,
-				    PCMCIA_IO_PHYS_ADDR   + 0x000010000 - 1,
-				    AU1100_GPIO11_INT,	 /* card */
-				    AU1100_GPIO9_INT,	 /* insert */
-				    /*AU1100_GPIO10_INT*/0, /* stschg */
-				    0,			 /* eject */
-				    0);			 /* id */
+	db1x_register_pcmcia_socket(
+		AU1000_PCMCIA_ATTR_PHYS_ADDR,
+		AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1,
+		AU1000_PCMCIA_MEM_PHYS_ADDR,
+		AU1000_PCMCIA_MEM_PHYS_ADDR  + 0x000400000 - 1,
+		AU1000_PCMCIA_IO_PHYS_ADDR,
+		AU1000_PCMCIA_IO_PHYS_ADDR   + 0x000010000 - 1,
+		AU1100_GPIO11_INT, AU1100_GPIO9_INT,	 /* card / insert */
+		/*AU1100_GPIO10_INT*/0, 0, 0); /* stschg / eject / id */
 
 	swapped = bcsr_read(BCSR_STATUS) &  BCSR_STATUS_DB1000_SWAPBOOT;
 	db1x_register_norflash(64 * 1024 * 1024, 4, swapped);
diff --git a/arch/mips/alchemy/devboards/pb1200/platform.c b/arch/mips/alchemy/devboards/pb1200/platform.c
index 3ef2dce..c52809d 100644
--- a/arch/mips/alchemy/devboards/pb1200/platform.c
+++ b/arch/mips/alchemy/devboards/pb1200/platform.c
@@ -170,29 +170,25 @@ static int __init board_register_devices(void)
 {
 	int swapped;
 
-	db1x_register_pcmcia_socket(PCMCIA_ATTR_PHYS_ADDR,
-				    PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1,
-				    PCMCIA_MEM_PHYS_ADDR,
-				    PCMCIA_MEM_PHYS_ADDR  + 0x000400000 - 1,
-				    PCMCIA_IO_PHYS_ADDR,
-				    PCMCIA_IO_PHYS_ADDR   + 0x000010000 - 1,
-				    PB1200_PC0_INT,
-				    PB1200_PC0_INSERT_INT,
-				    /*PB1200_PC0_STSCHG_INT*/0,
-				    PB1200_PC0_EJECT_INT,
-				    0);
-
-	db1x_register_pcmcia_socket(PCMCIA_ATTR_PHYS_ADDR + 0x008000000,
-				    PCMCIA_ATTR_PHYS_ADDR + 0x008400000 - 1,
-				    PCMCIA_MEM_PHYS_ADDR  + 0x008000000,
-				    PCMCIA_MEM_PHYS_ADDR  + 0x008400000 - 1,
-				    PCMCIA_IO_PHYS_ADDR   + 0x008000000,
-				    PCMCIA_IO_PHYS_ADDR   + 0x008010000 - 1,
-				    PB1200_PC1_INT,
-				    PB1200_PC1_INSERT_INT,
-				    /*PB1200_PC1_STSCHG_INT*/0,
-				    PB1200_PC1_EJECT_INT,
-				    1);
+	db1x_register_pcmcia_socket(
+		AU1000_PCMCIA_ATTR_PHYS_ADDR,
+		AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1,
+		AU1000_PCMCIA_MEM_PHYS_ADDR,
+		AU1000_PCMCIA_MEM_PHYS_ADDR  + 0x000400000 - 1,
+		AU1000_PCMCIA_IO_PHYS_ADDR,
+		AU1000_PCMCIA_IO_PHYS_ADDR   + 0x000010000 - 1,
+		PB1200_PC0_INT, PB1200_PC0_INSERT_INT,
+		/*PB1200_PC0_STSCHG_INT*/0, PB1200_PC0_EJECT_INT, 0);
+
+	db1x_register_pcmcia_socket(
+		AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x008000000,
+		AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x008400000 - 1,
+		AU1000_PCMCIA_MEM_PHYS_ADDR  + 0x008000000,
+		AU1000_PCMCIA_MEM_PHYS_ADDR  + 0x008400000 - 1,
+		AU1000_PCMCIA_IO_PHYS_ADDR   + 0x008000000,
+		AU1000_PCMCIA_IO_PHYS_ADDR   + 0x008010000 - 1,
+		PB1200_PC1_INT, PB1200_PC1_INSERT_INT,
+		/*PB1200_PC1_STSCHG_INT*/0, PB1200_PC1_EJECT_INT, 1);
 
 	swapped = bcsr_read(BCSR_STATUS) &  BCSR_STATUS_DB1200_SWAPBOOT;
 	db1x_register_norflash(128 * 1024 * 1024, 2, swapped);
diff --git a/arch/mips/alchemy/devboards/pb1500/platform.c b/arch/mips/alchemy/devboards/pb1500/platform.c
index d443bc7..42b0e6b 100644
--- a/arch/mips/alchemy/devboards/pb1500/platform.c
+++ b/arch/mips/alchemy/devboards/pb1500/platform.c
@@ -28,18 +28,16 @@ static int __init pb1500_dev_init(void)
 {
 	int swapped;
 
-	/* PCMCIA. single socket, identical to Pb1500 */
-	db1x_register_pcmcia_socket(PCMCIA_ATTR_PHYS_ADDR,
-				    PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1,
-				    PCMCIA_MEM_PHYS_ADDR,
-				    PCMCIA_MEM_PHYS_ADDR  + 0x000400000 - 1,
-				    PCMCIA_IO_PHYS_ADDR,
-				    PCMCIA_IO_PHYS_ADDR   + 0x000010000 - 1,
-				    AU1500_GPIO11_INT,	 /* card */
-				    AU1500_GPIO9_INT,	 /* insert */
-				    /*AU1500_GPIO10_INT*/0, /* stschg */
-				    0,			 /* eject */
-				    0);			 /* id */
+	/* PCMCIA. single socket, identical to Pb1100 */
+	db1x_register_pcmcia_socket(
+		AU1000_PCMCIA_ATTR_PHYS_ADDR,
+		AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1,
+		AU1000_PCMCIA_MEM_PHYS_ADDR,
+		AU1000_PCMCIA_MEM_PHYS_ADDR  + 0x000400000 - 1,
+		AU1000_PCMCIA_IO_PHYS_ADDR,
+		AU1000_PCMCIA_IO_PHYS_ADDR   + 0x000010000 - 1,
+		AU1500_GPIO11_INT, AU1500_GPIO9_INT,	 /* card / insert */
+		/*AU1500_GPIO10_INT*/0, 0, 0); /* stschg / eject / id */
 
 	swapped = bcsr_read(BCSR_STATUS) &  BCSR_STATUS_DB1000_SWAPBOOT;
 	db1x_register_norflash(64 * 1024 * 1024, 4, swapped);
diff --git a/arch/mips/alchemy/devboards/pb1550/platform.c b/arch/mips/alchemy/devboards/pb1550/platform.c
index d7150d0..87c79b7 100644
--- a/arch/mips/alchemy/devboards/pb1550/platform.c
+++ b/arch/mips/alchemy/devboards/pb1550/platform.c
@@ -37,29 +37,23 @@ static int __init pb1550_dev_init(void)
 	* drivers are used to shared irqs and b) statuschange isn't really use-
 	* ful anyway.
 	*/
-	db1x_register_pcmcia_socket(PCMCIA_ATTR_PHYS_ADDR,
-				    PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1,
-				    PCMCIA_MEM_PHYS_ADDR,
-				    PCMCIA_MEM_PHYS_ADDR  + 0x000400000 - 1,
-				    PCMCIA_IO_PHYS_ADDR,
-				    PCMCIA_IO_PHYS_ADDR   + 0x000010000 - 1,
-				    AU1550_GPIO201_205_INT,
-				    AU1550_GPIO0_INT,
-				    0,
-				    0,
-				    0);
-
-	db1x_register_pcmcia_socket(PCMCIA_ATTR_PHYS_ADDR + 0x008000000,
-				    PCMCIA_ATTR_PHYS_ADDR + 0x008400000 - 1,
-				    PCMCIA_MEM_PHYS_ADDR  + 0x008000000,
-				    PCMCIA_MEM_PHYS_ADDR  + 0x008400000 - 1,
-				    PCMCIA_IO_PHYS_ADDR   + 0x008000000,
-				    PCMCIA_IO_PHYS_ADDR   + 0x008010000 - 1,
-				    AU1550_GPIO201_205_INT,
-				    AU1550_GPIO1_INT,
-				    0,
-				    0,
-				    1);
+	db1x_register_pcmcia_socket(
+		AU1000_PCMCIA_ATTR_PHYS_ADDR,
+		AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1,
+		AU1000_PCMCIA_MEM_PHYS_ADDR,
+		AU1000_PCMCIA_MEM_PHYS_ADDR  + 0x000400000 - 1,
+		AU1000_PCMCIA_IO_PHYS_ADDR,
+		AU1000_PCMCIA_IO_PHYS_ADDR   + 0x000010000 - 1,
+		AU1550_GPIO201_205_INT, AU1550_GPIO0_INT, 0, 0, 0);
+
+	db1x_register_pcmcia_socket(
+		AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x008000000,
+		AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x008400000 - 1,
+		AU1000_PCMCIA_MEM_PHYS_ADDR  + 0x008000000,
+		AU1000_PCMCIA_MEM_PHYS_ADDR  + 0x008400000 - 1,
+		AU1000_PCMCIA_IO_PHYS_ADDR   + 0x008000000,
+		AU1000_PCMCIA_IO_PHYS_ADDR   + 0x008010000 - 1,
+		AU1550_GPIO201_205_INT, AU1550_GPIO1_INT, 0, 0, 1);
 
 	swapped = bcsr_read(BCSR_STATUS) & BCSR_STATUS_PB1550_SWAPBOOT;
 	db1x_register_norflash(128 * 1024 * 1024, 4, swapped);
diff --git a/arch/mips/alchemy/xxs1500/platform.c b/arch/mips/alchemy/xxs1500/platform.c
index e87c45c..06a3a45 100644
--- a/arch/mips/alchemy/xxs1500/platform.c
+++ b/arch/mips/alchemy/xxs1500/platform.c
@@ -27,20 +27,20 @@ static struct resource xxs1500_pcmcia_res[] = {
 	{
 		.name	= "pcmcia-io",
 		.flags	= IORESOURCE_MEM,
-		.start	= PCMCIA_IO_PHYS_ADDR,
-		.end	= PCMCIA_IO_PHYS_ADDR + 0x000400000 - 1,
+		.start	= AU1000_PCMCIA_IO_PHYS_ADDR,
+		.end	= AU1000_PCMCIA_IO_PHYS_ADDR + 0x000400000 - 1,
 	},
 	{
 		.name	= "pcmcia-attr",
 		.flags	= IORESOURCE_MEM,
-		.start	= PCMCIA_ATTR_PHYS_ADDR,
-		.end	= PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1,
+		.start	= AU1000_PCMCIA_ATTR_PHYS_ADDR,
+		.end	= AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1,
 	},
 	{
 		.name	= "pcmcia-mem",
 		.flags	= IORESOURCE_MEM,
-		.start	= PCMCIA_MEM_PHYS_ADDR,
-		.end	= PCMCIA_MEM_PHYS_ADDR + 0x000400000 - 1,
+		.start	= AU1000_PCMCIA_MEM_PHYS_ADDR,
+		.end	= AU1000_PCMCIA_MEM_PHYS_ADDR + 0x000400000 - 1,
 	},
 };
 
diff --git a/arch/mips/include/asm/mach-au1x00/au1000.h b/arch/mips/include/asm/mach-au1x00/au1000.h
index 86d39c3..bcf3d1e 100644
--- a/arch/mips/include/asm/mach-au1x00/au1000.h
+++ b/arch/mips/include/asm/mach-au1x00/au1000.h
@@ -698,114 +698,61 @@ enum soc_au1200_ints {
 #define AU1000_AC97_PHYS_ADDR		0x10000000 /* 012 */
 #define AU1000_USB_OHCI_PHYS_ADDR	0x10100000 /* 012 */
 #define AU1000_USB_UDC_PHYS_ADDR	0x10200000 /* 0123 */
+#define AU1000_IRDA_PHYS_ADDR		0x10300000 /* 02 */
+#define AU1200_AES_PHYS_ADDR		0x10300000 /* 4 */
 #define AU1000_IC0_PHYS_ADDR		0x10400000 /* 01234 */
 #define AU1000_MAC0_PHYS_ADDR		0x10500000 /* 023 */
 #define AU1000_MAC1_PHYS_ADDR		0x10510000 /* 023 */
 #define AU1000_MACEN_PHYS_ADDR		0x10520000 /* 023 */
 #define AU1100_SD0_PHYS_ADDR		0x10600000 /* 24 */
 #define AU1100_SD1_PHYS_ADDR		0x10680000 /* 24 */
+#define AU1550_PSC2_PHYS_ADDR		0x10A00000 /* 3 */
+#define AU1550_PSC3_PHYS_ADDR		0x10B00000 /* 3 */
 #define AU1000_I2S_PHYS_ADDR		0x11000000 /* 02 */
 #define AU1500_MAC0_PHYS_ADDR		0x11500000 /* 1 */
 #define AU1500_MAC1_PHYS_ADDR		0x11510000 /* 1 */
 #define AU1500_MACEN_PHYS_ADDR		0x11520000 /* 1 */
 #define AU1000_UART0_PHYS_ADDR		0x11100000 /* 01234 */
+#define AU1200_SWCNT_PHYS_ADDR		0x1110010C /* 4 */
 #define AU1000_UART1_PHYS_ADDR		0x11200000 /* 0234 */
 #define AU1000_UART2_PHYS_ADDR		0x11300000 /* 0 */
 #define AU1000_UART3_PHYS_ADDR		0x11400000 /* 0123 */
+#define AU1000_SSI0_PHYS_ADDR		0x11600000 /* 02 */
+#define AU1000_SSI1_PHYS_ADDR		0x11680000 /* 02 */
 #define AU1500_GPIO2_PHYS_ADDR		0x11700000 /* 1234 */
 #define AU1000_IC1_PHYS_ADDR		0x11800000 /* 01234 */
 #define AU1000_SYS_PHYS_ADDR		0x11900000 /* 01234 */
+#define AU1550_PSC0_PHYS_ADDR		0x11A00000 /* 34 */
+#define AU1550_PSC1_PHYS_ADDR		0x11B00000 /* 34 */
+#define AU1000_MEM_PHYS_ADDR		0x14000000 /* 01234 */
+#define AU1000_STATIC_MEM_PHYS_ADDR	0x14001000 /* 01234 */
 #define AU1000_DMA_PHYS_ADDR		0x14002000 /* 012 */
 #define AU1550_DBDMA_PHYS_ADDR		0x14002000 /* 34 */
 #define AU1550_DBDMA_CONF_PHYS_ADDR	0x14003000 /* 34 */
 #define AU1000_MACDMA0_PHYS_ADDR	0x14004000 /* 0123 */
 #define AU1000_MACDMA1_PHYS_ADDR	0x14004200 /* 0123 */
+#define AU1200_CIM_PHYS_ADDR		0x14004000 /* 4 */
+#define AU1500_PCI_PHYS_ADDR		0x14005000 /* 13 */
+#define AU1550_PE_PHYS_ADDR		0x14008000 /* 3 */
+#define AU1200_MAEBE_PHYS_ADDR		0x14010000 /* 4 */
+#define AU1200_MAEFE_PHYS_ADDR		0x14012000 /* 4 */
 #define AU1550_USB_OHCI_PHYS_ADDR	0x14020000 /* 3 */
 #define AU1200_USB_CTL_PHYS_ADDR	0x14020000 /* 4 */
 #define AU1200_USB_OTG_PHYS_ADDR	0x14020020 /* 4 */
 #define AU1200_USB_OHCI_PHYS_ADDR	0x14020100 /* 4 */
 #define AU1200_USB_EHCI_PHYS_ADDR	0x14020200 /* 4 */
 #define AU1200_USB_UDC_PHYS_ADDR	0x14022000 /* 4 */
+#define AU1100_LCD_PHYS_ADDR		0x15000000 /* 2 */
+#define AU1200_LCD_PHYS_ADDR		0x15000000 /* 4 */
+#define AU1500_PCI_MEM_PHYS_ADDR	0x400000000ULL /* 13 */
+#define AU1500_PCI_IO_PHYS_ADDR		0x500000000ULL /* 13 */
+#define AU1500_PCI_CONFIG0_PHYS_ADDR	0x600000000ULL /* 13 */
+#define AU1500_PCI_CONFIG1_PHYS_ADDR	0x680000000ULL /* 13 */
+#define AU1000_PCMCIA_IO_PHYS_ADDR	0xF00000000ULL /* 01234 */
+#define AU1000_PCMCIA_ATTR_PHYS_ADDR	0xF40000000ULL /* 01234 */
+#define AU1000_PCMCIA_MEM_PHYS_ADDR	0xF80000000ULL /* 01234 */
 
 
-#ifdef CONFIG_SOC_AU1000
-#define	MEM_PHYS_ADDR		0x14000000
-#define	STATIC_MEM_PHYS_ADDR	0x14001000
-#define	IRDA_PHYS_ADDR		0x10300000
-#define	SSI0_PHYS_ADDR		0x11600000
-#define	SSI1_PHYS_ADDR		0x11680000
-#define PCMCIA_IO_PHYS_ADDR	0xF00000000ULL
-#define PCMCIA_ATTR_PHYS_ADDR	0xF40000000ULL
-#define PCMCIA_MEM_PHYS_ADDR	0xF80000000ULL
-#endif
-
-/********************************************************************/
-
-#ifdef CONFIG_SOC_AU1500
-#define	MEM_PHYS_ADDR		0x14000000
-#define	STATIC_MEM_PHYS_ADDR	0x14001000
-#define PCI_PHYS_ADDR		0x14005000
-#define PCI_MEM_PHYS_ADDR	0x400000000ULL
-#define PCI_IO_PHYS_ADDR	0x500000000ULL
-#define PCI_CONFIG0_PHYS_ADDR	0x600000000ULL
-#define PCI_CONFIG1_PHYS_ADDR	0x680000000ULL
-#define PCMCIA_IO_PHYS_ADDR	0xF00000000ULL
-#define PCMCIA_ATTR_PHYS_ADDR	0xF40000000ULL
-#define PCMCIA_MEM_PHYS_ADDR	0xF80000000ULL
-#endif
-
-/********************************************************************/
-
-#ifdef CONFIG_SOC_AU1100
-#define	MEM_PHYS_ADDR		0x14000000
-#define	STATIC_MEM_PHYS_ADDR	0x14001000
-#define	IRDA_PHYS_ADDR		0x10300000
-#define	SSI0_PHYS_ADDR		0x11600000
-#define	SSI1_PHYS_ADDR		0x11680000
-#define LCD_PHYS_ADDR		0x15000000
-#define PCMCIA_IO_PHYS_ADDR	0xF00000000ULL
-#define PCMCIA_ATTR_PHYS_ADDR	0xF40000000ULL
-#define PCMCIA_MEM_PHYS_ADDR	0xF80000000ULL
-#endif
-
-/***********************************************************************/
-
-#ifdef CONFIG_SOC_AU1550
-#define	MEM_PHYS_ADDR		0x14000000
-#define	STATIC_MEM_PHYS_ADDR	0x14001000
-#define PCI_PHYS_ADDR		0x14005000
-#define PE_PHYS_ADDR		0x14008000
-#define PSC0_PHYS_ADDR		0x11A00000
-#define PSC1_PHYS_ADDR		0x11B00000
-#define PSC2_PHYS_ADDR		0x10A00000
-#define PSC3_PHYS_ADDR		0x10B00000
-#define PCI_MEM_PHYS_ADDR	0x400000000ULL
-#define PCI_IO_PHYS_ADDR	0x500000000ULL
-#define PCI_CONFIG0_PHYS_ADDR	0x600000000ULL
-#define PCI_CONFIG1_PHYS_ADDR	0x680000000ULL
-#define PCMCIA_IO_PHYS_ADDR	0xF00000000ULL
-#define PCMCIA_ATTR_PHYS_ADDR	0xF40000000ULL
-#define PCMCIA_MEM_PHYS_ADDR	0xF80000000ULL
-#endif
-
-/***********************************************************************/
-
-#ifdef CONFIG_SOC_AU1200
-#define	MEM_PHYS_ADDR		0x14000000
-#define	STATIC_MEM_PHYS_ADDR	0x14001000
-#define AES_PHYS_ADDR		0x10300000
-#define CIM_PHYS_ADDR		0x14004000
-#define PSC0_PHYS_ADDR	 	0x11A00000
-#define PSC1_PHYS_ADDR	 	0x11B00000
-#define LCD_PHYS_ADDR		0x15000000
-#define SWCNT_PHYS_ADDR		0x1110010C
-#define MAEFE_PHYS_ADDR		0x14012000
-#define MAEBE_PHYS_ADDR		0x14010000
-#define PCMCIA_IO_PHYS_ADDR	0xF00000000ULL
-#define PCMCIA_ATTR_PHYS_ADDR	0xF40000000ULL
-#define PCMCIA_MEM_PHYS_ADDR	0xF80000000ULL
-#endif
-
 /* Static Bus Controller */
 #define MEM_STCFG0		0xB4001000
 #define MEM_STTIME0		0xB4001004
diff --git a/arch/mips/include/asm/mach-au1x00/au1xxx_psc.h b/arch/mips/include/asm/mach-au1x00/au1xxx_psc.h
index 892b7f1..8e2fa67 100644
--- a/arch/mips/include/asm/mach-au1x00/au1xxx_psc.h
+++ b/arch/mips/include/asm/mach-au1x00/au1xxx_psc.h
@@ -33,19 +33,6 @@
 #ifndef _AU1000_PSC_H_
 #define _AU1000_PSC_H_
 
-/* The PSC base addresses.  */
-#ifdef CONFIG_SOC_AU1550
-#define PSC0_BASE_ADDR		0xb1a00000
-#define PSC1_BASE_ADDR		0xb1b00000
-#define PSC2_BASE_ADDR		0xb0a00000
-#define PSC3_BASE_ADDR		0xb0b00000
-#endif
-
-#ifdef CONFIG_SOC_AU1200
-#define PSC0_BASE_ADDR		0xb1a00000
-#define PSC1_BASE_ADDR		0xb1b00000
-#endif
-
 /*
  * The PSC select and control registers are common to all protocols.
  */
@@ -80,19 +67,6 @@
 #define PSC_AC97GPO_OFFSET	0x00000028
 #define PSC_AC97GPI_OFFSET	0x0000002c
 
-#define AC97_PSC_SEL		(AC97_PSC_BASE + PSC_SEL_OFFSET)
-#define AC97_PSC_CTRL		(AC97_PSC_BASE + PSC_CTRL_OFFSET)
-#define PSC_AC97CFG		(AC97_PSC_BASE + PSC_AC97CFG_OFFSET)
-#define PSC_AC97MSK		(AC97_PSC_BASE + PSC_AC97MSK_OFFSET)
-#define PSC_AC97PCR		(AC97_PSC_BASE + PSC_AC97PCR_OFFSET)
-#define PSC_AC97STAT		(AC97_PSC_BASE + PSC_AC97STAT_OFFSET)
-#define PSC_AC97EVNT		(AC97_PSC_BASE + PSC_AC97EVNT_OFFSET)
-#define PSC_AC97TXRX		(AC97_PSC_BASE + PSC_AC97TXRX_OFFSET)
-#define PSC_AC97CDC		(AC97_PSC_BASE + PSC_AC97CDC_OFFSET)
-#define PSC_AC97RST		(AC97_PSC_BASE + PSC_AC97RST_OFFSET)
-#define PSC_AC97GPO		(AC97_PSC_BASE + PSC_AC97GPO_OFFSET)
-#define PSC_AC97GPI		(AC97_PSC_BASE + PSC_AC97GPI_OFFSET)
-
 /* AC97 Config Register. */
 #define PSC_AC97CFG_RT_MASK	(3 << 30)
 #define PSC_AC97CFG_RT_FIFO1	(0 << 30)
diff --git a/arch/mips/include/asm/mach-db1x00/db1x00.h b/arch/mips/include/asm/mach-db1x00/db1x00.h
index a919dac..115cc7c 100644
--- a/arch/mips/include/asm/mach-db1x00/db1x00.h
+++ b/arch/mips/include/asm/mach-db1x00/db1x00.h
@@ -36,10 +36,10 @@
 #define DBDMA_I2S_TX_CHAN	DSCR_CMD0_PSC3_TX
 #define DBDMA_I2S_RX_CHAN	DSCR_CMD0_PSC3_RX
 
-#define SPI_PSC_BASE		PSC0_BASE_ADDR
-#define AC97_PSC_BASE		PSC1_BASE_ADDR
-#define SMBUS_PSC_BASE		PSC2_BASE_ADDR
-#define I2S_PSC_BASE		PSC3_BASE_ADDR
+#define SPI_PSC_BASE		AU1550_PSC0_PHYS_ADDR
+#define AC97_PSC_BASE		AU1550_PSC1_PHYS_ADDR
+#define SMBUS_PSC_BASE		AU1550_PSC2_PHYS_ADDR
+#define I2S_PSC_BASE		AU1550_PSC3_PHYS_ADDR
 
 #define NAND_PHYS_ADDR		0x20000000
 
diff --git a/arch/mips/include/asm/mach-pb1x00/pb1200.h b/arch/mips/include/asm/mach-pb1x00/pb1200.h
index fce4332..0ecff1c 100644
--- a/arch/mips/include/asm/mach-pb1x00/pb1200.h
+++ b/arch/mips/include/asm/mach-pb1x00/pb1200.h
@@ -37,14 +37,14 @@
  * SPI and SMB are muxed on the Pb1200 board.
  * Refer to board documentation.
  */
-#define SPI_PSC_BASE		PSC0_BASE_ADDR
-#define SMBUS_PSC_BASE		PSC0_BASE_ADDR
+#define SPI_PSC_BASE		AU1550_PSC0_PHYS_ADDR
+#define SMBUS_PSC_BASE		AU1550_PSC0_PHYS_ADDR
 /*
  * AC97 and I2S are muxed on the Pb1200 board.
  * Refer to board documentation.
  */
-#define AC97_PSC_BASE       PSC1_BASE_ADDR
-#define I2S_PSC_BASE	PSC1_BASE_ADDR
+#define AC97_PSC_BASE       AU1550_PSC1_PHYS_ADDR
+#define I2S_PSC_BASE	AU1550_PSC1_PHYS_ADDR
 
 
 #define BCSR_SYSTEM_VDDI	0x001F
diff --git a/arch/mips/include/asm/mach-pb1x00/pb1550.h b/arch/mips/include/asm/mach-pb1x00/pb1550.h
index f835c88..0b0f462 100644
--- a/arch/mips/include/asm/mach-pb1x00/pb1550.h
+++ b/arch/mips/include/asm/mach-pb1x00/pb1550.h
@@ -35,10 +35,10 @@
 #define DBDMA_I2S_TX_CHAN	DSCR_CMD0_PSC3_TX
 #define DBDMA_I2S_RX_CHAN	DSCR_CMD0_PSC3_RX
 
-#define SPI_PSC_BASE		PSC0_BASE_ADDR
-#define AC97_PSC_BASE		PSC1_BASE_ADDR
-#define SMBUS_PSC_BASE		PSC2_BASE_ADDR
-#define I2S_PSC_BASE		PSC3_BASE_ADDR
+#define SPI_PSC_BASE		AU1550_PSC0_PHYS_ADDR
+#define AC97_PSC_BASE		AU1550_PSC1_PHYS_ADDR
+#define SMBUS_PSC_BASE		AU1550_PSC2_PHYS_ADDR
+#define I2S_PSC_BASE		AU1550_PSC3_PHYS_ADDR
 
 /*
  * Timing values as described in databook, * ns value stripped of
-- 
1.7.6


From manuel.lauss@googlemail.com Fri Jul  8 11:18:57 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 08 Jul 2011 11:21:15 +0200 (CEST)
Received: from mail-fx0-f49.google.com ([209.85.161.49]:39803 "EHLO
        mail-fx0-f49.google.com" rhost-flags-OK-OK-OK-OK)
        by eddie.linux-mips.org with ESMTP id S1491779Ab1GHJS5 (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Fri, 8 Jul 2011 11:18:57 +0200
Received: by fxd20 with SMTP id 20so1399607fxd.36
        for <multiple recipients>; Fri, 08 Jul 2011 02:18:51 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=googlemail.com; s=gamma;
        h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references;
        bh=R6kXmSxLrzV06z2bKIWzyhlWBytvYssaF6Axl6sSoFs=;
        b=ffqRQGE0UWkvPRSSB7Cw519PwiMM97xt72fgip82fFlgqhC4wir5sCxKzEZAQ3+Sih
         YdUaoqaN+tuAj5nXXVR5JR4duIomQVBfcj2ZIb6tR8AeA8Uu1Y1zbzfaROMiBsTR1rc1
         yTmL8GWTnpRsYK4T9TeGrAM3X/gG0IpDtH4O8=
Received: by 10.223.10.143 with SMTP id p15mr2758171fap.12.1310116731625;
        Fri, 08 Jul 2011 02:18:51 -0700 (PDT)
Received: from localhost.localdomain (188-22-147-55.adsl.highway.telekom.at [188.22.147.55])
        by mx.google.com with ESMTPS id k26sm7260413fak.24.2011.07.08.02.18.49
        (version=TLSv1/SSLv3 cipher=OTHER);
        Fri, 08 Jul 2011 02:18:50 -0700 (PDT)
From:   Manuel Lauss <manuel.lauss@googlemail.com>
To:     Linux-MIPS <linux-mips@linux-mips.org>,
        Ralf Baechle <ralf@linux-mips.org>
Cc:     Manuel Lauss <manuel.lauss@googlemail.com>
Subject: [PATCH 3/5] MIPS: Alchemy: abstract USB block control register access
Date:   Fri,  8 Jul 2011 11:18:41 +0200
Message-Id: <1310116723-8632-4-git-send-email-manuel.lauss@googlemail.com>
X-Mailer: git-send-email 1.7.6
In-Reply-To: <1310116723-8632-1-git-send-email-manuel.lauss@googlemail.com>
References: <1310116723-8632-1-git-send-email-manuel.lauss@googlemail.com>
X-archive-position: 30592
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: manuel.lauss@googlemail.com
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 5986
Content-Length: 28169
Lines: 924

Au1200 and Au1300 have one or more registers which control access
to the usb blocks as well as PHY configuration.  I don't want
the OHCI/EHCI glues to know about the different registers and bits,
a new file hides the gory details of USB configuration from them.

Signed-off-by: Manuel Lauss <manuel.lauss@googlemail.com>
---
 arch/mips/alchemy/common/Makefile          |    2 +-
 arch/mips/alchemy/common/dma.c             |   12 +-
 arch/mips/alchemy/common/power.c           |   42 ----
 arch/mips/alchemy/common/usb.c             |  337 ++++++++++++++++++++++++++++
 arch/mips/include/asm/mach-au1x00/au1000.h |   84 ++------
 drivers/usb/host/ehci-au1xxx.c             |   77 +------
 drivers/usb/host/ohci-au1xxx.c             |  110 +--------
 7 files changed, 382 insertions(+), 282 deletions(-)
 create mode 100644 arch/mips/alchemy/common/usb.c

diff --git a/arch/mips/alchemy/common/Makefile b/arch/mips/alchemy/common/Makefile
index 27811fe..575db47 100644
--- a/arch/mips/alchemy/common/Makefile
+++ b/arch/mips/alchemy/common/Makefile
@@ -6,7 +6,7 @@
 #
 
 obj-y += prom.o time.o clocks.o platform.o power.o setup.o \
-	sleeper.o dma.o dbdma.o
+	sleeper.o dma.o dbdma.o usb.o
 
 obj-$(CONFIG_ALCHEMY_GPIOINT_AU1000) += irq.o
 
diff --git a/arch/mips/alchemy/common/dma.c b/arch/mips/alchemy/common/dma.c
index 347980e..6652a23 100644
--- a/arch/mips/alchemy/common/dma.c
+++ b/arch/mips/alchemy/common/dma.c
@@ -88,12 +88,12 @@ static const struct dma_dev {
 	{ AU1000_AC97_PHYS_ADDR + 0x08, DMA_DW16 | DMA_DR },	/* AC97 RX c */
 	{ AU1000_UART3_PHYS_ADDR + 0x04, DMA_DW8 | DMA_NC },	/* UART3_TX */
 	{ AU1000_UART3_PHYS_ADDR + 0x00, DMA_DW8 | DMA_NC | DMA_DR }, /* UART3_RX */
-	{ AU1000_USBD_PHYS_ADDR + 0x00, DMA_DW8 | DMA_NC | DMA_DR }, /* EP0RD */
-	{ AU1000_USBD_PHYS_ADDR + 0x04, DMA_DW8 | DMA_NC }, /* EP0WR */
-	{ AU1000_USBD_PHYS_ADDR + 0x08, DMA_DW8 | DMA_NC }, /* EP2WR */
-	{ AU1000_USBD_PHYS_ADDR + 0x0c, DMA_DW8 | DMA_NC }, /* EP3WR */
-	{ AU1000_USBD_PHYS_ADDR + 0x10, DMA_DW8 | DMA_NC | DMA_DR }, /* EP4RD */
-	{ AU1000_USBD_PHYS_ADDR + 0x14, DMA_DW8 | DMA_NC | DMA_DR }, /* EP5RD */
+	{ AU1000_USB_UDC_PHYS_ADDR + 0x00, DMA_DW8 | DMA_NC | DMA_DR }, /* EP0RD */
+	{ AU1000_USB_UDC_PHYS_ADDR + 0x04, DMA_DW8 | DMA_NC }, /* EP0WR */
+	{ AU1000_USB_UDC_PHYS_ADDR + 0x08, DMA_DW8 | DMA_NC }, /* EP2WR */
+	{ AU1000_USB_UDC_PHYS_ADDR + 0x0c, DMA_DW8 | DMA_NC }, /* EP3WR */
+	{ AU1000_USB_UDC_PHYS_ADDR + 0x10, DMA_DW8 | DMA_NC | DMA_DR }, /* EP4RD */
+	{ AU1000_USB_UDC_PHYS_ADDR + 0x14, DMA_DW8 | DMA_NC | DMA_DR }, /* EP5RD */
 	/* on Au1500, these 2 are DMA_REQ2/3 (GPIO208/209) instead! */
 	{ AU1000_I2S_PHYS_ADDR + 0x00, DMA_DW32 | DMA_NC},	/* I2S TX */
 	{ AU1000_I2S_PHYS_ADDR + 0x00, DMA_DW32 | DMA_NC | DMA_DR}, /* I2S RX */
diff --git a/arch/mips/alchemy/common/power.c b/arch/mips/alchemy/common/power.c
index b86324a..e53b4ce 100644
--- a/arch/mips/alchemy/common/power.c
+++ b/arch/mips/alchemy/common/power.c
@@ -49,7 +49,6 @@
  * We only have to save/restore registers that aren't otherwise
  * done as part of a driver pm_* function.
  */
-static unsigned int sleep_usb[2];
 static unsigned int sleep_sys_clocks[5];
 static unsigned int sleep_sys_pinfunc;
 static unsigned int sleep_static_memctlr[4][3];
@@ -57,31 +56,6 @@ static unsigned int sleep_static_memctlr[4][3];
 
 static void save_core_regs(void)
 {
-#ifndef CONFIG_SOC_AU1200
-	/* Shutdown USB host/device. */
-	sleep_usb[0] = au_readl(USB_HOST_CONFIG);
-
-	/* There appears to be some undocumented reset register.... */
-	au_writel(0, 0xb0100004);
-	au_sync();
-	au_writel(0, USB_HOST_CONFIG);
-	au_sync();
-
-	sleep_usb[1] = au_readl(USBD_ENABLE);
-	au_writel(0, USBD_ENABLE);
-	au_sync();
-
-#else	/* AU1200 */
-
-	/* enable access to OTG mmio so we can save OTG CAP/MUX.
-	 * FIXME: write an OTG driver and move this stuff there!
-	 */
-	au_writel(au_readl(USB_MSR_BASE + 4) | (1 << 6), USB_MSR_BASE + 4);
-	au_sync();
-	sleep_usb[0] = au_readl(0xb4020020);	/* OTG_CAP */
-	sleep_usb[1] = au_readl(0xb4020024);	/* OTG_MUX */
-#endif
-
 	/* Clocks and PLLs. */
 	sleep_sys_clocks[0] = au_readl(SYS_FREQCTRL0);
 	sleep_sys_clocks[1] = au_readl(SYS_FREQCTRL1);
@@ -125,22 +99,6 @@ static void restore_core_regs(void)
 	au_writel(sleep_sys_pinfunc, SYS_PINFUNC);
 	au_sync();
 
-#ifndef CONFIG_SOC_AU1200
-	au_writel(sleep_usb[0], USB_HOST_CONFIG);
-	au_writel(sleep_usb[1], USBD_ENABLE);
-	au_sync();
-#else
-	/* enable access to OTG memory */
-	au_writel(au_readl(USB_MSR_BASE + 4) | (1 << 6), USB_MSR_BASE + 4);
-	au_sync();
-
-	/* restore OTG caps and port mux. */
-	au_writel(sleep_usb[0], 0xb4020020 + 0);	/* OTG_CAP */
-	au_sync();
-	au_writel(sleep_usb[1], 0xb4020020 + 4);	/* OTG_MUX */
-	au_sync();
-#endif
-
 	/* Restore the static memory controller configuration. */
 	au_writel(sleep_static_memctlr[0][0], MEM_STCFG0);
 	au_writel(sleep_static_memctlr[0][1], MEM_STTIME0);
diff --git a/arch/mips/alchemy/common/usb.c b/arch/mips/alchemy/common/usb.c
new file mode 100644
index 0000000..f769364
--- /dev/null
+++ b/arch/mips/alchemy/common/usb.c
@@ -0,0 +1,337 @@
+/*
+ * USB block power/access management abstraction.
+ *
+ * Au1000+: The OHCI block control register is at the far end of the OHCI memory
+ *	    area. Au1550 has OHCI on different base address. No need to handle
+ *	    UDC here.
+ * Au1200:  one register to control access and clocks to O/EHCI, UDC and OTG
+ * 	    as well as the PHY for EHCI and UDC.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/syscore_ops.h>
+#include <asm/mach-au1x00/au1000.h>
+
+/* control register offsets */
+#define AU1000_OHCICFG	0x7fffc
+#define AU1550_OHCICFG	0x07ffc
+#define AU1200_USBCFG	0x04
+
+/* Au1000 USB block config bits */
+#define USBHEN_RD	(1 << 4)		/* OHCI reset-done indicator */
+#define USBHEN_CE	(1 << 3)		/* OHCI block clock enable */
+#define USBHEN_E	(1 << 2)		/* OHCI block enable */
+#define USBHEN_C	(1 << 1)		/* OHCI block coherency bit */
+#define USBHEN_BE	(1 << 0)		/* OHCI Big-Endian */
+
+/* Au1200 USB config bits */
+#define USBCFG_PFEN	(1 << 31)		/* prefetch enable (undoc) */
+#define USBCFG_RDCOMB	(1 << 30)		/* read combining (undoc) */
+#define USBCFG_UNKNOWN	(5 << 20)		/* unknown, leave this way */
+#define USBCFG_SSD	(1 << 23)		/* serial short detect en */
+#define USBCFG_PPE	(1 << 19)		/* HS PHY PLL */
+#define USBCFG_UCE	(1 << 18)		/* UDC clock enable */
+#define USBCFG_ECE	(1 << 17)		/* EHCI clock enable */
+#define USBCFG_OCE	(1 << 16)		/* OHCI clock enable */
+#define USBCFG_FLA(x)	(((x) & 0x3f) << 8)
+#define USBCFG_UCAM	(1 << 7)		/* coherent access (undoc) */
+#define USBCFG_GME	(1 << 6)		/* OTG mem access */
+#define USBCFG_DBE	(1 << 5)		/* UDC busmaster enable */
+#define USBCFG_DME	(1 << 4)		/* UDC mem enable */
+#define USBCFG_EBE	(1 << 3)		/* EHCI busmaster enable */
+#define USBCFG_EME	(1 << 2)		/* EHCI mem enable */
+#define USBCFG_OBE	(1 << 1)		/* OHCI busmaster enable */
+#define USBCFG_OME	(1 << 0)		/* OHCI mem enable */
+#define USBCFG_INIT_AU1200	(USBCFG_PFEN | USBCFG_RDCOMB | USBCFG_UNKNOWN |\
+				 USBCFG_SSD | USBCFG_FLA(0x20) | USBCFG_UCAM | \
+				 USBCFG_GME | USBCFG_DBE | USBCFG_DME |	       \
+				 USBCFG_EBE | USBCFG_EME | USBCFG_OBE |	       \
+				 USBCFG_OME)
+
+
+static DEFINE_SPINLOCK(alchemy_usb_lock);
+
+
+static inline void __au1200_ohci_control(void __iomem *base, int enable)
+{
+	unsigned long r = __raw_readl(base + AU1200_USBCFG);
+	if (enable) {
+		__raw_writel(r | USBCFG_OCE, base + AU1200_USBCFG);
+		wmb();
+		udelay(2000);
+	} else {
+		__raw_writel(r & ~USBCFG_OCE, base + AU1200_USBCFG);
+		wmb();
+		udelay(1000);
+	}
+}
+
+static inline void __au1200_ehci_control(void __iomem *base, int enable)
+{
+	unsigned long r = __raw_readl(base + AU1200_USBCFG);
+	if (enable) {
+		__raw_writel(r | USBCFG_ECE | USBCFG_PPE, base + AU1200_USBCFG);
+		wmb();
+		udelay(1000);
+	} else {
+		if (!(r & USBCFG_UCE))		/* UDC also off? */
+			r &= ~USBCFG_PPE;	/* yes: disable HS PHY PLL */
+		__raw_writel(r & ~USBCFG_ECE, base + AU1200_USBCFG);
+		wmb();
+		udelay(1000);
+	}
+}
+
+static inline void __au1200_udc_control(void __iomem *base, int enable)
+{
+	unsigned long r = __raw_readl(base + AU1200_USBCFG);
+	if (enable) {
+		__raw_writel(r | USBCFG_UCE | USBCFG_PPE, base + AU1200_USBCFG);
+		wmb();
+	} else {
+		if (!(r & USBCFG_ECE))		/* EHCI also off? */
+			r &= ~USBCFG_PPE;	/* yes: disable HS PHY PLL */
+		__raw_writel(r & ~USBCFG_UCE, base + AU1200_USBCFG);
+		wmb();
+	}
+}
+
+static inline int au1200_coherency_bug(void)
+{
+#if defined(CONFIG_DMA_COHERENT)
+	/* Au1200 AB USB does not support coherent memory */
+	if (!(read_c0_prid() & 0xff)) {
+		printk(KERN_INFO "Au1200 USB: this is chip revision AB !!\n");
+		printk(KERN_INFO "Au1200 USB: update your board or re-configure"
+				 " the kernel\n");
+		return -ENODEV;
+	}
+#endif
+	return 0;
+}
+
+static inline int au1200_usb_control(int block, int enable)
+{
+	void __iomem *base =
+			(void __iomem *)KSEG1ADDR(AU1200_USB_CTL_PHYS_ADDR);
+	int ret = 0;
+
+	switch (block) {
+	case ALCHEMY_USB_OHCI0:
+		ret = au1200_coherency_bug();
+		if (ret && enable)
+			goto out;
+		__au1200_ohci_control(base, enable);
+		break;
+	case ALCHEMY_USB_UDC0:
+		__au1200_udc_control(base, enable);
+		break;
+	case ALCHEMY_USB_EHCI0:
+		ret = au1200_coherency_bug();
+		if (ret && enable)
+			goto out;
+		__au1200_ehci_control(base, enable);
+		break;
+	default:
+		ret = -ENODEV;
+	}
+out:
+	return ret;
+}
+
+
+/* initialize USB block(s) to a known working state */
+static inline void au1200_usb_init(void)
+{
+	void __iomem *base =
+			(void __iomem *)KSEG1ADDR(AU1200_USB_CTL_PHYS_ADDR);
+	__raw_writel(USBCFG_INIT_AU1200, base + AU1200_USBCFG);
+	wmb();
+	udelay(1000);
+}
+
+static inline void au1000_usb_init(unsigned long rb, int reg)
+{
+	void __iomem *base = (void __iomem *)KSEG1ADDR(rb + reg);
+	unsigned long r = __raw_readl(base);
+
+#if defined(__BIG_ENDIAN)
+	r |= USBHEN_BE;
+#endif
+	r |= USBHEN_C;
+
+	__raw_writel(r, base);
+	wmb();
+	udelay(1000);
+}
+
+
+static inline void __au1xx0_ohci_control(int enable, unsigned long rb, int creg)
+{
+	void __iomem *base = (void __iomem *)KSEG1ADDR(rb);
+	unsigned long r = __raw_readl(base + creg);
+
+	if (enable) {
+		__raw_writel(r | USBHEN_CE, base + creg);
+		wmb();
+		udelay(1000);
+		__raw_writel(r | USBHEN_CE | USBHEN_E, base + creg);
+		wmb();
+		udelay(1000);
+
+		/* wait for reset complete (read reg twice: au1500 erratum) */
+		while (__raw_readl(base + creg),
+			!(__raw_readl(base + creg) & USBHEN_RD))
+			udelay(1000);
+	} else {
+		__raw_writel(r & ~(USBHEN_CE | USBHEN_E), base + creg);
+		wmb();
+	}
+}
+
+static inline int au1000_usb_control(int block, int enable, unsigned long rb,
+				     int creg)
+{
+	int ret = 0;
+
+	switch (block) {
+	case ALCHEMY_USB_OHCI0:
+		__au1xx0_ohci_control(enable, rb, creg);
+		break;
+	default:
+		ret = -ENODEV;
+	}
+	return ret;
+}
+
+/*
+ * alchemy_usb_control - control Alchemy on-chip USB blocks
+ * @block:	USB block to target
+ * @enable:	set 1 to enable a block, 0 to disable
+ */
+int alchemy_usb_control(int block, int enable)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&alchemy_usb_lock, flags);
+	switch (alchemy_get_cputype()) {
+	case ALCHEMY_CPU_AU1000:
+	case ALCHEMY_CPU_AU1500:
+	case ALCHEMY_CPU_AU1100:
+		ret = au1000_usb_control(block, enable,
+				AU1000_USB_OHCI_PHYS_ADDR, AU1000_OHCICFG);
+		break;
+	case ALCHEMY_CPU_AU1550:
+		ret = au1000_usb_control(block, enable,
+				AU1550_USB_OHCI_PHYS_ADDR, AU1550_OHCICFG);
+		break;
+	case ALCHEMY_CPU_AU1200:
+		ret = au1200_usb_control(block, enable);
+		break;
+	default:
+		ret = -ENODEV;
+	}
+	spin_unlock_irqrestore(&alchemy_usb_lock, flags);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(alchemy_usb_control);
+
+
+static unsigned long alchemy_usb_pmdata[2];
+
+static void au1000_usb_pm(unsigned long br, int creg, int susp)
+{
+	void __iomem *base = (void __iomem *)KSEG1ADDR(br);
+
+	if (susp) {
+		alchemy_usb_pmdata[0] = __raw_readl(base + creg);
+		/* There appears to be some undocumented reset register.... */
+		__raw_writel(0, base + 0x04);
+		wmb();
+		__raw_writel(0, base + creg);
+		wmb();
+	} else {
+		__raw_writel(alchemy_usb_pmdata[0], base + creg);
+		wmb();
+	}
+}
+
+static void au1200_usb_pm(int susp)
+{
+	void __iomem *base =
+			(void __iomem *)KSEG1ADDR(AU1200_USB_OTG_PHYS_ADDR);
+	if (susp) {
+		/* save OTG_CAP/MUX registers which indicate port routing */
+		/* FIXME: write an OTG driver to do that */
+		alchemy_usb_pmdata[0] = __raw_readl(base + 0x00);
+		alchemy_usb_pmdata[1] = __raw_readl(base + 0x04);
+	} else {
+		/* restore access to all MMIO areas */
+		au1200_usb_init();
+
+		/* restore OTG_CAP/MUX registers */
+		__raw_writel(alchemy_usb_pmdata[0], base + 0x00);
+		__raw_writel(alchemy_usb_pmdata[1], base + 0x04);
+		wmb();
+	}
+}
+
+static void alchemy_usb_pm(int susp)
+{
+	switch (alchemy_get_cputype()) {
+	case ALCHEMY_CPU_AU1000:
+	case ALCHEMY_CPU_AU1500:
+	case ALCHEMY_CPU_AU1100:
+		au1000_usb_pm(AU1000_USB_OHCI_PHYS_ADDR, AU1000_OHCICFG, susp);
+		break;
+	case ALCHEMY_CPU_AU1550:
+		au1000_usb_pm(AU1550_USB_OHCI_PHYS_ADDR, AU1550_OHCICFG, susp);
+		break;
+	case ALCHEMY_CPU_AU1200:
+		au1200_usb_pm(susp);
+		break;
+	}
+}
+
+static int alchemy_usb_suspend(void)
+{
+	alchemy_usb_pm(1);
+	return 0;
+}
+
+static void alchemy_usb_resume(void)
+{
+	alchemy_usb_pm(0);
+}
+
+static struct syscore_ops alchemy_usb_pm_ops = {
+	.suspend	= alchemy_usb_suspend,
+	.resume		= alchemy_usb_resume,
+};
+
+static int __init alchemy_usb_init(void)
+{
+	switch (alchemy_get_cputype()) {
+	case ALCHEMY_CPU_AU1000:
+	case ALCHEMY_CPU_AU1500:
+	case ALCHEMY_CPU_AU1100:
+		au1000_usb_init(AU1000_USB_OHCI_PHYS_ADDR, AU1000_OHCICFG);
+		break;
+	case ALCHEMY_CPU_AU1550:
+		au1000_usb_init(AU1550_USB_OHCI_PHYS_ADDR, AU1550_OHCICFG);
+		break;
+	case ALCHEMY_CPU_AU1200:
+		au1200_usb_init();
+		break;
+	}
+
+	register_syscore_ops(&alchemy_usb_pm_ops);
+
+	return 0;
+}
+arch_initcall(alchemy_usb_init);
diff --git a/arch/mips/include/asm/mach-au1x00/au1000.h b/arch/mips/include/asm/mach-au1x00/au1000.h
index f260ebe..73e0d79 100644
--- a/arch/mips/include/asm/mach-au1x00/au1000.h
+++ b/arch/mips/include/asm/mach-au1x00/au1000.h
@@ -245,6 +245,15 @@ void alchemy_sleep_au1000(void);
 void alchemy_sleep_au1550(void);
 void au_sleep(void);
 
+/* USB: arch/mips/alchemy/common/usb.c */
+enum alchemy_usb_block {
+	ALCHEMY_USB_OHCI0,
+	ALCHEMY_USB_UDC0,
+	ALCHEMY_USB_EHCI0,
+	ALCHEMY_USB_OTG0,
+};
+int alchemy_usb_control(int block, int enable);
+
 
 /* SOC Interrupt numbers */
 
@@ -687,7 +696,8 @@ enum soc_au1200_ints {
  */
 
 #define AU1000_AC97_PHYS_ADDR		0x10000000 /* 012 */
-#define AU1000_USBD_PHYS_ADDR		0x10200000 /* 0123 */
+#define AU1000_USB_OHCI_PHYS_ADDR	0x10100000 /* 012 */
+#define AU1000_USB_UDC_PHYS_ADDR	0x10200000 /* 0123 */
 #define AU1000_IC0_PHYS_ADDR		0x10400000 /* 01234 */
 #define AU1000_MAC0_PHYS_ADDR		0x10500000 /* 023 */
 #define AU1000_MAC1_PHYS_ADDR		0x10510000 /* 023 */
@@ -710,12 +720,17 @@ enum soc_au1200_ints {
 #define AU1550_DBDMA_CONF_PHYS_ADDR	0x14003000 /* 34 */
 #define AU1000_MACDMA0_PHYS_ADDR	0x14004000 /* 0123 */
 #define AU1000_MACDMA1_PHYS_ADDR	0x14004200 /* 0123 */
+#define AU1550_USB_OHCI_PHYS_ADDR	0x14020000 /* 3 */
+#define AU1200_USB_CTL_PHYS_ADDR	0x14020000 /* 4 */
+#define AU1200_USB_OTG_PHYS_ADDR	0x14020020 /* 4 */
+#define AU1200_USB_OHCI_PHYS_ADDR	0x14020100 /* 4 */
+#define AU1200_USB_EHCI_PHYS_ADDR	0x14020200 /* 4 */
+#define AU1200_USB_UDC_PHYS_ADDR	0x14022000 /* 4 */
 
 
 #ifdef CONFIG_SOC_AU1000
 #define	MEM_PHYS_ADDR		0x14000000
 #define	STATIC_MEM_PHYS_ADDR	0x14001000
-#define	USBH_PHYS_ADDR		0x10100000
 #define	IRDA_PHYS_ADDR		0x10300000
 #define	SSI0_PHYS_ADDR		0x11600000
 #define	SSI1_PHYS_ADDR		0x11680000
@@ -729,7 +744,6 @@ enum soc_au1200_ints {
 #ifdef CONFIG_SOC_AU1500
 #define	MEM_PHYS_ADDR		0x14000000
 #define	STATIC_MEM_PHYS_ADDR	0x14001000
-#define	USBH_PHYS_ADDR		0x10100000
 #define PCI_PHYS_ADDR		0x14005000
 #define PCI_MEM_PHYS_ADDR	0x400000000ULL
 #define PCI_IO_PHYS_ADDR	0x500000000ULL
@@ -745,7 +759,6 @@ enum soc_au1200_ints {
 #ifdef CONFIG_SOC_AU1100
 #define	MEM_PHYS_ADDR		0x14000000
 #define	STATIC_MEM_PHYS_ADDR	0x14001000
-#define	USBH_PHYS_ADDR		0x10100000
 #define	IRDA_PHYS_ADDR		0x10300000
 #define	SSI0_PHYS_ADDR		0x11600000
 #define	SSI1_PHYS_ADDR		0x11680000
@@ -760,7 +773,6 @@ enum soc_au1200_ints {
 #ifdef CONFIG_SOC_AU1550
 #define	MEM_PHYS_ADDR		0x14000000
 #define	STATIC_MEM_PHYS_ADDR	0x14001000
-#define	USBH_PHYS_ADDR		0x14020000
 #define PCI_PHYS_ADDR		0x14005000
 #define PE_PHYS_ADDR		0x14008000
 #define PSC0_PHYS_ADDR		0x11A00000
@@ -783,8 +795,6 @@ enum soc_au1200_ints {
 #define	STATIC_MEM_PHYS_ADDR	0x14001000
 #define AES_PHYS_ADDR		0x10300000
 #define CIM_PHYS_ADDR		0x14004000
-#define USBM_PHYS_ADDR		0x14020000
-#define	USBH_PHYS_ADDR		0x14020100
 #define PSC0_PHYS_ADDR	 	0x11A00000
 #define PSC1_PHYS_ADDR	 	0x11B00000
 #define LCD_PHYS_ADDR		0x15000000
@@ -868,21 +878,6 @@ enum soc_au1200_ints {
 #define USB_EHCI_LEN		0x100
 #define USB_UDC_BASE		0x14022000
 #define USB_UDC_LEN		0x2000
-#define USB_MSR_BASE		0xB4020000
-#define USB_MSR_MCFG		4
-#define USBMSRMCFG_OMEMEN	0
-#define USBMSRMCFG_OBMEN	1
-#define USBMSRMCFG_EMEMEN	2
-#define USBMSRMCFG_EBMEN	3
-#define USBMSRMCFG_DMEMEN	4
-#define USBMSRMCFG_DBMEN	5
-#define USBMSRMCFG_GMEMEN	6
-#define USBMSRMCFG_OHCCLKEN	16
-#define USBMSRMCFG_EHCCLKEN	17
-#define USBMSRMCFG_UDCCLKEN	18
-#define USBMSRMCFG_PHYPLLEN	19
-#define USBMSRMCFG_RDCOMB	30
-#define USBMSRMCFG_PFEN 	31
 
 #define FOR_PLATFORM_C_USB_HOST_INT AU1200_USB_INT
 
@@ -963,51 +958,6 @@ enum soc_au1200_ints {
 #define USB_OHCI_LEN		0x00100000
 #endif
 
-#ifndef CONFIG_SOC_AU1200
-
-/* USB Device Controller */
-#define USBD_EP0RD		0xB0200000
-#define USBD_EP0WR		0xB0200004
-#define USBD_EP2WR		0xB0200008
-#define USBD_EP3WR		0xB020000C
-#define USBD_EP4RD		0xB0200010
-#define USBD_EP5RD		0xB0200014
-#define USBD_INTEN		0xB0200018
-#define USBD_INTSTAT		0xB020001C
-#  define USBDEV_INT_SOF	(1 << 12)
-#  define USBDEV_INT_HF_BIT	6
-#  define USBDEV_INT_HF_MASK	(0x3f << USBDEV_INT_HF_BIT)
-#  define USBDEV_INT_CMPLT_BIT	0
-#  define USBDEV_INT_CMPLT_MASK (0x3f << USBDEV_INT_CMPLT_BIT)
-#define USBD_CONFIG		0xB0200020
-#define USBD_EP0CS		0xB0200024
-#define USBD_EP2CS		0xB0200028
-#define USBD_EP3CS		0xB020002C
-#define USBD_EP4CS		0xB0200030
-#define USBD_EP5CS		0xB0200034
-#  define USBDEV_CS_SU		(1 << 14)
-#  define USBDEV_CS_NAK 	(1 << 13)
-#  define USBDEV_CS_ACK 	(1 << 12)
-#  define USBDEV_CS_BUSY	(1 << 11)
-#  define USBDEV_CS_TSIZE_BIT	1
-#  define USBDEV_CS_TSIZE_MASK	(0x3ff << USBDEV_CS_TSIZE_BIT)
-#  define USBDEV_CS_STALL	(1 << 0)
-#define USBD_EP0RDSTAT		0xB0200040
-#define USBD_EP0WRSTAT		0xB0200044
-#define USBD_EP2WRSTAT		0xB0200048
-#define USBD_EP3WRSTAT		0xB020004C
-#define USBD_EP4RDSTAT		0xB0200050
-#define USBD_EP5RDSTAT		0xB0200054
-#  define USBDEV_FSTAT_FLUSH	(1 << 6)
-#  define USBDEV_FSTAT_UF	(1 << 5)
-#  define USBDEV_FSTAT_OF	(1 << 4)
-#  define USBDEV_FSTAT_FCNT_BIT 0
-#  define USBDEV_FSTAT_FCNT_MASK (0x0f << USBDEV_FSTAT_FCNT_BIT)
-#define USBD_ENABLE		0xB0200058
-#  define USBDEV_ENABLE 	(1 << 1)
-#  define USBDEV_CE		(1 << 0)
-
-#endif /* !CONFIG_SOC_AU1200 */
 
 /* Ethernet Controllers  */
 
diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c
index 42ae574..e480dc1 100644
--- a/drivers/usb/host/ehci-au1xxx.c
+++ b/drivers/usb/host/ehci-au1xxx.c
@@ -14,61 +14,9 @@
 #include <linux/platform_device.h>
 #include <asm/mach-au1x00/au1000.h>
 
-#define USB_HOST_CONFIG   (USB_MSR_BASE + USB_MSR_MCFG)
-#define USB_MCFG_PFEN     (1<<31)
-#define USB_MCFG_RDCOMB   (1<<30)
-#define USB_MCFG_SSDEN    (1<<23)
-#define USB_MCFG_PHYPLLEN (1<<19)
-#define USB_MCFG_UCECLKEN (1<<18)
-#define USB_MCFG_EHCCLKEN (1<<17)
-#ifdef CONFIG_DMA_COHERENT
-#define USB_MCFG_UCAM     (1<<7)
-#else
-#define USB_MCFG_UCAM     (0)
-#endif
-#define USB_MCFG_EBMEN    (1<<3)
-#define USB_MCFG_EMEMEN   (1<<2)
-
-#define USBH_ENABLE_CE	(USB_MCFG_PHYPLLEN | USB_MCFG_EHCCLKEN)
-#define USBH_ENABLE_INIT (USB_MCFG_PFEN  | USB_MCFG_RDCOMB |	\
-			  USBH_ENABLE_CE | USB_MCFG_SSDEN  |	\
-			  USB_MCFG_UCAM  | USB_MCFG_EBMEN  |	\
-			  USB_MCFG_EMEMEN)
-
-#define USBH_DISABLE      (USB_MCFG_EBMEN | USB_MCFG_EMEMEN)
 
 extern int usb_disabled(void);
 
-static void au1xxx_start_ehc(void)
-{
-	/* enable clock to EHCI block and HS PHY PLL*/
-	au_writel(au_readl(USB_HOST_CONFIG) | USBH_ENABLE_CE, USB_HOST_CONFIG);
-	au_sync();
-	udelay(1000);
-
-	/* enable EHCI mmio */
-	au_writel(au_readl(USB_HOST_CONFIG) | USBH_ENABLE_INIT, USB_HOST_CONFIG);
-	au_sync();
-	udelay(1000);
-}
-
-static void au1xxx_stop_ehc(void)
-{
-	unsigned long c;
-
-	/* Disable mem */
-	au_writel(au_readl(USB_HOST_CONFIG) & ~USBH_DISABLE, USB_HOST_CONFIG);
-	au_sync();
-	udelay(1000);
-
-	/* Disable EHC clock. If the HS PHY is unused disable it too. */
-	c = au_readl(USB_HOST_CONFIG) & ~USB_MCFG_EHCCLKEN;
-	if (!(c & USB_MCFG_UCECLKEN))		/* UDC disabled? */
-		c &= ~USB_MCFG_PHYPLLEN;	/* yes: disable HS PHY PLL */
-	au_writel(c, USB_HOST_CONFIG);
-	au_sync();
-}
-
 static int au1xxx_ehci_setup(struct usb_hcd *hcd)
 {
 	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
@@ -136,16 +84,6 @@ static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
 	if (usb_disabled())
 		return -ENODEV;
 
-#if defined(CONFIG_SOC_AU1200) && defined(CONFIG_DMA_COHERENT)
-	/* Au1200 AB USB does not support coherent memory */
-	if (!(read_c0_prid() & 0xff)) {
-		printk(KERN_INFO "%s: this is chip revision AB!\n", pdev->name);
-		printk(KERN_INFO "%s: update your board or re-configure"
-				 " the kernel\n", pdev->name);
-		return -ENODEV;
-	}
-#endif
-
 	if (pdev->resource[1].flags != IORESOURCE_IRQ) {
 		pr_debug("resource[1] is not IORESOURCE_IRQ");
 		return -ENOMEM;
@@ -171,7 +109,11 @@ static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
 		goto err2;
 	}
 
-	au1xxx_start_ehc();
+	if (alchemy_usb_control(ALCHEMY_USB_EHCI0, 1)) {
+		printk(KERN_INFO "%s: controller init failed!\n", pdev->name);
+		ret = -ENODEV;
+		goto err3;
+	}
 
 	ehci = hcd_to_ehci(hcd);
 	ehci->caps = hcd->regs;
@@ -187,7 +129,8 @@ static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	au1xxx_stop_ehc();
+	alchemy_usb_control(ALCHEMY_USB_EHCI0, 0);
+err3:
 	iounmap(hcd->regs);
 err2:
 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
@@ -201,10 +144,10 @@ static int ehci_hcd_au1xxx_drv_remove(struct platform_device *pdev)
 	struct usb_hcd *hcd = platform_get_drvdata(pdev);
 
 	usb_remove_hcd(hcd);
+	alchemy_usb_control(ALCHEMY_USB_EHCI0, 0);
 	iounmap(hcd->regs);
 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 	usb_put_hcd(hcd);
-	au1xxx_stop_ehc();
 	platform_set_drvdata(pdev, NULL);
 
 	return 0;
@@ -236,7 +179,7 @@ static int ehci_hcd_au1xxx_drv_suspend(struct device *dev)
 	// could save FLADJ in case of Vaux power loss
 	// ... we'd only use it to handle clock skew
 
-	au1xxx_stop_ehc();
+	alchemy_usb_control(ALCHEMY_USB_EHCI0, 0);
 
 	return rc;
 }
@@ -246,7 +189,7 @@ static int ehci_hcd_au1xxx_drv_resume(struct device *dev)
 	struct usb_hcd *hcd = dev_get_drvdata(dev);
 	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
 
-	au1xxx_start_ehc();
+	alchemy_usb_control(ALCHEMY_USB_EHCI0, 1);
 
 	// maybe restore FLADJ
 
diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c
index 958d985..299d719 100644
--- a/drivers/usb/host/ohci-au1xxx.c
+++ b/drivers/usb/host/ohci-au1xxx.c
@@ -23,92 +23,9 @@
 
 #include <asm/mach-au1x00/au1000.h>
 
-#ifndef	CONFIG_SOC_AU1200
-
-#define USBH_ENABLE_BE (1<<0)
-#define USBH_ENABLE_C  (1<<1)
-#define USBH_ENABLE_E  (1<<2)
-#define USBH_ENABLE_CE (1<<3)
-#define USBH_ENABLE_RD (1<<4)
-
-#ifdef __LITTLE_ENDIAN
-#define USBH_ENABLE_INIT (USBH_ENABLE_CE | USBH_ENABLE_E | USBH_ENABLE_C)
-#elif defined(__BIG_ENDIAN)
-#define USBH_ENABLE_INIT (USBH_ENABLE_CE | USBH_ENABLE_E | USBH_ENABLE_C | \
-			  USBH_ENABLE_BE)
-#else
-#error not byte order defined
-#endif
-
-#else   /* Au1200 */
-
-#define USB_HOST_CONFIG    (USB_MSR_BASE + USB_MSR_MCFG)
-#define USB_MCFG_PFEN     (1<<31)
-#define USB_MCFG_RDCOMB   (1<<30)
-#define USB_MCFG_SSDEN    (1<<23)
-#define USB_MCFG_OHCCLKEN (1<<16)
-#ifdef CONFIG_DMA_COHERENT
-#define USB_MCFG_UCAM     (1<<7)
-#else
-#define USB_MCFG_UCAM     (0)
-#endif
-#define USB_MCFG_OBMEN    (1<<1)
-#define USB_MCFG_OMEMEN   (1<<0)
-
-#define USBH_ENABLE_CE    USB_MCFG_OHCCLKEN
-
-#define USBH_ENABLE_INIT  (USB_MCFG_PFEN  | USB_MCFG_RDCOMB 	|	\
-			   USBH_ENABLE_CE | USB_MCFG_SSDEN	|	\
-			   USB_MCFG_UCAM  |				\
-			   USB_MCFG_OBMEN | USB_MCFG_OMEMEN)
-
-#define USBH_DISABLE      (USB_MCFG_OBMEN | USB_MCFG_OMEMEN)
-
-#endif  /* Au1200 */
 
 extern int usb_disabled(void);
 
-static void au1xxx_start_ohc(void)
-{
-	/* enable host controller */
-#ifndef CONFIG_SOC_AU1200
-	au_writel(USBH_ENABLE_CE, USB_HOST_CONFIG);
-	au_sync();
-	udelay(1000);
-
-	au_writel(au_readl(USB_HOST_CONFIG) | USBH_ENABLE_INIT, USB_HOST_CONFIG);
-	au_sync();
-	udelay(1000);
-
-	/* wait for reset complete (read register twice; see au1500 errata) */
-	while (au_readl(USB_HOST_CONFIG),
-		!(au_readl(USB_HOST_CONFIG) & USBH_ENABLE_RD))
-		udelay(1000);
-
-#else   /* Au1200 */
-	au_writel(au_readl(USB_HOST_CONFIG) | USBH_ENABLE_CE, USB_HOST_CONFIG);
-	au_sync();
-	udelay(1000);
-
-	au_writel(au_readl(USB_HOST_CONFIG) | USBH_ENABLE_INIT, USB_HOST_CONFIG);
-	au_sync();
-	udelay(2000);
-#endif  /* Au1200 */
-}
-
-static void au1xxx_stop_ohc(void)
-{
-#ifdef CONFIG_SOC_AU1200
-	/* Disable mem */
-	au_writel(au_readl(USB_HOST_CONFIG) & ~USBH_DISABLE, USB_HOST_CONFIG);
-	au_sync();
-	udelay(1000);
-#endif
-	/* Disable clock */
-	au_writel(au_readl(USB_HOST_CONFIG) & ~USBH_ENABLE_CE, USB_HOST_CONFIG);
-	au_sync();
-}
-
 static int __devinit ohci_au1xxx_start(struct usb_hcd *hcd)
 {
 	struct ohci_hcd	*ohci = hcd_to_ohci(hcd);
@@ -178,17 +95,6 @@ static int ohci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
 	if (usb_disabled())
 		return -ENODEV;
 
-#if defined(CONFIG_SOC_AU1200) && defined(CONFIG_DMA_COHERENT)
-	/* Au1200 AB USB does not support coherent memory */
-	if (!(read_c0_prid() & 0xff)) {
-		printk(KERN_INFO "%s: this is chip revision AB !!\n",
-			pdev->name);
-		printk(KERN_INFO "%s: update your board or re-configure "
-				 "the kernel\n", pdev->name);
-		return -ENODEV;
-	}
-#endif
-
 	if (pdev->resource[1].flags != IORESOURCE_IRQ) {
 		pr_debug("resource[1] is not IORESOURCE_IRQ\n");
 		return -ENOMEM;
@@ -214,7 +120,12 @@ static int ohci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
 		goto err2;
 	}
 
-	au1xxx_start_ohc();
+	if (alchemy_usb_control(ALCHEMY_USB_OHCI0, 1)) {
+		printk(KERN_INFO "%s: controller init failed!\n", pdev->name);
+		ret = -ENODEV;
+		goto err3;
+	}
+
 	ohci_hcd_init(hcd_to_ohci(hcd));
 
 	ret = usb_add_hcd(hcd, pdev->resource[1].start,
@@ -224,7 +135,8 @@ static int ohci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	au1xxx_stop_ohc();
+	alchemy_usb_control(ALCHEMY_USB_OHCI0, 0);
+err3:
 	iounmap(hcd->regs);
 err2:
 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
@@ -238,7 +150,7 @@ static int ohci_hcd_au1xxx_drv_remove(struct platform_device *pdev)
 	struct usb_hcd *hcd = platform_get_drvdata(pdev);
 
 	usb_remove_hcd(hcd);
-	au1xxx_stop_ohc();
+	alchemy_usb_control(ALCHEMY_USB_OHCI0, 0);
 	iounmap(hcd->regs);
 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 	usb_put_hcd(hcd);
@@ -275,7 +187,7 @@ static int ohci_hcd_au1xxx_drv_suspend(struct device *dev)
 
 	clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
 
-	au1xxx_stop_ohc();
+	alchemy_usb_control(ALCHEMY_USB_OHCI0, 0);
 bail:
 	spin_unlock_irqrestore(&ohci->lock, flags);
 
@@ -286,7 +198,7 @@ static int ohci_hcd_au1xxx_drv_resume(struct device *dev)
 {
 	struct usb_hcd *hcd = dev_get_drvdata(dev);
 
-	au1xxx_start_ohc();
+	alchemy_usb_control(ALCHEMY_USB_OHCI0, 1);
 
 	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
 	ohci_finish_controller_resume(hcd);
-- 
1.7.6


From hauke@hauke-m.de Sat Jul  9 13:06:29 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 09 Jul 2011 13:06:40 +0200 (CEST)
Received: from server19320154104.serverpool.info ([193.201.54.104]:41900 "EHLO
        hauke-m.de" rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org
        with ESMTP id S1491151Ab1GILG3 (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Sat, 9 Jul 2011 13:06:29 +0200
Received: from localhost (localhost [127.0.0.1])
        by hauke-m.de (Postfix) with ESMTP id D587D8C68;
        Sat,  9 Jul 2011 13:06:28 +0200 (CEST)
X-Virus-Scanned: Debian amavisd-new at hauke-m.de 
Received: from hauke-m.de ([127.0.0.1])
        by localhost (hauke-m.de [127.0.0.1]) (amavisd-new, port 10024)
        with ESMTP id ib9-Oyhirrq3; Sat,  9 Jul 2011 13:06:24 +0200 (CEST)
Received: from localhost.localdomain (dyndsl-095-033-240-133.ewe-ip-backbone.de [95.33.240.133])
        by hauke-m.de (Postfix) with ESMTPSA id 52C418C62;
        Sat,  9 Jul 2011 13:06:23 +0200 (CEST)
From:   Hauke Mehrtens <hauke@hauke-m.de>
To:     ralf@linux-mips.org, linux-wireless@vger.kernel.org,
        zajec5@gmail.com, linux-mips@linux-mips.org
Cc:     mb@bu3sch.de, george@znau.edu.ua, arend@broadcom.com,
        b43-dev@lists.infradead.org, bernhardloos@googlemail.com,
        arnd@arndb.de, julian.calaby@gmail.com, sshtylyov@mvista.com,
        Hauke Mehrtens <hauke@hauke-m.de>
Subject: [PATCH 01/11] bcma: move parsing of EEPROM into own function.
Date:   Sat,  9 Jul 2011 13:05:53 +0200
Message-Id: <1310209563-6405-2-git-send-email-hauke@hauke-m.de>
X-Mailer: git-send-email 1.7.4.1
In-Reply-To: <1310209563-6405-1-git-send-email-hauke@hauke-m.de>
References: <1310209563-6405-1-git-send-email-hauke@hauke-m.de>
X-archive-position: 30593
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: hauke@hauke-m.de
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 6773
Content-Length: 7162
Lines: 274

Move the parsing of the EEPROM data in scan function for one core into
an own function. Now we are able to use it in some other scan function
as well.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 drivers/bcma/scan.c |  230 ++++++++++++++++++++++++++-------------------------
 1 files changed, 118 insertions(+), 112 deletions(-)

diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c
index 40d7dcc..4012d8d 100644
--- a/drivers/bcma/scan.c
+++ b/drivers/bcma/scan.c
@@ -200,16 +200,124 @@ static s32 bcma_erom_get_addr_desc(struct bcma_bus *bus, u32 **eromptr,
 	return addrl;
 }
 
+static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
+			      struct bcma_device *core)
+{
+	s32 tmp;
+	u8 i, j;
+	s32 cia, cib;
+	u8 ports[2], wrappers[2];
+
+	/* get CIs */
+	cia = bcma_erom_get_ci(bus, eromptr);
+	if (cia < 0) {
+		bcma_erom_push_ent(eromptr);
+		if (bcma_erom_is_end(bus, eromptr))
+			return -ESPIPE;
+		return -EILSEQ;
+	}
+	cib = bcma_erom_get_ci(bus, eromptr);
+	if (cib < 0)
+		return -EILSEQ;
+
+	/* parse CIs */
+	core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT;
+	core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT;
+	core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT;
+	ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT;
+	ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT;
+	wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT;
+	wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT;
+	core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT;
+
+	if (((core->id.manuf == BCMA_MANUF_ARM) &&
+	     (core->id.id == 0xFFF)) ||
+	    (ports[1] == 0)) {
+		bcma_erom_skip_component(bus, eromptr);
+		return -ENXIO;
+	}
+
+	/* check if component is a core at all */
+	if (wrappers[0] + wrappers[1] == 0) {
+		/* we could save addrl of the router
+		if (cid == BCMA_CORE_OOB_ROUTER)
+		 */
+		bcma_erom_skip_component(bus, eromptr);
+		return -ENXIO;
+	}
+
+	if (bcma_erom_is_bridge(bus, eromptr)) {
+		bcma_erom_skip_component(bus, eromptr);
+		return -ENXIO;
+	}
+
+	/* get & parse master ports */
+	for (i = 0; i < ports[0]; i++) {
+		u32 mst_port_d = bcma_erom_get_mst_port(bus, eromptr);
+		if (mst_port_d < 0)
+			return -EILSEQ;
+	}
+
+	/* get & parse slave ports */
+	for (i = 0; i < ports[1]; i++) {
+		for (j = 0; ; j++) {
+			tmp = bcma_erom_get_addr_desc(bus, eromptr,
+				SCAN_ADDR_TYPE_SLAVE, i);
+			if (tmp < 0) {
+				/* no more entries for port _i_ */
+				/* pr_debug("erom: slave port %d "
+				 * "has %d descriptors\n", i, j); */
+				break;
+			} else {
+				if (i == 0 && j == 0)
+					core->addr = tmp;
+			}
+		}
+	}
+
+	/* get & parse master wrappers */
+	for (i = 0; i < wrappers[0]; i++) {
+		for (j = 0; ; j++) {
+			tmp = bcma_erom_get_addr_desc(bus, eromptr,
+				SCAN_ADDR_TYPE_MWRAP, i);
+			if (tmp < 0) {
+				/* no more entries for port _i_ */
+				/* pr_debug("erom: master wrapper %d "
+				 * "has %d descriptors\n", i, j); */
+				break;
+			} else {
+				if (i == 0 && j == 0)
+					core->wrap = tmp;
+			}
+		}
+	}
+
+	/* get & parse slave wrappers */
+	for (i = 0; i < wrappers[1]; i++) {
+		u8 hack = (ports[1] == 1) ? 0 : 1;
+		for (j = 0; ; j++) {
+			tmp = bcma_erom_get_addr_desc(bus, eromptr,
+				SCAN_ADDR_TYPE_SWRAP, i + hack);
+			if (tmp < 0) {
+				/* no more entries for port _i_ */
+				/* pr_debug("erom: master wrapper %d "
+				 * has %d descriptors\n", i, j); */
+				break;
+			} else {
+				if (wrappers[0] == 0 && !i && !j)
+					core->wrap = tmp;
+			}
+		}
+	}
+	return 0;
+}
+
 int bcma_bus_scan(struct bcma_bus *bus)
 {
 	u32 erombase;
 	u32 __iomem *eromptr, *eromend;
 
-	s32 cia, cib;
-	u8 ports[2], wrappers[2];
-
 	s32 tmp;
-	u8 i, j;
 
 	int err;
 
@@ -236,112 +344,13 @@ int bcma_bus_scan(struct bcma_bus *bus)
 		INIT_LIST_HEAD(&core->list);
 		core->bus = bus;
 
-		/* get CIs */
-		cia = bcma_erom_get_ci(bus, &eromptr);
-		if (cia < 0) {
-			bcma_erom_push_ent(&eromptr);
-			if (bcma_erom_is_end(bus, &eromptr))
-				break;
-			err= -EILSEQ;
-			goto out;
-		}
-		cib = bcma_erom_get_ci(bus, &eromptr);
-		if (cib < 0) {
-			err= -EILSEQ;
-			goto out;
-		}
-
-		/* parse CIs */
-		core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT;
-		core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT;
-		core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT;
-		ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT;
-		ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT;
-		wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT;
-		wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT;
-		core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT;
-
-		if (((core->id.manuf == BCMA_MANUF_ARM) &&
-		     (core->id.id == 0xFFF)) ||
-		    (ports[1] == 0)) {
-			bcma_erom_skip_component(bus, &eromptr);
-			continue;
-		}
-
-		/* check if component is a core at all */
-		if (wrappers[0] + wrappers[1] == 0) {
-			/* we could save addrl of the router
-			if (cid == BCMA_CORE_OOB_ROUTER)
-			 */
-			bcma_erom_skip_component(bus, &eromptr);
-			continue;
-		}
-
-		if (bcma_erom_is_bridge(bus, &eromptr)) {
-			bcma_erom_skip_component(bus, &eromptr);
+		err = bcma_get_next_core(bus, &eromptr, core);
+		if (err == -ENXIO)
 			continue;
-		}
-
-		/* get & parse master ports */
-		for (i = 0; i < ports[0]; i++) {
-			u32 mst_port_d = bcma_erom_get_mst_port(bus, &eromptr);
-			if (mst_port_d < 0) {
-				err= -EILSEQ;
-				goto out;
-			}
-		}
-
-		/* get & parse slave ports */
-		for (i = 0; i < ports[1]; i++) {
-			for (j = 0; ; j++) {
-				tmp = bcma_erom_get_addr_desc(bus, &eromptr,
-					SCAN_ADDR_TYPE_SLAVE, i);
-				if (tmp < 0) {
-					/* no more entries for port _i_ */
-					/* pr_debug("erom: slave port %d "
-					 * "has %d descriptors\n", i, j); */
-					break;
-				} else {
-					if (i == 0 && j == 0)
-						core->addr = tmp;
-				}
-			}
-		}
-
-		/* get & parse master wrappers */
-		for (i = 0; i < wrappers[0]; i++) {
-			for (j = 0; ; j++) {
-				tmp = bcma_erom_get_addr_desc(bus, &eromptr,
-					SCAN_ADDR_TYPE_MWRAP, i);
-				if (tmp < 0) {
-					/* no more entries for port _i_ */
-					/* pr_debug("erom: master wrapper %d "
-					 * "has %d descriptors\n", i, j); */
-					break;
-				} else {
-					if (i == 0 && j == 0)
-						core->wrap = tmp;
-				}
-			}
-		}
-
-		/* get & parse slave wrappers */
-		for (i = 0; i < wrappers[1]; i++) {
-			u8 hack = (ports[1] == 1) ? 0 : 1;
-			for (j = 0; ; j++) {
-				tmp = bcma_erom_get_addr_desc(bus, &eromptr,
-					SCAN_ADDR_TYPE_SWRAP, i + hack);
-				if (tmp < 0) {
-					/* no more entries for port _i_ */
-					/* pr_debug("erom: master wrapper %d "
-					 * has %d descriptors\n", i, j); */
-					break;
-				} else {
-					if (wrappers[0] == 0 && !i && !j)
-						core->wrap = tmp;
-				}
-			}
-		}
+		else if (err == -ESPIPE)
+			break;
+		else if (err < 0)
+			return err;
 
 		pr_info("Core %d found: %s "
 			"(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
@@ -351,9 +360,6 @@ int bcma_bus_scan(struct bcma_bus *bus)
 
 		core->core_index = bus->nr_cores++;
 		list_add(&core->list, &bus->cores);
-		continue;
-out:
-		return err;
 	}
 
 	return 0;
-- 
1.7.4.1


From hauke@hauke-m.de Sat Jul  9 13:06:29 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 09 Jul 2011 13:07:24 +0200 (CEST)
Received: from server19320154104.serverpool.info ([193.201.54.104]:41885 "EHLO
        hauke-m.de" rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org
        with ESMTP id S1491147Ab1GILG3 (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Sat, 9 Jul 2011 13:06:29 +0200
Received: from localhost (localhost [127.0.0.1])
        by hauke-m.de (Postfix) with ESMTP id E02CE8C66;
        Sat,  9 Jul 2011 13:06:26 +0200 (CEST)
X-Virus-Scanned: Debian amavisd-new at hauke-m.de 
Received: from hauke-m.de ([127.0.0.1])
        by localhost (hauke-m.de [127.0.0.1]) (amavisd-new, port 10024)
        with ESMTP id xTaM+1bSrEjC; Sat,  9 Jul 2011 13:06:23 +0200 (CEST)
Received: from localhost.localdomain (dyndsl-095-033-240-133.ewe-ip-backbone.de [95.33.240.133])
        by hauke-m.de (Postfix) with ESMTPSA id 4AA2E8C4F;
        Sat,  9 Jul 2011 13:06:22 +0200 (CEST)
From:   Hauke Mehrtens <hauke@hauke-m.de>
To:     ralf@linux-mips.org, linux-wireless@vger.kernel.org,
        zajec5@gmail.com, linux-mips@linux-mips.org
Cc:     mb@bu3sch.de, george@znau.edu.ua, arend@broadcom.com,
        b43-dev@lists.infradead.org, bernhardloos@googlemail.com,
        arnd@arndb.de, julian.calaby@gmail.com, sshtylyov@mvista.com,
        Hauke Mehrtens <hauke@hauke-m.de>
Subject: =?UTF-8?q?=5BPATCH=2000/11=5D=20bcma=3A=20add=20support=20for=20embedded=20devices=20like=20bcm4716?=
Date:   Sat,  9 Jul 2011 13:05:52 +0200
Message-Id: <1310209563-6405-1-git-send-email-hauke@hauke-m.de>
X-Mailer: git-send-email 1.7.4.1
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-archive-position: 30594
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: hauke@hauke-m.de
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 6774
Content-Length: 4020
Lines: 89

This patch series adds support for embedded devices like bcm47xx to 
bcma. Bcma is used on bcm4716 and bcm4718 SoCs as the system bus and
replaced ssb used on older devices. With these patches my bcm4716 
device boots up till it tries to access the flash, because the serial 
flash chip is unsupported for now, this will be my next task. This adds 
support for MIPS cores, interrupt configuration and the serial console.

These patches are not containing all functions needed to get the SoC to 
fully work and support every feature, but it is a good start.
These patches are now integrated in OpenWrt for everyone how wants to
test them.

This was tested with a BCM4704 device (SoC with ssb bus), a BCM4716 
device and a pcie wireless card supported by bcma.


@RafaÅ‚: If you are fine with the bcma patches could you please give
your Signed-off on them.

PATCH v1:
 * rebased on mips tree (mips/queue)
 * drop pcie hostmode patch as RafaÅ‚ sent a better patch to wireless mailing list
 * drop sprom patch because sprom is not supported in bcma version from mips tree,
     I will send a separate patch to wireless mailing list.
 * fix compilation of arch/mips/bcm47xx/wgt634u.c
 * fix texts in arch/mips/bcm47xx/Kconfig
RFC v3:
 * make bcm47xx built either with bcma, ssb or both and use mips MIPS 74K optimizations if possible
 * add block io support
 * some minor fixes for code and doku
RFC v2:
 * use list and no arry to store cores
 * rename bcma_host_bcma_ to bcma_host_soc_
 * use core->io_addr and core->io_wrap to access cores
 * checkpatch fixes
 * some minor fixes


Hauke Mehrtens (11):
  bcma: move parsing of EEPROM into own function.
  bcma: move initializing of struct bcma_bus to own function.
  bcma: add functions to scan cores needed on SoCs
  bcma: add SOC bus
  bcma: add mips driver
  bcma: add serial console support
  bcma: get CPU clock
  bcm47xx: prepare to support different buses
  bcm47xx: make it possible to build bcm47xx without ssb.
  bcm47xx: add support for bcma bus
  bcm47xx: fix irq assignment for new SoCs.

 arch/mips/Kconfig                            |    8 +-
 arch/mips/bcm47xx/Kconfig                    |   31 +++
 arch/mips/bcm47xx/Makefile                   |    3 +-
 arch/mips/bcm47xx/gpio.c                     |   82 +++++--
 arch/mips/bcm47xx/irq.c                      |   12 +
 arch/mips/bcm47xx/nvram.c                    |   29 ++-
 arch/mips/bcm47xx/serial.c                   |   46 ++++-
 arch/mips/bcm47xx/setup.c                    |   90 +++++++-
 arch/mips/bcm47xx/time.c                     |   16 +-
 arch/mips/bcm47xx/wgt634u.c                  |   14 +-
 arch/mips/include/asm/mach-bcm47xx/bcm47xx.h |   26 ++-
 arch/mips/include/asm/mach-bcm47xx/gpio.h    |  108 +++++++--
 arch/mips/pci/pci-bcm47xx.c                  |    6 +
 drivers/bcma/Kconfig                         |   14 +
 drivers/bcma/Makefile                        |    2 +
 drivers/bcma/bcma_private.h                  |   16 ++
 drivers/bcma/driver_chipcommon.c             |   69 ++++++
 drivers/bcma/driver_chipcommon_pmu.c         |   87 +++++++
 drivers/bcma/driver_mips.c                   |  254 +++++++++++++++++++
 drivers/bcma/driver_pci.c                    |    3 +
 drivers/bcma/host_soc.c                      |  178 ++++++++++++++
 drivers/bcma/main.c                          |   65 +++++
 drivers/bcma/scan.c                          |  336 +++++++++++++++++---------
 drivers/watchdog/bcm47xx_wdt.c               |   27 ++-
 include/linux/bcma/bcma.h                    |    8 +
 include/linux/bcma/bcma_driver_chipcommon.h  |   36 +++
 include/linux/bcma/bcma_driver_mips.h        |   61 +++++
 include/linux/bcma/bcma_soc.h                |   16 ++
 28 files changed, 1464 insertions(+), 179 deletions(-)
 create mode 100644 arch/mips/bcm47xx/Kconfig
 create mode 100644 drivers/bcma/driver_mips.c
 create mode 100644 drivers/bcma/host_soc.c
 create mode 100644 include/linux/bcma/bcma_driver_mips.h
 create mode 100644 include/linux/bcma/bcma_soc.h

-- 
1.7.4.1


From hauke@hauke-m.de Sat Jul  9 13:06:33 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 09 Jul 2011 13:07:48 +0200 (CEST)
Received: from server19320154104.serverpool.info ([193.201.54.104]:41917 "EHLO
        hauke-m.de" rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org
        with ESMTP id S1491152Ab1GILGd (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Sat, 9 Jul 2011 13:06:33 +0200
Received: from localhost (localhost [127.0.0.1])
        by hauke-m.de (Postfix) with ESMTP id 583568C6D;
        Sat,  9 Jul 2011 13:06:33 +0200 (CEST)
X-Virus-Scanned: Debian amavisd-new at hauke-m.de 
Received: from hauke-m.de ([127.0.0.1])
        by localhost (hauke-m.de [127.0.0.1]) (amavisd-new, port 10024)
        with ESMTP id gz4Hrk-JRXgX; Sat,  9 Jul 2011 13:06:27 +0200 (CEST)
Received: from localhost.localdomain (dyndsl-095-033-240-133.ewe-ip-backbone.de [95.33.240.133])
        by hauke-m.de (Postfix) with ESMTPSA id 3C15B8C63;
        Sat,  9 Jul 2011 13:06:24 +0200 (CEST)
From:   Hauke Mehrtens <hauke@hauke-m.de>
To:     ralf@linux-mips.org, linux-wireless@vger.kernel.org,
        zajec5@gmail.com, linux-mips@linux-mips.org
Cc:     mb@bu3sch.de, george@znau.edu.ua, arend@broadcom.com,
        b43-dev@lists.infradead.org, bernhardloos@googlemail.com,
        arnd@arndb.de, julian.calaby@gmail.com, sshtylyov@mvista.com,
        Hauke Mehrtens <hauke@hauke-m.de>
Subject: [PATCH 02/11] bcma: move initializing of struct bcma_bus to own function.
Date:   Sat,  9 Jul 2011 13:05:54 +0200
Message-Id: <1310209563-6405-3-git-send-email-hauke@hauke-m.de>
X-Mailer: git-send-email 1.7.4.1
In-Reply-To: <1310209563-6405-1-git-send-email-hauke@hauke-m.de>
References: <1310209563-6405-1-git-send-email-hauke@hauke-m.de>
X-archive-position: 30595
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: hauke@hauke-m.de
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 6775
Content-Length: 1185
Lines: 48

This makes it possible to use this code in some other method.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 drivers/bcma/scan.c |   17 +++++++++++------
 1 files changed, 11 insertions(+), 6 deletions(-)

diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c
index 4012d8d..7970553 100644
--- a/drivers/bcma/scan.c
+++ b/drivers/bcma/scan.c
@@ -312,15 +312,10 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
 	return 0;
 }
 
-int bcma_bus_scan(struct bcma_bus *bus)
+static void bcma_init_bus(struct bcma_bus *bus)
 {
-	u32 erombase;
-	u32 __iomem *eromptr, *eromend;
-
 	s32 tmp;
 
-	int err;
-
 	INIT_LIST_HEAD(&bus->cores);
 	bus->nr_cores = 0;
 
@@ -330,6 +325,16 @@ int bcma_bus_scan(struct bcma_bus *bus)
 	bus->chipinfo.id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT;
 	bus->chipinfo.rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT;
 	bus->chipinfo.pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT;
+}
+
+int bcma_bus_scan(struct bcma_bus *bus)
+{
+	u32 erombase;
+	u32 __iomem *eromptr, *eromend;
+
+	int err;
+
+	bcma_init_bus(bus);
 
 	erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
 	eromptr = bus->mmio;
-- 
1.7.4.1


From hauke@hauke-m.de Sat Jul  9 13:06:35 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 09 Jul 2011 13:08:13 +0200 (CEST)
Received: from server19320154104.serverpool.info ([193.201.54.104]:41928 "EHLO
        hauke-m.de" rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org
        with ESMTP id S1491153Ab1GILGf (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Sat, 9 Jul 2011 13:06:35 +0200
Received: from localhost (localhost [127.0.0.1])
        by hauke-m.de (Postfix) with ESMTP id 70BB88C63;
        Sat,  9 Jul 2011 13:06:35 +0200 (CEST)
X-Virus-Scanned: Debian amavisd-new at hauke-m.de 
Received: from hauke-m.de ([127.0.0.1])
        by localhost (hauke-m.de [127.0.0.1]) (amavisd-new, port 10024)
        with ESMTP id RX6WIczDbSNp; Sat,  9 Jul 2011 13:06:29 +0200 (CEST)
Received: from localhost.localdomain (dyndsl-095-033-240-133.ewe-ip-backbone.de [95.33.240.133])
        by hauke-m.de (Postfix) with ESMTPSA id 2BFCF8C64;
        Sat,  9 Jul 2011 13:06:25 +0200 (CEST)
From:   Hauke Mehrtens <hauke@hauke-m.de>
To:     ralf@linux-mips.org, linux-wireless@vger.kernel.org,
        zajec5@gmail.com, linux-mips@linux-mips.org
Cc:     mb@bu3sch.de, george@znau.edu.ua, arend@broadcom.com,
        b43-dev@lists.infradead.org, bernhardloos@googlemail.com,
        arnd@arndb.de, julian.calaby@gmail.com, sshtylyov@mvista.com,
        Hauke Mehrtens <hauke@hauke-m.de>
Subject: [PATCH 03/11] bcma: add functions to scan cores needed on SoCs
Date:   Sat,  9 Jul 2011 13:05:55 +0200
Message-Id: <1310209563-6405-4-git-send-email-hauke@hauke-m.de>
X-Mailer: git-send-email 1.7.4.1
In-Reply-To: <1310209563-6405-1-git-send-email-hauke@hauke-m.de>
References: <1310209563-6405-1-git-send-email-hauke@hauke-m.de>
X-archive-position: 30596
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: hauke@hauke-m.de
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 6776
Content-Length: 9331
Lines: 318

The chip common and mips core have to be setup early in the boot
process to get the cpu clock.
bcma_bus_early_register() gets pointers to some space to store the core
data and searches for the chip common and mips core and initializes
chip common. After that was done and the kernel is out of early boot we
just have to run bcma_bus_register() and it will search for the other
cores, initialize and register them.
The cores are getting the same numbers as before.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 drivers/bcma/bcma_private.h                 |    7 ++
 drivers/bcma/driver_chipcommon.c            |    5 ++
 drivers/bcma/driver_pci.c                   |    3 +
 drivers/bcma/main.c                         |   45 +++++++++++++
 drivers/bcma/scan.c                         |   95 +++++++++++++++++++++++++--
 include/linux/bcma/bcma.h                   |    1 +
 include/linux/bcma/bcma_driver_chipcommon.h |    1 +
 7 files changed, 151 insertions(+), 6 deletions(-)

diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h
index 2f72e9c..830386c 100644
--- a/drivers/bcma/bcma_private.h
+++ b/drivers/bcma/bcma_private.h
@@ -15,9 +15,16 @@ struct bcma_bus;
 /* main.c */
 extern int bcma_bus_register(struct bcma_bus *bus);
 extern void bcma_bus_unregister(struct bcma_bus *bus);
+int __init bcma_bus_early_register(struct bcma_bus *bus,
+				   struct bcma_device *core_cc,
+				   struct bcma_device *core_mips);
 
 /* scan.c */
 int bcma_bus_scan(struct bcma_bus *bus);
+int __init bcma_bus_scan_early(struct bcma_bus *bus,
+			       struct bcma_device_id *match,
+			       struct bcma_device *core);
+void bcma_init_bus(struct bcma_bus *bus);
 
 #ifdef CONFIG_BCMA_HOST_PCI
 /* host_pci.c */
diff --git a/drivers/bcma/driver_chipcommon.c b/drivers/bcma/driver_chipcommon.c
index 6061022..70321c6 100644
--- a/drivers/bcma/driver_chipcommon.c
+++ b/drivers/bcma/driver_chipcommon.c
@@ -23,6 +23,9 @@ static inline u32 bcma_cc_write32_masked(struct bcma_drv_cc *cc, u16 offset,
 
 void bcma_core_chipcommon_init(struct bcma_drv_cc *cc)
 {
+	if (cc->setup_done)
+		return;
+
 	if (cc->core->id.rev >= 11)
 		cc->status = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT);
 	cc->capabilities = bcma_cc_read32(cc, BCMA_CC_CAP);
@@ -38,6 +41,8 @@ void bcma_core_chipcommon_init(struct bcma_drv_cc *cc)
 		bcma_pmu_init(cc);
 	if (cc->capabilities & BCMA_CC_CAP_PCTL)
 		pr_err("Power control not implemented!\n");
+
+	cc->setup_done = true;
 }
 
 /* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */
diff --git a/drivers/bcma/driver_pci.c b/drivers/bcma/driver_pci.c
index e757e4e..f7378b3 100644
--- a/drivers/bcma/driver_pci.c
+++ b/drivers/bcma/driver_pci.c
@@ -159,5 +159,8 @@ static void bcma_pcicore_serdes_workaround(struct bcma_drv_pci *pc)
 
 void bcma_core_pci_init(struct bcma_drv_pci *pc)
 {
+	if (pc->setup_done)
+		return;
 	bcma_pcicore_serdes_workaround(pc);
+	pc->setup_done = true;
 }
diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c
index be52344..e6c308c 100644
--- a/drivers/bcma/main.c
+++ b/drivers/bcma/main.c
@@ -159,6 +159,51 @@ void bcma_bus_unregister(struct bcma_bus *bus)
 }
 EXPORT_SYMBOL_GPL(bcma_bus_unregister);
 
+int __init bcma_bus_early_register(struct bcma_bus *bus,
+				   struct bcma_device *core_cc,
+				   struct bcma_device *core_mips)
+{
+	int err;
+	struct bcma_device *core;
+	struct bcma_device_id match;
+
+	bcma_init_bus(bus);
+
+	match.manuf = BCMA_MANUF_BCM;
+	match.id = BCMA_CORE_CHIPCOMMON;
+	match.class = BCMA_CL_SIM;
+	match.rev = BCMA_ANY_REV;
+
+	/* Scan for devices (cores) */
+	err = bcma_bus_scan_early(bus, &match, core_cc);
+	if (err) {
+		pr_err("Failed to scan for common core: %d\n", err);
+		return -1;
+	}
+
+	match.manuf = BCMA_MANUF_MIPS;
+	match.id = BCMA_CORE_MIPS_74K;
+	match.class = BCMA_CL_SIM;
+	match.rev = BCMA_ANY_REV;
+
+	err = bcma_bus_scan_early(bus, &match, core_mips);
+	if (err) {
+		pr_err("Failed to scan for mips core: %d\n", err);
+		return -1;
+	}
+
+	/* Init CC core */
+	core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON);
+	if (core) {
+		bus->drv_cc.core = core;
+		bcma_core_chipcommon_init(&bus->drv_cc);
+	}
+
+	pr_info("Early bus registered\n");
+
+	return 0;
+}
+
 int __bcma_driver_register(struct bcma_driver *drv, struct module *owner)
 {
 	drv->drv.name = drv->name;
diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c
index 7970553..bf9f806 100644
--- a/drivers/bcma/scan.c
+++ b/drivers/bcma/scan.c
@@ -200,7 +200,20 @@ static s32 bcma_erom_get_addr_desc(struct bcma_bus *bus, u32 **eromptr,
 	return addrl;
 }
 
+static struct bcma_device *bcma_find_core_by_index(struct bcma_bus *bus,
+						   u16 index)
+{
+	struct bcma_device *core;
+
+	list_for_each_entry(core, &bus->cores, list) {
+		if (core->core_index == index)
+			return core;
+	}
+	return NULL;
+}
+
 static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
+			      struct bcma_device_id *match, int core_num,
 			      struct bcma_device *core)
 {
 	s32 tmp;
@@ -251,6 +264,21 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
 		return -ENXIO;
 	}
 
+	if (bcma_find_core_by_index(bus, core_num)) {
+		bcma_erom_skip_component(bus, eromptr);
+		return -ENODEV;
+	}
+
+	if (match && ((match->manuf != BCMA_ANY_MANUF &&
+	      match->manuf != core->id.manuf) ||
+	     (match->id != BCMA_ANY_ID && match->id != core->id.id) ||
+	     (match->rev != BCMA_ANY_REV && match->rev != core->id.rev) ||
+	     (match->class != BCMA_ANY_CLASS && match->class != core->id.class)
+	    )) {
+		bcma_erom_skip_component(bus, eromptr);
+		return -ENODEV;
+	}
+
 	/* get & parse master ports */
 	for (i = 0; i < ports[0]; i++) {
 		u32 mst_port_d = bcma_erom_get_mst_port(bus, eromptr);
@@ -312,10 +340,13 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
 	return 0;
 }
 
-static void bcma_init_bus(struct bcma_bus *bus)
+void bcma_init_bus(struct bcma_bus *bus)
 {
 	s32 tmp;
 
+	if (bus->init_done)
+		return;
+
 	INIT_LIST_HEAD(&bus->cores);
 	bus->nr_cores = 0;
 
@@ -325,6 +356,7 @@ static void bcma_init_bus(struct bcma_bus *bus)
 	bus->chipinfo.id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT;
 	bus->chipinfo.rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT;
 	bus->chipinfo.pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT;
+	bus->init_done = true;
 }
 
 int bcma_bus_scan(struct bcma_bus *bus)
@@ -332,7 +364,7 @@ int bcma_bus_scan(struct bcma_bus *bus)
 	u32 erombase;
 	u32 __iomem *eromptr, *eromend;
 
-	int err;
+	int err, core_num = 0;
 
 	bcma_init_bus(bus);
 
@@ -349,23 +381,74 @@ int bcma_bus_scan(struct bcma_bus *bus)
 		INIT_LIST_HEAD(&core->list);
 		core->bus = bus;
 
-		err = bcma_get_next_core(bus, &eromptr, core);
-		if (err == -ENXIO)
+		err = bcma_get_next_core(bus, &eromptr, NULL, core_num, core);
+		if (err == -ENODEV) {
+			core_num++;
+			continue;
+		} else if (err == -ENXIO)
 			continue;
 		else if (err == -ESPIPE)
 			break;
 		else if (err < 0)
 			return err;
 
+		core->core_index = core_num++;
+		bus->nr_cores++;
+
 		pr_info("Core %d found: %s "
 			"(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
-			bus->nr_cores, bcma_device_name(&core->id),
+			core->core_index, bcma_device_name(&core->id),
 			core->id.manuf, core->id.id, core->id.rev,
 			core->id.class);
 
-		core->core_index = bus->nr_cores++;
 		list_add(&core->list, &bus->cores);
 	}
 
 	return 0;
 }
+
+int __init bcma_bus_scan_early(struct bcma_bus *bus,
+			       struct bcma_device_id *match,
+			       struct bcma_device *core)
+{
+	u32 erombase;
+	u32 __iomem *eromptr, *eromend;
+
+	int err, core_num = 0;
+
+	erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
+	eromptr = bus->mmio;
+	eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
+
+	bcma_scan_switch_core(bus, erombase);
+
+	while (eromptr < eromend) {
+		memset(core, 0, sizeof(*core));
+		INIT_LIST_HEAD(&core->list);
+		core->bus = bus;
+
+		err = bcma_get_next_core(bus, &eromptr, match, core_num, core);
+		if (err == -ENODEV) {
+			core_num++;
+			continue;
+		} else if (err == -ENXIO)
+			continue;
+		else if (err == -ESPIPE)
+			break;
+		else if (err < 0)
+			return err;
+
+		core->core_index = core_num++;
+		bus->nr_cores++;
+		pr_info("Core %d found: %s "
+			"(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
+			core->core_index, bcma_device_name(&core->id),
+			core->id.manuf, core->id.id, core->id.rev,
+			core->id.class);
+
+		list_add(&core->list, &bus->cores);
+		return 0;
+	}
+
+	return -ENODEV;
+}
diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h
index 08763e4..6bd7b7f 100644
--- a/include/linux/bcma/bcma.h
+++ b/include/linux/bcma/bcma.h
@@ -176,6 +176,7 @@ struct bcma_bus {
 	struct bcma_device *mapped_core;
 	struct list_head cores;
 	u8 nr_cores;
+	u8 init_done:1;
 
 	struct bcma_drv_cc drv_cc;
 	struct bcma_drv_pci drv_pci;
diff --git a/include/linux/bcma/bcma_driver_chipcommon.h b/include/linux/bcma/bcma_driver_chipcommon.h
index 083c3b6..837c176 100644
--- a/include/linux/bcma/bcma_driver_chipcommon.h
+++ b/include/linux/bcma/bcma_driver_chipcommon.h
@@ -258,6 +258,7 @@ struct bcma_drv_cc {
 	u32 status;
 	u32 capabilities;
 	u32 capabilities_ext;
+	u8 setup_done:1;
 	/* Fast Powerup Delay constant */
 	u16 fast_pwrup_delay;
 	struct bcma_chipcommon_pmu pmu;
-- 
1.7.4.1


From hauke@hauke-m.de Sat Jul  9 13:06:39 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 09 Jul 2011 13:08:41 +0200 (CEST)
Received: from server19320154104.serverpool.info ([193.201.54.104]:41947 "EHLO
        hauke-m.de" rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org
        with ESMTP id S1491154Ab1GILGj (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Sat, 9 Jul 2011 13:06:39 +0200
Received: from localhost (localhost [127.0.0.1])
        by hauke-m.de (Postfix) with ESMTP id 4B61D8C70;
        Sat,  9 Jul 2011 13:06:39 +0200 (CEST)
X-Virus-Scanned: Debian amavisd-new at hauke-m.de 
Received: from hauke-m.de ([127.0.0.1])
        by localhost (hauke-m.de [127.0.0.1]) (amavisd-new, port 10024)
        with ESMTP id G15rvGEXBeIy; Sat,  9 Jul 2011 13:06:33 +0200 (CEST)
Received: from localhost.localdomain (dyndsl-095-033-240-133.ewe-ip-backbone.de [95.33.240.133])
        by hauke-m.de (Postfix) with ESMTPSA id 1A3D18C65;
        Sat,  9 Jul 2011 13:06:26 +0200 (CEST)
From:   Hauke Mehrtens <hauke@hauke-m.de>
To:     ralf@linux-mips.org, linux-wireless@vger.kernel.org,
        zajec5@gmail.com, linux-mips@linux-mips.org
Cc:     mb@bu3sch.de, george@znau.edu.ua, arend@broadcom.com,
        b43-dev@lists.infradead.org, bernhardloos@googlemail.com,
        arnd@arndb.de, julian.calaby@gmail.com, sshtylyov@mvista.com,
        Hauke Mehrtens <hauke@hauke-m.de>
Subject: [PATCH 04/11] bcma: add SOC bus
Date:   Sat,  9 Jul 2011 13:05:56 +0200
Message-Id: <1310209563-6405-5-git-send-email-hauke@hauke-m.de>
X-Mailer: git-send-email 1.7.4.1
In-Reply-To: <1310209563-6405-1-git-send-email-hauke@hauke-m.de>
References: <1310209563-6405-1-git-send-email-hauke@hauke-m.de>
X-archive-position: 30597
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: hauke@hauke-m.de
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 6777
Content-Length: 8236
Lines: 337

This patch adds support for using bcma on a Broadcom SoC as the system
bus. An SoC like the bcm4716 could register this bus and use it to
searches for the bcma cores and register the devices on this bus.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 drivers/bcma/Kconfig          |    5 +
 drivers/bcma/Makefile         |    1 +
 drivers/bcma/host_soc.c       |  178 +++++++++++++++++++++++++++++++++++++++++
 drivers/bcma/main.c           |    1 +
 drivers/bcma/scan.c           |   24 +++++-
 include/linux/bcma/bcma.h     |    4 +
 include/linux/bcma/bcma_soc.h |   16 ++++
 7 files changed, 227 insertions(+), 2 deletions(-)
 create mode 100644 drivers/bcma/host_soc.c
 create mode 100644 include/linux/bcma/bcma_soc.h

diff --git a/drivers/bcma/Kconfig b/drivers/bcma/Kconfig
index 353781b..8d82f42 100644
--- a/drivers/bcma/Kconfig
+++ b/drivers/bcma/Kconfig
@@ -22,6 +22,11 @@ config BCMA_HOST_PCI
 	bool "Support for BCMA on PCI-host bus"
 	depends on BCMA_HOST_PCI_POSSIBLE
 
+config BCMA_HOST_SOC
+	bool
+	depends on BCMA && MIPS
+	default n
+
 config BCMA_DEBUG
 	bool "BCMA debugging"
 	depends on BCMA
diff --git a/drivers/bcma/Makefile b/drivers/bcma/Makefile
index 0d56245..42d61dd 100644
--- a/drivers/bcma/Makefile
+++ b/drivers/bcma/Makefile
@@ -2,6 +2,7 @@ bcma-y					+= main.o scan.o core.o
 bcma-y					+= driver_chipcommon.o driver_chipcommon_pmu.o
 bcma-y					+= driver_pci.o
 bcma-$(CONFIG_BCMA_HOST_PCI)		+= host_pci.o
+bcma-$(CONFIG_BCMA_HOST_SOC)		+= host_soc.o
 obj-$(CONFIG_BCMA)			+= bcma.o
 
 ccflags-$(CONFIG_BCMA_DEBUG)		:= -DDEBUG
diff --git a/drivers/bcma/host_soc.c b/drivers/bcma/host_soc.c
new file mode 100644
index 0000000..a6fe724
--- /dev/null
+++ b/drivers/bcma/host_soc.c
@@ -0,0 +1,178 @@
+/*
+ * Broadcom specific AMBA
+ * System on Chip (SoC) Host
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include "bcma_private.h"
+#include "scan.h"
+#include <linux/bcma/bcma.h>
+#include <linux/bcma/bcma_soc.h>
+
+static u8 bcma_host_soc_read8(struct bcma_device *core, u16 offset)
+{
+	return readb(core->io_addr + offset);
+}
+
+static u16 bcma_host_soc_read16(struct bcma_device *core, u16 offset)
+{
+	return readw(core->io_addr + offset);
+}
+
+static u32 bcma_host_soc_read32(struct bcma_device *core, u16 offset)
+{
+	return readl(core->io_addr + offset);
+}
+
+static void bcma_host_soc_write8(struct bcma_device *core, u16 offset,
+				 u8 value)
+{
+	writeb(value, core->io_addr + offset);
+}
+
+static void bcma_host_soc_write16(struct bcma_device *core, u16 offset,
+				 u16 value)
+{
+	writew(value, core->io_addr + offset);
+}
+
+static void bcma_host_soc_write32(struct bcma_device *core, u16 offset,
+				 u32 value)
+{
+	writel(value, core->io_addr + offset);
+}
+
+#ifdef CONFIG_BCMA_BLOCKIO
+static void bcma_host_soc_block_read(struct bcma_device *core, void *buffer,
+				     size_t count, u16 offset, u8 reg_width)
+{
+	void __iomem *addr = core->io_addr + offset;
+
+	switch (reg_width) {
+	case sizeof(u8): {
+		u8 *buf = buffer;
+
+		while (count) {
+			*buf = __raw_readb(addr);
+			buf++;
+			count--;
+		}
+		break;
+	}
+	case sizeof(u16): {
+		__le16 *buf = buffer;
+
+		WARN_ON(count & 1);
+		while (count) {
+			*buf = (__force __le16)__raw_readw(addr);
+			buf++;
+			count -= 2;
+		}
+		break;
+	}
+	case sizeof(u32): {
+		__le32 *buf = buffer;
+
+		WARN_ON(count & 3);
+		while (count) {
+			*buf = (__force __le32)__raw_readl(addr);
+			buf++;
+			count -= 4;
+		}
+		break;
+	}
+	default:
+		WARN_ON(1);
+	}
+}
+
+static void bcma_host_soc_block_write(struct bcma_device *core,
+				      const void *buffer,
+				      size_t count, u16 offset, u8 reg_width)
+{
+	void __iomem *addr = core->io_addr + offset;
+
+	switch (reg_width) {
+	case sizeof(u8): {
+		const u8 *buf = buffer;
+
+		while (count) {
+			__raw_writeb(*buf, addr);
+			buf++;
+			count--;
+		}
+		break;
+	}
+	case sizeof(u16): {
+		const __le16 *buf = buffer;
+
+		WARN_ON(count & 1);
+		while (count) {
+			__raw_writew((__force u16)(*buf), addr);
+			buf++;
+			count -= 2;
+		}
+		break;
+	}
+	case sizeof(u32): {
+		const __le32 *buf = buffer;
+
+		WARN_ON(count & 3);
+		while (count) {
+			__raw_writel((__force u32)(*buf), addr);
+			buf++;
+			count -= 4;
+		}
+		break;
+	}
+	default:
+		WARN_ON(1);
+	}
+}
+#endif /* CONFIG_BCMA_BLOCKIO */
+
+static u32 bcma_host_soc_aread32(struct bcma_device *core, u16 offset)
+{
+	return readl(core->io_wrap + offset);
+}
+
+static void bcma_host_soc_awrite32(struct bcma_device *core, u16 offset,
+				  u32 value)
+{
+	writel(value, core->io_wrap + offset);
+}
+
+const struct bcma_host_ops bcma_host_soc_ops = {
+	.read8		= bcma_host_soc_read8,
+	.read16		= bcma_host_soc_read16,
+	.read32		= bcma_host_soc_read32,
+	.write8		= bcma_host_soc_write8,
+	.write16	= bcma_host_soc_write16,
+	.write32	= bcma_host_soc_write32,
+#ifdef CONFIG_BCMA_BLOCKIO
+	.block_read	= bcma_host_soc_block_read,
+	.block_write	= bcma_host_soc_block_write,
+#endif
+	.aread32	= bcma_host_soc_aread32,
+	.awrite32	= bcma_host_soc_awrite32,
+};
+
+int __init bcma_host_soc_register(struct bcma_soc *soc)
+{
+	struct bcma_bus *bus = &soc->bus;
+
+	/* iomap only first core. We have to read some register on this core
+	 * to scan the bus.
+	 */
+	bus->mmio = ioremap(BCMA_ADDR_BASE, BCMA_CORE_SIZE * 1);
+	if (!bus->mmio)
+		return -ENOMEM;
+
+	/* Host specific */
+	bus->hosttype = BCMA_HOSTTYPE_SOC;
+	bus->ops = &bcma_host_soc_ops;
+
+	/* Register */
+	return bcma_bus_early_register(bus, &soc->core_cc, &soc->core_mips);
+}
diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c
index e6c308c..2ca5eeb 100644
--- a/drivers/bcma/main.c
+++ b/drivers/bcma/main.c
@@ -92,6 +92,7 @@ static int bcma_register_cores(struct bcma_bus *bus)
 			break;
 		case BCMA_HOSTTYPE_NONE:
 		case BCMA_HOSTTYPE_SDIO:
+		case BCMA_HOSTTYPE_SOC:
 			break;
 		}
 
diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c
index bf9f806..202edc8 100644
--- a/drivers/bcma/scan.c
+++ b/drivers/bcma/scan.c
@@ -337,6 +337,14 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
 			}
 		}
 	}
+	if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
+		core->io_addr = ioremap(core->addr, BCMA_CORE_SIZE);
+		if (!core->io_addr)
+			return -ENOMEM;
+		core->io_wrap = ioremap(core->wrap, BCMA_CORE_SIZE);
+		if (!core->io_wrap)
+			return -ENOMEM;
+	}
 	return 0;
 }
 
@@ -369,7 +377,13 @@ int bcma_bus_scan(struct bcma_bus *bus)
 	bcma_init_bus(bus);
 
 	erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
-	eromptr = bus->mmio;
+	if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
+		eromptr = ioremap(erombase, BCMA_CORE_SIZE);
+		if (!eromptr)
+			return -ENOMEM;
+	} else
+		eromptr = bus->mmio;
+
 	eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
 
 	bcma_scan_switch_core(bus, erombase);
@@ -417,7 +431,13 @@ int __init bcma_bus_scan_early(struct bcma_bus *bus,
 	int err, core_num = 0;
 
 	erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
-	eromptr = bus->mmio;
+	if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
+		eromptr = ioremap(erombase, BCMA_CORE_SIZE);
+		if (!eromptr)
+			return -ENOMEM;
+	} else
+		eromptr = bus->mmio;
+
 	eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
 
 	bcma_scan_switch_core(bus, erombase);
diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h
index 6bd7b7f..73fda1c 100644
--- a/include/linux/bcma/bcma.h
+++ b/include/linux/bcma/bcma.h
@@ -16,6 +16,7 @@ enum bcma_hosttype {
 	BCMA_HOSTTYPE_NONE,
 	BCMA_HOSTTYPE_PCI,
 	BCMA_HOSTTYPE_SDIO,
+	BCMA_HOSTTYPE_SOC,
 };
 
 struct bcma_chipinfo {
@@ -124,6 +125,9 @@ struct bcma_device {
 	u32 addr;
 	u32 wrap;
 
+	void __iomem *io_addr;
+	void __iomem *io_wrap;
+
 	void *drvdata;
 	struct list_head list;
 };
diff --git a/include/linux/bcma/bcma_soc.h b/include/linux/bcma/bcma_soc.h
new file mode 100644
index 0000000..4203c55
--- /dev/null
+++ b/include/linux/bcma/bcma_soc.h
@@ -0,0 +1,16 @@
+#ifndef LINUX_BCMA_SOC_H_
+#define LINUX_BCMA_SOC_H_
+
+#include <linux/bcma/bcma.h>
+
+struct bcma_soc {
+	struct bcma_bus bus;
+	struct bcma_device core_cc;
+	struct bcma_device core_mips;
+};
+
+int __init bcma_host_soc_register(struct bcma_soc *soc);
+
+int bcma_bus_register(struct bcma_bus *bus);
+
+#endif /* LINUX_BCMA_SOC_H_ */
-- 
1.7.4.1


From hauke@hauke-m.de Sat Jul  9 13:06:41 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 09 Jul 2011 13:09:09 +0200 (CEST)
Received: from server19320154104.serverpool.info ([193.201.54.104]:41957 "EHLO
        hauke-m.de" rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org
        with ESMTP id S1491162Ab1GILGl (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Sat, 9 Jul 2011 13:06:41 +0200
Received: from localhost (localhost [127.0.0.1])
        by hauke-m.de (Postfix) with ESMTP id 416BC8C65;
        Sat,  9 Jul 2011 13:06:41 +0200 (CEST)
X-Virus-Scanned: Debian amavisd-new at hauke-m.de 
Received: from hauke-m.de ([127.0.0.1])
        by localhost (hauke-m.de [127.0.0.1]) (amavisd-new, port 10024)
        with ESMTP id aFDkHjgOs1ng; Sat,  9 Jul 2011 13:06:35 +0200 (CEST)
Received: from localhost.localdomain (dyndsl-095-033-240-133.ewe-ip-backbone.de [95.33.240.133])
        by hauke-m.de (Postfix) with ESMTPSA id 16AE08C67;
        Sat,  9 Jul 2011 13:06:26 +0200 (CEST)
From:   Hauke Mehrtens <hauke@hauke-m.de>
To:     ralf@linux-mips.org, linux-wireless@vger.kernel.org,
        zajec5@gmail.com, linux-mips@linux-mips.org
Cc:     mb@bu3sch.de, george@znau.edu.ua, arend@broadcom.com,
        b43-dev@lists.infradead.org, bernhardloos@googlemail.com,
        arnd@arndb.de, julian.calaby@gmail.com, sshtylyov@mvista.com,
        Hauke Mehrtens <hauke@hauke-m.de>
Subject: [PATCH 05/11] bcma: add mips driver
Date:   Sat,  9 Jul 2011 13:05:57 +0200
Message-Id: <1310209563-6405-6-git-send-email-hauke@hauke-m.de>
X-Mailer: git-send-email 1.7.4.1
In-Reply-To: <1310209563-6405-1-git-send-email-hauke@hauke-m.de>
References: <1310209563-6405-1-git-send-email-hauke@hauke-m.de>
X-archive-position: 30598
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: hauke@hauke-m.de
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 6778
Content-Length: 11401
Lines: 421

This adds a mips driver to bcma. This is only found on embedded
devices. For now the driver just initializes the irqs used on this
system.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 drivers/bcma/Kconfig                  |   11 ++-
 drivers/bcma/Makefile                 |    1 +
 drivers/bcma/driver_mips.c            |  233 +++++++++++++++++++++++++++++++++
 drivers/bcma/main.c                   |   19 +++
 include/linux/bcma/bcma.h             |    3 +
 include/linux/bcma/bcma_driver_mips.h |   49 +++++++
 6 files changed, 315 insertions(+), 1 deletions(-)
 create mode 100644 drivers/bcma/driver_mips.c
 create mode 100644 include/linux/bcma/bcma_driver_mips.h

diff --git a/drivers/bcma/Kconfig b/drivers/bcma/Kconfig
index 8d82f42..81926ce 100644
--- a/drivers/bcma/Kconfig
+++ b/drivers/bcma/Kconfig
@@ -24,9 +24,18 @@ config BCMA_HOST_PCI
 
 config BCMA_HOST_SOC
 	bool
-	depends on BCMA && MIPS
+	depends on BCMA_DRIVER_MIPS
 	default n
 
+config BCMA_DRIVER_MIPS
+	bool "BCMA Broadcom MIPS core driver"
+	depends on BCMA && MIPS
+	help
+	  Driver for the Broadcom MIPS core attached to Broadcom specific
+	  Advanced Microcontroller Bus.
+
+	  If unsure, say N
+
 config BCMA_DEBUG
 	bool "BCMA debugging"
 	depends on BCMA
diff --git a/drivers/bcma/Makefile b/drivers/bcma/Makefile
index 42d61dd..a4352e5 100644
--- a/drivers/bcma/Makefile
+++ b/drivers/bcma/Makefile
@@ -1,6 +1,7 @@
 bcma-y					+= main.o scan.o core.o
 bcma-y					+= driver_chipcommon.o driver_chipcommon_pmu.o
 bcma-y					+= driver_pci.o
+bcma-$(CONFIG_BCMA_DRIVER_MIPS)		+= driver_mips.o
 bcma-$(CONFIG_BCMA_HOST_PCI)		+= host_pci.o
 bcma-$(CONFIG_BCMA_HOST_SOC)		+= host_soc.o
 obj-$(CONFIG_BCMA)			+= bcma.o
diff --git a/drivers/bcma/driver_mips.c b/drivers/bcma/driver_mips.c
new file mode 100644
index 0000000..605bb08
--- /dev/null
+++ b/drivers/bcma/driver_mips.c
@@ -0,0 +1,233 @@
+/*
+ * Broadcom specific AMBA
+ * Broadcom MIPS32 74K core driver
+ *
+ * Copyright 2009, Broadcom Corporation
+ * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
+ * Copyright 2010, Bernhard Loos <bernhardloos@googlemail.com>
+ * Copyright 2011, Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include "bcma_private.h"
+
+#include <linux/bcma/bcma.h>
+
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/serial_reg.h>
+#include <linux/time.h>
+
+/* The 47162a0 hangs when reading its registers */
+static inline bool bcma_core_mips_bcm47162a0_quirk(struct bcma_device *dev)
+{
+	return dev->bus->chipinfo.id == 47162 && dev->bus->chipinfo.rev == 0 &&
+	       dev->id.id == BCMA_CORE_MIPS_74K;
+}
+
+static inline u32 mips_read32(struct bcma_drv_mips *mcore,
+			      u16 offset)
+{
+	return bcma_read32(mcore->core, offset);
+}
+
+static inline void mips_write32(struct bcma_drv_mips *mcore,
+				u16 offset,
+				u32 value)
+{
+	bcma_write32(mcore->core, offset, value);
+}
+
+static const u32 ipsflag_irq_mask[] = {
+	0,
+	BCMA_MIPS_IPSFLAG_IRQ1,
+	BCMA_MIPS_IPSFLAG_IRQ2,
+	BCMA_MIPS_IPSFLAG_IRQ3,
+	BCMA_MIPS_IPSFLAG_IRQ4,
+};
+
+static const u32 ipsflag_irq_shift[] = {
+	0,
+	BCMA_MIPS_IPSFLAG_IRQ1_SHIFT,
+	BCMA_MIPS_IPSFLAG_IRQ2_SHIFT,
+	BCMA_MIPS_IPSFLAG_IRQ3_SHIFT,
+	BCMA_MIPS_IPSFLAG_IRQ4_SHIFT,
+};
+
+static u32 bcma_core_mips_irqflag(struct bcma_device *dev)
+{
+	u32 flag;
+
+	if (bcma_core_mips_bcm47162a0_quirk(dev))
+		return dev->core_index;
+	flag = bcma_aread32(dev, BCMA_MIPS_OOBSELOUTA30);
+
+	return flag & 0x1F;
+}
+
+
+/* Get the MIPS IRQ assignment for a specified device.
+ * If unassigned, 0 is returned.
+ */
+unsigned int bcma_core_mips_irq(struct bcma_device *dev)
+{
+	struct bcma_device *mdev = dev->bus->drv_mips.core;
+	u32 irqflag;
+	unsigned int irq;
+
+	irqflag = bcma_core_mips_irqflag(dev);
+
+	for (irq = 1; irq <= 4; irq++)
+		if (bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq)) &
+		    (1 << irqflag))
+			return irq;
+
+	return 0;
+}
+EXPORT_SYMBOL(bcma_core_mips_irq);
+
+static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq)
+{
+	unsigned int oldirq = bcma_core_mips_irq(dev);
+	struct bcma_bus *bus = dev->bus;
+	struct bcma_device *mdev = bus->drv_mips.core;
+	u32 irqflag;
+
+	irqflag = bcma_core_mips_irqflag(dev);
+	BUG_ON(oldirq == 6);
+
+	dev->irq = irq + 2;
+
+	/* clear the old irq */
+	if (oldirq == 0)
+		bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0),
+			    bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) &
+			    ~(1 << irqflag));
+	else
+		bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq), 0);
+
+	/* assign the new one */
+	if (irq == 0) {
+		bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0),
+			    bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) |
+			    (1 << irqflag));
+	} else {
+		u32 oldirqflag = bcma_read32(mdev,
+					     BCMA_MIPS_MIPS74K_INTMASK(irq));
+		if (oldirqflag) {
+			struct bcma_device *core;
+
+			/* backplane irq line is in use, find out who uses
+			 * it and set user to irq 0
+			 */
+			list_for_each_entry_reverse(core, &bus->cores, list) {
+				if ((1 << bcma_core_mips_irqflag(core)) ==
+				    oldirqflag) {
+					bcma_core_mips_set_irq(core, 0);
+					break;
+				}
+			}
+		}
+		bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq),
+			     1 << irqflag);
+	}
+
+	pr_info("set_irq: core 0x%04x, irq %d => %d\n",
+		dev->id.id, oldirq + 2, irq + 2);
+}
+
+static void bcma_core_mips_print_irq(struct bcma_device *dev, unsigned int irq)
+{
+	int i;
+	static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"};
+	printk(KERN_INFO KBUILD_MODNAME ": core 0x%04x, irq :", dev->id.id);
+	for (i = 0; i <= 6; i++)
+		printk(" %s%s", irq_name[i], i == irq ? "*" : " ");
+	printk("\n");
+}
+
+static void bcma_core_mips_dump_irq(struct bcma_bus *bus)
+{
+	struct bcma_device *core;
+
+	list_for_each_entry_reverse(core, &bus->cores, list) {
+		bcma_core_mips_print_irq(core, bcma_core_mips_irq(core));
+	}
+}
+
+static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
+{
+	struct bcma_bus *bus = mcore->core->bus;
+
+	mcore->flash_buswidth = 2;
+	if (bus->drv_cc.core) {
+		mcore->flash_window = 0x1c000000;
+		mcore->flash_window_size = 0x02000000;
+		switch (bus->drv_cc.capabilities & BCMA_CC_CAP_FLASHT) {
+		case BCMA_CC_FLASHT_STSER:
+		case BCMA_CC_FLASHT_ATSER:
+			pr_err("Serial flash not supported.\n");
+			break;
+		case BCMA_CC_FLASHT_PARA:
+			if ((bcma_read32(bus->drv_cc.core, BCMA_CC_FLASH_CFG) &
+			     BCMA_CC_OTPS) == 0)
+				mcore->flash_buswidth = 1;
+			break;
+		}
+	} else {
+		mcore->flash_window = 0x1fc00000;
+		mcore->flash_window_size = 0x00400000;
+	}
+}
+
+void bcma_core_mips_init(struct bcma_drv_mips *mcore)
+{
+	struct bcma_bus *bus;
+	struct bcma_device *core;
+	bus = mcore->core->bus;
+
+	pr_info("Initializing MIPS core...\n");
+
+	if (!mcore->setup_done)
+		mcore->assigned_irqs = 1;
+
+	/* Assign IRQs to all cores on the bus */
+	list_for_each_entry_reverse(core, &bus->cores, list) {
+		int mips_irq;
+		if (core->irq)
+			continue;
+
+		mips_irq = bcma_core_mips_irq(core);
+		if (mips_irq > 4)
+			core->irq = 0;
+		else
+			core->irq = mips_irq + 2;
+		if (core->irq > 5)
+			continue;
+		switch (core->id.id) {
+		case BCMA_CORE_PCI:
+		case BCMA_CORE_PCIE:
+		case BCMA_CORE_ETHERNET:
+		case BCMA_CORE_ETHERNET_GBIT:
+		case BCMA_CORE_MAC_GBIT:
+		case BCMA_CORE_80211:
+		case BCMA_CORE_USB20_HOST:
+			/* These devices get their own IRQ line if available,
+			 * the rest goes on IRQ0
+			 */
+			if (mcore->assigned_irqs <= 4)
+				bcma_core_mips_set_irq(core,
+						       mcore->assigned_irqs++);
+			break;
+		}
+	}
+	pr_info("IRQ reconfiguration done\n");
+	bcma_core_mips_dump_irq(bus);
+
+	if (mcore->setup_done)
+		return;
+
+	bcma_core_mips_flash_detect(mcore);
+	mcore->setup_done = true;
+}
diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c
index 2ca5eeb..ba9a357 100644
--- a/drivers/bcma/main.c
+++ b/drivers/bcma/main.c
@@ -79,6 +79,7 @@ static int bcma_register_cores(struct bcma_bus *bus)
 		case BCMA_CORE_CHIPCOMMON:
 		case BCMA_CORE_PCI:
 		case BCMA_CORE_PCIE:
+		case BCMA_CORE_MIPS_74K:
 			continue;
 		}
 
@@ -138,6 +139,15 @@ int bcma_bus_register(struct bcma_bus *bus)
 		bcma_core_chipcommon_init(&bus->drv_cc);
 	}
 
+#ifdef CONFIG_BCMA_DRIVER_MIPS
+	/* Init MIPS core */
+	core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
+	if (core) {
+		bus->drv_mips.core = core;
+		bcma_core_mips_init(&bus->drv_mips);
+	}
+#endif
+
 	/* Init PCIE core */
 	core = bcma_find_core(bus, BCMA_CORE_PCIE);
 	if (core) {
@@ -200,6 +210,15 @@ int __init bcma_bus_early_register(struct bcma_bus *bus,
 		bcma_core_chipcommon_init(&bus->drv_cc);
 	}
 
+#ifdef CONFIG_BCMA_DRIVER_MIPS
+	/* Init MIPS core */
+	core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
+	if (core) {
+		bus->drv_mips.core = core;
+		bcma_core_mips_init(&bus->drv_mips);
+	}
+#endif
+
 	pr_info("Early bus registered\n");
 
 	return 0;
diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h
index 73fda1c..12313fd 100644
--- a/include/linux/bcma/bcma.h
+++ b/include/linux/bcma/bcma.h
@@ -6,6 +6,7 @@
 
 #include <linux/bcma/bcma_driver_chipcommon.h>
 #include <linux/bcma/bcma_driver_pci.h>
+#include <linux/bcma/bcma_driver_mips.h>
 
 #include "bcma_regs.h"
 
@@ -118,6 +119,7 @@ struct bcma_device {
 	struct bcma_device_id id;
 
 	struct device dev;
+	unsigned int irq;
 	bool dev_registered;
 
 	u8 core_index;
@@ -184,6 +186,7 @@ struct bcma_bus {
 
 	struct bcma_drv_cc drv_cc;
 	struct bcma_drv_pci drv_pci;
+	struct bcma_drv_mips drv_mips;
 };
 
 extern inline u32 bcma_read8(struct bcma_device *core, u16 offset)
diff --git a/include/linux/bcma/bcma_driver_mips.h b/include/linux/bcma/bcma_driver_mips.h
new file mode 100644
index 0000000..f19b21a
--- /dev/null
+++ b/include/linux/bcma/bcma_driver_mips.h
@@ -0,0 +1,49 @@
+#ifndef LINUX_BCMA_DRIVER_MIPS_H_
+#define LINUX_BCMA_DRIVER_MIPS_H_
+
+#define BCMA_MIPS_IPSFLAG		0x0F08
+/* which sbflags get routed to mips interrupt 1 */
+#define	 BCMA_MIPS_IPSFLAG_IRQ1		0x0000003F
+#define	 BCMA_MIPS_IPSFLAG_IRQ1_SHIFT	0
+/* which sbflags get routed to mips interrupt 2 */
+#define	 BCMA_MIPS_IPSFLAG_IRQ2		0x00003F00
+#define	 BCMA_MIPS_IPSFLAG_IRQ2_SHIFT	8
+/* which sbflags get routed to mips interrupt 3 */
+#define	 BCMA_MIPS_IPSFLAG_IRQ3		0x003F0000
+#define	 BCMA_MIPS_IPSFLAG_IRQ3_SHIFT	16
+/* which sbflags get routed to mips interrupt 4 */
+#define	 BCMA_MIPS_IPSFLAG_IRQ4		0x3F000000
+#define	 BCMA_MIPS_IPSFLAG_IRQ4_SHIFT	24
+
+/* MIPS 74K core registers */
+#define BCMA_MIPS_MIPS74K_CORECTL	0x0000
+#define BCMA_MIPS_MIPS74K_EXCEPTBASE	0x0004
+#define BCMA_MIPS_MIPS74K_BIST		0x000C
+#define BCMA_MIPS_MIPS74K_INTMASK_INT0	0x0014
+#define BCMA_MIPS_MIPS74K_INTMASK(int) \
+	((int) * 4 + BCMA_MIPS_MIPS74K_INTMASK_INT0)
+#define BCMA_MIPS_MIPS74K_NMIMASK	0x002C
+#define BCMA_MIPS_MIPS74K_GPIOSEL	0x0040
+#define BCMA_MIPS_MIPS74K_GPIOOUT	0x0044
+#define BCMA_MIPS_MIPS74K_GPIOEN	0x0048
+#define BCMA_MIPS_MIPS74K_CLKCTLST	0x01E0
+
+#define BCMA_MIPS_OOBSELOUTA30		0x100
+
+struct bcma_device;
+
+struct bcma_drv_mips {
+	struct bcma_device *core;
+	u8 setup_done:1;
+	unsigned int assigned_irqs;
+
+	u8 flash_buswidth;
+	u32 flash_window;
+	u32 flash_window_size;
+};
+
+extern void bcma_core_mips_init(struct bcma_drv_mips *mcore);
+
+extern unsigned int bcma_core_mips_irq(struct bcma_device *dev);
+
+#endif /* LINUX_BCMA_DRIVER_MIPS_H_ */
-- 
1.7.4.1


From hauke@hauke-m.de Sat Jul  9 13:06:45 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 09 Jul 2011 13:09:34 +0200 (CEST)
Received: from server19320154104.serverpool.info ([193.201.54.104]:41968 "EHLO
        hauke-m.de" rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org
        with ESMTP id S1491186Ab1GILGp (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Sat, 9 Jul 2011 13:06:45 +0200
Received: from localhost (localhost [127.0.0.1])
        by hauke-m.de (Postfix) with ESMTP id BA1158C72;
        Sat,  9 Jul 2011 13:06:44 +0200 (CEST)
X-Virus-Scanned: Debian amavisd-new at hauke-m.de 
Received: from hauke-m.de ([127.0.0.1])
        by localhost (hauke-m.de [127.0.0.1]) (amavisd-new, port 10024)
        with ESMTP id QTsfZdH4+PQI; Sat,  9 Jul 2011 13:06:39 +0200 (CEST)
Received: from localhost.localdomain (dyndsl-095-033-240-133.ewe-ip-backbone.de [95.33.240.133])
        by hauke-m.de (Postfix) with ESMTPSA id 04CFF8C4F;
        Sat,  9 Jul 2011 13:06:27 +0200 (CEST)
From:   Hauke Mehrtens <hauke@hauke-m.de>
To:     ralf@linux-mips.org, linux-wireless@vger.kernel.org,
        zajec5@gmail.com, linux-mips@linux-mips.org
Cc:     mb@bu3sch.de, george@znau.edu.ua, arend@broadcom.com,
        b43-dev@lists.infradead.org, bernhardloos@googlemail.com,
        arnd@arndb.de, julian.calaby@gmail.com, sshtylyov@mvista.com,
        Hauke Mehrtens <hauke@hauke-m.de>
Subject: [PATCH 06/11] bcma: add serial console support
Date:   Sat,  9 Jul 2011 13:05:58 +0200
Message-Id: <1310209563-6405-7-git-send-email-hauke@hauke-m.de>
X-Mailer: git-send-email 1.7.4.1
In-Reply-To: <1310209563-6405-1-git-send-email-hauke@hauke-m.de>
References: <1310209563-6405-1-git-send-email-hauke@hauke-m.de>
X-archive-position: 30599
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: hauke@hauke-m.de
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 6779
Content-Length: 4690
Lines: 156

This adds support for serial console to bcma, when operating on an SoC.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 drivers/bcma/bcma_private.h           |    6 +++
 drivers/bcma/driver_chipcommon.c      |   64 +++++++++++++++++++++++++++++++++
 drivers/bcma/driver_mips.c            |    9 +++++
 include/linux/bcma/bcma_driver_mips.h |   11 ++++++
 4 files changed, 90 insertions(+), 0 deletions(-)

diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h
index 830386c..92ec671 100644
--- a/drivers/bcma/bcma_private.h
+++ b/drivers/bcma/bcma_private.h
@@ -26,6 +26,12 @@ int __init bcma_bus_scan_early(struct bcma_bus *bus,
 			       struct bcma_device *core);
 void bcma_init_bus(struct bcma_bus *bus);
 
+/* driver_chipcommon.c */
+#ifdef CONFIG_BCMA_DRIVER_MIPS
+extern int bcma_chipco_serial_init(struct bcma_drv_cc *cc,
+				   struct bcma_drv_mips_serial_port *ports);
+#endif /* CONFIG_BCMA_DRIVER_MIPS */
+
 #ifdef CONFIG_BCMA_HOST_PCI
 /* host_pci.c */
 extern int __init bcma_host_pci_init(void);
diff --git a/drivers/bcma/driver_chipcommon.c b/drivers/bcma/driver_chipcommon.c
index 70321c6..88533ca 100644
--- a/drivers/bcma/driver_chipcommon.c
+++ b/drivers/bcma/driver_chipcommon.c
@@ -92,3 +92,67 @@ u32 bcma_chipco_gpio_polarity(struct bcma_drv_cc *cc, u32 mask, u32 value)
 {
 	return bcma_cc_write32_masked(cc, BCMA_CC_GPIOPOL, mask, value);
 }
+
+#ifdef CONFIG_BCMA_DRIVER_MIPS
+int bcma_chipco_serial_init(struct bcma_drv_cc *cc,
+			    struct bcma_drv_mips_serial_port *ports)
+{
+	int nr_ports = 0;
+	u32 plltype;
+	unsigned int irq;
+	u32 baud_base, div;
+	u32 i, n;
+	unsigned int ccrev = cc->core->id.rev;
+
+	plltype = (cc->capabilities & BCMA_CC_CAP_PLLT);
+	irq = bcma_core_mips_irq(cc->core);
+
+	if ((ccrev >= 11) && (ccrev != 15) && (ccrev != 20)) {
+		/* Fixed ALP clock */
+		baud_base = 20000000;
+		if (cc->capabilities & BCMA_CC_CAP_PMU) {
+			/* FIXME: baud_base is different for devices with a PMU */
+			WARN_ON(1);
+		}
+		div = 1;
+		if (ccrev >= 21) {
+			/* Turn off UART clock before switching clocksource. */
+			bcma_cc_write32(cc, BCMA_CC_CORECTL,
+				       bcma_cc_read32(cc, BCMA_CC_CORECTL)
+				       & ~BCMA_CC_CORECTL_UARTCLKEN);
+		}
+		/* Set the override bit so we don't divide it */
+		bcma_cc_write32(cc, BCMA_CC_CORECTL,
+			       bcma_cc_read32(cc, BCMA_CC_CORECTL)
+			       | BCMA_CC_CORECTL_UARTCLK0);
+		if (ccrev >= 21) {
+			/* Re-enable the UART clock. */
+			bcma_cc_write32(cc, BCMA_CC_CORECTL,
+				       bcma_cc_read32(cc, BCMA_CC_CORECTL)
+				       | BCMA_CC_CORECTL_UARTCLKEN);
+		}
+	} else
+		pr_err("serial not supported on this device ccrev: 0x%x\n",
+		       ccrev);
+
+	/* Determine the registers of the UARTs */
+	n = (cc->capabilities & BCMA_CC_CAP_NRUART);
+	for (i = 0; i < n; i++) {
+		void __iomem *cc_mmio;
+		void __iomem *uart_regs;
+
+		cc_mmio = cc->core->bus->mmio +
+			  (cc->core->core_index * BCMA_CORE_SIZE);
+		uart_regs = cc_mmio + BCMA_CC_UART0_DATA;
+		uart_regs += (i * 256);
+
+		nr_ports++;
+		ports[i].regs = uart_regs;
+		ports[i].irq = irq;
+		ports[i].baud_base = baud_base;
+		ports[i].reg_shift = 0;
+	}
+
+	return nr_ports;
+}
+#endif /* CONFIG_BCMA_DRIVER_MIPS */
diff --git a/drivers/bcma/driver_mips.c b/drivers/bcma/driver_mips.c
index 605bb08..3989fb9 100644
--- a/drivers/bcma/driver_mips.c
+++ b/drivers/bcma/driver_mips.c
@@ -156,6 +156,14 @@ static void bcma_core_mips_dump_irq(struct bcma_bus *bus)
 	}
 }
 
+static void bcma_core_mips_serial_init(struct bcma_drv_mips *mcore)
+{
+	struct bcma_bus *bus = mcore->core->bus;
+
+	mcore->nr_serial_ports = bcma_chipco_serial_init(&bus->drv_cc,
+							 mcore->serial_ports);
+}
+
 static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
 {
 	struct bcma_bus *bus = mcore->core->bus;
@@ -228,6 +236,7 @@ void bcma_core_mips_init(struct bcma_drv_mips *mcore)
 	if (mcore->setup_done)
 		return;
 
+	bcma_core_mips_serial_init(mcore);
 	bcma_core_mips_flash_detect(mcore);
 	mcore->setup_done = true;
 }
diff --git a/include/linux/bcma/bcma_driver_mips.h b/include/linux/bcma/bcma_driver_mips.h
index f19b21a..13b44c2 100644
--- a/include/linux/bcma/bcma_driver_mips.h
+++ b/include/linux/bcma/bcma_driver_mips.h
@@ -32,11 +32,22 @@
 
 struct bcma_device;
 
+struct bcma_drv_mips_serial_port {
+	void *regs;
+	unsigned long clockspeed;
+	unsigned int irq;
+	unsigned int baud_base;
+	unsigned int reg_shift;
+};
+
 struct bcma_drv_mips {
 	struct bcma_device *core;
 	u8 setup_done:1;
 	unsigned int assigned_irqs;
 
+	int nr_serial_ports;
+	struct bcma_drv_mips_serial_port serial_ports[4];
+
 	u8 flash_buswidth;
 	u32 flash_window;
 	u32 flash_window_size;
-- 
1.7.4.1


From hauke@hauke-m.de Sat Jul  9 13:06:51 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 09 Jul 2011 13:10:03 +0200 (CEST)
Received: from server19320154104.serverpool.info ([193.201.54.104]:41982 "EHLO
        hauke-m.de" rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org
        with ESMTP id S1491188Ab1GILGv (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Sat, 9 Jul 2011 13:06:51 +0200
Received: from localhost (localhost [127.0.0.1])
        by hauke-m.de (Postfix) with ESMTP id 66A978C74;
        Sat,  9 Jul 2011 13:06:51 +0200 (CEST)
X-Virus-Scanned: Debian amavisd-new at hauke-m.de 
Received: from hauke-m.de ([127.0.0.1])
        by localhost (hauke-m.de [127.0.0.1]) (amavisd-new, port 10024)
        with ESMTP id T5SUTgfy5NV5; Sat,  9 Jul 2011 13:06:45 +0200 (CEST)
Received: from localhost.localdomain (dyndsl-095-033-240-133.ewe-ip-backbone.de [95.33.240.133])
        by hauke-m.de (Postfix) with ESMTPSA id EEF138C62;
        Sat,  9 Jul 2011 13:06:29 +0200 (CEST)
From:   Hauke Mehrtens <hauke@hauke-m.de>
To:     ralf@linux-mips.org, linux-wireless@vger.kernel.org,
        zajec5@gmail.com, linux-mips@linux-mips.org
Cc:     mb@bu3sch.de, george@znau.edu.ua, arend@broadcom.com,
        b43-dev@lists.infradead.org, bernhardloos@googlemail.com,
        arnd@arndb.de, julian.calaby@gmail.com, sshtylyov@mvista.com,
        Hauke Mehrtens <hauke@hauke-m.de>
Subject: [PATCH 08/11] bcm47xx: prepare to support different buses
Date:   Sat,  9 Jul 2011 13:06:00 +0200
Message-Id: <1310209563-6405-9-git-send-email-hauke@hauke-m.de>
X-Mailer: git-send-email 1.7.4.1
In-Reply-To: <1310209563-6405-1-git-send-email-hauke@hauke-m.de>
References: <1310209563-6405-1-git-send-email-hauke@hauke-m.de>
X-archive-position: 30600
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: hauke@hauke-m.de
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 6780
Content-Length: 13520
Lines: 456

Prepare bcm47xx to support different System buses. Before adding
support for bcma it should be possible to build bcm47xx without the
need of ssb. With this patch bcm47xx does not directly contain a
ssb_bus, but a union contain all the supported system buses. As a SoC
just uses one system bus a union is a good choice.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 arch/mips/bcm47xx/gpio.c                     |   56 ++++++++++++++++----------
 arch/mips/bcm47xx/nvram.c                    |   15 +++++--
 arch/mips/bcm47xx/serial.c                   |   13 +++++-
 arch/mips/bcm47xx/setup.c                    |   33 ++++++++++++---
 arch/mips/bcm47xx/time.c                     |    9 +++-
 arch/mips/bcm47xx/wgt634u.c                  |   14 ++++--
 arch/mips/include/asm/mach-bcm47xx/bcm47xx.h |   14 ++++++-
 arch/mips/include/asm/mach-bcm47xx/gpio.h    |   55 ++++++++++++++++++-------
 drivers/watchdog/bcm47xx_wdt.c               |   12 +++++-
 9 files changed, 160 insertions(+), 61 deletions(-)

diff --git a/arch/mips/bcm47xx/gpio.c b/arch/mips/bcm47xx/gpio.c
index e4a5ee9..2f6d2df 100644
--- a/arch/mips/bcm47xx/gpio.c
+++ b/arch/mips/bcm47xx/gpio.c
@@ -20,42 +20,54 @@ static DECLARE_BITMAP(gpio_in_use, BCM47XX_EXTIF_GPIO_LINES);
 
 int gpio_request(unsigned gpio, const char *tag)
 {
-	if (ssb_chipco_available(&ssb_bcm47xx.chipco) &&
-	    ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
-		return -EINVAL;
+	switch (bcm47xx_active_bus_type) {
+	case BCM47XX_BUS_TYPE_SSB:
+		if (ssb_chipco_available(&bcm47xx_bus.ssb.chipco) &&
+		    ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
+			return -EINVAL;
 
-	if (ssb_extif_available(&ssb_bcm47xx.extif) &&
-	    ((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES))
-		return -EINVAL;
+		if (ssb_extif_available(&bcm47xx_bus.ssb.extif) &&
+		    ((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES))
+			return -EINVAL;
 
-	if (test_and_set_bit(gpio, gpio_in_use))
-		return -EBUSY;
+		if (test_and_set_bit(gpio, gpio_in_use))
+			return -EBUSY;
 
-	return 0;
+		return 0;
+	}
+	return -EINVAL;
 }
 EXPORT_SYMBOL(gpio_request);
 
 void gpio_free(unsigned gpio)
 {
-	if (ssb_chipco_available(&ssb_bcm47xx.chipco) &&
-	    ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
-		return;
+	switch (bcm47xx_active_bus_type) {
+	case BCM47XX_BUS_TYPE_SSB:
+		if (ssb_chipco_available(&bcm47xx_bus.ssb.chipco) &&
+		    ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
+			return;
 
-	if (ssb_extif_available(&ssb_bcm47xx.extif) &&
-	    ((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES))
-		return;
+		if (ssb_extif_available(&bcm47xx_bus.ssb.extif) &&
+		    ((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES))
+			return;
 
-	clear_bit(gpio, gpio_in_use);
+		clear_bit(gpio, gpio_in_use);
+		return;
+	}
 }
 EXPORT_SYMBOL(gpio_free);
 
 int gpio_to_irq(unsigned gpio)
 {
-	if (ssb_chipco_available(&ssb_bcm47xx.chipco))
-		return ssb_mips_irq(ssb_bcm47xx.chipco.dev) + 2;
-	else if (ssb_extif_available(&ssb_bcm47xx.extif))
-		return ssb_mips_irq(ssb_bcm47xx.extif.dev) + 2;
-	else
-		return -EINVAL;
+	switch (bcm47xx_active_bus_type) {
+	case BCM47XX_BUS_TYPE_SSB:
+		if (ssb_chipco_available(&bcm47xx_bus.ssb.chipco))
+			return ssb_mips_irq(bcm47xx_bus.ssb.chipco.dev) + 2;
+		else if (ssb_extif_available(&bcm47xx_bus.ssb.extif))
+			return ssb_mips_irq(bcm47xx_bus.ssb.extif.dev) + 2;
+		else
+			return -EINVAL;
+	}
+	return -EINVAL;
 }
 EXPORT_SYMBOL_GPL(gpio_to_irq);
diff --git a/arch/mips/bcm47xx/nvram.c b/arch/mips/bcm47xx/nvram.c
index 54db815..d2304d0 100644
--- a/arch/mips/bcm47xx/nvram.c
+++ b/arch/mips/bcm47xx/nvram.c
@@ -26,14 +26,21 @@ static char nvram_buf[NVRAM_SPACE];
 /* Probe for NVRAM header */
 static void early_nvram_init(void)
 {
-	struct ssb_mipscore *mcore = &ssb_bcm47xx.mipscore;
+	struct ssb_mipscore *mcore_ssb;
 	struct nvram_header *header;
 	int i;
-	u32 base, lim, off;
+	u32 base = 0;
+	u32 lim = 0;
+	u32 off;
 	u32 *src, *dst;
 
-	base = mcore->flash_window;
-	lim = mcore->flash_window_size;
+	switch (bcm47xx_active_bus_type) {
+	case BCM47XX_BUS_TYPE_SSB:
+		mcore_ssb = &bcm47xx_bus.ssb.mipscore;
+		base = mcore_ssb->flash_window;
+		lim = mcore_ssb->flash_window_size;
+		break;
+	}
 
 	off = FLASH_MIN;
 	while (off <= lim) {
diff --git a/arch/mips/bcm47xx/serial.c b/arch/mips/bcm47xx/serial.c
index 59c11af..87c2c5e 100644
--- a/arch/mips/bcm47xx/serial.c
+++ b/arch/mips/bcm47xx/serial.c
@@ -23,10 +23,10 @@ static struct platform_device uart8250_device = {
 	},
 };
 
-static int __init uart8250_init(void)
+static int __init uart8250_init_ssb(void)
 {
 	int i;
-	struct ssb_mipscore *mcore = &(ssb_bcm47xx.mipscore);
+	struct ssb_mipscore *mcore = &(bcm47xx_bus.ssb.mipscore);
 
 	memset(&uart8250_data, 0,  sizeof(uart8250_data));
 
@@ -45,6 +45,15 @@ static int __init uart8250_init(void)
 	return platform_device_register(&uart8250_device);
 }
 
+static int __init uart8250_init(void)
+{
+	switch (bcm47xx_active_bus_type) {
+	case BCM47XX_BUS_TYPE_SSB:
+		return uart8250_init_ssb();
+	}
+	return -EINVAL;
+}
+
 module_init(uart8250_init);
 
 MODULE_AUTHOR("Aurelien Jarno <aurelien@aurel32.net>");
diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c
index 73b529b..bff4181 100644
--- a/arch/mips/bcm47xx/setup.c
+++ b/arch/mips/bcm47xx/setup.c
@@ -35,15 +35,22 @@
 #include <bcm47xx.h>
 #include <asm/mach-bcm47xx/nvram.h>
 
-struct ssb_bus ssb_bcm47xx;
-EXPORT_SYMBOL(ssb_bcm47xx);
+union bcm47xx_bus bcm47xx_bus;
+EXPORT_SYMBOL(bcm47xx_bus);
+
+enum bcm47xx_bus_type bcm47xx_active_bus_type;
+EXPORT_SYMBOL(bcm47xx_active_bus_type);
 
 static void bcm47xx_machine_restart(char *command)
 {
 	printk(KERN_ALERT "Please stand by while rebooting the system...\n");
 	local_irq_disable();
 	/* Set the watchdog timer to reset immediately */
-	ssb_watchdog_timer_set(&ssb_bcm47xx, 1);
+	switch (bcm47xx_active_bus_type) {
+	case BCM47XX_BUS_TYPE_SSB:
+		ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 1);
+		break;
+	}
 	while (1)
 		cpu_relax();
 }
@@ -52,7 +59,11 @@ static void bcm47xx_machine_halt(void)
 {
 	/* Disable interrupts and watchdog and spin forever */
 	local_irq_disable();
-	ssb_watchdog_timer_set(&ssb_bcm47xx, 0);
+	switch (bcm47xx_active_bus_type) {
+	case BCM47XX_BUS_TYPE_SSB:
+		ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0);
+		break;
+	}
 	while (1)
 		cpu_relax();
 }
@@ -247,7 +258,7 @@ static int bcm47xx_get_invariants(struct ssb_bus *bus,
 	return 0;
 }
 
-void __init plat_mem_setup(void)
+static void __init bcm47xx_register_ssb(void)
 {
 	int err;
 	char buf[100];
@@ -258,12 +269,12 @@ void __init plat_mem_setup(void)
 		printk(KERN_WARNING "bcm47xx: someone else already registered"
 			" a ssb SPROM callback handler (err %d)\n", err);
 
-	err = ssb_bus_ssbbus_register(&ssb_bcm47xx, SSB_ENUM_BASE,
+	err = ssb_bus_ssbbus_register(&(bcm47xx_bus.ssb), SSB_ENUM_BASE,
 				      bcm47xx_get_invariants);
 	if (err)
 		panic("Failed to initialize SSB bus (err %d)\n", err);
 
-	mcore = &ssb_bcm47xx.mipscore;
+	mcore = &bcm47xx_bus.ssb.mipscore;
 	if (nvram_getenv("kernel_args", buf, sizeof(buf)) >= 0) {
 		if (strstr(buf, "console=ttyS1")) {
 			struct ssb_serial_port port;
@@ -276,6 +287,14 @@ void __init plat_mem_setup(void)
 			memcpy(&mcore->serial_ports[1], &port, sizeof(port));
 		}
 	}
+}
+
+void __init plat_mem_setup(void)
+{
+	struct cpuinfo_mips *c = &current_cpu_data;
+
+	bcm47xx_active_bus_type = BCM47XX_BUS_TYPE_SSB;
+	bcm47xx_register_ssb();
 
 	_machine_restart = bcm47xx_machine_restart;
 	_machine_halt = bcm47xx_machine_halt;
diff --git a/arch/mips/bcm47xx/time.c b/arch/mips/bcm47xx/time.c
index 0c6f47b..a7be993 100644
--- a/arch/mips/bcm47xx/time.c
+++ b/arch/mips/bcm47xx/time.c
@@ -30,7 +30,7 @@
 
 void __init plat_time_init(void)
 {
-	unsigned long hz;
+	unsigned long hz = 0;
 
 	/*
 	 * Use deterministic values for initial counter interrupt
@@ -39,7 +39,12 @@ void __init plat_time_init(void)
 	write_c0_count(0);
 	write_c0_compare(0xffff);
 
-	hz = ssb_cpu_clock(&ssb_bcm47xx.mipscore) / 2;
+	switch (bcm47xx_active_bus_type) {
+	case BCM47XX_BUS_TYPE_SSB:
+		hz = ssb_cpu_clock(&bcm47xx_bus.ssb.mipscore) / 2;
+		break;
+	}
+
 	if (!hz)
 		hz = 100000000;
 
diff --git a/arch/mips/bcm47xx/wgt634u.c b/arch/mips/bcm47xx/wgt634u.c
index 74d0696..d4aedd5 100644
--- a/arch/mips/bcm47xx/wgt634u.c
+++ b/arch/mips/bcm47xx/wgt634u.c
@@ -108,7 +108,7 @@ static irqreturn_t gpio_interrupt(int irq, void *ignored)
 
 	/* Interrupts are shared, check if the current one is
 	   a GPIO interrupt. */
-	if (!ssb_chipco_irq_status(&ssb_bcm47xx.chipco,
+	if (!ssb_chipco_irq_status(&bcm47xx_bus.ssb.chipco,
 				   SSB_CHIPCO_IRQ_GPIO))
 		return IRQ_NONE;
 
@@ -132,22 +132,26 @@ static int __init wgt634u_init(void)
 	 * machine. Use the MAC address as an heuristic. Netgear Inc. has
 	 * been allocated ranges 00:09:5b:xx:xx:xx and 00:0f:b5:xx:xx:xx.
 	 */
+	u8 *et0mac;
 
-	u8 *et0mac = ssb_bcm47xx.sprom.et0mac;
+	if (bcm47xx_active_bus_type != BCM47XX_BUS_TYPE_SSB)
+		return -ENODEV;
+
+	et0mac = bcm47xx_bus.ssb.sprom.et0mac;
 
 	if (et0mac[0] == 0x00 &&
 	    ((et0mac[1] == 0x09 && et0mac[2] == 0x5b) ||
 	     (et0mac[1] == 0x0f && et0mac[2] == 0xb5))) {
-		struct ssb_mipscore *mcore = &ssb_bcm47xx.mipscore;
+		struct ssb_mipscore *mcore = &bcm47xx_bus.ssb.mipscore;
 
 		printk(KERN_INFO "WGT634U machine detected.\n");
 
 		if (!request_irq(gpio_to_irq(WGT634U_GPIO_RESET),
 				 gpio_interrupt, IRQF_SHARED,
-				 "WGT634U GPIO", &ssb_bcm47xx.chipco)) {
+				 "WGT634U GPIO", &bcm47xx_bus.ssb.chipco)) {
 			gpio_direction_input(WGT634U_GPIO_RESET);
 			gpio_intmask(WGT634U_GPIO_RESET, 1);
-			ssb_chipco_irq_mask(&ssb_bcm47xx.chipco,
+			ssb_chipco_irq_mask(&bcm47xx_bus.ssb.chipco,
 					    SSB_CHIPCO_IRQ_GPIO,
 					    SSB_CHIPCO_IRQ_GPIO);
 		}
diff --git a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
index d008f47..4be8b95 100644
--- a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
+++ b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
@@ -19,7 +19,17 @@
 #ifndef __ASM_BCM47XX_H
 #define __ASM_BCM47XX_H
 
-/* SSB bus */
-extern struct ssb_bus ssb_bcm47xx;
+#include <linux/ssb/ssb.h>
+
+enum bcm47xx_bus_type {
+	BCM47XX_BUS_TYPE_SSB,
+};
+
+union bcm47xx_bus {
+	struct ssb_bus ssb;
+};
+
+extern union bcm47xx_bus bcm47xx_bus;
+extern enum bcm47xx_bus_type bcm47xx_active_bus_type;
 
 #endif /* __ASM_BCM47XX_H */
diff --git a/arch/mips/include/asm/mach-bcm47xx/gpio.h b/arch/mips/include/asm/mach-bcm47xx/gpio.h
index 9850414..976b8aa 100644
--- a/arch/mips/include/asm/mach-bcm47xx/gpio.h
+++ b/arch/mips/include/asm/mach-bcm47xx/gpio.h
@@ -21,41 +21,66 @@ extern int gpio_to_irq(unsigned gpio);
 
 static inline int gpio_get_value(unsigned gpio)
 {
-	return ssb_gpio_in(&ssb_bcm47xx, 1 << gpio);
+	switch (bcm47xx_active_bus_type) {
+	case BCM47XX_BUS_TYPE_SSB:
+		return ssb_gpio_in(&bcm47xx_bus.ssb, 1 << gpio);
+	}
+	return -EINVAL;
 }
 
 static inline void gpio_set_value(unsigned gpio, int value)
 {
-	ssb_gpio_out(&ssb_bcm47xx, 1 << gpio, value ? 1 << gpio : 0);
+	switch (bcm47xx_active_bus_type) {
+	case BCM47XX_BUS_TYPE_SSB:
+		ssb_gpio_out(&bcm47xx_bus.ssb, 1 << gpio,
+			     value ? 1 << gpio : 0);
+	}
 }
 
 static inline int gpio_direction_input(unsigned gpio)
 {
-	ssb_gpio_outen(&ssb_bcm47xx, 1 << gpio, 0);
-	return 0;
+	switch (bcm47xx_active_bus_type) {
+	case BCM47XX_BUS_TYPE_SSB:
+		ssb_gpio_outen(&bcm47xx_bus.ssb, 1 << gpio, 0);
+		return 0;
+	}
+	return -EINVAL;
 }
 
 static inline int gpio_direction_output(unsigned gpio, int value)
 {
-	/* first set the gpio out value */
-	ssb_gpio_out(&ssb_bcm47xx, 1 << gpio, value ? 1 << gpio : 0);
-	/* then set the gpio mode */
-	ssb_gpio_outen(&ssb_bcm47xx, 1 << gpio, 1 << gpio);
-	return 0;
+	switch (bcm47xx_active_bus_type) {
+	case BCM47XX_BUS_TYPE_SSB:
+		/* first set the gpio out value */
+		ssb_gpio_out(&bcm47xx_bus.ssb, 1 << gpio,
+			     value ? 1 << gpio : 0);
+		/* then set the gpio mode */
+		ssb_gpio_outen(&bcm47xx_bus.ssb, 1 << gpio, 1 << gpio);
+		return 0;
+	}
+	return -EINVAL;
 }
 
 static inline int gpio_intmask(unsigned gpio, int value)
 {
-	ssb_gpio_intmask(&ssb_bcm47xx, 1 << gpio,
-			 value ? 1 << gpio : 0);
-	return 0;
+	switch (bcm47xx_active_bus_type) {
+	case BCM47XX_BUS_TYPE_SSB:
+		ssb_gpio_intmask(&bcm47xx_bus.ssb, 1 << gpio,
+				 value ? 1 << gpio : 0);
+		return 0;
+	}
+	return -EINVAL;
 }
 
 static inline int gpio_polarity(unsigned gpio, int value)
 {
-	ssb_gpio_polarity(&ssb_bcm47xx, 1 << gpio,
-			  value ? 1 << gpio : 0);
-	return 0;
+	switch (bcm47xx_active_bus_type) {
+	case BCM47XX_BUS_TYPE_SSB:
+		ssb_gpio_polarity(&bcm47xx_bus.ssb, 1 << gpio,
+				  value ? 1 << gpio : 0);
+		return 0;
+	}
+	return -EINVAL;
 }
 
 
diff --git a/drivers/watchdog/bcm47xx_wdt.c b/drivers/watchdog/bcm47xx_wdt.c
index bd44417..7e4e063 100644
--- a/drivers/watchdog/bcm47xx_wdt.c
+++ b/drivers/watchdog/bcm47xx_wdt.c
@@ -54,12 +54,20 @@ static atomic_t ticks;
 static inline void bcm47xx_wdt_hw_start(void)
 {
 	/* this is 2,5s on 100Mhz clock  and 2s on 133 Mhz */
-	ssb_watchdog_timer_set(&ssb_bcm47xx, 0xfffffff);
+	switch (bcm47xx_active_bus_type) {
+	case BCM47XX_BUS_TYPE_SSB:
+		ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0xfffffff);
+		break;
+	}
 }
 
 static inline int bcm47xx_wdt_hw_stop(void)
 {
-	return ssb_watchdog_timer_set(&ssb_bcm47xx, 0);
+	switch (bcm47xx_active_bus_type) {
+	case BCM47XX_BUS_TYPE_SSB:
+		return ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0);
+	}
+	return -EINVAL;
 }
 
 static void bcm47xx_timer_tick(unsigned long unused)
-- 
1.7.4.1


From hauke@hauke-m.de Sat Jul  9 13:06:57 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 09 Jul 2011 13:10:26 +0200 (CEST)
Received: from server19320154104.serverpool.info ([193.201.54.104]:41998 "EHLO
        hauke-m.de" rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org
        with ESMTP id S1491197Ab1GILG5 (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Sat, 9 Jul 2011 13:06:57 +0200
Received: from localhost (localhost [127.0.0.1])
        by hauke-m.de (Postfix) with ESMTP id CF6AA8C75;
        Sat,  9 Jul 2011 13:06:56 +0200 (CEST)
X-Virus-Scanned: Debian amavisd-new at hauke-m.de 
Received: from hauke-m.de ([127.0.0.1])
        by localhost (hauke-m.de [127.0.0.1]) (amavisd-new, port 10024)
        with ESMTP id lwkMhvhEPqaY; Sat,  9 Jul 2011 13:06:41 +0200 (CEST)
Received: from localhost.localdomain (dyndsl-095-033-240-133.ewe-ip-backbone.de [95.33.240.133])
        by hauke-m.de (Postfix) with ESMTPSA id 10A4E8C69;
        Sat,  9 Jul 2011 13:06:29 +0200 (CEST)
From:   Hauke Mehrtens <hauke@hauke-m.de>
To:     ralf@linux-mips.org, linux-wireless@vger.kernel.org,
        zajec5@gmail.com, linux-mips@linux-mips.org
Cc:     mb@bu3sch.de, george@znau.edu.ua, arend@broadcom.com,
        b43-dev@lists.infradead.org, bernhardloos@googlemail.com,
        arnd@arndb.de, julian.calaby@gmail.com, sshtylyov@mvista.com,
        Hauke Mehrtens <hauke@hauke-m.de>
Subject: [PATCH 07/11] bcma: get CPU clock
Date:   Sat,  9 Jul 2011 13:05:59 +0200
Message-Id: <1310209563-6405-8-git-send-email-hauke@hauke-m.de>
X-Mailer: git-send-email 1.7.4.1
In-Reply-To: <1310209563-6405-1-git-send-email-hauke@hauke-m.de>
References: <1310209563-6405-1-git-send-email-hauke@hauke-m.de>
X-archive-position: 30601
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: hauke@hauke-m.de
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 6781
Content-Length: 6905
Lines: 212

Add method to return the clock of the CPU. This is needed by the arch
code to calculate the mips_hpt_frequency.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 drivers/bcma/bcma_private.h                 |    3 +
 drivers/bcma/driver_chipcommon_pmu.c        |   87 +++++++++++++++++++++++++++
 drivers/bcma/driver_mips.c                  |   12 ++++
 include/linux/bcma/bcma_driver_chipcommon.h |   35 +++++++++++
 include/linux/bcma/bcma_driver_mips.h       |    1 +
 5 files changed, 138 insertions(+), 0 deletions(-)

diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h
index 92ec671..7e126b9 100644
--- a/drivers/bcma/bcma_private.h
+++ b/drivers/bcma/bcma_private.h
@@ -26,6 +26,9 @@ int __init bcma_bus_scan_early(struct bcma_bus *bus,
 			       struct bcma_device *core);
 void bcma_init_bus(struct bcma_bus *bus);
 
+/* driver_chipcommon_pmu.c */
+extern u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc);
+
 /* driver_chipcommon.c */
 #ifdef CONFIG_BCMA_DRIVER_MIPS
 extern int bcma_chipco_serial_init(struct bcma_drv_cc *cc,
diff --git a/drivers/bcma/driver_chipcommon_pmu.c b/drivers/bcma/driver_chipcommon_pmu.c
index f44177a..83988be 100644
--- a/drivers/bcma/driver_chipcommon_pmu.c
+++ b/drivers/bcma/driver_chipcommon_pmu.c
@@ -11,6 +11,13 @@
 #include "bcma_private.h"
 #include <linux/bcma/bcma.h>
 
+static u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset)
+{
+	bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
+	bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
+	return bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
+}
+
 static void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
 					u32 offset, u32 mask, u32 set)
 {
@@ -132,3 +139,83 @@ void bcma_pmu_init(struct bcma_drv_cc *cc)
 	bcma_pmu_swreg_init(cc);
 	bcma_pmu_workarounds(cc);
 }
+
+static u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc)
+{
+	struct bcma_bus *bus = cc->core->bus;
+
+	switch (bus->chipinfo.id) {
+	case 0x4716:
+	case 0x4748:
+	case 47162:
+		/* always 20Mhz */
+		return 20000 * 1000;
+	default:
+		pr_warn("No ALP clock specified for %04X device, "
+			"pmu rev. %d, using default %d Hz\n",
+			bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_ALP_CLOCK);
+	}
+	return BCMA_CC_PMU_ALP_CLOCK;
+}
+
+/* Find the output of the "m" pll divider given pll controls that start with
+ * pllreg "pll0" i.e. 12 for main 6 for phy, 0 for misc.
+ */
+static u32 bcma_pmu_clock(struct bcma_drv_cc *cc, u32 pll0, u32 m)
+{
+	u32 tmp, div, ndiv, p1, p2, fc;
+
+	BUG_ON(!m || m > 4);
+
+	BUG_ON((pll0 & 3) || (pll0 > BCMA_CC_PMU4716_MAINPLL_PLL0));
+
+	tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_P1P2_OFF);
+	p1 = (tmp & BCMA_CC_PPL_P1_MASK) >> BCMA_CC_PPL_P1_SHIFT;
+	p2 = (tmp & BCMA_CC_PPL_P2_MASK) >> BCMA_CC_PPL_P2_SHIFT;
+
+	tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_M14_OFF);
+	div = (tmp >> ((m - 1) * BCMA_CC_PPL_MDIV_WIDTH)) &
+		BCMA_CC_PPL_MDIV_MASK;
+
+	tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_NM5_OFF);
+	ndiv = (tmp & BCMA_CC_PPL_NDIV_MASK) >> BCMA_CC_PPL_NDIV_SHIFT;
+
+	/* Do calculation in Mhz */
+	fc = bcma_pmu_alp_clock(cc) / 1000000;
+	fc = (p1 * ndiv * fc) / p2;
+
+	/* Return clock in Hertz */
+	return (fc / div) * 1000000;
+}
+
+/* query bus clock frequency for PMU-enabled chipcommon */
+u32 bcma_pmu_get_clockcontrol(struct bcma_drv_cc *cc)
+{
+	struct bcma_bus *bus = cc->core->bus;
+
+	switch (bus->chipinfo.id) {
+	case 0x4716:
+	case 0x4748:
+	case 47162:
+		return bcma_pmu_clock(cc, BCMA_CC_PMU4716_MAINPLL_PLL0,
+				      BCMA_CC_PMU5_MAINPLL_SSB);
+	default:
+		pr_warn("No backplane clock specified for %04X device, "
+			"pmu rev. %d, using default %d Hz\n",
+			bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_HT_CLOCK);
+	}
+	return BCMA_CC_PMU_HT_CLOCK;
+}
+
+/* query cpu clock frequency for PMU-enabled chipcommon */
+u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc)
+{
+	struct bcma_bus *bus = cc->core->bus;
+
+	if ((cc->pmu.rev == 5 || cc->pmu.rev == 6 || cc->pmu.rev == 7) &&
+	    (bus->chipinfo.id != 0x4319))
+		return bcma_pmu_clock(cc, BCMA_CC_PMU4716_MAINPLL_PLL0,
+				      BCMA_CC_PMU5_MAINPLL_CPU);
+
+	return bcma_pmu_get_clockcontrol(cc);
+}
diff --git a/drivers/bcma/driver_mips.c b/drivers/bcma/driver_mips.c
index 3989fb9..813f9df 100644
--- a/drivers/bcma/driver_mips.c
+++ b/drivers/bcma/driver_mips.c
@@ -156,6 +156,18 @@ static void bcma_core_mips_dump_irq(struct bcma_bus *bus)
 	}
 }
 
+u32 bcma_cpu_clock(struct bcma_drv_mips *mcore)
+{
+	struct bcma_bus *bus = mcore->core->bus;
+
+	if (bus->drv_cc.capabilities & BCMA_CC_CAP_PMU)
+		return bcma_pmu_get_clockcpu(&bus->drv_cc);
+
+	pr_err("No PMU available, need this to get the cpu clock\n");
+	return 0;
+}
+EXPORT_SYMBOL(bcma_cpu_clock);
+
 static void bcma_core_mips_serial_init(struct bcma_drv_mips *mcore)
 {
 	struct bcma_bus *bus = mcore->core->bus;
diff --git a/include/linux/bcma/bcma_driver_chipcommon.h b/include/linux/bcma/bcma_driver_chipcommon.h
index 837c176..9da7562 100644
--- a/include/linux/bcma/bcma_driver_chipcommon.h
+++ b/include/linux/bcma/bcma_driver_chipcommon.h
@@ -245,6 +245,41 @@
 #define BCMA_CC_PLLCTL_ADDR		0x0660
 #define BCMA_CC_PLLCTL_DATA		0x0664
 
+/* Divider allocation in 4716/47162/5356 */
+#define BCMA_CC_PMU5_MAINPLL_CPU	1
+#define BCMA_CC_PMU5_MAINPLL_MEM	2
+#define BCMA_CC_PMU5_MAINPLL_SSB	3
+
+/* PLL usage in 4716/47162 */
+#define BCMA_CC_PMU4716_MAINPLL_PLL0	12
+
+/* ALP clock on pre-PMU chips */
+#define BCMA_CC_PMU_ALP_CLOCK		20000000
+/* HT clock for systems with PMU-enabled chipcommon */
+#define BCMA_CC_PMU_HT_CLOCK		80000000
+
+/* PMU rev 5 (& 6) */
+#define	BCMA_CC_PPL_P1P2_OFF		0
+#define	BCMA_CC_PPL_P1_MASK		0x0f000000
+#define	BCMA_CC_PPL_P1_SHIFT		24
+#define	BCMA_CC_PPL_P2_MASK		0x00f00000
+#define	BCMA_CC_PPL_P2_SHIFT		20
+#define	BCMA_CC_PPL_M14_OFF		1
+#define	BCMA_CC_PPL_MDIV_MASK		0x000000ff
+#define	BCMA_CC_PPL_MDIV_WIDTH		8
+#define	BCMA_CC_PPL_NM5_OFF		2
+#define	BCMA_CC_PPL_NDIV_MASK		0xfff00000
+#define	BCMA_CC_PPL_NDIV_SHIFT		20
+#define	BCMA_CC_PPL_FMAB_OFF		3
+#define	BCMA_CC_PPL_MRAT_MASK		0xf0000000
+#define	BCMA_CC_PPL_MRAT_SHIFT		28
+#define	BCMA_CC_PPL_ABRAT_MASK		0x08000000
+#define	BCMA_CC_PPL_ABRAT_SHIFT		27
+#define	BCMA_CC_PPL_FDIV_MASK		0x07ffffff
+#define	BCMA_CC_PPL_PLLCTL_OFF		4
+#define	BCMA_CC_PPL_PCHI_OFF		5
+#define	BCMA_CC_PPL_PCHI_MASK		0x0000003f
+
 /* Data for the PMU, if available.
  * Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
  */
diff --git a/include/linux/bcma/bcma_driver_mips.h b/include/linux/bcma/bcma_driver_mips.h
index 13b44c2..402af95 100644
--- a/include/linux/bcma/bcma_driver_mips.h
+++ b/include/linux/bcma/bcma_driver_mips.h
@@ -54,6 +54,7 @@ struct bcma_drv_mips {
 };
 
 extern void bcma_core_mips_init(struct bcma_drv_mips *mcore);
+extern u32 bcma_cpu_clock(struct bcma_drv_mips *mcore);
 
 extern unsigned int bcma_core_mips_irq(struct bcma_device *dev);
 
-- 
1.7.4.1


From hauke@hauke-m.de Sat Jul  9 13:06:59 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 09 Jul 2011 13:10:50 +0200 (CEST)
Received: from server19320154104.serverpool.info ([193.201.54.104]:42009 "EHLO
        hauke-m.de" rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org
        with ESMTP id S1491859Ab1GILG7 (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Sat, 9 Jul 2011 13:06:59 +0200
Received: from localhost (localhost [127.0.0.1])
        by hauke-m.de (Postfix) with ESMTP id 77FB28C69;
        Sat,  9 Jul 2011 13:06:59 +0200 (CEST)
X-Virus-Scanned: Debian amavisd-new at hauke-m.de 
Received: from hauke-m.de ([127.0.0.1])
        by localhost (hauke-m.de [127.0.0.1]) (amavisd-new, port 10024)
        with ESMTP id RZ90UiHOJZzD; Sat,  9 Jul 2011 13:06:51 +0200 (CEST)
Received: from localhost.localdomain (dyndsl-095-033-240-133.ewe-ip-backbone.de [95.33.240.133])
        by hauke-m.de (Postfix) with ESMTPSA id ED4108C6A;
        Sat,  9 Jul 2011 13:06:30 +0200 (CEST)
From:   Hauke Mehrtens <hauke@hauke-m.de>
To:     ralf@linux-mips.org, linux-wireless@vger.kernel.org,
        zajec5@gmail.com, linux-mips@linux-mips.org
Cc:     mb@bu3sch.de, george@znau.edu.ua, arend@broadcom.com,
        b43-dev@lists.infradead.org, bernhardloos@googlemail.com,
        arnd@arndb.de, julian.calaby@gmail.com, sshtylyov@mvista.com,
        Hauke Mehrtens <hauke@hauke-m.de>
Subject: [PATCH 09/11] bcm47xx: make it possible to build bcm47xx without ssb.
Date:   Sat,  9 Jul 2011 13:06:01 +0200
Message-Id: <1310209563-6405-10-git-send-email-hauke@hauke-m.de>
X-Mailer: git-send-email 1.7.4.1
In-Reply-To: <1310209563-6405-1-git-send-email-hauke@hauke-m.de>
References: <1310209563-6405-1-git-send-email-hauke@hauke-m.de>
X-archive-position: 30602
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: hauke@hauke-m.de
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 6782
Content-Length: 11818
Lines: 418


Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 arch/mips/Kconfig                            |    8 +-------
 arch/mips/bcm47xx/Kconfig                    |   18 ++++++++++++++++++
 arch/mips/bcm47xx/Makefile                   |    3 ++-
 arch/mips/bcm47xx/gpio.c                     |    6 ++++++
 arch/mips/bcm47xx/nvram.c                    |    4 ++++
 arch/mips/bcm47xx/serial.c                   |    4 ++++
 arch/mips/bcm47xx/setup.c                    |    8 ++++++++
 arch/mips/bcm47xx/time.c                     |    2 ++
 arch/mips/include/asm/mach-bcm47xx/bcm47xx.h |    4 ++++
 arch/mips/include/asm/mach-bcm47xx/gpio.h    |   12 ++++++++++++
 arch/mips/pci/pci-bcm47xx.c                  |    6 ++++++
 drivers/watchdog/bcm47xx_wdt.c               |    4 ++++
 12 files changed, 71 insertions(+), 8 deletions(-)
 create mode 100644 arch/mips/bcm47xx/Kconfig

diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 653da62..ac6f237 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -91,15 +91,8 @@ config BCM47XX
 	select DMA_NONCOHERENT
 	select HW_HAS_PCI
 	select IRQ_CPU
-	select SYS_HAS_CPU_MIPS32_R1
 	select SYS_SUPPORTS_32BIT_KERNEL
 	select SYS_SUPPORTS_LITTLE_ENDIAN
-	select SSB
-	select SSB_DRIVER_MIPS
-	select SSB_DRIVER_EXTIF
-	select SSB_EMBEDDED
-	select SSB_B43_PCI_BRIDGE if PCI
-	select SSB_PCICORE_HOSTMODE if PCI
 	select GENERIC_GPIO
 	select SYS_HAS_EARLY_PRINTK
 	select CFE
@@ -785,6 +778,7 @@ endchoice
 
 source "arch/mips/alchemy/Kconfig"
 source "arch/mips/ath79/Kconfig"
+source "arch/mips/bcm47xx/Kconfig"
 source "arch/mips/bcm63xx/Kconfig"
 source "arch/mips/jazz/Kconfig"
 source "arch/mips/jz4740/Kconfig"
diff --git a/arch/mips/bcm47xx/Kconfig b/arch/mips/bcm47xx/Kconfig
new file mode 100644
index 0000000..0346f92
--- /dev/null
+++ b/arch/mips/bcm47xx/Kconfig
@@ -0,0 +1,18 @@
+if BCM47XX
+
+config BCM47XX_SSB
+	bool "SSB Support for Broadcom BCM47XX"
+	select SYS_HAS_CPU_MIPS32_R1
+	select SSB
+	select SSB_DRIVER_MIPS
+	select SSB_DRIVER_EXTIF
+	select SSB_EMBEDDED
+	select SSB_B43_PCI_BRIDGE if PCI
+	select SSB_PCICORE_HOSTMODE if PCI
+	default y
+	help
+	 Add support for old Broadcom BCM47xx boards with Sonics Silicon Backplane support.
+
+	 This will generate an image with support for SSB and MIPS32 R1 instruction set.
+
+endif
diff --git a/arch/mips/bcm47xx/Makefile b/arch/mips/bcm47xx/Makefile
index 7465e8a..4add173 100644
--- a/arch/mips/bcm47xx/Makefile
+++ b/arch/mips/bcm47xx/Makefile
@@ -3,4 +3,5 @@
 # under Linux.
 #
 
-obj-y := gpio.o irq.o nvram.o prom.o serial.o setup.o time.o wgt634u.o
+obj-y 				+= gpio.o irq.o nvram.o prom.o serial.o setup.o time.o
+obj-$(CONFIG_BCM47XX_SSB)	+= wgt634u.o
diff --git a/arch/mips/bcm47xx/gpio.c b/arch/mips/bcm47xx/gpio.c
index 2f6d2df..3320e91 100644
--- a/arch/mips/bcm47xx/gpio.c
+++ b/arch/mips/bcm47xx/gpio.c
@@ -21,6 +21,7 @@ static DECLARE_BITMAP(gpio_in_use, BCM47XX_EXTIF_GPIO_LINES);
 int gpio_request(unsigned gpio, const char *tag)
 {
 	switch (bcm47xx_active_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
 	case BCM47XX_BUS_TYPE_SSB:
 		if (ssb_chipco_available(&bcm47xx_bus.ssb.chipco) &&
 		    ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
@@ -34,6 +35,7 @@ int gpio_request(unsigned gpio, const char *tag)
 			return -EBUSY;
 
 		return 0;
+#endif
 	}
 	return -EINVAL;
 }
@@ -42,6 +44,7 @@ EXPORT_SYMBOL(gpio_request);
 void gpio_free(unsigned gpio)
 {
 	switch (bcm47xx_active_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
 	case BCM47XX_BUS_TYPE_SSB:
 		if (ssb_chipco_available(&bcm47xx_bus.ssb.chipco) &&
 		    ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
@@ -53,6 +56,7 @@ void gpio_free(unsigned gpio)
 
 		clear_bit(gpio, gpio_in_use);
 		return;
+#endif
 	}
 }
 EXPORT_SYMBOL(gpio_free);
@@ -60,6 +64,7 @@ EXPORT_SYMBOL(gpio_free);
 int gpio_to_irq(unsigned gpio)
 {
 	switch (bcm47xx_active_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
 	case BCM47XX_BUS_TYPE_SSB:
 		if (ssb_chipco_available(&bcm47xx_bus.ssb.chipco))
 			return ssb_mips_irq(bcm47xx_bus.ssb.chipco.dev) + 2;
@@ -67,6 +72,7 @@ int gpio_to_irq(unsigned gpio)
 			return ssb_mips_irq(bcm47xx_bus.ssb.extif.dev) + 2;
 		else
 			return -EINVAL;
+#endif
 	}
 	return -EINVAL;
 }
diff --git a/arch/mips/bcm47xx/nvram.c b/arch/mips/bcm47xx/nvram.c
index d2304d0..d223dac 100644
--- a/arch/mips/bcm47xx/nvram.c
+++ b/arch/mips/bcm47xx/nvram.c
@@ -26,7 +26,9 @@ static char nvram_buf[NVRAM_SPACE];
 /* Probe for NVRAM header */
 static void early_nvram_init(void)
 {
+#ifdef CONFIG_BCM47XX_SSB
 	struct ssb_mipscore *mcore_ssb;
+#endif
 	struct nvram_header *header;
 	int i;
 	u32 base = 0;
@@ -35,11 +37,13 @@ static void early_nvram_init(void)
 	u32 *src, *dst;
 
 	switch (bcm47xx_active_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
 	case BCM47XX_BUS_TYPE_SSB:
 		mcore_ssb = &bcm47xx_bus.ssb.mipscore;
 		base = mcore_ssb->flash_window;
 		lim = mcore_ssb->flash_window_size;
 		break;
+#endif
 	}
 
 	off = FLASH_MIN;
diff --git a/arch/mips/bcm47xx/serial.c b/arch/mips/bcm47xx/serial.c
index 87c2c5e..e9258cb 100644
--- a/arch/mips/bcm47xx/serial.c
+++ b/arch/mips/bcm47xx/serial.c
@@ -23,6 +23,7 @@ static struct platform_device uart8250_device = {
 	},
 };
 
+#ifdef CONFIG_BCM47XX_SSB
 static int __init uart8250_init_ssb(void)
 {
 	int i;
@@ -44,12 +45,15 @@ static int __init uart8250_init_ssb(void)
 	}
 	return platform_device_register(&uart8250_device);
 }
+#endif
 
 static int __init uart8250_init(void)
 {
 	switch (bcm47xx_active_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
 	case BCM47XX_BUS_TYPE_SSB:
 		return uart8250_init_ssb();
+#endif
 	}
 	return -EINVAL;
 }
diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c
index bff4181..9fc92bd 100644
--- a/arch/mips/bcm47xx/setup.c
+++ b/arch/mips/bcm47xx/setup.c
@@ -47,9 +47,11 @@ static void bcm47xx_machine_restart(char *command)
 	local_irq_disable();
 	/* Set the watchdog timer to reset immediately */
 	switch (bcm47xx_active_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
 	case BCM47XX_BUS_TYPE_SSB:
 		ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 1);
 		break;
+#endif
 	}
 	while (1)
 		cpu_relax();
@@ -60,14 +62,17 @@ static void bcm47xx_machine_halt(void)
 	/* Disable interrupts and watchdog and spin forever */
 	local_irq_disable();
 	switch (bcm47xx_active_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
 	case BCM47XX_BUS_TYPE_SSB:
 		ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0);
 		break;
+#endif
 	}
 	while (1)
 		cpu_relax();
 }
 
+#ifdef CONFIG_BCM47XX_SSB
 #define READ_FROM_NVRAM(_outvar, name, buf) \
 	if (nvram_getprefix(prefix, name, buf, sizeof(buf)) >= 0)\
 		sprom->_outvar = simple_strtoul(buf, NULL, 0);
@@ -288,13 +293,16 @@ static void __init bcm47xx_register_ssb(void)
 		}
 	}
 }
+#endif
 
 void __init plat_mem_setup(void)
 {
 	struct cpuinfo_mips *c = &current_cpu_data;
 
+#ifdef CONFIG_BCM47XX_SSB
 	bcm47xx_active_bus_type = BCM47XX_BUS_TYPE_SSB;
 	bcm47xx_register_ssb();
+#endif
 
 	_machine_restart = bcm47xx_machine_restart;
 	_machine_halt = bcm47xx_machine_halt;
diff --git a/arch/mips/bcm47xx/time.c b/arch/mips/bcm47xx/time.c
index a7be993..02a652a 100644
--- a/arch/mips/bcm47xx/time.c
+++ b/arch/mips/bcm47xx/time.c
@@ -40,9 +40,11 @@ void __init plat_time_init(void)
 	write_c0_compare(0xffff);
 
 	switch (bcm47xx_active_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
 	case BCM47XX_BUS_TYPE_SSB:
 		hz = ssb_cpu_clock(&bcm47xx_bus.ssb.mipscore) / 2;
 		break;
+#endif
 	}
 
 	if (!hz)
diff --git a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
index 4be8b95..764afea 100644
--- a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
+++ b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
@@ -22,11 +22,15 @@
 #include <linux/ssb/ssb.h>
 
 enum bcm47xx_bus_type {
+#ifdef CONFIG_BCM47XX_SSB
 	BCM47XX_BUS_TYPE_SSB,
+#endif
 };
 
 union bcm47xx_bus {
+#ifdef CONFIG_BCM47XX_SSB
 	struct ssb_bus ssb;
+#endif
 };
 
 extern union bcm47xx_bus bcm47xx_bus;
diff --git a/arch/mips/include/asm/mach-bcm47xx/gpio.h b/arch/mips/include/asm/mach-bcm47xx/gpio.h
index 976b8aa..0c3bd1f 100644
--- a/arch/mips/include/asm/mach-bcm47xx/gpio.h
+++ b/arch/mips/include/asm/mach-bcm47xx/gpio.h
@@ -22,8 +22,10 @@ extern int gpio_to_irq(unsigned gpio);
 static inline int gpio_get_value(unsigned gpio)
 {
 	switch (bcm47xx_active_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
 	case BCM47XX_BUS_TYPE_SSB:
 		return ssb_gpio_in(&bcm47xx_bus.ssb, 1 << gpio);
+#endif
 	}
 	return -EINVAL;
 }
@@ -31,18 +33,22 @@ static inline int gpio_get_value(unsigned gpio)
 static inline void gpio_set_value(unsigned gpio, int value)
 {
 	switch (bcm47xx_active_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
 	case BCM47XX_BUS_TYPE_SSB:
 		ssb_gpio_out(&bcm47xx_bus.ssb, 1 << gpio,
 			     value ? 1 << gpio : 0);
+#endif
 	}
 }
 
 static inline int gpio_direction_input(unsigned gpio)
 {
 	switch (bcm47xx_active_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
 	case BCM47XX_BUS_TYPE_SSB:
 		ssb_gpio_outen(&bcm47xx_bus.ssb, 1 << gpio, 0);
 		return 0;
+#endif
 	}
 	return -EINVAL;
 }
@@ -50,6 +56,7 @@ static inline int gpio_direction_input(unsigned gpio)
 static inline int gpio_direction_output(unsigned gpio, int value)
 {
 	switch (bcm47xx_active_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
 	case BCM47XX_BUS_TYPE_SSB:
 		/* first set the gpio out value */
 		ssb_gpio_out(&bcm47xx_bus.ssb, 1 << gpio,
@@ -57,6 +64,7 @@ static inline int gpio_direction_output(unsigned gpio, int value)
 		/* then set the gpio mode */
 		ssb_gpio_outen(&bcm47xx_bus.ssb, 1 << gpio, 1 << gpio);
 		return 0;
+#endif
 	}
 	return -EINVAL;
 }
@@ -64,10 +72,12 @@ static inline int gpio_direction_output(unsigned gpio, int value)
 static inline int gpio_intmask(unsigned gpio, int value)
 {
 	switch (bcm47xx_active_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
 	case BCM47XX_BUS_TYPE_SSB:
 		ssb_gpio_intmask(&bcm47xx_bus.ssb, 1 << gpio,
 				 value ? 1 << gpio : 0);
 		return 0;
+#endif
 	}
 	return -EINVAL;
 }
@@ -75,10 +85,12 @@ static inline int gpio_intmask(unsigned gpio, int value)
 static inline int gpio_polarity(unsigned gpio, int value)
 {
 	switch (bcm47xx_active_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
 	case BCM47XX_BUS_TYPE_SSB:
 		ssb_gpio_polarity(&bcm47xx_bus.ssb, 1 << gpio,
 				  value ? 1 << gpio : 0);
 		return 0;
+#endif
 	}
 	return -EINVAL;
 }
diff --git a/arch/mips/pci/pci-bcm47xx.c b/arch/mips/pci/pci-bcm47xx.c
index 455f8e5..924e158 100644
--- a/arch/mips/pci/pci-bcm47xx.c
+++ b/arch/mips/pci/pci-bcm47xx.c
@@ -25,6 +25,7 @@
 #include <linux/types.h>
 #include <linux/pci.h>
 #include <linux/ssb/ssb.h>
+#include <bcm47xx.h>
 
 int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
@@ -33,9 +34,13 @@ int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 
 int pcibios_plat_dev_init(struct pci_dev *dev)
 {
+#ifdef CONFIG_BCM47XX_SSB
 	int res;
 	u8 slot, pin;
 
+	if (bcm47xx_active_bus_type !=  BCM47XX_BUS_TYPE_SSB)
+		return 0;
+
 	res = ssb_pcibios_plat_dev_init(dev);
 	if (res < 0) {
 		printk(KERN_ALERT "PCI: Failed to init device %s\n",
@@ -55,5 +60,6 @@ int pcibios_plat_dev_init(struct pci_dev *dev)
 	}
 
 	dev->irq = res;
+#endif
 	return 0;
 }
diff --git a/drivers/watchdog/bcm47xx_wdt.c b/drivers/watchdog/bcm47xx_wdt.c
index 7e4e063..beacd79 100644
--- a/drivers/watchdog/bcm47xx_wdt.c
+++ b/drivers/watchdog/bcm47xx_wdt.c
@@ -55,17 +55,21 @@ static inline void bcm47xx_wdt_hw_start(void)
 {
 	/* this is 2,5s on 100Mhz clock  and 2s on 133 Mhz */
 	switch (bcm47xx_active_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
 	case BCM47XX_BUS_TYPE_SSB:
 		ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0xfffffff);
 		break;
+#endif
 	}
 }
 
 static inline int bcm47xx_wdt_hw_stop(void)
 {
 	switch (bcm47xx_active_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
 	case BCM47XX_BUS_TYPE_SSB:
 		return ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0);
+#endif
 	}
 	return -EINVAL;
 }
-- 
1.7.4.1


From hauke@hauke-m.de Sat Jul  9 13:07:02 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 09 Jul 2011 13:11:17 +0200 (CEST)
Received: from server19320154104.serverpool.info ([193.201.54.104]:42022 "EHLO
        hauke-m.de" rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org
        with ESMTP id S1492161Ab1GILHC (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Sat, 9 Jul 2011 13:07:02 +0200
Received: from localhost (localhost [127.0.0.1])
        by hauke-m.de (Postfix) with ESMTP id 1FEAD8C76;
        Sat,  9 Jul 2011 13:07:02 +0200 (CEST)
X-Virus-Scanned: Debian amavisd-new at hauke-m.de 
Received: from hauke-m.de ([127.0.0.1])
        by localhost (hauke-m.de [127.0.0.1]) (amavisd-new, port 10024)
        with ESMTP id mJSeJPEIJJHB; Sat,  9 Jul 2011 13:06:57 +0200 (CEST)
Received: from localhost.localdomain (dyndsl-095-033-240-133.ewe-ip-backbone.de [95.33.240.133])
        by hauke-m.de (Postfix) with ESMTPSA id D73418C6B;
        Sat,  9 Jul 2011 13:06:31 +0200 (CEST)
From:   Hauke Mehrtens <hauke@hauke-m.de>
To:     ralf@linux-mips.org, linux-wireless@vger.kernel.org,
        zajec5@gmail.com, linux-mips@linux-mips.org
Cc:     mb@bu3sch.de, george@znau.edu.ua, arend@broadcom.com,
        b43-dev@lists.infradead.org, bernhardloos@googlemail.com,
        arnd@arndb.de, julian.calaby@gmail.com, sshtylyov@mvista.com,
        Hauke Mehrtens <hauke@hauke-m.de>
Subject: [PATCH 10/11] bcm47xx: add support for bcma bus
Date:   Sat,  9 Jul 2011 13:06:02 +0200
Message-Id: <1310209563-6405-11-git-send-email-hauke@hauke-m.de>
X-Mailer: git-send-email 1.7.4.1
In-Reply-To: <1310209563-6405-1-git-send-email-hauke@hauke-m.de>
References: <1310209563-6405-1-git-send-email-hauke@hauke-m.de>
X-archive-position: 30603
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: hauke@hauke-m.de
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 6783
Content-Length: 11629
Lines: 426

This patch add support for the bcma bus. Broadcom uses only Mips 74K
CPUs on the new SoC and on the old ons using ssb bus there are no Mips
74K CPUs.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 arch/mips/bcm47xx/Kconfig                    |   13 ++++++
 arch/mips/bcm47xx/gpio.c                     |   22 +++++++++++
 arch/mips/bcm47xx/nvram.c                    |   10 +++++
 arch/mips/bcm47xx/serial.c                   |   29 ++++++++++++++
 arch/mips/bcm47xx/setup.c                    |   53 +++++++++++++++++++++++++-
 arch/mips/bcm47xx/time.c                     |    5 ++
 arch/mips/include/asm/mach-bcm47xx/bcm47xx.h |    8 ++++
 arch/mips/include/asm/mach-bcm47xx/gpio.h    |   41 ++++++++++++++++++++
 drivers/watchdog/bcm47xx_wdt.c               |   11 +++++
 9 files changed, 190 insertions(+), 2 deletions(-)

diff --git a/arch/mips/bcm47xx/Kconfig b/arch/mips/bcm47xx/Kconfig
index 0346f92..6210b8d 100644
--- a/arch/mips/bcm47xx/Kconfig
+++ b/arch/mips/bcm47xx/Kconfig
@@ -15,4 +15,17 @@ config BCM47XX_SSB
 
 	 This will generate an image with support for SSB and MIPS32 R1 instruction set.
 
+config BCM47XX_BCMA
+	bool "BCMA Support for Broadcom BCM47XX"
+	select SYS_HAS_CPU_MIPS32_R2
+	select BCMA
+	select BCMA_HOST_SOC
+	select BCMA_DRIVER_MIPS
+	select BCMA_DRIVER_PCI_HOSTMODE if PCI
+	default y
+	help
+	 Add support for new Broadcom BCM47xx boards with Broadcom specific Advanced Microcontroller Bus.
+
+	 This will generate an image with support for BCMA and MIPS32 R2 instruction set.
+
 endif
diff --git a/arch/mips/bcm47xx/gpio.c b/arch/mips/bcm47xx/gpio.c
index 3320e91..9d5bafe 100644
--- a/arch/mips/bcm47xx/gpio.c
+++ b/arch/mips/bcm47xx/gpio.c
@@ -36,6 +36,16 @@ int gpio_request(unsigned gpio, const char *tag)
 
 		return 0;
 #endif
+#ifdef CONFIG_BCM47XX_BCMA
+	case BCM47XX_BUS_TYPE_BCMA:
+		if ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES)
+			return -EINVAL;
+
+		if (test_and_set_bit(gpio, gpio_in_use))
+			return -EBUSY;
+
+		return 0;
+#endif
 	}
 	return -EINVAL;
 }
@@ -57,6 +67,14 @@ void gpio_free(unsigned gpio)
 		clear_bit(gpio, gpio_in_use);
 		return;
 #endif
+#ifdef CONFIG_BCM47XX_BCMA
+	case BCM47XX_BUS_TYPE_BCMA:
+		if ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES)
+			return;
+
+		clear_bit(gpio, gpio_in_use);
+		return;
+#endif
 	}
 }
 EXPORT_SYMBOL(gpio_free);
@@ -73,6 +91,10 @@ int gpio_to_irq(unsigned gpio)
 		else
 			return -EINVAL;
 #endif
+#ifdef CONFIG_BCM47XX_BCMA
+	case BCM47XX_BUS_TYPE_BCMA:
+		return bcma_core_mips_irq(bcm47xx_bus.bcma.bus.drv_cc.core) + 2;
+#endif
 	}
 	return -EINVAL;
 }
diff --git a/arch/mips/bcm47xx/nvram.c b/arch/mips/bcm47xx/nvram.c
index d223dac..1dafb9b 100644
--- a/arch/mips/bcm47xx/nvram.c
+++ b/arch/mips/bcm47xx/nvram.c
@@ -29,6 +29,9 @@ static void early_nvram_init(void)
 #ifdef CONFIG_BCM47XX_SSB
 	struct ssb_mipscore *mcore_ssb;
 #endif
+#ifdef CONFIG_BCM47XX_BCMA
+	struct bcma_drv_mips *mcore_bcma;
+#endif
 	struct nvram_header *header;
 	int i;
 	u32 base = 0;
@@ -44,6 +47,13 @@ static void early_nvram_init(void)
 		lim = mcore_ssb->flash_window_size;
 		break;
 #endif
+#ifdef CONFIG_BCM47XX_BCMA
+	case BCM47XX_BUS_TYPE_BCMA:
+		mcore_bcma = &bcm47xx_bus.bcma.bus.drv_mips;
+		base = mcore_bcma->flash_window;
+		lim = mcore_bcma->flash_window_size;
+		break;
+#endif
 	}
 
 	off = FLASH_MIN;
diff --git a/arch/mips/bcm47xx/serial.c b/arch/mips/bcm47xx/serial.c
index e9258cb..52ce06a 100644
--- a/arch/mips/bcm47xx/serial.c
+++ b/arch/mips/bcm47xx/serial.c
@@ -47,6 +47,31 @@ static int __init uart8250_init_ssb(void)
 }
 #endif
 
+#ifdef CONFIG_BCM47XX_BCMA
+static int __init uart8250_init_bcma(void)
+{
+	int i;
+	struct bcma_drv_mips *mcore = &(bcm47xx_bus.bcma.bus.drv_mips);
+
+	memset(&uart8250_data, 0,  sizeof(uart8250_data));
+
+	for (i = 0; i < mcore->nr_serial_ports; i++) {
+		struct plat_serial8250_port *p = &(uart8250_data[i]);
+		struct bcma_drv_mips_serial_port *bcma_port;
+		bcma_port = &(mcore->serial_ports[i]);
+
+		p->mapbase = (unsigned int) bcma_port->regs;
+		p->membase = (void *) bcma_port->regs;
+		p->irq = bcma_port->irq + 2;
+		p->uartclk = bcma_port->baud_base;
+		p->regshift = bcma_port->reg_shift;
+		p->iotype = UPIO_MEM;
+		p->flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
+	}
+	return platform_device_register(&uart8250_device);
+}
+#endif
+
 static int __init uart8250_init(void)
 {
 	switch (bcm47xx_active_bus_type) {
@@ -54,6 +79,10 @@ static int __init uart8250_init(void)
 	case BCM47XX_BUS_TYPE_SSB:
 		return uart8250_init_ssb();
 #endif
+#ifdef CONFIG_BCM47XX_BCMA
+	case BCM47XX_BUS_TYPE_BCMA:
+		return uart8250_init_bcma();
+#endif
 	}
 	return -EINVAL;
 }
diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c
index 9fc92bd..612a5ec 100644
--- a/arch/mips/bcm47xx/setup.c
+++ b/arch/mips/bcm47xx/setup.c
@@ -29,6 +29,7 @@
 #include <linux/types.h>
 #include <linux/ssb/ssb.h>
 #include <linux/ssb/ssb_embedded.h>
+#include <linux/bcma/bcma_soc.h>
 #include <asm/bootinfo.h>
 #include <asm/reboot.h>
 #include <asm/time.h>
@@ -52,6 +53,11 @@ static void bcm47xx_machine_restart(char *command)
 		ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 1);
 		break;
 #endif
+#ifdef CONFIG_BCM47XX_BCMA
+	case BCM47XX_BUS_TYPE_BCMA:
+		bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.bus.drv_cc, 1);
+		break;
+#endif
 	}
 	while (1)
 		cpu_relax();
@@ -67,6 +73,11 @@ static void bcm47xx_machine_halt(void)
 		ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0);
 		break;
 #endif
+#ifdef CONFIG_BCM47XX_BCMA
+	case BCM47XX_BUS_TYPE_BCMA:
+		bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.bus.drv_cc, 0);
+		break;
+#endif
 	}
 	while (1)
 		cpu_relax();
@@ -295,16 +306,54 @@ static void __init bcm47xx_register_ssb(void)
 }
 #endif
 
+#ifdef CONFIG_BCM47XX_BCMA
+static void __init bcm47xx_register_bcma(void)
+{
+	int err;
+
+	err = bcma_host_soc_register(&bcm47xx_bus.bcma);
+	if (err)
+		panic("Failed to initialize BCMA bus (err %d)\n", err);
+}
+#endif
+
 void __init plat_mem_setup(void)
 {
 	struct cpuinfo_mips *c = &current_cpu_data;
 
+	if (c->cputype == CPU_74K) {
+		printk(KERN_INFO "bcm47xx: using bcma bus\n");
+#ifdef CONFIG_BCM47XX_BCMA
+		bcm47xx_active_bus_type = BCM47XX_BUS_TYPE_BCMA;
+		bcm47xx_register_bcma();
+#endif
+	} else {
+		printk(KERN_INFO "bcm47xx: using ssb bus\n");
 #ifdef CONFIG_BCM47XX_SSB
-	bcm47xx_active_bus_type = BCM47XX_BUS_TYPE_SSB;
-	bcm47xx_register_ssb();
+		bcm47xx_active_bus_type = BCM47XX_BUS_TYPE_SSB;
+		bcm47xx_register_ssb();
 #endif
+	}
 
 	_machine_restart = bcm47xx_machine_restart;
 	_machine_halt = bcm47xx_machine_halt;
 	pm_power_off = bcm47xx_machine_halt;
 }
+
+static int __init bcm47xx_register_bus_complete(void)
+{
+	switch (bcm47xx_active_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
+	case BCM47XX_BUS_TYPE_SSB:
+		/* Nothing to do */
+		break;
+#endif
+#ifdef CONFIG_BCM47XX_BCMA
+	case BCM47XX_BUS_TYPE_BCMA:
+		bcma_bus_register(&bcm47xx_bus.bcma.bus);
+		break;
+#endif
+	}
+	return 0;
+}
+device_initcall(bcm47xx_register_bus_complete);
diff --git a/arch/mips/bcm47xx/time.c b/arch/mips/bcm47xx/time.c
index 02a652a..c10471a 100644
--- a/arch/mips/bcm47xx/time.c
+++ b/arch/mips/bcm47xx/time.c
@@ -45,6 +45,11 @@ void __init plat_time_init(void)
 		hz = ssb_cpu_clock(&bcm47xx_bus.ssb.mipscore) / 2;
 		break;
 #endif
+#ifdef CONFIG_BCM47XX_BCMA
+	case BCM47XX_BUS_TYPE_BCMA:
+		hz = bcma_cpu_clock(&bcm47xx_bus.bcma.bus.drv_mips) / 2;
+		break;
+#endif
 	}
 
 	if (!hz)
diff --git a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
index 764afea..3959485 100644
--- a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
+++ b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
@@ -20,17 +20,25 @@
 #define __ASM_BCM47XX_H
 
 #include <linux/ssb/ssb.h>
+#include <linux/bcma/bcma.h>
+#include <linux/bcma/bcma_soc.h>
 
 enum bcm47xx_bus_type {
 #ifdef CONFIG_BCM47XX_SSB
 	BCM47XX_BUS_TYPE_SSB,
 #endif
+#ifdef CONFIG_BCM47XX_BCMA
+	BCM47XX_BUS_TYPE_BCMA,
+#endif
 };
 
 union bcm47xx_bus {
 #ifdef CONFIG_BCM47XX_SSB
 	struct ssb_bus ssb;
 #endif
+#ifdef CONFIG_BCM47XX_BCMA
+	struct bcma_soc bcma;
+#endif
 };
 
 extern union bcm47xx_bus bcm47xx_bus;
diff --git a/arch/mips/include/asm/mach-bcm47xx/gpio.h b/arch/mips/include/asm/mach-bcm47xx/gpio.h
index 0c3bd1f..0dcb71a 100644
--- a/arch/mips/include/asm/mach-bcm47xx/gpio.h
+++ b/arch/mips/include/asm/mach-bcm47xx/gpio.h
@@ -10,6 +10,7 @@
 #define __BCM47XX_GPIO_H
 
 #include <linux/ssb/ssb_embedded.h>
+#include <linux/bcma/bcma.h>
 #include <asm/mach-bcm47xx/bcm47xx.h>
 
 #define BCM47XX_EXTIF_GPIO_LINES	5
@@ -26,6 +27,11 @@ static inline int gpio_get_value(unsigned gpio)
 	case BCM47XX_BUS_TYPE_SSB:
 		return ssb_gpio_in(&bcm47xx_bus.ssb, 1 << gpio);
 #endif
+#ifdef CONFIG_BCM47XX_BCMA
+	case BCM47XX_BUS_TYPE_BCMA:
+		return bcma_chipco_gpio_in(&bcm47xx_bus.bcma.bus.drv_cc,
+					   1 << gpio);
+#endif
 	}
 	return -EINVAL;
 }
@@ -37,6 +43,13 @@ static inline void gpio_set_value(unsigned gpio, int value)
 	case BCM47XX_BUS_TYPE_SSB:
 		ssb_gpio_out(&bcm47xx_bus.ssb, 1 << gpio,
 			     value ? 1 << gpio : 0);
+		return;
+#endif
+#ifdef CONFIG_BCM47XX_BCMA
+	case BCM47XX_BUS_TYPE_BCMA:
+		bcma_chipco_gpio_out(&bcm47xx_bus.bcma.bus.drv_cc, 1 << gpio,
+				     value ? 1 << gpio : 0);
+		return;
 #endif
 	}
 }
@@ -49,6 +62,12 @@ static inline int gpio_direction_input(unsigned gpio)
 		ssb_gpio_outen(&bcm47xx_bus.ssb, 1 << gpio, 0);
 		return 0;
 #endif
+#ifdef CONFIG_BCM47XX_BCMA
+	case BCM47XX_BUS_TYPE_BCMA:
+		bcma_chipco_gpio_outen(&bcm47xx_bus.bcma.bus.drv_cc, 1 << gpio,
+				       0);
+		return 0;
+#endif
 	}
 	return -EINVAL;
 }
@@ -65,6 +84,16 @@ static inline int gpio_direction_output(unsigned gpio, int value)
 		ssb_gpio_outen(&bcm47xx_bus.ssb, 1 << gpio, 1 << gpio);
 		return 0;
 #endif
+#ifdef CONFIG_BCM47XX_BCMA
+	case BCM47XX_BUS_TYPE_BCMA:
+		/* first set the gpio out value */
+		bcma_chipco_gpio_out(&bcm47xx_bus.bcma.bus.drv_cc, 1 << gpio,
+				     value ? 1 << gpio : 0);
+		/* then set the gpio mode */
+		bcma_chipco_gpio_outen(&bcm47xx_bus.bcma.bus.drv_cc, 1 << gpio,
+				       1 << gpio);
+		return 0;
+#endif
 	}
 	return -EINVAL;
 }
@@ -78,6 +107,12 @@ static inline int gpio_intmask(unsigned gpio, int value)
 				 value ? 1 << gpio : 0);
 		return 0;
 #endif
+#ifdef CONFIG_BCM47XX_BCMA
+	case BCM47XX_BUS_TYPE_BCMA:
+		bcma_chipco_gpio_intmask(&bcm47xx_bus.bcma.bus.drv_cc,
+					 1 << gpio, value ? 1 << gpio : 0);
+		return 0;
+#endif
 	}
 	return -EINVAL;
 }
@@ -91,6 +126,12 @@ static inline int gpio_polarity(unsigned gpio, int value)
 				  value ? 1 << gpio : 0);
 		return 0;
 #endif
+#ifdef CONFIG_BCM47XX_BCMA
+	case BCM47XX_BUS_TYPE_BCMA:
+		bcma_chipco_gpio_polarity(&bcm47xx_bus.bcma.bus.drv_cc,
+					  1 << gpio, value ? 1 << gpio : 0);
+		return 0;
+#endif
 	}
 	return -EINVAL;
 }
diff --git a/drivers/watchdog/bcm47xx_wdt.c b/drivers/watchdog/bcm47xx_wdt.c
index beacd79..febce9b 100644
--- a/drivers/watchdog/bcm47xx_wdt.c
+++ b/drivers/watchdog/bcm47xx_wdt.c
@@ -60,6 +60,12 @@ static inline void bcm47xx_wdt_hw_start(void)
 		ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0xfffffff);
 		break;
 #endif
+#ifdef CONFIG_BCM47XX_BCMA
+	case BCM47XX_BUS_TYPE_BCMA:
+		bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.bus.drv_cc,
+					       0xfffffff);
+		break;
+#endif
 	}
 }
 
@@ -70,6 +76,11 @@ static inline int bcm47xx_wdt_hw_stop(void)
 	case BCM47XX_BUS_TYPE_SSB:
 		return ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0);
 #endif
+#ifdef CONFIG_BCM47XX_BCMA
+	case BCM47XX_BUS_TYPE_BCMA:
+		bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.bus.drv_cc, 0);
+		return 0;
+#endif
 	}
 	return -EINVAL;
 }
-- 
1.7.4.1


From hauke@hauke-m.de Sat Jul  9 13:07:03 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 09 Jul 2011 13:11:44 +0200 (CEST)
Received: from server19320154104.serverpool.info ([193.201.54.104]:42032 "EHLO
        hauke-m.de" rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org
        with ESMTP id S1492162Ab1GILHD (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Sat, 9 Jul 2011 13:07:03 +0200
Received: from localhost (localhost [127.0.0.1])
        by hauke-m.de (Postfix) with ESMTP id 247418C6B;
        Sat,  9 Jul 2011 13:07:03 +0200 (CEST)
X-Virus-Scanned: Debian amavisd-new at hauke-m.de 
Received: from hauke-m.de ([127.0.0.1])
        by localhost (hauke-m.de [127.0.0.1]) (amavisd-new, port 10024)
        with ESMTP id kQyv79x88EoB; Sat,  9 Jul 2011 13:06:59 +0200 (CEST)
Received: from localhost.localdomain (dyndsl-095-033-240-133.ewe-ip-backbone.de [95.33.240.133])
        by hauke-m.de (Postfix) with ESMTPSA id C39F38C6C;
        Sat,  9 Jul 2011 13:06:32 +0200 (CEST)
From:   Hauke Mehrtens <hauke@hauke-m.de>
To:     ralf@linux-mips.org, linux-wireless@vger.kernel.org,
        zajec5@gmail.com, linux-mips@linux-mips.org
Cc:     mb@bu3sch.de, george@znau.edu.ua, arend@broadcom.com,
        b43-dev@lists.infradead.org, bernhardloos@googlemail.com,
        arnd@arndb.de, julian.calaby@gmail.com, sshtylyov@mvista.com,
        Hauke Mehrtens <hauke@hauke-m.de>
Subject: [PATCH 11/11] bcm47xx: fix irq assignment for new SoCs.
Date:   Sat,  9 Jul 2011 13:06:03 +0200
Message-Id: <1310209563-6405-12-git-send-email-hauke@hauke-m.de>
X-Mailer: git-send-email 1.7.4.1
In-Reply-To: <1310209563-6405-1-git-send-email-hauke@hauke-m.de>
References: <1310209563-6405-1-git-send-email-hauke@hauke-m.de>
X-archive-position: 30604
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: hauke@hauke-m.de
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 6784
Content-Length: 939
Lines: 37

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 arch/mips/bcm47xx/irq.c |   12 ++++++++++++
 1 files changed, 12 insertions(+), 0 deletions(-)

diff --git a/arch/mips/bcm47xx/irq.c b/arch/mips/bcm47xx/irq.c
index 325757a..70bdcf0 100644
--- a/arch/mips/bcm47xx/irq.c
+++ b/arch/mips/bcm47xx/irq.c
@@ -26,6 +26,7 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <asm/irq_cpu.h>
+#include <bcm47xx.h>
 
 void plat_irq_dispatch(void)
 {
@@ -51,5 +52,16 @@ void plat_irq_dispatch(void)
 
 void __init arch_init_irq(void)
 {
+#ifdef CONFIG_BCM47XX_BCMA
+	if (bcm47xx_active_bus_type == BCM47XX_BUS_TYPE_BCMA) {
+		bcma_write32(bcm47xx_bus.bcma.bus.drv_mips.core,
+			     BCMA_MIPS_MIPS74K_INTMASK(5), 1 << 31);
+		/*
+		 * the kernel reads the timer irq from some register and thinks
+		 * it's #5, but we offset it by 2 and route to #7
+		 */
+		cp0_compare_irq = 7;
+	}
+#endif
 	mips_cpu_irq_init();
 }
-- 
1.7.4.1


From jj@chaosbits.net Sat Jul  9 23:22:11 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 09 Jul 2011 23:22:18 +0200 (CEST)
Received: from swampdragon.chaosbits.net ([90.184.90.115]:13287 "EHLO
        swampdragon.chaosbits.net" rhost-flags-OK-OK-OK-OK)
        by eddie.linux-mips.org with ESMTP id S1492169Ab1GIVWL (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Sat, 9 Jul 2011 23:22:11 +0200
Received: by swampdragon.chaosbits.net (Postfix, from userid 1000)
        id A19A39403D; Sat,  9 Jul 2011 23:12:35 +0200 (CEST)
Received: from localhost (localhost [127.0.0.1])
        by swampdragon.chaosbits.net (Postfix) with ESMTP id 9F88D9403B;
        Sat,  9 Jul 2011 23:12:35 +0200 (CEST)
Date:   Sat, 9 Jul 2011 23:12:35 +0200 (CEST)
From:   Jesper Juhl <jj@chaosbits.net>
To:     linux-kernel@vger.kernel.org
cc:     trivial@kernel.org, Ralf Baechle <ralf@linux-mips.org>,
        Lars-Peter Clausen <lars@metafoo.de>, linux-mips@linux-mips.org
Subject: [PATCH 2/7] MIPS: static should be at beginning of declaration
In-Reply-To: <alpine.LNX.2.00.1107092304160.25516@swampdragon.chaosbits.net>
Message-ID: <alpine.LNX.2.00.1107092311190.25516@swampdragon.chaosbits.net>
References: <alpine.LNX.2.00.1107092304160.25516@swampdragon.chaosbits.net>
User-Agent: Alpine 2.00 (LNX 1167 2008-08-23)
MIME-Version: 1.0
Content-Type: MULTIPART/MIXED; BOUNDARY="8323328-244283129-1310245955=:25516"
X-archive-position: 30605
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: jj@chaosbits.net
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 6945
Content-Length: 1818
Lines: 61

  This message is in MIME format.  The first part should be readable text,
  while the remaining parts are likely unreadable without MIME-aware tools.

--8323328-244283129-1310245955=:25516
Content-Type: TEXT/PLAIN; charset=ISO-8859-7
Content-Transfer-Encoding: 8BIT

Make sure that the 'static' keywork is at the beginning of declaration
for arch/mips/include/asm/mach-jz4740/gpio.h

This gets rid of warnings like
  warning: ¡static¢ is not at beginning of declaration
when building with -Wold-style-declaration (and/or -Wextra which also
enables it).
Also a few tiny whitespace changes.

Signed-off-by: Jesper Juhl <jj@chaosbits.net>
---
 arch/mips/include/asm/mach-jz4740/gpio.h |    5 ++---
 1 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/arch/mips/include/asm/mach-jz4740/gpio.h b/arch/mips/include/asm/mach-jz4740/gpio.h
index 7b74703..1a6482e 100644
--- a/arch/mips/include/asm/mach-jz4740/gpio.h
+++ b/arch/mips/include/asm/mach-jz4740/gpio.h
@@ -25,14 +25,13 @@ enum jz_gpio_function {
     JZ_GPIO_FUNC3,
 };
 
-
 /*
  Usually a driver for a SoC component has to request several gpio pins and
  configure them as funcion pins.
  jz_gpio_bulk_request can be used to ease this process.
  Usually one would do something like:
 
- const static struct jz_gpio_bulk_request i2c_pins[] = {
+ static const struct jz_gpio_bulk_request i2c_pins[] = {
 	JZ_GPIO_BULK_PIN(I2C_SDA),
 	JZ_GPIO_BULK_PIN(I2C_SCK),
  };
@@ -47,8 +46,8 @@ enum jz_gpio_function {
 
     jz_gpio_bulk_free(i2c_pins, ARRAY_SIZE(i2c_pins));
 
-
 */
+
 struct jz_gpio_bulk_request {
 	int gpio;
 	const char *name;
-- 
1.7.6


-- 
Jesper Juhl <jj@chaosbits.net>       http://www.chaosbits.net/
Don't top-post http://www.catb.org/jargon/html/T/top-post.html
Plain text mails only, please.

--8323328-244283129-1310245955=:25516--

From mirq-linux@rere.qmqm.pl Tue Jul 12 11:55:45 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Tue, 12 Jul 2011 11:55:50 +0200 (CEST)
Received: from rere.qmqm.pl ([89.167.52.164]:36802 "EHLO rere.qmqm.pl"
        rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org with ESMTP
        id S1491129Ab1GLJzp (ORCPT <rfc822;linux-mips@linux-mips.org>);
        Tue, 12 Jul 2011 11:55:45 +0200
Received: by rere.qmqm.pl (Postfix, from userid 1000)
        id 59C1813A6A; Tue, 12 Jul 2011 11:55:41 +0200 (CEST)
Date:   Tue, 12 Jul 2011 11:55:41 +0200
From:   =?iso-8859-2?Q?Micha=B3_Miros=B3aw?= <mirq-linux@rere.qmqm.pl>
To:     Felix Fietkau <nbd@openwrt.org>
Cc:     netdev@vger.kernel.org, linux-wireless@vger.kernel.org,
        Jouni Malinen <jmalinen@atheros.com>,
        Senthil Balasubramanian <senthilkumar@atheros.com>,
        ath9k-devel@lists.ath9k.org,
        Vasanthakumar Thiagarajan <vasanth@atheros.com>,
        Ralf Baechle <ralf@linux-mips.org>, linux-mips@linux-mips.org
Subject: Re: [ath9k-devel] [PATCH v2 07/46] net/wireless: ath9k: fix DMA
 API usage
Message-ID: <20110712095541.GA6236@rere.qmqm.pl>
References: <cover.1310339688.git.mirq-linux@rere.qmqm.pl>
 <280ad9176e6532f231e054b38b952b20580874c5.1310339688.git.mirq-linux@rere.qmqm.pl>
 <4E1BCF36.2010506@openwrt.org>
MIME-Version: 1.0
Content-Type: text/plain; charset=iso-8859-2
Content-Disposition: inline
Content-Transfer-Encoding: 8bit
In-Reply-To: <4E1BCF36.2010506@openwrt.org>
User-Agent: Mutt/1.5.20 (2009-06-14)
X-archive-position: 30606
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: mirq-linux@rere.qmqm.pl
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 8480
Content-Length: 2149
Lines: 51

On Tue, Jul 12, 2011 at 12:36:06PM +0800, Felix Fietkau wrote:
> On 2011-07-11 8:52 AM, Micha³ Miros³aw wrote:
> >Also constify buf_addr for ath9k_hw_process_rxdesc_edma() to verify
> >assumptions --- dma_sync_single_for_device() call can be removed.
> >
> >Signed-off-by: Micha³ Miros³aw<mirq-linux@rere.qmqm.pl>
> >---
> >  drivers/net/wireless/ath/ath9k/ar9003_mac.c |    4 ++--
> >  drivers/net/wireless/ath/ath9k/ar9003_mac.h |    2 +-
> >  drivers/net/wireless/ath/ath9k/recv.c       |   10 +++-------
> >  3 files changed, 6 insertions(+), 10 deletions(-)
> >
> >diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
> >index 70dc8ec..c5f46d5 100644
> >--- a/drivers/net/wireless/ath/ath9k/recv.c
> >+++ b/drivers/net/wireless/ath/ath9k/recv.c
> >@@ -684,15 +684,11 @@ static bool ath_edma_get_buffers(struct ath_softc *sc,
> >  	BUG_ON(!bf);
> >
> >  	dma_sync_single_for_cpu(sc->dev, bf->bf_buf_addr,
> >-				common->rx_bufsize, DMA_FROM_DEVICE);
> >+				common->rx_bufsize, DMA_BIDIRECTIONAL);
> >
> >  	ret = ath9k_hw_process_rxdesc_edma(ah, NULL, skb->data);
> >-	if (ret == -EINPROGRESS) {
> >-		/*let device gain the buffer again*/
> >-		dma_sync_single_for_device(sc->dev, bf->bf_buf_addr,
> >-				common->rx_bufsize, DMA_FROM_DEVICE);
> >+	if (ret == -EINPROGRESS)
> >  		return false;
> >-	}
> >
> >  	__skb_unlink(skb,&rx_edma->rx_fifo);
> >  	if (ret == -EINVAL) {
> I have strong doubts about this change. On most MIPS devices,
> dma_sync_single_for_cpu is a no-op, whereas
> dma_sync_single_for_device flushes the cache range. With this
> change, the CPU could cache the DMA status part behind skb->data and
> that cache entry would not be flushed inbetween calls to this
> functions on the same buffer, likely leading to rx stalls.

You're suggesting a platform implementation bug then. If the platform is not
cache-coherent, it should invalidate relevant CPU cache lines for sync_to_cpu
and unmap cases. Do other devices show such symptoms on MIPS systems?

I'm not familiar with the platform internals, so we should ask MIPS people.

[added Cc: linux-mips]

Best Regards,
Micha³ Miros³aw

From nbd@nbd.name Tue Jul 12 14:56:20 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Tue, 12 Jul 2011 14:56:31 +0200 (CEST)
Received: from nbd.name ([46.4.11.11]:44013 "EHLO nbd.name"
        rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org with ESMTP
        id S1491143Ab1GLM4U convert rfc822-to-8bit (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Tue, 12 Jul 2011 14:56:20 +0200
References: <cover.1310339688.git.mirq-linux@rere.qmqm.pl> <280ad9176e6532f231e054b38b952b20580874c5.1310339688.git.mirq-linux@rere.qmqm.pl> <4E1BCF36.2010506@openwrt.org> <20110712095541.GA6236@rere.qmqm.pl>
In-Reply-To: <20110712095541.GA6236@rere.qmqm.pl>
Mime-Version: 1.0 (iPhone Mail 8H7)
Content-Transfer-Encoding: 8BIT
Content-Type: text/plain;
        charset=utf-8
Message-Id: <B4765EFC-B5C9-4E2D-BE00-ED5519D13A4E@nbd.name>
Cc:     Felix Fietkau <nbd@openwrt.org>,
        "netdev@vger.kernel.org" <netdev@vger.kernel.org>,
        "linux-wireless@vger.kernel.org" <linux-wireless@vger.kernel.org>,
        Jouni Malinen <jmalinen@atheros.com>,
        Senthil Balasubramanian <senthilkumar@atheros.com>,
        "ath9k-devel@lists.ath9k.org" <ath9k-devel@lists.ath9k.org>,
        Vasanthakumar Thiagarajan <vasanth@atheros.com>,
        Ralf Baechle <ralf@linux-mips.org>,
        "linux-mips@linux-mips.org" <linux-mips@linux-mips.org>
X-Mailer: iPhone Mail (8H7)
From:   Felix Fietkau <nbd@nbd.name>
Subject: Re: [ath9k-devel] [PATCH v2 07/46] net/wireless: ath9k: fix DMA API usage
Date:   Tue, 12 Jul 2011 20:54:32 +0800
To:     =?utf-8?Q?Micha=C5=82_Miros=C5=82aw?= <mirq-linux@rere.qmqm.pl>
X-archive-position: 30607
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: nbd@nbd.name
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 8582
Content-Length: 2913
Lines: 53

On 12.07.2011, at 17:55, MichaÅ‚ MirosÅ‚aw <mirq-linux@rere.qmqm.pl> wrote:

> On Tue, Jul 12, 2011 at 12:36:06PM +0800, Felix Fietkau wrote:
>> On 2011-07-11 8:52 AM, MichaÅ‚ MirosÅ‚aw wrote:
>>> Also constify buf_addr for ath9k_hw_process_rxdesc_edma() to verify
>>> assumptions --- dma_sync_single_for_device() call can be removed.
>>> 
>>> Signed-off-by: MichaÅ‚ MirosÅ‚aw<mirq-linux@rere.qmqm.pl>
>>> ---
>>> drivers/net/wireless/ath/ath9k/ar9003_mac.c |    4 ++--
>>> drivers/net/wireless/ath/ath9k/ar9003_mac.h |    2 +-
>>> drivers/net/wireless/ath/ath9k/recv.c       |   10 +++-------
>>> 3 files changed, 6 insertions(+), 10 deletions(-)
>>> 
>>> diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
>>> index 70dc8ec..c5f46d5 100644
>>> --- a/drivers/net/wireless/ath/ath9k/recv.c
>>> +++ b/drivers/net/wireless/ath/ath9k/recv.c
>>> @@ -684,15 +684,11 @@ static bool ath_edma_get_buffers(struct ath_softc *sc,
>>>    BUG_ON(!bf);
>>> 
>>>    dma_sync_single_for_cpu(sc->dev, bf->bf_buf_addr,
>>> -                common->rx_bufsize, DMA_FROM_DEVICE);
>>> +                common->rx_bufsize, DMA_BIDIRECTIONAL);
>>> 
>>>    ret = ath9k_hw_process_rxdesc_edma(ah, NULL, skb->data);
>>> -    if (ret == -EINPROGRESS) {
>>> -        /*let device gain the buffer again*/
>>> -        dma_sync_single_for_device(sc->dev, bf->bf_buf_addr,
>>> -                common->rx_bufsize, DMA_FROM_DEVICE);
>>> +    if (ret == -EINPROGRESS)
>>>        return false;
>>> -    }
>>> 
>>>    __skb_unlink(skb,&rx_edma->rx_fifo);
>>>    if (ret == -EINVAL) {
>> I have strong doubts about this change. On most MIPS devices,
>> dma_sync_single_for_cpu is a no-op, whereas
>> dma_sync_single_for_device flushes the cache range. With this
>> change, the CPU could cache the DMA status part behind skb->data and
>> that cache entry would not be flushed inbetween calls to this
>> functions on the same buffer, likely leading to rx stalls.
> 
> You're suggesting a platform implementation bug then. If the platform is not
> cache-coherent, it should invalidate relevant CPU cache lines for sync_to_cpu
> and unmap cases. Do other devices show such symptoms on MIPS systems?
> 
> I'm not familiar with the platform internals, so we should ask MIPS people.
I only mentioned MIPS to describe the potential side effect of this change. From my current understanding of the DMA API, it would be wrong on other platforms as well. I believe the _for_device function needs to be used to transfer ownership of the buffer back to the device, before calling _for_cpu again later for another read.
This is definitely required in this case, because when the return code is -EINPROGRESS, the driver waits for the hardware to complete this buffer, and the next call has to fetch the memory again after the device has updated it.
This is handled properly by the current code without your change.

- Felix

From mirq-linux@rere.qmqm.pl Tue Jul 12 15:03:17 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Tue, 12 Jul 2011 15:03:24 +0200 (CEST)
Received: from rere.qmqm.pl ([89.167.52.164]:47512 "EHLO rere.qmqm.pl"
        rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org with ESMTP
        id S1491141Ab1GLNDR (ORCPT <rfc822;linux-mips@linux-mips.org>);
        Tue, 12 Jul 2011 15:03:17 +0200
Received: by rere.qmqm.pl (Postfix, from userid 1000)
        id 8204C13A6A; Tue, 12 Jul 2011 15:03:16 +0200 (CEST)
Date:   Tue, 12 Jul 2011 15:03:16 +0200
From:   =?iso-8859-2?Q?Micha=B3_Miros=B3aw?= <mirq-linux@rere.qmqm.pl>
To:     Felix Fietkau <nbd@nbd.name>
Cc:     Felix Fietkau <nbd@openwrt.org>,
        "netdev@vger.kernel.org" <netdev@vger.kernel.org>,
        "linux-wireless@vger.kernel.org" <linux-wireless@vger.kernel.org>,
        Jouni Malinen <jmalinen@atheros.com>,
        Senthil Balasubramanian <senthilkumar@atheros.com>,
        "ath9k-devel@lists.ath9k.org" <ath9k-devel@lists.ath9k.org>,
        Vasanthakumar Thiagarajan <vasanth@atheros.com>,
        Ralf Baechle <ralf@linux-mips.org>,
        "linux-mips@linux-mips.org" <linux-mips@linux-mips.org>
Subject: Re: [ath9k-devel] [PATCH v2 07/46] net/wireless: ath9k: fix DMA
 API usage
Message-ID: <20110712130316.GA8621@rere.qmqm.pl>
References: <cover.1310339688.git.mirq-linux@rere.qmqm.pl>
 <280ad9176e6532f231e054b38b952b20580874c5.1310339688.git.mirq-linux@rere.qmqm.pl>
 <4E1BCF36.2010506@openwrt.org>
 <20110712095541.GA6236@rere.qmqm.pl>
 <B4765EFC-B5C9-4E2D-BE00-ED5519D13A4E@nbd.name>
MIME-Version: 1.0
Content-Type: text/plain; charset=iso-8859-2
Content-Disposition: inline
Content-Transfer-Encoding: 8bit
In-Reply-To: <B4765EFC-B5C9-4E2D-BE00-ED5519D13A4E@nbd.name>
User-Agent: Mutt/1.5.20 (2009-06-14)
X-archive-position: 30608
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: mirq-linux@rere.qmqm.pl
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 8588
Content-Length: 3394
Lines: 63

On Tue, Jul 12, 2011 at 08:54:32PM +0800, Felix Fietkau wrote:
> On 12.07.2011, at 17:55, Micha³ Miros³aw <mirq-linux@rere.qmqm.pl> wrote:
> 
> > On Tue, Jul 12, 2011 at 12:36:06PM +0800, Felix Fietkau wrote:
> >> On 2011-07-11 8:52 AM, Micha³ Miros³aw wrote:
> >>> Also constify buf_addr for ath9k_hw_process_rxdesc_edma() to verify
> >>> assumptions --- dma_sync_single_for_device() call can be removed.
> >>> 
> >>> Signed-off-by: Micha³ Miros³aw<mirq-linux@rere.qmqm.pl>
> >>> ---
> >>> drivers/net/wireless/ath/ath9k/ar9003_mac.c |    4 ++--
> >>> drivers/net/wireless/ath/ath9k/ar9003_mac.h |    2 +-
> >>> drivers/net/wireless/ath/ath9k/recv.c       |   10 +++-------
> >>> 3 files changed, 6 insertions(+), 10 deletions(-)
> >>> 
> >>> diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
> >>> index 70dc8ec..c5f46d5 100644
> >>> --- a/drivers/net/wireless/ath/ath9k/recv.c
> >>> +++ b/drivers/net/wireless/ath/ath9k/recv.c
> >>> @@ -684,15 +684,11 @@ static bool ath_edma_get_buffers(struct ath_softc *sc,
> >>>    BUG_ON(!bf);
> >>> 
> >>>    dma_sync_single_for_cpu(sc->dev, bf->bf_buf_addr,
> >>> -                common->rx_bufsize, DMA_FROM_DEVICE);
> >>> +                common->rx_bufsize, DMA_BIDIRECTIONAL);
> >>> 
> >>>    ret = ath9k_hw_process_rxdesc_edma(ah, NULL, skb->data);
> >>> -    if (ret == -EINPROGRESS) {
> >>> -        /*let device gain the buffer again*/
> >>> -        dma_sync_single_for_device(sc->dev, bf->bf_buf_addr,
> >>> -                common->rx_bufsize, DMA_FROM_DEVICE);
> >>> +    if (ret == -EINPROGRESS)
> >>>        return false;
> >>> -    }
> >>> 
> >>>    __skb_unlink(skb,&rx_edma->rx_fifo);
> >>>    if (ret == -EINVAL) {
> >> I have strong doubts about this change. On most MIPS devices,
> >> dma_sync_single_for_cpu is a no-op, whereas
> >> dma_sync_single_for_device flushes the cache range. With this
> >> change, the CPU could cache the DMA status part behind skb->data and
> >> that cache entry would not be flushed inbetween calls to this
> >> functions on the same buffer, likely leading to rx stalls.
> > 
> > You're suggesting a platform implementation bug then. If the platform is not
> > cache-coherent, it should invalidate relevant CPU cache lines for sync_to_cpu
> > and unmap cases. Do other devices show such symptoms on MIPS systems?
> > 
> > I'm not familiar with the platform internals, so we should ask MIPS people.
> I only mentioned MIPS to describe the potential side effect of this change. From my current understanding of the DMA API, it would be wrong on other platforms as well. I believe the _for_device function needs to be used to transfer ownership of the buffer back to the device, before calling _for_cpu again later for another read.

What you're saying reminds the wording in DMA-API-HOWTO.txt that I find
wrong (or at least misleading) compared to what DMA-API.txt describes.
DMA sync calls do not transfer the ownership of the buffer - they are
cache synchronization points, ownership passing is handled entirely by
the driver.

> This is definitely required in this case, because when the return code is -EINPROGRESS, the driver waits for the hardware to complete this buffer, and the next call has to fetch the memory again after the device has updated it.

Correctness of this access should be provided by sync_to_cpu() call.

Best Regards,
Micha³ Miros³aw

From nbd@nbd.name Tue Jul 12 16:22:58 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Tue, 12 Jul 2011 16:23:06 +0200 (CEST)
Received: from nbd.name ([46.4.11.11]:32888 "EHLO nbd.name"
        rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org with ESMTP
        id S1491141Ab1GLOW6 convert rfc822-to-8bit (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Tue, 12 Jul 2011 16:22:58 +0200
References: <cover.1310339688.git.mirq-linux@rere.qmqm.pl> <280ad9176e6532f231e054b38b952b20580874c5.1310339688.git.mirq-linux@rere.qmqm.pl> <4E1BCF36.2010506@openwrt.org> <20110712095541.GA6236@rere.qmqm.pl> <B4765EFC-B5C9-4E2D-BE00-ED5519D13A4E@nbd.name> <20110712130316.GA8621@rere.qmqm.pl>
In-Reply-To: <20110712130316.GA8621@rere.qmqm.pl>
Mime-Version: 1.0 (iPhone Mail 8H7)
Content-Transfer-Encoding: 8BIT
Content-Type: text/plain;
        charset=utf-8
Message-Id: <EC2F82D7-9206-4139-9539-F5DDE38A5629@nbd.name>
Cc:     Felix Fietkau <nbd@openwrt.org>,
        "netdev@vger.kernel.org" <netdev@vger.kernel.org>,
        "linux-wireless@vger.kernel.org" <linux-wireless@vger.kernel.org>,
        Jouni Malinen <jmalinen@atheros.com>,
        Senthil Balasubramanian <senthilkumar@atheros.com>,
        "ath9k-devel@lists.ath9k.org" <ath9k-devel@lists.ath9k.org>,
        Vasanthakumar Thiagarajan <vasanth@atheros.com>,
        Ralf Baechle <ralf@linux-mips.org>,
        "linux-mips@linux-mips.org" <linux-mips@linux-mips.org>
X-Mailer: iPhone Mail (8H7)
From:   Felix Fietkau <nbd@nbd.name>
Subject: Re: [ath9k-devel] [PATCH v2 07/46] net/wireless: ath9k: fix DMA API usage
Date:   Tue, 12 Jul 2011 22:21:05 +0800
To:     =?utf-8?Q?Micha=C5=82_Miros=C5=82aw?= <mirq-linux@rere.qmqm.pl>
X-archive-position: 30609
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: nbd@nbd.name
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 8617
Content-Length: 3958
Lines: 67

On 12.07.2011, at 21:03, MichaÅ‚ MirosÅ‚aw <mirq-linux@rere.qmqm.pl> wrote:

> On Tue, Jul 12, 2011 at 08:54:32PM +0800, Felix Fietkau wrote:
>> On 12.07.2011, at 17:55, MichaÅ‚ MirosÅ‚aw <mirq-linux@rere.qmqm.pl> wrote:
>> 
>>> On Tue, Jul 12, 2011 at 12:36:06PM +0800, Felix Fietkau wrote:
>>>> On 2011-07-11 8:52 AM, MichaÅ‚ MirosÅ‚aw wrote:
>>>>> Also constify buf_addr for ath9k_hw_process_rxdesc_edma() to verify
>>>>> assumptions --- dma_sync_single_for_device() call can be removed.
>>>>> 
>>>>> Signed-off-by: MichaÅ‚ MirosÅ‚aw<mirq-linux@rere.qmqm.pl>
>>>>> ---
>>>>> drivers/net/wireless/ath/ath9k/ar9003_mac.c |    4 ++--
>>>>> drivers/net/wireless/ath/ath9k/ar9003_mac.h |    2 +-
>>>>> drivers/net/wireless/ath/ath9k/recv.c       |   10 +++-------
>>>>> 3 files changed, 6 insertions(+), 10 deletions(-)
>>>>> 
>>>>> diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
>>>>> index 70dc8ec..c5f46d5 100644
>>>>> --- a/drivers/net/wireless/ath/ath9k/recv.c
>>>>> +++ b/drivers/net/wireless/ath/ath9k/recv.c
>>>>> @@ -684,15 +684,11 @@ static bool ath_edma_get_buffers(struct ath_softc *sc,
>>>>>   BUG_ON(!bf);
>>>>> 
>>>>>   dma_sync_single_for_cpu(sc->dev, bf->bf_buf_addr,
>>>>> -                common->rx_bufsize, DMA_FROM_DEVICE);
>>>>> +                common->rx_bufsize, DMA_BIDIRECTIONAL);
>>>>> 
>>>>>   ret = ath9k_hw_process_rxdesc_edma(ah, NULL, skb->data);
>>>>> -    if (ret == -EINPROGRESS) {
>>>>> -        /*let device gain the buffer again*/
>>>>> -        dma_sync_single_for_device(sc->dev, bf->bf_buf_addr,
>>>>> -                common->rx_bufsize, DMA_FROM_DEVICE);
>>>>> +    if (ret == -EINPROGRESS)
>>>>>       return false;
>>>>> -    }
>>>>> 
>>>>>   __skb_unlink(skb,&rx_edma->rx_fifo);
>>>>>   if (ret == -EINVAL) {
>>>> I have strong doubts about this change. On most MIPS devices,
>>>> dma_sync_single_for_cpu is a no-op, whereas
>>>> dma_sync_single_for_device flushes the cache range. With this
>>>> change, the CPU could cache the DMA status part behind skb->data and
>>>> that cache entry would not be flushed inbetween calls to this
>>>> functions on the same buffer, likely leading to rx stalls.
>>> 
>>> You're suggesting a platform implementation bug then. If the platform is not
>>> cache-coherent, it should invalidate relevant CPU cache lines for sync_to_cpu
>>> and unmap cases. Do other devices show such symptoms on MIPS systems?
>>> 
>>> I'm not familiar with the platform internals, so we should ask MIPS people.
>> I only mentioned MIPS to describe the potential side effect of this change. From my current understanding of the DMA API, it would be wrong on other platforms as well. I believe the _for_device function needs to be used to transfer ownership of the buffer back to the device, before calling _for_cpu again later for another read.
> 
> What you're saying reminds the wording in DMA-API-HOWTO.txt that I find
> wrong (or at least misleading) compared to what DMA-API.txt describes.
> DMA sync calls do not transfer the ownership of the buffer - they are
> cache synchronization points, ownership passing is handled entirely by
> the driver.
What I meant was that the DMA sync calls reflect the ownership transfer of the memory regions. In this case ownership is transferred between device and CPU multiple times and the code reflects that.

> 
>> This is definitely required in this case, because when the return code is -EINPROGRESS, the driver waits for the hardware to complete this buffer, and the next call has to fetch the memory again after the device has updated it.
> 
> Correctness of this access should be provided by sync_to_cpu() call.
At least in MIPS I'm sure it isn't. If I remember correctly, it also isn't on ARM, so I'm pretty sure that either your understanding of the API is incorrect, or arch code does not implement it properly. In either case, this change (and probably also the p54 one) should not be merged.

- Felix

From mirq-linux@rere.qmqm.pl Tue Jul 12 17:58:49 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Tue, 12 Jul 2011 17:58:58 +0200 (CEST)
Received: from rere.qmqm.pl ([89.167.52.164]:41633 "EHLO rere.qmqm.pl"
        rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org with ESMTP
        id S1491156Ab1GLP6t (ORCPT <rfc822;linux-mips@linux-mips.org>);
        Tue, 12 Jul 2011 17:58:49 +0200
Received: by rere.qmqm.pl (Postfix, from userid 1000)
        id 292FD13A6A; Tue, 12 Jul 2011 17:58:49 +0200 (CEST)
Date:   Tue, 12 Jul 2011 17:58:49 +0200
From:   =?iso-8859-2?Q?Micha=B3_Miros=B3aw?= <mirq-linux@rere.qmqm.pl>
To:     Felix Fietkau <nbd@nbd.name>
Cc:     Felix Fietkau <nbd@openwrt.org>,
        "netdev@vger.kernel.org" <netdev@vger.kernel.org>,
        "linux-wireless@vger.kernel.org" <linux-wireless@vger.kernel.org>,
        Jouni Malinen <jmalinen@atheros.com>,
        Senthil Balasubramanian <senthilkumar@atheros.com>,
        "ath9k-devel@lists.ath9k.org" <ath9k-devel@lists.ath9k.org>,
        Vasanthakumar Thiagarajan <vasanth@atheros.com>,
        Ralf Baechle <ralf@linux-mips.org>,
        "linux-mips@linux-mips.org" <linux-mips@linux-mips.org>
Subject: Re: [ath9k-devel] [PATCH v2 07/46] net/wireless: ath9k: fix DMA
 API usage
Message-ID: <20110712155849.GB10651@rere.qmqm.pl>
References: <cover.1310339688.git.mirq-linux@rere.qmqm.pl>
 <280ad9176e6532f231e054b38b952b20580874c5.1310339688.git.mirq-linux@rere.qmqm.pl>
 <4E1BCF36.2010506@openwrt.org>
 <20110712095541.GA6236@rere.qmqm.pl>
 <B4765EFC-B5C9-4E2D-BE00-ED5519D13A4E@nbd.name>
 <20110712130316.GA8621@rere.qmqm.pl>
 <EC2F82D7-9206-4139-9539-F5DDE38A5629@nbd.name>
MIME-Version: 1.0
Content-Type: text/plain; charset=iso-8859-2
Content-Disposition: inline
Content-Transfer-Encoding: 8bit
In-Reply-To: <EC2F82D7-9206-4139-9539-F5DDE38A5629@nbd.name>
User-Agent: Mutt/1.5.20 (2009-06-14)
X-archive-position: 30610
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: mirq-linux@rere.qmqm.pl
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 8683
Content-Length: 4804
Lines: 77

On Tue, Jul 12, 2011 at 10:21:05PM +0800, Felix Fietkau wrote:
> On 12.07.2011, at 21:03, Micha³ Miros³aw <mirq-linux@rere.qmqm.pl> wrote:
> 
> > On Tue, Jul 12, 2011 at 08:54:32PM +0800, Felix Fietkau wrote:
> >> On 12.07.2011, at 17:55, Micha³ Miros³aw <mirq-linux@rere.qmqm.pl> wrote:
> >> 
> >>> On Tue, Jul 12, 2011 at 12:36:06PM +0800, Felix Fietkau wrote:
> >>>> On 2011-07-11 8:52 AM, Micha³ Miros³aw wrote:
> >>>>> Also constify buf_addr for ath9k_hw_process_rxdesc_edma() to verify
> >>>>> assumptions --- dma_sync_single_for_device() call can be removed.
> >>>>> 
> >>>>> Signed-off-by: Micha³ Miros³aw<mirq-linux@rere.qmqm.pl>
> >>>>> ---
> >>>>> drivers/net/wireless/ath/ath9k/ar9003_mac.c |    4 ++--
> >>>>> drivers/net/wireless/ath/ath9k/ar9003_mac.h |    2 +-
> >>>>> drivers/net/wireless/ath/ath9k/recv.c       |   10 +++-------
> >>>>> 3 files changed, 6 insertions(+), 10 deletions(-)
> >>>>> 
> >>>>> diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
> >>>>> index 70dc8ec..c5f46d5 100644
> >>>>> --- a/drivers/net/wireless/ath/ath9k/recv.c
> >>>>> +++ b/drivers/net/wireless/ath/ath9k/recv.c
> >>>>> @@ -684,15 +684,11 @@ static bool ath_edma_get_buffers(struct ath_softc *sc,
> >>>>>   BUG_ON(!bf);
> >>>>> 
> >>>>>   dma_sync_single_for_cpu(sc->dev, bf->bf_buf_addr,
> >>>>> -                common->rx_bufsize, DMA_FROM_DEVICE);
> >>>>> +                common->rx_bufsize, DMA_BIDIRECTIONAL);
> >>>>> 
> >>>>>   ret = ath9k_hw_process_rxdesc_edma(ah, NULL, skb->data);
> >>>>> -    if (ret == -EINPROGRESS) {
> >>>>> -        /*let device gain the buffer again*/
> >>>>> -        dma_sync_single_for_device(sc->dev, bf->bf_buf_addr,
> >>>>> -                common->rx_bufsize, DMA_FROM_DEVICE);
> >>>>> +    if (ret == -EINPROGRESS)
> >>>>>       return false;
> >>>>> -    }
> >>>>> 
> >>>>>   __skb_unlink(skb,&rx_edma->rx_fifo);
> >>>>>   if (ret == -EINVAL) {
> >>>> I have strong doubts about this change. On most MIPS devices,
> >>>> dma_sync_single_for_cpu is a no-op, whereas
> >>>> dma_sync_single_for_device flushes the cache range. With this
> >>>> change, the CPU could cache the DMA status part behind skb->data and
> >>>> that cache entry would not be flushed inbetween calls to this
> >>>> functions on the same buffer, likely leading to rx stalls.
> >>> You're suggesting a platform implementation bug then. If the platform is not
> >>> cache-coherent, it should invalidate relevant CPU cache lines for sync_to_cpu
> >>> and unmap cases. Do other devices show such symptoms on MIPS systems?
> >>> 
> >>> I'm not familiar with the platform internals, so we should ask MIPS people.
> >> I only mentioned MIPS to describe the potential side effect of this change. From my current understanding of the DMA API, it would be wrong on other platforms as well. I believe the _for_device function needs to be used to transfer ownership of the buffer back to the device, before calling _for_cpu again later for another read.
> > What you're saying reminds the wording in DMA-API-HOWTO.txt that I find
> > wrong (or at least misleading) compared to what DMA-API.txt describes.
> > DMA sync calls do not transfer the ownership of the buffer - they are
> > cache synchronization points, ownership passing is handled entirely by
> > the driver.
> What I meant was that the DMA sync calls reflect the ownership transfer of the memory regions. In this case ownership is transferred between device and CPU multiple times and the code reflects that.
> >> This is definitely required in this case, because when the return code is -EINPROGRESS, the driver waits for the hardware to complete this buffer, and the next call has to fetch the memory again after the device has updated it.
> > Correctness of this access should be provided by sync_to_cpu() call.
> At least in MIPS I'm sure it isn't. If I remember correctly, it also isn't on ARM, so I'm pretty sure that either your understanding of the API is incorrect, or arch code does not implement it properly. In either case, this change (and probably also the p54 one) should not be merged.

I briefly looked through DMA API implementation in MIPS, and except
for R10k and R12k both sync_for_cpu and sync_for_device are no-ops
(see: arch/mips/mm/dma-default.c).  For R10k and R12k the syncs are
in both points, and exactly like I described before - CPU cachelines
are invalidated for DMA_FROM_DEVICE mappings, written back for
DMA_TO_DEVICE, both for DMA_BIDIRECTIONAL (including redundant
mapping+sync direction).

So doing that sync_to_device you are just invalidating the same cachelines
twice for no gain (or do nothing twice in some cases) - they are not read
by CPU between sync_to_device -> sync_to_cpu (unless you have other bugs
in the driver). 

Best Regards,
Micha³ Miros³aw

From nbd@nbd.name Tue Jul 12 18:10:09 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Tue, 12 Jul 2011 18:10:18 +0200 (CEST)
Received: from nbd.name ([46.4.11.11]:43872 "EHLO nbd.name"
        rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org with ESMTP
        id S1491153Ab1GLQKJ convert rfc822-to-8bit (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Tue, 12 Jul 2011 18:10:09 +0200
Subject: Re: [ath9k-devel] [PATCH v2 07/46] net/wireless: ath9k: fix DMA API usage
References: <cover.1310339688.git.mirq-linux@rere.qmqm.pl> <280ad9176e6532f231e054b38b952b20580874c5.1310339688.git.mirq-linux@rere.qmqm.pl> <4E1BCF36.2010506@openwrt.org> <20110712095541.GA6236@rere.qmqm.pl> <B4765EFC-B5C9-4E2D-BE00-ED5519D13A4E@nbd.name> <20110712130316.GA8621@rere.qmqm.pl> <EC2F82D7-9206-4139-9539-F5DDE38A5629@nbd.name> <20110712155849.GB10651@rere.qmqm.pl>
From:   Felix Fietkau <nbd@nbd.name>
Content-Transfer-Encoding: 8BIT
Content-Type: text/plain; charset=utf-8
In-Reply-To: <20110712155849.GB10651@rere.qmqm.pl>
Message-Id: <57124BD4-F53A-4424-A61F-5D8E629EB36F@nbd.name>
Date:   Wed, 13 Jul 2011 00:04:50 +0800
Cc:     Felix Fietkau <nbd@openwrt.org>,
        "netdev@vger.kernel.org" <netdev@vger.kernel.org>,
        "linux-wireless@vger.kernel.org" <linux-wireless@vger.kernel.org>,
        Jouni Malinen <jmalinen@atheros.com>,
        Senthil Balasubramanian <senthilkumar@atheros.com>,
        "ath9k-devel@lists.ath9k.org" <ath9k-devel@lists.ath9k.org>,
        Vasanthakumar Thiagarajan <vasanth@atheros.com>,
        Ralf Baechle <ralf@linux-mips.org>,
        "linux-mips@linux-mips.org" <linux-mips@linux-mips.org>
To:     =?utf-8?Q?Micha=C5=82_Miros=C5=82aw?= <mirq-linux@rere.qmqm.pl>
Mime-Version: 1.0 (iPhone Mail 8H7)
X-Mailer: iPhone Mail (8H7)
X-archive-position: 30611
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: nbd@nbd.name
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 8697
Content-Length: 5325
Lines: 79

On 12.07.2011, at 23:58, MichaÅ‚ MirosÅ‚aw <mirq-linux@rere.qmqm.pl> wrote:

> On Tue, Jul 12, 2011 at 10:21:05PM +0800, Felix Fietkau wrote:
>> On 12.07.2011, at 21:03, MichaÅ‚ MirosÅ‚aw <mirq-linux@rere.qmqm.pl> wrote:
>> 
>>> On Tue, Jul 12, 2011 at 08:54:32PM +0800, Felix Fietkau wrote:
>>>> On 12.07.2011, at 17:55, MichaÅ‚ MirosÅ‚aw <mirq-linux@rere.qmqm.pl> wrote:
>>>> 
>>>>> On Tue, Jul 12, 2011 at 12:36:06PM +0800, Felix Fietkau wrote:
>>>>>> On 2011-07-11 8:52 AM, MichaÅ‚ MirosÅ‚aw wrote:
>>>>>>> Also constify buf_addr for ath9k_hw_process_rxdesc_edma() to verify
>>>>>>> assumptions --- dma_sync_single_for_device() call can be removed.
>>>>>>> 
>>>>>>> Signed-off-by: MichaÅ‚ MirosÅ‚aw<mirq-linux@rere.qmqm.pl>
>>>>>>> ---
>>>>>>> drivers/net/wireless/ath/ath9k/ar9003_mac.c |    4 ++--
>>>>>>> drivers/net/wireless/ath/ath9k/ar9003_mac.h |    2 +-
>>>>>>> drivers/net/wireless/ath/ath9k/recv.c       |   10 +++-------
>>>>>>> 3 files changed, 6 insertions(+), 10 deletions(-)
>>>>>>> 
>>>>>>> diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
>>>>>>> index 70dc8ec..c5f46d5 100644
>>>>>>> --- a/drivers/net/wireless/ath/ath9k/recv.c
>>>>>>> +++ b/drivers/net/wireless/ath/ath9k/recv.c
>>>>>>> @@ -684,15 +684,11 @@ static bool ath_edma_get_buffers(struct ath_softc *sc,
>>>>>>>  BUG_ON(!bf);
>>>>>>> 
>>>>>>>  dma_sync_single_for_cpu(sc->dev, bf->bf_buf_addr,
>>>>>>> -                common->rx_bufsize, DMA_FROM_DEVICE);
>>>>>>> +                common->rx_bufsize, DMA_BIDIRECTIONAL);
>>>>>>> 
>>>>>>>  ret = ath9k_hw_process_rxdesc_edma(ah, NULL, skb->data);
>>>>>>> -    if (ret == -EINPROGRESS) {
>>>>>>> -        /*let device gain the buffer again*/
>>>>>>> -        dma_sync_single_for_device(sc->dev, bf->bf_buf_addr,
>>>>>>> -                common->rx_bufsize, DMA_FROM_DEVICE);
>>>>>>> +    if (ret == -EINPROGRESS)
>>>>>>>      return false;
>>>>>>> -    }
>>>>>>> 
>>>>>>>  __skb_unlink(skb,&rx_edma->rx_fifo);
>>>>>>>  if (ret == -EINVAL) {
>>>>>> I have strong doubts about this change. On most MIPS devices,
>>>>>> dma_sync_single_for_cpu is a no-op, whereas
>>>>>> dma_sync_single_for_device flushes the cache range. With this
>>>>>> change, the CPU could cache the DMA status part behind skb->data and
>>>>>> that cache entry would not be flushed inbetween calls to this
>>>>>> functions on the same buffer, likely leading to rx stalls.
>>>>> You're suggesting a platform implementation bug then. If the platform is not
>>>>> cache-coherent, it should invalidate relevant CPU cache lines for sync_to_cpu
>>>>> and unmap cases. Do other devices show such symptoms on MIPS systems?
>>>>> 
>>>>> I'm not familiar with the platform internals, so we should ask MIPS people.
>>>> I only mentioned MIPS to describe the potential side effect of this change. From my current understanding of the DMA API, it would be wrong on other platforms as well. I believe the _for_device function needs to be used to transfer ownership of the buffer back to the device, before calling _for_cpu again later for another read.
>>> What you're saying reminds the wording in DMA-API-HOWTO.txt that I find
>>> wrong (or at least misleading) compared to what DMA-API.txt describes.
>>> DMA sync calls do not transfer the ownership of the buffer - they are
>>> cache synchronization points, ownership passing is handled entirely by
>>> the driver.
>> What I meant was that the DMA sync calls reflect the ownership transfer of the memory regions. In this case ownership is transferred between device and CPU multiple times and the code reflects that.
>>>> This is definitely required in this case, because when the return code is -EINPROGRESS, the driver waits for the hardware to complete this buffer, and the next call has to fetch the memory again after the device has updated it.
>>> Correctness of this access should be provided by sync_to_cpu() call.
>> At least in MIPS I'm sure it isn't. If I remember correctly, it also isn't on ARM, so I'm pretty sure that either your understanding of the API is incorrect, or arch code does not implement it properly. In either case, this change (and probably also the p54 one) should not be merged.
> 
> I briefly looked through DMA API implementation in MIPS, and except
> for R10k and R12k both sync_for_cpu and sync_for_device are no-ops
> (see: arch/mips/mm/dma-default.c).  For R10k and R12k the syncs are
> in both points, and exactly like I described before - CPU cachelines
> are invalidated for DMA_FROM_DEVICE mappings, written back for
> DMA_TO_DEVICE, both for DMA_BIDIRECTIONAL (including redundant
> mapping+sync direction).
> 
> So doing that sync_to_device you are just invalidating the same cachelines
> twice for no gain (or do nothing twice in some cases) - they are not read
> by CPU between sync_to_device -> sync_to_cpu (unless you have other bugs
> in the driver). 
I think you're missing something. It works like this: In the AR9380 rx path, the descriptor is part of the skb. The rx tasklet checks for rx frame completion by calling the sync for cpu, reading the completion flag and (in case of a not completed frame) flushes the cache for that location again (for device). If you remove the for_device call, the next call to this function can see stale data, as the for_cpu call can be a no-op.

- Felix

From mirq-linux@rere.qmqm.pl Tue Jul 12 21:13:46 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Tue, 12 Jul 2011 21:13:55 +0200 (CEST)
Received: from rere.qmqm.pl ([89.167.52.164]:37535 "EHLO rere.qmqm.pl"
        rhost-flags-OK-FAIL-OK-FAIL) by eddie.linux-mips.org with ESMTP
        id S1491171Ab1GLTNq (ORCPT <rfc822;linux-mips@linux-mips.org>);
        Tue, 12 Jul 2011 21:13:46 +0200
Received: by rere.qmqm.pl (Postfix, from userid 1000)
        id 2D9B313A6A; Tue, 12 Jul 2011 21:13:45 +0200 (CEST)
Date:   Tue, 12 Jul 2011 21:13:45 +0200
From:   =?iso-8859-2?Q?Micha=B3_Miros=B3aw?= <mirq-linux@rere.qmqm.pl>
To:     Felix Fietkau <nbd@nbd.name>
Cc:     Felix Fietkau <nbd@openwrt.org>,
        "netdev@vger.kernel.org" <netdev@vger.kernel.org>,
        "linux-wireless@vger.kernel.org" <linux-wireless@vger.kernel.org>,
        Jouni Malinen <jmalinen@atheros.com>,
        Senthil Balasubramanian <senthilkumar@atheros.com>,
        "ath9k-devel@lists.ath9k.org" <ath9k-devel@lists.ath9k.org>,
        Vasanthakumar Thiagarajan <vasanth@atheros.com>,
        Ralf Baechle <ralf@linux-mips.org>,
        "linux-mips@linux-mips.org" <linux-mips@linux-mips.org>
Subject: Re: [ath9k-devel] [PATCH v2 07/46] net/wireless: ath9k: fix DMA
 API usage
Message-ID: <20110712191345.GA12934@rere.qmqm.pl>
References: <cover.1310339688.git.mirq-linux@rere.qmqm.pl>
 <280ad9176e6532f231e054b38b952b20580874c5.1310339688.git.mirq-linux@rere.qmqm.pl>
 <4E1BCF36.2010506@openwrt.org>
 <20110712095541.GA6236@rere.qmqm.pl>
 <B4765EFC-B5C9-4E2D-BE00-ED5519D13A4E@nbd.name>
 <20110712130316.GA8621@rere.qmqm.pl>
 <EC2F82D7-9206-4139-9539-F5DDE38A5629@nbd.name>
 <20110712155849.GB10651@rere.qmqm.pl>
 <57124BD4-F53A-4424-A61F-5D8E629EB36F@nbd.name>
MIME-Version: 1.0
Content-Type: text/plain; charset=iso-8859-2
Content-Disposition: inline
Content-Transfer-Encoding: 8bit
In-Reply-To: <57124BD4-F53A-4424-A61F-5D8E629EB36F@nbd.name>
User-Agent: Mutt/1.5.20 (2009-06-14)
X-archive-position: 30612
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: mirq-linux@rere.qmqm.pl
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 8852
Content-Length: 6466
Lines: 97

On Wed, Jul 13, 2011 at 12:04:50AM +0800, Felix Fietkau wrote:
> On 12.07.2011, at 23:58, Micha³ Miros³aw <mirq-linux@rere.qmqm.pl> wrote:
> 
> > On Tue, Jul 12, 2011 at 10:21:05PM +0800, Felix Fietkau wrote:
> >> On 12.07.2011, at 21:03, Micha³ Miros³aw <mirq-linux@rere.qmqm.pl> wrote:
> >> 
> >>> On Tue, Jul 12, 2011 at 08:54:32PM +0800, Felix Fietkau wrote:
> >>>> On 12.07.2011, at 17:55, Micha³ Miros³aw <mirq-linux@rere.qmqm.pl> wrote:
> >>>> 
> >>>>> On Tue, Jul 12, 2011 at 12:36:06PM +0800, Felix Fietkau wrote:
> >>>>>> On 2011-07-11 8:52 AM, Micha³ Miros³aw wrote:
> >>>>>>> Also constify buf_addr for ath9k_hw_process_rxdesc_edma() to verify
> >>>>>>> assumptions --- dma_sync_single_for_device() call can be removed.
> >>>>>>> 
> >>>>>>> Signed-off-by: Micha³ Miros³aw<mirq-linux@rere.qmqm.pl>
> >>>>>>> ---
> >>>>>>> drivers/net/wireless/ath/ath9k/ar9003_mac.c |    4 ++--
> >>>>>>> drivers/net/wireless/ath/ath9k/ar9003_mac.h |    2 +-
> >>>>>>> drivers/net/wireless/ath/ath9k/recv.c       |   10 +++-------
> >>>>>>> 3 files changed, 6 insertions(+), 10 deletions(-)
> >>>>>>> 
> >>>>>>> diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
> >>>>>>> index 70dc8ec..c5f46d5 100644
> >>>>>>> --- a/drivers/net/wireless/ath/ath9k/recv.c
> >>>>>>> +++ b/drivers/net/wireless/ath/ath9k/recv.c
> >>>>>>> @@ -684,15 +684,11 @@ static bool ath_edma_get_buffers(struct ath_softc *sc,
> >>>>>>>  BUG_ON(!bf);
> >>>>>>> 
> >>>>>>>  dma_sync_single_for_cpu(sc->dev, bf->bf_buf_addr,
> >>>>>>> -                common->rx_bufsize, DMA_FROM_DEVICE);
> >>>>>>> +                common->rx_bufsize, DMA_BIDIRECTIONAL);
> >>>>>>> 
> >>>>>>>  ret = ath9k_hw_process_rxdesc_edma(ah, NULL, skb->data);
> >>>>>>> -    if (ret == -EINPROGRESS) {
> >>>>>>> -        /*let device gain the buffer again*/
> >>>>>>> -        dma_sync_single_for_device(sc->dev, bf->bf_buf_addr,
> >>>>>>> -                common->rx_bufsize, DMA_FROM_DEVICE);
> >>>>>>> +    if (ret == -EINPROGRESS)
> >>>>>>>      return false;
> >>>>>>> -    }
> >>>>>>> 
> >>>>>>>  __skb_unlink(skb,&rx_edma->rx_fifo);
> >>>>>>>  if (ret == -EINVAL) {
> >>>>>> I have strong doubts about this change. On most MIPS devices,
> >>>>>> dma_sync_single_for_cpu is a no-op, whereas
> >>>>>> dma_sync_single_for_device flushes the cache range. With this
> >>>>>> change, the CPU could cache the DMA status part behind skb->data and
> >>>>>> that cache entry would not be flushed inbetween calls to this
> >>>>>> functions on the same buffer, likely leading to rx stalls.
> >>>>> You're suggesting a platform implementation bug then. If the platform is not
> >>>>> cache-coherent, it should invalidate relevant CPU cache lines for sync_to_cpu
> >>>>> and unmap cases. Do other devices show such symptoms on MIPS systems?
> >>>>> 
> >>>>> I'm not familiar with the platform internals, so we should ask MIPS people.
> >>>> I only mentioned MIPS to describe the potential side effect of this change. From my current understanding of the DMA API, it would be wrong on other platforms as well. I believe the _for_device function needs to be used to transfer ownership of the buffer back to the device, before calling _for_cpu again later for another read.
> >>> What you're saying reminds the wording in DMA-API-HOWTO.txt that I find
> >>> wrong (or at least misleading) compared to what DMA-API.txt describes.
> >>> DMA sync calls do not transfer the ownership of the buffer - they are
> >>> cache synchronization points, ownership passing is handled entirely by
> >>> the driver.
> >> What I meant was that the DMA sync calls reflect the ownership transfer of the memory regions. In this case ownership is transferred between device and CPU multiple times and the code reflects that.
> >>>> This is definitely required in this case, because when the return code is -EINPROGRESS, the driver waits for the hardware to complete this buffer, and the next call has to fetch the memory again after the device has updated it.
> >>> Correctness of this access should be provided by sync_to_cpu() call.
> >> At least in MIPS I'm sure it isn't. If I remember correctly, it also isn't on ARM, so I'm pretty sure that either your understanding of the API is incorrect, or arch code does not implement it properly. In either case, this change (and probably also the p54 one) should not be merged.
> > 
> > I briefly looked through DMA API implementation in MIPS, and except
> > for R10k and R12k both sync_for_cpu and sync_for_device are no-ops
> > (see: arch/mips/mm/dma-default.c).  For R10k and R12k the syncs are
> > in both points, and exactly like I described before - CPU cachelines
> > are invalidated for DMA_FROM_DEVICE mappings, written back for
> > DMA_TO_DEVICE, both for DMA_BIDIRECTIONAL (including redundant
> > mapping+sync direction).
> > 
> > So doing that sync_to_device you are just invalidating the same cachelines
> > twice for no gain (or do nothing twice in some cases) - they are not read
> > by CPU between sync_to_device -> sync_to_cpu (unless you have other bugs
> > in the driver). 
> I think you're missing something. It works like this: In the AR9380 rx path, the descriptor is part of the skb. The rx tasklet checks for rx frame completion by calling the sync for cpu, reading the completion flag and (in case of a not completed frame) flushes the cache for that location again (for device). If you remove the for_device call, the next call to this function can see stale data, as the for_cpu call can be a no-op.

Is the descriptor modified in any way before being checked again? Looks like
it isn't. That is my assumption - if this doesn't hold, then we're talking
about different things.

When I looked through the DMA API implementation for MIPS, I saw that whenever
sync_to_cpu is a no-op, sync_to_device is also a no-op. So the bug you're
seeing is not related to those calls. It might be that despite no-op sync
primitives, the platform is not cache-coherent --- that is DMA writes by
device do not cause corresponding CPU cache lines to be invalidated.

BTW, cache flush (other name: invalidation) is needed just before reading the
value. Doing it once more earlier does not really matter. Unless you're
modifying some data in the same cache line as mapped buffer --- then this
is a BUG in the driver and should either use DMA_BIDIRECTIONAL if the modified
value is part of the buffer, or move the modified data away.

Best Regards,
Micha³ Miros³aw

From linville@tuxdriver.com Wed Jul 13 20:47:25 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Wed, 13 Jul 2011 20:47:32 +0200 (CEST)
Received: from charlotte.tuxdriver.com ([70.61.120.58]:40924 "EHLO
        smtp.tuxdriver.com" rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org
        with ESMTP id S1491175Ab1GMSrZ (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Wed, 13 Jul 2011 20:47:25 +0200
Received: from uucp by smtp.tuxdriver.com with local-rmail (Exim 4.63)
        (envelope-from <linville@tuxdriver.com>)
        id 1Qh4SX-0001pT-SI; Wed, 13 Jul 2011 14:46:57 -0400
Received: from linville-8530p.local (linville-8530p.local [127.0.0.1])
        by linville-8530p.local (8.14.4/8.14.4) with ESMTP id p6DIXUwF030810;
        Wed, 13 Jul 2011 14:33:30 -0400
Received: (from linville@localhost)
        by linville-8530p.local (8.14.4/8.14.4/Submit) id p6DIXRBE030808;
        Wed, 13 Jul 2011 14:33:27 -0400
Date:   Wed, 13 Jul 2011 14:33:27 -0400
From:   "John W. Linville" <linville@tuxdriver.com>
To:     Hauke Mehrtens <hauke@hauke-m.de>
Cc:     ralf@linux-mips.org, linux-wireless@vger.kernel.org,
        zajec5@gmail.com, linux-mips@linux-mips.org, mb@bu3sch.de,
        george@znau.edu.ua, arend@broadcom.com,
        b43-dev@lists.infradead.org, bernhardloos@googlemail.com,
        arnd@arndb.de, julian.calaby@gmail.com, sshtylyov@mvista.com
Subject: Re: [PATCH 00/11] bcma: add support for embedded devices like bcm4716
Message-ID: <20110713183327.GD27827@tuxdriver.com>
References: <1310209563-6405-1-git-send-email-hauke@hauke-m.de>
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Disposition: inline
Content-Transfer-Encoding: 8bit
In-Reply-To: <1310209563-6405-1-git-send-email-hauke@hauke-m.de>
User-Agent: Mutt/1.5.21 (2010-09-15)
X-archive-position: 30613
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: linville@tuxdriver.com
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 9601
Content-Length: 1095
Lines: 25

On Sat, Jul 09, 2011 at 01:05:52PM +0200, Hauke Mehrtens wrote:
> This patch series adds support for embedded devices like bcm47xx to 
> bcma. Bcma is used on bcm4716 and bcm4718 SoCs as the system bus and
> replaced ssb used on older devices. With these patches my bcm4716 
> device boots up till it tries to access the flash, because the serial 
> flash chip is unsupported for now, this will be my next task. This adds 
> support for MIPS cores, interrupt configuration and the serial console.
> 
> These patches are not containing all functions needed to get the SoC to 
> fully work and support every feature, but it is a good start.
> These patches are now integrated in OpenWrt for everyone how wants to
> test them.
> 
> This was tested with a BCM4704 device (SoC with ssb bus), a BCM4716 
> device and a pcie wireless card supported by bcma.
> 
> 
> @RafaÅ‚: If you are fine with the bcma patches could you please give
> your Signed-off on them.

RafaÅ‚, ping?

-- 
John W. Linville		Someday the world will need a hero, and you
linville@tuxdriver.com			might be all we have.  Be ready.

From jonas.gorski@gmail.com Wed Jul 13 21:36:36 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Wed, 13 Jul 2011 21:36:42 +0200 (CEST)
Received: from mail-yi0-f49.google.com ([209.85.218.49]:57442 "EHLO
        mail-yi0-f49.google.com" rhost-flags-OK-OK-OK-OK)
        by eddie.linux-mips.org with ESMTP id S1491188Ab1GMTgg (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Wed, 13 Jul 2011 21:36:36 +0200
Received: by yib17 with SMTP id 17so2955384yib.36
        for <multiple recipients>; Wed, 13 Jul 2011 12:36:29 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=gmail.com; s=gamma;
        h=mime-version:in-reply-to:references:from:date:message-id:subject:to
         :cc:content-type:content-transfer-encoding;
        bh=/vbExA8+q67+sf5n2OE7IzhGh36kt6HaXxiAxSJ38s4=;
        b=hPJZlhrwd//IxghLw9nZRZMFUeX3mAFNOCO/U0lEa5/JIHF5QyNJnH1ojqk6R6q17z
         Tf5mnHclVlJghNT33kUie4oDYMjeHsq1fZUc+EsJTGpBit+NgqRE8LnxB6AcxFme/fvh
         OLMYs69wN4cNyJc0gvPmEoTCKD2dxx5UjUj9o=
Received: by 10.151.21.17 with SMTP id y17mr1654888ybi.13.1310585789143; Wed,
 13 Jul 2011 12:36:29 -0700 (PDT)
MIME-Version: 1.0
Received: by 10.151.158.21 with HTTP; Wed, 13 Jul 2011 12:36:09 -0700 (PDT)
In-Reply-To: <1310209563-6405-5-git-send-email-hauke@hauke-m.de>
References: <1310209563-6405-1-git-send-email-hauke@hauke-m.de> <1310209563-6405-5-git-send-email-hauke@hauke-m.de>
From:   Jonas Gorski <jonas.gorski@gmail.com>
Date:   Wed, 13 Jul 2011 21:36:09 +0200
Message-ID: <CAOiHx=n+sFWJ1WOwt-DBDMTNhZEH95MxkxOR-sQsKK1HkmmR9g@mail.gmail.com>
Subject: Re: [PATCH 04/11] bcma: add SOC bus
To:     Hauke Mehrtens <hauke@hauke-m.de>
Cc:     ralf@linux-mips.org, linux-wireless@vger.kernel.org,
        zajec5@gmail.com, linux-mips@linux-mips.org, mb@bu3sch.de,
        george@znau.edu.ua, arend@broadcom.com,
        b43-dev@lists.infradead.org, bernhardloos@googlemail.com,
        arnd@arndb.de, julian.calaby@gmail.com, sshtylyov@mvista.com
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: base64
X-archive-position: 30614
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: jonas.gorski@gmail.com
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 9631
Content-Length: 16669
Lines: 217

SGksCgpzb21lIG1pbm9yIHRoaW5ncyBJIHNhdzoKCk9uIDkgSnVseSAyMDExIDEzOjA1LCBIYXVr
ZSBNZWhydGVucyA8aGF1a2VAaGF1a2UtbS5kZT4gd3JvdGU6Cj4gVGhpcyBwYXRjaCBhZGRzIHN1
cHBvcnQgZm9yIHVzaW5nIGJjbWEgb24gYSBCcm9hZGNvbSBTb0MgYXMgdGhlIHN5c3RlbQo+IGJ1
cy4gQW4gU29DIGxpa2UgdGhlIGJjbTQ3MTYgY291bGQgcmVnaXN0ZXIgdGhpcyBidXMgYW5kIHVz
ZSBpdCB0bwo+IHNlYXJjaGVzIGZvciB0aGUgYmNtYSBjb3JlcyBhbmQgcmVnaXN0ZXIgdGhlIGRl
dmljZXMgb24gdGhpcyBidXMuCj4KPiBTaWduZWQtb2ZmLWJ5OiBIYXVrZSBNZWhydGVucyA8aGF1
a2VAaGF1a2UtbS5kZT4KPiAtLS0KPiDCoGRyaXZlcnMvYmNtYS9LY29uZmlnIMKgIMKgIMKgIMKg
IMKgfCDCoCDCoDUgKwo+IMKgZHJpdmVycy9iY21hL01ha2VmaWxlIMKgIMKgIMKgIMKgIHwgwqAg
wqAxICsKPiDCoGRyaXZlcnMvYmNtYS9ob3N0X3NvYy5jIMKgIMKgIMKgIHwgwqAxNzggKysrKysr
KysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysKPiDCoGRyaXZlcnMvYmNtYS9tYWlu
LmMgwqAgwqAgwqAgwqAgwqAgfCDCoCDCoDEgKwo+IMKgZHJpdmVycy9iY21hL3NjYW4uYyDCoCDC
oCDCoCDCoCDCoCB8IMKgIDI0ICsrKysrLQo+IMKgaW5jbHVkZS9saW51eC9iY21hL2JjbWEuaCDC
oCDCoCB8IMKgIMKgNCArCj4gwqBpbmNsdWRlL2xpbnV4L2JjbWEvYmNtYV9zb2MuaCB8IMKgIDE2
ICsrKysKPiDCoDcgZmlsZXMgY2hhbmdlZCwgMjI3IGluc2VydGlvbnMoKyksIDIgZGVsZXRpb25z
KC0pCj4gwqBjcmVhdGUgbW9kZSAxMDA2NDQgZHJpdmVycy9iY21hL2hvc3Rfc29jLmMKPiDCoGNy
ZWF0ZSBtb2RlIDEwMDY0NCBpbmNsdWRlL2xpbnV4L2JjbWEvYmNtYV9zb2MuaAo+Cj4gZGlmZiAt
LWdpdCBhL2RyaXZlcnMvYmNtYS9LY29uZmlnIGIvZHJpdmVycy9iY21hL0tjb25maWcKPiBpbmRl
eCAzNTM3ODFiLi44ZDgyZjQyIDEwMDY0NAo+IC0tLSBhL2RyaXZlcnMvYmNtYS9LY29uZmlnCj4g
KysrIGIvZHJpdmVycy9iY21hL0tjb25maWcKPiBAQCAtMjIsNiArMjIsMTEgQEAgY29uZmlnIEJD
TUFfSE9TVF9QQ0kKPiDCoCDCoCDCoCDCoGJvb2wgIlN1cHBvcnQgZm9yIEJDTUEgb24gUENJLWhv
c3QgYnVzIgo+IMKgIMKgIMKgIMKgZGVwZW5kcyBvbiBCQ01BX0hPU1RfUENJX1BPU1NJQkxFCj4K
PiArY29uZmlnIEJDTUFfSE9TVF9TT0MKPiArIMKgIMKgIMKgIGJvb2wKPiArIMKgIMKgIMKgIGRl
cGVuZHMgb24gQkNNQSAmJiBNSVBTCj4gKyDCoCDCoCDCoCBkZWZhdWx0IG4KCkRlZmF1bHQgZGVm
YXVsdCBpcyBhbHJlYWR5ICJuIiwgc28gdGhpcyBsaW5lIGlzIHN1cGVyZmx1b3VzLgoKPiArCj4g
wqBjb25maWcgQkNNQV9ERUJVRwo+IMKgIMKgIMKgIMKgYm9vbCAiQkNNQSBkZWJ1Z2dpbmciCj4g
wqAgwqAgwqAgwqBkZXBlbmRzIG9uIEJDTUEKPiBkaWZmIC0tZ2l0IGEvZHJpdmVycy9iY21hL01h
a2VmaWxlIGIvZHJpdmVycy9iY21hL01ha2VmaWxlCj4gaW5kZXggMGQ1NjI0NS4uNDJkNjFkZCAx
MDA2NDQKPiAtLS0gYS9kcml2ZXJzL2JjbWEvTWFrZWZpbGUKPiArKysgYi9kcml2ZXJzL2JjbWEv
TWFrZWZpbGUKPiBAQCAtMiw2ICsyLDcgQEAgYmNtYS15IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgKz0gbWFpbi5vIHNjYW4ubyBjb3JlLm8KPiDCoGJj
bWEteSDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCArPSBk
cml2ZXJfY2hpcGNvbW1vbi5vIGRyaXZlcl9jaGlwY29tbW9uX3BtdS5vCj4gwqBiY21hLXkgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgKz0gZHJpdmVyX3Bj
aS5vCj4gwqBiY21hLSQoQ09ORklHX0JDTUFfSE9TVF9QQ0kpIMKgIMKgIMKgIMKgIMKgICs9IGhv
c3RfcGNpLm8KPiArYmNtYS0kKENPTkZJR19CQ01BX0hPU1RfU09DKSDCoCDCoCDCoCDCoCDCoCAr
PSBob3N0X3NvYy5vCj4gwqBvYmotJChDT05GSUdfQkNNQSkgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgKz0gYmNtYS5vCj4KPiDCoGNjZmxhZ3MtJChDT05GSUdfQkNNQV9ERUJVRykgwqAg
wqAgwqAgwqAgwqAgOj0gLURERUJVRwo+IGRpZmYgLS1naXQgYS9kcml2ZXJzL2JjbWEvaG9zdF9z
b2MuYyBiL2RyaXZlcnMvYmNtYS9ob3N0X3NvYy5jCj4gbmV3IGZpbGUgbW9kZSAxMDA2NDQKPiBp
bmRleCAwMDAwMDAwLi5hNmZlNzI0Cj4gLS0tIC9kZXYvbnVsbAo+ICsrKyBiL2RyaXZlcnMvYmNt
YS9ob3N0X3NvYy5jCj4gQEAgLTAsMCArMSwxNzggQEAKPiArLyoKPiArICogQnJvYWRjb20gc3Bl
Y2lmaWMgQU1CQQo+ICsgKiBTeXN0ZW0gb24gQ2hpcCAoU29DKSBIb3N0Cj4gKyAqCj4gKyAqIExp
Y2Vuc2VkIHVuZGVyIHRoZSBHTlUvR1BMLiBTZWUgQ09QWUlORyBmb3IgZGV0YWlscy4KPiArICov
Cj4gKwo+ICsjaW5jbHVkZSAiYmNtYV9wcml2YXRlLmgiCj4gKyNpbmNsdWRlICJzY2FuLmgiCj4g
KyNpbmNsdWRlIDxsaW51eC9iY21hL2JjbWEuaD4KPiArI2luY2x1ZGUgPGxpbnV4L2JjbWEvYmNt
YV9zb2MuaD4KPiArCj4gK3N0YXRpYyB1OCBiY21hX2hvc3Rfc29jX3JlYWQ4KHN0cnVjdCBiY21h
X2RldmljZSAqY29yZSwgdTE2IG9mZnNldCkKPiArewo+ICsgwqAgwqAgwqAgcmV0dXJuIHJlYWRi
KGNvcmUtPmlvX2FkZHIgKyBvZmZzZXQpOwo+ICt9Cj4gKwo+ICtzdGF0aWMgdTE2IGJjbWFfaG9z
dF9zb2NfcmVhZDE2KHN0cnVjdCBiY21hX2RldmljZSAqY29yZSwgdTE2IG9mZnNldCkKPiArewo+
ICsgwqAgwqAgwqAgcmV0dXJuIHJlYWR3KGNvcmUtPmlvX2FkZHIgKyBvZmZzZXQpOwo+ICt9Cj4g
Kwo+ICtzdGF0aWMgdTMyIGJjbWFfaG9zdF9zb2NfcmVhZDMyKHN0cnVjdCBiY21hX2RldmljZSAq
Y29yZSwgdTE2IG9mZnNldCkKPiArewo+ICsgwqAgwqAgwqAgcmV0dXJuIHJlYWRsKGNvcmUtPmlv
X2FkZHIgKyBvZmZzZXQpOwo+ICt9Cj4gKwo+ICtzdGF0aWMgdm9pZCBiY21hX2hvc3Rfc29jX3dy
aXRlOChzdHJ1Y3QgYmNtYV9kZXZpY2UgKmNvcmUsIHUxNiBvZmZzZXQsCj4gKyDCoCDCoCDCoCDC
oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoHU4IHZhbHVlKQo+ICt7Cj4gKyDC
oCDCoCDCoCB3cml0ZWIodmFsdWUsIGNvcmUtPmlvX2FkZHIgKyBvZmZzZXQpOwo+ICt9Cj4gKwo+
ICtzdGF0aWMgdm9pZCBiY21hX2hvc3Rfc29jX3dyaXRlMTYoc3RydWN0IGJjbWFfZGV2aWNlICpj
b3JlLCB1MTYgb2Zmc2V0LAo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqB1MTYgdmFsdWUpCj4gK3sKPiArIMKgIMKgIMKgIHdyaXRldyh2YWx1ZSwgY29y
ZS0+aW9fYWRkciArIG9mZnNldCk7Cj4gK30KPiArCj4gK3N0YXRpYyB2b2lkIGJjbWFfaG9zdF9z
b2Nfd3JpdGUzMihzdHJ1Y3QgYmNtYV9kZXZpY2UgKmNvcmUsIHUxNiBvZmZzZXQsCj4gKyDCoCDC
oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoHUzMiB2YWx1ZSkKPiAr
ewo+ICsgwqAgwqAgwqAgd3JpdGVsKHZhbHVlLCBjb3JlLT5pb19hZGRyICsgb2Zmc2V0KTsKPiAr
fQo+ICsKPiArI2lmZGVmIENPTkZJR19CQ01BX0JMT0NLSU8KPiArc3RhdGljIHZvaWQgYmNtYV9o
b3N0X3NvY19ibG9ja19yZWFkKHN0cnVjdCBiY21hX2RldmljZSAqY29yZSwgdm9pZCAqYnVmZmVy
LAo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqBzaXplX3QgY291bnQsIHUxNiBvZmZzZXQsIHU4IHJlZ193aWR0aCkKPiArewo+ICsgwqAgwqAg
wqAgdm9pZCBfX2lvbWVtICphZGRyID0gY29yZS0+aW9fYWRkciArIG9mZnNldDsKPiArCj4gKyDC
oCDCoCDCoCBzd2l0Y2ggKHJlZ193aWR0aCkgewo+ICsgwqAgwqAgwqAgY2FzZSBzaXplb2YodTgp
OiB7Cj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCB1OCAqYnVmID0gYnVmZmVyOwo+ICsKPiArIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIHdoaWxlIChjb3VudCkgewo+ICsgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgKmJ1ZiA9IF9fcmF3X3JlYWRiKGFkZHIpOwo+ICsgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgYnVmKys7Cj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCBjb3VudC0tOwo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgfQo+ICsgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgYnJlYWs7Cj4gKyDCoCDCoCDCoCB9Cj4gKyDCoCDCoCDCoCBjYXNlIHNpemVv
Zih1MTYpOiB7Cj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCBfX2xlMTYgKmJ1ZiA9IGJ1ZmZlcjsK
PiArCj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCBXQVJOX09OKGNvdW50ICYgMSk7Cj4gKyDCoCDC
oCDCoCDCoCDCoCDCoCDCoCB3aGlsZSAoY291bnQpIHsKPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgICpidWYgPSAoX19mb3JjZSBfX2xlMTYpX19yYXdfcmVhZHcoYWRkcik7Cj4g
KyDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCBidWYrKzsKPiArIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIGNvdW50IC09IDI7Cj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDC
oCB9Cj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCBicmVhazsKPiArIMKgIMKgIMKgIH0KPiArIMKg
IMKgIMKgIGNhc2Ugc2l6ZW9mKHUzMik6IHsKPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIF9fbGUz
MiAqYnVmID0gYnVmZmVyOwo+ICsKPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIFdBUk5fT04oY291
bnQgJiAzKTsKPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIHdoaWxlIChjb3VudCkgewo+ICsgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgKmJ1ZiA9IChfX2ZvcmNlIF9fbGUzMilfX3Jh
d19yZWFkbChhZGRyKTsKPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGJ1Zisr
Owo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgY291bnQgLT0gNDsKPiArIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIH0KPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGJyZWFrOwo+ICsg
wqAgwqAgwqAgfQo+ICsgwqAgwqAgwqAgZGVmYXVsdDoKPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IFdBUk5fT04oMSk7Cj4gKyDCoCDCoCDCoCB9Cj4gK30KPiArCj4gK3N0YXRpYyB2b2lkIGJjbWFf
aG9zdF9zb2NfYmxvY2tfd3JpdGUoc3RydWN0IGJjbWFfZGV2aWNlICpjb3JlLAo+ICsgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgY29uc3Qgdm9p
ZCAqYnVmZmVyLAo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgc2l6ZV90IGNvdW50LCB1MTYgb2Zmc2V0LCB1OCByZWdfd2lkdGgpCj4gK3sK
PiArIMKgIMKgIMKgIHZvaWQgX19pb21lbSAqYWRkciA9IGNvcmUtPmlvX2FkZHIgKyBvZmZzZXQ7
Cj4gKwo+ICsgwqAgwqAgwqAgc3dpdGNoIChyZWdfd2lkdGgpIHsKPiArIMKgIMKgIMKgIGNhc2Ug
c2l6ZW9mKHU4KTogewo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgY29uc3QgdTggKmJ1ZiA9IGJ1
ZmZlcjsKPiArCj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCB3aGlsZSAoY291bnQpIHsKPiArIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIF9fcmF3X3dyaXRlYigqYnVmLCBhZGRyKTsK
PiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGJ1ZisrOwo+ICsgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgY291bnQtLTsKPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IH0KPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGJyZWFrOwo+ICsgwqAgwqAgwqAgfQo+ICsgwqAg
wqAgwqAgY2FzZSBzaXplb2YodTE2KTogewo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgY29uc3Qg
X19sZTE2ICpidWYgPSBidWZmZXI7Cj4gKwo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgV0FSTl9P
Tihjb3VudCAmIDEpOwo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgd2hpbGUgKGNvdW50KSB7Cj4g
KyDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCBfX3Jhd193cml0ZXcoKF9fZm9yY2Ug
dTE2KSgqYnVmKSwgYWRkcik7Cj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCBi
dWYrKzsKPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGNvdW50IC09IDI7Cj4g
KyDCoCDCoCDCoCDCoCDCoCDCoCDCoCB9Cj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCBicmVhazsK
PiArIMKgIMKgIMKgIH0KPiArIMKgIMKgIMKgIGNhc2Ugc2l6ZW9mKHUzMik6IHsKPiArIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIGNvbnN0IF9fbGUzMiAqYnVmID0gYnVmZmVyOwo+ICsKPiArIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIFdBUk5fT04oY291bnQgJiAzKTsKPiArIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIHdoaWxlIChjb3VudCkgewo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
X19yYXdfd3JpdGVsKChfX2ZvcmNlIHUzMikoKmJ1ZiksIGFkZHIpOwo+ICsgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgYnVmKys7Cj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCBjb3VudCAtPSA0Owo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgfQo+ICsgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgYnJlYWs7Cj4gKyDCoCDCoCDCoCB9Cj4gKyDCoCDCoCDCoCBkZWZhdWx0
Ogo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgV0FSTl9PTigxKTsKPiArIMKgIMKgIMKgIH0KPiAr
fQo+ICsjZW5kaWYgLyogQ09ORklHX0JDTUFfQkxPQ0tJTyAqLwo+ICsKPiArc3RhdGljIHUzMiBi
Y21hX2hvc3Rfc29jX2FyZWFkMzIoc3RydWN0IGJjbWFfZGV2aWNlICpjb3JlLCB1MTYgb2Zmc2V0
KQo+ICt7Cj4gKyDCoCDCoCDCoCByZXR1cm4gcmVhZGwoY29yZS0+aW9fd3JhcCArIG9mZnNldCk7
Cj4gK30KPiArCj4gK3N0YXRpYyB2b2lkIGJjbWFfaG9zdF9zb2NfYXdyaXRlMzIoc3RydWN0IGJj
bWFfZGV2aWNlICpjb3JlLCB1MTYgb2Zmc2V0LAo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgdTMyIHZhbHVlKQo+ICt7Cj4gKyDCoCDCoCDCoCB3cml0
ZWwodmFsdWUsIGNvcmUtPmlvX3dyYXAgKyBvZmZzZXQpOwo+ICt9Cj4gKwo+ICtjb25zdCBzdHJ1
Y3QgYmNtYV9ob3N0X29wcyBiY21hX2hvc3Rfc29jX29wcyA9IHsKPiArIMKgIMKgIMKgIC5yZWFk
OCDCoCDCoCDCoCDCoCDCoD0gYmNtYV9ob3N0X3NvY19yZWFkOCwKPiArIMKgIMKgIMKgIC5yZWFk
MTYgwqAgwqAgwqAgwqAgPSBiY21hX2hvc3Rfc29jX3JlYWQxNiwKPiArIMKgIMKgIMKgIC5yZWFk
MzIgwqAgwqAgwqAgwqAgPSBiY21hX2hvc3Rfc29jX3JlYWQzMiwKPiArIMKgIMKgIMKgIC53cml0
ZTggwqAgwqAgwqAgwqAgPSBiY21hX2hvc3Rfc29jX3dyaXRlOCwKPiArIMKgIMKgIMKgIC53cml0
ZTE2IMKgIMKgIMKgIMKgPSBiY21hX2hvc3Rfc29jX3dyaXRlMTYsCj4gKyDCoCDCoCDCoCAud3Jp
dGUzMiDCoCDCoCDCoCDCoD0gYmNtYV9ob3N0X3NvY193cml0ZTMyLAo+ICsjaWZkZWYgQ09ORklH
X0JDTUFfQkxPQ0tJTwo+ICsgwqAgwqAgwqAgLmJsb2NrX3JlYWQgwqAgwqAgPSBiY21hX2hvc3Rf
c29jX2Jsb2NrX3JlYWQsCj4gKyDCoCDCoCDCoCAuYmxvY2tfd3JpdGUgwqAgwqA9IGJjbWFfaG9z
dF9zb2NfYmxvY2tfd3JpdGUsCj4gKyNlbmRpZgo+ICsgwqAgwqAgwqAgLmFyZWFkMzIgwqAgwqAg
wqAgwqA9IGJjbWFfaG9zdF9zb2NfYXJlYWQzMiwKPiArIMKgIMKgIMKgIC5hd3JpdGUzMiDCoCDC
oCDCoCA9IGJjbWFfaG9zdF9zb2NfYXdyaXRlMzIsCj4gK307Cj4gKwo+ICtpbnQgX19pbml0IGJj
bWFfaG9zdF9zb2NfcmVnaXN0ZXIoc3RydWN0IGJjbWFfc29jICpzb2MpCj4gK3sKPiArIMKgIMKg
IMKgIHN0cnVjdCBiY21hX2J1cyAqYnVzID0gJnNvYy0+YnVzOwo+ICsKPiArIMKgIMKgIMKgIC8q
IGlvbWFwIG9ubHkgZmlyc3QgY29yZS4gV2UgaGF2ZSB0byByZWFkIHNvbWUgcmVnaXN0ZXIgb24g
dGhpcyBjb3JlCj4gKyDCoCDCoCDCoCDCoCogdG8gc2NhbiB0aGUgYnVzLgo+ICsgwqAgwqAgwqAg
wqAqLwo+ICsgwqAgwqAgwqAgYnVzLT5tbWlvID0gaW9yZW1hcChCQ01BX0FERFJfQkFTRSwgQkNN
QV9DT1JFX1NJWkUgKiAxKTsKPiArIMKgIMKgIMKgIGlmICghYnVzLT5tbWlvKQo+ICsgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgcmV0dXJuIC1FTk9NRU07Cj4gKwo+ICsgwqAgwqAgwqAgLyogSG9zdCBz
cGVjaWZpYyAqLwo+ICsgwqAgwqAgwqAgYnVzLT5ob3N0dHlwZSA9IEJDTUFfSE9TVFRZUEVfU09D
Owo+ICsgwqAgwqAgwqAgYnVzLT5vcHMgPSAmYmNtYV9ob3N0X3NvY19vcHM7Cj4gKwo+ICsgwqAg
wqAgwqAgLyogUmVnaXN0ZXIgKi8KPiArIMKgIMKgIMKgIHJldHVybiBiY21hX2J1c19lYXJseV9y
ZWdpc3RlcihidXMsICZzb2MtPmNvcmVfY2MsICZzb2MtPmNvcmVfbWlwcyk7Cj4gK30KPiBkaWZm
IC0tZ2l0IGEvZHJpdmVycy9iY21hL21haW4uYyBiL2RyaXZlcnMvYmNtYS9tYWluLmMKPiBpbmRl
eCBlNmMzMDhjLi4yY2E1ZWViIDEwMDY0NAo+IC0tLSBhL2RyaXZlcnMvYmNtYS9tYWluLmMKPiAr
KysgYi9kcml2ZXJzL2JjbWEvbWFpbi5jCj4gQEAgLTkyLDYgKzkyLDcgQEAgc3RhdGljIGludCBi
Y21hX3JlZ2lzdGVyX2NvcmVzKHN0cnVjdCBiY21hX2J1cyAqYnVzKQo+IMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgYnJlYWs7Cj4gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBjYXNl
IEJDTUFfSE9TVFRZUEVfTk9ORToKPiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoGNhc2UgQkNNQV9I
T1NUVFlQRV9TRElPOgo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgY2FzZSBCQ01BX0hPU1RUWVBF
X1NPQzoKPiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoGJyZWFrOwo+IMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgfQo+Cj4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvYmNtYS9zY2FuLmMg
Yi9kcml2ZXJzL2JjbWEvc2Nhbi5jCj4gaW5kZXggYmY5ZjgwNi4uMjAyZWRjOCAxMDA2NDQKPiAt
LS0gYS9kcml2ZXJzL2JjbWEvc2Nhbi5jCj4gKysrIGIvZHJpdmVycy9iY21hL3NjYW4uYwo+IEBA
IC0zMzcsNiArMzM3LDE0IEBAIHN0YXRpYyBpbnQgYmNtYV9nZXRfbmV4dF9jb3JlKHN0cnVjdCBi
Y21hX2J1cyAqYnVzLCB1MzIgX19pb21lbSAqKmVyb21wdHIsCj4gwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqB9Cj4gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqB9Cj4gwqAgwqAgwqAg
wqB9Cj4gKyDCoCDCoCDCoCBpZiAoYnVzLT5ob3N0dHlwZSA9PSBCQ01BX0hPU1RUWVBFX1NPQykg
ewo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgY29yZS0+aW9fYWRkciA9IGlvcmVtYXAoY29yZS0+
YWRkciwgQkNNQV9DT1JFX1NJWkUpOwo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgaWYgKCFjb3Jl
LT5pb19hZGRyKQo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgcmV0dXJuIC1F
Tk9NRU07Cj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCBjb3JlLT5pb193cmFwID0gaW9yZW1hcChj
b3JlLT53cmFwLCBCQ01BX0NPUkVfU0laRSk7Cj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCBpZiAo
IWNvcmUtPmlvX3dyYXApCj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCByZXR1
cm4gLUVOT01FTTsKClNob3VsZG4ndCB5b3UgdW5tYXAgY29yZS0+aW9fYWRkciBpZiByZW1hcHBp
bmcgaW9fd3JhcCBmYWlscz8KCj4gKyDCoCDCoCDCoCB9Cj4gwqAgwqAgwqAgwqByZXR1cm4gMDsK
PiDCoH0KPgo+IEBAIC0zNjksNyArMzc3LDEzIEBAIGludCBiY21hX2J1c19zY2FuKHN0cnVjdCBi
Y21hX2J1cyAqYnVzKQo+IMKgIMKgIMKgIMKgYmNtYV9pbml0X2J1cyhidXMpOwo+Cj4gwqAgwqAg
wqAgwqBlcm9tYmFzZSA9IGJjbWFfc2Nhbl9yZWFkMzIoYnVzLCAwLCBCQ01BX0NDX0VST00pOwo+
IC0gwqAgwqAgwqAgZXJvbXB0ciA9IGJ1cy0+bW1pbzsKPiArIMKgIMKgIMKgIGlmIChidXMtPmhv
c3R0eXBlID09IEJDTUFfSE9TVFRZUEVfU09DKSB7Cj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCBl
cm9tcHRyID0gaW9yZW1hcChlcm9tYmFzZSwgQkNNQV9DT1JFX1NJWkUpOwo+ICsgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgaWYgKCFlcm9tcHRyKQo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgcmV0dXJuIC1FTk9NRU07Cj4gKyDCoCDCoCDCoCB9IGVsc2UKPiArIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIGVyb21wdHIgPSBidXMtPm1taW87CgpEb2N1bWVudGF0aW9uL0NvZGluZ1N0eWxl
IHNheXMgdXNlIGJyYWNlcyBpbiBib3RoIGJyYW5jaGVzIGlmIG9uZSBuZWVkcyB0aGVtLgoKPiAr
Cj4gwqAgwqAgwqAgwqBlcm9tZW5kID0gZXJvbXB0ciArIEJDTUFfQ09SRV9TSVpFIC8gc2l6ZW9m
KHUzMik7Cj4KPiDCoCDCoCDCoCDCoGJjbWFfc2Nhbl9zd2l0Y2hfY29yZShidXMsIGVyb21iYXNl
KTsKPiBAQCAtNDE3LDcgKzQzMSwxMyBAQCBpbnQgX19pbml0IGJjbWFfYnVzX3NjYW5fZWFybHko
c3RydWN0IGJjbWFfYnVzICpidXMsCj4gwqAgwqAgwqAgwqBpbnQgZXJyLCBjb3JlX251bSA9IDA7
Cj4KPiDCoCDCoCDCoCDCoGVyb21iYXNlID0gYmNtYV9zY2FuX3JlYWQzMihidXMsIDAsIEJDTUFf
Q0NfRVJPTSk7Cj4gLSDCoCDCoCDCoCBlcm9tcHRyID0gYnVzLT5tbWlvOwo+ICsgwqAgwqAgwqAg
aWYgKGJ1cy0+aG9zdHR5cGUgPT0gQkNNQV9IT1NUVFlQRV9TT0MpIHsKPiArIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIGVyb21wdHIgPSBpb3JlbWFwKGVyb21iYXNlLCBCQ01BX0NPUkVfU0laRSk7Cj4g
KyDCoCDCoCDCoCDCoCDCoCDCoCDCoCBpZiAoIWVyb21wdHIpCj4gKyDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCDCoCDCoCDCoCByZXR1cm4gLUVOT01FTTsKPiArIMKgIMKgIMKgIH0gZWxzZQo+ICsg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgZXJvbXB0ciA9IGJ1cy0+bW1pbzsKCkRpdHRvLgoKPiArCj4g
wqAgwqAgwqAgwqBlcm9tZW5kID0gZXJvbXB0ciArIEJDTUFfQ09SRV9TSVpFIC8gc2l6ZW9mKHUz
Mik7Cj4KPiDCoCDCoCDCoCDCoGJjbWFfc2Nhbl9zd2l0Y2hfY29yZShidXMsIGVyb21iYXNlKTsK
PiBkaWZmIC0tZ2l0IGEvaW5jbHVkZS9saW51eC9iY21hL2JjbWEuaCBiL2luY2x1ZGUvbGludXgv
YmNtYS9iY21hLmgKPiBpbmRleCA2YmQ3YjdmLi43M2ZkYTFjIDEwMDY0NAo+IC0tLSBhL2luY2x1
ZGUvbGludXgvYmNtYS9iY21hLmgKPiArKysgYi9pbmNsdWRlL2xpbnV4L2JjbWEvYmNtYS5oCj4g
QEAgLTE2LDYgKzE2LDcgQEAgZW51bSBiY21hX2hvc3R0eXBlIHsKPiDCoCDCoCDCoCDCoEJDTUFf
SE9TVFRZUEVfTk9ORSwKPiDCoCDCoCDCoCDCoEJDTUFfSE9TVFRZUEVfUENJLAo+IMKgIMKgIMKg
IMKgQkNNQV9IT1NUVFlQRV9TRElPLAo+ICsgwqAgwqAgwqAgQkNNQV9IT1NUVFlQRV9TT0MsCj4g
wqB9Owo+Cj4gwqBzdHJ1Y3QgYmNtYV9jaGlwaW5mbyB7Cj4gQEAgLTEyNCw2ICsxMjUsOSBAQCBz
dHJ1Y3QgYmNtYV9kZXZpY2Ugewo+IMKgIMKgIMKgIMKgdTMyIGFkZHI7Cj4gwqAgwqAgwqAgwqB1
MzIgd3JhcDsKPgo+ICsgwqAgwqAgwqAgdm9pZCBfX2lvbWVtICppb19hZGRyOwo+ICsgwqAgwqAg
wqAgdm9pZCBfX2lvbWVtICppb193cmFwOwo+ICsKPiDCoCDCoCDCoCDCoHZvaWQgKmRydmRhdGE7
Cj4gwqAgwqAgwqAgwqBzdHJ1Y3QgbGlzdF9oZWFkIGxpc3Q7Cj4gwqB9Owo+IGRpZmYgLS1naXQg
YS9pbmNsdWRlL2xpbnV4L2JjbWEvYmNtYV9zb2MuaCBiL2luY2x1ZGUvbGludXgvYmNtYS9iY21h
X3NvYy5oCj4gbmV3IGZpbGUgbW9kZSAxMDA2NDQKPiBpbmRleCAwMDAwMDAwLi40MjAzYzU1Cj4g
LS0tIC9kZXYvbnVsbAo+ICsrKyBiL2luY2x1ZGUvbGludXgvYmNtYS9iY21hX3NvYy5oCj4gQEAg
LTAsMCArMSwxNiBAQAo+ICsjaWZuZGVmIExJTlVYX0JDTUFfU09DX0hfCj4gKyNkZWZpbmUgTElO
VVhfQkNNQV9TT0NfSF8KPiArCj4gKyNpbmNsdWRlIDxsaW51eC9iY21hL2JjbWEuaD4KPiArCj4g
K3N0cnVjdCBiY21hX3NvYyB7Cj4gKyDCoCDCoCDCoCBzdHJ1Y3QgYmNtYV9idXMgYnVzOwo+ICsg
wqAgwqAgwqAgc3RydWN0IGJjbWFfZGV2aWNlIGNvcmVfY2M7Cj4gKyDCoCDCoCDCoCBzdHJ1Y3Qg
YmNtYV9kZXZpY2UgY29yZV9taXBzOwo+ICt9Owo+ICsKPiAraW50IF9faW5pdCBiY21hX2hvc3Rf
c29jX3JlZ2lzdGVyKHN0cnVjdCBiY21hX3NvYyAqc29jKTsKPiArCj4gK2ludCBiY21hX2J1c19y
ZWdpc3RlcihzdHJ1Y3QgYmNtYV9idXMgKmJ1cyk7Cj4gKwo+ICsjZW5kaWYgLyogTElOVVhfQkNN
QV9TT0NfSF8gKi8KPiAtLQo+IDEuNy40LjEK

From jonas.gorski@gmail.com Wed Jul 13 21:52:33 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Wed, 13 Jul 2011 21:52:41 +0200 (CEST)
Received: from mail-yi0-f49.google.com ([209.85.218.49]:51785 "EHLO
        mail-yi0-f49.google.com" rhost-flags-OK-OK-OK-OK)
        by eddie.linux-mips.org with ESMTP id S1491187Ab1GMTwd convert rfc822-to-8bit
        (ORCPT <rfc822;linux-mips@linux-mips.org>);
        Wed, 13 Jul 2011 21:52:33 +0200
Received: by yib17 with SMTP id 17so2962616yib.36
        for <multiple recipients>; Wed, 13 Jul 2011 12:52:27 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=gmail.com; s=gamma;
        h=mime-version:in-reply-to:references:from:date:message-id:subject:to
         :cc:content-type:content-transfer-encoding;
        bh=neyNCn8R8SqY+9G0hSyBpFahem1RRmEMUaDTRUv12EI=;
        b=IVQgN9OJkj8NUfYUnRNdEnBNvarmHYvVvOz+vi0c2aieIYmx5pXs6KIe5KaMfCuwhk
         GWgN7gTEGE+uM1Os/mkKoaHBzRLOzvmzIFa4xaP6ve2WMvm8Pz5wfAxq+0/DXbBKbhbk
         KnOock3S1JnxnQC+Bk9n1r7O81iGD//F4+jF8=
Received: by 10.151.21.17 with SMTP id y17mr1670718ybi.13.1310586747120; Wed,
 13 Jul 2011 12:52:27 -0700 (PDT)
MIME-Version: 1.0
Received: by 10.151.158.21 with HTTP; Wed, 13 Jul 2011 12:52:07 -0700 (PDT)
In-Reply-To: <1310209563-6405-11-git-send-email-hauke@hauke-m.de>
References: <1310209563-6405-1-git-send-email-hauke@hauke-m.de> <1310209563-6405-11-git-send-email-hauke@hauke-m.de>
From:   Jonas Gorski <jonas.gorski@gmail.com>
Date:   Wed, 13 Jul 2011 21:52:07 +0200
Message-ID: <CAOiHx=myVVQYJumwhy7FwoSp5-mebhryDs1xnKMLCZpn=NP-7Q@mail.gmail.com>
Subject: Re: [PATCH 10/11] bcm47xx: add support for bcma bus
To:     Hauke Mehrtens <hauke@hauke-m.de>
Cc:     ralf@linux-mips.org, linux-wireless@vger.kernel.org,
        zajec5@gmail.com, linux-mips@linux-mips.org, mb@bu3sch.de,
        george@znau.edu.ua, arend@broadcom.com,
        b43-dev@lists.infradead.org, bernhardloos@googlemail.com,
        arnd@arndb.de, julian.calaby@gmail.com, sshtylyov@mvista.com
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8BIT
X-archive-position: 30615
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: jonas.gorski@gmail.com
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 9641
Content-Length: 3235
Lines: 80

On 9 July 2011 13:06, Hauke Mehrtens <hauke@hauke-m.de> wrote:
> This patch add support for the bcma bus. Broadcom uses only Mips 74K
> CPUs on the new SoC and on the old ons using ssb bus there are no Mips
> 74K CPUs.
>
> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
> ---
> Â arch/mips/bcm47xx/Kconfig Â  Â  Â  Â  Â  Â  Â  Â  Â  Â | Â  13 ++++++
> Â arch/mips/bcm47xx/gpio.c Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  | Â  22 +++++++++++
> Â arch/mips/bcm47xx/nvram.c Â  Â  Â  Â  Â  Â  Â  Â  Â  Â | Â  10 +++++
> Â arch/mips/bcm47xx/serial.c Â  Â  Â  Â  Â  Â  Â  Â  Â  | Â  29 ++++++++++++++
> Â arch/mips/bcm47xx/setup.c Â  Â  Â  Â  Â  Â  Â  Â  Â  Â | Â  53 +++++++++++++++++++++++++-
> Â arch/mips/bcm47xx/time.c Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  | Â  Â 5 ++
> Â arch/mips/include/asm/mach-bcm47xx/bcm47xx.h | Â  Â 8 ++++
> Â arch/mips/include/asm/mach-bcm47xx/gpio.h Â  Â | Â  41 ++++++++++++++++++++
> Â drivers/watchdog/bcm47xx_wdt.c Â  Â  Â  Â  Â  Â  Â  | Â  11 +++++
> Â 9 files changed, 190 insertions(+), 2 deletions(-)
>
> diff --git a/arch/mips/bcm47xx/Kconfig b/arch/mips/bcm47xx/Kconfig
> index 0346f92..6210b8d 100644
> --- a/arch/mips/bcm47xx/Kconfig
> +++ b/arch/mips/bcm47xx/Kconfig
> @@ -15,4 +15,17 @@ config BCM47XX_SSB
>
> Â  Â  Â  Â  This will generate an image with support for SSB and MIPS32 R1 instruction set.
>
> +config BCM47XX_BCMA
> + Â  Â  Â  bool "BCMA Support for Broadcom BCM47XX"
> + Â  Â  Â  select SYS_HAS_CPU_MIPS32_R2
> + Â  Â  Â  select BCMA
> + Â  Â  Â  select BCMA_HOST_SOC
> + Â  Â  Â  select BCMA_DRIVER_MIPS
> + Â  Â  Â  select BCMA_DRIVER_PCI_HOSTMODE if PCI
> + Â  Â  Â  default y
> + Â  Â  Â  help
> + Â  Â  Â  Â Add support for new Broadcom BCM47xx boards with Broadcom specific Advanced Microcontroller Bus.
> +
> + Â  Â  Â  Â This will generate an image with support for BCMA and MIPS32 R2 instruction set.
> +

BCM47XX_SSB and BCM47XX_BCMA should either exclude each other, or
SYS_HAS_CPU_MIPS32_R2 should only be selected when BCM47XX_SSB isn't
selected.
I would expect an image built when having both selected to also
support both systems, but selecting MIPS32_R2 as the CPU this will
make it actually not work on SSB systems.

> diff --git a/arch/mips/bcm47xx/gpio.c b/arch/mips/bcm47xx/gpio.c
> index 3320e91..9d5bafe 100644
> --- a/arch/mips/bcm47xx/gpio.c
> +++ b/arch/mips/bcm47xx/gpio.c
> @@ -36,6 +36,16 @@ int gpio_request(unsigned gpio, const char *tag)
>
> Â  Â  Â  Â  Â  Â  Â  Â return 0;
> Â #endif
> +#ifdef CONFIG_BCM47XX_BCMA
> + Â  Â  Â  case BCM47XX_BUS_TYPE_BCMA:
> + Â  Â  Â  Â  Â  Â  Â  if ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES)

gpio is already unsigned, you shouldn't need to cast it.

> + Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  return -EINVAL;
> +
> + Â  Â  Â  Â  Â  Â  Â  if (test_and_set_bit(gpio, gpio_in_use))
> + Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  return -EBUSY;
> +
> + Â  Â  Â  Â  Â  Â  Â  return 0;
> +#endif
> Â  Â  Â  Â }
> Â  Â  Â  Â return -EINVAL;
> Â }
> @@ -57,6 +67,14 @@ void gpio_free(unsigned gpio)
> Â  Â  Â  Â  Â  Â  Â  Â clear_bit(gpio, gpio_in_use);
> Â  Â  Â  Â  Â  Â  Â  Â return;
> Â #endif
> +#ifdef CONFIG_BCM47XX_BCMA
> + Â  Â  Â  case BCM47XX_BUS_TYPE_BCMA:
> + Â  Â  Â  Â  Â  Â  Â  if ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES)

Ditto.

From hauke@hauke-m.de Wed Jul 13 22:06:02 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Wed, 13 Jul 2011 22:06:10 +0200 (CEST)
Received: from server19320154104.serverpool.info ([193.201.54.104]:53550 "EHLO
        hauke-m.de" rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org
        with ESMTP id S1491187Ab1GMUGC (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Wed, 13 Jul 2011 22:06:02 +0200
Received: from localhost (localhost [127.0.0.1])
        by hauke-m.de (Postfix) with ESMTP id 57FF58C62;
        Wed, 13 Jul 2011 22:06:01 +0200 (CEST)
X-Virus-Scanned: Debian amavisd-new at hauke-m.de 
Received: from hauke-m.de ([127.0.0.1])
        by localhost (hauke-m.de [127.0.0.1]) (amavisd-new, port 10024)
        with ESMTP id gY0cHf2Gkn3r; Wed, 13 Jul 2011 22:05:56 +0200 (CEST)
Received: from [192.168.0.152] (host-091-097-251-162.ewe-ip-backbone.de [91.97.251.162])
        by hauke-m.de (Postfix) with ESMTPSA id 9813F8C4F;
        Wed, 13 Jul 2011 22:05:55 +0200 (CEST)
Message-ID: <4E1DFAA2.8060800@hauke-m.de>
Date:   Wed, 13 Jul 2011 22:05:54 +0200
From:   Hauke Mehrtens <hauke@hauke-m.de>
User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.17) Gecko/20110516 Lightning/1.0b2 Thunderbird/3.1.10
MIME-Version: 1.0
To:     Jonas Gorski <jonas.gorski@gmail.com>
CC:     ralf@linux-mips.org, linux-wireless@vger.kernel.org,
        zajec5@gmail.com, linux-mips@linux-mips.org, mb@bu3sch.de,
        george@znau.edu.ua, arend@broadcom.com,
        b43-dev@lists.infradead.org, bernhardloos@googlemail.com,
        arnd@arndb.de, julian.calaby@gmail.com, sshtylyov@mvista.com
Subject: Re: [PATCH 10/11] bcm47xx: add support for bcma bus
References: <1310209563-6405-1-git-send-email-hauke@hauke-m.de> <1310209563-6405-11-git-send-email-hauke@hauke-m.de> <CAOiHx=myVVQYJumwhy7FwoSp5-mebhryDs1xnKMLCZpn=NP-7Q@mail.gmail.com>
In-Reply-To: <CAOiHx=myVVQYJumwhy7FwoSp5-mebhryDs1xnKMLCZpn=NP-7Q@mail.gmail.com>
X-Enigmail-Version: 1.1.2
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 7bit
X-archive-position: 30616
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: hauke@hauke-m.de
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 9651
Content-Length: 3464
Lines: 91

Hi  Jonas,

Thank you for the review.

On 07/13/2011 09:52 PM, Jonas Gorski wrote:
> On 9 July 2011 13:06, Hauke Mehrtens <hauke@hauke-m.de> wrote:
>> This patch add support for the bcma bus. Broadcom uses only Mips 74K
>> CPUs on the new SoC and on the old ons using ssb bus there are no Mips
>> 74K CPUs.
>>
>> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
>> ---
>>  arch/mips/bcm47xx/Kconfig                    |   13 ++++++
>>  arch/mips/bcm47xx/gpio.c                     |   22 +++++++++++
>>  arch/mips/bcm47xx/nvram.c                    |   10 +++++
>>  arch/mips/bcm47xx/serial.c                   |   29 ++++++++++++++
>>  arch/mips/bcm47xx/setup.c                    |   53 +++++++++++++++++++++++++-
>>  arch/mips/bcm47xx/time.c                     |    5 ++
>>  arch/mips/include/asm/mach-bcm47xx/bcm47xx.h |    8 ++++
>>  arch/mips/include/asm/mach-bcm47xx/gpio.h    |   41 ++++++++++++++++++++
>>  drivers/watchdog/bcm47xx_wdt.c               |   11 +++++
>>  9 files changed, 190 insertions(+), 2 deletions(-)
>>
>> diff --git a/arch/mips/bcm47xx/Kconfig b/arch/mips/bcm47xx/Kconfig
>> index 0346f92..6210b8d 100644
>> --- a/arch/mips/bcm47xx/Kconfig
>> +++ b/arch/mips/bcm47xx/Kconfig
>> @@ -15,4 +15,17 @@ config BCM47XX_SSB
>>
>>         This will generate an image with support for SSB and MIPS32 R1 instruction set.
>>
>> +config BCM47XX_BCMA
>> +       bool "BCMA Support for Broadcom BCM47XX"
>> +       select SYS_HAS_CPU_MIPS32_R2
>> +       select BCMA
>> +       select BCMA_HOST_SOC
>> +       select BCMA_DRIVER_MIPS
>> +       select BCMA_DRIVER_PCI_HOSTMODE if PCI
>> +       default y
>> +       help
>> +        Add support for new Broadcom BCM47xx boards with Broadcom specific Advanced Microcontroller Bus.
>> +
>> +        This will generate an image with support for BCMA and MIPS32 R2 instruction set.
>> +
> 
> BCM47XX_SSB and BCM47XX_BCMA should either exclude each other, or
> SYS_HAS_CPU_MIPS32_R2 should only be selected when BCM47XX_SSB isn't
> selected.
> I would expect an image built when having both selected to also
> support both systems, but selecting MIPS32_R2 as the CPU this will
> make it actually not work on SSB systems.
It should be possible to build a kernel capable of running with both
versions. I would change "select SYS_HAS_CPU_MIPS32_R2" to "select
SYS_HAS_CPU_MIPS32_R2 if !BCM47XX_SSB" that should make the image mips
r1 compatible if it was build for older cpus.
> 
>> diff --git a/arch/mips/bcm47xx/gpio.c b/arch/mips/bcm47xx/gpio.c
>> index 3320e91..9d5bafe 100644
>> --- a/arch/mips/bcm47xx/gpio.c
>> +++ b/arch/mips/bcm47xx/gpio.c
>> @@ -36,6 +36,16 @@ int gpio_request(unsigned gpio, const char *tag)
>>
>>                return 0;
>>  #endif
>> +#ifdef CONFIG_BCM47XX_BCMA
>> +       case BCM47XX_BUS_TYPE_BCMA:
>> +               if ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES)
> 
> gpio is already unsigned, you shouldn't need to cast it.
Will do that.
> 
>> +                       return -EINVAL;
>> +
>> +               if (test_and_set_bit(gpio, gpio_in_use))
>> +                       return -EBUSY;
>> +
>> +               return 0;
>> +#endif
>>        }
>>        return -EINVAL;
>>  }
>> @@ -57,6 +67,14 @@ void gpio_free(unsigned gpio)
>>                clear_bit(gpio, gpio_in_use);
>>                return;
>>  #endif
>> +#ifdef CONFIG_BCM47XX_BCMA
>> +       case BCM47XX_BUS_TYPE_BCMA:
>> +               if ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES)
> 
> Ditto.


From jonas.gorski@gmail.com Wed Jul 13 22:39:55 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Wed, 13 Jul 2011 22:40:04 +0200 (CEST)
Received: from mail-yx0-f177.google.com ([209.85.213.177]:56327 "EHLO
        mail-yx0-f177.google.com" rhost-flags-OK-OK-OK-OK)
        by eddie.linux-mips.org with ESMTP id S1491187Ab1GMUjz convert rfc822-to-8bit
        (ORCPT <rfc822;linux-mips@linux-mips.org>);
        Wed, 13 Jul 2011 22:39:55 +0200
Received: by yxj20 with SMTP id 20so2980678yxj.36
        for <multiple recipients>; Wed, 13 Jul 2011 13:39:49 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=gmail.com; s=gamma;
        h=mime-version:in-reply-to:references:from:date:message-id:subject:to
         :cc:content-type:content-transfer-encoding;
        bh=J+JwlHC2XZThFQvj6GRIBMdaBb57R+z5U405CA/y3RA=;
        b=TZIYcgziIDOYvUd0kQwrf8Ldanf2YZsAjqksk0FvDENiAwWNQS/UPNYat/+R0D2fHO
         Lp+sqg7e0bfEz0YFqodg96Mk6PJLqr5HOrp0dVtSGRpF2ExJ7hjm1zbtNKiNVPuVZVsu
         v3zD9QSn2zg7CziPi7q2DWy6/mN/P8ZKEjQLY=
Received: by 10.150.175.13 with SMTP id x13mr1617820ybe.355.1310589589166;
 Wed, 13 Jul 2011 13:39:49 -0700 (PDT)
MIME-Version: 1.0
Received: by 10.151.158.21 with HTTP; Wed, 13 Jul 2011 13:39:29 -0700 (PDT)
In-Reply-To: <1310209563-6405-6-git-send-email-hauke@hauke-m.de>
References: <1310209563-6405-1-git-send-email-hauke@hauke-m.de> <1310209563-6405-6-git-send-email-hauke@hauke-m.de>
From:   Jonas Gorski <jonas.gorski@gmail.com>
Date:   Wed, 13 Jul 2011 22:39:29 +0200
Message-ID: <CAOiHx=mpRNUtmLHFBw4n9XC4-cf4agc1tn4_twYFvz7=TQStzQ@mail.gmail.com>
Subject: Re: [PATCH 05/11] bcma: add mips driver
To:     Hauke Mehrtens <hauke@hauke-m.de>
Cc:     ralf@linux-mips.org, linux-wireless@vger.kernel.org,
        zajec5@gmail.com, linux-mips@linux-mips.org, mb@bu3sch.de,
        george@znau.edu.ua, arend@broadcom.com,
        b43-dev@lists.infradead.org, bernhardloos@googlemail.com,
        arnd@arndb.de, julian.calaby@gmail.com, sshtylyov@mvista.com
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8BIT
X-archive-position: 30617
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: jonas.gorski@gmail.com
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 9681
Content-Length: 2013
Lines: 59

On 9 July 2011 13:05, Hauke Mehrtens <hauke@hauke-m.de> wrote:
> diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c
> index 2ca5eeb..ba9a357 100644
> --- a/drivers/bcma/main.c
> +++ b/drivers/bcma/main.c
> @@ -79,6 +79,7 @@ static int bcma_register_cores(struct bcma_bus *bus)
> Â  Â  Â  Â  Â  Â  Â  Â case BCMA_CORE_CHIPCOMMON:
> Â  Â  Â  Â  Â  Â  Â  Â case BCMA_CORE_PCI:
> Â  Â  Â  Â  Â  Â  Â  Â case BCMA_CORE_PCIE:
> + Â  Â  Â  Â  Â  Â  Â  case BCMA_CORE_MIPS_74K:
> Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â continue;
> Â  Â  Â  Â  Â  Â  Â  Â }
>
> @@ -138,6 +139,15 @@ int bcma_bus_register(struct bcma_bus *bus)
> Â  Â  Â  Â  Â  Â  Â  Â bcma_core_chipcommon_init(&bus->drv_cc);
> Â  Â  Â  Â }
>
> +#ifdef CONFIG_BCMA_DRIVER_MIPS
> + Â  Â  Â  /* Init MIPS core */
> + Â  Â  Â  core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
> + Â  Â  Â  if (core) {
> + Â  Â  Â  Â  Â  Â  Â  bus->drv_mips.core = core;
> + Â  Â  Â  Â  Â  Â  Â  bcma_core_mips_init(&bus->drv_mips);
> + Â  Â  Â  }
> +#endif

You could avoid the ugly ifdefs here by moving it to
bcma_driver_mips.h and change

extern void bcma_core_mips_init(struct bcma_drv_mips *mcore);

to
#ifdef CONFIG_BCMA_DRIVER_MIPS
extern void bcma_core_mips_init(struct bcma_drv_mips *mcore);
#else
static inline void bcma_core_mips_init(struct bcma_drv_mips *mcore) { }
#endif

assuming the bus->drv_mips.core being set doesn't have any side
effects in the no mips core driver case.

> +
> Â  Â  Â  Â /* Init PCIE core */
> Â  Â  Â  Â core = bcma_find_core(bus, BCMA_CORE_PCIE);
> Â  Â  Â  Â if (core) {
> @@ -200,6 +210,15 @@ int __init bcma_bus_early_register(struct bcma_bus *bus,
> Â  Â  Â  Â  Â  Â  Â  Â bcma_core_chipcommon_init(&bus->drv_cc);
> Â  Â  Â  Â }
>
> +#ifdef CONFIG_BCMA_DRIVER_MIPS
> + Â  Â  Â  /* Init MIPS core */
> + Â  Â  Â  core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
> + Â  Â  Â  if (core) {
> + Â  Â  Â  Â  Â  Â  Â  bus->drv_mips.core = core;
> + Â  Â  Â  Â  Â  Â  Â  bcma_core_mips_init(&bus->drv_mips);
> + Â  Â  Â  }
> +#endif

Ditto.

From jonas.gorski@gmail.com Wed Jul 13 22:56:42 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Wed, 13 Jul 2011 22:56:52 +0200 (CEST)
Received: from mail-yi0-f49.google.com ([209.85.218.49]:61149 "EHLO
        mail-yi0-f49.google.com" rhost-flags-OK-OK-OK-OK)
        by eddie.linux-mips.org with ESMTP id S1491187Ab1GMU4m (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Wed, 13 Jul 2011 22:56:42 +0200
Received: by yib17 with SMTP id 17so2991689yib.36
        for <multiple recipients>; Wed, 13 Jul 2011 13:56:36 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=gmail.com; s=gamma;
        h=mime-version:in-reply-to:references:from:date:message-id:subject:to
         :cc:content-type:content-transfer-encoding;
        bh=upBy/YHFn/AqHxF2wl2HvGzu/3kxTov8+mSQCd9/JeM=;
        b=Qy1uagbBH/0wllEpEin98FEw+B9WS+iROOmpVwE1HGt38RLtXQpXdo/8578Z9+dDcG
         SzPtirvWwHJoB5nfsugZPAv28b1m5CmkLDe0G75ADZIhQfhUW3Y0jHN+SplQkeESKzLq
         Fp7dg2y6sMqDErVPnaV3knsYMk6SOcMgkrj9E=
Received: by 10.150.114.10 with SMTP id m10mr1628583ybc.412.1310590596178;
 Wed, 13 Jul 2011 13:56:36 -0700 (PDT)
MIME-Version: 1.0
Received: by 10.151.158.21 with HTTP; Wed, 13 Jul 2011 13:56:16 -0700 (PDT)
In-Reply-To: <1310209563-6405-7-git-send-email-hauke@hauke-m.de>
References: <1310209563-6405-1-git-send-email-hauke@hauke-m.de> <1310209563-6405-7-git-send-email-hauke@hauke-m.de>
From:   Jonas Gorski <jonas.gorski@gmail.com>
Date:   Wed, 13 Jul 2011 22:56:16 +0200
Message-ID: <CAOiHx==5TdoOw0rt-GhnRG_gKCaWpcBE=yhRAe5ufu01tp_SnQ@mail.gmail.com>
Subject: Re: [PATCH 06/11] bcma: add serial console support
To:     Hauke Mehrtens <hauke@hauke-m.de>
Cc:     ralf@linux-mips.org, linux-wireless@vger.kernel.org,
        zajec5@gmail.com, linux-mips@linux-mips.org, mb@bu3sch.de,
        george@znau.edu.ua, arend@broadcom.com,
        b43-dev@lists.infradead.org, bernhardloos@googlemail.com,
        arnd@arndb.de, julian.calaby@gmail.com, sshtylyov@mvista.com
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: base64
X-archive-position: 30618
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: jonas.gorski@gmail.com
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 9692
Content-Length: 7044
Lines: 92

T24gOSBKdWx5IDIwMTEgMTM6MDUsIEhhdWtlIE1laHJ0ZW5zIDxoYXVrZUBoYXVrZS1tLmRlPiB3
cm90ZToKPiBUaGlzIGFkZHMgc3VwcG9ydCBmb3Igc2VyaWFsIGNvbnNvbGUgdG8gYmNtYSwgd2hl
biBvcGVyYXRpbmcgb24gYW4gU29DLgo+Cj4gU2lnbmVkLW9mZi1ieTogSGF1a2UgTWVocnRlbnMg
PGhhdWtlQGhhdWtlLW0uZGU+Cj4gLS0tCj4gwqBkcml2ZXJzL2JjbWEvYmNtYV9wcml2YXRlLmgg
wqAgwqAgwqAgwqAgwqAgfCDCoCDCoDYgKysrCj4gwqBkcml2ZXJzL2JjbWEvZHJpdmVyX2NoaXBj
b21tb24uYyDCoCDCoCDCoHwgwqAgNjQgKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysr
Cj4gwqBkcml2ZXJzL2JjbWEvZHJpdmVyX21pcHMuYyDCoCDCoCDCoCDCoCDCoCDCoHwgwqAgwqA5
ICsrKysrCj4gwqBpbmNsdWRlL2xpbnV4L2JjbWEvYmNtYV9kcml2ZXJfbWlwcy5oIHwgwqAgMTEg
KysrKysrCj4gwqA0IGZpbGVzIGNoYW5nZWQsIDkwIGluc2VydGlvbnMoKyksIDAgZGVsZXRpb25z
KC0pCj4KPiBkaWZmIC0tZ2l0IGEvZHJpdmVycy9iY21hL2JjbWFfcHJpdmF0ZS5oIGIvZHJpdmVy
cy9iY21hL2JjbWFfcHJpdmF0ZS5oCj4gaW5kZXggODMwMzg2Yy4uOTJlYzY3MSAxMDA2NDQKPiAt
LS0gYS9kcml2ZXJzL2JjbWEvYmNtYV9wcml2YXRlLmgKPiArKysgYi9kcml2ZXJzL2JjbWEvYmNt
YV9wcml2YXRlLmgKPiBAQCAtMjYsNiArMjYsMTIgQEAgaW50IF9faW5pdCBiY21hX2J1c19zY2Fu
X2Vhcmx5KHN0cnVjdCBiY21hX2J1cyAqYnVzLAo+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIHN0cnVjdCBiY21hX2RldmljZSAqY29yZSk7Cj4gwqB2b2lkIGJj
bWFfaW5pdF9idXMoc3RydWN0IGJjbWFfYnVzICpidXMpOwo+Cj4gKy8qIGRyaXZlcl9jaGlwY29t
bW9uLmMgKi8KPiArI2lmZGVmIENPTkZJR19CQ01BX0RSSVZFUl9NSVBTCj4gK2V4dGVybiBpbnQg
YmNtYV9jaGlwY29fc2VyaWFsX2luaXQoc3RydWN0IGJjbWFfZHJ2X2NjICpjYywKPiArIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgc3RydWN0IGJjbWFf
ZHJ2X21pcHNfc2VyaWFsX3BvcnQgKnBvcnRzKTsKPiArI2VuZGlmIC8qIENPTkZJR19CQ01BX0RS
SVZFUl9NSVBTICovCj4gKwo+IMKgI2lmZGVmIENPTkZJR19CQ01BX0hPU1RfUENJCj4gwqAvKiBo
b3N0X3BjaS5jICovCj4gwqBleHRlcm4gaW50IF9faW5pdCBiY21hX2hvc3RfcGNpX2luaXQodm9p
ZCk7Cj4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvYmNtYS9kcml2ZXJfY2hpcGNvbW1vbi5jIGIvZHJp
dmVycy9iY21hL2RyaXZlcl9jaGlwY29tbW9uLmMKPiBpbmRleCA3MDMyMWM2Li44ODUzM2NhIDEw
MDY0NAo+IC0tLSBhL2RyaXZlcnMvYmNtYS9kcml2ZXJfY2hpcGNvbW1vbi5jCj4gKysrIGIvZHJp
dmVycy9iY21hL2RyaXZlcl9jaGlwY29tbW9uLmMKPiBAQCAtOTIsMyArOTIsNjcgQEAgdTMyIGJj
bWFfY2hpcGNvX2dwaW9fcG9sYXJpdHkoc3RydWN0IGJjbWFfZHJ2X2NjICpjYywgdTMyIG1hc2ss
IHUzMiB2YWx1ZSkKPiDCoHsKPiDCoCDCoCDCoCDCoHJldHVybiBiY21hX2NjX3dyaXRlMzJfbWFz
a2VkKGNjLCBCQ01BX0NDX0dQSU9QT0wsIG1hc2ssIHZhbHVlKTsKPiDCoH0KPiArCj4gKyNpZmRl
ZiBDT05GSUdfQkNNQV9EUklWRVJfTUlQUwo+ICtpbnQgYmNtYV9jaGlwY29fc2VyaWFsX2luaXQo
c3RydWN0IGJjbWFfZHJ2X2NjICpjYywKPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIHN0cnVjdCBiY21hX2Rydl9taXBzX3NlcmlhbF9wb3J0ICpwb3J0cykKPiArewo+
ICsgwqAgwqAgwqAgaW50IG5yX3BvcnRzID0gMDsKPiArIMKgIMKgIMKgIHUzMiBwbGx0eXBlOwo+
ICsgwqAgwqAgwqAgdW5zaWduZWQgaW50IGlycTsKPiArIMKgIMKgIMKgIHUzMiBiYXVkX2Jhc2Us
IGRpdjsKPiArIMKgIMKgIMKgIHUzMiBpLCBuOwo+ICsgwqAgwqAgwqAgdW5zaWduZWQgaW50IGNj
cmV2ID0gY2MtPmNvcmUtPmlkLnJldjsKPiArCj4gKyDCoCDCoCDCoCBwbGx0eXBlID0gKGNjLT5j
YXBhYmlsaXRpZXMgJiBCQ01BX0NDX0NBUF9QTExUKTsKPiArIMKgIMKgIMKgIGlycSA9IGJjbWFf
Y29yZV9taXBzX2lycShjYy0+Y29yZSk7Cj4gKwo+ICsgwqAgwqAgwqAgaWYgKChjY3JldiA+PSAx
MSkgJiYgKGNjcmV2ICE9IDE1KSAmJiAoY2NyZXYgIT0gMjApKSB7Cj4gKyDCoCDCoCDCoCDCoCDC
oCDCoCDCoCAvKiBGaXhlZCBBTFAgY2xvY2sgKi8KPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGJh
dWRfYmFzZSA9IDIwMDAwMDAwOwo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgaWYgKGNjLT5jYXBh
YmlsaXRpZXMgJiBCQ01BX0NDX0NBUF9QTVUpIHsKPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIC8qIEZJWE1FOiBiYXVkX2Jhc2UgaXMgZGlmZmVyZW50IGZvciBkZXZpY2VzIHdp
dGggYSBQTVUgKi8KPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIFdBUk5fT04o
MSk7Cj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCB9Cj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCBk
aXYgPSAxOwo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgaWYgKGNjcmV2ID49IDIxKSB7Cj4gKyDC
oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCAvKiBUdXJuIG9mZiBVQVJUIGNsb2NrIGJl
Zm9yZSBzd2l0Y2hpbmcgY2xvY2tzb3VyY2UuICovCj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCDCoCBiY21hX2NjX3dyaXRlMzIoY2MsIEJDTUFfQ0NfQ09SRUNUTCwKPiArIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgYmNtYV9j
Y19yZWFkMzIoY2MsIEJDTUFfQ0NfQ09SRUNUTCkKPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgJiB+QkNNQV9DQ19DT1JFQ1RMX1VBUlRD
TEtFTik7Cj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCB9Cj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDC
oCAvKiBTZXQgdGhlIG92ZXJyaWRlIGJpdCBzbyB3ZSBkb24ndCBkaXZpZGUgaXQgKi8KPiArIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIGJjbWFfY2Nfd3JpdGUzMihjYywgQkNNQV9DQ19DT1JFQ1RMLAo+
ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBiY21hX2NjX3Jl
YWQzMihjYywgQkNNQV9DQ19DT1JFQ1RMKQo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqB8IEJDTUFfQ0NfQ09SRUNUTF9VQVJUQ0xLMCk7Cj4gKyDCoCDCoCDC
oCDCoCDCoCDCoCDCoCBpZiAoY2NyZXYgPj0gMjEpIHsKPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIC8qIFJlLWVuYWJsZSB0aGUgVUFSVCBjbG9jay4gKi8KPiArIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGJjbWFfY2Nfd3JpdGUzMihjYywgQkNNQV9DQ19DT1JF
Q1RMLAo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqBiY21hX2NjX3JlYWQzMihjYywgQkNNQV9DQ19DT1JFQ1RMKQo+ICsgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqB8IEJDTUFfQ0Nf
Q09SRUNUTF9VQVJUQ0xLRU4pOwo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgfQo+ICsgwqAgwqAg
wqAgfSBlbHNlCj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCBwcl9lcnIoInNlcmlhbCBub3Qgc3Vw
cG9ydGVkIG9uIHRoaXMgZGV2aWNlIGNjcmV2OiAweCV4XG4iLAo+ICsgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqBjY3Jldik7CgpEb2N1bWVudGF0aW9uL0NvZGluZ1N0eWxlIGFuZCBh
Z2FpbiA7LSkKCj4gKwo+ICsgwqAgwqAgwqAgLyogRGV0ZXJtaW5lIHRoZSByZWdpc3RlcnMgb2Yg
dGhlIFVBUlRzICovCj4gKyDCoCDCoCDCoCBuID0gKGNjLT5jYXBhYmlsaXRpZXMgJiBCQ01BX0ND
X0NBUF9OUlVBUlQpOwo+ICsgwqAgwqAgwqAgZm9yIChpID0gMDsgaSA8IG47IGkrKykgewo+ICsg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgdm9pZCBfX2lvbWVtICpjY19tbWlvOwo+ICsgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgdm9pZCBfX2lvbWVtICp1YXJ0X3JlZ3M7Cj4gKwo+ICsgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgY2NfbW1pbyA9IGNjLT5jb3JlLT5idXMtPm1taW8gKwo+ICsgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgKGNjLT5jb3JlLT5jb3JlX2luZGV4ICogQkNNQV9DT1JF
X1NJWkUpOwoKY2NfbW1pbyBpcyBjb25zdGFudCBmb3IgYWxsIHVhcnRzLCBzbyB5b3Ugc2hvdWxk
IG1vdmUgaXQgb3V0IG9mIHRoZQpsb29wIGFuZCBjYWxjdWxhdGUgaXQgb25jZS4KCj4gKyDCoCDC
oCDCoCDCoCDCoCDCoCDCoCB1YXJ0X3JlZ3MgPSBjY19tbWlvICsgQkNNQV9DQ19VQVJUMF9EQVRB
Owo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgdWFydF9yZWdzICs9IChpICogMjU2KTsKClNhbWUg
Zm9yIHRoZSB1YXJ0X3JlZ3MgYmFzZS4gSWYgeW91IGRvbid0IG1vZGlmeSBpdCBhdCBhbGwgeW91
IGNvdWxkCmRyb3AgdGhlIGNjX21taW8gdmFyaWFibGUgKHNpbmNlIHlvdSBvbmx5IG5lZWQgaXQg
dG8gY2FsY3VsYXRlCnVhcnRfcmVncykgYW5kCgo+ICsKPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IG5yX3BvcnRzKys7Cj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCBwb3J0c1tpXS5yZWdzID0gdWFy
dF9yZWdzOwoKdXNlIGhlcmUKIMKgIMKgIMKgIMKgIMKgIMKgIMKgIHBvcnRzW2ldLnJlZ3MgPSB1
YXJ0X3JlZ3MgKyAoaSAqIDI1Nik7CgpUaGlzIHdvdWxkIG1ha2UgdGhlIGNvZGUgYSBiaXQgY2xl
YW5lciBJTUhPLgoKPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIHBvcnRzW2ldLmlycSA9IGlycTsK
PiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIHBvcnRzW2ldLmJhdWRfYmFzZSA9IGJhdWRfYmFzZTsK
PiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIHBvcnRzW2ldLnJlZ19zaGlmdCA9IDA7Cj4gKyDCoCDC
oCDCoCB9Cj4gKwo+ICsgwqAgwqAgwqAgcmV0dXJuIG5yX3BvcnRzOwoKSXNuJ3QgbiBhbHdheXMg
dGhlIHNhbWUgYXMgbnJfcG9ydHM/IEF0IGxlYXN0IEkgZG9uJ3Qgc2VlIGFueSBjYXNlCndoZXJl
IGl0IGNvdWxkIGRpZmZlciwgc28geW91IHNob3VsZCBiZSBzYWZlIHdoZW4gZGlyZWN0bHkgdXNp
bmcKbnJfcG9ydHMgaW5zdGVhZCBvZiBuLgo=

From ben-i2c@fluff.org Wed Jul 13 23:57:04 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Wed, 13 Jul 2011 23:57:11 +0200 (CEST)
Received: from host6.manc-digital.ifl.telecomplete.net ([86.53.204.7]:11688
        "EHLO freya" rhost-flags-OK-OK-OK-FAIL) by eddie.linux-mips.org
        with ESMTP id S1491187Ab1GMV5E (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Wed, 13 Jul 2011 23:57:04 +0200
Received: from ben by freya with local (Exim 4.72)
        (envelope-from <ben@freya.fluff.org>)
        id 1Qh7QN-0001lf-8o; Wed, 13 Jul 2011 22:56:55 +0100
Date:   Wed, 13 Jul 2011 22:56:55 +0100
From:   Ben Dooks <ben-i2c@fluff.org>
To:     "Jayachandran C." <jayachandranc@netlogicmicro.com>
Cc:     linux-i2c@vger.kernel.org, linux-mips@linux-mips.org,
        ganesanr@netlogicmicro.com
Subject: Re: [PATCH] i2c: Support for Netlogic XLR/XLS on-chip I2C
 controller.
Message-ID: <20110713215655.GF3369@freya.fluff.org>
References: <20110623135057.GA26772@jayachandranc.netlogicmicro.com>
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
In-Reply-To: <20110623135057.GA26772@jayachandranc.netlogicmicro.com>
X-Disclaimer: These are my views alone.
X-URL:  http://www.fluff.org/
User-Agent: Mutt/1.5.20 (2009-06-14)
X-archive-position: 30619
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ben-i2c@fluff.org
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 9737
Content-Length: 7335
Lines: 260

On Thu, Jun 23, 2011 at 07:21:03PM +0530, Jayachandran C. wrote:
> From: Ganesan Ramalingam <ganesanr@netlogicmicro.com>
> 
> - platform.c : add i2c platform device
> - i2c-xlr.c : algorithm and i2c adaptor
> - Kconfig/Makefile: add CONFIG_I2C_XLR option
> 
> Signed-off-by: Ganesan Ramalingam <ganesanr@netlogicmicro.com>
> Signed-off-by: Jayachandran C <jayachandranc@netlogicmicro.com>
> ---

snip

> diff --git a/arch/mips/netlogic/xlr/platform.c b/arch/mips/netlogic/xlr/platform.c
> index 609ec25..2cd2d3c 100644
> --- a/arch/mips/netlogic/xlr/platform.c
> +++ b/arch/mips/netlogic/xlr/platform.c
> @@ -14,6 +14,7 @@
>  #include <linux/resource.h>
>  #include <linux/serial_8250.h>
>  #include <linux/serial_reg.h>
> +#include <linux/i2c.h>
>  
>  #include <asm/netlogic/xlr/iomap.h>
>  #include <asm/netlogic/xlr/pic.h>
> @@ -66,6 +67,34 @@ void nlm_xlr_uart_out(struct uart_port *p, int offset, int value)
>  		.serial_out	= nlm_xlr_uart_out,	\
>  	}
>  
> +#ifdef CONFIG_I2C
> +static struct i2c_board_info nlm_i2c_info1[] __initdata = {
> +	/* All XLR boards have this RTC and Max6657 Temp Chip */
> +	{"ds1374",          0, 0x68, 0, 0, 0},
> +	{"lm90",            0, 0x4c, 0, 0, 0},
> +};

- named initialisers, or even the I2C_BOARD_INFO()
- no need to have the fields initialiser with 0 after the address.
- spaces betwee { and }

>  config I2C_BLACKFIN_TWI
>  	tristate "Blackfin TWI I2C support"
>  	depends on BLACKFIN

> new file mode 100644
> index 0000000..ac3d989
> --- /dev/null
> +++ b/drivers/i2c/busses/i2c-xlr.c
> @@ -0,0 +1,335 @@
> +/*
> + * Copyright 2011, Netlogic Microsystems Inc.
> + * Copyright 2004, Matt Porter <mporter@kernel.crashing.org>
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2.  This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/init.h>
> +#include <linux/ioport.h>
> +#include <linux/delay.h>
> +#include <linux/errno.h>
> +#include <linux/i2c.h>
> +#include <linux/io.h>
> +#include <linux/platform_device.h>
> +#include <asm/netlogic/xlr/iomap.h>
> +
> +/* XLR I2C REGISTERS */
> +#define XLR_I2C_CFG		0x00
> +#define XLR_I2C_CLKDIV		0x01
> +#define XLR_I2C_DEVADDR		0x02
> +#define XLR_I2C_ADDR		0x03
> +#define XLR_I2C_DATAOUT		0x04
> +#define XLR_I2C_DATAIN		0x05
> +#define XLR_I2C_STATUS		0x06
> +#define XLR_I2C_STARTXFR	0x07
> +#define XLR_I2C_BYTECNT		0x08
> +#define XLR_I2C_HDSTATIM	0x09
> +
> +/* XLR I2C REGISTERS FLAGS */
> +#define XLR_I2C_BUS_BUSY	0x01
> +#define XLR_I2C_SDOEMPTY	0x02
> +#define XLR_I2C_RXRDY		0x04
> +#define XLR_I2C_ACK_ERR		0x08
> +#define XLR_I2C_ARB_STARTERR	0x30
> +
> +/* Register Programming Values!! Change as required */
> +#define XLR_I2C_CFG_ADDR	0xF8    /* 8-Bit dev Addr + POR Values */
> +#define XLR_I2C_CFG_NOADDR	0xFA    /* 8-Bit reg Addr + POR Values */
> +#define XLR_I2C_STARTXFR_ND	0x02    /* No data , only addr */
> +#define XLR_I2C_STARTXFR_RD	0x01    /* Read */
> +#define XLR_I2C_STARTXFR_WR	0x00    /* Write */
> +#define XLR_I2C_CLKDIV_DEF	0x14A   /* 0x00000052 */
> +#define XLR_I2C_HDSTATIM_DEF	0x107   /* 0x00000000 */
> +
> +struct xlr_i2c_private {
> +	struct i2c_adapter adap;
> +	u32 *iobase_i2c_regs;

this should at-least be __iomem attributed

> +};
> +static struct xlr_i2c_private  xlr_i2c_priv;
> +
> +u32 *get_i2c_base(unsigned short bus)
> +{
> +	nlm_reg_t *mmio = 0;
> +
> +	if (bus == 0)
> +		mmio = netlogic_io_mmio(NETLOGIC_IO_I2C_0_OFFSET);
> +	else
> +		mmio = netlogic_io_mmio(NETLOGIC_IO_I2C_1_OFFSET);
> +
> +	return (u32 *)mmio;
> +}

shouldn't this be in with the platform device?

> +static void xlr_i2c_write(u32 *iobase_i2c_regs, int reg, int val)
> +{
> +	netlogic_write_reg(iobase_i2c_regs, reg, val);
> +}

did you really need to wrapper these functions?

> +static u32 xlr_i2c_read(u32 *iobase_i2c_regs, int reg)
> +{
> +	u32 retVal = netlogic_read_reg(iobase_i2c_regs, reg);
> +	return retVal;
> +}
> +

> +		u16		addr,
> +		unsigned short	flags,
> +		char		read_write,
> +		u8		command,
> +		int		protocol,
> +		union i2c_smbus_data *data)
> +{
> +	struct xlr_i2c_private *priv = i2c_adap->algo_data;
> +	int err;
> +	int len;
> +
> +	switch (protocol) {
> +	case I2C_SMBUS_BYTE:
> +		if (read_write == I2C_SMBUS_READ)
> +			err = xlr_i2c_rx(priv, 1, &data->byte, addr, command);
> +		else
> +			err = xlr_i2c_tx(priv, 1, &data->byte, addr, command);
> +
> +		break;
> +	case I2C_SMBUS_BYTE_DATA:
> +		if (read_write == I2C_SMBUS_READ)
> +			err = xlr_i2c_rx(priv, 1, &data->byte, addr, command);
> +		else
> +			err = xlr_i2c_tx(priv, 1, &data->byte, addr, command);
> +		break;
> +
> +	case I2C_SMBUS_WORD_DATA:
> +	case I2C_SMBUS_PROC_CALL:
> +		if (read_write == I2C_SMBUS_READ)
> +			err = xlr_i2c_rx(priv, 2, (u8 *)&data->word,
> +					addr, command);
> +		else
> +			err = xlr_i2c_tx(priv, 2, (u8 *)&data->word,
> +					addr, command);
> +
> +		break;
> +	case I2C_FUNC_SMBUS_BLOCK_DATA:
> +	case I2C_SMBUS_I2C_BLOCK_DATA:
> +		len = (data->block[0] > I2C_SMBUS_BLOCK_MAX) ?
> +			I2C_SMBUS_BLOCK_MAX : data->block[0];
> +		if (read_write == I2C_SMBUS_READ)
> +			err = xlr_i2c_rx(priv, len, &data->block[1],
> +					addr, command);
> +		else
> +			err = xlr_i2c_tx(priv, len, &data->block[1],
> +					addr, command);
> +
> +		break;
> +	default:
> +		err = -1;
> +	}
> +	return err;
> +}

thought most of these case where handled by the core translating
them into the proper i2c messages?

> +
> +static u32 xlr_func(struct i2c_adapter *adap)
> +{
> +	/* We emulate SMBUS over I2C */
> +	return I2C_FUNC_SMBUS_EMUL;
> +}
> +
> +static struct i2c_algorithm xlr_i2c_algo = {
> +	.smbus_xfer	= smbus_xfer,
> +	.functionality	= xlr_func,
> +};
> +
> +int xlr_i2c_add_bus(struct xlr_i2c_private *priv)
> +{
> +	priv->adap.owner	= THIS_MODULE;
> +	priv->adap.algo_data	= priv;
> +	priv->adap.nr		= 1;
> +	priv->adap.algo		= &xlr_i2c_algo;
> +	priv->adap.class	= I2C_CLASS_HWMON | I2C_CLASS_SPD;
> +	snprintf(priv->adap.name, sizeof(priv->adap.name),
> +			"SMBus XLR I2C Adapter");
> +
> +	/* register new adapter to i2c module... */
> +	if (i2c_add_numbered_adapter(&priv->adap))
> +		return -1;
> +
> +	return 0;
> +}
> +
> +int xlr_i2c_del_bus(struct i2c_adapter *adap)
> +{
> +	return i2c_del_adapter(adap);
> +}
> +
> +static int __devinit xlr_i2c_probe(struct platform_device *pd)
> +{
> +	xlr_i2c_priv.iobase_i2c_regs = get_i2c_base(pd->id);
> +
> +	xlr_i2c_priv.adap.dev.parent = &pd->dev;
> +	if (xlr_i2c_add_bus(&xlr_i2c_priv) < 0) {
> +		dev_err(&xlr_i2c_priv.adap.dev, "Failed to add i2c bus\n");
> +		goto out;
> +	} else
> +		dev_info(&xlr_i2c_priv.adap.dev, "Added I2C Bus.\n");
> +
> +	return 0;
> +out:
> +	return -ENODEV;

-ENODEV will get ignored by the upper layer. Need to find a better
error code.

> +}

> +MODULE_AUTHOR("Netlogic Microsystems Inc.");
> +MODULE_DESCRIPTION("XLR I2C SMBus driver");
> +MODULE_LICENSE("GPL");

no module alias for the platform device?

> +module_init(xlr_i2c_init);
> +module_exit(xlr_i2c_exit);
> -- 
> 1.7.4.1
> --
> To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

From rvossen@broadcom.com Thu Jul 14 13:09:30 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 14 Jul 2011 13:09:34 +0200 (CEST)
Received: from mms2.broadcom.com ([216.31.210.18]:1855 "EHLO mms2.broadcom.com"
        rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org with ESMTP
        id S1491083Ab1GNLJa (ORCPT <rfc822;linux-mips@linux-mips.org>);
        Thu, 14 Jul 2011 13:09:30 +0200
Received: from [10.9.200.131] by mms2.broadcom.com with ESMTP (Broadcom
 SMTP Relay (Email Firewall v6.3.2)); Thu, 14 Jul 2011 04:13:38 -0700
X-Server-Uuid: D3C04415-6FA8-4F2C-93C1-920E106A2031
Received: from mail-irva-13.broadcom.com (10.11.16.103) by
 IRVEXCHHUB01.corp.ad.broadcom.com (10.9.200.131) with Microsoft SMTP
 Server id 8.2.247.2; Thu, 14 Jul 2011 04:08:46 -0700
Received: from mail-sj1-12.sj.broadcom.com (mail-sj1-12.sj.broadcom.com
 [10.17.16.106]) by mail-irva-13.broadcom.com (Postfix) with ESMTP id
 2CA1574D04; Thu, 14 Jul 2011 04:08:46 -0700 (PDT)
Received: from [10.176.68.26] (unknown [10.176.68.26]) by
 mail-sj1-12.sj.broadcom.com (Postfix) with ESMTP id EAFCC20501; Thu, 14
 Jul 2011 04:08:44 -0700 (PDT)
Message-ID: <4E1ECE3B.10308@broadcom.com>
Date:   Thu, 14 Jul 2011 13:08:43 +0200
From:   "Roland Vossen" <rvossen@broadcom.com>
Organization: Broadcom
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.17)
 Gecko/20110424 Thunderbird/3.1.10
MIME-Version: 1.0
To:     "Jonas Gorski" <jonas.gorski@gmail.com>
cc:     "Geert Uytterhoeven" <geert@linux-m68k.org>,
        "devel@linuxdriverproject.org" <devel@linuxdriverproject.org>,
        "linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
        linux-mips@linux-mips.org
Subject: Status of MIPS on 3.0.0-rc6 kernel
X-WSS-ID: 620010E85ZC697404-01-01
Content-Type: text/plain;
 charset=iso-8859-1;
 format=flowed
Content-Transfer-Encoding: 7bit
X-archive-position: 30620
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: rvossen@broadcom.com
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 10110
Content-Length: 378
Lines: 17

Hi Jonas,

The (defconfig) mips kernel fails to build, with the error message:

arch/mips/kernel/i8259.c:240: error: unknown field 'resume' specified in 
initializer

I read on https://lkml.org/lkml/2011/6/1/37 that Geert Uytterhoeven 
encountered the same issue on June 1st.

Do you know if there are still known problems building a 3.0.0-rc6 MIPS 
kernel ?

Thanks,

Roland.


From jonas.gorski@gmail.com Thu Jul 14 13:51:38 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 14 Jul 2011 13:51:45 +0200 (CEST)
Received: from mail-gw0-f49.google.com ([74.125.83.49]:37264 "EHLO
        mail-gw0-f49.google.com" rhost-flags-OK-OK-OK-OK)
        by eddie.linux-mips.org with ESMTP id S1491083Ab1GNLvi (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Thu, 14 Jul 2011 13:51:38 +0200
Received: by gwb1 with SMTP id 1so59996gwb.36
        for <linux-mips@linux-mips.org>; Thu, 14 Jul 2011 04:51:32 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=gmail.com; s=gamma;
        h=mime-version:in-reply-to:references:from:date:message-id:subject:to
         :cc:content-type;
        bh=ls9Cwy4exXxg+He/kKmswpQo6lfkP7VyxNryUzb+4Tg=;
        b=KTd2mpGrsvfAcXAOdzhhTy4ffcxLgJLL5tCqFTfU8I7WuJXVW9oEGKXApHmRRULATw
         FPudkmW0efWeTwuFwJyj6n6c+NG0svR/L88H9d0GcafY9C9Q/PKBWHCrrtWPhUIB+m4z
         IOfBA+ZLfTx0tK8FasOUdfWa1c1/S9PQXYLPY=
Received: by 10.150.47.42 with SMTP id u42mr2239270ybu.127.1310644292351; Thu,
 14 Jul 2011 04:51:32 -0700 (PDT)
MIME-Version: 1.0
Received: by 10.151.158.21 with HTTP; Thu, 14 Jul 2011 04:51:11 -0700 (PDT)
In-Reply-To: <4E1ECE3B.10308@broadcom.com>
References: <4E1ECE3B.10308@broadcom.com>
From:   Jonas Gorski <jonas.gorski@gmail.com>
Date:   Thu, 14 Jul 2011 13:51:11 +0200
Message-ID: <CAOiHx=kznEFL1BELeg2psg9yw+=-A5reunG0VYTu89DGKwrSzA@mail.gmail.com>
Subject: Re: Status of MIPS on 3.0.0-rc6 kernel
To:     Roland Vossen <rvossen@broadcom.com>
Cc:     Geert Uytterhoeven <geert@linux-m68k.org>,
        "devel@linuxdriverproject.org" <devel@linuxdriverproject.org>,
        "linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
        linux-mips@linux-mips.org, "Rafael J. Wysocki" <rjw@sisk.pl>
Content-Type: text/plain; charset=UTF-8
X-archive-position: 30621
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: jonas.gorski@gmail.com
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 10134
Content-Length: 939
Lines: 29

On 14 July 2011 13:08, Roland Vossen <rvossen@broadcom.com> wrote:
> Hi Jonas,
>
> The (defconfig) mips kernel fails to build, with the error message:
>
> arch/mips/kernel/i8259.c:240: error: unknown field 'resume' specified in
> initializer
>
> I read on https://lkml.org/lkml/2011/6/1/37 that Geert Uytterhoeven
> encountered the same issue on June 1st.
>
> Do you know if there are still known problems building a 3.0.0-rc6 MIPS
> kernel ?

You probably could have found that out yourself quite easily [1] ;-)

This is actually still a problem in rc7. Commit
2e711c04dbbf7a7732a3f7073b1fc285d12b369d ("PM: Remove sysdev suspend,
resume and shutdown operations") broke it.
It's probably easily fixable by just removing the offending
.resume/.shutdown lines (and their referenced functions), but I don't
know the code (or PM) enough to know if some replacement is missing
there.


Regards,
Jonas

[1] <https://lkml.org/lkml/2011/7/7/267>

From rjw@sisk.pl Thu Jul 14 21:50:42 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 14 Jul 2011 21:50:49 +0200 (CEST)
Received: from ogre.sisk.pl ([217.79.144.158]:54539 "EHLO ogre.sisk.pl"
        rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org with ESMTP
        id S1491198Ab1GNTum (ORCPT <rfc822;linux-mips@linux-mips.org>);
        Thu, 14 Jul 2011 21:50:42 +0200
Received: from localhost (localhost.localdomain [127.0.0.1])
        by ogre.sisk.pl (Postfix) with ESMTP id 41A871B0212;
        Thu, 14 Jul 2011 21:22:28 +0200 (CEST)
Received: from ogre.sisk.pl ([127.0.0.1])
 by localhost (ogre.sisk.pl [127.0.0.1]) (amavisd-new, port 10024) with ESMTP
 id 10637-09; Thu, 14 Jul 2011 21:22:05 +0200 (CEST)
Received: from ferrari.rjw.lan (220-bem-13.acn.waw.pl [82.210.184.220])
        (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits))
        (No client certificate requested)
        by ogre.sisk.pl (Postfix) with ESMTP id E53C91B0161;
        Thu, 14 Jul 2011 21:22:05 +0200 (CEST)
From:   "Rafael J. Wysocki" <rjw@sisk.pl>
To:     Jonas Gorski <jonas.gorski@gmail.com>
Subject: Re: Status of MIPS on 3.0.0-rc6 kernel
Date:   Thu, 14 Jul 2011 21:51:24 +0200
User-Agent: KMail/1.13.6 (Linux/3.0.0-rc7+; KDE/4.6.0; x86_64; ; )
Cc:     Roland Vossen <rvossen@broadcom.com>,
        Geert Uytterhoeven <geert@linux-m68k.org>,
        "devel@linuxdriverproject.org" <devel@linuxdriverproject.org>,
        "linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
        linux-mips@linux-mips.org
References: <4E1ECE3B.10308@broadcom.com> <CAOiHx=kznEFL1BELeg2psg9yw+=-A5reunG0VYTu89DGKwrSzA@mail.gmail.com>
In-Reply-To: <CAOiHx=kznEFL1BELeg2psg9yw+=-A5reunG0VYTu89DGKwrSzA@mail.gmail.com>
MIME-Version: 1.0
Content-Type: Text/Plain;
  charset="utf-8"
Content-Transfer-Encoding: 7bit
Message-Id: <201107142151.24763.rjw@sisk.pl>
X-Virus-Scanned: amavisd-new at ogre.sisk.pl using MkS_Vir for Linux
X-archive-position: 30622
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: rjw@sisk.pl
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 10432
Content-Length: 3174
Lines: 105

On Thursday, July 14, 2011, Jonas Gorski wrote:
> On 14 July 2011 13:08, Roland Vossen <rvossen@broadcom.com> wrote:
> > Hi Jonas,
> >
> > The (defconfig) mips kernel fails to build, with the error message:
> >
> > arch/mips/kernel/i8259.c:240: error: unknown field 'resume' specified in
> > initializer
> >
> > I read on https://lkml.org/lkml/2011/6/1/37 that Geert Uytterhoeven
> > encountered the same issue on June 1st.
> >
> > Do you know if there are still known problems building a 3.0.0-rc6 MIPS
> > kernel ?
> 
> You probably could have found that out yourself quite easily [1] ;-)
> 
> This is actually still a problem in rc7. Commit
> 2e711c04dbbf7a7732a3f7073b1fc285d12b369d ("PM: Remove sysdev suspend,
> resume and shutdown operations") broke it.
> It's probably easily fixable by just removing the offending
> .resume/.shutdown lines (and their referenced functions), but I don't
> know the code (or PM) enough to know if some replacement is missing
> there.

Please check if the appended patch helps.

Thanks,
Rafael

---
From: Rafael J. Wysocki <rjw@sisk.pl>
Subject: MIPS: Convert i8259.c to using syscore_ops

The code in arch/mips/kernel/i8259.c still hasn't been converted to
using struct syscore_ops instead of a sysdev for resume and shutdown.
As a result, this code doesn't build any more after suspend, resume
and shutdown callbacks have been removed from struct sysdev_class.
Fix this problem by converting i8259.c to using syscore_ops.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 arch/mips/kernel/i8259.c |   22 ++++++----------------
 1 file changed, 6 insertions(+), 16 deletions(-)

Index: linux-2.6/arch/mips/kernel/i8259.c
===================================================================
--- linux-2.6.orig/arch/mips/kernel/i8259.c
+++ linux-2.6/arch/mips/kernel/i8259.c
@@ -14,7 +14,7 @@
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/spinlock.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 #include <linux/irq.h>
 
 #include <asm/i8259.h>
@@ -215,14 +215,13 @@ spurious_8259A_irq:
 	}
 }
 
-static int i8259A_resume(struct sys_device *dev)
+static void i8259A_resume(void)
 {
 	if (i8259A_auto_eoi >= 0)
 		init_8259A(i8259A_auto_eoi);
-	return 0;
 }
 
-static int i8259A_shutdown(struct sys_device *dev)
+static void i8259A_shutdown(void)
 {
 	/* Put the i8259A into a quiescent state that
 	 * the kernel initialization code can get it
@@ -232,26 +231,17 @@ static int i8259A_shutdown(struct sys_de
 		outb(0xff, PIC_MASTER_IMR);	/* mask all of 8259A-1 */
 		outb(0xff, PIC_SLAVE_IMR);	/* mask all of 8259A-1 */
 	}
-	return 0;
 }
 
-static struct sysdev_class i8259_sysdev_class = {
-	.name = "i8259",
+static struct syscore_ops i8259_syscore_ops = {
 	.resume = i8259A_resume,
 	.shutdown = i8259A_shutdown,
 };
 
-static struct sys_device device_i8259A = {
-	.id	= 0,
-	.cls	= &i8259_sysdev_class,
-};
-
 static int __init i8259A_init_sysfs(void)
 {
-	int error = sysdev_class_register(&i8259_sysdev_class);
-	if (!error)
-		error = sysdev_register(&device_i8259A);
-	return error;
+	register_syscore_ops(&i8259_syscore_ops);
+	return 0;
 }
 
 device_initcall(i8259A_init_sysfs);

From hauke@hauke-m.de Thu Jul 14 22:37:37 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 14 Jul 2011 22:37:45 +0200 (CEST)
Received: from server19320154104.serverpool.info ([193.201.54.104]:46325 "EHLO
        hauke-m.de" rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org
        with ESMTP id S1491758Ab1GNUhh (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Thu, 14 Jul 2011 22:37:37 +0200
Received: from localhost (localhost [127.0.0.1])
        by hauke-m.de (Postfix) with ESMTP id 49AA68C62;
        Thu, 14 Jul 2011 22:37:36 +0200 (CEST)
X-Virus-Scanned: Debian amavisd-new at hauke-m.de 
Received: from hauke-m.de ([127.0.0.1])
        by localhost (hauke-m.de [127.0.0.1]) (amavisd-new, port 10024)
        with ESMTP id eJbT3rlTFUog; Thu, 14 Jul 2011 22:37:29 +0200 (CEST)
Received: from [192.168.0.152] (host-091-097-255-054.ewe-ip-backbone.de [91.97.255.54])
        by hauke-m.de (Postfix) with ESMTPSA id 0C7888C4F;
        Thu, 14 Jul 2011 22:37:27 +0200 (CEST)
Message-ID: <4E1F5386.8020808@hauke-m.de>
Date:   Thu, 14 Jul 2011 22:37:26 +0200
From:   Hauke Mehrtens <hauke@hauke-m.de>
User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.17) Gecko/20110516 Lightning/1.0b2 Thunderbird/3.1.10
MIME-Version: 1.0
To:     Jonas Gorski <jonas.gorski@gmail.com>
CC:     ralf@linux-mips.org, linux-wireless@vger.kernel.org,
        zajec5@gmail.com, linux-mips@linux-mips.org, mb@bu3sch.de,
        george@znau.edu.ua, arend@broadcom.com,
        b43-dev@lists.infradead.org, bernhardloos@googlemail.com,
        arnd@arndb.de, julian.calaby@gmail.com, sshtylyov@mvista.com
Subject: Re: [PATCH 04/11] bcma: add SOC bus
References: <1310209563-6405-1-git-send-email-hauke@hauke-m.de> <1310209563-6405-5-git-send-email-hauke@hauke-m.de> <CAOiHx=n+sFWJ1WOwt-DBDMTNhZEH95MxkxOR-sQsKK1HkmmR9g@mail.gmail.com>
In-Reply-To: <CAOiHx=n+sFWJ1WOwt-DBDMTNhZEH95MxkxOR-sQsKK1HkmmR9g@mail.gmail.com>
X-Enigmail-Version: 1.1.2
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 7bit
X-archive-position: 30623
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: hauke@hauke-m.de
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 10459
Content-Length: 11701
Lines: 364

Hi Jonas,


On 07/13/2011 09:36 PM, Jonas Gorski wrote:
> Hi,
> 
> some minor things I saw:
> 
> On 9 July 2011 13:05, Hauke Mehrtens <hauke@hauke-m.de> wrote:
>> This patch adds support for using bcma on a Broadcom SoC as the system
>> bus. An SoC like the bcm4716 could register this bus and use it to
>> searches for the bcma cores and register the devices on this bus.
>>
>> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
>> ---
>>  drivers/bcma/Kconfig          |    5 +
>>  drivers/bcma/Makefile         |    1 +
>>  drivers/bcma/host_soc.c       |  178 +++++++++++++++++++++++++++++++++++++++++
>>  drivers/bcma/main.c           |    1 +
>>  drivers/bcma/scan.c           |   24 +++++-
>>  include/linux/bcma/bcma.h     |    4 +
>>  include/linux/bcma/bcma_soc.h |   16 ++++
>>  7 files changed, 227 insertions(+), 2 deletions(-)
>>  create mode 100644 drivers/bcma/host_soc.c
>>  create mode 100644 include/linux/bcma/bcma_soc.h
>>
>> diff --git a/drivers/bcma/Kconfig b/drivers/bcma/Kconfig
>> index 353781b..8d82f42 100644
>> --- a/drivers/bcma/Kconfig
>> +++ b/drivers/bcma/Kconfig
>> @@ -22,6 +22,11 @@ config BCMA_HOST_PCI
>>        bool "Support for BCMA on PCI-host bus"
>>        depends on BCMA_HOST_PCI_POSSIBLE
>>
>> +config BCMA_HOST_SOC
>> +       bool
>> +       depends on BCMA && MIPS
>> +       default n
> 
> Default default is already "n", so this line is superfluous.

Will remove this.

> 
>> +
>>  config BCMA_DEBUG
>>        bool "BCMA debugging"
>>        depends on BCMA
>> diff --git a/drivers/bcma/Makefile b/drivers/bcma/Makefile
>> index 0d56245..42d61dd 100644
>> --- a/drivers/bcma/Makefile
>> +++ b/drivers/bcma/Makefile
>> @@ -2,6 +2,7 @@ bcma-y                                  += main.o scan.o core.o
>>  bcma-y                                 += driver_chipcommon.o driver_chipcommon_pmu.o
>>  bcma-y                                 += driver_pci.o
>>  bcma-$(CONFIG_BCMA_HOST_PCI)           += host_pci.o
>> +bcma-$(CONFIG_BCMA_HOST_SOC)           += host_soc.o
>>  obj-$(CONFIG_BCMA)                     += bcma.o
>>
>>  ccflags-$(CONFIG_BCMA_DEBUG)           := -DDEBUG
>> diff --git a/drivers/bcma/host_soc.c b/drivers/bcma/host_soc.c
>> new file mode 100644
>> index 0000000..a6fe724
>> --- /dev/null
>> +++ b/drivers/bcma/host_soc.c
>> @@ -0,0 +1,178 @@
>> +/*
>> + * Broadcom specific AMBA
>> + * System on Chip (SoC) Host
>> + *
>> + * Licensed under the GNU/GPL. See COPYING for details.
>> + */
>> +
>> +#include "bcma_private.h"
>> +#include "scan.h"
>> +#include <linux/bcma/bcma.h>
>> +#include <linux/bcma/bcma_soc.h>
>> +
>> +static u8 bcma_host_soc_read8(struct bcma_device *core, u16 offset)
>> +{
>> +       return readb(core->io_addr + offset);
>> +}
>> +
>> +static u16 bcma_host_soc_read16(struct bcma_device *core, u16 offset)
>> +{
>> +       return readw(core->io_addr + offset);
>> +}
>> +
>> +static u32 bcma_host_soc_read32(struct bcma_device *core, u16 offset)
>> +{
>> +       return readl(core->io_addr + offset);
>> +}
>> +
>> +static void bcma_host_soc_write8(struct bcma_device *core, u16 offset,
>> +                                u8 value)
>> +{
>> +       writeb(value, core->io_addr + offset);
>> +}
>> +
>> +static void bcma_host_soc_write16(struct bcma_device *core, u16 offset,
>> +                                u16 value)
>> +{
>> +       writew(value, core->io_addr + offset);
>> +}
>> +
>> +static void bcma_host_soc_write32(struct bcma_device *core, u16 offset,
>> +                                u32 value)
>> +{
>> +       writel(value, core->io_addr + offset);
>> +}
>> +
>> +#ifdef CONFIG_BCMA_BLOCKIO
>> +static void bcma_host_soc_block_read(struct bcma_device *core, void *buffer,
>> +                                    size_t count, u16 offset, u8 reg_width)
>> +{
>> +       void __iomem *addr = core->io_addr + offset;
>> +
>> +       switch (reg_width) {
>> +       case sizeof(u8): {
>> +               u8 *buf = buffer;
>> +
>> +               while (count) {
>> +                       *buf = __raw_readb(addr);
>> +                       buf++;
>> +                       count--;
>> +               }
>> +               break;
>> +       }
>> +       case sizeof(u16): {
>> +               __le16 *buf = buffer;
>> +
>> +               WARN_ON(count & 1);
>> +               while (count) {
>> +                       *buf = (__force __le16)__raw_readw(addr);
>> +                       buf++;
>> +                       count -= 2;
>> +               }
>> +               break;
>> +       }
>> +       case sizeof(u32): {
>> +               __le32 *buf = buffer;
>> +
>> +               WARN_ON(count & 3);
>> +               while (count) {
>> +                       *buf = (__force __le32)__raw_readl(addr);
>> +                       buf++;
>> +                       count -= 4;
>> +               }
>> +               break;
>> +       }
>> +       default:
>> +               WARN_ON(1);
>> +       }
>> +}
>> +
>> +static void bcma_host_soc_block_write(struct bcma_device *core,
>> +                                     const void *buffer,
>> +                                     size_t count, u16 offset, u8 reg_width)
>> +{
>> +       void __iomem *addr = core->io_addr + offset;
>> +
>> +       switch (reg_width) {
>> +       case sizeof(u8): {
>> +               const u8 *buf = buffer;
>> +
>> +               while (count) {
>> +                       __raw_writeb(*buf, addr);
>> +                       buf++;
>> +                       count--;
>> +               }
>> +               break;
>> +       }
>> +       case sizeof(u16): {
>> +               const __le16 *buf = buffer;
>> +
>> +               WARN_ON(count & 1);
>> +               while (count) {
>> +                       __raw_writew((__force u16)(*buf), addr);
>> +                       buf++;
>> +                       count -= 2;
>> +               }
>> +               break;
>> +       }
>> +       case sizeof(u32): {
>> +               const __le32 *buf = buffer;
>> +
>> +               WARN_ON(count & 3);
>> +               while (count) {
>> +                       __raw_writel((__force u32)(*buf), addr);
>> +                       buf++;
>> +                       count -= 4;
>> +               }
>> +               break;
>> +       }
>> +       default:
>> +               WARN_ON(1);
>> +       }
>> +}
>> +#endif /* CONFIG_BCMA_BLOCKIO */
>> +
>> +static u32 bcma_host_soc_aread32(struct bcma_device *core, u16 offset)
>> +{
>> +       return readl(core->io_wrap + offset);
>> +}
>> +
>> +static void bcma_host_soc_awrite32(struct bcma_device *core, u16 offset,
>> +                                 u32 value)
>> +{
>> +       writel(value, core->io_wrap + offset);
>> +}
>> +
>> +const struct bcma_host_ops bcma_host_soc_ops = {
>> +       .read8          = bcma_host_soc_read8,
>> +       .read16         = bcma_host_soc_read16,
>> +       .read32         = bcma_host_soc_read32,
>> +       .write8         = bcma_host_soc_write8,
>> +       .write16        = bcma_host_soc_write16,
>> +       .write32        = bcma_host_soc_write32,
>> +#ifdef CONFIG_BCMA_BLOCKIO
>> +       .block_read     = bcma_host_soc_block_read,
>> +       .block_write    = bcma_host_soc_block_write,
>> +#endif
>> +       .aread32        = bcma_host_soc_aread32,
>> +       .awrite32       = bcma_host_soc_awrite32,
>> +};
>> +
>> +int __init bcma_host_soc_register(struct bcma_soc *soc)
>> +{
>> +       struct bcma_bus *bus = &soc->bus;
>> +
>> +       /* iomap only first core. We have to read some register on this core
>> +        * to scan the bus.
>> +        */
>> +       bus->mmio = ioremap(BCMA_ADDR_BASE, BCMA_CORE_SIZE * 1);
>> +       if (!bus->mmio)
>> +               return -ENOMEM;
>> +
>> +       /* Host specific */
>> +       bus->hosttype = BCMA_HOSTTYPE_SOC;
>> +       bus->ops = &bcma_host_soc_ops;
>> +
>> +       /* Register */
>> +       return bcma_bus_early_register(bus, &soc->core_cc, &soc->core_mips);
>> +}
>> diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c
>> index e6c308c..2ca5eeb 100644
>> --- a/drivers/bcma/main.c
>> +++ b/drivers/bcma/main.c
>> @@ -92,6 +92,7 @@ static int bcma_register_cores(struct bcma_bus *bus)
>>                        break;
>>                case BCMA_HOSTTYPE_NONE:
>>                case BCMA_HOSTTYPE_SDIO:
>> +               case BCMA_HOSTTYPE_SOC:
>>                        break;
>>                }
>>
>> diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c
>> index bf9f806..202edc8 100644
>> --- a/drivers/bcma/scan.c
>> +++ b/drivers/bcma/scan.c
>> @@ -337,6 +337,14 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
>>                        }
>>                }
>>        }
>> +       if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
>> +               core->io_addr = ioremap(core->addr, BCMA_CORE_SIZE);
>> +               if (!core->io_addr)
>> +                       return -ENOMEM;
>> +               core->io_wrap = ioremap(core->wrap, BCMA_CORE_SIZE);
>> +               if (!core->io_wrap)
>> +                       return -ENOMEM;
> 
> Shouldn't you unmap core->io_addr if remapping io_wrap fails?

Ok I will add iounmap() on the error path and when the core is freed.
> 
>> +       }
>>        return 0;
>>  }
>>
>> @@ -369,7 +377,13 @@ int bcma_bus_scan(struct bcma_bus *bus)
>>        bcma_init_bus(bus);
>>
>>        erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
>> -       eromptr = bus->mmio;
>> +       if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
>> +               eromptr = ioremap(erombase, BCMA_CORE_SIZE);
>> +               if (!eromptr)
>> +                       return -ENOMEM;
>> +       } else
>> +               eromptr = bus->mmio;
> 
> Documentation/CodingStyle says use braces in both branches if one needs them.
Will fix this.
> 
>> +
>>        eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
>>
>>        bcma_scan_switch_core(bus, erombase);
>> @@ -417,7 +431,13 @@ int __init bcma_bus_scan_early(struct bcma_bus *bus,
>>        int err, core_num = 0;
>>
>>        erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
>> -       eromptr = bus->mmio;
>> +       if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
>> +               eromptr = ioremap(erombase, BCMA_CORE_SIZE);
>> +               if (!eromptr)
>> +                       return -ENOMEM;
>> +       } else
>> +               eromptr = bus->mmio;
> 
> Ditto.
> 
>> +
>>        eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
>>
>>        bcma_scan_switch_core(bus, erombase);
>> diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h
>> index 6bd7b7f..73fda1c 100644
>> --- a/include/linux/bcma/bcma.h
>> +++ b/include/linux/bcma/bcma.h
>> @@ -16,6 +16,7 @@ enum bcma_hosttype {
>>        BCMA_HOSTTYPE_NONE,
>>        BCMA_HOSTTYPE_PCI,
>>        BCMA_HOSTTYPE_SDIO,
>> +       BCMA_HOSTTYPE_SOC,
>>  };
>>
>>  struct bcma_chipinfo {
>> @@ -124,6 +125,9 @@ struct bcma_device {
>>        u32 addr;
>>        u32 wrap;
>>
>> +       void __iomem *io_addr;
>> +       void __iomem *io_wrap;
>> +
>>        void *drvdata;
>>        struct list_head list;
>>  };
>> diff --git a/include/linux/bcma/bcma_soc.h b/include/linux/bcma/bcma_soc.h
>> new file mode 100644
>> index 0000000..4203c55
>> --- /dev/null
>> +++ b/include/linux/bcma/bcma_soc.h
>> @@ -0,0 +1,16 @@
>> +#ifndef LINUX_BCMA_SOC_H_
>> +#define LINUX_BCMA_SOC_H_
>> +
>> +#include <linux/bcma/bcma.h>
>> +
>> +struct bcma_soc {
>> +       struct bcma_bus bus;
>> +       struct bcma_device core_cc;
>> +       struct bcma_device core_mips;
>> +};
>> +
>> +int __init bcma_host_soc_register(struct bcma_soc *soc);
>> +
>> +int bcma_bus_register(struct bcma_bus *bus);
>> +
>> +#endif /* LINUX_BCMA_SOC_H_ */
>> --
>> 1.7.4.1


From manuel.lauss@googlemail.com Fri Jul 15 13:41:30 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 15 Jul 2011 13:41:37 +0200 (CEST)
Received: from mail-fx0-f49.google.com ([209.85.161.49]:54536 "EHLO
        mail-fx0-f49.google.com" rhost-flags-OK-OK-OK-OK)
        by eddie.linux-mips.org with ESMTP id S1491805Ab1GOLla (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Fri, 15 Jul 2011 13:41:30 +0200
Received: by fxd20 with SMTP id 20so1823644fxd.36
        for <linux-mips@linux-mips.org>; Fri, 15 Jul 2011 04:41:25 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=googlemail.com; s=gamma;
        h=from:to:cc:subject:date:message-id:x-mailer;
        bh=cd4nQzv0O8ft5gUSBKxBrMs5c0IalUz4SLrOTr+7SAM=;
        b=HURw/1lriJrO02jIAlevsxPnoilwZiJDoolkWtR1AShVE1pmmL5hnrUsb2eBFYCcex
         HF3CNPc1+nryQkeY2U8nxqiVDxxSM7H3EPCRNshFBm/z6HO90UyB+Pj3jXUI7sDjyiQb
         YYyHilbQAsRZ80Wgx33U/ucy0aMv1vxZVAjBw=
Received: by 10.223.41.156 with SMTP id o28mr5270652fae.11.1310730084357;
        Fri, 15 Jul 2011 04:41:24 -0700 (PDT)
Received: from localhost.localdomain (178-191-8-8.adsl.highway.telekom.at [178.191.8.8])
        by mx.google.com with ESMTPS id q1sm794249faa.3.2011.07.15.04.41.22
        (version=TLSv1/SSLv3 cipher=OTHER);
        Fri, 15 Jul 2011 04:41:22 -0700 (PDT)
From:   Manuel Lauss <manuel.lauss@googlemail.com>
To:     Linux-MIPS <linux-mips@linux-mips.org>
Cc:     Manuel Lauss <manuel.lauss@googlemail.com>
Subject: [PATCH RFC V3 0/2] MIPS: Alchemy: Au1300 / DB1300 support
Date:   Fri, 15 Jul 2011 13:41:16 +0200
Message-Id: <1310730078-30265-1-git-send-email-manuel.lauss@googlemail.com>
X-Mailer: git-send-email 1.7.6
X-archive-position: 30624
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: manuel.lauss@googlemail.com
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 10919
Content-Length: 4234
Lines: 84

For posterity, here's a final, V3 dump of my Au1300/DB1300 support patches.

Changes since V2:
- removed the debug macros and cleaned the comments in new IRQ code,
- renamed the gpiolib hooks to something more sensible,
- merged the core DB1300 code into a single file.

Changes since V1:
- Au1300: simplified plat_irq_dispatch, made the assembly significantly smaller
- DB1300: now uses the bcsr irq dispatcher like the db1200, with a small
          modification.

What works:
- Au1300 integration, GPIO, IRQs
- Au1300 USB (EHCI, 2x OHCI).  OTG and UDC need drivers (Synopsys IP).
- I can play ScummVM under X with sound off a IDE HDD/CF card/NFS share with
  either USB mouse or the touchscreen and use it as a wireless access point.

These 2 patches depend on the "MIPS: Alchemy: misc updates" I sent on 2011-07-08,
as well as patches I sent to linux-fbdev and linux-i2c to work properly (esp.
wrt. the I2S codec).
The whole series is available at http://mlau.at/files/db1300-patches/ as well.

Code is run-tested on both Db1200 and Db1300, as well as compile-tested on
a small selection of other alchemy hardware.

Manuel Lauss (2):
  MIPS: Alchemy: Au1300 SoC support
  MIPS: Alchemy: DB1300 support

 arch/mips/alchemy/Kconfig                        |   16 +
 arch/mips/alchemy/Platform                       |    7 +
 arch/mips/alchemy/common/Makefile                |    4 +-
 arch/mips/alchemy/common/dbdma.c                 |   48 ++-
 arch/mips/alchemy/common/gpioint.c               |  411 ++++++++++++
 arch/mips/alchemy/common/gpiolib-au1300.c        |   54 ++
 arch/mips/alchemy/common/platform.c              |   31 +-
 arch/mips/alchemy/common/power.c                 |    3 +
 arch/mips/alchemy/common/sleeper.S               |   73 ++
 arch/mips/alchemy/common/time.c                  |    1 +
 arch/mips/alchemy/common/usb.c                   |  277 ++++++++
 arch/mips/alchemy/common/vss.c                   |   84 +++
 arch/mips/alchemy/devboards/Makefile             |    1 +
 arch/mips/alchemy/devboards/bcsr.c               |    4 +
 arch/mips/alchemy/devboards/db1300.c             |  767 ++++++++++++++++++++++
 arch/mips/alchemy/devboards/prom.c               |    4 +
 arch/mips/boot/compressed/uart-alchemy.c         |    5 +-
 arch/mips/configs/db1300_defconfig               |  391 +++++++++++
 arch/mips/include/asm/cpu.h                      |    1 +
 arch/mips/include/asm/mach-au1x00/au1000.h       |  223 ++++++-
 arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h |   33 +
 arch/mips/include/asm/mach-au1x00/gpio-au1300.h  |  250 +++++++
 arch/mips/include/asm/mach-au1x00/gpio.h         |    4 +
 arch/mips/include/asm/mach-db1x00/bcsr.h         |   34 +-
 arch/mips/include/asm/mach-db1x00/db1300.h       |   40 ++
 arch/mips/include/asm/mach-db1x00/irq.h          |   23 +
 arch/mips/kernel/cpu-probe.c                     |    7 +
 drivers/i2c/busses/Kconfig                       |    6 +-
 drivers/pcmcia/Kconfig                           |    4 +-
 drivers/pcmcia/db1xxx_ss.c                       |   26 +-
 drivers/spi/Kconfig                              |    6 +-
 drivers/usb/Kconfig                              |    2 +-
 drivers/usb/host/ehci-hcd.c                      |    2 +-
 drivers/usb/host/ohci-au1xxx.c                   |   13 +-
 drivers/video/Kconfig                            |   10 +-
 drivers/video/au1200fb.c                         |   36 +
 sound/soc/au1x/Kconfig                           |   18 +-
 sound/soc/au1x/Makefile                          |    2 +
 sound/soc/au1x/db1200.c                          |    4 +
 sound/soc/au1x/db1300.c                          |  147 +++++
 40 files changed, 3017 insertions(+), 55 deletions(-)
 create mode 100644 arch/mips/alchemy/common/gpioint.c
 create mode 100644 arch/mips/alchemy/common/gpiolib-au1300.c
 create mode 100644 arch/mips/alchemy/common/vss.c
 create mode 100644 arch/mips/alchemy/devboards/db1300.c
 create mode 100644 arch/mips/configs/db1300_defconfig
 create mode 100644 arch/mips/include/asm/mach-au1x00/gpio-au1300.h
 create mode 100644 arch/mips/include/asm/mach-db1x00/db1300.h
 create mode 100644 arch/mips/include/asm/mach-db1x00/irq.h
 create mode 100644 sound/soc/au1x/db1300.c

-- 
1.7.6


From manuel.lauss@googlemail.com Fri Jul 15 13:41:33 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 15 Jul 2011 13:42:16 +0200 (CEST)
Received: from mail-ey0-f177.google.com ([209.85.215.177]:49648 "EHLO
        mail-ey0-f177.google.com" rhost-flags-OK-OK-OK-OK)
        by eddie.linux-mips.org with ESMTP id S1491808Ab1GOLld (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Fri, 15 Jul 2011 13:41:33 +0200
Received: by eyh6 with SMTP id 6so733147eyh.36
        for <linux-mips@linux-mips.org>; Fri, 15 Jul 2011 04:41:27 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=googlemail.com; s=gamma;
        h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references;
        bh=HqyXfd35gNmwJ7kQy8BI/FArBMzUlaH9AMbShWHPuXw=;
        b=fkc5oGSBitS25dE+6xeSNuQqVK+EHh//BU2JiOJfB98NolVa93L9VlQPovxMnLL828
         ynlhmKLjpUA6lRdSVEEtidtHigjC2l0elAM3ipv9ab4LVr47JL7U5ZjCQyMBLChDRZVa
         smrzStjIj21vZLyHvc/ADZpzjAcz3h1SomoUY=
Received: by 10.204.23.208 with SMTP id s16mr1128099bkb.352.1310730087615;
        Fri, 15 Jul 2011 04:41:27 -0700 (PDT)
Received: from localhost.localdomain (178-191-8-8.adsl.highway.telekom.at [178.191.8.8])
        by mx.google.com with ESMTPS id q1sm794249faa.3.2011.07.15.04.41.24
        (version=TLSv1/SSLv3 cipher=OTHER);
        Fri, 15 Jul 2011 04:41:26 -0700 (PDT)
From:   Manuel Lauss <manuel.lauss@googlemail.com>
To:     Linux-MIPS <linux-mips@linux-mips.org>
Cc:     Manuel Lauss <manuel.lauss@googlemail.com>
Subject: [RFC PATCH V3 1/2] MIPS: Alchemy: Au1300 SoC support
Date:   Fri, 15 Jul 2011 13:41:17 +0200
Message-Id: <1310730078-30265-2-git-send-email-manuel.lauss@googlemail.com>
X-Mailer: git-send-email 1.7.6
In-Reply-To: <1310730078-30265-1-git-send-email-manuel.lauss@googlemail.com>
References: <1310730078-30265-1-git-send-email-manuel.lauss@googlemail.com>
X-archive-position: 30625
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: manuel.lauss@googlemail.com
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 10920
Content-Length: 64646
Lines: 2076

Add basic support for the Au1300 variant(s):
- New GPIO/Interrupt controller
- DBDMA ids
- USB setup
- enable various PSC drivers
- detection code.

Signed-off-by: Manuel Lauss <manuel.lauss@googlemail.com>
---
V3: removed debug code, tidied some comments, renamed gpiolib hook functions.
V2: simplified plat_irq_dispatch which made the assembly significantly smaller.

 arch/mips/alchemy/Kconfig                        |    8 +
 arch/mips/alchemy/common/Makefile                |    4 +-
 arch/mips/alchemy/common/dbdma.c                 |   48 +++-
 arch/mips/alchemy/common/gpioint.c               |  411 ++++++++++++++++++++++
 arch/mips/alchemy/common/gpiolib-au1300.c        |   54 +++
 arch/mips/alchemy/common/platform.c              |   31 ++-
 arch/mips/alchemy/common/power.c                 |    3 +
 arch/mips/alchemy/common/sleeper.S               |   73 ++++
 arch/mips/alchemy/common/time.c                  |    1 +
 arch/mips/alchemy/common/usb.c                   |  277 +++++++++++++++
 arch/mips/alchemy/common/vss.c                   |   84 +++++
 arch/mips/include/asm/cpu.h                      |    1 +
 arch/mips/include/asm/mach-au1x00/au1000.h       |  223 +++++++++++-
 arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h |   33 ++
 arch/mips/include/asm/mach-au1x00/gpio-au1300.h  |  250 +++++++++++++
 arch/mips/include/asm/mach-au1x00/gpio.h         |    4 +
 arch/mips/kernel/cpu-probe.c                     |    7 +
 drivers/i2c/busses/Kconfig                       |    6 +-
 drivers/spi/Kconfig                              |    6 +-
 drivers/usb/Kconfig                              |    2 +-
 drivers/usb/host/ehci-hcd.c                      |    2 +-
 drivers/usb/host/ohci-au1xxx.c                   |   13 +-
 drivers/video/Kconfig                            |   10 +-
 sound/soc/au1x/Kconfig                           |    6 +-
 24 files changed, 1516 insertions(+), 41 deletions(-)
 create mode 100644 arch/mips/alchemy/common/gpioint.c
 create mode 100644 arch/mips/alchemy/common/gpiolib-au1300.c
 create mode 100644 arch/mips/alchemy/common/vss.c
 create mode 100644 arch/mips/include/asm/mach-au1x00/gpio-au1300.h

diff --git a/arch/mips/alchemy/Kconfig b/arch/mips/alchemy/Kconfig
index 2ccfd4a..30277fd 100644
--- a/arch/mips/alchemy/Kconfig
+++ b/arch/mips/alchemy/Kconfig
@@ -2,6 +2,10 @@
 config ALCHEMY_GPIOINT_AU1000
 	bool
 
+# au1300-style GPIO/INT controller
+config ALCHEMY_GPIOINT_AU1300
+	bool
+
 # select this in your board config if you don't want to use the gpio
 # namespace as documented in the manuals.  In this case however you need
 # to create the necessary gpio_* functions in your board code/headers!
@@ -158,3 +162,7 @@ config SOC_AU1550
 config SOC_AU1200
 	bool
 	select ALCHEMY_GPIOINT_AU1000
+
+config SOC_AU1300
+	bool
+	select ALCHEMY_GPIOINT_AU1300
diff --git a/arch/mips/alchemy/common/Makefile b/arch/mips/alchemy/common/Makefile
index 575db47..39a2fd6 100644
--- a/arch/mips/alchemy/common/Makefile
+++ b/arch/mips/alchemy/common/Makefile
@@ -6,14 +6,16 @@
 #
 
 obj-y += prom.o time.o clocks.o platform.o power.o setup.o \
-	sleeper.o dma.o dbdma.o usb.o
+	sleeper.o dma.o dbdma.o usb.o vss.o
 
 obj-$(CONFIG_ALCHEMY_GPIOINT_AU1000) += irq.o
+obj-$(CONFIG_ALCHEMY_GPIOINT_AU1300) += gpioint.o
 
 # optional gpiolib support
 ifeq ($(CONFIG_ALCHEMY_GPIO_INDIRECT),)
  ifeq ($(CONFIG_GPIOLIB),y)
   obj-$(CONFIG_ALCHEMY_GPIOINT_AU1000) += gpiolib-au1000.o
+  obj-$(CONFIG_ALCHEMY_GPIOINT_AU1300) += gpiolib-au1300.o
  endif
 endif
 
diff --git a/arch/mips/alchemy/common/dbdma.c b/arch/mips/alchemy/common/dbdma.c
index 3a5abb5..83c02a2 100644
--- a/arch/mips/alchemy/common/dbdma.c
+++ b/arch/mips/alchemy/common/dbdma.c
@@ -40,8 +40,6 @@
 #include <asm/mach-au1x00/au1000.h>
 #include <asm/mach-au1x00/au1xxx_dbdma.h>
 
-#if defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200)
-
 /*
  * The Descriptor Based DMA supports up to 16 channels.
  *
@@ -152,6 +150,47 @@ static dbdev_tab_t dbdev_tab[] = {
 
 #endif /* CONFIG_SOC_AU1200 */
 
+#ifdef CONFIG_SOC_AU1300
+	{ DSCR_CMD0_UART0_TX, DEV_FLAGS_OUT, 0, 8,  0x10100004, 0, 0 },
+	{ DSCR_CMD0_UART0_RX, DEV_FLAGS_IN,  0, 8,  0x10100000, 0, 0 },
+	{ DSCR_CMD0_UART1_TX, DEV_FLAGS_OUT, 0, 8,  0x10101004, 0, 0 },
+	{ DSCR_CMD0_UART1_RX, DEV_FLAGS_IN,  0, 8,  0x10101000, 0, 0 },
+	{ DSCR_CMD0_UART2_TX, DEV_FLAGS_OUT, 0, 8,  0x10102004, 0, 0 },
+	{ DSCR_CMD0_UART2_RX, DEV_FLAGS_IN,  0, 8,  0x10102000, 0, 0 },
+	{ DSCR_CMD0_UART3_TX, DEV_FLAGS_OUT, 0, 8,  0x10103004, 0, 0 },
+	{ DSCR_CMD0_UART3_RX, DEV_FLAGS_IN,  0, 8,  0x10103000, 0, 0 },
+
+	{ DSCR_CMD0_SDMS_TX0, DEV_FLAGS_OUT, 4, 8,  0x10600000, 0, 0 },
+	{ DSCR_CMD0_SDMS_RX0, DEV_FLAGS_IN,  4, 8,  0x10600004, 0, 0 },
+	{ DSCR_CMD0_SDMS_TX1, DEV_FLAGS_OUT, 8, 8,  0x10601000, 0, 0 },
+	{ DSCR_CMD0_SDMS_RX1, DEV_FLAGS_IN,  8, 8,  0x10601004, 0, 0 },
+
+	{ DSCR_CMD0_AES_RX, DEV_FLAGS_IN ,   4, 32, 0x10300008, 0, 0 },
+	{ DSCR_CMD0_AES_TX, DEV_FLAGS_OUT,   4, 32, 0x10300004, 0, 0 },
+
+	{ DSCR_CMD0_PSC0_TX, DEV_FLAGS_OUT,  0, 16, 0x10a0001c, 0, 0 },
+	{ DSCR_CMD0_PSC0_RX, DEV_FLAGS_IN,   0, 16, 0x10a0001c, 0, 0 },
+	{ DSCR_CMD0_PSC1_TX, DEV_FLAGS_OUT,  0, 16, 0x10a0101c, 0, 0 },
+	{ DSCR_CMD0_PSC1_RX, DEV_FLAGS_IN,   0, 16, 0x10a0101c, 0, 0 },
+	{ DSCR_CMD0_PSC2_TX, DEV_FLAGS_OUT,  0, 16, 0x10a0201c, 0, 0 },
+	{ DSCR_CMD0_PSC2_RX, DEV_FLAGS_IN,   0, 16, 0x10a0201c, 0, 0 },
+	{ DSCR_CMD0_PSC3_TX, DEV_FLAGS_OUT,  0, 16, 0x10a0301c, 0, 0 },
+	{ DSCR_CMD0_PSC3_RX, DEV_FLAGS_IN,   0, 16, 0x10a0301c, 0, 0 },
+
+	{ DSCR_CMD0_LCD, DEV_FLAGS_ANYUSE,   0, 0,  0x00000000, 0, 0 },
+	{ DSCR_CMD0_NAND_FLASH, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 },
+
+	{ DSCR_CMD0_SDMS_TX2, DEV_FLAGS_OUT, 4, 8,  0x10602000, 0, 0 },
+	{ DSCR_CMD0_SDMS_RX2, DEV_FLAGS_IN,  4, 8,  0x10602004, 0, 0 },
+
+	{ DSCR_CMD0_CIM_SYNC, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
+
+	{ DSCR_CMD0_UDMA, DEV_FLAGS_ANYUSE,  0, 32, 0x14001810, 0, 0 },
+
+	{ DSCR_CMD0_DMA_REQ0, 0, 0, 0, 0x00000000, 0, 0 },
+	{ DSCR_CMD0_DMA_REQ1, 0, 0, 0, 0x00000000, 0, 0 },
+#endif /* CONFIG_SOC_AU1300 */
+
 	{ DSCR_CMD0_THROTTLE, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
 	{ DSCR_CMD0_ALWAYS, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
 
@@ -1044,6 +1083,9 @@ static int __init au1xxx_dbdma_init(void)
 	case ALCHEMY_CPU_AU1200:
 		irq_nr = AU1200_DDMA_INT;
 		break;
+	case ALCHEMY_CPU_AU1300:
+		irq_nr = AU1300_DDMA_INT;
+		break;
 	default:
 		return -ENODEV;
 	}
@@ -1061,5 +1103,3 @@ static int __init au1xxx_dbdma_init(void)
 	return ret;
 }
 subsys_initcall(au1xxx_dbdma_init);
-
-#endif /* defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200) */
diff --git a/arch/mips/alchemy/common/gpioint.c b/arch/mips/alchemy/common/gpioint.c
new file mode 100644
index 0000000..b8cd336
--- /dev/null
+++ b/arch/mips/alchemy/common/gpioint.c
@@ -0,0 +1,411 @@
+/*
+ * gpioint.c - Au1300 GPIO+Interrupt controller (I call it "GPIC") support.
+ *
+ * Copyright (c) 2009-2011 Manuel Lauss <manuel.lauss@googlemail.com>
+ *
+ * licensed under the GPLv2.
+ */
+
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/syscore_ops.h>
+#include <linux/types.h>
+
+#include <asm/irq_cpu.h>
+#include <asm/mach-au1x00/au1000.h>
+#include <asm/mach-au1x00/gpio-au1300.h>
+
+static int au1300_gpic_settype(struct irq_data *d, unsigned int type);
+
+/* setup for known onchip sources */
+struct gpic_devint_data {
+	int irq;	/* linux IRQ number */
+	int type;	/* IRQ_TYPE_ */
+	int prio;	/* irq priority, 0 highest, 3 lowest */
+	int internal;	/* internal source (no ext. pin)? */
+};
+
+static const struct gpic_devint_data au1300_devints[] __initdata = {
+	/* multifunction: gpio pin or device */
+	{ AU1300_UART1_INT,	 IRQ_TYPE_LEVEL_HIGH,	1, 0, },
+	{ AU1300_UART2_INT,	 IRQ_TYPE_LEVEL_HIGH,	1, 0, },
+	{ AU1300_UART3_INT,	 IRQ_TYPE_LEVEL_HIGH,	1, 0, },
+	{ AU1300_SD1_INT,	 IRQ_TYPE_LEVEL_HIGH,	1, 0, },
+	{ AU1300_SD2_INT,	 IRQ_TYPE_LEVEL_HIGH,	1, 0, },
+	{ AU1300_PSC0_INT,	 IRQ_TYPE_LEVEL_HIGH,	1, 0, },
+	{ AU1300_PSC1_INT,	 IRQ_TYPE_LEVEL_HIGH,	1, 0, },
+	{ AU1300_PSC2_INT,	 IRQ_TYPE_LEVEL_HIGH,	1, 0, },
+	{ AU1300_PSC3_INT,	 IRQ_TYPE_LEVEL_HIGH,	1, 0, },
+	{ AU1300_NAND_INT,	 IRQ_TYPE_LEVEL_HIGH,	1, 0, },
+	/* au1300 internal */
+	{ AU1300_DDMA_INT,	 IRQ_TYPE_LEVEL_HIGH,	1, 1, },
+	{ AU1300_MMU_INT,	 IRQ_TYPE_LEVEL_HIGH,	1, 1, },
+	{ AU1300_MPU_INT,	 IRQ_TYPE_LEVEL_HIGH,	1, 1, },
+	{ AU1300_GPU_INT,	 IRQ_TYPE_LEVEL_HIGH,	1, 1, },
+	{ AU1300_UDMA_INT,	 IRQ_TYPE_LEVEL_HIGH,	1, 1, },
+	{ AU1300_TOY_INT,	 IRQ_TYPE_EDGE_RISING,	1, 1, },
+	{ AU1300_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING,	1, 1, },
+	{ AU1300_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING,	1, 1, },
+	{ AU1300_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING,	1, 1, },
+	{ AU1300_RTC_INT,	 IRQ_TYPE_EDGE_RISING,	1, 1, },
+	{ AU1300_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING,	1, 1, },
+	{ AU1300_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING,	1, 1, },
+	{ AU1300_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING,	0, 1, },
+	{ AU1300_UART0_INT,	 IRQ_TYPE_LEVEL_HIGH,	1, 1, },
+	{ AU1300_SD0_INT,	 IRQ_TYPE_LEVEL_HIGH,	1, 1, },
+	{ AU1300_USB_INT,	 IRQ_TYPE_LEVEL_HIGH,	1, 1, },
+	{ AU1300_LCD_INT,	 IRQ_TYPE_LEVEL_HIGH,	1, 1, },
+	{ AU1300_BSA_INT,	 IRQ_TYPE_LEVEL_HIGH,	1, 1, },
+	{ AU1300_MPE_INT,	 IRQ_TYPE_EDGE_RISING,	1, 1, },
+	{ AU1300_ITE_INT,	 IRQ_TYPE_LEVEL_HIGH,	1, 1, },
+	{ AU1300_AES_INT,	 IRQ_TYPE_LEVEL_HIGH,	1, 1, },
+	{ AU1300_CIM_INT,	 IRQ_TYPE_LEVEL_HIGH,	1, 1, },
+	{ -1, },	/* terminator */
+};
+
+
+/*
+ * au1300_gpic_chgcfg - change PIN configuration.
+ * @gpio:	pin to change (0-based GPIO number from datasheet).
+ * @clr:	clear all bits set in 'clr'.
+ * @set:	set these bits.
+ *
+ * modifies a pins' configuration register, bits set in @clr will
+ * be cleared in the register, bits in @set will be set.
+ */
+static inline void au1300_gpic_chgcfg(unsigned int gpio,
+				      unsigned long clr,
+				      unsigned long set)
+{
+	void __iomem *r = AU1300_GPIC_ADDR;
+	unsigned long l;
+
+	r += gpio * 4;	/* offset into pin config array */
+	l = __raw_readl(r + AU1300_GPIC_PINCFG);
+	l &= ~clr;
+	l |= set;
+	__raw_writel(l, r + AU1300_GPIC_PINCFG);
+	wmb();
+}
+
+/*
+ * au1300_pinfunc_to_gpio - assign a pin as GPIO input (GPIO ctrl).
+ * @pin:	pin (0-based GPIO number from datasheet).
+ *
+ * Assigns a GPIO pin to the GPIO controller, so its level can either
+ * be read or set through the generic GPIO functions.
+ * If you need a GPOUT, use au1300_gpio_set_value(pin, 0/1).
+ * REVISIT: is this function really necessary?
+ */
+void au1300_pinfunc_to_gpio(enum au1300_multifunc_pins gpio)
+{
+	au1300_gpio_direction_input(gpio + AU1300_GPIO_BASE);
+}
+EXPORT_SYMBOL_GPL(au1300_pinfunc_to_gpio);
+
+/*
+ * au1300_pinfunc_to_dev - assign a pin to the device function.
+ * @pin:	pin (0-based GPIO number from datasheet).
+ *
+ * Assigns a GPIO pin to its associated device function; the pin will be
+ * driven by the device and not through GPIO functions.
+ */
+void au1300_pinfunc_to_dev(enum au1300_multifunc_pins gpio)
+{
+	void __iomem *r = AU1300_GPIC_ADDR;
+	unsigned long bit;
+
+	r += GPIC_GPIO_BANKOFF(gpio);
+	bit = GPIC_GPIO_TO_BIT(gpio);
+	__raw_writel(bit, r + AU1300_GPIC_DEVSEL);
+	wmb();
+}
+EXPORT_SYMBOL_GPL(au1300_pinfunc_to_dev);
+
+/*
+ * au1300_set_irq_priority -  set internal priority of IRQ.
+ * @irq:	irq to set priority (linux irq number).
+ * @p:		priority (0 = highest, 3 = lowest).
+ */
+void au1300_set_irq_priority(unsigned int irq, int p)
+{
+	irq -= ALCHEMY_GPIC_INT_BASE;
+	au1300_gpic_chgcfg(irq, GPIC_CFG_IL_MASK, GPIC_CFG_IL_SET(p));
+}
+EXPORT_SYMBOL_GPL(au1300_set_irq_priority);
+
+/*
+ * au1300_set_dbdma_gpio - assign a gpio to one of the DBDMA triggers.
+ * @dchan:	dbdma trigger select (0, 1).
+ * @gpio:	pin to assign as trigger.
+ *
+ * DBDMA controller has 2 external trigger sources; this function
+ * assigns a GPIO to the selected trigger.
+ */
+void au1300_set_dbdma_gpio(int dchan, unsigned int gpio)
+{
+	unsigned long r;
+
+	if ((dchan >= 0) && (dchan <= 1)) {
+		r = __raw_readl(AU1300_GPIC_ADDR + AU1300_GPIC_DMASEL);
+		r &= ~(0xff << (8 * dchan));
+		r |= (gpio & 0x7f) << (8 * dchan);
+		__raw_writel(r, AU1300_GPIC_ADDR + AU1300_GPIC_DMASEL);
+		wmb();
+	}
+}
+
+/**********************************************************************/
+
+static inline void gpic_pin_set_idlewake(unsigned int gpio, int allow)
+{
+	au1300_gpic_chgcfg(gpio, GPIC_CFG_IDLEWAKE,
+			   allow ? GPIC_CFG_IDLEWAKE : 0);
+}
+
+static void au1300_gpic_mask(struct irq_data *d)
+{
+	void __iomem *r = AU1300_GPIC_ADDR;
+	unsigned long bit, irq = d->irq;
+
+	irq -= ALCHEMY_GPIC_INT_BASE;
+	r += GPIC_GPIO_BANKOFF(irq);
+	bit = GPIC_GPIO_TO_BIT(irq);
+	__raw_writel(bit, r + AU1300_GPIC_IDIS);
+	wmb();
+
+	gpic_pin_set_idlewake(irq, 0);
+}
+
+static void au1300_gpic_unmask(struct irq_data *d)
+{
+	void __iomem *r = AU1300_GPIC_ADDR;
+	unsigned long bit, irq = d->irq;
+
+	irq -= ALCHEMY_GPIC_INT_BASE;
+
+	gpic_pin_set_idlewake(irq, 1);
+
+	r += GPIC_GPIO_BANKOFF(irq);
+	bit = GPIC_GPIO_TO_BIT(irq);
+	__raw_writel(bit, r + AU1300_GPIC_IEN);
+	wmb();
+}
+
+static void au1300_gpic_maskack(struct irq_data *d)
+{
+	void __iomem *r = AU1300_GPIC_ADDR;
+	unsigned long bit, irq = d->irq;
+
+	irq -= ALCHEMY_GPIC_INT_BASE;
+	r += GPIC_GPIO_BANKOFF(irq);
+	bit = GPIC_GPIO_TO_BIT(irq);
+	__raw_writel(bit, r + AU1300_GPIC_IPEND);	/* ack */
+	__raw_writel(bit, r + AU1300_GPIC_IDIS);	/* mask */
+	wmb();
+
+	gpic_pin_set_idlewake(irq, 0);
+}
+
+static void au1300_gpic_ack(struct irq_data *d)
+{
+	void __iomem *r = AU1300_GPIC_ADDR;
+	unsigned long bit, irq = d->irq;
+
+	irq -= ALCHEMY_GPIC_INT_BASE;
+	r += GPIC_GPIO_BANKOFF(irq);
+	bit = GPIC_GPIO_TO_BIT(irq);
+	__raw_writel(bit, r + AU1300_GPIC_IPEND);	/* ack */
+	wmb();
+}
+
+static struct irq_chip au1300_gpic = {
+	.name		= "GPIOINT",
+	.irq_ack	= au1300_gpic_ack,
+	.irq_mask	= au1300_gpic_mask,
+	.irq_mask_ack	= au1300_gpic_maskack,
+	.irq_unmask	= au1300_gpic_unmask,
+	.irq_set_type	= au1300_gpic_settype,
+};
+
+static int au1300_gpic_settype(struct irq_data *d, unsigned int type)
+{
+	unsigned long s;
+	unsigned char *name = NULL;
+	irq_flow_handler_t hdl = NULL;
+
+	switch (type) {
+	case IRQ_TYPE_LEVEL_HIGH:
+		s = GPIC_CFG_IC_LEVEL_HIGH;
+		name = "high";
+		hdl = handle_level_irq;
+		break;
+	case IRQ_TYPE_LEVEL_LOW:
+		s = GPIC_CFG_IC_LEVEL_LOW;
+		name = "low";
+		hdl = handle_level_irq;
+		break;
+	case IRQ_TYPE_EDGE_RISING:
+		s = GPIC_CFG_IC_EDGE_RISE;
+		name = "posedge";
+		hdl = handle_edge_irq;
+		break;
+	case IRQ_TYPE_EDGE_FALLING:
+		s = GPIC_CFG_IC_EDGE_FALL;
+		name = "negedge";
+		hdl = handle_edge_irq;
+		break;
+	case IRQ_TYPE_EDGE_BOTH:
+		s = GPIC_CFG_IC_EDGE_BOTH;
+		name = "bothedge";
+		hdl = handle_edge_irq;
+		break;
+	case IRQ_TYPE_NONE:
+		s = GPIC_CFG_IC_OFF;
+		name = "disabled";
+		hdl = handle_level_irq;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	__irq_set_chip_handler_name_locked(d->irq, &au1300_gpic, hdl, name);
+
+	au1300_gpic_chgcfg(d->irq - ALCHEMY_GPIC_INT_BASE, GPIC_CFG_IC_MASK, s);
+
+	return 0;
+}
+
+static void __init alchemy_gpic_init_irq(const struct gpic_devint_data *dints)
+{
+	int i;
+	void __iomem *bank_base;
+
+	mips_cpu_irq_init();
+
+	/* disable & ack all possible interrupt sources */
+	for (i = 0; i < 4; i++) {
+		bank_base = AU1300_GPIC_ADDR + (i * 4);
+		__raw_writel(~0UL, bank_base + AU1300_GPIC_IDIS);
+		wmb();
+		__raw_writel(~0UL, bank_base + AU1300_GPIC_IPEND);
+		wmb();
+	}
+
+	/* register an irq_chip for them, with 2nd highest priority */
+	for (i = ALCHEMY_GPIC_INT_BASE; i <= ALCHEMY_GPIC_INT_LAST; i++) {
+		au1300_set_irq_priority(i, 1);
+		au1300_gpic_settype(irq_get_irq_data(i), IRQ_TYPE_NONE);
+	}
+
+	/* setup known on-chip sources */
+	while ((i = dints->irq) != -1) {
+		au1300_gpic_settype(irq_get_irq_data(i), dints->type);
+		au1300_set_irq_priority(i, dints->prio);
+
+		if (dints->internal)
+			au1300_pinfunc_to_dev(i - ALCHEMY_GPIC_INT_BASE);
+
+		dints++;
+	}
+
+	set_c0_status(IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3);
+}
+
+static unsigned long alchemy_gpic_pmdata[ALCHEMY_GPIC_INT_NUM + 6];
+
+static int alchemy_gpic_suspend(void)
+{
+	void __iomem *base = (void __iomem *)KSEG1ADDR(AU1300_GPIC_PHYS_ADDR);
+	int i;
+
+	/* save 4 interrupt mask status registers */
+	alchemy_gpic_pmdata[0] = __raw_readl(base + AU1300_GPIC_IEN + 0x0);
+	alchemy_gpic_pmdata[1] = __raw_readl(base + AU1300_GPIC_IEN + 0x4);
+	alchemy_gpic_pmdata[2] = __raw_readl(base + AU1300_GPIC_IEN + 0x8);
+	alchemy_gpic_pmdata[3] = __raw_readl(base + AU1300_GPIC_IEN + 0xc);
+
+	/* save misc register(s) */
+	alchemy_gpic_pmdata[4] = __raw_readl(base + AU1300_GPIC_DMASEL);
+
+	/* molto silenzioso */
+	__raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0x0);
+	__raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0x4);
+	__raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0x8);
+	__raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0xc);
+	wmb();
+
+	/* save pin/int-type configuration */
+	base += AU1300_GPIC_PINCFG;
+	for (i = 0; i < ALCHEMY_GPIC_INT_NUM; i++)
+		alchemy_gpic_pmdata[i + 5] = __raw_readl(base + (i << 2));
+
+	wmb();
+
+	return 0;
+}
+
+static void alchemy_gpic_resume(void)
+{
+	void __iomem *base = (void __iomem *)KSEG1ADDR(AU1300_GPIC_PHYS_ADDR);
+	int i;
+
+	/* disable all first */
+	__raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0x0);
+	__raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0x4);
+	__raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0x8);
+	__raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0xc);
+	wmb();
+
+	/* restore pin/int-type configurations */
+	base += AU1300_GPIC_PINCFG;
+	for (i = 0; i < ALCHEMY_GPIC_INT_NUM; i++)
+		__raw_writel(alchemy_gpic_pmdata[i + 5], base + (i << 2));
+	wmb();
+
+	/* restore misc register(s) */
+	base = (void __iomem *)KSEG1ADDR(AU1300_GPIC_PHYS_ADDR);
+	__raw_writel(alchemy_gpic_pmdata[4], base + AU1300_GPIC_DMASEL);
+	wmb();
+
+	/* finally restore masks */
+	__raw_writel(alchemy_gpic_pmdata[0], base + AU1300_GPIC_IEN + 0x0);
+	__raw_writel(alchemy_gpic_pmdata[1], base + AU1300_GPIC_IEN + 0x4);
+	__raw_writel(alchemy_gpic_pmdata[2], base + AU1300_GPIC_IEN + 0x8);
+	__raw_writel(alchemy_gpic_pmdata[3], base + AU1300_GPIC_IEN + 0xc);
+	wmb();
+}
+
+static struct syscore_ops alchemy_gpic_pmops = {
+	.suspend	= alchemy_gpic_suspend,
+	.resume		= alchemy_gpic_resume,
+};
+
+/**********************************************************************/
+
+void __init arch_init_irq(void)
+{
+	switch (alchemy_get_cputype()) {
+	case ALCHEMY_CPU_AU1300:
+		alchemy_gpic_init_irq(&au1300_devints[0]);
+		register_syscore_ops(&alchemy_gpic_pmops);
+		break;
+	}
+}
+
+#define CAUSEF_GPIC (CAUSEF_IP2 | CAUSEF_IP3 | CAUSEF_IP4 | CAUSEF_IP5)
+
+void plat_irq_dispatch(void)
+{
+	unsigned long i, c = read_c0_cause() & read_c0_status();
+
+	if (c & CAUSEF_IP7)				/* c0 timer */
+		do_IRQ(MIPS_CPU_IRQ_BASE + 7);
+	else if (likely(c & CAUSEF_GPIC)) {
+		i = __raw_readl(AU1300_GPIC_ADDR + AU1300_GPIC_PRIENC);
+		do_IRQ(i + ALCHEMY_GPIC_INT_BASE);
+	} else
+		spurious_interrupt();
+}
diff --git a/arch/mips/alchemy/common/gpiolib-au1300.c b/arch/mips/alchemy/common/gpiolib-au1300.c
new file mode 100644
index 0000000..afccd03
--- /dev/null
+++ b/arch/mips/alchemy/common/gpiolib-au1300.c
@@ -0,0 +1,54 @@
+/*
+ * Au1300-style GPIO/INT Controller GPIOLIB support
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/gpio.h>
+
+#include <asm/mach-au1x00/gpio-au1300.h>
+
+static int alchemy_gpic_get(struct gpio_chip *chip, unsigned int off)
+{
+	return au1300_gpio_get_value(off + AU1300_GPIO_BASE);
+}
+
+static void alchemy_gpic_set(struct gpio_chip *chip, unsigned int off, int v)
+{
+	au1300_gpio_set_value(off + AU1300_GPIO_BASE, v);
+}
+
+static int alchemy_gpic_dir_input(struct gpio_chip *chip, unsigned int off)
+{
+	return au1300_gpio_direction_input(off + AU1300_GPIO_BASE);
+}
+
+static int alchemy_gpic_dir_output(struct gpio_chip *chip, unsigned int off,
+				   int v)
+{
+	return au1300_gpio_direction_output(off + AU1300_GPIO_BASE, v);
+}
+
+static int alchemy_gpic_gpio_to_irq(struct gpio_chip *chip, unsigned int off)
+{
+	return au1300_gpio_to_irq(off + AU1300_GPIO_BASE);
+}
+
+static struct gpio_chip au1300_gpiochip = {
+	.label			= "au1300",
+	.direction_input	= alchemy_gpic_dir_input,
+	.direction_output	= alchemy_gpic_dir_output,
+	.get			= alchemy_gpic_get,
+	.set			= alchemy_gpic_set,
+	.to_irq			= alchemy_gpic_gpio_to_irq,
+	.base			= AU1300_GPIO_BASE,
+	.ngpio			= AU1300_GPIO_NUM,
+};
+
+static int __init au1300_gpiochip_init(void)
+{
+	return gpiochip_add(&au1300_gpiochip);
+}
+arch_initcall(au1300_gpiochip_init);
diff --git a/arch/mips/alchemy/common/platform.c b/arch/mips/alchemy/common/platform.c
index a5b37b3..932f697 100644
--- a/arch/mips/alchemy/common/platform.c
+++ b/arch/mips/alchemy/common/platform.c
@@ -82,6 +82,12 @@ static struct plat_serial8250_port au1x00_uart_data[][4] __initdata = {
 		PORT(AU1000_UART0_PHYS_ADDR, AU1200_UART0_INT),
 		PORT(AU1000_UART1_PHYS_ADDR, AU1200_UART1_INT),
 	},
+	[ALCHEMY_CPU_AU1300] = {
+		PORT(AU1300_UART0_PHYS_ADDR, AU1300_UART0_INT),
+		PORT(AU1300_UART1_PHYS_ADDR, AU1300_UART1_INT),
+		PORT(AU1300_UART2_PHYS_ADDR, AU1300_UART2_INT),
+		PORT(AU1300_UART3_PHYS_ADDR, AU1300_UART3_INT),
+	},
 };
 
 static struct platform_device au1xx0_uart_device = {
@@ -122,10 +128,12 @@ static unsigned long alchemy_ohci_data[][2] __initdata = {
 	[ALCHEMY_CPU_AU1100] = { AU1000_USB_OHCI_PHYS_ADDR, AU1100_USB_HOST_INT },
 	[ALCHEMY_CPU_AU1550] = { AU1550_USB_OHCI_PHYS_ADDR, AU1550_USB_HOST_INT },
 	[ALCHEMY_CPU_AU1200] = { AU1200_USB_OHCI_PHYS_ADDR, AU1200_USB_INT },
+	[ALCHEMY_CPU_AU1300] = { AU1300_USB_OHCI0_PHYS_ADDR, AU1300_USB_INT },
 };
 
 static unsigned long alchemy_ehci_data[][2] __initdata = {
 	[ALCHEMY_CPU_AU1200] = { AU1200_USB_EHCI_PHYS_ADDR, AU1200_USB_INT },
+	[ALCHEMY_CPU_AU1300] = { AU1300_USB_EHCI_PHYS_ADDR, AU1300_USB_INT },
 };
 
 static int __init _new_usbres(struct resource **r, struct platform_device **d)
@@ -169,8 +177,8 @@ static void __init alchemy_setup_usb(int ctype)
 		printk(KERN_INFO "Alchemy USB: cannot add OHCI0\n");
 
 
-	/* setup EHCI0: Au1200 */
-	if (ctype == ALCHEMY_CPU_AU1200) {
+	/* setup EHCI0: Au1200/Au1300 */
+	if ((ctype == ALCHEMY_CPU_AU1200) || (ctype == ALCHEMY_CPU_AU1300)) {
 		if (_new_usbres(&res, &pdev))
 			return;
 
@@ -187,6 +195,25 @@ static void __init alchemy_setup_usb(int ctype)
 		if (platform_device_register(pdev))
 			printk(KERN_INFO "Alchemy USB: cannot add EHCI0\n");
 	}
+
+	/* Au1300: OHCI1 */
+	if (ctype == ALCHEMY_CPU_AU1300) {
+		if (_new_usbres(&res, &pdev))
+			return;
+
+		res[0].start = AU1300_USB_OHCI1_PHYS_ADDR;
+		res[0].end = res[0].start + 0x100 - 1;
+		res[0].flags = IORESOURCE_MEM;
+		res[1].start = AU1300_USB_INT;
+		res[1].end = res[1].start;
+		res[1].flags = IORESOURCE_IRQ;
+		pdev->name = "au1xxx-ohci";
+		pdev->id = 1;
+		pdev->dev.dma_mask = &alchemy_ohci_dmamask;
+
+		if (platform_device_register(pdev))
+			printk(KERN_INFO "Alchemy USB: cannot add OHCI1\n");
+	}
 }
 
 /*** AU1100 LCD controller ***/
diff --git a/arch/mips/alchemy/common/power.c b/arch/mips/alchemy/common/power.c
index e53b4ce..1b9bbb8 100644
--- a/arch/mips/alchemy/common/power.c
+++ b/arch/mips/alchemy/common/power.c
@@ -128,6 +128,9 @@ void au_sleep(void)
 	case ALCHEMY_CPU_AU1200:
 		alchemy_sleep_au1550();
 		break;
+	case ALCHEMY_CPU_AU1300:
+		alchemy_sleep_au1300();
+		break;
 	}
 
 	restore_core_regs();
diff --git a/arch/mips/alchemy/common/sleeper.S b/arch/mips/alchemy/common/sleeper.S
index 77f3c74..c7bcc7e 100644
--- a/arch/mips/alchemy/common/sleeper.S
+++ b/arch/mips/alchemy/common/sleeper.S
@@ -153,6 +153,79 @@ LEAF(alchemy_sleep_au1550)
 
 END(alchemy_sleep_au1550)
 
+/* sleepcode for Au1300 memory controller type */
+LEAF(alchemy_sleep_au1300)
+
+	SETUP_SLEEP
+
+	/* cache following instructions, as memory gets put to sleep */
+	la	t0, 2f
+	la	t1, 4f
+	subu	t2, t1, t0
+
+	.set	mips3
+
+1:	cache	0x14, 0(t0)
+	subu	t2, t2, 32
+	bgez	t2, 1b
+	 addu	t0, t0, 32
+
+	.set	mips0
+
+2:	lui	a0, 0xb400		/* mem_xxx */
+
+	/* disable all ports in mem_sdportcfga */
+	sw	zero, 0x868(a0)		/* mem_sdportcfga */
+	sync
+
+	/* disable ODT */
+	li	t0, 0x03010000
+	sw	t0, 0x08d8(a0)		/* mem_sdcmd0 */
+	sw	t0, 0x08dc(a0)		/* mem_sdcmd1 */
+	sync
+
+	/* precharge */
+	li	t0, 0x23000400
+	sw	t0, 0x08dc(a0)		/* mem_sdcmd1 */
+	sw	t0, 0x08d8(a0)		/* mem_sdcmd0 */
+	sync
+
+	/* auto refresh */
+	sw	zero, 0x08c8(a0)	/* mem_sdautoref */
+	sync
+
+	/* block access to the DDR */
+	lw	t0, 0x0848(a0)		/* mem_sdconfigb */
+	li	t1, (1 << 7 | 0x3F)
+	or	t0, t0, t1
+	sw	t0, 0x0848(a0)		/* mem_sdconfigb */
+	sync
+
+	/* issue the Self Refresh command */
+	li	t0, 0x10000000
+	sw	t0, 0x08dc(a0)		/* mem_sdcmd1 */
+	sw	t0, 0x08d8(a0)		/* mem_sdcmd0 */
+	sync
+
+	/* wait for sdram to enter self-refresh mode */
+	lui	t0, 0x0300
+3:	lw	t1, 0x0850(a0)		/* mem_sdstat */
+	and	t2, t1, t0
+	bne	t2, t0, 3b
+	 nop
+
+	/* disable SDRAM clocks */
+	li	t0, ~(3<<28)
+	lw	t1, 0x0840(a0)		/* mem_sdconfiga */
+	and	t1, t1, t0		/* clear CE[1:0] */
+	sw	t1, 0x0840(a0)		/* mem_sdconfiga */
+	sync
+
+	DO_SLEEP
+4:
+
+END(alchemy_sleep_au1300)
+
 
 	/* This is where we return upon wakeup.
 	 * Reload all of the registers and return.
diff --git a/arch/mips/alchemy/common/time.c b/arch/mips/alchemy/common/time.c
index d5da6ad..a594a85 100644
--- a/arch/mips/alchemy/common/time.c
+++ b/arch/mips/alchemy/common/time.c
@@ -178,6 +178,7 @@ static int alchemy_m2inttab[] __initdata = {
 	AU1100_RTC_MATCH2_INT,
 	AU1550_RTC_MATCH2_INT,
 	AU1200_RTC_MATCH2_INT,
+	AU1300_RTC_MATCH2_INT,
 };
 
 void __init plat_time_init(void)
diff --git a/arch/mips/alchemy/common/usb.c b/arch/mips/alchemy/common/usb.c
index f769364..0852a07 100644
--- a/arch/mips/alchemy/common/usb.c
+++ b/arch/mips/alchemy/common/usb.c
@@ -52,9 +52,263 @@
 				 USBCFG_EBE | USBCFG_EME | USBCFG_OBE |	       \
 				 USBCFG_OME)
 
+/* Au1300 USB config registers */
+#define USB_DWC_CTRL1		0x00
+#define USB_DWC_CTRL2		0x04
+#define USB_VBUS_TIMER		0x10
+#define USB_SBUS_CTRL		0x14
+#define USB_MSR_ERR		0x18
+#define USB_DWC_CTRL3		0x1C
+#define USB_DWC_CTRL4		0x20
+#define USB_OTG_STATUS		0x28
+#define USB_DWC_CTRL5		0x2C
+#define USB_DWC_CTRL6		0x30
+#define USB_DWC_CTRL7		0x34
+#define USB_PHY_STATUS		0xC0
+#define USB_INT_STATUS		0xC4
+#define USB_INT_ENABLE		0xC8
+
+#define USB_DWC_CTRL1_OTGD	0x04 /* set to DISable OTG */
+#define USB_DWC_CTRL1_HSTRS	0x02 /* set to ENable EHCI */
+#define USB_DWC_CTRL1_DCRS	0x01 /* set to ENable UDC */
+
+#define USB_DWC_CTRL2_PHY1RS	0x04 /* set to enable PHY1 */
+#define USB_DWC_CTRL2_PHY0RS	0x02 /* set to enable PHY0 */
+#define USB_DWC_CTRL2_PHYRS	0x01 /* set to enable PHY */
+
+#define USB_DWC_CTRL3_OHCI1_CKEN	(1 << 19)
+#define USB_DWC_CTRL3_OHCI0_CKEN	(1 << 18)
+#define USB_DWC_CTRL3_EHCI0_CKEN	(1 << 17)
+#define USB_DWC_CTRL3_OTG0_CKEN		(1 << 16)
+
+#define USB_SBUS_CTRL_SBCA		0x04 /* coherent access */
+
+#define USB_INTEN_FORCE			0x20
+#define USB_INTEN_PHY			0x10
+#define USB_INTEN_UDC			0x08
+#define USB_INTEN_EHCI			0x04
+#define USB_INTEN_OHCI1			0x02
+#define USB_INTEN_OHCI0			0x01
 
 static DEFINE_SPINLOCK(alchemy_usb_lock);
 
+static inline void __au1300_usb_phyctl(void __iomem *base, int enable)
+{
+	unsigned long r, s;
+
+	r = __raw_readl(base + USB_DWC_CTRL2);
+	s = __raw_readl(base + USB_DWC_CTRL3);
+
+	s &= USB_DWC_CTRL3_OHCI1_CKEN | USB_DWC_CTRL3_OHCI0_CKEN |
+		USB_DWC_CTRL3_EHCI0_CKEN | USB_DWC_CTRL3_OTG0_CKEN;
+
+	if (enable) {
+		/* simply enable all PHYs */
+		r |= USB_DWC_CTRL2_PHY1RS | USB_DWC_CTRL2_PHY0RS |
+		     USB_DWC_CTRL2_PHYRS;
+		__raw_writel(r, base + USB_DWC_CTRL2);
+		wmb();
+	} else if (!s) {
+		/* no USB block active, do disable all PHYs */
+		r &= ~(USB_DWC_CTRL2_PHY1RS | USB_DWC_CTRL2_PHY0RS |
+		       USB_DWC_CTRL2_PHYRS);
+		__raw_writel(r, base + USB_DWC_CTRL2);
+		wmb();
+	}
+}
+
+static inline void __au1300_ohci_control(void __iomem *base, int enable, int id)
+{
+	unsigned long r;
+
+	if (enable) {
+		__raw_writel(1, base + USB_DWC_CTRL7);  /* start OHCI clock */
+		wmb();
+
+		r = __raw_readl(base + USB_DWC_CTRL3);	/* enable OHCI block */
+		r |= (id == 0) ? USB_DWC_CTRL3_OHCI0_CKEN
+			       : USB_DWC_CTRL3_OHCI1_CKEN;
+		__raw_writel(r, base + USB_DWC_CTRL3);
+		wmb();
+
+		__au1300_usb_phyctl(base, enable);	/* power up the PHYs */
+
+		r = __raw_readl(base + USB_INT_ENABLE);
+		r |= (id == 0) ? USB_INTEN_OHCI0 : USB_INTEN_OHCI1;
+		__raw_writel(r, base + USB_INT_ENABLE);
+		wmb();
+
+		/* reset the OHCI start clock bit */
+		__raw_writel(0, base + USB_DWC_CTRL7);
+		wmb();
+	} else {
+		r = __raw_readl(base + USB_INT_ENABLE);
+		r &= ~((id == 0) ? USB_INTEN_OHCI0 : USB_INTEN_OHCI1);
+		__raw_writel(r, base + USB_INT_ENABLE);
+		wmb();
+
+		r = __raw_readl(base + USB_DWC_CTRL3);
+		r &= ~((id == 0) ? USB_DWC_CTRL3_OHCI0_CKEN
+				 : USB_DWC_CTRL3_OHCI1_CKEN);
+		__raw_writel(r, base + USB_DWC_CTRL3);
+		wmb();
+
+		__au1300_usb_phyctl(base, enable);
+	}
+}
+
+static inline void __au1300_ehci_control(void __iomem *base, int enable)
+{
+	unsigned long r;
+
+	if (enable) {
+		r = __raw_readl(base + USB_DWC_CTRL3);
+		r |= USB_DWC_CTRL3_EHCI0_CKEN;
+		__raw_writel(r, base + USB_DWC_CTRL3);
+		wmb();
+
+		r = __raw_readl(base + USB_DWC_CTRL1);
+		r |= USB_DWC_CTRL1_HSTRS;
+		__raw_writel(r, base + USB_DWC_CTRL1);
+		wmb();
+
+		__au1300_usb_phyctl(base, enable);
+
+		r = __raw_readl(base + USB_INT_ENABLE);
+		r |= USB_INTEN_EHCI;
+		__raw_writel(r, base + USB_INT_ENABLE);
+		wmb();
+	} else {
+		r = __raw_readl(base + USB_INT_ENABLE);
+		r &= ~USB_INTEN_EHCI;
+		__raw_writel(r, base + USB_INT_ENABLE);
+		wmb();
+
+		r = __raw_readl(base + USB_DWC_CTRL1);
+		r &= ~USB_DWC_CTRL1_HSTRS;
+		__raw_writel(r, base + USB_DWC_CTRL1);
+		wmb();
+
+		r = __raw_readl(base + USB_DWC_CTRL3);
+		r &= ~USB_DWC_CTRL3_EHCI0_CKEN;
+		__raw_writel(r, base + USB_DWC_CTRL3);
+		wmb();
+
+		__au1300_usb_phyctl(base, enable);
+	}
+}
+
+static inline void __au1300_udc_control(void __iomem *base, int enable)
+{
+	unsigned long r;
+
+	if (enable) {
+		r = __raw_readl(base + USB_DWC_CTRL1);
+		r |= USB_DWC_CTRL1_DCRS;
+		__raw_writel(r, base + USB_DWC_CTRL1);
+		wmb();
+
+		__au1300_usb_phyctl(base, enable);
+
+		r = __raw_readl(base + USB_INT_ENABLE);
+		r |= USB_INTEN_UDC;
+		__raw_writel(r, base + USB_INT_ENABLE);
+		wmb();
+	} else {
+		r = __raw_readl(base + USB_INT_ENABLE);
+		r &= ~USB_INTEN_UDC;
+		__raw_writel(r, base + USB_INT_ENABLE);
+		wmb();
+
+		r = __raw_readl(base + USB_DWC_CTRL1);
+		r &= ~USB_DWC_CTRL1_DCRS;
+		__raw_writel(r, base + USB_DWC_CTRL1);
+		wmb();
+
+		__au1300_usb_phyctl(base, enable);
+	}
+}
+
+static inline void __au1300_otg_control(void __iomem *base, int enable)
+{
+	unsigned long r;
+	if (enable) {
+		r = __raw_readl(base + USB_DWC_CTRL3);
+		r |= USB_DWC_CTRL3_OTG0_CKEN;
+		__raw_writel(r, base + USB_DWC_CTRL3);
+		wmb();
+
+		r = __raw_readl(base + USB_DWC_CTRL1);
+		r &= ~USB_DWC_CTRL1_OTGD;
+		__raw_writel(r, base + USB_DWC_CTRL1);
+		wmb();
+
+		__au1300_usb_phyctl(base, enable);
+	} else {
+		r = __raw_readl(base + USB_DWC_CTRL1);
+		r |= USB_DWC_CTRL1_OTGD;
+		__raw_writel(r, base + USB_DWC_CTRL1);
+		wmb();
+
+		r = __raw_readl(base + USB_DWC_CTRL3);
+		r &= ~USB_DWC_CTRL3_OTG0_CKEN;
+		__raw_writel(r, base + USB_DWC_CTRL3);
+		wmb();
+
+		__au1300_usb_phyctl(base, enable);
+	}
+}
+
+static inline int au1300_usb_control(int block, int enable)
+{
+	void __iomem *base =
+		(void __iomem *)KSEG1ADDR(AU1300_USB_CTL_PHYS_ADDR);
+	int ret = 0;
+
+	switch (block) {
+	case ALCHEMY_USB_OHCI0:
+		__au1300_ohci_control(base, enable, 0);
+		break;
+	case ALCHEMY_USB_OHCI1:
+		__au1300_ohci_control(base, enable, 1);
+		break;
+	case ALCHEMY_USB_EHCI0:
+		__au1300_ehci_control(base, enable);
+		break;
+	case ALCHEMY_USB_UDC0:
+		__au1300_udc_control(base, enable);
+		break;
+	case ALCHEMY_USB_OTG0:
+		__au1300_otg_control(base, enable);
+		break;
+	default:
+		ret = -ENODEV;
+	}
+	return ret;
+}
+
+static inline void au1300_usb_init(void)
+{
+	void __iomem *base =
+		(void __iomem *)KSEG1ADDR(AU1300_USB_CTL_PHYS_ADDR);
+
+	/* set some sane defaults.  Note: we don't fiddle with DWC_CTRL4
+	 * here at all: Port 2 routing (EHCI or UDC) must be set either
+	 * by boot firmware or platform init code; I can't autodetect
+	 * a sane setting.
+	 */
+	__raw_writel(0, base + USB_INT_ENABLE); /* disable all USB irqs */
+	wmb();
+	__raw_writel(0, base + USB_DWC_CTRL3); /* disable all clocks */
+	wmb();
+	__raw_writel(~0, base + USB_MSR_ERR); /* clear all errors */
+	wmb();
+	__raw_writel(~0, base + USB_INT_STATUS); /* clear int status */
+	wmb();
+	/* set coherent access bit */
+	__raw_writel(USB_SBUS_CTRL_SBCA, base + USB_SBUS_CTRL);
+	wmb();
+}
 
 static inline void __au1200_ohci_control(void __iomem *base, int enable)
 {
@@ -233,6 +487,9 @@ int alchemy_usb_control(int block, int enable)
 	case ALCHEMY_CPU_AU1200:
 		ret = au1200_usb_control(block, enable);
 		break;
+	case ALCHEMY_CPU_AU1300:
+		ret = au1300_usb_control(block, enable);
+		break;
 	default:
 		ret = -ENODEV;
 	}
@@ -281,6 +538,20 @@ static void au1200_usb_pm(int susp)
 	}
 }
 
+static void au1300_usb_pm(int susp)
+{
+	void __iomem *base =
+			(void __iomem *)KSEG1ADDR(AU1300_USB_CTL_PHYS_ADDR);
+	/* remember Port2 routing */
+	if (susp) {
+		alchemy_usb_pmdata[0] = __raw_readl(base + USB_DWC_CTRL4);
+	} else {
+		au1300_usb_init();
+		__raw_writel(alchemy_usb_pmdata[0], base + USB_DWC_CTRL4);
+		wmb();
+	}
+}
+
 static void alchemy_usb_pm(int susp)
 {
 	switch (alchemy_get_cputype()) {
@@ -295,6 +566,9 @@ static void alchemy_usb_pm(int susp)
 	case ALCHEMY_CPU_AU1200:
 		au1200_usb_pm(susp);
 		break;
+	case ALCHEMY_CPU_AU1300:
+		au1300_usb_pm(susp);
+		break;
 	}
 }
 
@@ -328,6 +602,9 @@ static int __init alchemy_usb_init(void)
 	case ALCHEMY_CPU_AU1200:
 		au1200_usb_init();
 		break;
+	case ALCHEMY_CPU_AU1300:
+		au1300_usb_init();
+		break;
 	}
 
 	register_syscore_ops(&alchemy_usb_pm_ops);
diff --git a/arch/mips/alchemy/common/vss.c b/arch/mips/alchemy/common/vss.c
new file mode 100644
index 0000000..d23b144
--- /dev/null
+++ b/arch/mips/alchemy/common/vss.c
@@ -0,0 +1,84 @@
+/*
+ * Au1300 media block power gating (VSS)
+ *
+ * This is a stop-gap solution until I have the clock framework integration
+ * ready. This stuff here really must be handled transparently when clocks
+ * for various media blocks are enabled/disabled.
+ */
+
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <asm/mach-au1x00/au1000.h>
+
+#define VSS_GATE	0x00	/* gate wait timers */
+#define VSS_CLKRST	0x04	/* clock/block control */
+#define VSS_FTR		0x08	/* footers */
+
+#define VSS_ADDR(blk)	(KSEG1ADDR(AU1300_VSS_PHYS_ADDR) + (blk * 0x0c))
+
+static DEFINE_SPINLOCK(au1300_vss_lock);
+
+/* enable a block as outlined in the databook */
+static inline void __enable_block(int block)
+{
+	void __iomem *base = (void __iomem *)VSS_ADDR(block);
+
+	__raw_writel(3, base + VSS_CLKRST);	/* enable clock, assert reset */
+	wmb();
+
+	__raw_writel(0x01fffffe, base + VSS_GATE); /* maximum setup time */
+	wmb();
+
+	/* enable footers in sequence */
+	__raw_writel(0x01, base + VSS_FTR);
+	wmb();
+	__raw_writel(0x03, base + VSS_FTR);
+	wmb();
+	__raw_writel(0x07, base + VSS_FTR);
+	wmb();
+	__raw_writel(0x0f, base + VSS_FTR);
+	wmb();
+
+	__raw_writel(0x01ffffff, base + VSS_GATE); /* start FSM too */
+	wmb();
+
+	__raw_writel(2, base + VSS_CLKRST);	/* deassert reset */
+	wmb();
+
+	__raw_writel(0x1f, base + VSS_FTR);	/* enable isolation cells */
+	wmb();
+}
+
+/* disable a block as outlined in the databook */
+static inline void __disable_block(int block)
+{
+	void __iomem *base = (void __iomem *)VSS_ADDR(block);
+
+	__raw_writel(0x0f, base + VSS_FTR);	/* disable isolation cells */
+	wmb();
+	__raw_writel(0, base + VSS_GATE);	/* disable FSM */
+	wmb();
+	__raw_writel(3, base + VSS_CLKRST);	/* assert reset */
+	wmb();
+	__raw_writel(1, base + VSS_CLKRST);	/* disable clock */
+	wmb();
+	__raw_writel(0, base + VSS_FTR);	/* disable all footers */
+	wmb();
+}
+
+void au1300_vss_block_control(int block, int enable)
+{
+	unsigned long flags;
+
+	if (alchemy_get_cputype() != ALCHEMY_CPU_AU1300)
+		return;
+
+	/* only one block at a time */
+	spin_lock_irqsave(&au1300_vss_lock, flags);
+	if (enable)
+		__enable_block(block);
+	else
+		__disable_block(block);
+	spin_unlock_irqrestore(&au1300_vss_lock, flags);
+}
+EXPORT_SYMBOL_GPL(au1300_vss_block_control);
diff --git a/arch/mips/include/asm/cpu.h b/arch/mips/include/asm/cpu.h
index 5f95a4b..bb9a470 100644
--- a/arch/mips/include/asm/cpu.h
+++ b/arch/mips/include/asm/cpu.h
@@ -166,6 +166,7 @@
 #define PRID_IMP_NETLOGIC_XLS412B	0x4c00
 #define PRID_IMP_NETLOGIC_XLS408B	0x4e00
 #define PRID_IMP_NETLOGIC_XLS404B	0x4f00
+#define PRID_IMP_NETLOGIC_AU13XX	0x8000
 
 /*
  * Definitions for 7:0 on legacy processors
diff --git a/arch/mips/include/asm/mach-au1x00/au1000.h b/arch/mips/include/asm/mach-au1x00/au1000.h
index bcf3d1e..610cc06 100644
--- a/arch/mips/include/asm/mach-au1x00/au1000.h
+++ b/arch/mips/include/asm/mach-au1x00/au1000.h
@@ -136,6 +136,7 @@ static inline int au1xxx_cpu_needs_config_od(void)
 #define ALCHEMY_CPU_AU1100	2
 #define ALCHEMY_CPU_AU1550	3
 #define ALCHEMY_CPU_AU1200	4
+#define ALCHEMY_CPU_AU1300	5
 
 static inline int alchemy_get_cputype(void)
 {
@@ -156,6 +157,9 @@ static inline int alchemy_get_cputype(void)
 	case 0x05030000:
 		return ALCHEMY_CPU_AU1200;
 		break;
+	case 0x800c0000:
+		return ALCHEMY_CPU_AU1300;
+		break;
 	}
 
 	return ALCHEMY_CPU_UNKNOWN;
@@ -166,6 +170,7 @@ static inline int alchemy_get_uarts(int type)
 {
 	switch (type) {
 	case ALCHEMY_CPU_AU1000:
+	case ALCHEMY_CPU_AU1300:
 		return 4;
 	case ALCHEMY_CPU_AU1500:
 	case ALCHEMY_CPU_AU1200:
@@ -243,6 +248,7 @@ extern unsigned long au1xxx_calc_clock(void);
 /* PM: arch/mips/alchemy/common/sleeper.S, power.c, irq.c */
 void alchemy_sleep_au1000(void);
 void alchemy_sleep_au1550(void);
+void alchemy_sleep_au1300(void);
 void au_sleep(void);
 
 /* USB: arch/mips/alchemy/common/usb.c */
@@ -251,18 +257,97 @@ enum alchemy_usb_block {
 	ALCHEMY_USB_UDC0,
 	ALCHEMY_USB_EHCI0,
 	ALCHEMY_USB_OTG0,
+	ALCHEMY_USB_OHCI1,	/* au1300 */
 };
 int alchemy_usb_control(int block, int enable);
 
 
-/* SOC Interrupt numbers */
+/* Multifunction pins: Each of these pins can either be assigned to the
+ * GPIO controller or a on-chip peripheral.
+ * Call "au1300_pinfunc_to_dev()" or "au1300_pinfunc_to_gpio()" to
+ * assign one of these to either the GPIO controller or the device.
+ */
+enum au1300_multifunc_pins {
+	/* wake-from-str pins 0-3 */
+	AU1300_PIN_WAKE0 = 0, AU1300_PIN_WAKE1, AU1300_PIN_WAKE2,
+	AU1300_PIN_WAKE3,
+	/* external clock sources for PSCs: 4-5 */
+	AU1300_PIN_EXTCLK0, AU1300_PIN_EXTCLK1,
+	/* 8bit MMC interface on SD0: 6-9 */
+	AU1300_PIN_SD0DAT4, AU1300_PIN_SD0DAT5, AU1300_PIN_SD0DAT6,
+	AU1300_PIN_SD0DAT7,
+	/* aux clk input for freqgen 3: 10 */
+	AU1300_PIN_FG3AUX,
+	/* UART1 pins: 11-18 */
+	AU1300_PIN_U1RI, AU1300_PIN_U1DCD, AU1300_PIN_U1DSR,
+	AU1300_PIN_U1CTS, AU1300_PIN_U1RTS, AU1300_PIN_U1DTR,
+	AU1300_PIN_U1RX, AU1300_PIN_U1TX,
+	/* UART0 pins: 19-24 */
+	AU1300_PIN_U0RI, AU1300_PIN_U0DCD, AU1300_PIN_U0DSR,
+	AU1300_PIN_U0CTS, AU1300_PIN_U0RTS, AU1300_PIN_U0DTR,
+	/* UART2: 25-26 */
+	AU1300_PIN_U2RX, AU1300_PIN_U2TX,
+	/* UART3: 27-28 */
+	AU1300_PIN_U3RX, AU1300_PIN_U3TX,
+	/* LCD controller PWMs, ext pixclock: 29-31 */
+	AU1300_PIN_LCDPWM0, AU1300_PIN_LCDPWM1, AU1300_PIN_LCDCLKIN,
+	/* SD1 interface: 32-37 */
+	AU1300_PIN_SD1DAT0, AU1300_PIN_SD1DAT1, AU1300_PIN_SD1DAT2,
+	AU1300_PIN_SD1DAT3, AU1300_PIN_SD1CMD, AU1300_PIN_SD1CLK,
+	/* SD2 interface: 38-43 */
+	AU1300_PIN_SD2DAT0, AU1300_PIN_SD2DAT1, AU1300_PIN_SD2DAT2,
+	AU1300_PIN_SD2DAT3, AU1300_PIN_SD2CMD, AU1300_PIN_SD2CLK,
+	/* PSC0/1 clocks: 44-45 */
+	AU1300_PIN_PSC0CLK, AU1300_PIN_PSC1CLK,
+	/* PSCs: 46-49/50-53/54-57/58-61 */
+	AU1300_PIN_PSC0SYNC0, AU1300_PIN_PSC0SYNC1, AU1300_PIN_PSC0D0,
+	AU1300_PIN_PSC0D1,
+	AU1300_PIN_PSC1SYNC0, AU1300_PIN_PSC1SYNC1, AU1300_PIN_PSC1D0,
+	AU1300_PIN_PSC1D1,
+	AU1300_PIN_PSC2SYNC0, AU1300_PIN_PSC2SYNC1, AU1300_PIN_PSC2D0,
+	AU1300_PIN_PSC2D1,
+	AU1300_PIN_PSC3SYNC0, AU1300_PIN_PSC3SYNC1, AU1300_PIN_PSC3D0,
+	AU1300_PIN_PSC3D1,
+	/* PCMCIA interface: 62-70 */
+	AU1300_PIN_PCE2, AU1300_PIN_PCE1, AU1300_PIN_PIOS16,
+	AU1300_PIN_PIOR, AU1300_PIN_PWE, AU1300_PIN_PWAIT,
+	AU1300_PIN_PREG, AU1300_PIN_POE, AU1300_PIN_PIOW,
+	/* camera interface H/V sync inputs: 71-72 */
+	AU1300_PIN_CIMLS, AU1300_PIN_CIMFS,
+	/* PSC2/3 clocks: 73-74 */
+	AU1300_PIN_PSC2CLK, AU1300_PIN_PSC3CLK,
+};
+
+/* GPIC (Au1300) pin management: arch/mips/alchemy/common/gpioint.c */
+extern void au1300_pinfunc_to_gpio(enum au1300_multifunc_pins gpio);
+extern void au1300_pinfunc_to_dev(enum au1300_multifunc_pins gpio);
+extern void au1300_set_irq_priority(unsigned int irq, int p);
+extern void au1300_set_dbdma_gpio(int dchan, unsigned int gpio);
+
+/* Au1300 allows to disconnect certain blocks from internal power supply */
+enum au1300_vss_block {
+	AU1300_VSS_MPE = 0,
+	AU1300_VSS_BSA,
+	AU1300_VSS_GPE,
+	AU1300_VSS_MGP,
+};
+
+extern void au1300_vss_block_control(int block, int enable);
+
 
+/* SOC Interrupt numbers */
+/* Au1000-style (IC0/1): 2 controllers with 32 sources each */
 #define AU1000_INTC0_INT_BASE	(MIPS_CPU_IRQ_BASE + 8)
 #define AU1000_INTC0_INT_LAST	(AU1000_INTC0_INT_BASE + 31)
 #define AU1000_INTC1_INT_BASE	(AU1000_INTC0_INT_LAST + 1)
 #define AU1000_INTC1_INT_LAST	(AU1000_INTC1_INT_BASE + 31)
 #define AU1000_MAX_INTR 	AU1000_INTC1_INT_LAST
 
+/* Au1300-style (GPIC): 1 controller with up to 128 sources */
+#define ALCHEMY_GPIC_INT_BASE	(MIPS_CPU_IRQ_BASE + 8)
+#define ALCHEMY_GPIC_INT_NUM	128
+#define ALCHEMY_GPIC_INT_LAST	(ALCHEMY_GPIC_INT_BASE + ALCHEMY_GPIC_INT_NUM - 1)
+
 enum soc_au1000_ints {
 	AU1000_FIRST_INT	= AU1000_INTC0_INT_BASE,
 	AU1000_UART0_INT	= AU1000_FIRST_INT,
@@ -583,6 +668,43 @@ enum soc_au1200_ints {
 
 #endif /* !defined (_LANGUAGE_ASSEMBLY) */
 
+/* Au1300 peripheral interrupt numbers */
+#define AU1300_FIRST_INT	(ALCHEMY_GPIC_INT_BASE)
+#define AU1300_UART1_INT	(AU1300_FIRST_INT + 17)
+#define AU1300_UART2_INT	(AU1300_FIRST_INT + 25)
+#define AU1300_UART3_INT	(AU1300_FIRST_INT + 27)
+#define AU1300_SD1_INT		(AU1300_FIRST_INT + 32)
+#define AU1300_SD2_INT		(AU1300_FIRST_INT + 38)
+#define AU1300_PSC0_INT		(AU1300_FIRST_INT + 48)
+#define AU1300_PSC1_INT		(AU1300_FIRST_INT + 52)
+#define AU1300_PSC2_INT		(AU1300_FIRST_INT + 56)
+#define AU1300_PSC3_INT		(AU1300_FIRST_INT + 60)
+#define AU1300_NAND_INT		(AU1300_FIRST_INT + 62)
+#define AU1300_DDMA_INT		(AU1300_FIRST_INT + 75)
+#define AU1300_MMU_INT		(AU1300_FIRST_INT + 76)
+#define AU1300_MPU_INT		(AU1300_FIRST_INT + 77)
+#define AU1300_GPU_INT		(AU1300_FIRST_INT + 78)
+#define AU1300_UDMA_INT		(AU1300_FIRST_INT + 79)
+#define AU1300_TOY_INT		(AU1300_FIRST_INT + 80)
+#define AU1300_TOY_MATCH0_INT	(AU1300_FIRST_INT + 81)
+#define AU1300_TOY_MATCH1_INT	(AU1300_FIRST_INT + 82)
+#define AU1300_TOY_MATCH2_INT	(AU1300_FIRST_INT + 83)
+#define AU1300_RTC_INT		(AU1300_FIRST_INT + 84)
+#define AU1300_RTC_MATCH0_INT	(AU1300_FIRST_INT + 85)
+#define AU1300_RTC_MATCH1_INT	(AU1300_FIRST_INT + 86)
+#define AU1300_RTC_MATCH2_INT	(AU1300_FIRST_INT + 87)
+#define AU1300_UART0_INT	(AU1300_FIRST_INT + 88)
+#define AU1300_SD0_INT		(AU1300_FIRST_INT + 89)
+#define AU1300_USB_INT		(AU1300_FIRST_INT + 90)
+#define AU1300_LCD_INT		(AU1300_FIRST_INT + 91)
+#define AU1300_BSA_INT		(AU1300_FIRST_INT + 92)
+#define AU1300_MPE_INT		(AU1300_FIRST_INT + 93)
+#define AU1300_ITE_INT		(AU1300_FIRST_INT + 94)
+#define AU1300_AES_INT		(AU1300_FIRST_INT + 95)
+#define AU1300_CIM_INT		(AU1300_FIRST_INT + 96)
+
+/**********************************************************************/
+
 /*
  * SDRAM register offsets
  */
@@ -692,22 +814,38 @@ enum soc_au1200_ints {
 
 /*
  * Physical base addresses for integrated peripherals
- * 0..au1000 1..au1500 2..au1100 3..au1550 4..au1200
+ * 0..au1000 1..au1500 2..au1100 3..au1550 4..au1200 5..au1300
  */
 
 #define AU1000_AC97_PHYS_ADDR		0x10000000 /* 012 */
+#define AU1300_ROM_PHYS_ADDR		0x10000000 /* 5 */
+#define AU1300_OTP_PHYS_ADDR		0x10002000 /* 5 */
+#define AU1300_VSS_PHYS_ADDR		0x10003000 /* 5 */
+#define AU1300_UART0_PHYS_ADDR		0x10100000 /* 5 */
+#define AU1300_UART1_PHYS_ADDR		0x10101000 /* 5 */
+#define AU1300_UART2_PHYS_ADDR		0x10102000 /* 5 */
+#define AU1300_UART3_PHYS_ADDR		0x10103000 /* 5 */
 #define AU1000_USB_OHCI_PHYS_ADDR	0x10100000 /* 012 */
 #define AU1000_USB_UDC_PHYS_ADDR	0x10200000 /* 0123 */
+#define AU1300_GPIC_PHYS_ADDR		0x10200000 /* 5 */
 #define AU1000_IRDA_PHYS_ADDR		0x10300000 /* 02 */
-#define AU1200_AES_PHYS_ADDR		0x10300000 /* 4 */
+#define AU1200_AES_PHYS_ADDR		0x10300000 /* 45 */
 #define AU1000_IC0_PHYS_ADDR		0x10400000 /* 01234 */
+#define AU1300_GPU_PHYS_ADDR		0x10500000 /* 5 */
 #define AU1000_MAC0_PHYS_ADDR		0x10500000 /* 023 */
 #define AU1000_MAC1_PHYS_ADDR		0x10510000 /* 023 */
 #define AU1000_MACEN_PHYS_ADDR		0x10520000 /* 023 */
-#define AU1100_SD0_PHYS_ADDR		0x10600000 /* 24 */
+#define AU1100_SD0_PHYS_ADDR		0x10600000 /* 245 */
+#define AU1300_SD1_PHYS_ADDR		0x10601000 /* 5 */
+#define AU1300_SD2_PHYS_ADDR		0x10602000 /* 5 */
 #define AU1100_SD1_PHYS_ADDR		0x10680000 /* 24 */
+#define AU1300_SYS_PHYS_ADDR		0x10900000 /* 5 */
 #define AU1550_PSC2_PHYS_ADDR		0x10A00000 /* 3 */
 #define AU1550_PSC3_PHYS_ADDR		0x10B00000 /* 3 */
+#define AU1300_PSC0_PHYS_ADDR		0x10A00000 /* 5 */
+#define AU1300_PSC1_PHYS_ADDR		0x10A01000 /* 5 */
+#define AU1300_PSC2_PHYS_ADDR		0x10A02000 /* 5 */
+#define AU1300_PSC3_PHYS_ADDR		0x10A03000 /* 5 */
 #define AU1000_I2S_PHYS_ADDR		0x11000000 /* 02 */
 #define AU1500_MAC0_PHYS_ADDR		0x11500000 /* 1 */
 #define AU1500_MAC1_PHYS_ADDR		0x11510000 /* 1 */
@@ -721,37 +859,96 @@ enum soc_au1200_ints {
 #define AU1000_SSI1_PHYS_ADDR		0x11680000 /* 02 */
 #define AU1500_GPIO2_PHYS_ADDR		0x11700000 /* 1234 */
 #define AU1000_IC1_PHYS_ADDR		0x11800000 /* 01234 */
-#define AU1000_SYS_PHYS_ADDR		0x11900000 /* 01234 */
+#define AU1000_SYS_PHYS_ADDR		0x11900000 /* 012345 */
 #define AU1550_PSC0_PHYS_ADDR		0x11A00000 /* 34 */
 #define AU1550_PSC1_PHYS_ADDR		0x11B00000 /* 34 */
 #define AU1000_MEM_PHYS_ADDR		0x14000000 /* 01234 */
 #define AU1000_STATIC_MEM_PHYS_ADDR	0x14001000 /* 01234 */
+#define AU1300_UDMA_PHYS_ADDR		0x14001800 /* 5 */
 #define AU1000_DMA_PHYS_ADDR		0x14002000 /* 012 */
-#define AU1550_DBDMA_PHYS_ADDR		0x14002000 /* 34 */
-#define AU1550_DBDMA_CONF_PHYS_ADDR	0x14003000 /* 34 */
+#define AU1550_DBDMA_PHYS_ADDR		0x14002000 /* 345 */
+#define AU1550_DBDMA_CONF_PHYS_ADDR	0x14003000 /* 345 */
 #define AU1000_MACDMA0_PHYS_ADDR	0x14004000 /* 0123 */
 #define AU1000_MACDMA1_PHYS_ADDR	0x14004200 /* 0123 */
-#define AU1200_CIM_PHYS_ADDR		0x14004000 /* 4 */
+#define AU1200_CIM_PHYS_ADDR		0x14004000 /* 45 */
 #define AU1500_PCI_PHYS_ADDR		0x14005000 /* 13 */
 #define AU1550_PE_PHYS_ADDR		0x14008000 /* 3 */
 #define AU1200_MAEBE_PHYS_ADDR		0x14010000 /* 4 */
 #define AU1200_MAEFE_PHYS_ADDR		0x14012000 /* 4 */
+#define AU1300_MAEITE_PHYS_ADDR		0x14010000 /* 5 */
+#define AU1300_MAEMPE_PHYS_ADDR		0x14014000 /* 5 */
 #define AU1550_USB_OHCI_PHYS_ADDR	0x14020000 /* 3 */
 #define AU1200_USB_CTL_PHYS_ADDR	0x14020000 /* 4 */
 #define AU1200_USB_OTG_PHYS_ADDR	0x14020020 /* 4 */
 #define AU1200_USB_OHCI_PHYS_ADDR	0x14020100 /* 4 */
 #define AU1200_USB_EHCI_PHYS_ADDR	0x14020200 /* 4 */
 #define AU1200_USB_UDC_PHYS_ADDR	0x14022000 /* 4 */
+#define AU1300_USB_EHCI_PHYS_ADDR	0x14020000 /* 5 */
+#define AU1300_USB_OHCI0_PHYS_ADDR	0x14020400 /* 5 */
+#define AU1300_USB_OHCI1_PHYS_ADDR	0x14020800 /* 5 */
+#define AU1300_USB_CTL_PHYS_ADDR	0x14021000 /* 5 */
+#define AU1300_USB_OTG_PHYS_ADDR	0x14022000 /* 5 */
+#define AU1300_MAEBSA_PHYS_ADDR		0x14030000 /* 5 */
 #define AU1100_LCD_PHYS_ADDR		0x15000000 /* 2 */
-#define AU1200_LCD_PHYS_ADDR		0x15000000 /* 4 */
+#define AU1200_LCD_PHYS_ADDR		0x15000000 /* 45 */
 #define AU1500_PCI_MEM_PHYS_ADDR	0x400000000ULL /* 13 */
 #define AU1500_PCI_IO_PHYS_ADDR		0x500000000ULL /* 13 */
 #define AU1500_PCI_CONFIG0_PHYS_ADDR	0x600000000ULL /* 13 */
 #define AU1500_PCI_CONFIG1_PHYS_ADDR	0x680000000ULL /* 13 */
-#define AU1000_PCMCIA_IO_PHYS_ADDR	0xF00000000ULL /* 01234 */
-#define AU1000_PCMCIA_ATTR_PHYS_ADDR	0xF40000000ULL /* 01234 */
-#define AU1000_PCMCIA_MEM_PHYS_ADDR	0xF80000000ULL /* 01234 */
+#define AU1000_PCMCIA_IO_PHYS_ADDR	0xF00000000ULL /* 012345 */
+#define AU1000_PCMCIA_ATTR_PHYS_ADDR	0xF40000000ULL /* 012345 */
+#define AU1000_PCMCIA_MEM_PHYS_ADDR	0xF80000000ULL /* 012345 */
+
+/**********************************************************************/
+
 
+/*
+ * Au1300 GPIO+INT controller (GPIC) register offsets and bits
+ * Registers are 128bits (0x10 bytes), divided into 4 "banks".
+ */
+#define AU1300_GPIC_PINVAL	0x0000
+#define AU1300_GPIC_PINVALCLR	0x0010
+#define AU1300_GPIC_IPEND	0x0020
+#define AU1300_GPIC_PRIENC	0x0030
+#define AU1300_GPIC_IEN		0x0040	/* int_mask in manual */
+#define AU1300_GPIC_IDIS	0x0050	/* int_maskclr in manual */
+#define AU1300_GPIC_DMASEL	0x0060
+#define AU1300_GPIC_DEVSEL	0x0080
+#define AU1300_GPIC_DEVCLR	0x0090
+#define AU1300_GPIC_RSTVAL	0x00a0
+/* pin configuration space. one 32bit register for up to 128 IRQs */
+#define AU1300_GPIC_PINCFG	0x1000
+
+#define GPIC_GPIO_TO_BIT(gpio)	\
+	(1 << ((gpio) & 0x1f))
+
+#define GPIC_GPIO_BANKOFF(gpio)	\
+	(((gpio) >> 5) * 4)
+
+/* Pin Control bits: who owns the pin, what does it do */
+#define GPIC_CFG_PC_GPIN		0
+#define GPIC_CFG_PC_DEV			1
+#define GPIC_CFG_PC_GPOLOW		2
+#define GPIC_CFG_PC_GPOHIGH		3
+#define GPIC_CFG_PC_MASK		3
+
+/* assign pin to MIPS IRQ line */
+#define GPIC_CFG_IL_SET(x)	(((x) & 3) << 2)
+#define GPIC_CFG_IL_MASK	(3 << 2)
+
+/* pin interrupt type setup */
+#define GPIC_CFG_IC_OFF		(0 << 4)
+#define GPIC_CFG_IC_LEVEL_LOW	(1 << 4)
+#define GPIC_CFG_IC_LEVEL_HIGH	(2 << 4)
+#define GPIC_CFG_IC_EDGE_FALL	(5 << 4)
+#define GPIC_CFG_IC_EDGE_RISE	(6 << 4)
+#define GPIC_CFG_IC_EDGE_BOTH	(7 << 4)
+#define GPIC_CFG_IC_MASK	(7 << 4)
+
+/* allow interrupt to wake cpu from 'wait' */
+#define GPIC_CFG_IDLEWAKE	(1 << 7)
+
+/***********************************************************************/
 
 /* Static Bus Controller */
 #define MEM_STCFG0		0xB4001000
@@ -770,14 +967,12 @@ enum soc_au1200_ints {
 #define MEM_STTIME3		0xB4001034
 #define MEM_STADDR3		0xB4001038
 
-#if defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200)
 #define MEM_STNDCTL		0xB4001100
 #define MEM_STSTAT		0xB4001104
 
 #define MEM_STNAND_CMD		0x0
 #define MEM_STNAND_ADDR 	0x4
 #define MEM_STNAND_DATA 	0x20
-#endif
 
 
 /* Programmable Counters 0 and 1 */
diff --git a/arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h b/arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h
index 2fdacfe..14b26ff 100644
--- a/arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h
+++ b/arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h
@@ -187,6 +187,39 @@ typedef volatile struct au1xxx_ddma_desc {
 #define DSCR_CMD0_CIM_SYNC	26
 #endif /* CONFIG_SOC_AU1200 */
 
+#ifdef CONFIG_SOC_AU1300
+#define DSCR_CMD0_UART0_TX      0
+#define DSCR_CMD0_UART0_RX      1
+#define DSCR_CMD0_UART1_TX      2
+#define DSCR_CMD0_UART1_RX      3
+#define DSCR_CMD0_UART2_TX      4
+#define DSCR_CMD0_UART2_RX      5
+#define DSCR_CMD0_UART3_TX      6
+#define DSCR_CMD0_UART3_RX      7
+#define DSCR_CMD0_SDMS_TX0      8
+#define DSCR_CMD0_SDMS_RX0      9
+#define DSCR_CMD0_SDMS_TX1      10
+#define DSCR_CMD0_SDMS_RX1      11
+#define DSCR_CMD0_AES_TX        12
+#define DSCR_CMD0_AES_RX        13
+#define DSCR_CMD0_PSC0_TX       14
+#define DSCR_CMD0_PSC0_RX       15
+#define DSCR_CMD0_PSC1_TX       16
+#define DSCR_CMD0_PSC1_RX       17
+#define DSCR_CMD0_PSC2_TX       18
+#define DSCR_CMD0_PSC2_RX       19
+#define DSCR_CMD0_PSC3_TX       20
+#define DSCR_CMD0_PSC3_RX       21
+#define DSCR_CMD0_LCD           22
+#define DSCR_CMD0_NAND_FLASH    23
+#define DSCR_CMD0_SDMS_TX2      24
+#define DSCR_CMD0_SDMS_RX2      25
+#define DSCR_CMD0_CIM_SYNC      26
+#define DSCR_CMD0_UDMA          27
+#define DSCR_CMD0_DMA_REQ0      28
+#define DSCR_CMD0_DMA_REQ1      29
+#endif /* CONFIG_SOC_AU1300 */
+
 #define DSCR_CMD0_THROTTLE	30
 #define DSCR_CMD0_ALWAYS	31
 #define DSCR_NDEV_IDS		32
diff --git a/arch/mips/include/asm/mach-au1x00/gpio-au1300.h b/arch/mips/include/asm/mach-au1x00/gpio-au1300.h
new file mode 100644
index 0000000..5d3bf5e
--- /dev/null
+++ b/arch/mips/include/asm/mach-au1x00/gpio-au1300.h
@@ -0,0 +1,250 @@
+/*
+ * gpio-au1300.h -- GPIO control for Au1300 and compatibles.
+ *
+ * Copyright (c) 2009-2010 Manuel Lauss <manuel.lauss@gmail.com>
+ */
+
+#ifndef _GPIO_AU1300_H_
+#define _GPIO_AU1300_H_
+
+#include <asm/addrspace.h>
+#include <asm/io.h>
+#include <asm/mach-au1x00/au1000.h>
+
+#define AU1300_GPIO_BASE	0
+#define AU1300_GPIO_NUM		75
+#define AU1300_GPIO_MAX		(AU1300_GPIO_BASE + AU1300_GPIO_NUM - 1)
+
+#define AU1300_GPIC_ADDR	\
+	(void __iomem *)KSEG1ADDR(AU1300_GPIC_PHYS_ADDR)
+
+static inline int au1300_gpio_get_value(unsigned int gpio)
+{
+	void __iomem *roff = AU1300_GPIC_ADDR;
+	int bit;
+
+	gpio -= AU1300_GPIO_BASE;
+	roff += GPIC_GPIO_BANKOFF(gpio);
+	bit = GPIC_GPIO_TO_BIT(gpio);
+	return __raw_readl(roff + AU1300_GPIC_PINVAL) & bit;
+}
+
+static inline int au1300_gpio_direction_input(unsigned int gpio)
+{
+	void __iomem *roff = AU1300_GPIC_ADDR;
+	unsigned long bit;
+
+	gpio -= AU1300_GPIO_BASE;
+
+	roff += GPIC_GPIO_BANKOFF(gpio);
+	bit = GPIC_GPIO_TO_BIT(gpio);
+	__raw_writel(bit, roff + AU1300_GPIC_DEVCLR);
+	wmb();
+
+	return 0;
+}
+
+static inline int au1300_gpio_set_value(unsigned int gpio, int v)
+{
+	void __iomem *roff = AU1300_GPIC_ADDR;
+	unsigned long bit;
+
+	gpio -= AU1300_GPIO_BASE;
+
+	roff += GPIC_GPIO_BANKOFF(gpio);
+	bit = GPIC_GPIO_TO_BIT(gpio);
+	__raw_writel(bit, roff + (v ? AU1300_GPIC_PINVAL
+				    : AU1300_GPIC_PINVALCLR));
+	wmb();
+
+	return 0;
+}
+
+static inline int au1300_gpio_direction_output(unsigned int gpio, int v)
+{
+	/* hw switches to output automatically */
+	return au1300_gpio_set_value(gpio, v);
+}
+
+static inline int au1300_gpio_to_irq(unsigned int gpio)
+{
+	return AU1300_FIRST_INT + (gpio - AU1300_GPIO_BASE);
+}
+
+static inline int au1300_irq_to_gpio(unsigned int irq)
+{
+	return (irq - AU1300_FIRST_INT) + AU1300_GPIO_BASE;
+}
+
+static inline int au1300_gpio_is_valid(unsigned int gpio)
+{
+	return ((gpio >= AU1300_GPIO_BASE) && (gpio <= AU1300_GPIO_MAX));
+}
+
+static inline int au1300_gpio_cansleep(unsigned int gpio)
+{
+	return 0;
+}
+
+static inline void alchemy_gpio1_input_enable(void)
+{
+	__raw_writel(0, (void __iomem *)KSEG1ADDR(AU1300_SYS_PHYS_ADDR) + 0x110);
+	wmb();
+}
+
+/* hardware remembers gpio 0-63 levels on powerup */
+static inline int au1300_gpio_getinitlvl(unsigned int gpio)
+{
+	void __iomem *roff = AU1300_GPIC_ADDR;
+	unsigned long v;
+
+	if (unlikely(gpio > 63))
+		return 0;
+	else if (gpio > 31) {
+		gpio -= 32;
+		roff += 4;
+	}
+
+	v = __raw_readl(roff + AU1300_GPIC_RSTVAL);
+	return (v >> gpio) & 1;
+}
+
+/**********************************************************************/
+
+/* Linux gpio framework integration.
+*
+* 4 use cases of Alchemy GPIOS:
+*(1) GPIOLIB=y, ALCHEMY_GPIO_INDIRECT=y:
+*	Board must register gpiochips.
+*(2) GPIOLIB=y, ALCHEMY_GPIO_INDIRECT=n:
+*	A gpiochip for the 75 GPIOs is registered.
+*
+*(3) GPIOLIB=n, ALCHEMY_GPIO_INDIRECT=y:
+*	the boards' gpio.h must provide	the linux gpio wrapper functions,
+*
+*(4) GPIOLIB=n, ALCHEMY_GPIO_INDIRECT=n:
+*	inlinable gpio functions are provided which enable access to the
+*	Au1300 gpios only by using the numbers straight out of the data-
+*	sheets.
+
+* Cases 1 and 3 are intended for boards which want to provide their own
+* GPIO namespace and -operations (i.e. for example you have 8 GPIOs
+* which are in part provided by spare Au1300 GPIO pins and in part by
+* an external FPGA but you still want them to be accssible in linux
+* as gpio0-7. The board can of course use the alchemy_gpioX_* functions
+* as required).
+*/
+
+#ifndef CONFIG_GPIOLIB
+
+
+#ifndef CONFIG_ALCHEMY_GPIO_INDIRECT	/* case (4) */
+
+static inline int gpio_direction_input(unsigned int gpio)
+{
+	return au1300_gpio_direction_input(gpio);
+}
+
+static inline int gpio_direction_output(unsigned int gpio, int v)
+{
+	return au1300_gpio_direction_output(gpio, v);
+}
+
+static inline int gpio_get_value(unsigned int gpio)
+{
+	return au1300_gpio_get_value(gpio);
+}
+
+static inline void gpio_set_value(unsigned int gpio, int v)
+{
+	au1300_gpio_set_value(gpio, v);
+}
+
+static inline int gpio_get_value_cansleep(unsigned gpio)
+{
+	return gpio_get_value(gpio);
+}
+
+static inline void gpio_set_value_cansleep(unsigned gpio, int value)
+{
+	gpio_set_value(gpio, value);
+}
+
+static inline int gpio_is_valid(unsigned int gpio)
+{
+	return au1300_gpio_is_valid(gpio);
+}
+
+static inline int gpio_cansleep(unsigned int gpio)
+{
+	return au1300_gpio_cansleep(gpio);
+}
+
+static inline int gpio_to_irq(unsigned int gpio)
+{
+	return au1300_gpio_to_irq(gpio);
+}
+
+static inline int irq_to_gpio(unsigned int irq)
+{
+	return au1300_irq_to_gpio(irq);
+}
+
+static inline int gpio_request(unsigned int gpio, const char *label)
+{
+	return 0;
+}
+
+static inline void gpio_free(unsigned int gpio)
+{
+}
+
+static inline int gpio_set_debounce(unsigned gpio, unsigned debounce)
+{
+	return -ENOSYS;
+}
+
+static inline void gpio_unexport(unsigned gpio)
+{
+}
+
+static inline int gpio_export(unsigned gpio, bool direction_may_change)
+{
+	return -ENOSYS;
+}
+
+static inline int gpio_sysfs_set_active_low(unsigned gpio, int value)
+{
+	return -ENOSYS;
+}
+
+static inline int gpio_export_link(struct device *dev, const char *name,
+				   unsigned gpio)
+{
+	return -ENOSYS;
+}
+
+#endif	/* !CONFIG_ALCHEMY_GPIO_INDIRECT */
+
+
+#else	/* CONFIG GPIOLIB */
+
+
+/* using gpiolib to provide up to 2 gpio_chips for on-chip gpios */
+#ifndef CONFIG_ALCHEMY_GPIO_INDIRECT	/* case (2) */
+
+/* get everything through gpiolib */
+#define gpio_to_irq	__gpio_to_irq
+#define gpio_get_value	__gpio_get_value
+#define gpio_set_value	__gpio_set_value
+#define gpio_cansleep	__gpio_cansleep
+#define irq_to_gpio	au1300_irq_to_gpio
+
+#include <asm-generic/gpio.h>
+
+#endif	/* !CONFIG_ALCHEMY_GPIO_INDIRECT */
+
+
+#endif	/* !CONFIG_GPIOLIB */
+
+#endif /* _GPIO_AU1300_H_ */
diff --git a/arch/mips/include/asm/mach-au1x00/gpio.h b/arch/mips/include/asm/mach-au1x00/gpio.h
index c3f60cd..4d6edea 100644
--- a/arch/mips/include/asm/mach-au1x00/gpio.h
+++ b/arch/mips/include/asm/mach-au1x00/gpio.h
@@ -5,6 +5,10 @@
 
 #include <asm/mach-au1x00/gpio-au1000.h>
 
+#elif defined(CONFIG_ALCHEMY_GPIOINT_AU1300)
+
+#include <asm/mach-au1x00/gpio-au1300.h>
+
 #endif
 
 #endif	/* _ALCHEMY_GPIO_H_ */
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index bb133d1..50da1a8 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -1011,6 +1011,13 @@ static inline void cpu_probe_netlogic(struct cpuinfo_mips *c, int cpu)
 {
 	decode_configs(c);
 
+	if ((c->processor_id & 0xff00) == PRID_IMP_NETLOGIC_AU13XX) {
+		c->cputype = CPU_ALCHEMY;
+		__cpu_name[cpu] = "Au1300";
+		/* following stuff is not for Alchemy */
+		return;
+	}
+
 	c->options = (MIPS_CPU_TLB       |
 			MIPS_CPU_4KEX    |
 			MIPS_CPU_COUNTER |
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 646068e..afafa35 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -300,11 +300,11 @@ config I2C_AT91
 	  unless your system can cope with those limitations.
 
 config I2C_AU1550
-	tristate "Au1550/Au1200 SMBus interface"
-	depends on SOC_AU1550 || SOC_AU1200
+	tristate "Au1550/Au1200/Au1300 SMBus interface"
+	depends on MIPS_ALCHEMY
 	help
 	  If you say yes to this option, support will be included for the
-	  Au1550 and Au1200 SMBus interface.
+	  Au1550/Au1200/Au1300 SMBus interface.
 
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-au1550.
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index de35c3a..aac451e 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -90,12 +90,12 @@ config SPI_BFIN_SPORT
 	  will be called spi_bfin_sport.
 
 config SPI_AU1550
-	tristate "Au1550/Au12x0 SPI Controller"
-	depends on (SOC_AU1550 || SOC_AU1200) && EXPERIMENTAL
+	tristate "Au1550/Au12x0/Au13xx SPI Controller"
+	depends on MIPS_ALCHEMY && EXPERIMENTAL
 	select SPI_BITBANG
 	help
 	  If you say yes to this option, support will be included for the
-	  Au1550 SPI controller (may also work with Au1200,Au1210,Au1250).
+	  PSC SPI controller found on Au1550, Au12xx, Au13xx.
 
 	  This driver can also be built as a module.  If so, the module
 	  will be called au1550_spi.
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 48f1781..ec33212 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -56,7 +56,7 @@ config USB_ARCH_HAS_EHCI
 	boolean
 	default y if PPC_83xx
 	default y if PPC_MPC512x
-	default y if SOC_AU1200
+	default y if MIPS_ALCHEMY
 	default y if ARCH_IXP4XX
 	default y if ARCH_W90X900
 	default y if ARCH_AT91SAM9G45
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index f8030ee..d561d4e 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -1191,7 +1191,7 @@ MODULE_LICENSE ("GPL");
 #define PLATFORM_DRIVER		ehci_hcd_sh_driver
 #endif
 
-#ifdef CONFIG_SOC_AU1200
+#ifdef CONFIG_MIPS_ALCHEMY
 #include "ehci-au1xxx.c"
 #define	PLATFORM_DRIVER		ehci_hcd_au1xxx_driver
 #endif
diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c
index 299d719..a89396b 100644
--- a/drivers/usb/host/ohci-au1xxx.c
+++ b/drivers/usb/host/ohci-au1xxx.c
@@ -89,7 +89,7 @@ static const struct hc_driver ohci_au1xxx_hc_driver = {
 
 static int ohci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
 {
-	int ret;
+	int ret, unit;
 	struct usb_hcd *hcd;
 
 	if (usb_disabled())
@@ -120,7 +120,9 @@ static int ohci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
 		goto err2;
 	}
 
-	if (alchemy_usb_control(ALCHEMY_USB_OHCI0, 1)) {
+	unit = (hcd->rsrc_start == AU1300_USB_OHCI1_PHYS_ADDR) ?
+			ALCHEMY_USB_OHCI1 : ALCHEMY_USB_OHCI0;
+	if (alchemy_usb_control(unit, 1)) {
 		printk(KERN_INFO "%s: controller init failed!\n", pdev->name);
 		ret = -ENODEV;
 		goto err3;
@@ -135,7 +137,7 @@ static int ohci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	alchemy_usb_control(ALCHEMY_USB_OHCI0, 0);
+	alchemy_usb_control(unit, 0);
 err3:
 	iounmap(hcd->regs);
 err2:
@@ -148,9 +150,12 @@ err1:
 static int ohci_hcd_au1xxx_drv_remove(struct platform_device *pdev)
 {
 	struct usb_hcd *hcd = platform_get_drvdata(pdev);
+	int unit;
 
+	unit = (hcd->rsrc_start == AU1300_USB_OHCI1_PHYS_ADDR) ?
+			ALCHEMY_USB_OHCI1 : ALCHEMY_USB_OHCI0;
 	usb_remove_hcd(hcd);
-	alchemy_usb_control(ALCHEMY_USB_OHCI0, 0);
+	alchemy_usb_control(unit, 0);
 	iounmap(hcd->regs);
 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 	usb_put_hcd(hcd);
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 5e19de9..e2155fe 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1754,16 +1754,16 @@ config FB_AU1100
 	  au1100fb:panel=<name>.
 
 config FB_AU1200
-	bool "Au1200 LCD Driver"
-	depends on (FB = y) && MIPS && SOC_AU1200
+	bool "Au1200/Au1300 LCD Driver"
+	depends on (FB = y) && MIPS_ALCHEMY
 	select FB_SYS_FILLRECT
 	select FB_SYS_COPYAREA
 	select FB_SYS_IMAGEBLIT
 	select FB_SYS_FOPS
 	help
-	  This is the framebuffer driver for the AMD Au1200 SOC.  It can drive
-	  various panels and CRTs by passing in kernel cmd line option
-	  au1200fb:panel=<name>.
+	  This is the framebuffer driver for the Au1200/Au1300 SOCs.
+	  It can drive various panels and CRTs by passing in kernel cmd line
+	  option au1200fb:panel=<name>.
 
 config FB_VT8500
 	bool "VT8500 LCD Driver"
diff --git a/sound/soc/au1x/Kconfig b/sound/soc/au1x/Kconfig
index 4b67140..894428b 100644
--- a/sound/soc/au1x/Kconfig
+++ b/sound/soc/au1x/Kconfig
@@ -2,12 +2,12 @@
 ## Au1200/Au1550 PSC + DBDMA
 ##
 config SND_SOC_AU1XPSC
-	tristate "SoC Audio for Au1200/Au1250/Au1550"
-	depends on SOC_AU1200 || SOC_AU1550
+	tristate "SoC Audio for Au12xx/Au13xx/Au1550"
+	depends on MIPS_ALCHEMY
 	help
 	  This option enables support for the Programmable Serial
 	  Controllers in AC97 and I2S mode, and the Descriptor-Based DMA
-	  Controller (DBDMA) as found on the Au1200/Au1250/Au1550 SoC.
+	  Controller (DBDMA) as found on the Au12xx/Au13xx/Au1550 SoC.
 
 config SND_SOC_AU1XPSC_I2S
 	tristate
-- 
1.7.6


From manuel.lauss@googlemail.com Fri Jul 15 13:41:36 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 15 Jul 2011 13:43:02 +0200 (CEST)
Received: from mail-fx0-f49.google.com ([209.85.161.49]:36151 "EHLO
        mail-fx0-f49.google.com" rhost-flags-OK-OK-OK-OK)
        by eddie.linux-mips.org with ESMTP id S1491809Ab1GOLlg (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Fri, 15 Jul 2011 13:41:36 +0200
Received: by fxd20 with SMTP id 20so1823723fxd.36
        for <linux-mips@linux-mips.org>; Fri, 15 Jul 2011 04:41:30 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=googlemail.com; s=gamma;
        h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references;
        bh=GCB2dJChLLrUi1AdqWmJpNwIhj1QFM1ZqwfJaxyhfMY=;
        b=BdfysHgnMNpNr6QtyeE/cJ/w0juj06MPeSdPdDHCQAFtYvfitdu1hDMsz8GCUvjbVR
         wapoyJMtmBJMGyUSq4ncxS0szuH33YDcEA4KYisCM+qdJE4jBEKqlTuJxvHbVgRKHFZ1
         tMgLm6ogWvEkg1aVgQxU1yCcqYvuf5bQzibZk=
Received: by 10.223.91.156 with SMTP id n28mr5297507fam.102.1310730090418;
        Fri, 15 Jul 2011 04:41:30 -0700 (PDT)
Received: from localhost.localdomain (178-191-8-8.adsl.highway.telekom.at [178.191.8.8])
        by mx.google.com with ESMTPS id q1sm794249faa.3.2011.07.15.04.41.27
        (version=TLSv1/SSLv3 cipher=OTHER);
        Fri, 15 Jul 2011 04:41:29 -0700 (PDT)
From:   Manuel Lauss <manuel.lauss@googlemail.com>
To:     Linux-MIPS <linux-mips@linux-mips.org>
Cc:     Manuel Lauss <manuel.lauss@googlemail.com>
Subject: [RFC PATCH V3 2/2] MIPS: Alchemy: DB1300 support
Date:   Fri, 15 Jul 2011 13:41:18 +0200
Message-Id: <1310730078-30265-3-git-send-email-manuel.lauss@googlemail.com>
X-Mailer: git-send-email 1.7.6
In-Reply-To: <1310730078-30265-1-git-send-email-manuel.lauss@googlemail.com>
References: <1310730078-30265-1-git-send-email-manuel.lauss@googlemail.com>
X-archive-position: 30626
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: manuel.lauss@googlemail.com
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 10921
Content-Length: 52048
Lines: 1832

Basic support for the DB1300 board.

Signed-off-by: Manuel Lauss <manuel.lauss@googlemail.com>
---
V3: merged core DB1300 code into a single file.
V2: use the BCSR irq dispatcher, just like DB1200/PB1200.

 arch/mips/alchemy/Kconfig                  |    8 +
 arch/mips/alchemy/Platform                 |    7 +
 arch/mips/alchemy/devboards/Makefile       |    1 +
 arch/mips/alchemy/devboards/bcsr.c         |    4 +
 arch/mips/alchemy/devboards/db1300.c       |  767 ++++++++++++++++++++++++++++
 arch/mips/alchemy/devboards/prom.c         |    4 +
 arch/mips/boot/compressed/uart-alchemy.c   |    5 +-
 arch/mips/configs/db1300_defconfig         |  391 ++++++++++++++
 arch/mips/include/asm/mach-db1x00/bcsr.h   |   34 +-
 arch/mips/include/asm/mach-db1x00/db1300.h |   40 ++
 arch/mips/include/asm/mach-db1x00/irq.h    |   23 +
 drivers/pcmcia/Kconfig                     |    4 +-
 drivers/pcmcia/db1xxx_ss.c                 |   26 +-
 drivers/video/au1200fb.c                   |   36 ++
 sound/soc/au1x/Kconfig                     |   12 +
 sound/soc/au1x/Makefile                    |    2 +
 sound/soc/au1x/db1200.c                    |    4 +
 sound/soc/au1x/db1300.c                    |  147 ++++++
 18 files changed, 1501 insertions(+), 14 deletions(-)
 create mode 100644 arch/mips/alchemy/devboards/db1300.c
 create mode 100644 arch/mips/configs/db1300_defconfig
 create mode 100644 arch/mips/include/asm/mach-db1x00/db1300.h
 create mode 100644 arch/mips/include/asm/mach-db1x00/irq.h
 create mode 100644 sound/soc/au1x/db1300.c

diff --git a/arch/mips/alchemy/Kconfig b/arch/mips/alchemy/Kconfig
index 30277fd..1e40bb6 100644
--- a/arch/mips/alchemy/Kconfig
+++ b/arch/mips/alchemy/Kconfig
@@ -56,6 +56,14 @@ config MIPS_DB1200
 	select SYS_SUPPORTS_LITTLE_ENDIAN
 	select SYS_HAS_EARLY_PRINTK
 
+config MIPS_DB1300
+	bool "NetLogic DB1300 board"
+	select SOC_AU1300
+	select DMA_COHERENT
+	select MIPS_DISABLE_OBSOLETE_IDE
+	select SYS_SUPPORTS_LITTLE_ENDIAN
+	select SYS_HAS_EARLY_PRINTK
+
 config MIPS_DB1500
 	bool "Alchemy DB1500 board"
 	select SOC_AU1500
diff --git a/arch/mips/alchemy/Platform b/arch/mips/alchemy/Platform
index 96e9e41..85699c7 100644
--- a/arch/mips/alchemy/Platform
+++ b/arch/mips/alchemy/Platform
@@ -75,6 +75,13 @@ cflags-$(CONFIG_MIPS_DB1200)	+= -I$(srctree)/arch/mips/include/asm/mach-db1x00
 load-$(CONFIG_MIPS_DB1200)	+= 0xffffffff80100000
 
 #
+# NetLogic DBAu1300 development platform
+#
+platform-$(CONFIG_MIPS_DB1300)	+= alchemy/devboards/
+cflags-$(CONFIG_MIPS_DB1300)	+= -I$(srctree)/arch/mips/include/asm/mach-db1x00
+load-$(CONFIG_MIPS_DB1300)	+= 0xffffffff80100000
+
+#
 # AMD Alchemy Bosporus eval board
 #
 platform-$(CONFIG_MIPS_BOSPORUS) += alchemy/devboards/
diff --git a/arch/mips/alchemy/devboards/Makefile b/arch/mips/alchemy/devboards/Makefile
index 826449c..3b669aa 100644
--- a/arch/mips/alchemy/devboards/Makefile
+++ b/arch/mips/alchemy/devboards/Makefile
@@ -16,3 +16,4 @@ obj-$(CONFIG_MIPS_DB1500)	+= db1x00/
 obj-$(CONFIG_MIPS_DB1550)	+= db1x00/
 obj-$(CONFIG_MIPS_BOSPORUS)	+= db1x00/
 obj-$(CONFIG_MIPS_MIRAGE)	+= db1x00/
+obj-$(CONFIG_MIPS_DB1300)	+= db1300.o
diff --git a/arch/mips/alchemy/devboards/bcsr.c b/arch/mips/alchemy/devboards/bcsr.c
index 596ad00..ad86f53 100644
--- a/arch/mips/alchemy/devboards/bcsr.c
+++ b/arch/mips/alchemy/devboards/bcsr.c
@@ -89,8 +89,12 @@ static void bcsr_csc_handler(unsigned int irq, struct irq_desc *d)
 {
 	unsigned short bisr = __raw_readw(bcsr_virt + BCSR_REG_INTSTAT);
 
+	disable_irq_nosync(irq);	/* makes DB1300 happy */
+
 	for ( ; bisr; bisr &= bisr - 1)
 		generic_handle_irq(bcsr_csc_base + __ffs(bisr));
+
+	enable_irq(irq);		/* makes DB1300 happy */
 }
 
 /* NOTE: both the enable and mask bits must be cleared, otherwise the
diff --git a/arch/mips/alchemy/devboards/db1300.c b/arch/mips/alchemy/devboards/db1300.c
new file mode 100644
index 0000000..f7461a5
--- /dev/null
+++ b/arch/mips/alchemy/devboards/db1300.c
@@ -0,0 +1,767 @@
+/*
+ * DBAu1300 init and platform device setup.
+ *
+ * (c) 2009 Manuel Lauss <manuel.lauss@googlemail.com>
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/gpio.h>
+#include <linux/gpio_keys.h>
+#include <linux/init.h>
+#include <linux/input.h>	/* KEY_* codes */
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/leds.h>
+#include <linux/ata_platform.h>
+#include <linux/mmc/host.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/platform_device.h>
+#include <linux/smsc911x.h>
+
+#include <asm/mach-au1x00/au1000.h>
+#include <asm/mach-au1x00/au1100_mmc.h>
+#include <asm/mach-au1x00/au1xxx_dbdma.h>
+#include <asm/mach-au1x00/au1xxx_psc.h>
+#include <asm/mach-db1x00/db1300.h>
+#include <asm/mach-db1x00/bcsr.h>
+#include <asm/mach-au1x00/prom.h>
+
+#include "platform.h"
+
+static struct i2c_board_info db1300_i2c_devs[] __initdata = {
+	{ I2C_BOARD_INFO("wm8731", 0x1b), },	/* I2S audio codec */
+	{ I2C_BOARD_INFO("ne1619", 0x2d), },	/* adm1025-compat hwmon */
+};
+
+/* multifunction pins to assign to GPIO controller */
+static int db1300_gpio_pins[] __initdata = {
+	AU1300_PIN_LCDPWM0, AU1300_PIN_PSC2SYNC1, AU1300_PIN_WAKE1,
+	AU1300_PIN_WAKE2, AU1300_PIN_WAKE3, AU1300_PIN_FG3AUX,
+	AU1300_PIN_EXTCLK1,
+
+	-1,	/* terminator */
+};
+
+/* multifunction pins to assign to device functions */
+static int db1300_dev_pins[] __initdata = {
+	/* wake-from-str pins 0-3 */
+	AU1300_PIN_WAKE0,
+	/* external clock sources for PSC0 */
+	AU1300_PIN_EXTCLK0,
+	/* 8bit MMC interface on SD0: 6-9 */
+	AU1300_PIN_SD0DAT4, AU1300_PIN_SD0DAT5, AU1300_PIN_SD0DAT6,
+	AU1300_PIN_SD0DAT7,
+	/* UART1 pins: 11-18 */
+	AU1300_PIN_U1RI, AU1300_PIN_U1DCD, AU1300_PIN_U1DSR,
+	AU1300_PIN_U1CTS, AU1300_PIN_U1RTS, AU1300_PIN_U1DTR,
+	AU1300_PIN_U1RX, AU1300_PIN_U1TX,
+	/* UART0 pins: 19-24 */
+	AU1300_PIN_U0RI, AU1300_PIN_U0DCD, AU1300_PIN_U0DSR,
+	AU1300_PIN_U0CTS, AU1300_PIN_U0RTS, AU1300_PIN_U0DTR,
+	/* UART2: 25-26 */
+	AU1300_PIN_U2RX, AU1300_PIN_U2TX,
+	/* UART3: 27-28 */
+	AU1300_PIN_U3RX, AU1300_PIN_U3TX,
+	/* LCD controller PWMs, ext pixclock: 30-31 */
+	AU1300_PIN_LCDPWM1, AU1300_PIN_LCDCLKIN,
+	/* SD1 interface: 32-37 */
+	AU1300_PIN_SD1DAT0, AU1300_PIN_SD1DAT1, AU1300_PIN_SD1DAT2,
+	AU1300_PIN_SD1DAT3, AU1300_PIN_SD1CMD, AU1300_PIN_SD1CLK,
+	/* SD2 interface: 38-43 */
+	AU1300_PIN_SD2DAT0, AU1300_PIN_SD2DAT1, AU1300_PIN_SD2DAT2,
+	AU1300_PIN_SD2DAT3, AU1300_PIN_SD2CMD, AU1300_PIN_SD2CLK,
+	/* PSC0/1 clocks: 44-45 */
+	AU1300_PIN_PSC0CLK, AU1300_PIN_PSC1CLK,
+	/* PSCs: 46-49/50-53/54-57/58-61 */
+	AU1300_PIN_PSC0SYNC0, AU1300_PIN_PSC0SYNC1, AU1300_PIN_PSC0D0,
+	AU1300_PIN_PSC0D1,
+	AU1300_PIN_PSC1SYNC0, AU1300_PIN_PSC1SYNC1, AU1300_PIN_PSC1D0,
+	AU1300_PIN_PSC1D1,
+	AU1300_PIN_PSC2SYNC0,                       AU1300_PIN_PSC2D0,
+	AU1300_PIN_PSC2D1,
+	AU1300_PIN_PSC3SYNC0, AU1300_PIN_PSC3SYNC1, AU1300_PIN_PSC3D0,
+	AU1300_PIN_PSC3D1,
+	/* PCMCIA interface: 62-70 */
+	AU1300_PIN_PCE2, AU1300_PIN_PCE1, AU1300_PIN_PIOS16,
+	AU1300_PIN_PIOR, AU1300_PIN_PWE, AU1300_PIN_PWAIT,
+	AU1300_PIN_PREG, AU1300_PIN_POE, AU1300_PIN_PIOW,
+	/* camera interface H/V sync inputs: 71-72 */
+	AU1300_PIN_CIMLS, AU1300_PIN_CIMFS,
+	/* PSC2/3 clocks: 73-74 */
+	AU1300_PIN_PSC2CLK, AU1300_PIN_PSC3CLK,
+	-1,	/* terminator */
+};
+
+static void __init db1300_gpio_config(void)
+{
+	int *i;
+
+	i = &db1300_dev_pins[0];
+	while (*i != -1)
+		au1300_pinfunc_to_dev(*i++);
+
+	i = &db1300_gpio_pins[0];
+	while (*i != -1)
+		au1300_gpio_direction_input(*i++);/* implies pin_to_gpio */
+
+	au1300_set_dbdma_gpio(1, AU1300_PIN_FG3AUX);
+}
+
+char *get_system_type(void)
+{
+	return "DB1300";
+}
+
+/**********************************************************************/
+
+static void au1300_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+				 unsigned int ctrl)
+{
+	struct nand_chip *this = mtd->priv;
+	unsigned long ioaddr = (unsigned long)this->IO_ADDR_W;
+
+	ioaddr &= 0xffffff00;
+
+	if (ctrl & NAND_CLE) {
+		ioaddr += MEM_STNAND_CMD;
+	} else if (ctrl & NAND_ALE) {
+		ioaddr += MEM_STNAND_ADDR;
+	} else {
+		/* assume we want to r/w real data  by default */
+		ioaddr += MEM_STNAND_DATA;
+	}
+	this->IO_ADDR_R = this->IO_ADDR_W = (void __iomem *)ioaddr;
+	if (cmd != NAND_CMD_NONE) {
+		__raw_writeb(cmd, this->IO_ADDR_W);
+		wmb();
+	}
+}
+
+static int au1300_nand_device_ready(struct mtd_info *mtd)
+{
+	return __raw_readl((void __iomem *)MEM_STSTAT) & 1;
+}
+
+static const char *db1300_part_probes[] = { "cmdlinepart", NULL };
+
+static struct mtd_partition db1300_nand_parts[] = {
+	{
+		.name	= "NAND FS 0",
+		.offset	= 0,
+		.size	= 8 * 1024 * 1024,
+	},
+	{
+		.name	= "NAND FS 1",
+		.offset	= MTDPART_OFS_APPEND,
+		.size	= MTDPART_SIZ_FULL
+	},
+};
+
+struct platform_nand_data db1300_nand_platdata = {
+	.chip = {
+		.nr_chips	= 1,
+		.chip_offset	= 0,
+		.nr_partitions	= ARRAY_SIZE(db1300_nand_parts),
+		.partitions	= db1300_nand_parts,
+		.chip_delay	= 20,
+		.part_probe_types = db1300_part_probes,
+	},
+	.ctrl = {
+		.dev_ready	= au1300_nand_device_ready,
+		.cmd_ctrl	= au1300_nand_cmd_ctrl,
+	},
+};
+
+static struct resource db1300_nand_res[] = {
+	[0] = {
+		.start	= DB1300_NAND_PHYS_ADDR,
+		.end	= DB1300_NAND_PHYS_ADDR + 0xff,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device db1300_nand_dev = {
+	.name		= "gen_nand",
+	.num_resources	= ARRAY_SIZE(db1300_nand_res),
+	.resource	= db1300_nand_res,
+	.id		= -1,
+	.dev		= {
+		.platform_data = &db1300_nand_platdata,
+	}
+};
+
+/**********************************************************************/
+
+static struct resource db1300_eth_res[] = {
+	[0] = {
+		.start		= DB1300_ETH_PHYS_ADDR,
+		.end		= DB1300_ETH_PHYS_END,
+		.flags		= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start		= DB1300_ETH_INT,
+		.end		= DB1300_ETH_INT,
+		.flags		= IORESOURCE_IRQ,
+	},
+};
+
+static struct smsc911x_platform_config db1300_eth_config = {
+	.phy_interface		= PHY_INTERFACE_MODE_MII,
+	.irq_polarity		= SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+	.irq_type		= SMSC911X_IRQ_TYPE_PUSH_PULL,
+	.flags			= SMSC911X_USE_32BIT,
+};
+
+static struct platform_device db1300_eth_dev = {
+	.name			= "smsc911x",
+	.id			= -1,
+	.num_resources		= ARRAY_SIZE(db1300_eth_res),
+	.resource		= db1300_eth_res,
+	.dev = {
+		.platform_data	= &db1300_eth_config,
+	},
+};
+
+/**********************************************************************/
+
+static struct resource au1300_psc1_res[] = {
+	[0] = {
+		.start	= AU1300_PSC1_PHYS_ADDR,
+		.end	= AU1300_PSC1_PHYS_ADDR + 0x0fff,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AU1300_PSC1_INT,
+		.end	= AU1300_PSC1_INT,
+		.flags	= IORESOURCE_IRQ,
+	},
+	[2] = {
+		.start	= DSCR_CMD0_PSC1_TX,
+		.end	= DSCR_CMD0_PSC1_TX,
+		.flags	= IORESOURCE_DMA,
+	},
+	[3] = {
+		.start	= DSCR_CMD0_PSC1_RX,
+		.end	= DSCR_CMD0_PSC1_RX,
+		.flags	= IORESOURCE_DMA,
+	},
+};
+
+static struct platform_device db1300_ac97_dev = {
+	.name		= "au1xpsc_ac97",
+	.id		= 1,	/* PSC ID. match with AC97 codec ID! */
+	.num_resources	= ARRAY_SIZE(au1300_psc1_res),
+	.resource	= au1300_psc1_res,
+};
+
+/**********************************************************************/
+
+static struct resource au1300_psc2_res[] = {
+	[0] = {
+		.start	= AU1300_PSC2_PHYS_ADDR,
+		.end	= AU1300_PSC2_PHYS_ADDR + 0x0fff,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AU1300_PSC2_INT,
+		.end	= AU1300_PSC2_INT,
+		.flags	= IORESOURCE_IRQ,
+	},
+	[2] = {
+		.start	= DSCR_CMD0_PSC2_TX,
+		.end	= DSCR_CMD0_PSC2_TX,
+		.flags	= IORESOURCE_DMA,
+	},
+	[3] = {
+		.start	= DSCR_CMD0_PSC2_RX,
+		.end	= DSCR_CMD0_PSC2_RX,
+		.flags	= IORESOURCE_DMA,
+	},
+};
+
+static struct platform_device db1300_i2s_dev = {
+	.name		= "au1xpsc_i2s",
+	.id		= 2,	/* PSC ID */
+	.num_resources	= ARRAY_SIZE(au1300_psc2_res),
+	.resource	= au1300_psc2_res,
+};
+
+/**********************************************************************/
+
+static struct resource au1300_psc3_res[] = {
+	[0] = {
+		.start	= AU1300_PSC3_PHYS_ADDR,
+		.end	= AU1300_PSC3_PHYS_ADDR + 0x0fff,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AU1300_PSC3_INT,
+		.end	= AU1300_PSC3_INT,
+		.flags	= IORESOURCE_IRQ,
+	},
+	[2] = {
+		.start	= DSCR_CMD0_PSC3_TX,
+		.end	= DSCR_CMD0_PSC3_TX,
+		.flags	= IORESOURCE_DMA,
+	},
+	[3] = {
+		.start	= DSCR_CMD0_PSC3_RX,
+		.end	= DSCR_CMD0_PSC3_RX,
+		.flags	= IORESOURCE_DMA,
+	},
+};
+
+static struct platform_device db1300_i2c_dev = {
+	.name		= "au1xpsc_smbus",
+	.id		= 0,	/* bus number */
+	.num_resources	= ARRAY_SIZE(au1300_psc3_res),
+	.resource	= au1300_psc3_res,
+};
+
+/**********************************************************************/
+
+/* proper key assignments when facing the LCD panel.  For key assignments
+ * according to the schematics swap up with down and left with right.
+ * I chose to use it to emulate the arrow keys of a keyboard.
+ */
+static struct gpio_keys_button db1300_5waysw_arrowkeys[] = {
+	{
+		.code			= KEY_DOWN,
+		.gpio			= AU1300_PIN_LCDPWM0,
+		.type			= EV_KEY,
+		.debounce_interval	= 1,
+		.active_low		= 1,
+		.desc			= "5waysw-down",
+	},
+	{
+		.code			= KEY_UP,
+		.gpio			= AU1300_PIN_PSC2SYNC1,
+		.type			= EV_KEY,
+		.debounce_interval	= 1,
+		.active_low		= 1,
+		.desc			= "5waysw-up",
+	},
+	{
+		.code			= KEY_RIGHT,
+		.gpio			= AU1300_PIN_WAKE3,
+		.type			= EV_KEY,
+		.debounce_interval	= 1,
+		.active_low		= 1,
+		.desc			= "5waysw-right",
+	},
+	{
+		.code			= KEY_LEFT,
+		.gpio			= AU1300_PIN_WAKE2,
+		.type			= EV_KEY,
+		.debounce_interval	= 1,
+		.active_low		= 1,
+		.desc			= "5waysw-left",
+	},
+	{
+		.code			= KEY_ENTER,
+		.gpio			= AU1300_PIN_WAKE1,
+		.type			= EV_KEY,
+		.debounce_interval	= 1,
+		.active_low		= 1,
+		.desc			= "5waysw-push",
+	},
+};
+
+static struct gpio_keys_platform_data db1300_5waysw_data = {
+	.buttons	= db1300_5waysw_arrowkeys,
+	.nbuttons	= ARRAY_SIZE(db1300_5waysw_arrowkeys),
+	.rep		= 1,
+	.name		= "db1300-5wayswitch",
+};
+
+static struct platform_device db1300_5waysw_dev = {
+	.name		= "gpio-keys",
+	.dev	= {
+		.platform_data	= &db1300_5waysw_data,
+	},
+};
+
+/**********************************************************************/
+
+static struct platform_device db1300_rtc_dev = {
+	.name	= "rtc-au1xxx",
+	.id	= -1,
+};
+
+/**********************************************************************/
+
+static struct pata_platform_info db1300_ide_info = {
+	.ioport_shift	= DB1300_IDE_REG_SHIFT,
+};
+
+#define IDE_ALT_START	(14 << DB1300_IDE_REG_SHIFT)
+static struct resource db1300_ide_res[] = {
+	[0] = {
+		.start	= DB1300_IDE_PHYS_ADDR,
+		.end	= DB1300_IDE_PHYS_ADDR + IDE_ALT_START - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= DB1300_IDE_PHYS_ADDR + IDE_ALT_START,
+		.end	= DB1300_IDE_PHYS_ADDR + DB1300_IDE_PHYS_LEN - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[2] = {
+		.start	= DB1300_IDE_INT,
+		.end	= DB1300_IDE_INT,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device db1300_ide_dev = {
+	.dev	= {
+		.platform_data	= &db1300_ide_info,
+	},
+	.name		= "pata_platform",
+	.resource	= db1300_ide_res,
+	.num_resources	= ARRAY_SIZE(db1300_ide_res),
+};
+
+/**********************************************************************/
+
+static irqreturn_t db1300_mmc_cd(int irq, void *ptr)
+{
+	void(*mmc_cd)(struct mmc_host *, unsigned long);
+
+	/* disable the one currently screaming. No other way to shut it up */
+	if (irq == DB1300_SD1_INSERT_INT) {
+		disable_irq_nosync(DB1300_SD1_INSERT_INT);
+		enable_irq(DB1300_SD1_EJECT_INT);
+	} else {
+		disable_irq_nosync(DB1300_SD1_EJECT_INT);
+		enable_irq(DB1300_SD1_INSERT_INT);
+	}
+
+	/* link against CONFIG_MMC=m.  We can only be called once MMC core has
+	 * initialized the controller, so symbol_get() should always succeed.
+	 */
+	mmc_cd = symbol_get(mmc_detect_change);
+	mmc_cd(ptr, msecs_to_jiffies(500));
+	symbol_put(mmc_detect_change);
+
+	return IRQ_HANDLED;
+}
+
+static int db1300_mmc_card_readonly(void *mmc_host)
+{
+	/* it uses SD1 interface, but the DB1200's SD0 bit in the CPLD */
+	return bcsr_read(BCSR_STATUS) & BCSR_STATUS_SD0WP;
+}
+
+static int db1300_mmc_card_inserted(void *mmc_host)
+{
+	return bcsr_read(BCSR_SIGSTAT) & (1 << 12); /* insertion irq signal */
+}
+
+static int db1300_mmc_cd_setup(void *mmc_host, int en)
+{
+	int ret;
+
+	if (en) {
+		ret = request_irq(DB1300_SD1_INSERT_INT, db1300_mmc_cd, 0,
+				  "sd_insert", mmc_host);
+		if (ret)
+			goto out;
+
+		ret = request_irq(DB1300_SD1_EJECT_INT, db1300_mmc_cd, 0,
+				  "sd_eject", mmc_host);
+		if (ret) {
+			free_irq(DB1300_SD1_INSERT_INT, mmc_host);
+			goto out;
+		}
+
+		if (db1300_mmc_card_inserted(mmc_host))
+			enable_irq(DB1300_SD1_EJECT_INT);
+		else
+			enable_irq(DB1300_SD1_INSERT_INT);
+
+	} else {
+		free_irq(DB1300_SD1_INSERT_INT, mmc_host);
+		free_irq(DB1300_SD1_EJECT_INT, mmc_host);
+	}
+	ret = 0;
+out:
+	return ret;
+}
+
+static void db1300_mmcled_set(struct led_classdev *led,
+			      enum led_brightness brightness)
+{
+	if (brightness != LED_OFF)
+		bcsr_mod(BCSR_LEDS, BCSR_LEDS_LED0, 0);
+	else
+		bcsr_mod(BCSR_LEDS, 0, BCSR_LEDS_LED0);
+}
+
+static struct led_classdev db1300_mmc_led = {
+	.brightness_set	= db1300_mmcled_set,
+};
+
+struct au1xmmc_platform_data db1300_sd1_platdata = {
+	.cd_setup	= db1300_mmc_cd_setup,
+	.card_inserted	= db1300_mmc_card_inserted,
+	.card_readonly	= db1300_mmc_card_readonly,
+	.led		= &db1300_mmc_led,
+};
+
+static struct resource au1300_sd1_res[] = {
+	[0] = {
+		.start	= AU1300_SD1_PHYS_ADDR,
+		.end	= AU1300_SD1_PHYS_ADDR,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AU1300_SD1_INT,
+		.end	= AU1300_SD1_INT,
+		.flags	= IORESOURCE_IRQ,
+	},
+	[2] = {
+		.start	= DSCR_CMD0_SDMS_TX1,
+		.end	= DSCR_CMD0_SDMS_TX1,
+		.flags	= IORESOURCE_DMA,
+	},
+	[3] = {
+		.start	= DSCR_CMD0_SDMS_RX1,
+		.end	= DSCR_CMD0_SDMS_RX1,
+		.flags	= IORESOURCE_DMA,
+	},
+};
+
+static struct platform_device db1300_sd1_dev = {
+	.dev = {
+		.platform_data	= &db1300_sd1_platdata,
+	},
+	.name		= "au1xxx-mmc",
+	.id		= 1,
+	.resource	= au1300_sd1_res,
+	.num_resources	= ARRAY_SIZE(au1300_sd1_res),
+};
+
+/**********************************************************************/
+
+static int db1300_movinand_inserted(void *mmc_host)
+{
+	return 1;	/* it's soldered on */
+}
+
+static int db1300_movinand_readonly(void *mmc_host)
+{
+	return 0;
+}
+
+static void db1300_movinand_led_set(struct led_classdev *led,
+				    enum led_brightness brightness)
+{
+	if (brightness != LED_OFF)
+		bcsr_mod(BCSR_LEDS, BCSR_LEDS_LED1, 0);
+	else
+		bcsr_mod(BCSR_LEDS, 0, BCSR_LEDS_LED1);
+}
+
+static struct led_classdev db1300_movinand_led = {
+	.brightness_set		= db1300_movinand_led_set,
+};
+
+struct au1xmmc_platform_data db1300_sd0_platdata = {
+	.card_inserted		= db1300_movinand_inserted,
+	.card_readonly		= db1300_movinand_readonly,
+	.led			= &db1300_movinand_led,
+	.mask_host_caps		= MMC_CAP_NEEDS_POLL,
+};
+
+static struct resource au1300_sd0_res[] = {
+	[0] = {
+		.start	= AU1100_SD0_PHYS_ADDR,
+		.end	= AU1100_SD0_PHYS_ADDR,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AU1300_SD0_INT,
+		.end	= AU1300_SD0_INT,
+		.flags	= IORESOURCE_IRQ,
+	},
+	[2] = {
+		.start	= DSCR_CMD0_SDMS_TX0,
+		.end	= DSCR_CMD0_SDMS_TX0,
+		.flags	= IORESOURCE_DMA,
+	},
+	[3] = {
+		.start	= DSCR_CMD0_SDMS_RX0,
+		.end	= DSCR_CMD0_SDMS_RX0,
+		.flags	= IORESOURCE_DMA,
+	},
+};
+
+static struct platform_device db1300_sd0_dev = {
+	.dev = {
+		.platform_data	= &db1300_sd0_platdata,
+	},
+	.name		= "au1xxx-mmc",
+	.id		= 0,
+	.resource	= au1300_sd0_res,
+	.num_resources	= ARRAY_SIZE(au1300_sd0_res),
+};
+
+/**********************************************************************/
+
+static struct platform_device db1300_wm9715_dev = {
+	.name		= "wm9712-codec",
+	.id		= 1,	/* ID of PSC for AC97 audio, see asoc glue! */
+};
+
+/**********************************************************************/
+
+static struct resource au1300_lcd_resources[] = {
+	[0] = {
+		.start          = AU1200_LCD_PHYS_ADDR,
+		.end            = AU1200_LCD_PHYS_ADDR + 0x800 - 1,
+		.flags          = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start          = AU1300_LCD_INT,
+		.end            = AU1300_LCD_INT,
+		.flags          = IORESOURCE_IRQ,
+	}
+};
+
+static u64 au1300_lcd_dmamask = DMA_BIT_MASK(32);
+
+static struct platform_device db1300_lcd_dev = {
+	.name           = "au1200-lcd",
+	.id             = -1,
+	.dev = {
+		.dma_mask               = &au1300_lcd_dmamask,
+		.coherent_dma_mask      = DMA_BIT_MASK(32),
+	},
+	.num_resources  = ARRAY_SIZE(au1300_lcd_resources),
+	.resource       = au1300_lcd_resources,
+};
+
+/**********************************************************************/
+
+static struct platform_device *db1300_dev[] __initdata = {
+	&db1300_eth_dev,
+	&db1300_i2c_dev,
+	&db1300_5waysw_dev,
+	&db1300_rtc_dev,
+	&db1300_nand_dev,
+	&db1300_ide_dev,
+	&db1300_sd0_dev,
+	&db1300_sd1_dev,
+	&db1300_lcd_dev,
+	&db1300_ac97_dev,
+	&db1300_i2s_dev,
+	&db1300_wm9715_dev,
+};
+
+static int __init db1300_device_init(void)
+{
+	int swapped, cpldirq;
+
+	/*
+	 * setup CPLD IRQ muxer
+	 */
+	cpldirq = au1300_gpio_to_irq(AU1300_PIN_EXTCLK1);
+	irq_set_irq_type(cpldirq, IRQF_TRIGGER_HIGH);
+	bcsr_init_irq(DB1300_FIRST_INT, DB1300_LAST_INT, cpldirq);
+
+	/* insert/eject IRQs: one always triggers so don't enable them
+	 * when doing request_irq() on them.  DB1200 has this bug too.
+	 */
+	irq_set_status_flags(DB1300_SD1_INSERT_INT, IRQ_NOAUTOEN);
+	irq_set_status_flags(DB1300_SD1_EJECT_INT, IRQ_NOAUTOEN);
+	irq_set_status_flags(DB1300_CF_INSERT_INT, IRQ_NOAUTOEN);
+	irq_set_status_flags(DB1300_CF_EJECT_INT, IRQ_NOAUTOEN);
+
+	/*
+	 * setup board
+	 */
+	prom_get_ethernet_addr(&db1300_eth_config.mac[0]);
+
+	i2c_register_board_info(0, db1300_i2c_devs,
+				ARRAY_SIZE(db1300_i2c_devs));
+
+	/* Audio PSC clock is supplied by codecs (PSC1, 2) */
+	__raw_writel(PSC_SEL_CLK_SERCLK,
+		(void __iomem *)KSEG1ADDR(AU1300_PSC1_PHYS_ADDR) + PSC_SEL_OFFSET);
+	wmb();
+	__raw_writel(PSC_SEL_CLK_SERCLK,
+		(void __iomem *)KSEG1ADDR(AU1300_PSC2_PHYS_ADDR) + PSC_SEL_OFFSET);
+	wmb();
+	/* I2C uses internal 48MHz EXTCLK1 */
+	__raw_writel(PSC_SEL_CLK_INTCLK,
+		(void __iomem *)KSEG1ADDR(AU1300_PSC3_PHYS_ADDR) + PSC_SEL_OFFSET);
+	wmb();
+
+	/* enable power to USB ports */
+	bcsr_mod(BCSR_RESETS, 0, BCSR_RESETS_USBHPWR | BCSR_RESETS_OTGPWR);
+
+	/* although it is socket #0, it uses the CPLD bits which previous boards
+	 * have used for socket #1.
+	 */
+	db1x_register_pcmcia_socket(
+		AU1000_PCMCIA_ATTR_PHYS_ADDR,
+		AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x00400000 - 1,
+		AU1000_PCMCIA_MEM_PHYS_ADDR,
+		AU1000_PCMCIA_MEM_PHYS_ADDR  + 0x00400000 - 1,
+		AU1000_PCMCIA_IO_PHYS_ADDR,
+		AU1000_PCMCIA_IO_PHYS_ADDR   + 0x00010000 - 1,
+		DB1300_CF_INT, DB1300_CF_INSERT_INT, 0, DB1300_CF_EJECT_INT, 1);
+
+	swapped = bcsr_read(BCSR_STATUS) & BCSR_STATUS_DB1200_SWAPBOOT;
+	db1x_register_norflash(64 * 1024 * 1024, 2, swapped);
+
+	return platform_add_devices(db1300_dev, ARRAY_SIZE(db1300_dev));
+}
+device_initcall(db1300_device_init);
+
+
+void __init board_setup(void)
+{
+	unsigned short whoami;
+
+	db1300_gpio_config();
+	bcsr_init(DB1300_BCSR_PHYS_ADDR,
+		  DB1300_BCSR_PHYS_ADDR + DB1300_BCSR_HEXLED_OFS);
+
+	whoami = bcsr_read(BCSR_WHOAMI);
+	printk(KERN_INFO "NetLogic DBAu1300 Development Platform.\n\t"
+		"BoardID %d   CPLD Rev %d   DaughtercardID %d\n",
+		BCSR_WHOAMI_BOARD(whoami), BCSR_WHOAMI_CPLD(whoami),
+		BCSR_WHOAMI_DCID(whoami));
+
+	/* enable UARTs, YAMON only enables #2 */
+	alchemy_uart_enable(AU1300_UART0_PHYS_ADDR);
+	alchemy_uart_enable(AU1300_UART1_PHYS_ADDR);
+	alchemy_uart_enable(AU1300_UART3_PHYS_ADDR);
+}
+
+
+/* au1200fb calls these: STERBT EINEN TRAGISCHEN TOD!!! */
+int board_au1200fb_panel(void)
+{
+	return 9;	/* DB1300_800x480 */
+}
+
+int board_au1200fb_panel_init(void)
+{
+	/* Apply power (Vee/Vdd logic is inverted on Panel DB1300_800x480) */
+	bcsr_mod(BCSR_BOARD, BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD,
+			     BCSR_BOARD_LCDBL);
+	return 0;
+}
+
+int board_au1200fb_panel_shutdown(void)
+{
+	/* Remove power (Vee/Vdd logic is inverted on Panel DB1300_800x480) */
+	bcsr_mod(BCSR_BOARD, BCSR_BOARD_LCDBL,
+			     BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD);
+	return 0;
+}
diff --git a/arch/mips/alchemy/devboards/prom.c b/arch/mips/alchemy/devboards/prom.c
index e5306b5..14d855a 100644
--- a/arch/mips/alchemy/devboards/prom.c
+++ b/arch/mips/alchemy/devboards/prom.c
@@ -62,5 +62,9 @@ void __init prom_init(void)
 
 void prom_putchar(unsigned char c)
 {
+#ifdef CONFIG_MIPS_DB1300
+	alchemy_uart_putchar(AU1300_UART2_PHYS_ADDR, c);
+#else
 	alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c);
+#endif
 }
diff --git a/arch/mips/boot/compressed/uart-alchemy.c b/arch/mips/boot/compressed/uart-alchemy.c
index eb063e6..3112df8 100644
--- a/arch/mips/boot/compressed/uart-alchemy.c
+++ b/arch/mips/boot/compressed/uart-alchemy.c
@@ -2,6 +2,9 @@
 
 void putc(char c)
 {
-	/* all current (Jan. 2010) in-kernel boards */
+#ifdef CONFIG_MIPS_DB1300
+	alchemy_uart_putchar(AU1300_UART2_PHYS_ADDR, c);
+#else
 	alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c);
+#endif
 }
diff --git a/arch/mips/configs/db1300_defconfig b/arch/mips/configs/db1300_defconfig
new file mode 100644
index 0000000..c38b190
--- /dev/null
+++ b/arch/mips/configs/db1300_defconfig
@@ -0,0 +1,391 @@
+CONFIG_MIPS=y
+CONFIG_MIPS_ALCHEMY=y
+CONFIG_ALCHEMY_GPIOINT_AU1300=y
+CONFIG_MIPS_DB1300=y
+CONFIG_SOC_AU1300=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_ARCH_SUPPORTS_OPROFILE=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_SCHED_OMIT_FRAME_POINTER=y
+CONFIG_CEVT_R4K_LIB=y
+CONFIG_CSRC_R4K_LIB=y
+CONFIG_DMA_COHERENT=y
+CONFIG_SYS_HAS_EARLY_PRINTK=y
+CONFIG_MIPS_DISABLE_OBSOLETE_IDE=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_IRQ_CPU=y
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+CONFIG_CPU_MIPS32_R1=y
+CONFIG_SYS_SUPPORTS_ZBOOT=y
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_CPU_MIPS32=y
+CONFIG_CPU_MIPSR1=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_HARDWARE_WATCHPOINTS=y
+CONFIG_32BIT=y
+CONFIG_PAGE_SIZE_4KB=y
+CONFIG_FORCE_MAX_ZONEORDER=11
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_MIPS_MT_DISABLED=y
+CONFIG_64BIT_PHYS_ADDR=y
+CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_COMPACTION=y
+CONFIG_MIGRATION=y
+CONFIG_PHYS_ADDR_T_64BIT=y
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+CONFIG_NEED_PER_CPU_KM=y
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_HZ_100=y
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_HZ=100
+CONFIG_PREEMPT_NONE=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+CONFIG_HAVE_IRQ_WORK=y
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_CROSS_COMPILE=""
+CONFIG_LOCALVERSION="-db1300"
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_BZIP2=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_KERNEL_LZMA=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
+CONFIG_FHANDLE=y
+CONFIG_HAVE_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_TINY_RCU=y
+CONFIG_LOG_BUF_SHIFT=19
+CONFIG_NAMESPACES=y
+CONFIG_UTS_NS=y
+CONFIG_IPC_NS=y
+CONFIG_USER_NS=y
+CONFIG_PID_NS=y
+CONFIG_NET_NS=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EXPERT=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_EMBEDDED=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_PERF_USE_VMALLOC=y
+CONFIG_SLAB=y
+CONFIG_HAVE_OPROFILE=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_DMA_ATTRS=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+CONFIG_HAVE_ARCH_JUMP_LABEL=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+CONFIG_BLK_DEV_BSG=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+CONFIG_INLINE_SPIN_UNLOCK=y
+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
+CONFIG_INLINE_READ_UNLOCK=y
+CONFIG_INLINE_READ_UNLOCK_IRQ=y
+CONFIG_INLINE_WRITE_UNLOCK=y
+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
+CONFIG_MMU=y
+CONFIG_PCCARD=y
+CONFIG_PCMCIA=y
+CONFIG_PCMCIA_LOAD_CIS=y
+CONFIG_PCMCIA_ALCHEMY_DEVBOARD=y
+CONFIG_BINFMT_ELF=y
+CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
+CONFIG_TRAD_SIGNALS=y
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_INET_TUNNEL=y
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+CONFIG_IPV6=y
+CONFIG_INET6_XFRM_MODE_TRANSPORT=y
+CONFIG_INET6_XFRM_MODE_TUNNEL=y
+CONFIG_INET6_XFRM_MODE_BEET=y
+CONFIG_IPV6_SIT=y
+CONFIG_IPV6_NDISC_NODETYPE=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+CONFIG_MTD=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_UTIL=y
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_NAND_ECC=y
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_IDS=y
+CONFIG_MTD_NAND_PLATFORM=y
+CONFIG_BLK_DEV=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_UB=y
+CONFIG_HAVE_IDE=y
+CONFIG_IDE=y
+CONFIG_IDE_GD=y
+CONFIG_IDE_GD_ATA=y
+CONFIG_BLK_DEV_IDECS=y
+CONFIG_IDE_TASK_IOCTL=y
+CONFIG_IDE_PROC_FS=y
+CONFIG_BLK_DEV_PLATFORM=y
+CONFIG_SCSI_MOD=y
+CONFIG_NETDEVICES=y
+CONFIG_MII=y
+CONFIG_PHYLIB=y
+CONFIG_SMSC_PHY=y
+CONFIG_NET_ETHERNET=y
+CONFIG_SMSC911X=y
+CONFIG_INPUT=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_GPIO=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_WM97XX=y
+CONFIG_TOUCHSCREEN_WM9712=y
+CONFIG_TOUCHSCREEN_WM9713=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_SMBUS=y
+CONFIG_I2C_AU1550=y
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+CONFIG_SPI_AU1550=y
+CONFIG_SPI_BITBANG=y
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+CONFIG_HWMON=y
+CONFIG_HWMON_VID=y
+CONFIG_SENSORS_ADM1025=y
+CONFIG_FB=y
+CONFIG_FB_AU1200=y
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FONTS=y
+CONFIG_FONT_ACORN_8x8=y
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_CLUT224=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+CONFIG_SND_JACK=y
+CONFIG_SND_HRTIMER=y
+CONFIG_SND_DYNAMIC_MINORS=y
+CONFIG_SND_VERBOSE_PROCFS=y
+CONFIG_SND_VERBOSE_PRINTK=y
+CONFIG_SND_VMASTER=y
+CONFIG_SND_AC97_CODEC=y
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_CACHE_LZO=y
+CONFIG_SND_SOC_AC97_BUS=y
+CONFIG_SND_SOC_AU1XPSC=y
+CONFIG_SND_SOC_AU1XPSC_I2S=y
+CONFIG_SND_SOC_AU1XPSC_AC97=y
+CONFIG_SND_SOC_DB1300=y
+CONFIG_SND_SOC_I2C_AND_SPI=y
+CONFIG_SND_SOC_WM8731=y
+CONFIG_SND_SOC_WM9712=y
+CONFIG_AC97_BUS=y
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+CONFIG_HIDRAW=y
+CONFIG_USB_HID=y
+CONFIG_USB_HIDDEV=y
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+CONFIG_USB_DYNAMIC_MINORS=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_EHCI_TT_NEWSCHED=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+CONFIG_RTC_INTF_DEV_UIE_EMUL=y
+CONFIG_RTC_DRV_AU1XXX=y
+CONFIG_EXT2_FS=y
+CONFIG_FS_POSIX_ACL=y
+CONFIG_EXPORTFS=y
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY_USER=y
+CONFIG_GENERIC_ACL=y
+CONFIG_FAT_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_TMPFS_XATTR=y
+CONFIG_MISC_FILESYSTEMS=y
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+CONFIG_JFFS2_SUMMARY=y
+CONFIG_JFFS2_FS_XATTR=y
+CONFIG_JFFS2_FS_POSIX_ACL=y
+CONFIG_JFFS2_FS_SECURITY=y
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_LZO=y
+CONFIG_JFFS2_RTIME=y
+CONFIG_JFFS2_RUBIN=y
+CONFIG_JFFS2_CMODE_PRIORITY=y
+CONFIG_SQUASHFS=y
+CONFIG_SQUASHFS_XZ=y
+CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_MSDOS_PARTITION=y
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_850=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_15=y
+CONFIG_NLS_UTF8=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_STRIP_ASM_SYMS=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_TRACING_SUPPORT=y
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="video=au1200fb:panel:bs console=tty console=ttyS2,115200"
+CONFIG_DEBUG_ZBOOT=y
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_DEFAULT_SECURITY=""
+CONFIG_CRYPTO=y
+CONFIG_BITREVERSE=y
+CONFIG_CRC32=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_XZ_DEC=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
diff --git a/arch/mips/include/asm/mach-db1x00/bcsr.h b/arch/mips/include/asm/mach-db1x00/bcsr.h
index 618d2de..0ef6300 100644
--- a/arch/mips/include/asm/mach-db1x00/bcsr.h
+++ b/arch/mips/include/asm/mach-db1x00/bcsr.h
@@ -34,6 +34,8 @@
 #define PB1200_BCSR_PHYS_ADDR	0x0D800000
 #define PB1200_BCSR_HEXLED_OFS	0x00400000
 
+#define DB1300_BCSR_PHYS_ADDR	0x19800000
+#define DB1300_BCSR_HEXLED_OFS	0x00400000
 
 enum bcsr_id {
 	/* BCSR base 1 */
@@ -105,6 +107,7 @@ enum bcsr_whoami_boards {
 	BCSR_WHOAMI_PB1200 = BCSR_WHOAMI_PB1200_DDR1,
 	BCSR_WHOAMI_PB1200_DDR2,
 	BCSR_WHOAMI_DB1200,
+	BCSR_WHOAMI_DB1300,
 };
 
 /* STATUS reg.  Unless otherwise noted, they're valid on all boards.
@@ -118,12 +121,12 @@ enum bcsr_whoami_boards {
 #define BCSR_STATUS_SRAMWIDTH		0x0080
 #define BCSR_STATUS_FLASHBUSY		0x0100
 #define BCSR_STATUS_ROMBUSY		0x0400
-#define BCSR_STATUS_SD0WP		0x0400	/* DB1200 */
+#define BCSR_STATUS_SD0WP		0x0400	/* DB1200/DB1300:SD1 */
 #define BCSR_STATUS_SD1WP		0x0800
 #define BCSR_STATUS_USBOTGID		0x0800	/* PB/DB1550 */
 #define BCSR_STATUS_DB1000_SWAPBOOT	0x2000
-#define BCSR_STATUS_DB1200_SWAPBOOT	0x0040	/* DB1200 */
-#define BCSR_STATUS_IDECBLID		0x0200	/* DB1200 */
+#define BCSR_STATUS_DB1200_SWAPBOOT	0x0040	/* DB1200/1300 */
+#define BCSR_STATUS_IDECBLID		0x0200	/* DB1200/1300 */
 #define BCSR_STATUS_DB1200_U0RXD	0x1000	/* DB1200 */
 #define BCSR_STATUS_DB1200_U1RXD	0x2000	/* DB1200 */
 #define BCSR_STATUS_FLASHDEN		0xC000
@@ -133,6 +136,11 @@ enum bcsr_whoami_boards {
 #define BCSR_STATUS_PB1550_U1RXD	0x2000	/* PB1550 */
 #define BCSR_STATUS_PB1550_U3RXD	0x8000	/* PB1550 */
 
+#define BCSR_STATUS_CFWP		0x4000	/* DB1300 */
+#define BCSR_STATUS_USBOCn		0x2000	/* DB1300 */
+#define BCSR_STATUS_OTGOCn		0x1000	/* DB1300 */
+#define BCSR_STATUS_DCDMARQ		0x0010	/* DB1300 */
+#define BCSR_STATUS_IDEDMARQ		0x0020	/* DB1300 */
 
 /* DB/PB1000,1100,1500,1550 */
 #define BCSR_RESETS_PHY0		0x0001
@@ -160,12 +168,12 @@ enum bcsr_whoami_boards {
 #define BCSR_BOARD_SD1WP		0x8000	/* DB1100 */
 
 
-/* DB/PB1200 */
+/* DB/PB1200/1300 */
 #define BCSR_RESETS_ETH			0x0001
 #define BCSR_RESETS_CAMERA		0x0002
 #define BCSR_RESETS_DC			0x0004
 #define BCSR_RESETS_IDE			0x0008
-#define BCSR_RESETS_TV			0x0010	/* DB1200 */
+#define BCSR_RESETS_TV			0x0010	/* DB1200/1300 */
 /* Not resets but in the same register */
 #define BCSR_RESETS_PWMR1MUX		0x0800	/* DB1200 */
 #define BCSR_RESETS_PB1200_WSCFSM	0x0800	/* PB1200 */
@@ -174,13 +182,22 @@ enum bcsr_whoami_boards {
 #define BCSR_RESETS_SPISEL		0x4000
 #define BCSR_RESETS_SD1MUX		0x8000	/* PB1200 */
 
+#define BCSR_RESETS_VDDQSHDN		0x0200	/* DB1300 */
+#define BCSR_RESETS_OTPPGM		0x0400	/* DB1300 */
+#define BCSR_RESETS_OTPSCLK		0x0800	/* DB1300 */
+#define BCSR_RESETS_OTPWRPROT		0x1000	/* DB1300 */
+#define BCSR_RESETS_OTPCSB		0x2000	/* DB1300 */
+#define BCSR_RESETS_OTGPWR		0x4000	/* DB1300 */
+#define BCSR_RESETS_USBHPWR		0x8000  /* DB1300 */
+
 #define BCSR_BOARD_LCDVEE		0x0001
 #define BCSR_BOARD_LCDVDD		0x0002
 #define BCSR_BOARD_LCDBL		0x0004
 #define BCSR_BOARD_CAMSNAP		0x0010
 #define BCSR_BOARD_CAMPWR		0x0020
 #define BCSR_BOARD_SD0PWR		0x0040
-
+#define BCSR_BOARD_CAMCS		0x0010	/* DB1300 */
+#define BCSR_BOARD_HDMI_DE		0x0040	/* DB1300 */
 
 #define BCSR_SWITCHES_DIP		0x00FF
 #define BCSR_SWITCHES_DIP_1		0x0080
@@ -214,7 +231,10 @@ enum bcsr_whoami_boards {
 #define BCSR_SYSTEM_RESET		0x8000	/* clear to reset */
 #define BCSR_SYSTEM_PWROFF		0x4000	/* set to power off */
 #define BCSR_SYSTEM_VDDI		0x001F	/* PB1xxx boards */
-
+#define BCSR_SYSTEM_DEBUGCSMASK		0x003F	/* DB1300 */
+#define BCSR_SYSTEM_UDMAMODE		0x0100	/* DB1300 */
+#define BCSR_SYSTEM_WAKEONIRQ		0x0200	/* DB1300 */
+#define BCSR_SYSTEM_VDDI1300		0x3C00	/* DB1300 */
 
 
 
diff --git a/arch/mips/include/asm/mach-db1x00/db1300.h b/arch/mips/include/asm/mach-db1x00/db1300.h
new file mode 100644
index 0000000..7fe5fb3
--- /dev/null
+++ b/arch/mips/include/asm/mach-db1x00/db1300.h
@@ -0,0 +1,40 @@
+/*
+ * NetLogic DB1300 board constants
+ */
+
+#ifndef _DB1300_H_
+#define _DB1300_H_
+
+/* FPGA (external mux) interrupt sources */
+#define DB1300_FIRST_INT	(ALCHEMY_GPIC_INT_LAST + 1)
+#define DB1300_IDE_INT		(DB1300_FIRST_INT + 0)
+#define DB1300_ETH_INT		(DB1300_FIRST_INT + 1)
+#define DB1300_CF_INT		(DB1300_FIRST_INT + 2)
+#define DB1300_VIDEO_INT	(DB1300_FIRST_INT + 4)
+#define DB1300_HDMI_INT		(DB1300_FIRST_INT + 5)
+#define DB1300_DC_INT		(DB1300_FIRST_INT + 6)
+#define DB1300_FLASH_INT	(DB1300_FIRST_INT + 7)
+#define DB1300_CF_INSERT_INT	(DB1300_FIRST_INT + 8)
+#define DB1300_CF_EJECT_INT	(DB1300_FIRST_INT + 9)
+#define DB1300_AC97_INT		(DB1300_FIRST_INT + 10)
+#define DB1300_AC97_PEN_INT	(DB1300_FIRST_INT + 11)
+#define DB1300_SD1_INSERT_INT	(DB1300_FIRST_INT + 12)
+#define DB1300_SD1_EJECT_INT	(DB1300_FIRST_INT + 13)
+#define DB1300_OTG_VBUS_OC_INT	(DB1300_FIRST_INT + 14)
+#define DB1300_HOST_VBUS_OC_INT	(DB1300_FIRST_INT + 15)
+#define DB1300_LAST_INT		(DB1300_FIRST_INT + 15)
+
+/* SMSC9210 CS */
+#define DB1300_ETH_PHYS_ADDR	0x19000000
+#define DB1300_ETH_PHYS_END	0x197fffff
+
+/* ATA CS */
+#define DB1300_IDE_PHYS_ADDR	0x18800000
+#define DB1300_IDE_REG_SHIFT	5
+#define DB1300_IDE_PHYS_LEN	(16 << DB1300_IDE_REG_SHIFT)
+
+/* NAND CS */
+#define DB1300_NAND_PHYS_ADDR	0x20000000
+#define DB1300_NAND_PHYS_END	0x20000fff
+
+#endif	/* _DB1300_H_ */
diff --git a/arch/mips/include/asm/mach-db1x00/irq.h b/arch/mips/include/asm/mach-db1x00/irq.h
new file mode 100644
index 0000000..15b2669
--- /dev/null
+++ b/arch/mips/include/asm/mach-db1x00/irq.h
@@ -0,0 +1,23 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2003 by Ralf Baechle
+ */
+#ifndef __ASM_MACH_GENERIC_IRQ_H
+#define __ASM_MACH_GENERIC_IRQ_H
+
+
+#ifdef NR_IRQS
+#undef NR_IRQS
+#endif
+
+#ifndef MIPS_CPU_IRQ_BASE
+#define MIPS_CPU_IRQ_BASE 0
+#endif
+
+/* 8 (MIPS) + 128 (au1300) + 16 (cpld) */
+#define NR_IRQS 152
+
+#endif /* __ASM_MACH_GENERIC_IRQ_H */
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
index 6e318ce..af497ca 100644
--- a/drivers/pcmcia/Kconfig
+++ b/drivers/pcmcia/Kconfig
@@ -165,8 +165,8 @@ config PCMCIA_ALCHEMY_DEVBOARD
 	select 64BIT_PHYS_ADDR
 	help
 	  Enable this driver of you want PCMCIA support on your Alchemy
-	  Db1000, Db/Pb1100, Db/Pb1500, Db/Pb1550, Db/Pb1200 board.
-	  NOT suitable for the PB1000!
+	  Db1000, Db/Pb1100, Db/Pb1500, Db/Pb1550, Db/Pb1200, DB1300
+	  board.  NOT suitable for the PB1000!
 
 	  This driver is also available as a module called db1xxx_ss.ko
 
diff --git a/drivers/pcmcia/db1xxx_ss.c b/drivers/pcmcia/db1xxx_ss.c
index 01757f1..984f431 100644
--- a/drivers/pcmcia/db1xxx_ss.c
+++ b/drivers/pcmcia/db1xxx_ss.c
@@ -7,7 +7,7 @@
 
 /* This is a fairly generic PCMCIA socket driver suitable for the
  * following Alchemy Development boards:
- *  Db1000, Db/Pb1500, Db/Pb1100, Db/Pb1550, Db/Pb1200.
+ *  Db1000, Db/Pb1500, Db/Pb1100, Db/Pb1550, Db/Pb1200, Db1300
  *
  * The Db1000 is used as a reference:  Per-socket card-, carddetect- and
  *  statuschange IRQs connected to SoC GPIOs, control and status register
@@ -18,6 +18,7 @@
  *	- Pb1100/Pb1500:  single socket only; voltage key bits VS are
  *			  at STATUS[5:4] (instead of STATUS[1:0]).
  *	- Au1200-based:	  additional card-eject irqs, irqs not gpios!
+ *	- Db1300:	  Db1200-like, no pwr ctrl, single socket (#1).
  */
 
 #include <linux/delay.h>
@@ -58,11 +59,17 @@ struct db1x_pcmcia_sock {
 #define BOARD_TYPE_DEFAULT	0	/* most boards */
 #define BOARD_TYPE_DB1200	1	/* IRQs aren't gpios */
 #define BOARD_TYPE_PB1100	2	/* VS bits slightly different */
+#define BOARD_TYPE_DB1300	3	/* no power control */
 	int	board_type;
 };
 
 #define to_db1x_socket(x) container_of(x, struct db1x_pcmcia_sock, socket)
 
+static int db1300_card_inserted(struct db1x_pcmcia_sock *sock)
+{
+	return bcsr_read(BCSR_SIGSTAT) & (1 << 8);
+}
+
 /* DB/PB1200: check CPLD SIGSTATUS register bit 10/12 */
 static int db1200_card_inserted(struct db1x_pcmcia_sock *sock)
 {
@@ -83,6 +90,8 @@ static int db1x_card_inserted(struct db1x_pcmcia_sock *sock)
 	switch (sock->board_type) {
 	case BOARD_TYPE_DB1200:
 		return db1200_card_inserted(sock);
+	case BOARD_TYPE_DB1300:
+		return db1300_card_inserted(sock);
 	default:
 		return db1000_card_inserted(sock);
 	}
@@ -159,7 +168,8 @@ static int db1x_pcmcia_setup_irqs(struct db1x_pcmcia_sock *sock)
 	 * ejection handler have been registered and the currently
 	 * active one disabled.
 	 */
-	if (sock->board_type == BOARD_TYPE_DB1200) {
+	if ((sock->board_type == BOARD_TYPE_DB1200) ||
+	    (sock->board_type == BOARD_TYPE_DB1300)) {
 		ret = request_irq(sock->insert_irq, db1200_pcmcia_cdirq,
 				  IRQF_DISABLED, "pcmcia_insert", sock);
 		if (ret)
@@ -173,7 +183,7 @@ static int db1x_pcmcia_setup_irqs(struct db1x_pcmcia_sock *sock)
 		}
 
 		/* enable the currently silent one */
-		if (db1200_card_inserted(sock))
+		if (db1x_card_inserted(sock))
 			enable_irq(sock->eject_irq);
 		else
 			enable_irq(sock->insert_irq);
@@ -269,7 +279,8 @@ static int db1x_pcmcia_configure(struct pcmcia_socket *skt,
 	}
 
 	/* create new voltage code */
-	cr_set |= ((v << 2) | p) << (sock->nr * 8);
+	if (sock->board_type != BOARD_TYPE_DB1300)
+		cr_set |= ((v << 2) | p) << (sock->nr * 8);
 
 	changed = state->flags ^ sock->old_flags;
 
@@ -342,6 +353,10 @@ static int db1x_pcmcia_get_status(struct pcmcia_socket *skt,
 	/* if Vcc is not zero, we have applied power to a card */
 	status |= GET_VCC(cr, sock->nr) ? SS_POWERON : 0;
 
+	/* DB1300: power always on, but don't tell when no card present */
+	if ((sock->board_type == BOARD_TYPE_DB1300) && (status & SS_DETECT))
+		status = SS_POWERON | SS_3VCARD | SS_DETECT;
+
 	/* reset de-asserted? then we're ready */
 	status |= (GET_RESET(cr, sock->nr)) ? SS_READY : SS_RESET;
 
@@ -418,6 +433,9 @@ static int __devinit db1x_pcmcia_socket_probe(struct platform_device *pdev)
 	case BCSR_WHOAMI_PB1200 ... BCSR_WHOAMI_DB1200:
 		sock->board_type = BOARD_TYPE_DB1200;
 		break;
+	case BCSR_WHOAMI_DB1300:
+		sock->board_type = BOARD_TYPE_DB1300;
+		break;
 	default:
 		printk(KERN_INFO "db1xxx-ss: unknown board %d!\n", bid);
 		ret = -ENODEV;
diff --git a/drivers/video/au1200fb.c b/drivers/video/au1200fb.c
index ed5dcdb2..e6d3478 100644
--- a/drivers/video/au1200fb.c
+++ b/drivers/video/au1200fb.c
@@ -639,6 +639,42 @@ static struct panel_settings known_lcd_panels[] =
 		856, 856,
 		480, 480,
 	},
+	[9] = {
+		.name = "DB1300_800x480",
+		.monspecs = {
+			.modedb = NULL,
+			.modedb_len = 0,
+			.hfmin = 30000,
+			.hfmax = 70000,
+			.vfmin = 60,
+			.vfmax = 60,
+			.dclkmin = 6000000,
+			.dclkmax = 28000000,
+			.input = FB_DISP_RGB,
+		},
+		.mode_screen		= LCD_SCREEN_SX_N(800) |
+					  LCD_SCREEN_SY_N(480),
+		.mode_horztiming	= LCD_HORZTIMING_HPW_N(5) |
+					  LCD_HORZTIMING_HND1_N(16) |
+					  LCD_HORZTIMING_HND2_N(8),
+		.mode_verttiming	= LCD_VERTTIMING_VPW_N(4) |
+					  LCD_VERTTIMING_VND1_N(8) |
+					  LCD_VERTTIMING_VND2_N(5),
+		.mode_clkcontrol	= LCD_CLKCONTROL_PCD_N(1) |
+					  LCD_CLKCONTROL_IV |
+					  LCD_CLKCONTROL_IH,
+		.mode_pwmdiv		= 0x00000000,
+		.mode_pwmhi		= 0x00000000,
+		.mode_outmask		= 0x00FFFFFF,
+		.mode_fifoctrl		= 0x2f2f2f2f,
+		.mode_toyclksrc		= 0x00000004, /* AUXPLL directly */
+		.mode_backlight		= 0x00000000,
+		.mode_auxpll		= (48/12) * 2,
+		.device_init		= board_au1200fb_panel_init,
+		.device_shutdown	= board_au1200fb_panel_shutdown,
+		800, 800,
+		480, 480,
+	},
 };
 
 #define NUM_PANELS (ARRAY_SIZE(known_lcd_panels))
diff --git a/sound/soc/au1x/Kconfig b/sound/soc/au1x/Kconfig
index 894428b..8567e78 100644
--- a/sound/soc/au1x/Kconfig
+++ b/sound/soc/au1x/Kconfig
@@ -32,3 +32,15 @@ config SND_SOC_DB1200
 	help
 	  Select this option to enable audio (AC97 or I2S) on the
 	  Alchemy/AMD/RMI DB1200 demoboard.
+
+config SND_SOC_DB1300
+	tristate "DB1300 audio support"
+	depends on SND_SOC_AU1XPSC
+	select SND_SOC_AU1XPSC_AC97
+	select SND_SOC_WM9712
+	select SND_SOC_AU1XPSC_I2S
+	select SND_SOC_WM8731
+	help
+	  Select this option to enable AC97 and I2S audio on the
+	  RMI/NetLogic DB1300 demoboard.  If you need touchscreen
+	  support you definitely want to say Y here.
diff --git a/sound/soc/au1x/Makefile b/sound/soc/au1x/Makefile
index 1687307..21b1061 100644
--- a/sound/soc/au1x/Makefile
+++ b/sound/soc/au1x/Makefile
@@ -9,5 +9,7 @@ obj-$(CONFIG_SND_SOC_AU1XPSC_AC97) += snd-soc-au1xpsc-ac97.o
 
 # Boards
 snd-soc-db1200-objs := db1200.o
+snd-soc-db1300-objs := db1300.o
 
 obj-$(CONFIG_SND_SOC_DB1200) += snd-soc-db1200.o
+obj-$(CONFIG_SND_SOC_DB1300) += snd-soc-db1300.o
diff --git a/sound/soc/au1x/db1200.c b/sound/soc/au1x/db1200.c
index 1d3e258..d20b7f4 100644
--- a/sound/soc/au1x/db1200.c
+++ b/sound/soc/au1x/db1200.c
@@ -95,6 +95,10 @@ static int __init db1200_audio_load(void)
 {
 	int ret;
 
+	/* impostor check */
+	if (BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI)) != BCSR_WHOAMI_DB1200)
+		return -ENODEV;
+
 	ret = -ENOMEM;
 	db1200_asoc_dev = platform_device_alloc("soc-audio", 1); /* PSC1 */
 	if (!db1200_asoc_dev)
diff --git a/sound/soc/au1x/db1300.c b/sound/soc/au1x/db1300.c
new file mode 100644
index 0000000..46d4070
--- /dev/null
+++ b/sound/soc/au1x/db1300.c
@@ -0,0 +1,147 @@
+/*
+ * DB1300 ASoC audio fabric support code.
+ *
+ * (c) 2010 Manuel Lauss <manuel.lauss@googlemail.com>
+ *
+ * DB1300: AC97(WM9715) on PSC1, I2S(WM8731) on PSC2
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <asm/mach-au1x00/au1000.h>
+#include <asm/mach-au1x00/au1xxx_psc.h>
+#include <asm/mach-au1x00/au1xxx_dbdma.h>
+#include <asm/mach-db1x00/bcsr.h>
+
+#include "../codecs/wm8731.h"
+#include "../codecs/wm9712.h"
+#include "psc.h"
+
+/*-------------------------  AC97 PART  ---------------------------*/
+
+static struct snd_soc_dai_link db1300_ac97_dai = {
+	.name		= "AC97",
+	.stream_name	= "AC97 HiFi",
+	.codec_dai_name	= "wm9712-hifi",
+	.cpu_dai_name	= "au1xpsc_ac97.1",
+	.platform_name	= "au1xpsc-pcm.1",
+	.codec_name	= "wm9712-codec.1",
+};
+
+static struct snd_soc_card db1300_ac97_machine = {
+	.name		= "DB1300_AC97",
+	.dai_link	= &db1300_ac97_dai,
+	.num_links	= 1,
+};
+
+/*-------------------------  I2S PART  ---------------------------*/
+
+static int db1300_i2s_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	int ret;
+
+	/* WM8731 has its own 12MHz crystal */
+	snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL,
+				12000000, SND_SOC_CLOCK_IN);
+
+	/* codec is bitclock and lrclk master */
+	ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_LEFT_J |
+			SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+	if (ret < 0)
+		goto out;
+
+	ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_LEFT_J |
+			SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+	if (ret < 0)
+		goto out;
+
+	ret = 0;
+out:
+	return ret;
+}
+
+static struct snd_soc_ops db1300_i2s_wm8731_ops = {
+	.startup	= db1300_i2s_startup,
+};
+
+static struct snd_soc_dai_link db1300_i2s_dai = {
+	.name		= "WM8731",
+	.stream_name	= "WM8731 PCM",
+	.codec_dai_name	= "wm8731-hifi",
+	.cpu_dai_name	= "au1xpsc_i2s.2",
+	.platform_name	= "au1xpsc-pcm.2",
+	.codec_name	= "wm8731.0-001b",
+	.ops		= &db1300_i2s_wm8731_ops,
+};
+
+static struct snd_soc_card db1300_i2s_machine = {
+	.name		= "DB1300_I2S",
+	.dai_link	= &db1300_i2s_dai,
+	.num_links	= 1,
+};
+
+/*-------------------------  COMMON PART  ---------------------------*/
+
+static struct platform_device *db1300_ac97_dev, *db1300_i2s_dev;
+
+static int __init db1300_audio_load(void)
+{
+	int ret;
+
+	/* impostor check */
+	if (BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI)) != BCSR_WHOAMI_DB1300)
+		return -ENODEV;
+
+	ret = -ENOMEM;
+	db1300_ac97_dev = platform_device_alloc("soc-audio", 1); /* PSC1 */
+	if (!db1300_ac97_dev)
+		goto out;
+	platform_set_drvdata(db1300_ac97_dev, &db1300_ac97_machine);
+
+	db1300_i2s_dev = platform_device_alloc("soc-audio", 2); /* PSC2 */
+	if (!db1300_i2s_dev)
+		goto out;
+	platform_set_drvdata(db1300_i2s_dev, &db1300_i2s_machine);
+
+	ret = platform_device_add(db1300_ac97_dev);
+	if (ret) {
+		platform_device_put(db1300_ac97_dev);
+		db1300_ac97_dev = NULL;
+		printk(KERN_ERR "DB1300: failed to register AC97 audio\n");
+	}
+
+	ret = platform_device_add(db1300_i2s_dev);
+	if (ret) {
+		platform_device_put(db1300_i2s_dev);
+		db1300_i2s_dev = NULL;
+		printk(KERN_ERR "DB1300: failed to register I2S audio\n");
+	}
+
+out:
+	return ret;
+}
+
+static void __exit db1300_audio_unload(void)
+{
+	if (db1300_i2s_dev)
+		platform_device_unregister(db1300_i2s_dev);
+	if (db1300_ac97_dev)
+		platform_device_unregister(db1300_ac97_dev);
+}
+
+module_init(db1300_audio_load);
+module_exit(db1300_audio_unload);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("DB1300 ASoC audio support");
+MODULE_AUTHOR("Manuel Lauss");
-- 
1.7.6


From rvossen@broadcom.com Fri Jul 15 14:30:40 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 15 Jul 2011 14:30:47 +0200 (CEST)
Received: from mms1.broadcom.com ([216.31.210.17]:1049 "EHLO mms1.broadcom.com"
        rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org with ESMTP
        id S1491791Ab1GOMak (ORCPT <rfc822;linux-mips@linux-mips.org>);
        Fri, 15 Jul 2011 14:30:40 +0200
Received: from [10.9.200.133] by mms1.broadcom.com with ESMTP (Broadcom
 SMTP Relay (Email Firewall v6.3.2)); Fri, 15 Jul 2011 05:35:31 -0700
X-Server-Uuid: 02CED230-5797-4B57-9875-D5D2FEE4708A
Received: from mail-irva-13.broadcom.com (10.11.16.103) by
 IRVEXCHHUB02.corp.ad.broadcom.com (10.9.200.133) with Microsoft SMTP
 Server id 8.2.247.2; Fri, 15 Jul 2011 05:30:04 -0700
Received: from mail-sj1-12.sj.broadcom.com (mail-sj1-12.sj.broadcom.com
 [10.17.16.106]) by mail-irva-13.broadcom.com (Postfix) with ESMTP id
 2C63A74D03; Fri, 15 Jul 2011 05:30:18 -0700 (PDT)
Received: from [10.176.68.26] (unknown [10.176.68.26]) by
 mail-sj1-12.sj.broadcom.com (Postfix) with ESMTP id 9A23520501; Fri, 15
 Jul 2011 05:30:16 -0700 (PDT)
Message-ID: <4E2032D7.9000704@broadcom.com>
Date:   Fri, 15 Jul 2011 14:30:15 +0200
From:   "Roland Vossen" <rvossen@broadcom.com>
Organization: Broadcom
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.17)
 Gecko/20110424 Thunderbird/3.1.10
MIME-Version: 1.0
To:     "Rafael J. Wysocki" <rjw@sisk.pl>
cc:     "Jonas Gorski" <jonas.gorski@gmail.com>,
        "Geert Uytterhoeven" <geert@linux-m68k.org>,
        "devel@linuxdriverproject.org" <devel@linuxdriverproject.org>,
        "linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
        "linux-mips@linux-mips.org" <linux-mips@linux-mips.org>
Subject: Re: Status of MIPS on 3.0.0-rc6 kernel
References: <4E1ECE3B.10308@broadcom.com>
 <CAOiHx=kznEFL1BELeg2psg9yw+=-A5reunG0VYTu89DGKwrSzA@mail.gmail.com>
 <201107142151.24763.rjw@sisk.pl>
In-Reply-To: <201107142151.24763.rjw@sisk.pl>
X-WSS-ID: 623EEB993B421038137-01-01
Content-Type: text/plain;
 charset=utf-8;
 format=flowed
Content-Transfer-Encoding: 7bit
X-archive-position: 30627
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: rvossen@broadcom.com
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 10931
Content-Length: 2485
Lines: 89

> Please check if the appended patch helps.

It does, I am able to build a big endian MIPS kernel now. Can you notify 
me if you submit this patch ?

Thanks, Roland.

>
> Thanks,
> Rafael
>
> ---
> From: Rafael J. Wysocki<rjw@sisk.pl>
> Subject: MIPS: Convert i8259.c to using syscore_ops
>
> The code in arch/mips/kernel/i8259.c still hasn't been converted to
> using struct syscore_ops instead of a sysdev for resume and shutdown.
> As a result, this code doesn't build any more after suspend, resume
> and shutdown callbacks have been removed from struct sysdev_class.
> Fix this problem by converting i8259.c to using syscore_ops.
>
> Signed-off-by: Rafael J. Wysocki<rjw@sisk.pl>
> ---
>   arch/mips/kernel/i8259.c |   22 ++++++----------------
>   1 file changed, 6 insertions(+), 16 deletions(-)
>
> Index: linux-2.6/arch/mips/kernel/i8259.c
> ===================================================================
> --- linux-2.6.orig/arch/mips/kernel/i8259.c
> +++ linux-2.6/arch/mips/kernel/i8259.c
> @@ -14,7 +14,7 @@
>   #include<linux/interrupt.h>
>   #include<linux/kernel.h>
>   #include<linux/spinlock.h>
> -#include<linux/sysdev.h>
> +#include<linux/syscore_ops.h>
>   #include<linux/irq.h>
>
>   #include<asm/i8259.h>
> @@ -215,14 +215,13 @@ spurious_8259A_irq:
>   	}
>   }
>
> -static int i8259A_resume(struct sys_device *dev)
> +static void i8259A_resume(void)
>   {
>   	if (i8259A_auto_eoi>= 0)
>   		init_8259A(i8259A_auto_eoi);
> -	return 0;
>   }
>
> -static int i8259A_shutdown(struct sys_device *dev)
> +static void i8259A_shutdown(void)
>   {
>   	/* Put the i8259A into a quiescent state that
>   	 * the kernel initialization code can get it
> @@ -232,26 +231,17 @@ static int i8259A_shutdown(struct sys_de
>   		outb(0xff, PIC_MASTER_IMR);	/* mask all of 8259A-1 */
>   		outb(0xff, PIC_SLAVE_IMR);	/* mask all of 8259A-1 */
>   	}
> -	return 0;
>   }
>
> -static struct sysdev_class i8259_sysdev_class = {
> -	.name = "i8259",
> +static struct syscore_ops i8259_syscore_ops = {
>   	.resume = i8259A_resume,
>   	.shutdown = i8259A_shutdown,
>   };
>
> -static struct sys_device device_i8259A = {
> -	.id	= 0,
> -	.cls	=&i8259_sysdev_class,
> -};
> -
>   static int __init i8259A_init_sysfs(void)
>   {
> -	int error = sysdev_class_register(&i8259_sysdev_class);
> -	if (!error)
> -		error = sysdev_register(&device_i8259A);
> -	return error;
> +	register_syscore_ops(&i8259_syscore_ops);
> +	return 0;
>   }
>
>   device_initcall(i8259A_init_sysfs);
>



From pev@sketchymonkey.com Fri Jul 15 16:56:42 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 15 Jul 2011 16:56:45 +0200 (CEST)
Received: from mail-ey0-f177.google.com ([209.85.215.177]:64809 "EHLO
        mail-ey0-f177.google.com" rhost-flags-OK-OK-OK-OK)
        by eddie.linux-mips.org with ESMTP id S1491782Ab1GOO4m (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Fri, 15 Jul 2011 16:56:42 +0200
Received: by eyh6 with SMTP id 6so857447eyh.36
        for <linux-mips@linux-mips.org>; Fri, 15 Jul 2011 07:56:36 -0700 (PDT)
MIME-Version: 1.0
Received: by 10.14.97.75 with SMTP id s51mr1309308eef.131.1310741796662; Fri,
 15 Jul 2011 07:56:36 -0700 (PDT)
Received: by 10.14.27.139 with HTTP; Fri, 15 Jul 2011 07:56:36 -0700 (PDT)
Date:   Fri, 15 Jul 2011 15:56:36 +0100
Message-ID: <CALGOZk2M8Hn_EA+Mqg3frZzLGZgr0bbj3VV8mUqUB1taCdwXJg@mail.gmail.com>
Subject: Confusion with vmlinux objcopy translation
From:   David Peverley <pev@sketchymonkey.com>
To:     linux-mips@linux-mips.org
Content-Type: text/plain; charset=ISO-8859-1
X-archive-position: 30628
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: pev@sketchymonkey.com
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 11015
Content-Length: 2516
Lines: 60

Hi all,

First off Hello! My first post on the list so *wave*.

I've got something going on where I'm not sure if I'm missing a
subtlety (likely) or if something bizarre is going on. I'm building a
hacked variant of kernel 2.6.29.6 that's come from somone who's ported
it to the particular board I'm using. I've built a working kernel but
I'm not sure what's going on when I try to boot it as it seems like
the objcopy to make a binary image from vmlinux is a bit odd... To
walk through what I'm doing :

This kernel is compiled with a load address of 0x80500000. Looking at
vmlinux to find kernel_entry  :
  $ mipsel-percello-linux-gnu-nm ../../../vmlinux | grep kernel_entry
  80504590 T kernel_entry

Checking via GDB to see what the code looks like :
 (gdb) disassemble kernel_entry
  Dump of assembler code for function kernel_entry:
  0x80504590 <kernel_entry+0>:    add    %ah,0x8(%eax)
  0x80504593 <kernel_entry+3>:    inc    %eax
  0x80504594 <kernel_entry+4>:    add    %dl,(%eax)
  0x80504596 <kernel_entry+6>:    add    %edi,(%edi,%ebx,1)
  0x80504599 <kernel_entry+9>:    add    %ah,(%ecx)
  0x8050459b <kernel_entry+11>:   xor    $0x25,%al

So it's where we expected it to be from the output of nm...  :
  (gdb) x/90xw 0x80504590
  0x80504590 <kernel_entry>:	0x40086000	0x3c011000	0x3421001f	0x01014025
  0x805045a0 <kernel_entry+16>:	0x3908001f	0x40886000	0x000000c0	0x3c088050

I then convert this vmlinux file to a binary image :
  $ mipsel-percello-linux-gnu-objcopy -O binary ./vmlinux ./vmlinux.bin.test

and then hexdump to see what's at the kernel_entry offset :
  $ xxd -g xxd -g 4 -s 0x4550 -l 0x80 ./vmlinux.bin.test
  0004550: 00600840 0010013c 1f002134 25400101  .`.@...<..!4%@..
  0004560: 1f000839 00608840 c0000000 5080083c  ...9.`.@....P..<
  0004570: bc450825 08000001 00000000 9c80083c  .E.%...........<
  0004580: 00700825 000000ad a180093c dcb22925  .p.%.......<..)%
  0004590: 04000825 feff0915 000000ad 9c80013c  ...%...........<
  00045a0: 647624ac 9c80013c 687625ac 9c80013c  dv$....<hv%....<
  00045b0: 6c7626ac 9c80013c 707627ac 00208040  lv&....<pv'.. .@
  00045c0: 96801c3c 00609c27 e01f1d24 21e8bc03  ...<.`.'...$!...

The code for kernel_entry seems to be at an offset of 0x0004550. This
is -0x40 bytes below where I'd expected! Am I missing something? I can
confirm this by using my bootloader to load vmlinux.bin a
(load_address + 0x40) and it runs just fine.

The toolchain we have is :
  binutils 2.16.1
  gcc 4.2.0

Any insight would be appreciated!

Cheers!

~Pev

From cernekee@gmail.com Fri Jul 15 19:44:55 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 15 Jul 2011 19:45:02 +0200 (CEST)
Received: from mail-pz0-f53.google.com ([209.85.210.53]:54058 "EHLO
        mail-pz0-f53.google.com" rhost-flags-OK-OK-OK-OK)
        by eddie.linux-mips.org with ESMTP id S1491803Ab1GORoz convert rfc822-to-8bit
        (ORCPT <rfc822;linux-mips@linux-mips.org>);
        Fri, 15 Jul 2011 19:44:55 +0200
Received: by pzk6 with SMTP id 6so1939552pzk.26
        for <linux-mips@linux-mips.org>; Fri, 15 Jul 2011 10:44:48 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=gmail.com; s=gamma;
        h=mime-version:in-reply-to:references:date:message-id:subject:from:to
         :cc:content-type:content-transfer-encoding;
        bh=fNGFwPa5t58uTJJWiyhaQcgxbBpkxw/KVuINtbdUJCU=;
        b=kjhPiZP/OUnAD4GKLWxhl95vrzsgczJsNWgF37CuazITYm4zzWs/0D+dC6/IXKxIuy
         v31hxwotaYJcsANVQUJs5A6s9iHP5t1l3JenwNdd7SsR1X/1EKgiaXGHy0OMzkFPy4hI
         M4zBXLgHCePm2WWptDRt+FHVYhlBWTyfiDXMo=
MIME-Version: 1.0
Received: by 10.68.57.71 with SMTP id g7mr4772586pbq.447.1310751888718; Fri,
 15 Jul 2011 10:44:48 -0700 (PDT)
Received: by 10.68.54.131 with HTTP; Fri, 15 Jul 2011 10:44:48 -0700 (PDT)
In-Reply-To: <CALGOZk2M8Hn_EA+Mqg3frZzLGZgr0bbj3VV8mUqUB1taCdwXJg@mail.gmail.com>
References: <CALGOZk2M8Hn_EA+Mqg3frZzLGZgr0bbj3VV8mUqUB1taCdwXJg@mail.gmail.com>
Date:   Fri, 15 Jul 2011 10:44:48 -0700
Message-ID: <CAJiQ=7Chq8zP9LHLvnQ_3Hi-YSD4PTbxT73ZLc=M2jLSZpW_cA@mail.gmail.com>
Subject: Re: Confusion with vmlinux objcopy translation
From:   Kevin Cernekee <cernekee@gmail.com>
To:     David Peverley <pev@sketchymonkey.com>
Cc:     linux-mips@linux-mips.org
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8BIT
X-archive-position: 30629
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: cernekee@gmail.com
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 11237
Content-Length: 2818
Lines: 58

On Fri, Jul 15, 2011 at 7:56 AM, David Peverley <pev@sketchymonkey.com> wrote:
> Checking via GDB to see what the code looks like :
> Â (gdb) disassemble kernel_entry
> Â Dump of assembler code for function kernel_entry:
> Â 0x80504590 <kernel_entry+0>: Â  Â add Â  Â %ah,0x8(%eax)
> Â 0x80504593 <kernel_entry+3>: Â  Â inc Â  Â %eax

In the future, you may want to use "disass/r kernel_entry" to see the
hex instructions, and correlate that output to what you see in the
file.

It would also be helpful to use a cross gdb built for MIPS.

But the "objdump -d" output is probably enough to go on.  e.g.
mipsel-percello-linux-gnu-objdump -d vmlinux | grep -A5
'kernel_entry.:'

> I then convert this vmlinux file to a binary image :
> Â $ mipsel-percello-linux-gnu-objcopy -O binary ./vmlinux ./vmlinux.bin.test
>
> and then hexdump to see what's at the kernel_entry offset :
> Â $ xxd -g xxd -g 4 -s 0x4550 -l 0x80 ./vmlinux.bin.test
> Â 0004550: 00600840 0010013c 1f002134 25400101 Â .`.@...<..!4%@..
> Â 0004560: 1f000839 00608840 c0000000 5080083c Â ...9.`.@....P..<
> Â 0004570: bc450825 08000001 00000000 9c80083c Â .E.%...........<
> Â 0004580: 00700825 000000ad a180093c dcb22925 Â .p.%.......<..)%
> Â 0004590: 04000825 feff0915 000000ad 9c80013c Â ...%...........<
> Â 00045a0: 647624ac 9c80013c 687625ac 9c80013c Â dv$....<hv%....<
> Â 00045b0: 6c7626ac 9c80013c 707627ac 00208040 Â lv&....<pv'.. .@
> Â 00045c0: 96801c3c 00609c27 e01f1d24 21e8bc03 Â ...<.`.'...$!...
>
> The code for kernel_entry seems to be at an offset of 0x0004550. This
> is -0x40 bytes below where I'd expected! Am I missing something? I can
> confirm this by using my bootloader to load vmlinux.bin a
> (load_address + 0x40) and it runs just fine.

I think the key here is the load address of the first ELF section.
>From the objcopy man page:

"objcopy can be used to generate a raw binary file by using an output
target of binary (e.g., use -O binary).  When objcopy generates a raw
binary file, it will essentially produce a memory dump of the contents
of the input object file.  All symbols and relocation information will
be discarded.  The memory dump will start at the load address of the
lowest section copied into the output file."

So, the kernel_entry address really does not matter in this context.
Although obviously it's good to know whether the kernel_entry code is
getting loaded into the right memory location.

Posting the output from "objdump -x vmlinux" (or maybe even a URL from
which to download your vmlinux file) may help shed light on what is
happening.

BTW: I enable CONFIG_BOOT_RAW on my images so that I don't have to
worry about finding the ELF start address after converting vmlinux
into a raw binary image.  This lets me jump to a fixed start address,
even if the address of kernel_entry moves around.

From rjw@sisk.pl Fri Jul 15 23:52:51 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 15 Jul 2011 23:52:57 +0200 (CEST)
Received: from ogre.sisk.pl ([217.79.144.158]:57558 "EHLO ogre.sisk.pl"
        rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org with ESMTP
        id S1490945Ab1GOVwv (ORCPT <rfc822;linux-mips@linux-mips.org>);
        Fri, 15 Jul 2011 23:52:51 +0200
Received: from localhost (localhost.localdomain [127.0.0.1])
        by ogre.sisk.pl (Postfix) with ESMTP id 50E161B0824;
        Fri, 15 Jul 2011 23:24:16 +0200 (CEST)
Received: from ogre.sisk.pl ([127.0.0.1])
 by localhost (ogre.sisk.pl [127.0.0.1]) (amavisd-new, port 10024) with ESMTP
 id 19052-08; Fri, 15 Jul 2011 23:23:55 +0200 (CEST)
Received: from ferrari.rjw.lan (220-bem-13.acn.waw.pl [82.210.184.220])
        (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits))
        (No client certificate requested)
        by ogre.sisk.pl (Postfix) with ESMTP id EC2601B06B5;
        Fri, 15 Jul 2011 23:23:54 +0200 (CEST)
From:   "Rafael J. Wysocki" <rjw@sisk.pl>
To:     Ralf Baechle <ralf@linux-mips.org>
Subject: [PATCH] MIPS: Convert i8259.c to using syscore_ops (was: Re: Status of MIPS on 3.0.0-rc6 kernel)
Date:   Fri, 15 Jul 2011 23:53:37 +0200
User-Agent: KMail/1.13.6 (Linux/3.0.0-rc7+; KDE/4.6.0; x86_64; ; )
Cc:     "Roland Vossen" <rvossen@broadcom.com>,
        "Jonas Gorski" <jonas.gorski@gmail.com>,
        "Geert Uytterhoeven" <geert@linux-m68k.org>,
        "devel@linuxdriverproject.org" <devel@linuxdriverproject.org>,
        "linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
        "linux-mips@linux-mips.org" <linux-mips@linux-mips.org>,
        Linux PM mailing list <linux-pm@lists.linux-foundation.org>
References: <4E1ECE3B.10308@broadcom.com> <201107142151.24763.rjw@sisk.pl> <4E2032D7.9000704@broadcom.com>
In-Reply-To: <4E2032D7.9000704@broadcom.com>
MIME-Version: 1.0
Content-Type: Text/Plain;
  charset="utf-8"
Content-Transfer-Encoding: 7bit
Message-Id: <201107152353.38004.rjw@sisk.pl>
X-Virus-Scanned: amavisd-new at ogre.sisk.pl using MkS_Vir for Linux
X-archive-position: 30630
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: rjw@sisk.pl
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 11462
Content-Length: 2646
Lines: 92

On Friday, July 15, 2011, Roland Vossen wrote:
> > Please check if the appended patch helps.
> 
> It does, I am able to build a big endian MIPS kernel now. Can you notify 
> me if you submit this patch ?

Well, it's been submitted already. :-)

Ralf, the appended patch is necessary to fix build on MIPS due to a
missing conversion to syscore_ops.  Please take it to your tree or
let me know if you want me to push it myself.

Thanks,
Rafael

---
From: Rafael J. Wysocki <rjw@sisk.pl>
Subject: MIPS: Convert i8259.c to using syscore_ops

The code in arch/mips/kernel/i8259.c still hasn't been converted to
using struct syscore_ops instead of a sysdev for resume and shutdown.
As a result, this code doesn't build any more after suspend, resume
and shutdown callbacks have been removed from struct sysdev_class.
Fix this problem by converting i8259.c to using syscore_ops.

Reported-and-tested-by: Roland Vossen <rvossen@broadcom.com>
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 arch/mips/kernel/i8259.c |   22 ++++++----------------
 1 file changed, 6 insertions(+), 16 deletions(-)

Index: linux-2.6/arch/mips/kernel/i8259.c
===================================================================
--- linux-2.6.orig/arch/mips/kernel/i8259.c
+++ linux-2.6/arch/mips/kernel/i8259.c
@@ -14,7 +14,7 @@
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/spinlock.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 #include <linux/irq.h>
 
 #include <asm/i8259.h>
@@ -215,14 +215,13 @@ spurious_8259A_irq:
 	}
 }
 
-static int i8259A_resume(struct sys_device *dev)
+static void i8259A_resume(void)
 {
 	if (i8259A_auto_eoi >= 0)
 		init_8259A(i8259A_auto_eoi);
-	return 0;
 }
 
-static int i8259A_shutdown(struct sys_device *dev)
+static void i8259A_shutdown(void)
 {
 	/* Put the i8259A into a quiescent state that
 	 * the kernel initialization code can get it
@@ -232,26 +231,17 @@ static int i8259A_shutdown(struct sys_de
 		outb(0xff, PIC_MASTER_IMR);	/* mask all of 8259A-1 */
 		outb(0xff, PIC_SLAVE_IMR);	/* mask all of 8259A-1 */
 	}
-	return 0;
 }
 
-static struct sysdev_class i8259_sysdev_class = {
-	.name = "i8259",
+static struct syscore_ops i8259_syscore_ops = {
 	.resume = i8259A_resume,
 	.shutdown = i8259A_shutdown,
 };
 
-static struct sys_device device_i8259A = {
-	.id	= 0,
-	.cls	= &i8259_sysdev_class,
-};
-
 static int __init i8259A_init_sysfs(void)
 {
-	int error = sysdev_class_register(&i8259_sysdev_class);
-	if (!error)
-		error = sysdev_register(&device_i8259A);
-	return error;
+	register_syscore_ops(&i8259_syscore_ops);
+	return 0;
 }
 
 device_initcall(i8259A_init_sysfs);
 

From hauke@hauke-m.de Sat Jul 16 18:56:04 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 16 Jul 2011 18:56:11 +0200 (CEST)
Received: from server19320154104.serverpool.info ([193.201.54.104]:50798 "EHLO
        hauke-m.de" rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org
        with ESMTP id S1491025Ab1GPQ4E (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Sat, 16 Jul 2011 18:56:04 +0200
Received: from localhost (localhost [127.0.0.1])
        by hauke-m.de (Postfix) with ESMTP id EAF778C65;
        Sat, 16 Jul 2011 18:56:02 +0200 (CEST)
X-Virus-Scanned: Debian amavisd-new at hauke-m.de 
Received: from hauke-m.de ([127.0.0.1])
        by localhost (hauke-m.de [127.0.0.1]) (amavisd-new, port 10024)
        with ESMTP id 5QLY0lkwAV2b; Sat, 16 Jul 2011 18:55:59 +0200 (CEST)
Received: from localhost.localdomain (host-091-097-255-051.ewe-ip-backbone.de [91.97.255.51])
        by hauke-m.de (Postfix) with ESMTPSA id 67D2B8C4F;
        Sat, 16 Jul 2011 18:55:58 +0200 (CEST)
From:   Hauke Mehrtens <hauke@hauke-m.de>
To:     ralf@linux-mips.org, linux-wireless@vger.kernel.org,
        zajec5@gmail.com, linux-mips@linux-mips.org
Cc:     jonas.gorski@gmail.com, mb@bu3sch.de, george@znau.edu.ua,
        arend@broadcom.com, b43-dev@lists.infradead.org,
        bernhardloos@googlemail.com, arnd@arndb.de,
        julian.calaby@gmail.com, sshtylyov@mvista.com,
        Hauke Mehrtens <hauke@hauke-m.de>
Subject: =?UTF-8?q?=5BPATCH=20v2=2000/11=5D=20bcma=3A=20add=20support=20for=20embedded=20devices=20like=20bcm4716?=
Date:   Sat, 16 Jul 2011 18:55:31 +0200
Message-Id: <1310835342-18877-1-git-send-email-hauke@hauke-m.de>
X-Mailer: git-send-email 1.7.4.1
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-archive-position: 30631
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: hauke@hauke-m.de
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 11702
Content-Length: 4854
Lines: 104

This patch series adds support for embedded devices like bcm47xx to 
bcma. Bcma is used on bcm4716 and bcm4718 SoCs as the system bus and
replaced ssb used on older devices. With these patches my bcm4716 
device boots up till it tries to access the flash, because the serial 
flash chip is unsupported for now, this will be my next task. This adds 
support for MIPS cores, interrupt configuration and the serial console.

These patches are not containing all functions needed to get the SoC to 
fully work and support every feature, but it is a good start.
These patches are now integrated in OpenWrt for everyone how wants to
test them.

This was tested with a BCM4704 device (SoC with ssb bus), a BCM4716 
device and a pcie wireless card supported by bcma.


@RafaÅ‚: If you are fine with the bcma patches could you please give
your Signed-off on them.

@Ralf: Could you please merger this into the mips tree so that it will be in linux-3.1.

PATCH v2:
 * define inline function bcma_core_mips_init() if mips driver is not build
 * iounmap core->io_wrap and core->io_addr after it was used.
 * update bcma based on new braodcom driver code
   * add workaround for 5357b0
 * move flash informations into own struct and store it in chipcommon.
   When adding serial flash support it will be in chipcommon and then all flash structs should be there.
 * some changes to bcma_chipco_serial_init()
  * some changes are done after looking into a more recent version of broadcom driver.
  * changes suggested by Jonas
  * serial struct is in chipcommon as it is accessed through chipcommon.
  * use bcma_pmu_alp_clock() to get the clock.
 * cpu clock: add detection support for some newer SoCs.

PATCH v1:
 * rebased on mips tree (mips/queue)
 * drop pcie hostmode patch as RafaÅ‚ sent a better patch to wireless mailing list
 * drop sprom patch because sprom is not supported in bcma version from mips tree,
     I will send a separate patch to wireless mailing list.
 * fix compilation of arch/mips/bcm47xx/wgt634u.c
 * fix texts in arch/mips/bcm47xx/Kconfig
RFC v3:
 * make bcm47xx built either with bcma, ssb or both and use mips MIPS 74K optimizations if possible
 * add block io support
 * some minor fixes for code and doku
RFC v2:
 * use list and no arry to store cores
 * rename bcma_host_bcma_ to bcma_host_soc_
 * use core->io_addr and core->io_wrap to access cores
 * checkpatch fixes
 * some minor fixes

Hauke Mehrtens (11):
  bcma: move parsing of EEPROM into own function.
  bcma: move initializing of struct bcma_bus to own function.
  bcma: add functions to scan cores needed on SoCs
  bcma: add SOC bus
  bcma: add mips driver
  bcma: add serial console support
  bcma: get CPU clock
  bcm47xx: prepare to support different buses
  bcm47xx: make it possible to build bcm47xx without ssb.
  bcm47xx: add support for bcma bus
  bcm47xx: fix irq assignment for new SoCs.

 arch/mips/Kconfig                            |    8 +-
 arch/mips/bcm47xx/Kconfig                    |   31 +++
 arch/mips/bcm47xx/Makefile                   |    3 +-
 arch/mips/bcm47xx/gpio.c                     |   82 +++++--
 arch/mips/bcm47xx/irq.c                      |   12 +
 arch/mips/bcm47xx/nvram.c                    |   29 ++-
 arch/mips/bcm47xx/serial.c                   |   46 ++++-
 arch/mips/bcm47xx/setup.c                    |   90 ++++++-
 arch/mips/bcm47xx/time.c                     |   16 +-
 arch/mips/bcm47xx/wgt634u.c                  |   14 +-
 arch/mips/include/asm/mach-bcm47xx/bcm47xx.h |   26 ++-
 arch/mips/include/asm/mach-bcm47xx/gpio.h    |  108 +++++++--
 arch/mips/pci/pci-bcm47xx.c                  |    6 +
 drivers/bcma/Kconfig                         |   13 +
 drivers/bcma/Makefile                        |    2 +
 drivers/bcma/bcma_private.h                  |   18 ++
 drivers/bcma/driver_chipcommon.c             |   53 ++++
 drivers/bcma/driver_chipcommon_pmu.c         |  133 ++++++++++
 drivers/bcma/driver_mips.c                   |  256 +++++++++++++++++++
 drivers/bcma/driver_pci.c                    |    3 +
 drivers/bcma/host_soc.c                      |  183 ++++++++++++++
 drivers/bcma/main.c                          |   65 +++++
 drivers/bcma/scan.c                          |  348 ++++++++++++++++++--------
 drivers/watchdog/bcm47xx_wdt.c               |   27 ++-
 include/linux/bcma/bcma.h                    |    8 +
 include/linux/bcma/bcma_driver_chipcommon.h  |   67 +++++
 include/linux/bcma/bcma_driver_mips.h        |   51 ++++
 include/linux/bcma/bcma_soc.h                |   16 ++
 28 files changed, 1535 insertions(+), 179 deletions(-)
 create mode 100644 arch/mips/bcm47xx/Kconfig
 create mode 100644 drivers/bcma/driver_mips.c
 create mode 100644 drivers/bcma/host_soc.c
 create mode 100644 include/linux/bcma/bcma_driver_mips.h
 create mode 100644 include/linux/bcma/bcma_soc.h

-- 
1.7.4.1


From hauke@hauke-m.de Sat Jul 16 18:56:05 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 16 Jul 2011 18:56:46 +0200 (CEST)
Received: from server19320154104.serverpool.info ([193.201.54.104]:50814 "EHLO
        hauke-m.de" rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org
        with ESMTP id S1491028Ab1GPQ4F (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Sat, 16 Jul 2011 18:56:05 +0200
Received: from localhost (localhost [127.0.0.1])
        by hauke-m.de (Postfix) with ESMTP id 0027F8C66;
        Sat, 16 Jul 2011 18:56:05 +0200 (CEST)
X-Virus-Scanned: Debian amavisd-new at hauke-m.de 
Received: from hauke-m.de ([127.0.0.1])
        by localhost (hauke-m.de [127.0.0.1]) (amavisd-new, port 10024)
        with ESMTP id 71n9X2sViqCg; Sat, 16 Jul 2011 18:56:00 +0200 (CEST)
Received: from localhost.localdomain (host-091-097-255-051.ewe-ip-backbone.de [91.97.255.51])
        by hauke-m.de (Postfix) with ESMTPSA id 734258C62;
        Sat, 16 Jul 2011 18:55:59 +0200 (CEST)
From:   Hauke Mehrtens <hauke@hauke-m.de>
To:     ralf@linux-mips.org, linux-wireless@vger.kernel.org,
        zajec5@gmail.com, linux-mips@linux-mips.org
Cc:     jonas.gorski@gmail.com, mb@bu3sch.de, george@znau.edu.ua,
        arend@broadcom.com, b43-dev@lists.infradead.org,
        bernhardloos@googlemail.com, arnd@arndb.de,
        julian.calaby@gmail.com, sshtylyov@mvista.com,
        Hauke Mehrtens <hauke@hauke-m.de>
Subject: [PATCH v2 01/11] bcma: move parsing of EEPROM into own function.
Date:   Sat, 16 Jul 2011 18:55:32 +0200
Message-Id: <1310835342-18877-2-git-send-email-hauke@hauke-m.de>
X-Mailer: git-send-email 1.7.4.1
In-Reply-To: <1310835342-18877-1-git-send-email-hauke@hauke-m.de>
References: <1310835342-18877-1-git-send-email-hauke@hauke-m.de>
X-archive-position: 30632
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: hauke@hauke-m.de
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 11703
Content-Length: 7162
Lines: 274

Move the parsing of the EEPROM data in scan function for one core into
an own function. Now we are able to use it in some other scan function
as well.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 drivers/bcma/scan.c |  230 ++++++++++++++++++++++++++-------------------------
 1 files changed, 118 insertions(+), 112 deletions(-)

diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c
index 40d7dcc..4012d8d 100644
--- a/drivers/bcma/scan.c
+++ b/drivers/bcma/scan.c
@@ -200,16 +200,124 @@ static s32 bcma_erom_get_addr_desc(struct bcma_bus *bus, u32 **eromptr,
 	return addrl;
 }
 
+static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
+			      struct bcma_device *core)
+{
+	s32 tmp;
+	u8 i, j;
+	s32 cia, cib;
+	u8 ports[2], wrappers[2];
+
+	/* get CIs */
+	cia = bcma_erom_get_ci(bus, eromptr);
+	if (cia < 0) {
+		bcma_erom_push_ent(eromptr);
+		if (bcma_erom_is_end(bus, eromptr))
+			return -ESPIPE;
+		return -EILSEQ;
+	}
+	cib = bcma_erom_get_ci(bus, eromptr);
+	if (cib < 0)
+		return -EILSEQ;
+
+	/* parse CIs */
+	core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT;
+	core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT;
+	core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT;
+	ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT;
+	ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT;
+	wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT;
+	wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT;
+	core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT;
+
+	if (((core->id.manuf == BCMA_MANUF_ARM) &&
+	     (core->id.id == 0xFFF)) ||
+	    (ports[1] == 0)) {
+		bcma_erom_skip_component(bus, eromptr);
+		return -ENXIO;
+	}
+
+	/* check if component is a core at all */
+	if (wrappers[0] + wrappers[1] == 0) {
+		/* we could save addrl of the router
+		if (cid == BCMA_CORE_OOB_ROUTER)
+		 */
+		bcma_erom_skip_component(bus, eromptr);
+		return -ENXIO;
+	}
+
+	if (bcma_erom_is_bridge(bus, eromptr)) {
+		bcma_erom_skip_component(bus, eromptr);
+		return -ENXIO;
+	}
+
+	/* get & parse master ports */
+	for (i = 0; i < ports[0]; i++) {
+		u32 mst_port_d = bcma_erom_get_mst_port(bus, eromptr);
+		if (mst_port_d < 0)
+			return -EILSEQ;
+	}
+
+	/* get & parse slave ports */
+	for (i = 0; i < ports[1]; i++) {
+		for (j = 0; ; j++) {
+			tmp = bcma_erom_get_addr_desc(bus, eromptr,
+				SCAN_ADDR_TYPE_SLAVE, i);
+			if (tmp < 0) {
+				/* no more entries for port _i_ */
+				/* pr_debug("erom: slave port %d "
+				 * "has %d descriptors\n", i, j); */
+				break;
+			} else {
+				if (i == 0 && j == 0)
+					core->addr = tmp;
+			}
+		}
+	}
+
+	/* get & parse master wrappers */
+	for (i = 0; i < wrappers[0]; i++) {
+		for (j = 0; ; j++) {
+			tmp = bcma_erom_get_addr_desc(bus, eromptr,
+				SCAN_ADDR_TYPE_MWRAP, i);
+			if (tmp < 0) {
+				/* no more entries for port _i_ */
+				/* pr_debug("erom: master wrapper %d "
+				 * "has %d descriptors\n", i, j); */
+				break;
+			} else {
+				if (i == 0 && j == 0)
+					core->wrap = tmp;
+			}
+		}
+	}
+
+	/* get & parse slave wrappers */
+	for (i = 0; i < wrappers[1]; i++) {
+		u8 hack = (ports[1] == 1) ? 0 : 1;
+		for (j = 0; ; j++) {
+			tmp = bcma_erom_get_addr_desc(bus, eromptr,
+				SCAN_ADDR_TYPE_SWRAP, i + hack);
+			if (tmp < 0) {
+				/* no more entries for port _i_ */
+				/* pr_debug("erom: master wrapper %d "
+				 * has %d descriptors\n", i, j); */
+				break;
+			} else {
+				if (wrappers[0] == 0 && !i && !j)
+					core->wrap = tmp;
+			}
+		}
+	}
+	return 0;
+}
+
 int bcma_bus_scan(struct bcma_bus *bus)
 {
 	u32 erombase;
 	u32 __iomem *eromptr, *eromend;
 
-	s32 cia, cib;
-	u8 ports[2], wrappers[2];
-
 	s32 tmp;
-	u8 i, j;
 
 	int err;
 
@@ -236,112 +344,13 @@ int bcma_bus_scan(struct bcma_bus *bus)
 		INIT_LIST_HEAD(&core->list);
 		core->bus = bus;
 
-		/* get CIs */
-		cia = bcma_erom_get_ci(bus, &eromptr);
-		if (cia < 0) {
-			bcma_erom_push_ent(&eromptr);
-			if (bcma_erom_is_end(bus, &eromptr))
-				break;
-			err= -EILSEQ;
-			goto out;
-		}
-		cib = bcma_erom_get_ci(bus, &eromptr);
-		if (cib < 0) {
-			err= -EILSEQ;
-			goto out;
-		}
-
-		/* parse CIs */
-		core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT;
-		core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT;
-		core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT;
-		ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT;
-		ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT;
-		wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT;
-		wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT;
-		core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT;
-
-		if (((core->id.manuf == BCMA_MANUF_ARM) &&
-		     (core->id.id == 0xFFF)) ||
-		    (ports[1] == 0)) {
-			bcma_erom_skip_component(bus, &eromptr);
-			continue;
-		}
-
-		/* check if component is a core at all */
-		if (wrappers[0] + wrappers[1] == 0) {
-			/* we could save addrl of the router
-			if (cid == BCMA_CORE_OOB_ROUTER)
-			 */
-			bcma_erom_skip_component(bus, &eromptr);
-			continue;
-		}
-
-		if (bcma_erom_is_bridge(bus, &eromptr)) {
-			bcma_erom_skip_component(bus, &eromptr);
+		err = bcma_get_next_core(bus, &eromptr, core);
+		if (err == -ENXIO)
 			continue;
-		}
-
-		/* get & parse master ports */
-		for (i = 0; i < ports[0]; i++) {
-			u32 mst_port_d = bcma_erom_get_mst_port(bus, &eromptr);
-			if (mst_port_d < 0) {
-				err= -EILSEQ;
-				goto out;
-			}
-		}
-
-		/* get & parse slave ports */
-		for (i = 0; i < ports[1]; i++) {
-			for (j = 0; ; j++) {
-				tmp = bcma_erom_get_addr_desc(bus, &eromptr,
-					SCAN_ADDR_TYPE_SLAVE, i);
-				if (tmp < 0) {
-					/* no more entries for port _i_ */
-					/* pr_debug("erom: slave port %d "
-					 * "has %d descriptors\n", i, j); */
-					break;
-				} else {
-					if (i == 0 && j == 0)
-						core->addr = tmp;
-				}
-			}
-		}
-
-		/* get & parse master wrappers */
-		for (i = 0; i < wrappers[0]; i++) {
-			for (j = 0; ; j++) {
-				tmp = bcma_erom_get_addr_desc(bus, &eromptr,
-					SCAN_ADDR_TYPE_MWRAP, i);
-				if (tmp < 0) {
-					/* no more entries for port _i_ */
-					/* pr_debug("erom: master wrapper %d "
-					 * "has %d descriptors\n", i, j); */
-					break;
-				} else {
-					if (i == 0 && j == 0)
-						core->wrap = tmp;
-				}
-			}
-		}
-
-		/* get & parse slave wrappers */
-		for (i = 0; i < wrappers[1]; i++) {
-			u8 hack = (ports[1] == 1) ? 0 : 1;
-			for (j = 0; ; j++) {
-				tmp = bcma_erom_get_addr_desc(bus, &eromptr,
-					SCAN_ADDR_TYPE_SWRAP, i + hack);
-				if (tmp < 0) {
-					/* no more entries for port _i_ */
-					/* pr_debug("erom: master wrapper %d "
-					 * has %d descriptors\n", i, j); */
-					break;
-				} else {
-					if (wrappers[0] == 0 && !i && !j)
-						core->wrap = tmp;
-				}
-			}
-		}
+		else if (err == -ESPIPE)
+			break;
+		else if (err < 0)
+			return err;
 
 		pr_info("Core %d found: %s "
 			"(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
@@ -351,9 +360,6 @@ int bcma_bus_scan(struct bcma_bus *bus)
 
 		core->core_index = bus->nr_cores++;
 		list_add(&core->list, &bus->cores);
-		continue;
-out:
-		return err;
 	}
 
 	return 0;
-- 
1.7.4.1


From hauke@hauke-m.de Sat Jul 16 18:56:09 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 16 Jul 2011 18:57:12 +0200 (CEST)
Received: from server19320154104.serverpool.info ([193.201.54.104]:50830 "EHLO
        hauke-m.de" rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org
        with ESMTP id S1491033Ab1GPQ4J (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Sat, 16 Jul 2011 18:56:09 +0200
Received: from localhost (localhost [127.0.0.1])
        by hauke-m.de (Postfix) with ESMTP id DB7638C6C;
        Sat, 16 Jul 2011 18:56:08 +0200 (CEST)
X-Virus-Scanned: Debian amavisd-new at hauke-m.de 
Received: from hauke-m.de ([127.0.0.1])
        by localhost (hauke-m.de [127.0.0.1]) (amavisd-new, port 10024)
        with ESMTP id tCN8spLyz3Dy; Sat, 16 Jul 2011 18:56:04 +0200 (CEST)
Received: from localhost.localdomain (host-091-097-255-051.ewe-ip-backbone.de [91.97.255.51])
        by hauke-m.de (Postfix) with ESMTPSA id 674F88C63;
        Sat, 16 Jul 2011 18:56:00 +0200 (CEST)
From:   Hauke Mehrtens <hauke@hauke-m.de>
To:     ralf@linux-mips.org, linux-wireless@vger.kernel.org,
        zajec5@gmail.com, linux-mips@linux-mips.org
Cc:     jonas.gorski@gmail.com, mb@bu3sch.de, george@znau.edu.ua,
        arend@broadcom.com, b43-dev@lists.infradead.org,
        bernhardloos@googlemail.com, arnd@arndb.de,
        julian.calaby@gmail.com, sshtylyov@mvista.com,
        Hauke Mehrtens <hauke@hauke-m.de>
Subject: [PATCH v2 02/11] bcma: move initializing of struct bcma_bus to own function.
Date:   Sat, 16 Jul 2011 18:55:33 +0200
Message-Id: <1310835342-18877-3-git-send-email-hauke@hauke-m.de>
X-Mailer: git-send-email 1.7.4.1
In-Reply-To: <1310835342-18877-1-git-send-email-hauke@hauke-m.de>
References: <1310835342-18877-1-git-send-email-hauke@hauke-m.de>
X-archive-position: 30633
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: hauke@hauke-m.de
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 11704
Content-Length: 1185
Lines: 48

This makes it possible to use this code in some other method.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 drivers/bcma/scan.c |   17 +++++++++++------
 1 files changed, 11 insertions(+), 6 deletions(-)

diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c
index 4012d8d..7970553 100644
--- a/drivers/bcma/scan.c
+++ b/drivers/bcma/scan.c
@@ -312,15 +312,10 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
 	return 0;
 }
 
-int bcma_bus_scan(struct bcma_bus *bus)
+static void bcma_init_bus(struct bcma_bus *bus)
 {
-	u32 erombase;
-	u32 __iomem *eromptr, *eromend;
-
 	s32 tmp;
 
-	int err;
-
 	INIT_LIST_HEAD(&bus->cores);
 	bus->nr_cores = 0;
 
@@ -330,6 +325,16 @@ int bcma_bus_scan(struct bcma_bus *bus)
 	bus->chipinfo.id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT;
 	bus->chipinfo.rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT;
 	bus->chipinfo.pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT;
+}
+
+int bcma_bus_scan(struct bcma_bus *bus)
+{
+	u32 erombase;
+	u32 __iomem *eromptr, *eromend;
+
+	int err;
+
+	bcma_init_bus(bus);
 
 	erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
 	eromptr = bus->mmio;
-- 
1.7.4.1


From hauke@hauke-m.de Sat Jul 16 18:56:11 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 16 Jul 2011 18:57:40 +0200 (CEST)
Received: from server19320154104.serverpool.info ([193.201.54.104]:50843 "EHLO
        hauke-m.de" rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org
        with ESMTP id S1491044Ab1GPQ4L (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Sat, 16 Jul 2011 18:56:11 +0200
Received: from localhost (localhost [127.0.0.1])
        by hauke-m.de (Postfix) with ESMTP id 2A7BB8C6E;
        Sat, 16 Jul 2011 18:56:11 +0200 (CEST)
X-Virus-Scanned: Debian amavisd-new at hauke-m.de 
Received: from hauke-m.de ([127.0.0.1])
        by localhost (hauke-m.de [127.0.0.1]) (amavisd-new, port 10024)
        with ESMTP id u52rmiraSOPK; Sat, 16 Jul 2011 18:56:05 +0200 (CEST)
Received: from localhost.localdomain (host-091-097-255-051.ewe-ip-backbone.de [91.97.255.51])
        by hauke-m.de (Postfix) with ESMTPSA id 630B88C64;
        Sat, 16 Jul 2011 18:56:01 +0200 (CEST)
From:   Hauke Mehrtens <hauke@hauke-m.de>
To:     ralf@linux-mips.org, linux-wireless@vger.kernel.org,
        zajec5@gmail.com, linux-mips@linux-mips.org
Cc:     jonas.gorski@gmail.com, mb@bu3sch.de, george@znau.edu.ua,
        arend@broadcom.com, b43-dev@lists.infradead.org,
        bernhardloos@googlemail.com, arnd@arndb.de,
        julian.calaby@gmail.com, sshtylyov@mvista.com,
        Hauke Mehrtens <hauke@hauke-m.de>
Subject: [PATCH v2 03/11] bcma: add functions to scan cores needed on SoCs
Date:   Sat, 16 Jul 2011 18:55:34 +0200
Message-Id: <1310835342-18877-4-git-send-email-hauke@hauke-m.de>
X-Mailer: git-send-email 1.7.4.1
In-Reply-To: <1310835342-18877-1-git-send-email-hauke@hauke-m.de>
References: <1310835342-18877-1-git-send-email-hauke@hauke-m.de>
X-archive-position: 30634
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: hauke@hauke-m.de
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 11705
Content-Length: 9331
Lines: 318

The chip common and mips core have to be setup early in the boot
process to get the cpu clock.
bcma_bus_early_register() gets pointers to some space to store the core
data and searches for the chip common and mips core and initializes
chip common. After that was done and the kernel is out of early boot we
just have to run bcma_bus_register() and it will search for the other
cores, initialize and register them.
The cores are getting the same numbers as before.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 drivers/bcma/bcma_private.h                 |    7 ++
 drivers/bcma/driver_chipcommon.c            |    5 ++
 drivers/bcma/driver_pci.c                   |    3 +
 drivers/bcma/main.c                         |   45 +++++++++++++
 drivers/bcma/scan.c                         |   95 +++++++++++++++++++++++++--
 include/linux/bcma/bcma.h                   |    1 +
 include/linux/bcma/bcma_driver_chipcommon.h |    1 +
 7 files changed, 151 insertions(+), 6 deletions(-)

diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h
index 2f72e9c..830386c 100644
--- a/drivers/bcma/bcma_private.h
+++ b/drivers/bcma/bcma_private.h
@@ -15,9 +15,16 @@ struct bcma_bus;
 /* main.c */
 extern int bcma_bus_register(struct bcma_bus *bus);
 extern void bcma_bus_unregister(struct bcma_bus *bus);
+int __init bcma_bus_early_register(struct bcma_bus *bus,
+				   struct bcma_device *core_cc,
+				   struct bcma_device *core_mips);
 
 /* scan.c */
 int bcma_bus_scan(struct bcma_bus *bus);
+int __init bcma_bus_scan_early(struct bcma_bus *bus,
+			       struct bcma_device_id *match,
+			       struct bcma_device *core);
+void bcma_init_bus(struct bcma_bus *bus);
 
 #ifdef CONFIG_BCMA_HOST_PCI
 /* host_pci.c */
diff --git a/drivers/bcma/driver_chipcommon.c b/drivers/bcma/driver_chipcommon.c
index 6061022..70321c6 100644
--- a/drivers/bcma/driver_chipcommon.c
+++ b/drivers/bcma/driver_chipcommon.c
@@ -23,6 +23,9 @@ static inline u32 bcma_cc_write32_masked(struct bcma_drv_cc *cc, u16 offset,
 
 void bcma_core_chipcommon_init(struct bcma_drv_cc *cc)
 {
+	if (cc->setup_done)
+		return;
+
 	if (cc->core->id.rev >= 11)
 		cc->status = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT);
 	cc->capabilities = bcma_cc_read32(cc, BCMA_CC_CAP);
@@ -38,6 +41,8 @@ void bcma_core_chipcommon_init(struct bcma_drv_cc *cc)
 		bcma_pmu_init(cc);
 	if (cc->capabilities & BCMA_CC_CAP_PCTL)
 		pr_err("Power control not implemented!\n");
+
+	cc->setup_done = true;
 }
 
 /* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */
diff --git a/drivers/bcma/driver_pci.c b/drivers/bcma/driver_pci.c
index e757e4e..f7378b3 100644
--- a/drivers/bcma/driver_pci.c
+++ b/drivers/bcma/driver_pci.c
@@ -159,5 +159,8 @@ static void bcma_pcicore_serdes_workaround(struct bcma_drv_pci *pc)
 
 void bcma_core_pci_init(struct bcma_drv_pci *pc)
 {
+	if (pc->setup_done)
+		return;
 	bcma_pcicore_serdes_workaround(pc);
+	pc->setup_done = true;
 }
diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c
index be52344..e6c308c 100644
--- a/drivers/bcma/main.c
+++ b/drivers/bcma/main.c
@@ -159,6 +159,51 @@ void bcma_bus_unregister(struct bcma_bus *bus)
 }
 EXPORT_SYMBOL_GPL(bcma_bus_unregister);
 
+int __init bcma_bus_early_register(struct bcma_bus *bus,
+				   struct bcma_device *core_cc,
+				   struct bcma_device *core_mips)
+{
+	int err;
+	struct bcma_device *core;
+	struct bcma_device_id match;
+
+	bcma_init_bus(bus);
+
+	match.manuf = BCMA_MANUF_BCM;
+	match.id = BCMA_CORE_CHIPCOMMON;
+	match.class = BCMA_CL_SIM;
+	match.rev = BCMA_ANY_REV;
+
+	/* Scan for devices (cores) */
+	err = bcma_bus_scan_early(bus, &match, core_cc);
+	if (err) {
+		pr_err("Failed to scan for common core: %d\n", err);
+		return -1;
+	}
+
+	match.manuf = BCMA_MANUF_MIPS;
+	match.id = BCMA_CORE_MIPS_74K;
+	match.class = BCMA_CL_SIM;
+	match.rev = BCMA_ANY_REV;
+
+	err = bcma_bus_scan_early(bus, &match, core_mips);
+	if (err) {
+		pr_err("Failed to scan for mips core: %d\n", err);
+		return -1;
+	}
+
+	/* Init CC core */
+	core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON);
+	if (core) {
+		bus->drv_cc.core = core;
+		bcma_core_chipcommon_init(&bus->drv_cc);
+	}
+
+	pr_info("Early bus registered\n");
+
+	return 0;
+}
+
 int __bcma_driver_register(struct bcma_driver *drv, struct module *owner)
 {
 	drv->drv.name = drv->name;
diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c
index 7970553..bf9f806 100644
--- a/drivers/bcma/scan.c
+++ b/drivers/bcma/scan.c
@@ -200,7 +200,20 @@ static s32 bcma_erom_get_addr_desc(struct bcma_bus *bus, u32 **eromptr,
 	return addrl;
 }
 
+static struct bcma_device *bcma_find_core_by_index(struct bcma_bus *bus,
+						   u16 index)
+{
+	struct bcma_device *core;
+
+	list_for_each_entry(core, &bus->cores, list) {
+		if (core->core_index == index)
+			return core;
+	}
+	return NULL;
+}
+
 static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
+			      struct bcma_device_id *match, int core_num,
 			      struct bcma_device *core)
 {
 	s32 tmp;
@@ -251,6 +264,21 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
 		return -ENXIO;
 	}
 
+	if (bcma_find_core_by_index(bus, core_num)) {
+		bcma_erom_skip_component(bus, eromptr);
+		return -ENODEV;
+	}
+
+	if (match && ((match->manuf != BCMA_ANY_MANUF &&
+	      match->manuf != core->id.manuf) ||
+	     (match->id != BCMA_ANY_ID && match->id != core->id.id) ||
+	     (match->rev != BCMA_ANY_REV && match->rev != core->id.rev) ||
+	     (match->class != BCMA_ANY_CLASS && match->class != core->id.class)
+	    )) {
+		bcma_erom_skip_component(bus, eromptr);
+		return -ENODEV;
+	}
+
 	/* get & parse master ports */
 	for (i = 0; i < ports[0]; i++) {
 		u32 mst_port_d = bcma_erom_get_mst_port(bus, eromptr);
@@ -312,10 +340,13 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
 	return 0;
 }
 
-static void bcma_init_bus(struct bcma_bus *bus)
+void bcma_init_bus(struct bcma_bus *bus)
 {
 	s32 tmp;
 
+	if (bus->init_done)
+		return;
+
 	INIT_LIST_HEAD(&bus->cores);
 	bus->nr_cores = 0;
 
@@ -325,6 +356,7 @@ static void bcma_init_bus(struct bcma_bus *bus)
 	bus->chipinfo.id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT;
 	bus->chipinfo.rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT;
 	bus->chipinfo.pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT;
+	bus->init_done = true;
 }
 
 int bcma_bus_scan(struct bcma_bus *bus)
@@ -332,7 +364,7 @@ int bcma_bus_scan(struct bcma_bus *bus)
 	u32 erombase;
 	u32 __iomem *eromptr, *eromend;
 
-	int err;
+	int err, core_num = 0;
 
 	bcma_init_bus(bus);
 
@@ -349,23 +381,74 @@ int bcma_bus_scan(struct bcma_bus *bus)
 		INIT_LIST_HEAD(&core->list);
 		core->bus = bus;
 
-		err = bcma_get_next_core(bus, &eromptr, core);
-		if (err == -ENXIO)
+		err = bcma_get_next_core(bus, &eromptr, NULL, core_num, core);
+		if (err == -ENODEV) {
+			core_num++;
+			continue;
+		} else if (err == -ENXIO)
 			continue;
 		else if (err == -ESPIPE)
 			break;
 		else if (err < 0)
 			return err;
 
+		core->core_index = core_num++;
+		bus->nr_cores++;
+
 		pr_info("Core %d found: %s "
 			"(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
-			bus->nr_cores, bcma_device_name(&core->id),
+			core->core_index, bcma_device_name(&core->id),
 			core->id.manuf, core->id.id, core->id.rev,
 			core->id.class);
 
-		core->core_index = bus->nr_cores++;
 		list_add(&core->list, &bus->cores);
 	}
 
 	return 0;
 }
+
+int __init bcma_bus_scan_early(struct bcma_bus *bus,
+			       struct bcma_device_id *match,
+			       struct bcma_device *core)
+{
+	u32 erombase;
+	u32 __iomem *eromptr, *eromend;
+
+	int err, core_num = 0;
+
+	erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
+	eromptr = bus->mmio;
+	eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
+
+	bcma_scan_switch_core(bus, erombase);
+
+	while (eromptr < eromend) {
+		memset(core, 0, sizeof(*core));
+		INIT_LIST_HEAD(&core->list);
+		core->bus = bus;
+
+		err = bcma_get_next_core(bus, &eromptr, match, core_num, core);
+		if (err == -ENODEV) {
+			core_num++;
+			continue;
+		} else if (err == -ENXIO)
+			continue;
+		else if (err == -ESPIPE)
+			break;
+		else if (err < 0)
+			return err;
+
+		core->core_index = core_num++;
+		bus->nr_cores++;
+		pr_info("Core %d found: %s "
+			"(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
+			core->core_index, bcma_device_name(&core->id),
+			core->id.manuf, core->id.id, core->id.rev,
+			core->id.class);
+
+		list_add(&core->list, &bus->cores);
+		return 0;
+	}
+
+	return -ENODEV;
+}
diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h
index 08763e4..6bd7b7f 100644
--- a/include/linux/bcma/bcma.h
+++ b/include/linux/bcma/bcma.h
@@ -176,6 +176,7 @@ struct bcma_bus {
 	struct bcma_device *mapped_core;
 	struct list_head cores;
 	u8 nr_cores;
+	u8 init_done:1;
 
 	struct bcma_drv_cc drv_cc;
 	struct bcma_drv_pci drv_pci;
diff --git a/include/linux/bcma/bcma_driver_chipcommon.h b/include/linux/bcma/bcma_driver_chipcommon.h
index 083c3b6..837c176 100644
--- a/include/linux/bcma/bcma_driver_chipcommon.h
+++ b/include/linux/bcma/bcma_driver_chipcommon.h
@@ -258,6 +258,7 @@ struct bcma_drv_cc {
 	u32 status;
 	u32 capabilities;
 	u32 capabilities_ext;
+	u8 setup_done:1;
 	/* Fast Powerup Delay constant */
 	u16 fast_pwrup_delay;
 	struct bcma_chipcommon_pmu pmu;
-- 
1.7.4.1


From hauke@hauke-m.de Sat Jul 16 18:56:14 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 16 Jul 2011 18:58:03 +0200 (CEST)
Received: from server19320154104.serverpool.info ([193.201.54.104]:50860 "EHLO
        hauke-m.de" rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org
        with ESMTP id S1491051Ab1GPQ4O (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Sat, 16 Jul 2011 18:56:14 +0200
Received: from localhost (localhost [127.0.0.1])
        by hauke-m.de (Postfix) with ESMTP id A3A3B8C64;
        Sat, 16 Jul 2011 18:56:14 +0200 (CEST)
X-Virus-Scanned: Debian amavisd-new at hauke-m.de 
Received: from hauke-m.de ([127.0.0.1])
        by localhost (hauke-m.de [127.0.0.1]) (amavisd-new, port 10024)
        with ESMTP id sha1qRxVrn6v; Sat, 16 Jul 2011 18:56:09 +0200 (CEST)
Received: from localhost.localdomain (host-091-097-255-051.ewe-ip-backbone.de [91.97.255.51])
        by hauke-m.de (Postfix) with ESMTPSA id 673468C67;
        Sat, 16 Jul 2011 18:56:03 +0200 (CEST)
From:   Hauke Mehrtens <hauke@hauke-m.de>
To:     ralf@linux-mips.org, linux-wireless@vger.kernel.org,
        zajec5@gmail.com, linux-mips@linux-mips.org
Cc:     jonas.gorski@gmail.com, mb@bu3sch.de, george@znau.edu.ua,
        arend@broadcom.com, b43-dev@lists.infradead.org,
        bernhardloos@googlemail.com, arnd@arndb.de,
        julian.calaby@gmail.com, sshtylyov@mvista.com,
        Hauke Mehrtens <hauke@hauke-m.de>
Subject: [PATCH v2 04/11] bcma: add SOC bus
Date:   Sat, 16 Jul 2011 18:55:35 +0200
Message-Id: <1310835342-18877-5-git-send-email-hauke@hauke-m.de>
X-Mailer: git-send-email 1.7.4.1
In-Reply-To: <1310835342-18877-1-git-send-email-hauke@hauke-m.de>
References: <1310835342-18877-1-git-send-email-hauke@hauke-m.de>
X-archive-position: 30635
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: hauke@hauke-m.de
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 11706
Content-Length: 9274
Lines: 386

This patch adds support for using bcma on a Broadcom SoC as the system
bus. An SoC like the bcm4716 could register this bus and use it to
searches for the bcma cores and register the devices on this bus.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 drivers/bcma/Kconfig          |    4 +
 drivers/bcma/Makefile         |    1 +
 drivers/bcma/host_soc.c       |  183 +++++++++++++++++++++++++++++++++++++++++
 drivers/bcma/main.c           |    5 +
 drivers/bcma/scan.c           |   42 ++++++++-
 include/linux/bcma/bcma.h     |    4 +
 include/linux/bcma/bcma_soc.h |   16 ++++
 7 files changed, 250 insertions(+), 5 deletions(-)
 create mode 100644 drivers/bcma/host_soc.c
 create mode 100644 include/linux/bcma/bcma_soc.h

diff --git a/drivers/bcma/Kconfig b/drivers/bcma/Kconfig
index 353781b..bedbb3b 100644
--- a/drivers/bcma/Kconfig
+++ b/drivers/bcma/Kconfig
@@ -22,6 +22,10 @@ config BCMA_HOST_PCI
 	bool "Support for BCMA on PCI-host bus"
 	depends on BCMA_HOST_PCI_POSSIBLE
 
+config BCMA_HOST_SOC
+	bool
+	depends on BCMA && MIPS
+
 config BCMA_DEBUG
 	bool "BCMA debugging"
 	depends on BCMA
diff --git a/drivers/bcma/Makefile b/drivers/bcma/Makefile
index 0d56245..42d61dd 100644
--- a/drivers/bcma/Makefile
+++ b/drivers/bcma/Makefile
@@ -2,6 +2,7 @@ bcma-y					+= main.o scan.o core.o
 bcma-y					+= driver_chipcommon.o driver_chipcommon_pmu.o
 bcma-y					+= driver_pci.o
 bcma-$(CONFIG_BCMA_HOST_PCI)		+= host_pci.o
+bcma-$(CONFIG_BCMA_HOST_SOC)		+= host_soc.o
 obj-$(CONFIG_BCMA)			+= bcma.o
 
 ccflags-$(CONFIG_BCMA_DEBUG)		:= -DDEBUG
diff --git a/drivers/bcma/host_soc.c b/drivers/bcma/host_soc.c
new file mode 100644
index 0000000..3c381fb
--- /dev/null
+++ b/drivers/bcma/host_soc.c
@@ -0,0 +1,183 @@
+/*
+ * Broadcom specific AMBA
+ * System on Chip (SoC) Host
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include "bcma_private.h"
+#include "scan.h"
+#include <linux/bcma/bcma.h>
+#include <linux/bcma/bcma_soc.h>
+
+static u8 bcma_host_soc_read8(struct bcma_device *core, u16 offset)
+{
+	return readb(core->io_addr + offset);
+}
+
+static u16 bcma_host_soc_read16(struct bcma_device *core, u16 offset)
+{
+	return readw(core->io_addr + offset);
+}
+
+static u32 bcma_host_soc_read32(struct bcma_device *core, u16 offset)
+{
+	return readl(core->io_addr + offset);
+}
+
+static void bcma_host_soc_write8(struct bcma_device *core, u16 offset,
+				 u8 value)
+{
+	writeb(value, core->io_addr + offset);
+}
+
+static void bcma_host_soc_write16(struct bcma_device *core, u16 offset,
+				 u16 value)
+{
+	writew(value, core->io_addr + offset);
+}
+
+static void bcma_host_soc_write32(struct bcma_device *core, u16 offset,
+				 u32 value)
+{
+	writel(value, core->io_addr + offset);
+}
+
+#ifdef CONFIG_BCMA_BLOCKIO
+static void bcma_host_soc_block_read(struct bcma_device *core, void *buffer,
+				     size_t count, u16 offset, u8 reg_width)
+{
+	void __iomem *addr = core->io_addr + offset;
+
+	switch (reg_width) {
+	case sizeof(u8): {
+		u8 *buf = buffer;
+
+		while (count) {
+			*buf = __raw_readb(addr);
+			buf++;
+			count--;
+		}
+		break;
+	}
+	case sizeof(u16): {
+		__le16 *buf = buffer;
+
+		WARN_ON(count & 1);
+		while (count) {
+			*buf = (__force __le16)__raw_readw(addr);
+			buf++;
+			count -= 2;
+		}
+		break;
+	}
+	case sizeof(u32): {
+		__le32 *buf = buffer;
+
+		WARN_ON(count & 3);
+		while (count) {
+			*buf = (__force __le32)__raw_readl(addr);
+			buf++;
+			count -= 4;
+		}
+		break;
+	}
+	default:
+		WARN_ON(1);
+	}
+}
+
+static void bcma_host_soc_block_write(struct bcma_device *core,
+				      const void *buffer,
+				      size_t count, u16 offset, u8 reg_width)
+{
+	void __iomem *addr = core->io_addr + offset;
+
+	switch (reg_width) {
+	case sizeof(u8): {
+		const u8 *buf = buffer;
+
+		while (count) {
+			__raw_writeb(*buf, addr);
+			buf++;
+			count--;
+		}
+		break;
+	}
+	case sizeof(u16): {
+		const __le16 *buf = buffer;
+
+		WARN_ON(count & 1);
+		while (count) {
+			__raw_writew((__force u16)(*buf), addr);
+			buf++;
+			count -= 2;
+		}
+		break;
+	}
+	case sizeof(u32): {
+		const __le32 *buf = buffer;
+
+		WARN_ON(count & 3);
+		while (count) {
+			__raw_writel((__force u32)(*buf), addr);
+			buf++;
+			count -= 4;
+		}
+		break;
+	}
+	default:
+		WARN_ON(1);
+	}
+}
+#endif /* CONFIG_BCMA_BLOCKIO */
+
+static u32 bcma_host_soc_aread32(struct bcma_device *core, u16 offset)
+{
+	return readl(core->io_wrap + offset);
+}
+
+static void bcma_host_soc_awrite32(struct bcma_device *core, u16 offset,
+				  u32 value)
+{
+	writel(value, core->io_wrap + offset);
+}
+
+const struct bcma_host_ops bcma_host_soc_ops = {
+	.read8		= bcma_host_soc_read8,
+	.read16		= bcma_host_soc_read16,
+	.read32		= bcma_host_soc_read32,
+	.write8		= bcma_host_soc_write8,
+	.write16	= bcma_host_soc_write16,
+	.write32	= bcma_host_soc_write32,
+#ifdef CONFIG_BCMA_BLOCKIO
+	.block_read	= bcma_host_soc_block_read,
+	.block_write	= bcma_host_soc_block_write,
+#endif
+	.aread32	= bcma_host_soc_aread32,
+	.awrite32	= bcma_host_soc_awrite32,
+};
+
+int __init bcma_host_soc_register(struct bcma_soc *soc)
+{
+	struct bcma_bus *bus = &soc->bus;
+	int err;
+
+	/* iomap only first core. We have to read some register on this core
+	 * to scan the bus.
+	 */
+	bus->mmio = ioremap_nocache(BCMA_ADDR_BASE, BCMA_CORE_SIZE * 1);
+	if (!bus->mmio)
+		return -ENOMEM;
+
+	/* Host specific */
+	bus->hosttype = BCMA_HOSTTYPE_SOC;
+	bus->ops = &bcma_host_soc_ops;
+
+	/* Register */
+	err = bcma_bus_early_register(bus, &soc->core_cc, &soc->core_mips);
+	if (err)
+		iounmap(bus->mmio);
+
+	return err;
+}
diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c
index e6c308c..9360b35 100644
--- a/drivers/bcma/main.c
+++ b/drivers/bcma/main.c
@@ -65,6 +65,10 @@ static struct bcma_device *bcma_find_core(struct bcma_bus *bus, u16 coreid)
 static void bcma_release_core_dev(struct device *dev)
 {
 	struct bcma_device *core = container_of(dev, struct bcma_device, dev);
+	if (core->io_addr)
+		iounmap(core->io_addr);
+	if (core->io_wrap)
+		iounmap(core->io_wrap);
 	kfree(core);
 }
 
@@ -92,6 +96,7 @@ static int bcma_register_cores(struct bcma_bus *bus)
 			break;
 		case BCMA_HOSTTYPE_NONE:
 		case BCMA_HOSTTYPE_SDIO:
+		case BCMA_HOSTTYPE_SOC:
 			break;
 		}
 
diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c
index bf9f806..0ea390f 100644
--- a/drivers/bcma/scan.c
+++ b/drivers/bcma/scan.c
@@ -337,6 +337,16 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
 			}
 		}
 	}
+	if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
+		core->io_addr = ioremap_nocache(core->addr, BCMA_CORE_SIZE);
+		if (!core->io_addr)
+			return -ENOMEM;
+		core->io_wrap = ioremap_nocache(core->wrap, BCMA_CORE_SIZE);
+		if (!core->io_wrap) {
+			iounmap(core->io_addr);
+			return -ENOMEM;
+		}
+	}
 	return 0;
 }
 
@@ -369,7 +379,14 @@ int bcma_bus_scan(struct bcma_bus *bus)
 	bcma_init_bus(bus);
 
 	erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
-	eromptr = bus->mmio;
+	if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
+		eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE);
+		if (!eromptr)
+			return -ENOMEM;
+	} else {
+		eromptr = bus->mmio;
+	}
+
 	eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
 
 	bcma_scan_switch_core(bus, erombase);
@@ -404,6 +421,9 @@ int bcma_bus_scan(struct bcma_bus *bus)
 		list_add(&core->list, &bus->cores);
 	}
 
+	if (bus->hosttype == BCMA_HOSTTYPE_SOC)
+		iounmap(eromptr);
+
 	return 0;
 }
 
@@ -414,10 +434,18 @@ int __init bcma_bus_scan_early(struct bcma_bus *bus,
 	u32 erombase;
 	u32 __iomem *eromptr, *eromend;
 
-	int err, core_num = 0;
+	int err = -ENODEV;
+	int core_num = 0;
 
 	erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
-	eromptr = bus->mmio;
+	if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
+		eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE);
+		if (!eromptr)
+			return -ENOMEM;
+	} else {
+		eromptr = bus->mmio;
+	}
+
 	eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
 
 	bcma_scan_switch_core(bus, erombase);
@@ -447,8 +475,12 @@ int __init bcma_bus_scan_early(struct bcma_bus *bus,
 			core->id.class);
 
 		list_add(&core->list, &bus->cores);
-		return 0;
+		err = 0;
+		break;
 	}
 
-	return -ENODEV;
+	if (bus->hosttype == BCMA_HOSTTYPE_SOC)
+		iounmap(eromptr);
+
+	return err;
 }
diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h
index 6bd7b7f..73fda1c 100644
--- a/include/linux/bcma/bcma.h
+++ b/include/linux/bcma/bcma.h
@@ -16,6 +16,7 @@ enum bcma_hosttype {
 	BCMA_HOSTTYPE_NONE,
 	BCMA_HOSTTYPE_PCI,
 	BCMA_HOSTTYPE_SDIO,
+	BCMA_HOSTTYPE_SOC,
 };
 
 struct bcma_chipinfo {
@@ -124,6 +125,9 @@ struct bcma_device {
 	u32 addr;
 	u32 wrap;
 
+	void __iomem *io_addr;
+	void __iomem *io_wrap;
+
 	void *drvdata;
 	struct list_head list;
 };
diff --git a/include/linux/bcma/bcma_soc.h b/include/linux/bcma/bcma_soc.h
new file mode 100644
index 0000000..4203c55
--- /dev/null
+++ b/include/linux/bcma/bcma_soc.h
@@ -0,0 +1,16 @@
+#ifndef LINUX_BCMA_SOC_H_
+#define LINUX_BCMA_SOC_H_
+
+#include <linux/bcma/bcma.h>
+
+struct bcma_soc {
+	struct bcma_bus bus;
+	struct bcma_device core_cc;
+	struct bcma_device core_mips;
+};
+
+int __init bcma_host_soc_register(struct bcma_soc *soc);
+
+int bcma_bus_register(struct bcma_bus *bus);
+
+#endif /* LINUX_BCMA_SOC_H_ */
-- 
1.7.4.1


From hauke@hauke-m.de Sat Jul 16 18:56:17 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 16 Jul 2011 18:58:36 +0200 (CEST)
Received: from server19320154104.serverpool.info ([193.201.54.104]:50869 "EHLO
        hauke-m.de" rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org
        with ESMTP id S1491076Ab1GPQ4R (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Sat, 16 Jul 2011 18:56:17 +0200
Received: from localhost (localhost [127.0.0.1])
        by hauke-m.de (Postfix) with ESMTP id 1F1E18C67;
        Sat, 16 Jul 2011 18:56:17 +0200 (CEST)
X-Virus-Scanned: Debian amavisd-new at hauke-m.de 
Received: from hauke-m.de ([127.0.0.1])
        by localhost (hauke-m.de [127.0.0.1]) (amavisd-new, port 10024)
        with ESMTP id wZWlaQvA4zQ6; Sat, 16 Jul 2011 18:56:11 +0200 (CEST)
Received: from localhost.localdomain (host-091-097-255-051.ewe-ip-backbone.de [91.97.255.51])
        by hauke-m.de (Postfix) with ESMTPSA id 5D2DB8C4F;
        Sat, 16 Jul 2011 18:56:04 +0200 (CEST)
From:   Hauke Mehrtens <hauke@hauke-m.de>
To:     ralf@linux-mips.org, linux-wireless@vger.kernel.org,
        zajec5@gmail.com, linux-mips@linux-mips.org
Cc:     jonas.gorski@gmail.com, mb@bu3sch.de, george@znau.edu.ua,
        arend@broadcom.com, b43-dev@lists.infradead.org,
        bernhardloos@googlemail.com, arnd@arndb.de,
        julian.calaby@gmail.com, sshtylyov@mvista.com,
        Hauke Mehrtens <hauke@hauke-m.de>
Subject: [PATCH v2 05/11] bcma: add mips driver
Date:   Sat, 16 Jul 2011 18:55:36 +0200
Message-Id: <1310835342-18877-6-git-send-email-hauke@hauke-m.de>
X-Mailer: git-send-email 1.7.4.1
In-Reply-To: <1310835342-18877-1-git-send-email-hauke@hauke-m.de>
References: <1310835342-18877-1-git-send-email-hauke@hauke-m.de>
X-archive-position: 30636
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: hauke@hauke-m.de
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 11707
Content-Length: 13420
Lines: 470

This adds a mips driver to bcma. This is only found on embedded
devices. For now the driver just initializes the irqs used on this
system.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 drivers/bcma/Kconfig                        |    9 +
 drivers/bcma/Makefile                       |    1 +
 drivers/bcma/driver_mips.c                  |  243 +++++++++++++++++++++++++++
 drivers/bcma/main.c                         |   15 ++
 include/linux/bcma/bcma.h                   |    3 +
 include/linux/bcma/bcma_driver_chipcommon.h |   13 ++
 include/linux/bcma/bcma_driver_mips.h       |   49 ++++++
 7 files changed, 333 insertions(+), 0 deletions(-)
 create mode 100644 drivers/bcma/driver_mips.c
 create mode 100644 include/linux/bcma/bcma_driver_mips.h

diff --git a/drivers/bcma/Kconfig b/drivers/bcma/Kconfig
index bedbb3b..52f488d 100644
--- a/drivers/bcma/Kconfig
+++ b/drivers/bcma/Kconfig
@@ -24,7 +24,16 @@ config BCMA_HOST_PCI
 
 config BCMA_HOST_SOC
 	bool
+	depends on BCMA_DRIVER_MIPS
+
+config BCMA_DRIVER_MIPS
+	bool "BCMA Broadcom MIPS core driver"
 	depends on BCMA && MIPS
+	help
+	  Driver for the Broadcom MIPS core attached to Broadcom specific
+	  Advanced Microcontroller Bus.
+
+	  If unsure, say N
 
 config BCMA_DEBUG
 	bool "BCMA debugging"
diff --git a/drivers/bcma/Makefile b/drivers/bcma/Makefile
index 42d61dd..a4352e5 100644
--- a/drivers/bcma/Makefile
+++ b/drivers/bcma/Makefile
@@ -1,6 +1,7 @@
 bcma-y					+= main.o scan.o core.o
 bcma-y					+= driver_chipcommon.o driver_chipcommon_pmu.o
 bcma-y					+= driver_pci.o
+bcma-$(CONFIG_BCMA_DRIVER_MIPS)		+= driver_mips.o
 bcma-$(CONFIG_BCMA_HOST_PCI)		+= host_pci.o
 bcma-$(CONFIG_BCMA_HOST_SOC)		+= host_soc.o
 obj-$(CONFIG_BCMA)			+= bcma.o
diff --git a/drivers/bcma/driver_mips.c b/drivers/bcma/driver_mips.c
new file mode 100644
index 0000000..4b60c9f9
--- /dev/null
+++ b/drivers/bcma/driver_mips.c
@@ -0,0 +1,243 @@
+/*
+ * Broadcom specific AMBA
+ * Broadcom MIPS32 74K core driver
+ *
+ * Copyright 2009, Broadcom Corporation
+ * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
+ * Copyright 2010, Bernhard Loos <bernhardloos@googlemail.com>
+ * Copyright 2011, Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include "bcma_private.h"
+
+#include <linux/bcma/bcma.h>
+
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/serial_reg.h>
+#include <linux/time.h>
+
+/* The 47162a0 hangs when reading MIPS DMP registers registers */
+static inline bool bcma_core_mips_bcm47162a0_quirk(struct bcma_device *dev)
+{
+	return dev->bus->chipinfo.id == 47162 && dev->bus->chipinfo.rev == 0 &&
+	       dev->id.id == BCMA_CORE_MIPS_74K;
+}
+
+/* The 5357b0 hangs when reading USB20H DMP registers */
+static inline bool bcma_core_mips_bcm5357b0_quirk(struct bcma_device *dev)
+{
+	return (dev->bus->chipinfo.id == 0x5357 ||
+		dev->bus->chipinfo.id == 0x4749) &&
+	       dev->bus->chipinfo.pkg == 11 &&
+	       dev->id.id == BCMA_CORE_USB20_HOST;
+}
+
+static inline u32 mips_read32(struct bcma_drv_mips *mcore,
+			      u16 offset)
+{
+	return bcma_read32(mcore->core, offset);
+}
+
+static inline void mips_write32(struct bcma_drv_mips *mcore,
+				u16 offset,
+				u32 value)
+{
+	bcma_write32(mcore->core, offset, value);
+}
+
+static const u32 ipsflag_irq_mask[] = {
+	0,
+	BCMA_MIPS_IPSFLAG_IRQ1,
+	BCMA_MIPS_IPSFLAG_IRQ2,
+	BCMA_MIPS_IPSFLAG_IRQ3,
+	BCMA_MIPS_IPSFLAG_IRQ4,
+};
+
+static const u32 ipsflag_irq_shift[] = {
+	0,
+	BCMA_MIPS_IPSFLAG_IRQ1_SHIFT,
+	BCMA_MIPS_IPSFLAG_IRQ2_SHIFT,
+	BCMA_MIPS_IPSFLAG_IRQ3_SHIFT,
+	BCMA_MIPS_IPSFLAG_IRQ4_SHIFT,
+};
+
+static u32 bcma_core_mips_irqflag(struct bcma_device *dev)
+{
+	u32 flag;
+
+	if (bcma_core_mips_bcm47162a0_quirk(dev))
+		return dev->core_index;
+	if (bcma_core_mips_bcm5357b0_quirk(dev))
+		return dev->core_index;
+	flag = bcma_aread32(dev, BCMA_MIPS_OOBSELOUTA30);
+
+	return flag & 0x1F;
+}
+
+/* Get the MIPS IRQ assignment for a specified device.
+ * If unassigned, 0 is returned.
+ */
+unsigned int bcma_core_mips_irq(struct bcma_device *dev)
+{
+	struct bcma_device *mdev = dev->bus->drv_mips.core;
+	u32 irqflag;
+	unsigned int irq;
+
+	irqflag = bcma_core_mips_irqflag(dev);
+
+	for (irq = 1; irq <= 4; irq++)
+		if (bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq)) &
+		    (1 << irqflag))
+			return irq;
+
+	return 0;
+}
+EXPORT_SYMBOL(bcma_core_mips_irq);
+
+static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq)
+{
+	unsigned int oldirq = bcma_core_mips_irq(dev);
+	struct bcma_bus *bus = dev->bus;
+	struct bcma_device *mdev = bus->drv_mips.core;
+	u32 irqflag;
+
+	irqflag = bcma_core_mips_irqflag(dev);
+	BUG_ON(oldirq == 6);
+
+	dev->irq = irq + 2;
+
+	/* clear the old irq */
+	if (oldirq == 0)
+		bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0),
+			    bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) &
+			    ~(1 << irqflag));
+	else
+		bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq), 0);
+
+	/* assign the new one */
+	if (irq == 0) {
+		bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0),
+			    bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) |
+			    (1 << irqflag));
+	} else {
+		u32 oldirqflag = bcma_read32(mdev,
+					     BCMA_MIPS_MIPS74K_INTMASK(irq));
+		if (oldirqflag) {
+			struct bcma_device *core;
+
+			/* backplane irq line is in use, find out who uses
+			 * it and set user to irq 0
+			 */
+			list_for_each_entry_reverse(core, &bus->cores, list) {
+				if ((1 << bcma_core_mips_irqflag(core)) ==
+				    oldirqflag) {
+					bcma_core_mips_set_irq(core, 0);
+					break;
+				}
+			}
+		}
+		bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq),
+			     1 << irqflag);
+	}
+
+	pr_info("set_irq: core 0x%04x, irq %d => %d\n",
+		dev->id.id, oldirq + 2, irq + 2);
+}
+
+static void bcma_core_mips_print_irq(struct bcma_device *dev, unsigned int irq)
+{
+	int i;
+	static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"};
+	printk(KERN_INFO KBUILD_MODNAME ": core 0x%04x, irq :", dev->id.id);
+	for (i = 0; i <= 6; i++)
+		printk(" %s%s", irq_name[i], i == irq ? "*" : " ");
+	printk("\n");
+}
+
+static void bcma_core_mips_dump_irq(struct bcma_bus *bus)
+{
+	struct bcma_device *core;
+
+	list_for_each_entry_reverse(core, &bus->cores, list) {
+		bcma_core_mips_print_irq(core, bcma_core_mips_irq(core));
+	}
+}
+
+static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
+{
+	struct bcma_bus *bus = mcore->core->bus;
+
+	switch (bus->drv_cc.capabilities & BCMA_CC_CAP_FLASHT) {
+	case BCMA_CC_FLASHT_STSER:
+	case BCMA_CC_FLASHT_ATSER:
+		pr_err("Serial flash not supported.\n");
+		break;
+	case BCMA_CC_FLASHT_PARA:
+		pr_info("found parallel flash.\n");
+		bus->drv_cc.pflash.window = 0x1c000000;
+		bus->drv_cc.pflash.window_size = 0x02000000;
+
+		if ((bcma_read32(bus->drv_cc.core, BCMA_CC_FLASH_CFG) &
+		     BCMA_CC_FLASH_CFG_DS) == 0)
+			bus->drv_cc.pflash.buswidth = 1;
+		else
+			bus->drv_cc.pflash.buswidth = 2;
+		break;
+	default:
+		pr_err("flash not supported.\n");
+	}
+}
+
+void bcma_core_mips_init(struct bcma_drv_mips *mcore)
+{
+	struct bcma_bus *bus;
+	struct bcma_device *core;
+	bus = mcore->core->bus;
+
+	pr_info("Initializing MIPS core...\n");
+
+	if (!mcore->setup_done)
+		mcore->assigned_irqs = 1;
+
+	/* Assign IRQs to all cores on the bus */
+	list_for_each_entry_reverse(core, &bus->cores, list) {
+		int mips_irq;
+		if (core->irq)
+			continue;
+
+		mips_irq = bcma_core_mips_irq(core);
+		if (mips_irq > 4)
+			core->irq = 0;
+		else
+			core->irq = mips_irq + 2;
+		if (core->irq > 5)
+			continue;
+		switch (core->id.id) {
+		case BCMA_CORE_PCI:
+		case BCMA_CORE_PCIE:
+		case BCMA_CORE_ETHERNET:
+		case BCMA_CORE_ETHERNET_GBIT:
+		case BCMA_CORE_MAC_GBIT:
+		case BCMA_CORE_80211:
+		case BCMA_CORE_USB20_HOST:
+			/* These devices get their own IRQ line if available,
+			 * the rest goes on IRQ0
+			 */
+			if (mcore->assigned_irqs <= 4)
+				bcma_core_mips_set_irq(core,
+						       mcore->assigned_irqs++);
+			break;
+		}
+	}
+	pr_info("IRQ reconfiguration done\n");
+	bcma_core_mips_dump_irq(bus);
+
+	if (mcore->setup_done)
+		return;
+
+	bcma_core_mips_flash_detect(mcore);
+	mcore->setup_done = true;
+}
diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c
index 9360b35..e8b4ba1 100644
--- a/drivers/bcma/main.c
+++ b/drivers/bcma/main.c
@@ -83,6 +83,7 @@ static int bcma_register_cores(struct bcma_bus *bus)
 		case BCMA_CORE_CHIPCOMMON:
 		case BCMA_CORE_PCI:
 		case BCMA_CORE_PCIE:
+		case BCMA_CORE_MIPS_74K:
 			continue;
 		}
 
@@ -142,6 +143,13 @@ int bcma_bus_register(struct bcma_bus *bus)
 		bcma_core_chipcommon_init(&bus->drv_cc);
 	}
 
+	/* Init MIPS core */
+	core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
+	if (core) {
+		bus->drv_mips.core = core;
+		bcma_core_mips_init(&bus->drv_mips);
+	}
+
 	/* Init PCIE core */
 	core = bcma_find_core(bus, BCMA_CORE_PCIE);
 	if (core) {
@@ -204,6 +212,13 @@ int __init bcma_bus_early_register(struct bcma_bus *bus,
 		bcma_core_chipcommon_init(&bus->drv_cc);
 	}
 
+	/* Init MIPS core */
+	core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
+	if (core) {
+		bus->drv_mips.core = core;
+		bcma_core_mips_init(&bus->drv_mips);
+	}
+
 	pr_info("Early bus registered\n");
 
 	return 0;
diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h
index 73fda1c..12313fd 100644
--- a/include/linux/bcma/bcma.h
+++ b/include/linux/bcma/bcma.h
@@ -6,6 +6,7 @@
 
 #include <linux/bcma/bcma_driver_chipcommon.h>
 #include <linux/bcma/bcma_driver_pci.h>
+#include <linux/bcma/bcma_driver_mips.h>
 
 #include "bcma_regs.h"
 
@@ -118,6 +119,7 @@ struct bcma_device {
 	struct bcma_device_id id;
 
 	struct device dev;
+	unsigned int irq;
 	bool dev_registered;
 
 	u8 core_index;
@@ -184,6 +186,7 @@ struct bcma_bus {
 
 	struct bcma_drv_cc drv_cc;
 	struct bcma_drv_pci drv_pci;
+	struct bcma_drv_mips drv_mips;
 };
 
 extern inline u32 bcma_read8(struct bcma_device *core, u16 offset)
diff --git a/include/linux/bcma/bcma_driver_chipcommon.h b/include/linux/bcma/bcma_driver_chipcommon.h
index 837c176..0d44121 100644
--- a/include/linux/bcma/bcma_driver_chipcommon.h
+++ b/include/linux/bcma/bcma_driver_chipcommon.h
@@ -24,6 +24,7 @@
 #define   BCMA_CC_FLASHT_NONE		0x00000000	/* No flash */
 #define   BCMA_CC_FLASHT_STSER		0x00000100	/* ST serial flash */
 #define   BCMA_CC_FLASHT_ATSER		0x00000200	/* Atmel serial flash */
+#define   BCMA_CC_FLASHT_NFLASH		0x00000200
 #define	  BCMA_CC_FLASHT_PARA		0x00000700	/* Parallel flash */
 #define  BCMA_CC_CAP_PLLT		0x00038000	/* PLL Type */
 #define   BCMA_PLLTYPE_NONE		0x00000000
@@ -178,6 +179,7 @@
 #define BCMA_CC_PROG_CFG		0x0120
 #define BCMA_CC_PROG_WAITCNT		0x0124
 #define BCMA_CC_FLASH_CFG		0x0128
+#define  BCMA_CC_FLASH_CFG_DS		0x0010	/* Data size, 0=8bit, 1=16bit */
 #define BCMA_CC_FLASH_WAITCNT		0x012C
 #define BCMA_CC_CLKCTLST		0x01E0 /* Clock control and status (rev >= 20) */
 #define  BCMA_CC_CLKCTLST_FORCEALP	0x00000001 /* Force ALP request */
@@ -253,6 +255,14 @@ struct bcma_chipcommon_pmu {
 	u32 crystalfreq;	/* The active crystal frequency (in kHz) */
 };
 
+#ifdef CONFIG_BCMA_DRIVER_MIPS
+struct bcma_pflash {
+	u8 buswidth;
+	u32 window;
+	u32 window_size;
+};
+#endif /* CONFIG_BCMA_DRIVER_MIPS */
+
 struct bcma_drv_cc {
 	struct bcma_device *core;
 	u32 status;
@@ -262,6 +272,9 @@ struct bcma_drv_cc {
 	/* Fast Powerup Delay constant */
 	u16 fast_pwrup_delay;
 	struct bcma_chipcommon_pmu pmu;
+#ifdef CONFIG_BCMA_DRIVER_MIPS
+	struct bcma_pflash pflash;
+#endif /* CONFIG_BCMA_DRIVER_MIPS */
 };
 
 /* Register access */
diff --git a/include/linux/bcma/bcma_driver_mips.h b/include/linux/bcma/bcma_driver_mips.h
new file mode 100644
index 0000000..82b3bfd
--- /dev/null
+++ b/include/linux/bcma/bcma_driver_mips.h
@@ -0,0 +1,49 @@
+#ifndef LINUX_BCMA_DRIVER_MIPS_H_
+#define LINUX_BCMA_DRIVER_MIPS_H_
+
+#define BCMA_MIPS_IPSFLAG		0x0F08
+/* which sbflags get routed to mips interrupt 1 */
+#define  BCMA_MIPS_IPSFLAG_IRQ1		0x0000003F
+#define  BCMA_MIPS_IPSFLAG_IRQ1_SHIFT	0
+/* which sbflags get routed to mips interrupt 2 */
+#define  BCMA_MIPS_IPSFLAG_IRQ2		0x00003F00
+#define  BCMA_MIPS_IPSFLAG_IRQ2_SHIFT	8
+/* which sbflags get routed to mips interrupt 3 */
+#define  BCMA_MIPS_IPSFLAG_IRQ3		0x003F0000
+#define  BCMA_MIPS_IPSFLAG_IRQ3_SHIFT	16
+/* which sbflags get routed to mips interrupt 4 */
+#define  BCMA_MIPS_IPSFLAG_IRQ4		0x3F000000
+#define  BCMA_MIPS_IPSFLAG_IRQ4_SHIFT	24
+
+/* MIPS 74K core registers */
+#define BCMA_MIPS_MIPS74K_CORECTL	0x0000
+#define BCMA_MIPS_MIPS74K_EXCEPTBASE	0x0004
+#define BCMA_MIPS_MIPS74K_BIST		0x000C
+#define BCMA_MIPS_MIPS74K_INTMASK_INT0	0x0014
+#define BCMA_MIPS_MIPS74K_INTMASK(int) \
+	((int) * 4 + BCMA_MIPS_MIPS74K_INTMASK_INT0)
+#define BCMA_MIPS_MIPS74K_NMIMASK	0x002C
+#define BCMA_MIPS_MIPS74K_GPIOSEL	0x0040
+#define BCMA_MIPS_MIPS74K_GPIOOUT	0x0044
+#define BCMA_MIPS_MIPS74K_GPIOEN	0x0048
+#define BCMA_MIPS_MIPS74K_CLKCTLST	0x01E0
+
+#define BCMA_MIPS_OOBSELOUTA30		0x100
+
+struct bcma_device;
+
+struct bcma_drv_mips {
+	struct bcma_device *core;
+	u8 setup_done:1;
+	unsigned int assigned_irqs;
+};
+
+#ifdef CONFIG_BCMA_DRIVER_MIPS
+extern void bcma_core_mips_init(struct bcma_drv_mips *mcore);
+#else
+static inline void bcma_core_mips_init(struct bcma_drv_mips *mcore) { }
+#endif
+
+extern unsigned int bcma_core_mips_irq(struct bcma_device *dev);
+
+#endif /* LINUX_BCMA_DRIVER_MIPS_H_ */
-- 
1.7.4.1


From hauke@hauke-m.de Sat Jul 16 18:56:20 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 16 Jul 2011 18:59:02 +0200 (CEST)
Received: from server19320154104.serverpool.info ([193.201.54.104]:50880 "EHLO
        hauke-m.de" rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org
        with ESMTP id S1491082Ab1GPQ4U (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Sat, 16 Jul 2011 18:56:20 +0200
Received: from localhost (localhost [127.0.0.1])
        by hauke-m.de (Postfix) with ESMTP id AE3BF8C6F;
        Sat, 16 Jul 2011 18:56:19 +0200 (CEST)
X-Virus-Scanned: Debian amavisd-new at hauke-m.de 
Received: from hauke-m.de ([127.0.0.1])
        by localhost (hauke-m.de [127.0.0.1]) (amavisd-new, port 10024)
        with ESMTP id aZFr+28hPUUl; Sat, 16 Jul 2011 18:56:15 +0200 (CEST)
Received: from localhost.localdomain (host-091-097-255-051.ewe-ip-backbone.de [91.97.255.51])
        by hauke-m.de (Postfix) with ESMTPSA id 62FAF8C68;
        Sat, 16 Jul 2011 18:56:05 +0200 (CEST)
From:   Hauke Mehrtens <hauke@hauke-m.de>
To:     ralf@linux-mips.org, linux-wireless@vger.kernel.org,
        zajec5@gmail.com, linux-mips@linux-mips.org
Cc:     jonas.gorski@gmail.com, mb@bu3sch.de, george@znau.edu.ua,
        arend@broadcom.com, b43-dev@lists.infradead.org,
        bernhardloos@googlemail.com, arnd@arndb.de,
        julian.calaby@gmail.com, sshtylyov@mvista.com,
        Hauke Mehrtens <hauke@hauke-m.de>
Subject: [PATCH v2 06/11] bcma: add serial console support
Date:   Sat, 16 Jul 2011 18:55:37 +0200
Message-Id: <1310835342-18877-7-git-send-email-hauke@hauke-m.de>
X-Mailer: git-send-email 1.7.4.1
In-Reply-To: <1310835342-18877-1-git-send-email-hauke@hauke-m.de>
References: <1310835342-18877-1-git-send-email-hauke@hauke-m.de>
X-archive-position: 30637
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: hauke@hauke-m.de
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 11708
Content-Length: 5294
Lines: 174

This adds support for serial console to bcma, when operating on an SoC.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 drivers/bcma/bcma_private.h                 |    8 ++++
 drivers/bcma/driver_chipcommon.c            |   48 +++++++++++++++++++++++++++
 drivers/bcma/driver_chipcommon_pmu.c        |   26 ++++++++++++++
 drivers/bcma/driver_mips.c                  |    1 +
 include/linux/bcma/bcma_driver_chipcommon.h |   14 ++++++++
 5 files changed, 97 insertions(+), 0 deletions(-)

diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h
index 830386c..b9b4587 100644
--- a/drivers/bcma/bcma_private.h
+++ b/drivers/bcma/bcma_private.h
@@ -26,6 +26,14 @@ int __init bcma_bus_scan_early(struct bcma_bus *bus,
 			       struct bcma_device *core);
 void bcma_init_bus(struct bcma_bus *bus);
 
+/* driver_chipcommon.c */
+#ifdef CONFIG_BCMA_DRIVER_MIPS
+void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
+#endif /* CONFIG_BCMA_DRIVER_MIPS */
+
+/* driver_chipcommon_pmu.c */
+u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc);
+
 #ifdef CONFIG_BCMA_HOST_PCI
 /* host_pci.c */
 extern int __init bcma_host_pci_init(void);
diff --git a/drivers/bcma/driver_chipcommon.c b/drivers/bcma/driver_chipcommon.c
index 70321c6..aaf035a 100644
--- a/drivers/bcma/driver_chipcommon.c
+++ b/drivers/bcma/driver_chipcommon.c
@@ -92,3 +92,51 @@ u32 bcma_chipco_gpio_polarity(struct bcma_drv_cc *cc, u32 mask, u32 value)
 {
 	return bcma_cc_write32_masked(cc, BCMA_CC_GPIOPOL, mask, value);
 }
+
+#ifdef CONFIG_BCMA_DRIVER_MIPS
+void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
+{
+	unsigned int irq;
+	u32 baud_base;
+	u32 i;
+	unsigned int ccrev = cc->core->id.rev;
+	struct bcma_serial_port *ports = cc->serial_ports;
+
+	if (ccrev >= 11 && ccrev != 15) {
+		/* Fixed ALP clock */
+		baud_base = bcma_pmu_alp_clock(cc);
+		if (ccrev >= 21) {
+			/* Turn off UART clock before switching clocksource. */
+			bcma_cc_write32(cc, BCMA_CC_CORECTL,
+				       bcma_cc_read32(cc, BCMA_CC_CORECTL)
+				       & ~BCMA_CC_CORECTL_UARTCLKEN);
+		}
+		/* Set the override bit so we don't divide it */
+		bcma_cc_write32(cc, BCMA_CC_CORECTL,
+			       bcma_cc_read32(cc, BCMA_CC_CORECTL)
+			       | BCMA_CC_CORECTL_UARTCLK0);
+		if (ccrev >= 21) {
+			/* Re-enable the UART clock. */
+			bcma_cc_write32(cc, BCMA_CC_CORECTL,
+				       bcma_cc_read32(cc, BCMA_CC_CORECTL)
+				       | BCMA_CC_CORECTL_UARTCLKEN);
+		}
+	} else {
+		pr_err("serial not supported on this device ccrev: 0x%x\n",
+		       ccrev);
+		return;
+	}
+
+	irq = bcma_core_mips_irq(cc->core);
+
+	/* Determine the registers of the UARTs */
+	cc->nr_serial_ports = (cc->capabilities & BCMA_CC_CAP_NRUART);
+	for (i = 0; i < cc->nr_serial_ports; i++) {
+		ports[i].regs = cc->core->io_addr + BCMA_CC_UART0_DATA +
+				(i * 256);
+		ports[i].irq = irq;
+		ports[i].baud_base = baud_base;
+		ports[i].reg_shift = 0;
+	}
+}
+#endif /* CONFIG_BCMA_DRIVER_MIPS */
diff --git a/drivers/bcma/driver_chipcommon_pmu.c b/drivers/bcma/driver_chipcommon_pmu.c
index f44177a..532757c 100644
--- a/drivers/bcma/driver_chipcommon_pmu.c
+++ b/drivers/bcma/driver_chipcommon_pmu.c
@@ -132,3 +132,29 @@ void bcma_pmu_init(struct bcma_drv_cc *cc)
 	bcma_pmu_swreg_init(cc);
 	bcma_pmu_workarounds(cc);
 }
+
+u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc)
+{
+	struct bcma_bus *bus = cc->core->bus;
+
+	switch (bus->chipinfo.id) {
+	case 0x4716:
+	case 0x4748:
+	case 47162:
+	case 0x4313:
+	case 0x5357:
+	case 0x4749:
+	case 53572:
+		/* always 20Mhz */
+		return 20000 * 1000;
+	case 0x5356:
+	case 0x5300:
+		/* always 25Mhz */
+		return 25000 * 1000;
+	default:
+		pr_warn("No ALP clock specified for %04X device, "
+			"pmu rev. %d, using default %d Hz\n",
+			bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_ALP_CLOCK);
+	}
+	return BCMA_CC_PMU_ALP_CLOCK;
+}
diff --git a/drivers/bcma/driver_mips.c b/drivers/bcma/driver_mips.c
index 4b60c9f9..b17233c 100644
--- a/drivers/bcma/driver_mips.c
+++ b/drivers/bcma/driver_mips.c
@@ -238,6 +238,7 @@ void bcma_core_mips_init(struct bcma_drv_mips *mcore)
 	if (mcore->setup_done)
 		return;
 
+	bcma_chipco_serial_init(&bus->drv_cc);
 	bcma_core_mips_flash_detect(mcore);
 	mcore->setup_done = true;
 }
diff --git a/include/linux/bcma/bcma_driver_chipcommon.h b/include/linux/bcma/bcma_driver_chipcommon.h
index 0d44121..ad7b0bc 100644
--- a/include/linux/bcma/bcma_driver_chipcommon.h
+++ b/include/linux/bcma/bcma_driver_chipcommon.h
@@ -247,6 +247,9 @@
 #define BCMA_CC_PLLCTL_ADDR		0x0660
 #define BCMA_CC_PLLCTL_DATA		0x0664
 
+/* ALP clock on pre-PMU chips */
+#define BCMA_CC_PMU_ALP_CLOCK		20000000
+
 /* Data for the PMU, if available.
  * Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
  */
@@ -261,6 +264,14 @@ struct bcma_pflash {
 	u32 window;
 	u32 window_size;
 };
+
+struct bcma_serial_port {
+	void *regs;
+	unsigned long clockspeed;
+	unsigned int irq;
+	unsigned int baud_base;
+	unsigned int reg_shift;
+};
 #endif /* CONFIG_BCMA_DRIVER_MIPS */
 
 struct bcma_drv_cc {
@@ -274,6 +285,9 @@ struct bcma_drv_cc {
 	struct bcma_chipcommon_pmu pmu;
 #ifdef CONFIG_BCMA_DRIVER_MIPS
 	struct bcma_pflash pflash;
+
+	int nr_serial_ports;
+	struct bcma_serial_port serial_ports[4];
 #endif /* CONFIG_BCMA_DRIVER_MIPS */
 };
 
-- 
1.7.4.1


From hauke@hauke-m.de Sat Jul 16 18:56:26 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 16 Jul 2011 18:59:26 +0200 (CEST)
Received: from server19320154104.serverpool.info ([193.201.54.104]:50895 "EHLO
        hauke-m.de" rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org
        with ESMTP id S1491084Ab1GPQ40 (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Sat, 16 Jul 2011 18:56:26 +0200
Received: from localhost (localhost [127.0.0.1])
        by hauke-m.de (Postfix) with ESMTP id 7AF798C6C;
        Sat, 16 Jul 2011 18:56:26 +0200 (CEST)
X-Virus-Scanned: Debian amavisd-new at hauke-m.de 
Received: from hauke-m.de ([127.0.0.1])
        by localhost (hauke-m.de [127.0.0.1]) (amavisd-new, port 10024)
        with ESMTP id H2r2CjyYznQI; Sat, 16 Jul 2011 18:56:20 +0200 (CEST)
Received: from localhost.localdomain (host-091-097-255-051.ewe-ip-backbone.de [91.97.255.51])
        by hauke-m.de (Postfix) with ESMTPSA id 574368C69;
        Sat, 16 Jul 2011 18:56:07 +0200 (CEST)
From:   Hauke Mehrtens <hauke@hauke-m.de>
To:     ralf@linux-mips.org, linux-wireless@vger.kernel.org,
        zajec5@gmail.com, linux-mips@linux-mips.org
Cc:     jonas.gorski@gmail.com, mb@bu3sch.de, george@znau.edu.ua,
        arend@broadcom.com, b43-dev@lists.infradead.org,
        bernhardloos@googlemail.com, arnd@arndb.de,
        julian.calaby@gmail.com, sshtylyov@mvista.com,
        Hauke Mehrtens <hauke@hauke-m.de>
Subject: [PATCH v2 08/11] bcm47xx: prepare to support different buses
Date:   Sat, 16 Jul 2011 18:55:39 +0200
Message-Id: <1310835342-18877-9-git-send-email-hauke@hauke-m.de>
X-Mailer: git-send-email 1.7.4.1
In-Reply-To: <1310835342-18877-1-git-send-email-hauke@hauke-m.de>
References: <1310835342-18877-1-git-send-email-hauke@hauke-m.de>
X-archive-position: 30638
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: hauke@hauke-m.de
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 11709
Content-Length: 13520
Lines: 456

Prepare bcm47xx to support different System buses. Before adding
support for bcma it should be possible to build bcm47xx without the
need of ssb. With this patch bcm47xx does not directly contain a
ssb_bus, but a union contain all the supported system buses. As a SoC
just uses one system bus a union is a good choice.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 arch/mips/bcm47xx/gpio.c                     |   56 ++++++++++++++++----------
 arch/mips/bcm47xx/nvram.c                    |   15 +++++--
 arch/mips/bcm47xx/serial.c                   |   13 +++++-
 arch/mips/bcm47xx/setup.c                    |   33 ++++++++++++---
 arch/mips/bcm47xx/time.c                     |    9 +++-
 arch/mips/bcm47xx/wgt634u.c                  |   14 ++++--
 arch/mips/include/asm/mach-bcm47xx/bcm47xx.h |   14 ++++++-
 arch/mips/include/asm/mach-bcm47xx/gpio.h    |   55 ++++++++++++++++++-------
 drivers/watchdog/bcm47xx_wdt.c               |   12 +++++-
 9 files changed, 160 insertions(+), 61 deletions(-)

diff --git a/arch/mips/bcm47xx/gpio.c b/arch/mips/bcm47xx/gpio.c
index e4a5ee9..2f6d2df 100644
--- a/arch/mips/bcm47xx/gpio.c
+++ b/arch/mips/bcm47xx/gpio.c
@@ -20,42 +20,54 @@ static DECLARE_BITMAP(gpio_in_use, BCM47XX_EXTIF_GPIO_LINES);
 
 int gpio_request(unsigned gpio, const char *tag)
 {
-	if (ssb_chipco_available(&ssb_bcm47xx.chipco) &&
-	    ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
-		return -EINVAL;
+	switch (bcm47xx_active_bus_type) {
+	case BCM47XX_BUS_TYPE_SSB:
+		if (ssb_chipco_available(&bcm47xx_bus.ssb.chipco) &&
+		    ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
+			return -EINVAL;
 
-	if (ssb_extif_available(&ssb_bcm47xx.extif) &&
-	    ((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES))
-		return -EINVAL;
+		if (ssb_extif_available(&bcm47xx_bus.ssb.extif) &&
+		    ((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES))
+			return -EINVAL;
 
-	if (test_and_set_bit(gpio, gpio_in_use))
-		return -EBUSY;
+		if (test_and_set_bit(gpio, gpio_in_use))
+			return -EBUSY;
 
-	return 0;
+		return 0;
+	}
+	return -EINVAL;
 }
 EXPORT_SYMBOL(gpio_request);
 
 void gpio_free(unsigned gpio)
 {
-	if (ssb_chipco_available(&ssb_bcm47xx.chipco) &&
-	    ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
-		return;
+	switch (bcm47xx_active_bus_type) {
+	case BCM47XX_BUS_TYPE_SSB:
+		if (ssb_chipco_available(&bcm47xx_bus.ssb.chipco) &&
+		    ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
+			return;
 
-	if (ssb_extif_available(&ssb_bcm47xx.extif) &&
-	    ((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES))
-		return;
+		if (ssb_extif_available(&bcm47xx_bus.ssb.extif) &&
+		    ((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES))
+			return;
 
-	clear_bit(gpio, gpio_in_use);
+		clear_bit(gpio, gpio_in_use);
+		return;
+	}
 }
 EXPORT_SYMBOL(gpio_free);
 
 int gpio_to_irq(unsigned gpio)
 {
-	if (ssb_chipco_available(&ssb_bcm47xx.chipco))
-		return ssb_mips_irq(ssb_bcm47xx.chipco.dev) + 2;
-	else if (ssb_extif_available(&ssb_bcm47xx.extif))
-		return ssb_mips_irq(ssb_bcm47xx.extif.dev) + 2;
-	else
-		return -EINVAL;
+	switch (bcm47xx_active_bus_type) {
+	case BCM47XX_BUS_TYPE_SSB:
+		if (ssb_chipco_available(&bcm47xx_bus.ssb.chipco))
+			return ssb_mips_irq(bcm47xx_bus.ssb.chipco.dev) + 2;
+		else if (ssb_extif_available(&bcm47xx_bus.ssb.extif))
+			return ssb_mips_irq(bcm47xx_bus.ssb.extif.dev) + 2;
+		else
+			return -EINVAL;
+	}
+	return -EINVAL;
 }
 EXPORT_SYMBOL_GPL(gpio_to_irq);
diff --git a/arch/mips/bcm47xx/nvram.c b/arch/mips/bcm47xx/nvram.c
index 54db815..d2304d0 100644
--- a/arch/mips/bcm47xx/nvram.c
+++ b/arch/mips/bcm47xx/nvram.c
@@ -26,14 +26,21 @@ static char nvram_buf[NVRAM_SPACE];
 /* Probe for NVRAM header */
 static void early_nvram_init(void)
 {
-	struct ssb_mipscore *mcore = &ssb_bcm47xx.mipscore;
+	struct ssb_mipscore *mcore_ssb;
 	struct nvram_header *header;
 	int i;
-	u32 base, lim, off;
+	u32 base = 0;
+	u32 lim = 0;
+	u32 off;
 	u32 *src, *dst;
 
-	base = mcore->flash_window;
-	lim = mcore->flash_window_size;
+	switch (bcm47xx_active_bus_type) {
+	case BCM47XX_BUS_TYPE_SSB:
+		mcore_ssb = &bcm47xx_bus.ssb.mipscore;
+		base = mcore_ssb->flash_window;
+		lim = mcore_ssb->flash_window_size;
+		break;
+	}
 
 	off = FLASH_MIN;
 	while (off <= lim) {
diff --git a/arch/mips/bcm47xx/serial.c b/arch/mips/bcm47xx/serial.c
index 59c11af..87c2c5e 100644
--- a/arch/mips/bcm47xx/serial.c
+++ b/arch/mips/bcm47xx/serial.c
@@ -23,10 +23,10 @@ static struct platform_device uart8250_device = {
 	},
 };
 
-static int __init uart8250_init(void)
+static int __init uart8250_init_ssb(void)
 {
 	int i;
-	struct ssb_mipscore *mcore = &(ssb_bcm47xx.mipscore);
+	struct ssb_mipscore *mcore = &(bcm47xx_bus.ssb.mipscore);
 
 	memset(&uart8250_data, 0,  sizeof(uart8250_data));
 
@@ -45,6 +45,15 @@ static int __init uart8250_init(void)
 	return platform_device_register(&uart8250_device);
 }
 
+static int __init uart8250_init(void)
+{
+	switch (bcm47xx_active_bus_type) {
+	case BCM47XX_BUS_TYPE_SSB:
+		return uart8250_init_ssb();
+	}
+	return -EINVAL;
+}
+
 module_init(uart8250_init);
 
 MODULE_AUTHOR("Aurelien Jarno <aurelien@aurel32.net>");
diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c
index 73b529b..bff4181 100644
--- a/arch/mips/bcm47xx/setup.c
+++ b/arch/mips/bcm47xx/setup.c
@@ -35,15 +35,22 @@
 #include <bcm47xx.h>
 #include <asm/mach-bcm47xx/nvram.h>
 
-struct ssb_bus ssb_bcm47xx;
-EXPORT_SYMBOL(ssb_bcm47xx);
+union bcm47xx_bus bcm47xx_bus;
+EXPORT_SYMBOL(bcm47xx_bus);
+
+enum bcm47xx_bus_type bcm47xx_active_bus_type;
+EXPORT_SYMBOL(bcm47xx_active_bus_type);
 
 static void bcm47xx_machine_restart(char *command)
 {
 	printk(KERN_ALERT "Please stand by while rebooting the system...\n");
 	local_irq_disable();
 	/* Set the watchdog timer to reset immediately */
-	ssb_watchdog_timer_set(&ssb_bcm47xx, 1);
+	switch (bcm47xx_active_bus_type) {
+	case BCM47XX_BUS_TYPE_SSB:
+		ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 1);
+		break;
+	}
 	while (1)
 		cpu_relax();
 }
@@ -52,7 +59,11 @@ static void bcm47xx_machine_halt(void)
 {
 	/* Disable interrupts and watchdog and spin forever */
 	local_irq_disable();
-	ssb_watchdog_timer_set(&ssb_bcm47xx, 0);
+	switch (bcm47xx_active_bus_type) {
+	case BCM47XX_BUS_TYPE_SSB:
+		ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0);
+		break;
+	}
 	while (1)
 		cpu_relax();
 }
@@ -247,7 +258,7 @@ static int bcm47xx_get_invariants(struct ssb_bus *bus,
 	return 0;
 }
 
-void __init plat_mem_setup(void)
+static void __init bcm47xx_register_ssb(void)
 {
 	int err;
 	char buf[100];
@@ -258,12 +269,12 @@ void __init plat_mem_setup(void)
 		printk(KERN_WARNING "bcm47xx: someone else already registered"
 			" a ssb SPROM callback handler (err %d)\n", err);
 
-	err = ssb_bus_ssbbus_register(&ssb_bcm47xx, SSB_ENUM_BASE,
+	err = ssb_bus_ssbbus_register(&(bcm47xx_bus.ssb), SSB_ENUM_BASE,
 				      bcm47xx_get_invariants);
 	if (err)
 		panic("Failed to initialize SSB bus (err %d)\n", err);
 
-	mcore = &ssb_bcm47xx.mipscore;
+	mcore = &bcm47xx_bus.ssb.mipscore;
 	if (nvram_getenv("kernel_args", buf, sizeof(buf)) >= 0) {
 		if (strstr(buf, "console=ttyS1")) {
 			struct ssb_serial_port port;
@@ -276,6 +287,14 @@ void __init plat_mem_setup(void)
 			memcpy(&mcore->serial_ports[1], &port, sizeof(port));
 		}
 	}
+}
+
+void __init plat_mem_setup(void)
+{
+	struct cpuinfo_mips *c = &current_cpu_data;
+
+	bcm47xx_active_bus_type = BCM47XX_BUS_TYPE_SSB;
+	bcm47xx_register_ssb();
 
 	_machine_restart = bcm47xx_machine_restart;
 	_machine_halt = bcm47xx_machine_halt;
diff --git a/arch/mips/bcm47xx/time.c b/arch/mips/bcm47xx/time.c
index 0c6f47b..a7be993 100644
--- a/arch/mips/bcm47xx/time.c
+++ b/arch/mips/bcm47xx/time.c
@@ -30,7 +30,7 @@
 
 void __init plat_time_init(void)
 {
-	unsigned long hz;
+	unsigned long hz = 0;
 
 	/*
 	 * Use deterministic values for initial counter interrupt
@@ -39,7 +39,12 @@ void __init plat_time_init(void)
 	write_c0_count(0);
 	write_c0_compare(0xffff);
 
-	hz = ssb_cpu_clock(&ssb_bcm47xx.mipscore) / 2;
+	switch (bcm47xx_active_bus_type) {
+	case BCM47XX_BUS_TYPE_SSB:
+		hz = ssb_cpu_clock(&bcm47xx_bus.ssb.mipscore) / 2;
+		break;
+	}
+
 	if (!hz)
 		hz = 100000000;
 
diff --git a/arch/mips/bcm47xx/wgt634u.c b/arch/mips/bcm47xx/wgt634u.c
index 74d0696..d4aedd5 100644
--- a/arch/mips/bcm47xx/wgt634u.c
+++ b/arch/mips/bcm47xx/wgt634u.c
@@ -108,7 +108,7 @@ static irqreturn_t gpio_interrupt(int irq, void *ignored)
 
 	/* Interrupts are shared, check if the current one is
 	   a GPIO interrupt. */
-	if (!ssb_chipco_irq_status(&ssb_bcm47xx.chipco,
+	if (!ssb_chipco_irq_status(&bcm47xx_bus.ssb.chipco,
 				   SSB_CHIPCO_IRQ_GPIO))
 		return IRQ_NONE;
 
@@ -132,22 +132,26 @@ static int __init wgt634u_init(void)
 	 * machine. Use the MAC address as an heuristic. Netgear Inc. has
 	 * been allocated ranges 00:09:5b:xx:xx:xx and 00:0f:b5:xx:xx:xx.
 	 */
+	u8 *et0mac;
 
-	u8 *et0mac = ssb_bcm47xx.sprom.et0mac;
+	if (bcm47xx_active_bus_type != BCM47XX_BUS_TYPE_SSB)
+		return -ENODEV;
+
+	et0mac = bcm47xx_bus.ssb.sprom.et0mac;
 
 	if (et0mac[0] == 0x00 &&
 	    ((et0mac[1] == 0x09 && et0mac[2] == 0x5b) ||
 	     (et0mac[1] == 0x0f && et0mac[2] == 0xb5))) {
-		struct ssb_mipscore *mcore = &ssb_bcm47xx.mipscore;
+		struct ssb_mipscore *mcore = &bcm47xx_bus.ssb.mipscore;
 
 		printk(KERN_INFO "WGT634U machine detected.\n");
 
 		if (!request_irq(gpio_to_irq(WGT634U_GPIO_RESET),
 				 gpio_interrupt, IRQF_SHARED,
-				 "WGT634U GPIO", &ssb_bcm47xx.chipco)) {
+				 "WGT634U GPIO", &bcm47xx_bus.ssb.chipco)) {
 			gpio_direction_input(WGT634U_GPIO_RESET);
 			gpio_intmask(WGT634U_GPIO_RESET, 1);
-			ssb_chipco_irq_mask(&ssb_bcm47xx.chipco,
+			ssb_chipco_irq_mask(&bcm47xx_bus.ssb.chipco,
 					    SSB_CHIPCO_IRQ_GPIO,
 					    SSB_CHIPCO_IRQ_GPIO);
 		}
diff --git a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
index d008f47..4be8b95 100644
--- a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
+++ b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
@@ -19,7 +19,17 @@
 #ifndef __ASM_BCM47XX_H
 #define __ASM_BCM47XX_H
 
-/* SSB bus */
-extern struct ssb_bus ssb_bcm47xx;
+#include <linux/ssb/ssb.h>
+
+enum bcm47xx_bus_type {
+	BCM47XX_BUS_TYPE_SSB,
+};
+
+union bcm47xx_bus {
+	struct ssb_bus ssb;
+};
+
+extern union bcm47xx_bus bcm47xx_bus;
+extern enum bcm47xx_bus_type bcm47xx_active_bus_type;
 
 #endif /* __ASM_BCM47XX_H */
diff --git a/arch/mips/include/asm/mach-bcm47xx/gpio.h b/arch/mips/include/asm/mach-bcm47xx/gpio.h
index 9850414..976b8aa 100644
--- a/arch/mips/include/asm/mach-bcm47xx/gpio.h
+++ b/arch/mips/include/asm/mach-bcm47xx/gpio.h
@@ -21,41 +21,66 @@ extern int gpio_to_irq(unsigned gpio);
 
 static inline int gpio_get_value(unsigned gpio)
 {
-	return ssb_gpio_in(&ssb_bcm47xx, 1 << gpio);
+	switch (bcm47xx_active_bus_type) {
+	case BCM47XX_BUS_TYPE_SSB:
+		return ssb_gpio_in(&bcm47xx_bus.ssb, 1 << gpio);
+	}
+	return -EINVAL;
 }
 
 static inline void gpio_set_value(unsigned gpio, int value)
 {
-	ssb_gpio_out(&ssb_bcm47xx, 1 << gpio, value ? 1 << gpio : 0);
+	switch (bcm47xx_active_bus_type) {
+	case BCM47XX_BUS_TYPE_SSB:
+		ssb_gpio_out(&bcm47xx_bus.ssb, 1 << gpio,
+			     value ? 1 << gpio : 0);
+	}
 }
 
 static inline int gpio_direction_input(unsigned gpio)
 {
-	ssb_gpio_outen(&ssb_bcm47xx, 1 << gpio, 0);
-	return 0;
+	switch (bcm47xx_active_bus_type) {
+	case BCM47XX_BUS_TYPE_SSB:
+		ssb_gpio_outen(&bcm47xx_bus.ssb, 1 << gpio, 0);
+		return 0;
+	}
+	return -EINVAL;
 }
 
 static inline int gpio_direction_output(unsigned gpio, int value)
 {
-	/* first set the gpio out value */
-	ssb_gpio_out(&ssb_bcm47xx, 1 << gpio, value ? 1 << gpio : 0);
-	/* then set the gpio mode */
-	ssb_gpio_outen(&ssb_bcm47xx, 1 << gpio, 1 << gpio);
-	return 0;
+	switch (bcm47xx_active_bus_type) {
+	case BCM47XX_BUS_TYPE_SSB:
+		/* first set the gpio out value */
+		ssb_gpio_out(&bcm47xx_bus.ssb, 1 << gpio,
+			     value ? 1 << gpio : 0);
+		/* then set the gpio mode */
+		ssb_gpio_outen(&bcm47xx_bus.ssb, 1 << gpio, 1 << gpio);
+		return 0;
+	}
+	return -EINVAL;
 }
 
 static inline int gpio_intmask(unsigned gpio, int value)
 {
-	ssb_gpio_intmask(&ssb_bcm47xx, 1 << gpio,
-			 value ? 1 << gpio : 0);
-	return 0;
+	switch (bcm47xx_active_bus_type) {
+	case BCM47XX_BUS_TYPE_SSB:
+		ssb_gpio_intmask(&bcm47xx_bus.ssb, 1 << gpio,
+				 value ? 1 << gpio : 0);
+		return 0;
+	}
+	return -EINVAL;
 }
 
 static inline int gpio_polarity(unsigned gpio, int value)
 {
-	ssb_gpio_polarity(&ssb_bcm47xx, 1 << gpio,
-			  value ? 1 << gpio : 0);
-	return 0;
+	switch (bcm47xx_active_bus_type) {
+	case BCM47XX_BUS_TYPE_SSB:
+		ssb_gpio_polarity(&bcm47xx_bus.ssb, 1 << gpio,
+				  value ? 1 << gpio : 0);
+		return 0;
+	}
+	return -EINVAL;
 }
 
 
diff --git a/drivers/watchdog/bcm47xx_wdt.c b/drivers/watchdog/bcm47xx_wdt.c
index bd44417..7e4e063 100644
--- a/drivers/watchdog/bcm47xx_wdt.c
+++ b/drivers/watchdog/bcm47xx_wdt.c
@@ -54,12 +54,20 @@ static atomic_t ticks;
 static inline void bcm47xx_wdt_hw_start(void)
 {
 	/* this is 2,5s on 100Mhz clock  and 2s on 133 Mhz */
-	ssb_watchdog_timer_set(&ssb_bcm47xx, 0xfffffff);
+	switch (bcm47xx_active_bus_type) {
+	case BCM47XX_BUS_TYPE_SSB:
+		ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0xfffffff);
+		break;
+	}
 }
 
 static inline int bcm47xx_wdt_hw_stop(void)
 {
-	return ssb_watchdog_timer_set(&ssb_bcm47xx, 0);
+	switch (bcm47xx_active_bus_type) {
+	case BCM47XX_BUS_TYPE_SSB:
+		return ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0);
+	}
+	return -EINVAL;
 }
 
 static void bcm47xx_timer_tick(unsigned long unused)
-- 
1.7.4.1


From hauke@hauke-m.de Sat Jul 16 18:56:31 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 16 Jul 2011 18:59:49 +0200 (CEST)
Received: from server19320154104.serverpool.info ([193.201.54.104]:50909 "EHLO
        hauke-m.de" rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org
        with ESMTP id S1491202Ab1GPQ4b (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Sat, 16 Jul 2011 18:56:31 +0200
Received: from localhost (localhost [127.0.0.1])
        by hauke-m.de (Postfix) with ESMTP id B61DA8C73;
        Sat, 16 Jul 2011 18:56:30 +0200 (CEST)
X-Virus-Scanned: Debian amavisd-new at hauke-m.de 
Received: from hauke-m.de ([127.0.0.1])
        by localhost (hauke-m.de [127.0.0.1]) (amavisd-new, port 10024)
        with ESMTP id c0wfq2vtZJdr; Sat, 16 Jul 2011 18:56:17 +0200 (CEST)
Received: from localhost.localdomain (host-091-097-255-051.ewe-ip-backbone.de [91.97.255.51])
        by hauke-m.de (Postfix) with ESMTPSA id 5D0418C62;
        Sat, 16 Jul 2011 18:56:06 +0200 (CEST)
From:   Hauke Mehrtens <hauke@hauke-m.de>
To:     ralf@linux-mips.org, linux-wireless@vger.kernel.org,
        zajec5@gmail.com, linux-mips@linux-mips.org
Cc:     jonas.gorski@gmail.com, mb@bu3sch.de, george@znau.edu.ua,
        arend@broadcom.com, b43-dev@lists.infradead.org,
        bernhardloos@googlemail.com, arnd@arndb.de,
        julian.calaby@gmail.com, sshtylyov@mvista.com,
        Hauke Mehrtens <hauke@hauke-m.de>
Subject: [PATCH v2 07/11] bcma: get CPU clock
Date:   Sat, 16 Jul 2011 18:55:38 +0200
Message-Id: <1310835342-18877-8-git-send-email-hauke@hauke-m.de>
X-Mailer: git-send-email 1.7.4.1
In-Reply-To: <1310835342-18877-1-git-send-email-hauke@hauke-m.de>
References: <1310835342-18877-1-git-send-email-hauke@hauke-m.de>
X-archive-position: 30639
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: hauke@hauke-m.de
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 11710
Content-Length: 7690
Lines: 239

Add method to return the clock of the CPU. This is needed by the arch
code to calculate the mips_hpt_frequency.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 drivers/bcma/bcma_private.h                 |    3 +
 drivers/bcma/driver_chipcommon_pmu.c        |  107 +++++++++++++++++++++++++++
 drivers/bcma/driver_mips.c                  |   12 +++
 include/linux/bcma/bcma_driver_chipcommon.h |   39 ++++++++++
 include/linux/bcma/bcma_driver_mips.h       |    2 +
 5 files changed, 163 insertions(+), 0 deletions(-)

diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h
index b9b4587..8b6f046 100644
--- a/drivers/bcma/bcma_private.h
+++ b/drivers/bcma/bcma_private.h
@@ -26,6 +26,9 @@ int __init bcma_bus_scan_early(struct bcma_bus *bus,
 			       struct bcma_device *core);
 void bcma_init_bus(struct bcma_bus *bus);
 
+/* driver_chipcommon_pmu.c */
+extern u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc);
+
 /* driver_chipcommon.c */
 #ifdef CONFIG_BCMA_DRIVER_MIPS
 void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
diff --git a/drivers/bcma/driver_chipcommon_pmu.c b/drivers/bcma/driver_chipcommon_pmu.c
index 532757c..250e0c2 100644
--- a/drivers/bcma/driver_chipcommon_pmu.c
+++ b/drivers/bcma/driver_chipcommon_pmu.c
@@ -11,6 +11,13 @@
 #include "bcma_private.h"
 #include <linux/bcma/bcma.h>
 
+static u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset)
+{
+	bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
+	bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
+	return bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
+}
+
 static void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
 					u32 offset, u32 mask, u32 set)
 {
@@ -158,3 +165,103 @@ u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc)
 	}
 	return BCMA_CC_PMU_ALP_CLOCK;
 }
+
+/* Find the output of the "m" pll divider given pll controls that start with
+ * pllreg "pll0" i.e. 12 for main 6 for phy, 0 for misc.
+ */
+static u32 bcma_pmu_clock(struct bcma_drv_cc *cc, u32 pll0, u32 m)
+{
+	u32 tmp, div, ndiv, p1, p2, fc;
+	struct bcma_bus *bus = cc->core->bus;
+
+	BUG_ON((pll0 & 3) || (pll0 > BCMA_CC_PMU4716_MAINPLL_PLL0));
+
+	BUG_ON(!m || m > 4);
+
+	if (bus->chipinfo.id == 0x5357 || bus->chipinfo.id == 0x4749) {
+		/* Detect failure in clock setting */
+		tmp = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT);
+		if (tmp & 0x40000)
+			return 133 * 1000000;
+	}
+
+	tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_P1P2_OFF);
+	p1 = (tmp & BCMA_CC_PPL_P1_MASK) >> BCMA_CC_PPL_P1_SHIFT;
+	p2 = (tmp & BCMA_CC_PPL_P2_MASK) >> BCMA_CC_PPL_P2_SHIFT;
+
+	tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_M14_OFF);
+	div = (tmp >> ((m - 1) * BCMA_CC_PPL_MDIV_WIDTH)) &
+		BCMA_CC_PPL_MDIV_MASK;
+
+	tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_NM5_OFF);
+	ndiv = (tmp & BCMA_CC_PPL_NDIV_MASK) >> BCMA_CC_PPL_NDIV_SHIFT;
+
+	/* Do calculation in Mhz */
+	fc = bcma_pmu_alp_clock(cc) / 1000000;
+	fc = (p1 * ndiv * fc) / p2;
+
+	/* Return clock in Hertz */
+	return (fc / div) * 1000000;
+}
+
+/* query bus clock frequency for PMU-enabled chipcommon */
+u32 bcma_pmu_get_clockcontrol(struct bcma_drv_cc *cc)
+{
+	struct bcma_bus *bus = cc->core->bus;
+
+	switch (bus->chipinfo.id) {
+	case 0x4716:
+	case 0x4748:
+	case 47162:
+		return bcma_pmu_clock(cc, BCMA_CC_PMU4716_MAINPLL_PLL0,
+				      BCMA_CC_PMU5_MAINPLL_SSB);
+	case 0x5356:
+		return bcma_pmu_clock(cc, BCMA_CC_PMU5356_MAINPLL_PLL0,
+				      BCMA_CC_PMU5_MAINPLL_SSB);
+	case 0x5357:
+	case 0x4749:
+		return bcma_pmu_clock(cc, BCMA_CC_PMU5357_MAINPLL_PLL0,
+				      BCMA_CC_PMU5_MAINPLL_SSB);
+	case 0x5300:
+		return bcma_pmu_clock(cc, BCMA_CC_PMU4706_MAINPLL_PLL0,
+				      BCMA_CC_PMU5_MAINPLL_SSB);
+	case 53572:
+		return 75000000;
+	default:
+		pr_warn("No backplane clock specified for %04X device, "
+			"pmu rev. %d, using default %d Hz\n",
+			bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_HT_CLOCK);
+	}
+	return BCMA_CC_PMU_HT_CLOCK;
+}
+
+/* query cpu clock frequency for PMU-enabled chipcommon */
+u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc)
+{
+	struct bcma_bus *bus = cc->core->bus;
+
+	if (bus->chipinfo.id == 53572)
+		return 300000000;
+
+	if (cc->pmu.rev >= 5) {
+		u32 pll;
+		switch (bus->chipinfo.id) {
+		case 0x5356:
+			pll = BCMA_CC_PMU5356_MAINPLL_PLL0;
+			break;
+		case 0x5357:
+		case 0x4749:
+			pll = BCMA_CC_PMU5357_MAINPLL_PLL0;
+			break;
+		default:
+			pll = BCMA_CC_PMU4716_MAINPLL_PLL0;
+			break;
+		}
+
+		/* TODO: if (bus->chipinfo.id == 0x5300)
+		  return si_4706_pmu_clock(sih, osh, cc, PMU4706_MAINPLL_PLL0, PMU5_MAINPLL_CPU); */
+		return bcma_pmu_clock(cc, pll, BCMA_CC_PMU5_MAINPLL_CPU);
+	}
+
+	return bcma_pmu_get_clockcontrol(cc);
+}
diff --git a/drivers/bcma/driver_mips.c b/drivers/bcma/driver_mips.c
index b17233c..c3e9dff 100644
--- a/drivers/bcma/driver_mips.c
+++ b/drivers/bcma/driver_mips.c
@@ -166,6 +166,18 @@ static void bcma_core_mips_dump_irq(struct bcma_bus *bus)
 	}
 }
 
+u32 bcma_cpu_clock(struct bcma_drv_mips *mcore)
+{
+	struct bcma_bus *bus = mcore->core->bus;
+
+	if (bus->drv_cc.capabilities & BCMA_CC_CAP_PMU)
+		return bcma_pmu_get_clockcpu(&bus->drv_cc);
+
+	pr_err("No PMU available, need this to get the cpu clock\n");
+	return 0;
+}
+EXPORT_SYMBOL(bcma_cpu_clock);
+
 static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
 {
 	struct bcma_bus *bus = mcore->core->bus;
diff --git a/include/linux/bcma/bcma_driver_chipcommon.h b/include/linux/bcma/bcma_driver_chipcommon.h
index ad7b0bc..099c478 100644
--- a/include/linux/bcma/bcma_driver_chipcommon.h
+++ b/include/linux/bcma/bcma_driver_chipcommon.h
@@ -247,8 +247,47 @@
 #define BCMA_CC_PLLCTL_ADDR		0x0660
 #define BCMA_CC_PLLCTL_DATA		0x0664
 
+/* Divider allocation in 4716/47162/5356 */
+#define BCMA_CC_PMU5_MAINPLL_CPU	1
+#define BCMA_CC_PMU5_MAINPLL_MEM	2
+#define BCMA_CC_PMU5_MAINPLL_SSB	3
+
+/* PLL usage in 4716/47162 */
+#define BCMA_CC_PMU4716_MAINPLL_PLL0	12
+
+/* PLL usage in 5356/5357 */
+#define BCMA_CC_PMU5356_MAINPLL_PLL0	0
+#define BCMA_CC_PMU5357_MAINPLL_PLL0	0
+
+/* 4706 PMU */
+#define BCMA_CC_PMU4706_MAINPLL_PLL0	0
+
 /* ALP clock on pre-PMU chips */
 #define BCMA_CC_PMU_ALP_CLOCK		20000000
+/* HT clock for systems with PMU-enabled chipcommon */
+#define BCMA_CC_PMU_HT_CLOCK		80000000
+
+/* PMU rev 5 (& 6) */
+#define BCMA_CC_PPL_P1P2_OFF		0
+#define BCMA_CC_PPL_P1_MASK		0x0f000000
+#define BCMA_CC_PPL_P1_SHIFT		24
+#define BCMA_CC_PPL_P2_MASK		0x00f00000
+#define BCMA_CC_PPL_P2_SHIFT		20
+#define BCMA_CC_PPL_M14_OFF		1
+#define BCMA_CC_PPL_MDIV_MASK		0x000000ff
+#define BCMA_CC_PPL_MDIV_WIDTH		8
+#define BCMA_CC_PPL_NM5_OFF		2
+#define BCMA_CC_PPL_NDIV_MASK		0xfff00000
+#define BCMA_CC_PPL_NDIV_SHIFT		20
+#define BCMA_CC_PPL_FMAB_OFF		3
+#define BCMA_CC_PPL_MRAT_MASK		0xf0000000
+#define BCMA_CC_PPL_MRAT_SHIFT		28
+#define BCMA_CC_PPL_ABRAT_MASK		0x08000000
+#define BCMA_CC_PPL_ABRAT_SHIFT		27
+#define BCMA_CC_PPL_FDIV_MASK		0x07ffffff
+#define BCMA_CC_PPL_PLLCTL_OFF		4
+#define BCMA_CC_PPL_PCHI_OFF		5
+#define BCMA_CC_PPL_PCHI_MASK		0x0000003f
 
 /* Data for the PMU, if available.
  * Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
diff --git a/include/linux/bcma/bcma_driver_mips.h b/include/linux/bcma/bcma_driver_mips.h
index 82b3bfd..c004364 100644
--- a/include/linux/bcma/bcma_driver_mips.h
+++ b/include/linux/bcma/bcma_driver_mips.h
@@ -44,6 +44,8 @@ extern void bcma_core_mips_init(struct bcma_drv_mips *mcore);
 static inline void bcma_core_mips_init(struct bcma_drv_mips *mcore) { }
 #endif
 
+extern u32 bcma_cpu_clock(struct bcma_drv_mips *mcore);
+
 extern unsigned int bcma_core_mips_irq(struct bcma_device *dev);
 
 #endif /* LINUX_BCMA_DRIVER_MIPS_H_ */
-- 
1.7.4.1


From hauke@hauke-m.de Sat Jul 16 18:56:33 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 16 Jul 2011 19:00:15 +0200 (CEST)
Received: from server19320154104.serverpool.info ([193.201.54.104]:50918 "EHLO
        hauke-m.de" rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org
        with ESMTP id S1491782Ab1GPQ4d (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Sat, 16 Jul 2011 18:56:33 +0200
Received: from localhost (localhost [127.0.0.1])
        by hauke-m.de (Postfix) with ESMTP id 00FF88C62;
        Sat, 16 Jul 2011 18:56:33 +0200 (CEST)
X-Virus-Scanned: Debian amavisd-new at hauke-m.de 
Received: from hauke-m.de ([127.0.0.1])
        by localhost (hauke-m.de [127.0.0.1]) (amavisd-new, port 10024)
        with ESMTP id L8OHJnVbkOl8; Sat, 16 Jul 2011 18:56:26 +0200 (CEST)
Received: from localhost.localdomain (host-091-097-255-051.ewe-ip-backbone.de [91.97.255.51])
        by hauke-m.de (Postfix) with ESMTPSA id 5E8F68C6B;
        Sat, 16 Jul 2011 18:56:08 +0200 (CEST)
From:   Hauke Mehrtens <hauke@hauke-m.de>
To:     ralf@linux-mips.org, linux-wireless@vger.kernel.org,
        zajec5@gmail.com, linux-mips@linux-mips.org
Cc:     jonas.gorski@gmail.com, mb@bu3sch.de, george@znau.edu.ua,
        arend@broadcom.com, b43-dev@lists.infradead.org,
        bernhardloos@googlemail.com, arnd@arndb.de,
        julian.calaby@gmail.com, sshtylyov@mvista.com,
        Hauke Mehrtens <hauke@hauke-m.de>
Subject: [PATCH v2 09/11] bcm47xx: make it possible to build bcm47xx without ssb.
Date:   Sat, 16 Jul 2011 18:55:40 +0200
Message-Id: <1310835342-18877-10-git-send-email-hauke@hauke-m.de>
X-Mailer: git-send-email 1.7.4.1
In-Reply-To: <1310835342-18877-1-git-send-email-hauke@hauke-m.de>
References: <1310835342-18877-1-git-send-email-hauke@hauke-m.de>
X-archive-position: 30640
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: hauke@hauke-m.de
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 11711
Content-Length: 11818
Lines: 418


Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 arch/mips/Kconfig                            |    8 +-------
 arch/mips/bcm47xx/Kconfig                    |   18 ++++++++++++++++++
 arch/mips/bcm47xx/Makefile                   |    3 ++-
 arch/mips/bcm47xx/gpio.c                     |    6 ++++++
 arch/mips/bcm47xx/nvram.c                    |    4 ++++
 arch/mips/bcm47xx/serial.c                   |    4 ++++
 arch/mips/bcm47xx/setup.c                    |    8 ++++++++
 arch/mips/bcm47xx/time.c                     |    2 ++
 arch/mips/include/asm/mach-bcm47xx/bcm47xx.h |    4 ++++
 arch/mips/include/asm/mach-bcm47xx/gpio.h    |   12 ++++++++++++
 arch/mips/pci/pci-bcm47xx.c                  |    6 ++++++
 drivers/watchdog/bcm47xx_wdt.c               |    4 ++++
 12 files changed, 71 insertions(+), 8 deletions(-)
 create mode 100644 arch/mips/bcm47xx/Kconfig

diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 653da62..ac6f237 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -91,15 +91,8 @@ config BCM47XX
 	select DMA_NONCOHERENT
 	select HW_HAS_PCI
 	select IRQ_CPU
-	select SYS_HAS_CPU_MIPS32_R1
 	select SYS_SUPPORTS_32BIT_KERNEL
 	select SYS_SUPPORTS_LITTLE_ENDIAN
-	select SSB
-	select SSB_DRIVER_MIPS
-	select SSB_DRIVER_EXTIF
-	select SSB_EMBEDDED
-	select SSB_B43_PCI_BRIDGE if PCI
-	select SSB_PCICORE_HOSTMODE if PCI
 	select GENERIC_GPIO
 	select SYS_HAS_EARLY_PRINTK
 	select CFE
@@ -785,6 +778,7 @@ endchoice
 
 source "arch/mips/alchemy/Kconfig"
 source "arch/mips/ath79/Kconfig"
+source "arch/mips/bcm47xx/Kconfig"
 source "arch/mips/bcm63xx/Kconfig"
 source "arch/mips/jazz/Kconfig"
 source "arch/mips/jz4740/Kconfig"
diff --git a/arch/mips/bcm47xx/Kconfig b/arch/mips/bcm47xx/Kconfig
new file mode 100644
index 0000000..0346f92
--- /dev/null
+++ b/arch/mips/bcm47xx/Kconfig
@@ -0,0 +1,18 @@
+if BCM47XX
+
+config BCM47XX_SSB
+	bool "SSB Support for Broadcom BCM47XX"
+	select SYS_HAS_CPU_MIPS32_R1
+	select SSB
+	select SSB_DRIVER_MIPS
+	select SSB_DRIVER_EXTIF
+	select SSB_EMBEDDED
+	select SSB_B43_PCI_BRIDGE if PCI
+	select SSB_PCICORE_HOSTMODE if PCI
+	default y
+	help
+	 Add support for old Broadcom BCM47xx boards with Sonics Silicon Backplane support.
+
+	 This will generate an image with support for SSB and MIPS32 R1 instruction set.
+
+endif
diff --git a/arch/mips/bcm47xx/Makefile b/arch/mips/bcm47xx/Makefile
index 7465e8a..4add173 100644
--- a/arch/mips/bcm47xx/Makefile
+++ b/arch/mips/bcm47xx/Makefile
@@ -3,4 +3,5 @@
 # under Linux.
 #
 
-obj-y := gpio.o irq.o nvram.o prom.o serial.o setup.o time.o wgt634u.o
+obj-y 				+= gpio.o irq.o nvram.o prom.o serial.o setup.o time.o
+obj-$(CONFIG_BCM47XX_SSB)	+= wgt634u.o
diff --git a/arch/mips/bcm47xx/gpio.c b/arch/mips/bcm47xx/gpio.c
index 2f6d2df..3320e91 100644
--- a/arch/mips/bcm47xx/gpio.c
+++ b/arch/mips/bcm47xx/gpio.c
@@ -21,6 +21,7 @@ static DECLARE_BITMAP(gpio_in_use, BCM47XX_EXTIF_GPIO_LINES);
 int gpio_request(unsigned gpio, const char *tag)
 {
 	switch (bcm47xx_active_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
 	case BCM47XX_BUS_TYPE_SSB:
 		if (ssb_chipco_available(&bcm47xx_bus.ssb.chipco) &&
 		    ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
@@ -34,6 +35,7 @@ int gpio_request(unsigned gpio, const char *tag)
 			return -EBUSY;
 
 		return 0;
+#endif
 	}
 	return -EINVAL;
 }
@@ -42,6 +44,7 @@ EXPORT_SYMBOL(gpio_request);
 void gpio_free(unsigned gpio)
 {
 	switch (bcm47xx_active_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
 	case BCM47XX_BUS_TYPE_SSB:
 		if (ssb_chipco_available(&bcm47xx_bus.ssb.chipco) &&
 		    ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
@@ -53,6 +56,7 @@ void gpio_free(unsigned gpio)
 
 		clear_bit(gpio, gpio_in_use);
 		return;
+#endif
 	}
 }
 EXPORT_SYMBOL(gpio_free);
@@ -60,6 +64,7 @@ EXPORT_SYMBOL(gpio_free);
 int gpio_to_irq(unsigned gpio)
 {
 	switch (bcm47xx_active_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
 	case BCM47XX_BUS_TYPE_SSB:
 		if (ssb_chipco_available(&bcm47xx_bus.ssb.chipco))
 			return ssb_mips_irq(bcm47xx_bus.ssb.chipco.dev) + 2;
@@ -67,6 +72,7 @@ int gpio_to_irq(unsigned gpio)
 			return ssb_mips_irq(bcm47xx_bus.ssb.extif.dev) + 2;
 		else
 			return -EINVAL;
+#endif
 	}
 	return -EINVAL;
 }
diff --git a/arch/mips/bcm47xx/nvram.c b/arch/mips/bcm47xx/nvram.c
index d2304d0..d223dac 100644
--- a/arch/mips/bcm47xx/nvram.c
+++ b/arch/mips/bcm47xx/nvram.c
@@ -26,7 +26,9 @@ static char nvram_buf[NVRAM_SPACE];
 /* Probe for NVRAM header */
 static void early_nvram_init(void)
 {
+#ifdef CONFIG_BCM47XX_SSB
 	struct ssb_mipscore *mcore_ssb;
+#endif
 	struct nvram_header *header;
 	int i;
 	u32 base = 0;
@@ -35,11 +37,13 @@ static void early_nvram_init(void)
 	u32 *src, *dst;
 
 	switch (bcm47xx_active_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
 	case BCM47XX_BUS_TYPE_SSB:
 		mcore_ssb = &bcm47xx_bus.ssb.mipscore;
 		base = mcore_ssb->flash_window;
 		lim = mcore_ssb->flash_window_size;
 		break;
+#endif
 	}
 
 	off = FLASH_MIN;
diff --git a/arch/mips/bcm47xx/serial.c b/arch/mips/bcm47xx/serial.c
index 87c2c5e..e9258cb 100644
--- a/arch/mips/bcm47xx/serial.c
+++ b/arch/mips/bcm47xx/serial.c
@@ -23,6 +23,7 @@ static struct platform_device uart8250_device = {
 	},
 };
 
+#ifdef CONFIG_BCM47XX_SSB
 static int __init uart8250_init_ssb(void)
 {
 	int i;
@@ -44,12 +45,15 @@ static int __init uart8250_init_ssb(void)
 	}
 	return platform_device_register(&uart8250_device);
 }
+#endif
 
 static int __init uart8250_init(void)
 {
 	switch (bcm47xx_active_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
 	case BCM47XX_BUS_TYPE_SSB:
 		return uart8250_init_ssb();
+#endif
 	}
 	return -EINVAL;
 }
diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c
index bff4181..9fc92bd 100644
--- a/arch/mips/bcm47xx/setup.c
+++ b/arch/mips/bcm47xx/setup.c
@@ -47,9 +47,11 @@ static void bcm47xx_machine_restart(char *command)
 	local_irq_disable();
 	/* Set the watchdog timer to reset immediately */
 	switch (bcm47xx_active_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
 	case BCM47XX_BUS_TYPE_SSB:
 		ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 1);
 		break;
+#endif
 	}
 	while (1)
 		cpu_relax();
@@ -60,14 +62,17 @@ static void bcm47xx_machine_halt(void)
 	/* Disable interrupts and watchdog and spin forever */
 	local_irq_disable();
 	switch (bcm47xx_active_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
 	case BCM47XX_BUS_TYPE_SSB:
 		ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0);
 		break;
+#endif
 	}
 	while (1)
 		cpu_relax();
 }
 
+#ifdef CONFIG_BCM47XX_SSB
 #define READ_FROM_NVRAM(_outvar, name, buf) \
 	if (nvram_getprefix(prefix, name, buf, sizeof(buf)) >= 0)\
 		sprom->_outvar = simple_strtoul(buf, NULL, 0);
@@ -288,13 +293,16 @@ static void __init bcm47xx_register_ssb(void)
 		}
 	}
 }
+#endif
 
 void __init plat_mem_setup(void)
 {
 	struct cpuinfo_mips *c = &current_cpu_data;
 
+#ifdef CONFIG_BCM47XX_SSB
 	bcm47xx_active_bus_type = BCM47XX_BUS_TYPE_SSB;
 	bcm47xx_register_ssb();
+#endif
 
 	_machine_restart = bcm47xx_machine_restart;
 	_machine_halt = bcm47xx_machine_halt;
diff --git a/arch/mips/bcm47xx/time.c b/arch/mips/bcm47xx/time.c
index a7be993..02a652a 100644
--- a/arch/mips/bcm47xx/time.c
+++ b/arch/mips/bcm47xx/time.c
@@ -40,9 +40,11 @@ void __init plat_time_init(void)
 	write_c0_compare(0xffff);
 
 	switch (bcm47xx_active_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
 	case BCM47XX_BUS_TYPE_SSB:
 		hz = ssb_cpu_clock(&bcm47xx_bus.ssb.mipscore) / 2;
 		break;
+#endif
 	}
 
 	if (!hz)
diff --git a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
index 4be8b95..764afea 100644
--- a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
+++ b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
@@ -22,11 +22,15 @@
 #include <linux/ssb/ssb.h>
 
 enum bcm47xx_bus_type {
+#ifdef CONFIG_BCM47XX_SSB
 	BCM47XX_BUS_TYPE_SSB,
+#endif
 };
 
 union bcm47xx_bus {
+#ifdef CONFIG_BCM47XX_SSB
 	struct ssb_bus ssb;
+#endif
 };
 
 extern union bcm47xx_bus bcm47xx_bus;
diff --git a/arch/mips/include/asm/mach-bcm47xx/gpio.h b/arch/mips/include/asm/mach-bcm47xx/gpio.h
index 976b8aa..0c3bd1f 100644
--- a/arch/mips/include/asm/mach-bcm47xx/gpio.h
+++ b/arch/mips/include/asm/mach-bcm47xx/gpio.h
@@ -22,8 +22,10 @@ extern int gpio_to_irq(unsigned gpio);
 static inline int gpio_get_value(unsigned gpio)
 {
 	switch (bcm47xx_active_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
 	case BCM47XX_BUS_TYPE_SSB:
 		return ssb_gpio_in(&bcm47xx_bus.ssb, 1 << gpio);
+#endif
 	}
 	return -EINVAL;
 }
@@ -31,18 +33,22 @@ static inline int gpio_get_value(unsigned gpio)
 static inline void gpio_set_value(unsigned gpio, int value)
 {
 	switch (bcm47xx_active_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
 	case BCM47XX_BUS_TYPE_SSB:
 		ssb_gpio_out(&bcm47xx_bus.ssb, 1 << gpio,
 			     value ? 1 << gpio : 0);
+#endif
 	}
 }
 
 static inline int gpio_direction_input(unsigned gpio)
 {
 	switch (bcm47xx_active_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
 	case BCM47XX_BUS_TYPE_SSB:
 		ssb_gpio_outen(&bcm47xx_bus.ssb, 1 << gpio, 0);
 		return 0;
+#endif
 	}
 	return -EINVAL;
 }
@@ -50,6 +56,7 @@ static inline int gpio_direction_input(unsigned gpio)
 static inline int gpio_direction_output(unsigned gpio, int value)
 {
 	switch (bcm47xx_active_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
 	case BCM47XX_BUS_TYPE_SSB:
 		/* first set the gpio out value */
 		ssb_gpio_out(&bcm47xx_bus.ssb, 1 << gpio,
@@ -57,6 +64,7 @@ static inline int gpio_direction_output(unsigned gpio, int value)
 		/* then set the gpio mode */
 		ssb_gpio_outen(&bcm47xx_bus.ssb, 1 << gpio, 1 << gpio);
 		return 0;
+#endif
 	}
 	return -EINVAL;
 }
@@ -64,10 +72,12 @@ static inline int gpio_direction_output(unsigned gpio, int value)
 static inline int gpio_intmask(unsigned gpio, int value)
 {
 	switch (bcm47xx_active_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
 	case BCM47XX_BUS_TYPE_SSB:
 		ssb_gpio_intmask(&bcm47xx_bus.ssb, 1 << gpio,
 				 value ? 1 << gpio : 0);
 		return 0;
+#endif
 	}
 	return -EINVAL;
 }
@@ -75,10 +85,12 @@ static inline int gpio_intmask(unsigned gpio, int value)
 static inline int gpio_polarity(unsigned gpio, int value)
 {
 	switch (bcm47xx_active_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
 	case BCM47XX_BUS_TYPE_SSB:
 		ssb_gpio_polarity(&bcm47xx_bus.ssb, 1 << gpio,
 				  value ? 1 << gpio : 0);
 		return 0;
+#endif
 	}
 	return -EINVAL;
 }
diff --git a/arch/mips/pci/pci-bcm47xx.c b/arch/mips/pci/pci-bcm47xx.c
index 455f8e5..924e158 100644
--- a/arch/mips/pci/pci-bcm47xx.c
+++ b/arch/mips/pci/pci-bcm47xx.c
@@ -25,6 +25,7 @@
 #include <linux/types.h>
 #include <linux/pci.h>
 #include <linux/ssb/ssb.h>
+#include <bcm47xx.h>
 
 int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
@@ -33,9 +34,13 @@ int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 
 int pcibios_plat_dev_init(struct pci_dev *dev)
 {
+#ifdef CONFIG_BCM47XX_SSB
 	int res;
 	u8 slot, pin;
 
+	if (bcm47xx_active_bus_type !=  BCM47XX_BUS_TYPE_SSB)
+		return 0;
+
 	res = ssb_pcibios_plat_dev_init(dev);
 	if (res < 0) {
 		printk(KERN_ALERT "PCI: Failed to init device %s\n",
@@ -55,5 +60,6 @@ int pcibios_plat_dev_init(struct pci_dev *dev)
 	}
 
 	dev->irq = res;
+#endif
 	return 0;
 }
diff --git a/drivers/watchdog/bcm47xx_wdt.c b/drivers/watchdog/bcm47xx_wdt.c
index 7e4e063..beacd79 100644
--- a/drivers/watchdog/bcm47xx_wdt.c
+++ b/drivers/watchdog/bcm47xx_wdt.c
@@ -55,17 +55,21 @@ static inline void bcm47xx_wdt_hw_start(void)
 {
 	/* this is 2,5s on 100Mhz clock  and 2s on 133 Mhz */
 	switch (bcm47xx_active_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
 	case BCM47XX_BUS_TYPE_SSB:
 		ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0xfffffff);
 		break;
+#endif
 	}
 }
 
 static inline int bcm47xx_wdt_hw_stop(void)
 {
 	switch (bcm47xx_active_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
 	case BCM47XX_BUS_TYPE_SSB:
 		return ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0);
+#endif
 	}
 	return -EINVAL;
 }
-- 
1.7.4.1


From hauke@hauke-m.de Sat Jul 16 18:56:36 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 16 Jul 2011 19:00:38 +0200 (CEST)
Received: from server19320154104.serverpool.info ([193.201.54.104]:50938 "EHLO
        hauke-m.de" rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org
        with ESMTP id S1491808Ab1GPQ4g (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Sat, 16 Jul 2011 18:56:36 +0200
Received: from localhost (localhost [127.0.0.1])
        by hauke-m.de (Postfix) with ESMTP id 9877D8C76;
        Sat, 16 Jul 2011 18:56:36 +0200 (CEST)
X-Virus-Scanned: Debian amavisd-new at hauke-m.de 
Received: from hauke-m.de ([127.0.0.1])
        by localhost (hauke-m.de [127.0.0.1]) (amavisd-new, port 10024)
        with ESMTP id 296hZdfFiKbf; Sat, 16 Jul 2011 18:56:31 +0200 (CEST)
Received: from localhost.localdomain (host-091-097-255-051.ewe-ip-backbone.de [91.97.255.51])
        by hauke-m.de (Postfix) with ESMTPSA id 539618C63;
        Sat, 16 Jul 2011 18:56:09 +0200 (CEST)
From:   Hauke Mehrtens <hauke@hauke-m.de>
To:     ralf@linux-mips.org, linux-wireless@vger.kernel.org,
        zajec5@gmail.com, linux-mips@linux-mips.org
Cc:     jonas.gorski@gmail.com, mb@bu3sch.de, george@znau.edu.ua,
        arend@broadcom.com, b43-dev@lists.infradead.org,
        bernhardloos@googlemail.com, arnd@arndb.de,
        julian.calaby@gmail.com, sshtylyov@mvista.com,
        Hauke Mehrtens <hauke@hauke-m.de>
Subject: [PATCH v2 10/11] bcm47xx: add support for bcma bus
Date:   Sat, 16 Jul 2011 18:55:41 +0200
Message-Id: <1310835342-18877-11-git-send-email-hauke@hauke-m.de>
X-Mailer: git-send-email 1.7.4.1
In-Reply-To: <1310835342-18877-1-git-send-email-hauke@hauke-m.de>
References: <1310835342-18877-1-git-send-email-hauke@hauke-m.de>
X-archive-position: 30641
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: hauke@hauke-m.de
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 11712
Content-Length: 11574
Lines: 426

This patch add support for the bcma bus. Broadcom uses only Mips 74K
CPUs on the new SoC and on the old ons using ssb bus there are no Mips
74K CPUs.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 arch/mips/bcm47xx/Kconfig                    |   13 ++++++
 arch/mips/bcm47xx/gpio.c                     |   22 +++++++++++
 arch/mips/bcm47xx/nvram.c                    |   10 +++++
 arch/mips/bcm47xx/serial.c                   |   29 ++++++++++++++
 arch/mips/bcm47xx/setup.c                    |   53 +++++++++++++++++++++++++-
 arch/mips/bcm47xx/time.c                     |    5 ++
 arch/mips/include/asm/mach-bcm47xx/bcm47xx.h |    8 ++++
 arch/mips/include/asm/mach-bcm47xx/gpio.h    |   41 ++++++++++++++++++++
 drivers/watchdog/bcm47xx_wdt.c               |   11 +++++
 9 files changed, 190 insertions(+), 2 deletions(-)

diff --git a/arch/mips/bcm47xx/Kconfig b/arch/mips/bcm47xx/Kconfig
index 0346f92..6210b8d 100644
--- a/arch/mips/bcm47xx/Kconfig
+++ b/arch/mips/bcm47xx/Kconfig
@@ -15,4 +15,17 @@ config BCM47XX_SSB
 
 	 This will generate an image with support for SSB and MIPS32 R1 instruction set.
 
+config BCM47XX_BCMA
+	bool "BCMA Support for Broadcom BCM47XX"
+	select SYS_HAS_CPU_MIPS32_R2
+	select BCMA
+	select BCMA_HOST_SOC
+	select BCMA_DRIVER_MIPS
+	select BCMA_DRIVER_PCI_HOSTMODE if PCI
+	default y
+	help
+	 Add support for new Broadcom BCM47xx boards with Broadcom specific Advanced Microcontroller Bus.
+
+	 This will generate an image with support for BCMA and MIPS32 R2 instruction set.
+
 endif
diff --git a/arch/mips/bcm47xx/gpio.c b/arch/mips/bcm47xx/gpio.c
index 3320e91..d43895b 100644
--- a/arch/mips/bcm47xx/gpio.c
+++ b/arch/mips/bcm47xx/gpio.c
@@ -36,6 +36,16 @@ int gpio_request(unsigned gpio, const char *tag)
 
 		return 0;
 #endif
+#ifdef CONFIG_BCM47XX_BCMA
+	case BCM47XX_BUS_TYPE_BCMA:
+		if (gpio >= BCM47XX_CHIPCO_GPIO_LINES)
+			return -EINVAL;
+
+		if (test_and_set_bit(gpio, gpio_in_use))
+			return -EBUSY;
+
+		return 0;
+#endif
 	}
 	return -EINVAL;
 }
@@ -57,6 +67,14 @@ void gpio_free(unsigned gpio)
 		clear_bit(gpio, gpio_in_use);
 		return;
 #endif
+#ifdef CONFIG_BCM47XX_BCMA
+	case BCM47XX_BUS_TYPE_BCMA:
+		if (gpio >= BCM47XX_CHIPCO_GPIO_LINES)
+			return;
+
+		clear_bit(gpio, gpio_in_use);
+		return;
+#endif
 	}
 }
 EXPORT_SYMBOL(gpio_free);
@@ -73,6 +91,10 @@ int gpio_to_irq(unsigned gpio)
 		else
 			return -EINVAL;
 #endif
+#ifdef CONFIG_BCM47XX_BCMA
+	case BCM47XX_BUS_TYPE_BCMA:
+		return bcma_core_mips_irq(bcm47xx_bus.bcma.bus.drv_cc.core) + 2;
+#endif
 	}
 	return -EINVAL;
 }
diff --git a/arch/mips/bcm47xx/nvram.c b/arch/mips/bcm47xx/nvram.c
index d223dac..539228d 100644
--- a/arch/mips/bcm47xx/nvram.c
+++ b/arch/mips/bcm47xx/nvram.c
@@ -29,6 +29,9 @@ static void early_nvram_init(void)
 #ifdef CONFIG_BCM47XX_SSB
 	struct ssb_mipscore *mcore_ssb;
 #endif
+#ifdef CONFIG_BCM47XX_BCMA
+	struct bcma_drv_cc *bcma_cc;
+#endif
 	struct nvram_header *header;
 	int i;
 	u32 base = 0;
@@ -44,6 +47,13 @@ static void early_nvram_init(void)
 		lim = mcore_ssb->flash_window_size;
 		break;
 #endif
+#ifdef CONFIG_BCM47XX_BCMA
+	case BCM47XX_BUS_TYPE_BCMA:
+		bcma_cc = &bcm47xx_bus.bcma.bus.drv_cc;
+		base = bcma_cc->pflash.window;
+		lim = bcma_cc->pflash.window_size;
+		break;
+#endif
 	}
 
 	off = FLASH_MIN;
diff --git a/arch/mips/bcm47xx/serial.c b/arch/mips/bcm47xx/serial.c
index e9258cb..2e8492b3 100644
--- a/arch/mips/bcm47xx/serial.c
+++ b/arch/mips/bcm47xx/serial.c
@@ -47,6 +47,31 @@ static int __init uart8250_init_ssb(void)
 }
 #endif
 
+#ifdef CONFIG_BCM47XX_BCMA
+static int __init uart8250_init_bcma(void)
+{
+	int i;
+	struct bcma_drv_cc *cc = &(bcm47xx_bus.bcma.bus.drv_cc);
+
+	memset(&uart8250_data, 0,  sizeof(uart8250_data));
+
+	for (i = 0; i < cc->nr_serial_ports; i++) {
+		struct plat_serial8250_port *p = &(uart8250_data[i]);
+		struct bcma_serial_port *bcma_port;
+		bcma_port = &(cc->serial_ports[i]);
+
+		p->mapbase = (unsigned int) bcma_port->regs;
+		p->membase = (void *) bcma_port->regs;
+		p->irq = bcma_port->irq + 2;
+		p->uartclk = bcma_port->baud_base;
+		p->regshift = bcma_port->reg_shift;
+		p->iotype = UPIO_MEM;
+		p->flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
+	}
+	return platform_device_register(&uart8250_device);
+}
+#endif
+
 static int __init uart8250_init(void)
 {
 	switch (bcm47xx_active_bus_type) {
@@ -54,6 +79,10 @@ static int __init uart8250_init(void)
 	case BCM47XX_BUS_TYPE_SSB:
 		return uart8250_init_ssb();
 #endif
+#ifdef CONFIG_BCM47XX_BCMA
+	case BCM47XX_BUS_TYPE_BCMA:
+		return uart8250_init_bcma();
+#endif
 	}
 	return -EINVAL;
 }
diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c
index 9fc92bd..612a5ec 100644
--- a/arch/mips/bcm47xx/setup.c
+++ b/arch/mips/bcm47xx/setup.c
@@ -29,6 +29,7 @@
 #include <linux/types.h>
 #include <linux/ssb/ssb.h>
 #include <linux/ssb/ssb_embedded.h>
+#include <linux/bcma/bcma_soc.h>
 #include <asm/bootinfo.h>
 #include <asm/reboot.h>
 #include <asm/time.h>
@@ -52,6 +53,11 @@ static void bcm47xx_machine_restart(char *command)
 		ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 1);
 		break;
 #endif
+#ifdef CONFIG_BCM47XX_BCMA
+	case BCM47XX_BUS_TYPE_BCMA:
+		bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.bus.drv_cc, 1);
+		break;
+#endif
 	}
 	while (1)
 		cpu_relax();
@@ -67,6 +73,11 @@ static void bcm47xx_machine_halt(void)
 		ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0);
 		break;
 #endif
+#ifdef CONFIG_BCM47XX_BCMA
+	case BCM47XX_BUS_TYPE_BCMA:
+		bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.bus.drv_cc, 0);
+		break;
+#endif
 	}
 	while (1)
 		cpu_relax();
@@ -295,16 +306,54 @@ static void __init bcm47xx_register_ssb(void)
 }
 #endif
 
+#ifdef CONFIG_BCM47XX_BCMA
+static void __init bcm47xx_register_bcma(void)
+{
+	int err;
+
+	err = bcma_host_soc_register(&bcm47xx_bus.bcma);
+	if (err)
+		panic("Failed to initialize BCMA bus (err %d)\n", err);
+}
+#endif
+
 void __init plat_mem_setup(void)
 {
 	struct cpuinfo_mips *c = &current_cpu_data;
 
+	if (c->cputype == CPU_74K) {
+		printk(KERN_INFO "bcm47xx: using bcma bus\n");
+#ifdef CONFIG_BCM47XX_BCMA
+		bcm47xx_active_bus_type = BCM47XX_BUS_TYPE_BCMA;
+		bcm47xx_register_bcma();
+#endif
+	} else {
+		printk(KERN_INFO "bcm47xx: using ssb bus\n");
 #ifdef CONFIG_BCM47XX_SSB
-	bcm47xx_active_bus_type = BCM47XX_BUS_TYPE_SSB;
-	bcm47xx_register_ssb();
+		bcm47xx_active_bus_type = BCM47XX_BUS_TYPE_SSB;
+		bcm47xx_register_ssb();
 #endif
+	}
 
 	_machine_restart = bcm47xx_machine_restart;
 	_machine_halt = bcm47xx_machine_halt;
 	pm_power_off = bcm47xx_machine_halt;
 }
+
+static int __init bcm47xx_register_bus_complete(void)
+{
+	switch (bcm47xx_active_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
+	case BCM47XX_BUS_TYPE_SSB:
+		/* Nothing to do */
+		break;
+#endif
+#ifdef CONFIG_BCM47XX_BCMA
+	case BCM47XX_BUS_TYPE_BCMA:
+		bcma_bus_register(&bcm47xx_bus.bcma.bus);
+		break;
+#endif
+	}
+	return 0;
+}
+device_initcall(bcm47xx_register_bus_complete);
diff --git a/arch/mips/bcm47xx/time.c b/arch/mips/bcm47xx/time.c
index 02a652a..c10471a 100644
--- a/arch/mips/bcm47xx/time.c
+++ b/arch/mips/bcm47xx/time.c
@@ -45,6 +45,11 @@ void __init plat_time_init(void)
 		hz = ssb_cpu_clock(&bcm47xx_bus.ssb.mipscore) / 2;
 		break;
 #endif
+#ifdef CONFIG_BCM47XX_BCMA
+	case BCM47XX_BUS_TYPE_BCMA:
+		hz = bcma_cpu_clock(&bcm47xx_bus.bcma.bus.drv_mips) / 2;
+		break;
+#endif
 	}
 
 	if (!hz)
diff --git a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
index 764afea..3959485 100644
--- a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
+++ b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
@@ -20,17 +20,25 @@
 #define __ASM_BCM47XX_H
 
 #include <linux/ssb/ssb.h>
+#include <linux/bcma/bcma.h>
+#include <linux/bcma/bcma_soc.h>
 
 enum bcm47xx_bus_type {
 #ifdef CONFIG_BCM47XX_SSB
 	BCM47XX_BUS_TYPE_SSB,
 #endif
+#ifdef CONFIG_BCM47XX_BCMA
+	BCM47XX_BUS_TYPE_BCMA,
+#endif
 };
 
 union bcm47xx_bus {
 #ifdef CONFIG_BCM47XX_SSB
 	struct ssb_bus ssb;
 #endif
+#ifdef CONFIG_BCM47XX_BCMA
+	struct bcma_soc bcma;
+#endif
 };
 
 extern union bcm47xx_bus bcm47xx_bus;
diff --git a/arch/mips/include/asm/mach-bcm47xx/gpio.h b/arch/mips/include/asm/mach-bcm47xx/gpio.h
index 0c3bd1f..0dcb71a 100644
--- a/arch/mips/include/asm/mach-bcm47xx/gpio.h
+++ b/arch/mips/include/asm/mach-bcm47xx/gpio.h
@@ -10,6 +10,7 @@
 #define __BCM47XX_GPIO_H
 
 #include <linux/ssb/ssb_embedded.h>
+#include <linux/bcma/bcma.h>
 #include <asm/mach-bcm47xx/bcm47xx.h>
 
 #define BCM47XX_EXTIF_GPIO_LINES	5
@@ -26,6 +27,11 @@ static inline int gpio_get_value(unsigned gpio)
 	case BCM47XX_BUS_TYPE_SSB:
 		return ssb_gpio_in(&bcm47xx_bus.ssb, 1 << gpio);
 #endif
+#ifdef CONFIG_BCM47XX_BCMA
+	case BCM47XX_BUS_TYPE_BCMA:
+		return bcma_chipco_gpio_in(&bcm47xx_bus.bcma.bus.drv_cc,
+					   1 << gpio);
+#endif
 	}
 	return -EINVAL;
 }
@@ -37,6 +43,13 @@ static inline void gpio_set_value(unsigned gpio, int value)
 	case BCM47XX_BUS_TYPE_SSB:
 		ssb_gpio_out(&bcm47xx_bus.ssb, 1 << gpio,
 			     value ? 1 << gpio : 0);
+		return;
+#endif
+#ifdef CONFIG_BCM47XX_BCMA
+	case BCM47XX_BUS_TYPE_BCMA:
+		bcma_chipco_gpio_out(&bcm47xx_bus.bcma.bus.drv_cc, 1 << gpio,
+				     value ? 1 << gpio : 0);
+		return;
 #endif
 	}
 }
@@ -49,6 +62,12 @@ static inline int gpio_direction_input(unsigned gpio)
 		ssb_gpio_outen(&bcm47xx_bus.ssb, 1 << gpio, 0);
 		return 0;
 #endif
+#ifdef CONFIG_BCM47XX_BCMA
+	case BCM47XX_BUS_TYPE_BCMA:
+		bcma_chipco_gpio_outen(&bcm47xx_bus.bcma.bus.drv_cc, 1 << gpio,
+				       0);
+		return 0;
+#endif
 	}
 	return -EINVAL;
 }
@@ -65,6 +84,16 @@ static inline int gpio_direction_output(unsigned gpio, int value)
 		ssb_gpio_outen(&bcm47xx_bus.ssb, 1 << gpio, 1 << gpio);
 		return 0;
 #endif
+#ifdef CONFIG_BCM47XX_BCMA
+	case BCM47XX_BUS_TYPE_BCMA:
+		/* first set the gpio out value */
+		bcma_chipco_gpio_out(&bcm47xx_bus.bcma.bus.drv_cc, 1 << gpio,
+				     value ? 1 << gpio : 0);
+		/* then set the gpio mode */
+		bcma_chipco_gpio_outen(&bcm47xx_bus.bcma.bus.drv_cc, 1 << gpio,
+				       1 << gpio);
+		return 0;
+#endif
 	}
 	return -EINVAL;
 }
@@ -78,6 +107,12 @@ static inline int gpio_intmask(unsigned gpio, int value)
 				 value ? 1 << gpio : 0);
 		return 0;
 #endif
+#ifdef CONFIG_BCM47XX_BCMA
+	case BCM47XX_BUS_TYPE_BCMA:
+		bcma_chipco_gpio_intmask(&bcm47xx_bus.bcma.bus.drv_cc,
+					 1 << gpio, value ? 1 << gpio : 0);
+		return 0;
+#endif
 	}
 	return -EINVAL;
 }
@@ -91,6 +126,12 @@ static inline int gpio_polarity(unsigned gpio, int value)
 				  value ? 1 << gpio : 0);
 		return 0;
 #endif
+#ifdef CONFIG_BCM47XX_BCMA
+	case BCM47XX_BUS_TYPE_BCMA:
+		bcma_chipco_gpio_polarity(&bcm47xx_bus.bcma.bus.drv_cc,
+					  1 << gpio, value ? 1 << gpio : 0);
+		return 0;
+#endif
 	}
 	return -EINVAL;
 }
diff --git a/drivers/watchdog/bcm47xx_wdt.c b/drivers/watchdog/bcm47xx_wdt.c
index beacd79..febce9b 100644
--- a/drivers/watchdog/bcm47xx_wdt.c
+++ b/drivers/watchdog/bcm47xx_wdt.c
@@ -60,6 +60,12 @@ static inline void bcm47xx_wdt_hw_start(void)
 		ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0xfffffff);
 		break;
 #endif
+#ifdef CONFIG_BCM47XX_BCMA
+	case BCM47XX_BUS_TYPE_BCMA:
+		bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.bus.drv_cc,
+					       0xfffffff);
+		break;
+#endif
 	}
 }
 
@@ -70,6 +76,11 @@ static inline int bcm47xx_wdt_hw_stop(void)
 	case BCM47XX_BUS_TYPE_SSB:
 		return ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0);
 #endif
+#ifdef CONFIG_BCM47XX_BCMA
+	case BCM47XX_BUS_TYPE_BCMA:
+		bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.bus.drv_cc, 0);
+		return 0;
+#endif
 	}
 	return -EINVAL;
 }
-- 
1.7.4.1


From hauke@hauke-m.de Sat Jul 16 18:56:38 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 16 Jul 2011 19:01:03 +0200 (CEST)
Received: from server19320154104.serverpool.info ([193.201.54.104]:50948 "EHLO
        hauke-m.de" rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org
        with ESMTP id S1491809Ab1GPQ4i (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Sat, 16 Jul 2011 18:56:38 +0200
Received: from localhost (localhost [127.0.0.1])
        by hauke-m.de (Postfix) with ESMTP id B17F08C63;
        Sat, 16 Jul 2011 18:56:37 +0200 (CEST)
X-Virus-Scanned: Debian amavisd-new at hauke-m.de 
Received: from hauke-m.de ([127.0.0.1])
        by localhost (hauke-m.de [127.0.0.1]) (amavisd-new, port 10024)
        with ESMTP id cnMGvYfJsC+Z; Sat, 16 Jul 2011 18:56:33 +0200 (CEST)
Received: from localhost.localdomain (host-091-097-255-051.ewe-ip-backbone.de [91.97.255.51])
        by hauke-m.de (Postfix) with ESMTPSA id 47A678C6D;
        Sat, 16 Jul 2011 18:56:10 +0200 (CEST)
From:   Hauke Mehrtens <hauke@hauke-m.de>
To:     ralf@linux-mips.org, linux-wireless@vger.kernel.org,
        zajec5@gmail.com, linux-mips@linux-mips.org
Cc:     jonas.gorski@gmail.com, mb@bu3sch.de, george@znau.edu.ua,
        arend@broadcom.com, b43-dev@lists.infradead.org,
        bernhardloos@googlemail.com, arnd@arndb.de,
        julian.calaby@gmail.com, sshtylyov@mvista.com,
        Hauke Mehrtens <hauke@hauke-m.de>
Subject: [PATCH v2 11/11] bcm47xx: fix irq assignment for new SoCs.
Date:   Sat, 16 Jul 2011 18:55:42 +0200
Message-Id: <1310835342-18877-12-git-send-email-hauke@hauke-m.de>
X-Mailer: git-send-email 1.7.4.1
In-Reply-To: <1310835342-18877-1-git-send-email-hauke@hauke-m.de>
References: <1310835342-18877-1-git-send-email-hauke@hauke-m.de>
X-archive-position: 30642
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: hauke@hauke-m.de
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 11713
Content-Length: 939
Lines: 37

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 arch/mips/bcm47xx/irq.c |   12 ++++++++++++
 1 files changed, 12 insertions(+), 0 deletions(-)

diff --git a/arch/mips/bcm47xx/irq.c b/arch/mips/bcm47xx/irq.c
index 325757a..70bdcf0 100644
--- a/arch/mips/bcm47xx/irq.c
+++ b/arch/mips/bcm47xx/irq.c
@@ -26,6 +26,7 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <asm/irq_cpu.h>
+#include <bcm47xx.h>
 
 void plat_irq_dispatch(void)
 {
@@ -51,5 +52,16 @@ void plat_irq_dispatch(void)
 
 void __init arch_init_irq(void)
 {
+#ifdef CONFIG_BCM47XX_BCMA
+	if (bcm47xx_active_bus_type == BCM47XX_BUS_TYPE_BCMA) {
+		bcma_write32(bcm47xx_bus.bcma.bus.drv_mips.core,
+			     BCMA_MIPS_MIPS74K_INTMASK(5), 1 << 31);
+		/*
+		 * the kernel reads the timer irq from some register and thinks
+		 * it's #5, but we offset it by 2 and route to #7
+		 */
+		cp0_compare_irq = 7;
+	}
+#endif
 	mips_cpu_irq_init();
 }
-- 
1.7.4.1


From rjw@sisk.pl Sat Jul 16 23:49:59 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 16 Jul 2011 23:50:06 +0200 (CEST)
Received: from ogre.sisk.pl ([217.79.144.158]:58501 "EHLO ogre.sisk.pl"
        rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org with ESMTP
        id S1491025Ab1GPVt7 (ORCPT <rfc822;linux-mips@linux-mips.org>);
        Sat, 16 Jul 2011 23:49:59 +0200
Received: from localhost (localhost.localdomain [127.0.0.1])
        by ogre.sisk.pl (Postfix) with ESMTP id 335BC1B09BA;
        Sat, 16 Jul 2011 23:21:13 +0200 (CEST)
Received: from ogre.sisk.pl ([127.0.0.1])
 by localhost (ogre.sisk.pl [127.0.0.1]) (amavisd-new, port 10024) with ESMTP
 id 24313-04; Sat, 16 Jul 2011 23:20:52 +0200 (CEST)
Received: from ferrari.rjw.lan (unknown [76.164.19.200])
        (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits))
        (No client certificate requested)
        by ogre.sisk.pl (Postfix) with ESMTP id 04CAD1B0826;
        Sat, 16 Jul 2011 23:20:52 +0200 (CEST)
From:   "Rafael J. Wysocki" <rjw@sisk.pl>
To:     Linus Torvalds <torvalds@linux-foundation.org>
Subject: [GIT PULL] MIPS build fix related to power management for 3.0
Date:   Sat, 16 Jul 2011 23:50:50 +0200
User-Agent: KMail/1.13.6 (Linux/3.0.0-rc7+; KDE/4.6.0; x86_64; ; )
Cc:     Ralf Baechle <ralf@linux-mips.org>, linux-mips@linux-mips.org,
        LKML <linux-kernel@vger.kernel.org>,
        Linux PM mailing list <linux-pm@lists.linux-foundation.org>
MIME-Version: 1.0
Content-Type: text/plain;
  charset="utf-8"
Content-Transfer-Encoding: 7bit
Message-Id: <201107162350.51025.rjw@sisk.pl>
X-Virus-Scanned: amavisd-new at ogre.sisk.pl using MkS_Vir for Linux
X-archive-position: 30643
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: rjw@sisk.pl
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 11765
Content-Length: 487
Lines: 18

Hi Linus,

Please pull a MIPS build fix related to PM for 3.0 from:

git://git.kernel.org/pub/scm/linux/kernel/git/rafael/suspend-2.6.git pm-fixes

It fixes a build regression resulting from a missing conversion from using
a sysdev to using syscore_ops for PM/shutdown in the MIPS tree.


 arch/mips/kernel/i8259.c |   22 ++++++----------------
 1 files changed, 6 insertions(+), 16 deletions(-)

----------

Rafael J. Wysocki (1):
      PM / MIPS: Convert i8259.c to using syscore_ops


From manuel.lauss@googlemail.com Mon Jul 18 20:30:42 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Mon, 18 Jul 2011 20:30:47 +0200 (CEST)
Received: from mail-fx0-f49.google.com ([209.85.161.49]:56701 "EHLO
        mail-fx0-f49.google.com" rhost-flags-OK-OK-OK-OK)
        by eddie.linux-mips.org with ESMTP id S1491106Ab1GRSam (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Mon, 18 Jul 2011 20:30:42 +0200
Received: by fxd20 with SMTP id 20so5090569fxd.36
        for <linux-mips@linux-mips.org>; Mon, 18 Jul 2011 11:30:36 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=googlemail.com; s=gamma;
        h=from:to:cc:subject:date:message-id:x-mailer;
        bh=wJcpmfDf2Rix9/+K38A30msixHpDw6KfJDIBLng2arg=;
        b=htENL0P3AMXmFwb/Siuxw2kF48zTLruJRWToMX2EhMSPWqa7DuTZe+kfbjcIVhvWeB
         p2k+BzduEu+KE4lQITO9t7nRJUXOjGC5SNmPIDRQ7Sfx8GK4FZbzGWrizR6bEOUAcr6c
         fTkDcYSa85xRDGmKpPv9B86Qyhu17qgzT9YSg=
Received: by 10.223.160.144 with SMTP id n16mr4222284fax.88.1311013836854;
        Mon, 18 Jul 2011 11:30:36 -0700 (PDT)
Received: from localhost.localdomain (188-22-157-220.adsl.highway.telekom.at [188.22.157.220])
        by mx.google.com with ESMTPS id n27sm3126522faa.4.2011.07.18.11.30.33
        (version=TLSv1/SSLv3 cipher=OTHER);
        Mon, 18 Jul 2011 11:30:35 -0700 (PDT)
From:   Manuel Lauss <manuel.lauss@googlemail.com>
To:     Linux-MIPS <linux-mips@linux-mips.org>
Cc:     Manuel Lauss <manuel.lauss@googlemail.com>
Subject: [RFC PATCH] MIPS: PCI: add a map_irq callback to struct pci_controller
Date:   Mon, 18 Jul 2011 20:30:30 +0200
Message-Id: <1311013830-9990-1-git-send-email-manuel.lauss@googlemail.com>
X-Mailer: git-send-email 1.7.6
X-archive-position: 30644
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: manuel.lauss@googlemail.com
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 12618
Content-Length: 5136
Lines: 143

I'm rewriting the Alchemy PCI driver to be a platform driver, and
one thing that bugs me to no end is that for every PCI controller
the same global pcibios_map_irq function is called.
Instead I'd like to pass the per-board pci irq tables through
platform data and provide a per-controller map_irq callback.

This patch adds a maq_irq callback to struct pci_controller,
and uses it if available in pcibios_init().

Run-tested on a DB1500 board.

Comments welcome!

Signed-off-by: Manuel Lauss <manuel.lauss@googlemail.com>
---

Eventually I'd like to do this also with pcibios_plat_dev_init,
which is unused except on octeon and SSB-bus BCM chips.

 arch/mips/alchemy/common/pci.c                   |    8 ++++++++
 arch/mips/alchemy/devboards/db1x00/board_setup.c |    8 ++++----
 arch/mips/include/asm/pci.h                      |    2 ++
 arch/mips/pci/fixup-au1000.c                     |    4 +---
 arch/mips/pci/pci.c                              |    9 ++++++---
 5 files changed, 21 insertions(+), 10 deletions(-)

diff --git a/arch/mips/alchemy/common/pci.c b/arch/mips/alchemy/common/pci.c
index 7866cf5..e7bd034 100644
--- a/arch/mips/alchemy/common/pci.c
+++ b/arch/mips/alchemy/common/pci.c
@@ -53,10 +53,18 @@ static struct resource pci_mem_resource = {
 
 extern struct pci_ops au1x_pci_ops;
 
+extern char irq_tab_alchemy[][5];
+
+int alchemy_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+	return irq_tab_alchemy[slot][pin];
+}
+
 static struct pci_controller au1x_controller = {
 	.pci_ops	= &au1x_pci_ops,
 	.io_resource	= &pci_io_resource,
 	.mem_resource	= &pci_mem_resource,
+	.map_irq	= alchemy_pci_map_irq,
 };
 
 #if defined(CONFIG_SOC_AU1500) || defined(CONFIG_SOC_AU1550)
diff --git a/arch/mips/alchemy/devboards/db1x00/board_setup.c b/arch/mips/alchemy/devboards/db1x00/board_setup.c
index 5c956fe..8f6b926 100644
--- a/arch/mips/alchemy/devboards/db1x00/board_setup.c
+++ b/arch/mips/alchemy/devboards/db1x00/board_setup.c
@@ -41,7 +41,7 @@
 #include <prom.h>
 
 #ifdef CONFIG_MIPS_DB1500
-char irq_tab_alchemy[][5] __initdata = {
+char irq_tab_alchemy[][5] = {
 	[12] = { -1, AU1500_PCI_INTA, 0xff, 0xff, 0xff }, /* IDSEL 12 - HPT371   */
 	[13] = { -1, AU1500_PCI_INTA, AU1500_PCI_INTB, AU1500_PCI_INTC, AU1500_PCI_INTD }, /* IDSEL 13 - PCI slot */
 };
@@ -50,7 +50,7 @@ char irq_tab_alchemy[][5] __initdata = {
 
 
 #ifdef CONFIG_MIPS_DB1550
-char irq_tab_alchemy[][5] __initdata = {
+char irq_tab_alchemy[][5] = {
 	[11] = { -1, AU1550_PCI_INTC, 0xff, 0xff, 0xff }, /* IDSEL 11 - on-board HPT371 */
 	[12] = { -1, AU1550_PCI_INTB, AU1550_PCI_INTC, AU1550_PCI_INTD, AU1550_PCI_INTA }, /* IDSEL 12 - PCI slot 2 (left) */
 	[13] = { -1, AU1550_PCI_INTA, AU1550_PCI_INTB, AU1550_PCI_INTC, AU1550_PCI_INTD }, /* IDSEL 13 - PCI slot 1 (right) */
@@ -59,7 +59,7 @@ char irq_tab_alchemy[][5] __initdata = {
 
 
 #ifdef CONFIG_MIPS_BOSPORUS
-char irq_tab_alchemy[][5] __initdata = {
+char irq_tab_alchemy[][5] = {
 	[11] = { -1, AU1500_PCI_INTA, AU1500_PCI_INTB, 0xff, 0xff }, /* IDSEL 11 - miniPCI  */
 	[12] = { -1, AU1500_PCI_INTA, 0xff, 0xff, 0xff }, /* IDSEL 12 - SN1741   */
 	[13] = { -1, AU1500_PCI_INTA, AU1500_PCI_INTB, AU1500_PCI_INTC, AU1500_PCI_INTD }, /* IDSEL 13 - PCI slot */
@@ -91,7 +91,7 @@ const char *get_system_type(void)
 
 
 #ifdef CONFIG_MIPS_MIRAGE
-char irq_tab_alchemy[][5] __initdata = {
+char irq_tab_alchemy[][5] = {
 	[11] = { -1, AU1500_PCI_INTD, 0xff, 0xff, 0xff }, /* IDSEL 11 - SMI VGX */
 	[12] = { -1, 0xff, 0xff, AU1500_PCI_INTC, 0xff }, /* IDSEL 12 - PNX1300 */
 	[13] = { -1, AU1500_PCI_INTA, AU1500_PCI_INTB, 0xff, 0xff }, /* IDSEL 13 - miniPCI */
diff --git a/arch/mips/include/asm/pci.h b/arch/mips/include/asm/pci.h
index 576397c..a5d30ef 100644
--- a/arch/mips/include/asm/pci.h
+++ b/arch/mips/include/asm/pci.h
@@ -45,6 +45,8 @@ struct pci_controller {
 	   of the PCI controller */
 	int (*get_busno)(void);
 	void (*set_busno)(int busno);
+
+	int (*map_irq)(const struct pci_dev *dev, u8 slot, u8 pin);
 };
 
 /*
diff --git a/arch/mips/pci/fixup-au1000.c b/arch/mips/pci/fixup-au1000.c
index e2ddfc4..448d8e5 100644
--- a/arch/mips/pci/fixup-au1000.c
+++ b/arch/mips/pci/fixup-au1000.c
@@ -29,11 +29,9 @@
 #include <linux/pci.h>
 #include <linux/init.h>
 
-extern char irq_tab_alchemy[][5];
-
 int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
-	return irq_tab_alchemy[slot][pin];
+	return -1;
 }
 
 /* Do platform specific device initialization at pci_enable_device() time */
diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c
index 33bba7b..74f62e4 100644
--- a/arch/mips/pci/pci.c
+++ b/arch/mips/pci/pci.c
@@ -154,10 +154,13 @@ static int __init pcibios_init(void)
 	struct pci_controller *hose;
 
 	/* Scan all of the recorded PCI controllers.  */
-	for (hose = hose_head; hose; hose = hose->next)
+	for (hose = hose_head; hose; hose = hose->next) {
 		pcibios_scanbus(hose);
-
-	pci_fixup_irqs(pci_common_swizzle, pcibios_map_irq);
+		if (hose->map_irq)
+			pci_fixup_irqs(pci_common_swizzle, hose->map_irq);
+		else
+			pci_fixup_irqs(pci_common_swizzle, pcibios_map_irq);
+	}
 
 	pci_initialized = 1;
 
-- 
1.7.6


From blogic@openwrt.org Mon Jul 18 22:03:03 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Mon, 18 Jul 2011 22:03:12 +0200 (CEST)
Received: from nbd.name ([46.4.11.11]:44582 "EHLO nbd.name"
        rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org with ESMTP
        id S1491147Ab1GRUDD (ORCPT <rfc822;linux-mips@linux-mips.org>);
        Mon, 18 Jul 2011 22:03:03 +0200
From:   John Crispin <blogic@openwrt.org>
To:     Ralf Baechle <ralf@linux-mips.org>
Cc:     John Crispin <blogic@openwrt.org>, linux-mips@linux-mips.org
Subject: [PATCH 1/3] MIPS: lantiq: fixes external interruot sources
Date:   Mon, 18 Jul 2011 22:04:11 +0200
Message-Id: <1311019453-21277-1-git-send-email-blogic@openwrt.org>
X-Mailer: git-send-email 1.7.2.3
X-archive-position: 30645
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: blogic@openwrt.org
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 12690
Content-Length: 1362
Lines: 43

The irq base offset needs to be ignored when matching irqs to external
interrupt pins. Taking the offset into account resulted in the EIU not
being brought up properly.

Signed-off-by: John Crispin <blogic@openwrt.org>
Cc: linux-mips@linux-mips.org
---
 arch/mips/lantiq/irq.c |    6 ++----
 1 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/arch/mips/lantiq/irq.c b/arch/mips/lantiq/irq.c
index fc89795..f9737bb 100644
--- a/arch/mips/lantiq/irq.c
+++ b/arch/mips/lantiq/irq.c
@@ -123,11 +123,10 @@ void ltq_enable_irq(struct irq_data *d)
 static unsigned int ltq_startup_eiu_irq(struct irq_data *d)
 {
 	int i;
-	int irq_nr = d->irq - INT_NUM_IRQ0;
 
 	ltq_enable_irq(d);
 	for (i = 0; i < MAX_EIU; i++) {
-		if (irq_nr == ltq_eiu_irq[i]) {
+		if (d->irq == ltq_eiu_irq[i]) {
 			/* low level - we should really handle set_type */
 			ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_C) |
 				(0x6 << (i * 4)), LTQ_EIU_EXIN_C);
@@ -147,11 +146,10 @@ static unsigned int ltq_startup_eiu_irq(struct irq_data *d)
 static void ltq_shutdown_eiu_irq(struct irq_data *d)
 {
 	int i;
-	int irq_nr = d->irq - INT_NUM_IRQ0;
 
 	ltq_disable_irq(d);
 	for (i = 0; i < MAX_EIU; i++) {
-		if (irq_nr == ltq_eiu_irq[i]) {
+		if (d->irq == ltq_eiu_irq[i]) {
 			/* disable */
 			ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) & ~(1 << i),
 				LTQ_EIU_EXIN_INEN);
-- 
1.7.2.3


From blogic@openwrt.org Mon Jul 18 22:03:03 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Mon, 18 Jul 2011 22:03:36 +0200 (CEST)
Received: from nbd.name ([46.4.11.11]:44583 "EHLO nbd.name"
        rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org with ESMTP
        id S1491106Ab1GRUDD (ORCPT <rfc822;linux-mips@linux-mips.org>);
        Mon, 18 Jul 2011 22:03:03 +0200
From:   John Crispin <blogic@openwrt.org>
To:     Ralf Baechle <ralf@linux-mips.org>
Cc:     John Crispin <blogic@openwrt.org>, linux-mips@linux-mips.org
Subject: [PATCH 2/3] MIPS: lantiq: fix setting the PCI bus speed on AR9
Date:   Mon, 18 Jul 2011 22:04:12 +0200
Message-Id: <1311019453-21277-2-git-send-email-blogic@openwrt.org>
X-Mailer: git-send-email 1.7.2.3
In-Reply-To: <1311019453-21277-1-git-send-email-blogic@openwrt.org>
References: <1311019453-21277-1-git-send-email-blogic@openwrt.org>
X-archive-position: 30646
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: blogic@openwrt.org
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 12692
Content-Length: 1104
Lines: 32

The bits used to set the PCI bus speed on AR9 are slightly different to those
used on Danube.

Signed-off-by: John Crispin <blogic@openwrt.org>
Cc: linux-mips@linux-mips.org
---
 arch/mips/pci/pci-lantiq.c |    9 +++++++--
 1 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/arch/mips/pci/pci-lantiq.c b/arch/mips/pci/pci-lantiq.c
index 603d749..8656388 100644
--- a/arch/mips/pci/pci-lantiq.c
+++ b/arch/mips/pci/pci-lantiq.c
@@ -171,8 +171,13 @@ static int __devinit ltq_pci_startup(struct ltq_pci_data *conf)
 	u32 temp_buffer;
 
 	/* set clock to 33Mhz */
-	ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) & ~0xf00000, LTQ_CGU_IFCCR);
-	ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) | 0x800000, LTQ_CGU_IFCCR);
+	if (ltq_is_ar9()) {
+		ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) & ~0x1f00000, LTQ_CGU_IFCCR);
+		ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) | 0xe00000, LTQ_CGU_IFCCR);
+	} else {
+		ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) & ~0xf00000, LTQ_CGU_IFCCR);
+		ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) | 0x800000, LTQ_CGU_IFCCR);
+	}
 
 	/* external or internal clock ? */
 	if (conf->clock) {
-- 
1.7.2.3


From blogic@openwrt.org Mon Jul 18 22:03:04 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Mon, 18 Jul 2011 22:04:03 +0200 (CEST)
Received: from nbd.name ([46.4.11.11]:44587 "EHLO nbd.name"
        rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org with ESMTP
        id S1491152Ab1GRUDE (ORCPT <rfc822;linux-mips@linux-mips.org>);
        Mon, 18 Jul 2011 22:03:04 +0200
From:   John Crispin <blogic@openwrt.org>
To:     Ralf Baechle <ralf@linux-mips.org>
Cc:     John Crispin <blogic@openwrt.org>,
        Thomas Langer <thomas.langer@lantiq.com>,
        linux-mips@linux-mips.org, linux-serial@vger.kernel.org
Subject: [PATCH 3/3] MIPS: lantiq: set timeout in uart_port
Date:   Mon, 18 Jul 2011 22:04:13 +0200
Message-Id: <1311019453-21277-3-git-send-email-blogic@openwrt.org>
X-Mailer: git-send-email 1.7.2.3
In-Reply-To: <1311019453-21277-1-git-send-email-blogic@openwrt.org>
References: <1311019453-21277-1-git-send-email-blogic@openwrt.org>
X-archive-position: 30647
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: blogic@openwrt.org
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 12693
Content-Length: 824
Lines: 29

Without this patch apps using readline hang.

Signed-off-by: Thomas Langer <thomas.langer@lantiq.com>
Signed-off-by: John Crispin <blogic@openwrt.org>
Cc: linux-mips@linux-mips.org
Cc: linux-serial@vger.kernel.org
---
 drivers/tty/serial/lantiq.c |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)

diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c
index 58cf279..bc95f52 100644
--- a/drivers/tty/serial/lantiq.c
+++ b/drivers/tty/serial/lantiq.c
@@ -478,8 +478,10 @@ lqasc_set_termios(struct uart_port *port,
 	spin_unlock_irqrestore(&ltq_asc_lock, flags);
 
 	/* Don't rewrite B0 */
-        if (tty_termios_baud_rate(new))
+	if (tty_termios_baud_rate(new))
 		tty_termios_encode_baud_rate(new, baud, baud);
+
+	uart_update_timeout(port, cflag, baud);
 }
 
 static const char*
-- 
1.7.2.3


From blogic@openwrt.org Mon Jul 18 22:07:29 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Mon, 18 Jul 2011 22:07:35 +0200 (CEST)
Received: from nbd.name ([46.4.11.11]:57517 "EHLO nbd.name"
        rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org with ESMTP
        id S1491106Ab1GRUH3 (ORCPT <rfc822;linux-mips@linux-mips.org>);
        Mon, 18 Jul 2011 22:07:29 +0200
From:   John Crispin <blogic@openwrt.org>
To:     Ralf Baechle <ralf@linux-mips.org>
Cc:     John Crispin <blogic@openwrt.org>, linux-mips@linux-mips.org
Subject: [PATCH V2 1/3] MIPS: lantiq: fixes external interrupt sources
Date:   Mon, 18 Jul 2011 22:08:40 +0200
Message-Id: <1311019720-22234-1-git-send-email-blogic@openwrt.org>
X-Mailer: git-send-email 1.7.2.3
X-archive-position: 30648
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: blogic@openwrt.org
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 12696
Content-Length: 1407
Lines: 47

The irq base offset needs to be ignored when matching irqs to external
interrupt pins. Taking the offset into account resulted in the EIU not
being brought up properly.

Signed-off-by: John Crispin <blogic@openwrt.org>
Cc: linux-mips@linux-mips.org

---
Changes in V2
* fix typo in patch title
---
 arch/mips/lantiq/irq.c |    6 ++----
 1 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/arch/mips/lantiq/irq.c b/arch/mips/lantiq/irq.c
index fc89795..f9737bb 100644
--- a/arch/mips/lantiq/irq.c
+++ b/arch/mips/lantiq/irq.c
@@ -123,11 +123,10 @@ void ltq_enable_irq(struct irq_data *d)
 static unsigned int ltq_startup_eiu_irq(struct irq_data *d)
 {
 	int i;
-	int irq_nr = d->irq - INT_NUM_IRQ0;
 
 	ltq_enable_irq(d);
 	for (i = 0; i < MAX_EIU; i++) {
-		if (irq_nr == ltq_eiu_irq[i]) {
+		if (d->irq == ltq_eiu_irq[i]) {
 			/* low level - we should really handle set_type */
 			ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_C) |
 				(0x6 << (i * 4)), LTQ_EIU_EXIN_C);
@@ -147,11 +146,10 @@ static unsigned int ltq_startup_eiu_irq(struct irq_data *d)
 static void ltq_shutdown_eiu_irq(struct irq_data *d)
 {
 	int i;
-	int irq_nr = d->irq - INT_NUM_IRQ0;
 
 	ltq_disable_irq(d);
 	for (i = 0; i < MAX_EIU; i++) {
-		if (irq_nr == ltq_eiu_irq[i]) {
+		if (d->irq == ltq_eiu_irq[i]) {
 			/* disable */
 			ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) & ~(1 << i),
 				LTQ_EIU_EXIN_INEN);
-- 
1.7.2.3


From tripeaks@gmail.com Tue Jul 19 07:35:06 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Tue, 19 Jul 2011 07:35:16 +0200 (CEST)
Received: from mail-qy0-f177.google.com ([209.85.216.177]:50896 "EHLO
        mail-qy0-f177.google.com" rhost-flags-OK-OK-OK-OK)
        by eddie.linux-mips.org with ESMTP id S1490984Ab1GSFfG (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Tue, 19 Jul 2011 07:35:06 +0200
Received: by qyk7 with SMTP id 7so2185597qyk.15
        for <multiple recipients>; Mon, 18 Jul 2011 22:35:00 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=gmail.com; s=gamma;
        h=mime-version:in-reply-to:references:date:message-id:subject:from:to
         :cc:content-type;
        bh=gOtOjJE1F5JmkhBGiWm6ftmeOKqiwCMnAaGGC9nV7Ek=;
        b=mRKY3BeOwm8PMrtotbw4tEvZRMKXsKAnZA0unN5RSKTT85UTwFr5qtKXfDBa9MXW2+
         7+gZbT2YSmOPOCkaD2bopS3XUvOy3Oo9WSpmKV0QBAlUySbOwOX/oNkVPXl6DsH/3oPV
         D8ljEY6fPmHifLLOYY8Yo2r9To+JZBo0MXdpE=
MIME-Version: 1.0
Received: by 10.229.2.89 with SMTP id 25mr5500677qci.39.1311053700421; Mon, 18
 Jul 2011 22:35:00 -0700 (PDT)
Received: by 10.229.46.135 with HTTP; Mon, 18 Jul 2011 22:35:00 -0700 (PDT)
In-Reply-To: <201107162350.51025.rjw@sisk.pl>
References: <201107162350.51025.rjw@sisk.pl>
Date:   Tue, 19 Jul 2011 14:35:00 +0900
Message-ID: <CACBHAewP5twv0X=SOJw+Yb0HVvr7binRQ+VknSzh6=dVBPw_ww@mail.gmail.com>
Subject: Re: [GIT PULL] MIPS build fix related to power management for 3.0
From:   Yuasa Yoichi <tripeaks@gmail.com>
To:     "Rafael J. Wysocki" <rjw@sisk.pl>
Cc:     Linus Torvalds <torvalds@linux-foundation.org>,
        Ralf Baechle <ralf@linux-mips.org>, linux-mips@linux-mips.org,
        LKML <linux-kernel@vger.kernel.org>,
        Linux PM mailing list <linux-pm@lists.linux-foundation.org>
Content-Type: text/plain; charset=ISO-8859-1
X-archive-position: 30649
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: tripeaks@gmail.com
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 12948
Content-Length: 397
Lines: 15

Hi,

2011/7/17 Rafael J. Wysocki <rjw@sisk.pl>:
> Hi Linus,
>
> Please pull a MIPS build fix related to PM for 3.0 from:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/rafael/suspend-2.6.git pm-fixes
>
> It fixes a build regression resulting from a missing conversion from using
> a sysdev to using syscore_ops for PM/shutdown in the MIPS tree.

It has already been fixed in MIPS tree.

Yoichi

From sjhill@realitydiluted.com Wed Jul 20 04:04:00 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Wed, 20 Jul 2011 04:04:04 +0200 (CEST)
Received: from home.bethel-hill.org ([63.228.164.32]:38068 "EHLO
        guruplug.inter.net" rhost-flags-OK-OK-OK-FAIL) by eddie.linux-mips.org
        with ESMTP id S1491186Ab1GTCEA (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Wed, 20 Jul 2011 04:04:00 +0200
Received: from home.bethel-hill.org ([63.228.164.32] helo=[10.0.0.3])
        by guruplug.inter.net with esmtpsa (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32)
        (Exim 4.72)
        (envelope-from <sjhill@realitydiluted.com>)
        id 1QjM8e-0002d8-RD
        for linux-mips@linux-mips.org; Tue, 19 Jul 2011 21:03:52 -0500
Message-ID: <4E263781.8010909@realitydiluted.com>
Date:   Tue, 19 Jul 2011 21:03:45 -0500
From:   "Steven J. Hill" <sjhill@realitydiluted.com>
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.18) Gecko/20110617 Thunderbird/3.1.11
MIME-Version: 1.0
To:     linux-mips@linux-mips.org
Subject: SGI Reality Server archive.
X-Enigmail-Version: 1.1.2
Content-Type: multipart/signed; micalg=pgp-sha1;
 protocol="application/pgp-signature";
 boundary="------------enig2BA371F1F992DE1D12FEADC6"
X-archive-position: 30650
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: sjhill@realitydiluted.com
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 13683
Content-Length: 62855
Lines: 885

This is an OpenPGP/MIME signed message (RFC 2440 and 3156)
--------------enig2BA371F1F992DE1D12FEADC6
Content-Type: multipart/mixed;
 boundary="------------040103000500030006000003"

This is a multi-part message in MIME format.
--------------040103000500030006000003
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

Greetings.

Attached is a torrent of an archive I made of the SGI Reality Webserver
back around 2001. If you are a history buff and want to see a little of
what was going on at that time, have a look. It is 281MB in size.

-Steve

--------------040103000500030006000003
Content-Type: application/x-bittorrent;
 name="SGI-Reality.torrent"
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
 filename="SGI-Reality.torrent"

ZDg6YW5ub3VuY2U0MTpodHRwOi8vaW5mZXJuby5kZW1vbm9pZC5jb206MzM5Mi9hbm5vdW5j
ZTEzOmFubm91bmNlLWxpc3RsbDQxOmh0dHA6Ly9pbmZlcm5vLmRlbW9ub2lkLmNvbTozMzky
L2Fubm91bmNlNDI6aHR0cDovL3RyYWNrZXIub3BlbmJpdHRvcnJlbnQuY29tL2Fubm91bmNl
ZWU3OmNvbW1lbnQ0MzpBcmNoaXZlIG9mIFNHSSBSZWFsaXR5IFdlYnNlcnZlciBmcm9tIDIw
MDEuMTA6Y3JlYXRlZCBieTI1OlRyYW5zbWlzc2lvbi8yLjAzICgxMTAzMCkxMzpjcmVhdGlv
biBkYXRlaTEzMDk5ODU2ODRlODplbmNvZGluZzU6VVRGLTg0OmluZm9kNTpmaWxlc2xkNjps
ZW5ndGhpMjU5ZTQ6cGF0aGw2OlJFQURNRWVlZDY6bGVuZ3RoaTI5NDQ2OTgyN2U0OnBhdGhs
MzI6cmVhbGl0eS5zZ2kuY29tLTIwMDEwOTA2LnRhci5iejJlZWQ2Omxlbmd0aGk0NmU0OnBh
dGhsMzk6VG9ycmVudCBkb3dubG9hZGVkIGZyb20gRGVtb25vaWQubWUudHh0ZWVlNDpuYW1l
MTE6U0dJLVJlYWxpdHkxMjpwaWVjZSBsZW5ndGhpMTMxMDcyZTY6cGllY2VzNDQ5NDA6XiBy
myincBmGYr9ZgbmXmhZNFXHOUZTbZTHoXBBQId/MRawd9Rk9W/U/Oxj2BHlUA370/lQSPySF
0ioAfRN8dczg4TnpAek4PVWcsXAt72Xd6ktweCBZytIudp/mDJGNueWeleNSbFjFjc5Brm+k
+Sl4d8kz8Jtm3DnyWfra4u+evbpZpZ5C1Kkil9PcMNWDn82T/aUDD6bWFV7ey8Q80dhicBmN
m8KZQ9GQcX83291+rLB9eniAYqKibJY+a56ugD63PYSnBW3M5PKEM9i1FwhZrQFv6RAesgvU
i/BBybAiTLB9mI7gQfBnQhokrEmiLIpPEGMlCC26gdTYqtO/IXxJ2CM/fa8wscmIFMM+YXIw
KiddndgH6HJMyt2NAf7VHozbAZDlFam5IbcTTY8jdoCPkv8B8HBz8mqlGTwEhRLH3kBHTto5
gjbissF6KAcWhMaLf+ZBrBCwaDrqdrQrqqVgJwlMClun2ksNCm9NLOeORI0rstwyq6QQkWFW
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
tNJXREp/qULzNzpwcml2YXRlaTBlZWU=
--------------040103000500030006000003--

--------------enig2BA371F1F992DE1D12FEADC6
Content-Type: application/pgp-signature; name="signature.asc"
Content-Description: OpenPGP digital signature
Content-Disposition: attachment; filename="signature.asc"

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAk4mN4EACgkQgyK5H2Ic36depQCgi1FuL5x5qePuKszeI37DghPV
nH4An1YCv9RzFODJH0E0DIPl5YpqavZt
=NgzF
-----END PGP SIGNATURE-----

--------------enig2BA371F1F992DE1D12FEADC6--

From ralf@linux-mips.org Thu Jul 21 15:55:30 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 21 Jul 2011 15:55:38 +0200 (CEST)
Received: from h5.dl5rb.org.uk ([81.2.74.5]:36844 "EHLO linux-mips.org"
        rhost-flags-OK-OK-OK-FAIL) by eddie.linux-mips.org with ESMTP
        id S1491099Ab1GUNza (ORCPT <rfc822;linux-mips@linux-mips.org>);
        Thu, 21 Jul 2011 15:55:30 +0200
Received: from duck.linux-mips.net (duck.linux-mips.net [127.0.0.1])
        by duck.linux-mips.net (8.14.4/8.14.4) with ESMTP id p6LDtQKU000554;
        Thu, 21 Jul 2011 14:55:26 +0100
Received: (from ralf@localhost)
        by duck.linux-mips.net (8.14.4/8.14.4/Submit) id p6LDtPh1000551;
        Thu, 21 Jul 2011 14:55:25 +0100
Date:   Thu, 21 Jul 2011 14:55:25 +0100
From:   Ralf Baechle <ralf@linux-mips.org>
To:     David Daney <david.daney@cavium.com>
Cc:     linux-mips@linux-mips.org
Subject: Re: [PATCH 2/2 v2] MIPS: Close races in TLB modify handlers.
Message-ID: <20110721135525.GB27341@linux-mips.org>
References: <1309908886-1624-1-git-send-email-david.daney@cavium.com>
 <1309908886-1624-2-git-send-email-david.daney@cavium.com>
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
In-Reply-To: <1309908886-1624-2-git-send-email-david.daney@cavium.com>
User-Agent: Mutt/1.5.21 (2010-09-15)
X-archive-position: 30651
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ralf@linux-mips.org
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 15069
Content-Length: 1354
Lines: 32

On Tue, Jul 05, 2011 at 04:34:46PM -0700, David Daney wrote:

> Page table entries are made invalid by writing a zero into the the PTE
> slot in a page table.  This creates a race condition with the TLB
> modify handlers when they are updating the PTE.
> 
> CPU0                              CPU1
> 
> Test for _PAGE_PRESENT
> .                                 set to not _PAGE_PRESENT (zero)
> Set to _PAGE_VALID
> 
> So now the page not present value (zero) is suddenly valid and user
> space programs have access to physical page zero.
> 
> We close the race by putting the test for _PAGE_PRESENT and setting of
> _PAGE_VALID into an atomic LL/SC section.  This requires more
> registers than just K0 and K1 in the handlers, so we need to save some
> registers to a save area and then restore them when we are done.
> 
> The save area is an array of cacheline aligned structures that should
> not suffer cache line bouncing as they are CPU private.
> 
> Signed-off-by: David Daney <david.daney@cavium.com>

Looks good and nobody else has complained but backporting to <= 2.6.37 is
gonna be ugly.  I either have to resolve huge conflicts or alternatively
backport tons of other tlbex.c patches.  The latter is less risky and
time consuming and will provide additional benefit so I'll do it.  Just
be prepared for a storm on the linux-git list.

  Ralf

From manuel.lauss@googlemail.com Thu Jul 21 18:34:20 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 21 Jul 2011 18:34:26 +0200 (CEST)
Received: from mail-fx0-f49.google.com ([209.85.161.49]:44461 "EHLO
        mail-fx0-f49.google.com" rhost-flags-OK-OK-OK-OK)
        by eddie.linux-mips.org with ESMTP id S1491141Ab1GUQeU (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Thu, 21 Jul 2011 18:34:20 +0200
Received: by fxd20 with SMTP id 20so2711731fxd.36
        for <multiple recipients>; Thu, 21 Jul 2011 09:34:15 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=googlemail.com; s=gamma;
        h=from:to:cc:subject:date:message-id:x-mailer;
        bh=ckQSLqNQcXhGbA07ONgK71iCDeymrFLXaWCxtEkyBF4=;
        b=Cni00reMDPWoKaIavYrsIdM4KgLEBeGYLpo0jlzm32IXsEylCeGn5WOzA9bdrghpe7
         579qwDfJsgT9EhRHYkukiLJQXld06lT1P+NJFT0XgmLgvoz0VDhRRLvV1GIMpwVdCz7V
         4Y0m80451L8KrGft4T9EnDE22hmTyyQWHsUzw=
Received: by 10.223.160.144 with SMTP id n16mr533406fax.88.1311266055001;
        Thu, 21 Jul 2011 09:34:15 -0700 (PDT)
Received: from localhost.localdomain (188-22-154-193.adsl.highway.telekom.at [188.22.154.193])
        by mx.google.com with ESMTPS id j19sm1490495faa.41.2011.07.21.09.34.13
        (version=TLSv1/SSLv3 cipher=OTHER);
        Thu, 21 Jul 2011 09:34:13 -0700 (PDT)
From:   Manuel Lauss <manuel.lauss@googlemail.com>
To:     alsa-devel@vger.kernel.org
Cc:     Ralf Baechle <ralf@linux-mips.org>,
        Linux-MIPS <linux-mips@linux-mips.org>,
        Manuel Lauss <manuel.lauss@googlemail.com>
Subject: [PATCH V2 0/2] ALSA: ASoC for Au1000/1500/1100
Date:   Thu, 21 Jul 2011 18:34:08 +0200
Message-Id: <1311266050-22199-1-git-send-email-manuel.lauss@googlemail.com>
X-Mailer: git-send-email 1.7.6
X-archive-position: 30652
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: manuel.lauss@googlemail.com
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 15238
Content-Length: 1569
Lines: 39

Hello,

These 2 patches implement ASoC drivers for the AC97 and I2S
controllers found on early Alchemy chips.  They are largely
based on the old mips/au1x00.c driver which they replace.

AC97 Tested on a Db1500 development board; I2S untested since none
of the testboards I have actually have an I2S codec (just testpoints).

Changes since V1:
- added untested I2S controller driver for completeness, removed the audio
  defines from the au1000 header.

Manuel Lauss (2):
  ALSA: Alchemy AC97C/I2SC audio support
  ALSA: delete MIPS au1x00 driver

 arch/mips/alchemy/devboards/db1x00/platform.c |   37 ++
 arch/mips/include/asm/mach-au1x00/au1000.h    |   61 ---
 sound/mips/Kconfig                            |    8 -
 sound/mips/Makefile                           |    2 -
 sound/mips/au1x00.c                           |  695 -------------------------
 sound/soc/au1x/Kconfig                        |   28 +
 sound/soc/au1x/Makefile                       |   10 +
 sound/soc/au1x/ac97c.c                        |  398 ++++++++++++++
 sound/soc/au1x/db1000.c                       |   75 +++
 sound/soc/au1x/dma.c                          |  470 +++++++++++++++++
 sound/soc/au1x/i2sc.c                         |  353 +++++++++++++
 sound/soc/au1x/psc.h                          |   31 +-
 12 files changed, 1393 insertions(+), 775 deletions(-)
 delete mode 100644 sound/mips/au1x00.c
 create mode 100644 sound/soc/au1x/ac97c.c
 create mode 100644 sound/soc/au1x/db1000.c
 create mode 100644 sound/soc/au1x/dma.c
 create mode 100644 sound/soc/au1x/i2sc.c

-- 
1.7.6


From manuel.lauss@googlemail.com Thu Jul 21 18:34:22 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 21 Jul 2011 18:34:55 +0200 (CEST)
Received: from mail-fx0-f49.google.com ([209.85.161.49]:48430 "EHLO
        mail-fx0-f49.google.com" rhost-flags-OK-OK-OK-OK)
        by eddie.linux-mips.org with ESMTP id S1491144Ab1GUQeW (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Thu, 21 Jul 2011 18:34:22 +0200
Received: by fxd20 with SMTP id 20so2711768fxd.36
        for <multiple recipients>; Thu, 21 Jul 2011 09:34:17 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=googlemail.com; s=gamma;
        h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references;
        bh=0H+GzBgACGzw0DEicWYRrhg/bNvsLLUvqUHkG43fAgc=;
        b=ErjL/NZ7eodm5ewbnycf86R5dML+d7PGn74rOrPq5Y67yw+zbF4nE0U3+vA3qFO1Hd
         C/X/b/rd+O0tVvwyWi2DK4OSy0PHLzY7sFHv9gIGJG6dLMM2VmsdUj/mw68+1kJuq17k
         OwUMg8PEJGo/g4w9GLamghxVWZTxBM8a7AgrM=
Received: by 10.223.52.155 with SMTP id i27mr501350fag.139.1311266057542;
        Thu, 21 Jul 2011 09:34:17 -0700 (PDT)
Received: from localhost.localdomain (188-22-154-193.adsl.highway.telekom.at [188.22.154.193])
        by mx.google.com with ESMTPS id j19sm1490495faa.41.2011.07.21.09.34.15
        (version=TLSv1/SSLv3 cipher=OTHER);
        Thu, 21 Jul 2011 09:34:16 -0700 (PDT)
From:   Manuel Lauss <manuel.lauss@googlemail.com>
To:     alsa-devel@vger.kernel.org
Cc:     Ralf Baechle <ralf@linux-mips.org>,
        Linux-MIPS <linux-mips@linux-mips.org>,
        Manuel Lauss <manuel.lauss@googlemail.com>
Subject: [PATCH V2 1/2] ALSA: Alchemy AC97C/I2SC audio support
Date:   Thu, 21 Jul 2011 18:34:09 +0200
Message-Id: <1311266050-22199-2-git-send-email-manuel.lauss@googlemail.com>
X-Mailer: git-send-email 1.7.6
In-Reply-To: <1311266050-22199-1-git-send-email-manuel.lauss@googlemail.com>
References: <1311266050-22199-1-git-send-email-manuel.lauss@googlemail.com>
X-archive-position: 30653
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: manuel.lauss@googlemail.com
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 15239
Content-Length: 41546
Lines: 1617

This patch adds ASoC support for the AC97 and I2S controllers
on the old Au1000/Au1500/Au1100 chips and a universal machine
driver for the Db1000/Db1500/Db1100 boards.

AC97 Tested on a Db1500.  I2S untested since none of the boards
actually have and I2S codec wired up.

Signed-off-by: Manuel Lauss <manuel.lauss@googlemail.com>
---
V2: added untested I2S controller driver for completeness, removed the audio
    defines from the au1000 header as well.

 arch/mips/alchemy/devboards/db1x00/platform.c |   37 ++
 arch/mips/include/asm/mach-au1x00/au1000.h    |   61 ----
 sound/soc/au1x/Kconfig                        |   28 ++
 sound/soc/au1x/Makefile                       |   10 +
 sound/soc/au1x/ac97c.c                        |  398 +++++++++++++++++++++
 sound/soc/au1x/db1000.c                       |   75 ++++
 sound/soc/au1x/dma.c                          |  470 +++++++++++++++++++++++++
 sound/soc/au1x/i2sc.c                         |  353 +++++++++++++++++++
 sound/soc/au1x/psc.h                          |   31 ++-
 9 files changed, 1393 insertions(+), 70 deletions(-)
 create mode 100644 sound/soc/au1x/ac97c.c
 create mode 100644 sound/soc/au1x/db1000.c
 create mode 100644 sound/soc/au1x/dma.c
 create mode 100644 sound/soc/au1x/i2sc.c

diff --git a/arch/mips/alchemy/devboards/db1x00/platform.c b/arch/mips/alchemy/devboards/db1x00/platform.c
index 978d5ab..e2025ac 100644
--- a/arch/mips/alchemy/devboards/db1x00/platform.c
+++ b/arch/mips/alchemy/devboards/db1x00/platform.c
@@ -19,8 +19,11 @@
  */
 
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/platform_device.h>
 
+#include <asm/mach-au1x00/au1000.h>
+#include <asm/mach-au1x00/au1000_dma.h>
 #include <asm/mach-au1x00/au1xxx.h>
 #include <asm/mach-db1x00/bcsr.h>
 #include "../platform.h"
@@ -85,6 +88,36 @@
 #endif
 #endif
 
+static struct resource alchemy_ac97c_res[] = {
+	[0] = {
+		.start	= AU1000_AC97_PHYS_ADDR,
+		.end	= AU1000_AC97_PHYS_ADDR + 0xfff,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= DMA_ID_AC97C_TX,
+		.end	= DMA_ID_AC97C_TX,
+		.flags	= IORESOURCE_DMA,
+	},
+	[2] = {
+		.start	= DMA_ID_AC97C_RX,
+		.end	= DMA_ID_AC97C_RX,
+		.flags	= IORESOURCE_DMA,
+	},
+};
+
+static struct platform_device alchemy_ac97c_dev = {
+	.name		= "alchemy-ac97c",
+	.id		= -1,
+	.resource	= alchemy_ac97c_res,
+	.num_resources	= ARRAY_SIZE(alchemy_ac97c_res),
+};
+
+static struct platform_device db1x00_codec_dev = {
+	.name		= "ac97-codec",
+	.id		= -1,
+};
+
 static int __init db1xxx_dev_init(void)
 {
 #ifdef DB1XXX_HAS_PCMCIA
@@ -113,6 +146,10 @@ static int __init db1xxx_dev_init(void)
 				    1);
 #endif
 	db1x_register_norflash(BOARD_FLASH_SIZE, BOARD_FLASH_WIDTH, F_SWAPPED);
+
+	platform_device_register(&db1x00_codec_dev);
+	platform_device_register(&alchemy_ac97c_dev);
+
 	return 0;
 }
 device_initcall(db1xxx_dev_init);
diff --git a/arch/mips/include/asm/mach-au1x00/au1000.h b/arch/mips/include/asm/mach-au1x00/au1000.h
index f260ebe..6de3c43 100644
--- a/arch/mips/include/asm/mach-au1x00/au1000.h
+++ b/arch/mips/include/asm/mach-au1x00/au1000.h
@@ -927,36 +927,6 @@ enum soc_au1200_ints {
 #define SYS_RTCMATCH2		(SYS_BASE + 0x54)
 #define SYS_RTCREAD		(SYS_BASE + 0x58)
 
-/* I2S Controller */
-#define I2S_DATA		0xB1000000
-#  define I2S_DATA_MASK 	0xffffff
-#define I2S_CONFIG		0xB1000004
-#  define I2S_CONFIG_XU 	(1 << 25)
-#  define I2S_CONFIG_XO 	(1 << 24)
-#  define I2S_CONFIG_RU 	(1 << 23)
-#  define I2S_CONFIG_RO 	(1 << 22)
-#  define I2S_CONFIG_TR 	(1 << 21)
-#  define I2S_CONFIG_TE 	(1 << 20)
-#  define I2S_CONFIG_TF 	(1 << 19)
-#  define I2S_CONFIG_RR 	(1 << 18)
-#  define I2S_CONFIG_RE 	(1 << 17)
-#  define I2S_CONFIG_RF 	(1 << 16)
-#  define I2S_CONFIG_PD 	(1 << 11)
-#  define I2S_CONFIG_LB 	(1 << 10)
-#  define I2S_CONFIG_IC 	(1 << 9)
-#  define I2S_CONFIG_FM_BIT	7
-#  define I2S_CONFIG_FM_MASK	(0x3 << I2S_CONFIG_FM_BIT)
-#    define I2S_CONFIG_FM_I2S	(0x0 << I2S_CONFIG_FM_BIT)
-#    define I2S_CONFIG_FM_LJ	(0x1 << I2S_CONFIG_FM_BIT)
-#    define I2S_CONFIG_FM_RJ	(0x2 << I2S_CONFIG_FM_BIT)
-#  define I2S_CONFIG_TN 	(1 << 6)
-#  define I2S_CONFIG_RN 	(1 << 5)
-#  define I2S_CONFIG_SZ_BIT	0
-#  define I2S_CONFIG_SZ_MASK	(0x1F << I2S_CONFIG_SZ_BIT)
-
-#define I2S_CONTROL		0xB1000008
-#  define I2S_CONTROL_D 	(1 << 1)
-#  define I2S_CONTROL_CE	(1 << 0)
 
 /* USB Host Controller */
 #ifndef USB_OHCI_LEN
@@ -1436,37 +1406,6 @@ enum soc_au1200_ints {
 #define SYS_CPUPLL		0xB1900060
 #define SYS_AUXPLL		0xB1900064
 
-/* AC97 Controller */
-#define AC97C_CONFIG		0xB0000000
-#  define AC97C_RECV_SLOTS_BIT	13
-#  define AC97C_RECV_SLOTS_MASK (0x3ff << AC97C_RECV_SLOTS_BIT)
-#  define AC97C_XMIT_SLOTS_BIT	3
-#  define AC97C_XMIT_SLOTS_MASK (0x3ff << AC97C_XMIT_SLOTS_BIT)
-#  define AC97C_SG		(1 << 2)
-#  define AC97C_SYNC		(1 << 1)
-#  define AC97C_RESET		(1 << 0)
-#define AC97C_STATUS		0xB0000004
-#  define AC97C_XU		(1 << 11)
-#  define AC97C_XO		(1 << 10)
-#  define AC97C_RU		(1 << 9)
-#  define AC97C_RO		(1 << 8)
-#  define AC97C_READY		(1 << 7)
-#  define AC97C_CP		(1 << 6)
-#  define AC97C_TR		(1 << 5)
-#  define AC97C_TE		(1 << 4)
-#  define AC97C_TF		(1 << 3)
-#  define AC97C_RR		(1 << 2)
-#  define AC97C_RE		(1 << 1)
-#  define AC97C_RF		(1 << 0)
-#define AC97C_DATA		0xB0000008
-#define AC97C_CMD		0xB000000C
-#  define AC97C_WD_BIT		16
-#  define AC97C_READ		(1 << 7)
-#  define AC97C_INDEX_MASK	0x7f
-#define AC97C_CNTRL		0xB0000010
-#  define AC97C_RS		(1 << 1)
-#  define AC97C_CE		(1 << 0)
-
 #if defined(CONFIG_SOC_AU1500) || defined(CONFIG_SOC_AU1550)
 /* Au1500 PCI Controller */
 #define Au1500_CFG_BASE 	0xB4005000	/* virtual, KSEG1 addr */
diff --git a/sound/soc/au1x/Kconfig b/sound/soc/au1x/Kconfig
index 4b67140..6d59254 100644
--- a/sound/soc/au1x/Kconfig
+++ b/sound/soc/au1x/Kconfig
@@ -18,10 +18,38 @@ config SND_SOC_AU1XPSC_AC97
 	select SND_AC97_CODEC
 	select SND_SOC_AC97_BUS
 
+##
+## Au1000/1500/1100 DMA + AC97C/I2SC
+##
+config SND_SOC_AU1XAUDIO
+	tristate "SoC Audio for Au1000/Au1500/Au1100"
+	depends on MIPS_ALCHEMY
+	help
+	  This is a driver set for the AC97 unit and the
+	  old DMA controller as found on the Au1000/Au1500/Au1100 chips.
+
+config SND_SOC_AU1XAC97C
+	tristate
+	select AC97_BUS
+	select SND_AC97_CODEC
+	select SND_SOC_AC97_BUS
+
+config SND_SOC_AU1XI2SC
+	tristate
+
 
 ##
 ## Boards
 ##
+config SND_SOC_DB1000
+	tristate "DB1000 Audio support"
+	depends on SND_SOC_AU1XAUDIO
+	select SND_SOC_AU1XAC97C
+	select SND_SOC_AC97_CODEC
+	help
+	  Select this option to enable AC97 audio on the early DB1x00 series
+	  of boards (DB1000/DB1500/DB1100).
+
 config SND_SOC_DB1200
 	tristate "DB1200 AC97+I2S audio support"
 	depends on SND_SOC_AU1XPSC
diff --git a/sound/soc/au1x/Makefile b/sound/soc/au1x/Makefile
index 1687307..9207105 100644
--- a/sound/soc/au1x/Makefile
+++ b/sound/soc/au1x/Makefile
@@ -3,11 +3,21 @@ snd-soc-au1xpsc-dbdma-objs := dbdma2.o
 snd-soc-au1xpsc-i2s-objs := psc-i2s.o
 snd-soc-au1xpsc-ac97-objs := psc-ac97.o
 
+# Au1000/1500/1100 Audio units
+snd-soc-au1x-dma-objs := dma.o
+snd-soc-au1x-ac97c-objs := ac97c.o
+snd-soc-au1x-i2sc-objs := i2sc.o
+
 obj-$(CONFIG_SND_SOC_AU1XPSC) += snd-soc-au1xpsc-dbdma.o
 obj-$(CONFIG_SND_SOC_AU1XPSC_I2S) += snd-soc-au1xpsc-i2s.o
 obj-$(CONFIG_SND_SOC_AU1XPSC_AC97) += snd-soc-au1xpsc-ac97.o
+obj-$(CONFIG_SND_SOC_AU1XAUDIO) += snd-soc-au1x-dma.o
+obj-$(CONFIG_SND_SOC_AU1XAC97C) += snd-soc-au1x-ac97c.o
+obj-$(CONFIG_SND_SOC_AU1XI2SC) += snd-soc-au1x-i2sc.o
 
 # Boards
+snd-soc-db1000-objs := db1000.o
 snd-soc-db1200-objs := db1200.o
 
+obj-$(CONFIG_SND_SOC_DB1000) += snd-soc-db1000.o
 obj-$(CONFIG_SND_SOC_DB1200) += snd-soc-db1200.o
diff --git a/sound/soc/au1x/ac97c.c b/sound/soc/au1x/ac97c.c
new file mode 100644
index 0000000..8fc25d0
--- /dev/null
+++ b/sound/soc/au1x/ac97c.c
@@ -0,0 +1,398 @@
+/*
+ * Au1000/Au1500/Au1100 AC97C controller driver for ASoC
+ *
+ * (c) 2011 Manuel Lauss <manuel.lauss@googlemail.com>
+ *
+ * based on the old ALSA driver by Charles Eidsness.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/suspend.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <asm/mach-au1x00/au1000.h>
+#include <asm/mach-au1x00/au1xxx_psc.h>
+
+#include "psc.h"
+
+/*#define AC_DEBUG*/
+
+#define MSG(x...)	printk(KERN_ERR "ac97c: " x)
+#ifdef AC_DEBUG
+#define DBG(x...)	MSG(x)
+#else
+#define DBG(x...)	do {} while (0)
+#endif
+
+/* register offsets and bits */
+#define AC97_CONFIG	0x00
+#define AC97_STATUS	0x04
+#define AC97_DATA	0x08
+#define AC97_CMDRESP	0x0c
+#define AC97_ENABLE	0x10
+
+#define CFG_RC(x)	(((x) & 0x3ff) << 13)
+#define CFG_XS(x)	(((x) & 0x3ff) << 3)
+#define CFG_SG		(1 << 2)	/* sync gate */
+#define CFG_SN		(1 << 1)	/* sync control */
+#define CFG_RS		(1 << 0)	/* acrst# control */
+#define STAT_XU		(1 << 11)	/* tx underflow */
+#define STAT_XO		(1 << 10)	/* tx overflow */
+#define STAT_RU		(1 << 9)	/* rx underflow */
+#define STAT_RO		(1 << 8)	/* rx overflow */
+#define STAT_RD		(1 << 7)	/* codec ready */
+#define STAT_CP		(1 << 6)	/* command pending */
+#define STAT_TE		(1 << 4)	/* tx fifo empty */
+#define STAT_TF		(1 << 3)	/* tx fifo full */
+#define STAT_RE		(1 << 1)	/* rx fifo empty */
+#define STAT_RF		(1 << 0)	/* rx fifo full */
+#define CMD_SET_DATA(x)	(((x) & 0xffff) << 16)
+#define CMD_GET_DATA(x)	((x) & 0xffff)
+#define CMD_READ	(1 << 7)
+#define CMD_WRITE	(0 << 7)
+#define CMD_IDX(x)	((x) & 0x7f)
+#define EN_D		(1 << 1)	/* DISable bit */
+#define EN_CE		(1 << 0)	/* clock enable bit */
+
+/* how often to retry failed codec register reads/writes */
+#define AC97_RW_RETRIES	5
+
+#define AC97_DIR	\
+	(SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE)
+
+#define AC97_RATES	\
+	SNDRV_PCM_RATE_8000_44100
+
+#define AC97_FMTS	\
+	SNDRV_PCM_FMTBIT_S16_LE
+
+struct ac97c_ctx {
+	void __iomem *mmio;
+
+	unsigned long cfg;
+
+	struct mutex lock;	/* codec access lock */
+
+	struct platform_device *dmapd;
+};
+
+/* instance data. There can be only one, MacLeod!!!!, fortunately there IS only
+ * once AC97C on early Alchemy chips.
+ */
+static struct ac97c_ctx *ac97c_workdata;
+
+
+#define ac97_to_ctx(x)		ac97c_workdata
+
+static inline unsigned long RD(struct ac97c_ctx *ctx, int reg)
+{
+	return __raw_readl(ctx->mmio + reg);
+}
+
+static inline void WR(struct ac97c_ctx *ctx, int reg, unsigned long v)
+{
+	__raw_writel(v, ctx->mmio + reg);
+	wmb();
+}
+
+static unsigned short au1xac97c_ac97_read(struct snd_ac97 *ac97,
+					  unsigned short r)
+{
+	struct ac97c_ctx *ctx = ac97_to_ctx(ac97);
+	unsigned int tmo, retry;
+	unsigned long data;
+
+	data = ~0;
+	retry = AC97_RW_RETRIES;
+	do {
+		mutex_lock(&ctx->lock);
+
+		tmo = 5;
+		while ((RD(ctx, AC97_STATUS) & STAT_CP) && tmo--)
+			udelay(21);	/* wait an ac97 frame time */
+		if (!tmo) {
+			DBG("ac97rd timeout #1\n");
+			goto next;
+		}
+
+		WR(ctx, AC97_CMDRESP, CMD_IDX(r) | CMD_READ);
+
+		/* stupid errata: data is only valid for 21us, so
+		 * poll, forrest, poll...
+		 */
+		tmo = 0x10000;
+		while ((RD(ctx, AC97_STATUS) & STAT_CP) && tmo--)
+			asm volatile ("nop");
+		data = RD(ctx, AC97_CMDRESP);
+
+		if (!tmo)
+			DBG("ac97rd timeout #2\n");
+
+next:
+		mutex_unlock(&ctx->lock);
+	} while (--retry && !tmo);
+
+	DBG("AC97RD %04x %04lx %d\n", r, data, retry);
+
+	return retry ? data & 0xffff : 0xffff;
+}
+
+static void au1xac97c_ac97_write(struct snd_ac97 *ac97, unsigned short r,
+				 unsigned short v)
+{
+	struct ac97c_ctx *ctx = ac97_to_ctx(ac97);
+	unsigned int tmo, retry;
+
+	retry = AC97_RW_RETRIES;
+	do {
+		mutex_lock(&ctx->lock);
+
+		for (tmo = 5; (RD(ctx, AC97_STATUS) & STAT_CP) && tmo; tmo--)
+			udelay(21);	/* wait an ac97 frame time */
+		if (!tmo) {
+			DBG("ac97wr timeout #1\n");
+			goto next;
+		}
+
+		WR(ctx, AC97_CMDRESP, CMD_WRITE | CMD_IDX(r) | CMD_SET_DATA(v));
+
+		for (tmo = 10; (RD(ctx, AC97_STATUS) & STAT_CP) && tmo; tmo--)
+			udelay(21);	/* wait an ac97 frame time */
+		if (!tmo)
+			DBG("ac97wr timeout #2\n");
+next:
+		mutex_unlock(&ctx->lock);
+	} while (--retry && !tmo);
+
+	DBG("AC97WR %04x %04x %d\n", r, v, retry);
+}
+
+static void au1xac97c_ac97_warm_reset(struct snd_ac97 *ac97)
+{
+	struct ac97c_ctx *ctx = ac97_to_ctx(ac97);
+
+	DBG("entering WARM_RESET\n");
+
+	WR(ctx, AC97_CONFIG, ctx->cfg | CFG_SG | CFG_SN);
+	msleep(20);
+	WR(ctx, AC97_CONFIG, ctx->cfg | CFG_SG);
+	WR(ctx, AC97_CONFIG, ctx->cfg);
+
+	DBG("leaving WARM_RESET\n");
+}
+
+static void au1xac97c_ac97_cold_reset(struct snd_ac97 *ac97)
+{
+	struct ac97c_ctx *ctx = ac97_to_ctx(ac97);
+	int i;
+
+	DBG("entering COLD_RESET\n");
+
+	WR(ctx, AC97_CONFIG, ctx->cfg | CFG_RS);
+	msleep(500);
+	WR(ctx, AC97_CONFIG, ctx->cfg);
+
+	/* wait for codec ready */
+	i = 1000;
+	while (((RD(ctx, AC97_STATUS) & STAT_RD) == 0) && --i)
+		msleep(20);
+	if (!i)
+		printk(KERN_ERR "ac97c: codec not ready\n");
+
+	DBG("leaving COLD_RESET\n");
+}
+
+/* AC97 controller operations */
+struct snd_ac97_bus_ops soc_ac97_ops = {
+	.read		= au1xac97c_ac97_read,
+	.write		= au1xac97c_ac97_write,
+	.reset		= au1xac97c_ac97_cold_reset,
+	.warm_reset	= au1xac97c_ac97_warm_reset,
+};
+EXPORT_SYMBOL_GPL(soc_ac97_ops);
+
+static int au1xac97c_hw_params(struct snd_pcm_substream *substream,
+			       struct snd_pcm_hw_params *params,
+			       struct snd_soc_dai *dai)
+{
+	return 0;
+}
+
+static int au1xac97c_trigger(struct snd_pcm_substream *substream,
+			     int cmd, struct snd_soc_dai *dai)
+{
+	return 0;
+}
+
+static int au1xac97c_dai_probe(struct snd_soc_dai *dai)
+{
+	return ac97c_workdata ? 0 : -ENODEV;
+}
+
+static struct snd_soc_dai_ops au1xac97c_dai_ops = {
+	.trigger	= au1xac97c_trigger,
+	.hw_params	= au1xac97c_hw_params,
+};
+
+static struct snd_soc_dai_driver au1xac97c_dai_driver = {
+	.name			= AC97C_DAINAME,
+	.ac97_control		= 1,
+	.probe			= au1xac97c_dai_probe,
+	.playback = {
+		.rates		= AC97_RATES,
+		.formats	= AC97_FMTS,
+		.channels_min	= 2,
+		.channels_max	= 2,
+	},
+	.capture = {
+		.rates		= AC97_RATES,
+		.formats	= AC97_FMTS,
+		.channels_min	= 2,
+		.channels_max	= 2,
+	},
+	.ops = &au1xac97c_dai_ops,
+};
+
+static int __devinit au1xac97c_drvprobe(struct platform_device *pdev)
+{
+	int ret;
+	struct resource *r;
+	struct ac97c_ctx *ctx;
+
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	mutex_init(&ctx->lock);
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!r) {
+		ret = -ENODEV;
+		goto out0;
+	}
+
+	ret = -EBUSY;
+	if (!request_mem_region(r->start, resource_size(r), pdev->name))
+		goto out0;
+
+	ctx->mmio = ioremap_nocache(r->start, resource_size(r));
+	if (!ctx->mmio)
+		goto out1;
+
+	/* switch it on */
+	WR(ctx, AC97_ENABLE, EN_D | EN_CE);
+	WR(ctx, AC97_ENABLE, EN_CE);
+
+	ctx->cfg = CFG_RC(3) | CFG_XS(3);
+	WR(ctx, AC97_CONFIG, ctx->cfg);
+
+	platform_set_drvdata(pdev, ctx);
+
+	ret = snd_soc_register_dai(&pdev->dev, &au1xac97c_dai_driver);
+	if (ret)
+		goto out1;
+
+	ctx->dmapd = alchemy_pcm_add(pdev, 0);	/* 0 == AC97 */
+	if (ctx->dmapd) {
+		ac97c_workdata = ctx;
+		return 0;
+	}
+
+	snd_soc_unregister_dai(&pdev->dev);
+out1:
+	release_mem_region(r->start, resource_size(r));
+out0:
+	kfree(ctx);
+	return ret;
+}
+
+static int __devexit au1xac97c_drvremove(struct platform_device *pdev)
+{
+	struct ac97c_ctx *ctx = platform_get_drvdata(pdev);
+	struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	if (ctx->dmapd)
+		alchemy_pcm_destroy(ctx->dmapd);
+
+	snd_soc_unregister_dai(&pdev->dev);
+
+	WR(ctx, AC97_ENABLE, EN_D);	/* clock off, disable */
+
+	iounmap(ctx->mmio);
+	release_mem_region(r->start, resource_size(r));
+	kfree(ctx);
+
+	ac97c_workdata = NULL;	/* MDEV */
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int au1xac97c_drvsuspend(struct device *dev)
+{
+	struct ac97c_ctx *ctx = dev_get_drvdata(dev);
+
+	WR(ctx, AC97_ENABLE, EN_D);	/* clock off, disable */
+
+	return 0;
+}
+
+static int au1xac97c_drvresume(struct device *dev)
+{
+	struct ac97c_ctx *ctx = dev_get_drvdata(dev);
+
+	WR(ctx, AC97_ENABLE, EN_D | EN_CE);
+	WR(ctx, AC97_ENABLE, EN_CE);
+	WR(ctx, AC97_CONFIG, ctx->cfg);
+
+	return 0;
+}
+
+static const struct dev_pm_ops au1xpscac97_pmops = {
+	.suspend	= au1xac97c_drvsuspend,
+	.resume		= au1xac97c_drvresume,
+};
+
+#define AU1XPSCAC97_PMOPS (&au1xpscac97_pmops)
+
+#else
+
+#define AU1XPSCAC97_PMOPS NULL
+
+#endif
+
+static struct platform_driver au1xac97c_driver = {
+	.driver	= {
+		.name	= "alchemy-ac97c",
+		.owner	= THIS_MODULE,
+		.pm	= AU1XPSCAC97_PMOPS,
+	},
+	.probe		= au1xac97c_drvprobe,
+	.remove		= __devexit_p(au1xac97c_drvremove),
+};
+
+static int __init au1xac97c_load(void)
+{
+	ac97c_workdata = NULL;
+	return platform_driver_register(&au1xac97c_driver);
+}
+
+static void __exit au1xac97c_unload(void)
+{
+	platform_driver_unregister(&au1xac97c_driver);
+}
+
+module_init(au1xac97c_load);
+module_exit(au1xac97c_unload);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Au1000/1500/1100 AC97C ALSA ASoC audio driver");
+MODULE_AUTHOR("Manuel Lauss");
diff --git a/sound/soc/au1x/db1000.c b/sound/soc/au1x/db1000.c
new file mode 100644
index 0000000..9368b5d
--- /dev/null
+++ b/sound/soc/au1x/db1000.c
@@ -0,0 +1,75 @@
+/*
+ * DB1000/DB1500/DB1100 ASoC audio fabric support code.
+ *
+ * (c) 2011 Manuel Lauss <manuel.lauss@googlemail.com>
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <asm/mach-au1x00/au1000.h>
+#include <asm/mach-db1x00/bcsr.h>
+
+#include "psc.h"
+
+/*-------------------------  AC97 PART  ---------------------------*/
+
+static struct snd_soc_dai_link db1000_ac97_dai = {
+	.name		= "AC97",
+	.stream_name	= "AC97 HiFi",
+	.codec_dai_name	= "ac97-hifi",
+	.cpu_dai_name	= AC97C_DAINAME,
+	.platform_name	= AC97C_DMANAME,
+	.codec_name	= "ac97-codec",
+};
+
+static struct snd_soc_card db1000_ac97_machine = {
+	.name		= "DB1000_AC97",
+	.dai_link	= &db1000_ac97_dai,
+	.num_links	= 1,
+};
+
+/*-------------------------  COMMON PART  ---------------------------*/
+
+static struct platform_device *db1000_asoc97_dev;
+
+static int __init db1000_audio_load(void)
+{
+	int ret, id;
+
+	/* impostor check */
+	id = BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI));
+
+	ret = -ENOMEM;
+	db1000_asoc97_dev = platform_device_alloc("soc-audio", 0);
+	if (!db1000_asoc97_dev)
+		goto out;
+
+	platform_set_drvdata(db1000_asoc97_dev, &db1000_ac97_machine);
+	ret = platform_device_add(db1000_asoc97_dev);
+
+	if (ret) {
+		platform_device_put(db1000_asoc97_dev);
+		db1000_asoc97_dev = NULL;
+	}
+out:
+	return ret;
+}
+
+static void __exit db1000_audio_unload(void)
+{
+	platform_device_unregister(db1000_asoc97_dev);
+}
+
+module_init(db1000_audio_load);
+module_exit(db1000_audio_unload);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("DB1000/DB1500/DB1100 ASoC audio support");
+MODULE_AUTHOR("Manuel Lauss");
diff --git a/sound/soc/au1x/dma.c b/sound/soc/au1x/dma.c
new file mode 100644
index 0000000..0f7d90a
--- /dev/null
+++ b/sound/soc/au1x/dma.c
@@ -0,0 +1,470 @@
+/*
+ * Au1000/Au1500/Au1100 Audio DMA support.
+ *
+ * (c) 2011 Manuel Lauss <manuel.lauss@googlemail.com>
+ *
+ * copied almost verbatim from the old ALSA driver, written by
+ *			Charles Eidsness <charles@cooper-street.com>
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <asm/mach-au1x00/au1000.h>
+#include <asm/mach-au1x00/au1000_dma.h>
+
+#include "psc.h"
+
+/*#define PCM_DEBUG*/
+
+#define MSG(x...)	printk(KERN_INFO "alchemy-pcm: " x)
+#ifdef PCM_DEBUG
+#define DBG(x...)		MSG(x)
+#else
+#define DBG(x...)	do {} while (0)
+#endif
+
+#define ALCHEMY_PCM_FMTS					\
+	(SNDRV_PCM_FMTBIT_S8     | SNDRV_PCM_FMTBIT_U8 |	\
+	 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |	\
+	 SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE |	\
+	 SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE |	\
+	 SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_U32_BE |	\
+	 0)
+
+
+struct pcm_period {
+	u32 start;
+	u32 relative_end;	/* relative to start of buffer */
+	struct pcm_period *next;
+};
+
+struct audio_stream {
+	struct snd_pcm_substream *substream;
+	int dma;
+	struct pcm_period *buffer;
+	unsigned int period_size;
+	unsigned int periods;
+};
+
+struct alchemy_pcm_ctx {
+	struct audio_stream stream[2];	/* playback & capture */
+};
+
+static void au1000_release_dma_link(struct audio_stream *stream)
+{
+	struct pcm_period *pointer;
+	struct pcm_period *pointer_next;
+
+	stream->period_size = 0;
+	stream->periods = 0;
+	pointer = stream->buffer;
+	if (!pointer)
+		return;
+	do {
+		pointer_next = pointer->next;
+		kfree(pointer);
+		pointer = pointer_next;
+	} while (pointer != stream->buffer);
+	stream->buffer = NULL;
+}
+
+static int au1000_setup_dma_link(struct audio_stream *stream,
+				 unsigned int period_bytes,
+				 unsigned int periods)
+{
+	struct snd_pcm_substream *substream = stream->substream;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct pcm_period *pointer;
+	unsigned long dma_start;
+	int i;
+
+	dma_start = virt_to_phys(runtime->dma_area);
+
+	if (stream->period_size == period_bytes &&
+	    stream->periods == periods)
+		return 0; /* not changed */
+
+	au1000_release_dma_link(stream);
+
+	stream->period_size = period_bytes;
+	stream->periods = periods;
+
+	stream->buffer = kmalloc(sizeof(struct pcm_period), GFP_KERNEL);
+	if (!stream->buffer)
+		return -ENOMEM;
+	pointer = stream->buffer;
+	for (i = 0; i < periods; i++) {
+		pointer->start = (u32)(dma_start + (i * period_bytes));
+		pointer->relative_end = (u32) (((i+1) * period_bytes) - 0x1);
+		if (i < periods - 1) {
+			pointer->next = kmalloc(sizeof(struct pcm_period),
+						GFP_KERNEL);
+			if (!pointer->next) {
+				au1000_release_dma_link(stream);
+				return -ENOMEM;
+			}
+			pointer = pointer->next;
+		}
+	}
+	pointer->next = stream->buffer;
+	return 0;
+}
+
+static void au1000_dma_stop(struct audio_stream *stream)
+{
+	if (stream->buffer)
+		disable_dma(stream->dma);
+}
+
+static void au1000_dma_start(struct audio_stream *stream)
+{
+	if (!stream->buffer)
+		return;
+
+	init_dma(stream->dma);
+	if (get_dma_active_buffer(stream->dma) == 0) {
+		clear_dma_done0(stream->dma);
+		set_dma_addr0(stream->dma, stream->buffer->start);
+		set_dma_count0(stream->dma, stream->period_size >> 1);
+		set_dma_addr1(stream->dma, stream->buffer->next->start);
+		set_dma_count1(stream->dma, stream->period_size >> 1);
+	} else {
+		clear_dma_done1(stream->dma);
+		set_dma_addr1(stream->dma, stream->buffer->start);
+		set_dma_count1(stream->dma, stream->period_size >> 1);
+		set_dma_addr0(stream->dma, stream->buffer->next->start);
+		set_dma_count0(stream->dma, stream->period_size >> 1);
+	}
+	enable_dma_buffers(stream->dma);
+	start_dma(stream->dma);
+}
+
+static irqreturn_t au1000_dma_interrupt(int irq, void *ptr)
+{
+	struct audio_stream *stream = (struct audio_stream *)ptr;
+	struct snd_pcm_substream *substream = stream->substream;
+
+	switch (get_dma_buffer_done(stream->dma)) {
+	case DMA_D0:
+		stream->buffer = stream->buffer->next;
+		clear_dma_done0(stream->dma);
+		set_dma_addr0(stream->dma, stream->buffer->next->start);
+		set_dma_count0(stream->dma, stream->period_size >> 1);
+		enable_dma_buffer0(stream->dma);
+		break;
+	case DMA_D1:
+		stream->buffer = stream->buffer->next;
+		clear_dma_done1(stream->dma);
+		set_dma_addr1(stream->dma, stream->buffer->next->start);
+		set_dma_count1(stream->dma, stream->period_size >> 1);
+		enable_dma_buffer1(stream->dma);
+		break;
+	case (DMA_D0 | DMA_D1):
+		DBG("DMA %d missed interrupt.\n", stream->dma);
+		au1000_dma_stop(stream);
+		au1000_dma_start(stream);
+		break;
+	case (~DMA_D0 & ~DMA_D1):
+		DBG("DMA %d empty irq.\n", stream->dma);
+	}
+	snd_pcm_period_elapsed(substream);
+	return IRQ_HANDLED;
+}
+
+static const struct snd_pcm_hardware alchemy_pcm_hardware = {
+	.info		  = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
+			    SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BATCH,
+	.formats	  = ALCHEMY_PCM_FMTS,
+	.rates		  = SNDRV_PCM_RATE_8000_192000,
+	.rate_min	  = SNDRV_PCM_RATE_8000,
+	.rate_max	  = SNDRV_PCM_RATE_192000,
+	.channels_min	  = 2,
+	.channels_max	  = 2,
+	.period_bytes_min = 1024,
+	.period_bytes_max = 16 * 1024 - 1,
+	.periods_min	  = 4,
+	.periods_max	  = 255,
+	.buffer_bytes_max = 128 * 1024,
+	.fifo_size	  = 16,
+};
+
+static inline struct alchemy_pcm_ctx *ss_to_ctx(struct snd_pcm_substream *ss)
+{
+	struct snd_soc_pcm_runtime *rtd = ss->private_data;
+	return snd_soc_platform_get_drvdata(rtd->platform);
+}
+
+static inline struct audio_stream *ss_to_as(struct snd_pcm_substream *ss)
+{
+	struct alchemy_pcm_ctx *ctx = ss_to_ctx(ss);
+	return &(ctx->stream[SUBSTREAM_TYPE(ss)]);
+}
+
+static int alchemy_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct alchemy_pcm_ctx *ctx = ss_to_ctx(substream);
+	int stype = SUBSTREAM_TYPE(substream);
+
+	ctx->stream[stype].substream = substream;
+	ctx->stream[stype].buffer = NULL;
+	snd_soc_set_runtime_hwparams(substream, &alchemy_pcm_hardware);
+
+	return 0;
+}
+
+static int alchemy_pcm_close(struct snd_pcm_substream *substream)
+{
+	struct alchemy_pcm_ctx *ctx = ss_to_ctx(substream);
+
+	ctx->stream[SUBSTREAM_TYPE(substream)].substream = NULL;
+
+	return 0;
+}
+
+static int alchemy_pcm_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *hw_params)
+{
+	struct audio_stream *stream = ss_to_as(substream);
+	int err;
+
+	err = snd_pcm_lib_malloc_pages(substream,
+				       params_buffer_bytes(hw_params));
+	if (err < 0)
+		return err;
+	return au1000_setup_dma_link(stream,
+				     params_period_bytes(hw_params),
+				     params_periods(hw_params));
+}
+
+static int alchemy_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	struct audio_stream *stream = ss_to_as(substream);
+	au1000_release_dma_link(stream);
+	return snd_pcm_lib_free_pages(substream);
+}
+
+static int alchemy_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct audio_stream *stream = ss_to_as(substream);
+	int err = 0;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		au1000_dma_start(stream);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		au1000_dma_stop(stream);
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+	return err;
+}
+
+static snd_pcm_uframes_t alchemy_pcm_pointer(struct snd_pcm_substream *ss)
+{
+	struct audio_stream *stream = ss_to_as(ss);
+	long location;
+
+	location = get_dma_residue(stream->dma);
+	location = stream->buffer->relative_end - location;
+	if (location == -1)
+		location = 0;
+	return bytes_to_frames(ss->runtime, location);
+}
+
+static struct snd_pcm_ops alchemy_pcm_ops = {
+	.open			= alchemy_pcm_open,
+	.close			= alchemy_pcm_close,
+	.ioctl			= snd_pcm_lib_ioctl,
+	.hw_params	        = alchemy_pcm_hw_params,
+	.hw_free	        = alchemy_pcm_hw_free,
+	.trigger		= alchemy_pcm_trigger,
+	.pointer		= alchemy_pcm_pointer,
+};
+
+static void alchemy_pcm_free_dma_buffers(struct snd_pcm *pcm)
+{
+	snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+static int alchemy_pcm_new(struct snd_card *card,
+			   struct snd_soc_dai *dai,
+			   struct snd_pcm *pcm)
+{
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
+		snd_dma_continuous_data(GFP_KERNEL), 65536, (4096 * 1024) - 1);
+
+	return 0;
+}
+
+struct snd_soc_platform_driver alchemy_pcm_soc_platform = {
+	.ops		= &alchemy_pcm_ops,
+	.pcm_new	= alchemy_pcm_new,
+	.pcm_free	= alchemy_pcm_free_dma_buffers,
+};
+
+
+static int __devinit alchemy_pcm_drvprobe(struct platform_device *pdev)
+{
+	struct alchemy_pcm_ctx *ctx;
+	struct resource *r;
+	int ret;
+
+	DBG("probing %s\n", pdev->name);
+
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+	if (!r) {
+		ret = -ENODEV;
+		goto out1;
+	}
+	ctx->stream[PCM_TX].dma = request_au1000_dma(r->start, "audio-tx",
+					au1000_dma_interrupt, IRQF_DISABLED,
+					&ctx->stream[PCM_TX]);
+	set_dma_mode(ctx->stream[PCM_TX].dma,
+		     get_dma_mode(ctx->stream[PCM_TX].dma) & ~DMA_NC);
+
+	/* RX DMA */
+	r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+	if (!r) {
+		ret = -ENODEV;
+		goto out2;
+	}
+	ctx->stream[PCM_RX].dma = request_au1000_dma(r->start, "audio-rx",
+					au1000_dma_interrupt, IRQF_DISABLED,
+					&ctx->stream[PCM_RX]);
+	set_dma_mode(ctx->stream[PCM_RX].dma,
+		     get_dma_mode(ctx->stream[PCM_RX].dma) & ~DMA_NC);
+
+	DBG("DMA: %d %d\n", ctx->stream[PCM_TX].dma, ctx->stream[PCM_RX].dma);
+
+	platform_set_drvdata(pdev, ctx);
+
+	ret = snd_soc_register_platform(&pdev->dev, &alchemy_pcm_soc_platform);
+	if (!ret)
+		return ret;
+
+	free_au1000_dma(ctx->stream[PCM_RX].dma);
+out2:
+	free_au1000_dma(ctx->stream[PCM_TX].dma);
+out1:
+	kfree(ctx);
+	DBG("bailing out\n");
+	return ret;
+}
+
+static int __devexit alchemy_pcm_drvremove(struct platform_device *pdev)
+{
+	struct alchemy_pcm_ctx *ctx = platform_get_drvdata(pdev);
+
+	free_au1000_dma(ctx->stream[PCM_RX].dma);
+	free_au1000_dma(ctx->stream[PCM_TX].dma);
+
+	kfree(ctx);
+	snd_soc_unregister_platform(&pdev->dev);
+
+	return 0;
+}
+
+static struct platform_driver alchemy_ac97pcm_driver = {
+	.driver	= {
+		.name	= AC97C_DMANAME,
+		.owner	= THIS_MODULE,
+	},
+	.probe		= alchemy_pcm_drvprobe,
+	.remove		= __devexit_p(alchemy_pcm_drvremove),
+};
+
+static struct platform_driver alchemy_i2spcm_driver = {
+	.driver	= {
+		.name	= I2SC_DMANAME,
+		.owner	= THIS_MODULE,
+	},
+	.probe		= alchemy_pcm_drvprobe,
+	.remove		= __devexit_p(alchemy_pcm_drvremove),
+};
+
+static int __init alchemy_audio_dma_load(void)
+{
+	(void)platform_driver_register(&alchemy_i2spcm_driver);
+	return platform_driver_register(&alchemy_ac97pcm_driver);
+}
+
+static void __exit alchemy_audio_dma_unload(void)
+{
+	platform_driver_unregister(&alchemy_i2spcm_driver);
+	platform_driver_unregister(&alchemy_ac97pcm_driver);
+}
+
+module_init(alchemy_audio_dma_load);
+module_exit(alchemy_audio_dma_unload);
+
+
+struct platform_device *alchemy_pcm_add(struct platform_device *pdev, int type)
+{
+	struct resource *res, *r;
+	struct platform_device *pd;
+	char *pdevname;
+	int id[2];
+	int ret;
+
+	r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+	if (!r)
+		return NULL;
+	id[0] = r->start;
+
+	r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+	if (!r)
+		return NULL;
+	id[1] = r->start;
+
+	res = kzalloc(sizeof(struct resource) * 2, GFP_KERNEL);
+	if (!res)
+		return NULL;
+
+	res[0].start = res[0].end = id[0];
+	res[1].start = res[1].end = id[1];
+	res[0].flags = res[1].flags = IORESOURCE_DMA;
+
+	/* "alchemy-pcm-ac97" or "alchemy-pcm-i2s" */
+	pdevname = (type == 0) ? AC97C_DMANAME : I2SC_DMANAME;
+	pd = platform_device_alloc(pdevname, -1);
+	if (!pd)
+		goto out;
+
+	pd->resource = res;
+	pd->num_resources = 2;
+
+	ret = platform_device_add(pd);
+	if (!ret)
+		return pd;
+
+	platform_device_put(pd);
+out:
+	kfree(res);
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(alchemy_pcm_add);
+
+void alchemy_pcm_destroy(struct platform_device *dmapd)
+{
+	if (dmapd)
+		platform_device_unregister(dmapd);
+}
+EXPORT_SYMBOL_GPL(alchemy_pcm_destroy);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Au1000/Au1500/Au1100 Audio DMA driver");
+MODULE_AUTHOR("Manuel Lauss");
diff --git a/sound/soc/au1x/i2sc.c b/sound/soc/au1x/i2sc.c
new file mode 100644
index 0000000..1a31d51
--- /dev/null
+++ b/sound/soc/au1x/i2sc.c
@@ -0,0 +1,353 @@
+/*
+ * Au1000/Au1500/Au1100 I2S controller driver for ASoC
+ *
+ * (c) 2011 Manuel Lauss <manuel.lauss@googlemail.com>
+ *
+ * Note: clock supplied to the I2S controller must be 256x samplerate.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/suspend.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <asm/mach-au1x00/au1000.h>
+
+#include "psc.h"
+
+#define I2S_DATA	0x00
+#define I2S_CONFIG	0x04
+#define I2S_ENABLE	0x08
+
+#define CFG_XU		(1 << 25)	/* tx underflow */
+#define CFG_XO		(1 << 24)
+#define CFG_RU		(1 << 23)
+#define CFG_RO		(1 << 22)
+#define CFG_TR		(1 << 21)
+#define CFG_TE		(1 << 20)
+#define CFG_TF		(1 << 19)
+#define CFG_RR		(1 << 18)
+#define CFG_RF		(1 << 17)
+#define CFG_ICK		(1 << 12)	/* clock invert */
+#define CFG_PD		(1 << 11)	/* set to make I2SDIO INPUT */
+#define CFG_LB		(1 << 10)	/* loopback */
+#define CFG_IC		(1 << 9)	/* word select invert */
+#define CFG_FM_I2S	(0 << 7)	/* I2S format */
+#define CFG_FM_LJ	(1 << 7)	/* left-justified */
+#define CFG_FM_RJ	(2 << 7)	/* right-justified */
+#define CFG_FM_MASK	(3 << 7)
+#define CFG_TN		(1 << 6)	/* tx fifo en */
+#define CFG_RN		(1 << 5)	/* rx fifo en */
+#define CFG_SZ_8	(0x08)
+#define CFG_SZ_16	(0x10)
+#define CFG_SZ_18	(0x12)
+#define CFG_SZ_20	(0x14)
+#define CFG_SZ_24	(0x18)
+#define CFG_SZ_MASK	(0x1f)
+#define EN_D		(1 << 1)	/* DISable */
+#define EN_CE		(1 << 0)	/* clock enable */
+
+/* supported I2S DAI hardware formats */
+#define AU1XI2SC_DAIFMT \
+	(SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J |	\
+	 SND_SOC_DAIFMT_NB_NF)
+
+/* supported I2S direction */
+#define AU1XI2SC_DIR \
+	(SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE)
+
+#define AU1XI2SC_RATES \
+	SNDRV_PCM_RATE_8000_192000
+
+#define AU1XI2SC_FMTS \
+	SNDRV_PCM_FMTBIT_S16_LE
+
+struct i2sc_ctx {
+	void __iomem *mmio;
+	unsigned long cfg, rate;
+	struct platform_device *dmapd;
+};
+
+static inline unsigned long RD(struct i2sc_ctx *ctx, int reg)
+{
+	return __raw_readl(ctx->mmio + reg);
+}
+
+static inline void WR(struct i2sc_ctx *ctx, int reg, unsigned long v)
+{
+	__raw_writel(v, ctx->mmio + reg);
+	wmb();
+}
+
+static int au1xi2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
+{
+	struct i2sc_ctx *ctx = snd_soc_dai_get_drvdata(cpu_dai);
+	unsigned long c;
+	int ret;
+
+	ret = -EINVAL;
+	c = ctx->cfg;
+
+	c &= ~CFG_FM_MASK;
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		c |= CFG_FM_I2S;	/* enable I2S mode */
+		break;
+	case SND_SOC_DAIFMT_MSB:
+		c |= CFG_FM_RJ;
+		break;
+	case SND_SOC_DAIFMT_LSB:
+		c |= CFG_FM_LJ;
+		break;
+	default:
+		goto out;
+	}
+
+	c &= ~(CFG_IC | CFG_ICK);		/* IB-IF */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		c |= CFG_IC | CFG_ICK;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		c |= CFG_IC;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		c |= CFG_ICK;
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		break;
+	default:
+		goto out;
+	}
+
+	/* I2S controller only supports master */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:	/* CODEC slave */
+		break;
+	default:
+		goto out;
+	}
+
+	ret = 0;
+	ctx->cfg = c;
+out:
+	return ret;
+}
+
+static int au1xi2s_trigger(struct snd_pcm_substream *substream,
+			   int cmd, struct snd_soc_dai *dai)
+{
+	struct i2sc_ctx *ctx = snd_soc_dai_get_drvdata(dai);
+	int stype = SUBSTREAM_TYPE(substream);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+		ctx->cfg |= (stype == PCM_TX) ? CFG_TN : CFG_RN;
+		WR(ctx, I2S_CONFIG, ctx->cfg);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		ctx->cfg &= ~((stype == PCM_TX) ? CFG_TN : CFG_RN);
+		WR(ctx, I2S_CONFIG, ctx->cfg);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static unsigned long msbits_to_reg(int msbits)
+{
+	switch (msbits) {
+	case 8:  return CFG_SZ_8;
+	case 16: return CFG_SZ_16;
+	case 18: return CFG_SZ_18;
+	case 20: return CFG_SZ_20;
+	case 24: return CFG_SZ_24;
+	}
+	return 0;
+}
+
+static int au1xi2s_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params,
+			     struct snd_soc_dai *dai)
+{
+	struct i2sc_ctx *ctx = snd_soc_dai_get_drvdata(dai);
+	unsigned long stat, v;
+
+	v = msbits_to_reg(params->msbits);
+	/* check if the PSC is already streaming data */
+	stat = RD(ctx, I2S_CONFIG);
+	if (stat & (CFG_TN | CFG_RN)) {
+		/* reject parameters not currently set up in hardware */
+		if ((ctx->rate != params_rate(params)) ||
+		    ((stat & CFG_SZ_MASK) != v))
+			return -EINVAL;
+	} else {
+		/* set sample bitdepth */
+		ctx->cfg &= ~CFG_SZ_MASK;
+		if (v)
+			ctx->cfg |= v;
+		else
+			return -EINVAL;
+		/* remember current rate for other stream */
+		ctx->rate = params_rate(params);
+	}
+	return 0;
+}
+
+static struct snd_soc_dai_ops au1xi2s_dai_ops = {
+	.trigger	= au1xi2s_trigger,
+	.hw_params	= au1xi2s_hw_params,
+	.set_fmt	= au1xi2s_set_fmt,
+};
+
+static struct snd_soc_dai_driver au1xi2s_dai_driver = {
+	.playback = {
+		.rates		= AU1XI2SC_RATES,
+		.formats	= AU1XI2SC_FMTS,
+		.channels_min	= 2,
+		.channels_max	= 2,
+	},
+	.capture = {
+		.rates		= AU1XI2SC_RATES,
+		.formats	= AU1XI2SC_FMTS,
+		.channels_min	= 2,
+		.channels_max	= 2,
+	},
+	.ops = &au1xi2s_dai_ops,
+};
+
+static int __devinit au1xi2s_drvprobe(struct platform_device *pdev)
+{
+	int ret;
+	struct resource *r;
+	struct i2sc_ctx *ctx;
+
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!r) {
+		ret = -ENODEV;
+		goto out0;
+	}
+
+	ret = -EBUSY;
+	if (!request_mem_region(r->start, resource_size(r), pdev->name))
+		goto out0;
+
+	ctx->mmio = ioremap_nocache(r->start, resource_size(r));
+	if (!ctx->mmio)
+		goto out1;
+
+	/* switch it on */
+	WR(ctx, I2S_ENABLE, EN_D | EN_CE);
+	WR(ctx, I2S_ENABLE, EN_CE);
+
+	ctx->cfg = CFG_FM_I2S | CFG_SZ_16;
+	WR(ctx, I2S_CONFIG, ctx->cfg);
+
+	platform_set_drvdata(pdev, ctx);
+
+	ret = snd_soc_register_dai(&pdev->dev, &au1xi2s_dai_driver);
+	if (ret)
+		goto out1;
+
+	ctx->dmapd = alchemy_pcm_add(pdev, 1);	/* 1 == I2S */
+	if (ctx->dmapd)
+		return 0;
+
+	snd_soc_unregister_dai(&pdev->dev);
+out1:
+	release_mem_region(r->start, resource_size(r));
+out0:
+	kfree(ctx);
+	return ret;
+}
+
+static int __devexit au1xi2s_drvremove(struct platform_device *pdev)
+{
+	struct i2sc_ctx *ctx = platform_get_drvdata(pdev);
+	struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	if (ctx->dmapd)
+		alchemy_pcm_destroy(ctx->dmapd);
+
+	snd_soc_unregister_dai(&pdev->dev);
+
+	WR(ctx, I2S_ENABLE, EN_D);	/* clock off, disable */
+
+	iounmap(ctx->mmio);
+	release_mem_region(r->start, resource_size(r));
+	kfree(ctx);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int au1xi2s_drvsuspend(struct device *dev)
+{
+	struct i2sc_ctx *ctx = dev_get_drvdata(dev);
+
+	WR(ctx, I2S_ENABLE, EN_D);	/* clock off, disable */
+
+	return 0;
+}
+
+static int au1xi2s_drvresume(struct device *dev)
+{
+	struct i2sc_ctx *ctx = dev_get_drvdata(dev);
+
+	WR(ctx, I2S_ENABLE, EN_D | EN_CE);
+	WR(ctx, I2S_ENABLE, EN_CE);
+	WR(ctx, I2S_CONFIG, ctx->cfg);
+
+	return 0;
+}
+
+static const struct dev_pm_ops au1xpscac97_pmops = {
+	.suspend	= au1xi2s_drvsuspend,
+	.resume		= au1xi2s_drvresume,
+};
+
+#define AU1XPSCAC97_PMOPS (&au1xpscac97_pmops)
+
+#else
+
+#define AU1XPSCAC97_PMOPS NULL
+
+#endif
+
+static struct platform_driver au1xi2s_driver = {
+	.driver	= {
+		.name	= "alchemy-ac97c",
+		.owner	= THIS_MODULE,
+		.pm	= AU1XPSCAC97_PMOPS,
+	},
+	.probe		= au1xi2s_drvprobe,
+	.remove		= __devexit_p(au1xi2s_drvremove),
+};
+
+static int __init au1xi2s_load(void)
+{
+	return platform_driver_register(&au1xi2s_driver);
+}
+
+static void __exit au1xi2s_unload(void)
+{
+	platform_driver_unregister(&au1xi2s_driver);
+}
+
+module_init(au1xi2s_load);
+module_exit(au1xi2s_unload);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Au1000/1500/1100 AC97C ALSA ASoC audio driver");
+MODULE_AUTHOR("Manuel Lauss");
diff --git a/sound/soc/au1x/psc.h b/sound/soc/au1x/psc.h
index b30eadd..21b944a 100644
--- a/sound/soc/au1x/psc.h
+++ b/sound/soc/au1x/psc.h
@@ -1,7 +1,7 @@
 /*
- * Au12x0/Au1550 PSC ALSA ASoC audio support.
+ * Alchemy ALSA ASoC audio support.
  *
- * (c) 2007-2008 MSC Vertriebsges.m.b.H.,
+ * (c) 2007-2011 MSC Vertriebsges.m.b.H.,
  *	Manuel Lauss <manuel.lauss@gmail.com>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -13,7 +13,26 @@
 #ifndef _AU1X_PCM_H
 #define _AU1X_PCM_H
 
-/* DBDMA helpers */
+#define PCM_TX	0
+#define PCM_RX	1
+
+#define SUBSTREAM_TYPE(substream) \
+	((substream)->stream == SNDRV_PCM_STREAM_PLAYBACK ? PCM_TX : PCM_RX)
+
+
+/* AC97C/I2SC DMA helpers */
+extern  struct platform_device *alchemy_pcm_add(struct platform_device *pdev,
+						int type);
+extern void alchemy_pcm_destroy(struct platform_device *dmapd);
+
+/* Au1000 AC97C/I2SC DAI names. Required to get at correct DMA instance */
+#define AC97C_DAINAME	"alchemy-ac97c"
+#define I2SC_DAINAME	"alchemy-i2sc"
+#define AC97C_DMANAME	"alchemy-pcm-ac97"
+#define I2SC_DMANAME	"alchemy-pcm-i2s"
+
+
+/* PSC/DBDMA helpers */
 extern struct platform_device *au1xpsc_pcm_add(struct platform_device *pdev);
 extern void au1xpsc_pcm_destroy(struct platform_device *dmapd);
 
@@ -30,12 +49,6 @@ struct au1xpsc_audio_data {
 	struct platform_device *dmapd;
 };
 
-#define PCM_TX	0
-#define PCM_RX	1
-
-#define SUBSTREAM_TYPE(substream) \
-	((substream)->stream == SNDRV_PCM_STREAM_PLAYBACK ? PCM_TX : PCM_RX)
-
 /* easy access macros */
 #define PSC_CTRL(x)	((unsigned long)((x)->mmio) + PSC_CTRL_OFFSET)
 #define PSC_SEL(x)	((unsigned long)((x)->mmio) + PSC_SEL_OFFSET)
-- 
1.7.6


From manuel.lauss@googlemail.com Thu Jul 21 18:34:24 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 21 Jul 2011 18:35:22 +0200 (CEST)
Received: from mail-fx0-f49.google.com ([209.85.161.49]:36949 "EHLO
        mail-fx0-f49.google.com" rhost-flags-OK-OK-OK-OK)
        by eddie.linux-mips.org with ESMTP id S1491146Ab1GUQeY (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Thu, 21 Jul 2011 18:34:24 +0200
Received: by fxd20 with SMTP id 20so2711822fxd.36
        for <multiple recipients>; Thu, 21 Jul 2011 09:34:19 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=googlemail.com; s=gamma;
        h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references;
        bh=rHM83cAYwXbkBy9eQAq1UhIuaC3ApaG32b9BB8chF70=;
        b=gMw7t3dtMul1iUaJJj1zBcf2aatsOQTP2Rh8mgHDMShP6bnK30ramjnFVbpDMaiREL
         vSEy0r5rrnGv9Z+6dnd7f5P7FZTPY9RGJVuOjrfQlqKQsN1lb4dfYqXPf3+4hbRmTz6m
         5ZazHf5bFsxdCCYwqqQ6F26TIZtjd2maoWveg=
Received: by 10.223.64.80 with SMTP id d16mr539461fai.86.1311266059554;
        Thu, 21 Jul 2011 09:34:19 -0700 (PDT)
Received: from localhost.localdomain (188-22-154-193.adsl.highway.telekom.at [188.22.154.193])
        by mx.google.com with ESMTPS id j19sm1490495faa.41.2011.07.21.09.34.17
        (version=TLSv1/SSLv3 cipher=OTHER);
        Thu, 21 Jul 2011 09:34:18 -0700 (PDT)
From:   Manuel Lauss <manuel.lauss@googlemail.com>
To:     alsa-devel@vger.kernel.org
Cc:     Ralf Baechle <ralf@linux-mips.org>,
        Linux-MIPS <linux-mips@linux-mips.org>,
        Manuel Lauss <manuel.lauss@googlemail.com>
Subject: [PATCH V2 2/2] ALSA: delete MIPS au1x00 driver
Date:   Thu, 21 Jul 2011 18:34:10 +0200
Message-Id: <1311266050-22199-3-git-send-email-manuel.lauss@googlemail.com>
X-Mailer: git-send-email 1.7.6
In-Reply-To: <1311266050-22199-1-git-send-email-manuel.lauss@googlemail.com>
References: <1311266050-22199-1-git-send-email-manuel.lauss@googlemail.com>
X-archive-position: 30654
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: manuel.lauss@googlemail.com
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 15240
Content-Length: 21345
Lines: 750

Since there's now an ASOC replacement.

Signed-off-by: Manuel Lauss <manuel.lauss@googlemail.com>
---
V2: no changes

 sound/mips/Kconfig  |    8 -
 sound/mips/Makefile |    2 -
 sound/mips/au1x00.c |  695 ---------------------------------------------------
 3 files changed, 0 insertions(+), 705 deletions(-)
 delete mode 100644 sound/mips/au1x00.c

diff --git a/sound/mips/Kconfig b/sound/mips/Kconfig
index a9823fa..bb8a4e3 100644
--- a/sound/mips/Kconfig
+++ b/sound/mips/Kconfig
@@ -22,13 +22,5 @@ config SND_SGI_HAL2
                 Sound support for the SGI Indy and Indigo2 Workstation.
 
 
-config SND_AU1X00
-	tristate "Au1x00 AC97 Port Driver"
-	depends on SOC_AU1000 || SOC_AU1100 || SOC_AU1500
-	select SND_PCM
-	select SND_AC97_CODEC
-	help
-	  ALSA Sound driver for the Au1x00's AC97 port.
-
 endif	# SND_MIPS
 
diff --git a/sound/mips/Makefile b/sound/mips/Makefile
index 861ec0a..b977c44 100644
--- a/sound/mips/Makefile
+++ b/sound/mips/Makefile
@@ -2,11 +2,9 @@
 # Makefile for ALSA
 #
 
-snd-au1x00-objs := au1x00.o
 snd-sgi-o2-objs := sgio2audio.o ad1843.o
 snd-sgi-hal2-objs := hal2.o
 
 # Toplevel Module Dependency
-obj-$(CONFIG_SND_AU1X00) += snd-au1x00.o
 obj-$(CONFIG_SND_SGI_O2) += snd-sgi-o2.o
 obj-$(CONFIG_SND_SGI_HAL2) += snd-sgi-hal2.o
diff --git a/sound/mips/au1x00.c b/sound/mips/au1x00.c
deleted file mode 100644
index 446cf97..0000000
--- a/sound/mips/au1x00.c
+++ /dev/null
@@ -1,695 +0,0 @@
-/*
- * BRIEF MODULE DESCRIPTION
- *  Driver for AMD Au1000 MIPS Processor, AC'97 Sound Port
- *
- * Copyright 2004 Cooper Street Innovations Inc.
- * Author: Charles Eidsness	<charles@cooper-street.com>
- *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- *
- *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
- *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
- *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
- *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
- *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
- *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
- *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *  You should have received a copy of the  GNU General Public License along
- *  with this program; if not, write  to the Free Software Foundation, Inc.,
- *  675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * History:
- *
- * 2004-09-09 Charles Eidsness	-- Original verion -- based on
- * 				  sa11xx-uda1341.c ALSA driver and the
- *				  au1000.c OSS driver.
- * 2004-09-09 Matt Porter	-- Added support for ALSA 1.0.6
- *
- */
-
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <sound/core.h>
-#include <sound/initval.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/ac97_codec.h>
-#include <asm/mach-au1x00/au1000.h>
-#include <asm/mach-au1x00/au1000_dma.h>
-
-MODULE_AUTHOR("Charles Eidsness <charles@cooper-street.com>");
-MODULE_DESCRIPTION("Au1000 AC'97 ALSA Driver");
-MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{AMD,Au1000 AC'97}}");
-
-#define PLAYBACK 0
-#define CAPTURE 1
-#define AC97_SLOT_3 0x01
-#define AC97_SLOT_4 0x02
-#define AC97_SLOT_6 0x08
-#define AC97_CMD_IRQ 31
-#define READ 0
-#define WRITE 1
-#define READ_WAIT 2
-#define RW_DONE 3
-
-struct au1000_period
-{
-	u32 start;
-	u32 relative_end;	/*realtive to start of buffer*/
-	struct au1000_period * next;
-};
-
-/*Au1000 AC97 Port Control Reisters*/
-struct au1000_ac97_reg {
-	u32 volatile config;
-	u32 volatile status;
-	u32 volatile data;
-	u32 volatile cmd;
-	u32 volatile cntrl;
-};
-
-struct audio_stream {
-	struct snd_pcm_substream *substream;
-	int dma;
-	spinlock_t dma_lock;
-	struct au1000_period * buffer;
-	unsigned int period_size;
-	unsigned int periods;
-};
-
-struct snd_au1000 {
-	struct snd_card *card;
-	struct au1000_ac97_reg volatile *ac97_ioport;
-
-	struct resource *ac97_res_port;
-	spinlock_t ac97_lock;
-	struct snd_ac97 *ac97;
-
-	struct snd_pcm *pcm;
-	struct audio_stream *stream[2];	/* playback & capture */
-};
-
-/*--------------------------- Local Functions --------------------------------*/
-static void
-au1000_set_ac97_xmit_slots(struct snd_au1000 *au1000, long xmit_slots)
-{
-	u32 volatile ac97_config;
-
-	spin_lock(&au1000->ac97_lock);
-	ac97_config = au1000->ac97_ioport->config;
-	ac97_config = ac97_config & ~AC97C_XMIT_SLOTS_MASK;
-	ac97_config |= (xmit_slots << AC97C_XMIT_SLOTS_BIT);
-	au1000->ac97_ioport->config = ac97_config;
-	spin_unlock(&au1000->ac97_lock);
-}
-
-static void
-au1000_set_ac97_recv_slots(struct snd_au1000 *au1000, long recv_slots)
-{
-	u32 volatile ac97_config;
-
-	spin_lock(&au1000->ac97_lock);
-	ac97_config = au1000->ac97_ioport->config;
-	ac97_config = ac97_config & ~AC97C_RECV_SLOTS_MASK;
-	ac97_config |= (recv_slots << AC97C_RECV_SLOTS_BIT);
-	au1000->ac97_ioport->config = ac97_config;
-	spin_unlock(&au1000->ac97_lock);
-}
-
-
-static void
-au1000_release_dma_link(struct audio_stream *stream)
-{
-	struct au1000_period * pointer;
-	struct au1000_period * pointer_next;
-
-	stream->period_size = 0;
-	stream->periods = 0;
-	pointer = stream->buffer;
-	if (! pointer)
-		return;
-	do {
-		pointer_next = pointer->next;
-		kfree(pointer);
-		pointer = pointer_next;
-	} while (pointer != stream->buffer);
-	stream->buffer = NULL;
-}
-
-static int
-au1000_setup_dma_link(struct audio_stream *stream, unsigned int period_bytes,
-		      unsigned int periods)
-{
-	struct snd_pcm_substream *substream = stream->substream;
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct au1000_period *pointer;
-	unsigned long dma_start;
-	int i;
-
-	dma_start = virt_to_phys(runtime->dma_area);
-
-	if (stream->period_size == period_bytes &&
-	    stream->periods == periods)
-		return 0; /* not changed */
-
-	au1000_release_dma_link(stream);
-
-	stream->period_size = period_bytes;
-	stream->periods = periods;
-
-	stream->buffer = kmalloc(sizeof(struct au1000_period), GFP_KERNEL);
-	if (! stream->buffer)
-		return -ENOMEM;
-	pointer = stream->buffer;
-	for (i = 0; i < periods; i++) {
-		pointer->start = (u32)(dma_start + (i * period_bytes));
-		pointer->relative_end = (u32) (((i+1) * period_bytes) - 0x1);
-		if (i < periods - 1) {
-			pointer->next = kmalloc(sizeof(struct au1000_period), GFP_KERNEL);
-			if (! pointer->next) {
-				au1000_release_dma_link(stream);
-				return -ENOMEM;
-			}
-			pointer = pointer->next;
-		}
-	}
-	pointer->next = stream->buffer;
-	return 0;
-}
-
-static void
-au1000_dma_stop(struct audio_stream *stream)
-{
-	if (snd_BUG_ON(!stream->buffer))
-		return;
-	disable_dma(stream->dma);
-}
-
-static void
-au1000_dma_start(struct audio_stream *stream)
-{
-	if (snd_BUG_ON(!stream->buffer))
-		return;
-
-	init_dma(stream->dma);
-	if (get_dma_active_buffer(stream->dma) == 0) {
-		clear_dma_done0(stream->dma);
-		set_dma_addr0(stream->dma, stream->buffer->start);
-		set_dma_count0(stream->dma, stream->period_size >> 1);
-		set_dma_addr1(stream->dma, stream->buffer->next->start);
-		set_dma_count1(stream->dma, stream->period_size >> 1);
-	} else {
-		clear_dma_done1(stream->dma);
-		set_dma_addr1(stream->dma, stream->buffer->start);
-		set_dma_count1(stream->dma, stream->period_size >> 1);
-		set_dma_addr0(stream->dma, stream->buffer->next->start);
-		set_dma_count0(stream->dma, stream->period_size >> 1);
-	}
-	enable_dma_buffers(stream->dma);
-	start_dma(stream->dma);
-}
-
-static irqreturn_t
-au1000_dma_interrupt(int irq, void *dev_id)
-{
-	struct audio_stream *stream = (struct audio_stream *) dev_id;
-	struct snd_pcm_substream *substream = stream->substream;
-
-	spin_lock(&stream->dma_lock);
-	switch (get_dma_buffer_done(stream->dma)) {
-	case DMA_D0:
-		stream->buffer = stream->buffer->next;
-		clear_dma_done0(stream->dma);
-		set_dma_addr0(stream->dma, stream->buffer->next->start);
-		set_dma_count0(stream->dma, stream->period_size >> 1);
-		enable_dma_buffer0(stream->dma);
-		break;
-	case DMA_D1:
-		stream->buffer = stream->buffer->next;
-		clear_dma_done1(stream->dma);
-		set_dma_addr1(stream->dma, stream->buffer->next->start);
-		set_dma_count1(stream->dma, stream->period_size >> 1);
-		enable_dma_buffer1(stream->dma);
-		break;
-	case (DMA_D0 | DMA_D1):
-		printk(KERN_ERR "DMA %d missed interrupt.\n",stream->dma);
-		au1000_dma_stop(stream);
-		au1000_dma_start(stream);
-		break;
-	case (~DMA_D0 & ~DMA_D1):
-		printk(KERN_ERR "DMA %d empty irq.\n",stream->dma);
-	}
-	spin_unlock(&stream->dma_lock);
-	snd_pcm_period_elapsed(substream);
-	return IRQ_HANDLED;
-}
-
-/*-------------------------- PCM Audio Streams -------------------------------*/
-
-static unsigned int rates[] = {8000, 11025, 16000, 22050};
-static struct snd_pcm_hw_constraint_list hw_constraints_rates = {
-	.count	= ARRAY_SIZE(rates),
-	.list	= rates,
-	.mask	= 0,
-};
-
-static struct snd_pcm_hardware snd_au1000_hw =
-{
-	.info			= (SNDRV_PCM_INFO_INTERLEAVED | \
-				SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
-	.formats		= SNDRV_PCM_FMTBIT_S16_LE,
-	.rates			= (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
-				SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050),
-	.rate_min		= 8000,
-	.rate_max		= 22050,
-	.channels_min		= 1,
-	.channels_max		= 2,
-	.buffer_bytes_max	= 128*1024,
-	.period_bytes_min	= 32,
-	.period_bytes_max	= 16*1024,
-	.periods_min		= 8,
-	.periods_max		= 255,
-	.fifo_size		= 16,
-};
-
-static int
-snd_au1000_playback_open(struct snd_pcm_substream *substream)
-{
-	struct snd_au1000 *au1000 = substream->pcm->private_data;
-
-	au1000->stream[PLAYBACK]->substream = substream;
-	au1000->stream[PLAYBACK]->buffer = NULL;
-	substream->private_data = au1000->stream[PLAYBACK];
-	substream->runtime->hw = snd_au1000_hw;
-	return (snd_pcm_hw_constraint_list(substream->runtime, 0,
-		SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates) < 0);
-}
-
-static int
-snd_au1000_capture_open(struct snd_pcm_substream *substream)
-{
-	struct snd_au1000 *au1000 = substream->pcm->private_data;
-
-	au1000->stream[CAPTURE]->substream = substream;
-	au1000->stream[CAPTURE]->buffer = NULL;
-	substream->private_data = au1000->stream[CAPTURE];
-	substream->runtime->hw = snd_au1000_hw;
-	return (snd_pcm_hw_constraint_list(substream->runtime, 0,
-		SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates) < 0);
-}
-
-static int
-snd_au1000_playback_close(struct snd_pcm_substream *substream)
-{
-	struct snd_au1000 *au1000 = substream->pcm->private_data;
-
-	au1000->stream[PLAYBACK]->substream = NULL;
-	return 0;
-}
-
-static int
-snd_au1000_capture_close(struct snd_pcm_substream *substream)
-{
-	struct snd_au1000 *au1000 = substream->pcm->private_data;
-
-	au1000->stream[CAPTURE]->substream = NULL;
-	return 0;
-}
-
-static int
-snd_au1000_hw_params(struct snd_pcm_substream *substream,
-					struct snd_pcm_hw_params *hw_params)
-{
-	struct audio_stream *stream = substream->private_data;
-	int err;
-
-	err = snd_pcm_lib_malloc_pages(substream,
-				       params_buffer_bytes(hw_params));
-	if (err < 0)
-		return err;
-	return au1000_setup_dma_link(stream,
-				     params_period_bytes(hw_params),
-				     params_periods(hw_params));
-}
-
-static int
-snd_au1000_hw_free(struct snd_pcm_substream *substream)
-{
-	struct audio_stream *stream = substream->private_data;
-	au1000_release_dma_link(stream);
-	return snd_pcm_lib_free_pages(substream);
-}
-
-static int
-snd_au1000_playback_prepare(struct snd_pcm_substream *substream)
-{
-	struct snd_au1000 *au1000 = substream->pcm->private_data;
-	struct snd_pcm_runtime *runtime = substream->runtime;
-
-	if (runtime->channels == 1)
-		au1000_set_ac97_xmit_slots(au1000, AC97_SLOT_4);
-	else
-		au1000_set_ac97_xmit_slots(au1000, AC97_SLOT_3 | AC97_SLOT_4);
-	snd_ac97_set_rate(au1000->ac97, AC97_PCM_FRONT_DAC_RATE, runtime->rate);
-	return 0;
-}
-
-static int
-snd_au1000_capture_prepare(struct snd_pcm_substream *substream)
-{
-	struct snd_au1000 *au1000 = substream->pcm->private_data;
-	struct snd_pcm_runtime *runtime = substream->runtime;
-
-	if (runtime->channels == 1)
-		au1000_set_ac97_recv_slots(au1000, AC97_SLOT_4);
-	else
-		au1000_set_ac97_recv_slots(au1000, AC97_SLOT_3 | AC97_SLOT_4);
-	snd_ac97_set_rate(au1000->ac97, AC97_PCM_LR_ADC_RATE, runtime->rate);
-	return 0;
-}
-
-static int
-snd_au1000_trigger(struct snd_pcm_substream *substream, int cmd)
-{
-	struct audio_stream *stream = substream->private_data;
-	int err = 0;
-
-	spin_lock(&stream->dma_lock);
-	switch (cmd) {
-	case SNDRV_PCM_TRIGGER_START:
-		au1000_dma_start(stream);
-		break;
-	case SNDRV_PCM_TRIGGER_STOP:
-		au1000_dma_stop(stream);
-		break;
-	default:
-		err = -EINVAL;
-		break;
-	}
-	spin_unlock(&stream->dma_lock);
-	return err;
-}
-
-static snd_pcm_uframes_t
-snd_au1000_pointer(struct snd_pcm_substream *substream)
-{
-	struct audio_stream *stream = substream->private_data;
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	long location;
-
-	spin_lock(&stream->dma_lock);
-	location = get_dma_residue(stream->dma);
-	spin_unlock(&stream->dma_lock);
-	location = stream->buffer->relative_end - location;
-	if (location == -1)
-		location = 0;
-	return bytes_to_frames(runtime,location);
-}
-
-static struct snd_pcm_ops snd_card_au1000_playback_ops = {
-	.open			= snd_au1000_playback_open,
-	.close			= snd_au1000_playback_close,
-	.ioctl			= snd_pcm_lib_ioctl,
-	.hw_params	        = snd_au1000_hw_params,
-	.hw_free	        = snd_au1000_hw_free,
-	.prepare		= snd_au1000_playback_prepare,
-	.trigger		= snd_au1000_trigger,
-	.pointer		= snd_au1000_pointer,
-};
-
-static struct snd_pcm_ops snd_card_au1000_capture_ops = {
-	.open			= snd_au1000_capture_open,
-	.close			= snd_au1000_capture_close,
-	.ioctl			= snd_pcm_lib_ioctl,
-	.hw_params	        = snd_au1000_hw_params,
-	.hw_free	        = snd_au1000_hw_free,
-	.prepare		= snd_au1000_capture_prepare,
-	.trigger		= snd_au1000_trigger,
-	.pointer		= snd_au1000_pointer,
-};
-
-static int __devinit
-snd_au1000_pcm_new(struct snd_au1000 *au1000)
-{
-	struct snd_pcm *pcm;
-	int err;
-	unsigned long flags;
-
-	if ((err = snd_pcm_new(au1000->card, "AU1000 AC97 PCM", 0, 1, 1, &pcm)) < 0)
-		return err;
-
-	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
-		snd_dma_continuous_data(GFP_KERNEL), 128*1024, 128*1024);
-
-	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
-		&snd_card_au1000_playback_ops);
-	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
-		&snd_card_au1000_capture_ops);
-
-	pcm->private_data = au1000;
-	pcm->info_flags = 0;
-	strcpy(pcm->name, "Au1000 AC97 PCM");
-
-	spin_lock_init(&au1000->stream[PLAYBACK]->dma_lock);
-	spin_lock_init(&au1000->stream[CAPTURE]->dma_lock);
-
-	flags = claim_dma_lock();
-	if ((au1000->stream[PLAYBACK]->dma = request_au1000_dma(DMA_ID_AC97C_TX,
-			"AC97 TX", au1000_dma_interrupt, IRQF_DISABLED,
-			au1000->stream[PLAYBACK])) < 0) {
-		release_dma_lock(flags);
-		return -EBUSY;
-	}
-	if ((au1000->stream[CAPTURE]->dma = request_au1000_dma(DMA_ID_AC97C_RX,
-			"AC97 RX", au1000_dma_interrupt, IRQF_DISABLED,
-			au1000->stream[CAPTURE])) < 0){
-		release_dma_lock(flags);
-		return -EBUSY;
-	}
-	/* enable DMA coherency in read/write DMA channels */
-	set_dma_mode(au1000->stream[PLAYBACK]->dma,
-		     get_dma_mode(au1000->stream[PLAYBACK]->dma) & ~DMA_NC);
-	set_dma_mode(au1000->stream[CAPTURE]->dma,
-		     get_dma_mode(au1000->stream[CAPTURE]->dma) & ~DMA_NC);
-	release_dma_lock(flags);
-	au1000->pcm = pcm;
-	return 0;
-}
-
-
-/*-------------------------- AC97 CODEC Control ------------------------------*/
-
-static unsigned short
-snd_au1000_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
-{
-	struct snd_au1000 *au1000 = ac97->private_data;
-	u32 volatile cmd;
-	u16 volatile data;
-	int             i;
-
-	spin_lock(&au1000->ac97_lock);
-/* would rather use the interrupt than this polling but it works and I can't
-get the interrupt driven case to work efficiently */
-	for (i = 0; i < 0x5000; i++)
-		if (!(au1000->ac97_ioport->status & AC97C_CP))
-			break;
-	if (i == 0x5000)
-		printk(KERN_ERR "au1000 AC97: AC97 command read timeout\n");
-
-	cmd = (u32) reg & AC97C_INDEX_MASK;
-	cmd |= AC97C_READ;
-	au1000->ac97_ioport->cmd = cmd;
-
-	/* now wait for the data */
-	for (i = 0; i < 0x5000; i++)
-		if (!(au1000->ac97_ioport->status & AC97C_CP))
-			break;
-	if (i == 0x5000) {
-		printk(KERN_ERR "au1000 AC97: AC97 command read timeout\n");
-		spin_unlock(&au1000->ac97_lock);
-		return 0;
-	}
-
-	data = au1000->ac97_ioport->cmd & 0xffff;
-	spin_unlock(&au1000->ac97_lock);
-
-	return data;
-
-}
-
-
-static void
-snd_au1000_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val)
-{
-	struct snd_au1000 *au1000 = ac97->private_data;
-	u32 cmd;
-	int i;
-
-	spin_lock(&au1000->ac97_lock);
-/* would rather use the interrupt than this polling but it works and I can't
-get the interrupt driven case to work efficiently */
-	for (i = 0; i < 0x5000; i++)
-		if (!(au1000->ac97_ioport->status & AC97C_CP))
-			break;
-	if (i == 0x5000)
-		printk(KERN_ERR "au1000 AC97: AC97 command write timeout\n");
-
-	cmd = (u32) reg & AC97C_INDEX_MASK;
-	cmd &= ~AC97C_READ;
-	cmd |= ((u32) val << AC97C_WD_BIT);
-	au1000->ac97_ioport->cmd = cmd;
-	spin_unlock(&au1000->ac97_lock);
-}
-
-static int __devinit
-snd_au1000_ac97_new(struct snd_au1000 *au1000)
-{
-	int err;
-	struct snd_ac97_bus *pbus;
-	struct snd_ac97_template ac97;
- 	static struct snd_ac97_bus_ops ops = {
-		.write = snd_au1000_ac97_write,
-		.read = snd_au1000_ac97_read,
-	};
-
-	if ((au1000->ac97_res_port = request_mem_region(CPHYSADDR(AC97C_CONFIG),
-	       		0x100000, "Au1x00 AC97")) == NULL) {
-		snd_printk(KERN_ERR "ALSA AC97: can't grap AC97 port\n");
-		return -EBUSY;
-	}
-	au1000->ac97_ioport = (struct au1000_ac97_reg *)
-		KSEG1ADDR(au1000->ac97_res_port->start);
-
-	spin_lock_init(&au1000->ac97_lock);
-
-	/* configure pins for AC'97
-	TODO: move to board_setup.c */
-	au_writel(au_readl(SYS_PINFUNC) & ~0x02, SYS_PINFUNC);
-
-	/* Initialise Au1000's AC'97 Control Block */
-	au1000->ac97_ioport->cntrl = AC97C_RS | AC97C_CE;
-	udelay(10);
-	au1000->ac97_ioport->cntrl = AC97C_CE;
-	udelay(10);
-
-	/* Initialise External CODEC -- cold reset */
-	au1000->ac97_ioport->config = AC97C_RESET;
-	udelay(10);
-	au1000->ac97_ioport->config = 0x0;
-	mdelay(5);
-
-	/* Initialise AC97 middle-layer */
-	if ((err = snd_ac97_bus(au1000->card, 0, &ops, au1000, &pbus)) < 0)
- 		return err;
-
-	memset(&ac97, 0, sizeof(ac97));
-	ac97.private_data = au1000;
-	if ((err = snd_ac97_mixer(pbus, &ac97, &au1000->ac97)) < 0)
-		return err;
-
-	return 0;
-}
-
-/*------------------------------ Setup / Destroy ----------------------------*/
-
-void
-snd_au1000_free(struct snd_card *card)
-{
-	struct snd_au1000 *au1000 = card->private_data;
-
-	if (au1000->ac97_res_port) {
-		/* put internal AC97 block into reset */
-		au1000->ac97_ioport->cntrl = AC97C_RS;
-		au1000->ac97_ioport = NULL;
-		release_and_free_resource(au1000->ac97_res_port);
-	}
-
-	if (au1000->stream[PLAYBACK]) {
-	  	if (au1000->stream[PLAYBACK]->dma >= 0)
-			free_au1000_dma(au1000->stream[PLAYBACK]->dma);
-		kfree(au1000->stream[PLAYBACK]);
-	}
-
-	if (au1000->stream[CAPTURE]) {
-		if (au1000->stream[CAPTURE]->dma >= 0)
-			free_au1000_dma(au1000->stream[CAPTURE]->dma);
-		kfree(au1000->stream[CAPTURE]);
-	}
-}
-
-
-static struct snd_card *au1000_card;
-
-static int __init
-au1000_init(void)
-{
-	int err;
-	struct snd_card *card;
-	struct snd_au1000 *au1000;
-
-	err = snd_card_create(-1, "AC97", THIS_MODULE,
-			      sizeof(struct snd_au1000), &card);
-	if (err < 0)
-		return err;
-
-	card->private_free = snd_au1000_free;
-	au1000 = card->private_data;
-	au1000->card = card;
-
-	au1000->stream[PLAYBACK] = kmalloc(sizeof(struct audio_stream), GFP_KERNEL);
-	au1000->stream[CAPTURE ] = kmalloc(sizeof(struct audio_stream), GFP_KERNEL);
-	/* so that snd_au1000_free will work as intended */
- 	au1000->ac97_res_port = NULL;
-	if (au1000->stream[PLAYBACK])
-		au1000->stream[PLAYBACK]->dma = -1;
-	if (au1000->stream[CAPTURE ])
-		au1000->stream[CAPTURE ]->dma = -1;
-
-	if (au1000->stream[PLAYBACK] == NULL ||
-	    au1000->stream[CAPTURE ] == NULL) {
-		snd_card_free(card);
-		return -ENOMEM;
-	}
-
-	if ((err = snd_au1000_ac97_new(au1000)) < 0 ) {
-		snd_card_free(card);
-		return err;
-	}
-
-	if ((err = snd_au1000_pcm_new(au1000)) < 0) {
-		snd_card_free(card);
-		return err;
-	}
-
-	strcpy(card->driver, "Au1000-AC97");
-	strcpy(card->shortname, "AMD Au1000-AC97");
-	sprintf(card->longname, "AMD Au1000--AC97 ALSA Driver");
-
-	if ((err = snd_card_register(card)) < 0) {
-		snd_card_free(card);
-		return err;
-	}
-
-	printk(KERN_INFO "ALSA AC97: Driver Initialized\n");
-	au1000_card = card;
-	return 0;
-}
-
-static void __exit au1000_exit(void)
-{
-	snd_card_free(au1000_card);
-}
-
-module_init(au1000_init);
-module_exit(au1000_exit);
-
-- 
1.7.6


From tiwai@suse.de Thu Jul 21 19:09:00 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 21 Jul 2011 19:09:07 +0200 (CEST)
Received: from cantor2.suse.de ([195.135.220.15]:52525 "EHLO mx2.suse.de"
        rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org with ESMTP
        id S1491146Ab1GURJA (ORCPT <rfc822;linux-mips@linux-mips.org>);
        Thu, 21 Jul 2011 19:09:00 +0200
Received: from relay2.suse.de (charybdis-ext.suse.de [195.135.221.2])
        (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits))
        (No client certificate requested)
        by mx2.suse.de (Postfix) with ESMTP id DF8568AD27;
        Thu, 21 Jul 2011 19:08:59 +0200 (CEST)
Date:   Thu, 21 Jul 2011 19:08:57 +0200
Message-ID: <s5hmxg78st2.wl%tiwai@suse.de>
From:   Takashi Iwai <tiwai@suse.de>
To:     Manuel Lauss <manuel.lauss@googlemail.com>
Cc:     alsa-devel@alsa-project.org,
        Linux-MIPS <linux-mips@linux-mips.org>,
        Ralf Baechle <ralf@linux-mips.org>
Subject: Re: [alsa-devel] [PATCH V2 0/2] ALSA: ASoC for Au1000/1500/1100
In-Reply-To: <1311266050-22199-1-git-send-email-manuel.lauss@googlemail.com>
References: <1311266050-22199-1-git-send-email-manuel.lauss@googlemail.com>
User-Agent: Wanderlust/2.15.6 (Almost Unreal) SEMI/1.14.6 (Maruoka)
 FLIM/1.14.9 (=?UTF-8?B?R29qxY0=?=) APEL/10.7 Emacs/23.3
 (x86_64-suse-linux-gnu) MULE/6.0 (HANACHIRUSATO)
MIME-Version: 1.0 (generated by SEMI 1.14.6 - "Maruoka")
Content-Type: text/plain; charset=US-ASCII
X-archive-position: 30655
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: tiwai@suse.de
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 15266
Content-Length: 411
Lines: 16

At Thu, 21 Jul 2011 18:34:08 +0200,
Manuel Lauss wrote:
> 
> Hello,
> 
> These 2 patches implement ASoC drivers for the AC97 and I2S
> controllers found on early Alchemy chips.  They are largely
> based on the old mips/au1x00.c driver which they replace.

In general, dropping an old driver happens a bit later after the new
driver comes in.  You can make the old one as deprecated at first.


thanks,

Takashi

From khc@pm.waw.pl Thu Jul 21 19:14:47 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 21 Jul 2011 19:14:52 +0200 (CEST)
Received: from inx.pm.waw.pl ([195.116.170.130]:58534 "EHLO inx.pm.waw.pl"
        rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org with ESMTP
        id S1491144Ab1GUROr convert rfc822-to-8bit (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Thu, 21 Jul 2011 19:14:47 +0200
Received: by inx.pm.waw.pl (Postfix, from userid 2530)
        id D3AA0B61E; Thu, 21 Jul 2011 19:14:24 +0200 (CEST)
From:   Krzysztof Halasa <khc@pm.waw.pl>
To:     Ralf Baechle <ralf@linux-mips.org>
Cc:     Jesse Barnes <jbarnes@virtuousgeek.org>,  linux-pci@vger.kernel.org,  Anton Vorontsov <avorontsov@mvista.com>,  Chris Metcalf <cmetcalf@tilera.com>,  Colin Cross <ccross@android.com>,  "David S. Miller" <davem@davemloft.net>,  Eric Miao <eric.y.miao@gmail.com>,  Erik Gilling <konkers@android.com>,  Guan Xuetao <gxt@mprc.pku.edu.cn>,  "H. Peter Anvin" <hpa@zytor.com>,  Imre Kaloz <kaloz@openwrt.org>,  Ingo Molnar <mingo@redhat.com>,  Ivan Kokshaysky <ink@jurassic.park.msu.ru>,  Lennert Buytenhek <kernel@wantstofly.org>,  Matt Turner <mattst88@gmail.com>,  Nicolas Pitre <nico@fluxnic.net>,  Olof Johansson <olof@lixom.net>,  Paul Mundt <lethal@linux-sh.org>,  Richard Henderson <rth@twiddle.net>,  Russell King <linux@arm.linux.org.uk>,  Thomas Gleixner <tglx@linutronix.de>,  Andrew Morton <akpm@linux-foundation.org>,  linux-alpha@vger.kernel.org,  linux-arm-kernel@lists.infradead.org,  linux-kernel@vger.kernel.org,  linux-mips@linux-mips.org,  linux-sh@vger.kernel.org,  linux
 -tegra@vger.kernel.org,  sparclinux@vger.kernel.org,  x86@kernel.org
Subject: Re: [PATCH] PCI: Make the struct pci_dev * argument of pci_fixup_irqs const.
References: <20110610143021.GA26043@linux-mips.org>
Date:   Thu, 21 Jul 2011 21:14:24 +0200
In-Reply-To: <20110610143021.GA26043@linux-mips.org> (Ralf Baechle's message
        of "Fri, 10 Jun 2011 15:30:21 +0100")
Message-ID: <m3hb6fe99r.fsf@intrepid.localdomain>
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: 8BIT
X-archive-position: 30656
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: khc@pm.waw.pl
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 15275
Content-Length: 1265
Lines: 29

Ralf Baechle <ralf@linux-mips.org> writes:

> Aside of the usual motivation for constification,  this function has a
> history of being abused a hook for interrupt and other fixups so I turned
> this function const ages ago in the MIPS code but it should be done
> treewide.
>
> Due to function pointer passing in varous places a few other functions
> had to be constified as well.

>  arch/arm/mach-ixp4xx/avila-pci.c               |    2 +-
>  arch/arm/mach-ixp4xx/coyote-pci.c              |    2 +-
>  arch/arm/mach-ixp4xx/dsmg600-pci.c             |    2 +-
>  arch/arm/mach-ixp4xx/fsg-pci.c                 |    2 +-
>  arch/arm/mach-ixp4xx/gateway7001-pci.c         |    3 ++-
>  arch/arm/mach-ixp4xx/goramo_mlr.c              |    2 +-
>  arch/arm/mach-ixp4xx/gtwx5715-pci.c            |    2 +-
>  arch/arm/mach-ixp4xx/ixdp425-pci.c             |    2 +-
>  arch/arm/mach-ixp4xx/ixdpg425-pci.c            |    2 +-
>  arch/arm/mach-ixp4xx/nas100d-pci.c             |    2 +-
>  arch/arm/mach-ixp4xx/nslu2-pci.c               |    2 +-
>  arch/arm/mach-ixp4xx/vulcan-pci.c              |    2 +-
>  arch/arm/mach-ixp4xx/wg302v2-pci.c             |    2 +-

The IXP4xx part looks good to me.

Acked-by: Krzysztof HaÅ‚asa <khc@pm.waw.pl>
-- 
Krzysztof Halasa

From manuel.lauss@googlemail.com Thu Jul 21 19:27:58 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 21 Jul 2011 19:28:01 +0200 (CEST)
Received: from mail-gy0-f177.google.com ([209.85.160.177]:61391 "EHLO
        mail-gy0-f177.google.com" rhost-flags-OK-OK-OK-OK)
        by eddie.linux-mips.org with ESMTP id S1491202Ab1GUR16 convert rfc822-to-8bit
        (ORCPT <rfc822;linux-mips@linux-mips.org>);
        Thu, 21 Jul 2011 19:27:58 +0200
Received: by gya1 with SMTP id 1so837308gya.36
        for <multiple recipients>; Thu, 21 Jul 2011 10:27:52 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=googlemail.com; s=gamma;
        h=mime-version:in-reply-to:references:date:message-id:subject:from:to
         :cc:content-type:content-transfer-encoding;
        bh=9ZVYsA70l+uoYlzseiUCADoLuduVm/y2Qm8bKGCdVWk=;
        b=SwHqbexKaiVAuIvXORllJJV+181Se4MOOkvLr4FPukZLxxgJ5lLIDvc6hKBtv2k2Fc
         F3jQi7+92HnkVKWkF9uFofzNRFm2U2Y0j6ErW+AFFsjXn7jhMtV8vYMDizBjkwnlZCsV
         QQ2a707zecd19lnTLR4jUPI36MYU63QoH6Stk=
MIME-Version: 1.0
Received: by 10.236.190.68 with SMTP id d44mr809119yhn.393.1311269271876; Thu,
 21 Jul 2011 10:27:51 -0700 (PDT)
Received: by 10.236.95.168 with HTTP; Thu, 21 Jul 2011 10:27:51 -0700 (PDT)
In-Reply-To: <s5hmxg78st2.wl%tiwai@suse.de>
References: <1311266050-22199-1-git-send-email-manuel.lauss@googlemail.com>
        <s5hmxg78st2.wl%tiwai@suse.de>
Date:   Thu, 21 Jul 2011 19:27:51 +0200
Message-ID: <CAOLZvyEaKdSwC9ZU_FrYYAqmTkHfCsztftip_sY0Vfe9wDN7Og@mail.gmail.com>
Subject: Re: [alsa-devel] [PATCH V2 0/2] ALSA: ASoC for Au1000/1500/1100
From:   Manuel Lauss <manuel.lauss@googlemail.com>
To:     Takashi Iwai <tiwai@suse.de>
Cc:     alsa-devel@alsa-project.org,
        Linux-MIPS <linux-mips@linux-mips.org>,
        Ralf Baechle <ralf@linux-mips.org>
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 8BIT
X-archive-position: 30657
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: manuel.lauss@googlemail.com
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 15298
Content-Length: 546
Lines: 17

On Thu, Jul 21, 2011 at 7:08 PM, Takashi Iwai <tiwai@suse.de> wrote:
> At Thu, 21 Jul 2011 18:34:08 +0200,
> Manuel Lauss wrote:
>>
>> Hello,
>>
>> These 2 patches implement ASoC drivers for the AC97 and I2S
>> controllers found on early Alchemy chips.  They are largely
>> based on the old mips/au1x00.c driver which they replace.
>
> In general, dropping an old driver happens a bit later after the new
> driver comes in.  You can make the old one as deprecated at first.

Makes sense, just ignore patch 2 then ;)

Thanks,
        Manuel Lauss

From zajec5@gmail.com Fri Jul 22 00:30:19 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 22 Jul 2011 00:30:25 +0200 (CEST)
Received: from mail-pz0-f47.google.com ([209.85.210.47]:59328 "EHLO
        mail-pz0-f47.google.com" rhost-flags-OK-OK-OK-OK)
        by eddie.linux-mips.org with ESMTP id S1491159Ab1GUWaT convert rfc822-to-8bit
        (ORCPT <rfc822;linux-mips@linux-mips.org>);
        Fri, 22 Jul 2011 00:30:19 +0200
Received: by pzk36 with SMTP id 36so2598291pzk.34
        for <multiple recipients>; Thu, 21 Jul 2011 15:30:12 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=gmail.com; s=gamma;
        h=mime-version:in-reply-to:references:date:message-id:subject:from:to
         :cc:content-type:content-transfer-encoding;
        bh=UPCbbdoReEChMha5dc3fLsmVVvEEeyrM0cAPTPx7WG8=;
        b=Bl9Q6Dw+0Vbr6KyI1EKWwJtfMJlASze4eciePHmz3pVosBpmEKodf6+XicS8KhFWlp
         J6lZKlXDfIM7qtff+eq5oiWA2UgUwFGi+JOUzO525YMx5j5RAoNcRJMkLT9+zf4F0DDm
         M96gXtM/6MEI+jbY/s+qRKHbWLtEdvp6e4dSs=
MIME-Version: 1.0
Received: by 10.68.27.135 with SMTP id t7mr1214669pbg.183.1311287411635; Thu,
 21 Jul 2011 15:30:11 -0700 (PDT)
Received: by 10.68.49.98 with HTTP; Thu, 21 Jul 2011 15:30:11 -0700 (PDT)
In-Reply-To: <1310835342-18877-1-git-send-email-hauke@hauke-m.de>
References: <1310835342-18877-1-git-send-email-hauke@hauke-m.de>
Date:   Fri, 22 Jul 2011 00:30:11 +0200
Message-ID: <CACna6ryjYGuLc5c88eke=gjgwQyVD+A9afM6zCRhqV1THHgWvA@mail.gmail.com>
Subject: Re: [PATCH v2 00/11] bcma: add support for embedded devices like bcm4716
From:   =?UTF-8?B?UmFmYcWCIE1pxYJlY2tp?= <zajec5@gmail.com>
To:     Hauke Mehrtens <hauke@hauke-m.de>
Cc:     ralf@linux-mips.org, linux-wireless@vger.kernel.org,
        linux-mips@linux-mips.org, jonas.gorski@gmail.com, mb@bu3sch.de,
        george@znau.edu.ua, arend@broadcom.com,
        b43-dev@lists.infradead.org, bernhardloos@googlemail.com,
        arnd@arndb.de, julian.calaby@gmail.com, sshtylyov@mvista.com
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8BIT
X-archive-position: 30658
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: zajec5@gmail.com
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 15555
Content-Length: 1309
Lines: 30

2011/7/16 Hauke Mehrtens <hauke@hauke-m.de>:
> This patch series adds support for embedded devices like bcm47xx to
> bcma. Bcma is used on bcm4716 and bcm4718 SoCs as the system bus and
> replaced ssb used on older devices. With these patches my bcm4716
> device boots up till it tries to access the flash, because the serial
> flash chip is unsupported for now, this will be my next task. This adds
> support for MIPS cores, interrupt configuration and the serial console.
>
> These patches are not containing all functions needed to get the SoC to
> fully work and support every feature, but it is a good start.
> These patches are now integrated in OpenWrt for everyone how wants to
> test them.
>
> This was tested with a BCM4704 device (SoC with ssb bus), a BCM4716
> device and a pcie wireless card supported by bcma.
>
>
> @RafaÅ‚: If you are fine with the bcma patches could you please give
> your Signed-off on them.
>
> @Ralf: Could you please merger this into the mips tree so that it will be in linux-3.1.

ML for bcma is linux-wireless. Should we pass that patches "via" Ralf
or John? Using linux-wireless (and John's tree) makes more sense to
me, as we will work on the same tree and will get less merge
conflicts. However don't take me as Linux development style guru, just
my POV.

-- 
RafaÅ‚

From zajec5@gmail.com Fri Jul 22 00:35:08 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 22 Jul 2011 00:35:14 +0200 (CEST)
Received: from mail-pz0-f47.google.com ([209.85.210.47]:65105 "EHLO
        mail-pz0-f47.google.com" rhost-flags-OK-OK-OK-OK)
        by eddie.linux-mips.org with ESMTP id S1491159Ab1GUWfI convert rfc822-to-8bit
        (ORCPT <rfc822;linux-mips@linux-mips.org>);
        Fri, 22 Jul 2011 00:35:08 +0200
Received: by pzk36 with SMTP id 36so2604315pzk.34
        for <multiple recipients>; Thu, 21 Jul 2011 15:35:02 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=gmail.com; s=gamma;
        h=mime-version:in-reply-to:references:date:message-id:subject:from:to
         :cc:content-type:content-transfer-encoding;
        bh=U+fioFA7j6d9z9dxChpGgwyy5Htf/m81f2IsKdBcQGw=;
        b=FglgcHUnc4FHnyXFgnDNhNNpxVwn0jjaU0+RpjxdpngYyhjX5/h6l/zMNIp+QOWGCS
         ibU1zJtL5U1msVnG8ZS1n83C8h4Quvbxjhwcuq20nE2h1vmP7zTXHDESSgfrPqH4n2ln
         Zs/5brQnTd/0JEuqHt4P7Y9Abdxqhsrw4cGTs=
MIME-Version: 1.0
Received: by 10.68.13.193 with SMTP id j1mr1018277pbc.384.1311287701851; Thu,
 21 Jul 2011 15:35:01 -0700 (PDT)
Received: by 10.68.49.98 with HTTP; Thu, 21 Jul 2011 15:35:01 -0700 (PDT)
In-Reply-To: <1310835342-18877-4-git-send-email-hauke@hauke-m.de>
References: <1310835342-18877-1-git-send-email-hauke@hauke-m.de>
        <1310835342-18877-4-git-send-email-hauke@hauke-m.de>
Date:   Fri, 22 Jul 2011 00:35:01 +0200
Message-ID: <CACna6ryPABAx87b2+-gsTY5a5_qHTo61Otre-Pm+vYH8ad9hNg@mail.gmail.com>
Subject: Re: [PATCH v2 03/11] bcma: add functions to scan cores needed on SoCs
From:   =?UTF-8?B?UmFmYcWCIE1pxYJlY2tp?= <zajec5@gmail.com>
To:     Hauke Mehrtens <hauke@hauke-m.de>
Cc:     ralf@linux-mips.org, linux-wireless@vger.kernel.org,
        linux-mips@linux-mips.org, jonas.gorski@gmail.com, mb@bu3sch.de,
        george@znau.edu.ua, arend@broadcom.com,
        b43-dev@lists.infradead.org, bernhardloos@googlemail.com,
        arnd@arndb.de, julian.calaby@gmail.com, sshtylyov@mvista.com
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8BIT
X-archive-position: 30659
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: zajec5@gmail.com
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 15559
Content-Length: 639
Lines: 22

2011/7/16 Hauke Mehrtens <hauke@hauke-m.de>:
> @@ -159,5 +159,8 @@ static void bcma_pcicore_serdes_workaround(struct bcma_drv_pci *pc)
>
> Â void bcma_core_pci_init(struct bcma_drv_pci *pc)
> Â {
> + Â  Â  Â  if (pc->setup_done)
> + Â  Â  Â  Â  Â  Â  Â  return;
> Â  Â  Â  Â bcma_pcicore_serdes_workaround(pc);
> + Â  Â  Â  pc->setup_done = true;
> Â }

This won't apply to the upstream driver_pci.c. Fix is obvious for me
and you, but could be nice to don't bother John/Ralf.


> + Â  Â  Â  /* Scan for devices (cores) */
> + Â  Â  Â  err = bcma_bus_scan_early(bus, &match, core_cc);

Could you update the comment by the way?

-- 
RafaÅ‚

From zajec5@gmail.com Fri Jul 22 01:01:33 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 22 Jul 2011 01:01:43 +0200 (CEST)
Received: from mail-pz0-f47.google.com ([209.85.210.47]:38034 "EHLO
        mail-pz0-f47.google.com" rhost-flags-OK-OK-OK-OK)
        by eddie.linux-mips.org with ESMTP id S1491803Ab1GUXBd convert rfc822-to-8bit
        (ORCPT <rfc822;linux-mips@linux-mips.org>);
        Fri, 22 Jul 2011 01:01:33 +0200
Received: by pzk36 with SMTP id 36so2632686pzk.34
        for <multiple recipients>; Thu, 21 Jul 2011 16:01:27 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=gmail.com; s=gamma;
        h=mime-version:in-reply-to:references:date:message-id:subject:from:to
         :cc:content-type:content-transfer-encoding;
        bh=xXAj/GV5d3WYrKihUNBB/i9eDyWPuJp+MdcL7k9b7Hk=;
        b=mRlYAAPtJNzbkf6MguLAmpkMXqn+Ix38wW1gk5gCj+zJ/jmD9AC5ArXbEii4FrPZ7P
         hI+02i8Gz6HwCCZ6DkybjLKUjGhAduI+W7OE5GYBgg3UpK9zbKm7rWgbbqtUPWkJZSSH
         D56D4M6fFJjgbUU6vEg8xGokDQ5WTSGC/mXI4=
MIME-Version: 1.0
Received: by 10.68.27.135 with SMTP id t7mr1258335pbg.183.1311289286668; Thu,
 21 Jul 2011 16:01:26 -0700 (PDT)
Received: by 10.68.49.98 with HTTP; Thu, 21 Jul 2011 16:01:26 -0700 (PDT)
In-Reply-To: <1310835342-18877-2-git-send-email-hauke@hauke-m.de>
References: <1310835342-18877-1-git-send-email-hauke@hauke-m.de>
        <1310835342-18877-2-git-send-email-hauke@hauke-m.de>
Date:   Fri, 22 Jul 2011 01:01:26 +0200
Message-ID: <CACna6rxugXiGd87hk_d5tK8NM0m9v_hjJ8o7xyQhkn=j9ocOJg@mail.gmail.com>
Subject: Re: [PATCH v2 01/11] bcma: move parsing of EEPROM into own function.
From:   =?UTF-8?B?UmFmYcWCIE1pxYJlY2tp?= <zajec5@gmail.com>
To:     Hauke Mehrtens <hauke@hauke-m.de>
Cc:     ralf@linux-mips.org, linux-wireless@vger.kernel.org,
        linux-mips@linux-mips.org, jonas.gorski@gmail.com, mb@bu3sch.de,
        george@znau.edu.ua, arend@broadcom.com,
        b43-dev@lists.infradead.org, bernhardloos@googlemail.com,
        arnd@arndb.de, julian.calaby@gmail.com, sshtylyov@mvista.com
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8BIT
X-archive-position: 30660
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: zajec5@gmail.com
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 15592
Content-Length: 313
Lines: 11

2011/7/16 Hauke Mehrtens <hauke@hauke-m.de>:
> Move the parsing of the EEPROM data in scan function for one core into
> an own function. Now we are able to use it in some other scan function
> as well.
>
> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>

Acked-by: RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com>

-- 
RafaÅ‚

From zajec5@gmail.com Fri Jul 22 01:01:51 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 22 Jul 2011 01:02:05 +0200 (CEST)
Received: from mail-pz0-f47.google.com ([209.85.210.47]:38034 "EHLO
        mail-pz0-f47.google.com" rhost-flags-OK-OK-OK-OK)
        by eddie.linux-mips.org with ESMTP id S1491808Ab1GUXBv convert rfc822-to-8bit
        (ORCPT <rfc822;linux-mips@linux-mips.org>);
        Fri, 22 Jul 2011 01:01:51 +0200
Received: by mail-pz0-f47.google.com with SMTP id 36so2632686pzk.34
        for <multiple recipients>; Thu, 21 Jul 2011 16:01:50 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=gmail.com; s=gamma;
        h=mime-version:in-reply-to:references:date:message-id:subject:from:to
         :cc:content-type:content-transfer-encoding;
        bh=3B5fgtYd9zJZUmZzO+FS1IZV4/BoYfq/Dqf5LbXlv3Y=;
        b=WL0vB7dnvnrwDmde2zQbxUG3kbRrHFFFeO+481dUnMlYWJ5qkPUddwGYZEjYRDhVm5
         Apj2w8DLXaEn6HGuNpiWX9XLVbXWoWQ+SCv6XcBaGtpHZtIRU98NaUoN3wRuuVxUzhT5
         LXNjjjqGuWdJwjvsORCytTkJsWWpv4fsFh4Pg=
MIME-Version: 1.0
Received: by 10.68.27.232 with SMTP id w8mr1116258pbg.49.1311289310116; Thu,
 21 Jul 2011 16:01:50 -0700 (PDT)
Received: by 10.68.49.98 with HTTP; Thu, 21 Jul 2011 16:01:50 -0700 (PDT)
In-Reply-To: <1310835342-18877-3-git-send-email-hauke@hauke-m.de>
References: <1310835342-18877-1-git-send-email-hauke@hauke-m.de>
        <1310835342-18877-3-git-send-email-hauke@hauke-m.de>
Date:   Fri, 22 Jul 2011 01:01:50 +0200
Message-ID: <CACna6rzTqqHpqOfKNQi_T8uUEnbO_KXKGiwwMCbtWY7mX=NtSA@mail.gmail.com>
Subject: Re: [PATCH v2 02/11] bcma: move initializing of struct bcma_bus to
 own function.
From:   =?UTF-8?B?UmFmYcWCIE1pxYJlY2tp?= <zajec5@gmail.com>
To:     Hauke Mehrtens <hauke@hauke-m.de>
Cc:     ralf@linux-mips.org, linux-wireless@vger.kernel.org,
        linux-mips@linux-mips.org, jonas.gorski@gmail.com, mb@bu3sch.de,
        george@znau.edu.ua, arend@broadcom.com,
        b43-dev@lists.infradead.org, bernhardloos@googlemail.com,
        arnd@arndb.de, julian.calaby@gmail.com, sshtylyov@mvista.com
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8BIT
X-archive-position: 30661
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: zajec5@gmail.com
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 15593
Content-Length: 220
Lines: 9

2011/7/16 Hauke Mehrtens <hauke@hauke-m.de>:
> This makes it possible to use this code in some other method.
>
> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>

Acked-by: RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com>

-- 
RafaÅ‚

From zajec5@gmail.com Fri Jul 22 01:04:13 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 22 Jul 2011 01:04:17 +0200 (CEST)
Received: from mail-pz0-f47.google.com ([209.85.210.47]:57169 "EHLO
        mail-pz0-f47.google.com" rhost-flags-OK-OK-OK-OK)
        by eddie.linux-mips.org with ESMTP id S1491809Ab1GUXEN convert rfc822-to-8bit
        (ORCPT <rfc822;linux-mips@linux-mips.org>);
        Fri, 22 Jul 2011 01:04:13 +0200
Received: by pzk36 with SMTP id 36so2635399pzk.34
        for <multiple recipients>; Thu, 21 Jul 2011 16:04:07 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=gmail.com; s=gamma;
        h=mime-version:in-reply-to:references:date:message-id:subject:from:to
         :cc:content-type:content-transfer-encoding;
        bh=W6mFYfu+/QZTIyM9HjMNLrw1TvxxMZzc8gpkX1C+TX0=;
        b=sMpve5rI5ppfffO2z4l+N3tStwFM/c1RwmcEQOKDdz1xVUIXVUdQwQFEJ1KaPTrtFn
         ib7n+uCGHm1P+RBrTTa+YZk+oy975tk1bkmH3xAeAEe/GxQKLRe5aijNXcwDaD8uKkiE
         LoL+LdQKeRsRw4FKo4huDH67h7VHVoQYUtLpI=
MIME-Version: 1.0
Received: by 10.68.13.193 with SMTP id j1mr1051136pbc.384.1311289446834; Thu,
 21 Jul 2011 16:04:06 -0700 (PDT)
Received: by 10.68.49.98 with HTTP; Thu, 21 Jul 2011 16:04:06 -0700 (PDT)
In-Reply-To: <CACna6ryPABAx87b2+-gsTY5a5_qHTo61Otre-Pm+vYH8ad9hNg@mail.gmail.com>
References: <1310835342-18877-1-git-send-email-hauke@hauke-m.de>
        <1310835342-18877-4-git-send-email-hauke@hauke-m.de>
        <CACna6ryPABAx87b2+-gsTY5a5_qHTo61Otre-Pm+vYH8ad9hNg@mail.gmail.com>
Date:   Fri, 22 Jul 2011 01:04:06 +0200
Message-ID: <CACna6rxRjxEoh+nrkk_3w5p18DkOb8G2qFGsKkK3tmLCCM1ivQ@mail.gmail.com>
Subject: Re: [PATCH v2 03/11] bcma: add functions to scan cores needed on SoCs
From:   =?UTF-8?B?UmFmYcWCIE1pxYJlY2tp?= <zajec5@gmail.com>
To:     Hauke Mehrtens <hauke@hauke-m.de>
Cc:     ralf@linux-mips.org, linux-wireless@vger.kernel.org,
        linux-mips@linux-mips.org, jonas.gorski@gmail.com, mb@bu3sch.de,
        george@znau.edu.ua, arend@broadcom.com,
        b43-dev@lists.infradead.org, bernhardloos@googlemail.com,
        arnd@arndb.de, julian.calaby@gmail.com, sshtylyov@mvista.com
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8BIT
X-archive-position: 30662
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: zajec5@gmail.com
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 15606
Content-Length: 760
Lines: 23

W dniu 22 lipca 2011 00:35 uÅ¼ytkownik RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> napisaÅ‚:
> 2011/7/16 Hauke Mehrtens <hauke@hauke-m.de>:
>> @@ -159,5 +159,8 @@ static void bcma_pcicore_serdes_workaround(struct bcma_drv_pci *pc)
>>
>> Â void bcma_core_pci_init(struct bcma_drv_pci *pc)
>> Â {
>> + Â  Â  Â  if (pc->setup_done)
>> + Â  Â  Â  Â  Â  Â  Â  return;
>> Â  Â  Â  Â bcma_pcicore_serdes_workaround(pc);
>> + Â  Â  Â  pc->setup_done = true;
>> Â }
>
> This won't apply to the upstream driver_pci.c. Fix is obvious for me
> and you, but could be nice to don't bother John/Ralf.

Acked-by: RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com>
After you rebase patch.

Please, be careful about this place. "git am" takes it as fuzzy and
applied in the incorrect place!

-- 
RafaÅ‚

From zajec5@gmail.com Fri Jul 22 01:20:34 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 22 Jul 2011 01:20:41 +0200 (CEST)
Received: from mail-pz0-f47.google.com ([209.85.210.47]:58665 "EHLO
        mail-pz0-f47.google.com" rhost-flags-OK-OK-OK-OK)
        by eddie.linux-mips.org with ESMTP id S1491763Ab1GUXUe convert rfc822-to-8bit
        (ORCPT <rfc822;linux-mips@linux-mips.org>);
        Fri, 22 Jul 2011 01:20:34 +0200
Received: by pzk36 with SMTP id 36so2652333pzk.34
        for <multiple recipients>; Thu, 21 Jul 2011 16:20:28 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=gmail.com; s=gamma;
        h=mime-version:in-reply-to:references:date:message-id:subject:from:to
         :cc:content-type:content-transfer-encoding;
        bh=iDUBJstFb96wiDWZ5wvxD0CUlwTR7vUK7rYmBP2pSxg=;
        b=f2Ci96Owywgoy6cnMbrl2DmKS3Xmlp06ox4YPY5oR2JHgZfp8uWQGi84YeAQHMlv1F
         CJDFk++pPmiCNGcOkFoSoBPBWIuL8iYYQQboAM6hY6Xnrlu7C4NBnl9lQQtsY90qzDKE
         mx936J9ihjBPPkpGH3Eqd24kRfkZgqZqEctrY=
MIME-Version: 1.0
Received: by 10.68.12.225 with SMTP id b1mr1199176pbc.116.1311290428183; Thu,
 21 Jul 2011 16:20:28 -0700 (PDT)
Received: by 10.68.49.98 with HTTP; Thu, 21 Jul 2011 16:20:28 -0700 (PDT)
In-Reply-To: <1310835342-18877-5-git-send-email-hauke@hauke-m.de>
References: <1310835342-18877-1-git-send-email-hauke@hauke-m.de>
        <1310835342-18877-5-git-send-email-hauke@hauke-m.de>
Date:   Fri, 22 Jul 2011 01:20:28 +0200
Message-ID: <CACna6rzf8=FpWn-=agGi4GESiw0-XG1QDS81fGTkV2J6dgtiOw@mail.gmail.com>
Subject: Re: [PATCH v2 04/11] bcma: add SOC bus
From:   =?UTF-8?B?UmFmYcWCIE1pxYJlY2tp?= <zajec5@gmail.com>
To:     Hauke Mehrtens <hauke@hauke-m.de>
Cc:     ralf@linux-mips.org, linux-wireless@vger.kernel.org,
        linux-mips@linux-mips.org, jonas.gorski@gmail.com, mb@bu3sch.de,
        george@znau.edu.ua, arend@broadcom.com,
        b43-dev@lists.infradead.org, bernhardloos@googlemail.com,
        arnd@arndb.de, julian.calaby@gmail.com, sshtylyov@mvista.com
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8BIT
X-archive-position: 30663
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: zajec5@gmail.com
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 15615
Content-Length: 976
Lines: 30

2011/7/16 Hauke Mehrtens <hauke@hauke-m.de>:
> This patch adds support for using bcma on a Broadcom SoC as the system
> bus. An SoC like the bcm4716 could register this bus and use it to
> searches for the bcma cores and register the devices on this bus.
>
> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>

Acked-by: RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com>

Cleaning enum bcma_hosttype would be nice (see below), but we cal
always easily do this later.


> diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h
> index 6bd7b7f..73fda1c 100644
> --- a/include/linux/bcma/bcma.h
> +++ b/include/linux/bcma/bcma.h
> @@ -16,6 +16,7 @@ enum bcma_hosttype {
> Â  Â  Â  Â BCMA_HOSTTYPE_NONE,
> Â  Â  Â  Â BCMA_HOSTTYPE_PCI,
> Â  Â  Â  Â BCMA_HOSTTYPE_SDIO,
> + Â  Â  Â  BCMA_HOSTTYPE_SOC,
> Â };

I wanted to use BCMA_HOSTTYPE_NONE for SoCs (embedded systems), when I
decided to add it. As we decided SOC is better name than NONE, you
could drop it (NONE one).

-- 
RafaÅ‚

From lars@metafoo.de Fri Jul 22 01:56:19 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 22 Jul 2011 01:56:26 +0200 (CEST)
Received: from mailhost.informatik.uni-hamburg.de ([134.100.9.70]:32944 "EHLO
        mailhost.informatik.uni-hamburg.de" rhost-flags-OK-OK-OK-OK)
        by eddie.linux-mips.org with ESMTP id S1491808Ab1GUX4T (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Fri, 22 Jul 2011 01:56:19 +0200
Received: from localhost (localhost [127.0.0.1])
        by mailhost.informatik.uni-hamburg.de (Postfix) with ESMTP id 4F0A57FF;
        Fri, 22 Jul 2011 01:56:13 +0200 (CEST)
X-Virus-Scanned: amavisd-new at informatik.uni-hamburg.de
Received: from mailhost.informatik.uni-hamburg.de ([127.0.0.1])
        by localhost (mailhost.informatik.uni-hamburg.de [127.0.0.1]) (amavisd-new, port 10024)
        with LMTP id 1FdFKk0KShTp; Fri, 22 Jul 2011 01:56:12 +0200 (CEST)
Received: from [192.168.123.134] (e177126024.adsl.alicedsl.de [85.177.126.24])
        (using TLSv1 with cipher DHE-RSA-CAMELLIA256-SHA (256/256 bits))
        (Client did not present a certificate)
        (Authenticated sender: 7clausen)
        by mailhost.informatik.uni-hamburg.de (Postfix) with ESMTPSA id 533177FE;
        Fri, 22 Jul 2011 01:55:51 +0200 (CEST)
Message-ID: <4E28BC1F.50804@metafoo.de>
Date:   Fri, 22 Jul 2011 01:54:07 +0200
From:   Lars-Peter Clausen <lars@metafoo.de>
User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.16) Gecko/20110702 Icedove/3.0.11
MIME-Version: 1.0
To:     Manuel Lauss <manuel.lauss@googlemail.com>
CC:     alsa-devel@vger.kernel.org, Ralf Baechle <ralf@linux-mips.org>,
        Linux-MIPS <linux-mips@linux-mips.org>,
        Mark Brown <broonie@opensource.wolfsonmicro.com>,
        Liam Girdwood <lrg@ti.com>
Subject: Re: [PATCH V2 1/2] ALSA: Alchemy AC97C/I2SC audio support
References: <1311266050-22199-1-git-send-email-manuel.lauss@googlemail.com> <1311266050-22199-2-git-send-email-manuel.lauss@googlemail.com>
In-Reply-To: <1311266050-22199-2-git-send-email-manuel.lauss@googlemail.com>
X-Enigmail-Version: 1.0.1
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit
X-archive-position: 30664
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: lars@metafoo.de
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 15627
Content-Length: 8671
Lines: 322

You should always Cc Mark and Liam on ASoC patch. Also the proper commit title
prefix is ASoC.

On 07/21/2011 06:34 PM, Manuel Lauss wrote:
> This patch adds ASoC support for the AC97 and I2S controllers
> on the old Au1000/Au1500/Au1100 chips and a universal machine
> driver for the Db1000/Db1500/Db1100 boards.
> 
> AC97 Tested on a Db1500.  I2S untested since none of the boards
> actually have and I2S codec wired up.
> 
> Signed-off-by: Manuel Lauss <manuel.lauss@googlemail.com>
> ---
> V2: added untested I2S controller driver for completeness, removed the audio
>     defines from the au1000 header as well.
> 
>  arch/mips/alchemy/devboards/db1x00/platform.c |   37 ++
>  arch/mips/include/asm/mach-au1x00/au1000.h    |   61 ----
>  sound/soc/au1x/Kconfig                        |   28 ++
>  sound/soc/au1x/Makefile                       |   10 +
>  sound/soc/au1x/ac97c.c                        |  398 +++++++++++++++++++++
>  sound/soc/au1x/db1000.c                       |   75 ++++
>  sound/soc/au1x/dma.c                          |  470 +++++++++++++++++++++++++
>  sound/soc/au1x/i2sc.c                         |  353 +++++++++++++++++++
>  sound/soc/au1x/psc.h                          |   31 ++-
>  9 files changed, 1393 insertions(+), 70 deletions(-)
>  create mode 100644 sound/soc/au1x/ac97c.c
>  create mode 100644 sound/soc/au1x/db1000.c
>  create mode 100644 sound/soc/au1x/dma.c
>  create mode 100644 sound/soc/au1x/i2sc.c

It might make sense to split this into multiple patches. Especially the
platform part should be put in a seperate patch, since there isn't really any
compile time dependency to the other parts it could go via the MIPS tree.

> diff --git a/sound/soc/au1x/ac97c.c b/sound/soc/au1x/ac97c.c
> new file mode 100644
> index 0000000..8fc25d0
> --- /dev/null
> +++ b/sound/soc/au1x/ac97c.c
> @@ -0,0 +1,398 @@
> +/*
> + * Au1000/Au1500/Au1100 AC97C controller driver for ASoC
> + *
> + * (c) 2011 Manuel Lauss <manuel.lauss@googlemail.com>
> + *
> + * based on the old ALSA driver by Charles Eidsness.
> + */
> +
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/device.h>
> +#include <linux/delay.h>
> +#include <linux/mutex.h>
> +#include <linux/platform_device.h>
> +#include <linux/suspend.h>
> +#include <sound/core.h>
> +#include <sound/pcm.h>
> +#include <sound/initval.h>
> +#include <sound/soc.h>
> +#include <asm/mach-au1x00/au1000.h>
> +#include <asm/mach-au1x00/au1xxx_psc.h>
> +
> +#include "psc.h"
> +
> +/*#define AC_DEBUG*/
> +
> +#define MSG(x...)	printk(KERN_ERR "ac97c: " x)

dev_err or pr_err

> +#ifdef AC_DEBUG
> +#define DBG(x...)	MSG(x)
> +#else
> +#define DBG(x...)	do {} while (0)
> +#endif

dev_dbg or pr_dbg

> [...]
> +
> +/* how often to retry failed codec register reads/writes */
> +#define AC97_RW_RETRIES	5
> +
> +#define AC97_DIR	\
> +	(SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE)
Unused

>[...]
> +
> +static int au1xac97c_hw_params(struct snd_pcm_substream *substream,
> +			       struct snd_pcm_hw_params *params,
> +			       struct snd_soc_dai *dai)
> +{
> +	return 0;
> +}
> +
> +static int au1xac97c_trigger(struct snd_pcm_substream *substream,
> +			     int cmd, struct snd_soc_dai *dai)
> +{
> +	return 0;
> +}
> +

If you don't want to do anything in the callbacks just leave them out.

> +static int au1xac97c_dai_probe(struct snd_soc_dai *dai)
> +{
> +	return ac97c_workdata ? 0 : -ENODEV;
> +}
> +
> +static struct snd_soc_dai_ops au1xac97c_dai_ops = {
const

> +	.trigger	= au1xac97c_trigger,
> +	.hw_params	= au1xac97c_hw_params,
> +};
> +
> [...]
> diff --git a/sound/soc/au1x/db1000.c b/sound/soc/au1x/db1000.c
> new file mode 100644
> index 0000000..9368b5d
> [...]
> +static int __init db1000_audio_load(void)
> +{
> +	int ret, id;
> +
> +	/* impostor check */
> +	id = BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI));
> +
> +	ret = -ENOMEM;
> +	db1000_asoc97_dev = platform_device_alloc("soc-audio", 0);

New drivers shouldn't user soc-audio anymore, just register a normal platform
device driver.

> +	if (!db1000_asoc97_dev)
> +		goto out;
> +
> +	platform_set_drvdata(db1000_asoc97_dev, &db1000_ac97_machine);
> +	ret = platform_device_add(db1000_asoc97_dev);
> +
> +	if (ret) {
> +		platform_device_put(db1000_asoc97_dev);
> +		db1000_asoc97_dev = NULL;
> +	}
> +out:
> +	return ret;
> +}
> +
> +static void __exit db1000_audio_unload(void)
> +{
> +	platform_device_unregister(db1000_asoc97_dev);
> +}
> +
> +module_init(db1000_audio_load);
> +module_exit(db1000_audio_unload);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("DB1000/DB1500/DB1100 ASoC audio support");
> +MODULE_AUTHOR("Manuel Lauss");
> diff --git a/sound/soc/au1x/dma.c b/sound/soc/au1x/dma.c
> new file mode 100644
> index 0000000..0f7d90a
> --- /dev/null
> +++ b/sound/soc/au1x/dma.c
> @@ -0,0 +1,470 @@
> [...]
> +
> +static struct platform_driver alchemy_ac97pcm_driver = {
> +	.driver	= {
> +		.name	= AC97C_DMANAME,
> +		.owner	= THIS_MODULE,
> +	},
> +	.probe		= alchemy_pcm_drvprobe,
> +	.remove		= __devexit_p(alchemy_pcm_drvremove),
> +};
> +
> +static struct platform_driver alchemy_i2spcm_driver = {
> +	.driver	= {
> +		.name	= I2SC_DMANAME,
> +		.owner	= THIS_MODULE,
> +	},
> +	.probe		= alchemy_pcm_drvprobe,
> +	.remove		= __devexit_p(alchemy_pcm_drvremove),
> +};

You shouldn't really have to register two identical drivers for this. If you
really want to be able to instantiate the driver with two different names use
platform_device_id. But in my opinion it should be enough to just have one
generic name, since there is nothing AC97 or I2S specific in this driver.

> [...]
> +
> +struct platform_device *alchemy_pcm_add(struct platform_device *pdev, int type)
> +{
+	struct resource *res, *r;
+	struct platform_device *pd;
+	char *pdevname;
+	int id[2];
+	int ret;
+
+	r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+	if (!r)
+		return NULL;
+	id[0] = r->start;
+
+	r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+	if (!r)
+		return NULL;
+	id[1] = r->start;
+
+	res = kzalloc(sizeof(struct resource) * 2, GFP_KERNEL);
+	if (!res)
+		return NULL;
+
+	res[0].start = res[0].end = id[0];
+	res[1].start = res[1].end = id[1];
+	res[0].flags = res[1].flags = IORESOURCE_DMA;
+
+	/* "alchemy-pcm-ac97" or "alchemy-pcm-i2s" */
+	pdevname = (type == 0) ? AC97C_DMANAME : I2SC_DMANAME;
+	pd = platform_device_alloc(pdevname, -1);
+	if (!pd)
+		goto out;
+
+	pd->resource = res;
+	pd->num_resources = 2;
+
+	ret = platform_device_add(pd);
+	if (!ret)
+		return pd;
+
+	platform_device_put(pd);
+out:
+	kfree(res);
+	return NULL;
> +}

This function looks a bit fishy. The pcm driver should be registered by the
platform code file as well. If you need different DMA regions for I2C and AC97
use snd_soc_dai_set_dma_data and snd_soc_dai_get_dma_data to pass them to the
PCM driver from the I2S or AC97 driver.

> [...]
> diff --git a/sound/soc/au1x/i2sc.c b/sound/soc/au1x/i2sc.c
> new file mode 100644
> index 0000000..1a31d51
> --- /dev/null
> +++ b/sound/soc/au1x/i2sc.c
> @@ -0,0 +1,353 @@
> [...]
> +
> +/* supported I2S DAI hardware formats */
> +#define AU1XI2SC_DAIFMT \
> +	(SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J |	\
> +	 SND_SOC_DAIFMT_NB_NF)
Unused


> +
> +/* supported I2S direction */
> +#define AU1XI2SC_DIR \
> +	(SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE)
Unused

> +
> +#define AU1XI2SC_RATES \
> +	SNDRV_PCM_RATE_8000_192000
> +
> +#define AU1XI2SC_FMTS \
> +	SNDRV_PCM_FMTBIT_S16_LE
> +
> +struct i2sc_ctx {
> +	void __iomem *mmio;
> +	unsigned long cfg, rate;
> +	struct platform_device *dmapd;
> +};
> +
> [...]
> +
> +static int au1xi2s_hw_params(struct snd_pcm_substream *substream,
> +			     struct snd_pcm_hw_params *params,
> +			     struct snd_soc_dai *dai)
> +{
> +	struct i2sc_ctx *ctx = snd_soc_dai_get_drvdata(dai);
> +	unsigned long stat, v;
> +
> +	v = msbits_to_reg(params->msbits);
> +	/* check if the PSC is already streaming data */

Use .symmetric_rates = 1 in your dai_driver struct for this.

> +	stat = RD(ctx, I2S_CONFIG);
> +	if (stat & (CFG_TN | CFG_RN)) {
> +		/* reject parameters not currently set up in hardware */
> +		if ((ctx->rate != params_rate(params)) ||
> +		    ((stat & CFG_SZ_MASK) != v))
> +			return -EINVAL;
> +	} else {
> +		/* set sample bitdepth */
> +		ctx->cfg &= ~CFG_SZ_MASK;
> +		if (v)
> +			ctx->cfg |= v;
> +		else
> +			return -EINVAL;
> +		/* remember current rate for other stream */
> +		ctx->rate = params_rate(params);
> +	}
> +	return 0;
> +}
> +
> +static struct snd_soc_dai_ops au1xi2s_dai_ops = {
const

> +	.trigger	= au1xi2s_trigger,
> +	.hw_params	= au1xi2s_hw_params,
> +	.set_fmt	= au1xi2s_set_fmt,
> +};
> +
> [...]

From manuel.lauss@googlemail.com Fri Jul 22 08:54:06 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 22 Jul 2011 08:54:14 +0200 (CEST)
Received: from mail-yi0-f49.google.com ([209.85.218.49]:42441 "EHLO
        mail-yi0-f49.google.com" rhost-flags-OK-OK-OK-OK)
        by eddie.linux-mips.org with ESMTP id S1491092Ab1GVGyG convert rfc822-to-8bit
        (ORCPT <rfc822;linux-mips@linux-mips.org>);
        Fri, 22 Jul 2011 08:54:06 +0200
Received: by yib17 with SMTP id 17so1153209yib.36
        for <multiple recipients>; Thu, 21 Jul 2011 23:54:00 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=googlemail.com; s=gamma;
        h=mime-version:in-reply-to:references:date:message-id:subject:from:to
         :cc:content-type:content-transfer-encoding;
        bh=do8nTYkuC5D+RyAV2dF6fgbyjaXEo2CRY8ueIVtsYSA=;
        b=cc7zBSLpHBoYdKWFNKVqWa+Q7I6e1sZ6NLZb7L7VwxiPJEE/QYiKtdXFA/FsGKz52U
         sET2j7JCvdk63nt7xcrUPwI0LvR+IS7wpnySG3P4Jt0XUjkIEF2A+/4GKRcx66SkF2Di
         FFqAvPzPB60hfTQ3xymawizMFOxUcakI//yRM=
MIME-Version: 1.0
Received: by 10.236.125.166 with SMTP id z26mr1551869yhh.259.1311317640366;
 Thu, 21 Jul 2011 23:54:00 -0700 (PDT)
Received: by 10.236.95.168 with HTTP; Thu, 21 Jul 2011 23:54:00 -0700 (PDT)
In-Reply-To: <4E28BC1F.50804@metafoo.de>
References: <1311266050-22199-1-git-send-email-manuel.lauss@googlemail.com>
        <1311266050-22199-2-git-send-email-manuel.lauss@googlemail.com>
        <4E28BC1F.50804@metafoo.de>
Date:   Fri, 22 Jul 2011 08:54:00 +0200
Message-ID: <CAOLZvyGxPB1oCKg4BtvBjiuKTb=8urq6L8YQHYbMfmQQigo0kA@mail.gmail.com>
Subject: Re: [PATCH V2 1/2] ALSA: Alchemy AC97C/I2SC audio support
From:   Manuel Lauss <manuel.lauss@googlemail.com>
To:     Lars-Peter Clausen <lars@metafoo.de>
Cc:     alsa-devel@vger.kernel.org, Ralf Baechle <ralf@linux-mips.org>,
        Linux-MIPS <linux-mips@linux-mips.org>,
        Mark Brown <broonie@opensource.wolfsonmicro.com>,
        Liam Girdwood <lrg@ti.com>
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 8BIT
X-archive-position: 30665
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: manuel.lauss@googlemail.com
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 15793
Content-Length: 3516
Lines: 110

On Fri, Jul 22, 2011 at 1:54 AM, Lars-Peter Clausen <lars@metafoo.de> wrote:
>> diff --git a/sound/soc/au1x/db1000.c b/sound/soc/au1x/db1000.c
>> +     ret = -ENOMEM;
>> +     db1000_asoc97_dev = platform_device_alloc("soc-audio", 0);
>
> New drivers shouldn't user soc-audio anymore, just register a normal platform
> device driver.

Can you point to an example of the new way?


>> diff --git a/sound/soc/au1x/dma.c b/sound/soc/au1x/dma.c
>> new file mode 100644
>> index 0000000..0f7d90a
>> --- /dev/null
>> +++ b/sound/soc/au1x/dma.c
>> @@ -0,0 +1,470 @@
>> [...]
>> +
>> +static struct platform_driver alchemy_ac97pcm_driver = {
>> +     .driver = {
>> +             .name   = AC97C_DMANAME,
>> +             .owner  = THIS_MODULE,
>> +     },
>> +     .probe          = alchemy_pcm_drvprobe,
>> +     .remove         = __devexit_p(alchemy_pcm_drvremove),
>> +};
>> +
>> +static struct platform_driver alchemy_i2spcm_driver = {
>> +     .driver = {
>> +             .name   = I2SC_DMANAME,
>> +             .owner  = THIS_MODULE,
>> +     },
>> +     .probe          = alchemy_pcm_drvprobe,
>> +     .remove         = __devexit_p(alchemy_pcm_drvremove),
>> +};
>
> You shouldn't really have to register two identical drivers for this. If you
> really want to be able to instantiate the driver with two different names use
> platform_device_id. But in my opinion it should be enough to just have one
> generic name, since there is nothing AC97 or I2S specific in this driver.

I need a unique name for the DMA device in soc_dai_link.  This was the
easiest way. Especially since both ac97 and i2s can be active at
runtime.


>> [...]
>> +
>> +struct platform_device *alchemy_pcm_add(struct platform_device *pdev, int type)
>> +{
> +       struct resource *res, *r;
> +       struct platform_device *pd;
> +       char *pdevname;
> +       int id[2];
> +       int ret;
> +
> +       r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
> +       if (!r)
> +               return NULL;
> +       id[0] = r->start;
> +
> +       r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
> +       if (!r)
> +               return NULL;
> +       id[1] = r->start;
> +
> +       res = kzalloc(sizeof(struct resource) * 2, GFP_KERNEL);
> +       if (!res)
> +               return NULL;
> +
> +       res[0].start = res[0].end = id[0];
> +       res[1].start = res[1].end = id[1];
> +       res[0].flags = res[1].flags = IORESOURCE_DMA;
> +
> +       /* "alchemy-pcm-ac97" or "alchemy-pcm-i2s" */
> +       pdevname = (type == 0) ? AC97C_DMANAME : I2SC_DMANAME;
> +       pd = platform_device_alloc(pdevname, -1);
> +       if (!pd)
> +               goto out;
> +
> +       pd->resource = res;
> +       pd->num_resources = 2;
> +
> +       ret = platform_device_add(pd);
> +       if (!ret)
> +               return pd;
> +
> +       platform_device_put(pd);
> +out:
> +       kfree(res);
> +       return NULL;
>> +}
>
> This function looks a bit fishy. The pcm driver should be registered by the
> platform code file as well. If you need different DMA regions for I2C and AC97
> use snd_soc_dai_set_dma_data and snd_soc_dai_get_dma_data to pass them to the
> PCM driver from the I2S or AC97 driver.

I like to pass the DMA id's along with the ac97/i2s resource
information (since they
belong together anyway). As an added benefit I get a sensibly named dma device
with the correct DMA information, all by simply registering the ac97
platform device.

I'll think about a way to change it.


Thank you!
      Manuel Lauss

From lars@metafoo.de Fri Jul 22 09:43:07 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 22 Jul 2011 09:43:15 +0200 (CEST)
Received: from mailhost.informatik.uni-hamburg.de ([134.100.9.70]:45899 "EHLO
        mailhost.informatik.uni-hamburg.de" rhost-flags-OK-OK-OK-OK)
        by eddie.linux-mips.org with ESMTP id S1491002Ab1GVHnH (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Fri, 22 Jul 2011 09:43:07 +0200
Received: from localhost (localhost [127.0.0.1])
        by mailhost.informatik.uni-hamburg.de (Postfix) with ESMTP id 6EDF8EF9;
        Fri, 22 Jul 2011 09:43:01 +0200 (CEST)
X-Virus-Scanned: amavisd-new at informatik.uni-hamburg.de
Received: from mailhost.informatik.uni-hamburg.de ([127.0.0.1])
        by localhost (mailhost.informatik.uni-hamburg.de [127.0.0.1]) (amavisd-new, port 10024)
        with LMTP id Mc9ZhT7eCBLJ; Fri, 22 Jul 2011 09:43:01 +0200 (CEST)
Received: from [192.168.123.134] (e177126024.adsl.alicedsl.de [85.177.126.24])
        (using TLSv1 with cipher DHE-RSA-CAMELLIA256-SHA (256/256 bits))
        (Client did not present a certificate)
        (Authenticated sender: 7clausen)
        by mailhost.informatik.uni-hamburg.de (Postfix) with ESMTPSA id 419BDEF3;
        Fri, 22 Jul 2011 09:42:36 +0200 (CEST)
Message-ID: <4E292984.5020708@metafoo.de>
Date:   Fri, 22 Jul 2011 09:40:52 +0200
From:   Lars-Peter Clausen <lars@metafoo.de>
User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.16) Gecko/20110702 Icedove/3.0.11
MIME-Version: 1.0
To:     Manuel Lauss <manuel.lauss@googlemail.com>
CC:     alsa-devel@vger.kernel.org, Ralf Baechle <ralf@linux-mips.org>,
        Linux-MIPS <linux-mips@linux-mips.org>,
        Mark Brown <broonie@opensource.wolfsonmicro.com>,
        Liam Girdwood <lrg@ti.com>
Subject: Re: [PATCH V2 1/2] ALSA: Alchemy AC97C/I2SC audio support
References: <1311266050-22199-1-git-send-email-manuel.lauss@googlemail.com>        <1311266050-22199-2-git-send-email-manuel.lauss@googlemail.com>        <4E28BC1F.50804@metafoo.de> <CAOLZvyGxPB1oCKg4BtvBjiuKTb=8urq6L8YQHYbMfmQQigo0kA@mail.gmail.com>
In-Reply-To: <CAOLZvyGxPB1oCKg4BtvBjiuKTb=8urq6L8YQHYbMfmQQigo0kA@mail.gmail.com>
X-Enigmail-Version: 1.0.1
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit
X-archive-position: 30666
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: lars@metafoo.de
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 15801
Content-Length: 4445
Lines: 125

On 07/22/2011 08:54 AM, Manuel Lauss wrote:
> On Fri, Jul 22, 2011 at 1:54 AM, Lars-Peter Clausen <lars@metafoo.de> wrote:
>>> diff --git a/sound/soc/au1x/db1000.c b/sound/soc/au1x/db1000.c
>>> +     ret = -ENOMEM;
>>> +     db1000_asoc97_dev = platform_device_alloc("soc-audio", 0);
>>
>> New drivers shouldn't user soc-audio anymore, just register a normal platform
>> device driver.
> 
> Can you point to an example of the new way?
> 

sound/soc/samsung/speyside.c

> 
>>> diff --git a/sound/soc/au1x/dma.c b/sound/soc/au1x/dma.c
>>> new file mode 100644
>>> index 0000000..0f7d90a
>>> --- /dev/null
>>> +++ b/sound/soc/au1x/dma.c
>>> @@ -0,0 +1,470 @@
>>> [...]
>>> +
>>> +static struct platform_driver alchemy_ac97pcm_driver = {
>>> +     .driver = {
>>> +             .name   = AC97C_DMANAME,
>>> +             .owner  = THIS_MODULE,
>>> +     },
>>> +     .probe          = alchemy_pcm_drvprobe,
>>> +     .remove         = __devexit_p(alchemy_pcm_drvremove),
>>> +};
>>> +
>>> +static struct platform_driver alchemy_i2spcm_driver = {
>>> +     .driver = {
>>> +             .name   = I2SC_DMANAME,
>>> +             .owner  = THIS_MODULE,
>>> +     },
>>> +     .probe          = alchemy_pcm_drvprobe,
>>> +     .remove         = __devexit_p(alchemy_pcm_drvremove),
>>> +};
>>
>> You shouldn't really have to register two identical drivers for this. If you
>> really want to be able to instantiate the driver with two different names use
>> platform_device_id. But in my opinion it should be enough to just have one
>> generic name, since there is nothing AC97 or I2S specific in this driver.
> 
> I need a unique name for the DMA device in soc_dai_link.  This was the
> easiest way. Especially since both ac97 and i2s can be active at
> runtime.

If you want to instantiate two pcm drivers you can just give the devices
different ids. As there is nothing I2C or AC97 specific in the pcm driver it
should not matter which one is used for what, if two devices are active at the
same time.
Right now you need to know which one is which, because you instantiate the
driver with either the I2C or AC97 DMA addresses, but if you use
snd_soc_dai_get_dma_data as described below and pass the DMA address at runtime
this issue will go away.

> 
> 
>>> [...]
>>> +
>>> +struct platform_device *alchemy_pcm_add(struct platform_device *pdev, int type)
>>> +{
>> +       struct resource *res, *r;
>> +       struct platform_device *pd;
>> +       char *pdevname;
>> +       int id[2];
>> +       int ret;
>> +
>> +       r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
>> +       if (!r)
>> +               return NULL;
>> +       id[0] = r->start;
>> +
>> +       r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
>> +       if (!r)
>> +               return NULL;
>> +       id[1] = r->start;
>> +
>> +       res = kzalloc(sizeof(struct resource) * 2, GFP_KERNEL);
>> +       if (!res)
>> +               return NULL;
>> +
>> +       res[0].start = res[0].end = id[0];
>> +       res[1].start = res[1].end = id[1];
>> +       res[0].flags = res[1].flags = IORESOURCE_DMA;
>> +
>> +       /* "alchemy-pcm-ac97" or "alchemy-pcm-i2s" */
>> +       pdevname = (type == 0) ? AC97C_DMANAME : I2SC_DMANAME;
>> +       pd = platform_device_alloc(pdevname, -1);
>> +       if (!pd)
>> +               goto out;
>> +
>> +       pd->resource = res;
>> +       pd->num_resources = 2;
>> +
>> +       ret = platform_device_add(pd);
>> +       if (!ret)
>> +               return pd;
>> +
>> +       platform_device_put(pd);
>> +out:
>> +       kfree(res);
>> +       return NULL;
>>> +}
>>
>> This function looks a bit fishy. The pcm driver should be registered by the
>> platform code file as well. If you need different DMA regions for I2C and AC97
>> use snd_soc_dai_set_dma_data and snd_soc_dai_get_dma_data to pass them to the
>> PCM driver from the I2S or AC97 driver.
> 
> I like to pass the DMA id's along with the ac97/i2s resource
> information (since they
> belong together anyway). As an added benefit I get a sensibly named dma device
> with the correct DMA information, all by simply registering the ac97
> platform device.

There is nothing wrong with passing the DMA ids along with the other AC97/I2C
resources. At least for the AC97 and I2C driver. But the PCM driver should use
snd_soc_dai_get_dma_data to get the DMA addresses at runtime rather then during
device instantiation. Take a look at how other platforms handle this.

- Lars

From manuel.lauss@googlemail.com Fri Jul 22 09:56:35 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 22 Jul 2011 09:56:40 +0200 (CEST)
Received: from mail-gy0-f177.google.com ([209.85.160.177]:37607 "EHLO
        mail-gy0-f177.google.com" rhost-flags-OK-OK-OK-OK)
        by eddie.linux-mips.org with ESMTP id S1491002Ab1GVH4f convert rfc822-to-8bit
        (ORCPT <rfc822;linux-mips@linux-mips.org>);
        Fri, 22 Jul 2011 09:56:35 +0200
Received: by gya1 with SMTP id 1so1168658gya.36
        for <multiple recipients>; Fri, 22 Jul 2011 00:56:28 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=googlemail.com; s=gamma;
        h=mime-version:in-reply-to:references:date:message-id:subject:from:to
         :cc:content-type:content-transfer-encoding;
        bh=bIo0M9imLnybeQU7Bb/rFF1JTPYRXLqQyWQLp9+a0zw=;
        b=IMezZtcSpIwHxLDTJZ83BOMR2a++g/4307v0kf6jAYPOiiR73JnR1vhgxKLBh+qB/y
         OPYWz/IKzm81PF4PEi4fZEoRiNW/EVw1REKcN2fqiWp2aSwsiqADgc2IDcwKds/XjnJf
         2jhYujJICQEzzUZHiDHohlHKWWeUmH9N61MkE=
MIME-Version: 1.0
Received: by 10.236.125.134 with SMTP id z6mr1735591yhh.58.1311321388771; Fri,
 22 Jul 2011 00:56:28 -0700 (PDT)
Received: by 10.236.95.168 with HTTP; Fri, 22 Jul 2011 00:56:28 -0700 (PDT)
In-Reply-To: <4E292984.5020708@metafoo.de>
References: <1311266050-22199-1-git-send-email-manuel.lauss@googlemail.com>
        <1311266050-22199-2-git-send-email-manuel.lauss@googlemail.com>
        <4E28BC1F.50804@metafoo.de>
        <CAOLZvyGxPB1oCKg4BtvBjiuKTb=8urq6L8YQHYbMfmQQigo0kA@mail.gmail.com>
        <4E292984.5020708@metafoo.de>
Date:   Fri, 22 Jul 2011 09:56:28 +0200
Message-ID: <CAOLZvyHfe+a694NKPt2+_PGtw_8JAAsvksFH=HFBYfSZ6odTMg@mail.gmail.com>
Subject: Re: [PATCH V2 1/2] ALSA: Alchemy AC97C/I2SC audio support
From:   Manuel Lauss <manuel.lauss@googlemail.com>
To:     Lars-Peter Clausen <lars@metafoo.de>
Cc:     alsa-devel@vger.kernel.org, Ralf Baechle <ralf@linux-mips.org>,
        Linux-MIPS <linux-mips@linux-mips.org>,
        Mark Brown <broonie@opensource.wolfsonmicro.com>,
        Liam Girdwood <lrg@ti.com>
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 8BIT
X-archive-position: 30667
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: manuel.lauss@googlemail.com
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 15803
Content-Length: 5137
Lines: 143

On Fri, Jul 22, 2011 at 9:40 AM, Lars-Peter Clausen <lars@metafoo.de> wrote:
> On 07/22/2011 08:54 AM, Manuel Lauss wrote:
>> On Fri, Jul 22, 2011 at 1:54 AM, Lars-Peter Clausen <lars@metafoo.de> wrote:
>>>> diff --git a/sound/soc/au1x/db1000.c b/sound/soc/au1x/db1000.c
>>>> +     ret = -ENOMEM;
>>>> +     db1000_asoc97_dev = platform_device_alloc("soc-audio", 0);
>>>
>>> New drivers shouldn't user soc-audio anymore, just register a normal platform
>>> device driver.
>>
>> Can you point to an example of the new way?
>>
>
> sound/soc/samsung/speyside.c

Thanks,



>>>> diff --git a/sound/soc/au1x/dma.c b/sound/soc/au1x/dma.c
>>>> new file mode 100644
>>>> index 0000000..0f7d90a
>>>> --- /dev/null
>>>> +++ b/sound/soc/au1x/dma.c
>>>> @@ -0,0 +1,470 @@
>>>> [...]
>>>> +
>>>> +static struct platform_driver alchemy_ac97pcm_driver = {
>>>> +     .driver = {
>>>> +             .name   = AC97C_DMANAME,
>>>> +             .owner  = THIS_MODULE,
>>>> +     },
>>>> +     .probe          = alchemy_pcm_drvprobe,
>>>> +     .remove         = __devexit_p(alchemy_pcm_drvremove),
>>>> +};
>>>> +
>>>> +static struct platform_driver alchemy_i2spcm_driver = {
>>>> +     .driver = {
>>>> +             .name   = I2SC_DMANAME,
>>>> +             .owner  = THIS_MODULE,
>>>> +     },
>>>> +     .probe          = alchemy_pcm_drvprobe,
>>>> +     .remove         = __devexit_p(alchemy_pcm_drvremove),
>>>> +};
>>>
>>> You shouldn't really have to register two identical drivers for this. If you
>>> really want to be able to instantiate the driver with two different names use
>>> platform_device_id. But in my opinion it should be enough to just have one
>>> generic name, since there is nothing AC97 or I2S specific in this driver.
>>
>> I need a unique name for the DMA device in soc_dai_link.  This was the
>> easiest way. Especially since both ac97 and i2s can be active at
>> runtime.
>
> If you want to instantiate two pcm drivers you can just give the devices
> different ids. As there is nothing I2C or AC97 specific in the pcm driver it
> should not matter which one is used for what, if two devices are active at the
> same time.
> Right now you need to know which one is which, because you instantiate the
> driver with either the I2C or AC97 DMA addresses, but if you use
> snd_soc_dai_get_dma_data as described below and pass the DMA address at runtime
> this issue will go away.

so instead of "alchemy-pcm-{ac97|i2s}" i'd have "alchemy-pcm.[01]". Not really
much clearer in my book.  And I still need to know the correct suffix for
dai link.

Or am I missing something fundamentally?



>>>> [...]
>>>> +
>>>> +struct platform_device *alchemy_pcm_add(struct platform_device *pdev, int type)
>>>> +{
>>> +       struct resource *res, *r;
>>> +       struct platform_device *pd;
>>> +       char *pdevname;
>>> +       int id[2];
>>> +       int ret;
>>> +
>>> +       r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
>>> +       if (!r)
>>> +               return NULL;
>>> +       id[0] = r->start;
>>> +
>>> +       r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
>>> +       if (!r)
>>> +               return NULL;
>>> +       id[1] = r->start;
>>> +
>>> +       res = kzalloc(sizeof(struct resource) * 2, GFP_KERNEL);
>>> +       if (!res)
>>> +               return NULL;
>>> +
>>> +       res[0].start = res[0].end = id[0];
>>> +       res[1].start = res[1].end = id[1];
>>> +       res[0].flags = res[1].flags = IORESOURCE_DMA;
>>> +
>>> +       /* "alchemy-pcm-ac97" or "alchemy-pcm-i2s" */
>>> +       pdevname = (type == 0) ? AC97C_DMANAME : I2SC_DMANAME;
>>> +       pd = platform_device_alloc(pdevname, -1);
>>> +       if (!pd)
>>> +               goto out;
>>> +
>>> +       pd->resource = res;
>>> +       pd->num_resources = 2;
>>> +
>>> +       ret = platform_device_add(pd);
>>> +       if (!ret)
>>> +               return pd;
>>> +
>>> +       platform_device_put(pd);
>>> +out:
>>> +       kfree(res);
>>> +       return NULL;
>>>> +}
>>>
>>> This function looks a bit fishy. The pcm driver should be registered by the
>>> platform code file as well. If you need different DMA regions for I2C and AC97
>>> use snd_soc_dai_set_dma_data and snd_soc_dai_get_dma_data to pass them to the
>>> PCM driver from the I2S or AC97 driver.
>>
>> I like to pass the DMA id's along with the ac97/i2s resource
>> information (since they
>> belong together anyway). As an added benefit I get a sensibly named dma device
>> with the correct DMA information, all by simply registering the ac97
>> platform device.
>
> There is nothing wrong with passing the DMA ids along with the other AC97/I2C
> resources. At least for the AC97 and I2C driver. But the PCM driver should use
> snd_soc_dai_get_dma_data to get the DMA addresses at runtime rather then during
> device instantiation. Take a look at how other platforms handle this.


The ac97/i2s units know they need dma and therefore register the
device themselves.
Having the board code register an "empty" dma device along with the
ac97/i2s devices
seems like a waste of code and a source of potential bugs.  I'll change my code.

Thank you!
        Manuel Lauss

From hauke@hauke-m.de Fri Jul 22 10:24:07 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 22 Jul 2011 10:24:16 +0200 (CEST)
Received: from server19320154104.serverpool.info ([193.201.54.104]:41677 "EHLO
        hauke-m.de" rhost-flags-OK-OK-OK-OK) by eddie.linux-mips.org
        with ESMTP id S1491157Ab1GVIYH (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Fri, 22 Jul 2011 10:24:07 +0200
Received: from localhost (localhost [127.0.0.1])
        by hauke-m.de (Postfix) with ESMTP id DC6E38C90;
        Fri, 22 Jul 2011 10:24:06 +0200 (CEST)
X-Virus-Scanned: Debian amavisd-new at hauke-m.de 
Received: from hauke-m.de ([127.0.0.1])
        by localhost (hauke-m.de [127.0.0.1]) (amavisd-new, port 10024)
        with ESMTP id R42nf1HWHWm6; Fri, 22 Jul 2011 10:24:03 +0200 (CEST)
Received: from [192.168.0.152] (dyndsl-095-033-240-157.ewe-ip-backbone.de [95.33.240.157])
        by hauke-m.de (Postfix) with ESMTPSA id 158D78C88;
        Fri, 22 Jul 2011 10:24:01 +0200 (CEST)
Message-ID: <4E2933A0.40200@hauke-m.de>
Date:   Fri, 22 Jul 2011 10:24:00 +0200
From:   Hauke Mehrtens <hauke@hauke-m.de>
User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.18) Gecko/20110617 Lightning/1.0b2 Thunderbird/3.1.11
MIME-Version: 1.0
To:     =?UTF-8?B?UmFmYcWCIE1pxYJlY2tp?= <zajec5@gmail.com>,
        ralf@linux-mips.org, "John W. Linville" <linville@tuxdriver.com>
CC:     linux-wireless@vger.kernel.org, linux-mips@linux-mips.org,
        jonas.gorski@gmail.com, mb@bu3sch.de, george@znau.edu.ua,
        arend@broadcom.com, b43-dev@lists.infradead.org,
        bernhardloos@googlemail.com, arnd@arndb.de,
        julian.calaby@gmail.com, sshtylyov@mvista.com
Subject: Re: [PATCH v2 00/11] bcma: add support for embedded devices like
 bcm4716
References: <1310835342-18877-1-git-send-email-hauke@hauke-m.de> <CACna6ryjYGuLc5c88eke=gjgwQyVD+A9afM6zCRhqV1THHgWvA@mail.gmail.com>
In-Reply-To: <CACna6ryjYGuLc5c88eke=gjgwQyVD+A9afM6zCRhqV1THHgWvA@mail.gmail.com>
X-Enigmail-Version: 1.1.2
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-archive-position: 30668
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: hauke@hauke-m.de
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 15827
Content-Length: 1737
Lines: 40

On 07/22/2011 12:30 AM, RafaÅ‚ MiÅ‚ecki wrote:
> 2011/7/16 Hauke Mehrtens <hauke@hauke-m.de>:
>> This patch series adds support for embedded devices like bcm47xx to
>> bcma. Bcma is used on bcm4716 and bcm4718 SoCs as the system bus and
>> replaced ssb used on older devices. With these patches my bcm4716
>> device boots up till it tries to access the flash, because the serial
>> flash chip is unsupported for now, this will be my next task. This adds
>> support for MIPS cores, interrupt configuration and the serial console.
>>
>> These patches are not containing all functions needed to get the SoC to
>> fully work and support every feature, but it is a good start.
>> These patches are now integrated in OpenWrt for everyone how wants to
>> test them.
>>
>> This was tested with a BCM4704 device (SoC with ssb bus), a BCM4716
>> device and a pcie wireless card supported by bcma.
>>
>>
>> @RafaÅ‚: If you are fine with the bcma patches could you please give
>> your Signed-off on them.
>>
>> @Ralf: Could you please merger this into the mips tree so that it will be in linux-3.1.
> 
> ML for bcma is linux-wireless. Should we pass that patches "via" Ralf
> or John? Using linux-wireless (and John's tree) makes more sense to
> me, as we will work on the same tree and will get less merge
> conflicts. However don't take me as Linux development style guru, just
> my POV.
> 
Hi,

Thank you for your reviewing.

I talked about this with Florian Fainelli and he said that the patches
should rather pass Ralf then John, but merging would be easier when they
are passing John. I do not have a problem with both solutions and
rebasing it to an other tree is no problem for me.
John and Ralf, who wants to take these patches? ;-)

Hauke

From lars@metafoo.de Fri Jul 22 10:39:44 2011
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 22 Jul 2011 10:39:52 +0200 (CEST)
Received: from mailhost.informatik.uni-hamburg.de ([134.100.9.70]:50179 "EHLO
        mailhost.informatik.uni-hamburg.de" rhost-flags-OK-OK-OK-OK)
        by eddie.linux-mips.org with ESMTP id S1491157Ab1GVIjo (ORCPT
        <rfc822;linux-mips@linux-mips.org>); Fri, 22 Jul 2011 10:39:44 +0200
Received: from localhost (localhost [127.0.0.1])
        by mailhost.informatik.uni-hamburg.de (Postfix) with ESMTP id F16F23DC;
        Fri, 22 Jul 2011 10:39:38 +0200 (CEST)
X-Virus-Scanned: amavisd-new at informatik.uni-hamburg.de
Received: from mailhost.informatik.uni-hamburg.de ([127.0.0.1])
        by localhost (mailhost.informatik.uni-hamburg.de [127.0.0.1]) (amavisd-new, port 10024)
        with LMTP id xbN6AFtyTGX5; Fri, 22 Jul 2011 10:39:38 +0200 (CEST)
Received: from [192.168.123.134] (e177126024.adsl.alicedsl.de [85.177.126.24])
        (using TLSv1 with cipher DHE-RSA-CAMELLIA256-SHA (256/256 bits))
        (Client did not present a certificate)
        (Authenticated sender: 7clausen)
        by mailhost.informatik.uni-hamburg.de (Postfix) with ESMTPSA id E388C3DB;
        Fri, 22 Jul 2011 10:39:30 +0200 (CEST)
Message-ID: <4E2936D9.90309@metafoo.de>
Date:   Fri, 22 Jul 2011 10:37:45 +0200
From:   Lars-Peter Clausen <lars@metafoo.de>
User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.16) Gecko/20110702 Icedove/3.0.11
MIME-Version: 1.0
To:     Manuel Lauss <manuel.lauss@googlemail.com>
CC:     alsa-devel@vger.kernel.org, Ralf Baechle <ralf@linux-mips.org>,
        Linux-MIPS <linux-mips@linux-mips.org>,
        Mark Brown <broonie@opensource.wolfsonmicro.com>,
        Liam Girdwood <lrg@ti.com>
Subject: Re: [PATCH V2 1/2] ALSA: Alchemy AC97C/I2SC audio support
References: <1311266050-22199-1-git-send-email-manuel.lauss@googlemail.com>     <1311266050-22199-2-git-send-email-manuel.lauss@googlemail.com> <4E28BC1F.50804@metafoo.de>     <CAOLZvyGxPB1oCKg4BtvBjiuKTb=8urq6L8YQHYbMfmQQigo0kA@mail.gmail.com>    <4E292984.5020708@metafoo.de> <CAOLZvyHfe+a694NKPt2+_PGtw_8JAAsvksFH=HFBYfSZ6odTMg@mail.gmail.com>
In-Reply-To: <CAOLZvyHfe+a694NKPt2+_PGtw_8JAAsvksFH=HFBYfSZ6odTMg@mail.gmail.com>
X-Enigmail-Version: 1.0.1
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit
X-archive-position: 30669
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: lars@metafoo.de
Precedence: bulk
X-list: linux-mips
Return-Path: <linux-mips-bounce@linux-mips.org>
X-Keywords:                  
X-UID: 15838
Content-Length: 5402
Lines: 136

On 07/22/2011 09:56 AM, Manuel Lauss wrote:
> On Fri, Jul 22, 2011 at 9:40 AM, Lars-Peter Clausen <lars@metafoo.de> wrote:
>> On 07/22/2011 08:54 AM, Manuel Lauss wrote:
>>> On Fri, Jul 22, 2011 at 1:54 AM, Lars-Peter Clausen <lars@metafoo.de> wrote:
>>>>> diff --git a/sound/soc/au1x/dma.c b/sound/soc/au1x/dma.c
>>>>> new file mode 100644
>>>>> index 0000000..0f7d90a
>>>>> --- /dev/null
>>>>> +++ b/sound/soc/au1x/dma.c
>>>>> @@ -0,0 +1,470 @@
>>>>> [...]
>>>>> +
>>>>> +static struct platform_driver alchemy_ac97pcm_driver = {
>>>>> +     .driver = {
>>>>> +             .name   = AC97C_DMANAME,
>>>>> +             .owner  = THIS_MODULE,
>>>>> +     },
>>>>> +     .probe          = alchemy_pcm_drvprobe,
>>>>> +     .remove         = __devexit_p(alchemy_pcm_drvremove),
>>>>> +};
>>>>> +
>>>>> +static struct platform_driver alchemy_i2spcm_driver = {
>>>>> +     .driver = {
>>>>> +             .name   = I2SC_DMANAME,
>>>>> +             .owner  = THIS_MODULE,
>>>>> +     },
>>>>> +     .probe          = alchemy_pcm_drvprobe,
>>>>> +     .remove         = __devexit_p(alchemy_pcm_drvremove),
>>>>> +};
>>>>
>>>> You shouldn't really have to register two identical drivers for this. If you
>>>> really want to be able to instantiate the driver with two different names use
>>>> platform_device_id. But in my opinion it should be enough to just have one
>>>> generic name, since there is nothing AC97 or I2S specific in this driver.
>>>
>>> I need a unique name for the DMA device in soc_dai_link.  This was the
>>> easiest way. Especially since both ac97 and i2s can be active at
>>> runtime.
>>
>> If you want to instantiate two pcm drivers you can just give the devices
>> different ids. As there is nothing I2C or AC97 specific in the pcm driver it
>> should not matter which one is used for what, if two devices are active at the
>> same time.
>> Right now you need to know which one is which, because you instantiate the
>> driver with either the I2C or AC97 DMA addresses, but if you use
>> snd_soc_dai_get_dma_data as described below and pass the DMA address at runtime
>> this issue will go away.
> 
> so instead of "alchemy-pcm-{ac97|i2s}" i'd have "alchemy-pcm.[01]". Not really
> much clearer in my book.  And I still need to know the correct suffix for
> dai link.
> 

Since there is nothing I2S or AC97 specific in the PCM driver it doesn't really
make much sense to put it in the pcm driver name in my opinion.
I would suspect that the common case is, that an board use either AC97 or I2S
audio, but not both. So in this case you'd always just have alchemy-pcm.0 in
your dai link regardless of whether the board uses AC97 or I2S.

> 
>>>>> [...]
>>>>> +
>>>>> +struct platform_device *alchemy_pcm_add(struct platform_device *pdev, int type)
>>>>> +{
>>>> +       struct resource *res, *r;
>>>> +       struct platform_device *pd;
>>>> +       char *pdevname;
>>>> +       int id[2];
>>>> +       int ret;
>>>> +
>>>> +       r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
>>>> +       if (!r)
>>>> +               return NULL;
>>>> +       id[0] = r->start;
>>>> +
>>>> +       r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
>>>> +       if (!r)
>>>> +               return NULL;
>>>> +       id[1] = r->start;
>>>> +
>>>> +       res = kzalloc(sizeof(struct resource) * 2, GFP_KERNEL);
>>>> +       if (!res)
>>>> +               return NULL;
>>>> +
>>>> +       res[0].start = res[0].end = id[0];
>>>> +       res[1].start = res[1].end = id[1];
>>>> +       res[0].flags = res[1].flags = IORESOURCE_DMA;
>>>> +
>>>> +       /* "alchemy-pcm-ac97" or "alchemy-pcm-i2s" */
>>>> +       pdevname = (type == 0) ? AC97C_DMANAME : I2SC_DMANAME;
>>>> +       pd = platform_device_alloc(pdevname, -1);
>>>> +       if (!pd)
>>>> +               goto out;
>>>> +
>>>> +       pd->resource = res;
>>>> +       pd->num_resources = 2;
>>>> +
>>>> +       ret = platform_device_add(pd);
>>>> +       if (!ret)
>>>> +               return pd;
>>>> +
>>>> +       platform_device_put(pd);
>>>> +out:
>>>> +       kfree(res);
>>>> +       return NULL;
>>>>> +}
>>>>
>>>> This function looks a bit fishy. The pcm driver should be registered by the
>>>> platform code file as well. If you need different DMA regions for I2C and AC97
>>>> use snd_soc_dai_set_dma_data and snd_soc_dai_get_dma_data to pass them to the
>>>> PCM driver from the I2S or AC97 driver.
>>>
>>> I like to pass the DMA id's along with the ac97/i2s resource
>>> information (since they
>>> belong together anyway). As an added benefit I get a sensibly named dma device
>>> with the correct DMA information, all by simply registering the ac97
>>> platform device.
>>
>> There is nothing wrong with passing the DMA ids along with the other AC97/I2C
>> resources. At least for the AC97 and I2C driver. But the PCM driver should use
>> snd_soc_dai_get_dma_data to get the DMA addresses at runtime rather then during
>> device instantiation. Take a look at how other platforms handle this.
> 
> 
> The ac97/i2s units know they need dma and therefore register the
> device themsel