* [PATCH 0/2] FPGA Manager support for Arria10 @ 2016-07-12 19:07 Alan Tull 2016-07-12 19:07 ` [PATCH 1/2] ARM: socfpga: add bindings doc for arria10 fpga manager Alan Tull 2016-07-12 19:07 ` [PATCH 2/2] fpga-manager: Add Socfpga Arria10 support Alan Tull 0 siblings, 2 replies; 11+ messages in thread From: Alan Tull @ 2016-07-12 19:07 UTC (permalink / raw) To: linux-arm-kernel New patch submission for FPGA Manager support for the Altera SoCFPGA Arria10 plus device tree bindings. Alan Tull (2): ARM: socfpga: add bindings doc for arria10 fpga manager fpga-manager: Add Socfpga Arria10 support .../bindings/fpga/altera-socfpga-a10-fpga-mgr.txt | 19 + drivers/fpga/Kconfig | 6 + drivers/fpga/Makefile | 1 + drivers/fpga/socfpga-a10.c | 573 +++++++++++++++++++++ 4 files changed, 599 insertions(+) create mode 100644 Documentation/devicetree/bindings/fpga/altera-socfpga-a10-fpga-mgr.txt create mode 100644 drivers/fpga/socfpga-a10.c -- 2.9.1 ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 1/2] ARM: socfpga: add bindings doc for arria10 fpga manager 2016-07-12 19:07 [PATCH 0/2] FPGA Manager support for Arria10 Alan Tull @ 2016-07-12 19:07 ` Alan Tull 2016-07-16 22:06 ` Rob Herring 2016-07-17 20:40 ` Moritz Fischer 2016-07-12 19:07 ` [PATCH 2/2] fpga-manager: Add Socfpga Arria10 support Alan Tull 1 sibling, 2 replies; 11+ messages in thread From: Alan Tull @ 2016-07-12 19:07 UTC (permalink / raw) To: linux-arm-kernel Add a device tree bindings document for the SoCFPGA Arria10 FPGA Manager driver. Signed-off-by: Alan Tull <atull@opensource.altera.com> --- .../bindings/fpga/altera-socfpga-a10-fpga-mgr.txt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 Documentation/devicetree/bindings/fpga/altera-socfpga-a10-fpga-mgr.txt diff --git a/Documentation/devicetree/bindings/fpga/altera-socfpga-a10-fpga-mgr.txt b/Documentation/devicetree/bindings/fpga/altera-socfpga-a10-fpga-mgr.txt new file mode 100644 index 0000000..2fd8e7a --- /dev/null +++ b/Documentation/devicetree/bindings/fpga/altera-socfpga-a10-fpga-mgr.txt @@ -0,0 +1,19 @@ +Altera SOCFPGA Arria10 FPGA Manager + +Required properties: +- compatible : should contain "altr,socfpga-a10-fpga-mgr" +- reg : base address and size for memory mapped io. + - The first index is for FPGA manager register access. + - The second index is for writing FPGA configuration data. +- resets : Phandle and reset specifier for the device's reset. +- clocks : Clocks used by the device. + +Example: + + fpga_mgr: fpga-mgr at ffd03000 { + compatible = "altr,socfpga-a10-fpga-mgr"; + reg = <0xffd03000 0x100 + 0xffcfe400 0x20>; + clocks = <&l4_mp_clk>; + resets = <&rst FPGAMGR_RESET>; + }; -- 2.9.1 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 1/2] ARM: socfpga: add bindings doc for arria10 fpga manager 2016-07-12 19:07 ` [PATCH 1/2] ARM: socfpga: add bindings doc for arria10 fpga manager Alan Tull @ 2016-07-16 22:06 ` Rob Herring 2016-07-19 2:39 ` atull 2016-07-17 20:40 ` Moritz Fischer 1 sibling, 1 reply; 11+ messages in thread From: Rob Herring @ 2016-07-16 22:06 UTC (permalink / raw) To: linux-arm-kernel On Tue, Jul 12, 2016 at 02:07:08PM -0500, Alan Tull wrote: > Add a device tree bindings document for the SoCFPGA Arria10 > FPGA Manager driver. > > Signed-off-by: Alan Tull <atull@opensource.altera.com> > --- > .../bindings/fpga/altera-socfpga-a10-fpga-mgr.txt | 19 +++++++++++++++++++ > 1 file changed, 19 insertions(+) > create mode 100644 Documentation/devicetree/bindings/fpga/altera-socfpga-a10-fpga-mgr.txt Acked-by: Rob Herring <robh@kernel.org> ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 1/2] ARM: socfpga: add bindings doc for arria10 fpga manager 2016-07-16 22:06 ` Rob Herring @ 2016-07-19 2:39 ` atull 0 siblings, 0 replies; 11+ messages in thread From: atull @ 2016-07-19 2:39 UTC (permalink / raw) To: linux-arm-kernel On Sat, 16 Jul 2016, Rob Herring wrote: > On Tue, Jul 12, 2016 at 02:07:08PM -0500, Alan Tull wrote: > > Add a device tree bindings document for the SoCFPGA Arria10 > > FPGA Manager driver. > > > > Signed-off-by: Alan Tull <atull@opensource.altera.com> > > --- > > .../bindings/fpga/altera-socfpga-a10-fpga-mgr.txt | 19 +++++++++++++++++++ > > 1 file changed, 19 insertions(+) > > create mode 100644 Documentation/devicetree/bindings/fpga/altera-socfpga-a10-fpga-mgr.txt > > Acked-by: Rob Herring <robh@kernel.org> > Thanks! Alan ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 1/2] ARM: socfpga: add bindings doc for arria10 fpga manager 2016-07-12 19:07 ` [PATCH 1/2] ARM: socfpga: add bindings doc for arria10 fpga manager Alan Tull 2016-07-16 22:06 ` Rob Herring @ 2016-07-17 20:40 ` Moritz Fischer 2016-07-19 13:45 ` atull 1 sibling, 1 reply; 11+ messages in thread From: Moritz Fischer @ 2016-07-17 20:40 UTC (permalink / raw) To: linux-arm-kernel Acked-By: Moritz Fischer <moritz.fischer@ettus.com> On Tue, Jul 12, 2016 at 12:07 PM, Alan Tull <atull@opensource.altera.com> wrote: > Add a device tree bindings document for the SoCFPGA Arria10 > FPGA Manager driver. > > Signed-off-by: Alan Tull <atull@opensource.altera.com> > --- > .../bindings/fpga/altera-socfpga-a10-fpga-mgr.txt | 19 +++++++++++++++++++ > 1 file changed, 19 insertions(+) > create mode 100644 Documentation/devicetree/bindings/fpga/altera-socfpga-a10-fpga-mgr.txt > > diff --git a/Documentation/devicetree/bindings/fpga/altera-socfpga-a10-fpga-mgr.txt b/Documentation/devicetree/bindings/fpga/altera-socfpga-a10-fpga-mgr.txt > new file mode 100644 > index 0000000..2fd8e7a > --- /dev/null > +++ b/Documentation/devicetree/bindings/fpga/altera-socfpga-a10-fpga-mgr.txt > @@ -0,0 +1,19 @@ > +Altera SOCFPGA Arria10 FPGA Manager > + > +Required properties: > +- compatible : should contain "altr,socfpga-a10-fpga-mgr" > +- reg : base address and size for memory mapped io. > + - The first index is for FPGA manager register access. > + - The second index is for writing FPGA configuration data. > +- resets : Phandle and reset specifier for the device's reset. > +- clocks : Clocks used by the device. > + > +Example: > + > + fpga_mgr: fpga-mgr at ffd03000 { > + compatible = "altr,socfpga-a10-fpga-mgr"; > + reg = <0xffd03000 0x100 > + 0xffcfe400 0x20>; > + clocks = <&l4_mp_clk>; > + resets = <&rst FPGAMGR_RESET>; > + }; > -- > 2.9.1 > ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 1/2] ARM: socfpga: add bindings doc for arria10 fpga manager 2016-07-17 20:40 ` Moritz Fischer @ 2016-07-19 13:45 ` atull 0 siblings, 0 replies; 11+ messages in thread From: atull @ 2016-07-19 13:45 UTC (permalink / raw) To: linux-arm-kernel On Sun, 17 Jul 2016, Moritz Fischer wrote: > Acked-By: Moritz Fischer <moritz.fischer@ettus.com> Thanks Moritz! Alan > > On Tue, Jul 12, 2016 at 12:07 PM, Alan Tull <atull@opensource.altera.com> wrote: > > Add a device tree bindings document for the SoCFPGA Arria10 > > FPGA Manager driver. > > > > Signed-off-by: Alan Tull <atull@opensource.altera.com> > > --- > > .../bindings/fpga/altera-socfpga-a10-fpga-mgr.txt | 19 +++++++++++++++++++ > > 1 file changed, 19 insertions(+) > > create mode 100644 Documentation/devicetree/bindings/fpga/altera-socfpga-a10-fpga-mgr.txt > > > > diff --git a/Documentation/devicetree/bindings/fpga/altera-socfpga-a10-fpga-mgr.txt b/Documentation/devicetree/bindings/fpga/altera-socfpga-a10-fpga-mgr.txt > > new file mode 100644 > > index 0000000..2fd8e7a > > --- /dev/null > > +++ b/Documentation/devicetree/bindings/fpga/altera-socfpga-a10-fpga-mgr.txt > > @@ -0,0 +1,19 @@ > > +Altera SOCFPGA Arria10 FPGA Manager > > + > > +Required properties: > > +- compatible : should contain "altr,socfpga-a10-fpga-mgr" > > +- reg : base address and size for memory mapped io. > > + - The first index is for FPGA manager register access. > > + - The second index is for writing FPGA configuration data. > > +- resets : Phandle and reset specifier for the device's reset. > > +- clocks : Clocks used by the device. > > + > > +Example: > > + > > + fpga_mgr: fpga-mgr at ffd03000 { > > + compatible = "altr,socfpga-a10-fpga-mgr"; > > + reg = <0xffd03000 0x100 > > + 0xffcfe400 0x20>; > > + clocks = <&l4_mp_clk>; > > + resets = <&rst FPGAMGR_RESET>; > > + }; > > -- > > 2.9.1 > > > ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 2/2] fpga-manager: Add Socfpga Arria10 support 2016-07-12 19:07 [PATCH 0/2] FPGA Manager support for Arria10 Alan Tull 2016-07-12 19:07 ` [PATCH 1/2] ARM: socfpga: add bindings doc for arria10 fpga manager Alan Tull @ 2016-07-12 19:07 ` Alan Tull 2016-07-12 21:31 ` Moritz Fischer 1 sibling, 1 reply; 11+ messages in thread From: Alan Tull @ 2016-07-12 19:07 UTC (permalink / raw) To: linux-arm-kernel Add low level driver to support reprogramming FPGAs for Altera SoCFPGA Arria10. Signed-off-by: Alan Tull <atull@opensource.altera.com> --- drivers/fpga/Kconfig | 6 + drivers/fpga/Makefile | 1 + drivers/fpga/socfpga-a10.c | 573 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 580 insertions(+) create mode 100644 drivers/fpga/socfpga-a10.c diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig index b346166..1a18623 100644 --- a/drivers/fpga/Kconfig +++ b/drivers/fpga/Kconfig @@ -26,6 +26,12 @@ config FPGA_MGR_SOCFPGA help FPGA manager driver support for Altera SOCFPGA. +config FPGA_MGR_SOCFPGA_A10 + tristate "Altera SoCFPGA Arria10" + depends on ARCH_SOCFPGA + help + FPGA manager driver support for Altera Arria10 SoCFPGA. + config FPGA_MGR_ZYNQ_FPGA tristate "Xilinx Zynq FPGA" depends on HAS_DMA diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile index e658436..0375cbd 100644 --- a/drivers/fpga/Makefile +++ b/drivers/fpga/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_FPGA) += fpga-mgr.o # FPGA Manager Drivers obj-$(CONFIG_FPGA_MGR_SOCFPGA) += socfpga.o +obj-$(CONFIG_FPGA_MGR_SOCFPGA_A10) += socfpga-a10.o obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA) += zynq-fpga.o # FPGA Bridge Drivers diff --git a/drivers/fpga/socfpga-a10.c b/drivers/fpga/socfpga-a10.c new file mode 100644 index 0000000..63e0c5b --- /dev/null +++ b/drivers/fpga/socfpga-a10.c @@ -0,0 +1,573 @@ +/* + * FPGA Manager Driver for Altera Arria10 SoCFPGA + * + * Copyright (C) 2015-2016 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 <http://www.gnu.org/licenses/>. + */ + +#include <linux/clk.h> +#include <linux/device.h> +#include <linux/delay.h> +#include <linux/fpga/fpga-mgr.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of_address.h> +#include <linux/regmap.h> + +#define A10_FPGAMGR_DCLKCNT_OFST 0x08 +#define A10_FPGAMGR_DCLKSTAT_OFST 0x0c +#define A10_FPGAMGR_IMGCFG_CTL_00_OFST 0x70 +#define A10_FPGAMGR_IMGCFG_CTL_01_OFST 0x74 +#define A10_FPGAMGR_IMGCFG_CTL_02_OFST 0x78 +#define A10_FPGAMGR_IMGCFG_STAT_OFST 0x80 + +#define A10_FPGAMGR_DCLKSTAT_DCLKDONE BIT(0) + +#define A10_FPGAMGR_IMGCFG_CTL_00_S2F_NENABLE_NCONFIG BIT(0) +#define A10_FPGAMGR_IMGCFG_CTL_00_S2F_NENABLE_NSTATUS BIT(1) +#define A10_FPGAMGR_IMGCFG_CTL_00_S2F_NENABLE_CONDONE BIT(2) +#define A10_FPGAMGR_IMGCFG_CTL_00_S2F_NCONFIG BIT(8) +#define A10_FPGAMGR_IMGCFG_CTL_00_S2F_NSTATUS_OE BIT(16) +#define A10_FPGAMGR_IMGCFG_CTL_00_S2F_CONDONE_OE BIT(24) + +#define A10_FPGAMGR_IMGCFG_CTL_01_S2F_NENABLE_CONFIG BIT(0) +#define A10_FPGAMGR_IMGCFG_CTL_01_S2F_PR_REQUEST BIT(16) +#define A10_FPGAMGR_IMGCFG_CTL_01_S2F_NCE BIT(24) + +#define A10_FPGAMGR_IMGCFG_CTL_02_EN_CFG_CTRL BIT(0) +#define A10_FPGAMGR_IMGCFG_CTL_02_CDRATIO_MASK (BIT(16) | BIT(17)) +#define A10_FPGAMGR_IMGCFG_CTL_02_CDRATIO_SHIFT 16 +#define A10_FPGAMGR_IMGCFG_CTL_02_CFGWIDTH BIT(24) +#define A10_FPGAMGR_IMGCFG_CTL_02_CFGWIDTH_SHIFT 24 + +#define A10_FPGAMGR_IMGCFG_STAT_F2S_CRC_ERROR BIT(0) +#define A10_FPGAMGR_IMGCFG_STAT_F2S_EARLY_USERMODE BIT(1) +#define A10_FPGAMGR_IMGCFG_STAT_F2S_USERMODE BIT(2) +#define A10_FPGAMGR_IMGCFG_STAT_F2S_NSTATUS_PIN BIT(4) +#define A10_FPGAMGR_IMGCFG_STAT_F2S_CONDONE_PIN BIT(6) +#define A10_FPGAMGR_IMGCFG_STAT_F2S_PR_READY BIT(9) +#define A10_FPGAMGR_IMGCFG_STAT_F2S_PR_DONE BIT(10) +#define A10_FPGAMGR_IMGCFG_STAT_F2S_PR_ERROR BIT(11) +#define A10_FPGAMGR_IMGCFG_STAT_F2S_NCONFIG_PIN BIT(12) +#define A10_FPGAMGR_IMGCFG_STAT_F2S_MSEL_MASK (BIT(16) | BIT(17) | BIT(18)) +#define A10_FPGAMGR_IMGCFG_STAT_F2S_MSEL_SHIFT 16 + +/* FPGA CD Ratio Value */ +#define CDRATIO_x1 0x0 +#define CDRATIO_x2 0x1 +#define CDRATIO_x4 0x2 +#define CDRATIO_x8 0x3 + +/* Configuration width 16/32 bit */ +#define CFGWDTH_32 1 +#define CFGWDTH_16 0 + +/* + * struct a10_fpga_priv - private data for fpga manager + * @regmap: regmap for register access + * @fpga_data_addr: iomap for single address data register to FPGA + * @clk: clock + */ +struct a10_fpga_priv { + struct regmap *regmap; + void __iomem *fpga_data_addr; + struct clk *clk; +}; + +static bool socfpga_a10_fpga_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case A10_FPGAMGR_DCLKCNT_OFST: + case A10_FPGAMGR_DCLKSTAT_OFST: + case A10_FPGAMGR_IMGCFG_CTL_00_OFST: + case A10_FPGAMGR_IMGCFG_CTL_01_OFST: + case A10_FPGAMGR_IMGCFG_CTL_02_OFST: + return true; + } + return false; +} + +static bool socfpga_a10_fpga_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case A10_FPGAMGR_DCLKCNT_OFST: + case A10_FPGAMGR_DCLKSTAT_OFST: + case A10_FPGAMGR_IMGCFG_CTL_00_OFST: + case A10_FPGAMGR_IMGCFG_CTL_01_OFST: + case A10_FPGAMGR_IMGCFG_CTL_02_OFST: + case A10_FPGAMGR_IMGCFG_STAT_OFST: + return true; + } + return false; +} + +static const struct regmap_config socfpga_a10_fpga_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .writeable_reg = socfpga_a10_fpga_writeable_reg, + .readable_reg = socfpga_a10_fpga_readable_reg, + .max_register = A10_FPGAMGR_IMGCFG_STAT_OFST, + .cache_type = REGCACHE_NONE, +}; + +/* + * from the register map description of cdratio in imgcfg_ctrl_02: + * Normal Configuration : 32bit Passive Parallel + * Partial Reconfiguration : 16bit Passive Parallel + */ +static void socfpga_a10_fpga_set_cfg_width(struct a10_fpga_priv *priv, + int width) +{ + width <<= A10_FPGAMGR_IMGCFG_CTL_02_CFGWIDTH_SHIFT; + + regmap_update_bits(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_02_OFST, + A10_FPGAMGR_IMGCFG_CTL_02_CFGWIDTH, width); +} + +static void socfpga_a10_fpga_generate_dclks(struct a10_fpga_priv *priv, + u32 count) +{ + u32 val; + unsigned int i; + + /* Clear any existing DONE status. */ + regmap_write(priv->regmap, A10_FPGAMGR_DCLKSTAT_OFST, + A10_FPGAMGR_DCLKSTAT_DCLKDONE); + + /* Issue the DCLK regmap. */ + regmap_write(priv->regmap, A10_FPGAMGR_DCLKCNT_OFST, count); + + /* wait till the dclkcnt done */ + for (i = 0; i < 100; i++) { + regmap_read(priv->regmap, A10_FPGAMGR_DCLKSTAT_OFST, &val); + if (val) + break; + udelay(1); + } + + /* Clear DONE status. */ + regmap_write(priv->regmap, A10_FPGAMGR_DCLKSTAT_OFST, + A10_FPGAMGR_DCLKSTAT_DCLKDONE); +} + +static int socfpga_a10_fpga_encrypted(struct fpga_manager *mgr, + u32 *buf32, size_t buf32_size) +{ + int encrypt; + + if (buf32_size < 70) + return -EINVAL; + + encrypt = ((buf32[69] >> 2) & 3) != 0; + + dev_dbg(&mgr->dev, "header word %d = %08x encrypt=%d\n", + 69, buf32[69], encrypt); + + return encrypt; +} + +static int socfpga_a10_fpga_compressed(struct fpga_manager *mgr, + u32 *buf32, size_t buf32_size) +{ + int compress; + + if (buf32_size < 230) + return -EINVAL; + + compress = !((buf32[229] >> 1) & 1); + + dev_dbg(&mgr->dev, "header word %d = %08x compress=%d\n", + 229, buf32[229], compress); + + return compress; +} + +static unsigned int socfpga_a10_fpga_get_cd_ratio(unsigned int cfg_width, + bool encrypt, bool compress) +{ + unsigned int cd_ratio; + + /* + * cd ratio is dependent on cfg width and whether the bitstream + * is encrypted and/or compressed. + * + * | width | encr. | compr. | cd ratio | + * | 16 | 0 | 0 | 1 | + * | 16 | 0 | 1 | 4 | + * | 16 | 1 | 0 | 2 | + * | 16 | 1 | 1 | 4 | + * | 32 | 0 | 0 | 1 | + * | 32 | 0 | 1 | 8 | + * | 32 | 1 | 0 | 4 | + * | 32 | 1 | 1 | 8 | + */ + if (!compress && !encrypt) + return CDRATIO_x1; + + if (compress) + cd_ratio = CDRATIO_x4; + else + cd_ratio = CDRATIO_x2; + + /* if 32 bit, double the cd ratio (so register + field setting is incremented) */ + if (cfg_width == CFGWDTH_32) + cd_ratio += 1; + + return cd_ratio; +} + +static int socfpga_a10_fpga_set_cdratio(struct fpga_manager *mgr, + unsigned int cfg_width, + const char *buf, size_t count) +{ + struct a10_fpga_priv *priv = mgr->priv; + unsigned int cd_ratio; + int encrypt, compress; + + encrypt = socfpga_a10_fpga_encrypted(mgr, (u32 *)buf, count / 4); + if (encrypt < 0) + return -EINVAL; + + compress = socfpga_a10_fpga_compressed(mgr, (u32 *)buf, count / 4); + if (compress < 0) + return -EINVAL; + + cd_ratio = socfpga_a10_fpga_get_cd_ratio(cfg_width, encrypt, compress); + + regmap_update_bits(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_02_OFST, + A10_FPGAMGR_IMGCFG_CTL_02_CDRATIO_MASK, + cd_ratio << A10_FPGAMGR_IMGCFG_CTL_02_CDRATIO_SHIFT); + + return 0; +} + +static u32 socfpga_a10_fpga_read_stat(struct a10_fpga_priv *priv) +{ + u32 val; + + regmap_read(priv->regmap, A10_FPGAMGR_IMGCFG_STAT_OFST, &val); + + return val; +} + +static int socfpga_a10_fpga_wait_for_pr_ready(struct a10_fpga_priv *priv) +{ + u32 reg, i; + + for (i = 0; i < 10 ; i++) { + reg = socfpga_a10_fpga_read_stat(priv); + + if (reg & A10_FPGAMGR_IMGCFG_STAT_F2S_PR_ERROR) + return -EINVAL; + + if (reg & A10_FPGAMGR_IMGCFG_STAT_F2S_PR_READY) + return 0; + } + + return -ETIMEDOUT; +} + +static int socfpga_a10_fpga_wait_for_pr_done(struct a10_fpga_priv *priv) +{ + u32 reg, i; + + for (i = 0; i < 10 ; i++) { + reg = socfpga_a10_fpga_read_stat(priv); + + if (reg & A10_FPGAMGR_IMGCFG_STAT_F2S_PR_ERROR) + return -EINVAL; + + if (reg & A10_FPGAMGR_IMGCFG_STAT_F2S_PR_DONE) + return 0; + } + + return -ETIMEDOUT; +} + +/* Start the FPGA programming by initialize the FPGA Manager */ +static int socfpga_a10_fpga_write_init(struct fpga_manager *mgr, u32 flags, + const char *buf, size_t count) +{ + struct a10_fpga_priv *priv = mgr->priv; + unsigned int cfg_width; + u32 msel, stat, mask; + int ret; + + if (flags & FPGA_MGR_PARTIAL_RECONFIG) + cfg_width = CFGWDTH_16; + else + return -EINVAL; + + /* Check for passive parallel (msel == 000 or 001) */ + msel = socfpga_a10_fpga_read_stat(priv); + msel &= A10_FPGAMGR_IMGCFG_STAT_F2S_MSEL_MASK; + msel >>= A10_FPGAMGR_IMGCFG_STAT_F2S_MSEL_SHIFT; + if ((msel != 0) && (msel != 1)) { + dev_dbg(&mgr->dev, "Fail: invalid msel=%d\n", msel); + return -EINVAL; + } + + /* Make sure no external devices are interfering */ + stat = socfpga_a10_fpga_read_stat(priv); + mask = A10_FPGAMGR_IMGCFG_STAT_F2S_NCONFIG_PIN | + A10_FPGAMGR_IMGCFG_STAT_F2S_NSTATUS_PIN; + if ((stat & mask) != mask) + return -EINVAL; + + /* Set cfg width */ + socfpga_a10_fpga_set_cfg_width(priv, cfg_width); + + /* Determine cd ratio from bitstream header and set cd ratio */ + ret = socfpga_a10_fpga_set_cdratio(mgr, cfg_width, buf, count); + if (ret) + return ret; + + /* + * Clear s2f_nce to enable chip select. Leave pr_request + * unasserted and override disabled. + */ + regmap_write(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_01_OFST, + A10_FPGAMGR_IMGCFG_CTL_01_S2F_NENABLE_CONFIG); + + /* Set cfg_ctrl to enable s2f dclk and data */ + regmap_update_bits(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_02_OFST, + A10_FPGAMGR_IMGCFG_CTL_02_EN_CFG_CTRL, + A10_FPGAMGR_IMGCFG_CTL_02_EN_CFG_CTRL); + + /* + * Disable overrides not needed for pr. + * s2f_config==1 leaves reset deasseted. + */ + regmap_write(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_00_OFST, + A10_FPGAMGR_IMGCFG_CTL_00_S2F_NENABLE_NCONFIG | + A10_FPGAMGR_IMGCFG_CTL_00_S2F_NENABLE_NSTATUS | + A10_FPGAMGR_IMGCFG_CTL_00_S2F_NENABLE_CONDONE | + A10_FPGAMGR_IMGCFG_CTL_00_S2F_NCONFIG); + + /* Enable override for data, dclk, nce, and pr_request to CSS */ + regmap_update_bits(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_01_OFST, + A10_FPGAMGR_IMGCFG_CTL_01_S2F_NENABLE_CONFIG, 0); + + /* Send some clocks to clear out any errors */ + socfpga_a10_fpga_generate_dclks(priv, 256); + + /* Assert pr_request */ + regmap_update_bits(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_01_OFST, + A10_FPGAMGR_IMGCFG_CTL_01_S2F_PR_REQUEST, + A10_FPGAMGR_IMGCFG_CTL_01_S2F_PR_REQUEST); + + /* Do some dclks, wait for pr_ready */ + socfpga_a10_fpga_generate_dclks(priv, 0x7ff); + + /* Wait for pr_ready */ + return socfpga_a10_fpga_wait_for_pr_ready(priv); +} + +/* + * write data to the FPGA data register + */ +static int socfpga_a10_fpga_write(struct fpga_manager *mgr, const char *buf, + size_t count) +{ + struct a10_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)) { + writel(buffer_32[i++], priv->fpga_data_addr); + count -= sizeof(u32); + } + + /* Write out remaining non 32-bit chunks */ + switch (count) { + case 3: + writel(buffer_32[i++] & 0x00ffffff, priv->fpga_data_addr); + break; + case 2: + writel(buffer_32[i++] & 0x0000ffff, priv->fpga_data_addr); + break; + case 1: + writel(buffer_32[i++] & 0x000000ff, priv->fpga_data_addr); + break; + case 0: + break; + default: + /* This will never happen */ + return -EFAULT; + } + + return 0; +} + +static int socfpga_a10_fpga_write_complete(struct fpga_manager *mgr, u32 flags) +{ + struct a10_fpga_priv *priv = mgr->priv; + u32 reg; + int ret; + + /* Wait for pr_done */ + ret = socfpga_a10_fpga_wait_for_pr_done(priv); + + /* Clear pr_request */ + regmap_update_bits(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_01_OFST, + A10_FPGAMGR_IMGCFG_CTL_01_S2F_PR_REQUEST, 0); + + /* Send some clocks to clear out any errors */ + socfpga_a10_fpga_generate_dclks(priv, 256); + + /* Disable s2f dclk and data */ + regmap_update_bits(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_02_OFST, + A10_FPGAMGR_IMGCFG_CTL_02_EN_CFG_CTRL, 0); + + /* Deassert chip select */ + regmap_update_bits(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_01_OFST, + A10_FPGAMGR_IMGCFG_CTL_01_S2F_NCE, + A10_FPGAMGR_IMGCFG_CTL_01_S2F_NCE); + + /* Disable data, dclk, nce, and pr_request override to CSS */ + regmap_update_bits(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_01_OFST, + A10_FPGAMGR_IMGCFG_CTL_01_S2F_NENABLE_CONFIG, + A10_FPGAMGR_IMGCFG_CTL_01_S2F_NENABLE_CONFIG); + + /* Return any errors regarding pr_done or pr_error */ + if (ret) + return ret; + + /* Final check */ + reg = socfpga_a10_fpga_read_stat(priv); + + if (((reg & A10_FPGAMGR_IMGCFG_STAT_F2S_USERMODE) == 0) || + ((reg & A10_FPGAMGR_IMGCFG_STAT_F2S_CONDONE_PIN) == 0) || + ((reg & A10_FPGAMGR_IMGCFG_STAT_F2S_NSTATUS_PIN) == 0)) { + dev_dbg(&mgr->dev, + "Timeout in final check. Status=%08xf\n", reg); + return -ETIMEDOUT; + } + + return 0; +} + +static enum fpga_mgr_states socfpga_a10_fpga_state(struct fpga_manager *mgr) +{ + struct a10_fpga_priv *priv = mgr->priv; + u32 reg = socfpga_a10_fpga_read_stat(priv); + + if (reg & A10_FPGAMGR_IMGCFG_STAT_F2S_USERMODE) + return FPGA_MGR_STATE_OPERATING; + + if (reg & A10_FPGAMGR_IMGCFG_STAT_F2S_PR_READY) + return FPGA_MGR_STATE_WRITE; + + if (reg & A10_FPGAMGR_IMGCFG_STAT_F2S_CRC_ERROR) + return FPGA_MGR_STATE_WRITE_COMPLETE_ERR; + + if ((reg & A10_FPGAMGR_IMGCFG_STAT_F2S_NSTATUS_PIN) == 0) + return FPGA_MGR_STATE_RESET; + + return FPGA_MGR_STATE_UNKNOWN; +} + +static const struct fpga_manager_ops socfpga_a10_fpga_mgr_ops = { + .state = socfpga_a10_fpga_state, + .write_init = socfpga_a10_fpga_write_init, + .write = socfpga_a10_fpga_write, + .write_complete = socfpga_a10_fpga_write_complete, +}; + +static int socfpga_a10_fpga_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct a10_fpga_priv *priv; + void __iomem *reg_base; + struct resource *res; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + /* First mmio base is for register access */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + reg_base = devm_ioremap_resource(dev, res); + if (IS_ERR(reg_base)) + return PTR_ERR(reg_base); + + /* Second mmio base is for writing FPGA image data */ + 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); + + /* regmap for register access */ + priv->regmap = devm_regmap_init_mmio(dev, reg_base, + &socfpga_a10_fpga_regmap_config); + if (IS_ERR(priv->regmap)) + return -ENODEV; + + priv->clk = devm_clk_get(dev, NULL); + if (IS_ERR(priv->clk)) { + dev_err(dev, "no clock specified\n"); + return PTR_ERR(priv->clk); + } + + ret = clk_prepare_enable(priv->clk); + if (ret) { + dev_err(dev, "could not enable clock\n"); + clk_put(priv->clk); + return -EBUSY; + } + + return fpga_mgr_register(dev, "SoCFPGA Arria10 FPGA Manager", + &socfpga_a10_fpga_mgr_ops, priv); +} + +static int socfpga_a10_fpga_remove(struct platform_device *pdev) +{ + struct fpga_manager *mgr = platform_get_drvdata(pdev); + struct a10_fpga_priv *priv = mgr->priv; + + fpga_mgr_unregister(&pdev->dev); + clk_disable_unprepare(priv->clk); + clk_put(priv->clk); + + return 0; +} + +static const struct of_device_id socfpga_a10_fpga_of_match[] = { + { .compatible = "altr,socfpga-a10-fpga-mgr", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, socfpga_a10_fpga_of_match); + +static struct platform_driver socfpga_a10_fpga_driver = { + .probe = socfpga_a10_fpga_probe, + .remove = socfpga_a10_fpga_remove, + .driver = { + .name = "socfpga_a10_fpga_manager", + .of_match_table = socfpga_a10_fpga_of_match, + }, +}; + +module_platform_driver(socfpga_a10_fpga_driver); + +MODULE_AUTHOR("Alan Tull <atull@opensource.altera.com>"); +MODULE_DESCRIPTION("SoCFPGA Arria10 FPGA Manager"); +MODULE_LICENSE("GPL v2"); -- 2.9.1 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 2/2] fpga-manager: Add Socfpga Arria10 support 2016-07-12 19:07 ` [PATCH 2/2] fpga-manager: Add Socfpga Arria10 support Alan Tull @ 2016-07-12 21:31 ` Moritz Fischer 2016-07-12 22:20 ` Russell King - ARM Linux 2016-07-13 14:58 ` atull 0 siblings, 2 replies; 11+ messages in thread From: Moritz Fischer @ 2016-07-12 21:31 UTC (permalink / raw) To: linux-arm-kernel Hi Alan, couple of nits inline below. On Tue, Jul 12, 2016 at 12:07 PM, Alan Tull <atull@opensource.altera.com> wrote: > +static int socfpga_a10_fpga_write_complete(struct fpga_manager *mgr, u32 flags) > +{ > + struct a10_fpga_priv *priv = mgr->priv; > + u32 reg; > + int ret; > + > + /* Wait for pr_done */ > + ret = socfpga_a10_fpga_wait_for_pr_done(priv); > + > + /* Clear pr_request */ > + regmap_update_bits(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_01_OFST, > + A10_FPGAMGR_IMGCFG_CTL_01_S2F_PR_REQUEST, 0); > + > + /* Send some clocks to clear out any errors */ > + socfpga_a10_fpga_generate_dclks(priv, 256); > + > + /* Disable s2f dclk and data */ > + regmap_update_bits(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_02_OFST, > + A10_FPGAMGR_IMGCFG_CTL_02_EN_CFG_CTRL, 0); Maybe replace 0 with named constant. > + > + /* Deassert chip select */ > + regmap_update_bits(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_01_OFST, > + A10_FPGAMGR_IMGCFG_CTL_01_S2F_NCE, > + A10_FPGAMGR_IMGCFG_CTL_01_S2F_NCE); > + > + /* Disable data, dclk, nce, and pr_request override to CSS */ > + regmap_update_bits(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_01_OFST, > + A10_FPGAMGR_IMGCFG_CTL_01_S2F_NENABLE_CONFIG, > + A10_FPGAMGR_IMGCFG_CTL_01_S2F_NENABLE_CONFIG); > + > + /* Return any errors regarding pr_done or pr_error */ > + if (ret) > + return ret; > + > + /* Final check */ > + reg = socfpga_a10_fpga_read_stat(priv); > + > + if (((reg & A10_FPGAMGR_IMGCFG_STAT_F2S_USERMODE) == 0) || > + ((reg & A10_FPGAMGR_IMGCFG_STAT_F2S_CONDONE_PIN) == 0) || > + ((reg & A10_FPGAMGR_IMGCFG_STAT_F2S_NSTATUS_PIN) == 0)) { > + dev_dbg(&mgr->dev, > + "Timeout in final check. Status=%08xf\n", reg); > + return -ETIMEDOUT; > + } > + > + return 0; > +} > + > +static enum fpga_mgr_states socfpga_a10_fpga_state(struct fpga_manager *mgr) > +{ > + struct a10_fpga_priv *priv = mgr->priv; > + u32 reg = socfpga_a10_fpga_read_stat(priv); > + > + if (reg & A10_FPGAMGR_IMGCFG_STAT_F2S_USERMODE) > + return FPGA_MGR_STATE_OPERATING; > + > + if (reg & A10_FPGAMGR_IMGCFG_STAT_F2S_PR_READY) > + return FPGA_MGR_STATE_WRITE; > + > + if (reg & A10_FPGAMGR_IMGCFG_STAT_F2S_CRC_ERROR) > + return FPGA_MGR_STATE_WRITE_COMPLETE_ERR; > + > + if ((reg & A10_FPGAMGR_IMGCFG_STAT_F2S_NSTATUS_PIN) == 0) > + return FPGA_MGR_STATE_RESET; > + > + return FPGA_MGR_STATE_UNKNOWN; > +} > + > +static const struct fpga_manager_ops socfpga_a10_fpga_mgr_ops = { > + .state = socfpga_a10_fpga_state, > + .write_init = socfpga_a10_fpga_write_init, > + .write = socfpga_a10_fpga_write, > + .write_complete = socfpga_a10_fpga_write_complete, > +}; > + > +static int socfpga_a10_fpga_probe(struct platform_device *pdev) > +{ > + struct device *dev = &pdev->dev; > + struct a10_fpga_priv *priv; > + void __iomem *reg_base; > + struct resource *res; > + int ret; > + > + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); > + if (!priv) > + return -ENOMEM; > + > + /* First mmio base is for register access */ > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + reg_base = devm_ioremap_resource(dev, res); > + if (IS_ERR(reg_base)) > + return PTR_ERR(reg_base); > + > + /* Second mmio base is for writing FPGA image data */ > + 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); > + > + /* regmap for register access */ > + priv->regmap = devm_regmap_init_mmio(dev, reg_base, > + &socfpga_a10_fpga_regmap_config); > + if (IS_ERR(priv->regmap)) > + return -ENODEV; > + > + priv->clk = devm_clk_get(dev, NULL); > + if (IS_ERR(priv->clk)) { > + dev_err(dev, "no clock specified\n"); > + return PTR_ERR(priv->clk); > + } > + > + ret = clk_prepare_enable(priv->clk); > + if (ret) { > + dev_err(dev, "could not enable clock\n"); > + clk_put(priv->clk); Seen that you used devm_clk_get() is this one necessary? > +static int socfpga_a10_fpga_remove(struct platform_device *pdev) > +{ > + struct fpga_manager *mgr = platform_get_drvdata(pdev); > + struct a10_fpga_priv *priv = mgr->priv; > + > + fpga_mgr_unregister(&pdev->dev); > + clk_disable_unprepare(priv->clk); > + clk_put(priv->clk); Same here, if needed at all shouldn't it be devm_clk_put() ? Cheers, Moritz ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 2/2] fpga-manager: Add Socfpga Arria10 support 2016-07-12 21:31 ` Moritz Fischer @ 2016-07-12 22:20 ` Russell King - ARM Linux 2016-07-13 14:47 ` atull 2016-07-13 14:58 ` atull 1 sibling, 1 reply; 11+ messages in thread From: Russell King - ARM Linux @ 2016-07-12 22:20 UTC (permalink / raw) To: linux-arm-kernel On Tue, Jul 12, 2016 at 02:31:05PM -0700, Moritz Fischer wrote: > On Tue, Jul 12, 2016 at 12:07 PM, Alan Tull <atull@opensource.altera.com> wrote: > > + priv->clk = devm_clk_get(dev, NULL); > > + if (IS_ERR(priv->clk)) { > > + dev_err(dev, "no clock specified\n"); > > + return PTR_ERR(priv->clk); > > + } > > + > > + ret = clk_prepare_enable(priv->clk); > > + if (ret) { > > + dev_err(dev, "could not enable clock\n"); > > + clk_put(priv->clk); > > Seen that you used devm_clk_get() is this one necessary? That's actually a bug. Never clk_put() a devm_clk_get()'d clock. devm_clk_put() is what you want if provided. However, I think this clk_put() call is useless here. > > +static int socfpga_a10_fpga_remove(struct platform_device *pdev) > > +{ > > + struct fpga_manager *mgr = platform_get_drvdata(pdev); > > + struct a10_fpga_priv *priv = mgr->priv; > > + > > + fpga_mgr_unregister(&pdev->dev); > > + clk_disable_unprepare(priv->clk); > > + clk_put(priv->clk); > > Same here, if needed at all shouldn't it be devm_clk_put() ? And also useless here, as the whole point of the devm_* stuff is to clean up the resources that were claimed on probe failure or when the device is unbound from its driver. -- RMK's Patch system: http://www.armlinux.org.uk/developer/patches/ FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up according to speedtest.net. ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 2/2] fpga-manager: Add Socfpga Arria10 support 2016-07-12 22:20 ` Russell King - ARM Linux @ 2016-07-13 14:47 ` atull 0 siblings, 0 replies; 11+ messages in thread From: atull @ 2016-07-13 14:47 UTC (permalink / raw) To: linux-arm-kernel On Tue, 12 Jul 2016, Russell King - ARM Linux wrote: > On Tue, Jul 12, 2016 at 02:31:05PM -0700, Moritz Fischer wrote: > > On Tue, Jul 12, 2016 at 12:07 PM, Alan Tull <atull@opensource.altera.com> wrote: > > > + priv->clk = devm_clk_get(dev, NULL); > > > + if (IS_ERR(priv->clk)) { > > > + dev_err(dev, "no clock specified\n"); > > > + return PTR_ERR(priv->clk); > > > + } > > > + > > > + ret = clk_prepare_enable(priv->clk); > > > + if (ret) { > > > + dev_err(dev, "could not enable clock\n"); > > > + clk_put(priv->clk); > > > > Seen that you used devm_clk_get() is this one necessary? > > That's actually a bug. Yes, it's wrong. And not needed anyway. > Never clk_put() a devm_clk_get()'d clock. > devm_clk_put() is what you want if provided. However, I think > this clk_put() call is useless here. > > > > +static int socfpga_a10_fpga_remove(struct platform_device *pdev) > > > +{ > > > + struct fpga_manager *mgr = platform_get_drvdata(pdev); > > > + struct a10_fpga_priv *priv = mgr->priv; > > > + > > > + fpga_mgr_unregister(&pdev->dev); > > > + clk_disable_unprepare(priv->clk); > > > + clk_put(priv->clk); > > > > Same here, if needed at all shouldn't it be devm_clk_put() ? > > And also useless here, as the whole point of the devm_* stuff is to > clean up the resources that were claimed on probe failure or when > the device is unbound from its driver. Thanks for pointing this out. I'll take out the clk_put's. Alan > > -- > RMK's Patch system: http://www.armlinux.org.uk/developer/patches/ > FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up > according to speedtest.net. > ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 2/2] fpga-manager: Add Socfpga Arria10 support 2016-07-12 21:31 ` Moritz Fischer 2016-07-12 22:20 ` Russell King - ARM Linux @ 2016-07-13 14:58 ` atull 1 sibling, 0 replies; 11+ messages in thread From: atull @ 2016-07-13 14:58 UTC (permalink / raw) To: linux-arm-kernel On Tue, 12 Jul 2016, Moritz Fischer wrote: > Hi Alan, > > couple of nits inline below. > Hi Moritz! Thanks for your review! > On Tue, Jul 12, 2016 at 12:07 PM, Alan Tull <atull@opensource.altera.com> wrote: > > > +static int socfpga_a10_fpga_write_complete(struct fpga_manager *mgr, u32 flags) > > +{ > > + struct a10_fpga_priv *priv = mgr->priv; > > + u32 reg; > > + int ret; > > + > > + /* Wait for pr_done */ > > + ret = socfpga_a10_fpga_wait_for_pr_done(priv); > > + > > + /* Clear pr_request */ > > + regmap_update_bits(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_01_OFST, > > + A10_FPGAMGR_IMGCFG_CTL_01_S2F_PR_REQUEST, 0); > > + > > + /* Send some clocks to clear out any errors */ > > + socfpga_a10_fpga_generate_dclks(priv, 256); > > + > > + /* Disable s2f dclk and data */ > > + regmap_update_bits(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_02_OFST, > > + A10_FPGAMGR_IMGCFG_CTL_02_EN_CFG_CTRL, 0); > > Maybe replace 0 with named constant. Generally I use named constants, but since regmap_updates_bits uses a mask, it is clear that we're clearing the A10_FPGAMGR_IMGCFG_CTL_02_EN_CFG_CTRL bit. > > +static int socfpga_a10_fpga_probe(struct platform_device *pdev) > > +{ > > + struct device *dev = &pdev->dev; > > + struct a10_fpga_priv *priv; > > + void __iomem *reg_base; > > + struct resource *res; > > + int ret; > > + > > + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); > > + if (!priv) > > + return -ENOMEM; > > + > > + /* First mmio base is for register access */ > > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > > + reg_base = devm_ioremap_resource(dev, res); > > + if (IS_ERR(reg_base)) > > + return PTR_ERR(reg_base); > > + > > + /* Second mmio base is for writing FPGA image data */ > > + 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); > > + > > + /* regmap for register access */ > > + priv->regmap = devm_regmap_init_mmio(dev, reg_base, > > + &socfpga_a10_fpga_regmap_config); > > + if (IS_ERR(priv->regmap)) > > + return -ENODEV; > > + > > + priv->clk = devm_clk_get(dev, NULL); > > + if (IS_ERR(priv->clk)) { > > + dev_err(dev, "no clock specified\n"); > > + return PTR_ERR(priv->clk); > > + } > > + > > + ret = clk_prepare_enable(priv->clk); > > + if (ret) { > > + dev_err(dev, "could not enable clock\n"); > > + clk_put(priv->clk); > > Seen that you used devm_clk_get() is this one necessary? Yes, this is wrong. I'll fix it. Thanks, Alan > > > +static int socfpga_a10_fpga_remove(struct platform_device *pdev) > > +{ > > + struct fpga_manager *mgr = platform_get_drvdata(pdev); > > + struct a10_fpga_priv *priv = mgr->priv; > > + > > + fpga_mgr_unregister(&pdev->dev); > > + clk_disable_unprepare(priv->clk); > > + clk_put(priv->clk); > > Same here, if needed at all shouldn't it be devm_clk_put() ? > > Cheers, > > Moritz > ^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2016-07-19 13:45 UTC | newest] Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2016-07-12 19:07 [PATCH 0/2] FPGA Manager support for Arria10 Alan Tull 2016-07-12 19:07 ` [PATCH 1/2] ARM: socfpga: add bindings doc for arria10 fpga manager Alan Tull 2016-07-16 22:06 ` Rob Herring 2016-07-19 2:39 ` atull 2016-07-17 20:40 ` Moritz Fischer 2016-07-19 13:45 ` atull 2016-07-12 19:07 ` [PATCH 2/2] fpga-manager: Add Socfpga Arria10 support Alan Tull 2016-07-12 21:31 ` Moritz Fischer 2016-07-12 22:20 ` Russell King - ARM Linux 2016-07-13 14:47 ` atull 2016-07-13 14:58 ` atull
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).