xref: /qemu/hw/net/fsl_etsec/miim.c (revision f64766976d39fbf2b81a25b5c5f043180383d408)
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