From patchwork Mon Apr 27 06:16:03 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bin Meng X-Patchwork-Id: 464800 X-Patchwork-Delegate: sjg@chromium.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id C4B8F140079 for ; Mon, 27 Apr 2015 16:16:46 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=fail reason="verification failed; unprotected key" header.d=gmail.com header.i=@gmail.com header.b=s31eXqz5; dkim-adsp=none (unprotected policy); dkim-atps=neutral Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 2A88F4BB20; Mon, 27 Apr 2015 08:16:39 +0200 (CEST) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id PwSr6H1wfpUn; Mon, 27 Apr 2015 08:16:39 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id B6D354BB00; Mon, 27 Apr 2015 08:16:38 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 5E6CB4BB30 for ; Mon, 27 Apr 2015 08:16:29 +0200 (CEST) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 7drf5uQ00PTS for ; Mon, 27 Apr 2015 08:16:29 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mail-vn0-f42.google.com (mail-vn0-f42.google.com [209.85.216.42]) by theia.denx.de (Postfix) with ESMTPS id CE9FE4BB25 for ; Mon, 27 Apr 2015 08:16:23 +0200 (CEST) Received: by vnbf62 with SMTP id f62so10729747vnb.13 for ; Sun, 26 Apr 2015 23:16:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=message-id:from:to:subject:date:in-reply-to:references:mime-version :content-type; bh=BiF/sUdIQJ1xe2Y1GSCv4CthFI2qFIsEdPxPr7qMqyY=; b=s31eXqz5r/evYAMEk33ym5AICFnYa0CXBldxpzToFVZsEqFwGcKah49u0rN23s+WMr YvYp5+orcUxLnsZl91NvRhhPjHfMz9RaOHHhvsre2Kms+2U3eMbwVotwxtbZ1BsiwluO UF/JcgoQGlbIG/bRdKfLBgqDXhQ/wCEs/hm7iEBBTNIVBN1OzeRcoYelPaa0ZzlrGVbY eVtpqspBrTDpYvvlNPBwOAfESHU7+UWpMUze6r0Xf/rkV6GcoS7avbQqVDErYAF9s1xR QA8m8BxxcVscNu/q0pdO4x9usy4+RyfhD7yLjJlki77/F/1PTKdgMt20VzLzntlpI3ka X3HA== X-Received: by 10.52.33.132 with SMTP id r4mr24048847vdi.0.1430115382317; Sun, 26 Apr 2015 23:16:22 -0700 (PDT) Received: from mail.hotmail.com (blu004-wss1s1.hotmail.com. [134.170.2.216]) by mx.google.com with ESMTPSA id bi2sm23401380vdc.19.2015.04.26.23.16.21 (version=TLSv1 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Sun, 26 Apr 2015 23:16:21 -0700 (PDT) Received: from BLU436-SMTP85 ([134.170.2.215]) by BLU004-WSS1S1.hotmail.com over TLS secured channel with Microsoft SMTPSVC(7.5.7601.22751); Sun, 26 Apr 2015 23:16:21 -0700 X-TMN: [tWkGsqv8YC0MdMkRB5v2aX2OBTF7TNRx] Message-ID: From: Bin Meng To: Simon Glass , U-Boot Mailing List Date: Mon, 27 Apr 2015 14:16:03 +0800 X-Mailer: git-send-email 1.8.2.1 In-Reply-To: <1430115363-31116-1-git-send-email-bmeng.cn@gmail.com> References: <1430115363-31116-1-git-send-email-bmeng.cn@gmail.com> X-OriginalArrivalTime: 27 Apr 2015 06:16:20.0258 (UTC) FILETIME=[AD867020:01D080B1] MIME-Version: 1.0 Subject: [U-Boot] [PATCH 3/3] x86: quark: Implement PIRQ routing X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.15 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" Intel Quark SoC has the same interrupt routing mechanism as the Queensbay platform, only the difference is that PCI devices' INTA/B/C/D are harcoded and cannot be changed freely. Signed-off-by: Bin Meng --- arch/x86/cpu/quark/Makefile | 2 +- arch/x86/cpu/quark/irq.c | 173 +++++++++++++++++++++++++++++++ arch/x86/cpu/quark/quark.c | 8 ++ arch/x86/include/asm/arch-quark/device.h | 70 ++++++++++--- arch/x86/include/asm/arch-quark/irq.h | 55 ++++++++++ arch/x86/include/asm/arch-quark/quark.h | 15 +++ configs/galileo_defconfig | 1 + include/configs/galileo.h | 1 + 8 files changed, 309 insertions(+), 16 deletions(-) create mode 100644 arch/x86/cpu/quark/irq.c create mode 100644 arch/x86/include/asm/arch-quark/irq.h diff --git a/arch/x86/cpu/quark/Makefile b/arch/x86/cpu/quark/Makefile index e87b424..1e37802 100644 --- a/arch/x86/cpu/quark/Makefile +++ b/arch/x86/cpu/quark/Makefile @@ -4,6 +4,6 @@ # SPDX-License-Identifier: GPL-2.0+ # -obj-y += car.o dram.o msg_port.o quark.o +obj-y += car.o dram.o irq.o msg_port.o quark.o obj-y += mrc.o mrc_util.o hte.o smc.o obj-$(CONFIG_PCI) += pci.o diff --git a/arch/x86/cpu/quark/irq.c b/arch/x86/cpu/quark/irq.c new file mode 100644 index 0000000..d6edd0c --- /dev/null +++ b/arch/x86/cpu/quark/irq.c @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2015, Bin Meng + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct irq_routing_table *pirq_routing_table; + +bool pirq_check_irq_routed(int link, u8 irq) +{ + u8 pirq; + + pirq = x86_pci_read_config8(QUARK_LEGACY_BRIDGE, LINK_N2V(link)); + pirq &= 0xf; + + /* IRQ# 0/1/2/8/13 are reserved */ + if (pirq < 3 || pirq == 8 || pirq == 13) + return false; + + return pirq == irq ? true : false; +} + +int pirq_translate_link(int link) +{ + return LINK_V2N(link); +} + +void pirq_assign_irq(int link, u8 irq) +{ + /* IRQ# 0/1/2/8/13 are reserved */ + if (irq < 3 || irq == 8 || irq == 13) + return; + + x86_pci_write_config8(QUARK_LEGACY_BRIDGE, LINK_N2V(link), irq); +} + +static inline void fill_irq_info(struct irq_info **slotp, int *entries, u8 bus, + u8 device, u8 func, u8 pin, u8 pirq) +{ + struct irq_info *slot = *slotp; + + slot->bus = bus; + slot->devfn = (device << 3) | func; + slot->irq[pin - 1].link = LINK_N2V(pirq); + slot->irq[pin - 1].bitmap = PIRQ_BITMAP; + (*entries)++; + (*slotp)++; +} + +__weak int board_fill_irq_info(struct irq_info *slot) +{ + return 0; +} + +static int create_pirq_routing_table(void) +{ + struct irq_routing_table *rt; + struct irq_info *slot; + int irq_entries = 0; + + rt = malloc(sizeof(struct irq_routing_table)); + if (!rt) + return -ENOMEM; + memset((char *)rt, 0, sizeof(struct irq_routing_table)); + + /* Populate the PIRQ table fields */ + rt->signature = PIRQ_SIGNATURE; + rt->version = PIRQ_VERSION; + rt->rtr_bus = 0; + rt->rtr_devfn = (QUARK_LGC_BRIDGE_DEV << 3) | QUARK_LGC_BRIDGE_FUNC; + rt->rtr_vendor = PCI_VENDOR_ID_INTEL; + rt->rtr_device = PCI_DEVICE_ID_INTEL_ICH7_31; + + slot = rt->slots; + + /* Now fill in the irq_info entries in the PIRQ table */ + fill_irq_info(&slot, &irq_entries, 0, QUARK_DEV_20, + QUARK_MMC_SDIO_FUNC, INTA, PIRQE); + fill_irq_info(&slot, &irq_entries, 0, QUARK_DEV_20, + QUARK_UART0_FUNC, INTB, PIRQF); + fill_irq_info(&slot, &irq_entries, 0, QUARK_DEV_20, + QUARK_USB_DEVICE_FUNC, INTC, PIRQG); + fill_irq_info(&slot, &irq_entries, 0, QUARK_DEV_20, + QUARK_USB_EHCI_FUNC, INTD, PIRQH); + fill_irq_info(&slot, &irq_entries, 0, QUARK_DEV_20, + QUARK_USB_OHCI_FUNC, INTD, PIRQH); + fill_irq_info(&slot, &irq_entries, 0, QUARK_DEV_20, + QUARK_UART1_FUNC, INTB, PIRQF); + fill_irq_info(&slot, &irq_entries, 0, QUARK_DEV_20, + QUARK_EMAC0_FUNC, INTC, PIRQG); + fill_irq_info(&slot, &irq_entries, 0, QUARK_DEV_20, + QUARK_EMAC1_FUNC, INTC, PIRQG); + + fill_irq_info(&slot, &irq_entries, 0, QUARK_DEV_21, + QUARK_SPI0_FUNC, INTA, PIRQE); + fill_irq_info(&slot, &irq_entries, 0, QUARK_DEV_21, + QUARK_SPI1_FUNC, INTA, PIRQE); + fill_irq_info(&slot, &irq_entries, 0, QUARK_DEV_21, + QUARK_I2C_GPIO_FUNC, INTC, PIRQG); + + /* + * TODO: + * + * For some unknown reason, the PCI enumeration process hangs + * when it scans to the PCIe root port 0 (D23:F0) & 1 (D23:F1). + * + * For now we just skip these two devices, and this needs to + * be revisited later. + */ +#ifdef TODO + fill_irq_info(&slot, &irq_entries, 0, QUARK_DEV_23, + QUARK_PCIE0_FUNC, INTA, PIRQA); + fill_irq_info(&slot, &irq_entries, 0, QUARK_DEV_23, + QUARK_PCIE1_FUNC, INTA, PIRQA); +#endif + + /* Call board-specific routine to fill in add-in card's irq info */ + irq_entries += board_fill_irq_info(slot); + + rt->size = irq_entries * sizeof(struct irq_info) + 32; + + pirq_routing_table = rt; + + return 0; +} + +void pirq_init(void) +{ + struct quark_rcba *rcba; + u32 base; + + base = x86_pci_read_config32(QUARK_LEGACY_BRIDGE, LB_RCBA); + base &= ~MEM_BAR_EN; + rcba = (struct quark_rcba *)base; + + /* + * Route Quark PCI device interrupt pin to PIRQ + * + * Route device#23's INTA/B/C/D to PIRQA/B/C/D + * Route device#20,21's INTA/B/C/D to PIRQE/F/G/H + */ + writew(PIRQC, &rcba->rmu_ir); + writew(PIRQA | (PIRQB << 4) | (PIRQC << 8) | (PIRQD << 12), + &rcba->d23_ir); + writew(PIRQD, &rcba->core_ir); + writew(PIRQE | (PIRQF << 4) | (PIRQG << 8) | (PIRQH << 12), + &rcba->d20d21_ir); + + if (create_pirq_routing_table()) { + debug("Failed to create pirq routing table\n"); + } else { + /* Route PIRQ */ + pirq_route_irqs(pirq_routing_table->slots, + get_irq_slot_count(pirq_routing_table)); + } +} + +u32 write_pirq_routing_table(u32 addr) +{ + return copy_pirq_routing_table(addr, pirq_routing_table); +} diff --git a/arch/x86/cpu/quark/quark.c b/arch/x86/cpu/quark/quark.c index 4ffa437..7a8f936 100644 --- a/arch/x86/cpu/quark/quark.c +++ b/arch/x86/cpu/quark/quark.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -147,3 +148,10 @@ int cpu_eth_init(bd_t *bis) else return 0; } + +int arch_misc_init(void) +{ + pirq_init(); + + return 0; +} diff --git a/arch/x86/include/asm/arch-quark/device.h b/arch/x86/include/asm/arch-quark/device.h index 4af3ded..7882f33 100644 --- a/arch/x86/include/asm/arch-quark/device.h +++ b/arch/x86/include/asm/arch-quark/device.h @@ -9,20 +9,60 @@ #include -#define QUARK_HOST_BRIDGE PCI_BDF(0, 0, 0) -#define QUARK_MMC_SDIO PCI_BDF(0, 20, 0) -#define QUARK_UART0 PCI_BDF(0, 20, 1) -#define QUARK_USB_DEVICE PCI_BDF(0, 20, 2) -#define QUARK_USB_EHCI PCI_BDF(0, 20, 3) -#define QUARK_USB_OHCI PCI_BDF(0, 20, 4) -#define QUARK_UART1 PCI_BDF(0, 20, 5) -#define QUARK_EMAC0 PCI_BDF(0, 20, 6) -#define QUARK_EMAC1 PCI_BDF(0, 20, 7) -#define QUARK_SPI0 PCI_BDF(0, 21, 0) -#define QUARK_SPI1 PCI_BDF(0, 21, 1) -#define QUARK_I2C_GPIO PCI_BDF(0, 21, 2) -#define QUARK_PCIE0 PCI_BDF(0, 23, 0) -#define QUARK_PCIE1 PCI_BDF(0, 23, 1) -#define QUARK_LEGACY_BRIDGE PCI_BDF(0, 31, 0) +#define QUARK_HOST_BRIDGE_DEV 0 +#define QUARK_HOST_BRIDGE_FUNC 0 + +#define QUARK_DEV_20 20 +#define QUARK_MMC_SDIO_FUNC 0 +#define QUARK_UART0_FUNC 1 +#define QUARK_USB_DEVICE_FUNC 2 +#define QUARK_USB_EHCI_FUNC 3 +#define QUARK_USB_OHCI_FUNC 4 +#define QUARK_UART1_FUNC 5 +#define QUARK_EMAC0_FUNC 6 +#define QUARK_EMAC1_FUNC 7 + +#define QUARK_DEV_21 21 +#define QUARK_SPI0_FUNC 0 +#define QUARK_SPI1_FUNC 1 +#define QUARK_I2C_GPIO_FUNC 2 + +#define QUARK_DEV_23 23 +#define QUARK_PCIE0_FUNC 0 +#define QUARK_PCIE1_FUNC 1 + +#define QUARK_LGC_BRIDGE_DEV 31 +#define QUARK_LGC_BRIDGE_FUNC 0 + +#define QUARK_HOST_BRIDGE \ + PCI_BDF(0, QUARK_HOST_BRIDGE_DEV, QUARK_HOST_BRIDGE_FUNC) +#define QUARK_MMC_SDIO \ + PCI_BDF(0, QUARK_DEV_20, QUARK_MMC_SDIO_FUNC) +#define QUARK_UART0 \ + PCI_BDF(0, QUARK_DEV_20, QUARK_UART0_FUNC) +#define QUARK_USB_DEVICE \ + PCI_BDF(0, QUARK_DEV_20, QUARK_USB_DEVICE_FUNC) +#define QUARK_USB_EHCI \ + PCI_BDF(0, QUARK_DEV_20, QUARK_USB_EHCI_FUNC) +#define QUARK_USB_OHCI \ + PCI_BDF(0, QUARK_DEV_20, QUARK_USB_OHCI_FUNC) +#define QUARK_UART1 \ + PCI_BDF(0, QUARK_DEV_20, QUARK_UART1_FUNC) +#define QUARK_EMAC0 \ + PCI_BDF(0, QUARK_DEV_20, QUARK_EMAC0_FUNC) +#define QUARK_EMAC1 \ + PCI_BDF(0, QUARK_DEV_20, QUARK_EMAC1_FUNC) +#define QUARK_SPI0 \ + PCI_BDF(0, QUARK_DEV_21, QUARK_SPI0_FUNC) +#define QUARK_SPI1 \ + PCI_BDF(0, QUARK_DEV_21, QUARK_SPI1_FUNC) +#define QUARK_I2C_GPIO \ + PCI_BDF(0, QUARK_DEV_21, QUARK_I2C_GPIO_FUNC) +#define QUARK_PCIE0 \ + PCI_BDF(0, QUARK_DEV_23, QUARK_PCIE0_FUNC) +#define QUARK_PCIE1 \ + PCI_BDF(0, QUARK_DEV_23, QUARK_PCIE1_FUNC) +#define QUARK_LEGACY_BRIDGE \ + PCI_BDF(0, QUARK_LGC_BRIDGE_DEV, QUARK_LGC_BRIDGE_FUNC) #endif /* _QUARK_DEVICE_H_ */ diff --git a/arch/x86/include/asm/arch-quark/irq.h b/arch/x86/include/asm/arch-quark/irq.h new file mode 100644 index 0000000..f69fb8c --- /dev/null +++ b/arch/x86/include/asm/arch-quark/irq.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2015, Bin Meng + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _ARCH_IRQ_H_ +#define _ARCH_IRQ_H_ + +enum pci_int_pin { + INTX, + INTA, + INTB, + INTC, + INTD +}; + +enum pirq_pin { + PIRQA, + PIRQB, + PIRQC, + PIRQD, + PIRQE, + PIRQF, + PIRQG, + PIRQH +}; + +/* PIRQ link number and value conversion */ +#define LINK_V2N(link) (link - 0x60) +#define LINK_N2V(link) (link + 0x60) + +#define PIRQ_BITMAP 0xdef8 + +struct irq_info; + +/** + * board_fill_irq_info() - Board-specific irq_info fill routine + * + * This fills the irq_info table for any board-specific add-in cards. + * + * @slot: pointer to the struct irq_info that is to be filled in + * @return: number of entries were written to the struct irq_info + */ +int board_fill_irq_info(struct irq_info *slot); + +/** + * pirq_init() - Initialize platform PIRQ routing + * + * This initializes the PIRQ routing on the platform and configures all PCI + * devices' interrupt line register to a working IRQ number on the 8259 PIC. + */ +void pirq_init(void); + +#endif /* _ARCH_IRQ_H_ */ diff --git a/arch/x86/include/asm/arch-quark/quark.h b/arch/x86/include/asm/arch-quark/quark.h index 6dd02fd..c997928 100644 --- a/arch/x86/include/asm/arch-quark/quark.h +++ b/arch/x86/include/asm/arch-quark/quark.h @@ -76,4 +76,19 @@ #define LB_BC 0xd8 #define LB_RCBA 0xf0 +#ifndef __ASSEMBLY__ + +/* Root Complex Register Block */ +struct quark_rcba { + u32 rctl; + u32 esd; + u32 rsvd1[3150]; + u16 rmu_ir; + u16 d23_ir; + u16 core_ir; + u16 d20d21_ir; +}; + +#endif /* __ASSEMBLY__ */ + #endif /* _QUARK_H_ */ diff --git a/configs/galileo_defconfig b/configs/galileo_defconfig index 9b0f969..0c77278 100644 --- a/configs/galileo_defconfig +++ b/configs/galileo_defconfig @@ -7,3 +7,4 @@ CONFIG_DEFAULT_DEVICE_TREE="galileo" CONFIG_ETH_DESIGNWARE=y CONFIG_NETDEVICES=y CONFIG_NET=y +CONFIG_GENERATE_PIRQ_TABLE=y diff --git a/include/configs/galileo.h b/include/configs/galileo.h index 9b0b650..961d087 100644 --- a/include/configs/galileo.h +++ b/include/configs/galileo.h @@ -15,6 +15,7 @@ #define CONFIG_SYS_MONITOR_LEN (1 << 20) #define CONFIG_BOARD_EARLY_INIT_F +#define CONFIG_ARCH_MISC_INIT #define CONFIG_NR_DRAM_BANKS 1