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: Cédric Le Goater <clg@kaod.org> Reviewed-by: Joel Stanley <joel@jms.id.au> Message-id: 20190925143248.10000-23-clg@kaod.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
parent
d300db0277
commit
289251b033
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user