.. | .. |
---|
11 | 11 | #include <linux/dma-mapping.h> |
---|
12 | 12 | #include <linux/firmware.h> |
---|
13 | 13 | #include <linux/interrupt.h> |
---|
| 14 | +#include <linux/iopoll.h> |
---|
14 | 15 | #include <linux/kernel.h> |
---|
15 | 16 | #include <linux/module.h> |
---|
16 | 17 | #include <linux/of_device.h> |
---|
.. | .. |
---|
18 | 19 | #include <linux/phy/tegra/xusb.h> |
---|
19 | 20 | #include <linux/platform_device.h> |
---|
20 | 21 | #include <linux/pm.h> |
---|
| 22 | +#include <linux/pm_domain.h> |
---|
21 | 23 | #include <linux/pm_runtime.h> |
---|
22 | 24 | #include <linux/regulator/consumer.h> |
---|
23 | 25 | #include <linux/reset.h> |
---|
24 | 26 | #include <linux/slab.h> |
---|
| 27 | +#include <linux/usb/otg.h> |
---|
| 28 | +#include <linux/usb/phy.h> |
---|
| 29 | +#include <linux/usb/role.h> |
---|
25 | 30 | #include <soc/tegra/pmc.h> |
---|
26 | 31 | |
---|
27 | 32 | #include "xhci.h" |
---|
.. | .. |
---|
37 | 42 | #define XUSB_CFG_4 0x010 |
---|
38 | 43 | #define XUSB_BASE_ADDR_SHIFT 15 |
---|
39 | 44 | #define XUSB_BASE_ADDR_MASK 0x1ffff |
---|
| 45 | +#define XUSB_CFG_16 0x040 |
---|
| 46 | +#define XUSB_CFG_24 0x060 |
---|
| 47 | +#define XUSB_CFG_AXI_CFG 0x0f8 |
---|
40 | 48 | #define XUSB_CFG_ARU_C11_CSBRANGE 0x41c |
---|
| 49 | +#define XUSB_CFG_ARU_CONTEXT 0x43c |
---|
| 50 | +#define XUSB_CFG_ARU_CONTEXT_HS_PLS 0x478 |
---|
| 51 | +#define XUSB_CFG_ARU_CONTEXT_FS_PLS 0x47c |
---|
| 52 | +#define XUSB_CFG_ARU_CONTEXT_HSFS_SPEED 0x480 |
---|
| 53 | +#define XUSB_CFG_ARU_CONTEXT_HSFS_PP 0x484 |
---|
41 | 54 | #define XUSB_CFG_CSB_BASE_ADDR 0x800 |
---|
42 | 55 | |
---|
43 | 56 | /* FPCI mailbox registers */ |
---|
44 | | -#define XUSB_CFG_ARU_MBOX_CMD 0x0e4 |
---|
| 57 | +/* XUSB_CFG_ARU_MBOX_CMD */ |
---|
45 | 58 | #define MBOX_DEST_FALC BIT(27) |
---|
46 | 59 | #define MBOX_DEST_PME BIT(28) |
---|
47 | 60 | #define MBOX_DEST_SMI BIT(29) |
---|
48 | 61 | #define MBOX_DEST_XHCI BIT(30) |
---|
49 | 62 | #define MBOX_INT_EN BIT(31) |
---|
50 | | -#define XUSB_CFG_ARU_MBOX_DATA_IN 0x0e8 |
---|
| 63 | +/* XUSB_CFG_ARU_MBOX_DATA_IN and XUSB_CFG_ARU_MBOX_DATA_OUT */ |
---|
51 | 64 | #define CMD_DATA_SHIFT 0 |
---|
52 | 65 | #define CMD_DATA_MASK 0xffffff |
---|
53 | 66 | #define CMD_TYPE_SHIFT 24 |
---|
54 | 67 | #define CMD_TYPE_MASK 0xff |
---|
55 | | -#define XUSB_CFG_ARU_MBOX_DATA_OUT 0x0ec |
---|
56 | | -#define XUSB_CFG_ARU_MBOX_OWNER 0x0f0 |
---|
| 68 | +/* XUSB_CFG_ARU_MBOX_OWNER */ |
---|
57 | 69 | #define MBOX_OWNER_NONE 0 |
---|
58 | 70 | #define MBOX_OWNER_FW 1 |
---|
59 | 71 | #define MBOX_OWNER_SW 2 |
---|
.. | .. |
---|
62 | 74 | #define MBOX_SMI_INTR_EN BIT(3) |
---|
63 | 75 | |
---|
64 | 76 | /* IPFS registers */ |
---|
| 77 | +#define IPFS_XUSB_HOST_MSI_BAR_SZ_0 0x0c0 |
---|
| 78 | +#define IPFS_XUSB_HOST_MSI_AXI_BAR_ST_0 0x0c4 |
---|
| 79 | +#define IPFS_XUSB_HOST_MSI_FPCI_BAR_ST_0 0x0c8 |
---|
| 80 | +#define IPFS_XUSB_HOST_MSI_VEC0_0 0x100 |
---|
| 81 | +#define IPFS_XUSB_HOST_MSI_EN_VEC0_0 0x140 |
---|
65 | 82 | #define IPFS_XUSB_HOST_CONFIGURATION_0 0x180 |
---|
66 | 83 | #define IPFS_EN_FPCI BIT(0) |
---|
| 84 | +#define IPFS_XUSB_HOST_FPCI_ERROR_MASKS_0 0x184 |
---|
67 | 85 | #define IPFS_XUSB_HOST_INTR_MASK_0 0x188 |
---|
68 | 86 | #define IPFS_IP_INT_MASK BIT(16) |
---|
| 87 | +#define IPFS_XUSB_HOST_INTR_ENABLE_0 0x198 |
---|
| 88 | +#define IPFS_XUSB_HOST_UFPCI_CONFIG_0 0x19c |
---|
69 | 89 | #define IPFS_XUSB_HOST_CLKGATE_HYSTERESIS_0 0x1bc |
---|
| 90 | +#define IPFS_XUSB_HOST_MCCIF_FIFOCTRL_0 0x1dc |
---|
70 | 91 | |
---|
71 | 92 | #define CSB_PAGE_SELECT_MASK 0x7fffff |
---|
72 | 93 | #define CSB_PAGE_SELECT_SHIFT 9 |
---|
.. | .. |
---|
101 | 122 | #define L2IMEMOP_ACTION_SHIFT 24 |
---|
102 | 123 | #define L2IMEMOP_INVALIDATE_ALL (0x40 << L2IMEMOP_ACTION_SHIFT) |
---|
103 | 124 | #define L2IMEMOP_LOAD_LOCKED_RESULT (0x11 << L2IMEMOP_ACTION_SHIFT) |
---|
| 125 | +#define XUSB_CSB_MEMPOOL_L2IMEMOP_RESULT 0x101a18 |
---|
| 126 | +#define L2IMEMOP_RESULT_VLD BIT(31) |
---|
104 | 127 | #define XUSB_CSB_MP_APMAP 0x10181c |
---|
105 | 128 | #define APMAP_BOOTPATH BIT(31) |
---|
106 | 129 | |
---|
107 | 130 | #define IMEM_BLOCK_SIZE 256 |
---|
108 | 131 | |
---|
109 | 132 | struct tegra_xusb_fw_header { |
---|
110 | | - u32 boot_loadaddr_in_imem; |
---|
111 | | - u32 boot_codedfi_offset; |
---|
112 | | - u32 boot_codetag; |
---|
113 | | - u32 boot_codesize; |
---|
114 | | - u32 phys_memaddr; |
---|
115 | | - u16 reqphys_memsize; |
---|
116 | | - u16 alloc_phys_memsize; |
---|
117 | | - u32 rodata_img_offset; |
---|
118 | | - u32 rodata_section_start; |
---|
119 | | - u32 rodata_section_end; |
---|
120 | | - u32 main_fnaddr; |
---|
121 | | - u32 fwimg_cksum; |
---|
122 | | - u32 fwimg_created_time; |
---|
123 | | - u32 imem_resident_start; |
---|
124 | | - u32 imem_resident_end; |
---|
125 | | - u32 idirect_start; |
---|
126 | | - u32 idirect_end; |
---|
127 | | - u32 l2_imem_start; |
---|
128 | | - u32 l2_imem_end; |
---|
129 | | - u32 version_id; |
---|
| 133 | + __le32 boot_loadaddr_in_imem; |
---|
| 134 | + __le32 boot_codedfi_offset; |
---|
| 135 | + __le32 boot_codetag; |
---|
| 136 | + __le32 boot_codesize; |
---|
| 137 | + __le32 phys_memaddr; |
---|
| 138 | + __le16 reqphys_memsize; |
---|
| 139 | + __le16 alloc_phys_memsize; |
---|
| 140 | + __le32 rodata_img_offset; |
---|
| 141 | + __le32 rodata_section_start; |
---|
| 142 | + __le32 rodata_section_end; |
---|
| 143 | + __le32 main_fnaddr; |
---|
| 144 | + __le32 fwimg_cksum; |
---|
| 145 | + __le32 fwimg_created_time; |
---|
| 146 | + __le32 imem_resident_start; |
---|
| 147 | + __le32 imem_resident_end; |
---|
| 148 | + __le32 idirect_start; |
---|
| 149 | + __le32 idirect_end; |
---|
| 150 | + __le32 l2_imem_start; |
---|
| 151 | + __le32 l2_imem_end; |
---|
| 152 | + __le32 version_id; |
---|
130 | 153 | u8 init_ddirect; |
---|
131 | 154 | u8 reserved[3]; |
---|
132 | | - u32 phys_addr_log_buffer; |
---|
133 | | - u32 total_log_entries; |
---|
134 | | - u32 dequeue_ptr; |
---|
135 | | - u32 dummy_var[2]; |
---|
136 | | - u32 fwimg_len; |
---|
| 155 | + __le32 phys_addr_log_buffer; |
---|
| 156 | + __le32 total_log_entries; |
---|
| 157 | + __le32 dequeue_ptr; |
---|
| 158 | + __le32 dummy_var[2]; |
---|
| 159 | + __le32 fwimg_len; |
---|
137 | 160 | u8 magic[8]; |
---|
138 | | - u32 ss_low_power_entry_timeout; |
---|
| 161 | + __le32 ss_low_power_entry_timeout; |
---|
139 | 162 | u8 num_hsic_port; |
---|
140 | 163 | u8 padding[139]; /* Pad to 256 bytes */ |
---|
141 | 164 | }; |
---|
.. | .. |
---|
145 | 168 | unsigned int num; |
---|
146 | 169 | }; |
---|
147 | 170 | |
---|
| 171 | +struct tegra_xusb_mbox_regs { |
---|
| 172 | + u16 cmd; |
---|
| 173 | + u16 data_in; |
---|
| 174 | + u16 data_out; |
---|
| 175 | + u16 owner; |
---|
| 176 | +}; |
---|
| 177 | + |
---|
| 178 | +struct tegra_xusb_context_soc { |
---|
| 179 | + struct { |
---|
| 180 | + const unsigned int *offsets; |
---|
| 181 | + unsigned int num_offsets; |
---|
| 182 | + } ipfs; |
---|
| 183 | + |
---|
| 184 | + struct { |
---|
| 185 | + const unsigned int *offsets; |
---|
| 186 | + unsigned int num_offsets; |
---|
| 187 | + } fpci; |
---|
| 188 | +}; |
---|
| 189 | + |
---|
148 | 190 | struct tegra_xusb_soc { |
---|
149 | 191 | const char *firmware; |
---|
150 | 192 | const char * const *supply_names; |
---|
151 | 193 | unsigned int num_supplies; |
---|
152 | 194 | const struct tegra_xusb_phy_type *phy_types; |
---|
153 | 195 | unsigned int num_types; |
---|
| 196 | + const struct tegra_xusb_context_soc *context; |
---|
154 | 197 | |
---|
155 | 198 | struct { |
---|
156 | 199 | struct { |
---|
.. | .. |
---|
159 | 202 | } usb2, ulpi, hsic, usb3; |
---|
160 | 203 | } ports; |
---|
161 | 204 | |
---|
| 205 | + struct tegra_xusb_mbox_regs mbox; |
---|
| 206 | + |
---|
162 | 207 | bool scale_ss_clock; |
---|
| 208 | + bool has_ipfs; |
---|
| 209 | + bool lpm_support; |
---|
| 210 | + bool otg_reset_sspi; |
---|
| 211 | +}; |
---|
| 212 | + |
---|
| 213 | +struct tegra_xusb_context { |
---|
| 214 | + u32 *ipfs; |
---|
| 215 | + u32 *fpci; |
---|
163 | 216 | }; |
---|
164 | 217 | |
---|
165 | 218 | struct tegra_xusb { |
---|
.. | .. |
---|
194 | 247 | struct reset_control *host_rst; |
---|
195 | 248 | struct reset_control *ss_rst; |
---|
196 | 249 | |
---|
| 250 | + struct device *genpd_dev_host; |
---|
| 251 | + struct device *genpd_dev_ss; |
---|
| 252 | + struct device_link *genpd_dl_host; |
---|
| 253 | + struct device_link *genpd_dl_ss; |
---|
| 254 | + |
---|
197 | 255 | struct phy **phys; |
---|
198 | 256 | unsigned int num_phys; |
---|
| 257 | + |
---|
| 258 | + struct usb_phy **usbphy; |
---|
| 259 | + unsigned int num_usb_phys; |
---|
| 260 | + int otg_usb2_port; |
---|
| 261 | + int otg_usb3_port; |
---|
| 262 | + bool host_mode; |
---|
| 263 | + struct notifier_block id_nb; |
---|
| 264 | + struct work_struct id_work; |
---|
199 | 265 | |
---|
200 | 266 | /* Firmware loading related */ |
---|
201 | 267 | struct { |
---|
.. | .. |
---|
203 | 269 | void *virt; |
---|
204 | 270 | dma_addr_t phys; |
---|
205 | 271 | } fw; |
---|
| 272 | + |
---|
| 273 | + struct tegra_xusb_context context; |
---|
206 | 274 | }; |
---|
207 | 275 | |
---|
208 | 276 | static struct hc_driver __read_mostly tegra_xhci_hc_driver; |
---|
.. | .. |
---|
347 | 415 | MBOX_CMD_NAK |
---|
348 | 416 | }; |
---|
349 | 417 | |
---|
350 | | -static const char * const mbox_cmd_name[] = { |
---|
351 | | - [ 1] = "MSG_ENABLE", |
---|
352 | | - [ 2] = "INC_FALCON_CLOCK", |
---|
353 | | - [ 3] = "DEC_FALCON_CLOCK", |
---|
354 | | - [ 4] = "INC_SSPI_CLOCK", |
---|
355 | | - [ 5] = "DEC_SSPI_CLOCK", |
---|
356 | | - [ 6] = "SET_BW", |
---|
357 | | - [ 7] = "SET_SS_PWR_GATING", |
---|
358 | | - [ 8] = "SET_SS_PWR_UNGATING", |
---|
359 | | - [ 9] = "SAVE_DFE_CTLE_CTX", |
---|
360 | | - [ 10] = "AIRPLANE_MODE_ENABLED", |
---|
361 | | - [ 11] = "AIRPLANE_MODE_DISABLED", |
---|
362 | | - [ 12] = "START_HSIC_IDLE", |
---|
363 | | - [ 13] = "STOP_HSIC_IDLE", |
---|
364 | | - [ 14] = "DBC_WAKE_STACK", |
---|
365 | | - [ 15] = "HSIC_PRETEND_CONNECT", |
---|
366 | | - [ 16] = "RESET_SSPI", |
---|
367 | | - [ 17] = "DISABLE_SS_LFPS_DETECTION", |
---|
368 | | - [ 18] = "ENABLE_SS_LFPS_DETECTION", |
---|
369 | | - [128] = "ACK", |
---|
370 | | - [129] = "NAK", |
---|
371 | | -}; |
---|
372 | | - |
---|
373 | 418 | struct tegra_xusb_mbox_msg { |
---|
374 | 419 | u32 cmd; |
---|
375 | 420 | u32 data; |
---|
.. | .. |
---|
411 | 456 | * ACK/NAK messages. |
---|
412 | 457 | */ |
---|
413 | 458 | if (!(msg->cmd == MBOX_CMD_ACK || msg->cmd == MBOX_CMD_NAK)) { |
---|
414 | | - value = fpci_readl(tegra, XUSB_CFG_ARU_MBOX_OWNER); |
---|
| 459 | + value = fpci_readl(tegra, tegra->soc->mbox.owner); |
---|
415 | 460 | if (value != MBOX_OWNER_NONE) { |
---|
416 | 461 | dev_err(tegra->dev, "mailbox is busy\n"); |
---|
417 | 462 | return -EBUSY; |
---|
418 | 463 | } |
---|
419 | 464 | |
---|
420 | | - fpci_writel(tegra, MBOX_OWNER_SW, XUSB_CFG_ARU_MBOX_OWNER); |
---|
| 465 | + fpci_writel(tegra, MBOX_OWNER_SW, tegra->soc->mbox.owner); |
---|
421 | 466 | |
---|
422 | | - value = fpci_readl(tegra, XUSB_CFG_ARU_MBOX_OWNER); |
---|
| 467 | + value = fpci_readl(tegra, tegra->soc->mbox.owner); |
---|
423 | 468 | if (value != MBOX_OWNER_SW) { |
---|
424 | 469 | dev_err(tegra->dev, "failed to acquire mailbox\n"); |
---|
425 | 470 | return -EBUSY; |
---|
.. | .. |
---|
429 | 474 | } |
---|
430 | 475 | |
---|
431 | 476 | value = tegra_xusb_mbox_pack(msg); |
---|
432 | | - fpci_writel(tegra, value, XUSB_CFG_ARU_MBOX_DATA_IN); |
---|
| 477 | + fpci_writel(tegra, value, tegra->soc->mbox.data_in); |
---|
433 | 478 | |
---|
434 | | - value = fpci_readl(tegra, XUSB_CFG_ARU_MBOX_CMD); |
---|
| 479 | + value = fpci_readl(tegra, tegra->soc->mbox.cmd); |
---|
435 | 480 | value |= MBOX_INT_EN | MBOX_DEST_FALC; |
---|
436 | | - fpci_writel(tegra, value, XUSB_CFG_ARU_MBOX_CMD); |
---|
| 481 | + fpci_writel(tegra, value, tegra->soc->mbox.cmd); |
---|
437 | 482 | |
---|
438 | 483 | if (wait_for_idle) { |
---|
439 | 484 | unsigned long timeout = jiffies + msecs_to_jiffies(250); |
---|
440 | 485 | |
---|
441 | 486 | while (time_before(jiffies, timeout)) { |
---|
442 | | - value = fpci_readl(tegra, XUSB_CFG_ARU_MBOX_OWNER); |
---|
| 487 | + value = fpci_readl(tegra, tegra->soc->mbox.owner); |
---|
443 | 488 | if (value == MBOX_OWNER_NONE) |
---|
444 | 489 | break; |
---|
445 | 490 | |
---|
.. | .. |
---|
447 | 492 | } |
---|
448 | 493 | |
---|
449 | 494 | if (time_after(jiffies, timeout)) |
---|
450 | | - value = fpci_readl(tegra, XUSB_CFG_ARU_MBOX_OWNER); |
---|
| 495 | + value = fpci_readl(tegra, tegra->soc->mbox.owner); |
---|
451 | 496 | |
---|
452 | 497 | if (value != MBOX_OWNER_NONE) |
---|
453 | 498 | return -ETIMEDOUT; |
---|
.. | .. |
---|
621 | 666 | |
---|
622 | 667 | mutex_lock(&tegra->lock); |
---|
623 | 668 | |
---|
624 | | - value = fpci_readl(tegra, XUSB_CFG_ARU_MBOX_DATA_OUT); |
---|
| 669 | + value = fpci_readl(tegra, tegra->soc->mbox.data_out); |
---|
625 | 670 | tegra_xusb_mbox_unpack(&msg, value); |
---|
626 | 671 | |
---|
627 | | - value = fpci_readl(tegra, XUSB_CFG_ARU_MBOX_CMD); |
---|
| 672 | + value = fpci_readl(tegra, tegra->soc->mbox.cmd); |
---|
628 | 673 | value &= ~MBOX_DEST_SMI; |
---|
629 | | - fpci_writel(tegra, value, XUSB_CFG_ARU_MBOX_CMD); |
---|
| 674 | + fpci_writel(tegra, value, tegra->soc->mbox.cmd); |
---|
630 | 675 | |
---|
631 | 676 | /* clear mailbox owner if no ACK/NAK is required */ |
---|
632 | 677 | if (!tegra_xusb_mbox_cmd_requires_ack(msg.cmd)) |
---|
633 | | - fpci_writel(tegra, MBOX_OWNER_NONE, XUSB_CFG_ARU_MBOX_OWNER); |
---|
| 678 | + fpci_writel(tegra, MBOX_OWNER_NONE, tegra->soc->mbox.owner); |
---|
634 | 679 | |
---|
635 | 680 | tegra_xusb_mbox_handle(tegra, &msg); |
---|
636 | 681 | |
---|
.. | .. |
---|
638 | 683 | return IRQ_HANDLED; |
---|
639 | 684 | } |
---|
640 | 685 | |
---|
641 | | -static void tegra_xusb_ipfs_config(struct tegra_xusb *tegra, |
---|
642 | | - struct resource *regs) |
---|
| 686 | +static void tegra_xusb_config(struct tegra_xusb *tegra) |
---|
643 | 687 | { |
---|
| 688 | + u32 regs = tegra->hcd->rsrc_start; |
---|
644 | 689 | u32 value; |
---|
645 | 690 | |
---|
646 | | - value = ipfs_readl(tegra, IPFS_XUSB_HOST_CONFIGURATION_0); |
---|
647 | | - value |= IPFS_EN_FPCI; |
---|
648 | | - ipfs_writel(tegra, value, IPFS_XUSB_HOST_CONFIGURATION_0); |
---|
| 691 | + if (tegra->soc->has_ipfs) { |
---|
| 692 | + value = ipfs_readl(tegra, IPFS_XUSB_HOST_CONFIGURATION_0); |
---|
| 693 | + value |= IPFS_EN_FPCI; |
---|
| 694 | + ipfs_writel(tegra, value, IPFS_XUSB_HOST_CONFIGURATION_0); |
---|
649 | 695 | |
---|
650 | | - usleep_range(10, 20); |
---|
| 696 | + usleep_range(10, 20); |
---|
| 697 | + } |
---|
651 | 698 | |
---|
652 | 699 | /* Program BAR0 space */ |
---|
653 | 700 | value = fpci_readl(tegra, XUSB_CFG_4); |
---|
654 | 701 | value &= ~(XUSB_BASE_ADDR_MASK << XUSB_BASE_ADDR_SHIFT); |
---|
655 | | - value |= regs->start & (XUSB_BASE_ADDR_MASK << XUSB_BASE_ADDR_SHIFT); |
---|
| 702 | + value |= regs & (XUSB_BASE_ADDR_MASK << XUSB_BASE_ADDR_SHIFT); |
---|
656 | 703 | fpci_writel(tegra, value, XUSB_CFG_4); |
---|
657 | 704 | |
---|
658 | 705 | usleep_range(100, 200); |
---|
.. | .. |
---|
662 | 709 | value |= XUSB_IO_SPACE_EN | XUSB_MEM_SPACE_EN | XUSB_BUS_MASTER_EN; |
---|
663 | 710 | fpci_writel(tegra, value, XUSB_CFG_1); |
---|
664 | 711 | |
---|
665 | | - /* Enable interrupt assertion */ |
---|
666 | | - value = ipfs_readl(tegra, IPFS_XUSB_HOST_INTR_MASK_0); |
---|
667 | | - value |= IPFS_IP_INT_MASK; |
---|
668 | | - ipfs_writel(tegra, value, IPFS_XUSB_HOST_INTR_MASK_0); |
---|
| 712 | + if (tegra->soc->has_ipfs) { |
---|
| 713 | + /* Enable interrupt assertion */ |
---|
| 714 | + value = ipfs_readl(tegra, IPFS_XUSB_HOST_INTR_MASK_0); |
---|
| 715 | + value |= IPFS_IP_INT_MASK; |
---|
| 716 | + ipfs_writel(tegra, value, IPFS_XUSB_HOST_INTR_MASK_0); |
---|
669 | 717 | |
---|
670 | | - /* Set hysteresis */ |
---|
671 | | - ipfs_writel(tegra, 0x80, IPFS_XUSB_HOST_CLKGATE_HYSTERESIS_0); |
---|
| 718 | + /* Set hysteresis */ |
---|
| 719 | + ipfs_writel(tegra, 0x80, IPFS_XUSB_HOST_CLKGATE_HYSTERESIS_0); |
---|
| 720 | + } |
---|
672 | 721 | } |
---|
673 | 722 | |
---|
674 | 723 | static int tegra_xusb_clk_enable(struct tegra_xusb *tegra) |
---|
.. | .. |
---|
774 | 823 | { |
---|
775 | 824 | struct tegra_xusb *tegra = dev_get_drvdata(dev); |
---|
776 | 825 | |
---|
777 | | - tegra_xusb_phy_disable(tegra); |
---|
778 | 826 | regulator_bulk_disable(tegra->soc->num_supplies, tegra->supplies); |
---|
779 | 827 | tegra_xusb_clk_disable(tegra); |
---|
780 | 828 | |
---|
.. | .. |
---|
798 | 846 | goto disable_clk; |
---|
799 | 847 | } |
---|
800 | 848 | |
---|
801 | | - err = tegra_xusb_phy_enable(tegra); |
---|
802 | | - if (err < 0) { |
---|
803 | | - dev_err(dev, "failed to enable PHYs: %d\n", err); |
---|
804 | | - goto disable_regulator; |
---|
805 | | - } |
---|
806 | | - |
---|
807 | 849 | return 0; |
---|
808 | 850 | |
---|
809 | | -disable_regulator: |
---|
810 | | - regulator_bulk_disable(tegra->soc->num_supplies, tegra->supplies); |
---|
811 | 851 | disable_clk: |
---|
812 | 852 | tegra_xusb_clk_disable(tegra); |
---|
813 | 853 | return err; |
---|
814 | 854 | } |
---|
815 | 855 | |
---|
816 | | -static int tegra_xusb_load_firmware(struct tegra_xusb *tegra) |
---|
| 856 | +#ifdef CONFIG_PM_SLEEP |
---|
| 857 | +static int tegra_xusb_init_context(struct tegra_xusb *tegra) |
---|
817 | 858 | { |
---|
818 | | - unsigned int code_tag_blocks, code_size_blocks, code_blocks; |
---|
| 859 | + const struct tegra_xusb_context_soc *soc = tegra->soc->context; |
---|
| 860 | + |
---|
| 861 | + tegra->context.ipfs = devm_kcalloc(tegra->dev, soc->ipfs.num_offsets, |
---|
| 862 | + sizeof(u32), GFP_KERNEL); |
---|
| 863 | + if (!tegra->context.ipfs) |
---|
| 864 | + return -ENOMEM; |
---|
| 865 | + |
---|
| 866 | + tegra->context.fpci = devm_kcalloc(tegra->dev, soc->fpci.num_offsets, |
---|
| 867 | + sizeof(u32), GFP_KERNEL); |
---|
| 868 | + if (!tegra->context.fpci) |
---|
| 869 | + return -ENOMEM; |
---|
| 870 | + |
---|
| 871 | + return 0; |
---|
| 872 | +} |
---|
| 873 | +#else |
---|
| 874 | +static inline int tegra_xusb_init_context(struct tegra_xusb *tegra) |
---|
| 875 | +{ |
---|
| 876 | + return 0; |
---|
| 877 | +} |
---|
| 878 | +#endif |
---|
| 879 | + |
---|
| 880 | +static int tegra_xusb_request_firmware(struct tegra_xusb *tegra) |
---|
| 881 | +{ |
---|
819 | 882 | struct tegra_xusb_fw_header *header; |
---|
820 | | - struct device *dev = tegra->dev; |
---|
821 | 883 | const struct firmware *fw; |
---|
822 | | - unsigned long timeout; |
---|
823 | | - time64_t timestamp; |
---|
824 | | - struct tm time; |
---|
825 | | - u64 address; |
---|
826 | | - u32 value; |
---|
827 | 884 | int err; |
---|
828 | 885 | |
---|
829 | 886 | err = request_firmware(&fw, tegra->soc->firmware, tegra->dev); |
---|
.. | .. |
---|
847 | 904 | header = (struct tegra_xusb_fw_header *)tegra->fw.virt; |
---|
848 | 905 | memcpy(tegra->fw.virt, fw->data, tegra->fw.size); |
---|
849 | 906 | release_firmware(fw); |
---|
| 907 | + |
---|
| 908 | + return 0; |
---|
| 909 | +} |
---|
| 910 | + |
---|
| 911 | +static int tegra_xusb_load_firmware(struct tegra_xusb *tegra) |
---|
| 912 | +{ |
---|
| 913 | + unsigned int code_tag_blocks, code_size_blocks, code_blocks; |
---|
| 914 | + struct xhci_cap_regs __iomem *cap = tegra->regs; |
---|
| 915 | + struct tegra_xusb_fw_header *header; |
---|
| 916 | + struct device *dev = tegra->dev; |
---|
| 917 | + struct xhci_op_regs __iomem *op; |
---|
| 918 | + unsigned long timeout; |
---|
| 919 | + time64_t timestamp; |
---|
| 920 | + struct tm time; |
---|
| 921 | + u64 address; |
---|
| 922 | + u32 value; |
---|
| 923 | + int err; |
---|
| 924 | + |
---|
| 925 | + header = (struct tegra_xusb_fw_header *)tegra->fw.virt; |
---|
| 926 | + op = tegra->regs + HC_LENGTH(readl(&cap->hc_capbase)); |
---|
850 | 927 | |
---|
851 | 928 | if (csb_readl(tegra, XUSB_CSB_MP_ILOAD_BASE_LO) != 0) { |
---|
852 | 929 | dev_info(dev, "Firmware already loaded, Falcon state %#x\n", |
---|
.. | .. |
---|
902 | 979 | |
---|
903 | 980 | csb_writel(tegra, 0, XUSB_FALC_DMACTL); |
---|
904 | 981 | |
---|
905 | | - msleep(50); |
---|
| 982 | + /* wait for RESULT_VLD to get set */ |
---|
| 983 | +#define tegra_csb_readl(offset) csb_readl(tegra, offset) |
---|
| 984 | + err = readx_poll_timeout(tegra_csb_readl, |
---|
| 985 | + XUSB_CSB_MEMPOOL_L2IMEMOP_RESULT, value, |
---|
| 986 | + value & L2IMEMOP_RESULT_VLD, 100, 10000); |
---|
| 987 | + if (err < 0) { |
---|
| 988 | + dev_err(dev, "DMA controller not ready %#010x\n", value); |
---|
| 989 | + return err; |
---|
| 990 | + } |
---|
| 991 | +#undef tegra_csb_readl |
---|
906 | 992 | |
---|
907 | 993 | csb_writel(tegra, le32_to_cpu(header->boot_codetag), |
---|
908 | 994 | XUSB_FALC_BOOTVEC); |
---|
909 | 995 | |
---|
910 | | - /* Boot Falcon CPU and wait for it to enter the STOPPED (idle) state. */ |
---|
911 | | - timeout = jiffies + msecs_to_jiffies(5); |
---|
912 | | - |
---|
| 996 | + /* Boot Falcon CPU and wait for USBSTS_CNR to get cleared. */ |
---|
913 | 997 | csb_writel(tegra, CPUCTL_STARTCPU, XUSB_FALC_CPUCTL); |
---|
914 | 998 | |
---|
915 | | - while (time_before(jiffies, timeout)) { |
---|
916 | | - if (csb_readl(tegra, XUSB_FALC_CPUCTL) == CPUCTL_STATE_STOPPED) |
---|
| 999 | + timeout = jiffies + msecs_to_jiffies(200); |
---|
| 1000 | + |
---|
| 1001 | + do { |
---|
| 1002 | + value = readl(&op->status); |
---|
| 1003 | + if ((value & STS_CNR) == 0) |
---|
917 | 1004 | break; |
---|
918 | 1005 | |
---|
919 | | - usleep_range(100, 200); |
---|
920 | | - } |
---|
| 1006 | + usleep_range(1000, 2000); |
---|
| 1007 | + } while (time_is_after_jiffies(timeout)); |
---|
921 | 1008 | |
---|
922 | | - if (csb_readl(tegra, XUSB_FALC_CPUCTL) != CPUCTL_STATE_STOPPED) { |
---|
923 | | - dev_err(dev, "Falcon failed to start, state: %#x\n", |
---|
924 | | - csb_readl(tegra, XUSB_FALC_CPUCTL)); |
---|
| 1009 | + value = readl(&op->status); |
---|
| 1010 | + if (value & STS_CNR) { |
---|
| 1011 | + value = csb_readl(tegra, XUSB_FALC_CPUCTL); |
---|
| 1012 | + dev_err(dev, "XHCI controller not read: %#010x\n", value); |
---|
925 | 1013 | return -EIO; |
---|
926 | 1014 | } |
---|
927 | 1015 | |
---|
.. | .. |
---|
935 | 1023 | return 0; |
---|
936 | 1024 | } |
---|
937 | 1025 | |
---|
938 | | -static int tegra_xusb_probe(struct platform_device *pdev) |
---|
| 1026 | +static void tegra_xusb_powerdomain_remove(struct device *dev, |
---|
| 1027 | + struct tegra_xusb *tegra) |
---|
| 1028 | +{ |
---|
| 1029 | + if (tegra->genpd_dl_ss) |
---|
| 1030 | + device_link_del(tegra->genpd_dl_ss); |
---|
| 1031 | + if (tegra->genpd_dl_host) |
---|
| 1032 | + device_link_del(tegra->genpd_dl_host); |
---|
| 1033 | + if (!IS_ERR_OR_NULL(tegra->genpd_dev_ss)) |
---|
| 1034 | + dev_pm_domain_detach(tegra->genpd_dev_ss, true); |
---|
| 1035 | + if (!IS_ERR_OR_NULL(tegra->genpd_dev_host)) |
---|
| 1036 | + dev_pm_domain_detach(tegra->genpd_dev_host, true); |
---|
| 1037 | +} |
---|
| 1038 | + |
---|
| 1039 | +static int tegra_xusb_powerdomain_init(struct device *dev, |
---|
| 1040 | + struct tegra_xusb *tegra) |
---|
| 1041 | +{ |
---|
| 1042 | + int err; |
---|
| 1043 | + |
---|
| 1044 | + tegra->genpd_dev_host = dev_pm_domain_attach_by_name(dev, "xusb_host"); |
---|
| 1045 | + if (IS_ERR_OR_NULL(tegra->genpd_dev_host)) { |
---|
| 1046 | + err = PTR_ERR(tegra->genpd_dev_host) ? : -ENODATA; |
---|
| 1047 | + dev_err(dev, "failed to get host pm-domain: %d\n", err); |
---|
| 1048 | + return err; |
---|
| 1049 | + } |
---|
| 1050 | + |
---|
| 1051 | + tegra->genpd_dev_ss = dev_pm_domain_attach_by_name(dev, "xusb_ss"); |
---|
| 1052 | + if (IS_ERR_OR_NULL(tegra->genpd_dev_ss)) { |
---|
| 1053 | + err = PTR_ERR(tegra->genpd_dev_ss) ? : -ENODATA; |
---|
| 1054 | + dev_err(dev, "failed to get superspeed pm-domain: %d\n", err); |
---|
| 1055 | + return err; |
---|
| 1056 | + } |
---|
| 1057 | + |
---|
| 1058 | + tegra->genpd_dl_host = device_link_add(dev, tegra->genpd_dev_host, |
---|
| 1059 | + DL_FLAG_PM_RUNTIME | |
---|
| 1060 | + DL_FLAG_STATELESS); |
---|
| 1061 | + if (!tegra->genpd_dl_host) { |
---|
| 1062 | + dev_err(dev, "adding host device link failed!\n"); |
---|
| 1063 | + return -ENODEV; |
---|
| 1064 | + } |
---|
| 1065 | + |
---|
| 1066 | + tegra->genpd_dl_ss = device_link_add(dev, tegra->genpd_dev_ss, |
---|
| 1067 | + DL_FLAG_PM_RUNTIME | |
---|
| 1068 | + DL_FLAG_STATELESS); |
---|
| 1069 | + if (!tegra->genpd_dl_ss) { |
---|
| 1070 | + dev_err(dev, "adding superspeed device link failed!\n"); |
---|
| 1071 | + return -ENODEV; |
---|
| 1072 | + } |
---|
| 1073 | + |
---|
| 1074 | + return 0; |
---|
| 1075 | +} |
---|
| 1076 | + |
---|
| 1077 | +static int __tegra_xusb_enable_firmware_messages(struct tegra_xusb *tegra) |
---|
939 | 1078 | { |
---|
940 | 1079 | struct tegra_xusb_mbox_msg msg; |
---|
941 | | - struct resource *res, *regs; |
---|
| 1080 | + int err; |
---|
| 1081 | + |
---|
| 1082 | + /* Enable firmware messages from controller. */ |
---|
| 1083 | + msg.cmd = MBOX_CMD_MSG_ENABLED; |
---|
| 1084 | + msg.data = 0; |
---|
| 1085 | + |
---|
| 1086 | + err = tegra_xusb_mbox_send(tegra, &msg); |
---|
| 1087 | + if (err < 0) |
---|
| 1088 | + dev_err(tegra->dev, "failed to enable messages: %d\n", err); |
---|
| 1089 | + |
---|
| 1090 | + return err; |
---|
| 1091 | +} |
---|
| 1092 | + |
---|
| 1093 | +static int tegra_xusb_enable_firmware_messages(struct tegra_xusb *tegra) |
---|
| 1094 | +{ |
---|
| 1095 | + int err; |
---|
| 1096 | + |
---|
| 1097 | + mutex_lock(&tegra->lock); |
---|
| 1098 | + err = __tegra_xusb_enable_firmware_messages(tegra); |
---|
| 1099 | + mutex_unlock(&tegra->lock); |
---|
| 1100 | + |
---|
| 1101 | + return err; |
---|
| 1102 | +} |
---|
| 1103 | + |
---|
| 1104 | +static void tegra_xhci_set_port_power(struct tegra_xusb *tegra, bool main, |
---|
| 1105 | + bool set) |
---|
| 1106 | +{ |
---|
| 1107 | + struct xhci_hcd *xhci = hcd_to_xhci(tegra->hcd); |
---|
| 1108 | + struct usb_hcd *hcd = main ? xhci->main_hcd : xhci->shared_hcd; |
---|
| 1109 | + unsigned int wait = (!main && !set) ? 1000 : 10; |
---|
| 1110 | + u16 typeReq = set ? SetPortFeature : ClearPortFeature; |
---|
| 1111 | + u16 wIndex = main ? tegra->otg_usb2_port + 1 : tegra->otg_usb3_port + 1; |
---|
| 1112 | + u32 status; |
---|
| 1113 | + u32 stat_power = main ? USB_PORT_STAT_POWER : USB_SS_PORT_STAT_POWER; |
---|
| 1114 | + u32 status_val = set ? stat_power : 0; |
---|
| 1115 | + |
---|
| 1116 | + dev_dbg(tegra->dev, "%s():%s %s port power\n", __func__, |
---|
| 1117 | + set ? "set" : "clear", main ? "HS" : "SS"); |
---|
| 1118 | + |
---|
| 1119 | + hcd->driver->hub_control(hcd, typeReq, USB_PORT_FEAT_POWER, wIndex, |
---|
| 1120 | + NULL, 0); |
---|
| 1121 | + |
---|
| 1122 | + do { |
---|
| 1123 | + tegra_xhci_hc_driver.hub_control(hcd, GetPortStatus, 0, wIndex, |
---|
| 1124 | + (char *) &status, sizeof(status)); |
---|
| 1125 | + if (status_val == (status & stat_power)) |
---|
| 1126 | + break; |
---|
| 1127 | + |
---|
| 1128 | + if (!main && !set) |
---|
| 1129 | + usleep_range(600, 700); |
---|
| 1130 | + else |
---|
| 1131 | + usleep_range(10, 20); |
---|
| 1132 | + } while (--wait > 0); |
---|
| 1133 | + |
---|
| 1134 | + if (status_val != (status & stat_power)) |
---|
| 1135 | + dev_info(tegra->dev, "failed to %s %s PP %d\n", |
---|
| 1136 | + set ? "set" : "clear", |
---|
| 1137 | + main ? "HS" : "SS", status); |
---|
| 1138 | +} |
---|
| 1139 | + |
---|
| 1140 | +static struct phy *tegra_xusb_get_phy(struct tegra_xusb *tegra, char *name, |
---|
| 1141 | + int port) |
---|
| 1142 | +{ |
---|
| 1143 | + unsigned int i, phy_count = 0; |
---|
| 1144 | + |
---|
| 1145 | + for (i = 0; i < tegra->soc->num_types; i++) { |
---|
| 1146 | + if (!strncmp(tegra->soc->phy_types[i].name, name, |
---|
| 1147 | + strlen(name))) |
---|
| 1148 | + return tegra->phys[phy_count+port]; |
---|
| 1149 | + |
---|
| 1150 | + phy_count += tegra->soc->phy_types[i].num; |
---|
| 1151 | + } |
---|
| 1152 | + |
---|
| 1153 | + return NULL; |
---|
| 1154 | +} |
---|
| 1155 | + |
---|
| 1156 | +static void tegra_xhci_id_work(struct work_struct *work) |
---|
| 1157 | +{ |
---|
| 1158 | + struct tegra_xusb *tegra = container_of(work, struct tegra_xusb, |
---|
| 1159 | + id_work); |
---|
| 1160 | + struct xhci_hcd *xhci = hcd_to_xhci(tegra->hcd); |
---|
| 1161 | + struct tegra_xusb_mbox_msg msg; |
---|
| 1162 | + struct phy *phy = tegra_xusb_get_phy(tegra, "usb2", |
---|
| 1163 | + tegra->otg_usb2_port); |
---|
| 1164 | + u32 status; |
---|
| 1165 | + int ret; |
---|
| 1166 | + |
---|
| 1167 | + dev_dbg(tegra->dev, "host mode %s\n", tegra->host_mode ? "on" : "off"); |
---|
| 1168 | + |
---|
| 1169 | + mutex_lock(&tegra->lock); |
---|
| 1170 | + |
---|
| 1171 | + if (tegra->host_mode) |
---|
| 1172 | + phy_set_mode_ext(phy, PHY_MODE_USB_OTG, USB_ROLE_HOST); |
---|
| 1173 | + else |
---|
| 1174 | + phy_set_mode_ext(phy, PHY_MODE_USB_OTG, USB_ROLE_NONE); |
---|
| 1175 | + |
---|
| 1176 | + mutex_unlock(&tegra->lock); |
---|
| 1177 | + |
---|
| 1178 | + if (tegra->host_mode) { |
---|
| 1179 | + /* switch to host mode */ |
---|
| 1180 | + if (tegra->otg_usb3_port >= 0) { |
---|
| 1181 | + if (tegra->soc->otg_reset_sspi) { |
---|
| 1182 | + /* set PP=0 */ |
---|
| 1183 | + tegra_xhci_hc_driver.hub_control( |
---|
| 1184 | + xhci->shared_hcd, GetPortStatus, |
---|
| 1185 | + 0, tegra->otg_usb3_port+1, |
---|
| 1186 | + (char *) &status, sizeof(status)); |
---|
| 1187 | + if (status & USB_SS_PORT_STAT_POWER) |
---|
| 1188 | + tegra_xhci_set_port_power(tegra, false, |
---|
| 1189 | + false); |
---|
| 1190 | + |
---|
| 1191 | + /* reset OTG port SSPI */ |
---|
| 1192 | + msg.cmd = MBOX_CMD_RESET_SSPI; |
---|
| 1193 | + msg.data = tegra->otg_usb3_port+1; |
---|
| 1194 | + |
---|
| 1195 | + ret = tegra_xusb_mbox_send(tegra, &msg); |
---|
| 1196 | + if (ret < 0) { |
---|
| 1197 | + dev_info(tegra->dev, |
---|
| 1198 | + "failed to RESET_SSPI %d\n", |
---|
| 1199 | + ret); |
---|
| 1200 | + } |
---|
| 1201 | + } |
---|
| 1202 | + |
---|
| 1203 | + tegra_xhci_set_port_power(tegra, false, true); |
---|
| 1204 | + } |
---|
| 1205 | + |
---|
| 1206 | + tegra_xhci_set_port_power(tegra, true, true); |
---|
| 1207 | + |
---|
| 1208 | + } else { |
---|
| 1209 | + if (tegra->otg_usb3_port >= 0) |
---|
| 1210 | + tegra_xhci_set_port_power(tegra, false, false); |
---|
| 1211 | + |
---|
| 1212 | + tegra_xhci_set_port_power(tegra, true, false); |
---|
| 1213 | + } |
---|
| 1214 | +} |
---|
| 1215 | + |
---|
| 1216 | +static int tegra_xusb_get_usb2_port(struct tegra_xusb *tegra, |
---|
| 1217 | + struct usb_phy *usbphy) |
---|
| 1218 | +{ |
---|
| 1219 | + unsigned int i; |
---|
| 1220 | + |
---|
| 1221 | + for (i = 0; i < tegra->num_usb_phys; i++) { |
---|
| 1222 | + if (tegra->usbphy[i] && usbphy == tegra->usbphy[i]) |
---|
| 1223 | + return i; |
---|
| 1224 | + } |
---|
| 1225 | + |
---|
| 1226 | + return -1; |
---|
| 1227 | +} |
---|
| 1228 | + |
---|
| 1229 | +static int tegra_xhci_id_notify(struct notifier_block *nb, |
---|
| 1230 | + unsigned long action, void *data) |
---|
| 1231 | +{ |
---|
| 1232 | + struct tegra_xusb *tegra = container_of(nb, struct tegra_xusb, |
---|
| 1233 | + id_nb); |
---|
| 1234 | + struct usb_phy *usbphy = (struct usb_phy *)data; |
---|
| 1235 | + |
---|
| 1236 | + dev_dbg(tegra->dev, "%s(): action is %d", __func__, usbphy->last_event); |
---|
| 1237 | + |
---|
| 1238 | + if ((tegra->host_mode && usbphy->last_event == USB_EVENT_ID) || |
---|
| 1239 | + (!tegra->host_mode && usbphy->last_event != USB_EVENT_ID)) { |
---|
| 1240 | + dev_dbg(tegra->dev, "Same role(%d) received. Ignore", |
---|
| 1241 | + tegra->host_mode); |
---|
| 1242 | + return NOTIFY_OK; |
---|
| 1243 | + } |
---|
| 1244 | + |
---|
| 1245 | + tegra->otg_usb2_port = tegra_xusb_get_usb2_port(tegra, usbphy); |
---|
| 1246 | + tegra->otg_usb3_port = tegra_xusb_padctl_get_usb3_companion( |
---|
| 1247 | + tegra->padctl, |
---|
| 1248 | + tegra->otg_usb2_port); |
---|
| 1249 | + |
---|
| 1250 | + tegra->host_mode = (usbphy->last_event == USB_EVENT_ID) ? true : false; |
---|
| 1251 | + |
---|
| 1252 | + schedule_work(&tegra->id_work); |
---|
| 1253 | + |
---|
| 1254 | + return NOTIFY_OK; |
---|
| 1255 | +} |
---|
| 1256 | + |
---|
| 1257 | +static int tegra_xusb_init_usb_phy(struct tegra_xusb *tegra) |
---|
| 1258 | +{ |
---|
| 1259 | + unsigned int i; |
---|
| 1260 | + |
---|
| 1261 | + tegra->usbphy = devm_kcalloc(tegra->dev, tegra->num_usb_phys, |
---|
| 1262 | + sizeof(*tegra->usbphy), GFP_KERNEL); |
---|
| 1263 | + if (!tegra->usbphy) |
---|
| 1264 | + return -ENOMEM; |
---|
| 1265 | + |
---|
| 1266 | + INIT_WORK(&tegra->id_work, tegra_xhci_id_work); |
---|
| 1267 | + tegra->id_nb.notifier_call = tegra_xhci_id_notify; |
---|
| 1268 | + tegra->otg_usb2_port = -EINVAL; |
---|
| 1269 | + tegra->otg_usb3_port = -EINVAL; |
---|
| 1270 | + |
---|
| 1271 | + for (i = 0; i < tegra->num_usb_phys; i++) { |
---|
| 1272 | + struct phy *phy = tegra_xusb_get_phy(tegra, "usb2", i); |
---|
| 1273 | + |
---|
| 1274 | + if (!phy) |
---|
| 1275 | + continue; |
---|
| 1276 | + |
---|
| 1277 | + tegra->usbphy[i] = devm_usb_get_phy_by_node(tegra->dev, |
---|
| 1278 | + phy->dev.of_node, |
---|
| 1279 | + &tegra->id_nb); |
---|
| 1280 | + if (!IS_ERR(tegra->usbphy[i])) { |
---|
| 1281 | + dev_dbg(tegra->dev, "usbphy-%d registered", i); |
---|
| 1282 | + otg_set_host(tegra->usbphy[i]->otg, &tegra->hcd->self); |
---|
| 1283 | + } else { |
---|
| 1284 | + /* |
---|
| 1285 | + * usb-phy is optional, continue if its not available. |
---|
| 1286 | + */ |
---|
| 1287 | + tegra->usbphy[i] = NULL; |
---|
| 1288 | + } |
---|
| 1289 | + } |
---|
| 1290 | + |
---|
| 1291 | + return 0; |
---|
| 1292 | +} |
---|
| 1293 | + |
---|
| 1294 | +static void tegra_xusb_deinit_usb_phy(struct tegra_xusb *tegra) |
---|
| 1295 | +{ |
---|
| 1296 | + unsigned int i; |
---|
| 1297 | + |
---|
| 1298 | + cancel_work_sync(&tegra->id_work); |
---|
| 1299 | + |
---|
| 1300 | + for (i = 0; i < tegra->num_usb_phys; i++) |
---|
| 1301 | + if (tegra->usbphy[i]) |
---|
| 1302 | + otg_set_host(tegra->usbphy[i]->otg, NULL); |
---|
| 1303 | +} |
---|
| 1304 | + |
---|
| 1305 | +static int tegra_xusb_probe(struct platform_device *pdev) |
---|
| 1306 | +{ |
---|
942 | 1307 | struct tegra_xusb *tegra; |
---|
| 1308 | + struct resource *regs; |
---|
943 | 1309 | struct xhci_hcd *xhci; |
---|
944 | 1310 | unsigned int i, j, k; |
---|
945 | 1311 | struct phy *phy; |
---|
.. | .. |
---|
955 | 1321 | mutex_init(&tegra->lock); |
---|
956 | 1322 | tegra->dev = &pdev->dev; |
---|
957 | 1323 | |
---|
| 1324 | + err = tegra_xusb_init_context(tegra); |
---|
| 1325 | + if (err < 0) |
---|
| 1326 | + return err; |
---|
| 1327 | + |
---|
958 | 1328 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
---|
959 | 1329 | tegra->regs = devm_ioremap_resource(&pdev->dev, regs); |
---|
960 | 1330 | if (IS_ERR(tegra->regs)) |
---|
961 | 1331 | return PTR_ERR(tegra->regs); |
---|
962 | 1332 | |
---|
963 | | - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); |
---|
964 | | - tegra->fpci_base = devm_ioremap_resource(&pdev->dev, res); |
---|
| 1333 | + tegra->fpci_base = devm_platform_ioremap_resource(pdev, 1); |
---|
965 | 1334 | if (IS_ERR(tegra->fpci_base)) |
---|
966 | 1335 | return PTR_ERR(tegra->fpci_base); |
---|
967 | 1336 | |
---|
968 | | - res = platform_get_resource(pdev, IORESOURCE_MEM, 2); |
---|
969 | | - tegra->ipfs_base = devm_ioremap_resource(&pdev->dev, res); |
---|
970 | | - if (IS_ERR(tegra->ipfs_base)) |
---|
971 | | - return PTR_ERR(tegra->ipfs_base); |
---|
| 1337 | + if (tegra->soc->has_ipfs) { |
---|
| 1338 | + tegra->ipfs_base = devm_platform_ioremap_resource(pdev, 2); |
---|
| 1339 | + if (IS_ERR(tegra->ipfs_base)) |
---|
| 1340 | + return PTR_ERR(tegra->ipfs_base); |
---|
| 1341 | + } |
---|
972 | 1342 | |
---|
973 | 1343 | tegra->xhci_irq = platform_get_irq(pdev, 0); |
---|
974 | 1344 | if (tegra->xhci_irq < 0) |
---|
.. | .. |
---|
1045 | 1415 | goto put_padctl; |
---|
1046 | 1416 | } |
---|
1047 | 1417 | |
---|
1048 | | - if (!pdev->dev.pm_domain) { |
---|
| 1418 | + if (!of_property_read_bool(pdev->dev.of_node, "power-domains")) { |
---|
1049 | 1419 | tegra->host_rst = devm_reset_control_get(&pdev->dev, |
---|
1050 | 1420 | "xusb_host"); |
---|
1051 | 1421 | if (IS_ERR(tegra->host_rst)) { |
---|
.. | .. |
---|
1076 | 1446 | tegra->host_clk, |
---|
1077 | 1447 | tegra->host_rst); |
---|
1078 | 1448 | if (err) { |
---|
| 1449 | + tegra_powergate_power_off(TEGRA_POWERGATE_XUSBA); |
---|
1079 | 1450 | dev_err(&pdev->dev, |
---|
1080 | 1451 | "failed to enable XUSBC domain: %d\n", err); |
---|
1081 | | - goto disable_xusba; |
---|
| 1452 | + goto put_padctl; |
---|
1082 | 1453 | } |
---|
| 1454 | + } else { |
---|
| 1455 | + err = tegra_xusb_powerdomain_init(&pdev->dev, tegra); |
---|
| 1456 | + if (err) |
---|
| 1457 | + goto put_powerdomains; |
---|
1083 | 1458 | } |
---|
1084 | 1459 | |
---|
1085 | 1460 | tegra->supplies = devm_kcalloc(&pdev->dev, tegra->soc->num_supplies, |
---|
1086 | 1461 | sizeof(*tegra->supplies), GFP_KERNEL); |
---|
1087 | 1462 | if (!tegra->supplies) { |
---|
1088 | 1463 | err = -ENOMEM; |
---|
1089 | | - goto disable_xusbc; |
---|
| 1464 | + goto put_powerdomains; |
---|
1090 | 1465 | } |
---|
1091 | 1466 | |
---|
1092 | | - for (i = 0; i < tegra->soc->num_supplies; i++) |
---|
1093 | | - tegra->supplies[i].supply = tegra->soc->supply_names[i]; |
---|
| 1467 | + regulator_bulk_set_supply_names(tegra->supplies, |
---|
| 1468 | + tegra->soc->supply_names, |
---|
| 1469 | + tegra->soc->num_supplies); |
---|
1094 | 1470 | |
---|
1095 | 1471 | err = devm_regulator_bulk_get(&pdev->dev, tegra->soc->num_supplies, |
---|
1096 | 1472 | tegra->supplies); |
---|
1097 | 1473 | if (err) { |
---|
1098 | 1474 | dev_err(&pdev->dev, "failed to get regulators: %d\n", err); |
---|
1099 | | - goto disable_xusbc; |
---|
| 1475 | + goto put_powerdomains; |
---|
1100 | 1476 | } |
---|
1101 | 1477 | |
---|
1102 | | - for (i = 0; i < tegra->soc->num_types; i++) |
---|
| 1478 | + for (i = 0; i < tegra->soc->num_types; i++) { |
---|
| 1479 | + if (!strncmp(tegra->soc->phy_types[i].name, "usb2", 4)) |
---|
| 1480 | + tegra->num_usb_phys = tegra->soc->phy_types[i].num; |
---|
1103 | 1481 | tegra->num_phys += tegra->soc->phy_types[i].num; |
---|
| 1482 | + } |
---|
1104 | 1483 | |
---|
1105 | 1484 | tegra->phys = devm_kcalloc(&pdev->dev, tegra->num_phys, |
---|
1106 | 1485 | sizeof(*tegra->phys), GFP_KERNEL); |
---|
1107 | 1486 | if (!tegra->phys) { |
---|
1108 | 1487 | err = -ENOMEM; |
---|
1109 | | - goto disable_xusbc; |
---|
| 1488 | + goto put_powerdomains; |
---|
1110 | 1489 | } |
---|
1111 | 1490 | |
---|
1112 | 1491 | for (i = 0, k = 0; i < tegra->soc->num_types; i++) { |
---|
.. | .. |
---|
1122 | 1501 | "failed to get PHY %s: %ld\n", prop, |
---|
1123 | 1502 | PTR_ERR(phy)); |
---|
1124 | 1503 | err = PTR_ERR(phy); |
---|
1125 | | - goto disable_xusbc; |
---|
| 1504 | + goto put_powerdomains; |
---|
1126 | 1505 | } |
---|
1127 | 1506 | |
---|
1128 | 1507 | tegra->phys[k++] = phy; |
---|
.. | .. |
---|
1133 | 1512 | dev_name(&pdev->dev)); |
---|
1134 | 1513 | if (!tegra->hcd) { |
---|
1135 | 1514 | err = -ENOMEM; |
---|
1136 | | - goto disable_xusbc; |
---|
| 1515 | + goto put_powerdomains; |
---|
1137 | 1516 | } |
---|
| 1517 | + |
---|
| 1518 | + tegra->hcd->regs = tegra->regs; |
---|
| 1519 | + tegra->hcd->rsrc_start = regs->start; |
---|
| 1520 | + tegra->hcd->rsrc_len = resource_size(regs); |
---|
1138 | 1521 | |
---|
1139 | 1522 | /* |
---|
1140 | 1523 | * This must happen after usb_create_hcd(), because usb_create_hcd() |
---|
.. | .. |
---|
1142 | 1525 | */ |
---|
1143 | 1526 | platform_set_drvdata(pdev, tegra); |
---|
1144 | 1527 | |
---|
1145 | | - pm_runtime_enable(&pdev->dev); |
---|
1146 | | - if (pm_runtime_enabled(&pdev->dev)) |
---|
1147 | | - err = pm_runtime_get_sync(&pdev->dev); |
---|
1148 | | - else |
---|
1149 | | - err = tegra_xusb_runtime_resume(&pdev->dev); |
---|
1150 | | - |
---|
| 1528 | + err = tegra_xusb_phy_enable(tegra); |
---|
1151 | 1529 | if (err < 0) { |
---|
1152 | | - dev_err(&pdev->dev, "failed to enable device: %d\n", err); |
---|
1153 | | - goto disable_rpm; |
---|
| 1530 | + dev_err(&pdev->dev, "failed to enable PHYs: %d\n", err); |
---|
| 1531 | + goto put_hcd; |
---|
1154 | 1532 | } |
---|
1155 | | - |
---|
1156 | | - tegra_xusb_ipfs_config(tegra, regs); |
---|
1157 | 1533 | |
---|
1158 | 1534 | /* |
---|
1159 | 1535 | * The XUSB Falcon microcontroller can only address 40 bits, so set |
---|
.. | .. |
---|
1162 | 1538 | err = dma_set_mask_and_coherent(tegra->dev, DMA_BIT_MASK(40)); |
---|
1163 | 1539 | if (err < 0) { |
---|
1164 | 1540 | dev_err(&pdev->dev, "failed to set DMA mask: %d\n", err); |
---|
1165 | | - goto put_rpm; |
---|
| 1541 | + goto disable_phy; |
---|
1166 | 1542 | } |
---|
| 1543 | + |
---|
| 1544 | + err = tegra_xusb_request_firmware(tegra); |
---|
| 1545 | + if (err < 0) { |
---|
| 1546 | + dev_err(&pdev->dev, "failed to request firmware: %d\n", err); |
---|
| 1547 | + goto disable_phy; |
---|
| 1548 | + } |
---|
| 1549 | + |
---|
| 1550 | + pm_runtime_enable(&pdev->dev); |
---|
| 1551 | + |
---|
| 1552 | + if (!pm_runtime_enabled(&pdev->dev)) |
---|
| 1553 | + err = tegra_xusb_runtime_resume(&pdev->dev); |
---|
| 1554 | + else |
---|
| 1555 | + err = pm_runtime_get_sync(&pdev->dev); |
---|
| 1556 | + |
---|
| 1557 | + if (err < 0) { |
---|
| 1558 | + dev_err(&pdev->dev, "failed to enable device: %d\n", err); |
---|
| 1559 | + goto free_firmware; |
---|
| 1560 | + } |
---|
| 1561 | + |
---|
| 1562 | + tegra_xusb_config(tegra); |
---|
1167 | 1563 | |
---|
1168 | 1564 | err = tegra_xusb_load_firmware(tegra); |
---|
1169 | 1565 | if (err < 0) { |
---|
1170 | 1566 | dev_err(&pdev->dev, "failed to load firmware: %d\n", err); |
---|
1171 | 1567 | goto put_rpm; |
---|
1172 | 1568 | } |
---|
1173 | | - |
---|
1174 | | - tegra->hcd->regs = tegra->regs; |
---|
1175 | | - tegra->hcd->rsrc_start = regs->start; |
---|
1176 | | - tegra->hcd->rsrc_len = resource_size(regs); |
---|
1177 | 1569 | |
---|
1178 | 1570 | err = usb_add_hcd(tegra->hcd, tegra->xhci_irq, IRQF_SHARED); |
---|
1179 | 1571 | if (err < 0) { |
---|
.. | .. |
---|
1201 | 1593 | goto put_usb3; |
---|
1202 | 1594 | } |
---|
1203 | 1595 | |
---|
1204 | | - mutex_lock(&tegra->lock); |
---|
1205 | | - |
---|
1206 | | - /* Enable firmware messages from controller. */ |
---|
1207 | | - msg.cmd = MBOX_CMD_MSG_ENABLED; |
---|
1208 | | - msg.data = 0; |
---|
1209 | | - |
---|
1210 | | - err = tegra_xusb_mbox_send(tegra, &msg); |
---|
| 1596 | + err = tegra_xusb_enable_firmware_messages(tegra); |
---|
1211 | 1597 | if (err < 0) { |
---|
1212 | 1598 | dev_err(&pdev->dev, "failed to enable messages: %d\n", err); |
---|
1213 | | - mutex_unlock(&tegra->lock); |
---|
1214 | 1599 | goto remove_usb3; |
---|
1215 | 1600 | } |
---|
1216 | | - |
---|
1217 | | - mutex_unlock(&tegra->lock); |
---|
1218 | 1601 | |
---|
1219 | 1602 | err = devm_request_threaded_irq(&pdev->dev, tegra->mbox_irq, |
---|
1220 | 1603 | tegra_xusb_mbox_irq, |
---|
.. | .. |
---|
1222 | 1605 | dev_name(&pdev->dev), tegra); |
---|
1223 | 1606 | if (err < 0) { |
---|
1224 | 1607 | dev_err(&pdev->dev, "failed to request IRQ: %d\n", err); |
---|
| 1608 | + goto remove_usb3; |
---|
| 1609 | + } |
---|
| 1610 | + |
---|
| 1611 | + err = tegra_xusb_init_usb_phy(tegra); |
---|
| 1612 | + if (err < 0) { |
---|
| 1613 | + dev_err(&pdev->dev, "failed to init USB PHY: %d\n", err); |
---|
1225 | 1614 | goto remove_usb3; |
---|
1226 | 1615 | } |
---|
1227 | 1616 | |
---|
.. | .. |
---|
1236 | 1625 | put_rpm: |
---|
1237 | 1626 | if (!pm_runtime_status_suspended(&pdev->dev)) |
---|
1238 | 1627 | tegra_xusb_runtime_suspend(&pdev->dev); |
---|
1239 | | -disable_rpm: |
---|
1240 | | - pm_runtime_disable(&pdev->dev); |
---|
| 1628 | +put_hcd: |
---|
1241 | 1629 | usb_put_hcd(tegra->hcd); |
---|
1242 | | -disable_xusbc: |
---|
1243 | | - if (!pdev->dev.pm_domain) |
---|
| 1630 | +free_firmware: |
---|
| 1631 | + dma_free_coherent(&pdev->dev, tegra->fw.size, tegra->fw.virt, |
---|
| 1632 | + tegra->fw.phys); |
---|
| 1633 | +disable_phy: |
---|
| 1634 | + tegra_xusb_phy_disable(tegra); |
---|
| 1635 | + pm_runtime_disable(&pdev->dev); |
---|
| 1636 | +put_powerdomains: |
---|
| 1637 | + if (!of_property_read_bool(pdev->dev.of_node, "power-domains")) { |
---|
1244 | 1638 | tegra_powergate_power_off(TEGRA_POWERGATE_XUSBC); |
---|
1245 | | -disable_xusba: |
---|
1246 | | - if (!pdev->dev.pm_domain) |
---|
1247 | 1639 | tegra_powergate_power_off(TEGRA_POWERGATE_XUSBA); |
---|
| 1640 | + } else { |
---|
| 1641 | + tegra_xusb_powerdomain_remove(&pdev->dev, tegra); |
---|
| 1642 | + } |
---|
1248 | 1643 | put_padctl: |
---|
1249 | 1644 | tegra_xusb_padctl_put(tegra->padctl); |
---|
1250 | 1645 | return err; |
---|
.. | .. |
---|
1254 | 1649 | { |
---|
1255 | 1650 | struct tegra_xusb *tegra = platform_get_drvdata(pdev); |
---|
1256 | 1651 | struct xhci_hcd *xhci = hcd_to_xhci(tegra->hcd); |
---|
| 1652 | + |
---|
| 1653 | + tegra_xusb_deinit_usb_phy(tegra); |
---|
1257 | 1654 | |
---|
1258 | 1655 | usb_remove_hcd(xhci->shared_hcd); |
---|
1259 | 1656 | usb_put_hcd(xhci->shared_hcd); |
---|
.. | .. |
---|
1267 | 1664 | pm_runtime_put_sync(&pdev->dev); |
---|
1268 | 1665 | pm_runtime_disable(&pdev->dev); |
---|
1269 | 1666 | |
---|
| 1667 | + if (!of_property_read_bool(pdev->dev.of_node, "power-domains")) { |
---|
| 1668 | + tegra_powergate_power_off(TEGRA_POWERGATE_XUSBC); |
---|
| 1669 | + tegra_powergate_power_off(TEGRA_POWERGATE_XUSBA); |
---|
| 1670 | + } else { |
---|
| 1671 | + tegra_xusb_powerdomain_remove(&pdev->dev, tegra); |
---|
| 1672 | + } |
---|
| 1673 | + |
---|
| 1674 | + tegra_xusb_phy_disable(tegra); |
---|
| 1675 | + |
---|
1270 | 1676 | tegra_xusb_padctl_put(tegra->padctl); |
---|
1271 | 1677 | |
---|
1272 | 1678 | return 0; |
---|
1273 | 1679 | } |
---|
1274 | 1680 | |
---|
1275 | 1681 | #ifdef CONFIG_PM_SLEEP |
---|
| 1682 | +static bool xhci_hub_ports_suspended(struct xhci_hub *hub) |
---|
| 1683 | +{ |
---|
| 1684 | + struct device *dev = hub->hcd->self.controller; |
---|
| 1685 | + bool status = true; |
---|
| 1686 | + unsigned int i; |
---|
| 1687 | + u32 value; |
---|
| 1688 | + |
---|
| 1689 | + for (i = 0; i < hub->num_ports; i++) { |
---|
| 1690 | + value = readl(hub->ports[i]->addr); |
---|
| 1691 | + if ((value & PORT_PE) == 0) |
---|
| 1692 | + continue; |
---|
| 1693 | + |
---|
| 1694 | + if ((value & PORT_PLS_MASK) != XDEV_U3) { |
---|
| 1695 | + dev_info(dev, "%u-%u isn't suspended: %#010x\n", |
---|
| 1696 | + hub->hcd->self.busnum, i + 1, value); |
---|
| 1697 | + status = false; |
---|
| 1698 | + } |
---|
| 1699 | + } |
---|
| 1700 | + |
---|
| 1701 | + return status; |
---|
| 1702 | +} |
---|
| 1703 | + |
---|
| 1704 | +static int tegra_xusb_check_ports(struct tegra_xusb *tegra) |
---|
| 1705 | +{ |
---|
| 1706 | + struct xhci_hcd *xhci = hcd_to_xhci(tegra->hcd); |
---|
| 1707 | + unsigned long flags; |
---|
| 1708 | + int err = 0; |
---|
| 1709 | + |
---|
| 1710 | + spin_lock_irqsave(&xhci->lock, flags); |
---|
| 1711 | + |
---|
| 1712 | + if (!xhci_hub_ports_suspended(&xhci->usb2_rhub) || |
---|
| 1713 | + !xhci_hub_ports_suspended(&xhci->usb3_rhub)) |
---|
| 1714 | + err = -EBUSY; |
---|
| 1715 | + |
---|
| 1716 | + spin_unlock_irqrestore(&xhci->lock, flags); |
---|
| 1717 | + |
---|
| 1718 | + return err; |
---|
| 1719 | +} |
---|
| 1720 | + |
---|
| 1721 | +static void tegra_xusb_save_context(struct tegra_xusb *tegra) |
---|
| 1722 | +{ |
---|
| 1723 | + const struct tegra_xusb_context_soc *soc = tegra->soc->context; |
---|
| 1724 | + struct tegra_xusb_context *ctx = &tegra->context; |
---|
| 1725 | + unsigned int i; |
---|
| 1726 | + |
---|
| 1727 | + if (soc->ipfs.num_offsets > 0) { |
---|
| 1728 | + for (i = 0; i < soc->ipfs.num_offsets; i++) |
---|
| 1729 | + ctx->ipfs[i] = ipfs_readl(tegra, soc->ipfs.offsets[i]); |
---|
| 1730 | + } |
---|
| 1731 | + |
---|
| 1732 | + if (soc->fpci.num_offsets > 0) { |
---|
| 1733 | + for (i = 0; i < soc->fpci.num_offsets; i++) |
---|
| 1734 | + ctx->fpci[i] = fpci_readl(tegra, soc->fpci.offsets[i]); |
---|
| 1735 | + } |
---|
| 1736 | +} |
---|
| 1737 | + |
---|
| 1738 | +static void tegra_xusb_restore_context(struct tegra_xusb *tegra) |
---|
| 1739 | +{ |
---|
| 1740 | + const struct tegra_xusb_context_soc *soc = tegra->soc->context; |
---|
| 1741 | + struct tegra_xusb_context *ctx = &tegra->context; |
---|
| 1742 | + unsigned int i; |
---|
| 1743 | + |
---|
| 1744 | + if (soc->fpci.num_offsets > 0) { |
---|
| 1745 | + for (i = 0; i < soc->fpci.num_offsets; i++) |
---|
| 1746 | + fpci_writel(tegra, ctx->fpci[i], soc->fpci.offsets[i]); |
---|
| 1747 | + } |
---|
| 1748 | + |
---|
| 1749 | + if (soc->ipfs.num_offsets > 0) { |
---|
| 1750 | + for (i = 0; i < soc->ipfs.num_offsets; i++) |
---|
| 1751 | + ipfs_writel(tegra, ctx->ipfs[i], soc->ipfs.offsets[i]); |
---|
| 1752 | + } |
---|
| 1753 | +} |
---|
| 1754 | + |
---|
| 1755 | +static int tegra_xusb_enter_elpg(struct tegra_xusb *tegra, bool wakeup) |
---|
| 1756 | +{ |
---|
| 1757 | + struct xhci_hcd *xhci = hcd_to_xhci(tegra->hcd); |
---|
| 1758 | + int err; |
---|
| 1759 | + |
---|
| 1760 | + err = tegra_xusb_check_ports(tegra); |
---|
| 1761 | + if (err < 0) { |
---|
| 1762 | + dev_err(tegra->dev, "not all ports suspended: %d\n", err); |
---|
| 1763 | + return err; |
---|
| 1764 | + } |
---|
| 1765 | + |
---|
| 1766 | + err = xhci_suspend(xhci, wakeup); |
---|
| 1767 | + if (err < 0) { |
---|
| 1768 | + dev_err(tegra->dev, "failed to suspend XHCI: %d\n", err); |
---|
| 1769 | + return err; |
---|
| 1770 | + } |
---|
| 1771 | + |
---|
| 1772 | + tegra_xusb_save_context(tegra); |
---|
| 1773 | + tegra_xusb_phy_disable(tegra); |
---|
| 1774 | + tegra_xusb_clk_disable(tegra); |
---|
| 1775 | + |
---|
| 1776 | + return 0; |
---|
| 1777 | +} |
---|
| 1778 | + |
---|
| 1779 | +static int tegra_xusb_exit_elpg(struct tegra_xusb *tegra, bool wakeup) |
---|
| 1780 | +{ |
---|
| 1781 | + struct xhci_hcd *xhci = hcd_to_xhci(tegra->hcd); |
---|
| 1782 | + int err; |
---|
| 1783 | + |
---|
| 1784 | + err = tegra_xusb_clk_enable(tegra); |
---|
| 1785 | + if (err < 0) { |
---|
| 1786 | + dev_err(tegra->dev, "failed to enable clocks: %d\n", err); |
---|
| 1787 | + return err; |
---|
| 1788 | + } |
---|
| 1789 | + |
---|
| 1790 | + err = tegra_xusb_phy_enable(tegra); |
---|
| 1791 | + if (err < 0) { |
---|
| 1792 | + dev_err(tegra->dev, "failed to enable PHYs: %d\n", err); |
---|
| 1793 | + goto disable_clk; |
---|
| 1794 | + } |
---|
| 1795 | + |
---|
| 1796 | + tegra_xusb_config(tegra); |
---|
| 1797 | + tegra_xusb_restore_context(tegra); |
---|
| 1798 | + |
---|
| 1799 | + err = tegra_xusb_load_firmware(tegra); |
---|
| 1800 | + if (err < 0) { |
---|
| 1801 | + dev_err(tegra->dev, "failed to load firmware: %d\n", err); |
---|
| 1802 | + goto disable_phy; |
---|
| 1803 | + } |
---|
| 1804 | + |
---|
| 1805 | + err = __tegra_xusb_enable_firmware_messages(tegra); |
---|
| 1806 | + if (err < 0) { |
---|
| 1807 | + dev_err(tegra->dev, "failed to enable messages: %d\n", err); |
---|
| 1808 | + goto disable_phy; |
---|
| 1809 | + } |
---|
| 1810 | + |
---|
| 1811 | + err = xhci_resume(xhci, true); |
---|
| 1812 | + if (err < 0) { |
---|
| 1813 | + dev_err(tegra->dev, "failed to resume XHCI: %d\n", err); |
---|
| 1814 | + goto disable_phy; |
---|
| 1815 | + } |
---|
| 1816 | + |
---|
| 1817 | + return 0; |
---|
| 1818 | + |
---|
| 1819 | +disable_phy: |
---|
| 1820 | + tegra_xusb_phy_disable(tegra); |
---|
| 1821 | +disable_clk: |
---|
| 1822 | + tegra_xusb_clk_disable(tegra); |
---|
| 1823 | + return err; |
---|
| 1824 | +} |
---|
| 1825 | + |
---|
1276 | 1826 | static int tegra_xusb_suspend(struct device *dev) |
---|
1277 | 1827 | { |
---|
1278 | 1828 | struct tegra_xusb *tegra = dev_get_drvdata(dev); |
---|
1279 | | - struct xhci_hcd *xhci = hcd_to_xhci(tegra->hcd); |
---|
1280 | 1829 | bool wakeup = device_may_wakeup(dev); |
---|
| 1830 | + int err; |
---|
1281 | 1831 | |
---|
1282 | | - /* TODO: Powergate controller across suspend/resume. */ |
---|
1283 | | - return xhci_suspend(xhci, wakeup); |
---|
| 1832 | + synchronize_irq(tegra->mbox_irq); |
---|
| 1833 | + |
---|
| 1834 | + mutex_lock(&tegra->lock); |
---|
| 1835 | + err = tegra_xusb_enter_elpg(tegra, wakeup); |
---|
| 1836 | + mutex_unlock(&tegra->lock); |
---|
| 1837 | + |
---|
| 1838 | + return err; |
---|
1284 | 1839 | } |
---|
1285 | 1840 | |
---|
1286 | 1841 | static int tegra_xusb_resume(struct device *dev) |
---|
1287 | 1842 | { |
---|
1288 | 1843 | struct tegra_xusb *tegra = dev_get_drvdata(dev); |
---|
1289 | | - struct xhci_hcd *xhci = hcd_to_xhci(tegra->hcd); |
---|
| 1844 | + bool wakeup = device_may_wakeup(dev); |
---|
| 1845 | + int err; |
---|
1290 | 1846 | |
---|
1291 | | - return xhci_resume(xhci, 0); |
---|
| 1847 | + mutex_lock(&tegra->lock); |
---|
| 1848 | + err = tegra_xusb_exit_elpg(tegra, wakeup); |
---|
| 1849 | + mutex_unlock(&tegra->lock); |
---|
| 1850 | + |
---|
| 1851 | + return err; |
---|
1292 | 1852 | } |
---|
1293 | 1853 | #endif |
---|
1294 | 1854 | |
---|
.. | .. |
---|
1302 | 1862 | "avddio-pex", |
---|
1303 | 1863 | "dvddio-pex", |
---|
1304 | 1864 | "avdd-usb", |
---|
1305 | | - "avdd-pll-utmip", |
---|
1306 | | - "avdd-pll-erefe", |
---|
1307 | | - "avdd-usb-ss-pll", |
---|
1308 | 1865 | "hvdd-usb-ss", |
---|
1309 | | - "hvdd-usb-ss-pll-e", |
---|
1310 | 1866 | }; |
---|
1311 | 1867 | |
---|
1312 | 1868 | static const struct tegra_xusb_phy_type tegra124_phy_types[] = { |
---|
.. | .. |
---|
1315 | 1871 | { .name = "hsic", .num = 2, }, |
---|
1316 | 1872 | }; |
---|
1317 | 1873 | |
---|
| 1874 | +static const unsigned int tegra124_xusb_context_ipfs[] = { |
---|
| 1875 | + IPFS_XUSB_HOST_MSI_BAR_SZ_0, |
---|
| 1876 | + IPFS_XUSB_HOST_MSI_AXI_BAR_ST_0, |
---|
| 1877 | + IPFS_XUSB_HOST_MSI_FPCI_BAR_ST_0, |
---|
| 1878 | + IPFS_XUSB_HOST_MSI_VEC0_0, |
---|
| 1879 | + IPFS_XUSB_HOST_MSI_EN_VEC0_0, |
---|
| 1880 | + IPFS_XUSB_HOST_FPCI_ERROR_MASKS_0, |
---|
| 1881 | + IPFS_XUSB_HOST_INTR_MASK_0, |
---|
| 1882 | + IPFS_XUSB_HOST_INTR_ENABLE_0, |
---|
| 1883 | + IPFS_XUSB_HOST_UFPCI_CONFIG_0, |
---|
| 1884 | + IPFS_XUSB_HOST_CLKGATE_HYSTERESIS_0, |
---|
| 1885 | + IPFS_XUSB_HOST_MCCIF_FIFOCTRL_0, |
---|
| 1886 | +}; |
---|
| 1887 | + |
---|
| 1888 | +static const unsigned int tegra124_xusb_context_fpci[] = { |
---|
| 1889 | + XUSB_CFG_ARU_CONTEXT_HS_PLS, |
---|
| 1890 | + XUSB_CFG_ARU_CONTEXT_FS_PLS, |
---|
| 1891 | + XUSB_CFG_ARU_CONTEXT_HSFS_SPEED, |
---|
| 1892 | + XUSB_CFG_ARU_CONTEXT_HSFS_PP, |
---|
| 1893 | + XUSB_CFG_ARU_CONTEXT, |
---|
| 1894 | + XUSB_CFG_AXI_CFG, |
---|
| 1895 | + XUSB_CFG_24, |
---|
| 1896 | + XUSB_CFG_16, |
---|
| 1897 | +}; |
---|
| 1898 | + |
---|
| 1899 | +static const struct tegra_xusb_context_soc tegra124_xusb_context = { |
---|
| 1900 | + .ipfs = { |
---|
| 1901 | + .num_offsets = ARRAY_SIZE(tegra124_xusb_context_ipfs), |
---|
| 1902 | + .offsets = tegra124_xusb_context_ipfs, |
---|
| 1903 | + }, |
---|
| 1904 | + .fpci = { |
---|
| 1905 | + .num_offsets = ARRAY_SIZE(tegra124_xusb_context_fpci), |
---|
| 1906 | + .offsets = tegra124_xusb_context_fpci, |
---|
| 1907 | + }, |
---|
| 1908 | +}; |
---|
| 1909 | + |
---|
1318 | 1910 | static const struct tegra_xusb_soc tegra124_soc = { |
---|
1319 | 1911 | .firmware = "nvidia/tegra124/xusb.bin", |
---|
1320 | 1912 | .supply_names = tegra124_supply_names, |
---|
1321 | 1913 | .num_supplies = ARRAY_SIZE(tegra124_supply_names), |
---|
1322 | 1914 | .phy_types = tegra124_phy_types, |
---|
1323 | 1915 | .num_types = ARRAY_SIZE(tegra124_phy_types), |
---|
| 1916 | + .context = &tegra124_xusb_context, |
---|
1324 | 1917 | .ports = { |
---|
1325 | 1918 | .usb2 = { .offset = 4, .count = 4, }, |
---|
1326 | 1919 | .hsic = { .offset = 6, .count = 2, }, |
---|
1327 | 1920 | .usb3 = { .offset = 0, .count = 2, }, |
---|
1328 | 1921 | }, |
---|
1329 | 1922 | .scale_ss_clock = true, |
---|
| 1923 | + .has_ipfs = true, |
---|
| 1924 | + .otg_reset_sspi = false, |
---|
| 1925 | + .mbox = { |
---|
| 1926 | + .cmd = 0xe4, |
---|
| 1927 | + .data_in = 0xe8, |
---|
| 1928 | + .data_out = 0xec, |
---|
| 1929 | + .owner = 0xf0, |
---|
| 1930 | + }, |
---|
1330 | 1931 | }; |
---|
1331 | 1932 | MODULE_FIRMWARE("nvidia/tegra124/xusb.bin"); |
---|
1332 | 1933 | |
---|
.. | .. |
---|
1334 | 1935 | "dvddio-pex", |
---|
1335 | 1936 | "hvddio-pex", |
---|
1336 | 1937 | "avdd-usb", |
---|
1337 | | - "avdd-pll-utmip", |
---|
1338 | | - "avdd-pll-uerefe", |
---|
1339 | | - "dvdd-pex-pll", |
---|
1340 | | - "hvdd-pex-pll-e", |
---|
1341 | 1938 | }; |
---|
1342 | 1939 | |
---|
1343 | 1940 | static const struct tegra_xusb_phy_type tegra210_phy_types[] = { |
---|
.. | .. |
---|
1352 | 1949 | .num_supplies = ARRAY_SIZE(tegra210_supply_names), |
---|
1353 | 1950 | .phy_types = tegra210_phy_types, |
---|
1354 | 1951 | .num_types = ARRAY_SIZE(tegra210_phy_types), |
---|
| 1952 | + .context = &tegra124_xusb_context, |
---|
1355 | 1953 | .ports = { |
---|
1356 | 1954 | .usb2 = { .offset = 4, .count = 4, }, |
---|
1357 | 1955 | .hsic = { .offset = 8, .count = 1, }, |
---|
1358 | 1956 | .usb3 = { .offset = 0, .count = 4, }, |
---|
1359 | 1957 | }, |
---|
1360 | 1958 | .scale_ss_clock = false, |
---|
| 1959 | + .has_ipfs = true, |
---|
| 1960 | + .otg_reset_sspi = true, |
---|
| 1961 | + .mbox = { |
---|
| 1962 | + .cmd = 0xe4, |
---|
| 1963 | + .data_in = 0xe8, |
---|
| 1964 | + .data_out = 0xec, |
---|
| 1965 | + .owner = 0xf0, |
---|
| 1966 | + }, |
---|
1361 | 1967 | }; |
---|
1362 | 1968 | MODULE_FIRMWARE("nvidia/tegra210/xusb.bin"); |
---|
| 1969 | + |
---|
| 1970 | +static const char * const tegra186_supply_names[] = { |
---|
| 1971 | +}; |
---|
| 1972 | +MODULE_FIRMWARE("nvidia/tegra186/xusb.bin"); |
---|
| 1973 | + |
---|
| 1974 | +static const struct tegra_xusb_phy_type tegra186_phy_types[] = { |
---|
| 1975 | + { .name = "usb3", .num = 3, }, |
---|
| 1976 | + { .name = "usb2", .num = 3, }, |
---|
| 1977 | + { .name = "hsic", .num = 1, }, |
---|
| 1978 | +}; |
---|
| 1979 | + |
---|
| 1980 | +static const struct tegra_xusb_context_soc tegra186_xusb_context = { |
---|
| 1981 | + .fpci = { |
---|
| 1982 | + .num_offsets = ARRAY_SIZE(tegra124_xusb_context_fpci), |
---|
| 1983 | + .offsets = tegra124_xusb_context_fpci, |
---|
| 1984 | + }, |
---|
| 1985 | +}; |
---|
| 1986 | + |
---|
| 1987 | +static const struct tegra_xusb_soc tegra186_soc = { |
---|
| 1988 | + .firmware = "nvidia/tegra186/xusb.bin", |
---|
| 1989 | + .supply_names = tegra186_supply_names, |
---|
| 1990 | + .num_supplies = ARRAY_SIZE(tegra186_supply_names), |
---|
| 1991 | + .phy_types = tegra186_phy_types, |
---|
| 1992 | + .num_types = ARRAY_SIZE(tegra186_phy_types), |
---|
| 1993 | + .context = &tegra186_xusb_context, |
---|
| 1994 | + .ports = { |
---|
| 1995 | + .usb3 = { .offset = 0, .count = 3, }, |
---|
| 1996 | + .usb2 = { .offset = 3, .count = 3, }, |
---|
| 1997 | + .hsic = { .offset = 6, .count = 1, }, |
---|
| 1998 | + }, |
---|
| 1999 | + .scale_ss_clock = false, |
---|
| 2000 | + .has_ipfs = false, |
---|
| 2001 | + .otg_reset_sspi = false, |
---|
| 2002 | + .mbox = { |
---|
| 2003 | + .cmd = 0xe4, |
---|
| 2004 | + .data_in = 0xe8, |
---|
| 2005 | + .data_out = 0xec, |
---|
| 2006 | + .owner = 0xf0, |
---|
| 2007 | + }, |
---|
| 2008 | + .lpm_support = true, |
---|
| 2009 | +}; |
---|
| 2010 | + |
---|
| 2011 | +static const char * const tegra194_supply_names[] = { |
---|
| 2012 | +}; |
---|
| 2013 | + |
---|
| 2014 | +static const struct tegra_xusb_phy_type tegra194_phy_types[] = { |
---|
| 2015 | + { .name = "usb3", .num = 4, }, |
---|
| 2016 | + { .name = "usb2", .num = 4, }, |
---|
| 2017 | +}; |
---|
| 2018 | + |
---|
| 2019 | +static const struct tegra_xusb_soc tegra194_soc = { |
---|
| 2020 | + .firmware = "nvidia/tegra194/xusb.bin", |
---|
| 2021 | + .supply_names = tegra194_supply_names, |
---|
| 2022 | + .num_supplies = ARRAY_SIZE(tegra194_supply_names), |
---|
| 2023 | + .phy_types = tegra194_phy_types, |
---|
| 2024 | + .num_types = ARRAY_SIZE(tegra194_phy_types), |
---|
| 2025 | + .context = &tegra186_xusb_context, |
---|
| 2026 | + .ports = { |
---|
| 2027 | + .usb3 = { .offset = 0, .count = 4, }, |
---|
| 2028 | + .usb2 = { .offset = 4, .count = 4, }, |
---|
| 2029 | + }, |
---|
| 2030 | + .scale_ss_clock = false, |
---|
| 2031 | + .has_ipfs = false, |
---|
| 2032 | + .otg_reset_sspi = false, |
---|
| 2033 | + .mbox = { |
---|
| 2034 | + .cmd = 0x68, |
---|
| 2035 | + .data_in = 0x6c, |
---|
| 2036 | + .data_out = 0x70, |
---|
| 2037 | + .owner = 0x74, |
---|
| 2038 | + }, |
---|
| 2039 | + .lpm_support = true, |
---|
| 2040 | +}; |
---|
| 2041 | +MODULE_FIRMWARE("nvidia/tegra194/xusb.bin"); |
---|
1363 | 2042 | |
---|
1364 | 2043 | static const struct of_device_id tegra_xusb_of_match[] = { |
---|
1365 | 2044 | { .compatible = "nvidia,tegra124-xusb", .data = &tegra124_soc }, |
---|
1366 | 2045 | { .compatible = "nvidia,tegra210-xusb", .data = &tegra210_soc }, |
---|
| 2046 | + { .compatible = "nvidia,tegra186-xusb", .data = &tegra186_soc }, |
---|
| 2047 | + { .compatible = "nvidia,tegra194-xusb", .data = &tegra194_soc }, |
---|
1367 | 2048 | { }, |
---|
1368 | 2049 | }; |
---|
1369 | 2050 | MODULE_DEVICE_TABLE(of, tegra_xusb_of_match); |
---|
.. | .. |
---|
1380 | 2061 | |
---|
1381 | 2062 | static void tegra_xhci_quirks(struct device *dev, struct xhci_hcd *xhci) |
---|
1382 | 2063 | { |
---|
| 2064 | + struct tegra_xusb *tegra = dev_get_drvdata(dev); |
---|
| 2065 | + |
---|
1383 | 2066 | xhci->quirks |= XHCI_PLAT; |
---|
| 2067 | + if (tegra && tegra->soc->lpm_support) |
---|
| 2068 | + xhci->quirks |= XHCI_LPM_SUPPORT; |
---|
1384 | 2069 | } |
---|
1385 | 2070 | |
---|
1386 | 2071 | static int tegra_xhci_setup(struct usb_hcd *hcd) |
---|