MTK平台 BootLoader lk部分串口驱动简析,以及客制化和外设通讯串口
MTK lk串口驱动源码简析
只分析主要代码,省略了不重要的代码:
bootable/bootloader/lk/platform/mtxxxx/uart.c
#define CONFIG_BAUDRATE 921600 //默认的串口波特率
volatile unsigned int g_uart; //当前要设置的串口号
unsigned int g_brg; //当前要设置的波特率
void mtk_set_current_uart(MTK_UART uart_base)
{
g_uart = uart_base; //给一个当前要设置的串口号,比如“UART1”
}
//根据传进来的串口号,使能对应的串口控制器
void mtk_uart_power_on(MTK_UART uart_base)
{
/* UART Powr PDN and Reset*/
#define AP_PERI_GLOBALCON_PDN0 (INFRACFG_AO_BASE+0x08)
if (uart_base == UART1)
UART_SET_BITS(1 << 17, AP_PERI_GLOBALCON_PDN0); /* Power on UART1 */
else if (uart_base == UART2)
UART_SET_BITS(1 << 18, AP_PERI_GLOBALCON_PDN0); /* Power on UART2 */
else if (uart_base == UART3)
UART_SET_BITS(1 << 19, AP_PERI_GLOBALCON_PDN0); /* Power on UART3 */
else if (uart_base == UART4)
UART_SET_BITS(1 << 20, AP_PERI_GLOBALCON_PDN0); /* Power on UART4 */
return;
}
//根据全局变量“g_brg”和“g_uart”,配置对应串口的时钟
void uart_setbrg()
{
unsigned int byte,speed;
unsigned int highspeed;
unsigned int quot, divisor, remainder;
unsigned int uartclk;
unsigned short data, high_speed_div, sample_count, sample_point;
unsigned int tmp_div;
speed = g_brg;
FIXME Disable for MT6582 LK Porting
uartclk = UART_SRC_CLK;
//uartclk = (unsigned int)(mtk_get_bus_freq()*1000/4);
if (speed <= 115200 ) {
highspeed = 0;
quot = 16;
} else {
highspeed = 3;
quot = 1;
}
if (highspeed < 3) { /*0~2*/
/* Set divisor DLL and DLH */
divisor = uartclk / (quot * speed);
remainder = uartclk % (quot * speed);
if (remainder >= (quot / 2) * speed)
divisor += 1;
mt65xx_reg_sync_writew(highspeed, UART_HIGHSPEED(g_uart));
byte = DRV_Reg32(UART_LCR(g_uart)); /* DLAB start */
mt65xx_reg_sync_writel((byte | UART_LCR_DLAB), UART_LCR(g_uart));
mt65xx_reg_sync_writel((divisor & 0x00ff), UART_DLL(g_uart));
mt65xx_reg_sync_writel(((divisor >> 8)&0x00ff), UART_DLH(g_uart));
mt65xx_reg_sync_writel(byte, UART_LCR(g_uart)); /* DLAB end */
}
else {
data=(unsigned short)(uartclk/speed);
high_speed_div = (data>>8) + 1; // divided by 256
tmp_div=uartclk/(speed*high_speed_div);
divisor = (unsigned short)tmp_div;
remainder = (uartclk)%(high_speed_div*speed);
/*get (sample_count+1)*/
if (remainder >= ((speed)*(high_speed_div))>>1)
divisor = (unsigned short)(tmp_div+1);
else
divisor = (unsigned short)tmp_div;
sample_count=divisor-1;
/*get the sample point*/
sample_point=(sample_count-1)>>1;
/*configure register*/
mt65xx_reg_sync_writel(highspeed, UART_HIGHSPEED(g_uart));
byte = DRV_Reg32(UART_LCR(g_uart)); /* DLAB start */
mt65xx_reg_sync_writel((byte | UART_LCR_DLAB), UART_LCR(g_uart));
mt65xx_reg_sync_writel((high_speed_div & 0x00ff), UART_DLL(g_uart));
mt65xx_reg_sync_writel(((high_speed_div >> 8)&0x00ff), UART_DLH(g_uart));
mt65xx_reg_sync_writel(sample_count, UART_SAMPLE_COUNT(g_uart));
mt65xx_reg_sync_writel(sample_point, UART_SAMPLE_POINT(g_uart));
mt65xx_reg_sync_writel(byte, UART_LCR(g_uart)); /* DLAB end */
}
}
//根据lk配置的log默认串口,初始化对应串口控制器
void uart_init_early(void)
{
//一般情况下,log会配置硬件uart0,这里就是“UART1”
if(get_uart_port_id() == 1){
mtk_set_current_uart(UART1); //设置全局变量“g_uart”,用到这个变量的函数,就会去设置“UART1”
mtk_uart_power_on(UART1); //使能“UART1”
}else if(get_uart_port_id() == 2){
mtk_set_current_uart(UART2);
mtk_uart_power_on(UART2);
}else if(get_uart_port_id() == 3){
mtk_set_current_uart(UART3);
mtk_uart_power_on(UART3);
}else if(get_uart_port_id() == 4){
mtk_set_current_uart(UART4);
mtk_uart_power_on(UART4);
}
else {
mtk_set_current_uart(UART4);
mtk_uart_power_on(UART4);
}
//由于只选择了一个串口,所以lk默认只是初始化了log用的串口,其他串口默认不会初始化
//初始化“UART1”的FIFO,因为“g_uart”被赋值“UART1”
DRV_SetReg32(UART_FCR(g_uart), UART_FCR_FIFO_INIT); /* clear fifo */
//初始化“UART1”其他配置,无校验,8数据位,1停止位,因为“g_uart”被赋值“UART1”
mt65xx_reg_sync_writew(UART_NONE_PARITY | UART_WLS_8 | UART_1_STOP, UART_LCR(g_uart));
//赋值变量“g_brg”,为默认波特率“921600”
g_brg = CONFIG_BAUDRATE;
//配置“UART1”的波特率为“921600”,因为“g_brg”被赋值“921600”,“g_uart”被赋值“UART1”
uart_setbrg();
}
//发送一个字节
int uart_putc(const char c )
{
//这里猜测应该是等待发送缓冲区有空位
while (!(DRV_Reg32(UART_LSR(g_uart)) & UART_LSR_THRE));
//如果要发送 '\n' ,则先发送一个 '\r'
if (c == '\n')
mt65xx_reg_sync_writel((unsigned int)'\r', UART_THR(g_uart));
//写数据到硬件发送缓冲区
mt65xx_reg_sync_writel((unsigned int)c, UART_THR(g_uart));
return 0;
}
//读一个字节
int uart_getc(void) /* returns -1 if no data available */
{
//这里猜测应该是等待接收缓冲区来数据
while (!(DRV_Reg32(UART_LSR(g_uart)) & UART_LSR_DR));
//返回收到的数据
return (int)DRV_Reg32(UART_RBR(g_uart));
}
//发送字符串
void uart_puts(const char *s)
{
while (*s)
uart_putc(*s++);
}
客制化一个和外设通讯的串口
//**********************************************************************
#define CONFIG_BAUDRATE_C 9600 //客制化的串口波特率
static bool custom_init = false; //客制化串口初始化标志位
//**********************************************************************
//在这个函数里面,先初始化要用的客制化串口“UART2”,避免影响默认log的串口
void uart_init_early(void)
{
//先初始化要用的客制化串口“UART2”,这里先做一个判断,确定lk默认不会用到“UART2”
//**********************************************************************
if(get_uart_port_id() != 2)
{
mtk_set_current_uart(UART2);
mtk_uart_power_on(UART2);
DRV_SetReg32(UART_FCR(g_uart), UART_FCR_FIFO_INIT); /* clear fifo */
mt65xx_reg_sync_writew(UART_NONE_PARITY | UART_WLS_8 | UART_1_STOP, UART_LCR(g_uart));
g_brg = CONFIG_BAUDRATE_C;
uart_setbrg();
custom_init = true; //设置标志位
}
//**********************************************************************
//初始化完成,下面的默认log串口“UART1”,不会受影响
//一般情况下,log会配置硬件uart0,这里就是“UART1”
if(get_uart_port_id() == 1){
mtk_set_current_uart(UART1); //设置全局变量“g_uart”,用到这个变量的函数,就会去设置“UART1”
mtk_uart_power_on(UART1); //使能“UART1”
}else if(get_uart_port_id() == 2){
mtk_set_current_uart(UART2);
mtk_uart_power_on(UART2);
}else if(get_uart_port_id() == 3){
mtk_set_current_uart(UART3);
mtk_uart_power_on(UART3);
}else if(get_uart_port_id() == 4){
mtk_set_current_uart(UART4);
mtk_uart_power_on(UART4);
}
else {
mtk_set_current_uart(UART4);
mtk_uart_power_on(UART4);
}
//由于只选择了一个串口,所以lk默认只是初始化了log用的串口,其他串口默认不会初始化
//初始化“UART1”的FIFO,因为“g_uart”被赋值“UART1”
DRV_SetReg32(UART_FCR(g_uart), UART_FCR_FIFO_INIT); /* clear fifo */
//初始化“UART1”其他配置,无校验,8数据位,1停止位,因为“g_uart”被赋值“UART1”
mt65xx_reg_sync_writew(UART_NONE_PARITY | UART_WLS_8 | UART_1_STOP, UART_LCR(g_uart));
//赋值变量“g_brg”,为默认波特率“921600”
g_brg = CONFIG_BAUDRATE;
//配置“UART1”的波特率为“921600”,因为“g_brg”被赋值“921600”,“g_uart”被赋值“UART1”
uart_setbrg();
}
//数据收发函数,直接使用“UART2”,不要使用“g_uart”,因为可能已经被赋值为其他串口了
//**********************************************************************
//发送一个字节
int uart2_put_byte(unsigned char c )
{
if(!custom_init) //如果没有初始化,则直接返回
return -1;
while (!(DRV_Reg32(UART_LSR(UART2)) & UART_LSR_THRE));
mt65xx_reg_sync_writel((unsigned int)c, UART_THR(UART2));
return 0;
}
//接收一个字节
int uart2_get_byte(unsigned char *c) /* returns -1 if no data available */
{
int _c, i = 0;
if(!custom_init) //如果没有初始化,则直接返回
return -1;
while (!(DRV_Reg32(UART_LSR(UART2)) & UART_LSR_DR))
{ //由于可能出现外设硬件故障,导致读数据时,一直没有收到数据,所以要加超时,避免死循环
i++;
if(i >= 0x2000)
return -1;
}
if ((_c = (int)DRV_Reg32(UART_RBR(UART2))) < 0)
return -1;
*c = (unsigned char)_c;
return 0;
}
//**********************************************************************