mirror of
https://gitee.com/Vancouver2017/luban-lite-t3e-pro.git
synced 2025-12-14 18:38:55 +00:00
348 lines
8.7 KiB
C
348 lines
8.7 KiB
C
/*
|
|
*
|
|
* Copyright (c) 2023, ArtInChip Technology Co., Ltd
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Authors: Mingfeng.Li <mingfeng.li@artinchip.com>
|
|
*/
|
|
|
|
#include <rtconfig.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <aic_common.h>
|
|
#include <string.h>
|
|
#include <aic_core.h>
|
|
#include <aic_hal.h>
|
|
#include <driver.h>
|
|
#include <xspi_psram.h>
|
|
#include <hal_xspi.h>
|
|
#include "aic_core.h"
|
|
|
|
#define XSPI_DDR_MODE 1
|
|
#define XSPI_SDR_MODE 0
|
|
|
|
#define XSPI_MODE_XCCELA 0
|
|
#define XSPI_MODE_HYPERBUS 1
|
|
#define XSPI_MODE_OPI 2
|
|
#define XSPI_MODE_SPI 3
|
|
|
|
#define XSPI_IO_1 0x0
|
|
#define XSPI_IO_2 0x1
|
|
#define XSPI_IO_4 0x2
|
|
#define XSPI_IO_8 0x3
|
|
|
|
#define XSPI_PARALLEL_MODE 1
|
|
#define XSPI_SINGLE_MODE 0
|
|
|
|
#define BASE_PSRAM 0x40000000
|
|
|
|
|
|
// usually config by menuconfig
|
|
#ifndef AIC_XSPI_PSRAM_CLK
|
|
#define AIC_XSPI_PSRAM_CLK 99000000
|
|
#endif
|
|
#ifndef AIC_XSPI_PSRAM_CS0_PINS
|
|
#define AIC_XSPI_PSRAM_CS0_PINS 0
|
|
#endif
|
|
#ifndef AIC_XSPI_PSRAM_CS1_PINS
|
|
#define AIC_XSPI_PSRAM_CS1_PINS 0
|
|
#endif
|
|
|
|
|
|
|
|
|
|
static struct aic_xspi aic_xspi_controller[] = {
|
|
{
|
|
.name = "xspi",
|
|
.idx = 0,
|
|
.clk_id = CLK_XSPI,
|
|
/* XSPI IP hw Frequency division=2 */
|
|
.clk_in_hz = AIC_XSPI_PSRAM_CLK * 2,
|
|
},
|
|
};
|
|
|
|
static struct aic_xspi *aic_get_xspi_by_index(u32 idx)
|
|
{
|
|
struct aic_xspi *xspi;
|
|
u32 i;
|
|
|
|
xspi = NULL;
|
|
for (i = 0; i < ARRAY_SIZE(aic_xspi_controller); i++) {
|
|
if (i == idx) {
|
|
xspi = &aic_xspi_controller[i];
|
|
break;
|
|
}
|
|
}
|
|
return xspi;
|
|
}
|
|
|
|
static u32 aic_xspi_psram_dev_reset(hal_xspi_handle *handle)
|
|
{
|
|
|
|
hal_xspi_set_cmd_width(handle, XSPI_DDR_MODE, XSPI_IO_8);
|
|
hal_xspi_set_cmd(handle, XSPI_DDR_MODE, 0xff);
|
|
hal_xspi_set_addr_width(handle, XSPI_DDR_MODE, XSPI_IO_8, 3);
|
|
hal_xspi_set_addr(handle, 0x0);
|
|
hal_xspi_set_dummy(handle, XSPI_IO_8, 0x0);
|
|
hal_xspi_set_write_cnt(handle, XSPI_DDR_MODE, XSPI_IO_8, 1);
|
|
|
|
u8 buf = 0;
|
|
struct hal_xspi_transfer t;
|
|
t.rx_data = NULL;
|
|
t.tx_data = &buf;
|
|
t.data_len = 1;
|
|
hal_xspi_transfer_cpu_sync(handle, &t);
|
|
pr_debug("aic_xspi_psram_dev_reset %s:%d\n\n\n", __FUNCTION__, __LINE__);
|
|
return 0;
|
|
}
|
|
|
|
static u32 aic_xspi_psram_dev_init(hal_xspi_handle *handle)
|
|
{
|
|
|
|
hal_xspi_set_cmd_width(handle, XSPI_DDR_MODE, XSPI_IO_8);
|
|
hal_xspi_set_cmd(handle, XSPI_DDR_MODE, 0xc0);
|
|
hal_xspi_set_addr_width(handle, XSPI_DDR_MODE, XSPI_IO_8, 3);
|
|
hal_xspi_set_addr(handle, 0x0);
|
|
hal_xspi_set_dummy(handle, XSPI_IO_8, 0x0);
|
|
hal_xspi_set_write_cnt(handle, XSPI_DDR_MODE, XSPI_IO_8, 2);
|
|
|
|
u8 buf1[2] = {0x19, 0x00};
|
|
struct hal_xspi_transfer t2;
|
|
t2.rx_data = NULL;
|
|
t2.tx_data = (u8 *)buf1;
|
|
t2.data_len = 2;
|
|
hal_xspi_transfer_cpu_sync(handle, &t2);
|
|
|
|
hal_xspi_set_addr(handle, 0x4);
|
|
u8 buf11[2] = {0x80, 0x00};
|
|
struct hal_xspi_transfer t22;
|
|
t22.rx_data = NULL;
|
|
t22.tx_data = (u8 *)buf11;
|
|
t22.data_len = 2;
|
|
hal_xspi_transfer_cpu_sync(handle, &t22);
|
|
|
|
return 0;
|
|
}
|
|
|
|
[[maybe_unused]] static u32 aic_xspi_psram_read_id(hal_xspi_handle *handle)
|
|
{
|
|
|
|
u32 data = 0;
|
|
|
|
hal_xspi_set_cmd_width(handle, XSPI_DDR_MODE, XSPI_IO_8);
|
|
hal_xspi_set_cmd(handle, XSPI_DDR_MODE, 0x40);
|
|
hal_xspi_set_addr_width(handle, XSPI_DDR_MODE, XSPI_IO_8, 3);
|
|
hal_xspi_set_addr(handle, 0x02);
|
|
hal_xspi_set_dummy(handle, XSPI_IO_8, 3);
|
|
hal_xspi_set_read_cnt(handle, XSPI_DDR_MODE, XSPI_IO_8, 4);
|
|
|
|
struct hal_xspi_transfer t3;
|
|
t3.rx_data = (u8 *)&data;
|
|
t3.tx_data = NULL;
|
|
t3.data_len = 4;
|
|
hal_xspi_transfer_cpu_sync(handle, &t3);
|
|
pr_debug("APS3208K_ID= 0x%x\n", data);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static u32 aic_xspi_psram_xip(hal_xspi_handle *handle, hal_xspi_proto_cfg_t proto)
|
|
{
|
|
hal_xspi_xip_cfg(handle, proto);
|
|
hal_xspi_xip_enable(handle);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static u8 aic_xspi_psram_mem_test(long address, u32 size)
|
|
{
|
|
u32 i;
|
|
|
|
/**< 32bit test */
|
|
{
|
|
u32 * p_u32 = (u32 *)address;
|
|
for(i=0; i<size/sizeof(u32); i++)
|
|
{
|
|
*p_u32++ = (u32)i;
|
|
}
|
|
|
|
p_u32 = (u32 *)address;
|
|
for(i=0; i<size/sizeof(u32); i++)
|
|
{
|
|
if( *p_u32 != (u32)i )
|
|
{
|
|
pr_err("32bit test fail @ 0x%08lX, system halt!!!!!",(long)p_u32);
|
|
return 1;
|
|
}
|
|
p_u32++;
|
|
}
|
|
pr_debug("32bit test pass!!\r\n");
|
|
}
|
|
|
|
/**< 32bit Loopback test */
|
|
{
|
|
u32 * p_u32 = (u32 *)address;
|
|
for(i=0; i<size/sizeof(u32); i++)
|
|
{
|
|
*p_u32 = (long)p_u32;
|
|
p_u32++;
|
|
}
|
|
|
|
p_u32 = (u32 *)address;
|
|
for(i=0; i<size/sizeof(u32); i++)
|
|
{
|
|
if( *p_u32 != (long)p_u32 )
|
|
{
|
|
pr_err("32bit Loopback test fail @ 0x%08lX", (long)p_u32);
|
|
pr_err(" data:0x%08X, ", (u32)*p_u32);
|
|
pr_err("system halt!!!!!\n");
|
|
return 1;
|
|
}
|
|
p_u32++;
|
|
}
|
|
pr_debug("32bit Loopback test pass!!\r\n");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
u32 aic_xspi_psram_training(hal_xspi_handle *h, u8 sel, u8 reg_icp, void *psram_buf, u32 len)
|
|
{
|
|
u8 temp = 0;
|
|
u8 temp1 = 0;
|
|
u8 temp2 = 0;
|
|
u8 ret_memtest = 0;
|
|
|
|
CHECK_PARAM(h, -EINVAL);
|
|
|
|
hal_xspi_set_cs(h, sel);
|
|
hal_xspi_set_parallel_mode(h, XSPI_SINGLE_MODE);
|
|
hal_xspi_set_dll_ctl(h, sel, reg_icp, 3);
|
|
|
|
aicos_dcache_clean();
|
|
for(u8 i=0; i<15; i++){
|
|
hal_xspi_set_phase_sel(h, sel, i);
|
|
aic_udelay(5);
|
|
temp1 = i;
|
|
ret_memtest = aic_xspi_psram_mem_test((long)psram_buf, len);
|
|
if (!ret_memtest) break;
|
|
}
|
|
if (temp1 == 15) {
|
|
hal_log_err("Trainning failed...\n");
|
|
return 1;
|
|
}
|
|
|
|
aicos_dcache_clean();
|
|
for(u8 i=14; i>=0; i--){
|
|
hal_xspi_set_phase_sel(h, sel, i);
|
|
aic_udelay(5);
|
|
temp2 = i;
|
|
ret_memtest = aic_xspi_psram_mem_test((long)psram_buf, len);
|
|
if (!ret_memtest) break;
|
|
}
|
|
|
|
temp = (temp1 + temp2)/2;
|
|
hal_xspi_set_dll_ctl(h, sel, reg_icp, temp);
|
|
pr_err(" %s:%d cs=%d, temp=%d, temp1=%d, temp2=%d...\n", __FUNCTION__, __LINE__, sel, temp, temp1, temp2);
|
|
return 0;
|
|
}
|
|
|
|
#define AIC_XSPI_ICP_50_100M 0
|
|
#define AIC_XSPI_ICP_100_150M 1
|
|
#define AIC_XSPI_ICP_150_200M 2
|
|
u32 aic_xspi_psram_icp_calc(u32 clk_in_hz)
|
|
{
|
|
if ((clk_in_hz >= 99000000) && (clk_in_hz <= 198000000)) {
|
|
return AIC_XSPI_ICP_50_100M;
|
|
} else if ((clk_in_hz > 198000000) && (clk_in_hz <= 247500000)) {
|
|
return AIC_XSPI_ICP_100_150M;
|
|
} else if ((clk_in_hz > 247500000) && (clk_in_hz <= 396000000)) {
|
|
return AIC_XSPI_ICP_150_200M;
|
|
}
|
|
return AIC_XSPI_ICP_50_100M;
|
|
}
|
|
|
|
u32 aic_xspi_psram_init(void)
|
|
{
|
|
u32 ret = 0;
|
|
|
|
struct aic_xspi *xspi;
|
|
struct hal_xspi_config cfg;
|
|
|
|
xspi = aic_get_xspi_by_index(0);
|
|
if (!xspi)
|
|
return -1;
|
|
|
|
if (xspi->inited)
|
|
return 0;
|
|
|
|
memset(&cfg, 0, sizeof(cfg));
|
|
cfg.idx = xspi->idx;
|
|
cfg.clk_in_hz = xspi->clk_in_hz;
|
|
cfg.clk_id = xspi->clk_id;
|
|
cfg.cs0_port = AIC_XSPI_PSRAM_CS0_PINS;
|
|
cfg.cs1_port = AIC_XSPI_PSRAM_CS1_PINS;
|
|
|
|
ret = hal_xspi_init(&xspi->handle, &cfg);
|
|
if (ret) {
|
|
pr_err("xspi init failed.\n");
|
|
return ret;
|
|
}
|
|
|
|
hal_xspi_set_cs(&xspi->handle, 0);
|
|
aic_xspi_psram_dev_reset(&xspi->handle);
|
|
aic_udelay(100);
|
|
aic_xspi_psram_dev_init(&xspi->handle);
|
|
|
|
|
|
hal_xspi_set_cs(&xspi->handle, 1);
|
|
aic_xspi_psram_dev_reset(&xspi->handle);
|
|
aic_udelay(100);
|
|
aic_xspi_psram_dev_init(&xspi->handle);
|
|
|
|
// set Boundary_Control = 2k.
|
|
hal_xspi_set_boudary(&xspi->handle, BOUNDARY_2K);
|
|
|
|
hal_xspi_proto_cfg_t psram_proto_cfg = {0};
|
|
psram_proto_cfg.mode = XSPI_MODE_OPI;
|
|
psram_proto_cfg.clk_mode = XSPI_DDR_MODE;
|
|
psram_proto_cfg.parallel_mode = XSPI_SINGLE_MODE;
|
|
psram_proto_cfg.wr_cmd_lines = XSPI_IO_8;
|
|
psram_proto_cfg.wr_cmd_val = 0x80;
|
|
psram_proto_cfg.addr_lines = XSPI_IO_8;
|
|
psram_proto_cfg.addr_width = 3;
|
|
//psram_proto_cfg.wr_dummy = 0;
|
|
psram_proto_cfg.wr_dummy = 2; // >166M
|
|
psram_proto_cfg.rd_dummy = 0x06;
|
|
psram_proto_cfg.wr_cnt_lines = XSPI_IO_8;
|
|
psram_proto_cfg.wr_cnt = 2;
|
|
psram_proto_cfg.rd_cnt_lines = XSPI_IO_8;
|
|
psram_proto_cfg.rd_cnt = 3;
|
|
psram_proto_cfg.rd_cmd_lines = XSPI_IO_8;
|
|
psram_proto_cfg.rd_cmd_val = 0x00;
|
|
|
|
|
|
aic_xspi_psram_xip(&xspi->handle, psram_proto_cfg);
|
|
|
|
void *psram_training_buf = (u32*)(BASE_PSRAM);
|
|
u32 len = 1024 * 64;
|
|
u32 icp_t = aic_xspi_psram_icp_calc(cfg.clk_in_hz);
|
|
|
|
ret = aic_xspi_psram_training(&xspi->handle, 0, icp_t, psram_training_buf, len);
|
|
if (ret) {
|
|
pr_err("xspi cs0 trainning failed.\n");
|
|
while(1);
|
|
}
|
|
|
|
ret = aic_xspi_psram_training(&xspi->handle, 1, icp_t, psram_training_buf, len);
|
|
if (ret) {
|
|
pr_err("xspi cs0 trainning failed.\n");
|
|
while(1);
|
|
}
|
|
|
|
hal_xspi_set_parallel_mode(&xspi->handle, XSPI_PARALLEL_MODE);
|
|
|
|
return 0;
|
|
|
|
}
|