You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6 into for-davem
Conflicts: drivers/net/wireless/iwlwifi/iwl-agn-tx.c net/mac80211/sta_info.h
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
What: /sys/bus/bcma/devices/.../manuf
|
||||
Date: May 2011
|
||||
KernelVersion: 2.6.40
|
||||
Contact: Rafał Miłecki <zajec5@gmail.com>
|
||||
Description:
|
||||
Each BCMA core has it's manufacturer id. See
|
||||
include/linux/bcma/bcma.h for possible values.
|
||||
|
||||
What: /sys/bus/bcma/devices/.../id
|
||||
Date: May 2011
|
||||
KernelVersion: 2.6.40
|
||||
Contact: Rafał Miłecki <zajec5@gmail.com>
|
||||
Description:
|
||||
There are a few types of BCMA cores, they can be identified by
|
||||
id field.
|
||||
|
||||
What: /sys/bus/bcma/devices/.../rev
|
||||
Date: May 2011
|
||||
KernelVersion: 2.6.40
|
||||
Contact: Rafał Miłecki <zajec5@gmail.com>
|
||||
Description:
|
||||
BCMA cores of the same type can still slightly differ depending
|
||||
on their revision. Use it for detailed programming.
|
||||
|
||||
What: /sys/bus/bcma/devices/.../class
|
||||
Date: May 2011
|
||||
KernelVersion: 2.6.40
|
||||
Contact: Rafał Miłecki <zajec5@gmail.com>
|
||||
Description:
|
||||
Each BCMA core is identified by few fields, including class it
|
||||
belongs to. See include/linux/bcma/bcma.h for possible values.
|
||||
@@ -5812,6 +5812,13 @@ S: Maintained
|
||||
F: drivers/ssb/
|
||||
F: include/linux/ssb/
|
||||
|
||||
BROADCOM SPECIFIC AMBA DRIVER (BCMA)
|
||||
M: Rafał Miłecki <zajec5@gmail.com>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/bcma/
|
||||
F: include/linux/bcma/
|
||||
|
||||
SONY VAIO CONTROL DEVICE DRIVER
|
||||
M: Mattia Dongili <malattia@linux.it>
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
|
||||
@@ -68,6 +68,8 @@ source "drivers/watchdog/Kconfig"
|
||||
|
||||
source "drivers/ssb/Kconfig"
|
||||
|
||||
source "drivers/bcma/Kconfig"
|
||||
|
||||
source "drivers/mfd/Kconfig"
|
||||
|
||||
source "drivers/regulator/Kconfig"
|
||||
|
||||
@@ -110,6 +110,7 @@ obj-$(CONFIG_HID) += hid/
|
||||
obj-$(CONFIG_PPC_PS3) += ps3/
|
||||
obj-$(CONFIG_OF) += of/
|
||||
obj-$(CONFIG_SSB) += ssb/
|
||||
obj-$(CONFIG_BCMA) += bcma/
|
||||
obj-$(CONFIG_VHOST_NET) += vhost/
|
||||
obj-$(CONFIG_VLYNQ) += vlynq/
|
||||
obj-$(CONFIG_STAGING) += staging/
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
config BCMA_POSSIBLE
|
||||
bool
|
||||
depends on HAS_IOMEM && HAS_DMA
|
||||
default y
|
||||
|
||||
menu "Broadcom specific AMBA"
|
||||
depends on BCMA_POSSIBLE
|
||||
|
||||
config BCMA
|
||||
tristate "BCMA support"
|
||||
depends on BCMA_POSSIBLE
|
||||
help
|
||||
Bus driver for Broadcom specific Advanced Microcontroller Bus
|
||||
Architecture.
|
||||
|
||||
config BCMA_HOST_PCI_POSSIBLE
|
||||
bool
|
||||
depends on BCMA && PCI = y
|
||||
default y
|
||||
|
||||
config BCMA_HOST_PCI
|
||||
bool "Support for BCMA on PCI-host bus"
|
||||
depends on BCMA_HOST_PCI_POSSIBLE
|
||||
|
||||
config BCMA_DEBUG
|
||||
bool "BCMA debugging"
|
||||
depends on BCMA
|
||||
help
|
||||
This turns on additional debugging messages.
|
||||
|
||||
If unsure, say N
|
||||
|
||||
endmenu
|
||||
@@ -0,0 +1,7 @@
|
||||
bcma-y += main.o scan.o core.o
|
||||
bcma-y += driver_chipcommon.o driver_chipcommon_pmu.o
|
||||
bcma-y += driver_pci.o
|
||||
bcma-$(CONFIG_BCMA_HOST_PCI) += host_pci.o
|
||||
obj-$(CONFIG_BCMA) += bcma.o
|
||||
|
||||
ccflags-$(CONFIG_BCMA_DEBUG) := -DDEBUG
|
||||
@@ -0,0 +1,19 @@
|
||||
Broadcom introduced new bus as replacement for older SSB. It is based on AMBA,
|
||||
however from programming point of view there is nothing AMBA specific we use.
|
||||
|
||||
Standard AMBA drivers are platform specific, have hardcoded addresses and use
|
||||
AMBA standard fields like CID and PID.
|
||||
|
||||
In case of Broadcom's cards every device consists of:
|
||||
1) Broadcom specific AMBA device. It is put on AMBA bus, but can not be treated
|
||||
as standard AMBA device. Reading it's CID or PID can cause machine lockup.
|
||||
2) AMBA standard devices called ports or wrappers. They have CIDs (AMBA_CID)
|
||||
and PIDs (0x103BB369), but we do not use that info for anything. One of that
|
||||
devices is used for managing Broadcom specific core.
|
||||
|
||||
Addresses of AMBA devices are not hardcoded in driver and have to be read from
|
||||
EPROM.
|
||||
|
||||
In this situation we decided to introduce separated bus. It can contain up to
|
||||
16 devices identified by Broadcom specific fields: manufacturer, id, revision
|
||||
and class.
|
||||
@@ -0,0 +1,3 @@
|
||||
- Interrupts
|
||||
- Defines for PCI core driver
|
||||
- Create kernel Documentation (use info from README)
|
||||
@@ -0,0 +1,28 @@
|
||||
#ifndef LINUX_BCMA_PRIVATE_H_
|
||||
#define LINUX_BCMA_PRIVATE_H_
|
||||
|
||||
#ifndef pr_fmt
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
#endif
|
||||
|
||||
#include <linux/bcma/bcma.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#define BCMA_CORE_SIZE 0x1000
|
||||
|
||||
struct bcma_bus;
|
||||
|
||||
/* main.c */
|
||||
extern int bcma_bus_register(struct bcma_bus *bus);
|
||||
extern void bcma_bus_unregister(struct bcma_bus *bus);
|
||||
|
||||
/* scan.c */
|
||||
int bcma_bus_scan(struct bcma_bus *bus);
|
||||
|
||||
#ifdef CONFIG_BCMA_HOST_PCI
|
||||
/* host_pci.c */
|
||||
extern int __init bcma_host_pci_init(void);
|
||||
extern void __exit bcma_host_pci_exit(void);
|
||||
#endif /* CONFIG_BCMA_HOST_PCI */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Broadcom specific AMBA
|
||||
* Core ops
|
||||
*
|
||||
* Licensed under the GNU/GPL. See COPYING for details.
|
||||
*/
|
||||
|
||||
#include "bcma_private.h"
|
||||
#include <linux/bcma/bcma.h>
|
||||
|
||||
bool bcma_core_is_enabled(struct bcma_device *core)
|
||||
{
|
||||
if ((bcma_aread32(core, BCMA_IOCTL) & (BCMA_IOCTL_CLK | BCMA_IOCTL_FGC))
|
||||
!= BCMA_IOCTL_CLK)
|
||||
return false;
|
||||
if (bcma_aread32(core, BCMA_RESET_CTL) & BCMA_RESET_CTL_RESET)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bcma_core_is_enabled);
|
||||
|
||||
static 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_awrite32(core, BCMA_RESET_CTL, BCMA_RESET_CTL_RESET);
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
int bcma_core_enable(struct bcma_device *core, u32 flags)
|
||||
{
|
||||
bcma_core_disable(core, flags);
|
||||
|
||||
bcma_awrite32(core, BCMA_IOCTL, (BCMA_IOCTL_CLK | BCMA_IOCTL_FGC | flags));
|
||||
bcma_aread32(core, BCMA_IOCTL);
|
||||
|
||||
bcma_awrite32(core, BCMA_RESET_CTL, 0);
|
||||
udelay(1);
|
||||
|
||||
bcma_awrite32(core, BCMA_IOCTL, (BCMA_IOCTL_CLK | flags));
|
||||
bcma_aread32(core, BCMA_IOCTL);
|
||||
udelay(1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bcma_core_enable);
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Broadcom specific AMBA
|
||||
* ChipCommon core driver
|
||||
*
|
||||
* Copyright 2005, Broadcom Corporation
|
||||
* Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
|
||||
*
|
||||
* Licensed under the GNU/GPL. See COPYING for details.
|
||||
*/
|
||||
|
||||
#include "bcma_private.h"
|
||||
#include <linux/bcma/bcma.h>
|
||||
|
||||
static inline u32 bcma_cc_write32_masked(struct bcma_drv_cc *cc, u16 offset,
|
||||
u32 mask, u32 value)
|
||||
{
|
||||
value &= mask;
|
||||
value |= bcma_cc_read32(cc, offset) & ~mask;
|
||||
bcma_cc_write32(cc, offset, value);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
void bcma_core_chipcommon_init(struct bcma_drv_cc *cc)
|
||||
{
|
||||
if (cc->core->id.rev >= 11)
|
||||
cc->status = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT);
|
||||
cc->capabilities = bcma_cc_read32(cc, BCMA_CC_CAP);
|
||||
if (cc->core->id.rev >= 35)
|
||||
cc->capabilities_ext = bcma_cc_read32(cc, BCMA_CC_CAP_EXT);
|
||||
|
||||
if (cc->core->id.rev >= 20) {
|
||||
bcma_cc_write32(cc, BCMA_CC_GPIOPULLUP, 0);
|
||||
bcma_cc_write32(cc, BCMA_CC_GPIOPULLDOWN, 0);
|
||||
}
|
||||
|
||||
if (cc->capabilities & BCMA_CC_CAP_PMU)
|
||||
bcma_pmu_init(cc);
|
||||
if (cc->capabilities & BCMA_CC_CAP_PCTL)
|
||||
pr_err("Power control not implemented!\n");
|
||||
}
|
||||
|
||||
/* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */
|
||||
void bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks)
|
||||
{
|
||||
/* instant NMI */
|
||||
bcma_cc_write32(cc, BCMA_CC_WATCHDOG, ticks);
|
||||
}
|
||||
|
||||
void bcma_chipco_irq_mask(struct bcma_drv_cc *cc, u32 mask, u32 value)
|
||||
{
|
||||
bcma_cc_write32_masked(cc, BCMA_CC_IRQMASK, mask, value);
|
||||
}
|
||||
|
||||
u32 bcma_chipco_irq_status(struct bcma_drv_cc *cc, u32 mask)
|
||||
{
|
||||
return bcma_cc_read32(cc, BCMA_CC_IRQSTAT) & mask;
|
||||
}
|
||||
|
||||
u32 bcma_chipco_gpio_in(struct bcma_drv_cc *cc, u32 mask)
|
||||
{
|
||||
return bcma_cc_read32(cc, BCMA_CC_GPIOIN) & mask;
|
||||
}
|
||||
|
||||
u32 bcma_chipco_gpio_out(struct bcma_drv_cc *cc, u32 mask, u32 value)
|
||||
{
|
||||
return bcma_cc_write32_masked(cc, BCMA_CC_GPIOOUT, mask, value);
|
||||
}
|
||||
|
||||
u32 bcma_chipco_gpio_outen(struct bcma_drv_cc *cc, u32 mask, u32 value)
|
||||
{
|
||||
return bcma_cc_write32_masked(cc, BCMA_CC_GPIOOUTEN, mask, value);
|
||||
}
|
||||
|
||||
u32 bcma_chipco_gpio_control(struct bcma_drv_cc *cc, u32 mask, u32 value)
|
||||
{
|
||||
return bcma_cc_write32_masked(cc, BCMA_CC_GPIOCTL, mask, value);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bcma_chipco_gpio_control);
|
||||
|
||||
u32 bcma_chipco_gpio_intmask(struct bcma_drv_cc *cc, u32 mask, u32 value)
|
||||
{
|
||||
return bcma_cc_write32_masked(cc, BCMA_CC_GPIOIRQ, mask, value);
|
||||
}
|
||||
|
||||
u32 bcma_chipco_gpio_polarity(struct bcma_drv_cc *cc, u32 mask, u32 value)
|
||||
{
|
||||
return bcma_cc_write32_masked(cc, BCMA_CC_GPIOPOL, mask, value);
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Broadcom specific AMBA
|
||||
* ChipCommon Power Management Unit driver
|
||||
*
|
||||
* Copyright 2009, Michael Buesch <mb@bu3sch.de>
|
||||
* Copyright 2007, Broadcom Corporation
|
||||
*
|
||||
* Licensed under the GNU/GPL. See COPYING for details.
|
||||
*/
|
||||
|
||||
#include "bcma_private.h"
|
||||
#include <linux/bcma/bcma.h>
|
||||
|
||||
static void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
|
||||
u32 offset, u32 mask, u32 set)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR);
|
||||
bcma_cc_write32(cc, BCMA_CC_CHIPCTL_ADDR, offset);
|
||||
bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR);
|
||||
value = bcma_cc_read32(cc, BCMA_CC_CHIPCTL_DATA);
|
||||
value &= mask;
|
||||
value |= set;
|
||||
bcma_cc_write32(cc, BCMA_CC_CHIPCTL_DATA, value);
|
||||
bcma_cc_read32(cc, BCMA_CC_CHIPCTL_DATA);
|
||||
}
|
||||
|
||||
static void bcma_pmu_pll_init(struct bcma_drv_cc *cc)
|
||||
{
|
||||
struct bcma_bus *bus = cc->core->bus;
|
||||
|
||||
switch (bus->chipinfo.id) {
|
||||
case 0x4313:
|
||||
case 0x4331:
|
||||
case 43224:
|
||||
case 43225:
|
||||
break;
|
||||
default:
|
||||
pr_err("PLL init unknown for device 0x%04X\n",
|
||||
bus->chipinfo.id);
|
||||
}
|
||||
}
|
||||
|
||||
static void bcma_pmu_resources_init(struct bcma_drv_cc *cc)
|
||||
{
|
||||
struct bcma_bus *bus = cc->core->bus;
|
||||
u32 min_msk = 0, max_msk = 0;
|
||||
|
||||
switch (bus->chipinfo.id) {
|
||||
case 0x4313:
|
||||
min_msk = 0x200D;
|
||||
max_msk = 0xFFFF;
|
||||
break;
|
||||
case 43224:
|
||||
break;
|
||||
default:
|
||||
pr_err("PMU resource config unknown for device 0x%04X\n",
|
||||
bus->chipinfo.id);
|
||||
}
|
||||
|
||||
/* Set the resource masks. */
|
||||
if (min_msk)
|
||||
bcma_cc_write32(cc, BCMA_CC_PMU_MINRES_MSK, min_msk);
|
||||
if (max_msk)
|
||||
bcma_cc_write32(cc, BCMA_CC_PMU_MAXRES_MSK, max_msk);
|
||||
}
|
||||
|
||||
void bcma_pmu_swreg_init(struct bcma_drv_cc *cc)
|
||||
{
|
||||
struct bcma_bus *bus = cc->core->bus;
|
||||
|
||||
switch (bus->chipinfo.id) {
|
||||
case 0x4313:
|
||||
case 0x4331:
|
||||
case 43224:
|
||||
break;
|
||||
default:
|
||||
pr_err("PMU switch/regulators init unknown for device "
|
||||
"0x%04X\n", bus->chipinfo.id);
|
||||
}
|
||||
}
|
||||
|
||||
void bcma_pmu_workarounds(struct bcma_drv_cc *cc)
|
||||
{
|
||||
struct bcma_bus *bus = cc->core->bus;
|
||||
|
||||
switch (bus->chipinfo.id) {
|
||||
case 0x4313:
|
||||
bcma_chipco_chipctl_maskset(cc, 0, ~0, 0x7);
|
||||
break;
|
||||
case 0x4331:
|
||||
pr_err("Enabling Ext PA lines not implemented\n");
|
||||
break;
|
||||
case 43224:
|
||||
if (bus->chipinfo.rev == 0) {
|
||||
pr_err("Workarounds for 43224 rev 0 not fully "
|
||||
"implemented\n");
|
||||
bcma_chipco_chipctl_maskset(cc, 0, ~0, 0xF0);
|
||||
} else {
|
||||
bcma_chipco_chipctl_maskset(cc, 0, ~0, 0xF0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
pr_err("Workarounds unknown for device 0x%04X\n",
|
||||
bus->chipinfo.id);
|
||||
}
|
||||
}
|
||||
|
||||
void bcma_pmu_init(struct bcma_drv_cc *cc)
|
||||
{
|
||||
u32 pmucap;
|
||||
|
||||
pmucap = bcma_cc_read32(cc, BCMA_CC_PMU_CAP);
|
||||
cc->pmu.rev = (pmucap & BCMA_CC_PMU_CAP_REVISION);
|
||||
|
||||
pr_debug("Found rev %u PMU (capabilities 0x%08X)\n", cc->pmu.rev,
|
||||
pmucap);
|
||||
|
||||
if (cc->pmu.rev == 1)
|
||||
bcma_cc_mask32(cc, BCMA_CC_PMU_CTL,
|
||||
~BCMA_CC_PMU_CTL_NOILPONW);
|
||||
else
|
||||
bcma_cc_set32(cc, BCMA_CC_PMU_CTL,
|
||||
BCMA_CC_PMU_CTL_NOILPONW);
|
||||
|
||||
if (cc->core->id.id == 0x4329 && cc->core->id.rev == 2)
|
||||
pr_err("Fix for 4329b0 bad LPOM state not implemented!\n");
|
||||
|
||||
bcma_pmu_pll_init(cc);
|
||||
bcma_pmu_resources_init(cc);
|
||||
bcma_pmu_swreg_init(cc);
|
||||
bcma_pmu_workarounds(cc);
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Broadcom specific AMBA
|
||||
* PCI Core
|
||||
*
|
||||
* Copyright 2005, Broadcom Corporation
|
||||
* Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
|
||||
*
|
||||
* Licensed under the GNU/GPL. See COPYING for details.
|
||||
*/
|
||||
|
||||
#include "bcma_private.h"
|
||||
#include <linux/bcma/bcma.h>
|
||||
|
||||
/**************************************************
|
||||
* R/W ops.
|
||||
**************************************************/
|
||||
|
||||
static u32 bcma_pcie_read(struct bcma_drv_pci *pc, u32 address)
|
||||
{
|
||||
pcicore_write32(pc, 0x130, address);
|
||||
pcicore_read32(pc, 0x130);
|
||||
return pcicore_read32(pc, 0x134);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void bcma_pcie_write(struct bcma_drv_pci *pc, u32 address, u32 data)
|
||||
{
|
||||
pcicore_write32(pc, 0x130, address);
|
||||
pcicore_read32(pc, 0x130);
|
||||
pcicore_write32(pc, 0x134, data);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void bcma_pcie_mdio_set_phy(struct bcma_drv_pci *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 bcma_pcie_mdio_read(struct bcma_drv_pci *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;
|
||||
|
||||
v = 0x80; /* Enable Preamble Sequence */
|
||||
v |= 0x2; /* MDIO Clock Divisor */
|
||||
pcicore_write32(pc, mdio_control, v);
|
||||
|
||||
if (pc->core->id.rev >= 10) {
|
||||
max_retries = 200;
|
||||
bcma_pcie_mdio_set_phy(pc, device);
|
||||
}
|
||||
|
||||
v = (1 << 30); /* Start of Transaction */
|
||||
v |= (1 << 29); /* Read Transaction */
|
||||
v |= (1 << 17); /* Turnaround */
|
||||
if (pc->core->id.rev < 10)
|
||||
v |= (u32)device << 22;
|
||||
v |= (u32)address << 18;
|
||||
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 */) {
|
||||
udelay(10);
|
||||
ret = pcicore_read32(pc, mdio_data);
|
||||
break;
|
||||
}
|
||||
msleep(1);
|
||||
}
|
||||
pcicore_write32(pc, mdio_control, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void bcma_pcie_mdio_write(struct bcma_drv_pci *pc, u8 device,
|
||||
u8 address, u16 data)
|
||||
{
|
||||
const u16 mdio_control = 0x128;
|
||||
const u16 mdio_data = 0x12C;
|
||||
int max_retries = 10;
|
||||
u32 v;
|
||||
int i;
|
||||
|
||||
v = 0x80; /* Enable Preamble Sequence */
|
||||
v |= 0x2; /* MDIO Clock Divisor */
|
||||
pcicore_write32(pc, mdio_control, v);
|
||||
|
||||
if (pc->core->id.rev >= 10) {
|
||||
max_retries = 200;
|
||||
bcma_pcie_mdio_set_phy(pc, device);
|
||||
}
|
||||
|
||||
v = (1 << 30); /* Start of Transaction */
|
||||
v |= (1 << 28); /* Write Transaction */
|
||||
v |= (1 << 17); /* Turnaround */
|
||||
if (pc->core->id.rev < 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);
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* Workarounds.
|
||||
**************************************************/
|
||||
|
||||
static u8 bcma_pcicore_polarity_workaround(struct bcma_drv_pci *pc)
|
||||
{
|
||||
return (bcma_pcie_read(pc, 0x204) & 0x10) ? 0xC0 : 0x80;
|
||||
}
|
||||
|
||||
static void bcma_pcicore_serdes_workaround(struct bcma_drv_pci *pc)
|
||||
{
|
||||
const u8 serdes_pll_device = 0x1D;
|
||||
const u8 serdes_rx_device = 0x1F;
|
||||
u16 tmp;
|
||||
|
||||
bcma_pcie_mdio_write(pc, serdes_rx_device, 1 /* Control */,
|
||||
bcma_pcicore_polarity_workaround(pc));
|
||||
tmp = bcma_pcie_mdio_read(pc, serdes_pll_device, 1 /* Control */);
|
||||
if (tmp & 0x4000)
|
||||
bcma_pcie_mdio_write(pc, serdes_pll_device, 1, tmp & ~0x4000);
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* Init.
|
||||
**************************************************/
|
||||
|
||||
void bcma_core_pci_init(struct bcma_drv_pci *pc)
|
||||
{
|
||||
bcma_pcicore_serdes_workaround(pc);
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* Broadcom specific AMBA
|
||||
* PCI Host
|
||||
*
|
||||
* Licensed under the GNU/GPL. See COPYING for details.
|
||||
*/
|
||||
|
||||
#include "bcma_private.h"
|
||||
#include <linux/bcma/bcma.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
static void bcma_host_pci_switch_core(struct bcma_device *core)
|
||||
{
|
||||
pci_write_config_dword(core->bus->host_pci, BCMA_PCI_BAR0_WIN,
|
||||
core->addr);
|
||||
pci_write_config_dword(core->bus->host_pci, BCMA_PCI_BAR0_WIN2,
|
||||
core->wrap);
|
||||
core->bus->mapped_core = core;
|
||||
pr_debug("Switched to core: 0x%X\n", core->id.id);
|
||||
}
|
||||
|
||||
static u8 bcma_host_pci_read8(struct bcma_device *core, u16 offset)
|
||||
{
|
||||
if (core->bus->mapped_core != core)
|
||||
bcma_host_pci_switch_core(core);
|
||||
return ioread8(core->bus->mmio + offset);
|
||||
}
|
||||
|
||||
static u16 bcma_host_pci_read16(struct bcma_device *core, u16 offset)
|
||||
{
|
||||
if (core->bus->mapped_core != core)
|
||||
bcma_host_pci_switch_core(core);
|
||||
return ioread16(core->bus->mmio + offset);
|
||||
}
|
||||
|
||||
static u32 bcma_host_pci_read32(struct bcma_device *core, u16 offset)
|
||||
{
|
||||
if (core->bus->mapped_core != core)
|
||||
bcma_host_pci_switch_core(core);
|
||||
return ioread32(core->bus->mmio + offset);
|
||||
}
|
||||
|
||||
static void bcma_host_pci_write8(struct bcma_device *core, u16 offset,
|
||||
u8 value)
|
||||
{
|
||||
if (core->bus->mapped_core != core)
|
||||
bcma_host_pci_switch_core(core);
|
||||
iowrite8(value, core->bus->mmio + offset);
|
||||
}
|
||||
|
||||
static void bcma_host_pci_write16(struct bcma_device *core, u16 offset,
|
||||
u16 value)
|
||||
{
|
||||
if (core->bus->mapped_core != core)
|
||||
bcma_host_pci_switch_core(core);
|
||||
iowrite16(value, core->bus->mmio + offset);
|
||||
}
|
||||
|
||||
static void bcma_host_pci_write32(struct bcma_device *core, u16 offset,
|
||||
u32 value)
|
||||
{
|
||||
if (core->bus->mapped_core != core)
|
||||
bcma_host_pci_switch_core(core);
|
||||
iowrite32(value, core->bus->mmio + offset);
|
||||
}
|
||||
|
||||
static u32 bcma_host_pci_aread32(struct bcma_device *core, u16 offset)
|
||||
{
|
||||
if (core->bus->mapped_core != core)
|
||||
bcma_host_pci_switch_core(core);
|
||||
return ioread32(core->bus->mmio + (1 * BCMA_CORE_SIZE) + offset);
|
||||
}
|
||||
|
||||
static void bcma_host_pci_awrite32(struct bcma_device *core, u16 offset,
|
||||
u32 value)
|
||||
{
|
||||
if (core->bus->mapped_core != core)
|
||||
bcma_host_pci_switch_core(core);
|
||||
iowrite32(value, core->bus->mmio + (1 * BCMA_CORE_SIZE) + offset);
|
||||
}
|
||||
|
||||
const struct bcma_host_ops bcma_host_pci_ops = {
|
||||
.read8 = bcma_host_pci_read8,
|
||||
.read16 = bcma_host_pci_read16,
|
||||
.read32 = bcma_host_pci_read32,
|
||||
.write8 = bcma_host_pci_write8,
|
||||
.write16 = bcma_host_pci_write16,
|
||||
.write32 = bcma_host_pci_write32,
|
||||
.aread32 = bcma_host_pci_aread32,
|
||||
.awrite32 = bcma_host_pci_awrite32,
|
||||
};
|
||||
|
||||
static int bcma_host_pci_probe(struct pci_dev *dev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
struct bcma_bus *bus;
|
||||
int err = -ENOMEM;
|
||||
const char *name;
|
||||
u32 val;
|
||||
|
||||
/* Alloc */
|
||||
bus = kzalloc(sizeof(*bus), GFP_KERNEL);
|
||||
if (!bus)
|
||||
goto out;
|
||||
|
||||
/* Basic PCI configuration */
|
||||
err = pci_enable_device(dev);
|
||||
if (err)
|
||||
goto err_kfree_bus;
|
||||
|
||||
name = dev_name(&dev->dev);
|
||||
if (dev->driver && dev->driver->name)
|
||||
name = dev->driver->name;
|
||||
err = pci_request_regions(dev, name);
|
||||
if (err)
|
||||
goto err_pci_disable;
|
||||
pci_set_master(dev);
|
||||
|
||||
/* Disable the RETRY_TIMEOUT register (0x41) to keep
|
||||
* PCI Tx retries from interfering with C3 CPU state */
|
||||
pci_read_config_dword(dev, 0x40, &val);
|
||||
if ((val & 0x0000ff00) != 0)
|
||||
pci_write_config_dword(dev, 0x40, val & 0xffff00ff);
|
||||
|
||||
/* SSB needed additional powering up, do we have any AMBA PCI cards? */
|
||||
if (!pci_is_pcie(dev))
|
||||
pr_err("PCI card detected, report problems.\n");
|
||||
|
||||
/* Map MMIO */
|
||||
err = -ENOMEM;
|
||||
bus->mmio = pci_iomap(dev, 0, ~0UL);
|
||||
if (!bus->mmio)
|
||||
goto err_pci_release_regions;
|
||||
|
||||
/* Host specific */
|
||||
bus->host_pci = dev;
|
||||
bus->hosttype = BCMA_HOSTTYPE_PCI;
|
||||
bus->ops = &bcma_host_pci_ops;
|
||||
|
||||
/* Register */
|
||||
err = bcma_bus_register(bus);
|
||||
if (err)
|
||||
goto err_pci_unmap_mmio;
|
||||
|
||||
pci_set_drvdata(dev, bus);
|
||||
|
||||
out:
|
||||
return err;
|
||||
|
||||
err_pci_unmap_mmio:
|
||||
pci_iounmap(dev, bus->mmio);
|
||||
err_pci_release_regions:
|
||||
pci_release_regions(dev);
|
||||
err_pci_disable:
|
||||
pci_disable_device(dev);
|
||||
err_kfree_bus:
|
||||
kfree(bus);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void bcma_host_pci_remove(struct pci_dev *dev)
|
||||
{
|
||||
struct bcma_bus *bus = pci_get_drvdata(dev);
|
||||
|
||||
bcma_bus_unregister(bus);
|
||||
pci_iounmap(dev, bus->mmio);
|
||||
pci_release_regions(dev);
|
||||
pci_disable_device(dev);
|
||||
kfree(bus);
|
||||
pci_set_drvdata(dev, NULL);
|
||||
}
|
||||
|
||||
static DEFINE_PCI_DEVICE_TABLE(bcma_pci_bridge_tbl) = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4331) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4353) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) },
|
||||
{ 0, },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, bcma_pci_bridge_tbl);
|
||||
|
||||
static struct pci_driver bcma_pci_bridge_driver = {
|
||||
.name = "bcma-pci-bridge",
|
||||
.id_table = bcma_pci_bridge_tbl,
|
||||
.probe = bcma_host_pci_probe,
|
||||
.remove = bcma_host_pci_remove,
|
||||
};
|
||||
|
||||
int __init bcma_host_pci_init(void)
|
||||
{
|
||||
return pci_register_driver(&bcma_pci_bridge_driver);
|
||||
}
|
||||
|
||||
void __exit bcma_host_pci_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&bcma_pci_bridge_driver);
|
||||
}
|
||||
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
* Broadcom specific AMBA
|
||||
* Bus subsystem
|
||||
*
|
||||
* Licensed under the GNU/GPL. See COPYING for details.
|
||||
*/
|
||||
|
||||
#include "bcma_private.h"
|
||||
#include <linux/bcma/bcma.h>
|
||||
|
||||
MODULE_DESCRIPTION("Broadcom's specific AMBA driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static int bcma_bus_match(struct device *dev, struct device_driver *drv);
|
||||
static int bcma_device_probe(struct device *dev);
|
||||
static int bcma_device_remove(struct device *dev);
|
||||
|
||||
static ssize_t manuf_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct bcma_device *core = container_of(dev, struct bcma_device, dev);
|
||||
return sprintf(buf, "0x%03X\n", core->id.manuf);
|
||||
}
|
||||
static ssize_t id_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct bcma_device *core = container_of(dev, struct bcma_device, dev);
|
||||
return sprintf(buf, "0x%03X\n", core->id.id);
|
||||
}
|
||||
static ssize_t rev_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct bcma_device *core = container_of(dev, struct bcma_device, dev);
|
||||
return sprintf(buf, "0x%02X\n", core->id.rev);
|
||||
}
|
||||
static ssize_t class_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct bcma_device *core = container_of(dev, struct bcma_device, dev);
|
||||
return sprintf(buf, "0x%X\n", core->id.class);
|
||||
}
|
||||
static struct device_attribute bcma_device_attrs[] = {
|
||||
__ATTR_RO(manuf),
|
||||
__ATTR_RO(id),
|
||||
__ATTR_RO(rev),
|
||||
__ATTR_RO(class),
|
||||
__ATTR_NULL,
|
||||
};
|
||||
|
||||
static struct bus_type bcma_bus_type = {
|
||||
.name = "bcma",
|
||||
.match = bcma_bus_match,
|
||||
.probe = bcma_device_probe,
|
||||
.remove = bcma_device_remove,
|
||||
.dev_attrs = bcma_device_attrs,
|
||||
};
|
||||
|
||||
static struct bcma_device *bcma_find_core(struct bcma_bus *bus, u16 coreid)
|
||||
{
|
||||
struct bcma_device *core;
|
||||
|
||||
list_for_each_entry(core, &bus->cores, list) {
|
||||
if (core->id.id == coreid)
|
||||
return core;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void bcma_release_core_dev(struct device *dev)
|
||||
{
|
||||
struct bcma_device *core = container_of(dev, struct bcma_device, dev);
|
||||
kfree(core);
|
||||
}
|
||||
|
||||
static int bcma_register_cores(struct bcma_bus *bus)
|
||||
{
|
||||
struct bcma_device *core;
|
||||
int err, dev_id = 0;
|
||||
|
||||
list_for_each_entry(core, &bus->cores, list) {
|
||||
/* We support that cores ourself */
|
||||
switch (core->id.id) {
|
||||
case BCMA_CORE_CHIPCOMMON:
|
||||
case BCMA_CORE_PCI:
|
||||
case BCMA_CORE_PCIE:
|
||||
continue;
|
||||
}
|
||||
|
||||
core->dev.release = bcma_release_core_dev;
|
||||
core->dev.bus = &bcma_bus_type;
|
||||
dev_set_name(&core->dev, "bcma%d:%d", 0/*bus->num*/, dev_id);
|
||||
|
||||
switch (bus->hosttype) {
|
||||
case BCMA_HOSTTYPE_PCI:
|
||||
core->dev.parent = &bus->host_pci->dev;
|
||||
break;
|
||||
case BCMA_HOSTTYPE_NONE:
|
||||
case BCMA_HOSTTYPE_SDIO:
|
||||
break;
|
||||
}
|
||||
|
||||
err = device_register(&core->dev);
|
||||
if (err) {
|
||||
pr_err("Could not register dev for core 0x%03X\n",
|
||||
core->id.id);
|
||||
continue;
|
||||
}
|
||||
core->dev_registered = true;
|
||||
dev_id++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bcma_unregister_cores(struct bcma_bus *bus)
|
||||
{
|
||||
struct bcma_device *core;
|
||||
|
||||
list_for_each_entry(core, &bus->cores, list) {
|
||||
if (core->dev_registered)
|
||||
device_unregister(&core->dev);
|
||||
}
|
||||
}
|
||||
|
||||
int bcma_bus_register(struct bcma_bus *bus)
|
||||
{
|
||||
int err;
|
||||
struct bcma_device *core;
|
||||
|
||||
/* Scan for devices (cores) */
|
||||
err = bcma_bus_scan(bus);
|
||||
if (err) {
|
||||
pr_err("Failed to scan: %d\n", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Init CC core */
|
||||
core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON);
|
||||
if (core) {
|
||||
bus->drv_cc.core = core;
|
||||
bcma_core_chipcommon_init(&bus->drv_cc);
|
||||
}
|
||||
|
||||
/* Init PCIE core */
|
||||
core = bcma_find_core(bus, BCMA_CORE_PCIE);
|
||||
if (core) {
|
||||
bus->drv_pci.core = core;
|
||||
bcma_core_pci_init(&bus->drv_pci);
|
||||
}
|
||||
|
||||
/* Register found cores */
|
||||
bcma_register_cores(bus);
|
||||
|
||||
pr_info("Bus registered\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bcma_bus_register);
|
||||
|
||||
void bcma_bus_unregister(struct bcma_bus *bus)
|
||||
{
|
||||
bcma_unregister_cores(bus);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bcma_bus_unregister);
|
||||
|
||||
int __bcma_driver_register(struct bcma_driver *drv, struct module *owner)
|
||||
{
|
||||
drv->drv.name = drv->name;
|
||||
drv->drv.bus = &bcma_bus_type;
|
||||
drv->drv.owner = owner;
|
||||
|
||||
return driver_register(&drv->drv);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__bcma_driver_register);
|
||||
|
||||
void bcma_driver_unregister(struct bcma_driver *drv)
|
||||
{
|
||||
driver_unregister(&drv->drv);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bcma_driver_unregister);
|
||||
|
||||
static int bcma_bus_match(struct device *dev, struct device_driver *drv)
|
||||
{
|
||||
struct bcma_device *core = container_of(dev, struct bcma_device, dev);
|
||||
struct bcma_driver *adrv = container_of(drv, struct bcma_driver, drv);
|
||||
const struct bcma_device_id *cid = &core->id;
|
||||
const struct bcma_device_id *did;
|
||||
|
||||
for (did = adrv->id_table; did->manuf || did->id || did->rev; did++) {
|
||||
if ((did->manuf == cid->manuf || did->manuf == BCMA_ANY_MANUF) &&
|
||||
(did->id == cid->id || did->id == BCMA_ANY_ID) &&
|
||||
(did->rev == cid->rev || did->rev == BCMA_ANY_REV) &&
|
||||
(did->class == cid->class || did->class == BCMA_ANY_CLASS))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcma_device_probe(struct device *dev)
|
||||
{
|
||||
struct bcma_device *core = container_of(dev, struct bcma_device, dev);
|
||||
struct bcma_driver *adrv = container_of(dev->driver, struct bcma_driver,
|
||||
drv);
|
||||
int err = 0;
|
||||
|
||||
if (adrv->probe)
|
||||
err = adrv->probe(core);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int bcma_device_remove(struct device *dev)
|
||||
{
|
||||
struct bcma_device *core = container_of(dev, struct bcma_device, dev);
|
||||
struct bcma_driver *adrv = container_of(dev->driver, struct bcma_driver,
|
||||
drv);
|
||||
|
||||
if (adrv->remove)
|
||||
adrv->remove(core);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init bcma_modinit(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bus_register(&bcma_bus_type);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
#ifdef CONFIG_BCMA_HOST_PCI
|
||||
err = bcma_host_pci_init();
|
||||
if (err) {
|
||||
pr_err("PCI host initialization failed\n");
|
||||
err = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return err;
|
||||
}
|
||||
fs_initcall(bcma_modinit);
|
||||
|
||||
static void __exit bcma_modexit(void)
|
||||
{
|
||||
#ifdef CONFIG_BCMA_HOST_PCI
|
||||
bcma_host_pci_exit();
|
||||
#endif
|
||||
bus_unregister(&bcma_bus_type);
|
||||
}
|
||||
module_exit(bcma_modexit)
|
||||
@@ -0,0 +1,360 @@
|
||||
/*
|
||||
* Broadcom specific AMBA
|
||||
* Bus scanning
|
||||
*
|
||||
* Licensed under the GNU/GPL. See COPYING for details.
|
||||
*/
|
||||
|
||||
#include "scan.h"
|
||||
#include "bcma_private.h"
|
||||
|
||||
#include <linux/bcma/bcma.h>
|
||||
#include <linux/bcma/bcma_regs.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
struct bcma_device_id_name {
|
||||
u16 id;
|
||||
const char *name;
|
||||
};
|
||||
struct bcma_device_id_name bcma_device_names[] = {
|
||||
{ BCMA_CORE_OOB_ROUTER, "OOB Router" },
|
||||
{ BCMA_CORE_INVALID, "Invalid" },
|
||||
{ BCMA_CORE_CHIPCOMMON, "ChipCommon" },
|
||||
{ BCMA_CORE_ILINE20, "ILine 20" },
|
||||
{ BCMA_CORE_SRAM, "SRAM" },
|
||||
{ BCMA_CORE_SDRAM, "SDRAM" },
|
||||
{ BCMA_CORE_PCI, "PCI" },
|
||||
{ BCMA_CORE_MIPS, "MIPS" },
|
||||
{ BCMA_CORE_ETHERNET, "Fast Ethernet" },
|
||||
{ BCMA_CORE_V90, "V90" },
|
||||
{ BCMA_CORE_USB11_HOSTDEV, "USB 1.1 Hostdev" },
|
||||
{ BCMA_CORE_ADSL, "ADSL" },
|
||||
{ BCMA_CORE_ILINE100, "ILine 100" },
|
||||
{ BCMA_CORE_IPSEC, "IPSEC" },
|
||||
{ BCMA_CORE_UTOPIA, "UTOPIA" },
|
||||
{ BCMA_CORE_PCMCIA, "PCMCIA" },
|
||||
{ BCMA_CORE_INTERNAL_MEM, "Internal Memory" },
|
||||
{ BCMA_CORE_MEMC_SDRAM, "MEMC SDRAM" },
|
||||
{ BCMA_CORE_OFDM, "OFDM" },
|
||||
{ BCMA_CORE_EXTIF, "EXTIF" },
|
||||
{ BCMA_CORE_80211, "IEEE 802.11" },
|
||||
{ BCMA_CORE_PHY_A, "PHY A" },
|
||||
{ BCMA_CORE_PHY_B, "PHY B" },
|
||||
{ BCMA_CORE_PHY_G, "PHY G" },
|
||||
{ BCMA_CORE_MIPS_3302, "MIPS 3302" },
|
||||
{ BCMA_CORE_USB11_HOST, "USB 1.1 Host" },
|
||||
{ BCMA_CORE_USB11_DEV, "USB 1.1 Device" },
|
||||
{ BCMA_CORE_USB20_HOST, "USB 2.0 Host" },
|
||||
{ BCMA_CORE_USB20_DEV, "USB 2.0 Device" },
|
||||
{ BCMA_CORE_SDIO_HOST, "SDIO Host" },
|
||||
{ BCMA_CORE_ROBOSWITCH, "Roboswitch" },
|
||||
{ BCMA_CORE_PARA_ATA, "PATA" },
|
||||
{ BCMA_CORE_SATA_XORDMA, "SATA XOR-DMA" },
|
||||
{ BCMA_CORE_ETHERNET_GBIT, "GBit Ethernet" },
|
||||
{ BCMA_CORE_PCIE, "PCIe" },
|
||||
{ BCMA_CORE_PHY_N, "PHY N" },
|
||||
{ BCMA_CORE_SRAM_CTL, "SRAM Controller" },
|
||||
{ BCMA_CORE_MINI_MACPHY, "Mini MACPHY" },
|
||||
{ BCMA_CORE_ARM_1176, "ARM 1176" },
|
||||
{ BCMA_CORE_ARM_7TDMI, "ARM 7TDMI" },
|
||||
{ BCMA_CORE_PHY_LP, "PHY LP" },
|
||||
{ BCMA_CORE_PMU, "PMU" },
|
||||
{ BCMA_CORE_PHY_SSN, "PHY SSN" },
|
||||
{ BCMA_CORE_SDIO_DEV, "SDIO Device" },
|
||||
{ BCMA_CORE_ARM_CM3, "ARM CM3" },
|
||||
{ BCMA_CORE_PHY_HT, "PHY HT" },
|
||||
{ BCMA_CORE_MIPS_74K, "MIPS 74K" },
|
||||
{ BCMA_CORE_MAC_GBIT, "GBit MAC" },
|
||||
{ BCMA_CORE_DDR12_MEM_CTL, "DDR1/DDR2 Memory Controller" },
|
||||
{ BCMA_CORE_PCIE_RC, "PCIe Root Complex" },
|
||||
{ BCMA_CORE_OCP_OCP_BRIDGE, "OCP to OCP Bridge" },
|
||||
{ BCMA_CORE_SHARED_COMMON, "Common Shared" },
|
||||
{ BCMA_CORE_OCP_AHB_BRIDGE, "OCP to AHB Bridge" },
|
||||
{ BCMA_CORE_SPI_HOST, "SPI Host" },
|
||||
{ BCMA_CORE_I2S, "I2S" },
|
||||
{ BCMA_CORE_SDR_DDR1_MEM_CTL, "SDR/DDR1 Memory Controller" },
|
||||
{ BCMA_CORE_SHIM, "SHIM" },
|
||||
{ BCMA_CORE_DEFAULT, "Default" },
|
||||
};
|
||||
const char *bcma_device_name(struct bcma_device_id *id)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (id->manuf == BCMA_MANUF_BCM) {
|
||||
for (i = 0; i < ARRAY_SIZE(bcma_device_names); i++) {
|
||||
if (bcma_device_names[i].id == id->id)
|
||||
return bcma_device_names[i].name;
|
||||
}
|
||||
}
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
static u32 bcma_scan_read32(struct bcma_bus *bus, u8 current_coreidx,
|
||||
u16 offset)
|
||||
{
|
||||
return readl(bus->mmio + offset);
|
||||
}
|
||||
|
||||
static void bcma_scan_switch_core(struct bcma_bus *bus, u32 addr)
|
||||
{
|
||||
if (bus->hosttype == BCMA_HOSTTYPE_PCI)
|
||||
pci_write_config_dword(bus->host_pci, BCMA_PCI_BAR0_WIN,
|
||||
addr);
|
||||
}
|
||||
|
||||
static u32 bcma_erom_get_ent(struct bcma_bus *bus, u32 **eromptr)
|
||||
{
|
||||
u32 ent = readl(*eromptr);
|
||||
(*eromptr)++;
|
||||
return ent;
|
||||
}
|
||||
|
||||
static void bcma_erom_push_ent(u32 **eromptr)
|
||||
{
|
||||
(*eromptr)--;
|
||||
}
|
||||
|
||||
static s32 bcma_erom_get_ci(struct bcma_bus *bus, u32 **eromptr)
|
||||
{
|
||||
u32 ent = bcma_erom_get_ent(bus, eromptr);
|
||||
if (!(ent & SCAN_ER_VALID))
|
||||
return -ENOENT;
|
||||
if ((ent & SCAN_ER_TAG) != SCAN_ER_TAG_CI)
|
||||
return -ENOENT;
|
||||
return ent;
|
||||
}
|
||||
|
||||
static bool bcma_erom_is_end(struct bcma_bus *bus, u32 **eromptr)
|
||||
{
|
||||
u32 ent = bcma_erom_get_ent(bus, eromptr);
|
||||
bcma_erom_push_ent(eromptr);
|
||||
return (ent == (SCAN_ER_TAG_END | SCAN_ER_VALID));
|
||||
}
|
||||
|
||||
static bool bcma_erom_is_bridge(struct bcma_bus *bus, u32 **eromptr)
|
||||
{
|
||||
u32 ent = bcma_erom_get_ent(bus, eromptr);
|
||||
bcma_erom_push_ent(eromptr);
|
||||
return (((ent & SCAN_ER_VALID)) &&
|
||||
((ent & SCAN_ER_TAGX) == SCAN_ER_TAG_ADDR) &&
|
||||
((ent & SCAN_ADDR_TYPE) == SCAN_ADDR_TYPE_BRIDGE));
|
||||
}
|
||||
|
||||
static void bcma_erom_skip_component(struct bcma_bus *bus, u32 **eromptr)
|
||||
{
|
||||
u32 ent;
|
||||
while (1) {
|
||||
ent = bcma_erom_get_ent(bus, eromptr);
|
||||
if ((ent & SCAN_ER_VALID) &&
|
||||
((ent & SCAN_ER_TAG) == SCAN_ER_TAG_CI))
|
||||
break;
|
||||
if (ent == (SCAN_ER_TAG_END | SCAN_ER_VALID))
|
||||
break;
|
||||
}
|
||||
bcma_erom_push_ent(eromptr);
|
||||
}
|
||||
|
||||
static s32 bcma_erom_get_mst_port(struct bcma_bus *bus, u32 **eromptr)
|
||||
{
|
||||
u32 ent = bcma_erom_get_ent(bus, eromptr);
|
||||
if (!(ent & SCAN_ER_VALID))
|
||||
return -ENOENT;
|
||||
if ((ent & SCAN_ER_TAG) != SCAN_ER_TAG_MP)
|
||||
return -ENOENT;
|
||||
return ent;
|
||||
}
|
||||
|
||||
static s32 bcma_erom_get_addr_desc(struct bcma_bus *bus, u32 **eromptr,
|
||||
u32 type, u8 port)
|
||||
{
|
||||
u32 addrl, addrh, sizel, sizeh = 0;
|
||||
u32 size;
|
||||
|
||||
u32 ent = bcma_erom_get_ent(bus, eromptr);
|
||||
if ((!(ent & SCAN_ER_VALID)) ||
|
||||
((ent & SCAN_ER_TAGX) != SCAN_ER_TAG_ADDR) ||
|
||||
((ent & SCAN_ADDR_TYPE) != type) ||
|
||||
(((ent & SCAN_ADDR_PORT) >> SCAN_ADDR_PORT_SHIFT) != port)) {
|
||||
bcma_erom_push_ent(eromptr);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
addrl = ent & SCAN_ADDR_ADDR;
|
||||
if (ent & SCAN_ADDR_AG32)
|
||||
addrh = bcma_erom_get_ent(bus, eromptr);
|
||||
else
|
||||
addrh = 0;
|
||||
|
||||
if ((ent & SCAN_ADDR_SZ) == SCAN_ADDR_SZ_SZD) {
|
||||
size = bcma_erom_get_ent(bus, eromptr);
|
||||
sizel = size & SCAN_SIZE_SZ;
|
||||
if (size & SCAN_SIZE_SG32)
|
||||
sizeh = bcma_erom_get_ent(bus, eromptr);
|
||||
} else
|
||||
sizel = SCAN_ADDR_SZ_BASE <<
|
||||
((ent & SCAN_ADDR_SZ) >> SCAN_ADDR_SZ_SHIFT);
|
||||
|
||||
return addrl;
|
||||
}
|
||||
|
||||
int bcma_bus_scan(struct bcma_bus *bus)
|
||||
{
|
||||
u32 erombase;
|
||||
u32 __iomem *eromptr, *eromend;
|
||||
|
||||
s32 cia, cib;
|
||||
u8 ports[2], wrappers[2];
|
||||
|
||||
s32 tmp;
|
||||
u8 i, j;
|
||||
|
||||
int err;
|
||||
|
||||
INIT_LIST_HEAD(&bus->cores);
|
||||
bus->nr_cores = 0;
|
||||
|
||||
bcma_scan_switch_core(bus, BCMA_ADDR_BASE);
|
||||
|
||||
tmp = bcma_scan_read32(bus, 0, BCMA_CC_ID);
|
||||
bus->chipinfo.id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT;
|
||||
bus->chipinfo.rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT;
|
||||
bus->chipinfo.pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT;
|
||||
|
||||
erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
|
||||
eromptr = bus->mmio;
|
||||
eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
|
||||
|
||||
bcma_scan_switch_core(bus, erombase);
|
||||
|
||||
while (eromptr < eromend) {
|
||||
struct bcma_device *core = kzalloc(sizeof(*core), GFP_KERNEL);
|
||||
if (!core)
|
||||
return -ENOMEM;
|
||||
INIT_LIST_HEAD(&core->list);
|
||||
core->bus = bus;
|
||||
|
||||
/* get CIs */
|
||||
cia = bcma_erom_get_ci(bus, &eromptr);
|
||||
if (cia < 0) {
|
||||
bcma_erom_push_ent(&eromptr);
|
||||
if (bcma_erom_is_end(bus, &eromptr))
|
||||
break;
|
||||
err= -EILSEQ;
|
||||
goto out;
|
||||
}
|
||||
cib = bcma_erom_get_ci(bus, &eromptr);
|
||||
if (cib < 0) {
|
||||
err= -EILSEQ;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* parse CIs */
|
||||
core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT;
|
||||
core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT;
|
||||
core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT;
|
||||
ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT;
|
||||
ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT;
|
||||
wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT;
|
||||
wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT;
|
||||
core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT;
|
||||
|
||||
if (((core->id.manuf == BCMA_MANUF_ARM) &&
|
||||
(core->id.id == 0xFFF)) ||
|
||||
(ports[1] == 0)) {
|
||||
bcma_erom_skip_component(bus, &eromptr);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* check if component is a core at all */
|
||||
if (wrappers[0] + wrappers[1] == 0) {
|
||||
/* we could save addrl of the router
|
||||
if (cid == BCMA_CORE_OOB_ROUTER)
|
||||
*/
|
||||
bcma_erom_skip_component(bus, &eromptr);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bcma_erom_is_bridge(bus, &eromptr)) {
|
||||
bcma_erom_skip_component(bus, &eromptr);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* get & parse master ports */
|
||||
for (i = 0; i < ports[0]; i++) {
|
||||
u32 mst_port_d = bcma_erom_get_mst_port(bus, &eromptr);
|
||||
if (mst_port_d < 0) {
|
||||
err= -EILSEQ;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* get & parse slave ports */
|
||||
for (i = 0; i < ports[1]; i++) {
|
||||
for (j = 0; ; j++) {
|
||||
tmp = bcma_erom_get_addr_desc(bus, &eromptr,
|
||||
SCAN_ADDR_TYPE_SLAVE, i);
|
||||
if (tmp < 0) {
|
||||
/* no more entries for port _i_ */
|
||||
/* pr_debug("erom: slave port %d "
|
||||
* "has %d descriptors\n", i, j); */
|
||||
break;
|
||||
} else {
|
||||
if (i == 0 && j == 0)
|
||||
core->addr = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* get & parse master wrappers */
|
||||
for (i = 0; i < wrappers[0]; i++) {
|
||||
for (j = 0; ; j++) {
|
||||
tmp = bcma_erom_get_addr_desc(bus, &eromptr,
|
||||
SCAN_ADDR_TYPE_MWRAP, i);
|
||||
if (tmp < 0) {
|
||||
/* no more entries for port _i_ */
|
||||
/* pr_debug("erom: master wrapper %d "
|
||||
* "has %d descriptors\n", i, j); */
|
||||
break;
|
||||
} else {
|
||||
if (i == 0 && j == 0)
|
||||
core->wrap = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* get & parse slave wrappers */
|
||||
for (i = 0; i < wrappers[1]; i++) {
|
||||
u8 hack = (ports[1] == 1) ? 0 : 1;
|
||||
for (j = 0; ; j++) {
|
||||
tmp = bcma_erom_get_addr_desc(bus, &eromptr,
|
||||
SCAN_ADDR_TYPE_SWRAP, i + hack);
|
||||
if (tmp < 0) {
|
||||
/* no more entries for port _i_ */
|
||||
/* pr_debug("erom: master wrapper %d "
|
||||
* has %d descriptors\n", i, j); */
|
||||
break;
|
||||
} else {
|
||||
if (wrappers[0] == 0 && !i && !j)
|
||||
core->wrap = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pr_info("Core %d found: %s "
|
||||
"(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
|
||||
bus->nr_cores, bcma_device_name(&core->id),
|
||||
core->id.manuf, core->id.id, core->id.rev,
|
||||
core->id.class);
|
||||
|
||||
core->core_index = bus->nr_cores++;
|
||||
list_add(&core->list, &bus->cores);
|
||||
continue;
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
#ifndef BCMA_SCAN_H_
|
||||
#define BCMA_SCAN_H_
|
||||
|
||||
#define BCMA_ADDR_BASE 0x18000000
|
||||
#define BCMA_WRAP_BASE 0x18100000
|
||||
|
||||
#define SCAN_ER_VALID 0x00000001
|
||||
#define SCAN_ER_TAGX 0x00000006 /* we have to ignore 0x8 bit when checking tag for SCAN_ER_TAG_ADDR */
|
||||
#define SCAN_ER_TAG 0x0000000E
|
||||
#define SCAN_ER_TAG_CI 0x00000000
|
||||
#define SCAN_ER_TAG_MP 0x00000002
|
||||
#define SCAN_ER_TAG_ADDR 0x00000004
|
||||
#define SCAN_ER_TAG_END 0x0000000E
|
||||
#define SCAN_ER_BAD 0xFFFFFFFF
|
||||
|
||||
#define SCAN_CIA_CLASS 0x000000F0
|
||||
#define SCAN_CIA_CLASS_SHIFT 4
|
||||
#define SCAN_CIA_ID 0x000FFF00
|
||||
#define SCAN_CIA_ID_SHIFT 8
|
||||
#define SCAN_CIA_MANUF 0xFFF00000
|
||||
#define SCAN_CIA_MANUF_SHIFT 20
|
||||
|
||||
#define SCAN_CIB_NMP 0x000001F0
|
||||
#define SCAN_CIB_NMP_SHIFT 4
|
||||
#define SCAN_CIB_NSP 0x00003E00
|
||||
#define SCAN_CIB_NSP_SHIFT 9
|
||||
#define SCAN_CIB_NMW 0x0007C000
|
||||
#define SCAN_CIB_NMW_SHIFT 14
|
||||
#define SCAN_CIB_NSW 0x00F80000
|
||||
#define SCAN_CIB_NSW_SHIFT 17
|
||||
#define SCAN_CIB_REV 0xFF000000
|
||||
#define SCAN_CIB_REV_SHIFT 24
|
||||
|
||||
#define SCAN_ADDR_AG32 0x00000008
|
||||
#define SCAN_ADDR_SZ 0x00000030
|
||||
#define SCAN_ADDR_SZ_SHIFT 4
|
||||
#define SCAN_ADDR_SZ_4K 0x00000000
|
||||
#define SCAN_ADDR_SZ_8K 0x00000010
|
||||
#define SCAN_ADDR_SZ_16K 0x00000020
|
||||
#define SCAN_ADDR_SZ_SZD 0x00000030
|
||||
#define SCAN_ADDR_TYPE 0x000000C0
|
||||
#define SCAN_ADDR_TYPE_SLAVE 0x00000000
|
||||
#define SCAN_ADDR_TYPE_BRIDGE 0x00000040
|
||||
#define SCAN_ADDR_TYPE_SWRAP 0x00000080
|
||||
#define SCAN_ADDR_TYPE_MWRAP 0x000000C0
|
||||
#define SCAN_ADDR_PORT 0x00000F00
|
||||
#define SCAN_ADDR_PORT_SHIFT 8
|
||||
#define SCAN_ADDR_ADDR 0xFFFFF000
|
||||
|
||||
#define SCAN_ADDR_SZ_BASE 0x00001000 /* 4KB */
|
||||
|
||||
#define SCAN_SIZE_SZ_ALIGN 0x00000FFF
|
||||
#define SCAN_SIZE_SZ 0xFFFFF000
|
||||
#define SCAN_SIZE_SG32 0x00000008
|
||||
|
||||
#endif /* BCMA_SCAN_H_ */
|
||||
@@ -62,6 +62,7 @@ static struct usb_device_id ath3k_table[] = {
|
||||
|
||||
/* Atheros AR3011 with sflash firmware*/
|
||||
{ USB_DEVICE(0x0CF3, 0x3002) },
|
||||
{ USB_DEVICE(0x13d3, 0x3304) },
|
||||
|
||||
/* Atheros AR9285 Malbec with sflash firmware */
|
||||
{ USB_DEVICE(0x03F0, 0x311D) },
|
||||
|
||||
@@ -104,6 +104,7 @@ static struct usb_device_id blacklist_table[] = {
|
||||
|
||||
/* Atheros 3011 with sflash firmware */
|
||||
{ USB_DEVICE(0x0cf3, 0x3002), .driver_info = BTUSB_IGNORE },
|
||||
{ USB_DEVICE(0x13d3, 0x3304), .driver_info = BTUSB_IGNORE },
|
||||
|
||||
/* Atheros AR9285 Malbec with sflash firmware */
|
||||
{ USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE },
|
||||
|
||||
@@ -2394,7 +2394,7 @@ ath5k_init_softc(struct ath5k_softc *sc, const struct ath_bus_ops *bus_ops)
|
||||
spin_lock_init(&sc->rxbuflock);
|
||||
spin_lock_init(&sc->txbuflock);
|
||||
spin_lock_init(&sc->block);
|
||||
|
||||
spin_lock_init(&sc->irqlock);
|
||||
|
||||
/* Setup interrupt handler */
|
||||
ret = request_irq(sc->irq, ath5k_intr, IRQF_SHARED, "ath", sc);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user