15db43992SSimon Glass /* 25db43992SSimon Glass * (C) Copyright 2015 Google, Inc 35db43992SSimon Glass * Written by Simon Glass <sjg@chromium.org> 45db43992SSimon Glass * 55db43992SSimon Glass * SPDX-License-Identifier: GPL-2.0+ 65db43992SSimon Glass */ 75db43992SSimon Glass 85db43992SSimon Glass #include <common.h> 95db43992SSimon Glass #include <dm.h> 105db43992SSimon Glass #include <usb.h> 115db43992SSimon Glass #include <dm/device-internal.h> 125db43992SSimon Glass 135db43992SSimon Glass DECLARE_GLOBAL_DATA_PTR; 145db43992SSimon Glass 155db43992SSimon Glass /* We only support up to 8 */ 1680438a6cSSimon Glass #define SANDBOX_NUM_PORTS 4 175db43992SSimon Glass 185db43992SSimon Glass struct sandbox_hub_platdata { 195db43992SSimon Glass struct usb_dev_platdata plat; 205db43992SSimon Glass int port; /* Port number (numbered from 0) */ 215db43992SSimon Glass }; 225db43992SSimon Glass 235db43992SSimon Glass enum { 245db43992SSimon Glass STRING_MANUFACTURER = 1, 255db43992SSimon Glass STRING_PRODUCT, 265db43992SSimon Glass STRING_SERIAL, 275db43992SSimon Glass 285db43992SSimon Glass STRING_count, 295db43992SSimon Glass }; 305db43992SSimon Glass 315db43992SSimon Glass static struct usb_string hub_strings[] = { 325db43992SSimon Glass {STRING_MANUFACTURER, "sandbox"}, 335db43992SSimon Glass {STRING_PRODUCT, "hub"}, 345db43992SSimon Glass {STRING_SERIAL, "2345"}, 35093f2dceSSimon Glass {}, 365db43992SSimon Glass }; 375db43992SSimon Glass 385db43992SSimon Glass static struct usb_device_descriptor hub_device_desc = { 395db43992SSimon Glass .bLength = sizeof(hub_device_desc), 405db43992SSimon Glass .bDescriptorType = USB_DT_DEVICE, 415db43992SSimon Glass 425db43992SSimon Glass .bcdUSB = __constant_cpu_to_le16(0x0200), 435db43992SSimon Glass 445db43992SSimon Glass .bDeviceClass = USB_CLASS_HUB, 455db43992SSimon Glass .bDeviceSubClass = 0, 465db43992SSimon Glass .bDeviceProtocol = 0, 475db43992SSimon Glass 485db43992SSimon Glass .idVendor = __constant_cpu_to_le16(0x1234), 495db43992SSimon Glass .idProduct = __constant_cpu_to_le16(0x5678), 505db43992SSimon Glass .iManufacturer = STRING_MANUFACTURER, 515db43992SSimon Glass .iProduct = STRING_PRODUCT, 525db43992SSimon Glass .iSerialNumber = STRING_SERIAL, 535db43992SSimon Glass .bNumConfigurations = 1, 545db43992SSimon Glass }; 555db43992SSimon Glass 565db43992SSimon Glass static struct usb_config_descriptor hub_config1 = { 575db43992SSimon Glass .bLength = sizeof(hub_config1), 585db43992SSimon Glass .bDescriptorType = USB_DT_CONFIG, 595db43992SSimon Glass 605db43992SSimon Glass /* wTotalLength is set up by usb-emul-uclass */ 615db43992SSimon Glass .bNumInterfaces = 1, 625db43992SSimon Glass .bConfigurationValue = 0, 635db43992SSimon Glass .iConfiguration = 0, 645db43992SSimon Glass .bmAttributes = 1 << 7, 655db43992SSimon Glass .bMaxPower = 50, 665db43992SSimon Glass }; 675db43992SSimon Glass 685db43992SSimon Glass static struct usb_interface_descriptor hub_interface0 = { 695db43992SSimon Glass .bLength = sizeof(hub_interface0), 705db43992SSimon Glass .bDescriptorType = USB_DT_INTERFACE, 715db43992SSimon Glass 725db43992SSimon Glass .bInterfaceNumber = 0, 735db43992SSimon Glass .bAlternateSetting = 0, 745db43992SSimon Glass .bNumEndpoints = 1, 755db43992SSimon Glass .bInterfaceClass = USB_CLASS_HUB, 765db43992SSimon Glass .bInterfaceSubClass = 0, 775db43992SSimon Glass .bInterfaceProtocol = US_PR_CB, 785db43992SSimon Glass .iInterface = 0, 795db43992SSimon Glass }; 805db43992SSimon Glass 815db43992SSimon Glass static struct usb_endpoint_descriptor hub_endpoint0_in = { 825db43992SSimon Glass .bLength = USB_DT_ENDPOINT_SIZE, 835db43992SSimon Glass .bDescriptorType = USB_DT_ENDPOINT, 845db43992SSimon Glass 855db43992SSimon Glass .bEndpointAddress = 1 | USB_DIR_IN, 865db43992SSimon Glass .bmAttributes = USB_ENDPOINT_XFER_INT, 875db43992SSimon Glass .wMaxPacketSize = __constant_cpu_to_le16(1024), 885db43992SSimon Glass .bInterval = 0, 895db43992SSimon Glass }; 905db43992SSimon Glass 915db43992SSimon Glass static struct usb_hub_descriptor hub_desc = { 925db43992SSimon Glass .bLength = sizeof(hub_desc), 935db43992SSimon Glass .bDescriptorType = USB_DT_HUB, 945db43992SSimon Glass .bNbrPorts = SANDBOX_NUM_PORTS, 955db43992SSimon Glass .wHubCharacteristics = __constant_cpu_to_le16(1 << 0 | 1 << 3 | 965db43992SSimon Glass 1 << 7), 975db43992SSimon Glass .bPwrOn2PwrGood = 2, 985db43992SSimon Glass .bHubContrCurrent = 5, 995db43992SSimon Glass .DeviceRemovable = {0, 0xff}, /* all ports removeable */ 1005db43992SSimon Glass #if SANDBOX_NUM_PORTS > 8 1015db43992SSimon Glass #error "This code sets up an incorrect mask" 1025db43992SSimon Glass #endif 1035db43992SSimon Glass }; 1045db43992SSimon Glass 1055db43992SSimon Glass static void *hub_desc_list[] = { 1065db43992SSimon Glass &hub_device_desc, 1075db43992SSimon Glass &hub_config1, 1085db43992SSimon Glass &hub_interface0, 1095db43992SSimon Glass &hub_endpoint0_in, 1105db43992SSimon Glass &hub_desc, 1115db43992SSimon Glass NULL, 1125db43992SSimon Glass }; 1135db43992SSimon Glass 1145db43992SSimon Glass struct sandbox_hub_priv { 1155db43992SSimon Glass int status[SANDBOX_NUM_PORTS]; 1165db43992SSimon Glass int change[SANDBOX_NUM_PORTS]; 1175db43992SSimon Glass }; 1185db43992SSimon Glass 1195db43992SSimon Glass static struct udevice *hub_find_device(struct udevice *hub, int port) 1205db43992SSimon Glass { 1215db43992SSimon Glass struct udevice *dev; 1225db43992SSimon Glass 1235db43992SSimon Glass for (device_find_first_child(hub, &dev); 1245db43992SSimon Glass dev; 1255db43992SSimon Glass device_find_next_child(&dev)) { 1265db43992SSimon Glass struct sandbox_hub_platdata *plat; 1275db43992SSimon Glass 1285db43992SSimon Glass plat = dev_get_parent_platdata(dev); 1295db43992SSimon Glass if (plat->port == port) 1305db43992SSimon Glass return dev; 1315db43992SSimon Glass } 1325db43992SSimon Glass 1335db43992SSimon Glass return NULL; 1345db43992SSimon Glass } 1355db43992SSimon Glass 1365db43992SSimon Glass static int clrset_post_state(struct udevice *hub, int port, int clear, int set) 1375db43992SSimon Glass { 1385db43992SSimon Glass struct sandbox_hub_priv *priv = dev_get_priv(hub); 1395db43992SSimon Glass int *status = &priv->status[port]; 1405db43992SSimon Glass int *change = &priv->change[port]; 1415db43992SSimon Glass int ret = 0; 1425db43992SSimon Glass 1435db43992SSimon Glass if ((clear | set) & USB_PORT_STAT_POWER) { 1445db43992SSimon Glass struct udevice *dev = hub_find_device(hub, port); 1455db43992SSimon Glass 1465db43992SSimon Glass if (dev) { 1475db43992SSimon Glass if (set & USB_PORT_STAT_POWER) { 1485db43992SSimon Glass ret = device_probe(dev); 1495db43992SSimon Glass debug("%s: %s: power on, probed, ret=%d\n", 1505db43992SSimon Glass __func__, dev->name, ret); 1515db43992SSimon Glass if (!ret) { 1525db43992SSimon Glass set |= USB_PORT_STAT_CONNECTION | 1535db43992SSimon Glass USB_PORT_STAT_ENABLE; 1545db43992SSimon Glass } 1555db43992SSimon Glass 1565db43992SSimon Glass } else if (clear & USB_PORT_STAT_POWER) { 1575db43992SSimon Glass debug("%s: %s: power off, removed, ret=%d\n", 1585db43992SSimon Glass __func__, dev->name, ret); 159*706865afSStefan Roese ret = device_remove(dev, DM_REMOVE_NORMAL); 1605db43992SSimon Glass clear |= USB_PORT_STAT_CONNECTION; 1615db43992SSimon Glass } 1625db43992SSimon Glass } 1635db43992SSimon Glass } 1645db43992SSimon Glass *change |= *status & clear; 1655db43992SSimon Glass *change |= ~*status & set; 1665db43992SSimon Glass *change &= 0x1f; 1675db43992SSimon Glass *status = (*status & ~clear) | set; 1685db43992SSimon Glass 1695db43992SSimon Glass return ret; 1705db43992SSimon Glass } 1715db43992SSimon Glass 1725db43992SSimon Glass static int sandbox_hub_submit_control_msg(struct udevice *bus, 1735db43992SSimon Glass struct usb_device *udev, 1745db43992SSimon Glass unsigned long pipe, 1755db43992SSimon Glass void *buffer, int length, 1765db43992SSimon Glass struct devrequest *setup) 1775db43992SSimon Glass { 1785db43992SSimon Glass struct sandbox_hub_priv *priv = dev_get_priv(bus); 1795db43992SSimon Glass int ret = 0; 1805db43992SSimon Glass 1815db43992SSimon Glass if (pipe == usb_rcvctrlpipe(udev, 0)) { 1825db43992SSimon Glass switch (setup->requesttype) { 1835db43992SSimon Glass case USB_RT_HUB | USB_DIR_IN: 1845db43992SSimon Glass switch (setup->request) { 1855db43992SSimon Glass case USB_REQ_GET_STATUS: { 1865db43992SSimon Glass struct usb_hub_status *hubsts = buffer; 1875db43992SSimon Glass 1885db43992SSimon Glass hubsts->wHubStatus = 0; 1895db43992SSimon Glass hubsts->wHubChange = 0; 1905db43992SSimon Glass udev->status = 0; 1915db43992SSimon Glass udev->act_len = sizeof(*hubsts); 1925db43992SSimon Glass return 0; 1935db43992SSimon Glass } 1945db43992SSimon Glass default: 1955db43992SSimon Glass debug("%s: rx ctl requesttype=%x, request=%x\n", 1965db43992SSimon Glass __func__, setup->requesttype, 1975db43992SSimon Glass setup->request); 1985db43992SSimon Glass break; 1995db43992SSimon Glass } 2005db43992SSimon Glass case USB_RT_PORT | USB_DIR_IN: 2015db43992SSimon Glass switch (setup->request) { 2025db43992SSimon Glass case USB_REQ_GET_STATUS: { 2035db43992SSimon Glass struct usb_port_status *portsts = buffer; 2045db43992SSimon Glass int port; 2055db43992SSimon Glass 2065db43992SSimon Glass port = (setup->index & USB_HUB_PORT_MASK) - 1; 2075db43992SSimon Glass portsts->wPortStatus = priv->status[port]; 2085db43992SSimon Glass portsts->wPortChange = priv->change[port]; 2095db43992SSimon Glass udev->status = 0; 2105db43992SSimon Glass udev->act_len = sizeof(*portsts); 2115db43992SSimon Glass return 0; 2125db43992SSimon Glass } 2135db43992SSimon Glass } 2145db43992SSimon Glass default: 2155db43992SSimon Glass debug("%s: rx ctl requesttype=%x, request=%x\n", 2165db43992SSimon Glass __func__, setup->requesttype, setup->request); 2175db43992SSimon Glass break; 2185db43992SSimon Glass } 2195db43992SSimon Glass } else if (pipe == usb_sndctrlpipe(udev, 0)) { 2205db43992SSimon Glass switch (setup->requesttype) { 2215db43992SSimon Glass case USB_RT_PORT: 2225db43992SSimon Glass switch (setup->request) { 2235db43992SSimon Glass case USB_REQ_SET_FEATURE: { 2245db43992SSimon Glass int port; 2255db43992SSimon Glass 2265db43992SSimon Glass port = (setup->index & USB_HUB_PORT_MASK) - 1; 2275db43992SSimon Glass debug("set feature port=%x, feature=%x\n", 2285db43992SSimon Glass port, setup->value); 2295db43992SSimon Glass if (setup->value < USB_PORT_FEAT_C_CONNECTION) { 2305db43992SSimon Glass ret = clrset_post_state(bus, port, 0, 2315db43992SSimon Glass 1 << setup->value); 2325db43992SSimon Glass } else { 2335db43992SSimon Glass debug(" ** Invalid feature\n"); 2345db43992SSimon Glass } 2355db43992SSimon Glass return ret; 2365db43992SSimon Glass } 2375db43992SSimon Glass case USB_REQ_CLEAR_FEATURE: { 2385db43992SSimon Glass int port; 2395db43992SSimon Glass 2405db43992SSimon Glass port = (setup->index & USB_HUB_PORT_MASK) - 1; 2415db43992SSimon Glass debug("clear feature port=%x, feature=%x\n", 2425db43992SSimon Glass port, setup->value); 2435db43992SSimon Glass if (setup->value < USB_PORT_FEAT_C_CONNECTION) { 2445db43992SSimon Glass ret = clrset_post_state(bus, port, 2455db43992SSimon Glass 1 << setup->value, 0); 2465db43992SSimon Glass } else { 2475db43992SSimon Glass priv->change[port] &= 1 << 2485db43992SSimon Glass (setup->value - 16); 2495db43992SSimon Glass } 2505db43992SSimon Glass udev->status = 0; 2515db43992SSimon Glass return 0; 2525db43992SSimon Glass } 2535db43992SSimon Glass default: 2545db43992SSimon Glass debug("%s: tx ctl requesttype=%x, request=%x\n", 2555db43992SSimon Glass __func__, setup->requesttype, 2565db43992SSimon Glass setup->request); 2575db43992SSimon Glass break; 2585db43992SSimon Glass } 2595db43992SSimon Glass default: 2605db43992SSimon Glass debug("%s: tx ctl requesttype=%x, request=%x\n", 2615db43992SSimon Glass __func__, setup->requesttype, setup->request); 2625db43992SSimon Glass break; 2635db43992SSimon Glass } 2645db43992SSimon Glass } 2655db43992SSimon Glass debug("pipe=%lx\n", pipe); 2665db43992SSimon Glass 2675db43992SSimon Glass return -EIO; 2685db43992SSimon Glass } 2695db43992SSimon Glass 2705db43992SSimon Glass static int sandbox_hub_bind(struct udevice *dev) 2715db43992SSimon Glass { 2725db43992SSimon Glass return usb_emul_setup_device(dev, PACKET_SIZE_64, hub_strings, 2735db43992SSimon Glass hub_desc_list); 2745db43992SSimon Glass } 2755db43992SSimon Glass 2765db43992SSimon Glass static int sandbox_child_post_bind(struct udevice *dev) 2775db43992SSimon Glass { 2785db43992SSimon Glass struct sandbox_hub_platdata *plat = dev_get_parent_platdata(dev); 2795db43992SSimon Glass 280e160f7d4SSimon Glass plat->port = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "reg", 281e160f7d4SSimon Glass -1); 2825db43992SSimon Glass 2835db43992SSimon Glass return 0; 2845db43992SSimon Glass } 2855db43992SSimon Glass 2865db43992SSimon Glass static const struct dm_usb_ops sandbox_usb_hub_ops = { 2875db43992SSimon Glass .control = sandbox_hub_submit_control_msg, 2885db43992SSimon Glass }; 2895db43992SSimon Glass 2905db43992SSimon Glass static const struct udevice_id sandbox_usb_hub_ids[] = { 2915db43992SSimon Glass { .compatible = "sandbox,usb-hub" }, 2925db43992SSimon Glass { } 2935db43992SSimon Glass }; 2945db43992SSimon Glass 2955db43992SSimon Glass U_BOOT_DRIVER(usb_sandbox_hub) = { 2965db43992SSimon Glass .name = "usb_sandbox_hub", 2975db43992SSimon Glass .id = UCLASS_USB_EMUL, 2985db43992SSimon Glass .of_match = sandbox_usb_hub_ids, 2995db43992SSimon Glass .bind = sandbox_hub_bind, 3005db43992SSimon Glass .ops = &sandbox_usb_hub_ops, 3015db43992SSimon Glass .priv_auto_alloc_size = sizeof(struct sandbox_hub_priv), 3025db43992SSimon Glass .per_child_platdata_auto_alloc_size = 3035db43992SSimon Glass sizeof(struct sandbox_hub_platdata), 3045db43992SSimon Glass .child_post_bind = sandbox_child_post_bind, 3055db43992SSimon Glass }; 306