root/drivers/remoteproc/qcom_q6v5_adsp.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. qcom_adsp_shutdown
  2. adsp_load
  3. adsp_start
  4. qcom_adsp_pil_handover
  5. adsp_stop
  6. adsp_da_to_va
  7. adsp_init_clock
  8. adsp_init_reset
  9. adsp_init_mmio
  10. adsp_alloc_memory_region
  11. adsp_probe
  12. adsp_remove

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Qualcomm Technology Inc. ADSP Peripheral Image Loader for SDM845.
   4  * Copyright (c) 2018, The Linux Foundation. All rights reserved.
   5  */
   6 
   7 #include <linux/clk.h>
   8 #include <linux/delay.h>
   9 #include <linux/firmware.h>
  10 #include <linux/interrupt.h>
  11 #include <linux/io.h>
  12 #include <linux/iopoll.h>
  13 #include <linux/kernel.h>
  14 #include <linux/mfd/syscon.h>
  15 #include <linux/module.h>
  16 #include <linux/of_address.h>
  17 #include <linux/of_device.h>
  18 #include <linux/platform_device.h>
  19 #include <linux/pm_domain.h>
  20 #include <linux/pm_runtime.h>
  21 #include <linux/regmap.h>
  22 #include <linux/remoteproc.h>
  23 #include <linux/reset.h>
  24 #include <linux/soc/qcom/mdt_loader.h>
  25 #include <linux/soc/qcom/smem.h>
  26 #include <linux/soc/qcom/smem_state.h>
  27 
  28 #include "qcom_common.h"
  29 #include "qcom_q6v5.h"
  30 #include "remoteproc_internal.h"
  31 
  32 /* time out value */
  33 #define ACK_TIMEOUT                     1000
  34 #define BOOT_FSM_TIMEOUT                10000
  35 /* mask values */
  36 #define EVB_MASK                        GENMASK(27, 4)
  37 /*QDSP6SS register offsets*/
  38 #define RST_EVB_REG                     0x10
  39 #define CORE_START_REG                  0x400
  40 #define BOOT_CMD_REG                    0x404
  41 #define BOOT_STATUS_REG                 0x408
  42 #define RET_CFG_REG                     0x1C
  43 /*TCSR register offsets*/
  44 #define LPASS_MASTER_IDLE_REG           0x8
  45 #define LPASS_HALTACK_REG               0x4
  46 #define LPASS_PWR_ON_REG                0x10
  47 #define LPASS_HALTREQ_REG               0x0
  48 
  49 #define QDSP6SS_XO_CBCR         0x38
  50 #define QDSP6SS_CORE_CBCR       0x20
  51 #define QDSP6SS_SLEEP_CBCR      0x3c
  52 
  53 struct adsp_pil_data {
  54         int crash_reason_smem;
  55         const char *firmware_name;
  56 
  57         const char *ssr_name;
  58         const char *sysmon_name;
  59         int ssctl_id;
  60 
  61         const char **clk_ids;
  62         int num_clks;
  63 };
  64 
  65 struct qcom_adsp {
  66         struct device *dev;
  67         struct rproc *rproc;
  68 
  69         struct qcom_q6v5 q6v5;
  70 
  71         struct clk *xo;
  72 
  73         int num_clks;
  74         struct clk_bulk_data *clks;
  75 
  76         void __iomem *qdsp6ss_base;
  77 
  78         struct reset_control *pdc_sync_reset;
  79         struct reset_control *restart;
  80 
  81         struct regmap *halt_map;
  82         unsigned int halt_lpass;
  83 
  84         int crash_reason_smem;
  85 
  86         struct completion start_done;
  87         struct completion stop_done;
  88 
  89         phys_addr_t mem_phys;
  90         phys_addr_t mem_reloc;
  91         void *mem_region;
  92         size_t mem_size;
  93 
  94         struct qcom_rproc_glink glink_subdev;
  95         struct qcom_rproc_ssr ssr_subdev;
  96         struct qcom_sysmon *sysmon;
  97 };
  98 
  99 static int qcom_adsp_shutdown(struct qcom_adsp *adsp)
 100 {
 101         unsigned long timeout;
 102         unsigned int val;
 103         int ret;
 104 
 105         /* Reset the retention logic */
 106         val = readl(adsp->qdsp6ss_base + RET_CFG_REG);
 107         val |= 0x1;
 108         writel(val, adsp->qdsp6ss_base + RET_CFG_REG);
 109 
 110         clk_bulk_disable_unprepare(adsp->num_clks, adsp->clks);
 111 
 112         /* QDSP6 master port needs to be explicitly halted */
 113         ret = regmap_read(adsp->halt_map,
 114                         adsp->halt_lpass + LPASS_PWR_ON_REG, &val);
 115         if (ret || !val)
 116                 goto reset;
 117 
 118         ret = regmap_read(adsp->halt_map,
 119                         adsp->halt_lpass + LPASS_MASTER_IDLE_REG,
 120                         &val);
 121         if (ret || val)
 122                 goto reset;
 123 
 124         regmap_write(adsp->halt_map,
 125                         adsp->halt_lpass + LPASS_HALTREQ_REG, 1);
 126 
 127         /* Wait for halt ACK from QDSP6 */
 128         timeout = jiffies + msecs_to_jiffies(ACK_TIMEOUT);
 129         for (;;) {
 130                 ret = regmap_read(adsp->halt_map,
 131                         adsp->halt_lpass + LPASS_HALTACK_REG, &val);
 132                 if (ret || val || time_after(jiffies, timeout))
 133                         break;
 134 
 135                 usleep_range(1000, 1100);
 136         }
 137 
 138         ret = regmap_read(adsp->halt_map,
 139                         adsp->halt_lpass + LPASS_MASTER_IDLE_REG, &val);
 140         if (ret || !val)
 141                 dev_err(adsp->dev, "port failed halt\n");
 142 
 143 reset:
 144         /* Assert the LPASS PDC Reset */
 145         reset_control_assert(adsp->pdc_sync_reset);
 146         /* Place the LPASS processor into reset */
 147         reset_control_assert(adsp->restart);
 148         /* wait after asserting subsystem restart from AOSS */
 149         usleep_range(200, 300);
 150 
 151         /* Clear the halt request for the AXIM and AHBM for Q6 */
 152         regmap_write(adsp->halt_map, adsp->halt_lpass + LPASS_HALTREQ_REG, 0);
 153 
 154         /* De-assert the LPASS PDC Reset */
 155         reset_control_deassert(adsp->pdc_sync_reset);
 156         /* Remove the LPASS reset */
 157         reset_control_deassert(adsp->restart);
 158         /* wait after de-asserting subsystem restart from AOSS */
 159         usleep_range(200, 300);
 160 
 161         return 0;
 162 }
 163 
 164 static int adsp_load(struct rproc *rproc, const struct firmware *fw)
 165 {
 166         struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
 167 
 168         return qcom_mdt_load_no_init(adsp->dev, fw, rproc->firmware, 0,
 169                              adsp->mem_region, adsp->mem_phys, adsp->mem_size,
 170                              &adsp->mem_reloc);
 171 }
 172 
 173 static int adsp_start(struct rproc *rproc)
 174 {
 175         struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
 176         int ret;
 177         unsigned int val;
 178 
 179         qcom_q6v5_prepare(&adsp->q6v5);
 180 
 181         ret = clk_prepare_enable(adsp->xo);
 182         if (ret)
 183                 goto disable_irqs;
 184 
 185         dev_pm_genpd_set_performance_state(adsp->dev, INT_MAX);
 186         ret = pm_runtime_get_sync(adsp->dev);
 187         if (ret)
 188                 goto disable_xo_clk;
 189 
 190         ret = clk_bulk_prepare_enable(adsp->num_clks, adsp->clks);
 191         if (ret) {
 192                 dev_err(adsp->dev, "adsp clk_enable failed\n");
 193                 goto disable_power_domain;
 194         }
 195 
 196         /* Enable the XO clock */
 197         writel(1, adsp->qdsp6ss_base + QDSP6SS_XO_CBCR);
 198 
 199         /* Enable the QDSP6SS sleep clock */
 200         writel(1, adsp->qdsp6ss_base + QDSP6SS_SLEEP_CBCR);
 201 
 202         /* Enable the QDSP6 core clock */
 203         writel(1, adsp->qdsp6ss_base + QDSP6SS_CORE_CBCR);
 204 
 205         /* Program boot address */
 206         writel(adsp->mem_phys >> 4, adsp->qdsp6ss_base + RST_EVB_REG);
 207 
 208         /* De-assert QDSP6 stop core. QDSP6 will execute after out of reset */
 209         writel(0x1, adsp->qdsp6ss_base + CORE_START_REG);
 210 
 211         /* Trigger boot FSM to start QDSP6 */
 212         writel(0x1, adsp->qdsp6ss_base + BOOT_CMD_REG);
 213 
 214         /* Wait for core to come out of reset */
 215         ret = readl_poll_timeout(adsp->qdsp6ss_base + BOOT_STATUS_REG,
 216                         val, (val & BIT(0)) != 0, 10, BOOT_FSM_TIMEOUT);
 217         if (ret) {
 218                 dev_err(adsp->dev, "failed to bootup adsp\n");
 219                 goto disable_adsp_clks;
 220         }
 221 
 222         ret = qcom_q6v5_wait_for_start(&adsp->q6v5, msecs_to_jiffies(5 * HZ));
 223         if (ret == -ETIMEDOUT) {
 224                 dev_err(adsp->dev, "start timed out\n");
 225                 goto disable_adsp_clks;
 226         }
 227 
 228         return 0;
 229 
 230 disable_adsp_clks:
 231         clk_bulk_disable_unprepare(adsp->num_clks, adsp->clks);
 232 disable_power_domain:
 233         dev_pm_genpd_set_performance_state(adsp->dev, 0);
 234         pm_runtime_put(adsp->dev);
 235 disable_xo_clk:
 236         clk_disable_unprepare(adsp->xo);
 237 disable_irqs:
 238         qcom_q6v5_unprepare(&adsp->q6v5);
 239 
 240         return ret;
 241 }
 242 
 243 static void qcom_adsp_pil_handover(struct qcom_q6v5 *q6v5)
 244 {
 245         struct qcom_adsp *adsp = container_of(q6v5, struct qcom_adsp, q6v5);
 246 
 247         clk_disable_unprepare(adsp->xo);
 248         dev_pm_genpd_set_performance_state(adsp->dev, 0);
 249         pm_runtime_put(adsp->dev);
 250 }
 251 
 252 static int adsp_stop(struct rproc *rproc)
 253 {
 254         struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
 255         int handover;
 256         int ret;
 257 
 258         ret = qcom_q6v5_request_stop(&adsp->q6v5);
 259         if (ret == -ETIMEDOUT)
 260                 dev_err(adsp->dev, "timed out on wait\n");
 261 
 262         ret = qcom_adsp_shutdown(adsp);
 263         if (ret)
 264                 dev_err(adsp->dev, "failed to shutdown: %d\n", ret);
 265 
 266         handover = qcom_q6v5_unprepare(&adsp->q6v5);
 267         if (handover)
 268                 qcom_adsp_pil_handover(&adsp->q6v5);
 269 
 270         return ret;
 271 }
 272 
 273 static void *adsp_da_to_va(struct rproc *rproc, u64 da, int len)
 274 {
 275         struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
 276         int offset;
 277 
 278         offset = da - adsp->mem_reloc;
 279         if (offset < 0 || offset + len > adsp->mem_size)
 280                 return NULL;
 281 
 282         return adsp->mem_region + offset;
 283 }
 284 
 285 static const struct rproc_ops adsp_ops = {
 286         .start = adsp_start,
 287         .stop = adsp_stop,
 288         .da_to_va = adsp_da_to_va,
 289         .parse_fw = qcom_register_dump_segments,
 290         .load = adsp_load,
 291 };
 292 
 293 static int adsp_init_clock(struct qcom_adsp *adsp, const char **clk_ids)
 294 {
 295         int num_clks = 0;
 296         int i, ret;
 297 
 298         adsp->xo = devm_clk_get(adsp->dev, "xo");
 299         if (IS_ERR(adsp->xo)) {
 300                 ret = PTR_ERR(adsp->xo);
 301                 if (ret != -EPROBE_DEFER)
 302                         dev_err(adsp->dev, "failed to get xo clock");
 303                 return ret;
 304         }
 305 
 306         for (i = 0; clk_ids[i]; i++)
 307                 num_clks++;
 308 
 309         adsp->num_clks = num_clks;
 310         adsp->clks = devm_kcalloc(adsp->dev, adsp->num_clks,
 311                                 sizeof(*adsp->clks), GFP_KERNEL);
 312         if (!adsp->clks)
 313                 return -ENOMEM;
 314 
 315         for (i = 0; i < adsp->num_clks; i++)
 316                 adsp->clks[i].id = clk_ids[i];
 317 
 318         return devm_clk_bulk_get(adsp->dev, adsp->num_clks, adsp->clks);
 319 }
 320 
 321 static int adsp_init_reset(struct qcom_adsp *adsp)
 322 {
 323         adsp->pdc_sync_reset = devm_reset_control_get_optional_exclusive(adsp->dev,
 324                         "pdc_sync");
 325         if (IS_ERR(adsp->pdc_sync_reset)) {
 326                 dev_err(adsp->dev, "failed to acquire pdc_sync reset\n");
 327                 return PTR_ERR(adsp->pdc_sync_reset);
 328         }
 329 
 330         adsp->restart = devm_reset_control_get_optional_exclusive(adsp->dev, "restart");
 331 
 332         /* Fall back to the  old "cc_lpass" if "restart" is absent */
 333         if (!adsp->restart)
 334                 adsp->restart = devm_reset_control_get_exclusive(adsp->dev, "cc_lpass");
 335 
 336         if (IS_ERR(adsp->restart)) {
 337                 dev_err(adsp->dev, "failed to acquire restart\n");
 338                 return PTR_ERR(adsp->restart);
 339         }
 340 
 341         return 0;
 342 }
 343 
 344 static int adsp_init_mmio(struct qcom_adsp *adsp,
 345                                 struct platform_device *pdev)
 346 {
 347         struct device_node *syscon;
 348         struct resource *res;
 349         int ret;
 350 
 351         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 352         adsp->qdsp6ss_base = devm_ioremap(&pdev->dev, res->start,
 353                         resource_size(res));
 354         if (!adsp->qdsp6ss_base) {
 355                 dev_err(adsp->dev, "failed to map QDSP6SS registers\n");
 356                 return -ENOMEM;
 357         }
 358 
 359         syscon = of_parse_phandle(pdev->dev.of_node, "qcom,halt-regs", 0);
 360         if (!syscon) {
 361                 dev_err(&pdev->dev, "failed to parse qcom,halt-regs\n");
 362                 return -EINVAL;
 363         }
 364 
 365         adsp->halt_map = syscon_node_to_regmap(syscon);
 366         of_node_put(syscon);
 367         if (IS_ERR(adsp->halt_map))
 368                 return PTR_ERR(adsp->halt_map);
 369 
 370         ret = of_property_read_u32_index(pdev->dev.of_node, "qcom,halt-regs",
 371                         1, &adsp->halt_lpass);
 372         if (ret < 0) {
 373                 dev_err(&pdev->dev, "no offset in syscon\n");
 374                 return ret;
 375         }
 376 
 377         return 0;
 378 }
 379 
 380 static int adsp_alloc_memory_region(struct qcom_adsp *adsp)
 381 {
 382         struct device_node *node;
 383         struct resource r;
 384         int ret;
 385 
 386         node = of_parse_phandle(adsp->dev->of_node, "memory-region", 0);
 387         if (!node) {
 388                 dev_err(adsp->dev, "no memory-region specified\n");
 389                 return -EINVAL;
 390         }
 391 
 392         ret = of_address_to_resource(node, 0, &r);
 393         if (ret)
 394                 return ret;
 395 
 396         adsp->mem_phys = adsp->mem_reloc = r.start;
 397         adsp->mem_size = resource_size(&r);
 398         adsp->mem_region = devm_ioremap_wc(adsp->dev,
 399                                 adsp->mem_phys, adsp->mem_size);
 400         if (!adsp->mem_region) {
 401                 dev_err(adsp->dev, "unable to map memory region: %pa+%zx\n",
 402                         &r.start, adsp->mem_size);
 403                 return -EBUSY;
 404         }
 405 
 406         return 0;
 407 }
 408 
 409 static int adsp_probe(struct platform_device *pdev)
 410 {
 411         const struct adsp_pil_data *desc;
 412         struct qcom_adsp *adsp;
 413         struct rproc *rproc;
 414         int ret;
 415 
 416         desc = of_device_get_match_data(&pdev->dev);
 417         if (!desc)
 418                 return -EINVAL;
 419 
 420         rproc = rproc_alloc(&pdev->dev, pdev->name, &adsp_ops,
 421                             desc->firmware_name, sizeof(*adsp));
 422         if (!rproc) {
 423                 dev_err(&pdev->dev, "unable to allocate remoteproc\n");
 424                 return -ENOMEM;
 425         }
 426 
 427         adsp = (struct qcom_adsp *)rproc->priv;
 428         adsp->dev = &pdev->dev;
 429         adsp->rproc = rproc;
 430         platform_set_drvdata(pdev, adsp);
 431 
 432         ret = adsp_alloc_memory_region(adsp);
 433         if (ret)
 434                 goto free_rproc;
 435 
 436         ret = adsp_init_clock(adsp, desc->clk_ids);
 437         if (ret)
 438                 goto free_rproc;
 439 
 440         pm_runtime_enable(adsp->dev);
 441 
 442         ret = adsp_init_reset(adsp);
 443         if (ret)
 444                 goto disable_pm;
 445 
 446         ret = adsp_init_mmio(adsp, pdev);
 447         if (ret)
 448                 goto disable_pm;
 449 
 450         ret = qcom_q6v5_init(&adsp->q6v5, pdev, rproc, desc->crash_reason_smem,
 451                              qcom_adsp_pil_handover);
 452         if (ret)
 453                 goto disable_pm;
 454 
 455         qcom_add_glink_subdev(rproc, &adsp->glink_subdev);
 456         qcom_add_ssr_subdev(rproc, &adsp->ssr_subdev, desc->ssr_name);
 457         adsp->sysmon = qcom_add_sysmon_subdev(rproc,
 458                                               desc->sysmon_name,
 459                                               desc->ssctl_id);
 460         if (IS_ERR(adsp->sysmon)) {
 461                 ret = PTR_ERR(adsp->sysmon);
 462                 goto disable_pm;
 463         }
 464 
 465         ret = rproc_add(rproc);
 466         if (ret)
 467                 goto disable_pm;
 468 
 469         return 0;
 470 
 471 disable_pm:
 472         pm_runtime_disable(adsp->dev);
 473 free_rproc:
 474         rproc_free(rproc);
 475 
 476         return ret;
 477 }
 478 
 479 static int adsp_remove(struct platform_device *pdev)
 480 {
 481         struct qcom_adsp *adsp = platform_get_drvdata(pdev);
 482 
 483         rproc_del(adsp->rproc);
 484 
 485         qcom_remove_glink_subdev(adsp->rproc, &adsp->glink_subdev);
 486         qcom_remove_sysmon_subdev(adsp->sysmon);
 487         qcom_remove_ssr_subdev(adsp->rproc, &adsp->ssr_subdev);
 488         pm_runtime_disable(adsp->dev);
 489         rproc_free(adsp->rproc);
 490 
 491         return 0;
 492 }
 493 
 494 static const struct adsp_pil_data adsp_resource_init = {
 495         .crash_reason_smem = 423,
 496         .firmware_name = "adsp.mdt",
 497         .ssr_name = "lpass",
 498         .sysmon_name = "adsp",
 499         .ssctl_id = 0x14,
 500         .clk_ids = (const char*[]) {
 501                 "sway_cbcr", "lpass_ahbs_aon_cbcr", "lpass_ahbm_aon_cbcr",
 502                 "qdsp6ss_xo", "qdsp6ss_sleep", "qdsp6ss_core", NULL
 503         },
 504         .num_clks = 7,
 505 };
 506 
 507 static const struct adsp_pil_data cdsp_resource_init = {
 508         .crash_reason_smem = 601,
 509         .firmware_name = "cdsp.mdt",
 510         .ssr_name = "cdsp",
 511         .sysmon_name = "cdsp",
 512         .ssctl_id = 0x17,
 513         .clk_ids = (const char*[]) {
 514                 "sway", "tbu", "bimc", "ahb_aon", "q6ss_slave", "q6ss_master",
 515                 "q6_axim", NULL
 516         },
 517         .num_clks = 7,
 518 };
 519 
 520 static const struct of_device_id adsp_of_match[] = {
 521         { .compatible = "qcom,qcs404-cdsp-pil", .data = &cdsp_resource_init },
 522         { .compatible = "qcom,sdm845-adsp-pil", .data = &adsp_resource_init },
 523         { },
 524 };
 525 MODULE_DEVICE_TABLE(of, adsp_of_match);
 526 
 527 static struct platform_driver adsp_pil_driver = {
 528         .probe = adsp_probe,
 529         .remove = adsp_remove,
 530         .driver = {
 531                 .name = "qcom_q6v5_adsp",
 532                 .of_match_table = adsp_of_match,
 533         },
 534 };
 535 
 536 module_platform_driver(adsp_pil_driver);
 537 MODULE_DESCRIPTION("QTI SDM845 ADSP Peripheral Image Loader");
 538 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */