2018-01-26 21:50:27 +03:00
// SPDX-License-Identifier: GPL-2.0
2014-11-05 11:45:11 +03:00
/*
* PCIe host controller driver for Freescale Layerscape SoCs
*
* Copyright ( C ) 2014 Freescale Semiconductor .
2021-12-24 12:40:00 +03:00
* Copyright 2021 NXP
2014-11-05 11:45:11 +03:00
*
2015-10-16 10:19:19 +03:00
* Author : Minghuan Lian < Minghuan . Lian @ freescale . com >
2014-11-05 11:45:11 +03:00
*/
# include <linux/kernel.h>
# include <linux/interrupt.h>
2016-07-03 02:13:27 +03:00
# include <linux/init.h>
2014-11-05 11:45:11 +03:00
# include <linux/of_pci.h>
# include <linux/of_platform.h>
# include <linux/of_irq.h>
# include <linux/of_address.h>
# include <linux/pci.h>
# include <linux/platform_device.h>
# include <linux/resource.h>
# include <linux/mfd/syscon.h>
# include <linux/regmap.h>
# include "pcie-designware.h"
2015-10-16 10:19:19 +03:00
/* PEX Internal Configuration Registers */
# define PCIE_STRFMR1 0x71c /* Symbol Timer & Filter Mask Register1 */
2017-10-12 12:44:48 +03:00
# define PCIE_ABSERR 0x8d0 /* Bridge Slave Error Response Register */
# define PCIE_ABSERR_SETTING 0x9401 /* Forward error of non-posted request */
2015-10-16 10:19:19 +03:00
2017-08-28 13:52:58 +03:00
# define PCIE_IATU_NUM 6
2014-11-05 11:45:11 +03:00
struct ls_pcie {
2017-02-15 16:18:14 +03:00
struct dw_pcie * pci ;
2014-11-05 11:45:11 +03:00
} ;
2017-02-15 16:18:14 +03:00
# define to_ls_pcie(x) dev_get_drvdata((x)->dev)
2014-11-05 11:45:11 +03:00
2015-10-16 10:19:16 +03:00
static bool ls_pcie_is_bridge ( struct ls_pcie * pcie )
{
2017-02-15 16:18:14 +03:00
struct dw_pcie * pci = pcie - > pci ;
2015-10-16 10:19:16 +03:00
u32 header_type ;
2017-02-15 16:18:14 +03:00
header_type = ioread8 ( pci - > dbi_base + PCI_HEADER_TYPE ) ;
2015-10-16 10:19:16 +03:00
header_type & = 0x7f ;
return header_type = = PCI_HEADER_TYPE_BRIDGE ;
}
2015-10-16 10:19:19 +03:00
/* Clear multi-function bit */
static void ls_pcie_clear_multifunction ( struct ls_pcie * pcie )
{
2017-02-15 16:18:14 +03:00
struct dw_pcie * pci = pcie - > pci ;
iowrite8 ( PCI_HEADER_TYPE_BRIDGE , pci - > dbi_base + PCI_HEADER_TYPE ) ;
2015-10-16 10:19:19 +03:00
}
2016-03-01 02:24:15 +03:00
/* Drop MSG TLP except for Vendor MSG */
static void ls_pcie_drop_msg_tlp ( struct ls_pcie * pcie )
{
u32 val ;
2017-02-15 16:18:14 +03:00
struct dw_pcie * pci = pcie - > pci ;
2016-03-01 02:24:15 +03:00
2017-02-15 16:18:14 +03:00
val = ioread32 ( pci - > dbi_base + PCIE_STRFMR1 ) ;
2016-03-01 02:24:15 +03:00
val & = 0xDFFFFFFF ;
2017-02-15 16:18:14 +03:00
iowrite32 ( val , pci - > dbi_base + PCIE_STRFMR1 ) ;
2016-03-01 02:24:15 +03:00
}
2017-10-12 12:44:48 +03:00
/* Forward error response of outbound non-posted requests */
static void ls_pcie_fix_error_response ( struct ls_pcie * pcie )
{
struct dw_pcie * pci = pcie - > pci ;
iowrite32 ( PCIE_ABSERR_SETTING , pci - > dbi_base + PCIE_ABSERR ) ;
}
2022-06-24 17:34:25 +03:00
static int ls_pcie_host_init ( struct dw_pcie_rp * pp )
2017-08-28 13:52:56 +03:00
{
struct dw_pcie * pci = to_dw_pcie_from_pp ( pp ) ;
struct ls_pcie * pcie = to_ls_pcie ( pci ) ;
2017-10-12 12:44:48 +03:00
ls_pcie_fix_error_response ( pcie ) ;
2017-08-28 13:52:58 +03:00
2017-08-28 13:52:59 +03:00
dw_pcie_dbi_ro_wr_en ( pci ) ;
2017-08-28 13:52:56 +03:00
ls_pcie_clear_multifunction ( pcie ) ;
2017-08-28 13:52:59 +03:00
dw_pcie_dbi_ro_wr_dis ( pci ) ;
2017-08-28 13:52:56 +03:00
ls_pcie_drop_msg_tlp ( pcie ) ;
return 0 ;
}
2017-06-05 11:53:46 +03:00
static const struct dw_pcie_host_ops ls_pcie_host_ops = {
2015-10-16 10:19:19 +03:00
. host_init = ls_pcie_host_init ,
} ;
2015-10-16 10:19:17 +03:00
static const struct of_device_id ls_pcie_of_match [ ] = {
2021-12-24 12:40:00 +03:00
{ . compatible = " fsl,ls1012a-pcie " , } ,
{ . compatible = " fsl,ls1021a-pcie " , } ,
{ . compatible = " fsl,ls1028a-pcie " , } ,
{ . compatible = " fsl,ls1043a-pcie " , } ,
{ . compatible = " fsl,ls1046a-pcie " , } ,
{ . compatible = " fsl,ls2080a-pcie " , } ,
{ . compatible = " fsl,ls2085a-pcie " , } ,
{ . compatible = " fsl,ls2088a-pcie " , } ,
{ . compatible = " fsl,ls1088a-pcie " , } ,
2015-10-16 10:19:17 +03:00
{ } ,
} ;
2021-01-20 13:52:46 +03:00
static int ls_pcie_probe ( struct platform_device * pdev )
2014-11-05 11:45:11 +03:00
{
2016-10-06 21:38:05 +03:00
struct device * dev = & pdev - > dev ;
2017-02-15 16:18:14 +03:00
struct dw_pcie * pci ;
2014-11-05 11:45:11 +03:00
struct ls_pcie * pcie ;
struct resource * dbi_base ;
2016-10-06 21:38:05 +03:00
pcie = devm_kzalloc ( dev , sizeof ( * pcie ) , GFP_KERNEL ) ;
2014-11-05 11:45:11 +03:00
if ( ! pcie )
return - ENOMEM ;
2017-02-15 16:18:14 +03:00
pci = devm_kzalloc ( dev , sizeof ( * pci ) , GFP_KERNEL ) ;
if ( ! pci )
return - ENOMEM ;
pci - > dev = dev ;
2021-12-24 12:40:00 +03:00
pci - > pp . ops = & ls_pcie_host_ops ;
2016-10-06 21:38:06 +03:00
2017-02-25 13:08:12 +03:00
pcie - > pci = pci ;
2014-11-05 11:45:11 +03:00
dbi_base = platform_get_resource_byname ( pdev , IORESOURCE_MEM , " regs " ) ;
2017-04-19 19:49:08 +03:00
pci - > dbi_base = devm_pci_remap_cfg_resource ( dev , dbi_base ) ;
2017-02-15 16:18:14 +03:00
if ( IS_ERR ( pci - > dbi_base ) )
return PTR_ERR ( pci - > dbi_base ) ;
2014-11-05 11:45:11 +03:00
2015-10-16 10:19:16 +03:00
if ( ! ls_pcie_is_bridge ( pcie ) )
return - ENODEV ;
2017-02-15 16:18:11 +03:00
platform_set_drvdata ( pdev , pcie ) ;
2020-11-06 00:11:56 +03:00
return dw_pcie_host_init ( & pci - > pp ) ;
2014-11-05 11:45:11 +03:00
}
static struct platform_driver ls_pcie_driver = {
2021-01-20 13:52:46 +03:00
. probe = ls_pcie_probe ,
2014-11-05 11:45:11 +03:00
. driver = {
. name = " layerscape-pcie " ,
. of_match_table = ls_pcie_of_match ,
2017-04-20 23:36:25 +03:00
. suppress_bind_attrs = true ,
2014-11-05 11:45:11 +03:00
} ,
} ;
2021-01-20 13:52:46 +03:00
builtin_platform_driver ( ls_pcie_driver ) ;