blob: d95efd1a87361e0cfe86a59ab11719f362fa03d3 [file] [log] [blame]
Daisuke Nojiri4e2e8ee2015-02-25 17:39:42 -08001/*
2 * Copyright (C) 2014 Broadcom Corporation
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation version 2.
7 *
8 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
9 * kind, whether express or implied; without even the implied warranty
10 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <arch/io.h>
15#include <delay.h>
16#include <console/console.h>
17#include <soc/cygnus.h>
18
19#define CDRU_USBPHY_CLK_RST_SEL_OFFSET 0x11b4
20#define CDRU_USBPHY2_HOST_DEV_SEL_OFFSET 0x11b8
21#define CDRU_SPARE_REG_0_OFFSET 0x1238
22#define CRMU_USB_PHY_AON_CTRL_OFFSET 0x00028
23#define CDRU_USB_DEV_SUSPEND_RESUME_CTRL_OFFSET 0x1210
24#define CDRU_USBPHY_P2_STATUS_OFFSET 0x1200
25
26#define CDRU_USB_DEV_SUSPEND_RESUME_CTRL_DISABLE 0
27#define PHY2_DEV_HOST_CTRL_SEL_DEVICE 0
28#define PHY2_DEV_HOST_CTRL_SEL_HOST 1
29#define CDRU_USBPHY_P2_STATUS__USBPHY_ILDO_ON_FLAG 1
30#define CDRU_USBPHY_P2_STATUS__USBPHY_PLL_LOCK 0
31#define CRMU_USBPHY_P0_AFE_CORERDY_VDDC 1
32#define CRMU_USBPHY_P0_RESETB 2
33#define CRMU_USBPHY_P1_AFE_CORERDY_VDDC 9
34#define CRMU_USBPHY_P1_RESETB 10
35#define CRMU_USBPHY_P2_AFE_CORERDY_VDDC 17
36#define CRMU_USBPHY_P2_RESETB 18
37
38#define USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET 0x0408
39#define USB2_IDM_IDM_IO_CONTROL_DIRECT__clk_enable 0
40#define USB2_IDM_IDM_RESET_CONTROL_OFFSET 0x0800
41#define USB2_IDM_IDM_RESET_CONTROL__RESET 0
42
43#define PLL_LOCK_RETRY_COUNT 1000
44#define MAX_REGULATOR_NAME_LEN 25
45#define NUM_PHYS 3
46
47struct bcm_phy_instance {
48 struct phy *generic_phy;
49 int port;
50 int host_mode; /* 1 - Host , 0 - device */
51 int power; /* 1 -powered_on 0 -powered off */
52 struct regulator *vbus_supply;
53};
54
55struct bcm_phy_driver {
56 void *usbphy_regs;
57 void *usb2h_idm_regs;
58 void *usb2d_idm_regs;
59 int num_phys, idm_host_enabled;
60 struct bcm_phy_instance instances[NUM_PHYS];
61};
62
63static struct bcm_phy_driver phy_driver;
64
65static int bcm_phy_init(struct bcm_phy_instance *instance_ptr)
66{
67 /* Only PORT 2 is capabale of being device and host
68 * Default setting is device, check if it is set to host */
69 if (instance_ptr->port == 2) {
70 if (instance_ptr->host_mode == PHY2_DEV_HOST_CTRL_SEL_HOST)
71 write32(phy_driver.usbphy_regs + CDRU_USBPHY2_HOST_DEV_SEL_OFFSET,
72 PHY2_DEV_HOST_CTRL_SEL_HOST);
73 else
74 die("usb device mode unsupported\n");
75 }
76
77 return 0;
78}
79
80static int bcm_phy_poweron(struct bcm_phy_instance *instance_ptr)
81{
82 int clock_reset_flag = 1;
83 u32 val;
84
85 /* Bring the AFE block out of reset to start powering up the PHY */
86 val = read32(phy_driver.usbphy_regs + CRMU_USB_PHY_AON_CTRL_OFFSET);
87 if (instance_ptr->port == 0)
88 val |= (1 << CRMU_USBPHY_P0_AFE_CORERDY_VDDC);
89 else if (instance_ptr->port == 1)
90 val |= (1 << CRMU_USBPHY_P1_AFE_CORERDY_VDDC);
91 else if (instance_ptr->port == 2)
92 val |= (1 << CRMU_USBPHY_P2_AFE_CORERDY_VDDC);
93 write32(phy_driver.usbphy_regs + CRMU_USB_PHY_AON_CTRL_OFFSET, val);
94
95 instance_ptr->power = 1;
96
97 /* Check if the port 2 is configured for device */
98 if (instance_ptr->port == 2 &&
99 instance_ptr->host_mode == PHY2_DEV_HOST_CTRL_SEL_DEVICE)
100 die("usb device mode unsupported\n");
101
102 val = read32(phy_driver.usbphy_regs + CDRU_USBPHY_CLK_RST_SEL_OFFSET);
103
104 /* Check if the phy that is configured
105 * to provide clock and reset is powered on*/
106 if (val >= 0 && val < phy_driver.num_phys) {
107 if (phy_driver.instances[val].power == 1)
108 clock_reset_flag = 0;
109 }
110
111 /* if not set the current phy */
112 if (clock_reset_flag) {
113 val = instance_ptr->port;
114 write32(phy_driver.usbphy_regs + CDRU_USBPHY_CLK_RST_SEL_OFFSET,
115 val);
116 }
117
118 if (phy_driver.idm_host_enabled != 1) {
119 /* Enable clock to USB and get the USB out of reset */
120 setbits_le32(phy_driver.usb2h_idm_regs +
121 USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET,
122 (1 << USB2_IDM_IDM_IO_CONTROL_DIRECT__clk_enable));
123 clrbits_le32(phy_driver.usb2h_idm_regs +
124 USB2_IDM_IDM_RESET_CONTROL_OFFSET,
125 (1 << USB2_IDM_IDM_RESET_CONTROL__RESET));
126 phy_driver.idm_host_enabled = 1;
127 }
128
129 return 0;
130}
131
132static int bcm_phy_probe(void)
133{
134 int i;
135
136 phy_driver.num_phys = NUM_PHYS;
137 phy_driver.usbphy_regs = (void *)0x0301c000;
138 phy_driver.usb2h_idm_regs = (void *)0x18115000;
139 phy_driver.usb2d_idm_regs = (void *)0x18111000;
140 phy_driver.idm_host_enabled = 0;
141
142 /* Shutdown all ports. They can be powered up as required */
143 clrbits_le32(phy_driver.usbphy_regs + CRMU_USB_PHY_AON_CTRL_OFFSET,
144 (1 << CRMU_USBPHY_P0_AFE_CORERDY_VDDC) |
145 (1 << CRMU_USBPHY_P0_RESETB) |
146 (1 << CRMU_USBPHY_P1_AFE_CORERDY_VDDC) |
147 (1 << CRMU_USBPHY_P1_RESETB) |
148 (1 << CRMU_USBPHY_P2_AFE_CORERDY_VDDC) |
149 (1 << CRMU_USBPHY_P2_RESETB));
150
151 for (i = 0; i < phy_driver.num_phys; i++) {
152 phy_driver.instances[i].port = i;
153 phy_driver.instances[i].host_mode = PHY2_DEV_HOST_CTRL_SEL_HOST;
154 }
155
156 return 0;
157}
158
159void usb_init(void)
160{
161 bcm_phy_probe();
162 /* currently, we only need thus support port 0 */
163 bcm_phy_init(&phy_driver.instances[0]);
164 bcm_phy_poweron(&phy_driver.instances[0]);
165 printk(BIOS_INFO, "usb phy[%d] is powered on\n", 0);
166}