]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - drivers/usb/host/whci/init.c
USB: host: whci: Remove redundant license text
[mirror_ubuntu-bionic-kernel.git] / drivers / usb / host / whci / init.c
CommitLineData
5fd54ace 1// SPDX-License-Identifier: GPL-2.0
7e6133aa
DV
2/*
3 * Wireless Host Controller (WHC) initialization.
4 *
5 * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
7e6133aa
DV
6 */
7#include <linux/kernel.h>
5a0e3ad6 8#include <linux/gfp.h>
7e6133aa
DV
9#include <linux/dma-mapping.h>
10#include <linux/uwb/umc.h>
11
12#include "../../wusbcore/wusbhc.h"
13
14#include "whcd.h"
15
16/*
17 * Reset the host controller.
18 */
19static void whc_hw_reset(struct whc *whc)
20{
21 le_writel(WUSBCMD_WHCRESET, whc->base + WUSBCMD);
22 whci_wait_for(&whc->umc->dev, whc->base + WUSBCMD, WUSBCMD_WHCRESET, 0,
23 100, "reset");
24}
25
26static void whc_hw_init_di_buf(struct whc *whc)
27{
28 int d;
29
30 /* Disable all entries in the Device Information buffer. */
31 for (d = 0; d < whc->n_devices; d++)
32 whc->di_buf[d].addr_sec_info = WHC_DI_DISABLE;
33
34 le_writeq(whc->di_buf_dma, whc->base + WUSBDEVICEINFOADDR);
35}
36
37static void whc_hw_init_dn_buf(struct whc *whc)
38{
39 /* Clear the Device Notification buffer to ensure the V (valid)
40 * bits are clear. */
41 memset(whc->dn_buf, 0, 4096);
42
43 le_writeq(whc->dn_buf_dma, whc->base + WUSBDNTSBUFADDR);
44}
45
46int whc_init(struct whc *whc)
47{
48 u32 whcsparams;
49 int ret, i;
50 resource_size_t start, len;
51
52 spin_lock_init(&whc->lock);
53 mutex_init(&whc->mutex);
54 init_waitqueue_head(&whc->cmd_wq);
55 init_waitqueue_head(&whc->async_list_wq);
56 init_waitqueue_head(&whc->periodic_list_wq);
d35cbed6 57 whc->workqueue = alloc_ordered_workqueue(dev_name(&whc->umc->dev), 0);
7e6133aa
DV
58 if (whc->workqueue == NULL) {
59 ret = -ENOMEM;
60 goto error;
61 }
62 INIT_WORK(&whc->dn_work, whc_dn_work);
63
64 INIT_WORK(&whc->async_work, scan_async_work);
65 INIT_LIST_HEAD(&whc->async_list);
66 INIT_LIST_HEAD(&whc->async_removed_list);
67
68 INIT_WORK(&whc->periodic_work, scan_periodic_work);
69 for (i = 0; i < 5; i++)
70 INIT_LIST_HEAD(&whc->periodic_list[i]);
71 INIT_LIST_HEAD(&whc->periodic_removed_list);
72
73 /* Map HC registers. */
74 start = whc->umc->resource.start;
75 len = whc->umc->resource.end - start + 1;
76 if (!request_mem_region(start, len, "whci-hc")) {
77 dev_err(&whc->umc->dev, "can't request HC region\n");
78 ret = -EBUSY;
79 goto error;
80 }
81 whc->base_phys = start;
82 whc->base = ioremap(start, len);
83 if (!whc->base) {
84 dev_err(&whc->umc->dev, "ioremap\n");
85 ret = -ENOMEM;
86 goto error;
87 }
88
89 whc_hw_reset(whc);
90
91 /* Read maximum number of devices, keys and MMC IEs. */
92 whcsparams = le_readl(whc->base + WHCSPARAMS);
93 whc->n_devices = WHCSPARAMS_TO_N_DEVICES(whcsparams);
94 whc->n_keys = WHCSPARAMS_TO_N_KEYS(whcsparams);
95 whc->n_mmc_ies = WHCSPARAMS_TO_N_MMC_IES(whcsparams);
96
97 dev_dbg(&whc->umc->dev, "N_DEVICES = %d, N_KEYS = %d, N_MMC_IES = %d\n",
98 whc->n_devices, whc->n_keys, whc->n_mmc_ies);
99
100 whc->qset_pool = dma_pool_create("qset", &whc->umc->dev,
101 sizeof(struct whc_qset), 64, 0);
102 if (whc->qset_pool == NULL) {
103 ret = -ENOMEM;
104 goto error;
105 }
106
107 ret = asl_init(whc);
108 if (ret < 0)
109 goto error;
110 ret = pzl_init(whc);
111 if (ret < 0)
112 goto error;
113
114 /* Allocate and initialize a buffer for generic commands, the
115 Device Information buffer, and the Device Notification
116 buffer. */
117
118 whc->gen_cmd_buf = dma_alloc_coherent(&whc->umc->dev, WHC_GEN_CMD_DATA_LEN,
119 &whc->gen_cmd_buf_dma, GFP_KERNEL);
120 if (whc->gen_cmd_buf == NULL) {
121 ret = -ENOMEM;
122 goto error;
123 }
124
125 whc->dn_buf = dma_alloc_coherent(&whc->umc->dev,
126 sizeof(struct dn_buf_entry) * WHC_N_DN_ENTRIES,
127 &whc->dn_buf_dma, GFP_KERNEL);
128 if (!whc->dn_buf) {
129 ret = -ENOMEM;
130 goto error;
131 }
132 whc_hw_init_dn_buf(whc);
133
134 whc->di_buf = dma_alloc_coherent(&whc->umc->dev,
135 sizeof(struct di_buf_entry) * whc->n_devices,
136 &whc->di_buf_dma, GFP_KERNEL);
137 if (!whc->di_buf) {
138 ret = -ENOMEM;
139 goto error;
140 }
141 whc_hw_init_di_buf(whc);
142
143 return 0;
144
145error:
146 whc_clean_up(whc);
147 return ret;
148}
149
150void whc_clean_up(struct whc *whc)
151{
152 resource_size_t len;
153
154 if (whc->di_buf)
155 dma_free_coherent(&whc->umc->dev, sizeof(struct di_buf_entry) * whc->n_devices,
156 whc->di_buf, whc->di_buf_dma);
157 if (whc->dn_buf)
158 dma_free_coherent(&whc->umc->dev, sizeof(struct dn_buf_entry) * WHC_N_DN_ENTRIES,
159 whc->dn_buf, whc->dn_buf_dma);
160 if (whc->gen_cmd_buf)
161 dma_free_coherent(&whc->umc->dev, WHC_GEN_CMD_DATA_LEN,
162 whc->gen_cmd_buf, whc->gen_cmd_buf_dma);
163
164 pzl_clean_up(whc);
165 asl_clean_up(whc);
166
03bce87c 167 dma_pool_destroy(whc->qset_pool);
7e6133aa 168
28f65c11 169 len = resource_size(&whc->umc->resource);
7e6133aa
DV
170 if (whc->base)
171 iounmap(whc->base);
172 if (whc->base_phys)
173 release_mem_region(whc->base_phys, len);
174
175 if (whc->workqueue)
176 destroy_workqueue(whc->workqueue);
177}