diff options
Diffstat (limited to 'drivers/ssb')
| -rw-r--r-- | drivers/ssb/Kconfig | 18 | ||||
| -rw-r--r-- | drivers/ssb/Makefile | 2 | ||||
| -rw-r--r-- | drivers/ssb/b43_pci_bridge.c | 7 | ||||
| -rw-r--r-- | drivers/ssb/driver_chipcommon.c | 251 | ||||
| -rw-r--r-- | drivers/ssb/driver_chipcommon_pmu.c | 154 | ||||
| -rw-r--r-- | drivers/ssb/driver_chipcommon_sflash.c | 164 | ||||
| -rw-r--r-- | drivers/ssb/driver_extif.c | 69 | ||||
| -rw-r--r-- | drivers/ssb/driver_gige.c | 6 | ||||
| -rw-r--r-- | drivers/ssb/driver_gpio.c | 484 | ||||
| -rw-r--r-- | drivers/ssb/driver_mipscore.c | 103 | ||||
| -rw-r--r-- | drivers/ssb/driver_pcicore.c | 283 | ||||
| -rw-r--r-- | drivers/ssb/embedded.c | 37 | ||||
| -rw-r--r-- | drivers/ssb/main.c | 274 | ||||
| -rw-r--r-- | drivers/ssb/pci.c | 373 | ||||
| -rw-r--r-- | drivers/ssb/pcihost_wrapper.c | 5 | ||||
| -rw-r--r-- | drivers/ssb/pcmcia.c | 62 | ||||
| -rw-r--r-- | drivers/ssb/scan.c | 54 | ||||
| -rw-r--r-- | drivers/ssb/sdio.c | 14 | ||||
| -rw-r--r-- | drivers/ssb/sprom.c | 53 | ||||
| -rw-r--r-- | drivers/ssb/ssb_private.h | 98 | 
20 files changed, 2066 insertions, 445 deletions
diff --git a/drivers/ssb/Kconfig b/drivers/ssb/Kconfig index 2d8cc455dbc..75b3603906c 100644 --- a/drivers/ssb/Kconfig +++ b/drivers/ssb/Kconfig @@ -82,7 +82,7 @@ config SSB_SDIOHOST  config SSB_SILENT  	bool "No SSB kernel messages" -	depends on SSB && EMBEDDED +	depends on SSB && EXPERT  	help  	  This option turns off all Sonics Silicon Backplane printks.  	  Note that you won't be able to identify problems, once @@ -136,10 +136,15 @@ config SSB_DRIVER_MIPS  	  If unsure, say N +config SSB_SFLASH +	bool "SSB serial flash support" +	depends on SSB_DRIVER_MIPS +	default y +  # Assumption: We are on embedded, if we compile the MIPS core.  config SSB_EMBEDDED  	bool -	depends on SSB_DRIVER_MIPS +	depends on SSB_DRIVER_MIPS && SSB_PCICORE_HOSTMODE  	default y  config SSB_DRIVER_EXTIF @@ -160,4 +165,13 @@ config SSB_DRIVER_GIGE  	  If unsure, say N +config SSB_DRIVER_GPIO +	bool "SSB GPIO driver" +	depends on SSB && GPIOLIB +	select IRQ_DOMAIN if SSB_EMBEDDED +	help +	  Driver to provide access to the GPIO pins on the bus. + +	  If unsure, say N +  endmenu diff --git a/drivers/ssb/Makefile b/drivers/ssb/Makefile index 656e58b9261..b1ddc116d38 100644 --- a/drivers/ssb/Makefile +++ b/drivers/ssb/Makefile @@ -11,10 +11,12 @@ ssb-$(CONFIG_SSB_SDIOHOST)		+= sdio.o  # built-in drivers  ssb-y					+= driver_chipcommon.o  ssb-y					+= driver_chipcommon_pmu.o +ssb-$(CONFIG_SSB_SFLASH)		+= driver_chipcommon_sflash.o  ssb-$(CONFIG_SSB_DRIVER_MIPS)		+= driver_mipscore.o  ssb-$(CONFIG_SSB_DRIVER_EXTIF)		+= driver_extif.o  ssb-$(CONFIG_SSB_DRIVER_PCICORE)	+= driver_pcicore.o  ssb-$(CONFIG_SSB_DRIVER_GIGE)		+= driver_gige.o +ssb-$(CONFIG_SSB_DRIVER_GPIO)		+= driver_gpio.o  # b43 pci-ssb-bridge driver  # Not strictly a part of SSB, but kept here for convenience diff --git a/drivers/ssb/b43_pci_bridge.c b/drivers/ssb/b43_pci_bridge.c index 744d3f6e470..19396dc4ee4 100644 --- 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" @@ -28,11 +29,15 @@ static const struct pci_device_id b43_pci_bridge_tbl[] = {  	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4319) },  	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4320) },  	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4321) }, +	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4322) }, +	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 43222) },  	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4324) },  	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4325) },  	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4328) },  	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4329) },  	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x432b) }, +	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x432c) }, +	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4350) },  	{ 0, },  };  MODULE_DEVICE_TABLE(pci, b43_pci_bridge_tbl); diff --git a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c index 7c031fdc820..7cb7d2c8fd8 100644 --- a/drivers/ssb/driver_chipcommon.c +++ b/drivers/ssb/driver_chipcommon.c @@ -3,14 +3,17 @@   * Broadcom ChipCommon core driver   *   * Copyright 2005, Broadcom Corporation - * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de> + * Copyright 2006, 2007, Michael Buesch <m@bues.ch> + * Copyright 2012, Hauke Mehrtens <hauke@hauke-m.de>   *   * Licensed under the GNU/GPL. See COPYING for details.   */  #include <linux/ssb/ssb.h>  #include <linux/ssb/ssb_regs.h> +#include <linux/export.h>  #include <linux/pci.h> +#include <linux/bcm47xx_wdt.h>  #include "ssb_private.h" @@ -46,40 +49,66 @@ void ssb_chipco_set_clockmode(struct ssb_chipcommon *cc,  	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); @@ -253,17 +282,94 @@ static void calc_fast_powerup_delay(struct ssb_chipcommon *cc)  	cc->fast_pwrup_delay = tmp;  } +static u32 ssb_chipco_alp_clock(struct ssb_chipcommon *cc) +{ +	if (cc->capabilities & SSB_CHIPCO_CAP_PMU) +		return ssb_pmu_get_alp_clock(cc); + +	return 20000000; +} + +static u32 ssb_chipco_watchdog_get_max_timer(struct ssb_chipcommon *cc) +{ +	u32 nb; + +	if (cc->capabilities & SSB_CHIPCO_CAP_PMU) { +		if (cc->dev->id.revision < 26) +			nb = 16; +		else +			nb = (cc->dev->id.revision >= 37) ? 32 : 24; +	} else { +		nb = 28; +	} +	if (nb == 32) +		return 0xffffffff; +	else +		return (1 << nb) - 1; +} + +u32 ssb_chipco_watchdog_timer_set_wdt(struct bcm47xx_wdt *wdt, u32 ticks) +{ +	struct ssb_chipcommon *cc = bcm47xx_wdt_get_drvdata(wdt); + +	if (cc->dev->bus->bustype != SSB_BUSTYPE_SSB) +		return 0; + +	return ssb_chipco_watchdog_timer_set(cc, ticks); +} + +u32 ssb_chipco_watchdog_timer_set_ms(struct bcm47xx_wdt *wdt, u32 ms) +{ +	struct ssb_chipcommon *cc = bcm47xx_wdt_get_drvdata(wdt); +	u32 ticks; + +	if (cc->dev->bus->bustype != SSB_BUSTYPE_SSB) +		return 0; + +	ticks = ssb_chipco_watchdog_timer_set(cc, cc->ticks_per_ms * ms); +	return ticks / cc->ticks_per_ms; +} + +static int ssb_chipco_watchdog_ticks_per_ms(struct ssb_chipcommon *cc) +{ +	struct ssb_bus *bus = cc->dev->bus; + +	if (cc->capabilities & SSB_CHIPCO_CAP_PMU) { +			/* based on 32KHz ILP clock */ +			return 32; +	} else { +		if (cc->dev->id.revision < 18) +			return ssb_clockspeed(bus) / 1000; +		else +			return ssb_chipco_alp_clock(cc) / 1000; +	} +} +  void ssb_chipcommon_init(struct ssb_chipcommon *cc)  {  	if (!cc->dev)  		return; /* We don't have a ChipCommon */ + +	spin_lock_init(&cc->gpio_lock); +  	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); +	ssb_dbg("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);  	calc_fast_powerup_delay(cc); + +	if (cc->dev->bus->bustype == SSB_BUSTYPE_SSB) { +		cc->ticks_per_ms = ssb_chipco_watchdog_ticks_per_ms(cc); +		cc->max_timer_ms = ssb_chipco_watchdog_get_max_timer(cc) / cc->ticks_per_ms; +	}  }  void ssb_chipco_suspend(struct ssb_chipcommon *cc) @@ -362,10 +468,27 @@ void ssb_chipco_timing_init(struct ssb_chipcommon *cc,  }  /* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */ -void ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc, u32 ticks) +u32 ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc, u32 ticks)  { -	/* instant NMI */ -	chipco_write32(cc, SSB_CHIPCO_WATCHDOG, ticks); +	u32 maxt; +	enum ssb_clkmode clkmode; + +	maxt = ssb_chipco_watchdog_get_max_timer(cc); +	if (cc->capabilities & SSB_CHIPCO_CAP_PMU) { +		if (ticks == 1) +			ticks = 2; +		else if (ticks > maxt) +			ticks = maxt; +		chipco_write32(cc, SSB_CHIPCO_PMU_WATCHDOG, ticks); +	} else { +		clkmode = ticks ? SSB_CLKMODE_FAST : SSB_CLKMODE_DYNAMIC; +		ssb_chipco_set_clockmode(cc, clkmode); +		if (ticks > maxt) +			ticks = maxt; +		/* instant NMI */ +		chipco_write32(cc, SSB_CHIPCO_WATCHDOG, ticks); +	} +	return ticks;  }  void ssb_chipco_irq_mask(struct ssb_chipcommon *cc, u32 mask, u32 value) @@ -385,28 +508,93 @@ u32 ssb_chipco_gpio_in(struct ssb_chipcommon *cc, u32 mask)  u32 ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value)  { -	return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUT, mask, value); +	unsigned long flags; +	u32 res = 0; + +	spin_lock_irqsave(&cc->gpio_lock, flags); +	res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUT, mask, value); +	spin_unlock_irqrestore(&cc->gpio_lock, flags); + +	return res;  }  u32 ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value)  { -	return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUTEN, mask, value); +	unsigned long flags; +	u32 res = 0; + +	spin_lock_irqsave(&cc->gpio_lock, flags); +	res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUTEN, mask, value); +	spin_unlock_irqrestore(&cc->gpio_lock, flags); + +	return res;  }  u32 ssb_chipco_gpio_control(struct ssb_chipcommon *cc, u32 mask, u32 value)  { -	return chipco_write32_masked(cc, SSB_CHIPCO_GPIOCTL, mask, value); +	unsigned long flags; +	u32 res = 0; + +	spin_lock_irqsave(&cc->gpio_lock, flags); +	res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOCTL, mask, value); +	spin_unlock_irqrestore(&cc->gpio_lock, flags); + +	return res;  }  EXPORT_SYMBOL(ssb_chipco_gpio_control);  u32 ssb_chipco_gpio_intmask(struct ssb_chipcommon *cc, u32 mask, u32 value)  { -	return chipco_write32_masked(cc, SSB_CHIPCO_GPIOIRQ, mask, value); +	unsigned long flags; +	u32 res = 0; + +	spin_lock_irqsave(&cc->gpio_lock, flags); +	res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOIRQ, mask, value); +	spin_unlock_irqrestore(&cc->gpio_lock, flags); + +	return res;  }  u32 ssb_chipco_gpio_polarity(struct ssb_chipcommon *cc, u32 mask, u32 value)  { -	return chipco_write32_masked(cc, SSB_CHIPCO_GPIOPOL, mask, value); +	unsigned long flags; +	u32 res = 0; + +	spin_lock_irqsave(&cc->gpio_lock, flags); +	res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOPOL, mask, value); +	spin_unlock_irqrestore(&cc->gpio_lock, flags); + +	return res; +} + +u32 ssb_chipco_gpio_pullup(struct ssb_chipcommon *cc, u32 mask, u32 value) +{ +	unsigned long flags; +	u32 res = 0; + +	if (cc->dev->id.revision < 20) +		return 0xffffffff; + +	spin_lock_irqsave(&cc->gpio_lock, flags); +	res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOPULLUP, mask, value); +	spin_unlock_irqrestore(&cc->gpio_lock, flags); + +	return res; +} + +u32 ssb_chipco_gpio_pulldown(struct ssb_chipcommon *cc, u32 mask, u32 value) +{ +	unsigned long flags; +	u32 res = 0; + +	if (cc->dev->id.revision < 20) +		return 0xffffffff; + +	spin_lock_irqsave(&cc->gpio_lock, flags); +	res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOPULLDOWN, mask, value); +	spin_unlock_irqrestore(&cc->gpio_lock, flags); + +	return res;  }  #ifdef CONFIG_SSB_SERIAL @@ -440,12 +628,7 @@ int ssb_chipco_serial_init(struct ssb_chipcommon *cc,  				       chipco_read32(cc, SSB_CHIPCO_CORECTL)  				       | SSB_CHIPCO_CORECTL_UARTCLK0);  		} else if ((ccrev >= 11) && (ccrev != 15)) { -			/* Fixed ALP clock */ -			baud_base = 20000000; -			if (cc->capabilities & SSB_CHIPCO_CAP_PMU) { -				/* FIXME: baud_base is different for devices with a PMU */ -				SSB_WARN_ON(1); -			} +			baud_base = ssb_chipco_alp_clock(cc);  			div = 1;  			if (ccrev >= 21) {  				/* Turn off UART clock before switching clocksource. */ diff --git a/drivers/ssb/driver_chipcommon_pmu.c b/drivers/ssb/driver_chipcommon_pmu.c index 5732bb2c357..1173a091b40 100644 --- 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. @@ -12,6 +12,10 @@  #include <linux/ssb/ssb_regs.h>  #include <linux/ssb/ssb_driver_chipcommon.h>  #include <linux/delay.h> +#include <linux/export.h> +#ifdef CONFIG_BCM47XX +#include <bcm47xx_nvram.h> +#endif  #include "ssb_private.h" @@ -91,10 +95,6 @@ static void ssb_pmu0_pllinit_r0(struct ssb_chipcommon *cc,  	u32 pmuctl, tmp, pllctl;  	unsigned int i; -	if ((bus->chip_id == 0x5354) && !crystalfreq) { -		/* The 5354 crystal freq is 25MHz */ -		crystalfreq = 25000; -	}  	if (crystalfreq)  		e = pmu0_plltab_find_entry(crystalfreq);  	if (!e) @@ -110,8 +110,8 @@ static void ssb_pmu0_pllinit_r0(struct ssb_chipcommon *cc,  		return;  	} -	ssb_printk(KERN_INFO PFX "Programming PLL to %u.%03u MHz\n", -		   (crystalfreq / 1000), (crystalfreq % 1000)); +	ssb_info("Programming PLL to %u.%03u MHz\n", +		 crystalfreq / 1000, crystalfreq % 1000);  	/* First turn the PLL off. */  	switch (bus->chip_id) { @@ -138,7 +138,7 @@ static void ssb_pmu0_pllinit_r0(struct ssb_chipcommon *cc,  	}  	tmp = chipco_read32(cc, SSB_CHIPCO_CLKCTLST);  	if (tmp & SSB_CHIPCO_CLKCTLST_HAVEHT) -		ssb_printk(KERN_EMERG PFX "Failed to turn the PLL off!\n"); +		ssb_emerg("Failed to turn the PLL off!\n");  	/* Set PDIV in PLL control 0. */  	pllctl = ssb_chipco_pll_read(cc, SSB_PMU0_PLLCTL0); @@ -249,8 +249,8 @@ static void ssb_pmu1_pllinit_r0(struct ssb_chipcommon *cc,  		return;  	} -	ssb_printk(KERN_INFO PFX "Programming PLL to %u.%03u MHz\n", -		   (crystalfreq / 1000), (crystalfreq % 1000)); +	ssb_info("Programming PLL to %u.%03u MHz\n", +		 crystalfreq / 1000, crystalfreq % 1000);  	/* First turn the PLL off. */  	switch (bus->chip_id) { @@ -275,7 +275,7 @@ static void ssb_pmu1_pllinit_r0(struct ssb_chipcommon *cc,  	}  	tmp = chipco_read32(cc, SSB_CHIPCO_CLKCTLST);  	if (tmp & SSB_CHIPCO_CLKCTLST_HAVEHT) -		ssb_printk(KERN_EMERG PFX "Failed to turn the PLL off!\n"); +		ssb_emerg("Failed to turn the PLL off!\n");  	/* Set p1div and p2div. */  	pllctl = ssb_chipco_pll_read(cc, SSB_PMU1_PLLCTL0); @@ -320,7 +320,11 @@ static void ssb_pmu_pll_init(struct ssb_chipcommon *cc)  	u32 crystalfreq = 0; /* in kHz. 0 = keep default freq. */  	if (bus->bustype == SSB_BUSTYPE_SSB) { -		/* TODO: The user may override the crystal frequency. */ +#ifdef CONFIG_BCM47XX +		char buf[20]; +		if (bcm47xx_nvram_getenv("xtalfreq", buf, sizeof(buf)) >= 0) +			crystalfreq = simple_strtoul(buf, NULL, 0); +#endif  	}  	switch (bus->chip_id) { @@ -329,7 +333,11 @@ static void ssb_pmu_pll_init(struct ssb_chipcommon *cc)  		ssb_pmu1_pllinit_r0(cc, crystalfreq);  		break;  	case 0x4328: +		ssb_pmu0_pllinit_r0(cc, crystalfreq); +		break;  	case 0x5354: +		if (crystalfreq == 0) +			crystalfreq = 25000;  		ssb_pmu0_pllinit_r0(cc, crystalfreq);  		break;  	case 0x4322: @@ -338,10 +346,11 @@ static void ssb_pmu_pll_init(struct ssb_chipcommon *cc)  			chipco_write32(cc, SSB_CHIPCO_PLLCTL_DATA, 0x380005C0);  		}  		break; +	case 43222: +		break;  	default: -		ssb_printk(KERN_ERR PFX -			   "ERROR: PLL init unknown for device %04X\n", -			   bus->chip_id); +		ssb_err("ERROR: PLL init unknown for device %04X\n", +			bus->chip_id);  	}  } @@ -417,13 +426,16 @@ static void ssb_pmu_resources_init(struct ssb_chipcommon *cc)  	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: +	case 43222:  		/* We keep the default settings:  		 * min_msk = 0xCBB  		 * max_msk = 0x7FFFF @@ -459,9 +471,8 @@ static void ssb_pmu_resources_init(struct ssb_chipcommon *cc)  		max_msk = 0xFFFFF;  		break;  	default: -		ssb_printk(KERN_ERR PFX -			   "ERROR: PMU resource config unknown for device %04X\n", -			   bus->chip_id); +		ssb_err("ERROR: PMU resource config unknown for device %04X\n", +			bus->chip_id);  	}  	if (updown_tab) { @@ -513,8 +524,8 @@ void ssb_pmu_init(struct ssb_chipcommon *cc)  	pmucap = chipco_read32(cc, SSB_CHIPCO_PMU_CAP);  	cc->pmu.rev = (pmucap & SSB_CHIPCO_PMU_CAP_REVISION); -	ssb_dprintk(KERN_DEBUG PFX "Found rev %u PMU (capabilities 0x%08X)\n", -		    cc->pmu.rev, pmucap); +	ssb_dbg("Found rev %u PMU (capabilities 0x%08X)\n", +		cc->pmu.rev, pmucap);  	if (cc->pmu.rev == 1)  		chipco_mask32(cc, SSB_CHIPCO_PMU_CTL, @@ -604,3 +615,102 @@ void ssb_pmu_set_ldo_paref(struct ssb_chipcommon *cc, bool on)  EXPORT_SYMBOL(ssb_pmu_set_ldo_voltage);  EXPORT_SYMBOL(ssb_pmu_set_ldo_paref); + +static u32 ssb_pmu_get_alp_clock_clk0(struct ssb_chipcommon *cc) +{ +	u32 crystalfreq; +	const struct pmu0_plltab_entry *e = NULL; + +	crystalfreq = chipco_read32(cc, SSB_CHIPCO_PMU_CTL) & +		      SSB_CHIPCO_PMU_CTL_XTALFREQ >> SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT; +	e = pmu0_plltab_find_entry(crystalfreq); +	BUG_ON(!e); +	return e->freq * 1000; +} + +u32 ssb_pmu_get_alp_clock(struct ssb_chipcommon *cc) +{ +	struct ssb_bus *bus = cc->dev->bus; + +	switch (bus->chip_id) { +	case 0x5354: +		ssb_pmu_get_alp_clock_clk0(cc); +	default: +		ssb_err("ERROR: PMU alp clock unknown for device %04X\n", +			bus->chip_id); +		return 0; +	} +} + +u32 ssb_pmu_get_cpu_clock(struct ssb_chipcommon *cc) +{ +	struct ssb_bus *bus = cc->dev->bus; + +	switch (bus->chip_id) { +	case 0x5354: +		/* 5354 chip uses a non programmable PLL of frequency 240MHz */ +		return 240000000; +	default: +		ssb_err("ERROR: PMU cpu clock unknown for device %04X\n", +			bus->chip_id); +		return 0; +	} +} + +u32 ssb_pmu_get_controlclock(struct ssb_chipcommon *cc) +{ +	struct ssb_bus *bus = cc->dev->bus; + +	switch (bus->chip_id) { +	case 0x5354: +		return 120000000; +	default: +		ssb_err("ERROR: PMU controlclock unknown for device %04X\n", +			bus->chip_id); +		return 0; +	} +} + +void ssb_pmu_spuravoid_pllupdate(struct ssb_chipcommon *cc, int spuravoid) +{ +	u32 pmu_ctl = 0; + +	switch (cc->dev->bus->chip_id) { +	case 0x4322: +		ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL0, 0x11100070); +		ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL1, 0x1014140a); +		ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL5, 0x88888854); +		if (spuravoid == 1) +			ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL2, 0x05201828); +		else +			ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL2, 0x05001828); +		pmu_ctl = SSB_CHIPCO_PMU_CTL_PLL_UPD; +		break; +	case 43222: +		if (spuravoid == 1) { +			ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL0, 0x11500008); +			ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL1, 0x0C000C06); +			ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL2, 0x0F600a08); +			ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL3, 0x00000000); +			ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL4, 0x2001E920); +			ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL5, 0x88888815); +		} else { +			ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL0, 0x11100008); +			ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL1, 0x0c000c06); +			ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL2, 0x03000a08); +			ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL3, 0x00000000); +			ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL4, 0x200005c0); +			ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL5, 0x88888855); +		} +		pmu_ctl = SSB_CHIPCO_PMU_CTL_PLL_UPD; +		break; +	default: +		ssb_printk(KERN_ERR PFX +			   "Unknown spuravoidance settings for chip 0x%04X, not changing PLL\n", +			   cc->dev->bus->chip_id); +		return; +	} + +	chipco_set32(cc, SSB_CHIPCO_PMU_CTL, pmu_ctl); +} +EXPORT_SYMBOL_GPL(ssb_pmu_spuravoid_pllupdate); diff --git a/drivers/ssb/driver_chipcommon_sflash.c b/drivers/ssb/driver_chipcommon_sflash.c new file mode 100644 index 00000000000..937fc31971a --- /dev/null +++ b/drivers/ssb/driver_chipcommon_sflash.c @@ -0,0 +1,164 @@ +/* + * Sonics Silicon Backplane + * ChipCommon serial flash interface + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include <linux/ssb/ssb.h> + +#include "ssb_private.h" + +static struct resource ssb_sflash_resource = { +	.name	= "ssb_sflash", +	.start	= SSB_FLASH2, +	.end	= 0, +	.flags  = IORESOURCE_MEM | IORESOURCE_READONLY, +}; + +struct platform_device ssb_sflash_dev = { +	.name		= "ssb_sflash", +	.resource	= &ssb_sflash_resource, +	.num_resources	= 1, +}; + +struct ssb_sflash_tbl_e { +	char *name; +	u32 id; +	u32 blocksize; +	u16 numblocks; +}; + +static const struct ssb_sflash_tbl_e ssb_sflash_st_tbl[] = { +	{ "M25P20", 0x11, 0x10000, 4, }, +	{ "M25P40", 0x12, 0x10000, 8, }, + +	{ "M25P16", 0x14, 0x10000, 32, }, +	{ "M25P32", 0x15, 0x10000, 64, }, +	{ "M25P64", 0x16, 0x10000, 128, }, +	{ "M25FL128", 0x17, 0x10000, 256, }, +	{ NULL }, +}; + +static const struct ssb_sflash_tbl_e ssb_sflash_sst_tbl[] = { +	{ "SST25WF512", 1, 0x1000, 16, }, +	{ "SST25VF512", 0x48, 0x1000, 16, }, +	{ "SST25WF010", 2, 0x1000, 32, }, +	{ "SST25VF010", 0x49, 0x1000, 32, }, +	{ "SST25WF020", 3, 0x1000, 64, }, +	{ "SST25VF020", 0x43, 0x1000, 64, }, +	{ "SST25WF040", 4, 0x1000, 128, }, +	{ "SST25VF040", 0x44, 0x1000, 128, }, +	{ "SST25VF040B", 0x8d, 0x1000, 128, }, +	{ "SST25WF080", 5, 0x1000, 256, }, +	{ "SST25VF080B", 0x8e, 0x1000, 256, }, +	{ "SST25VF016", 0x41, 0x1000, 512, }, +	{ "SST25VF032", 0x4a, 0x1000, 1024, }, +	{ "SST25VF064", 0x4b, 0x1000, 2048, }, +	{ NULL }, +}; + +static const struct ssb_sflash_tbl_e ssb_sflash_at_tbl[] = { +	{ "AT45DB011", 0xc, 256, 512, }, +	{ "AT45DB021", 0x14, 256, 1024, }, +	{ "AT45DB041", 0x1c, 256, 2048, }, +	{ "AT45DB081", 0x24, 256, 4096, }, +	{ "AT45DB161", 0x2c, 512, 4096, }, +	{ "AT45DB321", 0x34, 512, 8192, }, +	{ "AT45DB642", 0x3c, 1024, 8192, }, +	{ NULL }, +}; + +static void ssb_sflash_cmd(struct ssb_chipcommon *cc, u32 opcode) +{ +	int i; +	chipco_write32(cc, SSB_CHIPCO_FLASHCTL, +		       SSB_CHIPCO_FLASHCTL_START | opcode); +	for (i = 0; i < 1000; i++) { +		if (!(chipco_read32(cc, SSB_CHIPCO_FLASHCTL) & +		      SSB_CHIPCO_FLASHCTL_BUSY)) +			return; +		cpu_relax(); +	} +	pr_err("SFLASH control command failed (timeout)!\n"); +} + +/* Initialize serial flash access */ +int ssb_sflash_init(struct ssb_chipcommon *cc) +{ +	struct ssb_sflash *sflash = &cc->dev->bus->mipscore.sflash; +	const struct ssb_sflash_tbl_e *e; +	u32 id, id2; + +	switch (cc->capabilities & SSB_CHIPCO_CAP_FLASHT) { +	case SSB_CHIPCO_FLASHT_STSER: +		ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_ST_DP); + +		chipco_write32(cc, SSB_CHIPCO_FLASHADDR, 0); +		ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_ST_RES); +		id = chipco_read32(cc, SSB_CHIPCO_FLASHDATA); + +		chipco_write32(cc, SSB_CHIPCO_FLASHADDR, 1); +		ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_ST_RES); +		id2 = chipco_read32(cc, SSB_CHIPCO_FLASHDATA); + +		switch (id) { +		case 0xbf: +			for (e = ssb_sflash_sst_tbl; e->name; e++) { +				if (e->id == id2) +					break; +			} +			break; +		case 0x13: +			return -ENOTSUPP; +		default: +			for (e = ssb_sflash_st_tbl; e->name; e++) { +				if (e->id == id) +					break; +			} +			break; +		} +		if (!e->name) { +			pr_err("Unsupported ST serial flash (id: 0x%X, id2: 0x%X)\n", +			       id, id2); +			return -ENOTSUPP; +		} + +		break; +	case SSB_CHIPCO_FLASHT_ATSER: +		ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_AT_STATUS); +		id = chipco_read32(cc, SSB_CHIPCO_FLASHDATA) & 0x3c; + +		for (e = ssb_sflash_at_tbl; e->name; e++) { +			if (e->id == id) +				break; +		} +		if (!e->name) { +			pr_err("Unsupported Atmel serial flash (id: 0x%X)\n", +			       id); +			return -ENOTSUPP; +		} + +		break; +	default: +		pr_err("Unsupported flash type\n"); +		return -ENOTSUPP; +	} + +	sflash->window = SSB_FLASH2; +	sflash->blocksize = e->blocksize; +	sflash->numblocks = e->numblocks; +	sflash->size = sflash->blocksize * sflash->numblocks; +	sflash->present = true; + +	pr_info("Found %s serial flash (size: %dKiB, blocksize: 0x%X, blocks: %d)\n", +		e->name, sflash->size / 1024, e->blocksize, e->numblocks); + +	/* Prepare platform device, but don't register it yet. It's too early, +	 * malloc (required by device_private_init) is not available yet. */ +	ssb_sflash_dev.resource[0].end = ssb_sflash_dev.resource[0].start + +					 sflash->size; +	ssb_sflash_dev.dev.platform_data = sflash; + +	return 0; +} diff --git a/drivers/ssb/driver_extif.c b/drivers/ssb/driver_extif.c index c3e1d3e6d61..59385fdab5b 100644 --- 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>   * @@ -112,10 +112,37 @@ void ssb_extif_get_clockcontrol(struct ssb_extif *extif,  	*m = extif_read32(extif, SSB_EXTIF_CLOCK_SB);  } -void ssb_extif_watchdog_timer_set(struct ssb_extif *extif, -				  u32 ticks) +u32 ssb_extif_watchdog_timer_set_wdt(struct bcm47xx_wdt *wdt, u32 ticks)  { +	struct ssb_extif *extif = bcm47xx_wdt_get_drvdata(wdt); + +	return ssb_extif_watchdog_timer_set(extif, ticks); +} + +u32 ssb_extif_watchdog_timer_set_ms(struct bcm47xx_wdt *wdt, u32 ms) +{ +	struct ssb_extif *extif = bcm47xx_wdt_get_drvdata(wdt); +	u32 ticks = (SSB_EXTIF_WATCHDOG_CLK / 1000) * ms; + +	ticks = ssb_extif_watchdog_timer_set(extif, ticks); + +	return (ticks * 1000) / SSB_EXTIF_WATCHDOG_CLK; +} + +u32 ssb_extif_watchdog_timer_set(struct ssb_extif *extif, u32 ticks) +{ +	if (ticks > SSB_EXTIF_WATCHDOG_MAX_TIMER) +		ticks = SSB_EXTIF_WATCHDOG_MAX_TIMER;  	extif_write32(extif, SSB_EXTIF_WATCHDOG, ticks); + +	return ticks; +} + +void ssb_extif_init(struct ssb_extif *extif) +{ +	if (!extif->dev) +		return; /* We don't have a Extif core */ +	spin_lock_init(&extif->gpio_lock);  }  u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask) @@ -125,22 +152,50 @@ u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask)  u32 ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, u32 value)  { -	return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUT(0), +	unsigned long flags; +	u32 res = 0; + +	spin_lock_irqsave(&extif->gpio_lock, flags); +	res = extif_write32_masked(extif, SSB_EXTIF_GPIO_OUT(0),  				   mask, value); +	spin_unlock_irqrestore(&extif->gpio_lock, flags); + +	return res;  }  u32 ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, u32 value)  { -	return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUTEN(0), +	unsigned long flags; +	u32 res = 0; + +	spin_lock_irqsave(&extif->gpio_lock, flags); +	res = extif_write32_masked(extif, SSB_EXTIF_GPIO_OUTEN(0),  				   mask, value); +	spin_unlock_irqrestore(&extif->gpio_lock, flags); + +	return res;  }  u32 ssb_extif_gpio_polarity(struct ssb_extif *extif, u32 mask, u32 value)  { -	return extif_write32_masked(extif, SSB_EXTIF_GPIO_INTPOL, mask, value); +	unsigned long flags; +	u32 res = 0; + +	spin_lock_irqsave(&extif->gpio_lock, flags); +	res = extif_write32_masked(extif, SSB_EXTIF_GPIO_INTPOL, mask, value); +	spin_unlock_irqrestore(&extif->gpio_lock, flags); + +	return res;  }  u32 ssb_extif_gpio_intmask(struct ssb_extif *extif, u32 mask, u32 value)  { -	return extif_write32_masked(extif, SSB_EXTIF_GPIO_INTMASK, mask, value); +	unsigned long flags; +	u32 res = 0; + +	spin_lock_irqsave(&extif->gpio_lock, flags); +	res = extif_write32_masked(extif, SSB_EXTIF_GPIO_INTMASK, mask, value); +	spin_unlock_irqrestore(&extif->gpio_lock, flags); + +	return res;  } diff --git a/drivers/ssb/driver_gige.c b/drivers/ssb/driver_gige.c index 5ba92a2719a..21f71a1581f 100644 --- a/drivers/ssb/driver_gige.c +++ b/drivers/ssb/driver_gige.c @@ -3,13 +3,14 @@   * 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.   */  #include <linux/ssb/ssb.h>  #include <linux/ssb/ssb_driver_gige.h> +#include <linux/export.h>  #include <linux/pci.h>  #include <linux/pci_regs.h>  #include <linux/slab.h> @@ -166,7 +167,8 @@ static int ssb_gige_pci_write_config(struct pci_bus *bus, unsigned int devfn,  	return PCIBIOS_SUCCESSFUL;  } -static int ssb_gige_probe(struct ssb_device *sdev, const struct ssb_device_id *id) +static int ssb_gige_probe(struct ssb_device *sdev, +			  const struct ssb_device_id *id)  {  	struct ssb_gige *dev;  	u32 base, tmslow, tmshigh; diff --git a/drivers/ssb/driver_gpio.c b/drivers/ssb/driver_gpio.c new file mode 100644 index 00000000000..ba350d2035c --- /dev/null +++ b/drivers/ssb/driver_gpio.c @@ -0,0 +1,484 @@ +/* + * Sonics Silicon Backplane + * GPIO driver + * + * Copyright 2011, Broadcom Corporation + * Copyright 2012, Hauke Mehrtens <hauke@hauke-m.de> + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include <linux/gpio.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/irqdomain.h> +#include <linux/export.h> +#include <linux/ssb/ssb.h> + +#include "ssb_private.h" + + +/************************************************** + * Shared + **************************************************/ + +static struct ssb_bus *ssb_gpio_get_bus(struct gpio_chip *chip) +{ +	return container_of(chip, struct ssb_bus, gpio); +} + +#if IS_ENABLED(CONFIG_SSB_EMBEDDED) +static int ssb_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) +{ +	struct ssb_bus *bus = ssb_gpio_get_bus(chip); + +	if (bus->bustype == SSB_BUSTYPE_SSB) +		return irq_find_mapping(bus->irq_domain, gpio); +	else +		return -EINVAL; +} +#endif + +/************************************************** + * ChipCommon + **************************************************/ + +static int ssb_gpio_chipco_get_value(struct gpio_chip *chip, unsigned gpio) +{ +	struct ssb_bus *bus = ssb_gpio_get_bus(chip); + +	return !!ssb_chipco_gpio_in(&bus->chipco, 1 << gpio); +} + +static void ssb_gpio_chipco_set_value(struct gpio_chip *chip, unsigned gpio, +				      int value) +{ +	struct ssb_bus *bus = ssb_gpio_get_bus(chip); + +	ssb_chipco_gpio_out(&bus->chipco, 1 << gpio, value ? 1 << gpio : 0); +} + +static int ssb_gpio_chipco_direction_input(struct gpio_chip *chip, +					   unsigned gpio) +{ +	struct ssb_bus *bus = ssb_gpio_get_bus(chip); + +	ssb_chipco_gpio_outen(&bus->chipco, 1 << gpio, 0); +	return 0; +} + +static int ssb_gpio_chipco_direction_output(struct gpio_chip *chip, +					    unsigned gpio, int value) +{ +	struct ssb_bus *bus = ssb_gpio_get_bus(chip); + +	ssb_chipco_gpio_outen(&bus->chipco, 1 << gpio, 1 << gpio); +	ssb_chipco_gpio_out(&bus->chipco, 1 << gpio, value ? 1 << gpio : 0); +	return 0; +} + +static int ssb_gpio_chipco_request(struct gpio_chip *chip, unsigned gpio) +{ +	struct ssb_bus *bus = ssb_gpio_get_bus(chip); + +	ssb_chipco_gpio_control(&bus->chipco, 1 << gpio, 0); +	/* clear pulldown */ +	ssb_chipco_gpio_pulldown(&bus->chipco, 1 << gpio, 0); +	/* Set pullup */ +	ssb_chipco_gpio_pullup(&bus->chipco, 1 << gpio, 1 << gpio); + +	return 0; +} + +static void ssb_gpio_chipco_free(struct gpio_chip *chip, unsigned gpio) +{ +	struct ssb_bus *bus = ssb_gpio_get_bus(chip); + +	/* clear pullup */ +	ssb_chipco_gpio_pullup(&bus->chipco, 1 << gpio, 0); +} + +#if IS_ENABLED(CONFIG_SSB_EMBEDDED) +static void ssb_gpio_irq_chipco_mask(struct irq_data *d) +{ +	struct ssb_bus *bus = irq_data_get_irq_chip_data(d); +	int gpio = irqd_to_hwirq(d); + +	ssb_chipco_gpio_intmask(&bus->chipco, BIT(gpio), 0); +} + +static void ssb_gpio_irq_chipco_unmask(struct irq_data *d) +{ +	struct ssb_bus *bus = irq_data_get_irq_chip_data(d); +	int gpio = irqd_to_hwirq(d); +	u32 val = ssb_chipco_gpio_in(&bus->chipco, BIT(gpio)); + +	ssb_chipco_gpio_polarity(&bus->chipco, BIT(gpio), val); +	ssb_chipco_gpio_intmask(&bus->chipco, BIT(gpio), BIT(gpio)); +} + +static struct irq_chip ssb_gpio_irq_chipco_chip = { +	.name		= "SSB-GPIO-CC", +	.irq_mask	= ssb_gpio_irq_chipco_mask, +	.irq_unmask	= ssb_gpio_irq_chipco_unmask, +}; + +static irqreturn_t ssb_gpio_irq_chipco_handler(int irq, void *dev_id) +{ +	struct ssb_bus *bus = dev_id; +	struct ssb_chipcommon *chipco = &bus->chipco; +	u32 val = chipco_read32(chipco, SSB_CHIPCO_GPIOIN); +	u32 mask = chipco_read32(chipco, SSB_CHIPCO_GPIOIRQ); +	u32 pol = chipco_read32(chipco, SSB_CHIPCO_GPIOPOL); +	unsigned long irqs = (val ^ pol) & mask; +	int gpio; + +	if (!irqs) +		return IRQ_NONE; + +	for_each_set_bit(gpio, &irqs, bus->gpio.ngpio) +		generic_handle_irq(ssb_gpio_to_irq(&bus->gpio, gpio)); +	ssb_chipco_gpio_polarity(chipco, irqs, val & irqs); + +	return IRQ_HANDLED; +} + +static int ssb_gpio_irq_chipco_domain_init(struct ssb_bus *bus) +{ +	struct ssb_chipcommon *chipco = &bus->chipco; +	struct gpio_chip *chip = &bus->gpio; +	int gpio, hwirq, err; + +	if (bus->bustype != SSB_BUSTYPE_SSB) +		return 0; + +	bus->irq_domain = irq_domain_add_linear(NULL, chip->ngpio, +						&irq_domain_simple_ops, chipco); +	if (!bus->irq_domain) { +		err = -ENODEV; +		goto err_irq_domain; +	} +	for (gpio = 0; gpio < chip->ngpio; gpio++) { +		int irq = irq_create_mapping(bus->irq_domain, gpio); + +		irq_set_chip_data(irq, bus); +		irq_set_chip_and_handler(irq, &ssb_gpio_irq_chipco_chip, +					 handle_simple_irq); +	} + +	hwirq = ssb_mips_irq(bus->chipco.dev) + 2; +	err = request_irq(hwirq, ssb_gpio_irq_chipco_handler, IRQF_SHARED, +			  "gpio", bus); +	if (err) +		goto err_req_irq; + +	ssb_chipco_gpio_intmask(&bus->chipco, ~0, 0); +	chipco_set32(chipco, SSB_CHIPCO_IRQMASK, SSB_CHIPCO_IRQ_GPIO); + +	return 0; + +err_req_irq: +	for (gpio = 0; gpio < chip->ngpio; gpio++) { +		int irq = irq_find_mapping(bus->irq_domain, gpio); + +		irq_dispose_mapping(irq); +	} +	irq_domain_remove(bus->irq_domain); +err_irq_domain: +	return err; +} + +static void ssb_gpio_irq_chipco_domain_exit(struct ssb_bus *bus) +{ +	struct ssb_chipcommon *chipco = &bus->chipco; +	struct gpio_chip *chip = &bus->gpio; +	int gpio; + +	if (bus->bustype != SSB_BUSTYPE_SSB) +		return; + +	chipco_mask32(chipco, SSB_CHIPCO_IRQMASK, ~SSB_CHIPCO_IRQ_GPIO); +	free_irq(ssb_mips_irq(bus->chipco.dev) + 2, chipco); +	for (gpio = 0; gpio < chip->ngpio; gpio++) { +		int irq = irq_find_mapping(bus->irq_domain, gpio); + +		irq_dispose_mapping(irq); +	} +	irq_domain_remove(bus->irq_domain); +} +#else +static int ssb_gpio_irq_chipco_domain_init(struct ssb_bus *bus) +{ +	return 0; +} + +static void ssb_gpio_irq_chipco_domain_exit(struct ssb_bus *bus) +{ +} +#endif + +static int ssb_gpio_chipco_init(struct ssb_bus *bus) +{ +	struct gpio_chip *chip = &bus->gpio; +	int err; + +	chip->label		= "ssb_chipco_gpio"; +	chip->owner		= THIS_MODULE; +	chip->request		= ssb_gpio_chipco_request; +	chip->free		= ssb_gpio_chipco_free; +	chip->get		= ssb_gpio_chipco_get_value; +	chip->set		= ssb_gpio_chipco_set_value; +	chip->direction_input	= ssb_gpio_chipco_direction_input; +	chip->direction_output	= ssb_gpio_chipco_direction_output; +#if IS_ENABLED(CONFIG_SSB_EMBEDDED) +	chip->to_irq		= ssb_gpio_to_irq; +#endif +	chip->ngpio		= 16; +	/* There is just one SoC in one device and its GPIO addresses should be +	 * deterministic to address them more easily. The other buses could get +	 * a random base number. */ +	if (bus->bustype == SSB_BUSTYPE_SSB) +		chip->base		= 0; +	else +		chip->base		= -1; + +	err = ssb_gpio_irq_chipco_domain_init(bus); +	if (err) +		return err; + +	err = gpiochip_add(chip); +	if (err) { +		ssb_gpio_irq_chipco_domain_exit(bus); +		return err; +	} + +	return 0; +} + +/************************************************** + * EXTIF + **************************************************/ + +#ifdef CONFIG_SSB_DRIVER_EXTIF + +static int ssb_gpio_extif_get_value(struct gpio_chip *chip, unsigned gpio) +{ +	struct ssb_bus *bus = ssb_gpio_get_bus(chip); + +	return !!ssb_extif_gpio_in(&bus->extif, 1 << gpio); +} + +static void ssb_gpio_extif_set_value(struct gpio_chip *chip, unsigned gpio, +				     int value) +{ +	struct ssb_bus *bus = ssb_gpio_get_bus(chip); + +	ssb_extif_gpio_out(&bus->extif, 1 << gpio, value ? 1 << gpio : 0); +} + +static int ssb_gpio_extif_direction_input(struct gpio_chip *chip, +					  unsigned gpio) +{ +	struct ssb_bus *bus = ssb_gpio_get_bus(chip); + +	ssb_extif_gpio_outen(&bus->extif, 1 << gpio, 0); +	return 0; +} + +static int ssb_gpio_extif_direction_output(struct gpio_chip *chip, +					   unsigned gpio, int value) +{ +	struct ssb_bus *bus = ssb_gpio_get_bus(chip); + +	ssb_extif_gpio_outen(&bus->extif, 1 << gpio, 1 << gpio); +	ssb_extif_gpio_out(&bus->extif, 1 << gpio, value ? 1 << gpio : 0); +	return 0; +} + +#if IS_ENABLED(CONFIG_SSB_EMBEDDED) +static void ssb_gpio_irq_extif_mask(struct irq_data *d) +{ +	struct ssb_bus *bus = irq_data_get_irq_chip_data(d); +	int gpio = irqd_to_hwirq(d); + +	ssb_extif_gpio_intmask(&bus->extif, BIT(gpio), 0); +} + +static void ssb_gpio_irq_extif_unmask(struct irq_data *d) +{ +	struct ssb_bus *bus = irq_data_get_irq_chip_data(d); +	int gpio = irqd_to_hwirq(d); +	u32 val = ssb_extif_gpio_in(&bus->extif, BIT(gpio)); + +	ssb_extif_gpio_polarity(&bus->extif, BIT(gpio), val); +	ssb_extif_gpio_intmask(&bus->extif, BIT(gpio), BIT(gpio)); +} + +static struct irq_chip ssb_gpio_irq_extif_chip = { +	.name		= "SSB-GPIO-EXTIF", +	.irq_mask	= ssb_gpio_irq_extif_mask, +	.irq_unmask	= ssb_gpio_irq_extif_unmask, +}; + +static irqreturn_t ssb_gpio_irq_extif_handler(int irq, void *dev_id) +{ +	struct ssb_bus *bus = dev_id; +	struct ssb_extif *extif = &bus->extif; +	u32 val = ssb_read32(extif->dev, SSB_EXTIF_GPIO_IN); +	u32 mask = ssb_read32(extif->dev, SSB_EXTIF_GPIO_INTMASK); +	u32 pol = ssb_read32(extif->dev, SSB_EXTIF_GPIO_INTPOL); +	unsigned long irqs = (val ^ pol) & mask; +	int gpio; + +	if (!irqs) +		return IRQ_NONE; + +	for_each_set_bit(gpio, &irqs, bus->gpio.ngpio) +		generic_handle_irq(ssb_gpio_to_irq(&bus->gpio, gpio)); +	ssb_extif_gpio_polarity(extif, irqs, val & irqs); + +	return IRQ_HANDLED; +} + +static int ssb_gpio_irq_extif_domain_init(struct ssb_bus *bus) +{ +	struct ssb_extif *extif = &bus->extif; +	struct gpio_chip *chip = &bus->gpio; +	int gpio, hwirq, err; + +	if (bus->bustype != SSB_BUSTYPE_SSB) +		return 0; + +	bus->irq_domain = irq_domain_add_linear(NULL, chip->ngpio, +						&irq_domain_simple_ops, extif); +	if (!bus->irq_domain) { +		err = -ENODEV; +		goto err_irq_domain; +	} +	for (gpio = 0; gpio < chip->ngpio; gpio++) { +		int irq = irq_create_mapping(bus->irq_domain, gpio); + +		irq_set_chip_data(irq, bus); +		irq_set_chip_and_handler(irq, &ssb_gpio_irq_extif_chip, +					 handle_simple_irq); +	} + +	hwirq = ssb_mips_irq(bus->extif.dev) + 2; +	err = request_irq(hwirq, ssb_gpio_irq_extif_handler, IRQF_SHARED, +			  "gpio", bus); +	if (err) +		goto err_req_irq; + +	ssb_extif_gpio_intmask(&bus->extif, ~0, 0); + +	return 0; + +err_req_irq: +	for (gpio = 0; gpio < chip->ngpio; gpio++) { +		int irq = irq_find_mapping(bus->irq_domain, gpio); + +		irq_dispose_mapping(irq); +	} +	irq_domain_remove(bus->irq_domain); +err_irq_domain: +	return err; +} + +static void ssb_gpio_irq_extif_domain_exit(struct ssb_bus *bus) +{ +	struct ssb_extif *extif = &bus->extif; +	struct gpio_chip *chip = &bus->gpio; +	int gpio; + +	if (bus->bustype != SSB_BUSTYPE_SSB) +		return; + +	free_irq(ssb_mips_irq(bus->extif.dev) + 2, extif); +	for (gpio = 0; gpio < chip->ngpio; gpio++) { +		int irq = irq_find_mapping(bus->irq_domain, gpio); + +		irq_dispose_mapping(irq); +	} +	irq_domain_remove(bus->irq_domain); +} +#else +static int ssb_gpio_irq_extif_domain_init(struct ssb_bus *bus) +{ +	return 0; +} + +static void ssb_gpio_irq_extif_domain_exit(struct ssb_bus *bus) +{ +} +#endif + +static int ssb_gpio_extif_init(struct ssb_bus *bus) +{ +	struct gpio_chip *chip = &bus->gpio; +	int err; + +	chip->label		= "ssb_extif_gpio"; +	chip->owner		= THIS_MODULE; +	chip->get		= ssb_gpio_extif_get_value; +	chip->set		= ssb_gpio_extif_set_value; +	chip->direction_input	= ssb_gpio_extif_direction_input; +	chip->direction_output	= ssb_gpio_extif_direction_output; +#if IS_ENABLED(CONFIG_SSB_EMBEDDED) +	chip->to_irq		= ssb_gpio_to_irq; +#endif +	chip->ngpio		= 5; +	/* There is just one SoC in one device and its GPIO addresses should be +	 * deterministic to address them more easily. The other buses could get +	 * a random base number. */ +	if (bus->bustype == SSB_BUSTYPE_SSB) +		chip->base		= 0; +	else +		chip->base		= -1; + +	err = ssb_gpio_irq_extif_domain_init(bus); +	if (err) +		return err; + +	err = gpiochip_add(chip); +	if (err) { +		ssb_gpio_irq_extif_domain_exit(bus); +		return err; +	} + +	return 0; +} + +#else +static int ssb_gpio_extif_init(struct ssb_bus *bus) +{ +	return -ENOTSUPP; +} +#endif + +/************************************************** + * Init + **************************************************/ + +int ssb_gpio_init(struct ssb_bus *bus) +{ +	if (ssb_chipco_available(&bus->chipco)) +		return ssb_gpio_chipco_init(bus); +	else if (ssb_extif_available(&bus->extif)) +		return ssb_gpio_extif_init(bus); +	else +		SSB_WARN_ON(1); + +	return -1; +} + +int ssb_gpio_unregister(struct ssb_bus *bus) +{ +	if (ssb_chipco_available(&bus->chipco) || +	    ssb_extif_available(&bus->extif)) { +		return gpiochip_remove(&bus->gpio); +	} else { +		SSB_WARN_ON(1); +	} + +	return -1; +} diff --git a/drivers/ssb/driver_mipscore.c b/drivers/ssb/driver_mipscore.c index 97efce184a8..09077067b0c 100644 --- a/drivers/ssb/driver_mipscore.c +++ b/drivers/ssb/driver_mipscore.c @@ -3,13 +3,14 @@   * 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.   */  #include <linux/ssb/ssb.h> +#include <linux/mtd/physmap.h>  #include <linux/serial.h>  #include <linux/serial_core.h>  #include <linux/serial_reg.h> @@ -17,6 +18,25 @@  #include "ssb_private.h" +static const char * const part_probes[] = { "bcm47xxpart", NULL }; + +static struct physmap_flash_data ssb_pflash_data = { +	.part_probe_types	= part_probes, +}; + +static struct resource ssb_pflash_resource = { +	.name	= "ssb_pflash", +	.flags  = IORESOURCE_MEM, +}; + +struct platform_device ssb_pflash_dev = { +	.name		= "physmap-flash", +	.dev		= { +		.platform_data  = &ssb_pflash_data, +	}, +	.resource	= &ssb_pflash_resource, +	.num_resources	= 1, +};  static inline u32 mips_read32(struct ssb_mipscore *mcore,  			      u16 offset) @@ -147,21 +167,22 @@ static void set_irq(struct ssb_device *dev, unsigned int irq)  		irqflag |= (ipsflag & ~ipsflag_irq_mask[irq]);  		ssb_write32(mdev, SSB_IPSFLAG, irqflag);  	} -	ssb_dprintk(KERN_INFO PFX -		    "set_irq: core 0x%04x, irq %d => %d\n", -		    dev->id.coreid, oldirq+2, irq+2); +	ssb_dbg("set_irq: core 0x%04x, irq %d => %d\n", +		dev->id.coreid, oldirq+2, irq+2);  }  static void print_irq(struct ssb_device *dev, unsigned int irq)  { -	int i;  	static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"}; -	ssb_dprintk(KERN_INFO PFX -		"core 0x%04x, irq :", dev->id.coreid); -	for (i = 0; i <= 6; i++) { -		ssb_dprintk(" %s%s", irq_name[i], i==irq?"*":" "); -	} -	ssb_dprintk("\n"); +	ssb_dbg("core 0x%04x, irq : %s%s %s%s %s%s %s%s %s%s %s%s %s%s\n", +		dev->id.coreid, +		irq_name[0], irq == 0 ? "*" : " ", +		irq_name[1], irq == 1 ? "*" : " ", +		irq_name[2], irq == 2 ? "*" : " ", +		irq_name[3], irq == 3 ? "*" : " ", +		irq_name[4], irq == 4 ? "*" : " ", +		irq_name[5], irq == 5 ? "*" : " ", +		irq_name[6], irq == 6 ? "*" : " ");  }  static void dump_irq(struct ssb_bus *bus) @@ -178,9 +199,9 @@ static void ssb_mips_serial_init(struct ssb_mipscore *mcore)  {  	struct ssb_bus *bus = mcore->dev->bus; -	if (bus->extif.dev) +	if (ssb_extif_available(&bus->extif))  		mcore->nr_serial_ports = ssb_extif_serial_init(&bus->extif, mcore->serial_ports); -	else if (bus->chipco.dev) +	else if (ssb_chipco_available(&bus->chipco))  		mcore->nr_serial_ports = ssb_chipco_serial_init(&bus->chipco, mcore->serial_ports);  	else  		mcore->nr_serial_ports = 0; @@ -189,17 +210,42 @@ static void ssb_mips_serial_init(struct ssb_mipscore *mcore)  static void ssb_mips_flash_detect(struct ssb_mipscore *mcore)  {  	struct ssb_bus *bus = mcore->dev->bus; +	struct ssb_pflash *pflash = &mcore->pflash; + +	/* When there is no chipcommon on the bus there is 4MB flash */ +	if (!ssb_chipco_available(&bus->chipco)) { +		pflash->present = true; +		pflash->buswidth = 2; +		pflash->window = SSB_FLASH1; +		pflash->window_size = SSB_FLASH1_SZ; +		goto ssb_pflash; +	} -	mcore->flash_buswidth = 2; -	if (bus->chipco.dev) { -		mcore->flash_window = 0x1c000000; -		mcore->flash_window_size = 0x02000000; +	/* There is ChipCommon, so use it to read info about flash */ +	switch (bus->chipco.capabilities & SSB_CHIPCO_CAP_FLASHT) { +	case SSB_CHIPCO_FLASHT_STSER: +	case SSB_CHIPCO_FLASHT_ATSER: +		pr_debug("Found serial flash\n"); +		ssb_sflash_init(&bus->chipco); +		break; +	case SSB_CHIPCO_FLASHT_PARA: +		pr_debug("Found parallel flash\n"); +		pflash->present = true; +		pflash->window = SSB_FLASH2; +		pflash->window_size = SSB_FLASH2_SZ;  		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 = 0x00400000; +			pflash->buswidth = 1; +		else +			pflash->buswidth = 2; +		break; +	} + +ssb_pflash: +	if (pflash->present) { +		ssb_pflash_data.width = pflash->buswidth; +		ssb_pflash_resource.start = pflash->window; +		ssb_pflash_resource.end = pflash->window + pflash->window_size;  	}  } @@ -208,9 +254,12 @@ 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) { +	if (bus->chipco.capabilities & SSB_CHIPCO_CAP_PMU) +		return ssb_pmu_get_cpu_clock(&bus->chipco); + +	if (ssb_extif_available(&bus->extif)) {  		ssb_extif_get_clockcontrol(&bus->extif, &pll_type, &n, &m); -	} else if (bus->chipco.dev) { +	} else if (ssb_chipco_available(&bus->chipco)) {  		ssb_chipco_get_clockcpu(&bus->chipco, &pll_type, &n, &m);  	} else  		return 0; @@ -238,7 +287,7 @@ void ssb_mipscore_init(struct ssb_mipscore *mcore)  	if (!mcore->dev)  		return; /* We don't have a MIPS core */ -	ssb_dprintk(KERN_INFO PFX "Initializing MIPS core...\n"); +	ssb_dbg("Initializing MIPS core...\n");  	bus = mcore->dev->bus;  	hz = ssb_clockspeed(bus); @@ -246,9 +295,9 @@ void ssb_mipscore_init(struct ssb_mipscore *mcore)  		hz = 100000000;  	ns = 1000000000 / hz; -	if (bus->extif.dev) +	if (ssb_extif_available(&bus->extif))  		ssb_extif_timing_init(&bus->extif, ns); -	else if (bus->chipco.dev) +	else if (ssb_chipco_available(&bus->chipco))  		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 */ @@ -286,7 +335,7 @@ void ssb_mipscore_init(struct ssb_mipscore *mcore)  			break;  		}  	} -	ssb_dprintk(KERN_INFO PFX "after irq reconfiguration\n"); +	ssb_dbg("after irq reconfiguration\n");  	dump_irq(bus);  	ssb_mips_serial_init(mcore); diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c index 0e8d3522461..d75b72ba267 100644 --- a/drivers/ssb/driver_pcicore.c +++ b/drivers/ssb/driver_pcicore.c @@ -3,18 +3,24 @@   * 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.   */  #include <linux/ssb/ssb.h>  #include <linux/pci.h> +#include <linux/export.h>  #include <linux/delay.h>  #include <linux/ssb/ssb_embedded.h>  #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) @@ -69,7 +75,7 @@ static u32 get_cfgspace_addr(struct ssb_pcicore *pc,  	u32 tmp;  	/* We do only have one cardbus device behind the bridge. */ -	if (pc->cardbusmode && (dev >= 1)) +	if (pc->cardbusmode && (dev > 1))  		goto out;  	if (bus == 0) { @@ -257,8 +263,7 @@ int ssb_pcicore_plat_dev_init(struct pci_dev *d)  		return -ENODEV;  	} -	ssb_printk(KERN_INFO "PCI: Fixing up device %s\n", -		   pci_name(d)); +	ssb_info("PCI: Fixing up device %s\n", pci_name(d));  	/* Fix up interrupt lines */  	d->irq = ssb_mips_irq(extpci_core->dev) + 2; @@ -279,12 +284,12 @@ static void ssb_pcicore_fixup_pcibridge(struct pci_dev *dev)  	if (dev->bus->number != 0 || PCI_SLOT(dev->devfn) != 0)  		return; -	ssb_printk(KERN_INFO "PCI: Fixing up bridge %s\n", pci_name(dev)); +	ssb_info("PCI: Fixing up bridge %s\n", pci_name(dev));  	/* Enable PCI bridge bus mastering and memory space */  	pci_set_master(dev);  	if (pcibios_enable_device(dev, ~0) < 0) { -		ssb_printk(KERN_ERR "PCI: SSB bridge enable failed\n"); +		ssb_err("PCI: SSB bridge enable failed\n");  		return;  	} @@ -293,8 +298,8 @@ static void ssb_pcicore_fixup_pcibridge(struct pci_dev *dev)  	/* Make sure our latency is high enough to handle the devices behind us */  	lat = 168; -	ssb_printk(KERN_INFO "PCI: Fixing latency timer of device %s to %u\n", -		   pci_name(dev), lat); +	ssb_info("PCI: Fixing latency timer of device %s to %u\n", +		 pci_name(dev), lat);  	pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);  }  DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ssb_pcicore_fixup_pcibridge); @@ -317,7 +322,7 @@ static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc)  		return;  	extpci_core = pc; -	ssb_dprintk(KERN_INFO PFX "PCIcore in host mode found\n"); +	ssb_dbg("PCIcore in host mode found\n");  	/* Reset devices on the external PCI bus */  	val = SSB_PCICORE_CTL_RST_OE;  	val |= SSB_PCICORE_CTL_CLK_OE; @@ -332,7 +337,7 @@ static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc)  	udelay(1); /* Assertion time demanded by the PCI standard */  	if (pc->dev->bus->has_cardbus_slot) { -		ssb_dprintk(KERN_INFO PFX "CardBus slot detected\n"); +		ssb_dbg("CardBus slot detected\n");  		pc->cardbusmode = 1;  		/* GPIO 1 resets the bridge */  		ssb_gpio_out(pc->dev->bus, 1, 1); @@ -403,6 +408,107 @@ static int pcicore_is_in_hostmode(struct ssb_pcicore *pc)  }  #endif /* CONFIG_SSB_PCICORE_HOSTMODE */ +/************************************************** + * Workarounds. + **************************************************/ + +static void 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. @@ -410,18 +516,29 @@ static int pcicore_is_in_hostmode(struct ssb_pcicore *pc)  static void 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)  {  	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_pcicore *pc, u32 address, u32 data)  	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 ssb_pcicore *pc, u8 device,  	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); - -	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 */ -} +	const u16 mdio_control = 0x128; +	const u16 mdio_data = 0x12C; +	int max_retries = 10; +	u32 v; +	int i; -static void ssb_commit_settings(struct ssb_bus *bus) -{ -	struct ssb_device *dev; +	v = 0x80; /* Enable Preamble Sequence */ +	v |= 0x2; /* MDIO Clock Divisor */ +	pcicore_write32(pc, mdio_control, v); -	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); +	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 << 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(struct ssb_pcicore *pc,  	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: diff --git a/drivers/ssb/embedded.c b/drivers/ssb/embedded.c index a0e0d246b59..55e10111503 100644 --- a/drivers/ssb/embedded.c +++ b/drivers/ssb/embedded.c @@ -3,11 +3,14 @@   * 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> + * Copyright 2012, Hauke Mehrtens <hauke@hauke-m.de>   *   * Licensed under the GNU/GPL. See COPYING for details.   */ +#include <linux/export.h> +#include <linux/platform_device.h>  #include <linux/ssb/ssb.h>  #include <linux/ssb/ssb_embedded.h>  #include <linux/ssb/ssb_driver_pci.h> @@ -31,6 +34,38 @@ int ssb_watchdog_timer_set(struct ssb_bus *bus, u32 ticks)  }  EXPORT_SYMBOL(ssb_watchdog_timer_set); +int ssb_watchdog_register(struct ssb_bus *bus) +{ +	struct bcm47xx_wdt wdt = {}; +	struct platform_device *pdev; + +	if (ssb_chipco_available(&bus->chipco)) { +		wdt.driver_data = &bus->chipco; +		wdt.timer_set = ssb_chipco_watchdog_timer_set_wdt; +		wdt.timer_set_ms = ssb_chipco_watchdog_timer_set_ms; +		wdt.max_timer_ms = bus->chipco.max_timer_ms; +	} else if (ssb_extif_available(&bus->extif)) { +		wdt.driver_data = &bus->extif; +		wdt.timer_set = ssb_extif_watchdog_timer_set_wdt; +		wdt.timer_set_ms = ssb_extif_watchdog_timer_set_ms; +		wdt.max_timer_ms = SSB_EXTIF_WATCHDOG_MAX_TIMER_MS; +	} else { +		return -ENODEV; +	} + +	pdev = platform_device_register_data(NULL, "bcm47xx-wdt", +					     bus->busnumber, &wdt, +					     sizeof(wdt)); +	if (IS_ERR(pdev)) { +		ssb_dbg("can not register watchdog device, err: %li\n", +			PTR_ERR(pdev)); +		return PTR_ERR(pdev); +	} + +	bus->watchdog = pdev; +	return 0; +} +  u32 ssb_gpio_in(struct ssb_bus *bus, u32 mask)  {  	unsigned long flags; diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index c68b3dc19e1..2fead382084 100644 --- 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,8 @@  #include <linux/delay.h>  #include <linux/io.h> +#include <linux/module.h> +#include <linux/platform_device.h>  #include <linux/ssb/ssb.h>  #include <linux/ssb/ssb_regs.h>  #include <linux/ssb/ssb_driver_gige.h> @@ -139,19 +141,6 @@ static void ssb_device_put(struct ssb_device *dev)  		put_device(dev->dev);  } -static inline struct ssb_driver *ssb_driver_get(struct ssb_driver *drv) -{ -	if (drv) -		get_driver(&drv->drv); -	return drv; -} - -static inline void ssb_driver_put(struct ssb_driver *drv) -{ -	if (drv) -		put_driver(&drv->drv); -} -  static int ssb_device_resume(struct device *dev)  {  	struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); @@ -249,11 +238,9 @@ int ssb_devices_freeze(struct ssb_bus *bus, struct ssb_freeze_context *ctx)  			ssb_device_put(sdev);  			continue;  		} -		sdrv = ssb_driver_get(drv_to_ssb_drv(sdev->dev->driver)); -		if (!sdrv || SSB_WARN_ON(!sdrv->remove)) { -			ssb_device_put(sdev); +		sdrv = drv_to_ssb_drv(sdev->dev->driver); +		if (SSB_WARN_ON(!sdrv->remove))  			continue; -		}  		sdrv->remove(sdev);  		ctx->device_frozen[i] = 1;  	} @@ -288,11 +275,10 @@ int ssb_devices_thaw(struct ssb_freeze_context *ctx)  		err = sdrv->probe(sdev, &sdev->id);  		if (err) { -			ssb_printk(KERN_ERR PFX "Failed to thaw device %s\n", -				   dev_name(sdev->dev)); +			ssb_err("Failed to thaw device %s\n", +				dev_name(sdev->dev));  			result = err;  		} -		ssb_driver_put(sdrv);  		ssb_device_put(sdev);  	} @@ -383,6 +369,38 @@ static int ssb_device_uevent(struct device *dev, struct kobj_uevent_env *env)  			     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); \ +} \ +static DEVICE_ATTR_RO(attrib); + +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 DEVICE_ATTR_RO(name); + +static struct attribute *ssb_device_attrs[] = { +	&dev_attr_name.attr, +	&dev_attr_core_num.attr, +	&dev_attr_coreid.attr, +	&dev_attr_vendor.attr, +	&dev_attr_revision.attr, +	&dev_attr_irq.attr, +	NULL, +}; +ATTRIBUTE_GROUPS(ssb_device); +  static struct bus_type ssb_bustype = {  	.name		= "ssb",  	.match		= ssb_bus_match, @@ -392,6 +410,7 @@ static struct bus_type ssb_bustype = {  	.suspend	= ssb_device_suspend,  	.resume		= ssb_device_resume,  	.uevent		= ssb_device_uevent, +	.dev_groups	= ssb_device_groups,  };  static void ssb_buses_lock(void) @@ -418,10 +437,23 @@ static void ssb_devices_unregister(struct ssb_bus *bus)  		if (sdev->dev)  			device_unregister(sdev->dev);  	} + +#ifdef CONFIG_SSB_EMBEDDED +	if (bus->bustype == SSB_BUSTYPE_SSB) +		platform_device_unregister(bus->watchdog); +#endif  }  void ssb_bus_unregister(struct ssb_bus *bus)  { +	int err; + +	err = ssb_gpio_unregister(bus); +	if (err == -EBUSY) +		ssb_dbg("Some GPIOs are still in use\n"); +	else if (err) +		ssb_dbg("Can not unregister GPIO driver: %i\n", err); +  	ssb_buses_lock();  	ssb_devices_unregister(bus);  	list_del(&bus->list); @@ -467,8 +499,7 @@ static int ssb_devices_register(struct ssb_bus *bus)  		devwrap = kzalloc(sizeof(*devwrap), GFP_KERNEL);  		if (!devwrap) { -			ssb_printk(KERN_ERR PFX -				   "Could not allocate device\n"); +			ssb_err("Could not allocate device\n");  			err = -ENOMEM;  			goto error;  		} @@ -507,9 +538,7 @@ static int ssb_devices_register(struct ssb_bus *bus)  		sdev->dev = dev;  		err = device_register(dev);  		if (err) { -			ssb_printk(KERN_ERR PFX -				   "Could not register %s\n", -				   dev_name(dev)); +			ssb_err("Could not register %s\n", dev_name(dev));  			/* Set dev to NULL to not unregister  			 * dev on error unwinding. */  			sdev->dev = NULL; @@ -519,6 +548,22 @@ static int ssb_devices_register(struct ssb_bus *bus)  		dev_idx++;  	} +#ifdef CONFIG_SSB_DRIVER_MIPS +	if (bus->mipscore.pflash.present) { +		err = platform_device_register(&ssb_pflash_dev); +		if (err) +			pr_err("Error registering parallel flash\n"); +	} +#endif + +#ifdef CONFIG_SSB_SFLASH +	if (bus->mipscore.sflash.present) { +		err = platform_device_register(&ssb_sflash_dev); +		if (err) +			pr_err("Error registering serial flash\n"); +	} +#endif +  	return 0;  error:  	/* Unwind the already registered devices. */ @@ -546,6 +591,15 @@ static int ssb_attach_queued_buses(void)  		if (err)  			goto error;  		ssb_pcicore_init(&bus->pcicore); +		if (bus->bustype == SSB_BUSTYPE_SSB) +			ssb_watchdog_register(bus); + +		err = ssb_gpio_init(bus); +		if (err == -ENOTSUPP) +			ssb_dbg("GPIO driver not activated\n"); +		else if (err) +			ssb_dbg("Error registering GPIO driver: %i\n", err); +  		ssb_bus_may_powerdown(bus);  		err = ssb_devices_register(bus); @@ -781,6 +835,7 @@ static int ssb_bus_register(struct ssb_bus *bus,  	if (err)  		goto err_pcmcia_exit;  	ssb_chipcommon_init(&bus->chipco); +	ssb_extif_init(&bus->extif);  	ssb_mipscore_init(&bus->mipscore);  	err = ssb_fetch_invariants(bus, get_invariants);  	if (err) { @@ -821,8 +876,7 @@ err_disable_xtal:  }  #ifdef CONFIG_SSB_PCIHOST -int ssb_bus_pcibus_register(struct ssb_bus *bus, -			    struct pci_dev *host_pci) +int ssb_bus_pcibus_register(struct ssb_bus *bus, struct pci_dev *host_pci)  {  	int err; @@ -832,11 +886,11 @@ int ssb_bus_pcibus_register(struct ssb_bus *bus,  	err = ssb_bus_register(bus, ssb_pci_get_invariants, 0);  	if (!err) { -		ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found on " -			   "PCI device %s\n", dev_name(&host_pci->dev)); +		ssb_info("Sonics Silicon Backplane found on PCI device %s\n", +			 dev_name(&host_pci->dev));  	} else { -		ssb_printk(KERN_ERR PFX "Failed to register PCI version" -			   " of SSB with error %d\n", err); +		ssb_err("Failed to register PCI version of SSB with error %d\n", +			err);  	}  	return err; @@ -857,8 +911,8 @@ int ssb_bus_pcmciabus_register(struct ssb_bus *bus,  	err = ssb_bus_register(bus, ssb_pcmcia_get_invariants, baseaddr);  	if (!err) { -		ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found on " -			   "PCMCIA device %s\n", pcmcia_dev->devname); +		ssb_info("Sonics Silicon Backplane found on PCMCIA device %s\n", +			 pcmcia_dev->devname);  	}  	return err; @@ -879,8 +933,8 @@ int ssb_bus_sdiobus_register(struct ssb_bus *bus, struct sdio_func *func,  	err = ssb_bus_register(bus, ssb_sdio_get_invariants, ~0);  	if (!err) { -		ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found on " -			   "SDIO device %s\n", sdio_func_id(func)); +		ssb_info("Sonics Silicon Backplane found on SDIO device %s\n", +			 sdio_func_id(func));  	}  	return err; @@ -888,8 +942,7 @@ int ssb_bus_sdiobus_register(struct ssb_bus *bus, struct sdio_func *func,  EXPORT_SYMBOL(ssb_bus_sdiobus_register);  #endif /* CONFIG_SSB_PCMCIAHOST */ -int ssb_bus_ssbbus_register(struct ssb_bus *bus, -			    unsigned long baseaddr, +int ssb_bus_ssbbus_register(struct ssb_bus *bus, unsigned long baseaddr,  			    ssb_invariants_func_t get_invariants)  {  	int err; @@ -899,8 +952,8 @@ int ssb_bus_ssbbus_register(struct ssb_bus *bus,  	err = ssb_bus_register(bus, get_invariants, baseaddr);  	if (!err) { -		ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found at " -			   "address 0x%08lX\n", baseaddr); +		ssb_info("Sonics Silicon Backplane found at address 0x%08lX\n", +			 baseaddr);  	}  	return err; @@ -971,8 +1024,8 @@ u32 ssb_calc_clock_rate(u32 plltype, u32 n, u32 m)  	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 */ @@ -1062,6 +1115,9 @@ u32 ssb_clockspeed(struct ssb_bus *bus)  	u32 plltype;  	u32 clkctl_n, clkctl_m; +	if (bus->chipco.capabilities & SSB_CHIPCO_CAP_PMU) +		return ssb_pmu_get_controlclock(&bus->chipco); +  	if (ssb_extif_available(&bus->extif))  		ssb_extif_get_clockcontrol(&bus->extif, &plltype,  					   &clkctl_n, &clkctl_m); @@ -1087,23 +1143,21 @@ static u32 ssb_tmslow_reject_bitmask(struct ssb_device *dev)  {  	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); +		WARN(1, KERN_INFO "ssb: Backplane Revision 0x%.8X\n", rev);  	} -	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 +1216,10 @@ void ssb_device_enable(struct ssb_device *dev, u32 core_specific_flags)  }  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 +1227,7 @@ static int ssb_wait_bit(struct ssb_device *dev, u16 reg, u32 bitmask,  	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 +1244,38 @@ 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; +	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 +1284,34 @@ void ssb_device_disable(struct ssb_device *dev, u32 core_specific_flags)  }  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);  	} @@ -1254,34 +1347,65 @@ out:  #endif  	return err;  error: -	ssb_printk(KERN_ERR PFX "Bus powerdown failed\n"); +	ssb_err("Bus powerdown failed\n");  	goto out;  }  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"); +	ssb_err("Bus powerup failed\n");  	return err;  }  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; @@ -1354,15 +1478,13 @@ static int __init ssb_modinit(void)  	err = b43_pci_ssb_bridge_init();  	if (err) { -		ssb_printk(KERN_ERR "Broadcom 43xx PCI-SSB-bridge " -			   "initialization failed\n"); +		ssb_err("Broadcom 43xx PCI-SSB-bridge initialization failed\n");  		/* don't fail SSB init because of this */  		err = 0;  	}  	err = ssb_gige_init();  	if (err) { -		ssb_printk(KERN_ERR "SSB Broadcom Gigabit Ethernet " -			   "driver initialization failed\n"); +		ssb_err("SSB Broadcom Gigabit Ethernet driver initialization failed\n");  		/* don't fail SSB init because of this */  		err = 0;  	} diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c index f52966305e0..a8dc95ebf2d 100644 --- 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> @@ -56,7 +56,7 @@ int ssb_pci_switch_coreidx(struct ssb_bus *bus, u8 coreidx)  	}  	return 0;  error: -	ssb_printk(KERN_ERR PFX "Failed to switch to core %u\n", coreidx); +	ssb_err("Failed to switch to core %u\n", coreidx);  	return -ENODEV;  } @@ -67,10 +67,9 @@ int ssb_pci_switch_core(struct ssb_bus *bus,  	unsigned long flags;  #if SSB_VERBOSE_PCICORESWITCH_DEBUG -	ssb_printk(KERN_INFO PFX -		   "Switching to %s core, index %d\n", -		   ssb_core_name(dev->id.coreid), -		   dev->core_index); +	ssb_info("Switching to %s core, index %d\n", +		 ssb_core_name(dev->id.coreid), +		 dev->core_index);  #endif  	spin_lock_irqsave(&bus->bar_lock, flags); @@ -178,6 +177,18 @@ err_pci:  #define SPEX(_outvar, _offset, _mask, _shift) \  	SPEX16(_outvar, _offset, _mask, _shift) +#define SPEX_ARRAY8(_field, _offset, _mask, _shift)	\ +	do {	\ +		SPEX(_field[0], _offset +  0, _mask, _shift);	\ +		SPEX(_field[1], _offset +  2, _mask, _shift);	\ +		SPEX(_field[2], _offset +  4, _mask, _shift);	\ +		SPEX(_field[3], _offset +  6, _mask, _shift);	\ +		SPEX(_field[4], _offset +  8, _mask, _shift);	\ +		SPEX(_field[5], _offset + 10, _mask, _shift);	\ +		SPEX(_field[6], _offset + 12, _mask, _shift);	\ +		SPEX(_field[7], _offset + 14, _mask, _shift);	\ +	} while (0) +  static inline u8 ssb_crc8(u8 crc, u8 data)  { @@ -219,6 +230,15 @@ static inline u8 ssb_crc8(u8 crc, u8 data)  	return t[crc ^ data];  } +static void sprom_get_mac(char *mac, const u16 *in) +{ +	int i; +	for (i = 0; i < 3; i++) { +		*mac++ = in[i] >> 8; +		*mac++ = in[i]; +	} +} +  static u8 ssb_sprom_crc(const u16 *sprom, u16 size)  {  	int word; @@ -266,7 +286,7 @@ static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom)  	u32 spromctl;  	u16 size = bus->sprom_size; -	ssb_printk(KERN_NOTICE PFX "Writing SPROM. Do NOT turn off the power! Please stand by...\n"); +	ssb_notice("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; @@ -274,17 +294,17 @@ static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom)  	err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl);  	if (err)  		goto err_ctlreg; -	ssb_printk(KERN_NOTICE PFX "[ 0%%"); +	ssb_notice("[ 0%%");  	msleep(500);  	for (i = 0; i < size; i++) {  		if (i == size / 4) -			ssb_printk("25%%"); +			ssb_cont("25%%");  		else if (i == size / 2) -			ssb_printk("50%%"); +			ssb_cont("50%%");  		else if (i == (size * 3) / 4) -			ssb_printk("75%%"); +			ssb_cont("75%%");  		else if (i % 2) -			ssb_printk("."); +			ssb_cont(".");  		writew(sprom[i], bus->mmio + bus->sprom_offset + (i * 2));  		mmiowb();  		msleep(20); @@ -297,12 +317,12 @@ static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom)  	if (err)  		goto err_ctlreg;  	msleep(500); -	ssb_printk("100%% ]\n"); -	ssb_printk(KERN_NOTICE PFX "SPROM written.\n"); +	ssb_cont("100%% ]\n"); +	ssb_notice("SPROM written\n");  	return 0;  err_ctlreg: -	ssb_printk(KERN_ERR PFX "Could not access SPROM control register.\n"); +	ssb_err("Could not access SPROM control register.\n");  	return err;  } @@ -327,11 +347,23 @@ static s8 r123_extract_antgain(u8 sprom_revision, const u16 *in,  	return (s8)gain;  } +static void sprom_extract_r23(struct ssb_sprom *out, const u16 *in) +{ +	SPEX(boardflags_hi, SSB_SPROM2_BFLHI, 0xFFFF, 0); +	SPEX(opo, SSB_SPROM2_OPO, SSB_SPROM2_OPO_VALUE, 0); +	SPEX(pa1lob0, SSB_SPROM2_PA1LOB0, 0xFFFF, 0); +	SPEX(pa1lob1, SSB_SPROM2_PA1LOB1, 0xFFFF, 0); +	SPEX(pa1lob2, SSB_SPROM2_PA1LOB2, 0xFFFF, 0); +	SPEX(pa1hib0, SSB_SPROM2_PA1HIB0, 0xFFFF, 0); +	SPEX(pa1hib1, SSB_SPROM2_PA1HIB1, 0xFFFF, 0); +	SPEX(pa1hib2, SSB_SPROM2_PA1HIB2, 0xFFFF, 0); +	SPEX(maxpwr_ah, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_HI, 0); +	SPEX(maxpwr_al, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_LO, +	     SSB_SPROM2_MAXP_A_LO_SHIFT); +} +  static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in)  { -	int i; -	u16 v; -	s8 gain;  	u16 loc[3];  	if (out->revision == 3)			/* rev 3 moved MAC */ @@ -341,19 +373,10 @@ static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in)  		loc[1] = SSB_SPROM1_ET0MAC;  		loc[2] = SSB_SPROM1_ET1MAC;  	} -	for (i = 0; i < 3; i++) { -		v = in[SPOFF(loc[0]) + i]; -		*(((__be16 *)out->il0mac) + i) = cpu_to_be16(v); -	} +	sprom_get_mac(out->il0mac, &in[SPOFF(loc[0])]);  	if (out->revision < 3) { 	/* only rev 1-2 have et0, et1 */ -		for (i = 0; i < 3; i++) { -			v = in[SPOFF(loc[1]) + i]; -			*(((__be16 *)out->et0mac) + i) = cpu_to_be16(v); -		} -		for (i = 0; i < 3; i++) { -			v = in[SPOFF(loc[2]) + i]; -			*(((__be16 *)out->et1mac) + i) = cpu_to_be16(v); -		} +		sprom_get_mac(out->et0mac, &in[SPOFF(loc[1])]); +		sprom_get_mac(out->et1mac, &in[SPOFF(loc[2])]);  	}  	SPEX(et0phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0A, 0);  	SPEX(et1phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1A, @@ -361,8 +384,10 @@ static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in)  	SPEX(et0mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0M, 14);  	SPEX(et1mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1M, 15);  	SPEX(board_rev, SSB_SPROM1_BINF, SSB_SPROM1_BINF_BREV, 0); -	SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE, -	     SSB_SPROM1_BINF_CCODE_SHIFT); +	SPEX(board_type, SSB_SPROM1_SPID, 0xFFFF, 0); +	if (out->revision == 1) +		SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE, +		     SSB_SPROM1_BINF_CCODE_SHIFT);  	SPEX(ant_available_a, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTA,  	     SSB_SPROM1_BINF_ANTA_SHIFT);  	SPEX(ant_available_bg, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTBG, @@ -386,52 +411,91 @@ static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in)  	     SSB_SPROM1_ITSSI_A_SHIFT);  	SPEX(itssi_bg, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_BG, 0);  	SPEX(boardflags_lo, SSB_SPROM1_BFLLO, 0xFFFF, 0); -	if (out->revision >= 2) -		SPEX(boardflags_hi, SSB_SPROM2_BFLHI, 0xFFFF, 0); + +	SPEX(alpha2[0], SSB_SPROM1_CCODE, 0xff00, 8); +	SPEX(alpha2[1], SSB_SPROM1_CCODE, 0x00ff, 0);  	/* Extract the antenna gain values. */ -	gain = r123_extract_antgain(out->revision, in, -				    SSB_SPROM1_AGAIN_BG, -				    SSB_SPROM1_AGAIN_BG_SHIFT); -	out->antenna_gain.ghz24.a0 = gain; -	out->antenna_gain.ghz24.a1 = gain; -	out->antenna_gain.ghz24.a2 = gain; -	out->antenna_gain.ghz24.a3 = gain; -	gain = r123_extract_antgain(out->revision, in, -				    SSB_SPROM1_AGAIN_A, -				    SSB_SPROM1_AGAIN_A_SHIFT); -	out->antenna_gain.ghz5.a0 = gain; -	out->antenna_gain.ghz5.a1 = gain; -	out->antenna_gain.ghz5.a2 = gain; -	out->antenna_gain.ghz5.a3 = gain; +	out->antenna_gain.a0 = r123_extract_antgain(out->revision, in, +						    SSB_SPROM1_AGAIN_BG, +						    SSB_SPROM1_AGAIN_BG_SHIFT); +	out->antenna_gain.a1 = r123_extract_antgain(out->revision, in, +						    SSB_SPROM1_AGAIN_A, +						    SSB_SPROM1_AGAIN_A_SHIFT); +	if (out->revision >= 2) +		sprom_extract_r23(out, in); +} + +/* 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; -	u16 v;  	u16 il0mac_offset;  	if (out->revision == 4)  		il0mac_offset = SSB_SPROM4_IL0MAC;  	else  		il0mac_offset = SSB_SPROM5_IL0MAC; -	/* extract the MAC address */ -	for (i = 0; i < 3; i++) { -		v = in[SPOFF(il0mac_offset) + i]; -		*(((__be16 *)out->il0mac) + i) = cpu_to_be16(v); -	} + +	sprom_get_mac(out->il0mac, &in[SPOFF(il0mac_offset)]); +  	SPEX(et0phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET0A, 0);  	SPEX(et1phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET1A,  	     SSB_SPROM4_ETHPHY_ET1A_SHIFT); +	SPEX(board_rev, SSB_SPROM4_BOARDREV, 0xFFFF, 0); +	SPEX(board_type, SSB_SPROM1_SPID, 0xFFFF, 0);  	if (out->revision == 4) { -		SPEX(country_code, SSB_SPROM4_CCODE, 0xFFFF, 0); +		SPEX(alpha2[0], SSB_SPROM4_CCODE, 0xff00, 8); +		SPEX(alpha2[1], SSB_SPROM4_CCODE, 0x00ff, 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(alpha2[0], SSB_SPROM5_CCODE, 0xff00, 8); +		SPEX(alpha2[1], SSB_SPROM5_CCODE, 0x00ff, 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); @@ -460,16 +524,16 @@ static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in)  	}  	/* Extract the antenna gain values. */ -	SPEX(antenna_gain.ghz24.a0, SSB_SPROM4_AGAIN01, +	SPEX(antenna_gain.a0, SSB_SPROM4_AGAIN01,  	     SSB_SPROM4_AGAIN0, SSB_SPROM4_AGAIN0_SHIFT); -	SPEX(antenna_gain.ghz24.a1, SSB_SPROM4_AGAIN01, +	SPEX(antenna_gain.a1, SSB_SPROM4_AGAIN01,  	     SSB_SPROM4_AGAIN1, SSB_SPROM4_AGAIN1_SHIFT); -	SPEX(antenna_gain.ghz24.a2, SSB_SPROM4_AGAIN23, +	SPEX(antenna_gain.a2, SSB_SPROM4_AGAIN23,  	     SSB_SPROM4_AGAIN2, SSB_SPROM4_AGAIN2_SHIFT); -	SPEX(antenna_gain.ghz24.a3, SSB_SPROM4_AGAIN23, +	SPEX(antenna_gain.a3, SSB_SPROM4_AGAIN23,  	     SSB_SPROM4_AGAIN3, SSB_SPROM4_AGAIN3_SHIFT); -	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 */  } @@ -477,14 +541,21 @@ static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in)  static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in)  {  	int i; -	u16 v; +	u16 o; +	u16 pwr_info_offset[] = { +		SSB_SROM8_PWR_INFO_CORE0, SSB_SROM8_PWR_INFO_CORE1, +		SSB_SROM8_PWR_INFO_CORE2, SSB_SROM8_PWR_INFO_CORE3 +	}; +	BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset) != +			ARRAY_SIZE(out->core_pwr_info));  	/* extract the MAC address */ -	for (i = 0; i < 3; i++) { -		v = in[SPOFF(SSB_SPROM8_IL0MAC) + i]; -		*(((__be16 *)out->il0mac) + i) = cpu_to_be16(v); -	} -	SPEX(country_code, SSB_SPROM8_CCODE, 0xFFFF, 0); +	sprom_get_mac(out->il0mac, &in[SPOFF(SSB_SPROM8_IL0MAC)]); + +	SPEX(board_rev, SSB_SPROM8_BOARDREV, 0xFFFF, 0); +	SPEX(board_type, SSB_SPROM1_SPID, 0xFFFF, 0); +	SPEX(alpha2[0], SSB_SPROM8_CCODE, 0xff00, 8); +	SPEX(alpha2[1], SSB_SPROM8_CCODE, 0x00ff, 0);  	SPEX(boardflags_lo, SSB_SPROM8_BFLLO, 0xFFFF, 0);  	SPEX(boardflags_hi, SSB_SPROM8_BFLHI, 0xFFFF, 0);  	SPEX(boardflags2_lo, SSB_SPROM8_BFL2LO, 0xFFFF, 0); @@ -550,16 +621,128 @@ static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in)  	SPEX32(ofdm5ghpo, SSB_SPROM8_OFDM5GHPO, 0xFFFFFFFF, 0);  	/* Extract the antenna gain values. */ -	SPEX(antenna_gain.ghz24.a0, SSB_SPROM8_AGAIN01, +	SPEX(antenna_gain.a0, SSB_SPROM8_AGAIN01,  	     SSB_SPROM8_AGAIN0, SSB_SPROM8_AGAIN0_SHIFT); -	SPEX(antenna_gain.ghz24.a1, SSB_SPROM8_AGAIN01, +	SPEX(antenna_gain.a1, SSB_SPROM8_AGAIN01,  	     SSB_SPROM8_AGAIN1, SSB_SPROM8_AGAIN1_SHIFT); -	SPEX(antenna_gain.ghz24.a2, SSB_SPROM8_AGAIN23, +	SPEX(antenna_gain.a2, SSB_SPROM8_AGAIN23,  	     SSB_SPROM8_AGAIN2, SSB_SPROM8_AGAIN2_SHIFT); -	SPEX(antenna_gain.ghz24.a3, SSB_SPROM8_AGAIN23, +	SPEX(antenna_gain.a3, SSB_SPROM8_AGAIN23,  	     SSB_SPROM8_AGAIN3, SSB_SPROM8_AGAIN3_SHIFT); -	memcpy(&out->antenna_gain.ghz5, &out->antenna_gain.ghz24, -	       sizeof(out->antenna_gain.ghz5)); + +	/* Extract cores power info info */ +	for (i = 0; i < ARRAY_SIZE(pwr_info_offset); i++) { +		o = pwr_info_offset[i]; +		SPEX(core_pwr_info[i].itssi_2g, o + SSB_SROM8_2G_MAXP_ITSSI, +			SSB_SPROM8_2G_ITSSI, SSB_SPROM8_2G_ITSSI_SHIFT); +		SPEX(core_pwr_info[i].maxpwr_2g, o + SSB_SROM8_2G_MAXP_ITSSI, +			SSB_SPROM8_2G_MAXP, 0); + +		SPEX(core_pwr_info[i].pa_2g[0], o + SSB_SROM8_2G_PA_0, ~0, 0); +		SPEX(core_pwr_info[i].pa_2g[1], o + SSB_SROM8_2G_PA_1, ~0, 0); +		SPEX(core_pwr_info[i].pa_2g[2], o + SSB_SROM8_2G_PA_2, ~0, 0); + +		SPEX(core_pwr_info[i].itssi_5g, o + SSB_SROM8_5G_MAXP_ITSSI, +			SSB_SPROM8_5G_ITSSI, SSB_SPROM8_5G_ITSSI_SHIFT); +		SPEX(core_pwr_info[i].maxpwr_5g, o + SSB_SROM8_5G_MAXP_ITSSI, +			SSB_SPROM8_5G_MAXP, 0); +		SPEX(core_pwr_info[i].maxpwr_5gh, o + SSB_SPROM8_5GHL_MAXP, +			SSB_SPROM8_5GH_MAXP, 0); +		SPEX(core_pwr_info[i].maxpwr_5gl, o + SSB_SPROM8_5GHL_MAXP, +			SSB_SPROM8_5GL_MAXP, SSB_SPROM8_5GL_MAXP_SHIFT); + +		SPEX(core_pwr_info[i].pa_5gl[0], o + SSB_SROM8_5GL_PA_0, ~0, 0); +		SPEX(core_pwr_info[i].pa_5gl[1], o + SSB_SROM8_5GL_PA_1, ~0, 0); +		SPEX(core_pwr_info[i].pa_5gl[2], o + SSB_SROM8_5GL_PA_2, ~0, 0); +		SPEX(core_pwr_info[i].pa_5g[0], o + SSB_SROM8_5G_PA_0, ~0, 0); +		SPEX(core_pwr_info[i].pa_5g[1], o + SSB_SROM8_5G_PA_1, ~0, 0); +		SPEX(core_pwr_info[i].pa_5g[2], o + SSB_SROM8_5G_PA_2, ~0, 0); +		SPEX(core_pwr_info[i].pa_5gh[0], o + SSB_SROM8_5GH_PA_0, ~0, 0); +		SPEX(core_pwr_info[i].pa_5gh[1], o + SSB_SROM8_5GH_PA_1, ~0, 0); +		SPEX(core_pwr_info[i].pa_5gh[2], o + SSB_SROM8_5GH_PA_2, ~0, 0); +	} + +	/* 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); + +	SPEX(leddc_on_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_ON, +	     SSB_SPROM8_LEDDC_ON_SHIFT); +	SPEX(leddc_off_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_OFF, +	     SSB_SPROM8_LEDDC_OFF_SHIFT); + +	SPEX(txchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_TXCHAIN, +	     SSB_SPROM8_TXRXC_TXCHAIN_SHIFT); +	SPEX(rxchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_RXCHAIN, +	     SSB_SPROM8_TXRXC_RXCHAIN_SHIFT); +	SPEX(antswitch, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_SWITCH, +	     SSB_SPROM8_TXRXC_SWITCH_SHIFT); + +	SPEX(opo, SSB_SPROM8_OFDM2GPO, 0x00ff, 0); + +	SPEX_ARRAY8(mcs2gpo, SSB_SPROM8_2G_MCSPO, ~0, 0); +	SPEX_ARRAY8(mcs5gpo, SSB_SPROM8_5G_MCSPO, ~0, 0); +	SPEX_ARRAY8(mcs5glpo, SSB_SPROM8_5GL_MCSPO, ~0, 0); +	SPEX_ARRAY8(mcs5ghpo, SSB_SPROM8_5GH_MCSPO, ~0, 0); + +	SPEX(rawtempsense, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_RAWTEMP, +	     SSB_SPROM8_RAWTS_RAWTEMP_SHIFT); +	SPEX(measpower, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_MEASPOWER, +	     SSB_SPROM8_RAWTS_MEASPOWER_SHIFT); +	SPEX(tempsense_slope, SSB_SPROM8_OPT_CORRX, +	     SSB_SPROM8_OPT_CORRX_TEMP_SLOPE, +	     SSB_SPROM8_OPT_CORRX_TEMP_SLOPE_SHIFT); +	SPEX(tempcorrx, SSB_SPROM8_OPT_CORRX, SSB_SPROM8_OPT_CORRX_TEMPCORRX, +	     SSB_SPROM8_OPT_CORRX_TEMPCORRX_SHIFT); +	SPEX(tempsense_option, SSB_SPROM8_OPT_CORRX, +	     SSB_SPROM8_OPT_CORRX_TEMP_OPTION, +	     SSB_SPROM8_OPT_CORRX_TEMP_OPTION_SHIFT); +	SPEX(freqoffset_corr, SSB_SPROM8_HWIQ_IQSWP, +	     SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR, +	     SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR_SHIFT); +	SPEX(iqcal_swp_dis, SSB_SPROM8_HWIQ_IQSWP, +	     SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP, +	     SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP_SHIFT); +	SPEX(hw_iqcal_en, SSB_SPROM8_HWIQ_IQSWP, SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL, +	     SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL_SHIFT); + +	SPEX(bw40po, SSB_SPROM8_BW40PO, ~0, 0); +	SPEX(cddpo, SSB_SPROM8_CDDPO, ~0, 0); +	SPEX(stbcpo, SSB_SPROM8_STBCPO, ~0, 0); +	SPEX(bwduppo, SSB_SPROM8_BWDUPPO, ~0, 0); + +	SPEX(tempthresh, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_TRESH, +	     SSB_SPROM8_THERMAL_TRESH_SHIFT); +	SPEX(tempoffset, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_OFFSET, +	     SSB_SPROM8_THERMAL_OFFSET_SHIFT); +	SPEX(phycal_tempdelta, SSB_SPROM8_TEMPDELTA, +	     SSB_SPROM8_TEMPDELTA_PHYCAL, +	     SSB_SPROM8_TEMPDELTA_PHYCAL_SHIFT); +	SPEX(temps_period, SSB_SPROM8_TEMPDELTA, SSB_SPROM8_TEMPDELTA_PERIOD, +	     SSB_SPROM8_TEMPDELTA_PERIOD_SHIFT); +	SPEX(temps_hysteresis, SSB_SPROM8_TEMPDELTA, +	     SSB_SPROM8_TEMPDELTA_HYSTERESIS, +	     SSB_SPROM8_TEMPDELTA_HYSTERESIS_SHIFT); +	sprom_extract_r458(out, in);  	/* TODO - get remaining rev 8 stuff needed */  } @@ -570,7 +753,7 @@ static int sprom_extract(struct ssb_bus *bus, struct ssb_sprom *out,  	memset(out, 0, sizeof(*out));  	out->revision = in[size - 1] & 0x00FF; -	ssb_dprintk(KERN_DEBUG PFX "SPROM revision %d detected.\n", out->revision); +	ssb_dbg("SPROM revision %d detected\n", out->revision);  	memset(out->et0mac, 0xFF, 6);		/* preset et0 and et1 mac */  	memset(out->et1mac, 0xFF, 6); @@ -579,7 +762,7 @@ static int sprom_extract(struct ssb_bus *bus, struct ssb_sprom *out,  		 * number stored in the SPROM.  		 * Always extract r1. */  		out->revision = 1; -		ssb_dprintk(KERN_DEBUG PFX "SPROM treated as revision %d\n", out->revision); +		ssb_dbg("SPROM treated as revision %d\n", out->revision);  	}  	switch (out->revision) { @@ -596,9 +779,8 @@ static int sprom_extract(struct ssb_bus *bus, struct ssb_sprom *out,  		sprom_extract_r8(out, in);  		break;  	default: -		ssb_printk(KERN_WARNING PFX "Unsupported SPROM" -			   "  revision %d detected. Will extract" -			   " v1\n", out->revision); +		ssb_warn("Unsupported SPROM revision %d detected. Will extract v1\n", +			 out->revision);  		out->revision = 1;  		sprom_extract_r123(out, in);  	} @@ -614,15 +796,14 @@ static int sprom_extract(struct ssb_bus *bus, struct ssb_sprom *out,  static int ssb_pci_sprom_get(struct ssb_bus *bus,  			     struct ssb_sprom *sprom)  { -	const struct ssb_sprom *fallback;  	int err;  	u16 *buf;  	if (!ssb_is_sprom_available(bus)) { -		ssb_printk(KERN_ERR PFX "No SPROM available!\n"); +		ssb_err("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 @@ -638,7 +819,7 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus,  	} else {  		bus->sprom_offset = SSB_SPROM_BASE1;  	} -	ssb_dprintk(KERN_INFO PFX "SPROM offset is 0x%x\n", bus->sprom_offset); +	ssb_dbg("SPROM offset is 0x%x\n", bus->sprom_offset);  	buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL);  	if (!buf) @@ -659,15 +840,19 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus,  		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_warn("WARNING: Using fallback SPROM failed (err %d)\n", +					 err); +			} else { +				ssb_dbg("Using SPROM revision %d provided by platform\n", +					sprom->revision);  				err = 0;  				goto out_free;  			} -			ssb_printk(KERN_WARNING PFX "WARNING: Invalid" -				   " SPROM CRC (corrupt SPROM)\n"); +			ssb_warn("WARNING: Invalid SPROM CRC (corrupt SPROM)\n");  		}  	}  	err = sprom_extract(bus, sprom, buf, bus->sprom_size); @@ -680,12 +865,8 @@ out_free:  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;  }  int ssb_pci_get_invariants(struct ssb_bus *bus, diff --git a/drivers/ssb/pcihost_wrapper.c b/drivers/ssb/pcihost_wrapper.c index f6c8c81a002..69161bbc4d0 100644 --- a/drivers/ssb/pcihost_wrapper.c +++ b/drivers/ssb/pcihost_wrapper.c @@ -6,12 +6,13 @@   * 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.   */  #include <linux/pci.h> +#include <linux/export.h>  #include <linux/slab.h>  #include <linux/ssb/ssb.h> @@ -37,7 +38,7 @@ static int ssb_pcihost_resume(struct pci_dev *dev)  	struct ssb_bus *ssb = pci_get_drvdata(dev);  	int err; -	pci_set_power_state(dev, 0); +	pci_set_power_state(dev, PCI_D0);  	err = pci_enable_device(dev);  	if (err)  		return err; diff --git a/drivers/ssb/pcmcia.c b/drivers/ssb/pcmcia.c index c7345dbf43f..b413e018708 100644 --- 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.   */ @@ -143,7 +143,7 @@ int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus,  	return 0;  error: -	ssb_printk(KERN_ERR PFX "Failed to switch to core %u\n", coreidx); +	ssb_err("Failed to switch to core %u\n", coreidx);  	return err;  } @@ -153,10 +153,9 @@ int ssb_pcmcia_switch_core(struct ssb_bus *bus,  	int err;  #if SSB_VERBOSE_PCMCIACORESWITCH_DEBUG -	ssb_printk(KERN_INFO PFX -		   "Switching to %s core, index %d\n", -		   ssb_core_name(dev->id.coreid), -		   dev->core_index); +	ssb_info("Switching to %s core, index %d\n", +		 ssb_core_name(dev->id.coreid), +		 dev->core_index);  #endif  	err = ssb_pcmcia_switch_coreidx(bus, dev->core_index); @@ -192,7 +191,7 @@ int ssb_pcmcia_switch_segment(struct ssb_bus *bus, u8 seg)  	return 0;  error: -	ssb_printk(KERN_ERR PFX "Failed to switch pcmcia segment\n"); +	ssb_err("Failed to switch pcmcia segment\n");  	return err;  } @@ -549,44 +548,39 @@ static int ssb_pcmcia_sprom_write_all(struct ssb_bus *bus, const u16 *sprom)  	bool failed = 0;  	size_t size = SSB_PCMCIA_SPROM_SIZE; -	ssb_printk(KERN_NOTICE PFX -		   "Writing SPROM. Do NOT turn off the power! " -		   "Please stand by...\n"); +	ssb_notice("Writing SPROM. Do NOT turn off the power! Please stand by...\n");  	err = ssb_pcmcia_sprom_command(bus, SSB_PCMCIA_SPROMCTL_WRITEEN);  	if (err) { -		ssb_printk(KERN_NOTICE PFX -			   "Could not enable SPROM write access.\n"); +		ssb_notice("Could not enable SPROM write access\n");  		return -EBUSY;  	} -	ssb_printk(KERN_NOTICE PFX "[ 0%%"); +	ssb_notice("[ 0%%");  	msleep(500);  	for (i = 0; i < size; i++) {  		if (i == size / 4) -			ssb_printk("25%%"); +			ssb_cont("25%%");  		else if (i == size / 2) -			ssb_printk("50%%"); +			ssb_cont("50%%");  		else if (i == (size * 3) / 4) -			ssb_printk("75%%"); +			ssb_cont("75%%");  		else if (i % 2) -			ssb_printk("."); +			ssb_cont(".");  		err = ssb_pcmcia_sprom_write(bus, i, sprom[i]);  		if (err) { -			ssb_printk(KERN_NOTICE PFX -				   "Failed to write to SPROM.\n"); +			ssb_notice("Failed to write to SPROM\n");  			failed = 1;  			break;  		}  	}  	err = ssb_pcmcia_sprom_command(bus, SSB_PCMCIA_SPROMCTL_WRITEDIS);  	if (err) { -		ssb_printk(KERN_NOTICE PFX -			   "Could not disable SPROM write access.\n"); +		ssb_notice("Could not disable SPROM write access\n");  		failed = 1;  	}  	msleep(500);  	if (!failed) { -		ssb_printk("100%% ]\n"); -		ssb_printk(KERN_NOTICE PFX "SPROM written.\n"); +		ssb_cont("100%% ]\n"); +		ssb_notice("SPROM written\n");  	}  	return failed ? -EBUSY : 0; @@ -676,14 +670,10 @@ static int ssb_pcmcia_do_get_invariants(struct pcmcia_device *p_dev,  	case SSB_PCMCIA_CIS_ANTGAIN:  		GOTO_ERROR_ON(tuple->TupleDataLen != 2,  			"antg tpl size"); -		sprom->antenna_gain.ghz24.a0 = tuple->TupleData[1]; -		sprom->antenna_gain.ghz24.a1 = tuple->TupleData[1]; -		sprom->antenna_gain.ghz24.a2 = tuple->TupleData[1]; -		sprom->antenna_gain.ghz24.a3 = tuple->TupleData[1]; -		sprom->antenna_gain.ghz5.a0 = tuple->TupleData[1]; -		sprom->antenna_gain.ghz5.a1 = tuple->TupleData[1]; -		sprom->antenna_gain.ghz5.a2 = tuple->TupleData[1]; -		sprom->antenna_gain.ghz5.a3 = tuple->TupleData[1]; +		sprom->antenna_gain.a0 = tuple->TupleData[1]; +		sprom->antenna_gain.a1 = tuple->TupleData[1]; +		sprom->antenna_gain.a2 = tuple->TupleData[1]; +		sprom->antenna_gain.a3 = tuple->TupleData[1];  		break;  	case SSB_PCMCIA_CIS_BFLAGS:  		GOTO_ERROR_ON((tuple->TupleDataLen != 3) && @@ -704,7 +694,7 @@ static int ssb_pcmcia_do_get_invariants(struct pcmcia_device *p_dev,  	return -ENOSPC; /* continue with next entry */  error: -	ssb_printk(KERN_ERR PFX +	ssb_err(  		   "PCMCIA: Failed to fetch device invariants: %s\n",  		   error_description);  	return -ENODEV; @@ -726,18 +716,18 @@ int ssb_pcmcia_get_invariants(struct ssb_bus *bus,  	res = pcmcia_loop_tuple(bus->host_pcmcia, CISTPL_FUNCE,  				ssb_pcmcia_get_mac, sprom);  	if (res != 0) { -		ssb_printk(KERN_ERR PFX +		ssb_err(  			"PCMCIA: Failed to fetch MAC address\n");  		return -ENODEV;  	}  	/* Fetch the vendor specific tuples. */  	res = pcmcia_loop_tuple(bus->host_pcmcia, SSB_PCMCIA_CIS, -				ssb_pcmcia_do_get_invariants, sprom); +				ssb_pcmcia_do_get_invariants, iv);  	if ((res == 0) || (res == -ENOSPC))  		return 0; -	ssb_printk(KERN_ERR PFX +	ssb_err(  			"PCMCIA: Failed to fetch device invariants\n");  	return -ENODEV;  } @@ -847,6 +837,6 @@ int ssb_pcmcia_init(struct ssb_bus *bus)  	return 0;  error: -	ssb_printk(KERN_ERR PFX "Failed to initialize PCMCIA host device\n"); +	ssb_err("Failed to initialize PCMCIA host device\n");  	return err;  } diff --git a/drivers/ssb/scan.c b/drivers/ssb/scan.c index ee079ab9fb2..b9429df583e 100644 --- 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> @@ -90,6 +90,8 @@ const char *ssb_core_name(u16 coreid)  		return "ARM 1176";  	case SSB_DEV_ARM_7TDMI:  		return "ARM 7TDMI"; +	case SSB_DEV_ARM_CM3: +		return "ARM Cortex M3";  	}  	return "UNKNOWN";  } @@ -123,8 +125,7 @@ static u16 pcidev_to_chipid(struct pci_dev *pci_dev)  		chipid_fallback = 0x4401;  		break;  	default: -		ssb_printk(KERN_ERR PFX -			   "PCI-ID not in fallback list\n"); +		ssb_err("PCI-ID not in fallback list\n");  	}  	return chipid_fallback; @@ -150,8 +151,7 @@ static u8 chipid_to_nrcores(u16 chipid)  	case 0x4704:  		return 9;  	default: -		ssb_printk(KERN_ERR PFX -			   "CHIPID not in nrcores fallback list\n"); +		ssb_err("CHIPID not in nrcores fallback list\n");  	}  	return 1; @@ -258,7 +258,10 @@ static int we_support_multiple_80211_cores(struct ssb_bus *bus)  #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; @@ -316,12 +318,13 @@ int ssb_bus_scan(struct ssb_bus *bus,  			bus->chip_package = 0;  		}  	} +	ssb_info("Found chip with id 0x%04X, rev 0x%02X and package 0x%02X\n", +		 bus->chip_id, bus->chip_rev, bus->chip_package);  	if (!bus->nr_devices)  		bus->nr_devices = chipid_to_nrcores(bus->chip_id);  	if (bus->nr_devices > ARRAY_SIZE(bus->devices)) { -		ssb_printk(KERN_ERR PFX -			   "More than %d ssb cores found (%d)\n", -			   SSB_MAX_NR_CORES, bus->nr_devices); +		ssb_err("More than %d ssb cores found (%d)\n", +			SSB_MAX_NR_CORES, bus->nr_devices);  		goto err_unmap;  	}  	if (bus->bustype == SSB_BUSTYPE_SSB) { @@ -363,8 +366,7 @@ int ssb_bus_scan(struct ssb_bus *bus,  			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"); +					ssb_dbg("Ignoring additional 802.11 core\n");  					continue;  				}  			} @@ -372,8 +374,7 @@ int ssb_bus_scan(struct ssb_bus *bus,  		case SSB_DEV_EXTIF:  #ifdef CONFIG_SSB_DRIVER_EXTIF  			if (bus->extif.dev) { -				ssb_printk(KERN_WARNING PFX -					   "WARNING: Multiple EXTIFs found\n"); +				ssb_warn("WARNING: Multiple EXTIFs found\n");  				break;  			}  			bus->extif.dev = dev; @@ -381,8 +382,7 @@ int ssb_bus_scan(struct ssb_bus *bus,  			break;  		case SSB_DEV_CHIPCOMMON:  			if (bus->chipco.dev) { -				ssb_printk(KERN_WARNING PFX -					   "WARNING: Multiple ChipCommon found\n"); +				ssb_warn("WARNING: Multiple ChipCommon found\n");  				break;  			}  			bus->chipco.dev = dev; @@ -391,8 +391,7 @@ int ssb_bus_scan(struct ssb_bus *bus,  		case SSB_DEV_MIPS_3302:  #ifdef CONFIG_SSB_DRIVER_MIPS  			if (bus->mipscore.dev) { -				ssb_printk(KERN_WARNING PFX -					   "WARNING: Multiple MIPS cores found\n"); +				ssb_warn("WARNING: Multiple MIPS cores found\n");  				break;  			}  			bus->mipscore.dev = dev; @@ -405,21 +404,30 @@ 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;  				}  			}  			if (bus->pcicore.dev) { -				ssb_printk(KERN_WARNING PFX -					   "WARNING: Multiple PCI(E) cores found\n"); +				ssb_warn("WARNING: Multiple PCI(E) cores found\n");  				break;  			}  			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;  		} diff --git a/drivers/ssb/sdio.c b/drivers/ssb/sdio.c index 65a6080cb02..b2d36f7736c 100644 --- 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.   * @@ -551,14 +551,10 @@ int ssb_sdio_get_invariants(struct ssb_bus *bus,  			case SSB_SDIO_CIS_ANTGAIN:  				GOTO_ERROR_ON(tuple->size != 2,  					      "antg tpl size"); -				sprom->antenna_gain.ghz24.a0 = tuple->data[1]; -				sprom->antenna_gain.ghz24.a1 = tuple->data[1]; -				sprom->antenna_gain.ghz24.a2 = tuple->data[1]; -				sprom->antenna_gain.ghz24.a3 = tuple->data[1]; -				sprom->antenna_gain.ghz5.a0 = tuple->data[1]; -				sprom->antenna_gain.ghz5.a1 = tuple->data[1]; -				sprom->antenna_gain.ghz5.a2 = tuple->data[1]; -				sprom->antenna_gain.ghz5.a3 = tuple->data[1]; +				sprom->antenna_gain.a0 = tuple->data[1]; +				sprom->antenna_gain.a1 = tuple->data[1]; +				sprom->antenna_gain.a2 = tuple->data[1]; +				sprom->antenna_gain.a3 = tuple->data[1];  				break;  			case SSB_SDIO_CIS_BFLAGS:  				GOTO_ERROR_ON((tuple->size != 3) && diff --git a/drivers/ssb/sprom.c b/drivers/ssb/sprom.c index 4f7cc8d1327..e753fbe302a 100644 --- 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, @@ -54,7 +54,7 @@ static int hex2sprom(u16 *sprom, const char *dump, size_t len,  	while (cnt < sprom_size_words) {  		memcpy(tmp, dump, 4);  		dump += 4; -		err = strict_strtoul(tmp, 16, &parsed); +		err = kstrtoul(tmp, 16, &parsed);  		if (err)  			return err;  		sprom[cnt++] = swab16((u16)parsed); @@ -127,13 +127,13 @@ ssize_t ssb_attr_sprom_store(struct ssb_bus *bus,  		goto out_kfree;  	err = ssb_devices_freeze(bus, &freeze);  	if (err) { -		ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze all devices\n"); +		ssb_err("SPROM write: Could not freeze all devices\n");  		goto out_unlock;  	}  	res = sprom_write(bus, sprom);  	err = ssb_devices_thaw(&freeze);  	if (err) -		ssb_printk(KERN_ERR PFX "SPROM write: Could not thaw all devices\n"); +		ssb_err("SPROM write: Could not thaw all devices\n");  out_unlock:  	mutex_unlock(&bus->sprom_mutex);  out_kfree: @@ -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. + * 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. + * 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_bus *bus)  	/* 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; diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h index 0331139a726..eb507a50a56 100644 --- a/drivers/ssb/ssb_private.h +++ b/drivers/ssb/ssb_private.h @@ -3,21 +3,33 @@  #include <linux/ssb/ssb.h>  #include <linux/types.h> +#include <linux/bcm47xx_wdt.h>  #define PFX	"ssb: "  #ifdef CONFIG_SSB_SILENT -# define ssb_printk(fmt, x...)	do { /* nothing */ } while (0) +# define ssb_printk(fmt, ...)					\ +	do { if (0) printk(fmt, ##__VA_ARGS__); } while (0)  #else -# define ssb_printk		printk +# define ssb_printk(fmt, ...)					\ +	printk(fmt, ##__VA_ARGS__)  #endif /* CONFIG_SSB_SILENT */ +#define ssb_emerg(fmt, ...)	ssb_printk(KERN_EMERG PFX fmt, ##__VA_ARGS__) +#define ssb_err(fmt, ...)	ssb_printk(KERN_ERR PFX fmt, ##__VA_ARGS__) +#define ssb_warn(fmt, ...)	ssb_printk(KERN_WARNING PFX fmt, ##__VA_ARGS__) +#define ssb_notice(fmt, ...)	ssb_printk(KERN_NOTICE PFX fmt, ##__VA_ARGS__) +#define ssb_info(fmt, ...)	ssb_printk(KERN_INFO PFX fmt, ##__VA_ARGS__) +#define ssb_cont(fmt, ...)	ssb_printk(KERN_CONT fmt, ##__VA_ARGS__) +  /* dprintk: Debugging printk; vanishes for non-debug compilation */  #ifdef CONFIG_SSB_DEBUG -# define ssb_dprintk(fmt, x...)	ssb_printk(fmt , ##x) +# define ssb_dbg(fmt, ...)					\ +	ssb_printk(KERN_DEBUG PFX fmt, ##__VA_ARGS__)  #else -# define ssb_dprintk(fmt, x...)	do { /* nothing */ } while (0) +# define ssb_dbg(fmt, ...)					\ +	do { if (0) printk(KERN_DEBUG PFX fmt, ##__VA_ARGS__); } while (0)  #endif  #ifdef CONFIG_SSB_DEBUG @@ -171,7 +183,8 @@ ssize_t ssb_attr_sprom_store(struct ssb_bus *bus,  			     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 */ @@ -206,4 +219,79 @@ static inline void b43_pci_ssb_bridge_exit(void)  }  #endif /* CONFIG_SSB_B43_PCI_BRIDGE */ +/* driver_chipcommon_pmu.c */ +extern u32 ssb_pmu_get_cpu_clock(struct ssb_chipcommon *cc); +extern u32 ssb_pmu_get_controlclock(struct ssb_chipcommon *cc); +extern u32 ssb_pmu_get_alp_clock(struct ssb_chipcommon *cc); + +extern u32 ssb_chipco_watchdog_timer_set_wdt(struct bcm47xx_wdt *wdt, +					     u32 ticks); +extern u32 ssb_chipco_watchdog_timer_set_ms(struct bcm47xx_wdt *wdt, u32 ms); + +/* driver_chipcommon_sflash.c */ +#ifdef CONFIG_SSB_SFLASH +int ssb_sflash_init(struct ssb_chipcommon *cc); +#else +static inline int ssb_sflash_init(struct ssb_chipcommon *cc) +{ +	pr_err("Serial flash not supported\n"); +	return 0; +} +#endif /* CONFIG_SSB_SFLASH */ + +#ifdef CONFIG_SSB_DRIVER_MIPS +extern struct platform_device ssb_pflash_dev; +#endif + +#ifdef CONFIG_SSB_SFLASH +extern struct platform_device ssb_sflash_dev; +#endif + +#ifdef CONFIG_SSB_DRIVER_EXTIF +extern u32 ssb_extif_watchdog_timer_set_wdt(struct bcm47xx_wdt *wdt, u32 ticks); +extern u32 ssb_extif_watchdog_timer_set_ms(struct bcm47xx_wdt *wdt, u32 ms); +#else +static inline u32 ssb_extif_watchdog_timer_set_wdt(struct bcm47xx_wdt *wdt, +						   u32 ticks) +{ +	return 0; +} +static inline u32 ssb_extif_watchdog_timer_set_ms(struct bcm47xx_wdt *wdt, +						  u32 ms) +{ +	return 0; +} +#endif + +#ifdef CONFIG_SSB_EMBEDDED +extern int ssb_watchdog_register(struct ssb_bus *bus); +#else /* CONFIG_SSB_EMBEDDED */ +static inline int ssb_watchdog_register(struct ssb_bus *bus) +{ +	return 0; +} +#endif /* CONFIG_SSB_EMBEDDED */ + +#ifdef CONFIG_SSB_DRIVER_EXTIF +extern void ssb_extif_init(struct ssb_extif *extif); +#else +static inline void ssb_extif_init(struct ssb_extif *extif) +{ +} +#endif + +#ifdef CONFIG_SSB_DRIVER_GPIO +extern int ssb_gpio_init(struct ssb_bus *bus); +extern int ssb_gpio_unregister(struct ssb_bus *bus); +#else /* CONFIG_SSB_DRIVER_GPIO */ +static inline int ssb_gpio_init(struct ssb_bus *bus) +{ +	return -ENOTSUPP; +} +static inline int ssb_gpio_unregister(struct ssb_bus *bus) +{ +	return 0; +} +#endif /* CONFIG_SSB_DRIVER_GPIO */ +  #endif /* LINUX_SSB_PRIVATE_H_ */  | 
