示例#1
0
int ar100_hwmsgbox_feedback_message(struct ar100_message *pmessage, unsigned int timeout)
{
	volatile unsigned long value;
	
	if (pmessage->attr & AR100_MESSAGE_ATTR_HARDSYN) {
		//use ac327 hard syn receiver channel.
		while (readl(IO_ADDRESS(AW_MSGBOX_FIFO_STATUS_REG(AR100_HWMSGBOX_AR100_SYN_RX_CH))) == 1) {
			//message-queue fifo is full, waiting.
			;
		}
		value = ((volatile unsigned long)pmessage) - ar100_sram_a2_vbase;
		AR100_INF("ar100 feedback hard syn message : %x\n", (unsigned int)value);
		writel(value, IO_ADDRESS(AW_MSGBOX_MSG_REG(AR100_HWMSGBOX_AR100_SYN_RX_CH)));
		return 0;
	}
	//soft syn use asyn tx channel
	if (pmessage->attr & AR100_MESSAGE_ATTR_SOFTSYN) {
		while (readl(IO_ADDRESS(AW_MSGBOX_FIFO_STATUS_REG(AR100_HWMSGBOX_AR100_ASYN_RX_CH))) == 1) {
			//fifo is full, wait
			;
		}
		//write message to message-queue fifo.
		value = ((volatile unsigned long)pmessage) - ar100_sram_a2_vbase;
		AR100_INF("ar100 send asyn or soft syn message : %x\n", (unsigned int)value);
		writel(value, IO_ADDRESS(AW_MSGBOX_MSG_REG(AR100_HWMSGBOX_AR100_ASYN_RX_CH)));
		return 0;
	}
	
	//invalid syn message
	return -EINVAL;
}
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;
}
示例#3
0
/*
*********************************************************************************************************
*                                       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;
}
/*
 * 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_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;
}
static int  sun6i_ar100_probe(struct platform_device *pdev)
{
	int binary_len;
	script_item_u script_val;
	script_item_value_type_e type;
	
	AR100_INF("ar100 initialize\n");
	
	/* 
	 * request ar100 resources:
	 * p2wi/uart gpio...
	 */
	sw_gpio_setcfg(GPIOL(0), 3);	/* p2wi sck */
	sw_gpio_setcfg(GPIOL(1), 3);	/* p2wi sda */
	
	type = script_get_item("cpus_config_paras", "cpus_uart_debug_used", &script_val);
	if (SCIRPT_ITEM_VALUE_TYPE_INT != type) {
		AR100_WRN("ar100 uart debug config type err!");
		script_val.val = 1;
	}
	if (script_val.val) {
		sw_gpio_setcfg(GPIOL(2), 2);	/* uart tx */
		sw_gpio_setcfg(GPIOL(3), 2);	/* uart rx */
	}
	AR100_INF("ar100 uart debug config [%s] [%s] : %d\n", "cpus_config_paras", "cpus_uart_debug_used", script_val.val);
	
	AR100_INF("sram_a2 vaddr(%x)\n", (unsigned int)ar100_sram_a2_vbase);
	
	/* clear sram_a2 area */
	memset((void *)ar100_sram_a2_vbase, 0, AW_SRAM_A2_SIZE);
	
	/* load ar100 system binary data to sram_a2 */
	binary_len = 0x13000;
	memcpy((void *)ar100_sram_a2_vbase, (void *)(&ar100_binary_start), binary_len);
	printk("move ar100 binary data [addr = %x, len = %x] to sram_a2 finished\n",
	         (unsigned int)(&ar100_binary_start), (unsigned int)binary_len);
	
	/* initialize hwspinlock */
	AR100_INF("hwspinlock initialize\n");
	ar100_hwspinlock_init();
	
	/* initialize hwmsgbox */
	AR100_INF("hwmsgbox initialize\n");
	ar100_hwmsgbox_init();
	
	/* initialize message manager */
	AR100_INF("message manager initialize\n");
	ar100_message_manager_init();
	
	/* set ar100 cpu reset to de-assert state */
	AR100_INF("set ar100 reset to de-assert state\n");
	{
		volatile unsigned long value;
		value = readl((IO_ADDRESS(AW_R_CPUCFG_BASE) + 0x0));
		value |= 1;
		writel(value, (IO_ADDRESS(AW_R_CPUCFG_BASE) + 0x0));
	}
	
	/* wait ar100 ready */
	AR100_INF("wait ar100 ready....\n");
	if (ar100_wait_ready(10000)) {
		AR100_LOG("ar100 startup failed\n");
	}
	
	/* enable ar100 asyn tx interrupt */
	ar100_hwmsgbox_enable_receiver_int(AR100_HWMSGBOX_AR100_ASYN_TX_CH, AW_HWMSG_QUEUE_USER_AC327);
	
	/* enable ar100 syn tx interrupt */
	ar100_hwmsgbox_enable_receiver_int(AR100_HWMSGBOX_AR100_SYN_TX_CH, AW_HWMSG_QUEUE_USER_AC327);
	
	/* config dvfs v-f table */
	if (ar100_dvfs_cfg_vf_table()) {
		AR100_WRN("config dvfs v-f table failed\n");
	}
	
	/* config dram config paras */
	if (ar100_config_dram_paras()) {
		AR100_WRN("config dram paras failed\n");
	}

	/* config ir config paras */
	if (ar100_config_ir_paras()) {
		AR100_WRN("config ir paras failed\n");
	}

	/* config pmu config paras */
	if (ar100_config_pmu_paras()) {
		AR100_WRN("config pmu paras failed\n");
	}

#ifdef CONFIG_PM
	atomic_set(&ar100_suspend_flag, 0);
#endif
	
	/* ar100 initialize succeeded */
	AR100_INF("ar100 startup succeeded, driver version : %d\n", AR100_VERSIONS);
	
	return 0;
}
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;
}