1/*
2 * Copyright (c) 2012, 2015, The Linux Foundation. All rights reserved.
3 * Permission to use, copy, modify, and/or distribute this software for
4 * any purpose with or without fee is hereby granted, provided that the
5 * above copyright notice and this permission notice appear in all copies.
6 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
7 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
8 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
9 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
10 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
11 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
12 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
13 */
14
15
16
17#include "sw.h"
18#include "fal_port_ctrl.h"
19#include "hsl_api.h"
20#include "hsl.h"
21#include "f1_phy.h"
22#include "aos_timer.h"
23#include "hsl_phy.h"
24#include <linux/kconfig.h>
25#include <linux/kernel.h>
26#include <linux/module.h>
27#include <linux/phy.h>
28
29static a_uint16_t
30_phy_reg_read(a_uint32_t dev_id, a_uint32_t phy_addr, a_uint32_t reg)
31{
32    sw_error_t rv;
33    a_uint16_t val;
34
35    HSL_PHY_GET(rv, dev_id, phy_addr, reg, &val);
36    if (SW_OK != rv)
37        return 0xFFFF;
38
39    return val;
40}
41
42static void
43_phy_reg_write(a_uint32_t dev_id, a_uint32_t phy_addr, a_uint32_t reg,
44               a_uint16_t val)
45{
46    sw_error_t rv;
47
48    HSL_PHY_SET(rv, dev_id, phy_addr, reg, val);
49}
50
51/* #define f1_phy_reg_read _phy_reg_read */
52/* #define f1_phy_reg_write _phy_reg_write */
53
54/******************************************************************************
55*
56* f1_phy_mii_read - mii register read
57*
58* mil register read
59*/
60a_uint16_t
61f1_phy_reg_read(a_uint32_t dev_id, a_uint32_t phy_id, a_uint32_t reg_id)
62{
63 	return _phy_reg_read(dev_id, phy_id, reg_id);
64
65}
66
67/******************************************************************************
68*
69* f1_phy_reg_write - mii register write
70*
71* mii register write
72*/
73sw_error_t
74f1_phy_reg_write(a_uint32_t dev_id, a_uint32_t phy_id, a_uint32_t reg_id,
75		       a_uint16_t reg_val)
76{
77
78       _phy_reg_write(dev_id,phy_id, reg_id, reg_val);
79
80	return SW_OK;
81}
82
83
84/******************************************************************************
85*
86* f1_phy_debug_write - debug port write
87*
88* debug port write
89*/
90sw_error_t
91f1_phy_debug_write(a_uint32_t dev_id, a_uint32_t phy_id, a_uint16_t reg_id,
92                   a_uint16_t reg_val)
93{
94    f1_phy_reg_write(dev_id, phy_id, F1_DEBUG_PORT_ADDRESS, reg_id);
95    f1_phy_reg_write(dev_id, phy_id, F1_DEBUG_PORT_DATA, reg_val);
96
97    return SW_OK;
98}
99
100/******************************************************************************
101*
102* f1_phy_debug_read - debug port read
103*
104* debug port read
105*/
106a_uint16_t
107f1_phy_debug_read(a_uint32_t dev_id, a_uint32_t phy_id, a_uint16_t reg_id)
108{
109    f1_phy_reg_write(dev_id, phy_id, F1_DEBUG_PORT_ADDRESS, reg_id);
110    return f1_phy_reg_read(dev_id, phy_id, F1_DEBUG_PORT_DATA);
111}
112
113/******************************************************************************
114*
115* f1_phy_mmd_write - PHY MMD register write
116*
117* PHY MMD register write
118*/
119sw_error_t
120f1_phy_mmd_write(a_uint32_t dev_id, a_uint32_t phy_id,
121                 a_uint16_t mmd_num,
122                 a_uint16_t reg_id,
123                 a_uint16_t reg_val)
124{
125    f1_phy_reg_write(dev_id, phy_id, F1_MMD_CTRL_REG, mmd_num);
126    f1_phy_reg_write(dev_id, phy_id, F1_MMD_DATA_REG, reg_id);
127    f1_phy_reg_write(dev_id, phy_id, F1_MMD_CTRL_REG, 0x4000|mmd_num);
128    f1_phy_reg_write(dev_id, phy_id, F1_MMD_DATA_REG, reg_val);
129
130    return SW_OK;
131}
132
133/******************************************************************************
134*
135* f1_phy_mmd_read -  PHY MMD register read
136*
137* PHY MMD register read
138*/
139a_uint16_t
140f1_phy_mmd_read(a_uint32_t dev_id, a_uint32_t phy_id,
141                  a_uint16_t mmd_num,
142                  a_uint16_t reg_id)
143{
144    f1_phy_reg_write(dev_id, phy_id, F1_MMD_CTRL_REG, mmd_num);
145    f1_phy_reg_write(dev_id, phy_id, F1_MMD_DATA_REG, reg_id);
146    f1_phy_reg_write(dev_id, phy_id, F1_MMD_CTRL_REG, 0x4000|mmd_num);
147
148    return f1_phy_reg_read(dev_id, phy_id, F1_MMD_DATA_REG);
149}
150
151
152/******************************************************************************
153*
154* f1_phy_set_powersave - set power saving status
155*
156* set power saving status
157*/
158sw_error_t
159f1_phy_set_powersave(a_uint32_t dev_id, a_uint32_t phy_id, a_bool_t enable)
160{
161    a_uint16_t phy_data;
162    f1_phy_reg_write(dev_id, phy_id, F1_DEBUG_PORT_ADDRESS, 0x29);
163    phy_data = f1_phy_reg_read(dev_id, phy_id, F1_DEBUG_PORT_DATA);
164
165    if(enable == A_TRUE)
166    {
167        phy_data |= 0x8000;
168    }
169    else
170    {
171        phy_data &= ~0x8000;
172    }
173
174    f1_phy_reg_write(dev_id, phy_id, F1_DEBUG_PORT_DATA, phy_data);
175
176    return SW_OK;
177}
178
179/******************************************************************************
180*
181* f1_phy_get_powersave - get power saving status
182*
183* set power saving status
184*/
185sw_error_t
186f1_phy_get_powersave(a_uint32_t dev_id, a_uint32_t phy_id, a_bool_t *enable)
187{
188    a_uint16_t phy_data;
189    *enable = A_FALSE;
190
191    f1_phy_reg_write(dev_id, phy_id, F1_DEBUG_PORT_ADDRESS, 0x29);
192    phy_data = f1_phy_reg_read(dev_id, phy_id, F1_DEBUG_PORT_DATA);
193
194    if(phy_data & 0x8000)
195        *enable =  A_TRUE;
196
197    return SW_OK;
198}
199
200/******************************************************************************
201*
202* f1_phy_set_hibernate - set hibernate status
203*
204* set hibernate status
205*/
206sw_error_t
207f1_phy_set_hibernate(a_uint32_t dev_id, a_uint32_t phy_id, a_bool_t enable)
208{
209    a_uint16_t phy_data;
210    f1_phy_reg_write(dev_id, phy_id, F1_DEBUG_PORT_ADDRESS, 0xb);
211    phy_data = f1_phy_reg_read(dev_id, phy_id, F1_DEBUG_PORT_DATA);
212
213    if(enable == A_TRUE)
214    {
215        phy_data |= 0x8000;
216    }
217    else
218    {
219        phy_data &= ~0x8000;
220    }
221
222    f1_phy_reg_write(dev_id, phy_id, F1_DEBUG_PORT_DATA, phy_data);
223
224    return SW_OK;
225}
226
227/******************************************************************************
228*
229* f1_phy_get_hibernate - get hibernate status
230*
231* get hibernate status
232*/
233sw_error_t
234f1_phy_get_hibernate(a_uint32_t dev_id, a_uint32_t phy_id, a_bool_t *enable)
235{
236    a_uint16_t phy_data;
237    *enable = A_FALSE;
238
239    f1_phy_reg_write(dev_id, phy_id, F1_DEBUG_PORT_ADDRESS, 0xb);
240    phy_data = f1_phy_reg_read(dev_id, phy_id, F1_DEBUG_PORT_DATA);
241
242    if(phy_data & 0x8000)
243        *enable =  A_TRUE;
244
245    return SW_OK;
246}
247
248/******************************************************************************
249*
250* f1_phy_cdt - cable diagnostic test
251*
252* cable diagnostic test
253*/
254#ifdef ISISC
255#define RUN_CDT 0x8000
256#define CABLE_LENGTH_UNIT 0x0400
257sw_error_t f1_phy_reset(a_uint32_t dev_id, a_uint32_t phy_id);
258a_bool_t f1_phy_reset_done(a_uint32_t dev_id, a_uint32_t phy_id);
259a_bool_t f1_phy_get_link_status(a_uint32_t dev_id, a_uint32_t phy_id);
260
261static inline fal_cable_status_t
262_fal_cdt_status_mapping(a_uint16_t status)
263{
264    fal_cable_status_t status_mapping = FAL_CABLE_STATUS_INVALID;
265
266    if (0 == status)
267        status_mapping = FAL_CABLE_STATUS_INVALID;
268    else if (1 == status)
269        status_mapping = FAL_CABLE_STATUS_NORMAL;
270    else if (2 == status)
271        status_mapping = FAL_CABLE_STATUS_OPENED;
272    else if (3 == status)
273        status_mapping = FAL_CABLE_STATUS_SHORT;
274
275    return status_mapping;
276}
277
278static sw_error_t
279f1_phy_cdt_start(a_uint32_t dev_id, a_uint32_t phy_id)
280{
281    a_uint16_t status = 0;
282    a_uint16_t ii = 100;
283
284    /* RUN CDT */
285    f1_phy_reg_write(dev_id, phy_id, F1_PHY_CDT_CONTROL, RUN_CDT|CABLE_LENGTH_UNIT);
286    do
287    {
288        aos_mdelay(30);
289        status = f1_phy_reg_read(dev_id, phy_id, F1_PHY_CDT_CONTROL);
290    }
291    while ((status & RUN_CDT) && (--ii));
292
293    return SW_OK;
294}
295
296sw_error_t
297f1_phy_cdt_get(a_uint32_t dev_id, a_uint32_t phy_id, fal_port_cdt_t *port_cdt)
298{
299    a_uint16_t status = 0;
300    a_uint16_t cable_delta_time = 0;
301    a_uint16_t org_debug_value = 0;
302    int ii = 100;
303    a_bool_t link_st = A_FALSE;
304    a_uint16_t reg806e = 0;
305    int i;
306
307    if((!port_cdt) || (phy_id > 4))
308    {
309        return SW_FAIL;
310    }
311
312    /*disable clock gating*/
313    org_debug_value = f1_phy_debug_read(dev_id, phy_id, 0x3f);
314    f1_phy_debug_write(dev_id, phy_id, 0x3f, 0);
315
316    f1_phy_cdt_start(dev_id, phy_id);
317
318    /* Get cable status */
319    status = f1_phy_mmd_read(dev_id, phy_id, 3, 0x8064);
320
321    /* Workaround for cable lenth less than 20M  */
322    port_cdt->pair_c_status = (status >> 4) & 0x3;
323    /* Get Cable Length value */
324    cable_delta_time = f1_phy_mmd_read(dev_id, phy_id, 3, 0x8067);
325    /* the actual cable length equals to CableDeltaTime * 0.824*/
326    port_cdt->pair_c_len = (cable_delta_time * 824) /1000;
327    if ((1 == port_cdt->pair_c_status) &&
328        (port_cdt->pair_c_len > 0) && (port_cdt->pair_c_len <= 20))
329    {
330        reg806e = f1_phy_mmd_read(dev_id, phy_id, 3, 0x806e);
331	f1_phy_mmd_write(dev_id, phy_id, 3, 0x806e, reg806e & (~0x8000));
332
333        f1_phy_reset(dev_id, phy_id);
334        f1_phy_reset_done(dev_id, phy_id);
335	do
336        {
337            link_st = f1_phy_get_link_status(dev_id, phy_id);
338	    aos_mdelay(100);
339        } while ((A_FALSE == link_st) && (--ii));
340
341	f1_phy_cdt_start(dev_id, phy_id);
342        /* Get cable status */
343        status = f1_phy_mmd_read(dev_id, phy_id, 3, 0x8064);
344    }
345
346    for (i=0;i<4;i++)
347    {
348        switch(i)
349        {
350            case 0:
351                port_cdt->pair_a_status = (status >> 12) & 0x3;
352                /* Get Cable Length value */
353                cable_delta_time = f1_phy_mmd_read(dev_id, phy_id, 3, 0x8065);
354                /* the actual cable length equals to CableDeltaTime * 0.824*/
355                port_cdt->pair_a_len = (cable_delta_time * 824) /1000;
356
357                break;
358            case 1:
359                port_cdt->pair_b_status = (status >> 8) & 0x3;
360                /* Get Cable Length value */
361                cable_delta_time = f1_phy_mmd_read(dev_id, phy_id, 3, 0x8066);
362                /* the actual cable length equals to CableDeltaTime * 0.824*/
363                port_cdt->pair_b_len = (cable_delta_time * 824) /1000;
364                break;
365            case 2:
366                port_cdt->pair_c_status = (status >> 4) & 0x3;
367                /* Get Cable Length value */
368                cable_delta_time = f1_phy_mmd_read(dev_id, phy_id, 3, 0x8067);
369                /* the actual cable length equals to CableDeltaTime * 0.824*/
370                port_cdt->pair_c_len = (cable_delta_time * 824) /1000;
371                break;
372            case 3:
373                port_cdt->pair_d_status = status & 0x3;
374                /* Get Cable Length value */
375                cable_delta_time = f1_phy_mmd_read(dev_id, phy_id, 3, 0x8068);
376                /* the actual cable length equals to CableDeltaTime * 0.824*/
377                port_cdt->pair_d_len = (cable_delta_time * 824) /1000;
378                break;
379            default:
380                break;
381        }
382    }
383
384    /*restore debug port value*/
385    f1_phy_debug_write(dev_id, phy_id, 0x3f, org_debug_value);
386
387    return SW_OK;
388}
389
390sw_error_t
391f1_phy_cdt(a_uint32_t dev_id, a_uint32_t phy_id, a_uint32_t mdi_pair,
392           fal_cable_status_t *cable_status, a_uint32_t *cable_len)
393{
394    fal_port_cdt_t f1_port_cdt;
395
396    if((mdi_pair >= 4) || (phy_id > 4))
397    {
398        //There are only 4 mdi pairs in 1000BASE-T
399        return SW_BAD_PARAM;
400    }
401
402    f1_phy_cdt_get(dev_id, phy_id, &f1_port_cdt);
403
404    switch(mdi_pair)
405    {
406        case 0:
407            *cable_status = _fal_cdt_status_mapping(f1_port_cdt.pair_a_status);
408            /* Get Cable Length value */
409	    *cable_len = f1_port_cdt.pair_a_len;
410            break;
411        case 1:
412            *cable_status = _fal_cdt_status_mapping(f1_port_cdt.pair_b_status);
413            /* Get Cable Length value */
414	    *cable_len = f1_port_cdt.pair_b_len;
415            break;
416        case 2:
417            *cable_status = _fal_cdt_status_mapping(f1_port_cdt.pair_c_status);
418            /* Get Cable Length value */
419	    *cable_len = f1_port_cdt.pair_c_len;
420            break;
421        case 3:
422            *cable_status = _fal_cdt_status_mapping(f1_port_cdt.pair_d_status);
423            /* Get Cable Length value */
424	    *cable_len = f1_port_cdt.pair_d_len;
425            break;
426        default:
427            break;
428    }
429
430    return SW_OK;
431}
432#else
433sw_error_t
434f1_phy_cdt(a_uint32_t dev_id, a_uint32_t phy_id, a_uint32_t mdi_pair,
435           fal_cable_status_t *cable_status, a_uint32_t *cable_len)
436{
437    a_uint16_t status = 0;
438    a_uint16_t ii = 100;
439
440    if(!cable_status || !cable_len)
441    {
442        return SW_FAIL;
443    }
444
445    if(mdi_pair >= 4)
446    {
447        //There are only 4 mdi pairs in 1000BASE-T
448        return SW_BAD_PARAM;
449    }
450
451    a_uint16_t org_debug_value = f1_phy_debug_read(dev_id, phy_id, 0x3f);
452
453    /*disable clock gating*/
454    f1_phy_debug_write(dev_id, phy_id, 0x3f, 0);
455    f1_phy_reg_write(dev_id, phy_id, F1_PHY_CDT_CONTROL, (mdi_pair << 8) | 0x0001);
456
457    do
458    {
459        aos_mdelay(30);
460        status = f1_phy_reg_read(dev_id, phy_id, F1_PHY_CDT_CONTROL);
461    }
462    while ((status & 0x0001) && (--ii));
463
464    status = f1_phy_reg_read(dev_id, phy_id, F1_PHY_CDT_STATUS);
465
466    *cable_status = (status&0x300) >> 8;
467    if ( (*cable_status == 1) || (*cable_status == 2))
468    {
469        if ( mdi_pair == 1 || mdi_pair == 3 )
470        {
471            /*Reverse the mdi status for channel 1 and channel 3*/
472            *cable_status = (~(*cable_status)) & 0x3;
473        }
474    }
475
476    /* the actual cable length equals to CableDeltaTime * 0.824*/
477    a_uint16_t cable_delta_time = status & 0xff;
478    *cable_len = (cable_delta_time * 824) /1000;
479
480    /*restore debug port value*/
481    f1_phy_debug_write(dev_id, phy_id, 0x3f, org_debug_value);
482    //f1_phy_reg_write(dev_id, phy_id, 0x00, 0x9000);//Reset the PHY if necessary
483
484    return SW_OK;
485}
486#endif
487
488/******************************************************************************
489*
490* f1_phy_reset_done - reset the phy
491*
492* reset the phy
493*/
494a_bool_t
495f1_phy_reset_done(a_uint32_t dev_id, a_uint32_t phy_id)
496{
497    a_uint16_t phy_data;
498    a_uint16_t ii = 200;
499
500    do
501    {
502        phy_data = f1_phy_reg_read(dev_id, phy_id, F1_PHY_CONTROL);
503        aos_mdelay(10);
504    }
505    while ((!F1_RESET_DONE(phy_data)) && --ii);
506
507    if (ii == 0)
508        return A_FALSE;
509
510    return A_TRUE;
511}
512
513/******************************************************************************
514*
515* f1_autoneg_done
516*
517* f1_autoneg_done
518*/
519a_bool_t
520f1_autoneg_done(a_uint32_t dev_id, a_uint32_t phy_id)
521{
522    a_uint16_t phy_data;
523    a_uint16_t ii = 200;
524
525    do
526    {
527        phy_data = f1_phy_reg_read(dev_id, phy_id, F1_PHY_STATUS);
528        aos_mdelay(10);
529    }
530    while ((!F1_AUTONEG_DONE(phy_data)) && --ii);
531
532    if (ii == 0)
533        return A_FALSE;
534
535    return A_TRUE;
536}
537
538/******************************************************************************
539*
540* f1_phy_Speed_Duplex_Resolved
541 - reset the phy
542*
543* reset the phy
544*/
545a_bool_t
546f1_phy_speed_duplex_resolved(a_uint32_t dev_id, a_uint32_t phy_id)
547{
548    a_uint16_t phy_data;
549    a_uint16_t ii = 200;
550
551    do
552    {
553        phy_data = f1_phy_reg_read(dev_id, phy_id, F1_PHY_SPEC_STATUS);
554        aos_mdelay(10);
555    }
556    while ((!F1_SPEED_DUPLEX_RESOVLED(phy_data)) && --ii);
557
558    if (ii == 0)
559        return A_FALSE;
560
561    return A_TRUE;
562}
563
564/******************************************************************************
565*
566* f1_phy_reset - reset the phy
567*
568* reset the phy
569*/
570sw_error_t
571f1_phy_reset(a_uint32_t dev_id, a_uint32_t phy_id)
572{
573    a_uint16_t phy_data;
574
575    phy_data = f1_phy_reg_read(dev_id, phy_id, F1_PHY_CONTROL);
576    f1_phy_reg_write(dev_id, phy_id, F1_PHY_CONTROL,
577                     phy_data | F1_CTRL_SOFTWARE_RESET);
578
579    return SW_OK;
580}
581
582/******************************************************************************
583*
584* f1_phy_off - power off the phy to change its speed
585*
586* Power off the phy
587*/
588sw_error_t
589f1_phy_poweroff(a_uint32_t dev_id, a_uint32_t phy_id)
590{
591    a_uint16_t phy_data;
592
593    phy_data = f1_phy_reg_read(dev_id, phy_id, F1_PHY_CONTROL);
594    f1_phy_reg_write(dev_id, phy_id, F1_PHY_CONTROL,
595                     phy_data | F1_CTRL_POWER_DOWN);
596
597    return SW_OK;
598}
599
600/******************************************************************************
601*
602* f1_phy_on - power on the phy after speed changed
603*
604* Power on the phy
605*/
606sw_error_t
607f1_phy_poweron(a_uint32_t dev_id, a_uint32_t phy_id)
608{
609    a_uint16_t phy_data;
610
611    phy_data = f1_phy_reg_read(dev_id, phy_id, F1_PHY_CONTROL);
612    f1_phy_reg_write(dev_id, phy_id, F1_PHY_CONTROL,
613                     phy_data & ~F1_CTRL_POWER_DOWN);
614
615    aos_mdelay(200);
616
617    return SW_OK;
618}
619
620/******************************************************************************
621*
622* f1_phy_get_ability - get the phy ability
623*
624*
625*/
626sw_error_t
627f1_phy_get_ability(a_uint32_t dev_id, a_uint32_t phy_id,
628                   a_uint32_t * ability)
629{
630    a_uint16_t phy_data;
631
632    *ability = 0;
633    phy_data = f1_phy_reg_read(dev_id, phy_id, F1_PHY_STATUS);
634
635    if (phy_data & F1_STATUS_AUTONEG_CAPS)
636        *ability |= FAL_PHY_AUTONEG_CAPS;
637
638    if (phy_data & F1_STATUS_100T2_HD_CAPS)
639        *ability |= FAL_PHY_100T2_HD_CAPS;
640
641    if (phy_data & F1_STATUS_100T2_FD_CAPS)
642        *ability |= FAL_PHY_100T2_FD_CAPS;
643
644    if (phy_data & F1_STATUS_10T_HD_CAPS)
645        *ability |= FAL_PHY_10T_HD_CAPS;
646
647    if (phy_data & F1_STATUS_10T_FD_CAPS)
648        *ability |= FAL_PHY_10T_FD_CAPS;
649
650    if (phy_data & F1_STATUS_100X_HD_CAPS)
651        *ability |= FAL_PHY_100X_HD_CAPS;
652
653    if (phy_data & F1_STATUS_100X_FD_CAPS)
654        *ability |= FAL_PHY_100X_FD_CAPS;
655
656    if (phy_data & F1_STATUS_100T4_CAPS)
657        *ability |= FAL_PHY_100T4_CAPS;
658
659    if (phy_data & F1_STATUS_EXTENDED_STATUS)
660    {
661        phy_data = f1_phy_reg_read(dev_id, phy_id, F1_EXTENDED_STATUS);
662
663        if (phy_data & F1_STATUS_1000T_FD_CAPS)
664        {
665            *ability |= FAL_PHY_1000T_FD_CAPS;
666        }
667
668        if (phy_data & F1_STATUS_1000X_FD_CAPS)
669        {
670            *ability |= FAL_PHY_1000X_FD_CAPS;
671        }
672    }
673
674    return SW_OK;
675}
676
677/******************************************************************************
678*
679* f1_phy_get_ability - get the phy ability
680*
681*
682*/
683sw_error_t
684f1_phy_get_partner_ability(a_uint32_t dev_id, a_uint32_t phy_id,
685                           a_uint32_t * ability)
686{
687    a_uint16_t phy_data;
688
689    *ability = 0;
690    phy_data = f1_phy_reg_read(dev_id, phy_id, F1_LINK_PARTNER_ABILITY);
691
692    if (phy_data & F1_LINK_10BASETX_HALF_DUPLEX)
693        *ability |= FAL_PHY_PART_10T_HD;
694
695    if (phy_data & F1_LINK_10BASETX_FULL_DUPLEX)
696        *ability |= FAL_PHY_PART_10T_FD;
697
698    if (phy_data & F1_LINK_100BASETX_HALF_DUPLEX)
699        *ability |= FAL_PHY_PART_100TX_HD;
700
701    if (phy_data & F1_LINK_100BASETX_FULL_DUPLEX)
702        *ability |= FAL_PHY_PART_100TX_FD;
703
704    if (phy_data & F1_LINK_NPAGE)
705    {
706        phy_data = f1_phy_reg_read(dev_id, phy_id, F1_1000BASET_STATUS);
707
708        if (phy_data & F1_LINK_1000BASETX_FULL_DUPLEX)
709            *ability |= FAL_PHY_PART_1000T_FD;
710    }
711
712    return SW_OK;
713}
714
715/******************************************************************************
716*
717* f1_phy_status - test to see if the specified phy link is alive
718*
719* RETURNS:
720*    A_TRUE  --> link is alive
721*    A_FALSE --> link is down
722*/
723a_bool_t
724f1_phy_get_link_status(a_uint32_t dev_id, a_uint32_t phy_id)
725{
726    a_uint16_t phy_data;
727
728    phy_data = f1_phy_reg_read(dev_id, phy_id, F1_PHY_SPEC_STATUS);
729
730    if (phy_data & F1_STATUS_LINK_PASS)
731        return A_TRUE;
732
733    return A_FALSE;
734}
735
736/******************************************************************************
737*
738* f1_set_autoneg_adv - set the phy autoneg Advertisement
739*
740*/
741sw_error_t
742f1_phy_set_autoneg_adv(a_uint32_t dev_id, a_uint32_t phy_id,
743                       a_uint32_t autoneg)
744{
745    a_uint16_t phy_data = 0;
746
747    phy_data = f1_phy_reg_read(dev_id, phy_id, F1_AUTONEG_ADVERT);
748    phy_data &= ~F1_ADVERTISE_MEGA_ALL;
749    phy_data &= ~(F1_ADVERTISE_PAUSE | F1_ADVERTISE_ASYM_PAUSE);
750
751    if (autoneg & FAL_PHY_ADV_100TX_FD)
752        phy_data |= F1_ADVERTISE_100FULL;
753
754    if (autoneg & FAL_PHY_ADV_100TX_HD)
755        phy_data |= F1_ADVERTISE_100HALF;
756
757    if (autoneg & FAL_PHY_ADV_10T_FD)
758        phy_data |= F1_ADVERTISE_10FULL;
759
760    if (autoneg & FAL_PHY_ADV_10T_HD)
761        phy_data |= F1_ADVERTISE_10HALF;
762
763    if (autoneg & FAL_PHY_ADV_PAUSE)
764        phy_data |= F1_ADVERTISE_PAUSE;
765
766    if (autoneg & FAL_PHY_ADV_ASY_PAUSE)
767        phy_data |= F1_ADVERTISE_ASYM_PAUSE;
768
769    f1_phy_reg_write(dev_id, phy_id, F1_AUTONEG_ADVERT, phy_data);
770
771    phy_data = f1_phy_reg_read(dev_id, phy_id, F1_1000BASET_CONTROL);
772    phy_data &= ~F1_ADVERTISE_1000FULL;
773    phy_data &= ~F1_ADVERTISE_1000HALF;
774
775    if (autoneg & FAL_PHY_ADV_1000T_FD)
776        phy_data |= F1_ADVERTISE_1000FULL;
777
778    f1_phy_reg_write(dev_id, phy_id, F1_1000BASET_CONTROL, phy_data);
779
780    return SW_OK;
781}
782
783/******************************************************************************
784*
785* f1_get_autoneg_adv - get the phy autoneg Advertisement
786*
787*/
788sw_error_t
789f1_phy_get_autoneg_adv(a_uint32_t dev_id, a_uint32_t phy_id,
790                       a_uint32_t * autoneg)
791{
792    a_uint16_t phy_data = 0;
793
794    *autoneg = 0;
795    phy_data = f1_phy_reg_read(dev_id, phy_id, F1_AUTONEG_ADVERT);
796
797    if (phy_data & F1_ADVERTISE_100FULL)
798        *autoneg |= FAL_PHY_ADV_100TX_FD;
799
800    if (phy_data & F1_ADVERTISE_100HALF)
801        *autoneg |= FAL_PHY_ADV_100TX_HD;
802
803    if (phy_data & F1_ADVERTISE_10FULL)
804        *autoneg |= FAL_PHY_ADV_10T_FD;
805
806    if (phy_data & F1_ADVERTISE_10HALF)
807        *autoneg |= FAL_PHY_ADV_10T_HD;
808
809    if (phy_data & F1_ADVERTISE_PAUSE)
810        *autoneg |= FAL_PHY_ADV_PAUSE;
811
812    if (phy_data & F1_ADVERTISE_ASYM_PAUSE)
813        *autoneg |= FAL_PHY_ADV_ASY_PAUSE;
814
815    phy_data = f1_phy_reg_read(dev_id, phy_id, F1_1000BASET_CONTROL);
816
817    if (phy_data & F1_ADVERTISE_1000FULL)
818        *autoneg |= FAL_PHY_ADV_1000T_FD;
819
820    return SW_OK;
821}
822
823/******************************************************************************
824*
825* f1_phy_enable_autonego - power off the phy to change its speed
826*
827* Power off the phy
828*/
829a_bool_t
830f1_phy_autoneg_status(a_uint32_t dev_id, a_uint32_t phy_id)
831{
832    a_uint16_t phy_data;
833
834    phy_data = f1_phy_reg_read(dev_id, phy_id, F1_PHY_CONTROL);
835
836    if (phy_data & F1_CTRL_AUTONEGOTIATION_ENABLE)
837        return A_TRUE;
838
839    return A_FALSE;
840}
841
842/******************************************************************************
843*
844* f1_restart_autoneg - restart the phy autoneg
845*
846*/
847sw_error_t
848f1_phy_restart_autoneg(a_uint32_t dev_id, a_uint32_t phy_id)
849{
850    a_uint16_t phy_data = 0;
851
852    phy_data = f1_phy_reg_read(dev_id, phy_id, F1_PHY_CONTROL);
853
854    phy_data |= F1_CTRL_AUTONEGOTIATION_ENABLE;
855    f1_phy_reg_write(dev_id, phy_id, F1_PHY_CONTROL,
856                     phy_data | F1_CTRL_RESTART_AUTONEGOTIATION);
857
858    return SW_OK;
859}
860
861/******************************************************************************
862*
863* f1_phy_enable_autonego - power off the phy to change its speed
864*
865* Power off the phy
866*/
867sw_error_t
868f1_phy_enable_autoneg(a_uint32_t dev_id, a_uint32_t phy_id)
869{
870    a_uint16_t phy_data = 0;
871
872    phy_data = f1_phy_reg_read(dev_id, phy_id, F1_PHY_CONTROL);
873
874    f1_phy_reg_write(dev_id, phy_id, F1_PHY_CONTROL,
875                     phy_data | F1_CTRL_AUTONEGOTIATION_ENABLE);
876
877    return SW_OK;
878}
879
880
881/******************************************************************************
882*
883* f1_phy_get_speed - Determines the speed of phy ports associated with the
884* specified device.
885*/
886
887sw_error_t
888f1_phy_get_speed(a_uint32_t dev_id, a_uint32_t phy_id,
889                 fal_port_speed_t * speed)
890{
891    a_uint16_t phy_data;
892
893    phy_data = f1_phy_reg_read(dev_id, phy_id, F1_PHY_SPEC_STATUS);
894
895    switch (phy_data & F1_STATUS_SPEED_MASK)
896    {
897        case F1_STATUS_SPEED_1000MBS:
898            *speed = FAL_SPEED_1000;
899            break;
900        case F1_STATUS_SPEED_100MBS:
901            *speed = FAL_SPEED_100;
902            break;
903        case F1_STATUS_SPEED_10MBS:
904            *speed = FAL_SPEED_10;
905            break;
906        default:
907            return SW_READ_ERROR;
908    }
909
910    return SW_OK;
911}
912
913/******************************************************************************
914*
915* f1_phy_set_speed - Determines the speed of phy ports associated with the
916* specified device.
917*/
918sw_error_t
919f1_phy_set_speed(a_uint32_t dev_id, a_uint32_t phy_id,
920                 fal_port_speed_t speed)
921{
922    a_uint16_t phy_data = 0;
923    a_uint16_t phy_status = 0;
924
925    a_uint32_t autoneg, oldneg;
926    fal_port_duplex_t old_duplex;
927
928    if (FAL_SPEED_1000 == speed)
929    {
930        phy_data |= F1_CTRL_SPEED_1000;
931    }
932    else if (FAL_SPEED_100 == speed)
933    {
934        phy_data |= F1_CTRL_SPEED_100;
935    }
936    else if (FAL_SPEED_10 == speed)
937    {
938        phy_data |= F1_CTRL_SPEED_10;
939    }
940    else
941    {
942        return SW_BAD_PARAM;
943    }
944
945    phy_data &= ~F1_CTRL_AUTONEGOTIATION_ENABLE;
946
947    (void)f1_phy_get_autoneg_adv(dev_id, phy_id, &autoneg);
948    oldneg = autoneg;
949    autoneg &= ~FAL_PHY_ADV_GE_SPEED_ALL;
950
951    (void)f1_phy_get_duplex(dev_id, phy_id, &old_duplex);
952
953    if (old_duplex == FAL_FULL_DUPLEX)
954    {
955        phy_data |= F1_CTRL_FULL_DUPLEX;
956
957        if (FAL_SPEED_1000 == speed)
958        {
959            autoneg |= FAL_PHY_ADV_1000T_FD;
960        }
961        else if (FAL_SPEED_100 == speed)
962        {
963            autoneg |= FAL_PHY_ADV_100TX_FD;
964        }
965        else
966        {
967            autoneg |= FAL_PHY_ADV_10T_FD;
968        }
969    }
970    else if (old_duplex == FAL_HALF_DUPLEX)
971    {
972        phy_data &= ~F1_CTRL_FULL_DUPLEX;
973
974        if (FAL_SPEED_100 == speed)
975        {
976            autoneg |= FAL_PHY_ADV_100TX_HD;
977        }
978        else
979        {
980            autoneg |= FAL_PHY_ADV_10T_HD;
981        }
982    }
983    else
984    {
985        return SW_FAIL;
986    }
987
988    (void)f1_phy_set_autoneg_adv(dev_id, phy_id, autoneg);
989    (void)f1_phy_restart_autoneg(dev_id, phy_id);
990    if(f1_phy_get_link_status(dev_id, phy_id))
991    {
992        do
993        {
994            phy_status = f1_phy_reg_read(dev_id, phy_id, F1_PHY_STATUS);
995        }
996        while(!F1_AUTONEG_DONE(phy_status));
997    }
998
999    f1_phy_reg_write(dev_id, phy_id, F1_PHY_CONTROL, phy_data);
1000    (void)f1_phy_set_autoneg_adv(dev_id, phy_id, oldneg);
1001
1002    return SW_OK;
1003
1004}
1005
1006/******************************************************************************
1007*
1008* f1_phy_get_duplex - Determines the speed of phy ports associated with the
1009* specified device.
1010*/
1011sw_error_t
1012f1_phy_get_duplex(a_uint32_t dev_id, a_uint32_t phy_id,
1013                  fal_port_duplex_t * duplex)
1014{
1015    a_uint16_t phy_data;
1016
1017    phy_data = f1_phy_reg_read(dev_id, phy_id, F1_PHY_SPEC_STATUS);
1018
1019    //read duplex
1020    if (phy_data & F1_STATUS_FULL_DUPLEX)
1021        *duplex = FAL_FULL_DUPLEX;
1022    else
1023        *duplex = FAL_HALF_DUPLEX;
1024
1025    return SW_OK;
1026}
1027
1028/******************************************************************************
1029*
1030* f1_phy_set_duplex - Determines the speed of phy ports associated with the
1031* specified device.
1032*/
1033sw_error_t
1034f1_phy_set_duplex(a_uint32_t dev_id, a_uint32_t phy_id,
1035                  fal_port_duplex_t duplex)
1036{
1037    a_uint16_t phy_data = 0;
1038    a_uint16_t phy_status = 0;
1039
1040    fal_port_speed_t old_speed;
1041    a_uint32_t oldneg, autoneg;
1042
1043    if (A_TRUE == f1_phy_autoneg_status(dev_id, phy_id))
1044        phy_data &= ~F1_CTRL_AUTONEGOTIATION_ENABLE;
1045
1046    (void)f1_phy_get_autoneg_adv(dev_id, phy_id, &autoneg);
1047    oldneg = autoneg;
1048    autoneg &= ~FAL_PHY_ADV_GE_SPEED_ALL;
1049    (void)f1_phy_get_speed(dev_id, phy_id, &old_speed);
1050
1051    if (FAL_SPEED_1000 == old_speed)
1052    {
1053        phy_data |= F1_CTRL_SPEED_1000;
1054    }
1055    else if (FAL_SPEED_100 == old_speed)
1056    {
1057        phy_data |= F1_CTRL_SPEED_100;
1058    }
1059    else if (FAL_SPEED_10 == old_speed)
1060    {
1061        phy_data |= F1_CTRL_SPEED_10;
1062    }
1063    else
1064    {
1065        return SW_FAIL;
1066    }
1067
1068    if (duplex == FAL_FULL_DUPLEX)
1069    {
1070        phy_data |= F1_CTRL_FULL_DUPLEX;
1071
1072        if (FAL_SPEED_1000 == old_speed)
1073        {
1074            autoneg = FAL_PHY_ADV_1000T_FD;
1075        }
1076        else if (FAL_SPEED_100 == old_speed)
1077        {
1078            autoneg = FAL_PHY_ADV_100TX_FD;
1079        }
1080        else
1081        {
1082            autoneg = FAL_PHY_ADV_10T_FD;
1083        }
1084    }
1085    else if (duplex == FAL_HALF_DUPLEX)
1086    {
1087        phy_data &= ~F1_CTRL_FULL_DUPLEX;
1088
1089        if (FAL_SPEED_100 == old_speed)
1090        {
1091            autoneg = FAL_PHY_ADV_100TX_HD;
1092        }
1093        else
1094        {
1095            autoneg = FAL_PHY_ADV_10T_HD;
1096        }
1097    }
1098    else
1099    {
1100        return SW_BAD_PARAM;
1101    }
1102
1103    (void)f1_phy_set_autoneg_adv(dev_id, phy_id, autoneg);
1104    (void)f1_phy_restart_autoneg(dev_id, phy_id);
1105    if(f1_phy_get_link_status(dev_id, phy_id))
1106    {
1107        do
1108        {
1109            phy_status = f1_phy_reg_read(dev_id, phy_id, F1_PHY_STATUS);
1110        }
1111        while(!F1_AUTONEG_DONE(phy_status));
1112    }
1113
1114    f1_phy_reg_write(dev_id, phy_id, F1_PHY_CONTROL, phy_data);
1115    (void)f1_phy_set_autoneg_adv(dev_id, phy_id, oldneg);
1116
1117    return SW_OK;
1118}
1119
1120/******************************************************************************
1121*
1122* f1_phy_get_phy_id - get the phy id
1123*
1124*/
1125static sw_error_t
1126f1_phy_get_phy_id(a_uint32_t dev_id, a_uint32_t phy_id,
1127                  a_uint16_t * org_id, a_uint16_t * rev_id)
1128{
1129    *org_id = f1_phy_reg_read(dev_id, phy_id, F1_PHY_ID1);
1130    *rev_id = f1_phy_reg_read(dev_id, phy_id, F1_PHY_ID2);
1131
1132    return SW_OK;
1133}
1134
1135/******************************************************************************
1136*
1137* f1_phy_intr_mask_set - Set interrupt mask with the
1138* specified device.
1139*/
1140sw_error_t
1141f1_phy_intr_mask_set(a_uint32_t dev_id, a_uint32_t phy_id,
1142                     a_uint32_t intr_mask_flag)
1143{
1144    a_uint16_t phy_data = 0;
1145
1146    phy_data = f1_phy_reg_read(dev_id, phy_id, F1_PHY_INTR_MASK);
1147
1148    if (FAL_PHY_INTR_STATUS_UP_CHANGE & intr_mask_flag)
1149    {
1150        phy_data |= F1_INTR_STATUS_UP_CHANGE;
1151    }
1152    else
1153    {
1154        phy_data &= (~F1_INTR_STATUS_UP_CHANGE);
1155    }
1156
1157    if (FAL_PHY_INTR_STATUS_DOWN_CHANGE & intr_mask_flag)
1158    {
1159        phy_data |= F1_INTR_STATUS_DOWN_CHANGE;
1160    }
1161    else
1162    {
1163        phy_data &= (~F1_INTR_STATUS_DOWN_CHANGE);
1164    }
1165
1166    if (FAL_PHY_INTR_SPEED_CHANGE & intr_mask_flag)
1167    {
1168        phy_data |= F1_INTR_SPEED_CHANGE;
1169    }
1170    else
1171    {
1172        phy_data &= (~F1_INTR_SPEED_CHANGE);
1173    }
1174
1175    if (FAL_PHY_INTR_DUPLEX_CHANGE & intr_mask_flag)
1176    {
1177        phy_data |= F1_INTR_DUPLEX_CHANGE;
1178    }
1179    else
1180    {
1181        phy_data &= (~F1_INTR_DUPLEX_CHANGE);
1182    }
1183
1184    f1_phy_reg_write(dev_id, phy_id, F1_PHY_INTR_MASK, phy_data);
1185    return SW_OK;
1186}
1187
1188/******************************************************************************
1189*
1190* f1_phy_intr_mask_get - Get interrupt mask with the
1191* specified device.
1192*/
1193sw_error_t
1194f1_phy_intr_mask_get(a_uint32_t dev_id, a_uint32_t phy_id,
1195                     a_uint32_t * intr_mask_flag)
1196{
1197    a_uint16_t phy_data = 0;
1198
1199    phy_data = f1_phy_reg_read(dev_id, phy_id, F1_PHY_INTR_MASK);
1200
1201    *intr_mask_flag = 0;
1202    if (F1_INTR_STATUS_UP_CHANGE & phy_data)
1203    {
1204        *intr_mask_flag |= FAL_PHY_INTR_STATUS_UP_CHANGE;
1205    }
1206
1207    if (F1_INTR_STATUS_DOWN_CHANGE & phy_data)
1208    {
1209        *intr_mask_flag |= FAL_PHY_INTR_STATUS_DOWN_CHANGE;
1210    }
1211
1212    if (F1_INTR_SPEED_CHANGE & phy_data)
1213    {
1214        *intr_mask_flag |= FAL_PHY_INTR_SPEED_CHANGE;
1215    }
1216
1217    if (F1_INTR_DUPLEX_CHANGE & phy_data)
1218    {
1219        *intr_mask_flag |= FAL_PHY_INTR_DUPLEX_CHANGE;
1220    }
1221
1222    return SW_OK;
1223}
1224
1225/******************************************************************************
1226*
1227* f1_phy_intr_status_get - Get interrupt status with the
1228* specified device.
1229*/
1230sw_error_t
1231f1_phy_intr_status_get(a_uint32_t dev_id, a_uint32_t phy_id,
1232                       a_uint32_t * intr_status_flag)
1233{
1234    a_uint16_t phy_data = 0;
1235
1236    phy_data = f1_phy_reg_read(dev_id, phy_id, F1_PHY_INTR_STATUS);
1237
1238    *intr_status_flag = 0;
1239    if (F1_INTR_STATUS_UP_CHANGE & phy_data)
1240    {
1241        *intr_status_flag |= FAL_PHY_INTR_STATUS_UP_CHANGE;
1242    }
1243
1244    if (F1_INTR_STATUS_DOWN_CHANGE & phy_data)
1245    {
1246        *intr_status_flag |= FAL_PHY_INTR_STATUS_DOWN_CHANGE;
1247    }
1248
1249    if (F1_INTR_SPEED_CHANGE & phy_data)
1250    {
1251        *intr_status_flag |= FAL_PHY_INTR_SPEED_CHANGE;
1252    }
1253
1254    if (F1_INTR_DUPLEX_CHANGE & phy_data)
1255    {
1256        *intr_status_flag |= FAL_PHY_INTR_DUPLEX_CHANGE;
1257    }
1258
1259    return SW_OK;
1260}
1261
1262
1263#if 0
1264/******************************************************************************
1265*
1266* f1_phy_init -
1267*
1268*/
1269a_bool_t
1270f1_phy_init(a_uint32_t dev_id, a_uint32_t phy_id,
1271            a_uint16_t org_id, a_uint16_t rev_id)
1272{
1273    a_uint16_t org_tmp, rev_tmp;
1274
1275    (void)f1_phy_get_phy_id(dev_id, phy_id, &org_tmp, &rev_tmp);
1276    if ((org_id == org_tmp) && (rev_id == rev_tmp))
1277        return A_TRUE;
1278    else
1279        return A_FALSE;
1280}
1281
1282#endif
1283
1284static int f1_phy_probe(struct phy_device *pdev)
1285{
1286	int ret;
1287	hsl_phy_ops_t f1_phy_api_ops = { 0 };
1288
1289	f1_phy_api_ops.phy_hibernation_set = f1_phy_set_hibernate;
1290	f1_phy_api_ops.phy_hibernation_get = f1_phy_get_hibernate;
1291	f1_phy_api_ops.phy_speed_get = f1_phy_get_speed;
1292	f1_phy_api_ops.phy_speed_set = f1_phy_set_speed;
1293	f1_phy_api_ops.phy_duplex_get = f1_phy_get_duplex;
1294	f1_phy_api_ops.phy_duplex_set = f1_phy_set_duplex;
1295	f1_phy_api_ops.phy_autoneg_enable_set = f1_phy_enable_autoneg;
1296	f1_phy_api_ops.phy_restart_autoneg = f1_phy_restart_autoneg;
1297	f1_phy_api_ops.phy_autoneg_status_get = f1_phy_autoneg_status;
1298	f1_phy_api_ops.phy_autoneg_adv_set = f1_phy_set_autoneg_adv;
1299	f1_phy_api_ops.phy_autoneg_adv_get = f1_phy_get_autoneg_adv;
1300	f1_phy_api_ops.phy_powersave_set = f1_phy_set_powersave;
1301	f1_phy_api_ops.phy_powersave_get = f1_phy_get_powersave;
1302	f1_phy_api_ops.phy_cdt = f1_phy_cdt;
1303	f1_phy_api_ops.phy_link_status_get = f1_phy_get_link_status;
1304	f1_phy_api_ops.phy_reset = f1_phy_reset;
1305	f1_phy_api_ops.phy_power_off = f1_phy_poweroff;
1306	f1_phy_api_ops.phy_power_on = 	f1_phy_poweron;
1307	f1_phy_api_ops.phy_id_get = f1_phy_get_phy_id;
1308	f1_phy_api_ops.phy_reg_write = f1_phy_reg_write;
1309	f1_phy_api_ops.phy_reg_read = f1_phy_reg_read;
1310	f1_phy_api_ops.phy_debug_write = f1_phy_debug_write;
1311	f1_phy_api_ops.phy_debug_read = f1_phy_debug_read;
1312	f1_phy_api_ops.phy_mmd_write = f1_phy_mmd_write;
1313	f1_phy_api_ops.phy_mmd_read = f1_phy_mmd_read;
1314	f1_phy_api_ops.phy_intr_mask_set = f1_phy_intr_mask_set;
1315	f1_phy_api_ops.phy_intr_mask_get = f1_phy_intr_mask_get;
1316	f1_phy_api_ops.phy_intr_status_get = f1_phy_intr_status_get;
1317	ret = hsl_phy_api_ops_register(&f1_phy_api_ops);
1318
1319	if (ret == 0)
1320		printk("qca probe f1 phy driver succeeded!\n");
1321	else
1322		printk("qca probe f1 phy driver failed! (code: %d)\n", ret);
1323	return ret;
1324}
1325
1326int f1_phy_init(void)
1327{
1328	phy_api_ops_init(0);
1329	return f1_phy_probe((struct phy_device *)NULL);
1330}
1331
1332