static ssize_t arisc_p2wi_write_block_data_show(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t size = 0; u32 ret = 0; if ((block_cfg.addr == NULL) || (block_cfg.data == NULL) || (*block_cfg.addr < 0) || (*block_cfg.addr > 0xff)) { ARISC_WRN("invalid p2wi paras, regaddr:0x%x, data:0x%x\n", block_cfg.addr ? *block_cfg.addr : 0, block_cfg.data ? *block_cfg.data : 0); ARISC_LOG("pls echo like that: echo regaddr data > p2wi_write_block_data\n"); return size; } block_cfg.msgattr = ARISC_MESSAGE_ATTR_SOFTSYN; block_cfg.len = 1; block_cfg.addr = ®addr; block_cfg.data = &data; ret = arisc_p2wi_read_block_data(&block_cfg); if (ret) { ARISC_WRN("p2wi read data:0x%x from regaddr:0x%x fail\n", *block_cfg.data, *block_cfg.addr); } else { ARISC_LOG("p2wi read data:0x%x from regaddr:0x%x success\n", *block_cfg.data, *block_cfg.addr); } size = sprintf(buf, "%x\n", data); return size; }
int sunxi_arisc_wait_ready(void) { ARISC_INF("wait arisc ready....\n"); if (arisc_wait_ready(10000)) { ARISC_LOG("arisc startup failed\n"); } arisc_set_paras(); ARISC_LOG("sunxi-arisc driver v%s startup ok\n", DRV_VERSION); return 0; }
static ssize_t arisc_p2wi_write_block_data_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { u32 ret; sscanf(buf, "%x %x", (u32 *)®addr, (u32 *)&data); if ((regaddr < 0) || (regaddr > 0xff)) { ARISC_WRN("invalid p2wi paras, regaddr:0x%x, data:0x%x\n", regaddr, data); ARISC_WRN("pls echo like that: echo regaddr data > p2wi_write_block_data\n"); return size; } block_cfg.msgattr = ARISC_MESSAGE_ATTR_SOFTSYN; block_cfg.len = 1; block_cfg.addr = ®addr; block_cfg.data = &data; ret = arisc_p2wi_write_block_data(&block_cfg); if (ret) { ARISC_WRN("p2wi write data:0x%x to regaddr:0x%x fail\n", *block_cfg.data, *block_cfg.addr); } else { ARISC_LOG("p2wi write data:0x%x to regaddr:0x%x success\n", *block_cfg.data, *block_cfg.addr); } return size; }
static ssize_t arisc_rsb_write_block_data_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { u32 ret = 0; sscanf(buf, "%x %x %x %x", &devaddr, (u32 *)®addr, (u32 *)&data, &datatype); if ((devaddr > 0xff) || ((datatype != RSB_DATA_TYPE_BYTE) && (datatype != RSB_DATA_TYPE_HWORD) && (datatype != RSB_DATA_TYPE_WORD))) { ARISC_WRN("invalid rsb paras, devaddr:0x%x, regaddr:0x%x, data:0x%x, datatype:0x%x\n", devaddr, regaddr, data, datatype); ARISC_WRN("pls echo like that: echo devaddr regaddr data datatype > rsb_write_block_data\n"); return size; } block_cfg.msgattr = ARISC_MESSAGE_ATTR_SOFTSYN; block_cfg.datatype = datatype; block_cfg.len = 1; block_cfg.devaddr = devaddr; block_cfg.regaddr = ®addr; block_cfg.data = &data; ret = arisc_rsb_write_block_data(&block_cfg); if (ret) { ARISC_ERR("rsb write data:0x%x to devaddr:0x%x regaddr:0x%x fail\n", *block_cfg.data, block_cfg.devaddr, *block_cfg.regaddr); } else { ARISC_LOG("rsb write data:0x%x to devaddr:0x%x regaddr:0x%x success\n", *block_cfg.data, block_cfg.devaddr, *block_cfg.regaddr); } return size; }
static int sunxi_arisc_para_init(struct arisc_para *para) { /* init para */ memset(para, 0, sizeof(struct arisc_para)); para->message_pool_phys = (uint32_t)dts_cfg.space.msgpool_dst; para->message_pool_size = (uint32_t)dts_cfg.space.msgpool_size; para->standby_base = (uint32_t)dts_cfg.space.standby_dst; para->standby_size = (uint32_t)dts_cfg.space.standby_size; memcpy((void *)¶->vf, (void *)dts_cfg.vf, sizeof(para->vf)); memcpy((void *)¶->dram_para, (void *)&dts_cfg.dram_para, sizeof(para->dram_para)); para->power_key_code = dts_cfg.s_cir.power_key_code; para->addr_code = dts_cfg.s_cir.addr_code; para->suart_status = dts_cfg.s_uart.status; para->pmu_bat_shutdown_ltf = dts_cfg.pmu.pmu_bat_shutdown_ltf; para->pmu_bat_shutdown_htf = dts_cfg.pmu.pmu_bat_shutdown_htf; para->pmu_pwroff_vol = dts_cfg.pmu.pmu_pwroff_vol; para->power_start = dts_cfg.pmu.power_start; para->powchk_used = dts_cfg.power.powchk_used; para->power_reg = dts_cfg.power.power_reg; para->system_power = dts_cfg.power.system_power; ARISC_LOG("arisc_para size:%llx\n", sizeof(struct arisc_para)); ARISC_INF("msgpool base:%x, size:%u\n", para->message_pool_phys, para->message_pool_size); return 0; }
static ssize_t arisc_dram_crc_paras_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { u32 dram_crc_en = 0; u32 dram_crc_srcaddr = 0; u32 dram_crc_len = 0; sscanf(buf, "%x %x %x\n", &dram_crc_en, &dram_crc_srcaddr, &dram_crc_len); if ((dram_crc_en != 0) && (dram_crc_en != 1)) { ARISC_WRN("invalid arisc debug dram crc paras [%x] [%x] [%x] to set\n", dram_crc_en, dram_crc_srcaddr, dram_crc_len); return size; } arisc_debug_dram_crc_en = dram_crc_en; arisc_debug_dram_crc_srcaddr = dram_crc_srcaddr; arisc_debug_dram_crc_len = dram_crc_len; arisc_set_dram_crc_paras(arisc_debug_dram_crc_en, arisc_debug_dram_crc_srcaddr, arisc_debug_dram_crc_len); ARISC_LOG("dram_crc_en=0x%x, dram_crc_srcaddr=0x%x, dram_crc_len=0x%x\n", arisc_debug_dram_crc_en, arisc_debug_dram_crc_srcaddr, arisc_debug_dram_crc_len); return size; }
static int __init arisc_init(void) { int ret; ARISC_LOG("sunxi-arisc driver v%s\n", DRV_VERSION); ret = platform_driver_register(&sunxi_arisc_driver); if (IS_ERR_VALUE(ret)) { ARISC_ERR("register sunxi arisc platform driver failed\n"); goto err_platform_driver_register; } ret = platform_device_register(&sunxi_arisc_device); if (IS_ERR_VALUE(ret)) { ARISC_ERR("register sunxi arisc platform device failed\n"); goto err_platform_device_register; } sunxi_arisc_sysfs(&sunxi_arisc_device); /* arisc init ok */ arisc_notify(ARISC_INIT_READY, NULL); return 0; err_platform_device_register: platform_device_unregister(&sunxi_arisc_device); err_platform_driver_register: platform_driver_unregister(&sunxi_arisc_driver); return -EINVAL; }
static ssize_t arisc_freq_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { u32 freq = 0; u32 pll = 0; u32 mode = 0; u32 ret = 0; sscanf(buf, "%u %u", &pll, &freq); #if (defined CONFIG_ARCH_SUN8IW1P1) || (defined CONFIG_ARCH_SUN8IW3P1) || (defined CONFIG_ARCH_SUN8IW5P1) if ((pll != 1) || (freq < 0) || (freq > 3000000)) { ARISC_WRN("invalid pll [%u] or freq [%u] to set, this platform only support pll1, freq [0, 3000000]KHz\n", pll, freq); ARISC_WRN("pls echo like that: echo pll freq > freq\n"); return size; } #elif (defined CONFIG_ARCH_SUN9IW1P1) || (defined CONFIG_ARCH_SUN8IW6P1) if (((pll != 1) && (pll != 2)) || (freq < 0) || (freq > 3000000)) { ARISC_WRN("invalid pll [%u] or freq [%u] to set, this platform only support pll1 and pll2, freq [0, 3000000]KHz\n", pll, freq); ARISC_WRN("pls echo like that: echo pll freq > freq\n"); return size; } #endif arisc_pll = pll; ret = arisc_dvfs_set_cpufreq(freq, pll, mode, NULL, NULL); if (ret) { ARISC_ERR("pll%u freq set to %u fail\n", pll, freq); } else { ARISC_LOG("pll%u freq set to %u success\n", pll, freq); } return size; }
static int arisc_wait_ready(unsigned int timeout) { /* wait arisc startup ready */ while (1) { /* * linux cpu interrupt is disable now, * we should query message by hand. */ struct arisc_message *pmessage = arisc_hwmsgbox_query_message(); if (pmessage == NULL) { /* try to query again */ continue; } /* query valid message */ if (pmessage->type == ARISC_STARTUP_NOTIFY) { /* check arisc software and driver version match or not */ if (pmessage->paras[0] != ARISC_VERSIONS) { ARISC_ERR("arisc firmware:%d and driver version:%u not matched\n", pmessage->paras[0], ARISC_VERSIONS); return -EINVAL; } else { /* printf the main and sub version string */ memcpy((void *)arisc_version, (const void*)(&(pmessage->paras[1])), 40); ARISC_LOG("arisc version: [%s]\n", arisc_version); } /* received arisc startup ready message */ ARISC_INF("arisc startup ready\n"); if ((pmessage->attr & ARISC_MESSAGE_ATTR_SOFTSYN) || (pmessage->attr & ARISC_MESSAGE_ATTR_HARDSYN)) { /* synchronous message, just feedback it */ ARISC_INF("arisc startup notify message feedback\n"); pmessage->paras[0] = (uint32_t)dts_cfg.image.base; arisc_hwmsgbox_feedback_message(pmessage, ARISC_SEND_MSG_TIMEOUT); } else { /* asyn message, free message directly */ ARISC_INF("arisc startup notify message free directly\n"); arisc_message_free(pmessage); } break; } /* * invalid message detected, ignore it. * by superm at 2012-7-6 18:34:38. */ ARISC_WRN("arisc startup waiting ignore message\n"); if ((pmessage->attr & ARISC_MESSAGE_ATTR_SOFTSYN) || (pmessage->attr & ARISC_MESSAGE_ATTR_HARDSYN)) { /* synchronous message, just feedback it */ arisc_hwmsgbox_send_message(pmessage, ARISC_SEND_MSG_TIMEOUT); } else { /* asyn message, free message directly */ arisc_message_free(pmessage); } /* we need waiting continue */ } return 0; }
int sunxi_arisc_probe(void *cfg) { struct arisc_para para; ARISC_LOG("sunxi-arisc driver begin startup %d\n", arisc_debug_level); memcpy((void *)&dts_cfg, (const void *)cfg, sizeof(struct dts_cfg)); /* init arisc parameter */ sunxi_arisc_para_init(¶); /* load arisc */ sunxi_load_arisc(dts_cfg.image.base, dts_cfg.image.size, (void *)(¶), sizeof(struct arisc_para)); /* initialize hwspinlock */ ARISC_INF("hwspinlock initialize\n"); arisc_hwspinlock_init(); /* initialize hwmsgbox */ ARISC_INF("hwmsgbox initialize\n"); arisc_hwmsgbox_init(); /* initialize message manager */ ARISC_INF("message manager initialize start:0x%llx, size:0x%llx\n", dts_cfg.space.msgpool_dst, dts_cfg.space.msgpool_size); arisc_message_manager_init((void *)dts_cfg.space.msgpool_dst, dts_cfg.space.msgpool_size); /* wait arisc ready */ ARISC_INF("wait arisc ready....\n"); if (arisc_wait_ready(10000)) { ARISC_LOG("arisc startup failed\n"); } arisc_set_paras(); /* enable arisc asyn tx interrupt */ //arisc_hwmsgbox_enable_receiver_int(ARISC_HWMSGBOX_ARISC_ASYN_TX_CH, AW_HWMSG_QUEUE_USER_AC327); /* enable arisc syn tx interrupt */ //arisc_hwmsgbox_enable_receiver_int(ARISC_HWMSGBOX_ARISC_SYN_TX_CH, AW_HWMSG_QUEUE_USER_AC327); /* arisc initialize succeeded */ ARISC_LOG("sunxi-arisc driver v%s is starting\n", DRV_VERSION); return 0; }
static ssize_t arisc_p2wi_read_block_data_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { sscanf(buf, "%x", (u32 *)®addr); if ((regaddr < 0) || (regaddr > 0xff)) { ARISC_WRN("invalid p2wi paras, regaddr:0x%x\n", regaddr); ARISC_LOG("pls echo like that: echo regaddr > p2wi_read_block_data\n"); return size; } block_cfg.msgattr = ARISC_MESSAGE_ATTR_SOFTSYN; block_cfg.len = 1; block_cfg.addr = ®addr; block_cfg.data = &data; ARISC_LOG("p2wi read regaddr:0x%x\n", *block_cfg.addr); return size; }
static int sunxi_arisc_resume(struct device *dev) { unsigned long wake_event; standby_info_para_t sst_info; atomic_set(&arisc_suspend_flag, 0); arisc_query_wakeup_source(&wake_event); if (wake_event & CPUS_WAKEUP_POWER_EXP) { ARISC_LOG("power exception during standby, enable:0x%x" \ " expect state:0x%x, expect consumption:%dmw", \ arisc_powchk_back.power_state.enable, \ arisc_powchk_back.power_state.power_reg, \ arisc_powchk_back.power_state.system_power); arisc_query_standby_power(&sst_info); ARISC_LOG(" real state:0x%x, real consumption:%dmw\n", \ sst_info.power_state.power_reg, \ sst_info.power_state.system_power); } return 0; }
static ssize_t arisc_p2wi_read_block_data_show(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t size = 0; u32 ret = 0; if ((block_cfg.addr == NULL) || (block_cfg.data == NULL) || (*block_cfg.addr < 0) || (*block_cfg.addr > 0xff)) { ARISC_LOG("invalid p2wi paras, regaddr:0x%x\n", block_cfg.addr ? *block_cfg.addr : 0); ARISC_LOG("pls echo like that: echo regaddr > p2wi_read_block_data\n"); return size; } ret = arisc_p2wi_read_block_data(&block_cfg); if (ret) { ARISC_LOG("p2wi read data:0x%x from regaddr:0x%x fail\n", *block_cfg.data, *block_cfg.addr); } else { ARISC_LOG("p2wi read data:0x%x from regaddr:0x%x success\n", *block_cfg.data, *block_cfg.addr); } size = sprintf(buf, "%x\n", data); return size; }
/* ********************************************************************************************************* * SEND MESSAGE BY HWMSGBOX * * Description: send one message to another processor by hwmsgbox. * * Arguments : pmessage : the pointer of sended message frame. * timeout : the wait time limit when message fifo is full, * it is valid only when parameter mode = HWMSG_SEND_WAIT_TIMEOUT. * * Returns : 0 if send message succeeded, other if failed. ********************************************************************************************************* */ int arisc_hwmsgbox_send_message(struct arisc_message *pmessage, unsigned int timeout) { volatile unsigned long value; if (pmessage == (struct arisc_message *)(NULL)) { return -EINVAL; } if (pmessage->attr & ARISC_MESSAGE_ATTR_HARDSYN) { //use ac327 hwsyn transmit channel. while (readl(IO_ADDRESS(AW_MSGBOX_FIFO_STATUS_REG(ARISC_HWMSGBOX_AC327_SYN_TX_CH))) == 1) { //message-queue fifo is full, waiting always ; } value = ((volatile unsigned long)pmessage) - arisc_sram_a2_vbase; ARISC_INF("ac327 send hard syn message : %x\n", (unsigned int)value); writel(value, IO_ADDRESS(AW_MSGBOX_MSG_REG(ARISC_HWMSGBOX_AC327_SYN_TX_CH))); //hwsyn messsage must feedback use syn rx channel while (readl(IO_ADDRESS(AW_MSGBOX_MSG_STATUS_REG(ARISC_HWMSGBOX_AC327_SYN_RX_CH))) == 0) { //message not valid ; } //check message valid if (value != (readl(IO_ADDRESS(AW_MSGBOX_MSG_REG(ARISC_HWMSGBOX_AC327_SYN_RX_CH))))) { ARISC_ERR("hard syn message error\n"); return -EINVAL; } ARISC_INF("ac327 hard syn message [%x, %x] feedback\n", (unsigned int)value, (unsigned int)pmessage->type); return 0; } //use ac327 asyn transmit channel. while (readl(IO_ADDRESS(AW_MSGBOX_FIFO_STATUS_REG(ARISC_HWMSGBOX_ARISC_ASYN_RX_CH))) == 1) { //message-queue fifo is full, waiting always ; } //write message to message-queue fifo. value = ((volatile unsigned long)pmessage) - arisc_sram_a2_vbase; ARISC_LOG("ac327 send soft syn or asyn message : %x\n", (unsigned int)value); writel(value, IO_ADDRESS(AW_MSGBOX_MSG_REG(ARISC_HWMSGBOX_ARISC_ASYN_RX_CH))); //syn messsage must wait message feedback if (pmessage->attr & ARISC_MESSAGE_ATTR_SOFTSYN) { ARISC_ERR("standby arisc driver not support soft syn message transfer\n"); return -EINVAL; } return 0; }
static ssize_t arisc_rsb_read_block_data_show(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t size = 0; u32 ret = 0; if ((block_cfg.regaddr == NULL) || (block_cfg.data == NULL) || (block_cfg.devaddr > 0xff) || ((block_cfg.datatype != RSB_DATA_TYPE_BYTE) && (block_cfg.datatype != RSB_DATA_TYPE_HWORD) && (block_cfg.datatype != RSB_DATA_TYPE_WORD))) { ARISC_WRN("invalid rsb paras, devaddr:0x%x, regaddr:0x%x, datatype:0x%x\n", block_cfg.devaddr, block_cfg.regaddr ? *block_cfg.regaddr : 0, block_cfg.datatype); ARISC_WRN("pls echo like that: echo devaddr regaddr datatype > rsb_read_block_data\n"); return size; } ret = arisc_rsb_read_block_data(&block_cfg); if (ret) { ARISC_LOG("rsb read data:0x%x from devaddr:0x%x regaddr:0x%x fail\n", *block_cfg.data, block_cfg.devaddr, *block_cfg.regaddr); } else { ARISC_LOG("rsb read data:0x%x from devaddr:0x%x regaddr:0x%x success\n", *block_cfg.data, block_cfg.devaddr, *block_cfg.regaddr); } size = sprintf(buf, "%x\n", data); return size; }
static ssize_t arisc_debug_baudrate_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { u32 value = 0; sscanf(buf, "%u", &value); if ((value != 115200) && (value != 57600) && (value != 9600)) { ARISC_WRN("invalid arisc uart baudrate [%d] to set\n", value); return size; } arisc_debug_baudrate = value; arisc_set_uart_baudrate(arisc_debug_baudrate); ARISC_LOG("debug_baudrate change to %d\n", arisc_debug_baudrate); return size; }
static ssize_t arisc_debug_mask_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { u32 value = 0; sscanf(buf, "%u", &value); if ((value < 0) || (value > 3)) { ARISC_WRN("invalid arisc debug mask [%d] to set\n", value); return size; } arisc_debug_level = value; arisc_set_debug_level(arisc_debug_level); ARISC_LOG("debug_mask change to %d\n", arisc_debug_level); return size; }
static ssize_t arisc_power_state_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { unsigned long value; if (kstrtoul(buf, 0, &value) < 0) { ARISC_ERR("illegal value, only one para support"); return -EINVAL; } arisc_powchk_back.power_state.power_reg = value; arisc_set_standby_power_cfg(&arisc_powchk_back); ARISC_LOG("standby_power_set power_state 0x%x\n", arisc_powchk_back.power_state.power_reg); return size; }
static ssize_t arisc_power_consum_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { unsigned long value; if (kstrtoul(buf, 0, &value) < 0) { if (1 != sscanf(buf, "%lu", &value)) { ARISC_ERR("illegal value, only one para support"); return -EINVAL; } } arisc_powchk_back.power_state.system_power = value; arisc_set_standby_power_cfg(&arisc_powchk_back); ARISC_LOG("standby_power_set power_consum %dmw\n", arisc_powchk_back.power_state.system_power); return size; }
static ssize_t arisc_rsb_read_block_data_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { sscanf(buf, "%x %x %x", &devaddr, (u32 *)®addr, &datatype); if ((devaddr > 0xff) || ((datatype != RSB_DATA_TYPE_BYTE) && (datatype != RSB_DATA_TYPE_HWORD) && (datatype != RSB_DATA_TYPE_WORD))) { ARISC_WRN("invalid rsb paras to set, devaddr:0x%x, regaddr:0x%x, datatype:0x%x\n", devaddr, regaddr, datatype); ARISC_WRN("pls echo like that: echo devaddr regaddr datatype > rsb_read_block_data\n"); return size; } block_cfg.msgattr = ARISC_MESSAGE_ATTR_SOFTSYN; block_cfg.datatype = datatype; block_cfg.len = 1; block_cfg.devaddr = devaddr; block_cfg.regaddr = ®addr; block_cfg.data = &data; ARISC_LOG("rsb read data from devaddr:0x%x regaddr:0x%x\n", devaddr, regaddr); return size; }
static ssize_t arisc_dram_crc_result_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { u32 error = 0; u32 total_count = 0; u32 error_count = 0; sscanf(buf, "%u %u %u", &error, &total_count, &error_count); if ((error != 0) && (error != 1)) { ARISC_WRN("invalid arisc dram crc result [%d] [%d] [%d] to set\n", error, total_count, error_count); return size; } arisc_debug_dram_crc_error = error; arisc_debug_dram_crc_total_count = total_count; arisc_debug_dram_crc_error_count = error_count; arisc_set_dram_crc_result((unsigned long)arisc_debug_dram_crc_error, (unsigned long)arisc_debug_dram_crc_total_count, (unsigned long)arisc_debug_dram_crc_error_count); ARISC_LOG("debug_dram_crc_result change to error:%u total count:%u error count:%u\n", arisc_debug_dram_crc_error, arisc_debug_dram_crc_total_count, arisc_debug_dram_crc_error_count); return size; }
static ssize_t arisc_power_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { unsigned long value; if (kstrtoul(buf, 0, &value) < 0) { ARISC_ERR("illegal value, only one para support\n"); return -EINVAL; } if (value & ~(CPUS_ENABLE_POWER_EXP | CPUS_WAKEUP_POWER_STA | CPUS_WAKEUP_POWER_CSM)) { ARISC_ERR("invalid format, 'enable' should:\n"\ " bit31:enable power check during standby\n"\ " bit1: enable wakeup when power state exception\n"\ " bit0: enable wakeup when power consume exception\n"); return size; } arisc_powchk_back.power_state.enable = value; arisc_set_standby_power_cfg(&arisc_powchk_back); ARISC_LOG("standby_power_set enable:0x%x\n", arisc_powchk_back.power_state.enable); return size; }
static void __exit arisc_exit(void) { platform_device_unregister(&sunxi_arisc_device); platform_driver_unregister(&sunxi_arisc_driver); ARISC_LOG("module unloaded\n"); }
static int arisc_wait_ready(unsigned int timeout) { unsigned long expire; #ifdef CONFIG_SUNXI_MODULE struct sunxi_module_info arisc_module_info; #endif expire = msecs_to_jiffies(timeout) + jiffies; /* wait arisc startup ready */ while (1) { /* * linux cpu interrupt is disable now, * we should query message by hand. */ struct arisc_message *pmessage = arisc_hwmsgbox_query_message(); if (pmessage == NULL) { if (time_is_before_eq_jiffies(expire)) { return -ETIMEDOUT; } /* try to query again */ continue; } /* query valid message */ if (pmessage->type == ARISC_STARTUP_NOTIFY) { /* check arisc software and driver version match or not */ if (pmessage->paras[0] != ARISC_VERSIONS) { ARISC_ERR("arisc firmware:%d and driver version:%d not matched\n", pmessage->paras[0], ARISC_VERSIONS); return -EINVAL; } else { /* printf the main and sub version string */ memcpy((void *)arisc_version, (const void*)(&(pmessage->paras[1])), 40); ARISC_LOG("arisc version: [%s]\n", arisc_version); #ifdef CONFIG_SUNXI_MODULE strncpy((char *)arisc_module_info.module, (const char *)"arisc", 16); strncpy((char *)arisc_module_info.version, (const char *)arisc_version, 16); sunxi_module_info_register(&arisc_module_info); #endif } /* received arisc startup ready message */ ARISC_INF("arisc startup ready\n"); if ((pmessage->attr & ARISC_MESSAGE_ATTR_SOFTSYN) || (pmessage->attr & ARISC_MESSAGE_ATTR_HARDSYN)) { /* synchronous message, just feedback it */ ARISC_INF("arisc startup notify message feedback\n"); pmessage->paras[0] = virt_to_phys((void *)&arisc_binary_start); arisc_hwmsgbox_feedback_message(pmessage, ARISC_SEND_MSG_TIMEOUT); } else { /* asyn message, free message directly */ ARISC_INF("arisc startup notify message free directly\n"); arisc_message_free(pmessage); } break; } /* * invalid message detected, ignore it. * by sunny at 2012-7-6 18:34:38. */ ARISC_WRN("arisc startup waiting ignore message\n"); if ((pmessage->attr & ARISC_MESSAGE_ATTR_SOFTSYN) || (pmessage->attr & ARISC_MESSAGE_ATTR_HARDSYN)) { /* synchronous message, just feedback it */ arisc_hwmsgbox_send_message(pmessage, ARISC_SEND_MSG_TIMEOUT); } else { /* asyn message, free message directly */ arisc_message_free(pmessage); } /* we need waiting continue */ } return 0; }
static int sunxi_arisc_probe(struct platform_device *pdev) { int binary_len; int ret; ARISC_INF("arisc initialize\n"); /* cfg sunxi arisc clk */ ret = sunxi_arisc_clk_cfg(pdev); if (ret) { ARISC_ERR("sunxi-arisc clk cfg failed\n"); return -EINVAL; } /* cfg sunxi arisc pin */ ret = sunxi_arisc_pin_cfg(pdev); if (ret) { ARISC_ERR("sunxi-arisc pin cfg failed\n"); return -EINVAL; } ARISC_INF("sram_a2 vaddr(%x)\n", (unsigned int)arisc_sram_a2_vbase); #if (defined CONFIG_ARCH_SUN8IW1P1) || (defined CONFIG_ARCH_SUN8IW3P1) || (defined CONFIG_ARCH_SUN8IW5P1) || (defined CONFIG_ARCH_SUN8IW6P1) binary_len = 0x13000; #elif defined CONFIG_ARCH_SUN9IW1P1 binary_len = (int)(&arisc_binary_end) - (int)(&arisc_binary_start); #endif /* clear sram_a2 area */ memset((void *)arisc_sram_a2_vbase, 0, SUNXI_SRAM_A2_SIZE); /* load arisc system binary data to sram_a2 */ memcpy((void *)arisc_sram_a2_vbase, (void *)(&arisc_binary_start), binary_len); ARISC_INF("move arisc binary data [addr = %x, len = %x] to sram_a2 finished\n", (unsigned int)(&arisc_binary_start), (unsigned int)binary_len); /* initialize hwspinlock */ ARISC_INF("hwspinlock initialize\n"); arisc_hwspinlock_init(); /* initialize hwmsgbox */ ARISC_INF("hwmsgbox initialize\n"); arisc_hwmsgbox_init(); /* initialize message manager */ ARISC_INF("message manager initialize\n"); arisc_message_manager_init(); /* set arisc cpu reset to de-assert state */ ARISC_INF("set arisc reset to de-assert state\n"); #if (defined CONFIG_ARCH_SUN8IW1P1) || (defined CONFIG_ARCH_SUN8IW3P1) || (defined CONFIG_ARCH_SUN8IW5P1) || (defined CONFIG_ARCH_SUN8IW6P1) { volatile unsigned long value; value = readl((IO_ADDRESS(SUNXI_R_CPUCFG_PBASE) + 0x0)); value &= ~1; writel(value, (IO_ADDRESS(SUNXI_R_CPUCFG_PBASE) + 0x0)); value = readl((IO_ADDRESS(SUNXI_R_CPUCFG_PBASE) + 0x0)); value |= 1; writel(value, (IO_ADDRESS(SUNXI_R_CPUCFG_PBASE) + 0x0)); } #elif defined CONFIG_ARCH_SUN9IW1P1 { volatile unsigned long value; value = readl((IO_ADDRESS(SUNXI_R_PRCM_PBASE) + 0x0)); value &= ~1; writel(value, (IO_ADDRESS(SUNXI_R_PRCM_PBASE) + 0x0)); value = readl((IO_ADDRESS(SUNXI_R_PRCM_PBASE) + 0x0)); value |= 1; writel(value, (IO_ADDRESS(SUNXI_R_PRCM_PBASE) + 0x0)); } #endif /* wait arisc ready */ ARISC_INF("wait arisc ready....\n"); if (arisc_wait_ready(10000)) { ARISC_LOG("arisc startup failed\n"); } /* enable arisc asyn tx interrupt */ arisc_hwmsgbox_enable_receiver_int(ARISC_HWMSGBOX_ARISC_ASYN_TX_CH, AW_HWMSG_QUEUE_USER_AC327); /* enable arisc syn tx interrupt */ arisc_hwmsgbox_enable_receiver_int(ARISC_HWMSGBOX_ARISC_SYN_TX_CH, AW_HWMSG_QUEUE_USER_AC327); /* config dvfs v-f table */ if (arisc_dvfs_cfg_vf_table()) { ARISC_WRN("config dvfs v-f table failed\n"); } #if (defined CONFIG_ARCH_SUN8IW1P1) || (defined CONFIG_ARCH_SUN8IW6P1) || (defined CONFIG_ARCH_SUN9IW1P1) /* config ir config paras */ if (arisc_config_ir_paras()) { ARISC_WRN("config ir paras failed\n"); } #endif #if (defined CONFIG_ARCH_SUN8IW1P1) || (defined CONFIG_ARCH_SUN8IW3P1) || (defined CONFIG_ARCH_SUN8IW5P1) /* config pmu config paras */ if (arisc_config_pmu_paras()) { ARISC_WRN("config pmu paras failed\n"); } #endif /* config dram config paras */ if (arisc_config_dram_paras()) { ARISC_WRN("config dram paras failed\n"); } #if (defined CONFIG_ARCH_SUN8IW5P1) || (defined CONFIG_ARCH_SUN9IW1P1) /* config standby power paras */ if (arisc_sysconfig_sstpower_paras()) { ARISC_WRN("config sst power paras failed\n"); } #endif atomic_set(&arisc_suspend_flag, 0); /* * detect sunxi chip id * include soc chip id, pmu chip id and serial. */ sunxi_chip_id_init(); /* arisc initialize succeeded */ ARISC_LOG("sunxi-arisc driver v%s startup succeeded\n", DRV_VERSION); return 0; }