2012-03-14 13:36:10 +04:00
/*
* Atheros AR71xx PCI host controller driver
*
* Copyright ( C ) 2008 - 2011 Gabor Juhos < juhosg @ openwrt . org >
* Copyright ( C ) 2008 Imre Kaloz < kaloz @ openwrt . org >
*
* Parts of this file are based on Atheros ' 2.6 .15 BSP
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation .
*/
# include <linux/resource.h>
# include <linux/types.h>
# include <linux/delay.h>
# include <linux/bitops.h>
# include <linux/pci.h>
# include <linux/pci_regs.h>
# include <linux/interrupt.h>
2016-08-21 22:58:16 +03:00
# include <linux/init.h>
2013-02-02 15:40:43 +04:00
# include <linux/platform_device.h>
2012-03-14 13:36:10 +04:00
# include <asm/mach-ath79/ar71xx_regs.h>
# include <asm/mach-ath79/ath79.h>
# define AR71XX_PCI_REG_CRP_AD_CBE 0x00
# define AR71XX_PCI_REG_CRP_WRDATA 0x04
# define AR71XX_PCI_REG_CRP_RDDATA 0x08
# define AR71XX_PCI_REG_CFG_AD 0x0c
# define AR71XX_PCI_REG_CFG_CBE 0x10
# define AR71XX_PCI_REG_CFG_WRDATA 0x14
# define AR71XX_PCI_REG_CFG_RDDATA 0x18
# define AR71XX_PCI_REG_PCI_ERR 0x1c
# define AR71XX_PCI_REG_PCI_ERR_ADDR 0x20
# define AR71XX_PCI_REG_AHB_ERR 0x24
# define AR71XX_PCI_REG_AHB_ERR_ADDR 0x28
# define AR71XX_PCI_CRP_CMD_WRITE 0x00010000
# define AR71XX_PCI_CRP_CMD_READ 0x00000000
# define AR71XX_PCI_CFG_CMD_READ 0x0000000a
# define AR71XX_PCI_CFG_CMD_WRITE 0x0000000b
# define AR71XX_PCI_INT_CORE BIT(4)
# define AR71XX_PCI_INT_DEV2 BIT(2)
# define AR71XX_PCI_INT_DEV1 BIT(1)
# define AR71XX_PCI_INT_DEV0 BIT(0)
# define AR71XX_PCI_IRQ_COUNT 5
2013-02-07 23:28:14 +04:00
struct ar71xx_pci_controller {
void __iomem * cfg_base ;
int irq ;
2013-02-07 23:29:38 +04:00
int irq_base ;
2013-02-07 23:28:14 +04:00
struct pci_controller pci_ctrl ;
2013-02-07 23:28:15 +04:00
struct resource io_res ;
struct resource mem_res ;
2013-02-07 23:28:14 +04:00
} ;
2012-03-14 13:36:10 +04:00
/* Byte lane enable bits */
static const u8 ar71xx_pci_ble_table [ 4 ] [ 4 ] = {
{ 0x0 , 0xf , 0xf , 0xf } ,
{ 0xe , 0xd , 0xb , 0x7 } ,
{ 0xc , 0xf , 0x3 , 0xf } ,
{ 0xf , 0xf , 0xf , 0xf } ,
} ;
static const u32 ar71xx_pci_read_mask [ 8 ] = {
0 , 0xff , 0xffff , 0 , 0xffffffff , 0 , 0 , 0
} ;
static inline u32 ar71xx_pci_get_ble ( int where , int size , int local )
{
u32 t ;
t = ar71xx_pci_ble_table [ size & 3 ] [ where & 3 ] ;
BUG_ON ( t = = 0xf ) ;
t < < = ( local ) ? 20 : 4 ;
return t ;
}
static inline u32 ar71xx_pci_bus_addr ( struct pci_bus * bus , unsigned int devfn ,
int where )
{
u32 ret ;
if ( ! bus - > number ) {
/* type 0 */
ret = ( 1 < < PCI_SLOT ( devfn ) ) | ( PCI_FUNC ( devfn ) < < 8 ) |
( where & ~ 3 ) ;
} else {
/* type 1 */
ret = ( bus - > number < < 16 ) | ( PCI_SLOT ( devfn ) < < 11 ) |
( PCI_FUNC ( devfn ) < < 8 ) | ( where & ~ 3 ) | 1 ;
}
return ret ;
}
2013-02-07 23:28:14 +04:00
static inline struct ar71xx_pci_controller *
pci_bus_to_ar71xx_controller ( struct pci_bus * bus )
2012-03-14 13:36:10 +04:00
{
2013-02-07 23:28:14 +04:00
struct pci_controller * hose ;
hose = ( struct pci_controller * ) bus - > sysdata ;
return container_of ( hose , struct ar71xx_pci_controller , pci_ctrl ) ;
}
static int ar71xx_pci_check_error ( struct ar71xx_pci_controller * apc , int quiet )
{
void __iomem * base = apc - > cfg_base ;
2012-03-14 13:36:10 +04:00
u32 pci_err ;
u32 ahb_err ;
pci_err = __raw_readl ( base + AR71XX_PCI_REG_PCI_ERR ) & 3 ;
if ( pci_err ) {
if ( ! quiet ) {
u32 addr ;
addr = __raw_readl ( base + AR71XX_PCI_REG_PCI_ERR_ADDR ) ;
pr_crit ( " ar71xx: %s bus error %d at addr 0x%x \n " ,
" PCI " , pci_err , addr ) ;
}
/* clear PCI error status */
__raw_writel ( pci_err , base + AR71XX_PCI_REG_PCI_ERR ) ;
}
ahb_err = __raw_readl ( base + AR71XX_PCI_REG_AHB_ERR ) & 1 ;
if ( ahb_err ) {
if ( ! quiet ) {
u32 addr ;
addr = __raw_readl ( base + AR71XX_PCI_REG_AHB_ERR_ADDR ) ;
pr_crit ( " ar71xx: %s bus error %d at addr 0x%x \n " ,
" AHB " , ahb_err , addr ) ;
}
/* clear AHB error status */
__raw_writel ( ahb_err , base + AR71XX_PCI_REG_AHB_ERR ) ;
}
return ! ! ( ahb_err | pci_err ) ;
}
2013-02-07 23:28:14 +04:00
static inline void ar71xx_pci_local_write ( struct ar71xx_pci_controller * apc ,
int where , int size , u32 value )
2012-03-14 13:36:10 +04:00
{
2013-02-07 23:28:14 +04:00
void __iomem * base = apc - > cfg_base ;
2012-03-14 13:36:10 +04:00
u32 ad_cbe ;
value = value < < ( 8 * ( where & 3 ) ) ;
ad_cbe = AR71XX_PCI_CRP_CMD_WRITE | ( where & ~ 3 ) ;
ad_cbe | = ar71xx_pci_get_ble ( where , size , 1 ) ;
__raw_writel ( ad_cbe , base + AR71XX_PCI_REG_CRP_AD_CBE ) ;
__raw_writel ( value , base + AR71XX_PCI_REG_CRP_WRDATA ) ;
}
static inline int ar71xx_pci_set_cfgaddr ( struct pci_bus * bus ,
unsigned int devfn ,
int where , int size , u32 cmd )
{
2013-02-07 23:28:14 +04:00
struct ar71xx_pci_controller * apc = pci_bus_to_ar71xx_controller ( bus ) ;
void __iomem * base = apc - > cfg_base ;
2012-03-14 13:36:10 +04:00
u32 addr ;
addr = ar71xx_pci_bus_addr ( bus , devfn , where ) ;
__raw_writel ( addr , base + AR71XX_PCI_REG_CFG_AD ) ;
__raw_writel ( cmd | ar71xx_pci_get_ble ( where , size , 0 ) ,
base + AR71XX_PCI_REG_CFG_CBE ) ;
2013-02-07 23:28:14 +04:00
return ar71xx_pci_check_error ( apc , 1 ) ;
2012-03-14 13:36:10 +04:00
}
static int ar71xx_pci_read_config ( struct pci_bus * bus , unsigned int devfn ,
int where , int size , u32 * value )
{
2013-02-07 23:28:14 +04:00
struct ar71xx_pci_controller * apc = pci_bus_to_ar71xx_controller ( bus ) ;
void __iomem * base = apc - > cfg_base ;
2012-03-14 13:36:10 +04:00
u32 data ;
int err ;
int ret ;
ret = PCIBIOS_SUCCESSFUL ;
data = ~ 0 ;
err = ar71xx_pci_set_cfgaddr ( bus , devfn , where , size ,
AR71XX_PCI_CFG_CMD_READ ) ;
if ( err )
ret = PCIBIOS_DEVICE_NOT_FOUND ;
else
data = __raw_readl ( base + AR71XX_PCI_REG_CFG_RDDATA ) ;
* value = ( data > > ( 8 * ( where & 3 ) ) ) & ar71xx_pci_read_mask [ size & 7 ] ;
return ret ;
}
static int ar71xx_pci_write_config ( struct pci_bus * bus , unsigned int devfn ,
int where , int size , u32 value )
{
2013-02-07 23:28:14 +04:00
struct ar71xx_pci_controller * apc = pci_bus_to_ar71xx_controller ( bus ) ;
void __iomem * base = apc - > cfg_base ;
2012-03-14 13:36:10 +04:00
int err ;
int ret ;
value = value < < ( 8 * ( where & 3 ) ) ;
ret = PCIBIOS_SUCCESSFUL ;
err = ar71xx_pci_set_cfgaddr ( bus , devfn , where , size ,
AR71XX_PCI_CFG_CMD_WRITE ) ;
if ( err )
ret = PCIBIOS_DEVICE_NOT_FOUND ;
else
__raw_writel ( value , base + AR71XX_PCI_REG_CFG_WRDATA ) ;
return ret ;
}
static struct pci_ops ar71xx_pci_ops = {
. read = ar71xx_pci_read_config ,
. write = ar71xx_pci_write_config ,
} ;
2015-09-14 11:42:37 +03:00
static void ar71xx_pci_irq_handler ( struct irq_desc * desc )
2012-03-14 13:36:10 +04:00
{
2013-02-07 23:29:38 +04:00
struct ar71xx_pci_controller * apc ;
2012-03-14 13:36:10 +04:00
void __iomem * base = ath79_reset_base ;
u32 pending ;
2015-05-20 12:59:51 +03:00
apc = irq_desc_get_handler_data ( desc ) ;
2013-02-07 23:29:38 +04:00
2012-03-14 13:36:10 +04:00
pending = __raw_readl ( base + AR71XX_RESET_REG_PCI_INT_STATUS ) &
__raw_readl ( base + AR71XX_RESET_REG_PCI_INT_ENABLE ) ;
if ( pending & AR71XX_PCI_INT_DEV0 )
2013-02-07 23:29:38 +04:00
generic_handle_irq ( apc - > irq_base + 0 ) ;
2012-03-14 13:36:10 +04:00
else if ( pending & AR71XX_PCI_INT_DEV1 )
2013-02-07 23:29:38 +04:00
generic_handle_irq ( apc - > irq_base + 1 ) ;
2012-03-14 13:36:10 +04:00
else if ( pending & AR71XX_PCI_INT_DEV2 )
2013-02-07 23:29:38 +04:00
generic_handle_irq ( apc - > irq_base + 2 ) ;
2012-03-14 13:36:10 +04:00
else if ( pending & AR71XX_PCI_INT_CORE )
2013-02-07 23:29:38 +04:00
generic_handle_irq ( apc - > irq_base + 4 ) ;
2012-03-14 13:36:10 +04:00
else
spurious_interrupt ( ) ;
}
static void ar71xx_pci_irq_unmask ( struct irq_data * d )
{
2013-02-07 23:29:38 +04:00
struct ar71xx_pci_controller * apc ;
unsigned int irq ;
2012-03-14 13:36:10 +04:00
void __iomem * base = ath79_reset_base ;
u32 t ;
2013-02-07 23:29:38 +04:00
apc = irq_data_get_irq_chip_data ( d ) ;
irq = d - > irq - apc - > irq_base ;
2012-03-14 13:36:10 +04:00
t = __raw_readl ( base + AR71XX_RESET_REG_PCI_INT_ENABLE ) ;
__raw_writel ( t | ( 1 < < irq ) , base + AR71XX_RESET_REG_PCI_INT_ENABLE ) ;
/* flush write */
__raw_readl ( base + AR71XX_RESET_REG_PCI_INT_ENABLE ) ;
}
static void ar71xx_pci_irq_mask ( struct irq_data * d )
{
2013-02-07 23:29:38 +04:00
struct ar71xx_pci_controller * apc ;
unsigned int irq ;
2012-03-14 13:36:10 +04:00
void __iomem * base = ath79_reset_base ;
u32 t ;
2013-02-07 23:29:38 +04:00
apc = irq_data_get_irq_chip_data ( d ) ;
irq = d - > irq - apc - > irq_base ;
2012-03-14 13:36:10 +04:00
t = __raw_readl ( base + AR71XX_RESET_REG_PCI_INT_ENABLE ) ;
__raw_writel ( t & ~ ( 1 < < irq ) , base + AR71XX_RESET_REG_PCI_INT_ENABLE ) ;
/* flush write */
__raw_readl ( base + AR71XX_RESET_REG_PCI_INT_ENABLE ) ;
}
static struct irq_chip ar71xx_pci_irq_chip = {
. name = " AR71XX PCI " ,
. irq_mask = ar71xx_pci_irq_mask ,
. irq_unmask = ar71xx_pci_irq_unmask ,
. irq_mask_ack = ar71xx_pci_irq_mask ,
} ;
2013-02-07 23:28:14 +04:00
static void ar71xx_pci_irq_init ( struct ar71xx_pci_controller * apc )
2012-03-14 13:36:10 +04:00
{
void __iomem * base = ath79_reset_base ;
int i ;
__raw_writel ( 0 , base + AR71XX_RESET_REG_PCI_INT_ENABLE ) ;
__raw_writel ( 0 , base + AR71XX_RESET_REG_PCI_INT_STATUS ) ;
BUILD_BUG_ON ( ATH79_PCI_IRQ_COUNT < AR71XX_PCI_IRQ_COUNT ) ;
2013-02-07 23:29:38 +04:00
apc - > irq_base = ATH79_PCI_IRQ_BASE ;
for ( i = apc - > irq_base ;
i < apc - > irq_base + AR71XX_PCI_IRQ_COUNT ; i + + ) {
2012-03-14 13:36:10 +04:00
irq_set_chip_and_handler ( i , & ar71xx_pci_irq_chip ,
handle_level_irq ) ;
2013-02-07 23:29:38 +04:00
irq_set_chip_data ( i , apc ) ;
}
2012-03-14 13:36:10 +04:00
2015-07-13 23:45:55 +03:00
irq_set_chained_handler_and_data ( apc - > irq , ar71xx_pci_irq_handler ,
apc ) ;
2012-03-14 13:36:10 +04:00
}
2013-02-02 15:40:43 +04:00
static void ar71xx_pci_reset ( void )
2012-03-14 13:36:10 +04:00
{
ath79_device_reset_set ( AR71XX_RESET_PCI_BUS | AR71XX_RESET_PCI_CORE ) ;
mdelay ( 100 ) ;
ath79_device_reset_clear ( AR71XX_RESET_PCI_BUS | AR71XX_RESET_PCI_CORE ) ;
mdelay ( 100 ) ;
2015-04-19 15:30:03 +03:00
ath79_ddr_set_pci_windows ( ) ;
2012-03-14 13:36:10 +04:00
mdelay ( 100 ) ;
}
2013-02-02 15:40:43 +04:00
static int ar71xx_pci_probe ( struct platform_device * pdev )
{
2013-02-07 23:28:14 +04:00
struct ar71xx_pci_controller * apc ;
2013-02-02 15:40:43 +04:00
struct resource * res ;
u32 t ;
2013-02-07 23:28:14 +04:00
apc = devm_kzalloc ( & pdev - > dev , sizeof ( struct ar71xx_pci_controller ) ,
GFP_KERNEL ) ;
if ( ! apc )
return - ENOMEM ;
2013-02-02 15:40:43 +04:00
res = platform_get_resource_byname ( pdev , IORESOURCE_MEM , " cfg_base " ) ;
2013-03-12 14:30:05 +04:00
apc - > cfg_base = devm_ioremap_resource ( & pdev - > dev , res ) ;
if ( IS_ERR ( apc - > cfg_base ) )
return PTR_ERR ( apc - > cfg_base ) ;
2013-02-02 15:40:43 +04:00
2013-02-07 23:28:14 +04:00
apc - > irq = platform_get_irq ( pdev , 0 ) ;
if ( apc - > irq < 0 )
2013-02-02 15:40:43 +04:00
return - EINVAL ;
2013-02-07 23:28:15 +04:00
res = platform_get_resource_byname ( pdev , IORESOURCE_IO , " io_base " ) ;
if ( ! res )
return - EINVAL ;
apc - > io_res . parent = res ;
apc - > io_res . name = " PCI IO space " ;
apc - > io_res . start = res - > start ;
apc - > io_res . end = res - > end ;
apc - > io_res . flags = IORESOURCE_IO ;
res = platform_get_resource_byname ( pdev , IORESOURCE_MEM , " mem_base " ) ;
if ( ! res )
return - EINVAL ;
apc - > mem_res . parent = res ;
apc - > mem_res . name = " PCI memory space " ;
apc - > mem_res . start = res - > start ;
apc - > mem_res . end = res - > end ;
apc - > mem_res . flags = IORESOURCE_MEM ;
2013-02-02 15:40:43 +04:00
ar71xx_pci_reset ( ) ;
/* setup COMMAND register */
t = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE
| PCI_COMMAND_PARITY | PCI_COMMAND_SERR | PCI_COMMAND_FAST_BACK ;
2013-02-07 23:28:14 +04:00
ar71xx_pci_local_write ( apc , PCI_COMMAND , 4 , t ) ;
2013-02-02 15:40:43 +04:00
/* clear bus errors */
2013-02-07 23:28:14 +04:00
ar71xx_pci_check_error ( apc , 1 ) ;
ar71xx_pci_irq_init ( apc ) ;
2013-02-02 15:40:43 +04:00
2013-02-07 23:28:14 +04:00
apc - > pci_ctrl . pci_ops = & ar71xx_pci_ops ;
2013-02-07 23:28:15 +04:00
apc - > pci_ctrl . mem_resource = & apc - > mem_res ;
apc - > pci_ctrl . io_resource = & apc - > io_res ;
2013-02-02 15:40:43 +04:00
2013-02-07 23:28:14 +04:00
register_pci_controller ( & apc - > pci_ctrl ) ;
2013-02-02 15:40:43 +04:00
return 0 ;
}
static struct platform_driver ar71xx_pci_driver = {
. probe = ar71xx_pci_probe ,
. driver = {
. name = " ar71xx-pci " ,
} ,
} ;
static int __init ar71xx_pci_init ( void )
{
return platform_driver_register ( & ar71xx_pci_driver ) ;
}
postcore_initcall ( ar71xx_pci_init ) ;