Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752925AbbGQQ1A (ORCPT ); Fri, 17 Jul 2015 12:27:00 -0400 Received: from mail-bl2on0062.outbound.protection.outlook.com ([65.55.169.62]:55808 "EHLO na01-bl2-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1751964AbbGQQ05 (ORCPT ); Fri, 17 Jul 2015 12:26:57 -0400 Authentication-Results: spf=fail (sender IP is 66.35.236.227) smtp.mailfrom=opensource.altera.com; vger.kernel.org; dkim=none (message not signed) header.d=none; Authentication-Results: linuxfoundation.org; dkim=none (message not signed) header.d=none; From: To: , , , , , CC: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , Petr Cvek , , , , Alan Tull Subject: [PATCH v9 7/7] staging: fpga manager: add driver for socfpga fpga manager Date: Fri, 17 Jul 2015 10:51:17 -0500 Message-ID: <1437148277-5405-8-git-send-email-atull@opensource.altera.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1437148277-5405-1-git-send-email-atull@opensource.altera.com> References: <1437148277-5405-1-git-send-email-atull@opensource.altera.com> MIME-Version: 1.0 Content-Type: text/plain X-Originating-IP: [64.129.157.38] X-ClientProxiedBy: DM2PR21CA0039.namprd21.prod.outlook.com (25.161.137.177) To CY1PR03MB1519.namprd03.prod.outlook.com (25.163.17.25) X-Microsoft-Exchange-Diagnostics-untrusted: 1;CY1PR03MB1519;2:mTCHCQz44qtdRhkWAkgJTmVgC99xIkhF7+fm6GS2yrikuIxgQchP2WlaD7CQPuP/;3:Qs0liKw0rSpQAP5eg8+qS8bJfkBOnUjLYiP4y2oIMDvHqJX5ASHEJpxKK17a2IZnygoscY0ixFJEQLWModquL+4of/KLViJXh1t2d66mZNpSR9yXQIYSWYtXakwFRLZ90W+WHJ8x+Tasog16vxx6xw==;25:s4HPTsKF+Zn8hPXMSLsaeqAoKRUHYPk4GW3sYErTb0RbPDvx32B/ClstzyztS67II2tu74TxteSWtGMbUPdcBRVCfZ9jp/GChoUOZVkGfTjpxJCBlBRlVJ2wyU4CkbM1nSvj9Yxf4UcvY2knb5e+KnfnGytZ6Sbo42rfArII3L0+Wwbozd+gV5YzZRBgdQI4yo5o7itECrzx0w3LgFdXV+i4nK4fjJH8UHu7x9nkDUzjItsDQjWYXSNs8CGezA5X;20:zdo+Wa682aaLDHSImkInKMziovTvs1Q+CLT5/n+J3b7XaPgQAxsjXpbCFFlc4W1ZmjeswX/DZy7F2qhB1pFw+daFbMbWRuiYzwh7xR0AnT/dzZv+ZPFeFxOjVfA6vEQMco+i++z1yZp8BfqjRvWSvdSd8Q4biHLg0cZHWhpQAJY=;4:Dzd3zmEpWEVHA0SlMxXz0UuXA/mFSA0CDM+Qla0juuEnIPOsj6VDkvvzyKWH8csylvLEFQMMz4N3mFpVA3LHBomZ+/5Uqt2P4qxW4aa+Gh5oNZCvu2+eS4WuinXO1NKPq/5Bh4yViVbWoQJ1LT9EBsnJwsD+vKxzSlrZ4Nxhp01aTKqk/rS0u4xOSfbEMW0MzKAclJQ8m8lf/tIN9YTw0e7yMIrLWc38MwKfMNuUxsZKpN3yvZbMQP1GVAg0Q3vYRKdSVaEvuCSXd6IzIf/B02JDSWQhuEBnf3kmR/xinFc= X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:CY1PR03MB1519;UriScan:;BCL:0;PCL:0;RULEID:;SRVR:BY2PR03MB297; CY1PR03MB1519: X-MS-Exchange-Organization-RulesExecuted X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:;UriScan:; X-Exchange-Antispam-Report-CFA-Test: BCL:0;PCL:0;RULEID:(601004)(5005006)(3002001);SRVR:CY1PR03MB1519;BCL:0;PCL:0;RULEID:;SRVR:CY1PR03MB1519;BCL:0;PCL:0;RULEID:(601004)(5005006)(3002001);SRVR:BY2PR03MB297;BCL:0;PCL:0;RULEID:;SRVR:BY2PR03MB297; X-Forefront-PRVS: 06400060E1 X-Forefront-Antispam-Report-Untrusted: SFV:NSPM;SFS:(10009020)(6009001)(42186005)(19580405001)(19580395003)(229853001)(53416004)(46102003)(87976001)(122386002)(2201001)(86362001)(575784001)(86152002)(33646002)(62966003)(50466002)(77156002)(92566002)(15975445007)(5001960100002)(2950100001)(48376002)(50226001)(107886002)(77096005)(5001770100001)(76176999)(47776003)(50986999)(5001920100001)(5003940100001)(189998001)(7059030)(4001430100001)(2101003);DIR:OUT;SFP:1101;SCL:1;SRVR:CY1PR03MB1519;H:linuxheads99.altera.com;FPR:;SPF:None;MLV:sfv;LANG:en; X-Microsoft-Exchange-Diagnostics-untrusted: =?us-ascii?Q?1;CY1PR03MB1519;23:Jrq6Kzg/heVopqDc1zzPMosQNF3hgTsngsf9t7iv0?= =?us-ascii?Q?3JNKX6IuL7EePduRKcZ/QzXe6N0YQFBYIOjZ18eggKOak5CeeYkHX4muOCua?= =?us-ascii?Q?VoD/NmfGt9PClK0gJhgnPkFwyLtlu2onXc8y1UPJXou9wxDoXqyNSssPqr3/?= =?us-ascii?Q?6sB0O6CZRLvYYEM6b6c9ZvEh/cetR/kZBazuuQEEYZP8SGpuADGYkw1b5ZWg?= =?us-ascii?Q?FdzqvmB01RKvTcshnCa3L4ZXhjSDAxpFLeutPJ95+/n0rE4G0pTtpd44LoFK?= =?us-ascii?Q?DplkKb1MCIPiyrEti/MuJbzlzrS2DmykxoKZ68Dz1QRBIZLWZWZ+uaRUb48B?= =?us-ascii?Q?tuDChQNKi9YHDsN6VqmmTyC8OLxKoUV9Q6TD4J9OV4ALTpgv5xc/8jFrL4fA?= =?us-ascii?Q?e/4wApCzXE4RReiTlLTDm1Dvpjz+1xfoDNRgFHbdbTo4xAbYygO2LVB/0qw3?= =?us-ascii?Q?o3OvrL1ASQuPiblXGB9HGnd3qcOaMYrQftUNufSD11whLRpLjY2T5c1zcA1x?= =?us-ascii?Q?cHBQy9b2hiSB/+pxhpZ55gIQuMJ/u313eCYxF+5YOSHzsUoUeZQB9wGGznsg?= =?us-ascii?Q?rrvo+e+ZX4UjTiy19ki2BgzjWDj84sr1ddU4hoG0rRKlOYE5Dek10yLHq/xc?= =?us-ascii?Q?2VZkppiOUHVNHE7o4NIw68gq4kxjpItQyVeIflXFQSwNmTt74dtPp3eSY5BT?= =?us-ascii?Q?V/rjsjLTnzEGrc7ntyJH4qn3zM1EzHYZKs1XYGbCTQ7ONO7zqLPu1gPgzC86?= =?us-ascii?Q?EFqGDqoMC8yixryhkoVEQOTk9EsFS3rkqq4SAf05HdlsSWgeNI67NbNY45N1?= =?us-ascii?Q?qjtVPs2uhysj+syg2f1SskyMxlPe8lYRySphY3TUrv8WfgoqsG3iSu7Tn4uy?= =?us-ascii?Q?Pvhpg7otYwSL4asgIu7Y9+BFDkbMgBV+qiUf9kX5QaOofk3SQFLXiJdhCN3Q?= =?us-ascii?Q?WD5q+InU3r4C6DP5vwxoahcfKzq+TwUdw539nJjzQ=3D=3D?= X-Microsoft-Exchange-Diagnostics-untrusted: 1;CY1PR03MB1519;5:vFoI0TVShza1G3EJzHmJY8RznUthgZanfEh6KrBruoS/VW2E1uvafI6deT8nbjbtFS+11C7kyw7Atks8jTQ0gzmzvmicQJvbM8VNloFngcUJe+0uIINi7EnDUyYLZEZsiPpPKCxB1Ww+hSe92Qqnew==;24:86aT+ZDr4NjyaLHsWsDCQS4SN9d+iG/LavTQ1JQrL3andGjLaR1LaSf2IdANRPMdJXvHMahPdB/ukH6zXo9o5FzHPqgJNrJpLZmbFVkxj68=;20:I4Yy7zhg4X86nx+S3dPdZikNIRChM9fQEymFfQZgofSSSUmWPKpSZOojQJwS6J0tNXvW+mWnStS2EPj7/FJ4l2Ab1KliwGSSY1I9KlPILkz7pLAcc+z1Pq0hReEH3fewTrAyWaHP7wFWMED5dcTOCRWU0TDpjbwg05Hv6AnsVKM= X-MS-Exchange-Transport-CrossTenantHeadersStamped: CY1PR03MB1519 X-EOPAttributedMessage: 0 X-MS-Exchange-Transport-CrossTenantHeadersStripped: BN1AFFO11FD021.protection.gbl X-Microsoft-Exchange-Diagnostics: 1;BN1AFFO11FD021;1:cpx67P021ektBI15T8MHehuQ7SYBrQnVHAmdGxsNLgGEYvjybZPZbP7KrTp3mMKExNoS5QW+10PcUVUf0SQjd43IHswOaOA5MpuWy4EsBVLCCU89rr5tpAK/LiHqgdAa+ShRJ2YPXxBRWRY5M7EAwhzIKelwyHbWkhv89bMTr060Yja29Fn/ES22mx3ON16GrCligXLgxAMbRC1SuaHWzDDoUAC7R0GwzvgW1Wn18tOJ+cp7CJWKtHTGefPWEtQAFc5B7NQ5icw6hn+EgUi+ILaDoynZQjHuHW9cyo65GEoU3N2U+Acyo0axOJ7I0NXKtE52xykbI1Q4FgpuaSDm5JvVvuJEr0gHj7u8MUFgXgRGX1hMxIiMJEzwbNoxkXvD+d+iXSawU9479UZXptwOmzEWA366SC4soUMipG6rJfa3Lw6kLN/FHcVgxpzBBOiu X-Forefront-Antispam-Report: CIP:66.35.236.227;CTRY:US;IPV:NLI;EFV:NLI;SFV:NSPM;SFS:(10009020)(6009001)(2980300002)(339900001)(189002)(199003)(76176999)(53416004)(87936001)(122386002)(105606002)(106466001)(85426001)(6806004)(50226001)(5003940100001)(15975445007)(92566002)(2950100001)(77156002)(86362001)(575784001)(77096005)(5001960100002)(107886002)(19580395003)(16796002)(19580405001)(62966003)(189998001)(5001770100001)(5001920100001)(2201001)(229853001)(50986999)(46102003)(47776003)(86152002)(50466002)(33646002)(48376002)(7099028)(7059030)(2101003)(4001430100001);DIR:OUT;SFP:1101;SCL:1;SRVR:BY2PR03MB297;H:sj-itexedge03.altera.priv.altera.com;FPR:;SPF:Fail;MLV:sfv;MX:1;A:0;LANG:en; X-Microsoft-Exchange-Diagnostics: 1;BY2PR03MB297;2:9e3TqpDPalQ8crjvLF7n4MDeCK64fQ09XP6OzKjADXe88kBVwdWA5hHET/zX9+w8;3:c5c6cAO32SUhyb+BnUrCCuQ7AxhuagGb1J159JpUUf3UDNEm2rGlUirG6yc6EBsJPZz/Vh8p59C0tjM5H0BD6V171toB8oQwDdZUxR0a8aFMWQeBokV10aByAMyMk1yX3fZb/bp84J4AAHGrnLKLcqCTErKHNSPz1qLQmNjQ1HekCYUoBThcUmZeRJtikP3JOWGwvxC1uFmJGn1dz2cnXS32toV6K1fpH/AIs/Gi93I=;25:3vdNsNE7RGLA/oOsd1j+jlaVQ2NbdrjyT/VKjjIDR4g67K+rvh9m3robBhkDQOOFKKsH5EFjSWbpHKCUSpCzhaxl00cNYjlwNByvDsax/MaYyCi/gqaivZ2kJalLSFGSOp3Wc3OQiUrkEIoPPU2wLHDdlDQ7SSLQYbrBQrEl0Bs3kqV6TVh59k0fB/wibsMpqIeCqybbYJG3RYB90oFSB7rEF6AOjJ8cD0FjJVfT6xSlYp3wMfTo2dgWKHax84ua;20:f5VH9AeEguoH3y2RtmhmOEz/psBVhvECiWrM4+5rMlIYEYHSBBryZr1+2986ZIFvsDw9FADhURvtRzeGvy3Rh7V1fZCbQcr/5ieWD/XEj3pMVMR20agjSM2Nq2NQqmPOL0kc2CRQORB+wlZ3B8kRbDwNhM3AYQDqNEj1dk6hux0= BY2PR03MB297: X-MS-Exchange-Organization-RulesExecuted X-Microsoft-Exchange-Diagnostics: 1;BY2PR03MB297;4:xAHvNgR4Qs+g6d91bX3SFSIv8MbaTFYoXNBjX40zj0oxDn//X1lkqfCb4OsM67tSh2hn+P1NDVUWdcLF7xItrT7SM/QhMxtJqOMDEAWtzGWtkojL2xedC0YvQmtUmfn6J0edzURRBRYgOb8oJpRaYkQwBN6NA0WSmRtp3oSN3SGrCgzNm1uu76Uhs6qb4i+hcvqKGB67ypGuQyMPvPTJt3bXCZ4WHv3d0hWk8PLuVv5AOUOoJBm6CkxPLhqfIilE+kgemLLQ1sD+/wZxNyJUNxayOwUMPJpzQ5mdqq30oac= X-Forefront-PRVS: 06400060E1 X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1;BY2PR03MB297;23:fpATDoENwkiTO63saY4wcGJauV5UrAMCuJLNh2CM9p?= =?us-ascii?Q?rUuLff7MFwss3FVoeRhmMAir3dxvVGtcedIZmiifXn6oDnwkWa67RPO2/BQ3?= =?us-ascii?Q?74SOp2zEUhsB+EEgESzjeXqexpEexFTJ/rQv1HXUeJdUAU3+SkuJ5mA5FD/O?= =?us-ascii?Q?mDK5AXTeEx0NCIR2pca6vQPTsOyRyAUozXzOrVxXU4le8NS0kni+gUQnlQyt?= =?us-ascii?Q?RezrcthGAGbeN5lZhmxJt7sB+aOw0II52jb8JEK/Hypef7OSnd1F8a0ZoYl+?= =?us-ascii?Q?tTznikap7rl+frBaHNjMpAlZVjtmofu58QUnwSGaApY2aKs8+dthq3COnT/h?= =?us-ascii?Q?6FsEt3TMKPjX/Cr5q8xjQnXAeVaSi35XWuOVJr7OXoBKkZQRzVVPLbWwU5vz?= =?us-ascii?Q?qmZ+f9edjYEM+ntXD2BZTdsNfeKaGQsJMezRdysBATJ7Y47ZS9CNR/KUWr8T?= =?us-ascii?Q?f4FjfoJMshT+OnWm7x4qYgW58xKT45td66E7QLiLWKzi5wWUw/sBJE26uyKa?= =?us-ascii?Q?I28E8pBiNXy5rfJ3VgcNOG8eIxNYyyvAHqHscD8xVvqI868ya3Tfr6p9Is8H?= =?us-ascii?Q?07ZY/IOcmGe85qy0CctsB6lMGppBpzto8/KcZB9NrhB/XNaFTTBLWMPsWW1d?= =?us-ascii?Q?0j/czTSuC5G7EixO4GXg+UFzbCZ0GBVBA69F/r0Y+aS01Y9FJvcKEnM94g65?= =?us-ascii?Q?nOTf7jxjdiOPIThlxYWnKF8MP01tt/FYcR7GNAnDWwiLd3YcxmcSrNYEbKIL?= =?us-ascii?Q?aYnsQ1sMPHtz6ZUJd7Tz6ARvdiRXEmbyEICDQsPbww4gAmVoCIP/lpXXLsCJ?= =?us-ascii?Q?na5wgA1FV9h9WOhkvjIl1UkzrZJNaGYtVWQpfGfLIDT4Gq9aXgaTK5ORx0pN?= =?us-ascii?Q?ELtIMxbcpZCqREbn2DMrtKkna4Mug9TmiiYOy13IzZMln19CX0H61i7+7V7/?= =?us-ascii?Q?/xb7VBNbbmecgAvexQgtM+RVNI1T8SrIMfw73UYUR2FN6cefoKlE7s/fIscW?= =?us-ascii?Q?7cBwSanU6xUzRzwO4heG3Uaze5XvfDwCirRHy3hXN4OrzBZP1hnCMLmPUv/5?= =?us-ascii?Q?I15isbQ+12UEedBXy5VDyxisEl7oMkp7YPZ/TOyA6hrrwr+bY+xZ50AA6LiD?= =?us-ascii?Q?iTdxqFi/7U8Hx3i3m8wqnAyv81jcBzeBOOnVERWw16CYv4cBRpoA=3D=3D?= X-Microsoft-Exchange-Diagnostics: 1;BY2PR03MB297;5:j5bAY1vKSvA7ZmAz9+EU1ZipKEvfr52XXpeuGEm4mcQcN3gizZ3V4yPhAPvQHLsAu+N5EBHj4gdOz6B9fZ8GyJO6zV0Qnh7pF5R9zhWe5N5Zi7CQER/ig4rmE9NFXTCcrnCQ1hJ7ttraMzLzZXtaEA==;24:SVbNydhCby28xJG6PE0e/hEDWxH6g5gOEq+H3WQ85L6IeVt9oDeOYay05tvXfR5gGqiBt+VognBbQitA+DsiZVrN/aYyoW7wjbuYiLbDHRE=;20:f6oL4p0CJ9XcNpoZG5EBMa1AaiUdyoovXU+7kIhL6M+VZW/sIKTQhU5/QZid5EYaaVqYya0Om1ImyzcIMYvLXFxIKeJ6w/y3iCJeqxEofpnMFXdZZVKhmsPcKLhTy4Hj8hM0J81nhQKoLk8w9oUTc9nmGHRs+/FtgTZ9G+WHIKQ= X-OriginatorOrg: opensource.altera.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 17 Jul 2015 15:56:37.3898 (UTC) X-MS-Exchange-CrossTenant-Id: fbd72e03-d4a5-4110-adce-614d51f2077a X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=fbd72e03-d4a5-4110-adce-614d51f2077a;Ip=[66.35.236.227];Helo=[sj-itexedge03.altera.priv.altera.com] X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: BY2PR03MB297 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 21419 Lines: 710 From: Alan Tull Add driver to fpga manager framework to allow configuration of FPGA in Altera SoCFPGA parts. Signed-off-by: Alan Tull Acked-by: Michal Simek --- v2: fpga_manager struct now contains struct device fpga_manager_register parameters now take device v3: skip a version to align versions v4: move to drivers/staging v5: fix array_size.cocci warnings fix platform_no_drv_owner.cocci warnings Remove .owner = THIS_MODULE include asm/irq.h clean up list of includes use altera_fpga_reset for ops use enum fpga_mgr_states or u32 as needed use devm_request_irq check irq <= 0 instead of == NO_IRQ Use ARRAY_SIZE rename altera -> socfpga static const socfpga_fpga_ops header moved to linux/fpga/ folder remove ifdef'ed code use platform_get_resource and platform_get_irq move .probe and .remove lines adjacent use module_platform_driver use __maybe_unused only need to 'if (IS_ENABLED(CONFIG_REGULATOR))' in one fn fix "unsigned 'mode' is never < 0" v6: return error for (unused) default of case statement v7: PTR_ERR should access the value just tested by IS_ERR v8: change compatible string to be more chip specific v9: update copyright year remove suspend/resume support and regulators use updated fn names for register/unregister use updated params for write_init check for partial reconfiguration request --- drivers/staging/fpga/Kconfig | 6 + drivers/staging/fpga/Makefile | 1 + drivers/staging/fpga/socfpga.c | 616 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 623 insertions(+) create mode 100644 drivers/staging/fpga/socfpga.c diff --git a/drivers/staging/fpga/Kconfig b/drivers/staging/fpga/Kconfig index 8d003e3..36dd7b6 100644 --- a/drivers/staging/fpga/Kconfig +++ b/drivers/staging/fpga/Kconfig @@ -13,6 +13,12 @@ config FPGA if FPGA +config FPGA_MGR_SOCFPGA + bool "Altera SOCFPGA FPGA Manager" + depends on ARCH_SOCFPGA + help + FPGA manager driver support for Altera SOCFPGA. + config SIMPLE_FPGA_BUS bool "Simple FPGA Bus" depends on OF diff --git a/drivers/staging/fpga/Makefile b/drivers/staging/fpga/Makefile index 6115213..d1f9406 100644 --- a/drivers/staging/fpga/Makefile +++ b/drivers/staging/fpga/Makefile @@ -7,3 +7,4 @@ obj-$(CONFIG_FPGA) += fpga-mgr.o obj-$(CONFIG_SIMPLE_FPGA_BUS) += simple-fpga-bus.o # FPGA Manager Drivers +obj-$(CONFIG_FPGA_MGR_SOCFPGA) += socfpga.o diff --git a/drivers/staging/fpga/socfpga.c b/drivers/staging/fpga/socfpga.c new file mode 100644 index 0000000..38276f9 --- /dev/null +++ b/drivers/staging/fpga/socfpga.c @@ -0,0 +1,616 @@ +/* + * FPGA Manager Driver for Altera SOCFPGA + * + * Copyright (C) 2013-2015 Altera Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Register offsets */ +#define SOCFPGA_FPGMGR_STAT_OFST 0x0 +#define SOCFPGA_FPGMGR_CTL_OFST 0x4 +#define SOCFPGA_FPGMGR_DCLKCNT_OFST 0x8 +#define SOCFPGA_FPGMGR_DCLKSTAT_OFST 0xc +#define SOCFPGA_FPGMGR_GPIO_INTEN_OFST 0x830 +#define SOCFPGA_FPGMGR_GPIO_INTMSK_OFST 0x834 +#define SOCFPGA_FPGMGR_GPIO_INTTYPE_LEVEL_OFST 0x838 +#define SOCFPGA_FPGMGR_GPIO_INT_POL_OFST 0x83c +#define SOCFPGA_FPGMGR_GPIO_INTSTAT_OFST 0x840 +#define SOCFPGA_FPGMGR_GPIO_RAW_INTSTAT_OFST 0x844 +#define SOCFPGA_FPGMGR_GPIO_PORTA_EOI_OFST 0x84c +#define SOCFPGA_FPGMGR_GPIO_EXT_PORTA_OFST 0x850 + +/* Register bit defines */ +/* SOCFPGA_FPGMGR_STAT register mode field values */ +#define SOCFPGA_FPGMGR_STAT_POWER_UP 0x0 /*ramping*/ +#define SOCFPGA_FPGMGR_STAT_RESET 0x1 +#define SOCFPGA_FPGMGR_STAT_CFG 0x2 +#define SOCFPGA_FPGMGR_STAT_INIT 0x3 +#define SOCFPGA_FPGMGR_STAT_USER_MODE 0x4 +#define SOCFPGA_FPGMGR_STAT_UNKNOWN 0x5 +#define SOCFPGA_FPGMGR_STAT_STATE_MASK 0x7 +/* This is a flag value that doesn't really happen in this register field */ +#define SOCFPGA_FPGMGR_STAT_POWER_OFF 0x0 + +#define MSEL_PP16_FAST_NOAES_NODC 0x0 +#define MSEL_PP16_FAST_AES_NODC 0x1 +#define MSEL_PP16_FAST_AESOPT_DC 0x2 +#define MSEL_PP16_SLOW_NOAES_NODC 0x4 +#define MSEL_PP16_SLOW_AES_NODC 0x5 +#define MSEL_PP16_SLOW_AESOPT_DC 0x6 +#define MSEL_PP32_FAST_NOAES_NODC 0x8 +#define MSEL_PP32_FAST_AES_NODC 0x9 +#define MSEL_PP32_FAST_AESOPT_DC 0xa +#define MSEL_PP32_SLOW_NOAES_NODC 0xc +#define MSEL_PP32_SLOW_AES_NODC 0xd +#define MSEL_PP32_SLOW_AESOPT_DC 0xe +#define SOCFPGA_FPGMGR_STAT_MSEL_MASK 0x000000f8 +#define SOCFPGA_FPGMGR_STAT_MSEL_SHIFT 3 + +/* SOCFPGA_FPGMGR_CTL register */ +#define SOCFPGA_FPGMGR_CTL_EN 0x00000001 +#define SOCFPGA_FPGMGR_CTL_NCE 0x00000002 +#define SOCFPGA_FPGMGR_CTL_NCFGPULL 0x00000004 + +#define CDRATIO_X1 0x00000000 +#define CDRATIO_X2 0x00000040 +#define CDRATIO_X4 0x00000080 +#define CDRATIO_X8 0x000000c0 +#define SOCFPGA_FPGMGR_CTL_CDRATIO_MASK 0x000000c0 + +#define SOCFPGA_FPGMGR_CTL_AXICFGEN 0x00000100 + +#define CFGWDTH_16 0x00000000 +#define CFGWDTH_32 0x00000200 +#define SOCFPGA_FPGMGR_CTL_CFGWDTH_MASK 0x00000200 + +/* SOCFPGA_FPGMGR_DCLKSTAT register */ +#define SOCFPGA_FPGMGR_DCLKSTAT_DCNTDONE_E_DONE 0x1 + +/* SOCFPGA_FPGMGR_GPIO_* registers share the same bit positions */ +#define SOCFPGA_FPGMGR_MON_NSTATUS 0x0001 +#define SOCFPGA_FPGMGR_MON_CONF_DONE 0x0002 +#define SOCFPGA_FPGMGR_MON_INIT_DONE 0x0004 +#define SOCFPGA_FPGMGR_MON_CRC_ERROR 0x0008 +#define SOCFPGA_FPGMGR_MON_CVP_CONF_DONE 0x0010 +#define SOCFPGA_FPGMGR_MON_PR_READY 0x0020 +#define SOCFPGA_FPGMGR_MON_PR_ERROR 0x0040 +#define SOCFPGA_FPGMGR_MON_PR_DONE 0x0080 +#define SOCFPGA_FPGMGR_MON_NCONFIG_PIN 0x0100 +#define SOCFPGA_FPGMGR_MON_NSTATUS_PIN 0x0200 +#define SOCFPGA_FPGMGR_MON_CONF_DONE_PIN 0x0400 +#define SOCFPGA_FPGMGR_MON_FPGA_POWER_ON 0x0800 +#define SOCFPGA_FPGMGR_MON_STATUS_MASK 0x0fff + +#define SOCFPGA_FPGMGR_NUM_SUPPLIES 3 +#define SOCFPGA_RESUME_TIMEOUT 3 + +/* In power-up order. Reverse for power-down. */ +static const char *supply_names[SOCFPGA_FPGMGR_NUM_SUPPLIES] __maybe_unused = { + "FPGA-1.5V", + "FPGA-1.1V", + "FPGA-2.5V", +}; + +struct socfpga_fpga_priv { + void __iomem *fpga_base_addr; + void __iomem *fpga_data_addr; + struct completion status_complete; + int irq; +}; + +struct cfgmgr_mode { + /* Values to set in the CTRL register */ + u32 ctrl; + + /* flag that this table entry is a valid mode */ + bool valid; +}; + +/* For SOCFPGA_FPGMGR_STAT_MSEL field */ +static struct cfgmgr_mode cfgmgr_modes[] = { + [MSEL_PP16_FAST_NOAES_NODC] = { CFGWDTH_16 | CDRATIO_X1, 1 }, + [MSEL_PP16_FAST_AES_NODC] = { CFGWDTH_16 | CDRATIO_X2, 1 }, + [MSEL_PP16_FAST_AESOPT_DC] = { CFGWDTH_16 | CDRATIO_X4, 1 }, + [MSEL_PP16_SLOW_NOAES_NODC] = { CFGWDTH_16 | CDRATIO_X1, 1 }, + [MSEL_PP16_SLOW_AES_NODC] = { CFGWDTH_16 | CDRATIO_X2, 1 }, + [MSEL_PP16_SLOW_AESOPT_DC] = { CFGWDTH_16 | CDRATIO_X4, 1 }, + [MSEL_PP32_FAST_NOAES_NODC] = { CFGWDTH_32 | CDRATIO_X1, 1 }, + [MSEL_PP32_FAST_AES_NODC] = { CFGWDTH_32 | CDRATIO_X4, 1 }, + [MSEL_PP32_FAST_AESOPT_DC] = { CFGWDTH_32 | CDRATIO_X8, 1 }, + [MSEL_PP32_SLOW_NOAES_NODC] = { CFGWDTH_32 | CDRATIO_X1, 1 }, + [MSEL_PP32_SLOW_AES_NODC] = { CFGWDTH_32 | CDRATIO_X4, 1 }, + [MSEL_PP32_SLOW_AESOPT_DC] = { CFGWDTH_32 | CDRATIO_X8, 1 }, +}; + +static u32 socfpga_fpga_readl(struct socfpga_fpga_priv *priv, u32 reg_offset) +{ + return readl(priv->fpga_base_addr + reg_offset); +} + +static void socfpga_fpga_writel(struct socfpga_fpga_priv *priv, u32 reg_offset, + u32 value) +{ + writel(value, priv->fpga_base_addr + reg_offset); +} + +static u32 socfpga_fpga_raw_readl(struct socfpga_fpga_priv *priv, + u32 reg_offset) +{ + return __raw_readl(priv->fpga_base_addr + reg_offset); +} + +static void socfpga_fpga_raw_writel(struct socfpga_fpga_priv *priv, + u32 reg_offset, u32 value) +{ + __raw_writel(value, priv->fpga_base_addr + reg_offset); +} + +static void socfpga_fpga_data_writel(struct socfpga_fpga_priv *priv, u32 value) +{ + writel(value, priv->fpga_data_addr); +} + +static inline void socfpga_fpga_set_bitsl(struct socfpga_fpga_priv *priv, + u32 offset, u32 bits) +{ + u32 val; + + val = socfpga_fpga_readl(priv, offset); + val |= bits; + socfpga_fpga_writel(priv, offset, val); +} + +static inline void socfpga_fpga_clr_bitsl(struct socfpga_fpga_priv *priv, + u32 offset, u32 bits) +{ + u32 val; + + val = socfpga_fpga_readl(priv, offset); + val &= ~bits; + socfpga_fpga_writel(priv, offset, val); +} + +static u32 socfpga_fpga_mon_status_get(struct socfpga_fpga_priv *priv) +{ + return socfpga_fpga_readl(priv, SOCFPGA_FPGMGR_GPIO_EXT_PORTA_OFST) & + SOCFPGA_FPGMGR_MON_STATUS_MASK; +} + +static u32 socfpga_fpga_state_get(struct socfpga_fpga_priv *priv) +{ + u32 status = socfpga_fpga_mon_status_get(priv); + + if ((status & SOCFPGA_FPGMGR_MON_FPGA_POWER_ON) == 0) + return SOCFPGA_FPGMGR_STAT_POWER_OFF; + + return socfpga_fpga_readl(priv, SOCFPGA_FPGMGR_STAT_OFST) & + SOCFPGA_FPGMGR_STAT_STATE_MASK; +} + +static void socfpga_fpga_clear_done_status(struct socfpga_fpga_priv *priv) +{ + socfpga_fpga_writel(priv, SOCFPGA_FPGMGR_DCLKSTAT_OFST, + SOCFPGA_FPGMGR_DCLKSTAT_DCNTDONE_E_DONE); +} + +/* + * Set the DCLKCNT, wait for DCLKSTAT to report the count completed, and clear + * the complete status. + */ +static int socfpga_fpga_dclk_set_and_wait_clear(struct socfpga_fpga_priv *priv, + u32 count) +{ + int timeout = 2; + u32 done; + + /* Clear any existing DONE status. */ + if (socfpga_fpga_readl(priv, SOCFPGA_FPGMGR_DCLKSTAT_OFST)) + socfpga_fpga_clear_done_status(priv); + + /* Issue the DCLK count. */ + socfpga_fpga_writel(priv, SOCFPGA_FPGMGR_DCLKCNT_OFST, count); + + /* Poll DCLKSTAT to see if it completed in the timeout period. */ + do { + done = socfpga_fpga_readl(priv, SOCFPGA_FPGMGR_DCLKSTAT_OFST); + if (done == SOCFPGA_FPGMGR_DCLKSTAT_DCNTDONE_E_DONE) { + socfpga_fpga_clear_done_status(priv); + return 0; + } + udelay(1); + } while (timeout--); + + return -ETIMEDOUT; +} + +static int socfpga_fpga_wait_for_state(struct socfpga_fpga_priv *priv, + u32 state) +{ + int timeout = 2; + + /* + * HW doesn't support an interrupt for changes in state, so poll to see + * if it matches the requested state within the timeout period. + */ + do { + if ((socfpga_fpga_state_get(priv) & state) != 0) + return 0; + msleep(20); + } while (timeout--); + + return -ETIMEDOUT; +} + +static void socfpga_fpga_enable_irqs(struct socfpga_fpga_priv *priv, u32 irqs) +{ + /* set irqs to level sensitive */ + socfpga_fpga_writel(priv, SOCFPGA_FPGMGR_GPIO_INTTYPE_LEVEL_OFST, 0); + + /* set interrupt polarity */ + socfpga_fpga_writel(priv, SOCFPGA_FPGMGR_GPIO_INT_POL_OFST, irqs); + + /* clear irqs */ + socfpga_fpga_writel(priv, SOCFPGA_FPGMGR_GPIO_PORTA_EOI_OFST, irqs); + + /* unmask interrupts */ + socfpga_fpga_writel(priv, SOCFPGA_FPGMGR_GPIO_INTMSK_OFST, 0); + + /* enable interrupts */ + socfpga_fpga_writel(priv, SOCFPGA_FPGMGR_GPIO_INTEN_OFST, irqs); +} + +static void socfpga_fpga_disable_irqs(struct socfpga_fpga_priv *priv) +{ + socfpga_fpga_writel(priv, SOCFPGA_FPGMGR_GPIO_INTEN_OFST, 0); +} + +static irqreturn_t socfpga_fpga_isr(int irq, void *dev_id) +{ + struct socfpga_fpga_priv *priv = dev_id; + u32 irqs, st; + bool conf_done, nstatus; + + /* clear irqs */ + irqs = socfpga_fpga_raw_readl(priv, SOCFPGA_FPGMGR_GPIO_INTSTAT_OFST); + + socfpga_fpga_raw_writel(priv, SOCFPGA_FPGMGR_GPIO_PORTA_EOI_OFST, irqs); + + st = socfpga_fpga_raw_readl(priv, SOCFPGA_FPGMGR_GPIO_EXT_PORTA_OFST); + conf_done = (st & SOCFPGA_FPGMGR_MON_CONF_DONE) != 0; + nstatus = (st & SOCFPGA_FPGMGR_MON_NSTATUS) != 0; + + /* success */ + if (conf_done && nstatus) { + /* disable irqs */ + socfpga_fpga_raw_writel(priv, + SOCFPGA_FPGMGR_GPIO_INTEN_OFST, 0); + complete(&priv->status_complete); + } + + return IRQ_HANDLED; +} + +static int socfpga_fpga_wait_for_config_done(struct socfpga_fpga_priv *priv) +{ + int timeout, ret = 0; + + socfpga_fpga_disable_irqs(priv); + init_completion(&priv->status_complete); + socfpga_fpga_enable_irqs(priv, SOCFPGA_FPGMGR_MON_CONF_DONE); + + timeout = wait_for_completion_interruptible_timeout( + &priv->status_complete, + msecs_to_jiffies(10)); + if (timeout == 0) + ret = -ETIMEDOUT; + + socfpga_fpga_disable_irqs(priv); + return ret; +} + +static int socfpga_fpga_cfg_mode_get(struct socfpga_fpga_priv *priv) +{ + u32 msel; + + msel = socfpga_fpga_readl(priv, SOCFPGA_FPGMGR_STAT_OFST); + msel &= SOCFPGA_FPGMGR_STAT_MSEL_MASK; + msel >>= SOCFPGA_FPGMGR_STAT_MSEL_SHIFT; + + /* Check that this MSEL setting is supported */ + if ((msel >= ARRAY_SIZE(cfgmgr_modes)) || !cfgmgr_modes[msel].valid) + return -EINVAL; + + return msel; +} + +static int socfpga_fpga_cfg_mode_set(struct socfpga_fpga_priv *priv) +{ + u32 ctrl_reg; + int mode; + + /* get value from MSEL pins */ + mode = socfpga_fpga_cfg_mode_get(priv); + if (mode < 0) + return mode; + + /* Adjust CTRL for the CDRATIO */ + ctrl_reg = socfpga_fpga_readl(priv, SOCFPGA_FPGMGR_CTL_OFST); + ctrl_reg &= ~SOCFPGA_FPGMGR_CTL_CDRATIO_MASK; + ctrl_reg &= ~SOCFPGA_FPGMGR_CTL_CFGWDTH_MASK; + ctrl_reg |= cfgmgr_modes[mode].ctrl; + + /* Set NCE to 0. */ + ctrl_reg &= ~SOCFPGA_FPGMGR_CTL_NCE; + socfpga_fpga_writel(priv, SOCFPGA_FPGMGR_CTL_OFST, ctrl_reg); + + return 0; +} + +static int socfpga_fpga_reset(struct fpga_manager *mgr) +{ + struct socfpga_fpga_priv *priv = mgr->priv; + u32 ctrl_reg, status; + int ret; + + /* + * Step 1: + * - Set CTRL.CFGWDTH, CTRL.CDRATIO to match cfg mode + * - Set CTRL.NCE to 0 + */ + ret = socfpga_fpga_cfg_mode_set(priv); + if (ret) + return ret; + + /* Step 2: Set CTRL.EN to 1 */ + socfpga_fpga_set_bitsl(priv, SOCFPGA_FPGMGR_CTL_OFST, + SOCFPGA_FPGMGR_CTL_EN); + + /* Step 3: Set CTRL.NCONFIGPULL to 1 to put FPGA in reset */ + ctrl_reg = socfpga_fpga_readl(priv, SOCFPGA_FPGMGR_CTL_OFST); + ctrl_reg |= SOCFPGA_FPGMGR_CTL_NCFGPULL; + socfpga_fpga_writel(priv, SOCFPGA_FPGMGR_CTL_OFST, ctrl_reg); + + /* Step 4: Wait for STATUS.MODE to report FPGA is in reset phase */ + status = socfpga_fpga_wait_for_state(priv, SOCFPGA_FPGMGR_STAT_RESET); + + /* Step 5: Set CONTROL.NCONFIGPULL to 0 to release FPGA from reset */ + ctrl_reg &= ~SOCFPGA_FPGMGR_CTL_NCFGPULL; + socfpga_fpga_writel(priv, SOCFPGA_FPGMGR_CTL_OFST, ctrl_reg); + + /* Timeout waiting for reset */ + if (status) + return -ETIMEDOUT; + + return 0; +} + +/* + * Prepare the FPGA to receive the configuration data. + */ +static int socfpga_fpga_ops_configure_init(struct fpga_manager *mgr, u32 flags, + const char *buf, size_t count) +{ + struct socfpga_fpga_priv *priv = mgr->priv; + int ret; + + if (flags & FPGA_MGR_PARTIAL_RECONFIG) { + dev_err(&mgr->dev, "Partial reconfiguration not supported.\n"); + return -EINVAL; + } + /* Steps 1 - 5: Reset the FPGA */ + ret = socfpga_fpga_reset(mgr); + if (ret) + return ret; + + /* Step 6: Wait for FPGA to enter configuration phase */ + if (socfpga_fpga_wait_for_state(priv, SOCFPGA_FPGMGR_STAT_CFG)) + return -ETIMEDOUT; + + /* Step 7: Clear nSTATUS interrupt */ + socfpga_fpga_writel(priv, SOCFPGA_FPGMGR_GPIO_PORTA_EOI_OFST, + SOCFPGA_FPGMGR_MON_NSTATUS); + + /* Step 8: Set CTRL.AXICFGEN to 1 to enable transfer of config data */ + socfpga_fpga_set_bitsl(priv, SOCFPGA_FPGMGR_CTL_OFST, + SOCFPGA_FPGMGR_CTL_AXICFGEN); + + return 0; +} + +/* + * Step 9: write data to the FPGA data register + */ +static int socfpga_fpga_ops_configure_write(struct fpga_manager *mgr, + const char *buf, size_t count) +{ + struct socfpga_fpga_priv *priv = mgr->priv; + u32 *buffer_32 = (u32 *)buf; + size_t i = 0; + + if (count <= 0) + return -EINVAL; + + /* Write out the complete 32-bit chunks. */ + while (count >= sizeof(u32)) { + socfpga_fpga_data_writel(priv, buffer_32[i++]); + count -= sizeof(u32); + } + + /* Write out remaining non 32-bit chunks. */ + switch (count) { + case 3: + socfpga_fpga_data_writel(priv, buffer_32[i++] & 0x00ffffff); + break; + case 2: + socfpga_fpga_data_writel(priv, buffer_32[i++] & 0x0000ffff); + break; + case 1: + socfpga_fpga_data_writel(priv, buffer_32[i++] & 0x000000ff); + break; + case 0: + break; + default: + /* This will never happen. */ + return -EFAULT; + } + + return 0; +} + +static int socfpga_fpga_ops_configure_complete(struct fpga_manager *mgr) +{ + struct socfpga_fpga_priv *priv = mgr->priv; + u32 status; + + /* + * Step 10: + * - Observe CONF_DONE and nSTATUS (active low) + * - if CONF_DONE = 1 and nSTATUS = 1, configuration was successful + * - if CONF_DONE = 0 and nSTATUS = 0, configuration failed + */ + status = socfpga_fpga_wait_for_config_done(priv); + if (status) + return status; + + /* Step 11: Clear CTRL.AXICFGEN to disable transfer of config data */ + socfpga_fpga_clr_bitsl(priv, SOCFPGA_FPGMGR_CTL_OFST, + SOCFPGA_FPGMGR_CTL_AXICFGEN); + + /* + * Step 12: + * - Write 4 to DCLKCNT + * - Wait for STATUS.DCNTDONE = 1 + * - Clear W1C bit in STATUS.DCNTDONE + */ + if (socfpga_fpga_dclk_set_and_wait_clear(priv, 4)) + return -ETIMEDOUT; + + /* Step 13: Wait for STATUS.MODE to report USER MODE */ + if (socfpga_fpga_wait_for_state(priv, SOCFPGA_FPGMGR_STAT_USER_MODE)) + return -ETIMEDOUT; + + /* Step 14: Set CTRL.EN to 0 */ + socfpga_fpga_clr_bitsl(priv, SOCFPGA_FPGMGR_CTL_OFST, + SOCFPGA_FPGMGR_CTL_EN); + + return 0; +} + +/* Translate state register values to FPGA framework state */ +static const enum fpga_mgr_states socfpga_state_to_framework_state[] = { + [SOCFPGA_FPGMGR_STAT_POWER_OFF] = FPGA_MGR_STATE_POWER_OFF, + [SOCFPGA_FPGMGR_STAT_RESET] = FPGA_MGR_STATE_RESET, + [SOCFPGA_FPGMGR_STAT_CFG] = FPGA_MGR_STATE_WRITE_INIT, + [SOCFPGA_FPGMGR_STAT_INIT] = FPGA_MGR_STATE_WRITE_INIT, + [SOCFPGA_FPGMGR_STAT_USER_MODE] = FPGA_MGR_STATE_OPERATING, + [SOCFPGA_FPGMGR_STAT_UNKNOWN] = FPGA_MGR_STATE_UNKNOWN, +}; + +static enum fpga_mgr_states socfpga_fpga_ops_state(struct fpga_manager *mgr) +{ + struct socfpga_fpga_priv *priv = mgr->priv; + enum fpga_mgr_states ret; + u32 state; + + state = socfpga_fpga_state_get(priv); + + if (state < ARRAY_SIZE(socfpga_state_to_framework_state)) + ret = socfpga_state_to_framework_state[state]; + else + ret = FPGA_MGR_STATE_UNKNOWN; + + return ret; +} + +static const struct fpga_manager_ops socfpga_fpga_ops = { + .state = socfpga_fpga_ops_state, + .write_init = socfpga_fpga_ops_configure_init, + .write = socfpga_fpga_ops_configure_write, + .write_complete = socfpga_fpga_ops_configure_complete, +}; + +static int socfpga_fpga_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct socfpga_fpga_priv *priv; + struct resource *res; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->fpga_base_addr = devm_ioremap_resource(dev, res); + if (IS_ERR(priv->fpga_base_addr)) + return PTR_ERR(priv->fpga_base_addr); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + priv->fpga_data_addr = devm_ioremap_resource(dev, res); + if (IS_ERR(priv->fpga_data_addr)) + return PTR_ERR(priv->fpga_data_addr); + + priv->irq = platform_get_irq(pdev, 0); + if (priv->irq < 0) + return priv->irq; + + ret = devm_request_irq(dev, priv->irq, socfpga_fpga_isr, 0, + dev_name(dev), priv); + if (IS_ERR_VALUE(ret)) + return ret; + + return fpga_mgr_register(dev, "Altera SOCFPGA FPGA Manager", + &socfpga_fpga_ops, priv); +} + +static int socfpga_fpga_remove(struct platform_device *pdev) +{ + fpga_mgr_unregister(&pdev->dev); + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id socfpga_fpga_of_match[] = { + { .compatible = "altr,socfpga-fpga-mgr", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, socfpga_fpga_of_match); +#endif + +static struct platform_driver socfpga_fpga_driver = { + .probe = socfpga_fpga_probe, + .remove = socfpga_fpga_remove, + .driver = { + .name = "socfpga_fpga_manager", + .of_match_table = of_match_ptr(socfpga_fpga_of_match), + }, +}; + +module_platform_driver(socfpga_fpga_driver); + +MODULE_AUTHOR("Alan Tull "); +MODULE_DESCRIPTION("Altera SOCFPGA FPGA Manager"); +MODULE_LICENSE("GPL v2"); -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/