You've already forked linux-rockchip
mirror of
https://github.com/armbian/linux-rockchip.git
synced 2026-01-06 11:08:10 -08:00
[SSB]: add Sonics Silicon Backplane bus support
SSB is an SoC bus used in a number of embedded devices. The most well-known of these devices is probably the Linksys WRT54G, but there are others as well. The bus is also used internally on the BCM43xx and BCM44xx devices from Broadcom. This patch also includes support for SSB ID tables in modules, so that SSB drivers can be loaded automatically. Signed-off-by: Michael Buesch <mb@bu3sch.de> Signed-off-by: John W. Linville <linville@tuxdriver.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
5ee3afba88
commit
61e115a56d
@@ -3446,6 +3446,12 @@ M: tsbogend@alpha.franken.de
|
||||
L: netdev@vger.kernel.org
|
||||
S: Maintained
|
||||
|
||||
SONICS SILICON BACKPLANE DRIVER (SSB)
|
||||
P: Michael Buesch
|
||||
M: mb@bu3sch.de
|
||||
L: netdev@vger.kernel.org
|
||||
S: Maintained
|
||||
|
||||
SONY VAIO CONTROL DEVICE DRIVER
|
||||
P: Mattia Dongili
|
||||
M: malattia@linux.it
|
||||
|
||||
@@ -58,6 +58,8 @@ source "drivers/power/Kconfig"
|
||||
|
||||
source "drivers/hwmon/Kconfig"
|
||||
|
||||
source "drivers/ssb/Kconfig"
|
||||
|
||||
source "drivers/mfd/Kconfig"
|
||||
|
||||
source "drivers/media/Kconfig"
|
||||
|
||||
@@ -88,3 +88,4 @@ obj-$(CONFIG_DMA_ENGINE) += dma/
|
||||
obj-$(CONFIG_HID) += hid/
|
||||
obj-$(CONFIG_PPC_PS3) += ps3/
|
||||
obj-$(CONFIG_OF) += of/
|
||||
obj-$(CONFIG_SSB) += ssb/
|
||||
|
||||
117
drivers/ssb/Kconfig
Normal file
117
drivers/ssb/Kconfig
Normal file
@@ -0,0 +1,117 @@
|
||||
menu "Sonics Silicon Backplane"
|
||||
|
||||
config SSB_POSSIBLE
|
||||
bool
|
||||
depends on HAS_IOMEM
|
||||
default y
|
||||
|
||||
config SSB
|
||||
tristate "Sonics Silicon Backplane support"
|
||||
depends on SSB_POSSIBLE
|
||||
help
|
||||
Support for the Sonics Silicon Backplane bus.
|
||||
You only need to enable this option, if you are
|
||||
configuring a kernel for an embedded system with
|
||||
this bus.
|
||||
It will be auto-selected if needed in other
|
||||
environments.
|
||||
|
||||
The module will be called ssb.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config SSB_PCIHOST_POSSIBLE
|
||||
bool
|
||||
depends on SSB && PCI
|
||||
default y
|
||||
|
||||
config SSB_PCIHOST
|
||||
bool "Support for SSB on PCI-bus host"
|
||||
depends on SSB_PCIHOST_POSSIBLE
|
||||
default y
|
||||
help
|
||||
Support for a Sonics Silicon Backplane on top
|
||||
of a PCI device.
|
||||
|
||||
If unsure, say Y
|
||||
|
||||
config SSB_PCMCIAHOST_POSSIBLE
|
||||
bool
|
||||
depends on SSB && PCMCIA && EXPERIMENTAL
|
||||
default y
|
||||
|
||||
config SSB_PCMCIAHOST
|
||||
bool "Support for SSB on PCMCIA-bus host (EXPERIMENTAL)"
|
||||
depends on SSB_PCMCIAHOST_POSSIBLE
|
||||
help
|
||||
Support for a Sonics Silicon Backplane on top
|
||||
of a PCMCIA device.
|
||||
|
||||
If unsure, say N
|
||||
|
||||
config SSB_SILENT
|
||||
bool "No SSB kernel messages"
|
||||
depends on SSB && EMBEDDED
|
||||
help
|
||||
This option turns off all Sonics Silicon Backplane printks.
|
||||
Note that you won't be able to identify problems, once
|
||||
messages are turned off.
|
||||
This might only be desired for production kernels on
|
||||
embedded devices to reduce the kernel size.
|
||||
|
||||
Say N
|
||||
|
||||
config SSB_DEBUG
|
||||
bool "SSB debugging"
|
||||
depends on SSB && !SSB_SILENT
|
||||
help
|
||||
This turns on additional runtime checks and debugging
|
||||
messages. Turn this on for SSB troubleshooting.
|
||||
|
||||
If unsure, say N
|
||||
|
||||
config SSB_SERIAL
|
||||
bool
|
||||
depends on SSB
|
||||
# ChipCommon and ExtIf serial support routines.
|
||||
|
||||
config SSB_DRIVER_PCICORE_POSSIBLE
|
||||
bool
|
||||
depends on SSB_PCIHOST
|
||||
default y
|
||||
|
||||
config SSB_DRIVER_PCICORE
|
||||
bool "SSB PCI core driver"
|
||||
depends on SSB_DRIVER_PCICORE_POSSIBLE
|
||||
help
|
||||
Driver for the Sonics Silicon Backplane attached
|
||||
Broadcom PCI core.
|
||||
|
||||
If unsure, say Y
|
||||
|
||||
config SSB_PCICORE_HOSTMODE
|
||||
bool "Hostmode support for SSB PCI core (EXPERIMENTAL)"
|
||||
depends on SSB_DRIVER_PCICORE && SSB_DRIVER_MIPS && EXPERIMENTAL
|
||||
help
|
||||
PCIcore hostmode operation (external PCI bus).
|
||||
|
||||
config SSB_DRIVER_MIPS
|
||||
bool "SSB Broadcom MIPS core driver (EXPERIMENTAL)"
|
||||
depends on SSB && MIPS && EXPERIMENTAL
|
||||
select SSB_SERIAL
|
||||
help
|
||||
Driver for the Sonics Silicon Backplane attached
|
||||
Broadcom MIPS core.
|
||||
|
||||
If unsure, say N
|
||||
|
||||
config SSB_DRIVER_EXTIF
|
||||
bool "SSB Broadcom EXTIF core driver (EXPERIMENTAL)"
|
||||
depends on SSB_DRIVER_MIPS && EXPERIMENTAL
|
||||
help
|
||||
Driver for the Sonics Silicon Backplane attached
|
||||
Broadcom EXTIF core.
|
||||
|
||||
If unsure, say N
|
||||
|
||||
endmenu
|
||||
18
drivers/ssb/Makefile
Normal file
18
drivers/ssb/Makefile
Normal file
@@ -0,0 +1,18 @@
|
||||
# core
|
||||
ssb-y += main.o scan.o
|
||||
|
||||
# host support
|
||||
ssb-$(CONFIG_SSB_PCIHOST) += pci.o pcihost_wrapper.o
|
||||
ssb-$(CONFIG_SSB_PCMCIAHOST) += pcmcia.o
|
||||
|
||||
# built-in drivers
|
||||
ssb-y += driver_chipcommon.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
|
||||
|
||||
# b43 pci-ssb-bridge driver
|
||||
# Not strictly a part of SSB, but kept here for convenience
|
||||
ssb-$(CONFIG_SSB_PCIHOST) += b43_pci_bridge.o
|
||||
|
||||
obj-$(CONFIG_SSB) += ssb.o
|
||||
46
drivers/ssb/b43_pci_bridge.c
Normal file
46
drivers/ssb/b43_pci_bridge.c
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Broadcom 43xx PCI-SSB bridge module
|
||||
*
|
||||
* This technically is a seperate PCI driver module, but
|
||||
* 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>
|
||||
*
|
||||
* Licensed under the GNU/GPL. See COPYING for details.
|
||||
*/
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/ssb/ssb.h>
|
||||
|
||||
|
||||
static const struct pci_device_id b43_pci_bridge_tbl[] = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4301) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4307) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4311) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4312) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4318) },
|
||||
{ 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, 0x4324) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4325) },
|
||||
{ 0, },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, b43_pci_bridge_tbl);
|
||||
|
||||
static struct pci_driver b43_pci_bridge_driver = {
|
||||
.name = "b43-pci-bridge",
|
||||
.id_table = b43_pci_bridge_tbl,
|
||||
};
|
||||
|
||||
|
||||
int __init b43_pci_ssb_bridge_init(void)
|
||||
{
|
||||
return ssb_pcihost_register(&b43_pci_bridge_driver);
|
||||
}
|
||||
|
||||
void __exit b43_pci_ssb_bridge_exit(void)
|
||||
{
|
||||
ssb_pcihost_unregister(&b43_pci_bridge_driver);
|
||||
}
|
||||
446
drivers/ssb/driver_chipcommon.c
Normal file
446
drivers/ssb/driver_chipcommon.c
Normal file
@@ -0,0 +1,446 @@
|
||||
/*
|
||||
* Sonics Silicon Backplane
|
||||
* Broadcom 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 <linux/ssb/ssb.h>
|
||||
#include <linux/ssb/ssb_regs.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include "ssb_private.h"
|
||||
|
||||
|
||||
/* Clock sources */
|
||||
enum ssb_clksrc {
|
||||
/* PCI clock */
|
||||
SSB_CHIPCO_CLKSRC_PCI,
|
||||
/* Crystal slow clock oscillator */
|
||||
SSB_CHIPCO_CLKSRC_XTALOS,
|
||||
/* Low power oscillator */
|
||||
SSB_CHIPCO_CLKSRC_LOPWROS,
|
||||
};
|
||||
|
||||
|
||||
static inline u32 chipco_read32(struct ssb_chipcommon *cc,
|
||||
u16 offset)
|
||||
{
|
||||
return ssb_read32(cc->dev, offset);
|
||||
}
|
||||
|
||||
static inline void chipco_write32(struct ssb_chipcommon *cc,
|
||||
u16 offset,
|
||||
u32 value)
|
||||
{
|
||||
ssb_write32(cc->dev, offset, value);
|
||||
}
|
||||
|
||||
static inline void chipco_write32_masked(struct ssb_chipcommon *cc, u16 offset,
|
||||
u32 mask, u32 value)
|
||||
{
|
||||
value &= mask;
|
||||
value |= chipco_read32(cc, offset) & ~mask;
|
||||
chipco_write32(cc, offset, value);
|
||||
}
|
||||
|
||||
void ssb_chipco_set_clockmode(struct ssb_chipcommon *cc,
|
||||
enum ssb_clkmode mode)
|
||||
{
|
||||
struct ssb_device *ccdev = cc->dev;
|
||||
struct ssb_bus *bus;
|
||||
u32 tmp;
|
||||
|
||||
if (!ccdev)
|
||||
return;
|
||||
bus = ccdev->bus;
|
||||
/* 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 */
|
||||
if (ccdev->id.revision >= 10)
|
||||
return;
|
||||
if (!(cc->capabilities & SSB_CHIPCO_CAP_PCTL))
|
||||
return;
|
||||
|
||||
switch (mode) {
|
||||
case SSB_CLKMODE_SLOW:
|
||||
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);
|
||||
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);
|
||||
break;
|
||||
default:
|
||||
SSB_WARN_ON(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the Slow Clock Source */
|
||||
static enum ssb_clksrc chipco_pctl_get_slowclksrc(struct ssb_chipcommon *cc)
|
||||
{
|
||||
struct ssb_bus *bus = cc->dev->bus;
|
||||
u32 uninitialized_var(tmp);
|
||||
|
||||
if (cc->dev->id.revision < 6) {
|
||||
if (bus->bustype == SSB_BUSTYPE_SSB ||
|
||||
bus->bustype == SSB_BUSTYPE_PCMCIA)
|
||||
return SSB_CHIPCO_CLKSRC_XTALOS;
|
||||
if (bus->bustype == SSB_BUSTYPE_PCI) {
|
||||
pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT, &tmp);
|
||||
if (tmp & 0x10)
|
||||
return SSB_CHIPCO_CLKSRC_PCI;
|
||||
return SSB_CHIPCO_CLKSRC_XTALOS;
|
||||
}
|
||||
}
|
||||
if (cc->dev->id.revision < 10) {
|
||||
tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL);
|
||||
tmp &= 0x7;
|
||||
if (tmp == 0)
|
||||
return SSB_CHIPCO_CLKSRC_LOPWROS;
|
||||
if (tmp == 1)
|
||||
return SSB_CHIPCO_CLKSRC_XTALOS;
|
||||
if (tmp == 2)
|
||||
return SSB_CHIPCO_CLKSRC_PCI;
|
||||
}
|
||||
|
||||
return SSB_CHIPCO_CLKSRC_XTALOS;
|
||||
}
|
||||
|
||||
/* Get maximum or minimum (depending on get_max flag) slowclock frequency. */
|
||||
static int chipco_pctl_clockfreqlimit(struct ssb_chipcommon *cc, int get_max)
|
||||
{
|
||||
int uninitialized_var(limit);
|
||||
enum ssb_clksrc clocksrc;
|
||||
int divisor = 1;
|
||||
u32 tmp;
|
||||
|
||||
clocksrc = chipco_pctl_get_slowclksrc(cc);
|
||||
if (cc->dev->id.revision < 6) {
|
||||
switch (clocksrc) {
|
||||
case SSB_CHIPCO_CLKSRC_PCI:
|
||||
divisor = 64;
|
||||
break;
|
||||
case SSB_CHIPCO_CLKSRC_XTALOS:
|
||||
divisor = 32;
|
||||
break;
|
||||
default:
|
||||
SSB_WARN_ON(1);
|
||||
}
|
||||
} else if (cc->dev->id.revision < 10) {
|
||||
switch (clocksrc) {
|
||||
case SSB_CHIPCO_CLKSRC_LOPWROS:
|
||||
break;
|
||||
case SSB_CHIPCO_CLKSRC_XTALOS:
|
||||
case SSB_CHIPCO_CLKSRC_PCI:
|
||||
tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL);
|
||||
divisor = (tmp >> 16) + 1;
|
||||
divisor *= 4;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
tmp = chipco_read32(cc, SSB_CHIPCO_SYSCLKCTL);
|
||||
divisor = (tmp >> 16) + 1;
|
||||
divisor *= 4;
|
||||
}
|
||||
|
||||
switch (clocksrc) {
|
||||
case SSB_CHIPCO_CLKSRC_LOPWROS:
|
||||
if (get_max)
|
||||
limit = 43000;
|
||||
else
|
||||
limit = 25000;
|
||||
break;
|
||||
case SSB_CHIPCO_CLKSRC_XTALOS:
|
||||
if (get_max)
|
||||
limit = 20200000;
|
||||
else
|
||||
limit = 19800000;
|
||||
break;
|
||||
case SSB_CHIPCO_CLKSRC_PCI:
|
||||
if (get_max)
|
||||
limit = 34000000;
|
||||
else
|
||||
limit = 25000000;
|
||||
break;
|
||||
}
|
||||
limit /= divisor;
|
||||
|
||||
return limit;
|
||||
}
|
||||
|
||||
static void chipco_powercontrol_init(struct ssb_chipcommon *cc)
|
||||
{
|
||||
struct ssb_bus *bus = cc->dev->bus;
|
||||
|
||||
if (bus->chip_id == 0x4321) {
|
||||
if (bus->chip_rev == 0)
|
||||
chipco_write32(cc, SSB_CHIPCO_CHIPCTL, 0x3A4);
|
||||
else if (bus->chip_rev == 1)
|
||||
chipco_write32(cc, SSB_CHIPCO_CHIPCTL, 0xA4);
|
||||
}
|
||||
|
||||
if (!(cc->capabilities & SSB_CHIPCO_CAP_PCTL))
|
||||
return;
|
||||
|
||||
if (cc->dev->id.revision >= 10) {
|
||||
/* Set Idle Power clock rate to 1Mhz */
|
||||
chipco_write32(cc, SSB_CHIPCO_SYSCLKCTL,
|
||||
(chipco_read32(cc, SSB_CHIPCO_SYSCLKCTL) &
|
||||
0x0000FFFF) | 0x00040000);
|
||||
} else {
|
||||
int maxfreq;
|
||||
|
||||
maxfreq = chipco_pctl_clockfreqlimit(cc, 1);
|
||||
chipco_write32(cc, SSB_CHIPCO_PLLONDELAY,
|
||||
(maxfreq * 150 + 999999) / 1000000);
|
||||
chipco_write32(cc, SSB_CHIPCO_FREFSELDELAY,
|
||||
(maxfreq * 15 + 999999) / 1000000);
|
||||
}
|
||||
}
|
||||
|
||||
static void calc_fast_powerup_delay(struct ssb_chipcommon *cc)
|
||||
{
|
||||
struct ssb_bus *bus = cc->dev->bus;
|
||||
int minfreq;
|
||||
unsigned int tmp;
|
||||
u32 pll_on_delay;
|
||||
|
||||
if (bus->bustype != SSB_BUSTYPE_PCI)
|
||||
return;
|
||||
if (!(cc->capabilities & SSB_CHIPCO_CAP_PCTL))
|
||||
return;
|
||||
|
||||
minfreq = chipco_pctl_clockfreqlimit(cc, 0);
|
||||
pll_on_delay = chipco_read32(cc, SSB_CHIPCO_PLLONDELAY);
|
||||
tmp = (((pll_on_delay + 2) * 1000000) + (minfreq - 1)) / minfreq;
|
||||
SSB_WARN_ON(tmp & ~0xFFFF);
|
||||
|
||||
cc->fast_pwrup_delay = tmp;
|
||||
}
|
||||
|
||||
void ssb_chipcommon_init(struct ssb_chipcommon *cc)
|
||||
{
|
||||
if (!cc->dev)
|
||||
return; /* We don't have a ChipCommon */
|
||||
chipco_powercontrol_init(cc);
|
||||
ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST);
|
||||
calc_fast_powerup_delay(cc);
|
||||
}
|
||||
|
||||
void ssb_chipco_suspend(struct ssb_chipcommon *cc, pm_message_t state)
|
||||
{
|
||||
if (!cc->dev)
|
||||
return;
|
||||
ssb_chipco_set_clockmode(cc, SSB_CLKMODE_SLOW);
|
||||
}
|
||||
|
||||
void ssb_chipco_resume(struct ssb_chipcommon *cc)
|
||||
{
|
||||
if (!cc->dev)
|
||||
return;
|
||||
chipco_powercontrol_init(cc);
|
||||
ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST);
|
||||
}
|
||||
|
||||
/* Get the processor clock */
|
||||
void ssb_chipco_get_clockcpu(struct ssb_chipcommon *cc,
|
||||
u32 *plltype, u32 *n, u32 *m)
|
||||
{
|
||||
*n = chipco_read32(cc, SSB_CHIPCO_CLOCK_N);
|
||||
*plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT);
|
||||
switch (*plltype) {
|
||||
case SSB_PLLTYPE_2:
|
||||
case SSB_PLLTYPE_4:
|
||||
case SSB_PLLTYPE_6:
|
||||
case SSB_PLLTYPE_7:
|
||||
*m = chipco_read32(cc, SSB_CHIPCO_CLOCK_MIPS);
|
||||
break;
|
||||
case SSB_PLLTYPE_3:
|
||||
/* 5350 uses m2 to control mips */
|
||||
*m = chipco_read32(cc, SSB_CHIPCO_CLOCK_M2);
|
||||
break;
|
||||
default:
|
||||
*m = chipco_read32(cc, SSB_CHIPCO_CLOCK_SB);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the bus clock */
|
||||
void ssb_chipco_get_clockcontrol(struct ssb_chipcommon *cc,
|
||||
u32 *plltype, u32 *n, u32 *m)
|
||||
{
|
||||
*n = chipco_read32(cc, SSB_CHIPCO_CLOCK_N);
|
||||
*plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT);
|
||||
switch (*plltype) {
|
||||
case SSB_PLLTYPE_6: /* 100/200 or 120/240 only */
|
||||
*m = chipco_read32(cc, SSB_CHIPCO_CLOCK_MIPS);
|
||||
break;
|
||||
case SSB_PLLTYPE_3: /* 25Mhz, 2 dividers */
|
||||
if (cc->dev->bus->chip_id != 0x5365) {
|
||||
*m = chipco_read32(cc, SSB_CHIPCO_CLOCK_M2);
|
||||
break;
|
||||
}
|
||||
/* Fallthough */
|
||||
default:
|
||||
*m = chipco_read32(cc, SSB_CHIPCO_CLOCK_SB);
|
||||
}
|
||||
}
|
||||
|
||||
void ssb_chipco_timing_init(struct ssb_chipcommon *cc,
|
||||
unsigned long ns)
|
||||
{
|
||||
struct ssb_device *dev = cc->dev;
|
||||
struct ssb_bus *bus = dev->bus;
|
||||
u32 tmp;
|
||||
|
||||
/* set register for external IO to control LED. */
|
||||
chipco_write32(cc, SSB_CHIPCO_PROG_CFG, 0x11);
|
||||
tmp = DIV_ROUND_UP(10, ns) << SSB_PROG_WCNT_3_SHIFT; /* Waitcount-3 = 10ns */
|
||||
tmp |= DIV_ROUND_UP(40, ns) << SSB_PROG_WCNT_1_SHIFT; /* Waitcount-1 = 40ns */
|
||||
tmp |= DIV_ROUND_UP(240, ns); /* Waitcount-0 = 240ns */
|
||||
chipco_write32(cc, SSB_CHIPCO_PROG_WAITCNT, tmp); /* 0x01020a0c for a 100Mhz clock */
|
||||
|
||||
/* Set timing for the flash */
|
||||
tmp = DIV_ROUND_UP(10, ns) << SSB_FLASH_WCNT_3_SHIFT; /* Waitcount-3 = 10nS */
|
||||
tmp |= DIV_ROUND_UP(10, ns) << SSB_FLASH_WCNT_1_SHIFT; /* Waitcount-1 = 10nS */
|
||||
tmp |= DIV_ROUND_UP(120, ns); /* Waitcount-0 = 120nS */
|
||||
if ((bus->chip_id == 0x5365) ||
|
||||
(dev->id.revision < 9))
|
||||
chipco_write32(cc, SSB_CHIPCO_FLASH_WAITCNT, tmp);
|
||||
if ((bus->chip_id == 0x5365) ||
|
||||
(dev->id.revision < 9) ||
|
||||
((bus->chip_id == 0x5350) && (bus->chip_rev == 0)))
|
||||
chipco_write32(cc, SSB_CHIPCO_PCMCIA_MEMWAIT, tmp);
|
||||
|
||||
if (bus->chip_id == 0x5350) {
|
||||
/* Enable EXTIF */
|
||||
tmp = DIV_ROUND_UP(10, ns) << SSB_PROG_WCNT_3_SHIFT; /* Waitcount-3 = 10ns */
|
||||
tmp |= DIV_ROUND_UP(20, ns) << SSB_PROG_WCNT_2_SHIFT; /* Waitcount-2 = 20ns */
|
||||
tmp |= DIV_ROUND_UP(100, ns) << SSB_PROG_WCNT_1_SHIFT; /* Waitcount-1 = 100ns */
|
||||
tmp |= DIV_ROUND_UP(120, ns); /* Waitcount-0 = 120ns */
|
||||
chipco_write32(cc, SSB_CHIPCO_PROG_WAITCNT, tmp); /* 0x01020a0c for a 100Mhz clock */
|
||||
}
|
||||
}
|
||||
|
||||
/* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */
|
||||
void
|
||||
ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc, u32 ticks)
|
||||
{
|
||||
/* instant NMI */
|
||||
chipco_write32(cc, SSB_CHIPCO_WATCHDOG, ticks);
|
||||
}
|
||||
|
||||
u32 ssb_chipco_gpio_in(struct ssb_chipcommon *cc, u32 mask)
|
||||
{
|
||||
return chipco_read32(cc, SSB_CHIPCO_GPIOIN) & mask;
|
||||
}
|
||||
|
||||
void ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value)
|
||||
{
|
||||
return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUT, mask, value);
|
||||
}
|
||||
|
||||
void ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value)
|
||||
{
|
||||
return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUTEN, mask, value);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SSB_SERIAL
|
||||
int ssb_chipco_serial_init(struct ssb_chipcommon *cc,
|
||||
struct ssb_serial_port *ports)
|
||||
{
|
||||
struct ssb_bus *bus = cc->dev->bus;
|
||||
int nr_ports = 0;
|
||||
u32 plltype;
|
||||
unsigned int irq;
|
||||
u32 baud_base, div;
|
||||
u32 i, n;
|
||||
|
||||
plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT);
|
||||
irq = ssb_mips_irq(cc->dev);
|
||||
|
||||
if (plltype == SSB_PLLTYPE_1) {
|
||||
/* PLL clock */
|
||||
baud_base = ssb_calc_clock_rate(plltype,
|
||||
chipco_read32(cc, SSB_CHIPCO_CLOCK_N),
|
||||
chipco_read32(cc, SSB_CHIPCO_CLOCK_M2));
|
||||
div = 1;
|
||||
} else {
|
||||
if (cc->dev->id.revision >= 11) {
|
||||
/* Fixed ALP clock */
|
||||
baud_base = 20000000;
|
||||
div = 1;
|
||||
/* Set the override bit so we don't divide it */
|
||||
chipco_write32(cc, SSB_CHIPCO_CORECTL,
|
||||
SSB_CHIPCO_CORECTL_UARTCLK0);
|
||||
} else if (cc->dev->id.revision >= 3) {
|
||||
/* Internal backplane clock */
|
||||
baud_base = ssb_clockspeed(bus);
|
||||
div = chipco_read32(cc, SSB_CHIPCO_CLKDIV)
|
||||
& SSB_CHIPCO_CLKDIV_UART;
|
||||
} else {
|
||||
/* Fixed internal backplane clock */
|
||||
baud_base = 88000000;
|
||||
div = 48;
|
||||
}
|
||||
|
||||
/* Clock source depends on strapping if UartClkOverride is unset */
|
||||
if ((cc->dev->id.revision > 0) &&
|
||||
!(chipco_read32(cc, SSB_CHIPCO_CORECTL) & SSB_CHIPCO_CORECTL_UARTCLK0)) {
|
||||
if ((cc->capabilities & SSB_CHIPCO_CAP_UARTCLK) ==
|
||||
SSB_CHIPCO_CAP_UARTCLK_INT) {
|
||||
/* Internal divided backplane clock */
|
||||
baud_base /= div;
|
||||
} else {
|
||||
/* Assume external clock of 1.8432 MHz */
|
||||
baud_base = 1843200;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine the registers of the UARTs */
|
||||
n = (cc->capabilities & SSB_CHIPCO_CAP_NRUART);
|
||||
for (i = 0; i < n; i++) {
|
||||
void __iomem *cc_mmio;
|
||||
void __iomem *uart_regs;
|
||||
|
||||
cc_mmio = cc->dev->bus->mmio + (cc->dev->core_index * SSB_CORE_SIZE);
|
||||
uart_regs = cc_mmio + SSB_CHIPCO_UART0_DATA;
|
||||
/* Offset changed at after rev 0 */
|
||||
if (cc->dev->id.revision == 0)
|
||||
uart_regs += (i * 8);
|
||||
else
|
||||
uart_regs += (i * 256);
|
||||
|
||||
nr_ports++;
|
||||
ports[i].regs = uart_regs;
|
||||
ports[i].irq = irq;
|
||||
ports[i].baud_base = baud_base;
|
||||
ports[i].reg_shift = 0;
|
||||
}
|
||||
|
||||
return nr_ports;
|
||||
}
|
||||
#endif /* CONFIG_SSB_SERIAL */
|
||||
129
drivers/ssb/driver_extif.c
Normal file
129
drivers/ssb/driver_extif.c
Normal file
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Sonics Silicon Backplane
|
||||
* Broadcom EXTIF core driver
|
||||
*
|
||||
* Copyright 2005, Broadcom Corporation
|
||||
* Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
|
||||
* Copyright 2006, 2007, Felix Fietkau <nbd@openwrt.org>
|
||||
* Copyright 2007, Aurelien Jarno <aurelien@aurel32.net>
|
||||
*
|
||||
* Licensed under the GNU/GPL. See COPYING for details.
|
||||
*/
|
||||
|
||||
#include <linux/serial.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/serial_reg.h>
|
||||
|
||||
#include "ssb_private.h"
|
||||
|
||||
|
||||
static inline u32 extif_read32(struct ssb_extif *extif, u16 offset)
|
||||
{
|
||||
return ssb_read32(extif->dev, offset);
|
||||
}
|
||||
|
||||
static inline void extif_write32(struct ssb_extif *extif, u16 offset, u32 value)
|
||||
{
|
||||
ssb_write32(extif->dev, offset, value);
|
||||
}
|
||||
|
||||
static inline void extif_write32_masked(struct ssb_extif *extif, u16 offset,
|
||||
u32 mask, u32 value)
|
||||
{
|
||||
value &= mask;
|
||||
value |= extif_read32(extif, offset) & ~mask;
|
||||
extif_write32(extif, offset, value);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SSB_SERIAL
|
||||
static bool serial_exists(u8 *regs)
|
||||
{
|
||||
u8 save_mcr, msr = 0;
|
||||
|
||||
if (regs) {
|
||||
save_mcr = regs[UART_MCR];
|
||||
regs[UART_MCR] = (UART_MCR_LOOP | UART_MCR_OUT2 | UART_MCR_RTS);
|
||||
msr = regs[UART_MSR] & (UART_MSR_DCD | UART_MSR_RI
|
||||
| UART_MSR_CTS | UART_MSR_DSR);
|
||||
regs[UART_MCR] = save_mcr;
|
||||
}
|
||||
return (msr == (UART_MSR_DCD | UART_MSR_CTS));
|
||||
}
|
||||
|
||||
int ssb_extif_serial_init(struct ssb_extif *extif, struct ssb_serial_port *ports)
|
||||
{
|
||||
u32 i, nr_ports = 0;
|
||||
|
||||
/* Disable GPIO interrupt initially */
|
||||
extif_write32(extif, SSB_EXTIF_GPIO_INTPOL, 0);
|
||||
extif_write32(extif, SSB_EXTIF_GPIO_INTMASK, 0);
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
void __iomem *uart_regs;
|
||||
|
||||
uart_regs = ioremap_nocache(SSB_EUART, 16);
|
||||
if (uart_regs) {
|
||||
uart_regs += (i * 8);
|
||||
|
||||
if (serial_exists(uart_regs) && ports) {
|
||||
extif_write32(extif, SSB_EXTIF_GPIO_INTMASK, 2);
|
||||
|
||||
nr_ports++;
|
||||
ports[i].regs = uart_regs;
|
||||
ports[i].irq = 2;
|
||||
ports[i].baud_base = 13500000;
|
||||
ports[i].reg_shift = 0;
|
||||
}
|
||||
iounmap(uart_regs);
|
||||
}
|
||||
}
|
||||
return nr_ports;
|
||||
}
|
||||
#endif /* CONFIG_SSB_SERIAL */
|
||||
|
||||
void ssb_extif_timing_init(struct ssb_extif *extif, unsigned long ns)
|
||||
{
|
||||
u32 tmp;
|
||||
|
||||
/* Initialize extif so we can get to the LEDs and external UART */
|
||||
extif_write32(extif, SSB_EXTIF_PROG_CFG, SSB_EXTCFG_EN);
|
||||
|
||||
/* Set timing for the flash */
|
||||
tmp = DIV_ROUND_UP(10, ns) << SSB_PROG_WCNT_3_SHIFT;
|
||||
tmp |= DIV_ROUND_UP(40, ns) << SSB_PROG_WCNT_1_SHIFT;
|
||||
tmp |= DIV_ROUND_UP(120, ns);
|
||||
extif_write32(extif, SSB_EXTIF_PROG_WAITCNT, tmp);
|
||||
|
||||
/* Set programmable interface timing for external uart */
|
||||
tmp = DIV_ROUND_UP(10, ns) << SSB_PROG_WCNT_3_SHIFT;
|
||||
tmp |= DIV_ROUND_UP(20, ns) << SSB_PROG_WCNT_2_SHIFT;
|
||||
tmp |= DIV_ROUND_UP(100, ns) << SSB_PROG_WCNT_1_SHIFT;
|
||||
tmp |= DIV_ROUND_UP(120, ns);
|
||||
extif_write32(extif, SSB_EXTIF_PROG_WAITCNT, tmp);
|
||||
}
|
||||
|
||||
void ssb_extif_get_clockcontrol(struct ssb_extif *extif,
|
||||
u32 *pll_type, u32 *n, u32 *m)
|
||||
{
|
||||
*pll_type = SSB_PLLTYPE_1;
|
||||
*n = extif_read32(extif, SSB_EXTIF_CLOCK_N);
|
||||
*m = extif_read32(extif, SSB_EXTIF_CLOCK_SB);
|
||||
}
|
||||
|
||||
u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask)
|
||||
{
|
||||
return extif_read32(extif, SSB_EXTIF_GPIO_IN) & mask;
|
||||
}
|
||||
|
||||
void ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, u32 value)
|
||||
{
|
||||
return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUT(0),
|
||||
mask, value);
|
||||
}
|
||||
|
||||
void ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, u32 value)
|
||||
{
|
||||
return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUTEN(0),
|
||||
mask, value);
|
||||
}
|
||||
|
||||
223
drivers/ssb/driver_mipscore.c
Normal file
223
drivers/ssb/driver_mipscore.c
Normal file
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
* Sonics Silicon Backplane
|
||||
* Broadcom MIPS core driver
|
||||
*
|
||||
* Copyright 2005, Broadcom Corporation
|
||||
* Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
|
||||
*
|
||||
* Licensed under the GNU/GPL. See COPYING for details.
|
||||
*/
|
||||
|
||||
#include <linux/ssb/ssb.h>
|
||||
|
||||
#include <linux/serial.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/serial_reg.h>
|
||||
#include <linux/time.h>
|
||||
|
||||
#include "ssb_private.h"
|
||||
|
||||
|
||||
static inline u32 mips_read32(struct ssb_mipscore *mcore,
|
||||
u16 offset)
|
||||
{
|
||||
return ssb_read32(mcore->dev, offset);
|
||||
}
|
||||
|
||||
static inline void mips_write32(struct ssb_mipscore *mcore,
|
||||
u16 offset,
|
||||
u32 value)
|
||||
{
|
||||
ssb_write32(mcore->dev, offset, value);
|
||||
}
|
||||
|
||||
static const u32 ipsflag_irq_mask[] = {
|
||||
0,
|
||||
SSB_IPSFLAG_IRQ1,
|
||||
SSB_IPSFLAG_IRQ2,
|
||||
SSB_IPSFLAG_IRQ3,
|
||||
SSB_IPSFLAG_IRQ4,
|
||||
};
|
||||
|
||||
static const u32 ipsflag_irq_shift[] = {
|
||||
0,
|
||||
SSB_IPSFLAG_IRQ1_SHIFT,
|
||||
SSB_IPSFLAG_IRQ2_SHIFT,
|
||||
SSB_IPSFLAG_IRQ3_SHIFT,
|
||||
SSB_IPSFLAG_IRQ4_SHIFT,
|
||||
};
|
||||
|
||||
static inline u32 ssb_irqflag(struct ssb_device *dev)
|
||||
{
|
||||
return ssb_read32(dev, SSB_TPSFLAG) & SSB_TPSFLAG_BPFLAG;
|
||||
}
|
||||
|
||||
/* Get the MIPS IRQ assignment for a specified device.
|
||||
* If unassigned, 0 is returned.
|
||||
*/
|
||||
unsigned int ssb_mips_irq(struct ssb_device *dev)
|
||||
{
|
||||
struct ssb_bus *bus = dev->bus;
|
||||
u32 irqflag;
|
||||
u32 ipsflag;
|
||||
u32 tmp;
|
||||
unsigned int irq;
|
||||
|
||||
irqflag = ssb_irqflag(dev);
|
||||
ipsflag = ssb_read32(bus->mipscore.dev, SSB_IPSFLAG);
|
||||
for (irq = 1; irq <= 4; irq++) {
|
||||
tmp = ((ipsflag & ipsflag_irq_mask[irq]) >> ipsflag_irq_shift[irq]);
|
||||
if (tmp == irqflag)
|
||||
break;
|
||||
}
|
||||
if (irq == 5)
|
||||
irq = 0;
|
||||
|
||||
return irq;
|
||||
}
|
||||
|
||||
static void clear_irq(struct ssb_bus *bus, unsigned int irq)
|
||||
{
|
||||
struct ssb_device *dev = bus->mipscore.dev;
|
||||
|
||||
/* Clear the IRQ in the MIPScore backplane registers */
|
||||
if (irq == 0) {
|
||||
ssb_write32(dev, SSB_INTVEC, 0);
|
||||
} else {
|
||||
ssb_write32(dev, SSB_IPSFLAG,
|
||||
ssb_read32(dev, SSB_IPSFLAG) |
|
||||
ipsflag_irq_mask[irq]);
|
||||
}
|
||||
}
|
||||
|
||||
static void set_irq(struct ssb_device *dev, unsigned int irq)
|
||||
{
|
||||
unsigned int oldirq = ssb_mips_irq(dev);
|
||||
struct ssb_bus *bus = dev->bus;
|
||||
struct ssb_device *mdev = bus->mipscore.dev;
|
||||
u32 irqflag = ssb_irqflag(dev);
|
||||
|
||||
dev->irq = irq + 2;
|
||||
|
||||
ssb_dprintk(KERN_INFO PFX
|
||||
"set_irq: core 0x%04x, irq %d => %d\n",
|
||||
dev->id.coreid, oldirq, irq);
|
||||
/* clear the old irq */
|
||||
if (oldirq == 0)
|
||||
ssb_write32(mdev, SSB_INTVEC, (~(1 << irqflag) & ssb_read32(mdev, SSB_INTVEC)));
|
||||
else
|
||||
clear_irq(bus, oldirq);
|
||||
|
||||
/* assign the new one */
|
||||
if (irq == 0)
|
||||
ssb_write32(mdev, SSB_INTVEC, ((1 << irqflag) & ssb_read32(mdev, SSB_INTVEC)));
|
||||
|
||||
irqflag <<= ipsflag_irq_shift[irq];
|
||||
irqflag |= (ssb_read32(mdev, SSB_IPSFLAG) & ~ipsflag_irq_mask[irq]);
|
||||
ssb_write32(mdev, SSB_IPSFLAG, irqflag);
|
||||
}
|
||||
|
||||
static void ssb_mips_serial_init(struct ssb_mipscore *mcore)
|
||||
{
|
||||
struct ssb_bus *bus = mcore->dev->bus;
|
||||
|
||||
if (bus->extif.dev)
|
||||
mcore->nr_serial_ports = ssb_extif_serial_init(&bus->extif, mcore->serial_ports);
|
||||
else if (bus->chipco.dev)
|
||||
mcore->nr_serial_ports = ssb_chipco_serial_init(&bus->chipco, mcore->serial_ports);
|
||||
else
|
||||
mcore->nr_serial_ports = 0;
|
||||
}
|
||||
|
||||
static void ssb_mips_flash_detect(struct ssb_mipscore *mcore)
|
||||
{
|
||||
struct ssb_bus *bus = mcore->dev->bus;
|
||||
|
||||
mcore->flash_buswidth = 2;
|
||||
if (bus->chipco.dev) {
|
||||
mcore->flash_window = 0x1c000000;
|
||||
mcore->flash_window_size = 0x02000000;
|
||||
if ((ssb_read32(bus->chipco.dev, SSB_CHIPCO_FLASH_CFG)
|
||||
& SSB_CHIPCO_CFG_DS16) == 0)
|
||||
mcore->flash_buswidth = 1;
|
||||
} else {
|
||||
mcore->flash_window = 0x1fc00000;
|
||||
mcore->flash_window_size = 0x00400000;
|
||||
}
|
||||
}
|
||||
|
||||
u32 ssb_cpu_clock(struct ssb_mipscore *mcore)
|
||||
{
|
||||
struct ssb_bus *bus = mcore->dev->bus;
|
||||
u32 pll_type, n, m, rate = 0;
|
||||
|
||||
if (bus->extif.dev) {
|
||||
ssb_extif_get_clockcontrol(&bus->extif, &pll_type, &n, &m);
|
||||
} else if (bus->chipco.dev) {
|
||||
ssb_chipco_get_clockcpu(&bus->chipco, &pll_type, &n, &m);
|
||||
} else
|
||||
return 0;
|
||||
|
||||
if ((pll_type == SSB_PLLTYPE_5) || (bus->chip_id == 0x5365)) {
|
||||
rate = 200000000;
|
||||
} else {
|
||||
rate = ssb_calc_clock_rate(pll_type, n, m);
|
||||
}
|
||||
|
||||
if (pll_type == SSB_PLLTYPE_6) {
|
||||
rate *= 2;
|
||||
}
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
void ssb_mipscore_init(struct ssb_mipscore *mcore)
|
||||
{
|
||||
struct ssb_bus *bus = mcore->dev->bus;
|
||||
struct ssb_device *dev;
|
||||
unsigned long hz, ns;
|
||||
unsigned int irq, i;
|
||||
|
||||
if (!mcore->dev)
|
||||
return; /* We don't have a MIPS core */
|
||||
|
||||
ssb_dprintk(KERN_INFO PFX "Initializing MIPS core...\n");
|
||||
|
||||
hz = ssb_clockspeed(bus);
|
||||
if (!hz)
|
||||
hz = 100000000;
|
||||
ns = 1000000000 / hz;
|
||||
|
||||
if (bus->extif.dev)
|
||||
ssb_extif_timing_init(&bus->extif, ns);
|
||||
else if (bus->chipco.dev)
|
||||
ssb_chipco_timing_init(&bus->chipco, ns);
|
||||
|
||||
/* Assign IRQs to all cores on the bus, start with irq line 2, because serial usually takes 1 */
|
||||
for (irq = 2, i = 0; i < bus->nr_devices; i++) {
|
||||
dev = &(bus->devices[i]);
|
||||
dev->irq = ssb_mips_irq(dev) + 2;
|
||||
switch (dev->id.coreid) {
|
||||
case SSB_DEV_USB11_HOST:
|
||||
/* shouldn't need a separate irq line for non-4710, most of them have a proper
|
||||
* external usb controller on the pci */
|
||||
if ((bus->chip_id == 0x4710) && (irq <= 4)) {
|
||||
set_irq(dev, irq++);
|
||||
break;
|
||||
}
|
||||
/* fallthrough */
|
||||
case SSB_DEV_PCI:
|
||||
case SSB_DEV_ETHERNET:
|
||||
case SSB_DEV_80211:
|
||||
case SSB_DEV_USB20_HOST:
|
||||
/* These devices get their own IRQ line if available, the rest goes on IRQ0 */
|
||||
if (irq <= 4) {
|
||||
set_irq(dev, irq++);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ssb_mips_serial_init(mcore);
|
||||
ssb_mips_flash_detect(mcore);
|
||||
}
|
||||
576
drivers/ssb/driver_pcicore.c
Normal file
576
drivers/ssb/driver_pcicore.c
Normal file
File diff suppressed because it is too large
Load Diff
1162
drivers/ssb/main.c
Normal file
1162
drivers/ssb/main.c
Normal file
File diff suppressed because it is too large
Load Diff
740
drivers/ssb/pci.c
Normal file
740
drivers/ssb/pci.c
Normal file
File diff suppressed because it is too large
Load Diff
104
drivers/ssb/pcihost_wrapper.c
Normal file
104
drivers/ssb/pcihost_wrapper.c
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Sonics Silicon Backplane
|
||||
* PCI Hostdevice wrapper
|
||||
*
|
||||
* Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>
|
||||
* Copyright (c) 2005 Stefano Brivio <st3@riseup.net>
|
||||
* Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
|
||||
* Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
|
||||
* Copyright (c) 2005-2007 Michael Buesch <mbuesch@freenet.de>
|
||||
*
|
||||
* Licensed under the GNU/GPL. See COPYING for details.
|
||||
*/
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/ssb/ssb.h>
|
||||
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int ssb_pcihost_suspend(struct pci_dev *dev, pm_message_t state)
|
||||
{
|
||||
pci_save_state(dev);
|
||||
pci_disable_device(dev);
|
||||
pci_set_power_state(dev, pci_choose_state(dev, state));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ssb_pcihost_resume(struct pci_dev *dev)
|
||||
{
|
||||
int err;
|
||||
|
||||
pci_set_power_state(dev, 0);
|
||||
err = pci_enable_device(dev);
|
||||
if (err)
|
||||
return err;
|
||||
pci_restore_state(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else /* CONFIG_PM */
|
||||
# define ssb_pcihost_suspend NULL
|
||||
# define ssb_pcihost_resume NULL
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static int ssb_pcihost_probe(struct pci_dev *dev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
struct ssb_bus *ssb;
|
||||
int err = -ENOMEM;
|
||||
const char *name;
|
||||
|
||||
ssb = kzalloc(sizeof(*ssb), GFP_KERNEL);
|
||||
if (!ssb)
|
||||
goto out;
|
||||
err = pci_enable_device(dev);
|
||||
if (err)
|
||||
goto err_kfree_ssb;
|
||||
name = dev->dev.bus_id;
|
||||
if (dev->driver && dev->driver->name)
|
||||
name = dev->driver->name;
|
||||
err = pci_request_regions(dev, name);
|
||||
if (err)
|
||||
goto err_pci_disable;
|
||||
pci_set_master(dev);
|
||||
|
||||
err = ssb_bus_pcibus_register(ssb, dev);
|
||||
if (err)
|
||||
goto err_pci_release_regions;
|
||||
|
||||
pci_set_drvdata(dev, ssb);
|
||||
|
||||
out:
|
||||
return err;
|
||||
|
||||
err_pci_release_regions:
|
||||
pci_release_regions(dev);
|
||||
err_pci_disable:
|
||||
pci_disable_device(dev);
|
||||
err_kfree_ssb:
|
||||
kfree(ssb);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void ssb_pcihost_remove(struct pci_dev *dev)
|
||||
{
|
||||
struct ssb_bus *ssb = pci_get_drvdata(dev);
|
||||
|
||||
ssb_bus_unregister(ssb);
|
||||
pci_release_regions(dev);
|
||||
pci_disable_device(dev);
|
||||
kfree(ssb);
|
||||
pci_set_drvdata(dev, NULL);
|
||||
}
|
||||
|
||||
int ssb_pcihost_register(struct pci_driver *driver)
|
||||
{
|
||||
driver->probe = ssb_pcihost_probe;
|
||||
driver->remove = ssb_pcihost_remove;
|
||||
driver->suspend = ssb_pcihost_suspend;
|
||||
driver->resume = ssb_pcihost_resume;
|
||||
|
||||
return pci_register_driver(driver);
|
||||
}
|
||||
EXPORT_SYMBOL(ssb_pcihost_register);
|
||||
271
drivers/ssb/pcmcia.c
Normal file
271
drivers/ssb/pcmcia.c
Normal file
@@ -0,0 +1,271 @@
|
||||
/*
|
||||
* Sonics Silicon Backplane
|
||||
* PCMCIA-Hostbus related functions
|
||||
*
|
||||
* Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2007 Michael Buesch <mb@bu3sch.de>
|
||||
*
|
||||
* Licensed under the GNU/GPL. See COPYING for details.
|
||||
*/
|
||||
|
||||
#include <linux/ssb/ssb.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include <pcmcia/cs_types.h>
|
||||
#include <pcmcia/cs.h>
|
||||
#include <pcmcia/cistpl.h>
|
||||
#include <pcmcia/ciscode.h>
|
||||
#include <pcmcia/ds.h>
|
||||
#include <pcmcia/cisreg.h>
|
||||
|
||||
#include "ssb_private.h"
|
||||
|
||||
|
||||
/* Define the following to 1 to enable a printk on each coreswitch. */
|
||||
#define SSB_VERBOSE_PCMCIACORESWITCH_DEBUG 0
|
||||
|
||||
|
||||
int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus,
|
||||
u8 coreidx)
|
||||
{
|
||||
struct pcmcia_device *pdev = bus->host_pcmcia;
|
||||
int err;
|
||||
int attempts = 0;
|
||||
u32 cur_core;
|
||||
conf_reg_t reg;
|
||||
u32 addr;
|
||||
u32 read_addr;
|
||||
|
||||
addr = (coreidx * SSB_CORE_SIZE) + SSB_ENUM_BASE;
|
||||
while (1) {
|
||||
reg.Action = CS_WRITE;
|
||||
reg.Offset = 0x2E;
|
||||
reg.Value = (addr & 0x0000F000) >> 12;
|
||||
err = pcmcia_access_configuration_register(pdev, ®);
|
||||
if (err != CS_SUCCESS)
|
||||
goto error;
|
||||
reg.Offset = 0x30;
|
||||
reg.Value = (addr & 0x00FF0000) >> 16;
|
||||
err = pcmcia_access_configuration_register(pdev, ®);
|
||||
if (err != CS_SUCCESS)
|
||||
goto error;
|
||||
reg.Offset = 0x32;
|
||||
reg.Value = (addr & 0xFF000000) >> 24;
|
||||
err = pcmcia_access_configuration_register(pdev, ®);
|
||||
if (err != CS_SUCCESS)
|
||||
goto error;
|
||||
|
||||
read_addr = 0;
|
||||
|
||||
reg.Action = CS_READ;
|
||||
reg.Offset = 0x2E;
|
||||
err = pcmcia_access_configuration_register(pdev, ®);
|
||||
if (err != CS_SUCCESS)
|
||||
goto error;
|
||||
read_addr |= (reg.Value & 0xF) << 12;
|
||||
reg.Offset = 0x30;
|
||||
err = pcmcia_access_configuration_register(pdev, ®);
|
||||
if (err != CS_SUCCESS)
|
||||
goto error;
|
||||
read_addr |= reg.Value << 16;
|
||||
reg.Offset = 0x32;
|
||||
err = pcmcia_access_configuration_register(pdev, ®);
|
||||
if (err != CS_SUCCESS)
|
||||
goto error;
|
||||
read_addr |= reg.Value << 24;
|
||||
|
||||
cur_core = (read_addr - SSB_ENUM_BASE) / SSB_CORE_SIZE;
|
||||
if (cur_core == coreidx)
|
||||
break;
|
||||
|
||||
if (attempts++ > SSB_BAR0_MAX_RETRIES)
|
||||
goto error;
|
||||
udelay(10);
|
||||
}
|
||||
|
||||
return 0;
|
||||
error:
|
||||
ssb_printk(KERN_ERR PFX "Failed to switch to core %u\n", coreidx);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
int ssb_pcmcia_switch_core(struct ssb_bus *bus,
|
||||
struct ssb_device *dev)
|
||||
{
|
||||
int err;
|
||||
unsigned long flags;
|
||||
|
||||
#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);
|
||||
#endif
|
||||
|
||||
spin_lock_irqsave(&bus->bar_lock, flags);
|
||||
err = ssb_pcmcia_switch_coreidx(bus, dev->core_index);
|
||||
if (!err)
|
||||
bus->mapped_device = dev;
|
||||
spin_unlock_irqrestore(&bus->bar_lock, flags);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int ssb_pcmcia_switch_segment(struct ssb_bus *bus, u8 seg)
|
||||
{
|
||||
int attempts = 0;
|
||||
unsigned long flags;
|
||||
conf_reg_t reg;
|
||||
int res, err = 0;
|
||||
|
||||
SSB_WARN_ON((seg != 0) && (seg != 1));
|
||||
reg.Offset = 0x34;
|
||||
reg.Function = 0;
|
||||
spin_lock_irqsave(&bus->bar_lock, flags);
|
||||
while (1) {
|
||||
reg.Action = CS_WRITE;
|
||||
reg.Value = seg;
|
||||
res = pcmcia_access_configuration_register(bus->host_pcmcia, ®);
|
||||
if (unlikely(res != CS_SUCCESS))
|
||||
goto error;
|
||||
reg.Value = 0xFF;
|
||||
reg.Action = CS_READ;
|
||||
res = pcmcia_access_configuration_register(bus->host_pcmcia, ®);
|
||||
if (unlikely(res != CS_SUCCESS))
|
||||
goto error;
|
||||
|
||||
if (reg.Value == seg)
|
||||
break;
|
||||
|
||||
if (unlikely(attempts++ > SSB_BAR0_MAX_RETRIES))
|
||||
goto error;
|
||||
udelay(10);
|
||||
}
|
||||
bus->mapped_pcmcia_seg = seg;
|
||||
out_unlock:
|
||||
spin_unlock_irqrestore(&bus->bar_lock, flags);
|
||||
return err;
|
||||
error:
|
||||
ssb_printk(KERN_ERR PFX "Failed to switch pcmcia segment\n");
|
||||
err = -ENODEV;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
/* These are the main device register access functions.
|
||||
* do_select_core is inline to have the likely hotpath inline.
|
||||
* All unlikely codepaths are out-of-line. */
|
||||
static inline int do_select_core(struct ssb_bus *bus,
|
||||
struct ssb_device *dev,
|
||||
u16 *offset)
|
||||
{
|
||||
int err;
|
||||
u8 need_seg = (*offset >= 0x800) ? 1 : 0;
|
||||
|
||||
if (unlikely(dev != bus->mapped_device)) {
|
||||
err = ssb_pcmcia_switch_core(bus, dev);
|
||||
if (unlikely(err))
|
||||
return err;
|
||||
}
|
||||
if (unlikely(need_seg != bus->mapped_pcmcia_seg)) {
|
||||
err = ssb_pcmcia_switch_segment(bus, need_seg);
|
||||
if (unlikely(err))
|
||||
return err;
|
||||
}
|
||||
if (need_seg == 1)
|
||||
*offset -= 0x800;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u16 ssb_pcmcia_read16(struct ssb_device *dev, u16 offset)
|
||||
{
|
||||
struct ssb_bus *bus = dev->bus;
|
||||
u16 x;
|
||||
|
||||
if (unlikely(do_select_core(bus, dev, &offset)))
|
||||
return 0xFFFF;
|
||||
x = readw(bus->mmio + offset);
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
static u32 ssb_pcmcia_read32(struct ssb_device *dev, u16 offset)
|
||||
{
|
||||
struct ssb_bus *bus = dev->bus;
|
||||
u32 x;
|
||||
|
||||
if (unlikely(do_select_core(bus, dev, &offset)))
|
||||
return 0xFFFFFFFF;
|
||||
x = readl(bus->mmio + offset);
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
static void ssb_pcmcia_write16(struct ssb_device *dev, u16 offset, u16 value)
|
||||
{
|
||||
struct ssb_bus *bus = dev->bus;
|
||||
|
||||
if (unlikely(do_select_core(bus, dev, &offset)))
|
||||
return;
|
||||
writew(value, bus->mmio + offset);
|
||||
}
|
||||
|
||||
static void ssb_pcmcia_write32(struct ssb_device *dev, u16 offset, u32 value)
|
||||
{
|
||||
struct ssb_bus *bus = dev->bus;
|
||||
|
||||
if (unlikely(do_select_core(bus, dev, &offset)))
|
||||
return;
|
||||
readw(bus->mmio + offset);
|
||||
writew(value >> 16, bus->mmio + offset + 2);
|
||||
readw(bus->mmio + offset);
|
||||
writew(value, bus->mmio + offset);
|
||||
}
|
||||
|
||||
/* Not "static", as it's used in main.c */
|
||||
const struct ssb_bus_ops ssb_pcmcia_ops = {
|
||||
.read16 = ssb_pcmcia_read16,
|
||||
.read32 = ssb_pcmcia_read32,
|
||||
.write16 = ssb_pcmcia_write16,
|
||||
.write32 = ssb_pcmcia_write32,
|
||||
};
|
||||
|
||||
int ssb_pcmcia_get_invariants(struct ssb_bus *bus,
|
||||
struct ssb_init_invariants *iv)
|
||||
{
|
||||
//TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ssb_pcmcia_init(struct ssb_bus *bus)
|
||||
{
|
||||
conf_reg_t reg;
|
||||
int err;
|
||||
|
||||
if (bus->bustype != SSB_BUSTYPE_PCMCIA)
|
||||
return 0;
|
||||
|
||||
/* Switch segment to a known state and sync
|
||||
* bus->mapped_pcmcia_seg with hardware state. */
|
||||
ssb_pcmcia_switch_segment(bus, 0);
|
||||
|
||||
/* Init IRQ routing */
|
||||
reg.Action = CS_READ;
|
||||
reg.Function = 0;
|
||||
if (bus->chip_id == 0x4306)
|
||||
reg.Offset = 0x00;
|
||||
else
|
||||
reg.Offset = 0x80;
|
||||
err = pcmcia_access_configuration_register(bus->host_pcmcia, ®);
|
||||
if (err != CS_SUCCESS)
|
||||
goto error;
|
||||
reg.Action = CS_WRITE;
|
||||
reg.Value |= 0x04 | 0x01;
|
||||
err = pcmcia_access_configuration_register(bus->host_pcmcia, ®);
|
||||
if (err != CS_SUCCESS)
|
||||
goto error;
|
||||
|
||||
return 0;
|
||||
error:
|
||||
return -ENODEV;
|
||||
}
|
||||
413
drivers/ssb/scan.c
Normal file
413
drivers/ssb/scan.c
Normal file
@@ -0,0 +1,413 @@
|
||||
/*
|
||||
* Sonics Silicon Backplane
|
||||
* Bus scanning
|
||||
*
|
||||
* Copyright (C) 2005-2007 Michael Buesch <mb@bu3sch.de>
|
||||
* Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
|
||||
* Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
|
||||
* Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
|
||||
* Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
|
||||
* Copyright (C) 2006 Broadcom Corporation.
|
||||
*
|
||||
* Licensed under the GNU/GPL. See COPYING for details.
|
||||
*/
|
||||
|
||||
#include <linux/ssb/ssb.h>
|
||||
#include <linux/ssb/ssb_regs.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <pcmcia/cs_types.h>
|
||||
#include <pcmcia/cs.h>
|
||||
#include <pcmcia/cistpl.h>
|
||||
#include <pcmcia/ds.h>
|
||||
|
||||
#include "ssb_private.h"
|
||||
|
||||
|
||||
const char *ssb_core_name(u16 coreid)
|
||||
{
|
||||
switch (coreid) {
|
||||
case SSB_DEV_CHIPCOMMON:
|
||||
return "ChipCommon";
|
||||
case SSB_DEV_ILINE20:
|
||||
return "ILine 20";
|
||||
case SSB_DEV_SDRAM:
|
||||
return "SDRAM";
|
||||
case SSB_DEV_PCI:
|
||||
return "PCI";
|
||||
case SSB_DEV_MIPS:
|
||||
return "MIPS";
|
||||
case SSB_DEV_ETHERNET:
|
||||
return "Fast Ethernet";
|
||||
case SSB_DEV_V90:
|
||||
return "V90";
|
||||
case SSB_DEV_USB11_HOSTDEV:
|
||||
return "USB 1.1 Hostdev";
|
||||
case SSB_DEV_ADSL:
|
||||
return "ADSL";
|
||||
case SSB_DEV_ILINE100:
|
||||
return "ILine 100";
|
||||
case SSB_DEV_IPSEC:
|
||||
return "IPSEC";
|
||||
case SSB_DEV_PCMCIA:
|
||||
return "PCMCIA";
|
||||
case SSB_DEV_INTERNAL_MEM:
|
||||
return "Internal Memory";
|
||||
case SSB_DEV_MEMC_SDRAM:
|
||||
return "MEMC SDRAM";
|
||||
case SSB_DEV_EXTIF:
|
||||
return "EXTIF";
|
||||
case SSB_DEV_80211:
|
||||
return "IEEE 802.11";
|
||||
case SSB_DEV_MIPS_3302:
|
||||
return "MIPS 3302";
|
||||
case SSB_DEV_USB11_HOST:
|
||||
return "USB 1.1 Host";
|
||||
case SSB_DEV_USB11_DEV:
|
||||
return "USB 1.1 Device";
|
||||
case SSB_DEV_USB20_HOST:
|
||||
return "USB 2.0 Host";
|
||||
case SSB_DEV_USB20_DEV:
|
||||
return "USB 2.0 Device";
|
||||
case SSB_DEV_SDIO_HOST:
|
||||
return "SDIO Host";
|
||||
case SSB_DEV_ROBOSWITCH:
|
||||
return "Roboswitch";
|
||||
case SSB_DEV_PARA_ATA:
|
||||
return "PATA";
|
||||
case SSB_DEV_SATA_XORDMA:
|
||||
return "SATA XOR-DMA";
|
||||
case SSB_DEV_ETHERNET_GBIT:
|
||||
return "GBit Ethernet";
|
||||
case SSB_DEV_PCIE:
|
||||
return "PCI-E";
|
||||
case SSB_DEV_MIMO_PHY:
|
||||
return "MIMO PHY";
|
||||
case SSB_DEV_SRAM_CTRLR:
|
||||
return "SRAM Controller";
|
||||
case SSB_DEV_MINI_MACPHY:
|
||||
return "Mini MACPHY";
|
||||
case SSB_DEV_ARM_1176:
|
||||
return "ARM 1176";
|
||||
case SSB_DEV_ARM_7TDMI:
|
||||
return "ARM 7TDMI";
|
||||
}
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
static u16 pcidev_to_chipid(struct pci_dev *pci_dev)
|
||||
{
|
||||
u16 chipid_fallback = 0;
|
||||
|
||||
switch (pci_dev->device) {
|
||||
case 0x4301:
|
||||
chipid_fallback = 0x4301;
|
||||
break;
|
||||
case 0x4305 ... 0x4307:
|
||||
chipid_fallback = 0x4307;
|
||||
break;
|
||||
case 0x4403:
|
||||
chipid_fallback = 0x4402;
|
||||
break;
|
||||
case 0x4610 ... 0x4615:
|
||||
chipid_fallback = 0x4610;
|
||||
break;
|
||||
case 0x4710 ... 0x4715:
|
||||
chipid_fallback = 0x4710;
|
||||
break;
|
||||
case 0x4320 ... 0x4325:
|
||||
chipid_fallback = 0x4309;
|
||||
break;
|
||||
case PCI_DEVICE_ID_BCM4401:
|
||||
case PCI_DEVICE_ID_BCM4401B0:
|
||||
case PCI_DEVICE_ID_BCM4401B1:
|
||||
chipid_fallback = 0x4401;
|
||||
break;
|
||||
default:
|
||||
ssb_printk(KERN_ERR PFX
|
||||
"PCI-ID not in fallback list\n");
|
||||
}
|
||||
|
||||
return chipid_fallback;
|
||||
}
|
||||
|
||||
static u8 chipid_to_nrcores(u16 chipid)
|
||||
{
|
||||
switch (chipid) {
|
||||
case 0x5365:
|
||||
return 7;
|
||||
case 0x4306:
|
||||
return 6;
|
||||
case 0x4310:
|
||||
return 8;
|
||||
case 0x4307:
|
||||
case 0x4301:
|
||||
return 5;
|
||||
case 0x4401:
|
||||
case 0x4402:
|
||||
return 3;
|
||||
case 0x4710:
|
||||
case 0x4610:
|
||||
case 0x4704:
|
||||
return 9;
|
||||
default:
|
||||
ssb_printk(KERN_ERR PFX
|
||||
"CHIPID not in nrcores fallback list\n");
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static u32 scan_read32(struct ssb_bus *bus, u8 current_coreidx,
|
||||
u16 offset)
|
||||
{
|
||||
switch (bus->bustype) {
|
||||
case SSB_BUSTYPE_SSB:
|
||||
offset += current_coreidx * SSB_CORE_SIZE;
|
||||
break;
|
||||
case SSB_BUSTYPE_PCI:
|
||||
break;
|
||||
case SSB_BUSTYPE_PCMCIA:
|
||||
if (offset >= 0x800) {
|
||||
ssb_pcmcia_switch_segment(bus, 1);
|
||||
offset -= 0x800;
|
||||
} else
|
||||
ssb_pcmcia_switch_segment(bus, 0);
|
||||
break;
|
||||
}
|
||||
return readl(bus->mmio + offset);
|
||||
}
|
||||
|
||||
static int scan_switchcore(struct ssb_bus *bus, u8 coreidx)
|
||||
{
|
||||
switch (bus->bustype) {
|
||||
case SSB_BUSTYPE_SSB:
|
||||
break;
|
||||
case SSB_BUSTYPE_PCI:
|
||||
return ssb_pci_switch_coreidx(bus, coreidx);
|
||||
case SSB_BUSTYPE_PCMCIA:
|
||||
return ssb_pcmcia_switch_coreidx(bus, coreidx);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ssb_iounmap(struct ssb_bus *bus)
|
||||
{
|
||||
switch (bus->bustype) {
|
||||
case SSB_BUSTYPE_SSB:
|
||||
case SSB_BUSTYPE_PCMCIA:
|
||||
iounmap(bus->mmio);
|
||||
break;
|
||||
case SSB_BUSTYPE_PCI:
|
||||
#ifdef CONFIG_SSB_PCIHOST
|
||||
pci_iounmap(bus->host_pci, bus->mmio);
|
||||
#else
|
||||
SSB_BUG_ON(1); /* Can't reach this code. */
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
bus->mmio = NULL;
|
||||
bus->mapped_device = NULL;
|
||||
}
|
||||
|
||||
static void __iomem *ssb_ioremap(struct ssb_bus *bus,
|
||||
unsigned long baseaddr)
|
||||
{
|
||||
void __iomem *mmio = NULL;
|
||||
|
||||
switch (bus->bustype) {
|
||||
case SSB_BUSTYPE_SSB:
|
||||
/* Only map the first core for now. */
|
||||
/* fallthrough... */
|
||||
case SSB_BUSTYPE_PCMCIA:
|
||||
mmio = ioremap(baseaddr, SSB_CORE_SIZE);
|
||||
break;
|
||||
case SSB_BUSTYPE_PCI:
|
||||
#ifdef CONFIG_SSB_PCIHOST
|
||||
mmio = pci_iomap(bus->host_pci, 0, ~0UL);
|
||||
#else
|
||||
SSB_BUG_ON(1); /* Can't reach this code. */
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
return mmio;
|
||||
}
|
||||
|
||||
static int we_support_multiple_80211_cores(struct ssb_bus *bus)
|
||||
{
|
||||
/* More than one 802.11 core is only supported by special chips.
|
||||
* There are chips with two 802.11 cores, but with dangling
|
||||
* pins on the second core. Be careful and reject them here.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_SSB_PCIHOST
|
||||
if (bus->bustype == SSB_BUSTYPE_PCI) {
|
||||
if (bus->host_pci->vendor == PCI_VENDOR_ID_BROADCOM &&
|
||||
bus->host_pci->device == 0x4324)
|
||||
return 1;
|
||||
}
|
||||
#endif /* CONFIG_SSB_PCIHOST */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ssb_bus_scan(struct ssb_bus *bus,
|
||||
unsigned long baseaddr)
|
||||
{
|
||||
int err = -ENOMEM;
|
||||
void __iomem *mmio;
|
||||
u32 idhi, cc, rev, tmp;
|
||||
int dev_i, i;
|
||||
struct ssb_device *dev;
|
||||
int nr_80211_cores = 0;
|
||||
|
||||
mmio = ssb_ioremap(bus, baseaddr);
|
||||
if (!mmio)
|
||||
goto out;
|
||||
bus->mmio = mmio;
|
||||
|
||||
err = scan_switchcore(bus, 0); /* Switch to first core */
|
||||
if (err)
|
||||
goto err_unmap;
|
||||
|
||||
idhi = scan_read32(bus, 0, SSB_IDHIGH);
|
||||
cc = (idhi & SSB_IDHIGH_CC) >> SSB_IDHIGH_CC_SHIFT;
|
||||
rev = (idhi & SSB_IDHIGH_RCLO);
|
||||
rev |= (idhi & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT;
|
||||
|
||||
bus->nr_devices = 0;
|
||||
if (cc == SSB_DEV_CHIPCOMMON) {
|
||||
tmp = scan_read32(bus, 0, SSB_CHIPCO_CHIPID);
|
||||
|
||||
bus->chip_id = (tmp & SSB_CHIPCO_IDMASK);
|
||||
bus->chip_rev = (tmp & SSB_CHIPCO_REVMASK) >>
|
||||
SSB_CHIPCO_REVSHIFT;
|
||||
bus->chip_package = (tmp & SSB_CHIPCO_PACKMASK) >>
|
||||
SSB_CHIPCO_PACKSHIFT;
|
||||
if (rev >= 4) {
|
||||
bus->nr_devices = (tmp & SSB_CHIPCO_NRCORESMASK) >>
|
||||
SSB_CHIPCO_NRCORESSHIFT;
|
||||
}
|
||||
tmp = scan_read32(bus, 0, SSB_CHIPCO_CAP);
|
||||
bus->chipco.capabilities = tmp;
|
||||
} 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_package = 0;
|
||||
} else {
|
||||
bus->chip_id = 0x4710;
|
||||
bus->chip_rev = 0;
|
||||
bus->chip_package = 0;
|
||||
}
|
||||
}
|
||||
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);
|
||||
goto err_unmap;
|
||||
}
|
||||
if (bus->bustype == SSB_BUSTYPE_SSB) {
|
||||
/* Now that we know the number of cores,
|
||||
* remap the whole IO space for all cores.
|
||||
*/
|
||||
err = -ENOMEM;
|
||||
iounmap(mmio);
|
||||
mmio = ioremap(baseaddr, SSB_CORE_SIZE * bus->nr_devices);
|
||||
if (!mmio)
|
||||
goto out;
|
||||
bus->mmio = mmio;
|
||||
}
|
||||
|
||||
/* Fetch basic information about each core/device */
|
||||
for (i = 0, dev_i = 0; i < bus->nr_devices; i++) {
|
||||
err = scan_switchcore(bus, i);
|
||||
if (err)
|
||||
goto err_unmap;
|
||||
dev = &(bus->devices[dev_i]);
|
||||
|
||||
idhi = scan_read32(bus, i, SSB_IDHIGH);
|
||||
dev->id.coreid = (idhi & SSB_IDHIGH_CC) >> SSB_IDHIGH_CC_SHIFT;
|
||||
dev->id.revision = (idhi & SSB_IDHIGH_RCLO);
|
||||
dev->id.revision |= (idhi & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT;
|
||||
dev->id.vendor = (idhi & SSB_IDHIGH_VC) >> SSB_IDHIGH_VC_SHIFT;
|
||||
dev->core_index = i;
|
||||
dev->bus = bus;
|
||||
dev->ops = bus->ops;
|
||||
|
||||
ssb_dprintk(KERN_INFO PFX
|
||||
"Core %d found: %s "
|
||||
"(cc 0x%03X, rev 0x%02X, vendor 0x%04X)\n",
|
||||
i, ssb_core_name(dev->id.coreid),
|
||||
dev->id.coreid, dev->id.revision, dev->id.vendor);
|
||||
|
||||
switch (dev->id.coreid) {
|
||||
case SSB_DEV_80211:
|
||||
nr_80211_cores++;
|
||||
if (nr_80211_cores > 1) {
|
||||
if (!we_support_multiple_80211_cores(bus)) {
|
||||
ssb_dprintk(KERN_INFO PFX "Ignoring additional "
|
||||
"802.11 core\n");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SSB_DEV_EXTIF:
|
||||
#ifdef CONFIG_SSB_DRIVER_EXTIF
|
||||
if (bus->extif.dev) {
|
||||
ssb_printk(KERN_WARNING PFX
|
||||
"WARNING: Multiple EXTIFs found\n");
|
||||
break;
|
||||
}
|
||||
bus->extif.dev = dev;
|
||||
#endif /* CONFIG_SSB_DRIVER_EXTIF */
|
||||
break;
|
||||
case SSB_DEV_CHIPCOMMON:
|
||||
if (bus->chipco.dev) {
|
||||
ssb_printk(KERN_WARNING PFX
|
||||
"WARNING: Multiple ChipCommon found\n");
|
||||
break;
|
||||
}
|
||||
bus->chipco.dev = dev;
|
||||
break;
|
||||
case SSB_DEV_MIPS:
|
||||
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");
|
||||
break;
|
||||
}
|
||||
bus->mipscore.dev = dev;
|
||||
#endif /* CONFIG_SSB_DRIVER_MIPS */
|
||||
break;
|
||||
case SSB_DEV_PCI:
|
||||
case SSB_DEV_PCIE:
|
||||
#ifdef CONFIG_SSB_DRIVER_PCICORE
|
||||
if (bus->pcicore.dev) {
|
||||
ssb_printk(KERN_WARNING PFX
|
||||
"WARNING: Multiple PCI(E) cores found\n");
|
||||
break;
|
||||
}
|
||||
bus->pcicore.dev = dev;
|
||||
#endif /* CONFIG_SSB_DRIVER_PCICORE */
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
dev_i++;
|
||||
}
|
||||
bus->nr_devices = dev_i;
|
||||
|
||||
err = 0;
|
||||
out:
|
||||
return err;
|
||||
err_unmap:
|
||||
ssb_iounmap(bus);
|
||||
goto out;
|
||||
}
|
||||
136
drivers/ssb/ssb_private.h
Normal file
136
drivers/ssb/ssb_private.h
Normal file
@@ -0,0 +1,136 @@
|
||||
#ifndef LINUX_SSB_PRIVATE_H_
|
||||
#define LINUX_SSB_PRIVATE_H_
|
||||
|
||||
#include <linux/ssb/ssb.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
|
||||
#define PFX "ssb: "
|
||||
|
||||
#ifdef CONFIG_SSB_SILENT
|
||||
# define ssb_printk(fmt, x...) do { /* nothing */ } while (0)
|
||||
#else
|
||||
# define ssb_printk printk
|
||||
#endif /* CONFIG_SSB_SILENT */
|
||||
|
||||
/* dprintk: Debugging printk; vanishes for non-debug compilation */
|
||||
#ifdef CONFIG_SSB_DEBUG
|
||||
# define ssb_dprintk(fmt, x...) ssb_printk(fmt , ##x)
|
||||
#else
|
||||
# define ssb_dprintk(fmt, x...) do { /* nothing */ } while (0)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SSB_DEBUG
|
||||
# define SSB_WARN_ON(x) WARN_ON(x)
|
||||
# define SSB_BUG_ON(x) BUG_ON(x)
|
||||
#else
|
||||
static inline int __ssb_do_nothing(int x) { return x; }
|
||||
# define SSB_WARN_ON(x) __ssb_do_nothing(unlikely(!!(x)))
|
||||
# define SSB_BUG_ON(x) __ssb_do_nothing(unlikely(!!(x)))
|
||||
#endif
|
||||
|
||||
|
||||
/* pci.c */
|
||||
#ifdef CONFIG_SSB_PCIHOST
|
||||
extern int ssb_pci_switch_core(struct ssb_bus *bus,
|
||||
struct ssb_device *dev);
|
||||
extern int ssb_pci_switch_coreidx(struct ssb_bus *bus,
|
||||
u8 coreidx);
|
||||
extern int ssb_pci_xtal(struct ssb_bus *bus, u32 what,
|
||||
int turn_on);
|
||||
extern int ssb_pci_get_invariants(struct ssb_bus *bus,
|
||||
struct ssb_init_invariants *iv);
|
||||
extern void ssb_pci_exit(struct ssb_bus *bus);
|
||||
extern int ssb_pci_init(struct ssb_bus *bus);
|
||||
extern const struct ssb_bus_ops ssb_pci_ops;
|
||||
|
||||
#else /* CONFIG_SSB_PCIHOST */
|
||||
|
||||
static inline int ssb_pci_switch_core(struct ssb_bus *bus,
|
||||
struct ssb_device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline int ssb_pci_switch_coreidx(struct ssb_bus *bus,
|
||||
u8 coreidx)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline int ssb_pci_xtal(struct ssb_bus *bus, u32 what,
|
||||
int turn_on)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void ssb_pci_exit(struct ssb_bus *bus)
|
||||
{
|
||||
}
|
||||
static inline int ssb_pci_init(struct ssb_bus *bus)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_SSB_PCIHOST */
|
||||
|
||||
|
||||
/* pcmcia.c */
|
||||
#ifdef CONFIG_SSB_PCMCIAHOST
|
||||
extern int ssb_pcmcia_switch_core(struct ssb_bus *bus,
|
||||
struct ssb_device *dev);
|
||||
extern int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus,
|
||||
u8 coreidx);
|
||||
extern int ssb_pcmcia_switch_segment(struct ssb_bus *bus,
|
||||
u8 seg);
|
||||
extern int ssb_pcmcia_get_invariants(struct ssb_bus *bus,
|
||||
struct ssb_init_invariants *iv);
|
||||
extern int ssb_pcmcia_init(struct ssb_bus *bus);
|
||||
extern const struct ssb_bus_ops ssb_pcmcia_ops;
|
||||
#else /* CONFIG_SSB_PCMCIAHOST */
|
||||
static inline int ssb_pcmcia_switch_core(struct ssb_bus *bus,
|
||||
struct ssb_device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus,
|
||||
u8 coreidx)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline int ssb_pcmcia_switch_segment(struct ssb_bus *bus,
|
||||
u8 seg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline int ssb_pcmcia_init(struct ssb_bus *bus)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_SSB_PCMCIAHOST */
|
||||
|
||||
|
||||
/* scan.c */
|
||||
extern const char *ssb_core_name(u16 coreid);
|
||||
extern int ssb_bus_scan(struct ssb_bus *bus,
|
||||
unsigned long baseaddr);
|
||||
extern void ssb_iounmap(struct ssb_bus *ssb);
|
||||
|
||||
|
||||
/* core.c */
|
||||
extern u32 ssb_calc_clock_rate(u32 plltype, u32 n, u32 m);
|
||||
extern int ssb_devices_freeze(struct ssb_bus *bus);
|
||||
extern int ssb_devices_thaw(struct ssb_bus *bus);
|
||||
extern struct ssb_bus *ssb_pci_dev_to_bus(struct pci_dev *pdev);
|
||||
|
||||
/* b43_pci_bridge.c */
|
||||
#ifdef CONFIG_SSB_PCIHOST
|
||||
extern int __init b43_pci_ssb_bridge_init(void);
|
||||
extern void __exit b43_pci_ssb_bridge_exit(void);
|
||||
#else /* CONFIG_SSB_PCIHOST */
|
||||
static inline int b43_pci_ssb_bridge_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void b43_pci_ssb_bridge_exit(void)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_SSB_PCIHOST */
|
||||
|
||||
#endif /* LINUX_SSB_PRIVATE_H_ */
|
||||
@@ -340,4 +340,19 @@ struct parisc_device_id {
|
||||
#define PA_HVERSION_ANY_ID 0xffff
|
||||
#define PA_SVERSION_ANY_ID 0xffffffff
|
||||
|
||||
/* SSB core, see drivers/ssb/ */
|
||||
struct ssb_device_id {
|
||||
__u16 vendor;
|
||||
__u16 coreid;
|
||||
__u8 revision;
|
||||
};
|
||||
#define SSB_DEVICE(_vendor, _coreid, _revision) \
|
||||
{ .vendor = _vendor, .coreid = _coreid, .revision = _revision, }
|
||||
#define SSB_DEVTABLE_END \
|
||||
{ 0, },
|
||||
|
||||
#define SSB_ANY_VENDOR 0xFFFF
|
||||
#define SSB_ANY_ID 0xFFFF
|
||||
#define SSB_ANY_REV 0xFF
|
||||
|
||||
#endif /* LINUX_MOD_DEVICETABLE_H */
|
||||
|
||||
424
include/linux/ssb/ssb.h
Normal file
424
include/linux/ssb/ssb.h
Normal file
@@ -0,0 +1,424 @@
|
||||
#ifndef LINUX_SSB_H_
|
||||
#define LINUX_SSB_H_
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
|
||||
#include <linux/ssb/ssb_regs.h>
|
||||
|
||||
|
||||
struct pcmcia_device;
|
||||
struct ssb_bus;
|
||||
struct ssb_driver;
|
||||
|
||||
|
||||
struct ssb_sprom_r1 {
|
||||
u16 pci_spid; /* Subsystem Product ID for PCI */
|
||||
u16 pci_svid; /* Subsystem Vendor ID for PCI */
|
||||
u16 pci_pid; /* Product ID for PCI */
|
||||
u8 il0mac[6]; /* MAC address for 802.11b/g */
|
||||
u8 et0mac[6]; /* MAC address for Ethernet */
|
||||
u8 et1mac[6]; /* MAC address for 802.11a */
|
||||
u8 et0phyaddr:5; /* MII address for enet0 */
|
||||
u8 et1phyaddr:5; /* MII address for enet1 */
|
||||
u8 et0mdcport:1; /* MDIO for enet0 */
|
||||
u8 et1mdcport:1; /* MDIO for enet1 */
|
||||
u8 board_rev; /* Board revision */
|
||||
u8 country_code:4; /* Country Code */
|
||||
u8 antenna_a:2; /* Antenna 0/1 available for A-PHY */
|
||||
u8 antenna_bg:2; /* Antenna 0/1 available for B-PHY and G-PHY */
|
||||
u16 pa0b0;
|
||||
u16 pa0b1;
|
||||
u16 pa0b2;
|
||||
u16 pa1b0;
|
||||
u16 pa1b1;
|
||||
u16 pa1b2;
|
||||
u8 gpio0; /* GPIO pin 0 */
|
||||
u8 gpio1; /* GPIO pin 1 */
|
||||
u8 gpio2; /* GPIO pin 2 */
|
||||
u8 gpio3; /* GPIO pin 3 */
|
||||
u16 maxpwr_a; /* A-PHY Power Amplifier Max Power (in dBm Q5.2) */
|
||||
u16 maxpwr_bg; /* B/G-PHY Power Amplifier Max Power (in dBm Q5.2) */
|
||||
u8 itssi_a; /* Idle TSSI Target for A-PHY */
|
||||
u8 itssi_bg; /* Idle TSSI Target for B/G-PHY */
|
||||
u16 boardflags_lo; /* Boardflags (low 16 bits) */
|
||||
u8 antenna_gain_a; /* A-PHY Antenna gain (in dBm Q5.2) */
|
||||
u8 antenna_gain_bg; /* B/G-PHY Antenna gain (in dBm Q5.2) */
|
||||
u8 oem[8]; /* OEM string (rev 1 only) */
|
||||
};
|
||||
|
||||
struct ssb_sprom_r2 {
|
||||
u16 boardflags_hi; /* Boardflags (high 16 bits) */
|
||||
u8 maxpwr_a_lo; /* A-PHY Max Power Low */
|
||||
u8 maxpwr_a_hi; /* A-PHY Max Power High */
|
||||
u16 pa1lob0; /* A-PHY PA Low Settings */
|
||||
u16 pa1lob1; /* A-PHY PA Low Settings */
|
||||
u16 pa1lob2; /* A-PHY PA Low Settings */
|
||||
u16 pa1hib0; /* A-PHY PA High Settings */
|
||||
u16 pa1hib1; /* A-PHY PA High Settings */
|
||||
u16 pa1hib2; /* A-PHY PA High Settings */
|
||||
u8 ofdm_pwr_off; /* OFDM Power Offset from CCK Level */
|
||||
u8 country_str[2]; /* Two char Country Code */
|
||||
};
|
||||
|
||||
struct ssb_sprom_r3 {
|
||||
u32 ofdmapo; /* A-PHY OFDM Mid Power Offset */
|
||||
u32 ofdmalpo; /* A-PHY OFDM Low Power Offset */
|
||||
u32 ofdmahpo; /* A-PHY OFDM High Power Offset */
|
||||
u8 gpioldc_on_cnt; /* GPIO LED Powersave Duty Cycle ON count */
|
||||
u8 gpioldc_off_cnt; /* GPIO LED Powersave Duty Cycle OFF count */
|
||||
u8 cckpo_1M:4; /* CCK Power Offset for Rate 1M */
|
||||
u8 cckpo_2M:4; /* CCK Power Offset for Rate 2M */
|
||||
u8 cckpo_55M:4; /* CCK Power Offset for Rate 5.5M */
|
||||
u8 cckpo_11M:4; /* CCK Power Offset for Rate 11M */
|
||||
u32 ofdmgpo; /* G-PHY OFDM Power Offset */
|
||||
};
|
||||
|
||||
struct ssb_sprom_r4 {
|
||||
/* TODO */
|
||||
};
|
||||
|
||||
struct ssb_sprom {
|
||||
u8 revision;
|
||||
u8 crc;
|
||||
/* The valid r# fields are selected by the "revision".
|
||||
* Revision 3 and lower inherit from lower revisions.
|
||||
*/
|
||||
union {
|
||||
struct {
|
||||
struct ssb_sprom_r1 r1;
|
||||
struct ssb_sprom_r2 r2;
|
||||
struct ssb_sprom_r3 r3;
|
||||
};
|
||||
struct ssb_sprom_r4 r4;
|
||||
};
|
||||
};
|
||||
|
||||
/* Information about the PCB the circuitry is soldered on. */
|
||||
struct ssb_boardinfo {
|
||||
u16 vendor;
|
||||
u16 type;
|
||||
u16 rev;
|
||||
};
|
||||
|
||||
|
||||
struct ssb_device;
|
||||
/* Lowlevel read/write operations on the device MMIO.
|
||||
* Internal, don't use that outside of ssb. */
|
||||
struct ssb_bus_ops {
|
||||
u16 (*read16)(struct ssb_device *dev, u16 offset);
|
||||
u32 (*read32)(struct ssb_device *dev, u16 offset);
|
||||
void (*write16)(struct ssb_device *dev, u16 offset, u16 value);
|
||||
void (*write32)(struct ssb_device *dev, u16 offset, u32 value);
|
||||
};
|
||||
|
||||
|
||||
/* Core-ID values. */
|
||||
#define SSB_DEV_CHIPCOMMON 0x800
|
||||
#define SSB_DEV_ILINE20 0x801
|
||||
#define SSB_DEV_SDRAM 0x803
|
||||
#define SSB_DEV_PCI 0x804
|
||||
#define SSB_DEV_MIPS 0x805
|
||||
#define SSB_DEV_ETHERNET 0x806
|
||||
#define SSB_DEV_V90 0x807
|
||||
#define SSB_DEV_USB11_HOSTDEV 0x808
|
||||
#define SSB_DEV_ADSL 0x809
|
||||
#define SSB_DEV_ILINE100 0x80A
|
||||
#define SSB_DEV_IPSEC 0x80B
|
||||
#define SSB_DEV_PCMCIA 0x80D
|
||||
#define SSB_DEV_INTERNAL_MEM 0x80E
|
||||
#define SSB_DEV_MEMC_SDRAM 0x80F
|
||||
#define SSB_DEV_EXTIF 0x811
|
||||
#define SSB_DEV_80211 0x812
|
||||
#define SSB_DEV_MIPS_3302 0x816
|
||||
#define SSB_DEV_USB11_HOST 0x817
|
||||
#define SSB_DEV_USB11_DEV 0x818
|
||||
#define SSB_DEV_USB20_HOST 0x819
|
||||
#define SSB_DEV_USB20_DEV 0x81A
|
||||
#define SSB_DEV_SDIO_HOST 0x81B
|
||||
#define SSB_DEV_ROBOSWITCH 0x81C
|
||||
#define SSB_DEV_PARA_ATA 0x81D
|
||||
#define SSB_DEV_SATA_XORDMA 0x81E
|
||||
#define SSB_DEV_ETHERNET_GBIT 0x81F
|
||||
#define SSB_DEV_PCIE 0x820
|
||||
#define SSB_DEV_MIMO_PHY 0x821
|
||||
#define SSB_DEV_SRAM_CTRLR 0x822
|
||||
#define SSB_DEV_MINI_MACPHY 0x823
|
||||
#define SSB_DEV_ARM_1176 0x824
|
||||
#define SSB_DEV_ARM_7TDMI 0x825
|
||||
|
||||
/* Vendor-ID values */
|
||||
#define SSB_VENDOR_BROADCOM 0x4243
|
||||
|
||||
/* Some kernel subsystems poke with dev->drvdata, so we must use the
|
||||
* following ugly workaround to get from struct device to struct ssb_device */
|
||||
struct __ssb_dev_wrapper {
|
||||
struct device dev;
|
||||
struct ssb_device *sdev;
|
||||
};
|
||||
|
||||
struct ssb_device {
|
||||
/* Having a copy of the ops pointer in each dev struct
|
||||
* is an optimization. */
|
||||
const struct ssb_bus_ops *ops;
|
||||
|
||||
struct device *dev;
|
||||
struct ssb_bus *bus;
|
||||
struct ssb_device_id id;
|
||||
|
||||
u8 core_index;
|
||||
unsigned int irq;
|
||||
|
||||
/* Internal-only stuff follows. */
|
||||
void *drvdata; /* Per-device data */
|
||||
void *devtypedata; /* Per-devicetype (eg 802.11) data */
|
||||
};
|
||||
|
||||
/* Go from struct device to struct ssb_device. */
|
||||
static inline
|
||||
struct ssb_device * dev_to_ssb_dev(struct device *dev)
|
||||
{
|
||||
struct __ssb_dev_wrapper *wrap;
|
||||
wrap = container_of(dev, struct __ssb_dev_wrapper, dev);
|
||||
return wrap->sdev;
|
||||
}
|
||||
|
||||
/* Device specific user data */
|
||||
static inline
|
||||
void ssb_set_drvdata(struct ssb_device *dev, void *data)
|
||||
{
|
||||
dev->drvdata = data;
|
||||
}
|
||||
static inline
|
||||
void * ssb_get_drvdata(struct ssb_device *dev)
|
||||
{
|
||||
return dev->drvdata;
|
||||
}
|
||||
|
||||
/* Devicetype specific user data. This is per device-type (not per device) */
|
||||
void ssb_set_devtypedata(struct ssb_device *dev, void *data);
|
||||
static inline
|
||||
void * ssb_get_devtypedata(struct ssb_device *dev)
|
||||
{
|
||||
return dev->devtypedata;
|
||||
}
|
||||
|
||||
|
||||
struct ssb_driver {
|
||||
const char *name;
|
||||
const struct ssb_device_id *id_table;
|
||||
|
||||
int (*probe)(struct ssb_device *dev, const struct ssb_device_id *id);
|
||||
void (*remove)(struct ssb_device *dev);
|
||||
int (*suspend)(struct ssb_device *dev, pm_message_t state);
|
||||
int (*resume)(struct ssb_device *dev);
|
||||
void (*shutdown)(struct ssb_device *dev);
|
||||
|
||||
struct device_driver drv;
|
||||
};
|
||||
#define drv_to_ssb_drv(_drv) container_of(_drv, struct ssb_driver, drv)
|
||||
|
||||
extern int __ssb_driver_register(struct ssb_driver *drv, struct module *owner);
|
||||
static inline int ssb_driver_register(struct ssb_driver *drv)
|
||||
{
|
||||
return __ssb_driver_register(drv, THIS_MODULE);
|
||||
}
|
||||
extern void ssb_driver_unregister(struct ssb_driver *drv);
|
||||
|
||||
|
||||
|
||||
|
||||
enum ssb_bustype {
|
||||
SSB_BUSTYPE_SSB, /* This SSB bus is the system bus */
|
||||
SSB_BUSTYPE_PCI, /* SSB is connected to PCI bus */
|
||||
SSB_BUSTYPE_PCMCIA, /* SSB is connected to PCMCIA bus */
|
||||
};
|
||||
|
||||
/* board_vendor */
|
||||
#define SSB_BOARDVENDOR_BCM 0x14E4 /* Broadcom */
|
||||
#define SSB_BOARDVENDOR_DELL 0x1028 /* Dell */
|
||||
#define SSB_BOARDVENDOR_HP 0x0E11 /* HP */
|
||||
/* board_type */
|
||||
#define SSB_BOARD_BCM94306MP 0x0418
|
||||
#define SSB_BOARD_BCM4309G 0x0421
|
||||
#define SSB_BOARD_BCM4306CB 0x0417
|
||||
#define SSB_BOARD_BCM4309MP 0x040C
|
||||
#define SSB_BOARD_MP4318 0x044A
|
||||
#define SSB_BOARD_BU4306 0x0416
|
||||
#define SSB_BOARD_BU4309 0x040A
|
||||
/* chip_package */
|
||||
#define SSB_CHIPPACK_BCM4712S 1 /* Small 200pin 4712 */
|
||||
#define SSB_CHIPPACK_BCM4712M 2 /* Medium 225pin 4712 */
|
||||
#define SSB_CHIPPACK_BCM4712L 0 /* Large 340pin 4712 */
|
||||
|
||||
#include <linux/ssb/ssb_driver_chipcommon.h>
|
||||
#include <linux/ssb/ssb_driver_mips.h>
|
||||
#include <linux/ssb/ssb_driver_extif.h>
|
||||
#include <linux/ssb/ssb_driver_pci.h>
|
||||
|
||||
struct ssb_bus {
|
||||
/* The MMIO area. */
|
||||
void __iomem *mmio;
|
||||
|
||||
const struct ssb_bus_ops *ops;
|
||||
|
||||
/* The core in the basic address register window. (PCI bus only) */
|
||||
struct ssb_device *mapped_device;
|
||||
/* Currently mapped PCMCIA segment. (bustype == SSB_BUSTYPE_PCMCIA only) */
|
||||
u8 mapped_pcmcia_seg;
|
||||
/* Lock for core and segment switching. */
|
||||
spinlock_t bar_lock;
|
||||
|
||||
/* The bus this backplane is running on. */
|
||||
enum ssb_bustype bustype;
|
||||
/* Pointer to the PCI bus (only valid if bustype == SSB_BUSTYPE_PCI). */
|
||||
struct pci_dev *host_pci;
|
||||
/* Pointer to the PCMCIA device (only if bustype == SSB_BUSTYPE_PCMCIA). */
|
||||
struct pcmcia_device *host_pcmcia;
|
||||
|
||||
#ifdef CONFIG_SSB_PCIHOST
|
||||
/* Mutex to protect the SPROM writing. */
|
||||
struct mutex pci_sprom_mutex;
|
||||
#endif
|
||||
|
||||
/* ID information about the Chip. */
|
||||
u16 chip_id;
|
||||
u16 chip_rev;
|
||||
u8 chip_package;
|
||||
|
||||
/* List of devices (cores) on the backplane. */
|
||||
struct ssb_device devices[SSB_MAX_NR_CORES];
|
||||
u8 nr_devices;
|
||||
|
||||
/* Reference count. Number of suspended devices. */
|
||||
u8 suspend_cnt;
|
||||
|
||||
/* Software ID number for this bus. */
|
||||
unsigned int busnumber;
|
||||
|
||||
/* The ChipCommon device (if available). */
|
||||
struct ssb_chipcommon chipco;
|
||||
/* The PCI-core device (if available). */
|
||||
struct ssb_pcicore pcicore;
|
||||
/* The MIPS-core device (if available). */
|
||||
struct ssb_mipscore mipscore;
|
||||
/* The EXTif-core device (if available). */
|
||||
struct ssb_extif extif;
|
||||
|
||||
/* The following structure elements are not available in early
|
||||
* SSB initialization. Though, they are available for regular
|
||||
* registered drivers at any stage. So be careful when
|
||||
* using them in the ssb core code. */
|
||||
|
||||
/* ID information about the PCB. */
|
||||
struct ssb_boardinfo boardinfo;
|
||||
/* Contents of the SPROM. */
|
||||
struct ssb_sprom sprom;
|
||||
|
||||
/* Internal-only stuff follows. Do not touch. */
|
||||
struct list_head list;
|
||||
#ifdef CONFIG_SSB_DEBUG
|
||||
/* Is the bus already powered up? */
|
||||
bool powered_up;
|
||||
int power_warn_count;
|
||||
#endif /* DEBUG */
|
||||
};
|
||||
|
||||
/* The initialization-invariants. */
|
||||
struct ssb_init_invariants {
|
||||
struct ssb_boardinfo boardinfo;
|
||||
struct ssb_sprom sprom;
|
||||
};
|
||||
/* Type of function to fetch the invariants. */
|
||||
typedef int (*ssb_invariants_func_t)(struct ssb_bus *bus,
|
||||
struct ssb_init_invariants *iv);
|
||||
|
||||
/* Register a SSB system bus. get_invariants() is called after the
|
||||
* basic system devices are initialized.
|
||||
* The invariants are usually fetched from some NVRAM.
|
||||
* Put the invariants into the struct pointed to by iv. */
|
||||
extern int ssb_bus_ssbbus_register(struct ssb_bus *bus,
|
||||
unsigned long baseaddr,
|
||||
ssb_invariants_func_t get_invariants);
|
||||
#ifdef CONFIG_SSB_PCIHOST
|
||||
extern int ssb_bus_pcibus_register(struct ssb_bus *bus,
|
||||
struct pci_dev *host_pci);
|
||||
#endif /* CONFIG_SSB_PCIHOST */
|
||||
#ifdef CONFIG_SSB_PCMCIAHOST
|
||||
extern int ssb_bus_pcmciabus_register(struct ssb_bus *bus,
|
||||
struct pcmcia_device *pcmcia_dev,
|
||||
unsigned long baseaddr);
|
||||
#endif /* CONFIG_SSB_PCMCIAHOST */
|
||||
|
||||
extern void ssb_bus_unregister(struct ssb_bus *bus);
|
||||
|
||||
extern u32 ssb_clockspeed(struct ssb_bus *bus);
|
||||
|
||||
/* Is the device enabled in hardware? */
|
||||
int ssb_device_is_enabled(struct ssb_device *dev);
|
||||
/* Enable a device and pass device-specific SSB_TMSLOW flags.
|
||||
* If no device-specific flags are available, use 0. */
|
||||
void ssb_device_enable(struct ssb_device *dev, u32 core_specific_flags);
|
||||
/* Disable a device in hardware and pass SSB_TMSLOW flags (if any). */
|
||||
void ssb_device_disable(struct ssb_device *dev, u32 core_specific_flags);
|
||||
|
||||
|
||||
/* Device MMIO register read/write functions. */
|
||||
static inline u16 ssb_read16(struct ssb_device *dev, u16 offset)
|
||||
{
|
||||
return dev->ops->read16(dev, offset);
|
||||
}
|
||||
static inline u32 ssb_read32(struct ssb_device *dev, u16 offset)
|
||||
{
|
||||
return dev->ops->read32(dev, offset);
|
||||
}
|
||||
static inline void ssb_write16(struct ssb_device *dev, u16 offset, u16 value)
|
||||
{
|
||||
dev->ops->write16(dev, offset, value);
|
||||
}
|
||||
static inline void ssb_write32(struct ssb_device *dev, u16 offset, u32 value)
|
||||
{
|
||||
dev->ops->write32(dev, offset, value);
|
||||
}
|
||||
|
||||
|
||||
/* Translation (routing) bits that need to be ORed to DMA
|
||||
* addresses before they are given to a device. */
|
||||
extern u32 ssb_dma_translation(struct ssb_device *dev);
|
||||
#define SSB_DMA_TRANSLATION_MASK 0xC0000000
|
||||
#define SSB_DMA_TRANSLATION_SHIFT 30
|
||||
|
||||
extern int ssb_dma_set_mask(struct ssb_device *ssb_dev, u64 mask);
|
||||
|
||||
|
||||
#ifdef CONFIG_SSB_PCIHOST
|
||||
/* PCI-host wrapper driver */
|
||||
extern int ssb_pcihost_register(struct pci_driver *driver);
|
||||
static inline void ssb_pcihost_unregister(struct pci_driver *driver)
|
||||
{
|
||||
pci_unregister_driver(driver);
|
||||
}
|
||||
#endif /* CONFIG_SSB_PCIHOST */
|
||||
|
||||
|
||||
/* If a driver is shutdown or suspended, call this to signal
|
||||
* that the bus may be completely powered down. SSB will decide,
|
||||
* if it's really time to power down the bus, based on if there
|
||||
* are other devices that want to run. */
|
||||
extern int ssb_bus_may_powerdown(struct ssb_bus *bus);
|
||||
/* Before initializing and enabling a device, call this to power-up the bus.
|
||||
* If you want to allow use of dynamic-power-control, pass the flag.
|
||||
* Otherwise static always-on powercontrol will be used. */
|
||||
extern int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl);
|
||||
|
||||
|
||||
/* Various helper functions */
|
||||
extern u32 ssb_admatch_base(u32 adm);
|
||||
extern u32 ssb_admatch_size(u32 adm);
|
||||
|
||||
|
||||
#endif /* LINUX_SSB_H_ */
|
||||
396
include/linux/ssb/ssb_driver_chipcommon.h
Normal file
396
include/linux/ssb/ssb_driver_chipcommon.h
Normal file
@@ -0,0 +1,396 @@
|
||||
#ifndef LINUX_SSB_CHIPCO_H_
|
||||
#define LINUX_SSB_CHIPCO_H_
|
||||
|
||||
/* SonicsSiliconBackplane CHIPCOMMON core hardware definitions
|
||||
*
|
||||
* The chipcommon core provides chip identification, SB control,
|
||||
* jtag, 0/1/2 uarts, clock frequency control, a watchdog interrupt timer,
|
||||
* gpio interface, extbus, and support for serial and parallel flashes.
|
||||
*
|
||||
* Copyright 2005, Broadcom Corporation
|
||||
* Copyright 2006, Michael Buesch <mb@bu3sch.de>
|
||||
*
|
||||
* Licensed under the GPL version 2. See COPYING for details.
|
||||
*/
|
||||
|
||||
/** ChipCommon core registers. **/
|
||||
|
||||
#define SSB_CHIPCO_CHIPID 0x0000
|
||||
#define SSB_CHIPCO_IDMASK 0x0000FFFF
|
||||
#define SSB_CHIPCO_REVMASK 0x000F0000
|
||||
#define SSB_CHIPCO_REVSHIFT 16
|
||||
#define SSB_CHIPCO_PACKMASK 0x00F00000
|
||||
#define SSB_CHIPCO_PACKSHIFT 20
|
||||
#define SSB_CHIPCO_NRCORESMASK 0x0F000000
|
||||
#define SSB_CHIPCO_NRCORESSHIFT 24
|
||||
#define SSB_CHIPCO_CAP 0x0004 /* Capabilities */
|
||||
#define SSB_CHIPCO_CAP_NRUART 0x00000003 /* # of UARTs */
|
||||
#define SSB_CHIPCO_CAP_MIPSEB 0x00000004 /* MIPS in BigEndian Mode */
|
||||
#define SSB_CHIPCO_CAP_UARTCLK 0x00000018 /* UART clock select */
|
||||
#define SSB_CHIPCO_CAP_UARTCLK_INT 0x00000008 /* UARTs are driven by internal divided clock */
|
||||
#define SSB_CHIPCO_CAP_UARTGPIO 0x00000020 /* UARTs on GPIO 15-12 */
|
||||
#define SSB_CHIPCO_CAP_EXTBUS 0x000000C0 /* External buses present */
|
||||
#define SSB_CHIPCO_CAP_FLASHT 0x00000700 /* Flash Type */
|
||||
#define SSB_CHIPCO_FLASHT_NONE 0x00000000 /* No flash */
|
||||
#define SSB_CHIPCO_FLASHT_STSER 0x00000100 /* ST serial flash */
|
||||
#define SSB_CHIPCO_FLASHT_ATSER 0x00000200 /* Atmel serial flash */
|
||||
#define SSB_CHIPCO_FLASHT_PARA 0x00000700 /* Parallel flash */
|
||||
#define SSB_CHIPCO_CAP_PLLT 0x00038000 /* PLL Type */
|
||||
#define SSB_PLLTYPE_NONE 0x00000000
|
||||
#define SSB_PLLTYPE_1 0x00010000 /* 48Mhz base, 3 dividers */
|
||||
#define SSB_PLLTYPE_2 0x00020000 /* 48Mhz, 4 dividers */
|
||||
#define SSB_PLLTYPE_3 0x00030000 /* 25Mhz, 2 dividers */
|
||||
#define SSB_PLLTYPE_4 0x00008000 /* 48Mhz, 4 dividers */
|
||||
#define SSB_PLLTYPE_5 0x00018000 /* 25Mhz, 4 dividers */
|
||||
#define SSB_PLLTYPE_6 0x00028000 /* 100/200 or 120/240 only */
|
||||
#define SSB_PLLTYPE_7 0x00038000 /* 25Mhz, 4 dividers */
|
||||
#define SSB_CHIPCO_CAP_PCTL 0x00040000 /* Power Control */
|
||||
#define SSB_CHIPCO_CAP_OTPS 0x00380000 /* OTP size */
|
||||
#define SSB_CHIPCO_CAP_OTPS_SHIFT 19
|
||||
#define SSB_CHIPCO_CAP_OTPS_BASE 5
|
||||
#define SSB_CHIPCO_CAP_JTAGM 0x00400000 /* JTAG master present */
|
||||
#define SSB_CHIPCO_CAP_BROM 0x00800000 /* Internal boot ROM active */
|
||||
#define SSB_CHIPCO_CAP_64BIT 0x08000000 /* 64-bit Backplane */
|
||||
#define SSB_CHIPCO_CORECTL 0x0008
|
||||
#define SSB_CHIPCO_CORECTL_UARTCLK0 0x00000001 /* Drive UART with internal clock */
|
||||
#define SSB_CHIPCO_CORECTL_SE 0x00000002 /* sync clk out enable (corerev >= 3) */
|
||||
#define SSB_CHIPCO_BIST 0x000C
|
||||
#define SSB_CHIPCO_OTPS 0x0010 /* OTP status */
|
||||
#define SSB_CHIPCO_OTPS_PROGFAIL 0x80000000
|
||||
#define SSB_CHIPCO_OTPS_PROTECT 0x00000007
|
||||
#define SSB_CHIPCO_OTPS_HW_PROTECT 0x00000001
|
||||
#define SSB_CHIPCO_OTPS_SW_PROTECT 0x00000002
|
||||
#define SSB_CHIPCO_OTPS_CID_PROTECT 0x00000004
|
||||
#define SSB_CHIPCO_OTPC 0x0014 /* OTP control */
|
||||
#define SSB_CHIPCO_OTPC_RECWAIT 0xFF000000
|
||||
#define SSB_CHIPCO_OTPC_PROGWAIT 0x00FFFF00
|
||||
#define SSB_CHIPCO_OTPC_PRW_SHIFT 8
|
||||
#define SSB_CHIPCO_OTPC_MAXFAIL 0x00000038
|
||||
#define SSB_CHIPCO_OTPC_VSEL 0x00000006
|
||||
#define SSB_CHIPCO_OTPC_SELVL 0x00000001
|
||||
#define SSB_CHIPCO_OTPP 0x0018 /* OTP prog */
|
||||
#define SSB_CHIPCO_OTPP_COL 0x000000FF
|
||||
#define SSB_CHIPCO_OTPP_ROW 0x0000FF00
|
||||
#define SSB_CHIPCO_OTPP_ROW_SHIFT 8
|
||||
#define SSB_CHIPCO_OTPP_READERR 0x10000000
|
||||
#define SSB_CHIPCO_OTPP_VALUE 0x20000000
|
||||
#define SSB_CHIPCO_OTPP_READ 0x40000000
|
||||
#define SSB_CHIPCO_OTPP_START 0x80000000
|
||||
#define SSB_CHIPCO_OTPP_BUSY 0x80000000
|
||||
#define SSB_CHIPCO_IRQSTAT 0x0020
|
||||
#define SSB_CHIPCO_IRQMASK 0x0024
|
||||
#define SSB_CHIPCO_IRQ_GPIO 0x00000001 /* gpio intr */
|
||||
#define SSB_CHIPCO_IRQ_EXT 0x00000002 /* ro: ext intr pin (corerev >= 3) */
|
||||
#define SSB_CHIPCO_IRQ_WDRESET 0x80000000 /* watchdog reset occurred */
|
||||
#define SSB_CHIPCO_CHIPCTL 0x0028 /* Rev >= 11 only */
|
||||
#define SSB_CHIPCO_CHIPSTAT 0x002C /* Rev >= 11 only */
|
||||
#define SSB_CHIPCO_JCMD 0x0030 /* Rev >= 10 only */
|
||||
#define SSB_CHIPCO_JCMD_START 0x80000000
|
||||
#define SSB_CHIPCO_JCMD_BUSY 0x80000000
|
||||
#define SSB_CHIPCO_JCMD_PAUSE 0x40000000
|
||||
#define SSB_CHIPCO_JCMD0_ACC_MASK 0x0000F000
|
||||
#define SSB_CHIPCO_JCMD0_ACC_IRDR 0x00000000
|
||||
#define SSB_CHIPCO_JCMD0_ACC_DR 0x00001000
|
||||
#define SSB_CHIPCO_JCMD0_ACC_IR 0x00002000
|
||||
#define SSB_CHIPCO_JCMD0_ACC_RESET 0x00003000
|
||||
#define SSB_CHIPCO_JCMD0_ACC_IRPDR 0x00004000
|
||||
#define SSB_CHIPCO_JCMD0_ACC_PDR 0x00005000
|
||||
#define SSB_CHIPCO_JCMD0_IRW_MASK 0x00000F00
|
||||
#define SSB_CHIPCO_JCMD_ACC_MASK 0x000F0000 /* Changes for corerev 11 */
|
||||
#define SSB_CHIPCO_JCMD_ACC_IRDR 0x00000000
|
||||
#define SSB_CHIPCO_JCMD_ACC_DR 0x00010000
|
||||
#define SSB_CHIPCO_JCMD_ACC_IR 0x00020000
|
||||
#define SSB_CHIPCO_JCMD_ACC_RESET 0x00030000
|
||||
#define SSB_CHIPCO_JCMD_ACC_IRPDR 0x00040000
|
||||
#define SSB_CHIPCO_JCMD_ACC_PDR 0x00050000
|
||||
#define SSB_CHIPCO_JCMD_IRW_MASK 0x00001F00
|
||||
#define SSB_CHIPCO_JCMD_IRW_SHIFT 8
|
||||
#define SSB_CHIPCO_JCMD_DRW_MASK 0x0000003F
|
||||
#define SSB_CHIPCO_JIR 0x0034 /* Rev >= 10 only */
|
||||
#define SSB_CHIPCO_JDR 0x0038 /* Rev >= 10 only */
|
||||
#define SSB_CHIPCO_JCTL 0x003C /* Rev >= 10 only */
|
||||
#define SSB_CHIPCO_JCTL_FORCE_CLK 4 /* Force clock */
|
||||
#define SSB_CHIPCO_JCTL_EXT_EN 2 /* Enable external targets */
|
||||
#define SSB_CHIPCO_JCTL_EN 1 /* Enable Jtag master */
|
||||
#define SSB_CHIPCO_FLASHCTL 0x0040
|
||||
#define SSB_CHIPCO_FLASHCTL_START 0x80000000
|
||||
#define SSB_CHIPCO_FLASHCTL_BUSY SSB_CHIPCO_FLASHCTL_START
|
||||
#define SSB_CHIPCO_FLASHADDR 0x0044
|
||||
#define SSB_CHIPCO_FLASHDATA 0x0048
|
||||
#define SSB_CHIPCO_BCAST_ADDR 0x0050
|
||||
#define SSB_CHIPCO_BCAST_DATA 0x0054
|
||||
#define SSB_CHIPCO_GPIOIN 0x0060
|
||||
#define SSB_CHIPCO_GPIOOUT 0x0064
|
||||
#define SSB_CHIPCO_GPIOOUTEN 0x0068
|
||||
#define SSB_CHIPCO_GPIOCTL 0x006C
|
||||
#define SSB_CHIPCO_GPIOPOL 0x0070
|
||||
#define SSB_CHIPCO_GPIOIRQ 0x0074
|
||||
#define SSB_CHIPCO_WATCHDOG 0x0080
|
||||
#define SSB_CHIPCO_GPIOTIMER 0x0088 /* LED powersave (corerev >= 16) */
|
||||
#define SSB_CHIPCO_GPIOTIMER_ONTIME_SHIFT 16
|
||||
#define SSB_CHIPCO_GPIOTOUTM 0x008C /* LED powersave (corerev >= 16) */
|
||||
#define SSB_CHIPCO_CLOCK_N 0x0090
|
||||
#define SSB_CHIPCO_CLOCK_SB 0x0094
|
||||
#define SSB_CHIPCO_CLOCK_PCI 0x0098
|
||||
#define SSB_CHIPCO_CLOCK_M2 0x009C
|
||||
#define SSB_CHIPCO_CLOCK_MIPS 0x00A0
|
||||
#define SSB_CHIPCO_CLKDIV 0x00A4 /* Rev >= 3 only */
|
||||
#define SSB_CHIPCO_CLKDIV_SFLASH 0x0F000000
|
||||
#define SSB_CHIPCO_CLKDIV_SFLASH_SHIFT 24
|
||||
#define SSB_CHIPCO_CLKDIV_OTP 0x000F0000
|
||||
#define SSB_CHIPCO_CLKDIV_OTP_SHIFT 16
|
||||
#define SSB_CHIPCO_CLKDIV_JTAG 0x00000F00
|
||||
#define SSB_CHIPCO_CLKDIV_JTAG_SHIFT 8
|
||||
#define SSB_CHIPCO_CLKDIV_UART 0x000000FF
|
||||
#define SSB_CHIPCO_PLLONDELAY 0x00B0 /* Rev >= 4 only */
|
||||
#define SSB_CHIPCO_FREFSELDELAY 0x00B4 /* Rev >= 4 only */
|
||||
#define SSB_CHIPCO_SLOWCLKCTL 0x00B8 /* 6 <= Rev <= 9 only */
|
||||
#define SSB_CHIPCO_SLOWCLKCTL_SRC 0x00000007 /* slow clock source mask */
|
||||
#define SSB_CHIPCO_SLOWCLKCTL_SRC_LPO 0x00000000 /* source of slow clock is LPO */
|
||||
#define SSB_CHIPCO_SLOWCLKCTL_SRC_XTAL 0x00000001 /* source of slow clock is crystal */
|
||||
#define SSB_CHIPCO_SLOECLKCTL_SRC_PCI 0x00000002 /* source of slow clock is PCI */
|
||||
#define SSB_CHIPCO_SLOWCLKCTL_LPOFREQ 0x00000200 /* LPOFreqSel, 1: 160Khz, 0: 32KHz */
|
||||
#define SSB_CHIPCO_SLOWCLKCTL_LPOPD 0x00000400 /* LPOPowerDown, 1: LPO is disabled, 0: LPO is enabled */
|
||||
#define SSB_CHIPCO_SLOWCLKCTL_FSLOW 0x00000800 /* ForceSlowClk, 1: sb/cores running on slow clock, 0: power logic control */
|
||||
#define SSB_CHIPCO_SLOWCLKCTL_IPLL 0x00001000 /* IgnorePllOffReq, 1/0: power logic ignores/honors PLL clock disable requests from core */
|
||||
#define SSB_CHIPCO_SLOWCLKCTL_ENXTAL 0x00002000 /* XtalControlEn, 1/0: power logic does/doesn't disable crystal when appropriate */
|
||||
#define SSB_CHIPCO_SLOWCLKCTL_XTALPU 0x00004000 /* XtalPU (RO), 1/0: crystal running/disabled */
|
||||
#define SSB_CHIPCO_SLOWCLKCTL_CLKDIV 0xFFFF0000 /* ClockDivider (SlowClk = 1/(4+divisor)) */
|
||||
#define SSB_CHIPCO_SLOWCLKCTL_CLKDIV_SHIFT 16
|
||||
#define SSB_CHIPCO_SYSCLKCTL 0x00C0 /* Rev >= 3 only */
|
||||
#define SSB_CHIPCO_SYSCLKCTL_IDLPEN 0x00000001 /* ILPen: Enable Idle Low Power */
|
||||
#define SSB_CHIPCO_SYSCLKCTL_ALPEN 0x00000002 /* ALPen: Enable Active Low Power */
|
||||
#define SSB_CHIPCO_SYSCLKCTL_PLLEN 0x00000004 /* ForcePLLOn */
|
||||
#define SSB_CHIPCO_SYSCLKCTL_FORCEALP 0x00000008 /* Force ALP (or HT if ALPen is not set */
|
||||
#define SSB_CHIPCO_SYSCLKCTL_FORCEHT 0x00000010 /* Force HT */
|
||||
#define SSB_CHIPCO_SYSCLKCTL_CLKDIV 0xFFFF0000 /* ClkDiv (ILP = 1/(4+divisor)) */
|
||||
#define SSB_CHIPCO_SYSCLKCTL_CLKDIV_SHIFT 16
|
||||
#define SSB_CHIPCO_CLKSTSTR 0x00C4 /* Rev >= 3 only */
|
||||
#define SSB_CHIPCO_PCMCIA_CFG 0x0100
|
||||
#define SSB_CHIPCO_PCMCIA_MEMWAIT 0x0104
|
||||
#define SSB_CHIPCO_PCMCIA_ATTRWAIT 0x0108
|
||||
#define SSB_CHIPCO_PCMCIA_IOWAIT 0x010C
|
||||
#define SSB_CHIPCO_IDE_CFG 0x0110
|
||||
#define SSB_CHIPCO_IDE_MEMWAIT 0x0114
|
||||
#define SSB_CHIPCO_IDE_ATTRWAIT 0x0118
|
||||
#define SSB_CHIPCO_IDE_IOWAIT 0x011C
|
||||
#define SSB_CHIPCO_PROG_CFG 0x0120
|
||||
#define SSB_CHIPCO_PROG_WAITCNT 0x0124
|
||||
#define SSB_CHIPCO_FLASH_CFG 0x0128
|
||||
#define SSB_CHIPCO_FLASH_WAITCNT 0x012C
|
||||
#define SSB_CHIPCO_UART0_DATA 0x0300
|
||||
#define SSB_CHIPCO_UART0_IMR 0x0304
|
||||
#define SSB_CHIPCO_UART0_FCR 0x0308
|
||||
#define SSB_CHIPCO_UART0_LCR 0x030C
|
||||
#define SSB_CHIPCO_UART0_MCR 0x0310
|
||||
#define SSB_CHIPCO_UART0_LSR 0x0314
|
||||
#define SSB_CHIPCO_UART0_MSR 0x0318
|
||||
#define SSB_CHIPCO_UART0_SCRATCH 0x031C
|
||||
#define SSB_CHIPCO_UART1_DATA 0x0400
|
||||
#define SSB_CHIPCO_UART1_IMR 0x0404
|
||||
#define SSB_CHIPCO_UART1_FCR 0x0408
|
||||
#define SSB_CHIPCO_UART1_LCR 0x040C
|
||||
#define SSB_CHIPCO_UART1_MCR 0x0410
|
||||
#define SSB_CHIPCO_UART1_LSR 0x0414
|
||||
#define SSB_CHIPCO_UART1_MSR 0x0418
|
||||
#define SSB_CHIPCO_UART1_SCRATCH 0x041C
|
||||
|
||||
|
||||
|
||||
/** Clockcontrol masks and values **/
|
||||
|
||||
/* SSB_CHIPCO_CLOCK_N */
|
||||
#define SSB_CHIPCO_CLK_N1 0x0000003F /* n1 control */
|
||||
#define SSB_CHIPCO_CLK_N2 0x00003F00 /* n2 control */
|
||||
#define SSB_CHIPCO_CLK_N2_SHIFT 8
|
||||
#define SSB_CHIPCO_CLK_PLLC 0x000F0000 /* pll control */
|
||||
#define SSB_CHIPCO_CLK_PLLC_SHIFT 16
|
||||
|
||||
/* SSB_CHIPCO_CLOCK_SB/PCI/UART */
|
||||
#define SSB_CHIPCO_CLK_M1 0x0000003F /* m1 control */
|
||||
#define SSB_CHIPCO_CLK_M2 0x00003F00 /* m2 control */
|
||||
#define SSB_CHIPCO_CLK_M2_SHIFT 8
|
||||
#define SSB_CHIPCO_CLK_M3 0x003F0000 /* m3 control */
|
||||
#define SSB_CHIPCO_CLK_M3_SHIFT 16
|
||||
#define SSB_CHIPCO_CLK_MC 0x1F000000 /* mux control */
|
||||
#define SSB_CHIPCO_CLK_MC_SHIFT 24
|
||||
|
||||
/* N3M Clock control magic field values */
|
||||
#define SSB_CHIPCO_CLK_F6_2 0x02 /* A factor of 2 in */
|
||||
#define SSB_CHIPCO_CLK_F6_3 0x03 /* 6-bit fields like */
|
||||
#define SSB_CHIPCO_CLK_F6_4 0x05 /* N1, M1 or M3 */
|
||||
#define SSB_CHIPCO_CLK_F6_5 0x09
|
||||
#define SSB_CHIPCO_CLK_F6_6 0x11
|
||||
#define SSB_CHIPCO_CLK_F6_7 0x21
|
||||
|
||||
#define SSB_CHIPCO_CLK_F5_BIAS 5 /* 5-bit fields get this added */
|
||||
|
||||
#define SSB_CHIPCO_CLK_MC_BYPASS 0x08
|
||||
#define SSB_CHIPCO_CLK_MC_M1 0x04
|
||||
#define SSB_CHIPCO_CLK_MC_M1M2 0x02
|
||||
#define SSB_CHIPCO_CLK_MC_M1M2M3 0x01
|
||||
#define SSB_CHIPCO_CLK_MC_M1M3 0x11
|
||||
|
||||
/* Type 2 Clock control magic field values */
|
||||
#define SSB_CHIPCO_CLK_T2_BIAS 2 /* n1, n2, m1 & m3 bias */
|
||||
#define SSB_CHIPCO_CLK_T2M2_BIAS 3 /* m2 bias */
|
||||
|
||||
#define SSB_CHIPCO_CLK_T2MC_M1BYP 1
|
||||
#define SSB_CHIPCO_CLK_T2MC_M2BYP 2
|
||||
#define SSB_CHIPCO_CLK_T2MC_M3BYP 4
|
||||
|
||||
/* Type 6 Clock control magic field values */
|
||||
#define SSB_CHIPCO_CLK_T6_MMASK 1 /* bits of interest in m */
|
||||
#define SSB_CHIPCO_CLK_T6_M0 120000000 /* sb clock for m = 0 */
|
||||
#define SSB_CHIPCO_CLK_T6_M1 100000000 /* sb clock for m = 1 */
|
||||
#define SSB_CHIPCO_CLK_SB2MIPS_T6(sb) (2 * (sb))
|
||||
|
||||
/* Common clock base */
|
||||
#define SSB_CHIPCO_CLK_BASE1 24000000 /* Half the clock freq */
|
||||
#define SSB_CHIPCO_CLK_BASE2 12500000 /* Alternate crystal on some PLL's */
|
||||
|
||||
/* Clock control values for 200Mhz in 5350 */
|
||||
#define SSB_CHIPCO_CLK_5350_N 0x0311
|
||||
#define SSB_CHIPCO_CLK_5350_M 0x04020009
|
||||
|
||||
|
||||
/** Bits in the config registers **/
|
||||
|
||||
#define SSB_CHIPCO_CFG_EN 0x0001 /* Enable */
|
||||
#define SSB_CHIPCO_CFG_EXTM 0x000E /* Extif Mode */
|
||||
#define SSB_CHIPCO_CFG_EXTM_ASYNC 0x0002 /* Async/Parallel flash */
|
||||
#define SSB_CHIPCO_CFG_EXTM_SYNC 0x0004 /* Synchronous */
|
||||
#define SSB_CHIPCO_CFG_EXTM_PCMCIA 0x0008 /* PCMCIA */
|
||||
#define SSB_CHIPCO_CFG_EXTM_IDE 0x000A /* IDE */
|
||||
#define SSB_CHIPCO_CFG_DS16 0x0010 /* Data size, 0=8bit, 1=16bit */
|
||||
#define SSB_CHIPCO_CFG_CLKDIV 0x0060 /* Sync: Clock divisor */
|
||||
#define SSB_CHIPCO_CFG_CLKEN 0x0080 /* Sync: Clock enable */
|
||||
#define SSB_CHIPCO_CFG_BSTRO 0x0100 /* Sync: Size/Bytestrobe */
|
||||
|
||||
|
||||
/** Flash-specific control/status values */
|
||||
|
||||
/* flashcontrol opcodes for ST flashes */
|
||||
#define SSB_CHIPCO_FLASHCTL_ST_WREN 0x0006 /* Write Enable */
|
||||
#define SSB_CHIPCO_FLASHCTL_ST_WRDIS 0x0004 /* Write Disable */
|
||||
#define SSB_CHIPCO_FLASHCTL_ST_RDSR 0x0105 /* Read Status Register */
|
||||
#define SSB_CHIPCO_FLASHCTL_ST_WRSR 0x0101 /* Write Status Register */
|
||||
#define SSB_CHIPCO_FLASHCTL_ST_READ 0x0303 /* Read Data Bytes */
|
||||
#define SSB_CHIPCO_FLASHCTL_ST_PP 0x0302 /* Page Program */
|
||||
#define SSB_CHIPCO_FLASHCTL_ST_SE 0x02D8 /* Sector Erase */
|
||||
#define SSB_CHIPCO_FLASHCTL_ST_BE 0x00C7 /* Bulk Erase */
|
||||
#define SSB_CHIPCO_FLASHCTL_ST_DP 0x00B9 /* Deep Power-down */
|
||||
#define SSB_CHIPCO_FLASHCTL_ST_RSIG 0x03AB /* Read Electronic Signature */
|
||||
|
||||
/* Status register bits for ST flashes */
|
||||
#define SSB_CHIPCO_FLASHSTA_ST_WIP 0x01 /* Write In Progress */
|
||||
#define SSB_CHIPCO_FLASHSTA_ST_WEL 0x02 /* Write Enable Latch */
|
||||
#define SSB_CHIPCO_FLASHSTA_ST_BP 0x1C /* Block Protect */
|
||||
#define SSB_CHIPCO_FLASHSTA_ST_BP_SHIFT 2
|
||||
#define SSB_CHIPCO_FLASHSTA_ST_SRWD 0x80 /* Status Register Write Disable */
|
||||
|
||||
/* flashcontrol opcodes for Atmel flashes */
|
||||
#define SSB_CHIPCO_FLASHCTL_AT_READ 0x07E8
|
||||
#define SSB_CHIPCO_FLASHCTL_AT_PAGE_READ 0x07D2
|
||||
#define SSB_CHIPCO_FLASHCTL_AT_BUF1_READ /* FIXME */
|
||||
#define SSB_CHIPCO_FLASHCTL_AT_BUF2_READ /* FIXME */
|
||||
#define SSB_CHIPCO_FLASHCTL_AT_STATUS 0x01D7
|
||||
#define SSB_CHIPCO_FLASHCTL_AT_BUF1_WRITE 0x0384
|
||||
#define SSB_CHIPCO_FLASHCTL_AT_BUF2_WRITE 0x0387
|
||||
#define SSB_CHIPCO_FLASHCTL_AT_BUF1_ERASE_PRGM 0x0283 /* Erase program */
|
||||
#define SSB_CHIPCO_FLASHCTL_AT_BUF2_ERASE_PRGM 0x0286 /* Erase program */
|
||||
#define SSB_CHIPCO_FLASHCTL_AT_BUF1_PROGRAM 0x0288
|
||||
#define SSB_CHIPCO_FLASHCTL_AT_BUF2_PROGRAM 0x0289
|
||||
#define SSB_CHIPCO_FLASHCTL_AT_PAGE_ERASE 0x0281
|
||||
#define SSB_CHIPCO_FLASHCTL_AT_BLOCK_ERASE 0x0250
|
||||
#define SSB_CHIPCO_FLASHCTL_AT_BUF1_WRER_PRGM 0x0382 /* Write erase program */
|
||||
#define SSB_CHIPCO_FLASHCTL_AT_BUF2_WRER_PRGM 0x0385 /* Write erase program */
|
||||
#define SSB_CHIPCO_FLASHCTL_AT_BUF1_LOAD 0x0253
|
||||
#define SSB_CHIPCO_FLASHCTL_AT_BUF2_LOAD 0x0255
|
||||
#define SSB_CHIPCO_FLASHCTL_AT_BUF1_COMPARE 0x0260
|
||||
#define SSB_CHIPCO_FLASHCTL_AT_BUF2_COMPARE 0x0261
|
||||
#define SSB_CHIPCO_FLASHCTL_AT_BUF1_REPROGRAM 0x0258
|
||||
#define SSB_CHIPCO_FLASHCTL_AT_BUF2_REPROGRAM 0x0259
|
||||
|
||||
/* Status register bits for Atmel flashes */
|
||||
#define SSB_CHIPCO_FLASHSTA_AT_READY 0x80
|
||||
#define SSB_CHIPCO_FLASHSTA_AT_MISMATCH 0x40
|
||||
#define SSB_CHIPCO_FLASHSTA_AT_ID 0x38
|
||||
#define SSB_CHIPCO_FLASHSTA_AT_ID_SHIFT 3
|
||||
|
||||
|
||||
/** OTP **/
|
||||
|
||||
/* OTP regions */
|
||||
#define SSB_CHIPCO_OTP_HW_REGION SSB_CHIPCO_OTPS_HW_PROTECT
|
||||
#define SSB_CHIPCO_OTP_SW_REGION SSB_CHIPCO_OTPS_SW_PROTECT
|
||||
#define SSB_CHIPCO_OTP_CID_REGION SSB_CHIPCO_OTPS_CID_PROTECT
|
||||
|
||||
/* OTP regions (Byte offsets from otp size) */
|
||||
#define SSB_CHIPCO_OTP_SWLIM_OFF (-8)
|
||||
#define SSB_CHIPCO_OTP_CIDBASE_OFF 0
|
||||
#define SSB_CHIPCO_OTP_CIDLIM_OFF 8
|
||||
|
||||
/* Predefined OTP words (Word offset from otp size) */
|
||||
#define SSB_CHIPCO_OTP_BOUNDARY_OFF (-4)
|
||||
#define SSB_CHIPCO_OTP_HWSIGN_OFF (-3)
|
||||
#define SSB_CHIPCO_OTP_SWSIGN_OFF (-2)
|
||||
#define SSB_CHIPCO_OTP_CIDSIGN_OFF (-1)
|
||||
|
||||
#define SSB_CHIPCO_OTP_CID_OFF 0
|
||||
#define SSB_CHIPCO_OTP_PKG_OFF 1
|
||||
#define SSB_CHIPCO_OTP_FID_OFF 2
|
||||
#define SSB_CHIPCO_OTP_RSV_OFF 3
|
||||
#define SSB_CHIPCO_OTP_LIM_OFF 4
|
||||
|
||||
#define SSB_CHIPCO_OTP_SIGNATURE 0x578A
|
||||
#define SSB_CHIPCO_OTP_MAGIC 0x4E56
|
||||
|
||||
|
||||
struct ssb_device;
|
||||
struct ssb_serial_port;
|
||||
|
||||
struct ssb_chipcommon {
|
||||
struct ssb_device *dev;
|
||||
u32 capabilities;
|
||||
/* Fast Powerup Delay constant */
|
||||
u16 fast_pwrup_delay;
|
||||
};
|
||||
|
||||
extern void ssb_chipcommon_init(struct ssb_chipcommon *cc);
|
||||
|
||||
#include <linux/pm.h>
|
||||
extern void ssb_chipco_suspend(struct ssb_chipcommon *cc, pm_message_t state);
|
||||
extern void ssb_chipco_resume(struct ssb_chipcommon *cc);
|
||||
|
||||
extern void ssb_chipco_get_clockcpu(struct ssb_chipcommon *cc,
|
||||
u32 *plltype, u32 *n, u32 *m);
|
||||
extern void ssb_chipco_get_clockcontrol(struct ssb_chipcommon *cc,
|
||||
u32 *plltype, u32 *n, u32 *m);
|
||||
extern void ssb_chipco_timing_init(struct ssb_chipcommon *cc,
|
||||
unsigned long ns_per_cycle);
|
||||
|
||||
enum ssb_clkmode {
|
||||
SSB_CLKMODE_SLOW,
|
||||
SSB_CLKMODE_FAST,
|
||||
SSB_CLKMODE_DYNAMIC,
|
||||
};
|
||||
|
||||
extern void ssb_chipco_set_clockmode(struct ssb_chipcommon *cc,
|
||||
enum ssb_clkmode mode);
|
||||
|
||||
extern void ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc,
|
||||
u32 ticks);
|
||||
|
||||
u32 ssb_chipco_gpio_in(struct ssb_chipcommon *cc, u32 mask);
|
||||
|
||||
void ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value);
|
||||
|
||||
void ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value);
|
||||
|
||||
#ifdef CONFIG_SSB_SERIAL
|
||||
extern int ssb_chipco_serial_init(struct ssb_chipcommon *cc,
|
||||
struct ssb_serial_port *ports);
|
||||
#endif /* CONFIG_SSB_SERIAL */
|
||||
|
||||
#endif /* LINUX_SSB_CHIPCO_H_ */
|
||||
204
include/linux/ssb/ssb_driver_extif.h
Normal file
204
include/linux/ssb/ssb_driver_extif.h
Normal file
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
* Hardware-specific External Interface I/O core definitions
|
||||
* for the BCM47xx family of SiliconBackplane-based chips.
|
||||
*
|
||||
* The External Interface core supports a total of three external chip selects
|
||||
* supporting external interfaces. One of the external chip selects is
|
||||
* used for Flash, one is used for PCMCIA, and the other may be
|
||||
* programmed to support either a synchronous interface or an
|
||||
* asynchronous interface. The asynchronous interface can be used to
|
||||
* support external devices such as UARTs and the BCM2019 Bluetooth
|
||||
* baseband processor.
|
||||
* The external interface core also contains 2 on-chip 16550 UARTs, clock
|
||||
* frequency control, a watchdog interrupt timer, and a GPIO interface.
|
||||
*
|
||||
* Copyright 2005, Broadcom Corporation
|
||||
* Copyright 2006, Michael Buesch
|
||||
*
|
||||
* Licensed under the GPL version 2. See COPYING for details.
|
||||
*/
|
||||
#ifndef LINUX_SSB_EXTIFCORE_H_
|
||||
#define LINUX_SSB_EXTIFCORE_H_
|
||||
|
||||
/* external interface address space */
|
||||
#define SSB_EXTIF_PCMCIA_MEMBASE(x) (x)
|
||||
#define SSB_EXTIF_PCMCIA_IOBASE(x) ((x) + 0x100000)
|
||||
#define SSB_EXTIF_PCMCIA_CFGBASE(x) ((x) + 0x200000)
|
||||
#define SSB_EXTIF_CFGIF_BASE(x) ((x) + 0x800000)
|
||||
#define SSB_EXTIF_FLASH_BASE(x) ((x) + 0xc00000)
|
||||
|
||||
#define SSB_EXTIF_NR_GPIOOUT 5
|
||||
/* GPIO NOTE:
|
||||
* The multiple instances of output and output enable registers
|
||||
* are present to allow driver software for multiple cores to control
|
||||
* gpio outputs without needing to share a single register pair.
|
||||
* Use the following helper macro to get a register offset value.
|
||||
*/
|
||||
#define SSB_EXTIF_GPIO_OUT(index) ({ \
|
||||
BUILD_BUG_ON(index >= SSB_EXTIF_NR_GPIOOUT); \
|
||||
SSB_EXTIF_GPIO_OUT_BASE + ((index) * 8); \
|
||||
})
|
||||
#define SSB_EXTIF_GPIO_OUTEN(index) ({ \
|
||||
BUILD_BUG_ON(index >= SSB_EXTIF_NR_GPIOOUT); \
|
||||
SSB_EXTIF_GPIO_OUTEN_BASE + ((index) * 8); \
|
||||
})
|
||||
|
||||
/** EXTIF core registers **/
|
||||
|
||||
#define SSB_EXTIF_CTL 0x0000
|
||||
#define SSB_EXTIF_CTL_UARTEN (1 << 0) /* UART enable */
|
||||
#define SSB_EXTIF_EXTSTAT 0x0004
|
||||
#define SSB_EXTIF_EXTSTAT_EMODE (1 << 0) /* Endian mode (ro) */
|
||||
#define SSB_EXTIF_EXTSTAT_EIRQPIN (1 << 1) /* External interrupt pin (ro) */
|
||||
#define SSB_EXTIF_EXTSTAT_GPIOIRQPIN (1 << 2) /* GPIO interrupt pin (ro) */
|
||||
#define SSB_EXTIF_PCMCIA_CFG 0x0010
|
||||
#define SSB_EXTIF_PCMCIA_MEMWAIT 0x0014
|
||||
#define SSB_EXTIF_PCMCIA_ATTRWAIT 0x0018
|
||||
#define SSB_EXTIF_PCMCIA_IOWAIT 0x001C
|
||||
#define SSB_EXTIF_PROG_CFG 0x0020
|
||||
#define SSB_EXTIF_PROG_WAITCNT 0x0024
|
||||
#define SSB_EXTIF_FLASH_CFG 0x0028
|
||||
#define SSB_EXTIF_FLASH_WAITCNT 0x002C
|
||||
#define SSB_EXTIF_WATCHDOG 0x0040
|
||||
#define SSB_EXTIF_CLOCK_N 0x0044
|
||||
#define SSB_EXTIF_CLOCK_SB 0x0048
|
||||
#define SSB_EXTIF_CLOCK_PCI 0x004C
|
||||
#define SSB_EXTIF_CLOCK_MII 0x0050
|
||||
#define SSB_EXTIF_GPIO_IN 0x0060
|
||||
#define SSB_EXTIF_GPIO_OUT_BASE 0x0064
|
||||
#define SSB_EXTIF_GPIO_OUTEN_BASE 0x0068
|
||||
#define SSB_EXTIF_EJTAG_OUTEN 0x0090
|
||||
#define SSB_EXTIF_GPIO_INTPOL 0x0094
|
||||
#define SSB_EXTIF_GPIO_INTMASK 0x0098
|
||||
#define SSB_EXTIF_UART_DATA 0x0300
|
||||
#define SSB_EXTIF_UART_TIMER 0x0310
|
||||
#define SSB_EXTIF_UART_FCR 0x0320
|
||||
#define SSB_EXTIF_UART_LCR 0x0330
|
||||
#define SSB_EXTIF_UART_MCR 0x0340
|
||||
#define SSB_EXTIF_UART_LSR 0x0350
|
||||
#define SSB_EXTIF_UART_MSR 0x0360
|
||||
#define SSB_EXTIF_UART_SCRATCH 0x0370
|
||||
|
||||
|
||||
|
||||
|
||||
/* pcmcia/prog/flash_config */
|
||||
#define SSB_EXTCFG_EN (1 << 0) /* enable */
|
||||
#define SSB_EXTCFG_MODE 0xE /* mode */
|
||||
#define SSB_EXTCFG_MODE_SHIFT 1
|
||||
#define SSB_EXTCFG_MODE_FLASH 0x0 /* flash/asynchronous mode */
|
||||
#define SSB_EXTCFG_MODE_SYNC 0x2 /* synchronous mode */
|
||||
#define SSB_EXTCFG_MODE_PCMCIA 0x4 /* pcmcia mode */
|
||||
#define SSB_EXTCFG_DS16 (1 << 4) /* destsize: 0=8bit, 1=16bit */
|
||||
#define SSB_EXTCFG_BSWAP (1 << 5) /* byteswap */
|
||||
#define SSB_EXTCFG_CLKDIV 0xC0 /* clock divider */
|
||||
#define SSB_EXTCFG_CLKDIV_SHIFT 6
|
||||
#define SSB_EXTCFG_CLKDIV_2 0x0 /* backplane/2 */
|
||||
#define SSB_EXTCFG_CLKDIV_3 0x40 /* backplane/3 */
|
||||
#define SSB_EXTCFG_CLKDIV_4 0x80 /* backplane/4 */
|
||||
#define SSB_EXTCFG_CLKEN (1 << 8) /* clock enable */
|
||||
#define SSB_EXTCFG_STROBE (1 << 9) /* size/bytestrobe (synch only) */
|
||||
|
||||
/* pcmcia_memwait */
|
||||
#define SSB_PCMCIA_MEMW_0 0x0000003F /* waitcount0 */
|
||||
#define SSB_PCMCIA_MEMW_1 0x00001F00 /* waitcount1 */
|
||||
#define SSB_PCMCIA_MEMW_1_SHIFT 8
|
||||
#define SSB_PCMCIA_MEMW_2 0x001F0000 /* waitcount2 */
|
||||
#define SSB_PCMCIA_MEMW_2_SHIFT 16
|
||||
#define SSB_PCMCIA_MEMW_3 0x1F000000 /* waitcount3 */
|
||||
#define SSB_PCMCIA_MEMW_3_SHIFT 24
|
||||
|
||||
/* pcmcia_attrwait */
|
||||
#define SSB_PCMCIA_ATTW_0 0x0000003F /* waitcount0 */
|
||||
#define SSB_PCMCIA_ATTW_1 0x00001F00 /* waitcount1 */
|
||||
#define SSB_PCMCIA_ATTW_1_SHIFT 8
|
||||
#define SSB_PCMCIA_ATTW_2 0x001F0000 /* waitcount2 */
|
||||
#define SSB_PCMCIA_ATTW_2_SHIFT 16
|
||||
#define SSB_PCMCIA_ATTW_3 0x1F000000 /* waitcount3 */
|
||||
#define SSB_PCMCIA_ATTW_3_SHIFT 24
|
||||
|
||||
/* pcmcia_iowait */
|
||||
#define SSB_PCMCIA_IOW_0 0x0000003F /* waitcount0 */
|
||||
#define SSB_PCMCIA_IOW_1 0x00001F00 /* waitcount1 */
|
||||
#define SSB_PCMCIA_IOW_1_SHIFT 8
|
||||
#define SSB_PCMCIA_IOW_2 0x001F0000 /* waitcount2 */
|
||||
#define SSB_PCMCIA_IOW_2_SHIFT 16
|
||||
#define SSB_PCMCIA_IOW_3 0x1F000000 /* waitcount3 */
|
||||
#define SSB_PCMCIA_IOW_3_SHIFT 24
|
||||
|
||||
/* prog_waitcount */
|
||||
#define SSB_PROG_WCNT_0 0x0000001F /* waitcount0 */
|
||||
#define SSB_PROG_WCNT_1 0x00001F00 /* waitcount1 */
|
||||
#define SSB_PROG_WCNT_1_SHIFT 8
|
||||
#define SSB_PROG_WCNT_2 0x001F0000 /* waitcount2 */
|
||||
#define SSB_PROG_WCNT_2_SHIFT 16
|
||||
#define SSB_PROG_WCNT_3 0x1F000000 /* waitcount3 */
|
||||
#define SSB_PROG_WCNT_3_SHIFT 24
|
||||
|
||||
#define SSB_PROG_W0 0x0000000C
|
||||
#define SSB_PROG_W1 0x00000A00
|
||||
#define SSB_PROG_W2 0x00020000
|
||||
#define SSB_PROG_W3 0x01000000
|
||||
|
||||
/* flash_waitcount */
|
||||
#define SSB_FLASH_WCNT_0 0x0000001F /* waitcount0 */
|
||||
#define SSB_FLASH_WCNT_1 0x00001F00 /* waitcount1 */
|
||||
#define SSB_FLASH_WCNT_1_SHIFT 8
|
||||
#define SSB_FLASH_WCNT_2 0x001F0000 /* waitcount2 */
|
||||
#define SSB_FLASH_WCNT_2_SHIFT 16
|
||||
#define SSB_FLASH_WCNT_3 0x1F000000 /* waitcount3 */
|
||||
#define SSB_FLASH_WCNT_3_SHIFT 24
|
||||
|
||||
/* watchdog */
|
||||
#define SSB_EXTIF_WATCHDOG_CLK 48000000 /* Hz */
|
||||
|
||||
|
||||
|
||||
#ifdef CONFIG_SSB_DRIVER_EXTIF
|
||||
|
||||
struct ssb_extif {
|
||||
struct ssb_device *dev;
|
||||
};
|
||||
|
||||
static inline bool ssb_extif_available(struct ssb_extif *extif)
|
||||
{
|
||||
return (extif->dev != NULL);
|
||||
}
|
||||
|
||||
extern void ssb_extif_get_clockcontrol(struct ssb_extif *extif,
|
||||
u32 *plltype, u32 *n, u32 *m);
|
||||
|
||||
extern void ssb_extif_timing_init(struct ssb_extif *extif,
|
||||
unsigned long ns);
|
||||
|
||||
u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask);
|
||||
|
||||
void ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, u32 value);
|
||||
|
||||
void ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, u32 value);
|
||||
|
||||
#ifdef CONFIG_SSB_SERIAL
|
||||
extern int ssb_extif_serial_init(struct ssb_extif *extif,
|
||||
struct ssb_serial_port *ports);
|
||||
#endif /* CONFIG_SSB_SERIAL */
|
||||
|
||||
|
||||
#else /* CONFIG_SSB_DRIVER_EXTIF */
|
||||
/* extif disabled */
|
||||
|
||||
struct ssb_extif {
|
||||
};
|
||||
|
||||
static inline bool ssb_extif_available(struct ssb_extif *extif)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline
|
||||
void ssb_extif_get_clockcontrol(struct ssb_extif *extif,
|
||||
u32 *plltype, u32 *n, u32 *m)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SSB_DRIVER_EXTIF */
|
||||
#endif /* LINUX_SSB_EXTIFCORE_H_ */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user