xref: /openbmc/qemu/hw/net/fsl_etsec/miim.c (revision e8d1e0cd)
1 /*
2  * QEMU Freescale eTSEC Emulator
3  *
4  * Copyright (c) 2011-2013 AdaCore
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24 
25 #include "qemu/osdep.h"
26 #include "hw/net/mii.h"
27 #include "etsec.h"
28 #include "registers.h"
29 
30 /* #define DEBUG_MIIM */
31 
32 #define MIIM_CONTROL    0
33 #define MIIM_STATUS     1
34 #define MIIM_PHY_ID_1   2
35 #define MIIM_PHY_ID_2   3
36 #define MIIM_T2_STATUS  10
37 #define MIIM_EXT_STATUS 15
38 
39 static void miim_read_cycle(eTSEC *etsec)
40 {
41     uint8_t  phy;
42     uint8_t  addr;
43     uint16_t value;
44 
45     phy  = (etsec->regs[MIIMADD].value >> 8) & 0x1F;
46     (void)phy; /* Unreferenced */
47     addr = etsec->regs[MIIMADD].value & 0x1F;
48 
49     switch (addr) {
50     case MIIM_CONTROL:
51         value = etsec->phy_control;
52         break;
53     case MIIM_STATUS:
54         value = etsec->phy_status;
55         break;
56     case MIIM_T2_STATUS:
57         value = 0x1800;           /* Local and remote receivers OK */
58         break;
59     default:
60         value = 0x0;
61         break;
62     };
63 
64 #ifdef DEBUG_MIIM
65     qemu_log("%s phy:%d addr:0x%x value:0x%x\n", __func__, phy, addr, value);
66 #endif
67 
68     etsec->regs[MIIMSTAT].value = value;
69 }
70 
71 static void miim_write_cycle(eTSEC *etsec)
72 {
73     uint8_t  phy;
74     uint8_t  addr;
75     uint16_t value;
76 
77     phy   = (etsec->regs[MIIMADD].value >> 8) & 0x1F;
78     (void)phy; /* Unreferenced */
79     addr  = etsec->regs[MIIMADD].value & 0x1F;
80     value = etsec->regs[MIIMCON].value & 0xffff;
81 
82 #ifdef DEBUG_MIIM
83     qemu_log("%s phy:%d addr:0x%x value:0x%x\n", __func__, phy, addr, value);
84 #endif
85 
86     switch (addr) {
87     case MIIM_CONTROL:
88         etsec->phy_control = value & ~(0x8100);
89         break;
90     default:
91         break;
92     };
93 }
94 
95 void etsec_write_miim(eTSEC          *etsec,
96                       eTSEC_Register *reg,
97                       uint32_t        reg_index,
98                       uint32_t        value)
99 {
100 
101     switch (reg_index) {
102 
103     case MIIMCOM:
104         /* Read and scan cycle */
105 
106         if ((!(reg->value & MIIMCOM_READ)) && (value & MIIMCOM_READ)) {
107             /* Read */
108             miim_read_cycle(etsec);
109         }
110         reg->value = value;
111         break;
112 
113     case MIIMCON:
114         reg->value = value & 0xffff;
115         miim_write_cycle(etsec);
116         break;
117 
118     default:
119         /* Default handling */
120         switch (reg->access) {
121 
122         case ACC_RW:
123         case ACC_WO:
124             reg->value = value;
125             break;
126 
127         case ACC_W1C:
128             reg->value &= ~value;
129             break;
130 
131         case ACC_RO:
132         default:
133             /* Read Only or Unknown register */
134             break;
135         }
136     }
137 
138 }
139 
140 void etsec_miim_link_status(eTSEC *etsec, NetClientState *nc)
141 {
142     /* Set link status */
143     if (nc->link_down) {
144         etsec->phy_status &= ~MII_BMSR_LINK_ST;
145     } else {
146         etsec->phy_status |= MII_BMSR_LINK_ST;
147     }
148 }
149