From patchwork Mon Feb 4 14:22:34 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roger Quadros X-Patchwork-Id: 157419 Delivered-To: patch@linaro.org Received: by 2002:a02:48:0:0:0:0:0 with SMTP id 69csp3973508jaa; Mon, 4 Feb 2019 06:24:03 -0800 (PST) X-Google-Smtp-Source: ALg8bN5f5lmMiqUBw9dyYXX/mJEg8/e//zKoZRDMGCkNd0Tp6YL0Py1VuEwN0xdySR439yZs1XaA X-Received: by 2002:a62:3141:: with SMTP id x62mr50798304pfx.12.1549290243173; Mon, 04 Feb 2019 06:24:03 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1549290243; cv=none; d=google.com; s=arc-20160816; b=DZMgHj0pXcn3i/Q8t0HYec9GYHlqQWnYh+CVC04wM6Op8YrhdgbjTaJkHWZbH63/QU l9qHj3+pHZdAdR16YTPt6HIC+9tKYkX/u2Ut9ARX2Z69z2vf56uSZ3zXcVSS7/7AHp7X 8D6wHNwxgVrbgrLj5zRaExqOeYICuchxUewMXWZ8pRPauPEJFqeml6/v+bAk6U1Couje 3CPXAWjuTVjjR9/nwln1F3nAWBNf0jHX4opQu7rkWamPlhGMg9FGZBiT9Sa+Z2pDeG1b SWtuOSUz7ZatSt2dgX6zjh1KRW+PJR8QrRwyFbFyCQeuMKleBjavvcU4yWthrcLLXmqx +hkQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature; bh=IDKOkzngvCNd5neZHySPALtiWyrf9Lcw0FeR6NFiinU=; b=sDfkteL9c7mqY4LyVSdw8Hnx2D5LGPaUX/GuFmDXtyW8Bc2bxxBR0NowkDOCgaRuBY nx+42/zYbu4ZHr3Mz+i7t0pzvAXG3hU1G2ts2OHhCztSWld8musSy38LGVC0L6Z72cy9 iPYOIBPUNKgQmBpVQyQo0en5SMZD/qeY2QLYkYk5kjGHPHsiByuwOKND6GTSOAyMFTYn RA9UGYfjkFxRdELdVju+drbDqPV6LAAML1/klGLgoZXLT+ExrYKqsZiA0SaMwtUuZlYU 06lD4TnGt/A4rMKdz7TCEQ6dJ8lPXe+rQDTsSMwUBdBzEF0Ar1QYA94DNMGN14pcu8P7 t8tg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@ti.com header.s=ti-com-17Q1 header.b=Hf1hOuZU; 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; dmarc=pass (p=QUARANTINE sp=NONE dis=NONE) header.from=ti.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id 98si162055pls.205.2019.02.04.06.24.02; Mon, 04 Feb 2019 06:24:03 -0800 (PST) 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=@ti.com header.s=ti-com-17Q1 header.b=Hf1hOuZU; 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; dmarc=pass (p=QUARANTINE sp=NONE dis=NONE) header.from=ti.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729210AbfBDOX6 (ORCPT + 31 others); Mon, 4 Feb 2019 09:23:58 -0500 Received: from fllv0016.ext.ti.com ([198.47.19.142]:42790 "EHLO fllv0016.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728937AbfBDOX4 (ORCPT ); Mon, 4 Feb 2019 09:23:56 -0500 Received: from fllv0034.itg.ti.com ([10.64.40.246]) by fllv0016.ext.ti.com (8.15.2/8.15.2) with ESMTP id x14EMxu3023115; Mon, 4 Feb 2019 08:22:59 -0600 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=ti-com-17Q1; t=1549290179; bh=IDKOkzngvCNd5neZHySPALtiWyrf9Lcw0FeR6NFiinU=; h=From:To:CC:Subject:Date:In-Reply-To:References; b=Hf1hOuZUgU/8fmU0B6HJxUthZuH+Lm5FNtpt+Mofy7+au0IG0OIE/m5bPVs9nLmCn dHzFhnREIzMyWsqVUMaf6HBhAK54+2Gwzd8TSCXKmYJl64G2hIhVc0iaMWmnHJ3S+N 2ESaMC7KbgeP+WWeom8zVGd0C56AIKRXCyRU9gj0= Received: from DLEE107.ent.ti.com (dlee107.ent.ti.com [157.170.170.37]) by fllv0034.itg.ti.com (8.15.2/8.15.2) with ESMTPS id x14EMxu8009717 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL); Mon, 4 Feb 2019 08:22:59 -0600 Received: from DLEE104.ent.ti.com (157.170.170.34) by DLEE107.ent.ti.com (157.170.170.37) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.1591.10; Mon, 4 Feb 2019 08:22:58 -0600 Received: from dflp32.itg.ti.com (10.64.6.15) by DLEE104.ent.ti.com (157.170.170.34) with Microsoft SMTP Server (version=TLS1_0, cipher=TLS_RSA_WITH_AES_256_CBC_SHA) id 15.1.1591.10 via Frontend Transport; Mon, 4 Feb 2019 08:22:58 -0600 Received: from localhost.localdomain (ileax41-snat.itg.ti.com [10.172.224.153]) by dflp32.itg.ti.com (8.14.3/8.13.8) with ESMTP id x14EMoKZ012232; Mon, 4 Feb 2019 08:22:55 -0600 From: Roger Quadros To: , , CC: , , , , , , , , , , , , Subject: [PATCH v2 01/14] dt-bindings: remoteproc: Add TI PRUSS bindings Date: Mon, 4 Feb 2019 16:22:34 +0200 Message-ID: <1549290167-876-2-git-send-email-rogerq@ti.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1549290167-876-1-git-send-email-rogerq@ti.com> References: <1549290167-876-1-git-send-email-rogerq@ti.com> MIME-Version: 1.0 X-EXCLAIMER-MD-CONFIG: e1e8a2fd-e40a-4ac6-ac9b-f7e9cc9ee180 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Suman Anna This patch adds the bindings for the Programmable Real-Time Unit and Industrial Communication Subsystem (PRU-ICSS) present on various SoCs such as AM33xx, AM437x, AM57xx, Keystone 66AK2G SoC, etc. It is present on the Davinci based OMAPL138 SoCs and K3 architecture based AM65x SoCs as well (not covered for now). Signed-off-by: Suman Anna Signed-off-by: Roger Quadros --- .../devicetree/bindings/soc/ti/ti,pruss.txt | 212 +++++++++++++++++++++ 1 file changed, 212 insertions(+) create mode 100644 Documentation/devicetree/bindings/soc/ti/ti,pruss.txt -- Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki. Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki diff --git a/Documentation/devicetree/bindings/soc/ti/ti,pruss.txt b/Documentation/devicetree/bindings/soc/ti/ti,pruss.txt new file mode 100644 index 0000000..5ac76fd --- /dev/null +++ b/Documentation/devicetree/bindings/soc/ti/ti,pruss.txt @@ -0,0 +1,212 @@ +PRU-ICSS on TI SoCs +=================== + +The Programmable Real-Time Unit and Industrial Communication Subsystem +(PRU-ICSS) is present on various TI SoCs such as AM335x, AM437x, Keystone +66AK2G, etc. A PRUSS consists of dual 32-bit RISC cores (Programmable +Real-Time Units, or PRUs) with program memory and data memory. + +The programmable nature of the PRUs provide flexibility to implement +custom peripheral interfaces, fast real-time responses, or specialized +data handling. The common peripheral modules include the following, + + - Enhanced GPIO with async capture and serial support + - an Ethernet MII_RT module with two MII ports + - an MDIO port to control external Ethernet PHYs + - an Industrial Ethernet Peripheral (IEP) to manage/generate Industrial + Ethernet functions + - an Enhanced Capture Module (eCAP) + - a 16550-compatible UART to support PROFIBUS + - Interrupt controller with 64 input events and 10 Host interrupts. + +A shared Data RAM, if present, can be accessed by both the PRU cores. The +Interrupt Controller (INTC) and a CFG module are common to both the PRU +cores. + +Various sub-modules within a PRU-ICSS subsystem are represented as individual +nodes. + +PRUSS Node +============= + +This node represents the entire ICSS instance and the various modules are +contained as children. The PRUSS driver is responsible for managing the +common resources i.e. DRAM0, DRAM1, SHARED_RAM and CFG space. + +Required Properties: +-------------------- +- compatible : should be one of, + "ti,am3356-pruss" for AM335x family of SoCs + "ti,am4376-pruss" for AM437x family of SoCs + "ti,am5728-pruss" for AM57xx family of SoCs + "ti,k2g-pruss" for 66AK2G family of SoCs +- reg : base address and size for each of the Data RAMs as + mentioned in reg-names, and in the same order as the + reg-names +- reg-names : should contain a string(s) from among the following names, + each representing a specific Data RAM region. Some PRU-ICSS + instances on certain SoCs might not have Shared DRAM. + "dram0" for Data RAM0, + "dram1" for Data RAM1, + "shrdram2" for Shared Data RAM, +- #address-cells : should be 1 +- #size-cells : should be 1 +- ranges : no specific range translations required, child nodes have the + same address view as the parent, so should be mentioned without + any value for the property + +Optional Properties: +-------------------- +- no-shared-ram : Should be present if the instance doesn't have Shared RAM. + e.g. AM4376 ICSS0 instance doesn't have Shared RAM. + +The PRUSS node will have one or more of the folowing child nodes. + +PRU CORES +========= +ICSS typically has 2 PRU cores. These should be represented as remoteproc devices. + +INTC node +========= +ICSS has one INTC interrupt controller module. This should be represented as +a standard interrupt-controller node. + +CFG, IEP, MII_RT +================ +The individual sub-modules CFG, IEP and MII_RT are represented as a syscon +node each with specific node names as below: + "cfg" for CFG sub-module, + "iep" for IEP sub-module, + "mii_rt" for MII-RT sub-module, + +See Documentation/devicetree/bindings/mfd/syscon.txt for details. + +MDIO +==== +Each PRUSS has an MDIO module that can be used to control external PHYs. The +MDIO module used within the PRU-ICSS is an instance of the MDIO Controller +used in TI Davinci SoCs. Please refer to the corresponding binding document, +Documentation/devicetree/bindings/net/davinci-mdio.txt for details. + +Application/User Nodes +======================= +A PRU application/user node typically uses one or more PRU device nodes to +implement a PRU application/functionality. Each application/client node would +need a reference to at least a PRU node, and optionally pass some configuration +parameters. + +Required Properties: +-------------------- +- prus : phandles to the PRU nodes used + +Optional Properties: +-------------------- +- firmware-name : firmwares for the PRU cores, the default firmware + for the core from the PRU node will be used if not + provided. The firmware names should correspond to + the PRU cores listed in the 'prus' property +- ti,pruss-gp-mux-sel : array of values for the GP_MUX_SEL under PRUSS_GPCFG + register for a PRU. This selects the internal muxing + scheme for the PRU instance. If not provided, the + default out-of-reset value (0) for the PRU core is + used. Values should correspond to the PRU cores listed + in the 'prus' property +- ti,pru-interrupt-map : PRU interrupt mappings, containing an array of entries + with each entry consisting of 4 cell-values. First one + is an index towards the "prus" property to identify the + PRU core for the interrupt map, second is the PRU + System Event id, third is the PRU interrupt channel id + and fourth is the PRU host interrupt id. If provided, + this map will supercede any other configuration + provided through firmware + +Example: +======== +1. /* AM33xx PRU-ICSS */ + + pruss: pruss@0 { + compatible = "ti,am3356-pruss"; + reg = <0x0 0x2000>, + <0x2000 0x2000>, + <0x10000 0x3000>; + reg-names = "dram0", "dram1", + "shrdram2"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + pruss_cfg: cfg@26000 { + compatible = "syscon"; + reg = <0x26000 0x2000>; + }; + + pruss_iep: iep@2e000 { + compatible = "syscon"; + reg = <0x2e000 0x31c>; + }; + + pruss_mii_rt: mii_rt@32000 { + compatible = "syscon"; + reg = <0x32000 0x58>; + }; + + pruss_intc: intc@20000 { + compatible = "ti,am3356-pruss-intc"; + reg = <0x20000 0x2000>; + reg-names = "intc"; + interrupt-controller; + #interrupt-cells = <1>; + interrupts = <20 21 22 23 24 25 26 27>; + interrupt-names = "host2", "host3", "host4", + "host5", "host6", "host7", + "host8", "host9"; + }; + + pru0: pru@34000 { + compatible = "ti,am3356-pru"; + reg = <0x34000 0x2000>, + <0x22000 0x400>, + <0x22400 0x100>; + reg-names = "iram", "control", "debug"; + gpcfg = <&pruss_cfg 0x8>; + firmware-name = "am335x-pru0-fw"; + interrupt-parent = <&pruss_intc>; + interrupts = <16>, <17>; + interrupt-names = "vring", "kick"; + }; + + pru1: pru@38000 { + compatible = "ti,am3356-pru"; + reg = <0x38000 0x2000>, + <0x24000 0x400>, + <0x24400 0x100>; + reg-names = "iram", "control", "debug"; + gpcfg = <&pruss_cfg 0xc>; + firmware-name = "am335x-pru1-fw"; + interrupt-parent = <&pruss_intc>; + interrupts = <18>, <19>; + interrupt-names = "vring", "kick"; + }; + + pruss_mdio: mdio@32400 { + compatible = "ti,davinci_mdio"; + reg = <0x32400 0x90>; + clocks = <&dpll_core_m4_ck>; + clock-names = "fck"; + bus_freq = <1000000>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + }; + +2: /* PRU application node example */ + app_node: app_node { + prus = <&pru0>, <&pru1>; + firmware-name = "pruss-app-fw", "pruss-app-fw-2"; + ti,pruss-gp-mux-sel = <2>, <1>; + /* setup interrupts for prus: + prus[0] => pru1_0: ev=16, chnl=2, host-irq=7, + prus[1] => pru1_1: ev=19, chnl=1, host-irq=3 */ + ti,pru-interrupt-map = <0 16 2 7 >, <1 19 1 3>; + } From patchwork Mon Feb 4 14:22:36 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roger Quadros X-Patchwork-Id: 157424 Delivered-To: patch@linaro.org Received: by 2002:a02:48:0:0:0:0:0 with SMTP id 69csp3973942jaa; Mon, 4 Feb 2019 06:24:27 -0800 (PST) X-Google-Smtp-Source: ALg8bN4/cfSO6fIpsp+tdXDtnF0Lf6sVfrzE8zw2rwDluwEeMSNTc/UCVOoVmqCrxrZIy2IORV/U X-Received: by 2002:a62:5793:: with SMTP id i19mr51695700pfj.49.1549290267519; Mon, 04 Feb 2019 06:24:27 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1549290267; cv=none; d=google.com; s=arc-20160816; b=evF1zO7C2NdCX6XFtQDy/gH3dR77XzyB3MGBxhHF+rqByIA+v/1GMNAOvJ9NKhcpFT fEDTNw8bdV+TSRV6hwhSPix6Dp3qSh9+DqlzFiDqbGftRzVtlUUjmA+1rWJ6Mqs4jPW8 s2xJvA19Gq0Sc1KoKQpvi6RsUYYUO/vEcrZuuOqavrqdSmJsDiwNsHzA4ECMVKFdg7dN ysI/TPMzHTEAOmlzx5/MGnvbnoPEf/QvOkTQL5f2jLzuJB2RvJCIcqx7Cw8DxhVvptqh /OSsM486eG93o5gCzPgXeagVURf5hF+DYkOLkZnW0ysdHPsasHunqcL2heEjaqPS2mu0 hxwQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature; bh=BybUACh2KOzPXi9WzljjTKIRZASeNQ0xo78WVaTHwO4=; b=ShX0ssVOjZweZZpgilFRemK02FTTRLwEJpf1VNLTiIGD0qG5f3+2bMHYsWpxmrQGr6 p5h8Cqv/bqX0ceI39HBFpkBuGurZOMIHEdeUEv7rDges98yCHnBWreEGXefhJLj4+ki3 kGLxtJwVbIa9iG+AvqLiXwSU64W7KUXgh9GShDkR2XupiNY9X2P0s22wlTt9Gj3rKZgL WZ2Puh01Fnk/qD5u2Cv5ErDdgkRwZmOJ2sD6I7xV4tRGRggkfX3U+BTUxNF/GzNJLDrP RacRIp8uQNPDnQay/BZ4iNQQXRY9pdxN1fpmP7x6Pz0PfjBh8AdzCTZecxRkQnnPB0Tk LxlA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@ti.com header.s=ti-com-17Q1 header.b="VEXJ/ypB"; 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; dmarc=pass (p=QUARANTINE sp=NONE dis=NONE) header.from=ti.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id j63si162866pgc.109.2019.02.04.06.24.27; Mon, 04 Feb 2019 06:24:27 -0800 (PST) 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=@ti.com header.s=ti-com-17Q1 header.b="VEXJ/ypB"; 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; dmarc=pass (p=QUARANTINE sp=NONE dis=NONE) header.from=ti.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729875AbfBDOYZ (ORCPT + 31 others); Mon, 4 Feb 2019 09:24:25 -0500 Received: from fllv0015.ext.ti.com ([198.47.19.141]:43232 "EHLO fllv0015.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728861AbfBDOYY (ORCPT ); Mon, 4 Feb 2019 09:24:24 -0500 Received: from fllv0034.itg.ti.com ([10.64.40.246]) by fllv0015.ext.ti.com (8.15.2/8.15.2) with ESMTP id x14EN8rd031778; Mon, 4 Feb 2019 08:23:08 -0600 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=ti-com-17Q1; t=1549290188; bh=BybUACh2KOzPXi9WzljjTKIRZASeNQ0xo78WVaTHwO4=; h=From:To:CC:Subject:Date:In-Reply-To:References; b=VEXJ/ypBN5PdLeyHE9uxiTLiFoo+dlDmCQ07qTTWIz8Z0YnwBUGkeiRRZ85PrQGej dsEQ1zgAr/HbDW3kaEPigXZBFacP1UfBSE86TkfvQMQ7PncJlBkAVKcFZCL5LCmvXL FpRgj4gXQtOYOv9zNwXvpFV2IKpfvYXpJ+U72kOk= Received: from DFLE102.ent.ti.com (dfle102.ent.ti.com [10.64.6.23]) by fllv0034.itg.ti.com (8.15.2/8.15.2) with ESMTPS id x14EN8df010126 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL); Mon, 4 Feb 2019 08:23:08 -0600 Received: from DFLE102.ent.ti.com (10.64.6.23) by DFLE102.ent.ti.com (10.64.6.23) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.1591.10; Mon, 4 Feb 2019 08:23:07 -0600 Received: from dflp32.itg.ti.com (10.64.6.15) by DFLE102.ent.ti.com (10.64.6.23) with Microsoft SMTP Server (version=TLS1_0, cipher=TLS_RSA_WITH_AES_256_CBC_SHA) id 15.1.1591.10 via Frontend Transport; Mon, 4 Feb 2019 08:23:07 -0600 Received: from localhost.localdomain (ileax41-snat.itg.ti.com [10.172.224.153]) by dflp32.itg.ti.com (8.14.3/8.13.8) with ESMTP id x14EMoKb012232; Mon, 4 Feb 2019 08:23:03 -0600 From: Roger Quadros To: , , CC: , , , , , , , , , , , , , "Andrew F. Davis" , Thomas Gleixner , Jason Cooper , Marc Zyngier , Rob Herring Subject: [PATCH v2 03/14] dt-binding: irqchip: Add pruss-intc-irq driver for PRUSS interrupts Date: Mon, 4 Feb 2019 16:22:36 +0200 Message-ID: <1549290167-876-4-git-send-email-rogerq@ti.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1549290167-876-1-git-send-email-rogerq@ti.com> References: <1549290167-876-1-git-send-email-rogerq@ti.com> MIME-Version: 1.0 X-EXCLAIMER-MD-CONFIG: e1e8a2fd-e40a-4ac6-ac9b-f7e9cc9ee180 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: "Andrew F. Davis" The Programmable Real-Time Unit Subsystem (PRUSS) contains an interrupt controller (INTC) that can handle various system input events and post interrupts back to the device-level initiators. The INTC can support upto 64 input events with individual control configuration and hardware prioritization. These events are mapped onto 10 interrupt signals through two levels of many-to-one mapping support. Different interrupt signals are routed to the individual PRU cores or to the host CPU. The PRUSS INTC platform driver manages this PRUSS interrupt controller and implements an irqchip driver to provide a Linux standard way for the PRU client users to enable/disable/ack/ re-trigger a PRUSS system event. The system events to interrupt channels and host interrupts relies on the mapping configuration provided through a firmware resource table for now. This will be revisited and enhanced in the future for a better interface. The mappings will currently be programmed during the boot/shutdown of the PRU. Cc: Thomas Gleixner Cc: Jason Cooper Cc: Marc Zyngier Cc: Rob Herring Signed-off-by: Andrew F. Davis Signed-off-by: Roger Quadros --- .../interrupt-controller/ti,pruss-intc-irq.txt | 51 ++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/ti,pruss-intc-irq.txt -- Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki. Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki diff --git a/Documentation/devicetree/bindings/interrupt-controller/ti,pruss-intc-irq.txt b/Documentation/devicetree/bindings/interrupt-controller/ti,pruss-intc-irq.txt new file mode 100644 index 0000000..c70221c --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/ti,pruss-intc-irq.txt @@ -0,0 +1,51 @@ +PRU ICSS INTC on TI SoCs +======================== + +Each PRUSS has a single interrupt controller instance that is common to both +the PRU cores. Each interrupt controller can detect 64 input events which are +then mapped to 10 possible output interrupts through two levels of mapping. The +input events can be triggered by either the PRUs and/or various other PRUSS +internal and external peripherals. The first 2 output interrupts are fed +exclusively to the internal PRU cores, with the remaining 8 connected to +external interrupt controllers including the MPU. + +Required Properties: +-------------------- +- compatible : should be one of, + "ti,am3356-pruss-intc" for AM335x family of SoCs + "ti,am4376-pruss-intc" for AM437x family of SoCs + "ti,am5728-pruss-intc" for AM57xx family of SoCs + "ti,k2g-pruss-intc" for 66AK2G family of SoCs +- reg : base address and size for the PRUSS INTC sub-module +- reg-names : should contain the string "intc" +- interrupts : all the interrupts generated towards the main host + processor in the SoC. The format depends on the + interrupt specifier for the particular SoC's MPU + parent interrupt controller +- interrupt-names: should use one of the following names for each interrupt, + the name should match the corresponding host interrupt + number, + "host2", "host3", "host4", "host5", "host6", + "host7", "host8" or "host9" + NOTE: AM437x and 66AK2G SoCs do not have "host7" interrupt + connected to MPU +- interrupt-controller : mark this node as an interrupt controller +- #interrupt-cells : should be 1. Client users shall use the PRU System + event number (the interrupt source that the client + is interested in) as the value of the interrupts + property in their node + +Example: +-------- + pruss_intc: intc@20000 { + compatible = "ti,am3356-pruss-intc"; + reg = <0x20000 0x2000>; + reg-names = "intc"; + interrupt-controller; + #interrupt-cells = <1>; + interrupts = <20 21 22 23 24 25 26 27>; + interrupt-names = "host2", "host3", "host4", + "host5", "host6", "host7", + "host8", "host9"; + }; + From patchwork Mon Feb 4 14:22:37 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roger Quadros X-Patchwork-Id: 157431 Delivered-To: patch@linaro.org Received: by 2002:a02:48:0:0:0:0:0 with SMTP id 69csp3974551jaa; Mon, 4 Feb 2019 06:25:02 -0800 (PST) X-Google-Smtp-Source: ALg8bN5W8fWN7hrENSMfpcURvZrdZ6RBnKqOl+K6SXcPCwLEoJnCoPYAsokBytjmgQZVvTPTXflh X-Received: by 2002:a17:902:2c03:: with SMTP id m3mr49300198plb.6.1549290302054; Mon, 04 Feb 2019 06:25:02 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1549290302; cv=none; d=google.com; s=arc-20160816; b=YGAw+l/S3ksLpQC05GBnwp2vUis2XjA5CtCV86ngfTdPYsnKd7PcphIPmQHlCxyKfG Wmyu6kijGmzfWxtfdwF1W6AiEwtOoohOL2woBYQ3/2zL8NsN9R3KD3Q8kO9GwFEtWgFG tuFCQeIQBcqn386JXs05KPW9t3fXfjgPNeZKk4aZt+Ng5vapPCVFbGfJ4Mgu3eGWBRSJ B/vxXNzYrciTP4PX9RArjAPVx8tAuGvv4w4ard/5tmKo/LbyRzCkneqIS+dhNxSuKfd3 IVeMel44Uqb6GYBiZW6CcnTAmXtx264H/F/cgdS1DTHcCdNS+s/60UtfWlhBTJMxUOLG Df+w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature; bh=kIfHEbwbqqHCTgZNvJq/D6eZLWtRyKa3gcvCQXgGv1Y=; b=y2VRZryos1VjL2mHfXe9LGy+uJv6sPy7GxB1ZvoA/TO6brBnl5qy04VEqan62Kq6tf 3vbz3j7gsA8zXqIIkN202j7x4l/j9xkCRoNymXIngLWVBQagfw+UprWn4dfcIrgHvk0i ZLqUoed4xBMFW3ed91g6nVOsCDQlynlh7P3/OdxA1N8RqFIVqO6pcAnSmgpGoHNfO1BN 1cg24iJyBwhNPftKMrDD2fIkJwaS62/7LGFSUvzCpE5HddoR6XE1HuGL1Qz5GP9Collj jRDl8XQsmLQUt7dilb64T54lL3+sKoe81ePpKuWK6naPQ33nVvLYSSnXUncgtqeTv8Ql y98A== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@ti.com header.s=ti-com-17Q1 header.b=LhbughQ0; 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; dmarc=pass (p=QUARANTINE sp=NONE dis=NONE) header.from=ti.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id l33si175223pld.142.2019.02.04.06.25.01; Mon, 04 Feb 2019 06:25:02 -0800 (PST) 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=@ti.com header.s=ti-com-17Q1 header.b=LhbughQ0; 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; dmarc=pass (p=QUARANTINE sp=NONE dis=NONE) header.from=ti.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729999AbfBDOY7 (ORCPT + 31 others); Mon, 4 Feb 2019 09:24:59 -0500 Received: from lelv0142.ext.ti.com ([198.47.23.249]:59680 "EHLO lelv0142.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729937AbfBDOYe (ORCPT ); Mon, 4 Feb 2019 09:24:34 -0500 Received: from lelv0265.itg.ti.com ([10.180.67.224]) by lelv0142.ext.ti.com (8.15.2/8.15.2) with ESMTP id x14ENDtL092213; Mon, 4 Feb 2019 08:23:13 -0600 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=ti-com-17Q1; t=1549290193; bh=kIfHEbwbqqHCTgZNvJq/D6eZLWtRyKa3gcvCQXgGv1Y=; h=From:To:CC:Subject:Date:In-Reply-To:References; b=LhbughQ0TOg9zfwmOQbg3T31Xpa+oTePLgAG8scPoy+C6kTL/KDLMvPXyt7kFEksu /P78sOFJpqQKndt6RvenaAXSw/d616afpWvhGaWsTH1vZXAcuq7IfVT7YYUMj238lq /V2BfO+4GjHbPvSmBVkojIgsJpgGi2YXKQ7P+aJI= Received: from DLEE108.ent.ti.com (dlee108.ent.ti.com [157.170.170.38]) by lelv0265.itg.ti.com (8.15.2/8.15.2) with ESMTPS id x14ENDtg048781 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL); Mon, 4 Feb 2019 08:23:13 -0600 Received: from DLEE103.ent.ti.com (157.170.170.33) by DLEE108.ent.ti.com (157.170.170.38) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.1591.10; Mon, 4 Feb 2019 08:23:12 -0600 Received: from dflp32.itg.ti.com (10.64.6.15) by DLEE103.ent.ti.com (157.170.170.33) with Microsoft SMTP Server (version=TLS1_0, cipher=TLS_RSA_WITH_AES_256_CBC_SHA) id 15.1.1591.10 via Frontend Transport; Mon, 4 Feb 2019 08:23:12 -0600 Received: from localhost.localdomain (ileax41-snat.itg.ti.com [10.172.224.153]) by dflp32.itg.ti.com (8.14.3/8.13.8) with ESMTP id x14EMoKc012232; Mon, 4 Feb 2019 08:23:08 -0600 From: Roger Quadros To: , , CC: , , , , , , , , , , , , , "Andrew F. Davis" , Thomas Gleixner , Jason Cooper , Marc Zyngier Subject: [PATCH v2 04/14] irqchip: pruss: Add a PRUSS irqchip driver for PRUSS interrupts Date: Mon, 4 Feb 2019 16:22:37 +0200 Message-ID: <1549290167-876-5-git-send-email-rogerq@ti.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1549290167-876-1-git-send-email-rogerq@ti.com> References: <1549290167-876-1-git-send-email-rogerq@ti.com> MIME-Version: 1.0 X-EXCLAIMER-MD-CONFIG: e1e8a2fd-e40a-4ac6-ac9b-f7e9cc9ee180 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: "Andrew F. Davis" The Programmable Real-Time Unit Subsystem (PRUSS) contains an interrupt controller (INTC) that can handle various system input events and post interrupts back to the device-level initiators. The INTC can support upto 64 input events with individual control configuration and hardware prioritization. These events are mapped onto 10 interrupt signals through two levels of many-to-one mapping support. Different interrupt signals are routed to the individual PRU cores or to the host CPU. The PRUSS INTC platform driver manages this PRUSS interrupt controller and implements an irqchip driver to provide a Linux standard way for the PRU client users to enable/disable/ack/ re-trigger a PRUSS system event. The system events to interrupt channels and host interrupts relies on the mapping configuration provided through a firmware resource table for now. This will be revisited and enhanced in the future for a better interface. The mappings will currently be programmed during the boot/shutdown of the PRU. The PRUSS INTC module is reference counted during the interrupt setup phase through the irqchip's irq_request_resources() and irq_release_resources() ops. This restricts the module from being removed as long as there are active interrupt users. The PRUSS INTC can generate an interrupt to various processor subsystems on the SoC through a set of 64 possible PRU system events. These system events can be used by PRU client drivers or applications for event notifications/signalling between PRUs and MPU or other processors. An API, pruss_intc_trigger() is provided to MPU-side PRU client drivers/applications to be able to trigger an event/interrupt using IRQ numbers provided by the PRUSS-INTC irqdomain chip. Cc: Thomas Gleixner Cc: Jason Cooper Cc: Marc Zyngier Signed-off-by: Andrew F. Davis Signed-off-by: Suman Anna Signed-off-by: Roger Quadros --- drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-pruss-intc.c | 630 +++++++++++++++++++++++++++++++++ include/linux/irqchip/irq-pruss-intc.h | 94 +++++ 3 files changed, 725 insertions(+) create mode 100644 drivers/irqchip/irq-pruss-intc.c create mode 100644 include/linux/irqchip/irq-pruss-intc.h -- Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki. Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index c93713d..e309101 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -94,3 +94,4 @@ obj-$(CONFIG_CSKY_APB_INTC) += irq-csky-apb-intc.o obj-$(CONFIG_SIFIVE_PLIC) += irq-sifive-plic.o obj-$(CONFIG_IMX_IRQSTEER) += irq-imx-irqsteer.o obj-$(CONFIG_MADERA_IRQ) += irq-madera.o +obj-$(CONFIG_TI_PRUSS) += irq-pruss-intc.o diff --git a/drivers/irqchip/irq-pruss-intc.c b/drivers/irqchip/irq-pruss-intc.c new file mode 100644 index 0000000..0288535 --- /dev/null +++ b/drivers/irqchip/irq-pruss-intc.c @@ -0,0 +1,630 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * PRU-ICSS INTC IRQChip driver for various TI SoCs + * + * Copyright (C) 2016-2019 Texas Instruments Incorporated - http://www.ti.com/ + * Andrew F. Davis + * Suman Anna + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Number of host interrupts reaching the main MPU sub-system. Note that this + * is not the same as the total number of host interrupts supported by the PRUSS + * INTC instance + */ +#define MAX_HOST_NUM_IRQS 8 + +/* minimum starting host interrupt number for MPU */ +#define MIN_PRU_HOST_INT 2 + +/* maximum number of host interrupts */ +#define MAX_PRU_HOST_INT 10 + +/* PRU_ICSS_INTC registers */ +#define PRU_INTC_REVID 0x0000 +#define PRU_INTC_CR 0x0004 +#define PRU_INTC_GER 0x0010 +#define PRU_INTC_GNLR 0x001C +#define PRU_INTC_SISR 0x0020 +#define PRU_INTC_SICR 0x0024 +#define PRU_INTC_EISR 0x0028 +#define PRU_INTC_EICR 0x002C +#define PRU_INTC_HIEISR 0x0034 +#define PRU_INTC_HIDISR 0x0038 +#define PRU_INTC_GPIR 0x0080 +#define PRU_INTC_SRSR0 0x0200 +#define PRU_INTC_SRSR1 0x0204 +#define PRU_INTC_SECR0 0x0280 +#define PRU_INTC_SECR1 0x0284 +#define PRU_INTC_ESR0 0x0300 +#define PRU_INTC_ESR1 0x0304 +#define PRU_INTC_ECR0 0x0380 +#define PRU_INTC_ECR1 0x0384 +#define PRU_INTC_CMR(x) (0x0400 + (x) * 4) +#define PRU_INTC_HMR(x) (0x0800 + (x) * 4) +#define PRU_INTC_HIPIR(x) (0x0900 + (x) * 4) +#define PRU_INTC_SIPR0 0x0D00 +#define PRU_INTC_SIPR1 0x0D04 +#define PRU_INTC_SITR0 0x0D80 +#define PRU_INTC_SITR1 0x0D84 +#define PRU_INTC_HINLR(x) (0x1100 + (x) * 4) +#define PRU_INTC_HIER 0x1500 + +/* HIPIR register bit-fields */ +#define INTC_HIPIR_NONE_HINT 0x80000000 + +static const char * const irq_names[] = { + "host2", "host3", "host4", "host5", "host6", "host7", "host8", "host9", +}; + +/** + * struct pruss_intc_match_data - match data to handle SoC variations + * @no_host7_intr: flag denoting the absence of host7 interrupt into MPU + */ +struct pruss_intc_match_data { + bool no_host7_intr; +}; + +/** + * struct pruss_intc - PRUSS interrupt controller structure + * @irqs: kernel irq numbers corresponding to PRUSS host interrupts + * @mem: base virtual address of INTC register space + * @irqchip: irq chip for this interrupt controller + * @domain: irq domain for this interrupt controller + * @config_map: stored INTC configuration mapping data + * @lock: mutex to serialize access to INTCa + * @host_mask: indicate which HOST IRQs are enabled + */ +struct pruss_intc { + unsigned int irqs[MAX_HOST_NUM_IRQS]; + void __iomem *base; + struct irq_chip *irqchip; + struct irq_domain *domain; + struct pruss_intc_config config_map; + struct mutex lock; /* PRUSS INTC lock */ + u32 host_mask; +}; + +static inline u32 pruss_intc_read_reg(struct pruss_intc *intc, unsigned int reg) +{ + return readl_relaxed(intc->base + reg); +} + +static inline void pruss_intc_write_reg(struct pruss_intc *intc, + unsigned int reg, u32 val) +{ + writel_relaxed(val, intc->base + reg); +} + +static int pruss_intc_check_write(struct pruss_intc *intc, unsigned int reg, + unsigned int sysevent) +{ + if (!intc) + return -EINVAL; + + if (sysevent >= MAX_PRU_SYS_EVENTS) + return -EINVAL; + + pruss_intc_write_reg(intc, reg, sysevent); + + return 0; +} + +static struct pruss_intc *dev_to_intc(struct device *user_dev) +{ + struct device_node *np; + struct platform_device *pdev; + struct pruss_intc *intc; + + np = of_irq_find_parent(user_dev->of_node); + if (!np) + return ERR_PTR(-ENODEV); + + pdev = of_find_device_by_node(np); + if (!pdev) + return ERR_PTR(-EPROBE_DEFER); /* Not probed yet? */ + + intc = platform_get_drvdata(pdev); + if (!intc) + return ERR_PTR(-EINVAL); + + return intc; +} + +/** + * pruss_intc_configure() - configure the PRUSS INTC + * @dev: device + * @intc_config: PRU core-specific INTC configuration + * + * Configures the PRUSS INTC with the provided configuration from + * a PRU core. Any existing event to channel mappings or channel to + * host interrupt mappings are checked to make sure there are no + * conflicting configuration between both the PRU cores. The function + * is intended to be used only by the PRU remoteproc driver. + * + * Returns 0 on success, or a suitable error code otherwise + */ +int pruss_intc_configure(struct device *dev, + struct pruss_intc_config *intc_config) +{ + struct pruss_intc *intc; + int i, idx, ret; + s8 ch, host; + u64 sysevt_mask = 0; + u32 ch_mask = 0; + u32 host_mask = 0; + u32 val; + + intc = dev_to_intc(dev); + if (IS_ERR(intc)) + return PTR_ERR(intc); + + mutex_lock(&intc->lock); + + /* + * configure channel map registers - each register holds map info + * for 4 events, with each event occupying the lower nibble in + * a register byte address in little-endian fashion + */ + for (i = 0; i < ARRAY_SIZE(intc_config->sysev_to_ch); i++) { + ch = intc_config->sysev_to_ch[i]; + if (ch < 0) + continue; + + /* check if sysevent already assigned */ + if (intc->config_map.sysev_to_ch[i] != -1) { + dev_err(dev, "event %d (req. channel %d) already assigned to channel %d\n", + i, ch, intc->config_map.sysev_to_ch[i]); + ret = -EEXIST; + goto unlock; + } + + intc->config_map.sysev_to_ch[i] = ch; + + idx = i / 4; + val = pruss_intc_read_reg(intc, PRU_INTC_CMR(idx)); + val |= ch << ((i & 3) * 8); + pruss_intc_write_reg(intc, PRU_INTC_CMR(idx), val); + sysevt_mask |= BIT_ULL(i); + ch_mask |= BIT(ch); + + dev_dbg(dev, "SYSEV%d -> CH%d (CMR%d 0x%08x)\n", i, ch, idx, + pruss_intc_read_reg(intc, PRU_INTC_CMR(idx))); + } + + /* + * set host map registers - each register holds map info for + * 4 channels, with each channel occupying the lower nibble in + * a register byte address in little-endian fashion + */ + for (i = 0; i < ARRAY_SIZE(intc_config->ch_to_host); i++) { + host = intc_config->ch_to_host[i]; + if (host < 0) + continue; + + /* check if channel already assigned */ + if (intc->config_map.ch_to_host[i] != -1) { + dev_err(dev, "channel %d (req. intr_no %d) already assigned to intr_no %d\n", + i, host, intc->config_map.ch_to_host[i]); + ret = -EEXIST; + goto unlock; + } + + /* check if host intr is already in use by other PRU */ + if (intc->host_mask & (1U << host)) { + dev_err(dev, "%s: host intr %d already in use\n", + __func__, host); + ret = -EEXIST; + goto unlock; + } + + intc->config_map.ch_to_host[i] = host; + + idx = i / 4; + + val = pruss_intc_read_reg(intc, PRU_INTC_HMR(idx)); + val |= host << ((i & 3) * 8); + pruss_intc_write_reg(intc, PRU_INTC_HMR(idx), val); + + ch_mask |= BIT(i); + host_mask |= BIT(host); + + dev_dbg(dev, "CH%d -> HOST%d (HMR%d 0x%08x)\n", i, host, idx, + pruss_intc_read_reg(intc, PRU_INTC_HMR(idx))); + } + + dev_info(dev, "intc: config: system_events = 0x%016llx intr_channels = 0x%08x host_intr = 0x%08x\n", + sysevt_mask, ch_mask, host_mask); + + /* enable system events, writing 0 has no-effect */ + pruss_intc_write_reg(intc, PRU_INTC_ESR0, lower_32_bits(sysevt_mask)); + pruss_intc_write_reg(intc, PRU_INTC_SECR0, lower_32_bits(sysevt_mask)); + pruss_intc_write_reg(intc, PRU_INTC_ESR1, upper_32_bits(sysevt_mask)); + pruss_intc_write_reg(intc, PRU_INTC_SECR1, upper_32_bits(sysevt_mask)); + + /* enable host interrupts */ + for (i = 0; i < MAX_PRU_HOST_INT; i++) { + if (host_mask & BIT(i)) + pruss_intc_write_reg(intc, PRU_INTC_HIEISR, i); + } + + /* global interrupt enable */ + pruss_intc_write_reg(intc, PRU_INTC_GER, 1); + + intc->host_mask |= host_mask; + + mutex_unlock(&intc->lock); + return 0; + +unlock: + mutex_unlock(&intc->lock); + return ret; +} +EXPORT_SYMBOL_GPL(pruss_intc_configure); + +/** + * pruss_intc_unconfigure() - unconfigure the PRUSS INTC + * @dev: device + * @intc_config: PRU core specific INTC configuration + * + * Undo whatever was done in pruss_intc_configure() for a PRU core. + * It should be sufficient to just mark the resources free in the + * global map and disable the host interrupts and sysevents. + */ +int pruss_intc_unconfigure(struct device *dev, + struct pruss_intc_config *intc_config) +{ + struct pruss_intc *intc; + int i; + s8 ch, host; + u64 sysevt_mask = 0; + u32 host_mask = 0; + + intc = dev_to_intc(dev); + if (IS_ERR(intc)) + return PTR_ERR(intc); + + mutex_lock(&intc->lock); + + for (i = 0; i < ARRAY_SIZE(intc_config->sysev_to_ch); i++) { + ch = intc_config->sysev_to_ch[i]; + if (ch < 0) + continue; + + /* mark sysevent free in global map */ + intc->config_map.sysev_to_ch[i] = -1; + sysevt_mask |= BIT_ULL(i); + } + + for (i = 0; i < ARRAY_SIZE(intc_config->ch_to_host); i++) { + host = intc_config->ch_to_host[i]; + if (host < 0) + continue; + + /* mark channel free in global map */ + intc->config_map.ch_to_host[i] = -1; + host_mask |= BIT(host); + } + + dev_info(dev, "intc: unconfig: system_events = 0x%016llx host_intr = 0x%08x\n", + sysevt_mask, host_mask); + + /* disable system events, writing 0 has no-effect */ + pruss_intc_write_reg(intc, PRU_INTC_ECR0, lower_32_bits(sysevt_mask)); + pruss_intc_write_reg(intc, PRU_INTC_ECR1, upper_32_bits(sysevt_mask)); + /* clear any pending status */ + pruss_intc_write_reg(intc, PRU_INTC_SECR0, lower_32_bits(sysevt_mask)); + pruss_intc_write_reg(intc, PRU_INTC_SECR1, upper_32_bits(sysevt_mask)); + + /* disable host interrupts */ + for (i = 0; i < MAX_PRU_HOST_INT; i++) { + if (host_mask & BIT(i)) + pruss_intc_write_reg(intc, PRU_INTC_HIDISR, i); + } + + intc->host_mask &= ~host_mask; + mutex_unlock(&intc->lock); + + return 0; +} +EXPORT_SYMBOL_GPL(pruss_intc_unconfigure); + +static void pruss_intc_init(struct pruss_intc *intc) +{ + int i; + + /* configure polarity to active high for all system interrupts */ + pruss_intc_write_reg(intc, PRU_INTC_SIPR0, 0xffffffff); + pruss_intc_write_reg(intc, PRU_INTC_SIPR1, 0xffffffff); + + /* configure type to pulse interrupt for all system interrupts */ + pruss_intc_write_reg(intc, PRU_INTC_SITR0, 0); + pruss_intc_write_reg(intc, PRU_INTC_SITR1, 0); + + /* clear all 16 interrupt channel map registers */ + for (i = 0; i < 16; i++) + pruss_intc_write_reg(intc, PRU_INTC_CMR(i), 0); + + /* clear all 3 host interrupt map registers */ + for (i = 0; i < 3; i++) + pruss_intc_write_reg(intc, PRU_INTC_HMR(i), 0); +} + +static void pruss_intc_irq_ack(struct irq_data *data) +{ + struct pruss_intc *intc = irq_data_get_irq_chip_data(data); + unsigned int hwirq = data->hwirq; + + pruss_intc_check_write(intc, PRU_INTC_SICR, hwirq); +} + +static void pruss_intc_irq_mask(struct irq_data *data) +{ + struct pruss_intc *intc = irq_data_get_irq_chip_data(data); + unsigned int hwirq = data->hwirq; + + pruss_intc_check_write(intc, PRU_INTC_EICR, hwirq); +} + +static void pruss_intc_irq_unmask(struct irq_data *data) +{ + struct pruss_intc *intc = irq_data_get_irq_chip_data(data); + unsigned int hwirq = data->hwirq; + + pruss_intc_check_write(intc, PRU_INTC_EISR, hwirq); +} + +static int pruss_intc_irq_retrigger(struct irq_data *data) +{ + struct pruss_intc *intc = irq_data_get_irq_chip_data(data); + unsigned int hwirq = data->hwirq; + + return pruss_intc_check_write(intc, PRU_INTC_SISR, hwirq); +} + +static int pruss_intc_irq_reqres(struct irq_data *data) +{ + if (!try_module_get(THIS_MODULE)) + return -ENODEV; + + return 0; +} + +static void pruss_intc_irq_relres(struct irq_data *data) +{ + module_put(THIS_MODULE); +} + +/** + * pruss_intc_trigger() - trigger a PRU system event + * @irq: linux IRQ number associated with a PRU system event + * + * Trigger an interrupt by signalling a specific PRU system event. + * This can be used by PRUSS client users to raise/send an event to + * a PRU or any other core that is listening on the host interrupt + * mapped to that specific PRU system event. The @irq variable is the + * Linux IRQ number associated with a specific PRU system event that + * a client user/application uses. The interrupt mappings for this is + * provided by the PRUSS INTC irqchip instance. + * + * Returns 0 on success, or an error value upon failure. + */ +int pruss_intc_trigger(unsigned int irq) +{ + struct irq_desc *desc; + + if (irq <= 0) + return -EINVAL; + + desc = irq_to_desc(irq); + if (!desc) + return -EINVAL; + + pruss_intc_irq_retrigger(&desc->irq_data); + + return 0; +} +EXPORT_SYMBOL_GPL(pruss_intc_trigger); + +static int pruss_intc_irq_domain_map(struct irq_domain *d, unsigned int virq, + irq_hw_number_t hw) +{ + struct pruss_intc *intc = d->host_data; + + irq_set_chip_data(virq, intc); + irq_set_chip_and_handler(virq, intc->irqchip, handle_level_irq); + + return 0; +} + +static void pruss_intc_irq_domain_unmap(struct irq_domain *d, unsigned int virq) +{ + irq_set_chip_and_handler(virq, NULL, NULL); + irq_set_chip_data(virq, NULL); +} + +static const struct irq_domain_ops pruss_intc_irq_domain_ops = { + .xlate = irq_domain_xlate_onecell, + .map = pruss_intc_irq_domain_map, + .unmap = pruss_intc_irq_domain_unmap, +}; + +static void pruss_intc_irq_handler(struct irq_desc *desc) +{ + unsigned int irq = irq_desc_get_irq(desc); + struct irq_chip *chip = irq_desc_get_chip(desc); + struct pruss_intc *intc = irq_get_handler_data(irq); + u32 hipir; + unsigned int virq; + int i, hwirq; + + chained_irq_enter(chip, desc); + + /* find our host irq number */ + for (i = 0; i < MAX_HOST_NUM_IRQS; i++) + if (intc->irqs[i] == irq) + break; + if (i == MAX_HOST_NUM_IRQS) + goto err; + + i += MIN_PRU_HOST_INT; + + /* get highest priority pending PRUSS system event */ + hipir = pruss_intc_read_reg(intc, PRU_INTC_HIPIR(i)); + while (!(hipir & BIT(31))) { + hwirq = hipir & GENMASK(9, 0); + virq = irq_linear_revmap(intc->domain, hwirq); + + /* + * XXX: manually ACK any system events that do not have a + * handler mapped yet + */ + if (unlikely(!virq)) + pruss_intc_check_write(intc, PRU_INTC_SICR, hwirq); + else + generic_handle_irq(virq); + + /* get next system event */ + hipir = pruss_intc_read_reg(intc, PRU_INTC_HIPIR(i)); + } +err: + chained_irq_exit(chip, desc); +} + +static int pruss_intc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct pruss_intc *intc; + struct resource *res; + struct irq_chip *irqchip; + int i, irq; + const struct pruss_intc_match_data *data; + bool skip_host7; + + data = of_device_get_match_data(dev); + skip_host7 = data ? data->no_host7_intr : false; + + intc = devm_kzalloc(dev, sizeof(*intc), GFP_KERNEL); + if (!intc) + return -ENOMEM; + platform_set_drvdata(pdev, intc); + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "intc"); + intc->base = devm_ioremap_resource(dev, res); + if (IS_ERR(intc->base)) { + dev_err(dev, "failed to parse and map intc memory resource\n"); + return PTR_ERR(intc->base); + } + + mutex_init(&intc->lock); + + for (i = 0; i < ARRAY_SIZE(intc->config_map.sysev_to_ch); i++) + intc->config_map.sysev_to_ch[i] = -1; + + for (i = 0; i < ARRAY_SIZE(intc->config_map.ch_to_host); i++) + intc->config_map.ch_to_host[i] = -1; + + pruss_intc_init(intc); + + irqchip = devm_kzalloc(dev, sizeof(*irqchip), GFP_KERNEL); + if (!irqchip) + return -ENOMEM; + + irqchip->irq_ack = pruss_intc_irq_ack; + irqchip->irq_mask = pruss_intc_irq_mask; + irqchip->irq_unmask = pruss_intc_irq_unmask; + irqchip->irq_retrigger = pruss_intc_irq_retrigger; + irqchip->irq_request_resources = pruss_intc_irq_reqres; + irqchip->irq_release_resources = pruss_intc_irq_relres; + irqchip->name = dev_name(dev); + intc->irqchip = irqchip; + + /* always 64 events */ + intc->domain = irq_domain_add_linear(dev->of_node, MAX_PRU_SYS_EVENTS, + &pruss_intc_irq_domain_ops, intc); + if (!intc->domain) + return -ENOMEM; + + for (i = 0; i < MAX_HOST_NUM_IRQS; i++) { + irq = platform_get_irq_byname(pdev, irq_names[i]); + if (irq < 0) { + if (!strcmp(irq_names[i], "host7") && !!skip_host7) + continue; + + dev_err(dev->parent, "platform_get_irq_byname failed for %s : %d\n", + irq_names[i], irq); + goto fail_irq; + } + + intc->irqs[i] = irq; + irq_set_handler_data(irq, intc); + irq_set_chained_handler(irq, pruss_intc_irq_handler); + } + + return 0; + +fail_irq: + irq_domain_remove(intc->domain); + return irq; +} + +static int pruss_intc_remove(struct platform_device *pdev) +{ + struct pruss_intc *intc = platform_get_drvdata(pdev); + unsigned int hwirq; + + if (intc->domain) { + for (hwirq = 0; hwirq < MAX_PRU_SYS_EVENTS; hwirq++) + irq_dispose_mapping(irq_find_mapping(intc->domain, + hwirq)); + irq_domain_remove(intc->domain); + } + + return 0; +} + +static const struct pruss_intc_match_data am437x_pruss_intc_data = { + .no_host7_intr = true, +}; + +static const struct of_device_id pruss_intc_of_match[] = { + { + .compatible = "ti,am3356-pruss-intc", + .data = NULL, + }, + { + .compatible = "ti,am4376-pruss-intc", + .data = &am437x_pruss_intc_data, + }, + { + .compatible = "ti,am5728-pruss-intc", + .data = NULL, + }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, pruss_intc_of_match); + +static struct platform_driver pruss_intc_driver = { + .driver = { + .name = "pruss-intc", + .of_match_table = pruss_intc_of_match, + }, + .probe = pruss_intc_probe, + .remove = pruss_intc_remove, +}; +module_platform_driver(pruss_intc_driver); + +MODULE_AUTHOR("Andrew F. Davis "); +MODULE_AUTHOR("Suman Anna "); +MODULE_DESCRIPTION("PRU-ICSS INTC Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/irqchip/irq-pruss-intc.h b/include/linux/irqchip/irq-pruss-intc.h new file mode 100644 index 0000000..4538a0b --- /dev/null +++ b/include/linux/irqchip/irq-pruss-intc.h @@ -0,0 +1,94 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/** + * irq-pruss-intc.h - PRU-ICSS INTC management + * + * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com + */ + +#ifndef __INCLUDE_LINUX_IRQCHIP_IRQ_PRUSS_INTC_H +#define __INCLUDE_LINUX_IRQCHIP_IRQ_PRUSS_INTC_H + +/* maximum number of system events */ +#define MAX_PRU_SYS_EVENTS 64 + +/* maximum number of interrupt channels */ +#define MAX_PRU_CHANNELS 10 + +/** + * struct pruss_intc_config - INTC configuration info + * @sysev_to_ch: system events to channel mapping information + * @ch_to_host: interrupt channel to host interrupt information + */ +struct pruss_intc_config { + s8 sysev_to_ch[MAX_PRU_SYS_EVENTS]; + s8 ch_to_host[MAX_PRU_CHANNELS]; +}; + +#if IS_ENABLED(CONFIG_TI_PRUSS) + +/** + * pruss_intc_configure() - configure the PRUSS INTC + * @dev: device + * @intc_config: PRU core-specific INTC configuration + * + * Configures the PRUSS INTC with the provided configuration from + * a PRU core. Any existing event to channel mappings or channel to + * host interrupt mappings are checked to make sure there are no + * conflicting configuration between both the PRU cores. The function + * is intended to be used only by the PRU remoteproc driver. + * + * Returns 0 on success, or a suitable error code otherwise + */ +int pruss_intc_configure(struct device *dev, + struct pruss_intc_config *intc_config); + +/** + * pruss_intc_unconfigure() - unconfigure the PRUSS INTC + * @dev: device + * @intc_config: PRU core specific INTC configuration + * + * Undo whatever was done in pruss_intc_configure() for a PRU core. + * It should be sufficient to just mark the resources free in the + * global map and disable the host interrupts and sysevents. + */ +int pruss_intc_unconfigure(struct device *dev, + struct pruss_intc_config *intc_config); +/** + * pruss_intc_trigger() - trigger a PRU system event + * @irq: linux IRQ number associated with a PRU system event + * + * Trigger an interrupt by signalling a specific PRU system event. + * This can be used by PRUSS client users to raise/send an event to + * a PRU or any other core that is listening on the host interrupt + * mapped to that specific PRU system event. The @irq variable is the + * Linux IRQ number associated with a specific PRU system event that + * a client user/application uses. The interrupt mappings for this is + * provided by the PRUSS INTC irqchip instance. + * + * Returns 0 on success, or an error value upon failure. + */ +int pruss_intc_trigger(unsigned int irq); + +#else + +static inline int pruss_intc_configure(struct device *dev, + struct pruss_intc_config *intc_config) +{ + return -ENOTSUPP; +} + +static inline int pruss_intc_unconfigure(struct device *dev, + struct pruss_intc_config *intc_config) +{ + return -ENOTSUPP; +} + +static inline int pruss_intc_trigger(unsigned int irq) +{ + return -ENOTSUPP; +} + +#endif /* CONFIG_TI_PRUSS */ + +#endif /* __INCLUDE_LINUX_IRQCHIP_IRQ_OMAP_INTC_H */ + From patchwork Mon Feb 4 14:22:39 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roger Quadros X-Patchwork-Id: 157422 Delivered-To: patch@linaro.org Received: by 2002:a02:48:0:0:0:0:0 with SMTP id 69csp3973876jaa; Mon, 4 Feb 2019 06:24:22 -0800 (PST) X-Google-Smtp-Source: ALg8bN78Bn8jHz0zQUsuiWqaV9EIsYFSazKCu7ylSHhvkeYFdAMCtUphB6waJYyKXsYtDhud29xh X-Received: by 2002:a62:5dd1:: with SMTP id n78mr50500484pfj.58.1549290262364; Mon, 04 Feb 2019 06:24:22 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1549290262; cv=none; d=google.com; s=arc-20160816; b=OKkV2CDTUeD+sNDzP75dL1JZSjKTqiDB/tzof6tIHo75268lubToqJhUiDUDqUMgbl 6auCQGKujeWzHaEw8Tz2D55Z0N/zvfOLffRNfLrElNTyCC6Lg4wHkTRxmt0uVjv+Jldw UExlWf1CAsuziuA45MBfYNx4y43tL3Z3ITwredBQnbgGCFy7xbrCG2mwtgmd8LNBMc2N FMAS0d+ZKncUfml3IRhpNHIkSvBlcE1Vpdcltp8qGhOymlF6TWWWnbIoqc5xVk9IKBJr PnGXL3v+M/mOe/Ai/dEz/46eq9T2Ocg+ZKTg8ajKdFWlcLuA3VyUGAYL/SFOc2ADVmVy rQvA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature; bh=aQ07n4dTRhZW4jPqtL1fwT+4odc4r2dow30BwK9E+w8=; b=c8nS6Kmdd5PhzrgQMALyrhDk9crrrmeIxFnnkDAlKmzQdqAUyuryLpS0u4wZH3HYdb tVygOXwIPzKG8j+EHuVpaH1xHlFq9LVzWB4IwLxUPREWvwjojM33G8wuQGbCdzcgew48 9rUNhwlWYpKfCQyI9SiFt9Yxa94i4KMXs8h1K02kRk0k7jkTptWp+iKc/kGvi2XRaWEn 3vWSfqihsxbrUImejthqP2XZJN44xgtwaoZX2reT3yRfMLxZPWSqWPiOGSHZd5D5sHzi 2IgFesTdTaVcp/0cC7YhbNdvBmHprYEnGfqI+kGGBRUWZYfEJq34aHm0i8uebZ/cmiXo kKfA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@ti.com header.s=ti-com-17Q1 header.b=iaV7fXeF; 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; dmarc=pass (p=QUARANTINE sp=NONE dis=NONE) header.from=ti.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id k1si178732pld.71.2019.02.04.06.24.21; Mon, 04 Feb 2019 06:24:22 -0800 (PST) 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=@ti.com header.s=ti-com-17Q1 header.b=iaV7fXeF; 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; dmarc=pass (p=QUARANTINE sp=NONE dis=NONE) header.from=ti.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729708AbfBDOYU (ORCPT + 31 others); Mon, 4 Feb 2019 09:24:20 -0500 Received: from fllv0015.ext.ti.com ([198.47.19.141]:43182 "EHLO fllv0015.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728937AbfBDOYQ (ORCPT ); Mon, 4 Feb 2019 09:24:16 -0500 Received: from fllv0035.itg.ti.com ([10.64.41.0]) by fllv0015.ext.ti.com (8.15.2/8.15.2) with ESMTP id x14ENK65031831; Mon, 4 Feb 2019 08:23:20 -0600 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=ti-com-17Q1; t=1549290200; bh=aQ07n4dTRhZW4jPqtL1fwT+4odc4r2dow30BwK9E+w8=; h=From:To:CC:Subject:Date:In-Reply-To:References; b=iaV7fXeFoHKr94AWTx1zRW8z+rq/Lh6p+d4TbN9hh2XifdJUw5fHifVLWRt3/HDcI L/cs9O4JZV0MKTA9aC8ACWUp/L6iXH11xwLZXAWRxPdAraR4VcGvZ5JwkWMsUtGOMi /9ylDL6lNkKiadx2z2GqqM6z4MDN7dhEk9kmf+Dk= Received: from DFLE112.ent.ti.com (dfle112.ent.ti.com [10.64.6.33]) by fllv0035.itg.ti.com (8.15.2/8.15.2) with ESMTPS id x14ENJZo115822 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL); Mon, 4 Feb 2019 08:23:20 -0600 Received: from DFLE102.ent.ti.com (10.64.6.23) by DFLE112.ent.ti.com (10.64.6.33) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.1591.10; Mon, 4 Feb 2019 08:23:19 -0600 Received: from dflp32.itg.ti.com (10.64.6.15) by DFLE102.ent.ti.com (10.64.6.23) with Microsoft SMTP Server (version=TLS1_0, cipher=TLS_RSA_WITH_AES_256_CBC_SHA) id 15.1.1591.10 via Frontend Transport; Mon, 4 Feb 2019 08:23:19 -0600 Received: from localhost.localdomain (ileax41-snat.itg.ti.com [10.172.224.153]) by dflp32.itg.ti.com (8.14.3/8.13.8) with ESMTP id x14EMoKe012232; Mon, 4 Feb 2019 08:23:16 -0600 From: Roger Quadros To: , , CC: , , , , , , , , , , , , Subject: [PATCH v2 06/14] remoteproc: add page lookup for TI PRU to ELF loader Date: Mon, 4 Feb 2019 16:22:39 +0200 Message-ID: <1549290167-876-7-git-send-email-rogerq@ti.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1549290167-876-1-git-send-email-rogerq@ti.com> References: <1549290167-876-1-git-send-email-rogerq@ti.com> MIME-Version: 1.0 X-EXCLAIMER-MD-CONFIG: e1e8a2fd-e40a-4ac6-ac9b-f7e9cc9ee180 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: David Lechner This adds a special handler to the default remoteproc ELF firmware loader that looks up the memory map on TI PRU firmware files. These processors have multiple memory maps that share the same address space, so we need to know the page in addition to the physical address in order to translate the address to a local CPU address. Signed-off-by: David Lechner Signed-off-by: Roger Quadros --- drivers/remoteproc/remoteproc_elf_loader.c | 117 +++++++++++++++++++++++++++-- include/uapi/linux/elf-em.h | 1 + 2 files changed, 112 insertions(+), 6 deletions(-) -- Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki. Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c index 8888d39..79c9d39 100644 --- a/drivers/remoteproc/remoteproc_elf_loader.c +++ b/drivers/remoteproc/remoteproc_elf_loader.c @@ -32,6 +32,103 @@ #include "remoteproc_internal.h" +#define SHT_TI_PHATTRS 0x7F000004 +#define SHT_TI_SH_PAGE 0x7F000007 + +struct elf32_ti_phattrs { + Elf32_Half pha_seg_id; /* Segment id */ + Elf32_Half pha_tag_id; /* Attribute kind id */ + union { + Elf32_Off pha_offset; /* byte offset within the section */ + Elf32_Word pha_value; /* Constant tag value */ + } pha_un; +}; + +/* this struct is reverse engineered, so not sure what most of the values are */ +struct ti_section_page { + u32 unk0; + u32 unk1; + u32 unk2; + u32 unk3; + u32 unk4; + u16 size; + u16 unk5; + u16 unk6; + u8 data[0]; /* array of size */ +}; + +/** + * rproc_elf_segment_to_map() - Gets memory map for segment + * @id: segment id + * @elf_data: pointer to ELF file data + * + * Returns the memory map for the segment. + */ +static int rproc_elf_segment_to_map(u32 id, const u8 *elf_data) +{ + struct elf32_hdr *ehdr; + struct elf32_shdr *shdr; + struct elf32_ti_phattrs *ti_attrs = NULL; + int i; + + ehdr = (struct elf32_hdr *)elf_data; + shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff); + + if (ehdr->e_machine != EM_TI_PRU) + return 0; + + for (i = 0; i < ehdr->e_shnum; i++, shdr++) { + if (shdr->sh_type == SHT_TI_PHATTRS) { + ti_attrs = (struct elf32_ti_phattrs *)(elf_data + shdr->sh_offset); + break; + } + } + + if (!ti_attrs) + return 0; + + /* list is terminated by tag id == 0 (PHA_NULL) */ + for (; ti_attrs->pha_tag_id; ti_attrs++) { + if (ti_attrs->pha_tag_id == 3 && ti_attrs->pha_seg_id == id) + return ti_attrs->pha_un.pha_value; + } + + return 0; +} + +/** + * rproc_elf_section_to_map() - Gets memory map for section + * @id: segment id + * @elf_data: pointer to ELF file data + * + * Returns the memory map for the section. + */ +static int rproc_elf_section_to_map(u32 id, const u8 *elf_data) +{ + struct elf32_hdr *ehdr; + struct elf32_shdr *shdr; + struct ti_section_page *map = NULL; + int i; + + ehdr = (struct elf32_hdr *)elf_data; + shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff); + + if (ehdr->e_machine != EM_TI_PRU) + return 0; + + for (i = 0; i < ehdr->e_shnum; i++, shdr++) { + if (shdr->sh_type == SHT_TI_SH_PAGE) { + map = (struct ti_section_page *)(elf_data + shdr->sh_offset); + break; + } + } + + if (!map || id >= map->size) + return 0; + + return map->data[id]; +} + /** * rproc_elf_sanity_check() - Sanity Check ELF firmware image * @rproc: the remote processor handle @@ -147,7 +244,7 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw) struct device *dev = &rproc->dev; struct elf32_hdr *ehdr; struct elf32_phdr *phdr; - int i, ret = 0; + int i, map, ret = 0; const u8 *elf_data = fw->data; ehdr = (struct elf32_hdr *)elf_data; @@ -181,8 +278,10 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw) break; } + map = rproc_elf_segment_to_map(i, elf_data); + /* grab the kernel address for this device address */ - ptr = rproc_da_to_va(rproc, da, memsz, 0); + ptr = rproc_da_to_va(rproc, da, memsz, map); if (!ptr) { dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz); ret = -EINVAL; @@ -209,7 +308,7 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw) EXPORT_SYMBOL(rproc_elf_load_segments); static struct elf32_shdr * -find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size) +find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size, int *id) { struct elf32_shdr *shdr; int i; @@ -261,6 +360,9 @@ find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size) return NULL; } + if (id) + *id = i; + return shdr; } @@ -288,7 +390,7 @@ int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw) ehdr = (struct elf32_hdr *)elf_data; - shdr = find_table(dev, ehdr, fw->size); + shdr = find_table(dev, ehdr, fw->size, NULL); if (!shdr) return -EINVAL; @@ -328,11 +430,14 @@ struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc, { struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data; struct elf32_shdr *shdr; + int id, map; - shdr = find_table(&rproc->dev, ehdr, fw->size); + shdr = find_table(&rproc->dev, ehdr, fw->size, &id); if (!shdr) return NULL; - return rproc_da_to_va(rproc, shdr->sh_addr, shdr->sh_size, 0); + map = rproc_elf_section_to_map(id, fw->data); + + return rproc_da_to_va(rproc, shdr->sh_addr, shdr->sh_size, map); } EXPORT_SYMBOL(rproc_elf_find_loaded_rsc_table); diff --git a/include/uapi/linux/elf-em.h b/include/uapi/linux/elf-em.h index 0c3000fa..70b487a 100644 --- a/include/uapi/linux/elf-em.h +++ b/include/uapi/linux/elf-em.h @@ -38,6 +38,7 @@ #define EM_BLACKFIN 106 /* ADI Blackfin Processor */ #define EM_ALTERA_NIOS2 113 /* Altera Nios II soft-core processor */ #define EM_TI_C6000 140 /* TI C6X DSPs */ +#define EM_TI_PRU 144 /* TI Programmable Realtime Unit */ #define EM_AARCH64 183 /* ARM 64 bit */ #define EM_TILEPRO 188 /* Tilera TILEPro */ #define EM_MICROBLAZE 189 /* Xilinx MicroBlaze */ From patchwork Mon Feb 4 14:22:41 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roger Quadros X-Patchwork-Id: 157423 Delivered-To: patch@linaro.org Received: by 2002:a02:48:0:0:0:0:0 with SMTP id 69csp3973923jaa; Mon, 4 Feb 2019 06:24:26 -0800 (PST) X-Google-Smtp-Source: ALg8bN48hgYIIPpNydw3Whs8I+2Qote2xo0xaH2u5di/Ezq1pcPxVQyQE/4bNON15dJ/qUzu4ywC X-Received: by 2002:a62:9fd9:: with SMTP id v86mr51015312pfk.191.1549290266079; Mon, 04 Feb 2019 06:24:26 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1549290266; cv=none; d=google.com; s=arc-20160816; b=FVqIBVstUjUARIeGdHpw1E7ZEsUB1oUvckTFwPwGwk5wPvSu0eSp48dl34lH2v/6kv tkxQQVaZXOXXafKvl6ns4j1IhVyZSiBA6o56hNs6qOOY+exFTYFOTD5ssvyg9QFisAuX nsDHBgQZOeOlRlMpfAOBGZFydV6hPwXpU4DLds0RohY58MRhKjJZ6gZVsgsDfPytg3iw 3Fu3j3EhoxTo2HSBK11TnRz9+ZcI/dQD/CS4iNpo5wKg1/qd6LkZB70Kr6lWbJCfs2hp Nh6ykWNZDU5xZ3mOxEEXId/nbadojsqlVT+ttFblzHh5cFNUXXU25L8fwIFyNRBjB3SO eHYw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature; bh=0+KyfIOVDeytTSCzB8JNujMdAyrnWVoo29rT5qH9ivQ=; b=SDj0AGgNW7fNXUlyIiVH2bgqU07fb/wj7bcJrgVSAiqtNzPfJZQ6y8ENCdXCQwk62P ymhUJOJPGIPZEBg8M4GQ8HUXafYt80+PDT7EfpV14Z97mC0HEHaaAfJdECBhhwbc74RS MhsSHU0WcxMEmFshFcCRUkTJ+TKlDo+kmMo6E8x7xLNpKQ3LptkA0JTYOhvtFxPKobkj xUmqniA3clkHUUhhhuKa/Aijs/EmgAIGU5KowqglCZFyv9Y14/V9odE3VaHfTs+9YtBz euv/70riidFqSz1O5+wB+NzdobpBX7MoyCB94fRk7rg0A4oDj6AmC2alyvz0/W/pBZ31 byug== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@ti.com header.s=ti-com-17Q1 header.b="fMj/QMoA"; 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; dmarc=pass (p=QUARANTINE sp=NONE dis=NONE) header.from=ti.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id a193si168176pfa.214.2019.02.04.06.24.25; Mon, 04 Feb 2019 06:24:26 -0800 (PST) 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=@ti.com header.s=ti-com-17Q1 header.b="fMj/QMoA"; 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; dmarc=pass (p=QUARANTINE sp=NONE dis=NONE) header.from=ti.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729775AbfBDOYX (ORCPT + 31 others); Mon, 4 Feb 2019 09:24:23 -0500 Received: from fllv0015.ext.ti.com ([198.47.19.141]:43186 "EHLO fllv0015.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729553AbfBDOYT (ORCPT ); Mon, 4 Feb 2019 09:24:19 -0500 Received: from fllv0034.itg.ti.com ([10.64.40.246]) by fllv0015.ext.ti.com (8.15.2/8.15.2) with ESMTP id x14ENSEF031947; Mon, 4 Feb 2019 08:23:28 -0600 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=ti-com-17Q1; t=1549290208; bh=0+KyfIOVDeytTSCzB8JNujMdAyrnWVoo29rT5qH9ivQ=; h=From:To:CC:Subject:Date:In-Reply-To:References; b=fMj/QMoA2crKpPHMx69PccjBGiLr+7UnxRlLm+JPaBsTOzDoRtQC6BJMmCOJPEed+ S3j7ff6mayK93hhMgrq3EhmlzwQ7hFdAHpYO4xZBKe2wbTme2Of/Qv/G4iagly1oGt iEPHkn97OvgIwpqAqJ3Lk9GC+91CVRvOoPGchnG4= Received: from DFLE109.ent.ti.com (dfle109.ent.ti.com [10.64.6.30]) by fllv0034.itg.ti.com (8.15.2/8.15.2) with ESMTPS id x14ENStT010352 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL); Mon, 4 Feb 2019 08:23:28 -0600 Received: from DFLE100.ent.ti.com (10.64.6.21) by DFLE109.ent.ti.com (10.64.6.30) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.1591.10; Mon, 4 Feb 2019 08:23:27 -0600 Received: from dflp32.itg.ti.com (10.64.6.15) by DFLE100.ent.ti.com (10.64.6.21) with Microsoft SMTP Server (version=TLS1_0, cipher=TLS_RSA_WITH_AES_256_CBC_SHA) id 15.1.1591.10 via Frontend Transport; Mon, 4 Feb 2019 08:23:27 -0600 Received: from localhost.localdomain (ileax41-snat.itg.ti.com [10.172.224.153]) by dflp32.itg.ti.com (8.14.3/8.13.8) with ESMTP id x14EMoKg012232; Mon, 4 Feb 2019 08:23:24 -0600 From: Roger Quadros To: , , CC: , , , , , , , , , , , , Subject: [PATCH v2 08/14] remoteproc: Add support to handle device specific resource types Date: Mon, 4 Feb 2019 16:22:41 +0200 Message-ID: <1549290167-876-9-git-send-email-rogerq@ti.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1549290167-876-1-git-send-email-rogerq@ti.com> References: <1549290167-876-1-git-send-email-rogerq@ti.com> MIME-Version: 1.0 X-EXCLAIMER-MD-CONFIG: e1e8a2fd-e40a-4ac6-ac9b-f7e9cc9ee180 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Suman Anna The remoteproc framework handles a fixed set of resource table entries today. To make it scalable across multiple platforms, it makes sense for the framework to provide a way for the device specific implementation to define and handle vendor specific resource types. These resource types would be very specific to an implementation instance that it does not make sense for the framework to handle it. For instance, a remoteproc implementation might want timers information embedded in the resource table so that the driver could parse the binary and enable accordingly. Another example would be hwspinlocks that it is using, to properly share system wide resources. The PRU interrupt controller's interrupt-map could be provided via a vendor specific resource. This patch adds a function pointer to the list of rproc_ops for the driver implementation to handle such custom vendor resources. [rogerq@ti.com] Get rid of pre/post loaders. Show in debugfs. Signed-off-by: Suman Anna Signed-off-by: Roger Quadros --- drivers/remoteproc/remoteproc_core.c | 36 +++++++++++++++++++++++++++++++++ drivers/remoteproc/remoteproc_debugfs.c | 3 +++ include/linux/remoteproc.h | 17 ++++++++++++++-- 3 files changed, 54 insertions(+), 2 deletions(-) -- Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki. Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 2d9646f..b43aa40 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -896,6 +896,41 @@ void rproc_add_carveout(struct rproc *rproc, struct rproc_mem_entry *mem) EXPORT_SYMBOL(rproc_add_carveout); /** + * rproc_handle_vendor_rsc() - provide implementation specific hook + * to handle vendor/custom resources + * @rproc: the remote processor + * @rsc: vendor resource to be handled by remoteproc drivers + * @offset: offset of the resource data in resource table + * @avail: size of available data + * + * Remoteproc implementations might want to add resource table entries + * that are not generic enough to be handled by the framework. This + * provides a hook to handle such custom resources. + * + * Returns 0 on success, or an appropriate error code otherwise + */ +static int rproc_handle_vendor_rsc(struct rproc *rproc, + struct fw_rsc_vendor *rsc, + int offset, int avail) +{ + struct device *dev = &rproc->dev; + + if (sizeof(*rsc) > avail) { + dev_err(dev, "vendor rsc is truncated\n"); + return -EINVAL; + } + + dev_dbg(dev, "vendor rsc:"); + + if (!rproc->ops->handle_vendor_rsc) { + dev_err(dev, "no vendor rsc handler! ignoring resource\n"); + return 0; + } + + return rproc->ops->handle_vendor_rsc(rproc, (void *)rsc); +} + +/** * rproc_mem_entry_init() - allocate and initialize rproc_mem_entry struct * @dev: pointer on device struct * @va: virtual address @@ -983,6 +1018,7 @@ static rproc_handle_resource_t rproc_loading_handlers[RSC_LAST] = { [RSC_CARVEOUT] = (rproc_handle_resource_t)rproc_handle_carveout, [RSC_DEVMEM] = (rproc_handle_resource_t)rproc_handle_devmem, [RSC_TRACE] = (rproc_handle_resource_t)rproc_handle_trace, + [RSC_VENDOR] = (rproc_handle_resource_t)rproc_handle_vendor_rsc, [RSC_VDEV] = (rproc_handle_resource_t)rproc_handle_vdev, }; diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c index e90135c..ef66165 100644 --- a/drivers/remoteproc/remoteproc_debugfs.c +++ b/drivers/remoteproc/remoteproc_debugfs.c @@ -230,6 +230,9 @@ static int rproc_rsc_table_show(struct seq_file *seq, void *p) v->vring[j].pa); } break; + case RSC_VENDOR: + seq_printf(seq, "Entry %d is of type %s [Vendor specific]\n", + i, types[hdr->type]); default: seq_printf(seq, "Unknown resource type found: %d [hdr: %pK]\n", hdr->type, hdr); diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h index b5aa5fb..9f4c457 100644 --- a/include/linux/remoteproc.h +++ b/include/linux/remoteproc.h @@ -100,6 +100,7 @@ struct fw_rsc_hdr { * the remote processor will be writing logs. * @RSC_VDEV: declare support for a virtio device, and serve as its * virtio header. + * @RSC_VENDOR: vendor specific resource type. * @RSC_LAST: just keep this one at the end * * For more details regarding a specific resource type, please see its @@ -115,7 +116,8 @@ enum fw_resource_type { RSC_DEVMEM = 1, RSC_TRACE = 2, RSC_VDEV = 3, - RSC_LAST = 4, + RSC_VENDOR = 4, + RSC_LAST, }; #define FW_RSC_ADDR_ANY (-1) @@ -308,6 +310,14 @@ struct fw_rsc_vdev { struct rproc; /** + * struct fw_rsc_vendor - vendor specific resource definition + * @data: resource data. vendor defined. + */ +struct fw_rsc_vendor { + u8 data[0]; +} __packed; + +/** * struct rproc_mem_entry - memory entry descriptor * @va: virtual address * @dma: dma address @@ -347,7 +357,8 @@ struct firmware; * @da_to_va: optional platform hook to perform address translations * @load_rsc_table: load resource table from firmware image * @find_loaded_rsc_table: find the loaded resouce table - * @load: load firmeware to memory, where the remote processor + * @handle_vendor_rsc: hook to handle device specific resource table entries + * @load: load firmware to memory, where the remote processor * expects to find it * @sanity_check: sanity check the fw image * @get_boot_addr: get boot address to entry point specified in firmware @@ -360,6 +371,8 @@ struct rproc_ops { int (*parse_fw)(struct rproc *rproc, const struct firmware *fw); struct resource_table *(*find_loaded_rsc_table)( struct rproc *rproc, const struct firmware *fw); + int (*handle_vendor_rsc)(struct rproc *rproc, + struct fw_rsc_vendor *rsc); int (*load)(struct rproc *rproc, const struct firmware *fw); int (*sanity_check)(struct rproc *rproc, const struct firmware *fw); u32 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw); From patchwork Mon Feb 4 14:22:42 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roger Quadros X-Patchwork-Id: 157425 Delivered-To: patch@linaro.org Received: by 2002:a02:48:0:0:0:0:0 with SMTP id 69csp3973995jaa; Mon, 4 Feb 2019 06:24:30 -0800 (PST) X-Google-Smtp-Source: AHgI3IYk0sSHHl4aDER7h6/8fsEKY1QncQrYK2IDOsBXiNxdQkq5/7sboduXlHKW3ATXiYINO9B6 X-Received: by 2002:a63:d842:: with SMTP id k2mr3525782pgj.8.1549290270190; Mon, 04 Feb 2019 06:24:30 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1549290270; cv=none; d=google.com; s=arc-20160816; b=BtqK4KJcxW/+yc5YTpQTQsrTp1nJDXYkmaa1uePuoprttS2TSAXMJpKzjV89qpVpQ1 SrMkrfnuPnrAy4yDPbE2cI+Z04dmwnmJEU6aRiwhZJSNW0YgQ4SEB96OoxpRwYCf2eyj 8FNnuzp2eQY+ornHP46Om6nQIguXXqs1dxXfUim7N5H6o6Wa60SZ5TZLCAeZnt4hM/9r RuzwalKvsZI6nBlntcr+vxkc4B350CCXFGPVIfTveLVNk2yVdyUjRWFsDxd7A2QS1pAv iU1NPM6PZv3Pa49CnaCgC0lDoBAzu8NqiRwQVRDp3Rwb1lD3hn1HXQnu0Ax66X/koMCK Jmkg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature; bh=wKcx2dLXaiJQ7mZWX/QUVBP1grt4i6qXcUpv+wF4XR0=; b=wu85OO/w0mI5pTZiXVV16OQ8j5iJ3n+a5NiZNFnqseOJQf0rZmYX+n8xom0L0EevFK 7b5yv3fQRkQIY8fJ2XOpoAHARi4h2WW8uXmUcNaHr1rZROcyQkkoMZ5+T2+EJjFqcIfi zwa3ZPCYWIjpt81YOYMFPxINkGkKz9VGpmN+C+9DR92cBL/mcqIVctiHjxYL2ZXU8Aar ExafmkOSGGnbHVvSDK0ejFlGWUES4dAxRGmImhVErThAewXVEH5bIqKfoBq69pYbVw2A j8xJL1aSFWES6/xIlcQK1djuC7OobYsSibUjL1vmhggAppzX/n+1yHAboemp++dyzB9B lFyw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@ti.com header.s=ti-com-17Q1 header.b=EKro2kHF; 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; dmarc=pass (p=QUARANTINE sp=NONE dis=NONE) header.from=ti.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id j63si162866pgc.109.2019.02.04.06.24.29; Mon, 04 Feb 2019 06:24:30 -0800 (PST) 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=@ti.com header.s=ti-com-17Q1 header.b=EKro2kHF; 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; dmarc=pass (p=QUARANTINE sp=NONE dis=NONE) header.from=ti.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729936AbfBDOY2 (ORCPT + 31 others); Mon, 4 Feb 2019 09:24:28 -0500 Received: from lelv0143.ext.ti.com ([198.47.23.248]:49884 "EHLO lelv0143.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728937AbfBDOYY (ORCPT ); Mon, 4 Feb 2019 09:24:24 -0500 Received: from lelv0265.itg.ti.com ([10.180.67.224]) by lelv0143.ext.ti.com (8.15.2/8.15.2) with ESMTP id x14ENWPV044048; Mon, 4 Feb 2019 08:23:32 -0600 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=ti-com-17Q1; t=1549290212; bh=wKcx2dLXaiJQ7mZWX/QUVBP1grt4i6qXcUpv+wF4XR0=; h=From:To:CC:Subject:Date:In-Reply-To:References; b=EKro2kHFLLMt7Q5UZ/AAo9kFbgyf4Kn7V0IqKvKk6z+gm6HIh0IxjUVWwEzKm1rwh L9C6NFznxLL+0BAbAOe1Iv40aTBtrN2Zyix2UIZddoVmk6a8Ti7nhGx9zItgBUwvtd ESfykc6bljD64rZRd0fNEfoq4M9Iz+U+jaAPBRP4= Received: from DLEE115.ent.ti.com (dlee115.ent.ti.com [157.170.170.26]) by lelv0265.itg.ti.com (8.15.2/8.15.2) with ESMTPS id x14ENVTw048975 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL); Mon, 4 Feb 2019 08:23:31 -0600 Received: from DLEE104.ent.ti.com (157.170.170.34) by DLEE115.ent.ti.com (157.170.170.26) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.1591.10; Mon, 4 Feb 2019 08:23:31 -0600 Received: from dflp32.itg.ti.com (10.64.6.15) by DLEE104.ent.ti.com (157.170.170.34) with Microsoft SMTP Server (version=TLS1_0, cipher=TLS_RSA_WITH_AES_256_CBC_SHA) id 15.1.1591.10 via Frontend Transport; Mon, 4 Feb 2019 08:23:31 -0600 Received: from localhost.localdomain (ileax41-snat.itg.ti.com [10.172.224.153]) by dflp32.itg.ti.com (8.14.3/8.13.8) with ESMTP id x14EMoKh012232; Mon, 4 Feb 2019 08:23:27 -0600 From: Roger Quadros To: , , CC: , , , , , , , , , , , , , Rob Herring Subject: [PATCH v2 09/14] dt-binding: remoteproc: Add binding doc for PRU Cores in the PRU-ICSS Date: Mon, 4 Feb 2019 16:22:42 +0200 Message-ID: <1549290167-876-10-git-send-email-rogerq@ti.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1549290167-876-1-git-send-email-rogerq@ti.com> References: <1549290167-876-1-git-send-email-rogerq@ti.com> MIME-Version: 1.0 X-EXCLAIMER-MD-CONFIG: e1e8a2fd-e40a-4ac6-ac9b-f7e9cc9ee180 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Suman Anna The Programmable Real-Time Unit Subsystem (PRUSS) consists of dual 32-bit RISC cores (Programmable Real-Time Units, or PRUs) for program execution. This patch adds a remoteproc platform driver for managing the individual PRU RISC cores life cycle. Add DT binding documentation for that. Cc: Rob Herring Signed-off-by: Suman Anna Signed-off-by: Roger Quadros --- .../bindings/remoteproc/ti,pru-rproc.txt | 56 ++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 Documentation/devicetree/bindings/remoteproc/ti,pru-rproc.txt -- Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki. Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki diff --git a/Documentation/devicetree/bindings/remoteproc/ti,pru-rproc.txt b/Documentation/devicetree/bindings/remoteproc/ti,pru-rproc.txt new file mode 100644 index 0000000..02dfd0e --- /dev/null +++ b/Documentation/devicetree/bindings/remoteproc/ti,pru-rproc.txt @@ -0,0 +1,56 @@ +PRU Core on TI SoCs +=================== + +Each PRUSS has dual PRU cores, each represented by a PRU child node. Each node +can optionally be rendered inactive by using the standard DT string property, +"status". + +Required Properties: +-------------------- +- compatible : should be + "ti,am3356-pru" for AM335x family of SoCs + "ti,am4376-pru" for AM437x family of SoCs + "ti,am5728-pru" for AM57xx family of SoCs + "ti,k2g-pru" for 66AK2G family of SoCs +- reg : base address and size for each of the 3 sub-module address + spaces as mentioned in reg-names, and in the same order as + the reg-names +- reg-names : should contain each of the following 3 names, the binding is + agnostic of the order of these reg-names + "iram" for Instruction RAM, + "control" for the CTRL sub-module registers, + "debug" for the Debug sub-module registers, + +- firmware-name : should contain the name of the firmware image file + located on the firmware search path. This firmware will be + used as default if the Application node or User (via sysfs) + doesn't provide a firmware-name. + +- gpcfg : pHandle to CFG module's syscon regmap and offset to PRU's + GPCFG register. + +Optional Properties: +-------------------- +The virtio based communication between the MPU and a PRU core _requires_ +either the 'mboxes' property, or the set of 'interrupt-parent', 'interrupts' +and 'interrupt-names' properties to be defined. The latter option is the +preferred choice. The 'mboxes' property is not applicable for 66AK2G and +DA850/OMAP-L138 SoCs. + +- mboxes : OMAP Mailbox specifier denoting the sub-mailbox, if using + a mailbox for IPC signalling between host and a PRU core. + The specifier format is as per the bindings, + Documentation/devicetree/bindings/mailbox/omap-mailbox.txt + This property should match with the sub-mailbox node used + in the corresponding firmware image. +- interrupt-parent : phandle to the PRUSS INTC node. Should be defined if + interrupts property is to be used. +- interrupts : array of interrupt specifiers if using PRU system events + for IPC signalling between host and a PRU core. This + property should match with the PRU system event used in + the corresponding firmware image. +- interrupt-names : should use one of the following names for each interrupt, + the name should match the corresponding PRU system event + number, + "vring" - for PRU to HOST virtqueue signalling + "kick" - for HOST to PRU virtqueue signalling From patchwork Mon Feb 4 14:22:43 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roger Quadros X-Patchwork-Id: 157428 Delivered-To: patch@linaro.org Received: by 2002:a02:48:0:0:0:0:0 with SMTP id 69csp3974193jaa; Mon, 4 Feb 2019 06:24:41 -0800 (PST) X-Google-Smtp-Source: ALg8bN6vf6BrlhS+4oGUD8DjuGg5DFKZmsKyzoUG2Kzq0wfLf+Y+aEEcXyyWuRSZ7Ea387IJFEDD X-Received: by 2002:a62:4d81:: with SMTP id a123mr52868138pfb.122.1549290281818; Mon, 04 Feb 2019 06:24:41 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1549290281; cv=none; d=google.com; s=arc-20160816; b=eDbZuBN4OS8eCS9asjyO2SjUFK7vYj5tcybsCnn9feudocB7BnP07ceDLowOIA7Y28 6Y1LllWbW+GPrnIO8guwUeLgyTt43tZJfl7IU0OwwuJyFOemZ0ILbKQVZF1nMQIHUQDB lNg3MztT24E2Dz1pu6w4KKCUUW+HTELEynL1UGSFKDHHheOQ1VRcjPz+cIYICjH1B2fA ppzTw42cdsKTn3Ygy2qa0t5CFoqtkCq11WsiIDZtnlEgW+5Bw2+54EopPPr2bEuOtFMq XuyUtmgEXmHlRvQWIu8LHFCMOv097FemZC0Yu5h9KVtPCzoq8Cd7hc/rlETr2v98PPmD Y/Mg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature; bh=mTV1gxBwV7yQAc+zCtnJIHYZslZujoV0XVo1ED0F0VM=; b=gkZ+muzwR25itJLgwjiIzkVFfJcw+HRUU4BTBO5bjiW8GRGEsquveVE2QC25jRv6Js 8bvQ4Kc5z5TO4lyqouTQJDR3boir3MRMKDWsa/UfHLLED2vG2mO/yJqQlvEFoymC4Ew8 Ctcx7EcdGzrlzutTvYn0VliHDe6XlQMAtuabzy6dljrrINA9jTMHQ0mR8PJN4p9lSazh DjrkVr/1/mbPrQzdabAm/fIri9z8xKMTT+aZvOKts7DqTLgNxdZ6+gQjg9+p9WGup9gb K01R8M5L963Jw3Dep7LvsqnRoVg3O7LDLDKSw+qkF/Ka2TjS9/bcCZJ1HC/2IxraSAIW YaHg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@ti.com header.s=ti-com-17Q1 header.b=fBRSsgYu; 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; dmarc=pass (p=QUARANTINE sp=NONE dis=NONE) header.from=ti.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id g2si174845plp.18.2019.02.04.06.24.41; Mon, 04 Feb 2019 06:24:41 -0800 (PST) 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=@ti.com header.s=ti-com-17Q1 header.b=fBRSsgYu; 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; dmarc=pass (p=QUARANTINE sp=NONE dis=NONE) header.from=ti.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730154AbfBDOYk (ORCPT + 31 others); Mon, 4 Feb 2019 09:24:40 -0500 Received: from fllv0016.ext.ti.com ([198.47.19.142]:43072 "EHLO fllv0016.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730085AbfBDOYh (ORCPT ); Mon, 4 Feb 2019 09:24:37 -0500 Received: from fllv0035.itg.ti.com ([10.64.41.0]) by fllv0016.ext.ti.com (8.15.2/8.15.2) with ESMTP id x14ENaBD023330; Mon, 4 Feb 2019 08:23:36 -0600 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=ti-com-17Q1; t=1549290216; bh=mTV1gxBwV7yQAc+zCtnJIHYZslZujoV0XVo1ED0F0VM=; h=From:To:CC:Subject:Date:In-Reply-To:References; b=fBRSsgYu0czv1FNMMmKa7COHyZHPD60grBZo+vShKBLllf0RetqffZh0X1dFrSouY 9uTbIwFI2FKDvz//mJE2uEz4HO8KXIaodC8IcagRLS7+PldnTb22XY/mLvcniQGB7D hVGj5w8ob14u8TsgTNsak26lbNv134O87xAS2LjM= Received: from DLEE113.ent.ti.com (dlee113.ent.ti.com [157.170.170.24]) by fllv0035.itg.ti.com (8.15.2/8.15.2) with ESMTPS id x14ENaIq115943 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL); Mon, 4 Feb 2019 08:23:36 -0600 Received: from DLEE107.ent.ti.com (157.170.170.37) by DLEE113.ent.ti.com (157.170.170.24) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.1591.10; Mon, 4 Feb 2019 08:23:35 -0600 Received: from dflp32.itg.ti.com (10.64.6.15) by DLEE107.ent.ti.com (157.170.170.37) with Microsoft SMTP Server (version=TLS1_0, cipher=TLS_RSA_WITH_AES_256_CBC_SHA) id 15.1.1591.10 via Frontend Transport; Mon, 4 Feb 2019 08:23:35 -0600 Received: from localhost.localdomain (ileax41-snat.itg.ti.com [10.172.224.153]) by dflp32.itg.ti.com (8.14.3/8.13.8) with ESMTP id x14EMoKi012232; Mon, 4 Feb 2019 08:23:31 -0600 From: Roger Quadros To: , , CC: , , , , , , , , , , , , , "Andrew F . Davis" Subject: [PATCH v2 10/14] remoteproc/pru: Add PRU remoteproc driver Date: Mon, 4 Feb 2019 16:22:43 +0200 Message-ID: <1549290167-876-11-git-send-email-rogerq@ti.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1549290167-876-1-git-send-email-rogerq@ti.com> References: <1549290167-876-1-git-send-email-rogerq@ti.com> MIME-Version: 1.0 X-EXCLAIMER-MD-CONFIG: e1e8a2fd-e40a-4ac6-ac9b-f7e9cc9ee180 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Suman Anna The Programmable Real-Time Unit Subsystem (PRUSS) consists of dual 32-bit RISC cores (Programmable Real-Time Units, or PRUs) for program execution. This patch adds a remoteproc platform driver for managing the individual PRU RISC cores life cycle. This remoteproc driver does not have support for error recovery and system suspend/resume features. Different compatibles are used to allow providing scalability for instance-specific device data if needed. The driver uses a default firmware-name retrieved from device-tree, and the firmwares are expected to be present in the standard Linux firmware search paths. They can also be adjusted by userspace if required through the sysfs interface provided by the remoteproc core. The PRU remoteproc driver uses a client-driven boot methodology - it does _not_ support auto-boot so that the PRU load and boot is dictated by the corresponding client drivers for achieving various usecases. This allows flexibility for the client drivers or applications to set a firmware name (if needed) based on their desired functionality and boot the PRU. The sysfs bind and unbind attributes have also been suppressed so that the PRU devices cannot be unbound and thereby shutdown a PRU from underneath a PRU client driver. A new entry 'single_step' is added to the remoteproc debugfs dir. The 'single_step' utilizes the single-step execution of the PRU cores. Writing a non-zero value performs a single step, and a zero value restores the PRU to execute in the same mode as the mode before the first single step. (note: if the PRU is halted because of a halt instruction, then no change occurs). pru_rproc_get() and pru_rproc_put() functions allow client drivers to acquire and release the remoteproc device associated with a PRU core. The PRU cores are treated as resources with only one client owning it at a time. PRU interrupt mapping can be provided via devicetree using ti,pru-interrupt-map property or via the resource table in the firmware blob. If both are provided, the config in DT takes precedence. For interrupt map via resource table, pru-software-support-package [1] has been historically using version 0 for this. However, the current data structure is not scaleable and is not self sufficient. 1) it hard codes number of channel to host mappings so is not scaleable to newer SoCs than have more of these. 2) it does not contain the event to channel mappings within itself but relies on a pointer to point to another section in data memory. This causes a weird complication that the respective data section must be loaded before we can really use the INTC map. With this patch we drop support for version 0 and support version 1 which is a more robust and scalable data structure. It should be able to support a sufficiently large number (255) of sysevents, channels and host interrupts and is self contained so it can be used without dependency on order of loading sections. [1] git://git.ti.com/pru-software-support-package/pru-software-support-package.git Signed-off-by: Suman Anna Signed-off-by: Andrew F. Davis Signed-off-by: Tero Kristo Signed-off-by: Roger Quadros --- drivers/remoteproc/Kconfig | 14 + drivers/remoteproc/Makefile | 1 + drivers/remoteproc/pru_rproc.c | 930 +++++++++++++++++++++++++++++++++++ drivers/remoteproc/pru_rproc.h | 54 ++ include/linux/remoteproc/pru_rproc.h | 27 + 5 files changed, 1026 insertions(+) create mode 100644 drivers/remoteproc/pru_rproc.c create mode 100644 drivers/remoteproc/pru_rproc.h create mode 100644 include/linux/remoteproc/pru_rproc.h -- Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki. Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index f0abd26..333666e 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -197,6 +197,20 @@ config ST_REMOTEPROC config ST_SLIM_REMOTEPROC tristate +config PRUSS_REMOTEPROC + tristate "TI PRUSS remoteproc support" + depends on TI_PRUSS + default n + help + Support for TI PRU-ICSS remote processors via the remote processor + framework. + + Currently supported on AM33xx SoCs. + + Say Y or M here to support the Programmable Realtime Unit (PRU) + processors on various TI SoCs. It's safe to say N here if you're + not interested in the PRU or if you are unsure. + endif # REMOTEPROC endmenu diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile index ce5d061..88a86cc 100644 --- a/drivers/remoteproc/Makefile +++ b/drivers/remoteproc/Makefile @@ -26,3 +26,4 @@ qcom_wcnss_pil-y += qcom_wcnss.o qcom_wcnss_pil-y += qcom_wcnss_iris.o obj-$(CONFIG_ST_REMOTEPROC) += st_remoteproc.o obj-$(CONFIG_ST_SLIM_REMOTEPROC) += st_slim_rproc.o +obj-$(CONFIG_PRUSS_REMOTEPROC) += pru_rproc.o diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c new file mode 100644 index 0000000..ddd4b64 --- /dev/null +++ b/drivers/remoteproc/pru_rproc.c @@ -0,0 +1,930 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * PRU-ICSS remoteproc driver for various TI SoCs + * + * Copyright (C) 2014-2019 Texas Instruments Incorporated - http://www.ti.com/ + * Suman Anna + * Andrew F. Davis + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "remoteproc_internal.h" +#include "pru_rproc.h" + +/* ELF PAGE ID */ +#define PRU_PAGE_IRAM 0 +#define PRU_PAGE_DRAM 1 + +/* IRAM offsets */ +#define PRU0_IRAM_START 0x34000 +#define PRU1_IRAM_START 0x38000 +#define PRU_IRAM_MASK 0x3ffff + +/* PRU_ICSS_PRU_CTRL registers */ +#define PRU_CTRL_CTRL 0x0000 +#define PRU_CTRL_STS 0x0004 +#define PRU_CTRL_WAKEUP_EN 0x0008 +#define PRU_CTRL_CYCLE 0x000C +#define PRU_CTRL_STALL 0x0010 +#define PRU_CTRL_CTBIR0 0x0020 +#define PRU_CTRL_CTBIR1 0x0024 +#define PRU_CTRL_CTPPR0 0x0028 +#define PRU_CTRL_CTPPR1 0x002C + +/* CTRL register bit-fields */ +#define CTRL_CTRL_SOFT_RST_N BIT(0) +#define CTRL_CTRL_EN BIT(1) +#define CTRL_CTRL_SLEEPING BIT(2) +#define CTRL_CTRL_CTR_EN BIT(3) +#define CTRL_CTRL_SINGLE_STEP BIT(8) +#define CTRL_CTRL_RUNSTATE BIT(15) + +/* PRU_ICSS_PRU_DEBUG registers */ +#define PRU_DEBUG_GPREG(x) (0x0000 + (x) * 4) +#define PRU_DEBUG_CT_REG(x) (0x0080 + (x) * 4) + +/** + * struct pru_rproc - PRU remoteproc structure + * @id: id of the PRU core within the PRUSS + * @pruss: back-reference to parent PRUSS structure + * @rproc: remoteproc pointer for this PRU core + * @iram_region: PRU IRAM IOMEM + * @ctrl_regmap: regmap to PRU CTRL IOMEM + * @debug_regmap: regmap to PRU DEBUG IOMEM + * @client_np: client device node + * @intc_config: PRU INTC configuration data + * @dram0: PRUSS DRAM0 region + * @dram1: PRUSS DRAM1 region + * @shrdram: PRUSS SHARED RAM region + * @iram_da: device address of Instruction RAM for this PRU + * @pdram_da: device address of primary Data RAM for this PRU + * @sdram_da: device address of secondary Data RAM for this PRU + * @shrdram_da: device address of shared Data RAM + * @cfg: regmap to CFG module + * @gpcfg_reg: offset to gpcfg register of this PRU + * @fw_name: name of firmware image used during loading + * @gpmux_save: saved value for gpmux config + * @dt_irqs: number of irqs configured from DT + * @fw_irqs: number of irqs configured from FW + * @lock: mutex to protect client usage + * @dbg_single_step: debug state variable to set PRU into single step mode + * @ctrl_saved_state: saved CTRL state to return to normal mode + */ +struct pru_rproc { + int id; + struct pruss *pruss; + struct rproc *rproc; + struct pruss_mem_region iram_region; + struct regmap *ctrl_regmap; + struct regmap *debug_regmap; + struct device_node *client_np; + struct pruss_intc_config intc_config; + struct pruss_mem_region dram0; + struct pruss_mem_region dram1; + struct pruss_mem_region shrdram; + u32 iram_da; + u32 pdram_da; + u32 sdram_da; + u32 shrdram_da; + struct regmap *cfg; + int gpcfg_reg; + const char *fw_name; + u8 gpmux_save; + int dt_irqs; + int fw_irqs; + struct mutex lock; /* client access lock */ + bool dbg_single_step; + u32 ctrl_saved_state; +}; + +/** + * pru_rproc_set_firmware() - set firmware for a pru core + * @rproc: the rproc instance of the PRU + * @fw_name: the new firmware name, or NULL if default is desired + */ +static int pru_rproc_set_firmware(struct rproc *rproc, const char *fw_name) +{ + struct pru_rproc *pru = rproc->priv; + + if (!fw_name) + fw_name = pru->fw_name; + + return rproc_set_firmware(rproc, fw_name); +} + +/* + * pru_get_gpmux() - get the current GPMUX value for a PRU device + * @pru: pru_rproc instance + * @mux: pointer to store the current mux value into + * + * returns 0 on success, negative error value otherwise. + */ +static int pru_get_gpmux(struct pru_rproc *pru, u8 *mux) +{ + int ret; + unsigned int val; + + ret = regmap_read(pru->cfg, pru->gpcfg_reg, &val); + if (ret) + return ret; + + *mux = (u8)((val & PRUSS_GPCFG_PRU_MUX_SEL_MASK) >> + PRUSS_GPCFG_PRU_MUX_SEL_SHIFT); + + return 0; +} + +/** + * pru_set_gpmux() - set the GPMUX value for a PRU device + * @pru: pru_rproc instance + * @mux: new mux value for PRU + * + * returns 0 on success, negative error value otherwise. + */ +static int pru_set_gpmux(struct pru_rproc *pru, u8 mux) +{ + if (mux >= PRUSS_GP_MUX_SEL_MAX) + return -EINVAL; + + return regmap_update_bits(pru->cfg, pru->gpcfg_reg, + PRUSS_GPCFG_PRU_MUX_SEL_MASK, + (u32)mux << PRUSS_GPCFG_PRU_MUX_SEL_SHIFT); +} + +static int pru_get_intc_dt_config(struct pru_rproc *pru, + const char *propname, int index, + struct pruss_intc_config *intc_config) +{ + struct device *dev = &pru->rproc->dev; + struct device_node *np = pru->client_np; + struct property *prop; + int ret = 0, entries, i; + int dt_irqs = 0; + u32 *arr; + int max_system_events, max_pru_channels, max_pru_host_ints; + + max_system_events = MAX_PRU_SYS_EVENTS; + max_pru_channels = MAX_PRU_CHANNELS; + max_pru_host_ints = MAX_PRU_CHANNELS; + + prop = of_find_property(np, propname, NULL); + if (!prop) + return 0; + + entries = of_property_count_u32_elems(np, propname); + if (entries <= 0 || entries % 4) + return -EINVAL; + + arr = kmalloc_array(entries, sizeof(u32), GFP_KERNEL); + if (!arr) + return -ENOMEM; + + ret = of_property_read_u32_array(np, propname, arr, entries); + if (ret) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(intc_config->sysev_to_ch); i++) + intc_config->sysev_to_ch[i] = -1; + + for (i = 0; i < ARRAY_SIZE(intc_config->ch_to_host); i++) + intc_config->ch_to_host[i] = -1; + + for (i = 0; i < entries; i += 4) { + if (arr[i] != index) + continue; + + if (arr[i + 1] < 0 || + arr[i + 1] >= max_system_events) { + dev_err(dev, "bad sys event %d\n", arr[i + 1]); + ret = -EINVAL; + goto err; + } + + if (arr[i + 2] < 0 || + arr[i + 2] >= max_pru_channels) { + dev_err(dev, "bad channel %d\n", arr[i + 2]); + ret = -EINVAL; + goto err; + } + + if (arr[i + 3] < 0 || + arr[i + 3] >= max_pru_host_ints) { + dev_err(dev, "bad irq %d\n", arr[i + 3]); + ret = -EINVAL; + goto err; + } + + intc_config->sysev_to_ch[arr[i + 1]] = arr[i + 2]; + dev_dbg(dev, "sysevt-to-ch[%d] -> %d\n", arr[i + 1], + arr[i + 2]); + + intc_config->ch_to_host[arr[i + 2]] = arr[i + 3]; + dev_dbg(dev, "chnl-to-host[%d] -> %d\n", arr[i + 2], + arr[i + 3]); + + dt_irqs++; + } + + kfree(arr); + return dt_irqs; + +err: + kfree(arr); + return ret; +} + +static struct rproc *__pru_rproc_get(struct device_node *np, int index) +{ + struct device_node *rproc_np = NULL; + struct platform_device *pdev; + struct rproc *rproc; + + rproc_np = of_parse_phandle(np, "prus", index); + if (!rproc_np || !of_device_is_available(rproc_np)) + return ERR_PTR(-ENODEV); + + pdev = of_find_device_by_node(rproc_np); + of_node_put(rproc_np); + + if (!pdev) + /* probably PRU not yet probed */ + return ERR_PTR(-EPROBE_DEFER); + + /* TODO: replace the crude string based check to make sure it is PRU */ + if (!strstr(dev_name(&pdev->dev), "pru")) { + put_device(&pdev->dev); + return ERR_PTR(-ENODEV); + } + + rproc = platform_get_drvdata(pdev); + put_device(&pdev->dev); + if (!rproc) + return ERR_PTR(-EPROBE_DEFER); + + get_device(&rproc->dev); + + return rproc; +} + +/** + * pru_rproc_get() - get the PRU rproc instance from a device node + * @np: the user/client device node + * @index: index to use for the prus property + * + * This function looks through a client device node's "prus" property at index + * @index and returns the rproc handle for a valid PRU remote processor if + * found. The function allows only one user to own the PRU rproc resource at + * a time. Caller must call pru_rproc_put() when done with using the rproc, + * not required if the function returns a failure. + * + * Returns the rproc handle on success, and an ERR_PTR on failure using one + * of the following error values + * -ENODEV if device is not found + * -EBUSY if PRU is already acquired by anyone + * -EPROBE_DEFER is PRU device is not probed yet + */ +struct rproc *pru_rproc_get(struct device_node *np, int index) +{ + struct rproc *rproc; + struct pru_rproc *pru; + struct device *dev; + int ret; + u32 mux; + const char *fw_name; + + rproc = __pru_rproc_get(np, index); + if (IS_ERR(rproc)) + return rproc; + + pru = rproc->priv; + dev = &rproc->dev; + + mutex_lock(&pru->lock); + + if (pru->client_np) { + mutex_unlock(&pru->lock); + put_device(&rproc->dev); + return ERR_PTR(-EBUSY); + } + + pru->client_np = np; + + mutex_unlock(&pru->lock); + + ret = pru_get_gpmux(pru, &pru->gpmux_save); + if (ret) { + dev_err(dev, "failed to get cfg gpmux: %d\n", ret); + goto err; + } + + ret = of_property_read_u32_index(np, "ti,pruss-gp-mux-sel", index, + &mux); + if (!ret) { + ret = pru_set_gpmux(pru, mux); + if (ret) { + dev_err(dev, "failed to set cfg gpmux: %d\n", ret); + goto err; + } + } + + ret = of_property_read_string_index(np, "firmware-name", index, + &fw_name); + if (!ret) { + ret = pru_rproc_set_firmware(rproc, fw_name); + if (ret) { + dev_err(dev, "failed to set firmware: %d\n", ret); + goto err; + } + } + + ret = pru_get_intc_dt_config(pru, "ti,pru-interrupt-map", + index, &pru->intc_config); + if (ret < 0) { + dev_err(dev, "error getting DT interrupt map: %d\n", ret); + goto err; + } + + pru->dt_irqs = ret; + + return rproc; + +err: + pru_rproc_put(rproc); + return ERR_PTR(ret); +} +EXPORT_SYMBOL_GPL(pru_rproc_get); + +/** + * pru_rproc_put() - release the PRU rproc resource + * @rproc: the rproc resource to release + * + * Releases the PRU rproc resource and makes it available to other + * users. + */ +void pru_rproc_put(struct rproc *rproc) +{ + struct pru_rproc *pru; + + if (IS_ERR_OR_NULL(rproc)) + return; + + /* TODO: replace the crude string based check to make sure it is PRU */ + if (!strstr(dev_name(rproc->dev.parent), "pru")) + return; + + pru = rproc->priv; + if (!pru->client_np) + return; + + pru_rproc_set_firmware(rproc, NULL); + pru_set_gpmux(pru, pru->gpmux_save); + + mutex_lock(&pru->lock); + pru->client_np = NULL; + mutex_unlock(&pru->lock); + + put_device(&rproc->dev); +} +EXPORT_SYMBOL_GPL(pru_rproc_put); + +/* + * Control PRU single-step mode + * + * This is a debug helper function used for controlling the single-step + * mode of the PRU. The PRU Debug registers are not accessible when the + * PRU is in RUNNING state. + * + * Writing a non-zero value sets the PRU into single-step mode irrespective + * of its previous state. The PRU mode is saved only on the first set into + * a single-step mode. Writing a zero value will restore the PRU into its + * original mode. + */ +static int pru_rproc_debug_ss_set(void *data, u64 val) +{ + struct rproc *rproc = data; + struct pru_rproc *pru = rproc->priv; + u32 reg_val; + bool debug_ss; + + debug_ss = !!val; + if (!debug_ss && !pru->dbg_single_step) + return 0; + + regmap_read(pru->ctrl_regmap, PRU_CTRL_CTRL, ®_val); + + if (debug_ss && !pru->dbg_single_step) + pru->ctrl_saved_state = reg_val; + + if (debug_ss) + reg_val |= CTRL_CTRL_SINGLE_STEP | CTRL_CTRL_EN; + else + reg_val = pru->ctrl_saved_state; + + pru->dbg_single_step = debug_ss; + regmap_write(pru->ctrl_regmap, PRU_CTRL_CTRL, reg_val); + + return 0; +} + +static int pru_rproc_debug_ss_get(void *data, u64 *val) +{ + struct rproc *rproc = data; + struct pru_rproc *pru = rproc->priv; + + *val = pru->dbg_single_step; + + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(pru_rproc_debug_ss_fops, pru_rproc_debug_ss_get, + pru_rproc_debug_ss_set, "%llu\n"); + +/* + * Create PRU-specific debugfs entries + * + * The entries are created only if the parent remoteproc debugfs directory + * exists, and will be cleaned up by the remoteproc core. + */ +static void pru_rproc_create_debug_entries(struct rproc *rproc) +{ + if (!rproc->dbg_dir) + return; + + debugfs_create_file("single_step", 0600, rproc->dbg_dir, + rproc, &pru_rproc_debug_ss_fops); +} + +static void *pru_d_da_to_va(struct pru_rproc *pru, u32 da, int len); + +/* + * parse the custom interrupt map resource and save the intc_config + * for use when booting the processor. + */ +static int pru_handle_vendor_intrmap(struct rproc *rproc, + struct fw_rsc_pruss_intrmap *rsc) +{ + int fw_irqs = 0, i, ret = 0; + u8 *arr; + struct device *dev = &rproc->dev; + struct pru_rproc *pru = rproc->priv; + + dev_dbg(dev, "vendor rsc intc: version %d\n", rsc->version); + + /* + * 0 was prototyping version. Not supported. + * 1 is currently supported version. + */ + if (rsc->version == 0 || rsc->version > 1) { + dev_err(dev, "Unsupported version %d\n", rsc->version); + return -EINVAL; + } + + /* DT provided INTC config takes precedence */ + if (pru->dt_irqs) { + dev_info(dev, "INTC config in DT and FW. Using DT config.\n"); + return 0; + } + + arr = rsc->data; + + for (i = 0; i < ARRAY_SIZE(pru->intc_config.sysev_to_ch); i++) + pru->intc_config.sysev_to_ch[i] = -1; + + for (i = 0; i < ARRAY_SIZE(pru->intc_config.ch_to_host); i++) + pru->intc_config.ch_to_host[i] = -1; + + for (i = 0; i < rsc->num_maps * 3; i += 3) { + if (arr[i] < 0 || + arr[i] >= MAX_PRU_SYS_EVENTS) { + dev_err(dev, "bad sys event %d\n", arr[i]); + ret = -EINVAL; + goto err; + } + + if (arr[i + 1] < 0 || + arr[i + 1] >= MAX_PRU_CHANNELS) { + dev_err(dev, "bad channel %d\n", arr[i + 1]); + ret = -EINVAL; + goto err; + } + + if (arr[i + 2] < 0 || + arr[i + 2] >= MAX_PRU_CHANNELS) { + dev_err(dev, "bad host irq %d\n", arr[i + 2]); + ret = -EINVAL; + goto err; + } + + pru->intc_config.sysev_to_ch[arr[i]] = arr[i + 1]; + dev_dbg(dev, "sysevt-to-ch[%d] -> %d\n", arr[i], + arr[i + 1]); + + pru->intc_config.ch_to_host[arr[i + 1]] = arr[i + 2]; + dev_dbg(dev, "chnl-to-host[%d] -> %d\n", arr[i + 1], + arr[i + 2]); + + fw_irqs++; + } + + pru->fw_irqs = fw_irqs; + return 0; + +err: + pru->fw_irqs = 0; + return ret; +} + +/* PRU-specific vendor resource handler */ +static int pru_rproc_handle_vendor_rsc(struct rproc *rproc, + struct fw_rsc_vendor *ven_rsc) +{ + struct device *dev = rproc->dev.parent; + int ret = -EINVAL; + + struct fw_rsc_pruss_intrmap *rsc; + + rsc = (struct fw_rsc_pruss_intrmap *)ven_rsc->data; + + switch (rsc->type) { + case PRUSS_RSC_INTRS: + ret = pru_handle_vendor_intrmap(rproc, rsc); + break; + default: + dev_err(dev, "%s: cannot handle unknown type %d\n", __func__, + rsc->type); + } + + return ret; +} + +/* start a PRU core */ +static int pru_rproc_start(struct rproc *rproc) +{ + struct device *dev = &rproc->dev; + struct pru_rproc *pru = rproc->priv; + u32 val; + int ret; + + dev_dbg(dev, "starting PRU%d: entry-point = 0x%x\n", + pru->id, (rproc->bootaddr >> 2)); + + if (pru->dt_irqs || pru->fw_irqs) { + ret = pruss_intc_configure(rproc->dev.parent, + &pru->intc_config); + if (ret) { + dev_err(dev, "failed to configure intc %d\n", ret); + return ret; + } + } + + val = CTRL_CTRL_EN | ((rproc->bootaddr >> 2) << 16); + regmap_write(pru->ctrl_regmap, PRU_CTRL_CTRL, val); + + return 0; +} + +/* stop/disable a PRU core */ +static int pru_rproc_stop(struct rproc *rproc) +{ + struct device *dev = &rproc->dev; + struct pru_rproc *pru = rproc->priv; + + dev_dbg(dev, "stopping PRU%d\n", pru->id); + regmap_update_bits(pru->ctrl_regmap, PRU_CTRL_CTRL, CTRL_CTRL_EN, 0); + + /* undo INTC config */ + if (pru->dt_irqs || pru->fw_irqs) + pruss_intc_unconfigure(rproc->dev.parent, &pru->intc_config); + + return 0; +} + +/* + * Convert PRU device address (data spaces only) to kernel virtual address + * + * Each PRU has access to all data memories within the PRUSS, accessible at + * different ranges. So, look through both its primary and secondary Data + * RAMs as well as any shared Data RAM to convert a PRU device address to + * kernel virtual address. Data RAM0 is primary Data RAM for PRU0 and Data + * RAM1 is primary Data RAM for PRU1. + */ +static void *pru_d_da_to_va(struct pru_rproc *pru, u32 da, int len) +{ + struct pruss_mem_region dram0, dram1, shrd_ram; + u32 offset; + void *va = NULL; + + if (len <= 0) + return NULL; + + dram0 = pru->dram0; + dram1 = pru->dram1; + /* PRU1 has its local RAM addresses reversed */ + if (pru->id == 1) + swap(dram0, dram1); + shrd_ram = pru->shrdram; + + if (da >= pru->pdram_da && da + len <= pru->pdram_da + dram0.size) { + offset = da - pru->pdram_da; + va = (__force void *)(dram0.va + offset); + } else if (da >= pru->sdram_da && + da + len <= pru->sdram_da + dram1.size) { + offset = da - pru->sdram_da; + va = (__force void *)(dram1.va + offset); + } else if (da >= pru->shrdram_da && + da + len <= pru->shrdram_da + shrd_ram.size) { + offset = da - pru->shrdram_da; + va = (__force void *)(shrd_ram.va + offset); + } + + return va; +} + +/* + * Convert PRU device address (instruction space) to kernel virtual address + * + * A PRU does not have an unified address space. Each PRU has its very own + * private Instruction RAM, and its device address is identical to that of + * its primary Data RAM device address. + */ +static void *pru_i_da_to_va(struct pru_rproc *pru, u32 da, int len) +{ + u32 offset; + void *va = NULL; + + if (len <= 0) + return NULL; + + if (da >= pru->iram_da && + da + len <= pru->iram_da + pru->iram_region.size) { + offset = da - pru->iram_da; + va = (__force void *)(pru->iram_region.va + offset); + } + + return va; +} + +/* PRU-specific address translator */ +static void *pru_da_to_va(struct rproc *rproc, u64 da, int len, int map) +{ + struct pru_rproc *pru = rproc->priv; + void *va; + + switch (map) { + case PRU_PAGE_IRAM: + va = pru_i_da_to_va(pru, da, len); + break; + case PRU_PAGE_DRAM: + va = pru_d_da_to_va(pru, da, len); + break; + default: + dev_info(&rproc->dev, "%s: invalid page %d\n", __func__, map); + return 0; + }; + + return va; +} + +static struct rproc_ops pru_rproc_ops = { + .start = pru_rproc_start, + .stop = pru_rproc_stop, + .da_to_va = pru_da_to_va, + .handle_vendor_rsc = pru_rproc_handle_vendor_rsc, +}; + +static int pru_rproc_set_id(struct pru_rproc *pru) +{ + int ret = 0; + u32 iram_start = pru->iram_region.pa & PRU_IRAM_MASK; + + if (iram_start == PRU0_IRAM_START) + pru->id = 0; + else if (iram_start == PRU1_IRAM_START) + pru->id = 1; + else + ret = -EINVAL; + + return ret; +} + +static struct regmap_config pru_ctrl_regmap_config = { + .name = "ctrl", + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = PRU_CTRL_CTPPR1, +}; + +static struct regmap_config pru_debug_regmap_config = { + .name = "debug", + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = PRU_DEBUG_CT_REG(31), +}; + +static int pru_rproc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct platform_device *ppdev = to_platform_device(dev->parent); + struct pru_rproc *pru; + const char *fw_name; + struct rproc *rproc = NULL; + struct resource *res; + int ret; + void __iomem *va; + + if (!np) { + dev_err(dev, "Non-DT platform device not supported\n"); + return -ENODEV; + } + + ret = of_property_read_string(np, "firmware-name", &fw_name); + if (ret) { + dev_err(dev, "unable to retrieve firmware-name %d\n", ret); + return ret; + } + + rproc = rproc_alloc(dev, pdev->name, &pru_rproc_ops, fw_name, + sizeof(*pru)); + if (!rproc) { + dev_err(dev, "rproc_alloc failed\n"); + return -ENOMEM; + } + + pru = rproc->priv; + pru->cfg = syscon_regmap_lookup_by_phandle(np, "gpcfg"); + if (IS_ERR(pru->cfg)) { + if (PTR_ERR(pru->cfg) != -EPROBE_DEFER) + dev_err(dev, "can't get gpcfg syscon regmap\n"); + + return PTR_ERR(pru->cfg); + } + + if (of_property_read_u32_index(np, "gpcfg", 1, &pru->gpcfg_reg)) { + dev_err(dev, "couldn't get gpcfg reg. offset\n"); + return -EINVAL; + } + + /* error recovery is not supported for PRUs */ + rproc->recovery_disabled = true; + + /* + * rproc_add will auto-boot the processor normally, but this is + * not desired with PRU client driven boot-flow methodology. A PRU + * application/client driver will boot the corresponding PRU + * remote-processor as part of its state machine either through + * the remoteproc sysfs interface or through the equivalent kernel API + */ + rproc->auto_boot = false; + + pru->pruss = platform_get_drvdata(ppdev); + pru->rproc = rproc; + pru->fw_name = fw_name; + mutex_init(&pru->lock); + + ret = pruss_request_mem_region(pru->pruss, PRUSS_MEM_DRAM0, + &pru->dram0); + if (ret) { + dev_err(dev, "couldn't get PRUSS DRAM0: %d\n", ret); + return ret; + } + pruss_release_mem_region(pru->pruss, &pru->dram0); + + ret = pruss_request_mem_region(pru->pruss, PRUSS_MEM_DRAM1, + &pru->dram1); + if (ret) { + dev_err(dev, "couldn't get PRUSS DRAM1: %d\n", ret); + return ret; + } + pruss_release_mem_region(pru->pruss, &pru->dram1); + + ret = pruss_request_mem_region(pru->pruss, PRUSS_MEM_SHRD_RAM2, + &pru->shrdram); + if (ret) { + dev_err(dev, "couldn't get PRUSS Shared RAM: %d\n", ret); + return ret; + } + pruss_release_mem_region(pru->pruss, &pru->shrdram); + + /* XXX: get this from match data if different in the future */ + pru->iram_da = 0; + pru->pdram_da = 0; + pru->sdram_da = 0x2000; + pru->shrdram_da = 0x10000; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iram"); + pru->iram_region.va = devm_ioremap_resource(dev, res); + if (IS_ERR(pru->iram_region.va)) { + ret = PTR_ERR(pru->iram_region.va); + dev_err(dev, "failed to get iram resource: %d\n", ret); + goto free_rproc; + } + + pru->iram_region.pa = res->start; + pru->iram_region.size = resource_size(res); + + dev_dbg(dev, "iram: pa %pa size 0x%zx va %p\n", + &pru->iram_region.pa, pru->iram_region.size, + pru->iram_region.va); + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "control"); + va = devm_ioremap_resource(dev, res); + if (IS_ERR(va)) { + ret = PTR_ERR(va); + dev_err(dev, "failed to get control resource: %d\n", ret); + goto free_rproc; + } + + pru->ctrl_regmap = devm_regmap_init_mmio(dev, va, + &pru_ctrl_regmap_config); + if (IS_ERR(pru->ctrl_regmap)) { + ret = PTR_ERR(pru->ctrl_regmap); + dev_err(dev, "CTRL regmap init failed: %d\n", ret); + goto free_rproc; + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "debug"); + va = devm_ioremap_resource(dev, res); + if (IS_ERR(va)) { + ret = PTR_ERR(va); + dev_err(dev, "failed to get debug resource: %d\n", ret); + goto free_rproc; + } + pru->debug_regmap = devm_regmap_init_mmio(dev, va, + &pru_debug_regmap_config); + if (IS_ERR(pru->debug_regmap)) { + ret = PTR_ERR(pru->debug_regmap); + dev_err(dev, "DEBUG regmap init failed: %d\n", ret); + goto free_rproc; + } + + ret = pru_rproc_set_id(pru); + if (ret < 0) + goto free_rproc; + + platform_set_drvdata(pdev, rproc); + + ret = rproc_add(pru->rproc); + if (ret) { + dev_err(dev, "rproc_add failed: %d\n", ret); + goto free_rproc; + } + + pru_rproc_create_debug_entries(rproc); + + dev_info(dev, "PRU rproc node %s probed successfully\n", np->full_name); + + return 0; + +free_rproc: + rproc_free(rproc); + return ret; +} + +static int pru_rproc_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct rproc *rproc = platform_get_drvdata(pdev); + + dev_info(dev, "%s: removing rproc %s\n", __func__, rproc->name); + + rproc_del(rproc); + rproc_free(rproc); + + return 0; +} + +static const struct of_device_id pru_rproc_match[] = { + { .compatible = "ti,am3356-pru", }, + { .compatible = "ti,am4376-pru", }, + { .compatible = "ti,am5728-pru", }, + {}, +}; +MODULE_DEVICE_TABLE(of, pru_rproc_match); + +static struct platform_driver pru_rproc_driver = { + .driver = { + .name = "pru-rproc", + .of_match_table = pru_rproc_match, + .suppress_bind_attrs = true, + }, + .probe = pru_rproc_probe, + .remove = pru_rproc_remove, +}; +module_platform_driver(pru_rproc_driver); + +MODULE_AUTHOR("Suman Anna "); +MODULE_DESCRIPTION("PRU-ICSS Remote Processor Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/remoteproc/pru_rproc.h b/drivers/remoteproc/pru_rproc.h new file mode 100644 index 0000000..bbcf392 --- /dev/null +++ b/drivers/remoteproc/pru_rproc.h @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * PRUSS Remote Processor specific types + * + * Copyright (C) 2014-2019 Texas Instruments Incorporated - http://www.ti.com/ + * All rights reserved. + */ + +#ifndef _PRU_REMOTEPROC_H_ +#define _PRU_REMOTEPROC_H_ + +/** + * enum pruss_rsc_types - PRU specific resource types + * + * @PRUSS_RSC_INTRS: Resource holding information on PRU PINTC configuration + * @PRUSS_RSC_MAX: Indicates end of known/defined PRU resource types. + * This should be the last definition. + * + * Introduce new custom resource types before PRUSS_RSC_MAX. + */ +enum pruss_rsc_types { + PRUSS_RSC_INTRS = 1, + PRUSS_RSC_MAX = 2, +}; + +/** + * struct fw_rsc_pruss_intrmap - vendor resource to define PRU interrupts + * @type: should be PRUSS_RSC_INTRS + * @version: should be 1 or greater. 0 was for prototyping and is not supported + * @num_maps: number of interrupt mappings that follow + * @data: Array of 'num_maps' mappings. + * Each mapping is a triplet {s, c, h} + * s - system event id + * c - channel id + * h - host interrupt id + * + * PRU system events are mapped to channels, and these channels are mapped + * to host interrupts. Events can be mapped to channels in a one-to-one or + * many-to-one ratio (multiple events per channel), and channels can be + * mapped to host interrupts in a one-to-one or many-to-one ratio (multiple + * channels per interrupt). + * + * This resource is variable length due to the nature of INTC map. + * The below data structure is scalable so it can support sufficiently + * large number of sysevents and hosts. + */ +struct fw_rsc_pruss_intrmap { + u16 type; + u16 version; + u8 num_maps; + u8 data[]; +} __packed; + +#endif /* _PRU_REMOTEPROC_H_ */ diff --git a/include/linux/remoteproc/pru_rproc.h b/include/linux/remoteproc/pru_rproc.h new file mode 100644 index 0000000..841da09 --- /dev/null +++ b/include/linux/remoteproc/pru_rproc.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/** + * PRU-ICSS Remote Subsystem user interfaces + * + * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com + */ + +#ifndef __LINUX_REMOTEPROC_PRU_RPROC_H +#define __LINUX_REMOTEPROC_PRU_RPROC_H + +#if IS_ENABLED(CONFIG_PRUSS_REMOTEPROC) + +struct rproc *pru_rproc_get(struct device_node *node, int index); +void pru_rproc_put(struct rproc *rproc); + +#else + +static inline struct rproc *pru_rproc_get(struct device_node *node, int index) +{ + return ERR_PTR(-ENOTSUPP); +} + +static inline void pru_rproc_put(struct rproc *rproc) { } + +#endif /* CONFIG_PRUSS_REMOTEPROC */ + +#endif /* __LINUX_REMOTEPROC_PRU_RPROC_H */ From patchwork Mon Feb 4 14:22:44 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roger Quadros X-Patchwork-Id: 157426 Delivered-To: patch@linaro.org Received: by 2002:a02:48:0:0:0:0:0 with SMTP id 69csp3974069jaa; Mon, 4 Feb 2019 06:24:34 -0800 (PST) X-Google-Smtp-Source: AHgI3IbTkxP8HrD7thjQvAwRrcGtvT+t4LX3J+aXzigHOpCli68ly5txSCBd8vm3WNA7GHXhGK1q X-Received: by 2002:a65:6105:: with SMTP id z5mr13088795pgu.26.1549290274041; Mon, 04 Feb 2019 06:24:34 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1549290274; cv=none; d=google.com; s=arc-20160816; b=XcE761xYeiFk0FS0futd6eAoXDSaDjPi+1PdxBel2S0WweNuOy3O7xIymZ6Sdz60/F ay2l4JXbwgU7GedFle7G0TqIP8We68J2UyTuqsorfmhU8dQUfkX3buXcMZm3sPlRSm5d YPDaDXm91vJoQH5/NZOaY6U9/irTFYGGVKbIBU6McqkGT4l55+dP6OIeVKuqSd2yH75x VqmuIq4G4VIIqBS4WnljCPZNzYwSxNfHR9GUHiDa+cZeAOMH7gKfrJbVHdT+OJSTVtyO 5p0uqd7jaekxh/mfqNjqPhlprqXTHFCc3SkE6O/Sxhkwx6SEgh/EhqmYTGlo+Pf4IiPO u1zA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature; bh=qsmYhumlh7XE3EZ26jo895vDIW3+iN+t0S4IYcX/ScU=; b=Zbo5MoUJicb+emgywN8woZ/XR+h9v4qh6NWs4Z/+RcFihQMeoEP2vxi9adR55ASFMy DmPCRxxllsJ08KOtWwMLpzLHMncfRCmi8Fq/CHRzIUo8r/i7B6+t+lb4tHKCHsr0xxAe Qhy9NWejzyMuuZz+ynaXI2ku3fdr0SsbjBPC4NuephbOfzRAOuD7wrZktuaAsl5vyHgx vx8GRFRaCHxmFTc4Yu3kQPCbidjNFiNzoilfF0rQrFVbKdvfsINWGEVaYveLTbvmGflI Ke3E3W6+w4a3nBnfylAcqM2Z+lEB5ByTnQbhYIktPr+v9tOViJcJHX8UDN4pqTJxR0xQ yYjw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@ti.com header.s=ti-com-17Q1 header.b=UTs8vmFm; 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; dmarc=pass (p=QUARANTINE sp=NONE dis=NONE) header.from=ti.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id j9si143968pll.437.2019.02.04.06.24.33; Mon, 04 Feb 2019 06:24:34 -0800 (PST) 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=@ti.com header.s=ti-com-17Q1 header.b=UTs8vmFm; 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; dmarc=pass (p=QUARANTINE sp=NONE dis=NONE) header.from=ti.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730004AbfBDOYb (ORCPT + 31 others); Mon, 4 Feb 2019 09:24:31 -0500 Received: from fllv0015.ext.ti.com ([198.47.19.141]:43388 "EHLO fllv0015.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729937AbfBDOY3 (ORCPT ); Mon, 4 Feb 2019 09:24:29 -0500 Received: from lelv0266.itg.ti.com ([10.180.67.225]) by fllv0015.ext.ti.com (8.15.2/8.15.2) with ESMTP id x14ENdAG032100; Mon, 4 Feb 2019 08:23:39 -0600 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=ti-com-17Q1; t=1549290219; bh=qsmYhumlh7XE3EZ26jo895vDIW3+iN+t0S4IYcX/ScU=; h=From:To:CC:Subject:Date:In-Reply-To:References; b=UTs8vmFmgpVVIukQVYPq5xQgTZy4W+RN3d89GlaMAVJxa6jyEvLuH1NHIYuL8FBRh xuiQUnbWrmWwciVZ/r7YueUf73SeO+jS0g/5Wk1UFRGbTFU4lS8HGhDTkHEAUvxYN9 Ix2+MEIlTqeGIvGp6nNSO2LeWzqVGMDtlQxbStEA= Received: from DFLE112.ent.ti.com (dfle112.ent.ti.com [10.64.6.33]) by lelv0266.itg.ti.com (8.15.2/8.15.2) with ESMTPS id x14ENdBo069143 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL); Mon, 4 Feb 2019 08:23:39 -0600 Received: from DFLE101.ent.ti.com (10.64.6.22) by DFLE112.ent.ti.com (10.64.6.33) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.1591.10; Mon, 4 Feb 2019 08:23:39 -0600 Received: from dflp32.itg.ti.com (10.64.6.15) by DFLE101.ent.ti.com (10.64.6.22) with Microsoft SMTP Server (version=TLS1_0, cipher=TLS_RSA_WITH_AES_256_CBC_SHA) id 15.1.1591.10 via Frontend Transport; Mon, 4 Feb 2019 08:23:39 -0600 Received: from localhost.localdomain (ileax41-snat.itg.ti.com [10.172.224.153]) by dflp32.itg.ti.com (8.14.3/8.13.8) with ESMTP id x14EMoKj012232; Mon, 4 Feb 2019 08:23:35 -0600 From: Roger Quadros To: , , CC: , , , , , , , , , , , , , "Andrew F . Davis" Subject: [PATCH v2 11/14] remoteproc/pru: Add pru_rproc_set_ctable() and pru_rproc_set_gpimode() Date: Mon, 4 Feb 2019 16:22:44 +0200 Message-ID: <1549290167-876-12-git-send-email-rogerq@ti.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1549290167-876-1-git-send-email-rogerq@ti.com> References: <1549290167-876-1-git-send-email-rogerq@ti.com> MIME-Version: 1.0 X-EXCLAIMER-MD-CONFIG: e1e8a2fd-e40a-4ac6-ac9b-f7e9cc9ee180 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Some firmwares expect the OS drivers to configure the CTABLE entries publishing dynamically allocated memory regions. For example, the PRU Ethernet firmwares use the C28 and C30 entries for retrieving the Shared RAM and System SRAM (OCMC) areas allocated by the PRU Ethernet client driver. Provide a way for users to do that through a new API, pru_rproc_set_ctable(). The API returns 0 on success and a negative value on error. NOTE: The programmable CTABLE entries are typically re-programmed by the PRU firmwares when dealing with a certain block of memory during block processing. This API provides an interface to the PRU client drivers to publish a dynamically allocated memory block with the PRU firmware using a CTABLE entry instead of a negotiated address in shared memory. Additional synchronization may be needed between the PRU client drivers and firmwares if different addresses needs to be published at run-time reusing the same CTABLE entry. Some client drivers need to set the GPI mode of the PRU. The GPI mode select bits like in the GPCFG register space. Add pru_rproc_set_gpimode() API to set the GPI mode for the PRU. Signed-off-by: Roger Quadros Signed-off-by: Andrew F. Davis [s-anna@ti.com: add the NOTE: on patch description, minor cleanups] Signed-off-by: Suman Anna --- drivers/remoteproc/pru_rproc.c | 48 ++++++++++++++++++++++++++++++++++++ include/linux/remoteproc/pru_rproc.h | 30 ++++++++++++++++++++++ 2 files changed, 78 insertions(+) -- Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki. Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c index ddd4b64..85463f7 100644 --- a/drivers/remoteproc/pru_rproc.c +++ b/drivers/remoteproc/pru_rproc.c @@ -398,6 +398,54 @@ void pru_rproc_put(struct rproc *rproc) } EXPORT_SYMBOL_GPL(pru_rproc_put); +/** + * pru_rproc_set_ctable() - set the constant table index for the PRU + * @rproc: the rproc instance of the PRU + * @c: constant table index to set + * @addr: physical address to set it to + */ +int pru_rproc_set_ctable(struct rproc *rproc, enum pru_ctable_idx c, u32 addr) +{ + struct pru_rproc *pru = rproc->priv; + unsigned int reg; + u32 mask, set; + u16 idx; + u16 idx_mask; + + /* pointer is 16 bit and index is 8-bit so mask out the rest */ + idx_mask = (c >= PRU_C28) ? 0xFFFF : 0xFF; + + /* ctable uses bit 8 and upwards only */ + idx = (addr >> 8) & idx_mask; + + /* configurable ctable (i.e. C24) starts at PRU_CTRL_CTBIR0 */ + reg = PRU_CTRL_CTBIR0 + 4 * (c >> 1); + mask = idx_mask << (16 * (c & 1)); + set = idx << (16 * (c & 1)); + + regmap_update_bits(pru->ctrl_regmap, reg, mask, set); + + return 0; +} +EXPORT_SYMBOL_GPL(pru_rproc_set_ctable); + +/** + * pru_rproc_set_gpimode() - set the GPI mode for the PRU + * @rproc: the rproc instance of the PRU + * @mode: GPI mode to set + * + * Returns 0 on success, negative error value otherwise. + */ +int pru_rproc_set_gpimode(struct rproc *rproc, enum pruss_gpi_mode mode) +{ + struct pru_rproc *pru = rproc->priv; + + return regmap_update_bits(pru->cfg, pru->gpcfg_reg, + PRUSS_GPCFG_PRU_GPI_MODE_MASK, + mode << PRUSS_GPCFG_PRU_GPI_MODE_SHIFT); +} +EXPORT_SYMBOL_GPL(pru_rproc_set_gpimode); + /* * Control PRU single-step mode * diff --git a/include/linux/remoteproc/pru_rproc.h b/include/linux/remoteproc/pru_rproc.h index 841da09..887d996 100644 --- a/include/linux/remoteproc/pru_rproc.h +++ b/include/linux/remoteproc/pru_rproc.h @@ -8,10 +8,28 @@ #ifndef __LINUX_REMOTEPROC_PRU_RPROC_H #define __LINUX_REMOTEPROC_PRU_RPROC_H +/** + * enum pru_ctable_idx - Configurable Constant table index identifiers + */ +enum pru_ctable_idx { + PRU_C24 = 0, + PRU_C25, + PRU_C26, + PRU_C27, + PRU_C28, + PRU_C29, + PRU_C30, + PRU_C31, +}; + +enum pruss_gpi_mode; + #if IS_ENABLED(CONFIG_PRUSS_REMOTEPROC) struct rproc *pru_rproc_get(struct device_node *node, int index); void pru_rproc_put(struct rproc *rproc); +int pru_rproc_set_ctable(struct rproc *rproc, enum pru_ctable_idx c, u32 addr); +int pru_rproc_set_gpimode(struct rproc *rproc, enum pruss_gpi_mode mode); #else @@ -22,6 +40,18 @@ static inline struct rproc *pru_rproc_get(struct device_node *node, int index) static inline void pru_rproc_put(struct rproc *rproc) { } +static inline int pru_rproc_set_ctable(struct rproc *rproc, + enum pru_ctable_idx c, u32 addr) +{ + return -ENOTSUPP; +} + +static inline int pru_rproc_set_gpimode(struct rproc *rproc, + enum pruss_gpi_mode mode) +{ + return -ENOTSUPP; +} + #endif /* CONFIG_PRUSS_REMOTEPROC */ #endif /* __LINUX_REMOTEPROC_PRU_RPROC_H */ From patchwork Mon Feb 4 14:22:46 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roger Quadros X-Patchwork-Id: 157429 Delivered-To: patch@linaro.org Received: by 2002:a02:48:0:0:0:0:0 with SMTP id 69csp3974274jaa; Mon, 4 Feb 2019 06:24:46 -0800 (PST) X-Google-Smtp-Source: ALg8bN5W9MqDG3PqK8TYu4ltt+BW9WAzrS29GZdvTcKQQRPjIugtDep3Bjf/vbdlkaHIpv/U/6XR X-Received: by 2002:a62:6ec8:: with SMTP id j191mr51449188pfc.198.1549290286375; Mon, 04 Feb 2019 06:24:46 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1549290286; cv=none; d=google.com; s=arc-20160816; b=sYIw5MSCe0CFIybcCrRRo8g7CJACN87lFq2fiiHN/7kuhP83NcpjFPYH7Q7ENFsr+1 RH7O0fgpBpeoHfwLJoy344awFrEBIrDJPtEyU1UiDS3Xt5KSV2q1iUb0gBCrBtBH+4CU 66nrvNh8aRLy3LMnOyMrLxzZ71JxnHVMFesKB3IMqrtgdcVo8wrrqjRGE/irF5bVylw1 wuB0/eljJUiOIne+3Ff7RTJa6J1xp3LQroS//Zk7NlhBzrDxiMnM0ZHnwIJKk93tZkla dHbJ3ntWfvKimbAak6ZldnRr0u+6vTdjoyJfGIXGJ1iZt2VwxNImPRZah0xzCGwMdGZN 7IKg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature; bh=93dULJjujpSqIrNJQ463PFFgzThrUMl392hE2ZPf+UI=; b=aya7QhHStS074i8WrkZg6owlpOMa7So+hLVNwFl6zMANXBmej2beQqfcrJtEvUuiTz VM1H+D9hYad0BnPhwjVDpalAe8l3aJDVTp5IFwrA3gr0MAyxQ0K9VqHC3tiTuCVJPEW9 ZchMZ5dcFBPXpN9I/Dh1/PlUZLigN0tT7Xx50z1cHDmclSdP7BKc88R+5J4HjZk7OPc1 K90MmZ07d1CiZTprZ9e/tzYZxDdjWBkRkFT4WExAw44Nts6Q63HZQME93ydZbOPAQ28b qWSCmuMtBI9b1Wkl5n12vH7zJ9iMrnkjBDaaN3lt7KC/HzjyfSqM8QBLZZg4BFdiB8M9 EJOg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@ti.com header.s=ti-com-17Q1 header.b=KqxgWaCz; 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; dmarc=pass (p=QUARANTINE sp=NONE dis=NONE) header.from=ti.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id g2si174845plp.18.2019.02.04.06.24.45; Mon, 04 Feb 2019 06:24:46 -0800 (PST) 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=@ti.com header.s=ti-com-17Q1 header.b=KqxgWaCz; 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; dmarc=pass (p=QUARANTINE sp=NONE dis=NONE) header.from=ti.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730391AbfBDOYo (ORCPT + 31 others); Mon, 4 Feb 2019 09:24:44 -0500 Received: from lelv0142.ext.ti.com ([198.47.23.249]:59694 "EHLO lelv0142.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730110AbfBDOYj (ORCPT ); Mon, 4 Feb 2019 09:24:39 -0500 Received: from fllv0034.itg.ti.com ([10.64.40.246]) by lelv0142.ext.ti.com (8.15.2/8.15.2) with ESMTP id x14ENlHC092552; Mon, 4 Feb 2019 08:23:47 -0600 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=ti-com-17Q1; t=1549290227; bh=93dULJjujpSqIrNJQ463PFFgzThrUMl392hE2ZPf+UI=; h=From:To:CC:Subject:Date:In-Reply-To:References; b=KqxgWaCzRjdSVy5taTeA6JWQ2J15STPlHjTxqFKjeXRjNGCSMZGEXjWiXhmRnhAxO 7Om4R/nozEgq5HXTzSJZk3i3EN2OmMxXCV3w8+0GfHKENWoVV9bYfYZTKlFsrvXRGA gzx0suTuBCuiHU8W+kL90ztARRkjj6Pi73qh6g9c= Received: from DLEE103.ent.ti.com (dlee103.ent.ti.com [157.170.170.33]) by fllv0034.itg.ti.com (8.15.2/8.15.2) with ESMTPS id x14ENlBS010485 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL); Mon, 4 Feb 2019 08:23:47 -0600 Received: from DLEE111.ent.ti.com (157.170.170.22) by DLEE103.ent.ti.com (157.170.170.33) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.1591.10; Mon, 4 Feb 2019 08:23:47 -0600 Received: from dflp32.itg.ti.com (10.64.6.15) by DLEE111.ent.ti.com (157.170.170.22) with Microsoft SMTP Server (version=TLS1_0, cipher=TLS_RSA_WITH_AES_256_CBC_SHA) id 15.1.1591.10 via Frontend Transport; Mon, 4 Feb 2019 08:23:46 -0600 Received: from localhost.localdomain (ileax41-snat.itg.ti.com [10.172.224.153]) by dflp32.itg.ti.com (8.14.3/8.13.8) with ESMTP id x14EMoKl012232; Mon, 4 Feb 2019 08:23:43 -0600 From: Roger Quadros To: , , CC: , , , , , , , , , , , , Subject: [PATCH v2 13/14] rpmsg: virtio_rpmsg_bus: move back rpmsg_hdr into a public header Date: Mon, 4 Feb 2019 16:22:46 +0200 Message-ID: <1549290167-876-14-git-send-email-rogerq@ti.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1549290167-876-1-git-send-email-rogerq@ti.com> References: <1549290167-876-1-git-send-email-rogerq@ti.com> MIME-Version: 1.0 X-EXCLAIMER-MD-CONFIG: e1e8a2fd-e40a-4ac6-ac9b-f7e9cc9ee180 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Suman Anna Commit e88dae5da46d ("rpmsg: Move virtio specifics from public header") has moved the struct rpmsg_hdr definition from the public rpmsg.h and made it private to virtio_rpmsg_bus module. This structure is a common header used in all virtio rpmsg messages, and used by various virtio rpmsg bus drivers. So, move this back into the virtio_rpmsg specific public header to make it visible to various rpmsg drivers. Signed-off-by: Suman Anna Signed-off-by: Roger Quadros --- drivers/rpmsg/virtio_rpmsg_bus.c | 21 +-------------------- include/linux/rpmsg/virtio_rpmsg.h | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 20 deletions(-) create mode 100644 include/linux/rpmsg/virtio_rpmsg.h -- Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki. Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c index 664f957..f654923 100644 --- a/drivers/rpmsg/virtio_rpmsg_bus.c +++ b/drivers/rpmsg/virtio_rpmsg_bus.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "rpmsg_internal.h" @@ -73,26 +74,6 @@ struct virtproc_info { #define VIRTIO_RPMSG_F_NS 0 /* RP supports name service notifications */ /** - * struct rpmsg_hdr - common header for all rpmsg messages - * @src: source address - * @dst: destination address - * @reserved: reserved for future use - * @len: length of payload (in bytes) - * @flags: message flags - * @data: @len bytes of message payload data - * - * Every message sent(/received) on the rpmsg bus begins with this header. - */ -struct rpmsg_hdr { - u32 src; - u32 dst; - u32 reserved; - u16 len; - u16 flags; - u8 data[0]; -} __packed; - -/** * struct rpmsg_ns_msg - dynamic name service announcement message * @name: name of remote service that is published * @addr: address of remote service that is published diff --git a/include/linux/rpmsg/virtio_rpmsg.h b/include/linux/rpmsg/virtio_rpmsg.h new file mode 100644 index 0000000..cf5f820 --- /dev/null +++ b/include/linux/rpmsg/virtio_rpmsg.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _LINUX_RPMSG_VIRTIO_RPMSG_H +#define _LINUX_RPMSG_VIRTIO_RPMSG_H + +/** + * struct rpmsg_hdr - common header for all virtio rpmsg messages + * @src: source address + * @dst: destination address + * @reserved: reserved for future use + * @len: length of payload (in bytes) + * @flags: message flags + * @data: @len bytes of message payload data + * + * Every message sent(/received) on the rpmsg bus begins with this header. + */ +struct rpmsg_hdr { + u32 src; + u32 dst; + u32 reserved; + u16 len; + u16 flags; + u8 data[0]; +} __packed; + +#endif From patchwork Mon Feb 4 14:22:47 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roger Quadros X-Patchwork-Id: 157430 Delivered-To: patch@linaro.org Received: by 2002:a02:48:0:0:0:0:0 with SMTP id 69csp3974383jaa; Mon, 4 Feb 2019 06:24:52 -0800 (PST) X-Google-Smtp-Source: AHgI3IYeXzko6m3HAjS8p/muwUhLG9R+Q+pmLpU67IPjUGJraTaF5rwrn4/Al32rijWDfiWQBxDo X-Received: by 2002:a63:2ac9:: with SMTP id q192mr13135501pgq.58.1549290292724; Mon, 04 Feb 2019 06:24:52 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1549290292; cv=none; d=google.com; s=arc-20160816; b=g0E//cvW4xJYeokEkCXmi3SQgVsF+NJTRiq4SlczuEDVX83/vmxSGOpodIWznMTagZ vfF/og9Jm2eGMZPd0cFrrRtKVlU98ASy7eHWOcnsdifI0cpjNZAQHro1DyujZBQRpChP z6zvlsFT2nuAB2s51G7N9QGlbj4G+qarH7GdLEt9LwJMBgJS2cNr8wx0tVRDixx6YnIS aVyzTRLfN+kgSHPSNCuPje8cKMD2DFnbxYA/MqeW46iA618DWo64dyzt6Gw+FAzl701V EpyEyjbg6NuCKMpwlLXHeXTYQ5ER4v5aR1g4aQbSLUFQ2Knu/l68qAP/2e1AVO4mmqvx Q1xg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature; bh=XXQ80qS5M5gOIl4GkFMwJ6ZJ9BZqab716Oc1/PpEWl4=; b=ey/RJYY/BC+vyCicFvEcoVEhWuPaUE24VtcPBvy2oulex1t8gRVr3S3dp1Ur3JMro5 np8CcLt9oYB0Y1ibMduca9rVB9SY9tiU/bXI0bn5dSICcQ4JoTQoBpvNX/4URHHTUNWP qMvT+ns5ck7ss/mVUzaKu1WwGn+VjKzPGW1JZZTtc9ZSus5fph6vOlQ/aZKo59jJvtwM 4wQXXIQ+QZpeo2oFSo2NO5JiFnz9912fX3L9rd6fhGjeokELL3NupMamid8IJ3Z2MjIa N0v63FzzPBV5ksdcxtRnpp23ha1NoXYpB+0XfQd6A/y9ICSyu6UL2b6GNNo94N7fjp9t Oapw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@ti.com header.s=ti-com-17Q1 header.b=nIrf++DD; 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; dmarc=pass (p=QUARANTINE sp=NONE dis=NONE) header.from=ti.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id g2si174845plp.18.2019.02.04.06.24.52; Mon, 04 Feb 2019 06:24:52 -0800 (PST) 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=@ti.com header.s=ti-com-17Q1 header.b=nIrf++DD; 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; dmarc=pass (p=QUARANTINE sp=NONE dis=NONE) header.from=ti.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731364AbfBDOYu (ORCPT + 31 others); Mon, 4 Feb 2019 09:24:50 -0500 Received: from fllv0015.ext.ti.com ([198.47.19.141]:43436 "EHLO fllv0015.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730085AbfBDOYm (ORCPT ); Mon, 4 Feb 2019 09:24:42 -0500 Received: from lelv0265.itg.ti.com ([10.180.67.224]) by fllv0015.ext.ti.com (8.15.2/8.15.2) with ESMTP id x14ENpDm032277; Mon, 4 Feb 2019 08:23:51 -0600 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=ti-com-17Q1; t=1549290231; bh=XXQ80qS5M5gOIl4GkFMwJ6ZJ9BZqab716Oc1/PpEWl4=; h=From:To:CC:Subject:Date:In-Reply-To:References; b=nIrf++DD7YwqfxcUqbBOAd2nICgzUk+rJslqurEXrR/0ZzydexJqzobqg7RHuS9B5 mjz8fNOVgicS94esEx6V5PLExIET+Y6C2hywaUZfRZLPQW3Z5+EH9vJ8hcV9mYZxIC kkqIOd4wcRvqwsoeVSDfG/Fr4qI3naDwSeVR4nJg= Received: from DFLE107.ent.ti.com (dfle107.ent.ti.com [10.64.6.28]) by lelv0265.itg.ti.com (8.15.2/8.15.2) with ESMTPS id x14ENpor049097 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL); Mon, 4 Feb 2019 08:23:51 -0600 Received: from DFLE107.ent.ti.com (10.64.6.28) by DFLE107.ent.ti.com (10.64.6.28) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.1591.10; Mon, 4 Feb 2019 08:23:50 -0600 Received: from dflp32.itg.ti.com (10.64.6.15) by DFLE107.ent.ti.com (10.64.6.28) with Microsoft SMTP Server (version=TLS1_0, cipher=TLS_RSA_WITH_AES_256_CBC_SHA) id 15.1.1591.10 via Frontend Transport; Mon, 4 Feb 2019 08:23:50 -0600 Received: from localhost.localdomain (ileax41-snat.itg.ti.com [10.172.224.153]) by dflp32.itg.ti.com (8.14.3/8.13.8) with ESMTP id x14EMoKm012232; Mon, 4 Feb 2019 08:23:47 -0600 From: Roger Quadros To: , , CC: , , , , , , , , , , , , Subject: [PATCH v2 14/14] rpmsg: pru: add a PRU RPMsg driver Date: Mon, 4 Feb 2019 16:22:47 +0200 Message-ID: <1549290167-876-15-git-send-email-rogerq@ti.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1549290167-876-1-git-send-email-rogerq@ti.com> References: <1549290167-876-1-git-send-email-rogerq@ti.com> MIME-Version: 1.0 X-EXCLAIMER-MD-CONFIG: e1e8a2fd-e40a-4ac6-ac9b-f7e9cc9ee180 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Jason Reeder An RPMsg driver that exposes interfaces to user space, to allow applications to communicate with the PRU processors on available TI SoCs has been added. This is restricted to SoCs that have the PRUSS remoteproc support. Signed-off-by: Jason Reeder [s-anna@ti.com: various cleanups, rpmsg rebase fixes for 4.14] Signed-off-by: Suman Anna Signed-off-by: Roger Quadros --- drivers/rpmsg/Kconfig | 14 ++ drivers/rpmsg/Makefile | 1 + drivers/rpmsg/rpmsg_pru.c | 360 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 375 insertions(+) create mode 100644 drivers/rpmsg/rpmsg_pru.c -- Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki. Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig index d0322b4..5beb5e4 100644 --- a/drivers/rpmsg/Kconfig +++ b/drivers/rpmsg/Kconfig @@ -55,4 +55,18 @@ config RPMSG_VIRTIO select RPMSG select VIRTIO +config RPMSG_PRU + tristate "PRU RPMsg Communication driver" + default n + depends on RPMSG_VIRTIO + depends on REMOTEPROC + depends on PRUSS_REMOTEPROC + help + An rpmsg driver that exposes interfaces to user space, to allow + applications to communicate with the PRU processors on available + TI SoCs. This is restricted to SoCs that have the PRUSS remoteproc + support. + + If unsure, say N. + endmenu diff --git a/drivers/rpmsg/Makefile b/drivers/rpmsg/Makefile index 9aa8595..b66a5dd 100644 --- a/drivers/rpmsg/Makefile +++ b/drivers/rpmsg/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_RPMSG) += rpmsg_core.o obj-$(CONFIG_RPMSG_CHAR) += rpmsg_char.o +obj-$(CONFIG_RPMSG_PRU) += rpmsg_pru.o obj-$(CONFIG_RPMSG_QCOM_GLINK_RPM) += qcom_glink_rpm.o obj-$(CONFIG_RPMSG_QCOM_GLINK_NATIVE) += qcom_glink_native.o obj-$(CONFIG_RPMSG_QCOM_GLINK_SMEM) += qcom_glink_smem.o diff --git a/drivers/rpmsg/rpmsg_pru.c b/drivers/rpmsg/rpmsg_pru.c new file mode 100644 index 0000000..2e8d2b1 --- /dev/null +++ b/drivers/rpmsg/rpmsg_pru.c @@ -0,0 +1,360 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * PRU Remote Processor Messaging Driver + * + * Copyright (C) 2015-2019 Texas Instruments Incorporated - http://www.ti.com/ + * Jason Reeder + * Suman Anna + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PRU_MAX_DEVICES (8) +/* Matches the definition in virtio_rpmsg_bus.c */ +#define RPMSG_BUF_SIZE (512) +#define MAX_FIFO_MSG (32) +#define FIFO_MSG_SIZE RPMSG_BUF_SIZE + +/** + * struct rpmsg_pru_dev - Structure that contains the per-device data + * @rpdev: rpmsg channel device that is associated with this rpmsg_pru device + * @dev: device + * @cdev: character device + * @locked: boolean used to determine whether or not the device file is in use + * @devt: dev_t structure for the rpmsg_pru device + * @msg_fifo: kernel fifo used to buffer the messages between userspace and PRU + * @msg_len: array storing the lengths of each message in the kernel fifo + * @msg_idx_rd: kernel fifo read index + * @msg_idx_wr: kernel fifo write index + * @wait_list: wait queue used to implement the poll operation of the character + * device + * + * Each rpmsg_pru device provides an interface, using an rpmsg channel (rpdev), + * between a user space character device (cdev) and a PRU core. A kernel fifo + * (msg_fifo) is used to buffer the messages in the kernel that are + * being passed between the character device and the PRU. + */ +struct rpmsg_pru_dev { + struct rpmsg_device *rpdev; + struct device *dev; + struct cdev cdev; + bool locked; + dev_t devt; + struct kfifo msg_fifo; + u32 msg_len[MAX_FIFO_MSG]; + int msg_idx_rd; + int msg_idx_wr; + wait_queue_head_t wait_list; +}; + +static struct class *rpmsg_pru_class; +static dev_t rpmsg_pru_devt; +static DEFINE_MUTEX(rpmsg_pru_lock); +static DEFINE_IDR(rpmsg_pru_minors); + +static int rpmsg_pru_open(struct inode *inode, struct file *filp) +{ + struct rpmsg_pru_dev *prudev; + int ret = -EACCES; + + prudev = container_of(inode->i_cdev, struct rpmsg_pru_dev, cdev); + + mutex_lock(&rpmsg_pru_lock); + if (!prudev->locked) { + prudev->locked = true; + filp->private_data = prudev; + ret = 0; + } + mutex_unlock(&rpmsg_pru_lock); + + if (ret) + dev_err(prudev->dev, "Device already open\n"); + + return ret; +} + +static int rpmsg_pru_release(struct inode *inode, struct file *filp) +{ + struct rpmsg_pru_dev *prudev; + + prudev = container_of(inode->i_cdev, struct rpmsg_pru_dev, cdev); + mutex_lock(&rpmsg_pru_lock); + prudev->locked = false; + mutex_unlock(&rpmsg_pru_lock); + return 0; +} + +static ssize_t rpmsg_pru_read(struct file *filp, char __user *buf, + size_t count, loff_t *f_pos) +{ + int ret; + u32 length; + struct rpmsg_pru_dev *prudev; + + prudev = filp->private_data; + + if (kfifo_is_empty(&prudev->msg_fifo) && + (filp->f_flags & O_NONBLOCK)) + return -EAGAIN; + + ret = wait_event_interruptible(prudev->wait_list, + !kfifo_is_empty(&prudev->msg_fifo)); + if (ret) + return -EINTR; + + ret = kfifo_to_user(&prudev->msg_fifo, buf, + prudev->msg_len[prudev->msg_idx_rd], &length); + prudev->msg_idx_rd = (prudev->msg_idx_rd + 1) % MAX_FIFO_MSG; + + return ret ? ret : length; +} + +static ssize_t rpmsg_pru_write(struct file *filp, const char __user *buf, + size_t count, loff_t *f_pos) +{ + int ret; + struct rpmsg_pru_dev *prudev; + static char rpmsg_pru_buf[RPMSG_BUF_SIZE]; + + prudev = filp->private_data; + + if (count > RPMSG_BUF_SIZE - sizeof(struct rpmsg_hdr)) { + dev_err(prudev->dev, "Data too large for RPMsg Buffer\n"); + return -EINVAL; + } + + if (copy_from_user(rpmsg_pru_buf, buf, count)) { + dev_err(prudev->dev, "Error copying buffer from user space"); + return -EFAULT; + } + + ret = rpmsg_send(prudev->rpdev->ept, (void *)rpmsg_pru_buf, count); + if (ret) + dev_err(prudev->dev, "rpmsg_send failed: %d\n", ret); + + return ret ? ret : count; +} + +static unsigned int rpmsg_pru_poll(struct file *filp, + struct poll_table_struct *wait) +{ + int mask; + struct rpmsg_pru_dev *prudev; + + prudev = filp->private_data; + + poll_wait(filp, &prudev->wait_list, wait); + + mask = POLLOUT | POLLWRNORM; + + if (!kfifo_is_empty(&prudev->msg_fifo)) + mask |= POLLIN | POLLRDNORM; + + return mask; +} + +static const struct file_operations rpmsg_pru_fops = { + .owner = THIS_MODULE, + .open = rpmsg_pru_open, + .release = rpmsg_pru_release, + .read = rpmsg_pru_read, + .write = rpmsg_pru_write, + .poll = rpmsg_pru_poll, +}; + +static int rpmsg_pru_cb(struct rpmsg_device *rpdev, void *data, int len, + void *priv, u32 src) +{ + u32 length; + struct rpmsg_pru_dev *prudev; + + prudev = dev_get_drvdata(&rpdev->dev); + + if (kfifo_avail(&prudev->msg_fifo) < len) { + dev_err(&rpdev->dev, "Not enough space on the FIFO\n"); + return -ENOSPC; + } + + if ((prudev->msg_idx_wr + 1) % MAX_FIFO_MSG == + prudev->msg_idx_rd) { + dev_err(&rpdev->dev, "Message length table is full\n"); + return -ENOSPC; + } + + length = kfifo_in(&prudev->msg_fifo, data, len); + prudev->msg_len[prudev->msg_idx_wr] = length; + prudev->msg_idx_wr = (prudev->msg_idx_wr + 1) % MAX_FIFO_MSG; + + wake_up_interruptible(&prudev->wait_list); + + return 0; +} + +static int rpmsg_pru_probe(struct rpmsg_device *rpdev) +{ + int ret; + struct rpmsg_pru_dev *prudev; + int minor_got; + + prudev = devm_kzalloc(&rpdev->dev, sizeof(*prudev), GFP_KERNEL); + if (!prudev) + return -ENOMEM; + + mutex_lock(&rpmsg_pru_lock); + minor_got = idr_alloc(&rpmsg_pru_minors, prudev, 0, PRU_MAX_DEVICES, + GFP_KERNEL); + mutex_unlock(&rpmsg_pru_lock); + if (minor_got < 0) { + ret = minor_got; + dev_err(&rpdev->dev, "Failed to get a minor number for the rpmsg_pru device: %d\n", + ret); + goto fail_alloc_minor; + } + + prudev->devt = MKDEV(MAJOR(rpmsg_pru_devt), minor_got); + + cdev_init(&prudev->cdev, &rpmsg_pru_fops); + prudev->cdev.owner = THIS_MODULE; + ret = cdev_add(&prudev->cdev, prudev->devt, 1); + if (ret) { + dev_err(&rpdev->dev, "Unable to add cdev for the rpmsg_pru device\n"); + goto fail_add_cdev; + } + + prudev->dev = device_create(rpmsg_pru_class, &rpdev->dev, prudev->devt, + NULL, "rpmsg_pru%d", rpdev->dst); + if (IS_ERR(prudev->dev)) { + dev_err(&rpdev->dev, "Unable to create the rpmsg_pru device\n"); + ret = PTR_ERR(prudev->dev); + goto fail_create_device; + } + + prudev->rpdev = rpdev; + + ret = kfifo_alloc(&prudev->msg_fifo, MAX_FIFO_MSG * FIFO_MSG_SIZE, + GFP_KERNEL); + if (ret) { + dev_err(&rpdev->dev, "Unable to allocate fifo for the rpmsg_pru device\n"); + goto fail_alloc_fifo; + } + + init_waitqueue_head(&prudev->wait_list); + + dev_set_drvdata(&rpdev->dev, prudev); + + dev_info(&rpdev->dev, "new rpmsg_pru device: /dev/rpmsg_pru%d", + rpdev->dst); + + return 0; + +fail_alloc_fifo: + device_destroy(rpmsg_pru_class, prudev->devt); +fail_create_device: + cdev_del(&prudev->cdev); +fail_add_cdev: + mutex_lock(&rpmsg_pru_lock); + idr_remove(&rpmsg_pru_minors, minor_got); + mutex_unlock(&rpmsg_pru_lock); +fail_alloc_minor: + return ret; +} + +static void rpmsg_pru_remove(struct rpmsg_device *rpdev) +{ + struct rpmsg_pru_dev *prudev; + + prudev = dev_get_drvdata(&rpdev->dev); + + kfifo_free(&prudev->msg_fifo); + device_destroy(rpmsg_pru_class, prudev->devt); + cdev_del(&prudev->cdev); + mutex_lock(&rpmsg_pru_lock); + idr_remove(&rpmsg_pru_minors, MINOR(prudev->devt)); + mutex_unlock(&rpmsg_pru_lock); +} + +/* .name matches on RPMsg Channels and causes a probe */ +static const struct rpmsg_device_id rpmsg_driver_pru_id_table[] = { + { .name = "rpmsg-pru" }, + { }, +}; +MODULE_DEVICE_TABLE(rpmsg, rpmsg_driver_pru_id_table); + +static struct rpmsg_driver rpmsg_pru_driver = { + .drv.name = KBUILD_MODNAME, + .id_table = rpmsg_driver_pru_id_table, + .probe = rpmsg_pru_probe, + .callback = rpmsg_pru_cb, + .remove = rpmsg_pru_remove, +}; + +static int __init rpmsg_pru_init(void) +{ + int ret; + + rpmsg_pru_class = class_create(THIS_MODULE, "rpmsg_pru"); + if (IS_ERR(rpmsg_pru_class)) { + pr_err("Unable to create class\n"); + ret = PTR_ERR(rpmsg_pru_class); + goto fail_create_class; + } + + ret = alloc_chrdev_region(&rpmsg_pru_devt, 0, PRU_MAX_DEVICES, + "rpmsg_pru"); + if (ret) { + pr_err("Unable to allocate chrdev region\n"); + goto fail_alloc_region; + } + + ret = register_rpmsg_driver(&rpmsg_pru_driver); + if (ret) { + pr_err("Unable to register rpmsg driver"); + goto fail_register_rpmsg_driver; + } + + return 0; + +fail_register_rpmsg_driver: + unregister_chrdev_region(rpmsg_pru_devt, PRU_MAX_DEVICES); +fail_alloc_region: + class_destroy(rpmsg_pru_class); +fail_create_class: + return ret; +} + +static void __exit rpmsg_pru_exit(void) +{ + unregister_rpmsg_driver(&rpmsg_pru_driver); + idr_destroy(&rpmsg_pru_minors); + mutex_destroy(&rpmsg_pru_lock); + class_destroy(rpmsg_pru_class); + unregister_chrdev_region(rpmsg_pru_devt, PRU_MAX_DEVICES); +} + +module_init(rpmsg_pru_init); +module_exit(rpmsg_pru_exit); + +MODULE_AUTHOR("Jason Reeder "); +MODULE_ALIAS("rpmsg:rpmsg-pru"); +MODULE_DESCRIPTION("PRU Remote Processor Messaging Driver"); +MODULE_LICENSE("GPL v2");