Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.9-rc8 909 lines 22 kB view raw
1/* 2 * Qualcomm Peripheral Image Loader 3 * 4 * Copyright (C) 2016 Linaro Ltd. 5 * Copyright (C) 2014 Sony Mobile Communications AB 6 * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License 10 * version 2 as published by the Free Software Foundation. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 */ 17 18#include <linux/clk.h> 19#include <linux/delay.h> 20#include <linux/dma-mapping.h> 21#include <linux/interrupt.h> 22#include <linux/kernel.h> 23#include <linux/mfd/syscon.h> 24#include <linux/module.h> 25#include <linux/of_address.h> 26#include <linux/platform_device.h> 27#include <linux/regmap.h> 28#include <linux/regulator/consumer.h> 29#include <linux/remoteproc.h> 30#include <linux/reset.h> 31#include <linux/soc/qcom/smem.h> 32#include <linux/soc/qcom/smem_state.h> 33 34#include "remoteproc_internal.h" 35#include "qcom_mdt_loader.h" 36 37#include <linux/qcom_scm.h> 38 39#define MBA_FIRMWARE_NAME "mba.b00" 40#define MPSS_FIRMWARE_NAME "modem.mdt" 41 42#define MPSS_CRASH_REASON_SMEM 421 43 44/* RMB Status Register Values */ 45#define RMB_PBL_SUCCESS 0x1 46 47#define RMB_MBA_XPU_UNLOCKED 0x1 48#define RMB_MBA_XPU_UNLOCKED_SCRIBBLED 0x2 49#define RMB_MBA_META_DATA_AUTH_SUCCESS 0x3 50#define RMB_MBA_AUTH_COMPLETE 0x4 51 52/* PBL/MBA interface registers */ 53#define RMB_MBA_IMAGE_REG 0x00 54#define RMB_PBL_STATUS_REG 0x04 55#define RMB_MBA_COMMAND_REG 0x08 56#define RMB_MBA_STATUS_REG 0x0C 57#define RMB_PMI_META_DATA_REG 0x10 58#define RMB_PMI_CODE_START_REG 0x14 59#define RMB_PMI_CODE_LENGTH_REG 0x18 60 61#define RMB_CMD_META_DATA_READY 0x1 62#define RMB_CMD_LOAD_READY 0x2 63 64/* QDSP6SS Register Offsets */ 65#define QDSP6SS_RESET_REG 0x014 66#define QDSP6SS_GFMUX_CTL_REG 0x020 67#define QDSP6SS_PWR_CTL_REG 0x030 68 69/* AXI Halt Register Offsets */ 70#define AXI_HALTREQ_REG 0x0 71#define AXI_HALTACK_REG 0x4 72#define AXI_IDLE_REG 0x8 73 74#define HALT_ACK_TIMEOUT_MS 100 75 76/* QDSP6SS_RESET */ 77#define Q6SS_STOP_CORE BIT(0) 78#define Q6SS_CORE_ARES BIT(1) 79#define Q6SS_BUS_ARES_ENABLE BIT(2) 80 81/* QDSP6SS_GFMUX_CTL */ 82#define Q6SS_CLK_ENABLE BIT(1) 83 84/* QDSP6SS_PWR_CTL */ 85#define Q6SS_L2DATA_SLP_NRET_N_0 BIT(0) 86#define Q6SS_L2DATA_SLP_NRET_N_1 BIT(1) 87#define Q6SS_L2DATA_SLP_NRET_N_2 BIT(2) 88#define Q6SS_L2TAG_SLP_NRET_N BIT(16) 89#define Q6SS_ETB_SLP_NRET_N BIT(17) 90#define Q6SS_L2DATA_STBY_N BIT(18) 91#define Q6SS_SLP_RET_N BIT(19) 92#define Q6SS_CLAMP_IO BIT(20) 93#define QDSS_BHS_ON BIT(21) 94#define QDSS_LDO_BYP BIT(22) 95 96struct q6v5 { 97 struct device *dev; 98 struct rproc *rproc; 99 100 void __iomem *reg_base; 101 void __iomem *rmb_base; 102 103 struct regmap *halt_map; 104 u32 halt_q6; 105 u32 halt_modem; 106 u32 halt_nc; 107 108 struct reset_control *mss_restart; 109 110 struct qcom_smem_state *state; 111 unsigned stop_bit; 112 113 struct regulator_bulk_data supply[4]; 114 115 struct clk *ahb_clk; 116 struct clk *axi_clk; 117 struct clk *rom_clk; 118 119 struct completion start_done; 120 struct completion stop_done; 121 bool running; 122 123 phys_addr_t mba_phys; 124 void *mba_region; 125 size_t mba_size; 126 127 phys_addr_t mpss_phys; 128 phys_addr_t mpss_reloc; 129 void *mpss_region; 130 size_t mpss_size; 131}; 132 133enum { 134 Q6V5_SUPPLY_CX, 135 Q6V5_SUPPLY_MX, 136 Q6V5_SUPPLY_MSS, 137 Q6V5_SUPPLY_PLL, 138}; 139 140static int q6v5_regulator_init(struct q6v5 *qproc) 141{ 142 int ret; 143 144 qproc->supply[Q6V5_SUPPLY_CX].supply = "cx"; 145 qproc->supply[Q6V5_SUPPLY_MX].supply = "mx"; 146 qproc->supply[Q6V5_SUPPLY_MSS].supply = "mss"; 147 qproc->supply[Q6V5_SUPPLY_PLL].supply = "pll"; 148 149 ret = devm_regulator_bulk_get(qproc->dev, 150 ARRAY_SIZE(qproc->supply), qproc->supply); 151 if (ret < 0) { 152 dev_err(qproc->dev, "failed to get supplies\n"); 153 return ret; 154 } 155 156 regulator_set_load(qproc->supply[Q6V5_SUPPLY_CX].consumer, 100000); 157 regulator_set_load(qproc->supply[Q6V5_SUPPLY_MSS].consumer, 100000); 158 regulator_set_load(qproc->supply[Q6V5_SUPPLY_PLL].consumer, 10000); 159 160 return 0; 161} 162 163static int q6v5_regulator_enable(struct q6v5 *qproc) 164{ 165 struct regulator *mss = qproc->supply[Q6V5_SUPPLY_MSS].consumer; 166 struct regulator *mx = qproc->supply[Q6V5_SUPPLY_MX].consumer; 167 int ret; 168 169 /* TODO: Q6V5_SUPPLY_CX is supposed to be set to super-turbo here */ 170 171 ret = regulator_set_voltage(mx, 1050000, INT_MAX); 172 if (ret) 173 return ret; 174 175 regulator_set_voltage(mss, 1000000, 1150000); 176 177 return regulator_bulk_enable(ARRAY_SIZE(qproc->supply), qproc->supply); 178} 179 180static void q6v5_regulator_disable(struct q6v5 *qproc) 181{ 182 struct regulator *mss = qproc->supply[Q6V5_SUPPLY_MSS].consumer; 183 struct regulator *mx = qproc->supply[Q6V5_SUPPLY_MX].consumer; 184 185 /* TODO: Q6V5_SUPPLY_CX corner votes should be released */ 186 187 regulator_bulk_disable(ARRAY_SIZE(qproc->supply), qproc->supply); 188 regulator_set_voltage(mx, 0, INT_MAX); 189 regulator_set_voltage(mss, 0, 1150000); 190} 191 192static int q6v5_load(struct rproc *rproc, const struct firmware *fw) 193{ 194 struct q6v5 *qproc = rproc->priv; 195 196 memcpy(qproc->mba_region, fw->data, fw->size); 197 198 return 0; 199} 200 201static const struct rproc_fw_ops q6v5_fw_ops = { 202 .find_rsc_table = qcom_mdt_find_rsc_table, 203 .load = q6v5_load, 204}; 205 206static int q6v5_rmb_pbl_wait(struct q6v5 *qproc, int ms) 207{ 208 unsigned long timeout; 209 s32 val; 210 211 timeout = jiffies + msecs_to_jiffies(ms); 212 for (;;) { 213 val = readl(qproc->rmb_base + RMB_PBL_STATUS_REG); 214 if (val) 215 break; 216 217 if (time_after(jiffies, timeout)) 218 return -ETIMEDOUT; 219 220 msleep(1); 221 } 222 223 return val; 224} 225 226static int q6v5_rmb_mba_wait(struct q6v5 *qproc, u32 status, int ms) 227{ 228 229 unsigned long timeout; 230 s32 val; 231 232 timeout = jiffies + msecs_to_jiffies(ms); 233 for (;;) { 234 val = readl(qproc->rmb_base + RMB_MBA_STATUS_REG); 235 if (val < 0) 236 break; 237 238 if (!status && val) 239 break; 240 else if (status && val == status) 241 break; 242 243 if (time_after(jiffies, timeout)) 244 return -ETIMEDOUT; 245 246 msleep(1); 247 } 248 249 return val; 250} 251 252static int q6v5proc_reset(struct q6v5 *qproc) 253{ 254 u32 val; 255 int ret; 256 257 /* Assert resets, stop core */ 258 val = readl(qproc->reg_base + QDSP6SS_RESET_REG); 259 val |= (Q6SS_CORE_ARES | Q6SS_BUS_ARES_ENABLE | Q6SS_STOP_CORE); 260 writel(val, qproc->reg_base + QDSP6SS_RESET_REG); 261 262 /* Enable power block headswitch, and wait for it to stabilize */ 263 val = readl(qproc->reg_base + QDSP6SS_PWR_CTL_REG); 264 val |= QDSS_BHS_ON | QDSS_LDO_BYP; 265 writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG); 266 udelay(1); 267 268 /* 269 * Turn on memories. L2 banks should be done individually 270 * to minimize inrush current. 271 */ 272 val = readl(qproc->reg_base + QDSP6SS_PWR_CTL_REG); 273 val |= Q6SS_SLP_RET_N | Q6SS_L2TAG_SLP_NRET_N | 274 Q6SS_ETB_SLP_NRET_N | Q6SS_L2DATA_STBY_N; 275 writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG); 276 val |= Q6SS_L2DATA_SLP_NRET_N_2; 277 writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG); 278 val |= Q6SS_L2DATA_SLP_NRET_N_1; 279 writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG); 280 val |= Q6SS_L2DATA_SLP_NRET_N_0; 281 writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG); 282 283 /* Remove IO clamp */ 284 val &= ~Q6SS_CLAMP_IO; 285 writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG); 286 287 /* Bring core out of reset */ 288 val = readl(qproc->reg_base + QDSP6SS_RESET_REG); 289 val &= ~Q6SS_CORE_ARES; 290 writel(val, qproc->reg_base + QDSP6SS_RESET_REG); 291 292 /* Turn on core clock */ 293 val = readl(qproc->reg_base + QDSP6SS_GFMUX_CTL_REG); 294 val |= Q6SS_CLK_ENABLE; 295 writel(val, qproc->reg_base + QDSP6SS_GFMUX_CTL_REG); 296 297 /* Start core execution */ 298 val = readl(qproc->reg_base + QDSP6SS_RESET_REG); 299 val &= ~Q6SS_STOP_CORE; 300 writel(val, qproc->reg_base + QDSP6SS_RESET_REG); 301 302 /* Wait for PBL status */ 303 ret = q6v5_rmb_pbl_wait(qproc, 1000); 304 if (ret == -ETIMEDOUT) { 305 dev_err(qproc->dev, "PBL boot timed out\n"); 306 } else if (ret != RMB_PBL_SUCCESS) { 307 dev_err(qproc->dev, "PBL returned unexpected status %d\n", ret); 308 ret = -EINVAL; 309 } else { 310 ret = 0; 311 } 312 313 return ret; 314} 315 316static void q6v5proc_halt_axi_port(struct q6v5 *qproc, 317 struct regmap *halt_map, 318 u32 offset) 319{ 320 unsigned long timeout; 321 unsigned int val; 322 int ret; 323 324 /* Check if we're already idle */ 325 ret = regmap_read(halt_map, offset + AXI_IDLE_REG, &val); 326 if (!ret && val) 327 return; 328 329 /* Assert halt request */ 330 regmap_write(halt_map, offset + AXI_HALTREQ_REG, 1); 331 332 /* Wait for halt */ 333 timeout = jiffies + msecs_to_jiffies(HALT_ACK_TIMEOUT_MS); 334 for (;;) { 335 ret = regmap_read(halt_map, offset + AXI_HALTACK_REG, &val); 336 if (ret || val || time_after(jiffies, timeout)) 337 break; 338 339 msleep(1); 340 } 341 342 ret = regmap_read(halt_map, offset + AXI_IDLE_REG, &val); 343 if (ret || !val) 344 dev_err(qproc->dev, "port failed halt\n"); 345 346 /* Clear halt request (port will remain halted until reset) */ 347 regmap_write(halt_map, offset + AXI_HALTREQ_REG, 0); 348} 349 350static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw) 351{ 352 unsigned long dma_attrs = DMA_ATTR_FORCE_CONTIGUOUS; 353 dma_addr_t phys; 354 void *ptr; 355 int ret; 356 357 ptr = dma_alloc_attrs(qproc->dev, fw->size, &phys, GFP_KERNEL, dma_attrs); 358 if (!ptr) { 359 dev_err(qproc->dev, "failed to allocate mdt buffer\n"); 360 return -ENOMEM; 361 } 362 363 memcpy(ptr, fw->data, fw->size); 364 365 writel(phys, qproc->rmb_base + RMB_PMI_META_DATA_REG); 366 writel(RMB_CMD_META_DATA_READY, qproc->rmb_base + RMB_MBA_COMMAND_REG); 367 368 ret = q6v5_rmb_mba_wait(qproc, RMB_MBA_META_DATA_AUTH_SUCCESS, 1000); 369 if (ret == -ETIMEDOUT) 370 dev_err(qproc->dev, "MPSS header authentication timed out\n"); 371 else if (ret < 0) 372 dev_err(qproc->dev, "MPSS header authentication failed: %d\n", ret); 373 374 dma_free_attrs(qproc->dev, fw->size, ptr, phys, dma_attrs); 375 376 return ret < 0 ? ret : 0; 377} 378 379static int q6v5_mpss_validate(struct q6v5 *qproc, const struct firmware *fw) 380{ 381 const struct elf32_phdr *phdrs; 382 const struct elf32_phdr *phdr; 383 struct elf32_hdr *ehdr; 384 phys_addr_t boot_addr; 385 phys_addr_t fw_addr; 386 bool relocate; 387 size_t size; 388 int ret; 389 int i; 390 391 ret = qcom_mdt_parse(fw, &fw_addr, NULL, &relocate); 392 if (ret) { 393 dev_err(qproc->dev, "failed to parse mdt header\n"); 394 return ret; 395 } 396 397 if (relocate) 398 boot_addr = qproc->mpss_phys; 399 else 400 boot_addr = fw_addr; 401 402 ehdr = (struct elf32_hdr *)fw->data; 403 phdrs = (struct elf32_phdr *)(ehdr + 1); 404 for (i = 0; i < ehdr->e_phnum; i++, phdr++) { 405 phdr = &phdrs[i]; 406 407 if (phdr->p_type != PT_LOAD) 408 continue; 409 410 if ((phdr->p_flags & QCOM_MDT_TYPE_MASK) == QCOM_MDT_TYPE_HASH) 411 continue; 412 413 if (!phdr->p_memsz) 414 continue; 415 416 size = readl(qproc->rmb_base + RMB_PMI_CODE_LENGTH_REG); 417 if (!size) { 418 writel(boot_addr, qproc->rmb_base + RMB_PMI_CODE_START_REG); 419 writel(RMB_CMD_LOAD_READY, qproc->rmb_base + RMB_MBA_COMMAND_REG); 420 } 421 422 size += phdr->p_memsz; 423 writel(size, qproc->rmb_base + RMB_PMI_CODE_LENGTH_REG); 424 } 425 426 ret = q6v5_rmb_mba_wait(qproc, RMB_MBA_AUTH_COMPLETE, 10000); 427 if (ret == -ETIMEDOUT) 428 dev_err(qproc->dev, "MPSS authentication timed out\n"); 429 else if (ret < 0) 430 dev_err(qproc->dev, "MPSS authentication failed: %d\n", ret); 431 432 return ret < 0 ? ret : 0; 433} 434 435static int q6v5_mpss_load(struct q6v5 *qproc) 436{ 437 const struct firmware *fw; 438 phys_addr_t fw_addr; 439 bool relocate; 440 int ret; 441 442 ret = request_firmware(&fw, MPSS_FIRMWARE_NAME, qproc->dev); 443 if (ret < 0) { 444 dev_err(qproc->dev, "unable to load " MPSS_FIRMWARE_NAME "\n"); 445 return ret; 446 } 447 448 ret = qcom_mdt_parse(fw, &fw_addr, NULL, &relocate); 449 if (ret) { 450 dev_err(qproc->dev, "failed to parse mdt header\n"); 451 goto release_firmware; 452 } 453 454 if (relocate) 455 qproc->mpss_reloc = fw_addr; 456 457 /* Initialize the RMB validator */ 458 writel(0, qproc->rmb_base + RMB_PMI_CODE_LENGTH_REG); 459 460 ret = q6v5_mpss_init_image(qproc, fw); 461 if (ret) 462 goto release_firmware; 463 464 ret = qcom_mdt_load(qproc->rproc, fw, MPSS_FIRMWARE_NAME); 465 if (ret) 466 goto release_firmware; 467 468 ret = q6v5_mpss_validate(qproc, fw); 469 470release_firmware: 471 release_firmware(fw); 472 473 return ret < 0 ? ret : 0; 474} 475 476static int q6v5_start(struct rproc *rproc) 477{ 478 struct q6v5 *qproc = (struct q6v5 *)rproc->priv; 479 int ret; 480 481 ret = q6v5_regulator_enable(qproc); 482 if (ret) { 483 dev_err(qproc->dev, "failed to enable supplies\n"); 484 return ret; 485 } 486 487 ret = reset_control_deassert(qproc->mss_restart); 488 if (ret) { 489 dev_err(qproc->dev, "failed to deassert mss restart\n"); 490 goto disable_vdd; 491 } 492 493 ret = clk_prepare_enable(qproc->ahb_clk); 494 if (ret) 495 goto assert_reset; 496 497 ret = clk_prepare_enable(qproc->axi_clk); 498 if (ret) 499 goto disable_ahb_clk; 500 501 ret = clk_prepare_enable(qproc->rom_clk); 502 if (ret) 503 goto disable_axi_clk; 504 505 writel(qproc->mba_phys, qproc->rmb_base + RMB_MBA_IMAGE_REG); 506 507 ret = q6v5proc_reset(qproc); 508 if (ret) 509 goto halt_axi_ports; 510 511 ret = q6v5_rmb_mba_wait(qproc, 0, 5000); 512 if (ret == -ETIMEDOUT) { 513 dev_err(qproc->dev, "MBA boot timed out\n"); 514 goto halt_axi_ports; 515 } else if (ret != RMB_MBA_XPU_UNLOCKED && 516 ret != RMB_MBA_XPU_UNLOCKED_SCRIBBLED) { 517 dev_err(qproc->dev, "MBA returned unexpected status %d\n", ret); 518 ret = -EINVAL; 519 goto halt_axi_ports; 520 } 521 522 dev_info(qproc->dev, "MBA booted, loading mpss\n"); 523 524 ret = q6v5_mpss_load(qproc); 525 if (ret) 526 goto halt_axi_ports; 527 528 ret = wait_for_completion_timeout(&qproc->start_done, 529 msecs_to_jiffies(5000)); 530 if (ret == 0) { 531 dev_err(qproc->dev, "start timed out\n"); 532 ret = -ETIMEDOUT; 533 goto halt_axi_ports; 534 } 535 536 qproc->running = true; 537 538 /* TODO: All done, release the handover resources */ 539 540 return 0; 541 542halt_axi_ports: 543 q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_q6); 544 q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_modem); 545 q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_nc); 546 547 clk_disable_unprepare(qproc->rom_clk); 548disable_axi_clk: 549 clk_disable_unprepare(qproc->axi_clk); 550disable_ahb_clk: 551 clk_disable_unprepare(qproc->ahb_clk); 552assert_reset: 553 reset_control_assert(qproc->mss_restart); 554disable_vdd: 555 q6v5_regulator_disable(qproc); 556 557 return ret; 558} 559 560static int q6v5_stop(struct rproc *rproc) 561{ 562 struct q6v5 *qproc = (struct q6v5 *)rproc->priv; 563 int ret; 564 565 qproc->running = false; 566 567 qcom_smem_state_update_bits(qproc->state, 568 BIT(qproc->stop_bit), BIT(qproc->stop_bit)); 569 570 ret = wait_for_completion_timeout(&qproc->stop_done, 571 msecs_to_jiffies(5000)); 572 if (ret == 0) 573 dev_err(qproc->dev, "timed out on wait\n"); 574 575 qcom_smem_state_update_bits(qproc->state, BIT(qproc->stop_bit), 0); 576 577 q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_q6); 578 q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_modem); 579 q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_nc); 580 581 reset_control_assert(qproc->mss_restart); 582 clk_disable_unprepare(qproc->rom_clk); 583 clk_disable_unprepare(qproc->axi_clk); 584 clk_disable_unprepare(qproc->ahb_clk); 585 q6v5_regulator_disable(qproc); 586 587 return 0; 588} 589 590static void *q6v5_da_to_va(struct rproc *rproc, u64 da, int len) 591{ 592 struct q6v5 *qproc = rproc->priv; 593 int offset; 594 595 offset = da - qproc->mpss_reloc; 596 if (offset < 0 || offset + len > qproc->mpss_size) 597 return NULL; 598 599 return qproc->mpss_region + offset; 600} 601 602static const struct rproc_ops q6v5_ops = { 603 .start = q6v5_start, 604 .stop = q6v5_stop, 605 .da_to_va = q6v5_da_to_va, 606}; 607 608static irqreturn_t q6v5_wdog_interrupt(int irq, void *dev) 609{ 610 struct q6v5 *qproc = dev; 611 size_t len; 612 char *msg; 613 614 /* Sometimes the stop triggers a watchdog rather than a stop-ack */ 615 if (!qproc->running) { 616 complete(&qproc->stop_done); 617 return IRQ_HANDLED; 618 } 619 620 msg = qcom_smem_get(QCOM_SMEM_HOST_ANY, MPSS_CRASH_REASON_SMEM, &len); 621 if (!IS_ERR(msg) && len > 0 && msg[0]) 622 dev_err(qproc->dev, "watchdog received: %s\n", msg); 623 else 624 dev_err(qproc->dev, "watchdog without message\n"); 625 626 rproc_report_crash(qproc->rproc, RPROC_WATCHDOG); 627 628 if (!IS_ERR(msg)) 629 msg[0] = '\0'; 630 631 return IRQ_HANDLED; 632} 633 634static irqreturn_t q6v5_fatal_interrupt(int irq, void *dev) 635{ 636 struct q6v5 *qproc = dev; 637 size_t len; 638 char *msg; 639 640 msg = qcom_smem_get(QCOM_SMEM_HOST_ANY, MPSS_CRASH_REASON_SMEM, &len); 641 if (!IS_ERR(msg) && len > 0 && msg[0]) 642 dev_err(qproc->dev, "fatal error received: %s\n", msg); 643 else 644 dev_err(qproc->dev, "fatal error without message\n"); 645 646 rproc_report_crash(qproc->rproc, RPROC_FATAL_ERROR); 647 648 if (!IS_ERR(msg)) 649 msg[0] = '\0'; 650 651 return IRQ_HANDLED; 652} 653 654static irqreturn_t q6v5_handover_interrupt(int irq, void *dev) 655{ 656 struct q6v5 *qproc = dev; 657 658 complete(&qproc->start_done); 659 return IRQ_HANDLED; 660} 661 662static irqreturn_t q6v5_stop_ack_interrupt(int irq, void *dev) 663{ 664 struct q6v5 *qproc = dev; 665 666 complete(&qproc->stop_done); 667 return IRQ_HANDLED; 668} 669 670static int q6v5_init_mem(struct q6v5 *qproc, struct platform_device *pdev) 671{ 672 struct of_phandle_args args; 673 struct resource *res; 674 int ret; 675 676 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qdsp6"); 677 qproc->reg_base = devm_ioremap_resource(&pdev->dev, res); 678 if (IS_ERR(qproc->reg_base)) 679 return PTR_ERR(qproc->reg_base); 680 681 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rmb"); 682 qproc->rmb_base = devm_ioremap_resource(&pdev->dev, res); 683 if (IS_ERR(qproc->rmb_base)) 684 return PTR_ERR(qproc->rmb_base); 685 686 ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node, 687 "qcom,halt-regs", 3, 0, &args); 688 if (ret < 0) { 689 dev_err(&pdev->dev, "failed to parse qcom,halt-regs\n"); 690 return -EINVAL; 691 } 692 693 qproc->halt_map = syscon_node_to_regmap(args.np); 694 of_node_put(args.np); 695 if (IS_ERR(qproc->halt_map)) 696 return PTR_ERR(qproc->halt_map); 697 698 qproc->halt_q6 = args.args[0]; 699 qproc->halt_modem = args.args[1]; 700 qproc->halt_nc = args.args[2]; 701 702 return 0; 703} 704 705static int q6v5_init_clocks(struct q6v5 *qproc) 706{ 707 qproc->ahb_clk = devm_clk_get(qproc->dev, "iface"); 708 if (IS_ERR(qproc->ahb_clk)) { 709 dev_err(qproc->dev, "failed to get iface clock\n"); 710 return PTR_ERR(qproc->ahb_clk); 711 } 712 713 qproc->axi_clk = devm_clk_get(qproc->dev, "bus"); 714 if (IS_ERR(qproc->axi_clk)) { 715 dev_err(qproc->dev, "failed to get bus clock\n"); 716 return PTR_ERR(qproc->axi_clk); 717 } 718 719 qproc->rom_clk = devm_clk_get(qproc->dev, "mem"); 720 if (IS_ERR(qproc->rom_clk)) { 721 dev_err(qproc->dev, "failed to get mem clock\n"); 722 return PTR_ERR(qproc->rom_clk); 723 } 724 725 return 0; 726} 727 728static int q6v5_init_reset(struct q6v5 *qproc) 729{ 730 qproc->mss_restart = devm_reset_control_get(qproc->dev, NULL); 731 if (IS_ERR(qproc->mss_restart)) { 732 dev_err(qproc->dev, "failed to acquire mss restart\n"); 733 return PTR_ERR(qproc->mss_restart); 734 } 735 736 return 0; 737} 738 739static int q6v5_request_irq(struct q6v5 *qproc, 740 struct platform_device *pdev, 741 const char *name, 742 irq_handler_t thread_fn) 743{ 744 int ret; 745 746 ret = platform_get_irq_byname(pdev, name); 747 if (ret < 0) { 748 dev_err(&pdev->dev, "no %s IRQ defined\n", name); 749 return ret; 750 } 751 752 ret = devm_request_threaded_irq(&pdev->dev, ret, 753 NULL, thread_fn, 754 IRQF_TRIGGER_RISING | IRQF_ONESHOT, 755 "q6v5", qproc); 756 if (ret) 757 dev_err(&pdev->dev, "request %s IRQ failed\n", name); 758 759 return ret; 760} 761 762static int q6v5_alloc_memory_region(struct q6v5 *qproc) 763{ 764 struct device_node *child; 765 struct device_node *node; 766 struct resource r; 767 int ret; 768 769 child = of_get_child_by_name(qproc->dev->of_node, "mba"); 770 node = of_parse_phandle(child, "memory-region", 0); 771 ret = of_address_to_resource(node, 0, &r); 772 if (ret) { 773 dev_err(qproc->dev, "unable to resolve mba region\n"); 774 return ret; 775 } 776 777 qproc->mba_phys = r.start; 778 qproc->mba_size = resource_size(&r); 779 qproc->mba_region = devm_ioremap_wc(qproc->dev, qproc->mba_phys, qproc->mba_size); 780 if (!qproc->mba_region) { 781 dev_err(qproc->dev, "unable to map memory region: %pa+%zx\n", 782 &r.start, qproc->mba_size); 783 return -EBUSY; 784 } 785 786 child = of_get_child_by_name(qproc->dev->of_node, "mpss"); 787 node = of_parse_phandle(child, "memory-region", 0); 788 ret = of_address_to_resource(node, 0, &r); 789 if (ret) { 790 dev_err(qproc->dev, "unable to resolve mpss region\n"); 791 return ret; 792 } 793 794 qproc->mpss_phys = qproc->mpss_reloc = r.start; 795 qproc->mpss_size = resource_size(&r); 796 qproc->mpss_region = devm_ioremap_wc(qproc->dev, qproc->mpss_phys, qproc->mpss_size); 797 if (!qproc->mpss_region) { 798 dev_err(qproc->dev, "unable to map memory region: %pa+%zx\n", 799 &r.start, qproc->mpss_size); 800 return -EBUSY; 801 } 802 803 return 0; 804} 805 806static int q6v5_probe(struct platform_device *pdev) 807{ 808 struct q6v5 *qproc; 809 struct rproc *rproc; 810 int ret; 811 812 rproc = rproc_alloc(&pdev->dev, pdev->name, &q6v5_ops, 813 MBA_FIRMWARE_NAME, sizeof(*qproc)); 814 if (!rproc) { 815 dev_err(&pdev->dev, "failed to allocate rproc\n"); 816 return -ENOMEM; 817 } 818 819 rproc->fw_ops = &q6v5_fw_ops; 820 821 qproc = (struct q6v5 *)rproc->priv; 822 qproc->dev = &pdev->dev; 823 qproc->rproc = rproc; 824 platform_set_drvdata(pdev, qproc); 825 826 init_completion(&qproc->start_done); 827 init_completion(&qproc->stop_done); 828 829 ret = q6v5_init_mem(qproc, pdev); 830 if (ret) 831 goto free_rproc; 832 833 ret = q6v5_alloc_memory_region(qproc); 834 if (ret) 835 goto free_rproc; 836 837 ret = q6v5_init_clocks(qproc); 838 if (ret) 839 goto free_rproc; 840 841 ret = q6v5_regulator_init(qproc); 842 if (ret) 843 goto free_rproc; 844 845 ret = q6v5_init_reset(qproc); 846 if (ret) 847 goto free_rproc; 848 849 ret = q6v5_request_irq(qproc, pdev, "wdog", q6v5_wdog_interrupt); 850 if (ret < 0) 851 goto free_rproc; 852 853 ret = q6v5_request_irq(qproc, pdev, "fatal", q6v5_fatal_interrupt); 854 if (ret < 0) 855 goto free_rproc; 856 857 ret = q6v5_request_irq(qproc, pdev, "handover", q6v5_handover_interrupt); 858 if (ret < 0) 859 goto free_rproc; 860 861 ret = q6v5_request_irq(qproc, pdev, "stop-ack", q6v5_stop_ack_interrupt); 862 if (ret < 0) 863 goto free_rproc; 864 865 qproc->state = qcom_smem_state_get(&pdev->dev, "stop", &qproc->stop_bit); 866 if (IS_ERR(qproc->state)) { 867 ret = PTR_ERR(qproc->state); 868 goto free_rproc; 869 } 870 871 ret = rproc_add(rproc); 872 if (ret) 873 goto free_rproc; 874 875 return 0; 876 877free_rproc: 878 rproc_free(rproc); 879 880 return ret; 881} 882 883static int q6v5_remove(struct platform_device *pdev) 884{ 885 struct q6v5 *qproc = platform_get_drvdata(pdev); 886 887 rproc_del(qproc->rproc); 888 rproc_free(qproc->rproc); 889 890 return 0; 891} 892 893static const struct of_device_id q6v5_of_match[] = { 894 { .compatible = "qcom,q6v5-pil", }, 895 { }, 896}; 897 898static struct platform_driver q6v5_driver = { 899 .probe = q6v5_probe, 900 .remove = q6v5_remove, 901 .driver = { 902 .name = "qcom-q6v5-pil", 903 .of_match_table = q6v5_of_match, 904 }, 905}; 906module_platform_driver(q6v5_driver); 907 908MODULE_DESCRIPTION("Peripheral Image Loader for Hexagon"); 909MODULE_LICENSE("GPL v2");