]> Git Repo - linux.git/blob - drivers/net/dsa/mv88e6xxx/smi.c
x86/kaslr: Expose and use the end of the physical memory address space
[linux.git] / drivers / net / dsa / mv88e6xxx / smi.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Marvell 88E6xxx System Management Interface (SMI) support
4  *
5  * Copyright (c) 2008 Marvell Semiconductor
6  *
7  * Copyright (c) 2019 Vivien Didelot <[email protected]>
8  */
9
10 #include "chip.h"
11 #include "smi.h"
12
13 /* The switch ADDR[4:1] configuration pins define the chip SMI device address
14  * (ADDR[0] is always zero, thus only even SMI addresses can be strapped).
15  *
16  * When ADDR is all zero, the chip uses Single-chip Addressing Mode, assuming it
17  * is the only device connected to the SMI master. In this mode it responds to
18  * all 32 possible SMI addresses, and thus maps directly the internal devices.
19  *
20  * When ADDR is non-zero, the chip uses Multi-chip Addressing Mode, allowing
21  * multiple devices to share the SMI interface. In this mode it responds to only
22  * 2 registers, used to indirectly access the internal SMI devices.
23  *
24  * Some chips use a different scheme: Only the ADDR4 pin is used for
25  * configuration, and the device responds to 16 of the 32 SMI
26  * addresses, allowing two to coexist on the same SMI interface.
27  */
28
29 static int mv88e6xxx_smi_direct_read(struct mv88e6xxx_chip *chip,
30                                      int dev, int reg, u16 *data)
31 {
32         int ret;
33
34         ret = mdiobus_read_nested(chip->bus, dev, reg);
35         if (ret < 0)
36                 return ret;
37
38         *data = ret & 0xffff;
39
40         return 0;
41 }
42
43 static int mv88e6xxx_smi_direct_write(struct mv88e6xxx_chip *chip,
44                                       int dev, int reg, u16 data)
45 {
46         int ret;
47
48         ret = mdiobus_write_nested(chip->bus, dev, reg, data);
49         if (ret < 0)
50                 return ret;
51
52         return 0;
53 }
54
55 static int mv88e6xxx_smi_direct_wait(struct mv88e6xxx_chip *chip,
56                                      int dev, int reg, int bit, int val)
57 {
58         const unsigned long timeout = jiffies + msecs_to_jiffies(50);
59         u16 data;
60         int err;
61         int i;
62
63         /* Even if the initial poll takes longer than 50ms, always do
64          * at least one more attempt.
65          */
66         for (i = 0; time_before(jiffies, timeout) || (i < 2); i++) {
67                 err = mv88e6xxx_smi_direct_read(chip, dev, reg, &data);
68                 if (err)
69                         return err;
70
71                 if (!!(data & BIT(bit)) == !!val)
72                         return 0;
73
74                 if (i < 2)
75                         cpu_relax();
76                 else
77                         usleep_range(1000, 2000);
78         }
79
80         return -ETIMEDOUT;
81 }
82
83 static const struct mv88e6xxx_bus_ops mv88e6xxx_smi_direct_ops = {
84         .read = mv88e6xxx_smi_direct_read,
85         .write = mv88e6xxx_smi_direct_write,
86 };
87
88 static int mv88e6xxx_smi_dual_direct_read(struct mv88e6xxx_chip *chip,
89                                           int dev, int reg, u16 *data)
90 {
91         return mv88e6xxx_smi_direct_read(chip, chip->sw_addr + dev, reg, data);
92 }
93
94 static int mv88e6xxx_smi_dual_direct_write(struct mv88e6xxx_chip *chip,
95                                            int dev, int reg, u16 data)
96 {
97         return mv88e6xxx_smi_direct_write(chip, chip->sw_addr + dev, reg, data);
98 }
99
100 static const struct mv88e6xxx_bus_ops mv88e6xxx_smi_dual_direct_ops = {
101         .read = mv88e6xxx_smi_dual_direct_read,
102         .write = mv88e6xxx_smi_dual_direct_write,
103 };
104
105 /* Offset 0x00: SMI Command Register
106  * Offset 0x01: SMI Data Register
107  */
108
109 static int mv88e6xxx_smi_indirect_read(struct mv88e6xxx_chip *chip,
110                                        int dev, int reg, u16 *data)
111 {
112         int err;
113
114         err = mv88e6xxx_smi_direct_write(chip, chip->sw_addr,
115                                          MV88E6XXX_SMI_CMD,
116                                          MV88E6XXX_SMI_CMD_BUSY |
117                                          MV88E6XXX_SMI_CMD_MODE_22 |
118                                          MV88E6XXX_SMI_CMD_OP_22_READ |
119                                          (dev << 5) | reg);
120         if (err)
121                 return err;
122
123         err = mv88e6xxx_smi_direct_wait(chip, chip->sw_addr,
124                                         MV88E6XXX_SMI_CMD, 15, 0);
125         if (err)
126                 return err;
127
128         return mv88e6xxx_smi_direct_read(chip, chip->sw_addr,
129                                          MV88E6XXX_SMI_DATA, data);
130 }
131
132 static int mv88e6xxx_smi_indirect_write(struct mv88e6xxx_chip *chip,
133                                         int dev, int reg, u16 data)
134 {
135         int err;
136
137         err = mv88e6xxx_smi_direct_write(chip, chip->sw_addr,
138                                          MV88E6XXX_SMI_DATA, data);
139         if (err)
140                 return err;
141
142         err = mv88e6xxx_smi_direct_write(chip, chip->sw_addr,
143                                          MV88E6XXX_SMI_CMD,
144                                          MV88E6XXX_SMI_CMD_BUSY |
145                                          MV88E6XXX_SMI_CMD_MODE_22 |
146                                          MV88E6XXX_SMI_CMD_OP_22_WRITE |
147                                          (dev << 5) | reg);
148         if (err)
149                 return err;
150
151         return mv88e6xxx_smi_direct_wait(chip, chip->sw_addr,
152                                          MV88E6XXX_SMI_CMD, 15, 0);
153 }
154
155 static int mv88e6xxx_smi_indirect_init(struct mv88e6xxx_chip *chip)
156 {
157         /* Ensure that the chip starts out in the ready state. As both
158          * reads and writes always ensure this on return, they can
159          * safely depend on the chip not being busy on entry.
160          */
161         return mv88e6xxx_smi_direct_wait(chip, chip->sw_addr,
162                                          MV88E6XXX_SMI_CMD, 15, 0);
163 }
164
165 static const struct mv88e6xxx_bus_ops mv88e6xxx_smi_indirect_ops = {
166         .read = mv88e6xxx_smi_indirect_read,
167         .write = mv88e6xxx_smi_indirect_write,
168         .init = mv88e6xxx_smi_indirect_init,
169 };
170
171 int mv88e6xxx_smi_init(struct mv88e6xxx_chip *chip,
172                        struct mii_bus *bus, int sw_addr)
173 {
174         if (chip->info->dual_chip)
175                 chip->smi_ops = &mv88e6xxx_smi_dual_direct_ops;
176         else if (sw_addr == 0)
177                 chip->smi_ops = &mv88e6xxx_smi_direct_ops;
178         else if (chip->info->multi_chip)
179                 chip->smi_ops = &mv88e6xxx_smi_indirect_ops;
180         else
181                 return -EINVAL;
182
183         chip->bus = bus;
184         chip->sw_addr = sw_addr;
185
186         if (chip->smi_ops->init)
187                 return chip->smi_ops->init(chip);
188
189         return 0;
190 }
This page took 0.045386 seconds and 4 git commands to generate.