1210284Sjmallett/***********************license start***************
2232812Sjmallett * Copyright (c) 2003-2010  Cavium Inc. (support@cavium.com). All rights
3215990Sjmallett * reserved.
4210284Sjmallett *
5210284Sjmallett *
6215990Sjmallett * Redistribution and use in source and binary forms, with or without
7215990Sjmallett * modification, are permitted provided that the following conditions are
8215990Sjmallett * met:
9210284Sjmallett *
10215990Sjmallett *   * Redistributions of source code must retain the above copyright
11215990Sjmallett *     notice, this list of conditions and the following disclaimer.
12210284Sjmallett *
13215990Sjmallett *   * Redistributions in binary form must reproduce the above
14215990Sjmallett *     copyright notice, this list of conditions and the following
15215990Sjmallett *     disclaimer in the documentation and/or other materials provided
16215990Sjmallett *     with the distribution.
17215990Sjmallett
18232812Sjmallett *   * Neither the name of Cavium Inc. nor the names of
19215990Sjmallett *     its contributors may be used to endorse or promote products
20215990Sjmallett *     derived from this software without specific prior written
21215990Sjmallett *     permission.
22215990Sjmallett
23215990Sjmallett * This Software, including technical data, may be subject to U.S. export  control
24215990Sjmallett * laws, including the U.S. Export Administration Act and its  associated
25215990Sjmallett * regulations, and may be subject to export or import  regulations in other
26215990Sjmallett * countries.
27215990Sjmallett
28215990Sjmallett * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
29232812Sjmallett * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR
30215990Sjmallett * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
31215990Sjmallett * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR
32215990Sjmallett * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM
33215990Sjmallett * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE,
34215990Sjmallett * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF
35215990Sjmallett * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
36215990Sjmallett * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE  RISK ARISING OUT OF USE OR
37215990Sjmallett * PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
38210284Sjmallett ***********************license end**************************************/
39210284Sjmallett
40210284Sjmallett
41210284Sjmallett
42210284Sjmallett
43210284Sjmallett
44210284Sjmallett
45215990Sjmallett
46210284Sjmallett/**
47210284Sjmallett * @file
48210284Sjmallett *
49210284Sjmallett * Interface to the SMI/MDIO hardware, including support for both IEEE 802.3
50210284Sjmallett * clause 22 and clause 45 operations.
51210284Sjmallett *
52232812Sjmallett * <hr>$Revision: 70030 $<hr>
53210284Sjmallett */
54210284Sjmallett
55210284Sjmallett#ifndef __CVMX_MIO_H__
56210284Sjmallett#define __CVMX_MIO_H__
57210284Sjmallett
58215990Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
59215990Sjmallett#include <asm/octeon/octeon.h>
60215990Sjmallett#include <asm/octeon/cvmx-clock.h>
61215990Sjmallett#else
62215990Sjmallett#include "cvmx-clock.h"
63215990Sjmallett#endif
64215990Sjmallett
65210284Sjmallett#ifdef	__cplusplus
66210284Sjmallettextern "C" {
67210284Sjmallett#endif
68210284Sjmallett
69210284Sjmallett/**
70210284Sjmallett * PHY register 0 from the 802.3 spec
71210284Sjmallett */
72210284Sjmallett#define CVMX_MDIO_PHY_REG_CONTROL 0
73210284Sjmalletttypedef union
74210284Sjmallett{
75210284Sjmallett    uint16_t u16;
76210284Sjmallett    struct
77210284Sjmallett    {
78210284Sjmallett        uint16_t reset : 1;
79210284Sjmallett        uint16_t loopback : 1;
80210284Sjmallett        uint16_t speed_lsb : 1;
81210284Sjmallett        uint16_t autoneg_enable : 1;
82210284Sjmallett        uint16_t power_down : 1;
83210284Sjmallett        uint16_t isolate : 1;
84210284Sjmallett        uint16_t restart_autoneg : 1;
85210284Sjmallett        uint16_t duplex : 1;
86210284Sjmallett        uint16_t collision_test : 1;
87210284Sjmallett        uint16_t speed_msb : 1;
88210284Sjmallett        uint16_t unidirectional_enable : 1;
89210284Sjmallett        uint16_t reserved_0_4 : 5;
90210284Sjmallett    } s;
91210284Sjmallett} cvmx_mdio_phy_reg_control_t;
92210284Sjmallett
93210284Sjmallett/**
94210284Sjmallett * PHY register 1 from the 802.3 spec
95210284Sjmallett */
96210284Sjmallett#define CVMX_MDIO_PHY_REG_STATUS 1
97210284Sjmalletttypedef union
98210284Sjmallett{
99210284Sjmallett    uint16_t u16;
100210284Sjmallett    struct
101210284Sjmallett    {
102210284Sjmallett        uint16_t capable_100base_t4 : 1;
103210284Sjmallett        uint16_t capable_100base_x_full : 1;
104210284Sjmallett        uint16_t capable_100base_x_half : 1;
105210284Sjmallett        uint16_t capable_10_full : 1;
106210284Sjmallett        uint16_t capable_10_half : 1;
107210284Sjmallett        uint16_t capable_100base_t2_full : 1;
108210284Sjmallett        uint16_t capable_100base_t2_half : 1;
109210284Sjmallett        uint16_t capable_extended_status : 1;
110210284Sjmallett        uint16_t capable_unidirectional : 1;
111210284Sjmallett        uint16_t capable_mf_preamble_suppression : 1;
112210284Sjmallett        uint16_t autoneg_complete : 1;
113210284Sjmallett        uint16_t remote_fault : 1;
114210284Sjmallett        uint16_t capable_autoneg : 1;
115210284Sjmallett        uint16_t link_status : 1;
116210284Sjmallett        uint16_t jabber_detect : 1;
117210284Sjmallett        uint16_t capable_extended_registers : 1;
118210284Sjmallett
119210284Sjmallett    } s;
120210284Sjmallett} cvmx_mdio_phy_reg_status_t;
121210284Sjmallett
122210284Sjmallett/**
123210284Sjmallett * PHY register 2 from the 802.3 spec
124210284Sjmallett */
125210284Sjmallett#define CVMX_MDIO_PHY_REG_ID1 2
126210284Sjmalletttypedef union
127210284Sjmallett{
128210284Sjmallett    uint16_t u16;
129210284Sjmallett    struct
130210284Sjmallett    {
131210284Sjmallett        uint16_t oui_bits_3_18;
132210284Sjmallett    } s;
133210284Sjmallett} cvmx_mdio_phy_reg_id1_t;
134210284Sjmallett
135210284Sjmallett/**
136210284Sjmallett * PHY register 3 from the 802.3 spec
137210284Sjmallett */
138210284Sjmallett#define CVMX_MDIO_PHY_REG_ID2 3
139210284Sjmalletttypedef union
140210284Sjmallett{
141210284Sjmallett    uint16_t u16;
142210284Sjmallett    struct
143210284Sjmallett    {
144210284Sjmallett        uint16_t oui_bits_19_24 : 6;
145210284Sjmallett        uint16_t model : 6;
146210284Sjmallett        uint16_t revision : 4;
147210284Sjmallett    } s;
148210284Sjmallett} cvmx_mdio_phy_reg_id2_t;
149210284Sjmallett
150210284Sjmallett/**
151210284Sjmallett * PHY register 4 from the 802.3 spec
152210284Sjmallett */
153210284Sjmallett#define CVMX_MDIO_PHY_REG_AUTONEG_ADVER 4
154210284Sjmalletttypedef union
155210284Sjmallett{
156210284Sjmallett    uint16_t u16;
157210284Sjmallett    struct
158210284Sjmallett    {
159210284Sjmallett        uint16_t next_page : 1;
160210284Sjmallett        uint16_t reserved_14 : 1;
161210284Sjmallett        uint16_t remote_fault : 1;
162210284Sjmallett        uint16_t reserved_12 : 1;
163210284Sjmallett        uint16_t asymmetric_pause : 1;
164210284Sjmallett        uint16_t pause : 1;
165210284Sjmallett        uint16_t advert_100base_t4 : 1;
166210284Sjmallett        uint16_t advert_100base_tx_full : 1;
167210284Sjmallett        uint16_t advert_100base_tx_half : 1;
168210284Sjmallett        uint16_t advert_10base_tx_full : 1;
169210284Sjmallett        uint16_t advert_10base_tx_half : 1;
170210284Sjmallett        uint16_t selector : 5;
171210284Sjmallett    } s;
172210284Sjmallett} cvmx_mdio_phy_reg_autoneg_adver_t;
173210284Sjmallett
174210284Sjmallett/**
175210284Sjmallett * PHY register 5 from the 802.3 spec
176210284Sjmallett */
177210284Sjmallett#define CVMX_MDIO_PHY_REG_LINK_PARTNER_ABILITY 5
178210284Sjmalletttypedef union
179210284Sjmallett{
180210284Sjmallett    uint16_t u16;
181210284Sjmallett    struct
182210284Sjmallett    {
183210284Sjmallett        uint16_t next_page : 1;
184210284Sjmallett        uint16_t ack : 1;
185210284Sjmallett        uint16_t remote_fault : 1;
186210284Sjmallett        uint16_t reserved_12 : 1;
187210284Sjmallett        uint16_t asymmetric_pause : 1;
188210284Sjmallett        uint16_t pause : 1;
189210284Sjmallett        uint16_t advert_100base_t4 : 1;
190210284Sjmallett        uint16_t advert_100base_tx_full : 1;
191210284Sjmallett        uint16_t advert_100base_tx_half : 1;
192210284Sjmallett        uint16_t advert_10base_tx_full : 1;
193210284Sjmallett        uint16_t advert_10base_tx_half : 1;
194210284Sjmallett        uint16_t selector : 5;
195210284Sjmallett    } s;
196210284Sjmallett} cvmx_mdio_phy_reg_link_partner_ability_t;
197210284Sjmallett
198210284Sjmallett/**
199210284Sjmallett * PHY register 6 from the 802.3 spec
200210284Sjmallett */
201210284Sjmallett#define CVMX_MDIO_PHY_REG_AUTONEG_EXPANSION 6
202210284Sjmalletttypedef union
203210284Sjmallett{
204210284Sjmallett    uint16_t u16;
205210284Sjmallett    struct
206210284Sjmallett    {
207210284Sjmallett        uint16_t reserved_5_15 : 11;
208210284Sjmallett        uint16_t parallel_detection_fault : 1;
209210284Sjmallett        uint16_t link_partner_next_page_capable : 1;
210210284Sjmallett        uint16_t local_next_page_capable : 1;
211210284Sjmallett        uint16_t page_received : 1;
212210284Sjmallett        uint16_t link_partner_autoneg_capable : 1;
213210284Sjmallett
214210284Sjmallett    } s;
215210284Sjmallett} cvmx_mdio_phy_reg_autoneg_expansion_t;
216210284Sjmallett
217210284Sjmallett/**
218210284Sjmallett * PHY register 9 from the 802.3 spec
219210284Sjmallett */
220210284Sjmallett#define CVMX_MDIO_PHY_REG_CONTROL_1000 9
221210284Sjmalletttypedef union
222210284Sjmallett{
223210284Sjmallett    uint16_t u16;
224210284Sjmallett    struct
225210284Sjmallett    {
226210284Sjmallett        uint16_t test_mode : 3;
227210284Sjmallett        uint16_t manual_master_slave : 1;
228210284Sjmallett        uint16_t master : 1;
229210284Sjmallett        uint16_t port_type : 1;
230210284Sjmallett        uint16_t advert_1000base_t_full : 1;
231210284Sjmallett        uint16_t advert_1000base_t_half : 1;
232210284Sjmallett        uint16_t reserved_0_7 : 8;
233210284Sjmallett    } s;
234210284Sjmallett} cvmx_mdio_phy_reg_control_1000_t;
235210284Sjmallett
236210284Sjmallett/**
237210284Sjmallett * PHY register 10 from the 802.3 spec
238210284Sjmallett */
239210284Sjmallett#define CVMX_MDIO_PHY_REG_STATUS_1000 10
240210284Sjmalletttypedef union
241210284Sjmallett{
242210284Sjmallett    uint16_t u16;
243210284Sjmallett    struct
244210284Sjmallett    {
245210284Sjmallett        uint16_t master_slave_fault : 1;
246210284Sjmallett        uint16_t is_master : 1;
247210284Sjmallett        uint16_t local_receiver_ok : 1;
248210284Sjmallett        uint16_t remote_receiver_ok : 1;
249210284Sjmallett        uint16_t remote_capable_1000base_t_full : 1;
250210284Sjmallett        uint16_t remote_capable_1000base_t_half : 1;
251210284Sjmallett        uint16_t reserved_8_9 : 2;
252210284Sjmallett        uint16_t idle_error_count : 8;
253210284Sjmallett    } s;
254210284Sjmallett} cvmx_mdio_phy_reg_status_1000_t;
255210284Sjmallett
256210284Sjmallett/**
257210284Sjmallett * PHY register 15 from the 802.3 spec
258210284Sjmallett */
259210284Sjmallett#define CVMX_MDIO_PHY_REG_EXTENDED_STATUS 15
260210284Sjmalletttypedef union
261210284Sjmallett{
262210284Sjmallett    uint16_t u16;
263210284Sjmallett    struct
264210284Sjmallett    {
265210284Sjmallett        uint16_t capable_1000base_x_full : 1;
266210284Sjmallett        uint16_t capable_1000base_x_half : 1;
267210284Sjmallett        uint16_t capable_1000base_t_full : 1;
268210284Sjmallett        uint16_t capable_1000base_t_half : 1;
269210284Sjmallett        uint16_t reserved_0_11 : 12;
270210284Sjmallett    } s;
271210284Sjmallett} cvmx_mdio_phy_reg_extended_status_t;
272210284Sjmallett
273210284Sjmallett
274210284Sjmallett/**
275210284Sjmallett * PHY register 13 from the 802.3 spec
276210284Sjmallett */
277210284Sjmallett#define CVMX_MDIO_PHY_REG_MMD_CONTROL 13
278210284Sjmalletttypedef union
279210284Sjmallett{
280210284Sjmallett    uint16_t u16;
281210284Sjmallett    struct
282210284Sjmallett    {
283210284Sjmallett        uint16_t function : 2;
284210284Sjmallett        uint16_t reserved_5_13 : 9;
285210284Sjmallett        uint16_t devad : 5;
286210284Sjmallett    } s;
287210284Sjmallett} cvmx_mdio_phy_reg_mmd_control_t;
288210284Sjmallett
289210284Sjmallett/**
290210284Sjmallett * PHY register 14 from the 802.3 spec
291210284Sjmallett */
292210284Sjmallett#define CVMX_MDIO_PHY_REG_MMD_ADDRESS_DATA 14
293210284Sjmalletttypedef union
294210284Sjmallett{
295210284Sjmallett    uint16_t u16;
296210284Sjmallett    struct
297210284Sjmallett    {
298210284Sjmallett        uint16_t address_data : 16;
299210284Sjmallett    } s;
300210284Sjmallett} cvmx_mdio_phy_reg_mmd_address_data_t;
301210284Sjmallett
302210284Sjmallett/* Operating request encodings. */
303210284Sjmallett#define MDIO_CLAUSE_22_WRITE    0
304210284Sjmallett#define MDIO_CLAUSE_22_READ     1
305210284Sjmallett
306210284Sjmallett#define MDIO_CLAUSE_45_ADDRESS  0
307210284Sjmallett#define MDIO_CLAUSE_45_WRITE    1
308210284Sjmallett#define MDIO_CLAUSE_45_READ_INC 2
309210284Sjmallett#define MDIO_CLAUSE_45_READ     3
310210284Sjmallett
311232812Sjmallett/* MMD identifiers, mostly for accessing devices within XENPAK modules. */
312210284Sjmallett#define CVMX_MMD_DEVICE_PMA_PMD      1
313210284Sjmallett#define CVMX_MMD_DEVICE_WIS          2
314210284Sjmallett#define CVMX_MMD_DEVICE_PCS          3
315210284Sjmallett#define CVMX_MMD_DEVICE_PHY_XS       4
316210284Sjmallett#define CVMX_MMD_DEVICE_DTS_XS       5
317210284Sjmallett#define CVMX_MMD_DEVICE_TC           6
318210284Sjmallett#define CVMX_MMD_DEVICE_CL22_EXT     29
319210284Sjmallett#define CVMX_MMD_DEVICE_VENDOR_1     30
320210284Sjmallett#define CVMX_MMD_DEVICE_VENDOR_2     31
321210284Sjmallett
322215990Sjmallett#define CVMX_MDIO_TIMEOUT   100000 /* 100 millisec */
323215990Sjmallett
324210284Sjmallett/* Helper function to put MDIO interface into clause 45 mode */
325210284Sjmallettstatic inline void __cvmx_mdio_set_clause45_mode(int bus_id)
326210284Sjmallett{
327210284Sjmallett    cvmx_smix_clk_t smi_clk;
328210284Sjmallett    /* Put bus into clause 45 mode */
329210284Sjmallett    smi_clk.u64 = cvmx_read_csr(CVMX_SMIX_CLK(bus_id));
330210284Sjmallett    smi_clk.s.mode = 1;
331210284Sjmallett    smi_clk.s.preamble = 1;
332210284Sjmallett    cvmx_write_csr(CVMX_SMIX_CLK(bus_id), smi_clk.u64);
333210284Sjmallett}
334210284Sjmallett/* Helper function to put MDIO interface into clause 22 mode */
335210284Sjmallettstatic inline void __cvmx_mdio_set_clause22_mode(int bus_id)
336210284Sjmallett{
337210284Sjmallett    cvmx_smix_clk_t smi_clk;
338210284Sjmallett    /* Put bus into clause 22 mode */
339210284Sjmallett    smi_clk.u64 = cvmx_read_csr(CVMX_SMIX_CLK(bus_id));
340210284Sjmallett    smi_clk.s.mode = 0;
341210284Sjmallett    cvmx_write_csr(CVMX_SMIX_CLK(bus_id), smi_clk.u64);
342210284Sjmallett}
343210284Sjmallett
344210284Sjmallett/**
345215990Sjmallett * @INTERNAL
346215990Sjmallett * Function to read SMIX_RD_DAT and check for timeouts. This
347215990Sjmallett * code sequence is done fairly often, so put in in one spot.
348215990Sjmallett *
349215990Sjmallett * @param bus_id SMI/MDIO bus to read
350215990Sjmallett *
351215990Sjmallett * @return Value of SMIX_RD_DAT. pending will be set on
352215990Sjmallett *         a timeout.
353215990Sjmallett */
354215990Sjmallettstatic inline cvmx_smix_rd_dat_t __cvmx_mdio_read_rd_dat(int bus_id)
355215990Sjmallett{
356215990Sjmallett    cvmx_smix_rd_dat_t smi_rd;
357215990Sjmallett    uint64_t done = cvmx_get_cycle() + (uint64_t)CVMX_MDIO_TIMEOUT *
358215990Sjmallett                       cvmx_clock_get_rate(CVMX_CLOCK_CORE) / 1000000;
359215990Sjmallett    do
360215990Sjmallett    {
361215990Sjmallett        cvmx_wait(1000);
362215990Sjmallett        smi_rd.u64 = cvmx_read_csr(CVMX_SMIX_RD_DAT(bus_id));
363215990Sjmallett    } while (smi_rd.s.pending && (cvmx_get_cycle() < done));
364215990Sjmallett    return smi_rd;
365215990Sjmallett}
366215990Sjmallett
367215990Sjmallett
368215990Sjmallett/**
369210284Sjmallett * Perform an MII read. This function is used to read PHY
370210284Sjmallett * registers controlling auto negotiation.
371210284Sjmallett *
372210284Sjmallett * @param bus_id   MDIO bus number. Zero on most chips, but some chips (ex CN56XX)
373210284Sjmallett *                 support multiple busses.
374210284Sjmallett * @param phy_id   The MII phy id
375210284Sjmallett * @param location Register location to read
376210284Sjmallett *
377210284Sjmallett * @return Result from the read or -1 on failure
378210284Sjmallett */
379210284Sjmallettstatic inline int cvmx_mdio_read(int bus_id, int phy_id, int location)
380210284Sjmallett{
381215990Sjmallett#if defined(CVMX_BUILD_FOR_LINUX_KERNEL) && defined(CONFIG_PHYLIB)
382215990Sjmallett	struct mii_bus *bus;
383215990Sjmallett	int rv;
384215990Sjmallett
385232812Sjmallett	BUG_ON(bus_id > 3 || bus_id < 0);
386215990Sjmallett
387215990Sjmallett	bus = octeon_mdiobuses[bus_id];
388215990Sjmallett	if (bus == NULL)
389215990Sjmallett		return -1;
390215990Sjmallett
391215990Sjmallett	rv = mdiobus_read(bus, phy_id, location);
392215990Sjmallett
393215990Sjmallett	if (rv < 0)
394215990Sjmallett		return -1;
395215990Sjmallett	return rv;
396215990Sjmallett#else
397210284Sjmallett    cvmx_smix_cmd_t smi_cmd;
398210284Sjmallett    cvmx_smix_rd_dat_t smi_rd;
399210284Sjmallett
400210284Sjmallett    if (octeon_has_feature(OCTEON_FEATURE_MDIO_CLAUSE_45))
401210284Sjmallett        __cvmx_mdio_set_clause22_mode(bus_id);
402210284Sjmallett
403210284Sjmallett    smi_cmd.u64 = 0;
404210284Sjmallett    smi_cmd.s.phy_op = MDIO_CLAUSE_22_READ;
405210284Sjmallett    smi_cmd.s.phy_adr = phy_id;
406210284Sjmallett    smi_cmd.s.reg_adr = location;
407210284Sjmallett    cvmx_write_csr(CVMX_SMIX_CMD(bus_id), smi_cmd.u64);
408210284Sjmallett
409215990Sjmallett    smi_rd = __cvmx_mdio_read_rd_dat(bus_id);
410210284Sjmallett    if (smi_rd.s.val)
411210284Sjmallett        return smi_rd.s.dat;
412210284Sjmallett    else
413210284Sjmallett        return -1;
414215990Sjmallett#endif
415210284Sjmallett}
416210284Sjmallett
417210284Sjmallett
418210284Sjmallett/**
419210284Sjmallett * Perform an MII write. This function is used to write PHY
420210284Sjmallett * registers controlling auto negotiation.
421210284Sjmallett *
422210284Sjmallett * @param bus_id   MDIO bus number. Zero on most chips, but some chips (ex CN56XX)
423210284Sjmallett *                 support multiple busses.
424210284Sjmallett * @param phy_id   The MII phy id
425210284Sjmallett * @param location Register location to write
426210284Sjmallett * @param val      Value to write
427210284Sjmallett *
428210284Sjmallett * @return -1 on error
429210284Sjmallett *         0 on success
430210284Sjmallett */
431210284Sjmallettstatic inline int cvmx_mdio_write(int bus_id, int phy_id, int location, int val)
432210284Sjmallett{
433215990Sjmallett#if defined(CVMX_BUILD_FOR_LINUX_KERNEL) && defined(CONFIG_PHYLIB)
434215990Sjmallett	struct mii_bus *bus;
435215990Sjmallett	int rv;
436215990Sjmallett
437232812Sjmallett	BUG_ON(bus_id > 3 || bus_id < 0);
438215990Sjmallett
439215990Sjmallett	bus = octeon_mdiobuses[bus_id];
440215990Sjmallett	if (bus == NULL)
441215990Sjmallett		return -1;
442215990Sjmallett
443215990Sjmallett	rv = mdiobus_write(bus, phy_id, location, (u16)val);
444215990Sjmallett
445215990Sjmallett	if (rv < 0)
446215990Sjmallett		return -1;
447215990Sjmallett	return 0;
448215990Sjmallett#else
449215990Sjmallett     cvmx_smix_cmd_t smi_cmd;
450210284Sjmallett    cvmx_smix_wr_dat_t smi_wr;
451210284Sjmallett
452210284Sjmallett    if (octeon_has_feature(OCTEON_FEATURE_MDIO_CLAUSE_45))
453210284Sjmallett        __cvmx_mdio_set_clause22_mode(bus_id);
454210284Sjmallett
455210284Sjmallett    smi_wr.u64 = 0;
456210284Sjmallett    smi_wr.s.dat = val;
457210284Sjmallett    cvmx_write_csr(CVMX_SMIX_WR_DAT(bus_id), smi_wr.u64);
458210284Sjmallett
459210284Sjmallett    smi_cmd.u64 = 0;
460210284Sjmallett    smi_cmd.s.phy_op = MDIO_CLAUSE_22_WRITE;
461210284Sjmallett    smi_cmd.s.phy_adr = phy_id;
462210284Sjmallett    smi_cmd.s.reg_adr = location;
463210284Sjmallett    cvmx_write_csr(CVMX_SMIX_CMD(bus_id), smi_cmd.u64);
464210284Sjmallett
465215990Sjmallett    if (CVMX_WAIT_FOR_FIELD64(CVMX_SMIX_WR_DAT(bus_id),
466215990Sjmallett        cvmx_smix_wr_dat_t, pending, ==, 0, CVMX_MDIO_TIMEOUT))
467210284Sjmallett        return -1;
468210284Sjmallett
469210284Sjmallett    return 0;
470215990Sjmallett#endif
471210284Sjmallett}
472210284Sjmallett
473215990Sjmallett#ifndef CVMX_BUILD_FOR_LINUX_KERNEL
474210284Sjmallett/**
475210284Sjmallett * Perform an IEEE 802.3 clause 45 MII read. This function is used to read PHY
476210284Sjmallett * registers controlling auto negotiation.
477210284Sjmallett *
478210284Sjmallett * @param bus_id   MDIO bus number. Zero on most chips, but some chips (ex CN56XX)
479210284Sjmallett *                 support multiple busses.
480210284Sjmallett * @param phy_id   The MII phy id
481210284Sjmallett * @param device   MDIO Managable Device (MMD) id
482210284Sjmallett * @param location Register location to read
483210284Sjmallett *
484210284Sjmallett * @return Result from the read or -1 on failure
485210284Sjmallett */
486210284Sjmallett
487210284Sjmallettstatic inline int cvmx_mdio_45_read(int bus_id, int phy_id, int device, int location)
488210284Sjmallett{
489210284Sjmallett    cvmx_smix_cmd_t smi_cmd;
490210284Sjmallett    cvmx_smix_rd_dat_t smi_rd;
491210284Sjmallett    cvmx_smix_wr_dat_t smi_wr;
492210284Sjmallett
493210284Sjmallett    if (!octeon_has_feature(OCTEON_FEATURE_MDIO_CLAUSE_45))
494210284Sjmallett        return -1;
495210284Sjmallett
496210284Sjmallett    __cvmx_mdio_set_clause45_mode(bus_id);
497210284Sjmallett
498210284Sjmallett    smi_wr.u64 = 0;
499210284Sjmallett    smi_wr.s.dat = location;
500210284Sjmallett    cvmx_write_csr(CVMX_SMIX_WR_DAT(bus_id), smi_wr.u64);
501210284Sjmallett
502210284Sjmallett    smi_cmd.u64 = 0;
503210284Sjmallett    smi_cmd.s.phy_op = MDIO_CLAUSE_45_ADDRESS;
504210284Sjmallett    smi_cmd.s.phy_adr = phy_id;
505210284Sjmallett    smi_cmd.s.reg_adr = device;
506210284Sjmallett    cvmx_write_csr(CVMX_SMIX_CMD(bus_id), smi_cmd.u64);
507210284Sjmallett
508215990Sjmallett    if (CVMX_WAIT_FOR_FIELD64(CVMX_SMIX_WR_DAT(bus_id),
509215990Sjmallett        cvmx_smix_wr_dat_t, pending, ==, 0, CVMX_MDIO_TIMEOUT))
510210284Sjmallett    {
511210284Sjmallett        cvmx_dprintf ("cvmx_mdio_45_read: bus_id %d phy_id %2d device %2d register %2d   TIME OUT(address)\n", bus_id, phy_id, device, location);
512210284Sjmallett        return -1;
513210284Sjmallett    }
514210284Sjmallett
515210284Sjmallett    smi_cmd.u64 = 0;
516210284Sjmallett    smi_cmd.s.phy_op = MDIO_CLAUSE_45_READ;
517210284Sjmallett    smi_cmd.s.phy_adr = phy_id;
518210284Sjmallett    smi_cmd.s.reg_adr = device;
519210284Sjmallett    cvmx_write_csr(CVMX_SMIX_CMD(bus_id), smi_cmd.u64);
520210284Sjmallett
521215990Sjmallett    smi_rd = __cvmx_mdio_read_rd_dat(bus_id);
522215990Sjmallett    if (smi_rd.s.pending)
523210284Sjmallett    {
524210284Sjmallett        cvmx_dprintf ("cvmx_mdio_45_read: bus_id %d phy_id %2d device %2d register %2d   TIME OUT(data)\n", bus_id, phy_id, device, location);
525210284Sjmallett        return -1;
526210284Sjmallett    }
527210284Sjmallett
528210284Sjmallett    if (smi_rd.s.val)
529210284Sjmallett        return smi_rd.s.dat;
530210284Sjmallett    else
531210284Sjmallett    {
532210284Sjmallett        cvmx_dprintf ("cvmx_mdio_45_read: bus_id %d phy_id %2d device %2d register %2d   INVALID READ\n", bus_id, phy_id, device, location);
533210284Sjmallett        return -1;
534210284Sjmallett    }
535210284Sjmallett}
536210284Sjmallett
537210284Sjmallett/**
538210284Sjmallett * Perform an IEEE 802.3 clause 45 MII write. This function is used to write PHY
539210284Sjmallett * registers controlling auto negotiation.
540210284Sjmallett *
541210284Sjmallett * @param bus_id   MDIO bus number. Zero on most chips, but some chips (ex CN56XX)
542210284Sjmallett *                 support multiple busses.
543210284Sjmallett * @param phy_id   The MII phy id
544210284Sjmallett * @param device   MDIO Managable Device (MMD) id
545210284Sjmallett * @param location Register location to write
546210284Sjmallett * @param val      Value to write
547210284Sjmallett *
548210284Sjmallett * @return -1 on error
549210284Sjmallett *         0 on success
550210284Sjmallett */
551210284Sjmallettstatic inline int cvmx_mdio_45_write(int bus_id, int phy_id, int device, int location,
552210284Sjmallett                                     int val)
553210284Sjmallett{
554210284Sjmallett    cvmx_smix_cmd_t smi_cmd;
555210284Sjmallett    cvmx_smix_wr_dat_t smi_wr;
556210284Sjmallett
557210284Sjmallett    if (!octeon_has_feature(OCTEON_FEATURE_MDIO_CLAUSE_45))
558210284Sjmallett        return -1;
559210284Sjmallett
560210284Sjmallett    __cvmx_mdio_set_clause45_mode(bus_id);
561210284Sjmallett
562210284Sjmallett    smi_wr.u64 = 0;
563210284Sjmallett    smi_wr.s.dat = location;
564210284Sjmallett    cvmx_write_csr(CVMX_SMIX_WR_DAT(bus_id), smi_wr.u64);
565210284Sjmallett
566210284Sjmallett    smi_cmd.u64 = 0;
567210284Sjmallett    smi_cmd.s.phy_op = MDIO_CLAUSE_45_ADDRESS;
568210284Sjmallett    smi_cmd.s.phy_adr = phy_id;
569210284Sjmallett    smi_cmd.s.reg_adr = device;
570210284Sjmallett    cvmx_write_csr(CVMX_SMIX_CMD(bus_id), smi_cmd.u64);
571210284Sjmallett
572215990Sjmallett    if (CVMX_WAIT_FOR_FIELD64(CVMX_SMIX_WR_DAT(bus_id),
573215990Sjmallett        cvmx_smix_wr_dat_t, pending, ==, 0, CVMX_MDIO_TIMEOUT))
574210284Sjmallett        return -1;
575210284Sjmallett
576210284Sjmallett    smi_wr.u64 = 0;
577210284Sjmallett    smi_wr.s.dat = val;
578210284Sjmallett    cvmx_write_csr(CVMX_SMIX_WR_DAT(bus_id), smi_wr.u64);
579210284Sjmallett
580210284Sjmallett    smi_cmd.u64 = 0;
581210284Sjmallett    smi_cmd.s.phy_op = MDIO_CLAUSE_45_WRITE;
582210284Sjmallett    smi_cmd.s.phy_adr = phy_id;
583210284Sjmallett    smi_cmd.s.reg_adr = device;
584210284Sjmallett    cvmx_write_csr(CVMX_SMIX_CMD(bus_id), smi_cmd.u64);
585210284Sjmallett
586215990Sjmallett    if (CVMX_WAIT_FOR_FIELD64(CVMX_SMIX_WR_DAT(bus_id),
587215990Sjmallett        cvmx_smix_wr_dat_t, pending, ==, 0, CVMX_MDIO_TIMEOUT))
588210284Sjmallett        return -1;
589210284Sjmallett
590210284Sjmallett    return 0;
591210284Sjmallett}
592215990Sjmallett#endif
593210284Sjmallett
594210284Sjmallett#ifdef	__cplusplus
595210284Sjmallett}
596210284Sjmallett#endif
597210284Sjmallett
598210284Sjmallett#endif
599210284Sjmallett
600