* 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
* Re: [PATCH] 8xx: add cpm_get_cpmp()
From: Marcelo Tosatti @ 2005-08-07 4:31 UTC (permalink / raw)
To: Dan Malek; +Cc: linuxppc-embedded
In-Reply-To: <e5caa80a2cd721a4f6ee3c74ead906b2@embeddededge.com>
On Sat, Aug 06, 2005 at 10:40:37PM -0400, Dan Malek wrote:
>
> 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 :-)
OK makes sense (yep it was even discussed already).
Aris, sounds like you should proceed with cpm_get_cpmp() and change all
other drivers using it also.
>
>
> >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.
OK!
^ permalink raw reply
* A configure error for samba3 on ppc
From: JohnsonCheng @ 2005-08-07 9:15 UTC (permalink / raw)
To: linuxppc-embedded
[-- Attachment #1: Type: text/plain, Size: 413 bytes --]
When I configure samba3.0.10 on ppc as following command:
CC=powerpc-linux-gcc AR=powerpc-linux-ar RANLIB=powerpc-linux-ranlib
./configure -host=powerpc-linux
I got a configure error message as following:
Configure: error: cannot run test program while cross compiling
See 'config.log' for more details
I think this is a samba configure bug, do anybody know how to pass it?
Thanks,
Johnson Cheng
[-- Attachment #2: Type: text/html, Size: 3541 bytes --]
^ permalink raw reply
* Re: [PATCH] 8xx: add cpm_get_cpmp()
From: Dan Malek @ 2005-08-07 15:39 UTC (permalink / raw)
To: Marcelo Tosatti; +Cc: linuxppc-embedded
In-Reply-To: <20050807043110.GA6316@dmt.cnet>
On Aug 7, 2005, at 12:31 AM, Marcelo Tosatti wrote:
> Aris, sounds like you should proceed with cpm_get_cpmp() and change all
> other drivers using it also.
It depends how you define the semantics of this function call.
Can you call it any (and all of the) time you need it, or does it
actually perform an ioremap() and you only want to call it
once?
I guess implemented properly it doesn't matter. On the first
call it should do the ioremap() and on subsequent calls it
just returns the mapping. This is one of those common
functions that should be in commproc.c.
Thanks.
-- Dan
^ permalink raw reply
* Re: [PATCH] 8xx: add cpm_get_cpmp()
From: Aristeu Sergio Rozanski Filho @ 2005-08-07 15:44 UTC (permalink / raw)
To: Dan Malek; +Cc: linuxppc-embedded
In-Reply-To: <09b0792f426f1d5883cf5d437723f075@embeddededge.com>
> It depends how you define the semantics of this function call.
> Can you call it any (and all of the) time you need it, or does it
> actually perform an ioremap() and you only want to call it
> once?
what about don't cache it and call ioremap() from driver? (I guess
ioremap() already check if an area is already mapped, no?)
--
Aristeu
^ permalink raw reply
* Re: [PATCH] 8xx: add cpm_get_cpmp()
From: Marcelo Tosatti @ 2005-08-07 15:57 UTC (permalink / raw)
To: Aristeu Sergio Rozanski Filho; +Cc: linuxppc-embedded
In-Reply-To: <20050807154432.GE5210@cathedrallabs.org>
On Sun, Aug 07, 2005 at 12:44:32PM -0300, Aristeu Sergio Rozanski Filho wrote:
> > It depends how you define the semantics of this function call.
> > Can you call it any (and all of the) time you need it, or does it
> > actually perform an ioremap() and you only want to call it
> > once?
> what about don't cache it and call ioremap() from driver? (I guess
> ioremap() already check if an area is already mapped, no?)
Yep, ioremap() should be doing virtual address caching already, no?
^ permalink raw reply
* Re: [PATCH] 8xx: add cpm_get_cpmp()
From: Dan Malek @ 2005-08-07 17:25 UTC (permalink / raw)
To: Aristeu Sergio Rozanski Filho; +Cc: linuxppc-embedded
In-Reply-To: <20050807154432.GE5210@cathedrallabs.org>
On Aug 7, 2005, at 11:44 AM, Aristeu Sergio Rozanski Filho wrote:
> what about don't cache it and call ioremap() from driver? (I guess
> ioremap() already check if an area is already mapped, no?)
Either way. I'm actually leaning toward these "pointer helper"
functions. :-) Something like get_cpmp(), or get_immr(), that will
hide the details of the mapping, so you don't have to include
and know which #defines to use as part of an ioremap() call.
It seems to be more clear to me, and I'm thinking about making
the same changes to the CPM2 drivers. It also allows a
performance versus compact code trade off, declaring these
as inline functions or as real functions.
Thanks.
-- Dan
^ permalink raw reply
* Re: [PATCH] 8xx: add cpm_get_cpmp()
From: Eugene Surovegin @ 2005-08-07 19:18 UTC (permalink / raw)
To: Marcelo Tosatti; +Cc: linuxppc-embedded
In-Reply-To: <20050807155731.GA2715@dmt.cnet>
On Sun, Aug 07, 2005 at 12:57:31PM -0300, Marcelo Tosatti wrote:
> On Sun, Aug 07, 2005 at 12:44:32PM -0300, Aristeu Sergio Rozanski Filho wrote:
> > > It depends how you define the semantics of this function call.
> > > Can you call it any (and all of the) time you need it, or does it
> > > actually perform an ioremap() and you only want to call it
> > > once?
> > what about don't cache it and call ioremap() from driver? (I guess
> > ioremap() already check if an area is already mapped, no?)
>
> Yep, ioremap() should be doing virtual address caching already, no?
In general, ioremap() doesn't do any caching currently. Some subarchs
do some limited caching, e.g. if BATs (classic PPC) or CAMs (e500) are
available and were used previously for ioremap() mappings.
Some time ago I made a trivial ioremap cache patch (useful on 4xx,
which doesn't have BATs nor CAMs), although it wass really a hack and
it was never merged :).
--
Eugene
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox