提交 289251b0 编写于 作者: C Cédric Le Goater 提交者: Peter Maydell

aspeed: add support for the Aspeed MII controller of the AST2600

The AST2600 SoC has an extra controller to set the PHY registers.
Signed-off-by: NCédric Le Goater <clg@kaod.org>
Reviewed-by: NJoel Stanley <joel@jms.id.au>
Message-id: 20190925143248.10000-23-clg@kaod.org
Signed-off-by: NPeter Maydell <peter.maydell@linaro.org>
上级 d300db02
......@@ -31,6 +31,10 @@ static const hwaddr aspeed_soc_ast2600_memmap[] = {
[ASPEED_FMC] = 0x1E620000,
[ASPEED_SPI1] = 0x1E630000,
[ASPEED_SPI2] = 0x1E641000,
[ASPEED_MII1] = 0x1E650000,
[ASPEED_MII2] = 0x1E650008,
[ASPEED_MII3] = 0x1E650010,
[ASPEED_MII4] = 0x1E650018,
[ASPEED_ETH1] = 0x1E660000,
[ASPEED_ETH3] = 0x1E670000,
[ASPEED_ETH2] = 0x1E680000,
......@@ -181,6 +185,12 @@ static void aspeed_soc_ast2600_init(Object *obj)
for (i = 0; i < sc->macs_num; i++) {
sysbus_init_child_obj(obj, "ftgmac100[*]", OBJECT(&s->ftgmac100[i]),
sizeof(s->ftgmac100[i]), TYPE_FTGMAC100);
sysbus_init_child_obj(obj, "mii[*]", &s->mii[i], sizeof(s->mii[i]),
TYPE_ASPEED_MII);
object_property_add_const_link(OBJECT(&s->mii[i]), "nic",
OBJECT(&s->ftgmac100[i]),
&error_abort);
}
sysbus_init_child_obj(obj, "xdma", OBJECT(&s->xdma), sizeof(s->xdma),
......@@ -417,6 +427,16 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
sc->memmap[ASPEED_ETH1 + i]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->ftgmac100[i]), 0,
aspeed_soc_get_irq(s, ASPEED_ETH1 + i));
object_property_set_bool(OBJECT(&s->mii[i]), true, "realized",
&err);
if (err) {
error_propagate(errp, err);
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->mii[i]), 0,
sc->memmap[ASPEED_MII1 + i]);
}
/* XDMA */
......
......@@ -15,6 +15,7 @@
#include "hw/irq.h"
#include "hw/net/ftgmac100.h"
#include "sysemu/dma.h"
#include "qapi/error.h"
#include "qemu/log.h"
#include "qemu/module.h"
#include "net/checksum.h"
......@@ -1087,9 +1088,170 @@ static const TypeInfo ftgmac100_info = {
.class_init = ftgmac100_class_init,
};
/*
* AST2600 MII controller
*/
#define ASPEED_MII_PHYCR_FIRE BIT(31)
#define ASPEED_MII_PHYCR_ST_22 BIT(28)
#define ASPEED_MII_PHYCR_OP(x) ((x) & (ASPEED_MII_PHYCR_OP_WRITE | \
ASPEED_MII_PHYCR_OP_READ))
#define ASPEED_MII_PHYCR_OP_WRITE BIT(26)
#define ASPEED_MII_PHYCR_OP_READ BIT(27)
#define ASPEED_MII_PHYCR_DATA(x) (x & 0xffff)
#define ASPEED_MII_PHYCR_PHY(x) (((x) >> 21) & 0x1f)
#define ASPEED_MII_PHYCR_REG(x) (((x) >> 16) & 0x1f)
#define ASPEED_MII_PHYDATA_IDLE BIT(16)
static void aspeed_mii_transition(AspeedMiiState *s, bool fire)
{
if (fire) {
s->phycr |= ASPEED_MII_PHYCR_FIRE;
s->phydata &= ~ASPEED_MII_PHYDATA_IDLE;
} else {
s->phycr &= ~ASPEED_MII_PHYCR_FIRE;
s->phydata |= ASPEED_MII_PHYDATA_IDLE;
}
}
static void aspeed_mii_do_phy_ctl(AspeedMiiState *s)
{
uint8_t reg;
uint16_t data;
if (!(s->phycr & ASPEED_MII_PHYCR_ST_22)) {
aspeed_mii_transition(s, !ASPEED_MII_PHYCR_FIRE);
qemu_log_mask(LOG_UNIMP, "%s: unsupported ST code\n", __func__);
return;
}
/* Nothing to do */
if (!(s->phycr & ASPEED_MII_PHYCR_FIRE)) {
return;
}
reg = ASPEED_MII_PHYCR_REG(s->phycr);
data = ASPEED_MII_PHYCR_DATA(s->phycr);
switch (ASPEED_MII_PHYCR_OP(s->phycr)) {
case ASPEED_MII_PHYCR_OP_WRITE:
do_phy_write(s->nic, reg, data);
break;
case ASPEED_MII_PHYCR_OP_READ:
s->phydata = (s->phydata & ~0xffff) | do_phy_read(s->nic, reg);
break;
default:
qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid OP code %08x\n",
__func__, s->phycr);
}
aspeed_mii_transition(s, !ASPEED_MII_PHYCR_FIRE);
}
static uint64_t aspeed_mii_read(void *opaque, hwaddr addr, unsigned size)
{
AspeedMiiState *s = ASPEED_MII(opaque);
switch (addr) {
case 0x0:
return s->phycr;
case 0x4:
return s->phydata;
default:
g_assert_not_reached();
}
}
static void aspeed_mii_write(void *opaque, hwaddr addr,
uint64_t value, unsigned size)
{
AspeedMiiState *s = ASPEED_MII(opaque);
switch (addr) {
case 0x0:
s->phycr = value & ~(s->phycr & ASPEED_MII_PHYCR_FIRE);
break;
case 0x4:
s->phydata = value & ~(0xffff | ASPEED_MII_PHYDATA_IDLE);
break;
default:
g_assert_not_reached();
}
aspeed_mii_transition(s, !!(s->phycr & ASPEED_MII_PHYCR_FIRE));
aspeed_mii_do_phy_ctl(s);
}
static const MemoryRegionOps aspeed_mii_ops = {
.read = aspeed_mii_read,
.write = aspeed_mii_write,
.valid.min_access_size = 4,
.valid.max_access_size = 4,
.endianness = DEVICE_LITTLE_ENDIAN,
};
static void aspeed_mii_reset(DeviceState *dev)
{
AspeedMiiState *s = ASPEED_MII(dev);
s->phycr = 0;
s->phydata = 0;
aspeed_mii_transition(s, !!(s->phycr & ASPEED_MII_PHYCR_FIRE));
};
static void aspeed_mii_realize(DeviceState *dev, Error **errp)
{
AspeedMiiState *s = ASPEED_MII(dev);
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
Object *obj;
Error *local_err = NULL;
obj = object_property_get_link(OBJECT(dev), "nic", &local_err);
if (!obj) {
error_propagate(errp, local_err);
error_prepend(errp, "required link 'nic' not found: ");
return;
}
s->nic = FTGMAC100(obj);
memory_region_init_io(&s->iomem, OBJECT(dev), &aspeed_mii_ops, s,
TYPE_ASPEED_MII, 0x8);
sysbus_init_mmio(sbd, &s->iomem);
}
static const VMStateDescription vmstate_aspeed_mii = {
.name = TYPE_ASPEED_MII,
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT32(phycr, FTGMAC100State),
VMSTATE_UINT32(phydata, FTGMAC100State),
VMSTATE_END_OF_LIST()
}
};
static void aspeed_mii_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &vmstate_aspeed_mii;
dc->reset = aspeed_mii_reset;
dc->realize = aspeed_mii_realize;
dc->desc = "Aspeed MII controller";
}
static const TypeInfo aspeed_mii_info = {
.name = TYPE_ASPEED_MII,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(AspeedMiiState),
.class_init = aspeed_mii_class_init,
};
static void ftgmac100_register_types(void)
{
type_register_static(&ftgmac100_info);
type_register_static(&aspeed_mii_info);
}
type_init(ftgmac100_register_types)
......@@ -52,6 +52,7 @@ typedef struct AspeedSoCState {
AspeedSDMCState sdmc;
AspeedWDTState wdt[ASPEED_WDTS_NUM];
FTGMAC100State ftgmac100[ASPEED_MACS_NUM];
AspeedMiiState mii[ASPEED_MACS_NUM];
AspeedGPIOState gpio;
AspeedGPIOState gpio_1_8v;
AspeedSDHCIState sdhci;
......@@ -117,6 +118,10 @@ enum {
ASPEED_ETH2,
ASPEED_ETH3,
ASPEED_ETH4,
ASPEED_MII1,
ASPEED_MII2,
ASPEED_MII3,
ASPEED_MII4,
ASPEED_SDRAM,
ASPEED_XDMA,
};
......
......@@ -66,4 +66,21 @@ typedef struct FTGMAC100State {
uint32_t rxdes0_edorr;
} FTGMAC100State;
#define TYPE_ASPEED_MII "aspeed-mmi"
#define ASPEED_MII(obj) OBJECT_CHECK(AspeedMiiState, (obj), TYPE_ASPEED_MII)
/*
* AST2600 MII controller
*/
typedef struct AspeedMiiState {
/*< private >*/
SysBusDevice parent_obj;
FTGMAC100State *nic;
MemoryRegion iomem;
uint32_t phycr;
uint32_t phydata;
} AspeedMiiState;
#endif
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册