Commit 487bc828 authored by Tao Ren's avatar Tao Ren Committed by Felipe Balbi
Browse files

usb: gadget: aspeed: read vhub properties from device tree



The patch introduces 2 DT properties ("aspeed,vhub-downstream-ports" and
"aspeed,vhub-generic-endpoints") which replaces hardcoded port/endpoint
number. It is to make it more convenient to add support for newer vhub
revisions with different number of ports and endpoints.

Signed-off-by: default avatarTao Ren <rentao.bupt@gmail.com>
Reviewed-by: default avatarJoel Stanley <joel@jms.id.au>
Acked-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: default avatarFelipe Balbi <balbi@kernel.org>
parent 6dbf05fc
Loading
Loading
Loading
Loading
+42 −26
Original line number Diff line number Diff line
@@ -99,7 +99,7 @@ static irqreturn_t ast_vhub_irq(int irq, void *data)
{
	struct ast_vhub *vhub = data;
	irqreturn_t iret = IRQ_NONE;
	u32 istat;
	u32 i, istat;

	/* Stale interrupt while tearing down */
	if (!vhub->ep0_bufs)
@@ -121,10 +121,10 @@ static irqreturn_t ast_vhub_irq(int irq, void *data)

	/* Handle generic EPs first */
	if (istat & VHUB_IRQ_EP_POOL_ACK_STALL) {
		u32 i, ep_acks = readl(vhub->regs + AST_VHUB_EP_ACK_ISR);
		u32 ep_acks = readl(vhub->regs + AST_VHUB_EP_ACK_ISR);
		writel(ep_acks, vhub->regs + AST_VHUB_EP_ACK_ISR);

		for (i = 0; ep_acks && i < AST_VHUB_NUM_GEN_EPs; i++) {
		for (i = 0; ep_acks && i < vhub->max_epns; i++) {
			u32 mask = VHUB_EP_IRQ(i);
			if (ep_acks & mask) {
				ast_vhub_epn_ack_irq(&vhub->epns[i]);
@@ -134,21 +134,11 @@ static irqreturn_t ast_vhub_irq(int irq, void *data)
	}

	/* Handle device interrupts */
	if (istat & (VHUB_IRQ_DEVICE1 |
		     VHUB_IRQ_DEVICE2 |
		     VHUB_IRQ_DEVICE3 |
		     VHUB_IRQ_DEVICE4 |
		     VHUB_IRQ_DEVICE5)) {
		if (istat & VHUB_IRQ_DEVICE1)
			ast_vhub_dev_irq(&vhub->ports[0].dev);
		if (istat & VHUB_IRQ_DEVICE2)
			ast_vhub_dev_irq(&vhub->ports[1].dev);
		if (istat & VHUB_IRQ_DEVICE3)
			ast_vhub_dev_irq(&vhub->ports[2].dev);
		if (istat & VHUB_IRQ_DEVICE4)
			ast_vhub_dev_irq(&vhub->ports[3].dev);
		if (istat & VHUB_IRQ_DEVICE5)
			ast_vhub_dev_irq(&vhub->ports[4].dev);
	for (i = 0; i < vhub->max_ports; i++) {
		u32 dev_mask = VHUB_IRQ_DEVICE1 << i;

		if (istat & dev_mask)
			ast_vhub_dev_irq(&vhub->ports[i].dev);
	}

	/* Handle top-level vHub EP0 interrupts */
@@ -182,7 +172,7 @@ static irqreturn_t ast_vhub_irq(int irq, void *data)

void ast_vhub_init_hw(struct ast_vhub *vhub)
{
	u32 ctrl;
	u32 ctrl, port_mask, epn_mask;

	UDCDBG(vhub,"(Re)Starting HW ...\n");

@@ -222,15 +212,20 @@ void ast_vhub_init_hw(struct ast_vhub *vhub)
	}

	/* Reset all devices */
	writel(VHUB_SW_RESET_ALL, vhub->regs + AST_VHUB_SW_RESET);
	port_mask = GENMASK(vhub->max_ports, 1);
	writel(VHUB_SW_RESET_ROOT_HUB |
	       VHUB_SW_RESET_DMA_CONTROLLER |
	       VHUB_SW_RESET_EP_POOL |
	       port_mask, vhub->regs + AST_VHUB_SW_RESET);
	udelay(1);
	writel(0, vhub->regs + AST_VHUB_SW_RESET);

	/* Disable and cleanup EP ACK/NACK interrupts */
	epn_mask = GENMASK(vhub->max_epns - 1, 0);
	writel(0, vhub->regs + AST_VHUB_EP_ACK_IER);
	writel(0, vhub->regs + AST_VHUB_EP_NACK_IER);
	writel(VHUB_EP_IRQ_ALL, vhub->regs + AST_VHUB_EP_ACK_ISR);
	writel(VHUB_EP_IRQ_ALL, vhub->regs + AST_VHUB_EP_NACK_ISR);
	writel(epn_mask, vhub->regs + AST_VHUB_EP_ACK_ISR);
	writel(epn_mask, vhub->regs + AST_VHUB_EP_NACK_ISR);

	/* Default settings for EP0, enable HW hub EP1 */
	writel(0, vhub->regs + AST_VHUB_EP0_CTRL);
@@ -273,7 +268,7 @@ static int ast_vhub_remove(struct platform_device *pdev)
		return 0;

	/* Remove devices */
	for (i = 0; i < AST_VHUB_NUM_PORTS; i++)
	for (i = 0; i < vhub->max_ports; i++)
		ast_vhub_del_dev(&vhub->ports[i].dev);

	spin_lock_irqsave(&vhub->lock, flags);
@@ -295,7 +290,7 @@ static int ast_vhub_remove(struct platform_device *pdev)
	if (vhub->ep0_bufs)
		dma_free_coherent(&pdev->dev,
				  AST_VHUB_EP0_MAX_PACKET *
				  (AST_VHUB_NUM_PORTS + 1),
				  (vhub->max_ports + 1),
				  vhub->ep0_bufs,
				  vhub->ep0_bufs_dma);
	vhub->ep0_bufs = NULL;
@@ -309,11 +304,32 @@ static int ast_vhub_probe(struct platform_device *pdev)
	struct ast_vhub *vhub;
	struct resource *res;
	int i, rc = 0;
	const struct device_node *np = pdev->dev.of_node;

	vhub = devm_kzalloc(&pdev->dev, sizeof(*vhub), GFP_KERNEL);
	if (!vhub)
		return -ENOMEM;

	rc = of_property_read_u32(np, "aspeed,vhub-downstream-ports",
				  &vhub->max_ports);
	if (rc < 0)
		vhub->max_ports = AST_VHUB_NUM_PORTS;

	vhub->ports = devm_kcalloc(&pdev->dev, vhub->max_ports,
				   sizeof(*vhub->ports), GFP_KERNEL);
	if (!vhub->ports)
		return -ENOMEM;

	rc = of_property_read_u32(np, "aspeed,vhub-generic-endpoints",
				  &vhub->max_epns);
	if (rc < 0)
		vhub->max_epns = AST_VHUB_NUM_GEN_EPs;

	vhub->epns = devm_kcalloc(&pdev->dev, vhub->max_epns,
				  sizeof(*vhub->epns), GFP_KERNEL);
	if (!vhub->epns)
		return -ENOMEM;

	spin_lock_init(&vhub->lock);
	vhub->pdev = pdev;

@@ -366,7 +382,7 @@ static int ast_vhub_probe(struct platform_device *pdev)
	 */
	vhub->ep0_bufs = dma_alloc_coherent(&pdev->dev,
					    AST_VHUB_EP0_MAX_PACKET *
					    (AST_VHUB_NUM_PORTS + 1),
					    (vhub->max_ports + 1),
					    &vhub->ep0_bufs_dma, GFP_KERNEL);
	if (!vhub->ep0_bufs) {
		dev_err(&pdev->dev, "Failed to allocate EP0 DMA buffers\n");
@@ -380,7 +396,7 @@ static int ast_vhub_probe(struct platform_device *pdev)
	ast_vhub_init_ep0(vhub, &vhub->ep0, NULL);

	/* Init devices */
	for (i = 0; i < AST_VHUB_NUM_PORTS && rc == 0; i++)
	for (i = 0; i < vhub->max_ports && rc == 0; i++)
		rc = ast_vhub_init_dev(vhub, i);
	if (rc)
		goto err;
+22 −8
Original line number Diff line number Diff line
@@ -77,7 +77,7 @@ static void ast_vhub_dev_enable(struct ast_vhub_dev *d)
	writel(d->ep0.buf_dma, d->regs + AST_VHUB_DEV_EP0_DATA);

	/* Clear stall on all EPs */
	for (i = 0; i < AST_VHUB_NUM_GEN_EPs; i++) {
	for (i = 0; i < d->max_epns; i++) {
		struct ast_vhub_ep *ep = d->epns[i];

		if (ep && (ep->epn.stalled || ep->epn.wedged)) {
@@ -137,7 +137,7 @@ static int ast_vhub_ep_feature(struct ast_vhub_dev *d,
	     is_set ? "SET" : "CLEAR", ep_num, wValue);
	if (ep_num == 0)
		return std_req_complete;
	if (ep_num >= AST_VHUB_NUM_GEN_EPs || !d->epns[ep_num - 1])
	if (ep_num >= d->max_epns || !d->epns[ep_num - 1])
		return std_req_stall;
	if (wValue != USB_ENDPOINT_HALT)
		return std_req_driver;
@@ -181,7 +181,7 @@ static int ast_vhub_ep_status(struct ast_vhub_dev *d,

	DDBG(d, "GET_STATUS(ep%d)\n", ep_num);

	if (ep_num >= AST_VHUB_NUM_GEN_EPs)
	if (ep_num >= d->max_epns)
		return std_req_stall;
	if (ep_num != 0) {
		ep = d->epns[ep_num - 1];
@@ -299,7 +299,7 @@ static void ast_vhub_dev_nuke(struct ast_vhub_dev *d)
{
	unsigned int i;

	for (i = 0; i < AST_VHUB_NUM_GEN_EPs; i++) {
	for (i = 0; i < d->max_epns; i++) {
		if (!d->epns[i])
			continue;
		ast_vhub_nuke(d->epns[i], -ESHUTDOWN);
@@ -416,10 +416,10 @@ static struct usb_ep *ast_vhub_udc_match_ep(struct usb_gadget *gadget,
	 * that will allow the generic code to use our
	 * assigned address.
	 */
	for (i = 0; i < AST_VHUB_NUM_GEN_EPs; i++)
	for (i = 0; i < d->max_epns; i++)
		if (d->epns[i] == NULL)
			break;
	if (i >= AST_VHUB_NUM_GEN_EPs)
	if (i >= d->max_epns)
		return NULL;
	addr = i + 1;

@@ -526,6 +526,7 @@ void ast_vhub_del_dev(struct ast_vhub_dev *d)

	usb_del_gadget_udc(&d->gadget);
	device_unregister(d->port_dev);
	kfree(d->epns);
}

static void ast_vhub_dev_release(struct device *dev)
@@ -546,14 +547,25 @@ int ast_vhub_init_dev(struct ast_vhub *vhub, unsigned int idx)

	ast_vhub_init_ep0(vhub, &d->ep0, d);

	/*
	 * A USB device can have up to 30 endpoints besides control
	 * endpoint 0.
	 */
	d->max_epns = min_t(u32, vhub->max_epns, 30);
	d->epns = kcalloc(d->max_epns, sizeof(*d->epns), GFP_KERNEL);
	if (!d->epns)
		return -ENOMEM;

	/*
	 * The UDC core really needs us to have separate and uniquely
	 * named "parent" devices for each port so we create a sub device
	 * here for that purpose
	 */
	d->port_dev = kzalloc(sizeof(struct device), GFP_KERNEL);
	if (!d->port_dev)
		return -ENOMEM;
	if (!d->port_dev) {
		rc = -ENOMEM;
		goto fail_alloc;
	}
	device_initialize(d->port_dev);
	d->port_dev->release = ast_vhub_dev_release;
	d->port_dev->parent = parent;
@@ -584,6 +596,8 @@ int ast_vhub_init_dev(struct ast_vhub *vhub, unsigned int idx)
	device_del(d->port_dev);
 fail_add:
	put_device(d->port_dev);
 fail_alloc:
	kfree(d->epns);

	return rc;
}
+2 −2
Original line number Diff line number Diff line
@@ -800,10 +800,10 @@ struct ast_vhub_ep *ast_vhub_alloc_epn(struct ast_vhub_dev *d, u8 addr)

	/* Find a free one (no device) */
	spin_lock_irqsave(&vhub->lock, flags);
	for (i = 0; i < AST_VHUB_NUM_GEN_EPs; i++)
	for (i = 0; i < vhub->max_epns; i++)
		if (vhub->epns[i].dev == NULL)
			break;
	if (i >= AST_VHUB_NUM_GEN_EPs) {
	if (i >= vhub->max_epns) {
		spin_unlock_irqrestore(&vhub->lock, flags);
		return NULL;
	}
+8 −7
Original line number Diff line number Diff line
@@ -502,7 +502,7 @@ static void ast_vhub_wake_work(struct work_struct *work)
	 * we let the normal host wake path deal with it later.
	 */
	spin_lock_irqsave(&vhub->lock, flags);
	for (i = 0; i < AST_VHUB_NUM_PORTS; i++) {
	for (i = 0; i < vhub->max_ports; i++) {
		struct ast_vhub_port *p = &vhub->ports[i];

		if (!(p->status & USB_PORT_STAT_SUSPEND))
@@ -585,7 +585,7 @@ static enum std_req_rc ast_vhub_set_port_feature(struct ast_vhub_ep *ep,
	struct ast_vhub *vhub = ep->vhub;
	struct ast_vhub_port *p;

	if (port == 0 || port > AST_VHUB_NUM_PORTS)
	if (port == 0 || port > vhub->max_ports)
		return std_req_stall;
	port--;
	p = &vhub->ports[port];
@@ -628,7 +628,7 @@ static enum std_req_rc ast_vhub_clr_port_feature(struct ast_vhub_ep *ep,
	struct ast_vhub *vhub = ep->vhub;
	struct ast_vhub_port *p;

	if (port == 0 || port > AST_VHUB_NUM_PORTS)
	if (port == 0 || port > vhub->max_ports)
		return std_req_stall;
	port--;
	p = &vhub->ports[port];
@@ -674,7 +674,7 @@ static enum std_req_rc ast_vhub_get_port_stat(struct ast_vhub_ep *ep,
	struct ast_vhub *vhub = ep->vhub;
	u16 stat, chg;

	if (port == 0 || port > AST_VHUB_NUM_PORTS)
	if (port == 0 || port > vhub->max_ports)
		return std_req_stall;
	port--;

@@ -755,7 +755,7 @@ void ast_vhub_hub_suspend(struct ast_vhub *vhub)
	 * Forward to unsuspended ports without changing
	 * their connection status.
	 */
	for (i = 0; i < AST_VHUB_NUM_PORTS; i++) {
	for (i = 0; i < vhub->max_ports; i++) {
		struct ast_vhub_port *p = &vhub->ports[i];

		if (!(p->status & USB_PORT_STAT_SUSPEND))
@@ -778,7 +778,7 @@ void ast_vhub_hub_resume(struct ast_vhub *vhub)
	 * Forward to unsuspended ports without changing
	 * their connection status.
	 */
	for (i = 0; i < AST_VHUB_NUM_PORTS; i++) {
	for (i = 0; i < vhub->max_ports; i++) {
		struct ast_vhub_port *p = &vhub->ports[i];

		if (!(p->status & USB_PORT_STAT_SUSPEND))
@@ -812,7 +812,7 @@ void ast_vhub_hub_reset(struct ast_vhub *vhub)
	 * Clear all port status, disable gadgets and "suspend"
	 * them. They will be woken up by a port reset.
	 */
	for (i = 0; i < AST_VHUB_NUM_PORTS; i++) {
	for (i = 0; i < vhub->max_ports; i++) {
		struct ast_vhub_port *p = &vhub->ports[i];

		/* Only keep the connected flag */
@@ -845,6 +845,7 @@ static void ast_vhub_init_desc(struct ast_vhub *vhub)
	/* Initialize vhub Hub Descriptor. */
	memcpy(&vhub->vhub_hub_desc, &ast_vhub_hub_desc,
		sizeof(vhub->vhub_hub_desc));
	vhub->vhub_hub_desc.bNbrPorts = vhub->max_ports;

	/* Initialize vhub String Descriptors. */
	memcpy(&vhub->vhub_str_desc, &ast_vhub_strings,
+14 −14
Original line number Diff line number Diff line
@@ -79,17 +79,9 @@
#define VHUB_SW_RESET_DEVICE2			(1 << 2)
#define VHUB_SW_RESET_DEVICE1			(1 << 1)
#define VHUB_SW_RESET_ROOT_HUB			(1 << 0)
#define VHUB_SW_RESET_ALL			(VHUB_SW_RESET_EP_POOL | \
						 VHUB_SW_RESET_DMA_CONTROLLER | \
						 VHUB_SW_RESET_DEVICE5 | \
						 VHUB_SW_RESET_DEVICE4 | \
						 VHUB_SW_RESET_DEVICE3 | \
						 VHUB_SW_RESET_DEVICE2 | \
						 VHUB_SW_RESET_DEVICE1 | \
						 VHUB_SW_RESET_ROOT_HUB)

/* EP ACK/NACK IRQ masks */
#define VHUB_EP_IRQ(n)				(1 << (n))
#define VHUB_EP_IRQ_ALL				0x7fff	/* 15 EPs */

/* USB status reg */
#define VHUB_USBSTS_HISPEED			(1 << 27)
@@ -213,6 +205,11 @@
 *                                      *
 ****************************************/

/*
 * AST_VHUB_NUM_GEN_EPs and AST_VHUB_NUM_PORTS are kept to avoid breaking
 * existing AST2400/AST2500 platforms. AST2600 and future vhub revisions
 * should define number of downstream ports and endpoints in device tree.
 */
#define AST_VHUB_NUM_GEN_EPs	15	/* Generic non-0 EPs */
#define AST_VHUB_NUM_PORTS	5	/* vHub ports */
#define AST_VHUB_EP0_MAX_PACKET	64	/* EP0's max packet size */
@@ -315,7 +312,7 @@ struct ast_vhub_ep {
			/* Registers */
			void __iomem   		*regs;

			/* Index in global pool (0..14) */
			/* Index in global pool (zero-based) */
			unsigned int		g_idx;

			/* DMA Descriptors */
@@ -345,7 +342,7 @@ struct ast_vhub_dev {
	struct ast_vhub			*vhub;
	void __iomem			*regs;

	/* Device index (0...4) and name string */
	/* Device index (zero-based) and name string */
	unsigned int			index;
	const char			*name;

@@ -361,7 +358,8 @@ struct ast_vhub_dev {

	/* Endpoint structures */
	struct ast_vhub_ep		ep0;
	struct ast_vhub_ep		*epns[AST_VHUB_NUM_GEN_EPs];
	struct ast_vhub_ep		**epns;
	u32				max_epns;

};
#define to_ast_dev(__g) container_of(__g, struct ast_vhub_dev, gadget)
@@ -402,10 +400,12 @@ struct ast_vhub {
	bool				ep1_stalled : 1;

	/* Per-port info */
	struct ast_vhub_port		ports[AST_VHUB_NUM_PORTS];
	struct ast_vhub_port		*ports;
	u32				max_ports;

	/* Generic EP data structures */
	struct ast_vhub_ep		epns[AST_VHUB_NUM_GEN_EPs];
	struct ast_vhub_ep		*epns;
	u32				max_epns;

	/* Upstream bus is suspended ? */
	bool				suspended : 1;