/*
* Freescale i . MX6 PCI Express Root - Complex driver
*
* Copyright ( C ) 2013 Marek Vasut < marex @ denx . de >
*
* Based on upstream Linux kernel driver :
* pci - imx6 . c : Sean Cross < xobs @ kosagi . com >
* pcie - designware . c : Jingoo Han < jg1 . han @ samsung . com >
*
* SPDX - License - Identifier : GPL - 2.0
*/
# include <common.h>
# include <pci.h>
# include <asm/arch/clock.h>
# include <asm/arch/iomux.h>
# include <asm/arch/crm_regs.h>
# include <asm/gpio.h>
# include <asm/io.h>
# include <linux/sizes.h>
# include <errno.h>
# include <asm/arch/sys_proto.h>
# define PCI_ACCESS_READ 0
# define PCI_ACCESS_WRITE 1
# ifdef CONFIG_MX6SX
# define MX6_DBI_ADDR 0x08ffc000
# define MX6_IO_ADDR 0x08000000
# define MX6_MEM_ADDR 0x08100000
# define MX6_ROOT_ADDR 0x08f00000
# else
# define MX6_DBI_ADDR 0x01ffc000
# define MX6_IO_ADDR 0x01000000
# define MX6_MEM_ADDR 0x01100000
# define MX6_ROOT_ADDR 0x01f00000
# endif
# define MX6_DBI_SIZE 0x4000
# define MX6_IO_SIZE 0x100000
# define MX6_MEM_SIZE 0xe00000
# define MX6_ROOT_SIZE 0xfc000
/* PCIe Port Logic registers (memory-mapped) */
# define PL_OFFSET 0x700
# define PCIE_PHY_DEBUG_R0 (PL_OFFSET + 0x28)
# define PCIE_PHY_DEBUG_R1 (PL_OFFSET + 0x2c)
# define PCIE_PHY_DEBUG_R1_LINK_UP (1 << 4)
# define PCIE_PHY_DEBUG_R1_LINK_IN_TRAINING (1 << 29)
# define PCIE_PHY_CTRL (PL_OFFSET + 0x114)
# define PCIE_PHY_CTRL_DATA_LOC 0
# define PCIE_PHY_CTRL_CAP_ADR_LOC 16
# define PCIE_PHY_CTRL_CAP_DAT_LOC 17
# define PCIE_PHY_CTRL_WR_LOC 18
# define PCIE_PHY_CTRL_RD_LOC 19
# define PCIE_PHY_STAT (PL_OFFSET + 0x110)
# define PCIE_PHY_STAT_DATA_LOC 0
# define PCIE_PHY_STAT_ACK_LOC 16
/* PHY registers (not memory-mapped) */
# define PCIE_PHY_RX_ASIC_OUT 0x100D
# define PHY_RX_OVRD_IN_LO 0x1005
# define PHY_RX_OVRD_IN_LO_RX_DATA_EN (1 << 5)
# define PHY_RX_OVRD_IN_LO_RX_PLL_EN (1 << 3)
# define PCIE_PHY_PUP_REQ (1 << 7)
/* iATU registers */
# define PCIE_ATU_VIEWPORT 0x900
# define PCIE_ATU_REGION_INBOUND (0x1 << 31)
# define PCIE_ATU_REGION_OUTBOUND (0x0 << 31)
# define PCIE_ATU_REGION_INDEX1 (0x1 << 0)
# define PCIE_ATU_REGION_INDEX0 (0x0 << 0)
# define PCIE_ATU_CR1 0x904
# define PCIE_ATU_TYPE_MEM (0x0 << 0)
# define PCIE_ATU_TYPE_IO (0x2 << 0)
# define PCIE_ATU_TYPE_CFG0 (0x4 << 0)
# define PCIE_ATU_TYPE_CFG1 (0x5 << 0)
# define PCIE_ATU_CR2 0x908
# define PCIE_ATU_ENABLE (0x1 << 31)
# define PCIE_ATU_BAR_MODE_ENABLE (0x1 << 30)
# define PCIE_ATU_LOWER_BASE 0x90C
# define PCIE_ATU_UPPER_BASE 0x910
# define PCIE_ATU_LIMIT 0x914
# define PCIE_ATU_LOWER_TARGET 0x918
# define PCIE_ATU_BUS(x) (((x) & 0xff) << 24)
# define PCIE_ATU_DEV(x) (((x) & 0x1f) << 19)
# define PCIE_ATU_FUNC(x) (((x) & 0x7) << 16)
# define PCIE_ATU_UPPER_TARGET 0x91C
/*
* PHY access functions
*/
static int pcie_phy_poll_ack ( void __iomem * dbi_base , int exp_val )
{
u32 val ;
u32 max_iterations = 10 ;
u32 wait_counter = 0 ;
do {
val = readl ( dbi_base + PCIE_PHY_STAT ) ;
val = ( val > > PCIE_PHY_STAT_ACK_LOC ) & 0x1 ;
wait_counter + + ;
if ( val = = exp_val )
return 0 ;
udelay ( 1 ) ;
} while ( wait_counter < max_iterations ) ;
return - ETIMEDOUT ;
}
static int pcie_phy_wait_ack ( void __iomem * dbi_base , int addr )
{
u32 val ;
int ret ;
val = addr < < PCIE_PHY_CTRL_DATA_LOC ;
writel ( val , dbi_base + PCIE_PHY_CTRL ) ;
val | = ( 0x1 < < PCIE_PHY_CTRL_CAP_ADR_LOC ) ;
writel ( val , dbi_base + PCIE_PHY_CTRL ) ;
ret = pcie_phy_poll_ack ( dbi_base , 1 ) ;
if ( ret )
return ret ;
val = addr < < PCIE_PHY_CTRL_DATA_LOC ;
writel ( val , dbi_base + PCIE_PHY_CTRL ) ;
ret = pcie_phy_poll_ack ( dbi_base , 0 ) ;
if ( ret )
return ret ;
return 0 ;
}
/* Read from the 16-bit PCIe PHY control registers (not memory-mapped) */
static int pcie_phy_read ( void __iomem * dbi_base , int addr , int * data )
{
u32 val , phy_ctl ;
int ret ;
ret = pcie_phy_wait_ack ( dbi_base , addr ) ;
if ( ret )
return ret ;
/* assert Read signal */
phy_ctl = 0x1 < < PCIE_PHY_CTRL_RD_LOC ;
writel ( phy_ctl , dbi_base + PCIE_PHY_CTRL ) ;
ret = pcie_phy_poll_ack ( dbi_base , 1 ) ;
if ( ret )
return ret ;
val = readl ( dbi_base + PCIE_PHY_STAT ) ;
* data = val & 0xffff ;
/* deassert Read signal */
writel ( 0x00 , dbi_base + PCIE_PHY_CTRL ) ;
ret = pcie_phy_poll_ack ( dbi_base , 0 ) ;
if ( ret )
return ret ;
return 0 ;
}
static int pcie_phy_write ( void __iomem * dbi_base , int addr , int data )
{
u32 var ;
int ret ;
/* write addr */
/* cap addr */
ret = pcie_phy_wait_ack ( dbi_base , addr ) ;
if ( ret )
return ret ;
var = data < < PCIE_PHY_CTRL_DATA_LOC ;
writel ( var , dbi_base + PCIE_PHY_CTRL ) ;
/* capture data */
var | = ( 0x1 < < PCIE_PHY_CTRL_CAP_DAT_LOC ) ;
writel ( var , dbi_base + PCIE_PHY_CTRL ) ;
ret = pcie_phy_poll_ack ( dbi_base , 1 ) ;
if ( ret )
return ret ;
/* deassert cap data */
var = data < < PCIE_PHY_CTRL_DATA_LOC ;
writel ( var , dbi_base + PCIE_PHY_CTRL ) ;
/* wait for ack de-assertion */
ret = pcie_phy_poll_ack ( dbi_base , 0 ) ;
if ( ret )
return ret ;
/* assert wr signal */
var = 0x1 < < PCIE_PHY_CTRL_WR_LOC ;
writel ( var , dbi_base + PCIE_PHY_CTRL ) ;
/* wait for ack */
ret = pcie_phy_poll_ack ( dbi_base , 1 ) ;
if ( ret )
return ret ;
/* deassert wr signal */
var = data < < PCIE_PHY_CTRL_DATA_LOC ;
writel ( var , dbi_base + PCIE_PHY_CTRL ) ;
/* wait for ack de-assertion */
ret = pcie_phy_poll_ack ( dbi_base , 0 ) ;
if ( ret )
return ret ;
writel ( 0x0 , dbi_base + PCIE_PHY_CTRL ) ;
return 0 ;
}
static int imx6_pcie_link_up ( void )
{
u32 rc , ltssm ;
int rx_valid , temp ;
/* link is debug bit 36, debug register 1 starts at bit 32 */
rc = readl ( MX6_DBI_ADDR + PCIE_PHY_DEBUG_R1 ) ;
if ( ( rc & PCIE_PHY_DEBUG_R1_LINK_UP ) & &
! ( rc & PCIE_PHY_DEBUG_R1_LINK_IN_TRAINING ) )
return - EAGAIN ;
/*
* From L0 , initiate MAC entry to gen2 if EP / RC supports gen2 .
* Wait 2 ms ( LTSSM timeout is 24 ms , PHY lock is ~ 5u s in gen2 ) .
* If ( MAC / LTSSM . state = = Recovery . RcvrLock )
* & & ( PHY / rx_valid = = 0 ) then pulse PHY / rx_reset . Transition
* to gen2 is stuck
*/
pcie_phy_read ( ( void * ) MX6_DBI_ADDR , PCIE_PHY_RX_ASIC_OUT , & rx_valid ) ;
ltssm = readl ( MX6_DBI_ADDR + PCIE_PHY_DEBUG_R0 ) & 0x3F ;
if ( rx_valid & 0x01 )
return 0 ;
if ( ltssm ! = 0x0d )
return 0 ;
printf ( " transition to gen2 is stuck, reset PHY! \n " ) ;
pcie_phy_read ( ( void * ) MX6_DBI_ADDR , PHY_RX_OVRD_IN_LO , & temp ) ;
temp | = ( PHY_RX_OVRD_IN_LO_RX_DATA_EN | PHY_RX_OVRD_IN_LO_RX_PLL_EN ) ;
pcie_phy_write ( ( void * ) MX6_DBI_ADDR , PHY_RX_OVRD_IN_LO , temp ) ;
udelay ( 3000 ) ;
pcie_phy_read ( ( void * ) MX6_DBI_ADDR , PHY_RX_OVRD_IN_LO , & temp ) ;
temp & = ~ ( PHY_RX_OVRD_IN_LO_RX_DATA_EN | PHY_RX_OVRD_IN_LO_RX_PLL_EN ) ;
pcie_phy_write ( ( void * ) MX6_DBI_ADDR , PHY_RX_OVRD_IN_LO , temp ) ;
return 0 ;
}
/*
* iATU region setup
*/
static int imx_pcie_regions_setup ( void )
{
/*
* i . MX6 defines 16 MB in the AXI address map for PCIe .
*
* That address space excepted the pcie registers is
* split and defined into different regions by iATU ,
* with sizes and offsets as follows :
*
* 0x0100 _0000 - - - 0x010F _FFFF 1 MB IORESOURCE_IO
* 0x0110 _0000 - - - 0x01EF _FFFF 14 MB IORESOURCE_MEM
* 0x01F0 _0000 - - - 0x01FF _FFFF 1 MB Cfg + Registers
*/
/* CMD reg:I/O space, MEM space, and Bus Master Enable */
setbits_le32 ( MX6_DBI_ADDR | PCI_COMMAND ,
PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER ) ;
/* Set the CLASS_REV of RC CFG header to PCI_CLASS_BRIDGE_PCI */
setbits_le32 ( MX6_DBI_ADDR + PCI_CLASS_REVISION ,
PCI_CLASS_BRIDGE_PCI < < 16 ) ;
/* Region #0 is used for Outbound CFG space access. */
writel ( 0 , MX6_DBI_ADDR + PCIE_ATU_VIEWPORT ) ;
writel ( MX6_ROOT_ADDR , MX6_DBI_ADDR + PCIE_ATU_LOWER_BASE ) ;
writel ( 0 , MX6_DBI_ADDR + PCIE_ATU_UPPER_BASE ) ;
writel ( MX6_ROOT_ADDR + MX6_ROOT_SIZE , MX6_DBI_ADDR + PCIE_ATU_LIMIT ) ;
writel ( 0 , MX6_DBI_ADDR + PCIE_ATU_LOWER_TARGET ) ;
writel ( 0 , MX6_DBI_ADDR + PCIE_ATU_UPPER_TARGET ) ;
writel ( PCIE_ATU_TYPE_CFG0 , MX6_DBI_ADDR + PCIE_ATU_CR1 ) ;
writel ( PCIE_ATU_ENABLE , MX6_DBI_ADDR + PCIE_ATU_CR2 ) ;
return 0 ;
}
/*
* PCI Express accessors
*/
static uint32_t get_bus_address ( pci_dev_t d , int where )
{
uint32_t va_address ;
/* Reconfigure Region #0 */
writel ( 0 , MX6_DBI_ADDR + PCIE_ATU_VIEWPORT ) ;
if ( PCI_BUS ( d ) < 2 )
writel ( PCIE_ATU_TYPE_CFG0 , MX6_DBI_ADDR + PCIE_ATU_CR1 ) ;
else
writel ( PCIE_ATU_TYPE_CFG1 , MX6_DBI_ADDR + PCIE_ATU_CR1 ) ;
if ( PCI_BUS ( d ) = = 0 ) {
va_address = MX6_DBI_ADDR ;
} else {
writel ( d < < 8 , MX6_DBI_ADDR + PCIE_ATU_LOWER_TARGET ) ;
va_address = MX6_IO_ADDR + SZ_16M - SZ_1M ;
}
va_address + = ( where & ~ 0x3 ) ;
return va_address ;
}
static int imx_pcie_addr_valid ( pci_dev_t d )
{
if ( ( PCI_BUS ( d ) = = 0 ) & & ( PCI_DEV ( d ) > 1 ) )
return - EINVAL ;
if ( ( PCI_BUS ( d ) = = 1 ) & & ( PCI_DEV ( d ) > 0 ) )
return - EINVAL ;
return 0 ;
}
/*
* Replace the original ARM DABT handler with a simple jump - back one .
*
* The problem here is that if we have a PCIe bridge attached to this PCIe
* controller , but no PCIe device is connected to the bridges ' downstream
* port , the attempt to read / write from / to the config space will produce
* a DABT . This is a behavior of the controller and can not be disabled
* unfortuatelly .
*
* To work around the problem , we backup the current DABT handler address
* and replace it with our own DABT handler , which only bounces right back
* into the code .
*/
static void imx_pcie_fix_dabt_handler ( bool set )
{
extern uint32_t * _data_abort ;
uint32_t * data_abort_addr = ( uint32_t * ) & _data_abort ;
static const uint32_t data_abort_bounce_handler = 0xe25ef004 ;
uint32_t data_abort_bounce_addr = ( uint32_t ) & data_abort_bounce_handler ;
static uint32_t data_abort_backup ;
if ( set ) {
data_abort_backup = * data_abort_addr ;
* data_abort_addr = data_abort_bounce_addr ;
} else {
* data_abort_addr = data_abort_backup ;
}
}
static int imx_pcie_read_config ( struct pci_controller * hose , pci_dev_t d ,
int where , u32 * val )
{
uint32_t va_address ;
int ret ;
ret = imx_pcie_addr_valid ( d ) ;
if ( ret ) {
* val = 0xffffffff ;
return ret ;
}
va_address = get_bus_address ( d , where ) ;
/*
* Read the PCIe config space . We must replace the DABT handler
* here in case we got data abort from the PCIe controller , see
* imx_pcie_fix_dabt_handler ( ) description . Note that writing the
* " val " with valid value is also imperative here as in case we
* did got DABT , the val would contain random value .
*/
imx_pcie_fix_dabt_handler ( true ) ;
writel ( 0xffffffff , val ) ;
* val = readl ( va_address ) ;
imx_pcie_fix_dabt_handler ( false ) ;
return 0 ;
}
static int imx_pcie_write_config ( struct pci_controller * hose , pci_dev_t d ,
int where , u32 val )
{
uint32_t va_address = 0 ;
int ret ;
ret = imx_pcie_addr_valid ( d ) ;
if ( ret )
return ret ;
va_address = get_bus_address ( d , where ) ;
/*
* Write the PCIe config space . We must replace the DABT handler
* here in case we got data abort from the PCIe controller , see
* imx_pcie_fix_dabt_handler ( ) description .
*/
imx_pcie_fix_dabt_handler ( true ) ;
writel ( val , va_address ) ;
imx_pcie_fix_dabt_handler ( false ) ;
return 0 ;
}
/*
* Initial bus setup
*/
static int imx6_pcie_assert_core_reset ( void )
{
struct iomuxc * iomuxc_regs = ( struct iomuxc * ) IOMUXC_BASE_ADDR ;
if ( is_mx6dqp ( ) )
setbits_le32 ( & iomuxc_regs - > gpr [ 1 ] , IOMUXC_GPR1_PCIE_SW_RST ) ;
# if defined(CONFIG_MX6SX)
struct gpc * gpc_regs = ( struct gpc * ) GPC_BASE_ADDR ;
/* SSP_EN is not used on MX6SX anymore */
setbits_le32 ( & iomuxc_regs - > gpr [ 12 ] , IOMUXC_GPR12_TEST_POWERDOWN ) ;
/* Force PCIe PHY reset */
setbits_le32 ( & iomuxc_regs - > gpr [ 5 ] , IOMUXC_GPR5_PCIE_BTNRST ) ;
/* Power up PCIe PHY */
setbits_le32 ( & gpc_regs - > cntr , PCIE_PHY_PUP_REQ ) ;
# else
setbits_le32 ( & iomuxc_regs - > gpr [ 1 ] , IOMUXC_GPR1_TEST_POWERDOWN ) ;
clrbits_le32 ( & iomuxc_regs - > gpr [ 1 ] , IOMUXC_GPR1_REF_SSP_EN ) ;
# endif
return 0 ;
}
static int imx6_pcie_init_phy ( void )
{
struct iomuxc * iomuxc_regs = ( struct iomuxc * ) IOMUXC_BASE_ADDR ;
clrbits_le32 ( & iomuxc_regs - > gpr [ 12 ] , IOMUXC_GPR12_APPS_LTSSM_ENABLE ) ;
clrsetbits_le32 ( & iomuxc_regs - > gpr [ 12 ] ,
IOMUXC_GPR12_DEVICE_TYPE_MASK ,
IOMUXC_GPR12_DEVICE_TYPE_RC ) ;
clrsetbits_le32 ( & iomuxc_regs - > gpr [ 12 ] ,
IOMUXC_GPR12_LOS_LEVEL_MASK ,
IOMUXC_GPR12_LOS_LEVEL_9 ) ;
# ifdef CONFIG_MX6SX
clrsetbits_le32 ( & iomuxc_regs - > gpr [ 12 ] ,
IOMUXC_GPR12_RX_EQ_MASK ,
IOMUXC_GPR12_RX_EQ_2 ) ;
# endif
writel ( ( 0x0 < < IOMUXC_GPR8_PCS_TX_DEEMPH_GEN1_OFFSET ) |
( 0x0 < < IOMUXC_GPR8_PCS_TX_DEEMPH_GEN2_3P5DB_OFFSET ) |
( 20 < < IOMUXC_GPR8_PCS_TX_DEEMPH_GEN2_6DB_OFFSET ) |
( 127 < < IOMUXC_GPR8_PCS_TX_SWING_FULL_OFFSET ) |
( 127 < < IOMUXC_GPR8_PCS_TX_SWING_LOW_OFFSET ) ,
& iomuxc_regs - > gpr [ 8 ] ) ;
return 0 ;
}
__weak int imx6_pcie_toggle_power ( void )
{
# ifdef CONFIG_PCIE_IMX_POWER_GPIO
gpio_direction_output ( CONFIG_PCIE_IMX_POWER_GPIO , 0 ) ;
mdelay ( 20 ) ;
gpio_set_value ( CONFIG_PCIE_IMX_POWER_GPIO , 1 ) ;
mdelay ( 20 ) ;
# endif
return 0 ;
}
__weak int imx6_pcie_toggle_reset ( void )
{
/*
* See ' PCI EXPRESS BASE SPECIFICATION , REV 3.0 , SECTION 6.6 .1 '
* for detailed understanding of the PCIe CR reset logic .
*
* The PCIe # PERST reset line _MUST_ be connected , otherwise your
* design does not conform to the specification . You must wait at
* least 20 ms after de - asserting the # PERST so the EP device can
* do self - initialisation .
*
* In case your # PERST pin is connected to a plain GPIO pin of the
* CPU , you can define CONFIG_PCIE_IMX_PERST_GPIO in your board ' s
* configuration file and the condition below will handle the rest
* of the reset toggling .
*
* In case your # PERST toggling logic is more complex , for example
* connected via CPLD or somesuch , you can override this function
* in your board file and implement reset logic as needed . You must
* not forget to wait at least 20 ms after de - asserting # PERST in
* this case either though .
*
* In case your # PERST line of the PCIe EP device is not connected
* at all , your design is broken and you should fix your design ,
* otherwise you will observe problems like for example the link
* not coming up after rebooting the system back from running Linux
* that uses the PCIe as well OR the PCIe link might not come up in
* Linux at all in the first place since it ' s in some non - reset
* state due to being previously used in U - Boot .
*/
# ifdef CONFIG_PCIE_IMX_PERST_GPIO
gpio_direction_output ( CONFIG_PCIE_IMX_PERST_GPIO , 0 ) ;
mdelay ( 20 ) ;
gpio_set_value ( CONFIG_PCIE_IMX_PERST_GPIO , 1 ) ;
mdelay ( 20 ) ;
# else
puts ( " WARNING: Make sure the PCIe #PERST line is connected! \n " ) ;
# endif
return 0 ;
}
static int imx6_pcie_deassert_core_reset ( void )
{
struct iomuxc * iomuxc_regs = ( struct iomuxc * ) IOMUXC_BASE_ADDR ;
imx6_pcie_toggle_power ( ) ;
enable_pcie_clock ( ) ;
if ( is_mx6dqp ( ) )
clrbits_le32 ( & iomuxc_regs - > gpr [ 1 ] , IOMUXC_GPR1_PCIE_SW_RST ) ;
/*
* Wait for the clock to settle a bit , when the clock are sourced
* from the CPU , we need about 30 ms to settle .
*/
mdelay ( 50 ) ;
# if defined(CONFIG_MX6SX)
/* SSP_EN is not used on MX6SX anymore */
clrbits_le32 ( & iomuxc_regs - > gpr [ 12 ] , IOMUXC_GPR12_TEST_POWERDOWN ) ;
/* Clear PCIe PHY reset bit */
clrbits_le32 ( & iomuxc_regs - > gpr [ 5 ] , IOMUXC_GPR5_PCIE_BTNRST ) ;
# else
/* Enable PCIe */
clrbits_le32 ( & iomuxc_regs - > gpr [ 1 ] , IOMUXC_GPR1_TEST_POWERDOWN ) ;
setbits_le32 ( & iomuxc_regs - > gpr [ 1 ] , IOMUXC_GPR1_REF_SSP_EN ) ;
# endif
imx6_pcie_toggle_reset ( ) ;
return 0 ;
}
static int imx_pcie_link_up ( void )
{
struct iomuxc * iomuxc_regs = ( struct iomuxc * ) IOMUXC_BASE_ADDR ;
uint32_t tmp ;
int count = 0 ;
imx6_pcie_assert_core_reset ( ) ;
imx6_pcie_init_phy ( ) ;
imx6_pcie_deassert_core_reset ( ) ;
imx_pcie_regions_setup ( ) ;
/*
* FIXME : Force the PCIe RC to Gen1 operation
* The RC must be forced into Gen1 mode before bringing the link
* up , otherwise no downstream devices are detected . After the
* link is up , a managed Gen1 - > Gen2 transition can be initiated .
*/
tmp = readl ( MX6_DBI_ADDR + 0x7c ) ;
tmp & = ~ 0xf ;
tmp | = 0x1 ;
writel ( tmp , MX6_DBI_ADDR + 0x7c ) ;
/* LTSSM enable, starting link. */
setbits_le32 ( & iomuxc_regs - > gpr [ 12 ] , IOMUXC_GPR12_APPS_LTSSM_ENABLE ) ;
while ( ! imx6_pcie_link_up ( ) ) {
udelay ( 10 ) ;
count + + ;
if ( count > = 2000 ) {
# ifdef CONFIG_PCI_SCAN_SHOW
puts ( " PCI: pcie phy link never came up \n " ) ;
# endif
debug ( " DEBUG_R0: 0x%08x, DEBUG_R1: 0x%08x \n " ,
readl ( MX6_DBI_ADDR + PCIE_PHY_DEBUG_R0 ) ,
readl ( MX6_DBI_ADDR + PCIE_PHY_DEBUG_R1 ) ) ;
return - EINVAL ;
}
}
return 0 ;
}
void imx_pcie_init ( void )
{
/* Static instance of the controller. */
static struct pci_controller pcc ;
struct pci_controller * hose = & pcc ;
int ret ;
memset ( & pcc , 0 , sizeof ( pcc ) ) ;
/* PCI I/O space */
pci_set_region ( & hose - > regions [ 0 ] ,
MX6_IO_ADDR , MX6_IO_ADDR ,
MX6_IO_SIZE , PCI_REGION_IO ) ;
/* PCI memory space */
pci_set_region ( & hose - > regions [ 1 ] ,
MX6_MEM_ADDR , MX6_MEM_ADDR ,
MX6_MEM_SIZE , PCI_REGION_MEM ) ;
/* System memory space */
pci_set_region ( & hose - > regions [ 2 ] ,
MMDC0_ARB_BASE_ADDR , MMDC0_ARB_BASE_ADDR ,
0xefffffff , PCI_REGION_MEM | PCI_REGION_SYS_MEMORY ) ;
hose - > region_count = 3 ;
pci_set_ops ( hose ,
pci_hose_read_config_byte_via_dword ,
pci_hose_read_config_word_via_dword ,
imx_pcie_read_config ,
pci_hose_write_config_byte_via_dword ,
pci_hose_write_config_word_via_dword ,
imx_pcie_write_config ) ;
/* Start the controller. */
ret = imx_pcie_link_up ( ) ;
if ( ! ret ) {
pci_register_hose ( hose ) ;
hose - > last_busno = pci_hose_scan ( hose ) ;
}
}
/* Probe function. */
void pci_init_board ( void )
{
imx_pcie_init ( ) ;
}