LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH] cpm_uart: make dpram allocation actually work
From: Marcelo Tosatti @ 2005-08-05 20:34 UTC (permalink / raw)
  To: Pantelis Antoniou; +Cc: linuxppc-embedded
In-Reply-To: <200508021909.45729.pantelis.antoniou@gmail.com>

On Tue, Aug 02, 2005 at 07:09:45PM +0300, Pantelis Antoniou wrote:
>   Hi Marcelo
> 
> While the idea of allocating console buffers from dpram is sound, 
> the initial implementation didn't actually work :)
> 
> The following patch fixes it (tested and booted on 2.6.13-rc4).

OK thanks Panto. 

Despite my limited knowledge here, Vitaly's merged patch looks fine.

I suppose someone (Kumar?) is going to send it upstream now? 

^ permalink raw reply

* Re: swap_dup: Bad swap file entry 00480020
From: Geoff Levand @ 2005-08-05 21:12 UTC (permalink / raw)
  To: Bogdan Antonovici; +Cc: linuxppc-dev, linuxppc-embedded, ppckernel
In-Reply-To: <00ca01c599f1$a2411730$cd01a8c0@DESIGNLAB>

BTW, I posted a fix for a bug in the 2.6 page table attribute
settings for PPC440 that cause corruption when swapping.  I 
don't know if is the same for 2.4.

http://patchwork.ozlabs.org/linuxppc/patch?id=1458

-Geoff

Bogdan Antonovici wrote:
> Dan,
>  
> It hasn't crashed since i corrected that pointer initialization in
> driver. You were right.
> Thank you.
> Bogdan
> 
> ----- Original Message ----- 
> From: Dan Malek <mailto:dan@embeddededge.com>  
> To: bogdan antonovici <mailto:bantonovici@priority.mb.ca>  
> Cc: linuxppc-dev <mailto:linuxppc-dev@ozlabs.org>  ;
> linuxppc-embedded@ozlabs.org <mailto:linuxppc-embedded@ozlabs.org>  ;
> ppckernel <mailto:ppckernel@ppckernel.org>  
> Sent: Thursday, July 21, 2005 12:59 PM
> Subject: Re: swap_dup: Bad swap file entry 00480020
> 
> 
> On Jul 21, 2005, at 11:29 AM, bogdan antonovici wrote:
> 
> 
>>At the time of swap messages i was running a proprietary driver, my
>>application and few daemons.
> 
> 
> Looks like your driver may have written over some of the page
> tables in the kernel space.
> 
> 
>>I look on the net for some clues but it's quite confusing, i noticed
>>many emails on swap_dup/swap_free error messages but i couldn't figure
>>out what should i search for.
> 
> 
> Those messages are likely due to a bug with swapping to disk
> that has been in some 2.4 kernels, but I don't believe that is
> the case here, since you don't have a disk or swapping enabled.
> 
> 
> -- Dan
> 
> 
> 
> 
> 
> ------------------------------------------------------------------------
> 
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev

^ permalink raw reply

* Re: what to use to connect to JTAG/BDM port on PPC405EP
From: Wolfgang Denk @ 2005-08-05 21:19 UTC (permalink / raw)
  To: Igor Marnat; +Cc: linuxppc-embedded
In-Reply-To: <19013128171.20050805151105@rambler.ru>

In message <19013128171.20050805151105@rambler.ru> you wrote:
>
> I have EVB based on PPC 405 EP (PPChameleon EVB). It has JTAG port.
> What JTAG device can I use to connect to the board? I've found BDI2000

You found The Right Thing (TM). Use a BDI2000.

> device, for example, but it costs as N times as the EVB does

It's worth the price.

> (approximately). It seems unreasonable for me. Is it possible to make such a device or to find
> find the cheaper one? We found several schemes of how to make connector BDM-parallel
> port. Is it possible to do such a thing for PPC 405EP?

It's simple to rig up the required electrical interface and attach it
- say - to the parallel port of a standard PC. However, to  make  any
use  of  it,  you  have  to  understand which data to send and how to
interpret the results. This requires signing a NDA with IBM / AMCC  /
Freescale.  Assuming  you get the required information, it then means
quite a lot of hacking to get some working code that interfaces  with
a  standard debugger like GDB. And you will not be able to share your
code  with  others,  as  the  NDA  explicitely  prevents   you   from
implementing  it  in  any  form  of  open  source  software. You will
completely on your own there.

In the meantime the BDI user has completed 5 more real projects.


Go for a BDI.

Best regards,

Wolfgang Denk

-- 
Software Engineering:  Embedded and Realtime Systems,  Embedded Linux
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de
SW engineering is a race between programmers trying  to  make  better
idiot-proof programs and the universe producing greater idiots.

^ permalink raw reply

* [PATCH] ppc32: fix ppc440 pagetable attributes
From: Matt Porter @ 2005-08-05 22:45 UTC (permalink / raw)
  To: akpm; +Cc: linuxppc-embedded

This patch fixes a bug in the PPC440 pagetable attributes that breaks  
swap support.  It also adds some notes on the PPC440 attribute fields.

Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com> for CELF
Signed-off-by: Matt Porter <mporter@kernel.crashing.org>

Index: linux-2.6.12-bhpm/include/asm-ppc/pgtable.h
===================================================================
--- linux-2.6.12-bhpm.orig/include/asm-ppc/pgtable.h	2005-06-02 15:09:24.000000000 -0700
+++ linux-2.6.12-bhpm/include/asm-ppc/pgtable.h	2005-06-02 15:47:53.000000000 -0700
@@ -202,18 +202,64 @@
  *
  * Note that these bits preclude future use of a page size
  * less than 4KB.
+ *
+ *
+ * PPC 440 core has following TLB attribute fields;
+ *
+ *   TLB1:
+ *   0  1  2  3  4  ... 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
+ *   RPN.................................  -  -  -  -  -  - ERPN.......
+ *
+ *   TLB2:
+ *   0  1  2  3  4  ... 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
+ *   -  -  -  -  -    - U0 U1 U2 U3 W  I  M  G  E   - UX UW UR SX SW SR
+ *
+ * There are some constrains and options, to decide mapping software bits
+ * into TLB entry.
+ *
+ *   - PRESENT *must* be in the bottom three bits because swap cache
+ *     entries use the top 29 bits for TLB2.
+ *
+ *   - FILE *must* be in the bottom three bits because swap cache
+ *     entries use the top 29 bits for TLB2.
+ *
+ *   - CACHE COHERENT bit (M) has no effect on PPC440 core, because it
+ *     doesn't support SMP. So we can use this as software bit, like
+ *     DIRTY.
+ *
+ * PPC Book-E Linux implementation uses PPC HW PTE bit field definition, 
+ * even it doesn't have HW PTE. 0-11th LSB of PTE stand for memory 
+ * protection-related function. (See PTE structure in include/asm-ppc/mmu.h) 
+ * Definition of _PAGE_XXX in "include/asm-ppc/pagetable.h" stands for 
+ * above bits. Note that those bits values are CPU dependent, not 
+ * architecture.
+ * 
+ * Kernel PTE entry holds arch-dependent swp_entry structure under certain 
+ * situation. In other words, in such situation, some portion of PTE bits 
+ * are used as swp_entry. In PPC implementation, 3-24th LSB are shared with 
+ * swp_entry, however 0-2nd three LSB still hold protection values. 
+ * That means three protection bits are reserved for both PTE and SWAP 
+ * entry at the most three LSBs.
+ *
+ * There are three protection bits available for SWAP entry;
+ *	_PAGE_PRESENT
+ *	_PAGE_FILE
+ *	_PAGE_HASHPTE (if HW has)
+ *
+ * So those three bits have to be inside of 0-2nd LSB of PTE.
+ *
  */
+
 #define _PAGE_PRESENT	0x00000001		/* S: PTE valid */
 #define	_PAGE_RW	0x00000002		/* S: Write permission */
-#define	_PAGE_DIRTY	0x00000004		/* S: Page dirty */
+#define _PAGE_FILE	0x00000004		/* S: nonlinear file mapping */
 #define _PAGE_ACCESSED	0x00000008		/* S: Page referenced */
 #define _PAGE_HWWRITE	0x00000010		/* H: Dirty & RW */
 #define _PAGE_HWEXEC	0x00000020		/* H: Execute permission */
 #define	_PAGE_USER	0x00000040		/* S: User page */
 #define	_PAGE_ENDIAN	0x00000080		/* H: E bit */
 #define	_PAGE_GUARDED	0x00000100		/* H: G bit */
-#define	_PAGE_COHERENT	0x00000200		/* H: M bit */
-#define _PAGE_FILE	0x00000400		/* S: nonlinear file mapping */
+#define	_PAGE_DIRTY	0x00000200		/* S: Page dirty */
 #define	_PAGE_NO_CACHE	0x00000400		/* H: I bit */
 #define	_PAGE_WRITETHRU	0x00000800		/* H: W bit */

^ permalink raw reply

* Re: [PATCH] ppc32: fix ppc440 pagetable attributes
From: Andrew Morton @ 2005-08-05 22:54 UTC (permalink / raw)
  To: Matt Porter; +Cc: linuxppc-embedded
In-Reply-To: <20050805154505.A10842@cox.net>

Matt Porter <mporter@kernel.crashing.org> wrote:
>
> This patch fixes a bug in the PPC440 pagetable attributes that breaks  
>  swap support.  It also adds some notes on the PPC440 attribute fields.

hm, that looks pretty serious, but it affects all ppc's, yes?

Is this needed for 2.6.13?   Are you super-sure it's safe?

^ permalink raw reply

* Re: [PATCH] ppc32: fix ppc440 pagetable attributes
From: Matt Porter @ 2005-08-05 23:07 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linuxppc-embedded
In-Reply-To: <20050805155442.4e3dbf8f.akpm@osdl.org>

On Fri, Aug 05, 2005 at 03:54:42PM -0700, Andrew Morton wrote:
> Matt Porter <mporter@kernel.crashing.org> wrote:
> >
> > This patch fixes a bug in the PPC440 pagetable attributes that breaks  
> >  swap support.  It also adds some notes on the PPC440 attribute fields.
> 
> hm, that looks pretty serious, but it affects all ppc's, yes?

Just PPC440. I originally organized the attributes incorrectly.
 
> Is this needed for 2.6.13?   Are you super-sure it's safe?

This should go into 2.6.13.  I doublechecked it by inspection and
ran numerous tests. It's only existed this long (years) due to the
fact that few people run a disk-based PPC440 system. I would have
sent it up sooner except I wanted to be very sure of my testing
since I don't always trust my own inspection. :)

-Matt

^ permalink raw reply

* [PATCH] add field to struct ocp_func_emac_data for platform-specific unsupported PHY features
From: Wade Farnsworth @ 2005-08-05 23:26 UTC (permalink / raw)
  To: linuxppc-embedded, Matt Porter

[-- Attachment #1: Type: text/plain, Size: 514 bytes --]

Hello all,

This patch adds a field to struct ocp_func_emac_data that allows
platform-specific unsupported PHY features to be passed in to the
ibm_emac ethernet driver.

This patch also adds some logic for the Bamboo eval board to populate
this field based on the dip switches on the board.  This is a workaround
for the improperly biased RJ-45 sockets on the Rev. 0 Bamboo.  See the
comments in bamboo.c for more information on this bug.

-Wade Farnsworth

Signed-off by: Wade Farnsworth <wfarnsworth@mvista.com>

[-- Attachment #2: ibm-emac-phy-feat-unsupp-ppc.patch --]
[-- Type: text/plain, Size: 3116 bytes --]

--- linux-2.6/arch/ppc/platforms/4xx/bamboo.c	2005-08-03 13:33:41.000000000 -0700
+++ linux-2.6-dev/arch/ppc/platforms/4xx/bamboo.c	2005-08-02 10:51:00.000000000 -0700
@@ -123,33 +123,69 @@ bamboo_map_irq(struct pci_dev *dev, unsi
 
 static void __init bamboo_set_emacdata(void)
 {
-	unsigned char * selection1_base;
+	u8 * base_addr;
 	struct ocp_def *def;
 	struct ocp_func_emac_data *emacdata;
-	u8 selection1_val;
+	u8 val;
 	int mode;
+	u32 unsupported = 0;
 
-	selection1_base = ioremap64(BAMBOO_FPGA_SELECTION1_REG_ADDR, 16);
-	selection1_val = readb(selection1_base);
-	iounmap((void *) selection1_base);
-	if (BAMBOO_SEL_MII(selection1_val))
+	base_addr = ioremap64(BAMBOO_FPGA_SELECTION1_REG_ADDR, 16);
+	val = readb(base_addr);
+	iounmap((void *) base_addr);
+	if (BAMBOO_SEL_MII(val))
 		mode = PHY_MODE_MII;
-	else if (BAMBOO_SEL_RMII(selection1_val))
+	else if (BAMBOO_SEL_RMII(val))
 		mode = PHY_MODE_RMII;
 	else
 		mode = PHY_MODE_SMII;
 
-	/* Set mac_addr and phy mode for each EMAC */
+	/*
+	 * SW2 on the Bamboo is used for ethernet configuration and is accessed
+	 * via the CONFIG2 register in the FPGA.  If the ANEG pin is set,
+	 * overwrite the supported features with the settings in SW2.
+	 *
+	 * This is used as a workaround for the improperly biased RJ-45 sockets
+	 * on the Rev. 0 Bamboo.  By default only 10baseT is functional.
+	 * Removing inductors L17 and L18 from the board allows 100baseT, but
+	 * disables 10baseT.  The Rev. 1 has no such limitations.
+	 */
+
+	base_addr = ioremap64(BAMBOO_FPGA_CONFIG2_REG_ADDR, 8);
+	val = readb(base_addr);
+	iounmap((void *) base_addr);
+	if (!BAMBOO_AUTONEGOTIATE(val)) {
+		unsupported |= SUPPORTED_Autoneg;
+		if (BAMBOO_FORCE_100Mbps(val)) {
+			unsupported |= SUPPORTED_10baseT_Full;
+			unsupported |= SUPPORTED_10baseT_Half;
+			if (BAMBOO_FULL_DUPLEX_EN(val))
+				unsupported |= SUPPORTED_100baseT_Half;
+			else
+				unsupported |= SUPPORTED_100baseT_Full;
+		} else {
+			unsupported |= SUPPORTED_100baseT_Full;
+			unsupported |= SUPPORTED_100baseT_Half;
+			if (BAMBOO_FULL_DUPLEX_EN(val))
+				unsupported |= SUPPORTED_10baseT_Half;
+			else
+				unsupported |= SUPPORTED_10baseT_Full;
+		}
+	}
+	
+	/* Set mac_addr, phy mode and unsupported phy features for each EMAC */
 
 	def = ocp_get_one_device(OCP_VENDOR_IBM, OCP_FUNC_EMAC, 0);
 	emacdata = def->additions;
 	memcpy(emacdata->mac_addr, __res.bi_enetaddr, 6);
 	emacdata->phy_mode = mode;
+	emacdata->feat_unsupp = unsupported;
 
 	def = ocp_get_one_device(OCP_VENDOR_IBM, OCP_FUNC_EMAC, 1);
 	emacdata = def->additions;
 	memcpy(emacdata->mac_addr, __res.bi_enet1addr, 6);
 	emacdata->phy_mode = mode;
+	emacdata->feat_unsupp = unsupported;
 }
 
 static int
--- linux-2.6/include/asm-ppc/ibm_ocp.h	2005-08-03 13:34:08.000000000 -0700
+++ linux-2.6-dev/include/asm-ppc/ibm_ocp.h	2005-08-02 10:49:42.000000000 -0700
@@ -67,6 +67,7 @@ struct ocp_func_emac_data {
 	int	phy_mode;	/* PHY type or configurable mode */
 	u8	mac_addr[6];	/* EMAC mac address */
 	u32	phy_map;	/* EMAC phy map */
+	u32	feat_unsupp;	/* Unsupported phy features */
 };
 
 /* Sysfs support */

^ permalink raw reply

* Re: [PATCH] cpm_uart: make dpram allocation actually work
From: Kumar Gala @ 2005-08-06  3:11 UTC (permalink / raw)
  To: Marcelo Tosatti; +Cc: linuxppc-embedded, Pantelis Antoniou
In-Reply-To: <20050805203456.GD14338@dmt.cnet>


On Aug 5, 2005, at 3:34 PM, Marcelo Tosatti wrote:

> On Tue, Aug 02, 2005 at 07:09:45PM +0300, Pantelis Antoniou wrote:
>
>>   Hi Marcelo
>>
>> While the idea of allocating console buffers from dpram is sound,
>> the initial implementation didn't actually work :)
>>
>> The following patch fixes it (tested and booted on 2.6.13-rc4).
>>
>
> OK thanks Panto.
>
> Despite my limited knowledge here, Vitaly's merged patch looks fine.
>
> I suppose someone (Kumar?) is going to send it upstream now?

I plan on this, after we test it on 8560.

- kumar

^ permalink raw reply

* Where can I get manual of `mkimage' tool ?
From: hegs @ 2005-08-06  4:13 UTC (permalink / raw)
  To: linuxppc-embedded

IEkgdXNlIGBta2ltYWdlJyB0b29sIHRvICBidWlsZCBVLUJvb3QgaW1hZ2UsIGJ1dCBkb25vdCBr
bm93biBob3cgdG8gdXNlICJta2ltYWdlIiA/IA0KDQogIHdobyBjYW4gaGVscCBtZSA/DQoNCiBU
aGFuayB5b3UuDQo=

^ permalink raw reply

* Re: Where can I get manual of `mkimage' tool ?
From: Josh Boyer @ 2005-08-06 16:43 UTC (permalink / raw)
  To: hegs; +Cc: linuxppc-embedded
In-Reply-To: <GDEILMHADIJIGHOKJKDNKEGACAAA.hegs1999@21cn.com>

On Sat, 2005-08-06 at 12:13 +0800, hegs wrote:
>  I use `mkimage' tool to  build U-Boot image, but donot known how to use "mkimage" ? 
> 
>   who can help me ?

There is example usage in the README file of u-boot.

josh

^ permalink raw reply

* [PATCH] 8xx: fix CPM ethernet description
From: Aristeu Sergio Rozanski Filho @ 2005-08-06 17:58 UTC (permalink / raw)
  To: Marcelo Tosatti; +Cc: linuxppc-embedded

8xx: fix CPM Ethernet description

Signed-off-by: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>

Index: 8xx/arch/ppc/8xx_io/Kconfig
===================================================================
--- 8xx.orig/arch/ppc/8xx_io/Kconfig	2005-07-07 23:42:11.000000000 -0300
+++ 8xx/arch/ppc/8xx_io/Kconfig	2005-08-04 08:38:10.000000000 -0300
@@ -71,7 +71,7 @@
 	bool "Use Big CPM Ethernet Buffers"
 	depends on NET_ETHERNET
 	help
-	  Allocate large buffers for MPC8xx Etherenet.  Increases throughput
+	  Allocate large buffers for MPC8xx Ethernet. Increases throughput
 	  and decreases the likelihood of dropped packets, but costs memory.
 
 config HTDMSOUND

^ permalink raw reply

* [PATCH] 8xx: restrict ENET_BIG_BUFFERS option
From: Aristeu Sergio Rozanski Filho @ 2005-08-06 18:00 UTC (permalink / raw)
  To: Marcelo Tosatti; +Cc: linuxppc-embedded

8xx: restrict ENET_BIG_BUFFERS option to drivers which actually uses it

Signed-off-by: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>

Index: 8xx/arch/ppc/8xx_io/Kconfig
===================================================================
--- 8xx.orig/arch/ppc/8xx_io/Kconfig	2005-08-04 08:38:10.000000000 -0300
+++ 8xx/arch/ppc/8xx_io/Kconfig	2005-08-04 08:48:10.000000000 -0300
@@ -69,7 +69,7 @@
 	
 config ENET_BIG_BUFFERS
 	bool "Use Big CPM Ethernet Buffers"
-	depends on NET_ETHERNET
+	depends on SCC_ENET || FEC_ENET
 	help
 	  Allocate large buffers for MPC8xx Ethernet. Increases throughput
 	  and decreases the likelihood of dropped packets, but costs memory.

^ permalink raw reply

* [PATCH] 8xx: port i2c-algo-8xx to 2.6
From: Aristeu Sergio Rozanski Filho @ 2005-08-06 18:01 UTC (permalink / raw)
  To: Marcelo Tosatti; +Cc: linuxppc-embedded

8xx: port i2c-algo_8xx to 2.6

Based on Tom Rini's work

compile tested

Signed-off-by: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>

Index: 2.6-8xx/drivers/i2c/algos/i2c-algo-8xx.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ 2.6-8xx/drivers/i2c/algos/i2c-algo-8xx.c	2005-08-05 17:16:08.000000000 -0300
@@ -0,0 +1,625 @@
+/*
+ * i2c-algo-8xx.c i2x driver algorithms for MPC8XX CPM
+ * Copyright (c) 1999 Dan Malek (dmalek@jlc.net).
+ *
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * moved into proper i2c interface; separated out platform specific
+ * parts into i2c-rpx.c
+ * Brad Parker (brad@heeltoe.com)
+ */
+
+// XXX todo
+// timeout sleep?
+
+/* $Id: i2c-algo-8xx.c,v 1.7 2002/08/03 22:48:18 ac9410 Exp $ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+
+#include <asm/mpc8xx.h>
+#include <asm/commproc.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c-algo-8xx.h>
+
+#define CPM_MAX_READ	513
+/* Try uncomment this if you have an older CPU(earlier than rev D4) */
+/* #define I2C_CHIP_ERRATA */
+
+static char *module_name = "i2c_algo_8xx";
+#define DEBUGP(level, x, y...) do { \
+				if (cpm_debug >= level) \
+					printk(KERN_DEBUG "%s: " x, \
+					       module_name, ## y); \
+				} while(0)
+
+static wait_queue_head_t iic_wait;
+static ushort r_tbase, r_rbase;
+
+int cpm_scan = 0;
+int cpm_debug = 0;
+
+static  void
+cpm_iic_interrupt(void *dev_id, struct pt_regs *regs)
+ {
+	volatile i2c8xx_t *i2c = (i2c8xx_t *)dev_id;
+
+	DEBUGP(2, "cpm_iic_interrupt(dev_id=%p)\n", dev_id);
+
+#ifdef I2C_CHIP_ERRATA
+	/* Chip errata, clear enable.
+	 * This seems to not be needed on rev D4 or newer CPUs.
+	 * Someone with an older CPU needs to verify this.
+	 */
+	i2c->i2c_i2mod &= ~1;
+#endif
+
+	/* Clear interrupt.
+	*/
+	i2c->i2c_i2cer = 0xff;
+
+	/* Get 'me going again.
+	*/
+	wake_up_interruptible(&iic_wait);
+}
+
+static void
+cpm_iic_init(struct i2c_algo_8xx_data *cpm_adap)
+{
+	volatile iic_t		*iip = cpm_adap->iip;
+	volatile i2c8xx_t	*i2c = cpm_adap->i2c;
+	unsigned char brg;
+	bd_t *bd = (bd_t *)__res;
+
+	DEBUGP(1, "cpm_iic_init() - iip=%p\n", iip);
+
+	/* Initialize the parameter ram.
+	 * We need to make sure many things are initialized to zero,
+	 * especially in the case of a microcode patch.
+	 */
+	iip->iic_rstate = 0;
+	iip->iic_rdp = 0;
+	iip->iic_rbptr = 0;
+	iip->iic_rbc = 0;
+	iip->iic_rxtmp = 0;
+	iip->iic_tstate = 0;
+	iip->iic_tdp = 0;
+	iip->iic_tbptr = 0;
+	iip->iic_tbc = 0;
+	iip->iic_txtmp = 0;
+
+	/* Set up the IIC parameters in the parameter ram.
+	*/
+	iip->iic_tbase = r_tbase = cpm_adap->dp_addr;
+	iip->iic_rbase = r_rbase = cpm_adap->dp_addr + sizeof(cbd_t) * 2;
+
+	iip->iic_tfcr = SMC_EB;
+	iip->iic_rfcr = SMC_EB;
+
+	/* Set maximum receive size.
+	*/
+	iip->iic_mrblr = CPM_MAX_READ;
+
+	/* Initialize Tx/Rx parameters.
+	*/
+	if (cpm_adap->reloc == 0) {
+		volatile cpm8xx_t *cp = cpm_adap->cp;
+
+		cp->cp_cpcr =
+			mk_cr_cmd(CPM_CR_CH_I2C, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+		while (cp->cp_cpcr & CPM_CR_FLG);
+	} else {
+		iip->iic_rbptr = iip->iic_rbase;
+		iip->iic_tbptr = iip->iic_tbase;
+		iip->iic_rstate	= 0;
+		iip->iic_tstate	= 0;
+	}
+
+	/* Select an arbitrary address.  Just make sure it is unique.
+	*/
+	i2c->i2c_i2add = 0xfe;
+
+	/* Make clock run at 60 KHz.
+	*/
+	brg = (unsigned char) (bd->bi_intfreq/(32*2*60000) -3);
+	i2c->i2c_i2brg = brg;
+
+	i2c->i2c_i2mod = 0x00;
+	i2c->i2c_i2com = 0x01; /* Master mode */
+
+	/* Disable interrupts.
+	*/
+	i2c->i2c_i2cmr = 0;
+	i2c->i2c_i2cer = 0xff;
+
+	init_waitqueue_head(&iic_wait);
+
+	/* Install interrupt handler.
+	*/
+	DEBUGP(1, "Install ISR for IRQ %d\n", CPMVEC_I2C);
+	cpm_install_handler(CPMVEC_I2C, cpm_iic_interrupt, (void *)i2c);
+}
+
+
+static int
+cpm_iic_shutdown(struct i2c_algo_8xx_data *cpm_adap)
+{
+	volatile i2c8xx_t *i2c = cpm_adap->i2c;
+
+	/* Shut down IIC.
+	*/
+	i2c->i2c_i2mod &= ~1;
+	i2c->i2c_i2cmr = 0;
+	i2c->i2c_i2cer = 0xff;
+
+	return 0;
+}
+
+static void
+cpm_reset_iic_params(volatile iic_t *iip)
+{
+	iip->iic_tbase = r_tbase;
+	iip->iic_rbase = r_rbase;
+
+	iip->iic_tfcr = SMC_EB;
+	iip->iic_rfcr = SMC_EB;
+
+	iip->iic_mrblr = CPM_MAX_READ;
+
+	iip->iic_rstate = 0;
+	iip->iic_rdp = 0;
+	iip->iic_rbptr = iip->iic_rbase;
+	iip->iic_rbc = 0;
+	iip->iic_rxtmp = 0;
+	iip->iic_tstate = 0;
+	iip->iic_tdp = 0;
+	iip->iic_tbptr = iip->iic_tbase;
+	iip->iic_tbc = 0;
+	iip->iic_txtmp = 0;
+}
+
+#define BD_SC_NAK		((ushort)0x0004) /* NAK - did not respond */
+#define BD_SC_OV		((ushort)0x0002) /* OV - receive overrun */
+#define CPM_CR_CLOSE_RXBD	((ushort)0x0007)
+
+static void force_close(struct i2c_algo_8xx_data *cpm)
+{
+	volatile i2c8xx_t *i2c = cpm->i2c;
+	if (cpm->reloc == 0) { /* micro code disabled */
+		volatile cpm8xx_t *cp = cpm->cp;
+
+		DEBUGP(1, "force_close()\n");
+		cp->cp_cpcr =
+			mk_cr_cmd(CPM_CR_CH_I2C, CPM_CR_CLOSE_RXBD) |
+			CPM_CR_FLG;
+
+		while (cp->cp_cpcr & CPM_CR_FLG);
+	}
+	i2c->i2c_i2cmr = 0x00;	/* Disable all interrupts */
+	i2c->i2c_i2cer = 0xff;
+}
+
+
+/* Read from IIC...
+ * abyte = address byte, with r/w flag already set
+ */
+static int
+cpm_iic_read(struct i2c_algo_8xx_data *cpm, u_char abyte, char *buf, int count)
+{
+	volatile iic_t *iip = cpm->iip;
+	volatile i2c8xx_t *i2c = cpm->i2c;
+	volatile cpm8xx_t *cp = cpm->cp;
+	volatile cbd_t	*tbdf, *rbdf;
+	u_char *tb;
+	unsigned long flags, tmo;
+
+	if (count >= CPM_MAX_READ)
+		return -EINVAL;
+
+	/* check for and use a microcode relocation patch */
+	if (cpm->reloc)
+		cpm_reset_iic_params(iip);
+
+	tbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_tbase];
+	rbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_rbase];
+
+	/* To read, we need an empty buffer of the proper length.
+	 * All that is used is the first byte for address, the remainder
+	 * is just used for timing (and doesn't really have to exist).
+	 */
+	tb = cpm->temp;
+	tb = (u_char *)(((uint)tb + 15) & ~15);
+	tb[0] = abyte;		/* Device address byte w/rw flag */
+
+	flush_dcache_range((unsigned long) tb, (unsigned long) (tb + 1));
+
+	DEBUGP(1, "cpm_iic_read(abyte=0x%x)\n", abyte);
+
+	tbdf->cbd_bufaddr = __pa(tb);
+	tbdf->cbd_datlen = count + 1;
+	tbdf->cbd_sc =
+		BD_SC_READY | BD_SC_LAST |
+		BD_SC_WRAP | BD_IIC_START;
+
+	iip->iic_mrblr = count + 1; /* prevent excessive read, +1
+				      is needed otherwise will the
+				      RXB interrupt come too early */
+
+	/* flush will invalidate too. */
+	flush_dcache_range((unsigned long) buf, (unsigned long) (buf+count));
+
+	rbdf->cbd_datlen = 0;
+	rbdf->cbd_bufaddr = __pa(buf);
+
+	rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP| BD_SC_INTRPT;
+	if(count > 16){
+		/* Chip bug, set enable here */
+		local_irq_save(flags);
+		i2c->i2c_i2cmr = 0x13;	/* Enable some interupts */
+		i2c->i2c_i2cer = 0xff;
+		i2c->i2c_i2mod |= 1;	/* Enable */
+		i2c->i2c_i2com |= 0x80;	/* Begin transmission */
+
+		/* Wait for IIC transfer */
+		tmo = interruptible_sleep_on_timeout(&iic_wait,1*HZ);
+		local_irq_restore(flags);
+	} else { /* busy wait for small transfers, its faster */
+		i2c->i2c_i2cmr = 0x00;	/* Disable I2C interupts */
+		i2c->i2c_i2cer = 0xff;
+		i2c->i2c_i2mod |= 1;	/* Enable */
+		i2c->i2c_i2com |= 0x80;	/* Begin transmission */
+		tmo = jiffies + 1*HZ;
+	       	/* Busy wait, with a timeout */
+		while(!(i2c->i2c_i2cer & 0x11 || time_after(jiffies, tmo)));
+	}
+
+	if (signal_pending(current) || !tmo){
+		force_close(cpm);
+		DEBUGP(1, "IIC read: timeout!\n");
+ 		return -EIO;
+	}
+#ifdef I2C_CHIP_ERRATA
+	/* Chip errata, clear enable. This is not needed on rev D4 CPUs.
+	 Disabling I2C too early may cause too short stop condition */
+	udelay(4);
+	i2c->i2c_i2mod &= ~1;
+#endif
+
+	DEBUGP(1, "tx sc %04x, rx sc %04x\n", tbdf->cbd_sc, rbdf->cbd_sc);
+
+	if (tbdf->cbd_sc & BD_SC_READY) {
+		printk(KERN_INFO "IIC read; complete but tbuf ready\n");
+		force_close(cpm);
+		printk(KERN_INFO "tx sc %04x, rx sc %04x\n",
+		       tbdf->cbd_sc, rbdf->cbd_sc);
+	}
+
+	if (tbdf->cbd_sc & BD_SC_NAK) {
+		DEBUGP(1, "IIC read; no ack\n");
+		return -EREMOTEIO;
+ 	}
+
+	if (rbdf->cbd_sc & BD_SC_EMPTY) {
+		/* force_close(cpm); */
+		DEBUGP(1, "IIC read; complete but rbuf empty\n");
+		DEBUGP(1, "tx sc %04x, rx sc %04x\n", tbdf->cbd_sc, rbdf->cbd_sc);
+		return -EREMOTEIO;
+	}
+
+	if (rbdf->cbd_sc & BD_SC_OV) {
+		DEBUGP(1, "IIC read; Overrun\n");
+		return -EREMOTEIO;;
+ 	}
+
+	DEBUGP(1, "read %d bytes\n", rbdf->cbd_datlen);
+
+	if (rbdf->cbd_datlen < count) {
+		DEBUGP(1, "IIC read; short, wanted %d got %d\n", count,
+		       rbdf->cbd_datlen);
+		return 0;
+	}
+
+	return count;
+}
+
+/* Write to IIC...
+ * addr = address byte, with r/w flag already set
+ */
+static int
+cpm_iic_write(struct i2c_algo_8xx_data *cpm, u_char abyte, char *buf,int count)
+{
+	volatile iic_t *iip = cpm->iip;
+	volatile i2c8xx_t *i2c = cpm->i2c;
+	volatile cpm8xx_t *cp = cpm->cp;
+	volatile cbd_t	*tbdf;
+	u_char *tb;
+	unsigned long flags, tmo;
+
+	/* check for and use a microcode relocation patch */
+	if (cpm->reloc)
+		cpm_reset_iic_params(iip);
+	tb = cpm->temp;
+	tb = (u_char *)(((uint)tb + 15) & ~15);
+	*tb = abyte;		/* Device address byte w/rw flag */
+
+	flush_dcache_range((unsigned long) tb, (unsigned long) (tb+1));
+	flush_dcache_range((unsigned long) buf, (unsigned long) (buf+count));
+
+	DEBUGP(1, "cpm_iic_write(abyte=0x%x)\n", abyte);
+
+	/* set up 2 descriptors */
+	tbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_tbase];
+
+	tbdf[0].cbd_bufaddr = __pa(tb);
+	tbdf[0].cbd_datlen = 1;
+	tbdf[0].cbd_sc = BD_SC_READY | BD_IIC_START;
+
+	tbdf[1].cbd_bufaddr = __pa(buf);
+	tbdf[1].cbd_datlen = count;
+	tbdf[1].cbd_sc = BD_SC_READY | BD_SC_INTRPT | BD_SC_LAST | BD_SC_WRAP;
+
+	if (count > 16) {
+		/* Chip bug, set enable here */
+		local_irq_save(flags);
+		i2c->i2c_i2cmr = 0x13;	/* Enable some interupts */
+		i2c->i2c_i2cer = 0xff;
+		i2c->i2c_i2mod |= 1;	/* Enable */
+		i2c->i2c_i2com |= 0x80;	/* Begin transmission */
+
+		/* Wait for IIC transfer */
+		tmo = interruptible_sleep_on_timeout(&iic_wait,1*HZ);
+		local_irq_restore(flags);
+	} else {  /* busy wait for small transfers, its faster */
+		i2c->i2c_i2cmr = 0x00;	/* Disable I2C interupts */
+		i2c->i2c_i2cer = 0xff;
+		i2c->i2c_i2mod |= 1;	/* Enable */
+		i2c->i2c_i2com |= 0x80;	/* Begin transmission */
+		tmo = jiffies + 1*HZ;
+	       	/* Busy wait, with a timeout */
+		while(!(i2c->i2c_i2cer & 0x12 || time_after(jiffies, tmo)));
+	}
+
+	if (signal_pending(current) || !tmo){
+		force_close(cpm);
+		if (!tmo)
+			DEBUGP(1, "IIC write: timeout!\n");
+		return -EIO;
+	}
+
+#if I2C_CHIP_ERRATA
+	/* Chip errata, clear enable. This is not needed on rev D4 CPUs.
+	 Disabling I2C too early may cause too short stop condition */
+	udelay(4);
+	i2c->i2c_i2mod &= ~1;
+#endif
+	DEBUGP(1, "tx0 sc %04x, tx1 sc %04x\n", tbdf[0].cbd_sc,
+	       tbdf[1].cbd_sc);
+
+	if ((tbdf[0].cbd_sc | tbdf[1].cbd_sc) & BD_SC_NAK) {
+		DEBUGP(1, "IIC write; no ack\n");
+		return 0;
+	}
+
+	if ((tbdf[0].cbd_sc | tbdf[1].cbd_sc) & BD_SC_READY) {
+		DEBUGP(1, "IIC write; complete but tbuf ready\n");
+		return 0;
+	}
+
+	return count;
+}
+
+/* See if an IIC address exists..
+ * addr = 7 bit address, unshifted
+ */
+static int
+cpm_iic_tryaddress(struct i2c_algo_8xx_data *cpm, int addr)
+{
+	volatile iic_t *iip = cpm->iip;
+	volatile i2c8xx_t *i2c = cpm->i2c;
+	volatile cpm8xx_t *cp = cpm->cp;
+	volatile cbd_t *tbdf, *rbdf;
+	u_char *tb;
+	unsigned long flags, len, tmo;
+
+	DEBUGP(2, "cpm_iic_tryaddress(cpm=%p,addr=%d)\n", cpm, addr);
+
+	/* check for and use a microcode relocation patch */
+	if (cpm->reloc)
+		cpm_reset_iic_params(iip);
+
+	if (addr == 0) {
+		DEBUGP(1, "iip %p, dp_addr 0x%x\n", cpm->iip, cpm->dp_addr);
+		DEBUGP(1, "iic_tbase %d, r_tbase %d\n", iip->iic_tbase,
+		       r_tbase);
+	}
+
+	tbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_tbase];
+	rbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_rbase];
+
+	tb = cpm->temp;
+	tb = (u_char *)(((uint)tb + 15) & ~15);
+
+	/* do a simple read */
+	tb[0] = (addr << 1) | 1;	/* device address (+ read) */
+	len = 2;
+
+	flush_dcache_range((unsigned long) tb, (unsigned long) (tb+1));
+
+	tbdf->cbd_bufaddr = __pa(tb);
+	tbdf->cbd_datlen = len;
+	tbdf->cbd_sc =
+		BD_SC_READY | BD_SC_LAST |
+		BD_SC_WRAP | BD_IIC_START;
+
+	rbdf->cbd_datlen = 0;
+	rbdf->cbd_bufaddr = __pa(tb+2);
+	rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP | BD_SC_INTRPT;
+
+	local_irq_save(flags);
+	i2c->i2c_i2cmr = 0x13;	/* Enable some interupts */
+	i2c->i2c_i2cer = 0xff;
+	i2c->i2c_i2mod |= 1;	/* Enable */
+	i2c->i2c_i2com |= 0x80;	/* Begin transmission */
+
+	DEBUGP(1, "about to sleep\n");
+
+	/* wait for IIC transfer */
+	tmo = interruptible_sleep_on_timeout(&iic_wait,1*HZ);
+	local_irq_restore(flags);
+
+#ifdef I2C_CHIP_ERRATA
+	/* Chip errata, clear enable. This is not needed on rev D4 CPUs.
+	 Disabling I2C too early may cause too short stop condition */
+	udelay(4);
+	i2c->i2c_i2mod &= ~1;
+#endif
+
+	if (signal_pending(current) || !tmo){
+		force_close(cpm);
+		if (!tmo)
+			DEBUGP(1, "IIC tryaddress: timeout!\n");
+		return -EIO;
+	}
+
+	DEBUGP(2, "back from sleep\n");
+
+	if (tbdf->cbd_sc & BD_SC_NAK) {
+		DEBUGP(2, "IIC try; no ack\n");
+		return 0;
+	}
+
+	if (tbdf->cbd_sc & BD_SC_READY)
+		printk(KERN_INFO "IIC try; complete but tbuf ready\n");
+
+	return 1;
+}
+
+static int cpm_xfer(struct i2c_adapter *i2c_adap,
+		    struct i2c_msg msgs[],
+		    int num)
+{
+	struct i2c_algo_8xx_data *adap = i2c_adap->algo_data;
+	struct i2c_msg *pmsg;
+	int i, ret;
+	u_char addr;
+
+	for (i = 0; i < num; i++) {
+		pmsg = &msgs[i];
+
+		DEBUGP(1, "#%d addr=0x%x flags=0x%x len=%d\n buf=%p\n",
+		       i, pmsg->addr, pmsg->flags, pmsg->len, pmsg->buf);
+
+		addr = pmsg->addr << 1;
+		if (pmsg->flags & I2C_M_RD)
+			addr |= 1;
+		if (pmsg->flags & I2C_M_REV_DIR_ADDR)
+			addr ^= 1;
+
+		if (pmsg->flags & I2C_M_RD) {
+			/* read bytes into buffer*/
+			ret = cpm_iic_read(adap, addr, pmsg->buf, pmsg->len);
+			DEBUGP(1, "read %d bytes\n", ret);
+			if (ret < pmsg->len)
+				return (ret < 0)? ret:-EREMOTEIO;
+		} else {
+			/* write bytes from buffer */
+			ret = cpm_iic_write(adap, addr, pmsg->buf, pmsg->len);
+			DEBUGP(1, "wrote %d\n", ret);
+			if (ret < pmsg->len)
+				return (ret < 0)? ret:-EREMOTEIO;
+		}
+	}
+	return num;
+}
+
+static u32 cpm_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR |
+	       I2C_FUNC_PROTOCOL_MANGLING;
+}
+
+static struct i2c_algorithm i2c_algo_8xx = {
+	.name = "MPC8xx CPM algorithm",
+	.id = I2C_ALGO_MPC8XX,
+	.master_xfer = cpm_xfer,
+	.functionality = cpm_func,
+};
+
+/*
+ * registering functions to load algorithms at runtime
+ */
+int i2c_8xx_add_bus(struct i2c_adapter *adap)
+{
+	int i;
+	struct i2c_algo_8xx_data *cpm_adap = adap->algo_data;
+
+	DEBUGP(1, "hw routines for %s registered.\n", adap->name);
+
+	/* register new adapter to i2c module... */
+
+	adap->id |= i2c_algo_8xx.id;
+	adap->algo = &i2c_algo_8xx;
+
+	i2c_add_adapter(adap);
+	cpm_iic_init(cpm_adap);
+
+	/* scan bus */
+	if (cpm_scan) {
+		printk(KERN_INFO "%s: scanning bus %s...\n", module_name,
+		       adap->name);
+		for (i = 0; i < 128; i++)
+			if (cpm_iic_tryaddress(cpm_adap, i)) {
+				printk("(%02x)", i << 1);
+			}
+		printk("\n");
+	}
+	return 0;
+}
+
+int i2c_8xx_del_bus(struct i2c_adapter *adap)
+{
+	int res;
+	struct i2c_algo_8xx_data *cpm_adap = adap->algo_data;
+
+	cpm_iic_shutdown(cpm_adap);
+
+	if ((res = i2c_del_adapter(adap)) < 0)
+		return res;
+
+	printk(KERN_INFO "%s: adapter unregistered: %s\n", module_name,
+	       adap->name);
+
+	return 0;
+}
+
+module_param(cpm_debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(cpm_debug, "Sets the debug level. (0 = none, 1 = normal, "
+		 ">1 = plenty");
+MODULE_AUTHOR("Brad Parker <brad@heeltoe.com>");
+MODULE_DESCRIPTION("I2C-Bus MPC8XX algorithm");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(i2c_8xx_add_bus);
+EXPORT_SYMBOL(i2c_8xx_del_bus);
+
Index: 2.6-8xx/drivers/i2c/algos/Makefile
===================================================================
--- 2.6-8xx.orig/drivers/i2c/algos/Makefile	2005-07-28 12:05:11.000000000 -0300
+++ 2.6-8xx/drivers/i2c/algos/Makefile	2005-08-05 16:48:26.000000000 -0300
@@ -8,6 +8,7 @@
 obj-$(CONFIG_I2C_ALGOITE)	+= i2c-algo-ite.o
 obj-$(CONFIG_I2C_ALGO_SIBYTE)	+= i2c-algo-sibyte.o
 obj-$(CONFIG_I2C_ALGO_SGI)	+= i2c-algo-sgi.o
+obj-$(CONFIG_I2C_ALGO8XX)	+= i2c-algo-8xx.o
 
 ifeq ($(CONFIG_I2C_DEBUG_ALGO),y)
 EXTRA_CFLAGS += -DDEBUG
Index: 2.6-8xx/include/linux/i2c-algo-8xx.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ 2.6-8xx/include/linux/i2c-algo-8xx.h	2005-08-05 16:57:21.000000000 -0300
@@ -0,0 +1,28 @@
+/* ------------------------------------------------------------------------- */
+/* i2c-algo-8xx.h i2c driver algorithms for MPX8XX CPM			     */
+/* ------------------------------------------------------------------------- */
+
+/* $Id$ */
+
+#ifndef I2C_ALGO_8XX_H
+#define I2C_ALGO_8XX_H
+
+#include <linux/i2c.h>
+#include <asm/8xx_immap.h>
+#include <asm/commproc.h>
+
+struct i2c_algo_8xx_data {
+	uint dp_addr;
+	int reloc;
+	volatile i2c8xx_t *i2c;
+	volatile iic_t	*iip;
+	volatile cpm8xx_t *cp;
+
+	u_char	temp[513];
+};
+
+int i2c_8xx_add_bus(struct i2c_adapter *);
+int i2c_8xx_del_bus(struct i2c_adapter *);
+
+#endif /* I2C_ALGO_8XX_H */
+

^ permalink raw reply

* [PATCH] 8xx: remove rpx_install_isr() from i2c-rpx.c
From: Aristeu Sergio Rozanski Filho @ 2005-08-06 18:03 UTC (permalink / raw)
  To: Marcelo Tosatti; +Cc: linuxppc-embedded

8xx: remove rpx_install_isr(), IRQ handler is installed on i2c-algo-8xx

Signed-off-by: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>

Index: 2.6-8xx/drivers/i2c/busses/i2c-rpx.c
===================================================================
--- 2.6-8xx.orig/drivers/i2c/busses/i2c-rpx.c	2005-08-05 17:00:06.000000000 -0300
+++ 2.6-8xx/drivers/i2c/busses/i2c-rpx.c	2005-08-05 17:05:36.000000000 -0300
@@ -55,17 +55,7 @@
 	data->i2c = (i2c8xx_t *)&(((immap_t *)IMAP_ADDR)->im_i2c);
 }
 
-static int rpx_install_isr(int irq, void (*func)(void *, void *), void *data)
-{
-	/* install interrupt handler */
-	cpm_install_handler(irq, (void (*)(void *, struct pt_regs *)) func, data);
-
-	return 0;
-}
-
-static struct i2c_algo_8xx_data rpx_data = {
-	.setisr = rpx_install_isr
-};
+static struct i2c_algo_8xx_data rpx_data;
 
 static struct i2c_adapter rpx_ops = {
 	.owner		= THIS_MODULE,

^ permalink raw reply

* [PATCH] 8xx: add cpm_get_cpmp()
From: Aristeu Sergio Rozanski Filho @ 2005-08-06 18:03 UTC (permalink / raw)
  To: Marcelo Tosatti; +Cc: linuxppc-embedded

8xx: add cpm_get_cpmp() to make cpmp visible to modules

Signed-off-by: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>

Index: 2.6-8xx/arch/ppc/8xx_io/commproc.c
===================================================================
--- 2.6-8xx.orig/arch/ppc/8xx_io/commproc.c	2005-08-03 17:26:05.000000000 -0300
+++ 2.6-8xx/arch/ppc/8xx_io/commproc.c	2005-08-05 17:13:21.000000000 -0300
@@ -462,3 +462,10 @@
 	return ((immap_t *)IMAP_ADDR)->im_cpm.cp_dpmem + offset;
 }
 EXPORT_SYMBOL(cpm_dpram_addr);
+
+cpm8xx_t *cpm_get_cpmp(void)
+{
+	return cpmp;
+}
+EXPORT_SYMBOL(cpm_get_cpmp);
+
Index: 2.6-8xx/include/asm/commproc.h
===================================================================
--- 2.6-8xx.orig/include/asm/commproc.h	2005-07-28 12:06:51.000000000 -0300
+++ 2.6-8xx/include/asm/commproc.h	2005-08-05 17:14:28.000000000 -0300
@@ -78,6 +78,7 @@
 extern void cpm_dpdump(void);
 extern void *cpm_dpram_addr(uint offset);
 extern void cpm_setbrg(uint brg, uint rate);
+extern cpm8xx_t *cpm_get_cpmp(void);
 
 extern uint m8xx_cpm_hostalloc(uint size);
 extern int  m8xx_cpm_hostfree(uint start);

^ permalink raw reply

* [PATCH] 8xx: i2c_rpx: use cpm_get_cpmp()
From: Aristeu Sergio Rozanski Filho @ 2005-08-06 18:04 UTC (permalink / raw)
  To: Marcelo Tosatti; +Cc: linuxppc-embedded

8xx: use cpm_get_cpmp() in i2c-rpx

Signed-off-by: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>

Index: 2.6-8xx/drivers/i2c/busses/i2c-rpx.c
===================================================================
--- 2.6-8xx.orig/drivers/i2c/busses/i2c-rpx.c	2005-08-05 17:05:36.000000000 -0300
+++ 2.6-8xx/drivers/i2c/busses/i2c-rpx.c	2005-08-05 17:15:20.000000000 -0300
@@ -27,7 +27,7 @@
 	volatile cpm8xx_t *cp;
 	volatile immap_t *immap;
 
-	cp = cpmp;	/* Get pointer to Communication Processor */
+	cp = cpm_get_cpmp();	/* Get pointer to Communication Processor */
 	immap = (immap_t *)IMAP_ADDR;	/* and to internal registers */
 
 	data->iip = (iic_t *)&cp->cp_dparam[PROFF_IIC];

^ permalink raw reply

* [PATCH] 8xx: kill unused variable in commproc
From: Aristeu Sergio Rozanski Filho @ 2005-08-06 18:05 UTC (permalink / raw)
  To: Marcelo Tosatti; +Cc: linuxppc-embedded

8xx: commproc.c: kill unused variable

Signed-off-by: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>

Index: 2.6-8xx/arch/ppc/8xx_io/commproc.c
===================================================================
--- 2.6-8xx.orig/arch/ppc/8xx_io/commproc.c	2005-08-05 17:16:15.000000000 -0300
+++ 2.6-8xx/arch/ppc/8xx_io/commproc.c	2005-08-05 17:20:12.000000000 -0300
@@ -384,8 +384,6 @@
 
 void m8xx_cpm_dpinit(void)
 {
-	cpm8xx_t *cp = &((immap_t *)IMAP_ADDR)->im_cpm;
-
 	spin_lock_init(&cpm_dpmem_lock);
 
 	/* Initialize the info header */

^ permalink raw reply

* Re: [PATCH] 8xx: port i2c-algo-8xx to 2.6
From: Marcelo Tosatti @ 2005-08-06 23:20 UTC (permalink / raw)
  To: Aristeu Sergio Rozanski Filho; +Cc: linuxppc-embedded
In-Reply-To: <20050806180131.GU5210@cathedrallabs.org>

On Sat, Aug 06, 2005 at 03:01:31PM -0300, Aristeu Sergio Rozanski Filho wrote:
> 8xx: port i2c-algo_8xx to 2.6
> 
> Based on Tom Rini's work 
>
> compile tested 

Would be good to test before submitting? :)

> Signed-off-by: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
> 
> Index: 2.6-8xx/drivers/i2c/algos/i2c-algo-8xx.c
> ===================================================================
> --- /dev/null	1970-01-01 00:00:00.000000000 +0000
> +++ 2.6-8xx/drivers/i2c/algos/i2c-algo-8xx.c	2005-08-05 17:16:08.000000000 -0300
> @@ -0,0 +1,625 @@
> +/*
> + * i2c-algo-8xx.c i2x driver algorithms for MPC8XX CPM
> + * Copyright (c) 1999 Dan Malek (dmalek@jlc.net).
> + *
> +    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., 675 Mass Ave, Cambridge, MA 02139, USA.
> + *
> + * moved into proper i2c interface; separated out platform specific
> + * parts into i2c-rpx.c
> + * Brad Parker (brad@heeltoe.com)
> + */
> +
> +// XXX todo
> +// timeout sleep?
> +
> +/* $Id: i2c-algo-8xx.c,v 1.7 2002/08/03 22:48:18 ac9410 Exp $ */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/delay.h>
> +#include <linux/slab.h>
> +#include <linux/version.h>
> +#include <linux/init.h>
> +#include <asm/uaccess.h>
> +#include <linux/ioport.h>
> +#include <linux/errno.h>
> +#include <linux/sched.h>
> +
> +#include <asm/mpc8xx.h>
> +#include <asm/commproc.h>
> +
> +#include <linux/i2c.h>
> +#include <linux/i2c-algo-8xx.h>
> +
> +#define CPM_MAX_READ	513
> +/* Try uncomment this if you have an older CPU(earlier than rev D4) */
> +/* #define I2C_CHIP_ERRATA */
> +
> +static char *module_name = "i2c_algo_8xx";
> +#define DEBUGP(level, x, y...) do { \
> +				if (cpm_debug >= level) \
> +					printk(KERN_DEBUG "%s: " x, \
> +					       module_name, ## y); \
> +				} while(0)
> +
> +static wait_queue_head_t iic_wait;
> +static ushort r_tbase, r_rbase;
> +
> +int cpm_scan = 0;
> +int cpm_debug = 0;
> +
> +static  void
> +cpm_iic_interrupt(void *dev_id, struct pt_regs *regs)
> + {
> +	volatile i2c8xx_t *i2c = (i2c8xx_t *)dev_id;

You got an extra space everywhere other than the initial TAB?

^ permalink raw reply

* Re: [PATCH] 8xx: add cpm_get_cpmp()
From: Marcelo Tosatti @ 2005-08-06 23:27 UTC (permalink / raw)
  To: Aristeu Sergio Rozanski Filho; +Cc: linuxppc-embedded
In-Reply-To: <20050806180353.GW5210@cathedrallabs.org>


Aris,

It already is exported, declared as

commproc.h:extern       cpm8xx_t        *cpmp;          /* Pointer to comm processor */


and many drivers use the pointer directly.

arch/ppc/8260_io/ drivers also use the same convention.

Not sure I see much advantage in changing it?

On Sat, Aug 06, 2005 at 03:03:53PM -0300, Aristeu Sergio Rozanski Filho wrote:
> 8xx: add cpm_get_cpmp() to make cpmp visible to modules
> 
> Signed-off-by: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
> 
> Index: 2.6-8xx/arch/ppc/8xx_io/commproc.c
> ===================================================================
> --- 2.6-8xx.orig/arch/ppc/8xx_io/commproc.c	2005-08-03 17:26:05.000000000 -0300
> +++ 2.6-8xx/arch/ppc/8xx_io/commproc.c	2005-08-05 17:13:21.000000000 -0300
> @@ -462,3 +462,10 @@
>  	return ((immap_t *)IMAP_ADDR)->im_cpm.cp_dpmem + offset;
>  }
>  EXPORT_SYMBOL(cpm_dpram_addr);
> +
> +cpm8xx_t *cpm_get_cpmp(void)
> +{
> +	return cpmp;
> +}
> +EXPORT_SYMBOL(cpm_get_cpmp);
> +
> Index: 2.6-8xx/include/asm/commproc.h
> ===================================================================
> --- 2.6-8xx.orig/include/asm/commproc.h	2005-07-28 12:06:51.000000000 -0300
> +++ 2.6-8xx/include/asm/commproc.h	2005-08-05 17:14:28.000000000 -0300
> @@ -78,6 +78,7 @@
>  extern void cpm_dpdump(void);
>  extern void *cpm_dpram_addr(uint offset);
>  extern void cpm_setbrg(uint brg, uint rate);
> +extern cpm8xx_t *cpm_get_cpmp(void);
>  
>  extern uint m8xx_cpm_hostalloc(uint size);
>  extern int  m8xx_cpm_hostfree(uint start);

^ permalink raw reply

* Re: [PATCH] 8xx: add cpm_get_cpmp()
From: Aristeu Sergio Rozanski Filho @ 2005-08-06 23:42 UTC (permalink / raw)
  To: Marcelo Tosatti; +Cc: linuxppc-embedded
In-Reply-To: <20050806232701.GD1099@dmt.cnet>

> It already is exported, declared as
> 
> commproc.h:extern       cpm8xx_t        *cpmp;          /* Pointer to comm processor */
> 
> 
> and many drivers use the pointer directly.
> 
> arch/ppc/8260_io/ drivers also use the same convention.
> 
> Not sure I see much advantage in changing it?
but not with EXPORT_SYMBOL(). I noticed this while compiling i2c stuff
as module. also, I think it's better add a function to do this instead
doing EXPORT_SYMBOL() in a variable.
what you think?

-- 
Aristeu

^ permalink raw reply

* Re: [PATCH] 8xx: port i2c-algo-8xx to 2.6
From: Aristeu Sergio Rozanski Filho @ 2005-08-07  0:08 UTC (permalink / raw)
  To: Marcelo Tosatti; +Cc: linuxppc-embedded
In-Reply-To: <20050806232022.GC1099@dmt.cnet>

[-- Attachment #1: Type: text/plain, Size: 489 bytes --]

> Would be good to test before submitting? :)
I would like but I don't have the hardware and Alex (who reported this
on bugzilla) told me he doesn't have it anymore. feel free to discard it
until someone tests it

> > +static  void
> > +cpm_iic_interrupt(void *dev_id, struct pt_regs *regs)
> > + {
> > +	volatile i2c8xx_t *i2c = (i2c8xx_t *)dev_id;
> 
> You got an extra space everywhere other than the initial TAB?
fixed this and others I found in the file, patch attached

-- 
Aristeu


[-- Attachment #2: i2c_algo_8xx-port_to_2_6.patch --]
[-- Type: text/plain, Size: 18163 bytes --]

8xx: port i2c-algo_8xx to 2.6

Based on Tom Rini's work

Signed-off-by: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>

Index: 8xx/drivers/i2c/algos/i2c-algo-8xx.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ 8xx/drivers/i2c/algos/i2c-algo-8xx.c	2005-08-06 21:04:37.000000000 -0300
@@ -0,0 +1,625 @@
+/*
+ * i2c-algo-8xx.c i2x driver algorithms for MPC8XX CPM
+ * Copyright (c) 1999 Dan Malek (dmalek@jlc.net).
+ *
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * moved into proper i2c interface; separated out platform specific
+ * parts into i2c-rpx.c
+ * Brad Parker (brad@heeltoe.com)
+ */
+
+// XXX todo
+// timeout sleep?
+
+/* $Id: i2c-algo-8xx.c,v 1.7 2002/08/03 22:48:18 ac9410 Exp $ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+
+#include <asm/mpc8xx.h>
+#include <asm/commproc.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c-algo-8xx.h>
+
+#define CPM_MAX_READ	513
+/* Try uncomment this if you have an older CPU(earlier than rev D4) */
+/* #define I2C_CHIP_ERRATA */
+
+static char *module_name = "i2c_algo_8xx";
+#define DEBUGP(level, x, y...) do { \
+				if (cpm_debug >= level) \
+					printk(KERN_DEBUG "%s: " x, \
+					       module_name, ## y); \
+				} while(0)
+
+static wait_queue_head_t iic_wait;
+static ushort r_tbase, r_rbase;
+
+int cpm_scan = 0;
+int cpm_debug = 0;
+
+static  void
+cpm_iic_interrupt(void *dev_id, struct pt_regs *regs)
+{
+	volatile i2c8xx_t *i2c = (i2c8xx_t *)dev_id;
+
+	DEBUGP(2, "cpm_iic_interrupt(dev_id=%p)\n", dev_id);
+
+#ifdef I2C_CHIP_ERRATA
+	/* Chip errata, clear enable.
+	 * This seems to not be needed on rev D4 or newer CPUs.
+	 * Someone with an older CPU needs to verify this.
+	 */
+	i2c->i2c_i2mod &= ~1;
+#endif
+
+	/* Clear interrupt.
+	*/
+	i2c->i2c_i2cer = 0xff;
+
+	/* Get 'me going again.
+	*/
+	wake_up_interruptible(&iic_wait);
+}
+
+static void
+cpm_iic_init(struct i2c_algo_8xx_data *cpm_adap)
+{
+	volatile iic_t		*iip = cpm_adap->iip;
+	volatile i2c8xx_t	*i2c = cpm_adap->i2c;
+	unsigned char brg;
+	bd_t *bd = (bd_t *)__res;
+
+	DEBUGP(1, "cpm_iic_init() - iip=%p\n", iip);
+
+	/* Initialize the parameter ram.
+	 * We need to make sure many things are initialized to zero,
+	 * especially in the case of a microcode patch.
+	 */
+	iip->iic_rstate = 0;
+	iip->iic_rdp = 0;
+	iip->iic_rbptr = 0;
+	iip->iic_rbc = 0;
+	iip->iic_rxtmp = 0;
+	iip->iic_tstate = 0;
+	iip->iic_tdp = 0;
+	iip->iic_tbptr = 0;
+	iip->iic_tbc = 0;
+	iip->iic_txtmp = 0;
+
+	/* Set up the IIC parameters in the parameter ram.
+	*/
+	iip->iic_tbase = r_tbase = cpm_adap->dp_addr;
+	iip->iic_rbase = r_rbase = cpm_adap->dp_addr + sizeof(cbd_t) * 2;
+
+	iip->iic_tfcr = SMC_EB;
+	iip->iic_rfcr = SMC_EB;
+
+	/* Set maximum receive size.
+	*/
+	iip->iic_mrblr = CPM_MAX_READ;
+
+	/* Initialize Tx/Rx parameters.
+	*/
+	if (cpm_adap->reloc == 0) {
+		volatile cpm8xx_t *cp = cpm_adap->cp;
+
+		cp->cp_cpcr =
+			mk_cr_cmd(CPM_CR_CH_I2C, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+		while (cp->cp_cpcr & CPM_CR_FLG);
+	} else {
+		iip->iic_rbptr = iip->iic_rbase;
+		iip->iic_tbptr = iip->iic_tbase;
+		iip->iic_rstate	= 0;
+		iip->iic_tstate	= 0;
+	}
+
+	/* Select an arbitrary address.  Just make sure it is unique.
+	*/
+	i2c->i2c_i2add = 0xfe;
+
+	/* Make clock run at 60 KHz.
+	*/
+	brg = (unsigned char) (bd->bi_intfreq/(32*2*60000) -3);
+	i2c->i2c_i2brg = brg;
+
+	i2c->i2c_i2mod = 0x00;
+	i2c->i2c_i2com = 0x01; /* Master mode */
+
+	/* Disable interrupts.
+	*/
+	i2c->i2c_i2cmr = 0;
+	i2c->i2c_i2cer = 0xff;
+
+	init_waitqueue_head(&iic_wait);
+
+	/* Install interrupt handler.
+	*/
+	DEBUGP(1, "Install ISR for IRQ %d\n", CPMVEC_I2C);
+	cpm_install_handler(CPMVEC_I2C, cpm_iic_interrupt, (void *)i2c);
+}
+
+
+static int
+cpm_iic_shutdown(struct i2c_algo_8xx_data *cpm_adap)
+{
+	volatile i2c8xx_t *i2c = cpm_adap->i2c;
+
+	/* Shut down IIC.
+	*/
+	i2c->i2c_i2mod &= ~1;
+	i2c->i2c_i2cmr = 0;
+	i2c->i2c_i2cer = 0xff;
+
+	return 0;
+}
+
+static void
+cpm_reset_iic_params(volatile iic_t *iip)
+{
+	iip->iic_tbase = r_tbase;
+	iip->iic_rbase = r_rbase;
+
+	iip->iic_tfcr = SMC_EB;
+	iip->iic_rfcr = SMC_EB;
+
+	iip->iic_mrblr = CPM_MAX_READ;
+
+	iip->iic_rstate = 0;
+	iip->iic_rdp = 0;
+	iip->iic_rbptr = iip->iic_rbase;
+	iip->iic_rbc = 0;
+	iip->iic_rxtmp = 0;
+	iip->iic_tstate = 0;
+	iip->iic_tdp = 0;
+	iip->iic_tbptr = iip->iic_tbase;
+	iip->iic_tbc = 0;
+	iip->iic_txtmp = 0;
+}
+
+#define BD_SC_NAK		((ushort)0x0004) /* NAK - did not respond */
+#define BD_SC_OV		((ushort)0x0002) /* OV - receive overrun */
+#define CPM_CR_CLOSE_RXBD	((ushort)0x0007)
+
+static void force_close(struct i2c_algo_8xx_data *cpm)
+{
+	volatile i2c8xx_t *i2c = cpm->i2c;
+	if (cpm->reloc == 0) { /* micro code disabled */
+		volatile cpm8xx_t *cp = cpm->cp;
+
+		DEBUGP(1, "force_close()\n");
+		cp->cp_cpcr =
+			mk_cr_cmd(CPM_CR_CH_I2C, CPM_CR_CLOSE_RXBD) |
+			CPM_CR_FLG;
+
+		while (cp->cp_cpcr & CPM_CR_FLG);
+	}
+	i2c->i2c_i2cmr = 0x00;	/* Disable all interrupts */
+	i2c->i2c_i2cer = 0xff;
+}
+
+
+/* Read from IIC...
+ * abyte = address byte, with r/w flag already set
+ */
+static int
+cpm_iic_read(struct i2c_algo_8xx_data *cpm, u_char abyte, char *buf, int count)
+{
+	volatile iic_t *iip = cpm->iip;
+	volatile i2c8xx_t *i2c = cpm->i2c;
+	volatile cpm8xx_t *cp = cpm->cp;
+	volatile cbd_t	*tbdf, *rbdf;
+	u_char *tb;
+	unsigned long flags, tmo;
+
+	if (count >= CPM_MAX_READ)
+		return -EINVAL;
+
+	/* check for and use a microcode relocation patch */
+	if (cpm->reloc)
+		cpm_reset_iic_params(iip);
+
+	tbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_tbase];
+	rbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_rbase];
+
+	/* To read, we need an empty buffer of the proper length.
+	 * All that is used is the first byte for address, the remainder
+	 * is just used for timing (and doesn't really have to exist).
+	 */
+	tb = cpm->temp;
+	tb = (u_char *)(((uint)tb + 15) & ~15);
+	tb[0] = abyte;		/* Device address byte w/rw flag */
+
+	flush_dcache_range((unsigned long) tb, (unsigned long) (tb + 1));
+
+	DEBUGP(1, "cpm_iic_read(abyte=0x%x)\n", abyte);
+
+	tbdf->cbd_bufaddr = __pa(tb);
+	tbdf->cbd_datlen = count + 1;
+	tbdf->cbd_sc =
+		BD_SC_READY | BD_SC_LAST |
+		BD_SC_WRAP | BD_IIC_START;
+
+	iip->iic_mrblr = count + 1; /* prevent excessive read, +1
+				      is needed otherwise will the
+				      RXB interrupt come too early */
+
+	/* flush will invalidate too. */
+	flush_dcache_range((unsigned long) buf, (unsigned long) (buf+count));
+
+	rbdf->cbd_datlen = 0;
+	rbdf->cbd_bufaddr = __pa(buf);
+
+	rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP| BD_SC_INTRPT;
+	if(count > 16){
+		/* Chip bug, set enable here */
+		local_irq_save(flags);
+		i2c->i2c_i2cmr = 0x13;	/* Enable some interupts */
+		i2c->i2c_i2cer = 0xff;
+		i2c->i2c_i2mod |= 1;	/* Enable */
+		i2c->i2c_i2com |= 0x80;	/* Begin transmission */
+
+		/* Wait for IIC transfer */
+		tmo = interruptible_sleep_on_timeout(&iic_wait,1*HZ);
+		local_irq_restore(flags);
+	} else { /* busy wait for small transfers, its faster */
+		i2c->i2c_i2cmr = 0x00;	/* Disable I2C interupts */
+		i2c->i2c_i2cer = 0xff;
+		i2c->i2c_i2mod |= 1;	/* Enable */
+		i2c->i2c_i2com |= 0x80;	/* Begin transmission */
+		tmo = jiffies + 1*HZ;
+	       	/* Busy wait, with a timeout */
+		while(!(i2c->i2c_i2cer & 0x11 || time_after(jiffies, tmo)));
+	}
+
+	if (signal_pending(current) || !tmo){
+		force_close(cpm);
+		DEBUGP(1, "IIC read: timeout!\n");
+		return -EIO;
+	}
+#ifdef I2C_CHIP_ERRATA
+	/* Chip errata, clear enable. This is not needed on rev D4 CPUs.
+	 Disabling I2C too early may cause too short stop condition */
+	udelay(4);
+	i2c->i2c_i2mod &= ~1;
+#endif
+
+	DEBUGP(1, "tx sc %04x, rx sc %04x\n", tbdf->cbd_sc, rbdf->cbd_sc);
+
+	if (tbdf->cbd_sc & BD_SC_READY) {
+		printk(KERN_INFO "IIC read; complete but tbuf ready\n");
+		force_close(cpm);
+		printk(KERN_INFO "tx sc %04x, rx sc %04x\n",
+		       tbdf->cbd_sc, rbdf->cbd_sc);
+	}
+
+	if (tbdf->cbd_sc & BD_SC_NAK) {
+		DEBUGP(1, "IIC read; no ack\n");
+		return -EREMOTEIO;
+	}
+
+	if (rbdf->cbd_sc & BD_SC_EMPTY) {
+		/* force_close(cpm); */
+		DEBUGP(1, "IIC read; complete but rbuf empty\n");
+		DEBUGP(1, "tx sc %04x, rx sc %04x\n", tbdf->cbd_sc, rbdf->cbd_sc);
+		return -EREMOTEIO;
+	}
+
+	if (rbdf->cbd_sc & BD_SC_OV) {
+		DEBUGP(1, "IIC read; Overrun\n");
+		return -EREMOTEIO;;
+	}
+
+	DEBUGP(1, "read %d bytes\n", rbdf->cbd_datlen);
+
+	if (rbdf->cbd_datlen < count) {
+		DEBUGP(1, "IIC read; short, wanted %d got %d\n", count,
+		       rbdf->cbd_datlen);
+		return 0;
+	}
+
+	return count;
+}
+
+/* Write to IIC...
+ * addr = address byte, with r/w flag already set
+ */
+static int
+cpm_iic_write(struct i2c_algo_8xx_data *cpm, u_char abyte, char *buf,int count)
+{
+	volatile iic_t *iip = cpm->iip;
+	volatile i2c8xx_t *i2c = cpm->i2c;
+	volatile cpm8xx_t *cp = cpm->cp;
+	volatile cbd_t	*tbdf;
+	u_char *tb;
+	unsigned long flags, tmo;
+
+	/* check for and use a microcode relocation patch */
+	if (cpm->reloc)
+		cpm_reset_iic_params(iip);
+	tb = cpm->temp;
+	tb = (u_char *)(((uint)tb + 15) & ~15);
+	*tb = abyte;		/* Device address byte w/rw flag */
+
+	flush_dcache_range((unsigned long) tb, (unsigned long) (tb+1));
+	flush_dcache_range((unsigned long) buf, (unsigned long) (buf+count));
+
+	DEBUGP(1, "cpm_iic_write(abyte=0x%x)\n", abyte);
+
+	/* set up 2 descriptors */
+	tbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_tbase];
+
+	tbdf[0].cbd_bufaddr = __pa(tb);
+	tbdf[0].cbd_datlen = 1;
+	tbdf[0].cbd_sc = BD_SC_READY | BD_IIC_START;
+
+	tbdf[1].cbd_bufaddr = __pa(buf);
+	tbdf[1].cbd_datlen = count;
+	tbdf[1].cbd_sc = BD_SC_READY | BD_SC_INTRPT | BD_SC_LAST | BD_SC_WRAP;
+
+	if (count > 16) {
+		/* Chip bug, set enable here */
+		local_irq_save(flags);
+		i2c->i2c_i2cmr = 0x13;	/* Enable some interupts */
+		i2c->i2c_i2cer = 0xff;
+		i2c->i2c_i2mod |= 1;	/* Enable */
+		i2c->i2c_i2com |= 0x80;	/* Begin transmission */
+
+		/* Wait for IIC transfer */
+		tmo = interruptible_sleep_on_timeout(&iic_wait,1*HZ);
+		local_irq_restore(flags);
+	} else {  /* busy wait for small transfers, its faster */
+		i2c->i2c_i2cmr = 0x00;	/* Disable I2C interupts */
+		i2c->i2c_i2cer = 0xff;
+		i2c->i2c_i2mod |= 1;	/* Enable */
+		i2c->i2c_i2com |= 0x80;	/* Begin transmission */
+		tmo = jiffies + 1*HZ;
+	       	/* Busy wait, with a timeout */
+		while(!(i2c->i2c_i2cer & 0x12 || time_after(jiffies, tmo)));
+	}
+
+	if (signal_pending(current) || !tmo){
+		force_close(cpm);
+		if (!tmo)
+			DEBUGP(1, "IIC write: timeout!\n");
+		return -EIO;
+	}
+
+#if I2C_CHIP_ERRATA
+	/* Chip errata, clear enable. This is not needed on rev D4 CPUs.
+	 Disabling I2C too early may cause too short stop condition */
+	udelay(4);
+	i2c->i2c_i2mod &= ~1;
+#endif
+	DEBUGP(1, "tx0 sc %04x, tx1 sc %04x\n", tbdf[0].cbd_sc,
+	       tbdf[1].cbd_sc);
+
+	if ((tbdf[0].cbd_sc | tbdf[1].cbd_sc) & BD_SC_NAK) {
+		DEBUGP(1, "IIC write; no ack\n");
+		return 0;
+	}
+
+	if ((tbdf[0].cbd_sc | tbdf[1].cbd_sc) & BD_SC_READY) {
+		DEBUGP(1, "IIC write; complete but tbuf ready\n");
+		return 0;
+	}
+
+	return count;
+}
+
+/* See if an IIC address exists..
+ * addr = 7 bit address, unshifted
+ */
+static int
+cpm_iic_tryaddress(struct i2c_algo_8xx_data *cpm, int addr)
+{
+	volatile iic_t *iip = cpm->iip;
+	volatile i2c8xx_t *i2c = cpm->i2c;
+	volatile cpm8xx_t *cp = cpm->cp;
+	volatile cbd_t *tbdf, *rbdf;
+	u_char *tb;
+	unsigned long flags, len, tmo;
+
+	DEBUGP(2, "cpm_iic_tryaddress(cpm=%p,addr=%d)\n", cpm, addr);
+
+	/* check for and use a microcode relocation patch */
+	if (cpm->reloc)
+		cpm_reset_iic_params(iip);
+
+	if (addr == 0) {
+		DEBUGP(1, "iip %p, dp_addr 0x%x\n", cpm->iip, cpm->dp_addr);
+		DEBUGP(1, "iic_tbase %d, r_tbase %d\n", iip->iic_tbase,
+		       r_tbase);
+	}
+
+	tbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_tbase];
+	rbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_rbase];
+
+	tb = cpm->temp;
+	tb = (u_char *)(((uint)tb + 15) & ~15);
+
+	/* do a simple read */
+	tb[0] = (addr << 1) | 1;	/* device address (+ read) */
+	len = 2;
+
+	flush_dcache_range((unsigned long) tb, (unsigned long) (tb+1));
+
+	tbdf->cbd_bufaddr = __pa(tb);
+	tbdf->cbd_datlen = len;
+	tbdf->cbd_sc =
+		BD_SC_READY | BD_SC_LAST |
+		BD_SC_WRAP | BD_IIC_START;
+
+	rbdf->cbd_datlen = 0;
+	rbdf->cbd_bufaddr = __pa(tb+2);
+	rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP | BD_SC_INTRPT;
+
+	local_irq_save(flags);
+	i2c->i2c_i2cmr = 0x13;	/* Enable some interupts */
+	i2c->i2c_i2cer = 0xff;
+	i2c->i2c_i2mod |= 1;	/* Enable */
+	i2c->i2c_i2com |= 0x80;	/* Begin transmission */
+
+	DEBUGP(1, "about to sleep\n");
+
+	/* wait for IIC transfer */
+	tmo = interruptible_sleep_on_timeout(&iic_wait,1*HZ);
+	local_irq_restore(flags);
+
+#ifdef I2C_CHIP_ERRATA
+	/* Chip errata, clear enable. This is not needed on rev D4 CPUs.
+	 Disabling I2C too early may cause too short stop condition */
+	udelay(4);
+	i2c->i2c_i2mod &= ~1;
+#endif
+
+	if (signal_pending(current) || !tmo){
+		force_close(cpm);
+		if (!tmo)
+			DEBUGP(1, "IIC tryaddress: timeout!\n");
+		return -EIO;
+	}
+
+	DEBUGP(2, "back from sleep\n");
+
+	if (tbdf->cbd_sc & BD_SC_NAK) {
+		DEBUGP(2, "IIC try; no ack\n");
+		return 0;
+	}
+
+	if (tbdf->cbd_sc & BD_SC_READY)
+		printk(KERN_INFO "IIC try; complete but tbuf ready\n");
+
+	return 1;
+}
+
+static int cpm_xfer(struct i2c_adapter *i2c_adap,
+		    struct i2c_msg msgs[],
+		    int num)
+{
+	struct i2c_algo_8xx_data *adap = i2c_adap->algo_data;
+	struct i2c_msg *pmsg;
+	int i, ret;
+	u_char addr;
+
+	for (i = 0; i < num; i++) {
+		pmsg = &msgs[i];
+
+		DEBUGP(1, "#%d addr=0x%x flags=0x%x len=%d\n buf=%p\n",
+		       i, pmsg->addr, pmsg->flags, pmsg->len, pmsg->buf);
+
+		addr = pmsg->addr << 1;
+		if (pmsg->flags & I2C_M_RD)
+			addr |= 1;
+		if (pmsg->flags & I2C_M_REV_DIR_ADDR)
+			addr ^= 1;
+
+		if (pmsg->flags & I2C_M_RD) {
+			/* read bytes into buffer*/
+			ret = cpm_iic_read(adap, addr, pmsg->buf, pmsg->len);
+			DEBUGP(1, "read %d bytes\n", ret);
+			if (ret < pmsg->len)
+				return (ret < 0)? ret:-EREMOTEIO;
+		} else {
+			/* write bytes from buffer */
+			ret = cpm_iic_write(adap, addr, pmsg->buf, pmsg->len);
+			DEBUGP(1, "wrote %d\n", ret);
+			if (ret < pmsg->len)
+				return (ret < 0)? ret:-EREMOTEIO;
+		}
+	}
+	return num;
+}
+
+static u32 cpm_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR |
+	       I2C_FUNC_PROTOCOL_MANGLING;
+}
+
+static struct i2c_algorithm i2c_algo_8xx = {
+	.name = "MPC8xx CPM algorithm",
+	.id = I2C_ALGO_MPC8XX,
+	.master_xfer = cpm_xfer,
+	.functionality = cpm_func,
+};
+
+/*
+ * registering functions to load algorithms at runtime
+ */
+int i2c_8xx_add_bus(struct i2c_adapter *adap)
+{
+	int i;
+	struct i2c_algo_8xx_data *cpm_adap = adap->algo_data;
+
+	DEBUGP(1, "hw routines for %s registered.\n", adap->name);
+
+	/* register new adapter to i2c module... */
+
+	adap->id |= i2c_algo_8xx.id;
+	adap->algo = &i2c_algo_8xx;
+
+	i2c_add_adapter(adap);
+	cpm_iic_init(cpm_adap);
+
+	/* scan bus */
+	if (cpm_scan) {
+		printk(KERN_INFO "%s: scanning bus %s...\n", module_name,
+		       adap->name);
+		for (i = 0; i < 128; i++)
+			if (cpm_iic_tryaddress(cpm_adap, i)) {
+				printk("(%02x)", i << 1);
+			}
+		printk("\n");
+	}
+	return 0;
+}
+
+int i2c_8xx_del_bus(struct i2c_adapter *adap)
+{
+	int res;
+	struct i2c_algo_8xx_data *cpm_adap = adap->algo_data;
+
+	cpm_iic_shutdown(cpm_adap);
+
+	if ((res = i2c_del_adapter(adap)) < 0)
+		return res;
+
+	printk(KERN_INFO "%s: adapter unregistered: %s\n", module_name,
+	       adap->name);
+
+	return 0;
+}
+
+module_param(cpm_debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(cpm_debug, "Sets the debug level. (0 = none, 1 = normal, "
+		 ">1 = plenty");
+MODULE_AUTHOR("Brad Parker <brad@heeltoe.com>");
+MODULE_DESCRIPTION("I2C-Bus MPC8XX algorithm");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(i2c_8xx_add_bus);
+EXPORT_SYMBOL(i2c_8xx_del_bus);
+
Index: 8xx/drivers/i2c/algos/Makefile
===================================================================
--- 8xx.orig/drivers/i2c/algos/Makefile	2005-08-06 14:40:49.000000000 -0300
+++ 8xx/drivers/i2c/algos/Makefile	2005-08-06 21:03:57.000000000 -0300
@@ -8,6 +8,7 @@
 obj-$(CONFIG_I2C_ALGOITE)	+= i2c-algo-ite.o
 obj-$(CONFIG_I2C_ALGO_SIBYTE)	+= i2c-algo-sibyte.o
 obj-$(CONFIG_I2C_ALGO_SGI)	+= i2c-algo-sgi.o
+obj-$(CONFIG_I2C_ALGO8XX)	+= i2c-algo-8xx.o
 
 ifeq ($(CONFIG_I2C_DEBUG_ALGO),y)
 EXTRA_CFLAGS += -DDEBUG
Index: 8xx/include/linux/i2c-algo-8xx.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ 8xx/include/linux/i2c-algo-8xx.h	2005-08-06 21:03:57.000000000 -0300
@@ -0,0 +1,28 @@
+/* ------------------------------------------------------------------------- */
+/* i2c-algo-8xx.h i2c driver algorithms for MPX8XX CPM			     */
+/* ------------------------------------------------------------------------- */
+
+/* $Id$ */
+
+#ifndef I2C_ALGO_8XX_H
+#define I2C_ALGO_8XX_H
+
+#include <linux/i2c.h>
+#include <asm/8xx_immap.h>
+#include <asm/commproc.h>
+
+struct i2c_algo_8xx_data {
+	uint dp_addr;
+	int reloc;
+	volatile i2c8xx_t *i2c;
+	volatile iic_t	*iip;
+	volatile cpm8xx_t *cp;
+
+	u_char	temp[513];
+};
+
+int i2c_8xx_add_bus(struct i2c_adapter *);
+int i2c_8xx_del_bus(struct i2c_adapter *);
+
+#endif /* I2C_ALGO_8XX_H */
+

^ permalink raw reply

* Re: [PATCH] 8xx: add cpm_get_cpmp()
From: Marcelo Tosatti @ 2005-08-07  0:33 UTC (permalink / raw)
  To: Aristeu Sergio Rozanski Filho; +Cc: linuxppc-embedded
In-Reply-To: <20050806234244.GB5210@cathedrallabs.org>

On Sat, Aug 06, 2005 at 08:42:44PM -0300, Aristeu Sergio Rozanski Filho wrote:
> > It already is exported, declared as
> > 
> > commproc.h:extern       cpm8xx_t        *cpmp;          /* Pointer to comm processor */
> > 
> > 
> > and many drivers use the pointer directly.
> > 
> > arch/ppc/8260_io/ drivers also use the same convention.
> > 
> > Not sure I see much advantage in changing it?
> but not with EXPORT_SYMBOL(). I noticed this while compiling i2c stuff
> as module. 

Then other modules suffer from the same problem - what if you EXPORT_SYMBOL(cpmp)? 

> also, I think it's better add a function to do this instead
> doing EXPORT_SYMBOL() in a variable.
> what you think?

Well it is better in theory because it hides details, but in practice
I'm not sure its worth it - the CPM pointer (along with the whole immap)
never changes during runtime.

^ permalink raw reply

* Volunteers to test i2c-algo-8xx on v2.6?
From: Marcelo Tosatti @ 2005-08-07  0:34 UTC (permalink / raw)
  To: Aristeu Sergio Rozanski Filho; +Cc: linuxppc-embedded
In-Reply-To: <20050807000815.GC5210@cathedrallabs.org>

On Sat, Aug 06, 2005 at 09:08:15PM -0300, Aristeu Sergio Rozanski Filho wrote:
> > Would be good to test before submitting? :)
> I would like but I don't have the hardware and Alex (who reported this
> on bugzilla) told me he doesn't have it anymore. feel free to discard it
> until someone tests it

Does anyone volunteer to test this 8xx i2c driver?

> 
> > > +static  void
> > > +cpm_iic_interrupt(void *dev_id, struct pt_regs *regs)
> > > + {
> > > +	volatile i2c8xx_t *i2c = (i2c8xx_t *)dev_id;
> > 
> > You got an extra space everywhere other than the initial TAB?
> fixed this and others I found in the file, patch attached
> 
> -- 
> Aristeu
> 

> 8xx: port i2c-algo_8xx to 2.6
> 
> Based on Tom Rini's work
> 
> Signed-off-by: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
> 
> Index: 8xx/drivers/i2c/algos/i2c-algo-8xx.c
> ===================================================================
> --- /dev/null	1970-01-01 00:00:00.000000000 +0000
> +++ 8xx/drivers/i2c/algos/i2c-algo-8xx.c	2005-08-06 21:04:37.000000000 -0300
> @@ -0,0 +1,625 @@
> +/*
> + * i2c-algo-8xx.c i2x driver algorithms for MPC8XX CPM
> + * Copyright (c) 1999 Dan Malek (dmalek@jlc.net).
> + *
> +    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., 675 Mass Ave, Cambridge, MA 02139, USA.
> + *
> + * moved into proper i2c interface; separated out platform specific
> + * parts into i2c-rpx.c
> + * Brad Parker (brad@heeltoe.com)
> + */
> +
> +// XXX todo
> +// timeout sleep?
> +
> +/* $Id: i2c-algo-8xx.c,v 1.7 2002/08/03 22:48:18 ac9410 Exp $ */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/delay.h>
> +#include <linux/slab.h>
> +#include <linux/version.h>
> +#include <linux/init.h>
> +#include <asm/uaccess.h>
> +#include <linux/ioport.h>
> +#include <linux/errno.h>
> +#include <linux/sched.h>
> +
> +#include <asm/mpc8xx.h>
> +#include <asm/commproc.h>
> +
> +#include <linux/i2c.h>
> +#include <linux/i2c-algo-8xx.h>
> +
> +#define CPM_MAX_READ	513
> +/* Try uncomment this if you have an older CPU(earlier than rev D4) */
> +/* #define I2C_CHIP_ERRATA */
> +
> +static char *module_name = "i2c_algo_8xx";
> +#define DEBUGP(level, x, y...) do { \
> +				if (cpm_debug >= level) \
> +					printk(KERN_DEBUG "%s: " x, \
> +					       module_name, ## y); \
> +				} while(0)
> +
> +static wait_queue_head_t iic_wait;
> +static ushort r_tbase, r_rbase;
> +
> +int cpm_scan = 0;
> +int cpm_debug = 0;
> +
> +static  void
> +cpm_iic_interrupt(void *dev_id, struct pt_regs *regs)
> +{
> +	volatile i2c8xx_t *i2c = (i2c8xx_t *)dev_id;
> +
> +	DEBUGP(2, "cpm_iic_interrupt(dev_id=%p)\n", dev_id);
> +
> +#ifdef I2C_CHIP_ERRATA
> +	/* Chip errata, clear enable.
> +	 * This seems to not be needed on rev D4 or newer CPUs.
> +	 * Someone with an older CPU needs to verify this.
> +	 */
> +	i2c->i2c_i2mod &= ~1;
> +#endif
> +
> +	/* Clear interrupt.
> +	*/
> +	i2c->i2c_i2cer = 0xff;
> +
> +	/* Get 'me going again.
> +	*/
> +	wake_up_interruptible(&iic_wait);
> +}
> +
> +static void
> +cpm_iic_init(struct i2c_algo_8xx_data *cpm_adap)
> +{
> +	volatile iic_t		*iip = cpm_adap->iip;
> +	volatile i2c8xx_t	*i2c = cpm_adap->i2c;
> +	unsigned char brg;
> +	bd_t *bd = (bd_t *)__res;
> +
> +	DEBUGP(1, "cpm_iic_init() - iip=%p\n", iip);
> +
> +	/* Initialize the parameter ram.
> +	 * We need to make sure many things are initialized to zero,
> +	 * especially in the case of a microcode patch.
> +	 */
> +	iip->iic_rstate = 0;
> +	iip->iic_rdp = 0;
> +	iip->iic_rbptr = 0;
> +	iip->iic_rbc = 0;
> +	iip->iic_rxtmp = 0;
> +	iip->iic_tstate = 0;
> +	iip->iic_tdp = 0;
> +	iip->iic_tbptr = 0;
> +	iip->iic_tbc = 0;
> +	iip->iic_txtmp = 0;
> +
> +	/* Set up the IIC parameters in the parameter ram.
> +	*/
> +	iip->iic_tbase = r_tbase = cpm_adap->dp_addr;
> +	iip->iic_rbase = r_rbase = cpm_adap->dp_addr + sizeof(cbd_t) * 2;
> +
> +	iip->iic_tfcr = SMC_EB;
> +	iip->iic_rfcr = SMC_EB;
> +
> +	/* Set maximum receive size.
> +	*/
> +	iip->iic_mrblr = CPM_MAX_READ;
> +
> +	/* Initialize Tx/Rx parameters.
> +	*/
> +	if (cpm_adap->reloc == 0) {
> +		volatile cpm8xx_t *cp = cpm_adap->cp;
> +
> +		cp->cp_cpcr =
> +			mk_cr_cmd(CPM_CR_CH_I2C, CPM_CR_INIT_TRX) | CPM_CR_FLG;
> +		while (cp->cp_cpcr & CPM_CR_FLG);
> +	} else {
> +		iip->iic_rbptr = iip->iic_rbase;
> +		iip->iic_tbptr = iip->iic_tbase;
> +		iip->iic_rstate	= 0;
> +		iip->iic_tstate	= 0;
> +	}
> +
> +	/* Select an arbitrary address.  Just make sure it is unique.
> +	*/
> +	i2c->i2c_i2add = 0xfe;
> +
> +	/* Make clock run at 60 KHz.
> +	*/
> +	brg = (unsigned char) (bd->bi_intfreq/(32*2*60000) -3);
> +	i2c->i2c_i2brg = brg;
> +
> +	i2c->i2c_i2mod = 0x00;
> +	i2c->i2c_i2com = 0x01; /* Master mode */
> +
> +	/* Disable interrupts.
> +	*/
> +	i2c->i2c_i2cmr = 0;
> +	i2c->i2c_i2cer = 0xff;
> +
> +	init_waitqueue_head(&iic_wait);
> +
> +	/* Install interrupt handler.
> +	*/
> +	DEBUGP(1, "Install ISR for IRQ %d\n", CPMVEC_I2C);
> +	cpm_install_handler(CPMVEC_I2C, cpm_iic_interrupt, (void *)i2c);
> +}
> +
> +
> +static int
> +cpm_iic_shutdown(struct i2c_algo_8xx_data *cpm_adap)
> +{
> +	volatile i2c8xx_t *i2c = cpm_adap->i2c;
> +
> +	/* Shut down IIC.
> +	*/
> +	i2c->i2c_i2mod &= ~1;
> +	i2c->i2c_i2cmr = 0;
> +	i2c->i2c_i2cer = 0xff;
> +
> +	return 0;
> +}
> +
> +static void
> +cpm_reset_iic_params(volatile iic_t *iip)
> +{
> +	iip->iic_tbase = r_tbase;
> +	iip->iic_rbase = r_rbase;
> +
> +	iip->iic_tfcr = SMC_EB;
> +	iip->iic_rfcr = SMC_EB;
> +
> +	iip->iic_mrblr = CPM_MAX_READ;
> +
> +	iip->iic_rstate = 0;
> +	iip->iic_rdp = 0;
> +	iip->iic_rbptr = iip->iic_rbase;
> +	iip->iic_rbc = 0;
> +	iip->iic_rxtmp = 0;
> +	iip->iic_tstate = 0;
> +	iip->iic_tdp = 0;
> +	iip->iic_tbptr = iip->iic_tbase;
> +	iip->iic_tbc = 0;
> +	iip->iic_txtmp = 0;
> +}
> +
> +#define BD_SC_NAK		((ushort)0x0004) /* NAK - did not respond */
> +#define BD_SC_OV		((ushort)0x0002) /* OV - receive overrun */
> +#define CPM_CR_CLOSE_RXBD	((ushort)0x0007)
> +
> +static void force_close(struct i2c_algo_8xx_data *cpm)
> +{
> +	volatile i2c8xx_t *i2c = cpm->i2c;
> +	if (cpm->reloc == 0) { /* micro code disabled */
> +		volatile cpm8xx_t *cp = cpm->cp;
> +
> +		DEBUGP(1, "force_close()\n");
> +		cp->cp_cpcr =
> +			mk_cr_cmd(CPM_CR_CH_I2C, CPM_CR_CLOSE_RXBD) |
> +			CPM_CR_FLG;
> +
> +		while (cp->cp_cpcr & CPM_CR_FLG);
> +	}
> +	i2c->i2c_i2cmr = 0x00;	/* Disable all interrupts */
> +	i2c->i2c_i2cer = 0xff;
> +}
> +
> +
> +/* Read from IIC...
> + * abyte = address byte, with r/w flag already set
> + */
> +static int
> +cpm_iic_read(struct i2c_algo_8xx_data *cpm, u_char abyte, char *buf, int count)
> +{
> +	volatile iic_t *iip = cpm->iip;
> +	volatile i2c8xx_t *i2c = cpm->i2c;
> +	volatile cpm8xx_t *cp = cpm->cp;
> +	volatile cbd_t	*tbdf, *rbdf;
> +	u_char *tb;
> +	unsigned long flags, tmo;
> +
> +	if (count >= CPM_MAX_READ)
> +		return -EINVAL;
> +
> +	/* check for and use a microcode relocation patch */
> +	if (cpm->reloc)
> +		cpm_reset_iic_params(iip);
> +
> +	tbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_tbase];
> +	rbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_rbase];
> +
> +	/* To read, we need an empty buffer of the proper length.
> +	 * All that is used is the first byte for address, the remainder
> +	 * is just used for timing (and doesn't really have to exist).
> +	 */
> +	tb = cpm->temp;
> +	tb = (u_char *)(((uint)tb + 15) & ~15);
> +	tb[0] = abyte;		/* Device address byte w/rw flag */
> +
> +	flush_dcache_range((unsigned long) tb, (unsigned long) (tb + 1));
> +
> +	DEBUGP(1, "cpm_iic_read(abyte=0x%x)\n", abyte);
> +
> +	tbdf->cbd_bufaddr = __pa(tb);
> +	tbdf->cbd_datlen = count + 1;
> +	tbdf->cbd_sc =
> +		BD_SC_READY | BD_SC_LAST |
> +		BD_SC_WRAP | BD_IIC_START;
> +
> +	iip->iic_mrblr = count + 1; /* prevent excessive read, +1
> +				      is needed otherwise will the
> +				      RXB interrupt come too early */
> +
> +	/* flush will invalidate too. */
> +	flush_dcache_range((unsigned long) buf, (unsigned long) (buf+count));
> +
> +	rbdf->cbd_datlen = 0;
> +	rbdf->cbd_bufaddr = __pa(buf);
> +
> +	rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP| BD_SC_INTRPT;
> +	if(count > 16){
> +		/* Chip bug, set enable here */
> +		local_irq_save(flags);
> +		i2c->i2c_i2cmr = 0x13;	/* Enable some interupts */
> +		i2c->i2c_i2cer = 0xff;
> +		i2c->i2c_i2mod |= 1;	/* Enable */
> +		i2c->i2c_i2com |= 0x80;	/* Begin transmission */
> +
> +		/* Wait for IIC transfer */
> +		tmo = interruptible_sleep_on_timeout(&iic_wait,1*HZ);
> +		local_irq_restore(flags);
> +	} else { /* busy wait for small transfers, its faster */
> +		i2c->i2c_i2cmr = 0x00;	/* Disable I2C interupts */
> +		i2c->i2c_i2cer = 0xff;
> +		i2c->i2c_i2mod |= 1;	/* Enable */
> +		i2c->i2c_i2com |= 0x80;	/* Begin transmission */
> +		tmo = jiffies + 1*HZ;
> +	       	/* Busy wait, with a timeout */
> +		while(!(i2c->i2c_i2cer & 0x11 || time_after(jiffies, tmo)));
> +	}
> +
> +	if (signal_pending(current) || !tmo){
> +		force_close(cpm);
> +		DEBUGP(1, "IIC read: timeout!\n");
> +		return -EIO;
> +	}
> +#ifdef I2C_CHIP_ERRATA
> +	/* Chip errata, clear enable. This is not needed on rev D4 CPUs.
> +	 Disabling I2C too early may cause too short stop condition */
> +	udelay(4);
> +	i2c->i2c_i2mod &= ~1;
> +#endif
> +
> +	DEBUGP(1, "tx sc %04x, rx sc %04x\n", tbdf->cbd_sc, rbdf->cbd_sc);
> +
> +	if (tbdf->cbd_sc & BD_SC_READY) {
> +		printk(KERN_INFO "IIC read; complete but tbuf ready\n");
> +		force_close(cpm);
> +		printk(KERN_INFO "tx sc %04x, rx sc %04x\n",
> +		       tbdf->cbd_sc, rbdf->cbd_sc);
> +	}
> +
> +	if (tbdf->cbd_sc & BD_SC_NAK) {
> +		DEBUGP(1, "IIC read; no ack\n");
> +		return -EREMOTEIO;
> +	}
> +
> +	if (rbdf->cbd_sc & BD_SC_EMPTY) {
> +		/* force_close(cpm); */
> +		DEBUGP(1, "IIC read; complete but rbuf empty\n");
> +		DEBUGP(1, "tx sc %04x, rx sc %04x\n", tbdf->cbd_sc, rbdf->cbd_sc);
> +		return -EREMOTEIO;
> +	}
> +
> +	if (rbdf->cbd_sc & BD_SC_OV) {
> +		DEBUGP(1, "IIC read; Overrun\n");
> +		return -EREMOTEIO;;
> +	}
> +
> +	DEBUGP(1, "read %d bytes\n", rbdf->cbd_datlen);
> +
> +	if (rbdf->cbd_datlen < count) {
> +		DEBUGP(1, "IIC read; short, wanted %d got %d\n", count,
> +		       rbdf->cbd_datlen);
> +		return 0;
> +	}
> +
> +	return count;
> +}
> +
> +/* Write to IIC...
> + * addr = address byte, with r/w flag already set
> + */
> +static int
> +cpm_iic_write(struct i2c_algo_8xx_data *cpm, u_char abyte, char *buf,int count)
> +{
> +	volatile iic_t *iip = cpm->iip;
> +	volatile i2c8xx_t *i2c = cpm->i2c;
> +	volatile cpm8xx_t *cp = cpm->cp;
> +	volatile cbd_t	*tbdf;
> +	u_char *tb;
> +	unsigned long flags, tmo;
> +
> +	/* check for and use a microcode relocation patch */
> +	if (cpm->reloc)
> +		cpm_reset_iic_params(iip);
> +	tb = cpm->temp;
> +	tb = (u_char *)(((uint)tb + 15) & ~15);
> +	*tb = abyte;		/* Device address byte w/rw flag */
> +
> +	flush_dcache_range((unsigned long) tb, (unsigned long) (tb+1));
> +	flush_dcache_range((unsigned long) buf, (unsigned long) (buf+count));
> +
> +	DEBUGP(1, "cpm_iic_write(abyte=0x%x)\n", abyte);
> +
> +	/* set up 2 descriptors */
> +	tbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_tbase];
> +
> +	tbdf[0].cbd_bufaddr = __pa(tb);
> +	tbdf[0].cbd_datlen = 1;
> +	tbdf[0].cbd_sc = BD_SC_READY | BD_IIC_START;
> +
> +	tbdf[1].cbd_bufaddr = __pa(buf);
> +	tbdf[1].cbd_datlen = count;
> +	tbdf[1].cbd_sc = BD_SC_READY | BD_SC_INTRPT | BD_SC_LAST | BD_SC_WRAP;
> +
> +	if (count > 16) {
> +		/* Chip bug, set enable here */
> +		local_irq_save(flags);
> +		i2c->i2c_i2cmr = 0x13;	/* Enable some interupts */
> +		i2c->i2c_i2cer = 0xff;
> +		i2c->i2c_i2mod |= 1;	/* Enable */
> +		i2c->i2c_i2com |= 0x80;	/* Begin transmission */
> +
> +		/* Wait for IIC transfer */
> +		tmo = interruptible_sleep_on_timeout(&iic_wait,1*HZ);
> +		local_irq_restore(flags);
> +	} else {  /* busy wait for small transfers, its faster */
> +		i2c->i2c_i2cmr = 0x00;	/* Disable I2C interupts */
> +		i2c->i2c_i2cer = 0xff;
> +		i2c->i2c_i2mod |= 1;	/* Enable */
> +		i2c->i2c_i2com |= 0x80;	/* Begin transmission */
> +		tmo = jiffies + 1*HZ;
> +	       	/* Busy wait, with a timeout */
> +		while(!(i2c->i2c_i2cer & 0x12 || time_after(jiffies, tmo)));
> +	}
> +
> +	if (signal_pending(current) || !tmo){
> +		force_close(cpm);
> +		if (!tmo)
> +			DEBUGP(1, "IIC write: timeout!\n");
> +		return -EIO;
> +	}
> +
> +#if I2C_CHIP_ERRATA
> +	/* Chip errata, clear enable. This is not needed on rev D4 CPUs.
> +	 Disabling I2C too early may cause too short stop condition */
> +	udelay(4);
> +	i2c->i2c_i2mod &= ~1;
> +#endif
> +	DEBUGP(1, "tx0 sc %04x, tx1 sc %04x\n", tbdf[0].cbd_sc,
> +	       tbdf[1].cbd_sc);
> +
> +	if ((tbdf[0].cbd_sc | tbdf[1].cbd_sc) & BD_SC_NAK) {
> +		DEBUGP(1, "IIC write; no ack\n");
> +		return 0;
> +	}
> +
> +	if ((tbdf[0].cbd_sc | tbdf[1].cbd_sc) & BD_SC_READY) {
> +		DEBUGP(1, "IIC write; complete but tbuf ready\n");
> +		return 0;
> +	}
> +
> +	return count;
> +}
> +
> +/* See if an IIC address exists..
> + * addr = 7 bit address, unshifted
> + */
> +static int
> +cpm_iic_tryaddress(struct i2c_algo_8xx_data *cpm, int addr)
> +{
> +	volatile iic_t *iip = cpm->iip;
> +	volatile i2c8xx_t *i2c = cpm->i2c;
> +	volatile cpm8xx_t *cp = cpm->cp;
> +	volatile cbd_t *tbdf, *rbdf;
> +	u_char *tb;
> +	unsigned long flags, len, tmo;
> +
> +	DEBUGP(2, "cpm_iic_tryaddress(cpm=%p,addr=%d)\n", cpm, addr);
> +
> +	/* check for and use a microcode relocation patch */
> +	if (cpm->reloc)
> +		cpm_reset_iic_params(iip);
> +
> +	if (addr == 0) {
> +		DEBUGP(1, "iip %p, dp_addr 0x%x\n", cpm->iip, cpm->dp_addr);
> +		DEBUGP(1, "iic_tbase %d, r_tbase %d\n", iip->iic_tbase,
> +		       r_tbase);
> +	}
> +
> +	tbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_tbase];
> +	rbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_rbase];
> +
> +	tb = cpm->temp;
> +	tb = (u_char *)(((uint)tb + 15) & ~15);
> +
> +	/* do a simple read */
> +	tb[0] = (addr << 1) | 1;	/* device address (+ read) */
> +	len = 2;
> +
> +	flush_dcache_range((unsigned long) tb, (unsigned long) (tb+1));
> +
> +	tbdf->cbd_bufaddr = __pa(tb);
> +	tbdf->cbd_datlen = len;
> +	tbdf->cbd_sc =
> +		BD_SC_READY | BD_SC_LAST |
> +		BD_SC_WRAP | BD_IIC_START;
> +
> +	rbdf->cbd_datlen = 0;
> +	rbdf->cbd_bufaddr = __pa(tb+2);
> +	rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP | BD_SC_INTRPT;
> +
> +	local_irq_save(flags);
> +	i2c->i2c_i2cmr = 0x13;	/* Enable some interupts */
> +	i2c->i2c_i2cer = 0xff;
> +	i2c->i2c_i2mod |= 1;	/* Enable */
> +	i2c->i2c_i2com |= 0x80;	/* Begin transmission */
> +
> +	DEBUGP(1, "about to sleep\n");
> +
> +	/* wait for IIC transfer */
> +	tmo = interruptible_sleep_on_timeout(&iic_wait,1*HZ);
> +	local_irq_restore(flags);
> +
> +#ifdef I2C_CHIP_ERRATA
> +	/* Chip errata, clear enable. This is not needed on rev D4 CPUs.
> +	 Disabling I2C too early may cause too short stop condition */
> +	udelay(4);
> +	i2c->i2c_i2mod &= ~1;
> +#endif
> +
> +	if (signal_pending(current) || !tmo){
> +		force_close(cpm);
> +		if (!tmo)
> +			DEBUGP(1, "IIC tryaddress: timeout!\n");
> +		return -EIO;
> +	}
> +
> +	DEBUGP(2, "back from sleep\n");
> +
> +	if (tbdf->cbd_sc & BD_SC_NAK) {
> +		DEBUGP(2, "IIC try; no ack\n");
> +		return 0;
> +	}
> +
> +	if (tbdf->cbd_sc & BD_SC_READY)
> +		printk(KERN_INFO "IIC try; complete but tbuf ready\n");
> +
> +	return 1;
> +}
> +
> +static int cpm_xfer(struct i2c_adapter *i2c_adap,
> +		    struct i2c_msg msgs[],
> +		    int num)
> +{
> +	struct i2c_algo_8xx_data *adap = i2c_adap->algo_data;
> +	struct i2c_msg *pmsg;
> +	int i, ret;
> +	u_char addr;
> +
> +	for (i = 0; i < num; i++) {
> +		pmsg = &msgs[i];
> +
> +		DEBUGP(1, "#%d addr=0x%x flags=0x%x len=%d\n buf=%p\n",
> +		       i, pmsg->addr, pmsg->flags, pmsg->len, pmsg->buf);
> +
> +		addr = pmsg->addr << 1;
> +		if (pmsg->flags & I2C_M_RD)
> +			addr |= 1;
> +		if (pmsg->flags & I2C_M_REV_DIR_ADDR)
> +			addr ^= 1;
> +
> +		if (pmsg->flags & I2C_M_RD) {
> +			/* read bytes into buffer*/
> +			ret = cpm_iic_read(adap, addr, pmsg->buf, pmsg->len);
> +			DEBUGP(1, "read %d bytes\n", ret);
> +			if (ret < pmsg->len)
> +				return (ret < 0)? ret:-EREMOTEIO;
> +		} else {
> +			/* write bytes from buffer */
> +			ret = cpm_iic_write(adap, addr, pmsg->buf, pmsg->len);
> +			DEBUGP(1, "wrote %d\n", ret);
> +			if (ret < pmsg->len)
> +				return (ret < 0)? ret:-EREMOTEIO;
> +		}
> +	}
> +	return num;
> +}
> +
> +static u32 cpm_func(struct i2c_adapter *adap)
> +{
> +	return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR |
> +	       I2C_FUNC_PROTOCOL_MANGLING;
> +}
> +
> +static struct i2c_algorithm i2c_algo_8xx = {
> +	.name = "MPC8xx CPM algorithm",
> +	.id = I2C_ALGO_MPC8XX,
> +	.master_xfer = cpm_xfer,
> +	.functionality = cpm_func,
> +};
> +
> +/*
> + * registering functions to load algorithms at runtime
> + */
> +int i2c_8xx_add_bus(struct i2c_adapter *adap)
> +{
> +	int i;
> +	struct i2c_algo_8xx_data *cpm_adap = adap->algo_data;
> +
> +	DEBUGP(1, "hw routines for %s registered.\n", adap->name);
> +
> +	/* register new adapter to i2c module... */
> +
> +	adap->id |= i2c_algo_8xx.id;
> +	adap->algo = &i2c_algo_8xx;
> +
> +	i2c_add_adapter(adap);
> +	cpm_iic_init(cpm_adap);
> +
> +	/* scan bus */
> +	if (cpm_scan) {
> +		printk(KERN_INFO "%s: scanning bus %s...\n", module_name,
> +		       adap->name);
> +		for (i = 0; i < 128; i++)
> +			if (cpm_iic_tryaddress(cpm_adap, i)) {
> +				printk("(%02x)", i << 1);
> +			}
> +		printk("\n");
> +	}
> +	return 0;
> +}
> +
> +int i2c_8xx_del_bus(struct i2c_adapter *adap)
> +{
> +	int res;
> +	struct i2c_algo_8xx_data *cpm_adap = adap->algo_data;
> +
> +	cpm_iic_shutdown(cpm_adap);
> +
> +	if ((res = i2c_del_adapter(adap)) < 0)
> +		return res;
> +
> +	printk(KERN_INFO "%s: adapter unregistered: %s\n", module_name,
> +	       adap->name);
> +
> +	return 0;
> +}
> +
> +module_param(cpm_debug, int, S_IRUGO | S_IWUSR);
> +MODULE_PARM_DESC(cpm_debug, "Sets the debug level. (0 = none, 1 = normal, "
> +		 ">1 = plenty");
> +MODULE_AUTHOR("Brad Parker <brad@heeltoe.com>");
> +MODULE_DESCRIPTION("I2C-Bus MPC8XX algorithm");
> +MODULE_LICENSE("GPL");
> +
> +EXPORT_SYMBOL(i2c_8xx_add_bus);
> +EXPORT_SYMBOL(i2c_8xx_del_bus);
> +
> Index: 8xx/drivers/i2c/algos/Makefile
> ===================================================================
> --- 8xx.orig/drivers/i2c/algos/Makefile	2005-08-06 14:40:49.000000000 -0300
> +++ 8xx/drivers/i2c/algos/Makefile	2005-08-06 21:03:57.000000000 -0300
> @@ -8,6 +8,7 @@
>  obj-$(CONFIG_I2C_ALGOITE)	+= i2c-algo-ite.o
>  obj-$(CONFIG_I2C_ALGO_SIBYTE)	+= i2c-algo-sibyte.o
>  obj-$(CONFIG_I2C_ALGO_SGI)	+= i2c-algo-sgi.o
> +obj-$(CONFIG_I2C_ALGO8XX)	+= i2c-algo-8xx.o
>  
>  ifeq ($(CONFIG_I2C_DEBUG_ALGO),y)
>  EXTRA_CFLAGS += -DDEBUG
> Index: 8xx/include/linux/i2c-algo-8xx.h
> ===================================================================
> --- /dev/null	1970-01-01 00:00:00.000000000 +0000
> +++ 8xx/include/linux/i2c-algo-8xx.h	2005-08-06 21:03:57.000000000 -0300
> @@ -0,0 +1,28 @@
> +/* ------------------------------------------------------------------------- */
> +/* i2c-algo-8xx.h i2c driver algorithms for MPX8XX CPM			     */
> +/* ------------------------------------------------------------------------- */
> +
> +/* $Id$ */
> +
> +#ifndef I2C_ALGO_8XX_H
> +#define I2C_ALGO_8XX_H
> +
> +#include <linux/i2c.h>
> +#include <asm/8xx_immap.h>
> +#include <asm/commproc.h>
> +
> +struct i2c_algo_8xx_data {
> +	uint dp_addr;
> +	int reloc;
> +	volatile i2c8xx_t *i2c;
> +	volatile iic_t	*iip;
> +	volatile cpm8xx_t *cp;
> +
> +	u_char	temp[513];
> +};
> +
> +int i2c_8xx_add_bus(struct i2c_adapter *);
> +int i2c_8xx_del_bus(struct i2c_adapter *);
> +
> +#endif /* I2C_ALGO_8XX_H */
> +

^ permalink raw reply

* Re: [PATCH] 8xx: add cpm_get_cpmp()
From: Dan Malek @ 2005-08-07  2:40 UTC (permalink / raw)
  To: Marcelo Tosatti; +Cc: linuxppc-embedded
In-Reply-To: <20050806232701.GD1099@dmt.cnet>


On Aug 6, 2005, at 7:27 PM, Marcelo Tosatti wrote:

> It already is exported, declared as
>
> commproc.h:extern       cpm8xx_t        *cpmp;          /* Pointer to 
> comm processor */
>
>
> and many drivers use the pointer directly.

We shouldn't be doing this.  All drivers should ioremap() any
peripheral spaces they use and not make any assumptions
someone else has done that already.  We've been making
such changes in the 82xx/83xx/85xx CPM2 drivers.  If it
isn't convenient to find the #defines for the ioremap(), we
should change that.  When I originally wrote all of this
code, it was long ago when we didn't have some of the
abstractions and it seemed any shortcuts for performance
were desired :-)


> arch/ppc/8260_io/ drivers also use the same convention.

If there are any drivers in here, they either aren't used or
on their way out.  The only things that should remain are
common support functions.


Thanks.

	-- Dan

^ permalink raw reply

* Re: [PATCH] 8xx: add cpm_get_cpmp()
From: Dan Malek @ 2005-08-07  3:36 UTC (permalink / raw)
  To: Aristeu Sergio Rozanski Filho; +Cc: linuxppc-embedded
In-Reply-To: <20050806234244.GB5210@cathedrallabs.org>


On Aug 6, 2005, at 7:42 PM, Aristeu Sergio Rozanski Filho wrote:

> but not with EXPORT_SYMBOL(). I noticed this while compiling i2c stuff
> as module. also, I think it's better add a function to do this instead
> doing EXPORT_SYMBOL() in a variable.

Right.  We should just ioremap() :-)

Thanks.

	-- Dan

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox