T113-i 通用工控主板


__s32 drv_g2d_init(void)
{
memset(&g2d_ext_hd, 0, sizeof(__g2d_drv_t));
init_wait_event(&g2d_ext_hd.wait_event);
g2d_top_set_base((unsigned long) para.io);
#if defined(CONFIG_SUNXI_G2D_ROTATE)
g2d_rot_set_base((unsigned long) para.io);
#endif
return 0;
}
int g2d_probe(void )
{
__g2d_info_t *info = NULL;
info = ¶
info->dev = 0;
info->io = (__u32 *)0x05410000;
info->irq = 121;
info->clk = (__u32 *)0x02001630;
info->clk_parent = 0;
info->bus_clk = (__u32 *)0x0200163c;
info->mbus_clk = (__u32 *)0x02001804;
bsp_int_vect_set(info->irq, /* Assign ISR handler. */
8u, /* 中断的优先级 */
1u, /* 中断的目标CPU */
0u, /* 参数 */
g2d_handle_irq);
irq_enable(info->irq);//
drv_g2d_init();
mutex_init(&info->mutex);
mutex_init(&global_lock);
return 0;
}

T113-s3的SMHC1接一片SD NAND ,但在读取数据时,传输描述符配置都正确的情况下。iDMA始终报描述符不可用中断。
status_t sd_mmc_set_dma_table_config(v3x_sd_mmc_t *base,
sd_mmc_dma_config_t *dma_config,
sd_mmc_data_t *data_config,
uint32_t flags)
{
base->DMAC = 1;//IMAC 复位
const uint32_t *start_address;
uint32_t entries;
uint32_t i, dma_buffer_len = 0U;
sd_mmc_dma_descriptor_t *dma_entry_address;
uint32_t data_bytes = data_config->block_size * data_config->block_count;
const uint32_t *data = (data_config->rx_data == NULL) ? data_config->tx_data : data_config->rx_data;
/* check DMA data buffer address align or not */
if ( ((uint32_t)data & 0x03) != 0U )
{
return STA_DMA_DATA_ADDR_NOT_ALIGN;
}
/*
* Add non aligned access support ,user need make sure your buffer size is big
* enough to hold the data,in other words,user need make sure the buffer size
* is 4 byte aligned
*/
data_bytes = (data_bytes + 3) & (~3);
start_address = data;
base->GCTL |= (SDXC_FIFO_RESET | SDXC_DMA_RESET | SDXC_DMA_ENABLE_BIT);/* reset fifo & dma*/
/* Check if ADMA descriptor's number is enough. */
if ((data_bytes % MMC_SD_DMA_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) == 0U)
entries = data_bytes / MMC_SD_DMA_DESCRIPTOR_MAX_LENGTH_PER_ENTRY;
else
entries = ((data_bytes / MMC_SD_DMA_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) + 1U);
if (entries > ((dma_config->dma_table_words * sizeof(uint32_t)) / sizeof(sd_mmc_dma_descriptor_t)))
{
/*如果超过预置(1个)数量,应该支持动态分配描述符表 */
if( STA_SUCCESS != sd_mmc_malloc_dma_descriptor( dma_config,entries))
return STA_MEM_ERROR;
}
dma_entry_address = (sd_mmc_dma_descriptor_t *)(dma_config->dma_table);
for (i = 0U; i < entries; i++)
{
if (data_bytes > MMC_SD_DMA_DESCRIPTOR_MAX_LENGTH_PER_ENTRY)
{
dma_buffer_len = MMC_SD_DMA_DESCRIPTOR_MAX_LENGTH_PER_ENTRY;
data_bytes -= dma_buffer_len;
}
else
{
dma_buffer_len = data_bytes;
}
/* */
dma_entry_address[i].buf_addr_ptr = (uint32_t)start_address;
dma_entry_address[i].buf_size = dma_buffer_len ;
dma_entry_address[i].config = SD_MMC_DESCRIPTOR_TC_INT_DIS
| SD_MMC_DESCRIPTOR_CHAIM_MOD
| SD_MMC_DESCRIPTOR_OWN_FLAG;
dma_entry_address[i].buf_addr_next = (uint32_t)&dma_entry_address[i + 1];
start_address += (dma_buffer_len / sizeof(uint32_t));/*32bit 偏移*/
}
/* set the end bit */
dma_entry_address[0].config = SD_MMC_DESCRIPTOR_FIRST_FLAG
| SD_MMC_DESCRIPTOR_TC_INT_DIS
| SD_MMC_DESCRIPTOR_CHAIM_MOD
| SD_MMC_DESCRIPTOR_OWN_FLAG;
uint32_t config = dma_entry_address[i - 1U].config & (~(SD_MMC_DESCRIPTOR_TC_INT_DIS
));
dma_entry_address[i - 1U].config = config | SD_MMC_DESCRIPTOR_LAST_FLAG;// \
// | (1 << 5); /* end of ring */
dma_entry_address[i - 1U].buf_addr_next = 0;
base->DMAC = (1 << 1) | (1 << 7);
/* enable dma interrupt */
base->IDST = 0x3F; /*清除DMA中断状态 */
/*config the burst length */
base->FWLR = (burst_len_16 << 28) | (0x0f << 16) | 240;//0x10;
/*允许dma中断 */
if(data_config->rx_data)
{
/*DMA 接收利用 DMA传输完毕产生中断*/
base->IDIE = ( SDXC_IDMAC_RECEIVE_INTERRUPT
| SDXC_IDMAC_FATAL_BUS_ERROR
| SDXC_IDMAC_DESTINATION_INVALID
| SDXC_IDMAC_CARD_ERROR_SUM);
base->IMKR &= ~(1 << 3);
}
else if(data_config->tx_data)
{
/*DMA 传输利用 MCI传输完毕产生中断*/
base->IDIE = ( SDXC_IDMAC_FATAL_BUS_ERROR
| SDXC_IDMAC_TRANSMIT_INTERRUPT
| SDXC_IDMAC_DESTINATION_INVALID
| SDXC_IDMAC_CARD_ERROR_SUM);
base->IMKR |= (1 << 3);
}
else
base->IDIE = 0;
base->DLBA = (uint32_t)(dma_config->dma_table);
/* enable DMA */
sd_mmc_enable_dma(base);
/*动态分配的内存 ,需要刷新cache */
if (entries > ((dma_config->dma_table_words * sizeof(uint32_t)) / sizeof(sd_mmc_dma_descriptor_t)))
{
L1C_CleanDataCacheRange(dma_config->dma_table,dma_config->dma_table_words * entries);
}
return STA_SUCCESS;
}
上面说使用的描述符的内存空间是位于非cache段的内存中。


从内存数据看配置都是正确的,数据已经从sd nsnd 传输到fifo中了,而 IDMA总是报描述符不可用,致使数据不能从fifo读取到内存中。 大家帮我看看问题可能在哪里。
终于将G2D裸机环境使用搞定了。 简单测试了一下bitblt 和矩形填充。
extern const unsigned char image_mn_map[800*480*4];/*图片文件*/
void g2d_test(void)
{
g2d_probe();
g2d_open();
g2d_blt_h blit_para;
while(1)
{
/* bitblt测试 */
memset(&blit_para,0,sizeof(g2d_blt_h));
g2d_image_enh *src = &blit_para.src_image_h;
g2d_image_enh *des = &blit_para.dst_image_h;
blit_para.flag_h = G2D_ROT_180;//G2D_ROT_V;// G2D_ROT_0;
src->laddr[0] = (uint32_t)image_mn_map;
src->align[0] = 4;
src->clip_rect.w = 800;
src->clip_rect.h = 480;
src->width = 800;
src->height = 480;
src->format = G2D_FORMAT_ARGB8888;
src->mode = G2D_PIXEL_ALPHA;
src->bpremul = 0;
des->laddr[0] = r528_de_config.LayerAddr[0] ;
des->align[0] = 4;
des->clip_rect.w = 800;
des->clip_rect.h = 480;
des->width = 800;
des->height = 480;
des->format = G2D_FORMAT_ARGB8888;
des->mode = G2D_PIXEL_ALPHA;
des->bpremul = 0;
long ret = g2d_ioctl( G2D_CMD_BITBLT_H, (unsigned long )&blit_para);
/* 矩形填充测试 */
g2d_fillrect_h fill_para;
memset(&fill_para,0,sizeof(g2d_fillrect_h));
src = &fill_para.dst_image_h;
src->laddr[0] = (uint32_t)r528_de_config.LayerAddr[0] ;;
src->align[0] = 4;
src->clip_rect.w = 800;
src->clip_rect.h = 480;
src->width = 800;
src->height = 480;
src->format = G2D_FORMAT_ARGB8888;
src->mode = G2D_PIXEL_ALPHA;
src->bpremul = 0;
src->gamut = G2D_BT709;
src->color = 0xFFFF0000;
src->alpha = 0xff;
ret = g2d_ioctl( G2D_CMD_FILLRECT_H, (unsigned long )&fill_para);
}
}
经过实际测试,T133-S3的CAN模块完全可用。测试相关信息如下:
#define CAN0 0x02504000
#define CAN1 0x02504400
#define CAN_OFFSET(can_base,offset) (*((volatile uint32_t *)(can_base + (offset))))
#define CAN_MSEL(can_base) CAN_OFFSET(can_base,0x0000) //CAN mode select register
#define CAN_CMD(can_base) CAN_OFFSET(can_base,0x0004) //CAN command register
#define CAN_STA(can_base) CAN_OFFSET(can_base,0x0008) //CAN status register
#define CAN_INT(can_base) CAN_OFFSET(can_base,0x000C) //CAN interrupt register
#define CAN_INTEN(can_base) CAN_OFFSET(can_base,0x0010) //CAN interrupt enable register
#define CAN_BUSTIME(can_base) CAN_OFFSET(can_base,0x0014) //CAN bus timing register
#define CAN_TEWL(can_base) CAN_OFFSET(can_base,0x0018) //CAN TX error warning limit register
#define CAN_ERRC(can_base) CAN_OFFSET(can_base,0x001c) //CAN error counter register
#define CAN_RMCNT(can_base) CAN_OFFSET(can_base,0x0020) //CAN receive message counter register
#define CAN_RBUF_SADDR(can_base) CAN_OFFSET(can_base,0x0024) //CAN receive buffer start address register
#define CAN_TRBUF0(can_base) CAN_OFFSET(can_base,0x0040) //CAN TX/RX message buffer 0 register
#define CAN_TRBUF1(can_base) CAN_OFFSET(can_base,0x0044) //CAN TX/RX message buffer 0 register
#define CAN_TRBUF2(can_base) CAN_OFFSET(can_base,0x0048) //CAN TX/RX message buffer 0 register
#define CAN_TRBUF3(can_base) CAN_OFFSET(can_base,0x004c) //CAN TX/RX message buffer 0 register
#define CAN_TRBUF4(can_base) CAN_OFFSET(can_base,0x0050) //CAN TX/RX message buffer 0 register
#define CAN_TRBUF5(can_base) CAN_OFFSET(can_base,0x0054) //CAN TX/RX message buffer 0 register
#define CAN_TRBUF6(can_base) CAN_OFFSET(can_base,0x0058) //CAN TX/RX message buffer 0 register
#define CAN_TRBUF7(can_base) CAN_OFFSET(can_base,0x005c) //CAN TX/RX message buffer 0 register
#define CAN_TRBUF8(can_base) CAN_OFFSET(can_base,0x0060) //CAN TX/RX message buffer 0 register
#define CAN_TRBUF9(can_base) CAN_OFFSET(can_base,0x0064) //CAN TX/RX message buffer 0 register
#define CAN_TRBUF10(can_base) CAN_OFFSET(can_base,0x0068) //CAN TX/RX message buffer 0 register
#define CAN_TRBUF11(can_base) CAN_OFFSET(can_base,0x006c) //CAN TX/RX message buffer 0 register
#define CAN_TRBUF12(can_base) CAN_OFFSET(can_base,0x0070) //CAN TX/RX message buffer 0 register
#define CAN_ACPC(can_base) CAN_OFFSET(can_base,0x0028) //CAN acceptance code 0 register(reset mode)
#define CAN_ACPM(can_base) CAN_OFFSET(can_base,0x002C) //CAN acceptance mask 0 register(reset mode)
#define CAN_RBUF_RBACK(can_base) CAN_OFFSET(can_base,0x0180) //~0x1b0 //CAN transmit buffer for read back register
#define CAN_VERSION(can_base) CAN_OFFSET(can_base,0x0300) //CAN Version Register
typedef struct _t113_can_control_t_
{
volatile uint32_t * can_clk_gate;
uint32_t can_base;
uint32_t int_id;
}t113_can_control_t;
t113_can_control_t t113_can[2] =
{
{
(volatile uint32_t *)0x0200192C,
0x02504000,
53
},
{
(volatile uint32_t *)0x0200192C,
0x02504400,
54
}
};
uint32_t rxd_buf[13];
void t113_can_irq_handle(void* p)
{
uint32_t can_base = (uint32_t) p;
uint32_t int_sta = CAN_INT(can_base);
if(int_sta & 1)
{
/* 接收中断 */
can_read_data(can_base,rxd_buf);
/* 后续处理 */
}
if(int_sta & 2 )
{
/*发送中断*/
}
if(int_sta & 0xFC )
{
/* 错 误 中断 */
}
CAN_INT(can_base) = int_sta;
}
void ini_can(int can_id)
{
if(can_id > 1) return;
GPIOB->CFG0 &= ~(0xff00 << (can_id * 8));
GPIOB->CFG0 |= (0x8800 << (can_id * 8));
GPIOB->DRV0 |= (0x3300 << (can_id * 8));
t113_can_control_t * can_info = &t113_can[can_id];
uint32_t can_base = can_info->can_base;
int can_int_id = can_info->int_id;
*can_info->can_clk_gate |= (1 << (16 + can_id)) | (1 << can_id);/* CCU_CAN_BGR */
CAN_MSEL(can_base) |= 1; /* Reset mode selected*/
/* 500KHz CAN速率 */
CAN_BUSTIME(can_base) = (9 /* apb_clk = 100Mz , 100/10 = 10MHz*/
| (1 << 14) /* Synchronization Jump Width :2 Tq clock cycles */
| (13 << 16) /*Phase Segment 1 : 14 Tq clock cycles */
| ( 3 << 20) /*Phase Segment 2 : 4 Tq clock cycles */
| ( 0 << 23)); /* Bus line is sampled three times at the sample point */
CAN_ACPC(can_base) = 0xffffffff; /*实际使用时根据需要设置滤波*/
CAN_ACPM(can_base) = 0xffffffff; /*实际使用时根据需要设置滤波*/
CAN_MSEL(can_base) &= (~1);
// CAN_MSEL(can_base) |= (1 << 2); /* Loopback Mode */
CAN_MSEL(can_base) |= (1 << 3);/* Single Filter */
bsp_int_vect_set(can_int_id, /* Assign ISR handler. */
1u, /* 中断的优先级 */
1u, /* 中断的目标CPU */
(void *)can_base, /* 参数 */
t113_can_irq_handle);
irq_enable(can_int_id);//
/* 使能中断 */
CAN_INTEN(can_base) = 0x0FF;
}
void can_send_data(uint32_t can_base,uint8_t * buf,int len)
{
CAN_CMD(can_base) |= (1 << 2);
CAN_MSEL(can_base) &= (~1);
int retry = 1000;
do{
if(--retry == 0) break;
}while(!(CAN_STA(can_base) & (1 << 2)));
if(retry == 0) return;//
uint32_t * des = &CAN_TRBUF0(can_base);
for(int i = 0; i < len; i++)
des[i] = buf[i];
//CAN_CMD(can_base) = (1 << 4);
CAN_CMD(can_base) |= (1 << 0);
}
void can_read_data(uint32_t can_base,uint8_t * buf)
{
uint32_t * src = &CAN_TRBUF0(can_base);
for(int i = 0; i < 13; i++)
buf[i] = (char)src[i];
CAN_CMD(can_base) |= (1 << 2);
}
uint8_t can_teat_data[13] =
{
8,
0,
0x80,
0x55, /* SFF - TX data byte 1 / EFF- ID[12:5] */
0x55, /* SFF-TX data byte2[7:3] / EFF-ID[4:0]
SFF-TX data byte2[2:0] */
0x55, /* SFF-TX data byte 3 / EFF-TX data byte 1 */
0x55, /* SDATA4_EDATA2 SFF-TX data byte 4 / EFF-TX data byte 2 */
0x55, /* SDATA5_EDATA3 SFF-TX data byte 5 / EFF-TX data byte 3 */
0x55,/* SDATA5_EDATA4 SFF-TX data byte 6 / EFF-TX data byte 4 */
0x55,/* SDATA5_EDATA5 SFF-TX data byte 7 / EFF-TX data byte 5 */
0x55,/* SDATA5_EDATA6 SFF-TX data byte 8 / EFF-TX data byte 6 */
0x55, /* SDATA5_EDATA7 */
0x55 /* SDATA5_EDATA8 */
};
/* can_id: is 0 or 1 */
void t113_can_test(void)
{
ini_can(0);
ini_can(1);
while(1)
{
can_send_data(CAN0,can_data);
ms_delay(500);
can_send_data(CAN1,can_data);
ms_delay(500);
}
}
@tripod9 我也是裸奔,没遇到这个问题。请教你裸奔,主频最高能跑到多少MHz?我这里最高就只能跑到800MHz,高于800M值,切换主频源时CPU就跑飞了。
使用芒果派小麻雀板的T113做测试,CPU运行主频高于800MHz,切换时就跑飞。测试代码如下,请求大佬们支招:
#define CPU_RUN_FREQ 1200000000
#define SYS_XTOSC_CLK 24000000
static void set_pll_cpux_axi(void)
{
uint32_t val;
int n = (CPU_RUN_FREQ / SYS_XTOSC_CLK -1 ) & 0xFF;
/* Switch to PLL_PERI(1X) clock while changing cpu pll (600MHz) */
CCU_CPU_AXI_CFG = (4<<24) ;
sdelay(10000);
/* cpu pll rate = 24000000 * n */
val = PLL_CPU_CTRL_REG & (~((0xff << 8) | (1 << 27)));
val |= (n << 8);
PLL_CPU_CTRL_REG = val;
PLL_CPU_CTRL_REG &= ~(1 << 29);
sdelay(5);
PLL_CPU_CTRL_REG |= (1 << 29);
sdelay(1000);
while( (PLL_CPU_CTRL_REG &(1 << 28)) == 0 ); /* wait for pll lock */
PLL_CPU_CTRL_REG |= (1 << 27); /* open pll out gate */
sdelay(10000);
/* Switch clock source */
CCU_CPU_AXI_CFG = (3 << 24);
sdelay(10000);
}
这一句CCU_CPU_AXI_CFG = (3 << 24)一执行,CPU就跑飞了.
请求支援。期待中。
@mangogeek 在staru.s中添加下面一段后,中断就正常了。
/* Set vector base address register */
ldr r0, =__vector_table
mcr p15, 0, r0, c12, c0, 0
mrc p15, 0, r0, c1, c0, 0
bic r0, #(1 << 13)
mcr p15, 0, r0, c1, c0, 0
/* Enable SMP mode for dcache, by setting bit 6 of auxiliary ctl reg */
mrc p15, 0, r0, c1, c0, 1
orr r0, r0, #(1 << 6)
mcr p15, 0, r0, c1, c0, 1
/* enable branch prediction */
mrc p15, 0, r0, c1, c0, 0
orr r0, r0, #(1<<11)
mcr p15, 0, r0, c1, c0, 0
/* Enable neon/vfp unit */
mrc p15, 0, r0, c1, c0, 2
orr r0, r0, #(0xf << 20)
mcr p15, 0, r0, c1, c0, 2
isb
mov r0, #0x40000000
vmsr fpexc, r0
T113就配置TIMER0做tick时钟:
#define TIMER_IRQ_CON_BASE (0x02050000)
#define TIMER0_BASE (0x02050010)
#define TIMER1_BASE (0x02050020)
#define timer0 ((timer_t *)(TIMER0_BASE))
#define timer1 ((timer_t *)(TIMER1_BASE))
/* for R528/T113 */
#define T113_GIC_BASE (0x03021000)
#define T113_CPUIF_BASE (0x03022000)
#define PRESCALER_VALUE 1UL
#define OS_CFG_TICK_RATE_HZ 1000
#define GPTIM_LOAD_CONST ((24000000 / OS_CFG_TICK_RATE_HZ) /(PRESCALER_VALUE) )
timer_irq_con_t * timer_irq_con = (timer_irq_con_t * )TIMER_IRQ_CON_BASE;
void BSP_OS_TickInit (void)
{
timer0->INTV_VALUE = GPTIM_LOAD_CONST;
timer0->CUR_VALUE = GPTIM_LOAD_CONST;
bsp_int_vect_set(INT_TIMER0, /* Assign ISR handler. */
1u, /* 中断的优先级 */
3u, /* 中断的目标CPU */
0u, /* 参数 */
BSP_OS_TickISR_Handler);
/* 周期连续模式 */
timer0->CTRL_REG = (1 << 2);
irq_enable(INT_TIMER0);
timer_irq_con->TMR_IRQ_STA = 1;/*clear int sta */
timer_irq_con->TMR_IRQ_EN |= 1;/*enable timer0 int */
timer0->CTRL_REG |= 1;/*enable timer0 */
}
运行后timer0的计数正常,中断标志也已经置1了,但就是不产生中断。请教各位大佬,问题该如何定位。
gic模块的代码基本上是提取uboot的代码,代码在V3s上是能够正常运行的,只是迁移时根据T113的地址分布更改了各模块的基地址:
/*
* (C) Copyright 2007-2013
* Allwinner Technology Co., Ltd. <www.allwinnertech.com>
* Jerry Wang <wangflord@allwinnertech.com>
*
* See file CREDITS for list of people who contributed to this
* project.
*
* 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 "v3s_map.h"
#include "reg-ccu.h"
#include "gic.h"
#include "v3s_irq_id.h"
#include <stdio.h>
#include <stdint.h>
#include "bsp_sys.h"
struct _irq_handler
{
void *m_data;
void (*m_func)( void * data);
};
struct _irq_handler sunxi_int_handlers[NUMBER_OF_INT_VECTORS]@"OcramData";
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
static void default_isr(void *data)
{
sysprintf("default_isr(): called from IRQ %d\n", (uint32_t)data);
while(1);
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
int irq_enable(int irq_no)
{
uint32_t reg_val;
uint32_t offset;
if (irq_no >= NUMBER_OF_INT_VECTORS)
{
printf("irq NO.(%d) > NUMBER_OF_INT_VECTORS(%d) !!\n", irq_no, NUMBER_OF_INT_VECTORS);
return -1;
}
if(irq_no == INT_NMI)
{
*(volatile unsigned int *)(0x01f00c00 + 0x10) |= 1;
*(volatile unsigned int *)(0x01f00c00 + 0x40) |= 1;
}
offset = irq_no >> 5; // 除32
reg_val = readl(GIC_SET_EN(offset));
reg_val |= 1 << (irq_no & 0x1f);
writel(reg_val, GIC_SET_EN(offset));
return 0;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
int irq_disable(int irq_no)
{
uint32_t reg_val;
uint32_t offset;
if (irq_no >= NUMBER_OF_INT_VECTORS)
{
sysprintf("irq NO.(%d) > NUMBER_OF_INT_VECTORS(%d) !!\n", irq_no, NUMBER_OF_INT_VECTORS);
return -1;
}
if(irq_no == INT_NMI)
{
*(volatile unsigned int *)(0x01f00c00 + 0x10) |= 1;
*(volatile unsigned int *)(0x01f00c00 + 0x40) &= ~1;
}
offset = irq_no >> 5; // 除32
reg_val = (1 << (irq_no & 0x1f));
writel(reg_val, GIC_CLR_EN(offset));
return 0;
}
void irq_int_prio_set (uint32_t int_id,
uint32_t prio)
{
if (int_id >= NUMBER_OF_INT_VECTORS)
{
sysprintf("irq NO.(%d) > NUMBER_OF_INT_VECTORS(%d) !!\n", int_id, NUMBER_OF_INT_VECTORS);
return ;
}
if (prio > BSP_INT_PRIO_LVL_MAX) {
prio = BSP_INT_PRIO_LVL_MAX;
return;
}
CPU_SR_ALLOC();
CPU_CRITICAL_ENTER();
// uint32_t * prio_r = (uint32_t *)GIC_SGI_PRIO((int_id>>5));
//prio_r[int_id] = (uint8_t)((prio << (8UL - __GIC_PRIO_BITS)) & (uint8_t)0xFFUL);
uint32_t reg_val, addr, offset;
/* dispatch the usb interrupt to CPU1 */
addr = GIC_SGI_PRIO(int_id>>2);
reg_val = readl(addr);
offset = 8 * (int_id & 3);
reg_val &= ~(0xff<<offset);
reg_val |= ((prio << (8UL - __GIC_PRIO_BITS)) << offset);
writel(reg_val, addr);
CPU_CRITICAL_EXIT();
}
void irq_int_target_cpu_set (uint32_t int_id,
uint8_t int_target_cpu)
{
if (int_id >= NUMBER_OF_INT_VECTORS)
{
sysprintf("irq NO.(%d) > NUMBER_OF_INT_VECTORS(%d) !!\n", int_id, NUMBER_OF_INT_VECTORS);
return ;
}
CPU_SR_ALLOC();
CPU_CRITICAL_ENTER();
uint32_t reg_val, addr, offset;
/* dispatch the usb interrupt to CPU1 */
addr = GIC_SGI_PROC_TARG(int_id>>2);
reg_val = readl(addr);
offset = 8 * (int_id & 3);
reg_val &= ~(0xff<<offset);
reg_val |= (int_target_cpu <<offset);
writel(reg_val, addr);
CPU_CRITICAL_EXIT();
return ;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
static void gic_sgi_handler(uint32_t irq_no)
{
sysprintf("SGI irq %d coming... \n", irq_no);
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
static void gic_ppi_handler(uint32_t irq_no)
{
sysprintf("PPI irq %d coming... \n", irq_no);
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
static void gic_spi_handler(uint32_t irq_no)
{
if (sunxi_int_handlers[irq_no].m_func != default_isr)
{
sunxi_int_handlers[irq_no].m_func(sunxi_int_handlers[irq_no].m_data);
}
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
static void gic_clear_pending(uint32_t irq_no)
{
uint32_t reg_val;
uint32_t offset;
offset = irq_no >> 5; // 除32
reg_val = readl(GIC_PEND_CLR(offset));
reg_val |= (1 << (irq_no & 0x1f));
writel(reg_val, GIC_PEND_CLR(offset));
return ;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
void irq_install_handler (int irq, interrupt_handler_t handle_irq, void *data)
{
CPU_SR_ALLOC();
CPU_CRITICAL_ENTER();
if (irq >= NUMBER_OF_INT_VECTORS || !handle_irq)
{
CPU_CRITICAL_EXIT();
return;
}
sunxi_int_handlers[irq].m_data = data;
sunxi_int_handlers[irq].m_func = handle_irq;
CPU_CRITICAL_EXIT();
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
void irq_free_handler(int irq)
{
CPU_SR_ALLOC();
CPU_CRITICAL_ENTER();
if (irq >= NUMBER_OF_INT_VECTORS)
{
CPU_CRITICAL_EXIT();
return;
}
sunxi_int_handlers[irq].m_data = NULL;
sunxi_int_handlers[irq].m_func = default_isr;
CPU_CRITICAL_EXIT();
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
void BSP_IntHandler (void)
{
u32 idnum;
idnum = readl(GIC_INT_ACK_REG);
if ((idnum == 1023) ||(idnum == 1022))
{
sysprintf("spurious irq !!\n");
return;
}
if (idnum >= NUMBER_OF_INT_VECTORS)
{
sysprintf("irq NO.(%d) > NUMBER_OF_INT_VECTORS(%d) !!\n", idnum, NUMBER_OF_INT_VECTORS-32);
return;
}
// u32 int_cpu = (idnum >> 10) & 0x0f;
if (idnum < 16)
gic_sgi_handler(idnum);
else if (idnum < 32)
gic_ppi_handler(idnum);
else
gic_spi_handler(idnum);
if(idnum == INT_NMI)
{
*(volatile unsigned int *)(0x01f00c00 + 0x10) |= 1;
}
writel(idnum, GIC_END_INT_REG);/*write GICC_EOIR, to cause priority drop on the GIC CPU interface*/
writel(idnum, GIC_DEACT_INT_REG);/* write to the GICC_DIR, to deactivate the interrupt*/
gic_clear_pending(idnum);
return;
}
//#endif
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
static void gic_distributor_init(void)
{
uint32_t cpumask = 0x01010101;
uint32_t gic_irqs;
uint32_t i;
writel(0, GIC_DIST_CON);
/* check GIC hardware configutation */
gic_irqs = ((readl(GIC_CON_TYPE) & 0x1f) + 1) * 32;
if (gic_irqs > 1020)
{
gic_irqs = 1020;
}
if (gic_irqs < NUMBER_OF_INT_VECTORS)
{
sysprintf("GIC parameter config error, only support %d"
" irqs < %d(spec define)!!\n", gic_irqs, NUMBER_OF_INT_VECTORS);
return ;
}
/* set trigger type to be level-triggered, active low */
for (i=0; i<NUMBER_OF_INT_VECTORS; i+=16)
{
writel(0, GIC_IRQ_MOD_CFG(i>>4));
}
/* set priority */
for (i=GIC_SRC_SPI(0); i<NUMBER_OF_INT_VECTORS; i+=4)
{
writel(0xffffffff, GIC_SPI_PRIO((i-32)>>2));
}
/* set processor target */
for (i=32; i<NUMBER_OF_INT_VECTORS; i+=4)
{
writel(cpumask, GIC_SPI_PROC_TARG((i-32)>>2));
}
/* disable all interrupts */
for (i=32; i<NUMBER_OF_INT_VECTORS; i+=32)
{
writel(0xffffffff, GIC_CLR_EN(i>>5));
}
/* clear all interrupt active state */
for (i=32; i<NUMBER_OF_INT_VECTORS; i+=32)
{
writel(0xffffffff, GIC_ACT_CLR(i>>5));
}
writel(1, GIC_DIST_CON);
return ;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
static void gic_cpuif_init(void)
{
uint32_t i;
writel(0, GIC_CPU_IF_CTRL);
/*
* Deal with the banked PPI and SGI interrupts - disable all
* PPI interrupts, ensure all SGI interrupts are enabled.
*/
writel(0xffff0000, GIC_CLR_EN(0));
writel(0x0000ffff, GIC_SET_EN(0));
/* Set priority on PPI and SGI interrupts */
for (i=0; i<16; i+=4)
{
writel(0xffffffff, GIC_SGI_PRIO(i>>2));
}
for (i=16; i<32; i+=4)
{
writel(0xffffffff, GIC_PPI_PRIO((i-16)>>2));
}
/* Priority level is implementation defined.
To determine the number of priority bits implemented write 0xFF to an IPRIORITYR
priority field and read back the value stored.*/
// GIC_SetPriority((IRQn_Type)0U, 0xFFU);
//priority_field = GIC_GetPriority((IRQn_Type)0U);
writel(0xff, GIC_INT_PRIO_MASK);
writel(1, GIC_CPU_IF_CTRL);
return ;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
int arch_interrupt_init (void)
{
int i;
for (i=0; i<NUMBER_OF_INT_VECTORS; i++)
{
sunxi_int_handlers[i].m_func = default_isr;
}
gic_distributor_init();
gic_cpuif_init();
return 0;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
int arch_interrupt_exit(void)
{
gic_distributor_init();
gic_cpuif_init();
return 0;
}
void bsp_int_vect_set( uint32_t int_id,
uint32_t int_prio,
uint8_t int_target_list,
void * pParam,
system_irq_handler_t int_fnct)
{
irq_install_handler (int_id, int_fnct, pParam);
irq_int_prio_set(int_id,int_prio);
irq_int_target_cpu_set(int_id,int_target_list);
}