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; }
/* * set target frequency. * @freq: target frequency to be set, based on KHZ; * @mode: the attribute of message, whether syn or asyn; * @cb: callback handler; * @cb_arg: callback handler arguments; * * return: result, 0 - set frequency successed, * !0 - set frequency failed; */ int ar100_dvfs_set_cpufreq(unsigned int freq, unsigned long mode, ar100_cb_t cb, void *cb_arg) { unsigned int msg_attr = 0; struct ar100_message *pmessage; int result = 0; if (mode & AR100_DVFS_SYN) { msg_attr |= AR100_MESSAGE_ATTR_HARDSYN; } /* allocate a message frame */ pmessage = ar100_message_allocate(msg_attr); if (pmessage == NULL) { AR100_WRN("allocate message failed\n"); return -ENOMEM; } /* initialize message */ pmessage->type = AR100_CPUX_DVFS_REQ; pmessage->paras[0] = freq; pmessage->state = AR100_MESSAGE_INITIALIZED; pmessage->cb.handler = cb; pmessage->cb.arg = cb_arg; AR100_INF("ar100 dvfs request : %d\n", freq); ar100_hwmsgbox_send_message(pmessage, AR100_SEND_MSG_TIMEOUT); /* dvfs mode : syn or not */ if (mode & AR100_DVFS_SYN) { result = pmessage->result; ar100_message_free(pmessage); } return result; }
int ar100_dvfs_cfg_vf_table(void) { u32 value = 0; int index = 0; int result = 0; int vf_table_size = 0; char vf_table_key[256]; struct ar100_message *pmessage; /* parse system config v-f table information */ if (ar100_dvfs_get_cfg("dvfs_table", "LV_count", &vf_table_size)) { AR100_WRN("parse system config dvfs_table size fail\n"); } for (index = 0; index < vf_table_size; index++) { sprintf(vf_table_key, "LV%d_freq", index + 1); if (ar100_dvfs_get_cfg("dvfs_table", vf_table_key, &value) == 0) { ar100_vf_table[index].freq = value; } sprintf(vf_table_key, "LV%d_volt", index + 1); if (ar100_dvfs_get_cfg("dvfs_table", vf_table_key, &value) == 0) { if (value > 1400) { /* cpu_vdd must < 1.4V */ AR100_WRN("v-f table voltage [%d] > 1400mV\n", value); value = 1400; } ar100_vf_table[index].voltage = value; } } /* allocate a message frame */ pmessage = ar100_message_allocate(AR100_MESSAGE_ATTR_HARDSYN); if (pmessage == NULL) { AR100_WRN("allocate message failed\n"); return -ENOMEM; } for (index = 0; index < AR100_DVFS_VF_TABLE_MAX; index++) { /* initialize message */ pmessage->type = AR100_CPUX_DVFS_CFG_VF_REQ; pmessage->paras[0] = index; pmessage->paras[1] = ar100_vf_table[index].freq; pmessage->paras[2] = ar100_vf_table[index].voltage; pmessage->paras[3] = ar100_vf_table[index].axi_div; pmessage->state = AR100_MESSAGE_INITIALIZED; pmessage->cb.handler = NULL; pmessage->cb.arg = NULL; AR100_INF("v-f table: index %d freq %d vol %d axi_div %d\n", pmessage->paras[0], pmessage->paras[1], pmessage->paras[2], pmessage->paras[3]); /* send request message */ ar100_hwmsgbox_send_message(pmessage, AR100_SEND_MSG_TIMEOUT); //check config fail or not if (pmessage->result) { AR100_WRN("config dvfs v-f table [%d] fail\n", index); result = -EINVAL; break; } } /* free allocated message */ ar100_message_free(pmessage); return result; }