[U-Boot] [PATCH v2 1/5] regmap: Add size parameter

The regmap functions currently assume that all register map accesses have a data width of 32 bits, but there are maps that have different widths.
Implement a size parameter for the regmap_read and regmap_write functions to specify the width of a desired read or write operation on a regmap.
Correct all current clients of the regmap API to use 32 bit width reads and writes to keep backwards compatibility.
Signed-off-by: Mario Six mario.six@gdsys.cc ---
v1 -> v2: New in v2
--- drivers/clk/at91/clk-utmi.c | 6 +++-- drivers/clk/clk_boston.c | 3 ++- drivers/core/regmap.c | 45 ++++++++++++++++++++++++------- drivers/phy/meson-gxl-usb2.c | 18 ++++++------- drivers/phy/meson-gxl-usb3.c | 22 +++++++-------- drivers/power/regulator/pbias_regulator.c | 5 ++-- drivers/reset/reset-meson.c | 14 +++++----- drivers/sysreset/sysreset_syscon.c | 2 +- include/regmap.h | 11 ++++++-- 9 files changed, 82 insertions(+), 44 deletions(-)
diff --git a/drivers/clk/at91/clk-utmi.c b/drivers/clk/at91/clk-utmi.c index 875bf293f9..1da625cab1 100644 --- a/drivers/clk/at91/clk-utmi.c +++ b/drivers/clk/at91/clk-utmi.c @@ -68,13 +68,15 @@ static int utmi_clk_enable(struct clk *clk) }
if (plat->regmap_sfr) { - err = regmap_read(plat->regmap_sfr, AT91_SFR_UTMICKTRIM, &tmp); + err = regmap_read(plat->regmap_sfr, AT91_SFR_UTMICKTRIM, &tmp, + REGMAP_SIZE_32); if (err) return -EINVAL;
tmp &= ~AT91_UTMICKTRIM_FREQ; tmp |= utmi_ref_clk_freq; - err = regmap_write(plat->regmap_sfr, AT91_SFR_UTMICKTRIM, tmp); + err = regmap_write(plat->regmap_sfr, AT91_SFR_UTMICKTRIM, tmp, + REGMAP_SIZE_32); if (err) return -EINVAL; } else if (utmi_ref_clk_freq) { diff --git a/drivers/clk/clk_boston.c b/drivers/clk/clk_boston.c index 5c05e3d78d..e09fd06fa0 100644 --- a/drivers/clk/clk_boston.c +++ b/drivers/clk/clk_boston.c @@ -33,7 +33,8 @@ static ulong clk_boston_get_rate(struct clk *clk) uint mmcmdiv; int err;
- err = regmap_read(state->regmap, BOSTON_PLAT_MMCMDIV, &mmcmdiv); + err = regmap_read(state->regmap, BOSTON_PLAT_MMCMDIV, &mmcmdiv, + REGMAP_SIZE_32); if (err) return 0;
diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c index 8a0e00ff9a..c2cdff3979 100644 --- a/drivers/core/regmap.c +++ b/drivers/core/regmap.c @@ -130,20 +130,47 @@ int regmap_uninit(struct regmap *map) return 0; }
-int regmap_read(struct regmap *map, uint offset, uint *valp) +int regmap_read(struct regmap *map, ulong offset, ulong *valp, + enum regmap_size_t size) { - uint32_t *ptr = map_physmem(map->base + offset, 4, MAP_NOCACHE); - - *valp = le32_to_cpu(readl(ptr)); - + void *ptr; + + switch (size) { + case REGMAP_SIZE_8: + ptr = map_physmem(map->base + offset, 1, MAP_NOCACHE); + *valp = readb(ptr); + break; + case REGMAP_SIZE_16: + ptr = map_physmem(map->base + offset, 2, MAP_NOCACHE); + *valp = le16_to_cpu(readw(ptr)); + break; + case REGMAP_SIZE_32: + ptr = map_physmem(map->base + offset, 4, MAP_NOCACHE); + *valp = le32_to_cpu(readl(ptr)); + break; + } return 0; }
-int regmap_write(struct regmap *map, uint offset, uint val) +int regmap_write(struct regmap *map, ulong offset, ulong val, + enum regmap_size_t size) { - uint32_t *ptr = map_physmem(map->base + offset, 4, MAP_NOCACHE); - - writel(cpu_to_le32(val), ptr); + void *ptr; + + switch (size) { + case REGMAP_SIZE_8: + ptr = map_physmem(map->base + offset, 1, MAP_NOCACHE); + writel((u8)val, ptr); + break; + case REGMAP_SIZE_16: + ptr = map_physmem(map->base + offset, 2, MAP_NOCACHE); + writel(cpu_to_le16((u16)val), ptr); + break; + case REGMAP_SIZE_32: + ptr = map_physmem(map->base + offset, 4, MAP_NOCACHE); + writel(cpu_to_le32((u32)val), ptr); + break; + }
return 0; } diff --git a/drivers/phy/meson-gxl-usb2.c b/drivers/phy/meson-gxl-usb2.c index 15c9c89fd9..704b78747c 100644 --- a/drivers/phy/meson-gxl-usb2.c +++ b/drivers/phy/meson-gxl-usb2.c @@ -111,15 +111,15 @@ static void phy_meson_gxl_usb2_reset(struct phy_meson_gxl_usb2_priv *priv) { uint val;
- regmap_read(priv->regmap, U2P_R0, &val); + regmap_read(priv->regmap, U2P_R0, &val, REGMAP_SIZE_32);
/* reset the PHY and wait until settings are stabilized */ val |= U2P_R0_POWER_ON_RESET; - regmap_write(priv->regmap, U2P_R0, val); + regmap_write(priv->regmap, U2P_R0, val, REGMAP_SIZE_32); udelay(RESET_COMPLETE_TIME);
val &= ~U2P_R0_POWER_ON_RESET; - regmap_write(priv->regmap, U2P_R0, val); + regmap_write(priv->regmap, U2P_R0, val, REGMAP_SIZE_32); udelay(RESET_COMPLETE_TIME); }
@@ -128,11 +128,11 @@ phy_meson_gxl_usb2_set_host_mode(struct phy_meson_gxl_usb2_priv *priv) { uint val;
- regmap_read(priv->regmap, U2P_R0, &val); + regmap_read(priv->regmap, U2P_R0, &val, REGMAP_SIZE_32); val |= U2P_R0_DM_PULLDOWN; val |= U2P_R0_DP_PULLDOWN; val &= ~U2P_R0_ID_PULLUP; - regmap_write(priv->regmap, U2P_R0, val); + regmap_write(priv->regmap, U2P_R0, val, REGMAP_SIZE_32);
phy_meson_gxl_usb2_reset(priv); } @@ -143,10 +143,10 @@ static int phy_meson_gxl_usb2_power_on(struct phy *phy) struct phy_meson_gxl_usb2_priv *priv = dev_get_priv(dev); uint val;
- regmap_read(priv->regmap, U2P_R0, &val); + regmap_read(priv->regmap, U2P_R0, &val, REGMAP_SIZE_32); /* power on the PHY by taking it out of reset mode */ val &= ~U2P_R0_POWER_ON_RESET; - regmap_write(priv->regmap, U2P_R0, val); + regmap_write(priv->regmap, U2P_R0, val, REGMAP_SIZE_32);
phy_meson_gxl_usb2_set_host_mode(priv);
@@ -167,10 +167,10 @@ static int phy_meson_gxl_usb2_power_off(struct phy *phy) struct phy_meson_gxl_usb2_priv *priv = dev_get_priv(dev); uint val;
- regmap_read(priv->regmap, U2P_R0, &val); + regmap_read(priv->regmap, U2P_R0, &val, REGMAP_SIZE_32); /* power off the PHY by putting it into reset mode */ val |= U2P_R0_POWER_ON_RESET; - regmap_write(priv->regmap, U2P_R0, val); + regmap_write(priv->regmap, U2P_R0, val, REGMAP_SIZE_32);
#if CONFIG_IS_ENABLED(DM_REGULATOR) if (priv->phy_supply) { diff --git a/drivers/phy/meson-gxl-usb3.c b/drivers/phy/meson-gxl-usb3.c index a385fbdf12..33c24fd989 100644 --- a/drivers/phy/meson-gxl-usb3.c +++ b/drivers/phy/meson-gxl-usb3.c @@ -100,13 +100,13 @@ phy_meson_gxl_usb3_set_host_mode(struct phy_meson_gxl_usb3_priv *priv) { uint val;
- regmap_read(priv->regmap, USB_R0, &val); + regmap_read(priv->regmap, USB_R0, &val, REGMAP_SIZE_32); val &= ~USB_R0_U2D_ACT; - regmap_write(priv->regmap, USB_R0, val); + regmap_write(priv->regmap, USB_R0, val, REGMAP_SIZE_32);
- regmap_read(priv->regmap, USB_R4, &val); + regmap_read(priv->regmap, USB_R4, &val, REGMAP_SIZE_32); val &= ~USB_R4_P21_SLEEP_M0; - regmap_write(priv->regmap, USB_R4, val); + regmap_write(priv->regmap, USB_R4, val, REGMAP_SIZE_32);
return 0; } @@ -117,12 +117,12 @@ static int phy_meson_gxl_usb3_power_on(struct phy *phy) struct phy_meson_gxl_usb3_priv *priv = dev_get_priv(dev); uint val;
- regmap_read(priv->regmap, USB_R5, &val); + regmap_read(priv->regmap, USB_R5, &val, REGMAP_SIZE_32); val |= USB_R5_ID_DIG_EN_0; val |= USB_R5_ID_DIG_EN_1; val &= ~USB_R5_ID_DIG_TH_MASK; val |= FIELD_PREP(USB_R5_ID_DIG_TH_MASK, 0xff); - regmap_write(priv->regmap, USB_R5, val); + regmap_write(priv->regmap, USB_R5, val, REGMAP_SIZE_32);
return phy_meson_gxl_usb3_set_host_mode(priv); } @@ -133,10 +133,10 @@ static int phy_meson_gxl_usb3_power_off(struct phy *phy) struct phy_meson_gxl_usb3_priv *priv = dev_get_priv(dev); uint val;
- regmap_read(priv->regmap, USB_R5, &val); + regmap_read(priv->regmap, USB_R5, &val, REGMAP_SIZE_32); val &= ~USB_R5_ID_DIG_EN_0; val &= ~USB_R5_ID_DIG_EN_1; - regmap_write(priv->regmap, USB_R5, val); + regmap_write(priv->regmap, USB_R5, val, REGMAP_SIZE_32);
return 0; } @@ -147,10 +147,10 @@ static int phy_meson_gxl_usb3_init(struct phy *phy) struct phy_meson_gxl_usb3_priv *priv = dev_get_priv(dev); uint val;
- regmap_read(priv->regmap, USB_R1, &val); + regmap_read(priv->regmap, USB_R1, &val, REGMAP_SIZE_32); val &= ~USB_R1_U3H_FLADJ_30MHZ_REG_MASK; val |= FIELD_PREP(USB_R1_U3H_FLADJ_30MHZ_REG_MASK, 0x20); - regmap_write(priv->regmap, USB_R1, val); + regmap_write(priv->regmap, USB_R1, val, REGMAP_SIZE_32);
return 0; } @@ -169,7 +169,7 @@ int meson_gxl_usb3_phy_probe(struct udevice *dev) ret = regmap_init_mem(dev, &priv->regmap); if (ret) return ret; - + #if CONFIG_IS_ENABLED(CLK) ret = clk_get_by_index(dev, 0, &priv->clk); if (ret < 0) diff --git a/drivers/power/regulator/pbias_regulator.c b/drivers/power/regulator/pbias_regulator.c index adf589b224..386da3a58f 100644 --- a/drivers/power/regulator/pbias_regulator.c +++ b/drivers/power/regulator/pbias_regulator.c @@ -46,7 +46,7 @@ static int pbias_write(struct udevice *dev, uint reg, const uint8_t *buff, if (len != 4) return -EINVAL;
- return regmap_write(priv->regmap, priv->offset, val); + return regmap_write(priv->regmap, priv->offset, val, REGMAP_SIZE_32); }
static int pbias_read(struct udevice *dev, uint reg, uint8_t *buff, int len) @@ -56,7 +56,8 @@ static int pbias_read(struct udevice *dev, uint reg, uint8_t *buff, int len) if (len != 4) return -EINVAL;
- return regmap_read(priv->regmap, priv->offset, (u32 *)buff); + return regmap_read(priv->regmap, priv->offset, (u32 *)buff, + REGMAP_SIZE_32); }
static int pbias_ofdata_to_platdata(struct udevice *dev) diff --git a/drivers/reset/reset-meson.c b/drivers/reset/reset-meson.c index 5324f86f5f..c31f302143 100644 --- a/drivers/reset/reset-meson.c +++ b/drivers/reset/reset-meson.c @@ -41,12 +41,12 @@ static int meson_reset_level(struct reset_ctl *reset_ctl, bool assert) uint reg_offset = LEVEL_OFFSET + (bank << 2); uint val;
- regmap_read(priv->regmap, reg_offset, &val); + regmap_read(priv->regmap, reg_offset, &val, REGMAP_SIZE_32); if (assert) val &= ~BIT(offset); else val |= BIT(offset); - regmap_write(priv->regmap, reg_offset, val); + regmap_write(priv->regmap, reg_offset, val, REGMAP_SIZE_32);
return 0; } @@ -68,15 +68,15 @@ struct reset_ops meson_reset_ops = { .rst_deassert = meson_reset_deassert, };
-static const struct udevice_id meson_reset_ids[] = { - { .compatible = "amlogic,meson-gxbb-reset" }, - { } -}; +static const struct udevice_id meson_reset_ids[] = { + { .compatible = "amlogic,meson-gxbb-reset" }, + { } +};
static int meson_reset_probe(struct udevice *dev) { struct meson_reset_priv *priv = dev_get_priv(dev); - + return regmap_init_mem(dev, &priv->regmap); }
diff --git a/drivers/sysreset/sysreset_syscon.c b/drivers/sysreset/sysreset_syscon.c index 22c602a4d2..0c374a7443 100644 --- a/drivers/sysreset/sysreset_syscon.c +++ b/drivers/sysreset/sysreset_syscon.c @@ -25,7 +25,7 @@ static int syscon_reboot_request(struct udevice *dev, enum sysreset_t type) { struct syscon_reboot_priv *priv = dev_get_priv(dev);
- regmap_write(priv->regmap, priv->offset, priv->mask); + regmap_write(priv->regmap, priv->offset, priv->mask, REGMAP_SIZE_32);
return -EINPROGRESS; } diff --git a/include/regmap.h b/include/regmap.h index 493a5d8eff..a6e2fafd27 100644 --- a/include/regmap.h +++ b/include/regmap.h @@ -8,6 +8,13 @@ #ifndef __REGMAP_H #define __REGMAP_H
+/* Access sizes for fpgamap reads and writes */ +enum regmap_size_t { + REGMAP_SIZE_8 = 1, + REGMAP_SIZE_16 = 2, + REGMAP_SIZE_32 = 4, +}; + /** * struct regmap_range - a register map range * @@ -37,8 +44,8 @@ struct regmap { * Interface to provide access to registers either through a direct memory * bus or through a peripheral bus like I2C, SPI. */ -int regmap_write(struct regmap *map, uint offset, uint val); -int regmap_read(struct regmap *map, uint offset, uint *valp); +int regmap_write(struct regmap *map, ulong offset, ulong val, enum regmap_size_t size); +int regmap_read(struct regmap *map, ulong offset, ulong *valp, enum regmap_size_t size);
#define regmap_write32(map, ptr, member, val) \ regmap_write(map, (uint32_t *)(ptr)->member - (uint32_t *)(ptr), val)

It is useful to be able to treat the different ranges of a regmap separately to be able to use distinct offset for them, but this is currently not implemented in the regmap API.
To preserve backwards compatibility, add regmap_read_ext and regmap_write_ext functions that take an additional parameter 'range_num' that identifies the range to operate on.
Signed-off-by: Mario Six mario.six@gdsys.cc ---
v1 -> v2: New in v2
--- drivers/core/regmap.c | 69 +++++++++++++++++++++++++++++++++++++++------------ include/regmap.h | 2 ++ 2 files changed, 55 insertions(+), 16 deletions(-)
diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c index c2cdff3979..80718b3820 100644 --- a/drivers/core/regmap.c +++ b/drivers/core/regmap.c @@ -130,47 +130,84 @@ int regmap_uninit(struct regmap *map) return 0; }
-int regmap_read(struct regmap *map, ulong offset, ulong *valp, - enum regmap_size_t size) +int regmap_read_ext(struct regmap *map, uint range_num, ulong offset, + ulong *valp, enum regmap_size_t size) { + struct regmap_range *range; void *ptr;
+ if (range_num >= map->range_count) + return 0; + range = &map->range[range_num]; + + ptr = map_physmem(range->start + offset, size, MAP_NOCACHE); + + if (offset + size > range->size) { + debug("%s: offset/size combination invalid\n", __func__); + return -EINVAL; + } + switch (size) { case REGMAP_SIZE_8: - ptr = map_physmem(map->base + offset, 1, MAP_NOCACHE); - *valp = readb(ptr); + *((u8 *)valp) = readb((u8 *)ptr); break; case REGMAP_SIZE_16: - ptr = map_physmem(map->base + offset, 2, MAP_NOCACHE); - *valp = le16_to_cpu(readw(ptr)); + *((u16 *)valp) = readw((u16 *)ptr); break; case REGMAP_SIZE_32: - ptr = map_physmem(map->base + offset, 4, MAP_NOCACHE); - *valp = le32_to_cpu(readl(ptr)); + *((u32 *)valp) = readl((u32 *)ptr); break; + default: + debug("%s: size %d not supported\n", __func__, size); + return -ENOTSUPP; } + return 0; }
-int regmap_write(struct regmap *map, ulong offset, ulong val, - enum regmap_size_t size) +int regmap_read(struct regmap *map, ulong offset, ulong *valp, + enum regmap_size_t size) { + return regmap_read_ext(map, 0, offset, valp, size); +} + +int regmap_write_ext(struct regmap *map, uint range_num, ulong offset, + ulong val, enum regmap_size_t size) +{ + struct regmap_range *range; void *ptr;
+ if (range_num >= map->range_count) + return 0; + range = &map->range[range_num]; + + ptr = map_physmem(range->start + offset, size, MAP_NOCACHE); + + if (offset + size > range->size) { + debug("%s: offset/size combination invalid\n", __func__); + return -EINVAL; + } + switch (size) { case REGMAP_SIZE_8: - ptr = map_physmem(map->base + offset, 1, MAP_NOCACHE); - writel((u8)val, ptr); + writeb((u8)val, (u8 *)ptr); break; case REGMAP_SIZE_16: - ptr = map_physmem(map->base + offset, 2, MAP_NOCACHE); - writel(cpu_to_le16((u16)val), ptr); + out_le16((u16 *)ptr, (u16)val); break; case REGMAP_SIZE_32: - ptr = map_physmem(map->base + offset, 4, MAP_NOCACHE); - writel(cpu_to_le32((u32)val), ptr); + writel((u32)val, (u32 *)ptr); break; + default: + debug("%s: size %d not supported\n", __func__, size); + return -ENOTSUPP; }
return 0; } + +int regmap_write(struct regmap *map, ulong offset, ulong val, + enum regmap_size_t size) +{ + return regmap_write_ext(map, 0, offset, val, size); +} diff --git a/include/regmap.h b/include/regmap.h index a6e2fafd27..bb7e947ce2 100644 --- a/include/regmap.h +++ b/include/regmap.h @@ -44,7 +44,9 @@ struct regmap { * Interface to provide access to registers either through a direct memory * bus or through a peripheral bus like I2C, SPI. */ +int regmap_write_ext(struct regmap *map, uint range_num, ulong offset, ulong val, enum regmap_size_t size); int regmap_write(struct regmap *map, ulong offset, ulong val, enum regmap_size_t size); +int regmap_read_ext(struct regmap *map, uint range_num, ulong offset, ulong *valp, enum regmap_size_t size); int regmap_read(struct regmap *map, ulong offset, ulong *valp, enum regmap_size_t size);
#define regmap_write32(map, ptr, member, val) \

Hi Mario,
On 27 April 2018 at 06:52, Mario Six mario.six@gdsys.cc wrote:
It is useful to be able to treat the different ranges of a regmap separately to be able to use distinct offset for them, but this is currently not implemented in the regmap API.
To preserve backwards compatibility, add regmap_read_ext and regmap_write_ext functions that take an additional parameter 'range_num' that identifies the range to operate on.
Signed-off-by: Mario Six mario.six@gdsys.cc
v1 -> v2: New in v2
drivers/core/regmap.c | 69 +++++++++++++++++++++++++++++++++++++++------------ include/regmap.h | 2 ++ 2 files changed, 55 insertions(+), 16 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org
diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c index c2cdff3979..80718b3820 100644 --- a/drivers/core/regmap.c +++ b/drivers/core/regmap.c @@ -130,47 +130,84 @@ int regmap_uninit(struct regmap *map) return 0; }
-int regmap_read(struct regmap *map, ulong offset, ulong *valp,
enum regmap_size_t size)
+int regmap_read_ext(struct regmap *map, uint range_num, ulong offset,
ulong *valp, enum regmap_size_t size)
How about regmap_read_range() ?
{
struct regmap_range *range; void *ptr;
if (range_num >= map->range_count)
return 0;
range = &map->range[range_num];
ptr = map_physmem(range->start + offset, size, MAP_NOCACHE);
if (offset + size > range->size) {
debug("%s: offset/size combination invalid\n", __func__);
return -EINVAL;
}
switch (size) { case REGMAP_SIZE_8:
ptr = map_physmem(map->base + offset, 1, MAP_NOCACHE);
*valp = readb(ptr);
*((u8 *)valp) = readb((u8 *)ptr); break; case REGMAP_SIZE_16:
ptr = map_physmem(map->base + offset, 2, MAP_NOCACHE);
*valp = le16_to_cpu(readw(ptr));
*((u16 *)valp) = readw((u16 *)ptr); break; case REGMAP_SIZE_32:
ptr = map_physmem(map->base + offset, 4, MAP_NOCACHE);
*valp = le32_to_cpu(readl(ptr));
*((u32 *)valp) = readl((u32 *)ptr); break;
default:
debug("%s: size %d not supported\n", __func__, size);
return -ENOTSUPP; }
return 0;
}
-int regmap_write(struct regmap *map, ulong offset, ulong val,
enum regmap_size_t size)
+int regmap_read(struct regmap *map, ulong offset, ulong *valp,
enum regmap_size_t size)
{
return regmap_read_ext(map, 0, offset, valp, size);
+}
+int regmap_write_ext(struct regmap *map, uint range_num, ulong offset,
ulong val, enum regmap_size_t size)
+{
struct regmap_range *range; void *ptr;
if (range_num >= map->range_count)
return 0;
range = &map->range[range_num];
ptr = map_physmem(range->start + offset, size, MAP_NOCACHE);
if (offset + size > range->size) {
debug("%s: offset/size combination invalid\n", __func__);
return -EINVAL;
}
switch (size) { case REGMAP_SIZE_8:
ptr = map_physmem(map->base + offset, 1, MAP_NOCACHE);
writel((u8)val, ptr);
writeb((u8)val, (u8 *)ptr); break; case REGMAP_SIZE_16:
ptr = map_physmem(map->base + offset, 2, MAP_NOCACHE);
writel(cpu_to_le16((u16)val), ptr);
out_le16((u16 *)ptr, (u16)val); break; case REGMAP_SIZE_32:
ptr = map_physmem(map->base + offset, 4, MAP_NOCACHE);
writel(cpu_to_le32((u32)val), ptr);
writel((u32)val, (u32 *)ptr); break;
default:
debug("%s: size %d not supported\n", __func__, size);
return -ENOTSUPP; } return 0;
}
+int regmap_write(struct regmap *map, ulong offset, ulong val,
enum regmap_size_t size)
+{
return regmap_write_ext(map, 0, offset, val, size);
+} diff --git a/include/regmap.h b/include/regmap.h index a6e2fafd27..bb7e947ce2 100644 --- a/include/regmap.h +++ b/include/regmap.h @@ -44,7 +44,9 @@ struct regmap {
- Interface to provide access to registers either through a direct memory
- bus or through a peripheral bus like I2C, SPI.
*/ +int regmap_write_ext(struct regmap *map, uint range_num, ulong offset, ulong val, enum regmap_size_t size); int regmap_write(struct regmap *map, ulong offset, ulong val, enum regmap_size_t size); +int regmap_read_ext(struct regmap *map, uint range_num, ulong offset, ulong *valp, enum regmap_size_t size); int regmap_read(struct regmap *map, ulong offset, ulong *valp, enum regmap_size_t size);
Can you please add full function comments?
#define regmap_write32(map, ptr, member, val) \
2.16.1
Regards, Simon

Hi Simon,
On Thu, May 3, 2018 at 4:33 AM, Simon Glass sjg@chromium.org wrote:
Hi Mario,
On 27 April 2018 at 06:52, Mario Six mario.six@gdsys.cc wrote:
It is useful to be able to treat the different ranges of a regmap separately to be able to use distinct offset for them, but this is currently not implemented in the regmap API.
To preserve backwards compatibility, add regmap_read_ext and regmap_write_ext functions that take an additional parameter 'range_num' that identifies the range to operate on.
Signed-off-by: Mario Six mario.six@gdsys.cc
v1 -> v2: New in v2
drivers/core/regmap.c | 69 +++++++++++++++++++++++++++++++++++++++------------ include/regmap.h | 2 ++ 2 files changed, 55 insertions(+), 16 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org
diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c index c2cdff3979..80718b3820 100644 --- a/drivers/core/regmap.c +++ b/drivers/core/regmap.c @@ -130,47 +130,84 @@ int regmap_uninit(struct regmap *map) return 0; }
-int regmap_read(struct regmap *map, ulong offset, ulong *valp,
enum regmap_size_t size)
+int regmap_read_ext(struct regmap *map, uint range_num, ulong offset,
ulong *valp, enum regmap_size_t size)
How about regmap_read_range() ?
Yes, sounds more descriptive. Will change for v3.
{
struct regmap_range *range; void *ptr;
if (range_num >= map->range_count)
return 0;
range = &map->range[range_num];
ptr = map_physmem(range->start + offset, size, MAP_NOCACHE);
if (offset + size > range->size) {
debug("%s: offset/size combination invalid\n", __func__);
return -EINVAL;
}
switch (size) { case REGMAP_SIZE_8:
ptr = map_physmem(map->base + offset, 1, MAP_NOCACHE);
*valp = readb(ptr);
*((u8 *)valp) = readb((u8 *)ptr); break; case REGMAP_SIZE_16:
ptr = map_physmem(map->base + offset, 2, MAP_NOCACHE);
*valp = le16_to_cpu(readw(ptr));
*((u16 *)valp) = readw((u16 *)ptr); break; case REGMAP_SIZE_32:
ptr = map_physmem(map->base + offset, 4, MAP_NOCACHE);
*valp = le32_to_cpu(readl(ptr));
*((u32 *)valp) = readl((u32 *)ptr); break;
default:
debug("%s: size %d not supported\n", __func__, size);
return -ENOTSUPP; }
return 0;
}
-int regmap_write(struct regmap *map, ulong offset, ulong val,
enum regmap_size_t size)
+int regmap_read(struct regmap *map, ulong offset, ulong *valp,
enum regmap_size_t size)
{
return regmap_read_ext(map, 0, offset, valp, size);
+}
+int regmap_write_ext(struct regmap *map, uint range_num, ulong offset,
ulong val, enum regmap_size_t size)
+{
struct regmap_range *range; void *ptr;
if (range_num >= map->range_count)
return 0;
range = &map->range[range_num];
ptr = map_physmem(range->start + offset, size, MAP_NOCACHE);
if (offset + size > range->size) {
debug("%s: offset/size combination invalid\n", __func__);
return -EINVAL;
}
switch (size) { case REGMAP_SIZE_8:
ptr = map_physmem(map->base + offset, 1, MAP_NOCACHE);
writel((u8)val, ptr);
writeb((u8)val, (u8 *)ptr); break; case REGMAP_SIZE_16:
ptr = map_physmem(map->base + offset, 2, MAP_NOCACHE);
writel(cpu_to_le16((u16)val), ptr);
out_le16((u16 *)ptr, (u16)val); break; case REGMAP_SIZE_32:
ptr = map_physmem(map->base + offset, 4, MAP_NOCACHE);
writel(cpu_to_le32((u32)val), ptr);
writel((u32)val, (u32 *)ptr); break;
default:
debug("%s: size %d not supported\n", __func__, size);
return -ENOTSUPP; } return 0;
}
+int regmap_write(struct regmap *map, ulong offset, ulong val,
enum regmap_size_t size)
+{
return regmap_write_ext(map, 0, offset, val, size);
+} diff --git a/include/regmap.h b/include/regmap.h index a6e2fafd27..bb7e947ce2 100644 --- a/include/regmap.h +++ b/include/regmap.h @@ -44,7 +44,9 @@ struct regmap {
- Interface to provide access to registers either through a direct memory
- bus or through a peripheral bus like I2C, SPI.
*/ +int regmap_write_ext(struct regmap *map, uint range_num, ulong offset, ulong val, enum regmap_size_t size); int regmap_write(struct regmap *map, ulong offset, ulong val, enum regmap_size_t size); +int regmap_read_ext(struct regmap *map, uint range_num, ulong offset, ulong *valp, enum regmap_size_t size); int regmap_read(struct regmap *map, ulong offset, ulong *valp, enum regmap_size_t size);
Can you please add full function comments?
OK, will be documented in v3.
#define regmap_write32(map, ptr, member, val) \
2.16.1
Regards, Simon
Best regards, Mario

It would be convenient if one could use the regmap API in conjunction with register maps defined as structs (i.e. structs that directly mirror the memory layout of the registers in question). A similar approach was planned with the regmap_write32/regmap_read32 macros, but was never used.
Hence, implement regmap_set/regmap_range_set and regmap_get/regmap_range_get macros, which, given a register map, a struct describing the layout of the register map, and a member name automatically produce regmap_read/regmap_write calls that access the specified member in the register map.
Signed-off-by: Mario Six mario.six@gdsys.cc ---
v1 -> v2: New in v2
--- include/regmap.h | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/include/regmap.h b/include/regmap.h index bb7e947ce2..69cbe8a96a 100644 --- a/include/regmap.h +++ b/include/regmap.h @@ -49,11 +49,17 @@ int regmap_write(struct regmap *map, ulong offset, ulong val, enum regmap_size_t int regmap_read_ext(struct regmap *map, uint range_num, ulong offset, ulong *valp, enum regmap_size_t size); int regmap_read(struct regmap *map, ulong offset, ulong *valp, enum regmap_size_t size);
-#define regmap_write32(map, ptr, member, val) \ - regmap_write(map, (uint32_t *)(ptr)->member - (uint32_t *)(ptr), val) +#define regmap_range_set(map, range, type, member, val) \ + regmap_write_ext(map, range, offsetof(type, member), val, sizeof(((type *)0)->member))
-#define regmap_read32(map, ptr, member, valp) \ - regmap_read(map, (uint32_t *)(ptr)->member - (uint32_t *)(ptr), valp) +#define regmap_set(map, type, member, val) \ + regmap_range_set(map, 0, type, member, val) + +#define regmap_range_get(map, range, type, member, valp) \ + regmap_read_ext(map, range, offsetof(type, member), (void *)valp, sizeof(((type *)0)->member)) + +#define regmap_get(map, type, member, valp) \ + regmap_range_get(map, 0, type, member, valp) \
/** * regmap_init_mem() - Set up a new register map that uses memory access

Hi Mario,
On 27 April 2018 at 06:52, Mario Six mario.six@gdsys.cc wrote:
It would be convenient if one could use the regmap API in conjunction with register maps defined as structs (i.e. structs that directly mirror the memory layout of the registers in question). A similar approach was planned with the regmap_write32/regmap_read32 macros, but was never used.
Hence, implement regmap_set/regmap_range_set and regmap_get/regmap_range_get macros, which, given a register map, a struct describing the layout of the register map, and a member name automatically produce regmap_read/regmap_write calls that access the specified member in the register map.
Signed-off-by: Mario Six mario.six@gdsys.cc
v1 -> v2: New in v2
include/regmap.h | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org
Please can you add function comments and also a test that calls these? I think Masahiro made a start.
Regards, Simon

Hi Simon,
On Thu, May 3, 2018 at 4:33 AM, Simon Glass sjg@chromium.org wrote:
Hi Mario,
On 27 April 2018 at 06:52, Mario Six mario.six@gdsys.cc wrote:
It would be convenient if one could use the regmap API in conjunction with register maps defined as structs (i.e. structs that directly mirror the memory layout of the registers in question). A similar approach was planned with the regmap_write32/regmap_read32 macros, but was never used.
Hence, implement regmap_set/regmap_range_set and regmap_get/regmap_range_get macros, which, given a register map, a struct describing the layout of the register map, and a member name automatically produce regmap_read/regmap_write calls that access the specified member in the register map.
Signed-off-by: Mario Six mario.six@gdsys.cc
v1 -> v2: New in v2
include/regmap.h | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org
Please can you add function comments and also a test that calls these? I think Masahiro made a start.
OK, I'll add some tests for v3.
Regards, Simon
Best regards, Mario

This patch adds a driver for the bus associated with a IHS FPGA.
Signed-off-by: Mario Six mario.six@gdsys.cc ---
v1 -> v2: * Switched to correct uclass for IHS FPGA driver (now in MISC uclass)
--- drivers/misc/Kconfig | 6 ++++- drivers/misc/Makefile | 1 + drivers/misc/gdsys_soc.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++ drivers/misc/gdsys_soc.h | 24 +++++++++++++++++ 4 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 drivers/misc/gdsys_soc.c create mode 100644 drivers/misc/gdsys_soc.h
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index d774569cbc..9d58d96321 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -263,5 +263,9 @@ config SYS_I2C_EEPROM_ADDR_OVERFLOW
endif
- +config GDSYS_SOC + bool "Enable gdsys SOC driver" + depends on MISC + help + Support for IHS SOC. endmenu diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index e8d598cd47..d35f7d856d 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -54,3 +54,4 @@ obj-$(CONFIG_QFW) += qfw.o obj-$(CONFIG_ROCKCHIP_EFUSE) += rockchip-efuse.o obj-$(CONFIG_STM32_RCC) += stm32_rcc.o obj-$(CONFIG_SYS_DPAA_QBMAN) += fsl_portals.o +obj-$(CONFIG_GDSYS_SOC) += gdsys_soc.o diff --git a/drivers/misc/gdsys_soc.c b/drivers/misc/gdsys_soc.c new file mode 100644 index 0000000000..0bf1dd8303 --- /dev/null +++ b/drivers/misc/gdsys_soc.c @@ -0,0 +1,67 @@ +/* + * (C) Copyright 2017 + * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <dm/lists.h> + +#include "gdsys_soc.h" + +struct gdsys_soc_priv { + struct udevice *fpga; +}; + +static const struct udevice_id gdsys_soc_ids[] = { + { .compatible = "gdsys,soc" }, + { /* sentinel */ } +}; + +int gdsys_soc_get_fpga(struct udevice *child, struct udevice **fpga) +{ + struct gdsys_soc_priv *bus_priv; + + if (!child->parent) + return -EINVAL; + + if (!device_is_compatible(child->parent, "gdsys,soc")) + return -EINVAL; + + bus_priv = dev_get_priv(child->parent); + + *fpga = bus_priv->fpga; + + return 0; +} + +static int gdsys_soc_probe(struct udevice *dev) +{ + struct gdsys_soc_priv *priv = dev_get_priv(dev); + struct udevice *fpga; + int res = uclass_get_device_by_phandle(UCLASS_MISC, dev, "fpga", + &fpga); + if (res == -ENOENT) { + printf("%s: Could not find 'fpga' phandle.\n", dev->name); + return -EINVAL; + } + + if (res == -ENODEV) { + printf("%s: Could not get FPGA device.\n", dev->name); + return -EINVAL; + } + + priv->fpga = fpga; + + return 0; +} + +U_BOOT_DRIVER(gdsys_soc_bus) = { + .name = "gdsys_soc_bus", + .id = UCLASS_SIMPLE_BUS, + .of_match = gdsys_soc_ids, + .probe = gdsys_soc_probe, + .priv_auto_alloc_size = sizeof(struct gdsys_soc_priv), +}; diff --git a/drivers/misc/gdsys_soc.h b/drivers/misc/gdsys_soc.h new file mode 100644 index 0000000000..0f88149fd6 --- /dev/null +++ b/drivers/misc/gdsys_soc.h @@ -0,0 +1,24 @@ +/* + * (C) Copyright 2017 + * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _GDSYS_SOC_H_ +#define _GDSYS_SOC_H_ + +/** + * gdsys_soc_get_fpga() - Retrieve pointer to parent bus' FPGA device + * + * To access their register maps, devices on gdsys soc buses usually have + * facilitate the accessor function of the IHS FPGA their parent bus is + * attached to. To access the FPGA device from within the bus' children, this + * function returns a pointer to it. + * + * @child: The child device on the FPGA bus needing access to the FPGA. + * @fpga: Pointer to the retrieved FPGA device. + * @return 0 on success, -ve on failure + */ +int gdsys_soc_get_fpga(struct udevice *child, struct udevice **fpga); +#endif /* _GDSYS_SOC_H_ */

Add a driver for gdsys IHS (Integrated Hardware Systems) FPGAs, which supports initialization of the FPGA, as well as information gathering.
Signed-off-by: Mario Six mario.six@gdsys.cc ---
v1 -> v2: New in v2
--- drivers/misc/Kconfig | 6 + drivers/misc/Makefile | 1 + drivers/misc/ihs_fpga.c | 686 ++++++++++++++++++++++++++++++++++++++++++++++++ drivers/misc/ihs_fpga.h | 26 ++ 4 files changed, 719 insertions(+) create mode 100644 drivers/misc/ihs_fpga.c create mode 100644 drivers/misc/ihs_fpga.h
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 9d58d96321..2dd65fd621 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -268,4 +268,10 @@ config GDSYS_SOC depends on MISC help Support for IHS SOC. + +config IHS_FPGA + bool "Enable IHS FPGA driver" + depends on MISC + help + Support IHS FPGA driver. endmenu diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index d35f7d856d..a94627bc8b 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -55,3 +55,4 @@ obj-$(CONFIG_ROCKCHIP_EFUSE) += rockchip-efuse.o obj-$(CONFIG_STM32_RCC) += stm32_rcc.o obj-$(CONFIG_SYS_DPAA_QBMAN) += fsl_portals.o obj-$(CONFIG_GDSYS_SOC) += gdsys_soc.o +obj-$(CONFIG_IHS_FPGA) += ihs_fpga.o diff --git a/drivers/misc/ihs_fpga.c b/drivers/misc/ihs_fpga.c new file mode 100644 index 0000000000..dc7e497163 --- /dev/null +++ b/drivers/misc/ihs_fpga.c @@ -0,0 +1,686 @@ +/* + * (C) Copyright 2017 + * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc + * + * based on the ioep-fpga driver, which is + * + * (C) Copyright 2014 + * Dirk Eibach, Guntermann & Drunck GmbH, eibach@gdsys.de + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <dm/lists.h> +#include <regmap.h> +#include <misc.h> +#include <mapmem.h> +#include <asm/gpio.h> +#include <linux/bitops.h> + +#include "ihs_fpga.h" + +struct ihs_fpga_priv { + struct regmap *map; + struct gpio_desc reset_gpio; + struct gpio_desc done_gpio; + struct gpio_desc startupfin_gpios[2]; + bool has_osd; +}; + +const u16 reflection_testpattern = 0xdead; + +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; + + bool pcm_tx; + bool pcm_rx; + bool spdif_tx; + bool spdif_rx; + bool usb2; + bool rs232; + bool compression_type1; + bool compression_type2; + bool compression_type3; + bool interlace; + bool osd; + bool compression_pipes; +}; + +#ifdef CONFIG_SYS_FPGA_FLAVOR_GAZERBEAM + +static int get_versions(struct udevice *dev, struct fpga_versions *versions) +{ + struct ihs_fpga_priv *priv = dev_get_priv(dev); + enum { + VERSIONS_FPGA_VIDEO_CHANNEL = BIT(12), + VERSIONS_FPGA_CON_SIDE = BIT(13), + VERSIONS_FPGA_SC = BIT(14), + VERSIONS_PCB_CON = BIT(9), + VERSIONS_PCB_SC = BIT(8), + VERSIONS_PCB_VIDEO_MASK = 0x3 << 6, + VERSIONS_PCB_VIDEO_DP_1_2 = 0x0 << 6, + VERSIONS_PCB_VIDEO_HDMI_2_0 = 0x1 << 6, + VERSIONS_PCB_TRANSMISSION_MASK = 0x3 << 4, + VERSIONS_PCB_TRANSMISSION_FIBER_10G = 0x0 << 4, + VERSIONS_PCB_TRANSMISSION_CAT_10G = 0x1 << 4, + VERSIONS_PCB_TRANSMISSION_FIBER_3G = 0x2 << 4, + VERSIONS_PCB_TRANSMISSION_CAT_1G = 0x3 << 4, + VERSIONS_HW_VER_MASK = 0xf << 0, + }; + u16 raw_versions; + + memset(versions, 0, sizeof(struct fpga_versions)); + + ihs_fpga_get(priv->map, versions, &raw_versions); + + versions->video_channel = raw_versions & VERSIONS_FPGA_VIDEO_CHANNEL; + versions->con_side = raw_versions & VERSIONS_FPGA_CON_SIDE; + + switch (raw_versions & VERSIONS_PCB_VIDEO_MASK) { + case VERSIONS_PCB_VIDEO_DP_1_2: + versions->pcb_video_type = PCB_DP_1_2; + break; + + case VERSIONS_PCB_VIDEO_HDMI_2_0: + versions->pcb_video_type = PCB_HDMI_2_0; + break; + } + + switch (raw_versions & VERSIONS_PCB_TRANSMISSION_MASK) { + case VERSIONS_PCB_TRANSMISSION_FIBER_10G: + versions->pcb_transmission_type = PCB_FIBER_10G; + break; + + case VERSIONS_PCB_TRANSMISSION_CAT_10G: + versions->pcb_transmission_type = PCB_CAT_10G; + break; + + case VERSIONS_PCB_TRANSMISSION_FIBER_3G: + versions->pcb_transmission_type = PCB_FIBER_3G; + break; + + case VERSIONS_PCB_TRANSMISSION_CAT_1G: + versions->pcb_transmission_type = PCB_CAT_1G; + break; + } + + versions->hw_version = raw_versions & VERSIONS_HW_VER_MASK; + + return 0; +} + +static int get_features(struct udevice *dev, struct fpga_features *features) +{ + struct ihs_fpga_priv *priv = dev_get_priv(dev); + enum { + FEATURE_SPDIF_RX = BIT(15), + FEATURE_SPDIF_TX = BIT(14), + FEATURE_PCM_RX = BIT(13), + FEATURE_PCM_TX = BIT(12), + FEATURE_RAM_MASK = GENMASK(11, 8), + FEATURE_RAM_DDR2_32BIT_295MBPS = 0x0 << 8, + FEATURE_RAM_DDR3_32BIT_590MBPS = 0x1 << 8, + FEATURE_RAM_DDR3_48BIT_590MBPS = 0x2 << 8, + FEATURE_RAM_DDR3_64BIT_1800MBPS = 0x3 << 8, + FEATURE_RAM_DDR3_48BIT_1800MBPS = 0x4 << 8, + FEATURE_CARRIER_SPEED_MASK = GENMASK(7, 6), + FEATURE_CARRIER_SPEED_1G = 0x0 << 6, + FEATURE_CARRIER_SPEED_2_5G = 0x1 << 6, + FEATURE_CARRIER_SPEED_10G = 0x2 << 6, + FEATURE_CARRIERS_MASK = GENMASK(5, 4), + FEATURE_CARRIERS_0 = 0x0 << 4, + FEATURE_CARRIERS_1 = 0x1 << 4, + FEATURE_CARRIERS_2 = 0x2 << 4, + FEATURE_CARRIERS_4 = 0x3 << 4, + FEATURE_USB2 = BIT(3), + FEATURE_VIDEOCHANNELS_MASK = GENMASK(2, 0), + FEATURE_VIDEOCHANNELS_0 = 0x0 << 0, + FEATURE_VIDEOCHANNELS_1 = 0x1 << 0, + FEATURE_VIDEOCHANNELS_1_1 = 0x2 << 0, + FEATURE_VIDEOCHANNELS_2 = 0x3 << 0, + }; + + enum { + EXT_FEATURE_OSD = BIT(15), + EXT_FEATURE_ETHERNET = BIT(9), + EXT_FEATURE_INTERLACE = BIT(8), + EXT_FEATURE_RS232 = BIT(7), + EXT_FEATURE_COMPRESSION_PERF_MASK = GENMASK(6, 4), + EXT_FEATURE_COMPRESSION_PERF_1X = 0x0 << 4, + EXT_FEATURE_COMPRESSION_PERF_2X = 0x1 << 4, + EXT_FEATURE_COMPRESSION_PERF_4X = 0x2 << 4, + EXT_FEATURE_COMPRESSION_TYPE1 = BIT(0), + EXT_FEATURE_COMPRESSION_TYPE2 = BIT(1), + EXT_FEATURE_COMPRESSION_TYPE3 = BIT(2), + }; + + u16 raw_features; + u16 raw_extended_features; + + memset(features, 0, sizeof(struct fpga_features)); + + ihs_fpga_get(priv->map, features, &raw_features); + ihs_fpga_get(priv->map, extended_features, &raw_extended_features); + + switch (raw_features & FEATURE_VIDEOCHANNELS_MASK) { + case FEATURE_VIDEOCHANNELS_0: + features->video_channels = 0; + break; + + case FEATURE_VIDEOCHANNELS_1: + features->video_channels = 1; + break; + + case FEATURE_VIDEOCHANNELS_1_1: + case FEATURE_VIDEOCHANNELS_2: + features->video_channels = 2; + break; + }; + + switch (raw_features & FEATURE_CARRIERS_MASK) { + case FEATURE_CARRIERS_0: + features->carriers = 0; + break; + + case FEATURE_CARRIERS_1: + features->carriers = 1; + break; + + case FEATURE_CARRIERS_2: + features->carriers = 2; + break; + + case FEATURE_CARRIERS_4: + features->carriers = 4; + break; + } + + switch (raw_features & FEATURE_CARRIER_SPEED_MASK) { + case FEATURE_CARRIER_SPEED_1G: + features->carrier_speed = CARRIER_SPEED_1G; + break; + case FEATURE_CARRIER_SPEED_2_5G: + features->carrier_speed = CARRIER_SPEED_2_5G; + break; + case FEATURE_CARRIER_SPEED_10G: + features->carrier_speed = CARRIER_SPEED_10G; + break; + } + + switch (raw_features & FEATURE_RAM_MASK) { + case FEATURE_RAM_DDR2_32BIT_295MBPS: + features->ram_config = RAM_DDR2_32BIT_295MBPS; + break; + + case FEATURE_RAM_DDR3_32BIT_590MBPS: + features->ram_config = RAM_DDR3_32BIT_590MBPS; + break; + + case FEATURE_RAM_DDR3_48BIT_590MBPS: + features->ram_config = RAM_DDR3_48BIT_590MBPS; + break; + + case FEATURE_RAM_DDR3_64BIT_1800MBPS: + features->ram_config = RAM_DDR3_64BIT_1800MBPS; + break; + + case FEATURE_RAM_DDR3_48BIT_1800MBPS: + features->ram_config = RAM_DDR3_48BIT_1800MBPS; + break; + } + + features->pcm_tx = raw_features & FEATURE_PCM_TX; + features->pcm_rx = raw_features & FEATURE_PCM_RX; + features->spdif_tx = raw_features & FEATURE_SPDIF_TX; + features->spdif_rx = raw_features & FEATURE_SPDIF_RX; + features->usb2 = raw_features & FEATURE_USB2; + features->rs232 = raw_extended_features & EXT_FEATURE_RS232; + features->compression_type1 = raw_extended_features & + EXT_FEATURE_COMPRESSION_TYPE1; + features->compression_type2 = raw_extended_features & + EXT_FEATURE_COMPRESSION_TYPE2; + features->compression_type3 = raw_extended_features & + EXT_FEATURE_COMPRESSION_TYPE3; + features->interlace = raw_extended_features & EXT_FEATURE_INTERLACE; + features->osd = raw_extended_features & EXT_FEATURE_OSD; + features->compression_pipes = raw_extended_features & + EXT_FEATURE_COMPRESSION_PERF_MASK; + + return 0; +} + +#else + +static int get_versions(unsigned int fpga, struct fpga_versions *versions) +{ + enum { + /* HW version encoding is a mess, leave it for the moment */ + VERSIONS_HW_VER_MASK = 0xf << 0, + VERSIONS_PIX_CLOCK_GEN_IDT8N3QV01 = BIT(4), + VERSIONS_SFP = BIT(5), + VERSIONS_VIDEO_MASK = 0x7 << 6, + VERSIONS_VIDEO_DVI = 0x0 << 6, + VERSIONS_VIDEO_DP_165 = 0x1 << 6, + VERSIONS_VIDEO_DP_300 = 0x2 << 6, + VERSIONS_VIDEO_HDMI = 0x3 << 6, + VERSIONS_UT_MASK = 0xf << 12, + VERSIONS_UT_MAIN_SERVER = 0x0 << 12, + VERSIONS_UT_MAIN_USER = 0x1 << 12, + VERSIONS_UT_VIDEO_SERVER = 0x2 << 12, + VERSIONS_UT_VIDEO_USER = 0x3 << 12, + }; + u16 raw_versions; + + memset(versions, 0, sizeof(struct fpga_versions)); + + FPGA_GET_REG(fpga, versions, &raw_versions); + + switch (raw_versions & VERSIONS_UT_MASK) { + case VERSIONS_UT_MAIN_SERVER: + versions->video_channel = false; + versions->con_side = false; + break; + + case VERSIONS_UT_MAIN_USER: + versions->video_channel = false; + versions->con_side = true; + break; + + case VERSIONS_UT_VIDEO_SERVER: + versions->video_channel = true; + versions->con_side = false; + break; + + case VERSIONS_UT_VIDEO_USER: + versions->video_channel = true; + versions->con_side = true; + break; + } + + switch (raw_versions & VERSIONS_VIDEO_MASK) { + case VERSIONS_VIDEO_DVI: + versions->pcb_video_type = PCB_DVI_SL; + break; + + case VERSIONS_VIDEO_DP_165: + versions->pcb_video_type = PCB_DP_165MPIX; + break; + + case VERSIONS_VIDEO_DP_300: + versions->pcb_video_type = PCB_DP_300MPIX; + break; + + case VERSIONS_VIDEO_HDMI: + versions->pcb_video_type = PCB_HDMI; + break; + } + + versions->hw_version = raw_versions & VERSIONS_HW_VER_MASK; + + if (raw_versions & VERSIONS_SFP) + versions->pcb_transmission_type = PCB_FIBER_3G; + else + versions->pcb_transmission_type = PCB_CAT_1G; + + return 0; +} + +static int get_features(unsigned int fpga, struct fpga_features *features) +{ + enum { + FEATURE_CARRIER_SPEED_2_5 = BIT(4), + FEATURE_RAM_MASK = 0x7 << 5, + FEATURE_RAM_DDR2_32BIT = 0x0 << 5, + FEATURE_RAM_DDR3_32BIT = 0x1 << 5, + FEATURE_RAM_DDR3_48BIT = 0x2 << 5, + FEATURE_PCM_AUDIO_TX = BIT(9), + FEATURE_PCM_AUDIO_RX = BIT(10), + FEATURE_OSD = BIT(11), + FEATURE_USB20 = BIT(12), + FEATURE_COMPRESSION_MASK = 7 << 13, + FEATURE_COMPRESSION_TYPE1 = 0x1 << 13, + FEATURE_COMPRESSION_TYPE1_TYPE2 = 0x3 << 13, + FEATURE_COMPRESSION_TYPE1_TYPE2_TYPE3 = 0x7 << 13, + }; + + enum { + EXTENDED_FEATURE_SPDIF_AUDIO_TX = BIT(0), + EXTENDED_FEATURE_SPDIF_AUDIO_RX = BIT(1), + EXTENDED_FEATURE_RS232 = BIT(2), + EXTENDED_FEATURE_COMPRESSION_PIPES = BIT(3), + EXTENDED_FEATURE_INTERLACE = BIT(4), + }; + + u16 raw_features; + u16 raw_extended_features; + + memset(features, 0, sizeof(struct fpga_features)); + + FPGA_GET_REG(fpga, fpga_features, &raw_features); + FPGA_GET_REG(fpga, fpga_ext_features, &raw_extended_features); + + features->video_channels = raw_features & 0x3; + features->carriers = (raw_features >> 2) & 0x3; + + features->carrier_speed = (raw_features & FEATURE_CARRIER_SPEED_2_5) + ? CARRIER_SPEED_2_5G : CARRIER_SPEED_1G; + + switch (raw_features & FEATURE_RAM_MASK) { + case FEATURE_RAM_DDR2_32BIT: + features->ram_config = RAM_DDR2_32BIT_295MBPS; + break; + + case FEATURE_RAM_DDR3_32BIT: + features->ram_config = RAM_DDR3_32BIT_590MBPS; + break; + + case FEATURE_RAM_DDR3_48BIT: + features->ram_config = RAM_DDR3_48BIT_590MBPS; + break; + } + + features->pcm_tx = raw_features & FEATURE_PCM_AUDIO_TX; + features->pcm_rx = raw_features & FEATURE_PCM_AUDIO_RX; + features->spdif_tx = raw_extended_features & + EXTENDED_FEATURE_SPDIF_AUDIO_TX; + features->spdif_rx = raw_extended_features & + EXTENDED_FEATURE_SPDIF_AUDIO_RX; + + features->usb2 = raw_features & FEATURE_USB20; + features->rs232 = raw_extended_features & EXTENDED_FEATURE_RS232; + + features->compression_type1 = false; + features->compression_type2 = false; + features->compression_type3 = false; + switch (raw_features & FEATURE_COMPRESSION_MASK) { + case FEATURE_COMPRESSION_TYPE1_TYPE2_TYPE3: + features->compression_type3 = true; + case FEATURE_COMPRESSION_TYPE1_TYPE2: + features->compression_type2 = true; + case FEATURE_COMPRESSION_TYPE1: + features->compression_type1 = true; + break; + } + + features->interlace = raw_extended_features & + EXTENDED_FEATURE_INTERLACE; + features->osd = raw_features & FEATURE_OSD; + features->compression_pipes = raw_extended_features & + EXTENDED_FEATURE_COMPRESSION_PIPES; + + return 0; +} + +#endif + +static void fpga_print_info(struct udevice *dev) +{ + struct ihs_fpga_priv *priv = dev_get_priv(dev); + u16 fpga_version; + struct fpga_versions versions; + struct fpga_features features; + + ihs_fpga_get(priv->map, fpga_version, &fpga_version); + get_versions(dev, &versions); + get_features(dev, &features); + + priv->has_osd = features.osd; + + if (versions.video_channel) + printf("Videochannel"); + else + printf("Mainchannel"); + + if (versions.con_side) + printf(" User"); + else + printf(" Server"); + +// FIXME +#if 0 + if (versions & (1<<4)) + printf(" UC"); +#endif + + switch (versions.pcb_transmission_type) { + case PCB_CAT_1G: + case PCB_CAT_10G: + printf(" CAT"); + break; + case PCB_FIBER_3G: + case PCB_FIBER_10G: + printf(" Fiber"); + break; + }; + + switch (versions.pcb_video_type) { + case PCB_DVI_SL: + printf(" DVI,"); + break; + case PCB_DP_165MPIX: + printf(" DP 165MPix/s,"); + break; + case PCB_DP_300MPIX: + printf(" DP 300MPix/s,"); + break; + case PCB_HDMI: + printf(" HDMI,"); + break; + case PCB_DP_1_2: + printf(" DP 1.2,"); + break; + case PCB_HDMI_2_0: + printf(" HDMI 2.0,"); + break; + } + + printf(" FPGA V %d.%02d\n features: ", + fpga_version / 100, fpga_version % 100); + + if (!features.compression_type1 && + !features.compression_type2 && + !features.compression_type3) + printf("no compression, "); + + if (features.compression_type1) + printf("type1, "); + + if (features.compression_type2) + printf("type2, "); + + if (features.compression_type3) + printf("type3, "); + + printf("%sosd", features.osd ? "" : "no "); + + if (features.pcm_rx && features.pcm_tx) + printf(", pcm rx+tx"); + else if (features.pcm_rx) + printf(", pcm rx"); + else if (features.pcm_tx) + printf(", pcm tx"); + + if (features.spdif_rx && features.spdif_tx) + printf(", spdif rx+tx"); + else if (features.spdif_rx) + printf(", spdif rx"); + else if (features.spdif_tx) + printf(", spdif tx"); + + puts(",\n "); + + switch (features.sysclock) { + case SYSCLK_147456: + printf("clock 147.456 MHz"); + break; + } + + switch (features.ram_config) { + case RAM_DDR2_32BIT_295MBPS: + printf(", RAM 32 bit DDR2"); + break; + case RAM_DDR3_32BIT_590MBPS: + printf(", RAM 32 bit DDR3"); + break; + case RAM_DDR3_48BIT_590MBPS: + case RAM_DDR3_48BIT_1800MBPS: + printf(", RAM 48 bit DDR3"); + break; + case RAM_DDR3_64BIT_1800MBPS: + printf(", RAM 64 bit DDR3"); + break; + } + + printf(", %d carrier(s)", features.carriers); + + switch (features.carrier_speed) { + case CARRIER_SPEED_1G: + printf(", 1Gbit/s"); + break; + case CARRIER_SPEED_3G: + printf(", 3Gbit/s"); + break; + case CARRIER_SPEED_10G: + printf(", 10Gbit/s"); + break; + } + + printf(", %d video channel(s)\n", features.video_channels); +} + +static int do_reflection_test(struct udevice *dev) +{ + struct ihs_fpga_priv *priv = dev_get_priv(dev); + int ctr = 0; + + while (1) { + u16 val; + + ihs_fpga_set(priv->map, reflection_low, reflection_testpattern); + + ihs_fpga_get(priv->map, reflection_low, &val); + if (val == (~reflection_testpattern & 0xffff)) + return -EIO; + + mdelay(100); + if (ctr++ > 5) + return 0; + } +} + +static int ihs_fpga_probe(struct udevice *dev) +{ + struct ihs_fpga_priv *priv = dev_get_priv(dev); + + /* TODO: FPGA attached to MCLink bus */ + + regmap_init_mem(dev, &priv->map); + + gpio_request_by_name(dev, "reset-gpios", 0, &priv->reset_gpio, + GPIOD_IS_OUT); + if (!priv->reset_gpio.dev) { + printf("%s: Could not get reset-GPIO.\n", dev->name); + return -ENOENT; + } + + gpio_request_by_name(dev, "done-gpios", 0, &priv->done_gpio, + GPIOD_IS_IN); + if (!priv->done_gpio.dev) { + printf("%s: Could not get done-GPIO.\n", dev->name); + return -ENOENT; + } + + dm_gpio_set_value(&priv->reset_gpio, 1); + + if (!do_reflection_test(dev)) { + int ctr = 0; + + dm_gpio_set_value(&priv->reset_gpio, 0); + + while (!dm_gpio_get_value(&priv->done_gpio)) { + mdelay(100); + if (ctr++ > 5) { + printf("Initializing FPGA failed\n"); + break; + } + } + + udelay(10); + + dm_gpio_set_value(&priv->reset_gpio, 1); + + if (!do_reflection_test(dev)) { + printf("%s: Reflection test FAILED.\n", dev->name); + return -EIO; + } + } + + printf("%s: Reflection test passed.\n", dev->name); + + fpga_print_info(dev); + + return 0; +} + +static const struct udevice_id ihs_fpga_ids[] = { + { .compatible = "gdsys,iocon_fpga" }, + { .compatible = "gdsys,iocpu_fpga" }, + { } +}; + +U_BOOT_DRIVER(ihs_fpga_bus) = { + .name = "ihs_fpga_bus", + .id = UCLASS_MISC, + .of_match = ihs_fpga_ids, + .probe = ihs_fpga_probe, + .priv_auto_alloc_size = sizeof(struct ihs_fpga_priv), +}; diff --git a/drivers/misc/ihs_fpga.h b/drivers/misc/ihs_fpga.h new file mode 100644 index 0000000000..be36b0dc62 --- /dev/null +++ b/drivers/misc/ihs_fpga.h @@ -0,0 +1,26 @@ +/* + * (C) Copyright 2018 + * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +struct ihs_fpga_regs { + u16 reflection_low; + u16 versions; + u16 fpga_version; + u16 features; + u16 extended_features; + u16 top_interrupt; + u16 top_interrupt_enable; + u16 status; + u16 control; + u16 extended_control; +}; + +#define ihs_fpga_set(map, member, val) \ + regmap_set(map, struct ihs_fpga_regs, member, val) + +#define ihs_fpga_get(map, member, valp) \ + regmap_get(map, struct ihs_fpga_regs, member, valp) +

Hi Mario,
On 27/04/2018 14:51, Mario Six wrote:
The regmap functions currently assume that all register map accesses have a data width of 32 bits, but there are maps that have different widths.
Implement a size parameter for the regmap_read and regmap_write functions to specify the width of a desired read or write operation on a regmap.
This changes the regmap API which is based on the Linux API.
Linux passes a struct defining the regmap access type instead, I think the same should happen here.
Neil
Correct all current clients of the regmap API to use 32 bit width reads and writes to keep backwards compatibility.
Signed-off-by: Mario Six mario.six@gdsys.cc
v1 -> v2: New in v2
drivers/clk/at91/clk-utmi.c | 6 +++-- drivers/clk/clk_boston.c | 3 ++- drivers/core/regmap.c | 45 ++++++++++++++++++++++++------- drivers/phy/meson-gxl-usb2.c | 18 ++++++------- drivers/phy/meson-gxl-usb3.c | 22 +++++++-------- drivers/power/regulator/pbias_regulator.c | 5 ++-- drivers/reset/reset-meson.c | 14 +++++----- drivers/sysreset/sysreset_syscon.c | 2 +- include/regmap.h | 11 ++++++-- 9 files changed, 82 insertions(+), 44 deletions(-)
diff --git a/drivers/clk/at91/clk-utmi.c b/drivers/clk/at91/clk-utmi.c index 875bf293f9..1da625cab1 100644 --- a/drivers/clk/at91/clk-utmi.c +++ b/drivers/clk/at91/clk-utmi.c @@ -68,13 +68,15 @@ static int utmi_clk_enable(struct clk *clk) }
if (plat->regmap_sfr) {
err = regmap_read(plat->regmap_sfr, AT91_SFR_UTMICKTRIM, &tmp);
err = regmap_read(plat->regmap_sfr, AT91_SFR_UTMICKTRIM, &tmp,
REGMAP_SIZE_32);
if (err) return -EINVAL;
tmp &= ~AT91_UTMICKTRIM_FREQ; tmp |= utmi_ref_clk_freq;
err = regmap_write(plat->regmap_sfr, AT91_SFR_UTMICKTRIM, tmp);
err = regmap_write(plat->regmap_sfr, AT91_SFR_UTMICKTRIM, tmp,
if (err) return -EINVAL; } else if (utmi_ref_clk_freq) {REGMAP_SIZE_32);
diff --git a/drivers/clk/clk_boston.c b/drivers/clk/clk_boston.c index 5c05e3d78d..e09fd06fa0 100644 --- a/drivers/clk/clk_boston.c +++ b/drivers/clk/clk_boston.c @@ -33,7 +33,8 @@ static ulong clk_boston_get_rate(struct clk *clk) uint mmcmdiv; int err;
- err = regmap_read(state->regmap, BOSTON_PLAT_MMCMDIV, &mmcmdiv);
- err = regmap_read(state->regmap, BOSTON_PLAT_MMCMDIV, &mmcmdiv,
if (err) return 0;REGMAP_SIZE_32);
diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c index 8a0e00ff9a..c2cdff3979 100644 --- a/drivers/core/regmap.c +++ b/drivers/core/regmap.c @@ -130,20 +130,47 @@ int regmap_uninit(struct regmap *map) return 0; }
-int regmap_read(struct regmap *map, uint offset, uint *valp) +int regmap_read(struct regmap *map, ulong offset, ulong *valp,
enum regmap_size_t size)
{
- uint32_t *ptr = map_physmem(map->base + offset, 4, MAP_NOCACHE);
- *valp = le32_to_cpu(readl(ptr));
- void *ptr;
- switch (size) {
- case REGMAP_SIZE_8:
ptr = map_physmem(map->base + offset, 1, MAP_NOCACHE);
*valp = readb(ptr);
break;
- case REGMAP_SIZE_16:
ptr = map_physmem(map->base + offset, 2, MAP_NOCACHE);
*valp = le16_to_cpu(readw(ptr));
break;
- case REGMAP_SIZE_32:
ptr = map_physmem(map->base + offset, 4, MAP_NOCACHE);
*valp = le32_to_cpu(readl(ptr));
break;
- } return 0;
}
-int regmap_write(struct regmap *map, uint offset, uint val) +int regmap_write(struct regmap *map, ulong offset, ulong val,
enum regmap_size_t size)
{
- uint32_t *ptr = map_physmem(map->base + offset, 4, MAP_NOCACHE);
- writel(cpu_to_le32(val), ptr);
void *ptr;
switch (size) {
case REGMAP_SIZE_8:
ptr = map_physmem(map->base + offset, 1, MAP_NOCACHE);
writel((u8)val, ptr);
break;
case REGMAP_SIZE_16:
ptr = map_physmem(map->base + offset, 2, MAP_NOCACHE);
writel(cpu_to_le16((u16)val), ptr);
break;
case REGMAP_SIZE_32:
ptr = map_physmem(map->base + offset, 4, MAP_NOCACHE);
writel(cpu_to_le32((u32)val), ptr);
break;
}
return 0;
} diff --git a/drivers/phy/meson-gxl-usb2.c b/drivers/phy/meson-gxl-usb2.c index 15c9c89fd9..704b78747c 100644 --- a/drivers/phy/meson-gxl-usb2.c +++ b/drivers/phy/meson-gxl-usb2.c @@ -111,15 +111,15 @@ static void phy_meson_gxl_usb2_reset(struct phy_meson_gxl_usb2_priv *priv) { uint val;
- regmap_read(priv->regmap, U2P_R0, &val);
regmap_read(priv->regmap, U2P_R0, &val, REGMAP_SIZE_32);
/* reset the PHY and wait until settings are stabilized */ val |= U2P_R0_POWER_ON_RESET;
- regmap_write(priv->regmap, U2P_R0, val);
regmap_write(priv->regmap, U2P_R0, val, REGMAP_SIZE_32); udelay(RESET_COMPLETE_TIME);
val &= ~U2P_R0_POWER_ON_RESET;
- regmap_write(priv->regmap, U2P_R0, val);
- regmap_write(priv->regmap, U2P_R0, val, REGMAP_SIZE_32); udelay(RESET_COMPLETE_TIME);
}
@@ -128,11 +128,11 @@ phy_meson_gxl_usb2_set_host_mode(struct phy_meson_gxl_usb2_priv *priv) { uint val;
- regmap_read(priv->regmap, U2P_R0, &val);
- regmap_read(priv->regmap, U2P_R0, &val, REGMAP_SIZE_32); val |= U2P_R0_DM_PULLDOWN; val |= U2P_R0_DP_PULLDOWN; val &= ~U2P_R0_ID_PULLUP;
- regmap_write(priv->regmap, U2P_R0, val);
regmap_write(priv->regmap, U2P_R0, val, REGMAP_SIZE_32);
phy_meson_gxl_usb2_reset(priv);
} @@ -143,10 +143,10 @@ static int phy_meson_gxl_usb2_power_on(struct phy *phy) struct phy_meson_gxl_usb2_priv *priv = dev_get_priv(dev); uint val;
- regmap_read(priv->regmap, U2P_R0, &val);
- regmap_read(priv->regmap, U2P_R0, &val, REGMAP_SIZE_32); /* power on the PHY by taking it out of reset mode */ val &= ~U2P_R0_POWER_ON_RESET;
- regmap_write(priv->regmap, U2P_R0, val);
regmap_write(priv->regmap, U2P_R0, val, REGMAP_SIZE_32);
phy_meson_gxl_usb2_set_host_mode(priv);
@@ -167,10 +167,10 @@ static int phy_meson_gxl_usb2_power_off(struct phy *phy) struct phy_meson_gxl_usb2_priv *priv = dev_get_priv(dev); uint val;
- regmap_read(priv->regmap, U2P_R0, &val);
- regmap_read(priv->regmap, U2P_R0, &val, REGMAP_SIZE_32); /* power off the PHY by putting it into reset mode */ val |= U2P_R0_POWER_ON_RESET;
- regmap_write(priv->regmap, U2P_R0, val);
- regmap_write(priv->regmap, U2P_R0, val, REGMAP_SIZE_32);
#if CONFIG_IS_ENABLED(DM_REGULATOR) if (priv->phy_supply) { diff --git a/drivers/phy/meson-gxl-usb3.c b/drivers/phy/meson-gxl-usb3.c index a385fbdf12..33c24fd989 100644 --- a/drivers/phy/meson-gxl-usb3.c +++ b/drivers/phy/meson-gxl-usb3.c @@ -100,13 +100,13 @@ phy_meson_gxl_usb3_set_host_mode(struct phy_meson_gxl_usb3_priv *priv) { uint val;
- regmap_read(priv->regmap, USB_R0, &val);
- regmap_read(priv->regmap, USB_R0, &val, REGMAP_SIZE_32); val &= ~USB_R0_U2D_ACT;
- regmap_write(priv->regmap, USB_R0, val);
- regmap_write(priv->regmap, USB_R0, val, REGMAP_SIZE_32);
- regmap_read(priv->regmap, USB_R4, &val);
- regmap_read(priv->regmap, USB_R4, &val, REGMAP_SIZE_32); val &= ~USB_R4_P21_SLEEP_M0;
- regmap_write(priv->regmap, USB_R4, val);
regmap_write(priv->regmap, USB_R4, val, REGMAP_SIZE_32);
return 0;
} @@ -117,12 +117,12 @@ static int phy_meson_gxl_usb3_power_on(struct phy *phy) struct phy_meson_gxl_usb3_priv *priv = dev_get_priv(dev); uint val;
- regmap_read(priv->regmap, USB_R5, &val);
- regmap_read(priv->regmap, USB_R5, &val, REGMAP_SIZE_32); val |= USB_R5_ID_DIG_EN_0; val |= USB_R5_ID_DIG_EN_1; val &= ~USB_R5_ID_DIG_TH_MASK; val |= FIELD_PREP(USB_R5_ID_DIG_TH_MASK, 0xff);
- regmap_write(priv->regmap, USB_R5, val);
regmap_write(priv->regmap, USB_R5, val, REGMAP_SIZE_32);
return phy_meson_gxl_usb3_set_host_mode(priv);
} @@ -133,10 +133,10 @@ static int phy_meson_gxl_usb3_power_off(struct phy *phy) struct phy_meson_gxl_usb3_priv *priv = dev_get_priv(dev); uint val;
- regmap_read(priv->regmap, USB_R5, &val);
- regmap_read(priv->regmap, USB_R5, &val, REGMAP_SIZE_32); val &= ~USB_R5_ID_DIG_EN_0; val &= ~USB_R5_ID_DIG_EN_1;
- regmap_write(priv->regmap, USB_R5, val);
regmap_write(priv->regmap, USB_R5, val, REGMAP_SIZE_32);
return 0;
} @@ -147,10 +147,10 @@ static int phy_meson_gxl_usb3_init(struct phy *phy) struct phy_meson_gxl_usb3_priv *priv = dev_get_priv(dev); uint val;
- regmap_read(priv->regmap, USB_R1, &val);
- regmap_read(priv->regmap, USB_R1, &val, REGMAP_SIZE_32); val &= ~USB_R1_U3H_FLADJ_30MHZ_REG_MASK; val |= FIELD_PREP(USB_R1_U3H_FLADJ_30MHZ_REG_MASK, 0x20);
- regmap_write(priv->regmap, USB_R1, val);
regmap_write(priv->regmap, USB_R1, val, REGMAP_SIZE_32);
return 0;
} @@ -169,7 +169,7 @@ int meson_gxl_usb3_phy_probe(struct udevice *dev) ret = regmap_init_mem(dev, &priv->regmap); if (ret) return ret;
#if CONFIG_IS_ENABLED(CLK) ret = clk_get_by_index(dev, 0, &priv->clk); if (ret < 0) diff --git a/drivers/power/regulator/pbias_regulator.c b/drivers/power/regulator/pbias_regulator.c index adf589b224..386da3a58f 100644 --- a/drivers/power/regulator/pbias_regulator.c +++ b/drivers/power/regulator/pbias_regulator.c @@ -46,7 +46,7 @@ static int pbias_write(struct udevice *dev, uint reg, const uint8_t *buff, if (len != 4) return -EINVAL;
- return regmap_write(priv->regmap, priv->offset, val);
- return regmap_write(priv->regmap, priv->offset, val, REGMAP_SIZE_32);
}
static int pbias_read(struct udevice *dev, uint reg, uint8_t *buff, int len) @@ -56,7 +56,8 @@ static int pbias_read(struct udevice *dev, uint reg, uint8_t *buff, int len) if (len != 4) return -EINVAL;
- return regmap_read(priv->regmap, priv->offset, (u32 *)buff);
- return regmap_read(priv->regmap, priv->offset, (u32 *)buff,
REGMAP_SIZE_32);
}
static int pbias_ofdata_to_platdata(struct udevice *dev) diff --git a/drivers/reset/reset-meson.c b/drivers/reset/reset-meson.c index 5324f86f5f..c31f302143 100644 --- a/drivers/reset/reset-meson.c +++ b/drivers/reset/reset-meson.c @@ -41,12 +41,12 @@ static int meson_reset_level(struct reset_ctl *reset_ctl, bool assert) uint reg_offset = LEVEL_OFFSET + (bank << 2); uint val;
- regmap_read(priv->regmap, reg_offset, &val);
- regmap_read(priv->regmap, reg_offset, &val, REGMAP_SIZE_32); if (assert) val &= ~BIT(offset); else val |= BIT(offset);
- regmap_write(priv->regmap, reg_offset, val);
regmap_write(priv->regmap, reg_offset, val, REGMAP_SIZE_32);
return 0;
} @@ -68,15 +68,15 @@ struct reset_ops meson_reset_ops = { .rst_deassert = meson_reset_deassert, };
-static const struct udevice_id meson_reset_ids[] = {
- { .compatible = "amlogic,meson-gxbb-reset" },
- { }
-}; +static const struct udevice_id meson_reset_ids[] = {
- { .compatible = "amlogic,meson-gxbb-reset" },
- { }
+};
static int meson_reset_probe(struct udevice *dev) { struct meson_reset_priv *priv = dev_get_priv(dev);
- return regmap_init_mem(dev, &priv->regmap);
}
diff --git a/drivers/sysreset/sysreset_syscon.c b/drivers/sysreset/sysreset_syscon.c index 22c602a4d2..0c374a7443 100644 --- a/drivers/sysreset/sysreset_syscon.c +++ b/drivers/sysreset/sysreset_syscon.c @@ -25,7 +25,7 @@ static int syscon_reboot_request(struct udevice *dev, enum sysreset_t type) { struct syscon_reboot_priv *priv = dev_get_priv(dev);
- regmap_write(priv->regmap, priv->offset, priv->mask);
regmap_write(priv->regmap, priv->offset, priv->mask, REGMAP_SIZE_32);
return -EINPROGRESS;
} diff --git a/include/regmap.h b/include/regmap.h index 493a5d8eff..a6e2fafd27 100644 --- a/include/regmap.h +++ b/include/regmap.h @@ -8,6 +8,13 @@ #ifndef __REGMAP_H #define __REGMAP_H
+/* Access sizes for fpgamap reads and writes */ +enum regmap_size_t {
- REGMAP_SIZE_8 = 1,
- REGMAP_SIZE_16 = 2,
- REGMAP_SIZE_32 = 4,
+};
/**
- struct regmap_range - a register map range
@@ -37,8 +44,8 @@ struct regmap {
- Interface to provide access to registers either through a direct memory
- bus or through a peripheral bus like I2C, SPI.
*/ -int regmap_write(struct regmap *map, uint offset, uint val); -int regmap_read(struct regmap *map, uint offset, uint *valp); +int regmap_write(struct regmap *map, ulong offset, ulong val, enum regmap_size_t size); +int regmap_read(struct regmap *map, ulong offset, ulong *valp, enum regmap_size_t size);
#define regmap_write32(map, ptr, member, val) \ regmap_write(map, (uint32_t *)(ptr)->member - (uint32_t *)(ptr), val)

Hi Neil,
On Fri, Apr 27, 2018 at 3:00 PM, Neil Armstrong narmstrong@baylibre.com wrote:
Hi Mario,
On 27/04/2018 14:51, Mario Six wrote:
The regmap functions currently assume that all register map accesses have a data width of 32 bits, but there are maps that have different widths.
Implement a size parameter for the regmap_read and regmap_write functions to specify the width of a desired read or write operation on a regmap.
This changes the regmap API which is based on the Linux API.
Linux passes a struct defining the regmap access type instead, I think the same should happen here.
OK, I see what you mean.
I see that the Linux API also has regmap_raw_read/regmap_raw_write functions, which do have size parameters, so I think those would suite this use case rather nicely (and won't break the existing API).
Neil
Best regards, Mario
Correct all current clients of the regmap API to use 32 bit width reads and writes to keep backwards compatibility.
Signed-off-by: Mario Six mario.six@gdsys.cc
v1 -> v2: New in v2
drivers/clk/at91/clk-utmi.c | 6 +++-- drivers/clk/clk_boston.c | 3 ++- drivers/core/regmap.c | 45 ++++++++++++++++++++++++------- drivers/phy/meson-gxl-usb2.c | 18 ++++++------- drivers/phy/meson-gxl-usb3.c | 22 +++++++-------- drivers/power/regulator/pbias_regulator.c | 5 ++-- drivers/reset/reset-meson.c | 14 +++++----- drivers/sysreset/sysreset_syscon.c | 2 +- include/regmap.h | 11 ++++++-- 9 files changed, 82 insertions(+), 44 deletions(-)
diff --git a/drivers/clk/at91/clk-utmi.c b/drivers/clk/at91/clk-utmi.c index 875bf293f9..1da625cab1 100644 --- a/drivers/clk/at91/clk-utmi.c +++ b/drivers/clk/at91/clk-utmi.c @@ -68,13 +68,15 @@ static int utmi_clk_enable(struct clk *clk) }
if (plat->regmap_sfr) {
err = regmap_read(plat->regmap_sfr, AT91_SFR_UTMICKTRIM, &tmp);
err = regmap_read(plat->regmap_sfr, AT91_SFR_UTMICKTRIM, &tmp,
REGMAP_SIZE_32); if (err) return -EINVAL; tmp &= ~AT91_UTMICKTRIM_FREQ; tmp |= utmi_ref_clk_freq;
err = regmap_write(plat->regmap_sfr, AT91_SFR_UTMICKTRIM, tmp);
err = regmap_write(plat->regmap_sfr, AT91_SFR_UTMICKTRIM, tmp,
REGMAP_SIZE_32); if (err) return -EINVAL; } else if (utmi_ref_clk_freq) {
diff --git a/drivers/clk/clk_boston.c b/drivers/clk/clk_boston.c index 5c05e3d78d..e09fd06fa0 100644 --- a/drivers/clk/clk_boston.c +++ b/drivers/clk/clk_boston.c @@ -33,7 +33,8 @@ static ulong clk_boston_get_rate(struct clk *clk) uint mmcmdiv; int err;
err = regmap_read(state->regmap, BOSTON_PLAT_MMCMDIV, &mmcmdiv);
err = regmap_read(state->regmap, BOSTON_PLAT_MMCMDIV, &mmcmdiv,
REGMAP_SIZE_32); if (err) return 0;
diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c index 8a0e00ff9a..c2cdff3979 100644 --- a/drivers/core/regmap.c +++ b/drivers/core/regmap.c @@ -130,20 +130,47 @@ int regmap_uninit(struct regmap *map) return 0; }
-int regmap_read(struct regmap *map, uint offset, uint *valp) +int regmap_read(struct regmap *map, ulong offset, ulong *valp,
enum regmap_size_t size)
{
uint32_t *ptr = map_physmem(map->base + offset, 4, MAP_NOCACHE);
*valp = le32_to_cpu(readl(ptr));
void *ptr;
switch (size) {
case REGMAP_SIZE_8:
ptr = map_physmem(map->base + offset, 1, MAP_NOCACHE);
*valp = readb(ptr);
break;
case REGMAP_SIZE_16:
ptr = map_physmem(map->base + offset, 2, MAP_NOCACHE);
*valp = le16_to_cpu(readw(ptr));
break;
case REGMAP_SIZE_32:
ptr = map_physmem(map->base + offset, 4, MAP_NOCACHE);
*valp = le32_to_cpu(readl(ptr));
break;
} return 0;
}
-int regmap_write(struct regmap *map, uint offset, uint val) +int regmap_write(struct regmap *map, ulong offset, ulong val,
enum regmap_size_t size)
{
uint32_t *ptr = map_physmem(map->base + offset, 4, MAP_NOCACHE);
writel(cpu_to_le32(val), ptr);
void *ptr;
switch (size) {
case REGMAP_SIZE_8:
ptr = map_physmem(map->base + offset, 1, MAP_NOCACHE);
writel((u8)val, ptr);
break;
case REGMAP_SIZE_16:
ptr = map_physmem(map->base + offset, 2, MAP_NOCACHE);
writel(cpu_to_le16((u16)val), ptr);
break;
case REGMAP_SIZE_32:
ptr = map_physmem(map->base + offset, 4, MAP_NOCACHE);
writel(cpu_to_le32((u32)val), ptr);
break;
} return 0;
} diff --git a/drivers/phy/meson-gxl-usb2.c b/drivers/phy/meson-gxl-usb2.c index 15c9c89fd9..704b78747c 100644 --- a/drivers/phy/meson-gxl-usb2.c +++ b/drivers/phy/meson-gxl-usb2.c @@ -111,15 +111,15 @@ static void phy_meson_gxl_usb2_reset(struct phy_meson_gxl_usb2_priv *priv) { uint val;
regmap_read(priv->regmap, U2P_R0, &val);
regmap_read(priv->regmap, U2P_R0, &val, REGMAP_SIZE_32); /* reset the PHY and wait until settings are stabilized */ val |= U2P_R0_POWER_ON_RESET;
regmap_write(priv->regmap, U2P_R0, val);
regmap_write(priv->regmap, U2P_R0, val, REGMAP_SIZE_32); udelay(RESET_COMPLETE_TIME); val &= ~U2P_R0_POWER_ON_RESET;
regmap_write(priv->regmap, U2P_R0, val);
regmap_write(priv->regmap, U2P_R0, val, REGMAP_SIZE_32); udelay(RESET_COMPLETE_TIME);
}
@@ -128,11 +128,11 @@ phy_meson_gxl_usb2_set_host_mode(struct phy_meson_gxl_usb2_priv *priv) { uint val;
regmap_read(priv->regmap, U2P_R0, &val);
regmap_read(priv->regmap, U2P_R0, &val, REGMAP_SIZE_32); val |= U2P_R0_DM_PULLDOWN; val |= U2P_R0_DP_PULLDOWN; val &= ~U2P_R0_ID_PULLUP;
regmap_write(priv->regmap, U2P_R0, val);
regmap_write(priv->regmap, U2P_R0, val, REGMAP_SIZE_32); phy_meson_gxl_usb2_reset(priv);
} @@ -143,10 +143,10 @@ static int phy_meson_gxl_usb2_power_on(struct phy *phy) struct phy_meson_gxl_usb2_priv *priv = dev_get_priv(dev); uint val;
regmap_read(priv->regmap, U2P_R0, &val);
regmap_read(priv->regmap, U2P_R0, &val, REGMAP_SIZE_32); /* power on the PHY by taking it out of reset mode */ val &= ~U2P_R0_POWER_ON_RESET;
regmap_write(priv->regmap, U2P_R0, val);
regmap_write(priv->regmap, U2P_R0, val, REGMAP_SIZE_32); phy_meson_gxl_usb2_set_host_mode(priv);
@@ -167,10 +167,10 @@ static int phy_meson_gxl_usb2_power_off(struct phy *phy) struct phy_meson_gxl_usb2_priv *priv = dev_get_priv(dev); uint val;
regmap_read(priv->regmap, U2P_R0, &val);
regmap_read(priv->regmap, U2P_R0, &val, REGMAP_SIZE_32); /* power off the PHY by putting it into reset mode */ val |= U2P_R0_POWER_ON_RESET;
regmap_write(priv->regmap, U2P_R0, val);
regmap_write(priv->regmap, U2P_R0, val, REGMAP_SIZE_32);
#if CONFIG_IS_ENABLED(DM_REGULATOR) if (priv->phy_supply) { diff --git a/drivers/phy/meson-gxl-usb3.c b/drivers/phy/meson-gxl-usb3.c index a385fbdf12..33c24fd989 100644 --- a/drivers/phy/meson-gxl-usb3.c +++ b/drivers/phy/meson-gxl-usb3.c @@ -100,13 +100,13 @@ phy_meson_gxl_usb3_set_host_mode(struct phy_meson_gxl_usb3_priv *priv) { uint val;
regmap_read(priv->regmap, USB_R0, &val);
regmap_read(priv->regmap, USB_R0, &val, REGMAP_SIZE_32); val &= ~USB_R0_U2D_ACT;
regmap_write(priv->regmap, USB_R0, val);
regmap_write(priv->regmap, USB_R0, val, REGMAP_SIZE_32);
regmap_read(priv->regmap, USB_R4, &val);
regmap_read(priv->regmap, USB_R4, &val, REGMAP_SIZE_32); val &= ~USB_R4_P21_SLEEP_M0;
regmap_write(priv->regmap, USB_R4, val);
regmap_write(priv->regmap, USB_R4, val, REGMAP_SIZE_32); return 0;
} @@ -117,12 +117,12 @@ static int phy_meson_gxl_usb3_power_on(struct phy *phy) struct phy_meson_gxl_usb3_priv *priv = dev_get_priv(dev); uint val;
regmap_read(priv->regmap, USB_R5, &val);
regmap_read(priv->regmap, USB_R5, &val, REGMAP_SIZE_32); val |= USB_R5_ID_DIG_EN_0; val |= USB_R5_ID_DIG_EN_1; val &= ~USB_R5_ID_DIG_TH_MASK; val |= FIELD_PREP(USB_R5_ID_DIG_TH_MASK, 0xff);
regmap_write(priv->regmap, USB_R5, val);
regmap_write(priv->regmap, USB_R5, val, REGMAP_SIZE_32); return phy_meson_gxl_usb3_set_host_mode(priv);
} @@ -133,10 +133,10 @@ static int phy_meson_gxl_usb3_power_off(struct phy *phy) struct phy_meson_gxl_usb3_priv *priv = dev_get_priv(dev); uint val;
regmap_read(priv->regmap, USB_R5, &val);
regmap_read(priv->regmap, USB_R5, &val, REGMAP_SIZE_32); val &= ~USB_R5_ID_DIG_EN_0; val &= ~USB_R5_ID_DIG_EN_1;
regmap_write(priv->regmap, USB_R5, val);
regmap_write(priv->regmap, USB_R5, val, REGMAP_SIZE_32); return 0;
} @@ -147,10 +147,10 @@ static int phy_meson_gxl_usb3_init(struct phy *phy) struct phy_meson_gxl_usb3_priv *priv = dev_get_priv(dev); uint val;
regmap_read(priv->regmap, USB_R1, &val);
regmap_read(priv->regmap, USB_R1, &val, REGMAP_SIZE_32); val &= ~USB_R1_U3H_FLADJ_30MHZ_REG_MASK; val |= FIELD_PREP(USB_R1_U3H_FLADJ_30MHZ_REG_MASK, 0x20);
regmap_write(priv->regmap, USB_R1, val);
regmap_write(priv->regmap, USB_R1, val, REGMAP_SIZE_32); return 0;
} @@ -169,7 +169,7 @@ int meson_gxl_usb3_phy_probe(struct udevice *dev) ret = regmap_init_mem(dev, &priv->regmap); if (ret) return ret;
#if CONFIG_IS_ENABLED(CLK) ret = clk_get_by_index(dev, 0, &priv->clk); if (ret < 0) diff --git a/drivers/power/regulator/pbias_regulator.c b/drivers/power/regulator/pbias_regulator.c index adf589b224..386da3a58f 100644 --- a/drivers/power/regulator/pbias_regulator.c +++ b/drivers/power/regulator/pbias_regulator.c @@ -46,7 +46,7 @@ static int pbias_write(struct udevice *dev, uint reg, const uint8_t *buff, if (len != 4) return -EINVAL;
return regmap_write(priv->regmap, priv->offset, val);
return regmap_write(priv->regmap, priv->offset, val, REGMAP_SIZE_32);
}
static int pbias_read(struct udevice *dev, uint reg, uint8_t *buff, int len) @@ -56,7 +56,8 @@ static int pbias_read(struct udevice *dev, uint reg, uint8_t *buff, int len) if (len != 4) return -EINVAL;
return regmap_read(priv->regmap, priv->offset, (u32 *)buff);
return regmap_read(priv->regmap, priv->offset, (u32 *)buff,
REGMAP_SIZE_32);
}
static int pbias_ofdata_to_platdata(struct udevice *dev) diff --git a/drivers/reset/reset-meson.c b/drivers/reset/reset-meson.c index 5324f86f5f..c31f302143 100644 --- a/drivers/reset/reset-meson.c +++ b/drivers/reset/reset-meson.c @@ -41,12 +41,12 @@ static int meson_reset_level(struct reset_ctl *reset_ctl, bool assert) uint reg_offset = LEVEL_OFFSET + (bank << 2); uint val;
regmap_read(priv->regmap, reg_offset, &val);
regmap_read(priv->regmap, reg_offset, &val, REGMAP_SIZE_32); if (assert) val &= ~BIT(offset); else val |= BIT(offset);
regmap_write(priv->regmap, reg_offset, val);
regmap_write(priv->regmap, reg_offset, val, REGMAP_SIZE_32); return 0;
} @@ -68,15 +68,15 @@ struct reset_ops meson_reset_ops = { .rst_deassert = meson_reset_deassert, };
-static const struct udevice_id meson_reset_ids[] = {
{ .compatible = "amlogic,meson-gxbb-reset" },
{ }
-}; +static const struct udevice_id meson_reset_ids[] = {
{ .compatible = "amlogic,meson-gxbb-reset" },
{ }
+};
static int meson_reset_probe(struct udevice *dev) { struct meson_reset_priv *priv = dev_get_priv(dev);
return regmap_init_mem(dev, &priv->regmap);
}
diff --git a/drivers/sysreset/sysreset_syscon.c b/drivers/sysreset/sysreset_syscon.c index 22c602a4d2..0c374a7443 100644 --- a/drivers/sysreset/sysreset_syscon.c +++ b/drivers/sysreset/sysreset_syscon.c @@ -25,7 +25,7 @@ static int syscon_reboot_request(struct udevice *dev, enum sysreset_t type) { struct syscon_reboot_priv *priv = dev_get_priv(dev);
regmap_write(priv->regmap, priv->offset, priv->mask);
regmap_write(priv->regmap, priv->offset, priv->mask, REGMAP_SIZE_32); return -EINPROGRESS;
} diff --git a/include/regmap.h b/include/regmap.h index 493a5d8eff..a6e2fafd27 100644 --- a/include/regmap.h +++ b/include/regmap.h @@ -8,6 +8,13 @@ #ifndef __REGMAP_H #define __REGMAP_H
+/* Access sizes for fpgamap reads and writes */ +enum regmap_size_t {
REGMAP_SIZE_8 = 1,
REGMAP_SIZE_16 = 2,
REGMAP_SIZE_32 = 4,
+};
/**
- struct regmap_range - a register map range
@@ -37,8 +44,8 @@ struct regmap {
- Interface to provide access to registers either through a direct memory
- bus or through a peripheral bus like I2C, SPI.
*/ -int regmap_write(struct regmap *map, uint offset, uint val); -int regmap_read(struct regmap *map, uint offset, uint *valp); +int regmap_write(struct regmap *map, ulong offset, ulong val, enum regmap_size_t size); +int regmap_read(struct regmap *map, ulong offset, ulong *valp, enum regmap_size_t size);
#define regmap_write32(map, ptr, member, val) \ regmap_write(map, (uint32_t *)(ptr)->member - (uint32_t *)(ptr), val)
participants (3)
-
Mario Six
-
Neil Armstrong
-
Simon Glass