Linux Audio

Check our new training course

Embedded Linux training

Mar 10-20, 2025, special US time zones
Register
Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * xHCI host controller driver for HiSilicon STB SoCs
  4 *
  5 * Copyright (C) 2017-2018 HiSilicon Co., Ltd. http://www.hisilicon.com
  6 *
  7 * Authors: Jianguo Sun <sunjianguo1@huawei.com>
  8 */
  9
 10#include <linux/clk.h>
 11#include <linux/dma-mapping.h>
 12#include <linux/kernel.h>
 13#include <linux/module.h>
 14#include <linux/of.h>
 15#include <linux/platform_device.h>
 16#include <linux/pm_runtime.h>
 17#include <linux/reset.h>
 18
 19#include "xhci.h"
 20
 21#define GTXTHRCFG		0xc108
 22#define GRXTHRCFG		0xc10c
 23#define REG_GUSB2PHYCFG0	0xc200
 24#define BIT_UTMI_8_16		BIT(3)
 25#define BIT_UTMI_ULPI		BIT(4)
 26#define BIT_FREECLK_EXIST	BIT(30)
 27
 28#define REG_GUSB3PIPECTL0	0xc2c0
 29#define USB3_DEEMPHASIS_MASK	GENMASK(2, 1)
 30#define USB3_DEEMPHASIS0	BIT(1)
 31#define USB3_TX_MARGIN1		BIT(4)
 32
 33struct xhci_hcd_histb {
 34	struct device		*dev;
 35	struct usb_hcd		*hcd;
 36	void __iomem		*ctrl;
 37	struct clk		*bus_clk;
 38	struct clk		*utmi_clk;
 39	struct clk		*pipe_clk;
 40	struct clk		*suspend_clk;
 41	struct reset_control	*soft_reset;
 42};
 43
 44static inline struct xhci_hcd_histb *hcd_to_histb(struct usb_hcd *hcd)
 45{
 46	return dev_get_drvdata(hcd->self.controller);
 47}
 48
 49static int xhci_histb_config(struct xhci_hcd_histb *histb)
 50{
 51	struct device_node *np = histb->dev->of_node;
 52	u32 regval;
 53
 54	if (of_property_match_string(np, "phys-names", "inno") >= 0) {
 55		/* USB2 PHY chose ulpi 8bit interface */
 56		regval = readl(histb->ctrl + REG_GUSB2PHYCFG0);
 57		regval &= ~BIT_UTMI_ULPI;
 58		regval &= ~(BIT_UTMI_8_16);
 59		regval &= ~BIT_FREECLK_EXIST;
 60		writel(regval, histb->ctrl + REG_GUSB2PHYCFG0);
 61	}
 62
 63	if (of_property_match_string(np, "phys-names", "combo") >= 0) {
 64		/*
 65		 * write 0x010c0012 to GUSB3PIPECTL0
 66		 * GUSB3PIPECTL0[5:3] = 010 : Tx Margin = 900mV ,
 67		 * decrease TX voltage
 68		 * GUSB3PIPECTL0[2:1] = 01 : Tx Deemphasis = -3.5dB,
 69		 * refer to xHCI spec
 70		 */
 71		regval = readl(histb->ctrl + REG_GUSB3PIPECTL0);
 72		regval &= ~USB3_DEEMPHASIS_MASK;
 73		regval |= USB3_DEEMPHASIS0;
 74		regval |= USB3_TX_MARGIN1;
 75		writel(regval, histb->ctrl + REG_GUSB3PIPECTL0);
 76	}
 77
 78	writel(0x23100000, histb->ctrl + GTXTHRCFG);
 79	writel(0x23100000, histb->ctrl + GRXTHRCFG);
 80
 81	return 0;
 82}
 83
 84static int xhci_histb_clks_get(struct xhci_hcd_histb *histb)
 85{
 86	struct device *dev = histb->dev;
 87
 88	histb->bus_clk = devm_clk_get(dev, "bus");
 89	if (IS_ERR(histb->bus_clk)) {
 90		dev_err(dev, "fail to get bus clk\n");
 91		return PTR_ERR(histb->bus_clk);
 92	}
 93
 94	histb->utmi_clk = devm_clk_get(dev, "utmi");
 95	if (IS_ERR(histb->utmi_clk)) {
 96		dev_err(dev, "fail to get utmi clk\n");
 97		return PTR_ERR(histb->utmi_clk);
 98	}
 99
100	histb->pipe_clk = devm_clk_get(dev, "pipe");
101	if (IS_ERR(histb->pipe_clk)) {
102		dev_err(dev, "fail to get pipe clk\n");
103		return PTR_ERR(histb->pipe_clk);
104	}
105
106	histb->suspend_clk = devm_clk_get(dev, "suspend");
107	if (IS_ERR(histb->suspend_clk)) {
108		dev_err(dev, "fail to get suspend clk\n");
109		return PTR_ERR(histb->suspend_clk);
110	}
111
112	return 0;
113}
114
115static int xhci_histb_host_enable(struct xhci_hcd_histb *histb)
116{
117	int ret;
118
119	ret = clk_prepare_enable(histb->bus_clk);
120	if (ret) {
121		dev_err(histb->dev, "failed to enable bus clk\n");
122		return ret;
123	}
124
125	ret = clk_prepare_enable(histb->utmi_clk);
126	if (ret) {
127		dev_err(histb->dev, "failed to enable utmi clk\n");
128		goto err_utmi_clk;
129	}
130
131	ret = clk_prepare_enable(histb->pipe_clk);
132	if (ret) {
133		dev_err(histb->dev, "failed to enable pipe clk\n");
134		goto err_pipe_clk;
135	}
136
137	ret = clk_prepare_enable(histb->suspend_clk);
138	if (ret) {
139		dev_err(histb->dev, "failed to enable suspend clk\n");
140		goto err_suspend_clk;
141	}
142
143	reset_control_deassert(histb->soft_reset);
144
145	return 0;
146
147err_suspend_clk:
148	clk_disable_unprepare(histb->pipe_clk);
149err_pipe_clk:
150	clk_disable_unprepare(histb->utmi_clk);
151err_utmi_clk:
152	clk_disable_unprepare(histb->bus_clk);
153
154	return ret;
155}
156
157static void xhci_histb_host_disable(struct xhci_hcd_histb *histb)
158{
159	reset_control_assert(histb->soft_reset);
160
161	clk_disable_unprepare(histb->suspend_clk);
162	clk_disable_unprepare(histb->pipe_clk);
163	clk_disable_unprepare(histb->utmi_clk);
164	clk_disable_unprepare(histb->bus_clk);
165}
166
167static void xhci_histb_quirks(struct device *dev, struct xhci_hcd *xhci)
168{
169	/*
170	 * As of now platform drivers don't provide MSI support so we ensure
171	 * here that the generic code does not try to make a pci_dev from our
172	 * dev struct in order to setup MSI
173	 */
174	xhci->quirks |= XHCI_PLAT;
175}
176
177/* called during probe() after chip reset completes */
178static int xhci_histb_setup(struct usb_hcd *hcd)
179{
180	struct xhci_hcd_histb *histb = hcd_to_histb(hcd);
181	int ret;
182
183	if (usb_hcd_is_primary_hcd(hcd)) {
184		ret = xhci_histb_config(histb);
185		if (ret)
186			return ret;
187	}
188
189	return xhci_gen_setup(hcd, xhci_histb_quirks);
190}
191
192static const struct xhci_driver_overrides xhci_histb_overrides __initconst = {
193	.reset = xhci_histb_setup,
194};
195
196static struct hc_driver __read_mostly xhci_histb_hc_driver;
197static int xhci_histb_probe(struct platform_device *pdev)
198{
199	struct device *dev = &pdev->dev;
200	struct xhci_hcd_histb *histb;
201	const struct hc_driver *driver;
202	struct usb_hcd *hcd;
203	struct xhci_hcd *xhci;
204	struct resource *res;
205	int irq;
206	int ret = -ENODEV;
207
208	if (usb_disabled())
209		return -ENODEV;
210
211	driver = &xhci_histb_hc_driver;
212	histb = devm_kzalloc(dev, sizeof(*histb), GFP_KERNEL);
213	if (!histb)
214		return -ENOMEM;
215
216	histb->dev = dev;
217
218	irq = platform_get_irq(pdev, 0);
219	if (irq < 0)
220		return irq;
221
222	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
223	histb->ctrl = devm_ioremap_resource(&pdev->dev, res);
224	if (IS_ERR(histb->ctrl))
225		return PTR_ERR(histb->ctrl);
226
227	ret = xhci_histb_clks_get(histb);
228	if (ret)
229		return ret;
230
231	histb->soft_reset = devm_reset_control_get(dev, "soft");
232	if (IS_ERR(histb->soft_reset)) {
233		dev_err(dev, "failed to get soft reset\n");
234		return PTR_ERR(histb->soft_reset);
235	}
236
237	pm_runtime_enable(dev);
238	pm_runtime_get_sync(dev);
239	device_enable_async_suspend(dev);
240
241	/* Initialize dma_mask and coherent_dma_mask to 32-bits */
242	ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
243	if (ret)
244		return ret;
245
246	hcd = usb_create_hcd(driver, dev, dev_name(dev));
247	if (!hcd) {
248		ret = -ENOMEM;
249		goto disable_pm;
250	}
251
252	hcd->regs = histb->ctrl;
253	hcd->rsrc_start = res->start;
254	hcd->rsrc_len = resource_size(res);
255
256	histb->hcd = hcd;
257	dev_set_drvdata(hcd->self.controller, histb);
258
259	ret = xhci_histb_host_enable(histb);
260	if (ret)
261		goto put_hcd;
262
263	xhci = hcd_to_xhci(hcd);
264
265	device_wakeup_enable(hcd->self.controller);
266
267	xhci->main_hcd = hcd;
268	xhci->shared_hcd = usb_create_shared_hcd(driver, dev, dev_name(dev),
269						 hcd);
270	if (!xhci->shared_hcd) {
271		ret = -ENOMEM;
272		goto disable_host;
273	}
274
275	if (device_property_read_bool(dev, "usb2-lpm-disable"))
276		xhci->quirks |= XHCI_HW_LPM_DISABLE;
277
278	if (device_property_read_bool(dev, "usb3-lpm-capable"))
279		xhci->quirks |= XHCI_LPM_SUPPORT;
280
281	/* imod_interval is the interrupt moderation value in nanoseconds. */
282	xhci->imod_interval = 40000;
283	device_property_read_u32(dev, "imod-interval-ns",
284				 &xhci->imod_interval);
285
286	ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
287	if (ret)
288		goto put_usb3_hcd;
289
290	if (HCC_MAX_PSA(xhci->hcc_params) >= 4)
291		xhci->shared_hcd->can_do_streams = 1;
292
293	ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
294	if (ret)
295		goto dealloc_usb2_hcd;
296
297	device_enable_async_suspend(dev);
298	pm_runtime_put_noidle(dev);
299
300	/*
301	 * Prevent runtime pm from being on as default, users should enable
302	 * runtime pm using power/control in sysfs.
303	 */
304	pm_runtime_forbid(dev);
305
306	return 0;
307
308dealloc_usb2_hcd:
309	usb_remove_hcd(hcd);
310put_usb3_hcd:
311	usb_put_hcd(xhci->shared_hcd);
312disable_host:
313	xhci_histb_host_disable(histb);
314put_hcd:
315	usb_put_hcd(hcd);
316disable_pm:
317	pm_runtime_put_sync(dev);
318	pm_runtime_disable(dev);
319
320	return ret;
321}
322
323static int xhci_histb_remove(struct platform_device *dev)
324{
325	struct xhci_hcd_histb *histb = platform_get_drvdata(dev);
326	struct usb_hcd *hcd = histb->hcd;
327	struct xhci_hcd	*xhci = hcd_to_xhci(hcd);
328	struct usb_hcd *shared_hcd = xhci->shared_hcd;
329
330	xhci->xhc_state |= XHCI_STATE_REMOVING;
331
332	usb_remove_hcd(shared_hcd);
333	xhci->shared_hcd = NULL;
334	device_wakeup_disable(&dev->dev);
335
336	usb_remove_hcd(hcd);
337	usb_put_hcd(shared_hcd);
338
339	xhci_histb_host_disable(histb);
340	usb_put_hcd(hcd);
341	pm_runtime_put_sync(&dev->dev);
342	pm_runtime_disable(&dev->dev);
343
344	return 0;
345}
346
347static int __maybe_unused xhci_histb_suspend(struct device *dev)
348{
349	struct xhci_hcd_histb *histb = dev_get_drvdata(dev);
350	struct usb_hcd *hcd = histb->hcd;
351	struct xhci_hcd	*xhci = hcd_to_xhci(hcd);
352	int ret;
353
354	ret = xhci_suspend(xhci, device_may_wakeup(dev));
355
356	if (!device_may_wakeup(dev))
357		xhci_histb_host_disable(histb);
358
359	return ret;
360}
361
362static int __maybe_unused xhci_histb_resume(struct device *dev)
363{
364	struct xhci_hcd_histb *histb = dev_get_drvdata(dev);
365	struct usb_hcd *hcd = histb->hcd;
366	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
367
368	if (!device_may_wakeup(dev))
369		xhci_histb_host_enable(histb);
370
371	return xhci_resume(xhci, 0);
372}
373
374static const struct dev_pm_ops xhci_histb_pm_ops = {
375	SET_SYSTEM_SLEEP_PM_OPS(xhci_histb_suspend, xhci_histb_resume)
376};
377#define DEV_PM_OPS (IS_ENABLED(CONFIG_PM) ? &xhci_histb_pm_ops : NULL)
378
379#ifdef CONFIG_OF
380static const struct of_device_id histb_xhci_of_match[] = {
381	{ .compatible = "hisilicon,hi3798cv200-xhci"},
382	{ },
383};
384MODULE_DEVICE_TABLE(of, histb_xhci_of_match);
385#endif
386
387static struct platform_driver histb_xhci_driver = {
388	.probe	= xhci_histb_probe,
389	.remove	= xhci_histb_remove,
390	.driver	= {
391		.name = "xhci-histb",
392		.pm = DEV_PM_OPS,
393		.of_match_table = of_match_ptr(histb_xhci_of_match),
394	},
395};
396MODULE_ALIAS("platform:xhci-histb");
397
398static int __init xhci_histb_init(void)
399{
400	xhci_init_driver(&xhci_histb_hc_driver, &xhci_histb_overrides);
401	return platform_driver_register(&histb_xhci_driver);
402}
403module_init(xhci_histb_init);
404
405static void __exit xhci_histb_exit(void)
406{
407	platform_driver_unregister(&histb_xhci_driver);
408}
409module_exit(xhci_histb_exit);
410
411MODULE_DESCRIPTION("HiSilicon STB xHCI Host Controller Driver");
412MODULE_LICENSE("GPL v2");