2013-09-26 11:24:47 +08:00
/*
* PCIe host controller driver for Freescale i . MX6 SoCs
*
* Copyright ( C ) 2013 Kosagi
* http : //www.kosagi.com
*
* Author : Sean Cross < xobs @ kosagi . com >
*
* 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/clk.h>
# include <linux/delay.h>
# include <linux/gpio.h>
# include <linux/kernel.h>
# include <linux/mfd/syscon.h>
# include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
# include <linux/module.h>
# include <linux/of_gpio.h>
# include <linux/pci.h>
# include <linux/platform_device.h>
# include <linux/regmap.h>
# include <linux/resource.h>
# include <linux/signal.h>
# include <linux/types.h>
2014-03-28 17:52:59 +01:00
# include <linux/interrupt.h>
2013-09-26 11:24:47 +08:00
# include "pcie-designware.h"
# define to_imx6_pcie(x) container_of(x, struct imx6_pcie, pp)
struct imx6_pcie {
int reset_gpio ;
2014-03-28 17:52:55 +01:00
struct clk * pcie_bus ;
struct clk * pcie_phy ;
struct clk * pcie ;
2013-09-26 11:24:47 +08:00
struct pcie_port pp ;
struct regmap * iomuxc_gpr ;
void __iomem * mem_base ;
} ;
2013-12-12 22:50:02 +01:00
/* PCIe Root Complex registers (memory-mapped) */
# define PCIE_RC_LCR 0x7c
# define PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN1 0x1
# define PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN2 0x2
# define PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK 0xf
2015-06-12 17:27:43 -05:00
# define PCIE_RC_LCSR 0x80
2013-09-26 11:24:47 +08:00
/* PCIe Port Logic registers (memory-mapped) */
# define PL_OFFSET 0x700
2014-07-31 20:16:05 +02:00
# define PCIE_PL_PFLR (PL_OFFSET + 0x08)
# define PCIE_PL_PFLR_LINK_STATE_MASK (0x3f << 16)
# define PCIE_PL_PFLR_FORCE_LINK (1 << 15)
2013-09-26 11:24:47 +08:00
# define PCIE_PHY_DEBUG_R0 (PL_OFFSET + 0x28)
# define PCIE_PHY_DEBUG_R1 (PL_OFFSET + 0x2c)
2013-12-12 22:49:59 +01:00
# define PCIE_PHY_DEBUG_R1_XMLH_LINK_IN_TRAINING (1 << 29)
# define PCIE_PHY_DEBUG_R1_XMLH_LINK_UP (1 << 4)
2013-09-26 11:24:47 +08:00
# 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_ACK_LOC 16
2013-12-12 22:50:02 +01:00
# define PCIE_LINK_WIDTH_SPEED_CONTROL 0x80C
# define PORT_LOGIC_SPEED_CHANGE (0x1 << 17)
2013-09-26 11:24:47 +08:00
/* 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)
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 ) ;
2015-08-20 01:31:58 -05:00
return pcie_phy_poll_ack ( dbi_base , 0 ) ;
2013-09-26 11:24:47 +08:00
}
/* 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 ) ;
2015-08-20 01:31:58 -05:00
return pcie_phy_poll_ack ( dbi_base , 0 ) ;
2013-09-26 11:24:47 +08:00
}
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 ;
}
/* Added for PCI abort handling */
static int imx6q_pcie_abort_handler ( unsigned long addr ,
unsigned int fsr , struct pt_regs * regs )
{
return 0 ;
}
static int imx6_pcie_assert_core_reset ( struct pcie_port * pp )
{
struct imx6_pcie * imx6_pcie = to_imx6_pcie ( pp ) ;
2014-07-31 20:16:05 +02:00
u32 val , gpr1 , gpr12 ;
/*
* If the bootloader already enabled the link we need some special
* handling to get the core back into a state where it is safe to
* touch it for configuration . As there is no dedicated reset signal
* wired up for MX6QDL , we need to manually force LTSSM into " detect "
* state before completely disabling LTSSM , which is a prerequisite
* for core configuration .
*
* If both LTSSM_ENABLE and REF_SSP_ENABLE are active we have a strong
* indication that the bootloader activated the link .
*/
regmap_read ( imx6_pcie - > iomuxc_gpr , IOMUXC_GPR1 , & gpr1 ) ;
regmap_read ( imx6_pcie - > iomuxc_gpr , IOMUXC_GPR12 , & gpr12 ) ;
if ( ( gpr1 & IMX6Q_GPR1_PCIE_REF_CLK_EN ) & &
( gpr12 & IMX6Q_GPR12_PCIE_CTL_2 ) ) {
val = readl ( pp - > dbi_base + PCIE_PL_PFLR ) ;
val & = ~ PCIE_PL_PFLR_LINK_STATE_MASK ;
val | = PCIE_PL_PFLR_FORCE_LINK ;
writel ( val , pp - > dbi_base + PCIE_PL_PFLR ) ;
regmap_update_bits ( imx6_pcie - > iomuxc_gpr , IOMUXC_GPR12 ,
IMX6Q_GPR12_PCIE_CTL_2 , 0 < < 10 ) ;
}
2013-09-26 11:24:47 +08:00
regmap_update_bits ( imx6_pcie - > iomuxc_gpr , IOMUXC_GPR1 ,
IMX6Q_GPR1_PCIE_TEST_PD , 1 < < 18 ) ;
regmap_update_bits ( imx6_pcie - > iomuxc_gpr , IOMUXC_GPR1 ,
IMX6Q_GPR1_PCIE_REF_CLK_EN , 0 < < 16 ) ;
return 0 ;
}
static int imx6_pcie_deassert_core_reset ( struct pcie_port * pp )
{
struct imx6_pcie * imx6_pcie = to_imx6_pcie ( pp ) ;
int ret ;
2014-03-28 17:52:55 +01:00
ret = clk_prepare_enable ( imx6_pcie - > pcie_phy ) ;
2013-09-26 11:24:47 +08:00
if ( ret ) {
2014-03-28 17:52:55 +01:00
dev_err ( pp - > dev , " unable to enable pcie_phy clock \n " ) ;
goto err_pcie_phy ;
2013-09-26 11:24:47 +08:00
}
2014-03-28 17:52:55 +01:00
ret = clk_prepare_enable ( imx6_pcie - > pcie_bus ) ;
2013-09-26 11:24:47 +08:00
if ( ret ) {
2014-03-28 17:52:55 +01:00
dev_err ( pp - > dev , " unable to enable pcie_bus clock \n " ) ;
goto err_pcie_bus ;
2013-09-26 11:24:47 +08:00
}
2014-03-28 17:52:55 +01:00
ret = clk_prepare_enable ( imx6_pcie - > pcie ) ;
2013-09-26 11:24:47 +08:00
if ( ret ) {
2014-03-28 17:52:55 +01:00
dev_err ( pp - > dev , " unable to enable pcie clock \n " ) ;
goto err_pcie ;
2013-09-26 11:24:47 +08:00
}
2014-08-07 23:36:40 -07:00
/* power up core phy and enable ref clock */
regmap_update_bits ( imx6_pcie - > iomuxc_gpr , IOMUXC_GPR1 ,
IMX6Q_GPR1_PCIE_TEST_PD , 0 < < 18 ) ;
2014-10-27 13:17:32 +08:00
/*
* the async reset input need ref clock to sync internally ,
* when the ref clock comes after reset , internal synced
* reset time is too short , cannot meet the requirement .
* add one ~ 10u s delay here .
*/
udelay ( 10 ) ;
2014-08-07 23:36:40 -07:00
regmap_update_bits ( imx6_pcie - > iomuxc_gpr , IOMUXC_GPR1 ,
IMX6Q_GPR1_PCIE_REF_CLK_EN , 1 < < 16 ) ;
2014-10-27 13:17:32 +08:00
/* allow the clocks to stabilize */
usleep_range ( 200 , 500 ) ;
2013-12-12 22:50:03 +01:00
/* Some boards don't have PCIe reset GPIO. */
if ( gpio_is_valid ( imx6_pcie - > reset_gpio ) ) {
gpio_set_value ( imx6_pcie - > reset_gpio , 0 ) ;
msleep ( 100 ) ;
gpio_set_value ( imx6_pcie - > reset_gpio , 1 ) ;
}
2013-09-26 11:24:47 +08:00
return 0 ;
2014-03-28 17:52:55 +01:00
err_pcie :
clk_disable_unprepare ( imx6_pcie - > pcie_bus ) ;
err_pcie_bus :
clk_disable_unprepare ( imx6_pcie - > pcie_phy ) ;
err_pcie_phy :
2013-09-26 11:24:47 +08:00
return ret ;
}
static void imx6_pcie_init_phy ( struct pcie_port * pp )
{
struct imx6_pcie * imx6_pcie = to_imx6_pcie ( pp ) ;
regmap_update_bits ( imx6_pcie - > iomuxc_gpr , IOMUXC_GPR12 ,
IMX6Q_GPR12_PCIE_CTL_2 , 0 < < 10 ) ;
/* configure constant input signal to the pcie ctrl and phy */
regmap_update_bits ( imx6_pcie - > iomuxc_gpr , IOMUXC_GPR12 ,
IMX6Q_GPR12_DEVICE_TYPE , PCI_EXP_TYPE_ROOT_PORT < < 12 ) ;
regmap_update_bits ( imx6_pcie - > iomuxc_gpr , IOMUXC_GPR12 ,
IMX6Q_GPR12_LOS_LEVEL , 9 < < 4 ) ;
regmap_update_bits ( imx6_pcie - > iomuxc_gpr , IOMUXC_GPR8 ,
IMX6Q_GPR8_TX_DEEMPH_GEN1 , 0 < < 0 ) ;
regmap_update_bits ( imx6_pcie - > iomuxc_gpr , IOMUXC_GPR8 ,
IMX6Q_GPR8_TX_DEEMPH_GEN2_3P5DB , 0 < < 6 ) ;
regmap_update_bits ( imx6_pcie - > iomuxc_gpr , IOMUXC_GPR8 ,
IMX6Q_GPR8_TX_DEEMPH_GEN2_6DB , 20 < < 12 ) ;
regmap_update_bits ( imx6_pcie - > iomuxc_gpr , IOMUXC_GPR8 ,
IMX6Q_GPR8_TX_SWING_FULL , 127 < < 18 ) ;
regmap_update_bits ( imx6_pcie - > iomuxc_gpr , IOMUXC_GPR8 ,
IMX6Q_GPR8_TX_SWING_LOW , 127 < < 25 ) ;
}
2013-12-12 22:50:01 +01:00
static int imx6_pcie_wait_for_link ( struct pcie_port * pp )
{
2015-06-02 16:47:17 -05:00
unsigned int retries ;
2013-12-12 22:50:01 +01:00
2015-06-02 16:47:17 -05:00
for ( retries = 0 ; retries < 200 ; retries + + ) {
if ( dw_pcie_link_up ( pp ) )
return 0 ;
2013-12-12 22:50:01 +01:00
usleep_range ( 100 , 1000 ) ;
}
2015-06-02 16:47:17 -05:00
dev_err ( pp - > dev , " phy link never came up \n " ) ;
dev_dbg ( pp - > dev , " DEBUG_R0: 0x%08x, DEBUG_R1: 0x%08x \n " ,
readl ( pp - > dbi_base + PCIE_PHY_DEBUG_R0 ) ,
readl ( pp - > dbi_base + PCIE_PHY_DEBUG_R1 ) ) ;
return - EINVAL ;
2013-12-12 22:50:01 +01:00
}
2015-06-12 14:30:16 -05:00
static int imx6_pcie_wait_for_speed_change ( struct pcie_port * pp )
{
2015-06-12 15:02:49 -05:00
u32 tmp ;
2015-06-12 14:30:16 -05:00
unsigned int retries ;
for ( retries = 0 ; retries < 200 ; retries + + ) {
tmp = readl ( pp - > dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL ) ;
/* Test if the speed change finished. */
if ( ! ( tmp & PORT_LOGIC_SPEED_CHANGE ) )
return 0 ;
usleep_range ( 100 , 1000 ) ;
}
dev_err ( pp - > dev , " Speed change timeout \n " ) ;
return - EINVAL ;
2013-12-12 22:50:01 +01:00
}
2014-03-28 17:52:59 +01:00
static irqreturn_t imx6_pcie_msi_handler ( int irq , void * arg )
{
struct pcie_port * pp = arg ;
return dw_handle_msi_irq ( pp ) ;
}
2015-06-02 16:16:44 -05:00
static int imx6_pcie_establish_link ( struct pcie_port * pp )
2013-09-26 11:24:47 +08:00
{
struct imx6_pcie * imx6_pcie = to_imx6_pcie ( pp ) ;
2015-06-12 15:02:49 -05:00
u32 tmp ;
2015-06-12 14:30:16 -05:00
int ret ;
2013-12-12 22:50:02 +01:00
/*
* Force Gen1 operation when starting the link . In case the link is
* started in Gen2 mode , there is a possibility the devices on the
* bus will not be detected at all . This happens with PCIe switches .
*/
tmp = readl ( pp - > dbi_base + PCIE_RC_LCR ) ;
tmp & = ~ PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK ;
tmp | = PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN1 ;
writel ( tmp , pp - > dbi_base + PCIE_RC_LCR ) ;
/* Start LTSSM. */
regmap_update_bits ( imx6_pcie - > iomuxc_gpr , IOMUXC_GPR12 ,
IMX6Q_GPR12_PCIE_CTL_2 , 1 < < 10 ) ;
ret = imx6_pcie_wait_for_link ( pp ) ;
if ( ret )
return ret ;
/* Allow Gen2 mode after the link is up. */
tmp = readl ( pp - > dbi_base + PCIE_RC_LCR ) ;
tmp & = ~ PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK ;
tmp | = PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN2 ;
writel ( tmp , pp - > dbi_base + PCIE_RC_LCR ) ;
/*
* Start Directed Speed Change so the best possible speed both link
* partners support can be negotiated .
*/
tmp = readl ( pp - > dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL ) ;
tmp | = PORT_LOGIC_SPEED_CHANGE ;
writel ( tmp , pp - > dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL ) ;
2015-06-12 14:30:16 -05:00
ret = imx6_pcie_wait_for_speed_change ( pp ) ;
if ( ret ) {
dev_err ( pp - > dev , " Failed to bring link up! \n " ) ;
return ret ;
2013-12-12 22:50:02 +01:00
}
/* Make sure link training is finished as well! */
2015-06-12 14:30:16 -05:00
ret = imx6_pcie_wait_for_link ( pp ) ;
2013-12-12 22:50:02 +01:00
if ( ret ) {
dev_err ( pp - > dev , " Failed to bring link up! \n " ) ;
2015-06-12 14:30:16 -05:00
return ret ;
2013-12-12 22:50:02 +01:00
}
2015-06-12 17:27:43 -05:00
tmp = readl ( pp - > dbi_base + PCIE_RC_LCSR ) ;
2015-06-12 14:30:16 -05:00
dev_dbg ( pp - > dev , " Link up, Gen=%i \n " , ( tmp > > 16 ) & 0xf ) ;
return 0 ;
2013-12-12 22:50:02 +01:00
}
static void imx6_pcie_host_init ( struct pcie_port * pp )
{
2013-09-26 11:24:47 +08:00
imx6_pcie_assert_core_reset ( pp ) ;
imx6_pcie_init_phy ( pp ) ;
imx6_pcie_deassert_core_reset ( pp ) ;
dw_pcie_setup_rc ( pp ) ;
2015-06-02 16:16:44 -05:00
imx6_pcie_establish_link ( pp ) ;
2014-03-28 17:52:59 +01:00
if ( IS_ENABLED ( CONFIG_PCI_MSI ) )
dw_pcie_msi_init ( pp ) ;
2013-09-26 11:24:47 +08:00
}
2013-12-12 22:50:00 +01:00
static void imx6_pcie_reset_phy ( struct pcie_port * pp )
{
2015-06-12 15:02:49 -05:00
u32 tmp ;
2013-12-12 22:50:00 +01:00
2015-06-12 15:02:49 -05:00
pcie_phy_read ( pp - > dbi_base , PHY_RX_OVRD_IN_LO , & tmp ) ;
tmp | = ( PHY_RX_OVRD_IN_LO_RX_DATA_EN |
PHY_RX_OVRD_IN_LO_RX_PLL_EN ) ;
pcie_phy_write ( pp - > dbi_base , PHY_RX_OVRD_IN_LO , tmp ) ;
2013-12-12 22:50:00 +01:00
usleep_range ( 2000 , 3000 ) ;
2015-06-12 15:02:49 -05:00
pcie_phy_read ( pp - > dbi_base , PHY_RX_OVRD_IN_LO , & tmp ) ;
tmp & = ~ ( PHY_RX_OVRD_IN_LO_RX_DATA_EN |
2013-12-12 22:50:00 +01:00
PHY_RX_OVRD_IN_LO_RX_PLL_EN ) ;
2015-06-12 15:02:49 -05:00
pcie_phy_write ( pp - > dbi_base , PHY_RX_OVRD_IN_LO , tmp ) ;
2013-12-12 22:50:00 +01:00
}
2013-09-26 11:24:47 +08:00
static int imx6_pcie_link_up ( struct pcie_port * pp )
{
2014-02-19 13:22:18 -07:00
u32 rc , debug_r0 , rx_valid ;
int count = 5 ;
2013-09-26 11:24:47 +08:00
2013-12-12 22:49:59 +01:00
/*
2014-02-19 13:22:18 -07:00
* Test if the PHY reports that the link is up and also that the LTSSM
* training finished . There are three possible states of the link when
* this code is called :
* 1 ) The link is DOWN ( unlikely )
* The link didn ' t come up yet for some reason . This usually means
* we have a real problem somewhere . Reset the PHY and exit . This
* state calls for inspection of the DEBUG registers .
* 2 ) The link is UP , but still in LTSSM training
* Wait for the training to finish , which should take a very short
* time . If the training does not finish , we have a problem and we
* need to inspect the DEBUG registers . If the training does finish ,
* the link is up and operating correctly .
* 3 ) The link is UP and no longer in LTSSM training
* The link is up and operating correctly .
2013-12-12 22:49:59 +01:00
*/
2014-02-19 13:22:18 -07:00
while ( 1 ) {
rc = readl ( pp - > dbi_base + PCIE_PHY_DEBUG_R1 ) ;
if ( ! ( rc & PCIE_PHY_DEBUG_R1_XMLH_LINK_UP ) )
break ;
if ( ! ( rc & PCIE_PHY_DEBUG_R1_XMLH_LINK_IN_TRAINING ) )
return 1 ;
if ( ! count - - )
break ;
dev_dbg ( pp - > dev , " Link is up, but still in training \n " ) ;
/*
* Wait a little bit , then re - check if the link finished
* the training .
*/
usleep_range ( 1000 , 2000 ) ;
}
2013-09-26 11:24:47 +08:00
/*
* 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 ( pp - > dbi_base , PCIE_PHY_RX_ASIC_OUT , & rx_valid ) ;
2014-02-19 13:22:18 -07:00
debug_r0 = readl ( pp - > dbi_base + PCIE_PHY_DEBUG_R0 ) ;
2013-09-26 11:24:47 +08:00
if ( rx_valid & 0x01 )
return 0 ;
2014-02-19 13:22:18 -07:00
if ( ( debug_r0 & 0x3f ) ! = 0x0d )
2013-09-26 11:24:47 +08:00
return 0 ;
dev_err ( pp - > dev , " transition to gen2 is stuck, reset PHY! \n " ) ;
2014-02-19 13:22:18 -07:00
dev_dbg ( pp - > dev , " debug_r0=%08x debug_r1=%08x \n " , debug_r0 , rc ) ;
2013-09-26 11:24:47 +08:00
2013-12-12 22:50:00 +01:00
imx6_pcie_reset_phy ( pp ) ;
2013-09-26 11:24:47 +08:00
return 0 ;
}
static struct pcie_host_ops imx6_pcie_host_ops = {
. link_up = imx6_pcie_link_up ,
. host_init = imx6_pcie_host_init ,
} ;
2014-05-30 12:08:48 +05:30
static int __init imx6_add_pcie_port ( struct pcie_port * pp ,
2013-09-26 11:24:47 +08:00
struct platform_device * pdev )
{
int ret ;
2014-03-28 17:52:59 +01:00
if ( IS_ENABLED ( CONFIG_PCI_MSI ) ) {
pp - > msi_irq = platform_get_irq_byname ( pdev , " msi " ) ;
if ( pp - > msi_irq < = 0 ) {
dev_err ( & pdev - > dev , " failed to get MSI irq \n " ) ;
return - ENODEV ;
}
ret = devm_request_irq ( & pdev - > dev , pp - > msi_irq ,
2014-11-12 12:25:09 +09:00
imx6_pcie_msi_handler ,
IRQF_SHARED , " mx6-pcie-msi " , pp ) ;
2014-03-28 17:52:59 +01:00
if ( ret ) {
dev_err ( & pdev - > dev , " failed to request MSI irq \n " ) ;
return - ENODEV ;
}
}
2013-09-26 11:24:47 +08:00
pp - > root_bus_nr = - 1 ;
pp - > ops = & imx6_pcie_host_ops ;
ret = dw_pcie_host_init ( pp ) ;
if ( ret ) {
dev_err ( & pdev - > dev , " failed to initialize host \n " ) ;
return ret ;
}
return 0 ;
}
static int __init imx6_pcie_probe ( struct platform_device * pdev )
{
struct imx6_pcie * imx6_pcie ;
struct pcie_port * pp ;
struct device_node * np = pdev - > dev . of_node ;
struct resource * dbi_base ;
int ret ;
imx6_pcie = devm_kzalloc ( & pdev - > dev , sizeof ( * imx6_pcie ) , GFP_KERNEL ) ;
if ( ! imx6_pcie )
return - ENOMEM ;
pp = & imx6_pcie - > pp ;
pp - > dev = & pdev - > dev ;
/* Added for PCI abort handling */
hook_fault_code ( 16 + 6 , imx6q_pcie_abort_handler , SIGBUS , 0 ,
" imprecise external abort " ) ;
dbi_base = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
pp - > dbi_base = devm_ioremap_resource ( & pdev - > dev , dbi_base ) ;
2013-12-02 01:39:35 -02:00
if ( IS_ERR ( pp - > dbi_base ) )
return PTR_ERR ( pp - > dbi_base ) ;
2013-09-26 11:24:47 +08:00
/* Fetch GPIOs */
imx6_pcie - > reset_gpio = of_get_named_gpio ( np , " reset-gpio " , 0 ) ;
2013-12-12 22:49:58 +01:00
if ( gpio_is_valid ( imx6_pcie - > reset_gpio ) ) {
ret = devm_gpio_request_one ( & pdev - > dev , imx6_pcie - > reset_gpio ,
GPIOF_OUT_INIT_LOW , " PCIe reset " ) ;
if ( ret ) {
dev_err ( & pdev - > dev , " unable to get reset gpio \n " ) ;
return ret ;
}
2013-09-26 11:24:47 +08:00
}
/* Fetch clocks */
2014-03-28 17:52:55 +01:00
imx6_pcie - > pcie_phy = devm_clk_get ( & pdev - > dev , " pcie_phy " ) ;
if ( IS_ERR ( imx6_pcie - > pcie_phy ) ) {
2013-09-26 11:24:47 +08:00
dev_err ( & pdev - > dev ,
2014-03-28 17:52:55 +01:00
" pcie_phy clock source missing or invalid \n " ) ;
return PTR_ERR ( imx6_pcie - > pcie_phy ) ;
2013-09-26 11:24:47 +08:00
}
2014-03-28 17:52:55 +01:00
imx6_pcie - > pcie_bus = devm_clk_get ( & pdev - > dev , " pcie_bus " ) ;
if ( IS_ERR ( imx6_pcie - > pcie_bus ) ) {
2013-09-26 11:24:47 +08:00
dev_err ( & pdev - > dev ,
2014-03-28 17:52:55 +01:00
" pcie_bus clock source missing or invalid \n " ) ;
return PTR_ERR ( imx6_pcie - > pcie_bus ) ;
2013-09-26 11:24:47 +08:00
}
2014-03-28 17:52:55 +01:00
imx6_pcie - > pcie = devm_clk_get ( & pdev - > dev , " pcie " ) ;
if ( IS_ERR ( imx6_pcie - > pcie ) ) {
2013-09-26 11:24:47 +08:00
dev_err ( & pdev - > dev ,
2014-03-28 17:52:55 +01:00
" pcie clock source missing or invalid \n " ) ;
return PTR_ERR ( imx6_pcie - > pcie ) ;
2013-09-26 11:24:47 +08:00
}
/* Grab GPR config register range */
imx6_pcie - > iomuxc_gpr =
syscon_regmap_lookup_by_compatible ( " fsl,imx6q-iomuxc-gpr " ) ;
if ( IS_ERR ( imx6_pcie - > iomuxc_gpr ) ) {
dev_err ( & pdev - > dev , " unable to find iomuxc registers \n " ) ;
2013-12-02 01:39:35 -02:00
return PTR_ERR ( imx6_pcie - > iomuxc_gpr ) ;
2013-09-26 11:24:47 +08:00
}
ret = imx6_add_pcie_port ( pp , pdev ) ;
if ( ret < 0 )
2013-12-02 01:39:35 -02:00
return ret ;
2013-09-26 11:24:47 +08:00
platform_set_drvdata ( pdev , imx6_pcie ) ;
return 0 ;
}
2014-07-31 20:16:05 +02:00
static void imx6_pcie_shutdown ( struct platform_device * pdev )
{
struct imx6_pcie * imx6_pcie = platform_get_drvdata ( pdev ) ;
/* bring down link, so bootloader gets clean state in case of reboot */
imx6_pcie_assert_core_reset ( & imx6_pcie - > pp ) ;
}
2013-09-26 11:24:47 +08:00
static const struct of_device_id imx6_pcie_of_match [ ] = {
{ . compatible = " fsl,imx6q-pcie " , } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , imx6_pcie_of_match ) ;
static struct platform_driver imx6_pcie_driver = {
. driver = {
. name = " imx6q-pcie " ,
2013-10-21 14:36:41 +05:30
. of_match_table = imx6_pcie_of_match ,
2013-09-26 11:24:47 +08:00
} ,
2014-07-31 20:16:05 +02:00
. shutdown = imx6_pcie_shutdown ,
2013-09-26 11:24:47 +08:00
} ;
/* Freescale PCIe driver does not allow module unload */
static int __init imx6_pcie_init ( void )
{
return platform_driver_probe ( & imx6_pcie_driver , imx6_pcie_probe ) ;
}
2014-09-05 09:36:48 -06:00
module_init ( imx6_pcie_init ) ;
2013-09-26 11:24:47 +08:00
MODULE_AUTHOR ( " Sean Cross <xobs@kosagi.com> " ) ;
MODULE_DESCRIPTION ( " Freescale i.MX6 PCIe host controller driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;