mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-10-30 21:44:27 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			1728 lines
		
	
	
		
			58 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			1728 lines
		
	
	
		
			58 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| --- a/drivers/ssb/main.c
 | |
| +++ b/drivers/ssb/main.c
 | |
| @@ -3,7 +3,7 @@
 | |
|   * Subsystem core
 | |
|   *
 | |
|   * Copyright 2005, Broadcom Corporation
 | |
| - * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
 | |
| + * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
 | |
|   *
 | |
|   * Licensed under the GNU/GPL. See COPYING for details.
 | |
|   */
 | |
| @@ -12,6 +12,7 @@
 | |
|  
 | |
|  #include <linux/delay.h>
 | |
|  #include <linux/io.h>
 | |
| +#include <linux/module.h>
 | |
|  #include <linux/ssb/ssb.h>
 | |
|  #include <linux/ssb/ssb_regs.h>
 | |
|  #include <linux/ssb/ssb_driver_gige.h>
 | |
| @@ -383,6 +384,35 @@ static int ssb_device_uevent(struct devi
 | |
|  			     ssb_dev->id.revision);
 | |
|  }
 | |
|  
 | |
| +#define ssb_config_attr(attrib, field, format_string) \
 | |
| +static ssize_t \
 | |
| +attrib##_show(struct device *dev, struct device_attribute *attr, char *buf) \
 | |
| +{ \
 | |
| +	return sprintf(buf, format_string, dev_to_ssb_dev(dev)->field); \
 | |
| +}
 | |
| +
 | |
| +ssb_config_attr(core_num, core_index, "%u\n")
 | |
| +ssb_config_attr(coreid, id.coreid, "0x%04x\n")
 | |
| +ssb_config_attr(vendor, id.vendor, "0x%04x\n")
 | |
| +ssb_config_attr(revision, id.revision, "%u\n")
 | |
| +ssb_config_attr(irq, irq, "%u\n")
 | |
| +static ssize_t
 | |
| +name_show(struct device *dev, struct device_attribute *attr, char *buf)
 | |
| +{
 | |
| +	return sprintf(buf, "%s\n",
 | |
| +		       ssb_core_name(dev_to_ssb_dev(dev)->id.coreid));
 | |
| +}
 | |
| +
 | |
| +static struct device_attribute ssb_device_attrs[] = {
 | |
| +	__ATTR_RO(name),
 | |
| +	__ATTR_RO(core_num),
 | |
| +	__ATTR_RO(coreid),
 | |
| +	__ATTR_RO(vendor),
 | |
| +	__ATTR_RO(revision),
 | |
| +	__ATTR_RO(irq),
 | |
| +	__ATTR_NULL,
 | |
| +};
 | |
| +
 | |
|  static struct bus_type ssb_bustype = {
 | |
|  	.name		= "ssb",
 | |
|  	.match		= ssb_bus_match,
 | |
| @@ -392,6 +422,7 @@ static struct bus_type ssb_bustype = {
 | |
|  	.suspend	= ssb_device_suspend,
 | |
|  	.resume		= ssb_device_resume,
 | |
|  	.uevent		= ssb_device_uevent,
 | |
| +	.dev_attrs	= ssb_device_attrs,
 | |
|  };
 | |
|  
 | |
|  static void ssb_buses_lock(void)
 | |
| @@ -527,7 +558,7 @@ error:
 | |
|  }
 | |
|  
 | |
|  /* Needs ssb_buses_lock() */
 | |
| -static int ssb_attach_queued_buses(void)
 | |
| +static int __devinit ssb_attach_queued_buses(void)
 | |
|  {
 | |
|  	struct ssb_bus *bus, *n;
 | |
|  	int err = 0;
 | |
| @@ -738,9 +769,9 @@ out:
 | |
|  	return err;
 | |
|  }
 | |
|  
 | |
| -static int ssb_bus_register(struct ssb_bus *bus,
 | |
| -			    ssb_invariants_func_t get_invariants,
 | |
| -			    unsigned long baseaddr)
 | |
| +static int __devinit ssb_bus_register(struct ssb_bus *bus,
 | |
| +				      ssb_invariants_func_t get_invariants,
 | |
| +				      unsigned long baseaddr)
 | |
|  {
 | |
|  	int err;
 | |
|  
 | |
| @@ -821,8 +852,8 @@ err_disable_xtal:
 | |
|  }
 | |
|  
 | |
|  #ifdef CONFIG_SSB_PCIHOST
 | |
| -int ssb_bus_pcibus_register(struct ssb_bus *bus,
 | |
| -			    struct pci_dev *host_pci)
 | |
| +int __devinit ssb_bus_pcibus_register(struct ssb_bus *bus,
 | |
| +				      struct pci_dev *host_pci)
 | |
|  {
 | |
|  	int err;
 | |
|  
 | |
| @@ -845,9 +876,9 @@ EXPORT_SYMBOL(ssb_bus_pcibus_register);
 | |
|  #endif /* CONFIG_SSB_PCIHOST */
 | |
|  
 | |
|  #ifdef CONFIG_SSB_PCMCIAHOST
 | |
| -int ssb_bus_pcmciabus_register(struct ssb_bus *bus,
 | |
| -			       struct pcmcia_device *pcmcia_dev,
 | |
| -			       unsigned long baseaddr)
 | |
| +int __devinit ssb_bus_pcmciabus_register(struct ssb_bus *bus,
 | |
| +					 struct pcmcia_device *pcmcia_dev,
 | |
| +					 unsigned long baseaddr)
 | |
|  {
 | |
|  	int err;
 | |
|  
 | |
| @@ -867,8 +898,9 @@ EXPORT_SYMBOL(ssb_bus_pcmciabus_register
 | |
|  #endif /* CONFIG_SSB_PCMCIAHOST */
 | |
|  
 | |
|  #ifdef CONFIG_SSB_SDIOHOST
 | |
| -int ssb_bus_sdiobus_register(struct ssb_bus *bus, struct sdio_func *func,
 | |
| -			     unsigned int quirks)
 | |
| +int __devinit ssb_bus_sdiobus_register(struct ssb_bus *bus,
 | |
| +				       struct sdio_func *func,
 | |
| +				       unsigned int quirks)
 | |
|  {
 | |
|  	int err;
 | |
|  
 | |
| @@ -888,9 +920,9 @@ int ssb_bus_sdiobus_register(struct ssb_
 | |
|  EXPORT_SYMBOL(ssb_bus_sdiobus_register);
 | |
|  #endif /* CONFIG_SSB_PCMCIAHOST */
 | |
|  
 | |
| -int ssb_bus_ssbbus_register(struct ssb_bus *bus,
 | |
| -			    unsigned long baseaddr,
 | |
| -			    ssb_invariants_func_t get_invariants)
 | |
| +int __devinit ssb_bus_ssbbus_register(struct ssb_bus *bus,
 | |
| +				      unsigned long baseaddr,
 | |
| +				      ssb_invariants_func_t get_invariants)
 | |
|  {
 | |
|  	int err;
 | |
|  
 | |
| @@ -971,8 +1003,8 @@ u32 ssb_calc_clock_rate(u32 plltype, u32
 | |
|  	switch (plltype) {
 | |
|  	case SSB_PLLTYPE_6: /* 100/200 or 120/240 only */
 | |
|  		if (m & SSB_CHIPCO_CLK_T6_MMASK)
 | |
| -			return SSB_CHIPCO_CLK_T6_M0;
 | |
| -		return SSB_CHIPCO_CLK_T6_M1;
 | |
| +			return SSB_CHIPCO_CLK_T6_M1;
 | |
| +		return SSB_CHIPCO_CLK_T6_M0;
 | |
|  	case SSB_PLLTYPE_1: /* 48Mhz base, 3 dividers */
 | |
|  	case SSB_PLLTYPE_3: /* 25Mhz, 2 dividers */
 | |
|  	case SSB_PLLTYPE_4: /* 48Mhz, 4 dividers */
 | |
| @@ -1087,23 +1119,22 @@ static u32 ssb_tmslow_reject_bitmask(str
 | |
|  {
 | |
|  	u32 rev = ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_SSBREV;
 | |
|  
 | |
| -	/* The REJECT bit changed position in TMSLOW between
 | |
| -	 * Backplane revisions. */
 | |
| +	/* The REJECT bit seems to be different for Backplane rev 2.3 */
 | |
|  	switch (rev) {
 | |
|  	case SSB_IDLOW_SSBREV_22:
 | |
| -		return SSB_TMSLOW_REJECT_22;
 | |
| +	case SSB_IDLOW_SSBREV_24:
 | |
| +	case SSB_IDLOW_SSBREV_26:
 | |
| +		return SSB_TMSLOW_REJECT;
 | |
|  	case SSB_IDLOW_SSBREV_23:
 | |
|  		return SSB_TMSLOW_REJECT_23;
 | |
| -	case SSB_IDLOW_SSBREV_24:     /* TODO - find the proper REJECT bits */
 | |
| -	case SSB_IDLOW_SSBREV_25:     /* same here */
 | |
| -	case SSB_IDLOW_SSBREV_26:     /* same here */
 | |
| +	case SSB_IDLOW_SSBREV_25:     /* TODO - find the proper REJECT bit */
 | |
|  	case SSB_IDLOW_SSBREV_27:     /* same here */
 | |
| -		return SSB_TMSLOW_REJECT_23;	/* this is a guess */
 | |
| +		return SSB_TMSLOW_REJECT;	/* this is a guess */
 | |
|  	default:
 | |
|  		printk(KERN_INFO "ssb: Backplane Revision 0x%.8X\n", rev);
 | |
|  		WARN_ON(1);
 | |
|  	}
 | |
| -	return (SSB_TMSLOW_REJECT_22 | SSB_TMSLOW_REJECT_23);
 | |
| +	return (SSB_TMSLOW_REJECT | SSB_TMSLOW_REJECT_23);
 | |
|  }
 | |
|  
 | |
|  int ssb_device_is_enabled(struct ssb_device *dev)
 | |
| @@ -1162,10 +1193,10 @@ void ssb_device_enable(struct ssb_device
 | |
|  }
 | |
|  EXPORT_SYMBOL(ssb_device_enable);
 | |
|  
 | |
| -/* Wait for a bit in a register to get set or unset.
 | |
| +/* Wait for bitmask in a register to get set or cleared.
 | |
|   * timeout is in units of ten-microseconds */
 | |
| -static int ssb_wait_bit(struct ssb_device *dev, u16 reg, u32 bitmask,
 | |
| -			int timeout, int set)
 | |
| +static int ssb_wait_bits(struct ssb_device *dev, u16 reg, u32 bitmask,
 | |
| +			 int timeout, int set)
 | |
|  {
 | |
|  	int i;
 | |
|  	u32 val;
 | |
| @@ -1173,7 +1204,7 @@ static int ssb_wait_bit(struct ssb_devic
 | |
|  	for (i = 0; i < timeout; i++) {
 | |
|  		val = ssb_read32(dev, reg);
 | |
|  		if (set) {
 | |
| -			if (val & bitmask)
 | |
| +			if ((val & bitmask) == bitmask)
 | |
|  				return 0;
 | |
|  		} else {
 | |
|  			if (!(val & bitmask))
 | |
| @@ -1190,20 +1221,38 @@ static int ssb_wait_bit(struct ssb_devic
 | |
|  
 | |
|  void ssb_device_disable(struct ssb_device *dev, u32 core_specific_flags)
 | |
|  {
 | |
| -	u32 reject;
 | |
| +	u32 reject, val;
 | |
|  
 | |
|  	if (ssb_read32(dev, SSB_TMSLOW) & SSB_TMSLOW_RESET)
 | |
|  		return;
 | |
|  
 | |
|  	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 |
 | |
| -		    reject | SSB_TMSLOW_RESET |
 | |
| -		    core_specific_flags);
 | |
| -	ssb_flush_tmslow(dev);
 | |
| +
 | |
| +	if (ssb_read32(dev, SSB_TMSLOW) & SSB_TMSLOW_CLOCK) {
 | |
| +		ssb_write32(dev, SSB_TMSLOW, reject | SSB_TMSLOW_CLOCK);
 | |
| +		ssb_wait_bits(dev, SSB_TMSLOW, reject, 1000, 1);
 | |
| +		ssb_wait_bits(dev, SSB_TMSHIGH, SSB_TMSHIGH_BUSY, 1000, 0);
 | |
| +
 | |
| +		if (ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_INITIATOR) {
 | |
| +			val = ssb_read32(dev, SSB_IMSTATE);
 | |
| +			val |= SSB_IMSTATE_REJECT;
 | |
| +			ssb_write32(dev, SSB_IMSTATE, val);
 | |
| +			ssb_wait_bits(dev, SSB_IMSTATE, SSB_IMSTATE_BUSY, 1000,
 | |
| +				      0);
 | |
| +		}
 | |
| +
 | |
| +		ssb_write32(dev, SSB_TMSLOW,
 | |
| +			SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK |
 | |
| +			reject | SSB_TMSLOW_RESET |
 | |
| +			core_specific_flags);
 | |
| +		ssb_flush_tmslow(dev);
 | |
| +
 | |
| +		if (ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_INITIATOR) {
 | |
| +			val = ssb_read32(dev, SSB_IMSTATE);
 | |
| +			val &= ~SSB_IMSTATE_REJECT;
 | |
| +			ssb_write32(dev, SSB_IMSTATE, val);
 | |
| +		}
 | |
| +	}
 | |
|  
 | |
|  	ssb_write32(dev, SSB_TMSLOW,
 | |
|  		    reject | SSB_TMSLOW_RESET |
 | |
| @@ -1212,13 +1261,34 @@ void ssb_device_disable(struct ssb_devic
 | |
|  }
 | |
|  EXPORT_SYMBOL(ssb_device_disable);
 | |
|  
 | |
| +/* Some chipsets need routing known for PCIe and 64-bit DMA */
 | |
| +static bool ssb_dma_translation_special_bit(struct ssb_device *dev)
 | |
| +{
 | |
| +	u16 chip_id = dev->bus->chip_id;
 | |
| +
 | |
| +	if (dev->id.coreid == SSB_DEV_80211) {
 | |
| +		return (chip_id == 0x4322 || chip_id == 43221 ||
 | |
| +			chip_id == 43231 || chip_id == 43222);
 | |
| +	}
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
|  u32 ssb_dma_translation(struct ssb_device *dev)
 | |
|  {
 | |
|  	switch (dev->bus->bustype) {
 | |
|  	case SSB_BUSTYPE_SSB:
 | |
|  		return 0;
 | |
|  	case SSB_BUSTYPE_PCI:
 | |
| -		return SSB_PCI_DMA;
 | |
| +		if (pci_is_pcie(dev->bus->host_pci) &&
 | |
| +		    ssb_read32(dev, SSB_TMSHIGH) & SSB_TMSHIGH_DMA64) {
 | |
| +			return SSB_PCIE_DMA_H32;
 | |
| +		} else {
 | |
| +			if (ssb_dma_translation_special_bit(dev))
 | |
| +				return SSB_PCIE_DMA_H32;
 | |
| +			else
 | |
| +				return SSB_PCI_DMA;
 | |
| +		}
 | |
|  	default:
 | |
|  		__ssb_dma_not_implemented(dev);
 | |
|  	}
 | |
| @@ -1261,20 +1331,20 @@ EXPORT_SYMBOL(ssb_bus_may_powerdown);
 | |
|  
 | |
|  int ssb_bus_powerup(struct ssb_bus *bus, bool 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);
 | |
|  
 | |
|  #ifdef CONFIG_SSB_DEBUG
 | |
|  	bus->powered_up = 1;
 | |
|  #endif
 | |
| +
 | |
| +	mode = dynamic_pctl ? SSB_CLKMODE_DYNAMIC : SSB_CLKMODE_FAST;
 | |
| +	ssb_chipco_set_clockmode(&bus->chipco, mode);
 | |
| +
 | |
|  	return 0;
 | |
|  error:
 | |
|  	ssb_printk(KERN_ERR PFX "Bus powerup failed\n");
 | |
| @@ -1282,6 +1352,37 @@ error:
 | |
|  }
 | |
|  EXPORT_SYMBOL(ssb_bus_powerup);
 | |
|  
 | |
| +static void ssb_broadcast_value(struct ssb_device *dev,
 | |
| +				u32 address, u32 data)
 | |
| +{
 | |
| +#ifdef CONFIG_SSB_DRIVER_PCICORE
 | |
| +	/* This is used for both, PCI and ChipCommon core, so be careful. */
 | |
| +	BUILD_BUG_ON(SSB_PCICORE_BCAST_ADDR != SSB_CHIPCO_BCAST_ADDR);
 | |
| +	BUILD_BUG_ON(SSB_PCICORE_BCAST_DATA != SSB_CHIPCO_BCAST_DATA);
 | |
| +#endif
 | |
| +
 | |
| +	ssb_write32(dev, SSB_CHIPCO_BCAST_ADDR, address);
 | |
| +	ssb_read32(dev, SSB_CHIPCO_BCAST_ADDR); /* flush */
 | |
| +	ssb_write32(dev, SSB_CHIPCO_BCAST_DATA, data);
 | |
| +	ssb_read32(dev, SSB_CHIPCO_BCAST_DATA); /* flush */
 | |
| +}
 | |
| +
 | |
| +void ssb_commit_settings(struct ssb_bus *bus)
 | |
| +{
 | |
| +	struct ssb_device *dev;
 | |
| +
 | |
| +#ifdef CONFIG_SSB_DRIVER_PCICORE
 | |
| +	dev = bus->chipco.dev ? bus->chipco.dev : bus->pcicore.dev;
 | |
| +#else
 | |
| +	dev = bus->chipco.dev;
 | |
| +#endif
 | |
| +	if (WARN_ON(!dev))
 | |
| +		return;
 | |
| +	/* This forces an update of the cached registers. */
 | |
| +	ssb_broadcast_value(dev, 0xFD8, 0);
 | |
| +}
 | |
| +EXPORT_SYMBOL(ssb_commit_settings);
 | |
| +
 | |
|  u32 ssb_admatch_base(u32 adm)
 | |
|  {
 | |
|  	u32 base = 0;
 | |
| --- a/drivers/ssb/pci.c
 | |
| +++ b/drivers/ssb/pci.c
 | |
| @@ -1,7 +1,7 @@
 | |
|  /*
 | |
|   * Sonics Silicon Backplane PCI-Hostbus related functions.
 | |
|   *
 | |
| - * Copyright (C) 2005-2006 Michael Buesch <mb@bu3sch.de>
 | |
| + * Copyright (C) 2005-2006 Michael Buesch <m@bues.ch>
 | |
|   * 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>
 | |
| @@ -406,6 +406,46 @@ static void sprom_extract_r123(struct ss
 | |
|  	out->antenna_gain.ghz5.a3 = gain;
 | |
|  }
 | |
|  
 | |
| +/* Revs 4 5 and 8 have partially shared layout */
 | |
| +static void sprom_extract_r458(struct ssb_sprom *out, const u16 *in)
 | |
| +{
 | |
| +	SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01,
 | |
| +	     SSB_SPROM4_TXPID2G0, SSB_SPROM4_TXPID2G0_SHIFT);
 | |
| +	SPEX(txpid2g[1], SSB_SPROM4_TXPID2G01,
 | |
| +	     SSB_SPROM4_TXPID2G1, SSB_SPROM4_TXPID2G1_SHIFT);
 | |
| +	SPEX(txpid2g[2], SSB_SPROM4_TXPID2G23,
 | |
| +	     SSB_SPROM4_TXPID2G2, SSB_SPROM4_TXPID2G2_SHIFT);
 | |
| +	SPEX(txpid2g[3], SSB_SPROM4_TXPID2G23,
 | |
| +	     SSB_SPROM4_TXPID2G3, SSB_SPROM4_TXPID2G3_SHIFT);
 | |
| +
 | |
| +	SPEX(txpid5gl[0], SSB_SPROM4_TXPID5GL01,
 | |
| +	     SSB_SPROM4_TXPID5GL0, SSB_SPROM4_TXPID5GL0_SHIFT);
 | |
| +	SPEX(txpid5gl[1], SSB_SPROM4_TXPID5GL01,
 | |
| +	     SSB_SPROM4_TXPID5GL1, SSB_SPROM4_TXPID5GL1_SHIFT);
 | |
| +	SPEX(txpid5gl[2], SSB_SPROM4_TXPID5GL23,
 | |
| +	     SSB_SPROM4_TXPID5GL2, SSB_SPROM4_TXPID5GL2_SHIFT);
 | |
| +	SPEX(txpid5gl[3], SSB_SPROM4_TXPID5GL23,
 | |
| +	     SSB_SPROM4_TXPID5GL3, SSB_SPROM4_TXPID5GL3_SHIFT);
 | |
| +
 | |
| +	SPEX(txpid5g[0], SSB_SPROM4_TXPID5G01,
 | |
| +	     SSB_SPROM4_TXPID5G0, SSB_SPROM4_TXPID5G0_SHIFT);
 | |
| +	SPEX(txpid5g[1], SSB_SPROM4_TXPID5G01,
 | |
| +	     SSB_SPROM4_TXPID5G1, SSB_SPROM4_TXPID5G1_SHIFT);
 | |
| +	SPEX(txpid5g[2], SSB_SPROM4_TXPID5G23,
 | |
| +	     SSB_SPROM4_TXPID5G2, SSB_SPROM4_TXPID5G2_SHIFT);
 | |
| +	SPEX(txpid5g[3], SSB_SPROM4_TXPID5G23,
 | |
| +	     SSB_SPROM4_TXPID5G3, SSB_SPROM4_TXPID5G3_SHIFT);
 | |
| +
 | |
| +	SPEX(txpid5gh[0], SSB_SPROM4_TXPID5GH01,
 | |
| +	     SSB_SPROM4_TXPID5GH0, SSB_SPROM4_TXPID5GH0_SHIFT);
 | |
| +	SPEX(txpid5gh[1], SSB_SPROM4_TXPID5GH01,
 | |
| +	     SSB_SPROM4_TXPID5GH1, SSB_SPROM4_TXPID5GH1_SHIFT);
 | |
| +	SPEX(txpid5gh[2], SSB_SPROM4_TXPID5GH23,
 | |
| +	     SSB_SPROM4_TXPID5GH2, SSB_SPROM4_TXPID5GH2_SHIFT);
 | |
| +	SPEX(txpid5gh[3], SSB_SPROM4_TXPID5GH23,
 | |
| +	     SSB_SPROM4_TXPID5GH3, SSB_SPROM4_TXPID5GH3_SHIFT);
 | |
| +}
 | |
| +
 | |
|  static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in)
 | |
|  {
 | |
|  	int i;
 | |
| @@ -428,10 +468,14 @@ static void sprom_extract_r45(struct ssb
 | |
|  		SPEX(country_code, SSB_SPROM4_CCODE, 0xFFFF, 0);
 | |
|  		SPEX(boardflags_lo, SSB_SPROM4_BFLLO, 0xFFFF, 0);
 | |
|  		SPEX(boardflags_hi, SSB_SPROM4_BFLHI, 0xFFFF, 0);
 | |
| +		SPEX(boardflags2_lo, SSB_SPROM4_BFL2LO, 0xFFFF, 0);
 | |
| +		SPEX(boardflags2_hi, SSB_SPROM4_BFL2HI, 0xFFFF, 0);
 | |
|  	} else {
 | |
|  		SPEX(country_code, SSB_SPROM5_CCODE, 0xFFFF, 0);
 | |
|  		SPEX(boardflags_lo, SSB_SPROM5_BFLLO, 0xFFFF, 0);
 | |
|  		SPEX(boardflags_hi, SSB_SPROM5_BFLHI, 0xFFFF, 0);
 | |
| +		SPEX(boardflags2_lo, SSB_SPROM5_BFL2LO, 0xFFFF, 0);
 | |
| +		SPEX(boardflags2_hi, SSB_SPROM5_BFL2HI, 0xFFFF, 0);
 | |
|  	}
 | |
|  	SPEX(ant_available_a, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_A,
 | |
|  	     SSB_SPROM4_ANTAVAIL_A_SHIFT);
 | |
| @@ -471,6 +515,8 @@ static void sprom_extract_r45(struct ssb
 | |
|  	memcpy(&out->antenna_gain.ghz5, &out->antenna_gain.ghz24,
 | |
|  	       sizeof(out->antenna_gain.ghz5));
 | |
|  
 | |
| +	sprom_extract_r458(out, in);
 | |
| +
 | |
|  	/* TODO - get remaining rev 4 stuff needed */
 | |
|  }
 | |
|  
 | |
| @@ -561,6 +607,31 @@ static void sprom_extract_r8(struct ssb_
 | |
|  	memcpy(&out->antenna_gain.ghz5, &out->antenna_gain.ghz24,
 | |
|  	       sizeof(out->antenna_gain.ghz5));
 | |
|  
 | |
| +	/* Extract FEM info */
 | |
| +	SPEX(fem.ghz2.tssipos, SSB_SPROM8_FEM2G,
 | |
| +		SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT);
 | |
| +	SPEX(fem.ghz2.extpa_gain, SSB_SPROM8_FEM2G,
 | |
| +		SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
 | |
| +	SPEX(fem.ghz2.pdet_range, SSB_SPROM8_FEM2G,
 | |
| +		SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT);
 | |
| +	SPEX(fem.ghz2.tr_iso, SSB_SPROM8_FEM2G,
 | |
| +		SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT);
 | |
| +	SPEX(fem.ghz2.antswlut, SSB_SPROM8_FEM2G,
 | |
| +		SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT);
 | |
| +
 | |
| +	SPEX(fem.ghz5.tssipos, SSB_SPROM8_FEM5G,
 | |
| +		SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT);
 | |
| +	SPEX(fem.ghz5.extpa_gain, SSB_SPROM8_FEM5G,
 | |
| +		SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
 | |
| +	SPEX(fem.ghz5.pdet_range, SSB_SPROM8_FEM5G,
 | |
| +		SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT);
 | |
| +	SPEX(fem.ghz5.tr_iso, SSB_SPROM8_FEM5G,
 | |
| +		SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT);
 | |
| +	SPEX(fem.ghz5.antswlut, SSB_SPROM8_FEM5G,
 | |
| +		SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT);
 | |
| +
 | |
| +	sprom_extract_r458(out, in);
 | |
| +
 | |
|  	/* TODO - get remaining rev 8 stuff needed */
 | |
|  }
 | |
|  
 | |
| @@ -573,37 +644,34 @@ static int sprom_extract(struct ssb_bus
 | |
|  	ssb_dprintk(KERN_DEBUG PFX "SPROM revision %d detected.\n", out->revision);
 | |
|  	memset(out->et0mac, 0xFF, 6);		/* preset et0 and et1 mac */
 | |
|  	memset(out->et1mac, 0xFF, 6);
 | |
| +
 | |
|  	if ((bus->chip_id & 0xFF00) == 0x4400) {
 | |
|  		/* Workaround: The BCM44XX chip has a stupid revision
 | |
|  		 * number stored in the SPROM.
 | |
|  		 * Always extract r1. */
 | |
|  		out->revision = 1;
 | |
| +		ssb_dprintk(KERN_DEBUG PFX "SPROM treated as revision %d\n", out->revision);
 | |
| +	}
 | |
| +
 | |
| +	switch (out->revision) {
 | |
| +	case 1:
 | |
| +	case 2:
 | |
| +	case 3:
 | |
|  		sprom_extract_r123(out, in);
 | |
| -	} else if (bus->chip_id == 0x4321) {
 | |
| -		/* the BCM4328 has a chipid == 0x4321 and a rev 4 SPROM */
 | |
| -		out->revision = 4;
 | |
| +		break;
 | |
| +	case 4:
 | |
| +	case 5:
 | |
|  		sprom_extract_r45(out, in);
 | |
| -	} else {
 | |
| -		switch (out->revision) {
 | |
| -		case 1:
 | |
| -		case 2:
 | |
| -		case 3:
 | |
| -			sprom_extract_r123(out, in);
 | |
| -			break;
 | |
| -		case 4:
 | |
| -		case 5:
 | |
| -			sprom_extract_r45(out, in);
 | |
| -			break;
 | |
| -		case 8:
 | |
| -			sprom_extract_r8(out, in);
 | |
| -			break;
 | |
| -		default:
 | |
| -			ssb_printk(KERN_WARNING PFX "Unsupported SPROM"
 | |
| -				   "  revision %d detected. Will extract"
 | |
| -				   " v1\n", out->revision);
 | |
| -			out->revision = 1;
 | |
| -			sprom_extract_r123(out, in);
 | |
| -		}
 | |
| +		break;
 | |
| +	case 8:
 | |
| +		sprom_extract_r8(out, in);
 | |
| +		break;
 | |
| +	default:
 | |
| +		ssb_printk(KERN_WARNING PFX "Unsupported SPROM"
 | |
| +			   " revision %d detected. Will extract"
 | |
| +			   " v1\n", out->revision);
 | |
| +		out->revision = 1;
 | |
| +		sprom_extract_r123(out, in);
 | |
|  	}
 | |
|  
 | |
|  	if (out->boardflags_lo == 0xFFFF)
 | |
| @@ -617,15 +685,14 @@ static int sprom_extract(struct ssb_bus
 | |
|  static int ssb_pci_sprom_get(struct ssb_bus *bus,
 | |
|  			     struct ssb_sprom *sprom)
 | |
|  {
 | |
| -	const struct ssb_sprom *fallback;
 | |
| -	int err = -ENOMEM;
 | |
| +	int err;
 | |
|  	u16 *buf;
 | |
|  
 | |
|  	if (!ssb_is_sprom_available(bus)) {
 | |
|  		ssb_printk(KERN_ERR PFX "No SPROM available!\n");
 | |
|  		return -ENODEV;
 | |
|  	}
 | |
| -	if (bus->chipco.dev) {	/* can be unavailible! */
 | |
| +	if (bus->chipco.dev) {	/* can be unavailable! */
 | |
|  		/*
 | |
|  		 * get SPROM offset: SSB_SPROM_BASE1 except for
 | |
|  		 * chipcommon rev >= 31 or chip ID is 0x4312 and
 | |
| @@ -645,7 +712,7 @@ static int ssb_pci_sprom_get(struct ssb_
 | |
|  
 | |
|  	buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL);
 | |
|  	if (!buf)
 | |
| -		goto out;
 | |
| +		return -ENOMEM;
 | |
|  	bus->sprom_size = SSB_SPROMSIZE_WORDS_R123;
 | |
|  	sprom_do_read(bus, buf);
 | |
|  	err = sprom_check_crc(buf, bus->sprom_size);
 | |
| @@ -655,17 +722,24 @@ static int ssb_pci_sprom_get(struct ssb_
 | |
|  		buf = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
 | |
|  			      GFP_KERNEL);
 | |
|  		if (!buf)
 | |
| -			goto out;
 | |
| +			return -ENOMEM;
 | |
|  		bus->sprom_size = SSB_SPROMSIZE_WORDS_R4;
 | |
|  		sprom_do_read(bus, buf);
 | |
|  		err = sprom_check_crc(buf, bus->sprom_size);
 | |
|  		if (err) {
 | |
|  			/* All CRC attempts failed.
 | |
|  			 * Maybe there is no SPROM on the device?
 | |
| -			 * If we have a fallback, use that. */
 | |
| -			fallback = ssb_get_fallback_sprom();
 | |
| -			if (fallback) {
 | |
| -				memcpy(sprom, fallback, sizeof(*sprom));
 | |
| +			 * Now we ask the arch code if there is some sprom
 | |
| +			 * available for this device in some other storage */
 | |
| +			err = ssb_fill_sprom_with_fallback(bus, sprom);
 | |
| +			if (err) {
 | |
| +				ssb_printk(KERN_WARNING PFX "WARNING: Using"
 | |
| +					   " fallback SPROM failed (err %d)\n",
 | |
| +					   err);
 | |
| +			} else {
 | |
| +				ssb_dprintk(KERN_DEBUG PFX "Using SPROM"
 | |
| +					    " revision %d provided by"
 | |
| +					    " platform.\n", sprom->revision);
 | |
|  				err = 0;
 | |
|  				goto out_free;
 | |
|  			}
 | |
| @@ -677,19 +751,15 @@ static int ssb_pci_sprom_get(struct ssb_
 | |
|  
 | |
|  out_free:
 | |
|  	kfree(buf);
 | |
| -out:
 | |
|  	return err;
 | |
|  }
 | |
|  
 | |
|  static void ssb_pci_get_boardinfo(struct ssb_bus *bus,
 | |
|  				  struct ssb_boardinfo *bi)
 | |
|  {
 | |
| -	pci_read_config_word(bus->host_pci, PCI_SUBSYSTEM_VENDOR_ID,
 | |
| -			     &bi->vendor);
 | |
| -	pci_read_config_word(bus->host_pci, PCI_SUBSYSTEM_ID,
 | |
| -			     &bi->type);
 | |
| -	pci_read_config_word(bus->host_pci, PCI_REVISION_ID,
 | |
| -			     &bi->rev);
 | |
| +	bi->vendor = bus->host_pci->subsystem_vendor;
 | |
| +	bi->type = bus->host_pci->subsystem_device;
 | |
| +	bi->rev = bus->host_pci->revision;
 | |
|  }
 | |
|  
 | |
|  int ssb_pci_get_invariants(struct ssb_bus *bus,
 | |
| --- a/drivers/ssb/pcihost_wrapper.c
 | |
| +++ b/drivers/ssb/pcihost_wrapper.c
 | |
| @@ -6,7 +6,7 @@
 | |
|   * 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>
 | |
| + * Copyright (c) 2005-2007 Michael Buesch <m@bues.ch>
 | |
|   *
 | |
|   * Licensed under the GNU/GPL. See COPYING for details.
 | |
|   */
 | |
| @@ -53,12 +53,13 @@ static int ssb_pcihost_resume(struct pci
 | |
|  # define ssb_pcihost_resume	NULL
 | |
|  #endif /* CONFIG_PM */
 | |
|  
 | |
| -static int ssb_pcihost_probe(struct pci_dev *dev,
 | |
| -			     const struct pci_device_id *id)
 | |
| +static int __devinit ssb_pcihost_probe(struct pci_dev *dev,
 | |
| +				       const struct pci_device_id *id)
 | |
|  {
 | |
|  	struct ssb_bus *ssb;
 | |
|  	int err = -ENOMEM;
 | |
|  	const char *name;
 | |
| +	u32 val;
 | |
|  
 | |
|  	ssb = kzalloc(sizeof(*ssb), GFP_KERNEL);
 | |
|  	if (!ssb)
 | |
| @@ -74,6 +75,12 @@ static int ssb_pcihost_probe(struct pci_
 | |
|  		goto err_pci_disable;
 | |
|  	pci_set_master(dev);
 | |
|  
 | |
| +	/* Disable the RETRY_TIMEOUT register (0x41) to keep
 | |
| +	 * PCI Tx retries from interfering with C3 CPU state */
 | |
| +	pci_read_config_dword(dev, 0x40, &val);
 | |
| +	if ((val & 0x0000ff00) != 0)
 | |
| +		pci_write_config_dword(dev, 0x40, val & 0xffff00ff);
 | |
| +
 | |
|  	err = ssb_bus_pcibus_register(ssb, dev);
 | |
|  	if (err)
 | |
|  		goto err_pci_release_regions;
 | |
| @@ -103,7 +110,7 @@ static void ssb_pcihost_remove(struct pc
 | |
|  	pci_set_drvdata(dev, NULL);
 | |
|  }
 | |
|  
 | |
| -int ssb_pcihost_register(struct pci_driver *driver)
 | |
| +int __devinit ssb_pcihost_register(struct pci_driver *driver)
 | |
|  {
 | |
|  	driver->probe = ssb_pcihost_probe;
 | |
|  	driver->remove = ssb_pcihost_remove;
 | |
| --- a/drivers/ssb/scan.c
 | |
| +++ b/drivers/ssb/scan.c
 | |
| @@ -2,7 +2,7 @@
 | |
|   * Sonics Silicon Backplane
 | |
|   * Bus scanning
 | |
|   *
 | |
| - * Copyright (C) 2005-2007 Michael Buesch <mb@bu3sch.de>
 | |
| + * Copyright (C) 2005-2007 Michael Buesch <m@bues.ch>
 | |
|   * 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>
 | |
| @@ -258,7 +258,10 @@ static int we_support_multiple_80211_cor
 | |
|  #ifdef CONFIG_SSB_PCIHOST
 | |
|  	if (bus->bustype == SSB_BUSTYPE_PCI) {
 | |
|  		if (bus->host_pci->vendor == PCI_VENDOR_ID_BROADCOM &&
 | |
| -		    bus->host_pci->device == 0x4324)
 | |
| +		    ((bus->host_pci->device == 0x4313) ||
 | |
| +		     (bus->host_pci->device == 0x431A) ||
 | |
| +		     (bus->host_pci->device == 0x4321) ||
 | |
| +		     (bus->host_pci->device == 0x4324)))
 | |
|  			return 1;
 | |
|  	}
 | |
|  #endif /* CONFIG_SSB_PCIHOST */
 | |
| @@ -307,8 +310,7 @@ int ssb_bus_scan(struct ssb_bus *bus,
 | |
|  	} else {
 | |
|  		if (bus->bustype == SSB_BUSTYPE_PCI) {
 | |
|  			bus->chip_id = pcidev_to_chipid(bus->host_pci);
 | |
| -			pci_read_config_word(bus->host_pci, PCI_REVISION_ID,
 | |
| -					     &bus->chip_rev);
 | |
| +			bus->chip_rev = bus->host_pci->revision;
 | |
|  			bus->chip_package = 0;
 | |
|  		} else {
 | |
|  			bus->chip_id = 0x4710;
 | |
| @@ -405,10 +407,10 @@ int ssb_bus_scan(struct ssb_bus *bus,
 | |
|  				/* Ignore PCI cores on PCI-E cards.
 | |
|  				 * Ignore PCI-E cores on PCI cards. */
 | |
|  				if (dev->id.coreid == SSB_DEV_PCI) {
 | |
| -					if (bus->host_pci->is_pcie)
 | |
| +					if (pci_is_pcie(bus->host_pci))
 | |
|  						continue;
 | |
|  				} else {
 | |
| -					if (!bus->host_pci->is_pcie)
 | |
| +					if (!pci_is_pcie(bus->host_pci))
 | |
|  						continue;
 | |
|  				}
 | |
|  			}
 | |
| @@ -420,6 +422,16 @@ int ssb_bus_scan(struct ssb_bus *bus,
 | |
|  			bus->pcicore.dev = dev;
 | |
|  #endif /* CONFIG_SSB_DRIVER_PCICORE */
 | |
|  			break;
 | |
| +		case SSB_DEV_ETHERNET:
 | |
| +			if (bus->bustype == SSB_BUSTYPE_PCI) {
 | |
| +				if (bus->host_pci->vendor == PCI_VENDOR_ID_BROADCOM &&
 | |
| +				    (bus->host_pci->device & 0xFF00) == 0x4300) {
 | |
| +					/* This is a dangling ethernet core on a
 | |
| +					 * wireless device. Ignore it. */
 | |
| +					continue;
 | |
| +				}
 | |
| +			}
 | |
| +			break;
 | |
|  		default:
 | |
|  			break;
 | |
|  		}
 | |
| --- a/include/linux/ssb/ssb.h
 | |
| +++ b/include/linux/ssb/ssb.h
 | |
| @@ -25,8 +25,10 @@ struct ssb_sprom {
 | |
|  	u8 et1phyaddr;		/* MII address for enet1 */
 | |
|  	u8 et0mdcport;		/* MDIO for enet0 */
 | |
|  	u8 et1mdcport;		/* MDIO for enet1 */
 | |
| -	u8 board_rev;		/* Board revision number from SPROM. */
 | |
| +	u16 board_rev;		/* Board revision number from SPROM. */
 | |
|  	u8 country_code;	/* Country Code */
 | |
| +	u16 leddc_on_time;	/* LED Powersave Duty Cycle On Count */
 | |
| +	u16 leddc_off_time;	/* LED Powersave Duty Cycle Off Count */
 | |
|  	u8 ant_available_a;	/* 2GHz antenna available bits (up to 4) */
 | |
|  	u8 ant_available_bg;	/* 5GHz antenna available bits (up to 4) */
 | |
|  	u16 pa0b0;
 | |
| @@ -55,6 +57,10 @@ struct ssb_sprom {
 | |
|  	u8 tri5gl;		/* 5.2GHz TX isolation */
 | |
|  	u8 tri5g;		/* 5.3GHz TX isolation */
 | |
|  	u8 tri5gh;		/* 5.8GHz TX isolation */
 | |
| +	u8 txpid2g[4];		/* 2GHz TX power index */
 | |
| +	u8 txpid5gl[4];		/* 4.9 - 5.1GHz TX power index */
 | |
| +	u8 txpid5g[4];		/* 5.1 - 5.5GHz TX power index */
 | |
| +	u8 txpid5gh[4];		/* 5.5 - ...GHz TX power index */
 | |
|  	u8 rxpo2g;		/* 2GHz RX power offset */
 | |
|  	u8 rxpo5g;		/* 5GHz RX power offset */
 | |
|  	u8 rssisav2g;		/* 2GHz RSSI params */
 | |
| @@ -88,6 +94,15 @@ struct ssb_sprom {
 | |
|  		} ghz5;		/* 5GHz band */
 | |
|  	} antenna_gain;
 | |
|  
 | |
| +	struct {
 | |
| +		struct {
 | |
| +			u8 tssipos, extpa_gain, pdet_range, tr_iso, antswlut;
 | |
| +		} ghz2;
 | |
| +		struct {
 | |
| +			u8 tssipos, extpa_gain, pdet_range, tr_iso, antswlut;
 | |
| +		} ghz5;
 | |
| +	} fem;
 | |
| +
 | |
|  	/* TODO - add any parameters needed from rev 2, 3, 4, 5 or 8 SPROMs */
 | |
|  };
 | |
|  
 | |
| @@ -95,7 +110,7 @@ struct ssb_sprom {
 | |
|  struct ssb_boardinfo {
 | |
|  	u16 vendor;
 | |
|  	u16 type;
 | |
| -	u16 rev;
 | |
| +	u8  rev;
 | |
|  };
 | |
|  
 | |
|  
 | |
| @@ -225,10 +240,9 @@ struct ssb_driver {
 | |
|  #define drv_to_ssb_drv(_drv) container_of(_drv, struct ssb_driver, drv)
 | |
|  
 | |
|  extern int __ssb_driver_register(struct ssb_driver *drv, struct module *owner);
 | |
| -static inline int ssb_driver_register(struct ssb_driver *drv)
 | |
| -{
 | |
| -	return __ssb_driver_register(drv, THIS_MODULE);
 | |
| -}
 | |
| +#define ssb_driver_register(drv) \
 | |
| +	__ssb_driver_register(drv, THIS_MODULE)
 | |
| +
 | |
|  extern void ssb_driver_unregister(struct ssb_driver *drv);
 | |
|  
 | |
|  
 | |
| @@ -304,7 +318,7 @@ struct ssb_bus {
 | |
|  
 | |
|  	/* ID information about the Chip. */
 | |
|  	u16 chip_id;
 | |
| -	u16 chip_rev;
 | |
| +	u8 chip_rev;
 | |
|  	u16 sprom_offset;
 | |
|  	u16 sprom_size;		/* number of words in sprom */
 | |
|  	u8 chip_package;
 | |
| @@ -400,7 +414,9 @@ extern bool ssb_is_sprom_available(struc
 | |
|  
 | |
|  /* Set a fallback SPROM.
 | |
|   * See kdoc at the function definition for complete documentation. */
 | |
| -extern int ssb_arch_set_fallback_sprom(const struct ssb_sprom *sprom);
 | |
| +extern int ssb_arch_register_fallback_sprom(
 | |
| +		int (*sprom_callback)(struct ssb_bus *bus,
 | |
| +		struct ssb_sprom *out));
 | |
|  
 | |
|  /* Suspend a SSB bus.
 | |
|   * Call this from the parent bus suspend routine. */
 | |
| @@ -514,6 +530,7 @@ extern int ssb_bus_may_powerdown(struct
 | |
|   * Otherwise static always-on powercontrol will be used. */
 | |
|  extern int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl);
 | |
|  
 | |
| +extern void ssb_commit_settings(struct ssb_bus *bus);
 | |
|  
 | |
|  /* Various helper functions */
 | |
|  extern u32 ssb_admatch_base(u32 adm);
 | |
| --- a/include/linux/ssb/ssb_regs.h
 | |
| +++ b/include/linux/ssb/ssb_regs.h
 | |
| @@ -85,6 +85,8 @@
 | |
|  #define  SSB_IMSTATE_AP_RSV	0x00000030 /* Reserved */
 | |
|  #define  SSB_IMSTATE_IBE	0x00020000 /* In Band Error */
 | |
|  #define  SSB_IMSTATE_TO		0x00040000 /* Timeout */
 | |
| +#define  SSB_IMSTATE_BUSY	0x01800000 /* Busy (Backplane rev >= 2.3 only) */
 | |
| +#define  SSB_IMSTATE_REJECT	0x02000000 /* Reject (Backplane rev >= 2.3 only) */
 | |
|  #define SSB_INTVEC		0x0F94     /* SB Interrupt Mask */
 | |
|  #define  SSB_INTVEC_PCI		0x00000001 /* Enable interrupts for PCI */
 | |
|  #define  SSB_INTVEC_ENET0	0x00000002 /* Enable interrupts for enet 0 */
 | |
| @@ -95,9 +97,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_22	0x00000002 /* Reject (Backplane rev 2.2) */
 | |
| +#define  SSB_TMSLOW_REJECT	0x00000002 /* Reject (Standard Backplane) */
 | |
|  #define  SSB_TMSLOW_REJECT_23	0x00000004 /* Reject (Backplane rev 2.3) */
 | |
| -#define  SSB_TMSLOW_PHYCLK	0x00000010 /* MAC PHY Clock Control Enable */
 | |
|  #define  SSB_TMSLOW_CLOCK	0x00010000 /* Clock Enable */
 | |
|  #define  SSB_TMSLOW_FGC		0x00020000 /* Force Gated Clocks On */
 | |
|  #define  SSB_TMSLOW_PE		0x40000000 /* Power Management Enable */
 | |
| @@ -268,6 +269,8 @@
 | |
|  /* SPROM Revision 4 */
 | |
|  #define SSB_SPROM4_BFLLO		0x0044	/* Boardflags (low 16 bits) */
 | |
|  #define SSB_SPROM4_BFLHI		0x0046  /* Board Flags Hi */
 | |
| +#define SSB_SPROM4_BFL2LO		0x0048	/* Board flags 2 (low 16 bits) */
 | |
| +#define SSB_SPROM4_BFL2HI		0x004A	/* Board flags 2 Hi */
 | |
|  #define SSB_SPROM4_IL0MAC		0x004C	/* 6 byte MAC address for a/b/g/n */
 | |
|  #define SSB_SPROM4_CCODE		0x0052	/* Country Code (2 bytes) */
 | |
|  #define SSB_SPROM4_GPIOA		0x0056	/* Gen. Purpose IO # 0 and 1 */
 | |
| @@ -299,6 +302,46 @@
 | |
|  #define  SSB_SPROM4_AGAIN2_SHIFT	0
 | |
|  #define  SSB_SPROM4_AGAIN3		0xFF00	/* Antenna 3 */
 | |
|  #define  SSB_SPROM4_AGAIN3_SHIFT	8
 | |
| +#define SSB_SPROM4_TXPID2G01		0x0062 	/* TX Power Index 2GHz */
 | |
| +#define  SSB_SPROM4_TXPID2G0		0x00FF
 | |
| +#define  SSB_SPROM4_TXPID2G0_SHIFT	0
 | |
| +#define  SSB_SPROM4_TXPID2G1		0xFF00
 | |
| +#define  SSB_SPROM4_TXPID2G1_SHIFT	8
 | |
| +#define SSB_SPROM4_TXPID2G23		0x0064 	/* TX Power Index 2GHz */
 | |
| +#define  SSB_SPROM4_TXPID2G2		0x00FF
 | |
| +#define  SSB_SPROM4_TXPID2G2_SHIFT	0
 | |
| +#define  SSB_SPROM4_TXPID2G3		0xFF00
 | |
| +#define  SSB_SPROM4_TXPID2G3_SHIFT	8
 | |
| +#define SSB_SPROM4_TXPID5G01		0x0066 	/* TX Power Index 5GHz middle subband */
 | |
| +#define  SSB_SPROM4_TXPID5G0		0x00FF
 | |
| +#define  SSB_SPROM4_TXPID5G0_SHIFT	0
 | |
| +#define  SSB_SPROM4_TXPID5G1		0xFF00
 | |
| +#define  SSB_SPROM4_TXPID5G1_SHIFT	8
 | |
| +#define SSB_SPROM4_TXPID5G23		0x0068 	/* TX Power Index 5GHz middle subband */
 | |
| +#define  SSB_SPROM4_TXPID5G2		0x00FF
 | |
| +#define  SSB_SPROM4_TXPID5G2_SHIFT	0
 | |
| +#define  SSB_SPROM4_TXPID5G3		0xFF00
 | |
| +#define  SSB_SPROM4_TXPID5G3_SHIFT	8
 | |
| +#define SSB_SPROM4_TXPID5GL01		0x006A 	/* TX Power Index 5GHz low subband */
 | |
| +#define  SSB_SPROM4_TXPID5GL0		0x00FF
 | |
| +#define  SSB_SPROM4_TXPID5GL0_SHIFT	0
 | |
| +#define  SSB_SPROM4_TXPID5GL1		0xFF00
 | |
| +#define  SSB_SPROM4_TXPID5GL1_SHIFT	8
 | |
| +#define SSB_SPROM4_TXPID5GL23		0x006C 	/* TX Power Index 5GHz low subband */
 | |
| +#define  SSB_SPROM4_TXPID5GL2		0x00FF
 | |
| +#define  SSB_SPROM4_TXPID5GL2_SHIFT	0
 | |
| +#define  SSB_SPROM4_TXPID5GL3		0xFF00
 | |
| +#define  SSB_SPROM4_TXPID5GL3_SHIFT	8
 | |
| +#define SSB_SPROM4_TXPID5GH01		0x006E 	/* TX Power Index 5GHz high subband */
 | |
| +#define  SSB_SPROM4_TXPID5GH0		0x00FF
 | |
| +#define  SSB_SPROM4_TXPID5GH0_SHIFT	0
 | |
| +#define  SSB_SPROM4_TXPID5GH1		0xFF00
 | |
| +#define  SSB_SPROM4_TXPID5GH1_SHIFT	8
 | |
| +#define SSB_SPROM4_TXPID5GH23		0x0070 	/* TX Power Index 5GHz high subband */
 | |
| +#define  SSB_SPROM4_TXPID5GH2		0x00FF
 | |
| +#define  SSB_SPROM4_TXPID5GH2_SHIFT	0
 | |
| +#define  SSB_SPROM4_TXPID5GH3		0xFF00
 | |
| +#define  SSB_SPROM4_TXPID5GH3_SHIFT	8
 | |
|  #define SSB_SPROM4_MAXP_BG		0x0080  /* Max Power BG in path 1 */
 | |
|  #define  SSB_SPROM4_MAXP_BG_MASK	0x00FF  /* Mask for Max Power BG */
 | |
|  #define  SSB_SPROM4_ITSSI_BG		0xFF00	/* Mask for path 1 itssi_bg */
 | |
| @@ -318,6 +361,8 @@
 | |
|  #define SSB_SPROM5_CCODE		0x0044	/* Country Code (2 bytes) */
 | |
|  #define SSB_SPROM5_BFLLO		0x004A	/* Boardflags (low 16 bits) */
 | |
|  #define SSB_SPROM5_BFLHI		0x004C  /* Board Flags Hi */
 | |
| +#define SSB_SPROM5_BFL2LO		0x004E	/* Board flags 2 (low 16 bits) */
 | |
| +#define SSB_SPROM5_BFL2HI		0x0050	/* Board flags 2 Hi */
 | |
|  #define SSB_SPROM5_IL0MAC		0x0052	/* 6 byte MAC address for a/b/g/n */
 | |
|  #define SSB_SPROM5_GPIOA		0x0076	/* Gen. Purpose IO # 0 and 1 */
 | |
|  #define  SSB_SPROM5_GPIOA_P0		0x00FF	/* Pin 0 */
 | |
| @@ -387,6 +432,23 @@
 | |
|  #define  SSB_SPROM8_RXPO2G		0x00FF	/* 2GHz RX power offset */
 | |
|  #define  SSB_SPROM8_RXPO5G		0xFF00	/* 5GHz RX power offset */
 | |
|  #define  SSB_SPROM8_RXPO5G_SHIFT	8
 | |
| +#define SSB_SPROM8_FEM2G		0x00AE
 | |
| +#define SSB_SPROM8_FEM5G		0x00B0
 | |
| +#define  SSB_SROM8_FEM_TSSIPOS		0x0001
 | |
| +#define  SSB_SROM8_FEM_TSSIPOS_SHIFT	0
 | |
| +#define  SSB_SROM8_FEM_EXTPA_GAIN	0x0006
 | |
| +#define  SSB_SROM8_FEM_EXTPA_GAIN_SHIFT	1
 | |
| +#define  SSB_SROM8_FEM_PDET_RANGE	0x00F8
 | |
| +#define  SSB_SROM8_FEM_PDET_RANGE_SHIFT	3
 | |
| +#define  SSB_SROM8_FEM_TR_ISO		0x0700
 | |
| +#define  SSB_SROM8_FEM_TR_ISO_SHIFT	8
 | |
| +#define  SSB_SROM8_FEM_ANTSWLUT		0xF800
 | |
| +#define  SSB_SROM8_FEM_ANTSWLUT_SHIFT	11
 | |
| +#define SSB_SPROM8_THERMAL		0x00B2
 | |
| +#define SSB_SPROM8_MPWR_RAWTS		0x00B4
 | |
| +#define SSB_SPROM8_TS_SLP_OPT_CORRX	0x00B6
 | |
| +#define SSB_SPROM8_FOC_HWIQ_IQSWP	0x00B8
 | |
| +#define SSB_SPROM8_PHYCAL_TEMPDELTA	0x00BA
 | |
|  #define SSB_SPROM8_MAXP_BG		0x00C0  /* Max Power 2GHz in path 1 */
 | |
|  #define  SSB_SPROM8_MAXP_BG_MASK	0x00FF  /* Mask for Max Power 2GHz */
 | |
|  #define  SSB_SPROM8_ITSSI_BG		0xFF00	/* Mask for path 1 itssi_bg */
 | |
| @@ -417,6 +479,46 @@
 | |
|  #define SSB_SPROM8_OFDM5GLPO		0x014A	/* 5.2GHz OFDM power offset */
 | |
|  #define SSB_SPROM8_OFDM5GHPO		0x014E	/* 5.8GHz OFDM power offset */
 | |
|  
 | |
| +/* Values for boardflags_lo read from SPROM */
 | |
| +#define SSB_BFL_BTCOEXIST		0x0001	/* implements Bluetooth coexistance */
 | |
| +#define SSB_BFL_PACTRL			0x0002	/* GPIO 9 controlling the PA */
 | |
| +#define SSB_BFL_AIRLINEMODE		0x0004	/* implements GPIO 13 radio disable indication */
 | |
| +#define SSB_BFL_RSSI			0x0008	/* software calculates nrssi slope. */
 | |
| +#define SSB_BFL_ENETSPI			0x0010	/* has ephy roboswitch spi */
 | |
| +#define SSB_BFL_XTAL_NOSLOW		0x0020	/* no slow clock available */
 | |
| +#define SSB_BFL_CCKHIPWR		0x0040	/* can do high power CCK transmission */
 | |
| +#define SSB_BFL_ENETADM			0x0080	/* has ADMtek switch */
 | |
| +#define SSB_BFL_ENETVLAN		0x0100	/* can do vlan */
 | |
| +#define SSB_BFL_AFTERBURNER		0x0200	/* supports Afterburner mode */
 | |
| +#define SSB_BFL_NOPCI			0x0400	/* board leaves PCI floating */
 | |
| +#define SSB_BFL_FEM			0x0800	/* supports the Front End Module */
 | |
| +#define SSB_BFL_EXTLNA			0x1000	/* has an external LNA */
 | |
| +#define SSB_BFL_HGPA			0x2000	/* had high gain PA */
 | |
| +#define SSB_BFL_BTCMOD			0x4000	/* BFL_BTCOEXIST is given in alternate GPIOs */
 | |
| +#define SSB_BFL_ALTIQ			0x8000	/* alternate I/Q settings */
 | |
| +
 | |
| +/* Values for boardflags_hi read from SPROM */
 | |
| +#define SSB_BFH_NOPA			0x0001	/* has no PA */
 | |
| +#define SSB_BFH_RSSIINV			0x0002	/* RSSI uses positive slope (not TSSI) */
 | |
| +#define SSB_BFH_PAREF			0x0004	/* uses the PARef LDO */
 | |
| +#define SSB_BFH_3TSWITCH		0x0008	/* uses a triple throw switch shared with bluetooth */
 | |
| +#define SSB_BFH_PHASESHIFT		0x0010	/* can support phase shifter */
 | |
| +#define SSB_BFH_BUCKBOOST		0x0020	/* has buck/booster */
 | |
| +#define SSB_BFH_FEM_BT			0x0040	/* has FEM and switch to share antenna with bluetooth */
 | |
| +
 | |
| +/* Values for boardflags2_lo read from SPROM */
 | |
| +#define SSB_BFL2_RXBB_INT_REG_DIS	0x0001	/* external RX BB regulator present */
 | |
| +#define SSB_BFL2_APLL_WAR		0x0002	/* alternative A-band PLL settings implemented */
 | |
| +#define SSB_BFL2_TXPWRCTRL_EN 		0x0004	/* permits enabling TX Power Control */
 | |
| +#define SSB_BFL2_2X4_DIV		0x0008	/* 2x4 diversity switch */
 | |
| +#define SSB_BFL2_5G_PWRGAIN		0x0010	/* supports 5G band power gain */
 | |
| +#define SSB_BFL2_PCIEWAR_OVR		0x0020	/* overrides ASPM and Clkreq settings */
 | |
| +#define SSB_BFL2_CAESERS_BRD		0x0040	/* is Caesers board (unused) */
 | |
| +#define SSB_BFL2_BTC3WIRE		0x0080	/* used 3-wire bluetooth coexist */
 | |
| +#define SSB_BFL2_SKWRKFEM_BRD		0x0100	/* 4321mcm93 uses Skyworks FEM */
 | |
| +#define SSB_BFL2_SPUR_WAR		0x0200	/* has a workaround for clock-harmonic spurs */
 | |
| +#define SSB_BFL2_GPLL_WAR		0x0400	/* altenative G-band PLL settings implemented */
 | |
| +
 | |
|  /* Values for SSB_SPROM1_BINF_CCODE */
 | |
|  enum {
 | |
|  	SSB_SPROM1CCODE_WORLD = 0,
 | |
| --- a/drivers/ssb/driver_chipcommon.c
 | |
| +++ b/drivers/ssb/driver_chipcommon.c
 | |
| @@ -3,7 +3,7 @@
 | |
|   * Broadcom ChipCommon core driver
 | |
|   *
 | |
|   * Copyright 2005, Broadcom Corporation
 | |
| - * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
 | |
| + * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
 | |
|   *
 | |
|   * Licensed under the GNU/GPL. See COPYING for details.
 | |
|   */
 | |
| @@ -46,40 +46,66 @@ void ssb_chipco_set_clockmode(struct ssb
 | |
|  	if (!ccdev)
 | |
|  		return;
 | |
|  	bus = ccdev->bus;
 | |
| +
 | |
| +	/* We support SLOW only on 6..9 */
 | |
| +	if (ccdev->id.revision >= 10 && mode == SSB_CLKMODE_SLOW)
 | |
| +		mode = SSB_CLKMODE_DYNAMIC;
 | |
| +
 | |
| +	if (cc->capabilities & SSB_CHIPCO_CAP_PMU)
 | |
| +		return; /* PMU controls clockmode, separated function needed */
 | |
| +	SSB_WARN_ON(ccdev->id.revision >= 20);
 | |
| +
 | |
|  	/* chipcommon cores prior to rev6 don't support dynamic clock control */
 | |
|  	if (ccdev->id.revision < 6)
 | |
|  		return;
 | |
| -	/* chipcommon cores rev10 are a whole new ball game */
 | |
| +
 | |
| +	/* ChipCommon cores rev10+ need testing */
 | |
|  	if (ccdev->id.revision >= 10)
 | |
|  		return;
 | |
| +
 | |
|  	if (!(cc->capabilities & SSB_CHIPCO_CAP_PCTL))
 | |
|  		return;
 | |
|  
 | |
|  	switch (mode) {
 | |
| -	case SSB_CLKMODE_SLOW:
 | |
| +	case SSB_CLKMODE_SLOW: /* For revs 6..9 only */
 | |
|  		tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL);
 | |
|  		tmp |= SSB_CHIPCO_SLOWCLKCTL_FSLOW;
 | |
|  		chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp);
 | |
|  		break;
 | |
|  	case SSB_CLKMODE_FAST:
 | |
| -		ssb_pci_xtal(bus, SSB_GPIO_XTAL, 1); /* Force crystal on */
 | |
| -		tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL);
 | |
| -		tmp &= ~SSB_CHIPCO_SLOWCLKCTL_FSLOW;
 | |
| -		tmp |= SSB_CHIPCO_SLOWCLKCTL_IPLL;
 | |
| -		chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp);
 | |
| +		if (ccdev->id.revision < 10) {
 | |
| +			ssb_pci_xtal(bus, SSB_GPIO_XTAL, 1); /* Force crystal on */
 | |
| +			tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL);
 | |
| +			tmp &= ~SSB_CHIPCO_SLOWCLKCTL_FSLOW;
 | |
| +			tmp |= SSB_CHIPCO_SLOWCLKCTL_IPLL;
 | |
| +			chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp);
 | |
| +		} else {
 | |
| +			chipco_write32(cc, SSB_CHIPCO_SYSCLKCTL,
 | |
| +				(chipco_read32(cc, SSB_CHIPCO_SYSCLKCTL) |
 | |
| +				 SSB_CHIPCO_SYSCLKCTL_FORCEHT));
 | |
| +			/* udelay(150); TODO: not available in early init */
 | |
| +		}
 | |
|  		break;
 | |
|  	case SSB_CLKMODE_DYNAMIC:
 | |
| -		tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL);
 | |
| -		tmp &= ~SSB_CHIPCO_SLOWCLKCTL_FSLOW;
 | |
| -		tmp &= ~SSB_CHIPCO_SLOWCLKCTL_IPLL;
 | |
| -		tmp &= ~SSB_CHIPCO_SLOWCLKCTL_ENXTAL;
 | |
| -		if ((tmp & SSB_CHIPCO_SLOWCLKCTL_SRC) != SSB_CHIPCO_SLOWCLKCTL_SRC_XTAL)
 | |
| -			tmp |= SSB_CHIPCO_SLOWCLKCTL_ENXTAL;
 | |
| -		chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp);
 | |
| -
 | |
| -		/* for dynamic control, we have to release our xtal_pu "force on" */
 | |
| -		if (tmp & SSB_CHIPCO_SLOWCLKCTL_ENXTAL)
 | |
| -			ssb_pci_xtal(bus, SSB_GPIO_XTAL, 0);
 | |
| +		if (ccdev->id.revision < 10) {
 | |
| +			tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL);
 | |
| +			tmp &= ~SSB_CHIPCO_SLOWCLKCTL_FSLOW;
 | |
| +			tmp &= ~SSB_CHIPCO_SLOWCLKCTL_IPLL;
 | |
| +			tmp &= ~SSB_CHIPCO_SLOWCLKCTL_ENXTAL;
 | |
| +			if ((tmp & SSB_CHIPCO_SLOWCLKCTL_SRC) !=
 | |
| +			    SSB_CHIPCO_SLOWCLKCTL_SRC_XTAL)
 | |
| +				tmp |= SSB_CHIPCO_SLOWCLKCTL_ENXTAL;
 | |
| +			chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp);
 | |
| +
 | |
| +			/* For dynamic control, we have to release our xtal_pu
 | |
| +			 * "force on" */
 | |
| +			if (tmp & SSB_CHIPCO_SLOWCLKCTL_ENXTAL)
 | |
| +				ssb_pci_xtal(bus, SSB_GPIO_XTAL, 0);
 | |
| +		} else {
 | |
| +			chipco_write32(cc, SSB_CHIPCO_SYSCLKCTL,
 | |
| +				(chipco_read32(cc, SSB_CHIPCO_SYSCLKCTL) &
 | |
| +				 ~SSB_CHIPCO_SYSCLKCTL_FORCEHT));
 | |
| +		}
 | |
|  		break;
 | |
|  	default:
 | |
|  		SSB_WARN_ON(1);
 | |
| @@ -260,6 +286,12 @@ void ssb_chipcommon_init(struct ssb_chip
 | |
|  	if (cc->dev->id.revision >= 11)
 | |
|  		cc->status = chipco_read32(cc, SSB_CHIPCO_CHIPSTAT);
 | |
|  	ssb_dprintk(KERN_INFO PFX "chipcommon status is 0x%x\n", cc->status);
 | |
| +
 | |
| +	if (cc->dev->id.revision >= 20) {
 | |
| +		chipco_write32(cc, SSB_CHIPCO_GPIOPULLUP, 0);
 | |
| +		chipco_write32(cc, SSB_CHIPCO_GPIOPULLDOWN, 0);
 | |
| +	}
 | |
| +
 | |
|  	ssb_pmu_init(cc);
 | |
|  	chipco_powercontrol_init(cc);
 | |
|  	ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST);
 | |
| --- a/drivers/ssb/driver_chipcommon_pmu.c
 | |
| +++ b/drivers/ssb/driver_chipcommon_pmu.c
 | |
| @@ -2,7 +2,7 @@
 | |
|   * Sonics Silicon Backplane
 | |
|   * Broadcom ChipCommon Power Management Unit driver
 | |
|   *
 | |
| - * Copyright 2009, Michael Buesch <mb@bu3sch.de>
 | |
| + * Copyright 2009, Michael Buesch <m@bues.ch>
 | |
|   * Copyright 2007, Broadcom Corporation
 | |
|   *
 | |
|   * Licensed under the GNU/GPL. See COPYING for details.
 | |
| @@ -417,12 +417,14 @@ static void ssb_pmu_resources_init(struc
 | |
|  	u32 min_msk = 0, max_msk = 0;
 | |
|  	unsigned int i;
 | |
|  	const struct pmu_res_updown_tab_entry *updown_tab = NULL;
 | |
| -	unsigned int updown_tab_size;
 | |
| +	unsigned int updown_tab_size = 0;
 | |
|  	const struct pmu_res_depend_tab_entry *depend_tab = NULL;
 | |
| -	unsigned int depend_tab_size;
 | |
| +	unsigned int depend_tab_size = 0;
 | |
|  
 | |
|  	switch (bus->chip_id) {
 | |
|  	case 0x4312:
 | |
| +		 min_msk = 0xCBB;
 | |
| +		 break;
 | |
|  	case 0x4322:
 | |
|  		/* We keep the default settings:
 | |
|  		 * min_msk = 0xCBB
 | |
| --- a/drivers/ssb/driver_gige.c
 | |
| +++ b/drivers/ssb/driver_gige.c
 | |
| @@ -3,7 +3,7 @@
 | |
|   * Broadcom Gigabit Ethernet core driver
 | |
|   *
 | |
|   * Copyright 2008, Broadcom Corporation
 | |
| - * Copyright 2008, Michael Buesch <mb@bu3sch.de>
 | |
| + * Copyright 2008, Michael Buesch <m@bues.ch>
 | |
|   *
 | |
|   * Licensed under the GNU/GPL. See COPYING for details.
 | |
|   */
 | |
| @@ -106,8 +106,9 @@ void gige_pcicfg_write32(struct ssb_gige
 | |
|  	gige_write32(dev, SSB_GIGE_PCICFG + offset, value);
 | |
|  }
 | |
|  
 | |
| -static int ssb_gige_pci_read_config(struct pci_bus *bus, unsigned int devfn,
 | |
| -				    int reg, int size, u32 *val)
 | |
| +static int __devinit ssb_gige_pci_read_config(struct pci_bus *bus,
 | |
| +					      unsigned int devfn, int reg,
 | |
| +					      int size, u32 *val)
 | |
|  {
 | |
|  	struct ssb_gige *dev = container_of(bus->ops, struct ssb_gige, pci_ops);
 | |
|  	unsigned long flags;
 | |
| @@ -136,8 +137,9 @@ static int ssb_gige_pci_read_config(stru
 | |
|  	return PCIBIOS_SUCCESSFUL;
 | |
|  }
 | |
|  
 | |
| -static int ssb_gige_pci_write_config(struct pci_bus *bus, unsigned int devfn,
 | |
| -				     int reg, int size, u32 val)
 | |
| +static int __devinit ssb_gige_pci_write_config(struct pci_bus *bus,
 | |
| +					       unsigned int devfn, int reg,
 | |
| +					       int size, u32 val)
 | |
|  {
 | |
|  	struct ssb_gige *dev = container_of(bus->ops, struct ssb_gige, pci_ops);
 | |
|  	unsigned long flags;
 | |
| @@ -166,7 +168,8 @@ static int ssb_gige_pci_write_config(str
 | |
|  	return PCIBIOS_SUCCESSFUL;
 | |
|  }
 | |
|  
 | |
| -static int ssb_gige_probe(struct ssb_device *sdev, const struct ssb_device_id *id)
 | |
| +static int __devinit ssb_gige_probe(struct ssb_device *sdev,
 | |
| +				    const struct ssb_device_id *id)
 | |
|  {
 | |
|  	struct ssb_gige *dev;
 | |
|  	u32 base, tmslow, tmshigh;
 | |
| --- a/drivers/ssb/driver_pcicore.c
 | |
| +++ b/drivers/ssb/driver_pcicore.c
 | |
| @@ -3,7 +3,7 @@
 | |
|   * Broadcom PCI-core driver
 | |
|   *
 | |
|   * Copyright 2005, Broadcom Corporation
 | |
| - * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
 | |
| + * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
 | |
|   *
 | |
|   * Licensed under the GNU/GPL. See COPYING for details.
 | |
|   */
 | |
| @@ -15,6 +15,11 @@
 | |
|  
 | |
|  #include "ssb_private.h"
 | |
|  
 | |
| +static u32 ssb_pcie_read(struct ssb_pcicore *pc, u32 address);
 | |
| +static void ssb_pcie_write(struct ssb_pcicore *pc, u32 address, u32 data);
 | |
| +static u16 ssb_pcie_mdio_read(struct ssb_pcicore *pc, u8 device, u8 address);
 | |
| +static void ssb_pcie_mdio_write(struct ssb_pcicore *pc, u8 device,
 | |
| +				u8 address, u16 data);
 | |
|  
 | |
|  static inline
 | |
|  u32 pcicore_read32(struct ssb_pcicore *pc, u16 offset)
 | |
| @@ -309,7 +314,7 @@ int ssb_pcicore_pcibios_map_irq(const st
 | |
|  	return ssb_mips_irq(extpci_core->dev) + 2;
 | |
|  }
 | |
|  
 | |
| -static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc)
 | |
| +static void __devinit ssb_pcicore_init_hostmode(struct ssb_pcicore *pc)
 | |
|  {
 | |
|  	u32 val;
 | |
|  
 | |
| @@ -374,7 +379,7 @@ static void ssb_pcicore_init_hostmode(st
 | |
|  	register_pci_controller(&ssb_pcicore_controller);
 | |
|  }
 | |
|  
 | |
| -static int pcicore_is_in_hostmode(struct ssb_pcicore *pc)
 | |
| +static int __devinit pcicore_is_in_hostmode(struct ssb_pcicore *pc)
 | |
|  {
 | |
|  	struct ssb_bus *bus = pc->dev->bus;
 | |
|  	u16 chipid_top;
 | |
| @@ -403,25 +408,137 @@ static int pcicore_is_in_hostmode(struct
 | |
|  }
 | |
|  #endif /* CONFIG_SSB_PCICORE_HOSTMODE */
 | |
|  
 | |
| +/**************************************************
 | |
| + * Workarounds.
 | |
| + **************************************************/
 | |
| +
 | |
| +static void __devinit ssb_pcicore_fix_sprom_core_index(struct ssb_pcicore *pc)
 | |
| +{
 | |
| +	u16 tmp = pcicore_read16(pc, SSB_PCICORE_SPROM(0));
 | |
| +	if (((tmp & 0xF000) >> 12) != pc->dev->core_index) {
 | |
| +		tmp &= ~0xF000;
 | |
| +		tmp |= (pc->dev->core_index << 12);
 | |
| +		pcicore_write16(pc, SSB_PCICORE_SPROM(0), tmp);
 | |
| +	}
 | |
| +}
 | |
| +
 | |
| +static u8 ssb_pcicore_polarity_workaround(struct ssb_pcicore *pc)
 | |
| +{
 | |
| +	return (ssb_pcie_read(pc, 0x204) & 0x10) ? 0xC0 : 0x80;
 | |
| +}
 | |
| +
 | |
| +static void ssb_pcicore_serdes_workaround(struct ssb_pcicore *pc)
 | |
| +{
 | |
| +	const u8 serdes_pll_device = 0x1D;
 | |
| +	const u8 serdes_rx_device = 0x1F;
 | |
| +	u16 tmp;
 | |
| +
 | |
| +	ssb_pcie_mdio_write(pc, serdes_rx_device, 1 /* Control */,
 | |
| +			    ssb_pcicore_polarity_workaround(pc));
 | |
| +	tmp = ssb_pcie_mdio_read(pc, serdes_pll_device, 1 /* Control */);
 | |
| +	if (tmp & 0x4000)
 | |
| +		ssb_pcie_mdio_write(pc, serdes_pll_device, 1, tmp & ~0x4000);
 | |
| +}
 | |
| +
 | |
| +static void ssb_pcicore_pci_setup_workarounds(struct ssb_pcicore *pc)
 | |
| +{
 | |
| +	struct ssb_device *pdev = pc->dev;
 | |
| +	struct ssb_bus *bus = pdev->bus;
 | |
| +	u32 tmp;
 | |
| +
 | |
| +	tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2);
 | |
| +	tmp |= SSB_PCICORE_SBTOPCI_PREF;
 | |
| +	tmp |= SSB_PCICORE_SBTOPCI_BURST;
 | |
| +	pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp);
 | |
| +
 | |
| +	if (pdev->id.revision < 5) {
 | |
| +		tmp = ssb_read32(pdev, SSB_IMCFGLO);
 | |
| +		tmp &= ~SSB_IMCFGLO_SERTO;
 | |
| +		tmp |= 2;
 | |
| +		tmp &= ~SSB_IMCFGLO_REQTO;
 | |
| +		tmp |= 3 << SSB_IMCFGLO_REQTO_SHIFT;
 | |
| +		ssb_write32(pdev, SSB_IMCFGLO, tmp);
 | |
| +		ssb_commit_settings(bus);
 | |
| +	} else if (pdev->id.revision >= 11) {
 | |
| +		tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2);
 | |
| +		tmp |= SSB_PCICORE_SBTOPCI_MRM;
 | |
| +		pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp);
 | |
| +	}
 | |
| +}
 | |
| +
 | |
| +static void ssb_pcicore_pcie_setup_workarounds(struct ssb_pcicore *pc)
 | |
| +{
 | |
| +	u32 tmp;
 | |
| +	u8 rev = pc->dev->id.revision;
 | |
| +
 | |
| +	if (rev == 0 || rev == 1) {
 | |
| +		/* TLP Workaround register. */
 | |
| +		tmp = ssb_pcie_read(pc, 0x4);
 | |
| +		tmp |= 0x8;
 | |
| +		ssb_pcie_write(pc, 0x4, tmp);
 | |
| +	}
 | |
| +	if (rev == 1) {
 | |
| +		/* DLLP Link Control register. */
 | |
| +		tmp = ssb_pcie_read(pc, 0x100);
 | |
| +		tmp |= 0x40;
 | |
| +		ssb_pcie_write(pc, 0x100, tmp);
 | |
| +	}
 | |
| +
 | |
| +	if (rev == 0) {
 | |
| +		const u8 serdes_rx_device = 0x1F;
 | |
| +
 | |
| +		ssb_pcie_mdio_write(pc, serdes_rx_device,
 | |
| +					2 /* Timer */, 0x8128);
 | |
| +		ssb_pcie_mdio_write(pc, serdes_rx_device,
 | |
| +					6 /* CDR */, 0x0100);
 | |
| +		ssb_pcie_mdio_write(pc, serdes_rx_device,
 | |
| +					7 /* CDR BW */, 0x1466);
 | |
| +	} else if (rev == 3 || rev == 4 || rev == 5) {
 | |
| +		/* TODO: DLLP Power Management Threshold */
 | |
| +		ssb_pcicore_serdes_workaround(pc);
 | |
| +		/* TODO: ASPM */
 | |
| +	} else if (rev == 7) {
 | |
| +		/* TODO: No PLL down */
 | |
| +	}
 | |
| +
 | |
| +	if (rev >= 6) {
 | |
| +		/* Miscellaneous Configuration Fixup */
 | |
| +		tmp = pcicore_read16(pc, SSB_PCICORE_SPROM(5));
 | |
| +		if (!(tmp & 0x8000))
 | |
| +			pcicore_write16(pc, SSB_PCICORE_SPROM(5),
 | |
| +					tmp | 0x8000);
 | |
| +	}
 | |
| +}
 | |
|  
 | |
|  /**************************************************
 | |
|   * Generic and Clientmode operation code.
 | |
|   **************************************************/
 | |
|  
 | |
| -static void ssb_pcicore_init_clientmode(struct ssb_pcicore *pc)
 | |
| +static void __devinit ssb_pcicore_init_clientmode(struct ssb_pcicore *pc)
 | |
|  {
 | |
| +	struct ssb_device *pdev = pc->dev;
 | |
| +	struct ssb_bus *bus = pdev->bus;
 | |
| +
 | |
| +	if (bus->bustype == SSB_BUSTYPE_PCI)
 | |
| +		ssb_pcicore_fix_sprom_core_index(pc);
 | |
| +
 | |
|  	/* Disable PCI interrupts. */
 | |
| -	ssb_write32(pc->dev, SSB_INTVEC, 0);
 | |
| +	ssb_write32(pdev, SSB_INTVEC, 0);
 | |
| +
 | |
| +	/* Additional PCIe always once-executed workarounds */
 | |
| +	if (pc->dev->id.coreid == SSB_DEV_PCIE) {
 | |
| +		ssb_pcicore_serdes_workaround(pc);
 | |
| +		/* TODO: ASPM */
 | |
| +		/* TODO: Clock Request Update */
 | |
| +	}
 | |
|  }
 | |
|  
 | |
| -void ssb_pcicore_init(struct ssb_pcicore *pc)
 | |
| +void __devinit ssb_pcicore_init(struct ssb_pcicore *pc)
 | |
|  {
 | |
|  	struct ssb_device *dev = pc->dev;
 | |
| -	struct ssb_bus *bus;
 | |
|  
 | |
|  	if (!dev)
 | |
|  		return;
 | |
| -	bus = dev->bus;
 | |
|  	if (!ssb_device_is_enabled(dev))
 | |
|  		ssb_device_enable(dev, 0);
 | |
|  
 | |
| @@ -446,11 +563,35 @@ static void ssb_pcie_write(struct ssb_pc
 | |
|  	pcicore_write32(pc, 0x134, data);
 | |
|  }
 | |
|  
 | |
| -static void ssb_pcie_mdio_write(struct ssb_pcicore *pc, u8 device,
 | |
| -				u8 address, u16 data)
 | |
| +static void ssb_pcie_mdio_set_phy(struct ssb_pcicore *pc, u8 phy)
 | |
| +{
 | |
| +	const u16 mdio_control = 0x128;
 | |
| +	const u16 mdio_data = 0x12C;
 | |
| +	u32 v;
 | |
| +	int i;
 | |
| +
 | |
| +	v = (1 << 30); /* Start of Transaction */
 | |
| +	v |= (1 << 28); /* Write Transaction */
 | |
| +	v |= (1 << 17); /* Turnaround */
 | |
| +	v |= (0x1F << 18);
 | |
| +	v |= (phy << 4);
 | |
| +	pcicore_write32(pc, mdio_data, v);
 | |
| +
 | |
| +	udelay(10);
 | |
| +	for (i = 0; i < 200; i++) {
 | |
| +		v = pcicore_read32(pc, mdio_control);
 | |
| +		if (v & 0x100 /* Trans complete */)
 | |
| +			break;
 | |
| +		msleep(1);
 | |
| +	}
 | |
| +}
 | |
| +
 | |
| +static u16 ssb_pcie_mdio_read(struct ssb_pcicore *pc, u8 device, u8 address)
 | |
|  {
 | |
|  	const u16 mdio_control = 0x128;
 | |
|  	const u16 mdio_data = 0x12C;
 | |
| +	int max_retries = 10;
 | |
| +	u16 ret = 0;
 | |
|  	u32 v;
 | |
|  	int i;
 | |
|  
 | |
| @@ -458,46 +599,68 @@ static void ssb_pcie_mdio_write(struct s
 | |
|  	v |= 0x2; /* MDIO Clock Divisor */
 | |
|  	pcicore_write32(pc, mdio_control, v);
 | |
|  
 | |
| +	if (pc->dev->id.revision >= 10) {
 | |
| +		max_retries = 200;
 | |
| +		ssb_pcie_mdio_set_phy(pc, device);
 | |
| +	}
 | |
| +
 | |
|  	v = (1 << 30); /* Start of Transaction */
 | |
| -	v |= (1 << 28); /* Write Transaction */
 | |
| +	v |= (1 << 29); /* Read Transaction */
 | |
|  	v |= (1 << 17); /* Turnaround */
 | |
| -	v |= (u32)device << 22;
 | |
| +	if (pc->dev->id.revision < 10)
 | |
| +		v |= (u32)device << 22;
 | |
|  	v |= (u32)address << 18;
 | |
| -	v |= data;
 | |
|  	pcicore_write32(pc, mdio_data, v);
 | |
|  	/* Wait for the device to complete the transaction */
 | |
|  	udelay(10);
 | |
| -	for (i = 0; i < 10; i++) {
 | |
| +	for (i = 0; i < max_retries; i++) {
 | |
|  		v = pcicore_read32(pc, mdio_control);
 | |
| -		if (v & 0x100 /* Trans complete */)
 | |
| +		if (v & 0x100 /* Trans complete */) {
 | |
| +			udelay(10);
 | |
| +			ret = pcicore_read32(pc, mdio_data);
 | |
|  			break;
 | |
| +		}
 | |
|  		msleep(1);
 | |
|  	}
 | |
|  	pcicore_write32(pc, mdio_control, 0);
 | |
| +	return ret;
 | |
|  }
 | |
|  
 | |
| -static void ssb_broadcast_value(struct ssb_device *dev,
 | |
| -				u32 address, u32 data)
 | |
| +static void ssb_pcie_mdio_write(struct ssb_pcicore *pc, u8 device,
 | |
| +				u8 address, u16 data)
 | |
|  {
 | |
| -	/* This is used for both, PCI and ChipCommon core, so be careful. */
 | |
| -	BUILD_BUG_ON(SSB_PCICORE_BCAST_ADDR != SSB_CHIPCO_BCAST_ADDR);
 | |
| -	BUILD_BUG_ON(SSB_PCICORE_BCAST_DATA != SSB_CHIPCO_BCAST_DATA);
 | |
| +	const u16 mdio_control = 0x128;
 | |
| +	const u16 mdio_data = 0x12C;
 | |
| +	int max_retries = 10;
 | |
| +	u32 v;
 | |
| +	int i;
 | |
|  
 | |
| -	ssb_write32(dev, SSB_PCICORE_BCAST_ADDR, address);
 | |
| -	ssb_read32(dev, SSB_PCICORE_BCAST_ADDR); /* flush */
 | |
| -	ssb_write32(dev, SSB_PCICORE_BCAST_DATA, data);
 | |
| -	ssb_read32(dev, SSB_PCICORE_BCAST_DATA); /* flush */
 | |
| -}
 | |
| +	v = 0x80; /* Enable Preamble Sequence */
 | |
| +	v |= 0x2; /* MDIO Clock Divisor */
 | |
| +	pcicore_write32(pc, mdio_control, v);
 | |
|  
 | |
| -static void ssb_commit_settings(struct ssb_bus *bus)
 | |
| -{
 | |
| -	struct ssb_device *dev;
 | |
| +	if (pc->dev->id.revision >= 10) {
 | |
| +		max_retries = 200;
 | |
| +		ssb_pcie_mdio_set_phy(pc, device);
 | |
| +	}
 | |
|  
 | |
| -	dev = bus->chipco.dev ? bus->chipco.dev : bus->pcicore.dev;
 | |
| -	if (WARN_ON(!dev))
 | |
| -		return;
 | |
| -	/* This forces an update of the cached registers. */
 | |
| -	ssb_broadcast_value(dev, 0xFD8, 0);
 | |
| +	v = (1 << 30); /* Start of Transaction */
 | |
| +	v |= (1 << 28); /* Write Transaction */
 | |
| +	v |= (1 << 17); /* Turnaround */
 | |
| +	if (pc->dev->id.revision < 10)
 | |
| +		v |= (u32)device << 22;
 | |
| +	v |= (u32)address << 18;
 | |
| +	v |= data;
 | |
| +	pcicore_write32(pc, mdio_data, v);
 | |
| +	/* Wait for the device to complete the transaction */
 | |
| +	udelay(10);
 | |
| +	for (i = 0; i < max_retries; i++) {
 | |
| +		v = pcicore_read32(pc, mdio_control);
 | |
| +		if (v & 0x100 /* Trans complete */)
 | |
| +			break;
 | |
| +		msleep(1);
 | |
| +	}
 | |
| +	pcicore_write32(pc, mdio_control, 0);
 | |
|  }
 | |
|  
 | |
|  int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc,
 | |
| @@ -550,48 +713,10 @@ int ssb_pcicore_dev_irqvecs_enable(struc
 | |
|  	if (pc->setup_done)
 | |
|  		goto out;
 | |
|  	if (pdev->id.coreid == SSB_DEV_PCI) {
 | |
| -		tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2);
 | |
| -		tmp |= SSB_PCICORE_SBTOPCI_PREF;
 | |
| -		tmp |= SSB_PCICORE_SBTOPCI_BURST;
 | |
| -		pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp);
 | |
| -
 | |
| -		if (pdev->id.revision < 5) {
 | |
| -			tmp = ssb_read32(pdev, SSB_IMCFGLO);
 | |
| -			tmp &= ~SSB_IMCFGLO_SERTO;
 | |
| -			tmp |= 2;
 | |
| -			tmp &= ~SSB_IMCFGLO_REQTO;
 | |
| -			tmp |= 3 << SSB_IMCFGLO_REQTO_SHIFT;
 | |
| -			ssb_write32(pdev, SSB_IMCFGLO, tmp);
 | |
| -			ssb_commit_settings(bus);
 | |
| -		} else if (pdev->id.revision >= 11) {
 | |
| -			tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2);
 | |
| -			tmp |= SSB_PCICORE_SBTOPCI_MRM;
 | |
| -			pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp);
 | |
| -		}
 | |
| +		ssb_pcicore_pci_setup_workarounds(pc);
 | |
|  	} else {
 | |
|  		WARN_ON(pdev->id.coreid != SSB_DEV_PCIE);
 | |
| -		//TODO: Better make defines for all these magic PCIE values.
 | |
| -		if ((pdev->id.revision == 0) || (pdev->id.revision == 1)) {
 | |
| -			/* TLP Workaround register. */
 | |
| -			tmp = ssb_pcie_read(pc, 0x4);
 | |
| -			tmp |= 0x8;
 | |
| -			ssb_pcie_write(pc, 0x4, tmp);
 | |
| -		}
 | |
| -		if (pdev->id.revision == 0) {
 | |
| -			const u8 serdes_rx_device = 0x1F;
 | |
| -
 | |
| -			ssb_pcie_mdio_write(pc, serdes_rx_device,
 | |
| -					    2 /* Timer */, 0x8128);
 | |
| -			ssb_pcie_mdio_write(pc, serdes_rx_device,
 | |
| -					    6 /* CDR */, 0x0100);
 | |
| -			ssb_pcie_mdio_write(pc, serdes_rx_device,
 | |
| -					    7 /* CDR BW */, 0x1466);
 | |
| -		} else if (pdev->id.revision == 1) {
 | |
| -			/* DLLP Link Control register. */
 | |
| -			tmp = ssb_pcie_read(pc, 0x100);
 | |
| -			tmp |= 0x40;
 | |
| -			ssb_pcie_write(pc, 0x100, tmp);
 | |
| -		}
 | |
| +		ssb_pcicore_pcie_setup_workarounds(pc);
 | |
|  	}
 | |
|  	pc->setup_done = 1;
 | |
|  out:
 | |
| --- a/drivers/ssb/sprom.c
 | |
| +++ b/drivers/ssb/sprom.c
 | |
| @@ -2,7 +2,7 @@
 | |
|   * Sonics Silicon Backplane
 | |
|   * Common SPROM support routines
 | |
|   *
 | |
| - * Copyright (C) 2005-2008 Michael Buesch <mb@bu3sch.de>
 | |
| + * Copyright (C) 2005-2008 Michael Buesch <m@bues.ch>
 | |
|   * 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>
 | |
| @@ -17,7 +17,7 @@
 | |
|  #include <linux/slab.h>
 | |
|  
 | |
|  
 | |
| -static const struct ssb_sprom *fallback_sprom;
 | |
| +static int(*get_fallback_sprom)(struct ssb_bus *dev, struct ssb_sprom *out);
 | |
|  
 | |
|  
 | |
|  static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len,
 | |
| @@ -145,36 +145,43 @@ out:
 | |
|  }
 | |
|  
 | |
|  /**
 | |
| - * ssb_arch_set_fallback_sprom - Set a fallback SPROM for use if no SPROM is found.
 | |
| + * ssb_arch_register_fallback_sprom - Registers a method providing a
 | |
| + * fallback SPROM if no SPROM is found.
 | |
|   *
 | |
| - * @sprom: The SPROM data structure to register.
 | |
| + * @sprom_callback: The callback function.
 | |
|   *
 | |
| - * With this function the architecture implementation may register a fallback
 | |
| - * SPROM data structure. The fallback is only used for PCI based SSB devices,
 | |
| - * where no valid SPROM can be found in the shadow registers.
 | |
| + * With this function the architecture implementation may register a
 | |
| + * callback handler which fills the SPROM data structure. The fallback is
 | |
| + * only used for PCI based SSB devices, where no valid SPROM can be found
 | |
| + * in the shadow registers.
 | |
| + *
 | |
| + * This function is useful for weird architectures that have a half-assed
 | |
| + * SSB device hardwired to their PCI bus.
 | |
| + *
 | |
| + * Note that it does only work with PCI attached SSB devices. PCMCIA
 | |
| + * devices currently don't use this fallback.
 | |
| + * Architectures must provide the SPROM for native SSB devices anyway, so
 | |
| + * the fallback also isn't used for native devices.
 | |
|   *
 | |
| - * This function is useful for weird architectures that have a half-assed SSB device
 | |
| - * hardwired to their PCI bus.
 | |
| - *
 | |
| - * Note that it does only work with PCI attached SSB devices. PCMCIA devices currently
 | |
| - * don't use this fallback.
 | |
| - * Architectures must provide the SPROM for native SSB devices anyway,
 | |
| - * so the fallback also isn't used for native devices.
 | |
| - *
 | |
| - * This function is available for architecture code, only. So it is not exported.
 | |
| + * This function is available for architecture code, only. So it is not
 | |
| + * exported.
 | |
|   */
 | |
| -int ssb_arch_set_fallback_sprom(const struct ssb_sprom *sprom)
 | |
| +int ssb_arch_register_fallback_sprom(int (*sprom_callback)(struct ssb_bus *bus,
 | |
| +				     struct ssb_sprom *out))
 | |
|  {
 | |
| -	if (fallback_sprom)
 | |
| +	if (get_fallback_sprom)
 | |
|  		return -EEXIST;
 | |
| -	fallback_sprom = sprom;
 | |
| +	get_fallback_sprom = sprom_callback;
 | |
|  
 | |
|  	return 0;
 | |
|  }
 | |
|  
 | |
| -const struct ssb_sprom *ssb_get_fallback_sprom(void)
 | |
| +int ssb_fill_sprom_with_fallback(struct ssb_bus *bus, struct ssb_sprom *out)
 | |
|  {
 | |
| -	return fallback_sprom;
 | |
| +	if (!get_fallback_sprom)
 | |
| +		return -ENOENT;
 | |
| +
 | |
| +	return get_fallback_sprom(bus, out);
 | |
|  }
 | |
|  
 | |
|  /* http://bcm-v4.sipsolutions.net/802.11/IsSpromAvailable */
 | |
| @@ -185,7 +192,7 @@ bool ssb_is_sprom_available(struct ssb_b
 | |
|  	/* this routine differs from specs as we do not access SPROM directly
 | |
|  	   on PCMCIA */
 | |
|  	if (bus->bustype == SSB_BUSTYPE_PCI &&
 | |
| -	    bus->chipco.dev &&	/* can be unavailible! */
 | |
| +	    bus->chipco.dev &&	/* can be unavailable! */
 | |
|  	    bus->chipco.dev->id.revision >= 31)
 | |
|  		return bus->chipco.capabilities & SSB_CHIPCO_CAP_SPROM;
 | |
|  
 | |
| --- a/drivers/ssb/ssb_private.h
 | |
| +++ b/drivers/ssb/ssb_private.h
 | |
| @@ -171,7 +171,8 @@ ssize_t ssb_attr_sprom_store(struct ssb_
 | |
|  			     const char *buf, size_t count,
 | |
|  			     int (*sprom_check_crc)(const u16 *sprom, size_t size),
 | |
|  			     int (*sprom_write)(struct ssb_bus *bus, const u16 *sprom));
 | |
| -extern const struct ssb_sprom *ssb_get_fallback_sprom(void);
 | |
| +extern int ssb_fill_sprom_with_fallback(struct ssb_bus *bus,
 | |
| +					struct ssb_sprom *out);
 | |
|  
 | |
|  
 | |
|  /* core.c */
 | |
| --- a/include/linux/ssb/ssb_driver_chipcommon.h
 | |
| +++ b/include/linux/ssb/ssb_driver_chipcommon.h
 | |
| @@ -8,7 +8,7 @@
 | |
|   * gpio interface, extbus, and support for serial and parallel flashes.
 | |
|   *
 | |
|   * Copyright 2005, Broadcom Corporation
 | |
| - * Copyright 2006, Michael Buesch <mb@bu3sch.de>
 | |
| + * Copyright 2006, Michael Buesch <m@bues.ch>
 | |
|   *
 | |
|   * Licensed under the GPL version 2. See COPYING for details.
 | |
|   */
 | |
| @@ -123,6 +123,8 @@
 | |
|  #define SSB_CHIPCO_FLASHDATA		0x0048
 | |
|  #define SSB_CHIPCO_BCAST_ADDR		0x0050
 | |
|  #define SSB_CHIPCO_BCAST_DATA		0x0054
 | |
| +#define SSB_CHIPCO_GPIOPULLUP		0x0058		/* Rev >= 20 only */
 | |
| +#define SSB_CHIPCO_GPIOPULLDOWN		0x005C		/* Rev >= 20 only */
 | |
|  #define SSB_CHIPCO_GPIOIN		0x0060
 | |
|  #define SSB_CHIPCO_GPIOOUT		0x0064
 | |
|  #define SSB_CHIPCO_GPIOOUTEN		0x0068
 | |
| @@ -131,6 +133,9 @@
 | |
|  #define SSB_CHIPCO_GPIOIRQ		0x0074
 | |
|  #define SSB_CHIPCO_WATCHDOG		0x0080
 | |
|  #define SSB_CHIPCO_GPIOTIMER		0x0088		/* LED powersave (corerev >= 16) */
 | |
| +#define  SSB_CHIPCO_GPIOTIMER_OFFTIME	0x0000FFFF
 | |
| +#define  SSB_CHIPCO_GPIOTIMER_OFFTIME_SHIFT	0
 | |
| +#define  SSB_CHIPCO_GPIOTIMER_ONTIME	0xFFFF0000
 | |
|  #define  SSB_CHIPCO_GPIOTIMER_ONTIME_SHIFT	16
 | |
|  #define SSB_CHIPCO_GPIOTOUTM		0x008C		/* LED powersave (corerev >= 16) */
 | |
|  #define SSB_CHIPCO_CLOCK_N		0x0090
 | |
| @@ -189,8 +194,10 @@
 | |
|  #define  SSB_CHIPCO_CLKCTLST_HAVEALPREQ	0x00000008 /* ALP available request */
 | |
|  #define  SSB_CHIPCO_CLKCTLST_HAVEHTREQ	0x00000010 /* HT available request */
 | |
|  #define  SSB_CHIPCO_CLKCTLST_HWCROFF	0x00000020 /* Force HW clock request off */
 | |
| -#define  SSB_CHIPCO_CLKCTLST_HAVEHT	0x00010000 /* HT available */
 | |
| -#define  SSB_CHIPCO_CLKCTLST_HAVEALP	0x00020000 /* APL available */
 | |
| +#define  SSB_CHIPCO_CLKCTLST_HAVEALP	0x00010000 /* ALP available */
 | |
| +#define  SSB_CHIPCO_CLKCTLST_HAVEHT	0x00020000 /* HT available */
 | |
| +#define  SSB_CHIPCO_CLKCTLST_4328A0_HAVEHT	0x00010000 /* 4328a0 has reversed bits */
 | |
| +#define  SSB_CHIPCO_CLKCTLST_4328A0_HAVEALP	0x00020000 /* 4328a0 has reversed bits */
 | |
|  #define SSB_CHIPCO_HW_WORKAROUND	0x01E4 /* Hardware workaround (rev >= 20) */
 | |
|  #define SSB_CHIPCO_UART0_DATA		0x0300
 | |
|  #define SSB_CHIPCO_UART0_IMR		0x0304
 | |
| --- a/drivers/ssb/b43_pci_bridge.c
 | |
| +++ b/drivers/ssb/b43_pci_bridge.c
 | |
| @@ -5,12 +5,13 @@
 | |
|   * because of its small size we include it in the SSB core
 | |
|   * instead of creating a standalone module.
 | |
|   *
 | |
| - * Copyright 2007  Michael Buesch <mb@bu3sch.de>
 | |
| + * Copyright 2007  Michael Buesch <m@bues.ch>
 | |
|   *
 | |
|   * Licensed under the GNU/GPL. See COPYING for details.
 | |
|   */
 | |
|  
 | |
|  #include <linux/pci.h>
 | |
| +#include <linux/module.h>
 | |
|  #include <linux/ssb/ssb.h>
 | |
|  
 | |
|  #include "ssb_private.h"
 | |
| --- a/drivers/ssb/driver_extif.c
 | |
| +++ b/drivers/ssb/driver_extif.c
 | |
| @@ -3,7 +3,7 @@
 | |
|   * Broadcom EXTIF core driver
 | |
|   *
 | |
|   * Copyright 2005, Broadcom Corporation
 | |
| - * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
 | |
| + * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
 | |
|   * Copyright 2006, 2007, Felix Fietkau <nbd@openwrt.org>
 | |
|   * Copyright 2007, Aurelien Jarno <aurelien@aurel32.net>
 | |
|   *
 | |
| --- a/drivers/ssb/driver_mipscore.c
 | |
| +++ b/drivers/ssb/driver_mipscore.c
 | |
| @@ -3,7 +3,7 @@
 | |
|   * Broadcom MIPS core driver
 | |
|   *
 | |
|   * Copyright 2005, Broadcom Corporation
 | |
| - * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
 | |
| + * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
 | |
|   *
 | |
|   * Licensed under the GNU/GPL. See COPYING for details.
 | |
|   */
 | |
| --- a/drivers/ssb/embedded.c
 | |
| +++ b/drivers/ssb/embedded.c
 | |
| @@ -3,7 +3,7 @@
 | |
|   * Embedded systems support code
 | |
|   *
 | |
|   * Copyright 2005-2008, Broadcom Corporation
 | |
| - * Copyright 2006-2008, Michael Buesch <mb@bu3sch.de>
 | |
| + * Copyright 2006-2008, Michael Buesch <m@bues.ch>
 | |
|   *
 | |
|   * Licensed under the GNU/GPL. See COPYING for details.
 | |
|   */
 | |
| --- a/drivers/ssb/pcmcia.c
 | |
| +++ b/drivers/ssb/pcmcia.c
 | |
| @@ -3,7 +3,7 @@
 | |
|   * PCMCIA-Hostbus related functions
 | |
|   *
 | |
|   * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
 | |
| - * Copyright 2007-2008 Michael Buesch <mb@bu3sch.de>
 | |
| + * Copyright 2007-2008 Michael Buesch <m@bues.ch>
 | |
|   *
 | |
|   * Licensed under the GNU/GPL. See COPYING for details.
 | |
|   */
 | |
| --- a/drivers/ssb/sdio.c
 | |
| +++ b/drivers/ssb/sdio.c
 | |
| @@ -6,7 +6,7 @@
 | |
|   *
 | |
|   * Based on drivers/ssb/pcmcia.c
 | |
|   * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
 | |
| - * Copyright 2007-2008 Michael Buesch <mb@bu3sch.de>
 | |
| + * Copyright 2007-2008 Michael Buesch <m@bues.ch>
 | |
|   *
 | |
|   * Licensed under the GNU/GPL. See COPYING for details.
 | |
|   *
 |