static int __init ar100_init(void) { int ret; AR100_LOG("sun6i ar100 driver v%s\n", DRV_VERSION); ret = platform_driver_register(&sun6i_ar100_driver); if (IS_ERR_VALUE(ret)) { AR100_ERR("register sun6i ar100 platform driver failed\n"); goto err_platform_driver_register; } ret = platform_device_register(&sun6i_ar100_device); if (IS_ERR_VALUE(ret)) { AR100_ERR("register sun6i ar100 platform device failed\n"); goto err_platform_device_register; } sun6i_ar100_sysfs(&sun6i_ar100_device); return 0; err_platform_device_register: platform_device_unregister(&sun6i_ar100_device); err_platform_driver_register: platform_driver_unregister(&sun6i_ar100_driver); return -EINVAL; }
/* ********************************************************************************************************* * QUERY MESSAGE * * Description: query message of hwmsgbox by hand, mainly for. * * Arguments : none. * * Returns : the point of message, NULL if timeout. ********************************************************************************************************* */ struct ar100_message *ar100_hwmsgbox_query_message(void) { struct ar100_message *pmessage = NULL; //query ac327 asyn received channel if (readl(IO_ADDRESS(AW_MSGBOX_MSG_STATUS_REG(AR100_HWMSGBOX_AR100_ASYN_TX_CH)))) { volatile unsigned long value; value = readl(IO_ADDRESS(AW_MSGBOX_MSG_REG(AR100_HWMSGBOX_AR100_ASYN_TX_CH))); pmessage = (struct ar100_message *)(value + ar100_sram_a2_vbase); if (ar100_message_valid(pmessage)) { //message state switch if (pmessage->state == AR100_MESSAGE_PROCESSED) { //AR100_MESSAGE_PROCESSED->AR100_MESSAGE_FEEDBACKED pmessage->state = AR100_MESSAGE_FEEDBACKED; } else { //AR100_MESSAGE_INITIALIZED->AR100_MESSAGE_RECEIVED pmessage->state = AR100_MESSAGE_RECEIVED; } } else { //print_call_info(); AR100_ERR("invalid message received: 1 pmessage = 0x%x. \n", (__u32)pmessage); return NULL; } //clear pending ar100_hwmsgbox_clear_receiver_pending(AR100_HWMSGBOX_AR100_ASYN_TX_CH, AW_HWMSG_QUEUE_USER_AC327); return pmessage; } //query ac327 syn received channel if (readl(IO_ADDRESS(AW_MSGBOX_MSG_STATUS_REG(AR100_HWMSGBOX_AR100_SYN_TX_CH)))) { volatile unsigned long value; value = readl(IO_ADDRESS(AW_MSGBOX_MSG_REG(AR100_HWMSGBOX_AR100_SYN_TX_CH))); pmessage = (struct ar100_message *)(value + ar100_sram_a2_vbase); if (ar100_message_valid(pmessage)) { //message state switch if (pmessage->state == AR100_MESSAGE_PROCESSED) { //AR100_MESSAGE_PROCESSED->AR100_MESSAGE_FEEDBACKED pmessage->state = AR100_MESSAGE_FEEDBACKED; } else { //AR100_MESSAGE_INITIALIZED->AR100_MESSAGE_RECEIVED pmessage->state = AR100_MESSAGE_RECEIVED; } } else { //print_call_info(); AR100_ERR("invalid message received: 2 pmessage = 0x%x. \n", (__u32)pmessage); return NULL; } ar100_hwmsgbox_clear_receiver_pending(AR100_HWMSGBOX_AR100_SYN_TX_CH, AW_HWMSG_QUEUE_USER_AC327); return pmessage; } //no valid message return NULL; }
/* ********************************************************************************************************* * 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 ar100_hwmsgbox_send_message(struct ar100_message *pmessage, unsigned int timeout) { volatile unsigned long value; if (pmessage == NULL) { return -EINVAL; } if (pmessage->attr & AR100_MESSAGE_ATTR_HARDSYN) { //use ac327 hwsyn transmit channel. while (readl(IO_ADDRESS(AW_MSGBOX_FIFO_STATUS_REG(AR100_HWMSGBOX_AC327_SYN_TX_CH))) == 1) { //message-queue fifo is full, waiting always ; } value = ((volatile unsigned long)pmessage) - ar100_sram_a2_vbase; AR100_INF("ac327 send hard syn message : %x\n", (unsigned int)value); writel(value, IO_ADDRESS(AW_MSGBOX_MSG_REG(AR100_HWMSGBOX_AC327_SYN_TX_CH))); //hwsyn messsage must feedback use syn rx channel while (readl(IO_ADDRESS(AW_MSGBOX_MSG_STATUS_REG(AR100_HWMSGBOX_AC327_SYN_RX_CH))) == 0) { //message not valid ; } //check message valid if (value != (readl(IO_ADDRESS(AW_MSGBOX_MSG_REG(AR100_HWMSGBOX_AC327_SYN_RX_CH))))) { AR100_ERR("hard syn message error\n"); return -EINVAL; } AR100_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(AR100_HWMSGBOX_AR100_ASYN_RX_CH))) == 1) { //message-queue fifo is full, waiting always ; } //write message to message-queue fifo. value = ((volatile unsigned long)pmessage) - ar100_sram_a2_vbase; AR100_LOG("ac327 send message : %x\n", (unsigned int)value); writel(value, IO_ADDRESS(AW_MSGBOX_MSG_REG(AR100_HWMSGBOX_AR100_ASYN_RX_CH))); //syn messsage must wait message feedback if (pmessage->attr & AR100_MESSAGE_ATTR_SOFTSYN) { AR100_ERR("standby ar100 driver not support soft syn message transfer\n"); return -EINVAL; } return 0; }
static int ar100_wait_ready(unsigned int timeout) { unsigned long expire; expire = msecs_to_jiffies(timeout) + jiffies; /* wait ar100 startup ready */ while (1) { /* * linux cpu interrupt is disable now, * we should query message by hand. */ struct ar100_message *pmessage = ar100_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 == AR100_STARTUP_NOTIFY) { /* check ar100 software and driver version match or not */ if (pmessage->paras[0] != AR100_VERSIONS) { AR100_ERR("ar100 firmware and driver version not matched\n"); return -EINVAL; } /* received ar100 startup ready message */ AR100_INF("ar100 startup ready\n"); if ((pmessage->attr & AR100_MESSAGE_ATTR_SOFTSYN) || (pmessage->attr & AR100_MESSAGE_ATTR_HARDSYN)) { /* synchronous message, just feedback it */ AR100_INF("ar100 startup notify message feedback\n"); pmessage->paras[0] = virt_to_phys((void *)&ar100_binary_start); ar100_hwmsgbox_feedback_message(pmessage, AR100_SEND_MSG_TIMEOUT); } else { /* asyn message, free message directly */ AR100_INF("ar100 startup notify message free directly\n"); ar100_message_free(pmessage); } break; } /* * invalid message detected, ignore it. * by sunny at 2012-7-6 18:34:38. */ AR100_WRN("ar100 startup waiting ignore message\n"); if ((pmessage->attr & AR100_MESSAGE_ATTR_SOFTSYN) || (pmessage->attr & AR100_MESSAGE_ATTR_HARDSYN)) { /* synchronous message, just feedback it */ ar100_hwmsgbox_send_message(pmessage, AR100_SEND_MSG_TIMEOUT); } else { /* asyn message, free message directly */ ar100_message_free(pmessage); } /* we need waiting continue */ } return 0; }
int ar100_dvfs_get_cfg(char *main, char *sub, u32 *val) { script_item_u script_val; script_item_value_type_e type; type = script_get_item(main, sub, &script_val); if (SCIRPT_ITEM_VALUE_TYPE_INT != type) { AR100_ERR("ar100 dvfs config type err!"); return -EINVAL; } *val = script_val.val; AR100_INF("ar100 dvfs config [%s] [%s] : %d\n", main, sub, *val); return 0; }