brintos

brintos / linux-shallow public Read only

0
0
Text · 9.5 KiB · 4805ce3 Raw
336 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Qualcomm Technologies HIDMA DMA engine Management interface4 *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		0x70022#define HIDMA_CFG_OFFSET		0x40023#define HIDMA_MAX_BUS_REQ_LEN_OFFSET	0x41C24#define HIDMA_MAX_XACTIONS_OFFSET	0x42025#define HIDMA_HW_VERSION_OFFSET	0x42426#define HIDMA_CHRESET_TIMEOUT_OFFSET	0x41827 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	1635#define HIDMA_MAX_BUS_WR_REQ_BIT_POS	1636#define HIDMA_WRR_BIT_POS		837#define HIDMA_PRIORITY_BIT_POS		1538 39#define HIDMA_AUTOSUSPEND_TIMEOUT	200040#define HIDMA_MAX_CHANNEL_WEIGHT	1541 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	} else224		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	} else238		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	} else252		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	} else266		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#endif324 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");336