128b8d5fdSMugunthan V N /* 228b8d5fdSMugunthan V N * MISC driver for TI MUSB Glue. 328b8d5fdSMugunthan V N * 428b8d5fdSMugunthan V N * (C) Copyright 2016 528b8d5fdSMugunthan V N * Texas Instruments Incorporated, <www.ti.com> 628b8d5fdSMugunthan V N * 728b8d5fdSMugunthan V N * SPDX-License-Identifier: GPL-2.0+ 828b8d5fdSMugunthan V N */ 928b8d5fdSMugunthan V N #include <common.h> 1028b8d5fdSMugunthan V N #include <command.h> 1128b8d5fdSMugunthan V N #include <console.h> 1228b8d5fdSMugunthan V N #include <dm.h> 1328b8d5fdSMugunthan V N #include <linux/usb/otg.h> 1428b8d5fdSMugunthan V N #include <dm/device-internal.h> 1528b8d5fdSMugunthan V N #include <dm/lists.h> 1628b8d5fdSMugunthan V N 17ae6acf9fSMugunthan V N #include <asm/io.h> 18ae6acf9fSMugunthan V N #include <asm/omap_musb.h> 19ae6acf9fSMugunthan V N #include "musb_uboot.h" 20ae6acf9fSMugunthan V N 2128b8d5fdSMugunthan V N DECLARE_GLOBAL_DATA_PTR; 2228b8d5fdSMugunthan V N 2328b8d5fdSMugunthan V N #ifdef CONFIG_DM_USB 2428b8d5fdSMugunthan V N 25ae6acf9fSMugunthan V N /* USB 2.0 PHY Control */ 26ae6acf9fSMugunthan V N #define CM_PHY_PWRDN (1 << 0) 27ae6acf9fSMugunthan V N #define CM_PHY_OTG_PWRDN (1 << 1) 28ae6acf9fSMugunthan V N #define OTGVDET_EN (1 << 19) 29ae6acf9fSMugunthan V N #define OTGSESSENDEN (1 << 20) 30ae6acf9fSMugunthan V N 31ae6acf9fSMugunthan V N #define AM335X_USB1_CTRL 0x8 32ae6acf9fSMugunthan V N 33ae6acf9fSMugunthan V N struct ti_musb_platdata { 34ae6acf9fSMugunthan V N void *base; 35ae6acf9fSMugunthan V N void *ctrl_mod_base; 36ae6acf9fSMugunthan V N struct musb_hdrc_platform_data plat; 37ae6acf9fSMugunthan V N struct musb_hdrc_config musb_config; 38ae6acf9fSMugunthan V N struct omap_musb_board_data otg_board_data; 39ae6acf9fSMugunthan V N }; 40ae6acf9fSMugunthan V N 41ae6acf9fSMugunthan V N static int ti_musb_get_usb_index(int node) 42ae6acf9fSMugunthan V N { 43ae6acf9fSMugunthan V N const void *fdt = gd->fdt_blob; 44ae6acf9fSMugunthan V N int i = 0; 45ae6acf9fSMugunthan V N char path[64]; 46ae6acf9fSMugunthan V N const char *alias_path; 47ae6acf9fSMugunthan V N char alias[16]; 48ae6acf9fSMugunthan V N 49ae6acf9fSMugunthan V N fdt_get_path(fdt, node, path, sizeof(path)); 50ae6acf9fSMugunthan V N 51ae6acf9fSMugunthan V N do { 52ae6acf9fSMugunthan V N snprintf(alias, sizeof(alias), "usb%d", i); 53ae6acf9fSMugunthan V N alias_path = fdt_get_alias(fdt, alias); 54ae6acf9fSMugunthan V N if (alias_path == NULL) { 55ae6acf9fSMugunthan V N debug("USB index not found\n"); 56ae6acf9fSMugunthan V N return -ENOENT; 57ae6acf9fSMugunthan V N } 58ae6acf9fSMugunthan V N 59ae6acf9fSMugunthan V N if (!strcmp(path, alias_path)) 60ae6acf9fSMugunthan V N return i; 61ae6acf9fSMugunthan V N 62ae6acf9fSMugunthan V N i++; 63ae6acf9fSMugunthan V N } while (alias_path); 64ae6acf9fSMugunthan V N 65ae6acf9fSMugunthan V N return -ENOENT; 66ae6acf9fSMugunthan V N } 67ae6acf9fSMugunthan V N 68ae6acf9fSMugunthan V N static void ti_musb_set_phy_power(struct udevice *dev, u8 on) 69ae6acf9fSMugunthan V N { 70ae6acf9fSMugunthan V N struct ti_musb_platdata *platdata = dev_get_platdata(dev); 71ae6acf9fSMugunthan V N 72ae6acf9fSMugunthan V N if (on) { 73ae6acf9fSMugunthan V N clrsetbits_le32(platdata->ctrl_mod_base, 74ae6acf9fSMugunthan V N CM_PHY_PWRDN | CM_PHY_OTG_PWRDN, 75ae6acf9fSMugunthan V N OTGVDET_EN | OTGSESSENDEN); 76ae6acf9fSMugunthan V N } else { 77ae6acf9fSMugunthan V N clrsetbits_le32(platdata->ctrl_mod_base, 0, 78ae6acf9fSMugunthan V N CM_PHY_PWRDN | CM_PHY_OTG_PWRDN); 79ae6acf9fSMugunthan V N } 80ae6acf9fSMugunthan V N } 81ae6acf9fSMugunthan V N 82ae6acf9fSMugunthan V N static int ti_musb_ofdata_to_platdata(struct udevice *dev) 83ae6acf9fSMugunthan V N { 84ae6acf9fSMugunthan V N struct ti_musb_platdata *platdata = dev_get_platdata(dev); 85ae6acf9fSMugunthan V N const void *fdt = gd->fdt_blob; 86e160f7d4SSimon Glass int node = dev_of_offset(dev); 87ae6acf9fSMugunthan V N int phys; 88ae6acf9fSMugunthan V N int ctrl_mod; 89ae6acf9fSMugunthan V N int usb_index; 90ae6acf9fSMugunthan V N 91a821c4afSSimon Glass platdata->base = (void *)devfdt_get_addr_index(dev, 1); 92ae6acf9fSMugunthan V N 93ae6acf9fSMugunthan V N phys = fdtdec_lookup_phandle(fdt, node, "phys"); 94ae6acf9fSMugunthan V N ctrl_mod = fdtdec_lookup_phandle(fdt, phys, "ti,ctrl_mod"); 95ae6acf9fSMugunthan V N platdata->ctrl_mod_base = (void *)fdtdec_get_addr(fdt, ctrl_mod, "reg"); 96ae6acf9fSMugunthan V N usb_index = ti_musb_get_usb_index(node); 97ae6acf9fSMugunthan V N switch (usb_index) { 98ae6acf9fSMugunthan V N case 1: 99ae6acf9fSMugunthan V N platdata->ctrl_mod_base += AM335X_USB1_CTRL; 100ae6acf9fSMugunthan V N case 0: 101ae6acf9fSMugunthan V N default: 102ae6acf9fSMugunthan V N break; 103ae6acf9fSMugunthan V N } 104ae6acf9fSMugunthan V N 105ae6acf9fSMugunthan V N platdata->musb_config.multipoint = fdtdec_get_int(fdt, node, 106ae6acf9fSMugunthan V N "mentor,multipoint", 107ae6acf9fSMugunthan V N -1); 108ae6acf9fSMugunthan V N if (platdata->musb_config.multipoint < 0) { 109*9b643e31SMasahiro Yamada pr_err("MUSB multipoint DT entry missing\n"); 110ae6acf9fSMugunthan V N return -ENOENT; 111ae6acf9fSMugunthan V N } 112ae6acf9fSMugunthan V N 113ae6acf9fSMugunthan V N platdata->musb_config.dyn_fifo = 1; 114ae6acf9fSMugunthan V N 115ae6acf9fSMugunthan V N platdata->musb_config.num_eps = fdtdec_get_int(fdt, node, 116ae6acf9fSMugunthan V N "mentor,num-eps", -1); 117ae6acf9fSMugunthan V N if (platdata->musb_config.num_eps < 0) { 118*9b643e31SMasahiro Yamada pr_err("MUSB num-eps DT entry missing\n"); 119ae6acf9fSMugunthan V N return -ENOENT; 120ae6acf9fSMugunthan V N } 121ae6acf9fSMugunthan V N 122ae6acf9fSMugunthan V N platdata->musb_config.ram_bits = fdtdec_get_int(fdt, node, 123ae6acf9fSMugunthan V N "mentor,ram-bits", -1); 124ae6acf9fSMugunthan V N if (platdata->musb_config.ram_bits < 0) { 125*9b643e31SMasahiro Yamada pr_err("MUSB ram-bits DT entry missing\n"); 126ae6acf9fSMugunthan V N return -ENOENT; 127ae6acf9fSMugunthan V N } 128ae6acf9fSMugunthan V N 129ae6acf9fSMugunthan V N platdata->otg_board_data.set_phy_power = ti_musb_set_phy_power; 130ae6acf9fSMugunthan V N platdata->otg_board_data.dev = dev; 131ae6acf9fSMugunthan V N platdata->plat.config = &platdata->musb_config; 132ae6acf9fSMugunthan V N 133ae6acf9fSMugunthan V N platdata->plat.power = fdtdec_get_int(fdt, node, "mentor,power", -1); 134ae6acf9fSMugunthan V N if (platdata->plat.power < 0) { 135*9b643e31SMasahiro Yamada pr_err("MUSB mentor,power DT entry missing\n"); 136ae6acf9fSMugunthan V N return -ENOENT; 137ae6acf9fSMugunthan V N } 138ae6acf9fSMugunthan V N 139ae6acf9fSMugunthan V N platdata->plat.platform_ops = &musb_dsps_ops; 140ae6acf9fSMugunthan V N platdata->plat.board_data = &platdata->otg_board_data; 141ae6acf9fSMugunthan V N 142ae6acf9fSMugunthan V N return 0; 143ae6acf9fSMugunthan V N } 144ae6acf9fSMugunthan V N 145ae6acf9fSMugunthan V N static int ti_musb_host_probe(struct udevice *dev) 146ae6acf9fSMugunthan V N { 147ae6acf9fSMugunthan V N struct musb_host_data *host = dev_get_priv(dev); 148ae6acf9fSMugunthan V N struct ti_musb_platdata *platdata = dev_get_platdata(dev); 149ae6acf9fSMugunthan V N struct usb_bus_priv *priv = dev_get_uclass_priv(dev); 150ae6acf9fSMugunthan V N struct omap_musb_board_data *otg_board_data; 151ae6acf9fSMugunthan V N int ret; 152ae6acf9fSMugunthan V N 153ae6acf9fSMugunthan V N priv->desc_before_addr = true; 154ae6acf9fSMugunthan V N 155ae6acf9fSMugunthan V N otg_board_data = &platdata->otg_board_data; 156ae6acf9fSMugunthan V N 157ae6acf9fSMugunthan V N host->host = musb_init_controller(&platdata->plat, 158ae6acf9fSMugunthan V N (struct device *)otg_board_data, 159ae6acf9fSMugunthan V N platdata->base); 160ae6acf9fSMugunthan V N if (!host->host) 161ae6acf9fSMugunthan V N return -EIO; 162ae6acf9fSMugunthan V N 163ae6acf9fSMugunthan V N ret = musb_lowlevel_init(host); 164ae6acf9fSMugunthan V N 165ae6acf9fSMugunthan V N return ret; 166ae6acf9fSMugunthan V N } 167ae6acf9fSMugunthan V N 168ae6acf9fSMugunthan V N static int ti_musb_host_remove(struct udevice *dev) 169ae6acf9fSMugunthan V N { 170ae6acf9fSMugunthan V N struct musb_host_data *host = dev_get_priv(dev); 171ae6acf9fSMugunthan V N 172ae6acf9fSMugunthan V N musb_stop(host->host); 173ae6acf9fSMugunthan V N 174ae6acf9fSMugunthan V N return 0; 175ae6acf9fSMugunthan V N } 176ae6acf9fSMugunthan V N 177ae6acf9fSMugunthan V N static int ti_musb_host_ofdata_to_platdata(struct udevice *dev) 178ae6acf9fSMugunthan V N { 179ae6acf9fSMugunthan V N struct ti_musb_platdata *platdata = dev_get_platdata(dev); 180ae6acf9fSMugunthan V N const void *fdt = gd->fdt_blob; 181e160f7d4SSimon Glass int node = dev_of_offset(dev); 182ae6acf9fSMugunthan V N int ret; 183ae6acf9fSMugunthan V N 184ae6acf9fSMugunthan V N ret = ti_musb_ofdata_to_platdata(dev); 185ae6acf9fSMugunthan V N if (ret) { 186*9b643e31SMasahiro Yamada pr_err("platdata dt parse error\n"); 187ae6acf9fSMugunthan V N return ret; 188ae6acf9fSMugunthan V N } 189ae6acf9fSMugunthan V N 190ae6acf9fSMugunthan V N platdata->plat.mode = MUSB_HOST; 191ae6acf9fSMugunthan V N 192ae6acf9fSMugunthan V N return 0; 193ae6acf9fSMugunthan V N } 194ae6acf9fSMugunthan V N 195ae6acf9fSMugunthan V N U_BOOT_DRIVER(ti_musb_host) = { 196ae6acf9fSMugunthan V N .name = "ti-musb-host", 197ae6acf9fSMugunthan V N .id = UCLASS_USB, 198ae6acf9fSMugunthan V N .ofdata_to_platdata = ti_musb_host_ofdata_to_platdata, 199ae6acf9fSMugunthan V N .probe = ti_musb_host_probe, 200ae6acf9fSMugunthan V N .remove = ti_musb_host_remove, 201ae6acf9fSMugunthan V N .ops = &musb_usb_ops, 202ae6acf9fSMugunthan V N .platdata_auto_alloc_size = sizeof(struct ti_musb_platdata), 203ae6acf9fSMugunthan V N .priv_auto_alloc_size = sizeof(struct musb_host_data), 204ae6acf9fSMugunthan V N }; 205ae6acf9fSMugunthan V N 20628b8d5fdSMugunthan V N static int ti_musb_wrapper_bind(struct udevice *parent) 20728b8d5fdSMugunthan V N { 20828b8d5fdSMugunthan V N const void *fdt = gd->fdt_blob; 20928b8d5fdSMugunthan V N int node; 21028b8d5fdSMugunthan V N int ret; 21128b8d5fdSMugunthan V N 212e160f7d4SSimon Glass for (node = fdt_first_subnode(fdt, dev_of_offset(parent)); node > 0; 21328b8d5fdSMugunthan V N node = fdt_next_subnode(fdt, node)) { 21428b8d5fdSMugunthan V N struct udevice *dev; 21528b8d5fdSMugunthan V N const char *name = fdt_get_name(fdt, node, NULL); 21628b8d5fdSMugunthan V N enum usb_dr_mode dr_mode; 21728b8d5fdSMugunthan V N struct driver *drv; 21828b8d5fdSMugunthan V N 21928b8d5fdSMugunthan V N if (strncmp(name, "usb@", 4)) 22028b8d5fdSMugunthan V N continue; 22128b8d5fdSMugunthan V N 22228b8d5fdSMugunthan V N dr_mode = usb_get_dr_mode(node); 22328b8d5fdSMugunthan V N switch (dr_mode) { 22428b8d5fdSMugunthan V N case USB_DR_MODE_PERIPHERAL: 22528b8d5fdSMugunthan V N /* Bind MUSB device */ 22628b8d5fdSMugunthan V N break; 22728b8d5fdSMugunthan V N case USB_DR_MODE_HOST: 22828b8d5fdSMugunthan V N /* Bind MUSB host */ 229ae6acf9fSMugunthan V N ret = device_bind_driver_to_node(parent, "ti-musb-host", 23045a26867SSimon Glass name, offset_to_ofnode(node), &dev); 231ae6acf9fSMugunthan V N if (ret) { 232*9b643e31SMasahiro Yamada pr_err("musb - not able to bind usb host node\n"); 233ae6acf9fSMugunthan V N return ret; 234ae6acf9fSMugunthan V N } 23528b8d5fdSMugunthan V N break; 23628b8d5fdSMugunthan V N default: 23728b8d5fdSMugunthan V N break; 23828b8d5fdSMugunthan V N }; 23928b8d5fdSMugunthan V N } 24028b8d5fdSMugunthan V N return 0; 24128b8d5fdSMugunthan V N } 24228b8d5fdSMugunthan V N 24328b8d5fdSMugunthan V N static const struct udevice_id ti_musb_ids[] = { 24428b8d5fdSMugunthan V N { .compatible = "ti,am33xx-usb" }, 24528b8d5fdSMugunthan V N { } 24628b8d5fdSMugunthan V N }; 24728b8d5fdSMugunthan V N 24828b8d5fdSMugunthan V N U_BOOT_DRIVER(ti_musb_wrapper) = { 24928b8d5fdSMugunthan V N .name = "ti-musb-wrapper", 25028b8d5fdSMugunthan V N .id = UCLASS_MISC, 25128b8d5fdSMugunthan V N .of_match = ti_musb_ids, 25228b8d5fdSMugunthan V N .bind = ti_musb_wrapper_bind, 25328b8d5fdSMugunthan V N }; 25428b8d5fdSMugunthan V N 25528b8d5fdSMugunthan V N #endif /* CONFIG_DM_USB */ 256