diff options
19 files changed, 1841 insertions, 335 deletions
diff --git a/target/linux/brcm47xx-2.6/files/drivers/ssb/Kconfig b/target/linux/brcm47xx-2.6/files/drivers/ssb/Kconfig index 09330dfa6..03c494586 100644 --- a/target/linux/brcm47xx-2.6/files/drivers/ssb/Kconfig +++ b/target/linux/brcm47xx-2.6/files/drivers/ssb/Kconfig @@ -71,4 +71,23 @@ config SSB_PCICORE_HOSTMODE  	help  	  PCIcore hostmode operation (external PCI bus). +config SSB_DRIVER_MIPS +	bool "SSB Broadcom MIPS core driver" +	depends on SSB && MIPS +	select SSB_SERIAL +	help +	  Driver for the Sonics Silicon Backplane attached +	  Broadcom MIPS core. + +	  If unsure, say N + +config SSB_DRIVER_EXTIF +	bool "SSB Broadcom EXTIF core driver" +	depends on SSB_DRIVER_MIPS +	help +	  Driver for the Sonics Silicon Backplane attached +	  Broadcom EXTIF core. + +	  If unsure, say N +  endmenu diff --git a/target/linux/brcm47xx-2.6/files/drivers/ssb/Makefile b/target/linux/brcm47xx-2.6/files/drivers/ssb/Makefile index 9f85d225d..9a2b379fb 100644 --- a/target/linux/brcm47xx-2.6/files/drivers/ssb/Makefile +++ b/target/linux/brcm47xx-2.6/files/drivers/ssb/Makefile @@ -1,14 +1,11 @@ -ssb-driver-chipcommon-y				:= driver_chipcommon/chipcommon.o -ssb-driver-mips-$(CONFIG_BCM947XX)	:= driver_mips/mips.o -ssb-driver-pci-$(CONFIG_SSB_DRIVER_PCICORE)	:= driver_pci/pcicore.o +ssb-builtin-drivers-y					+= driver_chipcommon.o +ssb-builtin-drivers-$(CONFIG_SSB_DRIVER_MIPS)		+= driver_mipscore.o +ssb-builtin-drivers-$(CONFIG_SSB_DRIVER_PCICORE)	+= driver_pcicore.o -ssb-$(CONFIG_SSB_PCIHOST)			+= pci.o -ssb-$(CONFIG_SSB_PCMCIAHOST)			+= pcmcia.o +ssb-hostsupport-$(CONFIG_SSB_PCIHOST)			+= pci.o pcihost_wrapper.o +ssb-hostsupport-$(CONFIG_SSB_PCMCIAHOST)		+= pcmcia.o  obj-$(CONFIG_SSB) += ssb.o -ssb-objs	:= core.o scan.o \ -		   $(ssb-y) $(ssb-m) \ -		   $(ssb-driver-chipcommon-y) \ -		   $(ssb-driver-mips-y) \ -		   $(ssb-driver-pci-y) +ssb-objs	:= main.o scan.o \ +		   $(ssb-hostsupport-y) $(ssb-builtin-drivers-y) diff --git a/target/linux/brcm47xx-2.6/files/drivers/ssb/driver_chipcommon/chipcommon.c b/target/linux/brcm47xx-2.6/files/drivers/ssb/driver_chipcommon.c index a17910947..8e511c77b 100644 --- a/target/linux/brcm47xx-2.6/files/drivers/ssb/driver_chipcommon/chipcommon.c +++ b/target/linux/brcm47xx-2.6/files/drivers/ssb/driver_chipcommon.c @@ -12,7 +12,7 @@  #include <linux/ssb/ssb_regs.h>  #include <linux/pci.h> -#include "../ssb_private.h" +#include "ssb_private.h"  /* Clock sources */ @@ -39,7 +39,6 @@ static inline void chipco_write32(struct ssb_chipcommon *cc,  	ssb_write32(cc->dev, offset, value);  } -  void ssb_chipco_set_clockmode(struct ssb_chipcommon *cc,  			      enum ssb_clkmode mode)  { @@ -89,7 +88,6 @@ void ssb_chipco_set_clockmode(struct ssb_chipcommon *cc,  		assert(0);  	}  } -EXPORT_SYMBOL(ssb_chipco_set_clockmode);  /* Get the Slow Clock Source */  static int chipco_pctl_get_slowclksrc(struct ssb_chipcommon *cc) @@ -98,8 +96,8 @@ static int chipco_pctl_get_slowclksrc(struct ssb_chipcommon *cc)  	u32 tmp = 0;  	if (cc->dev->id.revision < 6) { -		if (bus->bustype == SSB_BUSTYPE_SSB /*TODO || -		    bus->bustype == SSB_BUSTYPE_PCMCIA*/) +		if (bus->bustype == SSB_BUSTYPE_SSB || +		    bus->bustype == SSB_BUSTYPE_PCMCIA)  			return SSB_CHIPCO_CLKSRC_XTALOS;  		if (bus->bustype == SSB_BUSTYPE_PCI) {  			pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT, &tmp); @@ -246,8 +244,8 @@ void ssb_chipcommon_init(struct ssb_chipcommon *cc)  {  	if (!cc->dev)  		return; /* We don't have a ChipCommon */ -	ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST);  	chipco_powercontrol_init(cc); +	ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST);  	calc_fast_powerup_delay(cc);  } @@ -262,37 +260,8 @@ void ssb_chipco_resume(struct ssb_chipcommon *cc)  {  	if (!cc->dev)  		return; -	ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST);  	chipco_powercontrol_init(cc); -} - -void ssb_chipco_get_clockcpu(struct ssb_chipcommon *cc, u32 chip_id, u32 *rate, -			     u32 *plltype, u32 *n, u32 *m) -{ -	*rate = 0; -	*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_5: -			*rate = 200000000; -			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; -	} - -	if (*rate == 0 && chip_id == 0x5365) -		*rate = 200000000; +	ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST);  }  void ssb_chipco_get_clockcontrol(struct ssb_chipcommon *cc, @@ -351,6 +320,7 @@ void ssb_chipco_timing_init(struct ssb_chipcommon *cc,  	}  } +  #ifdef CONFIG_SSB_SERIAL  int ssb_chipco_serial_init(struct ssb_chipcommon *cc,  			   struct ssb_serial_port *ports) @@ -430,13 +400,3 @@ int ssb_chipco_serial_init(struct ssb_chipcommon *cc,  	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); diff --git a/target/linux/brcm47xx-2.6/files/drivers/ssb/driver_mips/mips.c b/target/linux/brcm47xx-2.6/files/drivers/ssb/driver_mipscore.c index 7b3880ab0..67d10178b 100644 --- a/target/linux/brcm47xx-2.6/files/drivers/ssb/driver_mips/mips.c +++ b/target/linux/brcm47xx-2.6/files/drivers/ssb/driver_mipscore.c @@ -4,7 +4,6 @@   *   * 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.   */ @@ -16,12 +15,21 @@  #include <linux/serial_reg.h>  #include <asm/time.h> -#include "../ssb_private.h" +#include "ssb_private.h" -#define mips_read32(mcore, offset) ssb_read32((mcore)->dev, offset) -#define mips_write32(mcore, offset, value) ssb_write32((mcore)->dev, offset, value) -#define extif_read32(extif, offset) ssb_read32((extif)->dev, offset) -#define extif_write32(extif, offset, value) ssb_write32((extif)->dev, offset, value) + +static inline u32 mips_read32(struct ssb_mipscore *mcore, +			      u16 offset) +{ +	return ssb_read32(mcore->dev, offset); +} + +static inline void mips_write32(struct ssb_mipscore *mcore, +				u16 offset, +				u32 value) +{ +	ssb_write32(mcore->dev, offset, value); +}  static const u32 ipsflag_irq_mask[] = {  	0, @@ -109,8 +117,17 @@ static void set_irq(struct ssb_device *dev, unsigned int irq)  	ssb_write32(mdev, SSB_IPSFLAG, irqflag);  } -static int ssb_extif_serial_init(struct ssb_extif *dev, struct ssb_serial_port *ports) +/* 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 void ssb_mips_serial_init(struct ssb_mipscore *mcore)  { +	struct ssb_bus *bus = mcore->dev->bus; +  	//TODO if (EXTIF available  #if 0  		extifregs_t *eir = (extifregs_t *) regs; @@ -145,14 +162,6 @@ static int ssb_extif_serial_init(struct ssb_extif *dev, struct ssb_serial_port *  				add((void *) &eir->uartdata, irq, sb_clock(sbh), 2);  #endif - -} - - -static void ssb_mips_serial_init(struct ssb_mipscore *mcore) -{ -	struct ssb_bus *bus = mcore->dev->bus; -  	if (bus->extif.dev)  		mcore->nr_serial_ports = ssb_extif_serial_init(&bus->extif, mcore->serial_ports);  	else if (bus->chipco.dev) @@ -165,68 +174,18 @@ static void ssb_mips_flash_detect(struct ssb_mipscore *mcore)  {  	struct ssb_bus *bus = mcore->dev->bus; -	mcore->flash_buswidth = 2;  	if (bus->chipco.dev) {  		mcore->flash_window = 0x1c000000; -		mcore->flash_window_size = 0x02000000; -		if ((ssb_read32(bus->chipco.dev, SSB_CHIPCO_FLASH_CFG) -				& SSB_CHIPCO_CFG_DS16) == 0) -			mcore->flash_buswidth = 1; +		mcore->flash_window_size = 0x800000;  	} else {  		mcore->flash_window = 0x1fc00000; -		mcore->flash_window_size = 0x00400000; +		mcore->flash_window_size = 0x400000;  	}  } -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  = ceildiv(10, ns) << SSB_PROG_WCNT_3_SHIFT; -	tmp |= ceildiv(40, ns) << SSB_PROG_WCNT_1_SHIFT; -	tmp |= ceildiv(120, ns); -	extif_write32(extif, SSB_EXTIF_PROG_WAITCNT, tmp); - -	/* Set programmable interface timing for external uart */ -	tmp  = ceildiv(10, ns) << SSB_PROG_WCNT_3_SHIFT; -	tmp |= ceildiv(20, ns) << SSB_PROG_WCNT_2_SHIFT; -	tmp |= ceildiv(100, ns) << SSB_PROG_WCNT_1_SHIFT; -	tmp |= ceildiv(120, ns); -	extif_write32(extif, SSB_EXTIF_PROG_WAITCNT, tmp); -} - -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); -} -u32 ssb_cpu_clock(struct ssb_mipscore *mcore) +static void 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, bus->chip_id, &rate, -			&pll_type, &n, &m); -	} else -		return 0; - -	if (rate == 0) -		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) @@ -246,9 +205,28 @@ void ssb_mipscore_init(struct ssb_mipscore *mcore)  		hz = 100000000;  	ns = 1000000000 / hz; -	if (bus->extif.dev) -		ssb_extif_timing_init(&bus->extif, ns); -	else if (bus->chipco.dev) +//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)  		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 */ @@ -278,5 +256,3 @@ void ssb_mipscore_init(struct ssb_mipscore *mcore)  	ssb_mips_serial_init(mcore);  	ssb_mips_flash_detect(mcore);  } - -EXPORT_SYMBOL(ssb_mips_irq); diff --git a/target/linux/brcm47xx-2.6/files/drivers/ssb/driver_pci/pcicore.c b/target/linux/brcm47xx-2.6/files/drivers/ssb/driver_pcicore.c index 3ad97036f..a59dff083 100644 --- a/target/linux/brcm47xx-2.6/files/drivers/ssb/driver_pci/pcicore.c +++ b/target/linux/brcm47xx-2.6/files/drivers/ssb/driver_pcicore.c @@ -12,7 +12,8 @@  #include <linux/pci.h>  #include <linux/delay.h> -#include "../ssb_private.h" +#include "ssb_private.h" +  static inline  u32 pcicore_read32(struct ssb_pcicore *pc, u16 offset) @@ -92,9 +93,6 @@ static void __init ssb_fixup_pcibridge(struct pci_dev *dev)  	/* Enable PCI bridge BAR1 prefetch and burst */  	pci_write_config_dword(dev, SSB_BAR1_CONTROL, 3); - -	/* Make sure our latency is high enough to handle the devices behind us */ -	pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xa8);  }  DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ssb_fixup_pcibridge); @@ -112,7 +110,7 @@ static u32 get_cfgspace_addr(struct ssb_pcicore *pc,  	if (unlikely(pc->cardbusmode && dev > 1))  		goto out; -	if (bus == 0) {//FIXME busnumber ok? +	if (bus == 0) {  		/* Type 0 transaction */  		if (unlikely(dev >= SSB_PCI_SLOT_MAX))  			goto out; @@ -164,7 +162,8 @@ static int ssb_extpci_read_config(struct ssb_pcicore *pc,  		val = 0xffffffff;  		goto unmap;  	} -	 + +	val = readl(mmio);  	val >>= (8 * (off & 3));  	switch (len) { @@ -212,10 +211,12 @@ static int ssb_extpci_write_config(struct ssb_pcicore *pc,  	switch (len) {  	case 1: +		val = readl(mmio);  		val &= ~(0xFF << (8 * (off & 3)));  		val |= *((const u8 *)buf) << (8 * (off & 3));  		break;  	case 2: +		val = readl(mmio);  		val &= ~(0xFFFF << (8 * (off & 3)));  		val |= *((const u16 *)buf) << (8 * (off & 3));  		break; @@ -223,7 +224,7 @@ static int ssb_extpci_write_config(struct ssb_pcicore *pc,  		val = *((const u32 *)buf);  		break;  	} -	writel(val, mmio); +	writel(*((const u32 *)buf), mmio);  	err = 0;  unmap: @@ -290,7 +291,10 @@ static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc)  {  	u32 val; -	assert(!extpci_core); +	if (extpci_core) { +		WARN_ON(1); +		return; +	}  	extpci_core = pc;  	ssb_dprintk(KERN_INFO PFX "PCIcore in host mode found\n"); @@ -303,8 +307,6 @@ static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc)  	udelay(150);  	val |= SSB_PCICORE_CTL_RST; /* Deassert RST# */  	pcicore_write32(pc, SSB_PCICORE_CTL, val); -	val = SSB_PCICORE_ARBCTL_INTERN; -	pcicore_write32(pc, SSB_PCICORE_ARBCTL, val);   	udelay(1);  	//TODO cardbus mode @@ -321,7 +323,10 @@ static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc)  	/* Enable PCI bridge BAR0 prefetch and burst */  	val = PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; -	ssb_extpci_write_config(pc, 0, 0, 0, PCI_COMMAND, &val, 4); +	ssb_extpci_write_config(pc, 0, 0, 0, PCI_COMMAND, &val, 2); +	/* Clear error conditions */ +	val = 0; +	ssb_extpci_write_config(pc, 0, 0, 0, PCI_STATUS, &val, 2);  	/* Enable PCI interrupts */  	pcicore_write32(pc, SSB_PCICORE_IMASK, @@ -331,7 +336,6 @@ static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc)  	 * The following needs change, if we want to port hostmode  	 * to non-MIPS platform. */  	set_io_port_base((unsigned long)ioremap_nocache(SSB_PCI_MEM, 0x04000000)); -	mdelay(300);  	register_pci_controller(&ssb_pcicore_controller);  } @@ -383,7 +387,8 @@ void ssb_pcicore_init(struct ssb_pcicore *pc)  	if (!dev)  		return;  	bus = dev->bus; -	ssb_device_enable(dev, 0); +	if (!ssb_device_is_enabled(dev)) +		ssb_device_enable(dev, 0);  #ifdef CONFIG_SSB_PCICORE_HOSTMODE  	pc->hostmode = pcicore_is_in_hostmode(pc); diff --git a/target/linux/brcm47xx-2.6/files/drivers/ssb/core.c b/target/linux/brcm47xx-2.6/files/drivers/ssb/main.c index 2ee13d2d3..a2d22312c 100644 --- a/target/linux/brcm47xx-2.6/files/drivers/ssb/core.c +++ b/target/linux/brcm47xx-2.6/files/drivers/ssb/main.c @@ -35,35 +35,55 @@ static LIST_HEAD(buses);  static int nr_buses;  static DEFINE_MUTEX(buses_mutex); -#define ssb_buses_lock() do {			\ -	if (!is_early_boot())			\ -		mutex_lock(&buses_mutex);	\ -			} while (0) +static void ssb_buses_lock(void); +static void ssb_buses_unlock(void); -#define ssb_buses_unlock() do {			\ -	if (!is_early_boot())			\ -		mutex_unlock(&buses_mutex);	\ -			} while (0) +#ifdef CONFIG_SSB_PCIHOST +struct ssb_bus * ssb_pci_dev_to_bus(struct pci_dev *pdev) +{ +	struct ssb_bus *bus; + +	ssb_buses_lock(); +	list_for_each_entry(bus, &buses, list) { +		if (bus->bustype == SSB_BUSTYPE_PCI && +		    bus->host_pci == pdev) +			goto found; +	} +	bus = NULL; +found: +	ssb_buses_unlock(); + +	return bus; +} +#endif /* CONFIG_SSB_PCIHOST */  static struct ssb_device * ssb_device_get(struct ssb_device *dev)  {  	if (dev) -		get_device(&dev->dev); +		get_device(dev->dev);  	return dev;  }  static void ssb_device_put(struct ssb_device *dev)  {  	if (dev) -		put_device(&dev->dev); +		put_device(dev->dev);  } -static void ssb_bus_resume(struct ssb_bus *bus) +static int ssb_bus_resume(struct ssb_bus *bus)  { -printk("SSB BUS RESUME\n"); +	int err; +  	ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1); +	err = ssb_pcmcia_init(bus); +	if (err) { +		/* No need to disable XTAL, as we don't have one on PCMCIA. */ +		return err; +	}  	ssb_chipco_resume(&bus->chipco); + +	return 0;  }  static int ssb_device_resume(struct device *dev) @@ -73,10 +93,12 @@ static int ssb_device_resume(struct device *dev)  	struct ssb_bus *bus;  	int err = 0; -printk("SSB DEV RESUME\n");  	bus = ssb_dev->bus; -	if (bus->suspend_cnt == bus->nr_devices) -		ssb_bus_resume(bus); +	if (bus->suspend_cnt == bus->nr_devices) { +		err = ssb_bus_resume(bus); +		if (err) +			return err; +	}  	bus->suspend_cnt--;  	if (dev->driver) {  		ssb_drv = drv_to_ssb_drv(dev->driver); @@ -91,9 +113,15 @@ out:  static void ssb_bus_suspend(struct ssb_bus *bus, pm_message_t state)  { -printk("SSB BUS SUSPEND\n"); -//	ssb_chipco_suspend(&bus->chipco, state); -//	ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0); +	ssb_chipco_suspend(&bus->chipco, state); +	ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0); + +	/* Reset HW state information in memory, so that HW is +	 * completely reinitialized on resume. */ +	bus->mapped_device = NULL; +#ifdef CONFIG_SSB_DRIVER_PCICORE +	bus->pcicore.setup_done = 0; +#endif  }  static int ssb_device_suspend(struct device *dev, pm_message_t state) @@ -103,7 +131,6 @@ static int ssb_device_suspend(struct device *dev, pm_message_t state)  	struct ssb_bus *bus;  	int err = 0; -printk("SSB DEV SUSPEND\n");  	if (dev->driver) {  		ssb_drv = drv_to_ssb_drv(dev->driver);  		if (ssb_drv && ssb_drv->suspend) @@ -123,6 +150,57 @@ out:  	return err;  } +#ifdef CONFIG_SSB_PCIHOST +int ssb_devices_freeze(struct ssb_bus *bus) +{ +	struct ssb_device *dev; +	struct ssb_driver *drv; +	int err = 0; +	int i; +	pm_message_t state = PMSG_FREEZE; + +	for (i = 0; i < bus->nr_devices; i++) { +		dev = &(bus->devices[i]); +		if (!dev->dev->driver) +			continue; +		if (!device_is_registered(dev->dev)) +			continue; +		drv = drv_to_ssb_drv(dev->dev->driver); +		if (drv && drv->suspend) { +			err = drv->suspend(dev, state); +			if (err) +				goto out; +		} +	} +out: +	return err; +} + +int ssb_devices_thaw(struct ssb_bus *bus) +{ +	struct ssb_device *dev; +	struct ssb_driver *drv; +	int err = 0; +	int i; + +	for (i = 0; i < bus->nr_devices; i++) { +		dev = &(bus->devices[i]); +		if (!dev->dev->driver) +			continue; +		if (!device_is_registered(dev->dev)) +			continue; +		drv = drv_to_ssb_drv(dev->dev->driver); +		if (drv && drv->resume) { +			err = drv->resume(dev); +			if (err) +				goto out; +		} +	} +out: +	return err; +} +#endif /* CONFIG_SSB_PCIHOST */ +  static void ssb_device_shutdown(struct device *dev)  {  	struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); @@ -193,7 +271,7 @@ static int ssb_bus_match(struct device *dev, struct device_driver *drv)  	return 0;  } -struct bus_type ssb_bustype = { +static struct bus_type ssb_bustype = {  	.name		= NULL, /* Intentionally NULL to indicate early boot */  	.match		= ssb_bus_match,  	.probe		= ssb_device_probe, @@ -205,51 +283,156 @@ struct bus_type ssb_bustype = {  #define is_early_boot()		(ssb_bustype.name == NULL) -void ssb_bus_unregister(struct ssb_bus *bus) +static void ssb_buses_lock(void)  { -	struct ssb_device *dev; +	if (!is_early_boot()) +		mutex_lock(&buses_mutex); +} + +static void ssb_buses_unlock(void) +{ +	if (!is_early_boot()) +		mutex_unlock(&buses_mutex); +} + +static void ssb_devices_unregister(struct ssb_bus *bus) +{ +	struct ssb_device *sdev;  	int i; -	ssb_buses_lock();  	for (i = bus->nr_devices - 1; i >= 0; i--) { -		dev = &(bus->devices[i]); -		device_unregister(&dev->dev); +		sdev = &(bus->devices[i]); +		if (sdev->dev) +			device_unregister(sdev->dev);  	} +} + +void ssb_bus_unregister(struct ssb_bus *bus) +{ +	ssb_buses_lock(); +	ssb_devices_unregister(bus);  	list_del(&bus->list);  	ssb_buses_unlock(); +	/* ssb_pcmcia_exit(bus); */ +	ssb_pci_exit(bus);  	ssb_iounmap(bus);  }  EXPORT_SYMBOL(ssb_bus_unregister);  static void ssb_release_dev(struct device *dev)  { -	/* Nothing, devices are allocated together with struct ssb_bus. */ +	struct __ssb_dev_wrapper *devwrap; + +	devwrap = container_of(dev, struct __ssb_dev_wrapper, dev); +	kfree(devwrap); +} + +static int ssb_devices_register(struct ssb_bus *bus) +{ +	struct ssb_device *sdev; +	struct device *dev; +	struct __ssb_dev_wrapper *devwrap; +	int i, err = 0; +	int dev_idx = 0; + +	for (i = 0; i < bus->nr_devices; i++) { +		sdev = &(bus->devices[i]); + +		/* We don't register SSB-system devices to the kernel, +		 * as the drivers for them are built into SSB. */ +		switch (sdev->id.coreid) { +		case SSB_DEV_CHIPCOMMON: +		case SSB_DEV_PCI: +		case SSB_DEV_PCIE: +		case SSB_DEV_PCMCIA: +		case SSB_DEV_MIPS: +		case SSB_DEV_MIPS_3302: +		case SSB_DEV_EXTIF: +			continue; +		} + +		devwrap = kzalloc(sizeof(*devwrap), GFP_KERNEL); +		if (!devwrap) { +			ssb_printk(KERN_ERR PFX +				   "Could not allocate device\n"); +			err = -ENOMEM; +			goto error; +		} +		dev = &devwrap->dev; +		devwrap->sdev = sdev; + +		dev->release = ssb_release_dev; +		dev->bus = &ssb_bustype; +		snprintf(dev->bus_id, sizeof(dev->bus_id), +			 "ssb%d:%d", bus->busnumber, dev_idx); + +		switch (bus->bustype) { +		case SSB_BUSTYPE_PCI: +#ifdef CONFIG_SSB_PCIHOST +			sdev->irq = bus->host_pci->irq; +			dev->parent = &bus->host_pci->dev; +#endif +			break; +		case SSB_BUSTYPE_PCMCIA: +#ifdef CONFIG_SSB_PCMCIAHOST +			dev->parent = &bus->host_pcmcia->dev; +#endif +			break; +		case SSB_BUSTYPE_SSB: +			break; +		} + +		sdev->dev = dev; +		err = device_register(dev); +		if (err) { +			ssb_printk(KERN_ERR PFX +				   "Could not register %s\n", +				   dev->bus_id); +			/* Set dev to NULL to not unregister +			 * dev on error unwinding. */ +			sdev->dev = NULL; +			kfree(devwrap); +			goto error; +		} +		dev_idx++; +	} + +	return 0; +error: +	/* Unwind the already registered devices. */ +	ssb_devices_unregister(bus); +	return err;  }  /* Needs ssb_buses_lock() */  static int ssb_attach_queued_buses(void)  {  	struct ssb_bus *bus, *n; -	struct ssb_device *dev; -	int i, err; +	int err = 0; +	int drop_them_all = 0;  	list_for_each_entry_safe(bus, n, &attach_queue, list) { +		if (drop_them_all) { +			list_del(&bus->list); +			continue; +		} +		/* Can't init the PCIcore in ssb_bus_register(), as that +		 * is too early in boot for embedded systems +		 * (no udelay() available). So do it here in attach stage. +		 */  		ssb_pcicore_init(&bus->pcicore); -		for (i = 0; i < bus->nr_devices; i++) { -			dev = &(bus->devices[i]); - -			dev->dev.release = ssb_release_dev; -			err = device_register(&dev->dev); -			if (err) { -				ssb_printk(KERN_ERR PFX -					   "Could not register %s\n", -					   dev->dev.bus_id); -			} + +		err = ssb_devices_register(bus); +		if (err) { +			drop_them_all = 1; +			list_del(&bus->list); +			continue;  		}  		list_move_tail(&bus->list, &buses);  	} -	return 0; + +	return err;  }  static void ssb_get_boardtype(struct ssb_bus *bus) @@ -307,23 +490,6 @@ static int ssb_bus_register(struct ssb_bus *bus,  {  	int err; -	ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found on "); -	switch (bus->bustype) { -	case SSB_BUSTYPE_SSB: -		ssb_printk("address 0x%08lX\n", baseaddr); -		break; -	case SSB_BUSTYPE_PCI: -#ifdef CONFIG_SSB_PCIHOST -		ssb_printk("PCI device %s\n", bus->host_pci->dev.bus_id); -#endif -		break; -	case SSB_BUSTYPE_PCMCIA: -#ifdef CONFIG_SSB_PCMCIAHOST -		ssb_printk("PCMCIA device %s\n", bus->host_pcmcia->devname); -#endif -		break; -	} -  	spin_lock_init(&bus->bar_lock);  	INIT_LIST_HEAD(&bus->list); @@ -346,7 +512,7 @@ static int ssb_bus_register(struct ssb_bus *bus,  	/* Init PCMCIA-host device (if any) */  	err = ssb_pcmcia_init(bus);  	if (err) -		goto err_unmap; +		goto err_pci_exit;  	/* Initialize basic system devices (if available) */  	ssb_chipcommon_init(&bus->chipco); @@ -368,12 +534,16 @@ out:  err_dequeue:  	list_del(&bus->list); +/* err_pcmcia_exit: */ +/*	ssb_pcmcia_exit(bus); */ +err_pci_exit: +	ssb_pci_exit(bus);  err_unmap:  	ssb_iounmap(bus);  err_disable_xtal:  	ssb_buses_unlock();  	ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0); -	goto out; +	return err;  }  #ifdef CONFIG_SSB_PCIHOST @@ -387,6 +557,10 @@ int ssb_bus_pcibus_register(struct ssb_bus *bus,  	bus->ops = &ssb_pci_ops;  	err = ssb_bus_register(bus, 0); +	if (!err) { +		ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found on " +			   "PCI device %s\n", host_pci->dev.bus_id); +	}  	return err;  } @@ -407,6 +581,10 @@ int ssb_bus_pcmciabus_register(struct ssb_bus *bus,  	fill_sprom(&bus->sprom);  	err = ssb_bus_register(bus, baseaddr); +	if (!err) { +		ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found on " +			   "PCMCIA device %s\n", pcmcia_dev->devname); +	}  	return err;  } @@ -422,7 +600,12 @@ int ssb_bus_ssbbus_register(struct ssb_bus *bus,  	bus->bustype = SSB_BUSTYPE_SSB;  	bus->ops = &ssb_ssb_ops;  	fill_sprom(&bus->sprom); +  	err = ssb_bus_register(bus, baseaddr); +	if (!err) { +		ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found at " +			   "address 0x%08lX\n", baseaddr); +	}  	return err;  } @@ -603,12 +786,29 @@ u32 ssb_clockspeed(struct ssb_bus *bus)  }  EXPORT_SYMBOL(ssb_clockspeed); +static u32 ssb_tmslow_reject_bitmask(struct ssb_device *dev) +{ +	/* The REJECT bit changed position in TMSLOW between +	 * Backplane revisions. */ +	switch (ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_SSBREV) { +	case SSB_IDLOW_SSBREV_22: +		return SSB_TMSLOW_REJECT_22; +	case SSB_IDLOW_SSBREV_23: +		return SSB_TMSLOW_REJECT_23; +	default: +		assert(0); +	} +	return (SSB_TMSLOW_REJECT_22 | SSB_TMSLOW_REJECT_23); +} +  int ssb_device_is_enabled(struct ssb_device *dev)  {  	u32 val; +	u32 reject; +	reject = ssb_tmslow_reject_bitmask(dev);  	val = ssb_read32(dev, SSB_TMSLOW); -	val &= SSB_TMSLOW_CLOCK | SSB_TMSLOW_RESET | SSB_TMSLOW_REJECT; +	val &= SSB_TMSLOW_CLOCK | SSB_TMSLOW_RESET | reject;  	return (val == SSB_TMSLOW_CLOCK);  } @@ -677,22 +877,25 @@ static int ssb_wait_bit(struct ssb_device *dev, u16 reg, u32 bitmask,  void ssb_device_disable(struct ssb_device *dev, u32 core_specific_flags)  { +	u32 reject; +  	if (ssb_read32(dev, SSB_TMSLOW) & SSB_TMSLOW_RESET)  		return; -	ssb_write32(dev, SSB_TMSLOW, SSB_TMSLOW_REJECT | SSB_TMSLOW_CLOCK); -	ssb_wait_bit(dev, SSB_TMSLOW, SSB_TMSLOW_REJECT, 1000, 1); +	reject = ssb_tmslow_reject_bitmask(dev); +	ssb_write32(dev, SSB_TMSLOW, reject | SSB_TMSLOW_CLOCK); +	ssb_wait_bit(dev, SSB_TMSLOW, reject, 1000, 1);  	ssb_wait_bit(dev, SSB_TMSHIGH, SSB_TMSHIGH_BUSY, 1000, 0);  	ssb_write32(dev, SSB_TMSLOW,  		    SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | -		    SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET | +		    reject | SSB_TMSLOW_RESET |  		    core_specific_flags);  	/* flush */  	ssb_read32(dev, SSB_TMSLOW);  	udelay(1);  	ssb_write32(dev, SSB_TMSLOW, -		    SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET | +		    reject | SSB_TMSLOW_RESET |  		    core_specific_flags);  	/* flush */  	ssb_read32(dev, SSB_TMSLOW); @@ -715,7 +918,7 @@ EXPORT_SYMBOL(ssb_dma_translation);  int ssb_dma_set_mask(struct ssb_device *ssb_dev, u64 mask)  { -	struct device *dev = &ssb_dev->dev; +	struct device *dev = ssb_dev->dev;  #ifdef CONFIG_SSB_PCIHOST  	if (ssb_dev->bus->bustype == SSB_BUSTYPE_PCI && @@ -729,6 +932,50 @@ int ssb_dma_set_mask(struct ssb_device *ssb_dev, u64 mask)  }  EXPORT_SYMBOL(ssb_dma_set_mask); +int ssb_bus_may_powerdown(struct ssb_bus *bus) +{ +	struct ssb_chipcommon *cc; +	int err; + +	/* On buses where more than one core may be working +	 * at a time, we must not powerdown stuff if there are +	 * still cores that may want to run. */ +	if (bus->bustype == SSB_BUSTYPE_SSB) +		return 0; + +	cc = &bus->chipco; +	ssb_chipco_set_clockmode(cc, SSB_CLKMODE_SLOW); +	err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0); +	if (err) +		goto error; + +	return 0; +error: +	ssb_printk(KERN_ERR PFX "Bus powerdown failed\n"); +	return err; +} +EXPORT_SYMBOL(ssb_bus_may_powerdown); + +int ssb_bus_powerup(struct ssb_bus *bus, int dynamic_pctl) +{ +	struct ssb_chipcommon *cc; +	int err; +	enum ssb_clkmode mode; + +	err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1); +	if (err) +		goto error; +	cc = &bus->chipco; +	mode = dynamic_pctl ? SSB_CLKMODE_DYNAMIC : SSB_CLKMODE_FAST; +	ssb_chipco_set_clockmode(cc, mode); + +	return 0; +error: +	ssb_printk(KERN_ERR PFX "Bus powerup failed\n"); +	return err; +} +EXPORT_SYMBOL(ssb_bus_powerup); +  u32 ssb_admatch_base(u32 adm)  {  	u32 base = 0; @@ -793,6 +1040,8 @@ static int __init ssb_modinit(void)  	ssb_buses_lock();  	err = ssb_attach_queued_buses();  	ssb_buses_unlock(); +	if (err) +		bus_unregister(&ssb_bustype);  	return err;  } diff --git a/target/linux/brcm47xx-2.6/files/drivers/ssb/pci.c b/target/linux/brcm47xx-2.6/files/drivers/ssb/pci.c index 811af789e..fcd8e871c 100644 --- a/target/linux/brcm47xx-2.6/files/drivers/ssb/pci.c +++ b/target/linux/brcm47xx-2.6/files/drivers/ssb/pci.c @@ -121,7 +121,7 @@ int ssb_pci_xtal(struct ssb_bus *bus, u32 what, int turn_on)  				err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out);  				if (err)  					goto err_pci; -				msleep(2); +				msleep(5);  			}  		} @@ -240,6 +240,52 @@ static void sprom_do_read(struct ssb_bus *bus, u16 *sprom)  		sprom[i] = readw(bus->mmio + SSB_SPROM_BASE + (i * 2));  } +static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom) +{ +	struct pci_dev *pdev = bus->host_pci; +	int i, err; +	u32 spromctl; + +	ssb_printk(KERN_NOTICE PFX "Writing SPROM. Do NOT turn off the power! Please stand by...\n"); +	err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl); +	if (err) +		goto err_ctlreg; +	spromctl |= SSB_SPROMCTL_WE; +	err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl); +	if (err) +		goto err_ctlreg; +	ssb_printk(KERN_NOTICE PFX "[ 0%%"); +	msleep(500); +	for (i = 0; i < SSB_SPROMSIZE_WORDS; i++) { +		if (i == SSB_SPROMSIZE_WORDS / 4) +			ssb_printk("25%%"); +		else if (i == SSB_SPROMSIZE_WORDS / 2) +			ssb_printk("50%%"); +		else if (i == (SSB_SPROMSIZE_WORDS / 4) * 3) +			ssb_printk("75%%"); +		else if (i % 2) +			ssb_printk("."); +		writew(sprom[i], bus->mmio + SSB_SPROM_BASE + (i * 2)); +		mmiowb(); +		msleep(20); +	} +	err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl); +	if (err) +		goto err_ctlreg; +	spromctl &= ~SSB_SPROMCTL_WE; +	err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl); +	if (err) +		goto err_ctlreg; +	msleep(500); +	ssb_printk("100%% ]\n"); +	ssb_printk(KERN_NOTICE PFX "SPROM written.\n"); + +	return 0; +err_ctlreg: +	ssb_printk(KERN_ERR PFX "Could not access SPROM control register.\n"); +	return err; +} +  static void sprom_extract_r1(struct ssb_sprom_r1 *out, const u16 *in)  {  	int i; @@ -472,9 +518,155 @@ const struct ssb_bus_ops ssb_pci_ops = {  	.write32	= ssb_pci_write32,  }; +static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len) +{ +	int i, pos = 0; + +	for (i = 0; i < SSB_SPROMSIZE_WORDS; i++) { +		pos += snprintf(buf + pos, buf_len - pos - 1, +				"%04X", swab16(sprom[i]) & 0xFFFF); +	} +	pos += snprintf(buf + pos, buf_len - pos - 1, "\n"); + +	return pos + 1; +} + +static int hex2sprom(u16 *sprom, const char *dump, size_t len) +{ +	char tmp[5] = { 0 }; +	int cnt = 0; +	unsigned long parsed; + +	if (len < SSB_SPROMSIZE_BYTES * 2) +		return -EINVAL; + +	while (cnt < SSB_SPROMSIZE_WORDS) { +		memcpy(tmp, dump, 4); +		dump += 4; +		parsed = simple_strtoul(tmp, NULL, 16); +		sprom[cnt++] = swab16((u16)parsed); +	} + +	return 0; +} + +static ssize_t ssb_pci_attr_sprom_show(struct device *pcidev, +				       struct device_attribute *attr, +				       char *buf) +{ +	struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev); +	struct ssb_bus *bus; +	u16 *sprom; +	int err = -ENODEV; +	ssize_t count = 0; + +	bus = ssb_pci_dev_to_bus(pdev); +	if (!bus) +		goto out; +	err = -ENOMEM; +	sprom = kcalloc(SSB_SPROMSIZE_WORDS, sizeof(u16), GFP_KERNEL); +	if (!sprom) +		goto out; + +	err = -ERESTARTSYS; +	if (mutex_lock_interruptible(&bus->pci_sprom_mutex)) +		goto out_kfree; +	sprom_do_read(bus, sprom); +	mutex_unlock(&bus->pci_sprom_mutex); + +	count = sprom2hex(sprom, buf, PAGE_SIZE); +	err = 0; + +out_kfree: +	kfree(sprom); +out: +	return err ? err : count; +} + +static ssize_t ssb_pci_attr_sprom_store(struct device *pcidev, +					struct device_attribute *attr, +					const char *buf, size_t count) +{ +	struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev); +	struct ssb_bus *bus; +	u16 *sprom; +	int res = 0, err = -ENODEV; + +	bus = ssb_pci_dev_to_bus(pdev); +	if (!bus) +		goto out; +	err = -ENOMEM; +	sprom = kcalloc(SSB_SPROMSIZE_WORDS, sizeof(u16), GFP_KERNEL); +	if (!sprom) +		goto out; +	err = hex2sprom(sprom, buf, count); +	if (err) { +		err = -EINVAL; +		goto out_kfree; +	} +	err = sprom_check_crc(sprom); +	if (err) { +		err = -EINVAL; +		goto out_kfree; +	} + +	err = -ERESTARTSYS; +	if (mutex_lock_interruptible(&bus->pci_sprom_mutex)) +		goto out_kfree; +	err = ssb_devices_freeze(bus); +	if (err) { +		ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze all devices\n"); +		goto out_unlock; +	} +	res = sprom_do_write(bus, sprom); +	err = ssb_devices_thaw(bus); +	if (err) +		ssb_printk(KERN_ERR PFX "SPROM write: Could not thaw all devices\n"); +out_unlock: +	mutex_unlock(&bus->pci_sprom_mutex); +out_kfree: +	kfree(sprom); +out: +	if (res) +		return res; +	return err ? err : count; +} + +static DEVICE_ATTR(ssb_sprom, 0600, +		   ssb_pci_attr_sprom_show, +		   ssb_pci_attr_sprom_store); + +void ssb_pci_exit(struct ssb_bus *bus) +{ +	struct pci_dev *pdev; + +	if (bus->bustype != SSB_BUSTYPE_PCI) +		return; + +	pdev = bus->host_pci; +	device_remove_file(&pdev->dev, &dev_attr_ssb_sprom); +} +  int ssb_pci_init(struct ssb_bus *bus)  { +	struct pci_dev *pdev; +	int err; +  	if (bus->bustype != SSB_BUSTYPE_PCI)  		return 0; -	return ssb_pci_sprom_get(bus); + +	pdev = bus->host_pci; +	mutex_init(&bus->pci_sprom_mutex); +	err = device_create_file(&pdev->dev, &dev_attr_ssb_sprom); +	if (err) +		goto out; +	err = ssb_pci_sprom_get(bus); +	if (err) +		goto err_remove_sprom_file; + +out: +	return err; +err_remove_sprom_file: +	device_remove_file(&pdev->dev, &dev_attr_ssb_sprom); +	return err;  } diff --git a/target/linux/brcm47xx-2.6/files/drivers/ssb/pcihost_wrapper.c b/target/linux/brcm47xx-2.6/files/drivers/ssb/pcihost_wrapper.c new file mode 100644 index 000000000..82a10abef --- /dev/null +++ b/target/linux/brcm47xx-2.6/files/drivers/ssb/pcihost_wrapper.c @@ -0,0 +1,104 @@ +/* + * Sonics Silicon Backplane + * PCI Hostdevice wrapper + * + * Copyright (c) 2005 Martin Langer <martin-langer@gmx.de> + * Copyright (c) 2005 Stefano Brivio <st3@riseup.net> + * Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org> + * Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch> + * Copyright (c) 2005-2007 Michael Buesch <mbuesch@freenet.de> + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include <linux/pci.h> +#include <linux/ssb/ssb.h> + + +#ifdef CONFIG_PM +static int ssb_pcihost_suspend(struct pci_dev *dev, pm_message_t state) +{ +	pci_save_state(dev); +	pci_disable_device(dev); +	pci_set_power_state(dev, pci_choose_state(dev, state)); + +	return 0; +} + +static int ssb_pcihost_resume(struct pci_dev *dev) +{ +	int err; + +	pci_set_power_state(dev, 0); +	err = pci_enable_device(dev); +	if (err) +		return err; +	pci_restore_state(dev); + +	return 0; +} +#else /* CONFIG_PM */ +# define ssb_pcihost_suspend	NULL +# define ssb_pcihost_resume	NULL +#endif /* CONFIG_PM */ + +static int ssb_pcihost_probe(struct pci_dev *dev, +			     const struct pci_device_id *id) +{ +	struct ssb_bus *ssb; +	int err = -ENOMEM; +	const char *name; + +	ssb = kzalloc(sizeof(*ssb), GFP_KERNEL); +	if (!ssb) +		goto out; +	err = pci_enable_device(dev); +	if (err) +		goto err_kfree_ssb; +	name = dev->dev.bus_id; +	if (dev->driver && dev->driver->name) +		name = dev->driver->name; +	err = pci_request_regions(dev, name); +	if (err) +		goto err_pci_disable; +	pci_set_master(dev); + +	err = ssb_bus_pcibus_register(ssb, dev); +	if (err) +		goto err_pci_release_regions; + +	pci_set_drvdata(dev, ssb); + +out: +	return err; + +err_pci_release_regions: +	pci_release_regions(dev); +err_pci_disable: +	pci_disable_device(dev); +err_kfree_ssb: +	kfree(ssb); +	return err; +} + +static void ssb_pcihost_remove(struct pci_dev *dev) +{ +	struct ssb_bus *ssb = pci_get_drvdata(dev); + +	ssb_bus_unregister(ssb); +	pci_release_regions(dev); +	pci_disable_device(dev); +	kfree(ssb); +	pci_set_drvdata(dev, NULL); +} + +int ssb_pcihost_register(struct pci_driver *driver) +{ +	driver->probe = ssb_pcihost_probe; +	driver->remove = ssb_pcihost_remove; +	driver->suspend = ssb_pcihost_suspend; +	driver->resume = ssb_pcihost_resume; + +	return pci_register_driver(driver); +} +EXPORT_SYMBOL(ssb_pcihost_register); diff --git a/target/linux/brcm47xx-2.6/files/drivers/ssb/scan.c b/target/linux/brcm47xx-2.6/files/drivers/ssb/scan.c index 9e4a121c1..feaf1e57d 100644 --- a/target/linux/brcm47xx-2.6/files/drivers/ssb/scan.c +++ b/target/linux/brcm47xx-2.6/files/drivers/ssb/scan.c @@ -17,6 +17,13 @@  #include <linux/pci.h>  #include <asm/io.h> +#ifdef CONFIG_SSB_PCMCIAHOST +# include <pcmcia/cs_types.h> +# include <pcmcia/cs.h> +# include <pcmcia/cistpl.h> +# include <pcmcia/ds.h> +#endif +  #include "ssb_private.h" @@ -222,14 +229,32 @@ static void __iomem * ssb_ioremap(struct ssb_bus *bus,  	return mmio;  } +static int we_support_multiple_80211_cores(struct ssb_bus *bus) +{ +	/* More than one 802.11 core is only supported by special chips. +	 * There are chips with two 802.11 cores, but with dangling +	 * pins on the second core. Be careful and reject them here. +	 */ + +#ifdef CONFIG_SSB_PCIHOST +	if (bus->bustype == SSB_BUSTYPE_PCI) { +		if (bus->host_pci->vendor == PCI_VENDOR_ID_BROADCOM && +		    bus->host_pci->device == 0x4324) +			return 1; +	} +#endif /* CONFIG_SSB_PCIHOST */ +	return 0; +} +  int ssb_bus_scan(struct ssb_bus *bus,  		 unsigned long baseaddr)  {  	int err = -ENOMEM;  	void __iomem *mmio;  	u32 idhi, cc, rev, tmp; -	int i; +	int dev_i, i;  	struct ssb_device *dev; +	int nr_80211_cores = 0;  	mmio = ssb_ioremap(bus, baseaddr);  	if (!mmio) @@ -293,11 +318,11 @@ int ssb_bus_scan(struct ssb_bus *bus,  	}  	/* Fetch basic information about each core/device */ -	for (i = 0; i < bus->nr_devices; i++) { +	for (i = 0, dev_i = 0; i < bus->nr_devices; i++) {  		err = scan_switchcore(bus, i);  		if (err)  			goto err_unmap; -		dev = &(bus->devices[i]); +		dev = &(bus->devices[dev_i]);  		idhi = scan_read32(bus, i, SSB_IDHIGH);  		dev->id.coreid = (idhi & SSB_IDHIGH_CC) >> SSB_IDHIGH_CC_SHIFT; @@ -306,8 +331,7 @@ int ssb_bus_scan(struct ssb_bus *bus,  		dev->id.vendor = (idhi & SSB_IDHIGH_VC) >> SSB_IDHIGH_VC_SHIFT;  		dev->core_index = i;  		dev->bus = bus; -		if ((dev->bus->bustype == SSB_BUSTYPE_PCI) && (bus->host_pci)) -			dev->irq = bus->host_pci->irq; +		dev->ops = bus->ops;  		ssb_dprintk(KERN_INFO PFX  			    "Core %d found: %s " @@ -315,13 +339,19 @@ int ssb_bus_scan(struct ssb_bus *bus,  			    i, ssb_core_name(dev->id.coreid),  			    dev->id.coreid, dev->id.revision, dev->id.vendor); -		dev->dev.bus = &ssb_bustype; -		snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id), -			 "ssb%02x:%02x", bus->busnumber, i); -  		switch (dev->id.coreid) { +		case SSB_DEV_80211: +			nr_80211_cores++; +			if (nr_80211_cores > 1) { +				if (!we_support_multiple_80211_cores(bus)) { +					ssb_dprintk(KERN_INFO PFX "Ignoring additional " +						    "802.11 core\n"); +					continue; +				} +			} +			break;  		case SSB_DEV_EXTIF: -#ifdef CONFIG_BCM947XX +#ifdef CONFIG_SSB_DRIVER_EXTIF  			if (bus->extif.dev) {  				ssb_printk(KERN_WARNING PFX  					   "WARNING: Multiple EXTIFs found\n"); @@ -340,14 +370,14 @@ int ssb_bus_scan(struct ssb_bus *bus,  			break;  		case SSB_DEV_MIPS:  		case SSB_DEV_MIPS_3302: -#ifdef CONFIG_BCM947XX +#ifdef CONFIG_SSB_DRIVER_MIPS  			if (bus->mipscore.dev) {  				ssb_printk(KERN_WARNING PFX  					   "WARNING: Multiple MIPS cores found\n");  				break;  			}  			bus->mipscore.dev = dev; -#endif /* CONFIG_BCM947XX */ +#endif /* CONFIG_SSB_DRIVER_MIPS */  			break;  		case SSB_DEV_PCI:  		case SSB_DEV_PCIE: @@ -363,7 +393,11 @@ int ssb_bus_scan(struct ssb_bus *bus,  		default:  			break;  		} + +		dev_i++;  	} +	bus->nr_devices = dev_i; +  	err = 0;  out:  	return err; diff --git a/target/linux/brcm47xx-2.6/files/drivers/ssb/ssb_private.h b/target/linux/brcm47xx-2.6/files/drivers/ssb/ssb_private.h index 59645f5a6..ae1fc0633 100644 --- a/target/linux/brcm47xx-2.6/files/drivers/ssb/ssb_private.h +++ b/target/linux/brcm47xx-2.6/files/drivers/ssb/ssb_private.h @@ -53,6 +53,7 @@ extern int ssb_pci_xtal(struct ssb_bus *bus, u32 what,  			int turn_on);  extern int ssb_pci_sprom_get(struct ssb_bus *bus);  extern void ssb_pci_get_boardtype(struct ssb_bus *bus); +extern void ssb_pci_exit(struct ssb_bus *bus);  extern int ssb_pci_init(struct ssb_bus *bus);  extern const struct ssb_bus_ops ssb_pci_ops; @@ -80,6 +81,9 @@ static inline int ssb_pci_sprom_get(struct ssb_bus *bus)  static inline void ssb_pci_get_boardtype(struct ssb_bus *bus)  {  } +static inline void ssb_pci_exit(struct ssb_bus *bus) +{ +}  static inline int ssb_pci_init(struct ssb_bus *bus)  {  	return 0; @@ -128,8 +132,12 @@ extern void ssb_iounmap(struct ssb_bus *ssb);  /* core.c */ -extern struct bus_type ssb_bustype;  extern u32 ssb_calc_clock_rate(u32 plltype, u32 n, u32 m); +#ifdef CONFIG_SSB_PCIHOST +extern int ssb_devices_freeze(struct ssb_bus *bus); +extern int ssb_devices_thaw(struct ssb_bus *bus); +extern struct ssb_bus * ssb_pci_dev_to_bus(struct pci_dev *pdev); +#endif /* CONFIG_SSB_PCIHOST */  /* Ceiling division helper. Divides x by y. */ diff --git a/target/linux/brcm47xx-2.6/files/drivers/usb/host/ohci-ssb.c b/target/linux/brcm47xx-2.6/files/drivers/usb/host/ohci-ssb.c new file mode 100644 index 000000000..2b3ef36b1 --- /dev/null +++ b/target/linux/brcm47xx-2.6/files/drivers/usb/host/ohci-ssb.c @@ -0,0 +1,254 @@ +/* + * Sonics Silicon Backplane + * Broadcom USB-core OHCI driver + * + * Copyright 2007 Michael Buesch <mb@bu3sch.de> + * + * Derived from the OHCI-PCI driver + * Copyright 1999 Roman Weissgaerber + * Copyright 2000-2002 David Brownell + * Copyright 1999 Linus Torvalds + * Copyright 1999 Gregory P. Smith + * + * Derived from the USBcore related parts of Broadcom-SB + * Copyright 2005 Broadcom Corporation + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include <linux/ssb/ssb.h> + + +#define SSB_OHCI_TMSLOW_HOSTMODE	(1 << 29) + +struct ssb_ohci_device { +	struct ohci_hcd ohci; /* _must_ be at the beginning. */ + +	u32 enable_flags; +}; + + +static inline +struct ssb_ohci_device * hcd_to_ssb_ohci(struct usb_hcd *hcd) +{ +	return (struct ssb_ohci_device *)(hcd->hcd_priv); +} + + +static const struct ssb_device_id ssb_ohci_table[] = { +	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV), +	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV), +	SSB_DEVTABLE_END +}; +MODULE_DEVICE_TABLE(ssb, ssb_ohci_table); + + +static int ssb_ohci_reset(struct usb_hcd *hcd) +{ +	struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd); +	struct ohci_hcd *ohci = &ohcidev->ohci; +	int err; + +	ohci_hcd_init(ohci); +	err = ohci_init(ohci); + +	return err; +} + +static int ssb_ohci_start(struct usb_hcd *hcd) +{ +	struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd); +	struct ohci_hcd *ohci = &ohcidev->ohci; +	int err; + +	err = ohci_run(ohci); +	if (err < 0) { +		ohci_err(ohci, "can't start\n"); +		ohci_stop(hcd); +	} + +	return err; +} + +#ifdef CONFIG_PM +static int ssb_ohci_hcd_suspend(struct usb_hcd *hcd, pm_message_t message) +{ +	struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd); +	struct ohci_hcd *ohci = &ohcidev->ohci; +	unsigned long flags; + +	spin_lock_irqsave(&ohci->lock, flags); + +	ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); +	ohci_readl(ohci, &ohci->regs->intrdisable); /* commit write */ + +	/* make sure snapshot being resumed re-enumerates everything */ +	if (message.event == PM_EVENT_PRETHAW) +		ohci_usb_reset(ohci); + +	clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + +	spin_unlock_irqrestore(&ohci->lock, flags); + +	return 0; +} + +static int ssb_ohci_hcd_resume(struct usb_hcd *hcd) +{ +	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); +	usb_hcd_resume_root_hub(hcd); +	return 0; +} +#endif /* CONFIG_PM */ + +static const struct hc_driver ssb_ohci_hc_driver = { +	.description		= "ssb-usb-ohci", +	.product_desc		= "SSB OHCI Controller", +	.hcd_priv_size		= sizeof(struct ssb_ohci_device), + +	.irq			= ohci_irq, +	.flags			= HCD_MEMORY | HCD_USB11, + +	.reset			= ssb_ohci_reset, +	.start			= ssb_ohci_start, +	.stop			= ohci_stop, +	.shutdown		= ohci_shutdown, + +#ifdef CONFIG_PM +	.suspend		= ssb_ohci_hcd_suspend, +	.resume			= ssb_ohci_hcd_resume, +#endif + +	.urb_enqueue		= ohci_urb_enqueue, +	.urb_dequeue		= ohci_urb_dequeue, +	.endpoint_disable	= ohci_endpoint_disable, + +	.get_frame_number	= ohci_get_frame, + +	.hub_status_data	= ohci_hub_status_data, +	.hub_control		= ohci_hub_control, +	.hub_irq_enable		= ohci_rhsc_enable, + +#ifdef CONFIG_PM +	.bus_suspend		= ohci_bus_suspend, +	.bus_resume		= ohci_bus_resume, +#endif + +	.start_port_reset	= ohci_start_port_reset, +}; + + +static void ssb_ohci_detach(struct ssb_device *dev) +{ +	struct usb_hcd *hcd = ssb_get_drvdata(dev); + +	usb_remove_hcd(hcd); +	iounmap(hcd->regs); +	usb_put_hcd(hcd); +	ssb_device_disable(dev, 0); +} + +static int ssb_ohci_attach(struct ssb_device *dev) +{ +	struct ssb_ohci_device *ohcidev; +	struct usb_hcd *hcd; +	int err = -ENOMEM; +	u32 tmp, flags = 0; + +	if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV) +		flags |= SSB_OHCI_TMSLOW_HOSTMODE; + +	ssb_device_enable(dev, flags); + +	hcd = usb_create_hcd(&ssb_ohci_hc_driver, dev->dev, +			     dev->dev->bus_id); +	if (!hcd) +		goto err_dev_disable; +	ohcidev = hcd_to_ssb_ohci(hcd); +	ohcidev->enable_flags = flags; + +	tmp = ssb_read32(dev, SSB_ADMATCH0); +	hcd->rsrc_start = ssb_admatch_base(tmp); +	hcd->rsrc_len = ssb_admatch_size(tmp); +	hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); +	if (!hcd->regs) +		goto err_put_hcd; +	err = usb_add_hcd(hcd, dev->irq, IRQF_SHARED); +	if (err) +		goto err_iounmap; + +	ssb_set_drvdata(dev, hcd); + +	return err; + +err_iounmap: +	iounmap(hcd->regs); +err_put_hcd: +	usb_put_hcd(hcd); +err_dev_disable: +	ssb_device_disable(dev, flags); +	return err; +} + +static int ssb_ohci_probe(struct ssb_device *dev, +			  const struct ssb_device_id *id) +{ +	int err; +	u16 chipid_top; + +	chipid_top = (dev->bus->chip_id & 0xFF00); +	if (chipid_top != 0x4700 && +	    chipid_top != 0x5300) { +		/* USBcores are only connected on embedded devices. */ +		return -ENODEV; +	} +	/* TODO: Probably need more checks here whether the core is connected. */ + +	if (usb_disabled()) +		return -ENODEV; + +	/* We currently always attach SSB_DEV_USB11_HOSTDEV +	 * as HOST OHCI. If we want to attach it as Client device, +	 * we must branch here and call into the (yet to +	 * be written) Client mode driver. Same for remove(). */ + +	err = ssb_ohci_attach(dev); + +	return err; +} + +static void ssb_ohci_remove(struct ssb_device *dev) +{ +	ssb_ohci_detach(dev); +} + +#ifdef CONFIG_PM +static int ssb_ohci_suspend(struct ssb_device *dev, pm_message_t state) +{ +	ssb_device_disable(dev, 0); + +	return 0; +} + +static int ssb_ohci_resume(struct ssb_device *dev) +{ +	struct usb_hcd *hcd = ssb_get_drvdata(dev); +	struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd); + +	ssb_device_enable(dev, ohcidev->enable_flags); + +	return 0; +} +#else /* CONFIG_PM */ +# define ssb_ohci_suspend	NULL +# define ssb_ohci_resume	NULL +#endif /* CONFIG_PM */ + +static struct ssb_driver ssb_ohci_driver = { +	.name		= KBUILD_MODNAME, +	.id_table	= ssb_ohci_table, +	.probe		= ssb_ohci_probe, +	.remove		= ssb_ohci_remove, +	.suspend	= ssb_ohci_suspend, +	.resume		= ssb_ohci_resume, +}; diff --git a/target/linux/brcm47xx-2.6/files/include/linux/ssb/ssb.h b/target/linux/brcm47xx-2.6/files/include/linux/ssb/ssb.h index 7fdeae71c..1ed3cbc1e 100644 --- a/target/linux/brcm47xx-2.6/files/include/linux/ssb/ssb.h +++ b/target/linux/brcm47xx-2.6/files/include/linux/ssb/ssb.h @@ -6,6 +6,9 @@  #include <linux/list.h>  #include <linux/types.h>  #include <linux/spinlock.h> +#ifdef CONFIG_SSB_PCIHOST +# include <linux/pci.h> +#endif  #include <linux/ssb/ssb_regs.h> @@ -98,6 +101,17 @@ struct ssb_sprom {  }; +struct ssb_device; +/* Lowlevel read/write operations on the device MMIO. + * Internal, don't use that outside of ssb. */ +struct ssb_bus_ops { +	u16 (*read16)(struct ssb_device *dev, u16 offset); +	u32 (*read32)(struct ssb_device *dev, u16 offset); +	void (*write16)(struct ssb_device *dev, u16 offset, u16 value); +	void (*write32)(struct ssb_device *dev, u16 offset, u32 value); +}; + +  /* Core-ID values. */  #define SSB_DEV_CHIPCOMMON	0x800  #define SSB_DEV_ILINE20		0x801 @@ -149,18 +163,37 @@ struct ssb_device_id {  #define SSB_ANY_ID		0xFFFF  #define SSB_ANY_REV		0xFF +/* Some kernel subsystems poke with dev->drvdata, so we must use the + * following ugly workaround to get from struct device to struct ssb_device */ +struct __ssb_dev_wrapper { +	struct device dev; +	struct ssb_device *sdev; +};  struct ssb_device { -	struct device dev; +	/* Having a copy of the ops pointer in each dev struct +	 * is an optimization. */ +	const struct ssb_bus_ops *ops; + +	struct device *dev;  	struct ssb_bus *bus;  	struct ssb_device_id id;  	u8 core_index;  	unsigned int irq; + +	/* Internal-only stuff follows. */  	void *drvdata;		/* Per-device data */  	void *devtypedata;	/* Per-devicetype (eg 802.11) data */  }; -#define dev_to_ssb_dev(_dev) container_of(_dev, struct ssb_device, dev) + +/* Go from struct device to struct ssb_device. */ +static inline +struct ssb_device * dev_to_ssb_dev(struct device *dev) +{ +	struct __ssb_dev_wrapper *wrap = container_of(dev, struct __ssb_dev_wrapper, dev); +	return wrap->sdev; +}  /* Device specific user data */  static inline @@ -182,13 +215,6 @@ void * ssb_get_devtypedata(struct ssb_device *dev)  	return dev->devtypedata;  } -struct ssb_bus_ops { -	u16 (*read16)(struct ssb_device *dev, u16 offset); -	u32 (*read32)(struct ssb_device *dev, u16 offset); -	void (*write16)(struct ssb_device *dev, u16 offset, u16 value); -	void (*write32)(struct ssb_device *dev, u16 offset, u32 value); -}; -  struct ssb_driver {  	const char *name; @@ -218,7 +244,6 @@ enum ssb_bustype {  	SSB_BUSTYPE_SSB,	/* This SSB bus is the system bus */  	SSB_BUSTYPE_PCI,	/* SSB is connected to PCI bus */  	SSB_BUSTYPE_PCMCIA,	/* SSB is connected to PCMCIA bus */ -	//TODO SSB_BUSTYPE_JTAG,  };  /* board_vendor */ @@ -238,12 +263,6 @@ enum ssb_bustype {  #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> @@ -269,6 +288,10 @@ struct ssb_bus {  	/* Pointer to the PCMCIA device (only if bustype == SSB_BUSTYPE_PCMCIA). */  	struct pcmcia_device *host_pcmcia; +#ifdef CONFIG_SSB_PCIHOST +	struct mutex pci_sprom_mutex; +#endif +  	/* ID information about the PCB. */  	u16 board_vendor;  	u16 board_type; @@ -328,32 +351,22 @@ void ssb_device_enable(struct ssb_device *dev, u32 core_specific_flags);  void ssb_device_disable(struct ssb_device *dev, u32 core_specific_flags); +/* Device MMIO register read/write functions. */  static inline u16 ssb_read16(struct ssb_device *dev, u16 offset)  { -	return dev->bus->ops->read16(dev, offset); +	return dev->ops->read16(dev, offset);  }  static inline u32 ssb_read32(struct ssb_device *dev, u16 offset)  { -	return dev->bus->ops->read32(dev, offset); +	return dev->ops->read32(dev, offset);  }  static inline void ssb_write16(struct ssb_device *dev, u16 offset, u16 value)  { -	dev->bus->ops->write16(dev, offset, value); +	dev->ops->write16(dev, offset, value);  }  static inline void ssb_write32(struct ssb_device *dev, u16 offset, u32 value)  { -	dev->bus->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; +	dev->ops->write32(dev, offset, value);  } @@ -366,6 +379,21 @@ extern u32 ssb_dma_translation(struct ssb_device *dev);  extern int ssb_dma_set_mask(struct ssb_device *ssb_dev, u64 mask); +#ifdef CONFIG_SSB_PCIHOST +/* PCI-host wrapper driver */ +extern int ssb_pcihost_register(struct pci_driver *driver); +static inline void ssb_pcihost_unregister(struct pci_driver *driver) +{ +	pci_unregister_driver(driver); +} +#endif /* CONFIG_SSB_PCIHOST */ + + +/* Bus-Power handling functions. */ +extern int ssb_bus_may_powerdown(struct ssb_bus *bus); +extern int ssb_bus_powerup(struct ssb_bus *bus, int dynamic_pctl); + +  /* Various helper functions */  extern u32 ssb_admatch_base(u32 adm);  extern u32 ssb_admatch_size(u32 adm); diff --git a/target/linux/brcm47xx-2.6/files/include/linux/ssb/ssb_driver_chipcommon.h b/target/linux/brcm47xx-2.6/files/include/linux/ssb/ssb_driver_chipcommon.h index e0c0e61b8..885659023 100644 --- a/target/linux/brcm47xx-2.6/files/include/linux/ssb/ssb_driver_chipcommon.h +++ b/target/linux/brcm47xx-2.6/files/include/linux/ssb/ssb_driver_chipcommon.h @@ -124,8 +124,8 @@  #define SSB_CHIPCO_GPIOOUT		0x0064  #define SSB_CHIPCO_GPIOOUTEN		0x0068  #define SSB_CHIPCO_GPIOCTL		0x006C -#define SSB_CHIPCO_GPIOINTPOL		0x0070 -#define SSB_CHIPCO_GPIOINTMASK		0x0074 +#define SSB_CHIPCO_GPIOPOL		0x0070 +#define SSB_CHIPCO_GPIOIRQ		0x0074  #define SSB_CHIPCO_WATCHDOG		0x0080  #define SSB_CHIPCO_GPIOTIMER		0x0088		/* LED powersave (corerev >= 16) */  #define  SSB_CHIPCO_GPIOTIMER_ONTIME_SHIFT	16 @@ -364,8 +364,6 @@ extern void ssb_chipcommon_init(struct ssb_chipcommon *cc);  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 chip_id, -	u32 *rate, 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, @@ -380,47 +378,6 @@ enum ssb_clkmode {  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_GPIOINTMASK, 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_GPIOINTPOL, 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); diff --git a/target/linux/brcm47xx-2.6/files/include/linux/ssb/ssb_driver_extif.h b/target/linux/brcm47xx-2.6/files/include/linux/ssb/ssb_driver_extif.h index 63add5662..278a637e8 100644 --- a/target/linux/brcm47xx-2.6/files/include/linux/ssb/ssb_driver_extif.h +++ b/target/linux/brcm47xx-2.6/files/include/linux/ssb/ssb_driver_extif.h @@ -159,37 +159,5 @@ struct ssb_extif {  #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_ */ diff --git a/target/linux/brcm47xx-2.6/files/include/linux/ssb/ssb_driver_mips.h b/target/linux/brcm47xx-2.6/files/include/linux/ssb/ssb_driver_mips.h index 61c766550..91f2373be 100644 --- a/target/linux/brcm47xx-2.6/files/include/linux/ssb/ssb_driver_mips.h +++ b/target/linux/brcm47xx-2.6/files/include/linux/ssb/ssb_driver_mips.h @@ -3,7 +3,7 @@  #ifdef __KERNEL__ -#ifdef CONFIG_BCM947XX +#ifdef CONFIG_SSB_DRIVER_MIPS  struct ssb_device; @@ -22,17 +22,16 @@ struct ssb_mipscore {  	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); -#else /* CONFIG_BCM947XX */ +#else /* CONFIG_SSB_DRIVER_MIPS */  struct ssb_mipscore {  }; @@ -42,7 +41,7 @@ void ssb_mipscore_init(struct ssb_mipscore *mcore)  {  } -#endif /* CONFIG_BCM947XX */ +#endif /* CONFIG_SSB_DRIVER_MIPS */  #endif /* __KERNEL__ */  #endif /* LINUX_SSB_MIPSCORE_H_ */ diff --git a/target/linux/brcm47xx-2.6/files/include/linux/ssb/ssb_regs.h b/target/linux/brcm47xx-2.6/files/include/linux/ssb/ssb_regs.h index 6bb40464d..e1c7ff78a 100644 --- a/target/linux/brcm47xx-2.6/files/include/linux/ssb/ssb_regs.h +++ b/target/linux/brcm47xx-2.6/files/include/linux/ssb/ssb_regs.h @@ -96,7 +96,8 @@  #define  SSB_INTVEC_ENET1	0x00000040 /* Enable interrupts for enet 1 */  #define SSB_TMSLOW		0x0F98     /* SB Target State Low */  #define  SSB_TMSLOW_RESET	0x00000001 /* Reset */ -#define  SSB_TMSLOW_REJECT	0x00000002 /* Reject */ +#define  SSB_TMSLOW_REJECT_22	0x00000002 /* Reject (Backplane rev 2.2) */ +#define  SSB_TMSLOW_REJECT_23	0x00000004 /* Reject (Backplane rev 2.3) */  #define  SSB_TMSLOW_CLOCK	0x00010000 /* Clock Enable */  #define  SSB_TMSLOW_FGC		0x00020000 /* Force Gated Clocks On */  #define  SSB_TMSLOW_PE		0x40000000 /* Power Management Enable */ diff --git a/target/linux/brcm47xx-2.6/patches/200-b44_ssb_fixup.patch b/target/linux/brcm47xx-2.6/patches/200-b44_ssb_fixup.patch new file mode 100644 index 000000000..816d7e18b --- /dev/null +++ b/target/linux/brcm47xx-2.6/patches/200-b44_ssb_fixup.patch @@ -0,0 +1,256 @@ +Index: linux-2.6.22-rc4/drivers/net/b44.c +=================================================================== +--- linux-2.6.22-rc4.orig/drivers/net/b44.c	2007-06-10 21:33:15.000000000 +0100 ++++ linux-2.6.22-rc4/drivers/net/b44.c	2007-06-10 21:33:23.000000000 +0100 +@@ -128,7 +128,7 @@ + 	                                       unsigned long offset, + 	                                       enum dma_data_direction dir) + { +-	dma_sync_single_range_for_device(&sdev->dev, dma_base, ++	dma_sync_single_range_for_device(sdev->dev, dma_base, + 		                        offset & dma_desc_align_mask, + 		                        dma_desc_sync_size, dir); + } +@@ -138,7 +138,7 @@ + 	                                    unsigned long offset, + 	                                    enum dma_data_direction dir) + { +-	dma_sync_single_range_for_cpu(&sdev->dev, dma_base, ++	dma_sync_single_range_for_cpu(sdev->dev, dma_base, + 		                     offset & dma_desc_align_mask, + 		                     dma_desc_sync_size, dir); + } +@@ -563,7 +563,7 @@ +  + 		BUG_ON(skb == NULL); +  +-		dma_unmap_single(&bp->sdev->dev, ++		dma_unmap_single(bp->sdev->dev, + 				 pci_unmap_addr(rp, mapping), + 				 skb->len, + 				 DMA_TO_DEVICE); +@@ -603,7 +603,7 @@ + 	if (skb == NULL) + 		return -ENOMEM; + 	 +-	mapping = dma_map_single(&bp->sdev->dev, skb->data, ++	mapping = dma_map_single(bp->sdev->dev, skb->data, + 				 RX_PKT_BUF_SZ, + 				 DMA_FROM_DEVICE); +  +@@ -613,18 +613,18 @@ + 		mapping + RX_PKT_BUF_SZ > DMA_30BIT_MASK) { + 		/* Sigh... */ + 		if (!dma_mapping_error(mapping)) +-			dma_unmap_single(&bp->sdev->dev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE); ++			dma_unmap_single(bp->sdev->dev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE); + 		dev_kfree_skb_any(skb); + 		skb = __dev_alloc_skb(RX_PKT_BUF_SZ,GFP_DMA); + 		if (skb == NULL) + 			return -ENOMEM; +-		mapping = dma_map_single(&bp->sdev->dev, skb->data, ++		mapping = dma_map_single(bp->sdev->dev, skb->data, + 					 RX_PKT_BUF_SZ, + 					 DMA_FROM_DEVICE); + 		if (dma_mapping_error(mapping) || + 			mapping + RX_PKT_BUF_SZ > DMA_30BIT_MASK) { + 			if (!dma_mapping_error(mapping)) +-				dma_unmap_single(&bp->sdev->dev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE); ++				dma_unmap_single(bp->sdev->dev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE); + 			dev_kfree_skb_any(skb); + 			return -ENOMEM; + 		} +@@ -702,7 +702,7 @@ + 			                    dest_idx * sizeof(dest_desc), + 			                    DMA_BIDIRECTIONAL); +  +-	dma_sync_single_for_device(&bp->sdev->dev, le32_to_cpu(src_desc->addr), ++	dma_sync_single_for_device(bp->sdev->dev, le32_to_cpu(src_desc->addr), + 				       RX_PKT_BUF_SZ, + 				       DMA_FROM_DEVICE); + } +@@ -724,7 +724,7 @@ + 		struct rx_header *rh; + 		u16 len; +  +-		dma_sync_single_for_cpu(&bp->sdev->dev, map, ++		dma_sync_single_for_cpu(bp->sdev->dev, map, + 					    RX_PKT_BUF_SZ, + 					    DMA_FROM_DEVICE); + 		rh = (struct rx_header *) skb->data; +@@ -758,7 +758,7 @@ + 			skb_size = b44_alloc_rx_skb(bp, cons, bp->rx_prod); + 			if (skb_size < 0) + 				goto drop_it; +-			dma_unmap_single(&bp->sdev->dev, map, ++			dma_unmap_single(bp->sdev->dev, map, + 					 skb_size, DMA_FROM_DEVICE); + 			/* Leave out rx_header */ + 	       	skb_put(skb, len+bp->rx_offset); +@@ -931,22 +931,22 @@ + 		goto err_out; + 	} +  +-	mapping = dma_map_single(&bp->sdev->dev, skb->data, len, DMA_TO_DEVICE); ++	mapping = dma_map_single(bp->sdev->dev, skb->data, len, DMA_TO_DEVICE); + 	if (dma_mapping_error(mapping) || mapping + len > DMA_30BIT_MASK) { + 		/* Chip can't handle DMA to/from >1GB, use bounce buffer */ + 		if (!dma_mapping_error(mapping)) +-			dma_unmap_single(&bp->sdev->dev, mapping, len, DMA_TO_DEVICE); ++			dma_unmap_single(bp->sdev->dev, mapping, len, DMA_TO_DEVICE); +  + 		bounce_skb = __dev_alloc_skb(TX_PKT_BUF_SZ, + 					     GFP_ATOMIC|GFP_DMA); + 		if (!bounce_skb) + 			goto err_out; +  +-		mapping = dma_map_single(&bp->sdev->dev, bounce_skb->data, ++		mapping = dma_map_single(bp->sdev->dev, bounce_skb->data, + 					 len, DMA_TO_DEVICE); + 		if (dma_mapping_error(mapping) || mapping + len > DMA_30BIT_MASK) { + 			if (!dma_mapping_error(mapping)) +-				dma_unmap_single(&bp->sdev->dev, mapping, ++				dma_unmap_single(bp->sdev->dev, mapping, + 					 len, DMA_TO_DEVICE); + 			dev_kfree_skb_any(bounce_skb); + 			goto err_out; +@@ -1046,7 +1046,7 @@ +  + 		if (rp->skb == NULL) + 			continue; +-		dma_unmap_single(&bp->sdev->dev, ++		dma_unmap_single(bp->sdev->dev, + 				 pci_unmap_addr(rp, mapping), + 				 RX_PKT_BUF_SZ, + 				 DMA_FROM_DEVICE); +@@ -1060,7 +1060,7 @@ +  + 		if (rp->skb == NULL) + 			continue; +-		dma_unmap_single(&bp->sdev->dev, ++		dma_unmap_single(bp->sdev->dev, + 				 pci_unmap_addr(rp, mapping), + 				 rp->skb->len, + 				 DMA_TO_DEVICE); +@@ -1085,12 +1085,12 @@ + 	memset(bp->tx_ring, 0, B44_TX_RING_BYTES); +  + 	if (bp->flags & B44_FLAG_RX_RING_HACK) +-		dma_sync_single_for_device(&bp->sdev->dev, bp->rx_ring_dma, ++		dma_sync_single_for_device(bp->sdev->dev, bp->rx_ring_dma, + 			                  DMA_TABLE_BYTES, + 			                  DMA_BIDIRECTIONAL); +  + 	if (bp->flags & B44_FLAG_TX_RING_HACK) +-		dma_sync_single_for_device(&bp->sdev->dev, bp->tx_ring_dma, ++		dma_sync_single_for_device(bp->sdev->dev, bp->tx_ring_dma, + 			                  DMA_TABLE_BYTES, + 			                  DMA_TO_DEVICE); +  +@@ -1112,24 +1112,24 @@ + 	bp->tx_buffers = NULL; + 	if (bp->rx_ring) { + 		if (bp->flags & B44_FLAG_RX_RING_HACK) { +-			dma_unmap_single(&bp->sdev->dev, bp->rx_ring_dma, ++			dma_unmap_single(bp->sdev->dev, bp->rx_ring_dma, + 					DMA_TABLE_BYTES, + 					DMA_BIDIRECTIONAL); + 			kfree(bp->rx_ring); + 		} else +-			dma_free_coherent(&bp->sdev->dev, DMA_TABLE_BYTES, ++			dma_free_coherent(bp->sdev->dev, DMA_TABLE_BYTES, + 					    bp->rx_ring, bp->rx_ring_dma); + 		bp->rx_ring = NULL; + 		bp->flags &= ~B44_FLAG_RX_RING_HACK; + 	} + 	if (bp->tx_ring) { + 		if (bp->flags & B44_FLAG_TX_RING_HACK) { +-			dma_unmap_single(&bp->sdev->dev, bp->tx_ring_dma, ++			dma_unmap_single(bp->sdev->dev, bp->tx_ring_dma, + 					DMA_TABLE_BYTES, + 					DMA_TO_DEVICE); + 			kfree(bp->tx_ring); + 		} else +-			dma_free_coherent(&bp->sdev->dev, DMA_TABLE_BYTES, ++			dma_free_coherent(bp->sdev->dev, DMA_TABLE_BYTES, + 					    bp->tx_ring, bp->tx_ring_dma); + 		bp->tx_ring = NULL; + 		bp->flags &= ~B44_FLAG_TX_RING_HACK; +@@ -1155,7 +1155,7 @@ + 		goto out_err; +  + 	size = DMA_TABLE_BYTES; +-	bp->rx_ring = dma_alloc_coherent(&bp->sdev->dev, size, &bp->rx_ring_dma, GFP_ATOMIC); ++	bp->rx_ring = dma_alloc_coherent(bp->sdev->dev, size, &bp->rx_ring_dma, GFP_ATOMIC); + 	if (!bp->rx_ring) { + 		/* Allocation may have failed due to pci_alloc_consistent + 		   insisting on use of GFP_DMA, which is more restrictive +@@ -1167,7 +1167,7 @@ + 		if (!rx_ring) + 			goto out_err; +  +-		rx_ring_dma = dma_map_single(&bp->sdev->dev, rx_ring, ++		rx_ring_dma = dma_map_single(bp->sdev->dev, rx_ring, + 			                    DMA_TABLE_BYTES, + 			                    DMA_BIDIRECTIONAL); +  +@@ -1182,7 +1182,7 @@ + 		bp->flags |= B44_FLAG_RX_RING_HACK; + 	} +  +-	bp->tx_ring = dma_alloc_coherent(&bp->sdev->dev, size, &bp->tx_ring_dma, GFP_ATOMIC); ++	bp->tx_ring = dma_alloc_coherent(bp->sdev->dev, size, &bp->tx_ring_dma, GFP_ATOMIC); + 	if (!bp->tx_ring) { + 		/* Allocation may have failed due to dma_alloc_coherent + 		   insisting on use of GFP_DMA, which is more restrictive +@@ -1194,7 +1194,7 @@ + 		if (!tx_ring) + 			goto out_err; +  +-		tx_ring_dma = dma_map_single(&bp->sdev->dev, tx_ring, ++		tx_ring_dma = dma_map_single(bp->sdev->dev, tx_ring, + 			                    DMA_TABLE_BYTES, + 			                    DMA_TO_DEVICE); +  +@@ -2314,13 +2314,13 @@ +  + 	dev = alloc_etherdev(sizeof(*bp)); + 	if (!dev) { +-		dev_err(&sdev->dev, "Etherdev alloc failed, aborting.\n"); ++		dev_err(sdev->dev, "Etherdev alloc failed, aborting.\n"); + 		err = -ENOMEM; + 		goto out; + 	} +  + 	SET_MODULE_OWNER(dev); +-	SET_NETDEV_DEV(dev,&sdev->dev); ++	SET_NETDEV_DEV(dev,sdev->dev); +  + 	/* No interesting netdevice features in this card... */ + 	dev->features |= 0; +@@ -2358,7 +2358,7 @@ +  + 	err = b44_get_invariants(bp); + 	if (err) { +-		dev_err(&sdev->dev, ++		dev_err(sdev->dev, + 			"Problem fetching invariants of chip, aborting.\n"); + 		goto err_out_free_dev; + 	} +@@ -2379,7 +2379,7 @@ +  + 	err = register_netdev(dev); + 	if (err) { +-		dev_err(&sdev->dev, "Cannot register net device, aborting.\n"); ++		dev_err(sdev->dev, "Cannot register net device, aborting.\n"); + 		goto out; + 	} +  +@@ -2458,7 +2458,6 @@ + 	rc = request_irq(dev->irq, b44_interrupt, IRQF_SHARED, dev->name, dev); + 	if (rc) { + 		printk(KERN_ERR PFX "%s: request_irq failed\n", dev->name); +-		pci_disable_device(pdev); + 		return rc; + 	} +  diff --git a/target/linux/brcm47xx-2.6/patches/205-ssb_integrate.patch b/target/linux/brcm47xx-2.6/patches/205-ssb_integrate.patch new file mode 100644 index 000000000..67882454d --- /dev/null +++ b/target/linux/brcm47xx-2.6/patches/205-ssb_integrate.patch @@ -0,0 +1,78 @@ +Index: linux-2.6.22-rc4/drivers/usb/host/Kconfig +=================================================================== +--- linux-2.6.22-rc4.orig/drivers/usb/host/Kconfig	2007-06-10 21:32:11.000000000 +0100 ++++ linux-2.6.22-rc4/drivers/usb/host/Kconfig	2007-06-10 21:33:24.000000000 +0100 +@@ -142,6 +142,19 @@ + 	  Enables support for PCI-bus plug-in USB controller cards. + 	  If unsure, say Y. +  ++config USB_OHCI_HCD_SSB ++	bool "OHCI support for the Broadcom SSB OHCI core (embedded systems only)" ++	depends on USB_OHCI_HCD && ((USB_OHCI_HCD=m && SSB) || (USB_OHCI_HCD=y && SSB=y)) && EXPERIMENTAL ++	default n ++	---help--- ++	  Support for the Sonics Silicon Backplane (SSB) attached ++	  Broadcom USB OHCI core. ++ ++	  This device is only present in some embedded devices with ++	  Broadcom based SSB bus. ++ ++	  If unsure, say N. ++ + config USB_OHCI_BIG_ENDIAN_DESC + 	bool + 	depends on USB_OHCI_HCD +Index: linux-2.6.22-rc4/drivers/usb/host/ohci-hcd.c +=================================================================== +--- linux-2.6.22-rc4.orig/drivers/usb/host/ohci-hcd.c	2007-06-10 21:32:11.000000000 +0100 ++++ linux-2.6.22-rc4/drivers/usb/host/ohci-hcd.c	2007-06-10 21:33:24.000000000 +0100 +@@ -920,11 +920,17 @@ + #define PS3_SYSTEM_BUS_DRIVER	ps3_ohci_sb_driver + #endif +  ++#ifdef CONFIG_USB_OHCI_HCD_SSB ++#include "ohci-ssb.c" ++#define SSB_OHCI_DRIVER		ssb_ohci_driver ++#endif ++ + #if	!defined(PCI_DRIVER) &&		\ + 	!defined(PLATFORM_DRIVER) &&	\ + 	!defined(OF_PLATFORM_DRIVER) &&	\ + 	!defined(SA1111_DRIVER) &&	\ +-	!defined(PS3_SYSTEM_BUS_DRIVER) ++	!defined(PS3_SYSTEM_BUS_DRIVER) && \ ++	!defined(SSB_OHCI_DRIVER) + #error "missing bus glue for ohci-hcd" + #endif +  +@@ -972,10 +978,20 @@ + 		goto error_pci; + #endif +  ++#ifdef SSB_OHCI_DRIVER ++	retval = ssb_driver_register(&SSB_OHCI_DRIVER); ++	if (retval) ++		goto error_ssb; ++#endif ++ + 	return retval; +  + 	/* Error path */ ++#ifdef SSB_OHCI_DRIVER ++ error_ssb: ++#endif + #ifdef PCI_DRIVER ++	pci_unregister_driver(&PCI_DRIVER); +  error_pci: + #endif + #ifdef SA1111_DRIVER +@@ -1001,6 +1017,9 @@ +  + static void __exit ohci_hcd_mod_exit(void) + { ++#ifdef SSB_OHCI_DRIVER ++	ssb_driver_unregister(&SSB_OHCI_DRIVER); ++#endif + #ifdef PCI_DRIVER + 	pci_unregister_driver(&PCI_DRIVER); + #endif diff --git a/target/linux/brcm47xx-2.6/patches/210-ssb_merge.patch b/target/linux/brcm47xx-2.6/patches/210-ssb_merge.patch new file mode 100644 index 000000000..21986b342 --- /dev/null +++ b/target/linux/brcm47xx-2.6/patches/210-ssb_merge.patch @@ -0,0 +1,421 @@ +Index: linux-2.6.22-rc4/drivers/ssb/driver_chipcommon.c +=================================================================== +--- linux-2.6.22-rc4.orig/drivers/ssb/driver_chipcommon.c	2007-06-10 21:32:11.000000000 +0100 ++++ linux-2.6.22-rc4/drivers/ssb/driver_chipcommon.c	2007-06-10 21:33:25.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-rc4/drivers/ssb/driver_mipscore.c +=================================================================== +--- linux-2.6.22-rc4.orig/drivers/ssb/driver_mipscore.c	2007-06-10 21:32:11.000000000 +0100 ++++ linux-2.6.22-rc4/drivers/ssb/driver_mipscore.c	2007-06-10 21:33:25.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  = ceildiv(10, ns) << SSB_PROG_WCNT_3_SHIFT; ++	tmp |= ceildiv(40, ns) << SSB_PROG_WCNT_1_SHIFT; ++	tmp |= ceildiv(120, ns); ++	extif_write32(extif, SSB_EXTIF_PROG_WAITCNT, tmp); ++ ++	/* Set programmable interface timing for external uart */ ++	tmp  = ceildiv(10, ns) << SSB_PROG_WCNT_3_SHIFT; ++	tmp |= ceildiv(20, ns) << SSB_PROG_WCNT_2_SHIFT; ++	tmp |= ceildiv(100, ns) << SSB_PROG_WCNT_1_SHIFT; ++	tmp |= ceildiv(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-rc4/drivers/ssb/driver_pcicore.c +=================================================================== +--- linux-2.6.22-rc4.orig/drivers/ssb/driver_pcicore.c	2007-06-10 21:32:11.000000000 +0100 ++++ linux-2.6.22-rc4/drivers/ssb/driver_pcicore.c	2007-06-10 21:33:25.000000000 +0100 +@@ -93,6 +93,9 @@ +  + 	/* Enable PCI bridge BAR1 prefetch and burst */ + 	pci_write_config_dword(dev, SSB_BAR1_CONTROL, 3); ++ ++	/* Make sure our latency is high enough to handle the devices behind us */ ++	pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xa8); + } + DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ssb_fixup_pcibridge); +  +@@ -110,7 +113,7 @@ +  + 	if (unlikely(pc->cardbusmode && dev > 1)) + 		goto out; +-	if (bus == 0) { ++	if (bus == 0) {//FIXME busnumber ok? + 		/* Type 0 transaction */ + 		if (unlikely(dev >= SSB_PCI_SLOT_MAX)) + 			goto out; +@@ -224,7 +227,7 @@ + 		val = *((const u32 *)buf); + 		break; + 	} +-	writel(*((const u32 *)buf), mmio); ++	writel(val, mmio); +  + 	err = 0; + unmap: +@@ -307,6 +310,8 @@ + 	udelay(150); + 	val |= SSB_PCICORE_CTL_RST; /* Deassert RST# */ + 	pcicore_write32(pc, SSB_PCICORE_CTL, val); ++	val = SSB_PCICORE_ARBCTL_INTERN; ++	pcicore_write32(pc, SSB_PCICORE_ARBCTL, val);  + 	udelay(1); +  + 	//TODO cardbus mode +@@ -336,6 +341,7 @@ + 	 * The following needs change, if we want to port hostmode + 	 * to non-MIPS platform. */ + 	set_io_port_base((unsigned long)ioremap_nocache(SSB_PCI_MEM, 0x04000000)); ++	mdelay(300); + 	register_pci_controller(&ssb_pcicore_controller); + } +  +Index: linux-2.6.22-rc4/include/linux/ssb/ssb_driver_chipcommon.h +=================================================================== +--- linux-2.6.22-rc4.orig/include/linux/ssb/ssb_driver_chipcommon.h	2007-06-10 21:32:11.000000000 +0100 ++++ linux-2.6.22-rc4/include/linux/ssb/ssb_driver_chipcommon.h	2007-06-10 21:33:25.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-rc4/include/linux/ssb/ssb_driver_extif.h +=================================================================== +--- linux-2.6.22-rc4.orig/include/linux/ssb/ssb_driver_extif.h	2007-06-10 21:32:11.000000000 +0100 ++++ linux-2.6.22-rc4/include/linux/ssb/ssb_driver_extif.h	2007-06-10 21:33:25.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-rc4/include/linux/ssb/ssb_driver_mips.h +=================================================================== +--- linux-2.6.22-rc4.orig/include/linux/ssb/ssb_driver_mips.h	2007-06-10 21:32:11.000000000 +0100 ++++ linux-2.6.22-rc4/include/linux/ssb/ssb_driver_mips.h	2007-06-10 21:33:25.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-rc4/include/linux/ssb/ssb.h +=================================================================== +--- linux-2.6.22-rc4.orig/include/linux/ssb/ssb.h	2007-06-10 21:32:11.000000000 +0100 ++++ linux-2.6.22-rc4/include/linux/ssb/ssb.h	2007-06-10 21:33:25.000000000 +0100 +@@ -263,6 +263,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> +@@ -369,6 +375,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. */  | 
