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