linux 3.0: Fix sprz319 erratum 2.1
authorKoen Kooi <koen@dominion.thruhere.net>
Mon, 19 Mar 2012 18:16:08 +0000 (19:16 +0100)
committerDenys Dmytriyenko <denys@ti.com>
Mon, 19 Mar 2012 18:34:40 +0000 (14:34 -0400)
Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
Signed-off-by: Denys Dmytriyenko <denys@ti.com>
recipes-kernel/linux/linux-3.0/patch.sh
recipes-kernel/linux/linux-3.0/usb/0001-Fix-sprz319-erratum-2.1.patch [new file with mode: 0644]
recipes-kernel/linux/linux_3.0.bb

index dc19a9e5123ea7380a872e6dfe00b7c03e292db6..31bdfe18f008c63dadebbe98ac33bc159de16f82 100755 (executable)
@@ -13,7 +13,7 @@ git reset --hard ${TAG}
 rm export -rf
 
 previous=${TAG}
 rm export -rf
 
 previous=${TAG}
-PATCHSET="pm-wip/voltdm pm-wip/cpufreq beagle madc sakoman sgx ulcd omap4 misc"
+PATCHSET="pm-wip/voltdm pm-wip/cpufreq beagle madc sakoman sgx ulcd omap4 misc usb"
 
 # apply patches
 for patchset in ${PATCHSET} ; do
 
 # apply patches
 for patchset in ${PATCHSET} ; do
diff --git a/recipes-kernel/linux/linux-3.0/usb/0001-Fix-sprz319-erratum-2.1.patch b/recipes-kernel/linux/linux-3.0/usb/0001-Fix-sprz319-erratum-2.1.patch
new file mode 100644 (file)
index 0000000..8d65b5f
--- /dev/null
@@ -0,0 +1,210 @@
+From cf5db5477d8d43f02f4511f3835ab4bec0dcc27c Mon Sep 17 00:00:00 2001
+From: Richard Watts <rrw@kynesim.co.uk>
+Date: Mon, 20 Feb 2012 17:58:26 +0000
+Subject: [PATCH] Fix sprz319 erratum 2.1
+
+There is an erratum in DM3730 which results in the
+EHCI USB PLL (DPLL5) not updating sufficiently frequently; this
+leads to USB PHY clock drift and once the clock has drifted far
+enough, the PHY's ULPI interface stops responding and USB
+drops out. This is manifested on a Beagle xM by having the attached
+SMSC9514 report 'Cannot enable port 2. Maybe the USB cable is bad?'
+or similar.
+
+The fix is to carefully adjust your DPLL5 settings so as to
+keep the PHY clock as close as possible to 120MHz over the long
+term; TI SPRZ319e gives a table of such settings and this patch
+applies that table to systems with a 13MHz or a 26MHz clock,
+thus fixing the issue (inasfar as it can be fixed) on Beagle xM
+and Overo Firestorm.
+
+Signed-off-by: Richard Watts <rrw@kynesim.co.uk>
+---
+ arch/arm/mach-omap2/clkt_clksel.c    |   15 ++++++++
+ arch/arm/mach-omap2/clock.h          |    7 ++++
+ arch/arm/mach-omap2/clock3xxx.c      |   65 +++++++++++++++++++++++++++++----
+ arch/arm/mach-omap2/clock3xxx.h      |    1 +
+ arch/arm/mach-omap2/clock3xxx_data.c |    2 +-
+ arch/arm/mach-omap2/dpll3xxx.c       |    2 +-
+ 6 files changed, 82 insertions(+), 10 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/clkt_clksel.c b/arch/arm/mach-omap2/clkt_clksel.c
+index e25364d..e378fe7 100644
+--- a/arch/arm/mach-omap2/clkt_clksel.c
++++ b/arch/arm/mach-omap2/clkt_clksel.c
+@@ -460,6 +460,21 @@ int omap2_clksel_set_rate(struct clk *clk, unsigned long rate)
+       return 0;
+ }
++int omap2_clksel_force_divisor(struct clk *clk, int new_div)
++{
++      u32 field_val;
++
++      field_val = _divisor_to_clksel(clk, new_div);
++      if (field_val == ~0)
++              return -EINVAL;
++
++      _write_clksel_reg(clk, field_val);
++
++      clk->rate = clk->parent->rate / new_div;
++
++      return 0;
++}
++
+ /*
+  * Clksel parent setting function - not passed in struct clk function
+  * pointer - instead, the OMAP clock code currently assumes that any
+diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h
+index 8bad1c6..ac3d367 100644
+--- a/arch/arm/mach-omap2/clock.h
++++ b/arch/arm/mach-omap2/clock.h
+@@ -61,6 +61,12 @@ void omap3_dpll_allow_idle(struct clk *clk);
+ void omap3_dpll_deny_idle(struct clk *clk);
+ u32 omap3_dpll_autoidle_read(struct clk *clk);
+ int omap3_noncore_dpll_set_rate(struct clk *clk, unsigned long rate);
++#if CONFIG_ARCH_OMAP3
++int omap3_noncore_dpll_program(struct clk *clk, u16 m, u8 n, u16 freqsel);
++/* If you are using this function and not on OMAP3, you are
++ * Doing It Wrong(tm), so there is no stub.
++ */
++#endif
+ int omap3_noncore_dpll_enable(struct clk *clk);
+ void omap3_noncore_dpll_disable(struct clk *clk);
+ int omap4_dpllmx_gatectrl_read(struct clk *clk);
+@@ -84,6 +90,7 @@ unsigned long omap2_clksel_recalc(struct clk *clk);
+ long omap2_clksel_round_rate(struct clk *clk, unsigned long target_rate);
+ int omap2_clksel_set_rate(struct clk *clk, unsigned long rate);
+ int omap2_clksel_set_parent(struct clk *clk, struct clk *new_parent);
++int omap2_clksel_force_divisor(struct clk *clk, int new_div);
+ /* clkt_iclk.c public functions */
+ extern void omap2_clkt_iclk_allow_idle(struct clk *clk);
+diff --git a/arch/arm/mach-omap2/clock3xxx.c b/arch/arm/mach-omap2/clock3xxx.c
+index 952c3e0..d5be086 100644
+--- a/arch/arm/mach-omap2/clock3xxx.c
++++ b/arch/arm/mach-omap2/clock3xxx.c
+@@ -40,6 +40,60 @@
+ /* needed by omap3_core_dpll_m2_set_rate() */
+ struct clk *sdrc_ick_p, *arm_fck_p;
++struct dpll_settings {
++      int rate, m, n, f;
++};
++
++
++static int omap3_dpll5_apply_erratum21(struct clk *clk, struct clk *dpll5_m2)
++{
++      struct clk *sys_clk;
++      int i, rv;
++      static const struct dpll_settings precomputed[] = {
++              /* From DM3730 errata (sprz319e), table 36
++              * +1 is because the values in the table are register values;
++              * dpll_program() will subtract one from what we give it,
++              * so ...
++              */
++              { 13000000, 443+1, 5+1, 8 },
++              { 26000000, 443+1, 11+1, 8 }
++      };
++
++      sys_clk = clk_get(NULL, "sys_ck");
++
++      for (i = 0 ; i < (sizeof(precomputed)/sizeof(struct dpll_settings)) ;
++              ++i) {
++              const struct dpll_settings *d = &precomputed[i];
++              if (sys_clk->rate == d->rate) {
++                      rv =  omap3_noncore_dpll_program(clk, d->m , d->n, 0);
++                      if (rv)
++                              return 1;
++                      rv =  omap2_clksel_force_divisor(dpll5_m2 , d->f);
++                      return 1;
++              }
++      }
++      return 0;
++}
++
++int omap3_dpll5_set_rate(struct clk *clk, unsigned long rate)
++{
++      struct clk *dpll5_m2;
++      int rv;
++      dpll5_m2 = clk_get(NULL, "dpll5_m2_ck");
++
++      if (cpu_is_omap3630() && rate == DPLL5_FREQ_FOR_USBHOST &&
++              omap3_dpll5_apply_erratum21(clk, dpll5_m2)) {
++              return 1;
++      }
++      rv = omap3_noncore_dpll_set_rate(clk, rate);
++      if (rv)
++              goto out;
++      rv = clk_set_rate(dpll5_m2, rate);
++
++out:
++      return rv;
++}
++
+ int omap3_dpll4_set_rate(struct clk *clk, unsigned long rate)
+ {
+       /*
+@@ -59,19 +113,14 @@ int omap3_dpll4_set_rate(struct clk *clk, unsigned long rate)
+ void __init omap3_clk_lock_dpll5(void)
+ {
+       struct clk *dpll5_clk;
+-      struct clk *dpll5_m2_clk;
+       dpll5_clk = clk_get(NULL, "dpll5_ck");
+       clk_set_rate(dpll5_clk, DPLL5_FREQ_FOR_USBHOST);
+-      clk_enable(dpll5_clk);
+-      /* Program dpll5_m2_clk divider for no division */
+-      dpll5_m2_clk = clk_get(NULL, "dpll5_m2_ck");
+-      clk_enable(dpll5_m2_clk);
+-      clk_set_rate(dpll5_m2_clk, DPLL5_FREQ_FOR_USBHOST);
++      /* dpll5_m2_ck is now (grottily!) handled by dpll5_clk's set routine,
++       * to cope with an erratum on DM3730
++       */
+-      clk_disable(dpll5_m2_clk);
+-      clk_disable(dpll5_clk);
+       return;
+ }
+diff --git a/arch/arm/mach-omap2/clock3xxx.h b/arch/arm/mach-omap2/clock3xxx.h
+index 8bbeeaf..0ede513 100644
+--- a/arch/arm/mach-omap2/clock3xxx.h
++++ b/arch/arm/mach-omap2/clock3xxx.h
+@@ -10,6 +10,7 @@
+ int omap3xxx_clk_init(void);
+ int omap3_dpll4_set_rate(struct clk *clk, unsigned long rate);
++int omap3_dpll5_set_rate(struct clk *clk, unsigned long rate);
+ int omap3_core_dpll_m2_set_rate(struct clk *clk, unsigned long rate);
+ void omap3_clk_lock_dpll5(void);
+diff --git a/arch/arm/mach-omap2/clock3xxx_data.c b/arch/arm/mach-omap2/clock3xxx_data.c
+index ffd55b1..dcd7bdc 100644
+--- a/arch/arm/mach-omap2/clock3xxx_data.c
++++ b/arch/arm/mach-omap2/clock3xxx_data.c
+@@ -942,7 +942,7 @@ static struct clk dpll5_ck = {
+       .parent         = &sys_ck,
+       .dpll_data      = &dpll5_dd,
+       .round_rate     = &omap2_dpll_round_rate,
+-      .set_rate       = &omap3_noncore_dpll_set_rate,
++      .set_rate       = &omap3_dpll5_set_rate,
+       .clkdm_name     = "dpll5_clkdm",
+       .recalc         = &omap3_dpll_recalc,
+ };
+diff --git a/arch/arm/mach-omap2/dpll3xxx.c b/arch/arm/mach-omap2/dpll3xxx.c
+index f77022b..1909cd0 100644
+--- a/arch/arm/mach-omap2/dpll3xxx.c
++++ b/arch/arm/mach-omap2/dpll3xxx.c
+@@ -291,7 +291,7 @@ static void _lookup_sddiv(struct clk *clk, u8 *sd_div, u16 m, u8 n)
+  * Program the DPLL with the supplied M, N values, and wait for the DPLL to
+  * lock..  Returns -EINVAL upon error, or 0 upon success.
+  */
+-static int omap3_noncore_dpll_program(struct clk *clk, u16 m, u8 n, u16 freqsel)
++int omap3_noncore_dpll_program(struct clk *clk, u16 m, u8 n, u16 freqsel)
+ {
+       struct dpll_data *dd = clk->dpll_data;
+       u8 dco, sd_div;
+-- 
+1.7.2.5
+
index 32ef9632edd5450d18688de098b17af9f6978a27..c95542e9a918e7b12b366467cc660ec84d22ddf8 100644 (file)
@@ -10,7 +10,7 @@ PV = "3.0.23"
 SRCREV_pn-${PN} = "bf6a68d2a214e07f7c0d6538e00e17b826714160"
 
 # The main PR is now using MACHINE_KERNEL_PR, for omap3 see conf/machine/include/omap3.inc
 SRCREV_pn-${PN} = "bf6a68d2a214e07f7c0d6538e00e17b826714160"
 
 # The main PR is now using MACHINE_KERNEL_PR, for omap3 see conf/machine/include/omap3.inc
-MACHINE_KERNEL_PR_append = "a"
+MACHINE_KERNEL_PR_append = "b"
 
 FILESPATH =. "${FILE_DIRNAME}/linux-3.0:${FILE_DIRNAME}/linux-3.0/${MACHINE}:"
 
 
 FILESPATH =. "${FILE_DIRNAME}/linux-3.0:${FILE_DIRNAME}/linux-3.0/${MACHINE}:"
 
@@ -224,6 +224,8 @@ SRC_URI += "git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.gi
             \
             file://misc/0001-compiler.h-Undef-before-redefining-__attribute_const.patch \
             \
             \
             file://misc/0001-compiler.h-Undef-before-redefining-__attribute_const.patch \
             \
+            file://usb/0001-Fix-sprz319-erratum-2.1.patch \
+            \
             file://defconfig"
 
 SRC_URI_append_beagleboard = " file://logo_linux_clut224.ppm \
             file://defconfig"
 
 SRC_URI_append_beagleboard = " file://logo_linux_clut224.ppm \