/* Set the different timeouts needed by the SCU FW */ static int watchdog_set_timeouts(int timer_threshold, int warning_pretimeout, int reset_timeout) { u32 ipc_wbuf[3]; int ret = 0; u32 freq = watchdog_device.timer7_tbl_ptr->freq_hz; ipc_wbuf[0] = timer_threshold * freq; ipc_wbuf[1] = warning_pretimeout * freq; ipc_wbuf[2] = (reset_timeout - timer_threshold - warning_pretimeout) * freq; pr_debug(PFX "Watchdog ipc_buff[0]%x\n", ipc_wbuf[0]); pr_debug(PFX "Watchdog ipc_buff[1]%x\n", ipc_wbuf[1]); pr_debug(PFX "Watchdog ipc_buff[2]%x\n", ipc_wbuf[2]); ret = rpmsg_send_command(watchdog_instance, IPC_SET_WATCHDOG_TIMER, IPC_SET_SUB_LOAD_THRES, (u8 *) ipc_wbuf, NULL, 12, 0); if (ret) pr_crit(PFX "Error Setting SCU Watchdog Timer: %x\n", ret); return ret; }
int rpmsg_send_simple_command(struct rpmsg_instance *instance, u32 cmd, u32 sub) { int ret; ret = rpmsg_send_command(instance, cmd, sub, NULL, NULL, 0, 0); return ret; }
/* Providing rpmsg ipc generic interfaces. * Modules can call these API directly without registering rpmsg driver. * * The arg list is the same as intel_scu_ipc_command(), * so simply change intel_scu_ipc_command() to rpmsg_send_generic_command() */ int rpmsg_send_generic_command(u32 cmd, u32 sub, u8 *in, u32 inlen, u32 *out, u32 outlen) { struct rpmsg_instance *rpmsg_ipc_instance = rpmsg_ddata[RPMSG_IPC_COMMAND].rpmsg_instance; return rpmsg_send_command(rpmsg_ipc_instance, cmd, sub, in, out, inlen, outlen); }
/* Set the different timeouts needed by the SCU FW and start the * kernel watchdog */ static int watchdog_set_timeouts_and_start(int pretimeout, int timeout) { int ret, error = 0; struct ipc_wd_start { u32 pretimeout; u32 timeout; } ipc_wd_start = { pretimeout, timeout }; ret = rpmsg_send_command(watchdog_instance, IPC_WATCHDOG, SCU_WATCHDOG_START, (u8 *)&ipc_wd_start, NULL, sizeof(ipc_wd_start), 0); if (ret) { pr_crit("Error configuring and starting watchdog: %d\n", ret); error = -EIO; } return error; }
/* stops the timer */ static int intel_scu_stop(void) { int ret; pr_crit(PFX "%s\n", __func__); ret = rpmsg_send_command(watchdog_instance, IPC_SET_WATCHDOG_TIMER, IPC_SET_SUB_DISABLE, NULL, NULL, 0, 0); if (ret) { pr_crit(PFX "Error sending disable ipc: %x\n", ret); goto err; } watchdog_device.started = false; err: return ret; }
/* Keep alive */ static int watchdog_keepalive(void) { int ret; pr_err(PFX "%s\n", __func__); if (unlikely(!kicking_active)) { /* Close our eyes */ pr_err(PFX "Transparent kicking\n"); return 0; } /* Really kick it */ ret = rpmsg_send_command(watchdog_instance, IPC_SET_WATCHDOG_TIMER, IPC_SET_SUB_KEEPALIVE, NULL, NULL, 0, 0); if (ret) pr_err(PFX "Error sending keepalive ipc: %x\n", ret); return ret; }
int rpmsg_send_raw_command(struct rpmsg_instance *instance, u32 cmd, u32 sub, u8 *in, u32 *out, u32 inlen, u32 outlen, u32 sptr, u32 dptr) { int ret = 0; if (!instance) { pr_err("%s: Instance is NULL\n", __func__); return -EFAULT; } mutex_lock(&instance->instance_lock); instance->tx_msg->sptr = sptr; instance->tx_msg->dptr = dptr; mutex_unlock(&instance->instance_lock); ret = rpmsg_send_command(instance, cmd, sub, in, out, inlen, outlen); return ret; }
static int vrtc_mrst_do_probe(struct device *dev, struct resource *iomem, int rtc_irq) { int retval = 0; unsigned char rtc_control; unsigned char enable_bit_save = 0; /* There can be only one ... */ if (mrst_rtc.dev) return -EBUSY; if (!iomem) return -ENODEV; iomem = request_mem_region(iomem->start, iomem->end + 1 - iomem->start, driver_name); if (!iomem) { dev_dbg(dev, "i/o mem already in use.\n"); return -EBUSY; } mrst_rtc.irq = rtc_irq; mrst_rtc.iomem = iomem; mrst_rtc.dev = dev; dev_set_drvdata(dev, &mrst_rtc); mrst_rtc.rtc = rtc_device_register(driver_name, dev, &mrst_rtc_ops, THIS_MODULE); if (IS_ERR(mrst_rtc.rtc)) { retval = PTR_ERR(mrst_rtc.rtc); goto cleanup0; } rename_region(iomem, dev_name(&mrst_rtc.rtc->dev)); printk(KERN_ALERT"(%s) +------------rtc info-----------+\n",__func__); spin_lock_irq(&rtc_lock); enable_bit_save = vrtc_cmos_read(RTC_CONTROL); enable_bit_save &= (RTC_PIE | RTC_AIE); mrst_irq_disable(&mrst_rtc, RTC_PIE | RTC_AIE); rtc_control = vrtc_cmos_read(RTC_CONTROL); spin_unlock_irq(&rtc_lock); printk(KERN_ALERT"read PIE_AIE_save = 0x%02x, then clear. rtc_control = 0x%02x\n",enable_bit_save,rtc_control); if (!(rtc_control & RTC_24H) || (rtc_control & (RTC_DM_BINARY))) dev_dbg(dev, "TODO: support more than 24-hr BCD mode\n"); if (is_valid_irq(rtc_irq)) { retval = request_irq(rtc_irq, mrst_rtc_irq, IRQF_NO_SUSPEND, dev_name(&mrst_rtc.rtc->dev), mrst_rtc.rtc); if (retval < 0) { dev_dbg(dev, "IRQ %d is already in use, err %d\n", rtc_irq, retval); goto cleanup1; } } /* make RTC device wake capable from sleep */ device_init_wakeup(dev, true); if ((__intel_mid_cpu_chip == INTEL_MID_CPU_CHIP_PENWELL) || (__intel_mid_cpu_chip == INTEL_MID_CPU_CHIP_CLOVERVIEW)) { retval = rpmsg_send_command(vrtc_mrst_instance, IPCMSG_GET_HOBADDR, 0, NULL, &oshob_base, 0, 1); if (retval < 0) { dev_dbg(dev, "Unable to get OSHOB base address, err %d\n", retval); goto cleanup1; } oshob_addr = ioremap_nocache(oshob_base+OSHOB_ALARM_OFFSET, 4); if (!oshob_addr) { dev_dbg(dev, "Unable to do ioremap for OSHOB\n"); retval = -ENOMEM; goto cleanup1; } } spin_lock_irq(&rtc_lock); if(enable_bit_save) mrst_irq_enable(&mrst_rtc, enable_bit_save);//add for power off rtc issue spin_unlock_irq(&rtc_lock); rtc_control = vrtc_cmos_read(RTC_CONTROL); printk(KERN_ALERT"read resume rtc_control = 0x%02x.\n",rtc_control); printk(KERN_ALERT"(%s) +-------------------------------+\n",__func__); dev_dbg(dev, "vRTC driver initialised\n"); return 0; cleanup1: rtc_device_unregister(mrst_rtc.rtc); cleanup0: dev_set_drvdata(dev, NULL); mrst_rtc.dev = NULL; release_mem_region(iomem->start, resource_size(iomem)); dev_err(dev, "rtc-mrst: unable to initialise\n"); return retval; }
/* ioctl */ static long intel_scu_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { void __user *argp = (void __user *)arg; u32 __user *p = argp; u32 val; int options; static const struct watchdog_info ident = { .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, /* @todo Get from SCU via ipc_get_scu_fw_version()? */ .firmware_version = 0, /* len < 32 */ .identity = "Intel_SCU IOH Watchdog" }; switch (cmd) { case WDIOC_GETSUPPORT: return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; case WDIOC_GETSTATUS: case WDIOC_GETBOOTSTATUS: return put_user(0, p); case WDIOC_KEEPALIVE: pr_warn("%s: KeepAlive ioctl\n", __func__); if (!watchdog_device.started) return -EINVAL; watchdog_keepalive(); return 0; case WDIOC_SETPRETIMEOUT: pr_warn("%s: SetPreTimeout ioctl\n", __func__); if (watchdog_device.started) return -EBUSY; /* Timeout to warn */ if (get_user(val, p)) return -EFAULT; pre_timeout = val; return 0; case WDIOC_SETTIMEOUT: pr_warn("%s: SetTimeout ioctl\n", __func__); if (watchdog_device.started) return -EBUSY; if (get_user(val, p)) return -EFAULT; timeout = val; return 0; case WDIOC_GETTIMEOUT: return put_user(timeout, p); case WDIOC_SETOPTIONS: if (get_user(options, p)) return -EFAULT; if (options & WDIOS_DISABLECARD) { pr_warn("%s: Stopping the watchdog\n", __func__); watchdog_stop(); return 0; } if (options & WDIOS_ENABLECARD) { pr_warn("%s: Starting the watchdog\n", __func__); if (watchdog_device.started) return -EBUSY; if (check_timeouts(pre_timeout, timeout)) { pr_warn("%s: Invalid thresholds\n", __func__); return -EINVAL; } if (watchdog_config_and_start(timeout, pre_timeout)) return -EINVAL; return 0; } return 0; default: return -ENOTTY; } } static int watchdog_set_reset_type(int reset_type) { int ret; struct ipc_wd_on_timeout { u32 reset_type; } ipc_wd_on_timeout = { reset_type }; ret = rpmsg_send_command(watchdog_instance, IPC_WATCHDOG, SCU_WATCHDOG_SET_ACTION_ON_TIMEOUT, (u8 *)&ipc_wd_on_timeout, NULL, sizeof(ipc_wd_on_timeout), 0); if (ret) { pr_crit("Error setting watchdog action: %d\n", ret); return -EIO; } watchdog_device.normal_wd_action = reset_type; return 0; }