2011-05-09 20:56:46 +04:00
/*
* Broadcom specific AMBA
* PCI Host
*
* Licensed under the GNU / GPL . See COPYING for details .
*/
# include "bcma_private.h"
2011-05-27 03:24:57 +04:00
# include <linux/slab.h>
2011-05-09 20:56:46 +04:00
# include <linux/bcma/bcma.h>
# include <linux/pci.h>
2011-07-02 00:06:37 +04:00
# include <linux/module.h>
2011-05-09 20:56:46 +04:00
static void bcma_host_pci_switch_core ( struct bcma_device * core )
{
2015-01-25 15:41:19 +03:00
int win2 = core - > bus - > host_is_pcie2 ?
BCMA_PCIE2_BAR0_WIN2 : BCMA_PCI_BAR0_WIN2 ;
2011-05-09 20:56:46 +04:00
pci_write_config_dword ( core - > bus - > host_pci , BCMA_PCI_BAR0_WIN ,
core - > addr ) ;
2015-01-25 15:41:19 +03:00
pci_write_config_dword ( core - > bus - > host_pci , win2 , core - > wrap ) ;
2011-05-09 20:56:46 +04:00
core - > bus - > mapped_core = core ;
2012-07-06 00:07:32 +04:00
bcma_debug ( core - > bus , " Switched to core: 0x%X \n " , core - > id . id ) ;
2011-05-09 20:56:46 +04:00
}
2011-12-05 22:13:39 +04:00
/* Provides access to the requested core. Returns base offset that has to be
* used . It makes use of fixed windows when possible . */
static u16 bcma_host_pci_provide_access_to_core ( struct bcma_device * core )
2011-05-09 20:56:46 +04:00
{
2011-12-05 22:13:39 +04:00
switch ( core - > id . id ) {
case BCMA_CORE_CHIPCOMMON :
return 3 * BCMA_CORE_SIZE ;
case BCMA_CORE_PCIE :
return 2 * BCMA_CORE_SIZE ;
}
2011-05-09 20:56:46 +04:00
if ( core - > bus - > mapped_core ! = core )
bcma_host_pci_switch_core ( core ) ;
2011-12-05 22:13:39 +04:00
return 0 ;
}
static u8 bcma_host_pci_read8 ( struct bcma_device * core , u16 offset )
{
offset + = bcma_host_pci_provide_access_to_core ( core ) ;
2011-05-09 20:56:46 +04:00
return ioread8 ( core - > bus - > mmio + offset ) ;
}
static u16 bcma_host_pci_read16 ( struct bcma_device * core , u16 offset )
{
2011-12-05 22:13:39 +04:00
offset + = bcma_host_pci_provide_access_to_core ( core ) ;
2011-05-09 20:56:46 +04:00
return ioread16 ( core - > bus - > mmio + offset ) ;
}
static u32 bcma_host_pci_read32 ( struct bcma_device * core , u16 offset )
{
2011-12-05 22:13:39 +04:00
offset + = bcma_host_pci_provide_access_to_core ( core ) ;
2011-05-09 20:56:46 +04:00
return ioread32 ( core - > bus - > mmio + offset ) ;
}
static void bcma_host_pci_write8 ( struct bcma_device * core , u16 offset ,
u8 value )
{
2011-12-05 22:13:39 +04:00
offset + = bcma_host_pci_provide_access_to_core ( core ) ;
2011-05-09 20:56:46 +04:00
iowrite8 ( value , core - > bus - > mmio + offset ) ;
}
static void bcma_host_pci_write16 ( struct bcma_device * core , u16 offset ,
u16 value )
{
2011-12-05 22:13:39 +04:00
offset + = bcma_host_pci_provide_access_to_core ( core ) ;
2011-05-09 20:56:46 +04:00
iowrite16 ( value , core - > bus - > mmio + offset ) ;
}
static void bcma_host_pci_write32 ( struct bcma_device * core , u16 offset ,
u32 value )
{
2011-12-05 22:13:39 +04:00
offset + = bcma_host_pci_provide_access_to_core ( core ) ;
2011-05-09 20:56:46 +04:00
iowrite32 ( value , core - > bus - > mmio + offset ) ;
}
2011-05-20 05:27:06 +04:00
# ifdef CONFIG_BCMA_BLOCKIO
2012-08-05 18:54:41 +04:00
static void bcma_host_pci_block_read ( struct bcma_device * core , void * buffer ,
size_t count , u16 offset , u8 reg_width )
2011-05-20 05:27:06 +04:00
{
void __iomem * addr = core - > bus - > mmio + offset ;
if ( core - > bus - > mapped_core ! = core )
bcma_host_pci_switch_core ( core ) ;
switch ( reg_width ) {
case sizeof ( u8 ) :
ioread8_rep ( addr , buffer , count ) ;
break ;
case sizeof ( u16 ) :
WARN_ON ( count & 1 ) ;
ioread16_rep ( addr , buffer , count > > 1 ) ;
break ;
case sizeof ( u32 ) :
WARN_ON ( count & 3 ) ;
ioread32_rep ( addr , buffer , count > > 2 ) ;
break ;
default :
WARN_ON ( 1 ) ;
}
}
2012-08-05 18:54:41 +04:00
static void bcma_host_pci_block_write ( struct bcma_device * core ,
const void * buffer , size_t count ,
u16 offset , u8 reg_width )
2011-05-20 05:27:06 +04:00
{
void __iomem * addr = core - > bus - > mmio + offset ;
if ( core - > bus - > mapped_core ! = core )
bcma_host_pci_switch_core ( core ) ;
switch ( reg_width ) {
case sizeof ( u8 ) :
iowrite8_rep ( addr , buffer , count ) ;
break ;
case sizeof ( u16 ) :
WARN_ON ( count & 1 ) ;
iowrite16_rep ( addr , buffer , count > > 1 ) ;
break ;
case sizeof ( u32 ) :
WARN_ON ( count & 3 ) ;
iowrite32_rep ( addr , buffer , count > > 2 ) ;
break ;
default :
WARN_ON ( 1 ) ;
}
}
# endif
2011-05-09 20:56:46 +04:00
static u32 bcma_host_pci_aread32 ( struct bcma_device * core , u16 offset )
{
if ( core - > bus - > mapped_core ! = core )
bcma_host_pci_switch_core ( core ) ;
return ioread32 ( core - > bus - > mmio + ( 1 * BCMA_CORE_SIZE ) + offset ) ;
}
static void bcma_host_pci_awrite32 ( struct bcma_device * core , u16 offset ,
u32 value )
{
if ( core - > bus - > mapped_core ! = core )
bcma_host_pci_switch_core ( core ) ;
iowrite32 ( value , core - > bus - > mmio + ( 1 * BCMA_CORE_SIZE ) + offset ) ;
}
2012-08-05 18:54:41 +04:00
static const struct bcma_host_ops bcma_host_pci_ops = {
2011-05-09 20:56:46 +04:00
. read8 = bcma_host_pci_read8 ,
. read16 = bcma_host_pci_read16 ,
. read32 = bcma_host_pci_read32 ,
. write8 = bcma_host_pci_write8 ,
. write16 = bcma_host_pci_write16 ,
. write32 = bcma_host_pci_write32 ,
2011-05-20 05:27:06 +04:00
# ifdef CONFIG_BCMA_BLOCKIO
. block_read = bcma_host_pci_block_read ,
. block_write = bcma_host_pci_block_write ,
# endif
2011-05-09 20:56:46 +04:00
. aread32 = bcma_host_pci_aread32 ,
. awrite32 = bcma_host_pci_awrite32 ,
} ;
2012-12-22 03:12:59 +04:00
static int bcma_host_pci_probe ( struct pci_dev * dev ,
const struct pci_device_id * id )
2011-05-09 20:56:46 +04:00
{
struct bcma_bus * bus ;
int err = - ENOMEM ;
const char * name ;
u32 val ;
/* Alloc */
bus = kzalloc ( sizeof ( * bus ) , GFP_KERNEL ) ;
if ( ! bus )
goto out ;
/* Basic PCI configuration */
err = pci_enable_device ( dev ) ;
if ( err )
goto err_kfree_bus ;
name = dev_name ( & dev - > dev ) ;
if ( dev - > driver & & dev - > driver - > name )
name = dev - > driver - > name ;
err = pci_request_regions ( dev , name ) ;
if ( err )
goto err_pci_disable ;
pci_set_master ( dev ) ;
/* Disable the RETRY_TIMEOUT register (0x41) to keep
* PCI Tx retries from interfering with C3 CPU state */
pci_read_config_dword ( dev , 0x40 , & val ) ;
if ( ( val & 0x0000ff00 ) ! = 0 )
pci_write_config_dword ( dev , 0x40 , val & 0xffff00ff ) ;
/* SSB needed additional powering up, do we have any AMBA PCI cards? */
2013-10-03 15:49:09 +04:00
if ( ! pci_is_pcie ( dev ) ) {
bcma_err ( bus , " PCI card detected, they are not supported. \n " ) ;
err = - ENXIO ;
goto err_pci_release_regions ;
}
2011-05-09 20:56:46 +04:00
/* Map MMIO */
err = - ENOMEM ;
bus - > mmio = pci_iomap ( dev , 0 , ~ 0UL ) ;
if ( ! bus - > mmio )
goto err_pci_release_regions ;
/* Host specific */
bus - > host_pci = dev ;
bus - > hosttype = BCMA_HOSTTYPE_PCI ;
bus - > ops = & bcma_host_pci_ops ;
2012-04-29 04:04:08 +04:00
bus - > boardinfo . vendor = bus - > host_pci - > subsystem_vendor ;
bus - > boardinfo . type = bus - > host_pci - > subsystem_device ;
2014-09-02 01:11:06 +04:00
/* Initialize struct, detect chip */
bcma_init_bus ( bus ) ;
2015-02-08 19:11:50 +03:00
/* Scan bus to find out generation of PCIe core */
err = bcma_bus_scan ( bus ) ;
if ( err )
goto err_pci_unmap_mmio ;
if ( bcma_find_core ( bus , BCMA_CORE_PCIE2 ) )
bus - > host_is_pcie2 = true ;
2011-05-09 20:56:46 +04:00
/* Register */
err = bcma_bus_register ( bus ) ;
if ( err )
2015-02-08 19:11:50 +03:00
goto err_unregister_cores ;
2011-05-09 20:56:46 +04:00
pci_set_drvdata ( dev , bus ) ;
out :
return err ;
2015-02-08 19:11:50 +03:00
err_unregister_cores :
bcma_unregister_cores ( bus ) ;
2011-05-09 20:56:46 +04:00
err_pci_unmap_mmio :
pci_iounmap ( dev , bus - > mmio ) ;
err_pci_release_regions :
pci_release_regions ( dev ) ;
err_pci_disable :
pci_disable_device ( dev ) ;
err_kfree_bus :
kfree ( bus ) ;
return err ;
}
2012-12-22 03:12:59 +04:00
static void bcma_host_pci_remove ( struct pci_dev * dev )
2011-05-09 20:56:46 +04:00
{
struct bcma_bus * bus = pci_get_drvdata ( dev ) ;
bcma_bus_unregister ( bus ) ;
pci_iounmap ( dev , bus - > mmio ) ;
pci_release_regions ( dev ) ;
pci_disable_device ( dev ) ;
kfree ( bus ) ;
}
2012-10-16 18:59:02 +04:00
# ifdef CONFIG_PM_SLEEP
2012-01-14 02:58:39 +04:00
static int bcma_host_pci_suspend ( struct device * dev )
2011-12-10 01:16:07 +04:00
{
2012-01-14 02:58:39 +04:00
struct pci_dev * pdev = to_pci_dev ( dev ) ;
struct bcma_bus * bus = pci_get_drvdata ( pdev ) ;
2011-12-10 01:16:07 +04:00
2012-01-14 02:58:38 +04:00
bus - > mapped_core = NULL ;
2012-01-14 02:58:39 +04:00
2012-01-14 02:58:40 +04:00
return bcma_bus_suspend ( bus ) ;
2011-12-10 01:16:07 +04:00
}
2012-01-14 02:58:39 +04:00
static int bcma_host_pci_resume ( struct device * dev )
2011-12-10 01:16:07 +04:00
{
2012-01-14 02:58:39 +04:00
struct pci_dev * pdev = to_pci_dev ( dev ) ;
struct bcma_bus * bus = pci_get_drvdata ( pdev ) ;
2011-12-10 01:16:07 +04:00
2012-01-14 02:58:39 +04:00
return bcma_bus_resume ( bus ) ;
}
2011-12-10 01:16:07 +04:00
2012-01-14 02:58:39 +04:00
static SIMPLE_DEV_PM_OPS ( bcma_pm_ops , bcma_host_pci_suspend ,
bcma_host_pci_resume ) ;
# define BCMA_PM_OPS (&bcma_pm_ops)
2011-12-10 01:16:07 +04:00
2012-10-16 18:59:02 +04:00
# else /* CONFIG_PM_SLEEP */
2012-01-14 02:58:39 +04:00
# define BCMA_PM_OPS NULL
2012-10-16 18:59:02 +04:00
# endif /* CONFIG_PM_SLEEP */
2011-12-10 01:16:07 +04:00
2013-12-03 03:00:27 +04:00
static const struct pci_device_id bcma_pci_bridge_tbl [ ] = {
2011-05-14 12:31:46 +04:00
{ PCI_DEVICE ( PCI_VENDOR_ID_BROADCOM , 0x0576 ) } ,
2013-10-03 15:49:10 +04:00
{ PCI_DEVICE ( PCI_VENDOR_ID_BROADCOM , 0x4313 ) } ,
2014-10-15 09:51:44 +04:00
{ PCI_DEVICE ( PCI_VENDOR_ID_BROADCOM , 43224 ) } , /* 0xa8d8 */
2011-05-09 20:56:46 +04:00
{ PCI_DEVICE ( PCI_VENDOR_ID_BROADCOM , 0x4331 ) } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_BROADCOM , 0x4353 ) } ,
2011-06-17 15:15:23 +04:00
{ PCI_DEVICE ( PCI_VENDOR_ID_BROADCOM , 0x4357 ) } ,
2012-09-21 10:38:38 +04:00
{ PCI_DEVICE ( PCI_VENDOR_ID_BROADCOM , 0x4358 ) } ,
2012-07-23 20:20:12 +04:00
{ PCI_DEVICE ( PCI_VENDOR_ID_BROADCOM , 0x4359 ) } ,
2015-02-08 19:11:50 +03:00
{ PCI_DEVICE ( PCI_VENDOR_ID_BROADCOM , 0x4360 ) } ,
2016-01-26 19:02:09 +03:00
{ PCI_DEVICE_SUB ( PCI_VENDOR_ID_BROADCOM , 0x4365 , PCI_VENDOR_ID_DELL , 0x0016 ) } ,
bcma: add Dell Inspiron 3148
This is what is in the laptop:
01:00.0 Network controller [0280]: Broadcom Limited BCM43142 802.11b/g/n [14e4:4365] (rev 01)
Subsystem: Dell Device [1028:0018]
Flags: bus master, fast devsel, latency 0, IRQ 18
Memory at b0400000 (64-bit, non-prefetchable) [size=32K]
Capabilities: [40] Power Management version 3
Capabilities: [58] Vendor Specific Information: Len=78 <?>
Capabilities: [48] MSI: Enable- Count=1/1 Maskable- 64bit+
Capabilities: [d0] Express Endpoint, MSI 00
Capabilities: [100] Advanced Error Reporting
Capabilities: [13c] Virtual Channel
Capabilities: [160] Device Serial Number 00-00-9a-ff-ff-f3-40-b8
Capabilities: [16c] Power Budgeting <?>
With the patch, I can see:
bcma: bus0: Found chip with id 43142, rev 0x01 and package 0x08
bcma: bus0: Core 0 found: ChipCommon (manuf 0x4BF, id 0x800, rev 0x28, class 0x0)
bcma: bus0: Core 1 found: IEEE 802.11 (manuf 0x4BF, id 0x812, rev 0x21, class 0x0)
bcma: bus0: Core 2 found: PCIe (manuf 0x4BF, id 0x820, rev 0x16, class 0x0)
bcma: bus0: Core 3 found: UNKNOWN (manuf 0x43B, id 0x368, rev 0x00, class 0x0)
bcma: bus0: Bus registered
The wifi is not currently supported by brcmsmac yet:
brcmsmac bcma1:1: mfg 4bf core 812 rev 33 class 0 irq 18
brcmsmac: unknown device id 4365
So don't expect a working wifi from this patch :).
Signed-off-by: Jiri Slaby <jslaby@suse.cz>
Cc: Rafał Miłecki <zajec5@gmail.com>
Cc: <linux-wireless@vger.kernel.org>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
2016-11-28 10:57:12 +03:00
{ PCI_DEVICE_SUB ( PCI_VENDOR_ID_BROADCOM , 0x4365 , PCI_VENDOR_ID_DELL , 0x0018 ) } ,
2016-07-12 00:01:36 +03:00
{ PCI_DEVICE_SUB ( PCI_VENDOR_ID_BROADCOM , 0x4365 , PCI_VENDOR_ID_FOXCONN , 0xe092 ) } ,
bcma: add HP Stream Notebook
In this laptop we have the following PCI device:
02:00.0 Network controller [0280]: Broadcom Limited BCM43142 802.11b/g/n [14e4:4365] (rev 01)
Subsystem: Hewlett-Packard Company BCM43142 802.11b/g/n [103c:804a]
[...]
Region 0: Memory at 91000000 (64-bit, non-prefetchable) [size=32K]
[...]
With this patch, we can now see its WiFi chip:
bcma: bus0: Found chip with id 43142, rev 0x01 and package 0x08
bcma: bus0: Core 0 found: ChipCommon (manuf 0x4BF, id 0x800, rev 0x28, class 0x0)
bcma: bus0: Core 1 found: IEEE 802.11 (manuf 0x4BF, id 0x812, rev 0x21, class 0x0)
bcma: bus0: Core 2 found: PCIe (manuf 0x4BF, id 0x820, rev 0x16, class 0x0)
bcma: bus0: Core 3 found: UNKNOWN (manuf 0x43B, id 0x368, rev 0x00, class 0x0)
bcma: bus0: Found rev 15 PMU (capabilities 0x518C5E0F)
bcma: bus0: SPROM offset 0x840
bcma: bus0: Found SPROM revision 10
bcma: bus0: Workarounds unknown or not needed for device 0xA886
bcma: bus0: Bus registered
But it not yet supported by brcmsmac so it won't work for now:
brcmsmac bcma0:1: brcms_b_attach wl0: vendor 0x14e4 device 0x4365
brcmsmac: unknown device id 4365
Signed-off-by: Denis 'GNUtoo' Carikli <GNUtoo@no-log.org>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
2018-02-08 19:25:42 +03:00
{ PCI_DEVICE_SUB ( PCI_VENDOR_ID_BROADCOM , 0x4365 , PCI_VENDOR_ID_HP , 0x804a ) } ,
2015-02-08 19:11:50 +03:00
{ PCI_DEVICE ( PCI_VENDOR_ID_BROADCOM , 0x43a0 ) } ,
2014-07-15 21:44:28 +04:00
{ PCI_DEVICE ( PCI_VENDOR_ID_BROADCOM , 0x43a9 ) } ,
2014-07-24 17:29:19 +04:00
{ PCI_DEVICE ( PCI_VENDOR_ID_BROADCOM , 0x43aa ) } ,
2015-02-08 19:11:50 +03:00
{ PCI_DEVICE ( PCI_VENDOR_ID_BROADCOM , 0x43b1 ) } ,
2011-05-09 20:56:46 +04:00
{ PCI_DEVICE ( PCI_VENDOR_ID_BROADCOM , 0x4727 ) } ,
2014-10-15 09:51:44 +04:00
{ PCI_DEVICE ( PCI_VENDOR_ID_BROADCOM , 43227 ) } , /* 0xa8db, BCM43217 (sic!) */
{ PCI_DEVICE ( PCI_VENDOR_ID_BROADCOM , 43228 ) } , /* 0xa8dc */
2011-05-09 20:56:46 +04:00
{ 0 , } ,
} ;
MODULE_DEVICE_TABLE ( pci , bcma_pci_bridge_tbl ) ;
static struct pci_driver bcma_pci_bridge_driver = {
. name = " bcma-pci-bridge " ,
. id_table = bcma_pci_bridge_tbl ,
. probe = bcma_host_pci_probe ,
2012-12-22 03:12:59 +04:00
. remove = bcma_host_pci_remove ,
2012-01-14 02:58:39 +04:00
. driver . pm = BCMA_PM_OPS ,
2011-05-09 20:56:46 +04:00
} ;
int __init bcma_host_pci_init ( void )
{
return pci_register_driver ( & bcma_pci_bridge_driver ) ;
}
void __exit bcma_host_pci_exit ( void )
{
pci_unregister_driver ( & bcma_pci_bridge_driver ) ;
}
2015-02-08 19:11:47 +03:00
/**************************************************
* Runtime ops for drivers .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* See also pcicore_up */
void bcma_host_pci_up ( struct bcma_bus * bus )
{
if ( bus - > hosttype ! = BCMA_HOSTTYPE_PCI )
return ;
if ( bus - > host_is_pcie2 )
2015-02-08 19:11:49 +03:00
bcma_core_pcie2_up ( & bus - > drv_pcie2 ) ;
2015-02-08 19:11:47 +03:00
else
bcma_core_pci_up ( & bus - > drv_pci [ 0 ] ) ;
}
EXPORT_SYMBOL_GPL ( bcma_host_pci_up ) ;
/* See also pcicore_down */
void bcma_host_pci_down ( struct bcma_bus * bus )
{
if ( bus - > hosttype ! = BCMA_HOSTTYPE_PCI )
return ;
if ( ! bus - > host_is_pcie2 )
bcma_core_pci_down ( & bus - > drv_pci [ 0 ] ) ;
}
EXPORT_SYMBOL_GPL ( bcma_host_pci_down ) ;
2015-03-05 20:25:10 +03:00
/* See also si_pci_setup */
int bcma_host_pci_irq_ctl ( struct bcma_bus * bus , struct bcma_device * core ,
bool enable )
{
struct pci_dev * pdev ;
u32 coremask , tmp ;
int err = 0 ;
if ( bus - > hosttype ! = BCMA_HOSTTYPE_PCI ) {
/* This bcma device is not on a PCI host-bus. So the IRQs are
* not routed through the PCI core .
* So we must not enable routing through the PCI core . */
goto out ;
}
pdev = bus - > host_pci ;
err = pci_read_config_dword ( pdev , BCMA_PCI_IRQMASK , & tmp ) ;
if ( err )
goto out ;
coremask = BIT ( core - > core_index ) < < 8 ;
if ( enable )
tmp | = coremask ;
else
tmp & = ~ coremask ;
err = pci_write_config_dword ( pdev , BCMA_PCI_IRQMASK , tmp ) ;
out :
return err ;
}
EXPORT_SYMBOL_GPL ( bcma_host_pci_irq_ctl ) ;