summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobert Jarzmik <robert.jarzmik@free.fr>2015-01-31 14:10:08 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2015-02-04 12:52:43 +0100
commitd6f8016ce7bc877a19c95d92e2ce1786aed78e8d (patch)
tree99af83a5f6f3b2468ef6e487570c38893a4b9e85
parent3155f5df4d908d9d2cac56720297fcf2e9a4a0c1 (diff)
downloadbarebox-d6f8016ce7bc877a19c95d92e2ce1786aed78e8d.tar.gz
barebox-d6f8016ce7bc877a19c95d92e2ce1786aed78e8d.tar.xz
net: smc1111: add 16 bits accessors, allow address shift
Smc network IPs can be wired up in different funny ways. For example the lubbock pxa25x development platform wires all address lines shifted by 2, ie. bus A2 is smc91c96 A0, bus A3 is smc91c96 A1 etc ... In order to cope with the different possible combination, add a shift parameter for addresses. By default, the old behaviour using the 32 bit accesses is kept. Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
-rw-r--r--drivers/net/smc91111.c134
-rw-r--r--include/net/smc91111.h2
2 files changed, 94 insertions, 42 deletions
diff --git a/drivers/net/smc91111.c b/drivers/net/smc91111.c
index 100688ccf8..1e194e4ce1 100644
--- a/drivers/net/smc91111.c
+++ b/drivers/net/smc91111.c
@@ -435,14 +435,14 @@
#define MEMORY_WAIT_TIME 16
struct accessors {
- void (*ob)(unsigned, void __iomem *);
- void (*ow)(unsigned, void __iomem *);
- void (*ol)(unsigned long, void __iomem *);
- void (*osl)(void __iomem *, const void *, int);
- unsigned (*ib)(void __iomem *);
- unsigned (*iw)(void __iomem *);
- unsigned long (*il)(void __iomem *);
- void (*isl)(void __iomem *, void*, int);
+ void (*ob)(unsigned, void __iomem *, unsigned, unsigned);
+ void (*ow)(unsigned, void __iomem *, unsigned, unsigned);
+ void (*ol)(unsigned long, void __iomem *, unsigned, unsigned);
+ void (*osl)(void __iomem *, unsigned, const void *, int, unsigned);
+ unsigned (*ib)(void __iomem *, unsigned, unsigned);
+ unsigned (*iw)(void __iomem *, unsigned, unsigned);
+ unsigned long (*il)(void __iomem *, unsigned, unsigned);
+ void (*isl)(void __iomem *, unsigned, void*, int, unsigned);
};
struct smc91c111_priv {
@@ -450,6 +450,7 @@ struct smc91c111_priv {
struct accessors a;
void __iomem *base;
int qemu_fixup;
+ unsigned shift;
};
#if (SMC_DEBUG > 2 )
@@ -479,56 +480,103 @@ struct smc91c111_priv {
#define ETH_ZLEN 60
-static void a_outb(unsigned value, void __iomem *offset)
+static void a8_outb(unsigned value, void __iomem *base, unsigned int offset,
+ unsigned shift)
{
- writeb(value, offset);
+ writeb(value, base + (offset << shift));
}
-static void a_outw(unsigned value, void __iomem *offset)
+static void a16_outw(unsigned value, void __iomem *base, unsigned int offset,
+ unsigned shift)
{
- writew(value, offset);
+ writew(value, base + (offset << shift));
}
-static void a_outl(unsigned long value, void __iomem *offset)
+static void a32_outl(unsigned long value, void __iomem *base,
+ unsigned int offset, unsigned shift)
{
- writel(value, offset);
+ writel(value, base + (offset << shift));
}
-static void a_outsl(void __iomem *offset, const void *data, int count)
+static void a16_outsl(void __iomem *base, unsigned int offset,
+ const void *data, int count, unsigned shift)
{
- writesl(offset, data, count);
+ writesw(base + (offset << shift), data, count * 2);
}
-static unsigned a_inb(void __iomem *offset)
+static void a16_outl(unsigned long value, void __iomem *base,
+ unsigned int offset, unsigned shift)
{
- return readb(offset);
+ writew(value & 0xffff, base + (offset << shift));
+ writew(value >> 16, base + ((offset + 2) << shift));
}
-static unsigned a_inw(void __iomem *offset)
+static void a32_outsl(void __iomem *base, unsigned int offset,
+ const void *data, int count, unsigned shift)
{
- return readw(offset);
+ writesw(base + (offset << shift), data, count * 2);
}
-static unsigned long a_inl(void __iomem *offset)
+static unsigned a8_inb(void __iomem *base, unsigned int offset, unsigned shift)
{
- return readl(offset);
+ return readb(base + (offset << shift));
}
-static inline void a_insl(void __iomem *offset, void *data, int count)
+static unsigned a16_inw(void __iomem *base, unsigned int offset, unsigned shift)
{
- readsl(offset, data, count);
+ return readw(base + (offset << shift));
}
+static unsigned long a16_inl(void __iomem *base, unsigned int offset,
+ unsigned shift)
+{
+ u32 value;
+
+ value = readw(base + (offset << shift));
+ value |= readw(base + (offset << shift)) << 16;
+
+ return value;
+}
+
+static inline void a16_insl(void __iomem *base, unsigned int offset, void *data,
+ int count, unsigned shift)
+{
+ readsw(base + (offset << shift), data, count * 2);
+}
+
+static unsigned long a32_inl(void __iomem *base, unsigned int offset,
+ unsigned shift)
+{
+ return readl(base + (offset << shift));
+}
+
+static inline void a32_insl(void __iomem *base, unsigned int offset, void *data,
+ int count, unsigned shift)
+{
+ readsl(base + (offset << shift), data, count);
+}
+
+static const struct accessors access_via_16bit = {
+ .ob = a8_outb,
+ .ow = a16_outw,
+ .ol = a16_outl,
+ .osl = a16_outsl,
+ .ib = a8_inb,
+ .iw = a16_inw,
+ .il = a16_inl,
+ .isl = a16_insl,
+};
+
/* access happens via a 32 bit bus */
static const struct accessors access_via_32bit = {
- .ob = a_outb,
- .ow = a_outw,
- .ol = a_outl,
- .osl = a_outsl,
- .ib = a_inb,
- .iw = a_inw,
- .il = a_inl,
- .isl = a_insl,
+ .ob = a8_outb,
+ .ow = a16_outw,
+ .ol = a32_outl,
+ .osl = a32_outsl,
+ .ib = a8_inb,
+ .iw = a16_inw,
+ .il = a32_inl,
+ .isl = a32_insl,
};
/* ------------------------------------------------------------------------ */
@@ -536,46 +584,46 @@ static const struct accessors access_via_32bit = {
static inline void SMC_outb(struct smc91c111_priv *p, unsigned value,
unsigned offset)
{
- (p->a.ob)(value, p->base + offset);
+ (p->a.ob)(value, p->base, offset, p->shift);
}
static inline void SMC_outw(struct smc91c111_priv *p, unsigned value,
unsigned offset)
{
- (p->a.ow)(value, p->base + offset);
+ (p->a.ow)(value, p->base, offset, p->shift);
}
static inline void SMC_outl(struct smc91c111_priv *p, unsigned long value,
unsigned offset)
{
- (p->a.ol)(value, p->base + offset);
+ (p->a.ol)(value, p->base, offset, p->shift);
}
static inline void SMC_outsl(struct smc91c111_priv *p, unsigned offset,
const void *data, int count)
{
- (p->a.osl)(p->base + offset, data, count);
+ (p->a.osl)(p->base, offset, data, count, p->shift);
}
static inline unsigned SMC_inb(struct smc91c111_priv *p, unsigned offset)
{
- return (p->a.ib)(p->base + offset);
+ return (p->a.ib)(p->base, offset, p->shift);
}
static inline unsigned SMC_inw(struct smc91c111_priv *p, unsigned offset)
{
- return (p->a.iw)(p->base + offset);
+ return (p->a.iw)(p->base, offset, p->shift);
}
static inline unsigned long SMC_inl(struct smc91c111_priv *p, unsigned offset)
{
- return (p->a.il)(p->base + offset);
+ return (p->a.il)(p->base, offset, p->shift);
}
static inline void SMC_insl(struct smc91c111_priv *p, unsigned offset,
void *data, int count)
{
- (p->a.isl)(p->base + offset, data, count);
+ (p->a.isl)(p->base, offset, data, count, p->shift);
}
static inline void SMC_SELECT_BANK(struct smc91c111_priv *p, int bank)
@@ -1333,15 +1381,17 @@ static int smc91c111_probe(struct device_d *dev)
edev->priv = (struct smc91c111_priv *)(edev + 1);
priv = edev->priv;
+ priv->a = access_via_32bit;
if (dev->platform_data) {
struct smc91c111_pdata *pdata = dev->platform_data;
priv->qemu_fixup = pdata->qemu_fixup;
+ priv->shift = pdata->addr_shift;
+ if (pdata->bus_width == 16)
+ priv->a = access_via_16bit;
}
- priv->a = access_via_32bit;
-
edev->init = smc91c111_init_dev;
edev->open = smc91c111_eth_open;
edev->send = smc91c111_eth_send;
diff --git a/include/net/smc91111.h b/include/net/smc91111.h
index 0b2d49bb19..5191c85079 100644
--- a/include/net/smc91111.h
+++ b/include/net/smc91111.h
@@ -9,6 +9,8 @@
struct smc91c111_pdata {
int qemu_fixup;
+ int addr_shift;
+ int bus_width;
};
#endif /* __SMC91111_H__ */