Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Copyright (C) 2014 Marvell
  4 * Author: Gregory CLEMENT <gregory.clement@free-electrons.com>
  5 */
  6
  7#include <linux/io.h>
  8#include <linux/mbus.h>
  9#include <linux/of.h>
 10#include <linux/platform_device.h>
 11#include <linux/phy/phy.h>
 12
 13#include <linux/usb.h>
 14#include <linux/usb/hcd.h>
 15
 16#include "xhci-mvebu.h"
 17#include "xhci.h"
 18
 19#define USB3_MAX_WINDOWS	4
 20#define USB3_WIN_CTRL(w)	(0x0 + ((w) * 8))
 21#define USB3_WIN_BASE(w)	(0x4 + ((w) * 8))
 22
 23static void xhci_mvebu_mbus_config(void __iomem *base,
 24			const struct mbus_dram_target_info *dram)
 25{
 26	int win;
 27
 28	/* Clear all existing windows */
 29	for (win = 0; win < USB3_MAX_WINDOWS; win++) {
 30		writel(0, base + USB3_WIN_CTRL(win));
 31		writel(0, base + USB3_WIN_BASE(win));
 32	}
 33
 34	/* Program each DRAM CS in a seperate window */
 35	for (win = 0; win < dram->num_cs; win++) {
 36		const struct mbus_dram_window *cs = dram->cs + win;
 37
 38		writel(((cs->size - 1) & 0xffff0000) | (cs->mbus_attr << 8) |
 39		       (dram->mbus_dram_target_id << 4) | 1,
 40		       base + USB3_WIN_CTRL(win));
 41
 42		writel((cs->base & 0xffff0000), base + USB3_WIN_BASE(win));
 43	}
 44}
 45
 46int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd)
 47{
 48	struct device *dev = hcd->self.controller;
 49	struct platform_device *pdev = to_platform_device(dev);
 50	struct resource	*res;
 51	void __iomem *base;
 52	const struct mbus_dram_target_info *dram;
 53
 54	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
 55	if (!res)
 56		return -ENODEV;
 57
 58	/*
 59	 * We don't use devm_ioremap() because this mapping should
 60	 * only exists for the duration of this probe function.
 61	 */
 62	base = ioremap(res->start, resource_size(res));
 63	if (!base)
 64		return -ENODEV;
 65
 66	dram = mv_mbus_dram_info();
 67	xhci_mvebu_mbus_config(base, dram);
 68
 69	/*
 70	 * This memory area was only needed to configure the MBus
 71	 * windows, and is therefore no longer useful.
 72	 */
 73	iounmap(base);
 74
 75	return 0;
 76}
 77
 78int xhci_mvebu_a3700_plat_setup(struct usb_hcd *hcd)
 79{
 80	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
 81	struct device *dev = hcd->self.controller;
 82	struct phy *phy;
 83	int ret;
 84
 85	/* Old bindings miss the PHY handle */
 86	phy = of_phy_get(dev->of_node, "usb3-phy");
 87	if (IS_ERR(phy) && PTR_ERR(phy) == -EPROBE_DEFER)
 88		return -EPROBE_DEFER;
 89	else if (IS_ERR(phy))
 90		goto phy_out;
 91
 92	ret = phy_init(phy);
 93	if (ret)
 94		goto phy_put;
 95
 96	ret = phy_set_mode(phy, PHY_MODE_USB_HOST_SS);
 97	if (ret)
 98		goto phy_exit;
 99
100	ret = phy_power_on(phy);
101	if (ret == -EOPNOTSUPP) {
102		/* Skip initializatin of XHCI PHY when it is unsupported by firmware */
103		dev_warn(dev, "PHY unsupported by firmware\n");
104		xhci->quirks |= XHCI_SKIP_PHY_INIT;
105	}
106	if (ret)
107		goto phy_exit;
108
109	phy_power_off(phy);
110phy_exit:
111	phy_exit(phy);
112phy_put:
113	of_phy_put(phy);
114phy_out:
115
116	return 0;
117}
118
119int xhci_mvebu_a3700_init_quirk(struct usb_hcd *hcd)
120{
121	struct xhci_hcd	*xhci = hcd_to_xhci(hcd);
122
123	/* Without reset on resume, the HC won't work at all */
124	xhci->quirks |= XHCI_RESET_ON_RESUME;
125
126	return 0;
127}