From patchwork Thu Dec 3 15:19:59 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gabriele Paoloni X-Patchwork-Id: 7760851 Return-Path: X-Original-To: patchwork-linux-acpi@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 1DD0EBEEE1 for ; Thu, 3 Dec 2015 15:06:45 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 5652C20567 for ; Thu, 3 Dec 2015 15:06:41 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 02B4020573 for ; Thu, 3 Dec 2015 15:06:33 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1758629AbbLCPG3 (ORCPT ); Thu, 3 Dec 2015 10:06:29 -0500 Received: from szxga01-in.huawei.com ([58.251.152.64]:37228 "EHLO szxga01-in.huawei.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1758556AbbLCPGZ (ORCPT ); Thu, 3 Dec 2015 10:06:25 -0500 Received: from 172.24.1.49 (EHLO SZXEML424-HUB.china.huawei.com) ([172.24.1.49]) by szxrg01-dlp.huawei.com (MOS 4.3.7-GA FastPath queued) with ESMTP id DAF26471; Thu, 03 Dec 2015 23:05:00 +0800 (CST) Received: from localhost.localdomain (10.67.212.75) by SZXEML424-HUB.china.huawei.com (10.82.67.153) with Microsoft SMTP Server id 14.3.235.1; Thu, 3 Dec 2015 23:04:50 +0800 From: Gabriele Paoloni To: , , , , , , , CC: , , , , , , , , , , , , Gabriele Paoloni Subject: [RFC PATCH 2/2] PCI/ACPI: HiSi: Add ACPI support for HiSi PCIe Host Bridge Date: Thu, 3 Dec 2015 23:19:59 +0800 Message-ID: <1449155999-220955-3-git-send-email-gabriele.paoloni@huawei.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1449155999-220955-1-git-send-email-gabriele.paoloni@huawei.com> References: <1449155999-220955-1-git-send-email-gabriele.paoloni@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.67.212.75] X-CFilter-Loop: Reflected X-Mirapoint-Virus-RAPID-Raw: score=unknown(0), refid=str=0001.0A090202.56605A1E.017C, ss=1, re=0.000, recu=0.000, reip=0.000, cl=1, cld=1, fgs=0, ip=0.0.0.0, so=2013-06-18 04:22:30, dmn=2013-03-21 17:37:32 X-Mirapoint-Loop-Id: ed01160a9ee58cdf118f0a2d4d18b135 Sender: linux-acpi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-acpi@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This patch adds ACPI support for HiSilicon PCIe Host Bridge controller Signed-off-by: Liudongdong Signed-off-by: Gabriele Paoloni --- MAINTAINERS | 8 ++ arch/arm64/kernel/Makefile | 1 + arch/arm64/kernel/pci.c | 1 + arch/arm64/kernel/pci_acpi_hisi.c | 211 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 221 insertions(+) create mode 100644 arch/arm64/kernel/pci_acpi_hisi.c diff --git a/MAINTAINERS b/MAINTAINERS index 5f46784..b84f359 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7943,6 +7943,14 @@ F: include/linux/pci* F: arch/x86/pci/ F: arch/x86/kernel/quirks.c +PCI ACPI DRIVER FOR HISILICON HIP05 +M: Dongdong Liu +M: Gabriele Paoloni +L: linux-pci@vger.kernel.org +L: linux-arm-kernel@lists.infradead.org +S: Maintained +F: arch/arm64/kernel/pci_acpi_hisi.c + PCI DRIVER FOR ARM VERSATILE PLATFORM M: Rob Herring L: linux-pci@vger.kernel.org diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index 22dc9bc..1c89d07 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -36,6 +36,7 @@ arm64-obj-$(CONFIG_EFI) += efi.o efi-stub.o efi-entry.o arm64-obj-$(CONFIG_PCI) += pci.o arm64-obj-$(CONFIG_ARMV8_DEPRECATED) += armv8_deprecated.o arm64-obj-$(CONFIG_ACPI) += acpi.o +arm64-obj-$(CONFIG_ACPI) += pci_acpi_hisi.o obj-y += $(arm64-obj-y) vdso/ obj-m += $(arm64-obj-m) diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c index d60edb4..391e743 100644 --- a/arch/arm64/kernel/pci.c +++ b/arch/arm64/kernel/pci.c @@ -236,6 +236,7 @@ static struct acpi_pci_root_ops acpi_pci_root_ops = { * Host Bridge controllers that are non ECAM compliant */ static struct acpi_scan_handler *quirks_array[] = { + &pci_root_hisi_handler, 0 }; diff --git a/arch/arm64/kernel/pci_acpi_hisi.c b/arch/arm64/kernel/pci_acpi_hisi.c new file mode 100644 index 0000000..c528604 --- /dev/null +++ b/arch/arm64/kernel/pci_acpi_hisi.c @@ -0,0 +1,211 @@ +/* + * PCIe host controller driver for HiSilicon Hip05 SoC + * + * Copyright (C) 2015 HiSilicon Co., Ltd. http://www.hisilicon.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 +#include +#include +#include +#include +#include +#include +#include + +#include "pci_quirks.h" + + +#define MAX_PCIE_PORT_NUM 4 +static int acpi_pci_root_hisi_add(struct acpi_device *device, + const struct acpi_device_id *not_used); + +static void acpi_pci_root_hisi_remove(struct acpi_device *device); + + +static const struct acpi_device_id root_hisi_device_ids[] = { + {"HISI0080", 0}, + {"", 0}, +}; + +struct acpi_scan_handler pci_root_hisi_handler = { + .ids = root_hisi_device_ids, + .attach = acpi_pci_root_hisi_add, + .detach = acpi_pci_root_hisi_remove, +}; + +static void __iomem *rc_base[MAX_PCIE_PORT_NUM]; + +static void __iomem * +pci_mcfg_dev_base(struct pci_bus *bus, unsigned int devfn, int offset) +{ + struct pci_mmcfg_region *cfg; + + cfg = pci_mmconfig_lookup(pci_domain_nr(bus), bus->number); + if (cfg && cfg->virt) + return cfg->virt + + (PCI_MMCFG_BUS_OFFSET(bus->number) | (devfn << 12)) + + offset; + return NULL; +} + + +/* Hip05 PCIe host only supports 32-bit config access */ +static int hisi_pcie_cfg_read(void __iomem *addr, int where, int size, + u32 *val) +{ + u32 reg; + u32 reg_val; + void *walker = ®_val; + + walker += (where & 0x3); + reg = where & ~0x3; + reg_val = readl(addr + reg); + + if (size == 1) + *val = *(u8 __force *) walker; + else if (size == 2) + *val = *(u16 __force *) walker; + else if (size != 4) + return PCIBIOS_BAD_REGISTER_NUMBER; + + return PCIBIOS_SUCCESSFUL; +} + + +/* Hip05 PCIe host only supports 32-bit config access */ +static int hisi_pcie_cfg_write(void __iomem *addr, int where, int size, + u32 val) +{ + u32 reg_val; + u32 reg; + void *walker = ®_val; + + walker += (where & 0x3); + reg = where & ~0x3; + if (size == 4) + writel(val, addr + reg); + else if (size == 2) { + reg_val = readl(addr + reg); + *(u16 __force *) walker = val; + writel(reg_val, addr + reg); + } else if (size == 1) { + reg_val = readl(addr + reg); + *(u8 __force *) walker = val; + writel(reg_val, addr + reg); + } else + return PCIBIOS_BAD_REGISTER_NUMBER; + + return PCIBIOS_SUCCESSFUL; +} + +/* +* hip05 support ECAM to access EP config space +* but not support RC +*/ +static int pci_read(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 *value) +{ + struct acpi_pci_root *root = bus->sysdata; + int ret; + + if (bus->number == root->secondary.start) + ret = hisi_pcie_cfg_read(rc_base[root->segment], where, size, + value); + else + ret = pci_generic_config_read(bus, devfn, where, size, value); + + return ret; +} + +static int pci_write(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 value) +{ + struct acpi_pci_root *root = bus->sysdata; + int ret; + + if (bus->number == root->secondary.start) + ret = hisi_pcie_cfg_write(rc_base[root->segment], where, size, + value); + else + ret = pci_generic_config_write(bus, devfn, where, size, value); + return ret; +} + +static struct pci_ops pci_root_ops = { + .map_bus = pci_mcfg_dev_base, + .read = pci_read, + .write = pci_write, +}; + + +/* +* Sample DSDT (PCIe Root bus) +* +* Device (RC0) +*{ +* Name (_HID, "HISI0081") +* Name (_CID, "HISI0080") +* Name(_SEG, 0) +* Name (_DSD, Package () { +* ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), +* Package () { +* Package () {"rc-base", 0xb0070000} +* Package () {"rc-size", 0x10000} +* }) +*} +*Device (PCI0) +*{ +* Name (_HID, "PNP0A08") // PCI Express Root Bridge +* Name (_CID, "PNP0A03") // Compatible PCI Root Bridge +*..... +*} +* +*use segment to distinguish pcie host controller +*0-pcie0 +*1-pcie1 +*/ +static int acpi_pci_root_hisi_add(struct acpi_device *device, + const struct acpi_device_id *not_used) +{ + u32 base; + u32 size; + int ret; + unsigned long long segment; + acpi_status status; + acpi_handle handle = device->handle; + + ret = fwnode_property_read_u32(&device->fwnode, "rc-base", &base); + if (ret) { + dev_err(&device->dev, "can't get rc-base\n"); + return ret; + } + + ret = fwnode_property_read_u32(&device->fwnode, "rc-size", &size); + if (ret) { + dev_err(&device->dev, "can't get rc-size\n"); + return ret; + } + + status = acpi_evaluate_integer(handle, METHOD_NAME__SEG, NULL, + &segment); + if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { + dev_err(&device->dev, "can't evaluate _SEG\n"); + return -ENODEV; + } + + rc_base[segment] = ioremap(base, size); + set_quirk_pci_ops(&pci_root_ops); + + return 0; +} + +static void acpi_pci_root_hisi_remove(struct acpi_device *device) +{ + unset_quirk_pci_ops(); +}