1/***********************license start***************
2 * Copyright (c) 2003-2010  Cavium Inc. (support@cavium.com). All rights
3 * reserved.
4 *
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 *   * Redistributions of source code must retain the above copyright
11 *     notice, this list of conditions and the following disclaimer.
12 *
13 *   * Redistributions in binary form must reproduce the above
14 *     copyright notice, this list of conditions and the following
15 *     disclaimer in the documentation and/or other materials provided
16 *     with the distribution.
17
18 *   * Neither the name of Cavium Inc. nor the names of
19 *     its contributors may be used to endorse or promote products
20 *     derived from this software without specific prior written
21 *     permission.
22
23 * This Software, including technical data, may be subject to U.S. export  control
24 * laws, including the U.S. Export Administration Act and its  associated
25 * regulations, and may be subject to export or import  regulations in other
26 * countries.
27
28 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
29 * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR
30 * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
31 * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR
32 * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM
33 * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE,
34 * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF
35 * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
36 * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE  RISK ARISING OUT OF USE OR
37 * PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
38 ***********************license end**************************************/
39
40
41
42
43
44
45
46/**
47 * @file
48 *
49 * Interface to the SMI/MDIO hardware, including support for both IEEE 802.3
50 * clause 22 and clause 45 operations.
51 *
52 * <hr>$Revision: 70030 $<hr>
53 */
54
55#ifndef __CVMX_MIO_H__
56#define __CVMX_MIO_H__
57
58#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
59#include <asm/octeon/octeon.h>
60#include <asm/octeon/cvmx-clock.h>
61#else
62#include "cvmx-clock.h"
63#endif
64
65#ifdef	__cplusplus
66extern "C" {
67#endif
68
69/**
70 * PHY register 0 from the 802.3 spec
71 */
72#define CVMX_MDIO_PHY_REG_CONTROL 0
73typedef union
74{
75    uint16_t u16;
76    struct
77    {
78        uint16_t reset : 1;
79        uint16_t loopback : 1;
80        uint16_t speed_lsb : 1;
81        uint16_t autoneg_enable : 1;
82        uint16_t power_down : 1;
83        uint16_t isolate : 1;
84        uint16_t restart_autoneg : 1;
85        uint16_t duplex : 1;
86        uint16_t collision_test : 1;
87        uint16_t speed_msb : 1;
88        uint16_t unidirectional_enable : 1;
89        uint16_t reserved_0_4 : 5;
90    } s;
91} cvmx_mdio_phy_reg_control_t;
92
93/**
94 * PHY register 1 from the 802.3 spec
95 */
96#define CVMX_MDIO_PHY_REG_STATUS 1
97typedef union
98{
99    uint16_t u16;
100    struct
101    {
102        uint16_t capable_100base_t4 : 1;
103        uint16_t capable_100base_x_full : 1;
104        uint16_t capable_100base_x_half : 1;
105        uint16_t capable_10_full : 1;
106        uint16_t capable_10_half : 1;
107        uint16_t capable_100base_t2_full : 1;
108        uint16_t capable_100base_t2_half : 1;
109        uint16_t capable_extended_status : 1;
110        uint16_t capable_unidirectional : 1;
111        uint16_t capable_mf_preamble_suppression : 1;
112        uint16_t autoneg_complete : 1;
113        uint16_t remote_fault : 1;
114        uint16_t capable_autoneg : 1;
115        uint16_t link_status : 1;
116        uint16_t jabber_detect : 1;
117        uint16_t capable_extended_registers : 1;
118
119    } s;
120} cvmx_mdio_phy_reg_status_t;
121
122/**
123 * PHY register 2 from the 802.3 spec
124 */
125#define CVMX_MDIO_PHY_REG_ID1 2
126typedef union
127{
128    uint16_t u16;
129    struct
130    {
131        uint16_t oui_bits_3_18;
132    } s;
133} cvmx_mdio_phy_reg_id1_t;
134
135/**
136 * PHY register 3 from the 802.3 spec
137 */
138#define CVMX_MDIO_PHY_REG_ID2 3
139typedef union
140{
141    uint16_t u16;
142    struct
143    {
144        uint16_t oui_bits_19_24 : 6;
145        uint16_t model : 6;
146        uint16_t revision : 4;
147    } s;
148} cvmx_mdio_phy_reg_id2_t;
149
150/**
151 * PHY register 4 from the 802.3 spec
152 */
153#define CVMX_MDIO_PHY_REG_AUTONEG_ADVER 4
154typedef union
155{
156    uint16_t u16;
157    struct
158    {
159        uint16_t next_page : 1;
160        uint16_t reserved_14 : 1;
161        uint16_t remote_fault : 1;
162        uint16_t reserved_12 : 1;
163        uint16_t asymmetric_pause : 1;
164        uint16_t pause : 1;
165        uint16_t advert_100base_t4 : 1;
166        uint16_t advert_100base_tx_full : 1;
167        uint16_t advert_100base_tx_half : 1;
168        uint16_t advert_10base_tx_full : 1;
169        uint16_t advert_10base_tx_half : 1;
170        uint16_t selector : 5;
171    } s;
172} cvmx_mdio_phy_reg_autoneg_adver_t;
173
174/**
175 * PHY register 5 from the 802.3 spec
176 */
177#define CVMX_MDIO_PHY_REG_LINK_PARTNER_ABILITY 5
178typedef union
179{
180    uint16_t u16;
181    struct
182    {
183        uint16_t next_page : 1;
184        uint16_t ack : 1;
185        uint16_t remote_fault : 1;
186        uint16_t reserved_12 : 1;
187        uint16_t asymmetric_pause : 1;
188        uint16_t pause : 1;
189        uint16_t advert_100base_t4 : 1;
190        uint16_t advert_100base_tx_full : 1;
191        uint16_t advert_100base_tx_half : 1;
192        uint16_t advert_10base_tx_full : 1;
193        uint16_t advert_10base_tx_half : 1;
194        uint16_t selector : 5;
195    } s;
196} cvmx_mdio_phy_reg_link_partner_ability_t;
197
198/**
199 * PHY register 6 from the 802.3 spec
200 */
201#define CVMX_MDIO_PHY_REG_AUTONEG_EXPANSION 6
202typedef union
203{
204    uint16_t u16;
205    struct
206    {
207        uint16_t reserved_5_15 : 11;
208        uint16_t parallel_detection_fault : 1;
209        uint16_t link_partner_next_page_capable : 1;
210        uint16_t local_next_page_capable : 1;
211        uint16_t page_received : 1;
212        uint16_t link_partner_autoneg_capable : 1;
213
214    } s;
215} cvmx_mdio_phy_reg_autoneg_expansion_t;
216
217/**
218 * PHY register 9 from the 802.3 spec
219 */
220#define CVMX_MDIO_PHY_REG_CONTROL_1000 9
221typedef union
222{
223    uint16_t u16;
224    struct
225    {
226        uint16_t test_mode : 3;
227        uint16_t manual_master_slave : 1;
228        uint16_t master : 1;
229        uint16_t port_type : 1;
230        uint16_t advert_1000base_t_full : 1;
231        uint16_t advert_1000base_t_half : 1;
232        uint16_t reserved_0_7 : 8;
233    } s;
234} cvmx_mdio_phy_reg_control_1000_t;
235
236/**
237 * PHY register 10 from the 802.3 spec
238 */
239#define CVMX_MDIO_PHY_REG_STATUS_1000 10
240typedef union
241{
242    uint16_t u16;
243    struct
244    {
245        uint16_t master_slave_fault : 1;
246        uint16_t is_master : 1;
247        uint16_t local_receiver_ok : 1;
248        uint16_t remote_receiver_ok : 1;
249        uint16_t remote_capable_1000base_t_full : 1;
250        uint16_t remote_capable_1000base_t_half : 1;
251        uint16_t reserved_8_9 : 2;
252        uint16_t idle_error_count : 8;
253    } s;
254} cvmx_mdio_phy_reg_status_1000_t;
255
256/**
257 * PHY register 15 from the 802.3 spec
258 */
259#define CVMX_MDIO_PHY_REG_EXTENDED_STATUS 15
260typedef union
261{
262    uint16_t u16;
263    struct
264    {
265        uint16_t capable_1000base_x_full : 1;
266        uint16_t capable_1000base_x_half : 1;
267        uint16_t capable_1000base_t_full : 1;
268        uint16_t capable_1000base_t_half : 1;
269        uint16_t reserved_0_11 : 12;
270    } s;
271} cvmx_mdio_phy_reg_extended_status_t;
272
273
274/**
275 * PHY register 13 from the 802.3 spec
276 */
277#define CVMX_MDIO_PHY_REG_MMD_CONTROL 13
278typedef union
279{
280    uint16_t u16;
281    struct
282    {
283        uint16_t function : 2;
284        uint16_t reserved_5_13 : 9;
285        uint16_t devad : 5;
286    } s;
287} cvmx_mdio_phy_reg_mmd_control_t;
288
289/**
290 * PHY register 14 from the 802.3 spec
291 */
292#define CVMX_MDIO_PHY_REG_MMD_ADDRESS_DATA 14
293typedef union
294{
295    uint16_t u16;
296    struct
297    {
298        uint16_t address_data : 16;
299    } s;
300} cvmx_mdio_phy_reg_mmd_address_data_t;
301
302/* Operating request encodings. */
303#define MDIO_CLAUSE_22_WRITE    0
304#define MDIO_CLAUSE_22_READ     1
305
306#define MDIO_CLAUSE_45_ADDRESS  0
307#define MDIO_CLAUSE_45_WRITE    1
308#define MDIO_CLAUSE_45_READ_INC 2
309#define MDIO_CLAUSE_45_READ     3
310
311/* MMD identifiers, mostly for accessing devices within XENPAK modules. */
312#define CVMX_MMD_DEVICE_PMA_PMD      1
313#define CVMX_MMD_DEVICE_WIS          2
314#define CVMX_MMD_DEVICE_PCS          3
315#define CVMX_MMD_DEVICE_PHY_XS       4
316#define CVMX_MMD_DEVICE_DTS_XS       5
317#define CVMX_MMD_DEVICE_TC           6
318#define CVMX_MMD_DEVICE_CL22_EXT     29
319#define CVMX_MMD_DEVICE_VENDOR_1     30
320#define CVMX_MMD_DEVICE_VENDOR_2     31
321
322#define CVMX_MDIO_TIMEOUT   100000 /* 100 millisec */
323
324/* Helper function to put MDIO interface into clause 45 mode */
325static inline void __cvmx_mdio_set_clause45_mode(int bus_id)
326{
327    cvmx_smix_clk_t smi_clk;
328    /* Put bus into clause 45 mode */
329    smi_clk.u64 = cvmx_read_csr(CVMX_SMIX_CLK(bus_id));
330    smi_clk.s.mode = 1;
331    smi_clk.s.preamble = 1;
332    cvmx_write_csr(CVMX_SMIX_CLK(bus_id), smi_clk.u64);
333}
334/* Helper function to put MDIO interface into clause 22 mode */
335static inline void __cvmx_mdio_set_clause22_mode(int bus_id)
336{
337    cvmx_smix_clk_t smi_clk;
338    /* Put bus into clause 22 mode */
339    smi_clk.u64 = cvmx_read_csr(CVMX_SMIX_CLK(bus_id));
340    smi_clk.s.mode = 0;
341    cvmx_write_csr(CVMX_SMIX_CLK(bus_id), smi_clk.u64);
342}
343
344/**
345 * @INTERNAL
346 * Function to read SMIX_RD_DAT and check for timeouts. This
347 * code sequence is done fairly often, so put in in one spot.
348 *
349 * @param bus_id SMI/MDIO bus to read
350 *
351 * @return Value of SMIX_RD_DAT. pending will be set on
352 *         a timeout.
353 */
354static inline cvmx_smix_rd_dat_t __cvmx_mdio_read_rd_dat(int bus_id)
355{
356    cvmx_smix_rd_dat_t smi_rd;
357    uint64_t done = cvmx_get_cycle() + (uint64_t)CVMX_MDIO_TIMEOUT *
358                       cvmx_clock_get_rate(CVMX_CLOCK_CORE) / 1000000;
359    do
360    {
361        cvmx_wait(1000);
362        smi_rd.u64 = cvmx_read_csr(CVMX_SMIX_RD_DAT(bus_id));
363    } while (smi_rd.s.pending && (cvmx_get_cycle() < done));
364    return smi_rd;
365}
366
367
368/**
369 * Perform an MII read. This function is used to read PHY
370 * registers controlling auto negotiation.
371 *
372 * @param bus_id   MDIO bus number. Zero on most chips, but some chips (ex CN56XX)
373 *                 support multiple busses.
374 * @param phy_id   The MII phy id
375 * @param location Register location to read
376 *
377 * @return Result from the read or -1 on failure
378 */
379static inline int cvmx_mdio_read(int bus_id, int phy_id, int location)
380{
381#if defined(CVMX_BUILD_FOR_LINUX_KERNEL) && defined(CONFIG_PHYLIB)
382	struct mii_bus *bus;
383	int rv;
384
385	BUG_ON(bus_id > 3 || bus_id < 0);
386
387	bus = octeon_mdiobuses[bus_id];
388	if (bus == NULL)
389		return -1;
390
391	rv = mdiobus_read(bus, phy_id, location);
392
393	if (rv < 0)
394		return -1;
395	return rv;
396#else
397    cvmx_smix_cmd_t smi_cmd;
398    cvmx_smix_rd_dat_t smi_rd;
399
400    if (octeon_has_feature(OCTEON_FEATURE_MDIO_CLAUSE_45))
401        __cvmx_mdio_set_clause22_mode(bus_id);
402
403    smi_cmd.u64 = 0;
404    smi_cmd.s.phy_op = MDIO_CLAUSE_22_READ;
405    smi_cmd.s.phy_adr = phy_id;
406    smi_cmd.s.reg_adr = location;
407    cvmx_write_csr(CVMX_SMIX_CMD(bus_id), smi_cmd.u64);
408
409    smi_rd = __cvmx_mdio_read_rd_dat(bus_id);
410    if (smi_rd.s.val)
411        return smi_rd.s.dat;
412    else
413        return -1;
414#endif
415}
416
417
418/**
419 * Perform an MII write. This function is used to write PHY
420 * registers controlling auto negotiation.
421 *
422 * @param bus_id   MDIO bus number. Zero on most chips, but some chips (ex CN56XX)
423 *                 support multiple busses.
424 * @param phy_id   The MII phy id
425 * @param location Register location to write
426 * @param val      Value to write
427 *
428 * @return -1 on error
429 *         0 on success
430 */
431static inline int cvmx_mdio_write(int bus_id, int phy_id, int location, int val)
432{
433#if defined(CVMX_BUILD_FOR_LINUX_KERNEL) && defined(CONFIG_PHYLIB)
434	struct mii_bus *bus;
435	int rv;
436
437	BUG_ON(bus_id > 3 || bus_id < 0);
438
439	bus = octeon_mdiobuses[bus_id];
440	if (bus == NULL)
441		return -1;
442
443	rv = mdiobus_write(bus, phy_id, location, (u16)val);
444
445	if (rv < 0)
446		return -1;
447	return 0;
448#else
449     cvmx_smix_cmd_t smi_cmd;
450    cvmx_smix_wr_dat_t smi_wr;
451
452    if (octeon_has_feature(OCTEON_FEATURE_MDIO_CLAUSE_45))
453        __cvmx_mdio_set_clause22_mode(bus_id);
454
455    smi_wr.u64 = 0;
456    smi_wr.s.dat = val;
457    cvmx_write_csr(CVMX_SMIX_WR_DAT(bus_id), smi_wr.u64);
458
459    smi_cmd.u64 = 0;
460    smi_cmd.s.phy_op = MDIO_CLAUSE_22_WRITE;
461    smi_cmd.s.phy_adr = phy_id;
462    smi_cmd.s.reg_adr = location;
463    cvmx_write_csr(CVMX_SMIX_CMD(bus_id), smi_cmd.u64);
464
465    if (CVMX_WAIT_FOR_FIELD64(CVMX_SMIX_WR_DAT(bus_id),
466        cvmx_smix_wr_dat_t, pending, ==, 0, CVMX_MDIO_TIMEOUT))
467        return -1;
468
469    return 0;
470#endif
471}
472
473#ifndef CVMX_BUILD_FOR_LINUX_KERNEL
474/**
475 * Perform an IEEE 802.3 clause 45 MII read. This function is used to read PHY
476 * registers controlling auto negotiation.
477 *
478 * @param bus_id   MDIO bus number. Zero on most chips, but some chips (ex CN56XX)
479 *                 support multiple busses.
480 * @param phy_id   The MII phy id
481 * @param device   MDIO Managable Device (MMD) id
482 * @param location Register location to read
483 *
484 * @return Result from the read or -1 on failure
485 */
486
487static inline int cvmx_mdio_45_read(int bus_id, int phy_id, int device, int location)
488{
489    cvmx_smix_cmd_t smi_cmd;
490    cvmx_smix_rd_dat_t smi_rd;
491    cvmx_smix_wr_dat_t smi_wr;
492
493    if (!octeon_has_feature(OCTEON_FEATURE_MDIO_CLAUSE_45))
494        return -1;
495
496    __cvmx_mdio_set_clause45_mode(bus_id);
497
498    smi_wr.u64 = 0;
499    smi_wr.s.dat = location;
500    cvmx_write_csr(CVMX_SMIX_WR_DAT(bus_id), smi_wr.u64);
501
502    smi_cmd.u64 = 0;
503    smi_cmd.s.phy_op = MDIO_CLAUSE_45_ADDRESS;
504    smi_cmd.s.phy_adr = phy_id;
505    smi_cmd.s.reg_adr = device;
506    cvmx_write_csr(CVMX_SMIX_CMD(bus_id), smi_cmd.u64);
507
508    if (CVMX_WAIT_FOR_FIELD64(CVMX_SMIX_WR_DAT(bus_id),
509        cvmx_smix_wr_dat_t, pending, ==, 0, CVMX_MDIO_TIMEOUT))
510    {
511        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);
512        return -1;
513    }
514
515    smi_cmd.u64 = 0;
516    smi_cmd.s.phy_op = MDIO_CLAUSE_45_READ;
517    smi_cmd.s.phy_adr = phy_id;
518    smi_cmd.s.reg_adr = device;
519    cvmx_write_csr(CVMX_SMIX_CMD(bus_id), smi_cmd.u64);
520
521    smi_rd = __cvmx_mdio_read_rd_dat(bus_id);
522    if (smi_rd.s.pending)
523    {
524        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);
525        return -1;
526    }
527
528    if (smi_rd.s.val)
529        return smi_rd.s.dat;
530    else
531    {
532        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);
533        return -1;
534    }
535}
536
537/**
538 * Perform an IEEE 802.3 clause 45 MII write. This function is used to write PHY
539 * registers controlling auto negotiation.
540 *
541 * @param bus_id   MDIO bus number. Zero on most chips, but some chips (ex CN56XX)
542 *                 support multiple busses.
543 * @param phy_id   The MII phy id
544 * @param device   MDIO Managable Device (MMD) id
545 * @param location Register location to write
546 * @param val      Value to write
547 *
548 * @return -1 on error
549 *         0 on success
550 */
551static inline int cvmx_mdio_45_write(int bus_id, int phy_id, int device, int location,
552                                     int val)
553{
554    cvmx_smix_cmd_t smi_cmd;
555    cvmx_smix_wr_dat_t smi_wr;
556
557    if (!octeon_has_feature(OCTEON_FEATURE_MDIO_CLAUSE_45))
558        return -1;
559
560    __cvmx_mdio_set_clause45_mode(bus_id);
561
562    smi_wr.u64 = 0;
563    smi_wr.s.dat = location;
564    cvmx_write_csr(CVMX_SMIX_WR_DAT(bus_id), smi_wr.u64);
565
566    smi_cmd.u64 = 0;
567    smi_cmd.s.phy_op = MDIO_CLAUSE_45_ADDRESS;
568    smi_cmd.s.phy_adr = phy_id;
569    smi_cmd.s.reg_adr = device;
570    cvmx_write_csr(CVMX_SMIX_CMD(bus_id), smi_cmd.u64);
571
572    if (CVMX_WAIT_FOR_FIELD64(CVMX_SMIX_WR_DAT(bus_id),
573        cvmx_smix_wr_dat_t, pending, ==, 0, CVMX_MDIO_TIMEOUT))
574        return -1;
575
576    smi_wr.u64 = 0;
577    smi_wr.s.dat = val;
578    cvmx_write_csr(CVMX_SMIX_WR_DAT(bus_id), smi_wr.u64);
579
580    smi_cmd.u64 = 0;
581    smi_cmd.s.phy_op = MDIO_CLAUSE_45_WRITE;
582    smi_cmd.s.phy_adr = phy_id;
583    smi_cmd.s.reg_adr = device;
584    cvmx_write_csr(CVMX_SMIX_CMD(bus_id), smi_cmd.u64);
585
586    if (CVMX_WAIT_FOR_FIELD64(CVMX_SMIX_WR_DAT(bus_id),
587        cvmx_smix_wr_dat_t, pending, ==, 0, CVMX_MDIO_TIMEOUT))
588        return -1;
589
590    return 0;
591}
592#endif
593
594#ifdef	__cplusplus
595}
596#endif
597
598#endif
599
600