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