1 // SPDX-License-Identifier: GPL-2.0
3 * Wireless Host Controller (WHC) initialization.
5 * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
7 #include <linux/kernel.h>
9 #include <linux/dma-mapping.h>
10 #include <linux/uwb/umc.h>
12 #include "../../wusbcore/wusbhc.h"
17 * Reset the host controller.
19 static void whc_hw_reset(struct whc
*whc
)
21 le_writel(WUSBCMD_WHCRESET
, whc
->base
+ WUSBCMD
);
22 whci_wait_for(&whc
->umc
->dev
, whc
->base
+ WUSBCMD
, WUSBCMD_WHCRESET
, 0,
26 static void whc_hw_init_di_buf(struct whc
*whc
)
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
;
34 le_writeq(whc
->di_buf_dma
, whc
->base
+ WUSBDEVICEINFOADDR
);
37 static void whc_hw_init_dn_buf(struct whc
*whc
)
39 /* Clear the Device Notification buffer to ensure the V (valid)
41 memset(whc
->dn_buf
, 0, 4096);
43 le_writeq(whc
->dn_buf_dma
, whc
->base
+ WUSBDNTSBUFADDR
);
46 int whc_init(struct whc
*whc
)
50 resource_size_t start
, len
;
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
);
57 whc
->workqueue
= alloc_ordered_workqueue(dev_name(&whc
->umc
->dev
), 0);
58 if (whc
->workqueue
== NULL
) {
62 INIT_WORK(&whc
->dn_work
, whc_dn_work
);
64 INIT_WORK(&whc
->async_work
, scan_async_work
);
65 INIT_LIST_HEAD(&whc
->async_list
);
66 INIT_LIST_HEAD(&whc
->async_removed_list
);
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
);
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");
81 whc
->base_phys
= start
;
82 whc
->base
= ioremap(start
, len
);
84 dev_err(&whc
->umc
->dev
, "ioremap\n");
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
);
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
);
100 whc
->qset_pool
= dma_pool_create("qset", &whc
->umc
->dev
,
101 sizeof(struct whc_qset
), 64, 0);
102 if (whc
->qset_pool
== NULL
) {
114 /* Allocate and initialize a buffer for generic commands, the
115 Device Information buffer, and the Device Notification
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
) {
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
);
132 whc_hw_init_dn_buf(whc
);
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
);
141 whc_hw_init_di_buf(whc
);
150 void whc_clean_up(struct whc
*whc
)
155 dma_free_coherent(&whc
->umc
->dev
, sizeof(struct di_buf_entry
) * whc
->n_devices
,
156 whc
->di_buf
, whc
->di_buf_dma
);
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
);
167 dma_pool_destroy(whc
->qset_pool
);
169 len
= resource_size(&whc
->umc
->resource
);
173 release_mem_region(whc
->base_phys
, len
);
176 destroy_workqueue(whc
->workqueue
);