sunxi: remove h6 pcie support
This will cause orangepi 3 to fail to boot on 5.10, so remove it.
This commit is contained in:
parent
7a6d119cc1
commit
dd5c4f4d6d
@ -19,13 +19,12 @@ PKG_MIRROR_HASH:=b212d369a5286ebbf6a5616486efa05fa54d4294fd6e9ba2e54fdfae9eda918
|
||||
PKG_LICENSE:=BSD-3-Clause
|
||||
PKG_LICENSE_FILES:=license.md
|
||||
|
||||
PKG_CONFIG_DEPENDS:=ARM_TRUSTED_FIRMWARE_SUNXI_WRAPPED_PCIE
|
||||
|
||||
PKG_MAINTAINER:=Hauke Mehrtens <hauke@hauke-m.de>
|
||||
|
||||
include $(INCLUDE_DIR)/trusted-firmware-a.mk
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
|
||||
define Package/arm-trusted-firmware-sunxi/Default
|
||||
SECTION:=boot
|
||||
CATEGORY:=Boot Loaders
|
||||
@ -43,22 +42,11 @@ define Package/arm-trusted-firmware-sunxi-h6
|
||||
VARIANT:=sun50i_h6
|
||||
endef
|
||||
|
||||
define Package/arm-trusted-firmware-sunxi-h6/config
|
||||
config ARM_TRUSTED_FIRMAWRE_SUNXI_WRAPPED_PCIE
|
||||
depends on PACKAGE_arm-trusted-firmware-sunxi-h6
|
||||
bool "Enable sunxi wrapped PCIe driver support"
|
||||
endef
|
||||
|
||||
export GCC_HONOUR_COPTS=s
|
||||
|
||||
MAKE_VARS = \
|
||||
CROSS_COMPILE="$(TARGET_CROSS)"
|
||||
|
||||
ifneq ($(CONFIG_ARM_TRUSTED_FIRMAWRE_SUNXI_WRAPPED_PCIE),)
|
||||
MAKE_FLAGS += \
|
||||
PRELOADED_BL33_BASE=0x40010000
|
||||
endif
|
||||
|
||||
MAKE_FLAGS += \
|
||||
PLAT=$(BUILD_VARIANT) \
|
||||
bl31
|
||||
|
||||
@ -240,13 +240,10 @@ endef
|
||||
define U-Boot/orangepi_3
|
||||
BUILD_SUBTARGET:=cortexa53
|
||||
NAME:=Orange Pi 3 (H6)
|
||||
DEPENDS:=+PACKAGE_u-boot-orangepi_3:arm-trusted-firmware-sunxi-h6 \
|
||||
+@PACKAGE_u-boot-orangepi_3:ARM_TRUSTED_FIRMAWRE_SUNXI_WRAPPED_PCIE \
|
||||
+PACKAGE_u-boot-orangepi_3:aw-el2-barebone
|
||||
DEPENDS:=+PACKAGE_u-boot-orangepi_3:arm-trusted-firmware-sunxi-h6
|
||||
BUILD_DEVICES:=xunlong_orangepi-3
|
||||
UENV:=h6
|
||||
ATF:=h6
|
||||
HYP:=1
|
||||
endef
|
||||
|
||||
define U-Boot/pangolin
|
||||
@ -398,8 +395,7 @@ UBOOT_TARGETS := \
|
||||
UBOOT_CONFIGURE_VARS += USE_PRIVATE_LIBGCC=yes
|
||||
|
||||
UBOOT_MAKE_FLAGS += \
|
||||
BL31=$(STAGING_DIR_IMAGE)/bl31_sun50i_$(ATF).bin \
|
||||
$(if $(HYP),HYP=$(STAGING_DIR_IMAGE)/hyp.bin)
|
||||
BL31=$(STAGING_DIR_IMAGE)/bl31_sun50i_$(ATF).bin
|
||||
|
||||
define Build/InstallDev
|
||||
$(INSTALL_DIR) $(STAGING_DIR_IMAGE)
|
||||
|
||||
@ -176,7 +176,6 @@ CONFIG_DWMAC_SUNXI=y
|
||||
CONFIG_DYNAMIC_DEBUG=y
|
||||
CONFIG_EDAC_ATOMIC_SCRUB=y
|
||||
CONFIG_EDAC_SUPPORT=y
|
||||
CONFIG_EEPROM_AT24=y
|
||||
CONFIG_ELF_CORE=y
|
||||
CONFIG_ENABLE_MUST_CHECK=y
|
||||
CONFIG_EXT4_FS=y
|
||||
|
||||
@ -69,13 +69,11 @@ CONFIG_ARM64_VA_BITS_39=y
|
||||
CONFIG_ARM64_WORKAROUND_REPEAT_TLBI=y
|
||||
CONFIG_ARM_AMBA=y
|
||||
CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND=y
|
||||
CONFIG_ARM_GIC_V2M=y
|
||||
CONFIG_ARM_GIC_V3_ITS_PCI=y
|
||||
CONFIG_AUDIT_ARCH_COMPAT_GENERIC=y
|
||||
CONFIG_BLK_MQ_PCI=y
|
||||
CONFIG_DMA_DIRECT_REMAP=y
|
||||
CONFIG_DRM_RCAR_WRITEBACK=y
|
||||
CONFIG_DWMAC_SUN8I=y
|
||||
CONFIG_EEPROM_AT24=y
|
||||
CONFIG_EFI_EARLYCON=y
|
||||
# CONFIG_FLATMEM_MANUAL is not set
|
||||
CONFIG_FRAME_POINTER=y
|
||||
@ -102,10 +100,6 @@ CONFIG_HAVE_KVM_VCPU_RUN_PID_CHANGE=y
|
||||
CONFIG_HAVE_MEMORY_PRESENT=y
|
||||
CONFIG_HAVE_PATA_PLATFORM=y
|
||||
CONFIG_HOLES_IN_ZONE=y
|
||||
CONFIG_HOTPLUG_PCI=y
|
||||
# CONFIG_HOTPLUG_PCI_CPCI is not set
|
||||
# CONFIG_HOTPLUG_PCI_PCIE is not set
|
||||
# CONFIG_HOTPLUG_PCI_SHPC is not set
|
||||
CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000
|
||||
CONFIG_INLINE_READ_LOCK=y
|
||||
CONFIG_INLINE_READ_LOCK_BH=y
|
||||
@ -136,25 +130,6 @@ CONFIG_MUSB_PIO_ONLY=y
|
||||
CONFIG_NEED_SG_DMA_LENGTH=y
|
||||
CONFIG_NO_IOPORT_MAP=y
|
||||
CONFIG_NOP_USB_XCEIV=y
|
||||
CONFIG_PCI=y
|
||||
CONFIG_PCIEAER=y
|
||||
CONFIG_PCIEASPM=y
|
||||
# CONFIG_PCIEASPM_DEBUG is not set
|
||||
CONFIG_PCIEASPM_DEFAULT=y
|
||||
# CONFIG_PCIEASPM_PERFORMANCE is not set
|
||||
# CONFIG_PCIEASPM_POWERSAVE is not set
|
||||
# CONFIG_PCIEASPM_POWER_SUPERSAVE is not set
|
||||
CONFIG_PCIEPORTBUS=y
|
||||
CONFIG_PCIE_DW=y
|
||||
CONFIG_PCIE_DW_HOST=y
|
||||
CONFIG_PCIE_PME=y
|
||||
CONFIG_PCIE_SUNXI=y
|
||||
CONFIG_PCI_DOMAINS=y
|
||||
CONFIG_PCI_DOMAINS_GENERIC=y
|
||||
CONFIG_PCI_MSI=y
|
||||
CONFIG_PCI_MSI_IRQ_DOMAIN=y
|
||||
CONFIG_PCI_STUB=y
|
||||
CONFIG_PHY_SUN50I_USB3=y
|
||||
CONFIG_PINCTRL_SUN50I_A64=y
|
||||
CONFIG_PINCTRL_SUN50I_A64_R=y
|
||||
CONFIG_PINCTRL_SUN50I_H5=y
|
||||
@ -165,7 +140,6 @@ CONFIG_QUEUED_SPINLOCKS=y
|
||||
CONFIG_RODATA_FULL_DEFAULT_ENABLED=y
|
||||
CONFIG_RTC_CLASS=y
|
||||
CONFIG_RTC_DRV_SUN6I=y
|
||||
# CONFIG_SENSORS_DRIVETEMP is not set
|
||||
# CONFIG_SND_SUN50I_CODEC_ANALOG is not set
|
||||
CONFIG_SOUND_OSS_CORE_PRECLAIM=y
|
||||
CONFIG_SPARSEMEM=y
|
||||
|
||||
@ -1,589 +0,0 @@
|
||||
// SPDX-License-Identifier : GPL-2.0
|
||||
/*
|
||||
* PCIe RC driver for Allwinner DW PCIe controllers
|
||||
*
|
||||
* Copyright (C) 2018 Icenowy Zheng <icenowy@aosc.io>
|
||||
*
|
||||
* Copyright (C) 2016 Allwinner Co., Ltd.
|
||||
*/
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/resource.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "pcie-designware.h"
|
||||
|
||||
#define PCIE_RC_LCR 0x7c
|
||||
#define USER_DEFINED_REGISTER_LIST 0x1000
|
||||
#define PCIE_LTSSM_ENABLE 0x1000
|
||||
#define PCIE_INT_PENDING 0x1018
|
||||
#define PCIE_ADDR_PAGE_CFG 0x1020
|
||||
#define PCIE_AWMISC_INF0_CTRL 0x1030
|
||||
#define PCIE_ARMISC_INF0_CTRL 0x1034
|
||||
#define PCIE_LINK_STATUS 0x143C
|
||||
#define PCIE_PHY_CFG 0x1800
|
||||
#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
|
||||
#define SYS_CLK 0
|
||||
#define PAD_CLK 1
|
||||
#define RDLH_LINK_UP BIT(1)
|
||||
#define SMLH_LINK_UP BIT(0)
|
||||
#define PCIE_LINK_TRAINING BIT(0)
|
||||
#define PCIE_LINK_UP_MASK (0x3 << 16)
|
||||
#define LINK_WAIT_MAX_RETRIES 10
|
||||
#define LINK_WAIT_USLEEP_MIN 90000
|
||||
#define LINK_WAIT_USLEEP_MAX 100000
|
||||
|
||||
#define PERST_DELAY_US 1000
|
||||
|
||||
#define PCIE_BAR_NUM 6
|
||||
#define PCIE_MEM_FLAGS 0x4
|
||||
#define PCIE_IO_FLAGS 0x1
|
||||
#define PCIE_BAR_REG 0x4
|
||||
#define HIGH16_MASK GENMASK(31, 16)
|
||||
#define LOW16_MASK GENMASK(15, 0)
|
||||
|
||||
#define to_sunxi_pcie(x) dev_get_drvdata((x)->dev)
|
||||
|
||||
struct sunxi_pcie {
|
||||
struct dw_pcie *pci;
|
||||
int link_irq;
|
||||
int msi_irq;
|
||||
int speed_gen;
|
||||
int io_voltage;
|
||||
struct clk *pcie_ref;
|
||||
struct clk *pcie_axi;
|
||||
struct clk *pcie_aux;
|
||||
struct clk *pcie_bus;
|
||||
struct reset_control *pcie_power_rst;
|
||||
struct reset_control *pcie_bus_rst;
|
||||
struct regulator *reg_vcc;
|
||||
struct regulator *reg_vdd;
|
||||
struct regulator *reg_slot;
|
||||
struct gpio_desc *perst_gpio;
|
||||
};
|
||||
|
||||
static void sunxi_pcie_perst_gpio_assert(struct sunxi_pcie *pcie)
|
||||
{
|
||||
gpiod_set_value_cansleep(pcie->perst_gpio, 1);
|
||||
usleep_range(PERST_DELAY_US, PERST_DELAY_US + 500);
|
||||
}
|
||||
|
||||
static void sunxi_pcie_perst_gpio_deassert(struct sunxi_pcie *pcie)
|
||||
{
|
||||
gpiod_set_value_cansleep(pcie->perst_gpio, 0);
|
||||
usleep_range(PERST_DELAY_US, PERST_DELAY_US + 500);
|
||||
}
|
||||
|
||||
static void sunxi_pcie_clk_select(struct dw_pcie *pci, int status)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = dw_pcie_readl_dbi(pci, PCIE_PHY_CFG);
|
||||
val &= ~(0x1 << 31);
|
||||
val |= status << 31;
|
||||
dw_pcie_writel_dbi(pci, PCIE_PHY_CFG, val);
|
||||
}
|
||||
|
||||
static void sunxi_pcie_ltssm_enable(struct dw_pcie *pci)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = dw_pcie_readl_dbi(pci, PCIE_LTSSM_ENABLE);
|
||||
val |= PCIE_LINK_TRAINING;
|
||||
dw_pcie_writel_dbi(pci, PCIE_LTSSM_ENABLE, val);
|
||||
}
|
||||
|
||||
static void sunxi_pcie_irqpending(struct dw_pcie *pci)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = dw_pcie_readl_dbi(pci, PCIE_INT_PENDING);
|
||||
val &= ~(0x3<<16);
|
||||
dw_pcie_writel_dbi(pci, PCIE_INT_PENDING, val);
|
||||
}
|
||||
|
||||
static void sunxi_pcie_phy_cfg(struct dw_pcie *pci, int enable)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = dw_pcie_readl_dbi(pci, PCIE_PHY_CFG);
|
||||
if (enable)
|
||||
val |= 0x1<<0;
|
||||
else
|
||||
val &= ~(0x1<<0);
|
||||
dw_pcie_writel_dbi(pci, PCIE_PHY_CFG, val);
|
||||
}
|
||||
|
||||
static void sunxi_pcie_irqmask(struct dw_pcie *pci)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = dw_pcie_readl_dbi(pci, PCIE_INT_PENDING);
|
||||
val |= 0x3<<16;
|
||||
dw_pcie_writel_dbi(pci, PCIE_INT_PENDING, val);
|
||||
}
|
||||
|
||||
static void sunxi_pcie_ltssm_disable(struct dw_pcie *pci)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = dw_pcie_readl_dbi(pci, PCIE_LTSSM_ENABLE);
|
||||
val &= ~PCIE_LINK_TRAINING;
|
||||
dw_pcie_writel_dbi(pci, PCIE_LTSSM_ENABLE, val);
|
||||
}
|
||||
|
||||
static int sunxi_pcie_wait_for_speed_change(struct dw_pcie *pci)
|
||||
{
|
||||
u32 tmp;
|
||||
unsigned int retries;
|
||||
|
||||
for (retries = 0; retries < 200; retries++) {
|
||||
tmp = dw_pcie_readl_dbi(pci, 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(pci->dev, "Speed change timeout\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int sunxi_pcie_link_up_status(struct dw_pcie *pci)
|
||||
{
|
||||
u32 rc;
|
||||
int ret;
|
||||
|
||||
rc = dw_pcie_readl_dbi(pci, PCIE_LINK_STATUS);
|
||||
if ((rc & RDLH_LINK_UP) && (rc & SMLH_LINK_UP))
|
||||
ret = 1;
|
||||
else
|
||||
ret = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sunxi_pcie_speed_change(struct dw_pcie *pci, int gen)
|
||||
{
|
||||
int val;
|
||||
int ret;
|
||||
|
||||
if (gen == 2) {
|
||||
val = dw_pcie_readl_dbi(pci, PCIE_RC_LCR);
|
||||
val &= ~PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK;
|
||||
val |= PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN2;
|
||||
dw_pcie_writel_dbi(pci, PCIE_RC_LCR, val);
|
||||
|
||||
/*
|
||||
* Start Directed Speed Change so the best possible
|
||||
* speed both link partners support can be negotiated.
|
||||
*/
|
||||
val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
|
||||
val |= PORT_LOGIC_SPEED_CHANGE;
|
||||
dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val);
|
||||
ret = sunxi_pcie_wait_for_speed_change(pci);
|
||||
|
||||
if (!ret)
|
||||
dev_info(pci->dev, "PCI-e speed of Gen%d\n", gen);
|
||||
else
|
||||
dev_info(pci->dev, "PCI-e speed of Gen1\n");
|
||||
} else {
|
||||
dev_info(pci->dev, "PCI-e speed of Gen1\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sunxi_pcie_establish_link(struct dw_pcie *pci)
|
||||
{
|
||||
struct sunxi_pcie *pcie = to_sunxi_pcie(pci);
|
||||
|
||||
if (dw_pcie_link_up(pci)) {
|
||||
dev_err(pcie->pci->dev, "link is already up\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
sunxi_pcie_ltssm_enable(pci);
|
||||
dw_pcie_wait_for_link(pci);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sunxi_pcie_reset_deassert(struct sunxi_pcie *pcie)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = reset_control_deassert(pcie->pcie_bus_rst);
|
||||
if (ret) {
|
||||
dev_err(pcie->pci->dev, "unable to deassert bus reset\n");
|
||||
return ret;
|
||||
}
|
||||
usleep_range(1000, 2000);
|
||||
|
||||
if (pcie->io_voltage < 2000000)
|
||||
sunxi_pcie_phy_cfg(pcie->pci, 1);
|
||||
else
|
||||
sunxi_pcie_phy_cfg(pcie->pci, 0);
|
||||
|
||||
usleep_range(1000, 2000);
|
||||
ret = reset_control_deassert(pcie->pcie_power_rst);
|
||||
if (ret) {
|
||||
dev_err(pcie->pci->dev, "unable to deassert power reset\n");
|
||||
goto bus_reset_assert;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
bus_reset_assert:
|
||||
reset_control_assert(pcie->pcie_bus_rst);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sunxi_pcie_clk_setup(struct sunxi_pcie *pcie)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(pcie->pcie_ref);
|
||||
if (ret) {
|
||||
dev_err(pcie->pci->dev, "unable to enable pcie_ref clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(pcie->pcie_axi);
|
||||
if (ret) {
|
||||
dev_err(pcie->pci->dev, "unable to enable pcie_axi clock\n");
|
||||
goto disable_ref;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(pcie->pcie_aux);
|
||||
if (ret) {
|
||||
dev_err(pcie->pci->dev, "unable to enable pcie_aux clock\n");
|
||||
goto disable_axi;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(pcie->pcie_bus);
|
||||
if (ret) {
|
||||
dev_err(pcie->pci->dev, "unable to enable pcie_bus clock\n");
|
||||
goto disable_aux;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
disable_aux:
|
||||
clk_disable_unprepare(pcie->pcie_aux);
|
||||
disable_axi:
|
||||
clk_disable_unprepare(pcie->pcie_axi);
|
||||
disable_ref:
|
||||
clk_disable_unprepare(pcie->pcie_ref);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sunxi_pcie_regulator_enable(struct sunxi_pcie *pcie)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = regulator_enable(pcie->reg_vcc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pcie->io_voltage = regulator_get_voltage(pcie->reg_vcc);
|
||||
if (pcie->io_voltage < 0) {
|
||||
ret = pcie->io_voltage;
|
||||
goto disable_vcc;
|
||||
}
|
||||
|
||||
ret = regulator_enable(pcie->reg_vdd);
|
||||
if (ret)
|
||||
goto disable_vcc;
|
||||
|
||||
ret = regulator_enable(pcie->reg_slot);
|
||||
if (ret)
|
||||
goto disable_vdd;
|
||||
|
||||
return 0;
|
||||
|
||||
disable_vdd:
|
||||
regulator_disable(pcie->reg_vdd);
|
||||
disable_vcc:
|
||||
regulator_disable(pcie->reg_vcc);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static irqreturn_t sunxi_pcie_msi_irq_handler(int irq, void *arg)
|
||||
{
|
||||
struct sunxi_pcie *pcie = (struct sunxi_pcie *)arg;
|
||||
|
||||
return dw_handle_msi_irq(&pcie->pci->pp);
|
||||
}
|
||||
|
||||
static irqreturn_t sunxi_pcie_linkup_handler(int irq, void *arg)
|
||||
{
|
||||
struct sunxi_pcie *pcie = (struct sunxi_pcie *)arg;
|
||||
|
||||
sunxi_pcie_irqpending(pcie->pci);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int sunxi_pcie_get_clk_rst(struct platform_device *pdev,
|
||||
struct sunxi_pcie *pcie)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
pcie->pcie_ref = devm_clk_get(dev, "ref");
|
||||
if (IS_ERR(pcie->pcie_ref)) {
|
||||
dev_err(dev, "failed to get pcie ref clk\n");
|
||||
return PTR_ERR(pcie->pcie_ref);
|
||||
}
|
||||
|
||||
pcie->pcie_axi = devm_clk_get(dev, "axi");
|
||||
if (IS_ERR(pcie->pcie_axi)) {
|
||||
dev_err(dev, "failed to get pcie axi clk\n");
|
||||
return PTR_ERR(pcie->pcie_axi);
|
||||
}
|
||||
|
||||
pcie->pcie_aux = devm_clk_get(dev, "aux");
|
||||
if (IS_ERR(pcie->pcie_aux)) {
|
||||
dev_err(dev, "failed to get pcie aux clk\n");
|
||||
return PTR_ERR(pcie->pcie_aux);
|
||||
}
|
||||
|
||||
pcie->pcie_bus = devm_clk_get(dev, "bus");
|
||||
if (IS_ERR(pcie->pcie_bus)) {
|
||||
dev_err(dev, "failed to get pcie bus clk\n");
|
||||
return PTR_ERR(pcie->pcie_bus);
|
||||
}
|
||||
|
||||
pcie->pcie_bus_rst = devm_reset_control_get(dev, "bus");
|
||||
if (IS_ERR(pcie->pcie_bus_rst)) {
|
||||
dev_err(dev, "failed to get pcie bus reset\n");
|
||||
return PTR_ERR(pcie->pcie_bus_rst);
|
||||
}
|
||||
|
||||
pcie->pcie_power_rst = devm_reset_control_get(dev, "power");
|
||||
if (IS_ERR(pcie->pcie_power_rst)) {
|
||||
dev_err(dev, "failed to get pcie power reset\n");
|
||||
return PTR_ERR(pcie->pcie_power_rst);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sunxi_pcie_get_regulator(struct platform_device *pdev,
|
||||
struct sunxi_pcie *pcie)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
pcie->reg_vcc = devm_regulator_get(dev, "vcc");
|
||||
if (IS_ERR(pcie->reg_vcc)) {
|
||||
dev_err(dev, "failed to get pcie vcc supply\n");
|
||||
return PTR_ERR(pcie->reg_vcc);
|
||||
}
|
||||
|
||||
pcie->reg_vdd = devm_regulator_get(dev, "vdd");
|
||||
if (IS_ERR(pcie->reg_vdd)) {
|
||||
dev_err(dev, "failed to get pcie vdd supply\n");
|
||||
return PTR_ERR(pcie->reg_vdd);
|
||||
}
|
||||
|
||||
pcie->reg_slot = devm_regulator_get(dev, "slot");
|
||||
if (IS_ERR(pcie->reg_slot)) {
|
||||
dev_err(dev, "failed to get pcie slot supply\n");
|
||||
return PTR_ERR(pcie->reg_slot);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sunxi_pcie_host_init(struct pcie_port *pp)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct sunxi_pcie *pcie = to_sunxi_pcie(pci);
|
||||
|
||||
sunxi_pcie_ltssm_disable(pci);
|
||||
sunxi_pcie_clk_select(pci, PAD_CLK);
|
||||
|
||||
dw_pcie_setup_rc(pp);
|
||||
|
||||
dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX0,
|
||||
PCIE_ATU_TYPE_MEM, pp->mem_base,
|
||||
pp->mem_bus_addr, pp->mem_size);
|
||||
if (pci->num_viewport > 2)
|
||||
dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX2,
|
||||
PCIE_ATU_TYPE_IO, pp->io_base,
|
||||
pp->io_bus_addr, pp->io_size);
|
||||
|
||||
sunxi_pcie_establish_link(pci);
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI))
|
||||
dw_pcie_msi_init(pp);
|
||||
|
||||
sunxi_pcie_speed_change(pci, pcie->speed_gen);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dw_pcie_host_ops sunxi_pcie_host_ops = {
|
||||
.host_init = sunxi_pcie_host_init,
|
||||
};
|
||||
|
||||
static const struct dw_pcie_ops sunxi_pcie_ops = {
|
||||
.link_up = sunxi_pcie_link_up_status,
|
||||
};
|
||||
|
||||
static int sunxi_add_pcie_port(struct sunxi_pcie *pcie,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
struct pcie_port *pp = &pcie->pci->pp;
|
||||
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI)) {
|
||||
pp->msi_irq = platform_get_irq_byname(pdev, "msi");
|
||||
if (pp->msi_irq < 0)
|
||||
return pp->msi_irq;
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, pp->msi_irq,
|
||||
sunxi_pcie_msi_irq_handler,
|
||||
IRQF_SHARED, "sunxi-pcie-msi", pcie);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to request MSI IRQ\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
pp->root_bus_nr = -1;
|
||||
pp->ops = &sunxi_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 sunxi_pcie_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct sunxi_pcie *sunxi_pcie;
|
||||
struct dw_pcie *pci;
|
||||
struct resource *dbi_res;
|
||||
int ret;
|
||||
|
||||
sunxi_pcie = devm_kzalloc(&pdev->dev, sizeof(*sunxi_pcie),
|
||||
GFP_KERNEL);
|
||||
if (!sunxi_pcie)
|
||||
return -ENOMEM;
|
||||
|
||||
pci = devm_kzalloc(&pdev->dev, sizeof(*pci), GFP_KERNEL);
|
||||
if (!pci)
|
||||
return -ENOMEM;
|
||||
|
||||
sunxi_pcie->pci = pci;
|
||||
|
||||
pci->dev = &pdev->dev;
|
||||
pci->ops = &sunxi_pcie_ops;
|
||||
|
||||
platform_set_drvdata(pdev, sunxi_pcie);
|
||||
|
||||
dbi_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
|
||||
if (!dbi_res)
|
||||
return -ENODEV;
|
||||
|
||||
pci->dbi_base = devm_ioremap_resource(&pdev->dev, dbi_res);
|
||||
if (IS_ERR(pci->dbi_base))
|
||||
return PTR_ERR(pci->dbi_base);
|
||||
|
||||
ret = sunxi_pcie_get_clk_rst(pdev, sunxi_pcie);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = sunxi_pcie_get_regulator(pdev, sunxi_pcie);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
sunxi_pcie->perst_gpio = devm_gpiod_get_optional(&pdev->dev, "perst", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(sunxi_pcie->perst_gpio))
|
||||
return PTR_ERR(sunxi_pcie->perst_gpio);
|
||||
|
||||
ret = of_property_read_u32(pdev->dev.of_node, "max-link-speed", &sunxi_pcie->speed_gen);
|
||||
if (ret) {
|
||||
dev_info(&pdev->dev, "No speed generation info specified, fallback to Gen1\n");
|
||||
sunxi_pcie->speed_gen = 0x1;
|
||||
}
|
||||
|
||||
ret = sunxi_pcie_regulator_enable(sunxi_pcie);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = sunxi_pcie_clk_setup(sunxi_pcie);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = sunxi_pcie_reset_deassert(sunxi_pcie);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
sunxi_pcie_perst_gpio_deassert(sunxi_pcie);
|
||||
|
||||
sunxi_pcie_irqmask(pci);
|
||||
sunxi_pcie->link_irq = platform_get_irq_byname(pdev, "linkup");
|
||||
ret = devm_request_irq(&pdev->dev, sunxi_pcie->link_irq,
|
||||
sunxi_pcie_linkup_handler,
|
||||
IRQF_SHARED, "sunxi-pcie-linkup", sunxi_pcie);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to request linkup IRQ\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = sunxi_add_pcie_port(sunxi_pcie, pdev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sunxi_pcie_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct sunxi_pcie *pcie = platform_get_drvdata(pdev);
|
||||
|
||||
sunxi_pcie_perst_gpio_assert(pcie);
|
||||
reset_control_assert(pcie->pcie_bus_rst);
|
||||
reset_control_assert(pcie->pcie_power_rst);
|
||||
clk_disable_unprepare(pcie->pcie_ref);
|
||||
clk_disable_unprepare(pcie->pcie_axi);
|
||||
clk_disable_unprepare(pcie->pcie_aux);
|
||||
clk_disable_unprepare(pcie->pcie_bus);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id sunxi_pcie_of_match[] = {
|
||||
{ .compatible = "allwinner,sun50i-h6-pcie", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sunxi_pcie_of_match);
|
||||
|
||||
static struct platform_driver sunxi_pcie_driver = {
|
||||
.driver = {
|
||||
.name = "sunxi-pcie",
|
||||
.suppress_bind_attrs = true,
|
||||
.of_match_table = sunxi_pcie_of_match,
|
||||
},
|
||||
.remove = sunxi_pcie_remove,
|
||||
.probe = sunxi_pcie_probe,
|
||||
};
|
||||
builtin_platform_driver(sunxi_pcie_driver);
|
||||
@ -1,89 +0,0 @@
|
||||
From 9e57b0de548676f361ff5085f3b44f48fd91784f Mon Sep 17 00:00:00 2001
|
||||
From: Icenowy Zheng <icenowy@aosc.io>
|
||||
Date: Sun, 29 Mar 2020 10:56:16 +0800
|
||||
Subject: [PATCH] add wrapped PCIe for sunxi
|
||||
|
||||
Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
|
||||
---
|
||||
arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi | 31 +
|
||||
drivers/pci/controller/dwc/Kconfig | 8 +
|
||||
drivers/pci/controller/dwc/Makefile | 1 +
|
||||
.../pci/controller/dwc/pcie-sunxi.c | 589 ++++++++++++++++++
|
||||
4 files changed, 629 insertions(+)
|
||||
create mode 100644 drivers/pci/controller/dwc/pcie-sunxi.c
|
||||
|
||||
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
|
||||
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
|
||||
@@ -13,6 +13,8 @@
|
||||
#include <dt-bindings/reset/sun8i-de2.h>
|
||||
#include <dt-bindings/thermal/thermal.h>
|
||||
|
||||
+/memreserve/ 0x40010000 0x00070000;
|
||||
+
|
||||
/ {
|
||||
interrupt-parent = <&gic>;
|
||||
#address-cells = <1>;
|
||||
@@ -764,6 +766,36 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
+ /* On Allwinner H6 PCIe is quirky and needs to be wrapped */
|
||||
+ pcie: pcie@5400000 {
|
||||
+ #address-cells = <3>;
|
||||
+ #size-cells = <2>;
|
||||
+ compatible = "allwinner,sun50i-h6-pcie";
|
||||
+ reg = <0x05400000 0x4000>,
|
||||
+ <0x05410000 0x10000>;
|
||||
+ reg-names = "dbi", "config";
|
||||
+ device_type = "pci";
|
||||
+ bus-range = <0x00 0xff>;
|
||||
+ ranges = <0x81000000 0 0 0x05e00000 0 0x00010000 /* downstream I/O */
|
||||
+ 0x82000000 0 0x05500000 0x05500000 0 0x00800000>; /* non-prefetchable memory */
|
||||
+ num-lanes = <1>;
|
||||
+ max-link-speed = <2>;
|
||||
+ interrupts = <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>,
|
||||
+ <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>;
|
||||
+ interrupt-names = "msi", "linkup";
|
||||
+ clocks = <&ccu CLK_PCIE_REF_OUT>,
|
||||
+ <&ccu CLK_PCIE_MAXI>,
|
||||
+ <&ccu CLK_PCIE_AUX>,
|
||||
+ <&ccu CLK_BUS_PCIE>;
|
||||
+ clock-names = "ref", "axi", "aux", "bus";
|
||||
+ resets = <&ccu RST_PCIE_POWERUP>, <&ccu RST_BUS_PCIE>;
|
||||
+ reset-names = "power", "bus";
|
||||
+ #interrupt-cells = <1>;
|
||||
+ interrupt-map-mask = <0 0 0 0>;
|
||||
+ interrupt-map = <0 0 0 1 &gic GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>;
|
||||
+ status = "disabled";
|
||||
+ };
|
||||
+
|
||||
hdmi: hdmi@6000000 {
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "allwinner,sun50i-h6-dw-hdmi";
|
||||
--- a/drivers/pci/controller/dwc/Kconfig
|
||||
+++ b/drivers/pci/controller/dwc/Kconfig
|
||||
@@ -236,6 +236,14 @@ config PCI_MESON
|
||||
and therefore the driver re-uses the DesignWare core functions to
|
||||
implement the driver.
|
||||
|
||||
+config PCIE_SUNXI
|
||||
+ bool "Allwinner SoCs PCIe controllers"
|
||||
+ depends on PCI_MSI_IRQ_DOMAIN
|
||||
+ select PCIE_DW_HOST
|
||||
+ help
|
||||
+ Say Y here it you want PCIe controller support on Allwinner H6, wrapped
|
||||
+ to a regular PCIe controller by a hypervisor.
|
||||
+
|
||||
config PCIE_TEGRA194
|
||||
tristate "NVIDIA Tegra194 (and later) PCIe controller"
|
||||
depends on ARCH_TEGRA_194_SOC || COMPILE_TEST
|
||||
--- a/drivers/pci/controller/dwc/Makefile
|
||||
+++ b/drivers/pci/controller/dwc/Makefile
|
||||
@@ -17,6 +17,7 @@ obj-$(CONFIG_PCIE_KIRIN) += pcie-kirin.o
|
||||
obj-$(CONFIG_PCIE_HISI_STB) += pcie-histb.o
|
||||
obj-$(CONFIG_PCI_MESON) += pci-meson.o
|
||||
obj-$(CONFIG_PCIE_TEGRA194) += pcie-tegra194.o
|
||||
+obj-$(CONFIG_PCIE_SUNXI) += pcie-sunxi.o
|
||||
obj-$(CONFIG_PCIE_UNIPHIER) += pcie-uniphier.o
|
||||
|
||||
# The following drivers are for devices that use the generic ACPI
|
||||
@ -1,17 +0,0 @@
|
||||
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts
|
||||
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts
|
||||
@@ -207,6 +207,14 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
+&pcie {
|
||||
+ vcc-supply = <®_bldo2>;
|
||||
+ vdd-supply = <®_dcdcd>;
|
||||
+ slot-supply = <®_aldo3>;
|
||||
+ perst-gpio = <&pio 3 17 GPIO_ACTIVE_LOW>;
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&pio {
|
||||
vcc-pc-supply = <®_bldo2>;
|
||||
vcc-pd-supply = <®_cldo1>;
|
||||
Loading…
Reference in New Issue
Block a user