diff options
Diffstat (limited to 'drivers/pci/controller/pcie-cadence.c')
-rw-r--r-- | drivers/pci/controller/pcie-cadence.c | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/drivers/pci/controller/pcie-cadence.c b/drivers/pci/controller/pcie-cadence.c index 138d113eb45d..2edc12661e44 100644 --- a/drivers/pci/controller/pcie-cadence.c +++ b/drivers/pci/controller/pcie-cadence.c | |||
@@ -124,3 +124,96 @@ void cdns_pcie_reset_outbound_region(struct cdns_pcie *pcie, u32 r) | |||
124 | cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r), 0); | 124 | cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r), 0); |
125 | cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r), 0); | 125 | cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r), 0); |
126 | } | 126 | } |
127 | |||
128 | void cdns_pcie_disable_phy(struct cdns_pcie *pcie) | ||
129 | { | ||
130 | int i = pcie->phy_count; | ||
131 | |||
132 | while (i--) { | ||
133 | phy_power_off(pcie->phy[i]); | ||
134 | phy_exit(pcie->phy[i]); | ||
135 | } | ||
136 | } | ||
137 | |||
138 | int cdns_pcie_enable_phy(struct cdns_pcie *pcie) | ||
139 | { | ||
140 | int ret; | ||
141 | int i; | ||
142 | |||
143 | for (i = 0; i < pcie->phy_count; i++) { | ||
144 | ret = phy_init(pcie->phy[i]); | ||
145 | if (ret < 0) | ||
146 | goto err_phy; | ||
147 | |||
148 | ret = phy_power_on(pcie->phy[i]); | ||
149 | if (ret < 0) { | ||
150 | phy_exit(pcie->phy[i]); | ||
151 | goto err_phy; | ||
152 | } | ||
153 | } | ||
154 | |||
155 | return 0; | ||
156 | |||
157 | err_phy: | ||
158 | while (--i >= 0) { | ||
159 | phy_power_off(pcie->phy[i]); | ||
160 | phy_exit(pcie->phy[i]); | ||
161 | } | ||
162 | |||
163 | return ret; | ||
164 | } | ||
165 | |||
166 | int cdns_pcie_init_phy(struct device *dev, struct cdns_pcie *pcie) | ||
167 | { | ||
168 | struct device_node *np = dev->of_node; | ||
169 | int phy_count; | ||
170 | struct phy **phy; | ||
171 | struct device_link **link; | ||
172 | int i; | ||
173 | int ret; | ||
174 | const char *name; | ||
175 | |||
176 | phy_count = of_property_count_strings(np, "phy-names"); | ||
177 | if (phy_count < 1) { | ||
178 | dev_err(dev, "no phy-names. PHY will not be initialized\n"); | ||
179 | pcie->phy_count = 0; | ||
180 | return 0; | ||
181 | } | ||
182 | |||
183 | phy = devm_kzalloc(dev, sizeof(*phy) * phy_count, GFP_KERNEL); | ||
184 | if (!phy) | ||
185 | return -ENOMEM; | ||
186 | |||
187 | link = devm_kzalloc(dev, sizeof(*link) * phy_count, GFP_KERNEL); | ||
188 | if (!link) | ||
189 | return -ENOMEM; | ||
190 | |||
191 | for (i = 0; i < phy_count; i++) { | ||
192 | of_property_read_string_index(np, "phy-names", i, &name); | ||
193 | phy[i] = devm_phy_optional_get(dev, name); | ||
194 | if (IS_ERR(phy)) | ||
195 | return PTR_ERR(phy); | ||
196 | |||
197 | link[i] = device_link_add(dev, &phy[i]->dev, DL_FLAG_STATELESS); | ||
198 | if (!link[i]) { | ||
199 | ret = -EINVAL; | ||
200 | goto err_link; | ||
201 | } | ||
202 | } | ||
203 | |||
204 | pcie->phy_count = phy_count; | ||
205 | pcie->phy = phy; | ||
206 | pcie->link = link; | ||
207 | |||
208 | ret = cdns_pcie_enable_phy(pcie); | ||
209 | if (ret) | ||
210 | goto err_link; | ||
211 | |||
212 | return 0; | ||
213 | |||
214 | err_link: | ||
215 | while (--i >= 0) | ||
216 | device_link_del(link[i]); | ||
217 | |||
218 | return ret; | ||
219 | } | ||