blob: 93c87e998c4f3923213d60e3096bee1ef6cd7a40 [file] [log] [blame]
Mario Sixd2166312018-08-06 10:23:46 +02001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * (C) Copyright 2018
4 * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
5 *
6 * base on the MPC83xx serdes initialization, which is
7 *
8 * Copyright 2007,2011 Freescale Semiconductor, Inc.
9 * Copyright (C) 2008 MontaVista Software, Inc.
10 */
11
12#include <common.h>
13#include <dm.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -060014#include <log.h>
Mario Sixd2166312018-08-06 10:23:46 +020015#include <mapmem.h>
16#include <misc.h>
Simon Glassc05ed002020-05-10 11:40:11 -060017#include <linux/delay.h>
Mario Sixd2166312018-08-06 10:23:46 +020018
19#include "mpc83xx_serdes.h"
20
21/**
22 * struct mpc83xx_serdes_priv - Private structure for MPC83xx serdes
23 * @regs: The device's register map
24 * @rfcks: Variable to keep the serdes reference clock selection set during
25 * initialization in (is or'd to every value written to SRDSCR4)
26 */
27struct mpc83xx_serdes_priv {
28 struct mpc83xx_serdes_regs *regs;
29 u32 rfcks;
30};
31
32/**
33 * setup_sata() - Configure the SerDes device to SATA mode
34 * @dev: The device to configure
35 */
36static void setup_sata(struct udevice *dev)
37{
38 struct mpc83xx_serdes_priv *priv = dev_get_priv(dev);
39
40 /* Set and clear reset bits */
41 setbits_be32(&priv->regs->srdsrstctl, SRDSRSTCTL_SATA_RESET);
42 udelay(1000);
43 clrbits_be32(&priv->regs->srdsrstctl, SRDSRSTCTL_SATA_RESET);
44
45 /* Configure SRDSCR0 */
46 clrsetbits_be32(&priv->regs->srdscr0,
47 SRDSCR0_TXEQA_MASK | SRDSCR0_TXEQE_MASK,
48 SRDSCR0_TXEQA_SATA | SRDSCR0_TXEQE_SATA);
49
50 /* Configure SRDSCR1 */
51 clrbits_be32(&priv->regs->srdscr1, SRDSCR1_PLLBW);
52
53 /* Configure SRDSCR2 */
54 clrsetbits_be32(&priv->regs->srdscr2,
55 SRDSCR2_SEIC_MASK,
56 SRDSCR2_SEIC_SATA);
57
58 /* Configure SRDSCR3 */
59 out_be32(&priv->regs->srdscr3,
60 SRDSCR3_KFR_SATA | SRDSCR3_KPH_SATA |
61 SRDSCR3_SDFM_SATA_PEX | SRDSCR3_SDTXL_SATA);
62
63 /* Configure SRDSCR4 */
64 out_be32(&priv->regs->srdscr4, priv->rfcks | SRDSCR4_PROT_SATA);
65}
66
67/**
68 * setup_pex() - Configure the SerDes device to PCI Express mode
69 * @dev: The device to configure
70 * @type: The PCI Express type to configure for (x1 or x2)
71 */
72static void setup_pex(struct udevice *dev, enum pex_type type)
73{
74 struct mpc83xx_serdes_priv *priv = dev_get_priv(dev);
75
76 /* Configure SRDSCR1 */
77 setbits_be32(&priv->regs->srdscr1, SRDSCR1_PLLBW);
78
79 /* Configure SRDSCR2 */
80 clrsetbits_be32(&priv->regs->srdscr2,
81 SRDSCR2_SEIC_MASK,
82 SRDSCR2_SEIC_PEX);
83
84 /* Configure SRDSCR3 */
85 out_be32(&priv->regs->srdscr3, SRDSCR3_SDFM_SATA_PEX);
86
87 /* Configure SRDSCR4 */
88 if (type == PEX_X2)
89 out_be32(&priv->regs->srdscr4,
90 priv->rfcks | SRDSCR4_PROT_PEX | SRDSCR4_PLANE_X2);
91 else
92 out_be32(&priv->regs->srdscr4,
93 priv->rfcks | SRDSCR4_PROT_PEX);
94}
95
96/**
97 * setup_sgmii() - Configure the SerDes device to SGMII mode
98 * @dev: The device to configure
99 */
100static void setup_sgmii(struct udevice *dev)
101{
102 struct mpc83xx_serdes_priv *priv = dev_get_priv(dev);
103
104 /* Configure SRDSCR1 */
105 clrbits_be32(&priv->regs->srdscr1, SRDSCR1_PLLBW);
106
107 /* Configure SRDSCR2 */
108 clrsetbits_be32(&priv->regs->srdscr2,
109 SRDSCR2_SEIC_MASK,
110 SRDSCR2_SEIC_SGMII);
111
112 /* Configure SRDSCR3 */
113 out_be32(&priv->regs->srdscr3, 0);
114
115 /* Configure SRDSCR4 */
116 out_be32(&priv->regs->srdscr4, priv->rfcks | SRDSCR4_PROT_SGMII);
117}
118
119static int mpc83xx_serdes_probe(struct udevice *dev)
120{
121 struct mpc83xx_serdes_priv *priv = dev_get_priv(dev);
122 bool vdd;
123 const char *proto;
124
125 priv->regs = map_sysmem(dev_read_addr(dev),
126 sizeof(struct mpc83xx_serdes_regs));
127
128 switch (dev_read_u32_default(dev, "serdes-clk", -1)) {
129 case 100:
130 priv->rfcks = SRDSCR4_RFCKS_100;
131 break;
132 case 125:
133 priv->rfcks = SRDSCR4_RFCKS_125;
134 break;
135 case 150:
136 priv->rfcks = SRDSCR4_RFCKS_150;
137 break;
138 default:
139 debug("%s: Could not read serdes clock value\n", dev->name);
140 return -EINVAL;
141 }
142
143 vdd = dev_read_bool(dev, "vdd");
144
145 /* 1.0V corevdd */
146 if (vdd) {
147 /* DPPE/DPPA = 0 */
148 clrbits_be32(&priv->regs->srdscr0, SRDSCR0_DPP_1V2);
149
150 /* VDD = 0 */
151 clrbits_be32(&priv->regs->srdscr0, SRDSCR2_VDD_1V2);
152 }
153
154 proto = dev_read_string(dev, "proto");
155
156 /* protocol specific configuration */
157 if (!strcmp(proto, "sata")) {
158 setup_sata(dev);
159 } else if (!strcmp(proto, "pex")) {
160 setup_pex(dev, PEX_X1);
161 } else if (!strcmp(proto, "pex-x2")) {
162 setup_pex(dev, PEX_X2);
163 } else if (!strcmp(proto, "sgmii")) {
164 setup_sgmii(dev);
165 } else {
166 debug("%s: Invalid protocol value %s\n", dev->name, proto);
167 return -EINVAL;
168 }
169
170 /* Do a software reset */
171 setbits_be32(&priv->regs->srdsrstctl, SRDSRSTCTL_RST);
172
173 return 0;
174}
175
176static const struct udevice_id mpc83xx_serdes_ids[] = {
177 { .compatible = "fsl,mpc83xx-serdes" },
178 { }
179};
180
181U_BOOT_DRIVER(mpc83xx_serdes) = {
182 .name = "mpc83xx_serdes",
183 .id = UCLASS_MISC,
184 .of_match = mpc83xx_serdes_ids,
185 .probe = mpc83xx_serdes_probe,
Simon Glass41575d82020-12-03 16:55:17 -0700186 .priv_auto = sizeof(struct mpc83xx_serdes_priv),
Mario Sixd2166312018-08-06 10:23:46 +0200187};