diff options
Diffstat (limited to 'drivers/bcma')
| -rw-r--r-- | drivers/bcma/Kconfig | 1 | ||||
| -rw-r--r-- | drivers/bcma/bcma_private.h | 2 | ||||
| -rw-r--r-- | drivers/bcma/core.c | 28 | ||||
| -rw-r--r-- | drivers/bcma/driver_chipcommon.c | 11 | ||||
| -rw-r--r-- | drivers/bcma/driver_chipcommon_pmu.c | 123 | ||||
| -rw-r--r-- | drivers/bcma/driver_chipcommon_sflash.c | 8 | ||||
| -rw-r--r-- | drivers/bcma/host_pci.c | 1 | ||||
| -rw-r--r-- | drivers/bcma/main.c | 19 | ||||
| -rw-r--r-- | drivers/bcma/sprom.c | 72 | 
9 files changed, 224 insertions, 41 deletions
| diff --git a/drivers/bcma/Kconfig b/drivers/bcma/Kconfig index 8b4221cfd118..380a2003231e 100644 --- a/drivers/bcma/Kconfig +++ b/drivers/bcma/Kconfig @@ -26,6 +26,7 @@ config BCMA_HOST_PCI_POSSIBLE  config BCMA_HOST_PCI  	bool "Support for BCMA on PCI-host bus"  	depends on BCMA_HOST_PCI_POSSIBLE +	default y  config BCMA_DRIVER_PCI_HOSTMODE  	bool "Driver for PCI core working in hostmode" diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h index 79595a001204..0215f9ad755c 100644 --- a/drivers/bcma/bcma_private.h +++ b/drivers/bcma/bcma_private.h @@ -22,6 +22,8 @@  struct bcma_bus;  /* main.c */ +bool bcma_wait_value(struct bcma_device *core, u16 reg, u32 mask, u32 value, +		     int timeout);  int bcma_bus_register(struct bcma_bus *bus);  void bcma_bus_unregister(struct bcma_bus *bus);  int __init bcma_bus_early_register(struct bcma_bus *bus, diff --git a/drivers/bcma/core.c b/drivers/bcma/core.c index 17b26ce7e051..37a5ffe673d5 100644 --- a/drivers/bcma/core.c +++ b/drivers/bcma/core.c @@ -9,6 +9,25 @@  #include <linux/export.h>  #include <linux/bcma/bcma.h> +static bool bcma_core_wait_value(struct bcma_device *core, u16 reg, u32 mask, +				 u32 value, int timeout) +{ +	unsigned long deadline = jiffies + timeout; +	u32 val; + +	do { +		val = bcma_aread32(core, reg); +		if ((val & mask) == value) +			return true; +		cpu_relax(); +		udelay(10); +	} while (!time_after_eq(jiffies, deadline)); + +	bcma_warn(core->bus, "Timeout waiting for register 0x%04X!\n", reg); + +	return false; +} +  bool bcma_core_is_enabled(struct bcma_device *core)  {  	if ((bcma_aread32(core, BCMA_IOCTL) & (BCMA_IOCTL_CLK | BCMA_IOCTL_FGC)) @@ -25,13 +44,15 @@ void bcma_core_disable(struct bcma_device *core, u32 flags)  	if (bcma_aread32(core, BCMA_RESET_CTL) & BCMA_RESET_CTL_RESET)  		return; -	bcma_awrite32(core, BCMA_IOCTL, flags); -	bcma_aread32(core, BCMA_IOCTL); -	udelay(10); +	bcma_core_wait_value(core, BCMA_RESET_ST, ~0, 0, 300);  	bcma_awrite32(core, BCMA_RESET_CTL, BCMA_RESET_CTL_RESET);  	bcma_aread32(core, BCMA_RESET_CTL);  	udelay(1); + +	bcma_awrite32(core, BCMA_IOCTL, flags); +	bcma_aread32(core, BCMA_IOCTL); +	udelay(10);  }  EXPORT_SYMBOL_GPL(bcma_core_disable); @@ -43,6 +64,7 @@ int bcma_core_enable(struct bcma_device *core, u32 flags)  	bcma_aread32(core, BCMA_IOCTL);  	bcma_awrite32(core, BCMA_RESET_CTL, 0); +	bcma_aread32(core, BCMA_RESET_CTL);  	udelay(1);  	bcma_awrite32(core, BCMA_IOCTL, (BCMA_IOCTL_CLK | flags)); diff --git a/drivers/bcma/driver_chipcommon.c b/drivers/bcma/driver_chipcommon.c index 036c6744b39b..b068f98920a8 100644 --- a/drivers/bcma/driver_chipcommon.c +++ b/drivers/bcma/driver_chipcommon.c @@ -140,8 +140,15 @@ void bcma_core_chipcommon_init(struct bcma_drv_cc *cc)  	bcma_core_chipcommon_early_init(cc);  	if (cc->core->id.rev >= 20) { -		bcma_cc_write32(cc, BCMA_CC_GPIOPULLUP, 0); -		bcma_cc_write32(cc, BCMA_CC_GPIOPULLDOWN, 0); +		u32 pullup = 0, pulldown = 0; + +		if (cc->core->bus->chipinfo.id == BCMA_CHIP_ID_BCM43142) { +			pullup = 0x402e0; +			pulldown = 0x20500; +		} + +		bcma_cc_write32(cc, BCMA_CC_GPIOPULLUP, pullup); +		bcma_cc_write32(cc, BCMA_CC_GPIOPULLDOWN, pulldown);  	}  	if (cc->capabilities & BCMA_CC_CAP_PMU) diff --git a/drivers/bcma/driver_chipcommon_pmu.c b/drivers/bcma/driver_chipcommon_pmu.c index edca73af3cc0..5081a8c439cc 100644 --- a/drivers/bcma/driver_chipcommon_pmu.c +++ b/drivers/bcma/driver_chipcommon_pmu.c @@ -56,6 +56,109 @@ void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask,  }  EXPORT_SYMBOL_GPL(bcma_chipco_regctl_maskset); +static u32 bcma_pmu_xtalfreq(struct bcma_drv_cc *cc) +{ +	u32 ilp_ctl, alp_hz; + +	if (!(bcma_cc_read32(cc, BCMA_CC_PMU_STAT) & +	      BCMA_CC_PMU_STAT_EXT_LPO_AVAIL)) +		return 0; + +	bcma_cc_write32(cc, BCMA_CC_PMU_XTAL_FREQ, +			BIT(BCMA_CC_PMU_XTAL_FREQ_MEASURE_SHIFT)); +	usleep_range(1000, 2000); + +	ilp_ctl = bcma_cc_read32(cc, BCMA_CC_PMU_XTAL_FREQ); +	ilp_ctl &= BCMA_CC_PMU_XTAL_FREQ_ILPCTL_MASK; + +	bcma_cc_write32(cc, BCMA_CC_PMU_XTAL_FREQ, 0); + +	alp_hz = ilp_ctl * 32768 / 4; +	return (alp_hz + 50000) / 100000 * 100; +} + +static void bcma_pmu2_pll_init0(struct bcma_drv_cc *cc, u32 xtalfreq) +{ +	struct bcma_bus *bus = cc->core->bus; +	u32 freq_tgt_target = 0, freq_tgt_current; +	u32 pll0, mask; + +	switch (bus->chipinfo.id) { +	case BCMA_CHIP_ID_BCM43142: +		/* pmu2_xtaltab0_adfll_485 */ +		switch (xtalfreq) { +		case 12000: +			freq_tgt_target = 0x50D52; +			break; +		case 20000: +			freq_tgt_target = 0x307FE; +			break; +		case 26000: +			freq_tgt_target = 0x254EA; +			break; +		case 37400: +			freq_tgt_target = 0x19EF8; +			break; +		case 52000: +			freq_tgt_target = 0x12A75; +			break; +		} +		break; +	} + +	if (!freq_tgt_target) { +		bcma_err(bus, "Unknown TGT frequency for xtalfreq %d\n", +			 xtalfreq); +		return; +	} + +	pll0 = bcma_chipco_pll_read(cc, BCMA_CC_PMU15_PLL_PLLCTL0); +	freq_tgt_current = (pll0 & BCMA_CC_PMU15_PLL_PC0_FREQTGT_MASK) >> +		BCMA_CC_PMU15_PLL_PC0_FREQTGT_SHIFT; + +	if (freq_tgt_current == freq_tgt_target) { +		bcma_debug(bus, "Target TGT frequency already set\n"); +		return; +	} + +	/* Turn off PLL */ +	switch (bus->chipinfo.id) { +	case BCMA_CHIP_ID_BCM43142: +		mask = (u32)~(BCMA_RES_4314_HT_AVAIL | +			      BCMA_RES_4314_MACPHY_CLK_AVAIL); + +		bcma_cc_mask32(cc, BCMA_CC_PMU_MINRES_MSK, mask); +		bcma_cc_mask32(cc, BCMA_CC_PMU_MAXRES_MSK, mask); +		bcma_wait_value(cc->core, BCMA_CLKCTLST, +				BCMA_CLKCTLST_HAVEHT, 0, 20000); +		break; +	} + +	pll0 &= ~BCMA_CC_PMU15_PLL_PC0_FREQTGT_MASK; +	pll0 |= freq_tgt_target << BCMA_CC_PMU15_PLL_PC0_FREQTGT_SHIFT; +	bcma_chipco_pll_write(cc, BCMA_CC_PMU15_PLL_PLLCTL0, pll0); + +	/* Flush */ +	if (cc->pmu.rev >= 2) +		bcma_cc_set32(cc, BCMA_CC_PMU_CTL, BCMA_CC_PMU_CTL_PLL_UPD); + +	/* TODO: Do we need to update OTP? */ +} + +static void bcma_pmu_pll_init(struct bcma_drv_cc *cc) +{ +	struct bcma_bus *bus = cc->core->bus; +	u32 xtalfreq = bcma_pmu_xtalfreq(cc); + +	switch (bus->chipinfo.id) { +	case BCMA_CHIP_ID_BCM43142: +		if (xtalfreq == 0) +			xtalfreq = 20000; +		bcma_pmu2_pll_init0(cc, xtalfreq); +		break; +	} +} +  static void bcma_pmu_resources_init(struct bcma_drv_cc *cc)  {  	struct bcma_bus *bus = cc->core->bus; @@ -66,6 +169,25 @@ static void bcma_pmu_resources_init(struct bcma_drv_cc *cc)  		min_msk = 0x200D;  		max_msk = 0xFFFF;  		break; +	case BCMA_CHIP_ID_BCM43142: +		min_msk = BCMA_RES_4314_LPLDO_PU | +			  BCMA_RES_4314_PMU_SLEEP_DIS | +			  BCMA_RES_4314_PMU_BG_PU | +			  BCMA_RES_4314_CBUCK_LPOM_PU | +			  BCMA_RES_4314_CBUCK_PFM_PU | +			  BCMA_RES_4314_CLDO_PU | +			  BCMA_RES_4314_LPLDO2_LVM | +			  BCMA_RES_4314_WL_PMU_PU | +			  BCMA_RES_4314_LDO3P3_PU | +			  BCMA_RES_4314_OTP_PU | +			  BCMA_RES_4314_WL_PWRSW_PU | +			  BCMA_RES_4314_LQ_AVAIL | +			  BCMA_RES_4314_LOGIC_RET | +			  BCMA_RES_4314_MEM_SLEEP | +			  BCMA_RES_4314_MACPHY_RET | +			  BCMA_RES_4314_WL_CORE_READY; +		max_msk = 0x3FFFFFFF; +		break;  	default:  		bcma_debug(bus, "PMU resource config unknown or not needed for device 0x%04X\n",  			   bus->chipinfo.id); @@ -165,6 +287,7 @@ void bcma_pmu_init(struct bcma_drv_cc *cc)  		bcma_cc_set32(cc, BCMA_CC_PMU_CTL,  			     BCMA_CC_PMU_CTL_NOILPONW); +	bcma_pmu_pll_init(cc);  	bcma_pmu_resources_init(cc);  	bcma_pmu_workarounds(cc);  } diff --git a/drivers/bcma/driver_chipcommon_sflash.c b/drivers/bcma/driver_chipcommon_sflash.c index e6ed4fe5dced..4d07cce9c5d9 100644 --- a/drivers/bcma/driver_chipcommon_sflash.c +++ b/drivers/bcma/driver_chipcommon_sflash.c @@ -30,7 +30,7 @@ struct bcma_sflash_tbl_e {  	u16 numblocks;  }; -static struct bcma_sflash_tbl_e bcma_sflash_st_tbl[] = { +static const struct bcma_sflash_tbl_e bcma_sflash_st_tbl[] = {  	{ "M25P20", 0x11, 0x10000, 4, },  	{ "M25P40", 0x12, 0x10000, 8, }, @@ -41,7 +41,7 @@ static struct bcma_sflash_tbl_e bcma_sflash_st_tbl[] = {  	{ 0 },  }; -static struct bcma_sflash_tbl_e bcma_sflash_sst_tbl[] = { +static const struct bcma_sflash_tbl_e bcma_sflash_sst_tbl[] = {  	{ "SST25WF512", 1, 0x1000, 16, },  	{ "SST25VF512", 0x48, 0x1000, 16, },  	{ "SST25WF010", 2, 0x1000, 32, }, @@ -59,7 +59,7 @@ static struct bcma_sflash_tbl_e bcma_sflash_sst_tbl[] = {  	{ 0 },  }; -static struct bcma_sflash_tbl_e bcma_sflash_at_tbl[] = { +static const struct bcma_sflash_tbl_e bcma_sflash_at_tbl[] = {  	{ "AT45DB011", 0xc, 256, 512, },  	{ "AT45DB021", 0x14, 256, 1024, },  	{ "AT45DB041", 0x1c, 256, 2048, }, @@ -89,7 +89,7 @@ int bcma_sflash_init(struct bcma_drv_cc *cc)  {  	struct bcma_bus *bus = cc->core->bus;  	struct bcma_sflash *sflash = &cc->sflash; -	struct bcma_sflash_tbl_e *e; +	const struct bcma_sflash_tbl_e *e;  	u32 id, id2;  	switch (cc->capabilities & BCMA_CC_CAP_FLASHT) { diff --git a/drivers/bcma/host_pci.c b/drivers/bcma/host_pci.c index fbf2759e7e4e..a355e63a3838 100644 --- a/drivers/bcma/host_pci.c +++ b/drivers/bcma/host_pci.c @@ -275,6 +275,7 @@ static DEFINE_PCI_DEVICE_TABLE(bcma_pci_bridge_tbl) = {  	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4357) },  	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4358) },  	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4359) }, +	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4365) },  	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) },  	{ 0, },  }; diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c index f72f52b4b1dd..0067422ec17d 100644 --- a/drivers/bcma/main.c +++ b/drivers/bcma/main.c @@ -93,6 +93,25 @@ struct bcma_device *bcma_find_core_unit(struct bcma_bus *bus, u16 coreid,  	return NULL;  } +bool bcma_wait_value(struct bcma_device *core, u16 reg, u32 mask, u32 value, +		     int timeout) +{ +	unsigned long deadline = jiffies + timeout; +	u32 val; + +	do { +		val = bcma_read32(core, reg); +		if ((val & mask) == value) +			return true; +		cpu_relax(); +		udelay(10); +	} while (!time_after_eq(jiffies, deadline)); + +	bcma_warn(core->bus, "Timeout waiting for register 0x%04X!\n", reg); + +	return false; +} +  static void bcma_release_core_dev(struct device *dev)  {  	struct bcma_device *core = container_of(dev, struct bcma_device, dev); diff --git a/drivers/bcma/sprom.c b/drivers/bcma/sprom.c index 8934298a638d..72bf4540f565 100644 --- a/drivers/bcma/sprom.c +++ b/drivers/bcma/sprom.c @@ -72,12 +72,12 @@ fail:   * R/W ops.   **************************************************/ -static void bcma_sprom_read(struct bcma_bus *bus, u16 offset, u16 *sprom) +static void bcma_sprom_read(struct bcma_bus *bus, u16 offset, u16 *sprom, +			    size_t words)  {  	int i; -	for (i = 0; i < SSB_SPROMSIZE_WORDS_R4; i++) -		sprom[i] = bcma_read16(bus->drv_cc.core, -				       offset + (i * 2)); +	for (i = 0; i < words; i++) +		sprom[i] = bcma_read16(bus->drv_cc.core, offset + (i * 2));  }  /************************************************** @@ -124,29 +124,29 @@ static inline u8 bcma_crc8(u8 crc, u8 data)  	return t[crc ^ data];  } -static u8 bcma_sprom_crc(const u16 *sprom) +static u8 bcma_sprom_crc(const u16 *sprom, size_t words)  {  	int word;  	u8 crc = 0xFF; -	for (word = 0; word < SSB_SPROMSIZE_WORDS_R4 - 1; word++) { +	for (word = 0; word < words - 1; word++) {  		crc = bcma_crc8(crc, sprom[word] & 0x00FF);  		crc = bcma_crc8(crc, (sprom[word] & 0xFF00) >> 8);  	} -	crc = bcma_crc8(crc, sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & 0x00FF); +	crc = bcma_crc8(crc, sprom[words - 1] & 0x00FF);  	crc ^= 0xFF;  	return crc;  } -static int bcma_sprom_check_crc(const u16 *sprom) +static int bcma_sprom_check_crc(const u16 *sprom, size_t words)  {  	u8 crc;  	u8 expected_crc;  	u16 tmp; -	crc = bcma_sprom_crc(sprom); -	tmp = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & SSB_SPROM_REVISION_CRC; +	crc = bcma_sprom_crc(sprom, words); +	tmp = sprom[words - 1] & SSB_SPROM_REVISION_CRC;  	expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT;  	if (crc != expected_crc)  		return -EPROTO; @@ -154,21 +154,25 @@ static int bcma_sprom_check_crc(const u16 *sprom)  	return 0;  } -static int bcma_sprom_valid(const u16 *sprom) +static int bcma_sprom_valid(struct bcma_bus *bus, const u16 *sprom, +			    size_t words)  {  	u16 revision;  	int err; -	err = bcma_sprom_check_crc(sprom); +	err = bcma_sprom_check_crc(sprom, words);  	if (err)  		return err; -	revision = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & SSB_SPROM_REVISION_REV; -	if (revision != 8 && revision != 9) { +	revision = sprom[words - 1] & SSB_SPROM_REVISION_REV; +	if (revision != 8 && revision != 9 && revision != 10) {  		pr_err("Unsupported SPROM revision: %d\n", revision);  		return -ENOENT;  	} +	bus->sprom.revision = revision; +	bcma_debug(bus, "Found SPROM revision %d\n", revision); +  	return 0;  } @@ -208,9 +212,6 @@ static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom)  	BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset) !=  			ARRAY_SIZE(bus->sprom.core_pwr_info)); -	bus->sprom.revision = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & -		SSB_SPROM_REVISION_REV; -  	for (i = 0; i < 3; i++) {  		v = sprom[SPOFF(SSB_SPROM8_IL0MAC) + i];  		*(((__be16 *)bus->sprom.il0mac) + i) = cpu_to_be16(v); @@ -502,7 +503,7 @@ static bool bcma_sprom_onchip_available(struct bcma_bus *bus)  	case BCMA_CHIP_ID_BCM4331:  		present = chip_status & BCMA_CC_CHIPST_4331_OTP_PRESENT;  		break; - +	case BCMA_CHIP_ID_BCM43142:  	case BCMA_CHIP_ID_BCM43224:  	case BCMA_CHIP_ID_BCM43225:  		/* for these chips OTP is always available */ @@ -550,7 +551,9 @@ int bcma_sprom_get(struct bcma_bus *bus)  {  	u16 offset = BCMA_CC_SPROM;  	u16 *sprom; -	int err = 0; +	size_t sprom_sizes[] = { SSB_SPROMSIZE_WORDS_R4, +				 SSB_SPROMSIZE_WORDS_R10, }; +	int i, err = 0;  	if (!bus->drv_cc.core)  		return -EOPNOTSUPP; @@ -579,32 +582,37 @@ int bcma_sprom_get(struct bcma_bus *bus)  		}  	} -	sprom = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16), -			GFP_KERNEL); -	if (!sprom) -		return -ENOMEM; -  	if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 ||  	    bus->chipinfo.id == BCMA_CHIP_ID_BCM43431)  		bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false);  	bcma_debug(bus, "SPROM offset 0x%x\n", offset); -	bcma_sprom_read(bus, offset, sprom); +	for (i = 0; i < ARRAY_SIZE(sprom_sizes); i++) { +		size_t words = sprom_sizes[i]; + +		sprom = kcalloc(words, sizeof(u16), GFP_KERNEL); +		if (!sprom) +			return -ENOMEM; + +		bcma_sprom_read(bus, offset, sprom, words); +		err = bcma_sprom_valid(bus, sprom, words); +		if (!err) +			break; + +		kfree(sprom); +	}  	if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 ||  	    bus->chipinfo.id == BCMA_CHIP_ID_BCM43431)  		bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true); -	err = bcma_sprom_valid(sprom);  	if (err) { -		bcma_warn(bus, "invalid sprom read from the PCIe card, try to use fallback sprom\n"); +		bcma_warn(bus, "Invalid SPROM read from the PCIe card, trying to use fallback SPROM\n");  		err = bcma_fill_sprom_with_fallback(bus, &bus->sprom); -		goto out; +	} else { +		bcma_sprom_extract_r8(bus, sprom); +		kfree(sprom);  	} -	bcma_sprom_extract_r8(bus, sprom); - -out: -	kfree(sprom);  	return err;  } |