File Index
Files and directories
Sign in
FILE

hidma_mgmt.c

File preview with syntax highlighting.

linux-6.19.14/drivers/dma/qcom/hidma_mgmt.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Qualcomm Technologies HIDMA DMA engine Management interface
  4 *
  5 * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
  6 */
  7
  8#include <linux/dmaengine.h>
  9#include <linux/acpi.h>
 10#include <linux/property.h>
 11#include <linux/platform_device.h>
 12#include <linux/module.h>
 13#include <linux/uaccess.h>
 14#include <linux/slab.h>
 15#include <linux/pm_runtime.h>
 16#include <linux/bitops.h>
 17#include <linux/dma-mapping.h>
 18
 19#include "hidma_mgmt.h"
 20
 21#define HIDMA_QOS_N_OFFSET		0x700
 22#define HIDMA_CFG_OFFSET		0x400
 23#define HIDMA_MAX_BUS_REQ_LEN_OFFSET	0x41C
 24#define HIDMA_MAX_XACTIONS_OFFSET	0x420
 25#define HIDMA_HW_VERSION_OFFSET	0x424
 26#define HIDMA_CHRESET_TIMEOUT_OFFSET	0x418
 27
 28#define HIDMA_MAX_WR_XACTIONS_MASK	GENMASK(4, 0)
 29#define HIDMA_MAX_RD_XACTIONS_MASK	GENMASK(4, 0)
 30#define HIDMA_WEIGHT_MASK		GENMASK(6, 0)
 31#define HIDMA_MAX_BUS_REQ_LEN_MASK	GENMASK(15, 0)
 32#define HIDMA_CHRESET_TIMEOUT_MASK	GENMASK(19, 0)
 33
 34#define HIDMA_MAX_WR_XACTIONS_BIT_POS	16
 35#define HIDMA_MAX_BUS_WR_REQ_BIT_POS	16
 36#define HIDMA_WRR_BIT_POS		8
 37#define HIDMA_PRIORITY_BIT_POS		15
 38
 39#define HIDMA_AUTOSUSPEND_TIMEOUT	2000
 40#define HIDMA_MAX_CHANNEL_WEIGHT	15
 41
 42static unsigned int max_write_request;
 43module_param(max_write_request, uint, 0644);
 44MODULE_PARM_DESC(max_write_request,
 45		"maximum write burst (default: ACPI/DT value)");
 46
 47static unsigned int max_read_request;
 48module_param(max_read_request, uint, 0644);
 49MODULE_PARM_DESC(max_read_request,
 50		"maximum read burst (default: ACPI/DT value)");
 51
 52static unsigned int max_wr_xactions;
 53module_param(max_wr_xactions, uint, 0644);
 54MODULE_PARM_DESC(max_wr_xactions,
 55	"maximum number of write transactions (default: ACPI/DT value)");
 56
 57static unsigned int max_rd_xactions;
 58module_param(max_rd_xactions, uint, 0644);
 59MODULE_PARM_DESC(max_rd_xactions,
 60	"maximum number of read transactions (default: ACPI/DT value)");
 61
 62int hidma_mgmt_setup(struct hidma_mgmt_dev *mgmtdev)
 63{
 64	unsigned int i;
 65	u32 val;
 66
 67	if (!is_power_of_2(mgmtdev->max_write_request) ||
 68	    (mgmtdev->max_write_request < 128) ||
 69	    (mgmtdev->max_write_request > 1024)) {
 70		dev_err(&mgmtdev->pdev->dev, "invalid write request %d\n",
 71			mgmtdev->max_write_request);
 72		return -EINVAL;
 73	}
 74
 75	if (!is_power_of_2(mgmtdev->max_read_request) ||
 76	    (mgmtdev->max_read_request < 128) ||
 77	    (mgmtdev->max_read_request > 1024)) {
 78		dev_err(&mgmtdev->pdev->dev, "invalid read request %d\n",
 79			mgmtdev->max_read_request);
 80		return -EINVAL;
 81	}
 82
 83	if (mgmtdev->max_wr_xactions > HIDMA_MAX_WR_XACTIONS_MASK) {
 84		dev_err(&mgmtdev->pdev->dev,
 85			"max_wr_xactions cannot be bigger than %ld\n",
 86			HIDMA_MAX_WR_XACTIONS_MASK);
 87		return -EINVAL;
 88	}
 89
 90	if (mgmtdev->max_rd_xactions > HIDMA_MAX_RD_XACTIONS_MASK) {
 91		dev_err(&mgmtdev->pdev->dev,
 92			"max_rd_xactions cannot be bigger than %ld\n",
 93			HIDMA_MAX_RD_XACTIONS_MASK);
 94		return -EINVAL;
 95	}
 96
 97	for (i = 0; i < mgmtdev->dma_channels; i++) {
 98		if (mgmtdev->priority[i] > 1) {
 99			dev_err(&mgmtdev->pdev->dev,
100				"priority can be 0 or 1\n");
101			return -EINVAL;
102		}
103
104		if (mgmtdev->weight[i] > HIDMA_MAX_CHANNEL_WEIGHT) {
105			dev_err(&mgmtdev->pdev->dev,
106				"max value of weight can be %d.\n",
107				HIDMA_MAX_CHANNEL_WEIGHT);
108			return -EINVAL;
109		}
110
111		/* weight needs to be at least one */
112		if (mgmtdev->weight[i] == 0)
113			mgmtdev->weight[i] = 1;
114	}
115
116	pm_runtime_get_sync(&mgmtdev->pdev->dev);
117	val = readl(mgmtdev->virtaddr + HIDMA_MAX_BUS_REQ_LEN_OFFSET);
118	val &= ~(HIDMA_MAX_BUS_REQ_LEN_MASK << HIDMA_MAX_BUS_WR_REQ_BIT_POS);
119	val |= mgmtdev->max_write_request << HIDMA_MAX_BUS_WR_REQ_BIT_POS;
120	val &= ~HIDMA_MAX_BUS_REQ_LEN_MASK;
121	val |= mgmtdev->max_read_request;
122	writel(val, mgmtdev->virtaddr + HIDMA_MAX_BUS_REQ_LEN_OFFSET);
123
124	val = readl(mgmtdev->virtaddr + HIDMA_MAX_XACTIONS_OFFSET);
125	val &= ~(HIDMA_MAX_WR_XACTIONS_MASK << HIDMA_MAX_WR_XACTIONS_BIT_POS);
126	val |= mgmtdev->max_wr_xactions << HIDMA_MAX_WR_XACTIONS_BIT_POS;
127	val &= ~HIDMA_MAX_RD_XACTIONS_MASK;
128	val |= mgmtdev->max_rd_xactions;
129	writel(val, mgmtdev->virtaddr + HIDMA_MAX_XACTIONS_OFFSET);
130
131	mgmtdev->hw_version =
132	    readl(mgmtdev->virtaddr + HIDMA_HW_VERSION_OFFSET);
133	mgmtdev->hw_version_major = (mgmtdev->hw_version >> 28) & 0xF;
134	mgmtdev->hw_version_minor = (mgmtdev->hw_version >> 16) & 0xF;
135
136	for (i = 0; i < mgmtdev->dma_channels; i++) {
137		u32 weight = mgmtdev->weight[i];
138		u32 priority = mgmtdev->priority[i];
139
140		val = readl(mgmtdev->virtaddr + HIDMA_QOS_N_OFFSET + (4 * i));
141		val &= ~(1 << HIDMA_PRIORITY_BIT_POS);
142		val |= (priority & 0x1) << HIDMA_PRIORITY_BIT_POS;
143		val &= ~(HIDMA_WEIGHT_MASK << HIDMA_WRR_BIT_POS);
144		val |= (weight & HIDMA_WEIGHT_MASK) << HIDMA_WRR_BIT_POS;
145		writel(val, mgmtdev->virtaddr + HIDMA_QOS_N_OFFSET + (4 * i));
146	}
147
148	val = readl(mgmtdev->virtaddr + HIDMA_CHRESET_TIMEOUT_OFFSET);
149	val &= ~HIDMA_CHRESET_TIMEOUT_MASK;
150	val |= mgmtdev->chreset_timeout_cycles & HIDMA_CHRESET_TIMEOUT_MASK;
151	writel(val, mgmtdev->virtaddr + HIDMA_CHRESET_TIMEOUT_OFFSET);
152
153	pm_runtime_mark_last_busy(&mgmtdev->pdev->dev);
154	pm_runtime_put_autosuspend(&mgmtdev->pdev->dev);
155	return 0;
156}
157EXPORT_SYMBOL_GPL(hidma_mgmt_setup);
158
159static int hidma_mgmt_probe(struct platform_device *pdev)
160{
161	struct hidma_mgmt_dev *mgmtdev;
162	struct resource *res;
163	void __iomem *virtaddr;
164	int irq;
165	int rc;
166	u32 val;
167
168	pm_runtime_set_autosuspend_delay(&pdev->dev, HIDMA_AUTOSUSPEND_TIMEOUT);
169	pm_runtime_use_autosuspend(&pdev->dev);
170	pm_runtime_set_active(&pdev->dev);
171	pm_runtime_enable(&pdev->dev);
172	pm_runtime_get_sync(&pdev->dev);
173
174	virtaddr = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
175	if (IS_ERR(virtaddr)) {
176		rc = PTR_ERR(virtaddr);
177		goto out;
178	}
179
180	irq = platform_get_irq(pdev, 0);
181	if (irq < 0) {
182		rc = irq;
183		goto out;
184	}
185
186	mgmtdev = devm_kzalloc(&pdev->dev, sizeof(*mgmtdev), GFP_KERNEL);
187	if (!mgmtdev) {
188		rc = -ENOMEM;
189		goto out;
190	}
191
192	mgmtdev->pdev = pdev;
193	mgmtdev->addrsize = resource_size(res);
194	mgmtdev->virtaddr = virtaddr;
195
196	rc = device_property_read_u32(&pdev->dev, "dma-channels",
197				      &mgmtdev->dma_channels);
198	if (rc) {
199		dev_err(&pdev->dev, "number of channels missing\n");
200		goto out;
201	}
202
203	rc = device_property_read_u32(&pdev->dev,
204				      "channel-reset-timeout-cycles",
205				      &mgmtdev->chreset_timeout_cycles);
206	if (rc) {
207		dev_err(&pdev->dev, "channel reset timeout missing\n");
208		goto out;
209	}
210
211	rc = device_property_read_u32(&pdev->dev, "max-write-burst-bytes",
212				      &mgmtdev->max_write_request);
213	if (rc) {
214		dev_err(&pdev->dev, "max-write-burst-bytes missing\n");
215		goto out;
216	}
217
218	if (max_write_request &&
219			(max_write_request != mgmtdev->max_write_request)) {
220		dev_info(&pdev->dev, "overriding max-write-burst-bytes: %d\n",
221			max_write_request);
222		mgmtdev->max_write_request = max_write_request;
223	} else
224		max_write_request = mgmtdev->max_write_request;
225
226	rc = device_property_read_u32(&pdev->dev, "max-read-burst-bytes",
227				      &mgmtdev->max_read_request);
228	if (rc) {
229		dev_err(&pdev->dev, "max-read-burst-bytes missing\n");
230		goto out;
231	}
232	if (max_read_request &&
233			(max_read_request != mgmtdev->max_read_request)) {
234		dev_info(&pdev->dev, "overriding max-read-burst-bytes: %d\n",
235			max_read_request);
236		mgmtdev->max_read_request = max_read_request;
237	} else
238		max_read_request = mgmtdev->max_read_request;
239
240	rc = device_property_read_u32(&pdev->dev, "max-write-transactions",
241				      &mgmtdev->max_wr_xactions);
242	if (rc) {
243		dev_err(&pdev->dev, "max-write-transactions missing\n");
244		goto out;
245	}
246	if (max_wr_xactions &&
247			(max_wr_xactions != mgmtdev->max_wr_xactions)) {
248		dev_info(&pdev->dev, "overriding max-write-transactions: %d\n",
249			max_wr_xactions);
250		mgmtdev->max_wr_xactions = max_wr_xactions;
251	} else
252		max_wr_xactions = mgmtdev->max_wr_xactions;
253
254	rc = device_property_read_u32(&pdev->dev, "max-read-transactions",
255				      &mgmtdev->max_rd_xactions);
256	if (rc) {
257		dev_err(&pdev->dev, "max-read-transactions missing\n");
258		goto out;
259	}
260	if (max_rd_xactions &&
261			(max_rd_xactions != mgmtdev->max_rd_xactions)) {
262		dev_info(&pdev->dev, "overriding max-read-transactions: %d\n",
263			max_rd_xactions);
264		mgmtdev->max_rd_xactions = max_rd_xactions;
265	} else
266		max_rd_xactions = mgmtdev->max_rd_xactions;
267
268	mgmtdev->priority = devm_kcalloc(&pdev->dev,
269					 mgmtdev->dma_channels,
270					 sizeof(*mgmtdev->priority),
271					 GFP_KERNEL);
272	if (!mgmtdev->priority) {
273		rc = -ENOMEM;
274		goto out;
275	}
276
277	mgmtdev->weight = devm_kcalloc(&pdev->dev,
278				       mgmtdev->dma_channels,
279				       sizeof(*mgmtdev->weight), GFP_KERNEL);
280	if (!mgmtdev->weight) {
281		rc = -ENOMEM;
282		goto out;
283	}
284
285	rc = hidma_mgmt_setup(mgmtdev);
286	if (rc) {
287		dev_err(&pdev->dev, "setup failed\n");
288		goto out;
289	}
290
291	/* start the HW */
292	val = readl(mgmtdev->virtaddr + HIDMA_CFG_OFFSET);
293	val |= 1;
294	writel(val, mgmtdev->virtaddr + HIDMA_CFG_OFFSET);
295
296	rc = hidma_mgmt_init_sys(mgmtdev);
297	if (rc) {
298		dev_err(&pdev->dev, "sysfs setup failed\n");
299		goto out;
300	}
301
302	dev_info(&pdev->dev,
303		 "HW rev: %d.%d @ %pa with %d physical channels\n",
304		 mgmtdev->hw_version_major, mgmtdev->hw_version_minor,
305		 &res->start, mgmtdev->dma_channels);
306
307	platform_set_drvdata(pdev, mgmtdev);
308	pm_runtime_mark_last_busy(&pdev->dev);
309	pm_runtime_put_autosuspend(&pdev->dev);
310	return 0;
311out:
312	pm_runtime_put_sync_suspend(&pdev->dev);
313	pm_runtime_disable(&pdev->dev);
314	return rc;
315}
316
317#if IS_ENABLED(CONFIG_ACPI)
318static const struct acpi_device_id hidma_mgmt_acpi_ids[] = {
319	{"QCOM8060"},
320	{},
321};
322MODULE_DEVICE_TABLE(acpi, hidma_mgmt_acpi_ids);
323#endif
324
325static struct platform_driver hidma_mgmt_driver = {
326	.probe = hidma_mgmt_probe,
327	.driver = {
328		   .name = "hidma-mgmt",
329		   .acpi_match_table = ACPI_PTR(hidma_mgmt_acpi_ids),
330	},
331};
332
333module_platform_driver(hidma_mgmt_driver);
334MODULE_DESCRIPTION("Qualcomm Technologies HIDMA DMA engine interface");
335MODULE_LICENSE("GPL v2");
~/ Read-only file preview.