summaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/qualcomm/emac/emac-sgmii.c
blob: 75c1b530e39e8118f1788d0647988b97df260d23 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

/* Qualcomm Technologies, Inc. EMAC SGMII Controller driver.
 */

#include <linux/iopoll.h>
#include <linux/acpi.h>
#include <linux/of_device.h>
#include "emac.h"
#include "emac-mac.h"
#include "emac-sgmii.h"

/* EMAC_QSERDES register offsets */
#define EMAC_QSERDES_COM_SYS_CLK_CTRL		0x000000
#define EMAC_QSERDES_COM_PLL_CNTRL		0x000014
#define EMAC_QSERDES_COM_PLL_IP_SETI		0x000018
#define EMAC_QSERDES_COM_PLL_CP_SETI		0x000024
#define EMAC_QSERDES_COM_PLL_IP_SETP		0x000028
#define EMAC_QSERDES_COM_PLL_CP_SETP		0x00002c
#define EMAC_QSERDES_COM_SYSCLK_EN_SEL		0x000038
#define EMAC_QSERDES_COM_RESETSM_CNTRL		0x000040
#define EMAC_QSERDES_COM_PLLLOCK_CMP1		0x000044
#define EMAC_QSERDES_COM_PLLLOCK_CMP2		0x000048
#define EMAC_QSERDES_COM_PLLLOCK_CMP3		0x00004c
#define EMAC_QSERDES_COM_PLLLOCK_CMP_EN		0x000050
#define EMAC_QSERDES_COM_DEC_START1		0x000064
#define EMAC_QSERDES_COM_DIV_FRAC_START1	0x000098
#define EMAC_QSERDES_COM_DIV_FRAC_START2	0x00009c
#define EMAC_QSERDES_COM_DIV_FRAC_START3	0x0000a0
#define EMAC_QSERDES_COM_DEC_START2		0x0000a4
#define EMAC_QSERDES_COM_PLL_CRCTRL		0x0000ac
#define EMAC_QSERDES_COM_RESET_SM		0x0000bc
#define EMAC_QSERDES_TX_BIST_MODE_LANENO	0x000100
#define EMAC_QSERDES_TX_TX_EMP_POST1_LVL	0x000108
#define EMAC_QSERDES_TX_TX_DRV_LVL		0x00010c
#define EMAC_QSERDES_TX_LANE_MODE		0x000150
#define EMAC_QSERDES_TX_TRAN_DRVR_EMP_EN	0x000170
#define EMAC_QSERDES_RX_CDR_CONTROL		0x000200
#define EMAC_QSERDES_RX_CDR_CONTROL2		0x000210
#define EMAC_QSERDES_RX_RX_EQ_GAIN12		0x000230

/* EMAC_SGMII register offsets */
#define EMAC_SGMII_PHY_SERDES_START		0x000000
#define EMAC_SGMII_PHY_CMN_PWR_CTRL		0x000004
#define EMAC_SGMII_PHY_RX_PWR_CTRL		0x000008
#define EMAC_SGMII_PHY_TX_PWR_CTRL		0x00000C
#define EMAC_SGMII_PHY_LANE_CTRL1		0x000018
#define EMAC_SGMII_PHY_AUTONEG_CFG2		0x000048
#define EMAC_SGMII_PHY_CDR_CTRL0		0x000058
#define EMAC_SGMII_PHY_SPEED_CFG1		0x000074
#define EMAC_SGMII_PHY_POW_DWN_CTRL0		0x000080
#define EMAC_SGMII_PHY_RESET_CTRL		0x0000a8
#define EMAC_SGMII_PHY_IRQ_CMD			0x0000ac
#define EMAC_SGMII_PHY_INTERRUPT_CLEAR		0x0000b0
#define EMAC_SGMII_PHY_INTERRUPT_MASK		0x0000b4
#define EMAC_SGMII_PHY_INTERRUPT_STATUS		0x0000b8
#define EMAC_SGMII_PHY_RX_CHK_STATUS		0x0000d4
#define EMAC_SGMII_PHY_AUTONEG0_STATUS		0x0000e0
#define EMAC_SGMII_PHY_AUTONEG1_STATUS		0x0000e4

/* EMAC_QSERDES_COM_PLL_IP_SETI */
#define PLL_IPSETI(x)				((x) & 0x3f)

/* EMAC_QSERDES_COM_PLL_CP_SETI */
#define PLL_CPSETI(x)				((x) & 0xff)

/* EMAC_QSERDES_COM_PLL_IP_SETP */
#define PLL_IPSETP(x)				((x) & 0x3f)

/* EMAC_QSERDES_COM_PLL_CP_SETP */
#define PLL_CPSETP(x)				((x) & 0x1f)

/* EMAC_QSERDES_COM_PLL_CRCTRL */
#define PLL_RCTRL(x)				(((x) & 0xf) << 4)
#define PLL_CCTRL(x)				((x) & 0xf)

/* SGMII v2 PHY registers per lane */
#define EMAC_SGMII_PHY_LN_OFFSET		0x0400

/* SGMII v2 digital lane registers */
#define EMAC_SGMII_LN_DRVR_CTRL0		0x00C
#define EMAC_SGMII_LN_DRVR_TAP_EN		0x018
#define EMAC_SGMII_LN_TX_MARGINING		0x01C
#define EMAC_SGMII_LN_TX_PRE			0x020
#define EMAC_SGMII_LN_TX_POST			0x024
#define EMAC_SGMII_LN_TX_BAND_MODE		0x060
#define EMAC_SGMII_LN_LANE_MODE			0x064
#define EMAC_SGMII_LN_PARALLEL_RATE		0x078
#define EMAC_SGMII_LN_CML_CTRL_MODE0		0x0B8
#define EMAC_SGMII_LN_MIXER_CTRL_MODE0		0x0D0
#define EMAC_SGMII_LN_VGA_INITVAL		0x134
#define EMAC_SGMII_LN_UCDR_FO_GAIN_MODE0	0x17C
#define EMAC_SGMII_LN_UCDR_SO_GAIN_MODE0	0x188
#define EMAC_SGMII_LN_UCDR_SO_CONFIG		0x194
#define EMAC_SGMII_LN_RX_BAND			0x19C
#define EMAC_SGMII_LN_RX_RCVR_PATH1_MODE0	0x1B8
#define EMAC_SGMII_LN_RSM_CONFIG		0x1F0
#define EMAC_SGMII_LN_SIGDET_ENABLES		0x224
#define EMAC_SGMII_LN_SIGDET_CNTRL		0x228
#define EMAC_SGMII_LN_SIGDET_DEGLITCH_CNTRL	0x22C
#define EMAC_SGMII_LN_RX_EN_SIGNAL		0x2A0
#define EMAC_SGMII_LN_RX_MISC_CNTRL0		0x2AC
#define EMAC_SGMII_LN_DRVR_LOGIC_CLKDIV		0x2BC

/* SGMII v2 digital lane register values */
#define UCDR_STEP_BY_TWO_MODE0			BIT(7)
#define UCDR_xO_GAIN_MODE(x)			((x) & 0x7f)
#define UCDR_ENABLE				BIT(6)
#define UCDR_SO_SATURATION(x)			((x) & 0x3f)
#define SIGDET_LP_BYP_PS4			BIT(7)
#define SIGDET_EN_PS0_TO_PS2			BIT(6)
#define EN_ACCOUPLEVCM_SW_MUX			BIT(5)
#define EN_ACCOUPLEVCM_SW			BIT(4)
#define RX_SYNC_EN				BIT(3)
#define RXTERM_HIGHZ_PS5			BIT(2)
#define SIGDET_EN_PS3				BIT(1)
#define EN_ACCOUPLE_VCM_PS3			BIT(0)
#define UFS_MODE				BIT(5)
#define TXVAL_VALID_INIT			BIT(4)
#define TXVAL_VALID_MUX				BIT(3)
#define TXVAL_VALID				BIT(2)
#define USB3P1_MODE				BIT(1)
#define KR_PCIGEN3_MODE				BIT(0)
#define PRE_EN					BIT(3)
#define POST_EN					BIT(2)
#define MAIN_EN_MUX				BIT(1)
#define MAIN_EN					BIT(0)
#define TX_MARGINING_MUX			BIT(6)
#define TX_MARGINING(x)				((x) & 0x3f)
#define TX_PRE_MUX				BIT(6)
#define TX_PRE(x)				((x) & 0x3f)
#define TX_POST_MUX				BIT(6)
#define TX_POST(x)				((x) & 0x3f)
#define CML_GEAR_MODE(x)			(((x) & 7) << 3)
#define CML2CMOS_IBOOST_MODE(x)			((x) & 7)
#define MIXER_LOADB_MODE(x)			(((x) & 0xf) << 2)
#define MIXER_DATARATE_MODE(x)			((x) & 3)
#define VGA_THRESH_DFE(x)			((x) & 0x3f)
#define SIGDET_LP_BYP_PS0_TO_PS2		BIT(5)
#define SIGDET_LP_BYP_MUX			BIT(4)
#define SIGDET_LP_BYP				BIT(3)
#define SIGDET_EN_MUX				BIT(2)
#define SIGDET_EN				BIT(1)
#define SIGDET_FLT_BYP				BIT(0)
#define SIGDET_LVL(x)				(((x) & 0xf) << 4)
#define SIGDET_BW_CTRL(x)			((x) & 0xf)
#define SIGDET_DEGLITCH_CTRL(x)			(((x) & 0xf) << 1)
#define SIGDET_DEGLITCH_BYP			BIT(0)
#define INVERT_PCS_RX_CLK			BIT(7)
#define PWM_EN					BIT(6)
#define RXBIAS_SEL(x)				(((x) & 0x3) << 4)
#define EBDAC_SIGN				BIT(3)
#define EDAC_SIGN				BIT(2)
#define EN_AUXTAP1SIGN_INVERT			BIT(1)
#define EN_DAC_CHOPPING				BIT(0)
#define DRVR_LOGIC_CLK_EN			BIT(4)
#define DRVR_LOGIC_CLK_DIV(x)			((x) & 0xf)
#define PARALLEL_RATE_MODE2(x)			(((x) & 0x3) << 4)
#define PARALLEL_RATE_MODE1(x)			(((x) & 0x3) << 2)
#define PARALLEL_RATE_MODE0(x)			((x) & 0x3)
#define BAND_MODE2(x)				(((x) & 0x3) << 4)
#define BAND_MODE1(x)				(((x) & 0x3) << 2)
#define BAND_MODE0(x)				((x) & 0x3)
#define LANE_SYNC_MODE				BIT(5)
#define LANE_MODE(x)				((x) & 0x1f)
#define CDR_PD_SEL_MODE0(x)			(((x) & 0x3) << 5)
#define EN_DLL_MODE0				BIT(4)
#define EN_IQ_DCC_MODE0				BIT(3)
#define EN_IQCAL_MODE0				BIT(2)
#define EN_QPATH_MODE0				BIT(1)
#define EN_EPATH_MODE0				BIT(0)
#define FORCE_TSYNC_ACK				BIT(7)
#define FORCE_CMN_ACK				BIT(6)
#define FORCE_CMN_READY				BIT(5)
#define EN_RCLK_DEGLITCH			BIT(4)
#define BYPASS_RSM_CDR_RESET			BIT(3)
#define BYPASS_RSM_TSYNC			BIT(2)
#define BYPASS_RSM_SAMP_CAL			BIT(1)
#define BYPASS_RSM_DLL_CAL			BIT(0)

/* EMAC_QSERDES_COM_SYS_CLK_CTRL */
#define SYSCLK_CM				BIT(4)
#define SYSCLK_AC_COUPLE			BIT(3)

/* EMAC_QSERDES_COM_PLL_CNTRL */
#define OCP_EN					BIT(5)
#define PLL_DIV_FFEN				BIT(2)
#define PLL_DIV_ORD				BIT(1)

/* EMAC_QSERDES_COM_SYSCLK_EN_SEL */
#define SYSCLK_SEL_CMOS				BIT(3)

/* EMAC_QSERDES_COM_RESETSM_CNTRL */
#define FRQ_TUNE_MODE				BIT(4)

/* EMAC_QSERDES_COM_PLLLOCK_CMP_EN */
#define PLLLOCK_CMP_EN				BIT(0)

/* EMAC_QSERDES_COM_DEC_START1 */
#define DEC_START1_MUX				BIT(7)
#define DEC_START1(x)				((x) & 0x7f)

/* EMAC_QSERDES_COM_DIV_FRAC_START1 * EMAC_QSERDES_COM_DIV_FRAC_START2 */
#define DIV_FRAC_START_MUX			BIT(7)
#define DIV_FRAC_START(x)			((x) & 0x7f)

/* EMAC_QSERDES_COM_DIV_FRAC_START3 */
#define DIV_FRAC_START3_MUX			BIT(4)
#define DIV_FRAC_START3(x)			((x) & 0xf)

/* EMAC_QSERDES_COM_DEC_START2 */
#define DEC_START2_MUX				BIT(1)
#define DEC_START2				BIT(0)

/* EMAC_QSERDES_COM_RESET_SM */
#define READY					BIT(5)

/* EMAC_QSERDES_TX_TX_EMP_POST1_LVL */
#define TX_EMP_POST1_LVL_MUX			BIT(5)
#define TX_EMP_POST1_LVL(x)			((x) & 0x1f)
#define TX_EMP_POST1_LVL_BMSK			0x1f
#define TX_EMP_POST1_LVL_SHFT			0

/* EMAC_QSERDES_TX_TX_DRV_LVL */
#define TX_DRV_LVL_MUX				BIT(4)
#define TX_DRV_LVL(x)				((x) & 0xf)

/* EMAC_QSERDES_TX_TRAN_DRVR_EMP_EN */
#define EMP_EN_MUX				BIT(1)
#define EMP_EN					BIT(0)

/* EMAC_QSERDES_RX_CDR_CONTROL & EMAC_QSERDES_RX_CDR_CONTROL2 */
#define HBW_PD_EN				BIT(7)
#define SECONDORDERENABLE			BIT(6)
#define FIRSTORDER_THRESH(x)			(((x) & 0x7) << 3)
#define SECONDORDERGAIN(x)			((x) & 0x7)

/* EMAC_QSERDES_RX_RX_EQ_GAIN12 */
#define RX_EQ_GAIN2(x)				(((x) & 0xf) << 4)
#define RX_EQ_GAIN1(x)				((x) & 0xf)

/* EMAC_SGMII_PHY_SERDES_START */
#define SERDES_START				BIT(0)

/* EMAC_SGMII_PHY_CMN_PWR_CTRL */
#define BIAS_EN					BIT(6)
#define PLL_EN					BIT(5)
#define SYSCLK_EN				BIT(4)
#define CLKBUF_L_EN				BIT(3)
#define PLL_TXCLK_EN				BIT(1)
#define PLL_RXCLK_EN				BIT(0)

/* EMAC_SGMII_PHY_RX_PWR_CTRL */
#define L0_RX_SIGDET_EN				BIT(7)
#define L0_RX_TERM_MODE(x)			(((x) & 3) << 4)
#define L0_RX_I_EN				BIT(1)

/* EMAC_SGMII_PHY_TX_PWR_CTRL */
#define L0_TX_EN				BIT(5)
#define L0_CLKBUF_EN				BIT(4)
#define L0_TRAN_BIAS_EN				BIT(1)

/* EMAC_SGMII_PHY_LANE_CTRL1 */
#define L0_RX_EQUALIZE_ENABLE			BIT(6)
#define L0_RESET_TSYNC_EN			BIT(4)
#define L0_DRV_LVL(x)				((x) & 0xf)

/* EMAC_SGMII_PHY_AUTONEG_CFG2 */
#define FORCE_AN_TX_CFG				BIT(5)
#define FORCE_AN_RX_CFG				BIT(4)
#define AN_ENABLE				BIT(0)

/* EMAC_SGMII_PHY_SPEED_CFG1 */
#define DUPLEX_MODE				BIT(4)
#define SPDMODE_1000				BIT(1)
#define SPDMODE_100				BIT(0)
#define SPDMODE_10				0
#define SPDMODE_BMSK				3
#define SPDMODE_SHFT				0

/* EMAC_SGMII_PHY_POW_DWN_CTRL0 */
#define PWRDN_B					BIT(0)
#define CDR_MAX_CNT(x)				((x) & 0xff)

/* EMAC_QSERDES_TX_BIST_MODE_LANENO */
#define BIST_LANE_NUMBER(x)			(((x) & 3) << 5)
#define BISTMODE(x)				((x) & 0x1f)

/* EMAC_QSERDES_COM_PLLLOCK_CMPx */
#define PLLLOCK_CMP(x)				((x) & 0xff)

/* EMAC_SGMII_PHY_RESET_CTRL */
#define PHY_SW_RESET				BIT(0)

/* EMAC_SGMII_PHY_IRQ_CMD */
#define IRQ_GLOBAL_CLEAR			BIT(0)

/* EMAC_SGMII_PHY_INTERRUPT_MASK */
#define DECODE_CODE_ERR				BIT(7)
#define DECODE_DISP_ERR				BIT(6)
#define PLL_UNLOCK				BIT(5)
#define AN_ILLEGAL_TERM				BIT(4)
#define SYNC_FAIL				BIT(3)
#define AN_START				BIT(2)
#define AN_END					BIT(1)
#define AN_REQUEST				BIT(0)

#define SGMII_PHY_IRQ_CLR_WAIT_TIME		10

#define SGMII_PHY_INTERRUPT_ERR (\
	DECODE_CODE_ERR         |\
	DECODE_DISP_ERR)

#define SGMII_ISR_AN_MASK       (\
	AN_REQUEST              |\
	AN_START                |\
	AN_END                  |\
	AN_ILLEGAL_TERM         |\
	PLL_UNLOCK              |\
	SYNC_FAIL)

#define SGMII_ISR_MASK          (\
	SGMII_PHY_INTERRUPT_ERR |\
	SGMII_ISR_AN_MASK)

/* SGMII TX_CONFIG */
#define TXCFG_LINK				0x8000
#define TXCFG_MODE_BMSK				0x1c00
#define TXCFG_1000_FULL				0x1800
#define TXCFG_100_FULL				0x1400
#define TXCFG_100_HALF				0x0400
#define TXCFG_10_FULL				0x1000
#define TXCFG_10_HALF				0x0000

#define SERDES_START_WAIT_TIMES			100

struct emac_reg_write {
	unsigned int offset;
	u32 val;
};

static void emac_reg_write_all(void __iomem *base,
			       const struct emac_reg_write *itr, size_t size)
{
	size_t i;

	for (i = 0; i < size; ++itr, ++i)
		writel(itr->val, base + itr->offset);
}

static const struct emac_reg_write physical_coding_sublayer_programming_v1[] = {
	{EMAC_SGMII_PHY_CDR_CTRL0, CDR_MAX_CNT(15)},
	{EMAC_SGMII_PHY_POW_DWN_CTRL0, PWRDN_B},
	{EMAC_SGMII_PHY_CMN_PWR_CTRL,
		BIAS_EN | SYSCLK_EN | CLKBUF_L_EN | PLL_TXCLK_EN | PLL_RXCLK_EN},
	{EMAC_SGMII_PHY_TX_PWR_CTRL, L0_TX_EN | L0_CLKBUF_EN | L0_TRAN_BIAS_EN},
	{EMAC_SGMII_PHY_RX_PWR_CTRL,
		L0_RX_SIGDET_EN | L0_RX_TERM_MODE(1) | L0_RX_I_EN},
	{EMAC_SGMII_PHY_CMN_PWR_CTRL,
		BIAS_EN | PLL_EN | SYSCLK_EN | CLKBUF_L_EN | PLL_TXCLK_EN |
		PLL_RXCLK_EN},
	{EMAC_SGMII_PHY_LANE_CTRL1,
		L0_RX_EQUALIZE_ENABLE | L0_RESET_TSYNC_EN | L0_DRV_LVL(15)},
};

static const struct emac_reg_write sysclk_refclk_setting[] = {
	{EMAC_QSERDES_COM_SYSCLK_EN_SEL, SYSCLK_SEL_CMOS},
	{EMAC_QSERDES_COM_SYS_CLK_CTRL,	SYSCLK_CM | SYSCLK_AC_COUPLE},
};

static const struct emac_reg_write pll_setting[] = {
	{EMAC_QSERDES_COM_PLL_IP_SETI, PLL_IPSETI(1)},
	{EMAC_QSERDES_COM_PLL_CP_SETI, PLL_CPSETI(59)},
	{EMAC_QSERDES_COM_PLL_IP_SETP, PLL_IPSETP(10)},
	{EMAC_QSERDES_COM_PLL_CP_SETP, PLL_CPSETP(9)},
	{EMAC_QSERDES_COM_PLL_CRCTRL, PLL_RCTRL(15) | PLL_CCTRL(11)},
	{EMAC_QSERDES_COM_PLL_CNTRL, OCP_EN | PLL_DIV_FFEN | PLL_DIV_ORD},
	{EMAC_QSERDES_COM_DEC_START1, DEC_START1_MUX | DEC_START1(2)},
	{EMAC_QSERDES_COM_DEC_START2, DEC_START2_MUX | DEC_START2},
	{EMAC_QSERDES_COM_DIV_FRAC_START1,
		DIV_FRAC_START_MUX | DIV_FRAC_START(85)},
	{EMAC_QSERDES_COM_DIV_FRAC_START2,
		DIV_FRAC_START_MUX | DIV_FRAC_START(42)},
	{EMAC_QSERDES_COM_DIV_FRAC_START3,
		DIV_FRAC_START3_MUX | DIV_FRAC_START3(3)},
	{EMAC_QSERDES_COM_PLLLOCK_CMP1, PLLLOCK_CMP(43)},
	{EMAC_QSERDES_COM_PLLLOCK_CMP2, PLLLOCK_CMP(104)},
	{EMAC_QSERDES_COM_PLLLOCK_CMP3, PLLLOCK_CMP(0)},
	{EMAC_QSERDES_COM_PLLLOCK_CMP_EN, PLLLOCK_CMP_EN},
	{EMAC_QSERDES_COM_RESETSM_CNTRL, FRQ_TUNE_MODE},
};

static const struct emac_reg_write cdr_setting[] = {
	{EMAC_QSERDES_RX_CDR_CONTROL,
		SECONDORDERENABLE | FIRSTORDER_THRESH(3) | SECONDORDERGAIN(2)},
	{EMAC_QSERDES_RX_CDR_CONTROL2,
		SECONDORDERENABLE | FIRSTORDER_THRESH(3) | SECONDORDERGAIN(4)},
};

static const struct emac_reg_write tx_rx_setting[] = {
	{EMAC_QSERDES_TX_BIST_MODE_LANENO, 0},
	{EMAC_QSERDES_TX_TX_DRV_LVL, TX_DRV_LVL_MUX | TX_DRV_LVL(15)},
	{EMAC_QSERDES_TX_TRAN_DRVR_EMP_EN, EMP_EN_MUX | EMP_EN},
	{EMAC_QSERDES_TX_TX_EMP_POST1_LVL,
		TX_EMP_POST1_LVL_MUX | TX_EMP_POST1_LVL(1)},
	{EMAC_QSERDES_RX_RX_EQ_GAIN12, RX_EQ_GAIN2(15) | RX_EQ_GAIN1(15)},
	{EMAC_QSERDES_TX_LANE_MODE, LANE_MODE(8)},
};

static const struct emac_reg_write sgmii_v2_laned[] = {
	/* CDR Settings */
	{EMAC_SGMII_LN_UCDR_FO_GAIN_MODE0,
		UCDR_STEP_BY_TWO_MODE0 | UCDR_xO_GAIN_MODE(10)},
	{EMAC_SGMII_LN_UCDR_SO_GAIN_MODE0, UCDR_xO_GAIN_MODE(6)},
	{EMAC_SGMII_LN_UCDR_SO_CONFIG, UCDR_ENABLE | UCDR_SO_SATURATION(12)},

	/* TX/RX Settings */
	{EMAC_SGMII_LN_RX_EN_SIGNAL, SIGDET_LP_BYP_PS4 | SIGDET_EN_PS0_TO_PS2},

	{EMAC_SGMII_LN_DRVR_CTRL0, TXVAL_VALID_INIT | KR_PCIGEN3_MODE},
	{EMAC_SGMII_LN_DRVR_TAP_EN, MAIN_EN},
	{EMAC_SGMII_LN_TX_MARGINING, TX_MARGINING_MUX | TX_MARGINING(25)},
	{EMAC_SGMII_LN_TX_PRE, TX_PRE_MUX},
	{EMAC_SGMII_LN_TX_POST, TX_POST_MUX},

	{EMAC_SGMII_LN_CML_CTRL_MODE0,
		CML_GEAR_MODE(1) | CML2CMOS_IBOOST_MODE(1)},
	{EMAC_SGMII_LN_MIXER_CTRL_MODE0,
		MIXER_LOADB_MODE(12) | MIXER_DATARATE_MODE(1)},
	{EMAC_SGMII_LN_VGA_INITVAL, VGA_THRESH_DFE(31)},
	{EMAC_SGMII_LN_SIGDET_ENABLES,
		SIGDET_LP_BYP_PS0_TO_PS2 | SIGDET_FLT_BYP},
	{EMAC_SGMII_LN_SIGDET_CNTRL, SIGDET_LVL(8)},

	{EMAC_SGMII_LN_SIGDET_DEGLITCH_CNTRL, SIGDET_DEGLITCH_CTRL(4)},
	{EMAC_SGMII_LN_RX_MISC_CNTRL0, 0},
	{EMAC_SGMII_LN_DRVR_LOGIC_CLKDIV,
		DRVR_LOGIC_CLK_EN | DRVR_LOGIC_CLK_DIV(4)},

	{EMAC_SGMII_LN_PARALLEL_RATE, PARALLEL_RATE_MODE0(1)},
	{EMAC_SGMII_LN_TX_BAND_MODE, BAND_MODE0(2)},
	{EMAC_SGMII_LN_RX_BAND, BAND_MODE0(3)},
	{EMAC_SGMII_LN_LANE_MODE, LANE_MODE(26)},
	{EMAC_SGMII_LN_RX_RCVR_PATH1_MODE0, CDR_PD_SEL_MODE0(3)},
	{EMAC_SGMII_LN_RSM_CONFIG, BYPASS_RSM_SAMP_CAL | BYPASS_RSM_DLL_CAL},
};

static const struct emac_reg_write physical_coding_sublayer_programming_v2[] = {
	{EMAC_SGMII_PHY_POW_DWN_CTRL0, PWRDN_B},
	{EMAC_SGMII_PHY_CDR_CTRL0, CDR_MAX_CNT(15)},
	{EMAC_SGMII_PHY_TX_PWR_CTRL, 0},
	{EMAC_SGMII_PHY_LANE_CTRL1, L0_RX_EQUALIZE_ENABLE},
};

static int emac_sgmii_link_init(struct emac_adapter *adpt)
{
	struct phy_device *phydev = adpt->phydev;
	struct emac_phy *phy = &adpt->phy;
	u32 val;

	val = readl(phy->base + EMAC_SGMII_PHY_AUTONEG_CFG2);

	if (phydev->autoneg == AUTONEG_ENABLE) {
		val &= ~(FORCE_AN_RX_CFG | FORCE_AN_TX_CFG);
		val |= AN_ENABLE;
		writel(val, phy->base + EMAC_SGMII_PHY_AUTONEG_CFG2);
	} else {
		u32 speed_cfg;

		switch (phydev->speed) {
		case SPEED_10:
			speed_cfg = SPDMODE_10;
			break;
		case SPEED_100:
			speed_cfg = SPDMODE_100;
			break;
		case SPEED_1000:
			speed_cfg = SPDMODE_1000;
			break;
		default:
			return -EINVAL;
		}

		if (phydev->duplex == DUPLEX_FULL)
			speed_cfg |= DUPLEX_MODE;

		val &= ~AN_ENABLE;
		writel(speed_cfg, phy->base + EMAC_SGMII_PHY_SPEED_CFG1);
		writel(val, phy->base + EMAC_SGMII_PHY_AUTONEG_CFG2);
	}

	return 0;
}

static int emac_sgmii_irq_clear(struct emac_adapter *adpt, u32 irq_bits)
{
	struct emac_phy *phy = &adpt->phy;
	u32 status;

	writel_relaxed(irq_bits, phy->base + EMAC_SGMII_PHY_INTERRUPT_CLEAR);
	writel_relaxed(IRQ_GLOBAL_CLEAR, phy->base + EMAC_SGMII_PHY_IRQ_CMD);
	/* Ensure interrupt clear command is written to HW */
	wmb();

	/* After set the IRQ_GLOBAL_CLEAR bit, the status clearing must
	 * be confirmed before clearing the bits in other registers.
	 * It takes a few cycles for hw to clear the interrupt status.
	 */
	if (readl_poll_timeout_atomic(phy->base +
				      EMAC_SGMII_PHY_INTERRUPT_STATUS,
				      status, !(status & irq_bits), 1,
				      SGMII_PHY_IRQ_CLR_WAIT_TIME)) {
		netdev_err(adpt->netdev,
			   "error: failed clear SGMII irq: status:0x%x bits:0x%x\n",
			   status, irq_bits);
		return -EIO;
	}

	/* Finalize clearing procedure */
	writel_relaxed(0, phy->base + EMAC_SGMII_PHY_IRQ_CMD);
	writel_relaxed(0, phy->base + EMAC_SGMII_PHY_INTERRUPT_CLEAR);

	/* Ensure that clearing procedure finalization is written to HW */
	wmb();

	return 0;
}

int emac_sgmii_init_v1(struct emac_adapter *adpt)
{
	struct emac_phy *phy = &adpt->phy;
	unsigned int i;
	int ret;

	ret = emac_sgmii_link_init(adpt);
	if (ret)
		return ret;

	emac_reg_write_all(phy->base, physical_coding_sublayer_programming_v1,
			   ARRAY_SIZE(physical_coding_sublayer_programming_v1));
	emac_reg_write_all(phy->base, sysclk_refclk_setting,
			   ARRAY_SIZE(sysclk_refclk_setting));
	emac_reg_write_all(phy->base, pll_setting, ARRAY_SIZE(pll_setting));
	emac_reg_write_all(phy->base, cdr_setting, ARRAY_SIZE(cdr_setting));
	emac_reg_write_all(phy->base, tx_rx_setting,
			   ARRAY_SIZE(tx_rx_setting));

	/* Power up the Ser/Des engine */
	writel(SERDES_START, phy->base + EMAC_SGMII_PHY_SERDES_START);

	for (i = 0; i < SERDES_START_WAIT_TIMES; i++) {
		if (readl(phy->base + EMAC_QSERDES_COM_RESET_SM) & READY)
			break;
		usleep_range(100, 200);
	}

	if (i == SERDES_START_WAIT_TIMES) {
		netdev_err(adpt->netdev, "error: ser/des failed to start\n");
		return -EIO;
	}
	/* Mask out all the SGMII Interrupt */
	writel(0, phy->base + EMAC_SGMII_PHY_INTERRUPT_MASK);

	emac_sgmii_irq_clear(adpt, SGMII_PHY_INTERRUPT_ERR);

	return 0;
}

int emac_sgmii_init_v2(struct emac_adapter *adpt)
{
	struct emac_phy *phy = &adpt->phy;
	void __iomem *phy_regs = phy->base;
	void __iomem *laned = phy->digital;
	unsigned int i;
	u32 lnstatus;
	int ret;

	ret = emac_sgmii_link_init(adpt);
	if (ret)
		return ret;

	/* PCS lane-x init */
	emac_reg_write_all(phy->base, physical_coding_sublayer_programming_v2,
			   ARRAY_SIZE(physical_coding_sublayer_programming_v2));

	/* SGMII lane-x init */
	emac_reg_write_all(phy->digital,
			   sgmii_v2_laned, ARRAY_SIZE(sgmii_v2_laned));

	/* Power up PCS and start reset lane state machine */

	writel(0, phy_regs + EMAC_SGMII_PHY_RESET_CTRL);
	writel(1, laned + SGMII_LN_RSM_START);

	/* Wait for c_ready assertion */
	for (i = 0; i < SERDES_START_WAIT_TIMES; i++) {
		lnstatus = readl(phy_regs + SGMII_PHY_LN_LANE_STATUS);
		if (lnstatus & BIT(1))
			break;
		usleep_range(100, 200);
	}

	if (i == SERDES_START_WAIT_TIMES) {
		netdev_err(adpt->netdev, "SGMII failed to start\n");
		return -EIO;
	}

	/* Disable digital and SERDES loopback */
	writel(0, phy_regs + SGMII_PHY_LN_BIST_GEN0);
	writel(0, phy_regs + SGMII_PHY_LN_BIST_GEN2);
	writel(0, phy_regs + SGMII_PHY_LN_CDR_CTRL1);

	/* Mask out all the SGMII Interrupt */
	writel(0, phy_regs + EMAC_SGMII_PHY_INTERRUPT_MASK);

	emac_sgmii_irq_clear(adpt, SGMII_PHY_INTERRUPT_ERR);

	return 0;
}

static void emac_sgmii_reset_prepare(struct emac_adapter *adpt)
{
	struct emac_phy *phy = &adpt->phy;
	u32 val;

	/* Reset PHY */
	val = readl(phy->base + EMAC_EMAC_WRAPPER_CSR2);
	writel(((val & ~PHY_RESET) | PHY_RESET), phy->base +
	       EMAC_EMAC_WRAPPER_CSR2);
	/* Ensure phy-reset command is written to HW before the release cmd */
	msleep(50);
	val = readl(phy->base + EMAC_EMAC_WRAPPER_CSR2);
	writel((val & ~PHY_RESET), phy->base + EMAC_EMAC_WRAPPER_CSR2);
	/* Ensure phy-reset release command is written to HW before initializing
	 * SGMII
	 */
	msleep(50);
}

void emac_sgmii_reset(struct emac_adapter *adpt)
{
	int ret;

	clk_set_rate(adpt->clk[EMAC_CLK_HIGH_SPEED], 19200000);
	emac_sgmii_reset_prepare(adpt);

	ret = adpt->phy.initialize(adpt);
	if (ret)
		netdev_err(adpt->netdev,
			   "could not reinitialize internal PHY (error=%i)\n",
			   ret);

	clk_set_rate(adpt->clk[EMAC_CLK_HIGH_SPEED], 125000000);
}

static int emac_sgmii_acpi_match(struct device *dev, void *data)
{
	static const struct acpi_device_id match_table[] = {
		{
			.id = "QCOM8071",
			.driver_data = (kernel_ulong_t)emac_sgmii_init_v2,
		},
		{}
	};
	const struct acpi_device_id *id = acpi_match_device(match_table, dev);
	emac_sgmii_initialize *initialize = data;

	if (id)
		*initialize = (emac_sgmii_initialize)id->driver_data;

	return !!id;
}

static const struct of_device_id emac_sgmii_dt_match[] = {
	{
		.compatible = "qcom,fsm9900-emac-sgmii",
		.data = emac_sgmii_init_v1,
	},
	{
		.compatible = "qcom,qdf2432-emac-sgmii",
		.data = emac_sgmii_init_v2,
	},
	{}
};

int emac_sgmii_config(struct platform_device *pdev, struct emac_adapter *adpt)
{
	struct platform_device *sgmii_pdev = NULL;
	struct emac_phy *phy = &adpt->phy;
	struct resource *res;
	int ret;

	if (has_acpi_companion(&pdev->dev)) {
		struct device *dev;

		dev = device_find_child(&pdev->dev, &phy->initialize,
					emac_sgmii_acpi_match);

		if (!dev) {
			dev_err(&pdev->dev, "cannot find internal phy node\n");
			return -ENODEV;
		}

		sgmii_pdev = to_platform_device(dev);
	} else {
		const struct of_device_id *match;
		struct device_node *np;

		np = of_parse_phandle(pdev->dev.of_node, "internal-phy", 0);
		if (!np) {
			dev_err(&pdev->dev, "missing internal-phy property\n");
			return -ENODEV;
		}

		sgmii_pdev = of_find_device_by_node(np);
		if (!sgmii_pdev) {
			dev_err(&pdev->dev, "invalid internal-phy property\n");
			return -ENODEV;
		}

		match = of_match_device(emac_sgmii_dt_match, &sgmii_pdev->dev);
		if (!match) {
			dev_err(&pdev->dev, "unrecognized internal phy node\n");
			ret = -ENODEV;
			goto error_put_device;
		}

		phy->initialize = (emac_sgmii_initialize)match->data;
	}

	/* Base address is the first address */
	res = platform_get_resource(sgmii_pdev, IORESOURCE_MEM, 0);
	if (!res) {
		ret = -EINVAL;
		goto error_put_device;
	}

	phy->base = ioremap(res->start, resource_size(res));
	if (!phy->base) {
		ret = -ENOMEM;
		goto error_put_device;
	}

	/* v2 SGMII has a per-lane digital digital, so parse it if it exists */
	res = platform_get_resource(sgmii_pdev, IORESOURCE_MEM, 1);
	if (res) {
		phy->digital = ioremap(res->start, resource_size(res));
		if (!phy->digital) {
			ret = -ENOMEM;
			goto error_unmap_base;
		}
	}

	ret = phy->initialize(adpt);
	if (ret)
		goto error;

	/* We've remapped the addresses, so we don't need the device any
	 * more.  of_find_device_by_node() says we should release it.
	 */
	put_device(&sgmii_pdev->dev);

	return 0;

error:
	if (phy->digital)
		iounmap(phy->digital);
error_unmap_base:
	iounmap(phy->base);
error_put_device:
	put_device(&sgmii_pdev->dev);

	return ret;
}