diff options
Diffstat (limited to 'target/linux/brcm47xx/patches-2.6.22/210-ssb_fixes.patch')
-rw-r--r-- | target/linux/brcm47xx/patches-2.6.22/210-ssb_fixes.patch | 372 |
1 files changed, 372 insertions, 0 deletions
diff --git a/target/linux/brcm47xx/patches-2.6.22/210-ssb_fixes.patch b/target/linux/brcm47xx/patches-2.6.22/210-ssb_fixes.patch new file mode 100644 index 0000000000..273d8bb34f --- /dev/null +++ b/target/linux/brcm47xx/patches-2.6.22/210-ssb_fixes.patch @@ -0,0 +1,372 @@ +Index: linux-2.6.22-rc5/drivers/ssb/driver_chipcommon.c +=================================================================== +--- linux-2.6.22-rc5.orig/drivers/ssb/driver_chipcommon.c 2007-06-21 23:04:38.000000000 +0100 ++++ linux-2.6.22-rc5/drivers/ssb/driver_chipcommon.c 2007-06-24 20:07:15.000000000 +0100 +@@ -264,6 +264,31 @@ + ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST); + } + ++/* TODO: These two functions are a clear candidate for merging, but one gets ++ * the processor clock, and the other gets the bus clock. ++ */ ++void ssb_chipco_get_clockcpu(struct ssb_chipcommon *cc, ++ u32 *plltype, u32 *n, u32 *m) ++{ ++ *n = chipco_read32(cc, SSB_CHIPCO_CLOCK_N); ++ *plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT); ++ switch (*plltype) { ++ case SSB_PLLTYPE_2: ++ case SSB_PLLTYPE_4: ++ case SSB_PLLTYPE_6: ++ case SSB_PLLTYPE_7: ++ *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_MIPS); ++ break; ++ case SSB_PLLTYPE_3: ++ /* 5350 uses m2 to control mips */ ++ *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_M2); ++ break; ++ default: ++ *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_SB); ++ break; ++ } ++} ++ + void ssb_chipco_get_clockcontrol(struct ssb_chipcommon *cc, + u32 *plltype, u32 *n, u32 *m) + { +@@ -400,3 +425,13 @@ + return nr_ports; + } + #endif /* CONFIG_SSB_SERIAL */ ++ ++/* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */ ++int ++ssb_chipco_watchdog(struct ssb_chipcommon *cc, uint ticks) ++{ ++ /* instant NMI */ ++ chipco_write32(cc, SSB_CHIPCO_WATCHDOG, ticks); ++ return 0; ++} ++EXPORT_SYMBOL(ssb_chipco_watchdog); +Index: linux-2.6.22-rc5/drivers/ssb/driver_mipscore.c +=================================================================== +--- linux-2.6.22-rc5.orig/drivers/ssb/driver_mipscore.c 2007-06-10 16:44:31.000000000 +0100 ++++ linux-2.6.22-rc5/drivers/ssb/driver_mipscore.c 2007-06-24 20:48:52.000000000 +0100 +@@ -4,6 +4,7 @@ + * + * Copyright 2005, Broadcom Corporation + * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de> ++ * Copyright 2006, 2007, Felix Fietkau <nbd@openwrt.org> + * + * Licensed under the GNU/GPL. See COPYING for details. + */ +@@ -31,6 +32,16 @@ + ssb_write32(mcore->dev, offset, value); + } + ++static inline u32 extif_read32(struct ssb_extif *extif, u16 offset) ++{ ++ return ssb_read32(extif->dev, offset); ++} ++ ++static inline void extif_write32(struct ssb_extif *extif, u16 offset, u32 value) ++{ ++ ssb_write32(extif->dev, offset, value); ++} ++ + static const u32 ipsflag_irq_mask[] = { + 0, + SSB_IPSFLAG_IRQ1, +@@ -118,9 +129,9 @@ + } + + /* XXX: leave here or move into separate extif driver? */ +-static int ssb_extif_serial_init(struct ssb_device *dev, struct ssb_serial_ports *ports) ++static int ssb_extif_serial_init(struct ssb_extif *dev, struct ssb_serial_port *ports) + { +- ++ return 0; + } + + +@@ -174,23 +185,76 @@ + { + struct ssb_bus *bus = mcore->dev->bus; + ++ mcore->flash_buswidth = 2; + if (bus->chipco.dev) { + mcore->flash_window = 0x1c000000; +- mcore->flash_window_size = 0x800000; ++ mcore->flash_window_size = 0x02000000; ++ if ((ssb_read32(bus->chipco.dev, SSB_CHIPCO_FLASH_CFG) ++ & SSB_CHIPCO_CFG_DS16) == 0) ++ mcore->flash_buswidth = 1; + } else { + mcore->flash_window = 0x1fc00000; +- mcore->flash_window_size = 0x400000; ++ mcore->flash_window_size = 0x00400000; + } + } + ++static void ssb_extif_timing_init(struct ssb_extif *extif, u32 ns) ++{ ++ u32 tmp; ++ ++ /* Initialize extif so we can get to the LEDs and external UART */ ++ extif_write32(extif, SSB_EXTIF_PROG_CFG, SSB_EXTCFG_EN); ++ ++ /* Set timing for the flash */ ++ tmp = DIV_ROUND_UP(10, ns) << SSB_PROG_WCNT_3_SHIFT; ++ tmp |= DIV_ROUND_UP(40, ns) << SSB_PROG_WCNT_1_SHIFT; ++ tmp |= DIV_ROUND_UP(120, ns); ++ extif_write32(extif, SSB_EXTIF_PROG_WAITCNT, tmp); ++ ++ /* Set programmable interface timing for external uart */ ++ tmp = DIV_ROUND_UP(10, ns) << SSB_PROG_WCNT_3_SHIFT; ++ tmp |= DIV_ROUND_UP(20, ns) << SSB_PROG_WCNT_2_SHIFT; ++ tmp |= DIV_ROUND_UP(100, ns) << SSB_PROG_WCNT_1_SHIFT; ++ tmp |= DIV_ROUND_UP(120, ns); ++ extif_write32(extif, SSB_EXTIF_PROG_WAITCNT, tmp); ++} + +-static void ssb_cpu_clock(struct ssb_mipscore *mcore) ++static inline void ssb_extif_get_clockcontrol(struct ssb_extif *extif, ++ u32 *pll_type, u32 *n, u32 *m) + { ++ *pll_type = SSB_PLLTYPE_1; ++ *n = extif_read32(extif, SSB_EXTIF_CLOCK_N); ++ *m = extif_read32(extif, SSB_EXTIF_CLOCK_SB); + } + +-void ssb_mipscore_init(struct ssb_mipscore *mcore) ++u32 ssb_cpu_clock(struct ssb_mipscore *mcore) + { + struct ssb_bus *bus = mcore->dev->bus; ++ u32 pll_type, n, m, rate = 0; ++ ++ if (bus->extif.dev) { ++ ssb_extif_get_clockcontrol(&bus->extif, &pll_type, &n, &m); ++ } else if (bus->chipco.dev) { ++ ssb_chipco_get_clockcpu(&bus->chipco, &pll_type, &n, &m); ++ } else ++ return 0; ++ ++ if ((pll_type == SSB_PLLTYPE_5) || (bus->chip_id == 0x5365)) { ++ rate = 200000000; ++ } else { ++ rate = ssb_calc_clock_rate(pll_type, n, m); ++ } ++ ++ if (pll_type == SSB_PLLTYPE_6) { ++ rate *= 2; ++ } ++ ++ return rate; ++} ++ ++void ssb_mipscore_init(struct ssb_mipscore *mcore) ++{ ++ struct ssb_bus *bus; + struct ssb_device *dev; + unsigned long hz, ns; + unsigned int irq, i; +@@ -198,6 +262,8 @@ + if (!mcore->dev) + return; /* We don't have a MIPS core */ + ++ bus = mcore->dev->bus; ++ + ssb_dprintk(KERN_INFO PFX "Initializing MIPS core...\n"); + + hz = ssb_clockspeed(bus); +@@ -205,28 +271,9 @@ + hz = 100000000; + ns = 1000000000 / hz; + +-//TODO +-#if 0 +- if (have EXTIF) { +- /* Initialize extif so we can get to the LEDs and external UART */ +- W_REG(&eir->prog_config, CF_EN); +- +- /* Set timing for the flash */ +- tmp = CEIL(10, ns) << FW_W3_SHIFT; /* W3 = 10nS */ +- tmp = tmp | (CEIL(40, ns) << FW_W1_SHIFT); /* W1 = 40nS */ +- tmp = tmp | CEIL(120, ns); /* W0 = 120nS */ +- W_REG(&eir->prog_waitcount, tmp); /* 0x01020a0c for a 100Mhz clock */ +- +- /* Set programmable interface timing for external uart */ +- tmp = CEIL(10, ns) << FW_W3_SHIFT; /* W3 = 10nS */ +- tmp = tmp | (CEIL(20, ns) << FW_W2_SHIFT); /* W2 = 20nS */ +- tmp = tmp | (CEIL(100, ns) << FW_W1_SHIFT); /* W1 = 100nS */ +- tmp = tmp | CEIL(120, ns); /* W0 = 120nS */ +- W_REG(&eir->prog_waitcount, tmp); +- } +- else... chipcommon +-#endif +- if (bus->chipco.dev) ++ if (bus->extif.dev) ++ ssb_extif_timing_init(&bus->extif, ns); ++ else if (bus->chipco.dev) + ssb_chipco_timing_init(&bus->chipco, ns); + + /* Assign IRQs to all cores on the bus, start with irq line 2, because serial usually takes 1 */ +@@ -256,3 +303,5 @@ + ssb_mips_serial_init(mcore); + ssb_mips_flash_detect(mcore); + } ++ ++EXPORT_SYMBOL(ssb_mips_irq); +Index: linux-2.6.22-rc5/include/linux/ssb/ssb_driver_chipcommon.h +=================================================================== +--- linux-2.6.22-rc5.orig/include/linux/ssb/ssb_driver_chipcommon.h 2007-06-10 16:44:47.000000000 +0100 ++++ linux-2.6.22-rc5/include/linux/ssb/ssb_driver_chipcommon.h 2007-06-24 20:07:15.000000000 +0100 +@@ -364,6 +364,8 @@ + extern void ssb_chipco_suspend(struct ssb_chipcommon *cc, pm_message_t state); + extern void ssb_chipco_resume(struct ssb_chipcommon *cc); + ++extern void ssb_chipco_get_clockcpu(struct ssb_chipcommon *cc, ++ u32 *plltype, u32 *n, u32 *m); + extern void ssb_chipco_get_clockcontrol(struct ssb_chipcommon *cc, + u32 *plltype, u32 *n, u32 *m); + extern void ssb_chipco_timing_init(struct ssb_chipcommon *cc, +@@ -378,6 +380,46 @@ + extern void ssb_chipco_set_clockmode(struct ssb_chipcommon *cc, + enum ssb_clkmode mode); + ++/* GPIO functions */ ++static inline u32 ssb_chipco_gpio_in(struct ssb_chipcommon *cc, ++ u32 mask) ++{ ++ return ssb_read32(cc->dev, SSB_CHIPCO_GPIOIN) & mask; ++} ++ ++static inline u32 ssb_chipco_gpio_out(struct ssb_chipcommon *cc, ++ u32 mask, u32 value) ++{ ++ return ssb_write32_masked(cc->dev, SSB_CHIPCO_GPIOOUT, mask, value); ++} ++ ++static inline u32 ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, ++ u32 mask, u32 value) ++{ ++ return ssb_write32_masked(cc->dev, SSB_CHIPCO_GPIOOUTEN, mask, value); ++} ++ ++static inline u32 ssb_chipco_gpio_control(struct ssb_chipcommon *cc, ++ u32 mask, u32 value) ++{ ++ return ssb_write32_masked(cc->dev, SSB_CHIPCO_GPIOCTL, mask, value); ++} ++ ++static inline u32 ssb_chipco_gpio_intmask(struct ssb_chipcommon *cc, ++ u32 mask, u32 value) ++{ ++ return ssb_write32_masked(cc->dev, SSB_CHIPCO_GPIOIRQ, mask, value); ++} ++ ++static inline u32 ssb_chipco_gpio_polarity(struct ssb_chipcommon *cc, ++ u32 mask, u32 value) ++{ ++ return ssb_write32_masked(cc->dev, SSB_CHIPCO_GPIOPOL, mask, value); ++} ++/* TODO: GPIO reservation */ ++ ++extern int ssb_chipco_watchdog(struct ssb_chipcommon *cc, uint ticks); ++ + #ifdef CONFIG_SSB_SERIAL + extern int ssb_chipco_serial_init(struct ssb_chipcommon *cc, + struct ssb_serial_port *ports); +Index: linux-2.6.22-rc5/include/linux/ssb/ssb_driver_extif.h +=================================================================== +--- linux-2.6.22-rc5.orig/include/linux/ssb/ssb_driver_extif.h 2007-06-10 16:44:47.000000000 +0100 ++++ linux-2.6.22-rc5/include/linux/ssb/ssb_driver_extif.h 2007-06-24 20:07:15.000000000 +0100 +@@ -158,6 +158,36 @@ + /* watchdog */ + #define SSB_EXTIF_WATCHDOG_CLK 48000000 /* Hz */ + ++/* GPIO functions */ ++static inline u32 ssb_extif_gpio_in(struct ssb_extif *extif, ++ u32 mask) ++{ ++ return ssb_read32(extif->dev, SSB_EXTIF_GPIO_IN) & mask; ++} ++ ++static inline u32 ssb_extif_gpio_out(struct ssb_extif *extif, ++ u32 mask, u32 value) ++{ ++ return ssb_write32_masked(extif->dev, SSB_EXTIF_GPIO_OUT(0), mask, value); ++} ++ ++static inline u32 ssb_extif_gpio_outen(struct ssb_extif *extif, ++ u32 mask, u32 value) ++{ ++ return ssb_write32_masked(extif->dev, SSB_EXTIF_GPIO_OUTEN(0), mask, value); ++} ++ ++static inline u32 ssb_extif_gpio_polarity(struct ssb_extif *extif, ++ u32 mask, u32 value) ++{ ++ return ssb_write32_masked(extif->dev, SSB_EXTIF_GPIO_INTPOL, mask, value); ++} ++ ++static inline u32 ssb_extif_gpio_intmask(struct ssb_extif *extif, ++ u32 mask, u32 value) ++{ ++ return ssb_write32_masked(extif->dev, SSB_EXTIF_GPIO_INTMASK, mask, value); ++} + + #endif /* __KERNEL__ */ + #endif /* LINUX_SSB_EXTIFCORE_H_ */ +Index: linux-2.6.22-rc5/include/linux/ssb/ssb_driver_mips.h +=================================================================== +--- linux-2.6.22-rc5.orig/include/linux/ssb/ssb_driver_mips.h 2007-06-10 16:44:47.000000000 +0100 ++++ linux-2.6.22-rc5/include/linux/ssb/ssb_driver_mips.h 2007-06-24 20:07:15.000000000 +0100 +@@ -22,11 +22,13 @@ + int nr_serial_ports; + struct ssb_serial_port serial_ports[4]; + ++ int flash_buswidth; + u32 flash_window; + u32 flash_window_size; + }; + + extern void ssb_mipscore_init(struct ssb_mipscore *mcore); ++extern u32 ssb_cpu_clock(struct ssb_mipscore *mcore); + + extern unsigned int ssb_mips_irq(struct ssb_device *dev); + +Index: linux-2.6.22-rc5/include/linux/ssb/ssb.h +=================================================================== +--- linux-2.6.22-rc5.orig/include/linux/ssb/ssb.h 2007-06-24 19:49:56.000000000 +0100 ++++ linux-2.6.22-rc5/include/linux/ssb/ssb.h 2007-06-24 20:07:15.000000000 +0100 +@@ -270,6 +270,12 @@ + #define SSB_CHIPPACK_BCM4712M 2 /* Medium 225pin 4712 */ + #define SSB_CHIPPACK_BCM4712L 0 /* Large 340pin 4712 */ + ++static inline u16 ssb_read16(struct ssb_device *dev, u16 offset); ++static inline u32 ssb_read32(struct ssb_device *dev, u16 offset); ++static inline void ssb_write16(struct ssb_device *dev, u16 offset, u16 value); ++static inline void ssb_write32(struct ssb_device *dev, u16 offset, u32 value); ++static inline u32 ssb_write32_masked(struct ssb_device *dev, u16 offset, u32 mask, u32 value); ++ + #include <linux/ssb/ssb_driver_chipcommon.h> + #include <linux/ssb/ssb_driver_mips.h> + #include <linux/ssb/ssb_driver_extif.h> +@@ -388,6 +394,16 @@ + dev->ops->write32(dev, offset, value); + } + ++static inline u32 ssb_write32_masked(struct ssb_device *dev, ++ u16 offset, ++ u32 mask, ++ u32 value) ++{ ++ value &= mask; ++ value |= ssb_read32(dev, offset) & ~mask; ++ ssb_write32(dev, offset, value); ++ return value; ++} + + /* Translation (routing) bits that need to be ORed to DMA + * addresses before they are given to a device. */ |