summaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/ehci-rmobile.c
blob: 0d1a726d35ff6e4df02c44791c66257bd089b6db (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/*
 *  EHCI HCD (Host Controller Driver) for USB.
 *
 *  Copyright (C) 2013,2014 Renesas Electronics Corporation
 *  Copyright (C) 2014 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
 *
 *  SPDX-License-Identifier:     GPL-2.0
 */

#include <common.h>
#include <asm/io.h>
#include <asm/arch/ehci-rmobile.h>
#include "ehci.h"

#if defined(CONFIG_R8A7740)
static u32 usb_base_address[CONFIG_USB_MAX_CONTROLLER_COUNT] = {
	0xC6700000
};
#elif defined(CONFIG_R8A7790)
static u32 usb_base_address[CONFIG_USB_MAX_CONTROLLER_COUNT] = {
	0xEE080000,	/* USB0 (EHCI) */
	0xEE0A0000,	/* USB1 */
	0xEE0C0000,	/* USB2 */
};
#elif defined(CONFIG_R8A7791)
static u32 usb_base_address[CONFIG_USB_MAX_CONTROLLER_COUNT] = {
	0xEE080000,	/* USB0 (EHCI) */
	0xEE0C0000,	/* USB1 */
};
#elif defined(CONFIG_R8A7794)
static u32 usb_base_address[CONFIG_USB_MAX_CONTROLLER_COUNT] = {
	0xEE080000,	/* USB0 (EHCI) */
	0xEE0C0000,	/* USB1 */
};
#else
#error rmobile EHCI USB driver not supported on this platform
#endif

int ehci_hcd_stop(int index)
{
	int i;
	u32 base;
	struct ahbcom_pci_bridge *ahbcom_pci;

	base = usb_base_address[index];
	ahbcom_pci = (struct ahbcom_pci_bridge *)(base + AHBPCI_OFFSET);
	writel(0, &ahbcom_pci->ahb_bus_ctr);

	/* reset ehci */
	setbits_le32(base + EHCI_USBCMD, CMD_RESET);
	for (i = 100; i > 0; i--) {
		if (!(readl(base + EHCI_USBCMD) & CMD_RESET))
			break;
		udelay(100);
	}

	if (!i)
		printf("error : ehci(%d) reset failed.\n", index);

	if (index == (CONFIG_USB_MAX_CONTROLLER_COUNT - 1))
		setbits_le32(SMSTPCR7, SMSTPCR703);

	return 0;
}

int ehci_hcd_init(int index, enum usb_init_type init,
	struct ehci_hccr **hccr, struct ehci_hcor **hcor)
{
	u32 base;
	u32 phys_base;
	struct rmobile_ehci_reg *rehci;
	struct ahbcom_pci_bridge *ahbcom_pci;
	struct ahbconf_pci_bridge *ahbconf_pci;
	struct ahb_pciconf *ahb_pciconf_ohci;
	struct ahb_pciconf *ahb_pciconf_ehci;
	uint32_t cap_base;

	base = usb_base_address[index];
	phys_base = base;
	if (index == 0)
		clrbits_le32(SMSTPCR7, SMSTPCR703);

	rehci = (struct rmobile_ehci_reg *)(base + EHCI_OFFSET);
	ahbcom_pci = (struct ahbcom_pci_bridge *)(base + AHBPCI_OFFSET);
	ahbconf_pci =
		(struct ahbconf_pci_bridge *)(base + PCI_CONF_AHBPCI_OFFSET);
	ahb_pciconf_ohci = (struct ahb_pciconf *)(base + PCI_CONF_OHCI_OFFSET);
	ahb_pciconf_ehci = (struct ahb_pciconf *)(base + PCI_CONF_EHCI_OFFSET);

	/* Clock & Reset & Direct Power Down */
	clrsetbits_le32(&ahbcom_pci->usbctr,
			(DIRPD | PCICLK_MASK | USBH_RST), USBCTR_WIN_SIZE_1GB);
	clrbits_le32(&ahbcom_pci->usbctr, PLL_RST);

	/* AHB-PCI Bridge Communication Registers */
	writel(AHB_BUS_CTR_INIT, &ahbcom_pci->ahb_bus_ctr);
	writel((CONFIG_SYS_SDRAM_BASE & 0xf0000000) | PCIAHB_WIN_PREFETCH,
	       &ahbcom_pci->pciahb_win1_ctr);
	writel(0xf0000000 | PCIAHB_WIN_PREFETCH,
	       &ahbcom_pci->pciahb_win2_ctr);
	writel(phys_base | PCIWIN2_PCICMD, &ahbcom_pci->ahbpci_win2_ctr);

	setbits_le32(&ahbcom_pci->pci_arbiter_ctr,
		     PCIBP_MODE | PCIREQ1 | PCIREQ0);

	/* PCI Configuration Registers for AHBPCI */
	writel(PCIWIN1_PCICMD | AHB_CFG_AHBPCI,
	       &ahbcom_pci->ahbpci_win1_ctr);
	writel(phys_base + AHBPCI_OFFSET, &ahbconf_pci->basead);
	writel(CONFIG_SYS_SDRAM_BASE & 0xf0000000, &ahbconf_pci->win1_basead);
	writel(0xf0000000, &ahbconf_pci->win2_basead);
	writel(SERREN | PERREN | MASTEREN | MEMEN,
	       &ahbconf_pci->cmnd_sts);

	/* PCI Configuration Registers for EHCI */
	writel(PCIWIN1_PCICMD | AHB_CFG_HOST, &ahbcom_pci->ahbpci_win1_ctr);
	writel(phys_base + OHCI_OFFSET, &ahb_pciconf_ohci->basead);
	writel(phys_base + EHCI_OFFSET, &ahb_pciconf_ehci->basead);
	writel(SERREN | PERREN | MASTEREN | MEMEN,
	       &ahb_pciconf_ohci->cmnd_sts);
	writel(SERREN | PERREN | MASTEREN | MEMEN,
	       &ahb_pciconf_ehci->cmnd_sts);

	/* Enable PCI interrupt */
	setbits_le32(&ahbcom_pci->pci_int_enable,
		     USBH_PMEEN | USBH_INTBEN | USBH_INTAEN);

	*hccr = (struct ehci_hccr *)((uint32_t)&rehci->hciversion);
	cap_base = ehci_readl(&(*hccr)->cr_capbase);
	*hcor = (struct ehci_hcor *)((uint32_t)*hccr + HC_LENGTH(cap_base));

	return 0;
}
OpenPOWER on IntegriCloud