249 lines
7.6 KiB
C
Executable File
249 lines
7.6 KiB
C
Executable File
/*
|
|
* drivers/arisc/arisc.c
|
|
*
|
|
* Copyright (c) 2012 Allwinner.
|
|
* 2012-10-01 Written by superm (superm@allwinnertech.com).
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#include "arisc_i.h"
|
|
|
|
/* local functions */
|
|
static int arisc_wait_ready(unsigned int timeout);
|
|
|
|
struct dts_cfg dts_cfg;
|
|
unsigned int arisc_debug_dram_crc_en = 0;
|
|
unsigned int arisc_debug_dram_crc_srcaddr = 0x40000000;
|
|
unsigned int arisc_debug_dram_crc_len = (1024 * 1024);
|
|
unsigned int arisc_debug_dram_crc_error = 0;
|
|
unsigned int arisc_debug_dram_crc_total_count = 0;
|
|
unsigned int arisc_debug_dram_crc_error_count = 0;
|
|
volatile const unsigned int arisc_debug_level = 2;
|
|
static unsigned char arisc_version[40] = "arisc defualt version";
|
|
|
|
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_deassert_arisc(void)
|
|
{
|
|
ARISC_INF("set arisc reset to de-assert state\n");
|
|
{
|
|
volatile unsigned long value;
|
|
value = readl(dts_cfg.cpuscfg.base + 0x0);
|
|
value &= ~1;
|
|
writel(value, dts_cfg.cpuscfg.base + 0x0);
|
|
value = readl(dts_cfg.cpuscfg.base + 0x0);
|
|
value |= 1;
|
|
writel(value, dts_cfg.cpuscfg.base + 0x0);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
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));
|
|
memcpy(¶->ir_key, &dts_cfg.s_cir.ir_key, sizeof(ir_key_t));
|
|
memcpy(¶->start_os, &dts_cfg.start_os, sizeof(box_start_os_cfg_t));
|
|
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;
|
|
}
|
|
|
|
uint32_t sunxi_load_arisc(uintptr_t image_addr, size_t image_size, void *para, size_t para_size)
|
|
{
|
|
void *dst;
|
|
void *src;
|
|
size_t size;
|
|
|
|
#if 0
|
|
/*
|
|
* phys addr to virt addr
|
|
* io space: ioremap
|
|
* kernel space: phys_to_virt
|
|
*/
|
|
/* sram code space */
|
|
dst = (void *)dts_cfg.space.sram_dst;
|
|
src = (void *)((ptrdiff_t)image_addr + (ptrdiff_t)dts_cfg.space.sram_offset);
|
|
size = dts_cfg.space.sram_size;
|
|
memset(dst, 0, size);
|
|
memcpy(dst, src, size);
|
|
flush_dcache_range((uint64_t)dst, (uint64_t)size);
|
|
|
|
/* dram code space */
|
|
dst = (void *)dts_cfg.space.dram_dst;
|
|
src = (void *)((ptrdiff_t)image_addr + (ptrdiff_t)dts_cfg.space.dram_offset);
|
|
size = dts_cfg.space.dram_size;
|
|
memset(dst, 0, size);
|
|
memcpy(dst, src, size);
|
|
flush_dcache_range((uint64_t)dst, (uint64_t)size);
|
|
|
|
ARISC_INF("load arisc image finish\n");
|
|
#endif
|
|
/* para space */
|
|
dst = (void *)dts_cfg.space.para_dst;
|
|
src = para;
|
|
size = dts_cfg.space.para_size;
|
|
memset(dst, 0, size);
|
|
memcpy(dst, src, size);
|
|
ARISC_INF("setup arisc para finish\n");
|
|
//dcsw_op_all(DCCISW);
|
|
flush_dcache_range((uint64_t)dst, (uint64_t)size);
|
|
isb();
|
|
|
|
#if 0
|
|
/* relese arisc reset */
|
|
sunxi_deassert_arisc();
|
|
ARISC_INF("release arisc reset finish\n");
|
|
|
|
ARISC_INF("load arisc finish\n");
|
|
#endif
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|