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