xref: /qemu/hw/net/fsl_etsec/miim.c (revision 7a4e543d)
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 "etsec.h"
27 #include "registers.h"
28 
29 /* #define DEBUG_MIIM */
30 
31 #define MIIM_CONTROL    0
32 #define MIIM_STATUS     1
33 #define MIIM_PHY_ID_1   2
34 #define MIIM_PHY_ID_2   3
35 #define MIIM_T2_STATUS  10
36 #define MIIM_EXT_STATUS 15
37 
38 static void miim_read_cycle(eTSEC *etsec)
39 {
40     uint8_t  phy;
41     uint8_t  addr;
42     uint16_t value;
43 
44     phy  = (etsec->regs[MIIMADD].value >> 8) & 0x1F;
45     (void)phy; /* Unreferenced */
46     addr = etsec->regs[MIIMADD].value & 0x1F;
47 
48     switch (addr) {
49     case MIIM_CONTROL:
50         value = etsec->phy_control;
51         break;
52     case MIIM_STATUS:
53         value = etsec->phy_status;
54         break;
55     case MIIM_T2_STATUS:
56         value = 0x1800;           /* Local and remote receivers OK */
57         break;
58     default:
59         value = 0x0;
60         break;
61     };
62 
63 #ifdef DEBUG_MIIM
64     qemu_log("%s phy:%d addr:0x%x value:0x%x\n", __func__, phy, addr, value);
65 #endif
66 
67     etsec->regs[MIIMSTAT].value = value;
68 }
69 
70 static void miim_write_cycle(eTSEC *etsec)
71 {
72     uint8_t  phy;
73     uint8_t  addr;
74     uint16_t value;
75 
76     phy   = (etsec->regs[MIIMADD].value >> 8) & 0x1F;
77     (void)phy; /* Unreferenced */
78     addr  = etsec->regs[MIIMADD].value & 0x1F;
79     value = etsec->regs[MIIMCON].value & 0xffff;
80 
81 #ifdef DEBUG_MIIM
82     qemu_log("%s phy:%d addr:0x%x value:0x%x\n", __func__, phy, addr, value);
83 #endif
84 
85     switch (addr) {
86     case MIIM_CONTROL:
87         etsec->phy_control = value & ~(0x8100);
88         break;
89     default:
90         break;
91     };
92 }
93 
94 void etsec_write_miim(eTSEC          *etsec,
95                       eTSEC_Register *reg,
96                       uint32_t        reg_index,
97                       uint32_t        value)
98 {
99 
100     switch (reg_index) {
101 
102     case MIIMCOM:
103         /* Read and scan cycle */
104 
105         if ((!(reg->value & MIIMCOM_READ)) && (value & MIIMCOM_READ)) {
106             /* Read */
107             miim_read_cycle(etsec);
108         }
109         reg->value = value;
110         break;
111 
112     case MIIMCON:
113         reg->value = value & 0xffff;
114         miim_write_cycle(etsec);
115         break;
116 
117     default:
118         /* Default handling */
119         switch (reg->access) {
120 
121         case ACC_RW:
122         case ACC_WO:
123             reg->value = value;
124             break;
125 
126         case ACC_W1C:
127             reg->value &= ~value;
128             break;
129 
130         case ACC_RO:
131         default:
132             /* Read Only or Unknown register */
133             break;
134         }
135     }
136 
137 }
138 
139 void etsec_miim_link_status(eTSEC *etsec, NetClientState *nc)
140 {
141     /* Set link status */
142     if (nc->link_down) {
143         etsec->phy_status &= ~MII_SR_LINK_STATUS;
144     } else {
145         etsec->phy_status |= MII_SR_LINK_STATUS;
146     }
147 }
148