diff mbox series

[v11,3/5] drivers/soc/litex: add LiteX SoC Controller driver

Message ID 20200923120817.1667149-3-mholenko@antmicro.com
State New
Headers show
Series LiteX SoC controller and LiteUART serial driver | expand

Commit Message

Mateusz Holenko Sept. 23, 2020, 10:09 a.m. UTC
From: Pawel Czarnecki <pczarnecki@internships.antmicro.com>

This commit adds driver for the FPGA-based LiteX SoC
Controller from LiteX SoC builder.

Co-developed-by: Mateusz Holenko <mholenko@antmicro.com>
Signed-off-by: Mateusz Holenko <mholenko@antmicro.com>
Signed-off-by: Pawel Czarnecki <pczarnecki@internships.antmicro.com>
---

Notes:
    Changes in v11:
    - removed an unnecessary comment left over from previous version
    - changed a multi-line comment to comply with the formatting rules
    - use WARN instad of BUG on a failed CSR validation

    Changes in v10:
    - added casting to avoid sparse warnings in the SoC Controller's driver
    
    Changes in v9:
    - added exporting of the `litex_set_reg`/`litex_get_reg` symbols

    Changes in v8:
    - removed `litex_check_accessors()` helper function
    - added crashing (BUG) on the failed LiteX CSR access test

    No changes in v7.

    Changes in v6:
    - added dependency on OF || COMPILE_TEST
    - used le32_to_cpu(readl(addr)) instead of __raw_readl
      and writel(cpu_to_le32(value), addr) instead of __raw_writel
      to take advantage of memory barriers provided by readl/writel

    Changes in v5:
    - removed helper accessors and used __raw_readl/__raw_writel instead
    - fixed checking for errors in litex_soc_ctrl_probe

    Changes in v4:
    - fixed indent in Kconfig's help section
    - fixed copyright header
    - changed compatible to "litex,soc-controller"
    - simplified litex_soc_ctrl_probe
    - removed unnecessary litex_soc_ctrl_remove
   
    This commit has been introduced in v3 of the patchset.
    
    It includes a simplified version of common 'litex.h'
    header introduced in v2 of the patchset.

 MAINTAINERS                        |   2 +
 drivers/soc/Kconfig                |   1 +
 drivers/soc/Makefile               |   1 +
 drivers/soc/litex/Kconfig          |  15 +++
 drivers/soc/litex/Makefile         |   3 +
 drivers/soc/litex/litex_soc_ctrl.c | 194 +++++++++++++++++++++++++++++
 include/linux/litex.h              |  24 ++++
 7 files changed, 240 insertions(+)
 create mode 100644 drivers/soc/litex/Kconfig
 create mode 100644 drivers/soc/litex/Makefile
 create mode 100644 drivers/soc/litex/litex_soc_ctrl.c
 create mode 100644 include/linux/litex.h

Comments

Geert Uytterhoeven Sept. 25, 2020, 1:16 p.m. UTC | #1
Hi Mateusz,

On Wed, Sep 23, 2020 at 12:10 PM Mateusz Holenko <mholenko@antmicro.com> wrote:
> From: Pawel Czarnecki <pczarnecki@internships.antmicro.com>

>

> This commit adds driver for the FPGA-based LiteX SoC

> Controller from LiteX SoC builder.

>

> Co-developed-by: Mateusz Holenko <mholenko@antmicro.com>

> Signed-off-by: Mateusz Holenko <mholenko@antmicro.com>

> Signed-off-by: Pawel Czarnecki <pczarnecki@internships.antmicro.com>


Thanks for your patch!

> --- /dev/null

> +++ b/drivers/soc/litex/Kconfig

> @@ -0,0 +1,15 @@

> +# SPDX-License_Identifier: GPL-2.0

> +

> +menu "Enable LiteX SoC Builder specific drivers"

> +

> +config LITEX_SOC_CONTROLLER

> +       tristate "Enable LiteX SoC Controller driver"

> +       depends on OF || COMPILE_TEST

> +       help

> +         This option enables the SoC Controller Driver which verifies

> +         LiteX CSR access and provides common litex_get_reg/litex_set_reg

> +         accessors.

> +         All drivers that use functions from litex.h must depend on

> +         LITEX_SOC_CONTROLLER.


I'm wondering if it makes sense to have them depend on a "simpler"
symbol instead, e.g. LITEX?

Currently the SoC controller is limited to I/O accessors and a simple
register compatibility check, but you may want to extend it with more
features later, so you probably want to keep the LITEX_SOC_CONTROLLER.
Hence you could add

    config LITEX
        bool

and let LITEX_SOC_CONTROLLER select LITEX.

> --- /dev/null

> +++ b/drivers/soc/litex/litex_soc_ctrl.c

> @@ -0,0 +1,194 @@

> +// SPDX-License-Identifier: GPL-2.0

> +/*

> + * LiteX SoC Controller Driver

> + *

> + * Copyright (C) 2020 Antmicro <www.antmicro.com>

> + *

> + */

> +

> +#include <linux/litex.h>

> +#include <linux/device.h>

> +#include <linux/errno.h>

> +#include <linux/of.h>

> +#include <linux/of_platform.h>

> +#include <linux/platform_device.h>

> +#include <linux/printk.h>

> +#include <linux/module.h>

> +#include <linux/errno.h>

> +#include <linux/io.h>

> +

> +/*

> + * The parameters below are true for LiteX SoC


SoCs

> + * configured for 8-bit CSR Bus, 32-bit aligned.

> + *

> + * Supporting other configurations will require

> + * extending the logic in this header.


This is no longer a header file.

> + */

> +#define LITEX_REG_SIZE             0x4

> +#define LITEX_SUBREG_SIZE          0x1

> +#define LITEX_SUBREG_SIZE_BIT      (LITEX_SUBREG_SIZE * 8)

> +

> +static DEFINE_SPINLOCK(csr_lock);

> +

> +/*

> + * LiteX SoC Generator, depending on the configuration,

> + * can split a single logical CSR (Control & Status Register)

> + * into a series of consecutive physical registers.

> + *

> + * For example, in the configuration with 8-bit CSR Bus,

> + * 32-bit aligned (the default one for 32-bit CPUs) a 32-bit

> + * logical CSR will be generated as four 32-bit physical registers,

> + * each one containing one byte of meaningful data.

> + *

> + * For details see: https://github.com/enjoy-digital/litex/wiki/CSR-Bus

> + *

> + * The purpose of `litex_set_reg`/`litex_get_reg` is to implement

> + * the logic of writing to/reading from the LiteX CSR in a single

> + * place that can be then reused by all LiteX drivers.

> + */

> +void litex_set_reg(void __iomem *reg, unsigned long reg_size,

> +                   unsigned long val)

> +{

> +       unsigned long shifted_data, shift, i;

> +       unsigned long flags;

> +

> +       spin_lock_irqsave(&csr_lock, flags);

> +

> +       for (i = 0; i < reg_size; ++i) {

> +               shift = ((reg_size - i - 1) * LITEX_SUBREG_SIZE_BIT);

> +               shifted_data = val >> shift;

> +

> +               writel((u32 __force)cpu_to_le32(shifted_data), reg + (LITEX_REG_SIZE * i));

> +       }

> +

> +       spin_unlock_irqrestore(&csr_lock, flags);

> +}

> +EXPORT_SYMBOL_GPL(litex_set_reg);


I'm still wondering about the overhead of loops and multiple accesses,
and the need for them (see also BenH's earlier comment).
If e.g. the register widths change for LiteUART (currently they're
hardcoded to one), would you still consider it using the same
programming interface, and thus compatible with "litex,liteuart"?

The spinlock access will probably become the source of lock contention
later, especially when considering SMP variants.

> +/*

> + * Check LiteX CSR read/write access

> + *

> + * This function reads and writes a scratch register in order

> + * to verify if CSR access works.

> + *

> + * In case any problems are detected, the driver should panic.

> + *

> + * Access to the LiteX CSR is, by design, done in CPU native

> + * endianness. The driver should not dynamically configure

> + * access functions when the endianness mismatch is detected.

> + * Such situation indicates problems in the soft SoC design

> + * and should be solved at the LiteX generator level,

> + * not in the software.

> + */

> +static int litex_check_csr_access(void __iomem *reg_addr)

> +{

> +       unsigned long reg;

> +

> +       reg = litex_get_reg(reg_addr + SCRATCH_REG_OFF, SCRATCH_REG_SIZE);

> +

> +       if (reg != SCRATCH_REG_VALUE) {

> +               panic("Scratch register read error! Expected: 0x%x but got: 0x%lx",

> +                       SCRATCH_REG_VALUE, reg);


Do you think the user will ever see this panic message? (see below)

> +               return -EINVAL;


Good ;-)  All of BUG()/WARN()/panic() may be compiled out, depending on
config options, so the system may continue running beyond the panic()
call.

> +static int litex_soc_ctrl_probe(struct platform_device *pdev)

> +{

> +       int result;

> +       struct device *dev;

> +       struct device_node *node;

> +       struct litex_soc_ctrl_device *soc_ctrl_dev;

> +

> +       dev = &pdev->dev;

> +       node = dev->of_node;

> +       if (!node)

> +               return -ENODEV;


FYI, this cannot happen.

> +

> +       soc_ctrl_dev = devm_kzalloc(dev, sizeof(*soc_ctrl_dev), GFP_KERNEL);

> +       if (!soc_ctrl_dev)

> +               return -ENOMEM;

> +

> +       soc_ctrl_dev->base = devm_platform_ioremap_resource(pdev, 0);

> +       if (IS_ERR(soc_ctrl_dev->base))

> +               return PTR_ERR(soc_ctrl_dev->base);

> +

> +       result = litex_check_csr_access(soc_ctrl_dev->base);

> +       if (result) {

> +               /* LiteX CSRs access is broken which means that

> +                * none of LiteX drivers will most probably

> +                * operate correctly

> +                */

> +               WARN(1, "Failed to validate CSR registers, the system is probably broken.\n");


WARN(result, ...)

But is this WARN() needed? You have already called panic() before.

> +       }

> +

> +       return result;

> +}

> +

> +static struct platform_driver litex_soc_ctrl_driver = {

> +       .driver = {

> +               .name = "litex-soc-controller",

> +               .of_match_table = of_match_ptr(litex_soc_ctrl_of_match)

> +       },

> +       .probe = litex_soc_ctrl_probe,

> +};

> +

> +module_platform_driver(litex_soc_ctrl_driver);


module_platform_driver() means this driver is probed quite late in the
boot sequence.  Currently the only other LiteX driver is liteuart, which
is probed at more or less the same time, but I can envision more early
drivers to be added later (typically interrupt/clock controllers and
timers not integrated into the main CPU core).
Note that even liteuart will run earlier, and thus access CSR registers
before the check has run, when using e.g. earlycon...

> --- /dev/null

> +++ b/include/linux/litex.h

> @@ -0,0 +1,24 @@

> +/* SPDX-License-Identifier: GPL-2.0 */

> +/*

> + * Common LiteX header providing

> + * helper functions for accessing CSRs.

> + *

> + * Implementation of the functions is provided by

> + * the LiteX SoC Controller driver.

> + *

> + * Copyright (C) 2019-2020 Antmicro <www.antmicro.com>

> + */

> +

> +#ifndef _LINUX_LITEX_H

> +#define _LINUX_LITEX_H

> +

> +#include <linux/io.h>

> +#include <linux/types.h>

> +#include <linux/compiler_types.h>

> +

> +void litex_set_reg(void __iomem *reg, unsigned long reg_sz, unsigned long val);

> +

> +unsigned long litex_get_reg(void __iomem *reg, unsigned long reg_sz);


Perhaps you can add static inline litex_{read,write}{8,16,32}() wrappers,
so drivers don't have to pass the reg_sz parameter explicitly,
and to make it look more like accessors of other bus types?

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds
Gabriel L. Somlo Sept. 25, 2020, 3:06 p.m. UTC | #2
Hi Geert, Mateusz,

On Fri, Sep 25, 2020 at 03:16:02PM +0200, Geert Uytterhoeven wrote:
> Hi Mateusz,

> 

> On Wed, Sep 23, 2020 at 12:10 PM Mateusz Holenko <mholenko@antmicro.com> wrote:

> > From: Pawel Czarnecki <pczarnecki@internships.antmicro.com>

> >

> > This commit adds driver for the FPGA-based LiteX SoC

> > Controller from LiteX SoC builder.

> >

> > Co-developed-by: Mateusz Holenko <mholenko@antmicro.com>

> > Signed-off-by: Mateusz Holenko <mholenko@antmicro.com>

> > Signed-off-by: Pawel Czarnecki <pczarnecki@internships.antmicro.com>

> 

> Thanks for your patch!

> 

> > --- /dev/null

> > +++ b/drivers/soc/litex/Kconfig

> > @@ -0,0 +1,15 @@

> > +# SPDX-License_Identifier: GPL-2.0

> > +

> > +menu "Enable LiteX SoC Builder specific drivers"

> > +

> > +config LITEX_SOC_CONTROLLER

> > +       tristate "Enable LiteX SoC Controller driver"

> > +       depends on OF || COMPILE_TEST

> > +       help

> > +         This option enables the SoC Controller Driver which verifies

> > +         LiteX CSR access and provides common litex_get_reg/litex_set_reg

> > +         accessors.

> > +         All drivers that use functions from litex.h must depend on

> > +         LITEX_SOC_CONTROLLER.

> 

> I'm wondering if it makes sense to have them depend on a "simpler"

> symbol instead, e.g. LITEX?

> 

> Currently the SoC controller is limited to I/O accessors and a simple

> register compatibility check, but you may want to extend it with more

> features later, so you probably want to keep the LITEX_SOC_CONTROLLER.

> Hence you could add

> 

>     config LITEX

>         bool

> 

> and let LITEX_SOC_CONTROLLER select LITEX.

> 

> > --- /dev/null

> > +++ b/drivers/soc/litex/litex_soc_ctrl.c

> > @@ -0,0 +1,194 @@

> > +// SPDX-License-Identifier: GPL-2.0

> > +/*

> > + * LiteX SoC Controller Driver

> > + *

> > + * Copyright (C) 2020 Antmicro <www.antmicro.com>

> > + *

> > + */

> > +

> > +#include <linux/litex.h>

> > +#include <linux/device.h>

> > +#include <linux/errno.h>

> > +#include <linux/of.h>

> > +#include <linux/of_platform.h>

> > +#include <linux/platform_device.h>

> > +#include <linux/printk.h>

> > +#include <linux/module.h>

> > +#include <linux/errno.h>

> > +#include <linux/io.h>

> > +

> > +/*

> > + * The parameters below are true for LiteX SoC

> 

> SoCs

> 

> > + * configured for 8-bit CSR Bus, 32-bit aligned.

> > + *

> > + * Supporting other configurations will require

> > + * extending the logic in this header.

> 

> This is no longer a header file.

> 

> > + */

> > +#define LITEX_REG_SIZE             0x4

> > +#define LITEX_SUBREG_SIZE          0x1

> > +#define LITEX_SUBREG_SIZE_BIT      (LITEX_SUBREG_SIZE * 8)

> > +

> > +static DEFINE_SPINLOCK(csr_lock);

> > +

> > +/*

> > + * LiteX SoC Generator, depending on the configuration,

> > + * can split a single logical CSR (Control & Status Register)

> > + * into a series of consecutive physical registers.

> > + *

> > + * For example, in the configuration with 8-bit CSR Bus,

> > + * 32-bit aligned (the default one for 32-bit CPUs) a 32-bit

> > + * logical CSR will be generated as four 32-bit physical registers,

> > + * each one containing one byte of meaningful data.

> > + *

> > + * For details see: https://github.com/enjoy-digital/litex/wiki/CSR-Bus

> > + *

> > + * The purpose of `litex_set_reg`/`litex_get_reg` is to implement

> > + * the logic of writing to/reading from the LiteX CSR in a single

> > + * place that can be then reused by all LiteX drivers.

> > + */

> > +void litex_set_reg(void __iomem *reg, unsigned long reg_size,

> > +                   unsigned long val)

> > +{

> > +       unsigned long shifted_data, shift, i;

> > +       unsigned long flags;

> > +

> > +       spin_lock_irqsave(&csr_lock, flags);

> > +

> > +       for (i = 0; i < reg_size; ++i) {

> > +               shift = ((reg_size - i - 1) * LITEX_SUBREG_SIZE_BIT);

> > +               shifted_data = val >> shift;

> > +

> > +               writel((u32 __force)cpu_to_le32(shifted_data), reg + (LITEX_REG_SIZE * i));

> > +       }

> > +

> > +       spin_unlock_irqrestore(&csr_lock, flags);

> > +}

> > +EXPORT_SYMBOL_GPL(litex_set_reg);

> 

> I'm still wondering about the overhead of loops and multiple accesses,

> and the need for them (see also BenH's earlier comment).

> If e.g. the register widths change for LiteUART (currently they're

> hardcoded to one), would you still consider it using the same

> programming interface, and thus compatible with "litex,liteuart"?


There's been talk within the LiteX dev community to standardize on a
LITEX_SUBREG_SIZE of 0x4 (i.e., using all 32 bits of a 32-bit
(LITEX_REG_SIZE) aligned MMIO location). Early 32-bit (vexriscv based)
Linux capable LiteX designs started out with only the 8 LSBits used
within a 32-bit MMIO location, but 64-bit (Rocket chip) based LiteX SoCs
use 4-byte aligned, fully populated MMIO registers (i.e., both
LITEX_SUBREG_SIZE *and* LITEX_REG_SIZE are 4). There's also been talk of
deprecating LITEX_SUBREG_SIZE == 0x1 for "linux-capable LiteX builds",
but nothing definitive yet AFAIK.

As long as adding LITEX_SUBREG_SIZE 0x4 (either as a config option, or
as a hard-coded default in a subsequent version) won't break things, we
should be safe going forward afaict.

Geert: note that LiteX has wider-than-32-bit registers spread across
multiple 32-bit aligned, 8- or 32-bit wide "subregisters", so looping
and shifting will still be necessary, even with LITEX_SUBREG_SIZE 0x4.

> The spinlock access will probably become the source of lock contention

> later, especially when considering SMP variants.

> 

> > +/*

> > + * Check LiteX CSR read/write access

> > + *

> > + * This function reads and writes a scratch register in order

> > + * to verify if CSR access works.

> > + *

> > + * In case any problems are detected, the driver should panic.

> > + *

> > + * Access to the LiteX CSR is, by design, done in CPU native

> > + * endianness. The driver should not dynamically configure

> > + * access functions when the endianness mismatch is detected.

> > + * Such situation indicates problems in the soft SoC design

> > + * and should be solved at the LiteX generator level,

> > + * not in the software.

> > + */

> > +static int litex_check_csr_access(void __iomem *reg_addr)

> > +{

> > +       unsigned long reg;

> > +

> > +       reg = litex_get_reg(reg_addr + SCRATCH_REG_OFF, SCRATCH_REG_SIZE);

> > +

> > +       if (reg != SCRATCH_REG_VALUE) {

> > +               panic("Scratch register read error! Expected: 0x%x but got: 0x%lx",

> > +                       SCRATCH_REG_VALUE, reg);

> 

> Do you think the user will ever see this panic message? (see below)

> 

> > +               return -EINVAL;

> 

> Good ;-)  All of BUG()/WARN()/panic() may be compiled out, depending on

> config options, so the system may continue running beyond the panic()

> call.

> 

> > +static int litex_soc_ctrl_probe(struct platform_device *pdev)

> > +{

> > +       int result;

> > +       struct device *dev;

> > +       struct device_node *node;

> > +       struct litex_soc_ctrl_device *soc_ctrl_dev;

> > +

> > +       dev = &pdev->dev;

> > +       node = dev->of_node;

> > +       if (!node)

> > +               return -ENODEV;

> 

> FYI, this cannot happen.

> 

> > +

> > +       soc_ctrl_dev = devm_kzalloc(dev, sizeof(*soc_ctrl_dev), GFP_KERNEL);

> > +       if (!soc_ctrl_dev)

> > +               return -ENOMEM;

> > +

> > +       soc_ctrl_dev->base = devm_platform_ioremap_resource(pdev, 0);

> > +       if (IS_ERR(soc_ctrl_dev->base))

> > +               return PTR_ERR(soc_ctrl_dev->base);

> > +

> > +       result = litex_check_csr_access(soc_ctrl_dev->base);

> > +       if (result) {

> > +               /* LiteX CSRs access is broken which means that

> > +                * none of LiteX drivers will most probably

> > +                * operate correctly

> > +                */

> > +               WARN(1, "Failed to validate CSR registers, the system is probably broken.\n");

> 

> WARN(result, ...)

> 

> But is this WARN() needed? You have already called panic() before.

> 

> > +       }

> > +

> > +       return result;

> > +}

> > +

> > +static struct platform_driver litex_soc_ctrl_driver = {

> > +       .driver = {

> > +               .name = "litex-soc-controller",

> > +               .of_match_table = of_match_ptr(litex_soc_ctrl_of_match)

> > +       },

> > +       .probe = litex_soc_ctrl_probe,

> > +};

> > +

> > +module_platform_driver(litex_soc_ctrl_driver);

> 

> module_platform_driver() means this driver is probed quite late in the

> boot sequence.  Currently the only other LiteX driver is liteuart, which

> is probed at more or less the same time, but I can envision more early

> drivers to be added later (typically interrupt/clock controllers and

> timers not integrated into the main CPU core).

> Note that even liteuart will run earlier, and thus access CSR registers

> before the check has run, when using e.g. earlycon...

> 

> > --- /dev/null

> > +++ b/include/linux/litex.h

> > @@ -0,0 +1,24 @@

> > +/* SPDX-License-Identifier: GPL-2.0 */

> > +/*

> > + * Common LiteX header providing

> > + * helper functions for accessing CSRs.

> > + *

> > + * Implementation of the functions is provided by

> > + * the LiteX SoC Controller driver.

> > + *

> > + * Copyright (C) 2019-2020 Antmicro <www.antmicro.com>

> > + */

> > +

> > +#ifndef _LINUX_LITEX_H

> > +#define _LINUX_LITEX_H

> > +

> > +#include <linux/io.h>

> > +#include <linux/types.h>

> > +#include <linux/compiler_types.h>

> > +

> > +void litex_set_reg(void __iomem *reg, unsigned long reg_sz, unsigned long val);

> > +

> > +unsigned long litex_get_reg(void __iomem *reg, unsigned long reg_sz);

> 

> Perhaps you can add static inline litex_{read,write}{8,16,32}() wrappers,

> so drivers don't have to pass the reg_sz parameter explicitly,

> and to make it look more like accessors of other bus types?


Seconded -- perhaps simply cut'n'paste and/or adapt from
https://github.com/litex-hub/linux/blob/litex-rocket-rebase/include/linux/litex.h#L78
(from the 64-bit port of the LiteX linux patch set)
 
Cheers,
--Gabriel
Geert Uytterhoeven Sept. 30, 2020, 7:32 a.m. UTC | #3
Hi Gabriel,

On Fri, Sep 25, 2020 at 5:06 PM Gabriel L. Somlo <gsomlo@gmail.com> wrote:
> On Fri, Sep 25, 2020 at 03:16:02PM +0200, Geert Uytterhoeven wrote:

> > On Wed, Sep 23, 2020 at 12:10 PM Mateusz Holenko <mholenko@antmicro.com> wrote:

> > > + */

> > > +#define LITEX_REG_SIZE             0x4

> > > +#define LITEX_SUBREG_SIZE          0x1

> > > +#define LITEX_SUBREG_SIZE_BIT      (LITEX_SUBREG_SIZE * 8)

> > > +

> > > +static DEFINE_SPINLOCK(csr_lock);

> > > +

> > > +/*

> > > + * LiteX SoC Generator, depending on the configuration,

> > > + * can split a single logical CSR (Control & Status Register)

> > > + * into a series of consecutive physical registers.

> > > + *

> > > + * For example, in the configuration with 8-bit CSR Bus,

> > > + * 32-bit aligned (the default one for 32-bit CPUs) a 32-bit

> > > + * logical CSR will be generated as four 32-bit physical registers,

> > > + * each one containing one byte of meaningful data.

> > > + *

> > > + * For details see: https://github.com/enjoy-digital/litex/wiki/CSR-Bus

> > > + *

> > > + * The purpose of `litex_set_reg`/`litex_get_reg` is to implement

> > > + * the logic of writing to/reading from the LiteX CSR in a single

> > > + * place that can be then reused by all LiteX drivers.

> > > + */

> > > +void litex_set_reg(void __iomem *reg, unsigned long reg_size,

> > > +                   unsigned long val)

> > > +{

> > > +       unsigned long shifted_data, shift, i;

> > > +       unsigned long flags;

> > > +

> > > +       spin_lock_irqsave(&csr_lock, flags);

> > > +

> > > +       for (i = 0; i < reg_size; ++i) {

> > > +               shift = ((reg_size - i - 1) * LITEX_SUBREG_SIZE_BIT);

> > > +               shifted_data = val >> shift;

> > > +

> > > +               writel((u32 __force)cpu_to_le32(shifted_data), reg + (LITEX_REG_SIZE * i));

> > > +       }

> > > +

> > > +       spin_unlock_irqrestore(&csr_lock, flags);

> > > +}

> > > +EXPORT_SYMBOL_GPL(litex_set_reg);

> >

> > I'm still wondering about the overhead of loops and multiple accesses,

> > and the need for them (see also BenH's earlier comment).

> > If e.g. the register widths change for LiteUART (currently they're

> > hardcoded to one), would you still consider it using the same

> > programming interface, and thus compatible with "litex,liteuart"?

>

> There's been talk within the LiteX dev community to standardize on a

> LITEX_SUBREG_SIZE of 0x4 (i.e., using all 32 bits of a 32-bit

> (LITEX_REG_SIZE) aligned MMIO location). Early 32-bit (vexriscv based)

> Linux capable LiteX designs started out with only the 8 LSBits used

> within a 32-bit MMIO location, but 64-bit (Rocket chip) based LiteX SoCs

> use 4-byte aligned, fully populated MMIO registers (i.e., both

> LITEX_SUBREG_SIZE *and* LITEX_REG_SIZE are 4). There's also been talk of

> deprecating LITEX_SUBREG_SIZE == 0x1 for "linux-capable LiteX builds",

> but nothing definitive yet AFAIK.


That sounds like a good idea to me.
Having 8-bit accesses may be worthwhile on a small microcontroller, but a
full-fledge Linux system can use more and wider MMIO.

> Geert: note that LiteX has wider-than-32-bit registers spread across

> multiple 32-bit aligned, 8- or 32-bit wide "subregisters", so looping

> and shifting will still be necessary, even with LITEX_SUBREG_SIZE 0x4.


Can these be different than 64-bit (and 128-bit)?
That's not unlike accessors on other 32-bit platforms.
Still, no loop needed, just doing two (or four) 32-bit accesses in a row
is fine (but requires using inlines instead of your current single
out-of-line function).

> > > --- /dev/null

> > > +++ b/include/linux/litex.h


> > > +void litex_set_reg(void __iomem *reg, unsigned long reg_sz, unsigned long val);

> > > +

> > > +unsigned long litex_get_reg(void __iomem *reg, unsigned long reg_sz);

> >

> > Perhaps you can add static inline litex_{read,write}{8,16,32}() wrappers,

> > so drivers don't have to pass the reg_sz parameter explicitly,

> > and to make it look more like accessors of other bus types?

>

> Seconded -- perhaps simply cut'n'paste and/or adapt from

> https://github.com/litex-hub/linux/blob/litex-rocket-rebase/include/linux/litex.h#L78

> (from the 64-bit port of the LiteX linux patch set)


Yes, you definitely want the 32-bit and 64-bit ports to agree ;-)
Note that these are using the "old" "bwlq" convention (with "l"
predating 64-bit long on 64-bit platforms) instead of the more modern
explicit {8,16,32,64}, but that's a minor detail.

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds
Mateusz Holenko Oct. 6, 2020, 6:34 a.m. UTC | #4
Hi Jonathan,

thanks for your review!

On Wed, Sep 23, 2020 at 1:58 PM Jonathan Cameron
<Jonathan.Cameron@huawei.com> wrote:
>
> On Wed, 23 Sep 2020 12:09:06 +0200
> Mateusz Holenko <mholenko@antmicro.com> wrote:
>
> > From: Pawel Czarnecki <pczarnecki@internships.antmicro.com>
> >
> > This commit adds driver for the FPGA-based LiteX SoC
> > Controller from LiteX SoC builder.
> >
> > Co-developed-by: Mateusz Holenko <mholenko@antmicro.com>
> > Signed-off-by: Mateusz Holenko <mholenko@antmicro.com>
> > Signed-off-by: Pawel Czarnecki <pczarnecki@internships.antmicro.com>
>
> A few little things inline, but looks fine in general to me.
>
> Main request is for more formal documentation of parameters to the read
> and write functions.

You are right, the parameters should be better documented - I'll take
a look at that.
There are some other comments that suggest to replace the loop-based
generic functions
with a bunch of separate accessors - perhaps going this way would also
make it easier to understand
the code.

> Jonathan
>
> > ---
> >
> > Notes:
> >     Changes in v11:
> >     - removed an unnecessary comment left over from previous version
> >     - changed a multi-line comment to comply with the formatting rules
> >     - use WARN instad of BUG on a failed CSR validation
> >
> >     Changes in v10:
> >     - added casting to avoid sparse warnings in the SoC Controller's driver
> >
> >     Changes in v9:
> >     - added exporting of the `litex_set_reg`/`litex_get_reg` symbols
> >
> >     Changes in v8:
> >     - removed `litex_check_accessors()` helper function
> >     - added crashing (BUG) on the failed LiteX CSR access test
> >
> >     No changes in v7.
> >
> >     Changes in v6:
> >     - added dependency on OF || COMPILE_TEST
> >     - used le32_to_cpu(readl(addr)) instead of __raw_readl
> >       and writel(cpu_to_le32(value), addr) instead of __raw_writel
> >       to take advantage of memory barriers provided by readl/writel
> >
> >     Changes in v5:
> >     - removed helper accessors and used __raw_readl/__raw_writel instead
> >     - fixed checking for errors in litex_soc_ctrl_probe
> >
> >     Changes in v4:
> >     - fixed indent in Kconfig's help section
> >     - fixed copyright header
> >     - changed compatible to "litex,soc-controller"
> >     - simplified litex_soc_ctrl_probe
> >     - removed unnecessary litex_soc_ctrl_remove
> >
> >     This commit has been introduced in v3 of the patchset.
> >
> >     It includes a simplified version of common 'litex.h'
> >     header introduced in v2 of the patchset.
> >
> >  MAINTAINERS                        |   2 +
> >  drivers/soc/Kconfig                |   1 +
> >  drivers/soc/Makefile               |   1 +
> >  drivers/soc/litex/Kconfig          |  15 +++
> >  drivers/soc/litex/Makefile         |   3 +
> >  drivers/soc/litex/litex_soc_ctrl.c | 194 +++++++++++++++++++++++++++++
> >  include/linux/litex.h              |  24 ++++
> >  7 files changed, 240 insertions(+)
> >  create mode 100644 drivers/soc/litex/Kconfig
> >  create mode 100644 drivers/soc/litex/Makefile
> >  create mode 100644 drivers/soc/litex/litex_soc_ctrl.c
> >  create mode 100644 include/linux/litex.h
> >
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index 39be98db7418..4d70a1b22a87 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -9840,6 +9840,8 @@ M:      Karol Gugala <kgugala@antmicro.com>
> >  M:   Mateusz Holenko <mholenko@antmicro.com>
> >  S:   Maintained
> >  F:   Documentation/devicetree/bindings/*/litex,*.yaml
> > +F:   drivers/soc/litex/litex_soc_ctrl.c
> > +F:   include/linux/litex.h
> >
> >  LIVE PATCHING
> >  M:   Josh Poimboeuf <jpoimboe@redhat.com>
> > diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig
> > index 425ab6f7e375..d097d070f579 100644
> > --- a/drivers/soc/Kconfig
> > +++ b/drivers/soc/Kconfig
> > @@ -9,6 +9,7 @@ source "drivers/soc/bcm/Kconfig"
> >  source "drivers/soc/fsl/Kconfig"
> >  source "drivers/soc/imx/Kconfig"
> >  source "drivers/soc/ixp4xx/Kconfig"
> > +source "drivers/soc/litex/Kconfig"
> >  source "drivers/soc/mediatek/Kconfig"
> >  source "drivers/soc/qcom/Kconfig"
> >  source "drivers/soc/renesas/Kconfig"
> > diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile
> > index 36452bed86ef..0b16108823ef 100644
> > --- a/drivers/soc/Makefile
> > +++ b/drivers/soc/Makefile
> > @@ -14,6 +14,7 @@ obj-$(CONFIG_ARCH_GEMINI)   += gemini/
> >  obj-y                                += imx/
> >  obj-$(CONFIG_ARCH_IXP4XX)    += ixp4xx/
> >  obj-$(CONFIG_SOC_XWAY)               += lantiq/
> > +obj-$(CONFIG_LITEX_SOC_CONTROLLER) += litex/
> >  obj-y                                += mediatek/
> >  obj-y                                += amlogic/
> >  obj-y                                += qcom/
> > diff --git a/drivers/soc/litex/Kconfig b/drivers/soc/litex/Kconfig
> > new file mode 100644
> > index 000000000000..c974ec3846bc
> > --- /dev/null
> > +++ b/drivers/soc/litex/Kconfig
> > @@ -0,0 +1,15 @@
> > +# SPDX-License_Identifier: GPL-2.0
> > +
> > +menu "Enable LiteX SoC Builder specific drivers"
> > +
> > +config LITEX_SOC_CONTROLLER
> > +     tristate "Enable LiteX SoC Controller driver"
> > +     depends on OF || COMPILE_TEST
> > +     help
> > +       This option enables the SoC Controller Driver which verifies
> > +       LiteX CSR access and provides common litex_get_reg/litex_set_reg
> > +       accessors.
> > +       All drivers that use functions from litex.h must depend on
> > +       LITEX_SOC_CONTROLLER.
> > +
> > +endmenu
> > diff --git a/drivers/soc/litex/Makefile b/drivers/soc/litex/Makefile
> > new file mode 100644
> > index 000000000000..98ff7325b1c0
> > --- /dev/null
> > +++ b/drivers/soc/litex/Makefile
> > @@ -0,0 +1,3 @@
> > +# SPDX-License_Identifier: GPL-2.0
> > +
> > +obj-$(CONFIG_LITEX_SOC_CONTROLLER)   += litex_soc_ctrl.o
> > diff --git a/drivers/soc/litex/litex_soc_ctrl.c b/drivers/soc/litex/litex_soc_ctrl.c
> > new file mode 100644
> > index 000000000000..08330c9872b0
> > --- /dev/null
> > +++ b/drivers/soc/litex/litex_soc_ctrl.c
> > @@ -0,0 +1,194 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * LiteX SoC Controller Driver
> > + *
> > + * Copyright (C) 2020 Antmicro <www.antmicro.com>
> > + *
> > + */
> > +
> > +#include <linux/litex.h>
> > +#include <linux/device.h>
> > +#include <linux/errno.h>
> > +#include <linux/of.h>
> > +#include <linux/of_platform.h>
>
> I'm not seeing anything from this header in use in here yet.

I'll check and remove if this is not needed.

> > +#include <linux/platform_device.h>
> > +#include <linux/printk.h>
> > +#include <linux/module.h>
> > +#include <linux/errno.h>
> > +#include <linux/io.h>
> > +
> > +/*
> > + * The parameters below are true for LiteX SoC
> > + * configured for 8-bit CSR Bus, 32-bit aligned.
> > + *
> > + * Supporting other configurations will require
> > + * extending the logic in this header.
> > + */
> > +#define LITEX_REG_SIZE             0x4
> > +#define LITEX_SUBREG_SIZE          0x1
> > +#define LITEX_SUBREG_SIZE_BIT      (LITEX_SUBREG_SIZE * 8)
> > +
> > +static DEFINE_SPINLOCK(csr_lock);
> > +
> > +/*
> > + * LiteX SoC Generator, depending on the configuration,
> > + * can split a single logical CSR (Control & Status Register)
> > + * into a series of consecutive physical registers.
> > + *
> > + * For example, in the configuration with 8-bit CSR Bus,
> > + * 32-bit aligned (the default one for 32-bit CPUs) a 32-bit
> > + * logical CSR will be generated as four 32-bit physical registers,
> > + * each one containing one byte of meaningful data.
> > + *
> > + * For details see: https://github.com/enjoy-digital/litex/wiki/CSR-Bus
> > + *
> > + * The purpose of `litex_set_reg`/`litex_get_reg` is to implement
> > + * the logic of writing to/reading from the LiteX CSR in a single
> > + * place that can be then reused by all LiteX drivers.
> > + */
>
> I would argue in favor of formal kernel-doc for these.
> Even with this explanation the exact meaning of parameters
> isn't particularly clear.

As stated above, I'll make it clearer - either by adding a formal doc
or by splitting this function into several easier-to-understand ones.

> > +void litex_set_reg(void __iomem *reg, unsigned long reg_size,
> > +                 unsigned long val)
> > +{
> > +     unsigned long shifted_data, shift, i;
> > +     unsigned long flags;
> > +
> > +     spin_lock_irqsave(&csr_lock, flags);
> > +
> > +     for (i = 0; i < reg_size; ++i) {
> > +             shift = ((reg_size - i - 1) * LITEX_SUBREG_SIZE_BIT);
> > +             shifted_data = val >> shift;
> > +
> > +             writel((u32 __force)cpu_to_le32(shifted_data), reg + (LITEX_REG_SIZE * i));
> > +     }
> > +
> > +     spin_unlock_irqrestore(&csr_lock, flags);
> > +}
> > +EXPORT_SYMBOL_GPL(litex_set_reg);
> > +
> > +unsigned long litex_get_reg(void __iomem *reg, unsigned long reg_size)
> > +{
> > +     unsigned long shifted_data, shift, i;
> > +     unsigned long result = 0;
> > +     unsigned long flags;
> > +
> > +     spin_lock_irqsave(&csr_lock, flags);
> > +
> > +     for (i = 0; i < reg_size; ++i) {
> > +             shifted_data = le32_to_cpu((__le32 __force)readl(reg + (LITEX_REG_SIZE * i)));
> > +
> > +             shift = ((reg_size - i - 1) * LITEX_SUBREG_SIZE_BIT);
> > +             result |= (shifted_data << shift);
> > +     }
> > +
> > +     spin_unlock_irqrestore(&csr_lock, flags);
> > +
> > +     return result;
> > +}
> > +EXPORT_SYMBOL_GPL(litex_get_reg);
> > +
> > +#define SCRATCH_REG_OFF         0x04
> > +#define SCRATCH_REG_SIZE        4
> > +#define SCRATCH_REG_VALUE       0x12345678
> > +#define SCRATCH_TEST_VALUE      0xdeadbeef
> > +
> > +/*
> > + * Check LiteX CSR read/write access
> > + *
> > + * This function reads and writes a scratch register in order
> > + * to verify if CSR access works.
> > + *
> > + * In case any problems are detected, the driver should panic.
> > + *
> > + * Access to the LiteX CSR is, by design, done in CPU native
> > + * endianness. The driver should not dynamically configure
> > + * access functions when the endianness mismatch is detected.
> > + * Such situation indicates problems in the soft SoC design
> > + * and should be solved at the LiteX generator level,
> > + * not in the software.
> > + */
> > +static int litex_check_csr_access(void __iomem *reg_addr)
> > +{
> > +     unsigned long reg;
> > +
> > +     reg = litex_get_reg(reg_addr + SCRATCH_REG_OFF, SCRATCH_REG_SIZE);
> > +
> > +     if (reg != SCRATCH_REG_VALUE) {
> > +             panic("Scratch register read error! Expected: 0x%x but got: 0x%lx",
> > +                     SCRATCH_REG_VALUE, reg);
> > +             return -EINVAL;
> > +     }
> > +
> > +     litex_set_reg(reg_addr + SCRATCH_REG_OFF,
> > +             SCRATCH_REG_SIZE, SCRATCH_TEST_VALUE);
> > +     reg = litex_get_reg(reg_addr + SCRATCH_REG_OFF, SCRATCH_REG_SIZE);
> > +
> > +     if (reg != SCRATCH_TEST_VALUE) {
> > +             panic("Scratch register write error! Expected: 0x%x but got: 0x%lx",
> > +                     SCRATCH_TEST_VALUE, reg);
> > +             return -EINVAL;
> > +     }
> > +
> > +     /* restore original value of the SCRATCH register */
> > +     litex_set_reg(reg_addr + SCRATCH_REG_OFF,
> > +             SCRATCH_REG_SIZE, SCRATCH_REG_VALUE);
> > +
> > +     pr_info("LiteX SoC Controller driver initialized");
> > +
> > +     return 0;
> > +}
> > +
> > +struct litex_soc_ctrl_device {
> > +     void __iomem *base;
> > +};
> > +
> > +static const struct of_device_id litex_soc_ctrl_of_match[] = {
> > +     {.compatible = "litex,soc-controller"},
> > +     {},
> > +};
> > +
> > +MODULE_DEVICE_TABLE(of, litex_soc_ctrl_of_match);
> > +
> > +static int litex_soc_ctrl_probe(struct platform_device *pdev)
> > +{
> > +     int result;
> > +     struct device *dev;
> > +     struct device_node *node;
> > +     struct litex_soc_ctrl_device *soc_ctrl_dev;
> > +
> > +     dev = &pdev->dev;
> > +     node = dev->of_node;
> > +     if (!node)
> > +             return -ENODEV;
> > +
> > +     soc_ctrl_dev = devm_kzalloc(dev, sizeof(*soc_ctrl_dev), GFP_KERNEL);
> > +     if (!soc_ctrl_dev)
> > +             return -ENOMEM;
> > +
> > +     soc_ctrl_dev->base = devm_platform_ioremap_resource(pdev, 0);
> > +     if (IS_ERR(soc_ctrl_dev->base))
> > +             return PTR_ERR(soc_ctrl_dev->base);
> > +
> > +     result = litex_check_csr_access(soc_ctrl_dev->base);
> > +     if (result) {
> > +             /* LiteX CSRs access is broken which means that
> > +              * none of LiteX drivers will most probably
> > +              * operate correctly
> > +              */
> > +             WARN(1, "Failed to validate CSR registers, the system is probably broken.\n");
> > +     }
> > +
> > +     return result;
> > +}
> > +
> > +static struct platform_driver litex_soc_ctrl_driver = {
> > +     .driver = {
> > +             .name = "litex-soc-controller",
> > +             .of_match_table = of_match_ptr(litex_soc_ctrl_of_match)
> > +     },
> > +     .probe = litex_soc_ctrl_probe,
> > +};
> > +
> > +module_platform_driver(litex_soc_ctrl_driver);
> > +MODULE_DESCRIPTION("LiteX SoC Controller driver");
> > +MODULE_AUTHOR("Antmicro <www.antmicro.com>");
> > +MODULE_LICENSE("GPL v2");
> > diff --git a/include/linux/litex.h b/include/linux/litex.h
> > new file mode 100644
> > index 000000000000..72061018c172
> > --- /dev/null
> > +++ b/include/linux/litex.h
> > @@ -0,0 +1,24 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * Common LiteX header providing
> > + * helper functions for accessing CSRs.
> > + *
> > + * Implementation of the functions is provided by
> > + * the LiteX SoC Controller driver.
> > + *
> > + * Copyright (C) 2019-2020 Antmicro <www.antmicro.com>
> > + */
> > +
> > +#ifndef _LINUX_LITEX_H
> > +#define _LINUX_LITEX_H
> > +
> > +#include <linux/io.h>
> > +#include <linux/types.h>
> > +#include <linux/compiler_types.h>
> > +
> > +void litex_set_reg(void __iomem *reg, unsigned long reg_sz, unsigned long val);
> > +
> > +unsigned long litex_get_reg(void __iomem *reg, unsigned long reg_sz);
> > +
>
> Nitpick. One blank line is almost always enough!

Right, one blank line ought to be enough for anyone.

> > +
> > +#endif /* _LINUX_LITEX_H */
>
>

Best regards,
Mateusz


--
Mateusz Holenko
Antmicro Ltd | www.antmicro.com
Roosevelta 22, 60-829 Poznan, Poland
Mateusz Holenko Oct. 6, 2020, 8:02 a.m. UTC | #5
Hi Geert,

On Fri, Sep 25, 2020 at 3:16 PM Geert Uytterhoeven <geert@linux-m68k.org> wrote:
>
> Hi Mateusz,
>
> On Wed, Sep 23, 2020 at 12:10 PM Mateusz Holenko <mholenko@antmicro.com> wrote:
> > From: Pawel Czarnecki <pczarnecki@internships.antmicro.com>
> >
> > This commit adds driver for the FPGA-based LiteX SoC
> > Controller from LiteX SoC builder.
> >
> > Co-developed-by: Mateusz Holenko <mholenko@antmicro.com>
> > Signed-off-by: Mateusz Holenko <mholenko@antmicro.com>
> > Signed-off-by: Pawel Czarnecki <pczarnecki@internships.antmicro.com>
>
> Thanks for your patch!

Thanks for your review!

> > --- /dev/null
> > +++ b/drivers/soc/litex/Kconfig
> > @@ -0,0 +1,15 @@
> > +# SPDX-License_Identifier: GPL-2.0
> > +
> > +menu "Enable LiteX SoC Builder specific drivers"
> > +
> > +config LITEX_SOC_CONTROLLER
> > +       tristate "Enable LiteX SoC Controller driver"
> > +       depends on OF || COMPILE_TEST
> > +       help
> > +         This option enables the SoC Controller Driver which verifies
> > +         LiteX CSR access and provides common litex_get_reg/litex_set_reg
> > +         accessors.
> > +         All drivers that use functions from litex.h must depend on
> > +         LITEX_SOC_CONTROLLER.
>
> I'm wondering if it makes sense to have them depend on a "simpler"
> symbol instead, e.g. LITEX?
>
> Currently the SoC controller is limited to I/O accessors and a simple
> register compatibility check, but you may want to extend it with more
> features later, so you probably want to keep the LITEX_SOC_CONTROLLER.
> Hence you could add
>
>     config LITEX
>         bool
>
> and let LITEX_SOC_CONTROLLER select LITEX.

But then if other drivers depend just on LITEX, it would not automatically
mean that the LITEX_SOC_CONTROLLER is selected, right?. And if it's not selected
litex_{g,s}et_reg() are not available and the compilation would fail.

I could move the implementation of those functions directly to the
litex.h header
and avoid this KConfig dependency, but I'm not sure if they are not
too big to become a static inline.
What do you think?

> > --- /dev/null
> > +++ b/drivers/soc/litex/litex_soc_ctrl.c
> > @@ -0,0 +1,194 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * LiteX SoC Controller Driver
> > + *
> > + * Copyright (C) 2020 Antmicro <www.antmicro.com>
> > + *
> > + */
> > +
> > +#include <linux/litex.h>
> > +#include <linux/device.h>
> > +#include <linux/errno.h>
> > +#include <linux/of.h>
> > +#include <linux/of_platform.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/printk.h>
> > +#include <linux/module.h>
> > +#include <linux/errno.h>
> > +#include <linux/io.h>
> > +
> > +/*
> > + * The parameters below are true for LiteX SoC
>
> SoCs

Right, I will fix that.

> > + * configured for 8-bit CSR Bus, 32-bit aligned.
> > + *
> > + * Supporting other configurations will require
> > + * extending the logic in this header.
>
> This is no longer a header file.

It's not - you are correct. I will rephrase it to "extending the logic
in this file".

> > + */
> > +#define LITEX_REG_SIZE             0x4
> > +#define LITEX_SUBREG_SIZE          0x1
> > +#define LITEX_SUBREG_SIZE_BIT      (LITEX_SUBREG_SIZE * 8)
> > +
> > +static DEFINE_SPINLOCK(csr_lock);
> > +
> > +/*
> > + * LiteX SoC Generator, depending on the configuration,
> > + * can split a single logical CSR (Control & Status Register)
> > + * into a series of consecutive physical registers.
> > + *
> > + * For example, in the configuration with 8-bit CSR Bus,
> > + * 32-bit aligned (the default one for 32-bit CPUs) a 32-bit
> > + * logical CSR will be generated as four 32-bit physical registers,
> > + * each one containing one byte of meaningful data.
> > + *
> > + * For details see: https://github.com/enjoy-digital/litex/wiki/CSR-Bus
> > + *
> > + * The purpose of `litex_set_reg`/`litex_get_reg` is to implement
> > + * the logic of writing to/reading from the LiteX CSR in a single
> > + * place that can be then reused by all LiteX drivers.
> > + */
> > +void litex_set_reg(void __iomem *reg, unsigned long reg_size,
> > +                   unsigned long val)
> > +{
> > +       unsigned long shifted_data, shift, i;
> > +       unsigned long flags;
> > +
> > +       spin_lock_irqsave(&csr_lock, flags);
> > +
> > +       for (i = 0; i < reg_size; ++i) {
> > +               shift = ((reg_size - i - 1) * LITEX_SUBREG_SIZE_BIT);
> > +               shifted_data = val >> shift;
> > +
> > +               writel((u32 __force)cpu_to_le32(shifted_data), reg + (LITEX_REG_SIZE * i));
> > +       }
> > +
> > +       spin_unlock_irqrestore(&csr_lock, flags);
> > +}
> > +EXPORT_SYMBOL_GPL(litex_set_reg);
>
> I'm still wondering about the overhead of loops and multiple accesses,
> and the need for them (see also BenH's earlier comment).
> If e.g. the register widths change for LiteUART (currently they're
> hardcoded to one), would you still consider it using the same
> programming interface, and thus compatible with "litex,liteuart"?

Since the amount of possible `reg_size` is practically limited we could
add explicit 8/32/64/128 accessors to eliminate loops.
As for multiple writel/readl I don't really see an option to avoid
them for the 8-bit bus width.

> The spinlock access will probably become the source of lock contention
> later, especially when considering SMP variants.

Do you have any suggestions on how to handle this?
Dropping locks could lead to the situation when two cores write at the
same time leaving a wrong (mixed) value in the CSR.

> > +/*
> > + * Check LiteX CSR read/write access
> > + *
> > + * This function reads and writes a scratch register in order
> > + * to verify if CSR access works.
> > + *
> > + * In case any problems are detected, the driver should panic.
> > + *
> > + * Access to the LiteX CSR is, by design, done in CPU native
> > + * endianness. The driver should not dynamically configure
> > + * access functions when the endianness mismatch is detected.
> > + * Such situation indicates problems in the soft SoC design
> > + * and should be solved at the LiteX generator level,
> > + * not in the software.
> > + */
> > +static int litex_check_csr_access(void __iomem *reg_addr)
> > +{
> > +       unsigned long reg;
> > +
> > +       reg = litex_get_reg(reg_addr + SCRATCH_REG_OFF, SCRATCH_REG_SIZE);
> > +
> > +       if (reg != SCRATCH_REG_VALUE) {
> > +               panic("Scratch register read error! Expected: 0x%x but got: 0x%lx",
> > +                       SCRATCH_REG_VALUE, reg);
>
> Do you think the user will ever see this panic message? (see below)

On UART most probably not, as broken CSRs mean broken UART driver as well.
But I believe you can retrieve logs from the memory and analyze them
post-mortem, isn't that right?

> > +               return -EINVAL;
>
> Good ;-)  All of BUG()/WARN()/panic() may be compiled out, depending on
> config options, so the system may continue running beyond the panic()
> call.
>
> > +static int litex_soc_ctrl_probe(struct platform_device *pdev)
> > +{
> > +       int result;
> > +       struct device *dev;
> > +       struct device_node *node;
> > +       struct litex_soc_ctrl_device *soc_ctrl_dev;
> > +
> > +       dev = &pdev->dev;
> > +       node = dev->of_node;
> > +       if (!node)
> > +               return -ENODEV;
>
> FYI, this cannot happen.

Right, this check is not necessary - I will remove it.

> > +
> > +       soc_ctrl_dev = devm_kzalloc(dev, sizeof(*soc_ctrl_dev), GFP_KERNEL);
> > +       if (!soc_ctrl_dev)
> > +               return -ENOMEM;
> > +
> > +       soc_ctrl_dev->base = devm_platform_ioremap_resource(pdev, 0);
> > +       if (IS_ERR(soc_ctrl_dev->base))
> > +               return PTR_ERR(soc_ctrl_dev->base);
> > +
> > +       result = litex_check_csr_access(soc_ctrl_dev->base);
> > +       if (result) {
> > +               /* LiteX CSRs access is broken which means that
> > +                * none of LiteX drivers will most probably
> > +                * operate correctly
> > +                */
> > +               WARN(1, "Failed to validate CSR registers, the system is probably broken.\n");
>
> WARN(result, ...)
>
> But is this WARN() needed? You have already called panic() before.

You are right - in both cases (read/write) we call panic before
returning a non-0 value from litex_check_csr_access().
In this context additional WARN is probably not necessary. I'll extend
the panic message to indicate that read/write failure means a broken
system and drop this WARN.

> > +       }
> > +
> > +       return result;
> > +}
> > +
> > +static struct platform_driver litex_soc_ctrl_driver = {
> > +       .driver = {
> > +               .name = "litex-soc-controller",
> > +               .of_match_table = of_match_ptr(litex_soc_ctrl_of_match)
> > +       },
> > +       .probe = litex_soc_ctrl_probe,
> > +};
> > +
> > +module_platform_driver(litex_soc_ctrl_driver);
>
> module_platform_driver() means this driver is probed quite late in the
> boot sequence.  Currently the only other LiteX driver is liteuart, which
> is probed at more or less the same time, but I can envision more early
> drivers to be added later (typically interrupt/clock controllers and
> timers not integrated into the main CPU core).
> Note that even liteuart will run earlier, and thus access CSR registers
> before the check has run, when using e.g. earlycon...

Yes, this is an interesting point.
We have already covered it in some previous version of the patchset by testing
if the LiteX SoC Controller driver was probed and returning -EDEFER in
the UART driver otherwise
(to make sure CSR access is verified before UART uses it).
With this approach, however, all future LiteX drivers would have to
follow the pattern and we would require the LiteX SoC Controller
to be part of the system (which is not the case for the Microwatt
platform for example - it uses just an eth core from LiteX).

That's why we finally decided to go with the relaxed version - where
we allow the SoC controller driver not to be the first LiteX driver to
be probed (and possibly detect a problem after other drivers encounter
it).

> > --- /dev/null
> > +++ b/include/linux/litex.h
> > @@ -0,0 +1,24 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * Common LiteX header providing
> > + * helper functions for accessing CSRs.
> > + *
> > + * Implementation of the functions is provided by
> > + * the LiteX SoC Controller driver.
> > + *
> > + * Copyright (C) 2019-2020 Antmicro <www.antmicro.com>
> > + */
> > +
> > +#ifndef _LINUX_LITEX_H
> > +#define _LINUX_LITEX_H
> > +
> > +#include <linux/io.h>
> > +#include <linux/types.h>
> > +#include <linux/compiler_types.h>
> > +
> > +void litex_set_reg(void __iomem *reg, unsigned long reg_sz, unsigned long val);
> > +
> > +unsigned long litex_get_reg(void __iomem *reg, unsigned long reg_sz);
>
> Perhaps you can add static inline litex_{read,write}{8,16,32}() wrappers,
> so drivers don't have to pass the reg_sz parameter explicitly,
> and to make it look more like accessors of other bus types?

Yes, this is definitely doable.

> Gr{oetje,eeting}s,
>
>                         Geert
>
> --
> Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
>
> In personal conversations with technical people, I call myself a hacker. But
> when I'm talking to journalists I just say "programmer" or something like that.
>                                 -- Linus Torvalds

Best regards,
Mateusz

--
Mateusz Holenko
Antmicro Ltd | www.antmicro.com
Roosevelta 22, 60-829 Poznan, Poland
Geert Uytterhoeven Oct. 6, 2020, 8:38 a.m. UTC | #6
Hi Mateusz,

On Tue, Oct 6, 2020 at 10:02 AM Mateusz Holenko <mholenko@antmicro.com> wrote:
> On Fri, Sep 25, 2020 at 3:16 PM Geert Uytterhoeven <geert@linux-m68k.org> wrote:
> > On Wed, Sep 23, 2020 at 12:10 PM Mateusz Holenko <mholenko@antmicro.com> wrote:
> > > From: Pawel Czarnecki <pczarnecki@internships.antmicro.com>
> > >
> > > This commit adds driver for the FPGA-based LiteX SoC
> > > Controller from LiteX SoC builder.
> > >
> > > Co-developed-by: Mateusz Holenko <mholenko@antmicro.com>
> > > Signed-off-by: Mateusz Holenko <mholenko@antmicro.com>
> > > Signed-off-by: Pawel Czarnecki <pczarnecki@internships.antmicro.com>

> > > --- /dev/null
> > > +++ b/drivers/soc/litex/Kconfig
> > > @@ -0,0 +1,15 @@
> > > +# SPDX-License_Identifier: GPL-2.0
> > > +
> > > +menu "Enable LiteX SoC Builder specific drivers"
> > > +
> > > +config LITEX_SOC_CONTROLLER
> > > +       tristate "Enable LiteX SoC Controller driver"
> > > +       depends on OF || COMPILE_TEST
> > > +       help
> > > +         This option enables the SoC Controller Driver which verifies
> > > +         LiteX CSR access and provides common litex_get_reg/litex_set_reg
> > > +         accessors.
> > > +         All drivers that use functions from litex.h must depend on
> > > +         LITEX_SOC_CONTROLLER.
> >
> > I'm wondering if it makes sense to have them depend on a "simpler"
> > symbol instead, e.g. LITEX?
> >
> > Currently the SoC controller is limited to I/O accessors and a simple
> > register compatibility check, but you may want to extend it with more
> > features later, so you probably want to keep the LITEX_SOC_CONTROLLER.
> > Hence you could add
> >
> >     config LITEX
> >         bool
> >
> > and let LITEX_SOC_CONTROLLER select LITEX.
>
> But then if other drivers depend just on LITEX, it would not automatically
> mean that the LITEX_SOC_CONTROLLER is selected, right?. And if it's not selected
> litex_{g,s}et_reg() are not available and the compilation would fail.

As the LITEX config symbol above uses plain "bool", without a
description, it is invisible.  Hence it cannot be enabled by the user,
only be selected by other symbols.
If LITEX_SOC_CONTROLLER is the only symbol selecting LITEX, the
dependency is met.

> I could move the implementation of those functions directly to the
> litex.h header
> and avoid this KConfig dependency, but I'm not sure if they are not
> too big to become a static inline.
> What do you think?

With the spinlock and the loop, they're too large to be inlined, IMHO.

> > > --- /dev/null
> > > +++ b/drivers/soc/litex/litex_soc_ctrl.c

> > > + */
> > > +#define LITEX_REG_SIZE             0x4
> > > +#define LITEX_SUBREG_SIZE          0x1
> > > +#define LITEX_SUBREG_SIZE_BIT      (LITEX_SUBREG_SIZE * 8)
> > > +
> > > +static DEFINE_SPINLOCK(csr_lock);
> > > +
> > > +/*
> > > + * LiteX SoC Generator, depending on the configuration,
> > > + * can split a single logical CSR (Control & Status Register)
> > > + * into a series of consecutive physical registers.
> > > + *
> > > + * For example, in the configuration with 8-bit CSR Bus,
> > > + * 32-bit aligned (the default one for 32-bit CPUs) a 32-bit
> > > + * logical CSR will be generated as four 32-bit physical registers,
> > > + * each one containing one byte of meaningful data.
> > > + *
> > > + * For details see: https://github.com/enjoy-digital/litex/wiki/CSR-Bus
> > > + *
> > > + * The purpose of `litex_set_reg`/`litex_get_reg` is to implement
> > > + * the logic of writing to/reading from the LiteX CSR in a single
> > > + * place that can be then reused by all LiteX drivers.
> > > + */
> > > +void litex_set_reg(void __iomem *reg, unsigned long reg_size,
> > > +                   unsigned long val)
> > > +{
> > > +       unsigned long shifted_data, shift, i;
> > > +       unsigned long flags;
> > > +
> > > +       spin_lock_irqsave(&csr_lock, flags);
> > > +
> > > +       for (i = 0; i < reg_size; ++i) {
> > > +               shift = ((reg_size - i - 1) * LITEX_SUBREG_SIZE_BIT);
> > > +               shifted_data = val >> shift;
> > > +
> > > +               writel((u32 __force)cpu_to_le32(shifted_data), reg + (LITEX_REG_SIZE * i));
> > > +       }
> > > +
> > > +       spin_unlock_irqrestore(&csr_lock, flags);
> > > +}
> > > +EXPORT_SYMBOL_GPL(litex_set_reg);
> >
> > I'm still wondering about the overhead of loops and multiple accesses,
> > and the need for them (see also BenH's earlier comment).
> > If e.g. the register widths change for LiteUART (currently they're
> > hardcoded to one), would you still consider it using the same
> > programming interface, and thus compatible with "litex,liteuart"?
>
> Since the amount of possible `reg_size` is practically limited we could
> add explicit 8/32/64/128 accessors to eliminate loops.

Good.

(assuming 32-bit physical reg accesses below)

> As for multiple writel/readl I don't really see an option to avoid
> them for the 8-bit bus width.

Sure, 64-bit register accesses consist of two 32-bit accesses on other
32-bit platforms, too.

> > The spinlock access will probably become the source of lock contention
> > later, especially when considering SMP variants.
>
> Do you have any suggestions on how to handle this?
> Dropping locks could lead to the situation when two cores write at the
> same time leaving a wrong (mixed) value in the CSR.

Is this due to the CSR bus or due to the CSR register?
I mean can two 64-bit accesses to different CSR registers be done as
four interleaved 32-bit accesses, or must they not be interleaved?

If (hopefully) they can be interleaved, you just need serialization of
accesses to the same 64-bit register.  As the same register is usually
not accessed from multiple drivers, you can handle the serialization
inside the driver, if it can ever happen at all (e.g. main driver
operation and interrupt handler accessing the same register).
That avoids the need for the spinlock in the generic register accessors.

If they must not be interleaved, you indeed need serialization at the
bus level, but only for the 64-bit accesses?  And I would strongly
suggest to look into changing the CSR bus behavior at the hardware
level, if possible...

> > > +/*
> > > + * Check LiteX CSR read/write access
> > > + *
> > > + * This function reads and writes a scratch register in order
> > > + * to verify if CSR access works.
> > > + *
> > > + * In case any problems are detected, the driver should panic.
> > > + *
> > > + * Access to the LiteX CSR is, by design, done in CPU native
> > > + * endianness. The driver should not dynamically configure
> > > + * access functions when the endianness mismatch is detected.
> > > + * Such situation indicates problems in the soft SoC design
> > > + * and should be solved at the LiteX generator level,
> > > + * not in the software.
> > > + */
> > > +static int litex_check_csr_access(void __iomem *reg_addr)
> > > +{
> > > +       unsigned long reg;
> > > +
> > > +       reg = litex_get_reg(reg_addr + SCRATCH_REG_OFF, SCRATCH_REG_SIZE);
> > > +
> > > +       if (reg != SCRATCH_REG_VALUE) {
> > > +               panic("Scratch register read error! Expected: 0x%x but got: 0x%lx",
> > > +                       SCRATCH_REG_VALUE, reg);
> >
> > Do you think the user will ever see this panic message? (see below)
>
> On UART most probably not, as broken CSRs mean broken UART driver as well.
> But I believe you can retrieve logs from the memory and analyze them
> post-mortem, isn't that right?

Sure. Been there, done that ;-)

Gr{oetje,eeting}s,

                        Geert
Mateusz Holenko Oct. 6, 2020, 10:07 a.m. UTC | #7
Hi Gabriel,

On Fri, Sep 25, 2020 at 5:06 PM Gabriel L. Somlo <gsomlo@gmail.com> wrote:
>

> Hi Geert, Mateusz,

>

> On Fri, Sep 25, 2020 at 03:16:02PM +0200, Geert Uytterhoeven wrote:

> > Hi Mateusz,

> >

> > On Wed, Sep 23, 2020 at 12:10 PM Mateusz Holenko <mholenko@antmicro.com> wrote:

> > > From: Pawel Czarnecki <pczarnecki@internships.antmicro.com>

> > >

> > > This commit adds driver for the FPGA-based LiteX SoC

> > > Controller from LiteX SoC builder.

> > >

> > > Co-developed-by: Mateusz Holenko <mholenko@antmicro.com>

> > > Signed-off-by: Mateusz Holenko <mholenko@antmicro.com>

> > > Signed-off-by: Pawel Czarnecki <pczarnecki@internships.antmicro.com>

> >

> > Thanks for your patch!

> >

> > > --- /dev/null

> > > +++ b/drivers/soc/litex/Kconfig

> > > @@ -0,0 +1,15 @@

> > > +# SPDX-License_Identifier: GPL-2.0

> > > +

> > > +menu "Enable LiteX SoC Builder specific drivers"

> > > +

> > > +config LITEX_SOC_CONTROLLER

> > > +       tristate "Enable LiteX SoC Controller driver"

> > > +       depends on OF || COMPILE_TEST

> > > +       help

> > > +         This option enables the SoC Controller Driver which verifies

> > > +         LiteX CSR access and provides common litex_get_reg/litex_set_reg

> > > +         accessors.

> > > +         All drivers that use functions from litex.h must depend on

> > > +         LITEX_SOC_CONTROLLER.

> >

> > I'm wondering if it makes sense to have them depend on a "simpler"

> > symbol instead, e.g. LITEX?

> >

> > Currently the SoC controller is limited to I/O accessors and a simple

> > register compatibility check, but you may want to extend it with more

> > features later, so you probably want to keep the LITEX_SOC_CONTROLLER.

> > Hence you could add

> >

> >     config LITEX

> >         bool

> >

> > and let LITEX_SOC_CONTROLLER select LITEX.

> >

> > > --- /dev/null

> > > +++ b/drivers/soc/litex/litex_soc_ctrl.c

> > > @@ -0,0 +1,194 @@

> > > +// SPDX-License-Identifier: GPL-2.0

> > > +/*

> > > + * LiteX SoC Controller Driver

> > > + *

> > > + * Copyright (C) 2020 Antmicro <www.antmicro.com>

> > > + *

> > > + */

> > > +

> > > +#include <linux/litex.h>

> > > +#include <linux/device.h>

> > > +#include <linux/errno.h>

> > > +#include <linux/of.h>

> > > +#include <linux/of_platform.h>

> > > +#include <linux/platform_device.h>

> > > +#include <linux/printk.h>

> > > +#include <linux/module.h>

> > > +#include <linux/errno.h>

> > > +#include <linux/io.h>

> > > +

> > > +/*

> > > + * The parameters below are true for LiteX SoC

> >

> > SoCs

> >

> > > + * configured for 8-bit CSR Bus, 32-bit aligned.

> > > + *

> > > + * Supporting other configurations will require

> > > + * extending the logic in this header.

> >

> > This is no longer a header file.

> >

> > > + */

> > > +#define LITEX_REG_SIZE             0x4

> > > +#define LITEX_SUBREG_SIZE          0x1

> > > +#define LITEX_SUBREG_SIZE_BIT      (LITEX_SUBREG_SIZE * 8)

> > > +

> > > +static DEFINE_SPINLOCK(csr_lock);

> > > +

> > > +/*

> > > + * LiteX SoC Generator, depending on the configuration,

> > > + * can split a single logical CSR (Control & Status Register)

> > > + * into a series of consecutive physical registers.

> > > + *

> > > + * For example, in the configuration with 8-bit CSR Bus,

> > > + * 32-bit aligned (the default one for 32-bit CPUs) a 32-bit

> > > + * logical CSR will be generated as four 32-bit physical registers,

> > > + * each one containing one byte of meaningful data.

> > > + *

> > > + * For details see: https://github.com/enjoy-digital/litex/wiki/CSR-Bus

> > > + *

> > > + * The purpose of `litex_set_reg`/`litex_get_reg` is to implement

> > > + * the logic of writing to/reading from the LiteX CSR in a single

> > > + * place that can be then reused by all LiteX drivers.

> > > + */

> > > +void litex_set_reg(void __iomem *reg, unsigned long reg_size,

> > > +                   unsigned long val)

> > > +{

> > > +       unsigned long shifted_data, shift, i;

> > > +       unsigned long flags;

> > > +

> > > +       spin_lock_irqsave(&csr_lock, flags);

> > > +

> > > +       for (i = 0; i < reg_size; ++i) {

> > > +               shift = ((reg_size - i - 1) * LITEX_SUBREG_SIZE_BIT);

> > > +               shifted_data = val >> shift;

> > > +

> > > +               writel((u32 __force)cpu_to_le32(shifted_data), reg + (LITEX_REG_SIZE * i));

> > > +       }

> > > +

> > > +       spin_unlock_irqrestore(&csr_lock, flags);

> > > +}

> > > +EXPORT_SYMBOL_GPL(litex_set_reg);

> >

> > I'm still wondering about the overhead of loops and multiple accesses,

> > and the need for them (see also BenH's earlier comment).

> > If e.g. the register widths change for LiteUART (currently they're

> > hardcoded to one), would you still consider it using the same

> > programming interface, and thus compatible with "litex,liteuart"?

>

> There's been talk within the LiteX dev community to standardize on a

> LITEX_SUBREG_SIZE of 0x4 (i.e., using all 32 bits of a 32-bit

> (LITEX_REG_SIZE) aligned MMIO location). Early 32-bit (vexriscv based)

> Linux capable LiteX designs started out with only the 8 LSBits used

> within a 32-bit MMIO location, but 64-bit (Rocket chip) based LiteX SoCs

> use 4-byte aligned, fully populated MMIO registers (i.e., both

> LITEX_SUBREG_SIZE *and* LITEX_REG_SIZE are 4). There's also been talk of

> deprecating LITEX_SUBREG_SIZE == 0x1 for "linux-capable LiteX builds",

> but nothing definitive yet AFAIK.


I agree that having LITEX_SUBREG_SIZE equal to 4 would make the code
much simpler.

I believe, however, that at the moment LiteX (for 32-bit CPUs) and
both main 32-bit Linux capable LiteX-based platforms
(https://github.com/litex-hub/linux-on-litex-vexriscv and
https://github.com/timvideos/litex-buildenv) by default generate SoC
with 8-bit data width and that's why the driver currently targets this
configuration.

> As long as adding LITEX_SUBREG_SIZE 0x4 (either as a config option, or

> as a hard-coded default in a subsequent version) won't break things, we

> should be safe going forward afaict.


I'm totally open for extending/changing the default LITEX_SUBREG_SIZE
value for this driver once the default configuration for LiteX
platforms changes.

> Geert: note that LiteX has wider-than-32-bit registers spread across

> multiple 32-bit aligned, 8- or 32-bit wide "subregisters", so looping

> and shifting will still be necessary, even with LITEX_SUBREG_SIZE 0x4.


There are also situations (like the GPIO controller) where the layout
of registers is dynamic and depends on the LiteX configuration (number
of supported pins).
In this situation we need to read the configuration from DT and keep
the driver flexible by using dynamic, loop-based CSR accessors.

That's why I believe we could have both - fast, non-loop based
accessors for common registers widths 8/32/64/etc. and the current
implementation where runtime flexibility is required (at the cost of
performance).

> > The spinlock access will probably become the source of lock contention

> > later, especially when considering SMP variants.

> >

> > > +/*

> > > + * Check LiteX CSR read/write access

> > > + *

> > > + * This function reads and writes a scratch register in order

> > > + * to verify if CSR access works.

> > > + *

> > > + * In case any problems are detected, the driver should panic.

> > > + *

> > > + * Access to the LiteX CSR is, by design, done in CPU native

> > > + * endianness. The driver should not dynamically configure

> > > + * access functions when the endianness mismatch is detected.

> > > + * Such situation indicates problems in the soft SoC design

> > > + * and should be solved at the LiteX generator level,

> > > + * not in the software.

> > > + */

> > > +static int litex_check_csr_access(void __iomem *reg_addr)

> > > +{

> > > +       unsigned long reg;

> > > +

> > > +       reg = litex_get_reg(reg_addr + SCRATCH_REG_OFF, SCRATCH_REG_SIZE);

> > > +

> > > +       if (reg != SCRATCH_REG_VALUE) {

> > > +               panic("Scratch register read error! Expected: 0x%x but got: 0x%lx",

> > > +                       SCRATCH_REG_VALUE, reg);

> >

> > Do you think the user will ever see this panic message? (see below)

> >

> > > +               return -EINVAL;

> >

> > Good ;-)  All of BUG()/WARN()/panic() may be compiled out, depending on

> > config options, so the system may continue running beyond the panic()

> > call.

> >

> > > +static int litex_soc_ctrl_probe(struct platform_device *pdev)

> > > +{

> > > +       int result;

> > > +       struct device *dev;

> > > +       struct device_node *node;

> > > +       struct litex_soc_ctrl_device *soc_ctrl_dev;

> > > +

> > > +       dev = &pdev->dev;

> > > +       node = dev->of_node;

> > > +       if (!node)

> > > +               return -ENODEV;

> >

> > FYI, this cannot happen.

> >

> > > +

> > > +       soc_ctrl_dev = devm_kzalloc(dev, sizeof(*soc_ctrl_dev), GFP_KERNEL);

> > > +       if (!soc_ctrl_dev)

> > > +               return -ENOMEM;

> > > +

> > > +       soc_ctrl_dev->base = devm_platform_ioremap_resource(pdev, 0);

> > > +       if (IS_ERR(soc_ctrl_dev->base))

> > > +               return PTR_ERR(soc_ctrl_dev->base);

> > > +

> > > +       result = litex_check_csr_access(soc_ctrl_dev->base);

> > > +       if (result) {

> > > +               /* LiteX CSRs access is broken which means that

> > > +                * none of LiteX drivers will most probably

> > > +                * operate correctly

> > > +                */

> > > +               WARN(1, "Failed to validate CSR registers, the system is probably broken.\n");

> >

> > WARN(result, ...)

> >

> > But is this WARN() needed? You have already called panic() before.

> >

> > > +       }

> > > +

> > > +       return result;

> > > +}

> > > +

> > > +static struct platform_driver litex_soc_ctrl_driver = {

> > > +       .driver = {

> > > +               .name = "litex-soc-controller",

> > > +               .of_match_table = of_match_ptr(litex_soc_ctrl_of_match)

> > > +       },

> > > +       .probe = litex_soc_ctrl_probe,

> > > +};

> > > +

> > > +module_platform_driver(litex_soc_ctrl_driver);

> >

> > module_platform_driver() means this driver is probed quite late in the

> > boot sequence.  Currently the only other LiteX driver is liteuart, which

> > is probed at more or less the same time, but I can envision more early

> > drivers to be added later (typically interrupt/clock controllers and

> > timers not integrated into the main CPU core).

> > Note that even liteuart will run earlier, and thus access CSR registers

> > before the check has run, when using e.g. earlycon...

> >

> > > --- /dev/null

> > > +++ b/include/linux/litex.h

> > > @@ -0,0 +1,24 @@

> > > +/* SPDX-License-Identifier: GPL-2.0 */

> > > +/*

> > > + * Common LiteX header providing

> > > + * helper functions for accessing CSRs.

> > > + *

> > > + * Implementation of the functions is provided by

> > > + * the LiteX SoC Controller driver.

> > > + *

> > > + * Copyright (C) 2019-2020 Antmicro <www.antmicro.com>

> > > + */

> > > +

> > > +#ifndef _LINUX_LITEX_H

> > > +#define _LINUX_LITEX_H

> > > +

> > > +#include <linux/io.h>

> > > +#include <linux/types.h>

> > > +#include <linux/compiler_types.h>

> > > +

> > > +void litex_set_reg(void __iomem *reg, unsigned long reg_sz, unsigned long val);

> > > +

> > > +unsigned long litex_get_reg(void __iomem *reg, unsigned long reg_sz);

> >

> > Perhaps you can add static inline litex_{read,write}{8,16,32}() wrappers,

> > so drivers don't have to pass the reg_sz parameter explicitly,

> > and to make it look more like accessors of other bus types?

>

> Seconded -- perhaps simply cut'n'paste and/or adapt from

> https://github.com/litex-hub/linux/blob/litex-rocket-rebase/include/linux/litex.h#L78

> (from the 64-bit port of the LiteX linux patch set)

>

> Cheers,

> --Gabriel


Best regards,
Mateusz

--
Mateusz Holenko
Antmicro Ltd | www.antmicro.com
Roosevelta 22, 60-829 Poznan, Poland
Mateusz Holenko Oct. 6, 2020, 1:29 p.m. UTC | #8
On Tue, Oct 6, 2020 at 10:38 AM Geert Uytterhoeven <geert@linux-m68k.org> wrote:
>

> Hi Mateusz,

>

> On Tue, Oct 6, 2020 at 10:02 AM Mateusz Holenko <mholenko@antmicro.com> wrote:

> > On Fri, Sep 25, 2020 at 3:16 PM Geert Uytterhoeven <geert@linux-m68k.org> wrote:

> > > On Wed, Sep 23, 2020 at 12:10 PM Mateusz Holenko <mholenko@antmicro.com> wrote:

> > > > From: Pawel Czarnecki <pczarnecki@internships.antmicro.com>

> > > >

> > > > This commit adds driver for the FPGA-based LiteX SoC

> > > > Controller from LiteX SoC builder.

> > > >

> > > > Co-developed-by: Mateusz Holenko <mholenko@antmicro.com>

> > > > Signed-off-by: Mateusz Holenko <mholenko@antmicro.com>

> > > > Signed-off-by: Pawel Czarnecki <pczarnecki@internships.antmicro.com>

>

> > > > --- /dev/null

> > > > +++ b/drivers/soc/litex/Kconfig

> > > > @@ -0,0 +1,15 @@

> > > > +# SPDX-License_Identifier: GPL-2.0

> > > > +

> > > > +menu "Enable LiteX SoC Builder specific drivers"

> > > > +

> > > > +config LITEX_SOC_CONTROLLER

> > > > +       tristate "Enable LiteX SoC Controller driver"

> > > > +       depends on OF || COMPILE_TEST

> > > > +       help

> > > > +         This option enables the SoC Controller Driver which verifies

> > > > +         LiteX CSR access and provides common litex_get_reg/litex_set_reg

> > > > +         accessors.

> > > > +         All drivers that use functions from litex.h must depend on

> > > > +         LITEX_SOC_CONTROLLER.

> > >

> > > I'm wondering if it makes sense to have them depend on a "simpler"

> > > symbol instead, e.g. LITEX?

> > >

> > > Currently the SoC controller is limited to I/O accessors and a simple

> > > register compatibility check, but you may want to extend it with more

> > > features later, so you probably want to keep the LITEX_SOC_CONTROLLER.

> > > Hence you could add

> > >

> > >     config LITEX

> > >         bool

> > >

> > > and let LITEX_SOC_CONTROLLER select LITEX.

> >

> > But then if other drivers depend just on LITEX, it would not automatically

> > mean that the LITEX_SOC_CONTROLLER is selected, right?. And if it's not selected

> > litex_{g,s}et_reg() are not available and the compilation would fail.

>

> As the LITEX config symbol above uses plain "bool", without a

> description, it is invisible.  Hence it cannot be enabled by the user,

> only be selected by other symbols.

> If LITEX_SOC_CONTROLLER is the only symbol selecting LITEX, the

> dependency is met.

>

> > I could move the implementation of those functions directly to the

> > litex.h header

> > and avoid this KConfig dependency, but I'm not sure if they are not

> > too big to become a static inline.

> > What do you think?

>

> With the spinlock and the loop, they're too large to be inlined, IMHO.


Sure.

> > > > --- /dev/null

> > > > +++ b/drivers/soc/litex/litex_soc_ctrl.c

>

> > > > + */

> > > > +#define LITEX_REG_SIZE             0x4

> > > > +#define LITEX_SUBREG_SIZE          0x1

> > > > +#define LITEX_SUBREG_SIZE_BIT      (LITEX_SUBREG_SIZE * 8)

> > > > +

> > > > +static DEFINE_SPINLOCK(csr_lock);

> > > > +

> > > > +/*

> > > > + * LiteX SoC Generator, depending on the configuration,

> > > > + * can split a single logical CSR (Control & Status Register)

> > > > + * into a series of consecutive physical registers.

> > > > + *

> > > > + * For example, in the configuration with 8-bit CSR Bus,

> > > > + * 32-bit aligned (the default one for 32-bit CPUs) a 32-bit

> > > > + * logical CSR will be generated as four 32-bit physical registers,

> > > > + * each one containing one byte of meaningful data.

> > > > + *

> > > > + * For details see: https://github.com/enjoy-digital/litex/wiki/CSR-Bus

> > > > + *

> > > > + * The purpose of `litex_set_reg`/`litex_get_reg` is to implement

> > > > + * the logic of writing to/reading from the LiteX CSR in a single

> > > > + * place that can be then reused by all LiteX drivers.

> > > > + */

> > > > +void litex_set_reg(void __iomem *reg, unsigned long reg_size,

> > > > +                   unsigned long val)

> > > > +{

> > > > +       unsigned long shifted_data, shift, i;

> > > > +       unsigned long flags;

> > > > +

> > > > +       spin_lock_irqsave(&csr_lock, flags);

> > > > +

> > > > +       for (i = 0; i < reg_size; ++i) {

> > > > +               shift = ((reg_size - i - 1) * LITEX_SUBREG_SIZE_BIT);

> > > > +               shifted_data = val >> shift;

> > > > +

> > > > +               writel((u32 __force)cpu_to_le32(shifted_data), reg + (LITEX_REG_SIZE * i));

> > > > +       }

> > > > +

> > > > +       spin_unlock_irqrestore(&csr_lock, flags);

> > > > +}

> > > > +EXPORT_SYMBOL_GPL(litex_set_reg);

> > >

> > > I'm still wondering about the overhead of loops and multiple accesses,

> > > and the need for them (see also BenH's earlier comment).

> > > If e.g. the register widths change for LiteUART (currently they're

> > > hardcoded to one), would you still consider it using the same

> > > programming interface, and thus compatible with "litex,liteuart"?

> >

> > Since the amount of possible `reg_size` is practically limited we could

> > add explicit 8/32/64/128 accessors to eliminate loops.

>

> Good.

>

> (assuming 32-bit physical reg accesses below)

>

> > As for multiple writel/readl I don't really see an option to avoid

> > them for the 8-bit bus width.

>

> Sure, 64-bit register accesses consist of two 32-bit accesses on other

> 32-bit platforms, too.

>

> > > The spinlock access will probably become the source of lock contention

> > > later, especially when considering SMP variants.

> >

> > Do you have any suggestions on how to handle this?

> > Dropping locks could lead to the situation when two cores write at the

> > same time leaving a wrong (mixed) value in the CSR.

>

> Is this due to the CSR bus or due to the CSR register?

> I mean can two 64-bit accesses to different CSR registers be done as

> four interleaved 32-bit accesses, or must they not be interleaved?

>

> If (hopefully) they can be interleaved, you just need serialization of

> accesses to the same 64-bit register.  As the same register is usually

> not accessed from multiple drivers, you can handle the serialization

> inside the driver, if it can ever happen at all (e.g. main driver

> operation and interrupt handler accessing the same register).

> That avoids the need for the spinlock in the generic register accessors.

> If they must not be interleaved, you indeed need serialization at the

> bus level, but only for the 64-bit accesses?  And I would strongly

> suggest to look into changing the CSR bus behavior at the hardware

> level, if possible...


Good point. I was thinking about the single CSR register consistency,
not the whole bus.

Changing the CSR behaviour at the LiteX level is something that is
currently discussed by the developers, but I'm not aware of any
timeline.
I believe we can always simplify the driver's code in the future, once
the HW becomes better suited for Linux support in the default
configuration.

> > > > +/*

> > > > + * Check LiteX CSR read/write access

> > > > + *

> > > > + * This function reads and writes a scratch register in order

> > > > + * to verify if CSR access works.

> > > > + *

> > > > + * In case any problems are detected, the driver should panic.

> > > > + *

> > > > + * Access to the LiteX CSR is, by design, done in CPU native

> > > > + * endianness. The driver should not dynamically configure

> > > > + * access functions when the endianness mismatch is detected.

> > > > + * Such situation indicates problems in the soft SoC design

> > > > + * and should be solved at the LiteX generator level,

> > > > + * not in the software.

> > > > + */

> > > > +static int litex_check_csr_access(void __iomem *reg_addr)

> > > > +{

> > > > +       unsigned long reg;

> > > > +

> > > > +       reg = litex_get_reg(reg_addr + SCRATCH_REG_OFF, SCRATCH_REG_SIZE);

> > > > +

> > > > +       if (reg != SCRATCH_REG_VALUE) {

> > > > +               panic("Scratch register read error! Expected: 0x%x but got: 0x%lx",

> > > > +                       SCRATCH_REG_VALUE, reg);

> > >

> > > Do you think the user will ever see this panic message? (see below)

> >

> > On UART most probably not, as broken CSRs mean broken UART driver as well.

> > But I believe you can retrieve logs from the memory and analyze them

> > post-mortem, isn't that right?

>

> Sure. Been there, done that ;-)

>

> Gr{oetje,eeting}s,

>

>                         Geert

>

> --

> Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

>

> In personal conversations with technical people, I call myself a hacker. But

> when I'm talking to journalists I just say "programmer" or something like that.

>                                 -- Linus Torvalds


Best,
Mateusz

--
Mateusz Holenko
Antmicro Ltd | www.antmicro.com
Roosevelta 22, 60-829 Poznan, Poland
diff mbox series

Patch

diff --git a/MAINTAINERS b/MAINTAINERS
index 39be98db7418..4d70a1b22a87 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9840,6 +9840,8 @@  M:	Karol Gugala <kgugala@antmicro.com>
 M:	Mateusz Holenko <mholenko@antmicro.com>
 S:	Maintained
 F:	Documentation/devicetree/bindings/*/litex,*.yaml
+F:	drivers/soc/litex/litex_soc_ctrl.c
+F:	include/linux/litex.h
 
 LIVE PATCHING
 M:	Josh Poimboeuf <jpoimboe@redhat.com>
diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig
index 425ab6f7e375..d097d070f579 100644
--- a/drivers/soc/Kconfig
+++ b/drivers/soc/Kconfig
@@ -9,6 +9,7 @@  source "drivers/soc/bcm/Kconfig"
 source "drivers/soc/fsl/Kconfig"
 source "drivers/soc/imx/Kconfig"
 source "drivers/soc/ixp4xx/Kconfig"
+source "drivers/soc/litex/Kconfig"
 source "drivers/soc/mediatek/Kconfig"
 source "drivers/soc/qcom/Kconfig"
 source "drivers/soc/renesas/Kconfig"
diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile
index 36452bed86ef..0b16108823ef 100644
--- a/drivers/soc/Makefile
+++ b/drivers/soc/Makefile
@@ -14,6 +14,7 @@  obj-$(CONFIG_ARCH_GEMINI)	+= gemini/
 obj-y				+= imx/
 obj-$(CONFIG_ARCH_IXP4XX)	+= ixp4xx/
 obj-$(CONFIG_SOC_XWAY)		+= lantiq/
+obj-$(CONFIG_LITEX_SOC_CONTROLLER) += litex/
 obj-y				+= mediatek/
 obj-y				+= amlogic/
 obj-y				+= qcom/
diff --git a/drivers/soc/litex/Kconfig b/drivers/soc/litex/Kconfig
new file mode 100644
index 000000000000..c974ec3846bc
--- /dev/null
+++ b/drivers/soc/litex/Kconfig
@@ -0,0 +1,15 @@ 
+# SPDX-License_Identifier: GPL-2.0
+
+menu "Enable LiteX SoC Builder specific drivers"
+
+config LITEX_SOC_CONTROLLER
+	tristate "Enable LiteX SoC Controller driver"
+	depends on OF || COMPILE_TEST
+	help
+	  This option enables the SoC Controller Driver which verifies
+	  LiteX CSR access and provides common litex_get_reg/litex_set_reg
+	  accessors.
+	  All drivers that use functions from litex.h must depend on
+	  LITEX_SOC_CONTROLLER.
+
+endmenu
diff --git a/drivers/soc/litex/Makefile b/drivers/soc/litex/Makefile
new file mode 100644
index 000000000000..98ff7325b1c0
--- /dev/null
+++ b/drivers/soc/litex/Makefile
@@ -0,0 +1,3 @@ 
+# SPDX-License_Identifier: GPL-2.0
+
+obj-$(CONFIG_LITEX_SOC_CONTROLLER)	+= litex_soc_ctrl.o
diff --git a/drivers/soc/litex/litex_soc_ctrl.c b/drivers/soc/litex/litex_soc_ctrl.c
new file mode 100644
index 000000000000..08330c9872b0
--- /dev/null
+++ b/drivers/soc/litex/litex_soc_ctrl.c
@@ -0,0 +1,194 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * LiteX SoC Controller Driver
+ *
+ * Copyright (C) 2020 Antmicro <www.antmicro.com>
+ *
+ */
+
+#include <linux/litex.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/printk.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+
+/*
+ * The parameters below are true for LiteX SoC
+ * configured for 8-bit CSR Bus, 32-bit aligned.
+ *
+ * Supporting other configurations will require
+ * extending the logic in this header.
+ */
+#define LITEX_REG_SIZE             0x4
+#define LITEX_SUBREG_SIZE          0x1
+#define LITEX_SUBREG_SIZE_BIT      (LITEX_SUBREG_SIZE * 8)
+
+static DEFINE_SPINLOCK(csr_lock);
+
+/*
+ * LiteX SoC Generator, depending on the configuration,
+ * can split a single logical CSR (Control & Status Register)
+ * into a series of consecutive physical registers.
+ *
+ * For example, in the configuration with 8-bit CSR Bus,
+ * 32-bit aligned (the default one for 32-bit CPUs) a 32-bit
+ * logical CSR will be generated as four 32-bit physical registers,
+ * each one containing one byte of meaningful data.
+ *
+ * For details see: https://github.com/enjoy-digital/litex/wiki/CSR-Bus
+ *
+ * The purpose of `litex_set_reg`/`litex_get_reg` is to implement
+ * the logic of writing to/reading from the LiteX CSR in a single
+ * place that can be then reused by all LiteX drivers.
+ */
+void litex_set_reg(void __iomem *reg, unsigned long reg_size,
+		    unsigned long val)
+{
+	unsigned long shifted_data, shift, i;
+	unsigned long flags;
+
+	spin_lock_irqsave(&csr_lock, flags);
+
+	for (i = 0; i < reg_size; ++i) {
+		shift = ((reg_size - i - 1) * LITEX_SUBREG_SIZE_BIT);
+		shifted_data = val >> shift;
+
+		writel((u32 __force)cpu_to_le32(shifted_data), reg + (LITEX_REG_SIZE * i));
+	}
+
+	spin_unlock_irqrestore(&csr_lock, flags);
+}
+EXPORT_SYMBOL_GPL(litex_set_reg);
+
+unsigned long litex_get_reg(void __iomem *reg, unsigned long reg_size)
+{
+	unsigned long shifted_data, shift, i;
+	unsigned long result = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&csr_lock, flags);
+
+	for (i = 0; i < reg_size; ++i) {
+		shifted_data = le32_to_cpu((__le32 __force)readl(reg + (LITEX_REG_SIZE * i)));
+
+		shift = ((reg_size - i - 1) * LITEX_SUBREG_SIZE_BIT);
+		result |= (shifted_data << shift);
+	}
+
+	spin_unlock_irqrestore(&csr_lock, flags);
+
+	return result;
+}
+EXPORT_SYMBOL_GPL(litex_get_reg);
+
+#define SCRATCH_REG_OFF         0x04
+#define SCRATCH_REG_SIZE        4
+#define SCRATCH_REG_VALUE       0x12345678
+#define SCRATCH_TEST_VALUE      0xdeadbeef
+
+/*
+ * Check LiteX CSR read/write access
+ *
+ * This function reads and writes a scratch register in order
+ * to verify if CSR access works.
+ *
+ * In case any problems are detected, the driver should panic.
+ *
+ * Access to the LiteX CSR is, by design, done in CPU native
+ * endianness. The driver should not dynamically configure
+ * access functions when the endianness mismatch is detected.
+ * Such situation indicates problems in the soft SoC design
+ * and should be solved at the LiteX generator level,
+ * not in the software.
+ */
+static int litex_check_csr_access(void __iomem *reg_addr)
+{
+	unsigned long reg;
+
+	reg = litex_get_reg(reg_addr + SCRATCH_REG_OFF, SCRATCH_REG_SIZE);
+
+	if (reg != SCRATCH_REG_VALUE) {
+		panic("Scratch register read error! Expected: 0x%x but got: 0x%lx",
+			SCRATCH_REG_VALUE, reg);
+		return -EINVAL;
+	}
+
+	litex_set_reg(reg_addr + SCRATCH_REG_OFF,
+		SCRATCH_REG_SIZE, SCRATCH_TEST_VALUE);
+	reg = litex_get_reg(reg_addr + SCRATCH_REG_OFF, SCRATCH_REG_SIZE);
+
+	if (reg != SCRATCH_TEST_VALUE) {
+		panic("Scratch register write error! Expected: 0x%x but got: 0x%lx",
+			SCRATCH_TEST_VALUE, reg);
+		return -EINVAL;
+	}
+
+	/* restore original value of the SCRATCH register */
+	litex_set_reg(reg_addr + SCRATCH_REG_OFF,
+		SCRATCH_REG_SIZE, SCRATCH_REG_VALUE);
+
+	pr_info("LiteX SoC Controller driver initialized");
+
+	return 0;
+}
+
+struct litex_soc_ctrl_device {
+	void __iomem *base;
+};
+
+static const struct of_device_id litex_soc_ctrl_of_match[] = {
+	{.compatible = "litex,soc-controller"},
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, litex_soc_ctrl_of_match);
+
+static int litex_soc_ctrl_probe(struct platform_device *pdev)
+{
+	int result;
+	struct device *dev;
+	struct device_node *node;
+	struct litex_soc_ctrl_device *soc_ctrl_dev;
+
+	dev = &pdev->dev;
+	node = dev->of_node;
+	if (!node)
+		return -ENODEV;
+
+	soc_ctrl_dev = devm_kzalloc(dev, sizeof(*soc_ctrl_dev), GFP_KERNEL);
+	if (!soc_ctrl_dev)
+		return -ENOMEM;
+
+	soc_ctrl_dev->base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(soc_ctrl_dev->base))
+		return PTR_ERR(soc_ctrl_dev->base);
+
+	result = litex_check_csr_access(soc_ctrl_dev->base);
+	if (result) {
+		/* LiteX CSRs access is broken which means that
+		 * none of LiteX drivers will most probably
+		 * operate correctly
+		 */
+		WARN(1, "Failed to validate CSR registers, the system is probably broken.\n");
+	}
+
+	return result;
+}
+
+static struct platform_driver litex_soc_ctrl_driver = {
+	.driver = {
+		.name = "litex-soc-controller",
+		.of_match_table = of_match_ptr(litex_soc_ctrl_of_match)
+	},
+	.probe = litex_soc_ctrl_probe,
+};
+
+module_platform_driver(litex_soc_ctrl_driver);
+MODULE_DESCRIPTION("LiteX SoC Controller driver");
+MODULE_AUTHOR("Antmicro <www.antmicro.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/litex.h b/include/linux/litex.h
new file mode 100644
index 000000000000..72061018c172
--- /dev/null
+++ b/include/linux/litex.h
@@ -0,0 +1,24 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Common LiteX header providing
+ * helper functions for accessing CSRs.
+ *
+ * Implementation of the functions is provided by
+ * the LiteX SoC Controller driver.
+ *
+ * Copyright (C) 2019-2020 Antmicro <www.antmicro.com>
+ */
+
+#ifndef _LINUX_LITEX_H
+#define _LINUX_LITEX_H
+
+#include <linux/io.h>
+#include <linux/types.h>
+#include <linux/compiler_types.h>
+
+void litex_set_reg(void __iomem *reg, unsigned long reg_sz, unsigned long val);
+
+unsigned long litex_get_reg(void __iomem *reg, unsigned long reg_sz);
+
+
+#endif /* _LINUX_LITEX_H */