From patchwork Mon Oct 21 03:38:58 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1180216 X-Patchwork-Delegate: bmeng.cn@gmail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.denx.de (client-ip=81.169.180.215; helo=lists.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=chromium.org Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.b="BbbckLOq"; dkim-atps=neutral Received: from lists.denx.de (dione.denx.de [81.169.180.215]) by ozlabs.org (Postfix) with ESMTP id 46xN3C20Hgz9sPL for ; Mon, 21 Oct 2019 14:51:03 +1100 (AEDT) Received: by lists.denx.de (Postfix, from userid 105) id E11F8C21C2C; Mon, 21 Oct 2019 03:47:54 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=RCVD_IN_MSPIKE_H2, T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id 48BFBC21DA6; Mon, 21 Oct 2019 03:46:23 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 65CEEC21C93; Mon, 21 Oct 2019 03:40:53 +0000 (UTC) Received: from mail-io1-f66.google.com (mail-io1-f66.google.com [209.85.166.66]) by lists.denx.de (Postfix) with ESMTPS id 1CCB2C21DFB for ; Mon, 21 Oct 2019 03:40:52 +0000 (UTC) Received: by mail-io1-f66.google.com with SMTP id 1so2827012iou.4 for ; Sun, 20 Oct 2019 20:40:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=tSPUDno8rloxm80s/rCx5wPLkhNii2vPWlWosKDI5dM=; b=BbbckLOqqpgKlpLU+fmCz8X+ajT2l5irn9lesgZKiJ6m4zJcdM5ayEIlii/NgNwNIC CC+NhbFYpYy7h4lJJZ8kVc3ktB5hzFkUOH/jcDFVGFnN7HSZrWbdx6jP3e3hfLp3hiWw XTOyw8f+4xqEnS6eTs2rbaXdYZ7ZGrtohLEEI= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=tSPUDno8rloxm80s/rCx5wPLkhNii2vPWlWosKDI5dM=; b=S7EB80bT2eTQFXCUI2wGs6pEGQHCLsP+++9aUKLVIimTDn9CNO+QbNvHgD4Kmd/L7y G/VF4e822c0G3vOxWxhvMJ6QiqF6f8ED+FcNuYoXYApCAtJOdmeJPBMsCUSWwiaifPx7 p/6mAsQpveeJjVT4FcdYur6CXSu51NbQ4UoogY466Jk8GhmMYSmrBR7r64SGWkvi9jIM qGNfunJlGtGfT40Jh5kqmODpkilUaOzySl/ITL3kXmIJ03ELoe+9GwZkStgnTqArRdvP UnCtSst4hY5oZB1pT0xksZniZbu7scoT1pxEoFw2efRwtum9pvea4nx8daYVscmZoALV ayxw== X-Gm-Message-State: APjAAAVtTJnSgWML6A3t1r4It/kclJXCdsHF8HvGsQj1+nFXJmqOug4O rqfnL5zkdbLu58xjPNlHp2/jXiuUhQdAag== X-Google-Smtp-Source: APXvYqyfcgRmnp/I8sRZE/qb5tfdStfQBKaXhCgAmDmSa8MLQLBr1UVIyxVNWnEPTxAv+0uZcpyPng== X-Received: by 2002:a5d:824d:: with SMTP id n13mr19168125ioo.152.1571629249597; Sun, 20 Oct 2019 20:40:49 -0700 (PDT) Received: from kiwi.bld.corp.google.com ([2620:15c:183:0:8223:87c:a681:66aa]) by smtp.gmail.com with ESMTPSA id x14sm1947028ion.67.2019.10.20.20.40.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 20 Oct 2019 20:40:48 -0700 (PDT) From: Simon Glass To: U-Boot Mailing List Date: Sun, 20 Oct 2019 21:38:58 -0600 Message-Id: <20191021033913.220758-88-sjg@chromium.org> X-Mailer: git-send-email 2.23.0.866.gb869b98d4c-goog In-Reply-To: <20191021033913.220758-22-sjg@chromium.org> References: <20191021033913.220758-22-sjg@chromium.org> MIME-Version: 1.0 Subject: [U-Boot] [PATCH v3 093/108] x86: apollolake: Add GPIO driver X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 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" Add a driver for the apollolake GPIOs. It also handles pinctrl since this is not very well separated on x86. Signed-off-by: Simon Glass --- Changes in v3: - Fix mixed case in GPIO defines - Rework how pads configuration is defined in TPL and SPL - Use the IRQ uclass instead of ITSS Changes in v2: None arch/x86/cpu/apollolake/Makefile | 1 + arch/x86/cpu/apollolake/gpio.c | 735 ++++++++++++++++++ arch/x86/include/asm/arch-apollolake/gpio.h | 180 +++++ .../include/asm/arch-apollolake/gpio_apl.h | 491 ++++++++++++ .../include/asm/arch-apollolake/gpio_defs.h | 398 ++++++++++ 5 files changed, 1805 insertions(+) create mode 100644 arch/x86/cpu/apollolake/gpio.c create mode 100644 arch/x86/include/asm/arch-apollolake/gpio.h create mode 100644 arch/x86/include/asm/arch-apollolake/gpio_apl.h create mode 100644 arch/x86/include/asm/arch-apollolake/gpio_defs.h diff --git a/arch/x86/cpu/apollolake/Makefile b/arch/x86/cpu/apollolake/Makefile index ff42d0fd619..fa53ea10b79 100644 --- a/arch/x86/cpu/apollolake/Makefile +++ b/arch/x86/cpu/apollolake/Makefile @@ -2,6 +2,7 @@ # # Copyright (c) 2016 Google, Inc +obj-y += gpio.o obj-y += lpss.o obj-y += pmc.o obj-y += uart.o diff --git a/arch/x86/cpu/apollolake/gpio.c b/arch/x86/cpu/apollolake/gpio.c new file mode 100644 index 00000000000..80364006ef0 --- /dev/null +++ b/arch/x86/cpu/apollolake/gpio.c @@ -0,0 +1,735 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2017 Intel Corp. + * Copyright 2019 Google LLC + * + * Taken partly from coreboot gpio.c + */ + +#define LOG_CATEGORY UCLASS_GPIO + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * struct apl_gpio_platdata - platform data for each device + * + * @dtplat: of-platdata data from C struct + * @num_cfgs: Number of configuration words for each pad + * @comm: Pad community for this device + */ +struct apl_gpio_platdata { +#if CONFIG_IS_ENABLED(OF_PLATDATA) + /* Put this first since driver model will copy the data here */ + struct dtd_intel_apl_gpio dtplat; +#endif + int num_cfgs; + const struct pad_community *comm; +}; + +/** struct apl_gpio_priv - private data for each device + * + * @itss: ITSS device (for interrupt handling) + * @itss_pol_cfg: Use to program Interrupt Polarity Control (IPCx) register + * Each bit represents IRQx Active High Polarity Disable configuration: + * when set to 1, the interrupt polarity associated with IRQx is inverted + * to appear as Active Low to IOAPIC and vice versa + */ +struct apl_gpio_priv { + struct udevice *itss; + bool itss_pol_cfg; +}; + +#define GPIO_DWx_SIZE(x) (sizeof(u32) * (x)) +#define PAD_CFG_OFFSET(x, dw_num) ((x) + GPIO_DWx_SIZE(dw_num)) +#define PAD_CFG0_OFFSET(x) PAD_CFG_OFFSET(x, 0) +#define PAD_CFG1_OFFSET(x) PAD_CFG_OFFSET(x, 1) + +#define MISCCFG_GPE0_DW0_SHIFT 8 +#define MISCCFG_GPE0_DW0_MASK (0xf << MISCCFG_GPE0_DW0_SHIFT) +#define MISCCFG_GPE0_DW1_SHIFT 12 +#define MISCCFG_GPE0_DW1_MASK (0xf << MISCCFG_GPE0_DW1_SHIFT) +#define MISCCFG_GPE0_DW2_SHIFT 16 +#define MISCCFG_GPE0_DW2_MASK (0xf << MISCCFG_GPE0_DW2_SHIFT) + +#define GPI_SMI_STS_OFFSET(comm, group) ((comm)->gpi_smi_sts_reg_0 + \ + ((group) * sizeof(u32))) +#define GPI_SMI_EN_OFFSET(comm, group) ((comm)->gpi_smi_en_reg_0 + \ + ((group) * sizeof(u32))) +#define GPI_IS_OFFSET(comm, group) ((comm)->gpi_int_sts_reg_0 + \ + ((group) * sizeof(uint32_t))) +#define GPI_IE_OFFSET(comm, group) ((comm)->gpi_int_en_reg_0 + \ + ((group) * sizeof(uint32_t))) + +static const struct reset_mapping rst_map[] = { + { .logical = PAD_CFG0_LOGICAL_RESET_PWROK, .chipset = 0U << 30 }, + { .logical = PAD_CFG0_LOGICAL_RESET_DEEP, .chipset = 1U << 30 }, + { .logical = PAD_CFG0_LOGICAL_RESET_PLTRST, .chipset = 2U << 30 }, +}; + +static const struct pad_group apl_community_n_groups[] = { + INTEL_GPP(N_OFFSET, N_OFFSET, GPIO_31), /* NORTH 0 */ + INTEL_GPP(N_OFFSET, GPIO_32, JTAG_TRST_B), /* NORTH 1 */ + INTEL_GPP(N_OFFSET, JTAG_TMS, SVID0_CLK), /* NORTH 2 */ +}; + +static const struct pad_group apl_community_w_groups[] = { + INTEL_GPP(W_OFFSET, W_OFFSET, OSC_CLK_OUT_1),/* WEST 0 */ + INTEL_GPP(W_OFFSET, OSC_CLK_OUT_2, SUSPWRDNACK),/* WEST 1 */ +}; + +static const struct pad_group apl_community_sw_groups[] = { + INTEL_GPP(SW_OFFSET, SW_OFFSET, SMB_ALERTB), /* SOUTHWEST 0 */ + INTEL_GPP(SW_OFFSET, SMB_CLK, LPC_FRAMEB), /* SOUTHWEST 1 */ +}; + +static const struct pad_group apl_community_nw_groups[] = { + INTEL_GPP(NW_OFFSET, NW_OFFSET, PROCHOT_B), /* NORTHWEST 0 */ + INTEL_GPP(NW_OFFSET, PMIC_I2C_SCL, GPIO_106),/* NORTHWEST 1 */ + INTEL_GPP(NW_OFFSET, GPIO_109, GPIO_123), /* NORTHWEST 2 */ +}; + +/* TODO(sjg@chromium.org): Consider moving this to device tree */ +static const struct pad_community apl_gpio_communities[] = { + { + .port = PID_GPIO_N, + .first_pad = N_OFFSET, + .last_pad = SVID0_CLK, + .num_gpi_regs = NUM_N_GPI_REGS, + .gpi_status_offset = NUM_NW_GPI_REGS + NUM_W_GPI_REGS + + NUM_SW_GPI_REGS, + .pad_cfg_base = PAD_CFG_BASE, + .host_own_reg_0 = HOSTSW_OWN_REG_0, + .gpi_int_sts_reg_0 = GPI_INT_STS_0, + .gpi_int_en_reg_0 = GPI_INT_EN_0, + .gpi_smi_sts_reg_0 = GPI_SMI_STS_0, + .gpi_smi_en_reg_0 = GPI_SMI_EN_0, + .max_pads_per_group = GPIO_MAX_NUM_PER_GROUP, + .name = "GPIO_GPE_N", + .acpi_path = "\\_SB.GPO0", + .reset_map = rst_map, + .num_reset_vals = ARRAY_SIZE(rst_map), + .groups = apl_community_n_groups, + .num_groups = ARRAY_SIZE(apl_community_n_groups), + }, { + .port = PID_GPIO_NW, + .first_pad = NW_OFFSET, + .last_pad = GPIO_123, + .num_gpi_regs = NUM_NW_GPI_REGS, + .gpi_status_offset = NUM_W_GPI_REGS + NUM_SW_GPI_REGS, + .pad_cfg_base = PAD_CFG_BASE, + .host_own_reg_0 = HOSTSW_OWN_REG_0, + .gpi_int_sts_reg_0 = GPI_INT_STS_0, + .gpi_int_en_reg_0 = GPI_INT_EN_0, + .gpi_smi_sts_reg_0 = GPI_SMI_STS_0, + .gpi_smi_en_reg_0 = GPI_SMI_EN_0, + .max_pads_per_group = GPIO_MAX_NUM_PER_GROUP, + .name = "GPIO_GPE_NW", + .acpi_path = "\\_SB.GPO1", + .reset_map = rst_map, + .num_reset_vals = ARRAY_SIZE(rst_map), + .groups = apl_community_nw_groups, + .num_groups = ARRAY_SIZE(apl_community_nw_groups), + }, { + .port = PID_GPIO_W, + .first_pad = W_OFFSET, + .last_pad = SUSPWRDNACK, + .num_gpi_regs = NUM_W_GPI_REGS, + .gpi_status_offset = NUM_SW_GPI_REGS, + .pad_cfg_base = PAD_CFG_BASE, + .host_own_reg_0 = HOSTSW_OWN_REG_0, + .gpi_int_sts_reg_0 = GPI_INT_STS_0, + .gpi_int_en_reg_0 = GPI_INT_EN_0, + .gpi_smi_sts_reg_0 = GPI_SMI_STS_0, + .gpi_smi_en_reg_0 = GPI_SMI_EN_0, + .max_pads_per_group = GPIO_MAX_NUM_PER_GROUP, + .name = "GPIO_GPE_W", + .acpi_path = "\\_SB.GPO2", + .reset_map = rst_map, + .num_reset_vals = ARRAY_SIZE(rst_map), + .groups = apl_community_w_groups, + .num_groups = ARRAY_SIZE(apl_community_w_groups), + }, { + .port = PID_GPIO_SW, + .first_pad = SW_OFFSET, + .last_pad = LPC_FRAMEB, + .num_gpi_regs = NUM_SW_GPI_REGS, + .gpi_status_offset = 0, + .pad_cfg_base = PAD_CFG_BASE, + .host_own_reg_0 = HOSTSW_OWN_REG_0, + .gpi_int_sts_reg_0 = GPI_INT_STS_0, + .gpi_int_en_reg_0 = GPI_INT_EN_0, + .gpi_smi_sts_reg_0 = GPI_SMI_STS_0, + .gpi_smi_en_reg_0 = GPI_SMI_EN_0, + .max_pads_per_group = GPIO_MAX_NUM_PER_GROUP, + .name = "GPIO_GPE_SW", + .acpi_path = "\\_SB.GPO3", + .reset_map = rst_map, + .num_reset_vals = ARRAY_SIZE(rst_map), + .groups = apl_community_sw_groups, + .num_groups = ARRAY_SIZE(apl_community_sw_groups), + }, +}; + +static size_t relative_pad_in_comm(const struct pad_community *comm, + uint gpio) +{ + return gpio - comm->first_pad; +} + +/* find the group within the community that the pad is a part of */ +static int gpio_group_index(const struct pad_community *comm, uint relative_pad) +{ + int i; + + if (!comm->groups) + return -ESPIPE; + + /* find the base pad number for this pad's group */ + for (i = 0; i < comm->num_groups; i++) { + if (relative_pad >= comm->groups[i].first_pad && + relative_pad < comm->groups[i].first_pad + + comm->groups[i].size) + return i; + } + + return -ENOENT; +} + +static int gpio_group_index_scaled(const struct pad_community *comm, + uint relative_pad, size_t scale) +{ + int ret; + + ret = gpio_group_index(comm, relative_pad); + if (ret < 0) + return ret; + + return ret * scale; +} + +static int gpio_within_group(const struct pad_community *comm, + uint relative_pad) +{ + int ret; + + ret = gpio_group_index(comm, relative_pad); + if (ret < 0) + return ret; + + return relative_pad - comm->groups[ret].first_pad; +} + +static u32 gpio_bitmask_within_group(const struct pad_community *comm, + uint relative_pad) +{ + return 1U << gpio_within_group(comm, relative_pad); +} + +/** + * gpio_get_device() - Find the device for a particular pad + * + * Each GPIO device is attached to one community and this supports a number of + * GPIO pins. This function finds the device which controls a particular pad. + * + * @pad: Pad to check + * @devp: Returns the device for that pad + * @return 0 if OK, -ENOTBLK if no device was found for the given pin + */ +static int gpio_get_device(uint pad, struct udevice **devp) +{ + struct udevice *dev; + + /* + * We have to probe each one of these since the community link is only + * attached in apl_gpio_ofdata_to_platdata(). + */ + uclass_foreach_dev_probe(UCLASS_GPIO, dev) { + struct apl_gpio_platdata *plat = dev_get_platdata(dev); + const struct pad_community *comm = plat->comm; + + if (pad >= comm->first_pad && pad <= comm->last_pad) { + *devp = dev; + return 0; + } + } + printf("pad %d not found\n", pad); + + return -ENOTBLK; +} + +static int gpio_configure_owner(struct udevice *dev, + const struct pad_config *cfg, + const struct pad_community *comm) +{ + u32 hostsw_own; + u16 hostsw_own_offset; + int pin; + int ret; + + pin = relative_pad_in_comm(comm, cfg->pad); + + /* Based on the gpio pin number configure the corresponding bit in + * HOSTSW_OWN register. Value of 0x1 indicates GPIO Driver onwership. + */ + hostsw_own_offset = comm->host_own_reg_0; + ret = gpio_group_index_scaled(comm, pin, sizeof(u32)); + if (ret < 0) + return ret; + hostsw_own_offset += ret; + + hostsw_own = pcr_read32(dev, hostsw_own_offset); + + /* The 4th bit in pad_config 1 (RO) is used to indicate if the pad + * needs GPIO driver ownership. Set the bit if GPIO driver ownership + * requested, otherwise clear the bit. + */ + if (cfg->pad_config[1] & PAD_CFG1_GPIO_DRIVER) + hostsw_own |= gpio_bitmask_within_group(comm, pin); + else + hostsw_own &= ~gpio_bitmask_within_group(comm, pin); + + pcr_write32(dev, hostsw_own_offset, hostsw_own); + + return 0; +} + +static int gpi_enable_smi(struct udevice *dev, const struct pad_config *cfg, + const struct pad_community *comm) +{ + u32 value; + u16 sts_reg; + u16 en_reg; + int group; + int pin; + int ret; + + if ((cfg->pad_config[0] & PAD_CFG0_ROUTE_SMI) != PAD_CFG0_ROUTE_SMI) + return 0; + + pin = relative_pad_in_comm(comm, cfg->pad); + ret = gpio_group_index(comm, pin); + if (ret < 0) + return ret; + group = ret; + + sts_reg = GPI_SMI_STS_OFFSET(comm, group); + value = pcr_read32(dev, sts_reg); + /* Write back 1 to reset the sts bits */ + pcr_write32(dev, sts_reg, value); + + /* Set enable bits */ + en_reg = GPI_SMI_EN_OFFSET(comm, group); + pcr_setbits32(dev, en_reg, gpio_bitmask_within_group(comm, pin)); + + return 0; +} + +static int gpio_configure_itss(struct udevice *dev, + const struct pad_config *cfg, + uint pad_cfg_offset) +{ + struct apl_gpio_priv *priv = dev_get_priv(dev); + + if (!priv->itss_pol_cfg) + return -ENOSYS; + + int irq; + + /* Set up ITSS polarity if pad is routed to APIC. + * + * The ITSS takes only active high interrupt signals. Therefore, + * if the pad configuration indicates an inversion assume the + * intent is for the ITSS polarity. Before forwarding on the + * request to the APIC there's an inversion setting for how the + * signal is forwarded to the APIC. Honor the inversion setting + * in the GPIO pad configuration so that a hardware active low + * signal looks that way to the APIC (double inversion). + */ + if (!(cfg->pad_config[0] & PAD_CFG0_ROUTE_IOAPIC)) + return 0; + + irq = pcr_read32(dev, PAD_CFG1_OFFSET(pad_cfg_offset)); + irq &= PAD_CFG1_IRQ_MASK; + if (!irq) { + log_err("GPIO %u doesn't support APIC routing\n", cfg->pad); + + return -EPROTONOSUPPORT; + } + irq_set_polarity(priv->itss, irq, + cfg->pad_config[0] & PAD_CFG0_RX_POL_INVERT); + + return 0; +} + +/* Number of DWx config registers can be different for different SOCs */ +static uint pad_config_offset(const struct pad_community *comm, uint pad) +{ + size_t offset; + + offset = relative_pad_in_comm(comm, pad); + offset *= GPIO_DWx_SIZE(GPIO_NUM_PAD_CFG_REGS); + + return offset + comm->pad_cfg_base; +} + +static int gpio_pad_reset_config_override(const struct pad_community *comm, + u32 config_value) +{ + const struct reset_mapping *rst_map = comm->reset_map; + int i; + + /* Logical reset values equal chipset values */ + if (!rst_map || !comm->num_reset_vals) + return config_value; + + for (i = 0; i < comm->num_reset_vals; i++, rst_map++) { + if ((config_value & PAD_CFG0_RESET_MASK) == rst_map->logical) { + config_value &= ~PAD_CFG0_RESET_MASK; + config_value |= rst_map->chipset; + + return config_value; + } + } + log_err("Logical-to-Chipset mapping not found\n"); + + return -ENOENT; +} + +static const int mask[4] = { + PAD_CFG0_TX_STATE | + PAD_CFG0_TX_DISABLE | PAD_CFG0_RX_DISABLE | PAD_CFG0_MODE_MASK | + PAD_CFG0_ROUTE_MASK | PAD_CFG0_RXTENCFG_MASK | + PAD_CFG0_RXINV_MASK | PAD_CFG0_PREGFRXSEL | + PAD_CFG0_TRIG_MASK | PAD_CFG0_RXRAW1_MASK | + PAD_CFG0_RXPADSTSEL_MASK | PAD_CFG0_RESET_MASK, + +#ifdef CONFIG_INTEL_GPIO_IOSTANDBY + PAD_CFG1_IOSTERM_MASK | PAD_CFG1_PULL_MASK | PAD_CFG1_IOSSTATE_MASK, +#else + PAD_CFG1_IOSTERM_MASK | PAD_CFG1_PULL_MASK, +#endif + + PAD_CFG2_DEBOUNCE_MASK, + + 0, +}; + +/** + * gpio_configure_pad() - Configure a pad + * + * @dev: GPIO device containing the pad (see gpio_get_device()) + * @cfg: Configuration to apply + * @return 0 if OK, -ve on error + */ +static int gpio_configure_pad(struct udevice *dev, const struct pad_config *cfg) +{ + struct apl_gpio_platdata *plat = dev_get_platdata(dev); + const struct pad_community *comm = plat->comm; + uint config_offset; + u32 pad_conf, soc_pad_conf; + int ret; + int i; + + if (IS_ERR(comm)) + return PTR_ERR(comm); + config_offset = pad_config_offset(comm, cfg->pad); + for (i = 0; i < GPIO_NUM_PAD_CFG_REGS; i++) { + pad_conf = pcr_read32(dev, PAD_CFG_OFFSET(config_offset, i)); + + soc_pad_conf = cfg->pad_config[i]; + if (i == 0) { + ret = gpio_pad_reset_config_override(comm, + soc_pad_conf); + if (ret < 0) + return ret; + soc_pad_conf = ret; + } + soc_pad_conf &= mask[i]; + soc_pad_conf |= pad_conf & ~mask[i]; + + log_debug("gpio_padcfg [0x%02x, %02zd] DW%d [0x%08x : 0x%08x : 0x%08x]\n", + comm->port, relative_pad_in_comm(comm, cfg->pad), i, + pad_conf,/* old value */ + cfg->pad_config[i], /* value passed from gpio table */ + soc_pad_conf); /*new value*/ + pcr_write32(dev, PAD_CFG_OFFSET(config_offset, i), + soc_pad_conf); + } + ret = gpio_configure_itss(dev, cfg, config_offset); + if (ret && ret != -ENOSYS) + return log_msg_ret("itss config failed", ret); + ret = gpio_configure_owner(dev, cfg, comm); + if (ret) + return ret; + ret = gpi_enable_smi(dev, cfg, comm); + if (ret) + return ret; + + return 0; +} + +static u32 get_config_reg_addr(struct udevice *dev, uint offset) +{ + struct apl_gpio_platdata *plat = dev_get_platdata(dev); + const struct pad_community *comm = plat->comm; + uint config_offset; + + config_offset = comm->pad_cfg_base + offset * + GPIO_DWx_SIZE(GPIO_NUM_PAD_CFG_REGS); + + return config_offset; +} + +static u32 get_config_reg(struct udevice *dev, uint offset) +{ + uint config_offset = get_config_reg_addr(dev, offset); + + return pcr_read32(dev, config_offset); +} + +static int apl_gpio_direction_input(struct udevice *dev, uint offset) +{ + uint config_offset = get_config_reg_addr(dev, offset); + + pcr_clrsetbits32(dev, config_offset, + PAD_CFG0_MODE_MASK | PAD_CFG0_TX_STATE | + PAD_CFG0_RX_DISABLE, + PAD_CFG0_MODE_GPIO | PAD_CFG0_TX_DISABLE); + + return 0; +} + +static int apl_gpio_direction_output(struct udevice *dev, uint offset, + int value) +{ + uint config_offset = get_config_reg_addr(dev, offset); + + pcr_clrsetbits32(dev, config_offset, + PAD_CFG0_MODE_MASK | PAD_CFG0_RX_STATE | + PAD_CFG0_TX_DISABLE, + PAD_CFG0_MODE_GPIO | PAD_CFG0_RX_DISABLE | + (value ? PAD_CFG0_TX_STATE : 0)); + + return 0; +} + +static int apl_gpio_get_function(struct udevice *dev, uint offset) +{ + uint mode, rx_tx; + u32 reg; + + reg = get_config_reg(dev, offset); + mode = (reg & PAD_CFG0_MODE_MASK) >> PAD_CFG0_MODE_SHIFT; + if (!mode) { + rx_tx = reg & (PAD_CFG0_TX_DISABLE | PAD_CFG0_RX_DISABLE); + if (rx_tx == PAD_CFG0_TX_DISABLE) + return GPIOF_INPUT; + else if (rx_tx == PAD_CFG0_RX_DISABLE) + return GPIOF_OUTPUT; + } + + return GPIOF_FUNC; +} + +static int apl_gpio_get_value(struct udevice *dev, uint offset) +{ + uint mode, rx_tx; + u32 reg; + + reg = get_config_reg(dev, offset); + mode = (reg & PAD_CFG0_MODE_MASK) >> PAD_CFG0_MODE_SHIFT; + if (!mode) { + rx_tx = reg & (PAD_CFG0_TX_DISABLE | PAD_CFG0_RX_DISABLE); + if (rx_tx == PAD_CFG0_TX_DISABLE) + return mode & PAD_CFG0_RX_STATE_BIT ? 1 : 0; + else if (rx_tx == PAD_CFG0_RX_DISABLE) + return mode & PAD_CFG0_TX_STATE_BIT ? 1 : 0; + } + + return 0; +} + +int gpio_route_gpe(struct udevice *itss, uint gpe0b, uint gpe0c, uint gpe0d) +{ + struct udevice *gpio_dev; + u32 misccfg_value; + u32 misccfg_clr; + int ret; + + /* Get the group here for community specific MISCCFG register. + * If any of these returns -1 then there is some error in devicetree + * where the group is probably hardcoded and does not comply with the + * PMC group defines. So we return from here and MISCFG is set to + * default. + */ + ret = irq_route_pmc_gpio_gpe(itss, gpe0b); + if (ret) + return ret; + gpe0b = ret; + + ret = irq_route_pmc_gpio_gpe(itss, gpe0c); + if (ret) + return ret; + gpe0c = ret; + + ret = irq_route_pmc_gpio_gpe(itss, gpe0d); + if (ret) + return ret; + gpe0d = ret; + + misccfg_value = gpe0b << MISCCFG_GPE0_DW0_SHIFT; + misccfg_value |= gpe0c << MISCCFG_GPE0_DW1_SHIFT; + misccfg_value |= gpe0d << MISCCFG_GPE0_DW2_SHIFT; + + /* Program GPIO_MISCCFG */ + misccfg_clr = MISCCFG_GPE0_DW2_MASK | MISCCFG_GPE0_DW1_MASK | + MISCCFG_GPE0_DW0_MASK; + + log_debug("misccfg_clr:%x misccfg_value:%x\n", misccfg_clr, + misccfg_value); + uclass_foreach_dev_probe(UCLASS_GPIO, gpio_dev) { + pcr_clrsetbits32(gpio_dev, GPIO_MISCCFG, misccfg_clr, + misccfg_value); + } + + return 0; +} + +int gpio_gpi_clear_int_cfg(void) +{ + struct udevice *dev; + struct uclass *uc; + int ret; + + ret = uclass_get(UCLASS_GPIO, &uc); + if (ret) + return log_msg_ret("gpio uc", ret); + uclass_foreach_dev(dev, uc) { + struct apl_gpio_platdata *plat = dev_get_platdata(dev); + const struct pad_community *comm = plat->comm; + uint sts_value; + int group; + + for (group = 0; group < comm->num_gpi_regs; group++) { + /* Clear the enable register */ + pcr_write32(dev, GPI_IE_OFFSET(comm, group), 0); + + /* Read and clear the set status register bits*/ + sts_value = pcr_read32(dev, + GPI_IS_OFFSET(comm, group)); + pcr_write32(dev, GPI_IS_OFFSET(comm, group), sts_value); + } + } + + return 0; +} + +int gpio_config_pads(struct udevice *dev, int num_cfgs, u32 *pads, + int pads_count) +{ + const u32 *ptr; + int i; + + log_debug("%s: pads_count=%d\n", __func__, pads_count); + for (ptr = pads, i = 0; i < pads_count; ptr += 1 + num_cfgs, i++) { + struct udevice *pad_dev = NULL; + struct pad_config *cfg; + int ret; + + cfg = (struct pad_config *)ptr; + ret = gpio_get_device(cfg->pad, &pad_dev); + if (ret) + return ret; + ret = gpio_configure_pad(pad_dev, cfg); + if (ret) + return ret; + } + + return 0; +} + +static int apl_gpio_ofdata_to_platdata(struct udevice *dev) +{ + struct apl_gpio_platdata *plat = dev_get_platdata(dev); + struct apl_gpio_priv *priv = dev_get_priv(dev); + struct p2sb_child_platdata *pplat; + int ret; + int i; + + plat->num_cfgs = 2; +#if CONFIG_IS_ENABLED(OF_PLATDATA) + /* + * It would be nice to do this in the bind() method, but with + * of-platdata binding happens in the order that DM finds things in the + * linker list (i.e. alphabetical order by driver name). So the GPIO + * device may well be bound before its parent (p2sb), and this call + * will fail if p2sb is not bound yet. + * + * TODO(sjg@chromium.org): Add a parent pointer to child devices in dtoc + */ + ret = p2sb_set_port_id(dev, plat->dtplat.intel_p2sb_port_id); + if (ret) + return log_msg_ret("Could not set port id", ret); +#endif + /* Attach this device to its community structure */ + pplat = dev_get_parent_platdata(dev); + for (i = 0; i < ARRAY_SIZE(apl_gpio_communities); i++) { + if (apl_gpio_communities[i].port == pplat->pid) + plat->comm = &apl_gpio_communities[i]; + } + if (!plat->comm) { + log_err("Cannot find community for pid %d\n", pplat->pid); + return -EDOM; + } + ret = uclass_first_device_err(UCLASS_IRQ, &priv->itss); + if (ret) + return log_msg_ret("Cannot find ITSS", ret); + + return 0; +} + +static int apl_gpio_probe(struct udevice *dev) +{ + struct gpio_dev_priv *upriv = dev_get_uclass_priv(dev); + struct apl_gpio_platdata *plat = dev_get_platdata(dev); + struct apl_gpio_priv *priv = dev_get_priv(dev); + const struct pad_community *comm = plat->comm; + + upriv->gpio_count = comm->last_pad - comm->first_pad + 1; + upriv->bank_name = dev->name; + priv->itss_pol_cfg = true; + + return 0; +} + +static const struct dm_gpio_ops apl_gpio_ops = { + .get_function = apl_gpio_get_function, + .get_value = apl_gpio_get_value, + .direction_input = apl_gpio_direction_input, + .direction_output = apl_gpio_direction_output, +}; + +static const struct udevice_id apl_gpio_ids[] = { + { .compatible = "intel,apl-gpio"}, + { } +}; + +U_BOOT_DRIVER(apl_gpio_drv) = { + .name = "intel_apl_gpio", + .id = UCLASS_GPIO, + .of_match = apl_gpio_ids, + .probe = apl_gpio_probe, + .ops = &apl_gpio_ops, + .ofdata_to_platdata = apl_gpio_ofdata_to_platdata, + .priv_auto_alloc_size = sizeof(struct apl_gpio_priv), + .platdata_auto_alloc_size = sizeof(struct apl_gpio_platdata), +}; diff --git a/arch/x86/include/asm/arch-apollolake/gpio.h b/arch/x86/include/asm/arch-apollolake/gpio.h new file mode 100644 index 00000000000..19421950e61 --- /dev/null +++ b/arch/x86/include/asm/arch-apollolake/gpio.h @@ -0,0 +1,180 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2017 Intel Corporation. + * Copyright 2019 Google LLC + * + * Modified from coreboot gpio.h + */ + +#ifndef __ASM_ARCH_GPIO_H +#define __ASM_ARCH_GPIO_H + +/** + * struct pad_config - config for a pad + * @pad: offset of pad within community + * @pad_config: Pad config data corresponding to DW0, DW1, etc. + */ +struct pad_config { + int pad; + u32 pad_config[4]; +}; + +#include + +/* GPIO community IOSF sideband clock gating */ +#define MISCCFG_GPSIDEDPCGEN BIT(5) +/* GPIO community RCOMP clock gating */ +#define MISCCFG_GPRCOMPCDLCGEN BIT(4) +/* GPIO community RTC clock gating */ +#define MISCCFG_GPRTCDLCGEN BIT(3) +/* GFX controller clock gating */ +#define MISCCFG_GSXSLCGEN BIT(2) +/* GPIO community partition clock gating */ +#define MISCCFG_GPDPCGEN BIT(1) +/* GPIO community local clock gating */ +#define MISCCFG_GPDLCGEN BIT(0) +/* Enable GPIO community power management configuration */ +#define MISCCFG_ENABLE_GPIO_PM_CONFIG (MISCCFG_GPSIDEDPCGEN | \ + MISCCFG_GPRCOMPCDLCGEN | MISCCFG_GPRTCDLCGEN | MISCCFG_GSXSLCGEN \ + | MISCCFG_GPDPCGEN | MISCCFG_GPDLCGEN) + +/* + * GPIO numbers may not be contiguous and instead will have a different + * starting pin number for each pad group. + */ +#define INTEL_GPP_BASE(first_of_community, start_of_group, end_of_group,\ + group_pad_base) \ + { \ + .first_pad = (start_of_group) - (first_of_community), \ + .size = (end_of_group) - (start_of_group) + 1, \ + .acpi_pad_base = (group_pad_base), \ + } + +/* + * A pad base of -1 indicates that this group uses contiguous numbering + * and a pad base should not be used for this group. + */ +#define PAD_BASE_NONE -1 + +/* The common/default group numbering is contiguous */ +#define INTEL_GPP(first_of_community, start_of_group, end_of_group) \ + INTEL_GPP_BASE(first_of_community, start_of_group, end_of_group,\ + PAD_BASE_NONE) + +/** + * struct reset_mapping - logical to actual value for PADRSTCFG in DW0 + * + * Note that the values are expected to be within the field placement of the + * register itself. i.e. if the reset field is at 31:30 then the values within + * logical and chipset should occupy 31:30. + */ +struct reset_mapping { + u32 logical; + u32 chipset; +}; + +/** + * struct pad_group - describes the groups within each community + * + * @first_pad: offset of first pad of the group relative to the community + * @size: size of the group + * @acpi_pad_base: starting pin number for the pads in this group when they are + * used in ACPI. This is only needed if the pins are not contiguous across + * groups. Most groups will have this set to PAD_BASE_NONE and use + * contiguous numbering for ACPI. + */ +struct pad_group { + int first_pad; + uint size; + int acpi_pad_base; +}; + +/** + * struct pad_community - GPIO community + * + * This describes a community, or each group within a community when multiple + * groups exist inside a community + * + * @name: Community name + * @acpi_path: ACPI path + * @num_gpi_regs: number of gpi registers in community + * @max_pads_per_group: number of pads in each group; number of pads bit-mapped + * in each GPI status/en and Host Own Reg + * @first_pad: first pad in community + * @last_pad: last pad in community + * @host_own_reg_0: offset to Host Ownership Reg 0 + * @gpi_int_sts_reg_0: offset to GPI Int STS Reg 0 + * @gpi_int_en_reg_0: offset to GPI Int Enable Reg 0 + * @gpi_smi_sts_reg_0: offset to GPI SMI STS Reg 0 + * @gpi_smi_en_reg_0: offset to GPI SMI EN Reg 0 + * @pad_cfg_base: offset to first PAD_GFG_DW0 Reg + * @gpi_status_offset: specifies offset in struct gpi_status + * @port: PCR Port ID + * @reset_map: PADRSTCFG logical to chipset mapping + * @num_reset_vals: number of values in @reset_map + * @groups; list of groups for this community + * @num_groups: number of groups + */ +struct pad_community { + const char *name; + const char *acpi_path; + size_t num_gpi_regs; + size_t max_pads_per_group; + uint first_pad; + uint last_pad; + u16 host_own_reg_0; + u16 gpi_int_sts_reg_0; + u16 gpi_int_en_reg_0; + u16 gpi_smi_sts_reg_0; + u16 gpi_smi_en_reg_0; + u16 pad_cfg_base; + u8 gpi_status_offset; + u8 port; + const struct reset_mapping *reset_map; + size_t num_reset_vals; + const struct pad_group *groups; + size_t num_groups; +}; + +/** + * gpio_route_gpe() - set the GPIO groups for the general-purpose-event blocks + * + * The values from PMC register GPE_CFG are passed which is then mapped to + * proper groups for MISCCFG. This basically sets the MISCCFG register bits: + * dw0 = gpe0_route[11:8]. This is ACPI GPE0b. + * dw1 = gpe0_route[15:12]. This is ACPI GPE0c. + * dw2 = gpe0_route[19:16]. This is ACPI GPE0d. + * + * @dev: ITSS device + * @gpe0b: Value for GPE0B + * @gpe0c: Value for GPE0C + * @gpe0d: Value for GPE0D + * @return 0 if OK, -ve on error + */ +int gpio_route_gpe(struct udevice *dev, uint gpe0b, uint gpe0c, uint gpe0d); + +/** + * gpio_config_pads() - Configure a list of pads + * + * Configures multiple pads using the provided data from the device tree. + * + * @dev: GPIO device (any will do) + * @num_cfgs: Number of configuration words for each pad (e.g. 2) + * @pads: Pad data, consisting of a pad number followed by @num_cfgs entries + * containing the data for that pad + * @pads_count: Number of pads to configure + * @return 0 if OK, -ve on error + */ +int gpio_config_pads(struct udevice *dev, int num_cfgs, u32 *pads, + int pads_count); + +/** + * gpio_gpi_clear_int_cfg() - Set up the interrupts for use + * + * This enables the interrupt inputs and clears the status register bits + * + * @return 0 if OK, -ve on error + */ +int gpio_gpi_clear_int_cfg(void); + +#endif diff --git a/arch/x86/include/asm/arch-apollolake/gpio_apl.h b/arch/x86/include/asm/arch-apollolake/gpio_apl.h new file mode 100644 index 00000000000..0706a5a34a9 --- /dev/null +++ b/arch/x86/include/asm/arch-apollolake/gpio_apl.h @@ -0,0 +1,491 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Definitions for the GPIO subsystem on Apollolake + * + * Placed in a separate file since some of these definitions can be used from + * assembly code + * + * This file is part of the coreboot project. + * + * Copyright (C) 2015 - 2017 Intel Corp. + * (Written by Alexandru Gagniuc for Intel Corp.) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _SOC_APOLLOLAKE_GPIO_H_ +#define _SOC_APOLLOLAKE_GPIO_H_ + +/* + * Miscellaneous Configuration register(MISCCFG).These are community-specific + * registers and are meant to house miscellaneous configuration fields per + * community. There are 8 GPIO groups: GPP_0 -> GPP_8 (Group 3 is absent) + */ +#define GPIO_MISCCFG 0x10 /* Miscellaneous Configuration offset */ +#define GPIO_GPE_SW_31_0 0 /* SOUTHWEST GPIO# 0 ~ 31 belong to GROUP0 */ +#define GPIO_GPE_SW_63_32 1 /* SOUTHWEST GPIO# 32 ~ 42 belong to GROUP1 */ +#define GPIO_GPE_W_31_0 2 /* WEST GPIO# 0 ~ 25 belong to GROUP2 */ +#define GPIO_GPE_NW_31_0 4 /* NORTHWEST GPIO# 0 ~ 17 belong to GROUP4 */ +#define GPIO_GPE_NW_63_32 5 /* NORTHWEST GPIO# 32 ~ 63 belong to GROUP5 */ +#define GPIO_GPE_NW_95_64 6 /* NORTHWEST GPIO# 64 ~ 76 belong to GROUP6 */ +#define GPIO_GPE_N_31_0 7 /* NORTH GPIO# 0 ~ 31 belong to GROUP7 */ +#define GPIO_GPE_N_63_32 8 /* NORTH GPIO# 32 ~ 61 belong to GROUP8 */ + +#define GPIO_MAX_NUM_PER_GROUP 32 + +/* Host Software Pad Ownership Register. + * The pins in the community are divided into 3 groups : + * GPIO 0 ~ 31, GPIO 32 ~ 63, GPIO 64 ~ 95 + */ +#define HOSTSW_OWN_REG_0 0x80 + +#define PAD_CFG_BASE 0x500 + +#define GPI_INT_STS_0 0x100 +#define GPI_INT_EN_0 0x110 + +#define GPI_SMI_STS_0 0x140 +#define GPI_SMI_EN_0 0x150 + +#define NUM_N_PADS (PAD_N(SVID0_CLK) + 1) +#define NUM_NW_PADS (PAD_NW(GPIO_123) + 1) +#define NUM_W_PADS (PAD_W(SUSPWRDNACK) + 1) +#define NUM_SW_PADS (PAD_SW(LPC_FRAMEB) + 1) + +#define NUM_N_GPI_REGS \ + (ALIGN(NUM_N_PADS, GPIO_MAX_NUM_PER_GROUP) / GPIO_MAX_NUM_PER_GROUP) + +#define NUM_NW_GPI_REGS \ + (ALIGN(NUM_NW_PADS, GPIO_MAX_NUM_PER_GROUP) / GPIO_MAX_NUM_PER_GROUP) + +#define NUM_W_GPI_REGS \ + (ALIGN(NUM_W_PADS, GPIO_MAX_NUM_PER_GROUP) / GPIO_MAX_NUM_PER_GROUP) + +#define NUM_SW_GPI_REGS \ + (ALIGN(NUM_SW_PADS, GPIO_MAX_NUM_PER_GROUP) / GPIO_MAX_NUM_PER_GROUP) + +/* + * Total number of GPI status registers across all GPIO communities in the SOC + */ +#define NUM_GPI_STATUS_REGS (NUM_N_GPI_REGS + NUM_NW_GPI_REGS \ + + NUM_W_GPI_REGS + NUM_SW_GPI_REGS) + +/* North community pads */ +#define GPIO_0 0 +#define GPIO_1 1 +#define GPIO_2 2 +#define GPIO_3 3 +#define GPIO_4 4 +#define GPIO_5 5 +#define GPIO_6 6 +#define GPIO_7 7 +#define GPIO_8 8 +#define GPIO_9 9 +#define GPIO_10 10 +#define GPIO_11 11 +#define GPIO_12 12 +#define GPIO_13 13 +#define GPIO_14 14 +#define GPIO_15 15 +#define GPIO_16 16 +#define GPIO_17 17 +#define GPIO_18 18 +#define GPIO_19 19 +#define GPIO_20 20 +#define GPIO_21 21 +#define GPIO_22 22 +#define GPIO_23 23 +#define GPIO_24 24 +#define GPIO_25 25 +#define GPIO_26 26 +#define GPIO_27 27 +#define GPIO_28 28 +#define GPIO_29 29 +#define GPIO_30 30 +#define GPIO_31 31 +#define GPIO_32 32 +#define GPIO_33 33 +#define GPIO_34 34 +#define GPIO_35 35 +#define GPIO_36 36 +#define GPIO_37 37 +#define GPIO_38 38 +#define GPIO_39 39 +#define GPIO_40 40 +#define GPIO_41 41 +#define GPIO_42 42 +#define GPIO_43 43 +#define GPIO_44 44 +#define GPIO_45 45 +#define GPIO_46 46 +#define GPIO_47 47 +#define GPIO_48 48 +#define GPIO_49 49 +#define GPIO_62 50 +#define GPIO_63 51 +#define GPIO_64 52 +#define GPIO_65 53 +#define GPIO_66 54 +#define GPIO_67 55 +#define GPIO_68 56 +#define GPIO_69 57 +#define GPIO_70 58 +#define GPIO_71 59 +#define GPIO_72 60 +#define GPIO_73 61 +#define JTAG_TCK 62 +#define JTAG_TRST_B 63 +#define JTAG_TMS 64 +#define JTAG_TDI 65 +#define JTAG_CX_PMODE 66 +#define JTAG_CX_PREQ_B 67 +#define JTAGX 68 +#define JTAG_CX_PRDY_B 69 +#define JTAG_TDO 70 +#define CNV_BRI_DT 71 +#define CNV_BRI_RSP 72 +#define CNV_RGI_DT 73 +#define CNV_RGI_RSP 74 +#define SVID0_ALERT_B 75 +#define SVID0_DATA 76 +#define SVID0_CLK 77 + +/* Northwest community pads */ +#define GPIO_187 78 +#define GPIO_188 79 +#define GPIO_189 80 +#define GPIO_190 81 +#define GPIO_191 82 +#define GPIO_192 83 +#define GPIO_193 84 +#define GPIO_194 85 +#define GPIO_195 86 +#define GPIO_196 87 +#define GPIO_197 88 +#define GPIO_198 89 +#define GPIO_199 90 +#define GPIO_200 91 +#define GPIO_201 92 +#define GPIO_202 93 +#define GPIO_203 94 +#define GPIO_204 95 +#define PMC_SPI_FS0 96 +#define PMC_SPI_FS1 97 +#define PMC_SPI_FS2 98 +#define PMC_SPI_RXD 99 +#define PMC_SPI_TXD 100 +#define PMC_SPI_CLK 101 +#define PMIC_PWRGOOD 102 +#define PMIC_RESET_B 103 +#define GPIO_213 104 +#define GPIO_214 105 +#define GPIO_215 106 +#define PMIC_THERMTRIP_B 107 +#define PMIC_STDBY 108 +#define PROCHOT_B 109 +#define PMIC_I2C_SCL 110 +#define PMIC_I2C_SDA 111 +#define GPIO_74 112 +#define GPIO_75 113 +#define GPIO_76 114 +#define GPIO_77 115 +#define GPIO_78 116 +#define GPIO_79 117 +#define GPIO_80 118 +#define GPIO_81 119 +#define GPIO_82 120 +#define GPIO_83 121 +#define GPIO_84 122 +#define GPIO_85 123 +#define GPIO_86 124 +#define GPIO_87 125 +#define GPIO_88 126 +#define GPIO_89 127 +#define GPIO_90 128 +#define GPIO_91 129 +#define GPIO_92 130 +#define GPIO_97 131 +#define GPIO_98 132 +#define GPIO_99 133 +#define GPIO_100 134 +#define GPIO_101 135 +#define GPIO_102 136 +#define GPIO_103 137 +#define FST_SPI_CLK_FB 138 +#define GPIO_104 139 +#define GPIO_105 140 +#define GPIO_106 141 +#define GPIO_109 142 +#define GPIO_110 143 +#define GPIO_111 144 +#define GPIO_112 145 +#define GPIO_113 146 +#define GPIO_116 147 +#define GPIO_117 148 +#define GPIO_118 149 +#define GPIO_119 150 +#define GPIO_120 151 +#define GPIO_121 152 +#define GPIO_122 153 +#define GPIO_123 154 + +/* West community pads */ +#define GPIO_124 155 +#define GPIO_125 156 +#define GPIO_126 157 +#define GPIO_127 158 +#define GPIO_128 159 +#define GPIO_129 160 +#define GPIO_130 161 +#define GPIO_131 162 +#define GPIO_132 163 +#define GPIO_133 164 +#define GPIO_134 165 +#define GPIO_135 166 +#define GPIO_136 167 +#define GPIO_137 168 +#define GPIO_138 169 +#define GPIO_139 170 +#define GPIO_146 171 +#define GPIO_147 172 +#define GPIO_148 173 +#define GPIO_149 174 +#define GPIO_150 175 +#define GPIO_151 176 +#define GPIO_152 177 +#define GPIO_153 178 +#define GPIO_154 179 +#define GPIO_155 180 +#define GPIO_209 181 +#define GPIO_210 182 +#define GPIO_211 183 +#define GPIO_212 184 +#define OSC_CLK_OUT_0 185 +#define OSC_CLK_OUT_1 186 +#define OSC_CLK_OUT_2 187 +#define OSC_CLK_OUT_3 188 +#define OSC_CLK_OUT_4 189 +#define PMU_AC_PRESENT 190 +#define PMU_BATLOW_B 191 +#define PMU_PLTRST_B 192 +#define PMU_PWRBTN_B 193 +#define PMU_RESETBUTTON_B 194 +#define PMU_SLP_S0_B 195 +#define PMU_SLP_S3_B 196 +#define PMU_SLP_S4_B 197 +#define PMU_SUSCLK 198 +#define PMU_WAKE_B 199 +#define SUS_STAT_B 200 +#define SUSPWRDNACK 201 + +/* Southwest community pads */ +#define GPIO_205 202 +#define GPIO_206 203 +#define GPIO_207 204 +#define GPIO_208 205 +#define GPIO_156 206 +#define GPIO_157 207 +#define GPIO_158 208 +#define GPIO_159 209 +#define GPIO_160 210 +#define GPIO_161 211 +#define GPIO_162 212 +#define GPIO_163 213 +#define GPIO_164 214 +#define GPIO_165 215 +#define GPIO_166 216 +#define GPIO_167 217 +#define GPIO_168 218 +#define GPIO_169 219 +#define GPIO_170 220 +#define GPIO_171 221 +#define GPIO_172 222 +#define GPIO_179 223 +#define GPIO_173 224 +#define GPIO_174 225 +#define GPIO_175 226 +#define GPIO_176 227 +#define GPIO_177 228 +#define GPIO_178 229 +#define GPIO_186 230 +#define GPIO_182 231 +#define GPIO_183 232 +#define SMB_ALERTB 233 +#define SMB_CLK 234 +#define SMB_DATA 235 +#define LPC_ILB_SERIRQ 236 +#define LPC_CLKOUT0 237 +#define LPC_CLKOUT1 238 +#define LPC_AD0 239 +#define LPC_AD1 240 +#define LPC_AD2 241 +#define LPC_AD3 242 +#define LPC_CLKRUNB 243 +#define LPC_FRAMEB 244 + +/* PERST_0 not defined */ +#define GPIO_PRT0_UDEF 0xFF + +#define TOTAL_PADS 245 +#define N_OFFSET GPIO_0 +#define NW_OFFSET GPIO_187 +#define W_OFFSET GPIO_124 +#define SW_OFFSET GPIO_205 + +/* Macros for translating a global pad offset to a local offset */ +#define PAD_N(pad) (pad - N_OFFSET) +#define PAD_NW(pad) (pad - NW_OFFSET) +#define PAD_W(pad) (pad - W_OFFSET) +#define PAD_SW(pad) (pad - SW_OFFSET) + +/* Linux names of the GPIO devices */ +#define GPIO_COMM_N_NAME "INT3452:00" +#define GPIO_COMM_NW_NAME "INT3452:01" +#define GPIO_COMM_W_NAME "INT3452:02" +#define GPIO_COMM_SW_NAME "INT3452:03" + +/* Following is used in gpio asl */ +#define GPIO_COMM_NAME "INT3452" +#define GPIO_COMM_0_DESC \ + "General Purpose Input/Output (GPIO) Controller - North" +#define GPIO_COMM_1_DESC \ + "General Purpose Input/Output (GPIO) Controller - Northwest" +#define GPIO_COMM_2_DESC \ + "General Purpose Input/Output (GPIO) Controller - West" +#define GPIO_COMM_3_DESC \ + "General Purpose Input/Output (GPIO) Controller - Southwest" + +#define GPIO_COMM0_PID PID_GPIO_N +#define GPIO_COMM1_PID PID_GPIO_NW +#define GPIO_COMM2_PID PID_GPIO_W +#define GPIO_COMM3_PID PID_GPIO_SW + +/* + * IOxAPIC IRQs for the GPIOs, overlap is expected as we encourage to use + * shared IRQ instead of direct IRQ, in case of overlapping, we can easily + * program one of the overlap to shared IRQ to avoid the conflict. + */ + +/* NorthWest community pads */ +#define PMIC_I2C_SDA_IRQ 0x32 +#define GPIO_74_IRQ 0x33 +#define GPIO_75_IRQ 0x34 +#define GPIO_76_IRQ 0x35 +#define GPIO_77_IRQ 0x36 +#define GPIO_78_IRQ 0x37 +#define GPIO_79_IRQ 0x38 +#define GPIO_80_IRQ 0x39 +#define GPIO_81_IRQ 0x3A +#define GPIO_82_IRQ 0x3B +#define GPIO_83_IRQ 0x3C +#define GPIO_84_IRQ 0x3D +#define GPIO_85_IRQ 0x3E +#define GPIO_86_IRQ 0x3F +#define GPIO_87_IRQ 0x40 +#define GPIO_88_IRQ 0x41 +#define GPIO_89_IRQ 0x42 +#define GPIO_90_IRQ 0x43 +#define GPIO_91_IRQ 0x44 +#define GPIO_97_IRQ 0x49 +#define GPIO_98_IRQ 0x4A +#define GPIO_99_IRQ 0x4B +#define GPIO_100_IRQ 0x4C +#define GPIO_101_IRQ 0x4D +#define GPIO_102_IRQ 0x4E +#define GPIO_103_IRQ 0x4F +#define GPIO_104_IRQ 0x50 +#define GPIO_105_IRQ 0x51 +#define GPIO_106_IRQ 0x52 +#define GPIO_109_IRQ 0x54 +#define GPIO_110_IRQ 0x55 +#define GPIO_111_IRQ 0x56 +#define GPIO_112_IRQ 0x57 +#define GPIO_113_IRQ 0x58 +#define GPIO_116_IRQ 0x5B +#define GPIO_117_IRQ 0x5C +#define GPIO_118_IRQ 0x5D +#define GPIO_119_IRQ 0x5E +#define GPIO_120_IRQ 0x5F +#define GPIO_121_IRQ 0x60 +#define GPIO_122_IRQ 0x61 +#define GPIO_123_IRQ 0x62 + +/* North community pads */ +#define GPIO_0_IRQ 0x63 +#define GPIO_1_IRQ 0x64 +#define GPIO_2_IRQ 0x65 +#define GPIO_3_IRQ 0x66 +#define GPIO_4_IRQ 0x67 +#define GPIO_5_IRQ 0x68 +#define GPIO_6_IRQ 0x69 +#define GPIO_7_IRQ 0x6A +#define GPIO_8_IRQ 0x6B +#define GPIO_9_IRQ 0x6C +#define GPIO_10_IRQ 0x6D +#define GPIO_11_IRQ 0x6E +#define GPIO_12_IRQ 0x6F +#define GPIO_13_IRQ 0x70 +#define GPIO_14_IRQ 0x71 +#define GPIO_15_IRQ 0x72 +#define GPIO_16_IRQ 0x73 +#define GPIO_17_IRQ 0x74 +#define GPIO_18_IRQ 0x75 +#define GPIO_19_IRQ 0x76 +#define GPIO_20_IRQ 0x77 +#define GPIO_21_IRQ 0x32 +#define GPIO_22_IRQ 0x33 +#define GPIO_23_IRQ 0x34 +#define GPIO_24_IRQ 0x35 +#define GPIO_25_IRQ 0x36 +#define GPIO_26_IRQ 0x37 +#define GPIO_27_IRQ 0x38 +#define GPIO_28_IRQ num_reset_vals0x39 +#define GPIO_29_IRQ 0x3A +#define GPIO_30_IRQ 0x3B +#define GPIO_31_IRQ 0x3C +#define GPIO_32_IRQ 0x3D +#define GPIO_33_IRQ 0x3E +#define GPIO_34_IRQ 0x3F +#define GPIO_35_IRQ 0x40 +#define GPIO_36_IRQ 0x41 +#define GPIO_37_IRQ 0x42 +#define GPIO_38_IRQ 0x43 +#define GPIO_39_IRQ 0x44 +#define GPIO_40_IRQ 0x45 +#define GPIO_41_IRQ 0x46 +#define GPIO_42_IRQ 0x47 +#define GPIO_43_IRQ 0x48 +#define GPIO_44_IRQ 0x49 +#define GPIO_45_IRQ 0x4A +#define GPIO_46_IRQ 0x4B +#define GPIO_47_IRQ 0x4C +#define GPIO_48_IRQ 0x4D +#define GPIO_49_IRQ 0x4E +#define GPIO_62_IRQ 0x5B +#define GPIO_63_IRQ 0x5C +#define GPIO_64_IRQ 0x5D +#define GPIO_65_IRQ 0x5E +#define GPIO_66_IRQ 0x5F +#define GPIO_67_IRQ 0x60 +#define GPIO_68_IRQ 0x61 +#define GPIO_69_IRQ 0x62 +#define GPIO_70_IRQ 0x63 +#define GPIO_71_IRQ 0x64 +#define GPIO_72_IRQ 0x65 +#define GPIO_73_IRQ 0x66 + +/* + * Number of PAD config registers in the Soc that have DW0 and DW1. It should + * be 2. + */ +#define GPIO_NUM_PAD_CFG_REGS 2 /* DW0, DW1 */ + +#endif /* _SOC_APOLLOLAKE_GPIO_H_ */ diff --git a/arch/x86/include/asm/arch-apollolake/gpio_defs.h b/arch/x86/include/asm/arch-apollolake/gpio_defs.h new file mode 100644 index 00000000000..5f8ab71ab47 --- /dev/null +++ b/arch/x86/include/asm/arch-apollolake/gpio_defs.h @@ -0,0 +1,398 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2015-2016 Intel Corp. + * Copyright 2019 Google LLC + * + * Modified from coreboot gpio_defs.h + */ + +#ifndef _ASM_ARCH_GPIO_DEFS_H_ +#define _ASM_ARCH_GPIO_DEFS_H_ + +/* Port ids */ +#if IS_ENABLED(CONFIG_SOC_INTEL_GLK) +#define PID_GPIO_AUDIO 0xC9 +#define PID_GPIO_SCC 0xC8 +#else +#define PID_GPIO_SW 0xC0 +#define PID_GPIO_S 0xC2 +#define PID_GPIO_W 0xC7 +#endif +#define PID_GPIO_NW 0xC4 +#define PID_GPIO_N 0xC5 +#define PID_ITSS 0xD0 +#define PID_RTC 0xD1 + +#define PAD_CFG0_TX_STATE_BIT 0 +#define PAD_CFG0_TX_STATE (1 << PAD_CFG0_TX_STATE_BIT) +#define PAD_CFG0_RX_STATE_BIT 1 +#define PAD_CFG0_RX_STATE (1 << PAD_CFG0_RX_STATE_BIT) +#define PAD_CFG0_TX_DISABLE (1 << 8) +#define PAD_CFG0_RX_DISABLE (1 << 9) + +#define PAD_CFG0_MODE_SHIFT 10 +#define PAD_CFG0_MODE_MASK (7 << PAD_CFG0_MODE_SHIFT) +#define PAD_CFG0_MODE_GPIO (0 << PAD_CFG0_MODE_SHIFT) +#define PAD_CFG0_MODE_NF1 (1 << PAD_CFG0_MODE_SHIFT) +#define PAD_CFG0_MODE_NF2 (2 << PAD_CFG0_MODE_SHIFT) +#define PAD_CFG0_MODE_NF3 (3 << PAD_CFG0_MODE_SHIFT) +#define PAD_CFG0_MODE_NF4 (4 << PAD_CFG0_MODE_SHIFT) +#define PAD_CFG0_MODE_NF5 (5 << PAD_CFG0_MODE_SHIFT) +#define PAD_CFG0_MODE_NF6 (6 << PAD_CFG0_MODE_SHIFT) + +#define PAD_CFG0_ROUTE_MASK (0xf << 17) +#define PAD_CFG0_ROUTE_NMI (1 << 17) +#define PAD_CFG0_ROUTE_SMI (1 << 18) +#define PAD_CFG0_ROUTE_SCI (1 << 19) +#define PAD_CFG0_ROUTE_IOAPIC (1 << 20) +#define PAD_CFG0_RXTENCFG_MASK (3 << 21) +#define PAD_CFG0_RXINV_MASK (1 << 23) +#define PAD_CFG0_RX_POL_INVERT (1 << 23) +#define PAD_CFG0_RX_POL_NONE (0 << 23) +#define PAD_CFG0_PREGFRXSEL (1 << 24) +#define PAD_CFG0_TRIG_MASK (3 << 25) +#define PAD_CFG0_TRIG_LEVEL (0 << 25) +#define PAD_CFG0_TRIG_EDGE_SINGLE (1 << 25) /* controlled by RX_INVERT*/ +#define PAD_CFG0_TRIG_OFF (2 << 25) +#define PAD_CFG0_TRIG_EDGE_BOTH (3 << 25) +#define PAD_CFG0_RXRAW1_MASK (1 << 28) +#define PAD_CFG0_RXPADSTSEL_MASK (1 << 29) +#define PAD_CFG0_RESET_MASK (3 << 30) +#define PAD_CFG0_LOGICAL_RESET_PWROK (0U << 30) +#define PAD_CFG0_LOGICAL_RESET_DEEP (1U << 30) +#define PAD_CFG0_LOGICAL_RESET_PLTRST (2U << 30) +#define PAD_CFG0_LOGICAL_RESET_RSMRST (3U << 30) + +/* + * Use the fourth bit in IntSel field to indicate gpio ownership. This field is + * RO and hence not used during gpio configuration. + */ +#define PAD_CFG1_GPIO_DRIVER (0x1 << 4) +#define PAD_CFG1_IRQ_MASK (0xff << 0) +#define PAD_CFG1_IOSTERM_MASK (0x3 << 8) +#define PAD_CFG1_IOSTERM_SAME (0x0 << 8) +#define PAD_CFG1_IOSTERM_DISPUPD (0x1 << 8) +#define PAD_CFG1_IOSTERM_ENPD (0x2 << 8) +#define PAD_CFG1_IOSTERM_ENPU (0x3 << 8) +#define PAD_CFG1_PULL_MASK (0xf << 10) +#define PAD_CFG1_PULL_NONE (0x0 << 10) +#define PAD_CFG1_PULL_DN_5K (0x2 << 10) +#define PAD_CFG1_PULL_DN_20K (0x4 << 10) +#define PAD_CFG1_PULL_UP_1K (0x9 << 10) +#define PAD_CFG1_PULL_UP_5K (0xa << 10) +#define PAD_CFG1_PULL_UP_2K (0xb << 10) +#define PAD_CFG1_PULL_UP_20K (0xc << 10) +#define PAD_CFG1_PULL_UP_667 (0xd << 10) +#define PAD_CFG1_PULL_NATIVE (0xf << 10) + +/* Tx enabled driving last value driven, Rx enabled */ +#define PAD_CFG1_IOSSTATE_TX_LAST_RXE (0x0 << 14) +/* + * Tx enabled driving 0, Rx disabled and Rx driving 0 back to its controller + * internally + */ +#define PAD_CFG1_IOSSTATE_TX0_RX_DCR_X0 (0x1 << 14) +/* + * Tx enabled driving 0, Rx disabled and Rx driving 1 back to its controller + * internally + */ +#define PAD_CFG1_IOSSTATE_TX0_RX_DCR_X1 (0x2 << 14) +/* + * Tx enabled driving 1, Rx disabled and Rx driving 0 back to its controller + * internally + */ +#define PAD_CFG1_IOSSTATE_TX1_RX_DCR_X0 (0x3 << 14) +/* + * Tx enabled driving 1, Rx disabled and Rx driving 1 back to its controller + * internally + */ +#define PAD_CFG1_IOSSTATE_TX1_RX_DCR_X1 (0x4 << 14) +/* Tx enabled driving 0, Rx enabled */ +#define PAD_CFG1_IOSSTATE_TX0_RXE (0x5 << 14) +/* Tx enabled driving 1, Rx enabled */ +#define PAD_CFG1_IOSSTATE_TX1_RXE (0x6 << 14) +/* Hi-Z, Rx driving 0 back to its controller internally */ +#define PAD_CFG1_IOSSTATE_HIZCRX0 (0x7 << 14) +/* Hi-Z, Rx driving 1 back to its controller internally */ +#define PAD_CFG1_IOSSTATE_HIZCRX1 (0x8 << 14) +/* Tx disabled, Rx enabled */ +#define PAD_CFG1_IOSSTATE_TXD_RXE (0x9 << 14) +#define PAD_CFG1_IOSSTATE_IGNORE (0xf << 14) /* Ignore Iostandby */ +/* mask to extract Iostandby bits */ +#define PAD_CFG1_IOSSTATE_MASK (0xf << 14) +#define PAD_CFG1_IOSSTATE_SHIFT 14 /* set Iostandby bits [17:14] */ + +#define PAD_CFG2_DEBEN 1 +/* Debounce Duration = (2 ^ PAD_CFG2_DEBOUNCE_x_RTC) * RTC clock duration */ +#define PAD_CFG2_DEBOUNCE_8_RTC (0x3 << 1) +#define PAD_CFG2_DEBOUNCE_16_RTC (0x4 << 1) +#define PAD_CFG2_DEBOUNCE_32_RTC (0x5 << 1) +#define PAD_CFG2_DEBOUNCE_64_RTC (0x6 << 1) +#define PAD_CFG2_DEBOUNCE_128_RTC (0x7 << 1) +#define PAD_CFG2_DEBOUNCE_256_RTC (0x8 << 1) +#define PAD_CFG2_DEBOUNCE_512_RTC (0x9 << 1) +#define PAD_CFG2_DEBOUNCE_1K_RTC (0xa << 1) +#define PAD_CFG2_DEBOUNCE_2K_RTC (0xb << 1) +#define PAD_CFG2_DEBOUNCE_4K_RTC (0xc << 1) +#define PAD_CFG2_DEBOUNCE_8K_RTC (0xd << 1) +#define PAD_CFG2_DEBOUNCE_16K_RTC (0xe << 1) +#define PAD_CFG2_DEBOUNCE_32K_RTC (0xf << 1) +#define PAD_CFG2_DEBOUNCE_MASK 0x1f + +/* voltage tolerance 0=3.3V default 1=1.8V tolerant */ +#if IS_ENABLED(INTEL_COMMON_GPIO_IOSTANDBY) +#define PAD_CFG1_TOL_MASK (0x1 << 25) +#define PAD_CFG1_TOL_1V8 (0x1 << 25) +#endif + +#define PAD_FUNC(value) PAD_CFG0_MODE_##value +#define PAD_RESET(value) PAD_CFG0_LOGICAL_RESET_##value +#define PAD_PULL(value) PAD_CFG1_PULL_##value + +#define PAD_IOSSTATE(value) PAD_CFG1_IOSSTATE_##value +#define PAD_IOSTERM(value) PAD_CFG1_IOSTERM_##value + +#define PAD_IRQ_CFG(route, trig, inv) \ + (PAD_CFG0_ROUTE_##route | \ + PAD_CFG0_TRIG_##trig | \ + PAD_CFG0_RX_POL_##inv) + +#if IS_ENABLED(INTEL_GPIO_DUAL_ROUTE_SUPPORT) +#define PAD_IRQ_CFG_DUAL_ROUTE(route1, route2, trig, inv) \ + (PAD_CFG0_ROUTE_##route1 | \ + PAD_CFG0_ROUTE_##route2 | \ + PAD_CFG0_TRIG_##trig | \ + PAD_CFG0_RX_POL_##inv) +#endif /* CONFIG_INTEL_GPIO_DUAL_ROUTE_SUPPORT */ + +#define _PAD_CFG_STRUCT(__pad, __config0, __config1) \ + __pad(__config0) (__config1) + +#if GPIO_NUM_PAD_CFG_REGS > 2 +#define _PAD_CFG_STRUCT_3(__pad, __config0, __config1, __config2) \ + { \ + .pad = __pad, \ + .pad_config[0] = __config0, \ + .pad_config[1] = __config1, \ + .pad_config[2] = __config2, \ + } +#else +#define _PAD_CFG_STRUCT_3(__pad, __config0, __config1, __config2) \ + _PAD_CFG_STRUCT(__pad, __config0, __config1) +#endif + +/* Native function configuration */ +#define PAD_CFG_NF(pad, pull, rst, func) \ + _PAD_CFG_STRUCT(pad, PAD_RESET(rst) | PAD_FUNC(func), PAD_PULL(pull) | \ + PAD_IOSSTATE(TX_LAST_RXE)) + +#if IS_ENABLED(CONFIG_INTEL_GPIO_PADCFG_PADTOL) +/* + * Native 1.8V tolerant pad, only applies to some pads like I2C/I2S. Not + * applicable to all SOCs. Refer EDS. + */ +#define PAD_CFG_NF_1V8(pad, pull, rst, func) \ + _PAD_CFG_STRUCT(pad, PAD_RESET(rst) | PAD_FUNC(func), PAD_PULL(pull) |\ + PAD_IOSSTATE(TX_LAST_RXE) | PAD_CFG1_TOL_1V8) +#endif + +/* Native function configuration for standby state */ +#define PAD_CFG_NF_IOSSTATE(pad, pull, rst, func, iosstate) \ + _PAD_CFG_STRUCT(pad, PAD_RESET(rst) | PAD_FUNC(func), PAD_PULL(pull) | \ + PAD_IOSSTATE(iosstate)) + +/* + * Native function configuration for standby state, also configuring iostandby + * as masked + */ +#define PAD_CFG_NF_IOSTANDBY_IGNORE(pad, pull, rst, func) \ + _PAD_CFG_STRUCT(pad, PAD_RESET(rst) | PAD_FUNC(func), PAD_PULL(pull) | \ + PAD_IOSSTATE(IGNORE)) + +/* + * Native function configuration for standby state, also configuring iosstate + * and iosterm + */ +#define PAD_CFG_NF_IOSSTATE_IOSTERM(pad, pull, rst, func, iosstate, iosterm) \ + _PAD_CFG_STRUCT(pad, PAD_RESET(rst) | PAD_FUNC(func), PAD_PULL(pull) | \ + PAD_IOSSTATE(iosstate) | PAD_IOSTERM(iosterm)) + +/* General purpose output, no pullup/down */ +#define PAD_CFG_GPO(pad, val, rst) \ + _PAD_CFG_STRUCT(pad, \ + PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_RX_DISABLE | !!val, \ + PAD_PULL(NONE) | PAD_IOSSTATE(TX_LAST_RXE)) + +/* General purpose output, with termination specified */ +#define PAD_CFG_TERM_GPO(pad, val, pull, rst) \ + _PAD_CFG_STRUCT(pad, \ + PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_RX_DISABLE | !!val, \ + PAD_PULL(pull) | PAD_IOSSTATE(TX_LAST_RXE)) + +/* General purpose output, no pullup/down */ +#define PAD_CFG_GPO_GPIO_DRIVER(pad, val, rst, pull) \ + _PAD_CFG_STRUCT(pad, \ + PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_RX_DISABLE | !!val, \ + PAD_PULL(pull) | PAD_IOSSTATE(TX_LAST_RXE) | \ + PAD_CFG1_GPIO_DRIVER) + +/* General purpose output */ +#define PAD_CFG_GPO_IOSSTATE_IOSTERM(pad, val, rst, pull, iosstate, ioterm) \ + _PAD_CFG_STRUCT(pad, \ + PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_RX_DISABLE | !!val, \ + PAD_PULL(pull) | PAD_IOSSTATE(iosstate) | PAD_IOSTERM(ioterm)) + +/* General purpose input */ +#define PAD_CFG_GPI(pad, pull, rst) \ + _PAD_CFG_STRUCT(pad, \ + PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE, \ + PAD_PULL(pull) | PAD_IOSSTATE(TXD_RXE)) + +/* General purpose input. The following macro sets the + * Host Software Pad Ownership to GPIO Driver mode. + */ +#define PAD_CFG_GPI_GPIO_DRIVER(pad, pull, rst) \ + _PAD_CFG_STRUCT(pad, \ + PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE, \ + PAD_PULL(pull) | PAD_CFG1_GPIO_DRIVER | PAD_IOSSTATE(TXD_RXE)) + +#define PAD_CFG_GPIO_DRIVER_HI_Z(pad, pull, rst, iosstate, iosterm) \ + _PAD_CFG_STRUCT(pad, \ + PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE | \ + PAD_CFG0_RX_DISABLE, \ + PAD_PULL(pull) | PAD_CFG1_GPIO_DRIVER | \ + PAD_IOSSTATE(iosstate) | PAD_IOSTERM(iosterm)) + +#define PAD_CFG_GPIO_HI_Z(pad, pull, rst, iosstate, iosterm) \ + _PAD_CFG_STRUCT(pad, \ + PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE | \ + PAD_CFG0_RX_DISABLE, PAD_PULL(pull) | \ + PAD_IOSSTATE(iosstate) | PAD_IOSTERM(iosterm)) + +/* GPIO Interrupt */ +#define PAD_CFG_GPI_INT(pad, pull, rst, trig) \ + _PAD_CFG_STRUCT(pad, \ + PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE | \ + PAD_CFG0_TRIG_##trig | PAD_CFG0_RX_POL_NONE, \ + PAD_PULL(pull) | PAD_CFG1_GPIO_DRIVER | PAD_IOSSTATE(TXD_RXE)) + +/* + * No Connect configuration for unused pad. + * Both TX and RX are disabled. RX disabling is done to avoid unnecessary + * setting of GPI_STS. + */ +#define PAD_NC(pad, pull) \ + _PAD_CFG_STRUCT(pad, \ + PAD_FUNC(GPIO) | PAD_RESET(DEEP) | \ + PAD_CFG0_TX_DISABLE | PAD_CFG0_RX_DISABLE, \ + PAD_PULL(pull) | PAD_IOSSTATE(TXD_RXE)) + +/* General purpose input, routed to APIC */ +#define PAD_CFG_GPI_APIC(pad, pull, rst, trig, inv) \ + _PAD_CFG_STRUCT(pad, \ + PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE | \ + PAD_IRQ_CFG(IOAPIC, trig, inv), PAD_PULL(pull) | \ + PAD_IOSSTATE(TXD_RXE)) + +/* General purpose input, routed to APIC - with IOStandby Config*/ +#define PAD_CFG_GPI_APIC_IOS(pad, pull, rst, trig, inv, iosstate, iosterm) \ + _PAD_CFG_STRUCT(pad, \ + PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE | \ + PAD_IRQ_CFG(IOAPIC, trig, inv), PAD_PULL(pull) | \ + PAD_IOSSTATE(iosstate) | PAD_IOSTERM(iosterm)) + +/* + * The following APIC macros assume the APIC will handle the filtering + * on its own end. One just needs to pass an active high message into the + * ITSS. + */ +#define PAD_CFG_GPI_APIC_LOW(pad, pull, rst) \ + PAD_CFG_GPI_APIC(pad, pull, rst, LEVEL, INVERT) + +#define PAD_CFG_GPI_APIC_HIGH(pad, pull, rst) \ + PAD_CFG_GPI_APIC(pad, pull, rst, LEVEL, NONE) + +#define PAD_CFG_GPI_APIC_EDGE_LOW(pad, pull, rst) \ + PAD_CFG_GPI_APIC(pad, pull, rst, EDGE_SINGLE, INVERT) + +/* General purpose input, routed to SMI */ +#define PAD_CFG_GPI_SMI(pad, pull, rst, trig, inv) \ + _PAD_CFG_STRUCT(pad, \ + PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE | \ + PAD_IRQ_CFG(SMI, trig, inv), PAD_PULL(pull) | \ + PAD_IOSSTATE(TXD_RXE)) + +/* General purpose input, routed to SMI */ +#define PAD_CFG_GPI_SMI_IOS(pad, pull, rst, trig, inv, iosstate, iosterm) \ + _PAD_CFG_STRUCT(pad, \ + PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE | \ + PAD_IRQ_CFG(SMI, trig, inv), PAD_PULL(pull) | \ + PAD_IOSSTATE(iosstate) | PAD_IOSTERM(iosterm)) + +#define PAD_CFG_GPI_SMI_LOW(pad, pull, rst, trig) \ + PAD_CFG_GPI_SMI(pad, pull, rst, trig, INVERT) + +#define PAD_CFG_GPI_SMI_HIGH(pad, pull, rst, trig) \ + PAD_CFG_GPI_SMI(pad, pull, rst, trig, NONE) + +/* General purpose input, routed to SCI */ +#define PAD_CFG_GPI_SCI(pad, pull, rst, trig, inv) \ + _PAD_CFG_STRUCT(pad, \ + PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE | \ + PAD_IRQ_CFG(SCI, trig, inv), PAD_PULL(pull) | \ + PAD_IOSSTATE(TXD_RXE)) + +/* General purpose input, routed to SCI */ +#define PAD_CFG_GPI_SCI_IOS(pad, pull, rst, trig, inv, iosstate, iosterm) \ + _PAD_CFG_STRUCT(pad, \ + PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE | \ + PAD_IRQ_CFG(SCI, trig, inv), PAD_PULL(pull) | \ + PAD_IOSSTATE(iosstate) | PAD_IOSTERM(iosterm)) + +#define PAD_CFG_GPI_SCI_LOW(pad, pull, rst, trig) \ + PAD_CFG_GPI_SCI(pad, pull, rst, trig, INVERT) + +#define PAD_CFG_GPI_SCI_HIGH(pad, pull, rst, trig) \ + PAD_CFG_GPI_SCI(pad, pull, rst, trig, NONE) + +#define PAD_CFG_GPI_SCI_DEBEN(pad, pull, rst, trig, inv, dur) \ + _PAD_CFG_STRUCT_3(pad, \ + PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE | \ + PAD_IRQ_CFG(SCI, trig, inv), PAD_PULL(pull) | \ + PAD_IOSSTATE(TXD_RXE), PAD_CFG2_DEBEN | PAD_CFG2_##dur) + +#define PAD_CFG_GPI_SCI_LOW_DEBEN(pad, pull, rst, trig, dur) \ + PAD_CFG_GPI_SCI_DEBEN(pad, pull, rst, trig, INVERT, dur) + +#define PAD_CFG_GPI_SCI_HIGH_DEBEN(pad, pull, rst, trig, dur) \ + PAD_CFG_GPI_SCI_DEBEN(pad, pull, rst, trig, NONE, dur) + +/* General purpose input, routed to NMI */ +#define PAD_CFG_GPI_NMI(pad, pull, rst, trig, inv) \ + _PAD_CFG_STRUCT(pad, \ + PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE | \ + PAD_IRQ_CFG(NMI, trig, inv), PAD_PULL(pull) | \ + PAD_IOSSTATE(TXD_RXE)) + +#if IS_ENABLED(INTEL_GPIO_DUAL_ROUTE_SUPPORT) +/* GPI, GPIO Driver, SCI interrupt */ +#define PAD_CFG_GPI_GPIO_DRIVER_SCI(pad, pull, rst, trig, inv) \ + _PAD_CFG_STRUCT(pad, \ + PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE | \ + PAD_IRQ_CFG(SCI, trig, inv), \ + PAD_PULL(pull) | PAD_CFG1_GPIO_DRIVER | PAD_IOSSTATE(TXD_RXE)) + +#define PAD_CFG_GPI_DUAL_ROUTE(pad, pull, rst, trig, inv, route1, route2) \ + _PAD_CFG_STRUCT(pad, \ + PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE | \ + PAD_IRQ_CFG_DUAL_ROUTE(route1, route2, trig, inv), \ + PAD_PULL(pull) | PAD_IOSSTATE(TXD_RXE)) + +#define PAD_CFG_GPI_IRQ_WAKE(pad, pull, rst, trig, inv) \ + PAD_CFG_GPI_DUAL_ROUTE(pad, pull, rst, trig, inv, IOAPIC, SCI) + +#endif /* CONFIG_INTEL_GPIO_DUAL_ROUTE_SUPPORT */ + +#endif /* _ASM_ARCH_GPIO_DEFS_H_ */