From patchwork Mon Sep 18 13:46:09 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jerome Brunet X-Patchwork-Id: 112924 Delivered-To: patch@linaro.org Received: by 10.140.106.117 with SMTP id d108csp3685398qgf; Mon, 18 Sep 2017 06:46:52 -0700 (PDT) X-Received: by 10.98.224.65 with SMTP id f62mr32031170pfh.342.1505742412509; Mon, 18 Sep 2017 06:46:52 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1505742412; cv=none; d=google.com; s=arc-20160816; b=ufmgVJE4AHhaKIFU7m+au2JeS361zEo4+5XHgUF/VxxsK902co4RYuhLxGK7k54Snq n3Z+WlOjxxY8rJRJUJvW+9BIn8+XvKuf0XgIZ+744+KPpu1r1o0FueOmjbHcy6NwbvIX yAk6joDGD8Wqjc5IA4ijX1xm/FM2cILct8uD+FglLSdNhov348MHd9zJ2J3uVXyKMU2T jArm+mfddlWZ4ZrNldVg2h5A16cKvAECS+3gaLYhvf4AOROToUhwY1kd234aNnTjNFHe H/Z21kEaf/86tpSgw0V1j2JOVP4BVP1dzdCEHPOuKMkS0/MDu3d3GwqYXGcTqXabv7wH q/mg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature:arc-authentication-results; bh=r/zvGjiMzT2GM5av7cyQS7Gvu/XjANYw4OUvXWzraqM=; b=Zo8mlMPfRVCxmL/BfXS74VgxOwhhXEJIKWyVFoneGwavTEAtOXWticHwn5dxKWF+5x Zji9gl0/hEqjhTPhQY6wA0x7snmJFq7NpsC8bCXq6RHCHqOMjYD4qy+m6gdd2bwc7FY1 Xb/PXHkGNlBMYaQJHbtMmCj7Pu1ANKX/u2fbAYkGcAkU91w0e6IGyhMvXyvY6cWXZD2l WBnjrZ4sXEJAI0aDRN3THG+zZs2HX3TOzwbC4JdDHBcTtlUBojYtBo+2u0Ol/rK9mF39 kwbX32lC1ve1Q8Qkn+y2uCXrG9PYbr+1ai9Bfk/+rIJfSWFY/mfgC+IZcjmD/uT6yJgd CJug== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@baylibre-com.20150623.gappssmtp.com header.s=20150623 header.b=Gz4J7cW7; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id e1si4654106pgq.168.2017.09.18.06.46.52; Mon, 18 Sep 2017 06:46:52 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@baylibre-com.20150623.gappssmtp.com header.s=20150623 header.b=Gz4J7cW7; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755004AbdIRNqu (ORCPT + 26 others); Mon, 18 Sep 2017 09:46:50 -0400 Received: from mail-wr0-f174.google.com ([209.85.128.174]:43210 "EHLO mail-wr0-f174.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932687AbdIRNqR (ORCPT ); Mon, 18 Sep 2017 09:46:17 -0400 Received: by mail-wr0-f174.google.com with SMTP id a43so544503wrc.0 for ; Mon, 18 Sep 2017 06:46:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=r/zvGjiMzT2GM5av7cyQS7Gvu/XjANYw4OUvXWzraqM=; b=Gz4J7cW7LZO0xc06fhEn+XUe2tSkDmro7y0EkjWaWxlNb1ws5lcD8XM5qsQK9eHaD/ OaY5GNcGIV0OhBB0S7Px9DaxouRBUNU5OgjgmIIsN459gRNV3+R2JHr3EoA0GbIv3k+o M0Ry0cXGe3PT91vryVZtXgtsFpm3YRgx9QFDarPvNmXsPDvc1rkw285xU0Um0hNu2aTh 7vlL2ewD1/qjfRwJ/+eGQmQPv6+2Fue97LEqPncqwYLU5bIXNSBLh64msluqc5hIGEVl ATPUBMva3VQAXXQ5MReQ92Vwvekj4Fn/yzFcbi2F8CSkcthjbuKKIQqTMjMdNK5in2d1 6YAg== 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=r/zvGjiMzT2GM5av7cyQS7Gvu/XjANYw4OUvXWzraqM=; b=b8UCvA8M7p1JDpb7dygVAUBbvh5wElSP5NFYeRDoos1qU5mEkUKfrnUXnZpCMD+D5s zGyoaB7ydBFOwiygeksSE6I7OK3b7YVC3pnzh5xJE5Qu9T8tTYUS+o85+RatJRNrgp/J KGDkAnEMqjXz6NrKKO9UCPVh4T9Hnfwd/LnsoND1KP/318WL+QbXbRhNloB9Rzm2re1s A2WXTwXT7zIYG8pBMT/nNFYBLEOyUfLgIjPJe4hhHItzUa78YGKXomvKf/okOKIjh0/V SXu56CZwc/fs6hL+HbEoIaxI/jOQvyKh2rxjos4RNA0UbahYKKvjn50jeWsUvLTPnK5s Bt6g== X-Gm-Message-State: AHPjjUg7xmAyrC8R4dZ95I8UqPB7Mz6R/QBGbJ7FfnsNzMEJlTfmhx9E wL8RC5lHAFlNP4XQ X-Google-Smtp-Source: AOwi7QD7NhV5zDbzrJbhH/J0yNIThvodOAkN/cYBtvwszYIEe7VxbvR7gGNkAWtzwQ9mcAg/LuDHJQ== X-Received: by 10.223.161.137 with SMTP id u9mr14967752wru.280.1505742376200; Mon, 18 Sep 2017 06:46:16 -0700 (PDT) Received: from localhost.localdomain ([90.63.244.31]) by smtp.googlemail.com with ESMTPSA id n29sm6888585wmi.46.2017.09.18.06.46.15 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Mon, 18 Sep 2017 06:46:15 -0700 (PDT) From: Jerome Brunet To: Marc Zyngier , Thomas Gleixner , Jason Cooper , Heiner Kallweit Cc: Jerome Brunet , Kevin Hilman , Carlo Caione , linux-amlogic@lists.infradead.org, linux-arm-kernel@lists.infradead.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v4 1/2] dt-bindings: interrupt-controller: add DT binding for meson GPIO interrupt controller Date: Mon, 18 Sep 2017 15:46:09 +0200 Message-Id: <20170918134610.17743-3-jbrunet@baylibre.com> X-Mailer: git-send-email 2.13.5 In-Reply-To: <20170918134610.17743-1-jbrunet@baylibre.com> References: <20170918134610.17743-1-jbrunet@baylibre.com> MIME-Version: 1.0 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This commit adds the device tree bindings description for Amlogic's GPIO interrupt controller available on the meson8b, gxbb and gxl SoC families Cc: Heiner Kallweit Signed-off-by: Jerome Brunet --- .../amlogic,meson-gpio-intc.txt | 35 ++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/amlogic,meson-gpio-intc.txt -- 2.13.5 diff --git a/Documentation/devicetree/bindings/interrupt-controller/amlogic,meson-gpio-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/amlogic,meson-gpio-intc.txt new file mode 100644 index 000000000000..633e21ce4b17 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/amlogic,meson-gpio-intc.txt @@ -0,0 +1,35 @@ +Amlogic meson GPIO interrupt controller + +Meson SoCs contains an interrupt controller which is able to watch the SoC +pads and generate an interrupt on edge or level. The controller is essentially +a 256 pads to 8 GIC interrupt multiplexer, with a filter block to select edge +or level and polarity. It does not expose all 256 mux inputs because the +documentation shows that the upper part is not mapped to any pad. The actual +number of interrupt exposed depends on the SoC. + +Required properties: + +- compatible : must have "amlogic,meson8-gpio-intc” and either + “amlogic,meson8b-gpio-intc” for meson8b SoCs (S805) or + “amlogic,meson-gxbb-gpio-intc” for GXBB SoCs (S905) or + “amlogic,meson-gxl-gpio-intc” for GXL SoCs (S905X, S912) +- interrupt-parent : a phandle to the GIC the interrupts are routed to. + Usually this is provided at the root level of the device tree as it is + common to most of the SoC. +- reg : Specifies base physical address and size of the registers. +- interrupt-controller : Identifies the node as an interrupt controller. +- #interrupt-cells : Specifies the number of cells needed to encode an + interrupt source. The value must be 2. +- meson,channel-interrupts: Array with the 8 upstream hwirq numbers. These + are the hwirqs used on the parent interrupt controller. + +Example: + +gpio_interrupt: interrupt-controller@9880 { + compatible = "amlogic,meson-gxbb-gpio-intc", + "amlogic,meson-gpio-intc"; + reg = <0x0 0x9880 0x0 0x10>; + interrupt-controller; + #interrupt-cells = <2>; + meson,channel-interrupts = <64 65 66 67 68 69 70 71>; +}; From patchwork Mon Sep 18 13:46:10 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jerome Brunet X-Patchwork-Id: 112923 Delivered-To: patch@linaro.org Received: by 10.140.106.117 with SMTP id d108csp3685134qgf; Mon, 18 Sep 2017 06:46:34 -0700 (PDT) X-Received: by 10.99.3.22 with SMTP id 22mr19204292pgd.77.1505742394532; Mon, 18 Sep 2017 06:46:34 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1505742394; cv=none; d=google.com; s=arc-20160816; b=K1j1pe30FwWx63wjIOTqU8XCM0BD650REF3JKCOz752FGOGzNva/SU4QdfEtSv9gxl OrwsDTJDd3WUt/B3k5/1Y6XlVwd5YVAlOVa/LjqQruOtqxo3+7Kc11sco2LT1sECRvqT Qn/vdUPJu/9hO1SdD6VWCuf+zfkbhbfruUGFnoy3Cw140cKlbNi39dJplcpupOOdMREK bv9dWn3Y55dQioKx8n7Lrun0uAeU+D2CqimgyFC+6Tzj3pnxummnIKZpex9TPOyEBT/f IcVViGY81A5TRPJIRS4LpUY5F5TWrgld7Az+XFvNjYHb9E10B//DMV3YTPN8bcaJc98o mgoA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=agNECDTlRhnMGfuGLmbxIasCT1BsmbhaQ3JMZthZ1E4=; b=GMmb9AgMd3PApOk2PLMiE02tjB1zMmPuEStkroCPrnED5Jb4FokFbfNN/b69WQeZar KMtluF2/DjcoLK8qt7pl4vB7FA8+F91HN42e4UheRq68+bijCCZcz4+6NGP2DTPMtZAa MZp/1DIt3mjQ90+61X6YBUKL5BeMOdcsDK3KDwDRYuGxaGlUAPRAQd8OdBTCmG7YpLSQ 4eXGVS+65CkjzTN5BkLNMEIxSCMQUgZdDekEp5OTVzQ4SVwsg+QsC2HgwQyc/gvognYA uXdi+Jg7OlccKMrZhO9CvHcohJyflsAnRohb2R2zDSfz3k4opQJ5+ZUC3K98bsPIYmoo /GOA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@baylibre-com.20150623.gappssmtp.com header.s=20150623 header.b=mrUDRxcm; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id u184si4503693pfb.47.2017.09.18.06.46.34; Mon, 18 Sep 2017 06:46:34 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@baylibre-com.20150623.gappssmtp.com header.s=20150623 header.b=mrUDRxcm; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932732AbdIRNqc (ORCPT + 26 others); Mon, 18 Sep 2017 09:46:32 -0400 Received: from mail-wm0-f50.google.com ([74.125.82.50]:51129 "EHLO mail-wm0-f50.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932704AbdIRNqS (ORCPT ); Mon, 18 Sep 2017 09:46:18 -0400 Received: by mail-wm0-f50.google.com with SMTP id v142so2812972wmv.5 for ; Mon, 18 Sep 2017 06:46:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=agNECDTlRhnMGfuGLmbxIasCT1BsmbhaQ3JMZthZ1E4=; b=mrUDRxcmVGyoGzCmSb4y/t355+CEzAv9RZpt++jMvY5BVO0W0fSRztd1qDuYs7Ma/V 0uBt9tbI37mK+y+HEtnCJhqmWIX9GUyJZeTWAgKIk3NMH3TsNpaaJnybeWCFjFpUq8BO /D4IE3+7x0Jcj1DbBMppZwWPe28YvhPvsbGA3okr1YMTi7ru90FbuBx7GPZVOFre32Cq kfiItcC3kYl/Szaa4HLCJk2Wxm31IZWEXl59ceBUl/FPoGaxWDTH5b5LU2VvobizShTG Bmo2dFey8Ryp1qEt5PR2fn1yiZfjUeJPwh2/MIsbfA0ln0YrD1JrT9xko8Ea5qyQj6Zj HebA== 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; bh=agNECDTlRhnMGfuGLmbxIasCT1BsmbhaQ3JMZthZ1E4=; b=eAbQQFNVeeY6qNC27MSsJtyBMRWZ5Z29ajLL3cInb5vAG//wUOV3cX/VJnV5wl5w/N Ieh11pPolFg9JuBlOH768OFePAhuJQ5dmfTwxEAAwkR5d7uo77gLv3xearN5p5l0huBM TxIVxUUzX22Cs5l0x9jkGToIUCettddc4+3XRbh5o2A+TSeIElZrsfFSagkbewzLtp3b qooUzNZDyAQPfSehIQocRkDir1SDPU6Je27SEQTQE9Cu2oekLWv2cEQ0NjNdOUMLpTsl tPC9CCuwSoz4FDpvF5vLqizeN9Y8GbydBiJJ9s0z/i+26pWRUOsXxEaD6BSFDqgxqY6q wtFQ== X-Gm-Message-State: AHPjjUiB2zvEj4wzp8BqvwREC8PgagiFL8ajYwdrVO1a0+Q4iM0azh2p P8ZXrnOJrtMLj2sLR+U= X-Google-Smtp-Source: AOwi7QAt9cY96VXfD3wd4LjVD+JHkr3beeuFcTT8TkcQUGjFtvNo9IpAhsh93imoesUsk/rhr1fCDg== X-Received: by 10.28.191.138 with SMTP id o10mr8324136wmi.61.1505742377281; Mon, 18 Sep 2017 06:46:17 -0700 (PDT) Received: from localhost.localdomain ([90.63.244.31]) by smtp.googlemail.com with ESMTPSA id n29sm6888585wmi.46.2017.09.18.06.46.16 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Mon, 18 Sep 2017 06:46:16 -0700 (PDT) From: Jerome Brunet To: Marc Zyngier , Thomas Gleixner , Jason Cooper , Heiner Kallweit Cc: Jerome Brunet , Kevin Hilman , Carlo Caione , linux-amlogic@lists.infradead.org, linux-arm-kernel@lists.infradead.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v4 2/2] irqchip: meson: add support for gpio interrupt controller Date: Mon, 18 Sep 2017 15:46:10 +0200 Message-Id: <20170918134610.17743-4-jbrunet@baylibre.com> X-Mailer: git-send-email 2.13.5 In-Reply-To: <20170918134610.17743-1-jbrunet@baylibre.com> References: <20170918134610.17743-1-jbrunet@baylibre.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Add support for the interrupt gpio controller found on Amlogic's meson SoC family. This controller is a separate controller from the gpio controller. It is able to spy on the SoC pad. It is essentially a 256 to 8 router with a filtering block to select level or edge and polarity. The number of actual mappable inputs depends on the SoC. Cc: Heiner Kallweit Signed-off-by: Jerome Brunet --- drivers/irqchip/Kconfig | 8 + drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-meson-gpio.c | 414 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 423 insertions(+) create mode 100644 drivers/irqchip/irq-meson-gpio.c -- 2.13.5 diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 9d8a1dd2e2c2..8e50dfea0973 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -321,3 +321,11 @@ config IRQ_UNIPHIER_AIDET select IRQ_DOMAIN_HIERARCHY help Support for the UniPhier AIDET (ARM Interrupt Detector). + +config MESON_IRQ_GPIO + bool "Meson GPIO Interrupt Multiplexer" + depends on ARCH_MESON || COMPILE_TEST + select IRQ_DOMAIN + select IRQ_DOMAIN_HIERARCHY + help + Support Meson SoC Family GPIO Interrupt Multiplexer diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 845abc107ad5..065adf4102c9 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -79,3 +79,4 @@ obj-$(CONFIG_ARCH_ASPEED) += irq-aspeed-vic.o irq-aspeed-i2c-ic.o obj-$(CONFIG_STM32_EXTI) += irq-stm32-exti.o obj-$(CONFIG_QCOM_IRQ_COMBINER) += qcom-irq-combiner.o obj-$(CONFIG_IRQ_UNIPHIER_AIDET) += irq-uniphier-aidet.o +obj-$(CONFIG_MESON_IRQ_GPIO) += irq-meson-gpio.o diff --git a/drivers/irqchip/irq-meson-gpio.c b/drivers/irqchip/irq-meson-gpio.c new file mode 100644 index 000000000000..c7cc7e37a23c --- /dev/null +++ b/drivers/irqchip/irq-meson-gpio.c @@ -0,0 +1,414 @@ +/* + * Copyright (c) 2015 Endless Mobile, Inc. + * Author: Carlo Caione + * Copyright (c) 2016 BayLibre, SAS. + * Author: Jerome Brunet + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include + +#define NUM_CHANNEL 8 +#define MAX_INPUT_MUX 256 + +#define REG_EDGE_POL 0x00 +#define REG_PIN_03_SEL 0x04 +#define REG_PIN_47_SEL 0x08 +#define REG_FILTER_SEL 0x0c + +#define REG_EDGE_POL_MASK(x) (BIT(x) | BIT(16 + (x))) +#define REG_EDGE_POL_EDGE(x) BIT(x) +#define REG_EDGE_POL_LOW(x) BIT(16 + (x)) +#define REG_PIN_SEL_SHIFT(x) (((x) % 4) * 8) +#define REG_FILTER_SEL_SHIFT(x) ((x) * 4) + +struct meson_gpio_irq_params { + unsigned int nr_hwirq; +}; + +static const struct meson_gpio_irq_params meson8b_params = { + .nr_hwirq = 119, +}; + +static const struct meson_gpio_irq_params gxbb_params = { + .nr_hwirq = 133, +}; + +static const struct meson_gpio_irq_params gxl_params = { + .nr_hwirq = 110, +}; + +static const struct of_device_id meson_irq_gpio_matches[] = { + { .compatible = "amlogic,meson8b-gpio-intc", .data = &meson8b_params }, + { .compatible = "amlogic,meson-gxbb-gpio-intc", .data = &gxbb_params }, + { .compatible = "amlogic,meson-gxl-gpio-intc", .data = &gxl_params }, + { } +}; + +struct meson_gpio_irq_controller { + unsigned int nr_hwirq; + void __iomem *base; + u32 channel_irqs[NUM_CHANNEL]; + DECLARE_BITMAP(channel_map, NUM_CHANNEL); + spinlock_t lock; +}; + +static void meson_gpio_irq_update_bits(struct meson_gpio_irq_controller *ctl, + unsigned int reg, u32 mask, u32 val) +{ + u32 tmp; + + tmp = readl_relaxed(ctl->base + reg); + tmp &= ~mask; + tmp |= val; + writel_relaxed(tmp, ctl->base + reg); +} + +static unsigned int meson_gpio_irq_channel_to_reg(unsigned int channel) +{ + return (channel < 4) ? REG_PIN_03_SEL : REG_PIN_47_SEL; +} + +static int +meson_gpio_irq_request_channel(struct meson_gpio_irq_controller *ctl, + unsigned long hwirq, + u32 **channel_hwirq) +{ + unsigned int reg, idx; + + spin_lock(&ctl->lock); + + /* Find a free channel */ + idx = find_first_zero_bit(ctl->channel_map, NUM_CHANNEL); + if (idx >= NUM_CHANNEL) { + spin_unlock(&ctl->lock); + pr_err("No channel available\n"); + return -ENOSPC; + } + + /* Mark the channel as used */ + set_bit(idx, ctl->channel_map); + + /* + * Setup the mux of the channel to route the signal of the pad + * to the appropriate input of the GIC + */ + reg = meson_gpio_irq_channel_to_reg(idx); + meson_gpio_irq_update_bits(ctl, reg, + 0xff << REG_PIN_SEL_SHIFT(idx), + hwirq << REG_PIN_SEL_SHIFT(idx)); + + /* + * Get the hwirq number assigned to this channel through + * a pointer the channel_irq table. The added benifit of this + * method is that we can also retrieve the channel index with + * it, using the table base. + */ + *channel_hwirq = &(ctl->channel_irqs[idx]); + + spin_unlock(&ctl->lock); + + pr_debug("hwirq %lu assigned to channel %d - irq %u\n", + hwirq, idx, **channel_hwirq); + + return 0; +} + +static unsigned int +meson_gpio_irq_get_channel_idx(struct meson_gpio_irq_controller *ctl, + u32 *channel_hwirq) +{ + return channel_hwirq - ctl->channel_irqs; +} + +static void +meson_gpio_irq_release_channel(struct meson_gpio_irq_controller *ctl, + u32 *channel_hwirq) +{ + unsigned int idx; + + idx = meson_gpio_irq_get_channel_idx(ctl, channel_hwirq); + clear_bit(idx, ctl->channel_map); +} + +static int meson_gpio_irq_type_setup(struct meson_gpio_irq_controller *ctl, + unsigned int type, + u32 *channel_hwirq) +{ + u32 val = 0; + unsigned int idx; + + idx = meson_gpio_irq_get_channel_idx(ctl, channel_hwirq); + + /* + * The controller has a filter block to operate in either LEVEL or + * EDGE mode, then signal is sent to the GIC. To enable LEVEL_LOW and + * EDGE_FALLING support (which the GIC does not support), the filter + * block is also able to invert the input signal it gets before + * providing it to the GIC. + */ + type &= IRQ_TYPE_SENSE_MASK; + + if (type == IRQ_TYPE_EDGE_BOTH) + return -EINVAL; + + if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) + val |= REG_EDGE_POL_EDGE(idx); + + if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING)) + val |= REG_EDGE_POL_LOW(idx); + + spin_lock(&ctl->lock); + + meson_gpio_irq_update_bits(ctl, REG_EDGE_POL, + REG_EDGE_POL_MASK(idx), val); + + spin_unlock(&ctl->lock); + + return 0; +} + +static unsigned int meson_gpio_irq_type_output(unsigned int type) +{ + unsigned int sense = type & IRQ_TYPE_SENSE_MASK; + + type &= ~IRQ_TYPE_SENSE_MASK; + + /* + * The polarity of the signal provided to the GIC should always + * be high. + */ + if (sense & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) + type |= IRQ_TYPE_LEVEL_HIGH; + else if (sense & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) + type |= IRQ_TYPE_EDGE_RISING; + + return type; +} + +static int meson_gpio_irq_set_type(struct irq_data *data, unsigned int type) +{ + struct meson_gpio_irq_controller *ctl = data->domain->host_data; + u32 *channel_hwirq = irq_data_get_irq_chip_data(data); + int ret; + + ret = meson_gpio_irq_type_setup(ctl, type, channel_hwirq); + if (ret) + return ret; + + return irq_chip_set_type_parent(data, + meson_gpio_irq_type_output(type)); +} + +static struct irq_chip meson_gpio_irq_chip = { + .name = "meson-gpio-irqchip", + .irq_mask = irq_chip_mask_parent, + .irq_unmask = irq_chip_unmask_parent, + .irq_eoi = irq_chip_eoi_parent, + .irq_set_type = meson_gpio_irq_set_type, + .irq_retrigger = irq_chip_retrigger_hierarchy, +#ifdef CONFIG_SMP + .irq_set_affinity = irq_chip_set_affinity_parent, +#endif + .flags = IRQCHIP_SET_TYPE_MASKED, +}; + +static int meson_gpio_irq_domain_translate(struct irq_domain *domain, + struct irq_fwspec *fwspec, + unsigned long *hwirq, + unsigned int *type) +{ + if (is_of_node(fwspec->fwnode) && fwspec->param_count == 2) { + *hwirq = fwspec->param[0]; + *type = fwspec->param[1]; + return 0; + } + + return -EINVAL; +} + +static int meson_gpio_irq_allocate_gic_irq(struct irq_domain *domain, + unsigned int virq, + u32 hwirq, + unsigned int type) +{ + struct irq_fwspec fwspec; + + fwspec.fwnode = domain->parent->fwnode; + fwspec.param_count = 3; + fwspec.param[0] = 0; /* SPI */ + fwspec.param[1] = hwirq; + fwspec.param[2] = meson_gpio_irq_type_output(type); + + return irq_domain_alloc_irqs_parent(domain, virq, 1, &fwspec); +} + +static int meson_gpio_irq_domain_alloc(struct irq_domain *domain, + unsigned int virq, + unsigned int nr_irqs, + void *data) +{ + struct irq_fwspec *fwspec = data; + struct meson_gpio_irq_controller *ctl = domain->host_data; + unsigned long hwirq; + u32 *channel_hwirq; + unsigned int type; + int ret; + + if (WARN_ON(nr_irqs != 1)) + return -EINVAL; + + ret = meson_gpio_irq_domain_translate(domain, fwspec, &hwirq, &type); + if (ret) + return ret; + + ret = meson_gpio_irq_request_channel(ctl, hwirq, &channel_hwirq); + if (ret) + return ret; + + ret = meson_gpio_irq_allocate_gic_irq(domain, virq, + *channel_hwirq, type); + if (ret < 0) { + pr_err("failed to allocate gic irq %u\n", *channel_hwirq); + meson_gpio_irq_release_channel(ctl, channel_hwirq); + return ret; + } + + irq_domain_set_hwirq_and_chip(domain, virq, hwirq, + &meson_gpio_irq_chip, channel_hwirq); + + return 0; +} + +static void meson_gpio_irq_domain_free(struct irq_domain *domain, + unsigned int virq, + unsigned int nr_irqs) +{ + struct meson_gpio_irq_controller *ctl = domain->host_data; + struct irq_data *irq_data; + u32 *channel_hwirq; + + if (WARN_ON(nr_irqs != 1)) + return; + + irq_domain_free_irqs_parent(domain, virq, 1); + + irq_data = irq_domain_get_irq_data(domain, virq); + channel_hwirq = irq_data_get_irq_chip_data(irq_data); + + meson_gpio_irq_release_channel(ctl, channel_hwirq); +} + +static const struct irq_domain_ops meson_gpio_irq_domain_ops = { + .alloc = meson_gpio_irq_domain_alloc, + .free = meson_gpio_irq_domain_free, + .translate = meson_gpio_irq_domain_translate, +}; + +static int __init meson_gpio_irq_parse_dt(struct device_node *node, + struct meson_gpio_irq_controller *ctl) +{ + const struct of_device_id *match; + const struct meson_gpio_irq_params *params; + int ret; + + match = of_match_node(meson_irq_gpio_matches, node); + if (!match) + return -ENODEV; + + params = match->data; + ctl->nr_hwirq = params->nr_hwirq; + + ret = of_property_read_variable_u32_array(node, + "amlogic,channel-interrupts", + ctl->channel_irqs, + NUM_CHANNEL, + NUM_CHANNEL); + if (ret < 0) { + pr_err("can't get %d channel interrupts\n", NUM_CHANNEL); + return ret; + } + + return 0; +} + +static int __init meson_gpio_irq_of_init(struct device_node *node, + struct device_node *parent) +{ + struct irq_domain *domain, *parent_domain; + struct meson_gpio_irq_controller *ctl; + int ret; + + if (!parent) { + pr_err("missing parent interrupt node\n"); + return -ENODEV; + } + + parent_domain = irq_find_host(parent); + if (!parent_domain) { + pr_err("unable to obtain parent domain\n"); + return -ENXIO; + } + + ctl = kzalloc(sizeof(*ctl), GFP_KERNEL); + if (!ctl) + return -ENOMEM; + + spin_lock_init(&ctl->lock); + + ctl->base = of_iomap(node, 0); + if (!ctl->base) { + ret = -ENOMEM; + goto free_ctl; + } + + ret = meson_gpio_irq_parse_dt(node, ctl); + if (ret) + goto free_channel_irqs; + + domain = irq_domain_create_hierarchy(parent_domain, 0, ctl->nr_hwirq, + of_node_to_fwnode(node), + &meson_gpio_irq_domain_ops, + ctl); + if (!domain) { + pr_err("failed to add domain\n"); + ret = -ENODEV; + goto free_channel_irqs; + } + + pr_info("%d to %d gpio interrupt mux initialized\n", + ctl->nr_hwirq, NUM_CHANNEL); + + return 0; + +free_channel_irqs: + iounmap(ctl->base); +free_ctl: + kfree(ctl); + + return ret; +} + +IRQCHIP_DECLARE(meson_gpio_intc, "amlogic,meson-gpio-intc", + meson_gpio_irq_of_init);