* [PATCH 1/6] miidev: fix auto negotiation
2012-06-18 14:47 [PATCH 0/6] misc ethernet fixes and new driver Johannes Stezenbach
@ 2012-06-18 14:47 ` Johannes Stezenbach
2012-06-18 17:52 ` Roberto Nibali
2012-06-18 14:47 ` [PATCH 2/6] miidev: actually probe the PHY Johannes Stezenbach
` (5 subsequent siblings)
6 siblings, 1 reply; 16+ messages in thread
From: Johannes Stezenbach @ 2012-06-18 14:47 UTC (permalink / raw)
To: barebox
The auto negotiation result is the intersect
of the advertised abilities and the link partner abilities.
Signed-off-by: Johannes Stezenbach <js@sig21.net>
---
drivers/net/miidev.c | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/drivers/net/miidev.c b/drivers/net/miidev.c
index f47fc9e..272234e 100644
--- a/drivers/net/miidev.c
+++ b/drivers/net/miidev.c
@@ -123,6 +123,7 @@ int miidev_wait_aneg(struct mii_device *mdev)
int miidev_get_status(struct mii_device *mdev)
{
+ int ret, status, adv, lpa;
int ret, status;
ret = mii_read(mdev, mdev->address, MII_BMSR);
@@ -136,13 +137,16 @@ int miidev_get_status(struct mii_device *mdev)
goto err_out;
if (ret & BMCR_ANENABLE) {
- ret = mii_read(mdev, mdev->address, MII_LPA);
- if (ret < 0)
+ lpa = mii_read(mdev, mdev->address, MII_LPA);
+ if (lpa < 0)
goto err_out;
-
- status |= ret & LPA_DUPLEX ? MIIDEV_STATUS_IS_FULL_DUPLEX : 0;
- status |= ret & LPA_100 ? MIIDEV_STATUS_IS_100MBIT :
- MIIDEV_STATUS_IS_10MBIT;
+ adv = mii_read(mdev, mdev->address, MII_ADVERTISE);
+ if (adv < 0)
+ goto err_out;
+ lpa &= adv;
+ status |= lpa & LPA_DUPLEX ? MIIDEV_STATUS_IS_FULL_DUPLEX : 0;
+ status |= lpa & LPA_100 ? MIIDEV_STATUS_IS_100MBIT :
+ MIIDEV_STATUS_IS_10MBIT;
} else {
status |= ret & BMCR_FULLDPLX ? MIIDEV_STATUS_IS_FULL_DUPLEX : 0;
status |= ret & BMCR_SPEED100 ? MIIDEV_STATUS_IS_100MBIT :
--
1.7.10.4
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 1/6] miidev: fix auto negotiation
2012-06-18 14:47 ` [PATCH 1/6] miidev: fix auto negotiation Johannes Stezenbach
@ 2012-06-18 17:52 ` Roberto Nibali
2012-06-18 19:26 ` Johannes Stezenbach
0 siblings, 1 reply; 16+ messages in thread
From: Roberto Nibali @ 2012-06-18 17:52 UTC (permalink / raw)
To: Johannes Stezenbach; +Cc: barebox
[-- Attachment #1.1: Type: text/plain, Size: 1689 bytes --]
Hi
On Mon, Jun 18, 2012 at 4:47 PM, Johannes Stezenbach <js@sig21.net> wrote:
> The auto negotiation result is the intersect
> of the advertised abilities and the link partner abilities.
>
> Signed-off-by: Johannes Stezenbach <js@sig21.net>
> ---
> drivers/net/miidev.c | 16 ++++++++++------
> 1 file changed, 10 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/net/miidev.c b/drivers/net/miidev.c
> index f47fc9e..272234e 100644
> --- a/drivers/net/miidev.c
> +++ b/drivers/net/miidev.c
> @@ -123,6 +123,7 @@ int miidev_wait_aneg(struct mii_device *mdev)
>
> int miidev_get_status(struct mii_device *mdev)
> {
> + int ret, status, adv, lpa;
> int ret, status;
>
> ret = mii_read(mdev, mdev->address, MII_BMSR);
> @@ -136,13 +137,16 @@ int miidev_get_status(struct mii_device *mdev)
> goto err_out;
>
> if (ret & BMCR_ANENABLE) {
> - ret = mii_read(mdev, mdev->address, MII_LPA);
> - if (ret < 0)
> + lpa = mii_read(mdev, mdev->address, MII_LPA);
> + if (lpa < 0)
> goto err_out;
> -
> - status |= ret & LPA_DUPLEX ? MIIDEV_STATUS_IS_FULL_DUPLEX
> : 0;
> - status |= ret & LPA_100 ? MIIDEV_STATUS_IS_100MBIT :
> - MIIDEV_STATUS_IS_10MBIT;
> + adv = mii_read(mdev, mdev->address, MII_ADVERTISE);
> + if (adv < 0)
> + goto err_out;
> + lpa &= adv;
>
Good catch and obviously correct. I reckon since nowadays most PHY's
advertise ADVERTISE_FULL or ADVERTISE_ALL, this has never been an issue for
anybody so far.
Best regards
Roberto
[-- Attachment #1.2: Type: text/html, Size: 2188 bytes --]
[-- Attachment #2: Type: text/plain, Size: 149 bytes --]
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 1/6] miidev: fix auto negotiation
2012-06-18 17:52 ` Roberto Nibali
@ 2012-06-18 19:26 ` Johannes Stezenbach
0 siblings, 0 replies; 16+ messages in thread
From: Johannes Stezenbach @ 2012-06-18 19:26 UTC (permalink / raw)
To: Roberto Nibali; +Cc: barebox
Hi,
On Mon, Jun 18, 2012 at 07:52:44PM +0200, Roberto Nibali wrote:
> On Mon, Jun 18, 2012 at 4:47 PM, Johannes Stezenbach <js@sig21.net> wrote:
>
> > The auto negotiation result is the intersect
> > of the advertised abilities and the link partner abilities.
>
> Good catch and obviously correct. I reckon since nowadays most PHY's
> advertise ADVERTISE_FULL or ADVERTISE_ALL, this has never been an issue for
> anybody so far.
I think most PHYs have strap pins which when set to 10M
will change the advertised abilities. This is used
rarely but it needs to work.
Johannes
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 2/6] miidev: actually probe the PHY
2012-06-18 14:47 [PATCH 0/6] misc ethernet fixes and new driver Johannes Stezenbach
2012-06-18 14:47 ` [PATCH 1/6] miidev: fix auto negotiation Johannes Stezenbach
@ 2012-06-18 14:47 ` Johannes Stezenbach
2012-06-18 18:27 ` Roberto Nibali
2012-06-18 14:47 ` [PATCH 3/6] miidev: add support for 1000Mbit Johannes Stezenbach
` (4 subsequent siblings)
6 siblings, 1 reply; 16+ messages in thread
From: Johannes Stezenbach @ 2012-06-18 14:47 UTC (permalink / raw)
To: barebox
Check if the PHY is really accessible (e.g. the
PHY address is correct) during probe.
Signed-off-by: Johannes Stezenbach <js@sig21.net>
---
drivers/net/miidev.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/drivers/net/miidev.c b/drivers/net/miidev.c
index 272234e..3545889 100644
--- a/drivers/net/miidev.c
+++ b/drivers/net/miidev.c
@@ -225,6 +225,14 @@ static struct file_operations miidev_ops = {
static int miidev_probe(struct device_d *dev)
{
struct mii_device *mdev = dev->priv;
+ int val;
+
+ val = mii_read(mdev, mdev->address, MII_PHYSID1);
+ if (val < 0 || val == 0xffff)
+ goto err_out;
+ val = mii_read(mdev, mdev->address, MII_PHYSID2);
+ if (val < 0 || val == 0xffff)
+ goto err_out;
mdev->cdev.name = asprintf("phy%d", dev->id);
mdev->cdev.size = 64;
@@ -234,6 +242,10 @@ static int miidev_probe(struct device_d *dev)
devfs_create(&mdev->cdev);
list_add_tail(&mdev->list, &miidev_list);
return 0;
+
+err_out:
+ dev_err(dev, "cannot read PHY registers (addr %d)\n", mdev->address);
+ return -ENODEV;
}
static void miidev_remove(struct device_d *dev)
--
1.7.10.4
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 2/6] miidev: actually probe the PHY
2012-06-18 14:47 ` [PATCH 2/6] miidev: actually probe the PHY Johannes Stezenbach
@ 2012-06-18 18:27 ` Roberto Nibali
2012-06-18 19:39 ` Johannes Stezenbach
0 siblings, 1 reply; 16+ messages in thread
From: Roberto Nibali @ 2012-06-18 18:27 UTC (permalink / raw)
To: Johannes Stezenbach; +Cc: barebox
[-- Attachment #1.1: Type: text/plain, Size: 1057 bytes --]
Hi
On Mon, Jun 18, 2012 at 4:47 PM, Johannes Stezenbach <js@sig21.net> wrote:
> Check if the PHY is really accessible (e.g. the
> PHY address is correct) during probe.
>
> Signed-off-by: Johannes Stezenbach <js@sig21.net>
> ---
> drivers/net/miidev.c | 12 ++++++++++++
> 1 file changed, 12 insertions(+)
>
> diff --git a/drivers/net/miidev.c b/drivers/net/miidev.c
> index 272234e..3545889 100644
> --- a/drivers/net/miidev.c
> +++ b/drivers/net/miidev.c
> @@ -225,6 +225,14 @@ static struct file_operations miidev_ops = {
> static int miidev_probe(struct device_d *dev)
> {
> struct mii_device *mdev = dev->priv;
> + int val;
> +
> + val = mii_read(mdev, mdev->address, MII_PHYSID1);
> + if (val < 0 || val == 0xffff)
> + goto err_out;
> + val = mii_read(mdev, mdev->address, MII_PHYSID2);
> + if (val < 0 || val == 0xffff)
> + goto err_out;
>
>
Suppose this has no influence on drivers/net/fec_imx.c:fec_set_hwaddr()
returning -1?
Otherwise I believe this is fine.
Cheers
Roberto
[-- Attachment #1.2: Type: text/html, Size: 1513 bytes --]
[-- Attachment #2: Type: text/plain, Size: 149 bytes --]
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 2/6] miidev: actually probe the PHY
2012-06-18 18:27 ` Roberto Nibali
@ 2012-06-18 19:39 ` Johannes Stezenbach
0 siblings, 0 replies; 16+ messages in thread
From: Johannes Stezenbach @ 2012-06-18 19:39 UTC (permalink / raw)
To: Roberto Nibali; +Cc: barebox
Hi,
On Mon, Jun 18, 2012 at 08:27:08PM +0200, Roberto Nibali wrote:
> On Mon, Jun 18, 2012 at 4:47 PM, Johannes Stezenbach <js@sig21.net> wrote:
>
> > Check if the PHY is really accessible (e.g. the
> > PHY address is correct) during probe.
> >
> > Signed-off-by: Johannes Stezenbach <js@sig21.net>
> > ---
> > drivers/net/miidev.c | 12 ++++++++++++
> > 1 file changed, 12 insertions(+)
> >
> > diff --git a/drivers/net/miidev.c b/drivers/net/miidev.c
> > index 272234e..3545889 100644
> > --- a/drivers/net/miidev.c
> > +++ b/drivers/net/miidev.c
> > @@ -225,6 +225,14 @@ static struct file_operations miidev_ops = {
> > static int miidev_probe(struct device_d *dev)
> > {
> > struct mii_device *mdev = dev->priv;
> > + int val;
> > +
> > + val = mii_read(mdev, mdev->address, MII_PHYSID1);
> > + if (val < 0 || val == 0xffff)
> > + goto err_out;
> > + val = mii_read(mdev, mdev->address, MII_PHYSID2);
> > + if (val < 0 || val == 0xffff)
> > + goto err_out;
> >
> >
> Suppose this has no influence on drivers/net/fec_imx.c:fec_set_hwaddr()
> returning -1?
Well, the MAC address goes to the MAC not the PHY... so it
shouldn't have any adverse effect on that.
Besides checking that the PHY address is correct this also
catches cases where the PHY is broken or not soldered correctly,
or when the MDIO clock divisor is wrong etc.
Can save time in trouble shooting.
Johannes
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 3/6] miidev: add support for 1000Mbit
2012-06-18 14:47 [PATCH 0/6] misc ethernet fixes and new driver Johannes Stezenbach
2012-06-18 14:47 ` [PATCH 1/6] miidev: fix auto negotiation Johannes Stezenbach
2012-06-18 14:47 ` [PATCH 2/6] miidev: actually probe the PHY Johannes Stezenbach
@ 2012-06-18 14:47 ` Johannes Stezenbach
2012-06-18 14:47 ` [PATCH 4/6] miidev: consistent md and mw on phy regs Johannes Stezenbach
` (3 subsequent siblings)
6 siblings, 0 replies; 16+ messages in thread
From: Johannes Stezenbach @ 2012-06-18 14:47 UTC (permalink / raw)
To: barebox
Signed-off-by: Johannes Stezenbach <js@sig21.net>
---
drivers/net/miidev.c | 32 +++++++++++++++++++++++++++++---
include/miidev.h | 4 ++++
2 files changed, 33 insertions(+), 3 deletions(-)
diff --git a/drivers/net/miidev.c b/drivers/net/miidev.c
index 3545889..98ad790 100644
--- a/drivers/net/miidev.c
+++ b/drivers/net/miidev.c
@@ -124,7 +124,6 @@ int miidev_wait_aneg(struct mii_device *mdev)
int miidev_get_status(struct mii_device *mdev)
{
int ret, status, adv, lpa;
- int ret, status;
ret = mii_read(mdev, mdev->address, MII_BMSR);
if (ret < 0)
@@ -137,6 +136,21 @@ int miidev_get_status(struct mii_device *mdev)
goto err_out;
if (ret & BMCR_ANENABLE) {
+ if (mdev->capabilities & MIIDEV_CAPABLE_1000M) {
+ lpa = mii_read(mdev, mdev->address, MII_STAT1000);
+ if (lpa < 0)
+ goto err_out;
+ adv = mii_read(mdev, mdev->address, MII_CTRL1000);
+ if (adv < 0)
+ goto err_out;
+ lpa &= adv << 2;
+ if (lpa & (LPA_1000FULL | LPA_1000HALF)) {
+ if (lpa & LPA_1000FULL)
+ status |= MIIDEV_STATUS_IS_FULL_DUPLEX;
+ status |= MIIDEV_STATUS_IS_1000MBIT;
+ return status;
+ }
+ }
lpa = mii_read(mdev, mdev->address, MII_LPA);
if (lpa < 0)
goto err_out;
@@ -174,8 +188,8 @@ int miidev_print_status(struct mii_device *mdev)
return status;
duplex = status & MIIDEV_STATUS_IS_FULL_DUPLEX ? "Full" : "Half";
- speed = status & MIIDEV_STATUS_IS_100MBIT ? 100 : 10;
-
+ speed = status & MIIDEV_STATUS_IS_1000MBIT ? 1000 :
+ (status & MIIDEV_STATUS_IS_100MBIT ? 100 : 10);
printf("%s: Link is %s", mdev->cdev.name,
status & MIIDEV_STATUS_IS_UP ? "up" : "down");
@@ -226,6 +240,7 @@ static int miidev_probe(struct device_d *dev)
{
struct mii_device *mdev = dev->priv;
int val;
+ int caps = 0;
val = mii_read(mdev, mdev->address, MII_PHYSID1);
if (val < 0 || val == 0xffff)
@@ -233,7 +248,18 @@ static int miidev_probe(struct device_d *dev)
val = mii_read(mdev, mdev->address, MII_PHYSID2);
if (val < 0 || val == 0xffff)
goto err_out;
+ val = mii_read(mdev, mdev->address, MII_BMSR);
+ if (val < 0)
+ goto err_out;
+ if (val & BMSR_ESTATEN) {
+ val = mii_read(mdev, mdev->address, MII_ESTATUS);
+ if (val < 0)
+ goto err_out;
+ if (val & (ESTATUS_1000_TFULL | ESTATUS_1000_THALF))
+ caps = MIIDEV_CAPABLE_1000M;
+ }
+ mdev->capabilities = caps;
mdev->cdev.name = asprintf("phy%d", dev->id);
mdev->cdev.size = 64;
mdev->cdev.ops = &miidev_ops;
diff --git a/include/miidev.h b/include/miidev.h
index 622784f..4bbf94c 100644
--- a/include/miidev.h
+++ b/include/miidev.h
@@ -31,6 +31,8 @@
#define MIIDEV_FORCE_10 (1 << 0)
#define MIIDEV_FORCE_LINK (1 << 1)
+#define MIIDEV_CAPABLE_1000M (1 << 0)
+
struct mii_device {
struct device_d dev;
struct device_d *parent;
@@ -40,6 +42,7 @@ struct mii_device {
int (*write) (struct mii_device *dev, int addr, int reg, int value);
int flags;
+ int capabilities;
struct eth_device *edev;
struct cdev cdev;
@@ -55,6 +58,7 @@ int miidev_get_status(struct mii_device *mdev);
#define MIIDEV_STATUS_IS_FULL_DUPLEX (1 << 1)
#define MIIDEV_STATUS_IS_10MBIT (1 << 2)
#define MIIDEV_STATUS_IS_100MBIT (1 << 3)
+#define MIIDEV_STATUS_IS_1000MBIT (1 << 4)
int miidev_print_status(struct mii_device *mdev);
static int inline mii_write(struct mii_device *dev, int addr, int reg, int value)
--
1.7.10.4
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 4/6] miidev: consistent md and mw on phy regs
2012-06-18 14:47 [PATCH 0/6] misc ethernet fixes and new driver Johannes Stezenbach
` (2 preceding siblings ...)
2012-06-18 14:47 ` [PATCH 3/6] miidev: add support for 1000Mbit Johannes Stezenbach
@ 2012-06-18 14:47 ` Johannes Stezenbach
2012-06-20 6:49 ` Sascha Hauer
2012-06-18 14:47 ` [PATCH 5/6] eth: eth MAC addresses are six bytes Johannes Stezenbach
` (2 subsequent siblings)
6 siblings, 1 reply; 16+ messages in thread
From: Johannes Stezenbach @ 2012-06-18 14:47 UTC (permalink / raw)
To: barebox
The dump generated by "md -w -s /dev/phy0"
suggests individual registers need to be
addressed by byte offset, not by register number.
E.g. to set the autonegotiation advertisement register
for 10Mbit only, use "mw -w -d /dev/phy0 8+2 0x0061".
The current mix of offset == register number, but
count == byte count is unintuitive.
Also, to be consistent with "md" on /dev/mem, round up
the count so "8+1" also works to access one register.
However, no attempt is made to do read-modify-write
single byte writes.
Signed-off-by: Johannes Stezenbach <js@sig21.net>
---
drivers/net/miidev.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/net/miidev.c b/drivers/net/miidev.c
index 98ad790..1c75b87 100644
--- a/drivers/net/miidev.c
+++ b/drivers/net/miidev.c
@@ -204,11 +204,11 @@ static ssize_t miidev_read(struct cdev *cdev, void *_buf, size_t count, ulong of
uint16_t *buf = _buf;
struct mii_device *mdev = cdev->priv;
- while (i > 1) {
- *buf = mii_read(mdev, mdev->address, offset);
+ while (i > 0) {
+ *buf = mii_read(mdev, mdev->address, offset / 2);
buf++;
i -= 2;
- offset++;
+ offset += 2;
}
return count;
@@ -220,11 +220,11 @@ static ssize_t miidev_write(struct cdev *cdev, const void *_buf, size_t count, u
const uint16_t *buf = _buf;
struct mii_device *mdev = cdev->priv;
- while (i > 1) {
- mii_write(mdev, mdev->address, offset, *buf);
+ while (i > 0) {
+ mii_write(mdev, mdev->address, offset / 2, *buf);
buf++;
i -= 2;
- offset++;
+ offset += 2;
}
return count;
--
1.7.10.4
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 4/6] miidev: consistent md and mw on phy regs
2012-06-18 14:47 ` [PATCH 4/6] miidev: consistent md and mw on phy regs Johannes Stezenbach
@ 2012-06-20 6:49 ` Sascha Hauer
0 siblings, 0 replies; 16+ messages in thread
From: Sascha Hauer @ 2012-06-20 6:49 UTC (permalink / raw)
To: Johannes Stezenbach; +Cc: barebox
On Mon, Jun 18, 2012 at 04:47:58PM +0200, Johannes Stezenbach wrote:
> The dump generated by "md -w -s /dev/phy0"
> suggests individual registers need to be
> addressed by byte offset, not by register number.
> E.g. to set the autonegotiation advertisement register
> for 10Mbit only, use "mw -w -d /dev/phy0 8+2 0x0061".
> The current mix of offset == register number, but
> count == byte count is unintuitive.
>
> Also, to be consistent with "md" on /dev/mem, round up
> the count so "8+1" also works to access one register.
> However, no attempt is made to do read-modify-write
> single byte writes.
>
> Signed-off-by: Johannes Stezenbach <js@sig21.net>
Nice catch. The current behaviour wasn't intended. I probably never
tried to read phy registers with an offset from the command line.
Sascha
> ---
> drivers/net/miidev.c | 12 ++++++------
> 1 file changed, 6 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/net/miidev.c b/drivers/net/miidev.c
> index 98ad790..1c75b87 100644
> --- a/drivers/net/miidev.c
> +++ b/drivers/net/miidev.c
> @@ -204,11 +204,11 @@ static ssize_t miidev_read(struct cdev *cdev, void *_buf, size_t count, ulong of
> uint16_t *buf = _buf;
> struct mii_device *mdev = cdev->priv;
>
> - while (i > 1) {
> - *buf = mii_read(mdev, mdev->address, offset);
> + while (i > 0) {
> + *buf = mii_read(mdev, mdev->address, offset / 2);
> buf++;
> i -= 2;
> - offset++;
> + offset += 2;
> }
>
> return count;
> @@ -220,11 +220,11 @@ static ssize_t miidev_write(struct cdev *cdev, const void *_buf, size_t count, u
> const uint16_t *buf = _buf;
> struct mii_device *mdev = cdev->priv;
>
> - while (i > 1) {
> - mii_write(mdev, mdev->address, offset, *buf);
> + while (i > 0) {
> + mii_write(mdev, mdev->address, offset / 2, *buf);
> buf++;
> i -= 2;
> - offset++;
> + offset += 2;
> }
>
> return count;
> --
> 1.7.10.4
>
>
> _______________________________________________
> barebox mailing list
> barebox@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox
>
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 5/6] eth: eth MAC addresses are six bytes
2012-06-18 14:47 [PATCH 0/6] misc ethernet fixes and new driver Johannes Stezenbach
` (3 preceding siblings ...)
2012-06-18 14:47 ` [PATCH 4/6] miidev: consistent md and mw on phy regs Johannes Stezenbach
@ 2012-06-18 14:47 ` Johannes Stezenbach
2012-06-18 14:48 ` [PATCH 6/6] drivers/net: add designware driver Johannes Stezenbach
2012-06-20 7:15 ` [PATCH 0/6] misc ethernet fixes and new driver Sascha Hauer
6 siblings, 0 replies; 16+ messages in thread
From: Johannes Stezenbach @ 2012-06-18 14:47 UTC (permalink / raw)
To: barebox
Reduce confusion by making clear six bytes are passed,
not a string.
Signed-off-by: Johannes Stezenbach <js@sig21.net>
---
include/net.h | 8 ++++----
net/eth.c | 2 +-
net/net.c | 4 ++--
3 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/include/net.h b/include/net.h
index 08f897e..9152943 100644
--- a/include/net.h
+++ b/include/net.h
@@ -38,8 +38,8 @@ struct eth_device {
int (*send) (struct eth_device*, void *packet, int length);
int (*recv) (struct eth_device*);
void (*halt) (struct eth_device*);
- int (*get_ethaddr) (struct eth_device*, unsigned char *adr);
- int (*set_ethaddr) (struct eth_device*, unsigned char *adr);
+ int (*get_ethaddr) (struct eth_device*, u8 adr[6]);
+ int (*set_ethaddr) (struct eth_device*, u8 adr[6]);
struct eth_device *next;
void *priv;
@@ -287,8 +287,8 @@ int string_to_ip(const char *s, IPaddr_t *ip);
IPaddr_t getenv_ip(const char *name);
int setenv_ip(const char *name, IPaddr_t ip);
-int string_to_ethaddr(const char *str, char *enetaddr);
-void ethaddr_to_string(const unsigned char *enetaddr, char *str);
+int string_to_ethaddr(const char *str, u8 enetaddr[6]);
+void ethaddr_to_string(const u8 enetaddr[6], char *str);
#ifdef CONFIG_NET_RESOLV
IPaddr_t resolv(char *host);
diff --git a/net/eth.c b/net/eth.c
index 2b492ad..30d347a 100644
--- a/net/eth.c
+++ b/net/eth.c
@@ -169,7 +169,7 @@ int eth_rx(void)
static int eth_set_ethaddr(struct device_d *dev, struct param_d *param, const char *val)
{
struct eth_device *edev = dev_to_edev(dev);
- char ethaddr[sizeof("xx:xx:xx:xx:xx:xx")];
+ u8 ethaddr[6];
if (!val)
return dev_param_set_generic(dev, param, NULL);
diff --git a/net/net.c b/net/net.c
index c803c48..54d8c25 100644
--- a/net/net.c
+++ b/net/net.c
@@ -159,7 +159,7 @@ void print_IPaddr (IPaddr_t x)
puts(ip_to_string(x));
}
-int string_to_ethaddr(const char *str, char *enetaddr)
+int string_to_ethaddr(const char *str, u8 enetaddr[6])
{
int reg;
char *e;
@@ -181,7 +181,7 @@ int string_to_ethaddr(const char *str, char *enetaddr)
return 0;
}
-void ethaddr_to_string(const unsigned char *enetaddr, char *str)
+void ethaddr_to_string(const u8 enetaddr[6], char *str)
{
sprintf(str, "%02X:%02X:%02X:%02X:%02X:%02X",
enetaddr[0], enetaddr[1], enetaddr[2], enetaddr[3],
--
1.7.10.4
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 6/6] drivers/net: add designware driver
2012-06-18 14:47 [PATCH 0/6] misc ethernet fixes and new driver Johannes Stezenbach
` (4 preceding siblings ...)
2012-06-18 14:47 ` [PATCH 5/6] eth: eth MAC addresses are six bytes Johannes Stezenbach
@ 2012-06-18 14:48 ` Johannes Stezenbach
2012-06-20 7:13 ` Sascha Hauer
2012-06-20 7:15 ` [PATCH 0/6] misc ethernet fixes and new driver Sascha Hauer
6 siblings, 1 reply; 16+ messages in thread
From: Johannes Stezenbach @ 2012-06-18 14:48 UTC (permalink / raw)
To: barebox
Straight forward port of Synopsys Designware ethernet
driver from u-boot v2012.04.01.
Signed-off-by: Johannes Stezenbach <js@sig21.net>
---
drivers/net/Kconfig | 11 ++
drivers/net/Makefile | 1 +
drivers/net/designware.c | 433 ++++++++++++++++++++++++++++++++++++++++++++++
drivers/net/designware.h | 230 ++++++++++++++++++++++++
include/net/designware.h | 9 +
5 files changed, 684 insertions(+)
create mode 100644 drivers/net/designware.c
create mode 100644 drivers/net/designware.h
create mode 100644 include/net/designware.h
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 172cc39..ba59715 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -13,6 +13,9 @@ config HAS_AT91_ETHER
config HAS_NETX_ETHER
bool
+config HAS_DESIGNWARE_ETH
+ bool
+
config ARCH_HAS_FEC_IMX
bool
@@ -108,6 +111,14 @@ config DRIVER_NET_KS8851_MLL
This option enables support for the Micrel KS8851 MLL
ethernet chip.
+config DRIVER_NET_DESIGNWARE
+ bool "Designware Universal MAC ethernet driver"
+ select MIIDEV
+ depends on HAS_DESIGNWARE_ETH
+ help
+ This option enables support for the Synopsys
+ Designware Core Univesal MAC 10M/100M/1G ethernet IP.
+
source "drivers/net/usb/Kconfig"
endmenu
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 34dbee9..29727b7 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -13,3 +13,4 @@ obj-$(CONFIG_MIIDEV) += miidev.o
obj-$(CONFIG_NET_USB) += usb/
obj-$(CONFIG_DRIVER_NET_TSE) += altera_tse.o
obj-$(CONFIG_DRIVER_NET_KS8851_MLL) += ks8851_mll.o
+obj-$(CONFIG_DRIVER_NET_DESIGNWARE) += designware.o
diff --git a/drivers/net/designware.c b/drivers/net/designware.c
new file mode 100644
index 0000000..d9a87b0
--- /dev/null
+++ b/drivers/net/designware.c
@@ -0,0 +1,433 @@
+/*
+ * (C) Copyright 2010
+ * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * Designware ethernet IP driver for u-boot
+ */
+
+#include <common.h>
+#include <init.h>
+#include <io.h>
+#include <net.h>
+#include <miidev.h>
+#include <asm/mmu.h>
+#include <net/designware.h>
+#include "designware.h"
+
+
+struct dw_eth_dev {
+ struct eth_device netdev;
+ struct mii_device miidev;
+
+ void (*fix_mac_speed)(int speed);
+ u8 macaddr[6];
+ u32 tx_currdescnum;
+ u32 rx_currdescnum;
+
+ struct dmamacdescr *tx_mac_descrtable;
+ struct dmamacdescr *rx_mac_descrtable;
+
+ u8 *txbuffs;
+ u8 *rxbuffs;
+
+ struct eth_mac_regs *mac_regs_p;
+ struct eth_dma_regs *dma_regs_p;
+};
+
+/* Speed specific definitions */
+#define SPEED_10M 1
+#define SPEED_100M 2
+#define SPEED_1000M 3
+
+/* Duplex mode specific definitions */
+#define HALF_DUPLEX 1
+#define FULL_DUPLEX 2
+
+
+static int dwc_ether_mii_read(struct mii_device *dev, int addr, int reg)
+{
+ struct dw_eth_dev *priv = dev->edev->priv;
+ struct eth_mac_regs *mac_p = priv->mac_regs_p;
+ u64 start;
+ u32 miiaddr;
+
+ miiaddr = ((addr << MIIADDRSHIFT) & MII_ADDRMSK) | \
+ ((reg << MIIREGSHIFT) & MII_REGMSK);
+
+ writel(miiaddr | MII_CLKRANGE_150_250M | MII_BUSY, &mac_p->miiaddr);
+
+ start = get_time_ns();
+ while (readl(&mac_p->miiaddr) & MII_BUSY) {
+ if (is_timeout(start, 10 * MSECOND)) {
+ dev_err(&priv->netdev.dev, "MDIO timeout\n");
+ return -EIO;
+ }
+ udelay(10);
+ }
+ return readl(&mac_p->miidata) & 0xffff;
+}
+
+static int dwc_ether_mii_write(struct mii_device *dev, int addr, int reg, int val)
+{
+ struct dw_eth_dev *priv = dev->edev->priv;
+ struct eth_mac_regs *mac_p = priv->mac_regs_p;
+ u64 start;
+ u32 miiaddr;
+
+ writel(val, &mac_p->miidata);
+ miiaddr = ((addr << MIIADDRSHIFT) & MII_ADDRMSK) | \
+ ((reg << MIIREGSHIFT) & MII_REGMSK) | MII_WRITE;
+
+ writel(miiaddr | MII_CLKRANGE_150_250M | MII_BUSY, &mac_p->miiaddr);
+
+ start = get_time_ns();
+ while (readl(&mac_p->miiaddr) & MII_BUSY) {
+ if (is_timeout(start, 10 * MSECOND)) {
+ dev_err(&priv->netdev.dev, "MDIO timeout\n");
+ return -EIO;
+ }
+ udelay(10);
+ }
+
+ /* Needed as a fix for ST-Phy */
+ dwc_ether_mii_read(dev, addr, reg);
+ return 0;
+}
+
+
+static int mac_reset(struct eth_device *dev)
+{
+ struct dw_eth_dev *priv = dev->priv;
+ struct eth_mac_regs *mac_p = priv->mac_regs_p;
+ struct eth_dma_regs *dma_p = priv->dma_regs_p;
+ u64 start;
+
+ writel(DMAMAC_SRST, &dma_p->busmode);
+ writel(MII_PORTSELECT, &mac_p->conf);
+
+ start = get_time_ns();
+ while (readl(&dma_p->busmode) & DMAMAC_SRST) {
+ if (is_timeout(start, 10 * MSECOND)) {
+ dev_err(&priv->netdev.dev, "MAC reset timeout\n");
+ return -EIO;
+ }
+ udelay(10);
+ }
+ return 0;
+}
+
+static void tx_descs_init(struct eth_device *dev)
+{
+ struct dw_eth_dev *priv = dev->priv;
+ struct eth_dma_regs *dma_p = priv->dma_regs_p;
+ struct dmamacdescr *desc_table_p = &priv->tx_mac_descrtable[0];
+ char *txbuffs = &priv->txbuffs[0];
+ struct dmamacdescr *desc_p;
+ u32 idx;
+
+ for (idx = 0; idx < CONFIG_TX_DESCR_NUM; idx++) {
+ desc_p = &desc_table_p[idx];
+ desc_p->dmamac_addr = &txbuffs[idx * CONFIG_ETH_BUFSIZE];
+ desc_p->dmamac_next = &desc_table_p[idx + 1];
+
+#if defined(CONFIG_DW_ALTDESCRIPTOR)
+ desc_p->txrx_status &= ~(DESC_TXSTS_TXINT | DESC_TXSTS_TXLAST |
+ DESC_TXSTS_TXFIRST | DESC_TXSTS_TXCRCDIS | \
+ DESC_TXSTS_TXCHECKINSCTRL | \
+ DESC_TXSTS_TXRINGEND | DESC_TXSTS_TXPADDIS);
+
+ desc_p->txrx_status |= DESC_TXSTS_TXCHAIN;
+ desc_p->dmamac_cntl = 0;
+ desc_p->txrx_status &= ~(DESC_TXSTS_MSK | DESC_TXSTS_OWNBYDMA);
+#else
+ desc_p->dmamac_cntl = DESC_TXCTRL_TXCHAIN;
+ desc_p->txrx_status = 0;
+#endif
+ }
+
+ /* Correcting the last pointer of the chain */
+ desc_p->dmamac_next = &desc_table_p[0];
+
+ writel((ulong)&desc_table_p[0], &dma_p->txdesclistaddr);
+}
+
+static void rx_descs_init(struct eth_device *dev)
+{
+ struct dw_eth_dev *priv = dev->priv;
+ struct eth_dma_regs *dma_p = priv->dma_regs_p;
+ struct dmamacdescr *desc_table_p = &priv->rx_mac_descrtable[0];
+ char *rxbuffs = &priv->rxbuffs[0];
+ struct dmamacdescr *desc_p;
+ u32 idx;
+
+ for (idx = 0; idx < CONFIG_RX_DESCR_NUM; idx++) {
+ desc_p = &desc_table_p[idx];
+ desc_p->dmamac_addr = &rxbuffs[idx * CONFIG_ETH_BUFSIZE];
+ desc_p->dmamac_next = &desc_table_p[idx + 1];
+
+ desc_p->dmamac_cntl =
+ (MAC_MAX_FRAME_SZ & DESC_RXCTRL_SIZE1MASK) | \
+ DESC_RXCTRL_RXCHAIN;
+
+ desc_p->txrx_status = DESC_RXSTS_OWNBYDMA;
+ }
+
+ /* Correcting the last pointer of the chain */
+ desc_p->dmamac_next = &desc_table_p[0];
+
+ writel((ulong)&desc_table_p[0], &dma_p->rxdesclistaddr);
+}
+
+static void descs_init(struct eth_device *dev)
+{
+ tx_descs_init(dev);
+ rx_descs_init(dev);
+}
+
+static int dwc_ether_init(struct eth_device *dev)
+{
+ struct dw_eth_dev *priv = dev->priv;
+ struct eth_mac_regs *mac_p = priv->mac_regs_p;
+ struct eth_dma_regs *dma_p = priv->dma_regs_p;
+
+ if (mac_reset(dev) < 0)
+ return -1;
+
+ /* HW MAC address is lost during MAC reset */
+ dev->set_ethaddr(dev, priv->macaddr);
+
+ writel(FIXEDBURST | PRIORXTX_41 | BURST_16, &dma_p->busmode);
+ writel(FLUSHTXFIFO | readl(&dma_p->opmode), &dma_p->opmode);
+ writel(STOREFORWARD | TXSECONDFRAME, &dma_p->opmode);
+ writel(FRAMEBURSTENABLE | DISABLERXOWN, &mac_p->conf);
+ return 0;
+}
+
+static int dwc_ether_open(struct eth_device *dev)
+{
+ struct dw_eth_dev *priv = dev->priv;
+ struct eth_mac_regs *mac_p = priv->mac_regs_p;
+ struct eth_dma_regs *dma_p = priv->dma_regs_p;
+ u32 conf;
+ int link, speed;
+
+ miidev_wait_aneg(&priv->miidev);
+ miidev_print_status(&priv->miidev);
+ link = miidev_get_status(&priv->miidev);
+
+ if (priv->fix_mac_speed) {
+ speed = link & MIIDEV_STATUS_IS_1000MBIT ? 1000 :
+ (link & MIIDEV_STATUS_IS_100MBIT ? 100 : 10);
+ priv->fix_mac_speed(speed);
+ }
+
+ conf = readl(&mac_p->conf);
+ if (link & MIIDEV_STATUS_IS_FULL_DUPLEX)
+ conf |= FULLDPLXMODE;
+ else
+ conf &= ~FULLDPLXMODE;
+ if (link & MIIDEV_STATUS_IS_1000MBIT)
+ conf &= ~MII_PORTSELECT;
+ else
+ conf |= MII_PORTSELECT;
+ writel(conf, &mac_p->conf);
+
+ descs_init(dev);
+
+ /*
+ * Start/Enable xfer at dma as well as mac level
+ */
+ writel(readl(&dma_p->opmode) | RXSTART, &dma_p->opmode);
+ writel(readl(&dma_p->opmode) | TXSTART, &dma_p->opmode);
+ writel(readl(&mac_p->conf) | RXENABLE | TXENABLE, &mac_p->conf);
+ return 0;
+}
+
+static int dwc_ether_send(struct eth_device *dev, void *packet, int length)
+{
+ struct dw_eth_dev *priv = dev->priv;
+ struct eth_dma_regs *dma_p = priv->dma_regs_p;
+ u32 desc_num = priv->tx_currdescnum;
+ struct dmamacdescr *desc_p = &priv->tx_mac_descrtable[desc_num];
+
+ /* Check if the descriptor is owned by CPU */
+ if (desc_p->txrx_status & DESC_TXSTS_OWNBYDMA) {
+ dev_err(&dev->dev, "CPU not owner of tx frame\n");
+ return -1;
+ }
+
+ memcpy((void *)desc_p->dmamac_addr, packet, length);
+
+#if defined(CONFIG_DW_ALTDESCRIPTOR)
+ desc_p->txrx_status |= DESC_TXSTS_TXFIRST | DESC_TXSTS_TXLAST;
+ desc_p->dmamac_cntl |= (length << DESC_TXCTRL_SIZE1SHFT) & \
+ DESC_TXCTRL_SIZE1MASK;
+
+ desc_p->txrx_status &= ~(DESC_TXSTS_MSK);
+ desc_p->txrx_status |= DESC_TXSTS_OWNBYDMA;
+#else
+ desc_p->dmamac_cntl |= ((length << DESC_TXCTRL_SIZE1SHFT) & \
+ DESC_TXCTRL_SIZE1MASK) | DESC_TXCTRL_TXLAST | \
+ DESC_TXCTRL_TXFIRST;
+
+ desc_p->txrx_status = DESC_TXSTS_OWNBYDMA;
+#endif
+
+ /* Test the wrap-around condition. */
+ if (++desc_num >= CONFIG_TX_DESCR_NUM)
+ desc_num = 0;
+
+ priv->tx_currdescnum = desc_num;
+
+ /* Start the transmission */
+ writel(POLL_DATA, &dma_p->txpolldemand);
+ return 0;
+}
+
+static int dwc_ether_rx(struct eth_device *dev)
+{
+ struct dw_eth_dev *priv = dev->priv;
+ u32 desc_num = priv->rx_currdescnum;
+ struct dmamacdescr *desc_p = &priv->rx_mac_descrtable[desc_num];
+
+ u32 status = desc_p->txrx_status;
+ int length = 0;
+
+ /* Check if the owner is the CPU */
+ if (status & DESC_RXSTS_OWNBYDMA)
+ return 0;
+
+ length = (status & DESC_RXSTS_FRMLENMSK) >> \
+ DESC_RXSTS_FRMLENSHFT;
+
+ net_receive(desc_p->dmamac_addr, length);
+
+ /*
+ * Make the current descriptor valid again and go to
+ * the next one
+ */
+ desc_p->txrx_status |= DESC_RXSTS_OWNBYDMA;
+
+ /* Test the wrap-around condition. */
+ if (++desc_num >= CONFIG_RX_DESCR_NUM)
+ desc_num = 0;
+
+ priv->rx_currdescnum = desc_num;
+
+ return length;
+}
+
+static void dwc_ether_halt (struct eth_device *dev)
+{
+ struct dw_eth_dev *priv = dev->priv;
+
+ mac_reset(dev);
+ priv->tx_currdescnum = priv->rx_currdescnum = 0;
+}
+
+static int dwc_ether_get_ethaddr(struct eth_device *dev, u8 adr[6])
+{
+ /* we have no EEPROM */
+ return -1;
+}
+
+static int dwc_ether_set_ethaddr(struct eth_device *dev, u8 adr[6])
+{
+ struct dw_eth_dev *priv = dev->priv;
+ struct eth_mac_regs *mac_p = priv->mac_regs_p;
+ u32 macid_lo, macid_hi;
+
+ macid_lo = adr[0] + (adr[1] << 8) + \
+ (adr[2] << 16) + (adr[3] << 24);
+ macid_hi = adr[4] + (adr[5] << 8);
+ writel(macid_hi, &mac_p->macaddr0hi);
+ writel(macid_lo, &mac_p->macaddr0lo);
+ memcpy(priv->macaddr, adr, 6);
+ return 0;
+}
+
+static int dwc_ether_probe(struct device_d *dev)
+{
+ struct dw_eth_dev *priv;
+ struct eth_device *edev;
+ struct mii_device *miidev;
+ void __iomem *base;
+ struct dwc_ether_platform_data *pdata = dev->platform_data;
+
+ if (!pdata) {
+ printf("dwc_ether: no platform_data\n");
+ return -ENODEV;
+ }
+
+ priv = xzalloc(sizeof(struct dw_eth_dev));
+
+ base = dev_request_mem_region(dev, 0);
+ priv->mac_regs_p = base;
+ dev_info(dev, "MAC version %08x\n", readl(&priv->mac_regs_p->version));
+ priv->dma_regs_p = base + DW_DMA_BASE_OFFSET;
+ priv->tx_mac_descrtable = dma_alloc_coherent(
+ CONFIG_TX_DESCR_NUM * sizeof(struct dmamacdescr));
+ priv->rx_mac_descrtable = dma_alloc_coherent(
+ CONFIG_RX_DESCR_NUM * sizeof(struct dmamacdescr));
+ priv->txbuffs = dma_alloc_coherent(TX_TOTAL_BUFSIZE);
+ priv->rxbuffs = dma_alloc_coherent(RX_TOTAL_BUFSIZE);
+ priv->fix_mac_speed = pdata->fix_mac_speed;
+
+ edev = &priv->netdev;
+ miidev = &priv->miidev;
+ edev->priv = priv;
+
+ edev->init = dwc_ether_init;
+ edev->open = dwc_ether_open;
+ edev->send = dwc_ether_send;
+ edev->recv = dwc_ether_rx;
+ edev->halt = dwc_ether_halt;
+ edev->get_ethaddr = dwc_ether_get_ethaddr;
+ edev->set_ethaddr = dwc_ether_set_ethaddr;
+
+ miidev->address = pdata->phy_addr;
+ miidev->read = dwc_ether_mii_read;
+ miidev->write = dwc_ether_mii_write;
+ miidev->edev = edev;
+
+ mii_register(miidev);
+ eth_register(edev);
+ return 0;
+}
+
+static void dwc_ether_remove(struct device_d *dev)
+{
+}
+
+static struct driver_d dwc_ether_driver = {
+ .name = "designware_eth",
+ .probe = dwc_ether_probe,
+ .remove = dwc_ether_remove,
+};
+
+static int dwc_ether_driver_init(void)
+{
+ register_driver(&dwc_ether_driver);
+ return 0;
+}
+device_initcall(dwc_ether_driver_init);
diff --git a/drivers/net/designware.h b/drivers/net/designware.h
new file mode 100644
index 0000000..d28c52a
--- /dev/null
+++ b/drivers/net/designware.h
@@ -0,0 +1,230 @@
+/*
+ * (C) Copyright 2010
+ * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef __DESIGNWARE_ETH_H
+#define __DESIGNWARE_ETH_H
+
+#define CONFIG_TX_DESCR_NUM 16
+#define CONFIG_RX_DESCR_NUM 16
+#define CONFIG_ETH_BUFSIZE 2048
+#define TX_TOTAL_BUFSIZE (CONFIG_ETH_BUFSIZE * CONFIG_TX_DESCR_NUM)
+#define RX_TOTAL_BUFSIZE (CONFIG_ETH_BUFSIZE * CONFIG_RX_DESCR_NUM)
+
+struct eth_mac_regs {
+ u32 conf; /* 0x00 */
+ u32 framefilt; /* 0x04 */
+ u32 hashtablehigh; /* 0x08 */
+ u32 hashtablelow; /* 0x0c */
+ u32 miiaddr; /* 0x10 */
+ u32 miidata; /* 0x14 */
+ u32 flowcontrol; /* 0x18 */
+ u32 vlantag; /* 0x1c */
+ u32 version; /* 0x20 */
+ u8 reserved_1[20];
+ u32 intreg; /* 0x38 */
+ u32 intmask; /* 0x3c */
+ u32 macaddr0hi; /* 0x40 */
+ u32 macaddr0lo; /* 0x44 */
+};
+
+/* MAC configuration register definitions */
+#define FRAMEBURSTENABLE (1 << 21)
+#define MII_PORTSELECT (1 << 15)
+#define FES_100 (1 << 14)
+#define DISABLERXOWN (1 << 13)
+#define FULLDPLXMODE (1 << 11)
+#define RXENABLE (1 << 2)
+#define TXENABLE (1 << 3)
+
+/* MII address register definitions */
+#define MII_BUSY (1 << 0)
+#define MII_WRITE (1 << 1)
+#define MII_CLKRANGE_60_100M (0)
+#define MII_CLKRANGE_100_150M (0x4)
+#define MII_CLKRANGE_20_35M (0x8)
+#define MII_CLKRANGE_35_60M (0xC)
+#define MII_CLKRANGE_150_250M (0x10)
+#define MII_CLKRANGE_250_300M (0x14)
+
+#define MIIADDRSHIFT (11)
+#define MIIREGSHIFT (6)
+#define MII_REGMSK (0x1F << 6)
+#define MII_ADDRMSK (0x1F << 11)
+
+
+struct eth_dma_regs {
+ u32 busmode; /* 0x00 */
+ u32 txpolldemand; /* 0x04 */
+ u32 rxpolldemand; /* 0x08 */
+ u32 rxdesclistaddr; /* 0x0c */
+ u32 txdesclistaddr; /* 0x10 */
+ u32 status; /* 0x14 */
+ u32 opmode; /* 0x18 */
+ u32 intenable; /* 0x1c */
+ u8 reserved[40];
+ u32 currhosttxdesc; /* 0x48 */
+ u32 currhostrxdesc; /* 0x4c */
+ u32 currhosttxbuffaddr; /* 0x50 */
+ u32 currhostrxbuffaddr; /* 0x54 */
+};
+
+#define DW_DMA_BASE_OFFSET (0x1000)
+
+/* Bus mode register definitions */
+#define FIXEDBURST (1 << 16)
+#define PRIORXTX_41 (3 << 14)
+#define PRIORXTX_31 (2 << 14)
+#define PRIORXTX_21 (1 << 14)
+#define PRIORXTX_11 (0 << 14)
+#define BURST_1 (1 << 8)
+#define BURST_2 (2 << 8)
+#define BURST_4 (4 << 8)
+#define BURST_8 (8 << 8)
+#define BURST_16 (16 << 8)
+#define BURST_32 (32 << 8)
+#define RXHIGHPRIO (1 << 1)
+#define DMAMAC_SRST (1 << 0)
+
+/* Poll demand definitions */
+#define POLL_DATA (0xFFFFFFFF)
+
+/* Operation mode definitions */
+#define STOREFORWARD (1 << 21)
+#define FLUSHTXFIFO (1 << 20)
+#define TXSTART (1 << 13)
+#define TXSECONDFRAME (1 << 2)
+#define RXSTART (1 << 1)
+
+/* Descriptior related definitions */
+#define MAC_MAX_FRAME_SZ (1600)
+
+struct dmamacdescr {
+ u32 txrx_status;
+ u32 dmamac_cntl;
+ void *dmamac_addr;
+ struct dmamacdescr *dmamac_next;
+};
+
+/*
+ * txrx_status definitions
+ */
+
+/* tx status bits definitions */
+#if defined(CONFIG_DW_ALTDESCRIPTOR)
+
+#define DESC_TXSTS_OWNBYDMA (1 << 31)
+#define DESC_TXSTS_TXINT (1 << 30)
+#define DESC_TXSTS_TXLAST (1 << 29)
+#define DESC_TXSTS_TXFIRST (1 << 28)
+#define DESC_TXSTS_TXCRCDIS (1 << 27)
+
+#define DESC_TXSTS_TXPADDIS (1 << 26)
+#define DESC_TXSTS_TXCHECKINSCTRL (3 << 22)
+#define DESC_TXSTS_TXRINGEND (1 << 21)
+#define DESC_TXSTS_TXCHAIN (1 << 20)
+#define DESC_TXSTS_MSK (0x1FFFF << 0)
+
+#else
+
+#define DESC_TXSTS_OWNBYDMA (1 << 31)
+#define DESC_TXSTS_MSK (0x1FFFF << 0)
+
+#endif
+
+/* rx status bits definitions */
+#define DESC_RXSTS_OWNBYDMA (1 << 31)
+#define DESC_RXSTS_DAFILTERFAIL (1 << 30)
+#define DESC_RXSTS_FRMLENMSK (0x3FFF << 16)
+#define DESC_RXSTS_FRMLENSHFT (16)
+
+#define DESC_RXSTS_ERROR (1 << 15)
+#define DESC_RXSTS_RXTRUNCATED (1 << 14)
+#define DESC_RXSTS_SAFILTERFAIL (1 << 13)
+#define DESC_RXSTS_RXIPC_GIANTFRAME (1 << 12)
+#define DESC_RXSTS_RXDAMAGED (1 << 11)
+#define DESC_RXSTS_RXVLANTAG (1 << 10)
+#define DESC_RXSTS_RXFIRST (1 << 9)
+#define DESC_RXSTS_RXLAST (1 << 8)
+#define DESC_RXSTS_RXIPC_GIANT (1 << 7)
+#define DESC_RXSTS_RXCOLLISION (1 << 6)
+#define DESC_RXSTS_RXFRAMEETHER (1 << 5)
+#define DESC_RXSTS_RXWATCHDOG (1 << 4)
+#define DESC_RXSTS_RXMIIERROR (1 << 3)
+#define DESC_RXSTS_RXDRIBBLING (1 << 2)
+#define DESC_RXSTS_RXCRC (1 << 1)
+
+/*
+ * dmamac_cntl definitions
+ */
+
+/* tx control bits definitions */
+#if defined(CONFIG_DW_ALTDESCRIPTOR)
+
+#define DESC_TXCTRL_SIZE1MASK (0x1FFF << 0)
+#define DESC_TXCTRL_SIZE1SHFT (0)
+#define DESC_TXCTRL_SIZE2MASK (0x1FFF << 16)
+#define DESC_TXCTRL_SIZE2SHFT (16)
+
+#else
+
+#define DESC_TXCTRL_TXINT (1 << 31)
+#define DESC_TXCTRL_TXLAST (1 << 30)
+#define DESC_TXCTRL_TXFIRST (1 << 29)
+#define DESC_TXCTRL_TXCHECKINSCTRL (3 << 27)
+#define DESC_TXCTRL_TXCRCDIS (1 << 26)
+#define DESC_TXCTRL_TXRINGEND (1 << 25)
+#define DESC_TXCTRL_TXCHAIN (1 << 24)
+
+#define DESC_TXCTRL_SIZE1MASK (0x7FF << 0)
+#define DESC_TXCTRL_SIZE1SHFT (0)
+#define DESC_TXCTRL_SIZE2MASK (0x7FF << 11)
+#define DESC_TXCTRL_SIZE2SHFT (11)
+
+#endif
+
+/* rx control bits definitions */
+#if defined(CONFIG_DW_ALTDESCRIPTOR)
+
+#define DESC_RXCTRL_RXINTDIS (1 << 31)
+#define DESC_RXCTRL_RXRINGEND (1 << 15)
+#define DESC_RXCTRL_RXCHAIN (1 << 14)
+
+#define DESC_RXCTRL_SIZE1MASK (0x1FFF << 0)
+#define DESC_RXCTRL_SIZE1SHFT (0)
+#define DESC_RXCTRL_SIZE2MASK (0x1FFF << 16)
+#define DESC_RXCTRL_SIZE2SHFT (16)
+
+#else
+
+#define DESC_RXCTRL_RXINTDIS (1 << 31)
+#define DESC_RXCTRL_RXRINGEND (1 << 25)
+#define DESC_RXCTRL_RXCHAIN (1 << 24)
+
+#define DESC_RXCTRL_SIZE1MASK (0x7FF << 0)
+#define DESC_RXCTRL_SIZE1SHFT (0)
+#define DESC_RXCTRL_SIZE2MASK (0x7FF << 11)
+#define DESC_RXCTRL_SIZE2SHFT (11)
+
+#endif
+
+#endif
diff --git a/include/net/designware.h b/include/net/designware.h
new file mode 100644
index 0000000..3f9f5b9
--- /dev/null
+++ b/include/net/designware.h
@@ -0,0 +1,9 @@
+#ifndef __DWC_UNIMAC_H
+#define __DWC_UNIMAC_H
+
+struct dwc_ether_platform_data {
+ u8 phy_addr;
+ void (*fix_mac_speed)(int speed);
+};
+
+#endif
--
1.7.10.4
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 6/6] drivers/net: add designware driver
2012-06-18 14:48 ` [PATCH 6/6] drivers/net: add designware driver Johannes Stezenbach
@ 2012-06-20 7:13 ` Sascha Hauer
2012-06-20 8:11 ` Johannes Stezenbach
0 siblings, 1 reply; 16+ messages in thread
From: Sascha Hauer @ 2012-06-20 7:13 UTC (permalink / raw)
To: Johannes Stezenbach; +Cc: barebox
Hi Johannes,
On Mon, Jun 18, 2012 at 04:48:00PM +0200, Johannes Stezenbach wrote:
> Straight forward port of Synopsys Designware ethernet
> driver from u-boot v2012.04.01.
>
> Signed-off-by: Johannes Stezenbach <js@sig21.net>
> ---
> drivers/net/Kconfig | 11 ++
> drivers/net/Makefile | 1 +
> drivers/net/designware.c | 433 ++++++++++++++++++++++++++++++++++++++++++++++
> drivers/net/designware.h | 230 ++++++++++++++++++++++++
> include/net/designware.h | 9 +
> 5 files changed, 684 insertions(+)
> create mode 100644 drivers/net/designware.c
> create mode 100644 drivers/net/designware.h
> create mode 100644 include/net/designware.h
>
> diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
> index 172cc39..ba59715 100644
> --- a/drivers/net/Kconfig
> +++ b/drivers/net/Kconfig
> @@ -13,6 +13,9 @@ config HAS_AT91_ETHER
> config HAS_NETX_ETHER
> bool
>
> +config HAS_DESIGNWARE_ETH
> + bool
> +
> config ARCH_HAS_FEC_IMX
> bool
>
> @@ -108,6 +111,14 @@ config DRIVER_NET_KS8851_MLL
> This option enables support for the Micrel KS8851 MLL
> ethernet chip.
>
> +config DRIVER_NET_DESIGNWARE
> + bool "Designware Universal MAC ethernet driver"
> + select MIIDEV
> + depends on HAS_DESIGNWARE_ETH
> + help
> + This option enables support for the Synopsys
> + Designware Core Univesal MAC 10M/100M/1G ethernet IP.
This driver uses DMA, but it has no cache flush/invalidation. At least
on ARM this means that it won't work with MMU enabled, so we should
either add the following to Kconfig:
depends on !ARM || !MMU
Or add the dma_* functions. I added hints where to add these functions
inline, but I can't test this.
> +
> source "drivers/net/usb/Kconfig"
>
> endmenu
> diff --git a/drivers/net/Makefile b/drivers/net/Makefile
> index 34dbee9..29727b7 100644
> --- a/drivers/net/Makefile
> +++ b/drivers/net/Makefile
> @@ -13,3 +13,4 @@ obj-$(CONFIG_MIIDEV) += miidev.o
> obj-$(CONFIG_NET_USB) += usb/
> obj-$(CONFIG_DRIVER_NET_TSE) += altera_tse.o
> obj-$(CONFIG_DRIVER_NET_KS8851_MLL) += ks8851_mll.o
> +obj-$(CONFIG_DRIVER_NET_DESIGNWARE) += designware.o
> diff --git a/drivers/net/designware.c b/drivers/net/designware.c
> new file mode 100644
> index 0000000..d9a87b0
> --- /dev/null
> +++ b/drivers/net/designware.c
> @@ -0,0 +1,433 @@
> +/*
> + * (C) Copyright 2010
> + * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com.
> + *
> + * See file CREDITS for list of people who contributed to this
> + * project.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
> + * MA 02111-1307 USA
> + */
> +
> +/*
> + * Designware ethernet IP driver for u-boot
> + */
> +
> +#include <common.h>
> +#include <init.h>
> +#include <io.h>
> +#include <net.h>
> +#include <miidev.h>
> +#include <asm/mmu.h>
> +#include <net/designware.h>
> +#include "designware.h"
> +
> +
> +struct dw_eth_dev {
> + struct eth_device netdev;
> + struct mii_device miidev;
> +
> + void (*fix_mac_speed)(int speed);
> + u8 macaddr[6];
> + u32 tx_currdescnum;
> + u32 rx_currdescnum;
> +
> + struct dmamacdescr *tx_mac_descrtable;
> + struct dmamacdescr *rx_mac_descrtable;
> +
> + u8 *txbuffs;
> + u8 *rxbuffs;
> +
> + struct eth_mac_regs *mac_regs_p;
> + struct eth_dma_regs *dma_regs_p;
> +};
+
> +/* Speed specific definitions */
> +#define SPEED_10M 1
> +#define SPEED_100M 2
> +#define SPEED_1000M 3
> +
> +/* Duplex mode specific definitions */
> +#define HALF_DUPLEX 1
> +#define FULL_DUPLEX 2
> +
> +
> +static int dwc_ether_mii_read(struct mii_device *dev, int addr, int reg)
> +{
> + struct dw_eth_dev *priv = dev->edev->priv;
> + struct eth_mac_regs *mac_p = priv->mac_regs_p;
> + u64 start;
> + u32 miiaddr;
> +
> + miiaddr = ((addr << MIIADDRSHIFT) & MII_ADDRMSK) | \
> + ((reg << MIIREGSHIFT) & MII_REGMSK);
> +
> + writel(miiaddr | MII_CLKRANGE_150_250M | MII_BUSY, &mac_p->miiaddr);
> +
> + start = get_time_ns();
> + while (readl(&mac_p->miiaddr) & MII_BUSY) {
> + if (is_timeout(start, 10 * MSECOND)) {
> + dev_err(&priv->netdev.dev, "MDIO timeout\n");
> + return -EIO;
> + }
> + udelay(10);
We do not need udelay in timeout loops as we are polling anyway.
> + }
> + return readl(&mac_p->miidata) & 0xffff;
> +}
> +
> +static void tx_descs_init(struct eth_device *dev)
> +{
> + struct dw_eth_dev *priv = dev->priv;
> + struct eth_dma_regs *dma_p = priv->dma_regs_p;
> + struct dmamacdescr *desc_table_p = &priv->tx_mac_descrtable[0];
> + char *txbuffs = &priv->txbuffs[0];
> + struct dmamacdescr *desc_p;
> + u32 idx;
> +
> + for (idx = 0; idx < CONFIG_TX_DESCR_NUM; idx++) {
> + desc_p = &desc_table_p[idx];
> + desc_p->dmamac_addr = &txbuffs[idx * CONFIG_ETH_BUFSIZE];
> + desc_p->dmamac_next = &desc_table_p[idx + 1];
> +
> +#if defined(CONFIG_DW_ALTDESCRIPTOR)
Do we need this? If yes, we should add an (invisible, board selectable)
option to Kconfig.
In U-Boot this is described with:
1. CONFIG_DW_ALTDESCRIPTOR
Define this to use the Alternate/Enhanced Descriptor configurations.
Does this mean this is an alternative way to use this hardware or does
this mean it's another version (or IP core configuration) of this hardware?
> + desc_p->txrx_status &= ~(DESC_TXSTS_TXINT | DESC_TXSTS_TXLAST |
> + DESC_TXSTS_TXFIRST | DESC_TXSTS_TXCRCDIS | \
> + DESC_TXSTS_TXCHECKINSCTRL | \
> + DESC_TXSTS_TXRINGEND | DESC_TXSTS_TXPADDIS);
> +
> + desc_p->txrx_status |= DESC_TXSTS_TXCHAIN;
> + desc_p->dmamac_cntl = 0;
> + desc_p->txrx_status &= ~(DESC_TXSTS_MSK | DESC_TXSTS_OWNBYDMA);
> +#else
> + desc_p->dmamac_cntl = DESC_TXCTRL_TXCHAIN;
> + desc_p->txrx_status = 0;
> +#endif
> + }
> +
> + /* Correcting the last pointer of the chain */
> + desc_p->dmamac_next = &desc_table_p[0];
> +
> + writel((ulong)&desc_table_p[0], &dma_p->txdesclistaddr);
> +}
> +
> +static void rx_descs_init(struct eth_device *dev)
> +{
> + struct dw_eth_dev *priv = dev->priv;
> + struct eth_dma_regs *dma_p = priv->dma_regs_p;
> + struct dmamacdescr *desc_table_p = &priv->rx_mac_descrtable[0];
> + char *rxbuffs = &priv->rxbuffs[0];
> + struct dmamacdescr *desc_p;
> + u32 idx;
> +
> + for (idx = 0; idx < CONFIG_RX_DESCR_NUM; idx++) {
> + desc_p = &desc_table_p[idx];
> + desc_p->dmamac_addr = &rxbuffs[idx * CONFIG_ETH_BUFSIZE];
> + desc_p->dmamac_next = &desc_table_p[idx + 1];
> +
> + desc_p->dmamac_cntl =
> + (MAC_MAX_FRAME_SZ & DESC_RXCTRL_SIZE1MASK) | \
> + DESC_RXCTRL_RXCHAIN;
> +
> + desc_p->txrx_status = DESC_RXSTS_OWNBYDMA;
> + }
> +
> + /* Correcting the last pointer of the chain */
> + desc_p->dmamac_next = &desc_table_p[0];
> +
> + writel((ulong)&desc_table_p[0], &dma_p->rxdesclistaddr);
> +}
> +
> +static void descs_init(struct eth_device *dev)
> +{
> + tx_descs_init(dev);
> + rx_descs_init(dev);
> +}
> +
> +static int dwc_ether_init(struct eth_device *dev)
> +{
> + struct dw_eth_dev *priv = dev->priv;
> + struct eth_mac_regs *mac_p = priv->mac_regs_p;
> + struct eth_dma_regs *dma_p = priv->dma_regs_p;
> +
> + if (mac_reset(dev) < 0)
> + return -1;
> +
> + /* HW MAC address is lost during MAC reset */
> + dev->set_ethaddr(dev, priv->macaddr);
> +
> + writel(FIXEDBURST | PRIORXTX_41 | BURST_16, &dma_p->busmode);
> + writel(FLUSHTXFIFO | readl(&dma_p->opmode), &dma_p->opmode);
> + writel(STOREFORWARD | TXSECONDFRAME, &dma_p->opmode);
> + writel(FRAMEBURSTENABLE | DISABLERXOWN, &mac_p->conf);
> + return 0;
> +}
> +
> +static int dwc_ether_open(struct eth_device *dev)
> +{
> + struct dw_eth_dev *priv = dev->priv;
> + struct eth_mac_regs *mac_p = priv->mac_regs_p;
> + struct eth_dma_regs *dma_p = priv->dma_regs_p;
> + u32 conf;
> + int link, speed;
> +
> + miidev_wait_aneg(&priv->miidev);
> + miidev_print_status(&priv->miidev);
> + link = miidev_get_status(&priv->miidev);
> +
> + if (priv->fix_mac_speed) {
> + speed = link & MIIDEV_STATUS_IS_1000MBIT ? 1000 :
> + (link & MIIDEV_STATUS_IS_100MBIT ? 100 : 10);
> + priv->fix_mac_speed(speed);
> + }
> +
> + conf = readl(&mac_p->conf);
> + if (link & MIIDEV_STATUS_IS_FULL_DUPLEX)
> + conf |= FULLDPLXMODE;
> + else
> + conf &= ~FULLDPLXMODE;
> + if (link & MIIDEV_STATUS_IS_1000MBIT)
> + conf &= ~MII_PORTSELECT;
> + else
> + conf |= MII_PORTSELECT;
> + writel(conf, &mac_p->conf);
> +
> + descs_init(dev);
> +
> + /*
> + * Start/Enable xfer at dma as well as mac level
> + */
> + writel(readl(&dma_p->opmode) | RXSTART, &dma_p->opmode);
> + writel(readl(&dma_p->opmode) | TXSTART, &dma_p->opmode);
> + writel(readl(&mac_p->conf) | RXENABLE | TXENABLE, &mac_p->conf);
> + return 0;
> +}
> +
> +static int dwc_ether_send(struct eth_device *dev, void *packet, int length)
> +{
> + struct dw_eth_dev *priv = dev->priv;
> + struct eth_dma_regs *dma_p = priv->dma_regs_p;
> + u32 desc_num = priv->tx_currdescnum;
> + struct dmamacdescr *desc_p = &priv->tx_mac_descrtable[desc_num];
> +
> + /* Check if the descriptor is owned by CPU */
> + if (desc_p->txrx_status & DESC_TXSTS_OWNBYDMA) {
> + dev_err(&dev->dev, "CPU not owner of tx frame\n");
> + return -1;
> + }
> +
> + memcpy((void *)desc_p->dmamac_addr, packet, length);
For this to work with cache enabled you should add the following here:
dma_flush_range(desc_p->dmamac_addr, desc_p->dmamac_addr + length);
> +
> +#if defined(CONFIG_DW_ALTDESCRIPTOR)
> + desc_p->txrx_status |= DESC_TXSTS_TXFIRST | DESC_TXSTS_TXLAST;
> + desc_p->dmamac_cntl |= (length << DESC_TXCTRL_SIZE1SHFT) & \
> + DESC_TXCTRL_SIZE1MASK;
> +
> + desc_p->txrx_status &= ~(DESC_TXSTS_MSK);
> + desc_p->txrx_status |= DESC_TXSTS_OWNBYDMA;
> +#else
> + desc_p->dmamac_cntl |= ((length << DESC_TXCTRL_SIZE1SHFT) & \
> + DESC_TXCTRL_SIZE1MASK) | DESC_TXCTRL_TXLAST | \
> + DESC_TXCTRL_TXFIRST;
> +
> + desc_p->txrx_status = DESC_TXSTS_OWNBYDMA;
> +#endif
> +
> + /* Test the wrap-around condition. */
> + if (++desc_num >= CONFIG_TX_DESCR_NUM)
> + desc_num = 0;
> +
> + priv->tx_currdescnum = desc_num;
> +
> + /* Start the transmission */
> + writel(POLL_DATA, &dma_p->txpolldemand);
> + return 0;
> +}
> +
> +static int dwc_ether_rx(struct eth_device *dev)
> +{
> + struct dw_eth_dev *priv = dev->priv;
> + u32 desc_num = priv->rx_currdescnum;
> + struct dmamacdescr *desc_p = &priv->rx_mac_descrtable[desc_num];
> +
> + u32 status = desc_p->txrx_status;
> + int length = 0;
> +
> + /* Check if the owner is the CPU */
> + if (status & DESC_RXSTS_OWNBYDMA)
> + return 0;
> +
> + length = (status & DESC_RXSTS_FRMLENMSK) >> \
> + DESC_RXSTS_FRMLENSHFT;
For this to work with cache enabled you should add the following here:
dma_inv_range(desc_p->dmamac_addr, desc_p->dmamac_addr + length);
> +
> + net_receive(desc_p->dmamac_addr, length);
> +
> + /*
> + * Make the current descriptor valid again and go to
> + * the next one
> + */
> + desc_p->txrx_status |= DESC_RXSTS_OWNBYDMA;
> +
> + /* Test the wrap-around condition. */
> + if (++desc_num >= CONFIG_RX_DESCR_NUM)
> + desc_num = 0;
> +
> + priv->rx_currdescnum = desc_num;
> +
> + return length;
> +}
> +
> +static void dwc_ether_halt (struct eth_device *dev)
> +{
> + struct dw_eth_dev *priv = dev->priv;
> +
> + mac_reset(dev);
> + priv->tx_currdescnum = priv->rx_currdescnum = 0;
> +}
> +
> +static int dwc_ether_get_ethaddr(struct eth_device *dev, u8 adr[6])
> +{
> + /* we have no EEPROM */
> + return -1;
> +}
> +
> +static int dwc_ether_set_ethaddr(struct eth_device *dev, u8 adr[6])
> +{
> + struct dw_eth_dev *priv = dev->priv;
> + struct eth_mac_regs *mac_p = priv->mac_regs_p;
> + u32 macid_lo, macid_hi;
> +
> + macid_lo = adr[0] + (adr[1] << 8) + \
> + (adr[2] << 16) + (adr[3] << 24);
> + macid_hi = adr[4] + (adr[5] << 8);
> + writel(macid_hi, &mac_p->macaddr0hi);
> + writel(macid_lo, &mac_p->macaddr0lo);
> + memcpy(priv->macaddr, adr, 6);
> + return 0;
> +}
> +
> +static int dwc_ether_probe(struct device_d *dev)
> +{
> + struct dw_eth_dev *priv;
> + struct eth_device *edev;
> + struct mii_device *miidev;
> + void __iomem *base;
> + struct dwc_ether_platform_data *pdata = dev->platform_data;
> +
> + if (!pdata) {
> + printf("dwc_ether: no platform_data\n");
> + return -ENODEV;
> + }
> +
> + priv = xzalloc(sizeof(struct dw_eth_dev));
> +
> + base = dev_request_mem_region(dev, 0);
> + priv->mac_regs_p = base;
> + dev_info(dev, "MAC version %08x\n", readl(&priv->mac_regs_p->version));
> + priv->dma_regs_p = base + DW_DMA_BASE_OFFSET;
> + priv->tx_mac_descrtable = dma_alloc_coherent(
> + CONFIG_TX_DESCR_NUM * sizeof(struct dmamacdescr));
> + priv->rx_mac_descrtable = dma_alloc_coherent(
> + CONFIG_RX_DESCR_NUM * sizeof(struct dmamacdescr));
> + priv->txbuffs = dma_alloc_coherent(TX_TOTAL_BUFSIZE);
> + priv->rxbuffs = dma_alloc_coherent(RX_TOTAL_BUFSIZE);
> + priv->fix_mac_speed = pdata->fix_mac_speed;
> +
> + edev = &priv->netdev;
> + miidev = &priv->miidev;
> + edev->priv = priv;
> +
> + edev->init = dwc_ether_init;
> + edev->open = dwc_ether_open;
> + edev->send = dwc_ether_send;
> + edev->recv = dwc_ether_rx;
> + edev->halt = dwc_ether_halt;
> + edev->get_ethaddr = dwc_ether_get_ethaddr;
> + edev->set_ethaddr = dwc_ether_set_ethaddr;
> +
> + miidev->address = pdata->phy_addr;
> + miidev->read = dwc_ether_mii_read;
> + miidev->write = dwc_ether_mii_write;
> + miidev->edev = edev;
> +
> + mii_register(miidev);
> + eth_register(edev);
> + return 0;
> +}
> +
> +static void dwc_ether_remove(struct device_d *dev)
> +{
> +}
> +
> +static struct driver_d dwc_ether_driver = {
> + .name = "designware_eth",
> + .probe = dwc_ether_probe,
> + .remove = dwc_ether_remove,
> +};
> +
> +static int dwc_ether_driver_init(void)
> +{
> + register_driver(&dwc_ether_driver);
> + return 0;
> +}
> +device_initcall(dwc_ether_driver_init);
> diff --git a/drivers/net/designware.h b/drivers/net/designware.h
> new file mode 100644
> index 0000000..d28c52a
> --- /dev/null
> +++ b/drivers/net/designware.h
> @@ -0,0 +1,230 @@
> +/*
> + * (C) Copyright 2010
> + * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com.
> + *
> + * See file CREDITS for list of people who contributed to this
> + * project.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
> + * MA 02111-1307 USA
> + */
> +
> +#ifndef __DESIGNWARE_ETH_H
> +#define __DESIGNWARE_ETH_H
> +
> +#define CONFIG_TX_DESCR_NUM 16
> +#define CONFIG_RX_DESCR_NUM 16
> +#define CONFIG_ETH_BUFSIZE 2048
> +#define TX_TOTAL_BUFSIZE (CONFIG_ETH_BUFSIZE * CONFIG_TX_DESCR_NUM)
> +#define RX_TOTAL_BUFSIZE (CONFIG_ETH_BUFSIZE * CONFIG_RX_DESCR_NUM)
> +
> +struct eth_mac_regs {
> + u32 conf; /* 0x00 */
> + u32 framefilt; /* 0x04 */
> + u32 hashtablehigh; /* 0x08 */
> + u32 hashtablelow; /* 0x0c */
> + u32 miiaddr; /* 0x10 */
> + u32 miidata; /* 0x14 */
> + u32 flowcontrol; /* 0x18 */
> + u32 vlantag; /* 0x1c */
> + u32 version; /* 0x20 */
> + u8 reserved_1[20];
> + u32 intreg; /* 0x38 */
> + u32 intmask; /* 0x3c */
> + u32 macaddr0hi; /* 0x40 */
> + u32 macaddr0lo; /* 0x44 */
> +};
> +
> +/* MAC configuration register definitions */
> +#define FRAMEBURSTENABLE (1 << 21)
> +#define MII_PORTSELECT (1 << 15)
> +#define FES_100 (1 << 14)
> +#define DISABLERXOWN (1 << 13)
> +#define FULLDPLXMODE (1 << 11)
> +#define RXENABLE (1 << 2)
> +#define TXENABLE (1 << 3)
> +
> +/* MII address register definitions */
> +#define MII_BUSY (1 << 0)
> +#define MII_WRITE (1 << 1)
> +#define MII_CLKRANGE_60_100M (0)
> +#define MII_CLKRANGE_100_150M (0x4)
> +#define MII_CLKRANGE_20_35M (0x8)
> +#define MII_CLKRANGE_35_60M (0xC)
> +#define MII_CLKRANGE_150_250M (0x10)
> +#define MII_CLKRANGE_250_300M (0x14)
> +
> +#define MIIADDRSHIFT (11)
> +#define MIIREGSHIFT (6)
> +#define MII_REGMSK (0x1F << 6)
> +#define MII_ADDRMSK (0x1F << 11)
> +
> +
> +struct eth_dma_regs {
> + u32 busmode; /* 0x00 */
> + u32 txpolldemand; /* 0x04 */
> + u32 rxpolldemand; /* 0x08 */
> + u32 rxdesclistaddr; /* 0x0c */
> + u32 txdesclistaddr; /* 0x10 */
> + u32 status; /* 0x14 */
> + u32 opmode; /* 0x18 */
> + u32 intenable; /* 0x1c */
> + u8 reserved[40];
> + u32 currhosttxdesc; /* 0x48 */
> + u32 currhostrxdesc; /* 0x4c */
> + u32 currhosttxbuffaddr; /* 0x50 */
> + u32 currhostrxbuffaddr; /* 0x54 */
> +};
> +
> +#define DW_DMA_BASE_OFFSET (0x1000)
> +
> +/* Bus mode register definitions */
> +#define FIXEDBURST (1 << 16)
> +#define PRIORXTX_41 (3 << 14)
> +#define PRIORXTX_31 (2 << 14)
> +#define PRIORXTX_21 (1 << 14)
> +#define PRIORXTX_11 (0 << 14)
> +#define BURST_1 (1 << 8)
> +#define BURST_2 (2 << 8)
> +#define BURST_4 (4 << 8)
> +#define BURST_8 (8 << 8)
> +#define BURST_16 (16 << 8)
> +#define BURST_32 (32 << 8)
> +#define RXHIGHPRIO (1 << 1)
> +#define DMAMAC_SRST (1 << 0)
> +
> +/* Poll demand definitions */
> +#define POLL_DATA (0xFFFFFFFF)
> +
> +/* Operation mode definitions */
> +#define STOREFORWARD (1 << 21)
> +#define FLUSHTXFIFO (1 << 20)
> +#define TXSTART (1 << 13)
> +#define TXSECONDFRAME (1 << 2)
> +#define RXSTART (1 << 1)
> +
> +/* Descriptior related definitions */
> +#define MAC_MAX_FRAME_SZ (1600)
> +
> +struct dmamacdescr {
> + u32 txrx_status;
> + u32 dmamac_cntl;
> + void *dmamac_addr;
> + struct dmamacdescr *dmamac_next;
> +};
> +
> +/*
> + * txrx_status definitions
> + */
> +
> +/* tx status bits definitions */
> +#if defined(CONFIG_DW_ALTDESCRIPTOR)
> +
> +#define DESC_TXSTS_OWNBYDMA (1 << 31)
> +#define DESC_TXSTS_TXINT (1 << 30)
> +#define DESC_TXSTS_TXLAST (1 << 29)
> +#define DESC_TXSTS_TXFIRST (1 << 28)
> +#define DESC_TXSTS_TXCRCDIS (1 << 27)
> +
> +#define DESC_TXSTS_TXPADDIS (1 << 26)
> +#define DESC_TXSTS_TXCHECKINSCTRL (3 << 22)
> +#define DESC_TXSTS_TXRINGEND (1 << 21)
> +#define DESC_TXSTS_TXCHAIN (1 << 20)
> +#define DESC_TXSTS_MSK (0x1FFFF << 0)
> +
> +#else
> +
> +#define DESC_TXSTS_OWNBYDMA (1 << 31)
> +#define DESC_TXSTS_MSK (0x1FFFF << 0)
> +
> +#endif
> +
> +/* rx status bits definitions */
> +#define DESC_RXSTS_OWNBYDMA (1 << 31)
> +#define DESC_RXSTS_DAFILTERFAIL (1 << 30)
> +#define DESC_RXSTS_FRMLENMSK (0x3FFF << 16)
> +#define DESC_RXSTS_FRMLENSHFT (16)
> +
> +#define DESC_RXSTS_ERROR (1 << 15)
> +#define DESC_RXSTS_RXTRUNCATED (1 << 14)
> +#define DESC_RXSTS_SAFILTERFAIL (1 << 13)
> +#define DESC_RXSTS_RXIPC_GIANTFRAME (1 << 12)
> +#define DESC_RXSTS_RXDAMAGED (1 << 11)
> +#define DESC_RXSTS_RXVLANTAG (1 << 10)
> +#define DESC_RXSTS_RXFIRST (1 << 9)
> +#define DESC_RXSTS_RXLAST (1 << 8)
> +#define DESC_RXSTS_RXIPC_GIANT (1 << 7)
> +#define DESC_RXSTS_RXCOLLISION (1 << 6)
> +#define DESC_RXSTS_RXFRAMEETHER (1 << 5)
> +#define DESC_RXSTS_RXWATCHDOG (1 << 4)
> +#define DESC_RXSTS_RXMIIERROR (1 << 3)
> +#define DESC_RXSTS_RXDRIBBLING (1 << 2)
> +#define DESC_RXSTS_RXCRC (1 << 1)
> +
> +/*
> + * dmamac_cntl definitions
> + */
> +
> +/* tx control bits definitions */
> +#if defined(CONFIG_DW_ALTDESCRIPTOR)
> +
> +#define DESC_TXCTRL_SIZE1MASK (0x1FFF << 0)
> +#define DESC_TXCTRL_SIZE1SHFT (0)
> +#define DESC_TXCTRL_SIZE2MASK (0x1FFF << 16)
> +#define DESC_TXCTRL_SIZE2SHFT (16)
> +
> +#else
> +
> +#define DESC_TXCTRL_TXINT (1 << 31)
> +#define DESC_TXCTRL_TXLAST (1 << 30)
> +#define DESC_TXCTRL_TXFIRST (1 << 29)
> +#define DESC_TXCTRL_TXCHECKINSCTRL (3 << 27)
> +#define DESC_TXCTRL_TXCRCDIS (1 << 26)
> +#define DESC_TXCTRL_TXRINGEND (1 << 25)
> +#define DESC_TXCTRL_TXCHAIN (1 << 24)
> +
> +#define DESC_TXCTRL_SIZE1MASK (0x7FF << 0)
> +#define DESC_TXCTRL_SIZE1SHFT (0)
> +#define DESC_TXCTRL_SIZE2MASK (0x7FF << 11)
> +#define DESC_TXCTRL_SIZE2SHFT (11)
> +
> +#endif
> +
> +/* rx control bits definitions */
> +#if defined(CONFIG_DW_ALTDESCRIPTOR)
> +
> +#define DESC_RXCTRL_RXINTDIS (1 << 31)
> +#define DESC_RXCTRL_RXRINGEND (1 << 15)
> +#define DESC_RXCTRL_RXCHAIN (1 << 14)
> +
> +#define DESC_RXCTRL_SIZE1MASK (0x1FFF << 0)
> +#define DESC_RXCTRL_SIZE1SHFT (0)
> +#define DESC_RXCTRL_SIZE2MASK (0x1FFF << 16)
> +#define DESC_RXCTRL_SIZE2SHFT (16)
> +
> +#else
> +
> +#define DESC_RXCTRL_RXINTDIS (1 << 31)
> +#define DESC_RXCTRL_RXRINGEND (1 << 25)
> +#define DESC_RXCTRL_RXCHAIN (1 << 24)
> +
> +#define DESC_RXCTRL_SIZE1MASK (0x7FF << 0)
> +#define DESC_RXCTRL_SIZE1SHFT (0)
> +#define DESC_RXCTRL_SIZE2MASK (0x7FF << 11)
> +#define DESC_RXCTRL_SIZE2SHFT (11)
> +
> +#endif
> +
> +#endif
> diff --git a/include/net/designware.h b/include/net/designware.h
> new file mode 100644
> index 0000000..3f9f5b9
> --- /dev/null
> +++ b/include/net/designware.h
> @@ -0,0 +1,9 @@
> +#ifndef __DWC_UNIMAC_H
> +#define __DWC_UNIMAC_H
> +
> +struct dwc_ether_platform_data {
> + u8 phy_addr;
> + void (*fix_mac_speed)(int speed);
> +};
> +
> +#endif
> --
> 1.7.10.4
>
>
> _______________________________________________
> barebox mailing list
> barebox@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox
>
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 6/6] drivers/net: add designware driver
2012-06-20 7:13 ` Sascha Hauer
@ 2012-06-20 8:11 ` Johannes Stezenbach
2012-06-20 8:41 ` Sascha Hauer
0 siblings, 1 reply; 16+ messages in thread
From: Johannes Stezenbach @ 2012-06-20 8:11 UTC (permalink / raw)
To: Sascha Hauer; +Cc: barebox
Hi Sascha,
On Wed, Jun 20, 2012 at 09:13:01AM +0200, Sascha Hauer wrote:
> On Mon, Jun 18, 2012 at 04:48:00PM +0200, Johannes Stezenbach wrote:
> > Straight forward port of Synopsys Designware ethernet
> > driver from u-boot v2012.04.01.
...
> > +config DRIVER_NET_DESIGNWARE
> > + bool "Designware Universal MAC ethernet driver"
> > + select MIIDEV
> > + depends on HAS_DESIGNWARE_ETH
> > + help
> > + This option enables support for the Synopsys
> > + Designware Core Univesal MAC 10M/100M/1G ethernet IP.
>
> This driver uses DMA, but it has no cache flush/invalidation. At least
> on ARM this means that it won't work with MMU enabled, so we should
> either add the following to Kconfig:
>
> depends on !ARM || !MMU
>
> Or add the dma_* functions. I added hints where to add these functions
> inline, but I can't test this.
Well, the driver was tested on a platform with ARM926EJ-S CPU
and works -- because it uses dma_alloc_coherent(). That
might not be optimal wrt performance, but it matches what
the u-boot driver is doing. Do you want me to convert it
to use cachable memory and dma flush/inv?
> > + start = get_time_ns();
> > + while (readl(&mac_p->miiaddr) & MII_BUSY) {
> > + if (is_timeout(start, 10 * MSECOND)) {
> > + dev_err(&priv->netdev.dev, "MDIO timeout\n");
> > + return -EIO;
> > + }
> > + udelay(10);
>
> We do not need udelay in timeout loops as we are polling anyway.
OK, will fix
> > +#if defined(CONFIG_DW_ALTDESCRIPTOR)
>
> Do we need this? If yes, we should add an (invisible, board selectable)
> option to Kconfig.
>
> In U-Boot this is described with:
>
> 1. CONFIG_DW_ALTDESCRIPTOR
> Define this to use the Alternate/Enhanced Descriptor configurations.
>
> Does this mean this is an alternative way to use this hardware or does
> this mean it's another version (or IP core configuration) of this hardware?
This depends on IP core configuration. (The major difference of the
alternate descriptor is that it has a larger length field
with can support jumbo packets.)
I wasn't sure about Kconfig because of the arch/arm/board/*/config.h.
To me it looked like config.h is a good place for this?
Thanks,
Johannes
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 6/6] drivers/net: add designware driver
2012-06-20 8:11 ` Johannes Stezenbach
@ 2012-06-20 8:41 ` Sascha Hauer
0 siblings, 0 replies; 16+ messages in thread
From: Sascha Hauer @ 2012-06-20 8:41 UTC (permalink / raw)
To: Johannes Stezenbach; +Cc: barebox
On Wed, Jun 20, 2012 at 10:11:58AM +0200, Johannes Stezenbach wrote:
> Hi Sascha,
>
> On Wed, Jun 20, 2012 at 09:13:01AM +0200, Sascha Hauer wrote:
> > On Mon, Jun 18, 2012 at 04:48:00PM +0200, Johannes Stezenbach wrote:
> > > Straight forward port of Synopsys Designware ethernet
> > > driver from u-boot v2012.04.01.
> ...
> > > +config DRIVER_NET_DESIGNWARE
> > > + bool "Designware Universal MAC ethernet driver"
> > > + select MIIDEV
> > > + depends on HAS_DESIGNWARE_ETH
> > > + help
> > > + This option enables support for the Synopsys
> > > + Designware Core Univesal MAC 10M/100M/1G ethernet IP.
> >
> > This driver uses DMA, but it has no cache flush/invalidation. At least
> > on ARM this means that it won't work with MMU enabled, so we should
> > either add the following to Kconfig:
> >
> > depends on !ARM || !MMU
> >
> > Or add the dma_* functions. I added hints where to add these functions
> > inline, but I can't test this.
>
> Well, the driver was tested on a platform with ARM926EJ-S CPU
> and works -- because it uses dma_alloc_coherent(). That
> might not be optimal wrt performance, but it matches what
> the u-boot driver is doing. Do you want me to convert it
> to use cachable memory and dma flush/inv?
Ah, my bad. I thought you only allocated the descriptor ring with
dma_alloc_coherent, but indeed you also used it for allocating the
buffers. It's fine then.
>
> This depends on IP core configuration. (The major difference of the
> alternate descriptor is that it has a larger length field
> with can support jumbo packets.)
>
> I wasn't sure about Kconfig because of the arch/arm/board/*/config.h.
> To me it looked like config.h is a good place for this?
I prefer to use Kconfig whenever possible. Using config.h should be
avoided.
Sascha
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 0/6] misc ethernet fixes and new driver
2012-06-18 14:47 [PATCH 0/6] misc ethernet fixes and new driver Johannes Stezenbach
` (5 preceding siblings ...)
2012-06-18 14:48 ` [PATCH 6/6] drivers/net: add designware driver Johannes Stezenbach
@ 2012-06-20 7:15 ` Sascha Hauer
6 siblings, 0 replies; 16+ messages in thread
From: Sascha Hauer @ 2012-06-20 7:15 UTC (permalink / raw)
To: Johannes Stezenbach; +Cc: barebox
On Mon, Jun 18, 2012 at 04:47:54PM +0200, Johannes Stezenbach wrote:
> Hi,
>
> I ported the designware ethernet driver from u-boot, it
> only required minor changes and worked right away.
> Since my hw has 1G ethernet I added support for this,
> although speed is not so important in a boot loader it seemed
> easier than to reconfigure the PHY for 100Mbit.
>
> Patches 4 and 5 may be a bit controversial. The motivation
> for patch 4 is that took me some head scratching to get
> debug read/write on PHY regs correct since md and mw worked
> against my intuition on /dev/phy0.
> The string in eth_set_ethaddr() confused me to think a string
> would be passed to ->set_ethaddr(). Changing "unsigned char *adr"
> to "u8 adr[6]" does not change the generated code but is IMHO
> harder to misunderstand.
I applied this series up to 5/6 for now. Thanks, it's always nice to see code
cleanups.
Sascha
>
>
> Johannes
>
> drivers/net/Kconfig | 11 ++
> drivers/net/Makefile | 1 +
> drivers/net/designware.c | 433 ++++++++++++++++++++++++++++++++++++++++++++++
> drivers/net/designware.h | 230 ++++++++++++++++++++++++
> drivers/net/miidev.c | 72 ++++++--
> include/miidev.h | 4 +
> include/net.h | 8 +-
> include/net/designware.h | 9 +
> net/eth.c | 2 +-
> net/net.c | 4 +-
> 10 files changed, 752 insertions(+), 22 deletions(-)
>
>
> _______________________________________________
> barebox mailing list
> barebox@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox
>
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 16+ messages in thread