uboot/drivers/usb/host/ohci-sunxi.c
<<
>>
Prefs
   1/*
   2 * Sunxi ohci glue
   3 *
   4 * Copyright (C) 2015 Hans de Goede <hdegoede@redhat.com>
   5 *
   6 * Based on code from
   7 * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
   8 *
   9 * SPDX-License-Identifier:     GPL-2.0+
  10 */
  11
  12#include <common.h>
  13#include <asm/arch/clock.h>
  14#include <asm/arch/usb_phy.h>
  15#include <asm/io.h>
  16#include <dm.h>
  17#include <usb.h>
  18#include "ohci.h"
  19
  20#ifdef CONFIG_SUNXI_GEN_SUN4I
  21#define BASE_DIST               0x8000
  22#define AHB_CLK_DIST            2
  23#else
  24#define BASE_DIST               0x1000
  25#define AHB_CLK_DIST            1
  26#endif
  27
  28struct ohci_sunxi_priv {
  29        ohci_t ohci;
  30        int ahb_gate_mask; /* Mask of ahb_gate0 clk gate bits for this hcd */
  31        int usb_gate_mask; /* Mask of usb_clk_cfg clk gate bits for this hcd */
  32        int phy_index;     /* Index of the usb-phy attached to this hcd */
  33};
  34
  35static int ohci_usb_probe(struct udevice *dev)
  36{
  37        struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
  38        struct usb_bus_priv *bus_priv = dev_get_uclass_priv(dev);
  39        struct ohci_sunxi_priv *priv = dev_get_priv(dev);
  40        struct ohci_regs *regs = (struct ohci_regs *)devfdt_get_addr(dev);
  41        int extra_ahb_gate_mask = 0;
  42
  43        bus_priv->companion = true;
  44
  45        /*
  46         * This should go away once we've moved to the driver model for
  47         * clocks resp. phys.
  48         */
  49        priv->ahb_gate_mask = 1 << AHB_GATE_OFFSET_USB_OHCI0;
  50#ifdef CONFIG_MACH_SUN8I_H3
  51        extra_ahb_gate_mask = 1 << AHB_GATE_OFFSET_USB_EHCI0;
  52#endif
  53        priv->usb_gate_mask = CCM_USB_CTRL_OHCI0_CLK;
  54        priv->phy_index = ((uintptr_t)regs - (SUNXI_USB1_BASE + 0x400)) / BASE_DIST;
  55        priv->ahb_gate_mask <<= priv->phy_index * AHB_CLK_DIST;
  56        extra_ahb_gate_mask <<= priv->phy_index * AHB_CLK_DIST;
  57        priv->usb_gate_mask <<= priv->phy_index;
  58        priv->phy_index++; /* Non otg phys start at 1 */
  59
  60        setbits_le32(&ccm->ahb_gate0,
  61                     priv->ahb_gate_mask | extra_ahb_gate_mask);
  62        setbits_le32(&ccm->usb_clk_cfg, priv->usb_gate_mask);
  63#ifdef CONFIG_SUNXI_GEN_SUN6I
  64        setbits_le32(&ccm->ahb_reset0_cfg,
  65                     priv->ahb_gate_mask | extra_ahb_gate_mask);
  66#endif
  67
  68        sunxi_usb_phy_init(priv->phy_index);
  69        sunxi_usb_phy_power_on(priv->phy_index);
  70
  71        return ohci_register(dev, regs);
  72}
  73
  74static int ohci_usb_remove(struct udevice *dev)
  75{
  76        struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
  77        struct ohci_sunxi_priv *priv = dev_get_priv(dev);
  78        int ret;
  79
  80        ret = ohci_deregister(dev);
  81        if (ret)
  82                return ret;
  83
  84        sunxi_usb_phy_exit(priv->phy_index);
  85
  86#ifdef CONFIG_SUNXI_GEN_SUN6I
  87        clrbits_le32(&ccm->ahb_reset0_cfg, priv->ahb_gate_mask);
  88#endif
  89        clrbits_le32(&ccm->usb_clk_cfg, priv->usb_gate_mask);
  90        clrbits_le32(&ccm->ahb_gate0, priv->ahb_gate_mask);
  91
  92        return 0;
  93}
  94
  95static const struct udevice_id ohci_usb_ids[] = {
  96        { .compatible = "allwinner,sun4i-a10-ohci", },
  97        { .compatible = "allwinner,sun5i-a13-ohci", },
  98        { .compatible = "allwinner,sun6i-a31-ohci", },
  99        { .compatible = "allwinner,sun7i-a20-ohci", },
 100        { .compatible = "allwinner,sun8i-a23-ohci", },
 101        { .compatible = "allwinner,sun8i-a83t-ohci", },
 102        { .compatible = "allwinner,sun8i-h3-ohci",  },
 103        { .compatible = "allwinner,sun9i-a80-ohci", },
 104        { .compatible = "allwinner,sun50i-a64-ohci", },
 105        { }
 106};
 107
 108U_BOOT_DRIVER(usb_ohci) = {
 109        .name   = "ohci_sunxi",
 110        .id     = UCLASS_USB,
 111        .of_match = ohci_usb_ids,
 112        .probe = ohci_usb_probe,
 113        .remove = ohci_usb_remove,
 114        .ops    = &ohci_usb_ops,
 115        .platdata_auto_alloc_size = sizeof(struct usb_platdata),
 116        .priv_auto_alloc_size = sizeof(struct ohci_sunxi_priv),
 117        .flags  = DM_FLAG_ALLOC_PRIV_DMA,
 118};
 119