From: Yoshinori Sato <ysato@users.sourceforge.jp>
To: qemu-devel@nongnu.org
Cc: Yoshinori Sato <ysato@users.sourceforge.jp>
Subject: [PATCH 15/20] hw/net: Add generic Bit-bang MDIO PHY.
Date: Thu, 27 Aug 2020 21:38:54 +0900 [thread overview]
Message-ID: <20200827123859.81793-16-ysato@users.sourceforge.jp> (raw)
In-Reply-To: <20200827123859.81793-1-ysato@users.sourceforge.jp>
Only supported link status.
Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
include/hw/net/mdio.h | 126 ++++++++++++++++++++
hw/net/mdio.c | 264 ++++++++++++++++++++++++++++++++++++++++++
hw/net/Kconfig | 3 +
hw/net/meson.build | 2 +
4 files changed, 395 insertions(+)
create mode 100644 include/hw/net/mdio.h
create mode 100644 hw/net/mdio.c
diff --git a/include/hw/net/mdio.h b/include/hw/net/mdio.h
new file mode 100644
index 0000000000..55a7170e67
--- /dev/null
+++ b/include/hw/net/mdio.h
@@ -0,0 +1,126 @@
+/*
+ * MDIO PHY emulation
+ *
+ * Copyright 2020 Yoshinori Sato <ysato@users.sourceforge.jp>
+ *
+ * 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; under version 2 of the License.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
+ */
+
+#ifndef MDIO_H
+#define MDIO_H
+
+#include "hw/qdev-core.h"
+#include "hw/net/mii.h"
+
+typedef enum mdio_pin {
+ mdio_z = -1,
+ mdio_l = 0,
+ mdio_h = 1,
+} MDIOPin;
+
+#define TYPE_ETHER_PHY "ether-phy"
+#define TYPE_ETHER_PHY_CLASS(obj) \
+ OBJECT_GET_CLASS(EtherPHYClass, (obj), TYPE_ETHER_PHY)
+#define EtherPHYClass(klass) \
+ OBJECT_CHECK_CLASS(EtherPHYClass, (klass), TYPE_ETHER_PHY)
+#define EtherPHY(obj) \
+ OBJECT_CHECK(PHYState, (obj), TYPE_ETHER_PHY)
+
+#define TYPE_ETHER_MDIO_BB "ether-mdio-bb"
+#define TYPE_ETHER_MDIO_BB_CLASS(obj) \
+ OBJECT_GET_CLASS(MDIO_BBClass, (obj), TYPE_ETHER_MDIO_BB)
+#define MDIO_BBClass(klass) \
+ OBJECT_CHECK_CLASS(MDIO_BBClass, (klass), TYPE_ETHER_MDIO_BB)
+#define MDIO_BB(obj) \
+ OBJECT_CHECK(MDIOState, (obj), TYPE_ETHER_MDIO_BB)
+
+typedef enum {
+ phy_out_p = 0, /* Link up is 'H' */
+ phy_out_n = 1, /* Link up is 'L' */
+} phy_output_polarity;
+
+typedef struct {
+ DeviceState parent;
+
+ uint16_t regs[32];
+ uint32_t identifier;
+ bool link_ok;
+ phy_output_polarity link_out_pol;
+ uint16_t bmsr;
+ uint16_t anlpar;
+} PHYState;
+
+#define MDIO_ANLPAR_LINK \
+ (MII_ANLPAR_TXFD | MII_ANLPAR_TX | MII_ANLPAR_10FD | MII_ANLPAR_10 | \
+ MII_ANLPAR_CSMACD)
+
+typedef enum {
+ BB_PRE,
+ BB_ST,
+ BB_CMD,
+ BB_TA_R,
+ BB_TA_W,
+ BB_DATA_R,
+ BB_DATA_W,
+ BB_INH,
+} mdio_bb_state;
+
+typedef struct {
+ DeviceState parent;
+
+ PHYState *phy;
+ mdio_bb_state bb_state;
+ int pclk;
+ int bits;
+ int cmd;
+ int phyad;
+ int selphy;
+ int regad;
+ int data;
+ int mdi_pin;
+ int mdo_pin;
+} MDIOState;
+
+#define mdio_get_phy(s) (s->phy)
+
+typedef struct {
+ DeviceClass parent;
+} EtherPHYClass;
+
+typedef struct {
+ DeviceClass parent;
+} MDIO_BBClass;
+
+/* Generic PHY interface */
+void mdio_phy_set_link(PHYState *s, bool ok);
+int mdio_phy_linksta(PHYState *s);
+uint16_t mdio_phy_read(PHYState *s, int addr);
+void mdio_phy_write(PHYState *s, int addr, uint16_t val);
+
+/* Bit-bang MDIO operation */
+static inline MDIOPin mdio_read_mdi_pin(MDIOState *s)
+{
+ return s->mdi_pin;
+}
+
+static inline void mdio_set_mdo_pin(MDIOState *s, MDIOPin mdo)
+{
+ s->mdo_pin = mdo;
+}
+
+void mdio_set_mdc_pin(MDIOState *s, int clk);
+
+#endif
diff --git a/hw/net/mdio.c b/hw/net/mdio.c
new file mode 100644
index 0000000000..39670e70c6
--- /dev/null
+++ b/hw/net/mdio.c
@@ -0,0 +1,264 @@
+/*
+ * Bit-bang MII emulation
+ *
+ * Copyright 2020 Yoshinori Sato <ysato@users.sourceforge.jp>
+ *
+ * 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; under version 2 of the License.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/bitops.h"
+#include "qemu/log.h"
+#include "hw/qdev-properties.h"
+#include "hw/net/mdio.h"
+
+void mdio_phy_set_link(PHYState *s, bool ok)
+{
+ if (ok) {
+ s->regs[MII_BMSR] |= MII_BMSR_LINK_ST;
+ s->regs[MII_ANLPAR] |= MDIO_ANLPAR_LINK;
+ } else {
+ s->regs[MII_BMSR] &= ~(MII_BMSR_LINK_ST | MII_BMSR_AUTONEG);
+ s->regs[MII_ANLPAR] &= MDIO_ANLPAR_LINK;
+ }
+ s->link_ok = ok;
+}
+
+static void mdio_phy_reset(PHYState *s)
+{
+ memset(s->regs, 0, sizeof(s->regs));
+ s->regs[MII_BMSR] = s->bmsr;
+ s->regs[MII_ANLPAR] = s->anlpar;
+ s->regs[MII_PHYID1] = extract32(s->identifier, 16, 16);
+ s->regs[MII_PHYID2] = extract32(s->identifier, 0, 16);
+ mdio_phy_set_link(s, s->link_ok);
+}
+
+uint16_t mdio_phy_read(PHYState *s, int addr)
+{
+ if (addr >= 0 && addr < 32) {
+ return s->regs[addr];
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "mdio: Register %04x invalid address.\n", addr);
+ return 0;
+ }
+}
+
+int mdio_phy_linksta(PHYState *s)
+{
+ return s->link_ok ^ s->link_out_pol;
+}
+
+void mdio_phy_write(PHYState *s, int addr, uint16_t val)
+{
+ switch (addr) {
+ case MII_BMCR:
+ s->regs[MII_BMCR] = val & 0xfd80;
+ if (val & MII_BMCR_RESET) {
+ mdio_phy_reset(s);
+ }
+ break;
+ case MII_BMSR:
+ case MII_ANLPAR:
+ /* Read only */
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "mdio: Register %04x is read only register.\n", addr);
+ break;
+ case MII_PHYID1:
+ case MII_PHYID2:
+ s->regs[addr] = val;
+ break;
+ case MII_ANAR:
+ s->regs[addr] = val & 0x2dff;
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP,
+ "mdio: Register %04x not implemented\n", addr);
+ break;
+ }
+}
+
+static Property phy_properties[] = {
+ DEFINE_PROP_UINT32("phy-id", PHYState, identifier, 0),
+ DEFINE_PROP_UINT32("link-out-pol", PHYState, link_out_pol, 0),
+ DEFINE_PROP_UINT16("bmsr", PHYState, bmsr, 0),
+ DEFINE_PROP_UINT16("anlpar", PHYState, anlpar, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void phy_realize(DeviceState *dev, Error **errp)
+{
+ PHYState *s = EtherPHY(dev);
+ mdio_phy_reset(s);
+}
+
+static void phy_class_init(ObjectClass *klass, void *class_data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ device_class_set_props(dc, phy_properties);
+ dc->realize = phy_realize;
+}
+
+/* shift in MDO */
+static void read_mdo(MDIOState *s)
+{
+ int op;
+ s->bits++;
+ switch (s->bb_state) {
+ case BB_PRE: /* preamble */
+ if (s->mdo_pin == 0) {
+ /* ST 1st bit found */
+ s->bb_state = BB_ST;
+ }
+ break;
+ case BB_ST: /* ST 2nd bit */
+ if (s->mdo_pin == 0) {
+ s->bb_state = BB_CMD;
+ s->cmd = 0;
+ s->bits = 2;
+ s->selphy = -1;
+ s->regad = -1;
+ } else {
+ s->bb_state = BB_PRE;
+ }
+ break;
+ case BB_CMD:
+ s->cmd <<= 1;
+ s->cmd |= (s->mdo_pin & 1);
+ if (s->bits == 14) {
+ op = extract32(s->cmd, 10, 2);
+ s->selphy = extract32(s->cmd, 5, 5);
+ s->regad = extract32(s->cmd, 0, 5);
+ switch (op) {
+ case 0x02: /* READ */
+ s->bb_state = BB_TA_R;
+ break;
+ case 0x01: /* WRITE */
+ s->bb_state = BB_TA_W;
+ break;
+ default:
+ s->bb_state = BB_INH;
+ break;
+ }
+ }
+ break;
+ case BB_TA_R:
+ s->mdi_pin = 0;
+ if (s->bits == 16) {
+ if (s->phyad == s->selphy) {
+ s->data = mdio_phy_read(s->phy, s->regad);
+ s->bb_state = BB_DATA_R;
+ } else {
+ s->bb_state = BB_INH;
+ }
+ }
+ break;
+ case BB_TA_W:
+ if (s->bits == 16) {
+ s->bb_state = BB_DATA_W;
+ }
+ break;
+ case BB_DATA_W:
+ s->data <<= 1;
+ s->data |= (s->mdo_pin & 1);
+ if (s->bits == 32) {
+ if (s->phyad == s->selphy) {
+ mdio_phy_write(s->phy, s->regad, s->data);
+ }
+ s->bb_state = BB_PRE;
+ }
+ break;
+ case BB_INH:
+ case BB_DATA_R:
+ if (s->bits == 32) {
+ s->bb_state = BB_PRE;
+ }
+ break;
+ }
+}
+
+/* shift out MDI */
+static void write_mdi(MDIOState *s)
+{
+ switch (s->bb_state) {
+ case BB_DATA_R:
+ s->mdi_pin = (s->data >> 15) & 1;
+ s->data <<= 1;
+ break;
+ case BB_TA_R:
+ s->mdi_pin = 0;
+ break;
+ default:
+ s->mdi_pin = mdio_z;
+ break;
+ }
+}
+
+/* MDIO pin operation */
+void mdio_set_mdc_pin(MDIOState *s, int clk)
+{
+ if (s->pclk ^ (clk & 1)) {
+ s->pclk = (clk & 1);
+ if (s->pclk == 1) {
+ /* rising edge */
+ read_mdo(s);
+ } else {
+ /* faling edge */
+ write_mdi(s);
+ }
+ }
+}
+
+static Property bb_properties[] = {
+ DEFINE_PROP_INT32("address", MDIOState, phyad, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void bb_init(Object *obj)
+{
+ MDIOState *s = MDIO_BB(obj);
+
+ object_property_add_link(obj, "phy",
+ TYPE_ETHER_PHY,
+ (Object **)&s->phy,
+ qdev_prop_allow_set_link_before_realize,
+ OBJ_PROP_LINK_STRONG);
+}
+
+static void bb_class_init(ObjectClass *klass, void *class_data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ device_class_set_props(dc, bb_properties);
+}
+
+static const TypeInfo phy_types_info[] = {
+ {
+ .name = TYPE_ETHER_PHY,
+ .parent = TYPE_DEVICE,
+ .class_init = phy_class_init,
+ .instance_size = sizeof(PHYState),
+ },
+ {
+ .name = TYPE_ETHER_MDIO_BB,
+ .parent = TYPE_DEVICE,
+ .class_init = bb_class_init,
+ .instance_size = sizeof(MDIOState),
+ .instance_init = bb_init,
+ },
+};
+
+DEFINE_TYPES(phy_types_info);
diff --git a/hw/net/Kconfig b/hw/net/Kconfig
index e43c96dae0..e6a32a2ab0 100644
--- a/hw/net/Kconfig
+++ b/hw/net/Kconfig
@@ -143,3 +143,6 @@ config CAN_SJA1000
default y if PCI_DEVICES
depends on PCI
select CAN_BUS
+
+config MDIO_PHY
+ bool
diff --git a/hw/net/meson.build b/hw/net/meson.build
index 4a7051b54a..faa4e3d2c0 100644
--- a/hw/net/meson.build
+++ b/hw/net/meson.build
@@ -64,4 +64,6 @@ softmmu_ss.add(when: 'CONFIG_ROCKER', if_true: files(
), if_false: files('rocker/qmp-norocker.c'))
softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('rocker/qmp-norocker.c'))
+softmmu_ss.add(when: 'CONFIG_MDIO_PHY', if_true: files('mdio.c'))
+
subdir('can')
--
2.20.1
next prev parent reply other threads:[~2020-08-27 12:49 UTC|newest]
Thread overview: 40+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-08-27 12:38 [PATCH 00/20] RX target update Yoshinori Sato
2020-08-27 12:38 ` [PATCH 01/20] loader.c: Add support Motrola S-record format Yoshinori Sato
2020-09-08 20:44 ` Philippe Mathieu-Daudé
2020-10-25 0:43 ` Philippe Mathieu-Daudé
2020-10-27 21:05 ` Alistair Francis
2020-08-27 12:38 ` [PATCH 02/20] include/elf.h: Add EM_RX Yoshinori Sato
2020-08-27 12:38 ` [PATCH 03/20] hw/rx: Firmware and kernel loader Yoshinori Sato
2020-09-08 20:47 ` Philippe Mathieu-Daudé
2020-08-27 12:38 ` [PATCH 04/20] hw/rx: New firmware loader Yoshinori Sato
2020-08-27 12:38 ` [PATCH 05/20] hw/rx: Add RX62N Clock generator Yoshinori Sato
2020-09-08 21:11 ` Philippe Mathieu-Daudé
2020-10-24 21:56 ` Philippe Mathieu-Daudé
2020-10-24 21:58 ` Philippe Mathieu-Daudé
2020-08-27 12:38 ` [PATCH 06/20] hw/timer: Renesas 8bit timer emulation Yoshinori Sato
2020-10-24 21:27 ` Philippe Mathieu-Daudé
2020-10-24 21:29 ` Philippe Mathieu-Daudé
2020-08-27 12:38 ` [PATCH 07/20] hw/rx: RX62N convert new 8bit timer Yoshinori Sato
2020-08-27 12:38 ` [PATCH 08/20] hw/timer: Renesas TMU/CMT module Yoshinori Sato
2020-10-24 22:47 ` Philippe Mathieu-Daudé
2020-08-27 12:38 ` [PATCH 09/20] hw/timer: Remove renesas_cmt Yoshinori Sato
2020-08-27 12:38 ` [PATCH 10/20] hw/rx: Convert to renesas_timer Yoshinori Sato
2020-08-27 12:38 ` [PATCH 11/20] hw/char: Renesas SCI module Yoshinori Sato
2020-10-24 21:40 ` Philippe Mathieu-Daudé
2020-08-27 12:38 ` [PATCH 12/20] hw/rx/rx62n: Use New " Yoshinori Sato
2020-10-25 0:33 ` Philippe Mathieu-Daudé
2020-08-27 12:38 ` [PATCH 13/20] hw/timer: Add Renesas MTU2 Yoshinori Sato
2020-08-27 12:38 ` [PATCH 14/20] hw/rx/rx62n: RX62N Add MTU module Yoshinori Sato
2020-09-08 21:12 ` Philippe Mathieu-Daudé
2020-08-27 12:38 ` Yoshinori Sato [this message]
2020-08-27 12:38 ` [PATCH 16/20] hw/net: Add Renesas On-chip Ethernet MAC Yoshinori Sato
2020-10-24 21:37 ` Philippe Mathieu-Daudé
2020-08-27 12:38 ` [PATCH 17/20] hw/rx/rx62n: Add Ethernet support Yoshinori Sato
2020-08-27 12:38 ` [PATCH 18/20] hw/rx: Add Tokudenkairo TKDN-RX62N-BRD Yoshinori Sato
2020-09-08 21:18 ` Philippe Mathieu-Daudé
2020-08-27 12:38 ` [PATCH 19/20] hw/rx: Add CQ-FRK-RX62N target Yoshinori Sato
2020-09-08 21:20 ` Philippe Mathieu-Daudé
2020-08-27 12:38 ` [PATCH 20/20] MAINTAINERS: Update RX entry Yoshinori Sato
2020-09-08 21:21 ` Philippe Mathieu-Daudé
2020-08-31 20:38 ` [PATCH 00/20] RX target update Philippe Mathieu-Daudé
2020-09-10 16:06 ` Yoshinori Sato
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200827123859.81793-16-ysato@users.sourceforge.jp \
--to=ysato@users.sourceforge.jp \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.