mirror of https://gitee.com/openkylin/qemu.git
ftgmac100: implement the new MDIO interface on Aspeed SoC
The PHY behind the MAC of an Aspeed SoC can be controlled using two different MDC/MDIO interfaces. The same registers PHYCR (MAC60) and PHYDATA (MAC64) are involved but they have a different layout. BIT31 of the Feature Register (MAC40) controls which MDC/MDIO interface is active. Signed-off-by: Cédric Le Goater <clg@kaod.org> Reviewed-by: Andrew Jeffery <andrew@aj.id.au> Reviewed-by: Joel Stanley <joel@jms.id.au> Message-id: 20190111125759.31577-1-clg@kaod.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
parent
2d2a4549cc
commit
f16c845ade
|
@ -89,6 +89,18 @@
|
||||||
#define FTGMAC100_PHYDATA_MIIWDATA(x) ((x) & 0xffff)
|
#define FTGMAC100_PHYDATA_MIIWDATA(x) ((x) & 0xffff)
|
||||||
#define FTGMAC100_PHYDATA_MIIRDATA(x) (((x) >> 16) & 0xffff)
|
#define FTGMAC100_PHYDATA_MIIRDATA(x) (((x) >> 16) & 0xffff)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PHY control register - New MDC/MDIO interface
|
||||||
|
*/
|
||||||
|
#define FTGMAC100_PHYCR_NEW_DATA(x) (((x) >> 16) & 0xffff)
|
||||||
|
#define FTGMAC100_PHYCR_NEW_FIRE (1 << 15)
|
||||||
|
#define FTGMAC100_PHYCR_NEW_ST_22 (1 << 12)
|
||||||
|
#define FTGMAC100_PHYCR_NEW_OP(x) (((x) >> 10) & 3)
|
||||||
|
#define FTGMAC100_PHYCR_NEW_OP_WRITE 0x1
|
||||||
|
#define FTGMAC100_PHYCR_NEW_OP_READ 0x2
|
||||||
|
#define FTGMAC100_PHYCR_NEW_DEV(x) (((x) >> 5) & 0x1f)
|
||||||
|
#define FTGMAC100_PHYCR_NEW_REG(x) ((x) & 0x1f)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Feature Register
|
* Feature Register
|
||||||
*/
|
*/
|
||||||
|
@ -269,9 +281,9 @@ static void phy_reset(FTGMAC100State *s)
|
||||||
s->phy_int = 0;
|
s->phy_int = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t do_phy_read(FTGMAC100State *s, int reg)
|
static uint16_t do_phy_read(FTGMAC100State *s, uint8_t reg)
|
||||||
{
|
{
|
||||||
uint32_t val;
|
uint16_t val;
|
||||||
|
|
||||||
switch (reg) {
|
switch (reg) {
|
||||||
case MII_BMCR: /* Basic Control */
|
case MII_BMCR: /* Basic Control */
|
||||||
|
@ -336,7 +348,7 @@ static uint32_t do_phy_read(FTGMAC100State *s, int reg)
|
||||||
MII_BMCR_FD | MII_BMCR_CTST)
|
MII_BMCR_FD | MII_BMCR_CTST)
|
||||||
#define MII_ANAR_MASK 0x2d7f
|
#define MII_ANAR_MASK 0x2d7f
|
||||||
|
|
||||||
static void do_phy_write(FTGMAC100State *s, int reg, uint32_t val)
|
static void do_phy_write(FTGMAC100State *s, uint8_t reg, uint16_t val)
|
||||||
{
|
{
|
||||||
switch (reg) {
|
switch (reg) {
|
||||||
case MII_BMCR: /* Basic Control */
|
case MII_BMCR: /* Basic Control */
|
||||||
|
@ -373,6 +385,55 @@ static void do_phy_write(FTGMAC100State *s, int reg, uint32_t val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void do_phy_new_ctl(FTGMAC100State *s)
|
||||||
|
{
|
||||||
|
uint8_t reg;
|
||||||
|
uint16_t data;
|
||||||
|
|
||||||
|
if (!(s->phycr & FTGMAC100_PHYCR_NEW_ST_22)) {
|
||||||
|
qemu_log_mask(LOG_UNIMP, "%s: unsupported ST code\n", __func__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Nothing to do */
|
||||||
|
if (!(s->phycr & FTGMAC100_PHYCR_NEW_FIRE)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
reg = FTGMAC100_PHYCR_NEW_REG(s->phycr);
|
||||||
|
data = FTGMAC100_PHYCR_NEW_DATA(s->phycr);
|
||||||
|
|
||||||
|
switch (FTGMAC100_PHYCR_NEW_OP(s->phycr)) {
|
||||||
|
case FTGMAC100_PHYCR_NEW_OP_WRITE:
|
||||||
|
do_phy_write(s, reg, data);
|
||||||
|
break;
|
||||||
|
case FTGMAC100_PHYCR_NEW_OP_READ:
|
||||||
|
s->phydata = do_phy_read(s, reg) & 0xffff;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid OP code %08x\n",
|
||||||
|
__func__, s->phycr);
|
||||||
|
}
|
||||||
|
|
||||||
|
s->phycr &= ~FTGMAC100_PHYCR_NEW_FIRE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void do_phy_ctl(FTGMAC100State *s)
|
||||||
|
{
|
||||||
|
uint8_t reg = FTGMAC100_PHYCR_REG(s->phycr);
|
||||||
|
|
||||||
|
if (s->phycr & FTGMAC100_PHYCR_MIIWR) {
|
||||||
|
do_phy_write(s, reg, s->phydata & 0xffff);
|
||||||
|
s->phycr &= ~FTGMAC100_PHYCR_MIIWR;
|
||||||
|
} else if (s->phycr & FTGMAC100_PHYCR_MIIRD) {
|
||||||
|
s->phydata = do_phy_read(s, reg) << 16;
|
||||||
|
s->phycr &= ~FTGMAC100_PHYCR_MIIRD;
|
||||||
|
} else {
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR, "%s: no OP code %08x\n",
|
||||||
|
__func__, s->phycr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int ftgmac100_read_bd(FTGMAC100Desc *bd, dma_addr_t addr)
|
static int ftgmac100_read_bd(FTGMAC100Desc *bd, dma_addr_t addr)
|
||||||
{
|
{
|
||||||
if (dma_memory_read(&address_space_memory, addr, bd, sizeof(*bd))) {
|
if (dma_memory_read(&address_space_memory, addr, bd, sizeof(*bd))) {
|
||||||
|
@ -628,7 +689,6 @@ static void ftgmac100_write(void *opaque, hwaddr addr,
|
||||||
uint64_t value, unsigned size)
|
uint64_t value, unsigned size)
|
||||||
{
|
{
|
||||||
FTGMAC100State *s = FTGMAC100(opaque);
|
FTGMAC100State *s = FTGMAC100(opaque);
|
||||||
int reg;
|
|
||||||
|
|
||||||
switch (addr & 0xff) {
|
switch (addr & 0xff) {
|
||||||
case FTGMAC100_ISR: /* Interrupt status */
|
case FTGMAC100_ISR: /* Interrupt status */
|
||||||
|
@ -711,14 +771,11 @@ static void ftgmac100_write(void *opaque, hwaddr addr,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FTGMAC100_PHYCR: /* PHY Device control */
|
case FTGMAC100_PHYCR: /* PHY Device control */
|
||||||
reg = FTGMAC100_PHYCR_REG(value);
|
|
||||||
s->phycr = value;
|
s->phycr = value;
|
||||||
if (value & FTGMAC100_PHYCR_MIIWR) {
|
if (s->revr & FTGMAC100_REVR_NEW_MDIO_INTERFACE) {
|
||||||
do_phy_write(s, reg, s->phydata & 0xffff);
|
do_phy_new_ctl(s);
|
||||||
s->phycr &= ~FTGMAC100_PHYCR_MIIWR;
|
|
||||||
} else {
|
} else {
|
||||||
s->phydata = do_phy_read(s, reg) << 16;
|
do_phy_ctl(s);
|
||||||
s->phycr &= ~FTGMAC100_PHYCR_MIIRD;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case FTGMAC100_PHYDATA:
|
case FTGMAC100_PHYDATA:
|
||||||
|
@ -728,8 +785,7 @@ static void ftgmac100_write(void *opaque, hwaddr addr,
|
||||||
s->dblac = value;
|
s->dblac = value;
|
||||||
break;
|
break;
|
||||||
case FTGMAC100_REVR: /* Feature Register */
|
case FTGMAC100_REVR: /* Feature Register */
|
||||||
/* TODO: Only Old MDIO interface is supported */
|
s->revr = value;
|
||||||
s->revr = value & ~FTGMAC100_REVR_NEW_MDIO_INTERFACE;
|
|
||||||
break;
|
break;
|
||||||
case FTGMAC100_FEAR1: /* Feature Register 1 */
|
case FTGMAC100_FEAR1: /* Feature Register 1 */
|
||||||
s->fear1 = value;
|
s->fear1 = value;
|
||||||
|
|
Loading…
Reference in New Issue