2011-07-23 03:20:09 +04:00
/*
* Broadcom specific AMBA
* Broadcom MIPS32 74 K core driver
*
* Copyright 2009 , Broadcom Corporation
* Copyright 2006 , 2007 , Michael Buesch < mb @ bu3sch . de >
* Copyright 2010 , Bernhard Loos < bernhardloos @ googlemail . com >
* Copyright 2011 , Hauke Mehrtens < hauke @ hauke - m . de >
*
* Licensed under the GNU / GPL . See COPYING for details .
*/
# include "bcma_private.h"
# include <linux/bcma/bcma.h>
# include <linux/serial.h>
# include <linux/serial_core.h>
# include <linux/serial_reg.h>
# include <linux/time.h>
2014-10-28 15:30:23 +03:00
# ifdef CONFIG_BCM47XX
2014-12-01 09:58:18 +03:00
# include <linux/bcm47xx_nvram.h>
2014-10-28 15:30:23 +03:00
# endif
2011-07-23 03:20:09 +04:00
2014-09-03 12:35:13 +04:00
enum bcma_boot_dev {
BCMA_BOOT_DEV_UNK = 0 ,
BCMA_BOOT_DEV_ROM ,
BCMA_BOOT_DEV_PARALLEL ,
BCMA_BOOT_DEV_SERIAL ,
BCMA_BOOT_DEV_NAND ,
} ;
2011-07-23 03:20:09 +04:00
/* The 47162a0 hangs when reading MIPS DMP registers registers */
static inline bool bcma_core_mips_bcm47162a0_quirk ( struct bcma_device * dev )
{
2012-06-30 03:44:38 +04:00
return dev - > bus - > chipinfo . id = = BCMA_CHIP_ID_BCM47162 & &
dev - > bus - > chipinfo . rev = = 0 & & dev - > id . id = = BCMA_CORE_MIPS_74K ;
2011-07-23 03:20:09 +04:00
}
/* The 5357b0 hangs when reading USB20H DMP registers */
static inline bool bcma_core_mips_bcm5357b0_quirk ( struct bcma_device * dev )
{
2012-06-30 03:44:38 +04:00
return ( dev - > bus - > chipinfo . id = = BCMA_CHIP_ID_BCM5357 | |
dev - > bus - > chipinfo . id = = BCMA_CHIP_ID_BCM4749 ) & &
2011-07-23 03:20:09 +04:00
dev - > bus - > chipinfo . pkg = = 11 & &
dev - > id . id = = BCMA_CORE_USB20_HOST ;
}
static inline u32 mips_read32 ( struct bcma_drv_mips * mcore ,
u16 offset )
{
return bcma_read32 ( mcore - > core , offset ) ;
}
static u32 bcma_core_mips_irqflag ( struct bcma_device * dev )
{
u32 flag ;
if ( bcma_core_mips_bcm47162a0_quirk ( dev ) )
return dev - > core_index ;
if ( bcma_core_mips_bcm5357b0_quirk ( dev ) )
return dev - > core_index ;
flag = bcma_aread32 ( dev , BCMA_MIPS_OOBSELOUTA30 ) ;
2013-01-04 03:51:23 +04:00
if ( flag )
return flag & 0x1F ;
else
return 0x3f ;
2011-07-23 03:20:09 +04:00
}
/* Get the MIPS IRQ assignment for a specified device.
* If unassigned , 0 is returned .
2013-01-04 03:51:23 +04:00
* If disabled , 5 is returned .
* If not supported , 6 is returned .
2011-07-23 03:20:09 +04:00
*/
2014-11-01 18:54:55 +03:00
unsigned int bcma_core_mips_irq ( struct bcma_device * dev )
2011-07-23 03:20:09 +04:00
{
struct bcma_device * mdev = dev - > bus - > drv_mips . core ;
u32 irqflag ;
unsigned int irq ;
irqflag = bcma_core_mips_irqflag ( dev ) ;
2013-01-04 03:51:23 +04:00
if ( irqflag = = 0x3f )
return 6 ;
2011-07-23 03:20:09 +04:00
2013-01-04 03:51:23 +04:00
for ( irq = 0 ; irq < = 4 ; irq + + )
2011-07-23 03:20:09 +04:00
if ( bcma_read32 ( mdev , BCMA_MIPS_MIPS74K_INTMASK ( irq ) ) &
( 1 < < irqflag ) )
return irq ;
2013-01-04 03:51:23 +04:00
return 5 ;
2011-07-23 03:20:09 +04:00
}
2013-01-10 20:54:09 +04:00
2011-07-23 03:20:09 +04:00
static void bcma_core_mips_set_irq ( struct bcma_device * dev , unsigned int irq )
{
unsigned int oldirq = bcma_core_mips_irq ( dev ) ;
struct bcma_bus * bus = dev - > bus ;
struct bcma_device * mdev = bus - > drv_mips . core ;
u32 irqflag ;
irqflag = bcma_core_mips_irqflag ( dev ) ;
BUG_ON ( oldirq = = 6 ) ;
dev - > irq = irq + 2 ;
/* clear the old irq */
if ( oldirq = = 0 )
bcma_write32 ( mdev , BCMA_MIPS_MIPS74K_INTMASK ( 0 ) ,
bcma_read32 ( mdev , BCMA_MIPS_MIPS74K_INTMASK ( 0 ) ) &
~ ( 1 < < irqflag ) ) ;
2013-01-04 03:51:23 +04:00
else if ( oldirq ! = 5 )
2012-12-10 10:53:56 +04:00
bcma_write32 ( mdev , BCMA_MIPS_MIPS74K_INTMASK ( oldirq ) , 0 ) ;
2011-07-23 03:20:09 +04:00
/* assign the new one */
if ( irq = = 0 ) {
bcma_write32 ( mdev , BCMA_MIPS_MIPS74K_INTMASK ( 0 ) ,
bcma_read32 ( mdev , BCMA_MIPS_MIPS74K_INTMASK ( 0 ) ) |
( 1 < < irqflag ) ) ;
} else {
2013-01-04 03:51:25 +04:00
u32 irqinitmask = bcma_read32 ( mdev ,
BCMA_MIPS_MIPS74K_INTMASK ( irq ) ) ;
if ( irqinitmask ) {
2011-07-23 03:20:09 +04:00
struct bcma_device * core ;
/* backplane irq line is in use, find out who uses
* it and set user to irq 0
*/
2012-07-26 19:44:12 +04:00
list_for_each_entry ( core , & bus - > cores , list ) {
2011-07-23 03:20:09 +04:00
if ( ( 1 < < bcma_core_mips_irqflag ( core ) ) = =
2013-01-04 03:51:25 +04:00
irqinitmask ) {
2011-07-23 03:20:09 +04:00
bcma_core_mips_set_irq ( core , 0 ) ;
break ;
}
}
}
bcma_write32 ( mdev , BCMA_MIPS_MIPS74K_INTMASK ( irq ) ,
1 < < irqflag ) ;
}
2013-01-04 03:51:22 +04:00
bcma_debug ( bus , " set_irq: core 0x%04x, irq %d => %d \n " ,
2013-01-04 03:51:23 +04:00
dev - > id . id , oldirq < = 4 ? oldirq + 2 : 0 , irq + 2 ) ;
2011-07-23 03:20:09 +04:00
}
2013-01-04 03:51:21 +04:00
static void bcma_core_mips_set_irq_name ( struct bcma_bus * bus , unsigned int irq ,
u16 coreid , u8 unit )
{
struct bcma_device * core ;
core = bcma_find_core_unit ( bus , coreid , unit ) ;
if ( ! core ) {
bcma_warn ( bus ,
" Can not find core (id: 0x%x, unit %i) for IRQ configuration. \n " ,
coreid , unit ) ;
return ;
}
bcma_core_mips_set_irq ( core , irq ) ;
}
2011-07-23 03:20:09 +04:00
static void bcma_core_mips_print_irq ( struct bcma_device * dev , unsigned int irq )
{
int i ;
static const char * irq_name [ ] = { " 2(S) " , " 3 " , " 4 " , " 5 " , " 6 " , " D " , " I " } ;
2018-05-08 12:31:04 +03:00
char interrupts [ 25 ] ;
2017-10-19 08:45:27 +03:00
char * ints = interrupts ;
2017-10-16 15:54:32 +03:00
2017-10-19 08:45:27 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( irq_name ) ; i + + )
ints + = sprintf ( ints , " %s%c " ,
irq_name [ i ] , i = = irq ? ' * ' : ' ' ) ;
bcma_debug ( dev - > bus , " core 0x%04x, irq:%s \n " , dev - > id . id , interrupts ) ;
2011-07-23 03:20:09 +04:00
}
static void bcma_core_mips_dump_irq ( struct bcma_bus * bus )
{
struct bcma_device * core ;
2012-07-26 19:44:12 +04:00
list_for_each_entry ( core , & bus - > cores , list ) {
2011-07-23 03:20:09 +04:00
bcma_core_mips_print_irq ( core , bcma_core_mips_irq ( core ) ) ;
}
}
2011-07-23 03:20:11 +04:00
u32 bcma_cpu_clock ( struct bcma_drv_mips * mcore )
{
struct bcma_bus * bus = mcore - > core - > bus ;
if ( bus - > drv_cc . capabilities & BCMA_CC_CAP_PMU )
2012-12-07 15:56:56 +04:00
return bcma_pmu_get_cpu_clock ( & bus - > drv_cc ) ;
2011-07-23 03:20:11 +04:00
2012-07-06 00:07:32 +04:00
bcma_err ( bus , " No PMU available, need this to get the cpu clock \n " ) ;
2011-07-23 03:20:11 +04:00
return 0 ;
}
EXPORT_SYMBOL ( bcma_cpu_clock ) ;
2014-09-03 12:35:13 +04:00
static enum bcma_boot_dev bcma_boot_dev ( struct bcma_bus * bus )
{
struct bcma_drv_cc * cc = & bus - > drv_cc ;
u8 cc_rev = cc - > core - > id . rev ;
if ( cc_rev = = 42 ) {
struct bcma_device * core ;
core = bcma_find_core ( bus , BCMA_CORE_NS_ROM ) ;
if ( core ) {
switch ( bcma_aread32 ( core , BCMA_IOST ) &
BCMA_NS_ROM_IOST_BOOT_DEV_MASK ) {
case BCMA_NS_ROM_IOST_BOOT_DEV_NOR :
return BCMA_BOOT_DEV_SERIAL ;
case BCMA_NS_ROM_IOST_BOOT_DEV_NAND :
return BCMA_BOOT_DEV_NAND ;
case BCMA_NS_ROM_IOST_BOOT_DEV_ROM :
default :
return BCMA_BOOT_DEV_ROM ;
}
}
} else {
if ( cc_rev = = 38 ) {
if ( cc - > status & BCMA_CC_CHIPST_5357_NAND_BOOT )
return BCMA_BOOT_DEV_NAND ;
else if ( cc - > status & BIT ( 5 ) )
return BCMA_BOOT_DEV_ROM ;
}
if ( ( cc - > capabilities & BCMA_CC_CAP_FLASHT ) = =
BCMA_CC_FLASHT_PARA )
return BCMA_BOOT_DEV_PARALLEL ;
else
return BCMA_BOOT_DEV_SERIAL ;
}
return BCMA_BOOT_DEV_SERIAL ;
}
2016-02-12 12:15:45 +03:00
static void bcma_core_mips_nvram_init ( struct bcma_drv_mips * mcore )
2011-07-23 03:20:09 +04:00
{
struct bcma_bus * bus = mcore - > core - > bus ;
2014-09-03 12:35:13 +04:00
enum bcma_boot_dev boot_dev ;
2011-07-23 03:20:09 +04:00
2014-09-03 12:35:13 +04:00
/* Determine flash type this SoC boots from */
boot_dev = bcma_boot_dev ( bus ) ;
switch ( boot_dev ) {
case BCMA_BOOT_DEV_PARALLEL :
case BCMA_BOOT_DEV_SERIAL :
2014-10-28 15:30:23 +03:00
# ifdef CONFIG_BCM47XX
bcm47xx_nvram_init_from_mem ( BCMA_SOC_FLASH2 ,
BCMA_SOC_FLASH2_SZ ) ;
# endif
2014-09-03 12:35:13 +04:00
break ;
case BCMA_BOOT_DEV_NAND :
2014-10-28 15:30:23 +03:00
# ifdef CONFIG_BCM47XX
bcm47xx_nvram_init_from_mem ( BCMA_SOC_FLASH1 ,
BCMA_SOC_FLASH1_SZ ) ;
# endif
2014-09-03 12:35:13 +04:00
break ;
default :
break ;
}
2011-07-23 03:20:09 +04:00
}
2012-09-29 22:29:49 +04:00
void bcma_core_mips_early_init ( struct bcma_drv_mips * mcore )
{
2017-01-13 14:23:35 +03:00
struct bcma_bus * bus = mcore - > core - > bus ;
2012-09-29 22:29:49 +04:00
if ( mcore - > early_setup_done )
return ;
2017-01-13 14:23:35 +03:00
bcma_chipco_serial_init ( & bus - > drv_cc ) ;
2016-02-12 12:15:45 +03:00
bcma_core_mips_nvram_init ( mcore ) ;
2012-09-29 22:29:49 +04:00
mcore - > early_setup_done = true ;
}
2013-01-12 10:07:22 +04:00
static void bcma_fix_i2s_irqflag ( struct bcma_bus * bus )
{
struct bcma_device * cpu , * pcie , * i2s ;
/* Fixup the interrupts in 4716/4748 for i2s core (2010 Broadcom SDK)
* ( IRQ flags > 7 are ignored when setting the interrupt masks )
*/
if ( bus - > chipinfo . id ! = BCMA_CHIP_ID_BCM4716 & &
bus - > chipinfo . id ! = BCMA_CHIP_ID_BCM4748 )
return ;
cpu = bcma_find_core ( bus , BCMA_CORE_MIPS_74K ) ;
pcie = bcma_find_core ( bus , BCMA_CORE_PCIE ) ;
i2s = bcma_find_core ( bus , BCMA_CORE_I2S ) ;
if ( cpu & & pcie & & i2s & &
bcma_aread32 ( cpu , BCMA_MIPS_OOBSELINA74 ) = = 0x08060504 & &
bcma_aread32 ( pcie , BCMA_MIPS_OOBSELINA74 ) = = 0x08060504 & &
bcma_aread32 ( i2s , BCMA_MIPS_OOBSELOUTA30 ) = = 0x88 ) {
bcma_awrite32 ( cpu , BCMA_MIPS_OOBSELINA74 , 0x07060504 ) ;
bcma_awrite32 ( pcie , BCMA_MIPS_OOBSELINA74 , 0x07060504 ) ;
bcma_awrite32 ( i2s , BCMA_MIPS_OOBSELOUTA30 , 0x87 ) ;
bcma_debug ( bus ,
" Moved i2s interrupt to oob line 7 instead of 8 \n " ) ;
}
}
2011-07-23 03:20:09 +04:00
void bcma_core_mips_init ( struct bcma_drv_mips * mcore )
{
struct bcma_bus * bus ;
struct bcma_device * core ;
bus = mcore - > core - > bus ;
2012-09-29 22:29:49 +04:00
if ( mcore - > setup_done )
return ;
2013-01-04 03:51:22 +04:00
bcma_debug ( bus , " Initializing MIPS core... \n " ) ;
2011-07-23 03:20:09 +04:00
2012-09-29 22:29:49 +04:00
bcma_core_mips_early_init ( mcore ) ;
2013-01-12 10:07:22 +04:00
bcma_fix_i2s_irqflag ( bus ) ;
2013-01-04 03:51:21 +04:00
switch ( bus - > chipinfo . id ) {
case BCMA_CHIP_ID_BCM4716 :
case BCMA_CHIP_ID_BCM4748 :
bcma_core_mips_set_irq_name ( bus , 1 , BCMA_CORE_80211 , 0 ) ;
bcma_core_mips_set_irq_name ( bus , 2 , BCMA_CORE_MAC_GBIT , 0 ) ;
bcma_core_mips_set_irq_name ( bus , 3 , BCMA_CORE_USB20_HOST , 0 ) ;
bcma_core_mips_set_irq_name ( bus , 4 , BCMA_CORE_PCIE , 0 ) ;
bcma_core_mips_set_irq_name ( bus , 0 , BCMA_CORE_CHIPCOMMON , 0 ) ;
bcma_core_mips_set_irq_name ( bus , 0 , BCMA_CORE_I2S , 0 ) ;
break ;
case BCMA_CHIP_ID_BCM5356 :
case BCMA_CHIP_ID_BCM47162 :
case BCMA_CHIP_ID_BCM53572 :
bcma_core_mips_set_irq_name ( bus , 1 , BCMA_CORE_80211 , 0 ) ;
bcma_core_mips_set_irq_name ( bus , 2 , BCMA_CORE_MAC_GBIT , 0 ) ;
bcma_core_mips_set_irq_name ( bus , 0 , BCMA_CORE_CHIPCOMMON , 0 ) ;
break ;
case BCMA_CHIP_ID_BCM5357 :
case BCMA_CHIP_ID_BCM4749 :
bcma_core_mips_set_irq_name ( bus , 1 , BCMA_CORE_80211 , 0 ) ;
bcma_core_mips_set_irq_name ( bus , 2 , BCMA_CORE_MAC_GBIT , 0 ) ;
bcma_core_mips_set_irq_name ( bus , 3 , BCMA_CORE_USB20_HOST , 0 ) ;
bcma_core_mips_set_irq_name ( bus , 0 , BCMA_CORE_CHIPCOMMON , 0 ) ;
bcma_core_mips_set_irq_name ( bus , 0 , BCMA_CORE_I2S , 0 ) ;
break ;
case BCMA_CHIP_ID_BCM4706 :
bcma_core_mips_set_irq_name ( bus , 1 , BCMA_CORE_PCIE , 0 ) ;
bcma_core_mips_set_irq_name ( bus , 2 , BCMA_CORE_4706_MAC_GBIT ,
0 ) ;
bcma_core_mips_set_irq_name ( bus , 3 , BCMA_CORE_PCIE , 1 ) ;
bcma_core_mips_set_irq_name ( bus , 4 , BCMA_CORE_USB20_HOST , 0 ) ;
bcma_core_mips_set_irq_name ( bus , 0 , BCMA_CORE_4706_CHIPCOMMON ,
0 ) ;
break ;
default :
list_for_each_entry ( core , & bus - > cores , list ) {
2014-11-01 18:54:55 +03:00
core - > irq = bcma_core_irq ( core , 0 ) ;
2011-07-23 03:20:09 +04:00
}
2013-01-04 03:51:21 +04:00
bcma_err ( bus ,
" Unknown device (0x%x) found, can not configure IRQs \n " ,
bus - > chipinfo . id ) ;
2011-07-23 03:20:09 +04:00
}
2013-01-04 03:51:22 +04:00
bcma_debug ( bus , " IRQ reconfiguration done \n " ) ;
2011-07-23 03:20:09 +04:00
bcma_core_mips_dump_irq ( bus ) ;
mcore - > setup_done = true ;
}