2011-05-09 18:56:46 +02:00
/*
* Broadcom specific AMBA
* ChipCommon core driver
*
* Copyright 2005 , Broadcom Corporation
2011-07-04 20:50:05 +02:00
* Copyright 2006 , 2007 , Michael Buesch < m @ bues . ch >
2012-12-05 18:45:59 +01:00
* Copyright 2012 , Hauke Mehrtens < hauke @ hauke - m . de >
2011-05-09 18:56:46 +02:00
*
* Licensed under the GNU / GPL . See COPYING for details .
*/
# include "bcma_private.h"
2011-07-27 21:21:04 -04:00
# include <linux/export.h>
2011-05-09 18:56:46 +02:00
# include <linux/bcma/bcma.h>
static inline u32 bcma_cc_write32_masked ( struct bcma_drv_cc * cc , u16 offset ,
u32 mask , u32 value )
{
value & = mask ;
value | = bcma_cc_read32 ( cc , offset ) & ~ mask ;
bcma_cc_write32 ( cc , offset , value ) ;
return value ;
}
2012-12-05 18:45:59 +01:00
static u32 bcma_chipco_alp_clock ( struct bcma_drv_cc * cc )
{
if ( cc - > capabilities & BCMA_CC_CAP_PMU )
return bcma_pmu_alp_clock ( cc ) ;
return 20000000 ;
}
2012-12-05 18:46:00 +01:00
static u32 bcma_chipco_watchdog_get_max_timer ( struct bcma_drv_cc * cc )
{
struct bcma_bus * bus = cc - > core - > bus ;
u32 nb ;
if ( cc - > capabilities & BCMA_CC_CAP_PMU ) {
if ( bus - > chipinfo . id = = BCMA_CHIP_ID_BCM4706 )
nb = 32 ;
else if ( cc - > core - > id . rev < 26 )
nb = 16 ;
else
nb = ( cc - > core - > id . rev > = 37 ) ? 32 : 24 ;
} else {
nb = 28 ;
}
if ( nb = = 32 )
return 0xffffffff ;
else
return ( 1 < < nb ) - 1 ;
}
2012-09-29 20:29:49 +02:00
void bcma_core_chipcommon_early_init ( struct bcma_drv_cc * cc )
2011-05-09 18:56:46 +02:00
{
2012-09-29 20:29:49 +02:00
if ( cc - > early_setup_done )
2011-07-23 01:20:07 +02:00
return ;
2011-05-09 18:56:46 +02:00
if ( cc - > core - > id . rev > = 11 )
cc - > status = bcma_cc_read32 ( cc , BCMA_CC_CHIPSTAT ) ;
cc - > capabilities = bcma_cc_read32 ( cc , BCMA_CC_CAP ) ;
if ( cc - > core - > id . rev > = 35 )
cc - > capabilities_ext = bcma_cc_read32 ( cc , BCMA_CC_CAP_EXT ) ;
2012-09-29 20:29:49 +02:00
if ( cc - > capabilities & BCMA_CC_CAP_PMU )
bcma_pmu_early_init ( cc ) ;
cc - > early_setup_done = true ;
}
void bcma_core_chipcommon_init ( struct bcma_drv_cc * cc )
{
u32 leddc_on = 10 ;
u32 leddc_off = 90 ;
if ( cc - > setup_done )
return ;
bcma_core_chipcommon_early_init ( cc ) ;
2011-05-11 02:08:09 +02:00
if ( cc - > core - > id . rev > = 20 ) {
bcma_cc_write32 ( cc , BCMA_CC_GPIOPULLUP , 0 ) ;
bcma_cc_write32 ( cc , BCMA_CC_GPIOPULLDOWN , 0 ) ;
}
2011-05-09 18:56:46 +02:00
if ( cc - > capabilities & BCMA_CC_CAP_PMU )
bcma_pmu_init ( cc ) ;
if ( cc - > capabilities & BCMA_CC_CAP_PCTL )
2012-07-05 22:07:32 +02:00
bcma_err ( cc - > core - > bus , " Power control not implemented! \n " ) ;
2011-07-14 21:49:19 +02:00
if ( cc - > core - > id . rev > = 16 ) {
if ( cc - > core - > bus - > sprom . leddc_on_time & &
cc - > core - > bus - > sprom . leddc_off_time ) {
leddc_on = cc - > core - > bus - > sprom . leddc_on_time ;
leddc_off = cc - > core - > bus - > sprom . leddc_off_time ;
}
bcma_cc_write32 ( cc , BCMA_CC_GPIOTIMER ,
( ( leddc_on < < BCMA_CC_GPIOTIMER_ONTIME_SHIFT ) |
( leddc_off < < BCMA_CC_GPIOTIMER_OFFTIME_SHIFT ) ) ) ;
}
2011-07-23 01:20:07 +02:00
cc - > setup_done = true ;
2011-05-09 18:56:46 +02:00
}
/* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */
void bcma_chipco_watchdog_timer_set ( struct bcma_drv_cc * cc , u32 ticks )
{
2012-12-05 18:46:00 +01:00
u32 maxt ;
enum bcma_clkmode clkmode ;
maxt = bcma_chipco_watchdog_get_max_timer ( cc ) ;
if ( cc - > capabilities & BCMA_CC_CAP_PMU ) {
if ( ticks = = 1 )
ticks = 2 ;
else if ( ticks > maxt )
ticks = maxt ;
bcma_cc_write32 ( cc , BCMA_CC_PMU_WATCHDOG , ticks ) ;
} else {
clkmode = ticks ? BCMA_CLKMODE_FAST : BCMA_CLKMODE_DYNAMIC ;
bcma_core_set_clockmode ( cc - > core , clkmode ) ;
if ( ticks > maxt )
ticks = maxt ;
/* instant NMI */
bcma_cc_write32 ( cc , BCMA_CC_WATCHDOG , ticks ) ;
}
2011-05-09 18:56:46 +02:00
}
void bcma_chipco_irq_mask ( struct bcma_drv_cc * cc , u32 mask , u32 value )
{
bcma_cc_write32_masked ( cc , BCMA_CC_IRQMASK , mask , value ) ;
}
u32 bcma_chipco_irq_status ( struct bcma_drv_cc * cc , u32 mask )
{
return bcma_cc_read32 ( cc , BCMA_CC_IRQSTAT ) & mask ;
}
u32 bcma_chipco_gpio_in ( struct bcma_drv_cc * cc , u32 mask )
{
return bcma_cc_read32 ( cc , BCMA_CC_GPIOIN ) & mask ;
}
u32 bcma_chipco_gpio_out ( struct bcma_drv_cc * cc , u32 mask , u32 value )
{
return bcma_cc_write32_masked ( cc , BCMA_CC_GPIOOUT , mask , value ) ;
}
u32 bcma_chipco_gpio_outen ( struct bcma_drv_cc * cc , u32 mask , u32 value )
{
return bcma_cc_write32_masked ( cc , BCMA_CC_GPIOOUTEN , mask , value ) ;
}
u32 bcma_chipco_gpio_control ( struct bcma_drv_cc * cc , u32 mask , u32 value )
{
return bcma_cc_write32_masked ( cc , BCMA_CC_GPIOCTL , mask , value ) ;
}
EXPORT_SYMBOL_GPL ( bcma_chipco_gpio_control ) ;
u32 bcma_chipco_gpio_intmask ( struct bcma_drv_cc * cc , u32 mask , u32 value )
{
return bcma_cc_write32_masked ( cc , BCMA_CC_GPIOIRQ , mask , value ) ;
}
u32 bcma_chipco_gpio_polarity ( struct bcma_drv_cc * cc , u32 mask , u32 value )
{
return bcma_cc_write32_masked ( cc , BCMA_CC_GPIOPOL , mask , value ) ;
}
2011-07-23 01:20:10 +02:00
# ifdef CONFIG_BCMA_DRIVER_MIPS
void bcma_chipco_serial_init ( struct bcma_drv_cc * cc )
{
unsigned int irq ;
u32 baud_base ;
u32 i ;
unsigned int ccrev = cc - > core - > id . rev ;
struct bcma_serial_port * ports = cc - > serial_ports ;
if ( ccrev > = 11 & & ccrev ! = 15 ) {
2012-12-05 18:45:59 +01:00
baud_base = bcma_chipco_alp_clock ( cc ) ;
2011-07-23 01:20:10 +02:00
if ( ccrev > = 21 ) {
/* Turn off UART clock before switching clocksource. */
bcma_cc_write32 ( cc , BCMA_CC_CORECTL ,
bcma_cc_read32 ( cc , BCMA_CC_CORECTL )
& ~ BCMA_CC_CORECTL_UARTCLKEN ) ;
}
/* Set the override bit so we don't divide it */
bcma_cc_write32 ( cc , BCMA_CC_CORECTL ,
bcma_cc_read32 ( cc , BCMA_CC_CORECTL )
| BCMA_CC_CORECTL_UARTCLK0 ) ;
if ( ccrev > = 21 ) {
/* Re-enable the UART clock. */
bcma_cc_write32 ( cc , BCMA_CC_CORECTL ,
bcma_cc_read32 ( cc , BCMA_CC_CORECTL )
| BCMA_CC_CORECTL_UARTCLKEN ) ;
}
} else {
2012-07-09 19:34:59 +02:00
bcma_err ( cc - > core - > bus , " serial not supported on this device ccrev: 0x%x \n " , ccrev ) ;
2011-07-23 01:20:10 +02:00
return ;
}
irq = bcma_core_mips_irq ( cc - > core ) ;
/* Determine the registers of the UARTs */
cc - > nr_serial_ports = ( cc - > capabilities & BCMA_CC_CAP_NRUART ) ;
for ( i = 0 ; i < cc - > nr_serial_ports ; i + + ) {
ports [ i ] . regs = cc - > core - > io_addr + BCMA_CC_UART0_DATA +
( i * 256 ) ;
ports [ i ] . irq = irq ;
ports [ i ] . baud_base = baud_base ;
ports [ i ] . reg_shift = 0 ;
}
}
# endif /* CONFIG_BCMA_DRIVER_MIPS */