diff options
Diffstat (limited to 'roms/u-boot/drivers/usb/musb-new/ti-musb.c')
-rw-r--r-- | roms/u-boot/drivers/usb/musb-new/ti-musb.c | 344 |
1 files changed, 344 insertions, 0 deletions
diff --git a/roms/u-boot/drivers/usb/musb-new/ti-musb.c b/roms/u-boot/drivers/usb/musb-new/ti-musb.c new file mode 100644 index 000000000..91042935b --- /dev/null +++ b/roms/u-boot/drivers/usb/musb-new/ti-musb.c @@ -0,0 +1,344 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * MISC driver for TI MUSB Glue. + * + * (C) Copyright 2016 + * Texas Instruments Incorporated, <www.ti.com> + */ +#include <common.h> +#include <command.h> +#include <console.h> +#include <dm.h> +#include <log.h> +#include <malloc.h> +#include <asm/global_data.h> +#include <linux/usb/otg.h> +#include <dm/device-internal.h> +#include <dm/lists.h> + +#include <asm/io.h> +#include <asm/omap_musb.h> +#include "musb_uboot.h" + +DECLARE_GLOBAL_DATA_PTR; + +#if CONFIG_IS_ENABLED(DM_USB) +/* USB 2.0 PHY Control */ +#define CM_PHY_PWRDN (1 << 0) +#define CM_PHY_OTG_PWRDN (1 << 1) +#define OTGVDET_EN (1 << 19) +#define OTGSESSENDEN (1 << 20) + +#define AM335X_USB0_CTRL 0x0 +#define AM335X_USB1_CTRL 0x8 + +static void ti_musb_set_phy_power(struct udevice *dev, u8 on) +{ + struct ti_musb_plat *plat = dev_get_plat(dev); + + if (!plat->ctrl_mod_base) + return; + + if (on) { + clrsetbits_le32(plat->ctrl_mod_base, + CM_PHY_PWRDN | CM_PHY_OTG_PWRDN, + OTGVDET_EN | OTGSESSENDEN); + } else { + clrsetbits_le32(plat->ctrl_mod_base, 0, + CM_PHY_PWRDN | CM_PHY_OTG_PWRDN); + } +} + +#if CONFIG_IS_ENABLED(OF_CONTROL) + +static int ti_musb_get_usb_index(int node) +{ + const void *fdt = gd->fdt_blob; + int i = 0; + char path[64]; + const char *alias_path; + char alias[16]; + + fdt_get_path(fdt, node, path, sizeof(path)); + + do { + snprintf(alias, sizeof(alias), "usb%d", i); + alias_path = fdt_get_alias(fdt, alias); + if (alias_path == NULL) { + debug("USB index not found\n"); + return -ENOENT; + } + + if (!strcmp(path, alias_path)) + return i; + + i++; + } while (alias_path); + + return -ENOENT; +} + +static int ti_musb_of_to_plat(struct udevice *dev) +{ + struct ti_musb_plat *plat = dev_get_plat(dev); + const void *fdt = gd->fdt_blob; + int node = dev_of_offset(dev); + int phys; + int ctrl_mod; + int usb_index; + struct musb_hdrc_config *musb_config; + + plat->base = (void *)devfdt_get_addr_index(dev, 1); + + phys = fdtdec_lookup_phandle(fdt, node, "phys"); + ctrl_mod = fdtdec_lookup_phandle(fdt, phys, "ti,ctrl_mod"); + plat->ctrl_mod_base = (void *)fdtdec_get_addr(fdt, ctrl_mod, "reg"); + usb_index = ti_musb_get_usb_index(node); + switch (usb_index) { + case 1: + plat->ctrl_mod_base += AM335X_USB1_CTRL; + break; + case 0: + plat->ctrl_mod_base += AM335X_USB0_CTRL; + break; + default: + break; + } + + musb_config = malloc(sizeof(struct musb_hdrc_config)); + memset(musb_config, 0, sizeof(struct musb_hdrc_config)); + + musb_config->multipoint = fdtdec_get_int(fdt, node, + "mentor,multipoint", -1); + if (musb_config->multipoint < 0) { + pr_err("MUSB multipoint DT entry missing\n"); + return -ENOENT; + } + + musb_config->dyn_fifo = 1; + + musb_config->num_eps = fdtdec_get_int(fdt, node, "mentor,num-eps", + -1); + if (musb_config->num_eps < 0) { + pr_err("MUSB num-eps DT entry missing\n"); + return -ENOENT; + } + + musb_config->ram_bits = fdtdec_get_int(fdt, node, "mentor,ram-bits", + -1); + if (musb_config->ram_bits < 0) { + pr_err("MUSB ram-bits DT entry missing\n"); + return -ENOENT; + } + + plat->plat.config = musb_config; + + plat->plat.power = fdtdec_get_int(fdt, node, "mentor,power", -1); + if (plat->plat.power < 0) { + pr_err("MUSB mentor,power DT entry missing\n"); + return -ENOENT; + } + + plat->plat.platform_ops = &musb_dsps_ops; + + return 0; +} +#endif + +static int ti_musb_host_probe(struct udevice *dev) +{ + struct musb_host_data *host = dev_get_priv(dev); + struct ti_musb_plat *plat = dev_get_plat(dev); + struct usb_bus_priv *priv = dev_get_uclass_priv(dev); + int ret; + + priv->desc_before_addr = true; + + host->host = musb_init_controller(&plat->plat, + NULL, + plat->base); + if (!host->host) + return -EIO; + + ti_musb_set_phy_power(dev, 1); + ret = musb_lowlevel_init(host); + + return ret; +} + +static int ti_musb_host_remove(struct udevice *dev) +{ + struct musb_host_data *host = dev_get_priv(dev); + + musb_stop(host->host); + ti_musb_set_phy_power(dev, 0); + + return 0; +} + +#if CONFIG_IS_ENABLED(OF_CONTROL) +static int ti_musb_host_of_to_plat(struct udevice *dev) +{ + struct ti_musb_plat *plat = dev_get_plat(dev); + const void *fdt = gd->fdt_blob; + int node = dev_of_offset(dev); + int ret; + + ret = ti_musb_of_to_plat(dev); + if (ret) { + pr_err("plat dt parse error\n"); + return ret; + } + + plat->plat.mode = MUSB_HOST; + + return 0; +} +#endif + +U_BOOT_DRIVER(ti_musb_host) = { + .name = "ti-musb-host", + .id = UCLASS_USB, +#if CONFIG_IS_ENABLED(OF_CONTROL) + .of_to_plat = ti_musb_host_of_to_plat, +#endif + .probe = ti_musb_host_probe, + .remove = ti_musb_host_remove, + .ops = &musb_usb_ops, + .plat_auto = sizeof(struct ti_musb_plat), + .priv_auto = sizeof(struct musb_host_data), +}; + +#if CONFIG_IS_ENABLED(DM_USB_GADGET) +struct ti_musb_peripheral { + struct musb *periph; +}; + +#if CONFIG_IS_ENABLED(OF_CONTROL) +static int ti_musb_peripheral_of_to_plat(struct udevice *dev) +{ + struct ti_musb_plat *plat = dev_get_plat(dev); + const void *fdt = gd->fdt_blob; + int node = dev_of_offset(dev); + int ret; + + ret = ti_musb_of_to_plat(dev); + if (ret) { + pr_err("plat dt parse error\n"); + return ret; + } + plat->plat.mode = MUSB_PERIPHERAL; + + return 0; +} +#endif + +int dm_usb_gadget_handle_interrupts(struct udevice *dev) +{ + struct ti_musb_peripheral *priv = dev_get_priv(dev); + + priv->periph->isr(0, priv->periph); + + return 0; +} + +static int ti_musb_peripheral_probe(struct udevice *dev) +{ + struct ti_musb_peripheral *priv = dev_get_priv(dev); + struct ti_musb_plat *plat = dev_get_plat(dev); + int ret; + + priv->periph = musb_init_controller(&plat->plat, + NULL, + plat->base); + if (!priv->periph) + return -EIO; + + ti_musb_set_phy_power(dev, 1); + musb_gadget_setup(priv->periph); + return usb_add_gadget_udc((struct device *)dev, &priv->periph->g); +} + +static int ti_musb_peripheral_remove(struct udevice *dev) +{ + struct ti_musb_peripheral *priv = dev_get_priv(dev); + + usb_del_gadget_udc(&priv->periph->g); + ti_musb_set_phy_power(dev, 0); + + return 0; +} + +U_BOOT_DRIVER(ti_musb_peripheral) = { + .name = "ti-musb-peripheral", + .id = UCLASS_USB_GADGET_GENERIC, +#if CONFIG_IS_ENABLED(OF_CONTROL) + .of_to_plat = ti_musb_peripheral_of_to_plat, +#endif + .probe = ti_musb_peripheral_probe, + .remove = ti_musb_peripheral_remove, + .ops = &musb_usb_ops, + .plat_auto = sizeof(struct ti_musb_plat), + .priv_auto = sizeof(struct ti_musb_peripheral), + .flags = DM_FLAG_PRE_RELOC, +}; +#endif + +#if CONFIG_IS_ENABLED(OF_CONTROL) +static int ti_musb_wrapper_bind(struct udevice *parent) +{ + ofnode node; + int ret; + + ofnode_for_each_subnode(node, dev_ofnode(parent)) { + struct udevice *dev; + const char *name = ofnode_get_name(node); + enum usb_dr_mode dr_mode; + struct driver *drv; + + if (strncmp(name, "usb@", 4)) + continue; + + dr_mode = usb_get_dr_mode(node); + switch (dr_mode) { + case USB_DR_MODE_PERIPHERAL: + /* Bind MUSB device */ + ret = device_bind_driver_to_node(parent, + "ti-musb-peripheral", + name, + node, + &dev); + if (ret) + pr_err("musb - not able to bind usb peripheral node\n"); + break; + case USB_DR_MODE_HOST: + /* Bind MUSB host */ + ret = device_bind_driver_to_node(parent, + "ti-musb-host", + name, + node, + &dev); + if (ret) + pr_err("musb - not able to bind usb host node\n"); + break; + default: + break; + }; + } + return 0; +} + +static const struct udevice_id ti_musb_ids[] = { + { .compatible = "ti,am33xx-usb" }, + { } +}; + +U_BOOT_DRIVER(ti_musb_wrapper) = { + .name = "ti-musb-wrapper", + .id = UCLASS_MISC, + .of_match = ti_musb_ids, + .bind = ti_musb_wrapper_bind, +}; +#endif /* CONFIG_IS_ENABLED(OF_CONTROL) */ + +#endif /* CONFIG_IS_ENABLED(DM_USB) */ |