wkup_m3_ipc.c (18844B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * AMx3 Wkup M3 IPC driver 4 * 5 * Copyright (C) 2015 Texas Instruments, Inc. 6 * 7 * Dave Gerlach <d-gerlach@ti.com> 8 */ 9 10#include <linux/debugfs.h> 11#include <linux/err.h> 12#include <linux/firmware.h> 13#include <linux/kernel.h> 14#include <linux/kthread.h> 15#include <linux/interrupt.h> 16#include <linux/irq.h> 17#include <linux/module.h> 18#include <linux/of.h> 19#include <linux/omap-mailbox.h> 20#include <linux/platform_device.h> 21#include <linux/remoteproc.h> 22#include <linux/suspend.h> 23#include <linux/wkup_m3_ipc.h> 24 25#define AM33XX_CTRL_IPC_REG_COUNT 0x8 26#define AM33XX_CTRL_IPC_REG_OFFSET(m) (0x4 + 4 * (m)) 27 28/* AM33XX M3_TXEV_EOI register */ 29#define AM33XX_CONTROL_M3_TXEV_EOI 0x00 30 31#define AM33XX_M3_TXEV_ACK (0x1 << 0) 32#define AM33XX_M3_TXEV_ENABLE (0x0 << 0) 33 34#define IPC_CMD_DS0 0x4 35#define IPC_CMD_STANDBY 0xc 36#define IPC_CMD_IDLE 0x10 37#define IPC_CMD_RESET 0xe 38#define DS_IPC_DEFAULT 0xffffffff 39#define M3_VERSION_UNKNOWN 0x0000ffff 40#define M3_BASELINE_VERSION 0x191 41#define M3_STATUS_RESP_MASK (0xffff << 16) 42#define M3_FW_VERSION_MASK 0xffff 43#define M3_WAKE_SRC_MASK 0xff 44 45#define IPC_MEM_TYPE_SHIFT (0x0) 46#define IPC_MEM_TYPE_MASK (0x7 << 0) 47#define IPC_VTT_STAT_SHIFT (0x3) 48#define IPC_VTT_STAT_MASK (0x1 << 3) 49#define IPC_VTT_GPIO_PIN_SHIFT (0x4) 50#define IPC_VTT_GPIO_PIN_MASK (0x3f << 4) 51#define IPC_IO_ISOLATION_STAT_SHIFT (10) 52#define IPC_IO_ISOLATION_STAT_MASK (0x1 << 10) 53 54#define IPC_DBG_HALT_SHIFT (11) 55#define IPC_DBG_HALT_MASK (0x1 << 11) 56 57#define M3_STATE_UNKNOWN 0 58#define M3_STATE_RESET 1 59#define M3_STATE_INITED 2 60#define M3_STATE_MSG_FOR_LP 3 61#define M3_STATE_MSG_FOR_RESET 4 62 63#define WKUP_M3_SD_FW_MAGIC 0x570C 64 65#define WKUP_M3_DMEM_START 0x80000 66#define WKUP_M3_AUXDATA_OFFSET 0x1000 67#define WKUP_M3_AUXDATA_SIZE 0xFF 68 69static struct wkup_m3_ipc *m3_ipc_state; 70 71static const struct wkup_m3_wakeup_src wakeups[] = { 72 {.irq_nr = 16, .src = "PRCM"}, 73 {.irq_nr = 35, .src = "USB0_PHY"}, 74 {.irq_nr = 36, .src = "USB1_PHY"}, 75 {.irq_nr = 40, .src = "I2C0"}, 76 {.irq_nr = 41, .src = "RTC Timer"}, 77 {.irq_nr = 42, .src = "RTC Alarm"}, 78 {.irq_nr = 43, .src = "Timer0"}, 79 {.irq_nr = 44, .src = "Timer1"}, 80 {.irq_nr = 45, .src = "UART"}, 81 {.irq_nr = 46, .src = "GPIO0"}, 82 {.irq_nr = 48, .src = "MPU_WAKE"}, 83 {.irq_nr = 49, .src = "WDT0"}, 84 {.irq_nr = 50, .src = "WDT1"}, 85 {.irq_nr = 51, .src = "ADC_TSC"}, 86 {.irq_nr = 0, .src = "Unknown"}, 87}; 88 89/** 90 * wkup_m3_copy_aux_data - Copy auxiliary data to special region of m3 dmem 91 * @data - pointer to data 92 * @sz - size of data to copy (limit 256 bytes) 93 * 94 * Copies any additional blob of data to the wkup_m3 dmem to be used by the 95 * firmware 96 */ 97static unsigned long wkup_m3_copy_aux_data(struct wkup_m3_ipc *m3_ipc, 98 const void *data, int sz) 99{ 100 unsigned long aux_data_dev_addr; 101 void *aux_data_addr; 102 103 aux_data_dev_addr = WKUP_M3_DMEM_START + WKUP_M3_AUXDATA_OFFSET; 104 aux_data_addr = rproc_da_to_va(m3_ipc->rproc, 105 aux_data_dev_addr, 106 WKUP_M3_AUXDATA_SIZE, 107 NULL); 108 memcpy(aux_data_addr, data, sz); 109 110 return WKUP_M3_AUXDATA_OFFSET; 111} 112 113static void wkup_m3_scale_data_fw_cb(const struct firmware *fw, void *context) 114{ 115 unsigned long val, aux_base; 116 struct wkup_m3_scale_data_header hdr; 117 struct wkup_m3_ipc *m3_ipc = context; 118 struct device *dev = m3_ipc->dev; 119 120 if (!fw) { 121 dev_err(dev, "Voltage scale fw name given but file missing.\n"); 122 return; 123 } 124 125 memcpy(&hdr, fw->data, sizeof(hdr)); 126 127 if (hdr.magic != WKUP_M3_SD_FW_MAGIC) { 128 dev_err(dev, "PM: Voltage Scale Data binary does not appear valid.\n"); 129 goto release_sd_fw; 130 } 131 132 aux_base = wkup_m3_copy_aux_data(m3_ipc, fw->data + sizeof(hdr), 133 fw->size - sizeof(hdr)); 134 135 val = (aux_base + hdr.sleep_offset); 136 val |= ((aux_base + hdr.wake_offset) << 16); 137 138 m3_ipc->volt_scale_offsets = val; 139 140release_sd_fw: 141 release_firmware(fw); 142}; 143 144static int wkup_m3_init_scale_data(struct wkup_m3_ipc *m3_ipc, 145 struct device *dev) 146{ 147 int ret = 0; 148 149 /* 150 * If no name is provided, user has already been warned, pm will 151 * still work so return 0 152 */ 153 154 if (!m3_ipc->sd_fw_name) 155 return ret; 156 157 ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_UEVENT, 158 m3_ipc->sd_fw_name, dev, GFP_ATOMIC, 159 m3_ipc, wkup_m3_scale_data_fw_cb); 160 161 return ret; 162} 163 164#ifdef CONFIG_DEBUG_FS 165static void wkup_m3_set_halt_late(bool enabled) 166{ 167 if (enabled) 168 m3_ipc_state->halt = (1 << IPC_DBG_HALT_SHIFT); 169 else 170 m3_ipc_state->halt = 0; 171} 172 173static int option_get(void *data, u64 *val) 174{ 175 u32 *option = data; 176 177 *val = *option; 178 179 return 0; 180} 181 182static int option_set(void *data, u64 val) 183{ 184 u32 *option = data; 185 186 *option = val; 187 188 if (option == &m3_ipc_state->halt) { 189 if (val) 190 wkup_m3_set_halt_late(true); 191 else 192 wkup_m3_set_halt_late(false); 193 } 194 195 return 0; 196} 197 198DEFINE_SIMPLE_ATTRIBUTE(wkup_m3_ipc_option_fops, option_get, option_set, 199 "%llu\n"); 200 201static int wkup_m3_ipc_dbg_init(struct wkup_m3_ipc *m3_ipc) 202{ 203 m3_ipc->dbg_path = debugfs_create_dir("wkup_m3_ipc", NULL); 204 205 if (!m3_ipc->dbg_path) 206 return -EINVAL; 207 208 (void)debugfs_create_file("enable_late_halt", 0644, 209 m3_ipc->dbg_path, 210 &m3_ipc->halt, 211 &wkup_m3_ipc_option_fops); 212 213 return 0; 214} 215 216static inline void wkup_m3_ipc_dbg_destroy(struct wkup_m3_ipc *m3_ipc) 217{ 218 debugfs_remove_recursive(m3_ipc->dbg_path); 219} 220#else 221static inline int wkup_m3_ipc_dbg_init(struct wkup_m3_ipc *m3_ipc) 222{ 223 return 0; 224} 225 226static inline void wkup_m3_ipc_dbg_destroy(struct wkup_m3_ipc *m3_ipc) 227{ 228} 229#endif /* CONFIG_DEBUG_FS */ 230 231static void am33xx_txev_eoi(struct wkup_m3_ipc *m3_ipc) 232{ 233 writel(AM33XX_M3_TXEV_ACK, 234 m3_ipc->ipc_mem_base + AM33XX_CONTROL_M3_TXEV_EOI); 235} 236 237static void am33xx_txev_enable(struct wkup_m3_ipc *m3_ipc) 238{ 239 writel(AM33XX_M3_TXEV_ENABLE, 240 m3_ipc->ipc_mem_base + AM33XX_CONTROL_M3_TXEV_EOI); 241} 242 243static void wkup_m3_ctrl_ipc_write(struct wkup_m3_ipc *m3_ipc, 244 u32 val, int ipc_reg_num) 245{ 246 if (WARN(ipc_reg_num < 0 || ipc_reg_num > AM33XX_CTRL_IPC_REG_COUNT, 247 "ipc register operation out of range")) 248 return; 249 250 writel(val, m3_ipc->ipc_mem_base + 251 AM33XX_CTRL_IPC_REG_OFFSET(ipc_reg_num)); 252} 253 254static unsigned int wkup_m3_ctrl_ipc_read(struct wkup_m3_ipc *m3_ipc, 255 int ipc_reg_num) 256{ 257 if (WARN(ipc_reg_num < 0 || ipc_reg_num > AM33XX_CTRL_IPC_REG_COUNT, 258 "ipc register operation out of range")) 259 return 0; 260 261 return readl(m3_ipc->ipc_mem_base + 262 AM33XX_CTRL_IPC_REG_OFFSET(ipc_reg_num)); 263} 264 265static int wkup_m3_fw_version_read(struct wkup_m3_ipc *m3_ipc) 266{ 267 int val; 268 269 val = wkup_m3_ctrl_ipc_read(m3_ipc, 2); 270 271 return val & M3_FW_VERSION_MASK; 272} 273 274static irqreturn_t wkup_m3_txev_handler(int irq, void *ipc_data) 275{ 276 struct wkup_m3_ipc *m3_ipc = ipc_data; 277 struct device *dev = m3_ipc->dev; 278 int ver = 0; 279 280 am33xx_txev_eoi(m3_ipc); 281 282 switch (m3_ipc->state) { 283 case M3_STATE_RESET: 284 ver = wkup_m3_fw_version_read(m3_ipc); 285 286 if (ver == M3_VERSION_UNKNOWN || 287 ver < M3_BASELINE_VERSION) { 288 dev_warn(dev, "CM3 Firmware Version %x not supported\n", 289 ver); 290 } else { 291 dev_info(dev, "CM3 Firmware Version = 0x%x\n", ver); 292 } 293 294 m3_ipc->state = M3_STATE_INITED; 295 wkup_m3_init_scale_data(m3_ipc, dev); 296 complete(&m3_ipc->sync_complete); 297 break; 298 case M3_STATE_MSG_FOR_RESET: 299 m3_ipc->state = M3_STATE_INITED; 300 complete(&m3_ipc->sync_complete); 301 break; 302 case M3_STATE_MSG_FOR_LP: 303 complete(&m3_ipc->sync_complete); 304 break; 305 case M3_STATE_UNKNOWN: 306 dev_warn(dev, "Unknown CM3 State\n"); 307 } 308 309 am33xx_txev_enable(m3_ipc); 310 311 return IRQ_HANDLED; 312} 313 314static int wkup_m3_ping(struct wkup_m3_ipc *m3_ipc) 315{ 316 struct device *dev = m3_ipc->dev; 317 mbox_msg_t dummy_msg = 0; 318 int ret; 319 320 if (!m3_ipc->mbox) { 321 dev_err(dev, 322 "No IPC channel to communicate with wkup_m3!\n"); 323 return -EIO; 324 } 325 326 /* 327 * Write a dummy message to the mailbox in order to trigger the RX 328 * interrupt to alert the M3 that data is available in the IPC 329 * registers. We must enable the IRQ here and disable it after in 330 * the RX callback to avoid multiple interrupts being received 331 * by the CM3. 332 */ 333 ret = mbox_send_message(m3_ipc->mbox, &dummy_msg); 334 if (ret < 0) { 335 dev_err(dev, "%s: mbox_send_message() failed: %d\n", 336 __func__, ret); 337 return ret; 338 } 339 340 ret = wait_for_completion_timeout(&m3_ipc->sync_complete, 341 msecs_to_jiffies(500)); 342 if (!ret) { 343 dev_err(dev, "MPU<->CM3 sync failure\n"); 344 m3_ipc->state = M3_STATE_UNKNOWN; 345 return -EIO; 346 } 347 348 mbox_client_txdone(m3_ipc->mbox, 0); 349 return 0; 350} 351 352static int wkup_m3_ping_noirq(struct wkup_m3_ipc *m3_ipc) 353{ 354 struct device *dev = m3_ipc->dev; 355 mbox_msg_t dummy_msg = 0; 356 int ret; 357 358 if (!m3_ipc->mbox) { 359 dev_err(dev, 360 "No IPC channel to communicate with wkup_m3!\n"); 361 return -EIO; 362 } 363 364 ret = mbox_send_message(m3_ipc->mbox, &dummy_msg); 365 if (ret < 0) { 366 dev_err(dev, "%s: mbox_send_message() failed: %d\n", 367 __func__, ret); 368 return ret; 369 } 370 371 mbox_client_txdone(m3_ipc->mbox, 0); 372 return 0; 373} 374 375static int wkup_m3_is_available(struct wkup_m3_ipc *m3_ipc) 376{ 377 return ((m3_ipc->state != M3_STATE_RESET) && 378 (m3_ipc->state != M3_STATE_UNKNOWN)); 379} 380 381static void wkup_m3_set_vtt_gpio(struct wkup_m3_ipc *m3_ipc, int gpio) 382{ 383 m3_ipc->vtt_conf = (1 << IPC_VTT_STAT_SHIFT) | 384 (gpio << IPC_VTT_GPIO_PIN_SHIFT); 385} 386 387static void wkup_m3_set_io_isolation(struct wkup_m3_ipc *m3_ipc) 388{ 389 m3_ipc->isolation_conf = (1 << IPC_IO_ISOLATION_STAT_SHIFT); 390} 391 392/* Public functions */ 393/** 394 * wkup_m3_set_mem_type - Pass wkup_m3 which type of memory is in use 395 * @m3_ipc: Pointer to wkup_m3_ipc context 396 * @mem_type: memory type value read directly from emif 397 * 398 * wkup_m3 must know what memory type is in use to properly suspend 399 * and resume. 400 */ 401static void wkup_m3_set_mem_type(struct wkup_m3_ipc *m3_ipc, int mem_type) 402{ 403 m3_ipc->mem_type = mem_type; 404} 405 406/** 407 * wkup_m3_set_resume_address - Pass wkup_m3 resume address 408 * @m3_ipc: Pointer to wkup_m3_ipc context 409 * @addr: Physical address from which resume code should execute 410 */ 411static void wkup_m3_set_resume_address(struct wkup_m3_ipc *m3_ipc, void *addr) 412{ 413 m3_ipc->resume_addr = (unsigned long)addr; 414} 415 416/** 417 * wkup_m3_request_pm_status - Retrieve wkup_m3 status code after suspend 418 * @m3_ipc: Pointer to wkup_m3_ipc context 419 * 420 * Returns code representing the status of a low power mode transition. 421 * 0 - Successful transition 422 * 1 - Failure to transition to low power state 423 */ 424static int wkup_m3_request_pm_status(struct wkup_m3_ipc *m3_ipc) 425{ 426 unsigned int i; 427 int val; 428 429 val = wkup_m3_ctrl_ipc_read(m3_ipc, 1); 430 431 i = M3_STATUS_RESP_MASK & val; 432 i >>= __ffs(M3_STATUS_RESP_MASK); 433 434 return i; 435} 436 437/** 438 * wkup_m3_prepare_low_power - Request preparation for transition to 439 * low power state 440 * @m3_ipc: Pointer to wkup_m3_ipc context 441 * @state: A kernel suspend state to enter, either MEM or STANDBY 442 * 443 * Returns 0 if preparation was successful, otherwise returns error code 444 */ 445static int wkup_m3_prepare_low_power(struct wkup_m3_ipc *m3_ipc, int state) 446{ 447 struct device *dev = m3_ipc->dev; 448 int m3_power_state; 449 int ret = 0; 450 451 if (!wkup_m3_is_available(m3_ipc)) 452 return -ENODEV; 453 454 switch (state) { 455 case WKUP_M3_DEEPSLEEP: 456 m3_power_state = IPC_CMD_DS0; 457 wkup_m3_ctrl_ipc_write(m3_ipc, m3_ipc->volt_scale_offsets, 5); 458 break; 459 case WKUP_M3_STANDBY: 460 m3_power_state = IPC_CMD_STANDBY; 461 wkup_m3_ctrl_ipc_write(m3_ipc, DS_IPC_DEFAULT, 5); 462 break; 463 case WKUP_M3_IDLE: 464 m3_power_state = IPC_CMD_IDLE; 465 wkup_m3_ctrl_ipc_write(m3_ipc, DS_IPC_DEFAULT, 5); 466 break; 467 default: 468 return 1; 469 } 470 471 /* Program each required IPC register then write defaults to others */ 472 wkup_m3_ctrl_ipc_write(m3_ipc, m3_ipc->resume_addr, 0); 473 wkup_m3_ctrl_ipc_write(m3_ipc, m3_power_state, 1); 474 wkup_m3_ctrl_ipc_write(m3_ipc, m3_ipc->mem_type | 475 m3_ipc->vtt_conf | 476 m3_ipc->isolation_conf | 477 m3_ipc->halt, 4); 478 479 wkup_m3_ctrl_ipc_write(m3_ipc, DS_IPC_DEFAULT, 2); 480 wkup_m3_ctrl_ipc_write(m3_ipc, DS_IPC_DEFAULT, 3); 481 wkup_m3_ctrl_ipc_write(m3_ipc, DS_IPC_DEFAULT, 6); 482 wkup_m3_ctrl_ipc_write(m3_ipc, DS_IPC_DEFAULT, 7); 483 484 m3_ipc->state = M3_STATE_MSG_FOR_LP; 485 486 if (state == WKUP_M3_IDLE) 487 ret = wkup_m3_ping_noirq(m3_ipc); 488 else 489 ret = wkup_m3_ping(m3_ipc); 490 491 if (ret) { 492 dev_err(dev, "Unable to ping CM3\n"); 493 return ret; 494 } 495 496 return 0; 497} 498 499/** 500 * wkup_m3_finish_low_power - Return m3 to reset state 501 * @m3_ipc: Pointer to wkup_m3_ipc context 502 * 503 * Returns 0 if reset was successful, otherwise returns error code 504 */ 505static int wkup_m3_finish_low_power(struct wkup_m3_ipc *m3_ipc) 506{ 507 struct device *dev = m3_ipc->dev; 508 int ret = 0; 509 510 if (!wkup_m3_is_available(m3_ipc)) 511 return -ENODEV; 512 513 wkup_m3_ctrl_ipc_write(m3_ipc, IPC_CMD_RESET, 1); 514 wkup_m3_ctrl_ipc_write(m3_ipc, DS_IPC_DEFAULT, 2); 515 516 m3_ipc->state = M3_STATE_MSG_FOR_RESET; 517 518 ret = wkup_m3_ping(m3_ipc); 519 if (ret) { 520 dev_err(dev, "Unable to ping CM3\n"); 521 return ret; 522 } 523 524 return 0; 525} 526 527/** 528 * wkup_m3_request_wake_src - Get the wakeup source info passed from wkup_m3 529 * @m3_ipc: Pointer to wkup_m3_ipc context 530 */ 531static const char *wkup_m3_request_wake_src(struct wkup_m3_ipc *m3_ipc) 532{ 533 unsigned int wakeup_src_idx; 534 int j, val; 535 536 val = wkup_m3_ctrl_ipc_read(m3_ipc, 6); 537 538 wakeup_src_idx = val & M3_WAKE_SRC_MASK; 539 540 for (j = 0; j < ARRAY_SIZE(wakeups) - 1; j++) { 541 if (wakeups[j].irq_nr == wakeup_src_idx) 542 return wakeups[j].src; 543 } 544 return wakeups[j].src; 545} 546 547/** 548 * wkup_m3_set_rtc_only - Set the rtc_only flag 549 * @m3_ipc: Pointer to wkup_m3_ipc context 550 */ 551static void wkup_m3_set_rtc_only(struct wkup_m3_ipc *m3_ipc) 552{ 553 if (m3_ipc_state) 554 m3_ipc_state->is_rtc_only = true; 555} 556 557static struct wkup_m3_ipc_ops ipc_ops = { 558 .set_mem_type = wkup_m3_set_mem_type, 559 .set_resume_address = wkup_m3_set_resume_address, 560 .prepare_low_power = wkup_m3_prepare_low_power, 561 .finish_low_power = wkup_m3_finish_low_power, 562 .request_pm_status = wkup_m3_request_pm_status, 563 .request_wake_src = wkup_m3_request_wake_src, 564 .set_rtc_only = wkup_m3_set_rtc_only, 565}; 566 567/** 568 * wkup_m3_ipc_get - Return handle to wkup_m3_ipc 569 * 570 * Returns NULL if the wkup_m3 is not yet available, otherwise returns 571 * pointer to wkup_m3_ipc struct. 572 */ 573struct wkup_m3_ipc *wkup_m3_ipc_get(void) 574{ 575 if (m3_ipc_state) 576 get_device(m3_ipc_state->dev); 577 else 578 return NULL; 579 580 return m3_ipc_state; 581} 582EXPORT_SYMBOL_GPL(wkup_m3_ipc_get); 583 584/** 585 * wkup_m3_ipc_put - Free handle to wkup_m3_ipc returned from wkup_m3_ipc_get 586 * @m3_ipc: A pointer to wkup_m3_ipc struct returned by wkup_m3_ipc_get 587 */ 588void wkup_m3_ipc_put(struct wkup_m3_ipc *m3_ipc) 589{ 590 if (m3_ipc_state) 591 put_device(m3_ipc_state->dev); 592} 593EXPORT_SYMBOL_GPL(wkup_m3_ipc_put); 594 595static int wkup_m3_rproc_boot_thread(void *arg) 596{ 597 struct wkup_m3_ipc *m3_ipc = arg; 598 struct device *dev = m3_ipc->dev; 599 int ret; 600 601 init_completion(&m3_ipc->sync_complete); 602 603 ret = rproc_boot(m3_ipc->rproc); 604 if (ret) 605 dev_err(dev, "rproc_boot failed\n"); 606 else 607 m3_ipc_state = m3_ipc; 608 609 return 0; 610} 611 612static int wkup_m3_ipc_probe(struct platform_device *pdev) 613{ 614 struct device *dev = &pdev->dev; 615 int irq, ret, temp; 616 phandle rproc_phandle; 617 struct rproc *m3_rproc; 618 struct resource *res; 619 struct task_struct *task; 620 struct wkup_m3_ipc *m3_ipc; 621 struct device_node *np = dev->of_node; 622 623 m3_ipc = devm_kzalloc(dev, sizeof(*m3_ipc), GFP_KERNEL); 624 if (!m3_ipc) 625 return -ENOMEM; 626 627 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 628 m3_ipc->ipc_mem_base = devm_ioremap_resource(dev, res); 629 if (IS_ERR(m3_ipc->ipc_mem_base)) 630 return PTR_ERR(m3_ipc->ipc_mem_base); 631 632 irq = platform_get_irq(pdev, 0); 633 if (irq < 0) 634 return irq; 635 636 ret = devm_request_irq(dev, irq, wkup_m3_txev_handler, 637 0, "wkup_m3_txev", m3_ipc); 638 if (ret) { 639 dev_err(dev, "request_irq failed\n"); 640 return ret; 641 } 642 643 m3_ipc->mbox_client.dev = dev; 644 m3_ipc->mbox_client.tx_done = NULL; 645 m3_ipc->mbox_client.tx_prepare = NULL; 646 m3_ipc->mbox_client.rx_callback = NULL; 647 m3_ipc->mbox_client.tx_block = false; 648 m3_ipc->mbox_client.knows_txdone = false; 649 650 m3_ipc->mbox = mbox_request_channel(&m3_ipc->mbox_client, 0); 651 652 if (IS_ERR(m3_ipc->mbox)) { 653 dev_err(dev, "IPC Request for A8->M3 Channel failed! %ld\n", 654 PTR_ERR(m3_ipc->mbox)); 655 return PTR_ERR(m3_ipc->mbox); 656 } 657 658 if (of_property_read_u32(dev->of_node, "ti,rproc", &rproc_phandle)) { 659 dev_err(&pdev->dev, "could not get rproc phandle\n"); 660 ret = -ENODEV; 661 goto err_free_mbox; 662 } 663 664 m3_rproc = rproc_get_by_phandle(rproc_phandle); 665 if (!m3_rproc) { 666 dev_err(&pdev->dev, "could not get rproc handle\n"); 667 ret = -EPROBE_DEFER; 668 goto err_free_mbox; 669 } 670 671 m3_ipc->rproc = m3_rproc; 672 m3_ipc->dev = dev; 673 m3_ipc->state = M3_STATE_RESET; 674 675 m3_ipc->ops = &ipc_ops; 676 677 if (!of_property_read_u32(np, "ti,vtt-gpio-pin", &temp)) { 678 if (temp >= 0 && temp <= 31) 679 wkup_m3_set_vtt_gpio(m3_ipc, temp); 680 else 681 dev_warn(dev, "Invalid VTT GPIO(%d) pin\n", temp); 682 } 683 684 if (of_find_property(np, "ti,set-io-isolation", NULL)) 685 wkup_m3_set_io_isolation(m3_ipc); 686 687 ret = of_property_read_string(np, "firmware-name", 688 &m3_ipc->sd_fw_name); 689 if (ret) { 690 dev_dbg(dev, "Voltage scaling data blob not provided from DT.\n"); 691 }; 692 693 /* 694 * Wait for firmware loading completion in a thread so we 695 * can boot the wkup_m3 as soon as it's ready without holding 696 * up kernel boot 697 */ 698 task = kthread_run(wkup_m3_rproc_boot_thread, m3_ipc, 699 "wkup_m3_rproc_loader"); 700 701 if (IS_ERR(task)) { 702 dev_err(dev, "can't create rproc_boot thread\n"); 703 ret = PTR_ERR(task); 704 goto err_put_rproc; 705 } 706 707 wkup_m3_ipc_dbg_init(m3_ipc); 708 709 return 0; 710 711err_put_rproc: 712 rproc_put(m3_rproc); 713err_free_mbox: 714 mbox_free_channel(m3_ipc->mbox); 715 return ret; 716} 717 718static int wkup_m3_ipc_remove(struct platform_device *pdev) 719{ 720 wkup_m3_ipc_dbg_destroy(m3_ipc_state); 721 722 mbox_free_channel(m3_ipc_state->mbox); 723 724 rproc_shutdown(m3_ipc_state->rproc); 725 rproc_put(m3_ipc_state->rproc); 726 727 m3_ipc_state = NULL; 728 729 return 0; 730} 731 732static int __maybe_unused wkup_m3_ipc_suspend(struct device *dev) 733{ 734 /* 735 * Nothing needs to be done on suspend even with rtc_only flag set 736 */ 737 return 0; 738} 739 740static int __maybe_unused wkup_m3_ipc_resume(struct device *dev) 741{ 742 if (m3_ipc_state->is_rtc_only) { 743 rproc_shutdown(m3_ipc_state->rproc); 744 rproc_boot(m3_ipc_state->rproc); 745 } 746 747 m3_ipc_state->is_rtc_only = false; 748 749 return 0; 750} 751 752static const struct dev_pm_ops wkup_m3_ipc_pm_ops = { 753 SET_SYSTEM_SLEEP_PM_OPS(wkup_m3_ipc_suspend, wkup_m3_ipc_resume) 754}; 755 756static const struct of_device_id wkup_m3_ipc_of_match[] = { 757 { .compatible = "ti,am3352-wkup-m3-ipc", }, 758 { .compatible = "ti,am4372-wkup-m3-ipc", }, 759 {}, 760}; 761MODULE_DEVICE_TABLE(of, wkup_m3_ipc_of_match); 762 763static struct platform_driver wkup_m3_ipc_driver = { 764 .probe = wkup_m3_ipc_probe, 765 .remove = wkup_m3_ipc_remove, 766 .driver = { 767 .name = "wkup_m3_ipc", 768 .of_match_table = wkup_m3_ipc_of_match, 769 .pm = &wkup_m3_ipc_pm_ops, 770 }, 771}; 772 773module_platform_driver(wkup_m3_ipc_driver); 774 775MODULE_LICENSE("GPL v2"); 776MODULE_DESCRIPTION("wkup m3 remote processor ipc driver"); 777MODULE_AUTHOR("Dave Gerlach <d-gerlach@ti.com>");