Re: [U-Boot] [PATCH 32/51] drivers: Add ihs_fpga and gdsys_soc drivers
Hi Simon, On Wed, Jul 19, 2017 at 11:06 AM, Simon Glasswrote: > Hi Mario, > > On 14 July 2017 at 05:55, Mario Six wrote: >> This patch adds DM drivers for IHS FPGAs and their associated busses, as >> well as uclasses for both. >> >> Signed-off-by: Mario Six >> --- >> >> drivers/misc/Kconfig | 6 + >> drivers/misc/Makefile| 1 + >> drivers/misc/gdsys_soc.c | 51 +++ >> drivers/misc/ihs_fpga.c | 871 >> +++ >> include/dm/uclass-id.h | 2 + >> include/gdsys_soc.h | 29 ++ >> include/ihs_fpga.h | 111 ++ >> 7 files changed, 1071 insertions(+) >> create mode 100644 drivers/misc/gdsys_soc.c >> create mode 100644 drivers/misc/ihs_fpga.c >> create mode 100644 include/gdsys_soc.h >> create mode 100644 include/ihs_fpga.h > > There are definitely cases where you we might have a unique peripheral > and want to add a uclass for it. > > But for what you have here, could we use UCLASS_SYSCON for the soc bus? > OK, I wasn't aware that the syscon uclass could be used in such a case. > For the FPGA could we add a new FPGA uclass? It could have read and > write methods a bit like struct pci_ops where you specify the size of > the read/write. I think that would be useful generally. > > [..] > OK, I guess I can make a general FPGA class. But wouldn't that collide with the type of functionality we have in drivers/fpga now? That code is more concerned with getting a FPGA to run (load a bit file from somewhere and similar functions) than accessing the register interface of a running FPGA from what I can see. Would that be eventually absorbed into the new uclass? Or should those be different uclasses? Should I put the "new" fpga-uclass.c file in drivers/fpga, or make a new directory? >> +static int ihs_fpga_set_reg(struct udevice *dev, const char *compat, >> + uint value) >> +{ >> + struct ihs_fpga_priv *priv = dev_get_priv(dev); >> + struct reg_spec spec; >> + >> + if (get_reg_spec(dev, compat, )) { >> + printf("%s: Could not get %s regspec for '%s'.\n", __func__, >> + dev->name, compat); >> + return -ENODEV; > > Can you return the error from get_reg_spec()? Also -ENODEV means no > device which cannot be true if you have a dev pointer. Perhaps > -ENXIO? > Yes, that's a copy-paste-error; I'll fix it in v2. >> + } >> + >> + out_le16((void *)(priv->regs + spec.addr), value << spec.shift); >> + >> + return 0; >> +} >> + >> +static int ihs_fpga_get_reg(struct udevice *dev, const char *compat, >> + uint *value) >> +{ >> + struct ihs_fpga_priv *priv = dev_get_priv(dev); >> + struct reg_spec spec; >> + uint tmp; >> + >> + if (get_reg_spec(dev, compat, )) { >> + printf("%s: Could not get %s regspec for '%s'.\n", __func__, >> + dev->name, compat); > > Can we use debug() in drivers? > Will fix in v2. >> + return -ENODEV; >> + } >> + >> + tmp = in_le16((void *)(priv->regs + spec.addr)); >> + *value = (tmp & spec.mask) >> spec.shift; >> + >> + return 0; >> +} >> + >> +static u16 ihs_fpga_in_le16(struct udevice *dev, phys_addr_t addr) >> +{ >> + struct ihs_fpga_priv *priv = dev_get_priv(dev); >> + >> + /* TODO: MCLink transfer */ >> + >> + return in_le16((void *)(priv->regs + addr)); >> +} >> + >> +static void ihs_fpga_out_le16(struct udevice *dev, phys_addr_t addr, u16 >> value) >> +{ >> + struct ihs_fpga_priv *priv = dev_get_priv(dev); >> + >> + /* TODO: MCLink transfer */ >> + >> + out_le16((void *)(priv->regs + addr), value); >> +} >> + >> +static const struct ihs_fpga_ops ihs_fpga_ops = { >> + .set_reg = ihs_fpga_set_reg, >> + .get_reg = ihs_fpga_get_reg, >> + .in_le16 = ihs_fpga_in_le16, >> + .out_le16 = ihs_fpga_out_le16, >> +}; >> + >> +static int ihs_fpga_probe(struct udevice *dev) >> +{ >> + struct ihs_fpga_priv *priv = dev_get_priv(dev); >> + fdt_addr_t addr; >> + struct fdtdec_phandle_args phandle_args; > > Since this is new code I think using the dev_read_...() functions is better > OK, I'll switch it to the new API in v2. I had this code lying around for a bit, so it still uses the old interface. >> + struct fdtdec_phandle_args args; >> + struct udevice *busdev = NULL; >> + struct udevice *child = NULL; >> + uint mem_width; >> + >> + if (fdtdec_parse_phandle_with_args(gd->fdt_blob, dev_of_offset(dev), >> + "regmap", NULL, 0, 0, )) { >> + printf("%s: Could not get regmap.\n", dev->name); >> + return 1; >> + } >> + >> + priv->regmap_node = args.node; >> + >> + addr = devfdt_get_addr(dev); >> + >> + priv->addr = addr; >> + priv->regs =
Re: [U-Boot] [PATCH 32/51] drivers: Add ihs_fpga and gdsys_soc drivers
Hi Mario, On 14 July 2017 at 05:55, Mario Sixwrote: > This patch adds DM drivers for IHS FPGAs and their associated busses, as > well as uclasses for both. > > Signed-off-by: Mario Six > --- > > drivers/misc/Kconfig | 6 + > drivers/misc/Makefile| 1 + > drivers/misc/gdsys_soc.c | 51 +++ > drivers/misc/ihs_fpga.c | 871 > +++ > include/dm/uclass-id.h | 2 + > include/gdsys_soc.h | 29 ++ > include/ihs_fpga.h | 111 ++ > 7 files changed, 1071 insertions(+) > create mode 100644 drivers/misc/gdsys_soc.c > create mode 100644 drivers/misc/ihs_fpga.c > create mode 100644 include/gdsys_soc.h > create mode 100644 include/ihs_fpga.h There are definitely cases where you we might have a unique peripheral and want to add a uclass for it. But for what you have here, could we use UCLASS_SYSCON for the soc bus? For the FPGA could we add a new FPGA uclass? It could have read and write methods a bit like struct pci_ops where you specify the size of the read/write. I think that would be useful generally. [..] > +static int ihs_fpga_set_reg(struct udevice *dev, const char *compat, > + uint value) > +{ > + struct ihs_fpga_priv *priv = dev_get_priv(dev); > + struct reg_spec spec; > + > + if (get_reg_spec(dev, compat, )) { > + printf("%s: Could not get %s regspec for '%s'.\n", __func__, > + dev->name, compat); > + return -ENODEV; Can you return the error from get_reg_spec()? Also -ENODEV means no device which cannot be true if you have a dev pointer. Perhaps -ENXIO? > + } > + > + out_le16((void *)(priv->regs + spec.addr), value << spec.shift); > + > + return 0; > +} > + > +static int ihs_fpga_get_reg(struct udevice *dev, const char *compat, > + uint *value) > +{ > + struct ihs_fpga_priv *priv = dev_get_priv(dev); > + struct reg_spec spec; > + uint tmp; > + > + if (get_reg_spec(dev, compat, )) { > + printf("%s: Could not get %s regspec for '%s'.\n", __func__, > + dev->name, compat); Can we use debug() in drivers? > + return -ENODEV; > + } > + > + tmp = in_le16((void *)(priv->regs + spec.addr)); > + *value = (tmp & spec.mask) >> spec.shift; > + > + return 0; > +} > + > +static u16 ihs_fpga_in_le16(struct udevice *dev, phys_addr_t addr) > +{ > + struct ihs_fpga_priv *priv = dev_get_priv(dev); > + > + /* TODO: MCLink transfer */ > + > + return in_le16((void *)(priv->regs + addr)); > +} > + > +static void ihs_fpga_out_le16(struct udevice *dev, phys_addr_t addr, u16 > value) > +{ > + struct ihs_fpga_priv *priv = dev_get_priv(dev); > + > + /* TODO: MCLink transfer */ > + > + out_le16((void *)(priv->regs + addr), value); > +} > + > +static const struct ihs_fpga_ops ihs_fpga_ops = { > + .set_reg = ihs_fpga_set_reg, > + .get_reg = ihs_fpga_get_reg, > + .in_le16 = ihs_fpga_in_le16, > + .out_le16 = ihs_fpga_out_le16, > +}; > + > +static int ihs_fpga_probe(struct udevice *dev) > +{ > + struct ihs_fpga_priv *priv = dev_get_priv(dev); > + fdt_addr_t addr; > + struct fdtdec_phandle_args phandle_args; Since this is new code I think using the dev_read_...() functions is better > + struct fdtdec_phandle_args args; > + struct udevice *busdev = NULL; > + struct udevice *child = NULL; > + uint mem_width; > + > + if (fdtdec_parse_phandle_with_args(gd->fdt_blob, dev_of_offset(dev), > + "regmap", NULL, 0, 0, )) { > + printf("%s: Could not get regmap.\n", dev->name); > + return 1; > + } > + > + priv->regmap_node = args.node; > + > + addr = devfdt_get_addr(dev); > + > + priv->addr = addr; > + priv->regs = map_sysmem(addr, mem_width); > + > + gpio_request_by_name(dev, "reset-gpios", 0, >reset_gpio, > +GPIOD_IS_OUT); > + if (!priv->reset_gpio.dev) You should check the return value of the function. How come you don't return the error code here? If it is OK to not have a GPIO then use dm_gpio_is_valid() - and hopefully debug() instead of printf(). > + printf("%s: Could not get reset-GPIO.\n", dev->name); > + > + gpio_request_by_name(dev, "done-gpios", 0, >done_gpio, > +GPIOD_IS_IN); > + if (!priv->done_gpio.dev) > + printf("%s: Could not get done-GPIO.\n", dev->name); > + > + dm_gpio_set_value(>reset_gpio, 1); Error check? This returns -ENOENT if the GPIO is not valid (as above) so you could filter that out, or use dm_gpo_is_valid() to avoid calling it. > + > + signal_startup_finished(dev); > + > + if (!do_reflection_test(dev)) { > + int ctr =
[U-Boot] [PATCH 32/51] drivers: Add ihs_fpga and gdsys_soc drivers
This patch adds DM drivers for IHS FPGAs and their associated busses, as well as uclasses for both. Signed-off-by: Mario Six--- drivers/misc/Kconfig | 6 + drivers/misc/Makefile| 1 + drivers/misc/gdsys_soc.c | 51 +++ drivers/misc/ihs_fpga.c | 871 +++ include/dm/uclass-id.h | 2 + include/gdsys_soc.h | 29 ++ include/ihs_fpga.h | 111 ++ 7 files changed, 1071 insertions(+) create mode 100644 drivers/misc/gdsys_soc.c create mode 100644 drivers/misc/ihs_fpga.c create mode 100644 include/gdsys_soc.h create mode 100644 include/ihs_fpga.h diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index d1ddbbe157..8b59a444ce 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -196,4 +196,10 @@ config I2C_EEPROM depends on MISC help Enable a generic driver for EEPROMs attached via I2C. + +config IHS_FPGA + bool "Enable IHS FPGA driver" + depends on MISC + help + Support for IHS FPGA. endmenu diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 10265c8fb4..d2e46fc7d6 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -52,3 +52,4 @@ obj-$(CONFIG_FSL_DEVICE_DISABLE) += fsl_devdis.o obj-$(CONFIG_WINBOND_W83627) += winbond_w83627.o obj-$(CONFIG_QFW) += qfw.o obj-$(CONFIG_ROCKCHIP_EFUSE) += rockchip-efuse.o +obj-$(CONFIG_IHS_FPGA) += ihs_fpga.o gdsys_soc.o diff --git a/drivers/misc/gdsys_soc.c b/drivers/misc/gdsys_soc.c new file mode 100644 index 00..34b06d44bd --- /dev/null +++ b/drivers/misc/gdsys_soc.c @@ -0,0 +1,51 @@ +/* + * (C) Copyright 2017 + * Mario Six, Guntermann & Drunck GmbH, mario@gdsys.cc + * + * SPDX-License-Identifier:GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +static int gdsys_soc_child_post_bind(struct udevice *dev) +{ + struct gdsys_soc_child_platdata *pplat = dev_get_parent_platdata(dev); + struct udevice *fpga; + + if (uclass_get_device_by_phandle(UCLASS_IHS_FPGA, dev->parent, "fpga", +)) { + printf("%s: Could not find 'fpga' phandle.\n", + dev->parent->name); + return 1; + } + + pplat->fpga = fpga; + + return 0; +} + +UCLASS_DRIVER(gdsys_soc) = { + .id = UCLASS_GDSYS_SOC, + .name = "gdsys_soc", + .post_probe = dm_scan_fdt_dev, + .child_post_bind = gdsys_soc_child_post_bind, + .per_child_platdata_auto_alloc_size = + sizeof(struct gdsys_soc_child_platdata), +}; + +static const struct udevice_id gdsys_soc_ids[] = { + { .compatible = "gdsys,soc" }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(gdsys_soc_bus) = { + .name = "gdsys_soc_bus", + .id = UCLASS_GDSYS_SOC, + .of_match = gdsys_soc_ids, +}; diff --git a/drivers/misc/ihs_fpga.c b/drivers/misc/ihs_fpga.c new file mode 100644 index 00..a2b5d3f58c --- /dev/null +++ b/drivers/misc/ihs_fpga.c @@ -0,0 +1,871 @@ +/* + * (C) Copyright 2017 + * Mario Six, Guntermann & Drunck GmbH, mario@gdsys.cc + * + * based on the ioep-fpga driver, which is + * + * (C) Copyright 2014 + * Dirk Eibach, Guntermann & Drunck GmbH, eib...@gdsys.de + * + * SPDX-License-Identifier:GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +struct reg_spec { + uint addr; + uint shift; + ulong mask; +}; + +struct ihs_fpga_priv { + u8 *regs; + fdt_addr_t addr; + struct gpio_desc reset_gpio; + struct gpio_desc done_gpio; + struct gpio_desc startupfin_gpios[2]; + int regmap_node; + bool has_osd; +}; + +const u16 reflection_testpattern = 0xdede; + +enum pcb_video_type { + PCB_DVI_SL, + PCB_DP_165MPIX, + PCB_DP_300MPIX, + PCB_HDMI, + PCB_DP_1_2, + PCB_HDMI_2_0, +}; + +enum pcb_transmission_type { + PCB_CAT_1G, + PCB_FIBER_3G, + PCB_CAT_10G, + PCB_FIBER_10G, +}; + +enum carrier_speed { + CARRIER_SPEED_1G, + CARRIER_SPEED_3G, + CARRIER_SPEED_2_5G = CARRIER_SPEED_3G, + CARRIER_SPEED_10G, +}; + +enum ram_config { + RAM_DDR2_32BIT_295MBPS, + RAM_DDR3_32BIT_590MBPS, + RAM_DDR3_48BIT_590MBPS, + RAM_DDR3_64BIT_1800MBPS, + RAM_DDR3_48BIT_1800MBPS, +}; + +enum sysclock { + SYSCLK_147456, +}; + +struct fpga_versions { + bool video_channel; + bool con_side; + enum pcb_video_type pcb_video_type; + enum pcb_transmission_type pcb_transmission_type; + unsigned int hw_version; +}; + +struct fpga_features { + u8 video_channels; + u8 carriers; + enum carrier_speed carrier_speed; + enum ram_config ram_config; + enum sysclock sysclock; +