* [PATCH] I2C: Fix twl4030 timeouts on omap3430 @ 2008-03-28 8:41 Tony Lindgren 2008-03-31 10:43 ` Tony Lindgren 0 siblings, 1 reply; 11+ messages in thread From: Tony Lindgren @ 2008-03-28 8:41 UTC (permalink / raw) To: linux-omap [-- Attachment #1: Type: text/plain, Size: 294 bytes --] Hi all, This helps with the annoying I2C timeouts. Does anybody have an idea why the twl4030 chip does not like doing multiple transfers in a row? To me the only difference seems to be that clocks are idled between writing the twl4030 register and reading the register value. Regards, Tony [-- Attachment #2: i2c-twl4030-timeout.patch --] [-- Type: text/x-diff, Size: 1640 bytes --] >From 25c4c8f449819cb6f40b59ed1a9b25ebcc7cd72e Mon Sep 17 00:00:00 2001 From: Tony Lindgren <tony@atomide.com> Date: Thu, 27 Mar 2008 19:05:30 +0200 Subject: [PATCH] I2C: Fix twl4030 timeouts on omap3430 For some reason doing a twl4030 write-read cycle can hang the I2C bus on omap3430. And doing the write and read separately in twl4030_i2c_read() seems to fix the problem... Not intended for applying, just a temporary workaround. diff --git a/drivers/i2c/chips/twl4030-core.c b/drivers/i2c/chips/twl4030-core.c index ded86e7..62868b0 100644 --- a/drivers/i2c/chips/twl4030-core.c +++ b/drivers/i2c/chips/twl4030-core.c @@ -327,6 +327,7 @@ int twl4030_i2c_read(u8 mod_no, u8 * value, u8 reg, u8 num_bytes) return -EPERM; } mutex_lock(&twl->xfer_lock); + /* [MSG1] fill the register address data */ msg = &twl->xfer_msg[0]; msg->addr = twl->address; @@ -334,18 +335,25 @@ int twl4030_i2c_read(u8 mod_no, u8 * value, u8 reg, u8 num_bytes) msg->flags = 0; /* Read the register value */ val = twl4030_map[mod_no].base + reg; msg->buf = &val; + ret = i2c_transfer(twl->client.adapter, twl->xfer_msg, 1); + if (ret < 0) + goto out; + /* [MSG2] fill the data rx buffer */ msg = &twl->xfer_msg[1]; msg->addr = twl->address; msg->flags = I2C_M_RD; /* Read the register value */ msg->len = num_bytes; /* only n bytes */ msg->buf = value; - ret = i2c_transfer(twl->client.adapter, twl->xfer_msg, 2); + ret = i2c_transfer(twl->client.adapter, twl->xfer_msg, 1); + +out: mutex_unlock(&twl->xfer_lock); /* i2cTransfer returns num messages.translate it pls.. */ if (ret >= 0) ret = 0; + return ret; } ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH] I2C: Fix twl4030 timeouts on omap3430 2008-03-28 8:41 [PATCH] I2C: Fix twl4030 timeouts on omap3430 Tony Lindgren @ 2008-03-31 10:43 ` Tony Lindgren 2008-03-31 14:30 ` Tony Lindgren 0 siblings, 1 reply; 11+ messages in thread From: Tony Lindgren @ 2008-03-31 10:43 UTC (permalink / raw) To: linux-omap * Tony Lindgren <tony@atomide.com> [080328 10:41]: > Hi all, > > This helps with the annoying I2C timeouts. Does anybody have an idea > why the twl4030 chip does not like doing multiple transfers in a row? > > To me the only difference seems to be that clocks are idled between > writing the twl4030 register and reading the register value. I'll push this today with a REVISIT comment added. Tony > From 25c4c8f449819cb6f40b59ed1a9b25ebcc7cd72e Mon Sep 17 00:00:00 2001 > From: Tony Lindgren <tony@atomide.com> > Date: Thu, 27 Mar 2008 19:05:30 +0200 > Subject: [PATCH] I2C: Fix twl4030 timeouts on omap3430 > > For some reason doing a twl4030 write-read cycle can hang the I2C bus > on omap3430. And doing the write and read separately in twl4030_i2c_read() > seems to fix the problem... > > Not intended for applying, just a temporary workaround. > > diff --git a/drivers/i2c/chips/twl4030-core.c b/drivers/i2c/chips/twl4030-core.c > index ded86e7..62868b0 100644 > --- a/drivers/i2c/chips/twl4030-core.c > +++ b/drivers/i2c/chips/twl4030-core.c > @@ -327,6 +327,7 @@ int twl4030_i2c_read(u8 mod_no, u8 * value, u8 reg, u8 num_bytes) > return -EPERM; > } > mutex_lock(&twl->xfer_lock); > + > /* [MSG1] fill the register address data */ > msg = &twl->xfer_msg[0]; > msg->addr = twl->address; > @@ -334,18 +335,25 @@ int twl4030_i2c_read(u8 mod_no, u8 * value, u8 reg, u8 num_bytes) > msg->flags = 0; /* Read the register value */ > val = twl4030_map[mod_no].base + reg; > msg->buf = &val; > + ret = i2c_transfer(twl->client.adapter, twl->xfer_msg, 1); > + if (ret < 0) > + goto out; > + > /* [MSG2] fill the data rx buffer */ > msg = &twl->xfer_msg[1]; > msg->addr = twl->address; > msg->flags = I2C_M_RD; /* Read the register value */ > msg->len = num_bytes; /* only n bytes */ > msg->buf = value; > - ret = i2c_transfer(twl->client.adapter, twl->xfer_msg, 2); > + ret = i2c_transfer(twl->client.adapter, twl->xfer_msg, 1); > + > +out: > mutex_unlock(&twl->xfer_lock); > > /* i2cTransfer returns num messages.translate it pls.. */ > if (ret >= 0) > ret = 0; > + > return ret; > } > ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] I2C: Fix twl4030 timeouts on omap3430 2008-03-31 10:43 ` Tony Lindgren @ 2008-03-31 14:30 ` Tony Lindgren 2008-04-01 12:43 ` Tony Lindgren 0 siblings, 1 reply; 11+ messages in thread From: Tony Lindgren @ 2008-03-31 14:30 UTC (permalink / raw) To: linux-omap * Tony Lindgren <tony@atomide.com> [080331 13:43]: > * Tony Lindgren <tony@atomide.com> [080328 10:41]: > > Hi all, > > > > This helps with the annoying I2C timeouts. Does anybody have an idea > > why the twl4030 chip does not like doing multiple transfers in a row? > > > > To me the only difference seems to be that clocks are idled between > > writing the twl4030 register and reading the register value. > > I'll push this today with a REVISIT comment added. Looks like this kills twl4030 interrupts, so I've reverted it. Tony > > From 25c4c8f449819cb6f40b59ed1a9b25ebcc7cd72e Mon Sep 17 00:00:00 2001 > > From: Tony Lindgren <tony@atomide.com> > > Date: Thu, 27 Mar 2008 19:05:30 +0200 > > Subject: [PATCH] I2C: Fix twl4030 timeouts on omap3430 > > > > For some reason doing a twl4030 write-read cycle can hang the I2C bus > > on omap3430. And doing the write and read separately in twl4030_i2c_read() > > seems to fix the problem... > > > > Not intended for applying, just a temporary workaround. > > > > diff --git a/drivers/i2c/chips/twl4030-core.c b/drivers/i2c/chips/twl4030-core.c > > index ded86e7..62868b0 100644 > > --- a/drivers/i2c/chips/twl4030-core.c > > +++ b/drivers/i2c/chips/twl4030-core.c > > @@ -327,6 +327,7 @@ int twl4030_i2c_read(u8 mod_no, u8 * value, u8 reg, u8 num_bytes) > > return -EPERM; > > } > > mutex_lock(&twl->xfer_lock); > > + > > /* [MSG1] fill the register address data */ > > msg = &twl->xfer_msg[0]; > > msg->addr = twl->address; > > @@ -334,18 +335,25 @@ int twl4030_i2c_read(u8 mod_no, u8 * value, u8 reg, u8 num_bytes) > > msg->flags = 0; /* Read the register value */ > > val = twl4030_map[mod_no].base + reg; > > msg->buf = &val; > > + ret = i2c_transfer(twl->client.adapter, twl->xfer_msg, 1); > > + if (ret < 0) > > + goto out; > > + > > /* [MSG2] fill the data rx buffer */ > > msg = &twl->xfer_msg[1]; > > msg->addr = twl->address; > > msg->flags = I2C_M_RD; /* Read the register value */ > > msg->len = num_bytes; /* only n bytes */ > > msg->buf = value; > > - ret = i2c_transfer(twl->client.adapter, twl->xfer_msg, 2); > > + ret = i2c_transfer(twl->client.adapter, twl->xfer_msg, 1); > > + > > +out: > > mutex_unlock(&twl->xfer_lock); > > > > /* i2cTransfer returns num messages.translate it pls.. */ > > if (ret >= 0) > > ret = 0; > > + > > return ret; > > } > > > ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] I2C: Fix twl4030 timeouts on omap3430 2008-03-31 14:30 ` Tony Lindgren @ 2008-04-01 12:43 ` Tony Lindgren 2008-04-01 13:00 ` Peter 'p2' De Schrijver 0 siblings, 1 reply; 11+ messages in thread From: Tony Lindgren @ 2008-04-01 12:43 UTC (permalink / raw) To: linux-omap * Tony Lindgren <tony@atomide.com> [080331 17:30]: > * Tony Lindgren <tony@atomide.com> [080331 13:43]: > > * Tony Lindgren <tony@atomide.com> [080328 10:41]: > > > Hi all, > > > > > > This helps with the annoying I2C timeouts. Does anybody have an idea > > > why the twl4030 chip does not like doing multiple transfers in a row? > > > > > > To me the only difference seems to be that clocks are idled between > > > writing the twl4030 register and reading the register value. > > > > I'll push this today with a REVISIT comment added. > > Looks like this kills twl4030 interrupts, so I've reverted it. After looking into this problem a bit more, looks like twl4030 reads to anything in "POWER ID" (modules 0x10 and higher) will hang twl4030 eventually and I2C controller gets stuck in mode where STP never clears. Repeated reads to "USB ID", "AUD ID" or "AUX ID" will not hang twl4030. Tony ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] I2C: Fix twl4030 timeouts on omap3430 2008-04-01 12:43 ` Tony Lindgren @ 2008-04-01 13:00 ` Peter 'p2' De Schrijver 2008-04-01 13:38 ` Tony Lindgren 0 siblings, 1 reply; 11+ messages in thread From: Peter 'p2' De Schrijver @ 2008-04-01 13:00 UTC (permalink / raw) To: ext Tony Lindgren; +Cc: linux-omap On Tue, Apr 01, 2008 at 03:43:56PM +0300, ext Tony Lindgren wrote: > * Tony Lindgren <tony@atomide.com> [080331 17:30]: > > * Tony Lindgren <tony@atomide.com> [080331 13:43]: > > > * Tony Lindgren <tony@atomide.com> [080328 10:41]: > > > > Hi all, > > > > > > > > This helps with the annoying I2C timeouts. Does anybody have an idea > > > > why the twl4030 chip does not like doing multiple transfers in a row? > > > > > > > > To me the only difference seems to be that clocks are idled between > > > > writing the twl4030 register and reading the register value. > > > > > > I'll push this today with a REVISIT comment added. > > > > Looks like this kills twl4030 interrupts, so I've reverted it. > > After looking into this problem a bit more, looks like twl4030 reads > to anything in "POWER ID" (modules 0x10 and higher) will hang twl4030 > eventually and I2C controller gets stuck in mode where STP never clears. > > Repeated reads to "USB ID", "AUD ID" or "AUX ID" will not hang twl4030. > I remember seeing something similar when doing the powerbutton code. Klaus Pedersen found out that leaving CFG_BOOT to its reset value solved the problem. Unfortunately this breaks MADC and USB afaics, so it's not a real solution. CFG_BOOT is programmed in power_companion_init(). Cheers, Peter. -- goa is a state of mind ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] I2C: Fix twl4030 timeouts on omap3430 2008-04-01 13:00 ` Peter 'p2' De Schrijver @ 2008-04-01 13:38 ` Tony Lindgren 2008-04-01 14:04 ` Tony Lindgren 0 siblings, 1 reply; 11+ messages in thread From: Tony Lindgren @ 2008-04-01 13:38 UTC (permalink / raw) To: Peter 'p2' De Schrijver; +Cc: linux-omap * Peter 'p2' De Schrijver <peter.de-schrijver@nokia.com> [080401 16:01]: > On Tue, Apr 01, 2008 at 03:43:56PM +0300, ext Tony Lindgren wrote: > > * Tony Lindgren <tony@atomide.com> [080331 17:30]: > > > * Tony Lindgren <tony@atomide.com> [080331 13:43]: > > > > * Tony Lindgren <tony@atomide.com> [080328 10:41]: > > > > > Hi all, > > > > > > > > > > This helps with the annoying I2C timeouts. Does anybody have an idea > > > > > why the twl4030 chip does not like doing multiple transfers in a row? > > > > > > > > > > To me the only difference seems to be that clocks are idled between > > > > > writing the twl4030 register and reading the register value. > > > > > > > > I'll push this today with a REVISIT comment added. > > > > > > Looks like this kills twl4030 interrupts, so I've reverted it. > > > > After looking into this problem a bit more, looks like twl4030 reads > > to anything in "POWER ID" (modules 0x10 and higher) will hang twl4030 > > eventually and I2C controller gets stuck in mode where STP never clears. > > > > Repeated reads to "USB ID", "AUD ID" or "AUX ID" will not hang twl4030. > > > > I remember seeing something similar when doing the powerbutton code. > Klaus Pedersen found out that leaving CFG_BOOT to its reset value solved > the problem. Unfortunately this breaks MADC and USB afaics, so it's not > a real solution. CFG_BOOT is programmed in power_companion_init(). Great, this helped a lot! Looks like power_companion_init() tries to get osc_ck without checking for clkg_get() return value, and osc_ck does not exist in clock34xx.h. So R_CFG_BOOT gets set to default 26MHz value :) Will post a patch when available. Tony ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] I2C: Fix twl4030 timeouts on omap3430 2008-04-01 13:38 ` Tony Lindgren @ 2008-04-01 14:04 ` Tony Lindgren 0 siblings, 0 replies; 11+ messages in thread From: Tony Lindgren @ 2008-04-01 14:04 UTC (permalink / raw) To: Peter 'p2' De Schrijver; +Cc: linux-omap [-- Attachment #1: Type: text/plain, Size: 1843 bytes --] * Tony Lindgren <tony@atomide.com> [080401 16:39]: > * Peter 'p2' De Schrijver <peter.de-schrijver@nokia.com> [080401 16:01]: > > On Tue, Apr 01, 2008 at 03:43:56PM +0300, ext Tony Lindgren wrote: > > > * Tony Lindgren <tony@atomide.com> [080331 17:30]: > > > > * Tony Lindgren <tony@atomide.com> [080331 13:43]: > > > > > * Tony Lindgren <tony@atomide.com> [080328 10:41]: > > > > > > Hi all, > > > > > > > > > > > > This helps with the annoying I2C timeouts. Does anybody have an idea > > > > > > why the twl4030 chip does not like doing multiple transfers in a row? > > > > > > > > > > > > To me the only difference seems to be that clocks are idled between > > > > > > writing the twl4030 register and reading the register value. > > > > > > > > > > I'll push this today with a REVISIT comment added. > > > > > > > > Looks like this kills twl4030 interrupts, so I've reverted it. > > > > > > After looking into this problem a bit more, looks like twl4030 reads > > > to anything in "POWER ID" (modules 0x10 and higher) will hang twl4030 > > > eventually and I2C controller gets stuck in mode where STP never clears. > > > > > > Repeated reads to "USB ID", "AUD ID" or "AUX ID" will not hang twl4030. > > > > > > > I remember seeing something similar when doing the powerbutton code. > > Klaus Pedersen found out that leaving CFG_BOOT to its reset value solved > > the problem. Unfortunately this breaks MADC and USB afaics, so it's not > > a real solution. CFG_BOOT is programmed in power_companion_init(). > > Great, this helped a lot! Looks like power_companion_init() tries to get > osc_ck without checking for clkg_get() return value, and osc_ck does not > exist in clock34xx.h. So R_CFG_BOOT gets set to default 26MHz value :) > > Will post a patch when available. Thanks again, here's a patch, I've pushed it also. Tony [-- Attachment #2: i2c-twl4030-clock.patch --] [-- Type: text/x-diff, Size: 1317 bytes --] From: Tony Lindgren <tony@atomide.com> Date: Tue, 1 Apr 2008 16:58:02 +0300 Subject: [PATCH] I2C: Fix twl4030 clock init Without this patch twl4030 clock can get programmed to incorrect rate which can eventually hang twl4030 reads. Also minor formatting fixes. Signed-off-by: Tony Lindgren <tony@atomide.com> --- a/drivers/i2c/chips/twl4030-core.c +++ b/drivers/i2c/chips/twl4030-core.c @@ -672,11 +672,20 @@ static int power_companion_init(void) u32 rate, ctrl = HFCLK_FREQ_26_MHZ; int e = 0; - osc = clk_get(NULL,"osc_ck"); + if (cpu_is_omap2430()) + osc = clk_get(NULL, "osc_ck"); + else + osc = clk_get(NULL, "osc_sys_ck"); + if (IS_ERR(osc)) { + printk(KERN_ERR "Skipping twl3040 internal clock init and " + "using bootloader value (unknown osc rate)\n"); + return 0; + } + rate = clk_get_rate(osc); clk_put(osc); - switch(rate) { + switch (rate) { case 19200000 : ctrl = HFCLK_FREQ_19p2_MHZ; break; case 26000000 : ctrl = HFCLK_FREQ_26_MHZ; break; case 38400000 : ctrl = HFCLK_FREQ_38p4_MHZ; break; @@ -684,7 +693,7 @@ static int power_companion_init(void) ctrl |= HIGH_PERF_SQ; e |= unprotect_pm_master(); - /* effect->MADC+USB ck en */ + /* effect->MADC+USB ck en */ e |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, ctrl, R_CFG_BOOT); e |= protect_pm_master(); ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 0/2] Add sram34xx.S @ 2008-03-28 11:46 Tony Lindgren 2008-03-28 11:46 ` [PATCH 1/2] ARM: OMAP3: Add 34xx SRAM functions Tony Lindgren 0 siblings, 1 reply; 11+ messages in thread From: Tony Lindgren @ 2008-03-28 11:46 UTC (permalink / raw) To: linux-omap; +Cc: Dasu, Karthik P, Tony Lindgren Hi all, Following two patches add sram34xx.S based on Karthik's patch and what's at [1]. Looks like the sram code in [1] is newer so I've used that. Let me know if that's not the case. Karthik, can you please check and ack? I've only compile tested them. Regards, Tony [1] http://linux.omap.com/pub/kernel/3430zoom/linux-ldp-v1.0b.tar.gz ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 1/2] ARM: OMAP3: Add 34xx SRAM functions 2008-03-28 11:46 [PATCH 0/2] Add sram34xx.S Tony Lindgren @ 2008-03-28 11:46 ` Tony Lindgren 2008-03-28 11:46 ` [PATCH 2/2] ARCH: OMAP3: Make SRAM code from TI CDP compile and work Tony Lindgren 0 siblings, 1 reply; 11+ messages in thread From: Tony Lindgren @ 2008-03-28 11:46 UTC (permalink / raw) To: linux-omap; +Cc: Tony Lindgren This adds sram34xx.S From TI CDP. NOTE: This patch breaks compile for 34xx, the compile will be fixed in the next patch. This and next patch will eventually get merged into a single patch for linux-omap to keep git-bisect working. --- arch/arm/mach-omap2/Makefile | 1 + arch/arm/mach-omap2/sram34xx.S | 217 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 218 insertions(+), 0 deletions(-) create mode 100644 arch/arm/mach-omap2/sram34xx.S diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 45f4b4e..0a6df8e 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -8,6 +8,7 @@ obj-y := irq.o id.o io.o memory.o control.o prcm.o clock.o mux.o \ # Functions loaded to SRAM obj-$(CONFIG_ARCH_OMAP2) += sram24xx.o +obj-$(CONFIG_ARCH_OMAP3) += sram34xx.o # Power Management obj-$(CONFIG_PM) += pm.o sleep.o diff --git a/arch/arm/mach-omap2/sram34xx.S b/arch/arm/mach-omap2/sram34xx.S new file mode 100644 index 0000000..803f60d --- /dev/null +++ b/arch/arm/mach-omap2/sram34xx.S @@ -0,0 +1,217 @@ +/* + * linux/arch/arm/mach-omap3/sram.S + * + * Omap3 specific functions that need to be run in internal SRAM + * + * (C) Copyright 2007 + * Texas Instruments Inc. + * Rajendra Nayak <rnayak@ti.com> + * + * (C) Copyright 2004 + * Texas Instruments, <www.ti.com> + * Richard Woodruff <r-woodruff2@ti.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#include <linux/linkage.h> +#include <asm/assembler.h> +#include <asm/arch/io.h> +#include <asm/hardware.h> + +#include "prcm-regs.h" + +#define CM_CLKSEL1_PLL_V IO_ADDRESS(CM_BASE + 0xD40) +#define CM_ICLKEN1_CORE_V IO_ADDRESS(CM_BASE + 0xA10) +#define CM_IDLEST1_CORE_V IO_ADDRESS(CM_BASE + 0xA20) + +#define SDRC_POWER_V IO_ADDRESS(SDRC_BASE + 0x070) +#define SDRC_RFR_CTRL IO_ADDRESS(SDRC_BASE + 0x0A4) +#define SDRC_ACTIM_CTRL_A IO_ADDRESS(SDRC_BASE + 0x09C) +#define SDRC_ACTIM_CTRL_B IO_ADDRESS(SDRC_BASE + 0x0A0) +#define SDRC_DLLA_STATUS IO_ADDRESS(SDRC_BASE + 0x064) +#define SDRC_DLLA_CTRL IO_ADDRESS(SDRC_BASE + 0x060) + + .text + +ENTRY(omap34xx_sram_ddr_init) + stmfd sp!, {r0 - r12, lr} @ save registers on stack + ldmfd sp!, {r0 - r12, pc} @ restore regs and return +ENTRY(omap34xx_sram_ddr_init_sz) + .word . - omap34xx_sram_ddr_init + +ENTRY(omap34xx_sram_reprogram_sdrc) + stmfd sp!, {r0 - r10, lr} @ save registers on stack + ldmfd sp!, {r0 - r10, pc} @ restore regs and return +ENTRY(omap34xx_sram_reprogram_sdrc_sz) + .word . - omap34xx_sram_reprogram_sdrc + +/* + * Set dividers and pll. Also recalculate DLL value for DDR and unlock mode. + */ +ENTRY(omap34xx_sram_set_prcm) + stmfd sp!, {r0-r12, lr} @ regs to stack +ENTRY(omap34xx_sram_set_prcm_sz) + .word . - omap34xx_sram_set_prcm + +/* + * Change frequency of core dpll + * r0 = sdrc_rfr_ctrl r1 = sdrc_actim_ctrla r2 = sdrc_actim_ctrlb r3 = M2 + */ +ENTRY(omap34xx_sram_configure_core_dpll) + stmfd sp!, {r1-r12, lr} @ store regs to stack + cmp r3, #0x2 + blne configure_sdrc + cmp r3, #0x2 + blne lock_dll + cmp r3, #0x1 + blne unlock_dll + bl sdram_in_selfrefresh @ put the SDRAM in self refresh + bl configure_core_dpll + bl enable_sdrc + cmp r3, #0x1 + blne wait_dll_unlock + cmp r3, #0x2 + blne wait_dll_lock + cmp r3, #0x1 + blne configure_sdrc + mov r0, #0 @ return value + ldmfd sp!, {r1-r12, pc} @ restore regs and return +unlock_dll: + ldr r4, sdrc_dlla_ctrl + ldr r5, [r4] + orr r5, r5, #0x4 + str r5, [r4] + bx lr +lock_dll: + ldr r4, sdrc_dlla_ctrl + ldr r5, [r4] + bic r5, r5, #0x4 + str r5, [r4] + bx lr +sdram_in_selfrefresh: + mov r5, #0x0 @ Move 0 to R5 + mcr p15, 0, r5, c7, c10, 5 @ memory barrier + ldr r4, sdrc_power @ read the SDRC_POWER register + ldr r5, [r4] @ read the contents of SDRC_POWER + orr r5, r5, #0x40 @ enable self refresh on idle req + str r5, [r4] @ write back to SDRC_POWER register + ldr r4, cm_iclken1_core @ read the CM_ICLKEN1_CORE reg + ldr r5, [r4] + bic r5, r5, #0x2 @ disable iclk bit for SRDC + str r5, [r4] +wait_sdrc_idle: + ldr r4, cm_idlest1_core + ldr r5, [r4] + and r5, r5, #0x2 @ check for SDRC idle + cmp r5, #2 + bne wait_sdrc_idle + bx lr +configure_core_dpll: + ldr r4, cm_clksel1_pll + ldr r5, [r4] + ldr r6, core_m2_mask_val @ modify m2 for core dpll + and r5, r5, r6 + orr r5, r5, r3, lsl #0x1B @ r3 contains the M2 val + str r5, [r4] + mov r5, #0x800 @ wait for the clock to stabilise + cmp r3, #2 + bne wait_clk_stable + bx lr +wait_clk_stable: + subs r5, r5, #1 + bne wait_clk_stable + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + bx lr +enable_sdrc: + ldr r4, cm_iclken1_core + ldr r5, [r4] + orr r5, r5, #0x2 @ enable iclk bit for SDRC + str r5, [r4] +wait_sdrc_idle1: + ldr r4, cm_idlest1_core + ldr r5, [r4] + and r5, r5, #0x2 + cmp r5, #0 + bne wait_sdrc_idle1 + ldr r4, sdrc_power + ldr r5, [r4] + bic r5, r5, #0x40 + str r5, [r4] + bx lr +wait_dll_lock: + ldr r4, sdrc_dlla_status + ldr r5, [r4] + and r5, r5, #0x4 + cmp r5, #0x4 + bne wait_dll_lock + bx lr +wait_dll_unlock: + ldr r4, sdrc_dlla_status + ldr r5, [r4] + and r5, r5, #0x4 + cmp r5, #0x0 + bne wait_dll_unlock + bx lr +configure_sdrc: + ldr r4, sdrc_rfr_ctrl + str r0, [r4] + ldr r4, sdrc_actim_ctrla + str r1, [r4] + ldr r4, sdrc_actim_ctrlb + str r2, [r4] + bx lr +sdrc_power: + .word SDRC_POWER_V +cm_clksel1_pll: + .word CM_CLKSEL1_PLL_V +cm_idlest1_core: + .word CM_IDLEST1_CORE_V +cm_iclken1_core: + .word CM_ICLKEN1_CORE_V +sdrc_rfr_ctrl: + .word SDRC_RFR_CTRL +sdrc_actim_ctrla: + .word SDRC_ACTIM_CTRL_A +sdrc_actim_ctrlb: + .word SDRC_ACTIM_CTRL_B +sdrc_dlla_status: + .word SDRC_DLLA_STATUS +sdrc_dlla_ctrl: + .word SDRC_DLLA_CTRL +core_m2_mask_val: + .word 0xE7FFFFFF + +ENTRY(omap34xx_sram_configure_core_dpll_sz) + .word . - omap34xx_sram_configure_core_dpll + +/* + * Reprogram GPMC + */ +ENTRY(omap34xx_sram_reprogram_gpmc) + stmfd sp!, {r0-r12, lr} @ regs to stack + ldmfd sp!, {r0-r12, pc} @ restore regs and return + +ENTRY(omap34xx_sram_reprogram_gpmc_sz) + .word . - omap34xx_sram_reprogram_gpmc -- 1.5.3.6 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 2/2] ARCH: OMAP3: Make SRAM code from TI CDP compile and work 2008-03-28 11:46 ` [PATCH 1/2] ARM: OMAP3: Add 34xx SRAM functions Tony Lindgren @ 2008-03-28 11:46 ` Tony Lindgren [not found] ` <1206704800-6768-4-git-send-email-tony@atomide.com> 0 siblings, 1 reply; 11+ messages in thread From: Tony Lindgren @ 2008-03-28 11:46 UTC (permalink / raw) To: linux-omap; +Cc: Tony Lindgren Make SRAM code from TI CDP compile and work. Signed-off-by: Tony Lindgren <tony@atomide.com> --- arch/arm/mach-omap2/sram34xx.S | 112 ++++++++++++++++++-------------------- arch/arm/plat-omap/sram.c | 63 +++++++++++++++++++++ include/asm-arm/arch-omap/sdrc.h | 2 + include/asm-arm/arch-omap/sram.h | 19 +++++++ 4 files changed, 136 insertions(+), 60 deletions(-) diff --git a/arch/arm/mach-omap2/sram34xx.S b/arch/arm/mach-omap2/sram34xx.S index 803f60d..74873df 100644 --- a/arch/arm/mach-omap2/sram34xx.S +++ b/arch/arm/mach-omap2/sram34xx.S @@ -28,21 +28,12 @@ */ #include <linux/linkage.h> #include <asm/assembler.h> -#include <asm/arch/io.h> #include <asm/hardware.h> -#include "prcm-regs.h" - -#define CM_CLKSEL1_PLL_V IO_ADDRESS(CM_BASE + 0xD40) -#define CM_ICLKEN1_CORE_V IO_ADDRESS(CM_BASE + 0xA10) -#define CM_IDLEST1_CORE_V IO_ADDRESS(CM_BASE + 0xA20) +#include <asm/arch/io.h> -#define SDRC_POWER_V IO_ADDRESS(SDRC_BASE + 0x070) -#define SDRC_RFR_CTRL IO_ADDRESS(SDRC_BASE + 0x0A4) -#define SDRC_ACTIM_CTRL_A IO_ADDRESS(SDRC_BASE + 0x09C) -#define SDRC_ACTIM_CTRL_B IO_ADDRESS(SDRC_BASE + 0x0A0) -#define SDRC_DLLA_STATUS IO_ADDRESS(SDRC_BASE + 0x064) -#define SDRC_DLLA_CTRL IO_ADDRESS(SDRC_BASE + 0x060) +#include "sdrc.h" +#include "cm.h" .text @@ -68,7 +59,7 @@ ENTRY(omap34xx_sram_set_prcm_sz) /* * Change frequency of core dpll - * r0 = sdrc_rfr_ctrl r1 = sdrc_actim_ctrla r2 = sdrc_actim_ctrlb r3 = M2 + * r0 = sdrc_rfr_ctrl r1 = sdrc_actim_ctrla r2 = sdrc_actim_ctrlb r3 = M2 */ ENTRY(omap34xx_sram_configure_core_dpll) stmfd sp!, {r1-r12, lr} @ store regs to stack @@ -90,37 +81,37 @@ ENTRY(omap34xx_sram_configure_core_dpll) mov r0, #0 @ return value ldmfd sp!, {r1-r12, pc} @ restore regs and return unlock_dll: - ldr r4, sdrc_dlla_ctrl - ldr r5, [r4] + ldr r4, omap34xx_sdrc_dlla_ctrl + ldr r5, [r4] orr r5, r5, #0x4 str r5, [r4] bx lr lock_dll: - ldr r4, sdrc_dlla_ctrl - ldr r5, [r4] + ldr r4, omap34xx_sdrc_dlla_ctrl + ldr r5, [r4] bic r5, r5, #0x4 - str r5, [r4] - bx lr + str r5, [r4] + bx lr sdram_in_selfrefresh: mov r5, #0x0 @ Move 0 to R5 - mcr p15, 0, r5, c7, c10, 5 @ memory barrier - ldr r4, sdrc_power @ read the SDRC_POWER register - ldr r5, [r4] @ read the contents of SDRC_POWER + mcr p15, 0, r5, c7, c10, 5 @ memory barrier + ldr r4, omap34xx_sdrc_power @ read the SDRC_POWER register + ldr r5, [r4] @ read the contents of SDRC_POWER orr r5, r5, #0x40 @ enable self refresh on idle req str r5, [r4] @ write back to SDRC_POWER register - ldr r4, cm_iclken1_core @ read the CM_ICLKEN1_CORE reg + ldr r4, omap34xx_cm_iclken1_core @ read the CM_ICLKEN1_CORE reg ldr r5, [r4] bic r5, r5, #0x2 @ disable iclk bit for SRDC str r5, [r4] wait_sdrc_idle: - ldr r4, cm_idlest1_core + ldr r4, omap34xx_cm_idlest1_core ldr r5, [r4] and r5, r5, #0x2 @ check for SDRC idle cmp r5, #2 bne wait_sdrc_idle bx lr configure_core_dpll: - ldr r4, cm_clksel1_pll + ldr r4, omap34xx_cm_clksel1_pll ldr r5, [r4] ldr r6, core_m2_mask_val @ modify m2 for core dpll and r5, r5, r6 @@ -145,61 +136,62 @@ wait_clk_stable: nop bx lr enable_sdrc: - ldr r4, cm_iclken1_core + ldr r4, omap34xx_cm_iclken1_core ldr r5, [r4] orr r5, r5, #0x2 @ enable iclk bit for SDRC str r5, [r4] wait_sdrc_idle1: - ldr r4, cm_idlest1_core + ldr r4, omap34xx_cm_idlest1_core ldr r5, [r4] and r5, r5, #0x2 cmp r5, #0 bne wait_sdrc_idle1 - ldr r4, sdrc_power + ldr r4, omap34xx_sdrc_power ldr r5, [r4] bic r5, r5, #0x40 str r5, [r4] bx lr wait_dll_lock: - ldr r4, sdrc_dlla_status + ldr r4, omap34xx_sdrc_dlla_status ldr r5, [r4] and r5, r5, #0x4 cmp r5, #0x4 bne wait_dll_lock bx lr wait_dll_unlock: - ldr r4, sdrc_dlla_status - ldr r5, [r4] - and r5, r5, #0x4 - cmp r5, #0x0 - bne wait_dll_unlock - bx lr + ldr r4, omap34xx_sdrc_dlla_status + ldr r5, [r4] + and r5, r5, #0x4 + cmp r5, #0x0 + bne wait_dll_unlock + bx lr configure_sdrc: - ldr r4, sdrc_rfr_ctrl - str r0, [r4] - ldr r4, sdrc_actim_ctrla - str r1, [r4] - ldr r4, sdrc_actim_ctrlb - str r2, [r4] - bx lr -sdrc_power: - .word SDRC_POWER_V -cm_clksel1_pll: - .word CM_CLKSEL1_PLL_V -cm_idlest1_core: - .word CM_IDLEST1_CORE_V -cm_iclken1_core: - .word CM_ICLKEN1_CORE_V -sdrc_rfr_ctrl: - .word SDRC_RFR_CTRL -sdrc_actim_ctrla: - .word SDRC_ACTIM_CTRL_A -sdrc_actim_ctrlb: - .word SDRC_ACTIM_CTRL_B -sdrc_dlla_status: - .word SDRC_DLLA_STATUS -sdrc_dlla_ctrl: - .word SDRC_DLLA_CTRL + ldr r4, omap34xx_sdrc_rfr_ctrl + str r0, [r4] + ldr r4, omap34xx_sdrc_actim_ctrla + str r1, [r4] + ldr r4, omap34xx_sdrc_actim_ctrlb + str r2, [r4] + bx lr + +omap34xx_sdrc_power: + .word OMAP34XX_SDRC_REGADDR(SDRC_POWER) +omap34xx_cm_clksel1_pll: + .word OMAP34XX_CM_REGADDR(PLL_MOD, CM_CLKSEL1) +omap34xx_cm_idlest1_core: + .word OMAP34XX_CM_REGADDR(CORE_MOD, CM_IDLEST) +omap34xx_cm_iclken1_core: + .word OMAP34XX_CM_REGADDR(CORE_MOD, CM_ICLKEN1) +omap34xx_sdrc_rfr_ctrl: + .word OMAP34XX_SDRC_REGADDR(SDRC_RFR_CTRL_0) +omap34xx_sdrc_actim_ctrla: + .word OMAP34XX_SDRC_REGADDR(SDRC_ACTIM_CTRL_A) +omap34xx_sdrc_actim_ctrlb: + .word OMAP34XX_SDRC_REGADDR(SDRC_ACTIM_CTRL_B) +omap34xx_sdrc_dlla_status: + .word OMAP34XX_SDRC_REGADDR(SDRC_DLLA_STATUS) +omap34xx_sdrc_dlla_ctrl: + .word OMAP34XX_SDRC_REGADDR(SDRC_DLLA_CTRL) core_m2_mask_val: .word 0xE7FFFFFF diff --git a/arch/arm/plat-omap/sram.c b/arch/arm/plat-omap/sram.c index 2fc8f61..fb3f0d1 100644 --- a/arch/arm/plat-omap/sram.c +++ b/arch/arm/plat-omap/sram.c @@ -461,6 +461,67 @@ static inline int omap24xx_sram_init(void) } #endif +#ifdef CONFIG_ARCH_OMAP3 + +static u32 (*_omap2_sram_reprogram_gpmc)(u32 perf_level); +u32 omap2_sram_reprogram_gpmc(u32 perf_level) +{ + if (!_omap2_sram_reprogram_gpmc) + omap_sram_error(); + + return _omap2_sram_reprogram_gpmc(perf_level); +} + +static u32 (*_omap2_sram_configure_core_dpll)(u32 m, u32 n, + u32 freqsel, u32 m2); +u32 omap2_sram_configure_core_dpll(u32 m, u32 n, u32 freqsel, u32 m2) +{ + if (!_omap2_sram_configure_core_dpll) + omap_sram_error(); + + return _omap2_sram_configure_core_dpll(m, n, freqsel, m2); +} + +/* REVISIT: Should this be same as omap34xx_sram_init() after off-idle? */ +void restore_sram_functions(void) +{ + omap_sram_ceil = omap_sram_base + omap_sram_size; + + _omap2_sram_reprogram_gpmc = omap_sram_push(omap34xx_sram_reprogram_gpmc, + omap34xx_sram_reprogram_gpmc_sz); + + _omap2_sram_configure_core_dpll = + omap_sram_push(omap34xx_sram_configure_core_dpll, + omap34xx_sram_configure_core_dpll_sz); +} + +int __init omap34xx_sram_init(void) +{ + _omap2_sram_ddr_init = omap_sram_push(omap34xx_sram_ddr_init, + omap34xx_sram_ddr_init_sz); + + _omap2_sram_reprogram_sdrc = omap_sram_push(omap34xx_sram_reprogram_sdrc, + omap34xx_sram_reprogram_sdrc_sz); + + _omap2_set_prcm = omap_sram_push(omap34xx_sram_set_prcm, + omap34xx_sram_set_prcm_sz); + + _omap2_sram_reprogram_gpmc = omap_sram_push(omap34xx_sram_reprogram_gpmc, + omap34xx_sram_reprogram_gpmc_sz); + + _omap2_sram_configure_core_dpll = + omap_sram_push(omap34xx_sram_configure_core_dpll, + omap34xx_sram_configure_core_dpll_sz); + + return 0; +} +#else +static inline int omap34xx_sram_init(void) +{ + return 0; +} +#endif + int __init omap_sram_init(void) { omap_detect_sram(); @@ -470,6 +531,8 @@ int __init omap_sram_init(void) omap1_sram_init(); else if (cpu_is_omap24xx()) omap24xx_sram_init(); + else if (cpu_is_omap34xx()) + omap34xx_sram_init(); return 0; } diff --git a/include/asm-arm/arch-omap/sdrc.h b/include/asm-arm/arch-omap/sdrc.h index 673b396..660da4d 100644 --- a/include/asm-arm/arch-omap/sdrc.h +++ b/include/asm-arm/arch-omap/sdrc.h @@ -25,6 +25,8 @@ #define SDRC_DLLB_STATUS 0x06C #define SDRC_POWER 0x070 #define SDRC_MR_0 0x084 +#define SDRC_ACTIM_CTRL_A 0x09c +#define SDRC_ACTIM_CTRL_B 0x0a0 #define SDRC_RFR_CTRL_0 0x0a4 /* diff --git a/include/asm-arm/arch-omap/sram.h b/include/asm-arm/arch-omap/sram.h index c55df46..9c2863b 100644 --- a/include/asm-arm/arch-omap/sram.h +++ b/include/asm-arm/arch-omap/sram.h @@ -42,4 +42,23 @@ extern void omap24xx_sram_reprogram_sdrc(u32 perf_level, u32 dll_val, u32 mem_type); extern unsigned long omap24xx_sram_reprogram_sdrc_sz; + +extern void omap34xx_sram_ddr_init(u32 *slow_dll_ctrl, u32 fast_dll_ctrl, + u32 base_cs, u32 force_unlock); +extern unsigned long omap34xx_sram_ddr_init_sz; + +extern void omap34xx_sram_reprogram_sdrc(u32 perf_level, u32 dll_val, + u32 mem_type); +extern unsigned long omap34xx_sram_reprogram_sdrc_sz; + +extern u32 omap34xx_sram_set_prcm(u32 dpll_ctrl_val, u32 sdrc_rfr_val, + int bypass); +extern unsigned long omap34xx_sram_set_prcm_sz; + +extern u32 omap34xx_sram_reprogram_gpmc(u32 perf_level); +extern unsigned long omap34xx_sram_reprogram_gpmc_sz; + +extern u32 omap34xx_sram_configure_core_dpll(u32 m, u32 n, u32 freqsel, u32 m2); +extern unsigned long omap34xx_sram_configure_core_dpll_sz; + #endif -- 1.5.3.6 ^ permalink raw reply related [flat|nested] 11+ messages in thread
[parent not found: <1206704800-6768-4-git-send-email-tony@atomide.com>]
* [PATCH] I2C: Fix twl4030 timeouts on omap3430 [not found] ` <1206704800-6768-4-git-send-email-tony@atomide.com> @ 2008-03-28 11:46 ` Tony Lindgren 2008-03-28 11:46 ` Tony Lindgren 2008-03-28 11:48 ` Tony Lindgren 0 siblings, 2 replies; 11+ messages in thread From: Tony Lindgren @ 2008-03-28 11:46 UTC (permalink / raw) To: linux-omap; +Cc: Tony Lindgren For some reason doing a twl4030 write-read cycle can hang the I2C bus on omap3430. And doing the write and read separately in twl4030_i2c_read() seems to fix the problem... Not intended for applying, just a temporary workaround. diff --git a/drivers/i2c/chips/twl4030-core.c b/drivers/i2c/chips/twl4030-core.c index ded86e7..62868b0 100644 --- a/drivers/i2c/chips/twl4030-core.c +++ b/drivers/i2c/chips/twl4030-core.c @@ -327,6 +327,7 @@ int twl4030_i2c_read(u8 mod_no, u8 * value, u8 reg, u8 num_bytes) return -EPERM; } mutex_lock(&twl->xfer_lock); + /* [MSG1] fill the register address data */ msg = &twl->xfer_msg[0]; msg->addr = twl->address; @@ -334,18 +335,25 @@ int twl4030_i2c_read(u8 mod_no, u8 * value, u8 reg, u8 num_bytes) msg->flags = 0; /* Read the register value */ val = twl4030_map[mod_no].base + reg; msg->buf = &val; + ret = i2c_transfer(twl->client.adapter, twl->xfer_msg, 1); + if (ret < 0) + goto out; + /* [MSG2] fill the data rx buffer */ msg = &twl->xfer_msg[1]; msg->addr = twl->address; msg->flags = I2C_M_RD; /* Read the register value */ msg->len = num_bytes; /* only n bytes */ msg->buf = value; - ret = i2c_transfer(twl->client.adapter, twl->xfer_msg, 2); + ret = i2c_transfer(twl->client.adapter, twl->xfer_msg, 1); + +out: mutex_unlock(&twl->xfer_lock); /* i2cTransfer returns num messages.translate it pls.. */ if (ret >= 0) ret = 0; + return ret; } ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH] I2C: Fix twl4030 timeouts on omap3430 2008-03-28 11:46 ` [PATCH] I2C: Fix twl4030 timeouts on omap3430 Tony Lindgren @ 2008-03-28 11:46 ` Tony Lindgren 2008-03-28 11:49 ` Tony Lindgren 2008-03-28 11:48 ` Tony Lindgren 1 sibling, 1 reply; 11+ messages in thread From: Tony Lindgren @ 2008-03-28 11:46 UTC (permalink / raw) To: linux-omap; +Cc: Richard Woodruff, Tony Lindgren ARM: OMAP: Use posted mode for dmtimer This patch adds the use of write posting for the timer. Previously, every write could lock the requestor for almost 3x32KHz cycles. This patch only synchronizes before writes and reads instead of after them and it does it on per register basis. Doing it this way there is some chance to hide some of the sync latency. It also removes some needless reads when non-posted mode is there. With out this fix the read/writes take almost 2% CPU load @500MHz just waiting on tick timer registers. Also define new 34xx only registers. Signed-off-by: Richard Woodruff <r-woodruff2@ti.com> Signed-off-by: Tony Lindgren <tony@atomide.com> --- a/arch/arm/plat-omap/dmtimer.c +++ b/arch/arm/plat-omap/dmtimer.c @@ -38,34 +38,113 @@ #include <asm/arch/irqs.h> /* register offsets */ -#define OMAP_TIMER_ID_REG 0x00 -#define OMAP_TIMER_OCP_CFG_REG 0x10 -#define OMAP_TIMER_SYS_STAT_REG 0x14 -#define OMAP_TIMER_STAT_REG 0x18 -#define OMAP_TIMER_INT_EN_REG 0x1c -#define OMAP_TIMER_WAKEUP_EN_REG 0x20 -#define OMAP_TIMER_CTRL_REG 0x24 -#define OMAP_TIMER_COUNTER_REG 0x28 -#define OMAP_TIMER_LOAD_REG 0x2c -#define OMAP_TIMER_TRIGGER_REG 0x30 -#define OMAP_TIMER_WRITE_PEND_REG 0x34 -#define OMAP_TIMER_MATCH_REG 0x38 -#define OMAP_TIMER_CAPTURE_REG 0x3c -#define OMAP_TIMER_IF_CTRL_REG 0x40 - -/* timer control reg bits */ -#define OMAP_TIMER_CTRL_GPOCFG (1 << 14) -#define OMAP_TIMER_CTRL_CAPTMODE (1 << 13) -#define OMAP_TIMER_CTRL_PT (1 << 12) -#define OMAP_TIMER_CTRL_TCM_LOWTOHIGH (0x1 << 8) -#define OMAP_TIMER_CTRL_TCM_HIGHTOLOW (0x2 << 8) -#define OMAP_TIMER_CTRL_TCM_BOTHEDGES (0x3 << 8) -#define OMAP_TIMER_CTRL_SCPWM (1 << 7) -#define OMAP_TIMER_CTRL_CE (1 << 6) /* compare enable */ -#define OMAP_TIMER_CTRL_PRE (1 << 5) /* prescaler enable */ -#define OMAP_TIMER_CTRL_PTV_SHIFT 2 /* how much to shift the prescaler value */ -#define OMAP_TIMER_CTRL_AR (1 << 1) /* auto-reload enable */ -#define OMAP_TIMER_CTRL_ST (1 << 0) /* start timer */ +#define _OMAP_TIMER_ID_OFFSET 0x00 +#define _OMAP_TIMER_OCP_CFG_OFFSET 0x10 +#define _OMAP_TIMER_SYS_STAT_OFFSET 0x14 +#define _OMAP_TIMER_STAT_OFFSET 0x18 +#define _OMAP_TIMER_INT_EN_OFFSET 0x1c +#define _OMAP_TIMER_WAKEUP_EN_OFFSET 0x20 +#define _OMAP_TIMER_CTRL_OFFSET 0x24 +#define OMAP_TIMER_CTRL_GPOCFG (1 << 14) +#define OMAP_TIMER_CTRL_CAPTMODE (1 << 13) +#define OMAP_TIMER_CTRL_PT (1 << 12) +#define OMAP_TIMER_CTRL_TCM_LOWTOHIGH (0x1 << 8) +#define OMAP_TIMER_CTRL_TCM_HIGHTOLOW (0x2 << 8) +#define OMAP_TIMER_CTRL_TCM_BOTHEDGES (0x3 << 8) +#define OMAP_TIMER_CTRL_SCPWM (1 << 7) +#define OMAP_TIMER_CTRL_CE (1 << 6) /* compare enable */ +#define OMAP_TIMER_CTRL_PRE (1 << 5) /* prescaler enable */ +#define OMAP_TIMER_CTRL_PTV_SHIFT 2 /* prescaler value shift */ +#define OMAP_TIMER_CTRL_POSTED (1 << 2) +#define OMAP_TIMER_CTRL_AR (1 << 1) /* auto-reload enable */ +#define OMAP_TIMER_CTRL_ST (1 << 0) /* start timer */ +#define _OMAP_TIMER_COUNTER_OFFSET 0x28 +#define _OMAP_TIMER_LOAD_OFFSET 0x2c +#define _OMAP_TIMER_TRIGGER_OFFSET 0x30 +#define _OMAP_TIMER_WRITE_PEND_OFFSET 0x34 +#define WP_NONE 0 /* no write pending bit */ +#define WP_TCLR (1 << 0) +#define WP_TCRR (1 << 1) +#define WP_TLDR (1 << 2) +#define WP_TTGR (1 << 3) +#define WP_TMAR (1 << 4) +#define WP_TPIR (1 << 5) +#define WP_TNIR (1 << 6) +#define WP_TCVR (1 << 7) +#define WP_TOCR (1 << 8) +#define WP_TOWR (1 << 9) +#define _OMAP_TIMER_MATCH_OFFSET 0x38 +#define _OMAP_TIMER_CAPTURE_OFFSET 0x3c +#define _OMAP_TIMER_IF_CTRL_OFFSET 0x40 +#define _OMAP_TIMER_CAPTURE2_OFFSET 0x44 /* TCAR2, 34xx only */ +#define _OMAP_TIMER_TICK_POS_OFFSET 0x48 /* TPIR, 34xx only */ +#define _OMAP_TIMER_TICK_NEG_OFFSET 0x4c /* TNIR, 34xx only */ +#define _OMAP_TIMER_TICK_COUNT_OFFSET 0x50 /* TCVR, 34xx only */ +#define _OMAP_TIMER_TICK_INT_MASK_SET_OFFSET 0x54 /* TOCR, 34xx only */ +#define _OMAP_TIMER_TICK_INT_MASK_COUNT_OFFSET 0x58 /* TOWR, 34xx only */ + +/* register offsets with the write pending bit encoded */ +#define WPSHIFT 16 + +#define OMAP_TIMER_ID_REG (_OMAP_TIMER_ID_OFFSET \ + | (WP_NONE << WPSHIFT)) + +#define OMAP_TIMER_OCP_CFG_REG (_OMAP_TIMER_OCP_CFG_OFFSET \ + | (WP_NONE << WPSHIFT)) + +#define OMAP_TIMER_SYS_STAT_REG (_OMAP_TIMER_SYS_STAT_OFFSET \ + | (WP_NONE << WPSHIFT)) + +#define OMAP_TIMER_STAT_REG (_OMAP_TIMER_STAT_OFFSET \ + | (WP_NONE << WPSHIFT)) + +#define OMAP_TIMER_INT_EN_REG (_OMAP_TIMER_INT_EN_OFFSET \ + | (WP_NONE << WPSHIFT)) + +#define OMAP_TIMER_WAKEUP_EN_REG (_OMAP_TIMER_WAKEUP_EN_OFFSET \ + | (WP_NONE << WPSHIFT)) + +#define OMAP_TIMER_CTRL_REG (_OMAP_TIMER_CTRL_OFFSET \ + | (WP_TCLR << WPSHIFT)) + +#define OMAP_TIMER_COUNTER_REG (_OMAP_TIMER_COUNTER_OFFSET \ + | (WP_TCRR << WPSHIFT)) + +#define OMAP_TIMER_LOAD_REG (_OMAP_TIMER_LOAD_OFFSET \ + | (WP_TLDR << WPSHIFT)) + +#define OMAP_TIMER_TRIGGER_REG (_OMAP_TIMER_TRIGGER_OFFSET \ + | (WP_TTGR << WPSHIFT)) + +#define OMAP_TIMER_WRITE_PEND_REG (_OMAP_TIMER_WRITE_PEND_OFFSET \ + | (WP_NONE << WPSHIFT)) + +#define OMAP_TIMER_MATCH_REG (_OMAP_TIMER_MATCH_OFFSET \ + | (WP_TMAR << WPSHIFT)) + +#define OMAP_TIMER_CAPTURE_REG (_OMAP_TIMER_CAPTURE_OFFSET \ + | (WP_NONE << WPSHIFT)) + +#define OMAP_TIMER_IF_CTRL_REG (_OMAP_TIMER_IF_CTRL_OFFSET \ + | (WP_NONE << WPSHIFT)) + +#define OMAP_TIMER_CAPTURE2_REG (_OMAP_TIMER_CAPTURE2_OFFSET \ + | (WP_NONE << WPSHIFT)) + +#define OMAP_TIMER_TICK_POS_REG (_OMAP_TIMER_TICK_POS_OFFSET \ + | (WP_TPIR << WPSHIFT)) + +#define OMAP_TIMER_TICK_NEG_REG (_OMAP_TIMER_TICK_NEG_OFFSET \ + | (WP_TNIR << WPSHIFT)) + +#define OMAP_TIMER_TICK_COUNT_REG (_OMAP_TIMER_TICK_COUNT_OFFSET \ + | (WP_TCVR << WPSHIFT)) + +#define OMAP_TIMER_TICK_INT_MASK_SET_REG \ + (_OMAP_TIMER_TICK_INT_MASK_SET_OFFSET | (WP_TOCR << WPSHIFT)) + +#define OMAP_TIMER_TICK_INT_MASK_COUNT_REG \ + (_OMAP_TIMER_TICK_INT_MASK_COUNT_OFFSET | (WP_TOWR << WPSHIFT)) struct omap_dm_timer { unsigned long phys_base; @@ -76,6 +155,7 @@ struct omap_dm_timer { void __iomem *io_base; unsigned reserved:1; unsigned enabled:1; + unsigned posted:1; }; #ifdef CONFIG_ARCH_OMAP1 @@ -181,16 +261,34 @@ static struct clk **dm_source_clocks; static spinlock_t dm_timer_lock; -static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, int reg) +/* + * Reads timer registers in posted and non-posted mode. The posted mode bit + * is encoded in reg. Note that in posted mode write pending bit must be + * checked. Otherwise a read of a non completed write will produce an error. + */ +static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg) { - return readl(timer->io_base + reg); + if (timer->posted) + while (readl(timer->io_base + (OMAP_TIMER_WRITE_PEND_REG & 0xff)) + & (reg >> WPSHIFT)) + cpu_relax(); + return readl(timer->io_base + (reg & 0xff)); } -static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, int reg, u32 value) +/* + * Writes timer registers in posted and non-posted mode. The posted mode bit + * is encoded in reg. Note that in posted mode the write pending bit must be + * checked. Otherwise a write on a register which has a pending write will be + * lost. + */ +static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg, + u32 value) { - writel(value, timer->io_base + reg); - while (omap_dm_timer_read_reg(timer, OMAP_TIMER_WRITE_PEND_REG)) - ; + if (timer->posted) + while (readl(timer->io_base + (OMAP_TIMER_WRITE_PEND_REG & 0xff)) + & (reg >> WPSHIFT)) + cpu_relax(); + writel(value, timer->io_base + (reg & 0xff)); } static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer) @@ -217,17 +315,23 @@ static void omap_dm_timer_reset(struct omap_dm_timer *timer) } omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ); - /* Set to smart-idle mode */ l = omap_dm_timer_read_reg(timer, OMAP_TIMER_OCP_CFG_REG); - l |= 0x02 << 3; - - if (cpu_class_is_omap2() && timer == &dm_timers[0]) { - /* Enable wake-up only for GPT1 on OMAP2 CPUs*/ + l |= 0x02 << 3; /* Set to smart-idle mode */ + l |= 0x2 << 8; /* Set clock activity to perserve f-clock on idle */ + + /* + * Enable wake-up only for GPT1 on OMAP2 CPUs. + * FIXME: All timers should have wake-up enabled and clear + * PRCM status. + */ + if (cpu_class_is_omap2() && (timer == &dm_timers[0])) l |= 1 << 2; - /* Non-posted mode */ - omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0); - } omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_REG, l); + + /* Match hardware reset default of posted mode */ + omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, + OMAP_TIMER_CTRL_POSTED); + timer->posted = 1; } static void omap_dm_timer_prepare(struct omap_dm_timer *timer) @@ -434,6 +538,11 @@ void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload, l &= ~OMAP_TIMER_CTRL_AR; omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load); + + /* REVISIT: hw feature, ttgr overtaking tldr? */ + while (readl(timer->io_base + (OMAP_TIMER_WRITE_PEND_REG & 0xff))) + cpu_relax(); + omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0); } ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] I2C: Fix twl4030 timeouts on omap3430 2008-03-28 11:46 ` Tony Lindgren @ 2008-03-28 11:49 ` Tony Lindgren 0 siblings, 0 replies; 11+ messages in thread From: Tony Lindgren @ 2008-03-28 11:49 UTC (permalink / raw) To: linux-omap; +Cc: Richard Woodruff * Tony Lindgren <tony@atomide.com> [080328 13:47]: > ARM: OMAP: Use posted mode for dmtimer > > This patch adds the use of write posting for the timer. Previously, every > write could lock the requestor for almost 3x32KHz cycles. This patch only > synchronizes before writes and reads instead of after them and it does > it on per register basis. Doing it this way there is some chance to hide > some of the sync latency. It also removes some needless reads when > non-posted mode is there. With out this fix the read/writes take almost > 2% CPU load @500MHz just waiting on tick timer registers. > > Also define new 34xx only registers. Please ignore this patch too. Tony > > Signed-off-by: Richard Woodruff <r-woodruff2@ti.com> > Signed-off-by: Tony Lindgren <tony@atomide.com> > > --- a/arch/arm/plat-omap/dmtimer.c > +++ b/arch/arm/plat-omap/dmtimer.c > @@ -38,34 +38,113 @@ > #include <asm/arch/irqs.h> > > /* register offsets */ > -#define OMAP_TIMER_ID_REG 0x00 > -#define OMAP_TIMER_OCP_CFG_REG 0x10 > -#define OMAP_TIMER_SYS_STAT_REG 0x14 > -#define OMAP_TIMER_STAT_REG 0x18 > -#define OMAP_TIMER_INT_EN_REG 0x1c > -#define OMAP_TIMER_WAKEUP_EN_REG 0x20 > -#define OMAP_TIMER_CTRL_REG 0x24 > -#define OMAP_TIMER_COUNTER_REG 0x28 > -#define OMAP_TIMER_LOAD_REG 0x2c > -#define OMAP_TIMER_TRIGGER_REG 0x30 > -#define OMAP_TIMER_WRITE_PEND_REG 0x34 > -#define OMAP_TIMER_MATCH_REG 0x38 > -#define OMAP_TIMER_CAPTURE_REG 0x3c > -#define OMAP_TIMER_IF_CTRL_REG 0x40 > - > -/* timer control reg bits */ > -#define OMAP_TIMER_CTRL_GPOCFG (1 << 14) > -#define OMAP_TIMER_CTRL_CAPTMODE (1 << 13) > -#define OMAP_TIMER_CTRL_PT (1 << 12) > -#define OMAP_TIMER_CTRL_TCM_LOWTOHIGH (0x1 << 8) > -#define OMAP_TIMER_CTRL_TCM_HIGHTOLOW (0x2 << 8) > -#define OMAP_TIMER_CTRL_TCM_BOTHEDGES (0x3 << 8) > -#define OMAP_TIMER_CTRL_SCPWM (1 << 7) > -#define OMAP_TIMER_CTRL_CE (1 << 6) /* compare enable */ > -#define OMAP_TIMER_CTRL_PRE (1 << 5) /* prescaler enable */ > -#define OMAP_TIMER_CTRL_PTV_SHIFT 2 /* how much to shift the prescaler value */ > -#define OMAP_TIMER_CTRL_AR (1 << 1) /* auto-reload enable */ > -#define OMAP_TIMER_CTRL_ST (1 << 0) /* start timer */ > +#define _OMAP_TIMER_ID_OFFSET 0x00 > +#define _OMAP_TIMER_OCP_CFG_OFFSET 0x10 > +#define _OMAP_TIMER_SYS_STAT_OFFSET 0x14 > +#define _OMAP_TIMER_STAT_OFFSET 0x18 > +#define _OMAP_TIMER_INT_EN_OFFSET 0x1c > +#define _OMAP_TIMER_WAKEUP_EN_OFFSET 0x20 > +#define _OMAP_TIMER_CTRL_OFFSET 0x24 > +#define OMAP_TIMER_CTRL_GPOCFG (1 << 14) > +#define OMAP_TIMER_CTRL_CAPTMODE (1 << 13) > +#define OMAP_TIMER_CTRL_PT (1 << 12) > +#define OMAP_TIMER_CTRL_TCM_LOWTOHIGH (0x1 << 8) > +#define OMAP_TIMER_CTRL_TCM_HIGHTOLOW (0x2 << 8) > +#define OMAP_TIMER_CTRL_TCM_BOTHEDGES (0x3 << 8) > +#define OMAP_TIMER_CTRL_SCPWM (1 << 7) > +#define OMAP_TIMER_CTRL_CE (1 << 6) /* compare enable */ > +#define OMAP_TIMER_CTRL_PRE (1 << 5) /* prescaler enable */ > +#define OMAP_TIMER_CTRL_PTV_SHIFT 2 /* prescaler value shift */ > +#define OMAP_TIMER_CTRL_POSTED (1 << 2) > +#define OMAP_TIMER_CTRL_AR (1 << 1) /* auto-reload enable */ > +#define OMAP_TIMER_CTRL_ST (1 << 0) /* start timer */ > +#define _OMAP_TIMER_COUNTER_OFFSET 0x28 > +#define _OMAP_TIMER_LOAD_OFFSET 0x2c > +#define _OMAP_TIMER_TRIGGER_OFFSET 0x30 > +#define _OMAP_TIMER_WRITE_PEND_OFFSET 0x34 > +#define WP_NONE 0 /* no write pending bit */ > +#define WP_TCLR (1 << 0) > +#define WP_TCRR (1 << 1) > +#define WP_TLDR (1 << 2) > +#define WP_TTGR (1 << 3) > +#define WP_TMAR (1 << 4) > +#define WP_TPIR (1 << 5) > +#define WP_TNIR (1 << 6) > +#define WP_TCVR (1 << 7) > +#define WP_TOCR (1 << 8) > +#define WP_TOWR (1 << 9) > +#define _OMAP_TIMER_MATCH_OFFSET 0x38 > +#define _OMAP_TIMER_CAPTURE_OFFSET 0x3c > +#define _OMAP_TIMER_IF_CTRL_OFFSET 0x40 > +#define _OMAP_TIMER_CAPTURE2_OFFSET 0x44 /* TCAR2, 34xx only */ > +#define _OMAP_TIMER_TICK_POS_OFFSET 0x48 /* TPIR, 34xx only */ > +#define _OMAP_TIMER_TICK_NEG_OFFSET 0x4c /* TNIR, 34xx only */ > +#define _OMAP_TIMER_TICK_COUNT_OFFSET 0x50 /* TCVR, 34xx only */ > +#define _OMAP_TIMER_TICK_INT_MASK_SET_OFFSET 0x54 /* TOCR, 34xx only */ > +#define _OMAP_TIMER_TICK_INT_MASK_COUNT_OFFSET 0x58 /* TOWR, 34xx only */ > + > +/* register offsets with the write pending bit encoded */ > +#define WPSHIFT 16 > + > +#define OMAP_TIMER_ID_REG (_OMAP_TIMER_ID_OFFSET \ > + | (WP_NONE << WPSHIFT)) > + > +#define OMAP_TIMER_OCP_CFG_REG (_OMAP_TIMER_OCP_CFG_OFFSET \ > + | (WP_NONE << WPSHIFT)) > + > +#define OMAP_TIMER_SYS_STAT_REG (_OMAP_TIMER_SYS_STAT_OFFSET \ > + | (WP_NONE << WPSHIFT)) > + > +#define OMAP_TIMER_STAT_REG (_OMAP_TIMER_STAT_OFFSET \ > + | (WP_NONE << WPSHIFT)) > + > +#define OMAP_TIMER_INT_EN_REG (_OMAP_TIMER_INT_EN_OFFSET \ > + | (WP_NONE << WPSHIFT)) > + > +#define OMAP_TIMER_WAKEUP_EN_REG (_OMAP_TIMER_WAKEUP_EN_OFFSET \ > + | (WP_NONE << WPSHIFT)) > + > +#define OMAP_TIMER_CTRL_REG (_OMAP_TIMER_CTRL_OFFSET \ > + | (WP_TCLR << WPSHIFT)) > + > +#define OMAP_TIMER_COUNTER_REG (_OMAP_TIMER_COUNTER_OFFSET \ > + | (WP_TCRR << WPSHIFT)) > + > +#define OMAP_TIMER_LOAD_REG (_OMAP_TIMER_LOAD_OFFSET \ > + | (WP_TLDR << WPSHIFT)) > + > +#define OMAP_TIMER_TRIGGER_REG (_OMAP_TIMER_TRIGGER_OFFSET \ > + | (WP_TTGR << WPSHIFT)) > + > +#define OMAP_TIMER_WRITE_PEND_REG (_OMAP_TIMER_WRITE_PEND_OFFSET \ > + | (WP_NONE << WPSHIFT)) > + > +#define OMAP_TIMER_MATCH_REG (_OMAP_TIMER_MATCH_OFFSET \ > + | (WP_TMAR << WPSHIFT)) > + > +#define OMAP_TIMER_CAPTURE_REG (_OMAP_TIMER_CAPTURE_OFFSET \ > + | (WP_NONE << WPSHIFT)) > + > +#define OMAP_TIMER_IF_CTRL_REG (_OMAP_TIMER_IF_CTRL_OFFSET \ > + | (WP_NONE << WPSHIFT)) > + > +#define OMAP_TIMER_CAPTURE2_REG (_OMAP_TIMER_CAPTURE2_OFFSET \ > + | (WP_NONE << WPSHIFT)) > + > +#define OMAP_TIMER_TICK_POS_REG (_OMAP_TIMER_TICK_POS_OFFSET \ > + | (WP_TPIR << WPSHIFT)) > + > +#define OMAP_TIMER_TICK_NEG_REG (_OMAP_TIMER_TICK_NEG_OFFSET \ > + | (WP_TNIR << WPSHIFT)) > + > +#define OMAP_TIMER_TICK_COUNT_REG (_OMAP_TIMER_TICK_COUNT_OFFSET \ > + | (WP_TCVR << WPSHIFT)) > + > +#define OMAP_TIMER_TICK_INT_MASK_SET_REG \ > + (_OMAP_TIMER_TICK_INT_MASK_SET_OFFSET | (WP_TOCR << WPSHIFT)) > + > +#define OMAP_TIMER_TICK_INT_MASK_COUNT_REG \ > + (_OMAP_TIMER_TICK_INT_MASK_COUNT_OFFSET | (WP_TOWR << WPSHIFT)) > > struct omap_dm_timer { > unsigned long phys_base; > @@ -76,6 +155,7 @@ struct omap_dm_timer { > void __iomem *io_base; > unsigned reserved:1; > unsigned enabled:1; > + unsigned posted:1; > }; > > #ifdef CONFIG_ARCH_OMAP1 > @@ -181,16 +261,34 @@ static struct clk **dm_source_clocks; > > static spinlock_t dm_timer_lock; > > -static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, int reg) > +/* > + * Reads timer registers in posted and non-posted mode. The posted mode bit > + * is encoded in reg. Note that in posted mode write pending bit must be > + * checked. Otherwise a read of a non completed write will produce an error. > + */ > +static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg) > { > - return readl(timer->io_base + reg); > + if (timer->posted) > + while (readl(timer->io_base + (OMAP_TIMER_WRITE_PEND_REG & 0xff)) > + & (reg >> WPSHIFT)) > + cpu_relax(); > + return readl(timer->io_base + (reg & 0xff)); > } > > -static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, int reg, u32 value) > +/* > + * Writes timer registers in posted and non-posted mode. The posted mode bit > + * is encoded in reg. Note that in posted mode the write pending bit must be > + * checked. Otherwise a write on a register which has a pending write will be > + * lost. > + */ > +static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg, > + u32 value) > { > - writel(value, timer->io_base + reg); > - while (omap_dm_timer_read_reg(timer, OMAP_TIMER_WRITE_PEND_REG)) > - ; > + if (timer->posted) > + while (readl(timer->io_base + (OMAP_TIMER_WRITE_PEND_REG & 0xff)) > + & (reg >> WPSHIFT)) > + cpu_relax(); > + writel(value, timer->io_base + (reg & 0xff)); > } > > static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer) > @@ -217,17 +315,23 @@ static void omap_dm_timer_reset(struct omap_dm_timer *timer) > } > omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ); > > - /* Set to smart-idle mode */ > l = omap_dm_timer_read_reg(timer, OMAP_TIMER_OCP_CFG_REG); > - l |= 0x02 << 3; > - > - if (cpu_class_is_omap2() && timer == &dm_timers[0]) { > - /* Enable wake-up only for GPT1 on OMAP2 CPUs*/ > + l |= 0x02 << 3; /* Set to smart-idle mode */ > + l |= 0x2 << 8; /* Set clock activity to perserve f-clock on idle */ > + > + /* > + * Enable wake-up only for GPT1 on OMAP2 CPUs. > + * FIXME: All timers should have wake-up enabled and clear > + * PRCM status. > + */ > + if (cpu_class_is_omap2() && (timer == &dm_timers[0])) > l |= 1 << 2; > - /* Non-posted mode */ > - omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0); > - } > omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_REG, l); > + > + /* Match hardware reset default of posted mode */ > + omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, > + OMAP_TIMER_CTRL_POSTED); > + timer->posted = 1; > } > > static void omap_dm_timer_prepare(struct omap_dm_timer *timer) > @@ -434,6 +538,11 @@ void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload, > l &= ~OMAP_TIMER_CTRL_AR; > omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); > omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load); > + > + /* REVISIT: hw feature, ttgr overtaking tldr? */ > + while (readl(timer->io_base + (OMAP_TIMER_WRITE_PEND_REG & 0xff))) > + cpu_relax(); > + > omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0); > } > ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] I2C: Fix twl4030 timeouts on omap3430 2008-03-28 11:46 ` [PATCH] I2C: Fix twl4030 timeouts on omap3430 Tony Lindgren 2008-03-28 11:46 ` Tony Lindgren @ 2008-03-28 11:48 ` Tony Lindgren 1 sibling, 0 replies; 11+ messages in thread From: Tony Lindgren @ 2008-03-28 11:48 UTC (permalink / raw) To: linux-omap * Tony Lindgren <tony@atomide.com> [080328 13:47]: > For some reason doing a twl4030 write-read cycle can hang the I2C bus > on omap3430. And doing the write and read separately in twl4030_i2c_read() > seems to fix the problem... > > Not intended for applying, just a temporary workaround. Uh, please ignore this one, git-send-email weirdness where it sends all files ending in .patch.. The series should only contain two patches. Tony > > diff --git a/drivers/i2c/chips/twl4030-core.c b/drivers/i2c/chips/twl4030-core.c > index ded86e7..62868b0 100644 > --- a/drivers/i2c/chips/twl4030-core.c > +++ b/drivers/i2c/chips/twl4030-core.c > @@ -327,6 +327,7 @@ int twl4030_i2c_read(u8 mod_no, u8 * value, u8 reg, u8 num_bytes) > return -EPERM; > } > mutex_lock(&twl->xfer_lock); > + > /* [MSG1] fill the register address data */ > msg = &twl->xfer_msg[0]; > msg->addr = twl->address; > @@ -334,18 +335,25 @@ int twl4030_i2c_read(u8 mod_no, u8 * value, u8 reg, u8 num_bytes) > msg->flags = 0; /* Read the register value */ > val = twl4030_map[mod_no].base + reg; > msg->buf = &val; > + ret = i2c_transfer(twl->client.adapter, twl->xfer_msg, 1); > + if (ret < 0) > + goto out; > + > /* [MSG2] fill the data rx buffer */ > msg = &twl->xfer_msg[1]; > msg->addr = twl->address; > msg->flags = I2C_M_RD; /* Read the register value */ > msg->len = num_bytes; /* only n bytes */ > msg->buf = value; > - ret = i2c_transfer(twl->client.adapter, twl->xfer_msg, 2); > + ret = i2c_transfer(twl->client.adapter, twl->xfer_msg, 1); > + > +out: > mutex_unlock(&twl->xfer_lock); > > /* i2cTransfer returns num messages.translate it pls.. */ > if (ret >= 0) > ret = 0; > + > return ret; > } > ^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2008-04-01 14:05 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-03-28 8:41 [PATCH] I2C: Fix twl4030 timeouts on omap3430 Tony Lindgren
2008-03-31 10:43 ` Tony Lindgren
2008-03-31 14:30 ` Tony Lindgren
2008-04-01 12:43 ` Tony Lindgren
2008-04-01 13:00 ` Peter 'p2' De Schrijver
2008-04-01 13:38 ` Tony Lindgren
2008-04-01 14:04 ` Tony Lindgren
-- strict thread matches above, loose matches on Subject: below --
2008-03-28 11:46 [PATCH 0/2] Add sram34xx.S Tony Lindgren
2008-03-28 11:46 ` [PATCH 1/2] ARM: OMAP3: Add 34xx SRAM functions Tony Lindgren
2008-03-28 11:46 ` [PATCH 2/2] ARCH: OMAP3: Make SRAM code from TI CDP compile and work Tony Lindgren
[not found] ` <1206704800-6768-4-git-send-email-tony@atomide.com>
2008-03-28 11:46 ` [PATCH] I2C: Fix twl4030 timeouts on omap3430 Tony Lindgren
2008-03-28 11:46 ` Tony Lindgren
2008-03-28 11:49 ` Tony Lindgren
2008-03-28 11:48 ` Tony Lindgren
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox